[
  {
    "path": ".bazelrc",
    "content": "test --test_output=errors\n"
  },
  {
    "path": ".bazelversion",
    "content": "7.2.0\n"
  },
  {
    "path": ".clang-format",
    "content": "---\nLanguage: Cpp\nBasedOnStyle: Google\nIndentWidth: 4\nColumnLimit: 120\nAlignAfterOpenBracket: AlwaysBreak\nAllowShortBlocksOnASingleLine: Never\nAllowShortFunctionsOnASingleLine: None\nAllowShortIfStatementsOnASingleLine: Never\nAllowShortLoopsOnASingleLine: false\nAllowShortLambdasOnASingleLine: None\nBinPackArguments: false\nBinPackParameters: false\nPointerAlignment: Right\n\nIncludeCategories:\n  - Regex:           '^<.*>$'\n    Priority:        1\n  - Regex:           '^\"gtest/.*\"$'\n    Priority:        2\n  - Regex:           '^\".*\"$'\n    Priority:        3\n...\n"
  },
  {
    "path": ".editorconfig",
    "content": "# Copyright 2025 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n# Common editor configurations for this project.\n#\n# EditorConfig is a file format for specifying some common style parameters.\n# Many IDEs & editors read .editorconfig files, either natively or via plugins.\n# We mostly follow Google's style guides (https://google.github.io/styleguide/)\n# with only a few deviations for line length and indentation in some files.\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\ninsert_final_newline = true\nspelling_language = en-US\ntrim_trailing_whitespace = true\nmax_line_length = 120\n\n[{BUILD,*.BUILD,*.bzl,*.bazel,.bazelrc}]\nindent_size = 4\n\n[{*.cc,*.h}]\nindent_size = 4\n\n[{*.js,*.ts}]\nindent_size = 4\n\n[*.json]\nindent_size = 2\n\n[*.py]\nindent_size = 4\n\n[*.sh]\nindent_size = 4\n\n[{*.yaml,*.yml}]\nindent_size = 2\n"
  },
  {
    "path": ".github/SECURITY.md",
    "content": "# Reporting security issues\n\nThe Stim developers and community take security bugs in Stim seriously. We\nappreciate your efforts to disclose your findings responsibly, and will make\nevery effort to acknowledge your contributions.\n\nPlease **do not** use GitHub issues to report security vulnerabilities; GitHub\nissues are public, and doing so could allow someone to exploit the information\nbefore the problem can be addressed. Instead, please use the GitHub [\"Report a\nVulnerability\"](https://github.com/quantumlib/Stim/security/advisories/new)\ninterface from the _Security_ tab of the Stim repository.\n\nPlease report security issues in third-party modules to the person or team\nmaintaining the module rather than the Stim project stewards, unless you\nbelieve that some action needs to be taken with Stim in order to guard\nagainst the effects of a security vulnerability in a third-party module.\n\n## Responses to security reports\n\nThe project stewards at Google Quantum AI will send a response indicating the\nnext steps in handling your report. After the initial reply to your report, the\nproject stewards will keep you informed of the progress towards a fix and full\nannouncement, and may ask for additional information or guidance.\n\n## Additional points of contact\n\nPlease contact the project stewards at Google Quantum AI via email at\nquantum-oss-maintainers@google.com if you have questions or other concerns. If\nfor any reason you are uncomfortable reaching out to the project stewards,\nplease email opensource@google.com.\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nname: ci\non:\n  push:\n    branches:\n      - main\n    tags:\n      - v*\n  pull_request:\n    branches:\n      - main\njobs:\n  build_dist:\n    runs-on: ${{ matrix.os_dist.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os_dist: [\n          {os: ubuntu-24.04, dist: cp38-manylinux_x86_64},\n          {os: ubuntu-24.04, dist: cp39-manylinux_x86_64},\n          {os: ubuntu-24.04, dist: cp310-manylinux_x86_64},\n          {os: ubuntu-24.04, dist: cp311-manylinux_x86_64},\n          {os: ubuntu-24.04, dist: cp312-manylinux_x86_64},\n          {os: ubuntu-24.04, dist: cp313-manylinux_x86_64},\n          {os: ubuntu-24.04, dist: cp314-manylinux_x86_64},\n\n          # cp38-manylinux_i686 disabled because pandas isn't prebuilt and takes 20 minutes to build.\n          # {os: ubuntu-latest, dist: cp38-manylinux_i686},\n          # cp39-manylinux_i686 disabled because pandas isn't prebuilt and takes 20 minutes to build.\n          # {os: ubuntu-latest, dist: cp39-manylinux_i686},\n          # cp310-manylinux_i686 disabled because scipy isn't prebuilt and fails to build.\n          #\n          # The actual error seen in github actions:\n          #\n          #     numpy.distutils.system_info.NotFoundError: No BLAS/LAPACK\n          #     libraries found. To build Scipy from sources, BLAS & LAPACK\n          #     libraries need to be installed.\n          #\n          #{os: ubuntu-latest, dist: cp310-manylinux_i686},\n\n          # pypy manylinux builds disabled because scipy isn't prebuilt and fails to build.\n          #\n          # The actual error seen in github actions:\n          #\n          #     numpy.distutils.system_info.NotFoundError: No BLAS/LAPACK\n          #     libraries found. To build Scipy from sources, BLAS & LAPACK\n          #     libraries need to be installed.\n          #\n          # {os: ubuntu-latest, dist: pp37-manylinux_x86_64},\n          # {os: ubuntu-latest, dist: pp38-manylinux_x86_64},\n          # {os: ubuntu-latest, dist: pp39-manylinux_x86_64},\n          # {os: ubuntu-latest, dist: pp37-manylinux_i686},\n          # {os: ubuntu-latest, dist: pp38-manylinux_i686},\n          # {os: ubuntu-latest, dist: pp39-manylinux_i686},\n\n          # musllinux builds disabled because scipy isn't prebuilt and fails to build.\n          #\n          # The actual error seen in github actions:\n          #\n          #     numpy.distutils.system_info.NotFoundError: No BLAS/LAPACK\n          #     libraries found. To build Scipy from sources, BLAS & LAPACK\n          #     libraries need to be installed.\n          #\n          # {os: ubuntu-latest, dist: cp36-musllinux_x86_64},\n          # {os: ubuntu-latest, dist: cp37-musllinux_x86_64},\n          # {os: ubuntu-latest, dist: cp38-musllinux_x86_64},\n          # {os: ubuntu-latest, dist: cp39-musllinux_x86_64},\n          # {os: ubuntu-latest, dist: cp310-musllinux_x86_64},\n          # {os: ubuntu-latest, dist: cp36-musllinux_i686},\n          # {os: ubuntu-latest, dist: cp37-musllinux_i686},\n          # {os: ubuntu-latest, dist: cp38-musllinux_i686},\n          # {os: ubuntu-latest, dist: cp39-musllinux_i686},\n          # {os: ubuntu-latest, dist: cp310-musllinux_i686},\n\n          {os: macos-14, dist: cp38-macosx_x86_64, macosarch: x86_64},\n          {os: macos-14, dist: cp39-macosx_x86_64, macosarch: x86_64},\n          {os: macos-14, dist: cp310-macosx_x86_64, macosarch: x86_64},\n          {os: macos-14, dist: cp311-macosx_x86_64, macosarch: x86_64},\n          {os: macos-14, dist: cp312-macosx_x86_64, macosarch: x86_64},\n          {os: macos-14, dist: cp313-macosx_x86_64, macosarch: x86_64},\n          {os: macos-14, dist: cp314-macosx_x86_64, macosarch: x86_64},\n\n          {os: macos-14, dist: cp38-macosx_arm64, macosarch: arm64},\n          {os: macos-14, dist: cp39-macosx_arm64, macosarch: arm64},\n          {os: macos-14, dist: cp310-macosx_arm64, macosarch: arm64},\n          {os: macos-14, dist: cp311-macosx_arm64, macosarch: arm64},\n          {os: macos-14, dist: cp312-macosx_arm64, macosarch: arm64},\n          {os: macos-14, dist: cp313-macosx_arm64, macosarch: arm64},\n          {os: macos-14, dist: cp314-macosx_arm64, macosarch: arm64},\n\n          # pypy OSX builds disabled because numpy isn't prebuilt and fails to build.\n          #\n          # The actual error seen in github actions:\n          #\n          #     RuntimeError: Found /usr/lib/libcblas.dylib, but that file is a\n          #     symbolic link to the MacOS Accelerate framework, which is not\n          #     supported by NumPy. You must configure the build to use a\n          #     different optimized library, or disable the use of optimized\n          #     BLAS and LAPACK by setting the environment variables\n          #     NPY_BLAS_ORDER=\"\" and NPY_LAPACK_ORDER=\"\" before building NumPy.\n          #\n          # {os: macOS-10.15, dist: pp37-macosx_x86_64},\n          # {os: macOS-10.15, dist: pp38-macosx_x86_64},\n          # {os: macOS-10.15, dist: pp39-macosx_x86_64},\n\n          {os: windows-2025, dist: cp38-win_amd64},\n          {os: windows-2025, dist: cp39-win_amd64},\n          {os: windows-2025, dist: cp310-win_amd64},\n          {os: windows-2025, dist: cp311-win_amd64},\n          {os: windows-2025, dist: cp312-win_amd64},\n          {os: windows-2025, dist: cp313-win_amd64},\n          {os: windows-2025, dist: cp314-win_amd64},\n\n          # cp38-win32 and cp39-win32 disabled because scipy fails to build.\n          #\n          # The actual error seen in github actions:\n          #\n          #    Need python for 64-bit, but found 32-bit\n          #    ..\\..\\meson.build:82:0: ERROR: Python dependency not found\n          #\n          #{os: windows-2025, dist: cp38-win32},\n          #{os: windows-2025, dist: cp39-win32},\n\n          # cp310-win32 disabled because numpy isn't prebuilt and fails to build.\n          #\n          # The actual error seen in github actions:\n          #\n          #     CCompiler_spawn() got an unexpected keyword argument 'env'\n          #\n          # {os: windows-2025, dist: cp310-win32},\n        ]\n    env:\n      CIBW_BUILD: \"${{ matrix.os_dist.dist }}\"\n      CIBW_ARCHS_MACOS: \"${{ matrix.os_dist.macosarch }}\"\n      CIBW_TEST_REQUIRES: cirq-core pytest\n      CIBW_TEST_COMMAND: pytest {project}/src {project}/glue/cirq && stim help\n    steps:\n      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3\n      - run: python dev/overwrite_dev_versions_with_date.py\n      - run: python -m pip install pybind11~=2.11.1 cibuildwheel~=3.3.1 setuptools wheel\n      - run: python -m cibuildwheel --print-build-identifiers\n      - run: python -m cibuildwheel --output-dir dist\n      - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0\n        with:\n          name: \"dist-stim-${{ matrix.os_dist.os }}-${{ matrix.os_dist.dist }}-${{ matrix.os_dist.macosarch }}\"\n          path: dist/*\n  build_sdist:\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3\n      - run: python -m pip install setuptools pybind11~=2.11.1\n      - run: python dev/overwrite_dev_versions_with_date.py\n      - run: mkdir output\n      - run: python setup.py sdist\n      - run: cd glue/cirq && python setup.py sdist\n      - run: cd glue/cirq && python setup.py bdist_wheel\n      - run: cd glue/sample && python setup.py sdist\n      - run: cd glue/sample && python setup.py bdist_wheel\n      - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0\n        with:\n          name: \"dist-sinter\"\n          path: glue/sample/dist/*.tar.gz\n      - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0\n        with:\n          name: \"bdist-sinter\"\n          path: glue/sample/dist/*.whl\n      - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0\n        with:\n          name: \"dist-stimcirq\"\n          path: glue/cirq/dist/*.tar.gz\n      - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0\n        with:\n          name: \"bdist-stimcirq\"\n          path: glue/cirq/dist/*.whl\n      - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0\n        with:\n          name: \"dist-stim-sdist\"\n          path: dist/*.tar.gz\n  check_sdist_installs_stim:\n    runs-on: ubuntu-24.04\n    steps:\n    - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n    - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3\n    - run: python -m pip install pybind11~=2.11.1 cibuildwheel~=3.3.1 setuptools wheel\n    - run: python setup.py sdist\n    - run: pip install dist/*.tar.gz\n  check_sdist_installs_sinter:\n    runs-on: ubuntu-24.04\n    steps:\n    - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n    - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3\n    - run: python -m pip install setuptools\n    - run: cd glue/sample && python setup.py sdist\n    - run: pip install glue/sample/dist/*\n    - run: python -c \"import sinter\"\n  merge_upload_artifacts:\n    needs: [\"build_dist\", \"build_sdist\"]\n    runs-on: ubuntu-24.04\n    steps:\n      - name: Merge Artifacts\n        uses: actions/upload-artifact/merge@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4\n        with:\n          name: dist-stim\n          pattern: dist-stim-*\n  upload_dev_release_to_pypi:\n    needs: [\"merge_upload_artifacts\"]\n    if: github.ref == 'refs/heads/main'\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7\n        with:\n          name: dist-stim\n          path: dist-stim\n      - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7\n        with:\n          name: dist-stimcirq\n          path: dist-stimcirq\n      - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7\n        with:\n          name: dist-sinter\n          path: dist-sinter\n      - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1\n        with:\n          user: __token__\n          packages_dir: dist-stim\n          password: ${{ secrets.pypi_token_stim }}\n      - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1\n        with:\n          user: __token__\n          packages_dir: dist-stimcirq\n          password: ${{ secrets.pypi_token_stimcirq }}\n      - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1\n        with:\n          user: __token__\n          packages_dir: dist-sinter\n          password: ${{ secrets.pypi_token_sinter }}\n  run_main:\n    runs-on: ubuntu-24.04\n    steps:\n    - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n    - run: cmake .\n    - run: make stim -j 2\n    - run: echo -e \"H 0 \\n CNOT 0 1 \\n M 0 1\" | out/stim --sample\n  build_bazel:\n    runs-on: ubuntu-24.04\n    steps:\n    - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n    - uses: bazel-contrib/setup-bazel@e403ad507104847c3539436f64a9e9eecc73eeec # 0.8.5\n      with:\n        bazelisk-cache: true\n        disk-cache: ${{ github.workflow }}\n        repository-cache: true\n        bazelisk-version: 1.x\n    - run: bazel build :all\n    - run: bazel test :stim_test\n  build_clang_stim_test:\n    runs-on: 'ubuntu-24.04'\n    steps:\n    - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n    - run: |\n        cd ..\n        git clone https://github.com/google/googletest.git -b release-1.12.1\n        mkdir googletest/build && cd googletest/build\n        cmake .. -DBUILD_GMOCK=OFF\n        make\n        sudo make install\n    - uses: egor-tensin/setup-clang@ef434b41eb33a70396fb336b1bae39c76d740c3d # v1\n      with:\n        version: latest\n        platform: x64\n    - run: cmake . -DCMAKE_C_COMPILER=cc -DCMAKE_CXX_COMPILER=c++\n    - run: cmake --build . --target stim_test\n  build_clang_stim:\n    runs-on: 'ubuntu-24.04'\n    steps:\n      - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n      - run: |\n          cd ..\n          git clone https://github.com/google/googletest.git -b release-1.12.1\n          mkdir googletest/build && cd googletest/build\n          cmake .. -DBUILD_GMOCK=OFF\n          make\n          sudo make install\n      - uses: egor-tensin/setup-clang@ef434b41eb33a70396fb336b1bae39c76d740c3d # v1\n        with:\n          version: latest\n          platform: x64\n      - run: cmake . -DCMAKE_C_COMPILER=cc -DCMAKE_CXX_COMPILER=c++\n      - run: cmake --build . --target stim\n  build_clang_stim_perf:\n    runs-on: 'ubuntu-24.04'\n    steps:\n      - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n      - run: |\n          cd ..\n          git clone https://github.com/google/googletest.git -b release-1.12.1\n          mkdir googletest/build && cd googletest/build\n          cmake .. -DBUILD_GMOCK=OFF\n          make\n          sudo make install\n      - uses: egor-tensin/setup-clang@ef434b41eb33a70396fb336b1bae39c76d740c3d # v1\n        with:\n          version: latest\n          platform: x64\n      - run: cmake . -DCMAKE_C_COMPILER=cc -DCMAKE_CXX_COMPILER=c++\n      - run: cmake --build . --target stim_perf\n  build_lib:\n    runs-on: ubuntu-24.04\n    steps:\n    - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n    - run: cmake .\n    - run: make libstim -j 2\n    - run: echo -e '#include \"stim.h\"\\nint main(int argc,const char **argv) {return !stim::find_bool_argument(\"test\", argc, argv);}' > test.cc\n    - run: g++ -std=c++20 test.cc out/libstim.a -I src\n    - run: ./a.out test\n  build_lib_install:\n    runs-on: ubuntu-24.04\n    steps:\n    - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n    - run: mkdir install_dir\n    - run: cmake . -DCMAKE_INSTALL_PREFIX=install_dir\n    - run: make -j 2\n    - run: make install\n    - run: echo -e '#include \"stim.h\"\\nint main(int argc,const char **argv) {return !stim::find_bool_argument(\"test\", argc, argv);}' > test.cc\n    - run: g++ -std=c++20 test.cc install_dir/lib/libstim.a -I install_dir/include\n    - run: ./a.out test\n    - run: echo -e \"H 0 \\n CNOT 0 1 \\n M 0 1\" | install_dir/bin/stim --sample\n  benchmark_windows:\n    runs-on: windows-2025\n    steps:\n      - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n      - uses: microsoft/setup-msbuild@c26a08ba26249b81327e26f6ef381897b6a8754d # v1.0.2\n      - run: cmake .\n      - run: MSBuild.exe stim_perf.vcxproj /p:Configuration=Release /p:OutDir=msbuild_out /p:O=2\n      - run: msbuild_out/stim_perf.exe\n  benchmark:\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        simd_width: [64, 128, 256]\n    steps:\n    - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n    - run: cmake . -DSIMD_WIDTH=${{ matrix.simd_width }}\n    - run: make stim_perf -j 2\n    - run: out/stim_perf\n  test:\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        simd_width: [64, 128, 256]\n    steps:\n    - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n    - run: |\n        cd ..\n        git clone https://github.com/google/googletest.git -b release-1.12.1\n        mkdir googletest/build && cd googletest/build\n        cmake .. -DBUILD_GMOCK=OFF\n        make\n        sudo make install\n    - run: cmake . -DSIMD_WIDTH=${{ matrix.simd_width }}\n    - run: make stim_test -j 2\n    - run: out/stim_test\n  test_o3:\n    runs-on: ubuntu-24.04\n    steps:\n    - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e # v1\n    - run: |\n        cd ..\n        git clone https://github.com/google/googletest.git -b release-1.12.1\n        mkdir googletest/build && cd googletest/build\n        cmake .. -DBUILD_GMOCK=OFF\n        make\n        sudo make install\n    - run: cmake . -DSIMD_WIDTH=256\n    - run: make stim_test_o3 -j 2\n    - run: out/stim_test_o3\n  test_generated_docs_are_fresh:\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3\n      - uses: bazel-contrib/setup-bazel@e403ad507104847c3539436f64a9e9eecc73eeec # 0.8.5\n        with:\n          bazelisk-cache: true\n          disk-cache: ${{ github.workflow }}\n          repository-cache: true\n          bazelisk-version: 1.x\n      - uses: actions/setup-node@f1f314fca9dfce2769ece7d933488f076716723e # v1\n        with:\n          node-version: 16.x\n      - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6\n        with:\n          python-version: '3.13'\n      - run: bazel build :stim_dev_wheel\n      - run: pip install bazel-bin/stim-0.0.dev0-py3-none-any.whl\n      - run: diff <(python dev/gen_stim_api_reference.py -dev) doc/python_api_reference_vDev.md\n      - run: diff <(python dev/gen_stim_stub_file.py -dev) glue/python/src/stim/__init__.pyi\n      - run: diff <(python dev/gen_stim_stub_file.py -dev) doc/stim.pyi\n      - run: diff <(python -c \"import stim; stim.main(command_line_args=['help', 'gates_markdown'])\") doc/gates.md\n      - run: diff <(python -c \"import stim; stim.main(command_line_args=['help', 'formats_markdown'])\") doc/result_formats.md\n      - run: diff <(python -c \"import stim; stim.main(command_line_args=['help', 'commands_markdown'])\") doc/usage_command_line.md\n      - run: diff <(dev/gen_known_gates_for_js.sh) glue/crumble/test/generated_gate_name_list.test.js\n      - run: python doc/stim.pyi\n      - run: npm install -g rollup@3.21.2 uglify-js@3.17.4\n      - run: diff <(dev/compile_crumble_into_cpp_string_file.sh) src/stim/diagram/crumble_data.cc\n      - run: pip install -e glue/sample\n      - run: diff <(python dev/gen_sinter_api_reference.py -dev) doc/sinter_api.md\n  test_generated_file_lists_are_fresh:\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      - run: dev/regen_file_lists.sh /tmp\n      - run: diff /tmp/perf_files file_lists/perf_files\n      - run: diff /tmp/pybind_files file_lists/pybind_files\n      - run: diff /tmp/source_files_no_main file_lists/source_files_no_main\n      - run: diff /tmp/test_files file_lists/test_files\n  test_pybind:\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3\n      - uses: bazel-contrib/setup-bazel@e403ad507104847c3539436f64a9e9eecc73eeec # 0.8.5\n        with:\n          bazelisk-cache: true\n          disk-cache: ${{ github.workflow }}\n          repository-cache: true\n          bazelisk-version: 1.x\n      - run: bazel build :stim_dev_wheel\n      - run: pip install bazel-bin/stim-0.0.dev0-py3-none-any.whl\n      - run: pip install pytest\n      - run: pytest src\n      - run: dev/doctest_proper.py --module stim\n  test_stimcirq:\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3\n      - uses: bazel-contrib/setup-bazel@e403ad507104847c3539436f64a9e9eecc73eeec # 0.8.5\n        with:\n          bazelisk-cache: true\n          disk-cache: ${{ github.workflow }}\n          repository-cache: true\n          bazelisk-version: 1.x\n      - run: bazel build :stim_dev_wheel\n      - run: pip install bazel-bin/stim-0.0.dev0-py3-none-any.whl\n      - run: pip install -e glue/cirq\n      - run: pip install pytest\n      - run: pytest glue/cirq\n      - run: dev/doctest_proper.py --module stimcirq --import cirq sympy\n  test_sinter:\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3\n      - uses: bazel-contrib/setup-bazel@e403ad507104847c3539436f64a9e9eecc73eeec # 0.8.5\n        with:\n          bazelisk-cache: true\n          disk-cache: ${{ github.workflow }}\n          repository-cache: true\n          bazelisk-version: 1.x\n      - run: bazel build :stim_dev_wheel\n      - run: pip install bazel-bin/stim-0.0.dev0-py3-none-any.whl\n      - run: pip install -e glue/sample\n      - run: pip install pytest pymatching fusion-blossom~=0.1.4 mwpf~=0.1.5\n      - run: pytest glue/sample\n      - run: dev/doctest_proper.py --module sinter\n      - run: sinter help\n  test_stimzx:\n    runs-on: ubuntu-24.04\n    steps:\n      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      - uses: actions/setup-python@3542bca2639a428e1796aaa6a2ffef0c0f575566 # v3\n      - uses: bazel-contrib/setup-bazel@e403ad507104847c3539436f64a9e9eecc73eeec # 0.8.5\n        with:\n          bazelisk-cache: true\n          disk-cache: ${{ github.workflow }}\n          repository-cache: true\n          bazelisk-version: 1.x\n      - run: bazel build :stim_dev_wheel\n      - run: pip install bazel-bin/stim-0.0.dev0-py3-none-any.whl\n      - run: pip install -e glue/zx\n      - run: pip install pytest\n      - run: pytest glue/zx\n      - run: dev/doctest_proper.py --module stimzx\n  test_stimjs:\n    runs-on: ubuntu-22.04\n    steps:\n      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14\n        with:\n          version: 4.0.1\n          actions-cache-folder: 'emsdk-cache'\n      - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4\n        with:\n          node-version: 18.x\n      - run: npm install\n      - run: bash glue/javascript/build_wasm.sh\n      - run: node puppeteer_run_tests.js\n  test_crumble:\n    runs-on: ubuntu-24.04\n    steps:\n    - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n    - uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3\n      with:\n        node-version: 16\n    - run: node glue/crumble/run_tests_headless.js\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea/*\ncmake-build-debug/*\na.out\nperf.data\nperf.data.old\nCMakeFiles/*\nCMakeCache.txt\ngoogletest-build/*\ngoogletest-download/*\ngoogletest-src\ncmake_install.cmake\nMakefile\nlib\nout\nstim.cbp\ndata/*\n_deps/*\nbazel-*\npython_build_stim/*\n*.egg-*\nstim.cpython*\ndist\nMANIFEST\n*.whl\n*.swp\n__pycache__\npip-wheel-metadata/*\nwheelhouse/*\n*.pyd\nvenv\n.venv\n**/LastTest.log\n*.so\n.clwb/*\n.cmake/*\ncoverage/*\ncmake-build-debug-coverage/*\ncompile_commands.json\n.cache\nbuild.ninja\n.ninja_deps\n.ninja_log\n.pytest_cache\nnode_modules\nMODULE.bazel.lock\n.ninja_lock\n"
  },
  {
    "path": ".markdownlintrc",
    "content": "{ // -*- jsonc -*-\n  // Copyright 2025 Google LLC\n  //\n  // Licensed under the Apache License, Version 2.0 (the \"License\");\n  // you may not use this file except in compliance with the License.\n  // You may obtain a copy of the License at\n  //\n  //     https://www.apache.org/licenses/LICENSE-2.0\n  //\n  // Unless required by applicable law or agreed to in writing, software\n  // distributed under the License is distributed on an \"AS IS\" BASIS,\n  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  // See the License for the specific language governing permissions and\n  // limitations under the License.\n\n  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n  // Markdownlint linter configuration for this project.\n  //\n  // Note: there are multiple programs programs named \"markdownlint\". We use\n  // https://github.com/igorshubovych/markdownlint-cli/, which is the one you\n  // get with \"brew install markdownlint\" on MacOS.\n  //\n  // These settings try to stay close to the Google Markdown Style as\n  // described at https://google.github.io/styleguide/docguide/style.html\n  // with very few differences.\n  //\n  // For a list of configuration options, see the following page:\n  // https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md\n  // (Beware that the above looks similar but is NOT the same as the page\n  // https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md.)\n  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n  \"$schema\": \"https://raw.githubusercontent.com/DavidAnson/markdownlint/main/schema/markdownlint-config-schema.json\",\n\n  // Require ATX-style headings.\n  // https://google.github.io/styleguide/docguide/style.html#atx-style-headings\n  \"headings\": {\n    \"style\": \"atx\"\n  },\n\n  // Google style does not require that the first line of a file is a heading\n  // for the title; it only states that the first heading should be a level 1.\n  // https://google.github.io/styleguide/docguide/style.html#document-layout\n  \"first-line-heading\": false,\n\n  // The Google style does not define what to do about trailing punctuation in\n  // headings. The markdownlint default disallows exclamation points, which\n  // seems likely to be more annoying than useful – I have definitely seen\n  // people use exclamation points in headings in README files on GitHub.\n  // This setting removes exclamation point from the banned characters.\n  \"no-trailing-punctuation\": {\n    \"punctuation\": \".,;:。，；：\"\n  },\n\n  // No trailing spaces.\n  // https://google.github.io/styleguide/docguide/style.html#trailing-whitespace\n  \"whitespace\": {\n    \"br_spaces\": 0\n  },\n\n  // Google style is 80 characters.\n  // Google style exempts some constructs from the line-length limit:\n  // https://google.github.io/styleguide/docguide/style.html#exceptions\n  \"line-length\": {\n    \"line_length\": 120,\n    \"code_block_line_length\": 120,\n    \"heading_line_length\": 120,\n    \"code_blocks\": false,\n    \"headings\": false,\n    \"tables\": false\n  },\n\n  // Google Markdown style specifies 2 spaces after item numbers, 3 spaces\n  // after bullets, so that the text itself is consistently indented 4 spaces.\n  // https://google.github.io/styleguide/docguide/style.html#nested-list-spacing\n  \"list-marker-space\": {\n    \"ol_multi\": 2,\n    \"ol_single\": 2,\n    \"ul_multi\": 3,\n    \"ul_single\": 3\n  },\n\n  \"ul-indent\": {\n    \"indent\": 4\n  },\n\n  // Bare URLs are allowed in GitHub-flavored Markdown and in Google’s style.\n  \"no-bare-urls\": false,\n\n  // Basic Markdown allows raw HTML. Both GitHub & PyPI support subsets of\n  // HTML, though it's unclear what subset PyPI supports. Google's style guide\n  // recommends against using raw HTML, but does allow it. (C.f. the bottom of\n  // https://google.github.io/styleguide/docguide/style.html) Google's in-house\n  // documentation system allows many inline and block-level tags, but strips\n  // others that can pose security risks (e.g., <object> and standalone <svg>).\n  // The list below tries to capture the intersection of what GitHub allows\n  // (c.f. https://github.com/github/markup/issues/245#issuecomment-682231577),\n  // what PyPI seems to allow, what Google allows, and what seems likely to be\n  // most useful in situations where someone needs to reach for HTML.\n  \"html\": {\n    \"allowed_elements\": [\n      \"a\",\n      \"abbr\",\n      \"b\",\n      \"blockquote\",\n      \"br\",\n      \"caption\",\n      \"cite\",\n      \"code\",\n      \"dd\",\n      \"del\",\n      \"details\",\n      \"dfn\",\n      \"div\",\n      \"dl\",\n      \"dt\",\n      \"em\",\n      \"figcaption\",\n      \"figure\",\n      \"h1\",\n      \"h2\",\n      \"h3\",\n      \"h4\",\n      \"h5\",\n      \"h6\",\n      \"hr\",\n      \"i\",\n      \"img\",\n      \"ins\",\n      \"kbd\",\n      \"li\",\n      \"mark\",\n      \"ol\",\n      \"p\",\n      \"picture\",\n      \"pre\",\n      \"q\",\n      \"s\",\n      \"samp\",\n      \"small\",\n      \"span\",\n      \"strong\",\n      \"sub\",\n      \"summary\",\n      \"sup\",\n      \"table\",\n      \"tbody\",\n      \"td\",\n      \"tfoot\",\n      \"th\",\n      \"thead\",\n      \"time\",\n      \"tr\",\n      \"tt\",\n      \"ul\",\n      \"var\",\n      \"wbr\"\n    ]\n  }\n}\n"
  },
  {
    "path": "BUILD",
    "content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:packaging.bzl\", \"py_wheel\")\n\nSOURCE_FILES_NO_MAIN = glob(\n    [\n        \"src/**/*.cc\",\n        \"src/**/*.h\",\n        \"src/**/*.inl\",\n    ],\n    exclude = glob([\n        \"src/**/*.test.cc\",\n        \"src/**/*.test.h\",\n        \"src/**/*.perf.cc\",\n        \"src/**/*.perf.h\",\n        \"src/**/*.pybind.cc\",\n        \"src/**/*.pybind.h\",\n        \"src/**/main.cc\",\n    ]),\n)\n\nTEST_FILES = glob(\n    [\n        \"src/**/*.test.cc\",\n        \"src/**/*.test.h\",\n    ],\n)\n\nPERF_FILES = glob(\n    [\n        \"src/**/*.perf.cc\",\n        \"src/**/*.perf.h\",\n    ],\n)\n\nPYBIND_FILES = glob(\n    [\n        \"src/**/*.pybind.cc\",\n        \"src/**/*.pybind.h\",\n    ],\n)\n\ncc_library(\n    name = \"stim_lib\",\n    srcs = SOURCE_FILES_NO_MAIN,\n    copts = [\n        \"-std=c++20\",\n    ],\n    includes = [\"src/\"],\n)\n\ncc_binary(\n    name = \"stim\",\n    srcs = SOURCE_FILES_NO_MAIN + glob([\"src/**/main.cc\"]),\n    copts = [\n        \"-std=c++20\",\n        \"-march=native\",\n        \"-O3\",\n    ],\n    includes = [\"src/\"],\n)\n\ncc_binary(\n    name = \"stim_benchmark\",\n    srcs = SOURCE_FILES_NO_MAIN + PERF_FILES,\n    copts = [\n        \"-std=c++20\",\n        \"-march=native\",\n        \"-O3\",\n    ],\n    includes = [\"src/\"],\n)\n\ncc_test(\n    name = \"stim_test\",\n    srcs = SOURCE_FILES_NO_MAIN + TEST_FILES,\n    copts = [\n        \"-std=c++20\",\n        \"-march=native\",\n    ],\n    data = glob([\"testdata/**\"]),\n    includes = [\"src/\"],\n    deps = [\n        \"@googletest//:gtest\",\n        \"@googletest//:gtest_main\",\n    ],\n)\n\ncc_binary(\n    name = \"stim.so\",\n    srcs = SOURCE_FILES_NO_MAIN + PYBIND_FILES,\n    copts = [\n        \"-O3\",\n        \"-std=c++20\",\n        \"-fvisibility=hidden\",\n        \"-march=native\",\n        \"-DSTIM_PYBIND11_MODULE_NAME=stim\",\n        \"-DVERSION_INFO=0.0.dev0\",\n    ],\n    includes = [\"src/\"],\n    linkshared = 1,\n    deps = [\"@pybind11//:pybind11\"],\n)\n\ngenrule(\n    name = \"stim_wheel_files\",\n    srcs = [\"doc/stim.pyi\"],\n    outs = [\"stim.pyi\"],\n    cmd = \"cp $(location doc/stim.pyi) $@\",\n)\n\npy_wheel(\n    name = \"stim_dev_wheel\",\n    distribution = \"stim\",\n    requires = [\"numpy\"],\n    version = \"0.0.dev0\",\n    deps = [\n        \":stim.so\",\n        \":stim_wheel_files\",\n    ],\n)\n"
  },
  {
    "path": "CITATION.cff",
    "content": "# Citation information for this repository.                         -*- yaml -*-\n#\n# CITATION.cff files provide human- & machine-readable citation information for\n# software and datasets. GitHub, Zenodo, and the Zotero browser plugin all use\n# CFF files automatically if provided. https://citation-file-format.github.io/.\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\ncff-version: 1.2.0\nmessage: If you use Stim, please cite it using this metadata.\n\n# CITATION.cff files describe how to cite software or datasets, with the goal of\n# making software and data be citable in their own right. However, sometimes\n# projects want citations to go to a paper instead. 'Preferred-citation' serves\n# to communicate that. The distinction matters in different situations. If this\n# field is present, GitHub uses the value for the \"cite this repository\" button\n# and ignores the rest of this file; conversely, the Zenodo-GitHub integration\n# ignores this field when creating an entry for a new software release because\n# the Zenodo entry is specifically about the software in this repository.\npreferred-citation:\n  type: article\n  authors:\n    - family-names: Gidney\n      given-names: Craig\n  title: 'Stim: a fast stabilizer circuit simulator'\n  journal: Quantum\n  year: 2021\n  month: 7\n  volume: 5\n  start: 497\n  issn: 2521-327X\n  url: https://doi.org/10.22331/q-2021-07-06-497\n  publisher:\n    name: >-\n      Verein zur Förderung des Open Access Publizierens in den\n      Quantenwissenschaften\n\n# The remaining metadata in this file describes the current software release.\n\ntitle: Stim\nabstract: >-\n  Stim is a tool for high performance simulation and analysis of quantum\n  stabilizer circuits, especially quantum error correction (QEC) circuits.\nauthors:\n  - family-names: Gidney\n    given-names: Craig\nversion: 1.14.0\ndate-released: 2024-09-24\nurl: https://github.com/quantumlib/stim\nrepository-code: https://github.com/quantumlib/stim\nlicense: Apache-2.0\ntype: software\nidentifiers:\n  - description: The GitHub repository for Stim\n    value: https://github.com/quantumlib/Stim\n    type: url\n  - description: PyPI project for Stim\n    value: https://pypi.org/project/Stim\n    type: url\n  - description: Publication about Stim\n    value: 10.22331/q-2021-07-06-497\n    type: doi\nkeywords:\n  - algorithms\n  - API\n  - application programming interface\n  - C++\n  - Clifford gates\n  - Clifford operations\n  - high performance\n  - open-source software\n  - physics\n  - Python\n  - QEC\n  - quantum\n  - quantum algorithms\n  - quantum circuits\n  - quantum computing\n  - quantum error correction\n  - quantum error decoder\n  - quantum gates\n  - quantum programming\n  - quantum simulation\n  - quantum state\n  - qubit\n  - science\n  - SDK\n  - simulation\n  - simulator\n  - software\n  - software development toolkit\n  - stabilizer circuits\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\ncmake_minimum_required(VERSION 3.13)\nproject(stim)\ninclude_directories(src)\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY out)\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY out)\nset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY out)\n\n# Convert desired SIMD_WIDTH into machine architecture flags.\n\nif (CMAKE_SYSTEM_PROCESSOR MATCHES \"^(x86_64|I386|ARM64)$\")\n    if(NOT(SIMD_WIDTH))\n        set(MACHINE_FLAG \"-march=native\")\n    elseif(SIMD_WIDTH EQUAL 256)\n        set(MACHINE_FLAG \"-mavx2\" \"-msse2\")\n    elseif(SIMD_WIDTH EQUAL 128)\n        set(MACHINE_FLAG \"-mno-avx2\" \"-msse2\")\n    elseif(SIMD_WIDTH EQUAL 64)\n        set(MACHINE_FLAG \"-mno-avx2\" \"-mno-sse2\")\n    endif()\nelse ()\n    set(MACHINE_FLAG \"\")\nendif()\n\n# make changes to file_lists trigger a reconfigure\nset_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS file_lists/source_files_no_main)\nset_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS file_lists/test_files)\nset_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS file_lists/perf_files)\nset_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS file_lists/pybind_files)\n\nfile(STRINGS file_lists/source_files_no_main SOURCE_FILES_NO_MAIN)\nfile(STRINGS file_lists/test_files TEST_FILES)\nfile(STRINGS file_lists/perf_files PERF_FILES)\nfile(STRINGS file_lists/pybind_files PYBIND_FILES)\n\nadd_executable(stim src/main.cc ${SOURCE_FILES_NO_MAIN})\nif(NOT(MSVC))\n    target_compile_options(stim PRIVATE -O3 -Wall -Wpedantic -fno-strict-aliasing ${MACHINE_FLAG})\n    target_link_options(stim PRIVATE -O3)\nelse()\n    target_compile_options(stim PRIVATE ${MACHINE_FLAG} /O1)\nendif()\ninstall(TARGETS stim RUNTIME DESTINATION bin)\n\nadd_library(libstim ${SOURCE_FILES_NO_MAIN})\nset_target_properties(libstim PROPERTIES PREFIX \"\")\ntarget_include_directories(libstim PUBLIC src)\nif(NOT(MSVC))\n    target_compile_options(libstim PRIVATE -O3 -Wall -Wpedantic -fPIC -fno-strict-aliasing ${MACHINE_FLAG})\n    target_link_options(libstim PRIVATE -O3)\nelse()\n    target_compile_options(libstim PRIVATE ${MACHINE_FLAG} /O1)\nendif()\ninstall(TARGETS libstim LIBRARY DESTINATION)\ninstall(DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}/src/\" DESTINATION \"include\" FILES_MATCHING PATTERN \"*.h\" PATTERN \"*.inl\")\n\nadd_executable(stim_perf ${SOURCE_FILES_NO_MAIN} ${PERF_FILES})\nif(NOT(MSVC))\n    target_compile_options(stim_perf PRIVATE -Wall -Wpedantic -O3 -fno-strict-aliasing ${MACHINE_FLAG})\n    target_link_options(stim_perf PRIVATE)\nelse()\n    target_compile_options(stim_perf PRIVATE ${MACHINE_FLAG} /O1)\nendif()\n\nfind_package(GTest QUIET)\nif(${GTest_FOUND})\n    add_executable(stim_test ${SOURCE_FILES_NO_MAIN} ${TEST_FILES})\n    target_link_libraries(stim_test GTest::gtest GTest::gtest_main)\n    target_compile_options(stim_test PRIVATE -Wall -Wpedantic -g -fno-omit-frame-pointer -fno-strict-aliasing -fsanitize=undefined -fsanitize=address ${MACHINE_FLAG})\n    target_link_options(stim_test PRIVATE -g -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address)\n\n    add_executable(stim_test_o3 ${SOURCE_FILES_NO_MAIN} ${TEST_FILES})\n    target_link_libraries(stim_test_o3 GTest::gtest GTest::gtest_main)\n    target_compile_options(stim_test_o3 PRIVATE -O3 -Wall -Wpedantic -fno-strict-aliasing ${MACHINE_FLAG})\n    target_link_options(stim_test_o3 PRIVATE)\nelse()\n    message(\"WARNING: Skipped stim_test target. `GTest` not found. To fix, follow Standalone CMake Project install instructions at https://github.com/google/googletest/blob/master/googletest/README.md\")\nendif()\n\nfind_package(Python COMPONENTS Interpreter Development)\nfind_package(pybind11 CONFIG)\nif (${pybind11_FOUND} AND ${Python_FOUND})\n  pybind11_add_module(stim_python_bindings ${PYBIND_FILES} ${SOURCE_FILES_NO_MAIN})\n  set_target_properties(stim_python_bindings PROPERTIES OUTPUT_NAME stim)\n  add_compile_definitions(STIM_PYBIND11_MODULE_NAME=stim)\n  if(NOT(MSVC))\n      target_compile_options(stim_python_bindings PRIVATE -O3 -Wall -Wpedantic -fno-strict-aliasing ${MACHINE_FLAG})\n      target_link_options(stim_python_bindings PRIVATE -O3)\n  else()\n      target_compile_options(stim_python_bindings PRIVATE ${MACHINE_FLAG} /O1)\n  endif()\n\nelse()\n  message(\"WARNING: Skipped stim_python_bindings target. `pybind11` not found. To fix, install pybind11. On debian based distributions, the package name is `pybind11-dev`\")\nendif()\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of\nexperience, education, socio-economic status, nationality, personal appearance,\nrace, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n*   Using welcoming and inclusive language\n*   Being respectful of differing viewpoints and experiences\n*   Gracefully accepting constructive criticism\n*   Focusing on what is best for the community\n*   Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n*   The use of sexualized language or imagery and unwelcome sexual attention or\n    advances\n*   Trolling, insulting/derogatory comments, and personal or political attacks\n*   Public or private harassment\n*   Publishing others' private information, such as a physical or electronic\n    address, without explicit permission\n*   Other conduct which could reasonably be considered inappropriate in a\n    professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, or to ban temporarily or permanently any\ncontributor for other behaviors that they deem inappropriate, threatening,\noffensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\nThis Code of Conduct also applies outside the project spaces when the Project\nStewards have a reasonable belief that an individual's behavior may have a\nnegative impact on the project or its community.\n\n## Conflict Resolution\n\nWe do not believe that all conflict is bad; healthy debate and disagreement\noften yield positive results. However, it is never okay to be disrespectful or\nto engage in behavior that violates the project’s Code of Conduct.\n\nIf you see someone violating the Code of Conduct, you are encouraged to address\nthe behavior directly with those involved. Many issues can be resolved quickly\nand easily, and this gives people more control over the outcome of their\ndispute. If you are unable to resolve the matter for any reason, or if the\nbehavior is threatening or harassing, report it. We are dedicated to providing\nan environment where participants feel welcome and safe.\n\nReports should be directed to quantumai-oss-maintainers@googlegroups.com,\nthe project stewards at Google Quantum AI. They will then work with a committee\nconsisting of representatives from the Open Source Programs Office and the\nGoogle Open Source Strategy team. If for any reason you are uncomfortable\nreaching out to the Project Stewards, please email opensource@google.com.\n\nWe will investigate every complaint, but you may not receive a direct response.\nWe will use our discretion in determining when and how to follow up on reported\nincidents, which may range from not taking action to permanent expulsion from\nthe project and project-sponsored spaces. We will notify the accused of the\nreport and provide them an opportunity to discuss it before any action is taken.\nThe identity of the reporter will be omitted from the details of the report\nsupplied to the accused. In potentially harmful situations, such as ongoing\nharassment or threats to anyone's safety, we may take action without notice.\n\n## Attribution\n\nThis Code of Conduct is adapted from the Contributor Covenant, version 1.4,\navailable at\nhttps://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to contribute\n\nWe'd love to accept your patches and contributions to this project. We do have\nsome guidelines to follow, covered in this document, but don't be concerned\nabout getting everything right the first time! Create a pull request (discussed\nbelow) and we'll nudge you in the right direction.\n\n## Before you begin\n\n### Sign our Contributor License Agreement\n\nContributions to this project must be accompanied by a [Contributor License\nAgreement](https://cla.developers.google.com/about) (CLA). You (or your\nemployer) retain the copyright to your contribution; the CLA simply gives us\npermission to use and redistribute your contributions as part of the project.\nPlease visit https://cla.developers.google.com/ to see your current agreements\non file or to sign a new one. You generally only need to submit a Google CLA\nonce, so if you've already submitted one (even if it was for a different\nproject), you probably don't need to do it again.\n\n> [!WARNING]\n> Please note carefully clauses [#5](https://cla.developers.google.com/about/google-corporate#:~:text=You%20represent%20that%20each%20of%20Your%20Contributions%20is%20Your%20original%20creation)\n> and [#7](https://cla.developers.google.com/about/google-corporate#:~:text=Should%20You%20wish%20to%20submit%20work%20that%20is%20not%20Your%20original%20creation%2C%20You%20may%20submit%20it%20to%20Google%20separately)\n> in the CLA. Any code that you contribute to this project must be **your**\n> original creation. Code generated by artificial intelligence tools **does\n> not** qualify as your original creation.\n\n### Review our community guidelines\n\nWe have a [code of conduct](CODE_OF_CONDUCT.md) to make the Stim project an open\nand welcoming community environment. Please make sure to read and abide by the\ncode of conduct.\n\n## Contribution process\n\nAll submissions, including submissions by project members, require review. We\nuse the tools provided by GitHub for [pull\nrequests](https://help.github.com/articles/about-pull-requests/) for this\npurpose. The preferred manner for submitting pull requests is to fork the Stim\n[repository](https://github.com/quantumlib/Stim), create a [git\nbranch](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) in\nthis fork to do your work, and when ready, create a pull request from this\nbranch to the main Stim repository.\n\n### Repository forks\n\n1.  Fork the Stim repository (you can use the _Fork_ button in upper right\n    corner of the [repository page](https://github.com/quantumlib/Stim)).\n    Forking creates a new GitHub repo at the location\n    `https://github.com/USERNAME/Stim`, where `USERNAME` is your GitHub user\n    name.\n\n1.  Clone (using `git clone`) or otherwise download your forked repository to\n    your local computer, so that you have a local copy where you can do your\n    development work using your preferred editor and development tools.\n\n1.  Check out the `main` branch and create a new git branch from `main`:\n\n    ```shell\n    git checkout main -b YOUR_BRANCH_NAME\n    ```\n\n    where `YOUR_BRANCH_NAME` is the name of your new branch.\n\n### Development and testing\n\nPlease follow the detailed instructions in\n[`doc/developer_documentation.md`](doc/developer_documentation.md) for\ndeveloping and testing Stim.\n\n### Pull requests and code reviews\n\n1.  If your local copy has drifted out of sync with the `main` branch of the\n    main Stim repository, you may need to merge the latest changes into\n    your branch. To do this, first update your local `main` and then merge your\n    local `main` into your branch:\n\n    ```shell\n    # Track the upstream repo (if your local repo hasn't):\n    git remote add upstream https://github.com/quantumlib/Stim.git\n\n    # Update your local main.\n    git fetch upstream\n    git checkout main\n    git merge upstream/main\n    # Merge local main into your branch.\n    git checkout YOUR_BRANCH_NAME\n    git merge main\n    ```\n\n    If git reports conflicts during one or both of these merge processes, you\n    may need to [resolve the merge conflicts](\n    https://docs.github.com/articles/about-merge-conflicts) before continuing.\n\n1.  Finally, push your changes to your fork of the Stim repo on GitHub:\n\n    ```shell\n    git push origin YOUR_BRANCH_NAME\n    ```\n\n1.  Now when you navigate to the Stim repository on GitHub\n    (https://github.com/quantumlib/Stim), you should see the option to create a\n    new pull request from your forked repository. Alternatively, you can create\n    the pull request by navigating to the \"Pull requests\" tab near the top of\n    the page, and selecting the appropriate branches.\n\n1.  A reviewer from the Stim team will comment on your code and may ask for\n    changes. You can perform the necessary changes locally, commit them to your\n    branch as usual, and then push changes to your fork on GitHub following the\n    same process as above. When you do that, GitHub will update the code in the\n    pull request automatically.\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "MANIFEST.in",
    "content": "include glue/python/src/stim/__init__.pyi\ninclude glue/python/README.md\nrecursive-include src *.cc *.h *.inl\n"
  },
  {
    "path": "MODULE.bazel",
    "content": "bazel_dep(name = \"googletest\", version = \"1.14.0\")\nbazel_dep(name = \"pybind11_bazel\", version = \"2.11.1\")\n"
  },
  {
    "path": "README.md",
    "content": "# Stim\n\n<img align=\"right\" width=\"125em\" alt=\"Stim logo\" src=\"https://raw.githubusercontent.com/quantumlib/Stim/refs/heads/main/doc/logo_128x128.svg\">\n\nHigh-performance simulation of quantum stabilizer circuits for quantum error correction.\n\n◼︎︎&nbsp;&nbsp;[What is Stim?](#what-is-stim)<br>\n◼︎︎&nbsp;&nbsp;[How do I use Stim?](#how-use-stim)<br>\n◼︎&nbsp;&nbsp;[How does Stim work?](#how-stim-work)<br>\n◼︎&nbsp;&nbsp;[How do I cite Stim?](#how-cite-stim)<br>\n◼︎&nbsp;&nbsp;[*Subproject*: Sinter decoding sampler](glue/sample)<br>\n◼︎&nbsp;&nbsp;[*Subproject*: Crumble interactive editor](glue/crumble)<br>\n\n## <a name=\"what-is-stim\"></a>What is Stim?\n\nStim is a tool for high performance simulation and analysis of quantum stabilizer circuits,\nespecially quantum error correction (QEC) circuits.\nTypically Stim is used as a Python package (`pip install stim`), though Stim can also be used as\na command-line tool or a C++ library.\n\n*   [Watch the 15 minute lightning talk presenting Stim at QPL2021](https://youtu.be/7m_JrJIskPM?t=895)\n*   [Watch Stim being used to estimate the threshold of the honeycomb code over a\n    weekend](https://www.youtube.com/watch?v=E9yj0o1LGII)\n\nStim's key features:\n\n1.  **<em>Really</em> fast simulation of stabilizer circuits**.\n    Have a circuit with thousands of qubits and millions of operations?\n    [`stim.Circuit.compile_sampler()`](doc/python_api_reference_vDev.md#stim.Circuit.compile_sampler) will perform a few\n    seconds of analysis and then produce an object that can sample shots at kilohertz rates.\n\n2.  **Semi-automatic decoder configuration**.\n    [`stim.Circuit.detector_error_model()`](doc/python_api_reference_vDev.md#stim.Circuit.detector_error_model) converts\n    a noisy circuit into a detector error model (a [Tanner graph](https://en.wikipedia.org/wiki/Tanner_graph)) which can\n    be used to configure decoders.\n    Adding the option `decompose_operations=True` will additionally suggest how hyper errors can be decomposed into\n    graphlike errors, making it easier to configure matching-based decoders.\n\n3.  **Useful building blocks for working with stabilizers**, such as\n    [`stim.PauliString`](doc/python_api_reference_vDev.md#stim.PauliString),\n    [`stim.Tableau`](doc/python_api_reference_vDev.md#stim.Tableau),\n    and [`stim.TableauSimulator`](doc/python_api_reference_vDev.md#stim.TableauSimulator).\n\nStim's main limitations are:\n\n1.  There is no support for non-Clifford operations, such as T gates and Toffoli gates. Only stabilizer operations are\n    supported.\n\n2.  `stim.Circuit` only supports Pauli noise channels (eg. no amplitude decay). For more complex noise you must manually\n    drive a `stim.TableauSimulator`.\n\n3.  `stim.Circuit` only supports single-control Pauli feedback. For multi-control feedback, or non-Pauli feedback, you\n    must manually drive a `stim.TableauSimulator`.\n\nStim's design philosophy:\n\n*   **Performance is king.**\n    The goal is not to be fast *enough*, it is to be fast in an absolute sense.\n    Think of it this way.\n    The difference between doing one thing per second (human speeds) and doing ten billion things\n    per second (computer speeds) is 100 decibels (100 factors of 1.26).\n    Because software slowdowns tend to compound exponentially, the choices we make can be thought of multiplicatively;\n    they can be thought of as spending or saving decibels.\n    For example, under default usage, Python is 100 times slower than C++.\n    That's 20dB of the 100dB budget!\n    A *fifth* of the multiplicative performance budget allocated to *language choice*!\n    Too expensive!\n    Although Stim will never achieve the glory of [30 GiB per second of\n    FizzBuzz](https://codegolf.stackexchange.com/a/236630/74349), it at least *wishes* it could.\n\n*   **Bottom up.**\n    Stim is intended to be like an assembly language: a mostly straightforward layer upon which more complex layers\n    can be built.\n    The user may define QEC constructions at some high level, perhaps as a set of stabilizers or as a parity check\n    matrix, but these concepts are explained to Stim at a low level (e.g., as circuits).\n    Stim is not necessarily the abstraction that the user wants, but Stim wants to implement low-level\n    pieces simple enough and fast enough that the high-level pieces that the user wants can be built on top.\n\n*   **Backwards compatibility.**\n    Stim's Python package uses semantic versioning.\n    Within a major version (1.X), Stim guarantees backwards compatibility of its Python API and of its command-line API.\n    Note Stim DOESN'T guarantee backwards compatibility of the underlying C++ API.\n\n## <a name=\"how-use-stim\"></a>How do I use Stim?\n\nSee the [Getting Started Notebook](doc/getting_started.ipynb).\n\nStuck?\n[Get help on the quantum computing stack exchange](https://quantumcomputing.stackexchange.com)\nand use the [`stim`](https://quantumcomputing.stackexchange.com/questions/tagged/stim) tag.\n\nSee the reference documentation:\n\n*   [Stim Python API Reference](doc/python_api_reference_vDev.md)\n*   [Stim Supported Gates Reference](doc/gates.md)\n*   [Stim Command Line Reference](doc/usage_command_line.md)\n*   [Stim Circuit File Format (.stim)](doc/file_format_stim_circuit.md)\n*   [Stim Detector Error model Format (.dem)](doc/file_format_dem_detector_error_model.md)\n*   [Stim Results Format Reference](doc/result_formats.md)\n*   [Stim Internal Developer Reference](doc/developer_documentation.md)\n\n## <a name=\"how-stim-work\"></a>How does Stim work?\n\nSee [the paper describing Stim](https://quantum-journal.org/papers/q-2021-07-06-497/).\nStim makes three core improvements over previous stabilizer simulators:\n\n1.  **Vectorized code.**\n    Stim's hot loops are heavily vectorized, using 256 bit wide AVX instructions.\n    This makes them very fast.\n    For example, Stim can multiply Pauli strings with 100 billion terms in one second.\n\n2.  **Reference Frame Sampling.**\n    When bulk sampling, Stim only uses a general stabilizer simulator for an initial reference sample.\n    After that, it cheaply derives as many samples as needed by propagating simulated errors diffed against the\n    reference.\n    This simple trick is *ridiculously* cheaper than the alternative: constant cost per gate, instead of linear cost\n    or even quadratic cost.\n\n3.  **Inverted Stabilizer Tableau.**\n    When doing general stabilizer simulation, Stim tracks the inverse of the stabilizer tableau that was historically\n    used.\n    This has the unexpected benefit of making measurements that commute with the current stabilizers take\n    linear time instead of quadratic time. This is beneficial in error correcting codes, because the measurements\n    they perform are usually redundant and so commute with the current stabilizers.\n\n## <a name=\"how-cite-stim\"></a>How do I cite Stim?\n\nWhen using Stim for research, [please cite](https://quantum-journal.org/papers/q-2021-07-06-497/):\n\n```latex\n@article{gidney2021stim,\n  doi = {10.22331/q-2021-07-06-497},\n  url = {https://doi.org/10.22331/q-2021-07-06-497},\n  title = {Stim: a fast stabilizer circuit simulator},\n  author = {Gidney, Craig},\n  journal = {{Quantum}},\n  issn = {2521-327X},\n  publisher = {{Verein zur F{\\\"{o}}rderung des Open Access Publizierens\n                in den Quantenwissenschaften}},\n  volume = 5,\n  pages = 497,\n  month = jul,\n  year = 2021\n}\n```\n\n## Contact\n\nFor any questions or concerns not addressed here, please email quantum-oss-maintainers@google.com.\n\n## Disclaimer\n\nThis is not an officially supported Google product. This project is not eligible for the [Google Open Source Software\nVulnerability Rewards Program](https://bughunters.google.com/open-source-security).\n\nCopyright 2025 Google LLC.\n\n<div align=\"center\">\n  <a href=\"https://quantumai.google\">\n    <img width=\"15%\" alt=\"Google Quantum AI\"\n         src=\"./doc/quantum-ai-vertical.svg\">\n  </a>\n</div>\n"
  },
  {
    "path": "SUPPORT.md",
    "content": "# Support\n\nThank you for your interest in this project! If you are experiencing problems\nor have questions, the following are some suggestions for how to get help.\n\n> [!NOTE]\n> Before participating in our community, please read our [code of\n> conduct](CODE_OF_CONDUCT.md). By interacting with this repository,\n> organization, or community, you agree to abide by its terms.\n\n## Report an issue or request a feature\n\nTo report an issue or request a feature in Stim, please first search the\n[issue tracker on GitHub](https://github.com/quantumlib/Stim/issues) to\ncheck if there is already an open issue identical or similar to your bug\nreport/feature request. If there is none, go ahead and file a new issue in the\nissue tracker.\n\n## Contact the maintainers\n\nFor any questions or concerns not addressed here, please email\n[quantum-oss-maintainers@google.com](mailto:quantum-oss-maintainers@google.com).\n"
  },
  {
    "path": "WORKSPACE",
    "content": "load(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@pybind11_bazel//:python_configure.bzl\", \"python_configure\")\n\nhttp_archive(\n    name = \"pybind11\",\n    build_file = \"@pybind11_bazel//:pybind11.BUILD\",\n    sha256 = \"bf8f242abd1abcd375d516a7067490fb71abd79519a282d22b6e4d19282185a7\",\n    strip_prefix = \"pybind11-2.12.0\",\n    urls = [\"https://github.com/pybind/pybind11/archive/refs/tags/v2.12.0.tar.gz\"],\n)\n\npython_configure(name = \"local_config_python\")\n"
  },
  {
    "path": "dev/canvas_with_texture_for_3d_diagrams.html",
    "content": "<meta charset=\"utf-8\">\n<body style=\"margin: 0\">\n<canvas width=\"512\" height=\"512\" id=\"cv\" style=\"border: 1px solid black; margin: 0; padding: 0\">\n</canvas>\n<script>\n\n/**\n *\n * @param {!int} i\n * @returns {{x: !number, y: !number}}\n */\nfunction pickRect(i) {\n    if (i >= 6 * 16 && i < 9 * 16) {\n        i -= 6 * 16;\n        i = Math.floor(i / 3) + (i % 3) * 16;\n        i += 6 * 16;\n    }\n    let x = i % 16;\n    let y = Math.floor(i / 16);\n    return {x, y}\n}\n\n/**\n *\n * @param {!CanvasRenderingContext2D} ctx\n * @param {!string} text\n * @param {!string} fill\n * @param {!string} stroke\n * @param {!int} i\n */\nfunction drawRect(ctx, text, fill, stroke, i) {\n    let {x, y} = pickRect(i);\n    ctx.fillStyle = fill;\n    ctx.fillRect(x * 32, y * 32, 32, 32);\n\n    ctx.fillStyle = 'black';\n    let main = \"\";\n    let sub = \"\";\n    let sup = \"\";\n    if (text.indexOf(\"_\") !== -1 && text !== '_') {\n        [main, sub] = text.split(\"_\");\n    } else {\n        main = text;\n    }\n    if (main.indexOf(\"^\") !== -1 && main !== '^') {\n        [main, sup] = main.split(\"^\");\n    }\n    if (sub.indexOf(\"^\") !== -1 && sub !== '^') {\n        [sub, sup] = sub.split(\"^\");\n    }\n    let vert = Math.max(sub.length, sup.length, main.length) >= 3 && sub.length > 0;\n    let bigFontSize = 18;\n    let smallFontSize = 18 * 0.75;\n    while (bigFontSize > 6) {\n        let bigFont = bigFontSize + 'pt serif';\n        let smallFont = (smallFontSize * 0.75) + 'pt serif';\n        ctx.font = bigFont;\n        let w_main = ctx.measureText(main).width;\n        ctx.font = smallFont;\n        let w_sub = ctx.measureText(sub).width;\n        let w_sup = ctx.measureText(sup).width;\n        let w_subsup = Math.max(ctx.measureText(sub).width, ctx.measureText(sup).width);\n        if (vert) {\n            if (w_main > 32) {\n                bigFontSize -= 1;\n                smallFontSize -= 0.75;\n                continue;\n            } else if (w_subsup > 32) {\n                smallFontSize -= 0.75;\n                continue;\n            }\n        } else {\n            if (w_main + w_subsup > 32) {\n                bigFontSize -= 1;\n                smallFontSize -= 0.75;\n                continue;\n            }\n        }\n        if (vert) {\n            let dy = 0;\n            if (w_sub < w_main * 0.8) {\n                smallFont = bigFont;\n                dy = -2;\n            }\n            ctx.fillStyle = stroke;\n            ctx.font = bigFont;\n            ctx.textBaseline = 'middle'\n            ctx.fillText(main, x * 32 + 16 - w_main / 2, y * 32 + 11);\n            ctx.font = smallFont;\n            ctx.textBaseline = 'bottom';\n            ctx.fillText(sub, x * 32 + 16 - w_sub / 2, y * 32 + 34 + dy);\n            ctx.textBaseline = 'hanging';\n            ctx.fillText(sup, x * 32 + 16 - w_sup / 2, y * 32);\n        } else {\n            ctx.fillStyle = stroke;\n            ctx.font = bigFont;\n            ctx.textBaseline = 'middle'\n            ctx.fillText(main, x * 32 + 16 - w_main / 2 - w_subsup / 2, y * 32 + 18);\n            ctx.font = smallFont;\n            ctx.textBaseline = 'bottom';\n            ctx.fillText(sub, x * 32 + 16 + w_main / 2 - w_sub / 2, y * 32 + (sup !== \"\" ? 34 : 32));\n            ctx.textBaseline = 'hanging';\n            ctx.fillText(sup, x * 32 + 16 + w_main / 2 - w_sup / 2, y * 32);\n        }\n        break;\n    }\n}\n\nfunction drawHeraldErase(ctx, i) {\n    let {x, y} = pickRect(i);\n    ctx.fillStyle = 'black';\n    ctx.fillRect(x * 32, y * 32, 32, 32);\n    ctx.fillStyle = 'yellow';\n    ctx.font = '6pt serif';\n    ctx.fillText('HERALD', x * 32 + 16 - ctx.measureText('HERALD').width / 2, y * 32 + 11);\n    ctx.font = '7pt serif';\n    ctx.fillText('ERASE', x * 32 + 16 - ctx.measureText('ERASE').width / 2, y * 32 + 18);\n}\n\nfunction drawCpp(ctx, c1, c2, i) {\n    let {x, y} = pickRect(i);\n    ctx.fillStyle = '#' + (c1 === 'X' || c2 === 'X' ? 'f' : '4') + (c1 === 'Y' || c2 === 'Y' ? 'f' : '4') + (c1 === 'Z' || c2 === 'Z' ? 'f' : '4');\n    ctx.fillRect(x * 32, y * 32, 32, 32);\n    ctx.fillStyle = 'black';\n    ctx.font = '12pt serif';\n    let t1 = 'CPP';\n    ctx.fillText(t1, x * 32 + 16 - ctx.measureText(t1).width / 2, y * 32 + 5);\n    let t2 = c1 + ':' + c2;\n    ctx.font = '12pt serif';\n    ctx.fillText(t2, x * 32 + 16 - ctx.measureText(t2).width / 2, y * 32 + 18);\n}\n\nfunction drawHeraldPauliError1(ctx, i) {\n    let {x, y} = pickRect(i);\n    ctx.fillStyle = 'black';\n    ctx.fillRect(x * 32, y * 32, 32, 32);\n    ctx.fillStyle = 'yellow';\n    ctx.font = '6pt serif';\n    ctx.fillText('HERALD', x * 32 + 16 - ctx.measureText('HERALD').width / 2, y * 32 + 3);\n    ctx.font = '9pt serif';\n    ctx.fillText('Pauli', x * 32 + 16 - ctx.measureText('Pauli').width / 2, y * 32 + 11);\n    ctx.fillText('Err1', x * 32 + 16 - ctx.measureText('Err1').width / 2, y * 32 + 21);\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n */\nfunction draw(ctx) {\n    for (let a = 32; a < 127; a++) {\n        drawRect(ctx, String.fromCharCode(a), \"#fff\", \"#000\", a - 32);\n    }\n    drawRect(ctx, \"?\", \"white\", 127 - 32);\n    let n = 128 - 32;\n\n    drawRect(ctx, \"X\", \"#FEE\", \"#000\", n++);\n    drawRect(ctx, \"Y\", \"#EFE\", \"#000\", n++);\n    drawRect(ctx, \"Z\", \"#EEF\", \"#000\", n++);\n\n    drawRect(ctx, \"H_YZ\", \"#FAA\", \"#000\", n++);\n    drawRect(ctx, \"H\", \"#AFA\", \"#000\", n++);\n    drawRect(ctx, \"H_XY\", \"#AAF\", \"#000\", n++);\n\n    drawRect(ctx, \"S_X\", \"#FAA\", \"#000\", n++);\n    drawRect(ctx, \"S_Y\", \"#AFA\", \"#000\", n++);\n    drawRect(ctx, \"S\", \"#AAF\", \"#000\", n++);\n    drawRect(ctx, \"S_X^†\", \"#FAA\", \"#000\", n++);\n    drawRect(ctx, \"S_Y^†\", \"#AFA\", \"#000\", n++);\n    drawRect(ctx, \"S^†\", \"#AAF\", \"#000\", n++);\n\n    drawRect(ctx, \"M_X\", \"#F44\", \"#000\", n++);\n    drawRect(ctx, \"M_Y\", \"#4F4\", \"#000\", n++);\n    drawRect(ctx, \"M\", \"#44F\", \"#000\", n++);\n\n    drawRect(ctx, \"R_X\", \"#F44\", \"#000\", n++);\n    drawRect(ctx, \"R_Y\", \"#4F4\", \"#000\", n++);\n    drawRect(ctx, \"R\", \"#44F\", \"#000\", n++);\n\n    drawRect(ctx, \"MR_X\", \"#F44\", \"#000\", n++);\n    drawRect(ctx, \"MR_Y\", \"#4F4\", \"#000\", n++);\n    drawRect(ctx, \"MR\", \"#44F\", \"#000\", n++);\n\n    drawRect(ctx, \"X_ERR\", \"#000\", \"#F44\", n++);\n    drawRect(ctx, \"Y_ERR\", \"#000\", \"#4F4\", n++);\n    drawRect(ctx, \"Z_ERR\", \"#000\", \"#44F\", n++);\n\n    drawRect(ctx, \"X_CErr\", \"#000\", \"#F44\", n++);\n    drawRect(ctx, \"Y_CErr\", \"#000\", \"#4F4\", n++);\n    drawRect(ctx, \"Z_CErr\", \"#000\", \"#44F\", n++);\n\n    drawRect(ctx, \"X_ElErr\", \"#000\", \"#F44\", n++);\n    drawRect(ctx, \"Y_ElErr\", \"#000\", \"#4F4\", n++);\n    drawRect(ctx, \"Z_ElErr\", \"#000\", \"#44F\", n++);\n\n    drawRect(ctx, \"MPP_X\", \"#F44\", \"#000\", n++);\n    drawRect(ctx, \"MPP_Y\", \"#4F4\", \"#000\", n++);\n    drawRect(ctx, \"MPP_Z\", \"#44F\", \"#000\", n++);\n\n    drawRect(ctx, \"√XX\", \"#FAA\", \"#000\", n++);\n    drawRect(ctx, \"√YY\", \"#AFA\", \"#000\", n++);\n    drawRect(ctx, \"√ZZ\", \"#AAF\", \"#000\", n++);\n\n    drawRect(ctx, \"√XX_†\", \"#FAA\", \"#000\", n++);\n    drawRect(ctx, \"√YY_†\", \"#AFA\", \"#000\", n++);\n    drawRect(ctx, \"√ZZ_†\", \"#AAF\", \"#000\", n++);\n\n    drawRect(ctx, \"X^rec\", \"#FEE\", \"#000\", n++);\n    drawRect(ctx, \"Y^rec\", \"#EFE\", \"#000\", n++);\n    drawRect(ctx, \"Z^rec\", \"#EEF\", \"#000\", n++);\n\n    drawRect(ctx, \"sweep_X\", \"#FEE\", \"#000\", n++);\n    drawRect(ctx, \"sweep_Y\", \"#EFE\", \"#000\", n++);\n    drawRect(ctx, \"sweep_Z\", \"#EEF\", \"#000\", n++);\n    n += 2;\n    drawRect(ctx, \"I_ERR\", \"#FFF\", \"#000\", n++);\n\n    n = 128 + 16;\n    drawRect(ctx, \"I\", \"#FFF\", \"#000\", n++);\n    drawRect(ctx, \"C_XYZ\", \"#FFA\", \"#000\", n++);\n    drawRect(ctx, \"C_ZYX\", \"#AFF\", \"#000\", n++);\n    drawRect(ctx, \"DEP_1\", \"#000\", \"#FFF\", n++);\n    drawRect(ctx, \"DEP_2\", \"#000\", \"#FFF\", n++);\n    drawRect(ctx, \"iSw_ap\", \"#FFF\", \"#000\", n++);\n    drawRect(ctx, \"iSw_ap†\", \"#FFF\", \"#000\", n++);\n    drawRect(ctx, \"SWAP\", \"#FFF\", \"#000\", n++);\n    drawRect(ctx, \"Pauli_Err1\", \"#000\", \"#FFF\", n++);\n    drawRect(ctx, \"Pauli_Err2\", \"#000\", \"#FFF\", n++);\n\n    drawRect(ctx, \"M_XX\", \"#F44\", \"#000\", n++);\n    drawRect(ctx, \"M_YY\", \"#4F4\", \"#000\", n++);\n    drawRect(ctx, \"M_ZZ\", \"#44F\", \"#000\", n++);\n    drawRect(ctx, \"M_PAD\", \"#888\", \"#000\", n++);\n    drawHeraldErase(ctx, n++);\n    drawHeraldPauliError1(ctx, n++);\n\n    drawRect(ctx, \"SPP_X\", \"#F44\", \"#000\", n++);\n    drawRect(ctx, \"SPP_Y\", \"#4F4\", \"#000\", n++);\n    drawRect(ctx, \"SPP_Z\", \"#44F\", \"#000\", n++);\n    drawRect(ctx, \"SPP_X†\", \"#F44\", \"#000\", n++);\n    drawRect(ctx, \"SPP_Y†\", \"#4F4\", \"#000\", n++);\n    drawRect(ctx, \"SPP_Z†\", \"#44F\", \"#000\", n++);\n    drawRect(ctx, \"C_NXYZ\", \"#FFA\", \"#000\", n++);\n    drawRect(ctx, \"C_XNYZ\", \"#FFA\", \"#000\", n++);\n    drawRect(ctx, \"C_XYNZ\", \"#FFA\", \"#000\", n++);\n    drawRect(ctx, \"C_NZYX\", \"#AFF\", \"#000\", n++);\n    drawRect(ctx, \"C_ZNYX\", \"#AFF\", \"#000\", n++);\n    drawRect(ctx, \"C_ZYNX\", \"#AFF\", \"#000\", n++);\n    drawRect(ctx, \"H_NXY\", \"#FAA\", \"#000\", n++);\n    drawRect(ctx, \"H_NXZ\", \"#AFA\", \"#000\", n++);\n    drawRect(ctx, \"H_NYZ\", \"#AAF\", \"#000\", n++);\n    drawRect(ctx, \"II\", \"#FFF\", \"#000\", n++);\n\n    n = 128 + 48;\n    drawCpp(ctx, 'I', 'X', n++);\n    drawCpp(ctx, 'I', 'Y', n++);\n    drawCpp(ctx, 'I', 'Z', n++);\n    drawCpp(ctx, 'X', 'I', n++);\n    drawCpp(ctx, 'X', 'X', n++);\n    drawCpp(ctx, 'X', 'Y', n++);\n    drawCpp(ctx, 'X', 'Z', n++);\n    drawCpp(ctx, 'Y', 'I', n++);\n    drawCpp(ctx, 'Y', 'X', n++);\n    drawCpp(ctx, 'Y', 'Y', n++);\n    drawCpp(ctx, 'Y', 'Z', n++);\n    drawCpp(ctx, 'Z', 'I', n++);\n    drawCpp(ctx, 'Z', 'X', n++);\n    drawCpp(ctx, 'Z', 'Y', n++);\n    drawCpp(ctx, 'Z', 'Z', n++);\n    drawRect(ctx, \"II_ERR\", \"#FFF\", \"#000\", n++);\n}\n\ndraw(document.getElementById('cv').getContext('2d'))\n\n</script>\n</body>\n"
  },
  {
    "path": "dev/clean_build_files.sh",
    "content": "#!/bin/bash\nset -e\n\n#########################################################################\n# Deletes files created by cmake, python setup.py, and other build steps.\n#########################################################################\n\n# Get to this script's git repo root.\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\ncd \"$(git rev-parse --show-toplevel)\"\n\nrm CMakeFiles -rf\nrm CMakeCache.txt -f\nrm Makefile -f\nrm dist -rf\nrm cmake_install.cmake -f\nrm cmake-build-debug-coverage -rf\nrm coverage -rf\nrm stim.egg-info -rf\nrm bazel-bin -rf\nrm bazel-out -rf\nrm bazel-stim -rf\nrm bazel-testlogs -rf\nrm Testing -rf\nrm out -rf\nrm cmake-build-debug -rf\nrm .cmake -rf\n"
  },
  {
    "path": "dev/compile_crumble_into_cpp_string_file.sh",
    "content": "#!/bin/bash\nset -e\n\n# Get to this script's git repo root.\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\ncd \"$(git rev-parse --show-toplevel)\"\n\necho '#include \"stim/diagram/crumble_data.h\"'\necho '';\necho 'std::string stim_draw_internal::make_crumble_html() {'\necho '    std::string result;'\ndev/compile_crumble_into_single_html_page.sh | python -c '\nimport sys\nfor line in sys.stdin:\n    for k in range(0, len(line), 1024):\n        part = line[k:k+1024]\n        print(f\"\"\"    result.append(R\"CRUMBLE_PART({part})CRUMBLE_PART\");\"\"\")';\necho '    return result;'\necho '}'\n"
  },
  {
    "path": "dev/compile_crumble_into_single_html_page.sh",
    "content": "#!/bin/bash\nset -e\n\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\ncd \"$(git rev-parse --show-toplevel)\"\n\ncat glue/crumble/crumble.html | grep -v \"^<script\";\necho \"<script>\";\n# HACK: this temp file is to work around https://github.com/rollup/rollup/issues/5097\nrollup glue/crumble/main.js --silent > tmp_crumble.tmp\nuglifyjs -c -m --mangle-props --toplevel < tmp_crumble.tmp;\nrm tmp_crumble.tmp\necho \"</script>\";\n"
  },
  {
    "path": "dev/doctest_proper.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"Runs doctests on a module, including any objects imported into the module.\"\"\"\nimport argparse\nimport doctest\nimport inspect\nimport sys\nfrom typing import Dict\n\n\nSKIPPED_FIELDS = {\n    '__base__',\n    '__name__',\n    '__path__',\n    '__spec__',\n    '__version__',\n    '__package__',\n    '__subclasshook__',\n    '__abstractmethods__',\n    '__bases__',\n    '__basicsize__',\n    '__class__',\n    '__builtins__',\n    '__cached__',\n    '__doc__',\n    '__loader__',\n    '__file__',\n}\n\n\ndef no_really_i_have_a_doc_why_is_this_needed_argh(v: object, fullname: str) -> object:\n    def so_much_doc():\n        pass\n    so_much_doc.__doc__ = v.__doc__\n    so_much_doc.__qualname__ = fullname\n    return so_much_doc\n\n\ndef gen(*, obj: object, fullname: str, out: Dict[str, object]) -> None:\n    if obj is None:\n        return\n    if inspect.isfunction(obj) or inspect.ismethod(obj) or inspect.isbuiltin(obj) or inspect.isroutine(obj):\n        if hasattr(obj, '__doc__'):\n            out[fullname] = obj\n        return\n    if not inspect.ismodule(obj) and not inspect.isclass(obj):\n        if hasattr(obj, '__doc__'):\n            out[fullname] = no_really_i_have_a_doc_why_is_this_needed_argh(obj, fullname)\n        return\n    if hasattr(obj, '__doc__'):\n        out[fullname] = obj\n\n    for sub_name in dir(obj):\n        if sub_name in SKIPPED_FIELDS:\n            continue\n        if sub_name.startswith('__pybind11_module'):\n            continue\n        sub_obj = getattr(obj, sub_name, None)\n        if inspect.ismodule(sub_obj):\n            continue\n        sub_full_name = fullname + \".\" + sub_name\n        gen(obj=sub_obj, fullname=sub_full_name, out=out)\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\n        \"--module\",\n        type=str,\n        required=True,\n        nargs='+',\n        help=\"The module to test. \"\n             \"This module will be imported, \"\n             \"its imported values will be recursively explored, \"\n             \"and doctests will be run on them.\")\n    parser.add_argument(\n        '--import',\n        default=(),\n        nargs='*',\n        type=str,\n        help=\"Modules to import for each doctest.\")\n    args = parser.parse_args()\n\n    globs = {\n        k: __import__(k) for k in getattr(args, 'import')\n    }\n    any_failed = False\n    for module_name in args.module:\n        module = __import__(module_name)\n        out = {}\n        gen(obj=module, fullname=module_name, out=out)\n        for k, v in out.items():\n            if v.__doc__ is None:\n                continue\n            v = v.__doc__.lower()\n            if '\\n' in v.strip() and 'examples:' not in v and 'example:' not in v and '[deprecated]' not in v:\n                if k.split('.')[-1] not in ['__format__', '__next__', '__iter__', '__init_subclass__', '__module__', '__eq__', '__ne__', '__str__', '__repr__']:\n                    if all(not (e.startswith('_') and not e.startswith('__')) for e in k.split('.')):\n                        print(f\"    Warning: Missing 'examples:' section in docstring of {k!r}\", file=sys.stderr)\n\n        module.__test__ = {k: v for k, v in out.items()}\n        if doctest.testmod(module, globs=globs).failed:\n            any_failed = True\n    if any_failed:\n        sys.exit(1)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "dev/gen_known_gates_for_js.sh",
    "content": "#!/bin/bash\nset -e\n\n#########################################################################\n# Generates javascript exporting a string KNOWN_GATE_NAMES_FROM_STIM.\n#########################################################################\n\necho \"const KNOWN_GATE_NAMES_FROM_STIM = \\`\"\npython -c \"import stim; stim.main(command_line_args=['help', 'gates'])\" | grep \"    \" | sed 's/^ *//g'\necho \"\\`\"\necho\necho \"export {KNOWN_GATE_NAMES_FROM_STIM};\"\n"
  },
  {
    "path": "dev/gen_sinter_api_reference.py",
    "content": "\"\"\"\nIterates over modules and classes, listing their attributes and methods in markdown.\n\"\"\"\n\nimport sinter\n\nimport sys\n\nfrom util_gen_stub_file import generate_documentation\n\n\ndef main():\n    version = sinter.__version__\n    if \"dev\" in version or version == \"VERSION_INFO\" or \"-dev\" in sys.argv:\n        version = \"(Development Version)\"\n        is_dev = True\n    else:\n        version = \"v\" + version\n        is_dev = False\n    objects = [\n        obj\n        for obj in generate_documentation(obj=sinter, full_name=\"sinter\", level=0)\n        if all('[DEPRECATED]' not in line for line in obj.lines)\n    ]\n\n    print(f\"# Sinter {version} API Reference\")\n    print()\n    if is_dev:\n        print(\"*CAUTION*: this API reference is for the in-development version of sinter.\")\n        print(\"Methods and arguments mentioned here may not be accessible in stable versions, yet.\")\n        print(\"API references for stable versions are kept on the [stim github wiki](https://github.com/quantumlib/Stim/wiki)\")\n        print()\n    print(\"## Index\")\n    for obj in objects:\n        level = obj.level\n        print((level - 1) * \"    \" + f\"- [`{obj.full_name}`](#{obj.full_name})\")\n\n    print(f'''\n```python\n# Types used by the method definitions.\nfrom typing import overload, TYPE_CHECKING, Any, Counter, Dict, Iterable, List, Optional, Tuple, Union\nimport abc\nimport dataclasses\nimport io\nimport numpy as np\nimport pathlib\nimport stim\n```\n'''.strip())\n\n    replace_rules = []\n    for package in ['stim', 'sinter']:\n        p = __import__(package)\n        for name in dir(p):\n            x = getattr(p, name)\n            if isinstance(x, type) and 'class' in str(x):\n                desired_name = f'{package}.{name}'\n                if '._' in str(x):\n                    bad_name = str(x).split(\"'\")[1]\n                    replace_rules.append((bad_name, desired_name))\n                lonely_name = desired_name.split(\".\")[-1]\n                for q in ['\"', \"'\"]:\n                    replace_rules.append(('ForwardRef(' + q + lonely_name + q + ')', desired_name))\n                    replace_rules.append(('ForwardRef(' + q + desired_name + q + ')', desired_name))\n                    replace_rules.append((q + desired_name + q, desired_name))\n                    replace_rules.append((q + lonely_name + q, desired_name))\n                replace_rules.append(('ForwardRef(' + desired_name + ')', desired_name))\n                replace_rules.append(('ForwardRef(' + lonely_name + ')', desired_name))\n\n    for obj in objects:\n        print()\n        print(f'<a name=\"{obj.full_name}\"></a>')\n        print(\"```python\")\n        print(f'# {obj.full_name}')\n        print()\n        if len(obj.full_name.split('.')) > 2:\n            print(f'# (in class {\".\".join(obj.full_name.split(\".\")[:-1])})')\n        else:\n            print(f'# (at top-level in the sinter module)')\n        for line in obj.lines:\n            for a, b in replace_rules:\n                line = line.replace(a, b)\n            print(line)\n        print(\"```\")\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "dev/gen_stim_api_reference.py",
    "content": "\"\"\"\nIterates over modules and classes, listing their attributes and methods in markdown.\n\"\"\"\n\nimport stim\n\nimport sys\n\nfrom util_gen_stub_file import generate_documentation\n\n\ndef main():\n    version = stim.__version__\n    if \"dev\" in version or version == \"VERSION_INFO\" or \"-dev\" in sys.argv:\n        version = \"(Development Version)\"\n        is_dev = True\n    else:\n        version = \"v\" + version\n        is_dev = False\n    objects = [\n        obj\n        for obj in generate_documentation(obj=stim, full_name=\"stim\", level=0)\n        if all('[DEPRECATED]' not in line for line in obj.lines)\n    ]\n\n    print(f\"# Stim {version} API Reference\")\n    print()\n    if is_dev:\n        print(\"*CAUTION*: this API reference is for the in-development version of stim.\")\n        print(\"Methods and arguments mentioned here may not be accessible in stable versions, yet.\")\n        print(\"API references for stable versions are kept on the [stim github wiki](https://github.com/quantumlib/Stim/wiki)\")\n        print()\n    print(\"## Index\")\n    for obj in objects:\n        level = obj.level\n        print((level - 1) * \"    \" + f\"- [`{obj.full_name}`](#{obj.full_name})\")\n\n    print(f'''\n```python\n# Types used by the method definitions.\nfrom typing import overload, TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, Union\nimport io\nimport pathlib\nimport numpy as np\n```\n'''.strip())\n\n    for obj in objects:\n        print()\n        print(f'<a name=\"{obj.full_name}\"></a>')\n        print(\"```python\")\n        print(f'# {obj.full_name}')\n        print()\n        if len(obj.full_name.split('.')) > 2:\n            print(f'# (in class {\".\".join(obj.full_name.split(\".\")[:-1])})')\n        else:\n            print(f'# (at top-level in the stim module)')\n        print('\\n'.join(obj.lines))\n        print(\"```\")\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "dev/gen_stim_stub_file.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\nProduces a .pyi file for stim, describing the contained classes and functions.\n\"\"\"\n\nimport stim\nimport sys\n\nfrom util_gen_stub_file import generate_documentation\n\n\ndef main():\n    version = stim.__version__\n    if \"dev\" in version or version == \"VERSION_INFO\" or \"-dev\" in sys.argv:\n        version = \"(Development Version)\"\n    else:\n        version = \"v\" + version\n    print(f'''\n\"\"\"Stim {version}: a fast quantum stabilizer circuit library.\"\"\"\n# (This is a stubs file describing the classes and methods in stim.)\nfrom __future__ import annotations\nfrom typing import overload, TYPE_CHECKING, List, Dict, Tuple, Any, Union, Iterable, Optional, Sequence, Literal\nif TYPE_CHECKING:\n    import io\n    import pathlib\n    import numpy as np\n    import stim\n'''.strip())\n\n    for obj in generate_documentation(obj=stim, full_name=\"stim\", level=-1):\n        text = '\\n'.join((\"    \" * obj.level + line).rstrip()\n                        for paragraph in obj.lines\n                        for line in paragraph.splitlines())\n        assert \"stim::\" not in text, \"CONTAINS C++ STYLE TYPE SIGNATURE!!:\\n\" + text\n        print(text)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "dev/make_logo.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<body style=\"margin: 0\">\n</body>\n<script type=\"module\">\n    function make_svg(diam) {\n        let svg = `<svg width=\"${diam}\" height=\"${diam}\" viewBox=\"0 0 ${diam} ${diam}\" xmlns=\"http://www.w3.org/2000/svg\">\\n`;\n        let angles = [\n            Math.PI * 1 / 6,\n            Math.PI * 5 / 6,\n            Math.PI * 9 / 6,\n        ]\n\n        let cx = diam / 2;\n        let cy = diam / 2 + 10 * (diam / 256);\n        let rad = 46 * (diam / 256);\n        let rect_group = (a1, a2, color1, color2) => {\n            for (let k1 = 0; k1 < 2; k1++) {\n                for (let k2 = 0; k2 < 3; k2++) {\n                    rect(a1, a2, k1, k2, (k1 + k2) % 2 === 0 ? color1 : color2);\n                }\n            }\n        }\n        let rnd = x => Math.round(x * 10000) / 10000;\n        let rect = (a1, a2, d1, d2, color) => {\n            let dx1 = Math.cos(angles[a1]) * rad;\n            let dy1 = Math.sin(angles[a1]) * rad;\n            let dx2 = Math.cos(angles[a2]) * rad;\n            let dy2 = Math.sin(angles[a2]) * rad;\n            let xys = [];\n            let eps = 0.05;\n            for (let [e1, e2] of [[eps, eps], [eps, 1-eps], [1-eps, 1-eps], [1-eps, eps]]) {\n                let [x, y] = [cx + dx1*(d1 + e1) + dx2*(d2 + e2), cy + dy1*(d1 + e1) + dy2*(d2 + e2)];\n                xys.push([rnd(x), rnd(y)]);\n            }\n            svg += '<path d=\"';\n            svg += `M${xys[0][0]},${xys[0][1]} `\n            svg += `L${xys[1][0]},${xys[1][1]} `\n            svg += `L${xys[2][0]},${xys[2][1]} `\n            svg += `L${xys[3][0]},${xys[3][1]} `\n            svg += `Z\" fill=\"${color}\"/>\\n`\n        };\n        let r = '#FBBC04'\n        let g = '#FF8207'\n        let b = '#174EA6'\n        rect_group(0, 1, r, b)\n        rect_group(1, 2, b, g)\n        rect_group(2, 0, g, r)\n        svg += '</svg>';\n        return svg;\n    }\n    for (let diam of [32, 64, 128, 256]) {\n        let div = document.createElement('div');\n        div.textContent = `${diam}x${diam}`;\n        let img = document.createElement('img');\n        img.src = `data:image/svg+xml;base64,${btoa(make_svg(diam))}`;\n        let span = document.createElement('span');\n        document.body.appendChild(div);\n        document.body.appendChild(img);\n    }\n</script>\n</html>\n"
  },
  {
    "path": "dev/overwrite_dev_versions_with_date.py",
    "content": "#!/usr/bin/env python3\n\n#########################################################\n# Sets version numbers to a date-based dev version.\n#\n# Does nothing if not on a dev version.\n#########################################################\n# Example usage (from repo root):\n#\n# ./dev/overwrite_dev_versions_with_date.sh\n#########################################################\n\nimport os\nimport pathlib\nimport re\nimport subprocess\n\n\ndef main():\n    os.chdir(pathlib.Path(__file__).parent)\n    os.chdir(subprocess.check_output([\"git\", \"rev-parse\", \"--show-toplevel\"]).decode().strip())\n\n    # Generate dev version starting from major.minor version.\n    # (Requires the existing version to have a 'dev' suffix.)\n    # (Uses the timestamp of the HEAD commit, to ensure consistency when run multiple times.)\n    with open('setup.py') as f:\n        maj_min_version_line, = [line for line in f.read().splitlines() if re.match(\"^__version__ = '[^']+'\", line)]\n        maj_version, min_version, patch = maj_min_version_line.split()[-1].strip(\"'\").split('.')\n        if 'dev' not in patch:\n            return  # Do nothing for non-dev versions.\n    timestamp = subprocess.check_output(['git', 'show', '-s', '--format=%ct', 'HEAD']).decode().strip()\n    new_version = f\"{maj_version}.{min_version}.dev{timestamp}\"\n\n    # Overwrite existing versions.\n    package_setup_files = [\n        \"setup.py\",\n        \"glue/cirq/setup.py\",\n        \"glue/cirq/stimcirq/__init__.py\",\n        \"glue/zx/stimzx/__init__.py\",\n        \"glue/zx/setup.py\",\n        \"glue/sample/setup.py\",\n        \"glue/sample/src/sinter/__init__.py\",\n    ]\n    for path in package_setup_files:\n        with open(path) as f:\n            content = f.read()\n        assert maj_min_version_line in content\n        content = content.replace(maj_min_version_line, f\"__version__ = '{new_version}'\")\n        with open(path, 'w') as f:\n            print(content, file=f, end='')\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "dev/regen_crumble_cpp_resource.sh",
    "content": "#!/bin/bash\nset -e\n\n# Get to this script's git repo root.\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\ncd \"$(git rev-parse --show-toplevel)\"\n\ndev/compile_crumble_into_cpp_string_file.sh > src/stim/diagram/crumble_data.cc\n"
  },
  {
    "path": "dev/regen_docs.sh",
    "content": "#!/bin/bash\nset -e\n\n#########################################################################\n# Regenerates doc files using the installed version of stim.\n#########################################################################\n\n# Get to this script's git repo root.\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\ncd \"$(git rev-parse --show-toplevel)\"\n\npython dev/gen_stim_api_reference.py -dev > doc/python_api_reference_vDev.md\npython dev/gen_stim_stub_file.py -dev > glue/python/src/stim/__init__.pyi\npython dev/gen_stim_stub_file.py -dev > doc/stim.pyi\npython dev/gen_sinter_api_reference.py -dev > doc/sinter_api.md\npython -c \"import stim; stim.main(command_line_args=['help', 'gates_markdown'])\" > doc/gates.md\npython -c \"import stim; stim.main(command_line_args=['help', 'formats_markdown'])\" > doc/result_formats.md\npython -c \"import stim; stim.main(command_line_args=['help', 'commands_markdown'])\" > doc/usage_command_line.md\ndev/gen_known_gates_for_js.sh > glue/crumble/test/generated_gate_name_list.test.js\n"
  },
  {
    "path": "dev/regen_file_lists.sh",
    "content": "#!/bin/bash\nset -e\n\n#########################################################################\n# Regenerate file_lists\n#########################################################################\n\nif [ \"$#\" -ne 1 ]; then\n    FOLDER=file_lists\nelse\n    FOLDER=$1\nfi\n\n# Get to this script's git repo root.\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\ncd \"$(git rev-parse --show-toplevel)\"\n\n# LC_ALL=C forces sorting to happen by byte value\nfind src | grep \"\\\\.cc$\" | grep -v \"\\\\.\\(test\\|perf\\|pybind\\)\\\\.cc$\" | grep -v \"src/main\\\\.cc\" | LC_ALL=C sort > \"${FOLDER}/source_files_no_main\"\nfind src | grep \"\\\\.test\\\\.cc$\" | LC_ALL=C sort > \"${FOLDER}/test_files\"\nfind src | grep \"\\\\.perf\\\\.cc$\" | LC_ALL=C sort > \"${FOLDER}/perf_files\"\nfind src | grep \"\\\\.pybind\\\\.cc$\" | LC_ALL=C sort > \"${FOLDER}/pybind_files\"\n\n# Regenerate 'stim.h' to include all relevant headers.\n{\n    echo \"#ifndef _STIM_H\";\n    echo \"#define _STIM_H\";\n    echo \"/// WARNING: THE STIM C++ API MAKES NO COMPATIBILITY GUARANTEES.\";\n    echo \"/// It may change arbitrarily and catastrophically from minor version to minor version.\";\n    echo \"/// If you need a stable API, use stim's Python API.\";\n    find src | grep \"\\\\.h$\" | grep -v \"\\\\.\\(test\\|perf\\|pybind\\)\\\\.h$\" | grep -v \"src/stim\\\\.h\" | grep -v \"src/stim/mem/simd_word_.*\" | LC_ALL=C sort | sed 's/src\\/\\(.*\\)/#include \"\\1\"/g';\n    echo \"#endif\";\n} > src/stim.h\n\n# Regenerate crumble's unit test imports.\nfind glue/crumble | grep \"\\\\.test.js$\" | LC_ALL=C sort | sed 's/glue\\/crumble\\(.*\\)/import \"..\\1\"/g' > \"glue/crumble/test/test_import_all.js\"\n"
  },
  {
    "path": "dev/regen_texture_to_cpp_base64_string.sh",
    "content": "#!/bin/bash\nset -e\n\n#########################################################################\n# Transforms binary data into an array of string literals containing the\n# base 64 data encoding the data. The strings are split into an array\n# to avoid exceeding C++'s maximum string literal length.\n#########################################################################\n\n# Get to this script's git repo root.\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\ncd \"$(git rev-parse --show-toplevel)\"\n\n{\n    echo '#include \"stim/diagram/gate_data_3d_texture_data.h\"';\n    echo '';\n    echo 'std::string stim_draw_internal::make_gate_3d_texture_data_uri() {';\n    echo '    std::string result;';\n    echo '    result.append(\"data:image/png;base64,\");';\n    base64 -w 1024 | sed 's/.*/    result.append(\"\\0\");/g';\n    echo '    return result;';\n    echo '}';\n} > \"src/stim/diagram/gate_data_3d_texture_data.cc\"\n"
  },
  {
    "path": "dev/util_gen_stub_file.py",
    "content": "import dataclasses\nimport types\nfrom typing import Any\nfrom typing import Optional, Iterator, List\n\nimport inspect\nfrom typing import Tuple\n\nkeep = {\n    \"__add__\",\n    \"__ipow__\",\n    \"__radd__\",\n    \"__eq__\",\n    \"__call__\",\n    \"__ge__\",\n    \"__getitem__\",\n    \"__gt__\",\n    \"__iadd__\",\n    \"__imul__\",\n    \"__init__\",\n    \"__truediv__\",\n    \"__itruediv__\",\n    \"__ne__\",\n    \"__neg__\",\n    \"__le__\",\n    \"__len__\",\n    \"__lt__\",\n    \"__mul__\",\n    \"__setitem__\",\n    \"__str__\",\n    \"__pos__\",\n    \"__pow__\",\n    \"__repr__\",\n    \"__rmul__\",\n    \"__hash__\",\n    \"__iter__\",\n    \"__next__\",\n}\nskip = {\n    \"__annotate_func__\",\n    \"__annotations_cache__\",\n    \"__firstlineno__\",\n    \"__static_attributes__\",\n    \"__replace__\",\n    \"__builtins__\",\n    \"__cached__\",\n    \"__getstate__\",\n    \"__setstate__\",\n    \"__path__\",\n    \"__class__\",\n    \"__delattr__\",\n    \"__dir__\",\n    \"__doc__\",\n    \"__file__\",\n    \"__format__\",\n    \"__getattribute__\",\n    \"__init_subclass__\",\n    \"__loader__\",\n    \"__module__\",\n    \"__name__\",\n    \"__new__\",\n    \"__package__\",\n    \"__reduce__\",\n    \"__reduce_ex__\",\n    \"__setattr__\",\n    \"__sizeof__\",\n    \"__spec__\",\n    \"__subclasshook__\",\n    \"__version__\",\n    \"__annotations__\",\n    \"__dataclass_fields__\",\n    \"__dataclass_params__\",\n    \"__dict__\",\n    \"__match_args__\",\n    \"__post_init__\",\n    \"__weakref__\",\n    \"__abstractmethods__\",\n    \"__annotate_func__\",\n    \"__annotations_cache__\",\n}\n\n\ndef normalize_doc_string(d: str) -> str:\n    lines = d.splitlines()\n    indented_lines = [e for e in lines[1:] if e.strip()]\n    indentation = min([len(line) - len(line.lstrip()) for line in indented_lines], default=0)\n    return \"\\n\".join(lines[:1] + [e[indentation:] for e in lines[1:]])\n\n\ndef indented(*, paragraph: str, indentation: str) -> str:\n    return \"\".join(\n        indentation * (line != '\\n') + line\n        for line in paragraph.splitlines(keepends=True)\n    )\n\n\nclass DescribedObject:\n    def __init__(self):\n        self.full_name = \"\"\n        self.level = 0\n        self.lines = []\n\n\ndef splay_signature(sig: str) -> List[str]:\n    # Maintain backwards compatibility with python 3.6\n    sig = sig.replace('list[', 'List[')\n    sig = sig.replace('dict[', 'Dict[')\n    sig = sig.replace('tuple[', 'Tuple[')\n    sig = sig.replace('set[', 'Set[')\n    sig = sig.replace('pathlib._local.Path', 'pathlib.Path')\n\n    assert sig.startswith('def')\n    out = []\n\n    level = 0\n\n    start = sig.index('(') + 1\n    mark = start\n    out.append(sig[:mark])\n    for k in range(mark, len(sig)):\n        c = sig[k]\n        if c in '([':\n            level += 1\n        if c in '])':\n            level -= 1\n        if (c == ',' and level == 0) or level < 0:\n            k2 = k + (0 if level < 0 else 1)\n            s = sig[mark:k2].lstrip()\n            if s:\n                if not s.endswith(','):\n                    s += ','\n                out.append('    ' + s)\n            mark = k2\n        if level < 0:\n            break\n    assert level == -1\n    out.append(sig[mark:])\n    return out\n\n\ndef _handle_pybind_method(\n    *,\n    obj: Any,\n    is_property: bool,\n    out_obj: DescribedObject,\n    parent: Any,\n    full_name: str,\n) -> Tuple[str, bool, str, str]:\n    doc = normalize_doc_string(getattr(obj, \"__doc__\", \"\"))\n    if is_property:\n        out_obj.lines.append(\"@property\")\n    doc_lines = doc.splitlines()\n    new_args_name = None\n    was_args = False\n    sig_handled = False\n    has_setter = False\n    doc_lines_left = []\n    term_name = full_name.split(\".\")[-1]\n    for line in doc_lines:\n        if was_args and line.strip().startswith('*') and ':' in line:\n            new_args_name = line[line.index('*'):line.index(':')]\n        if '@overload ' in line:\n            _, sig = line.split('@overload ')\n            out_obj.lines.append(\"@overload\")\n            is_static = '(self' not in sig and inspect.isclass(parent)\n            if is_static:\n                out_obj.lines.append(\"@staticmethod\")\n            out_obj.lines.extend(splay_signature(sig))\n            out_obj.lines.append(\"    pass\")\n        elif '@signature ' in line:\n            _, sig = line.split('@signature ')\n            is_static = '(self' not in sig and inspect.isclass(parent)\n            if term_name not in sig:\n                raise ValueError(f\"Expected name {term_name!r} to appear in signature override for {full_name!r}:\\n    {line}\")\n            if is_static:\n                out_obj.lines.append(\"@staticmethod\")\n            out_obj.lines.extend(splay_signature(sig))\n            sig_handled = True\n        else:\n            doc_lines_left.append(line)\n        was_args = 'Args:' in line\n\n    if is_property:\n        if hasattr(obj, 'fget'):\n            sig_name = term_name + obj.fget.__doc__.replace('arg0', 'self').strip()\n        else:\n            sig_name = f'{term_name}(self)'\n        if getattr(obj, 'fset', None) is not None:\n            has_setter = True\n    elif doc_lines_left[0].startswith(term_name):\n        sig_name = term_name + doc_lines_left[0][len(term_name):]\n        doc_lines_left = doc_lines_left[1:]\n    else:\n        sig_name = term_name\n\n    doc = \"\\n\".join(doc_lines_left).lstrip()\n    text = \"\"\n    if not sig_handled:\n        if \"(self: \" in sig_name:\n            k_low = sig_name.index(\"(self: \") + len('(self')\n            k_high = len(sig_name)\n            if '->' in sig_name: k_high = sig_name.index('->', k_low, k_high)\n            k_high = sig_name.index(\", \" if \", \" in sig_name[k_low:k_high] else \")\", k_low, k_high)\n            sig_name = sig_name[:k_low] + sig_name[k_high:]\n        if not sig_handled:\n            is_static = '(self' not in sig_name and inspect.isclass(parent)\n            if is_static:\n                out_obj.lines.append(\"@staticmethod\")\n        sig_name = sig_name.replace(': handle', ': Any')\n        sig_name = sig_name.replace('numpy.', 'np.')\n        if new_args_name is not None:\n            sig_name = sig_name.replace('*args', new_args_name)\n        text = \"\\n\".join(splay_signature(f\"def {sig_name}:\"))\n    return text, has_setter, doc, sig_name\n\n\ndef print_doc(*, full_name: str, parent: object, obj: object, level: int) -> Optional[DescribedObject]:\n    out_obj = DescribedObject()\n    out_obj.full_name = full_name\n    out_obj.level = level\n    doc = getattr(obj, \"__doc__\", None) or \"\"\n    doc = normalize_doc_string(doc)\n    if full_name.endswith(\"__\") and len(doc.splitlines()) <= 2:\n        return None\n\n    term_name = full_name.split(\".\")[-1]\n    is_property = isinstance(obj, property)\n    is_method = doc.startswith(term_name)\n    has_setter = False\n    is_normal_method = isinstance(obj, types.FunctionType)\n    sig_name = ''\n    if 'sinter' in full_name and is_normal_method:\n        text = ''\n        if term_name in getattr(parent, '__abstractmethods__', []):\n            text += '@abc.abstractmethod\\n'\n        sig_name = f'{term_name}{inspect.signature(obj)}'\n        text += \"\\n\".join(splay_signature(f\"def {sig_name}:\"))\n\n        # Replace default value lambdas with their source.\n        if 'lambda' in str(text):\n            for name, param in inspect.signature(obj).parameters.items():\n                if 'lambda' in str(param.default):\n                    _, lambda_src = inspect.getsource(param.default).split('lambda ')\n                    lambda_src = lambda_src.strip()\n                    assert lambda_src.endswith(',')\n                    lambda_src = 'lambda ' + lambda_src[:-1]\n                    text = text.replace(str(param.default), lambda_src)\n\n        text = text.replace('numpy.', 'np.')\n    elif is_method or is_property:\n        text, has_setter, doc, sig_name = _handle_pybind_method(\n            obj=obj,\n            is_property=is_property,\n            out_obj=out_obj,\n            parent=parent,\n            full_name=full_name,\n        )\n    elif isinstance(obj, (int, str)):\n        text = f\"{term_name}: {type(obj).__name__} = {obj!r}\"\n        doc = ''\n    elif term_name == term_name.upper():\n        return None  # Skip constants because they lack a doc string.\n    else:\n        text = f\"class {term_name}\"\n        if inspect.isabstract(obj):\n            text += '(metaclass=abc.ABCMeta)'\n        text += ':'\n    if doc:\n        if text:\n            text += \"\\n\"\n        text += indented(paragraph=f\"\\\"\\\"\\\"{doc.rstrip()}\\n\\\"\\\"\\\"\",\n                         indentation=\"    \")\n\n    dataclass_fields = getattr(obj, \"__dataclass_fields__\", [])\n    if dataclass_fields:\n        dataclass_prop ='@dataclasses.dataclass'\n        if getattr(obj, '__dataclass_params__').frozen:\n            dataclass_prop += '(frozen=True)'\n        out_obj.lines.append(dataclass_prop)\n\n    out_obj.lines.append(text.replace('._stim_avx2', '').replace('._stim_sse2', ''))\n    if has_setter:\n        if '->' in sig_name:\n            setter_type = sig_name[sig_name.index('->') + 2:].strip().replace('._stim_avx2', '')\n        else:\n            setter_type = 'Any'\n        out_obj.lines.append(f\"@{term_name}.setter\")\n        out_obj.lines.append(f\"def {term_name}(self, value: {setter_type}):\")\n        out_obj.lines.append(f\"    pass\")\n\n    if dataclass_fields:\n        for f in dataclasses.fields(obj):\n            if str(f.type).startswith('typing'):\n                t = str(f.type).replace('typing.', '')\n            else:\n                t = f.type.__name__\n            t = t.replace('''Union[Dict[str, ForwardRef('JSON_TYPE')], List[ForwardRef('JSON_TYPE')], str, int, float]''', 'Any')\n            if f.default is dataclasses.MISSING:\n                out_obj.lines.append(f'    {f.name}: {t}')\n            else:\n                out_obj.lines.append(f'    {f.name}: {t} = {f.default}')\n\n    return out_obj\n\n\ndef generate_documentation(*, obj: object, level: int, full_name: str) -> Iterator[DescribedObject]:\n    if full_name.endswith(\"__\"):\n        return\n    if not inspect.ismodule(obj) and not inspect.isclass(obj):\n        return\n\n    for sub_name in dir(obj):\n        if sub_name in getattr(obj, '__dataclass_fields__', []):\n            continue\n        if sub_name in skip:\n            continue\n        if sub_name.startswith(\"__pybind11\"):\n            continue\n        if sub_name.startswith('_') and not sub_name.startswith('__'):\n            continue\n        if sub_name.endswith(\"__\") and sub_name not in keep:\n            raise ValueError(\"Need to classify \" + sub_name + \" as keep or skip.\")\n        sub_full_name = full_name + \".\" + sub_name\n        sub_obj = getattr(obj, sub_name)\n        v = print_doc(full_name=sub_full_name, obj=sub_obj, level=level + 1, parent=obj)\n        if v is not None:\n            yield v\n        yield from generate_documentation(\n            obj=sub_obj,\n            level=level + 1,\n            full_name=sub_full_name)\n"
  },
  {
    "path": "doc/circuit_data_references.md",
    "content": "## 2021\n\n- [arXiv:2103.02202](https://arxiv.org/abs/2103.02202) → [Ancillary files of \"Stim: a fast stabilizer circuit simulator\"](https://arxiv.org/src/2103.02202v3/anc)\n- [arXiv:2108.10457](https://arxiv.org/abs/2108.10457) → [Ancillary files of \"A Fault-Tolerant Honeycomb Memory\"](https://arxiv.org/src/2108.10457v2/anc)\n\n## 2022\n\n- [arXiv:2202.11845](https://arxiv.org/abs/2202.11845) → [Data for \"Benchmarking the Planar Honeycomb Code\"](https://zenodo.org/records/7072889)\n- [arXiv:2204.13834](https://arxiv.org/abs/2204.13834) → [Data for \"Stability Experiments: The Overlooked Dual of Memory Experiments\"](https://zenodo.org/records/6859486)\n- [arXiv:2206.12780](https://arxiv.org/abs/2206.12780) → [Data for \"A Pair Measurement Surface Code on Pentagons\"](https://zenodo.org/records/6626417)\n- [arXiv:2207.06431](https://arxiv.org/abs/2207.06431) → [Data for \"Suppressing quantum errors by scaling a surface code logical qubit\"](https://zenodo.org/records/6804040)\n- [arXiv:2209.08552](https://arxiv.org/abs/2209.08552) → [Parallel window decoding enables scalable fault tolerant quantum computation](https://doi.org/10.5281/zenodo.8422904)\n\n## 2023\n\n- [arXiv:2302.02192](https://arxiv.org/abs/2302.02192) → [Data for \"Relaxing Hardware Requirements for Surface Code Circuits using Time-dynamics\"](https://zenodo.org/records/7587578)\n- [arXiv:2302.07395](https://arxiv.org/abs/2302.07395) → [Data for \"Inplace Access to the Surface Code Y Basis\"](https://zenodo.org/records/7487893)\n- [arXiv:2302.12292](https://arxiv.org/abs/2302.12292) → [Data for \"Cleaner magic states with hook injection\"](https://zenodo.org/records/7575030)\n- [arXiv:2305.12046](https://arxiv.org/abs/2305.12046) → [Data for \"Less Bacon More Threshold\"](https://zenodo.org/records/7901729)\n- [arXiv:2307.10147](https://arxiv.org/abs/2307.10147) → [Stim circuits for \"Tangling schedules eases hardware connectivity requirements for quantum error correction\" manuscript](https://zenodo.org/records/8391674)\n- [arXiv:2308.03750](https://arxiv.org/abs/2308.03750) → [Ancillary data for the paper \"Constructions and performance of hyperbolic and semi-hyperbolic Floquet codes\" ](https://github.com/oscarhiggott/hyperbolic-floquet-data)\n- [arXiv:2309.05558](https://arxiv.org/abs/2309.05558) → [Data supporting \"A real-time, scalable, fast and resource-efficient decoder for a quantum computer\"](https://zenodo.org/records/11621878)\n- [arXiv:2312.04522](https://arxiv.org/abs/2312.04522) → [Data for \"Yoked Surface Codes\"](https://zenodo.org/records/10277397)\n- [arXiv:2312.08813](https://arxiv.org/abs/2312.08813) → [Data for \"New circuits and an open source decoder for the colorcode\"](https://zenodo.org/records/10375289)\n- [arXiv:2312.11605](https://arxiv.org/abs/2312.11605) → [Stim circuits and collected data for \"Error-corrected Hadamard gate simulated at the circuit level\" manuscript](https://zenodo.org/records/10391116)\n- [arXiv:2312.14060](https://arxiv.org/abs/2312.14060) → [Data for \"Fault-tolerant quantum architectures based on erasure qubits\"](https://zenodo.org/records/13730128)\n\n## 2024\n\n- [arXiv:2405.15854](https://arxiv.org/abs/2405.15854) → [Stim circuits for 'Accommodating Fabrication Defects on Floquet Codes with Minimal Hardware Requirements' manuscript](https://zenodo.org/records/11241876)\n- [arXiv:2406.02700](https://arxiv.org/abs/2406.02700) → [Data for \"Optimization of decoder priors for accurate quantum error correction\"](https://zenodo.org/records/11403595)\n- [arXiv:2407.13826](https://arxiv.org/abs/2407.13826) → [Stim circuits for 'Designing fault-tolerant circuits using detector error models'](https://github.com/peter-janderks/short_measurement_schedules_simulations/tree/main/stim_circuits)\n- [arXiv:2408.00758](https://arxiv.org/abs/2408.00758) → [Stim circuits for ``To reset, or not to reset -- that is the question\" manuscript](https://zenodo.org/records/13152440)\n- [arXiv:2408.11894](https://arxiv.org/abs/2408.11894) → [Stim circuits for 'Automated Synthesis of Fault-Tolerant State Preparation Circuits for Quantum Error Correction Codes'](https://github.com/cda-tum/mqt-qecc/tree/main/src/mqt/qecc/ft_stateprep/eval/circuits)\n- [arXiv:2408.13687](https://arxiv.org/abs/2408.13687) → [Data for \"Quantum error correction below the surface code threshold\"](https://zenodo.org/records/13273331)\n- [arXiv:2409.04628](https://arxiv.org/abs/2409.04628) → [Stim implementation of the [[16,4,4]] Tesseract Code](https://github.com/DeDuckProject/tesseract-code-stim) (circuits are in the stim_circuits/ directory)\n- [arXiv:2409.17595](https://arxiv.org/abs/2409.17595) → [Data for \"Magic state cultivation: growing T states as cheap as CNOT gates\"](https://zenodo.org/records/13777072)\n- [arXiv:2412.01391](https://arxiv.org/abs/2412.01391) → [GitHub repo for \"Transversal Logical Clifford gates on rotated surface codes with reconfigurable neutral atom arrays\"](https://github.com/Zihan-Chen-PhMA/Dynamical-S-gate-decoding/) (circuits are in the circuit_garage/ directory)\n- [arXiv:2412.14256](https://arxiv.org/abs/2412.14256) → [Data for \"Scaling and logic in the color code on a superconducting quantum processor\"](https://zenodo.org/records/14238944)\n- [arXiv:2412.14360](https://arxiv.org/abs/2412.14360) → [Data for \"Demonstrating dynamic surface codes\"](https://zenodo.org/records/14238907)\n- [arXiv:2412.15187](https://arxiv.org/abs/2412.15187) → [Stim circuits and results for \"Universal quantum computation via scalable measurement-free error correction\"](https://zenodo.org/records/15707012)\n\n## 2025\n\n- [arXiv:2503.04968](https://arxiv.org/abs/2503.04968) → [GitHub repo for \"Optimized Noise-Resilient Surface Code Teleportation Interfaces\"](https://github.com/QEC-pages/Modular-Surface-code-simulations/) (circuits are in the out/ directory)\n- [arXiv:2503.18657](https://arxiv.org/abs/2503.18657) → [GitHub repo for \"Efficient Magic State Cultivation on RP^2\"](https://github.com/Zihan-Chen-PhMA/Cultiv_T_RP2/) (circuits are in the circuit_garage/ directory)\n- [arXiv:2504.02935](https://arxiv.org/abs/2504.02935) → [Scripts, Stim circuits and simulation results for \"Magic State Injection with Erasure Qubits\"](https://zenodo.org/records/15874462)\n- [arXiv:2507.08069](https://arxiv.org/abs/2507.08069) → [Stim circuits and simulation results for \"A dynamic circuit for the honeycomb Floquet code\"](https://zenodo.org/records/15854678)\n- [arXiv:2507.19430](https://arxiv.org/abs/2507.19430) → [Stim circuits and parity check matrices for \"Directional Codes: a new family of quantum LDPC codes on hexagonal- and square-grid connectivity hardware\" manuscript](https://zenodo.org/records/16422162)\n- [arXiv:2512.17999](https://arxiv.org/abs/2512.17999) → [Stim circuits for \"Logical gates on Floquet codes via folds and twists\"](https://zenodo.org/records/17966122)\n"
  },
  {
    "path": "doc/developer_documentation.md",
    "content": "# Stim Developer Documentation\n\nThis is documentation for programmers working with stim, e.g. how to build it.\nThese notes generally assume you are on a Linux system.\n\n# Index\n\n- [compatibility guarantees across versions](#compatibility)\n- [releasing a new version](#release-checklist)\n- [building `stim` command line tool](#build)\n    - [with cmake](#build.cmake)\n    - [with bazel](#build.bazel)\n    - [with gcc](#build.gcc)\n- [linking to `libstim` shared library](#link)\n    - [with cmake](#link.cmake)\n    - [with bazel](#link.bazel)\n- [running C++ tests](#test)\n    - [with cmake](#test.cmake)\n    - [with bazel](#test.bazel)\n- [running performance benchmarks](#perf)\n    - [with cmake](#perf.cmake)\n    - [with bazel](#perf.bazel)\n    - [interpreting output from `stim_perf`](#perf.output)\n    - [profiling with gcc and perf](#perf.profile)\n- [creating a python dev environment](#venv)\n- [running python unit tests](#test.pytest)\n    - [running sinter tests against a custom decoder](#test.pytest.sinter.custom)\n- [python packaging `stim`](#pypackage.stim)\n    - [with cibuildwheels](#pypackage.stim.cibuildwheels)\n    - [with bazel](#pypackage.stim.bazel)\n    - [with python setup.py](#pypackage.stim.python)\n    - [with pip install -e](#pypackage.stim.pip)\n    - [with cmake](#pypackage.stim.cmake)\n- [python packaging `stimcirq`](#pypackage.stimcirq)\n    - [with python setup.py](#pypackage.stimcirq.python)\n    - [with pip install -e](#pypackage.stimcirq.pip)\n- [python packaging `sinter`](#pypackage.sinter)\n    - [with python setup.py](#pypackage.sinter.python)\n    - [with pip install -e](#pypackage.sinter.pip)\n- [javascript packaging `stimjs`](#jspackage.stimjs)\n    - [with emscripten](#jspackage.stimjs.emscripten)\n- [autoformating code](#autoformat)\n    - [with clang-format](#autoformat.clang-format)\n- [adding new c++ files](#newfile)\n- [adding new CLI commands](#newcmd)\n\n# <a name=\"compatibility\"></a>Compatibility guarantees across versions\n\nA *bug* is bad behavior that wasn't intended. For example, the program crashing instead of returning empty results when sampling from an empty circuit would be a bug.\n\nA *trap* is originally-intended behavior that leads to the user making mistakes. For example, allowing the user to take a number of shots that wasn't a multiple of 64 when using the data format `ptb64` was a trap because the shots were padded up to a multiple of 64 using zeroes (and these fake shots could then easily be treated as real by later analysis steps).\n\nA *spandrel* is an implementation detail that has observable effects, but which is not really required to behave in that specific way. For example, when stim derives a detector error model from a circuit, the exact probability of an error instruction depends on minor details such as floating point error (which is sensitive to compiler optimizations). The exact floating point error that occurs is a spandrel.\n\n- **Stim Python API**\n    - The python API must maintain backwards compatibility from minor version to minor version (except for bug fixes, trap fixes, and spandrels). Violating this requires a new major version.\n    - Trap fixes must be documented as breaking changes in the release notes.\n    - The exact behavior of random seeding is a spandrel. The behavior must be consistent on a single machine for a single version, with the same seed always producing the same results, but it is **not** stable between minor versions. This is enforced by intentionally introducing changes for every single minor version.\n- **Stim Command Line API**\n    - The command land API must maintain backwards compatibility from minor version to minor version (except for bug fixes, trap fixes, and spandrels). Violating this requires a new major version.\n    - Trap fixes must be documented as breaking changes in the release notes.\n    - It is explicitly **not** allowed for a command to stop working due to, for example, a cleanup effort to make the commands more consistent. Violating this requires a new major version.\n    - The exact behavior of random seeding is a spandrel. The behavior must be consistent on a single machine for a single version, with the same seed always producing the same results, but it is **not** stable between minor versions. This is enforced by intentionally introducing changes for every single minor version.\n- **Stim C++ API**\n    - The C++ API makes no compatibility guarantees. It may change arbitrarily and catastrophically from minor version to minor version.\n\n# <a name=\"release-checklist\"></a>Releasing a new version\n\n- Create an off-main-branch release commit\n    - [ ] `git checkout main -b SOMEBRANCHNAME`\n    - [ ] Global search replace `__version__ = 'X.Y.dev0'` with `__version__ = 'X.Y.0'`\n    - [ ] `git commit -a -m \"Bump to vX.Y.0\"`\n    - [ ] `git tag vX.Y.0`\n    - [ ] Push tag to github\n    - [ ] Check github `Actions` tab and confirm ci is running on the tag\n    - [ ] Wait for ci to finish validating and producing artifacts for the tag\n    - [ ] Get `stim`, `stimcirq`, and `sinter` wheels/sdists [from cibuildwheels](#pypackage.stim.cibuildwheels) of this tag\n- Bump to next dev version on main branch\n    - [ ] `git checkout main -b SOMEBRANCHNAME`\n    - [ ] Global search replace `__version__ = 'X.Y.dev0'` with `__version__ = 'X.(Y+1).dev0'`\n    - [ ] Increment `INTENTIONAL_VERSION_SEED_INCOMPATIBILITY` in `src/stim/circuit/circuit.h`\n    - [ ] `git commit -a -m \"Start vX.(Y+1).dev\"`\n    - [ ] Push to github as a branch and merge into main using a pull request\n- Write release notes on github\n    - [ ] In title, use two-word theming of most important changes\n    - [ ] Flagship changes section\n    - [ ] Notable changes section\n    - [ ] Include wheels/sdists as attachments\n- Do these irreversible and public viewable steps last!\n    - [ ] Upload wheels/sdists to pypi using `twine`\n    - [ ] Publish the github release notes\n    - [ ] Add gates reference page to wiki for the new version\n    - [ ] Add python api reference page to wiki for the new version\n    - [ ] Update main wiki page to point to latest reference pages\n    - [ ] Tweet about the release\n\n\n# <a name=\"build\"></a>Building `stim` command line tool\n\nThe stim command line tool is a binary program `stim` that accepts commands like\n`stim sample -shots 100 -in circuit.stim`\n(see [the command line reference](usage_command_line.md)).\nIt can be built [with cmake](#build.cmake), [with bazel](#build.bazel), or\nmanually [with gcc](#build.gcc).\n\n## <a name=\"build.cmake\"></a>Building `stim` command line tool with cmake\n\n```bash\n# from the repository root:\ncmake .\nmake stim\n\n# output binary ends up at:\n# ./out/stim\n```\n\nStim can also be installed:\n```bash\n# from the repository root:\ncmake .\nmake stim\nmake install\n\n# output binary ends up at:\n# -CMAKE_INSTALL_PREFIX/bin\n# output library ends up at:\n# -CMAKE_INSTALL_PREFIX/lib\n# output headers end up at:\n# -CMAKE_INSTALL_PREFIX/include\n```\nby default `make install` will install to the system default directory (e.g.\n`/usr/local`). The install path can be controlled by passing the flag\n`-DCMAKE_INSTALL_PREFIX=/path/to/install` to `cmake`.\n\nVectorization can be controlled by passing the flag `-DSIMD_WIDTH` to `cmake`:\n\n- `cmake . -DSIMD_WIDTH=256` means \"use 256 bit avx operations\" (forces `-mavx2`)\n- `cmake . -DSIMD_WIDTH=128` means \"use 128 bit sse operations\" (forces `-msse2`)\n- `cmake . -DSIMD_WIDTH=64` means \"don't use simd operations\" (no machine arch flags)\n- `cmake .` means \"use the best thing possible on this machine\" (forces `-march=native`)\n\nA `compile_commands.json` (used by clangd to provide IDE features over lsp)\ncan be generated by passing the flag `-DCMAKE_EXPORT_COMPILE_COMMANDS=1` to `cmake`.\n\n\n## <a name=\"build.bazel\"></a>Building `stim` command line tool with bazel\n\n```bash\nbazel build stim\n```\n\nor, to build and run:\n\n```bash\nbazel run stim\n```\n\n## <a name=\"build.gcc\"></a>Building `stim` command line tool with gcc\n\n```bash\n# from the repository root:\nfind src \\\n    | grep \"\\\\.cc$\" \\\n    | grep -v \"\\\\.\\(test\\|perf\\|pybind\\)\\\\.cc$\" \\\n    | xargs g++ -I src -pthread -std=c++20 -O3 -march=native\n\n# output binary ends up at:\n# ./a.out\n```\n\n\n# <a name=\"link\"></a>Linking to `libstim` shared library\n\n**!!!CAUTION!!!\nStim's C++ API is not kept stable!\nAlways pin to a specific version!\nI *WILL* break your downstream code when I update stim if you don't!\nThe API is also not extensively documented;\nwhat you can find in the headers is what you get.**\n\nTo use Stim functionality within your C++ program, you can build `libstim` and\nlink to it to gain direct access to underlying Stim types and methods.\n\nIf you want a stim API that promises backwards compatibility, use the python API.\n\n## <a name=\"link.cmake\"></a>Linking to `libstim` shared library with cmake\n\n**!!!CAUTION!!!\nStim's C++ API is not kept stable!\nAlways pin to a specific version!\nI *WILL* break your downstream code when I update stim if you don't!\nThe API is also not extensively documented;\nwhat you can find in the headers is what you get.**\n\nIn your `CMakeLists.txt` file, use `FetchContent` to automatically fetch stim\nfrom github when running `cmake .`:\n\n```\n# in CMakeLists.txt file\n\ninclude(FetchContent)\nFetchContent_Declare(stim\n        GIT_REPOSITORY https://github.com/quantumlib/stim.git\n        GIT_TAG v1.4.0)  # [[[<<<<<<< customize the version you want!!]]]\nFetchContent_MakeAvailable(stim)\n```\n\n(Replace `v1.4.0` with another version tag as appropriate.)\n\nFor build targets that need to use stim functionality, add `libstim` to them\nusing `target_link_libraries`:\n\n```\n# in CMakeLists.txt file\n\ntarget_link_libraries(some_cmake_target PRIVATE libstim)\n```\n\nIn your source code, use `#include \"stim.h\"` to access stim types and functions:\n\n```\n// in a source code file\n\n#include \"stim.h\"\n\nstim::Circuit make_bell_pair_circuit() {\n    return stim::Circuit(R\"CIRCUIT(\n        H 0\n        CNOT 0 1\n        M 0 1\n        DETECTOR rec[-1] rec[-2]\n    )CIRCUIT\");\n}\n```\n\n## <a name=\"link.bazel\"></a>Linking to `libstim` shared library with bazel\n\n**!!!CAUTION!!!\nStim's C++ API is not kept stable!\nAlways pin to a specific version!\nI *WILL* break your downstream code when I update stim if you don't!\nThe API is also not extensively documented;\nwhat you can find in the headers is what you get.**\n\nIn your `WORKSPACE` file, include stim's git repo using `git_repository`:\n\n```\n# in WORKSPACE file\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"git_repository\")\n\ngit_repository(\n    name = \"stim\",\n    commit = \"v1.4.0\",\n    remote = \"https://github.com/quantumlib/stim.git\",\n)\n```\n\n(Replace `v1.4.0` with another version tag or commit SHA as appropriate.)\n\nIn your `BUILD` file, add `@stim//:stim_lib` to the relevant target's `deps`:\n\n```\n# in BUILD file\n\ncc_binary(\n    ...\n    deps = [\n        ...\n        \"@stim//:stim_lib\",\n        ...\n    ],\n)\n```\n\nIn your source code, use `#include \"stim.h\"` to access stim types and functions:\n\n```\n// in a source code file\n\n#include \"stim.h\"\n\nstim::Circuit make_bell_pair_circuit() {\n    return stim::Circuit(R\"CIRCUIT(\n        H 0\n        CNOT 0 1\n        M 0 1\n        DETECTOR rec[-1] rec[-2]\n    )CIRCUIT\");\n}\n```\n\n\n# <a name=\"test\"></a>Running unit tests\n\nStim's code base includes a variety of types of tests, spanning over a few\npackages and languages.\n\n## <a name=\"test.cmake\"></a>Running C++ unit tests with cmake\n\nUnit testing with cmake requires the GTest library to be installed on your\nsystem in a place that cmake can find it.\nFollow the [\"Standalone CMake Project\" instructions from the GTest README](https://github.com/google/googletest/tree/master/googletest)\nto get GTest installed correctly.\n\nRun tests with address and memory sanitization, without compile time optimization:\n\n```bash\n# from the repository root:\ncmake .\nmake stim_test\n./out/stim_test\n```\n\nRun tests without sanitization, with compile time optimization:\n\n```bash\n# from the repository root:\ncmake .\nmake stim_test_o3\n./out/stim_test_o3\n```\n\nStim supports 256 bit (AVX), 128 bit (SSE), and 64 bit (native) vectorization.\nThe type to use is chosen at compile time.\nTo force this choice (so that each case can be tested on one machine),\nadd `-DSIMD_WIDTH=256` or `-DSIMD_WIDTH=128` or `-DSIMD_WIDTH=64`\nto the `cmake .` command.\n\n## <a name=\"test.bazel\"></a>Running C++ unit tests with bazel\n\n```bash\n# from the repository root:\nbazel test stim_test\n```\n\n# <a name=\"perf\"></a>Running performance benchmarks\n\n## <a name=\"perf.cmake\"></a>Running performance benchmarks with cmake\n\n```bash\ncmake .\nmake stim_perf\n./out/stim_perf\n```\n\n## <a name=\"perf.cmake\"></a>Running performance benchmarks with bazel\n\n```bash\nbazel run stim_perf\n```\n\n## <a name=\"perf.output\"></a>Interpreting output from `stim_perf`\n\nWhen you run `stim_perf` you will see output like:\n\n```\n[....................*....................] 460 ns (vs 450 ns) ( 21 GBits/s) simd_bits_randomize_10K\n[...................*|....................]  24 ns (vs  20 ns) (400 GBits/s) simd_bits_xor_10K\n[....................|>>>>*...............] 3.6 ns (vs 4.0 ns) (270 GBits/s) simd_bits_not_zero_100K\n[....................*....................] 5.8 ms (vs 6.0 ms) ( 17 GBits/s) simd_bit_table_inplace_square_transpose_diam10K\n[...............*<<<<|....................] 8.1 ms (vs 5.0 ms) ( 12 GOpQubits/s) FrameSimulator_depolarize1_100Kqubits_1Ksamples_per1000\n[....................*....................] 5.3 ms (vs 5.0 ms) ( 18 GOpQubits/s) FrameSimulator_depolarize2_100Kqubits_1Ksamples_per1000\n```\n\nThe bars on the left show how fast each task is running compared to baseline expectations (on my dev machine).\nEach tick away from the center `|` is 1 decibel slower or faster (i.e. each `<` or `>` represents a factor of `1.26`).\n\nBasically, if you see `[......*<<<<<<<<<<<<<|....................]` then something is *seriously* wrong, because the\ncode is running 25x slower than expected.\n\nThe `stim_perf` binary supports a `--only=BENCHMARK_NAME` filter flag.\nMultiple filters can be specified by separating them with commas `--only=A,B`.\nEnding a filter with a `*` turns it into a prefix filter `--only=sim_*`.\n\n## <a name=\"perf.profile\"></a>Profiling with gcc and perf\n\n```bash\nfind src \\\n    | grep \"\\\\.cc\" \\\n    | grep -v \"\\\\.\\(test\\|perf\\|pybind\\)\\\\.cc\" \\\n    | xargs g++ -I src -pthread -std=c++20 -O3 -march=native -g -fno-omit-frame-pointer\nsudo perf record -g ./a.out  # [ADD STIM FLAGS FOR THE CASE YOU WANT TO PROFILE]\nsudo perf report\n```\n\n\n## <a name=\"venv\"></a>Creating a python dev environment\n\nFirst, create a fresh python 3.6+ virtual environment using your favorite\nmethod:\n[`python -m venv`](https://docs.python.org/3/library/venv.html),\n[`virtualenvwrapper`](https://virtualenvwrapper.readthedocs.io/en/latest/),\n[`conda`](https://docs.conda.io/en/latest/),\nor etc.\n\nSecond, build and install a stim wheel.\nFollow the [python packaging stim](#pypackage.stim) instructions to\ncreate a wheel.\nI recommend [packaging with bazel](#pypackage.stim) because it is **BY FAR** the\nfastest.\nOnce you have the wheel, run `pip install [that_wheel]`.\nFor example:\n\n```base\n# from the repository root in a python virtual environment\nbazel build :stim_dev_wheel\npip uninstall stim --yes\npip install bazel-bin/stim-0.0.dev0-py3-none-any.whl\n```\n\nNote that you need to repeat the above steps each time you make a change to\n`stim`.\n\nThird, use `pip install -e` to install development references to the pure-python\nglue packages:\n\n```\n# install test dependencies\npip install pytest pymatching\n\n# install stimcirq dev reference:\npip install -e glue/cirq\n\n# install sinter dev reference:\npip install -e glue/sample\n\n# install stimzx dev reference:\npip install -e glue/zx\n```\n\n## <a name=\"test.pytest\"></a>Running python unit tests\n\nSee [creating a python dev environment](#venv) for instructions on creating a\npython virtual environment with your changes to stim installed.\n\nUnit tests are run using `pytest`.\nExamples in docstrings are tested using the `dev/doctest_proper` script,\nwhich uses python's [`doctest`](https://docs.python.org/3/library/doctest.html) module\nbut ensures values added to a module at import time are also tested (instead of requiring\nthem to be [manually listed in a `__test__` property](https://docs.python.org/3/library/doctest.html#which-docstrings-are-examined)).\n\nTo test everything:\n\n```bash\n# from the repository root in a virtualenv with development wheels installed:\npytest src glue\ndev/doctest_proper.py --module stim\ndev/doctest_proper.py --module stimcirq --import cirq sympy\ndev/doctest_proper.py --module sinter\ndev/doctest_proper.py --module stimzx\n```\n\nTest only `stim`:\n\n```bash\n# from the repository root in a virtualenv with development wheels installed:\npytest src\ndev/doctest_proper.py --module stim\n```\n\nTest only `stimcirq`:\n\n```bash\n# from the repository root in a virtualenv with development wheels installed:\npytest glue/cirq\ndev/doctest_proper.py --module stimcirq --import cirq sympy\n```\n\nTest only `sinter`:\n\n```bash\n# from the repository root in a virtualenv with development wheels installed:\npytest glue/sample\ndev/doctest_proper.py --module sinter\n```\n\nTest only `stimzx`:\n\n```bash\n# from the repository root in a virtualenv with development wheels installed:\npytest glue/zx\ndev/doctest_proper.py --module stimzx\n```\n\n## <a name=\"test.pytest.sinter.custom\"></a>Running sinter's python unit tests against a custom decoder\n\nSome of sinter's python unit tests verify that a decoder is behaving correctly.\nIt can be useful, when creating a custom decoder, to run these tests against the\ndecoder.\nThis can be done by setting the environment `SINTER_PYTEST_CUSTOM_DECODERS`\nvariable to `custom_package:custom_method` where `custom_package` is a python\npackage to import and `custom_method` is a method name implemented by that\npackage that returns a `Dict[str, sinter.Decoder]`. This is the same form of\nargument that's given to `sinter collect --custom_decoders`.\n\nExample:\n\n```\nSINTER_PYTEST_CUSTOM_DECODERS=\"my_custom_package:my_custom_sinter_decoder_dict_method\" pytest glue/sample\n```\n\n\n# <a name=\"pypackage.stim\"></a>python packaging `stim`\n\nBecause stim is a C++ extension, it is non-trivial to create working\npython packages for it.\nTo make cross-platform release wheels, we rely heavily on cibuildwheels.\nTo make development wheels, various other options are possible.\n\n## <a name=\"pypackage.stim.cibuildwheels\"></a>python packaging `stim` with cibuildwheels\n\nWhen a commit is merged into the `main` branch of stim's GitHub repository,\nthere are GitHub actions that use [cibuildwheels](https://github.com/pypa/cibuildwheel)\nto build wheels for all supported platforms.\n\ncibuildwheels can also be invoked locally, assuming you have Docker installed, using a command like:\n\n```bash\nCIBW_BUILD=cp39-manylinux_x86_64 cibuildwheel --platform linux\n# output goes into wheelhouse/\n````\n\nWhen these wheels are finished building, they are automatically uploaded to\npypi as a dev version of stim.\nFor release versions, the artifacts created by the github action must be\nmanually downloaded and uploaded using `twine`:\n\n```bash\ntwine upload --username=\"${PROD_TWINE_USERNAME}\" --password=\"${PROD_TWINE_PASSWORD}\" artifacts_directory/*\n```\n\n## <a name=\"pypackage.stim.bazel\"></a>python packaging `stim` with bazel\n\nBazel can be used to create dev versions of the stim python wheel:\n\n```bash\n# from the repository root:\nbazel build stim_dev_wheel\n# output is at bazel-bin/stim-0.0.dev0-py3-none-any.whl\n```\n\n## <a name=\"pypackage.stim.python\"></a>python packaging `stim` with python setup.py\n\nPython can be used to create dev versions of the stim python wheel (very slow):\n\nBinary distribution:\n\n```bash\n# from the repository root in a python venv with pybind11 installed:\npython setup.py bdist\n# output is at dist/*\n```\n\nSource distribution:\n\n```bash\n# from the repository root in a python venv with pybind11 installed:\npython setup.py sdist\n# output is at dist/*\n```\n\n## <a name=\"pypackage.stim.pip\"></a>python packaging `stim` with pip install -e\n\nYou can directly install stim as a development python wheel by using pip (very slow):\n\n```bash\n# from the repository root\npip install -e .\n# stim is now installed in current virtualenv as dev reference\n```\n\n## <a name=\"pypackage.stim.cmake\"></a>python packaging `stim` with cmake\n\nA python module can be built using cmake. The output can be imported as `import stim`, but is not packaged, so if you want to pip install, prefer building the bindings with Bazel.\n\n```bash\n# from the repository root\ncmake stim_python_bindings\n# output is at out/stim.cpython-${PYTHON_VERSION}-${ARCH}.so\nPYTHONPATH=out python -c \"import stim; print(stim.__version__)\"\n```\n\n\n# <a name=\"pypackage.stimcirq\"></a>Python packaging `stimcirq`\n\n## <a name=\"pypackage.stimcirq.python\"></a>Python packaging `stimcirq` with python setup.py\n\n```bash\n# from repo root\ncd glue/cirq\npython setup.py sdist\ncd -\n# output in glue/cirq/dist/*\n```\n\n## <a name=\"pypackage.stimcirq.pip\"></a>Python packaging `stimcirq` with pip install -e\n\n```bash\n# from repo root\npip install -e glue/cirq\n# stimcirq is now installed in current virtualenv as dev reference\n```\n\n# <a name=\"pypackage.sinter\"></a>Python packaging `sinter`\n\n## <a name=\"pypackage.sinter.python\"></a>Python packaging `sinter` with python setup.py\n\n```bash\n# from repo root\ncd glue/sample\npython setup.py sdist\ncd -\n# output in glue/sample/dist/*\n```\n\n## <a name=\"pypackage.sinter.pip\"></a>Python packaging `sinter` with pip install -e\n\n```bash\n# from repo root\npip install -e glue/sample\n# sinter is now installed in current virtualenv as dev reference\n```\n\n# <a name=\"pypackage.stimzx\"></a>Python packaging `stimzx`\n\n## <a name=\"pypackage.stimzx.python\"></a>Python packaging `stimzx` with python setup.py\n\n```bash\n# from repo root\ncd glue/zx\npython setup.py sdist\ncd -\n# output in glue/zx/dist/*\n```\n\n## <a name=\"pypackage.stimzx.pip\"></a>Python packaging `stimzx` with pip install -e\n\n```bash\n# from repo root\npip install -e glue/zx\n# stimzx is now installed in current virtualenv as dev reference\n```\n\n\n# <a name=\"jspackage\"></a>Javascript packaging `stimjs`\n\n## <a name=\"jspackage.stimjs\"></a>Javascript packaging `stimjs` with emscripten\n\nInstall and activate enscriptem (`emcc` must be in your PATH).\nExample:\n\n```bash\n# [outside of repo]\ngit clone git@github.com:emscripten-core/emsdk.git\ncd emsdk\n./emsdk install latest\n./emsdk activate latest\nsource emsdk_env.sh\n```\n\nRun the bash build script:\n\n```bash\n# [from repo root]\nglue/javascript/build_wasm.sh\n```\n\nOutputs are the binary `out/stim.js` and the test runner `out/all_stim_tests.html`.\nRun tests by opening in a browser and checking for an `All tests passed.` message in the browser console:\n\n```bash\nfirefox out/all_stim_tests.html\n```\n\n\n# <a name=\"autoformat\"></a>Autoformating code\n\n## <a name=\"autoformat.clang-format\"></a>Autoformating code with clang-format\n\nRun the following command from the repo root to auto-format all C++ code:\n\n```bash\nfind src | grep \"\\.\\(cc\\|h\\)$\" | grep -Pv \"crumble_data.cc|gate_data_3d_texture_data.cc\" | xargs clang-format -i\n```\n\n# <a name=\"newfile\"></a>Adding new C++ files\n\nFor the cmake build system, we maintain C++ file lists in the folder `file_lists`.\nWhen you add a new C++ file, they can be updated using `dev/regen_file_lists.sh`\n\n# <a name=\"newcmd\"></a>Adding new CLI commands\n\nA [reference](usage_command_line.md) is maintained to document the CLI usage. This is generated using\n`dev/regen_docs.sh` which assumes the script is run from a virtualenv with\na [dev wheel of stim](#python-packaging-stim) installed.\n"
  },
  {
    "path": "doc/file_format_dem_detector_error_model.md",
    "content": "# The Detector Error Model File Format (.dem)\n\nA detector error model file (.dem) is a human-readable specification of error mechanisms.\nThe intent of the file format is to act as a reasonably flexible configuration language that can be easily consumed by\n*decoders*, which attempt to predict the logical observable frame from symptoms within the context of an error model.\n\n## Index\n\n- [Encoding](#Encoding)\n- [Syntax](#Syntax)\n- [Semantics](#Semantics)\n    - [Instruction Types](#Instruction-Types)\n        - [`detector` instruction](#detector-instruction)\n        - [`logical_observable` instruction](#logical_observable-instruction)\n        - [`shift_detectors` instruction](#shift_detectors-instruction)\n        - [`error` instruction](#error-instruction)\n        - [`repeat` block](#repeat-block)\n    - [Target Types](#State-Space)\n        - [`D#`: relative detector target](#relative-detector-target)\n        - [`L#`: logical observable target](#logical-observable-target)\n        - [`#`: numeric target](#numeric-target)\n        - [`^`: separator target](#separator-target)\n    - [State Space](#State-Space)\n- [Examples](#Examples)\n    - [Circular Error Model](#circular-error-model)\n    - [Repetition Code Error Model](#repetition-code-error-model)\n    - [Surface Code Error Model](#surface-code-error-model)\n\n\n## Encoding\n\nDetector error model files are always encoded using UTF-8.\nFurthermore, the only place in the file where non-ASCII characters are permitted is inside of comments.\n\n## Syntax\n\nA detector error model file is made up of a series of lines.\nEach line is either blank, an instruction, a block initiator, or a block terminator.\nAlso, each line may be indented with spacing characters and may end with a comment indicated by a hash (`#`).\n\n```\n<DETECTOR_ERROR_MODEL> ::= <LINE>*\n<LINE> ::= <INDENT> (<INSTRUCTION> | <BLOCK_START> | <BLOCK_END>)? <COMMENT>? '\\n'\n<INDENT> ::= /[ \\t]*/\n<COMMENT> ::= '#' /[^\\n]*/\n```\n\nAn *instruction* is composed of a name,\nthen (introduced in stim v1.15) an optional tag inside square brackets,\nthen an optional comma-separated list of arguments inside of parentheses,\nthen a list of space-separated targets.\nFor example, the line `error[test](0.1) D5 D6 L0` is an instruction with\na name (`error`), a tag (`test`), one argument (`0.1`), and three targets\n(`D5`, `D6`, and `L0`).\n\n```\n<INSTRUCTION> ::= <NAME> <TAG>? <PARENS_ARGUMENTS>? <TARGETS>\n<TAG> ::= '[' /[^\\r\\]\\n]/* ']'\n<PARENS_ARGUMENTS> ::= '(' <ARGUMENTS> ')' \n<ARGUMENTS> ::= /[ \\t]*/ <ARG> /[ \\t]*/ (',' <ARGUMENTS>)?\n<TARGETS> ::= /[ \\t]+/ <TARG> <TARGETS>?\n```\n\nAn instruction *name* starts with a letter and then contains a series of letters, digits, and underscores.\nNames are case-insensitive.\n\nAn instruction *tag* is an arbitrary string enclosed by square brackets.\nCertain characters cannot appear directly in the tag, and must instead be included using escape sequences.\nThe closing square bracket character `]` cannot appear directly, and is instead encoded using the escape sequence `\\C`.\nThe carriage return character cannot appear directly, and is instead encoded using the escape sequence `\\r`.\nThe line feed character cannot appear directly, and is instead encoded using the escape sequence `\\n`.\nThe backslash character `\\` cannot appear directly, and is instead encoded using the escape sequence `\\B`.\n(This backslash escape sequence differs from the common escape sequence `\\\\` because that sequence causes exponential explosions when escaping multiple times.)\n\nAn *argument* is a double precision floating point number.\n\nA *target* can either be a relative detector target (a non-negative integer prefixed by `D`),\na logical observable target (a non-negative integer prefixed by `L`),\na component separator (`^`),\nor an unsigned integer target (a non-negative integer).\n\n```\n<NAME> ::= /[a-zA-Z][a-zA-Z0-9_]*/ \n<ARG> ::= <double> \n<TARG> ::= <RELATIVE_DETECTOR_TARGET> | <LOGICAL_OBSERVABLE_TARGET> | <NUMBER_TARGET> | <SEPARATOR>  \n<RELATIVE_DETECTOR_TARGET> ::= 'D' <uint>\n<LOGICAL_OBSERVABLE_TARGET> ::= 'L' <uint>\n<NUMBER_TARGET> = <uint>\n<SEPARATOR> = '^'\n```\n\nA *block initiator* is an instruction suffixed with `{`.\nEvery block initiator must be followed, eventually, by a matching *block terminator* which is just a `}`.\nThe `{` always goes in the same line as its instruction, and the `}` always goes on a line by itself. \n\n```\n<BLOCK_START> ::= <INSTRUCTION> /[ \\t]*/ '{'\n<BLOCK_END> ::= '}' \n```\n\n## Semantics\n\nA *detector error model* is a list of independent error mechanisms.\nEach error mechanism has a *probability*,\n*symptoms* (the detectors that the error flips),\nand *frame changes* (the logical observables that the error flips).\nError mechanisms may also suggest a *decomposition* into simpler error mechanisms.\n\nA detector error model can be sampled by independently keeping or discarding each error mechanism,\nwith a keep probability equal to each error mechanism's probability.\nThe resulting sample contains the symptoms and frame changes that appeared an odd number of times total in the kept\nerror mechanisms.\n\nA detector error model file (.dem) specifies a detector error model by a series of instructions which are interpreted\none by one, from start to finish. The instructions iteratively build up a detector error model by introducing error\nmechanisms.\n\n### Instruction Types\n\nA detector error model file can contain several different types of instructions and blocks.\n\n#### detector instruction\n\nA `detector` instruction declares a particular symptom that is in the error model.\nIt is not necessary to explicitly declare detectors using detector instructions.\nDetectors can also be implicitly declared simply by being mentioned in an error mechanism,\nor by a detector with a larger absolute index being declared.\nHowever, an explicit declaration is the only way to annotate the detector with coordinates,\nsuggesting a spacetime location for the detector.\n\nThe detector instruction should have a detector target (the detector being declared, relative to the\ncurrent detector index offset) and can include  any number of arguments specifying the detector's\ncoordinates (relative to the current coordinate offset).\nNote that when the current coordinate offset has more coordinates than the detector,\nthe additional coordinates are skipped.\nFor example, if the offset is `(1,2,3)` and the detector relative position is `(10,10)` then the\ndetector's absolute position would be `11,12`; not `11,12,3`. \n\nExample: `detector D4` declares a detector with index 4 (relative to the current detector index offset).\n\nExample: `detector D5 D6` declares a detector with index 5 (relative to the current detector index offset)\nand also a detector with index 6 (relative to the current detector index offset).\n\nExample: `detector(2.5,3.5,6) D7` declares a detector with index 7\n(relative to the current detector index offset)\nand coordinates `2.5`, `3.5`, `6` (relative to the current coordinate offset).\n\n#### logical_observable instruction\n\nA `logical_observable` instruction ensures a particular frame change's existence is noted by the error model,\neven if no error mechanism affects it.\nFrame changes can also be implicitly declared simply by being mentioned in an error mechanism or other\ninstruction, or by a frame change with a larger absolute index being declared.\n\nExample: `logical_observable L1` declares a logical observable with index 1.\n\nExample: `logical_observable L1 L2` declares a logical observable with index 1 and also a logical observable with\nindex 2.\n\n#### shift_detectors instruction\n\nA `shift_detectors` instruction adds an offset into the current detector offset and the current coordinate offset.\nTakes 1 numeric target indicating the detector offset.\nTakes a variable number of arguments indicating the coordinate offset.\nShifting is useful when writing loops, because otherwise the detectors declared by each iteration\nof the loop would all lie on top of each other.\nThe detector offset can only be increased, not decreased.\n\nExample: `shift_detectors(0, 0.5) 2` leaves the first coordinate's offset alone,\nincreases the second coordinate's offset by `0.5`,\nleaves all other coordinate offsets alone,\nand increases the detector offset by 2.\n\nExample: declaring a diagonal line of detectors.\n```\ndetector(0, 0) D0\nrepeat 1000 {\n    detector(0.5, 0.5) D1\n    error(0.01) D0 D1\n    shift_detectors(0.5, 0.5) 1\n}\n```\n\n#### error instruction\n\nAn `error` instruction adds an error mechanism to the error model.\nThe error instruction takes 1 argument (the probability of the error) and multiple targets.\nThe targets can include detectors, observables, and separators.\nSeparators are used to suggest a way to decompose complicated error mechanisms into simpler ones.\n\nFor example: `error(0.1) D2 D3 L0` adds an error mechanism with\nprobability equal to 10%,\ntwo symptoms (`D2`, `D3`),\none frame change (`L0`),\nand no suggested decomposition.\n\nAnother example: `error(0.02) D2 L0 ^ D5 D6` adds an error mechanism with\nprobability equal to 2%,\nthree symptoms (`D2`, `D5`, `D6`),\none frame change (`L0`),\nand a suggested decomposition into `D2 L0` and `D5 D6`.\n\nYet another example: `error(0.03) D2 L0 ^ D3 L0` adds an error mechanism with\nprobability equal to 3%,\ntwo symptoms (`D2`, `D3`),\nno frame changes (because the two `L0` cancel out),\nand a suggested decomposition into `D2 L0` and `D3 L0`.\n\nAn example of a situation where the decomposition is relevant is a surface code with X and Z basis stabilizers.\nIn such a surface code, Y errors can be factored into correlated X and Z errors.\nSo, error mechanisms in the detector error model corresponding to Y errors in the circuit can suggest decomposing\ninto the X and Z parts.\n\nIt is valid for multiple error mechanisms to have the exact same targets.\nTypically they would be fused as part of building the error model (via the equation\n`p_{combined} = p_1 (1 - p_2) + p_2 (1 - p_1)`).\nIt is also valid for error mechanisms to have the same symptoms but different frame changes\n(though this guarantees the error correcting code has distance at most 2).\nSimilarly, an error mechanism may have frame changes with no symptoms (guaranteeing a code distance equal to 1).\n\n#### repeat block\n\nA detector error model file can also contain `REPEAT K { ... }` blocks,\nwhich indicate that the block's instructions should be iterated over `K` times instead of just once.\n\nExample: declaring a diagonal line of detectors.\n\n```\ndetector(0, 0) D0\nrepeat 1000 {\n    detector(0.5, 0.5) D1\n    error(0.01) D0 D1\n    shift_detectors(0.5, 0.5) 1\n}\n```\n\n### Target Types\n\nThere are four types of targets that can be given to instructions:\nrelative detector targets,\nlogical observable targets,\nnumeric targets,\nand separator targets.\n\n#### relative detector target\n\nA relative detector target is a non-negative integer prefixed by `D`, such as `D5`.\nIt refers to a symptom in the error model.\nTo get the actual detector target specified by the relative detector target, the integer after the `D`\nhas to be added into the current relative detector offset.\n\n#### logical observable target\n\nA logical observable target is a non-negative integer prefixed by `L`, such as `L5`.\nIt refers to a possible frame change that an error can cause.\n\n#### numeric target\n\nA numeric target is a non-negative integer.\nFor example, the `REPEAT` block instruction takes a single numeric target indicating the number of repetitions\nand the `shift_detectors` instruction takes a single numeric target indicating the detector index shift.\n\n\n#### separator target\n\nA separator target (`^`) is not an actual thing to target, but rather a marker used to split up the targets of an error\nmechanism into a suggested decomposition.\n\n### State Space\n\nInterpreting a detector error model file, to produce a detector error model,\ninvolves tracking several pieces of state.\n\n1. **The Offsets**\n    As the error model file is interpreted, the *relative detector index* and *relative coordinate offset* are shifted\n    by `shift_detectors` instructions.\n    Interpreting relative detector targets and coordinate annotations requires tracking these\n    two values, since they shift the targets and coordinates.\n2. **The Nodes (possible symptoms and frame changes)**.\n    The error model must include every explicitly and implicitly declared detector (symptom) and\n    logical observable (frame change).\n    In practice this means computing the absolute index of the largest detector, and including\n    a number of detectors equal to that index plus one.\n    The same is done for frame changes: find the largest mentioned frame change index, and include\n    a number of frame changes equal to that index plus one.\n    Getting the number of nodes correct is important when parsing densely packed data that does not\n    include explicit detector indices or frame change indices.\n3. **The Edges (error mechanisms)**.\n    The error model must include the mentioned error mechanisms.\n\n## Examples\n\n### Circular Error Model\n\nThis error model defines 10 symptoms, and 10 error mechanisms with two symptoms.\nOne of the error mechanisms, the \"bad error\", also has a frame change (`L0`).\nIf the symptoms are nodes, and error mechanisms connect two nodes, then the model forms\nthe 10 node circular graph.\n\n```\nerror(0.1) D9 D0 L0\nerror(0.1) D0 D1\nerror(0.1) D1 D2\nerror(0.1) D2 D3\nerror(0.1) D3 D4\nerror(0.1) D4 D5\nerror(0.1) D5 D6\nerror(0.1) D6 D7\nerror(0.1) D7 D8\nerror(0.1) D8 D9\n```\n\nThis model can be defined more succinctly by using a `repeat` block:\n\n```\nerror(0.1) D9 D0 L0\nrepeat 9 {\n    error(0.1) D0 D1\n    shift_detectors 1\n}\n```\n\n### Repetition Code Error Model\n\nThis is the output from\n`stim --gen repetition_code --task memory --rounds 1000 --distance 4 --after_clifford_depolarization 0.001 | stim --analyze_errors --fold_loops`.\nIt includes coordinate annotations for the spacetime layout of the detectors.\n\n```\nerror(0.0002667378157289137966) D0\nerror(0.0002667378157289137966) D0 D1\nerror(0.0005333333333331479603) D0 D3\nerror(0.0005333333333331479603) D0 D4\nerror(0.0002667378157289137966) D1 D2\nerror(0.0005333333333331479603) D1 D4\nerror(0.0005333333333331479603) D1 D5\nerror(0.0005333333333331479603) D2 D5\nerror(0.0002667378157289137966) D2 L0\nerror(0.0002667378157289137966) D3\nerror(0.0002667378157289137966) D3 D4\nerror(0.0002667378157289137966) D4 D5\nerror(0.0002667378157289137966) D5 L0\ndetector(1, 0) D0\ndetector(3, 0) D1\ndetector(5, 0) D2\nrepeat 998 {\n    error(0.0002667378157289137966) D3\n    error(0.0002667378157289137966) D3 D4\n    error(0.0005333333333331479603) D3 D6\n    error(0.0005333333333331479603) D3 D7\n    error(0.0002667378157289137966) D4 D5\n    error(0.0005333333333331479603) D4 D7\n    error(0.0005333333333331479603) D4 D8\n    error(0.0005333333333331479603) D5 D8\n    error(0.0002667378157289137966) D5 L0\n    error(0.0002667378157289137966) D6\n    error(0.0002667378157289137966) D6 D7\n    error(0.0002667378157289137966) D7 D8\n    error(0.0002667378157289137966) D8 L0\n    shift_detectors(0, 1) 0\n    detector(1, 0) D3\n    detector(3, 0) D4\n    detector(5, 0) D5\n    shift_detectors 3\n}\nerror(0.0002667378157289137966) D3\nerror(0.0002667378157289137966) D3 D4\nerror(0.0005333333333331479603) D3 D6\nerror(0.0005333333333331479603) D3 D7\nerror(0.0002667378157289137966) D4 D5\nerror(0.0005333333333331479603) D4 D7\nerror(0.0005333333333331479603) D4 D8\nerror(0.0005333333333331479603) D5 D8\nerror(0.0002667378157289137966) D5 L0\nerror(0.0002667378157289137966) D6\nerror(0.0002667378157289137966) D6 D7\nerror(0.0002667378157289137966) D7 D8\nerror(0.0002667378157289137966) D8 L0\nshift_detectors(0, 1) 0\ndetector(1, 0) D3\ndetector(3, 0) D4\ndetector(5, 0) D5\ndetector(1, 1) D6\ndetector(3, 1) D7\ndetector(5, 1) D8\n```\n\n### Surface Code Error Model\n\nThis is the output from\n`stim --gen surface_code --task rotated_memory_x --rounds 1000 --distance 2 --after_clifford_depolarization 0.001 | stim --analyze_errors --fold_loops --decompose_errors`.\nIt includes coordinate annotations for the spacetime layout of the detectors.\n\n```\nerror(0.0002667378157289137966) D0\nerror(0.001332444444444449679) D0 D2\nerror(0.0002667378157289137966) D0 L0\nerror(0.0005333333333331479603) D1\nerror(0.001332444444444449679) D1 D4\nerror(0.0002667378157289137966) D1 L0\nerror(0.0001333866998761607556) D1 L0 ^ D2 L0\nerror(0.0002667378157289137966) D1 L0 ^ D3\nerror(0.0001333866998761607556) D1 L0 ^ D3 ^ D2 L0\nerror(0.0002667378157289137966) D1 ^ D3\nerror(0.0005333333333331479603) D2\nerror(0.001332444444444449679) D2 D5\nerror(0.0007997866287252842132) D2 L0\nerror(0.0002667378157289137966) D2 L0 ^ D0 L0\nerror(0.0004000533570511300221) D2 L0 ^ D3\nerror(0.0002667378157289137966) D2 ^ D0\nerror(0.0001333866998761607556) D2 ^ D1\nerror(0.0001333866998761607556) D2 ^ D3\nerror(0.0001333866998761607556) D2 ^ D3 ^ D1\nerror(0.001731254257715537058) D3\nerror(0.0002667378157289137966) D3 ^ D1\nerror(0.0001333866998761607556) D3 ^ D2\nerror(0.0001333866998761607556) D3 ^ D2 L0\nerror(0.0001333866998761607556) D3 ^ D4\nerror(0.0001333866998761607556) D3 ^ D4 ^ D1\nerror(0.0001333866998761607556) D3 ^ D5\nerror(0.0001333866998761607556) D3 ^ D5 ^ D2\nerror(0.0004666977902291165391) D4\nerror(0.001332444444444449679) D4 D7\nerror(0.0003334000326131335203) D4 L0\nerror(0.0001333866998761607556) D4 L0 ^ D1 L0\nerror(0.0001333866998761607556) D4 L0 ^ D1 L0 ^ D3\nerror(0.0002000667052120994559) D4 L0 ^ D3\nerror(6.669779853440971351e-05) D4 L0 ^ D5 L0\nerror(6.669779853440971351e-05) D4 L0 ^ D5 L0 ^ D3\nerror(0.0002000667052120994559) D4 L0 ^ D6\nerror(6.669779853440971351e-05) D4 L0 ^ D6 ^ D3\nerror(6.669779853440971351e-05) D4 L0 ^ D6 ^ D5 L0\nerror(6.669779853440971351e-05) D4 L0 ^ D6 ^ D5 L0 ^ D3\nerror(0.0001333866998761607556) D4 ^ D1\nerror(0.0002000667052120994559) D4 ^ D3\nerror(0.0001333866998761607556) D4 ^ D6\nerror(0.0001333866998761607556) D4 ^ D6 ^ D3\nerror(0.0002000667052120994559) D5\nerror(0.0003334000326131335203) D5 L0\nerror(0.0001333866998761607556) D5 L0 ^ D2 L0\nerror(0.0001333866998761607556) D5 L0 ^ D2 L0 ^ D3\nerror(0.0003334000326131335203) D5 L0 ^ D3\nerror(0.0001333866998761607556) D5 L0 ^ D6\nerror(0.0001333866998761607556) D5 L0 ^ D6 ^ D3\nerror(0.0001333866998761607556) D5 ^ D2\nerror(6.669779853440971351e-05) D5 ^ D3\nerror(6.669779853440971351e-05) D5 ^ D4\nerror(6.669779853440971351e-05) D5 ^ D4 ^ D3\nerror(6.669779853440971351e-05) D5 ^ D6\nerror(6.669779853440971351e-05) D5 ^ D6 ^ D3\nerror(6.669779853440971351e-05) D5 ^ D6 ^ D4\nerror(6.669779853440971351e-05) D5 ^ D6 ^ D4 ^ D3\nerror(0.0006665777540627741476) D6\nerror(0.0004000533570511300221) D6 ^ D3\nerror(0.0002000667052120994559) D6 ^ D4\nerror(6.669779853440971351e-05) D6 ^ D4 ^ D3\nerror(6.669779853440971351e-05) D6 ^ D5 L0\nerror(6.669779853440971351e-05) D6 ^ D5 L0 ^ D3\nerror(0.0001333866998761607556) D6 ^ D7\nerror(0.0001333866998761607556) D6 ^ D7 ^ D4\nerror(0.0001333866998761607556) D7\nerror(0.0001333866998761607556) D7 L0\nerror(0.0001333866998761607556) D7 L0 ^ D4 L0\nerror(0.0001333866998761607556) D7 L0 ^ D4 L0 ^ D6\nerror(0.0001333866998761607556) D7 L0 ^ D6\nerror(0.0001333866998761607556) D7 ^ D4\ndetector(2, 0, 0) D0\ndetector(2, 4, 0) D1\nshift_detectors(0, 0, 1) 0\ndetector(2, 0, 0) D2\ndetector(2, 2, 0) D3\ndetector(2, 4, 0) D4\nrepeat 498 {\n    error(0.0001333866998761607556) D5\n    error(0.001332444444444449679) D5 D8\n    error(0.0001333866998761607556) D5 L0\n    error(0.0001333866998761607556) D5 L0 ^ D6\n    error(0.0006665777540627741476) D6\n    error(0.0001333866998761607556) D6 ^ D5\n    error(0.0001333866998761607556) D6 ^ D8\n    error(0.0001333866998761607556) D6 ^ D8 ^ D5\n    error(0.0003334000326131335203) D7\n    error(0.001332444444444449679) D7 D10\n    error(0.0002000667052120994559) D7 L0\n    error(6.669779853440971351e-05) D7 L0 ^ D6\n    error(6.669779853440971351e-05) D7 L0 ^ D8 L0\n    error(6.669779853440971351e-05) D7 L0 ^ D8 L0 ^ D6\n    error(0.0002000667052120994559) D7 L0 ^ D9\n    error(6.669779853440971351e-05) D7 L0 ^ D9 ^ D6\n    error(6.669779853440971351e-05) D7 L0 ^ D9 ^ D8 L0\n    error(6.669779853440971351e-05) D7 L0 ^ D9 ^ D8 L0 ^ D6\n    error(0.0002000667052120994559) D7 ^ D6\n    error(0.0001333866998761607556) D7 ^ D9\n    error(0.0001333866998761607556) D7 ^ D9 ^ D6\n    error(0.0003334000326131335203) D8\n    error(0.001332444444444449679) D8 D11\n    error(0.0004666977902291165391) D8 L0\n    error(0.0001333866998761607556) D8 L0 ^ D5 L0\n    error(0.0001333866998761607556) D8 L0 ^ D5 L0 ^ D6\n    error(0.0003334000326131335203) D8 L0 ^ D6\n    error(0.0002667378157289137966) D8 L0 ^ D9\n    error(0.0001333866998761607556) D8 L0 ^ D9 ^ D6\n    error(0.0001333866998761607556) D8 ^ D5\n    error(6.669779853440971351e-05) D8 ^ D6\n    error(6.669779853440971351e-05) D8 ^ D7\n    error(6.669779853440971351e-05) D8 ^ D7 ^ D6\n    error(6.669779853440971351e-05) D8 ^ D9\n    error(6.669779853440971351e-05) D8 ^ D9 ^ D6\n    error(6.669779853440971351e-05) D8 ^ D9 ^ D7\n    error(6.669779853440971351e-05) D8 ^ D9 ^ D7 ^ D6\n    error(0.001332266856321125473) D9\n    error(0.0004000533570511300221) D9 ^ D6\n    error(0.0002000667052120994559) D9 ^ D7\n    error(6.669779853440971351e-05) D9 ^ D7 ^ D6\n    error(0.0001333866998761607556) D9 ^ D8\n    error(6.669779853440971351e-05) D9 ^ D8 L0\n    error(6.669779853440971351e-05) D9 ^ D8 L0 ^ D6\n    error(0.0001333866998761607556) D9 ^ D10\n    error(0.0001333866998761607556) D9 ^ D10 ^ D7\n    error(0.0001333866998761607556) D9 ^ D11\n    error(0.0001333866998761607556) D9 ^ D11 ^ D8\n    error(0.0004666977902291165391) D10\n    error(0.001332444444444449679) D10 D13\n    error(0.0003334000326131335203) D10 L0\n    error(0.0001333866998761607556) D10 L0 ^ D7 L0\n    error(0.0001333866998761607556) D10 L0 ^ D7 L0 ^ D9\n    error(0.0002000667052120994559) D10 L0 ^ D9\n    error(6.669779853440971351e-05) D10 L0 ^ D11 L0\n    error(6.669779853440971351e-05) D10 L0 ^ D11 L0 ^ D9\n    error(0.0002000667052120994559) D10 L0 ^ D12\n    error(6.669779853440971351e-05) D10 L0 ^ D12 ^ D9\n    error(6.669779853440971351e-05) D10 L0 ^ D12 ^ D11 L0\n    error(6.669779853440971351e-05) D10 L0 ^ D12 ^ D11 L0 ^ D9\n    error(0.0001333866998761607556) D10 ^ D7\n    error(0.0002000667052120994559) D10 ^ D9\n    error(0.0001333866998761607556) D10 ^ D12\n    error(0.0001333866998761607556) D10 ^ D12 ^ D9\n    error(0.0002000667052120994559) D11\n    error(0.0003334000326131335203) D11 L0\n    error(0.0001333866998761607556) D11 L0 ^ D8 L0\n    error(0.0001333866998761607556) D11 L0 ^ D8 L0 ^ D9\n    error(0.0003334000326131335203) D11 L0 ^ D9\n    error(0.0001333866998761607556) D11 L0 ^ D12\n    error(0.0001333866998761607556) D11 L0 ^ D12 ^ D9\n    error(0.0001333866998761607556) D11 ^ D8\n    error(6.669779853440971351e-05) D11 ^ D9\n    error(6.669779853440971351e-05) D11 ^ D10\n    error(6.669779853440971351e-05) D11 ^ D10 ^ D9\n    error(6.669779853440971351e-05) D11 ^ D12\n    error(6.669779853440971351e-05) D11 ^ D12 ^ D9\n    error(6.669779853440971351e-05) D11 ^ D12 ^ D10\n    error(6.669779853440971351e-05) D11 ^ D12 ^ D10 ^ D9\n    error(0.0006665777540627741476) D12\n    error(0.0004000533570511300221) D12 ^ D9\n    error(0.0002000667052120994559) D12 ^ D10\n    error(6.669779853440971351e-05) D12 ^ D10 ^ D9\n    error(6.669779853440971351e-05) D12 ^ D11 L0\n    error(6.669779853440971351e-05) D12 ^ D11 L0 ^ D9\n    error(0.0001333866998761607556) D12 ^ D13\n    error(0.0001333866998761607556) D12 ^ D13 ^ D10\n    error(0.0001333866998761607556) D13\n    error(0.0001333866998761607556) D13 L0\n    error(0.0001333866998761607556) D13 L0 ^ D10 L0\n    error(0.0001333866998761607556) D13 L0 ^ D10 L0 ^ D12\n    error(0.0001333866998761607556) D13 L0 ^ D12\n    error(0.0001333866998761607556) D13 ^ D10\n    shift_detectors(0, 0, 1) 0\n    detector(2, 0, 0) D5\n    detector(2, 2, 0) D6\n    detector(2, 4, 0) D7\n    shift_detectors(0, 0, 1) 0\n    detector(2, 0, 0) D8\n    detector(2, 2, 0) D9\n    detector(2, 4, 0) D10\n    shift_detectors 6\n}\nerror(0.0001333866998761607556) D5\nerror(0.001332444444444449679) D5 D8\nerror(0.0001333866998761607556) D5 L0\nerror(0.0001333866998761607556) D5 L0 ^ D6\nerror(0.0006665777540627741476) D6\nerror(0.0001333866998761607556) D6 ^ D5\nerror(0.0001333866998761607556) D6 ^ D8\nerror(0.0001333866998761607556) D6 ^ D8 ^ D5\nerror(0.0003334000326131335203) D7\nerror(0.001332444444444449679) D7 D10\nerror(0.0002000667052120994559) D7 L0\nerror(6.669779853440971351e-05) D7 L0 ^ D6\nerror(6.669779853440971351e-05) D7 L0 ^ D8 L0\nerror(6.669779853440971351e-05) D7 L0 ^ D8 L0 ^ D6\nerror(0.0002000667052120994559) D7 L0 ^ D9\nerror(6.669779853440971351e-05) D7 L0 ^ D9 ^ D6\nerror(6.669779853440971351e-05) D7 L0 ^ D9 ^ D8 L0\nerror(6.669779853440971351e-05) D7 L0 ^ D9 ^ D8 L0 ^ D6\nerror(0.0002000667052120994559) D7 ^ D6\nerror(0.0001333866998761607556) D7 ^ D9\nerror(0.0001333866998761607556) D7 ^ D9 ^ D6\nerror(0.0003334000326131335203) D8\nerror(0.001332444444444449679) D8 D11\nerror(0.0004666977902291165391) D8 L0\nerror(0.0001333866998761607556) D8 L0 ^ D5 L0\nerror(0.0001333866998761607556) D8 L0 ^ D5 L0 ^ D6\nerror(0.0003334000326131335203) D8 L0 ^ D6\nerror(0.0002667378157289137966) D8 L0 ^ D9\nerror(0.0001333866998761607556) D8 L0 ^ D9 ^ D6\nerror(0.0001333866998761607556) D8 ^ D5\nerror(6.669779853440971351e-05) D8 ^ D6\nerror(6.669779853440971351e-05) D8 ^ D7\nerror(6.669779853440971351e-05) D8 ^ D7 ^ D6\nerror(6.669779853440971351e-05) D8 ^ D9\nerror(6.669779853440971351e-05) D8 ^ D9 ^ D6\nerror(6.669779853440971351e-05) D8 ^ D9 ^ D7\nerror(6.669779853440971351e-05) D8 ^ D9 ^ D7 ^ D6\nerror(0.001731254257715537058) D9\nerror(0.0004000533570511300221) D9 ^ D6\nerror(0.0002000667052120994559) D9 ^ D7\nerror(6.669779853440971351e-05) D9 ^ D7 ^ D6\nerror(0.0001333866998761607556) D9 ^ D8\nerror(6.669779853440971351e-05) D9 ^ D8 L0\nerror(6.669779853440971351e-05) D9 ^ D8 L0 ^ D6\nerror(0.0001333866998761607556) D9 ^ D10\nerror(0.0001333866998761607556) D9 ^ D10 ^ D7\nerror(0.0001333866998761607556) D9 ^ D11\nerror(0.0001333866998761607556) D9 ^ D11 ^ D8\nerror(0.0007997866287252842132) D10\nerror(0.001332444444444449679) D10 D12\nerror(0.0005333333333331479603) D10 L0\nerror(0.0001333866998761607556) D10 L0 ^ D7 L0\nerror(0.0001333866998761607556) D10 L0 ^ D7 L0 ^ D9\nerror(0.0002667378157289137966) D10 L0 ^ D9\nerror(0.0001333866998761607556) D10 L0 ^ D11 L0\nerror(0.0001333866998761607556) D10 L0 ^ D11 L0 ^ D9\nerror(0.0001333866998761607556) D10 ^ D7\nerror(0.0004000533570511300221) D10 ^ D9\nerror(0.0002667378157289137966) D11\nerror(0.0005333333333331479603) D11 L0\nerror(0.0001333866998761607556) D11 L0 ^ D8 L0\nerror(0.0001333866998761607556) D11 L0 ^ D8 L0 ^ D9\nerror(0.0005333333333331479603) D11 L0 ^ D9\nerror(0.0001333866998761607556) D11 ^ D8\nerror(0.0001333866998761607556) D11 ^ D9\nerror(0.0001333866998761607556) D11 ^ D10\nerror(0.0001333866998761607556) D11 ^ D10 ^ D9\nerror(0.0002667378157289137966) D12\nerror(0.0002667378157289137966) D12 L0\nerror(0.0002667378157289137966) D12 L0 ^ D10 L0\nerror(0.0002667378157289137966) D12 ^ D10\nshift_detectors(0, 0, 1) 0\ndetector(2, 0, 0) D5\ndetector(2, 2, 0) D6\ndetector(2, 4, 0) D7\nshift_detectors(0, 0, 1) 0\ndetector(2, 0, 0) D8\ndetector(2, 2, 0) D9\ndetector(2, 4, 0) D10\ndetector(2, 0, 1) D11\ndetector(2, 4, 1) D12\n```\n"
  },
  {
    "path": "doc/file_format_stim_circuit.md",
    "content": "# The Stim Circuit File Format (.stim)\n\nA stim circuit file (.stim) is a human-readable specification of an annotated stabilizer circuit.\nThe circuit file includes gates to apply to qubits,\nnoise processes to apply during simulations,\nand annotations for tasks such as detection event sampling and drawing the circuit.\n\n## Index\n\n- [Encoding](#Encoding)\n- [Syntax](#Syntax)\n- [Semantics](#Semantics)\n    - [Instruction Types](#Instruction-Types)\n        - [Supported Gates](gates.md)\n    - [Broadcasting](#Broadcasting)\n    - [State Space](#State-Space)\n    - [Vacuous repeat blocks are not allowed](#Vacuous-repeat-blocks-are-not-allowed)\n- [Examples](#Examples)\n    - [Teleportation Circuit](#Teleportation-Circuit)\n    - [Repetition Code Circuit](#Repetition-Code-Circuit)\n    - [Fully Annotated Noisy Repetition Code Circuit](#Fully-Annotated-Noisy-Repetition-Code-Circuit)\n    - [Fully Annotated Noisy Surface Code Circuit](#Fully-Annotated-Noisy-Surface-Code-Circuit)\n\n\n## Encoding\n\nStim circuit files are always encoded using UTF-8.\n\n(Also, the only place in the file where non-ASCII characters can validly appear is inside of comments and tags.)\n\n## Syntax\n\nA stim circuit file is made up of a series of lines.\nEach line is either blank, an instruction, a block initiator, or a block terminator.\nAlso, each line may be indented with spacing characters and may end with a comment indicated by a hash (`#`).\nComments and indentation are purely decorative; they carry no semantic significance.\n\nHere is a formal definition of the above paragraph.\nEntries like `/this/` are regular expressions.\nEntries like `<this>` are named expressions.\nEntries like `'this'` are literal string expressions.\nThe `::=` operator means \"defined as\".\nThe `|` binary operator means \"or\".\nThe `?` suffix operator means \"zero-or-one\".\nThe `*` suffix operator means \"zero-or-many\".\nParens are used to group expressions.\nAdjacent expressions are combined by concatenation.\n\n```\n<CIRCUIT> ::= <LINE>*\n<LINE> ::= <INDENT> (<INSTRUCTION> | <BLOCK_START> | <BLOCK_END>)? <COMMENT>? '\\n'\n<INDENT> ::= /[ \\t]*/\n<COMMENT> ::= '#' /[^\\n]*/\n```\n\nAn *instruction* is composed of a name,\nthen (introduced in stim v1.15) an optional tag inside square brackets,\nthen an optional comma-separated list of arguments inside of parentheses,\nthen a list of space-separated targets.\nFor example, the line `X_ERROR[test](0.1) 5 6` is an instruction with a\nname (`X_ERROR`), a tag (`test`), one argument (`0.1`), and two targets\n(`5` and `6`).\n\n```\n<INSTRUCTION> ::= <NAME> <TAG>? <PARENS_ARGUMENTS>? <TARGETS>\n<TAG> ::= '[' /[^\\r\\]\\n]/* ']'\n<PARENS_ARGUMENTS> ::= '(' <ARGUMENTS> ')' \n<ARGUMENTS> ::= /[ \\t]*/ <ARG> /[ \\t]*/ (',' <ARGUMENTS>)?\n<TARGETS> ::= /[ \\t]+/ <TARG> <TARGETS>?\n```\n\nAn instruction *name* starts with a letter and then contains a series of letters, digits, and underscores.\nNames are case-insensitive.\n\nAn instruction *tag* is an arbitrary string enclosed by square brackets.\nCertain characters cannot appear directly in the tag, and must instead be included using escape sequences.\nThe closing square bracket character `]` cannot appear directly, and is instead encoded using the escape sequence `\\C`.\nThe carriage return character cannot appear directly, and is instead encoded using the escape sequence `\\r`.\nThe line feed character cannot appear directly, and is instead encoded using the escape sequence `\\n`.\nThe backslash character `\\` cannot appear directly, and is instead encoded using the escape sequence `\\B`.\n(This backslash escape sequence differs from the common escape sequence `\\\\` because that sequence causes exponential explosions when escaping multiple times.)\n\nAn *argument* is a double precision floating point number.\n\nA *target* can either be a qubit target (a non-negative integer),\na measurement record target (a negative integer prefixed by `rec[` and suffixed by `]`),\na sweep bit target (a non-negative integer prefixed by `sweep[` and suffixed by `]`),\na Pauli target (an integer prefixed by `X`, `Y`, or `Z`),\nor a combiner (`*`).\nAdditionally, qubit targets and Pauli targets may be prefixed by a `!` to indicate that\nmeasurement results should be negated.\n\n```\n<NAME> ::= /[a-zA-Z][a-zA-Z0-9_]*/ \n<ARG> ::= <double> \n<TARG> ::= <QUBIT_TARGET> | <MEASUREMENT_RECORD_TARGET> | <SWEEP_BIT_TARGET> | <PAULI_TARGET> | <COMBINER_TARGET> \n<QUBIT_TARGET> ::= '!'? <uint>\n<MEASUREMENT_RECORD_TARGET> ::= \"rec[-\" <uint> \"]\"\n<SWEEP_BIT_TARGET> ::= \"sweep[\" <uint> \"]\"\n<PAULI_TARGET> ::= '!'? /[XYZ]/ <uint>\n<COMBINER_TARGET> ::= '*'\n```\n\nA *block initiator* is an instruction suffixed with `{`.\nEvery block initiator must be followed, eventually, by a matching *block terminator* which is just a `}`.\nThe `{` always goes in the same line as its instruction, and the `}` always goes on a line by itself.\n\n```\n<BLOCK_START> ::= <INSTRUCTION> /[ \\t]*/ '{'\n<BLOCK_END> ::= '}' \n```\n\nBlocks can be nested.\nBlock contents are indented by convention, but this is not necessary.\n\n## Semantics\n\nA stim circuit file is executed by executing each of its instructions and blocks, one by one, from start to finish.\n\n### Instruction Types\n\nFor a complete list of instructions supported by stim and their individual meanings,\nsee the [gates reference](gates.md).\n\nGenerally speaking, the instructions that can appear in a stim circuit file can be divided up into three groups:\n\n1. Operations\n2. Annotations\n3. Control Flow\n\nAn *operation* is a quantum channel to apply to the quantum state of the system,\npossibly resulting in bits being appended to the measurement record.\nThere are Clifford operations (e.g. the Hadamard gate `H` or the controlled-not gate `CNOT`),\nstabilizers operations (e.g. the measurement gate `M` or the reset gate `R`),\nand noise operations (e.g. the phase damping channel `Z_ERROR` or the two qubit depolarizing channel `DEPOLARIZE2`).\n\nAn *annotation* is a piece of additional information that is not strictly necessary, but which enables other useful capabilities.\nThe most functionally useful annotations are `DETECTOR` and `OBSERVABLE_INCLUDE`,\nwhich define the measurements that are compared when sampling a circuit's detection events.\nOther annotations include `QUBIT_COORDS` and `TICK`, which can be used to hint at the intended spacetime layout of a circuit.\n\n(Depending on your needs, you may also find yourself considering noisy operations to be annotations.\nThey define a noise model for the circuit.)\n\n*Control flow* blocks make changes to the usual one-after-another execution order of instructions.\nCurrently, control flow is limited to *repetition*.\nA circuit can contain `REPEAT K { ... }` blocks,\nwhich indicate that the block's instructions should be iterated over `K` times instead of just once.\n\n### Tags\n\nInstruction tags have no effect on the function of a circuit.\nIn general, tools should attempt to propagate tags through circuit transformations and otherwise ignore them.\nThe intent is that users and tools can use tags to specify custom behavior that stim is not aware of.\nFor example, consider the tagged instruction `TICK[100ns]`.\nIn most situations, the `100ns` tag does nothing.\nBut if you are using a tool that adds noise to circuits, and it's programmed to look at tags to get hints about what\nnoise to add, then the `100ns` tag could be a message to that tool (specifying a duration, which the tool could use when\ncomputing the probability argument of an inserted `DEPOLARIZE1` instruction).\n\n### Target Types\n\nThere are four types of targets that can be given to instructions:\nqubit targets, measurement record targets, sweep bit targets, and Pauli targets.\n\nA qubit target refers to a qubit by index.\nThere's a qubit `0`, a qubit `1`, a qubit `2`, and so forth.\nA qubit target may be prefixed by `!`, like `!2`, to mark it as inverted.\nInverted qubit targets are only meaningful for operations that produce measurement results.\nThey indicate that the recorded measurement result, for the given qubit target, should be inverted.\nFor example `M 0 !1` measures qubit `0` and qubit `1`, but also inverts the result recorded for qubit `1`.\n\nA measurement record target refers to a recorded measurement result, relative to the current end of the measurement record.\nFor example, `rec[-1]` is the most recent measurement result, `rec[-2]` is the second most recent, and so forth.\n(The semantics of the negative indices into the measurement record match the semantics of negative indices into lists in Python.\nThe reason negative indices are used is to make it possible to write loops.)\nIt is an error to refer to a measurement result so far back that it would precede the start of the circuit.\n\nA sweep bit target refers to a column in a data table where each row refers to a separate shots of the circuit, and each column refers to configuration bits that vary from shot to shot.\nFor example, when using randomized spin echo, the spin echo operations that actually occurred could be recording into a table.\nFor example, `CNOT sweep[5] 1` says an X operation was applied (or should be applied) to qubit 1 for shots where the sweep bit in the column with index 5 is set.\nSweep bits default to False when running in a context where no table is provided, and sweep bits past the end of the provided table also default to False.\n\nA Pauli target is a qubit target prefixed by a Pauli operation `X`, `Y`, or `Z`.\nThey are used when specifying Pauli products.\nFor example, `CORRELATED_ERROR(0.1) X1 Y3 Z2` uses Pauli targets to specify the error that is applied.\nPauli targets may be grouped using combiners (`*`) and may be prefixed by `!` to mark them as inverted.\nInverted Pauli targets are only meaningful for operations that produce measurement results.\nThey indicate that the recorded measurement result, for the given group of Paulis, should be inverted.\nFor example `MPP !X1*Z2 Y3` measures the Pauli product `X1*Z2` and inverts the result, then also measures\nthe Pauli `Y3`.\n\n### Broadcasting\n\nWhen quantum operations are applied to too many targets, the operation is *broadcast* over the targets.\n\nWhen a single qubit operation (e.g. `H` or `DEPOLARIZE1`) is given multiple targets,\nit is applied to each target in order.\nFor example, `H 0 1 2` is equivalent to `H 0` then `H 1` then `H 2`.\nSimilarly, `X_ERROR(0.1) 3 2` is equivalent to `X_ERROR(0.1) 3` then `X_ERROR(0.1) 2`.\n\nWhen a two qubit operation (e.g. `CNOT` or `DEPOLARIZE2`) is given multiple targets,\nit is applied to aligned target pairs in order.\nFor example, `CNOT 0 1 1 2 2 0` is equivalent to `CNOT 0 1` then `CNOT 1 2` then `CNOT 2 0`.\nIt is an error to give a two qubit operation an odd number of targets.\n\n### State Space\n\nA simulator executing a stim circuit is expected to store three things:\n\n1. **The Qubits**.\n    By convention, all qubits start in the |0> state.\n    The simulator then tracks the state of any qubits that have been operated on.\n    \n    Note that stim circuit files don't explicitly state the number of qubits needed.\n    Instead, the number of qubits is implied by the qubit targets present in the file.\n    For example, a simulator may look over the circuit and find the largest qubit target `n-1` that is\n    operated on and then size itself for operating on `n` qubits.\n2. **The Measurement Record**.\n    When a measurement operation is performed, the measurement result is appended to a list of bits\n    referred to as the measurement record.\n    The measurement record is an immutable log of all measurement results so far.\n    Controlled operations can use a measurement record target as a control, instead of a qubit target.\n    For example, `CZ rec[-1] 5` says \"if the most recent measurement result was TRUE then apply a Z\n    gate to qubit `5`\".\n    The measurement record is also used when defining detectors and observables.\n3. **The \"Correlated Error Occurred\" Flag**.\n    The `ELSE_CORRELATED_ERROR` instruction applies an error mechanism conditioned on the preceding\n    `CORRELATED_ERROR` instruction (and any intermediate `ELSE_CORRELATED_ERROR` instructions)\n    having not occurred. This is tracked by a hidden boolean flag. \n\n(The interpreter of the circuit may also track coordinate offsets accumulated from `SHIFT_COORDS` annotations,\nwhich affect the meaning of `QUBIT_COORDS` annotations and the coordinate arguments given to `DETECTOR`.\nBut these have no effect on simulations, and so are often not strictly necessary to track.)\n\n### Vacuous repeat blocks are not allowed\n\nIt's an error for a circuit to contain a repeat block that is repeated 0 times.\n\nThe reason it's an error is because it's ambiguous whether observables and qubits mentioned in the block \"exist\".\nFor example, consider this malformed circuit:\n\n```\nREPEAT 0 {\n    M 0\n    OBSERVABLE_INCLUDE(0) rec[-1]\n}\n```\n\nThis circuit mentions a logical observable with index 0, suggesting the circuit has a logical observable.\nSo, a tool that samples logical observables should produce 1 bit of information when sampling this circuit.\nBut the logical observable is only mentioned in a block that is never run, effectively commenting it out, leaving behind\nan empty circuit with 0 logical observables.\nSo, a tool that samples logical observables should produce 0 bits of information when sampling this circuit.\nIs there an observable in the circuit or isn't there?\nShould the tool produce 0 bits or 1 bit?\nThat's the ambiguity.\n\nNote that a tool that unrolls loops in the circuit will implicitly delete the ambiguous logical observables.\nConversely, note that a tool that finds logical observables by iterating over the lines of the circuit file, looking\nfor `OBSERVABLE_INCLUDE` instructions, will implicitly keep the ambiguous logical observables.\nBoth of these methods seem \"obviously correct\" on their own, but they disagree about whether or not to keep the\nambiguous observables.\nIt's very easy to write code that accidentally disagrees with itself about the correct behavior, and introduce a bug.\nWhich is why vacuous repeat blocks are not allowed. \n\n## Examples\n\n### Teleportation Circuit\n\n[View equivalent circuit in Quirk](https://algassert.com/quirk#circuit=%7B%22cols%22%3A%5B%5B%22H%22%5D%2C%5B%22%E2%80%A2%22%2C1%2C1%2C1%2C1%2C1%2C1%2C%22X%22%5D%2C%5B1%2C%22H%22%5D%2C%5B1%2C%22Z%5E%C2%BD%22%5D%2C%5B%22%E2%80%A2%22%2C%22X%22%5D%2C%5B%22H%22%5D%2C%5B%22Measure%22%2C%22Measure%22%5D%2C%5B%22%E2%80%A2%22%2C1%2C1%2C1%2C1%2C1%2C1%2C%22Z%22%5D%2C%5B1%2C%22%E2%80%A2%22%2C1%2C1%2C1%2C1%2C1%2C%22X%22%5D%5D%7D)\n\n```\n# Distribute a Bell Pair.\nH 0\nCNOT 0 99\n\n# Sender creates an arbitrary qubit state to send.\nH 1\nS 1\n\n# Sender performs a Bell Basis measurement.\nCNOT 0 1\nH 0\nM 0 1  # Measure both of the sender's qubits.\n\n# Receiver performs frame corrections based on measurement results.\nCZ rec[-2] 99\nCNOT rec[-1] 99\n```\n\n### Repetition Code Circuit\n\n[View equivalent circuit in Quirk](https://algassert.com/quirk#circuit=%7B%22cols%22%3A%5B%5B%22~ch91%22%2C1%2C%22~ch91%22%2C1%2C%22~ch91%22%5D%2C%5B1%2C%22~tbv6%22%2C1%2C%22~tbv6%22%2C1%2C%22~tbv6%22%5D%2C%5B1%2C%22ZDetectControlReset%22%2C1%2C%22ZDetectControlReset%22%2C1%2C%22ZDetectControlReset%22%5D%2C%5B%22~ch91%22%2C1%2C%22~ch91%22%2C1%2C%22~ch91%22%5D%2C%5B1%2C%22~tbv6%22%2C1%2C%22~tbv6%22%2C1%2C%22~tbv6%22%5D%2C%5B1%2C%22ZDetectControlReset%22%2C1%2C%22ZDetectControlReset%22%2C1%2C%22ZDetectControlReset%22%5D%2C%5B%22%E2%80%A6%22%2C%22%E2%80%A6%22%2C%22%E2%80%A6%22%2C%22%E2%80%A6%22%2C%22%E2%80%A6%22%2C%22%E2%80%A6%22%2C%22%E2%80%A6%22%5D%2C%5B%22~ch91%22%2C1%2C%22~ch91%22%2C1%2C%22~ch91%22%5D%2C%5B1%2C%22~tbv6%22%2C1%2C%22~tbv6%22%2C1%2C%22~tbv6%22%5D%2C%5B1%2C%22ZDetectControlReset%22%2C1%2C%22ZDetectControlReset%22%2C1%2C%22ZDetectControlReset%22%5D%2C%5B%22~ch91%22%2C1%2C%22~ch91%22%2C1%2C%22~ch91%22%5D%2C%5B1%2C%22~tbv6%22%2C1%2C%22~tbv6%22%2C1%2C%22~tbv6%22%5D%2C%5B%22ZDetectControlReset%22%2C%22ZDetectControlReset%22%2C%22ZDetectControlReset%22%2C%22ZDetectControlReset%22%2C%22ZDetectControlReset%22%2C%22ZDetectControlReset%22%2C%22ZDetectControlReset%22%5D%5D%2C%22gates%22%3A%5B%7B%22id%22%3A%22~ch91%22%2C%22circuit%22%3A%7B%22cols%22%3A%5B%5B%22%E2%80%A2%22%2C%22X%22%5D%5D%7D%7D%2C%7B%22id%22%3A%22~tbv6%22%2C%22circuit%22%3A%7B%22cols%22%3A%5B%5B%22X%22%2C%22%E2%80%A2%22%5D%5D%7D%7D%5D%7D)\n(without detector annotations).\n\n```\n# Measure the parities of adjacent data qubits.\n# Data qubits are 0, 2, 4, 6.\n# Measurement qubits are 1, 3, 5.\nCNOT 0 1 2 3 4 5\nCNOT 2 1 4 3 6 5\nMR 1 3 5\n\n# Annotate that the measurements should be deterministic.\nDETECTOR rec[-3]\nDETECTOR rec[-2]\nDETECTOR rec[-1]\n\n# Perform 1000 more rounds of measurements.\nREPEAT 1000 {\n    # Measure the parities of adjacent data qubits.\n    CNOT 0 1 2 3 4 5\n    CNOT 2 1 4 3 6 5\n    MR 1 3 5\n\n    # Annotate that the measurements should agree with previous round.\n    DETECTOR rec[-3] rec[-6]\n    DETECTOR rec[-2] rec[-5]\n    DETECTOR rec[-1] rec[-4]\n}\n\n# Measure data qubits.\nM 0 2 4 6\n\n# Annotate that the data measurements should agree with the parity measurements.\nDETECTOR rec[-3] rec[-4] rec[-7]\nDETECTOR rec[-2] rec[-3] rec[-6]\nDETECTOR rec[-1] rec[-2] rec[-5]\n\n# Declare one of the data qubit measurements to a logical measurement result.\nOBSERVABLE_INCLUDE(0) rec[-1]\n```\n\n### Fully Annotated Noisy Repetition Code Circuit\n\nThis is the output from\n`stim --gen repetition_code --task memory --rounds 1000 --distance 4 --after_clifford_depolarization 0.001`.\nIt includes noise operations and annotations for the spacetime layout of the circuit.\n\n```\n# Generated repetition_code circuit.\n# task: memory\n# rounds: 1000\n# distance: 3\n# before_round_data_depolarization: 0\n# before_measure_flip_probability: 0\n# after_reset_flip_probability: 0\n# after_clifford_depolarization: 0.001\n# layout:\n# L0 Z1 d2 Z3 d4 Z5 d6\n# Legend:\n#     d# = data qubit\n#     L# = data qubit with logical observable crossing\n#     Z# = measurement qubit\nR 0 1 2 3 4 5 6\nTICK\nCX 0 1 2 3 4 5\nDEPOLARIZE2(0.001) 0 1 2 3 4 5\nTICK\nCX 2 1 4 3 6 5\nDEPOLARIZE2(0.001) 2 1 4 3 6 5\nTICK\nMR 1 3 5\nDETECTOR(1, 0) rec[-3]\nDETECTOR(3, 0) rec[-2]\nDETECTOR(5, 0) rec[-1]\nREPEAT 999 {\n    TICK\n    CX 0 1 2 3 4 5\n    DEPOLARIZE2(0.001) 0 1 2 3 4 5\n    TICK\n    CX 2 1 4 3 6 5\n    DEPOLARIZE2(0.001) 2 1 4 3 6 5\n    TICK\n    MR 1 3 5\n    SHIFT_COORDS(0, 1)\n    DETECTOR(1, 0) rec[-3] rec[-6]\n    DETECTOR(3, 0) rec[-2] rec[-5]\n    DETECTOR(5, 0) rec[-1] rec[-4]\n}\nM 0 2 4 6\nDETECTOR(1, 1) rec[-3] rec[-4] rec[-7]\nDETECTOR(3, 1) rec[-2] rec[-3] rec[-6]\nDETECTOR(5, 1) rec[-1] rec[-2] rec[-5]\nOBSERVABLE_INCLUDE(0) rec[-1]\n```\n\n### Fully Annotated Noisy Surface Code Circuit\n\nThis is the output from\n`stim --gen surface_code --task rotated_memory_x --rounds 1000 --distance 3 --after_clifford_depolarization 0.001`.\nIt includes noise operations and annotations for the spacetime layout of the circuit.\n\n```\n# Generated surface_code circuit.\n# task: rotated_memory_x\n# rounds: 1000\n# distance: 3\n# before_round_data_depolarization: 0\n# before_measure_flip_probability: 0\n# after_reset_flip_probability: 0\n# after_clifford_depolarization: 0.001\n# layout:\n#                 X25\n#     L15     d17     d19\n# Z14     X16     Z18\n#     L8      d10     d12\n#         Z9      X11     Z13\n#     L1      d3      d5 \n#         X2 \n# Legend:\n#     d# = data qubit\n#     L# = data qubit with logical observable crossing\n#     X# = measurement qubit (X stabilizer)\n#     Z# = measurement qubit (Z stabilizer)\nQUBIT_COORDS(1, 1) 1\nQUBIT_COORDS(2, 0) 2\nQUBIT_COORDS(3, 1) 3\nQUBIT_COORDS(5, 1) 5\nQUBIT_COORDS(1, 3) 8\nQUBIT_COORDS(2, 2) 9\nQUBIT_COORDS(3, 3) 10\nQUBIT_COORDS(4, 2) 11\nQUBIT_COORDS(5, 3) 12\nQUBIT_COORDS(6, 2) 13\nQUBIT_COORDS(0, 4) 14\nQUBIT_COORDS(1, 5) 15\nQUBIT_COORDS(2, 4) 16\nQUBIT_COORDS(3, 5) 17\nQUBIT_COORDS(4, 4) 18\nQUBIT_COORDS(5, 5) 19\nQUBIT_COORDS(4, 6) 25\nRX 1 3 5 8 10 12 15 17 19\nR 2 9 11 13 14 16 18 25\nTICK\nH 2 11 16 25\nDEPOLARIZE1(0.001) 2 11 16 25\nTICK\nCX 2 3 16 17 11 12 15 14 10 9 19 18\nDEPOLARIZE2(0.001) 2 3 16 17 11 12 15 14 10 9 19 18\nTICK\nCX 2 1 16 15 11 10 8 14 3 9 12 18\nDEPOLARIZE2(0.001) 2 1 16 15 11 10 8 14 3 9 12 18\nTICK\nCX 16 10 11 5 25 19 8 9 17 18 12 13\nDEPOLARIZE2(0.001) 16 10 11 5 25 19 8 9 17 18 12 13\nTICK\nCX 16 8 11 3 25 17 1 9 10 18 5 13\nDEPOLARIZE2(0.001) 16 8 11 3 25 17 1 9 10 18 5 13\nTICK\nH 2 11 16 25\nDEPOLARIZE1(0.001) 2 11 16 25\nTICK\nMR 2 9 11 13 14 16 18 25\nDETECTOR(2, 0, 0) rec[-8]\nDETECTOR(2, 4, 0) rec[-3]\nDETECTOR(4, 2, 0) rec[-6]\nDETECTOR(4, 6, 0) rec[-1]\nREPEAT 999 {\n    TICK\n    H 2 11 16 25\n    DEPOLARIZE1(0.001) 2 11 16 25\n    TICK\n    CX 2 3 16 17 11 12 15 14 10 9 19 18\n    DEPOLARIZE2(0.001) 2 3 16 17 11 12 15 14 10 9 19 18\n    TICK\n    CX 2 1 16 15 11 10 8 14 3 9 12 18\n    DEPOLARIZE2(0.001) 2 1 16 15 11 10 8 14 3 9 12 18\n    TICK\n    CX 16 10 11 5 25 19 8 9 17 18 12 13\n    DEPOLARIZE2(0.001) 16 10 11 5 25 19 8 9 17 18 12 13\n    TICK\n    CX 16 8 11 3 25 17 1 9 10 18 5 13\n    DEPOLARIZE2(0.001) 16 8 11 3 25 17 1 9 10 18 5 13\n    TICK\n    H 2 11 16 25\n    DEPOLARIZE1(0.001) 2 11 16 25\n    TICK\n    MR 2 9 11 13 14 16 18 25\n    SHIFT_COORDS(0, 0, 1)\n    DETECTOR(2, 0, 0) rec[-8] rec[-16]\n    DETECTOR(2, 2, 0) rec[-7] rec[-15]\n    DETECTOR(4, 2, 0) rec[-6] rec[-14]\n    DETECTOR(6, 2, 0) rec[-5] rec[-13]\n    DETECTOR(0, 4, 0) rec[-4] rec[-12]\n    DETECTOR(2, 4, 0) rec[-3] rec[-11]\n    DETECTOR(4, 4, 0) rec[-2] rec[-10]\n    DETECTOR(4, 6, 0) rec[-1] rec[-9]\n}\nMX 1 3 5 8 10 12 15 17 19\nDETECTOR(2, 0, 1) rec[-8] rec[-9] rec[-17]\nDETECTOR(2, 4, 1) rec[-2] rec[-3] rec[-5] rec[-6] rec[-12]\nDETECTOR(4, 2, 1) rec[-4] rec[-5] rec[-7] rec[-8] rec[-15]\nDETECTOR(4, 6, 1) rec[-1] rec[-2] rec[-10]\nOBSERVABLE_INCLUDE(0) rec[-3] rec[-6] rec[-9]\n```\n"
  },
  {
    "path": "doc/gates.md",
    "content": "# Gates supported by Stim\n\n- Pauli Gates\n    - [I](#I)\n    - [X](#X)\n    - [Y](#Y)\n    - [Z](#Z)\n- Single Qubit Clifford Gates\n    - [C_NXYZ](#C_NXYZ)\n    - [C_NZYX](#C_NZYX)\n    - [C_XNYZ](#C_XNYZ)\n    - [C_XYNZ](#C_XYNZ)\n    - [C_XYZ](#C_XYZ)\n    - [C_ZNYX](#C_ZNYX)\n    - [C_ZYNX](#C_ZYNX)\n    - [C_ZYX](#C_ZYX)\n    - [H](#H)\n    - [H_NXY](#H_NXY)\n    - [H_NXZ](#H_NXZ)\n    - [H_NYZ](#H_NYZ)\n    - [H_XY](#H_XY)\n    - [H_XZ](#H_XZ)\n    - [H_YZ](#H_YZ)\n    - [S](#S)\n    - [SQRT_X](#SQRT_X)\n    - [SQRT_X_DAG](#SQRT_X_DAG)\n    - [SQRT_Y](#SQRT_Y)\n    - [SQRT_Y_DAG](#SQRT_Y_DAG)\n    - [SQRT_Z](#SQRT_Z)\n    - [SQRT_Z_DAG](#SQRT_Z_DAG)\n    - [S_DAG](#S_DAG)\n- Two Qubit Clifford Gates\n    - [CNOT](#CNOT)\n    - [CX](#CX)\n    - [CXSWAP](#CXSWAP)\n    - [CY](#CY)\n    - [CZ](#CZ)\n    - [CZSWAP](#CZSWAP)\n    - [II](#II)\n    - [ISWAP](#ISWAP)\n    - [ISWAP_DAG](#ISWAP_DAG)\n    - [SQRT_XX](#SQRT_XX)\n    - [SQRT_XX_DAG](#SQRT_XX_DAG)\n    - [SQRT_YY](#SQRT_YY)\n    - [SQRT_YY_DAG](#SQRT_YY_DAG)\n    - [SQRT_ZZ](#SQRT_ZZ)\n    - [SQRT_ZZ_DAG](#SQRT_ZZ_DAG)\n    - [SWAP](#SWAP)\n    - [SWAPCX](#SWAPCX)\n    - [SWAPCZ](#SWAPCZ)\n    - [XCX](#XCX)\n    - [XCY](#XCY)\n    - [XCZ](#XCZ)\n    - [YCX](#YCX)\n    - [YCY](#YCY)\n    - [YCZ](#YCZ)\n    - [ZCX](#ZCX)\n    - [ZCY](#ZCY)\n    - [ZCZ](#ZCZ)\n- Noise Channels\n    - [CORRELATED_ERROR](#CORRELATED_ERROR)\n    - [DEPOLARIZE1](#DEPOLARIZE1)\n    - [DEPOLARIZE2](#DEPOLARIZE2)\n    - [E](#E)\n    - [ELSE_CORRELATED_ERROR](#ELSE_CORRELATED_ERROR)\n    - [HERALDED_ERASE](#HERALDED_ERASE)\n    - [HERALDED_PAULI_CHANNEL_1](#HERALDED_PAULI_CHANNEL_1)\n    - [II_ERROR](#II_ERROR)\n    - [I_ERROR](#I_ERROR)\n    - [PAULI_CHANNEL_1](#PAULI_CHANNEL_1)\n    - [PAULI_CHANNEL_2](#PAULI_CHANNEL_2)\n    - [X_ERROR](#X_ERROR)\n    - [Y_ERROR](#Y_ERROR)\n    - [Z_ERROR](#Z_ERROR)\n- Collapsing Gates\n    - [M](#M)\n    - [MR](#MR)\n    - [MRX](#MRX)\n    - [MRY](#MRY)\n    - [MRZ](#MRZ)\n    - [MX](#MX)\n    - [MY](#MY)\n    - [MZ](#MZ)\n    - [R](#R)\n    - [RX](#RX)\n    - [RY](#RY)\n    - [RZ](#RZ)\n- Pair Measurement Gates\n    - [MXX](#MXX)\n    - [MYY](#MYY)\n    - [MZZ](#MZZ)\n- Generalized Pauli Product Gates\n    - [MPP](#MPP)\n    - [SPP](#SPP)\n    - [SPP_DAG](#SPP_DAG)\n- Control Flow\n    - [REPEAT](#REPEAT)\n- Annotations\n    - [DETECTOR](#DETECTOR)\n    - [MPAD](#MPAD)\n    - [OBSERVABLE_INCLUDE](#OBSERVABLE_INCLUDE)\n    - [QUBIT_COORDS](#QUBIT_COORDS)\n    - [SHIFT_COORDS](#SHIFT_COORDS)\n    - [TICK](#TICK)\n\n## Pauli Gates\n\n<a name=\"I\"></a>\n### The 'I' Gate\n\nThe identity gate.\nDoes nothing to the target qubits.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to do nothing to.\n\nExample:\n\n    I 5\n    I 42\n    I 5 42\n    \nStabilizer Generators:\n\n    X -> X\n    Z -> Z\n    \nBloch Rotation (axis angle):\n\n    Axis: +X\n    Angle: 0°\n    \nBloch Rotation (Euler angles):\n\n      theta = 0°\n        phi = 0°\n     lambda = 0°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(0°) * RotZ(0°)\n    unitary = I * I * I\n\nUnitary Matrix:\n\n    [+1  ,     ]\n    [    , +1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `I 0`\n    # (no operations)\n    \n    # (The decomposition is empty because this gate has no effect.)\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `I 0` (but affects the measurement record and an ancilla qubit)\n                \n    # (The decomposition is empty because this gate has no effect.)\n    \n\n<a name=\"X\"></a>\n### The 'X' Gate\n\nThe Pauli X gate.\nThe bit flip gate.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    X 5\n    X 42\n    X 5 42\n    \nStabilizer Generators:\n\n    X -> X\n    Z -> -Z\n    \nBloch Rotation (axis angle):\n\n    Axis: +X\n    Angle: 180°\n    \nBloch Rotation (Euler angles):\n\n      theta = 180°\n        phi = 0°\n     lambda = 180°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(180°) * RotZ(180°)\n    unitary = I * Y * Z\n\nUnitary Matrix:\n\n    [    , +1  ]\n    [+1  ,     ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `X 0`\n    H 0\n    S 0\n    S 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `X 0` (but affects the measurement record and an ancilla qubit)\n    X 0\n                \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \n\n<a name=\"Y\"></a>\n### The 'Y' Gate\n\nThe Pauli Y gate.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    Y 5\n    Y 42\n    Y 5 42\n    \nStabilizer Generators:\n\n    X -> -X\n    Z -> -Z\n    \nBloch Rotation (axis angle):\n\n    Axis: +Y\n    Angle: 180°\n    \nBloch Rotation (Euler angles):\n\n      theta = 180°\n        phi = 0°\n     lambda = 0°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(180°) * RotZ(0°)\n    unitary = I * Y * I\n\nUnitary Matrix:\n\n    [    ,   -i]\n    [  +i,     ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `Y 0`\n    S 0\n    S 0\n    H 0\n    S 0\n    S 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `Y 0` (but affects the measurement record and an ancilla qubit)\n    Y 0\n                \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \n\n<a name=\"Z\"></a>\n### The 'Z' Gate\n\nThe Pauli Z gate.\nThe phase flip gate.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    Z 5\n    Z 42\n    Z 5 42\n    \nStabilizer Generators:\n\n    X -> -X\n    Z -> Z\n    \nBloch Rotation (axis angle):\n\n    Axis: +Z\n    Angle: 180°\n    \nBloch Rotation (Euler angles):\n\n      theta = 0°\n        phi = 0°\n     lambda = 180°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(0°) * RotZ(180°)\n    unitary = I * I * Z\n\nUnitary Matrix:\n\n    [+1  ,     ]\n    [    , -1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `Z 0`\n    S 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `Z 0` (but affects the measurement record and an ancilla qubit)\n    Z 0\n                \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \n\n## Single Qubit Clifford Gates\n\n<a name=\"C_NXYZ\"></a>\n### The 'C_NXYZ' Gate\n\nPerforms the period-3 cycle -X -> Y -> Z -> -X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    C_NXYZ 5\n    C_NXYZ 42\n    C_NXYZ 5 42\n    \nStabilizer Generators:\n\n    X -> -Y\n    Z -> -X\n    \nBloch Rotation (axis angle):\n\n    Axis: -X+Y+Z\n    Angle: -120°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 180°\n     lambda = 90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(180°) * RotY(90°) * RotZ(90°)\n    unitary = Z * SQRT_Y * S\n\nUnitary Matrix:\n\n    [+1+i, +1-i]\n    [-1-i, +1-i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `C_NXYZ 0`\n    S 0\n    S 0\n    S 0\n    H 0\n    S 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `C_NXYZ 0` (but affects the measurement record and an ancilla qubit)\n    MZ 1\n    MXX 0 1\n    MY 1\n    MZZ 0 1\n    MX 1\n    Z 0\n    CX rec[-3] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"C_NZYX\"></a>\n### The 'C_NZYX' Gate\n\nPerforms the period-3 cycle X -> -Z -> Y -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    C_NZYX 5\n    C_NZYX 42\n    C_NZYX 5 42\n    \nStabilizer Generators:\n\n    X -> -Z\n    Z -> -Y\n    \nBloch Rotation (axis angle):\n\n    Axis: +X+Y-Z\n    Angle: 120°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = -90°\n     lambda = 0°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(-90°) * RotY(90°) * RotZ(0°)\n    unitary = S_DAG * SQRT_Y * I\n\nUnitary Matrix:\n\n    [+1+i, -1-i]\n    [+1-i, +1-i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `C_NZYX 0`\n    S 0\n    S 0\n    H 0\n    S 0\n    S 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `C_NZYX 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    MXX 0 1\n    MZ 1\n    X 0\n    CX rec[-2] 0 rec[-1] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-3] 0\n                \n\n<a name=\"C_XNYZ\"></a>\n### The 'C_XNYZ' Gate\n\nPerforms the period-3 cycle X -> -Y -> Z -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    C_XNYZ 5\n    C_XNYZ 42\n    C_XNYZ 5 42\n    \nStabilizer Generators:\n\n    X -> -Y\n    Z -> X\n    \nBloch Rotation (axis angle):\n\n    Axis: +X-Y+Z\n    Angle: -120°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 0°\n     lambda = -90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(90°) * RotZ(-90°)\n    unitary = I * SQRT_Y * S_DAG\n\nUnitary Matrix:\n\n    [+1+i, -1+i]\n    [+1+i, +1-i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `C_XNYZ 0`\n    S 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `C_XNYZ 0` (but affects the measurement record and an ancilla qubit)\n    MZ 1\n    MXX 0 1\n    MY 1\n    MZZ 0 1\n    MX 1\n    X 0\n    CX rec[-3] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"C_XYNZ\"></a>\n### The 'C_XYNZ' Gate\n\nPerforms the period-3 cycle X -> Y -> -Z -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    C_XYNZ 5\n    C_XYNZ 42\n    C_XYNZ 5 42\n    \nStabilizer Generators:\n\n    X -> Y\n    Z -> -X\n    \nBloch Rotation (axis angle):\n\n    Axis: +X+Y-Z\n    Angle: -120°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 180°\n     lambda = -90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(180°) * RotY(90°) * RotZ(-90°)\n    unitary = Z * SQRT_Y * S_DAG\n\nUnitary Matrix:\n\n    [+1-i, +1+i]\n    [-1+i, +1+i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `C_XYNZ 0`\n    S 0\n    H 0\n    S 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `C_XYNZ 0` (but affects the measurement record and an ancilla qubit)\n    MZ 1\n    MXX 0 1\n    MY 1\n    MZZ 0 1\n    MX 1\n    Y 0\n    CX rec[-3] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"C_XYZ\"></a>\n### The 'C_XYZ' Gate\n\nRight handed period 3 axis cycling gate, sending X -> Y -> Z -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    C_XYZ 5\n    C_XYZ 42\n    C_XYZ 5 42\n    \nStabilizer Generators:\n\n    X -> Y\n    Z -> X\n    \nBloch Rotation (axis angle):\n\n    Axis: +X+Y+Z\n    Angle: 120°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 0°\n     lambda = 90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(90°) * RotZ(90°)\n    unitary = I * SQRT_Y * S\n\nUnitary Matrix:\n\n    [+1-i, -1-i]\n    [+1-i, +1+i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `C_XYZ 0`\n    S 0\n    S 0\n    S 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `C_XYZ 0` (but affects the measurement record and an ancilla qubit)\n    MZ 1\n    MXX 0 1\n    MY 1\n    MZZ 0 1\n    MX 1\n    CX rec[-3] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"C_ZNYX\"></a>\n### The 'C_ZNYX' Gate\n\nPerforms the period-3 cycle X -> Z -> -Y -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    C_ZNYX 5\n    C_ZNYX 42\n    C_ZNYX 5 42\n    \nStabilizer Generators:\n\n    X -> Z\n    Z -> -Y\n    \nBloch Rotation (axis angle):\n\n    Axis: +X-Y+Z\n    Angle: 120°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = -90°\n     lambda = 180°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(-90°) * RotY(90°) * RotZ(180°)\n    unitary = S_DAG * SQRT_Y * Z\n\nUnitary Matrix:\n\n    [+1-i, +1-i]\n    [-1-i, +1+i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `C_ZNYX 0`\n    H 0\n    S 0\n    S 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `C_ZNYX 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    MXX 0 1\n    MZ 1\n    Z 0\n    CX rec[-2] 0 rec[-1] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-3] 0\n                \n\n<a name=\"C_ZYNX\"></a>\n### The 'C_ZYNX' Gate\n\nPerforms the period-3 cycle -X -> Z -> Y -> -X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    C_ZYNX 5\n    C_ZYNX 42\n    C_ZYNX 5 42\n    \nStabilizer Generators:\n\n    X -> -Z\n    Z -> Y\n    \nBloch Rotation (axis angle):\n\n    Axis: -X+Y+Z\n    Angle: 120°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 90°\n     lambda = 0°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(90°) * RotY(90°) * RotZ(0°)\n    unitary = S * SQRT_Y * I\n\nUnitary Matrix:\n\n    [+1-i, -1+i]\n    [+1+i, +1+i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `C_ZYNX 0`\n    S 0\n    S 0\n    H 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `C_ZYNX 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    MXX 0 1\n    MZ 1\n    Y 0\n    CX rec[-2] 0 rec[-1] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-3] 0\n                \n\n<a name=\"C_ZYX\"></a>\n### The 'C_ZYX' Gate\n\nLeft handed period 3 axis cycling gate, sending Z -> Y -> X -> Z.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    C_ZYX 5\n    C_ZYX 42\n    C_ZYX 5 42\n    \nStabilizer Generators:\n\n    X -> Z\n    Z -> Y\n    \nBloch Rotation (axis angle):\n\n    Axis: +X+Y+Z\n    Angle: -120°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 90°\n     lambda = 180°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(90°) * RotY(90°) * RotZ(180°)\n    unitary = S * SQRT_Y * Z\n\nUnitary Matrix:\n\n    [+1+i, +1+i]\n    [-1+i, +1-i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `C_ZYX 0`\n    H 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `C_ZYX 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    MXX 0 1\n    MZ 1\n    CX rec[-2] 0 rec[-1] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-3] 0\n                \n\n<a name=\"H\"></a>\n### The 'H' Gate\n\nAlternate name: <a name=\"H_XZ\"></a>`H_XZ`\n\nThe Hadamard gate.\nSwaps the X and Z axes.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    H 5\n    H 42\n    H 5 42\n    \nStabilizer Generators:\n\n    X -> Z\n    Z -> X\n    \nBloch Rotation (axis angle):\n\n    Axis: +X+Z\n    Angle: 180°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 0°\n     lambda = 180°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(90°) * RotZ(180°)\n    unitary = I * SQRT_Y * Z\n\nUnitary Matrix:\n\n    [+1  , +1  ]\n    [+1  , -1  ] / sqrt(2)\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `H 0`\n    H 0\n    \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `H 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    MXX 0 1\n    MZ 1\n    MX 1\n    MZZ 0 1\n    MY 1\n    CX rec[-8] 0 rec[-7] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"H_NXY\"></a>\n### The 'H_NXY' Gate\n\nA variant of the Hadamard gate that swaps the -X and +Y axes.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    H_NXY 5\n    H_NXY 42\n    H_NXY 5 42\n    \nStabilizer Generators:\n\n    X -> -Y\n    Z -> -Z\n    \nBloch Rotation (axis angle):\n\n    Axis: +X-Y\n    Angle: 180°\n    \nBloch Rotation (Euler angles):\n\n      theta = 180°\n        phi = 0°\n     lambda = -90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(180°) * RotZ(-90°)\n    unitary = I * Y * S_DAG\n\nUnitary Matrix:\n\n    [    , +1+i]\n    [+1-i,     ] / sqrt(2)\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `H_NXY 0`\n    S 0\n    H 0\n    S 0\n    S 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `H_NXY 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    Y 0\n    CZ rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"H_NXZ\"></a>\n### The 'H_NXZ' Gate\n\nA variant of the Hadamard gate that swaps the -X and +Z axes.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    H_NXZ 5\n    H_NXZ 42\n    H_NXZ 5 42\n    \nStabilizer Generators:\n\n    X -> -Z\n    Z -> -X\n    \nBloch Rotation (axis angle):\n\n    Axis: +X-Z\n    Angle: 180°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 180°\n     lambda = 0°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(180°) * RotY(90°) * RotZ(0°)\n    unitary = Z * SQRT_Y * I\n\nUnitary Matrix:\n\n    [-1  , +1  ]\n    [+1  , +1  ] / sqrt(2)\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `H_NXZ 0`\n    S 0\n    S 0\n    H 0\n    S 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `H_NXZ 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    MXX 0 1\n    MZ 1\n    MX 1\n    MZZ 0 1\n    MY 1\n    Y 0\n    CX rec[-8] 0 rec[-7] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"H_NYZ\"></a>\n### The 'H_NYZ' Gate\n\nA variant of the Hadamard gate that swaps the -Y and +Z axes.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    H_NYZ 5\n    H_NYZ 42\n    H_NYZ 5 42\n    \nStabilizer Generators:\n\n    X -> -X\n    Z -> -Y\n    \nBloch Rotation (axis angle):\n\n    Axis: +Y-Z\n    Angle: 180°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = -90°\n     lambda = -90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(-90°) * RotY(90°) * RotZ(-90°)\n    unitary = S_DAG * SQRT_Y * S_DAG\n\nUnitary Matrix:\n\n    [-1  ,   -i]\n    [  +i, +1  ] / sqrt(2)\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `H_NYZ 0`\n    S 0\n    S 0\n    H 0\n    S 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `H_NYZ 0` (but affects the measurement record and an ancilla qubit)\n    MZ 1\n    MXX 0 1\n    MY 1\n    Y 0\n    CX rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"H_XY\"></a>\n### The 'H_XY' Gate\n\nA variant of the Hadamard gate that swaps the X and Y axes (instead of X and Z).\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    H_XY 5\n    H_XY 42\n    H_XY 5 42\n    \nStabilizer Generators:\n\n    X -> Y\n    Z -> -Z\n    \nBloch Rotation (axis angle):\n\n    Axis: +X+Y\n    Angle: 180°\n    \nBloch Rotation (Euler angles):\n\n      theta = 180°\n        phi = 0°\n     lambda = 90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(180°) * RotZ(90°)\n    unitary = I * Y * S\n\nUnitary Matrix:\n\n    [    , +1-i]\n    [+1+i,     ] / sqrt(2)\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `H_XY 0`\n    H 0\n    S 0\n    S 0\n    H 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `H_XY 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    X 0\n    CZ rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"H_YZ\"></a>\n### The 'H_YZ' Gate\n\nA variant of the Hadamard gate that swaps the Y and Z axes (instead of X and Z).\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    H_YZ 5\n    H_YZ 42\n    H_YZ 5 42\n    \nStabilizer Generators:\n\n    X -> -X\n    Z -> Y\n    \nBloch Rotation (axis angle):\n\n    Axis: +Y+Z\n    Angle: 180°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 90°\n     lambda = 90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(90°) * RotY(90°) * RotZ(90°)\n    unitary = S * SQRT_Y * S\n\nUnitary Matrix:\n\n    [+1  ,   -i]\n    [  +i, -1  ] / sqrt(2)\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `H_YZ 0`\n    H 0\n    S 0\n    H 0\n    S 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `H_YZ 0` (but affects the measurement record and an ancilla qubit)\n    MZ 1\n    MXX 0 1\n    MY 1\n    Z 0\n    CX rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"S\"></a>\n### The 'S' Gate\n\nAlternate name: <a name=\"SQRT_Z\"></a>`SQRT_Z`\n\nPrincipal square root of Z gate.\nPhases the amplitude of |1> by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    S 5\n    S 42\n    S 5 42\n    \nStabilizer Generators:\n\n    X -> Y\n    Z -> Z\n    \nBloch Rotation (axis angle):\n\n    Axis: +Z\n    Angle: 90°\n    \nBloch Rotation (Euler angles):\n\n      theta = 0°\n        phi = 0°\n     lambda = 90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(0°) * RotZ(90°)\n    unitary = I * I * S\n\nUnitary Matrix:\n\n    [+1  ,     ]\n    [    ,   +i]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `S 0`\n    S 0\n    \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `S 0` (but affects the measurement record and an ancilla qubit)\n    MY 1\n    MZZ 0 1\n    MX 1\n    CZ rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"SQRT_X\"></a>\n### The 'SQRT_X' Gate\n\nPrincipal square root of X gate.\nPhases the amplitude of |-> by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    SQRT_X 5\n    SQRT_X 42\n    SQRT_X 5 42\n    \nStabilizer Generators:\n\n    X -> X\n    Z -> -Y\n    \nBloch Rotation (axis angle):\n\n    Axis: +X\n    Angle: 90°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = -90°\n     lambda = 90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(-90°) * RotY(90°) * RotZ(90°)\n    unitary = S_DAG * SQRT_Y * S\n\nUnitary Matrix:\n\n    [+1+i, +1-i]\n    [+1-i, +1+i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_X 0`\n    H 0\n    S 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_X 0` (but affects the measurement record and an ancilla qubit)\n    MZ 1\n    MXX 0 1\n    MY 1\n    CX rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"SQRT_X_DAG\"></a>\n### The 'SQRT_X_DAG' Gate\n\nAdjoint of the principal square root of X gate.\nPhases the amplitude of |-> by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    SQRT_X_DAG 5\n    SQRT_X_DAG 42\n    SQRT_X_DAG 5 42\n    \nStabilizer Generators:\n\n    X -> X\n    Z -> Y\n    \nBloch Rotation (axis angle):\n\n    Axis: +X\n    Angle: -90°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 90°\n     lambda = -90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(90°) * RotY(90°) * RotZ(-90°)\n    unitary = S * SQRT_Y * S_DAG\n\nUnitary Matrix:\n\n    [+1-i, +1+i]\n    [+1+i, +1-i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_X_DAG 0`\n    S 0\n    H 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_X_DAG 0` (but affects the measurement record and an ancilla qubit)\n    MY 1\n    MXX 0 1\n    MZ 1\n    CX rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"SQRT_Y\"></a>\n### The 'SQRT_Y' Gate\n\nPrincipal square root of Y gate.\nPhases the amplitude of |-i> by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    SQRT_Y 5\n    SQRT_Y 42\n    SQRT_Y 5 42\n    \nStabilizer Generators:\n\n    X -> -Z\n    Z -> X\n    \nBloch Rotation (axis angle):\n\n    Axis: +Y\n    Angle: 90°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 0°\n     lambda = 0°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(90°) * RotZ(0°)\n    unitary = I * SQRT_Y * I\n\nUnitary Matrix:\n\n    [+1+i, -1-i]\n    [+1+i, +1+i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_Y 0`\n    S 0\n    S 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_Y 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    MXX 0 1\n    MZ 1\n    MX 1\n    MZZ 0 1\n    MY 1\n    X 0\n    CX rec[-8] 0 rec[-7] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"SQRT_Y_DAG\"></a>\n### The 'SQRT_Y_DAG' Gate\n\nAdjoint of the principal square root of Y gate.\nPhases the amplitude of |-i> by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    SQRT_Y_DAG 5\n    SQRT_Y_DAG 42\n    SQRT_Y_DAG 5 42\n    \nStabilizer Generators:\n\n    X -> Z\n    Z -> -X\n    \nBloch Rotation (axis angle):\n\n    Axis: +Y\n    Angle: -90°\n    \nBloch Rotation (Euler angles):\n\n      theta = 90°\n        phi = 180°\n     lambda = 180°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(180°) * RotY(90°) * RotZ(180°)\n    unitary = Z * SQRT_Y * Z\n\nUnitary Matrix:\n\n    [+1-i, +1-i]\n    [-1+i, +1-i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_Y_DAG 0`\n    H 0\n    S 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_Y_DAG 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    MXX 0 1\n    MZ 1\n    MX 1\n    MZZ 0 1\n    MY 1\n    Z 0\n    CX rec[-8] 0 rec[-7] 0\n    CY rec[-5] 0 rec[-4] 0\n    CZ rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"S_DAG\"></a>\n### The 'S_DAG' Gate\n\nAlternate name: <a name=\"SQRT_Z_DAG\"></a>`SQRT_Z_DAG`\n\nAdjoint of the principal square root of Z gate.\nPhases the amplitude of |1> by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n\nExample:\n\n    S_DAG 5\n    S_DAG 42\n    S_DAG 5 42\n    \nStabilizer Generators:\n\n    X -> -Y\n    Z -> Z\n    \nBloch Rotation (axis angle):\n\n    Axis: +Z\n    Angle: -90°\n    \nBloch Rotation (Euler angles):\n\n      theta = 0°\n        phi = 0°\n     lambda = -90°\n    unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\n    unitary = RotZ(0°) * RotY(0°) * RotZ(-90°)\n    unitary = I * I * S_DAG\n\nUnitary Matrix:\n\n    [+1  ,     ]\n    [    ,   -i]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `S_DAG 0`\n    S 0\n    S 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `S_DAG 0` (but affects the measurement record and an ancilla qubit)\n    MX 1\n    MZZ 0 1\n    MY 1\n    CZ rec[-3] 0 rec[-2] 0 rec[-1] 0\n                \n\n## Two Qubit Clifford Gates\n\n<a name=\"CX\"></a>\n### The 'CX' Gate\n\nAlternate name: <a name=\"CNOT\"></a>`CNOT`\n\nAlternate name: <a name=\"ZCX\"></a>`ZCX`\n\nThe Z-controlled X gate.\nApplies an X gate to the target if the control is in the |1> state.\nEquivalently: negates the amplitude of the |1>|-> state.\nThe first qubit is called the control, and the second qubit is the target.\n\nTo perform a classically controlled X, replace the control with a `rec`\ntarget like rec[-2].\n\nTo perform an I or X gate as configured by sweep data, replace the\ncontrol with a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Bit flip qubit 5 controlled by qubit 2.\n    CX 2 5\n\n    # Perform CX 2 5 then CX 4 2.\n    CX 2 5 4 2\n\n    # Bit flip qubit 6 if the most recent measurement result was TRUE.\n    CX rec[-1] 6\n\n    # Bit flip qubits 7 and 8 conditioned on sweep configuration data.\n    CX sweep[5] 7 sweep[5] 8\nStabilizer Generators:\n\n    X_ -> XX\n    Z_ -> Z_\n    _X -> _X\n    _Z -> ZZ\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,     ,     , +1  ]\n    [    ,     , +1  ,     ]\n    [    , +1  ,     ,     ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `CX 0 1`\n    CNOT 0 1\n    \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `CX 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 0 2\n    MXX 1 2\n    MZ 2\n    CX rec[-3] 1 rec[-1] 1\n    CZ rec[-4] 0 rec[-2] 0\n                \n\n<a name=\"CXSWAP\"></a>\n### The 'CXSWAP' Gate\n\nA combination CX-then-SWAP gate.\nThis gate is kak-equivalent to the iswap gate, but preserves X/Z noise bias.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    CXSWAP 5 6\n    CXSWAP 42 43\n    CXSWAP 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> XX\n    Z_ -> _Z\n    _X -> X_\n    _Z -> ZZ\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,     , +1  ,     ]\n    [    ,     ,     , +1  ]\n    [    , +1  ,     ,     ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `CXSWAP 0 1`\n    CNOT 1 0\n    CNOT 0 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `CXSWAP 0 1` (but affects the measurement record and an ancilla qubit)\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    MZZ 0 2\n    MXX 1 2\n    MZ 2\n    CX rec[-7] 0 rec[-7] 1 rec[-5] 0 rec[-5] 1 rec[-3] 1 rec[-1] 1\n    CZ rec[-6] 0 rec[-6] 1 rec[-2] 0 rec[-4] 1\n                \n\n<a name=\"CY\"></a>\n### The 'CY' Gate\n\nAlternate name: <a name=\"ZCY\"></a>`ZCY`\n\nThe Z-controlled Y gate.\nApplies a Y gate to the target if the control is in the |1> state.\nEquivalently: negates the amplitude of the |1>|-i> state.\nThe first qubit is the control, and the second qubit is the target.\n\nTo perform a classically controlled Y, replace the control with a `rec`\ntarget like rec[-2].\n\nTo perform an I or Y gate as configured by sweep data, replace the\ncontrol with a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Apply Y to qubit 5 controlled by qubit 2.\n    CY 2 5\n\n    # Perform CY 2 5 then CY 4 2.\n    CY 2 5 4 2\n\n    # Apply Y to qubit 6 if the most recent measurement result was TRUE.\n    CY rec[-1] 6\n\n    # Apply Y to qubits 7 and 8 conditioned on sweep configuration data.\n    CY sweep[5] 7 sweep[5] 8\nStabilizer Generators:\n\n    X_ -> XY\n    Z_ -> Z_\n    _X -> ZX\n    _Z -> ZZ\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,     ,     ,   -i]\n    [    ,     , +1  ,     ]\n    [    ,   +i,     ,     ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `CY 0 1`\n    S 1\n    S 1\n    S 1\n    CNOT 0 1\n    S 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `CY 0 1` (but affects the measurement record and an ancilla qubit)\n    MY 2\n    MZZ 1 2\n    MX 2\n    MZZ 0 2\n    MXX 1 2\n    MZ 2\n    MX 2\n    MZZ 1 2\n    MY 2\n    Z 0\n    CY rec[-6] 1 rec[-4] 1\n    CZ rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1\n                \n\n<a name=\"CZ\"></a>\n### The 'CZ' Gate\n\nAlternate name: <a name=\"ZCZ\"></a>`ZCZ`\n\nThe Z-controlled Z gate.\nApplies a Z gate to the target if the control is in the |1> state.\nEquivalently: negates the amplitude of the |1>|1> state.\nThe first qubit is called the control, and the second qubit is the target.\n\nTo perform a classically controlled Z, replace either qubit with a `rec`\ntarget like rec[-2].\n\nTo perform an I or Z gate as configured by sweep data, replace either qubit\nwith a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Apply Z to qubit 5 controlled by qubit 2.\n    CZ 2 5\n\n    # Perform CZ 2 5 then CZ 4 2.\n    CZ 2 5 4 2\n\n    # Apply Z to qubit 6 if the most recent measurement result was TRUE.\n    CZ rec[-1] 6\n\n    # Apply Z to qubit 7 if the 3rd most recent measurement result was TRUE.\n    CZ 7 rec[-3]\n\n    # Apply Z to qubits 7 and 8 conditioned on sweep configuration data.\n    CZ sweep[5] 7 8 sweep[5]\nStabilizer Generators:\n\n    X_ -> XZ\n    Z_ -> Z_\n    _X -> ZX\n    _Z -> _Z\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    , +1  ,     ,     ]\n    [    ,     , +1  ,     ]\n    [    ,     ,     , -1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `CZ 0 1`\n    H 1\n    CNOT 0 1\n    H 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `CZ 0 1` (but affects the measurement record and an ancilla qubit)\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 0 2\n    MX 2\n    MZZ 1 2\n    MXX 0 2\n    MZ 2\n    MX 2\n    MZZ 0 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    CX rec[-13] 0 rec[-12] 0 rec[-2] 0 rec[-1] 0\n    CY rec[-10] 0 rec[-9] 0 rec[-5] 0 rec[-4] 0\n    CZ rec[-11] 0 rec[-10] 1 rec[-8] 0 rec[-6] 0 rec[-3] 0 rec[-13] 1 rec[-12] 1 rec[-7] 1\n                \n\n<a name=\"CZSWAP\"></a>\n### The 'CZSWAP' Gate\n\nAlternate name: <a name=\"SWAPCZ\"></a>`SWAPCZ`\n\nA combination CZ-and-SWAP gate.\nThis gate is kak-equivalent to the iswap gate.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    CZSWAP 5 6\n    CZSWAP 42 43\n    CZSWAP 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> ZX\n    Z_ -> _Z\n    _X -> XZ\n    _Z -> Z_\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,     , +1  ,     ]\n    [    , +1  ,     ,     ]\n    [    ,     ,     , -1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `CZSWAP 0 1`\n    H 0\n    CX 0 1\n    CX 1 0\n    H 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `CZSWAP 0 1` (but affects the measurement record and an ancilla qubit)\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 0 2\n    MX 2\n    MZZ 0 2\n    MXX 1 2\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    MZZ 1 2\n    MY 2\n    MXX 1 2\n    MZ 2\n    CX rec[-10] 0 rec[-6] 0 rec[-15] 1 rec[-14] 1 rec[-2] 1 rec[-1] 1\n    CY rec[-12] 1 rec[-9] 1 rec[-7] 1 rec[-4] 1\n    CZ rec[-15] 0 rec[-14] 0 rec[-12] 0 rec[-9] 0 rec[-13] 1 rec[-10] 1 rec[-8] 1 rec[-3] 1\n                \n\n<a name=\"II\"></a>\n### The 'II' Gate\n\nA two-qubit identity gate.\n\nTwice as much doing-nothing as the I gate! This gate only exists because it\ncan be useful as a communication mechanism for systems built on top of stim.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExamples:\n\n    II 0 1\n\n    R 0\n    II[ACTUALLY_A_LEAKAGE_ISWAP] 0 1\n    R 0\n    CX 1 0\nStabilizer Generators:\n\n    X_ -> X_\n    Z_ -> Z_\n    _X -> _X\n    _Z -> _Z\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    , +1  ,     ,     ]\n    [    ,     , +1  ,     ]\n    [    ,     ,     , +1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `II 0 1`\n    \n    # (The decomposition is empty because this gate has no effect.)\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `II 0 1` (but affects the measurement record and an ancilla qubit)\n    # (The decomposition is empty because this gate has no effect.)\n    \n\n<a name=\"ISWAP\"></a>\n### The 'ISWAP' Gate\n\nSwaps two qubits and phases the -1 eigenspace of the ZZ observable by i.\nEquivalent to `SWAP` then `CZ` then `S` on both targets.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    ISWAP 5 6\n    ISWAP 42 43\n    ISWAP 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> ZY\n    Z_ -> _Z\n    _X -> YZ\n    _Z -> Z_\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,     ,   +i,     ]\n    [    ,   +i,     ,     ]\n    [    ,     ,     , +1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `ISWAP 0 1`\n    H 0\n    CNOT 0 1\n    CNOT 1 0\n    H 1\n    S 1\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `ISWAP 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 0 2\n    MY 2\n    MZZ 1 2\n    MX 2\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 0 2\n    MX 2\n    MZZ 0 2\n    MXX 1 2\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    MZZ 1 2\n    MY 2\n    MXX 1 2\n    MZ 2\n    Z 1\n    CX rec[-10] 0 rec[-6] 0 rec[-15] 1 rec[-14] 1 rec[-2] 1 rec[-1] 1\n    CY rec[-12] 1 rec[-9] 1 rec[-7] 1 rec[-4] 1\n    CZ rec[-18] 0 rec[-18] 1 rec[-17] 0 rec[-16] 0 rec[-15] 0 rec[-14] 0 rec[-12] 0 rec[-9] 0 rec[-20] 1 rec[-19] 1 rec[-13] 1 rec[-10] 1 rec[-8] 1 rec[-3] 1\n                \n\n<a name=\"ISWAP_DAG\"></a>\n### The 'ISWAP_DAG' Gate\n\nSwaps two qubits and phases the -1 eigenspace of the ZZ observable by -i.\nEquivalent to `SWAP` then `CZ` then `S_DAG` on both targets.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    ISWAP_DAG 5 6\n    ISWAP_DAG 42 43\n    ISWAP_DAG 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> -ZY\n    Z_ -> _Z\n    _X -> -YZ\n    _Z -> Z_\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,     ,   -i,     ]\n    [    ,   -i,     ,     ]\n    [    ,     ,     , +1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `ISWAP_DAG 0 1`\n    S 0\n    S 0\n    S 0\n    S 1\n    S 1\n    S 1\n    H 1\n    CNOT 1 0\n    CNOT 0 1\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `ISWAP_DAG 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 0 2\n    MY 2\n    MZZ 1 2\n    MX 2\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 0 2\n    MX 2\n    MZZ 0 2\n    MXX 1 2\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    MZZ 1 2\n    MY 2\n    MXX 1 2\n    MZ 2\n    Z 0\n    CX rec[-10] 0 rec[-6] 0 rec[-15] 1 rec[-14] 1 rec[-2] 1 rec[-1] 1\n    CY rec[-12] 1 rec[-9] 1 rec[-7] 1 rec[-4] 1\n    CZ rec[-18] 0 rec[-18] 1 rec[-17] 0 rec[-16] 0 rec[-15] 0 rec[-14] 0 rec[-12] 0 rec[-9] 0 rec[-20] 1 rec[-19] 1 rec[-13] 1 rec[-10] 1 rec[-8] 1 rec[-3] 1\n                \n\n<a name=\"SQRT_XX\"></a>\n### The 'SQRT_XX' Gate\n\nPhases the -1 eigenspace of the XX observable by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    SQRT_XX 5 6\n    SQRT_XX 42 43\n    SQRT_XX 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> X_\n    Z_ -> -YX\n    _X -> _X\n    _Z -> -XY\n    \nUnitary Matrix (little endian):\n\n    [+1+i,     ,     , +1-i]\n    [    , +1+i, +1-i,     ]\n    [    , +1-i, +1+i,     ]\n    [+1-i,     ,     , +1+i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_XX 0 1`\n    H 0\n    CNOT 0 1\n    H 1\n    S 0\n    S 1\n    H 0\n    H 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_XX 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 0 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MXX 1 2\n    MZZ 0 2\n    MX 2\n    MY 2\n    MXX 1 2\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 0 2\n    MX 2\n    MZ 2\n    MXX 0 2\n    MY 2\n    X 1\n    CX rec[-18] 1 rec[-17] 1 rec[-16] 0 rec[-13] 0 rec[-11] 0 rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-15] 1 rec[-12] 1 rec[-10] 1 rec[-9] 1 rec[-8] 1\n    CY rec[-18] 0 rec[-17] 0 rec[-5] 0 rec[-4] 0\n    CZ rec[-15] 0 rec[-14] 0 rec[-8] 0 rec[-7] 0\n                \n\n<a name=\"SQRT_XX_DAG\"></a>\n### The 'SQRT_XX_DAG' Gate\n\nPhases the -1 eigenspace of the XX observable by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    SQRT_XX_DAG 5 6\n    SQRT_XX_DAG 42 43\n    SQRT_XX_DAG 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> X_\n    Z_ -> YX\n    _X -> _X\n    _Z -> XY\n    \nUnitary Matrix (little endian):\n\n    [+1-i,     ,     , +1+i]\n    [    , +1-i, +1+i,     ]\n    [    , +1+i, +1-i,     ]\n    [+1+i,     ,     , +1-i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_XX_DAG 0 1`\n    H 0\n    CNOT 0 1\n    H 1\n    S 0\n    S 0\n    S 0\n    S 1\n    S 1\n    S 1\n    H 0\n    H 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_XX_DAG 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 0 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MXX 1 2\n    MZZ 0 2\n    MX 2\n    MY 2\n    MXX 1 2\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 0 2\n    MX 2\n    MZ 2\n    MXX 0 2\n    MY 2\n    X 0\n    CX rec[-18] 1 rec[-17] 1 rec[-16] 0 rec[-13] 0 rec[-11] 0 rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-15] 1 rec[-12] 1 rec[-10] 1 rec[-9] 1 rec[-8] 1\n    CY rec[-18] 0 rec[-17] 0 rec[-5] 0 rec[-4] 0\n    CZ rec[-15] 0 rec[-14] 0 rec[-8] 0 rec[-7] 0\n                \n\n<a name=\"SQRT_YY\"></a>\n### The 'SQRT_YY' Gate\n\nPhases the -1 eigenspace of the YY observable by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    SQRT_YY 5 6\n    SQRT_YY 42 43\n    SQRT_YY 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> -ZY\n    Z_ -> XY\n    _X -> -YZ\n    _Z -> YX\n    \nUnitary Matrix (little endian):\n\n    [+1+i,     ,     , -1+i]\n    [    , +1+i, +1-i,     ]\n    [    , +1-i, +1+i,     ]\n    [-1+i,     ,     , +1+i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_YY 0 1`\n    S 0\n    S 0\n    S 0\n    S 1\n    S 1\n    S 1\n    H 0\n    CNOT 0 1\n    H 1\n    S 0\n    S 1\n    H 0\n    H 1\n    S 0\n    S 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_YY 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 1 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MXX 1 2\n    MZZ 0 2\n    MX 2\n    MZZ 0 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MXX 1 2\n    MY 2\n    MZZ 1 2\n    MX 2\n    X 0\n    Y 1\n    CX rec[-16] 1 rec[-15] 1 rec[-14] 0 rec[-6] 0 rec[-5] 0 rec[-3] 1\n    CY rec[-16] 0 rec[-15] 0 rec[-11] 0 rec[-8] 0 rec[-5] 1 rec[-13] 1 rec[-10] 1 rec[-4] 1\n    CZ rec[-13] 0 rec[-12] 0 rec[-7] 0 rec[-14] 1 rec[-2] 1 rec[-1] 1\n                \n\n<a name=\"SQRT_YY_DAG\"></a>\n### The 'SQRT_YY_DAG' Gate\n\nPhases the -1 eigenspace of the YY observable by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    SQRT_YY_DAG 5 6\n    SQRT_YY_DAG 42 43\n    SQRT_YY_DAG 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> ZY\n    Z_ -> -XY\n    _X -> YZ\n    _Z -> -YX\n    \nUnitary Matrix (little endian):\n\n    [+1-i,     ,     , -1-i]\n    [    , +1-i, +1+i,     ]\n    [    , +1+i, +1-i,     ]\n    [-1-i,     ,     , +1-i] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_YY_DAG 0 1`\n    S 0\n    S 0\n    S 0\n    S 1\n    H 0\n    CNOT 0 1\n    H 1\n    S 0\n    S 1\n    H 0\n    H 1\n    S 0\n    S 1\n    S 1\n    S 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_YY_DAG 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 1 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MXX 1 2\n    MZZ 0 2\n    MX 2\n    MZZ 0 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MXX 1 2\n    MY 2\n    MZZ 1 2\n    MX 2\n    Z 0\n    CX rec[-16] 1 rec[-15] 1 rec[-14] 0 rec[-6] 0 rec[-5] 0 rec[-3] 1\n    CY rec[-16] 0 rec[-15] 0 rec[-11] 0 rec[-8] 0 rec[-5] 1 rec[-13] 1 rec[-10] 1 rec[-4] 1\n    CZ rec[-13] 0 rec[-12] 0 rec[-7] 0 rec[-14] 1 rec[-2] 1 rec[-1] 1\n                \n\n<a name=\"SQRT_ZZ\"></a>\n### The 'SQRT_ZZ' Gate\n\nPhases the -1 eigenspace of the ZZ observable by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    SQRT_ZZ 5 6\n    SQRT_ZZ 42 43\n    SQRT_ZZ 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> YZ\n    Z_ -> Z_\n    _X -> ZY\n    _Z -> _Z\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,   +i,     ,     ]\n    [    ,     ,   +i,     ]\n    [    ,     ,     , +1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_ZZ 0 1`\n    H 1\n    CNOT 0 1\n    H 1\n    S 0\n    S 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_ZZ 0 1` (but affects the measurement record and an ancilla qubit)\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 0 2\n    MX 2\n    MZZ 1 2\n    MXX 0 2\n    MZ 2\n    MY 2\n    MZZ 1 2\n    MX 2\n    MZZ 0 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MX 2\n    MZZ 0 2\n    MY 2\n    Z 0\n    CX rec[-15] 0 rec[-14] 0 rec[-8] 0 rec[-7] 0\n    CY rec[-18] 0 rec[-17] 0 rec[-5] 0 rec[-4] 0\n    CZ rec[-18] 1 rec[-17] 1 rec[-16] 0 rec[-13] 0 rec[-11] 0 rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-15] 1 rec[-12] 1 rec[-10] 1 rec[-9] 1 rec[-8] 1\n                \n\n<a name=\"SQRT_ZZ_DAG\"></a>\n### The 'SQRT_ZZ_DAG' Gate\n\nPhases the -1 eigenspace of the ZZ observable by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    SQRT_ZZ_DAG 5 6\n    SQRT_ZZ_DAG 42 43\n    SQRT_ZZ_DAG 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> -YZ\n    Z_ -> Z_\n    _X -> -ZY\n    _Z -> _Z\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,   -i,     ,     ]\n    [    ,     ,   -i,     ]\n    [    ,     ,     , +1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SQRT_ZZ_DAG 0 1`\n    H 1\n    CNOT 0 1\n    H 1\n    S 0\n    S 0\n    S 0\n    S 1\n    S 1\n    S 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SQRT_ZZ_DAG 0 1` (but affects the measurement record and an ancilla qubit)\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 0 2\n    MX 2\n    MZZ 1 2\n    MXX 0 2\n    MZ 2\n    MY 2\n    MZZ 1 2\n    MX 2\n    MZZ 0 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MX 2\n    MZZ 0 2\n    MY 2\n    Z 1\n    CX rec[-15] 0 rec[-14] 0 rec[-8] 0 rec[-7] 0\n    CY rec[-18] 0 rec[-17] 0 rec[-5] 0 rec[-4] 0\n    CZ rec[-18] 1 rec[-17] 1 rec[-16] 0 rec[-13] 0 rec[-11] 0 rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-15] 1 rec[-12] 1 rec[-10] 1 rec[-9] 1 rec[-8] 1\n                \n\n<a name=\"SWAP\"></a>\n### The 'SWAP' Gate\n\nSwaps two qubits.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    SWAP 5 6\n    SWAP 42 43\n    SWAP 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> _X\n    Z_ -> _Z\n    _X -> X_\n    _Z -> Z_\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,     , +1  ,     ]\n    [    , +1  ,     ,     ]\n    [    ,     ,     , +1  ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SWAP 0 1`\n    CNOT 0 1\n    CNOT 1 0\n    CNOT 0 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SWAP 0 1` (but affects the measurement record and an ancilla qubit)\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    MZZ 0 2\n    MXX 1 2\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    CX rec[-6] 0 rec[-6] 1 rec[-2] 0 rec[-10] 1 rec[-8] 1 rec[-4] 1\n    CZ rec[-9] 0 rec[-5] 0 rec[-5] 1 rec[-7] 1 rec[-3] 1 rec[-1] 1\n                \n\n<a name=\"SWAPCX\"></a>\n### The 'SWAPCX' Gate\n\nA combination SWAP-then-CX gate.\nThis gate is kak-equivalent to the iswap gate, but preserves X/Z noise bias.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    SWAPCX 5 6\n    SWAPCX 42 43\n    SWAPCX 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> _X\n    Z_ -> ZZ\n    _X -> XX\n    _Z -> Z_\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    ,     ,     , +1  ]\n    [    , +1  ,     ,     ]\n    [    ,     , +1  ,     ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SWAPCX 0 1`\n    CNOT 0 1\n    CNOT 1 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SWAPCX 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 0 2\n    MXX 1 2\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    CX rec[-6] 0 rec[-6] 1 rec[-2] 0 rec[-4] 1\n    CZ rec[-7] 0 rec[-7] 1 rec[-5] 0 rec[-5] 1 rec[-3] 1 rec[-1] 1\n                \n\n<a name=\"XCX\"></a>\n### The 'XCX' Gate\n\nThe X-controlled X gate.\nFirst qubit is the control, second qubit is the target.\n\nApplies an X gate to the target if the control is in the |-> state.\n\nNegates the amplitude of the |->|-> state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    XCX 5 6\n    XCX 42 43\n    XCX 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> X_\n    Z_ -> ZX\n    _X -> _X\n    _Z -> XZ\n    \nUnitary Matrix (little endian):\n\n    [+1  , +1  , +1  , -1  ]\n    [+1  , +1  , -1  , +1  ]\n    [+1  , -1  , +1  , +1  ]\n    [-1  , +1  , +1  , +1  ] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `XCX 0 1`\n    H 0\n    CNOT 0 1\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `XCX 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 0 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MXX 1 2\n    MZZ 0 2\n    MX 2\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 0 2\n    MX 2\n    CX rec[-11] 0 rec[-10] 1 rec[-8] 0 rec[-6] 0 rec[-3] 0 rec[-13] 1 rec[-12] 1 rec[-7] 1\n    CY rec[-10] 0 rec[-9] 0 rec[-5] 0 rec[-4] 0\n    CZ rec[-13] 0 rec[-12] 0 rec[-2] 0 rec[-1] 0\n                \n\n<a name=\"XCY\"></a>\n### The 'XCY' Gate\n\nThe X-controlled Y gate.\nFirst qubit is the control, second qubit is the target.\n\nApplies a Y gate to the target if the control is in the |-> state.\n\nNegates the amplitude of the |->|-i> state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    XCY 5 6\n    XCY 42 43\n    XCY 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> X_\n    Z_ -> ZY\n    _X -> XX\n    _Z -> XZ\n    \nUnitary Matrix (little endian):\n\n    [+1  , +1  ,   -i,   +i]\n    [+1  , +1  ,   +i,   -i]\n    [  +i,   -i, +1  , +1  ]\n    [  -i,   +i, +1  , +1  ] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `XCY 0 1`\n    H 0\n    S 1\n    S 1\n    S 1\n    CNOT 0 1\n    H 0\n    S 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `XCY 0 1` (but affects the measurement record and an ancilla qubit)\n    MY 2\n    MXX 1 2\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    MZ 2\n    MXX 1 2\n    MY 2\n    X 0\n    CX rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1\n    CY rec[-6] 1 rec[-4] 1\n                \n\n<a name=\"XCZ\"></a>\n### The 'XCZ' Gate\n\nThe X-controlled Z gate.\nApplies a Z gate to the target if the control is in the |-> state.\nEquivalently: negates the amplitude of the |->|1> state.\nSame as a CX gate, but with reversed qubit order.\nThe first qubit is the control, and the second qubit is the target.\n\nTo perform a classically controlled X, replace the Z target with a `rec`\ntarget like rec[-2].\n\nTo perform an I or X gate as configured by sweep data, replace the\nZ target with a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Bit flip qubit 5 controlled by qubit 2.\n    XCZ 5 2\n\n    # Perform CX 2 5 then CX 4 2.\n    XCZ 5 2 2 4\n\n    # Bit flip qubit 6 if the most recent measurement result was TRUE.\n    XCZ 6 rec[-1]\n\n    # Bit flip qubits 7 and 8 conditioned on sweep configuration data.\n    XCZ 7 sweep[5] 8 sweep[5]\nStabilizer Generators:\n\n    X_ -> X_\n    Z_ -> ZZ\n    _X -> XX\n    _Z -> _Z\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    , +1  ,     ,     ]\n    [    ,     ,     , +1  ]\n    [    ,     , +1  ,     ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `XCZ 0 1`\n    CNOT 1 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `XCZ 0 1` (but affects the measurement record and an ancilla qubit)\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    CX rec[-4] 0 rec[-2] 0\n    CZ rec[-3] 1 rec[-1] 1\n                \n\n<a name=\"YCX\"></a>\n### The 'YCX' Gate\n\nThe Y-controlled X gate.\nFirst qubit is the control, second qubit is the target.\n\nApplies an X gate to the target if the control is in the |-i> state.\n\nNegates the amplitude of the |-i>|-> state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    YCX 5 6\n    YCX 42 43\n    YCX 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> XX\n    Z_ -> ZX\n    _X -> _X\n    _Z -> YZ\n    \nUnitary Matrix (little endian):\n\n    [+1  ,   -i, +1  ,   +i]\n    [  +i, +1  ,   -i, +1  ]\n    [+1  ,   +i, +1  ,   -i]\n    [  -i, +1  ,   +i, +1  ] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `YCX 0 1`\n    S 0\n    S 0\n    S 0\n    H 1\n    CNOT 1 0\n    S 0\n    H 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `YCX 0 1` (but affects the measurement record and an ancilla qubit)\n    MY 2\n    MXX 0 2\n    MZ 2\n    MXX 1 2\n    MZZ 0 2\n    MX 2\n    MZ 2\n    MXX 0 2\n    MY 2\n    X 1\n    CX rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-7] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-5] 1\n    CY rec[-6] 0 rec[-4] 0\n                \n\n<a name=\"YCY\"></a>\n### The 'YCY' Gate\n\nThe Y-controlled Y gate.\nFirst qubit is the control, second qubit is the target.\n\nApplies a Y gate to the target if the control is in the |-i> state.\n\nNegates the amplitude of the |-i>|-i> state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    YCY 5 6\n    YCY 42 43\n    YCY 5 6 42 43\n    \nStabilizer Generators:\n\n    X_ -> XY\n    Z_ -> ZY\n    _X -> YX\n    _Z -> YZ\n    \nUnitary Matrix (little endian):\n\n    [+1  ,   -i,   -i, +1  ]\n    [  +i, +1  , -1  ,   -i]\n    [  +i, -1  , +1  ,   -i]\n    [+1  ,   +i,   +i, +1  ] / 2\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `YCY 0 1`\n    S 0\n    S 0\n    S 0\n    S 1\n    S 1\n    S 1\n    H 0\n    CNOT 0 1\n    H 0\n    S 0\n    S 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `YCY 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 1 2\n    MY 2\n    MXX 0 2\n    MZ 2\n    MXX 1 2\n    MZZ 0 2\n    MX 2\n    MZ 2\n    MXX 0 2\n    MY 2\n    MZZ 1 2\n    MX 2\n    Y 1\n    CX rec[-10] 0 rec[-9] 0 rec[-5] 0 rec[-4] 0 rec[-3] 0 rec[-11] 1\n    CY rec[-13] 0 rec[-12] 0 rec[-10] 1 rec[-8] 0 rec[-6] 0 rec[-7] 1\n    CZ rec[-13] 1 rec[-12] 1 rec[-11] 0 rec[-3] 1 rec[-2] 1 rec[-1] 1\n                \n\n<a name=\"YCZ\"></a>\n### The 'YCZ' Gate\n\nThe Y-controlled Z gate.\nApplies a Z gate to the target if the control is in the |-i> state.\nEquivalently: negates the amplitude of the |-i>|1> state.\nSame as a CY gate, but with reversed qubit order.\nThe first qubit is called the control, and the second qubit is the target.\n\nTo perform a classically controlled Y, replace the Z target with a `rec`\ntarget like rec[-2].\n\nTo perform an I or Y gate as configured by sweep data, replace the\nZ target with a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Apply Y to qubit 5 controlled by qubit 2.\n    YCZ 5 2\n\n    # Perform CY 2 5 then CY 4 2.\n    YCZ 5 2 2 4\n\n    # Apply Y to qubit 6 if the most recent measurement result was TRUE.\n    YCZ 6 rec[-1]\n\n    # Apply Y to qubits 7 and 8 conditioned on sweep configuration data.\n    YCZ 7 sweep[5] 8 sweep[5]\nStabilizer Generators:\n\n    X_ -> XZ\n    Z_ -> ZZ\n    _X -> YX\n    _Z -> _Z\n    \nUnitary Matrix (little endian):\n\n    [+1  ,     ,     ,     ]\n    [    , +1  ,     ,     ]\n    [    ,     ,     ,   -i]\n    [    ,     ,   +i,     ]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `YCZ 0 1`\n    S 0\n    S 0\n    S 0\n    CNOT 1 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `YCZ 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 0 2\n    MY 2\n    MZ 2\n    MXX 0 2\n    MZZ 1 2\n    MX 2\n    MZZ 0 2\n    MY 2\n    Z 0\n    CY rec[-6] 0 rec[-4] 0\n    CZ rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-7] 0 rec[-7] 1 rec[-3] 0 rec[-3] 1 rec[-2] 0 rec[-1] 0 rec[-5] 1\n                \n\n## Noise Channels\n\n<a name=\"DEPOLARIZE1\"></a>\n### The 'DEPOLARIZE1' Instruction\n\nThe single qubit depolarizing channel.\n\nApplies a single-qubit depolarizing error with the given probability.\nWhen a single-qubit depolarizing error is applied, a random Pauli\nerror (except for I) is chosen and applied. Note that this means\nmaximal mixing occurs when the probability parameter is set to 75%,\nrather than at 100%.\n\nApplies a randomly chosen Pauli with a given probability.\n\nParens Arguments:\n\n    A single float (p) specifying the depolarization strength.\n\nTargets:\n\n    Qubits to apply single-qubit depolarizing noise to.\n\nPauli Mixture:\n\n    1-p: I\n    p/3: X\n    p/3: Y\n    p/3: Z\n\nExamples:\n\n    # Apply 1-qubit depolarization to qubit 0 using p=1%\n    DEPOLARIZE1(0.01) 0\n\n    # Apply 1-qubit depolarization to qubit 2\n    # Separately apply 1-qubit depolarization to qubits 3 and 5\n    DEPOLARIZE1(0.01) 2 3 5\n\n    # Maximally mix qubits 0 through 2\n    DEPOLARIZE1(0.75) 0 1 2\n\n<a name=\"DEPOLARIZE2\"></a>\n### The 'DEPOLARIZE2' Instruction\n\nThe two qubit depolarizing channel.\n\nApplies a two-qubit depolarizing error with the given probability.\nWhen a two-qubit depolarizing error is applied, a random pair of Pauli\nerrors (except for II) is chosen and applied. Note that this means\nmaximal mixing occurs when the probability parameter is set to 93.75%,\nrather than at 100%.\n\nParens Arguments:\n\n    A single float (p) specifying the depolarization strength.\n\nTargets:\n\n    Qubit pairs to apply two-qubit depolarizing noise to.\n\nPauli Mixture:\n\n     1-p: II\n    p/15: IX\n    p/15: IY\n    p/15: IZ\n    p/15: XI\n    p/15: XX\n    p/15: XY\n    p/15: XZ\n    p/15: YI\n    p/15: YX\n    p/15: YY\n    p/15: YZ\n    p/15: ZI\n    p/15: ZX\n    p/15: ZY\n    p/15: ZZ\n\nExamples:\n\n    # Apply 2-qubit depolarization to qubit 0 and qubit 1 using p=1%\n    DEPOLARIZE2(0.01) 0 1\n\n    # Apply 2-qubit depolarization to qubit 2 and qubit 3\n    # Separately apply 2-qubit depolarization to qubit 5 and qubit 7\n    DEPOLARIZE2(0.01) 2 3 5 7\n\n    # Maximally mix qubits 0 through 3\n    DEPOLARIZE2(0.9375) 0 1 2 3\n\n<a name=\"E\"></a>\n### The 'E' Instruction\n\nAlternate name: <a name=\"CORRELATED_ERROR\"></a>`CORRELATED_ERROR`\n\nProbabilistically applies a Pauli product error with a given probability.\nSets the \"correlated error occurred flag\" to true if the error occurred.\nOtherwise sets the flag to false.\n\nSee also: `ELSE_CORRELATED_ERROR`.\n\nParens Arguments:\n\n    A single float specifying the probability of applying the Paulis making up the error.\n\nTargets:\n\n    Pauli targets specifying the Paulis to apply when the error occurs.\n    Note that, for backwards compatibility reasons, the targets are not combined using combiners (`*`).\n    They are implicitly all combined.\n\nExample:\n\n    # With 60% probability, uniformly pick X1*Y2 or Z2*Z3 or X1*Y2*Z3.\n    CORRELATED_ERROR(0.2) X1 Y2\n    ELSE_CORRELATED_ERROR(0.25) Z2 Z3\n    ELSE_CORRELATED_ERROR(0.33333333333) X1 Y2 Z3\n\n<a name=\"ELSE_CORRELATED_ERROR\"></a>\n### The 'ELSE_CORRELATED_ERROR' Instruction\n\nProbabilistically applies a Pauli product error with a given probability, unless the \"correlated error occurred flag\" is set.\nIf the error occurs, sets the \"correlated error occurred flag\" to true.\nOtherwise leaves the flag alone.\n\nNote: when converting a circuit into a detector error model, every `ELSE_CORRELATED_ERROR` instruction must be preceded by\nan ELSE_CORRELATED_ERROR instruction or an E instruction. In other words, ELSE_CORRELATED_ERROR instructions should appear\nin contiguous chunks started by a CORRELATED_ERROR.\n\nSee also: `CORRELATED_ERROR`.\n\nParens Arguments:\n\n    A single float specifying the probability of applying the Paulis making up the error, conditioned on the \"correlated\n    error occurred flag\" being False.\n\nTargets:\n\n    Pauli targets specifying the Paulis to apply when the error occurs.\n    Note that, for backwards compatibility reasons, the targets are not combined using combiners (`*`).\n    They are implicitly all combined.\n\nExample:\n\n    # With 60% probability, uniformly pick X1*Y2 or Z2*Z3 or X1*Y2*Z3.\n    CORRELATED_ERROR(0.2) X1 Y2\n    ELSE_CORRELATED_ERROR(0.25) Z2 Z3\n    ELSE_CORRELATED_ERROR(0.33333333333) X1 Y2 Z3\n\n<a name=\"HERALDED_ERASE\"></a>\n### The 'HERALDED_ERASE' Instruction\n\nThe heralded erasure noise channel.\n\nWhether or not this noise channel fires is recorded into the measurement\nrecord. When it doesn't fire, nothing happens to the target qubit and a\n0 is recorded. When it does fire, a 1 is recorded and the target qubit\nis erased to the maximally mixed state by applying X_ERROR(0.5) and\nZ_ERROR(0.5).\n\nCAUTION: when converting a circuit with this error into a detector\nerror model, this channel is split into multiple potential effects.\nIn the context of a DEM, these effects are considered independent.\nThis is an approximation, because independent effects can be combined.\nThe effect of this approximation, assuming a detector is declared\non the herald, is that it appears this detector can be cancelled out\nby two of the (originally disjoint) heralded effects firing together.\nSampling from the DEM instead of the circuit can thus produce unheralded\nerrors, even if the circuit noise model only contains heralded errors.\nThese issues occur with probability p^2, where p is the probability of a\nheralded error, since two effects that came from the same heralded error\nmust occur together to cancel out the herald detector. This also means\na decoder configured using the DEM will think there's a chance of unheralded\nerrors even if the circuit the DEM came from only uses heralded errors.\n\nParens Arguments:\n\n    A single float (p) specifying the chance of the noise firing.\n\nTargets:\n\n    Qubits to apply single-qubit depolarizing noise to. Each target\n    is operated on independently.\n\nPauli Mixture:\n\n    1-p: record 0, apply I\n    p/4: record 1, apply I\n    p/4: record 1, apply X\n    p/4: record 1, apply Y\n    p/4: record 1, apply Z\n\nExamples:\n\n    # Erase qubit 0 with probability 1%\n    HERALDED_ERASE(0.01) 0\n    # Declare a flag detector based on the erasure\n    DETECTOR rec[-1]\n\n    # Erase qubit 2 with 2% probability\n    # Separately, erase qubit 3 with 2% probability\n    HERALDED_ERASE(0.02) 2 3\n\n    # Do an XXXX measurement\n    MPP X2*X3*X5*X7\n    # Apply partially-heralded noise to the two qubits\n    HERALDED_ERASE(0.01) 2 3 5 7\n    DEPOLARIZE1(0.0001) 2 3 5 7\n    # Repeat the XXXX measurement\n    MPP X2*X3*X5*X7\n    # Declare a detector comparing the two XXXX measurements\n    DETECTOR rec[-1] rec[-6]\n    # Declare flag detectors based on the erasures\n    DETECTOR rec[-2]\n    DETECTOR rec[-3]\n    DETECTOR rec[-4]\n    DETECTOR rec[-5]\n\n<a name=\"HERALDED_PAULI_CHANNEL_1\"></a>\n### The 'HERALDED_PAULI_CHANNEL_1' Instruction\n\nA heralded error channel that applies biased noise.\n\nThis error records a bit into the measurement record, indicating whether\nor not the herald fired. How likely it is that the herald fires, and the\ncorresponding chance of each possible error effect (I, X, Y, or Z) are\nconfigured by the parens arguments of the instruction.\n\nCAUTION: when converting a circuit with this error into a detector\nerror model, this channel is split into multiple potential effects.\nIn the context of a DEM, these effects are considered independent.\nThis is an approximation, because independent effects can be combined.\nThe effect of this approximation, assuming a detector is declared\non the herald, is that it appears this detector can be cancelled out\nby two of the (originally disjoint) heralded effects firing together.\nSampling from the DEM instead of the circuit can thus produce unheralded\nerrors, even if the circuit noise model only contains heralded errors.\nThese issues occur with probability p^2, where p is the probability of a\nheralded error, since two effects that came from the same heralded error\nmust occur together to cancel out the herald detector. This also means\na decoder configured using the DEM will think there's a chance of unheralded\nerrors even if the circuit the DEM came from only uses heralded errors.\n\nParens Arguments:\n\n    This instruction takes four arguments (pi, px, py, pz). The\n    arguments are disjoint probabilities, specifying the chances\n    of heralding with various effects.\n\n    pi is the chance of heralding with no effect (a false positive).\n    px is the chance of heralding with an X error.\n    py is the chance of heralding with a Y error.\n    pz is the chance of heralding with a Z error.\n\nTargets:\n\n    Qubits to apply heralded biased noise to.\n\nPauli Mixture:\n\n    1-pi-px-py-pz: record 0, apply I\n               pi: record 1, apply I\n               px: record 1, apply X\n               py: record 1, apply Y\n               pz: record 1, apply Z\n\nExamples:\n\n    # With 10% probability perform a phase flip of qubit 0.\n    HERALDED_PAULI_CHANNEL_1(0, 0, 0, 0.1) 0\n    DETECTOR rec[-1]  # Include the herald in detectors available to the decoder\n\n    # With 20% probability perform a heralded dephasing of qubit 0.\n    HERALDED_PAULI_CHANNEL_1(0.1, 0, 0, 0.1) 0\n    DETECTOR rec[-1]\n\n    # Subject a Bell Pair to heralded noise.\n    MXX 0 1\n    MZZ 0 1\n    HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.04) 0 1\n    MXX 0 1\n    MZZ 0 1\n    DETECTOR rec[-1] rec[-5]  # Did ZZ stabilizer change?\n    DETECTOR rec[-2] rec[-6]  # Did XX stabilizer change?\n    DETECTOR rec[-3]    # Did the herald on qubit 1 fire?\n    DETECTOR rec[-4]    # Did the herald on qubit 0 fire?\n\n<a name=\"II_ERROR\"></a>\n### The 'II_ERROR' Instruction\n\nApplies a two-qubit identity with a given probability.\n\nThis gate has no effect. It only exists because it can be useful as a\ncommunication mechanism for systems built on top of stim.\n\nParens Arguments:\n\n    A list of disjoint probabilities summing to at most 1.\n\n    The probabilities have no effect on stim simulations or error analysis, but may be\n    interpreted in arbitrary ways by external tools.\n\nTargets:\n\n    Qubits to apply identity noise to.\n\nPauli Mixture:\n\n    *: II\n\nExamples:\n\n    # does nothing\n    II_ERROR 0 1\n\n    # does nothing with probability 0.1, else does nothing\n    II_ERROR(0.1) 0 1\n\n    # checks for you that the targets are two-qubit pairs\n    II_ERROR[TWO_QUBIT_LEAKAGE_NOISE_FOR_AN_ADVANCED_SIMULATOR:0.1] 0 2 4 6\n\n    # checks for you that the disjoint probabilities in the arguments are legal\n    II_ERROR[MULTIPLE_TWO_QUBIT_NOISE_MECHANISMS](0.1, 0.2) 0 2 4 6\n\n\n<a name=\"I_ERROR\"></a>\n### The 'I_ERROR' Instruction\n\nApplies an identity with a given probability.\n\nThis gate has no effect. It only exists because it can be useful as a\ncommunication mechanism for systems built on top of stim.\n\nParens Arguments:\n\n    A list of disjoint probabilities summing to at most 1.\n\n    The probabilities have no effect on stim simulations or error analysis, but may be\n    interpreted in arbitrary ways by external tools.\n\nTargets:\n\n    Qubits to apply identity noise to.\n\nPauli Mixture:\n\n     *: I\n\nExamples:\n\n    # does nothing\n    I_ERROR 0\n\n    # does nothing with probability 0.1, else does nothing\n    I_ERROR(0.1) 0\n\n    # doesn't require a probability argument\n    I_ERROR[LEAKAGE_NOISE_FOR_AN_ADVANCED_SIMULATOR:0.1] 0 2 4\n\n    # checks for you that the disjoint probabilities in the arguments are legal\n    I_ERROR[MULTIPLE_NOISE_MECHANISMS](0.1, 0.2) 0 2 4\n\n<a name=\"PAULI_CHANNEL_1\"></a>\n### The 'PAULI_CHANNEL_1' Instruction\n\nA single qubit Pauli error channel with explicitly specified probabilities for each case.\n\nParens Arguments:\n\n    Three floats specifying disjoint Pauli case probabilities.\n    px: Disjoint probability of applying an X error.\n    py: Disjoint probability of applying a Y error.\n    pz: Disjoint probability of applying a Z error.\n\nTargets:\n\n    Qubits to apply the custom noise channel to.\n\nExample:\n\n    # Sample errors from the distribution 10% X, 15% Y, 20% Z, 55% I.\n    # Apply independently to qubits 1, 2, 4.\n    PAULI_CHANNEL_1(0.1, 0.15, 0.2) 1 2 4\n\nPauli Mixture:\n\n    1-px-py-pz: I\n    px: X\n    py: Y\n    pz: Z\n\n<a name=\"PAULI_CHANNEL_2\"></a>\n### The 'PAULI_CHANNEL_2' Instruction\n\nA two qubit Pauli error channel with explicitly specified probabilities for each case.\n\nParens Arguments:\n\n    Fifteen floats specifying the disjoint probabilities of each possible Pauli pair\n    that can occur (except for the non-error double identity case).\n    The disjoint probability arguments are (in order):\n\n    1. pix: Probability of applying an IX operation.\n    2. piy: Probability of applying an IY operation.\n    3. piz: Probability of applying an IZ operation.\n    4. pxi: Probability of applying an XI operation.\n    5. pxx: Probability of applying an XX operation.\n    6. pxy: Probability of applying an XY operation.\n    7. pxz: Probability of applying an XZ operation.\n    8. pyi: Probability of applying a YI operation.\n    9. pyx: Probability of applying a YX operation.\n    10. pyy: Probability of applying a YY operation.\n    11. pyz: Probability of applying a YZ operation.\n    12. pzi: Probability of applying a ZI operation.\n    13. pzx: Probability of applying a ZX operation.\n    14. pzy: Probability of applying a ZY operation.\n    15. pzz: Probability of applying a ZZ operation.\n\nTargets:\n\n    Pairs of qubits to apply the custom noise channel to.\n    There must be an even number of targets.\n\nExample:\n\n    # Sample errors from the distribution 10% XX, 20% YZ, 70% II.\n    # Apply independently to qubit pairs (1,2), (5,6), and (8,3)\n    PAULI_CHANNEL_2(0,0,0, 0,0.1,0,0, 0,0,0,0.2, 0,0,0,0) 1 2 5 6 8 3\n\nPauli Mixture:\n\n    1-pix-piy-piz-pxi-pxx-pxy-pxz-pyi-pyx-pyy-pyz-pzi-pzx-pzy-pzz: II\n    pix: IX\n    piy: IY\n    piz: IZ\n    pxi: XI\n    pxx: XX\n    pxy: XY\n    pxz: XZ\n    pyi: YI\n    pyx: YX\n    pyy: YY\n    pyz: YZ\n    pzi: ZI\n    pzx: ZX\n    pzy: ZY\n    pzz: ZZ\n\n<a name=\"X_ERROR\"></a>\n### The 'X_ERROR' Instruction\n\nApplies a Pauli X with a given probability.\n\nParens Arguments:\n\n    A single float specifying the probability of applying an X operation.\n\nTargets:\n\n    Qubits to apply bit flip noise to.\n\nPauli Mixture:\n\n    1-p: I\n     p : X\n\nExample:\n\n    X_ERROR(0.001) 5\n    X_ERROR(0.001) 42\n    X_ERROR(0.001) 5 42\n    \n\n<a name=\"Y_ERROR\"></a>\n### The 'Y_ERROR' Instruction\n\nApplies a Pauli Y with a given probability.\n\nParens Arguments:\n\n    A single float specifying the probability of applying a Y operation.\n\nTargets:\n\n    Qubits to apply Y flip noise to.\n\nPauli Mixture:\n\n    1-p: I\n     p : Y\n\nExample:\n\n    Y_ERROR(0.001) 5\n    Y_ERROR(0.001) 42\n    Y_ERROR(0.001) 5 42\n    \n\n<a name=\"Z_ERROR\"></a>\n### The 'Z_ERROR' Instruction\n\nApplies a Pauli Z with a given probability.\n\nParens Arguments:\n\n    A single float specifying the probability of applying a Z operation.\n\nTargets:\n\n    Qubits to apply phase flip noise to.\n\nPauli Mixture:\n\n    1-p: I\n     p : Z\n\nExample:\n\n    Z_ERROR(0.001) 5\n    Z_ERROR(0.001) 42\n    Z_ERROR(0.001) 5 42\n    \n\n## Collapsing Gates\n\n<a name=\"M\"></a>\n### The 'M' Instruction\n\nAlternate name: <a name=\"MZ\"></a>`MZ`\n\nZ-basis measurement.\nProjects each target qubit into `|0>` or `|1>` and reports its value (false=`|0>`, true=`|1>`).\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The qubits to measure in the Z basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the Z basis, and append the result into the measurement record.\n    M 5\n\n    # 'MZ' is the same as 'M'. This also measures qubit 5 in the Z basis.\n    MZ 5\n\n    # Measure qubit 5 in the Z basis, and append the INVERSE of its result into the measurement record.\n    MZ !5\n\n    # Do a noisy measurement where the result put into the measurement record is wrong 1% of the time.\n    MZ(0.01) 5\n\n    # Measure multiple qubits in the Z basis, putting 3 bits into the measurement record.\n    MZ 2 3 5\n\n    # Perform multiple noisy measurements. Each measurement fails independently with 2% probability.\n    MZ(0.02) 2 3 5\nStabilizer Generators:\n\n    Z -> rec[-1]\n    Z -> Z\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `M 0`\n    M 0\n    \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `M 0` (but affects the measurement record and an ancilla qubit)\n    MZ 0\n                \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \n\n<a name=\"MR\"></a>\n### The 'MR' Instruction\n\nAlternate name: <a name=\"MRZ\"></a>`MRZ`\n\nZ-basis demolition measurement (optionally noisy).\nProjects each target qubit into `|0>` or `|1>`, reports its value (false=`|0>`, true=`|1>`), then resets to `|0>`.\n\nParens Arguments:\n\n    If no parens argument is given, the demolition measurement is perfect.\n    If one parens argument is given, the demolition measurement's result is noisy.\n    The argument is the probability of returning the wrong result.\n    The argument does not affect the fidelity of the reset.\n\nTargets:\n\n    The qubits to measure and reset in the Z basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the Z basis, reset it to the |0> state, append the measurement result into the measurement record.\n    MRZ 5\n\n    # MR is also a Z-basis demolition measurement.\n    MR 5\n\n    # Demolition measure qubit 5 in the Z basis, but append the INVERSE of its result into the measurement record.\n    MRZ !5\n\n    # Do a noisy demolition measurement where the result put into the measurement record is wrong 1% of the time.\n    MRZ(0.01) 5\n\n    # Demolition measure multiple qubits in the Z basis, putting 3 bits into the measurement record.\n    MRZ 2 3 5\n\n    # Perform multiple noisy demolition measurements. Each measurement result is flipped independently with 2% probability.\n    MRZ(0.02) 2 3 5\nStabilizer Generators:\n\n    Z -> rec[-1]\n    1 -> Z\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `MR 0`\n    M 0\n    R 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `MR 0` (but affects the measurement record and an ancilla qubit)\n    MZ 0\n    CX rec[-1] 0\n                \n\n<a name=\"MRX\"></a>\n### The 'MRX' Instruction\n\nX-basis demolition measurement (optionally noisy).\nProjects each target qubit into `|+>` or `|->`, reports its value (false=`|+>`, true=`|->`), then resets to `|+>`.\n\nParens Arguments:\n\n    If no parens argument is given, the demolition measurement is perfect.\n    If one parens argument is given, the demolition measurement's result is noisy.\n    The argument is the probability of returning the wrong result.\n    The argument does not affect the fidelity of the reset.\n\nTargets:\n\n    The qubits to measure and reset in the X basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the X basis, reset it to the |+> state, append the measurement result into the measurement record.\n    MRX 5\n\n    # Demolition measure qubit 5 in the X basis, but append the INVERSE of its result into the measurement record.\n    MRX !5\n\n    # Do a noisy demolition measurement where the result put into the measurement record is wrong 1% of the time.\n    MRX(0.01) 5\n\n    # Demolition measure multiple qubits in the X basis, putting 3 bits into the measurement record.\n    MRX 2 3 5\n\n    # Perform multiple noisy demolition measurements. Each measurement result is flipped independently with 2% probability.\n    MRX(0.02) 2 3 5\nStabilizer Generators:\n\n    X -> rec[-1]\n    1 -> X\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `MRX 0`\n    H 0\n    M 0\n    R 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `MRX 0` (but affects the measurement record and an ancilla qubit)\n    MX 0\n    CZ rec[-1] 0\n                \n\n<a name=\"MRY\"></a>\n### The 'MRY' Instruction\n\nY-basis demolition measurement (optionally noisy).\nProjects each target qubit into `|i>` or `|-i>`, reports its value (false=`|i>`, true=`|-i>`), then resets to `|i>`.\n\nParens Arguments:\n\n    If no parens argument is given, the demolition measurement is perfect.\n    If one parens argument is given, the demolition measurement's result is noisy.\n    The argument is the probability of returning the wrong result.\n    The argument does not affect the fidelity of the reset.\n\nTargets:\n\n    The qubits to measure and reset in the Y basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the Y basis, reset it to the |i> state, append the measurement result into the measurement record.\n    MRY 5\n\n    # Demolition measure qubit 5 in the Y basis, but append the INVERSE of its result into the measurement record.\n    MRY !5\n\n    # Do a noisy demolition measurement where the result put into the measurement record is wrong 1% of the time.\n    MRY(0.01) 5\n\n    # Demolition measure multiple qubits in the Y basis, putting 3 bits into the measurement record.\n    MRY 2 3 5\n\n    # Perform multiple noisy demolition measurements. Each measurement result is flipped independently with 2% probability.\n    MRY(0.02) 2 3 5\nStabilizer Generators:\n\n    Y -> rec[-1]\n    1 -> Y\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `MRY 0`\n    S 0\n    S 0\n    S 0\n    H 0\n    M 0\n    R 0\n    H 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `MRY 0` (but affects the measurement record and an ancilla qubit)\n    MY 0\n    CX rec[-1] 0\n                \n\n<a name=\"MX\"></a>\n### The 'MX' Instruction\n\nX-basis measurement.\nProjects each target qubit into `|+>` or `|->` and reports its value (false=`|+>`, true=`|->`).\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The qubits to measure in the X basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the X basis, and append the result into the measurement record.\n    MX 5\n\n    # Measure qubit 5 in the X basis, and append the INVERSE of its result into the measurement record.\n    MX !5\n\n    # Do a noisy measurement where the result put into the measurement record is wrong 1% of the time.\n    MX(0.01) 5\n\n    # Measure multiple qubits in the X basis, putting 3 bits into the measurement record.\n    MX 2 3 5\n\n    # Perform multiple noisy measurements. Each measurement fails independently with 2% probability.\n    MX(0.02) 2 3 5\nStabilizer Generators:\n\n    X -> rec[-1]\n    X -> X\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `MX 0`\n    H 0\n    M 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `MX 0` (but affects the measurement record and an ancilla qubit)\n    MX 0\n                \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \n\n<a name=\"MY\"></a>\n### The 'MY' Instruction\n\nY-basis measurement.\nProjects each target qubit into `|i>` or `|-i>` and reports its value (false=`|i>`, true=`|-i>`).\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The qubits to measure in the Y basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the Y basis, and append the result into the measurement record.\n    MY 5\n\n    # Measure qubit 5 in the Y basis, and append the INVERSE of its result into the measurement record.\n    MY !5\n\n    # Do a noisy measurement where the result put into the measurement record is wrong 1% of the time.\n    MY(0.01) 5\n\n    # Measure multiple qubits in the X basis, putting 3 bits into the measurement record.\n    MY 2 3 5\n\n    # Perform multiple noisy measurements. Each measurement fails independently with 2% probability.\n    MY(0.02) 2 3 5\nStabilizer Generators:\n\n    Y -> rec[-1]\n    Y -> Y\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `MY 0`\n    S 0\n    S 0\n    S 0\n    H 0\n    M 0\n    H 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `MY 0` (but affects the measurement record and an ancilla qubit)\n    MY 0\n                \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \n\n<a name=\"R\"></a>\n### The 'R' Instruction\n\nAlternate name: <a name=\"RZ\"></a>`RZ`\n\nZ-basis reset.\nForces each target qubit into the `|0>` state by silently measuring it in the Z basis and applying an `X` gate if it ended up in the `|1>` state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    The qubits to reset in the Z basis.\n\nExamples:\n\n    # Reset qubit 5 into the |0> state.\n    RZ 5\n\n    # R means the same thing as RZ.\n    R 5\n\n    # Reset multiple qubits into the |0> state.\n    RZ 2 3 5\nStabilizer Generators:\n\n    1 -> Z\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `R 0`\n    R 0\n    \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `R 0` (but affects the measurement record and an ancilla qubit)\n    MZ 0\n    CX rec[-1] 0\n                \n\n<a name=\"RX\"></a>\n### The 'RX' Instruction\n\nX-basis reset.\nForces each target qubit into the `|+>` state by silently measuring it in the X basis and applying a `Z` gate if it ended up in the `|->` state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    The qubits to reset in the X basis.\n\nExamples:\n\n    # Reset qubit 5 into the |+> state.\n    RX 5\n\n    # Reset multiple qubits into the |+> state.\n    RX 2 3 5\nStabilizer Generators:\n\n    1 -> X\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `RX 0`\n    R 0\n    H 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `RX 0` (but affects the measurement record and an ancilla qubit)\n    MX 0\n    CZ rec[-1] 0\n                \n\n<a name=\"RY\"></a>\n### The 'RY' Instruction\n\nY-basis reset.\nForces each target qubit into the `|i>` state by silently measuring it in the Y basis and applying an `X` gate if it ended up in the `|-i>` state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    The qubits to reset in the Y basis.\n\nExamples:\n\n    # Reset qubit 5 into the |i> state.\n    RY 5\n\n    # Reset multiple qubits into the |i> state.\n    RY 2 3 5\nStabilizer Generators:\n\n    1 -> Y\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `RY 0`\n    R 0\n    H 0\n    S 0\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `RY 0` (but affects the measurement record and an ancilla qubit)\n    MY 0\n    CX rec[-1] 0\n                \n\n## Pair Measurement Gates\n\n<a name=\"MXX\"></a>\n### The 'MXX' Instruction\n\nTwo-qubit X basis parity measurement.\n\nThis operation measures whether pairs of qubits are in the {|++>,|-->} subspace or in the\n{|+->,|-+>} subspace of the two qubit state space. |+> and |-> are the +1 and -1\neigenvectors of the X operator.\n\nIf the qubits were in the {|++>,|-->} subspace, False is appended to the measurement record.\nIf the qubits were in the {|+->,|-+>} subspace, True is appended to the measurement record.\nInverting one of the qubit targets inverts the result.\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The pairs of qubits to measure in the X basis.\n\n    This operation accepts inverted qubit targets (like `!5` instead of `5`). Inverted\n    targets flip the measurement result.\n\nExamples:\n\n    # Measure the +XX observable of qubit 1 vs qubit 2.\n    MXX 1 2\n\n    # Measure the -XX observable of qubit 1 vs qubit 2.\n    MXX !1 2\n\n    # Do a noisy measurement of the +XX observable of qubit 2 vs qubit 3.\n    # The result recorded to the measurement record will be flipped 1% of the time.\n    MXX(0.01) 2 3\n\n    # Measure the +XX observable qubit 1 vs qubit 2, and also qubit 8 vs qubit 9\n    MXX 1 2 8 9\n\n    # Perform multiple noisy measurements.\n    # Each measurement has an independent 2% chance of being recorded wrong.\n    MXX(0.02) 2 3 5 7 11 19 17 4\nStabilizer Generators:\n\n    X_ -> X_\n    _X -> _X\n    ZZ -> ZZ\n    XX -> rec[-1]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `MXX 0 1`\n    CX 0 1\n    H 0\n    M 0\n    H 0\n    CX 0 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `MXX 0 1` (but affects the measurement record and an ancilla qubit)\n    MXX 0 1\n                \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \n\n<a name=\"MYY\"></a>\n### The 'MYY' Instruction\n\nTwo-qubit Y basis parity measurement.\n\nThis operation measures whether pairs of qubits are in the {|ii>,|jj>} subspace or in the\n{|ij>,|ji>} subspace of the two qubit state space. |i> and |j> are the +1 and -1\neigenvectors of the Y operator.\n\nIf the qubits were in the {|ii>,|jj>} subspace, False is appended to the measurement record.\nIf the qubits were in the {|ij>,|ji>} subspace, True is appended to the measurement record.\nInverting one of the qubit targets inverts the result.\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The pairs of qubits to measure in the Y basis.\n\n    This operation accepts inverted qubit targets (like `!5` instead of `5`). Inverted\n    targets flip the measurement result.\n\nExamples:\n\n    # Measure the +YY observable of qubit 1 vs qubit 2.\n    MYY 1 2\n\n    # Measure the -YY observable of qubit 1 vs qubit 2.\n    MYY !1 2\n\n    # Do a noisy measurement of the +YY observable of qubit 2 vs qubit 3.\n    # The result recorded to the measurement record will be flipped 1% of the time.\n    MYY(0.01) 2 3\n\n    # Measure the +YY observable qubit 1 vs qubit 2, and also qubit 8 vs qubit 9\n    MYY 1 2 8 9\n\n    # Perform multiple noisy measurements.\n    # Each measurement has an independent 2% chance of being recorded wrong.\n    MYY(0.02) 2 3 5 7 11 19 17 4\nStabilizer Generators:\n\n    XX -> XX\n    Y_ -> Y_\n    _Y -> _Y\n    YY -> rec[-1]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `MYY 0 1`\n    S 0 1\n    CX 0 1\n    H 0\n    M 0\n    S 1 1\n    H 0\n    CX 0 1\n    S 0 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `MYY 0 1` (but affects the measurement record and an ancilla qubit)\n    MX 2\n    MZZ 0 2\n    MY 2\n    MX 2\n    MZZ 1 2\n    MY 2\n    MXX 0 1\n    MX 2\n    MZZ 0 2\n    MY 2\n    MX 2\n    MZZ 1 2\n    MY 2\n    Z 0 1\n    CZ rec[-13] 0 rec[-12] 0 rec[-11] 0 rec[-6] 0 rec[-5] 0 rec[-4] 0 rec[-10] 1 rec[-9] 1 rec[-8] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1\n                \n\n<a name=\"MZZ\"></a>\n### The 'MZZ' Instruction\n\nTwo-qubit Z basis parity measurement.\n\nThis operation measures whether pairs of qubits are in the {|00>,|11>} subspace or in the\n{|01>,|10>} subspace of the two qubit state space. |0> and |1> are the +1 and -1\neigenvectors of the Z operator.\n\nIf the qubits were in the {|00>,|11>} subspace, False is appended to the measurement record.\nIf the qubits were in the {|01>,|10>} subspace, True is appended to the measurement record.\nInverting one of the qubit targets inverts the result.\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The pairs of qubits to measure in the Z basis.\n\n    This operation accepts inverted qubit targets (like `!5` instead of `5`). Inverted\n    targets flip the measurement result.\n\nExamples:\n\n    # Measure the +ZZ observable of qubit 1 vs qubit 2.\n    MZZ 1 2\n\n    # Measure the -ZZ observable of qubit 1 vs qubit 2.\n    MZZ !1 2\n\n    # Do a noisy measurement of the +ZZ observable of qubit 2 vs qubit 3.\n    # The result recorded to the measurement record will be flipped 1% of the time.\n    MZZ(0.01) 2 3\n\n    # Measure the +ZZ observable qubit 1 vs qubit 2, and also qubit 8 vs qubit 9\n    MZZ 1 2 8 9\n\n    # Perform multiple noisy measurements.\n    # Each measurement has an independent 2% chance of being recorded wrong.\n    MZZ(0.02) 2 3 5 7 11 19 17 4\nStabilizer Generators:\n\n    XX -> XX\n    Z_ -> Z_\n    _Z -> _Z\n    ZZ -> rec[-1]\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `MZZ 0 1`\n    CX 0 1\n    M 1\n    CX 0 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `MZZ 0 1` (but affects the measurement record and an ancilla qubit)\n    MZZ 0 1\n                \n    # (The decomposition is trivial because this gate is in the target gate set.)\n    \n\n## Generalized Pauli Product Gates\n\n<a name=\"MPP\"></a>\n### The 'MPP' Instruction\n\nMeasures general pauli product operators, like X1*Y2*Z3.\n\nParens Arguments:\n\n    An optional failure probability.\n    If no argument is given, all measurements are perfect.\n    If one argument is given, it's the chance of reporting measurement results incorrectly.\n\nTargets:\n\n    A series of Pauli products to measure.\n\n    Each Pauli product is a series of Pauli targets (like `X1`, `Y2`, or `Z3`) separated by\n    combiners (`*`). Each Pauli term can be inverted (like `!Y2` instead of `Y2`). A negated\n    product will record the opposite measurement result.\n\n    Note that, although you can write down instructions that measure anti-Hermitian products,\n    like `MPP X1*Z1`, doing this will cause exceptions when you simulate or analyze the\n    circuit since measuring an anti-Hermitian operator doesn't have well defined semantics.\n\n    Using overly-complicated Hermitian products, like saying `MPP X1*Y1*Y2*Z2` instead of\n    `MPP !Z1*X2`, is technically allowed. But probably not a great idea since tools consuming\n    the circuit may have assumed that each qubit would appear at most once in each product.\n\nExamples:\n\n    # Measure the two-body +X1*Y2 observable.\n    MPP X1*Y2\n\n    # Measure the one-body -Z5 observable.\n    MPP !Z5\n\n    # Measure the two-body +X1*Y2 observable and also the three-body -Z3*Z4*Z5 observable.\n    MPP X1*Y2 !Z3*Z4*Z5\n\n    # Noisily measure +Z1+Z2 and +X1*X2 (independently flip each reported result 0.1% of the time).\n    MPP(0.001) Z1*Z2 X1*X2\n\nStabilizer Generators (for `MPP X0*Y1*Z2 X3*X4`):\n\n    XYZ__ -> rec[-2]\n    ___XX -> rec[-1]\n    X____ -> X____\n    _Y___ -> _Y___\n    __Z__ -> __Z__\n    ___X_ -> ___X_\n    ____X -> ____X\n    ZZ___ -> ZZ___\n    _XX__ -> _XX__\n    ___ZZ -> ___ZZ\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `MPP X0*Y1*Z2 X3*X4`\n    S 1 1 1\n    H 0 1 3 4\n    CX 2 0 1 0 4 3\n    M 0 3\n    CX 2 0 1 0 4 3\n    H 0 1 3 4\n    S 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `MPP X0*Y1*Z2 X3*X4` (but affects the measurement record and an ancilla qubit)\n    MY 5\n    MZZ 1 5\n    MX 5\n    MZZ 0 5\n    MXX 1 5\n    MZ 5\n    MX 5\n    MZZ 1 5\n    MY 5\n    MZ 5\n    MXX 2 5\n    MY 5\n    MZZ 2 5\n    MX 5\n    MXX 0 2\n    MXX 3 4\n    MX 5\n    MZZ 2 5\n    MY 5\n    MXX 2 5\n    MZ 5\n    MY 5\n    MZZ 1 5\n    MX 5\n    MZZ 0 5\n    MXX 1 5\n    MZ 5\n    MX 5\n    MZZ 1 5\n    MY 5\n    CX rec[-21] 2 rec[-20] 2 rec[-11] 2 rec[-10] 2\n    CY rec[-27] 1 rec[-25] 1 rec[-6] 1 rec[-4] 1 rec[-18] 2 rec[-13] 2\n    CZ rec[-28] 0 rec[-28] 1 rec[-26] 0 rec[-24] 0 rec[-24] 1 rec[-23] 0 rec[-23] 1 rec[-22] 0 rec[-22] 1 rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-30] 1 rec[-29] 1 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1 rec[-19] 2 rec[-12] 2\n                \n\n<a name=\"SPP\"></a>\n### The 'SPP' Gate\n\nThe generalized S gate. Phases the -1 eigenspace of Pauli product observables by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    A series of Pauli products to phase.\n\n    Each Pauli product is a series of Pauli targets (like `X1`, `Y2`, or `Z3`) separated by\n    combiners (`*`). Each Pauli term can be inverted (like `!Y2` instead of `Y2`), to negate\n    the product.\n\n    Note that, although you can write down instructions that phase anti-Hermitian products,\n    like `SPP X1*Z1`, doing this will cause exceptions when you simulate or analyze the\n    circuit since phasing an anti-Hermitian operator doesn't have well defined semantics.\n\n    Using overly-complicated Hermitian products, like saying `SPP X1*Y1*Y2*Z2` instead of\n    `SPP !Z1*X2`, is technically allowed. But probably not a great idea since tools consuming\n    the circuit may have assumed that each qubit would appear at most once in each product.\n\nExamples:\n\n    # Perform an S gate on qubit 1.\n    SPP Z1\n\n    # Perform a SQRT_X gate on qubit 1.\n    SPP X1\n\n    # Perform a SQRT_X_DAG gate on qubit 1.\n    SPP !X1\n\n    # Perform a SQRT_XX gate between qubit 1 and qubit 2.\n    SPP X1*X2\n\n    # Perform a SQRT_YY gate between qubit 1 and 2, and a SQRT_ZZ_DAG between qubit 3 and 4.\n    SPP Y1*Y2 !Z1*Z2\n\n    # Phase the -1 eigenspace of -X1*Y2*Z3 by i.\n    SPP !X1*Y2*Z3\n\nStabilizer Generators (for `SPP X0*Y1*Z2`):\n\n    X__ -> X__\n    Z__ -> -YYZ\n    _X_ -> -XZZ\n    _Z_ -> XXZ\n    __X -> XYY\n    __Z -> __Z\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SPP X0*Y1*Z2`\n    CX 2 1\n    CX 1 0\n    S 1\n    S 1\n    H 1\n    CX 1 0\n    CX 2 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SPP X0*Y1*Z2` (but affects the measurement record and an ancilla qubit)\n    MY 3\n    MZZ 1 3\n    MX 3\n    MZZ 0 3\n    MXX 1 3\n    MZ 3\n    MX 3\n    MZZ 1 3\n    MY 3\n    MZ 3\n    MXX 0 3\n    MY 3\n    MZZ 0 3\n    MX 3\n    MZZ 2 3\n    MXX 0 3\n    MZ 3\n    MX 3\n    MZZ 0 3\n    MY 3\n    MXX 0 3\n    MZ 3\n    MXX 0 3\n    MY 3\n    MZ 3\n    MXX 0 3\n    MY 3\n    MZZ 0 3\n    MX 3\n    MZZ 2 3\n    MXX 0 3\n    MZ 3\n    MX 3\n    MZZ 0 3\n    MY 3\n    MXX 0 3\n    MZ 3\n    MY 3\n    MZZ 1 3\n    MX 3\n    MZZ 0 3\n    MXX 1 3\n    MZ 3\n    MX 3\n    MZZ 1 3\n    MY 3\n    X 0\n    Y 1\n    Z 2\n    CX rec[-46] 0 rec[-46] 1 rec[-45] 0 rec[-45] 1 rec[-37] 0 rec[-36] 0 rec[-26] 0 rec[-24] 0 rec[-23] 0 rec[-22] 0 rec[-21] 0 rec[-11] 0 rec[-10] 0\n    CY rec[-42] 0 rec[-42] 1 rec[-37] 1 rec[-36] 1 rec[-35] 0 rec[-35] 1 rec[-32] 0 rec[-32] 1 rec[-30] 0 rec[-30] 1 rec[-27] 0 rec[-27] 1 rec[-26] 1 rec[-24] 1 rec[-23] 1 rec[-22] 1 rec[-21] 1 rec[-19] 0 rec[-19] 1 rec[-18] 0 rec[-18] 1 rec[-14] 0 rec[-14] 1 rec[-13] 0 rec[-13] 1 rec[-11] 1 rec[-10] 1 rec[-43] 1 rec[-41] 1 rec[-6] 1 rec[-4] 1\n    CZ rec[-44] 0 rec[-44] 1 rec[-42] 2 rec[-40] 0 rec[-40] 1 rec[-39] 0 rec[-39] 1 rec[-38] 0 rec[-38] 1 rec[-35] 2 rec[-34] 0 rec[-34] 2 rec[-33] 0 rec[-32] 2 rec[-30] 2 rec[-29] 0 rec[-28] 0 rec[-27] 2 rec[-20] 0 rec[-19] 2 rec[-17] 0 rec[-15] 0 rec[-12] 0 rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-26] 2 rec[-24] 2 rec[-23] 2 rec[-22] 2 rec[-21] 2 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1 rec[-46] 2 rec[-45] 2 rec[-31] 2 rec[-16] 2\n                \n\n<a name=\"SPP_DAG\"></a>\n### The 'SPP_DAG' Gate\n\nThe generalized S_DAG gate. Phases the -1 eigenspace of Pauli product observables by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    A series of Pauli products to phase.\n\n    Each Pauli product is a series of Pauli targets (like `X1`, `Y2`, or `Z3`) separated by\n    combiners (`*`). Each Pauli term can be inverted (like `!Y2` instead of `Y2`), to negate\n    the product.\n\n    Note that, although you can write down instructions that phase anti-Hermitian products,\n    like `SPP X1*Z1`, doing this will cause exceptions when you simulate or analyze the\n    circuit since phasing an anti-Hermitian operator doesn't have well defined semantics.\n\n    Using overly-complicated Hermitian products, like saying `SPP X1*Y1*Y2*Z2` instead of\n    `SPP !Z1*X2`, is technically allowed. But probably not a great idea since tools consuming\n    the circuit may have assumed that each qubit would appear at most once in each product.\n\nExamples:\n\n    # Perform an S_DAG gate on qubit 1.\n    SPP_DAG Z1\n\n    # Perform a SQRT_X_DAG gate on qubit 1.\n    SPP_DAG X1\n\n    # Perform a SQRT_X gate on qubit 1.\n    SPP_DAG !X1\n\n    # Perform a SQRT_XX_DAG gate between qubit 1 and qubit 2.\n    SPP_DAG X1*X2\n\n    # Perform a SQRT_YY_DAG gate between qubit 1 and 2, and a SQRT_ZZ between qubit 3 and 4.\n    SPP_DAG Y1*Y2 !Z1*Z2\n\n    # Phase the -1 eigenspace of -X1*Y2*Z3 by -i.\n    SPP_DAG !X1*Y2*Z3\n\nStabilizer Generators (for `SPP_DAG X0*Y1*Z2`):\n\n    X__ -> X__\n    Z__ -> YYZ\n    _X_ -> XZZ\n    _Z_ -> -XXZ\n    __X -> -XYY\n    __Z -> __Z\n    \nDecomposition (into H, S, CX, M, R):\n\n    # The following circuit is equivalent (up to global phase) to `SPP_DAG X0*Y1*Z2`\n    CX 2 1\n    CX 1 0\n    H 1\n    S 1\n    S 1\n    CX 1 0\n    CX 2 1\n    \nMBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\n\n    # The following circuit performs `SPP_DAG X0*Y1*Z2` (but affects the measurement record and an ancilla qubit)\n    MY 3\n    MZZ 1 3\n    MX 3\n    MZZ 0 3\n    MXX 1 3\n    MZ 3\n    MX 3\n    MZZ 1 3\n    MY 3\n    MZ 3\n    MXX 0 3\n    MY 3\n    MZZ 0 3\n    MX 3\n    MZZ 2 3\n    MXX 0 3\n    MZ 3\n    MX 3\n    MZZ 0 3\n    MY 3\n    MXX 0 3\n    MZ 3\n    MXX 0 3\n    MY 3\n    MZ 3\n    MXX 0 3\n    MY 3\n    MZZ 0 3\n    MX 3\n    MZZ 2 3\n    MXX 0 3\n    MZ 3\n    MX 3\n    MZZ 0 3\n    MY 3\n    MXX 0 3\n    MZ 3\n    MY 3\n    MZZ 1 3\n    MX 3\n    MZZ 0 3\n    MXX 1 3\n    MZ 3\n    MX 3\n    MZZ 1 3\n    MY 3\n    CX rec[-46] 0 rec[-46] 1 rec[-45] 0 rec[-45] 1 rec[-37] 0 rec[-36] 0 rec[-26] 0 rec[-24] 0 rec[-23] 0 rec[-22] 0 rec[-21] 0 rec[-11] 0 rec[-10] 0\n    CY rec[-42] 0 rec[-42] 1 rec[-37] 1 rec[-36] 1 rec[-35] 0 rec[-35] 1 rec[-32] 0 rec[-32] 1 rec[-30] 0 rec[-30] 1 rec[-27] 0 rec[-27] 1 rec[-26] 1 rec[-24] 1 rec[-23] 1 rec[-22] 1 rec[-21] 1 rec[-19] 0 rec[-19] 1 rec[-18] 0 rec[-18] 1 rec[-14] 0 rec[-14] 1 rec[-13] 0 rec[-13] 1 rec[-11] 1 rec[-10] 1 rec[-43] 1 rec[-41] 1 rec[-6] 1 rec[-4] 1\n    CZ rec[-44] 0 rec[-44] 1 rec[-42] 2 rec[-40] 0 rec[-40] 1 rec[-39] 0 rec[-39] 1 rec[-38] 0 rec[-38] 1 rec[-35] 2 rec[-34] 0 rec[-34] 2 rec[-33] 0 rec[-32] 2 rec[-30] 2 rec[-29] 0 rec[-28] 0 rec[-27] 2 rec[-20] 0 rec[-19] 2 rec[-17] 0 rec[-15] 0 rec[-12] 0 rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-26] 2 rec[-24] 2 rec[-23] 2 rec[-22] 2 rec[-21] 2 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1 rec[-46] 2 rec[-45] 2 rec[-31] 2 rec[-16] 2\n                \n\n## Control Flow\n\n<a name=\"REPEAT\"></a>\n### The 'REPEAT' Instruction\n\nRepeats the instructions in its body N times.\n\nCurrently, repetition counts of 0 are not allowed because they create corner cases with ambiguous resolutions.\nFor example, if a logical observable is only given measurements inside a repeat block with a repetition count of 0, it's\nambiguous whether the output of sampling the logical observables includes a bit for that logical observable.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    A positive integer in [1, 10^18] specifying the number of repetitions.\n\nExample:\n\n    REPEAT 2 {\n        CNOT 0 1\n        CNOT 2 1\n        M 1\n    }\n    REPEAT 10000000 {\n        CNOT 0 1\n        CNOT 2 1\n        M 1\n        DETECTOR rec[-1] rec[-3]\n    }\n\n## Annotations\n\n<a name=\"DETECTOR\"></a>\n### The 'DETECTOR' Instruction\n\nAnnotates that a set of measurements can be used to detect errors, because the set's parity should be deterministic.\n\nNote that it is not necessary to say whether the measurement set's parity is even or odd; all that matters is that the\nparity should be *consistent* when running the circuit and omitting all noisy operations. Note that, for example, this\nmeans that even though `X` and `X_ERROR(1)` have equivalent effects on the measurements making up a detector, they have\ndiffering effects on the detector (because `X` is intended, determining the expected value, and `X_ERROR` is noise,\ncausing deviations from the expected value).\n\nDetectors are ignored when sampling measurements, but produce results when sampling detection events. In detector\nsampling mode, each detector produces a result bit (where 0 means \"measurement set had expected parity\" and 1 means\n\"measurement set had incorrect parity\"). When converting a circuit into a detector error model, errors are grouped based\non the detectors they flip (the \"symptoms\" of the error) and the observables they flip (the \"frame changes\" of the\nerror).\n\nIt is permitted, though not recommended, for the measurement set given to a `DETECTOR` instruction to have inconsistent\nparity. When a detector's measurement set is inconsistent, the detector is called a \"gauge detector\" and the expected\nparity of the measurement set is chosen arbitrarily (in an implementation-defined way). Some circuit analysis tools\n(such as the circuit-to-detector-error-model conversion) will by default refuse to process circuits containing gauge\ndetectors. Gauge detectors produce random results when sampling detection events, though these results will be\nappropriately correlated with other gauge detectors. For example, if `DETECTOR rec[-1]` and `DETECTOR rec[-2]` are gauge\ndetectors but `DETECTOR rec[-1] rec[-2]` is not, then under noiseless execution the two gauge detectors would either\nalways produce the same result or always produce opposite results.\n\nDetectors can specify coordinates using their parens arguments. Coordinates have no effect on simulations, but can be\nuseful to tools consuming the circuit. For example, a tool drawing how the detectors in a circuit relate to each other\ncan use the coordinates as hints for where to place the detectors in the drawing.\n\nParens Arguments:\n\n    Optional.\n    Coordinate metadata, relative to the current coordinate offset accumulated from `SHIFT_COORDS` instructions.\n    Can be any number of coordinates from 1 to 16.\n    There is no required convention for which coordinate is which.\n\nTargets:\n\n    The measurement records to XOR together to get the deterministic-under-noiseless-execution parity.\n\nExample:\n\n    R 0\n    X_ERROR(0.1) 0\n    M 0  # This measurement is always False under noiseless execution.\n    # Annotate that most recent measurement should be deterministic.\n    DETECTOR rec[-1]\n\n    R 0\n    X 0\n    X_ERROR(0.1) 0\n    M 0  # This measurement is always True under noiseless execution.\n    # Annotate that most recent measurement should be deterministic.\n    DETECTOR rec[-1]\n\n    R 0 1\n    H 0\n    CNOT 0 1\n    DEPOLARIZE2(0.001) 0 1\n    M 0 1  # These two measurements are always equal under noiseless execution.\n    # Annotate that the parity of the previous two measurements should be consistent.\n    DETECTOR rec[-1] rec[-2]\n\n    # A series of trivial detectors with hinted coordinates along the diagonal line Y = 2X + 3.\n    REPEAT 100 {\n        R 0\n        M 0\n        SHIFT_COORDS(1, 2)\n        DETECTOR(0, 3) rec[-1]\n    }\n\n<a name=\"MPAD\"></a>\n### The 'MPAD' Instruction\n\nPads the measurement record with the listed measurement results.\n\nThis can be useful for ensuring measurements are aligned to word boundaries, or that the\nnumber of measurement bits produced per circuit layer is always the same even if the number\nof measured qubits varies.\n\nParens Arguments:\n\n    If no parens argument is given, the padding bits are recorded perfectly.\n    If one parens argument is given, the padding bits are recorded noisily.\n    The argument is the probability of recording the wrong result.\n\nTargets:\n\n    Each target is a measurement result to add.\n    Targets should be the value 0 or the value 1.\n\nExamples:\n\n    # Append a False result to the measurement record.\n    MPAD 0\n\n    # Append a True result to the measurement record.\n    MPAD 1\n\n    # Append a series of results to the measurement record.\n    MPAD 0 0 1 0 1\n\n<a name=\"OBSERVABLE_INCLUDE\"></a>\n### The 'OBSERVABLE_INCLUDE' Instruction\n\nAdds measurement records to a specified logical observable.\n\nA potential point of confusion here is that Stim's notion of a logical observable is nothing more than a set of\nmeasurements, potentially spanning across the entire circuit, that together produce a deterministic result. It's more\nakin to the \"boundary of a parity sheet\" in a topological spacetime diagram than it is to the notion of a qubit\nobservable. For example, consider a surface code memory experiment that initializes a logical |0>, preserves the state\nnoise, and eventually performs a logical Z basis measurement. The circuit representing this experiment would use\n`OBSERVABLE_INCLUDE` instructions to specifying which physical measurements within the logical Z basis measurement\nshould be XOR'd together to get the logical measurement result. This effectively identifies the logical Z observable.\nBut the circuit would *not* declare an X observable, because the X observable is not deterministic in a Z basis memory\nexperiment; it has no corresponding deterministic measurement set.\n\nLogical observables are ignored when sampling measurements, but can produce results (if requested) when sampling\ndetection events. In detector sampling mode, each observable can produce a result bit (where 0 means \"measurement set\nhad expected parity\" and 1 means \"measurement set had incorrect parity\"). When converting a circuit into a detector\nerror model, errors are grouped based on the detectors they flip (the \"symptoms\" of the error) and the observables they\nflip (the \"frame changes\" of the error).\n\nAnother potential point of confusion is that when sampling logical measurement results, as part of sampling detection\nevents in the circuit, the reported results are not measurements of the logical observable but rather whether those\nmeasurement results *were flipped*. This has significant simulation speed benefits, and also makes it so that it is not\nnecessary to say whether the logical measurement result is supposed to be False or True. Note that, for example, this\nmeans that even though `X` and `X_ERROR(1)` have equivalent effects on the measurements making up an observable, they\nhave differing effects on the reported value of an observable when sampling detection events (because `X` is intended,\ndetermining the expected value, and `X_ERROR` is noise, causing deviations from the expected value).\n\nIt is not recommended for the measurement set of an observable to have inconsistent parity. For example, the\ncircuit-to-detector-error-model conversion will refuse to operate on circuits containing such observables.\n\nIn addition to targeting measurements, observables can target Pauli operators. This has no effect when running the\nquantum computation, but is used when configuring the decoder. For example, when performing a logical Z initialization,\nit allows a logical X operator to be introduced (by marking its Pauli terms) despite the fact that it anticommutes\nwith the initialization. In practice, when physically sampling a circuit or simulating sampling its measurements and\nthen computing the observables from the measurements, these Pauli terms are effectively ignored. However, they affect\ndetection event simulations and affect whether the observable is included in errors in the detector error model. This\nmakes it easier to benchmark all observables of a code, without having to introduce noiseless qubits entangled with the\nlogical qubit to avoid the testing of the X observable anticommuting with the testing of the Z observable.\n\nUnlike a `DETECTOR` instruction which provides a complete description of a detector by listing all its constituent\nmeasurement records, an individual `OBSERVABLE_INCLUDE` instruction is not required to (and generally does not) fully\ndescribe a logical observable. Instead, measurement records or Pauli targets are added to it incrementally. A logical\nobservable can be given both types of description: as a collection of Pauli targets and as a collection of measurement\nrecord targets.\n\nParens Arguments:\n\n    A non-negative integer specifying the index of the logical observable to add the measurement records to.\n\nTargets:\n\n    The measurement records or Pauli terms to add to the specified observable.\n\nExample:\n\n    R 0 1\n    H 0\n    CNOT 0 1\n    M 0 1\n    # Observable 0 is the parity of the previous two measurements.\n    OBSERVABLE_INCLUDE(0) rec[-1] rec[-2]\n\n    R 0 1\n    H 0\n    CNOT 0 1\n    M 0 1\n    # Observable 1 is the parity of the previous measurement...\n    OBSERVABLE_INCLUDE(1) rec[-1]\n    # ...and the one before that.\n    OBSERVABLE_INCLUDE(1) rec[-2]\n\n    # Unphysically tracking two anticommuting observables of a 2x2 surface code.\n    QUBIT_COORDS(0, 0) 0\n    QUBIT_COORDS(1, 0) 1\n    QUBIT_COORDS(0, 1) 2\n    QUBIT_COORDS(1, 1) 3\n    OBSERVABLE_INCLUDE(0) X0 X1\n    OBSERVABLE_INCLUDE(1) Z0 Z2\n    MPP X0*X1*X2*X3 Z0*Z1 Z2*Z3\n    DEPOLARIZE1(0.001) 0 1 2 3\n    MPP X0*X1*X2*X3 Z0*Z1 Z2*Z3\n    DETECTOR rec[-1] rec[-4]\n    DETECTOR rec[-2] rec[-5]\n    DETECTOR rec[-3] rec[-6]\n    OBSERVABLE_INCLUDE(0) X0 X1\n    OBSERVABLE_INCLUDE(1) Z0 Z2\n\n    # Stim circuit may include a description of an observable in terms of Pauli targets\n    # alongside a description in terms of measurement records.\n    OBSERVABLE_INCLUDE(0) Z0 Z1\n    M 0 1\n    OBSERVABLE_INCLUDE(0) rec[-2] rec[-1]\n\n<a name=\"QUBIT_COORDS\"></a>\n### The 'QUBIT_COORDS' Instruction\n\nAnnotates the location of a qubit.\n\nCoordinates are not required and have no effect on simulations, but can be useful to tools consuming the circuit. For\nexample, a tool drawing the circuit  can use the coordinates as hints for where to place the qubits in the drawing.\n`stimcirq` uses `QUBIT_COORDS` instructions to preserve `cirq.LineQubit` and `cirq.GridQubit` coordinates when\nconverting between stim circuits and cirq circuits\n\nA qubit's coordinates can be specified multiple times, with the intended interpretation being that the qubit is at the\nlocation of the most recent assignment. For example, this could be used to indicate a simulated qubit is iteratively\nplaying the role of many physical qubits.\n\nParens Arguments:\n\n    Optional.\n    The latest coordinates of the qubit, relative to accumulated offsets from `SHIFT_COORDS` instructions.\n    Can be any number of coordinates from 1 to 16.\n    There is no required convention for which coordinate is which.\n\nTargets:\n\n    The qubit or qubits the coordinates apply to.\n\nExample:\n\n    # Annotate that qubits 0 to 3 are at the corners of a square.\n    QUBIT_COORDS(0, 0) 0\n    QUBIT_COORDS(0, 1) 1\n    QUBIT_COORDS(1, 0) 2\n    QUBIT_COORDS(1, 1) 3\n\n<a name=\"SHIFT_COORDS\"></a>\n### The 'SHIFT_COORDS' Instruction\n\nAccumulates offsets that affect qubit coordinates and detector coordinates.\n\nNote: when qubit/detector coordinates use fewer dimensions than SHIFT_COORDS, the offsets from the additional dimensions\nare ignored (i.e. not specifying a dimension is different from specifying it to be 0).\n\nSee also: `QUBIT_COORDS`, `DETECTOR`.\n\nParens Arguments:\n\n    Offsets to add into the current coordinate offset.\n    Can be any number of coordinate offsets from 1 to 16.\n    There is no required convention for which coordinate is which.\n\nTargets:\n\n    This instruction takes no targets.\n\nExample:\n\n    SHIFT_COORDS(500.5)\n    QUBIT_COORDS(1510) 0  # Actually at 2010.5\n    SHIFT_COORDS(1500)\n    QUBIT_COORDS(11) 1    # Actually at 2011.5\n    QUBIT_COORDS(10.5) 2  # Actually at 2011.0\n\n    # Declare some detectors with coordinates along a diagonal line.\n    REPEAT 1000 {\n        CNOT 0 2\n        CNOT 1 2\n        MR 2\n        DETECTOR(10.5, 0) rec[-1] rec[-2]  # Actually at (2011.0, iteration_count).\n        SHIFT_COORDS(0, 1)  # Advance 2nd coordinate to track loop iterations.\n    }\n\n<a name=\"TICK\"></a>\n### The 'TICK' Instruction\n\nAnnotates the end of a layer of gates, or that time is advancing.\n\nThis instruction is not necessary, it has no effect on simulations, but it can be used by tools that are transforming or\nvisualizing the circuit. For example, a tool that adds noise to a circuit may include cross-talk terms that require\nknowing whether or not operations are happening in the same time step or not.\n\nTICK instructions are added, and checked for, by `stimcirq` in order to preserve the moment structure of cirq circuits\nconverted between stim circuits and cirq circuits.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    This instruction takes no targets.\n\nExample:\n\n    # First time step.\n    H 0\n    CZ 1 2\n    TICK\n\n    # Second time step.\n    H 1\n    TICK\n\n    # Empty time step.\n    TICK\n\n"
  },
  {
    "path": "doc/getting_started.ipynb",
    "content": "{\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"7vg1S92NEAXs\"\n      },\n      \"source\": [\n        \"<img style=\\\"float:right\\\" width=\\\"65px\\\" align=\\\"right\\\" src=\\\"https://raw.githubusercontent.com/quantumlib/Stim/refs/heads/main/doc/logo_128x128.svg\\\">\\n\",\n        \"<h1>Welcome to the Stim tutorial!</h1>\\n\",\n        \"\\n\",\n        \"This Jupyter notebook is a tutorial for [Stim](https://github.com/quantumlib/stim), a tool for high-performance simulation and analysis of quantum stabilizer circuits. You can run this notebook in your browser using [Google Colab](https://colab.google/), or download it to your computer and run it using [Jupyter](https://docs.jupyter.org/en/latest/running.html).\\n\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"0V2LXIBKKqA9\"\n      },\n      \"source\": [\n        \"# Table of contents\\n\",\n        \"\\n\",\n        \"0. [Prerequisites](#prerequisites)\\n\",\n        \"1. [What is Stim?](#what-is-stim)\\n\",\n        \"2. [Copy and use this Jupyter/Colab notebook](#using-this-notebook)\\n\",\n        \"3. [Install the `stim` Python package](#install-stim)\\n\",\n        \"4. [Create a simple circuit, and sample from it](#make-circuit)\\n\",\n        \"5. [Add detector annotations to a circuit, and sample them](#sample-detectors)\\n\",\n        \"6. [Generate example error correction circuits](#make-qec-circuits)\\n\",\n        \"7. [Use `pymatching` to correct errors in a circuit](#use-pymatching)\\n\",\n        \"8. [Estimate the threshold of a repetition code using Monte Carlo sampling](#rep-code)\\n\",\n        \"9. [Use `sinter` to streamline the Monte Carlo sampling process](#use-sinter)\\n\",\n        \"10. [Estimate the threshold and footprint of a surface code](#surface-code)\\n\",\n        \"11. [Conclusion](#end-of-tutorial)\\n\",\n        \"12. [Additional resources](additional-resources)\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"43rMSrBhKtyX\"\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"prerequisites\\\"></a>\\n\",\n        \"# 0. Prerequisites\\n\",\n        \"\\n\",\n        \"To get the most out of this tutorial, it's helpful to have the following background:\\n\",\n        \"\\n\",\n        \"- Familiarity with basic Python syntax, and having a working Python 3.7+ environment. (Perhaps you are reading this notebook in such an environment.)\\n\",\n        \"\\n\",\n        \"- Familiarity with the basic concepts of *quantum circuits*, such as qubits and common quantum gates like [Hadamard](https://en.wikipedia.org/wiki/Quantum_logic_gate#Hadamard_gate) and [CNOT](https://en.wikipedia.org/wiki/Quantum_logic_gate#Controlled_gates).\\n\",\n        \"\\n\",\n        \"- A basic understanding of stabilizer circuits. For example, this tutorial assumes you've heard that they can be simulated cheaply and that they can represent protocols such as quantum error correction.\\n\",\n        \"\\n\",\n        \"- *Some* familiarity with quantum error-correcting codes. For example, this tutorial assumes that you've heard the terms \\\"surface code\\\" and \\\"threshold\\\".\\n\",\n        \"\\n\",\n        \"If you don't have these prerequisites yet, take a look at the [additional resources](additional-resources) at the end of this tutorial for suggestions about how to learn more.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"ulLKqhVxmfxr\",\n        \"jp-MarkdownHeadingCollapsed\": true\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"what-is-stim\\\"></a>\\n\",\n        \"# 1. What is Stim?\\n\",\n        \"\\n\",\n        \"Stim is an [open-source tool](https://github.com/quantumlib/Stim) for high-performance analysis and simulation of quantum stabilizer circuits, with a focus on quantum error correction circuits.\\n\",\n        \"\\n\",\n        \"Here is a plot from the [paper introducing Stim](https://doi.org/10.22331/q-2021-07-06-497), showing that Stim is thousands of times faster than other tools at sampling stabilizer circuits:\\n\",\n        \"\\n\",\n        \"![image.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABEMAAAKMCAIAAACPUOHuAAAgAElEQVR4Aeydd1QUyRfv3V12BUUFyTnnDEN2BMkgSXJWQcRAUKKAoosiEhQRRURYEQVRkuQgougqKqIgioqikuMQB2aGSe8865x+8wZ1w29//mStPv7RDt3Vtz5V01PfqntvLaPCAxKABCABSAASgAQgAUgAEoAEIIGlRmDZUjMY2gsJQAKQACQACUACkAAkAAlAApAAFSoZ2AkgAUgAEoAEIAFIABKABCABSGDpEYBKZum1GbQYEoAEIAFIABKABCABSAASgASgkoF9ABKABCABSAASgAQgAUgAEoAElh4BqGSWXptBiyEBSAASgAQgAUgAEoAEIAFIACoZ2AcgAUgAEoAEIAFIABKABCABSGDpEYBKZum1GbQYEoAEIAFIABKABCABSAASgASgkoF9ABKABCABSAASgAQgAUgAEoAElh4BqGSWXptBiyEBSAASgAQgAUgAEoAEIAFIACoZ2AcgAUgAEoAEIAFIABKABCABSGDpEYBKZum1GbQYEoAEIAFIABKABCABSAASgASgkoF9ABKABCABSAASgAQgAUgAEoAElh4BqGSWXptBiyEBSAASgAQgAUgAEoAEIAFIACoZ2AcgAUgAEoAEIAFIABKABCABSGDpEYBKZum12Xdo8cjISFlZmdWfO+Li4urq6qytrePj41+8ePEt4CISiW/fvm1qaqJQKP8NeyYmJq5cubJ9+/ba2trF5ZNIpKmpqatXr0ZERHh4eLi4uOzZs6esrGxgYIDuYgKB8OHDh4yMjICAAFdXVy8vr5iYmKampunpaborSSTSu3fvLl68uGvXLmdnZ09Pz5iYmOrqajweD+o4Pz//5MkTOzs7T0/P+vp65Paenp7nz5/39vaCTwYGBpKTk/38/AoKChYWFpDL/t0nz58/j4iI2LRp06NHj0gk0j9S2ZGRkWvXru3evdvBwcHNzS03N/f9+/f/SMnfWiEUCoVAIDx48ODly5d/z7bp6ekXL160tbX9vdsX30UkEoeGhry9vUNCQhobGxdf8PU/mZ6evn//flhYmIuLi7Ozc3x8/JMnT76+Gf/bJ5LJ5Pb29ujo6IiIiLt37341Y8hkclRUlI+PT15e3ld7KHjQ/v37vb29L126hDx3dna2q6vr0aNHZDIZ+RCeQAL/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MjIOHDiwZs2aBw8e+Pn5LVu2zM7ObuHChT4+PllZWZ0BVlVVXb58ecOGDXZ2dvPnz/f39z9w4EDneTKiKJaXlwcGBq5du3bOnDmzZ892dHQ8evRoaWkpy7L6V5HjuM2bN3/++efbt2/XRwcnIAACIGAlBKBkrCTQcHMIEdi+ffvvf//78ePHUxQlimL3lhEEUVVV1draqhv43tjYmJCQsGjRos8+++zzzz8fN27cF1988cEHH8ydO/fChQv6b1o5OTlubm4TJkz4+OOPbWxsvvrqq9mzZ0+YMOHNN9/86quvdDP+NRpNcnLyqlWrvmg7vvrqq/Hjx3/66affffddREREbW1t98borpSXlwcHB0+dOnXEiBFjx4796quvpk+fPmvWrDfeeOPzzz/XzfgvKCj4xz/+8cknn4SFhUmSVFdXd+jQocmTJ48dO3bKlCmTJ08eNWrU6NGj9+3b9/Tp07q6Om9v79GjR7/22mu/+93vvvvuOx8fn/Ly8oKCgmPHjk2ePHnMmDGTJk2aOHHiZ5999t57740dOzYyMrKmpkar1RYVFX3adtja2trb2y9cuNDe3l7n0fbt2/Pz83XcGIZJTk5ev379p59++sUXX0ycOHHChAkjR46cN29eXFxcU1MTz/NlZWVubm6TJk0aNWqUDtrIkSMnT57s7e3dxxoJGo3m5MmTv//97zdv3qwbWpabm7tz585///d/P3LkiG7hKYIgoqOj33///TfeeGPDhg1S26HVak+dOjVmzJiJEyc2NDT4+/t/8sknX3/9tU5vNDU1hYWFzZ49e8SIEV9++eXEiROnTp06adKkjz766Be/+EVsbGx2dra3t/enn376s5/97N13350+ffrRo0f1Suaf//zn4sWLJ02aNGHChI8++mjEiBHz5s27ceOGTln8YZ1RAAAgAElEQVRFRUXNnj1bx637f6dOnern56dXMm+99ZaNjc3UqVN14fvb3/72ySefrFu3rqSkRPddvL6+Pjo6et68eV988cXYsWMnTpw4bty4Tz/9dNWqVbGxsTRN62b829jY/Otf/zp16pTuLUpJSXFycho9evQ///lPGxubL7/8cubMmVOnTn3jjTcWL16cmZmpUzI///nPP/vsM1tb2ylTpuhC9qc//WnKlCmhoaGtra3Nzc3r169/9913X3/99T/+8Y8LFiyIiop6+PDh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)\\n\",\n        \"\\n\",\n        \"In addition to fast simulation, Stim provides general utilities for editing, inspecting, and transforming stabilizer circuits. In particular, Stim can automatically derive a matching graph from a stabilizer circuit annotated with detectors and noise channels.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"fh8rot1PYyDh\"\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"install-stim\\\"></a>\\n\",\n        \"# 2. Install the Stim python package\\n\",\n        \"\\n\",\n        \"The first thing to do is to install and import Stim.\\n\",\n        \"Thanks to the Python ecosystem, this is easy to do!\\n\",\n        \"Stim is available as a [PyPI](https://pypi.org/project/stim/) package, and can be installed using `pip install stim` and then imported with `import stim` (just like any other Python package).\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"fMf_vlB7D6fR\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!pip install stim~=1.14\\n\",\n        \"!pip install numpy~=1.0  # 1.0 instead of 2.0 for pymatching compatibility later\\n\",\n        \"!pip install scipy\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"P0lD6ilJD8Pi\",\n        \"outputId\": \"79a7cd42-9677-46f7-df1e-1cd4a518f601\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"1.14.0\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"import stim\\n\",\n        \"print(stim.__version__)\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"vah6-5YpGdaG\"\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"make-circuit\\\"></a>\\n\",\n        \"# 3. Create a simple circuit, and sample from it\\n\",\n        \"\\n\",\n        \"In Stim, circuits are instances of the [`stim.Circuit`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit) class. You create a new empty circuit with `stim.Circuit()`, and add operations to it by calling `circuit.append(name_of_gate, list_of_targets)`.\\n\",\n        \"\\n\",\n        \"You can find the name of the gate you want from the [Stim gates reference](https://github.com/quantumlib/Stim/blob/main/doc/gates.md). Most of the names are straightforward, like \\\"H\\\" for the Hadamard gate. A *target* is just a number representing the identity of a qubit. There's a qubit `0`, a qubit `1`, etc.\\n\",\n        \"\\n\",\n        \"The first circuit you'll make is a circuit that prepares a [Bell pair](https://en.wikipedia.org/wiki/Bell_state) and then measures it:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"UP84FdeWGodO\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"circuit = stim.Circuit()\\n\",\n        \"\\n\",\n        \"# First, the circuit will initialize a Bell pair.\\n\",\n        \"circuit.append(\\\"H\\\", [0])\\n\",\n        \"circuit.append(\\\"CNOT\\\", [0, 1])\\n\",\n        \"\\n\",\n        \"# Then, the circuit will measure both qubits of the Bell pair in the Z basis.\\n\",\n        \"circuit.append(\\\"M\\\", [0, 1])\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"ySG_dqfQ-qOQ\"\n      },\n      \"source\": [\n        \"Stim has a few ways to let you look at the circuits you've made. The circuit's `repr` is an expression that recreates the circuit using [Stim's circuit file syntax](https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md):\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"L51yrzUW-qOQ\",\n        \"outputId\": \"9b6d4b2f-1cb9-4941-d533-db148aaaf86f\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"text/plain\": [\n              \"stim.Circuit('''\\n\",\n              \"    H 0\\n\",\n              \"    CX 0 1\\n\",\n              \"    M 0 1\\n\",\n              \"''')\"\n            ]\n          },\n          \"execution_count\": 4,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"circuit\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"D-RpRUTw-qOQ\"\n      },\n      \"source\": [\n        \"You can also use the [`circuit.diagram`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.diagram) method to get an annotated text diagram of the circuit:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"_75gRftr-qOQ\",\n        \"outputId\": \"9b6d4b2f-1cb9-4941-d533-db148aaaf86f\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"text/html\": [\n              \"<pre>q0: -H-@-M:rec[0]-\\n\",\n              \"       |\\n\",\n              \"q1: ---X-M:rec[1]-</pre>\"\n            ],\n            \"text/plain\": [\n              \"q0: -H-@-M:rec[0]-\\n\",\n              \"       |\\n\",\n              \"q1: ---X-M:rec[1]-\"\n            ]\n          },\n          \"execution_count\": 5,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"circuit.diagram()\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"XKnYuBEB-qOQ\"\n      },\n      \"source\": [\n        \"There are also other types of diagrams. For example, specifying `timeline-svg` will return a Scalable Vector Graphics ([SVG](https://en.wikipedia.org/wiki/SVG)) picture of the circuit instead of a text diagram:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"NXlSD_sy-qOQ\",\n        \"outputId\": \"9b6d4b2f-1cb9-4941-d533-db148aaaf86f\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/svg+xml\": [\n              \"<svg viewBox=\\\"0 0 288 224\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"qubit_lines\\\">\\n\",\n              \"<path id=\\\"qubit_line:0\\\" d=\\\"M64,64 L256,64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"64\\\">q0</text>\\n\",\n              \"<path id=\\\"qubit_line:1\\\" d=\\\"M64,128 L256,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"128\\\">q1</text>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"64\\\">H</text>\\n\",\n              \"<path d=\\\"M160,64 L160,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"160\\\" cy=\\\"64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"160\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M148,128 L172,128 M160,116 L160,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"208\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"224\\\" y=\\\"64\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"224\\\" y=\\\"44\\\">rec[0]</text>\\n\",\n              \"<rect x=\\\"208\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"224\\\" y=\\\"128\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"224\\\" y=\\\"108\\\">rec[1]</text>\\n\",\n              \"</svg>\"\n            ],\n            \"text/plain\": [\n              \"<svg viewBox=\\\"0 0 288 224\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"qubit_lines\\\">\\n\",\n              \"<path id=\\\"qubit_line:0\\\" d=\\\"M64,64 L256,64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"64\\\">q0</text>\\n\",\n              \"<path id=\\\"qubit_line:1\\\" d=\\\"M64,128 L256,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"128\\\">q1</text>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"64\\\">H</text>\\n\",\n              \"<path d=\\\"M160,64 L160,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"160\\\" cy=\\\"64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"160\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M148,128 L172,128 M160,116 L160,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"208\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"224\\\" y=\\\"64\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"224\\\" y=\\\"44\\\">rec[0]</text>\\n\",\n              \"<rect x=\\\"208\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"224\\\" y=\\\"128\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"224\\\" y=\\\"108\\\">rec[1]</text>\\n\",\n              \"</svg>\"\n            ]\n          },\n          \"execution_count\": 6,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"circuit.diagram('timeline-svg')\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"5dRl_-WZHDP2\"\n      },\n      \"source\": [\n        \"Anyways, let's stop looking at your circuit and start using it. You can sample from the circuit by using the [`circuit.compile_sampler()`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.compile_sampler) method to get a sampler object, and then calling `sample` on that object.\\n\",\n        \"\\n\",\n        \"Try taking 10 shots from the circuit:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"sJVtzniUHL1X\",\n        \"outputId\": \"2b54c59c-0d0a-492f-fae7-87f4751f8415\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"[[False False]\\n\",\n            \" [ True  True]\\n\",\n            \" [False False]\\n\",\n            \" [False False]\\n\",\n            \" [ True  True]\\n\",\n            \" [False False]\\n\",\n            \" [ True  True]\\n\",\n            \" [False False]\\n\",\n            \" [False False]\\n\",\n            \" [ True  True]]\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"sampler = circuit.compile_sampler()\\n\",\n        \"print(sampler.sample(shots=10))\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"D5KUSysIJB5g\"\n      },\n      \"source\": [\n        \"Notice how there are ten rows (because you took ten shots), with two results per row (because there were two measurements in the circuit).\\n\",\n        \"Also notice how the results are random from row to row, but always agree within each row.\\n\",\n        \"That makes sense; that's what's supposed to happen when you repeatedly prepare and measure the |00⟩ + |11⟩ state.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"zX7ZyHVAHfF_\"\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"sample-detectors\\\"></a>\\n\",\n        \"# 4. Add detector annotations to a circuit, and sample them\\n\",\n        \"\\n\",\n        \"Stim circuits can include error-correction annotations.\\n\",\n        \"In particular, you can annotate that certain sets of measurements can be used to detect errors.\\n\",\n        \"For example, in the circuit you created above, the two measurement results should always be equal.\\n\",\n        \"You can tell Stim you care about that by adding a `DETECTOR` annotation to the circuit.\\n\",\n        \"\\n\",\n        \"The `DETECTOR` annotation will take two targets: the two measurements whose parity you are asserting should be consistent from run to run. You point at the measurements by using the [`stim.target_rec`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.target_rec) method (short for \\\"target measurement record\\\"). The most recent measurement is `stim.target_rec(-1)` (also known as `rec[-1]` in Stim's circuit language), and the second most recent measurement is `stim.target_rec(-2)`:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"GxViFukZIVI4\",\n        \"outputId\": \"218d0843-da8c-482a-d736-242b918aabc0\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"stim.Circuit('''\\n\",\n            \"    H 0\\n\",\n            \"    CX 0 1\\n\",\n            \"    M 0 1\\n\",\n            \"    DETECTOR rec[-1] rec[-2]\\n\",\n            \"''')\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"# Indicate the two previous measurements are supposed to consistently agree.\\n\",\n        \"circuit.append(\\\"DETECTOR\\\", [stim.target_rec(-1), stim.target_rec(-2)])\\n\",\n        \"print(repr(circuit))\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"tEz4G3OjI164\"\n      },\n      \"source\": [\n        \"A slightly subtle point about detectors is that they only assert that the parity of the measurements is *always the same under noiseless execution*.\\n\",\n        \"A detector doesn't say whether the parity should be even or should be odd, only that it should always be the same.\\n\",\n        \"You annotate that a pair of measurements is always different in the same way that you annotate that a pair of measurements is always the same; it's the *consistency* that's key.\\n\",\n        \"\\n\",\n        \"Moving on, now that you've annotated the circuit with a detector, you can sample from the circuit's detectors instead of sampling from its measurements.\\n\",\n        \"You do that by creating a detector sampler, using the [`compile_detector_sampler`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.compile_detector_sampler) method, and then calling [`sample`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.CompiledDetectorSampler.sample) on it.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"PkSoSb65JWsx\",\n        \"outputId\": \"bf9101c0-db23-42bf-a978-72e29fa83dcb\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"[[False]\\n\",\n            \" [False]\\n\",\n            \" [False]\\n\",\n            \" [False]\\n\",\n            \" [False]]\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"sampler = circuit.compile_detector_sampler()\\n\",\n        \"print(sampler.sample(shots=5))\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"kCby-NA4Jevl\"\n      },\n      \"source\": [\n        \"There are 5 rows in the results, because you took 5 shots.\\n\",\n        \"There's one entry per row, because you put one detector in the circuit.\\n\",\n        \"\\n\",\n        \"Notice how the results are always `False`.\\n\",\n        \"This means the detector is never producing a detection event.\\n\",\n        \"That's because there's no noise in the circuit; nothing to disturb the peace and quiet of a perfectly working machine.\\n\",\n        \"Well... time to fix that!\\n\",\n        \"\\n\",\n        \"Stim has a variety of error channels to pick from, like single qubit depolarization (`DEPOLARIZE1`) and phase damping (`Z_ERROR`), but in this context a good error to try is `X_ERROR`.\\n\",\n        \"The `X_ERROR` noise channel probabilistically applies a bit flip (a Pauli X error) to each of its targets.\\n\",\n        \"Note that each target is operated on independently.\\n\",\n        \"They don't all flip together with the given probability, each one flips individually with the given probability.\\n\",\n        \"\\n\",\n        \"You can recreate the circuit, with the noise inserted, by using Stim's domain specific language for circuits. While you're at it, throw in some `TICK` instructions to indicate the progression of time:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"HniubUFXJ9jh\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"circuit = stim.Circuit(\\\"\\\"\\\"\\n\",\n        \"    H 0\\n\",\n        \"    TICK\\n\",\n        \"\\n\",\n        \"    CX 0 1\\n\",\n        \"    X_ERROR(0.2) 0 1\\n\",\n        \"    TICK\\n\",\n        \"\\n\",\n        \"    M 0 1\\n\",\n        \"    DETECTOR rec[-1] rec[-2]\\n\",\n        \"\\\"\\\"\\\")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"U7_2QfyiKSBL\"\n      },\n      \"source\": [\n        \"Thanks to adding the `TICK` instructions, you get access to a new type of diagram: `timeslice-svg`.\\n\",\n        \"This diagram shows the operations from each tick in a separate frame:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"1jOOCijd-qOR\",\n        \"outputId\": \"44ff0bba-086b-4846-faa9-1dc4549c6b78\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/svg+xml\": [\n              \"<svg viewBox=\\\"0 0 470.4 336\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"qubit_dots\\\">\\n\",\n              \"<circle id=\\\"qubit_dot:0:0\\\" cx=\\\"80\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:0\\\" cx=\\\"144\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:0:0\\\" cx=\\\"80\\\" cy=\\\"256\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:0\\\" cx=\\\"144\\\" cy=\\\"256\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:0:1\\\" cx=\\\"326.4\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1\\\" cx=\\\"390.4\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"80\\\" y=\\\"80\\\">H</text>\\n\",\n              \"<path d=\\\"M326.4,80 L390.4,80 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"326.4\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"390.4\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M378.4,80 L402.4,80 M390.4,68 L390.4,92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"324.4\\\" y=\\\"80\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"340.4\\\" y=\\\"96\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"340.4\\\" y=\\\"116\\\">0.2</text>\\n\",\n              \"<rect x=\\\"388.4\\\" y=\\\"80\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"404.4\\\" y=\\\"96\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"404.4\\\" y=\\\"116\\\">0.2</text>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"80\\\" y=\\\"256\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"128\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"144\\\" y=\\\"256\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<g id=\\\"tick_borders\\\">\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"80\\\" y=\\\"-218\\\">Tick 0</text>\\n\",\n              \"<rect id=\\\"tick_border:0:0_0:0\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"224\\\" height=\\\"160\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"80\\\" y=\\\"-464.4\\\">Tick 1</text>\\n\",\n              \"<rect id=\\\"tick_border:1:0_1:1\\\" x=\\\"246.4\\\" y=\\\"0\\\" width=\\\"224\\\" height=\\\"160\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"256\\\" y=\\\"-218\\\">Tick 2</text>\\n\",\n              \"<rect id=\\\"tick_border:2:1_0:2\\\" x=\\\"0\\\" y=\\\"176\\\" width=\\\"224\\\" height=\\\"160\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"</svg>\"\n            ],\n            \"text/plain\": [\n              \"<svg viewBox=\\\"0 0 470.4 336\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"qubit_dots\\\">\\n\",\n              \"<circle id=\\\"qubit_dot:0:0\\\" cx=\\\"80\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:0\\\" cx=\\\"144\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:0:0\\\" cx=\\\"80\\\" cy=\\\"256\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:0\\\" cx=\\\"144\\\" cy=\\\"256\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:0:1\\\" cx=\\\"326.4\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1\\\" cx=\\\"390.4\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"80\\\" y=\\\"80\\\">H</text>\\n\",\n              \"<path d=\\\"M326.4,80 L390.4,80 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"326.4\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"390.4\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M378.4,80 L402.4,80 M390.4,68 L390.4,92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"324.4\\\" y=\\\"80\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"340.4\\\" y=\\\"96\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"340.4\\\" y=\\\"116\\\">0.2</text>\\n\",\n              \"<rect x=\\\"388.4\\\" y=\\\"80\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"404.4\\\" y=\\\"96\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"404.4\\\" y=\\\"116\\\">0.2</text>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"80\\\" y=\\\"256\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"128\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"144\\\" y=\\\"256\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<g id=\\\"tick_borders\\\">\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"80\\\" y=\\\"-218\\\">Tick 0</text>\\n\",\n              \"<rect id=\\\"tick_border:0:0_0:0\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"224\\\" height=\\\"160\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"80\\\" y=\\\"-464.4\\\">Tick 1</text>\\n\",\n              \"<rect id=\\\"tick_border:1:0_1:1\\\" x=\\\"246.4\\\" y=\\\"0\\\" width=\\\"224\\\" height=\\\"160\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"256\\\" y=\\\"-218\\\">Tick 2</text>\\n\",\n              \"<rect id=\\\"tick_border:2:1_0:2\\\" x=\\\"0\\\" y=\\\"176\\\" width=\\\"224\\\" height=\\\"160\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"</svg>\"\n            ]\n          },\n          \"execution_count\": 11,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"circuit.diagram('timeslice-svg')\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"7lBUrusk-qOR\"\n      },\n      \"source\": [\n        \"Now that you've added some noise, try sampling some more detector shots and see what happens:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"nfbwr9d-KWL4\",\n        \"outputId\": \"f5477d97-473c-4552-d73a-11190a296c05\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"[[False]\\n\",\n            \" [False]\\n\",\n            \" [ True]\\n\",\n            \" [ True]\\n\",\n            \" [False]\\n\",\n            \" [False]\\n\",\n            \" [ True]\\n\",\n            \" [ True]\\n\",\n            \" [ True]\\n\",\n            \" [False]]\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"sampler = circuit.compile_detector_sampler()\\n\",\n        \"print(sampler.sample(shots=10))\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"AreMncCeKb1x\"\n      },\n      \"source\": [\n        \"It's no longer all `False`s (unless you got very lucky).\\n\",\n        \"There are `True`s appearing amongst the `False`s.\\n\",\n        \"\\n\",\n        \"The *detection fraction* of the circuit is how often detectors fire on average.\\n\",\n        \"Given that an X error is being applied to each qubit with 20% probability, and the detector will fire when one of the qubits is hit (but not both), the detection fraction of the detectors in this circuit is $0.8 \\\\cdot 0.2 \\\\cdot 2 = 0.32$.\\n\",\n        \"\\n\",\n        \"You can estimate the detection fraction by just taking a lot of shots, and dividing by the number of shots and the number of detectors:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"6NqbK11eKlP1\",\n        \"outputId\": \"28cb1ee1-551b-4039-c537-ec3495e957cf\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"0.320135\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"import numpy as np\\n\",\n        \"print(np.sum(sampler.sample(shots=10**6)) / 10**6)\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"RKM6PLk8Tl13\"\n      },\n      \"source\": [\n        \"As you can see, the sampled estimate ends up close to the expected value $0.32$.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"fG2jQsH2LZQP\"\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"make-qec-circuits\\\"></a>\\n\",\n        \"# 5. Generate example error correction circuits\\n\",\n        \"\\n\",\n        \"Now it's time for you to work with a *real* error-correcting circuit.\\n\",\n        \"Well... a classical error-correcting circuit:\\n\",\n        \"the *repetition* code.\\n\",\n        \"\\n\",\n        \"You could generate a repetition code circuit for yourself, but for the purposes of this tutorial it's easiest to use the example included with Stim.\\n\",\n        \"You can do this by calling [`stim.Circuit.generated`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.generated) with an argument of `\\\"repetition_code:memory\\\"`.\\n\",\n        \"(You can find out about other valid arguments in the method's doc string, or just by passing in a bad one and looking at the exception message that comes out.)\\n\",\n        \"\\n\",\n        \"Stim takes a few different parameters when generating circuits.\\n\",\n        \"You have to decide how many times the stabilizers of the code are measured by specifying `rounds`, you have to decide on the size of the code by specifying `distance`, and you can specify what kind of noise to include using a few optional parameters.\\n\",\n        \"\\n\",\n        \"To start with, just set `before_round_data_depolarization=0.04` and `before_measure_flip_probability=0.01`. This will insert a `DEPOLARIZE1(0.04)` operation at the start of each round targeting every data qubit, and an `X_ERROR(0.01)` just before each measurement operation.\\n\",\n        \"This is a \\\"phenomenological noise model\\\".\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"ku1-_JnuLzVR\",\n        \"outputId\": \"e9b813a7-f4bc-42f0-e4ac-e73f90204ee4\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"stim.Circuit('''\\n\",\n            \"    R 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16\\n\",\n            \"    TICK\\n\",\n            \"    DEPOLARIZE1(0.04) 0 2 4 6 8 10 12 14 16\\n\",\n            \"    CX 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\\n\",\n            \"    TICK\\n\",\n            \"    CX 2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15\\n\",\n            \"    TICK\\n\",\n            \"    X_ERROR(0.01) 1 3 5 7 9 11 13 15\\n\",\n            \"    MR 1 3 5 7 9 11 13 15\\n\",\n            \"    DETECTOR(1, 0) rec[-8]\\n\",\n            \"    DETECTOR(3, 0) rec[-7]\\n\",\n            \"    DETECTOR(5, 0) rec[-6]\\n\",\n            \"    DETECTOR(7, 0) rec[-5]\\n\",\n            \"    DETECTOR(9, 0) rec[-4]\\n\",\n            \"    DETECTOR(11, 0) rec[-3]\\n\",\n            \"    DETECTOR(13, 0) rec[-2]\\n\",\n            \"    DETECTOR(15, 0) rec[-1]\\n\",\n            \"    REPEAT 24 {\\n\",\n            \"        TICK\\n\",\n            \"        DEPOLARIZE1(0.04) 0 2 4 6 8 10 12 14 16\\n\",\n            \"        CX 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\\n\",\n            \"        TICK\\n\",\n            \"        CX 2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15\\n\",\n            \"        TICK\\n\",\n            \"        X_ERROR(0.01) 1 3 5 7 9 11 13 15\\n\",\n            \"        MR 1 3 5 7 9 11 13 15\\n\",\n            \"        SHIFT_COORDS(0, 1)\\n\",\n            \"        DETECTOR(1, 0) rec[-8] rec[-16]\\n\",\n            \"        DETECTOR(3, 0) rec[-7] rec[-15]\\n\",\n            \"        DETECTOR(5, 0) rec[-6] rec[-14]\\n\",\n            \"        DETECTOR(7, 0) rec[-5] rec[-13]\\n\",\n            \"        DETECTOR(9, 0) rec[-4] rec[-12]\\n\",\n            \"        DETECTOR(11, 0) rec[-3] rec[-11]\\n\",\n            \"        DETECTOR(13, 0) rec[-2] rec[-10]\\n\",\n            \"        DETECTOR(15, 0) rec[-1] rec[-9]\\n\",\n            \"    }\\n\",\n            \"    X_ERROR(0.01) 0 2 4 6 8 10 12 14 16\\n\",\n            \"    M 0 2 4 6 8 10 12 14 16\\n\",\n            \"    DETECTOR(1, 1) rec[-8] rec[-9] rec[-17]\\n\",\n            \"    DETECTOR(3, 1) rec[-7] rec[-8] rec[-16]\\n\",\n            \"    DETECTOR(5, 1) rec[-6] rec[-7] rec[-15]\\n\",\n            \"    DETECTOR(7, 1) rec[-5] rec[-6] rec[-14]\\n\",\n            \"    DETECTOR(9, 1) rec[-4] rec[-5] rec[-13]\\n\",\n            \"    DETECTOR(11, 1) rec[-3] rec[-4] rec[-12]\\n\",\n            \"    DETECTOR(13, 1) rec[-2] rec[-3] rec[-11]\\n\",\n            \"    DETECTOR(15, 1) rec[-1] rec[-2] rec[-10]\\n\",\n            \"    OBSERVABLE_INCLUDE(0) rec[-1]\\n\",\n            \"''')\\n\"\n          ]\n        },\n        {\n          \"data\": {\n            \"image/svg+xml\": [\n              \"<svg viewBox=\\\"0 0 1888 1184\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"qubit_lines\\\">\\n\",\n              \"<path id=\\\"qubit_line:0\\\" d=\\\"M64,64 L1856,64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"64\\\">q0</text>\\n\",\n              \"<path id=\\\"qubit_line:1\\\" d=\\\"M64,128 L1856,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"128\\\">q1</text>\\n\",\n              \"<path id=\\\"qubit_line:2\\\" d=\\\"M64,192 L1856,192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"192\\\">q2</text>\\n\",\n              \"<path id=\\\"qubit_line:3\\\" d=\\\"M64,256 L1856,256 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"256\\\">q3</text>\\n\",\n              \"<path id=\\\"qubit_line:4\\\" d=\\\"M64,320 L1856,320 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"320\\\">q4</text>\\n\",\n              \"<path id=\\\"qubit_line:5\\\" d=\\\"M64,384 L1856,384 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"384\\\">q5</text>\\n\",\n              \"<path id=\\\"qubit_line:6\\\" d=\\\"M64,448 L1856,448 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"448\\\">q6</text>\\n\",\n              \"<path id=\\\"qubit_line:7\\\" d=\\\"M64,512 L1856,512 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"512\\\">q7</text>\\n\",\n              \"<path id=\\\"qubit_line:8\\\" d=\\\"M64,576 L1856,576 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"576\\\">q8</text>\\n\",\n              \"<path id=\\\"qubit_line:9\\\" d=\\\"M64,640 L1856,640 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"640\\\">q9</text>\\n\",\n              \"<path id=\\\"qubit_line:10\\\" d=\\\"M64,704 L1856,704 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"704\\\">q10</text>\\n\",\n              \"<path id=\\\"qubit_line:11\\\" d=\\\"M64,768 L1856,768 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"768\\\">q11</text>\\n\",\n              \"<path id=\\\"qubit_line:12\\\" d=\\\"M64,832 L1856,832 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"832\\\">q12</text>\\n\",\n              \"<path id=\\\"qubit_line:13\\\" d=\\\"M64,896 L1856,896 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"896\\\">q13</text>\\n\",\n              \"<path id=\\\"qubit_line:14\\\" d=\\\"M64,960 L1856,960 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"960\\\">q14</text>\\n\",\n              \"<path id=\\\"qubit_line:15\\\" d=\\\"M64,1024 L1856,1024 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"1024\\\">q15</text>\\n\",\n              \"<path id=\\\"qubit_line:16\\\" d=\\\"M64,1088 L1856,1088 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"1088\\\">q16</text>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"64\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"128\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"192\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"256\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"320\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"384\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"448\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"512\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"576\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"640\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"704\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"768\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"832\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"896\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"960\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"1024\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"1088\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"64\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"84\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"192\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"212\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"320\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"340\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"448\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"468\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"576\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"596\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"704\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"724\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"832\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"852\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"960\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"980\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"1088\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"1108\\\">0.04</text>\\n\",\n              \"<path d=\\\"M224,64 L224,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,128 L236,128 M224,116 L224,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,192 L224,256 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"256\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,256 L236,256 M224,244 L224,268 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,320 L224,384 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"320\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"384\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,384 L236,384 M224,372 L224,396 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,448 L224,512 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"448\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"512\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,512 L236,512 M224,500 L224,524 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,576 L224,640 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"576\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"640\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,640 L236,640 M224,628 L224,652 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,704 L224,768 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"704\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"768\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,768 L236,768 M224,756 L224,780 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,832 L224,896 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"832\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"896\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,896 L236,896 M224,884 L224,908 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,960 L224,1024 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"960\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"1024\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,1024 L236,1024 M224,1012 L224,1036 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M132,40 L132,32 L252,32 L252,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M132,1144 L132,1152 L252,1152 L252,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M288,128 L288,192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,128 L300,128 M288,116 L288,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,256 L288,320 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"320\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"256\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,256 L300,256 M288,244 L288,268 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,384 L288,448 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"448\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"384\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,384 L300,384 M288,372 L288,396 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,512 L288,576 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"576\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"512\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,512 L300,512 M288,500 L288,524 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,640 L288,704 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"704\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"640\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,640 L300,640 M288,628 L288,652 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,768 L288,832 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"832\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"768\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,768 L300,768 M288,756 L288,780 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,896 L288,960 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"960\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"896\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,896 L300,896 M288,884 L288,908 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,1024 L288,1088 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"1088\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"1024\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,1024 L300,1024 M288,1012 L288,1036 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"128\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"148\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"256\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"276\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"384\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"404\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"512\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"532\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"640\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"660\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"768\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"788\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"896\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"916\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"1024\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"1044\\\">0.01</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"128\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"108\\\">rec[0]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"256\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"236\\\">rec[1]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"384\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"364\\\">rec[2]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"512\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"492\\\">rec[3]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"640\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"620\\\">rec[4]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"768\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"748\\\">rec[5]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"896\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"876\\\">rec[6]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"1024\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"1004\\\">rec[7]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"112\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"128\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"148\\\">coords=(1,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"108\\\">D0 = rec[0]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"240\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"256\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"276\\\">coords=(3,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"236\\\">D1 = rec[1]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"368\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"384\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"404\\\">coords=(5,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"364\\\">D2 = rec[2]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"496\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"512\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"532\\\">coords=(7,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"492\\\">D3 = rec[3]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"624\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"640\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"660\\\">coords=(9,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"620\\\">D4 = rec[4]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"752\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"768\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"788\\\">coords=(11,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"748\\\">D5 = rec[5]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"880\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"896\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"916\\\">coords=(13,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"876\\\">D6 = rec[6]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"1008\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"1024\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"1044\\\">coords=(15,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"1004\\\">D7 = rec[7]</text>\\n\",\n              \"<path d=\\\"M324,40 L324,32 L636,32 L636,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M324,1144 L324,1152 L636,1152 L636,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M680,32 L672,32 L672,1152 L680,1152 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"auto\\\" text-anchor=\\\"start\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"676\\\" y=\\\"1148\\\">REP24</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"64\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"84\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"192\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"212\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"320\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"340\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"448\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"468\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"576\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"596\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"704\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"724\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"832\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"852\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"960\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"980\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"1088\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"1108\\\">0.04</text>\\n\",\n              \"<path d=\\\"M864,64 L864,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,128 L876,128 M864,116 L864,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,192 L864,256 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"256\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,256 L876,256 M864,244 L864,268 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,320 L864,384 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"320\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"384\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,384 L876,384 M864,372 L864,396 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,448 L864,512 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"448\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"512\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,512 L876,512 M864,500 L864,524 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,576 L864,640 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"576\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"640\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,640 L876,640 M864,628 L864,652 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,704 L864,768 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"704\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"768\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,768 L876,768 M864,756 L864,780 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,832 L864,896 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"832\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"896\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,896 L876,896 M864,884 L864,908 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,960 L864,1024 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"960\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"1024\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,1024 L876,1024 M864,1012 L864,1036 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M772,40 L772,32 L892,32 L892,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M772,1144 L772,1152 L892,1152 L892,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M928,128 L928,192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,128 L940,128 M928,116 L928,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,256 L928,320 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"320\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"256\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,256 L940,256 M928,244 L928,268 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,384 L928,448 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"448\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"384\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,384 L940,384 M928,372 L928,396 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,512 L928,576 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"576\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"512\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,512 L940,512 M928,500 L928,524 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,640 L928,704 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"704\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"640\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,640 L940,640 M928,628 L928,652 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,768 L928,832 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"832\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"768\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,768 L940,768 M928,756 L928,780 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,896 L928,960 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"960\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"896\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,896 L940,896 M928,884 L928,908 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,1024 L928,1088 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"1088\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"1024\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,1024 L940,1024 M928,1012 L928,1036 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"128\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"148\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"256\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"276\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"384\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"404\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"512\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"532\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"640\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"660\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"768\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"788\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"896\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"916\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"1024\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"1044\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"128\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"108\\\">rec[8+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"256\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"236\\\">rec[9+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"384\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"364\\\">rec[10+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"512\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"492\\\">rec[11+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"640\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"620\\\">rec[12+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"768\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"748\\\">rec[13+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"896\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"876\\\">rec[14+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"1024\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"1004\\\">rec[15+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"112\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"128\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"148\\\">coords=(1,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"108\\\">D[8+iter*8] = rec[8+iter*8]*rec[0+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"240\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"256\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"276\\\">coords=(3,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"236\\\">D[9+iter*8] = rec[9+iter*8]*rec[1+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"368\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"384\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"404\\\">coords=(5,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"364\\\">D[10+iter*8] = rec[10+iter*8]*rec[2+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"496\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"512\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"532\\\">coords=(7,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"492\\\">D[11+iter*8] = rec[11+iter*8]*rec[3+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"624\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"640\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"660\\\">coords=(9,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"620\\\">D[12+iter*8] = rec[12+iter*8]*rec[4+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"752\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"768\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"788\\\">coords=(11,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"748\\\">D[13+iter*8] = rec[13+iter*8]*rec[5+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"880\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"896\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"916\\\">coords=(13,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"876\\\">D[14+iter*8] = rec[14+iter*8]*rec[6+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"1008\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"1024\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"1044\\\">coords=(15,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"1004\\\">D[15+iter*8] = rec[15+iter*8]*rec[7+iter*8]</text>\\n\",\n              \"<path d=\\\"M964,40 L964,32 L1340,32 L1340,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M964,1144 L964,1152 L1340,1152 L1340,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M1368,32 L1376,32 L1376,1152 L1368,1152 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"64\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"84\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"192\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"212\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"320\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"340\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"448\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"468\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"576\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"596\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"704\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"724\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"832\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"852\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"960\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"980\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"1088\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"1108\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"64\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"44\\\">rec[200]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"192\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"172\\\">rec[201]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"320\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"300\\\">rec[202]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"448\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"428\\\">rec[203]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"576\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"556\\\">rec[204]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"704\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"684\\\">rec[205]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"832\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"812\\\">rec[206]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"960\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"940\\\">rec[207]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"1088\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"1068\\\">rec[208]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"48\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"64\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"84\\\">coords=(1,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"44\\\">D200 = rec[201]*rec[200]*rec[192]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"176\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"192\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"212\\\">coords=(3,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"172\\\">D201 = rec[202]*rec[201]*rec[193]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"304\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"320\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"340\\\">coords=(5,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"300\\\">D202 = rec[203]*rec[202]*rec[194]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"432\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"448\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"468\\\">coords=(7,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"428\\\">D203 = rec[204]*rec[203]*rec[195]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"560\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"576\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"596\\\">coords=(9,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"556\\\">D204 = rec[205]*rec[204]*rec[196]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"688\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"704\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"724\\\">coords=(11,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"684\\\">D205 = rec[206]*rec[205]*rec[197]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"816\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"832\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"852\\\">coords=(13,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"812\\\">D206 = rec[207]*rec[206]*rec[198]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"944\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"960\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"980\\\">coords=(15,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"940\\\">D207 = rec[208]*rec[207]*rec[199]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"1072\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1632\\\" y=\\\"1088\\\">OBS_INCLUDE(0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1632\\\" y=\\\"1068\\\">L0 *= rec[208]</text>\\n\",\n              \"<path d=\\\"M1412,40 L1412,32 L1852,32 L1852,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M1412,1144 L1412,1152 L1852,1152 L1852,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</svg>\"\n            ],\n            \"text/plain\": [\n              \"<svg viewBox=\\\"0 0 1888 1184\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"qubit_lines\\\">\\n\",\n              \"<path id=\\\"qubit_line:0\\\" d=\\\"M64,64 L1856,64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"64\\\">q0</text>\\n\",\n              \"<path id=\\\"qubit_line:1\\\" d=\\\"M64,128 L1856,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"128\\\">q1</text>\\n\",\n              \"<path id=\\\"qubit_line:2\\\" d=\\\"M64,192 L1856,192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"192\\\">q2</text>\\n\",\n              \"<path id=\\\"qubit_line:3\\\" d=\\\"M64,256 L1856,256 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"256\\\">q3</text>\\n\",\n              \"<path id=\\\"qubit_line:4\\\" d=\\\"M64,320 L1856,320 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"320\\\">q4</text>\\n\",\n              \"<path id=\\\"qubit_line:5\\\" d=\\\"M64,384 L1856,384 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"384\\\">q5</text>\\n\",\n              \"<path id=\\\"qubit_line:6\\\" d=\\\"M64,448 L1856,448 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"448\\\">q6</text>\\n\",\n              \"<path id=\\\"qubit_line:7\\\" d=\\\"M64,512 L1856,512 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"512\\\">q7</text>\\n\",\n              \"<path id=\\\"qubit_line:8\\\" d=\\\"M64,576 L1856,576 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"576\\\">q8</text>\\n\",\n              \"<path id=\\\"qubit_line:9\\\" d=\\\"M64,640 L1856,640 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"640\\\">q9</text>\\n\",\n              \"<path id=\\\"qubit_line:10\\\" d=\\\"M64,704 L1856,704 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"704\\\">q10</text>\\n\",\n              \"<path id=\\\"qubit_line:11\\\" d=\\\"M64,768 L1856,768 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"768\\\">q11</text>\\n\",\n              \"<path id=\\\"qubit_line:12\\\" d=\\\"M64,832 L1856,832 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"832\\\">q12</text>\\n\",\n              \"<path id=\\\"qubit_line:13\\\" d=\\\"M64,896 L1856,896 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"896\\\">q13</text>\\n\",\n              \"<path id=\\\"qubit_line:14\\\" d=\\\"M64,960 L1856,960 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"960\\\">q14</text>\\n\",\n              \"<path id=\\\"qubit_line:15\\\" d=\\\"M64,1024 L1856,1024 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"1024\\\">q15</text>\\n\",\n              \"<path id=\\\"qubit_line:16\\\" d=\\\"M64,1088 L1856,1088 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"end\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"64\\\" y=\\\"1088\\\">q16</text>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"64\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"128\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"192\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"256\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"320\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"384\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"448\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"512\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"576\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"640\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"704\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"768\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"832\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"896\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"960\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"1024\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"80\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"96\\\" y=\\\"1088\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"64\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"84\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"192\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"212\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"320\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"340\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"448\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"468\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"576\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"596\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"704\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"724\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"832\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"852\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"960\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"980\\\">0.04</text>\\n\",\n              \"<rect x=\\\"144\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"160\\\" y=\\\"1088\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"160\\\" y=\\\"1108\\\">0.04</text>\\n\",\n              \"<path d=\\\"M224,64 L224,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,128 L236,128 M224,116 L224,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,192 L224,256 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"256\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,256 L236,256 M224,244 L224,268 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,320 L224,384 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"320\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"384\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,384 L236,384 M224,372 L224,396 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,448 L224,512 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"448\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"512\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,512 L236,512 M224,500 L224,524 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,576 L224,640 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"576\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"640\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,640 L236,640 M224,628 L224,652 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,704 L224,768 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"704\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"768\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,768 L236,768 M224,756 L224,780 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,832 L224,896 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"832\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"896\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,896 L236,896 M224,884 L224,908 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M224,960 L224,1024 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"960\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"224\\\" cy=\\\"1024\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M212,1024 L236,1024 M224,1012 L224,1036 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M132,40 L132,32 L252,32 L252,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M132,1144 L132,1152 L252,1152 L252,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M288,128 L288,192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,128 L300,128 M288,116 L288,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,256 L288,320 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"320\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"256\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,256 L300,256 M288,244 L288,268 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,384 L288,448 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"448\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"384\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,384 L300,384 M288,372 L288,396 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,512 L288,576 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"576\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"512\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,512 L300,512 M288,500 L288,524 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,640 L288,704 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"704\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"640\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,640 L300,640 M288,628 L288,652 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,768 L288,832 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"832\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"768\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,768 L300,768 M288,756 L288,780 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,896 L288,960 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"960\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"896\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,896 L300,896 M288,884 L288,908 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M288,1024 L288,1088 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"1088\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"288\\\" cy=\\\"1024\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M276,1024 L300,1024 M288,1012 L288,1036 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"128\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"148\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"256\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"276\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"384\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"404\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"512\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"532\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"640\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"660\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"768\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"788\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"896\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"916\\\">0.01</text>\\n\",\n              \"<rect x=\\\"336\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"352\\\" y=\\\"1024\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"352\\\" y=\\\"1044\\\">0.01</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"128\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"108\\\">rec[0]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"256\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"236\\\">rec[1]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"384\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"364\\\">rec[2]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"512\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"492\\\">rec[3]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"640\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"620\\\">rec[4]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"768\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"748\\\">rec[5]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"896\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"876\\\">rec[6]</text>\\n\",\n              \"<rect x=\\\"400\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"416\\\" y=\\\"1024\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"416\\\" y=\\\"1004\\\">rec[7]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"112\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"128\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"148\\\">coords=(1,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"108\\\">D0 = rec[0]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"240\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"256\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"276\\\">coords=(3,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"236\\\">D1 = rec[1]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"368\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"384\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"404\\\">coords=(5,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"364\\\">D2 = rec[2]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"496\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"512\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"532\\\">coords=(7,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"492\\\">D3 = rec[3]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"624\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"640\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"660\\\">coords=(9,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"620\\\">D4 = rec[4]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"752\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"768\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"788\\\">coords=(11,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"748\\\">D5 = rec[5]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"880\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"896\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"916\\\">coords=(13,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"876\\\">D6 = rec[6]</text>\\n\",\n              \"<rect x=\\\"464\\\" y=\\\"1008\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"544\\\" y=\\\"1024\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"1044\\\">coords=(15,0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"544\\\" y=\\\"1004\\\">D7 = rec[7]</text>\\n\",\n              \"<path d=\\\"M324,40 L324,32 L636,32 L636,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M324,1144 L324,1152 L636,1152 L636,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M680,32 L672,32 L672,1152 L680,1152 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"auto\\\" text-anchor=\\\"start\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"676\\\" y=\\\"1148\\\">REP24</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"64\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"84\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"192\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"212\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"320\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"340\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"448\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"468\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"576\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"596\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"704\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"724\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"832\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"852\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"960\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"980\\\">0.04</text>\\n\",\n              \"<rect x=\\\"784\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"800\\\" y=\\\"1088\\\">DEP<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">1</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"800\\\" y=\\\"1108\\\">0.04</text>\\n\",\n              \"<path d=\\\"M864,64 L864,128 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,128 L876,128 M864,116 L864,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,192 L864,256 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"256\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,256 L876,256 M864,244 L864,268 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,320 L864,384 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"320\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"384\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,384 L876,384 M864,372 L864,396 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,448 L864,512 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"448\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"512\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,512 L876,512 M864,500 L864,524 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,576 L864,640 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"576\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"640\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,640 L876,640 M864,628 L864,652 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,704 L864,768 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"704\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"768\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,768 L876,768 M864,756 L864,780 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,832 L864,896 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"832\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"896\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,896 L876,896 M864,884 L864,908 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M864,960 L864,1024 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"960\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"864\\\" cy=\\\"1024\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M852,1024 L876,1024 M864,1012 L864,1036 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M772,40 L772,32 L892,32 L892,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M772,1144 L772,1152 L892,1152 L892,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M928,128 L928,192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"128\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,128 L940,128 M928,116 L928,140 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,256 L928,320 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"320\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"256\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,256 L940,256 M928,244 L928,268 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,384 L928,448 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"448\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"384\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,384 L940,384 M928,372 L928,396 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,512 L928,576 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"576\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"512\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,512 L940,512 M928,500 L928,524 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,640 L928,704 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"704\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"640\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,640 L940,640 M928,628 L928,652 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,768 L928,832 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"832\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"768\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,768 L940,768 M928,756 L928,780 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,896 L928,960 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"960\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"896\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,896 L940,896 M928,884 L928,908 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M928,1024 L928,1088 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"1088\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"928\\\" cy=\\\"1024\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M916,1024 L940,1024 M928,1012 L928,1036 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"128\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"148\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"256\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"276\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"384\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"404\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"512\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"532\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"640\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"660\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"768\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"788\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"896\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"916\\\">0.01</text>\\n\",\n              \"<rect x=\\\"976\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"992\\\" y=\\\"1024\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"992\\\" y=\\\"1044\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"112\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"128\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"108\\\">rec[8+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"240\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"256\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"236\\\">rec[9+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"368\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"384\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"364\\\">rec[10+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"496\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"512\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"492\\\">rec[11+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"624\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"640\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"620\\\">rec[12+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"752\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"768\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"748\\\">rec[13+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"880\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"896\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"876\\\">rec[14+iter*8]</text>\\n\",\n              \"<rect x=\\\"1040\\\" y=\\\"1008\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1056\\\" y=\\\"1024\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1056\\\" y=\\\"1004\\\">rec[15+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"112\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"128\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"148\\\">coords=(1,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"108\\\">D[8+iter*8] = rec[8+iter*8]*rec[0+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"240\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"256\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"276\\\">coords=(3,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"236\\\">D[9+iter*8] = rec[9+iter*8]*rec[1+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"368\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"384\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"404\\\">coords=(5,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"364\\\">D[10+iter*8] = rec[10+iter*8]*rec[2+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"496\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"512\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"532\\\">coords=(7,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"492\\\">D[11+iter*8] = rec[11+iter*8]*rec[3+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"624\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"640\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"660\\\">coords=(9,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"620\\\">D[12+iter*8] = rec[12+iter*8]*rec[4+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"752\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"768\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"788\\\">coords=(11,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"748\\\">D[13+iter*8] = rec[13+iter*8]*rec[5+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"880\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"896\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"916\\\">coords=(13,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"876\\\">D[14+iter*8] = rec[14+iter*8]*rec[6+iter*8]</text>\\n\",\n              \"<rect x=\\\"1104\\\" y=\\\"1008\\\" width=\\\"224\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1216\\\" y=\\\"1024\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"1044\\\">coords=(15,1+iter)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1216\\\" y=\\\"1004\\\">D[15+iter*8] = rec[15+iter*8]*rec[7+iter*8]</text>\\n\",\n              \"<path d=\\\"M964,40 L964,32 L1340,32 L1340,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M964,1144 L964,1152 L1340,1152 L1340,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M1368,32 L1376,32 L1376,1152 L1368,1152 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"64\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"84\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"192\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"212\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"320\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"340\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"448\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"468\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"576\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"596\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"704\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"724\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"832\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"852\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"960\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"980\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1424\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"pink\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"12\\\" x=\\\"1440\\\" y=\\\"1088\\\">ERR<tspan baseline-shift=\\\"sub\\\" font-size=\\\"10\\\">X</tspan></text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"10\\\" stroke=\\\"red\\\" x=\\\"1440\\\" y=\\\"1108\\\">0.01</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"48\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"64\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"44\\\">rec[200]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"176\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"192\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"172\\\">rec[201]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"304\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"320\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"300\\\">rec[202]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"432\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"448\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"428\\\">rec[203]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"560\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"576\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"556\\\">rec[204]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"688\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"704\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"684\\\">rec[205]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"816\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"832\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"812\\\">rec[206]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"944\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"960\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"940\\\">rec[207]</text>\\n\",\n              \"<rect x=\\\"1488\\\" y=\\\"1072\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1504\\\" y=\\\"1088\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1504\\\" y=\\\"1068\\\">rec[208]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"48\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"64\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"84\\\">coords=(1,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"44\\\">D200 = rec[201]*rec[200]*rec[192]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"176\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"192\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"212\\\">coords=(3,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"172\\\">D201 = rec[202]*rec[201]*rec[193]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"304\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"320\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"340\\\">coords=(5,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"300\\\">D202 = rec[203]*rec[202]*rec[194]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"432\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"448\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"468\\\">coords=(7,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"428\\\">D203 = rec[204]*rec[203]*rec[195]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"560\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"576\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"596\\\">coords=(9,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"556\\\">D204 = rec[205]*rec[204]*rec[196]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"688\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"704\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"724\\\">coords=(11,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"684\\\">D205 = rec[206]*rec[205]*rec[197]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"816\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"832\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"852\\\">coords=(13,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"812\\\">D206 = rec[207]*rec[206]*rec[198]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"944\\\" width=\\\"288\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1696\\\" y=\\\"960\\\">DETECTOR</text>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"980\\\">coords=(15,25)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1696\\\" y=\\\"940\\\">D207 = rec[208]*rec[207]*rec[199]</text>\\n\",\n              \"<rect x=\\\"1552\\\" y=\\\"1072\\\" width=\\\"160\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"lightgray\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"16\\\" x=\\\"1632\\\" y=\\\"1088\\\">OBS_INCLUDE(0)</text>\\n\",\n              \"<text text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"8\\\" x=\\\"1632\\\" y=\\\"1068\\\">L0 *= rec[208]</text>\\n\",\n              \"<path d=\\\"M1412,40 L1412,32 L1852,32 L1852,40 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<path d=\\\"M1412,1144 L1412,1152 L1852,1152 L1852,1144 \\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</svg>\"\n            ]\n          },\n          \"execution_count\": 14,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"circuit = stim.Circuit.generated(\\n\",\n        \"    \\\"repetition_code:memory\\\",\\n\",\n        \"    rounds=25,\\n\",\n        \"    distance=9,\\n\",\n        \"    before_round_data_depolarization=0.04,\\n\",\n        \"    before_measure_flip_probability=0.01)\\n\",\n        \"\\n\",\n        \"print(repr(circuit))\\n\",\n        \"circuit.diagram('timeline-svg')\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"DEE3Vqq_ZzXP\"\n      },\n      \"source\": [\n        \"You can see that this circuit is more complicated than the example you started with. Notice the little \\\"REP24\\\" at the bottom of the diagram. This circuit is using a `REPEAT` block to repeatedly measure the stabilizers of the code.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"lTu556AOMTv6\"\n      },\n      \"source\": [\n        \"With a circuit in hand, you can try sampling from it.\\n\",\n        \"Try sampling the measurements once, and printing out the results split up just right so that time advances from line to line:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"hQyBEti8Ng_S\",\n        \"outputId\": \"1c988414-9080-4f0f-facf-70c27b935730\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"_______1\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"_______1\\n\",\n            \"_______1\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"11_____1\\n\",\n            \"11___1_1\\n\",\n            \"11_____1\\n\",\n            \"11_____1\\n\",\n            \"11_____1\\n\",\n            \"11_11__1\\n\",\n            \"11_11__1\\n\",\n            \"11_11__1\\n\",\n            \"11_11__1\\n\",\n            \"1__11__1\\n\",\n            \"11_11__1\\n\",\n            \"1_111__1\\n\",\n            \"_11_1___\\n\",\n            \"1\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"sampler = circuit.compile_sampler()\\n\",\n        \"one_sample = sampler.sample(shots=1)[0]\\n\",\n        \"for k in range(0, len(one_sample), 8):\\n\",\n        \"    timeslice = one_sample[k:k+8]\\n\",\n        \"    print(\\\"\\\".join(\\\"1\\\" if e else \\\"_\\\" for e in timeslice))\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"I5J3W6bWOIhJ\"\n      },\n      \"source\": [\n        \"See how the 1s seem to come in pairs of streaks?\\n\",\n        \"That's because once a data qubit is flipped it stays flipped, and the measurements to its left and right permanently change parity.\\n\",\n        \"\\n\",\n        \"If you sample the circuit's detectors, instead of its measurements, the streaks are replaced by spackle.\\n\",\n        \"You get much sparser data:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"jJCydGZnOeez\",\n        \"outputId\": \"9149cd22-5b65-4b5b-ef39-549704f23f81\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"_____!!_\\n\",\n            \"____!!__\\n\",\n            \"_____!!_\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"___!_!__\\n\",\n            \"_____!!_\\n\",\n            \"!!______\\n\",\n            \"!_______\\n\",\n            \"!_______\\n\",\n            \"________\\n\",\n            \"________\\n\",\n            \"___!!___\\n\",\n            \"________\\n\",\n            \"________\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"detector_sampler = circuit.compile_detector_sampler()\\n\",\n        \"one_sample = detector_sampler.sample(shots=1)[0]\\n\",\n        \"for k in range(0, len(one_sample), 8):\\n\",\n        \"    timeslice = one_sample[k:k+8]\\n\",\n        \"    print(\\\"\\\".join(\\\"!\\\" if e else \\\"_\\\" for e in timeslice))\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"fFNsm0_GOh4H\"\n      },\n      \"source\": [\n        \"Notice how the `!`s tend to come in pairs, except near the sides.\\n\",\n        \"This \\\"comes in pairs\\\" property is extremely important, because it allows you to perform error correction.\\n\",\n        \"Every `!` must be paired with another `!`, with the left boundary, or with the right boundary.\\n\",\n        \"In the circuit generated by Stim, the logical observable is annotated to be a measurement of the leftmost data qubit.\\n\",\n        \"That data qubit was flipped once for each `!` that's paired with the left boundary.\\n\",\n        \"If the data qubit was flipped an even number of times, the observable that was measured is correct.\\n\",\n        \"If it was flipped an odd number of times, the observable that was measured needs to be flipped to be correct.\\n\",\n        \"If you just had a syndrome decoder, you could use it to solve the matching problem and figure out if the leftmost data qubit (and therefore the protected logical observable) ended up flipped or not...\\n\",\n        \"\\n\",\n        \"<a class=\\\"anchor\\\" id=\\\"use-pymatching\\\"></a>\\n\",\n        \"# 6. Use `pymatching` to correct errors in a circuit\\n\",\n        \"\\n\",\n        \"Stim has a key feature that makes it easier to use a decoder: converting a circuit into a detector error model.\\n\",\n        \"A detector error model is just a list of all the independent error mechanisms in a circuit, as well as their symptoms (which detectors they set off) and frame changes (which logical observables they flip).\\n\",\n        \"\\n\",\n        \"You can get the detector error mode for a circuit by calling [`circuit.detector_error_model()`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.detector_error_model):\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"qqUSe1BvO0V9\",\n        \"outputId\": \"fabb01fe-1608-42fb-c07a-9be9f6eb13c8\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"stim.DetectorErrorModel('''\\n\",\n            \"    error(0.0266667) D0\\n\",\n            \"    error(0.0266667) D0 D1\\n\",\n            \"    error(0.01) D0 D8\\n\",\n            \"    error(0.0266667) D1 D2\\n\",\n            \"    error(0.01) D1 D9\\n\",\n            \"    error(0.0266667) D2 D3\\n\",\n            \"    error(0.01) D2 D10\\n\",\n            \"    error(0.0266667) D3 D4\\n\",\n            \"    error(0.01) D3 D11\\n\",\n            \"    error(0.0266667) D4 D5\\n\",\n            \"    error(0.01) D4 D12\\n\",\n            \"    error(0.0266667) D5 D6\\n\",\n            \"    error(0.01) D5 D13\\n\",\n            \"    error(0.0266667) D6 D7\\n\",\n            \"    error(0.01) D6 D14\\n\",\n            \"    error(0.01) D7 D15\\n\",\n            \"    error(0.0266667) D7 L0\\n\",\n            \"    detector(1, 0) D0\\n\",\n            \"    detector(3, 0) D1\\n\",\n            \"    detector(5, 0) D2\\n\",\n            \"    detector(7, 0) D3\\n\",\n            \"    detector(9, 0) D4\\n\",\n            \"    detector(11, 0) D5\\n\",\n            \"    detector(13, 0) D6\\n\",\n            \"    detector(15, 0) D7\\n\",\n            \"    repeat 23 {\\n\",\n            \"        error(0.0266667) D8\\n\",\n            \"        error(0.0266667) D8 D9\\n\",\n            \"        error(0.01) D8 D16\\n\",\n            \"        error(0.0266667) D9 D10\\n\",\n            \"        error(0.01) D9 D17\\n\",\n            \"        error(0.0266667) D10 D11\\n\",\n            \"        error(0.01) D10 D18\\n\",\n            \"        error(0.0266667) D11 D12\\n\",\n            \"        error(0.01) D11 D19\\n\",\n            \"        error(0.0266667) D12 D13\\n\",\n            \"        error(0.01) D12 D20\\n\",\n            \"        error(0.0266667) D13 D14\\n\",\n            \"        error(0.01) D13 D21\\n\",\n            \"        error(0.0266667) D14 D15\\n\",\n            \"        error(0.01) D14 D22\\n\",\n            \"        error(0.01) D15 D23\\n\",\n            \"        error(0.0266667) D15 L0\\n\",\n            \"        shift_detectors(0, 1) 0\\n\",\n            \"        detector(1, 0) D8\\n\",\n            \"        detector(3, 0) D9\\n\",\n            \"        detector(5, 0) D10\\n\",\n            \"        detector(7, 0) D11\\n\",\n            \"        detector(9, 0) D12\\n\",\n            \"        detector(11, 0) D13\\n\",\n            \"        detector(13, 0) D14\\n\",\n            \"        detector(15, 0) D15\\n\",\n            \"        shift_detectors 8\\n\",\n            \"    }\\n\",\n            \"    error(0.0266667) D8\\n\",\n            \"    error(0.0266667) D8 D9\\n\",\n            \"    error(0.01) D8 D16\\n\",\n            \"    error(0.0266667) D9 D10\\n\",\n            \"    error(0.01) D9 D17\\n\",\n            \"    error(0.0266667) D10 D11\\n\",\n            \"    error(0.01) D10 D18\\n\",\n            \"    error(0.0266667) D11 D12\\n\",\n            \"    error(0.01) D11 D19\\n\",\n            \"    error(0.0266667) D12 D13\\n\",\n            \"    error(0.01) D12 D20\\n\",\n            \"    error(0.0266667) D13 D14\\n\",\n            \"    error(0.01) D13 D21\\n\",\n            \"    error(0.0266667) D14 D15\\n\",\n            \"    error(0.01) D14 D22\\n\",\n            \"    error(0.01) D15 D23\\n\",\n            \"    error(0.0266667) D15 L0\\n\",\n            \"    error(0.01) D16\\n\",\n            \"    error(0.01) D16 D17\\n\",\n            \"    error(0.01) D17 D18\\n\",\n            \"    error(0.01) D18 D19\\n\",\n            \"    error(0.01) D19 D20\\n\",\n            \"    error(0.01) D20 D21\\n\",\n            \"    error(0.01) D21 D22\\n\",\n            \"    error(0.01) D22 D23\\n\",\n            \"    error(0.01) D23 L0\\n\",\n            \"    shift_detectors(0, 1) 0\\n\",\n            \"    detector(1, 0) D8\\n\",\n            \"    detector(3, 0) D9\\n\",\n            \"    detector(5, 0) D10\\n\",\n            \"    detector(7, 0) D11\\n\",\n            \"    detector(9, 0) D12\\n\",\n            \"    detector(11, 0) D13\\n\",\n            \"    detector(13, 0) D14\\n\",\n            \"    detector(15, 0) D15\\n\",\n            \"    detector(1, 1) D16\\n\",\n            \"    detector(3, 1) D17\\n\",\n            \"    detector(5, 1) D18\\n\",\n            \"    detector(7, 1) D19\\n\",\n            \"    detector(9, 1) D20\\n\",\n            \"    detector(11, 1) D21\\n\",\n            \"    detector(13, 1) D22\\n\",\n            \"    detector(15, 1) D23\\n\",\n            \"''')\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"dem = circuit.detector_error_model()\\n\",\n        \"print(repr(dem))\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"QgqQ90GlBcB_\"\n      },\n      \"outputs\": [],\n      \"source\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"2NpcBtBM-qOS\"\n      },\n      \"source\": [\n        \"You can view the detector error model as a graph by using the `matchgraph-svg` diagram. Note that this diagram looking good relies heavily on the circuit specifying coordinate data for its detectors. Fortunately, the circuit you generated includes good coordinate data:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"DrUUoFMu-qOV\",\n        \"outputId\": \"1ee89575-a83e-47ad-de32-f636edd8726d\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/svg+xml\": [\n              \"<svg viewBox=\\\"0 0 319.746 472.251\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<path d=\\\"M54.8729,48.6253 L30.4428,5 M54.8729,48.6253 L84.8729,48.6253 M54.8729,48.6253 L54.8729,63.6253 M84.8729,48.6253 L114.873,48.6253 M84.8729,48.6253 L84.8729,63.6253 M114.873,48.6253 L144.873,48.6253 M114.873,48.6253 L114.873,63.6253 M144.873,48.6253 L174.873,48.6253 M144.873,48.6253 L144.873,63.6253 M174.873,48.6253 L204.873,48.6253 M174.873,48.6253 L174.873,63.6253 M204.873,48.6253 L234.873,48.6253 M204.873,48.6253 L204.873,63.6253 M234.873,48.6253 L264.873,48.6253 M234.873,48.6253 L234.873,63.6253 M264.873,48.6253 L264.873,63.6253 M54.8729,63.6253 L28.8756,20.9154 M54.8729,63.6253 L84.8729,63.6253 M54.8729,63.6253 L54.8729,78.6253 M84.8729,63.6253 L114.873,63.6253 M84.8729,63.6253 L84.8729,78.6253 M114.873,63.6253 L144.873,63.6253 M114.873,63.6253 L114.873,78.6253 M144.873,63.6253 L174.873,63.6253 M144.873,63.6253 L144.873,78.6253 M174.873,63.6253 L204.873,63.6253 M174.873,63.6253 L174.873,78.6253 M204.873,63.6253 L234.873,63.6253 M204.873,63.6253 L204.873,78.6253 M234.873,63.6253 L264.873,63.6253 M234.873,63.6253 L234.873,78.6253 M264.873,63.6253 L264.873,78.6253 M54.8729,78.6253 L27.1379,37.0228 M54.8729,78.6253 L84.8729,78.6253 M54.8729,78.6253 L54.8729,93.6253 M84.8729,78.6253 L114.873,78.6253 M84.8729,78.6253 L84.8729,93.6253 M114.873,78.6253 L144.873,78.6253 M114.873,78.6253 L114.873,93.6253 M144.873,78.6253 L174.873,78.6253 M144.873,78.6253 L144.873,93.6253 M174.873,78.6253 L204.873,78.6253 M174.873,78.6253 L174.873,93.6253 M204.873,78.6253 L234.873,78.6253 M204.873,78.6253 L204.873,93.6253 M234.873,78.6253 L264.873,78.6253 M234.873,78.6253 L234.873,93.6253 M264.873,78.6253 L264.873,93.6253 M54.8729,93.6253 L25.213,53.3725 M54.8729,93.6253 L84.8729,93.6253 M54.8729,93.6253 L54.8729,108.625 M84.8729,93.6253 L114.873,93.6253 M84.8729,93.6253 L84.8729,108.625 M114.873,93.6253 L144.873,93.6253 M114.873,93.6253 L114.873,108.625 M144.873,93.6253 L174.873,93.6253 M144.873,93.6253 L144.873,108.625 M174.873,93.6253 L204.873,93.6253 M174.873,93.6253 L174.873,108.625 M204.873,93.6253 L234.873,93.6253 M204.873,93.6253 L204.873,108.625 M234.873,93.6253 L264.873,93.6253 M234.873,93.6253 L234.873,108.625 M264.873,93.6253 L264.873,108.625 M54.8729,108.625 L23.0876,70.0288 M54.8729,108.625 L84.8729,108.625 M54.8729,108.625 L54.8729,123.625 M84.8729,108.625 L114.873,108.625 M84.8729,108.625 L84.8729,123.625 M114.873,108.625 L144.873,108.625 M114.873,108.625 L114.873,123.625 M144.873,108.625 L174.873,108.625 M144.873,108.625 L144.873,123.625 M174.873,108.625 L204.873,108.625 M174.873,108.625 L174.873,123.625 M204.873,108.625 L234.873,108.625 M204.873,108.625 L204.873,123.625 M234.873,108.625 L264.873,108.625 M234.873,108.625 L234.873,123.625 M264.873,108.625 L264.873,123.625 M54.8729,123.625 L20.757,87.0725 M54.8729,123.625 L84.8729,123.625 M54.8729,123.625 L54.8729,138.625 M84.8729,123.625 L114.873,123.625 M84.8729,123.625 L84.8729,138.625 M114.873,123.625 L144.873,123.625 M114.873,123.625 L114.873,138.625 M144.873,123.625 L174.873,123.625 M144.873,123.625 L144.873,138.625 M174.873,123.625 L204.873,123.625 M174.873,123.625 L174.873,138.625 M204.873,123.625 L234.873,123.625 M204.873,123.625 L204.873,138.625 M234.873,123.625 L264.873,123.625 M234.873,123.625 L234.873,138.625 M264.873,123.625 L264.873,138.625 M54.8729,138.625 L18.2333,104.603 M54.8729,138.625 L84.8729,138.625 M54.8729,138.625 L54.8729,153.625 M84.8729,138.625 L114.873,138.625 M84.8729,138.625 L84.8729,153.625 M114.873,138.625 L144.873,138.625 M114.873,138.625 L114.873,153.625 M144.873,138.625 L174.873,138.625 M144.873,138.625 L144.873,153.625 M174.873,138.625 L204.873,138.625 M174.873,138.625 L174.873,153.625 M204.873,138.625 L234.873,138.625 M204.873,138.625 L204.873,153.625 M234.873,138.625 L264.873,138.625 M234.873,138.625 L234.873,153.625 M264.873,138.625 L264.873,153.625 M54.8729,153.625 L15.557,122.734 M54.8729,153.625 L84.8729,153.625 M54.8729,153.625 L54.8729,168.625 M84.8729,153.625 L114.873,153.625 M84.8729,153.625 L84.8729,168.625 M114.873,153.625 L144.873,153.625 M114.873,153.625 L114.873,168.625 M144.873,153.625 L174.873,153.625 M144.873,153.625 L144.873,168.625 M174.873,153.625 L204.873,153.625 M174.873,153.625 L174.873,168.625 M204.873,153.625 L234.873,153.625 M204.873,153.625 L204.873,168.625 M234.873,153.625 L264.873,153.625 M234.873,153.625 L234.873,168.625 M264.873,153.625 L264.873,168.625 M54.8729,168.625 L12.814,141.587 M54.8729,168.625 L84.8729,168.625 M54.8729,168.625 L54.8729,183.625 M84.8729,168.625 L114.873,168.625 M84.8729,168.625 L84.8729,183.625 M114.873,168.625 L144.873,168.625 M114.873,168.625 L114.873,183.625 M144.873,168.625 L174.873,168.625 M144.873,168.625 L144.873,183.625 M174.873,168.625 L204.873,168.625 M174.873,168.625 L174.873,183.625 M204.873,168.625 L234.873,168.625 M204.873,168.625 L204.873,183.625 M234.873,168.625 L264.873,168.625 M234.873,168.625 L234.873,183.625 M264.873,168.625 L264.873,183.625 M54.8729,183.625 L10.1516,161.265 M54.8729,183.625 L84.8729,183.625 M54.8729,183.625 L54.8729,198.625 M84.8729,183.625 L114.873,183.625 M84.8729,183.625 L84.8729,198.625 M114.873,183.625 L144.873,183.625 M114.873,183.625 L114.873,198.625 M144.873,183.625 L174.873,183.625 M144.873,183.625 L144.873,198.625 M174.873,183.625 L204.873,183.625 M174.873,183.625 L174.873,198.625 M204.873,183.625 L234.873,183.625 M204.873,183.625 L204.873,198.625 M234.873,183.625 L264.873,183.625 M234.873,183.625 L234.873,198.625 M264.873,183.625 L264.873,198.625 M54.8729,198.625 L7.78584,181.808 M54.8729,198.625 L84.8729,198.625 M54.8729,198.625 L54.8729,213.625 M84.8729,198.625 L114.873,198.625 M84.8729,198.625 L84.8729,213.625 M114.873,198.625 L144.873,198.625 M114.873,198.625 L114.873,213.625 M144.873,198.625 L174.873,198.625 M144.873,198.625 L144.873,213.625 M174.873,198.625 L204.873,198.625 M174.873,198.625 L174.873,213.625 M204.873,198.625 L234.873,198.625 M204.873,198.625 L204.873,213.625 M234.873,198.625 L264.873,198.625 M234.873,198.625 L234.873,213.625 M264.873,198.625 L264.873,213.625 M54.8729,213.625 L5.98281,203.149 M54.8729,213.625 L84.8729,213.625 M54.8729,213.625 L54.8729,228.625 M84.8729,213.625 L114.873,213.625 M84.8729,213.625 L84.8729,228.625 M114.873,213.625 L144.873,213.625 M114.873,213.625 L114.873,228.625 M144.873,213.625 L174.873,213.625 M144.873,213.625 L144.873,228.625 M174.873,213.625 L204.873,213.625 M174.873,213.625 L174.873,228.625 M204.873,213.625 L234.873,213.625 M204.873,213.625 L204.873,228.625 M234.873,213.625 L264.873,213.625 M234.873,213.625 L234.873,228.625 M264.873,213.625 L264.873,228.625 M54.8729,228.625 L5,225.063 M54.8729,228.625 L84.8729,228.625 M54.8729,228.625 L54.8729,243.625 M84.8729,228.625 L114.873,228.625 M84.8729,228.625 L84.8729,243.625 M114.873,228.625 L144.873,228.625 M114.873,228.625 L114.873,243.625 M144.873,228.625 L174.873,228.625 M144.873,228.625 L144.873,243.625 M174.873,228.625 L204.873,228.625 M174.873,228.625 L174.873,243.625 M204.873,228.625 L234.873,228.625 M204.873,228.625 L204.873,243.625 M234.873,228.625 L264.873,228.625 M234.873,228.625 L234.873,243.625 M264.873,228.625 L264.873,243.625 M54.8729,243.625 L5,247.188 M54.8729,243.625 L84.8729,243.625 M54.8729,243.625 L54.8729,258.625 M84.8729,243.625 L114.873,243.625 M84.8729,243.625 L84.8729,258.625 M114.873,243.625 L144.873,243.625 M114.873,243.625 L114.873,258.625 M144.873,243.625 L174.873,243.625 M144.873,243.625 L144.873,258.625 M174.873,243.625 L204.873,243.625 M174.873,243.625 L174.873,258.625 M204.873,243.625 L234.873,243.625 M204.873,243.625 L204.873,258.625 M234.873,243.625 L264.873,243.625 M234.873,243.625 L234.873,258.625 M264.873,243.625 L264.873,258.625 M54.8729,258.625 L5.98281,269.102 M54.8729,258.625 L84.8729,258.625 M54.8729,258.625 L54.8729,273.625 M84.8729,258.625 L114.873,258.625 M84.8729,258.625 L84.8729,273.625 M114.873,258.625 L144.873,258.625 M114.873,258.625 L114.873,273.625 M144.873,258.625 L174.873,258.625 M144.873,258.625 L144.873,273.625 M174.873,258.625 L204.873,258.625 M174.873,258.625 L174.873,273.625 M204.873,258.625 L234.873,258.625 M204.873,258.625 L204.873,273.625 M234.873,258.625 L264.873,258.625 M234.873,258.625 L234.873,273.625 M264.873,258.625 L264.873,273.625 M54.8729,273.625 L7.78584,290.442 M54.8729,273.625 L84.8729,273.625 M54.8729,273.625 L54.8729,288.625 M84.8729,273.625 L114.873,273.625 M84.8729,273.625 L84.8729,288.625 M114.873,273.625 L144.873,273.625 M114.873,273.625 L114.873,288.625 M144.873,273.625 L174.873,273.625 M144.873,273.625 L144.873,288.625 M174.873,273.625 L204.873,273.625 M174.873,273.625 L174.873,288.625 M204.873,273.625 L234.873,273.625 M204.873,273.625 L204.873,288.625 M234.873,273.625 L264.873,273.625 M234.873,273.625 L234.873,288.625 M264.873,273.625 L264.873,288.625 M54.8729,288.625 L10.1516,310.986 M54.8729,288.625 L84.8729,288.625 M54.8729,288.625 L54.8729,303.625 M84.8729,288.625 L114.873,288.625 M84.8729,288.625 L84.8729,303.625 M114.873,288.625 L144.873,288.625 M114.873,288.625 L114.873,303.625 M144.873,288.625 L174.873,288.625 M144.873,288.625 L144.873,303.625 M174.873,288.625 L204.873,288.625 M174.873,288.625 L174.873,303.625 M204.873,288.625 L234.873,288.625 M204.873,288.625 L204.873,303.625 M234.873,288.625 L264.873,288.625 M234.873,288.625 L234.873,303.625 M264.873,288.625 L264.873,303.625 M54.8729,303.625 L12.814,330.663 M54.8729,303.625 L84.8729,303.625 M54.8729,303.625 L54.8729,318.625 M84.8729,303.625 L114.873,303.625 M84.8729,303.625 L84.8729,318.625 M114.873,303.625 L144.873,303.625 M114.873,303.625 L114.873,318.625 M144.873,303.625 L174.873,303.625 M144.873,303.625 L144.873,318.625 M174.873,303.625 L204.873,303.625 M174.873,303.625 L174.873,318.625 M204.873,303.625 L234.873,303.625 M204.873,303.625 L204.873,318.625 M234.873,303.625 L264.873,303.625 M234.873,303.625 L234.873,318.625 M264.873,303.625 L264.873,318.625 M54.8729,318.625 L15.557,349.516 M54.8729,318.625 L84.8729,318.625 M54.8729,318.625 L54.8729,333.625 M84.8729,318.625 L114.873,318.625 M84.8729,318.625 L84.8729,333.625 M114.873,318.625 L144.873,318.625 M114.873,318.625 L114.873,333.625 M144.873,318.625 L174.873,318.625 M144.873,318.625 L144.873,333.625 M174.873,318.625 L204.873,318.625 M174.873,318.625 L174.873,333.625 M204.873,318.625 L234.873,318.625 M204.873,318.625 L204.873,333.625 M234.873,318.625 L264.873,318.625 M234.873,318.625 L234.873,333.625 M264.873,318.625 L264.873,333.625 M54.8729,333.625 L18.2333,367.648 M54.8729,333.625 L84.8729,333.625 M54.8729,333.625 L54.8729,348.625 M84.8729,333.625 L114.873,333.625 M84.8729,333.625 L84.8729,348.625 M114.873,333.625 L144.873,333.625 M114.873,333.625 L114.873,348.625 M144.873,333.625 L174.873,333.625 M144.873,333.625 L144.873,348.625 M174.873,333.625 L204.873,333.625 M174.873,333.625 L174.873,348.625 M204.873,333.625 L234.873,333.625 M204.873,333.625 L204.873,348.625 M234.873,333.625 L264.873,333.625 M234.873,333.625 L234.873,348.625 M264.873,333.625 L264.873,348.625 M54.8729,348.625 L20.757,385.178 M54.8729,348.625 L84.8729,348.625 M54.8729,348.625 L54.8729,363.625 M84.8729,348.625 L114.873,348.625 M84.8729,348.625 L84.8729,363.625 M114.873,348.625 L144.873,348.625 M114.873,348.625 L114.873,363.625 M144.873,348.625 L174.873,348.625 M144.873,348.625 L144.873,363.625 M174.873,348.625 L204.873,348.625 M174.873,348.625 L174.873,363.625 M204.873,348.625 L234.873,348.625 M204.873,348.625 L204.873,363.625 M234.873,348.625 L264.873,348.625 M234.873,348.625 L234.873,363.625 M264.873,348.625 L264.873,363.625 M54.8729,363.625 L23.0876,402.222 M54.8729,363.625 L84.8729,363.625 M54.8729,363.625 L54.8729,378.625 M84.8729,363.625 L114.873,363.625 M84.8729,363.625 L84.8729,378.625 M114.873,363.625 L144.873,363.625 M114.873,363.625 L114.873,378.625 M144.873,363.625 L174.873,363.625 M144.873,363.625 L144.873,378.625 M174.873,363.625 L204.873,363.625 M174.873,363.625 L174.873,378.625 M204.873,363.625 L234.873,363.625 M204.873,363.625 L204.873,378.625 M234.873,363.625 L264.873,363.625 M234.873,363.625 L234.873,378.625 M264.873,363.625 L264.873,378.625 M54.8729,378.625 L25.213,418.878 M54.8729,378.625 L84.8729,378.625 M54.8729,378.625 L54.8729,393.625 M84.8729,378.625 L114.873,378.625 M84.8729,378.625 L84.8729,393.625 M114.873,378.625 L144.873,378.625 M114.873,378.625 L114.873,393.625 M144.873,378.625 L174.873,378.625 M144.873,378.625 L144.873,393.625 M174.873,378.625 L204.873,378.625 M174.873,378.625 L174.873,393.625 M204.873,378.625 L234.873,378.625 M204.873,378.625 L204.873,393.625 M234.873,378.625 L264.873,378.625 M234.873,378.625 L234.873,393.625 M264.873,378.625 L264.873,393.625 M54.8729,393.625 L27.1379,435.228 M54.8729,393.625 L84.8729,393.625 M54.8729,393.625 L54.8729,408.625 M84.8729,393.625 L114.873,393.625 M84.8729,393.625 L84.8729,408.625 M114.873,393.625 L144.873,393.625 M114.873,393.625 L114.873,408.625 M144.873,393.625 L174.873,393.625 M144.873,393.625 L144.873,408.625 M174.873,393.625 L204.873,393.625 M174.873,393.625 L174.873,408.625 M204.873,393.625 L234.873,393.625 M204.873,393.625 L204.873,408.625 M234.873,393.625 L264.873,393.625 M234.873,393.625 L234.873,408.625 M264.873,393.625 L264.873,408.625 M54.8729,408.625 L28.8756,451.335 M54.8729,408.625 L84.8729,408.625 M54.8729,408.625 L54.8729,423.625 M84.8729,408.625 L114.873,408.625 M84.8729,408.625 L84.8729,423.625 M114.873,408.625 L144.873,408.625 M114.873,408.625 L114.873,423.625 M144.873,408.625 L174.873,408.625 M144.873,408.625 L144.873,423.625 M174.873,408.625 L204.873,408.625 M174.873,408.625 L174.873,423.625 M204.873,408.625 L234.873,408.625 M204.873,408.625 L204.873,423.625 M234.873,408.625 L264.873,408.625 M234.873,408.625 L234.873,423.625 M264.873,408.625 L264.873,423.625 M54.8729,423.625 L30.4428,467.251 M54.8729,423.625 L84.8729,423.625 M84.8729,423.625 L114.873,423.625 M114.873,423.625 L144.873,423.625 M144.873,423.625 L174.873,423.625 M174.873,423.625 L204.873,423.625 M204.873,423.625 L234.873,423.625 M234.873,423.625 L264.873,423.625\\\" stroke=\\\"black\\\" fill=\\\"none\\\" stroke-width=\\\"0.2\\\"/>\\n\",\n              \"<path d=\\\"M264.873,48.6253 L289.303,5 M264.873,63.6253 L290.87,20.9154 M264.873,78.6253 L292.608,37.0228 M264.873,93.6253 L294.533,53.3725 M264.873,108.625 L296.658,70.0288 M264.873,123.625 L298.989,87.0725 M264.873,138.625 L301.513,104.603 M264.873,153.625 L304.189,122.734 M264.873,168.625 L306.932,141.587 M264.873,183.625 L309.594,161.265 M264.873,198.625 L311.96,181.808 M264.873,213.625 L313.763,203.149 M264.873,228.625 L314.746,225.063 M264.873,243.625 L314.746,247.188 M264.873,258.625 L313.763,269.102 M264.873,273.625 L311.96,290.442 M264.873,288.625 L309.594,310.986 M264.873,303.625 L306.932,330.663 M264.873,318.625 L304.189,349.516 M264.873,333.625 L301.513,367.648 M264.873,348.625 L298.989,385.178 M264.873,363.625 L296.658,402.222 M264.873,378.625 L294.533,418.878 M264.873,393.625 L292.608,435.228 M264.873,408.625 L290.87,451.335 M264.873,423.625 L289.303,467.251\\\" stroke=\\\"red\\\" fill=\\\"none\\\" stroke-width=\\\"0.2\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</svg>\"\n            ],\n            \"text/plain\": [\n              \"<svg viewBox=\\\"0 0 319.746 472.251\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<path d=\\\"M54.8729,48.6253 L30.4428,5 M54.8729,48.6253 L84.8729,48.6253 M54.8729,48.6253 L54.8729,63.6253 M84.8729,48.6253 L114.873,48.6253 M84.8729,48.6253 L84.8729,63.6253 M114.873,48.6253 L144.873,48.6253 M114.873,48.6253 L114.873,63.6253 M144.873,48.6253 L174.873,48.6253 M144.873,48.6253 L144.873,63.6253 M174.873,48.6253 L204.873,48.6253 M174.873,48.6253 L174.873,63.6253 M204.873,48.6253 L234.873,48.6253 M204.873,48.6253 L204.873,63.6253 M234.873,48.6253 L264.873,48.6253 M234.873,48.6253 L234.873,63.6253 M264.873,48.6253 L264.873,63.6253 M54.8729,63.6253 L28.8756,20.9154 M54.8729,63.6253 L84.8729,63.6253 M54.8729,63.6253 L54.8729,78.6253 M84.8729,63.6253 L114.873,63.6253 M84.8729,63.6253 L84.8729,78.6253 M114.873,63.6253 L144.873,63.6253 M114.873,63.6253 L114.873,78.6253 M144.873,63.6253 L174.873,63.6253 M144.873,63.6253 L144.873,78.6253 M174.873,63.6253 L204.873,63.6253 M174.873,63.6253 L174.873,78.6253 M204.873,63.6253 L234.873,63.6253 M204.873,63.6253 L204.873,78.6253 M234.873,63.6253 L264.873,63.6253 M234.873,63.6253 L234.873,78.6253 M264.873,63.6253 L264.873,78.6253 M54.8729,78.6253 L27.1379,37.0228 M54.8729,78.6253 L84.8729,78.6253 M54.8729,78.6253 L54.8729,93.6253 M84.8729,78.6253 L114.873,78.6253 M84.8729,78.6253 L84.8729,93.6253 M114.873,78.6253 L144.873,78.6253 M114.873,78.6253 L114.873,93.6253 M144.873,78.6253 L174.873,78.6253 M144.873,78.6253 L144.873,93.6253 M174.873,78.6253 L204.873,78.6253 M174.873,78.6253 L174.873,93.6253 M204.873,78.6253 L234.873,78.6253 M204.873,78.6253 L204.873,93.6253 M234.873,78.6253 L264.873,78.6253 M234.873,78.6253 L234.873,93.6253 M264.873,78.6253 L264.873,93.6253 M54.8729,93.6253 L25.213,53.3725 M54.8729,93.6253 L84.8729,93.6253 M54.8729,93.6253 L54.8729,108.625 M84.8729,93.6253 L114.873,93.6253 M84.8729,93.6253 L84.8729,108.625 M114.873,93.6253 L144.873,93.6253 M114.873,93.6253 L114.873,108.625 M144.873,93.6253 L174.873,93.6253 M144.873,93.6253 L144.873,108.625 M174.873,93.6253 L204.873,93.6253 M174.873,93.6253 L174.873,108.625 M204.873,93.6253 L234.873,93.6253 M204.873,93.6253 L204.873,108.625 M234.873,93.6253 L264.873,93.6253 M234.873,93.6253 L234.873,108.625 M264.873,93.6253 L264.873,108.625 M54.8729,108.625 L23.0876,70.0288 M54.8729,108.625 L84.8729,108.625 M54.8729,108.625 L54.8729,123.625 M84.8729,108.625 L114.873,108.625 M84.8729,108.625 L84.8729,123.625 M114.873,108.625 L144.873,108.625 M114.873,108.625 L114.873,123.625 M144.873,108.625 L174.873,108.625 M144.873,108.625 L144.873,123.625 M174.873,108.625 L204.873,108.625 M174.873,108.625 L174.873,123.625 M204.873,108.625 L234.873,108.625 M204.873,108.625 L204.873,123.625 M234.873,108.625 L264.873,108.625 M234.873,108.625 L234.873,123.625 M264.873,108.625 L264.873,123.625 M54.8729,123.625 L20.757,87.0725 M54.8729,123.625 L84.8729,123.625 M54.8729,123.625 L54.8729,138.625 M84.8729,123.625 L114.873,123.625 M84.8729,123.625 L84.8729,138.625 M114.873,123.625 L144.873,123.625 M114.873,123.625 L114.873,138.625 M144.873,123.625 L174.873,123.625 M144.873,123.625 L144.873,138.625 M174.873,123.625 L204.873,123.625 M174.873,123.625 L174.873,138.625 M204.873,123.625 L234.873,123.625 M204.873,123.625 L204.873,138.625 M234.873,123.625 L264.873,123.625 M234.873,123.625 L234.873,138.625 M264.873,123.625 L264.873,138.625 M54.8729,138.625 L18.2333,104.603 M54.8729,138.625 L84.8729,138.625 M54.8729,138.625 L54.8729,153.625 M84.8729,138.625 L114.873,138.625 M84.8729,138.625 L84.8729,153.625 M114.873,138.625 L144.873,138.625 M114.873,138.625 L114.873,153.625 M144.873,138.625 L174.873,138.625 M144.873,138.625 L144.873,153.625 M174.873,138.625 L204.873,138.625 M174.873,138.625 L174.873,153.625 M204.873,138.625 L234.873,138.625 M204.873,138.625 L204.873,153.625 M234.873,138.625 L264.873,138.625 M234.873,138.625 L234.873,153.625 M264.873,138.625 L264.873,153.625 M54.8729,153.625 L15.557,122.734 M54.8729,153.625 L84.8729,153.625 M54.8729,153.625 L54.8729,168.625 M84.8729,153.625 L114.873,153.625 M84.8729,153.625 L84.8729,168.625 M114.873,153.625 L144.873,153.625 M114.873,153.625 L114.873,168.625 M144.873,153.625 L174.873,153.625 M144.873,153.625 L144.873,168.625 M174.873,153.625 L204.873,153.625 M174.873,153.625 L174.873,168.625 M204.873,153.625 L234.873,153.625 M204.873,153.625 L204.873,168.625 M234.873,153.625 L264.873,153.625 M234.873,153.625 L234.873,168.625 M264.873,153.625 L264.873,168.625 M54.8729,168.625 L12.814,141.587 M54.8729,168.625 L84.8729,168.625 M54.8729,168.625 L54.8729,183.625 M84.8729,168.625 L114.873,168.625 M84.8729,168.625 L84.8729,183.625 M114.873,168.625 L144.873,168.625 M114.873,168.625 L114.873,183.625 M144.873,168.625 L174.873,168.625 M144.873,168.625 L144.873,183.625 M174.873,168.625 L204.873,168.625 M174.873,168.625 L174.873,183.625 M204.873,168.625 L234.873,168.625 M204.873,168.625 L204.873,183.625 M234.873,168.625 L264.873,168.625 M234.873,168.625 L234.873,183.625 M264.873,168.625 L264.873,183.625 M54.8729,183.625 L10.1516,161.265 M54.8729,183.625 L84.8729,183.625 M54.8729,183.625 L54.8729,198.625 M84.8729,183.625 L114.873,183.625 M84.8729,183.625 L84.8729,198.625 M114.873,183.625 L144.873,183.625 M114.873,183.625 L114.873,198.625 M144.873,183.625 L174.873,183.625 M144.873,183.625 L144.873,198.625 M174.873,183.625 L204.873,183.625 M174.873,183.625 L174.873,198.625 M204.873,183.625 L234.873,183.625 M204.873,183.625 L204.873,198.625 M234.873,183.625 L264.873,183.625 M234.873,183.625 L234.873,198.625 M264.873,183.625 L264.873,198.625 M54.8729,198.625 L7.78584,181.808 M54.8729,198.625 L84.8729,198.625 M54.8729,198.625 L54.8729,213.625 M84.8729,198.625 L114.873,198.625 M84.8729,198.625 L84.8729,213.625 M114.873,198.625 L144.873,198.625 M114.873,198.625 L114.873,213.625 M144.873,198.625 L174.873,198.625 M144.873,198.625 L144.873,213.625 M174.873,198.625 L204.873,198.625 M174.873,198.625 L174.873,213.625 M204.873,198.625 L234.873,198.625 M204.873,198.625 L204.873,213.625 M234.873,198.625 L264.873,198.625 M234.873,198.625 L234.873,213.625 M264.873,198.625 L264.873,213.625 M54.8729,213.625 L5.98281,203.149 M54.8729,213.625 L84.8729,213.625 M54.8729,213.625 L54.8729,228.625 M84.8729,213.625 L114.873,213.625 M84.8729,213.625 L84.8729,228.625 M114.873,213.625 L144.873,213.625 M114.873,213.625 L114.873,228.625 M144.873,213.625 L174.873,213.625 M144.873,213.625 L144.873,228.625 M174.873,213.625 L204.873,213.625 M174.873,213.625 L174.873,228.625 M204.873,213.625 L234.873,213.625 M204.873,213.625 L204.873,228.625 M234.873,213.625 L264.873,213.625 M234.873,213.625 L234.873,228.625 M264.873,213.625 L264.873,228.625 M54.8729,228.625 L5,225.063 M54.8729,228.625 L84.8729,228.625 M54.8729,228.625 L54.8729,243.625 M84.8729,228.625 L114.873,228.625 M84.8729,228.625 L84.8729,243.625 M114.873,228.625 L144.873,228.625 M114.873,228.625 L114.873,243.625 M144.873,228.625 L174.873,228.625 M144.873,228.625 L144.873,243.625 M174.873,228.625 L204.873,228.625 M174.873,228.625 L174.873,243.625 M204.873,228.625 L234.873,228.625 M204.873,228.625 L204.873,243.625 M234.873,228.625 L264.873,228.625 M234.873,228.625 L234.873,243.625 M264.873,228.625 L264.873,243.625 M54.8729,243.625 L5,247.188 M54.8729,243.625 L84.8729,243.625 M54.8729,243.625 L54.8729,258.625 M84.8729,243.625 L114.873,243.625 M84.8729,243.625 L84.8729,258.625 M114.873,243.625 L144.873,243.625 M114.873,243.625 L114.873,258.625 M144.873,243.625 L174.873,243.625 M144.873,243.625 L144.873,258.625 M174.873,243.625 L204.873,243.625 M174.873,243.625 L174.873,258.625 M204.873,243.625 L234.873,243.625 M204.873,243.625 L204.873,258.625 M234.873,243.625 L264.873,243.625 M234.873,243.625 L234.873,258.625 M264.873,243.625 L264.873,258.625 M54.8729,258.625 L5.98281,269.102 M54.8729,258.625 L84.8729,258.625 M54.8729,258.625 L54.8729,273.625 M84.8729,258.625 L114.873,258.625 M84.8729,258.625 L84.8729,273.625 M114.873,258.625 L144.873,258.625 M114.873,258.625 L114.873,273.625 M144.873,258.625 L174.873,258.625 M144.873,258.625 L144.873,273.625 M174.873,258.625 L204.873,258.625 M174.873,258.625 L174.873,273.625 M204.873,258.625 L234.873,258.625 M204.873,258.625 L204.873,273.625 M234.873,258.625 L264.873,258.625 M234.873,258.625 L234.873,273.625 M264.873,258.625 L264.873,273.625 M54.8729,273.625 L7.78584,290.442 M54.8729,273.625 L84.8729,273.625 M54.8729,273.625 L54.8729,288.625 M84.8729,273.625 L114.873,273.625 M84.8729,273.625 L84.8729,288.625 M114.873,273.625 L144.873,273.625 M114.873,273.625 L114.873,288.625 M144.873,273.625 L174.873,273.625 M144.873,273.625 L144.873,288.625 M174.873,273.625 L204.873,273.625 M174.873,273.625 L174.873,288.625 M204.873,273.625 L234.873,273.625 M204.873,273.625 L204.873,288.625 M234.873,273.625 L264.873,273.625 M234.873,273.625 L234.873,288.625 M264.873,273.625 L264.873,288.625 M54.8729,288.625 L10.1516,310.986 M54.8729,288.625 L84.8729,288.625 M54.8729,288.625 L54.8729,303.625 M84.8729,288.625 L114.873,288.625 M84.8729,288.625 L84.8729,303.625 M114.873,288.625 L144.873,288.625 M114.873,288.625 L114.873,303.625 M144.873,288.625 L174.873,288.625 M144.873,288.625 L144.873,303.625 M174.873,288.625 L204.873,288.625 M174.873,288.625 L174.873,303.625 M204.873,288.625 L234.873,288.625 M204.873,288.625 L204.873,303.625 M234.873,288.625 L264.873,288.625 M234.873,288.625 L234.873,303.625 M264.873,288.625 L264.873,303.625 M54.8729,303.625 L12.814,330.663 M54.8729,303.625 L84.8729,303.625 M54.8729,303.625 L54.8729,318.625 M84.8729,303.625 L114.873,303.625 M84.8729,303.625 L84.8729,318.625 M114.873,303.625 L144.873,303.625 M114.873,303.625 L114.873,318.625 M144.873,303.625 L174.873,303.625 M144.873,303.625 L144.873,318.625 M174.873,303.625 L204.873,303.625 M174.873,303.625 L174.873,318.625 M204.873,303.625 L234.873,303.625 M204.873,303.625 L204.873,318.625 M234.873,303.625 L264.873,303.625 M234.873,303.625 L234.873,318.625 M264.873,303.625 L264.873,318.625 M54.8729,318.625 L15.557,349.516 M54.8729,318.625 L84.8729,318.625 M54.8729,318.625 L54.8729,333.625 M84.8729,318.625 L114.873,318.625 M84.8729,318.625 L84.8729,333.625 M114.873,318.625 L144.873,318.625 M114.873,318.625 L114.873,333.625 M144.873,318.625 L174.873,318.625 M144.873,318.625 L144.873,333.625 M174.873,318.625 L204.873,318.625 M174.873,318.625 L174.873,333.625 M204.873,318.625 L234.873,318.625 M204.873,318.625 L204.873,333.625 M234.873,318.625 L264.873,318.625 M234.873,318.625 L234.873,333.625 M264.873,318.625 L264.873,333.625 M54.8729,333.625 L18.2333,367.648 M54.8729,333.625 L84.8729,333.625 M54.8729,333.625 L54.8729,348.625 M84.8729,333.625 L114.873,333.625 M84.8729,333.625 L84.8729,348.625 M114.873,333.625 L144.873,333.625 M114.873,333.625 L114.873,348.625 M144.873,333.625 L174.873,333.625 M144.873,333.625 L144.873,348.625 M174.873,333.625 L204.873,333.625 M174.873,333.625 L174.873,348.625 M204.873,333.625 L234.873,333.625 M204.873,333.625 L204.873,348.625 M234.873,333.625 L264.873,333.625 M234.873,333.625 L234.873,348.625 M264.873,333.625 L264.873,348.625 M54.8729,348.625 L20.757,385.178 M54.8729,348.625 L84.8729,348.625 M54.8729,348.625 L54.8729,363.625 M84.8729,348.625 L114.873,348.625 M84.8729,348.625 L84.8729,363.625 M114.873,348.625 L144.873,348.625 M114.873,348.625 L114.873,363.625 M144.873,348.625 L174.873,348.625 M144.873,348.625 L144.873,363.625 M174.873,348.625 L204.873,348.625 M174.873,348.625 L174.873,363.625 M204.873,348.625 L234.873,348.625 M204.873,348.625 L204.873,363.625 M234.873,348.625 L264.873,348.625 M234.873,348.625 L234.873,363.625 M264.873,348.625 L264.873,363.625 M54.8729,363.625 L23.0876,402.222 M54.8729,363.625 L84.8729,363.625 M54.8729,363.625 L54.8729,378.625 M84.8729,363.625 L114.873,363.625 M84.8729,363.625 L84.8729,378.625 M114.873,363.625 L144.873,363.625 M114.873,363.625 L114.873,378.625 M144.873,363.625 L174.873,363.625 M144.873,363.625 L144.873,378.625 M174.873,363.625 L204.873,363.625 M174.873,363.625 L174.873,378.625 M204.873,363.625 L234.873,363.625 M204.873,363.625 L204.873,378.625 M234.873,363.625 L264.873,363.625 M234.873,363.625 L234.873,378.625 M264.873,363.625 L264.873,378.625 M54.8729,378.625 L25.213,418.878 M54.8729,378.625 L84.8729,378.625 M54.8729,378.625 L54.8729,393.625 M84.8729,378.625 L114.873,378.625 M84.8729,378.625 L84.8729,393.625 M114.873,378.625 L144.873,378.625 M114.873,378.625 L114.873,393.625 M144.873,378.625 L174.873,378.625 M144.873,378.625 L144.873,393.625 M174.873,378.625 L204.873,378.625 M174.873,378.625 L174.873,393.625 M204.873,378.625 L234.873,378.625 M204.873,378.625 L204.873,393.625 M234.873,378.625 L264.873,378.625 M234.873,378.625 L234.873,393.625 M264.873,378.625 L264.873,393.625 M54.8729,393.625 L27.1379,435.228 M54.8729,393.625 L84.8729,393.625 M54.8729,393.625 L54.8729,408.625 M84.8729,393.625 L114.873,393.625 M84.8729,393.625 L84.8729,408.625 M114.873,393.625 L144.873,393.625 M114.873,393.625 L114.873,408.625 M144.873,393.625 L174.873,393.625 M144.873,393.625 L144.873,408.625 M174.873,393.625 L204.873,393.625 M174.873,393.625 L174.873,408.625 M204.873,393.625 L234.873,393.625 M204.873,393.625 L204.873,408.625 M234.873,393.625 L264.873,393.625 M234.873,393.625 L234.873,408.625 M264.873,393.625 L264.873,408.625 M54.8729,408.625 L28.8756,451.335 M54.8729,408.625 L84.8729,408.625 M54.8729,408.625 L54.8729,423.625 M84.8729,408.625 L114.873,408.625 M84.8729,408.625 L84.8729,423.625 M114.873,408.625 L144.873,408.625 M114.873,408.625 L114.873,423.625 M144.873,408.625 L174.873,408.625 M144.873,408.625 L144.873,423.625 M174.873,408.625 L204.873,408.625 M174.873,408.625 L174.873,423.625 M204.873,408.625 L234.873,408.625 M204.873,408.625 L204.873,423.625 M234.873,408.625 L264.873,408.625 M234.873,408.625 L234.873,423.625 M264.873,408.625 L264.873,423.625 M54.8729,423.625 L30.4428,467.251 M54.8729,423.625 L84.8729,423.625 M84.8729,423.625 L114.873,423.625 M114.873,423.625 L144.873,423.625 M144.873,423.625 L174.873,423.625 M174.873,423.625 L204.873,423.625 M204.873,423.625 L234.873,423.625 M234.873,423.625 L264.873,423.625\\\" stroke=\\\"black\\\" fill=\\\"none\\\" stroke-width=\\\"0.2\\\"/>\\n\",\n              \"<path d=\\\"M264.873,48.6253 L289.303,5 M264.873,63.6253 L290.87,20.9154 M264.873,78.6253 L292.608,37.0228 M264.873,93.6253 L294.533,53.3725 M264.873,108.625 L296.658,70.0288 M264.873,123.625 L298.989,87.0725 M264.873,138.625 L301.513,104.603 M264.873,153.625 L304.189,122.734 M264.873,168.625 L306.932,141.587 M264.873,183.625 L309.594,161.265 M264.873,198.625 L311.96,181.808 M264.873,213.625 L313.763,203.149 M264.873,228.625 L314.746,225.063 M264.873,243.625 L314.746,247.188 M264.873,258.625 L313.763,269.102 M264.873,273.625 L311.96,290.442 M264.873,288.625 L309.594,310.986 M264.873,303.625 L306.932,330.663 M264.873,318.625 L304.189,349.516 M264.873,333.625 L301.513,367.648 M264.873,348.625 L298.989,385.178 M264.873,363.625 L296.658,402.222 M264.873,378.625 L294.533,418.878 M264.873,393.625 L292.608,435.228 M264.873,408.625 L290.87,451.335 M264.873,423.625 L289.303,467.251\\\" stroke=\\\"red\\\" fill=\\\"none\\\" stroke-width=\\\"0.2\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"48.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"63.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"78.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"93.6253\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"108.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"123.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"138.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"153.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"168.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"183.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"198.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"213.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"228.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"243.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"258.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"273.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"288.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"303.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"318.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"333.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"348.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"363.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"378.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"393.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"408.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"54.8729\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"84.8729\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"114.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"144.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"174.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"204.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"234.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"264.873\\\" cy=\\\"423.625\\\" r=\\\"0.5\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</svg>\"\n            ]\n          },\n          \"execution_count\": 18,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"dem.diagram(\\\"matchgraph-svg\\\")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"fLY3a5w9PT1L\"\n      },\n      \"source\": [\n        \"In the diagram above, each node is a detector and each edge is an error mechanism. The matcher is going to decode errors by trying to match each excited node to another nearby excited node, or to the side boundaries, which minimizes the number of edges that were used.\\n\",\n        \"\\n\",\n        \"The detector error model format is easier for decoders to consume than a raw circuit, because everything is explained in terms of observable symptoms and hidden symptoms, which is how decoders usually conceptualize the problem space.\\n\",\n        \"For example, some decoders can be configured using a weighted graph, and [`stim.DetectorErrorModel`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.DetectorErrorModel) is effectively just a weighted graph.\\n\",\n        \"It might be a pain to write the glue code that converts the [`stim.DetectorErrorModel`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.DetectorErrorModel) into exactly the right kind of graph expected by the decoder, but it's much easier than starting from the circuit or generating the graph from scratch – and you only have to write that code once instead of once per circuit.\\n\",\n        \"\\n\",\n        \"For this tutorial, you'll use existing packages instead of writing your own glue code.\\n\",\n        \"Specifically, you'll use the open-source package [PyMatching](https://github.com/oscarhiggott/PyMatching) as your decoder.\\n\",\n        \"PyMatching is a minimum-weight perfect matching decoder written by Oscar Higgott.\\n\",\n        \"You can install it using `pip install pymatching`:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"xlH-hxBRPjNy\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!pip install pymatching~=2.0\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"cx7UkBiYQeOz\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"import pymatching\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"ewrxiwXMQ-Yz\"\n      },\n      \"source\": [\n        \"Now you're going to write a method that will sample a circuit using Stim, decode it using PyMatching, and count how often it gets the right answer.\\n\",\n        \"\\n\",\n        \"First, you sample detection events and observable flips from the circuit.\\n\",\n        \"You do this by creating a sampler with [`circuit.compile_detector_sampler()`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.compile_detector_sampler) and then calling [`sampler.sample(shots, separate_observables=True)`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.CompiledDetectorSampler.sample).\\n\",\n        \"The `separate_observables=True` argument is saying that you want the result of the method to be a tuple where the first entry is detection event data to give to the decoder and the second entry is the observable flip data the decoder is supposed to predict.\\n\",\n        \"\\n\",\n        \"Second, you extract decoder information by using [`stim.Circuit.detector_error_model(...)`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.detector_error_model) and create a decoder from this information using [`pymatching.Matching.from_detector_error_model`](https://pymatching.readthedocs.io/en/latest/api.html#pymatching.matching.Matching.from_detector_error_model).\\n\",\n        \"\\n\",\n        \"Third, you run `matching.predict` to get the predicted observable flips.\\n\",\n        \"\\n\",\n        \"Fourth, you compare the predictions made by PyMatching to the actual observable flip data that was sampled.\\n\",\n        \"Anytime the prediction differs, it indicates a logical error.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"32hBrUAQRbSc\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"def count_logical_errors(circuit: stim.Circuit, num_shots: int) -> int:\\n\",\n        \"    # Sample the circuit.\\n\",\n        \"    sampler = circuit.compile_detector_sampler()\\n\",\n        \"    detection_events, observable_flips = sampler.sample(num_shots, separate_observables=True)\\n\",\n        \"\\n\",\n        \"    # Configure a decoder using the circuit.\\n\",\n        \"    detector_error_model = circuit.detector_error_model(decompose_errors=True)\\n\",\n        \"    matcher = pymatching.Matching.from_detector_error_model(detector_error_model)\\n\",\n        \"\\n\",\n        \"    # Run the decoder.\\n\",\n        \"    predictions = matcher.decode_batch(detection_events)\\n\",\n        \"\\n\",\n        \"    # Count the mistakes.\\n\",\n        \"    num_errors = 0\\n\",\n        \"    for shot in range(num_shots):\\n\",\n        \"        actual_for_shot = observable_flips[shot]\\n\",\n        \"        predicted_for_shot = predictions[shot]\\n\",\n        \"        if not np.array_equal(actual_for_shot, predicted_for_shot):\\n\",\n        \"            num_errors += 1\\n\",\n        \"    return num_errors\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"gVvL0sbLSi4R\"\n      },\n      \"source\": [\n        \"You can try this method on the repetition code circuit:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"D93VJhBVS1Cn\",\n        \"outputId\": \"abeb4610-b2ac-47fc-ae4d-eba90403e095\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"there were 5 wrong predictions (logical errors) out of 100000 shots\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"circuit = stim.Circuit.generated(\\\"repetition_code:memory\\\", rounds=100, distance=9, before_round_data_depolarization=0.03)\\n\",\n        \"num_shots = 100_000\\n\",\n        \"num_logical_errors = count_logical_errors(circuit, num_shots)\\n\",\n        \"print(\\\"there were\\\", num_logical_errors, \\\"wrong predictions (logical errors) out of\\\", num_shots, \\\"shots\\\")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"jRbSSRC2TcBA\"\n      },\n      \"source\": [\n        \"You can check that increasing the physical noise strength increases the logical error rate.\\n\",\n        \"Try increasing the between-round depolarization strength to 13%:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"MLHl2S91Tnpi\",\n        \"outputId\": \"801e1e00-4ca7-4783-b556-cef8f180a110\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"there were 1234 wrong predictions (logical errors) out of 10000 shots\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"circuit = stim.Circuit.generated(\\n\",\n        \"    \\\"repetition_code:memory\\\",\\n\",\n        \"    rounds=100,\\n\",\n        \"    distance=9,\\n\",\n        \"    before_round_data_depolarization=0.13,\\n\",\n        \"    before_measure_flip_probability=0.01)\\n\",\n        \"num_shots = 10_000\\n\",\n        \"num_logical_errors = count_logical_errors(circuit, num_shots)\\n\",\n        \"print(\\\"there were\\\", num_logical_errors, \\\"wrong predictions (logical errors) out of\\\", num_shots, \\\"shots\\\")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"j2WD8EIIYSsO\"\n      },\n      \"source\": [\n        \"As you can see, you get a lot more wrong predictions with this higher noise strength.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"pJt8euOoT1kQ\"\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"rep-code\\\"></a>\\n\",\n        \"# 7. Estimate the threshold of a repetition code using Monte Carlo sampling\\n\",\n        \"\\n\",\n        \"Estimating the threshold of an error correcting code really just comes down to trying a bunch of physical error rates and code distances.\\n\",\n        \"You plot out the logical error rate vs physical error rate curve for each distance, and see where the curves cross.\\n\",\n        \"That's where the physical error rate gets bad enough that increasing the distance starts to make the logical error rate worse, instead of better.\\n\",\n        \"That's the threshold physical error rate.\\n\",\n        \"\\n\",\n        \"You can estimate the threshold of the repetition code, for the specific type of noise you're using, by plotting the logical error rate at various code distances and physical error rates:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\",\n          \"height\": 283\n        },\n        \"id\": \"qkWlL6pwT5xc\",\n        \"outputId\": \"cfd36225-8a66-4ce1-9c9c-79861041fb91\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/png\": \"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\",\n            \"text/plain\": [\n              \"<Figure size 640x480 with 1 Axes>\"\n            ]\n          },\n          \"metadata\": {},\n          \"output_type\": \"display_data\"\n        }\n      ],\n      \"source\": [\n        \"import matplotlib.pyplot as plt\\n\",\n        \"\\n\",\n        \"num_shots = 10_000\\n\",\n        \"for d in [3, 5, 7]:\\n\",\n        \"    xs = []\\n\",\n        \"    ys = []\\n\",\n        \"    for noise in [0.1, 0.2, 0.3, 0.4, 0.5]:\\n\",\n        \"        circuit = stim.Circuit.generated(\\n\",\n        \"            \\\"repetition_code:memory\\\",\\n\",\n        \"            rounds=d * 3,\\n\",\n        \"            distance=d,\\n\",\n        \"            before_round_data_depolarization=noise)\\n\",\n        \"        num_errors_sampled = count_logical_errors(circuit, num_shots)\\n\",\n        \"        xs.append(noise)\\n\",\n        \"        ys.append(num_errors_sampled / num_shots)\\n\",\n        \"    plt.plot(xs, ys, label=\\\"d=\\\" + str(d))\\n\",\n        \"plt.loglog()\\n\",\n        \"plt.xlabel(\\\"physical error rate\\\")\\n\",\n        \"plt.ylabel(\\\"logical error rate per shot\\\")\\n\",\n        \"plt.legend()\\n\",\n        \"plt.show()\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"J5TZ-AlJVGmk\"\n      },\n      \"source\": [\n        \"From the results here you can see that the repetition code has amazingly good performance! Well... it's not *quite* so amazing when you remember that you're using a phenomenological noise model (instead of a circuit-level noise model) and also that you're inserting depolarizing errors instead of bit-flip errors (the repetition code is immune to Z errors, and when a depolarizing error occurs it's a Z error one third of the time).\\n\",\n        \"\\n\",\n        \"Still, you can see that it's not so hard to run a few different cases and plot them out. A bit tedious, maybe.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"c88KJx_mVhZU\"\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"use-sinter\\\"></a>\\n\",\n        \"# 8. Use `sinter` to streamline the Monte Carlo sampling process\\n\",\n        \"\\n\",\n        \"Now that you understand the basic workflow of sampling from a circuit, making a decoder predict the observable flips, and plotting out the result, you probably never want to do that by hand ever again. And that's without even getting into dividing work into batches, or across multiple CPU cores!\\n\",\n        \"\\n\",\n        \"Fortunately, you can use [Sinter](https://pypi.org/project/sinter/) to do almost the entire thing for you. Install Sinter using `pip install sinter`:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"ogUrK7LhZyV-\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"!pip install sinter~=1.14\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"VrayGWt0-qOW\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"import sinter\\n\",\n        \"from typing import List\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"dxTADjNX-qOW\"\n      },\n      \"source\": [\n        \"Wrap your circuits into [`sinter.Task`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.Task) instances, and give those tasks to [`sinter.collect`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.collect).\\n\",\n        \"Sinter will spin up multiple worker processes to sample from and decode these circuits.\\n\",\n        \"[`sinter.collect`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.collect) takes a variety of useful options, such as the maximum number of shots or errors to take from each task, as well as the number of workers to use:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"4HmwlVCz-qOW\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"tasks = [\\n\",\n        \"    sinter.Task(\\n\",\n        \"        circuit=stim.Circuit.generated(\\n\",\n        \"            \\\"repetition_code:memory\\\",\\n\",\n        \"            rounds=d * 3,\\n\",\n        \"            distance=d,\\n\",\n        \"            before_round_data_depolarization=noise,\\n\",\n        \"        ),\\n\",\n        \"        json_metadata={'d': d, 'p': noise},\\n\",\n        \"    )\\n\",\n        \"    for d in [3, 5, 7, 9]\\n\",\n        \"    for noise in [0.05, 0.08, 0.1, 0.2, 0.3, 0.4, 0.5]\\n\",\n        \"]\\n\",\n        \"\\n\",\n        \"collected_stats: List[sinter.TaskStats] = sinter.collect(\\n\",\n        \"    num_workers=4,\\n\",\n        \"    tasks=tasks,\\n\",\n        \"    decoders=['pymatching'],\\n\",\n        \"    max_shots=100_000,\\n\",\n        \"    max_errors=500,\\n\",\n        \")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"mVDInHcUbAc0\"\n      },\n      \"source\": [\n        \"Sinter also has a [`sinter.plot_error_rate`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.plot_error_rate) method which can be used to plot the logical error rates. This method automatically adds highlighted regions quantifying uncertainty in the estimates.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\",\n          \"height\": 484\n        },\n        \"id\": \"ZOsb01E0bFhw\",\n        \"outputId\": \"ceb5a5c3-bb97-4da1-c186-024ad0f5bc92\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAArcAAAIkCAYAAAAEbwOaAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAABJ0AAASdAHeZh94AAEAAElEQVR4nOydd5xcZb3/36dML9t7NtkUEkIIoYXea4RQBASli1IuKhd/16siegmWe+WCosIFQaSIKCBSBEWkhF4SCAQIBEJ62c32Mv2U5/fHmZnd2ZndnU3ZbMLzzmte2TnnOc/znDJnvvM93+/nqwghBBKJRCKRSCQSyS6AuqMnIJFIJBKJRCKRbCukcSuRSCQSiUQi2WWQxq1EIpFIJBKJZJdBGrcSiUQikUgkkl0GadxKJBKJRCKRSHYZpHErkUgkEolEItllkMatRCKRSCQSiWSXQRq3EolEIpFIJJJdBmncSiQSiUQikUh2GaRxK5FIJBKJRCLZZZDGrUQikUgkEolkl0Eat5KdjqOOOgpFUUa1zb333ouiKNx7773bZ1I7MYqicNRRR+3oaUh2Ujo6OigvL+fKK6/cqn4uvvhiFEVhzZo122Ziku3GggULUBSFF198cczHHuv71Zo1a1AUhYsvvnjMxhwNY3k8hBDMmTOHww8/fEzG2xqkcbsLoShKzkvTNMrLyznqqKO49957EULs6CkWxZZ8yb344osoisKCBQu227y2F7Zt88gjj3DmmWfS2NiI1+slEAgwc+ZMLrvsMl577bUdPcWtInM+h3uN1y+Okch88Q186bpOdXU18+bN44knntgm4+xIY2IkrrvuOuLxOD/84Q9zlmfmPPDl8/mYPn063/jGN9iwYcMOmrFEsv0YeE848MADh2ynKAoTJkwYw5ltPYqi8OMf/5hXX32VRx55ZEdPZ1j0HT0BybbnuuuuA8AwDD777DMee+wxXnrpJd5++21uvfXWHTy7recPf/gDsVhsVNt88Ytf5KCDDqKurm47zWrLaGlp4ayzzuK1114jFApx/PHHM3XqVIQQrFixgj//+c/87ne/45ZbbuGb3/zmjp7uVnHaaaex9957F1w31PKdhZKSEq6++moAkskky5Yt46mnnuKZZ57hxhtv5Dvf+c6OneB2Yt26ddxxxx189atfpb6+vmCbI488MutZam9v51//+he33XYbDz/8MG+++SZTp04dwxlLdnY+/vhj/H7/jp5GUSxatIgHH3yQL3/5y9ttjLE+HqeddhozZ87k2muv5cwzzxz1U9SxQhq3uyCDvZevvfYaRxxxBLfddhv/8R//weTJk3fMxLYREydOHPU2JSUllJSUbIfZbDmxWIx58+axdOlSvvzlL3PbbbdRVlaW06a3t5ebbrqJnp6eHTTLbcfpp5++03poR6K0tDTvc/fggw/yla98heuuu44rr7xyp/lCHg133HEHpmkOe16POuqonGNjGAZf+MIXeP755/npT3/KPffcs/0nKtll2H333Xf0FIpi4sSJNDc384Mf/IAzzjgDt9u9XcbZEcfjoosu4vvf/z7PP/88xx133JiPXwwyLOFzwKGHHsruu++OEIJ33nknb/1bb73FWWedRW1tLW63m8bGRi6//HI2bdqU1zYT75pMJvnhD3/I5MmT8Xg8TJ06leuvv55UKlVwDsuXL+fiiy+msbERt9tNTU0N5557Lp988klOO0VRuO+++wCYPHly9vFOU1NT3hwyXHzxxRx99NEAXH/99TmPQTOPcYeLuX3nnXc488wzqa6uxuPxMGnSJK688kqam5vz2g4MmbjjjjuYPXs2Xq+XmpoaLrvsslEZoTfffDNLly7l0EMP5YEHHsgzbAHC4TA//vGP8zx/PT09XHPNNcyYMQOv10tZWRknnngizz33XMGxUqkUP/nJT5g6dSoej4fJkyfzwx/+kGQyOeT8TNPktttu46CDDiIcDuP3+9lnn3249dZbsW276P0cLQNj3D799FPOOeccqqurUVWVF198ccT14IR6/Pa3v2Xu3LkEg0ECgQBz587l9ttvLzj3TNxaS0sLX//612loaEDTtK2K0T7nnHMIBALEYjE++uijnHULFy7ksssuY4899iAcDuPz+dhzzz25/vrrSSQSOW2bmpq4/vrrATj66KNzru+BxGIx/ud//oe9996bQCBAMBjk4IMP5s9//nPe3IQQ3HfffRxyyCFUVVXh9XppbGzkxBNP5KGHHipq/4QQ3HPPPTQ2NnLIIYcUfVxcLheXXXYZ4Hi2CjGaz9aGDRv45je/yZQpU/B4PFRUVHDqqaeyePHivLYDwzseeeQRDjjgAPx+P+Xl5Xz5y19m48aNBcdYsWIFF154IQ0NDbjdburr67nwwgtZsWLFsGP8+c9/Zr/99sPv91NfX8//+3//L/uZe+GFFzjqqKMIh8OUlZVxwQUX0NHRsVPs43A8//zzzJs3j/LycjweD9OnT+f73//+kOdv8eLFnHDCCYRCIcLhMMcddxxvvPHGkKE4Q8WYWpbFb3/7Ww499FBKSkrw+XxMmzaNr3/96zn7sGnTJn784x9z6KGHZr/z6uvrOffcc/M+p1tDY2MjV155JatXr+aWW24perstvXcNpK+vj5/85CfsueeehMNhQqEQU6dO5ZxzztlqGwDIeqJ///vfF71fY4303H7OcLlcOe/vvvtuLrvsMjweD6eeeiqNjY2sWLGCu+66iyeffJI333yzoKf07LPPZvHixZx11lm4XC6eeOIJFixYwNtvv83f/va3nC/ef/7zn5xxxhkYhsEpp5zCtGnT2LBhA48++ih///vfWbhwIfvuuy/ghFQ8/vjjLF26lH//93+ntLQUIPt/IU4//XQA7rvvvpxHoECOUVyIp556ijPPPBMhBGeddRaTJk3inXfe4fbbb+eJJ57g1VdfLejp/u53v8szzzzDKaecwgknnMDChQv53e9+x2effcYLL7ww7JgZ7rzzTgB+9KMfoarD/870eDzZv7u7uzn00EP56KOPmDt3LldffTXt7e08/PDDnHDCCdx+++1cfvnl2fZCCM4++2yeeOIJpk6dyje/+U1SqRR33303H3zwQcHxMufqmWeeYcaMGZx77rl4vV4WLlzIt771Ld566y3uv//+ovZzS1m5ciUHHngg06dP57zzziMejxMOh4taf8EFF/CnP/2JxsZGvv71r6MoCo899hhXXnklr776Kg888EDeeJ2dnRx00EEEg0HOOOMMVFWlpqZmm+zL4M/dDTfcwPLlyznkkEM4+eSTSSQSvPbaayxYsIAXX3yR5557Dk3TALj66qt5/PHHeemll7jooosKXtPd3d0cc8wxvPvuu+y7775ccskl2LbNM888w7nnnsuyZcv46U9/mm1/7bXX8j//8z9MnjyZs88+m5KSEpqbm1m8eDF/+ctfOOecc0bcp2XLltHc3LxFj1wz8f+FHmmO5rO1ZMkSTjjhBDo7OznxxBM544wzaG9v5/HHH+ewww7jscce46STTsob47bbbuNvf/sbp556KkceeSRvvfUWDz30EEuXLuW9997L+bwtXryY4447jr6+Pk499VT22GMPli9fzh//+EeeeOIJnnvuOebOnZs3xi233MLTTz/N6aefzlFHHcW//vUvbr75Zjo7OznttNP48pe/zMknn8xll13G66+/zh//+Efa29t5+umnd5p9HMwdd9zBv/3bvxEIBPjSl75EdXU1L774IjfccANPPvkkr732Ws69/OWXX+aEE07AsizOOOMMpk6dygcffMDRRx/NMcccM+J4GVKpFPPnz+fZZ5+lsbGRc889l3A4zJo1a3jsscc47LDD2G233bJj/vznP+foo4/mzDPPJBgMsmLFCh555BH+9re/8dprrzFnzpyixx6O//qv/+K+++7jZz/7GV/96lcpLy8fcZstuXcNRAjBvHnzeP311zn44IP5+te/jq7rbNiwgYULF3L44Yez3377ZdtviQ0wadIkGhoaeO655xBCjM/QBCHZZQBEoVP60ksvCVVVhdvtFps2bcou/+STT4TL5RJTp04VGzZsyNnmueeeE6qqitNPPz1n+ZFHHikAsdtuu4nOzs7s8ng8Lg466CABiD/84Q/Z5Z2dnaK0tFRUVFSIZcuW5fT1wQcfiEAgIPbZZ5+c5RdddJEAxOrVqwvuZ2YOA1m4cKEAxHXXXVdwm3vuuUcA4p577sku6+vrE+Xl5UJVVfHyyy/ntP/5z38uAHH88ccXnFtjY6NYu3ZtdrlhGOLwww8XgHjrrbcKzmEg69atE4DQdV3E4/ER2w/ksssuE4C47LLLhG3b2eWffvqpCIfDwu125xy7Bx54QADioIMOyhmro6NDTJkyRQDiyCOPzBnjuuuuE4D45je/KUzTzC43TVNccsklAhCPP/54UfPNHLPTTjtNXHfddQVfH3/8cbb96tWrs9fyNddck9ffSOv/9Kc/CUDss88+oq+vL7s8EomI/fbbTwDigQceyNkm098FF1wgDMMoar8GzmXSpEl56+6//34BiKqqqrxzvHLlypxzl+GHP/yhAMSDDz6YszxzPhYuXFhwHpljfMMNN+Qsj8fj4sQTTxSKooh33303u7y8vFw0NDSIaDSa11dbW9sQe5vL7bffLgBx0003FVyfmfPgz6RhGOKYY44RgLjkkkvy9qHYz5ZhGGLq1KnC4/GIF198MWeMjRs3ivr6elFbWysSiUTenEKhkHj//fdztvnKV74iAPHQQw9ll9m2LXbffXcBiD/+8Y857R988EEBiBkz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0003AU7M4nnnnUdfXx8/+tGPctquXLmS3/zmN7hcLi644ILs8sz5uPbaa3MeIXd2dhaMqdV1nW9961s0Nzdz1VVXZR8/DaS5uXmbakJuSy655BIArrnmmpxKdrFYjO9///sAfO1rXxuTufzkJz8BnEfzmbi+jJTX4Ot+1apV2UeIgxnu+q6urua8887j7bff5ic/+UlBA3jlypWsXr0acH4oFSrpbBgGnZ2dAEUVnDj88MPRNC3vszNWnHbaaUydOpX/+7//4x//+EfBNm+88caoqxkO5NBDD2XGjBkFy40+8sgjvPLKK0yfPr1g3Oi2YGfax/PPPx+Xy8Utt9yS/QGX4Uc/+hG9vb2cf/752ScChx56KFOnTmXhwoV58md33nlnUfG24Pzwu/LKK4nH41xxxRV5IQWpVIq2tjbA+az4/X7eeeednEfthmHw7//+79s9fvSGG25A1/XsfWgw2+LetXr1alatWpW3vKuri2QymRNGsKU2QDKZ5L333mOfffYZVqZzRyLDEj4nNDQ0cMUVV/DrX/+a//3f/+V//ud/2H333bn77ru55JJLmDVrFvPmzWP69OkYhsG6det45ZVXqKqqKuiZmTlzJrNmzcrRuV25ciUnn3xyjmFVUVHBI488ki1/e+yxxzJr1iwURWH9+vW88cYb2bjTDMceeyw33ngjl156KWeeeSahUIjS0tJhy8/OmDGDhoYGHnzwQVwuF5MmTUJRFC644AImTZpUcJtgMMjdd9/Nl770JY488ki+9KUvMXHiRN555x3+9a9/UVtbyx133LEVR314/H4///znPznrrLN44IEHePLJJ3PK73722Wc8//zz9Pb25pRN/vnPf84rr7zCrbfeyuLFizn66KOzOrd9fX3ceuutOdq8X/nKV3jooYf429/+xp577slpp52GYRg88sgjzJ07l5UrV+bN7Uc/+hFLly7lt7/9LU8++STHHHMMDQ0NtLa2smLFCl577TV+9rOfjSoJ8PHHH8/GpQ6mqalpm1UvO/fcc3niiSd4+OGHmTVrFqeffno2nm716tWcc845nHfeedtkrJHYf//9Oe2003jiiSf4/e9/z+WXX57Vev7lL3/JBx98wD777MO6det46qmnOPnkkwsasEcffTSqqnLNNdfw4YcfZpO4fvjDHwJw6623smLFCv7rv/6L+++/n8MOO4yamho2bdrExx9/zOLFi/nzn//M5MmTicfjHHbYYUybNo399tuPSZMmkUgkePbZZ/n444859dRTs9614SgpKeHYY4/lxRdfpKura8TEsm2Ny+Xi0Ucf5cQTT+Tkk0/mkEMOYe+998bv97N+/XoWL17MqlWraG5u3uLqcJmiMscffzznnHMOp512GrvvvjuffPIJjz/+OKFQiD/84Q8j6lRvKTvTPjY1NfGrX/2Kb3zjG+y7776cffbZVFVV8dJLL/HGG2+w++67c8MNN2Tbq6rKXXfdxbx58zj11FM588wzmTp1Ku+//z7PPvssX/jCF3j66aeLOrbXXXcdb731Fk8++STTp09n/vz5hEIh1q9fz7/+9S9uvPFGLr74YlRV5aqrruLnP/85s2fP5rTTTiOVSrFw4UI6Ozs5+uijs57q7cGMGTO47LLLuO222wqu3xb3rqVLl3LGGWcwd+5cZs6cSX19PW1tbTzxxBMYhpHzA3pLbYAXX3yRVCrFmWeeufUHZXuxg9UaJNsQKKxzm6GlpUX4/X7h9/tFS0tLdvn7778vLrroIjFx4kThdrtFWVmZmDVrlrjsssvE888/n9NHRoYrkUiIa6+9NitxMnnyZLFgwYIhpYVWr14tvvGNb4hp06YJj8cjQqGQmDFjhjj//PNzZKAy/OIXvxC77767cLvdgkE6ooWkwIQQYtGiReKYY44R4XBYKIqSIyNTSAps4Hann366qKysFC6XSzQ2NoorrriioKzMcDJlI8mRDYVlWeLhhx8WX/ziF0VDQ4PweDzC5/OJGTNmiK997Wvitddey9umq6tLfPe73xXTpk0TbrdblJSUiOOOO66ghIwQjoTY9ddfLyZPnizcbreYNGmS+MEPfiASiUSelEwG27bFH/7wB3HMMceIsrIy4XK5RH19vTj00EPFz372M7Fu3bqi9q8YKbCB448kvVOMNI9lWeL//u//xH777Sd8Pp/w+Xxi3333FbfeemuOXmeGoY7BSAync5vhvffeE4qiiIaGhqze7bp168S5554r6uvrhdfrFXvssYe44YYbhGEYQ87l/vvvF3PmzBFer7fgZz2ZTIpbbrlFHHzwwVm948bGRnHMMceIm2++WbS3twshhEilUuKGG24Q8+bNE42NjcLj8YjKykpx4IEHittvv10kk8mi9z8jVXXbbbflrRtK53YotvSztXnzZvG9731PzJo1S/h8PhEIBMS0adPEmWeeKe6///4cObvhJNWGu66WL18uzj//fFFbWyt0XRe1tbXivPPOE8uXLx9yvwuNMdx9aFfZx2eeeUYcf/zxorS0VLjdbjF16lTxn//5n6KrqyuvrRBCvPnmm+K4444TwWBQBINBceyxx4rXX39dfOMb3xCQq/srxNCfVcMwxC233CLmzp0rAoGA8Pv9Ytq0aeLSSy8VK1asyGn3i1/8QsycOVN4vV5RU1Mjzj//fLFmzZqC1+DWSoENprW1VYTD4YJSYEJs/b1r/fr14pprrhGHHHKIqKmpEW63WzQ0NIh58+bl6QlnGI0NIISjl7wl0oljiSLEAP0ZiWQEjjrqKF566SXkZSORSCzLYvbs2bjdbt59993xWalIslNy6KGH8tZbb9HT00MgENjR05GkaW1tpampiXPPPZe77rprR09nSGTMbQHa2to4+eSTCQQCzJgxg+eff35HT0kikUjGHZqmcdNNN7F06dIdqqwh2TmJxWIFcw3uvfdeXn/9dU444QRp2I4z/vu//xtN07L5BOMVGXNbgG984xvU1tbS1tbGc889x9lnn82KFSuKqgstkUgknydOOukkfv3rX4+odyuRDGbdunXss88+HH/88UybNg3TNHn33Xd59dVXKS0t5Re/+MWOnqJkAEII6urquP/++7dZkYvthQxLGEQkEqG8vJxVq1YxYcIEwHkUf9FFF+VV+Po8IsMSJBKJRLIt6Orq4j//8z956aWXaGlpIZlMUltby3HHHce1117L1KlTd/QUJTspO31YQiQS4brrrmPevHmUl5ejKAr33ntvwbbJZJLvfe971NfX4/P5OPDAA3n22Wdz2qxYsYJgMJg1bAFmz57NsmXLtudu7DS8+OKL0rCVSCQSyVZTVlbGXXfdxYoVK+jr6yOVSrFu3TruvvtuadhKtoqd3rhtb2/nxz/+MR9//DFz5swZtu3FF1/ML3/5S8477zx+/etfo2kaJ510Uo6IdCQSyavUEQ6Hd0h5WIlEIpFIJBLJ6NjpY27r6upobm6mtraWt99+m7lz5xZst2jRIh588EFuvPFGvvOd7wBw4YUXsueee/Ld7343Ww0lGAzS29ubs21vb2+2FrNEIpFIJBKJZPyy03tuPR4PtbW1I7Z75JFH0DQtW/IUwOv18rWvfY033niD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BQvIzs5m8eLFbNu2jYceeogrr7ySP/7xjwD89Kc/5fe//z3vvPMOJ510Uvd2jY2NvP/++yxevLjPY3o8Hg4//HA2bdrExRdfzH777UdzczNvvvkmtbW15OXl4Xa7eeqpp5g7dy6XXnopnZ2drFy5kuOPP55169YxY8aMAT1fn8/XnUDvLCsrC7P5+38KNm/ezNy5c7nsssu49NJLeyTrd9xxB1arleuuu45gMIjVauWZZ57hoosu4sADD+See+7B6XSybNky/vnPf7J+/XqysrK6t1dVleOPP57DDjuM+++/f0DlINu2bQMgOzu7e1k05yw/P59HH32Uyy+/nNNOO43TTz8dgH333ReAjRs38sMf/pDS0lJuuukmHA4HL730Eqeeeiqvvvoqp512WsyxCiHiRBdCiCT29NNP64D+3nvv6S6XS6+pqdFffPFFPTc3V7fb7XptbW2P9Y477jg9HA53b3/NNdfoJpNJb29v13Vd1zVN08vKyvSzzz67x3EeeOAB3WAw6N999133ssrKSv3CCy/s/n3RokU6oL/22mu7xdl1TFVV9WAw2OOxtrY2vbCwUL/44ot7LAf0xYsX9/v8t27dqgN9/nz44Yc94gX0v/3tbz32sXr1ah3Qx48fr/t8vu7loVBILygo0KdNm6b7/f7u5W+//bYO6IsWLepeduGFF+qAftNNN/Ubb5fertsrr7yi5+fn6zabTa+pqeleN9pz5nK5+jxnxx57rL7PPvvogUCge1k4HNYPPfRQfa+99ooqZiFEYpA7t0KIMeG4447r8XtlZSV/+MMfKC0t7bF8/vz5GAyG7t8PP/xwHnzwQbZv386+++6L0WjkvPPOY/ny5XR2dpKeng7AH/7wBw499FDGjRvXZwyvvvoq06dP7/UuYNcxTSYTJpMJgHA4THt7O+FwmAMOOIBPP/10YE9+x/M688wzd1s+ZcqUHr+PGzeO448/vtd9XHjhhT3qb//973/T1NTEkiVLegzumj17NpMnT+bPf/5z9wCuLpdffnlMce963aqqqnjuuecoKyvrXjbYc9ba2sr777/P7bffTmdnJ52dnd2PHX/88SxevJi6urrdXitCiMQkya0QYkx4+OGHmTRpEmazmcLCQvbee+9eB0NVVFT0+L3r6++2trbuZRdccAH33nsvr7/+OhdccAGbN2/mP//5D4899li/MXz77becccYZe4x11apV/OY3v+Grr77qUdvbX+K8J3vttdduiWJv+jvGro9t374doEfpQpfJkyezdu3aHsvMZnOPpDQaXdeto6OD3/3ud3zwwQe9DtQbzDnbsmULuq6zcOFCFi5c2Os6TU1NktwKMUpIciuEGBNmzZrVPeq+P113AHel63r3/0+ZMoX999+f5557jgsuuIDnnnsOq9U6JKP3n3vuOebNm8epp57K9ddfT0FBASaTiXvuuafHIKrh0ltnhGgei4bNZou5u8LO1+3UU0/lsMMO49xzz2Xz5s2kpaUBgz9n4XAYgOuuu67Pu9YTJ06MKW4hRPxIciuEEANwwQUXcO2119LQ0MDzzz/P7Nmzewxy6s2ECRPYsGFDv+u88sorjB8/ntdee61HeUR/A9XipbKyEogMQuvqPtFl8+bN3Y8Pla6E9eijj2bFihXcdNNNQPTnbOfHdjZ+/HgALBZLVHe3hRCJTVqBCSHEAMydOxeDwcD//u//8t1330XVQ/aMM87g888/5/XXX9/tsa47w113jne+U/zxxx/z4YcfDlHkQ+eAAw6goKCAxx57jGAw2L38r3/9K5s2bWL27NlDfsyjjjqKWbNm8dBDDxEIBIDoz1lXd4b29vYeywsKCjjqqKN4/PHHaWho2O2YO7eCE0IkPrlzK4QQA5Cfn88JJ5zAyy+/TFZWVlSJ3PXXX88rr7zCmWeeycUXX8z+++9Pa2srb775Jo899hjTp0/npJNO4rXXXuO0005j9uzZbN26lccee4wpU6bg8XgGHO+nn37Kc889t9vyCRMmcMghhwxonxaLhXvvvZeLLrqII488krlz53a3AquqquKaa64ZcLz9uf766znzzDN55pln+PnPfx71ObPb7UyZMoU//vGPTJo0iZycHKZNm8a0adN4+OGHOeyww9hnn3249NJLGT9+PE6nkw8//JDa2lo+//zzYXkuQoihJ8mtEEIM0AUXXMDbb7/NWWedFdVsZGlpafzf//0fixcv5vXXX2fVqlUUFBRw7LHHdg+0mjdvHo2NjTz++OO88847TJkyheeee46XX36ZNWvWDDjWF154gRdeeGG35RdeeOGAk9uueFNTU/nVr37FjTfe2D3xxb333tujx+1QOv3005kwYQL3338/l156aUzn7KmnnmLBggVcc801hEIhFi9ezLRp05gyZQr//ve/Wbp0Kc888wwtLS0UFBQwc+ZMFi1aNCzPQwgxPAz6zt/jCCGEiNobb7zBqaeeygcffNA9c5YQQoj4kuRWCCEG6KSTTmLTpk1s2bKlz8FKQgghRpaUJQghRIxefPFFvvjiC/785z+zbNkySWyFECKByJ1bIYSIkcFgIC0tjbPPPpvHHnsMs1nuEwghRKKQd2QhhIiR3BMQQojEJX1uhRBCCCFE0pDkVgghhBBCJA1JboUQQgghRNKQ5FYIIYQQQiQNSW6FEEIIIUTSkORWCCGEEEIkDUluhRBCCCFE0pDkVgghhBBCJA1JboUQQgghRNKQ5FYIIYQQQiSN/w8D0+XutxTMJAAAAABJRU5ErkJggg==\",\n            \"text/plain\": [\n              \"<Figure size 768x576 with 1 Axes>\"\n            ]\n          },\n          \"metadata\": {},\n          \"output_type\": \"display_data\"\n        }\n      ],\n      \"source\": [\n        \"fig, ax = plt.subplots(1, 1)\\n\",\n        \"sinter.plot_error_rate(\\n\",\n        \"    ax=ax,\\n\",\n        \"    stats=collected_stats,\\n\",\n        \"    x_func=lambda stats: stats.json_metadata['p'],\\n\",\n        \"    group_func=lambda stats: stats.json_metadata['d'],\\n\",\n        \")\\n\",\n        \"ax.set_ylim(1e-4, 1e-0)\\n\",\n        \"ax.set_xlim(5e-2, 5e-1)\\n\",\n        \"ax.loglog()\\n\",\n        \"ax.set_title(\\\"Repetition Code Error Rates (Phenomenological Noise)\\\")\\n\",\n        \"ax.set_xlabel(\\\"Phyical Error Rate\\\")\\n\",\n        \"ax.set_ylabel(\\\"Logical Error Rate per Shot\\\")\\n\",\n        \"ax.grid(which='major')\\n\",\n        \"ax.grid(which='minor')\\n\",\n        \"ax.legend()\\n\",\n        \"fig.set_dpi(120)  # Show it bigger\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"gU4GZ66sZllH\"\n      },\n      \"source\": [\n        \"`sinter`'s goal is to make getting these kinds of results fast and easy.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"fe0PdLck-qOW\"\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"surface-code\\\"></a>\\n\",\n        \"# 9. Estimate the threshold and footprint of a surface code\\n\",\n        \"\\n\",\n        \"Estimating the threshold of a repetition code under phenomenelogical noise is one thing.\\n\",\n        \"Estimating the threshold of a true quantum code, such as a surface code, under circuit noise, is...\\n\",\n        \"well, historically, it would be a whole other thing.\\n\",\n        \"But when using Stim, and PyMatching, and Sinter, the workflow is exactly identical.\\n\",\n        \"The only thing that changes are the circuits input into the process.\\n\",\n        \"\\n\",\n        \"The hard part is making the circuits in the first place.\\n\",\n        \"So, for this tutorial, you'll continue to lean on Stim's example circuits.\\n\",\n        \"You can make simple surface code circuits using [`stim.Circuit.generated`](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md#stim.Circuit.generated).\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"gAtDhdGuV--e\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"surface_code_circuit = stim.Circuit.generated(\\n\",\n        \"    \\\"surface_code:rotated_memory_z\\\",\\n\",\n        \"    rounds=9,\\n\",\n        \"    distance=3,\\n\",\n        \"    after_clifford_depolarization=0.001,\\n\",\n        \"    after_reset_flip_probability=0.001,\\n\",\n        \"    before_measure_flip_probability=0.001,\\n\",\n        \"    before_round_data_depolarization=0.001)\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"huyjsuMBfSP9\"\n      },\n      \"source\": [\n        \"Surface code circuits have a much more complex structure than repetition codes, because they are laid out in a 2-D grid instead of a 1-D line. A time slice diagram of the circuit without noise will be much clearer than a timeline diagram:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\",\n          \"height\": 404\n        },\n        \"id\": \"-1O4qysufdXj\",\n        \"outputId\": \"42a217ab-1a92-4850-b634-932f3a8f603e\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/svg+xml\": [\n              \"<svg viewBox=\\\"0 0 3754.3 3754.3\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"qubit_dots\\\">\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"80\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"335.529\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"351.529\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"80\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"351.529\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"80\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"170.51\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"261.019\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"351.529\\\">H</text>\\n\",\n              \"<path d=\\\"M1119.87,80 L1165.13,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,125.255 L1177.13,125.255 M1165.13,113.255 L1165.13,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,261.019 L1165.13,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,306.274 L1177.13,306.274 M1165.13,294.274 L1165.13,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,170.51 L1255.64,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,215.764 L1267.64,215.764 M1255.64,203.764 L1255.64,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,306.274 L1029.36,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1017.36,261.019 L1041.36,261.019 M1029.36,249.019 L1029.36,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,215.764 L1119.87,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,170.51 L1131.87,170.51 M1119.87,158.51 L1119.87,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,306.274 L1210.38,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,261.019 L1222.38,261.019 M1210.38,249.019 L1210.38,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,80 L1549.3,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,125.255 L1561.3,125.255 M1549.3,113.255 L1549.3,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,261.019 L1549.3,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,306.274 L1561.3,306.274 M1549.3,294.274 L1549.3,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,170.51 L1639.81,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,215.764 L1651.81,215.764 M1639.81,203.764 L1639.81,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,215.764 L1504.05,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1504.05\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1492.05,261.019 L1516.05,261.019 M1504.05,249.019 L1504.05,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,125.255 L1594.56,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,170.51 L1606.56,170.51 M1594.56,158.51 L1594.56,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,215.764 L1685.06,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,261.019 L1697.06,261.019 M1685.06,249.019 L1685.06,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,261.019 L2114.49,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,215.764 L2126.49,215.764 M2114.49,203.764 L2114.49,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,170.51 L2205,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,125.255 L2217,125.255 M2205,113.255 L2205,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,351.529 L2205,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"351.529\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,306.274 L2217,306.274 M2205,294.274 L2205,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,215.764 L2069.24,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,170.51 L2081.24,170.51 M2069.24,158.51 L2069.24,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,306.274 L2159.75,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,261.019 L2171.75,261.019 M2159.75,249.019 L2159.75,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,215.764 L2250.26,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2250.26\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2238.26,170.51 L2262.26,170.51 M2250.26,158.51 L2250.26,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,261.019 L2498.66,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2486.66,215.764 L2510.66,215.764 M2498.66,203.764 L2498.66,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,170.51 L2589.17,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,125.255 L2601.17,125.255 M2589.17,113.255 L2589.17,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,351.529 L2589.17,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"351.529\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,306.274 L2601.17,306.274 M2589.17,294.274 L2589.17,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,125.255 L2543.92,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,170.51 L2555.92,170.51 M2543.92,158.51 L2543.92,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,215.764 L2634.43,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,261.019 L2646.43,261.019 M2634.43,249.019 L2634.43,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,125.255 L2724.94,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2724.94\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2712.94,170.51 L2736.94,170.51 M2724.94,158.51 L2724.94,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"80\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"170.51\\\">H</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"261.019\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"351.529\\\">H</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"80\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"170.51\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"170.51\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3658.3\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3674.3\\\" y=\\\"170.51\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3386.77\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3402.77\\\" y=\\\"261.019\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"261.019\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"261.019\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"351.529\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"538.682\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"554.682\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"645.192\\\">H</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"735.701\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"810.211\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"826.211\\\">H</text>\\n\",\n              \"<path d=\\\"M645.192,554.682 L690.446,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"554.682\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,599.937 L702.446,599.937 M690.446,587.937 L690.446,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,735.701 L690.446,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,780.956 L702.446,780.956 M690.446,768.956 L690.446,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,645.192 L780.956,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,690.446 L792.956,690.446 M780.956,678.446 L780.956,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,780.956 L554.682,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M542.682,735.701 L566.682,735.701 M554.682,723.701 L554.682,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,690.446 L645.192,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,645.192 L657.192,645.192 M645.192,633.192 L645.192,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,780.956 L735.701,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,735.701 L747.701,735.701 M735.701,723.701 L735.701,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,554.682 L1074.62,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"554.682\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1062.62,599.937 L1086.62,599.937 M1074.62,587.937 L1074.62,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,735.701 L1074.62,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1062.62,780.956 L1086.62,780.956 M1074.62,768.956 L1074.62,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,645.192 L1165.13,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,690.446 L1177.13,690.446 M1165.13,678.446 L1165.13,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,690.446 L1029.36,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1017.36,735.701 L1041.36,735.701 M1029.36,723.701 L1029.36,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,599.937 L1119.87,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,645.192 L1131.87,645.192 M1119.87,633.192 L1119.87,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,690.446 L1210.38,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,735.701 L1222.38,735.701 M1210.38,723.701 L1210.38,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,735.701 L1639.81,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,690.446 L1651.81,690.446 M1639.81,678.446 L1639.81,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,645.192 L1730.32,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1718.32,599.937 L1742.32,599.937 M1730.32,587.937 L1730.32,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,826.211 L1730.32,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"826.211\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1718.32,780.956 L1742.32,780.956 M1730.32,768.956 L1730.32,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,690.446 L1594.56,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,645.192 L1606.56,645.192 M1594.56,633.192 L1594.56,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,780.956 L1685.06,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,735.701 L1697.06,735.701 M1685.06,723.701 L1685.06,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,690.446 L1775.57,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1775.57\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1763.57,645.192 L1787.57,645.192 M1775.57,633.192 L1775.57,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,735.701 L2023.98,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2011.98,690.446 L2035.98,690.446 M2023.98,678.446 L2023.98,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,645.192 L2114.49,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,599.937 L2126.49,599.937 M2114.49,587.937 L2114.49,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,826.211 L2114.49,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"826.211\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,780.956 L2126.49,780.956 M2114.49,768.956 L2114.49,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,599.937 L2069.24,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,645.192 L2081.24,645.192 M2069.24,633.192 L2069.24,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,690.446 L2159.75,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,735.701 L2171.75,735.701 M2159.75,723.701 L2159.75,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,599.937 L2250.26,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2250.26\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2238.26,645.192 L2262.26,645.192 M2250.26,633.192 L2250.26,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"538.682\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2543.92\\\" y=\\\"554.682\\\">H</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2634.43\\\" y=\\\"645.192\\\">H</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2543.92\\\" y=\\\"735.701\\\">H</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"810.211\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2634.43\\\" y=\\\"826.211\\\">H</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"538.682\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3018.6\\\" y=\\\"554.682\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3018.6\\\" y=\\\"645.192\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3109.11\\\" y=\\\"645.192\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3183.62\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3199.62\\\" y=\\\"645.192\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2912.09\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2928.09\\\" y=\\\"735.701\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3018.6\\\" y=\\\"735.701\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3109.11\\\" y=\\\"735.701\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"810.211\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3109.11\\\" y=\\\"826.211\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"538.682\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3493.28\\\" y=\\\"554.682\\\">H</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3583.79\\\" y=\\\"645.192\\\">H</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3493.28\\\" y=\\\"735.701\\\">H</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"810.211\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3583.79\\\" y=\\\"826.211\\\">H</text>\\n\",\n              \"<path d=\\\"M170.51,1029.36 L215.764,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1029.36\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,1074.62 L227.764,1074.62 M215.764,1062.62 L215.764,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,1210.38 L215.764,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,1255.64 L227.764,1255.64 M215.764,1243.64 L215.764,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,1119.87 L306.274,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M294.274,1165.13 L318.274,1165.13 M306.274,1153.13 L306.274,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,1255.64 L80,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M68,1210.38 L92,1210.38 M80,1198.38 L80,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1165.13 L170.51,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,1119.87 L182.51,1119.87 M170.51,1107.87 L170.51,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,1255.64 L261.019,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,1210.38 L273.019,1210.38 M261.019,1198.38 L261.019,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,1029.36 L599.937,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M587.937,1074.62 L611.937,1074.62 M599.937,1062.62 L599.937,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,1210.38 L599.937,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M587.937,1255.64 L611.937,1255.64 M599.937,1243.64 L599.937,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,1119.87 L690.446,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,1165.13 L702.446,1165.13 M690.446,1153.13 L690.446,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,1165.13 L554.682,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M542.682,1210.38 L566.682,1210.38 M554.682,1198.38 L554.682,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1074.62 L645.192,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,1119.87 L657.192,1119.87 M645.192,1107.87 L645.192,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,1165.13 L735.701,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,1210.38 L747.701,1210.38 M735.701,1198.38 L735.701,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,1210.38 L1165.13,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,1165.13 L1177.13,1165.13 M1165.13,1153.13 L1165.13,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,1119.87 L1255.64,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,1074.62 L1267.64,1074.62 M1255.64,1062.62 L1255.64,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,1300.89 L1255.64,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,1255.64 L1267.64,1255.64 M1255.64,1243.64 L1255.64,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,1165.13 L1119.87,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,1119.87 L1131.87,1119.87 M1119.87,1107.87 L1119.87,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1255.64 L1210.38,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,1210.38 L1222.38,1210.38 M1210.38,1198.38 L1210.38,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,1165.13 L1300.89,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1288.89,1119.87 L1312.89,1119.87 M1300.89,1107.87 L1300.89,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,1210.38 L1549.3,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,1165.13 L1561.3,1165.13 M1549.3,1153.13 L1549.3,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,1119.87 L1639.81,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,1074.62 L1651.81,1074.62 M1639.81,1062.62 L1639.81,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,1300.89 L1639.81,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"1300.89\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,1255.64 L1651.81,1255.64 M1639.81,1243.64 L1639.81,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,1074.62 L1594.56,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,1119.87 L1606.56,1119.87 M1594.56,1107.87 L1594.56,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,1165.13 L1685.06,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,1210.38 L1697.06,1210.38 M1685.06,1198.38 L1685.06,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,1074.62 L1775.57,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1775.57\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1763.57,1119.87 L1787.57,1119.87 M1775.57,1107.87 L1775.57,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2069.24\\\" y=\\\"1029.36\\\">H</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2159.75\\\" y=\\\"1119.87\\\">H</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2069.24\\\" y=\\\"1210.38\\\">H</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2159.75\\\" y=\\\"1300.89\\\">H</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2543.92\\\" y=\\\"1029.36\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2543.92\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2634.43\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2708.94\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2724.94\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2437.41\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2453.41\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2543.92\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2634.43\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2634.43\\\" y=\\\"1300.89\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"1029.36\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"1119.87\\\">H</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"1210.38\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"1300.89\\\">H</text>\\n\",\n              \"<path d=\\\"M3493.28,1029.36 L3538.54,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1029.36\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,1074.62 L3550.54,1074.62 M3538.54,1062.62 L3538.54,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,1210.38 L3538.54,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,1255.64 L3550.54,1255.64 M3538.54,1243.64 L3538.54,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,1119.87 L3629.05,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3617.05,1165.13 L3641.05,1165.13 M3629.05,1153.13 L3629.05,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3448.03,1255.64 L3402.77,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3402.77\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3390.77,1210.38 L3414.77,1210.38 M3402.77,1198.38 L3402.77,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3538.54,1165.13 L3493.28,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3481.28,1119.87 L3505.28,1119.87 M3493.28,1107.87 L3493.28,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3629.05,1255.64 L3583.79,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3571.79,1210.38 L3595.79,1210.38 M3583.79,1198.38 L3583.79,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,1504.05 L125.255,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1504.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,1549.3 L137.255,1549.3 M125.255,1537.3 L125.255,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,1685.06 L125.255,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,1730.32 L137.255,1730.32 M125.255,1718.32 L125.255,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,1594.56 L215.764,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,1639.81 L227.764,1639.81 M215.764,1627.81 L215.764,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,1639.81 L80,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M68,1685.06 L92,1685.06 M80,1673.06 L80,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1549.3 L170.51,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,1594.56 L182.51,1594.56 M170.51,1582.56 L170.51,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,1639.81 L261.019,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,1685.06 L273.019,1685.06 M261.019,1673.06 L261.019,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,1685.06 L690.446,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,1639.81 L702.446,1639.81 M690.446,1627.81 L690.446,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,1594.56 L780.956,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,1549.3 L792.956,1549.3 M780.956,1537.3 L780.956,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,1775.57 L780.956,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1775.57\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,1730.32 L792.956,1730.32 M780.956,1718.32 L780.956,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,1639.81 L645.192,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,1594.56 L657.192,1594.56 M645.192,1582.56 L645.192,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1730.32 L735.701,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,1685.06 L747.701,1685.06 M735.701,1673.06 L735.701,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,1639.81 L826.211,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M814.211,1594.56 L838.211,1594.56 M826.211,1582.56 L826.211,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,1685.06 L1074.62,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1062.62,1639.81 L1086.62,1639.81 M1074.62,1627.81 L1074.62,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,1594.56 L1165.13,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,1549.3 L1177.13,1549.3 M1165.13,1537.3 L1165.13,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,1775.57 L1165.13,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1775.57\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,1730.32 L1177.13,1730.32 M1165.13,1718.32 L1165.13,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,1549.3 L1119.87,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,1594.56 L1131.87,1594.56 M1119.87,1582.56 L1119.87,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1639.81 L1210.38,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,1685.06 L1222.38,1685.06 M1210.38,1673.06 L1210.38,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,1549.3 L1300.89,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1288.89,1594.56 L1312.89,1594.56 M1300.89,1582.56 L1300.89,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"1488.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1594.56\\\" y=\\\"1504.05\\\">H</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1685.06\\\" y=\\\"1594.56\\\">H</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1594.56\\\" y=\\\"1685.06\\\">H</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"1759.57\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1685.06\\\" y=\\\"1775.57\\\">H</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1488.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2069.24\\\" y=\\\"1504.05\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2069.24\\\" y=\\\"1594.56\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2159.75\\\" y=\\\"1594.56\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2234.26\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2250.26\\\" y=\\\"1594.56\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1962.73\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1978.73\\\" y=\\\"1685.06\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2069.24\\\" y=\\\"1685.06\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2159.75\\\" y=\\\"1685.06\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1759.57\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2159.75\\\" y=\\\"1775.57\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1488.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2543.92\\\" y=\\\"1504.05\\\">H</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2634.43\\\" y=\\\"1594.56\\\">H</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2543.92\\\" y=\\\"1685.06\\\">H</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1759.57\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2634.43\\\" y=\\\"1775.57\\\">H</text>\\n\",\n              \"<path d=\\\"M3018.6,1504.05 L3063.86,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"1504.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,1549.3 L3075.86,1549.3 M3063.86,1537.3 L3063.86,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,1685.06 L3063.86,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,1730.32 L3075.86,1730.32 M3063.86,1718.32 L3063.86,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,1594.56 L3154.37,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3142.37,1639.81 L3166.37,1639.81 M3154.37,1627.81 L3154.37,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2973.35,1730.32 L2928.09,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2928.09\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2916.09,1685.06 L2940.09,1685.06 M2928.09,1673.06 L2928.09,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3063.86,1639.81 L3018.6,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3006.6,1594.56 L3030.6,1594.56 M3018.6,1582.56 L3018.6,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3154.37,1730.32 L3109.11,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3097.11,1685.06 L3121.11,1685.06 M3109.11,1673.06 L3109.11,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,1504.05 L3448.03,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1504.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3436.03,1549.3 L3460.03,1549.3 M3448.03,1537.3 L3448.03,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,1685.06 L3448.03,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3436.03,1730.32 L3460.03,1730.32 M3448.03,1718.32 L3448.03,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,1594.56 L3538.54,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,1639.81 L3550.54,1639.81 M3538.54,1627.81 L3538.54,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3448.03,1639.81 L3402.77,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3402.77\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3390.77,1685.06 L3414.77,1685.06 M3402.77,1673.06 L3402.77,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3538.54,1549.3 L3493.28,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3481.28,1594.56 L3505.28,1594.56 M3493.28,1582.56 L3493.28,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3629.05,1639.81 L3583.79,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3571.79,1685.06 L3595.79,1685.06 M3583.79,1673.06 L3583.79,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,2159.75 L215.764,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,2114.49 L227.764,2114.49 M215.764,2102.49 L215.764,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,2069.24 L306.274,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M294.274,2023.98 L318.274,2023.98 M306.274,2011.98 L306.274,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,2250.26 L306.274,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2250.26\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M294.274,2205 L318.274,2205 M306.274,2193 L306.274,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,2114.49 L170.51,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,2069.24 L182.51,2069.24 M170.51,2057.24 L170.51,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,2205 L261.019,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,2159.75 L273.019,2159.75 M261.019,2147.75 L261.019,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,2114.49 L351.529,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M339.529,2069.24 L363.529,2069.24 M351.529,2057.24 L351.529,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,2159.75 L599.937,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M587.937,2114.49 L611.937,2114.49 M599.937,2102.49 L599.937,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,2069.24 L690.446,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,2023.98 L702.446,2023.98 M690.446,2011.98 L690.446,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,2250.26 L690.446,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"2250.26\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,2205 L702.446,2205 M690.446,2193 L690.446,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,2023.98 L645.192,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,2069.24 L657.192,2069.24 M645.192,2057.24 L645.192,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,2114.49 L735.701,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,2159.75 L747.701,2159.75 M735.701,2147.75 L735.701,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,2023.98 L826.211,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M814.211,2069.24 L838.211,2069.24 M826.211,2057.24 L826.211,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"1962.73\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"1978.73\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"2069.24\\\">H</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"2159.75\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2234.26\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"2250.26\\\">H</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"1962.73\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1594.56\\\" y=\\\"1978.73\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1594.56\\\" y=\\\"2069.24\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1685.06\\\" y=\\\"2069.24\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1759.57\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1775.57\\\" y=\\\"2069.24\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1488.05\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1504.05\\\" y=\\\"2159.75\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1594.56\\\" y=\\\"2159.75\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1685.06\\\" y=\\\"2159.75\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2234.26\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1685.06\\\" y=\\\"2250.26\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1962.73\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2069.24\\\" y=\\\"1978.73\\\">H</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2159.75\\\" y=\\\"2069.24\\\">H</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2069.24\\\" y=\\\"2159.75\\\">H</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"2234.26\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2159.75\\\" y=\\\"2250.26\\\">H</text>\\n\",\n              \"<path d=\\\"M2543.92,1978.73 L2589.17,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"1978.73\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,2023.98 L2601.17,2023.98 M2589.17,2011.98 L2589.17,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,2159.75 L2589.17,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,2205 L2601.17,2205 M2589.17,2193 L2589.17,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,2069.24 L2679.68,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2667.68,2114.49 L2691.68,2114.49 M2679.68,2102.49 L2679.68,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,2205 L2453.41,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2453.41\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2441.41,2159.75 L2465.41,2159.75 M2453.41,2147.75 L2453.41,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,2114.49 L2543.92,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,2069.24 L2555.92,2069.24 M2543.92,2057.24 L2543.92,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,2205 L2634.43,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,2159.75 L2646.43,2159.75 M2634.43,2147.75 L2634.43,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,1978.73 L2973.35,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"1978.73\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2961.35,2023.98 L2985.35,2023.98 M2973.35,2011.98 L2973.35,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,2159.75 L2973.35,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2961.35,2205 L2985.35,2205 M2973.35,2193 L2973.35,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,2069.24 L3063.86,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,2114.49 L3075.86,2114.49 M3063.86,2102.49 L3063.86,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2973.35,2114.49 L2928.09,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2928.09\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2916.09,2159.75 L2940.09,2159.75 M2928.09,2147.75 L2928.09,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3063.86,2023.98 L3018.6,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3006.6,2069.24 L3030.6,2069.24 M3018.6,2057.24 L3018.6,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3154.37,2114.49 L3109.11,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3097.11,2159.75 L3121.11,2159.75 M3109.11,2147.75 L3109.11,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,2159.75 L3538.54,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,2114.49 L3550.54,2114.49 M3538.54,2102.49 L3538.54,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,2069.24 L3629.05,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3617.05,2023.98 L3641.05,2023.98 M3629.05,2011.98 L3629.05,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,2250.26 L3629.05,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2250.26\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3617.05,2205 L3641.05,2205 M3629.05,2193 L3629.05,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3448.03,2114.49 L3493.28,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3481.28,2069.24 L3505.28,2069.24 M3493.28,2057.24 L3493.28,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3538.54,2205 L3583.79,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3571.79,2159.75 L3595.79,2159.75 M3583.79,2147.75 L3583.79,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3629.05,2114.49 L3674.3,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3674.3\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3662.3,2069.24 L3686.3,2069.24 M3674.3,2057.24 L3674.3,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,2634.43 L125.255,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,2589.17 L137.255,2589.17 M125.255,2577.17 L125.255,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,2543.92 L215.764,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,2498.66 L227.764,2498.66 M215.764,2486.66 L215.764,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,2724.94 L215.764,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2724.94\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,2679.68 L227.764,2679.68 M215.764,2667.68 L215.764,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,2498.66 L170.51,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,2543.92 L182.51,2543.92 M170.51,2531.92 L170.51,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,2589.17 L261.019,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,2634.43 L273.019,2634.43 M261.019,2622.43 L261.019,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,2498.66 L351.529,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M339.529,2543.92 L363.529,2543.92 M351.529,2531.92 L351.529,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"2437.41\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"2453.41\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"2543.92\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"2634.43\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"2708.94\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"2724.94\\\">H</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2437.41\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1119.87\\\" y=\\\"2453.41\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1119.87\\\" y=\\\"2543.92\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1210.38\\\" y=\\\"2543.92\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1284.89\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1300.89\\\" y=\\\"2543.92\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1013.36\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1029.36\\\" y=\\\"2634.43\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1119.87\\\" y=\\\"2634.43\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1210.38\\\" y=\\\"2634.43\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2708.94\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1210.38\\\" y=\\\"2724.94\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"2437.41\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1594.56\\\" y=\\\"2453.41\\\">H</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1685.06\\\" y=\\\"2543.92\\\">H</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1594.56\\\" y=\\\"2634.43\\\">H</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2708.94\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1685.06\\\" y=\\\"2724.94\\\">H</text>\\n\",\n              \"<path d=\\\"M2069.24,2453.41 L2114.49,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"2453.41\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,2498.66 L2126.49,2498.66 M2114.49,2486.66 L2114.49,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,2634.43 L2114.49,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,2679.68 L2126.49,2679.68 M2114.49,2667.68 L2114.49,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,2543.92 L2205,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,2589.17 L2217,2589.17 M2205,2577.17 L2205,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,2679.68 L1978.73,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1978.73\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1966.73,2634.43 L1990.73,2634.43 M1978.73,2622.43 L1978.73,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,2589.17 L2069.24,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,2543.92 L2081.24,2543.92 M2069.24,2531.92 L2069.24,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,2679.68 L2159.75,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,2634.43 L2171.75,2634.43 M2159.75,2622.43 L2159.75,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,2453.41 L2498.66,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2453.41\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2486.66,2498.66 L2510.66,2498.66 M2498.66,2486.66 L2498.66,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,2634.43 L2498.66,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2486.66,2679.68 L2510.66,2679.68 M2498.66,2667.68 L2498.66,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,2543.92 L2589.17,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,2589.17 L2601.17,2589.17 M2589.17,2577.17 L2589.17,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,2589.17 L2453.41,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2453.41\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2441.41,2634.43 L2465.41,2634.43 M2453.41,2622.43 L2453.41,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,2498.66 L2543.92,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,2543.92 L2555.92,2543.92 M2543.92,2531.92 L2543.92,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,2589.17 L2634.43,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,2634.43 L2646.43,2634.43 M2634.43,2622.43 L2634.43,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,2634.43 L3063.86,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,2589.17 L3075.86,2589.17 M3063.86,2577.17 L3063.86,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,2543.92 L3154.37,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3142.37,2498.66 L3166.37,2498.66 M3154.37,2486.66 L3154.37,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,2724.94 L3154.37,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2724.94\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3142.37,2679.68 L3166.37,2679.68 M3154.37,2667.68 L3154.37,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2973.35,2589.17 L3018.6,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3006.6,2543.92 L3030.6,2543.92 M3018.6,2531.92 L3018.6,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3063.86,2679.68 L3109.11,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3097.11,2634.43 L3121.11,2634.43 M3109.11,2622.43 L3109.11,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3154.37,2589.17 L3199.62,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3199.62\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3187.62,2543.92 L3211.62,2543.92 M3199.62,2531.92 L3199.62,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,2634.43 L3448.03,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3436.03,2589.17 L3460.03,2589.17 M3448.03,2577.17 L3448.03,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,2543.92 L3538.54,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,2498.66 L3550.54,2498.66 M3538.54,2486.66 L3538.54,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,2724.94 L3538.54,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2724.94\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,2679.68 L3550.54,2679.68 M3538.54,2667.68 L3538.54,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3448.03,2498.66 L3493.28,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3481.28,2543.92 L3505.28,2543.92 M3493.28,2531.92 L3493.28,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3538.54,2589.17 L3583.79,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3571.79,2634.43 L3595.79,2634.43 M3583.79,2622.43 L3583.79,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3629.05,2498.66 L3674.3,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3674.3\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3662.3,2543.92 L3686.3,2543.92 M3674.3,2531.92 L3674.3,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"2912.09\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"2928.09\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"3018.6\\\">H</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"3109.11\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3183.62\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"3199.62\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"2912.09\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"2928.09\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"3018.6\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"3018.6\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"810.211\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"826.211\\\" y=\\\"3018.6\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"538.682\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"554.682\\\" y=\\\"3109.11\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"3109.11\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"3109.11\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3183.62\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"3199.62\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2912.09\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"2928.09\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"3018.6\\\">H</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"3109.11\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"3183.62\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"3199.62\\\">H</text>\\n\",\n              \"<path d=\\\"M1594.56,2928.09 L1639.81,2973.35 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"2928.09\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,2973.35 L1651.81,2973.35 M1639.81,2961.35 L1639.81,2985.35 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,3109.11 L1639.81,3154.37 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,3154.37 L1651.81,3154.37 M1639.81,3142.37 L1639.81,3166.37 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,3018.6 L1730.32,3063.86 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1718.32,3063.86 L1742.32,3063.86 M1730.32,3051.86 L1730.32,3075.86 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,3154.37 L1504.05,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1504.05\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1492.05,3109.11 L1516.05,3109.11 M1504.05,3097.11 L1504.05,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,3063.86 L1594.56,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,3018.6 L1606.56,3018.6 M1594.56,3006.6 L1594.56,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,3154.37 L1685.06,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,3109.11 L1697.06,3109.11 M1685.06,3097.11 L1685.06,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,2928.09 L2023.98,2973.35 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"2928.09\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2011.98,2973.35 L2035.98,2973.35 M2023.98,2961.35 L2023.98,2985.35 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,3109.11 L2023.98,3154.37 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2011.98,3154.37 L2035.98,3154.37 M2023.98,3142.37 L2023.98,3166.37 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,3018.6 L2114.49,3063.86 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,3063.86 L2126.49,3063.86 M2114.49,3051.86 L2114.49,3075.86 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,3063.86 L1978.73,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1978.73\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1966.73,3109.11 L1990.73,3109.11 M1978.73,3097.11 L1978.73,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,2973.35 L2069.24,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,3018.6 L2081.24,3018.6 M2069.24,3006.6 L2069.24,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,3063.86 L2159.75,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,3109.11 L2171.75,3109.11 M2159.75,3097.11 L2159.75,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,3109.11 L2589.17,3063.86 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,3063.86 L2601.17,3063.86 M2589.17,3051.86 L2589.17,3075.86 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,3018.6 L2679.68,2973.35 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2667.68,2973.35 L2691.68,2973.35 M2679.68,2961.35 L2679.68,2985.35 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,3199.62 L2679.68,3154.37 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3199.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2667.68,3154.37 L2691.68,3154.37 M2679.68,3142.37 L2679.68,3166.37 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,3063.86 L2543.92,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,3018.6 L2555.92,3018.6 M2543.92,3006.6 L2543.92,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,3154.37 L2634.43,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,3109.11 L2646.43,3109.11 M2634.43,3097.11 L2634.43,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,3063.86 L2724.94,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2724.94\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2712.94,3018.6 L2736.94,3018.6 M2724.94,3006.6 L2724.94,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,3109.11 L2973.35,3063.86 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2961.35,3063.86 L2985.35,3063.86 M2973.35,3051.86 L2973.35,3075.86 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,3018.6 L3063.86,2973.35 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,2973.35 L3075.86,2973.35 M3063.86,2961.35 L3063.86,2985.35 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,3199.62 L3063.86,3154.37 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"3199.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,3154.37 L3075.86,3154.37 M3063.86,3142.37 L3063.86,3166.37 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2973.35,2973.35 L3018.6,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3006.6,3018.6 L3030.6,3018.6 M3018.6,3006.6 L3018.6,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3063.86,3063.86 L3109.11,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3097.11,3109.11 L3121.11,3109.11 M3109.11,3097.11 L3109.11,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3154.37,2973.35 L3199.62,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3199.62\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3187.62,3018.6 L3211.62,3018.6 M3199.62,3006.6 L3199.62,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"2912.09\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3493.28\\\" y=\\\"2928.09\\\">H</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3583.79\\\" y=\\\"3018.6\\\">H</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3493.28\\\" y=\\\"3109.11\\\">H</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3183.62\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3583.79\\\" y=\\\"3199.62\\\">H</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"3386.77\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"170.51\\\" y=\\\"3402.77\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"170.51\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"261.019\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"335.529\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"351.529\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"80\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"170.51\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"261.019\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3658.3\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"261.019\\\" y=\\\"3674.3\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"3386.77\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"3402.77\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"3493.28\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"3583.79\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3658.3\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"3674.3\\\">H</text>\\n\",\n              \"<path d=\\\"M1119.87,3402.77 L1165.13,3448.03 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"3402.77\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,3448.03 L1177.13,3448.03 M1165.13,3436.03 L1165.13,3460.03 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,3583.79 L1165.13,3629.05 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,3629.05 L1177.13,3629.05 M1165.13,3617.05 L1165.13,3641.05 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,3493.28 L1255.64,3538.54 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,3538.54 L1267.64,3538.54 M1255.64,3526.54 L1255.64,3550.54 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,3629.05 L1029.36,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1017.36,3583.79 L1041.36,3583.79 M1029.36,3571.79 L1029.36,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,3538.54 L1119.87,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,3493.28 L1131.87,3493.28 M1119.87,3481.28 L1119.87,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,3629.05 L1210.38,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,3583.79 L1222.38,3583.79 M1210.38,3571.79 L1210.38,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,3402.77 L1549.3,3448.03 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3402.77\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,3448.03 L1561.3,3448.03 M1549.3,3436.03 L1549.3,3460.03 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,3583.79 L1549.3,3629.05 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,3629.05 L1561.3,3629.05 M1549.3,3617.05 L1549.3,3641.05 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,3493.28 L1639.81,3538.54 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,3538.54 L1651.81,3538.54 M1639.81,3526.54 L1639.81,3550.54 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,3538.54 L1504.05,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1504.05\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1492.05,3583.79 L1516.05,3583.79 M1504.05,3571.79 L1504.05,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,3448.03 L1594.56,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,3493.28 L1606.56,3493.28 M1594.56,3481.28 L1594.56,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,3538.54 L1685.06,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,3583.79 L1697.06,3583.79 M1685.06,3571.79 L1685.06,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,3583.79 L2114.49,3538.54 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,3538.54 L2126.49,3538.54 M2114.49,3526.54 L2114.49,3550.54 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,3493.28 L2205,3448.03 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,3448.03 L2217,3448.03 M2205,3436.03 L2205,3460.03 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,3674.3 L2205,3629.05 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3674.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,3629.05 L2217,3629.05 M2205,3617.05 L2205,3641.05 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,3538.54 L2069.24,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,3493.28 L2081.24,3493.28 M2069.24,3481.28 L2069.24,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,3629.05 L2159.75,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,3583.79 L2171.75,3583.79 M2159.75,3571.79 L2159.75,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,3538.54 L2250.26,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2250.26\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2238.26,3493.28 L2262.26,3493.28 M2250.26,3481.28 L2250.26,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,3583.79 L2498.66,3538.54 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2486.66,3538.54 L2510.66,3538.54 M2498.66,3526.54 L2498.66,3550.54 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,3493.28 L2589.17,3448.03 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,3448.03 L2601.17,3448.03 M2589.17,3436.03 L2589.17,3460.03 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,3674.3 L2589.17,3629.05 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3674.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,3629.05 L2601.17,3629.05 M2589.17,3617.05 L2589.17,3641.05 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,3448.03 L2543.92,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,3493.28 L2555.92,3493.28 M2543.92,3481.28 L2543.92,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,3538.54 L2634.43,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,3583.79 L2646.43,3583.79 M2634.43,3571.79 L2634.43,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,3448.03 L2724.94,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2724.94\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2712.94,3493.28 L2736.94,3493.28 M2724.94,3481.28 L2724.94,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"3386.77\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"3402.77\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"3493.28\\\">H</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"3583.79\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"3658.3\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"3674.3\\\">H</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"3386.77\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"3402.77\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3658.3\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3674.3\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3386.77\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3402.77\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3658.3\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"3674.3\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3432.03\\\" y=\\\"3432.03\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3448.03\\\" y=\\\"3448.03\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3522.54\\\" y=\\\"3432.03\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3538.54\\\" y=\\\"3448.03\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3613.05\\\" y=\\\"3432.03\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3629.05\\\" y=\\\"3448.03\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3432.03\\\" y=\\\"3522.54\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3448.03\\\" y=\\\"3538.54\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3522.54\\\" y=\\\"3522.54\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3538.54\\\" y=\\\"3538.54\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3613.05\\\" y=\\\"3522.54\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3629.05\\\" y=\\\"3538.54\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3432.03\\\" y=\\\"3613.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3448.03\\\" y=\\\"3629.05\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3522.54\\\" y=\\\"3613.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3538.54\\\" y=\\\"3629.05\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3613.05\\\" y=\\\"3613.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3629.05\\\" y=\\\"3629.05\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<g id=\\\"tick_borders\\\">\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-425.529\\\">Tick 0</text>\\n\",\n              \"<rect id=\\\"tick_border:0:0_0:0\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-900.211\\\">Tick 1</text>\\n\",\n              \"<rect id=\\\"tick_border:1:0_1:1\\\" x=\\\"474.682\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-1374.89\\\">Tick 2</text>\\n\",\n              \"<rect id=\\\"tick_border:2:0_2:2\\\" x=\\\"949.364\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-1849.57\\\">Tick 3</text>\\n\",\n              \"<rect id=\\\"tick_border:3:0_3:3\\\" x=\\\"1424.05\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-2324.26\\\">Tick 4</text>\\n\",\n              \"<rect id=\\\"tick_border:4:0_4:4\\\" x=\\\"1898.73\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-2798.94\\\">Tick 5</text>\\n\",\n              \"<rect id=\\\"tick_border:5:0_5:5\\\" x=\\\"2373.41\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-3273.62\\\">Tick 6</text>\\n\",\n              \"<rect id=\\\"tick_border:6:0_6:6\\\" x=\\\"2848.09\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-3748.3\\\">Tick 7</text>\\n\",\n              \"<rect id=\\\"tick_border:7:0_7:7\\\" x=\\\"3322.77\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-425.529\\\">Tick 8</text>\\n\",\n              \"<rect id=\\\"tick_border:8:1_0:8\\\" x=\\\"0\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-900.211\\\">Tick 9</text>\\n\",\n              \"<rect id=\\\"tick_border:9:1_1:9\\\" x=\\\"474.682\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-1374.89\\\">Tick 10</text>\\n\",\n              \"<rect id=\\\"tick_border:10:1_2:10\\\" x=\\\"949.364\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-1849.57\\\">Tick 11</text>\\n\",\n              \"<rect id=\\\"tick_border:11:1_3:11\\\" x=\\\"1424.05\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-2324.26\\\">Tick 12</text>\\n\",\n              \"<rect id=\\\"tick_border:12:1_4:12\\\" x=\\\"1898.73\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-2798.94\\\">Tick 13</text>\\n\",\n              \"<rect id=\\\"tick_border:13:1_5:13\\\" x=\\\"2373.41\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-3273.62\\\">Tick 14</text>\\n\",\n              \"<rect id=\\\"tick_border:14:1_6:14\\\" x=\\\"2848.09\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-3748.3\\\">Tick 15</text>\\n\",\n              \"<rect id=\\\"tick_border:15:1_7:15\\\" x=\\\"3322.77\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-425.529\\\">Tick 16</text>\\n\",\n              \"<rect id=\\\"tick_border:16:2_0:16\\\" x=\\\"0\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-900.211\\\">Tick 17</text>\\n\",\n              \"<rect id=\\\"tick_border:17:2_1:17\\\" x=\\\"474.682\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-1374.89\\\">Tick 18</text>\\n\",\n              \"<rect id=\\\"tick_border:18:2_2:18\\\" x=\\\"949.364\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-1849.57\\\">Tick 19</text>\\n\",\n              \"<rect id=\\\"tick_border:19:2_3:19\\\" x=\\\"1424.05\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-2324.26\\\">Tick 20</text>\\n\",\n              \"<rect id=\\\"tick_border:20:2_4:20\\\" x=\\\"1898.73\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-2798.94\\\">Tick 21</text>\\n\",\n              \"<rect id=\\\"tick_border:21:2_5:21\\\" x=\\\"2373.41\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-3273.62\\\">Tick 22</text>\\n\",\n              \"<rect id=\\\"tick_border:22:2_6:22\\\" x=\\\"2848.09\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-3748.3\\\">Tick 23</text>\\n\",\n              \"<rect id=\\\"tick_border:23:2_7:23\\\" x=\\\"3322.77\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-425.529\\\">Tick 24</text>\\n\",\n              \"<rect id=\\\"tick_border:24:3_0:24\\\" x=\\\"0\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-900.211\\\">Tick 25</text>\\n\",\n              \"<rect id=\\\"tick_border:25:3_1:25\\\" x=\\\"474.682\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-1374.89\\\">Tick 26</text>\\n\",\n              \"<rect id=\\\"tick_border:26:3_2:26\\\" x=\\\"949.364\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-1849.57\\\">Tick 27</text>\\n\",\n              \"<rect id=\\\"tick_border:27:3_3:27\\\" x=\\\"1424.05\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-2324.26\\\">Tick 28</text>\\n\",\n              \"<rect id=\\\"tick_border:28:3_4:28\\\" x=\\\"1898.73\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-2798.94\\\">Tick 29</text>\\n\",\n              \"<rect id=\\\"tick_border:29:3_5:29\\\" x=\\\"2373.41\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-3273.62\\\">Tick 30</text>\\n\",\n              \"<rect id=\\\"tick_border:30:3_6:30\\\" x=\\\"2848.09\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-3748.3\\\">Tick 31</text>\\n\",\n              \"<rect id=\\\"tick_border:31:3_7:31\\\" x=\\\"3322.77\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-425.529\\\">Tick 32</text>\\n\",\n              \"<rect id=\\\"tick_border:32:4_0:32\\\" x=\\\"0\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-900.211\\\">Tick 33</text>\\n\",\n              \"<rect id=\\\"tick_border:33:4_1:33\\\" x=\\\"474.682\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-1374.89\\\">Tick 34</text>\\n\",\n              \"<rect id=\\\"tick_border:34:4_2:34\\\" x=\\\"949.364\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-1849.57\\\">Tick 35</text>\\n\",\n              \"<rect id=\\\"tick_border:35:4_3:35\\\" x=\\\"1424.05\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-2324.26\\\">Tick 36</text>\\n\",\n              \"<rect id=\\\"tick_border:36:4_4:36\\\" x=\\\"1898.73\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-2798.94\\\">Tick 37</text>\\n\",\n              \"<rect id=\\\"tick_border:37:4_5:37\\\" x=\\\"2373.41\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-3273.62\\\">Tick 38</text>\\n\",\n              \"<rect id=\\\"tick_border:38:4_6:38\\\" x=\\\"2848.09\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-3748.3\\\">Tick 39</text>\\n\",\n              \"<rect id=\\\"tick_border:39:4_7:39\\\" x=\\\"3322.77\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-425.529\\\">Tick 40</text>\\n\",\n              \"<rect id=\\\"tick_border:40:5_0:40\\\" x=\\\"0\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-900.211\\\">Tick 41</text>\\n\",\n              \"<rect id=\\\"tick_border:41:5_1:41\\\" x=\\\"474.682\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-1374.89\\\">Tick 42</text>\\n\",\n              \"<rect id=\\\"tick_border:42:5_2:42\\\" x=\\\"949.364\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-1849.57\\\">Tick 43</text>\\n\",\n              \"<rect id=\\\"tick_border:43:5_3:43\\\" x=\\\"1424.05\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-2324.26\\\">Tick 44</text>\\n\",\n              \"<rect id=\\\"tick_border:44:5_4:44\\\" x=\\\"1898.73\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-2798.94\\\">Tick 45</text>\\n\",\n              \"<rect id=\\\"tick_border:45:5_5:45\\\" x=\\\"2373.41\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-3273.62\\\">Tick 46</text>\\n\",\n              \"<rect id=\\\"tick_border:46:5_6:46\\\" x=\\\"2848.09\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-3748.3\\\">Tick 47</text>\\n\",\n              \"<rect id=\\\"tick_border:47:5_7:47\\\" x=\\\"3322.77\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-425.529\\\">Tick 48</text>\\n\",\n              \"<rect id=\\\"tick_border:48:6_0:48\\\" x=\\\"0\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-900.211\\\">Tick 49</text>\\n\",\n              \"<rect id=\\\"tick_border:49:6_1:49\\\" x=\\\"474.682\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-1374.89\\\">Tick 50</text>\\n\",\n              \"<rect id=\\\"tick_border:50:6_2:50\\\" x=\\\"949.364\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-1849.57\\\">Tick 51</text>\\n\",\n              \"<rect id=\\\"tick_border:51:6_3:51\\\" x=\\\"1424.05\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-2324.26\\\">Tick 52</text>\\n\",\n              \"<rect id=\\\"tick_border:52:6_4:52\\\" x=\\\"1898.73\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-2798.94\\\">Tick 53</text>\\n\",\n              \"<rect id=\\\"tick_border:53:6_5:53\\\" x=\\\"2373.41\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-3273.62\\\">Tick 54</text>\\n\",\n              \"<rect id=\\\"tick_border:54:6_6:54\\\" x=\\\"2848.09\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-3748.3\\\">Tick 55</text>\\n\",\n              \"<rect id=\\\"tick_border:55:6_7:55\\\" x=\\\"3322.77\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-425.529\\\">Tick 56</text>\\n\",\n              \"<rect id=\\\"tick_border:56:7_0:56\\\" x=\\\"0\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-900.211\\\">Tick 57</text>\\n\",\n              \"<rect id=\\\"tick_border:57:7_1:57\\\" x=\\\"474.682\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-1374.89\\\">Tick 58</text>\\n\",\n              \"<rect id=\\\"tick_border:58:7_2:58\\\" x=\\\"949.364\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-1849.57\\\">Tick 59</text>\\n\",\n              \"<rect id=\\\"tick_border:59:7_3:59\\\" x=\\\"1424.05\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-2324.26\\\">Tick 60</text>\\n\",\n              \"<rect id=\\\"tick_border:60:7_4:60\\\" x=\\\"1898.73\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-2798.94\\\">Tick 61</text>\\n\",\n              \"<rect id=\\\"tick_border:61:7_5:61\\\" x=\\\"2373.41\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-3273.62\\\">Tick 62</text>\\n\",\n              \"<rect id=\\\"tick_border:62:7_6:62\\\" x=\\\"2848.09\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-3748.3\\\">Tick 63</text>\\n\",\n              \"<rect id=\\\"tick_border:63:7_7:63\\\" x=\\\"3322.77\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"</svg>\"\n            ],\n            \"text/plain\": [\n              \"<svg viewBox=\\\"0 0 3754.3 3754.3\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"qubit_dots\\\">\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"1549.3\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"1594.56\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"1639.81\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"1730.32\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"1549.3\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"1594.56\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"1639.81\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"1685.07\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"1730.32\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"1775.57\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"1504.05\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"1549.3\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"1594.56\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"1639.81\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"1685.07\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"1730.32\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"1685.07\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"2023.98\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"2069.24\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"2114.49\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"2205\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"2023.98\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"2069.24\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"2114.49\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"2159.75\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"2205\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"2250.26\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"1978.73\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"2023.98\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"2069.24\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"2114.49\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"2159.75\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"2205\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"2159.75\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"2498.66\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"2543.92\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"2589.17\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"2679.68\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"2498.66\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"2543.92\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"2589.17\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"2634.43\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"2679.68\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"2724.94\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"2453.41\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"2498.66\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"2543.92\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"2589.17\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"2634.43\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"2679.68\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"2634.43\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"2973.35\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"3018.6\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"3063.86\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"3154.37\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"2973.35\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"3018.6\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"3063.86\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"3109.11\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"3154.37\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"3199.62\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"2928.09\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"2973.35\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"3018.6\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"3063.86\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"3109.11\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"3154.37\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"3109.11\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"1504.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"1549.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"1639.81\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"1594.56\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"1685.07\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"1730.32\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"1775.57\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"1978.73\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"2023.98\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"2114.49\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"2069.24\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"2159.75\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"2205\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"2250.26\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"2453.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"2498.66\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"2589.17\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"2543.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"2634.43\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"2679.68\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"2724.94\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"2928.09\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"2973.35\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"3063.86\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"3018.6\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"3109.11\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"3154.37\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"3199.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"3448.03\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"3493.28\\\" cy=\\\"3402.77\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"3538.54\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"3629.05\\\" cy=\\\"3448.03\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"3448.03\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"3493.28\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"3538.54\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"3583.79\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"3629.05\\\" cy=\\\"3538.54\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"3674.3\\\" cy=\\\"3493.28\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"3402.77\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"3448.03\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"3493.28\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"3538.54\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"3583.79\\\" cy=\\\"3583.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"3629.05\\\" cy=\\\"3629.05\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"3583.79\\\" cy=\\\"3674.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"80\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"335.529\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"351.529\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"80\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"351.529\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"80\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"170.51\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"261.019\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"351.529\\\">H</text>\\n\",\n              \"<path d=\\\"M1119.87,80 L1165.13,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,125.255 L1177.13,125.255 M1165.13,113.255 L1165.13,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,261.019 L1165.13,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,306.274 L1177.13,306.274 M1165.13,294.274 L1165.13,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,170.51 L1255.64,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,215.764 L1267.64,215.764 M1255.64,203.764 L1255.64,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,306.274 L1029.36,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1017.36,261.019 L1041.36,261.019 M1029.36,249.019 L1029.36,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,215.764 L1119.87,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,170.51 L1131.87,170.51 M1119.87,158.51 L1119.87,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,306.274 L1210.38,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,261.019 L1222.38,261.019 M1210.38,249.019 L1210.38,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,80 L1549.3,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,125.255 L1561.3,125.255 M1549.3,113.255 L1549.3,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,261.019 L1549.3,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,306.274 L1561.3,306.274 M1549.3,294.274 L1549.3,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,170.51 L1639.81,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,215.764 L1651.81,215.764 M1639.81,203.764 L1639.81,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,215.764 L1504.05,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1504.05\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1492.05,261.019 L1516.05,261.019 M1504.05,249.019 L1504.05,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,125.255 L1594.56,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,170.51 L1606.56,170.51 M1594.56,158.51 L1594.56,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,215.764 L1685.06,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,261.019 L1697.06,261.019 M1685.06,249.019 L1685.06,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,261.019 L2114.49,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,215.764 L2126.49,215.764 M2114.49,203.764 L2114.49,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,170.51 L2205,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,125.255 L2217,125.255 M2205,113.255 L2205,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,351.529 L2205,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"351.529\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,306.274 L2217,306.274 M2205,294.274 L2205,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,215.764 L2069.24,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,170.51 L2081.24,170.51 M2069.24,158.51 L2069.24,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,306.274 L2159.75,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,261.019 L2171.75,261.019 M2159.75,249.019 L2159.75,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,215.764 L2250.26,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2250.26\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2238.26,170.51 L2262.26,170.51 M2250.26,158.51 L2250.26,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,261.019 L2498.66,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2486.66,215.764 L2510.66,215.764 M2498.66,203.764 L2498.66,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,170.51 L2589.17,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,125.255 L2601.17,125.255 M2589.17,113.255 L2589.17,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,351.529 L2589.17,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"351.529\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,306.274 L2601.17,306.274 M2589.17,294.274 L2589.17,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,125.255 L2543.92,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,170.51 L2555.92,170.51 M2543.92,158.51 L2543.92,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,215.764 L2634.43,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,261.019 L2646.43,261.019 M2634.43,249.019 L2634.43,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,125.255 L2724.94,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2724.94\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2712.94,170.51 L2736.94,170.51 M2724.94,158.51 L2724.94,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"80\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"170.51\\\">H</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"261.019\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"351.529\\\">H</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"80\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"170.51\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"170.51\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3658.3\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3674.3\\\" y=\\\"170.51\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3386.77\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3402.77\\\" y=\\\"261.019\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"261.019\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"261.019\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"351.529\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"538.682\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"554.682\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"645.192\\\">H</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"735.701\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"810.211\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"826.211\\\">H</text>\\n\",\n              \"<path d=\\\"M645.192,554.682 L690.446,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"554.682\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,599.937 L702.446,599.937 M690.446,587.937 L690.446,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,735.701 L690.446,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,780.956 L702.446,780.956 M690.446,768.956 L690.446,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,645.192 L780.956,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,690.446 L792.956,690.446 M780.956,678.446 L780.956,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,780.956 L554.682,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M542.682,735.701 L566.682,735.701 M554.682,723.701 L554.682,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,690.446 L645.192,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,645.192 L657.192,645.192 M645.192,633.192 L645.192,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,780.956 L735.701,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,735.701 L747.701,735.701 M735.701,723.701 L735.701,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,554.682 L1074.62,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"554.682\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1062.62,599.937 L1086.62,599.937 M1074.62,587.937 L1074.62,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,735.701 L1074.62,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1062.62,780.956 L1086.62,780.956 M1074.62,768.956 L1074.62,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,645.192 L1165.13,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,690.446 L1177.13,690.446 M1165.13,678.446 L1165.13,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,690.446 L1029.36,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1017.36,735.701 L1041.36,735.701 M1029.36,723.701 L1029.36,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,599.937 L1119.87,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,645.192 L1131.87,645.192 M1119.87,633.192 L1119.87,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,690.446 L1210.38,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,735.701 L1222.38,735.701 M1210.38,723.701 L1210.38,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,735.701 L1639.81,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,690.446 L1651.81,690.446 M1639.81,678.446 L1639.81,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,645.192 L1730.32,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1718.32,599.937 L1742.32,599.937 M1730.32,587.937 L1730.32,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,826.211 L1730.32,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"826.211\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1718.32,780.956 L1742.32,780.956 M1730.32,768.956 L1730.32,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,690.446 L1594.56,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,645.192 L1606.56,645.192 M1594.56,633.192 L1594.56,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,780.956 L1685.06,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,735.701 L1697.06,735.701 M1685.06,723.701 L1685.06,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,690.446 L1775.57,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1775.57\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1763.57,645.192 L1787.57,645.192 M1775.57,633.192 L1775.57,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,735.701 L2023.98,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2011.98,690.446 L2035.98,690.446 M2023.98,678.446 L2023.98,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,645.192 L2114.49,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,599.937 L2126.49,599.937 M2114.49,587.937 L2114.49,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,826.211 L2114.49,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"826.211\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,780.956 L2126.49,780.956 M2114.49,768.956 L2114.49,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,599.937 L2069.24,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,645.192 L2081.24,645.192 M2069.24,633.192 L2069.24,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,690.446 L2159.75,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,735.701 L2171.75,735.701 M2159.75,723.701 L2159.75,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,599.937 L2250.26,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2250.26\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2238.26,645.192 L2262.26,645.192 M2250.26,633.192 L2250.26,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"538.682\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2543.92\\\" y=\\\"554.682\\\">H</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2634.43\\\" y=\\\"645.192\\\">H</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2543.92\\\" y=\\\"735.701\\\">H</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"810.211\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2634.43\\\" y=\\\"826.211\\\">H</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"538.682\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3018.6\\\" y=\\\"554.682\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3018.6\\\" y=\\\"645.192\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3109.11\\\" y=\\\"645.192\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3183.62\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3199.62\\\" y=\\\"645.192\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2912.09\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2928.09\\\" y=\\\"735.701\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3018.6\\\" y=\\\"735.701\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3109.11\\\" y=\\\"735.701\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"810.211\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3109.11\\\" y=\\\"826.211\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"538.682\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3493.28\\\" y=\\\"554.682\\\">H</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"629.192\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3583.79\\\" y=\\\"645.192\\\">H</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"719.701\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3493.28\\\" y=\\\"735.701\\\">H</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"810.211\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3583.79\\\" y=\\\"826.211\\\">H</text>\\n\",\n              \"<path d=\\\"M170.51,1029.36 L215.764,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1029.36\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,1074.62 L227.764,1074.62 M215.764,1062.62 L215.764,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,1210.38 L215.764,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,1255.64 L227.764,1255.64 M215.764,1243.64 L215.764,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,1119.87 L306.274,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M294.274,1165.13 L318.274,1165.13 M306.274,1153.13 L306.274,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,1255.64 L80,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M68,1210.38 L92,1210.38 M80,1198.38 L80,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1165.13 L170.51,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,1119.87 L182.51,1119.87 M170.51,1107.87 L170.51,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,1255.64 L261.019,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,1210.38 L273.019,1210.38 M261.019,1198.38 L261.019,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,1029.36 L599.937,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M587.937,1074.62 L611.937,1074.62 M599.937,1062.62 L599.937,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,1210.38 L599.937,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M587.937,1255.64 L611.937,1255.64 M599.937,1243.64 L599.937,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,1119.87 L690.446,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,1165.13 L702.446,1165.13 M690.446,1153.13 L690.446,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,1165.13 L554.682,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M542.682,1210.38 L566.682,1210.38 M554.682,1198.38 L554.682,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1074.62 L645.192,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,1119.87 L657.192,1119.87 M645.192,1107.87 L645.192,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,1165.13 L735.701,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,1210.38 L747.701,1210.38 M735.701,1198.38 L735.701,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,1210.38 L1165.13,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,1165.13 L1177.13,1165.13 M1165.13,1153.13 L1165.13,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,1119.87 L1255.64,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,1074.62 L1267.64,1074.62 M1255.64,1062.62 L1255.64,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,1300.89 L1255.64,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,1255.64 L1267.64,1255.64 M1255.64,1243.64 L1255.64,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,1165.13 L1119.87,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,1119.87 L1131.87,1119.87 M1119.87,1107.87 L1119.87,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1255.64 L1210.38,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,1210.38 L1222.38,1210.38 M1210.38,1198.38 L1210.38,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,1165.13 L1300.89,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1288.89,1119.87 L1312.89,1119.87 M1300.89,1107.87 L1300.89,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,1210.38 L1549.3,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,1165.13 L1561.3,1165.13 M1549.3,1153.13 L1549.3,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,1119.87 L1639.81,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,1074.62 L1651.81,1074.62 M1639.81,1062.62 L1639.81,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,1300.89 L1639.81,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"1300.89\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,1255.64 L1651.81,1255.64 M1639.81,1243.64 L1639.81,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,1074.62 L1594.56,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,1119.87 L1606.56,1119.87 M1594.56,1107.87 L1594.56,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,1165.13 L1685.06,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,1210.38 L1697.06,1210.38 M1685.06,1198.38 L1685.06,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,1074.62 L1775.57,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1775.57\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1763.57,1119.87 L1787.57,1119.87 M1775.57,1107.87 L1775.57,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2069.24\\\" y=\\\"1029.36\\\">H</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2159.75\\\" y=\\\"1119.87\\\">H</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2069.24\\\" y=\\\"1210.38\\\">H</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2159.75\\\" y=\\\"1300.89\\\">H</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2543.92\\\" y=\\\"1029.36\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2543.92\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2634.43\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2708.94\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2724.94\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2437.41\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2453.41\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2543.92\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2634.43\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2634.43\\\" y=\\\"1300.89\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"1029.36\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"1119.87\\\">H</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"1210.38\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"1300.89\\\">H</text>\\n\",\n              \"<path d=\\\"M3493.28,1029.36 L3538.54,1074.62 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1029.36\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1074.62\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,1074.62 L3550.54,1074.62 M3538.54,1062.62 L3538.54,1086.62 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,1210.38 L3538.54,1255.64 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,1255.64 L3550.54,1255.64 M3538.54,1243.64 L3538.54,1267.64 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,1119.87 L3629.05,1165.13 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3617.05,1165.13 L3641.05,1165.13 M3629.05,1153.13 L3629.05,1177.13 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3448.03,1255.64 L3402.77,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3402.77\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3390.77,1210.38 L3414.77,1210.38 M3402.77,1198.38 L3402.77,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3538.54,1165.13 L3493.28,1119.87 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1165.13\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1119.87\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3481.28,1119.87 L3505.28,1119.87 M3493.28,1107.87 L3493.28,1131.87 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3629.05,1255.64 L3583.79,1210.38 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"1255.64\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"1210.38\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3571.79,1210.38 L3595.79,1210.38 M3583.79,1198.38 L3583.79,1222.38 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,1504.05 L125.255,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1504.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,1549.3 L137.255,1549.3 M125.255,1537.3 L125.255,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,1685.06 L125.255,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,1730.32 L137.255,1730.32 M125.255,1718.32 L125.255,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,1594.56 L215.764,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,1639.81 L227.764,1639.81 M215.764,1627.81 L215.764,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,1639.81 L80,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M68,1685.06 L92,1685.06 M80,1673.06 L80,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1549.3 L170.51,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,1594.56 L182.51,1594.56 M170.51,1582.56 L170.51,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,1639.81 L261.019,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,1685.06 L273.019,1685.06 M261.019,1673.06 L261.019,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,1685.06 L690.446,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,1639.81 L702.446,1639.81 M690.446,1627.81 L690.446,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,1594.56 L780.956,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,1549.3 L792.956,1549.3 M780.956,1537.3 L780.956,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,1775.57 L780.956,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1775.57\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,1730.32 L792.956,1730.32 M780.956,1718.32 L780.956,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,1639.81 L645.192,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,1594.56 L657.192,1594.56 M645.192,1582.56 L645.192,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1730.32 L735.701,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,1685.06 L747.701,1685.06 M735.701,1673.06 L735.701,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,1639.81 L826.211,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M814.211,1594.56 L838.211,1594.56 M826.211,1582.56 L826.211,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,1685.06 L1074.62,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1062.62,1639.81 L1086.62,1639.81 M1074.62,1627.81 L1074.62,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,1594.56 L1165.13,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,1549.3 L1177.13,1549.3 M1165.13,1537.3 L1165.13,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,1775.57 L1165.13,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1775.57\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,1730.32 L1177.13,1730.32 M1165.13,1718.32 L1165.13,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,1549.3 L1119.87,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,1594.56 L1131.87,1594.56 M1119.87,1582.56 L1119.87,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1639.81 L1210.38,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,1685.06 L1222.38,1685.06 M1210.38,1673.06 L1210.38,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,1549.3 L1300.89,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1288.89,1594.56 L1312.89,1594.56 M1300.89,1582.56 L1300.89,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"1488.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1594.56\\\" y=\\\"1504.05\\\">H</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1685.06\\\" y=\\\"1594.56\\\">H</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1594.56\\\" y=\\\"1685.06\\\">H</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"1759.57\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1685.06\\\" y=\\\"1775.57\\\">H</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1488.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2069.24\\\" y=\\\"1504.05\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2069.24\\\" y=\\\"1594.56\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2159.75\\\" y=\\\"1594.56\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2234.26\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2250.26\\\" y=\\\"1594.56\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1962.73\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1978.73\\\" y=\\\"1685.06\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2069.24\\\" y=\\\"1685.06\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2159.75\\\" y=\\\"1685.06\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"1759.57\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"2159.75\\\" y=\\\"1775.57\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1488.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2543.92\\\" y=\\\"1504.05\\\">H</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1578.56\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2634.43\\\" y=\\\"1594.56\\\">H</text>\\n\",\n              \"<rect x=\\\"2527.92\\\" y=\\\"1669.06\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2543.92\\\" y=\\\"1685.06\\\">H</text>\\n\",\n              \"<rect x=\\\"2618.43\\\" y=\\\"1759.57\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2634.43\\\" y=\\\"1775.57\\\">H</text>\\n\",\n              \"<path d=\\\"M3018.6,1504.05 L3063.86,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"1504.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,1549.3 L3075.86,1549.3 M3063.86,1537.3 L3063.86,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,1685.06 L3063.86,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,1730.32 L3075.86,1730.32 M3063.86,1718.32 L3063.86,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,1594.56 L3154.37,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3142.37,1639.81 L3166.37,1639.81 M3154.37,1627.81 L3154.37,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2973.35,1730.32 L2928.09,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2928.09\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2916.09,1685.06 L2940.09,1685.06 M2928.09,1673.06 L2928.09,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3063.86,1639.81 L3018.6,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3006.6,1594.56 L3030.6,1594.56 M3018.6,1582.56 L3018.6,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3154.37,1730.32 L3109.11,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3097.11,1685.06 L3121.11,1685.06 M3109.11,1673.06 L3109.11,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,1504.05 L3448.03,1549.3 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1504.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3436.03,1549.3 L3460.03,1549.3 M3448.03,1537.3 L3448.03,1561.3 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,1685.06 L3448.03,1730.32 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"1730.32\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3436.03,1730.32 L3460.03,1730.32 M3448.03,1718.32 L3448.03,1742.32 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,1594.56 L3538.54,1639.81 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,1639.81 L3550.54,1639.81 M3538.54,1627.81 L3538.54,1651.81 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3448.03,1639.81 L3402.77,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3402.77\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3390.77,1685.06 L3414.77,1685.06 M3402.77,1673.06 L3402.77,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3538.54,1549.3 L3493.28,1594.56 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"1549.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"1594.56\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3481.28,1594.56 L3505.28,1594.56 M3493.28,1582.56 L3493.28,1606.56 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3629.05,1639.81 L3583.79,1685.06 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"1639.81\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"1685.06\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3571.79,1685.06 L3595.79,1685.06 M3583.79,1673.06 L3583.79,1697.06 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,2159.75 L215.764,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,2114.49 L227.764,2114.49 M215.764,2102.49 L215.764,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,2069.24 L306.274,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M294.274,2023.98 L318.274,2023.98 M306.274,2011.98 L306.274,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,2250.26 L306.274,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2250.26\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M294.274,2205 L318.274,2205 M306.274,2193 L306.274,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,2114.49 L170.51,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,2069.24 L182.51,2069.24 M170.51,2057.24 L170.51,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,2205 L261.019,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,2159.75 L273.019,2159.75 M261.019,2147.75 L261.019,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,2114.49 L351.529,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M339.529,2069.24 L363.529,2069.24 M351.529,2057.24 L351.529,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,2159.75 L599.937,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M587.937,2114.49 L611.937,2114.49 M599.937,2102.49 L599.937,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,2069.24 L690.446,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,2023.98 L702.446,2023.98 M690.446,2011.98 L690.446,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,2250.26 L690.446,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"2250.26\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,2205 L702.446,2205 M690.446,2193 L690.446,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,2023.98 L645.192,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,2069.24 L657.192,2069.24 M645.192,2057.24 L645.192,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,2114.49 L735.701,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,2159.75 L747.701,2159.75 M735.701,2147.75 L735.701,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,2023.98 L826.211,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M814.211,2069.24 L838.211,2069.24 M826.211,2057.24 L826.211,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"1962.73\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"1978.73\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"2069.24\\\">H</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"2159.75\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2234.26\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"2250.26\\\">H</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"1962.73\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1594.56\\\" y=\\\"1978.73\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1594.56\\\" y=\\\"2069.24\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1685.06\\\" y=\\\"2069.24\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1759.57\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1775.57\\\" y=\\\"2069.24\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1488.05\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1504.05\\\" y=\\\"2159.75\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1594.56\\\" y=\\\"2159.75\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1685.06\\\" y=\\\"2159.75\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2234.26\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1685.06\\\" y=\\\"2250.26\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"1962.73\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2069.24\\\" y=\\\"1978.73\\\">H</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"2053.24\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2159.75\\\" y=\\\"2069.24\\\">H</text>\\n\",\n              \"<rect x=\\\"2053.24\\\" y=\\\"2143.75\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2069.24\\\" y=\\\"2159.75\\\">H</text>\\n\",\n              \"<rect x=\\\"2143.75\\\" y=\\\"2234.26\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"2159.75\\\" y=\\\"2250.26\\\">H</text>\\n\",\n              \"<path d=\\\"M2543.92,1978.73 L2589.17,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"1978.73\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,2023.98 L2601.17,2023.98 M2589.17,2011.98 L2589.17,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,2159.75 L2589.17,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,2205 L2601.17,2205 M2589.17,2193 L2589.17,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,2069.24 L2679.68,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2667.68,2114.49 L2691.68,2114.49 M2679.68,2102.49 L2679.68,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,2205 L2453.41,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2453.41\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2441.41,2159.75 L2465.41,2159.75 M2453.41,2147.75 L2453.41,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,2114.49 L2543.92,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,2069.24 L2555.92,2069.24 M2543.92,2057.24 L2543.92,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,2205 L2634.43,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,2159.75 L2646.43,2159.75 M2634.43,2147.75 L2634.43,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,1978.73 L2973.35,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"1978.73\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2961.35,2023.98 L2985.35,2023.98 M2973.35,2011.98 L2973.35,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,2159.75 L2973.35,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2961.35,2205 L2985.35,2205 M2973.35,2193 L2973.35,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,2069.24 L3063.86,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,2114.49 L3075.86,2114.49 M3063.86,2102.49 L3063.86,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2973.35,2114.49 L2928.09,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2928.09\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2916.09,2159.75 L2940.09,2159.75 M2928.09,2147.75 L2928.09,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3063.86,2023.98 L3018.6,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3006.6,2069.24 L3030.6,2069.24 M3018.6,2057.24 L3018.6,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3154.37,2114.49 L3109.11,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3097.11,2159.75 L3121.11,2159.75 M3109.11,2147.75 L3109.11,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,2159.75 L3538.54,2114.49 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,2114.49 L3550.54,2114.49 M3538.54,2102.49 L3538.54,2126.49 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,2069.24 L3629.05,2023.98 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"2023.98\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3617.05,2023.98 L3641.05,2023.98 M3629.05,2011.98 L3629.05,2035.98 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,2250.26 L3629.05,2205 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2250.26\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3617.05,2205 L3641.05,2205 M3629.05,2193 L3629.05,2217 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3448.03,2114.49 L3493.28,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3481.28,2069.24 L3505.28,2069.24 M3493.28,2057.24 L3493.28,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3538.54,2205 L3583.79,2159.75 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2205\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2159.75\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3571.79,2159.75 L3595.79,2159.75 M3583.79,2147.75 L3583.79,2171.75 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3629.05,2114.49 L3674.3,2069.24 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"2114.49\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3674.3\\\" cy=\\\"2069.24\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3662.3,2069.24 L3686.3,2069.24 M3674.3,2057.24 L3674.3,2081.24 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,2634.43 L125.255,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,2589.17 L137.255,2589.17 M125.255,2577.17 L125.255,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,2543.92 L215.764,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,2498.66 L227.764,2498.66 M215.764,2486.66 L215.764,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,2724.94 L215.764,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2724.94\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,2679.68 L227.764,2679.68 M215.764,2667.68 L215.764,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,2498.66 L170.51,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,2543.92 L182.51,2543.92 M170.51,2531.92 L170.51,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,2589.17 L261.019,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,2634.43 L273.019,2634.43 M261.019,2622.43 L261.019,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,2498.66 L351.529,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M339.529,2543.92 L363.529,2543.92 M351.529,2531.92 L351.529,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"2437.41\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"2453.41\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"2543.92\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"2634.43\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"2708.94\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"2724.94\\\">H</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2437.41\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1119.87\\\" y=\\\"2453.41\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1119.87\\\" y=\\\"2543.92\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1210.38\\\" y=\\\"2543.92\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1284.89\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1300.89\\\" y=\\\"2543.92\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1013.36\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1029.36\\\" y=\\\"2634.43\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1119.87\\\" y=\\\"2634.43\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1210.38\\\" y=\\\"2634.43\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"2708.94\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"1210.38\\\" y=\\\"2724.94\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"2437.41\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1594.56\\\" y=\\\"2453.41\\\">H</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2527.92\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1685.06\\\" y=\\\"2543.92\\\">H</text>\\n\",\n              \"<rect x=\\\"1578.56\\\" y=\\\"2618.43\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1594.56\\\" y=\\\"2634.43\\\">H</text>\\n\",\n              \"<rect x=\\\"1669.06\\\" y=\\\"2708.94\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1685.06\\\" y=\\\"2724.94\\\">H</text>\\n\",\n              \"<path d=\\\"M2069.24,2453.41 L2114.49,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"2453.41\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,2498.66 L2126.49,2498.66 M2114.49,2486.66 L2114.49,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,2634.43 L2114.49,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,2679.68 L2126.49,2679.68 M2114.49,2667.68 L2114.49,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,2543.92 L2205,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,2589.17 L2217,2589.17 M2205,2577.17 L2205,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,2679.68 L1978.73,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1978.73\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1966.73,2634.43 L1990.73,2634.43 M1978.73,2622.43 L1978.73,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,2589.17 L2069.24,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,2543.92 L2081.24,2543.92 M2069.24,2531.92 L2069.24,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,2679.68 L2159.75,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,2634.43 L2171.75,2634.43 M2159.75,2622.43 L2159.75,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,2453.41 L2498.66,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2453.41\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2486.66,2498.66 L2510.66,2498.66 M2498.66,2486.66 L2498.66,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,2634.43 L2498.66,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2486.66,2679.68 L2510.66,2679.68 M2498.66,2667.68 L2498.66,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,2543.92 L2589.17,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,2589.17 L2601.17,2589.17 M2589.17,2577.17 L2589.17,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,2589.17 L2453.41,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2453.41\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2441.41,2634.43 L2465.41,2634.43 M2453.41,2622.43 L2453.41,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,2498.66 L2543.92,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,2543.92 L2555.92,2543.92 M2543.92,2531.92 L2543.92,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,2589.17 L2634.43,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,2634.43 L2646.43,2634.43 M2634.43,2622.43 L2634.43,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,2634.43 L3063.86,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,2589.17 L3075.86,2589.17 M3063.86,2577.17 L3063.86,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,2543.92 L3154.37,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3142.37,2498.66 L3166.37,2498.66 M3154.37,2486.66 L3154.37,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,2724.94 L3154.37,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2724.94\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3142.37,2679.68 L3166.37,2679.68 M3154.37,2667.68 L3154.37,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2973.35,2589.17 L3018.6,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3006.6,2543.92 L3030.6,2543.92 M3018.6,2531.92 L3018.6,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3063.86,2679.68 L3109.11,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3097.11,2634.43 L3121.11,2634.43 M3109.11,2622.43 L3109.11,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3154.37,2589.17 L3199.62,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3199.62\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3187.62,2543.92 L3211.62,2543.92 M3199.62,2531.92 L3199.62,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3493.28,2634.43 L3448.03,2589.17 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3436.03,2589.17 L3460.03,2589.17 M3448.03,2577.17 L3448.03,2601.17 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,2543.92 L3538.54,2498.66 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,2498.66 L3550.54,2498.66 M3538.54,2486.66 L3538.54,2510.66 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3583.79,2724.94 L3538.54,2679.68 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2724.94\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2679.68\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3526.54,2679.68 L3550.54,2679.68 M3538.54,2667.68 L3538.54,2691.68 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3448.03,2498.66 L3493.28,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3448.03\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3493.28\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3481.28,2543.92 L3505.28,2543.92 M3493.28,2531.92 L3493.28,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3538.54,2589.17 L3583.79,2634.43 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3538.54\\\" cy=\\\"2589.17\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3583.79\\\" cy=\\\"2634.43\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3571.79,2634.43 L3595.79,2634.43 M3583.79,2622.43 L3583.79,2646.43 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3629.05,2498.66 L3674.3,2543.92 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3629.05\\\" cy=\\\"2498.66\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3674.3\\\" cy=\\\"2543.92\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3662.3,2543.92 L3686.3,2543.92 M3674.3,2531.92 L3674.3,2555.92 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"2912.09\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"2928.09\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"3018.6\\\">H</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"3109.11\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3183.62\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"3199.62\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"2912.09\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"2928.09\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"3018.6\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"3018.6\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"810.211\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"826.211\\\" y=\\\"3018.6\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"538.682\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"554.682\\\" y=\\\"3109.11\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"3109.11\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"3109.11\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3183.62\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"3199.62\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"2912.09\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"2928.09\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"3018.6\\\">H</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"3109.11\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"3183.62\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"3199.62\\\">H</text>\\n\",\n              \"<path d=\\\"M1594.56,2928.09 L1639.81,2973.35 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"2928.09\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,2973.35 L1651.81,2973.35 M1639.81,2961.35 L1639.81,2985.35 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,3109.11 L1639.81,3154.37 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,3154.37 L1651.81,3154.37 M1639.81,3142.37 L1639.81,3166.37 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,3018.6 L1730.32,3063.86 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1718.32,3063.86 L1742.32,3063.86 M1730.32,3051.86 L1730.32,3075.86 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,3154.37 L1504.05,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1504.05\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1492.05,3109.11 L1516.05,3109.11 M1504.05,3097.11 L1504.05,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,3063.86 L1594.56,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,3018.6 L1606.56,3018.6 M1594.56,3006.6 L1594.56,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,3154.37 L1685.06,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,3109.11 L1697.06,3109.11 M1685.06,3097.11 L1685.06,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,2928.09 L2023.98,2973.35 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"2928.09\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2011.98,2973.35 L2035.98,2973.35 M2023.98,2961.35 L2023.98,2985.35 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,3109.11 L2023.98,3154.37 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2011.98,3154.37 L2035.98,3154.37 M2023.98,3142.37 L2023.98,3166.37 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,3018.6 L2114.49,3063.86 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,3063.86 L2126.49,3063.86 M2114.49,3051.86 L2114.49,3075.86 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,3063.86 L1978.73,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1978.73\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1966.73,3109.11 L1990.73,3109.11 M1978.73,3097.11 L1978.73,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,2973.35 L2069.24,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,3018.6 L2081.24,3018.6 M2069.24,3006.6 L2069.24,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,3063.86 L2159.75,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,3109.11 L2171.75,3109.11 M2159.75,3097.11 L2159.75,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,3109.11 L2589.17,3063.86 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,3063.86 L2601.17,3063.86 M2589.17,3051.86 L2589.17,3075.86 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,3018.6 L2679.68,2973.35 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2667.68,2973.35 L2691.68,2973.35 M2679.68,2961.35 L2679.68,2985.35 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,3199.62 L2679.68,3154.37 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3199.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2667.68,3154.37 L2691.68,3154.37 M2679.68,3142.37 L2679.68,3166.37 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,3063.86 L2543.92,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,3018.6 L2555.92,3018.6 M2543.92,3006.6 L2543.92,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,3154.37 L2634.43,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,3109.11 L2646.43,3109.11 M2634.43,3097.11 L2634.43,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,3063.86 L2724.94,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2724.94\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2712.94,3018.6 L2736.94,3018.6 M2724.94,3006.6 L2724.94,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3018.6,3109.11 L2973.35,3063.86 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2961.35,3063.86 L2985.35,3063.86 M2973.35,3051.86 L2973.35,3075.86 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,3018.6 L3063.86,2973.35 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,2973.35 L3075.86,2973.35 M3063.86,2961.35 L3063.86,2985.35 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3109.11,3199.62 L3063.86,3154.37 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"3199.62\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"3154.37\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3051.86,3154.37 L3075.86,3154.37 M3063.86,3142.37 L3063.86,3166.37 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2973.35,2973.35 L3018.6,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2973.35\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3018.6\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3006.6,3018.6 L3030.6,3018.6 M3018.6,3006.6 L3018.6,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3063.86,3063.86 L3109.11,3109.11 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3063.86\\\" cy=\\\"3063.86\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3109.11\\\" cy=\\\"3109.11\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3097.11,3109.11 L3121.11,3109.11 M3109.11,3097.11 L3109.11,3121.11 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M3154.37,2973.35 L3199.62,3018.6 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"3154.37\\\" cy=\\\"2973.35\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"3199.62\\\" cy=\\\"3018.6\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M3187.62,3018.6 L3211.62,3018.6 M3199.62,3006.6 L3199.62,3030.6 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"2912.09\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3493.28\\\" y=\\\"2928.09\\\">H</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3002.6\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3583.79\\\" y=\\\"3018.6\\\">H</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"3093.11\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3493.28\\\" y=\\\"3109.11\\\">H</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3183.62\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3583.79\\\" y=\\\"3199.62\\\">H</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"3386.77\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"170.51\\\" y=\\\"3402.77\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"170.51\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"261.019\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"335.529\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"351.529\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"80\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"170.51\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"261.019\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"3658.3\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"261.019\\\" y=\\\"3674.3\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"3386.77\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"3402.77\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"3493.28\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"3583.79\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"3658.3\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"3674.3\\\">H</text>\\n\",\n              \"<path d=\\\"M1119.87,3402.77 L1165.13,3448.03 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"3402.77\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,3448.03 L1177.13,3448.03 M1165.13,3436.03 L1165.13,3460.03 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,3583.79 L1165.13,3629.05 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,3629.05 L1177.13,3629.05 M1165.13,3617.05 L1165.13,3641.05 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,3493.28 L1255.64,3538.54 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,3538.54 L1267.64,3538.54 M1255.64,3526.54 L1255.64,3550.54 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,3629.05 L1029.36,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1017.36,3583.79 L1041.36,3583.79 M1029.36,3571.79 L1029.36,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,3538.54 L1119.87,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,3493.28 L1131.87,3493.28 M1119.87,3481.28 L1119.87,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,3629.05 L1210.38,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,3583.79 L1222.38,3583.79 M1210.38,3571.79 L1210.38,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,3402.77 L1549.3,3448.03 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3402.77\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,3448.03 L1561.3,3448.03 M1549.3,3436.03 L1549.3,3460.03 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1594.56,3583.79 L1549.3,3629.05 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1537.3,3629.05 L1561.3,3629.05 M1549.3,3617.05 L1549.3,3641.05 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1685.06,3493.28 L1639.81,3538.54 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1627.81,3538.54 L1651.81,3538.54 M1639.81,3526.54 L1639.81,3550.54 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1549.3,3538.54 L1504.05,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1549.3\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1504.05\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1492.05,3583.79 L1516.05,3583.79 M1504.05,3571.79 L1504.05,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1639.81,3448.03 L1594.56,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1639.81\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1594.56\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1582.56,3493.28 L1606.56,3493.28 M1594.56,3481.28 L1594.56,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1730.32,3538.54 L1685.06,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1730.32\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1685.06\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1673.06,3583.79 L1697.06,3583.79 M1685.06,3571.79 L1685.06,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2069.24,3583.79 L2114.49,3538.54 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2102.49,3538.54 L2126.49,3538.54 M2114.49,3526.54 L2114.49,3550.54 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,3493.28 L2205,3448.03 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,3448.03 L2217,3448.03 M2205,3436.03 L2205,3460.03 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2159.75,3674.3 L2205,3629.05 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3674.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2193,3629.05 L2217,3629.05 M2205,3617.05 L2205,3641.05 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2023.98,3538.54 L2069.24,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2023.98\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2069.24\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2057.24,3493.28 L2081.24,3493.28 M2069.24,3481.28 L2069.24,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2114.49,3629.05 L2159.75,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2114.49\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2159.75\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2147.75,3583.79 L2171.75,3583.79 M2159.75,3571.79 L2159.75,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2205,3538.54 L2250.26,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2205\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2250.26\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2238.26,3493.28 L2262.26,3493.28 M2250.26,3481.28 L2250.26,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2543.92,3583.79 L2498.66,3538.54 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2486.66,3538.54 L2510.66,3538.54 M2498.66,3526.54 L2498.66,3550.54 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,3493.28 L2589.17,3448.03 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,3448.03 L2601.17,3448.03 M2589.17,3436.03 L2589.17,3460.03 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2634.43,3674.3 L2589.17,3629.05 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3674.3\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3629.05\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2577.17,3629.05 L2601.17,3629.05 M2589.17,3617.05 L2589.17,3641.05 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2498.66,3448.03 L2543.92,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2498.66\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2543.92\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2531.92,3493.28 L2555.92,3493.28 M2543.92,3481.28 L2543.92,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2589.17,3538.54 L2634.43,3583.79 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2589.17\\\" cy=\\\"3538.54\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2634.43\\\" cy=\\\"3583.79\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2622.43,3583.79 L2646.43,3583.79 M2634.43,3571.79 L2634.43,3595.79 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M2679.68,3448.03 L2724.94,3493.28 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"2679.68\\\" cy=\\\"3448.03\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"2724.94\\\" cy=\\\"3493.28\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M2712.94,3493.28 L2736.94,3493.28 M2724.94,3481.28 L2724.94,3505.28 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"3386.77\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"3402.77\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"3493.28\\\">H</text>\\n\",\n              \"<rect x=\\\"3002.6\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3018.6\\\" y=\\\"3583.79\\\">H</text>\\n\",\n              \"<rect x=\\\"3093.11\\\" y=\\\"3658.3\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3109.11\\\" y=\\\"3674.3\\\">H</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"3386.77\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"3402.77\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3658.3\\\" y=\\\"3477.28\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3674.3\\\" y=\\\"3493.28\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3386.77\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3402.77\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3477.28\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3493.28\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3567.79\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"3583.79\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3567.79\\\" y=\\\"3658.3\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"3583.79\\\" y=\\\"3674.3\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"3432.03\\\" y=\\\"3432.03\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3448.03\\\" y=\\\"3448.03\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3522.54\\\" y=\\\"3432.03\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3538.54\\\" y=\\\"3448.03\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3613.05\\\" y=\\\"3432.03\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3629.05\\\" y=\\\"3448.03\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3432.03\\\" y=\\\"3522.54\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3448.03\\\" y=\\\"3538.54\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3522.54\\\" y=\\\"3522.54\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3538.54\\\" y=\\\"3538.54\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3613.05\\\" y=\\\"3522.54\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3629.05\\\" y=\\\"3538.54\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3432.03\\\" y=\\\"3613.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3448.03\\\" y=\\\"3629.05\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3522.54\\\" y=\\\"3613.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3538.54\\\" y=\\\"3629.05\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<rect x=\\\"3613.05\\\" y=\\\"3613.05\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"3629.05\\\" y=\\\"3629.05\\\" fill=\\\"white\\\">M</text>\\n\",\n              \"<g id=\\\"tick_borders\\\">\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-425.529\\\">Tick 0</text>\\n\",\n              \"<rect id=\\\"tick_border:0:0_0:0\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-900.211\\\">Tick 1</text>\\n\",\n              \"<rect id=\\\"tick_border:1:0_1:1\\\" x=\\\"474.682\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-1374.89\\\">Tick 2</text>\\n\",\n              \"<rect id=\\\"tick_border:2:0_2:2\\\" x=\\\"949.364\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-1849.57\\\">Tick 3</text>\\n\",\n              \"<rect id=\\\"tick_border:3:0_3:3\\\" x=\\\"1424.05\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-2324.26\\\">Tick 4</text>\\n\",\n              \"<rect id=\\\"tick_border:4:0_4:4\\\" x=\\\"1898.73\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-2798.94\\\">Tick 5</text>\\n\",\n              \"<rect id=\\\"tick_border:5:0_5:5\\\" x=\\\"2373.41\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-3273.62\\\">Tick 6</text>\\n\",\n              \"<rect id=\\\"tick_border:6:0_6:6\\\" x=\\\"2848.09\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-3748.3\\\">Tick 7</text>\\n\",\n              \"<rect id=\\\"tick_border:7:0_7:7\\\" x=\\\"3322.77\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-425.529\\\">Tick 8</text>\\n\",\n              \"<rect id=\\\"tick_border:8:1_0:8\\\" x=\\\"0\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-900.211\\\">Tick 9</text>\\n\",\n              \"<rect id=\\\"tick_border:9:1_1:9\\\" x=\\\"474.682\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-1374.89\\\">Tick 10</text>\\n\",\n              \"<rect id=\\\"tick_border:10:1_2:10\\\" x=\\\"949.364\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-1849.57\\\">Tick 11</text>\\n\",\n              \"<rect id=\\\"tick_border:11:1_3:11\\\" x=\\\"1424.05\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-2324.26\\\">Tick 12</text>\\n\",\n              \"<rect id=\\\"tick_border:12:1_4:12\\\" x=\\\"1898.73\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-2798.94\\\">Tick 13</text>\\n\",\n              \"<rect id=\\\"tick_border:13:1_5:13\\\" x=\\\"2373.41\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-3273.62\\\">Tick 14</text>\\n\",\n              \"<rect id=\\\"tick_border:14:1_6:14\\\" x=\\\"2848.09\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-3748.3\\\">Tick 15</text>\\n\",\n              \"<rect id=\\\"tick_border:15:1_7:15\\\" x=\\\"3322.77\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-425.529\\\">Tick 16</text>\\n\",\n              \"<rect id=\\\"tick_border:16:2_0:16\\\" x=\\\"0\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-900.211\\\">Tick 17</text>\\n\",\n              \"<rect id=\\\"tick_border:17:2_1:17\\\" x=\\\"474.682\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-1374.89\\\">Tick 18</text>\\n\",\n              \"<rect id=\\\"tick_border:18:2_2:18\\\" x=\\\"949.364\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-1849.57\\\">Tick 19</text>\\n\",\n              \"<rect id=\\\"tick_border:19:2_3:19\\\" x=\\\"1424.05\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-2324.26\\\">Tick 20</text>\\n\",\n              \"<rect id=\\\"tick_border:20:2_4:20\\\" x=\\\"1898.73\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-2798.94\\\">Tick 21</text>\\n\",\n              \"<rect id=\\\"tick_border:21:2_5:21\\\" x=\\\"2373.41\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-3273.62\\\">Tick 22</text>\\n\",\n              \"<rect id=\\\"tick_border:22:2_6:22\\\" x=\\\"2848.09\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-3748.3\\\">Tick 23</text>\\n\",\n              \"<rect id=\\\"tick_border:23:2_7:23\\\" x=\\\"3322.77\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-425.529\\\">Tick 24</text>\\n\",\n              \"<rect id=\\\"tick_border:24:3_0:24\\\" x=\\\"0\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-900.211\\\">Tick 25</text>\\n\",\n              \"<rect id=\\\"tick_border:25:3_1:25\\\" x=\\\"474.682\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-1374.89\\\">Tick 26</text>\\n\",\n              \"<rect id=\\\"tick_border:26:3_2:26\\\" x=\\\"949.364\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-1849.57\\\">Tick 27</text>\\n\",\n              \"<rect id=\\\"tick_border:27:3_3:27\\\" x=\\\"1424.05\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-2324.26\\\">Tick 28</text>\\n\",\n              \"<rect id=\\\"tick_border:28:3_4:28\\\" x=\\\"1898.73\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-2798.94\\\">Tick 29</text>\\n\",\n              \"<rect id=\\\"tick_border:29:3_5:29\\\" x=\\\"2373.41\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-3273.62\\\">Tick 30</text>\\n\",\n              \"<rect id=\\\"tick_border:30:3_6:30\\\" x=\\\"2848.09\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1639.81\\\" y=\\\"-3748.3\\\">Tick 31</text>\\n\",\n              \"<rect id=\\\"tick_border:31:3_7:31\\\" x=\\\"3322.77\\\" y=\\\"1424.05\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-425.529\\\">Tick 32</text>\\n\",\n              \"<rect id=\\\"tick_border:32:4_0:32\\\" x=\\\"0\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-900.211\\\">Tick 33</text>\\n\",\n              \"<rect id=\\\"tick_border:33:4_1:33\\\" x=\\\"474.682\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-1374.89\\\">Tick 34</text>\\n\",\n              \"<rect id=\\\"tick_border:34:4_2:34\\\" x=\\\"949.364\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-1849.57\\\">Tick 35</text>\\n\",\n              \"<rect id=\\\"tick_border:35:4_3:35\\\" x=\\\"1424.05\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-2324.26\\\">Tick 36</text>\\n\",\n              \"<rect id=\\\"tick_border:36:4_4:36\\\" x=\\\"1898.73\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-2798.94\\\">Tick 37</text>\\n\",\n              \"<rect id=\\\"tick_border:37:4_5:37\\\" x=\\\"2373.41\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-3273.62\\\">Tick 38</text>\\n\",\n              \"<rect id=\\\"tick_border:38:4_6:38\\\" x=\\\"2848.09\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2114.49\\\" y=\\\"-3748.3\\\">Tick 39</text>\\n\",\n              \"<rect id=\\\"tick_border:39:4_7:39\\\" x=\\\"3322.77\\\" y=\\\"1898.73\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-425.529\\\">Tick 40</text>\\n\",\n              \"<rect id=\\\"tick_border:40:5_0:40\\\" x=\\\"0\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-900.211\\\">Tick 41</text>\\n\",\n              \"<rect id=\\\"tick_border:41:5_1:41\\\" x=\\\"474.682\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-1374.89\\\">Tick 42</text>\\n\",\n              \"<rect id=\\\"tick_border:42:5_2:42\\\" x=\\\"949.364\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-1849.57\\\">Tick 43</text>\\n\",\n              \"<rect id=\\\"tick_border:43:5_3:43\\\" x=\\\"1424.05\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-2324.26\\\">Tick 44</text>\\n\",\n              \"<rect id=\\\"tick_border:44:5_4:44\\\" x=\\\"1898.73\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-2798.94\\\">Tick 45</text>\\n\",\n              \"<rect id=\\\"tick_border:45:5_5:45\\\" x=\\\"2373.41\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-3273.62\\\">Tick 46</text>\\n\",\n              \"<rect id=\\\"tick_border:46:5_6:46\\\" x=\\\"2848.09\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"2589.17\\\" y=\\\"-3748.3\\\">Tick 47</text>\\n\",\n              \"<rect id=\\\"tick_border:47:5_7:47\\\" x=\\\"3322.77\\\" y=\\\"2373.41\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-425.529\\\">Tick 48</text>\\n\",\n              \"<rect id=\\\"tick_border:48:6_0:48\\\" x=\\\"0\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-900.211\\\">Tick 49</text>\\n\",\n              \"<rect id=\\\"tick_border:49:6_1:49\\\" x=\\\"474.682\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-1374.89\\\">Tick 50</text>\\n\",\n              \"<rect id=\\\"tick_border:50:6_2:50\\\" x=\\\"949.364\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-1849.57\\\">Tick 51</text>\\n\",\n              \"<rect id=\\\"tick_border:51:6_3:51\\\" x=\\\"1424.05\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-2324.26\\\">Tick 52</text>\\n\",\n              \"<rect id=\\\"tick_border:52:6_4:52\\\" x=\\\"1898.73\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-2798.94\\\">Tick 53</text>\\n\",\n              \"<rect id=\\\"tick_border:53:6_5:53\\\" x=\\\"2373.41\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-3273.62\\\">Tick 54</text>\\n\",\n              \"<rect id=\\\"tick_border:54:6_6:54\\\" x=\\\"2848.09\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3063.86\\\" y=\\\"-3748.3\\\">Tick 55</text>\\n\",\n              \"<rect id=\\\"tick_border:55:6_7:55\\\" x=\\\"3322.77\\\" y=\\\"2848.09\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-425.529\\\">Tick 56</text>\\n\",\n              \"<rect id=\\\"tick_border:56:7_0:56\\\" x=\\\"0\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-900.211\\\">Tick 57</text>\\n\",\n              \"<rect id=\\\"tick_border:57:7_1:57\\\" x=\\\"474.682\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-1374.89\\\">Tick 58</text>\\n\",\n              \"<rect id=\\\"tick_border:58:7_2:58\\\" x=\\\"949.364\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-1849.57\\\">Tick 59</text>\\n\",\n              \"<rect id=\\\"tick_border:59:7_3:59\\\" x=\\\"1424.05\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-2324.26\\\">Tick 60</text>\\n\",\n              \"<rect id=\\\"tick_border:60:7_4:60\\\" x=\\\"1898.73\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-2798.94\\\">Tick 61</text>\\n\",\n              \"<rect id=\\\"tick_border:61:7_5:61\\\" x=\\\"2373.41\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-3273.62\\\">Tick 62</text>\\n\",\n              \"<rect id=\\\"tick_border:62:7_6:62\\\" x=\\\"2848.09\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"3538.54\\\" y=\\\"-3748.3\\\">Tick 63</text>\\n\",\n              \"<rect id=\\\"tick_border:63:7_7:63\\\" x=\\\"3322.77\\\" y=\\\"3322.77\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"</svg>\"\n            ]\n          },\n          \"execution_count\": 30,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"surface_code_circuit.without_noise().diagram(\\\"timeslice-svg\\\")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"fPOBAR4T-qOW\"\n      },\n      \"source\": [\n        \"You can also make 3-D diagrams of the circuit, using `timeline-3d`.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\",\n          \"height\": 404\n        },\n        \"id\": \"XLqwFH29-qOW\",\n        \"outputId\": \"42a217ab-1a92-4850-b634-932f3a8f603e\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"text/html\": [\n              \"<iframe style=\\\"width: 100%; height: 300px; overflow: hidden; resize: both; border: 1px dashed gray;\\\" frameBorder=\\\"0\\\" srcdoc=\\\"\\n\",\n              \"&lt;!DOCTYPE html&gt;\\n\",\n              \"&lt;html&gt;\\n\",\n              \"&lt;head&gt;\\n\",\n              \"  &lt;meta charset=&quot;UTF-8&quot; /&gt;\\n\",\n              \"  &lt;script type=&quot;importmap&quot;&gt;\\n\",\n              \"    {\\n\",\n              \"      &quot;imports&quot;: {\\n\",\n              \"        &quot;three&quot;: &quot;https://unpkg.com/three@0.138.0/build/three.module.js&quot;,\\n\",\n              \"        &quot;three-orbitcontrols&quot;: &quot;https://unpkg.com/three@0.138.0/examples/jsm/controls/OrbitControls.js&quot;,\\n\",\n              \"        &quot;three-gltf-loader&quot;: &quot;https://unpkg.com/three@0.138.0/examples/jsm/loaders/GLTFLoader.js&quot;\\n\",\n              \"      }\\n\",\n              \"    }\\n\",\n              \"  &lt;/script&gt;\\n\",\n              \"&lt;/head&gt;\\n\",\n              \"&lt;body&gt;\\n\",\n              \"  &lt;a download=&quot;model.gltf&quot; id=&quot;stim-3d-viewer-download-link&quot; href=&quot;data:text/plain;base64,eyJhY2Nlc3NvcnMiOlt7ImJ1ZmZlclZpZXciOjAsImJ5dGVPZmZzZXQiOjAsImNvbXBvbmVudFR5cGUiOjUxMjYsImNvdW50IjoxMiwibWF4IjpbMCwwLjUsMC41XSwibWluIjpbMCwtMC41LC0wLjVdLCJuYW1lIjoiY3ViZSIsInR5cGUiOiJWRUMzIn0seyJidWZmZXJWaWV3IjoxLCJieXRlT2Zmc2V0IjowLCJjb21wb25lbnRUeXBlIjo1MTI2LCJjb3VudCI6MTIsIm1heCI6WzAuMzc1LDAuNTYyNV0sIm1pbiI6WzAuMzEyNSwwLjVdLCJuYW1lIjoidGV4X2Nvb3Jkc19nYXRlX1IiLCJ0eXBlIjoiVkVDMiJ9LHsiYnVmZmVyVmlldyI6MiwiYnl0ZU9mZnNldCI6MCwiY29tcG9uZW50VHlwZSI6NTEyNiwiY291bnQiOjEyLCJtYXgiOlswLjEyNSwwLjVdLCJtaW4iOlswLjA2MjUsMC40Mzc1XSwibmFtZSI6InRleF9jb29yZHNfZ2F0ZV9IIiwidHlwZSI6IlZFQzIifSx7ImJ1ZmZlclZpZXciOjMsImJ5dGVPZmZzZXQiOjAsImNvbXBvbmVudFR5cGUiOjUxMjYsImNvdW50IjoxNywibWF4IjpbMCwwLjQwMDAwMDAwNTk2MDQ2NCwwLjQwMDAwMDAwNTk2MDQ2NF0sIm1pbiI6WzAsLTAuNDAwMDAwMDA1OTYwNDY0LC0wLjQwMDAwMDAwNTk2MDQ2NF0sIm5hbWUiOiJjaXJjbGVfbG9vcCIsInR5cGUiOiJWRUMzIn0seyJidWZmZXJWaWV3Ijo0LCJieXRlT2Zmc2V0IjowLCJjb21wb25lbnRUeXBlIjo1MTI2LCJjb3VudCI6MTcsIm1heCI6WzAsMC40MDAwMDAwMDU5NjA0NjQsMC40MDAwMDAwMDU5NjA0NjRdLCJtaW4iOlswLC0wLjQwMDAwMDAwNTk2MDQ2NCwtMC40MDAwMDAwMDU5NjA0NjRdLCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ0eXBlIjoiVkVDMyJ9LHsiYnVmZmVyVmlldyI6NSwiYnl0ZU9mZnNldCI6MCwiY29tcG9uZW50VHlwZSI6NTEyNiwiY291bnQiOjQsIm1heCI6WzAsMC40MDAwMDAwMDU5NjA0NjQsMC40MDAwMDAwMDU5NjA0NjRdLCJtaW4iOlswLC0wLjQwMDAwMDAwNTk2MDQ2NCwtMC40MDAwMDAwMDU5NjA0NjRdLCJuYW1lIjoiY29udHJvbF94X2xpbmVfY3Jvc3MiLCJ0eXBlIjoiVkVDMyJ9LHsiYnVmZmVyVmlldyI6NiwiYnl0ZU9mZnNldCI6MCwiY29tcG9uZW50VHlwZSI6NTEyNiwiY291bnQiOjEyLCJtYXgiOlswLjQzNzUsMC41NjI1XSwibWluIjpbMC4zNzUsMC41XSwibmFtZSI6InRleF9jb29yZHNfZ2F0ZV9NUiIsInR5cGUiOiJWRUMyIn0seyJidWZmZXJWaWV3Ijo3LCJieXRlT2Zmc2V0IjowLCJjb21wb25lbnRUeXBlIjo1MTI2LCJjb3VudCI6MTIsIm1heCI6WzAuMzEyNSwwLjU2MjVdLCJtaW4iOlswLjI1LDAuNV0sIm5hbWUiOiJ0ZXhfY29vcmRzX2dhdGVfTSIsInR5cGUiOiJWRUMyIn0seyJidWZmZXJWaWV3Ijo4LCJieXRlT2Zmc2V0IjowLCJjb21wb25lbnRUeXBlIjo1MTI2LCJjb3VudCI6MTMwLCJtYXgiOlsxLC0zMiwtMzJdLCJtaW4iOlstMTcsLTQwLjQ4NTI4Mjg5Nzk0OTIsLTQwLjQ4NTI4Mjg5Nzk0OTJdLCJuYW1lIjoiYnVmX3NjYXR0ZXJlZF9saW5lcyIsInR5cGUiOiJWRUMzIn0seyJidWZmZXJWaWV3Ijo5LCJieXRlT2Zmc2V0IjowLCJjb21wb25lbnRUeXBlIjo1MTI2LCJjb3VudCI6MzAsIm1heCI6WzAsLTI5LjUsLTMxXSwibWluIjpbLTE1LjI1LC00MS40ODUyODI4OTc5NDkyLC00MS40ODUyODI4OTc5NDkyXSwibmFtZSI6ImJ1Zl9yZWRfc2NhdHRlcmVkX2xpbmVzIiwidHlwZSI6IlZFQzMifV0sImFzc2V0Ijp7InZlcnNpb24iOiIyLjAifSwiYnVmZmVyVmlld3MiOlt7ImJ1ZmZlciI6MCwiYnl0ZUxlbmd0aCI6MTQ0LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoiY3ViZSIsInRhcmdldCI6MzQ5NjJ9LHsiYnVmZmVyIjoxLCJieXRlTGVuZ3RoIjo5NiwiYnl0ZU9mZnNldCI6MCwibmFtZSI6InRleF9jb29yZHNfZ2F0ZV9SIiwidGFyZ2V0IjozNDk2Mn0seyJidWZmZXIiOjIsImJ5dGVMZW5ndGgiOjk2LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoidGV4X2Nvb3Jkc19nYXRlX0giLCJ0YXJnZXQiOjM0OTYyfSx7ImJ1ZmZlciI6MywiYnl0ZUxlbmd0aCI6MjA0LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ0YXJnZXQiOjM0OTYyfSx7ImJ1ZmZlciI6NCwiYnl0ZUxlbmd0aCI6MjA0LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ0YXJnZXQiOjM0OTYyfSx7ImJ1ZmZlciI6NSwiYnl0ZUxlbmd0aCI6NDgsImJ5dGVPZmZzZXQiOjAsIm5hbWUiOiJjb250cm9sX3hfbGluZV9jcm9zcyIsInRhcmdldCI6MzQ5NjJ9LHsiYnVmZmVyIjo2LCJieXRlTGVuZ3RoIjo5NiwiYnl0ZU9mZnNldCI6MCwibmFtZSI6InRleF9jb29yZHNfZ2F0ZV9NUiIsInRhcmdldCI6MzQ5NjJ9LHsiYnVmZmVyIjo3LCJieXRlTGVuZ3RoIjo5NiwiYnl0ZU9mZnNldCI6MCwibmFtZSI6InRleF9jb29yZHNfZ2F0ZV9NIiwidGFyZ2V0IjozNDk2Mn0seyJidWZmZXIiOjgsImJ5dGVMZW5ndGgiOjE1NjAsImJ5dGVPZmZzZXQiOjAsIm5hbWUiOiJidWZfc2NhdHRlcmVkX2xpbmVzIiwidGFyZ2V0IjozNDk2Mn0seyJidWZmZXIiOjksImJ5dGVMZW5ndGgiOjM2MCwiYnl0ZU9mZnNldCI6MCwibmFtZSI6ImJ1Zl9yZWRfc2NhdHRlcmVkX2xpbmVzIiwidGFyZ2V0IjozNDk2Mn1dLCJidWZmZXJzIjpbeyJieXRlTGVuZ3RoIjoxNDQsIm5hbWUiOiJjdWJlIiwidXJpIjoiZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LEFBQUFBQUFBQUQ4QUFBQS9BQUFBQUFBQUFEOEFBQUMvQUFBQUFBQUFBTDhBQUFBL0FBQUFBQUFBQUQ4QUFBQy9BQUFBQUFBQUFMOEFBQUMvQUFBQUFBQUFBTDhBQUFBL0FBQUFBQUFBQUw4QUFBQy9BQUFBQUFBQUFEOEFBQUMvQUFBQUFBQUFBTDhBQUFBL0FBQUFBQUFBQUw4QUFBQS9BQUFBQUFBQUFEOEFBQUMvQUFBQUFBQUFBRDhBQUFBLyJ9LHsiYnl0ZUxlbmd0aCI6OTYsIm5hbWUiOiJ0ZXhfY29vcmRzX2dhdGVfUiIsInVyaSI6ImRhdGE6YXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtO2Jhc2U2NCxBQURBUGdBQUFEOEFBS0ErQUFBQVB3QUF3RDRBQUJBL0FBQ2dQZ0FBQUQ4QUFLQStBQUFRUHdBQXdENEFBQkEvQUFEQVBnQUFFRDhBQU1BK0FBQUFQd0FBb0Q0QUFCQS9BQUNnUGdBQUVEOEFBTUErQUFBQVB3QUFvRDRBQUFBLyJ9LHsiYnl0ZUxlbmd0aCI6OTYsIm5hbWUiOiJ0ZXhfY29vcmRzX2dhdGVfSCIsInVyaSI6ImRhdGE6YXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtO2Jhc2U2NCxBQUFBUGdBQTRENEFBSUE5QUFEZ1BnQUFBRDRBQUFBL0FBQ0FQUUFBNEQ0QUFJQTlBQUFBUHdBQUFENEFBQUEvQUFBQVBnQUFBRDhBQUFBK0FBRGdQZ0FBZ0QwQUFBQS9BQUNBUFFBQUFEOEFBQUErQUFEZ1BnQUFnRDBBQU9BKyJ9LHsiYnl0ZUxlbmd0aCI6MjA0LCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ1cmkiOiJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsQUFBQUFNM016RDRBQUFBQUFBQUFBT1UxdlQ1RnZ4dytBQUFBQU1QUWtEN0QwSkErQUFBQUFFUy9IRDdsTmIwK0FBQUFBUEl3bHJMTnpNdytBQUFBQUVlL0hMN2xOYjArQUFBQUFNUFFrTDdEMEpBK0FBQUFBT2MxdmI1QXZ4dytBQUFBQU0zTXpMN3lNQmF6QUFBQUFPVTF2YjVFdnh5K0FBQUFBTUhRa0w3RTBKQytBQUFBQUR5L0hMN25OYjIrQUFBQUFQTGtvekhOek15K0FBQUFBRW0vSEQ3a05iMitBQUFBQU1iUWtENi8wSkMrQUFBQUFPWTF2VDVFdnh5K0FBQUFBTTNNekQ0QUFBQUEifSx7ImJ5dGVMZW5ndGgiOjIwNCwibmFtZSI6ImNpcmNsZV9sb29wIiwidXJpIjoiZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LEFBQUFBTTNNekQ0QUFBQUFBQUFBQU9VMXZUNUZ2eHcrQUFBQUFNUFFrRDdEMEpBK0FBQUFBRVMvSEQ3bE5iMCtBQUFBQVBJd2xyTE56TXcrQUFBQUFFZS9ITDdsTmIwK0FBQUFBTVBRa0w3RDBKQStBQUFBQU9jMXZiNUF2eHcrQUFBQUFNM016TDd5TUJhekFBQUFBT1UxdmI1RXZ4eStBQUFBQU1IUWtMN0UwSkMrQUFBQUFEeS9ITDduTmIyK0FBQUFBUExrb3pITnpNeStBQUFBQUVtL0hEN2tOYjIrQUFBQUFNYlFrRDYvMEpDK0FBQUFBT1kxdlQ1RXZ4eStBQUFBQU0zTXpENEFBQUFBIn0seyJieXRlTGVuZ3RoIjo0OCwibmFtZSI6ImNvbnRyb2xfeF9saW5lX2Nyb3NzIiwidXJpIjoiZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LEFBQUFBTTNNekw0QUFBQUFBQUFBQU0zTXpENEFBQUFBQUFBQUFBQUFBQUROek15K0FBQUFBQUFBQUFETnpNdysifSx7ImJ5dGVMZW5ndGgiOjk2LCJuYW1lIjoidGV4X2Nvb3Jkc19nYXRlX01SIiwidXJpIjoiZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LEFBRGdQZ0FBQUQ4QUFNQStBQUFBUHdBQTRENEFBQkEvQUFEQVBnQUFBRDhBQU1BK0FBQVFQd0FBNEQ0QUFCQS9BQURnUGdBQUVEOEFBT0ErQUFBQVB3QUF3RDRBQUJBL0FBREFQZ0FBRUQ4QUFPQStBQUFBUHdBQXdENEFBQUEvIn0seyJieXRlTGVuZ3RoIjo5NiwibmFtZSI6InRleF9jb29yZHNfZ2F0ZV9NIiwidXJpIjoiZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LEFBQ2dQZ0FBQUQ4QUFJQStBQUFBUHdBQW9ENEFBQkEvQUFDQVBnQUFBRDhBQUlBK0FBQVFQd0FBb0Q0QUFCQS9BQUNnUGdBQUVEOEFBS0ErQUFBQVB3QUFnRDRBQUJBL0FBQ0FQZ0FBRUQ4QUFLQStBQUFBUHdBQWdENEFBQUEvIn0seyJieXRlTGVuZ3RoIjoxNTYwLCJuYW1lIjoiYnVmX3NjYXR0ZXJlZF9saW5lcyIsInVyaSI6ImRhdGE6YXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtO2Jhc2U2NCxBQUFBd0U5UUM4SUFBQURDQUFBQXdIZjRFTUlvcUFYQ0FBQUF3RTlRQzhLZW9CYkNBQUFBd0hmNEVNTEdTQnpDQUFBQXdKNmdGc0pQVUF2Q0FBQUF3TVpJSE1KMytCRENBQUFBd0Npb0JjTEdTQnpDQUFBQXdBQUFBTUtlb0JiQ0FBQUF3SGY0RU1KMytCRENBQUFBd0U5UUM4SlBVQXZDQUFBQXdNWklITUxHU0J6Q0FBQUF3SjZnRnNLZW9CYkNBQUJBd0U5UUM4SUFBQURDQUFCQXdDaW9CY0lvcUFYQ0FBQkF3RTlRQzhLZW9CYkNBQUJBd0Npb0JjTEdTQnpDQUFCQXdKNmdGc0pQVUF2Q0FBQkF3SGY0RU1KMytCRENBQUJBd0Npb0JjSjMrQkRDQUFCQXdBQUFBTUtlb0JiQ0FBQkF3SGY0RU1Jb3FBWENBQUJBd0U5UUM4SlBVQXZDQUFCQXdNWklITUozK0JEQ0FBQkF3SjZnRnNLZW9CYkNBQUNBd0U5UUM4S2VvQmJDQUFDQXdIZjRFTUozK0JEQ0FBQ0F3SjZnRnNKUFVBdkNBQUNBd01aSUhNSW9xQVhDQUFDQXdKNmdGc0x1OENIQ0FBQ0F3TVpJSE1MR1NCekNBQUNBd0Npb0JjSjMrQkRDQUFDQXdFOVFDOEpQVUF2Q0FBQ0F3SGY0RU1MR1NCekNBQUNBd0o2Z0ZzS2VvQmJDQUFDQXdNWklITUozK0JEQ0FBQ0F3Tzd3SWNKUFVBdkNBQUNnd0U5UUM4S2VvQmJDQUFDZ3dDaW9CY0ozK0JEQ0FBQ2d3SjZnRnNKUFVBdkNBQUNnd0hmNEVNSW9xQVhDQUFDZ3dKNmdGc0x1OENIQ0FBQ2d3SGY0RU1MR1NCekNBQUNnd0Npb0JjSW9xQVhDQUFDZ3dFOVFDOEpQVUF2Q0FBQ2d3SGY0RU1KMytCRENBQUNnd0o2Z0ZzS2VvQmJDQUFDZ3dNWklITUlvcUFYQ0FBQ2d3Tzd3SWNKUFVBdkNBQUFnd1U5UUM4SUFBQURDQUFBZ3dYZjRFTUlvcUFYQ0FBQWd3VTlRQzhLZW9CYkNBQUFnd1hmNEVNTEdTQnpDQUFBZ3daNmdGc0pQVUF2Q0FBQWd3Y1pJSE1KMytCRENBQUFnd1Npb0JjTEdTQnpDQUFBZ3dRQUFBTUtlb0JiQ0FBQWd3WGY0RU1KMytCRENBQUFnd1U5UUM4SlBVQXZDQUFBZ3djWklITUxHU0J6Q0FBQWd3WjZnRnNLZW9CYkNBQUF3d1U5UUM4SUFBQURDQUFBd3dTaW9CY0lvcUFYQ0FBQXd3VTlRQzhLZW9CYkNBQUF3d1Npb0JjTEdTQnpDQUFBd3daNmdGc0pQVUF2Q0FBQXd3WGY0RU1KMytCRENBQUF3d1Npb0JjSjMrQkRDQUFBd3dRQUFBTUtlb0JiQ0FBQXd3WGY0RU1Jb3FBWENBQUF3d1U5UUM4SlBVQXZDQUFBd3djWklITUozK0JEQ0FBQXd3WjZnRnNLZW9CYkNBQUJBd1U5UUM4S2VvQmJDQUFCQXdYZjRFTUozK0JEQ0FBQkF3WjZnRnNKUFVBdkNBQUJBd2NaSUhNSW9xQVhDQUFCQXdaNmdGc0x1OENIQ0FBQkF3Y1pJSE1MR1NCekNBQUJBd1Npb0JjSjMrQkRDQUFCQXdVOVFDOEpQVUF2Q0FBQkF3WGY0RU1MR1NCekNBQUJBd1o2Z0ZzS2VvQmJDQUFCQXdjWklITUozK0JEQ0FBQkF3ZTd3SWNKUFVBdkNBQUJRd1U5UUM4S2VvQmJDQUFCUXdTaW9CY0ozK0JEQ0FBQlF3WjZnRnNKUFVBdkNBQUJRd1hmNEVNSW9xQVhDQUFCUXdaNmdGc0x1OENIQ0FBQlF3WGY0RU1MR1NCekNBQUJRd1Npb0JjSW9xQVhDQUFCUXdVOVFDOEpQVUF2Q0FBQlF3WGY0RU1KMytCRENBQUJRd1o2Z0ZzS2VvQmJDQUFCUXdjWklITUlvcUFYQ0FBQlF3ZTd3SWNKUFVBdkNBQUNBUHlpb0JjSW9xQVhDQUFDSXdTaW9CY0lvcUFYQ0FBQ0FQMDlRQzhJQUFBRENBQUNJd1U5UUM4SUFBQURDQUFDQVAzZjRFTUlvcUFYQ0FBQ0l3WGY0RU1Jb3FBWENBQUNBUDhaSUhNSW9xQVhDQUFDSXdjWklITUlvcUFYQ0FBQ0FQeWlvQmNKMytCRENBQUNJd1Npb0JjSjMrQkRDQUFDQVAwOVFDOEpQVUF2Q0FBQ0l3VTlRQzhKUFVBdkNBQUNBUDNmNEVNSjMrQkRDQUFDSXdYZjRFTUozK0JEQ0FBQ0FQNTZnRnNKUFVBdkNBQUNJd1o2Z0ZzSlBVQXZDQUFDQVA4WklITUozK0JEQ0FBQ0l3Y1pJSE1KMytCRENBQUNBUCs3d0ljSlBVQXZDQUFDSXdlN3dJY0pQVUF2Q0FBQ0FQd0FBQU1LZW9CYkNBQUNJd1FBQUFNS2VvQmJDQUFDQVB5aW9CY0xHU0J6Q0FBQ0l3U2lvQmNMR1NCekNBQUNBUDA5UUM4S2VvQmJDQUFDSXdVOVFDOEtlb0JiQ0FBQ0FQM2Y0RU1MR1NCekNBQUNJd1hmNEVNTEdTQnpDQUFDQVA1NmdGc0tlb0JiQ0FBQ0l3WjZnRnNLZW9CYkNBQUNBUDhaSUhNTEdTQnpDQUFDSXdjWklITUxHU0J6Q0FBQ0FQNTZnRnNMdThDSENBQUNJd1o2Z0ZzTHU4Q0hDIn0seyJieXRlTGVuZ3RoIjozNjAsIm5hbWUiOiJidWZfcmVkX3NjYXR0ZXJlZF9saW5lcyIsInVyaSI6ImRhdGE6YXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtO2Jhc2U2NCxBQUFBQUFBQThNRjMrQkRDQUFCQXdBQUE4TUYzK0JEQ0FBQWd3QUFBOU1GMytCRENBQUJBd0FBQThNRjMrQkRDQUFBZ3dBQUE3TUYzK0JEQ0FBQkF3QUFBOE1GMytCRENBQUQ0d0FBQStNRUFBUGpCQUFENHdBQUErTUh1OENYQ0FBRDR3QUFBK01FQUFQakJBQUQ0d083d0pjSUFBUGpCQUFENHdBQUErTUVBQVBqQkFBQjB3UUFBK01FQUFQakJBQUQ0d0FBQStNSHU4Q1hDQUFENHdPN3dKY0x1OENYQ0FBRDR3QUFBK01IdThDWENBQUIwd1FBQStNSHU4Q1hDQUFENHdPN3dKY0lBQVBqQkFBRDR3Tzd3SmNMdThDWENBQUQ0d083d0pjSUFBUGpCQUFCMHdlN3dKY0lBQVBqQkFBRDR3Tzd3SmNMdThDWENBQUIwd2U3d0pjTHU4Q1hDQUFCMHdRQUErTUVBQVBqQkFBQjB3UUFBK01IdThDWENBQUIwd1FBQStNRUFBUGpCQUFCMHdlN3dKY0lBQVBqQkFBQjB3UUFBK01IdThDWENBQUIwd2U3d0pjTHU4Q1hDQUFCMHdlN3dKY0lBQVBqQkFBQjB3ZTd3SmNMdThDWEMifV0sImltYWdlcyI6W3sidXJpIjoiZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFnQUFBQUlBQ0FZQUFBRDBlTlQ2QUFBZ0FFbEVRVlI0MnV5ZGQxUlV1ZHZIdjBPVkpvSWlWWW9DSWdpaXVCYXcvR3lzWXNPQ0RiRmdXUXYyWGtEQmlvcTlZbHNMVnRhdXU0cUs0T3JxS3Jvb05sQlJMSUNDSWdnQ00vQzhmK3c3OXpoTEVYWHVIWVI4enBrajNtVG1TWEtUbSs5Tm5pUWlJaUl3R0F3R2c4R29WQ2l4SW1Bd0dBd0dnd2tBQm9QQllEQVlUQUF3R0F3R2c4RmdBb0RCWURBWURBWVRBQXdHZzhGZ01KZ0FZRlF5enB3NWd6ZHYzckNDWURBWURDWUFHSldKMDZkUE13SEFBQUM4ZXZVS04yL2U1TjFPVEV3TVVsTlR5MFdlUFQwOTRlN3V6bTQrUStFTUdUSUV4NDRkcXp3QzRNT0hEM0J5Y29Lam95TXlNek1GczN2NzltM282K3RqekpneEFJRDgvSHcwYk5nUTl2YjIrUGp4bzJEcDJMWnRHMGFQSGkxekxUUTBGT1BHamVQVmJtNXVMZ0lEQTlHc1dUT0VoNGZEeThzTFZsWldHRGx5Sks1Y3VTSjNlK3ZXcllPcnF5dmMzZDNScmwwN0pDUWtsQm8vSVNFQkRnNE9lUC8rUFMvNXo4L1BSMGhJQ09yWHI0L2F0V3ZEenM0T2E5ZXVGYnorSnljbnc5VFV0RngwUU51M2I4ZWFOV3RRdjM1OTNtM1ZxMWNQQVFFQjJMTm5qOEx6ZmZ2MmJkeTZkWXYxUGd5RmtwK2ZqOGpJU0hUcTFPbnJ2MHcvS0NkUG5pUUFCSUJPbno0dG1OMk5HemNTQUxLd3NDQWlvb1NFQkM0ZGNYRnhncVZqeElnUnRIUG5UcGxyZ3djUHByQ3dNTjVzWm1abWtwT1RFM2w0ZUZCbVppYU5IVHVXN3Q2OVM2bXBxZFN0V3pjQ1FKOCtmWktidlZXclZwR2FtaG9sSmlZU0VaR25weWZaMk5pUVdDd3VObjUrZmo0MWFkS0VvcU9qZWNsL1lXRWhkZTdjbWFwVXFVSlhyMTRsSXFLNHVEaXFXclVxaFlhR0Nsci96NTA3eDlVN2VaYjUxekozN2x5YU9IR2lvRFlMQ2dxb2QrL2V0SERoUWtIdFBuandnR3JVcUVFK1BqNzA2ZE1uR2pKa0NIWHAwb1h5OHZMSXg4ZUg5UFgxQlgwR1NDUVNra2dreEtqY25EaHhnbng4Zkw3cHV6L3NDSUNPamc3M3Q1cWFtbUIyRFEwTkFRQldWbGJjLzBVaUVRREF5TWhJc0hUOC9mZmZhTnEwcWN5MXExZXZvbm56NXJ6WlhMdDJMZTdjdVlPRkN4ZktsSC9ObWpXeGI5OCttSnFheXMxV1lXRWhnb09ENGVUa0JFdExTMjdJTlNFaEFVZU9IQ24yTzdObnowYW5UcDNRc21WTFh2SWZHUm1KMDZkUG8yL2Z2bHc1T3pnNG9GdTNiaVdtaVMrTWpZMjVmNnRVcWFLUU5yaHQyemFFaDRkanhZb1ZndHBWVWxMQ2poMDdzSFhyVmh3K2ZGZ3d1L3I2K3REWDE4ZWVQWHZnNmVtSnhvMGJ3OFhGQlgzNjlNR2VQWHRRdFdwVjZPbnBDWmFlSlV1V1lOV3FWZXdWdUpKejhPQkI5TzNiOTl2YTBvK2E2VnExYW5GL201bVpDV2JYM3Q0ZUFPRGs1TVFKa2RxMWEwTmJXeHZWcTFjWEpBMDVPVGw0OGVJRjdPenN1R3R2Mzc1RlptWW1KMHo0NE1hTkd3Q0Fnb0tDSW1GYVdscmZOZ1JWQXE5ZnYwWktTZ3BxMUtqQlhUTXhNZUdHWHYvTHVYUG5jUDM2ZGZqNysvT1cvenQzN25BZDBPZWtwNmZEd01CQTBQcHZhMnNMVlZWVk9EbzZLcVQ5UFgzNkZCTW5Ub1MvdnorVWxaVVY4Z0l3ZCs1Y0RCMDZGQzlmdmhURVpzMmFOZkh3NFVQY3VuVUxyVnUzeHZyMTYzSHc0RUUwYWRJRWYvMzFGNTQ4ZWNMVlVRWkRDSEp6YzNINThtVjA2TkNoY2drQU16TXo3czNiM054YzBBZXZwcVltSndBQW9FR0RCbWpRb0lGZ2FZaUppVUdqUm8yNC9FdmYvcHMxYThhclhXa250M3o1OG1MRHg0MGJCMVZWVmJuWVVsRlJBUUJJSkJMdW12VFlpditPK0x4NTh3WVRKa3pBM3IxN2VlMk1wR0xrK3ZYck12Y2lLaW9LVTZkT0ZiVCtxNm1wd2M3T1RxWWVDc25jdVhNaGtValF2WHQzaFQwRCt2YnRDNGxFZ29VTEZ3cG1NeW9xQ212WHJrVm9hQ2pzN2UxaFlXR0JzTEF3N05xMUM1Y3ZYMlk5RWtOUXpwdzVnM2J0Mm4zektMaktqNXB4TlRVMTFLeFpFeEtKQkpxYW1vTFpWVkpTZ3FPam8weUgzNkJCQTZTbnAvTnFkOWFzV2RpMGFSTUE0Tk9uVDFCV1ZrYTFhdFc0OE0rdmpSNDlHa3VXTEpGN0dnWU5Hb1J0MjdiaDBLRkQwTkRRS1BJbUxNL095TWpJQ0hYcTFNR3JWNis0YTgrZVBRTUFOR3pZVUVZVURCMDZGRUZCUWJ3TFFlbVV5LzM3OTNINzltMjhlZk1HMDZkUHgrblRwK0hrNUZURUMxNVZWWlZYWVNpMDhKVHk0c1VMSER4NEVHM2J0b1dXbHBiQ25nRTZPanB3Y1hIQmpoMDdNRy9lUEc1YWhDL2k0dUxRdG0xYktDa3A0Y0NCQTRpUGowZFdWaGFHREJrQ2IyOXZiTm15QmJHeHNRb2JsV0ZVUGc0ZE9vU2hRNGQrK3cvOHlNNFBqUnMzSm1kblo4SHRCZ1lHVWs1T0R2Zi84K2ZQMDVFalJ3U3ozN05uVC9ydHQ5OWtyblh0MmxVUVo4amc0R0RPK1F3QXIva09EdzhuWldWbGlvbUpvZno4ZkhKMWRhVVdMVnBRWVdHaGpLUGc4T0hEQlN0N056YzNBa0RHeHNZMGQrNWN5c3JLNHNLV0xsM0tsVXUvZnYzbzNMbHp2S1pseDQ0ZGRQLytmY0hyLy9MbHl3a0FUWjQ4V2VIUGdERmp4aEFBUVp3d016TXphY3FVS1hUaHdnWHUrZE80Y1dNaUlycHc0UUxObkRtVE1qTXpCY3Y3Z2dVTGFQbnk1Y3dMcnBLU25aMU5GaFlXSlRwRmw0VWZXZ0QwNk5HRHVuWHJWdWx1dktXbEpUMS8vbHptbXJHeE1hV21wZ3BpLy9EaHcxU3RXalVDUU1yS3lqUjM3bHpldkpILytPTVA2dCsvUHcwYU5Jam16NTh2NC9GKysvWnRhdENnQVdWblozTmUwU3RXcktEZXZYdVR0N2MzM2J4NVU2NHJBSGJ0MmtXV2xwWmNKMS9jaWdzZEhSM3EyclZyaGE1L0hoNGVCSUMyYk5taThMU0VoSVFRQU9yZXZidmd0ZzBNREtoR2pSb0t5enNUQUpXYmd3Y1Awc2lSSTcvck4zNW9BVEIrL0hqeTgvT3JWRGM5UFQyZERBd01aSzY5ZlBtU3pNek1CRTNINjlldnFVbVRKbHhuMkxwMWEzcjc5cTJnNnJkQmd3WjArL1p0N3BxdnJ5ODVPVGxSYm00dVJVUkVrSWFHQmwyL2Z2MjdiYVdrcEZDN2R1Mm9lZlBtOU9USkUzSjFkU1VBWkdob1NPL2V2ZVBpSlNVbGtZNk9EcjE4K2JKQzEwRXpNek1DVUdRVVNsRVBRUUJrYTJzcnVPMklpQWo2L2ZmZmViZHo4dVJKMHRMU0t2SlJVMU1qTlRXMVlzTk9uanpKZXNnS1RzK2VQYm5ScUcvbGg5NEpzRmF0V29JNkFKWUhZbUppNE9MaUluUHR4bzBiYU55NHNhRHBNRFkyeGs4Ly9ZU0FnQURvNnVvaUtpb0tMVnUyRkd3enBQSGp4MlBvMEtGd2RuWUdBTnk5ZXhjN2R1ekFnQUVEb0s2dWp2YnQyOFBBd0FDelpzMzZManV2WHIxQzA2Wk5rWjZlam9pSUNOU3VYUnNyVjY2RVNDUkNhbW9xSms2Y3lNVU5DUW5CeXBVcjVib2Nzanp5OXUxYmJnNWUwVWo5ZjFKU1VnUzMzYjU5ZTNUczJKRjNPMTI2ZE1ISGp4K0xmUHo5L2JGbzBhSml3N3AwNmNJbXlDc3dIejkrNUZhamZBOHFQM0loZkw0VXNLSWpkUUxNeThzREVjazRBT2JtNWtJa0VuSFgrSElDTEE0dkx5OTRlM3VqZmZ2MmVQandJVmFzV0lINTgrZnphdlB3NGNOSVRrN0cxcTFidVd0Ly9QRUhBS0JPblRyY05XdHJhMFJGUlNFN08vdWJuZFdHREJtQzU4K2ZZK1BHamR4dk5HM2FGS05IajhiR2pSdXhlL2R1ZE9yVUNiVnExVUpTVWhKV3IxNWQ0ZXZpNXlzekZJMkdoZ2IzUUdSVWZQTHo4OUcyYmR0aXd5NWV2Q2pvbmpDSzVQang0L0R3OFBqdVZVOC90QUQ0NzV0d1JXYkpraVZZc21RSmV2YnNDUjhmSC9UbzBZTUw2OXk1TTZaTW1WSml3NUNuNnRUVzFpNXkzZGJXRmhzM2JrVFhybDE1MlE3NGM1NC9mNDU1OCtZaEtpcEtaaG1rOUEzdzh4VWhXbHBhS0Nnb3dOdTNiNzlKQU55OWV4Zm56NThIQUc2a1FjcUtGU3NRRlJXRmUvZnVZZFNvVWJDd3NFQkVSRVNscUlzR0JnWklTVWxCVGs2T3d0UHk2ZE1uQUVEVnFsVlo3MWdKS0N3c0xQRVpVMWhZV0duSzRkQ2hRNWd5WmNwMy84NFBQUVZnYlcwTmEydnJTdFVBcmwrL1htUzlmMHhNakNCVEFMLzg4c3NYeFpoMC9UNGZGQlFVd01mSEIydldyQ215OFk2dXJpNEFRQ3dXYzlmeTh2SUEvTHVCeTdjUUZ4ZkgvZjM0OGVNaWI1NkhEaDJDbHBZV1BuejRnS3lzTEJuYlV1N2R1MWZoNnFCMGlpTWpJMFBoYWNuS3lnSUExSzVkbS9XT2xZQXFWYXJnLzMzWGlud1V0U09tMEh6NDhBRjM3OTVGaXhZdEtxOEFJQ0tzVzdjT0d6ZHVyRFNWLzhXTEYxQlZWWlZaNzV5WW1JZ2FOV29JOGdhVW1wcUt5TWpJWXNPdVhic0c0TjhwQWI0SUNncENzMmJOaXQzMXFsV3JWZ0NBcEtRa21iS1JidHowTFVpM0lBYUFnSUFBNU9ibXlvUS9mZm9VQmdZR1VGVlZSV0ppSXR6YzNHVEs1K2pSbzdoMDZWS0ZxNGZTclpZVEV4TVZucGJuejU4RGdPQStNSldkbHk5Zll1ellzVmk3ZG0ybGV2UCtuRFZyMWlqa0lMQmp4NDZoVzdkdVJmWmgrZGFPOUlmazBxVkxuQWU2UER5OWZ3UU9IVHBFZmZ2MmxibDI0TUFCOHZYMUZjUit1M2J0eU16TWpNNmVQVXRFeEIwR2RQZnVYVEl6TTZOQmd3WlJRVUVCTDdham82T3BhZE9tbEorZlgrSXl2Zi85NzMvVXBrMGJLaXdzcEppWW1CS1g2bjBObnA2ZVhEMnp0N2VuZ0lBQVdyNThPYlZ2MzU3cTE2OVBEeDgrcEQvKytJTjBkSFM0ZUdabVpsU25UaDJ5dGJVVmRGMjRVRWdQSXVyZnY3L0Mweko0OEdBQ1FHZk9uS2wwWHVCTGxpeWhWYXRXS2NUMm9FR0R1UG9lRWhKUzZjcit6ei8vNVBKLzVjb1ZRVzEzNnRTSk80enNlL2xoQmNDYk4yL0kxdGFXNnRXcko3TVVxeUl6WmNxVUlnMSs4dVRKdEhuelprSHMzNzU5bXlaTm1rU05HalVpUjBkSE1qVTFwV2JObXBHSGh3ZXZTOExldlh0SDl2YjJGQjhmWDJxOGpJd01Hamh3SUxtN3U1T3pzek90V2JQbXUyMkx4V0phdDI0ZE9UczdrN2EyTnVucTZsS0xGaTFvMDZaTk1odHdKQ1ltMHNDQkE2bDY5ZXFrcDZkSFhsNWVSZlpxcUNpSXhXS3l0clltS3lzcmhhZkYxdGFXek0zTnYyc3pGTWJYczJIREJ0TFcxaVpuWjJmcTBLRkRwY3QvV2xvYTJkblpVZDI2ZFNrdExVMHd1K25wNlZTblRoMlp6ZEMrQnhIUi8yK3d6bUI4Slg1K2ZoZzFhcFFnNThBenloZGhZV0VZT0hBZzd0Mjd4eDJRSlRRSkNRbXd0YlhGMXExYk1YejRjSFpURkVCMGREUTJiOTZNZmZ2MnNjTDRBVkZpUmNENFZqdzhQTDdad1k3eFk5Ty9mMyswYjk4ZTY5YXRVMWdhMXExYmgxYXRXc0hYMTVmZEVBV3haOCtlVXAyREdlVWJOZ0xBWURDK2lYZnYzc0hWMVJXN2R1M2lEa29TaWdjUEhxQmJ0MjZJakl3VTlEaHd4ci9rNU9RZ09EZ1lKaVltVEFBd0FjQmdNQ29qU1VsSkdEbHlKTmF1WFF0YlcxdEJiTDUrL1JxK3ZyNkMybVRJRWg0ZURoY1hGMWhaV2JIQ1lBS0F3V0JVVnJLenM3RjI3VnAwNk5DQjkrVjROMi9leElrVEp6Qmx5aFJ1N3djR2c4RUVBSVBCVUNDRmhZWHlXWnVzWUJzTUJoTUFEQWFEd1dBd0tpeE1Tak1ZREFhRHdRUUFnOEZnTUJnTUpnQVlEQWFEd1dBd0FjQmdNQmdNQm9NSkFBYUR3V0F3R0V3QU1CZ01Cb1BCWUFLQXdXQXdHQXdHRXdBTUJvUEJZRENZQUdBd0dBd0dnL0dqQ1lEMzc5OWozTGh4YU5pd0lSbzFhb1FCQXdiZzFhdFhnaVk4TnpjWDY5ZXZoN201T1RJeU1nU3ptNU9UZ3hrelpzRFMwaEpxYW1vd056ZkgrUEhqOGU3ZE8wSHNTeVFTaElTRW9GNjlldERRMElDRmhRWG16SmtEc1Zpc3NFbzBiTmd3aUVRaTVPYm1DbVp6NXN5WkVJbEVSVDcvL1BPUG9IbFBUazdHM0xsejBhbFRKNHdkT3hhN2R1M2kxVjdUcGsyTHpiZjBZMkZod1h1ZWQrL2VqWll0VzZKRGh3NXdkM2RIeTVZdHNYdjNic0hLL09USmsyalRwZzJhTldzR1MwdExlSGw1NGRHalIreHB6cWdVbkRoeEFyNit2dkQxOVlXOXZUMGNIUjBSSEJ3TWlVVHk5VDlHWDBscWFpbzVPanFTdDdjM2ljVmlJaUthTTJjT21aaVkwTk9uVDRsdmNuTnphZlhxMVZTblRoMENRQURvL2Z2M0pBUUZCUVhVcWxVclVsWldKbXRyYTZwUm93YVhoanAxNmxCeWNqS3Y5Z3NMQzhuYjI1dnExYXRIUGo0KzVPcnF5dG4zOWZVbFJYRHc0RUV1RFo4K2ZSTEVabnA2T2xXdFdwV1VsWlZsUGgwN2RoUTA3OHVXTFNNZEhSMWF2SGd4NWVYbDhXN3YxcTFiQklDVWxaV3BldlhxWkdob0tQTVJpVVEwYnR3NFh0TXdiZG8wTWpFeG9VZVBIbkhYN3QrL1QzcDZlalJ6NWt6ZXkyRDU4dVZrWW1KQ2QrL2VKU0tpRHg4K1VJY09IYWhxMWFwMDdkbzFZakFxTW9HQmdlVHQ3VTBGQlFWRVJDUVdpMm5reUpFRWdBWU1HUERWdi9mVkFxQmJ0MjZrbzZOREdSa1ozTFc4dkR3eU5EUWtOemMzS2l3czVMVUF4R0l4dlh2M2psSlRVMGxWVlZWUUFiQm16UnBxMzc0OUpTWW1jdGNPSERoQW1wcWFCSUM4dmIxNXRiOS8vMzRLRGc2V3VSWWFHc3Axd0h3TGtQK1NtSmhJZGVyVW9hcFZxd29xQU9iTW1VTkxseTVWV0NPVVNDVFVwMDhmVWxOVG96LysrRU13dTZOR2phSWxTNVpRZG5aMnNmY0NBUDM1NTUrODJZK1BqeWVSU0VTclY2OHVFalpqeGd3U2lVU1VsSlRFbS8yLy92cUxsSlNVYVB2MjdUTFgwOUxTU0ZOVGt5d3NMSW90RzRhd2JTTThQSnhpWTJNclRKNXUzNzVOUjQ0YzRUcGRSWkdSa1VHcXFxcTBiTmt5bWVzNU9UbWtwNmRIQU9qdnYvL21Ud0JFUlVVUkFQTHk4aW9TNXV2clN3RG8rUEhqZ2hXSW1abVpvQUpnMEtCQmxKT1RVK1Q2cWxXckNBQnBhV254YXIra20ydHJhMHNBNk1HREI0S1Z2VmdzSmxkWFZ6cDU4aVNabXBvS0pnRGV2WHRIVmxaV2xKV1ZwYkNHS0szci8rMkkrQzd2alJzM2xoZ2VIQnhNWm1abXZBcncvZnYzRTRCaTA3RnUzVG9Dd090YnVLZW5Kd0dneDQ4ZkZ3bno4ZkVoQUxSMjdWcldDeXVBOVBSMFdycDBLVmxhV2xMMzd0M3AyYk5uRlNadkNRa0o5TC8vL1krc3JLd29KQ1JFNXVWWFNKNCtmVW9BcUhidDJrWGF1WFEwT0RRMDlLdCs4NnQ4QUE0ZVBBZ0FjSEZ4S1hadUVnRHZjNkNmbzZhbUp1amNpNStmSHpRME5JcGM3OWV2SHdCQUxCYURlRHhjOGFlZmZpcjJlczJhTmVIZzRJQzZkZXNLVmhiejVzMURreVpOMEtWTEYwSHZ3ZXJWcTVHU2tvSWVQWHBnMmJKbFNFNU9GdFQrN3QyN3NXUEhEclJ0MnhhK3ZyNkMyVlZSVWNIbzBhTkxERDkwNkJENjlPa0RrVWpFV3hwTVRVMEJBSnMzYjBaK2ZyNU1XR3hzTEl5TmpkR2dRUVBlN0YrOGVCRUFZR2hvV0NTc2RldldBSURqeDQrelNXSUJpWXVMdzhpUkkxRy9mbjI4ZWZNR0Z5OWV4TEZqeHdUeFJSRUthMnRyUkVaRzR1alJvNGlMaTRPMXRUWEdqUnVIK1BoNFFkTmhhV21KenAwN1EwVkZCWVdGaFVYODhqNXZvN3o0QU5TdVhac0EwTDU5KzRxRVJVUkVFQUF5TkRRVVRCRkovUUNFR2dFb2JkaExKQkpSdzRZTkZUSXNWTE5tVFlxSmlSSE1abVJrSkRWdTNKaWI5eFpxQkNBakk0T3FWYXZHVFhrQW9DcFZxdEQ4K2ZNRkdaNzcrUEVqR1JzYkV3QTZmLzU4dVhsRGVmTGtDUUdnNjlldjgycW5zTENRSEIwZENRQjE2OWFORzI2L2ZmczJWYXRXalg3Ly9YZmViT2ZtNW5MMy9NV0xGMFhDejU0OVN3REkyTmhZc0JHWlZxMWFrWm1abVl3L2hGQjgrUENCbkp5Y3FIYnQydlR5NVV0QmJSY1VGTkN4WThlb2JkdTJaR2RuUnhzMmJLQ1BIei95WnUva3laT2twYVgxVloralI0L3lscDQzYjk1UVVGQVFtWmlZa0llSEI1MDdkMDZoN1Q4NU9abFVWRlRJd3NLQ2NuTnorWmtDS0N3c0pHVmxaUUpBbHk1ZEtuWjRXdHBBTXpNeks1VUFpSXVMSXdDMGF0VXFRZTFtWldWUmx5NWRhTnUyYllMWlRFdExvN3AxNjFKOGZEeDNUU2dCa0ptWlNWZXVYS0hqeDQvVGpCa3p5TkxTa3F0enZYcjE0bDBFN05temgrdGtvcU9qeWR2Ym0yeHNiTWphMnBwR2pScEZxYW1wQ3FsL2l4Y3ZKa3RMUzBGc3hjZkhjeUxJMmRtWnpwdzVReTFidHFRYk4yN3dibHRMUzRzQUZQdHdQMzM2TkFFZ2JXMXR3UjY2SXBHSUFOQ3VYYnNFditleHNiRmMzVDk5K3JSZ0x4c2hJU0ZVcDA0ZDZ0U3BFLzN4eHgrOCszeVZaL0x5OG1qMzd0M2s0dUpDOXZiMnRIbnpab1g0b0V5Yk5vMlVsWlcvNmFXa3pBSWdMUzJOcTNERk5mWjc5KzV4NFh3NkFwVkhBVEJuemh5eXNMQW8xaitBRDE2OGVFRUxGeTdrZkNDVWxaVnA5dXpaZ3RqdTFxMGI3ZDY5VythYWtENEEvMzByREFvSzRoN0VLMWV1NU5WZWp4NDlPQUVRRkJSRXNiR3hkUHYyYlc1dTJ0TFNVaUVpd05uWm1XYk1tQ0dZdmNURVJISndjT0RhdTFEQ3QzdjM3Z1NBZnY3NTV5SmhVbWZZV3JWcUNWWU9lL2Jzb2FDZ0lFRldnQlJIYUdnb2hZU0U4QzU4azVPVGFjeVlNV1JzYkV4K2ZuNHk0cC94TDVjdlg2YmV2WHRUelpvMWFjYU1HWlNXbGlhSTNaU1VGTkxVMUN6VlAwZ3VBdURseTVkY2c3OXo1MDZwaWxTb2gyQjVFQUNwcWFta3I2OVBFUkVSZ25aOGlZbUp0SGZ2WG5KeGNlSEtmY3VXTGJ6YVhidDJMUTBhTktqSWRVVUpBQ2tyVjY0a0FHUm1ac2FybmJwMTZ4SUEyckJoZzh6MS9QeDhzcmUzSndBMGVQQmdRZk1lSHg5UEFPaldyVnVDMmJ4Ky9UcjE3dDJiQWdNRFNVbEppUURRNk5HamVlK0k3dHk1dzYyNG1USmxDbjM0OElFeU16UHB3SUVEM0xPZ2MrZk9yRGVTTTgrZVBTTlBUMDh5TWpLaWdJQUFTa2xKWVlYeUg3S3lzbWpkdW5Wa2JtNU9QLy84c3lCTDRvbUlKazJhUk5PbVRmdm03NWRaQUh6OCtMSFVFWUNyVjY4U0FCS0pSQ1NSU0NxTkFPalZxeGN0WExoUVlmWWxFZ2tOR2pTSUFKQzl2VDF2ZG1Kalk4bkp5YWxZNzN0RkM0REN3a0pxMkxBaEFhRFhyMS96WmtkWFY3ZkVJZWoxNjljVEFLcGF0YXFndzZJTEZpd2dXMXRid2V4RlJFU1FpWWtKdCtUMHQ5OStveXBWcW5BaWdHK3VYYnZHaVY0bEpTV3FWNjhlclZ1M2pxeXNyQWdBYmRxMGlmVkdQUEgwNlZPYVBIa3kxYXhaazN4OGZBVHpPenAxNmhUcDZ1cCsxVWVvMVdpUEh6K21pUk1ua3FtcEtZMFpNNFllUG53bzZJdWdoNGZIZC9XM1grVUVLSDNRRitmc2MrclVLY0dINEJRdEFGYXNXRUVqUm94UWVNTk1TMHNqTlRVMVVsVlY1YzJHZE9sYldUN1NUVnFFSkRBd2tBRHc2aEFsbmZzdXJ2N2Z2MytmeS8rSER4OEV5N2Vqb3lQNSsvc0xZdXZkdTNla3A2ZEgwNmRQbDduKysrKy9jM3R5Q0xVWlQzcDZPamZNZXVQR0RRSkFlbnA2Z3BaOVpYL2J0YlcxcFpZdFcxSjRlTGhnTDMzbGhmUG56MVBYcmwzSjJ0cGFZVXNEcjE2OVNvY09IZnF1MzFENW1oVURyVnExd3Y3OSsvSGt5Wk1pWWMrZVBRTUF1THU3VjRybEw0Y1BIOGJObXpjUkZoYW04TFJVcjE0ZExpNHV2RzZIMnJoeFkyUm5aNWU0TmVXblQ1L2c1ZVVGSlNVbFZLdFdUZkF5TURFeFFmWHExV0ZrWk1TYkRUczdPeVFuSitQTm16ZEZ3c3pNekFBQTZ1cnEwTmJXRmlUUGp4NDl3dDI3ZDdGLy8zNUI3TzNmdngvdjM3K0hxNnVyelBXT0hUc2lNREFRczJmUHhva1RKN2dsd1h5aXI2L1AvZTN2N3c4QVdMaHdJYXBXcmNyVzV2R010clkyL1B6OE1IYnNXSnc1Y3dacjFxekIxS2xUNGVmbmgySERoaW1rL1F0QlRrNE85dTdkaTdWcjE4TFEwQkRqeDQ5SDE2NWRvYVNrbUNOMW5qNTkrdjF0N1d2VWd0VFR0cmg1NE9IRGh4TUFPblhxVklVZkFUaDE2aFQxN05tVDh2UHppeDJTVndUMTY5ZW5mdjM2S2NTMm9xY0FpSWgrK2VVWG1qSmxDcTgyMXE1ZFN3Qm8xS2hSUmNKZXZIaFJvb01hbjZNZURnNE9ndG56OS9jdmNRb2tPVG1aQUpDZm41K2c5MTI2RlhYdjNyMHJ0VWU2b3JsMzd4Nk5IRG1TREF3TWFPellzUXBiRWNNSGI5KytwZW5UcDVPcHFTbU5HREdDNHVMaXlrVzY1RkhmdjNvcllGZFhWNnBldmJyTXd6NHZMNDhNREF5b2FkT21nalpDNmI0RVFncUFreWRQVXRldVhZdGRiL25xMVN2eThmSGh6WForZm42eEF1UGF0V3VrcmExTjkrN2RxOUFDNE9uVHAzVGh3b1ZpOCsvZzRNQjdQY2pKeVNGemMzUFMwOU1yNGd0eDZOQWhFb2xFeFM2UjVRdDdlM3NLQ2dvU3pGNWtaQ1FCb0tsVHB4WUplL2p3SVFHZ0V5ZE9DSmFlNjlldms2YW1Kbmw2ZWlwRWZHN2Z2cDNtejUrdmtGVUE3OSsvcDhtVEoxTlFVTkJYci8zbWUycG02ZEtsOU5kZmYxVVlBZkRubjMvUzBxVkxLVDA5dmR5a0tUOC9ueFl2WHZ6ZFM4Qy9XZ0E4ZWZLRURBME51WU0vQ2dvS3lNL1BqMHhNVE9qSmt5ZUNGb0wwTUo3bno1OExZaThzTEl4VVZWWEp4Y1dGM056Y3VJK3JxeXM1T1RtUmlvb0tyMHVpek0zTlNWZFhsMmJQbmswSkNRbjA3dDA3T25Ub0VOblkyTkRaczJjVlZobUZFZ0RTN1M1YnRteEpodzhmcHVqb2FKby9mejQxYTlaTTVud0dQb21KaVNFZEhSMGFNR0FBSjhaZXZueEpOalkydEdqUklrSGZ1QUFJdmduTmlCRWpxRXFWS2hRZEhjMWR5ODdPcHE1ZHUzN1RZU1RmeXErLy9rbzFhdFNnUllzV0tXU1A5bWZQbm5FK0gzdjM3aFhjZmtCQUFHZWY3d09nR09XUDhQQnc3djUvenpNQTMvS2x4TVJFNnQyN043bTZ1cEtibTV2Z1F6NGJObXlnM3IxN2N3WGc2dXBLUzVjdTViVURPbkxrQ0xmZXZLU1Bpb29LcitVUUdCaElwcWFtcEtxcVNsV3JWaVZuWjJlYU9YT213cGZsQ0NVQW9xT2p5Y1hGaFRRME5FaFBUNDlhdDI1Tm9hR2h4VTdGOE1uZHUzZXBjK2ZPNU96c1RGNWVYdFNsU3hkQno4Q1FkZ0RPenM2QzMrdkN3a0xhc21VTE5XblNoRHAyN0VnREJneWdMbDI2ME9iTm0za2YvZHUzYng5Tm5UcVZ1blhyUnRPbVRWUG9mdk81dWJuVXRHbFRNak16bzRTRUJNSHRIejkrbkhSMGRNakZ4WVZzYkd4WWoxakplUHIwS1ptYm0xUGp4bzIvYS9NaEVSR1BtOWN6R0F3R2d6ZVNrcExRcjE4L1hMMTZsUlVHNDZ0UllrWEFZREFZUHlaNzl1ekJxRkdqV0VFd3Zna1ZWZ1FNQm9QeFl5R1JTTEJ4NDBhSXhXTDQrUGl3QW1GOEUyd0tnTUZnTUg0dy92ampENWlhbXNMUjBaRVZCb01KQUFhRHdXQXdHR1dIK1FBd0dBd0dnOEVFQUlQQllEQVlEQ1lBR0F3R2c4RmdNQUhBWURBWURBYURDUUFHZzhGZ01CaE1BREFZREFhRHdXQUNnTUZnTUJnTUJoTUFEQWFEd1dBd21BQmdNQmdNQm9QQkJBQ0R3V0F3R0F3aCtlckRnTVJpTVU2ZVBJa3paODVBTEJaRFhWMGRSSVNjbkJ5b3FLamdwNTkrd3VEQmc2R2pvOE5LbDhGZ01CaU04Z3A5QmJ0Mzd5WTNOemZhc0dFRFpXUmtGQWt2S0NpZzMzLy9uVHc5UGVtUFAvNGd2aGs3ZGl4ZHZIaVJWeHNYTGx5Z21UTm5rcTZ1TGdFZ0FLU2hvVUcydHJiazR1SkNscGFXWkd0clN3TUdES0N6WjgrU0VFUkZSZEhnd1lPcFRwMDZaR3hzVEEwYk5xVG16WnZUZ2dVTDZQbno1M1RseWhWYXVIRGhkOXQ1OU9nUkxWeTRrT3JWcThmbEhRQ3BxYW1Sc2JFeDZldnJrNldsSmJWcDA0Wm16WnBGLy96ekR5LzVQWHo0TUUyWU1JRTBORFFJQUttcnE1T0ZoWVhNeDlUVWxOVFYxUWtBK2Z2N3k5WCtnd2NQYU1HQ0JXUmxaY1dWZ1ltSmlZeDlmWDE5TG16QmdnVzgzZnUzYjk5U1NFZ0l0V2pSZ2h3Y0hNakp5WW1hTkdsQ2JkcTBvVldyVmxGU1VoS05HVE9HOHZMeTVIYi82OWF0eStYTjJOaVlac3lZUVRkdTNPRGlIVHQyakNaTW1FQnFhbXBjdlAvOTczKzBmUGx5eXM3T2xtdis3OXk1UTRHQmdXUnBhY25aTWpjM3Avbno1OU9kTzNjRWFYL1MrbEM3ZG0yWitqQnYzanlLaVltUm14MXArZGVwVTBlbS9PZk5tOGUxdFl5TURGcTRjQ0ZwYTJzVEFCS0pSTlNsU3hjNmNPQ0EzTkp4OE9CQkdqTm1ES21xcW5McGNIRnhvWUNBQUxwOSs3YmN5L2ZodzRjMGMrWk1Nakl5NHV4dDM3Njl6TjhmT0d1Mjlrd0FBQ0FBU1VSQlZIQ2dURDBNRGc3KzZucVltNXRMaXhZdElqYzNOKzYzK3ZmdlgyTDhaOCtlMGFKRmk4akp5WWtBa0pPVEV5MWF0SWhldkhnaDE3S0ppWW1oWDM3NWhlenQ3Y25XMXBZc0xDekkzdDZlSms2Y1NFK2VQUG5xM3l1VEFNak96cVllUFhyUXNHSER5bFNRRW9tRVpzeVlRYUdob2J3MXdveU1ETkxXMXFZZVBYb0kwdWhYcjE1TkFFaExTNnRJMk9YTGw4blIwWkVBa0krUEQ0bkZZbDdTa0ptWlNYMzY5Q0ZsWldXYVBuMDZKU1VsY1dFNU9UbTBhOWN1TWpVMUpXVmxaWm8wYVpKY0g3clNSaEFlSGs0U2lZUUxpNDJOcGZIangzTVBCeDhmSC9yNDhTTXYrUjg5ZWpRQklEYzN0eEliN2VEQmcybml4SW04MlAvNzc3KzVjbmp3NEVHeEQreUdEUnZTekpremViRi82TkFoMHRIUm9SWXRXbEIwZERRVkZoWnlZYW1wcVRSbnpoeFNVVkVoQUhKOThNVEd4bkw1UG5IaVJJbnhwazJiUmdDb1JvMGFsSitmejdzSWxxWXBNaktTRk1FLy8vekRwZUgwNmRPODJZbUppZUhzbkR4NXN0ZzRqbzZPWkdob1NGRlJVYnlsdzlmWGx3Q1FvYUdoWEFUbWx6aDc5aXlYNzNyMTZzblU5NUo0K2ZJbDl5elMxdGFXU3oyY1AzOCtsNDdnNE9BdmloY0FsSmlZS05leXlNN09KbDlmWDFKVFU2TWxTNWJRdTNmdnVMQ0VoQVR5OXZibXd1UXFBSEp6YzZsRml4YmY5RlkxWk1nUXVuZnZIaStWSXlRa2hBQ1Fzckl5UFgvK25QZktlT3pZc1JJRkFCRlJlbm82cDFoRFFrSjRFVHoxNnRVakpTVWxPbmJzV0lueGtwS1N5TXpNakFZUEhpeFgyOUlHOFBtYjMrZjgrZWVmcEtlbng2bHVQanFBd01EQVVnV0E5QTE1eElnUnZOU0JseTlmbGlvQXBHSnB3b1FKY3JlOVlNRUM3aTJrb0tDZ1ZKRUFnRzdkdWlVMzIybHBhVnkrUzN2RGxiWkpSMGRIM3R2ajQ4ZVB1VFI5eTV1UFBFaEpTZUhTRUJzYnF6QTd5NVl0STB0TFMzcjY5Q212K1pWMmhFMmJOaFdrZkpPU2traE5UWTBiV1RwKy9QZ1h2ek4xNmxSdU5LUk9uVHB5UzR0MEJGaEpTWWwrLy8zM1VqdHFBREl2U2Q5TGJtNHV0VzdkbWdEUW9VT0hTb3puNStkSEFHajgrUEZsL3Uwdk9nR09HVE1HcHFhbUNBb0srdXJwaGRXclY4UGYzMS91MHhhRmhZVll2MzQ5dExXMVVWQlFnRTJiTnZFK1ZhS3NyRnhxdUw2K1B2cjI3UXNBMkwxN3Q5enREeDgrSEE4ZVBNRHc0Y1BSdlh2M0V1UFZxbFVMVzdac3dmdjM3d1hMT3dDNHVia2hMQ3dNQUhEcDBpVXNYYnBVN21XZ3BQUmxuOVVhTldxZ2E5ZXVDcWtEQU9EbzZGanEvZmtXSWlJaUVCQVFBQ3NySyt6Y3ViUFVjdkR5OHNLZ1FZUHc1czBiWHZKZG1tMXBXRm51azFCcHFnaHBLTTNPcjcvK2lnMGJOaUF5TWhKV1ZsYUM1RmRGUlVXUThsVlZWWVdHaGdZR0RCZ0FBRmkyYkZtcDhiT3lzckJ0MnpZTUd6YU1sM1RXcTFjUGhZV0Y2TisvUHhJU0VrcHRBMlY1VnBTVkNSTW1JQ29xQ2oxNjlJQ1hsMWVKOFlLRGcyRm9hSWkxYTlkaTc5NjlaWHVtbGhZWUdSbUpZOGVPWWVQR2pkK1VjRjFkWGRTb1VRUFBuajJUNjQwNGZ2dzRORFEwRUJnWUNBRFl0bTBiY25OekZlNVBJYjNwcWFtcGN2M2QzMy8vSGVIaDRRQ0FhZE9tZlRHK2g0Y0h6TTNOQmM5L3AwNmQwTEZqUndEQWloVXJrSldWcFpEN3dKY0FLQ3R0MnJTUjIyL2w1T1JnOE9EQklDSk1uejRkNnVycVgvek85T25USVpGSW1JTlRCV2ZuenAzdzkvZkgrZlBuWVdscFdXSHpPWFhxVkloRUlseTVjZ1ZYcjE0dE1WNW9hQ2hhdFdvRk96czdYdEt4Zi85K21KdWJJeU1qQTkyN2R4ZmsrUllYRjRldFc3Y0NBRWFQSGwxcVhFMU5UUXdjT0JBQU1HdldMT1RsNVgyZkFBZ0lDTUQwNmRPaHI2OWY3RnY0MXExYjBiZHZYMHlhTkFtQmdZRTRkZW9VV3JSb2dXUEhqc2wwUnVmUG41ZHJvYXhac3dianhvMkRyNjh2TkRVMWtaYVdoZ01IRGlpMGt1Yms1T0RJa1NNQWdDWk5tc2oxdDBORFF3RUFOalkyc0xhMkx0TjM1czJicDVCeUdEUm9FQUFnTXpNVHAwK2ZGdFQyL3YzNzhjOC8veWdrMzJLeEdMTm16Wkw3NzRhRmhTRTVPUmtBMEt0WHJ6Sjl4OEhCQVowN2QyWTlaQVZtM2JwMThQZjN4NFVMRjhyOFRQaFJjWEJ3NEY0c1Nob0ZrRWdrV0x0MkxhWk9uY3BiT2d3TkRYSDgrSEZvYVduaHdZTUhHRGh3SUlpSTE3eUhoWVdoc0xBUUtpb3FhTkdpeFJmanQyN2RHZ0R3OHVWTFJFWkdmcnNBdUgvL1BtN2N1SUdSSTBjV0Njdkx5ME92WHIwUUhSMk52WHYzWXRXcVZYQndjTUNFQ1JOdzllcFZORy9lbkl0cllXRlI0bkRKdHhBYkc0dlkyRmo0K1BpZ1dyVnE4UGIyNWhxRVVCUVVGTWo4ZmYzNmRYVHExQW5QbmoyRHZyNCtGaTllTEZkNzBodnA0T0JRNXUvVXFGRkRJWTIxV2JObTNOODNidHdRek83YnQyK3hZY01HaFltL3hZc1g0OU9uVDNMLzdaTW5Ud0lBVEUxTllXQmd3SG8rQmhZc1dJQ2xTNWZpNHNXTHNMVzFyUlI1bG81OG5qaHhBbzhlUFNvU2Z2RGdRUmdiRzZObHk1YThwc1BaMlJsNzl1eUJTQ1RDaVJNbkVCQVF3S3U5eTVjdkF3RE16YzJob2FIeHhmajI5dlpGdmxzYUpVNlNIRDkrSEczYXRJR2VubDZSenE5ejU4NTQvLzQ5cmw2OUNsVlZWUUNBcmEwdG5qNTlpcDkrK2dtR2hvWmNmQzB0TGJrT3o2OVpzd2JEaGcyRGxwWVdBTURQenc5YnQyN0ZyVnUzOE5kZmY4bUlEejdJenM2R2taRVJEQTBOa1oyZGpaY3ZYM0xEclYyNmRNR3FWYXZrcXNqVDB0THc0Y01IaFhicVg2dVNwYVNrcFBCaTQ5YXRXekxEZk5uWjJYajE2aFh2YXZ4ekdqUm9BSkZJQkFESXo4OEhFV0hDaEFseXQvUGd3UU1BUVBYcTFVdU50MkhEQmx5NWNnWHYzcjJUU2VPNGNlTmdabVltdC9UMDZOR2p4R2tJZWZxZE1JcG54b3daT0hQbUROemMzT1I2WDhzN2JkcTBnWXVMQzJKaVlyQjgrWEpzMjdaTkpqd2tKQVJ6NXN3UkpDMDlldlRBZ2dVTE1IZnVYQ3hhdEFqT3pzNWxIcDM3V3FTamY5V3FWU3RUL00valNiLzdUU01BTjIvZUxGWk5CUWNINCtMRmk5aXhZNGZNZzBBNnovL2ZvY2ZYcjEvRDJOaFlibTk1Qnc4ZWhKK2ZIM2ZOeWNtSlM2Y1Fvd0JhV2xwNCsvWXQ0dUxpa0ppWWlIZnYzaUU4UEJ6MTY5Zkh1WFBuTUhQbVRDUWxKY25OWG41K1B2ZDNXUlNnb3ZuY1NVbE5UWTBYRzQwYU5jTERodys1ejRzWEwvRGt5UlBVcjE5ZnNIekd4c1lpTnpjWHVibTV5TW5Kd2R5NWMzbXhJNzMvbVptWnBjWWJPM1lzbGk5ZmpxaW9LSnc5ZXhZYUdob0lEZzZXZXlkeDlPaFJtYkwvL01QSEZBaWpxUEJVVmxiR2xTdFgwS1ZMRitUazVGU2F2RXVIOS9mdTNTdlR1VjI0Y0FHWm1abm8wYU9IWUdtWk0yY08rdmZ2RHlMQzRNR0RjZmZ1WFY3dGZUN3FYQnFmUDNQTDRvaFlvZ0I0L3Z3NTZ0V3JKM1B0eVpNbkNBd01oS2VuSnhvMGFDQVRkdkhpeFdJRlFIeDh2TndjVkRadjNneDNkL2NpdnpkMjdGZ0FRSGg0T0c5dm5TV2hvNk9EWHIxNjRlYk5tM0IyZHNadnYvMkdaczJheWMwTFcxOWZuK3RVMzc1OVcrNGI2ZWY1TmpFeEVjeXVsWlVWUm8wYXBaQThWNmxTQllHQmdienNmaWtkVVhuOStqVUtDd3RMald0cWFzbzVmelpzMkpEMWxoV1FBUU1HWU0rZVBWQldWa1prWkNTNmR1M0t5OVJUZWNUTHl3dVdscGJJeTh2RG1qVnJ1T3NyVnF6QTVNbVRCVjhOc21QSERqUnAwZ1RaMmRubzNyMDcwdFBUNVc3RHlNZ0lRTmxIMXo1M1REUTFOZjEyQWZEeDQ4Y2l3dzRyVjY1RWZuNCtKazJhVkVTZEhEdDJEQVlHQm5CeGNaRUpPM1BtRERwMDZQRGRCU0VXaTdGcDB5YkV4TVRBenM1TzV1UHY3dzhWRlJXSXhXSnMyYkpGSVpWVFhWMmRtL3RQVGs3Ryt2WHI1ZGE1U045czc5Ky9YKzRiNmQ5Ly84Mzk3ZWJtSnFodGQzZDNyc0VvWXVSRHVseEpua2hIdC9MejgvSG5uMzkrTWI1MFNvNnYwUmRHOGNoejJkZVg2TisvUC9idDJ3Y1ZGUlZjdkhnUjNicDFxeFFpUUZsWm1ldDdObS9lakt5c0xOeTdkdzh4TVRFWU9uU29Rb1Qvc1dQSFlHcHFpc1RFUlBUdDI3Zk1iK3BsUmZvTWZmSGl4UmRIQWFVdjZWS2tEb0hmSkFBME5UVmxsaElSRVE0ZE9nUmpZK01pM29oaFlXRjQvdnc1ZnY3NVoyNWVGUGgzL2xvaWtYeHgvcklzSERwMENEVnIxa1JTVWxLUm9jZjQrSGpNbURFREFMQmx5eGFJeFdLRlZORFB2Zi9sMlZuMzY5Y1BBSERuemgwa0ppYVc2VHZaMmRtQ3pvbC9YaGVrYi8vdDI3Y1gxTGFOalkzQ0JBQ0FJaU5tOG1EWXNHRmNtNUtXTGFQOG9hdXJLNmk5UG4zNmNDTGcvUG56Nk42OWU3bFlDaTNsNGNPSHZQenVzR0hEb0srdmp3OGZQbURMbGkxWXNXSUZ4b3dabzdEcFVXTmpZNXc0Y1FLYW1wcTRjT0VDcGt5Wkl2Y1JIMm4vV3hhdmZ1a3l5VHAxNnBUSkliSkVBV0JoWVNFem5KNlltSWkwdERRWjV5ZmczK1VHMHZsUGQzZDNtZDlZdkhneE56ei92YXhaczZiVXdoMDdkaXhVVlZXUm5KeU0zMzc3VFNHVjRmTWhlZ3NMQzduOXJuUXpKZ0NZUFh0Mm1VWkxac3lZSWVNL0lBU1hMMS9HaVJNbkFBQUxGeTVVMkZ0b1hsNGVwaytmWGlFNkZudDdlNHdaTXdiQXYwT09zYkd4ckxjdForam82TWc0dndxRmw1Y1hEaHc0QUJVVkZVUkVSTURUMDdOY2lJRDgvUHd5YjBUenRXaHBhWEZUZlNFaElUaDY5S2pjK3BodnBWR2pSdmoxMTE4aEVvbmtQZ0x0N096TXZRQithY003aVVTQ25UdDNBZ0NXTDE5ZXBvMlFTaFFBUC8zMEUyN2R1aVh6VUFXQWpJd003bHBLU2dxQ2dvTFF0bTFiQUlDcnF5c1hkdTdjT2J4Ky9acGJ2L2s5UkVkSEl5a3BpU3VJa3BTWXA2Y25BR0RWcWxWeXY4bGxHVlVJQ1FuNXQxQ1ZsTGpkcU9UMWRuSGd3QUZvYW1yaXdJRURDQW9LS3ZIdFBpOHZEeU5IanNTSUVTUEt0R21NdlBJZUZ4ZUh2bjM3b3JDd0VDTkdqT0JsU0U0NnZQYWxrWTM1OCtmek1nZisrUnk4dklmNlNtUEZpaFh3OFBDQVJDSkIvLzc5OGVMRkMwRWZjR1hOdHpSTWlMSlJ4TDFJVDA5SDNicDEwYlZyVnhRV0ZuSjJPM2Z1ek9zVXdIK1hIWDlPcjE2OWNQRGdRYWlvcU9EczJiUG8zTGt6Ynh2VVNKOERYM29lQkFRRW9ISGp4dDl0VHlLUkZPdjNNbjc4ZUtpcnF5TWxKUVg5Ky9jdnNqeFdPbkw5Slo4WmVhVGxjekhHMTVMQTBOQlFPRG82NHV6WnM2V09BczZkT3hlUEhqM0M3Tm16eSs0UVdkSWV3WEZ4Y1dSdGJTMnpIM0dOR2pVSUFQM3l5eTgwZCs1YzZ0YXRHNzEvLzU0N2ZlbmV2WHVVbDVkSEsxYXNJQThQRCs1UW1PdlhyOVBseTVlL2FSOWtzVmhNVFpzMkpTOHZyeS9HM2JKbEM3ZG50anhQd3lJaVdyRmlCUUVnVFUxTit2RGhRNUU5NHFVSDFTZ3JLL04yQ0ZKVVZCUlpXRmh3KytIdjNidVg0dVBqS1NNamd4NC9ma3hidDI2bERoMDYwRjkvL1NWWHU3ZHUzZUxLOWIrbkw2YWtwTkRpeFl0SlIwZUh0TFcxdjNoWXh2Y3diTmd3QWtDV2xwYkZualh3NmRNbldyUm9FV2xwYWZGeUlORzFhOWNFT2Z5bE9QTHo4Mm5xMUtta3BxWkdSa1pHRkJvYVNqazVPVEo1MzdWckYrbnA2Wkc2dXJwYzYvL25oOTRjUFhxMHhIamp4bzNqRGdQaTYwQXNLWmN1WGVMU0ZCMGRMY2c5dUh2M0xtZHo3OTY5ZFA3OGVhcFpzeWJ2ZS9EZnVIR0RzM3ZxMUtsaTQ0d2NPWktMNCtqb3lNdlpCRU9HRENFQXBLdXJTd2tKQ1RKblV1VGs1TkQ5Ky9kcDlPalJwS21wS1pkVElLOWN1VUlpa2FqSTg1YUlhUGp3NGFTa3BFVHg4ZkVsSGtxbG82TWpsejM1Mzc5L1grbzVLRklLQ3d2Snk4dUw4SFdIN0pZNURWMjZkQ0ZWVlZVS0RnNm16TXhNTHV6cDA2Zms0K05ER2hvYXRHYk5HdmtkQnRTMmJWdVpCOTJaTTJmSTFOU1V6TXpNYVA3OCtaU2JtMHRFUkpHUmtXUnFha29tSmliazd1NU9ZV0ZoWE9Vb0tDZ2dkM2YzWW0vaWwvajk5OStwV2JObTNCRzhvMGVQTHZFbUxGbXlST2JZVW5WMWRSb3hZa1N4RmVScnVIRGhBazJmUHAwN1lBS2ZIY3RwWjJkSDV1Ym1wS3VyU3c0T0RqUnMyREM2ZS9jdXJ3K0Q3T3hzV3I5K1BiVnQyNWFNalkyNW8zbGJ0R2hCR3pac2tLa1kzOHVqUjQ5b3dZSUZaR05qSTVOM0F3TURjbkJ3SUh0N2U3S3lzcUxPblR0VFNFZ0lwYVdsOFpMbnc0Y1AwOWl4WTBsSlNZbExRL1hxMWFsT25UcmN4OHpNakRzRnJHL2Z2bksxLytEQkF3b0tDaUpyYTJ2T3ZxR2hJUVVFQk1qMStOZXlrSmlZU0lzV0xhSldyVnBSN2RxMXljbkppZXJWcTBlV2xwYms3dTVPSzFldXBPVGtaTG5lLzgvYmxaR1JFZm43K3hjNUR0alB6MC9tdUZnaGp3TzJzcktpd01CQVFZNERYckJnQVJrWUdKQ2hvU0Y1ZTN0LzkvT2xOTzdmdjA5ejVzeVJPWWJheU1pSVpzeVlJVlB2dG16WlFyVnExWkpwbzhyS3l1VGg0VUdiTjIvKzduUWNQSGlRUm8wYVJjckt5akkyU3ZwMDc5Nzl1K3RkVUZBUWR3eXltNXNiTFYyNmxONjhlU1BUSm52MTZpWHp2VE5uenRDa1NaT29TcFVxWEZvNmRPaEF5NVl0KzZaNitPYk5HMXF5WkFrMWFkS0VPNUZ3NGNLRjlPalJveEsvazVPVFF5NHVMcnpWaVlpSUNQTDI5aVliR3h0eWNIQ2dldlhxVVlNR0RXam16Sm5mZEFLb2lFb1pUNzExNnhZR0R4Nk1temR2ZnZOdzhvSUZDMkJzYkl6aHc0ZXp5VUlHZzhGZ01Nb0pTbDl5YnZEMTljV1FJVU8rYVQ0bE5EUVV5Y25KclBObk1CZ01CdU5IRWdBQU1HblNKRGc3TzhQVDA3UE1tOXQ4L1BnUmZuNStTRXhNbE50NmVBYUR3V0F3R1BLajFDbUF6NG1Pam9hL3Z6OWF0bXlKUVlNR0ZYc0l4ZVBIajdGLy8zNUVSMGRqOXV6WmNqMFdsY0ZnTUJnTWhnSUVBUER2OHF0ejU4NGhQRHdjejU4L2g2cXFLcFNVbENBU2lWQlFVQUFyS3l0NGVYbWhWYXRXTW5zRk1CZ01Cb1BCK0lFRkFJUEJZREFZaklxQkVpc0NCb1BCWURDWUFHQXdHQXdHZzhFRUFJUEJZREFZRENZQUdBd0dnOEZnTUFIQVlEQVlEQWFEQ1FBR2c4RmdNQmhNQURBWURBYUR3V0FDZ01GZ01CZ01CaE1BREFhRHdXQXdtQUJnTUJnTVJqbm4zYnQzc0xhMkJ0dEFGcmh4NHdhU2twSXF2Z0NJajQvSHdvVUxZV2RuQjVGSXhIMDBORFNncDZjSE96czcrUHI2SWlZbWh2Y0UzNzkvSCtQSGo0ZTl2VDNNek14UXZYcDFPRGs1WWViTW1YajE2cFhjN1YyOGVCR3paczJDbnA0ZWwyOWxaV1VZR2hxaWF0V3FzTEN3Z0llSEJ3NGZQaXhJbzdoLy96NzY5KzhQUTBORDZPcnF3c2JHQnVQR2pjT1ZLMWV3Y3VWS1hMcDBTZTQydzhMQ1pPNTdXVDU5Ky9iOWJydm56cDNEckZtelVLMWFOZTUzR3pac2lDVkxsdURseTVjeWNSTVRFN0Y0OFdJNE9UbEJKQktoVnExYW1EOS9QaDQvZnZ6TjlxT2pvOUd6WjArWmZOV3JWdytMRnk4dU52N3AwNmZSb2tVTExtNjNidDN3NU1tVHI3YTdiTmt5bUp1YmM3OVR1M1p0ckZ5NUVnQVFGeGNIWDE5Zjdnd09rVWlFamgwN0lpd3NUT1kzTGwrK2pKRWpSMEpKU1FtcXFxb1lNV0lFa3BPVHZ5b2RTVWxKbURScEVtclZxaVZUQm9hR2hwZ3padzZ5czdPNXVMLzk5aHQ2OSs3TnhhbGZ2ejZDZ29LKzYvNUhSa2FpWGJ0Mk1yWU5EQXpnNysrUEZ5OWV5TVI5OHVRSlJvMGF4WlZMMWFwVk1XM2FOTHgrL1ZvdWJTQXFLa3FtL1d0cmF4ZjVLQ3NyUXlRU1FVVkZCVmV2WHVYdEdaQ2Jtd3VSU0FRMU5UWFVxRkdEKy95M1RQaEFYMThmdHJhMnVIYnRta0k2ckJjdlhzamtXVTFORFNLUkNMbTV1WUttUXl3V1k5Q2dRWmcwYWRLUHJXTG9LN2g1OHlZQklBQjA2ZElsSWlKS1QwK25CUXNXa0xLeU1vbEVJbHExYWhYeFFVRkJBVTJmUHAxVVZWVnB5cFFwbEpTVVJFUkVFb21Fb3FLaXlNM05qYlMwdEdqcjFxMjgyRis3ZGkwQm9LcFZxMUoyZGpZUkVYMzY5SW0yYjk5TzJ0cmFCSUFHRHg1TWhZV0Z4QmVYTGwwaURRME5HakJnQUwxOCtaS0lpSktTa21qV3JGbWtvcUpDQUNneU1sTHVkamR2M2t6Mjl2WjA4K1pOeXN2TDQvSXVyUXQvL2ZVWGR5OGVQWHBFbnA2ZTVPSGhJVGY3d2NIQm5LMlVsSlJTNHlZa0pCQUF1bjc5dXR6c3o1dzVrN04vOGVMRlV1T0t4V0pTVjFlbnNXUEhmcGZOUjQ4ZWtaS1NFZ0VvdGsxTm1US0ZTOU9qUjQ5Sy9KMzY5ZXZUd29VTHZ5c3R1Ym01MUs5ZlA4N2UxS2xUaTQyWGxwWkdBR2pzMkxHVW41OHZ0L0tmTm0wYVp6c2dJS0RVdU0yYk55Y0xDd3VLajQrWGF4czRmUGd3MWExYmwvNysrKzlpMi9pOWUvZW9TcFVxQklCbXo1NU5mQ0p0ZSszYXRTTkZzSFBuVHBvd1lRS1ZCMzcrK1djQ1FKOCtmUkxVN3JKbHk4akh4NGZxMTY5UDU4K2ZweCtWcnhJQXFhbXBYRU84ZS9ldVROaWNPWE1JQUlsRUlyaytmSW1JQ2dzTHFVK2ZQZ1NBTm16WVVHeWN2THc4NnRpeEl3R2c0T0JndVJmVXNXUEhDQURwNnVvV0NkdTJiUnRYTHZ2MzcrZmxSa2trRWpJM042ZjY5ZXVUUkNJcEVuN2t5QkVTaVVTOENJRGx5NWR6bmZ4L0gwS2ZDNERQdzd5OHZPUm1Qenc4bkFDUXBxYm1GK1BtNWVVUkFIcjM3cDNjN0w5Nzk0NjB0TFFJQUsxWXNhTFV1QThmUGlSZFhWM0t5TWo0YnJ2dTd1NEVnUHIwNlZNazdPM2J0NlNxcWtvQTZNaVJJOFYrUHljbmg2cFZxeWFYc2hDTHhkU3FWU3NDUURWcjFxVDM3OThYaWVQbjUwZDkrL2FWZS8wVGk4WFVzR0ZEQWtCMmRuWWtGb3VMalplZW5rNTZlbnAwN2RvMXVhZGg0OGFOZE9yVXFXTEQ4dlB6dWZRMWF0UklydUtuUEFxQTkrL2ZrNVdWRmE4dk8rVlpBTHgrL1pyTXpNd29KU1dGTGw2OFNBNE9EaVhXeVFvbEFONitmVnVpQUhqMTZoVVhObkxrU0xrbWN0R2lSUVNBL3ZlLy81VWFMeWtwaVRRME5FaEpTWW5PblRzbjF6U2NQSG15UkFFZ2tVaElYVjJkQUpDbnB5Y3ZOK3IyN2RzRWdIcjM3bDFpbkU2ZE92RWlBUGJ1M1Z1a3NaY21BSWlJZHUzYUpUZjdSNDhlTGJIc2krc3NBRkJXVnBaY3kyRE1tREVFZ096dDdVdU5OMmZPSEpvNGNhTGN5aDBBYVdscDBjZVBINHVFZCszYWxRRFF3SUVEaS8zK2tTTkhxR3ZYcm5Jcmc1Y3ZYNUtlbmg0Qm9DRkRoc2lFN2QrL254d2RIYm5STVQ3cXYzU1VhK25TcGNYR0dUdDJMRTJlUEprWCswdVdMQ2t4YjlJUm9pcFZxdEM5ZS9kNGYyZ3JXZ0FRRVhYcDBvV2lvNk1ycFFBWU1HQ0F6S2ljbDVjWHJWbXpwbklMQUNMaTNwSisvdmxudVNVd0pTV0ZORFUxQ1FDRmg0ZC9NWDdQbmowSkFEazVPY2xWb1pZbUFJaUk2dFNwUXdDb1JZc1d2TnlvVzdkdWNaMUJTUStaSFR0MjhDSUFTbnNJbFNRQTVFbDVFQUR4OGZFa0Vva0lBSjA5ZTdiRU4wRmpZK05TaCtTL2h1enNiRzU2S1N3c3JFajQrdlhyQ1FCcGEyc1gyem4xN3QyYjl1M2JKM2N4S0wzdlo4NmNJU0tpdTNmdmtyR3hzZHlIM1lzVFZ3QklRME9ERWhJU1pNS3VYYnRHVmxaV3hRb2xQcmw4K1RJM1ZiTjY5V3BCMjU0aUJjQ2VQWHZJejgrdjBnbUE2T2hvcWwrL3Zzd2IvL1BuejhuRXhJVGV2bjFiZVFYQWh3OGZ1TENoUTRmS0xZSExsaTNqZnJjc1E1bmJ0Mi9uNGwrOWVsVVFBZkRwMHlkT3BJd2FOWXFYR3lVV2k4blUxSlJMdzYrLy9sb2t6cXRYcitqNTgrZE1BUEFnQUtSdlBRQ29ZOGVPeFlidjM3K2YycmR2TDFlYmd3WU5JZ0RGK2xUMDd0MmJ1d2YvN2Vnek16T3BSbzBhdkx5UjkralJnd0NRbVprWlBYLytuR3hzYkVxY2hwQW51Ym01Vks5ZVBXNDBVQ3J3OC9QenlkSFJzY1FoZXI3SXpNd2tLeXNycmpNV2FraThQQWlBek14TXNyUzBwSUtDZ2tvakFDUVNDVFZvMElBdVhMaFFKQ3dvS0VqdUk5OC9sQURZdEdrVEYxYlNHOUwzM0dCVFU5T3ZlbE1HOE4zT1QyVVZBQXNXTENBQXBLYW14dXRiMFBuejV6bEhJd0RVdkhsemlvcUtVa2pGcVl3QzRNS0ZDNXlmeS8zNzk0dUV0MnpaVXU0ZFlVUkVCQUVnRlJVVmV2UG1qWXpncmxhdEdpY0MvaXNRZnYzMVYvTDI5dWJsZnFTbXBsS05HalU0cDlocDA2WUpWdSt1WHIzS3ZYRkxIWDRYTFZwVXJKOEUzd3dkT3BRQVVMVnExZWpGaXhlQ3R6MUZDZ0FpSWs5UHp5ODZ4VllrQWJCMjdkb1NmWnMrZmZwRTF0YldkT3ZXcmNvaEFHN2N1RUZFLzNybkh6NThtSFIwZEFpQTNPWS9wZGpaMlJFQWNuUjBMRlA4Rnk5ZThPS0xVSndBU0VwS29pbFRwcEJJSktMcTFhdlRpUk1uZUw5aDE2OWZwN3AxNjNKNUJFQ2RPM2N1dGtOaUFrRCtOR2pRb05pNkZSY1hSN1ZxMVNyV1FmTjdLQ2dvNEVaKzFxMWJ4MTNmdVhNbjllelprNktpb29vVkNPN3U3blQ2OUduZTdzbmh3NGU1KzMveTVFbEI2OTdFaVJPNWpqYzZPcHFNakl3b09UbFowRFJJNjJSSjB6T1ZRUURzMzcrZnR4SFA4aVlBM3I1OVM2YW1wcVdPc0I0N2RvemMzTndxaHdEbzBhTUhlWHA2VXFOR2pjakJ3WUc4dkx4NEdZSXpOemNuQU9UaTRsS20rRGs1T1Z3YSsvZnZMM2NCb0tLaVF1N3U3dVRnNEVBQVNFbEppVFp2M3N4YmgxTWNlWGw1RkJ3Y1RMcTZ1bHhlVlZWVmFkR2lSVXdBOEN3QWR1N2N5YzFEcDZXbGNkZEhqeDVOQ3hZczRNV21kQmxjczJiTnVHc2RPblNnbzBlUFVtRmhJVmxhV2hJQVdydDJMUkg5NnpkamFHaklxMmZ5MWF0WFNWbFptWnNLK1BEaGcyQjFMenM3bXh0NlYxRlJvYzJiTnd2NjBFeEpTZUZHUVBoWTlmQ2pDSUNQSHorU2hZV0YzRVZ2ZVIwQnFJakkxUW1RRDF4Y1hBZ0EyZHJhbGluK3UzZnZ1RFNPR1RPR3R4R0FqSXdNcWwyN05nR2dFU05HS09UbXBhV2wwYVJKazdqbFlHVlpKLzBqQ29BVEowNlVXUURrNXVZU0FNckp5ZUZOZkJrYUdoSUFUbkJsWldWUjllclZ2N2hId2JkeTU4NGRycXdmUDM1TUtTa3BaR0Jnd08zSk1IdjJiQUpBVFpvMElTS2lOV3ZXME9qUm8zbnRBQzB0TFNrOFBKd1RvY09HRFJPMDd1L1pzNGNUWWtJdlIvUHc4T0NtSmVXNTNQUkhFd0JFLy9xaFJFUkVNQUh3ZzFMdXR3SzJzcklDQUx4Ky9ScUZoWVZmalAvMjdWdnU3d1lOR3ZDV0xsMWRYUncrZkJqcTZ1cll1blVyOXUvZnoyczU1T1RrNFA3OSt6TFhxbGV2anBVclZ5STJOaFoxNjlZRkFDeFpzZ1JwYVdrVmFzdE5EUTBOcmd6b0M3c3RabWRuUTFsWkdWV3FWT0VsTFdwcWFoZ3paZ3dBWU1PR0RSQ0x4ZGk5ZXpmYXQyOFBRME5EWG13Nk9qcHlkWG5mdm4wNGNPQUFldlhxQlRVMU5RQ0FqNDhQQU9EdnYvL0c0OGVQc1cvZlBnd1lNSUNYdEVna0V2VHQyeGVUSjA5R3IxNjlFQklTQWdEWXZuMDd6cDA3SjFpZHFGYXQycjlibWY3L3puOUNzV25USnB3NWN3WWlrUWc3ZCs2RW5wNWVwZDRPdDIvZnZqaDQ4Q0RiSTdraWJ3V3NTTHAwNlFJQStQanhJeDQ5ZXZURitMR3hzUUFBWldWbGVIaDQ4SnEyUm8wYWNWdTAvdkxMTDBoSVNPRE5WbVptSnJadTNWcHNXTDE2OVhEeTVFbW9xS2hBTEJiajl1M2JGYXFTMXF4Wms5dCtNelUxOVl0YmhacVltUERhS1l3ZVBScFZxbFRCNjlldmNmRGdRV3phdEFsang0N2x0UXlrblh4WVdCakN3c0l3Y09CQUxzek96ZzR1TGk0QWdLQ2dJS1NtcHNMTnpZMlhkRXlmUGgzR3hzWVlOMjRjQUdEWXNHSG8wS0VEQUdERWlCSEl5c3Fxc0EvTGhJUUVUSjA2RlFEZzUrZkg1YnVrZWxnWjZOeTVNODZkT3dlSlJNSjZVeVlBNUUrUEhqMjREaUE4UFB5TDhZOGRPd1lBNk5ldkg4ek16SGhQMzVneFk5QzNiMTlrWldXaFQ1OCt2TzVKZmV6WXNSSkhRV3hzYkdCblo4ZU5UbFFrYkcxdG9hV2xCUUJmM0lNOElpSUN6Wm8xNHpVOUJnWUc4UGIyQmdCTW1USUZBTkN5WlV0ZWJRNFlNQURLeXNwNDlPZ1IwdExTaW5Ud1VrR3c5N21HRlFBQUlBQkpSRUZVWjg4ZTlPdlhqeGNCZE9qUUladzllN2FJRU4yNmRTdTB0YldSbEpURWxVZEZReUtSWU9EQWdjakp5WUdkblIyQ2c0TkxqQ3NXaTdGcDA2WkswWUZvYUdqQTFkVVY1OCtmWjczcGo4alh6QmNrSnlkemM1R3hzYkdDZXBzQ0lDTWpvMUszV0UxSVNDQjFkWFV5TkRTVXUxZXcxQkZOUjBlblNGaG1aaWJaMk5nUUFQTDE5ZVdsREtSbFg1S2ozNXMzYjBoRFE0TnNiR3dFV1p1YmxaWEYxWVVyVjY3d2JpOGdJSURiYUtrazU3YmJ0MitUcnE0dXhjVEU4SjZldUxnNEx2OGJOMjRVcEIxSXR3YjI5L2N2ZGw1ZTZwUjM1ODRkdWR1K2NlTUdHUmdZbExqYVJMb3BFUUJCVnNOSTI2T0dob1lnWlQ5djNqek82VkM2QXFva3RtelpRaXRYcnF3VVBnQkUvKzQ0K2QrZElaa1BRQVYwQXZ6Nzc3KzVSaTcwcGh2U0RZRjY5dXhaYkFmdy92MTdjbkZ4b2VyVnEzK3hnWDRMcTFldjV0YUFGK2Z4L004Ly8zQnI5Q2RQbml4M0QrelB4ZGZBZ1FNNUFWWllXRWkzYnQyaUprMmFrTDYrdmlDZEh4SFJnd2NQdVBRY1BIaVFkM3U1dWJuVXExY3ZBa0N0VzdlbXlNaEl5c3pNcEt5c0xMcDE2eFpObXphTnRMVzFhY2VPSFlMVnlRNGRPcENPam81Z0swQ2tqbThsN1RUWXNXTkhxbCsvdnR6dG5qeDVrdlQwOUVwMTlNdkx5K1BXNSt2cDZmRytKZTY2ZGV1NCtwZWVuczZycmV2WHIzUGJFQWNGQlpVWUx5TWpnMEpEUTBsTFM0dlhBMkxLbXdENDlPa1RtWnViYzA2cFRBQlVNQUh3Nk5FakNnb0tJbXRyYTY3UjFhcFZpd0lEQXdYcmNJaitYV2RacTFZdGF0U29FZTNkdTVmdTNMbEROMi9lcERWcjFwQ1ptUm0xYTllT25qeDVJbGViRnk1Y29Ca3pabkQ3SEFBZ1YxZFhDZzRPTGpMS0VCb2F5c1V4TnpjblB6OC9ldjM2dGR3RXdQang0K25HalJ1MFlNRUNjblYxSldOalk2cGF0U3BaV0ZqUXFGR2pCTm1NNU5telo3Unc0VUtxWDc4K2wxY1RFeE9hTjI4ZUw4THJjd29LQ21qbnpwM1VvVU1ITWpRMEpCVVZGZExWMVNWN2Uzc2FNMmFNNEhzaG5EbHpScTRyVGI3RXg0OGZxVzNidGlXR2g0V0YwZUxGaStWbTcvVHAwOVN1WFR2dVB0ZXNXWlBtenAxTHVibTVNdkdpbzZObGRpWEUvMjlaUFdyVXFDSmI5bjR2MGRIUk5HdldMTzVNQWdEVXRHbFRXckprQ2FXbXB2SlM3cC9YZFUxTlRkTFMwaXJ5MGREUWtNay9YMmtwandLQWlHamd3SUdDN3dmQkJNRDNJeUlTNEJCN09TSVdpN0Zueng1TW5EaVJjemhTVjFmSGhRc1hlSE44WWpBWWpQSkNibTR1TkRRMDBLNWR1MG8vOTk2eFkwZWNQWHNXbno1OTRtM2xEM01DTEVlb3FxckMxOWNYbHk1ZGdxbXBLUUFnTHk4UEZ5OWVaSGVUd1dBd0dJeUtLZ0NrTkdyVUNIZnUzRUdmUG4wQUFJR0JnVGgxNmhTN293d0dnOEZnVkdRQkFBRDYrdm80ZVBBZ29xT2o0ZWJtaGw2OWVtSFZxbFhJejg5bmQ1YkJZREFZakZMNDRYd0FTdVArL2ZzNGRPZ1FuajU5Q2x0Ylc3UnYzNTczTmVFTUJvTWhKRklmQURVMU5abWRDRy9jdUlGYXRXcFY2THkvZVBFQ0RSczI1UDZmbVprSnNWaGNvWDBBWW1KaTBMUnAwNi82enBVclY4cjBuUW9sQUJnTUJvUEJZSlFOSlZZRURBYUR3V0F3QWNCZ01CZ01Cb01KQUFhRHdXQXdHRXdBTUJnTUJvUEJZQUtBd1dBd0dBd0dFd0FNQm9QQllEQ1lBR0F3R0F3R2c4RUVBSVBCWURBWURDWUFHQXdHZzhGZ01BSHdReEFSRVlFdVhicWdaOCtlckRBK0l5TWpBeXRXcklDRmhVV2xPNTVVTEJaajZkS2w2TkNoQTdTMXRkR29VU1A4OXR0dkZUS3ZzYkd4R0RwMEtDd3RMY3RGZXZyMzd3OURRMFBFeGNVcHhQN0FnUU5oWkdTRWUvZnVDV0x2eG8wYkdESmtTTG5ZN3ZmbHk1Znc5L2VIc2JFeC92bm5IL1lRL0ZHaGIrRGF0V3Vrb2FGQkFPamh3NGRVMFNrc0xLUUpFeWFRdWJrNUFhRHUzYnNUNDE5dTNyeEpYbDVlcEtTa1JBQW9JaUtpMHVSZElwRlErL2J0S1RRMGxJaUlybDY5U2xXcVZDRUFkUDc4K1FxVjEvWHIxNU96c3pNQklFTkR3M0tSSmt0TFN3SkFSNDRjVVloOTZmTWdQRHljZDFzN2QrNms5dTNiRXdDcVhyMjZRc3Y5eXBVcjVPUGpReUtSaUFEUTdkdTMyWVB3QndYZitzWERodytUU0NTaVpjdVdWWnJDQ2c4UFp3S2dCTnpjM0NxZEFOaXdZUU1Cb0t5c0xPN2E3dDI3eWNqSWlQNzY2NjhLbDkvSGp4K1hLd0h3NU1rVE9uMzZ0TUxzeDhmSDA0a1RKNml3c0ZBUWU4bkp5ZVZDQUVoeGNIQmdBdUFINTV1bkFIcjM3bzBsUzViZytQSGpsV2EwcEhyMTZteklxQVJxMUtoUjZmSzhmLzkrcUtxcVFsdGJtN3ZtNCtPRDVPVGtDbmtLWlhtci83VnIxNGFIaDRmQzdOdlkyS0JyMTY0UWlVU0MyUHY4NUwveVFIbExEME5nSDRBWk0yYkEwZEVSYjk2OHFSU0ZwYUtpd21vTUt4dU9odzhmUWxWVmxkMWpoaUFvS3l1ejlERGsyNmEvOXdjMmJkckVTcEZSS2NuSXlJQzZ1am9yQ0FhRFVmbEdBQlJCWVdFaHRtN2RpdGF0VzZOSGp4Nm9XN2N1ZnZycEo0U0ZoUW1hanJ5OFBNeWNPUk5HUmtiUTBkR0JsNWNYa3BLU0JMR2RtNXVMeFlzWHc5WFZGVTJhTkVIdDJyWHh5eSsvSUNVbFJSRDc1OCtmaDd1N085cTBhUU0zTnpmNCt2cmkvZnYzZ3BYOWh3OGZNSFBtVExSbzBRSm1abVl3TmpiRzhPSERrWnFhS2tpbmIyZG5CenM3TzBna0V1VGs1SEQvSHpGaWhDRDUzN2x6Sjl6ZDNURnExQ2c0T3p0REpCTEpmQUlDQWdSSng5bXpaL0hUVHo5QlUxTVRMVnEwd09QSGp3V3JBNG1KaVpnelp3Nk1qWTF4OCtaTndaOURTVWxKQ0FnSWdLbXBLZjc4ODArRlBRL3o4dkl3WU1BQWlFUWlHQnNiWStiTW1ZaUtpcW9RblpORUlzR1JJMGZ3ODg4L2N5dXZqaDQ5Q2hjWEYyaHJhNk5ObXpaY25YdjY5Q2s4UFQyaG82TURVMU5UYk55NFVlN3B1WHo1TXJ5OXZXRm5ad2NBdUhqeElwbzNidzVOVFUwMGI5NGNDUWtKZ3BUTHFWT24wTGx6WjNUczJCRTJOalp3YzNQRDNyMTd2KzNIZmpTbmhmSGp4eE1BdW5mdkhoRVJaV2RuazcyOVBRR2dQLy84azFmYmx5OWZKdndmZStjZEZ0WHhOZUIzZCtsVkVKQXFFa1NrMm52c0dudUxMV0pOeE42TkxkR2ZKcmJZZXk4azloSkxqQnFqMGFqQkduc0RDeGFrV09pOU05OGZMdnNCZ2hwbEY4dDluNGNuWnU3dW5ybHo1ODZjT1hQT0dSQXRXN1lVWDN6eGhmajg4ODlGaXhZdFZKN2Z0cmEySWl3c1RLMTFpSXVMRTlXcVZSTyt2cjRpUFQxZENDSEU3dDI3QlNDY25KeEVmSHk4V3VXdldyVktHQnNiaXhNblRxaktKazZjS0FDTk9BRkdSa2FLeXBVcml3TUhEZ2doaE1qS3loSkxseTVWM1g5MGRMVEcrcUpDb1JDR2hvWWE3ZjlqeDQ0VjJ0cmE0dTdkdTBJSUlkTFQwMFhkdW5VRklIcjI3Q2tTRXhORlptYW1XbVFuSkNTb25BQlhyMTR0MnJadEt4WXNXQ0JhdG13cEFGR3paazJOdE1FLy8vd2ordlRwbytwekZ5NWMwT2d6T0hmdW5PamZ2Ny9LQzk3ZjMxOGpjak15TWdwMEFodzFhcFJvMUtpUlJ2dStFRUxVcjE5ZnJVNkEzMy8vdlhCemMxTTVYaytaTWtWODg4MDNZdUhDaGFKbXpab0NFQlVxVkJBWEwxNFVkZXJVRWJObXpSS1RKazFTUmFqOTg4OC9SVmFYalJzM2lxNWR1d3BBT0RvNml0V3JWNHRtelpxSjZkT25pNlpObXdwQVZLNWNXZTF0UG5ueVpPSHM3Q3dlUFhxazZoTkRoZ3dSZ1BEMTlkVmNGRUJ4WVd4c0xMUzF0Zk9VVFpvMFNRRGlwNTkrMG9nQ1VLcFVLWEg2OU9rODNzQzJ0cllDRUQ0K1BtcXRRNDhlUFlTOXZiMUlUazVXbGFXbXBtb2svT3p5NWN0Q1MwdEx6SnMzTDA5NVptYW1jSEJ3MElnQzRPUGpJeVpObXZSU3VhZW5wd0RFdEduVFBsb0ZJQ0FnUU1oa010R29VYU04NVFjUEhoU0FNRE16VTZ2OEhBVkFSMGRIL1B6enozbWV2NTJkblFCRWFHaW94dHJEeTh1cldCU0FIS3BYcjE3c0NzRFlzV05GMjdadFJXcHFxc2J2WDkwS2dCRC9IM25sNk9nb0xsKytyQ3BQU2tvU0ppWW1BaEREaHc5WExZYUVFR0xPbkRrQ0VFT0hEaTNTdW9TRWhBaEE2T3ZyNStuL0dSa1p3c3JLU2dEaTRjT0hhbXVMdi83NlN3QmkyN1p0TC9XTG5QRnYvZnIxbW9rQ0tDNUdqUnJGdUhIajhwUVpHeHNEa0p5Y3JKRTYxS3haazlxMWE2diszOFhGaFZtelpnSHcyMisva1pHUm9SYTVZV0ZoYk4yNmxTKysrQUo5ZlgxVnVhNnVMc2VQSDhmUHo0OEdEUnFvN2I0blQ1NU1abVltWDMzMVZaNXloVUpCbFNwVjFON3UwZEhSN05peGc4T0hEOU8rZmZzOGZ6bzZPcmk2dW1wa0c2QzRPSFBtREVJSXJLeXM4cFJYckZnUmdKaVlHRkpUVTlWZUR6TXpNL3IwNlpQbitidTd1NnY2cUtZbzdxZ0VjM1B6WXQwS0hUQmdBS0dob2V6ZXZmdWo5VVVwVWFLRXFvOVhxbFJKVlc1Z1lLRHFjNzE2OWNyampPdmw1UVZBZUhoNGtkWWxaNTZ4c3JMSzAvKzF0TFNvVUtFQ0FFK2VQRkZiVzh5Y09ST0F4bzBiNXluWDB0Smk4T0RCQVB6MDAwLy82VGMvT0xmZUgzLzhFWUQwOUhSMjd0ekozcjE3Q1FrSlViMFV4VVhuenAzcDNiczN5Y25KaElhRzR1VGtwSllKSURzN3U4Qk1ZRFZyMWxScjZGbFNVaEtIRHg5R1YxY1hPenU3bDY1cndpUDQwcVZMWkdWbE1XclVLTHAxNjhhblJzNkVsOS9YSTJjaU1qVTFSVTlQcjFqcWxxT1Fha0lCMFdTZmV4L2xDeUhvM3IwN2UvZnVKU2dvNktPT3puaFZHeHNhR3FyYUl6YzU3MEJhV3ByRzZtSmlZcUthbDlSQlltSWlKMDZjS0ZUeHJWZXZIZ0JCUVVFOGZmb1VhMnZyTi9yZER6SVZzSitmSHpWcTFDQWxKWVd0VzdmU3ExZXZZcStUbnA3ZUd6ZjZ1NnlBMWExbEZzYWpSNC9JeU1oQUxpKytMcE56L3c4ZVBPQlRwRm16WnRqWjJYSDE2bFVTRWhKVTVjSEJ3UUIwNmRLbDJPcVdFd3RmbkVyNHA0Sk1Kc1BZMkZqbEFKaVptU2sxeW50Q2ZtV2txQWdORFZYOWRzNDRtQnQ3ZTN2VnYvK0xKZnlEVXdENjl1M0xoQWtUK1AzMzMrblhyOTk3WmZyS3pzNUdSMGNIR3hzYnRmeStxYW1weWhKUUdPcktTNTZqL2Fha3BCQVJFVkVzN1p1VGNHZi8vdjJGZnViQ2hRc2Y3ZUNpcjYvUG9VT0hLRldxRkpNbVRWTDF1Umt6WnVEdTdzN3MyYk9sRWZnVFljbVNKVlNzV0JGL2YzOG1USmdnTmNoSFRzN1luMXZoejAzT1BLaWxwVldnaGZhalVBRCsrZWNmL1B6OGFOV3ExWHR4SUVadW9xS2llUGJzR2MyYU5WT2JHYlpxMWFvQTNMeDVrNE1IRDc1MC9lVEprMm83R01YSnlVbGw1bjNWQkt6T0ZXRE9IdUQ1OCtmWnZuMzdTOWR2M3J6SjMzLy8vVkVQQkFZR0JoZ1pHWkdjbk16WFgzK05yNjh2N3U3dW5EdDNUc3JNOWdtaHA2ZkhybDI3TURVMVpmNzgrZXpkdTFkcWxJOFlHeHNiWEZ4Y0FBcDgxam1Mc2hZdFd2eW5SZkVIcFFEa09IWGN1SEZEWlE3Snlzcmkrdlhyd1AvditVUkdSbXE4YnV2WHIwZFhWNWZwMDZlclRVYlpzbVZwMkxDaHloSnkrdlJwMWJXLy92cUxFU05HMEtaTkc3WEkxdFhWeGNmSEIzamhESmgvR3lJeE1SRjRFYU92TG14dGJXbmR1alVBZmZyMFlkbXlaYW85NS9Qbno5TzllM2VOK1FZSUljak96aVlySzB0amZTd2xKWVdtVFp2aTQrUEQyclZyK2Zubm4vSHo4MlBDaEFrcUJ5VjEzM05SZkVhVDlmbVl5SCsvenM3TytQbjVxZDZITzNmdUZHdDlQdlpuL0NhTEczWFdkL3o0OGNDTFBDQkpTVWt2TGY3a2N2bC90d1o5U0NHQTkrL2ZGOXJhMmdJUVRabzBFZVBHalJQVnExY1hYYnAwRVlCd2RuWVdQWHIwVU9VSUtHcHUzcndwOVBUMGhJR0JnVml6Wm8wcTlHVFhybDNDM054YzdOdTNUeU50WUdOam80cUJkbkJ3RUJZV0ZrSmJXMXVjUEhsU3JiS2pvcUpFdVhMbEJDRHM3T3pFa2lWTHhPN2R1MFhQbmoyRm82T2pBSVNucDZlWU1tV0syZzVJQ1EwTlZja0NoTGEydGpBeU1oS0FXTHQyclViN1lrNGRuajkvcmhHWnQyN2RFb0JRS0JUQ3ljbEp1THE2Q2pjM04rSHA2U2xxMXF3cEJnd1lvTW9Qb0E2Q2c0TUZJQXdORFY5NnZvMGFOZExZeVhnNWVIdDdDMEFjT1hLa1dNYWpWcTFhYVRRTU1PY3dJRjFkM1R5NUh2cjM3eThBNGVMaUlwNCtmYXF4Kzg4NURFaWRvY2M1WVlEMTY5Y3ZOQXp6NzcvL3psUCsrKysvQzBEVXFWT25TT3R5NTg0ZEFZZ1NKVXE4MVA5elRtcFVaLy9QenM0V1BYdjJWT1ZGaUkyTkZVSUljZjM2ZFZHNmRHa3hlL2Jzano4UHdKWXRXNFNqbzZNd01EQVFiZHUyRlk4ZVBSSVBIandRTmpZMndzUERRNXc1YzBhdDhoODllaVJHakJnaG5KMmRoYm01dWFoUW9ZTG8xYXVYdUhQbmpzYmE0UEhqeDZKSGp4N0N6TXhNNk92cml5Wk5tb2h6NTg1cFJIWmtaS1FZTUdDQXNMQ3dFUHI2K3FKeDQ4YmkzMy8vRlowNmRSSU5HellVTzNmdUZCa1pHV3F0dzdObno4VEFnUU9GdGJXMTBOSFJFUlVyVmhRN2QrN1VXUHZQbVROSEZZTU9pRnExYW9tRkN4ZUttemR2cWwzMnBFbVRoSzJ0cmJDeHNSRUdCZ2FxWTVoei9zek16TVNUSjArS1hPNXZ2LzBtNnRXcnA1TFRxVk1uY2VqUUlYSDkrblV4WnN3WVZWSWNOemMzNGVmbnAvWjhDTU9HRFZQVnhjdkxTL3p5eXkvRnBnRGt6Z21pTGpadDJpUWFObXlvdXVldVhidUtQLzc0UTZTa3BJaU9IVHZtV1JETW5EbFROVG1vZzN2MzdvbWhRNGVxWkhwNGVJaGx5NVlWdVp6VnExY0xGeGNYQVFpNVhDNUdqeDR0cmx5NUlpNWN1Q0FHRFJxVTUva3ZXclJJQ0NIRXZIbnpWSXNVdVZ3dVJvd1lJZTdmdi8vT2RkbTNiNTlvMEtDQlN1WlhYMzBsRGg4K0xHN2N1Q0hHamgycjZ2L2x5NWNYcTFhdFVxc1NzR2JOR2xHNWNtVlJzbVJKVWJseVpkRzhlZk8zVm9KbDRsT3pvMGxJZktCRVJFVFFyVnMzZHUzYXBZcVB6aUUxTlpWSGp4NHhZTUFBZkgxOTZkbXpwOVJnYXFaMTY5WWNQSGlRYTlldTRlM3RMVFdJeEFlSFhHb0NDWWtQQXg4Zkh4bzNidnpTNUE4dm5NTEtseTlQdzRZTlA4bWptWXRyVDFndWw2c2w1NGVFaEtRQVNFaElBSER4NGtXT0hqMkt2Nzkvb2NsMnJsMjd4cmx6NS9qaWl5K2tCbE1Ec2JHeGVaTExKQ1ltVXJkdVhZMDRZRXBJcUFQcGdHOEppUThBTnpjM3ZMMjlPWFRvRUU1T1RyUnUzUnBYVjFjTURBeUlpNHZqNHNXTFJFWkdzbVBIRHVtY2RqV1FtcHJLWjU5OWhyYTJOdHUyYmNQRHc0TzdkKysrTWlSV1F1SjlSL0lCa0pENGdDYWgxYXRYOCt1dnYzTHo1azJTa3BJd016T2pjdVhLcWhESWp6a3RiSEhUcjE4L2R1ellRWFoyTnZYcjErZkhIMzlVNWVhUWtKQVVBQWtKQ1FrSkNZa1BBc2tIUUVKQ1FrSkNRbElBSkNRa0pDUWtKRDRGcEExRENRa0pDUW1KWWtDV2M0eW1aQUdRa0pDUWtKQ1FrQlFBQ1FrSkNRa0pDVWtCa0pDUWtKQ1FrSkFVQUFrSkNRa0pDUWxKQVpDUWtKQ1FrSkNRRkFBSkNRa0pDUWtKU1FHUWtKQ1ErSmk1Zi84K2l4Y3ZKaWtwU1dNeWZYMTkyYng1czBidmMvLysvZXpmdjUrc3JDenBvVXNLZ0lTRWhNU25peENDeVpNbnMzVHBVbnIzN28yaG9lRkhmYit0VzdkR29WRFFva1VMSGoxNkpIV0FkMFJLQkNUeFR2ajcrMU8zYmwycElTUWtpb0ZaczJaeCt2UnBqaDA3OWtuY3Iwd21vMlhMbHFTbHBkRzBhVk91WExtQ2taR1IxQkVrQzRDRXBybHk1UXArZm41U1EwaElGQVB4OGZGTW16YU5oZzBiZm5MMzNxQkJBNEtDZ2xpMWFwWFVFU1FGUUVMVHBLYW1NbURBQUtUREpDVWtpb2RMbHk2UmtwSkNWRlRVSjNmdk9mZnM3Kzh2ZFFSSkFaRFFKR2xwYWZUczJaTUxGeTVJalNFaFVVemtwSkcvZXZYcUozZnZPZmNzbDB0VG1FWVVnT3pzYkE0ZVBFajc5dTFwMGFJRlFnaG16WnFGZzRNREJnWUdORy9lbklDQUFJMVUrdkxseTNUdTNKbnExYXRUcmx3NWF0V3F4YnAxNjZoUm93WW5UcHhRdS93elo4N1F1M2R2WEZ4Y0VFSXdkdXhZVEUxTmFkT21EZG5aMldxWDcrL3ZUOHVXTFduZnZqM2x5cFZESnBOUm9rUUpqYlM5RUlJK2ZmcHc4ZUpGQUg3Ly9YY3FWcXhJeFlvVkNROFBWNXZjZWZQbTRlbnBpVXdtbzJiTm1xcnkwNmRQMDdkdlgyUXlHVEtaak51M2I2dEYvb29WSzdDeXNsTEo2ZHUzTDZHaG9hcnJ1M2Z2eHN2TEN6TXpNOWFzV1ZNa012ZnQyNGVqbzZOSzV2VHAwd0U0ZE9nUTlldlhWNVczYmR0V3RSTEt5c3BpM0xoeHlPVnl2TDI5dVhIalJwSFVaZGV1WFZTdFdsVWwwOXZibTF1M2JwR1dsa2FuVHAyUXlXUlVybHlaSTBlT3FLWDlwMDZkaXI2K1BqS1pEQzB0TFNaTW1FQmNYSnpxK3FGRGgzQnpjME5YVjFmVlRtb1pNT1Z5ek16TThQTHlVdlg3aWhVclltSmlna3dtbzNUcDBocXppcm02dWdKdzgrYk5UMjdpdW5YckZnRHU3dTdTTFA2T0Evb2JNV1BHREZHaFFnVUJpTWFORzR2aHc0ZUx0bTNiaW43OStna3JLeXNCQ0hOemN4RWNIQ3pVeWJwMTY0UzF0YlU0Y2VLRXFteno1czFDTHBjTFFCdy9mbHl0OHBjdVhTcHExYW9sQUdGblp5ZCsrT0VIMGE1ZE82RlFLSVJDb1JDUmtaRnFsWC9uemgxaGJXMHR3c0xDaEJCQ1pHZG5peGt6WmdoVFUxT2hTZmJ1M1NzQTBidDNiNDNKUEhQbWpBQkVqUm8xWHJybTd1NHVBQkVZR0tnMitWZXVYQkV5bVV3QUlqbzYrcVhydnI2KzR1ZWZmeTVTbWJkdTNSSnl1VnpvNit1TGpJd01WWGxpWXFLd3NMQVFnTGg3OTI2ZTd5UW5KNHVTSlV1SzU4K2ZGMmxkVWxKU1JQWHExUVVndnZ6eVMxWDU0c1dMUmMyYU5VVlNVcEphbi8rS0ZTc0VJS3l0clF1ODNyMTdkekZ4NGtTMXljL0l5QkFlSGg0aUpTVWxUL21OR3plRW5wNmVVQ2dVNHA5Ly90SG9lMmhqWXlQTXpjMUZjZEMzYjEreGFkT21ZcEg5di8vOVR3Qmk5KzdkNGtQbWcxRUFoQkRpcjcvK0VvQ3d0TFFVVzdac1VaV0hoWVdKMHFWTEMwQjg5ZFZYYW1zc2YzOS9vVkFvQ256b2RlclUwWWdDSUlRUXdjSEJBaEI2ZW5waStmTGxxb0g2MUtsVGFwYzlmZnAwWVcxdExUSXpNMVZsMmRuWm9uYnQyaCs5QWhBWUdGaW9BcER6L05XcEFBZ2hSSXNXTFFRZ05tL2UvTktrNis3dUx0TFQwOVVtODYrLy9zcFRQbXJVS0FHSWVmUG01U25mdlh1M0dEaHdvRnJ1Ly83OSs4TEl5RWdBNHNpUkl5STBORlM0dUxpb0ZGSjFrcDJkTGJ5OXZRVWcvUDM5ODF4TFRVMFZWbFpXNHZIangycVRuNXljTEtaTW1WTGdjd2ZFMUtsVE5UNkJWSzVjT1k4eTlxa29BSC8vL2JjQXhObXpaeVVGUUZNK0FEbmhGbDVlWHZqNCtLaktiVzF0K2ZISEgxVm15L1QwZExWVWR2TGt5UmdaR2RHK2ZmdVhybGxiVzJ1czBYTE03VVpHUmd3Y09GQmxpcXBUcDQ3YVphZW5wL1AwNlZQNjl1MUxiR3lzYWk5dzdOaXhramxMQXd3Yk5neUE1Y3VYNXluZnNXTUhYMzc1SmRyYTJrVXU4NXR2dmdIZ2wxOStLYkRQcjEyN05rKzVuNThmdnI2K2Fybi96ejc3akxsejV3SXdaTWdRK3ZUcHc0SUZDN0MxdGRYSW52ZUVDUk9BRitGditiY29hdFNvZ1lPRGc5cms2K3ZyTTNIaXhEeGxJMGFNSUNBZ2dJWU5HNzUwVGQwOGZmcVVpSWlJbDlyaVU2Qmh3NFowN2RxVjQ4ZVBhMFRlNDhlUGFkKytQWFoyZHRTcVZZdXBVNmR5NTg2ZEFqL3I1K2ZIZ3djUFBxNHRBQ0dFT0h2MnJHb0xJRCtSa1pFQ0VJQUlDZ29xY2swcFBqNWVLQlFLVWFWS2xRS3ZkK3pZVVdNV2dJU0VCTlVXZ0tZSkNnb1N4c2JHQWhCbVptWmkwcVJKUlc3cWxTd0FyMTZGdXJpNENFQmN2SGhSVlY2N2RtMFJFaEtpRnBscGFXbkN3c0pDR0JnWWlMaTRPQ0dFRU9ucDZhSkNoUXFpYXRXcUFoQW5UNTRVUWdqeDVNbVRRdCtSb3FScDA2WUNFRjk4OFlWRysxMW1acVp3ZG5ZV2dMaDY5YXFxdkc3ZHV1TGd3WU1hcmN2T25Uc0ZJQ3dzTERSaUFjbmRCdjcrL21MUW9FRWlJQ0NnMkZhdnhXa0J5Tm1TR1RkdW5GaTZkS21JaW9wUzZ6dGZ2MzU5c1duVEpoRVlHQ2oyN05ramV2YnNLWXlNakVUMTZ0WEZraVZMVkZ2ZlY2OWVGWTBhTlJKWldWa2Zud1hnVlpRc1dSSmpZMk1BTWpNemk3eWlJU0VoWkdWbHFlVzNQeVNjblozNTk5OS9hZGl3SVRFeE1VeWZQcDJ5WmN1eWJ0MDZhWG11QVdReUdVT0dEQUZnNmRLbHdBdW5WR3RyYSt6dDdkVWlVMGRIaCs3ZHU1T2NuTXpPblRzQjJMSmxDKzNhdFdQbzBLRUFLc2ZERFJzMjBLZFBIN1czdzhpUkl3SDQrKysvVlE2aG1rQ2hVS2lzWFRObnpnUWdNRENRa0pBUW1qZHZyckY2QkFjSDA3OS9mMlF5R2IvODhvdEdMQ0E1bkRwMWlvVUxGOUt4WTBmYzNOdysyWGN4eHhrMEpDUkVyVmFRb0tBZ21qVnJSbzhlUFNoZnZqd2RPblJnNDhhTlBIbnloTUdEQjdOdjN6NmNuWjNSMTlmbnE2KytZdjc4K1I5T2RFSlJXUUNFRU1MUTBGREk1WExWS3FVb3VYbnpwZ0NFaVluSkoyMEJ5TTJ4WThkVVRsbWFkb2dwRGd2QTdkdTNpOTBDSUlRUWNYRnh3c2pJU09qcDZZbUlpQWpoNitzcmpoNDlxbGFaMTY5ZkY0RDQvUFBQUlhaMnRxaGF0YXA0L3Z5NVNFcEtFcWFtcGtKUFQwOUVSVVdKaWhVckZ1aWdXTlQ5djFLbFNtTENoQWtDRUI0ZUhpSTFOVlZqL1NBMU5WWFkyTmdJdVZ3dTd0eTVJNFlQSHk1bXpKaWgwWlZuamlQd3FGR2ppdTM5bnoxN3RoZzllclRJenM3K0pDMEFGeTllRk0yYU5STVJFUkZxbFpPU2t2S1M0MmQrMHRQVDM2b2VINlFGb0tCUXQ0aUlDSktTa3FoV3JSb21KaVpGWGxFbkp5ZTB0TFNJajQ5bi8vNzluNnpXdTNyMWF0TFMwZ0JvMUtnUlo4K2VaY1NJRVFCczNManhvNzUzSFIwZGdGY2VlS0tKTUV3VEV4TjY5ZXBGYW1vcTgrYk40OHFWS3pSdTNGaXRNcjI4dktoU3BRcW5UcDFpMGFKRlZLdFdEVXRMU3d3TURPamV2VHVwcWFrTUhqd1lEdzhQek16TTFGcVhJVU9HTUh6NGNINzY2U2VhTjIvT3JWdTNtREpsaXNiNmdhNnVMaU5IamlRN081c3BVNmF3ZmZ0Mit2YnRxekg1VTZaTTRlelpzMVNwVXVXbGxlZTllL2MwVm85eDQ4YXhaODhlZnY3NTUwOXVISXlQajZkbHk1WU1IVG9VQ3dzTHRjclMwOU5EVDAvdmxaL1IxdFpXZXozZUd3dUF1N3Y3UzlmV3JGa2pBTEZyMXk2MWFXTHQyN2NYZ0hCMmRoWVBIejVVbGQrOWUxYzRPRGhvM0FKZ1kyT2pjYTEzL1BqeEwybmRPZlZSWndSR2ZnNGVQQ2dBMGE1ZE95SEVDMjlvZFllQUppVWxDYmxjTGd3TURQS0VXMjdac2tXWW1aa1Y2QjJ1TGdJQ0FnUWdaREtaV0x4NHNVWmtMbCsrWEFCQ1cxdGIzTHQzVDFWKzVjb1ZsUlhvNzcvL1Ztc2RObTNhSkh4OGZGVC9IeElTSW95TmpZVkNvUkJuenB6UldQK0xqNDhYSlVxVUVJRG8zTG16UnExdWNybGNHQnNiNTNrR09mejQ0NDhhSFErOHZiMkZwNmZuSjJjQldMbHlwVWJmZDNYeFFTb0FnRmkzYnAycS9ONjllOExPems3MDY5ZFByWTMxNE1FRFZleXp2cjYrYU5teXBXalZxcFh3OGZFUjdkcTEwNWdDRUI0ZUxnQ2hvNk1qRWhJU05LNEFtSnFhNW9rM1BuTGtpTkRXMXRib3k1QmpqamN3TUJDTEZ5OFduVHAxRWsrZlBsVzczQnpuTTFkWFZ6RjgrSER4K2VlZmkrblRwNnUyQUtwVnF5Wm16WnFsa1RabzBxU0pNRFEwRkxHeHNScVJGeE1USS9UMDlFU25UcDFldWxhMWFsWGg3T3lzVm5QdzFhdFhoWTJOallpSmljbFRQbjM2ZEFHSXp6Nzc3S1ZyNm1UaXhJa0NFTWVPSGRPSXZJaUlDR0ZyYXl1QVBHSFFPUVFGQlltV0xWdHFkQ3RDVjFkWEdCb2FmbklLd0xoeDR3UWdWcTVjS1NrQW1sWUFhdGFzS1FZUEhpeGF0V29sR2pkdUxLcFhyeTVXckZpaGtiMm91M2Z2aXRhdFd3c0RBd05oYjI4dlpzeVlJVEl6TXpYbUE3Qno1MDVSdDI1ZGxTSlVzMlpOc1hYSytPY01BQUFnQUVsRVFWVHJWbzBxQURteUsxYXNLTnEzYnk5YXRXb2x6cDgvci9IT08zbnlaR0ZrWkNTOHZMdzBrZ05CaUJjNUo1bzJiU3IwOVBTRW01dWJxdTNyMTY4djJyWnRLLzc4ODArTjdZbnUyN2RQOU8vZlg2TnQ3dVBqVStDelhyMTZ0Wmc1YzZiYTVPN2F0VXRZV0ZnSWhVS1JKOTc5eG8wYmVmeFFQRDA5eGZidDJ6WFNGaGN1WEJEbHlwWFRhTnZuV0dCcTFLaVI1OC9MeTB2bzZPaUlaczJhYWF3K09YNGhMaTR1bjV3Q3NHalJJZ0VJWDE5ZlNRRjRYNXdBaXhOTk9nRktTRWdVUDk5Kys2MllQMy8rSjN2L2h3OGYxdmdXeVB1aUFKdzhlVklBR3JXNGZJd0tnSllVMkNVaElmR2hrWmlZeVBidDI3bCsvZm9uMndhbFNwVUNQczE4K0RuaGo1cE1BUGN4OHA4VWdCeUZSYnlIUjhBSzZWaGFDWW1QbW9NSEQ2S2pvME85ZXZVWVAzNDhYYnQyeGR6Yy9KTnREMjl2Yjd5OXZVbE9UdjdrN2owbEpRV0FuajE3U2krR3BoU0FuTk8zY3AvQzliNFFFeFB6M3RaTlFrTGkzZkQzOTZkMTY5YkFpeFA1eXBjdno2bFRwejdwTnBISlpHemF0SW5PblRzellzUUk3T3pzUHBsN256RmpCdVBIajZkQmd3YlN5L0VPdkZFZWdOVFVWS1pNbWFLS043OTA2Ukw5K3ZYajVNbVR4WDRETjI3Y1lNeVlNYXE2akI4Ly9wUE1qUzBoOFRIajZlbEp0V3JWTURVMXhjZkhoK1BIajZzOTM4R0hZZ1U0ZVBBZzA2Wk5ZKzdjdWFvY0lSOHJKMDZjWVBEZ3dkU3FWVXNhNTR0Q2lSU1M3VnhDUWtMaWd5Y3BLUWxkWFYyMHRENWUxNjc0K0hpMUpKb3J0Z2xZSnBOSkNvQ0VoSVNFaE1TbnRnSXZaZ1ZBTGowQ0NRa0pDUW1KVHc4dGxNNXp4Y2JSbzlKVEtFNlVwOGhKRk5NS1FPci94WXBvMHFSNEs5Qy8vM3ZkUGx0UG5jTG44OC9WSjZDNDIvOFRSN0lBZklTRVJVZGozYThmU3c0ZGtocERRa0xpcmNnV2d2TWFQTnhJUWxJQUpJcUE1M0Z4UEl1TDQ4Ymp4MUpqU0VoSXZCV1BuaituakpXVjFCQWZNVkltd0krUWltWEtVTnJDZ2krclY1Y2E0d1BIV1YrZlFmYjI5TEN4b1pUeU9PUzA3R3dXUEg3TWtzZVBlWnFlRHNBZ2UzdUdPampnYm1oSWVGb2FQNGVITS8zaFExTGY4WGprNHBZUFVNN0FnUDUyZHZTM3Q4ZFlvUUJnVFZnWXN4ODk0a0ZLQ3FaYVdneXdzMk9hc3pOWndMS1FFT1lGQi9OY1dUZUp0eU13TEF5Mzl6UzN3SlhyMTVtNVlBRXV6czdjQ0FnZ01pcUtzMGVPc1BPMzM3aDMvejUvblRoQmpTcFZtUDNERHdBRTNMbkRwaDA3U0VsTjVVWkFBRnZYcnFXVXBlVW4vNHhsSWpxNmVLTUFwRDFRdGZERHI3L3l2NDRkVWNoZlkrU1JmQUNLOXdWOHcvNXZwcTNONFVxVnFHWml3c09VRkp4UG55Yi9penZIeFlYcUppYTB1WHFWaEt5c0lxMW5jY3NIOERReTRsVFZxcGhxYVZIendnWE81MHI2WmFSUUVGQ3JGbTJ2WGVOcVFzSWIvNmJrQTFBNDgvYnZwM1BObXB3TUNHRHBuMzl5OGY1OXRCUUtsbno5TllPKytBS0FQZWZQTTNEdFdzeU5qSmpVc1NOdHFsUmg3YkZqTERod2dDY3hNWlN4dEdUTmdBRTA5ZlltT1MyTlZYLzl4YmNiTjlLOFlrVys3OUNCdXNPR3ZWWGRVbEpUNmRTN056R3hzYXhic29STFY2L2k2dUxDc1pNbitXN1VLR0ppWTdIMzhHRDcrdlUwckZ1WHBoMDZjUExBQVhSMGRLamNvQUh0V3JSZ3l2anh4Zi8rbTVzWGF4U0FaQUg0aU9pNWRDbWIvZjJ4TVRQRHpjNk9qdlBucy8vaVJVd01ERGc4Y1NMVnk1YVZHdWtESlNZamc3WlhyM0sxWmsyYzlQWHBiMmZINnJBdzFmWEt4c1o4WVc1T2cwdVgxREw1RnJkOGdKdUppUXdJREdTN2x4ZXp5cGFsNGFWTHFtdkx5cGRuNU4yNy8ybnl6K0Z1Y2pJL1BYckVMK0hoekhGeFlheWo0MHVmaWMvTXhON2ZuNUk2T2l3cVZ3NFBRME9XaFlheStQRmo2cFlvUVZrREE2NG5KdExSeW9vSlpjb1FrNUhCbnVmUEdYRDdObVgxOWFsYm9nUUJTVWw0R2hreHUyeFp6TFMxMy9zKzl6Z3lrdElXRnZTcVg1OHV0V3ZUNk1jZnVYRC9QaTBxVlZKOXBvR0hCKzcyOXV3Yk53NVRBd01BeHJScFE4Y2FOYWc2WVFLNjJ0bzA4dlFFd0VCWGw2ck96dlNvVzVkTmJ6bng1NkN2cDRlMWxSVVZ2Ynh3ZDNYRjNkV1ZJV1BIQXJCbzVVb0FtalZ1VEd4Y0hMOGRQSWl6a3hNNlNndlc0VjI3ME5mWGx3WVZKQitBajRvdktsUmdScmR1M0YyOEdHOUhSM2FOSHMyUlNaUDR1a0VEU2x0WVNBMzBnZk0wUFoydmI5MTZzVG9yVjQ0eXlrSE1RbHVialo2ZWRMdDVrOWpNekk5V1BzQ09aOC9ZOC93NURjek0rTWJXRm9DdmJXMkp6OHhrei9QbmIvV2I1UXdNK0w1TUdmVGxjcFk4Zmt4R0FhbFIxb1dIa3lrRVRjek5hV2RwU1ZrREE0YmEyd013MWRrWlAzZDNWcFl2ejhTZ0lHWStmSWk1dGphK2RuYlk2T2pRemRxYWRlN3VIS3BVaVQ4aUkrbHk0OFo3MTdkQ29xSkl5OGpJVTVhZG5VMU9tTHFldGpiYlJvekFRRWVISWV2V3ZiQ2VDTUdROWV0WjFhK2ZhdkxQd2NuS2l2V0RCbkVuUEp3RkJ3NEFFSldRd0p4OSsxZ3pZRURScko1bE1uS0gwVDhPRGFWK25UcU1IRFNJa1lNR3NXZmpSbnAyN1Vwd1NFaWVESW1XRmhZWUdScEtBNHFrQUh4a0ZvQjY5ZmkrUXdlUzA5TFkvTTgvckQ1NmxNWmVYaXpvM1J2ckVpV2tCdm9JT0JRVnhlcXdNSXdVQ3Z6YzNkR1d5ZGp1NWNXUER4NFFtSlQwMGNzSEdITDdOakVaR2N4emNhR3h1VG5mMk5veTVoMjkxYlZsTXJwWlcvTTBQWjN0VDUvbXVaWWxCUC9FeE9CdGJJd2lWN2xXdmh3dTFVeE04RFF5WWx1dTcrZitqS21XRmw5YVdYRTBPcHJJZkpOdFlXeFY4M2tIVVFrSmpONndnVGF6WnJIKzc3OWZtbUJ6NDJocHlkeWVQZm5qeWhXMm5qckZyTjkrbzAyVktwUXZ4RStnZmJWcWRLdFRoeWs3ZDNMdnlSTUdybDNML0Y2OTBGZXV4SXNhbTFLbDJMVnZYNTZ5ODVjdVlXdHR6WW5UcC9Nb0FhZlBuNWNHazljcEFJOURReGsxY1NJT25wN0l6TTFWZjZWY1haazRmVHBKdVU2aDJyMS9QNTE2OTFaOXhyTjJiYWJPbWZOQk5rcFdkalpMRGgyaTR0aXhHUGZxaFpXdkw0Mm5UbVgxWDM4UkdCWkd2OVdyMzJ2NU4wTkNpRXhJNE4rZ29BK2l2Wk96c3BnYkhFeXpLMWVRSFQycStqTTZmaHpMa3ljcGVmSWtsYzZmNTl1N2R3bjl5SE9kdnduZjNyMUxVSEl5RGMzTU9GZTlPdGNTRS9uMTJiTlBSdjdUOUhTK3ZYY1BNMjF0OWxlc3lOY0JBYVFYZ2JPaGc1NGVuYXlzbUo4dmVtWnZSQVFkL29NM3ZQRnJVdkhLWlRJTUZZclgvbzRtd3ZDMHRiUVkwN1l0djQwYngvd0RCMGhYV25DZXhzWmlVOEJaQy8yYk5LR3hseGREMXE4bkpDcnF0VGtDbG43ekRjYjYrdFNhTklrTzFhdmpxclRhRk5sWW1XdTdxVnZIanZ5NmJ4L0RKMHpneEtsVGpQL2hCd3owOVduVHZEbHBhV2wwNzkrZmN4Y3ZNbS9aTXVMaTQxWGZpNG1ONWJ1cFU1bTdkQ25WR2pjbU1TbUo1cDA2MGJoOWUyTGo0dWc1Y0NBVjY5VWpORHlja0xBdzZyVnF4Wk5uenpoeDZoUUxWcXlnUmVmT2JOaTJEWUMwdERSbUxWckVqN05uMDd4VEoySmlZMW5wNThmbkxWcXdaUFZxSEwyOTZkNi9QOWxGMEYvVnJnQ1V0cmRuNFl3WkJGMjZ4RmRmZnFrcTc5VzFLek1tVGNJd2w5bW5ZNXMyckY2NDhJV0c3dXZMbFpNbm1UeHUzQWM1K1hlWU81ZHB1M2J4WTVjdVJQbjVFYlo2TldQYXRHSGxrU080anhyRnZTZFAzbXY1bFp5Y0FLaXMvTy83am9GQ3dWaEhSdzVWcklpRmNtOTB1ck16aVEwYkVsRy9QdWVyVmNOU1c1c0ZqeDlUNGR3NUx1VjZlVDlGa3JLeTZIWHJGbGxDVU5uWW1QVzU5dUkvQmZrQVA0ZUhFNUNVaEw1Y2ptcys4L003S1RlT2pseExTT0JvZExTcWJQdlRwM1FyVmVxMTN6MFdIZjNDVDZHUUZmR1R0RFIyUG50R1QydHI5T1d2Tjc1cUlnelBSRjhmV3pNenlsaGFVcy9OalY5T25BQmVIUUV3cDBjUFlwT1NpSGtEaTA5SlkyUEd0MnRIVkVJQ0Njb2pmSXVDUzFldmN1YmZmOW4vNTU5Y3ZuWU5nSVoxNjdKODdsejI3TjlQOS83OThTaGZIaTkzZHl4S2xtVFBwazNjQ0FpZ1RiZHVDQ0ZvMmJUcC8xdTFqaDZsbEtVbFk0Y05ZOVNnUVJnWkd2TFQ1TW5FeE1aU3d0U1VIOGFQSnpvbUJsdHJhM1IwZE9qZnV6ZW1KaWFzMzd5WjBZTUhzM3JoUW9hTUhVdDhRZ0pMMXF5aGZwMDZUQmsvSGxzYkd4YXVYRW16Um8yNGUvOCtyYjc0Z2h1blQrTi85aXk3ZnYvOS9WY0FjdERWMVdYVHFsWFVxMTBiZ0kwN2RoQmJ3TEc3UDh5ZVRkY09IVmcyWnc3YUg0Q1RTNEVEeS9IajdMOTBpZVcrdnJTclZnMGRMUzIwRlFwYVZLckV1Wmt6cWVIaTh0N0xOek0wcEl5bDVSc3JBT3ZDd3FoMzhhSnE1YjNqRFZaenlWbFpXSnc4aWV6b1VUNDdmWnE1d2NHRXZlUHFYQzZUWWErbkI1Qm5oVlRXd0lEZksxYWtySUVCMFJrWnFzbm5VeVl5STBQbGJMZk8zUjI1aGxPS0Y3ZjhUbFpXM0U1S0lqVTdtNVhseTJQMEJpdnFONkdxaVFsMVM1UmdYbkF3QVAvR3gxUFoyQmlkVjB6WXYwVkVNUDNoUTdZOGZjcHZGU3JRSjk4cTkwSjhQQXNlUDJiUy9mdDhWNllNNjl6ZDM2Z3VtZzdEKzc1REIrYnMyMGRtVmhhQm9hRUZ5aFpDc09EQUFZYTNhTUgyMDZmWm44c1JzeUNpRWhJNGZlY09MU3BWWXR6bXpZUkdSYjA4NW0zWlFyMVdyVlRXNHpJVktyQjU1MDdWOWVQKy9qUnUzeDZadVRsMW1qZG43NEVEVktsWWtZQno1N2g1NWd5VksxUlFmWFp3Mzc2RTNycEZXRUFBdmI3NlNsWGVwSDU5N2x5NFFNUzllNHpONTRCWXMycFZwczJiUjk5aHcyaWd0R2hVOHZZbUxTMk5PMEZCWExwMkRYTXpNMDZlUHMzdmh3N1JybVZMcnQrNlJVUmtKTDlzM2NyZi8veEQwNFlOaVlxTzV0akprMXk3ZVpOZnRtNmxsS1VsK25wNjZPam9ZR0pzakxPVEV5Ykd4blJxMjVZTGx5OS9PQW9BZ0phV0Zsdlhyc1dzUkFtZVIwUXdhdUxFUE5lMzc5bkR5ZE9uOFZ1MjdEOVg0dlNkTzNSZnNnUlpseTZZZmYwMUs0OGNVV21YSjI3ZG91M3MyY2k2ZE1GMndBRFdIVHRHWW1xcTJocmtnUExCZUNnZGZIS2pwNjNOa3ErL1Z1c0RLU3I1NWUzc2NMR3hlYVBQK3RyWmNiaHlaWFNWZzl6c1I0OWUrNTMxNGVGRUtmY3haemc3TTliUkVUdGQzWGUrZjBVaEU0bWVYRTV2NWYwRUpDVnhNekh4azUzOGpSUUt0bmw2MHZicVZZS1NrNmxsYXNxWTBxVS9HZmxsRFF3WTV1Q0F6ODJiekh6NEVBYzlQV1lVWVlUTGFFZEhEa2RGY1RNeGtWV2hvUXdvNEYzTVRYdExTeVk1T2VIbjdrN2JBbUxMcTVtWU1McDBhZGE3dXpPaWRPbVhmQWRlcHdCc1BIbVNhdDk5aDZ4TEY3UzdkV1Bsa1NPcXordzVmeDRyWDEvS2p4ekpabjkvNHBLVG1iZC9QN1lEQmlEcjBnV25JVVA0Ni9yMUYwcDdXaG9MRGh4QTFxVUxMV2JPeEQ4d01JODhGeHNicXBVdHk4Wi8vaUhvNlZPY3JhMWZxdE9zMzM2alk0MGFMT2pkbThwT1RneGF1NWE0WEZ2QitaV0ZvWDUrek92Wms5WDkrNU10QklPVURvUzUrYnA3ZDA0ZU9JQnZ6NTRBdUpVclI0OHVYVlRYRzlhdFM0TTZkZWpkclJ2K2YveEJoOWF0aTdRL09UbzRjT1AwYVpKVFVxaGN2NzVxY2V2VHFSUGJkKzhtN01rVFJnd1l3S2FkTzBsSVRNVFl5SWpNekV3TURRM3A0K05ESHg4ZjltN2FoSzIxTlpsWldkU3BVWU0rUGo3OE5Ia3lvd2NQZmttZXVaa1pKc2JHSDVZQ0FHQm5ZOFBTMmJNQitHWHJWZzRwWTVodkJnWXlldUpFZG0vWWdNRmJoRmZVY1hWbGZxOWVBSFN1V1pOQlgzeUJtZEpMczRHSEIzT1ZIYVA3NTUvajI3Z3hSc3BWb2pySU9SeHgzdjc5QlY2dlhyWXNqbXBNSUZGVThxMU1UU254SHp4ZDllVnlTbXByODVtK1BsY1NFamhjZ0thZVE1WVFMSDc4K1ArOXdOWGsxSk9mTXJtZSs1czZVYjJPNkl3TTVnY0hJenQ2bEZaWHJ4YjZ1ZnFYTHFGOTdCanJ3OE9KeTh4azcvUG5sRGwxaXBJblR6SWdNSkJ1TjI1UTVmeDV0ZStGeTRBTkhoNHNEdzNGUHphV3J3TUN5QmFDcWM3T3VHdkFzN200NWV2SjVmaTV1K01iR0VoYWRqYXpnNE1KVEVwaXFMMDlOVXhOaTBSR1d3c0x5aG9ZTU9iZVBRd1ZDa29Xa3pVemR4aWUvOVNwMUNwWERxREFNTHp6TTJmU28yNWRUQTBNR05PbURhZW5UY1BjeUtqUU1MeEQzMzlQWFRlM2wyUk8vUEpMZnRxN2w1VDBkTFR6V1ZXTzM3cEZaRUlDSGFwWFJ5R1hzMjdnUUo3RnhURjIwNllDNno5OXp4NjYxS3FGazVVVkRpVkw4cE9QRHdjdVhTclFzVkVtazdGODdsd3FlSHJ5NTdGakhQZjNWMTBMdUhPSFkvLzh3NXFGQzVITGk5NXZmZGZ2djJOa2FNaTJkZXVvNE9uSlE2WDF4NmRUSjVhdlgwK1ZDaFhvMkxZdCsvNzRnM0xPemdCNGUzaHc4dlJwZnQ2eWhXY1JFYXhZdjU3a2xCVHExNjdONERGanVIZi9QamNEQS9sVjZaU1ltSmlvR3RzRDc5NmxsVEtQd2dlbEFBQjA3OXhacFlIMUh6bVN4NkdoZk5tckY4dm56c1ZGMlRodjlXSXJYektEQWxhUmhzb3lYUTI4aURrdjF5OG5UdEJtOXV3Q1RWYUQxUGp3aWtxK2hiR3hxazMveStBK1Joa0RQZXNWVm9CZm56L0gyOWdZWjZVQ29Dbmo3d1BsSHFJTWlteXlNZGZXNWx0SFI1ejE5VGtVR1VsQUFmdWFseE1TdUJBWFJ4bDlmZnJhMm1LcXBVVUhLeXNhbUpuaFptaklhamMzdG5sNTBkWGFtcTQzYm5BNk5sWnRiVERSeVlubjZlbjhIQjRPd0tuWVdCYUhoS0FybDdQUncrT05WNWNmcXZ5bHJxNnNDZzNsbm5MVm1aNmR6WURBUUdReUdldmMzRjVwcW44Vm1VS1FxUnlnNVRJWkl4d2NPQklWeFZBSGh6eUtiMmF1cmFlY2YyZStZanNxTTk5M0N1TjlDY1B6ZEhEQXEzUnBJdkw1MmR3SkQyZnFybDM4NU9Paktxdms1TVRBcGsxWmUrd1lmMXk1a25kU1BYZU9zT2hvT3VUS1JqcTRXVE84SFIwWjV1ZFg0TGltbzZQRHo4dVdvYVdseFlEUm8wbE5TeU1wT1JuZjRjUDVlZGt5VlJ4L1VaT1FtRWlycmwxWnZtNGRsU3RVb0tLWDE0czJkSFNrWTVzMjFLdGRHeE5qWTdwMjZFQ3pSbzBBTURFMlp1UEtsZnc0Wnc0VjY5YWxsSlVWWmlWSzhPM1FvZGpaMkZDbFlVTyttenFWOXExYUFaQ1duczY4WmN0WXZtNGR0YXRYejdOdDhVRXBBQUNyNXMvSG9tUkpRc1BEOGFwVGgvWXRXeGE1V2FhNDZOZTRzV29TUG5EcEV1VkhqbVR5amgzRTUzSmdxYWxHUDRDaWttOXBZdkpXOG52WjJHQ3RvOE9KbUJqK0xjVFpidTZqUjR3cklGbUtPb2xJVDJlVjB0bXNqNjB0TmtXdzNaREhDbFdpQks2R2hzeFhhdis1V1JFU1FsZHJhL0x2TXVlZjdIcloyQ0NBQTVHUmFtbURkcGFXdExTd1lNVGR1M2tuNWFBZzdpUW5VOFhFaE1tZmZhYTJaMURjOHI5M2NxSzBuaDViODRYcCtjZkc4bnRFQko1R1JzeDlpM2N6S0RtWnhTRWhISXlNVkRuL2ZXMXJTdzhiRzF3TkRFak95bUx6a3ljRUpDVnhMQ2FHZlJFUkJDVW5zeVFrQkFDLzhQQ1hFaEJGWjJTd09peU1KK25wSEl5TTVFZ2hGclgzTVF4dlVzZU91Q20zUFpMVDBwaTZheGZWdnZ1T1o3R3hYSDc0VVBXNXUwK2U4RkNaZTZIYm9rWE0yYmVQZ05CUStxOWVUZGVGQzNrZUY4ZWppQWpWNS84SkNDQWxQWjNveEVTYVRKdFdvQ1dna3JjM1k0WU81ZDc5KzB5Yk81ZkJZOFl3ZXNnUW5OUTQzdmoyN0luL0gzOHd4TmVYbnlaUHp0UHVLK2ZQLy85eFlONjhQTDV0TFpzMjVkRzFhenk1Zlp1T2JkcThXTURxNjdOOS9YcmlIejltLzdadHFud0RKYzNOR1R0c0dFTjhmUm5pNi92ZXpIZHZwUUJZV1ZxcUdpWStJVUhsSFBneG9KREwrVzNzV0w1dDB3YUZYRTVTV2hyVGR1L0dlZWhRbGh3NlJLYWFzcHdWdFh4ekk2TzNrcThybHpOU3VaOWJrQlhnV0hRMFJscGExQ3dpYyt2cnlCQ0NQeUlqcVh2eElrL1MwdWhnWmNVU1YxZTFtTFpIbGk3TmxxZFBlWllyaDN4NFdob0ttVXlWQi85VnhDcFhjRlpxV0tsMExsV0tiVjVlREFnTWZDbmtMU1U3bTJrUEhyeVlqTXVVb1pVYWtqNFZwL3pHNXVZY3IxS0ZHYzdPdUJvYXZoU1MxOG5LaWdySy9qN2N3WUd0bnA1VS9ROEtjRmtEQTVhNnVuS2xSZzJhbUp1L3NEb3FGR3owOEhneHFDc1U5TEN4SWFsaFF4N1dxYU5LQkxURTFSWFJwQWxiUFQycG1HOVAxMXhibXdGMmRtUTFic3lWR2pYNG9tVEpBbVcvajJGNGxaMmM2TmU0c2NvaU83bFRKK0kzYkNCZzRjSThpNDl5TmpZY21EQUJzWE1uY1JzMk1LNWRPOXp0N1ZrellBQlpPM2F3Wjh3WXl1VGFybXpnNGNIZHhZc1JPM2R5ZTlHaVF1cytaZng0WE11V1pkYWlSV2dwRkhScTJ4YUo5MGdCZ0JmK0FBcmxIdEdnYjc4bC9pMVNjTDZ2NkdocE1hOW5UeTdObnEzYVA0dE1TR0RFeno5VGRjS0VQR0Y0RDU4LzU4ZGZmNlhrTjk4ZzY5SUZSZGV1TER4NGtHU2xSL3p0c0RBR3JWMkxyRXNYR2srZHlvSFhlTTMrVi9tRjhTNStFZ1B0N1RIUjB1SzM1OCs1bmM4a1BpYzRXQ09yLzlWaFlUUytmQm56RXlkb2RmVXFOcnE2WEtwUmd6M2UzaTk1ZkNkblpiRTBKQVQzczJkVmtRd0RBd041cUxTYVJHZGtzUGp4WStSSGorSjgralRMUTBJUWhWZy9qQlVLbGlwWGRnQXJRa01aa3NzTVhCaHhtWmw4ZSs4ZTVRME5WUm5xaW9JdlNwYmtTT1hLN1BUeVFsOHVaM1RwMG5qbFUrNmFsU3lKcjNJVktKZkoyT1B0emNyeTVWLzYzSWNvUDBmcGJIanBFcktqUnlsejZoUjc4Mlg4Mi9YOE9VNm5UNnVldmMvTm0xejhRRUpGMzljd3ZPTE1IS3FucTh1MGlSUEp6czdtWm1EZ2V4TXovelprWjJleisvZmZlZnJzMlh1WmZPaXR6Z0o0RmhHQlQ3OSs3UER6bysrd1lZU0doek42NGtUV0xWbnl6aFU2Y3UwYWZaWXZ6enZBRjlPcFhoVWNIVGsyZVRLSHJseGgzT2JOM0F3SjRWcHdNSFVuVCticTNMbFlseWlCazVVVlV6cDNwa3Z0MnRTZU5JbUVsQlE2MTZ5cDhtVW9iMmRINWM4K28zZjkrdnc4ZVBCTFpyMTNsVjhZcjFzWnZBcFRMUzBHMnRreEp6aVlPY0hCK0NuRGxxNG5KaEtlbGtiTFZ3d09HNTg4WVdsSUNCZmo0OUdTeVZqaTZzb2dwVGx4ei9QbkRMeDlHM010TFNZNU9kSGpGVkVLQSt6c0dGbTZOTXRDUWhoMjV3NFg0K01MRGZVeVVDZ1k1dUJBSDF0YkdsKzZ4SVg0ZUJxWW0rT2s5RkV3MTlhbXVZVUZQejk1d3NrcVZUQXRKRkdMdmx6T0lIdDdsb2VHOG4yWk1zaGtNdTRuSitOdFpNVFdRdW9abXByS21IdjNXQnNXUm04YkczWjRlUlZaU0JyQWthaW9RczNIT1J5T2lucWwwK2FITFA5VDR2c09IV2d4Y3liZk5HeElZR2lvU3ZuUFRlNHd2Q1dIRHVIeitlZTBxVktsME4vTUg0YlhxbkpsN0F1eFJyd05iV2ZQeHN6SWlBMURoaFRaYjZhbHBiRmkvWHBhTjJ2R2djT0hXYloyTGNPTEtIMnd4bGZZY2prakJnNWt4TUNCSDRjRklETXprNjdmZk1Qb3dZUHAyS1lOODZkUEIyRDk1czBjT1g3ODNWY2NGU3J3eTVBaGVmNFdLQ01FTk1IRisvZGZLbXRScVJKWDU4N2xSMlZveXJPNE9HYm5Tem5wWm1mSEw0TUhrNVdkelRBL1AxWDVuZkJ3ZmoxN2xqVURCcnpSNVA5ZjVhdkRBZ0V2ek9HNmNqbGJuajVWWmQrYjgrZ1JZeDBkWCtuMDE4dkdCditxVmFtbDNDSm9rV3V3YVdCbWhydWhJZWVyVjMvbDVKK2JvUTRPZExLeUlqRXJpeTQzYnJ6eWVGbGpoWUpmdmIwcG9hWEZ1SHYzaUZlYVUxT3lzeGtVR01oZWIrOUNKLzhjaGpnNGtKU1Z4Yy9oNFd3SUQ2ZlhhMWJ6OW5wNnpITnhvYjJsSlFjakk5L0k0VXRDb2lDS0t3enZYY2pJeWlyeUZmcW9pUk1aK1BYWGJGaXhBa3NMQ3laT244N2owRkNwZzd3UENzQzRLVk93S1ZXS1ljcGpMUHYyNkVIVEJnMEE2RGRpQkFrZmVIeTIzL0hqQlpyV0ZISTVrenQxb25mOStnQUZwdGx0VjYwYWZSbzA0TGNMRjloMitqU0pxYW4wWDcyYTlZTUdvYU9scFJiNU9SYUlVOU9tVWNMUUVKbE1WcWdGNHVqLy9rZnJWNndXY21PanEwdFBHeHZTczdOWkdCeE1TR29xWitMaTZGYkFvUFNTQ1U4dVo1dVhGd1lLQlVQdTNIa3hHUEVpaC91cTh1VmZPd25uWjcyN08yVU5ETGlXa01CSTVlOFZocU9lSG90Y1hRbEpUV1dzTW8zcXdNQkF4amc2cWl3Q3I2S1VqZzQrMXRZc2ZQeVlJOUhSTkgvRDFkTEs4dVV4VkNqb2Mrc1cvMFVGTUZZbzZHVmp3L042OVlocjBJQmZQRHhVZjNzclZDQ2pjV04wNUhKY0RBeVk1dXlNYU5LRTBMcDEyZUhseGJIS2xibGFvd2FEODhXcDF5bFJndDNlM29nbVRiaGFvd2Jidkx6NHQzcDFUbFNwUWlQbEhuZEJmS2F2ejhyeTVkbGJvUUxyM04xWjQrYkcvNXljK1BHenovQXdOS1NHcVNtL2VIZ2dtalRoWkpVcXFucHU4dkRnZHUzYXpIaUhLS0FQaGRPeHNYUzhmaDNaMGFPWW56ekpNYVhUWUhSR0JoT0NnakErZnB6Wmp4NnBsTS8vU25HRjRiMHRBNW8yNWV1R0RZdnM5N2J2MlVOMmRqWmRPM1RBM015TStkT21rWmlVeE9BeFk2VFp1cmdWZ0oyLy9jYmh2LzltN2VMRmVjclhMbDZNa2FFaGowTkQrWGJTSkxWWCtrbE1ERjBYTGtUV3BRdDlWNjRrV3FsMFJDVWs4T1c4ZVZULzdqc3VLRmZTNVVhTVlQU0dEVXphdnAxSjI3ZlQ2TWNmMGZYeDRXYXVmZDdjWkF2QjNuLy9MVlIybTZwVkFWNEt1OGxoVVo4KzJKY3N5VEEvUDdvdldjTC9PblhDNFQrWTNONVdmbEZaSUhJejF0RVJ1VXpHbXJBdy9uZi9Qc01jSE5CK3c5OXcxTk5qcm9zTGYwUkdzdlhwVTJZOWVrUWJTMHZLdjBYNG5vbVdGanU5dk5DVHkxa2RGc2IyMThUYTk3YXhvWTJsSld2Q3d1aDk2eGFPZW5xdjNMWUE4bGdXUnBjdXpmMlVGSnFYTEtteWRtUVZFTTZWS1lRcUk2R0JRc0Z1YjIrT3g4U29IT0xlaElTc0xEWStlY0twMkZpZXBLZlQ1OVl0MVYrSGE5Y1lkZmN1UmdvRjk1S1QrZC85KzJRS3dmYW5UK2w2NHdhTkwxOW0rN05uTEM5ZlBvOFNjRG8ybGdYS2ZQYVQ3dCtuMjQwYjFMbHdnWVNzTEE1WHFrU0ZBcEtRTkRZMzUxeTFhaHlManFiRHRXdjRCZ1RRUHpDUVExRlJESE53d0V4Ym0vTnhjU3hRUmttc0RBMVYxYlBuclZ0VU9IZU9lRFU1eU1wbE12cloyWEd2ZG0yc05aUnpvakJ5bEt2dTF0YWtabVZSVHZrZW1tdHJJd04rcTFDQjhXWEtZS0wxZGlldEYyY1kzcHNTRVIrUFJkKytLTHAyWmNrZmY3RGswQ0cwdTNYRHNtOWZuaFdRSWZaTnVYM3ZIa3ZYckdIUlR6K3B5bnAyN1VxVCt2VTVlT1FJVzNmdGVpOG16VTA3ZG1EdDZvcXhnd01YbGUzKzcrWExXTHE0c0hqVkt0S0xhY3RhclFyQXhTdFhHRHB1SExzMmJIanBLRVZIQndkbVRabnlRaG5ZdUpIOWYvNzVueXVTczgrZlVjQWdrcWJVcG5QaVpHM016TmcwYkJnZURnN0k1WEtWeDN0SlkyTnN6TXc0OVAzM1ZITjJKaXM3bTZsZHVyQ2dkMittZi9VVjM3WnB3KzN3Y0NaMzZvVG5LeHk3ZnRpNWs2ZUZ4SEtmVllaQWRhdFRwOERycGdZR3JCczRrS2lFQko3SHhkRkVHVlA2WDNoYitlOXFnUkRLdnh6S0dSalEzdEtTeEt3c2ZvK01wRjgrcHlTUjc3LzU2VzluUjJOemM0YmN2azFJYWlvK2IyQTl5SmxrOHhzVkt4a2JzMGpwL2Q4dklJQmJyM0dBV2wyK1BPYmEydXg4OW96UnIzQmF6QW5YT2h3VnhiYW5UMG5KenNiVHlBZ2ZhMnQ2S3JjcERrZEY4VWRrSk1HcHFmZ3BFd0h0ZWY2YzR6RXgzRXBNWk52VHB5UmxaZUZpWUlDZnV6dFRIanpnNjRBQXp2Nkh3VEM5a0swRHYvRHdQS3ZKdEh6bTFxVktoOFpPK1hMVjUvOWNoaENzREExRlN5YWpYYjVFVXRZNk91enc4c0l2UEp4ZCtSenNMc2JITStqMmJkWDU5WVhWTXkwN20xVnZhYVp0WjJsSjhPZWZjNjkyYlJhVks4ZWljdVZZNXVyS3d6cDFxR3hzUmFzQUFDQUFTVVJCVkdaaVFyWVFYSWlQcDZ4eXN2MU1YNThGNWNvaG1qUmhrNGVINmp1L2VudHpvR0pGalF5Y3E5emNLS1dyeTZEYnR3RTRHQm1KdWJZMmpWOWhZWGxUaWpNTTcwMHdOVENnVDRNR25KMHhnMUd0V3pQeHl5ODVQbVVLZlJvMG9NUmJuc3NRSEJKQ20yN2RtRGR0R25yNVFuem5UcDBLd0pDeFkzbndCbGxLMVUzUHJsMzViY3NXMHRMVDBWWFdOU1VsaGRrLy9NQ0lnUVBWbHE5QUhieVJtbnJnOEdGNkRSckVsNjFiNDZiTVJwV2ZmcjE2TVh6Q0JMS3pzK2s5ZURDbkRoM0MvUTNEdGM3Y3VjTWFaVmJCZlJjdVVObkppUzlyMU1ETTBKQi9BZ05aZCt6WUMvUFFtVE9VdDdPamErM2FHT25wc2JwL2YrcFBtVUsveG8ycFhyWXMvb0dCMUNoYmxwSzVWamc1SzJhQVlYNSsySnFaTWI1ZHUxZldKeVFxaXNyanh6T3pXemM2MWF5SmtaNGVTV2xwckRweWhFVUhEOUtuUVFONjFLMzd5aGZFek5DUWMvZnVzZjMwYWI0cVJGbFFoL3hGZmZwdzlNWU5odm41c2YzMDZUZTJRR1FKUVd4bUpwSHA2WGxpN01lWEtjT2U1ODhaWkcvL2tuTmJwRkpwaTNpRnhqdkh4WVVxNTg4VDh3YVorN0tGSUZTWjVqbXNnSFRQQSt6c09Ca1R3N2FuVDJsKytUSi9WS3BVcUtlNXJseU9yYTR1TnhNVG1YRHZIcXNLeUhxV3MzSWJZR2YzMGdFdVczSTVZRFVyV1pKYnRXcmx1ZjZsbFJWZkZuQlFTMGNySzBTVEpnREVabWF5TkNTRXNmZnVNY0RPam5ubHloR2RrVUhINjlmcGFXT2pTbTFjR0IydHJMaVVrTUNqVjNodm0ycHBJUU9ldnNFNURDV1VTbUQrenc2d3Q2ZWt0aloreXVRKytkbjkvRG1lci9Eb1Y4aGtESE53WUpIUzZsREQxSlJScFVzVGtaNU9aRVlHbzB1WHBuOWdJTlZNVFBpOFJBbW1QWHpJQmc4UEZqeCt6TXlIRDlrWEVVRTNhMnUwWkRKRzVzb3hzQ0kwVkJWU2VUL1hQdmVEbEJUV2hJVXhxblJwWmdjSDUwa0xQZmcxYVh1TENpT0ZnblZ1YmpTNWZKbFpqeDRSbUpURUw4cXd3WGVsc3BNVEZzb3hMQ2NNYjNLblRpOTlMaWNNTHo5ckJnd29NTmxQVGhqZXU1SVRwUVRRWnZac2JNM01XTjIvUDUrWEwvL2ZGMzRwS2N5WVA1K2xhOWFRa0pqSXh1M2JjWFJ3d0ZhNVdBZ0pDMlBOaGcwdjNxZTRPT3ExYXNYd0FRTVlOM3g0c1U2Y05hdFdaVUNmUGd5Zk1JRjlXN2F3NThBQkZ1ZXlYSHdVQ3NBZmYvM0ZnaFVyT0hieUpBRDdEeC9tZnpObk11bmJiMVdhRDRELzJiTXNXYjFhNVF3U0V4dEw5Y2FONmRtMUs5OE9HVUxaMXlRSHFlM3FTbTFYVjM0cHdKTzBucHNiOWR6YzJEaDA2TXZtT0ZkWHZtbllrSUZyMTNKMituUzJuVDdOOHI1OS8zOWdrc3RWV1FSL3YzaVJYOCtlNWRMczJXaTl3a3ZiV0UrUEszUG1jTy9KRS9aZnVzVFVYYnRJVGtzakpUMGRiMGRITmd3WlF2ZFhUUDdQNCtLWXNHVUxGMmZOb3Zha1NReno4Nk9ScHlkV2J4ZzMvNjd5Y3l3UXpXZk1lR01MeE9ZblQ5Z1hFVUZ5VmhaZkJ3VFF6dEtTZ2ZiMnlJRHFKaVkwTDFtUzRia3NKbjlFUm5Jd01wTHJ5b0gzaHdjUGlFaFBwM09wVXRqbTZoY0NXQkFjekhBSEI1YUVoT0JqYlUyYkF0SVlKMmRsc1R3MGxEK2pvbFRuQzZ4VXJpYnJtcG5SUHRkMzFyaTVjVGsrbmp2SnlWUTZmNTdtSlV2U3RWUXAxV285UjVINE9pQ0FuOTNkK1M0b2lEVmhZWFF1VmFwSVZtZi9oUkphV2d4emNNQkFvV0RSNDhka0M4SE54RVRHT1RvV21EUGVSa2RITlltWWFXblIwc0lDbHpObkN2MzlrdHJhckhaejQybDZPdE55clF3THd0M1FrR25PenB5TGkyTlR2akRTRmlWTGtwaVZ4ZDFDbk1reWhYZ3AwYzBnZTN1YVcxZ2dCMnFhbW5JbWw3VWpJVE9UQ2taR3BHVm44K1BEaDJ4Nzlvem96RXlzZFhWeDFOZkhVVStQSlNFaGVTYjFUQ0ZlU3F3VWtKVEVJNlVpS0FxeEZPVm5neHBQNml4bzI2U2ZuUjNmQlFVUldLdFdrV2JFTE00d3ZQL0M1UWNQaUh5SHVocm82ek5qMGlSbUZMSjE3R0JueDRwNTgxZ3hiOTU3ZCsvVEowNmtYTFZxZE9qWms2MXIxL0loOGtvRm9HWFRwbm1PVFN5TXVyVnFVVGZmQ2tsVHpPN1JBN2VSSTJrMGRTb3JmWDBMM09lT1RreGt3Sm8xcnpYOUE2cHpCeXFXS1VQbi8zaFBtVmxaOUZteGdzVmZmODFucFVxeHJHOWZPaTlZd0pEMTYvbDE5T2czK28xM2tmKzJGb2dlTmphdjlNby9sQ3YzT0VCTEN3dGFXbGl3L0RVYS82eEhqK2hvWlVWYlMwdE94Y1l5NlBadDZwbVp2ZVFFbUhNYzhOZzN5QzlncEZCdyt6V0pweVkvZUVBckN3dXFtcGl3MXMwTnozUG44QTBNNUViTm1rVWFvdmVtOUxXMTVYQlVGSDBEQXFocGFwb252V3h1Y253QWNwaFdpRk5kWFRNenRubDUwZDdTa25WS1A0Zm9RaXdzZld4dEdlM29TTDBTSmVnWEdNam1KMC9JeURkNTJ1dnBGZnI5d2xnWkdxcnl4YkRTMFdGOG1USjVKdTU3eWNra1ptV3g5L2x6VmR5K2w2RWhEY3pNV0JrYStscEhTWDI1bkE1V1ZpOWwvWHRkTzY4UEQwZEhMbWVvdlQwalNwZG04TzNiK0xtN00vN2VQU29ZRytOcWFNaloyRmdHT3poUXJRamlzaTExZExEUzBXSEtnd2ZzZUl2dHZnOGR6OUtsUHhobHBhZ3hOVEZocUs4dmF3cllGdjlRa0gvb0Q4SE0wSkJCWDN5QlFpN0h1NUFKWkppZkgzYm01cTgxL2I4cjR6WnZwa3V0V2xSUTFxTlR6WnAwckZHRFhlZk9zZlBzV1kyMFIyNExSQ2xUVTRiNStmSDhIUnh6M3Biak1URkVwcWZUd2NvS2hVekdPbmQzbnFXbnF6enoxY1craUFqQzB0TG9yelRwbDlIWFoxYlpzanhLU1dHY21tVy9pZ1hseXJIajJUTTgva055bklPRnBCVDJqNG1oOTYxYjNFMU9wcDZaR1ltdmNMNzdKVHljZmdFQnBHWm5VOFBVOUtYSlA4Y0NZL3dPaXRIejlIUXU1T3RqMmZDU1UyQTJrSmlWVmVqazcybGt4S3l5WlpudDRvSi8xYXFZdjhGWkZpTkxsMlpXMmJLc2NuTmpxbEpoeWhTQ2YrUGpLYTJuaDVGQ3djRGJ0N21Ra01EVDlIUXFHaGx4TkRxYVNVRkJSTCtscDM3dXZtYXZxOHRxTnpkMlBudkd2bHo3N1orTUFxQjBXdndVaVk2SklTMDlIU3RMUzJia1Noa3NLUUFhUmxkYnU5RHp5SCs3Y0lGZDU4N3h5NUFoZVV6L1QySmlpclFPeXc4ZjVuRmtKSDJVSVpFNUxPdmJGMjJGZ29GcjFxZ2NkdFJGUVJhSXlJUUVocXhmcjlIbmNTYzVtYWtQSHZCVHJpTmFLeGtiTTlEZW5yVmhZZnlocGx6NTUrTGkrRDRvaU9YNWZFK0dPRGhRd2RpWWxhR2hMMldSMHdRQzJCQWV6ZzR2TC9yY3VrWGNHMDQ4NStMaUN0My9UOC9PcHRldFc1UTNNT0NIMTJ5eDNVOUpZWXpTRDZHZ2xMUm40dUl3MDlaV25lNzRObXd2Z2xNUWJ5WW1NaUVvaVBIMzd0SDh5cFZYNW56SVlkSGp4MHdJQ21KZ1lLQXFnMk8yRUFRcnR3NzJLQzBRdDVSSnJCNm1wbkkyTG83MTRlRWt2MFBVd29PVUZQNk1pbUtRdlQzdExTM3BhR1hGNE51M2lYMUhwZUpEbzZ5MWRaNTB2NThTUHkxY3lQZ1JJMWcyWnc0TFY2emdYZ0U1WENRRlFBTmtDMEYyQVN1YnFJUUVCaFpnK285T1RPVG9qUnRGSXZ1ZndFQmF6SnpKMFBYckNZdU81bnl1VldaNlppYTd6cDBqV3doaWtwSm84TU1QTEQxMHFNQzZmZ3dXaU9Tc0xLWStlRUMxOCtkNWxwN081Vno3eG5lVGsxV3BlYnZkdk1tYzRPQjNHb0R6RDhZREF3T3BlL0VpejlQVE9aUXZ4T2xBUklUS3hOMzk1azJtUEhqQWt6ZHdtaXNxbG9XRTBNUEdoaSt0ckdobFljSEFmT2V3djQ2ZWhXelBYRXRJNEljSER4am42UGphc3hsV2hZWnlPQ3FLOWU3dUttZkFIQlkvZmt5V0VJd3NaR3VpbEk0T1RkL0FmOEpaWDUvYVJYUkdSR1JHQmlmK281S2VPNEloNStoVmtVOFJFMFh3N3NWbVpqTHE3dDA4Qnc4dEsxK2UrTXhNaGlpakFqNFZMSXlOQ3cySi9wangyN0tGbGsyYllteGtSSzFxMWVqY3ZqMUR4NDM3NE81RDYwTi9FRGREUXZqcituVUNRa001Zk8wYXpYSWRzemg2NDBhaUV4TkpTRWxoMHZidHFrbjV3S1ZMTEMraUU1bHluQlFMUWtkTGk2SE5tek8wZVhPMXQwT09CV0pCNzk0dldTQit2M2lSZ1d2V1VNM1pHYWNDUE5lTENnT0Znc21mZlZiZ2lYRGxEQXpVRnFMMW1iNCtxOXpjQ3ZYMGIyTnBXYUR6b2JwNWtwYkdUNDhlOFR3OVhaVXJ2NG01T1Iydlg4ZEdWNWZ2blp4VW45V1d5UXJNc2REVTNEeFA3THVPWEk1ZXJpTnY1d1FIMDliU2ttMmVubFMvY0VFVmthR3IvRXp1ei9ZTkNPQm1yVnBzOFBEZ3krdlhWVGtNcmlRa01QTHVYUmFYSzBka1JnYnpnNE5KVWE2K3l4a1kwTTNhbXFuSzNBWTVkZFRPZCt5dXRrekdYQmNYdnJwNVU3V3kwTTEzUHdXVnZZcWc1R1E4all6eWVQbS83dk01UjBYSHFXa2x2dm5KRXlZL2VJQ2hRc0hEbEJSVkZNcXR4RVIwNVhLMlBuMktrVUxCaERKbDNpangxSWVPaVlIQk81MDc4cUdSbkpMQ3ZLVkxtYjk4T1g4cnM3R21wS1ppb0svUGtlUEhHZkhkZDB3ZU81YVNHblk0Zmx0a0lqcTZlSE9YS3NQL0pON2VBdkhUM3IzOGVmVXFOVjFjV05TbkR6V1VLNVAwekV6V0hEM0t5RjkrSVNzN205SVdGb3hwMDRZaHpadi8vNWJKbWpWU0l4Ym5BSHI4T0Y5Wld6UEh4UVZUTFMxMlAzOU9rdEl5VWxKYm15L016YWx3L2p4WlF0REh4b2J2blp3SVNVMWxRbEFRdno1N1JvWVF1QmdZY0xWR0RaNmxwN01zSklUTENRbU1LRjJhOXBhVy9CMGR6VStQSHFtT3VlMXViYzFtVDAvOFkyTlovUGd4dTNPdG1odWFtVEcyVEJuY0RRMEpUa2toTEMyTmYrUGpXUklTUXJZUTFEUTFaWFRwMG5RdVZZcTd5Y21xUEFmYU1obFZUVXk0a3BEQVZ6ZHUwTnJDZ3ArVjBReURiOS9tMTJmUHFHaHN6TXJ5LzhmZVdZZEhkWFJoL0xlNzJiaHQzSVVZSklRUVhJcFRxcmdWV3V6RHJVaWhVS3hJVzZCSTBRTEZ2VkNjQW9YaVVnb1VqUkNpeE4xZE52djlzV0ZoU1FJaEJJTHMreng1a3R3N2QyYnUzSHZubkhublNFMmFHQmd3UFNTRUplSGhTckVLZHRXdWpZWlFTUGQ3OXhUSDlFUWl2blZ3WUdaSUNIb2lFUmx0Mm1CMTZSS3grZm00YW12em9Ga3o2dno3THo1UEtBakRyYTI1bUpaR1psRVJrUzFhb0huMnJLS2RyeXd0R1cxalE5TWJOeDZ6QWlVdW05V0drb2lxYi9QOFk2cXZYMjdpb3VlaXVzZS91Z1d3a1pHZ1d0dFhLUUR2T1ZRS1FQVk9BS3IzbjI0bEtaNDFoVUoyeE1aU0pKT2hMaFR5cVlrSk00S0QrVDArbnE5dGJWbnU1c2Iwa0JBT0pDUXd4c2FHMGJhMm5FaE94ajhyQzRGQWdJMkdCcDY2dXRTOWRvMFpqbzdNZEhSa2RtZ29DeDQreEZnc1pwV2JHeDhaRy9PVm41L0NGa1NsQUx3Y3JnY0hZNnF2WDNsbVVhVUFxQlFBRlZRS2dFb0JVS0U2b0ZJQVhnNjN3c0l3TnpEQXVyS1V0MG9CcUZZRlFDMVZVcjBEY0xxbmFoS3FWdm12R3Y5cW5nRlVRMUNkK1BEdmFwYi9iL2o0WE41MW1RLzZQaXUxdUNNdlkvdmVYdlVLVml1RXFpRjQ5NUFTbmNKUWk2R2NXSEZDTlJncXFLQkNwU0FybGhGMExVZzFFQ29GUUlXM0Nla0o2YVRIcHhQaEU2RWFEQlZVVUtGU1NIaVlnSm1EbVdvZzNtR29xWWJnM1lORFhRZE03RXhvMUsyUmFqRGVja2hhU2FqeGZRMGtiVXIyNm1RUXRTNkttQTB4Wk56TVVDNDN1d2FTMWhKa1JUS2kxa1FSc1R5QzNKRGN0N3A5QU1NUERISDUyUVdEcHZJWUE2bm5VM200NENISkp4L0hlN0FhYUlYTEloZkVKbUxpZHNZUk5qK01iTDlzMVF2MEVvaStINDExTGVzM3NtLzNidDlqNlU5TGNYSnh3dC9IbitTa1pFNWRQY1dodlljSUNRcmgvTi9ucWQrNFByTVh6Z2JnZ2Y4RDltemZRMTV1SHY0Ky9xemZ0UjVUYzlQMy9obXJHSUIzRUFLQmdEYUQydURWd1VzMUdHODVVaStrY3JQZFRlSjJ5V1BpRjZVWDhXRE1BeVhoKzZoYzhQUmdpdk9MdWRYK0ZnKytmbEFsd3JlNjJ3ZEl1NXpHemRZM3lid2pEeXdWdHpOT1NmZ0R4R3lKSWUxS0dzSFRndkg5eWxjbC9LdElBVEIzTXVlUE9YL1FWNk12dlFTOVdQTy9OY1FGUDg3UEVIZzFrQW51RXhoZ01JQ2pTNDRTRnhMSHF2NnI2Q1hvUlM5Qkw0NHVQa3BPK3VPa1Q1ZDNYYWFmVGovRzF4elB0UU9WejhYZ1d0T1YzSnhjTHArL3pPeUZzeGs4YWpDM3J0OGlMQ1NNYjZaL3cvYUQyMW0vYWoxL0hmMkw3S3hzeGc0ZXk5UTVVL2xwMlUra3BhYXhhZTBtMVFOV01RRHZGbGIyVzhtbEhaZVFXRXF3cm1YTmt1NUwrTy9vZjJqcmF6UDk1SFNjR3ptckJ1bHRoQXdDUmdaZzJNSVFUVnROYkViWUVMazZzbFF4cS81V2hNd01JZlZDNnJ2VlBsQmNVSXovLy94cGRLTVI5dC9hRTdzdGx1S0N4M0VFTk8wMUVSdUpDVjhZL3NKMTV3VG04SEQrUTJLMnhPRHlzd3YyazB2bkZDbktLT0tTelNYVWpkVnhYZWFLam9jT1VhdmtMSWRoQzBPMG5iWEp1cGVGV1hjekhLWTZVSmhhU01LQkJBS0dCNkRscklWaEMwT3kvYlBScmEyTDgwSm54Qkx4Ry8vYUpVVWtZZUZzUWMvdmU2SnRvTTNXQ1Z0eGJlcUtoYlBGWTBIYzFCVmJEMXRHYkJpQld6TjVDTzR4MjhhUW01SExqY00zYU5DcEFkb0dqeU1GTnUzWmxLTkxqakx6NzVub0d1bFd1bSthV3BxWVdaamhXZGNUTjNjMzNOemRtRHg2TWdCcmxxMEJvTjFIN1VoUFMrZllvV000T2ptaVhoSlFhOS9KZldpOUIwR2FWQXpBZXdhdkRsNzArYkVQeXdPWFkxL0hub243SmpMajFBeGFEMnFOaVoySmFvRGVZaFJsRkhGL3FEeUVzUE44WnpSdGxhT3Y2VGZTUjdldUxoRkxJOTdKOWdFeWIyY1N1U0lTYlJkdDdMOVZGdEt1UzF3Sm5CQ0lyUGpGdlpxMVhiVnhtT2FBVUV0SXhJb0laSVdsNjRqWkVJT3NTSVpSZXlOTU81dWk3YXlOelJnYkFKem1PdUcreVoyYWEyb1NQRDJZc0ovQ0VCdUpzUjVpamJxbE9oWjlMSERmNEk3M0NXK1NqaWZoMDh2bmpYdS9raU9US2N4WHpnaFpYRnlzeUs3NjZkZWY0dHpJbWIyejk1S2I4WmpaQ2IwWmlyR05zVUw0UDhLUVg0ZWdwYS9GdG0rMktSMy9hL1ZmZEovUi9hV0UveU1JQkFLbDdLOVJFVkUwYjlXY2tlTkhNbkw4U0xZZDJFYnZmcjJKREk4ay80blEzeWFtSnVqbzZxZ21GWlVDOEc2aFpiK1dkSjNXbGZ5Y2ZDN3V1TWpwZGFmeGJPZkpnS1VETUxRd1ZBM1FXNDdrazhuRWJJNUJwQ2VpMXJySFlZOEZZZ0cxMXRRaVlIZ0FNcW5zblcwZklHUldDSG1SZVRoT2QwVExTYjZLTS83RW1JS0VnbExiRWk4a1RNUUNMUHBZVUJCWFFOenZ5aW1JWlZJWnFSZFQwYXVqQjA4a1RSU29LZnR3NmpmVVI3ZTJMbkc3NDhvc28yYWdobGszTTFKT3AxQ1lWTEgweTVkM1hYNmw0NW1abk1uV2lWdFowSEVCWnplZUxTVmdGWDhMQlF4ZlA1eU1oQXgyVGRzbEg1ZGlHZnZuN2FmWG5GNmw2cFZZU2VnN3Z5ODMvN3pKdi92K0JTQTFKcFhnYThFMDZ2cHFiSlBNTGMwNXZPK3cwckdiMTI1aVlXWEJsZk5YbEpTQWExZXVxU2FVNXlrQWw4NWRva3U3TGhnSmpCUS9McVl1L0RUeko2SWpvNVhLaG9XRU1YSEVSSXlGeGhnSmpMRFR0MlBXNUZuRXhjUlZ1bk94Z2JFYytQRUE0MnVPVit3cERiY2F6czZwT3duNTc3SDM2WTNETjlneWZvdGluNnFYb0JkejJzemg2T0tqNU9lOGVOS1hZbWt4SjFhY1lITGR5ZlRYNjg4UXN5SE1iVGVYdjlmOVRmVDlhTllOWGZkS0g4ckx0aC9wRzBsbVVpYkIxNFBmaXBkUW1pTWxmRkU0dHorNnpXbkJhY1hQT2QxelhEQzl3QVhqQzF6enZrYmdONEhrUitXLzF4OXM0SVJBOHFQek1mN0VHTXYrOGlSQkRsTWRTUG9yaWN5N21lOTgrOUlzS1EvR1BrQ29LYVRtcXBvSU5ZWFVtRldEa09rdm40bE4wMVlUc3g1bVJDeFJaakVTRHlaaTFyWGkxdkJxZXMvZVdSVUlCWWgwbnA5KytYVzQ0YW1KMWVnMHFSUGZIdnFXUDVmOFNWR0JQSWRDV2x3YUVrdmxJREgyZGV6NWZPTG5uRnB6aXFCclFaeGFlNHJtZlpxanBWODJuZDVoUkFkY203cXkrZXZONUdia3NtdmFMdnI4MUtkcTM0Y25Fb3AxNzlPZHczOGNadXJYVStXMkFWTm1vNld0eGNjZFB5WS9QNTloWHc3anYzLy9ZOVhpVldTa1AxWVcwMUxUbVB2ZFhGWXVXa203aHUzSXpzcW14OGM5Nk5LdUMrbHA2WXpvTjRLV2RWc1NFeFZEZEdRMG43WDhqUGpZZUM2ZnY4eXZTMytsNXljOTJiMTFOd0Q1K2Zrc1c3Q01oWE1XMHVQakhuSjdneldiK09TRFQxaTNZaDExN09zdzdNdGhGRmNnMDJXMUt3QXQyclRnMEpsRGpKMDhWbkZzOEtqQlRKczNEV3RiWmV0UVJ5ZEhscTVkU29NbURiQzF0K1hjelhQTVhUUVhDeXVMU25mTzB0V1NidE83TVdIdkJNV3hZZXVHOGVXQ0wzRnE0S1E0MXJCelF3WXVHOGluNHo0RlFNOUVqeG1uWnRCeFVrYzB0RFZlV1BndTZycUlmZlAyMFd0T0x6WWxiMkpkOURvNlR1cklxVFdubU9BK2dkaWcyRmNxL0YrMmZVZHZlWklaeDNxT2I0VlFFMm1Mc0o5c1Q5MFRkUkdieVBkR25YNXdvazFXRzFvbHRxTGh0WWFJVGNWRUxJM2dYNjkvWDJxbDk3YWpLTDJJKzhQbFZMenJMNjVJV2trdzcyRk8yTHl3OTZKOWdNVERpU1FlU3NUNFkyTzgvL0ltZWtNMGhhbUZWVkszL1RmMlpON05KT1YwaXVKWTNPOXhtUGN4Zis2MUtXZFN5UExOd25wNDJaYnorYkg1eE8rTng2S2ZCVUt0NTVPdnI4TU5UMHRmQzRtVkJGTUhVMnExck1YNUxlZUI4ajBBZXM3dWlabURHV3YrdHdiL0MvNDA2OTNzbVlyTzhOK0drNUdVd1UrZi9vU1ZteFZtamxWelAzZHUzdUg2UDlmNTYraGYzTDExVnlHdkZxMWV4TkVEUnhuMjVUQnFldFRFM2RNZFl4Tmp0aC9ZanIrUFAzMDY5a0Vtay9IaHB4OHE2anA5NGpTbTVxYU1uVHlXa1JOR29xT3J3Nno1czBoTFRjUEEwSUFwczZlUW1wS0toWlVGNnVycURCZzJBSDBEZlhaczNNR29pYVA0WmQwdlRCNDltY3lNVEg1YjhSdk5XelZueXZkVHNMU3laTTB2YTJqN1VWdENBa1BvOEZrSHJ2aGM0ZXFscXh6WmQrVE5Wd0FlWWVaUE02bmpYUWVBZzNzUFVsUk9wcTNVbEZTQ0FvTFl0R2NUVGk1T1ZkWkpJMnVqTXY5K0dvOW9ib21sQkpGWVZLbTJ6bTAreDgyak54bXllZ2dOT3pkRVRWME5rVmlFOXlmZS9QVHZUN2cwZG5tbEQ2UXEydGVSNkdEcVlGcGhCU0I2UXpUL3RmeFBzZktPMy9QODNPN1NIQ2tYVEM1d1duQ2FLeld1RUw0b25Qem9sMXVkQzRRQ05HM2tlOHRQcnBDMG5iV3BlNlF1MnM3YUZLWVU0dGZmNzVWVHpXOHlrbzRsRWJzOUZyR1JtSHAvMXlOZ1RBREZlY1h2VGZzQUFXTURrQlhKMExUUkpHWlRUSlhWcTk5QUg4TVdob1F2bGhzVFpselBRSytlSGtMMThxZkt4RU9KaFAwUVJ0ek9PTHdPZVdFMTBFcnBmTWFORENLV1JoQXlJd1NIN3h4dzMrQmVzZS95TmJ2aGRaM1dsY00vSDBaYUpDWHFmbFNaYmF0cnFkTnJiaStpL0tQb01MTERjK3UwclcxTDZ3R3RDYjRlVEtkSm5Vb3JSZm41L0RqalI2eTByVEFTR0dHcFpjbmlIeGFUbXBLcXhDNFAvbUl3UmdJamF0dldadjJxOWRTdFg1ZC8vZi9sSDk5LzhLcm5wYlJBOVl2eXd6L2FueS82ZjZFNDNxcDlLMjQ4dUVGUVlwRFNnaGFnUVpNR0xKNjNtTEdEeC9KQmEzblV3enJlZGNqUHp5ZjRRVEIzYjk1RllpVGh5b1VybkRoeWdrODdmNHJmUFQrU0VwUFl0V1VYRjg5ZXBNMkhiVWhKVHVIQ21RdjQzdlZsMTVaZG1KcWJvcW1saWJxNk9ucjZlamc2T2FLbnIwZW5IcDI0ZGVQVzI2TUFxS21wc1hMVFN0VFUxQWdLQ0dMMWt0VmxscHMvYXo1OUIvV2xmdVA2VmR0SmtWQkpTRHhMZ0R5dnpQTnc2MC81ZzdIeHNDbDFUcXdwWnRDS1FhLzBnVlJWKzlZMXJiRjBzYXhZMlNIVzFEdFpENkdHZkp3ZkxuejQzR3RpTnNaUW1DeGZkVG45NklUOVpIczByRFZlK3Y0Rm9yS2ZuVkJUaU9VQStmMWsrMmVUNVp2Ris0eEhLKzc4bUh6U0xxVzlkKzNuUitWVG5GOU1ZVm9oVkxFdWFEL1JudVNUeVdUNVpoRzFOZ3FiNFRiUExHL2F4UlRIR1k2NGIzTEh0Rk5wMzNMOWh2cllUYlREZmFNN2R1UHNTdGtPUEVzQmVKMXVlSll1bGpnM2RPYml0b3ZFQmNkaDRWUTJlNnRuckNkWEJqVFZLM1FmdXNhNkNJWENNaGRsR2hvYVRQOWhPbXUyeWkzM1RVeE5tRGh0SWhJamlSSzdQSDdxZUt4dHJUbDM4eHhEeHd5dDB1ZHRhMi9MRlo4cjVPYmswcXBlSzlMVDVGa3VlL1R0d2Y3Zjl4TWJIY3Z3Y2NQWnUzMHZXWmxaNk9ycFVsUlVoSTZPRG4wSDlxWHZ3TDVzUDdnZEN5c0xwRVZTR2pkdlROK0JmWmsxZnhhakpvNHExWjdFU0lLZXZ0N2Jvd0FBZU5iMVpOeVVjUUFzbkxPUTBPQlFwZk0zcjkzazcrTi9NMjN1dExkNllwV1Y1RWcvdXZob21lZWRHemxqYW0vNnhyZHZZR2FBam1IRkxWMkZXa0xFeG1LMGFtaVJlVHV6bEorMVVoK2xNaUtXUjZEbElOLzdVemRSZnkzUFJ0UGhzZVY1Ulkyb25vZkNsRUxDbDRSelduQ2FPNS9kS2JmY3pWWTNPU00rUTh6R0dJclNpMGc0bU1CbGg4dGNNTDdBL2VIMzhlbmp3N1g2MTRqL0kvNzF2S2VGMWN1QVZIZjdyeEltblV6UWR0WW1hRklRSWgwUll1UHFjZGw3MGczdnk0VmZBcFRyaGpmdHhEUTZmdE1SQ3ljTHhtd2JROFBPRGVXcjJ6TGM4S3hxV3ZIRFB6L1F1RnZqVW0xMm05Nk5nL01QVXBCYlVHa1d0VExvM0xNekhidDFKRG95V3JHZi9pUTJyOTNNNGw4WFkycFc5WFB2a1gxSDBOSFZZY1B1RGRUMnFrMTRXTGhDQWRpNGVpTmU5YjNvMUwwVHh3OGZ4OGxWem14NzFQSGd5b1VyN055OGs4VDRSRGIrdXBIY25GeWF0V3JHcEZHVENBa0s0Yjd2ZlE3L0lUZEt6TXJLVXN6dGdmY0Q2ZkJaaHpmaVhYOGhMNEJKTXlmaFdzdVZ2Tnc4eGc4ZHI3aWh3c0pDeGcwZHg4S1ZDOUhXMFg2clAzN3ZUN3dCT0wvbFBBczdMaVE1cXJRZ3JBajFWZDN0NjVub0lkWjh3WWxMQVBhVDVPNVZEeGVVendJay9KR0FYaDA5aFJYMjYwcG9reHVhcTJoUHg3MXEzSGpFUm1Mc3Y3Rkh5MG1McEJOSlpQdVhEaUNUZVN1VDlCdnBhRGxvWVRYWVNtN04zZFVNU1dzSk9yVjBxTFd1RnA2N1BiSG9iWUZQYngvU3JxU2h3bHVtK0JmSmtCWEpGQXlpN1RoYmtrOGxZenZHVmtueGZWVG0wVFZQL241ZXZjL0NtK0tHWjF2YkZqdFBPeklTeTdlemVXUW8rSFIvbjFXK3FMQklJUy9LdzRJVkM5RFYwMlhPbERsS1d3QjNiOTBsS1NHSmp6Ny82SlU4KzZ6TUxIcC8xcHNOcXpmZ1ZjOEx6N3FlY2liSTBaNk8zVHZTckdVejlQVDE2TnE3SzIwL2FpdWZYL1gxV0xOdERUL1ArWmtXZFZ0Z1ptNkdvY1NRTWQrTXdkTGFramIxMnpEM3U3bDgxdVV6QUFyeUMxaTFlQlViVm0rZ1ViTkdTdHNXYjQwQ29LR2h3Y3FOS3hFS2hWdytmNWtkRzNjQXNITFJTbHhydWI0eFdzM0xvTjNRZGdvaGZQUFBtNHl2T1o0OXMvWW9mWFF1VFZ6ZStQYjFUZlVyMWI1bGYwdlVMZFJKUFo5S3h2V3lKNEdIaXg2VzhzTisxU2hJTENCNnJkenp4R3FnRlJxV0dsVmF2MkZ6UTNUY2RBaGZVanFRVE9TdmtWajB0bEJ5QVlQU2JtQ1cvUzFCQmtsL0pyMzZBUkh3V3BXdk42MTlnVmlBVUV1SW1zSEx4ekxMQ2M0aGNua2tTY2VTRk1aL1ZvT3NzUHpLRW0wM2JhUTVVbUozeEpMdG4wM3FtVlFTRHlmS3Ixa2hENFlVc3lsR0VhWHdTV1lwZWwwMEJiRUZKQjFMSXZsVTJZemFtK2lHMTMxR2QyeHFsYjN0NFh2V2w3OVcvUVhBc1dYSENMZ2NVTDd5VXl6ajhxN0xYRDk0SFZteGpOOW4vUDVNQTJaTGEwdW16WnRHVW1JU2M2Yk9VVENpc3liTjRvZWxQN3l5ZDZuZmtINGN2M1NjSWFPSE1HditMS1Z4WDdKbWllTHZ4Yjh1Uml4K3ZLajY4Tk1QdWZ2d0xnR3hBWFRzM2hFQUxXMHROdjYra1lpTUNIWWYzYTJJTjJCa2JNVFl5V01aTW5vSUNXS1JKd0FBSUFCSlJFRlVRMFlQZVdQazNRdC9QUTJiTm1UNDE4TlpzMndOc3liUHd0bk5tZDlXL3NiRjJ4ZGZTNGNYZFYyRVdLUHNsVzEyNnN1SC94U0toRXcrTkpuZDAzWnpiTmt4OHJQejJUOXZQNmZXbktMSHpCNTBHTlVCa2Rxcm84YXFxdjNLQnRvUWFnaXhHMjlIOE5SZ0hpNTRTSjBEZFpUT3A1eEpRVTFYRFlNbUJxOW5aVllvSS9udlpBSW5CcElmbTQ5WlZ6UGNWcmk5RW9GbU45Nk9CK01lNFB5VE0rcm04bTJOL0poOEJDS0J3anZoV1NoTWs2K0kxTTFlL1piSW8vNklqY1FJUklMWGJoUlpuZTBidFRYQ29wOEZBcUVBYldkdG5INXdJdUZBQXBtM0t1ZUdxTzJzamR0SzVYZEtwQ1BDWTV1SC9HOXRFWlpmV1dMNWxiSk5qZHNLdDNMZlJiR1JHT3ZoMXVWNkJDZ200QkkzdkUrLy9wUzU3ZWJTYmtnNzFOVFZudW1HZDJUeEVWcjJhMG5vemREbnV1RmQybkdKelY5dnhxdURWNFhkOEJ6ck9hSm5VdlllZGUyMnRhbmR0bmJGUGltaGdBLzZmdkNjZE1MS0dEWjJHSC9zK0lQdEc3Yno1YUF2Q2ZBTDRJTTJIMkRuWUtlaXFhcWJBWGlFR1QvT3dON1JudlMwZERxMzdjelUyVk14czNnOVdhTW1INXpNc29CbFpmNTArYTVMMVdoRjZtcjBXOXlQaFRjWEtsNzJ6S1JNTm8vYnpOUUdVNVcwMk9EcndjeHROMWRoZExOMnlGb2kvUjZIU2MzTnlHWFB6RDMwRXZSaWxQMG96cXcvVTZYdGx3ZE5YYzFLMzcvTkNCdlU5TlZJT0pSQWRvQ3lVaFgrYy9ocldmMUhyNHZtVnJ0Ym5EYzZ6NTNQN3FCaHFVSGptNDJwYzZBT0lsMWxCU2cvS3AvN0krNHJ2QmorYS9rZktYK25LSldKMlJ6RGVZUHpuTlUrUytqY1VBcFRDc3RrUDBSNklpSlhQbjUrVWI5R1lUdmE5dmswWjNvUlFkOEVvVk5UQjZ2L1diMnljUkhwaXJBZFkwdk4xVFVWLzlmZVVSdUx2aGF2NWZ1cjd2WUJVczZtNEQvSVgvRzhRMmFFVkZyNFZ6ZmVWRGU4Nm9vY0toUUtXYnB1S1VLaGtIRkR4N0Y5NDNhKy92YnJ0MWJBRmhjWGMyVC9FZUxqNHQvSTRFT1ZVZ0MwdExYNGJ1NTNDZzEyd0xBQjc2UjJaTzlsejZ3enMvanUrSGZZMXBZTGdmQzc0Y3hxTVl1ME9QaytyM01qWjZhZm5LNXd6MnZVdFJHMkhyWktIL2luNHovRnlOcUkrVGZtMDI1b3V5cHR2enk4aU5aZFNnRXhVTU42aERYSTVBTC9FYkx1WlpFZms0L0pwMlZQRHNYNXhZVE9DZVdzeGxsT0MwN2ovejkvY29JZld5Q25YMDNucXZ0VnpodWNKM3hKdUZJczk2ZGhQZHlhZW1mcTRUeGZucjhnNDcrTVVvTC9FVFJzTktpMXRoWjJFK1dyQklQR0JoaDlxT3d1YWpYSUNxMGFXbmovNVUyTldUVVFHNVZlMFF1MWhOaU10Q0ZxVFJUU0hDbkZ1Y1hraE9TZ1c2ZDhOaVV2S28rZ1NVRmN0cnVNbHBNV2pXNDBxaEphdWp4SXM2UkVyb3JrZXFQckNnSG8wOGRIa2F6blZhTzYyMytYVVIxdWVDK0xoWjBXc25yQTZpcXQwNnVlRi8yRzlDUEFMNERCb3dham9hSHgxajVUb1ZESWlIRWppTXFLb25Ienh1K0dBZ0JnWUdpZ3VNRW45MHplZGp3WllmQVJ2RC94WnRHZFJZcTl0dlQ0ZEE0dmZCeHlVcVFtWXRTV1VZZzF4T3ljdWhOcG9WVHArZ00vSG1EdzZzRVltQmxVZWZ1dmdvRUFPUjB1MUJBU3R6Tk9FWDN2NGM4UDVZbFN5bm5jUWcwaE5iNnZnZk5DdWRBMmFHcUF0dk5qbzFDRHBnYm9lT2pnZmNJYisyL3NuK2xiclpqQXh0aGkxc01NYVpZVW4xNCt6L1EzZC83UkdXMDNiU0pYUno0MkdDeEI0cEZFSkcwa1NGcEtudDNlYUZ1azJWSmlOc2NRc3pVR3EvN1BYczFyMm1qaXN0Z0YweTZtSkIxTHFwREJsd29xbElYcWNNTjdhWVd3VVBwS290clZjSzRCZ0tGRUZjTDhqVlFBM2xXYzIzU3VURnNDb1VoSWoxazlhRFdnbFVMd0txMVlhMXJUZldaM0luMGpPYlRna09KNDJPMHdVcUpURkc0NVZkMytxMklnTkN3MXNPeG5TWEZCTWVHL2hKTVhtVWY2UCtsWTlIaysxV3Y3dFMzNmpmUUpuUjFLVWNiam9GRVpOelBRdE5IRW9ObUwyUSs0YjNSSDIxbWJ6THVaUEJqL29QeVhXVk9JK3daM2l2T0t1VC9zL3VOSktsc2VhdGhwM3ZPRFU2bWJxMlBSMTRLSVh5SklPWldDOGNmR0ZlcGp6VFUxRWVtSThCdm85MEorNlNJOUVaYjlMV21aMEpMVzZhM3gyT0toK1BFNjZFVzd3bllJMVlWb3UyampOTStKOXJMMnRJaHFnZWNlVCtxZHFVZmpPNDJ4R2FWc3NHWFkzSkE2Kyt2UVh0YWV4bmNhNDduYmswYlhHMUgvZkgyTTJwWWZTRXVyaGhZMTE5VEU2NkFYN2h2Y3FmVmJMUnhuT2xKalRnMTBQSFF3YUd5QXh4WVAyc3ZhVS85Qy9jZDkzZTVCczRCbU9QM285TTdQRC9GNzRybG9jWkhUZ3RNRVRRNTY3STRxZy9ERmNuZlNnRkVCbFE1WlhWMXVlSlhGaDhNL3BNMmdOaXJCb1ZJQTNnM0lpbVZjUDNpOTNQTU5PallBVVBLdGZZVE9VenBqNzJYUGdSOFBFQjBRamF4WXhvN0pPeGo0eThCWDJuNVZNaEJQd242eVBRS2hnT2pmb2dtWkdZTHRXRnNFNHVlelBRS2hBUGYxN2hRa0ZCQXlMVVJ4WDJIendxZ3hwOFlMUHhNMWZUVTg5M29pMUJRU3ZTNmErTi9MOTdVMy9NQVFtNUUycEp4SklXYXpQRUpjeU13UUhLWTZQRFArK3BQTWd0MUVPM0pEY3VYQ3YrUjJuM1lCZ3hJWHJ4TGpONUcyaURyNzY1QjZMcFhRZWFFVlgwRmxTb25kRmt2YTVUUUtZZ3Z3RytpbitMbmI5UzZCRXdJUjZZcklDY29oWkdZSXNpSVpjYi9INGRQYmgxdnRiaEgvZXp3MVY5ZFVVZ0xTcnFRcHN2S0Z6QWpCcDQ4UE41cmZRSm9weGZ1a04zcGVwUTI4ak5vWjBmRGZocVNjU2VGdTE3djREL0huL3JEN0pKOUl4bmFzTFdLSm1QUnI2WVF2bFc4SlJhMkpldHpYZm43ODYvVXYwZ3pwSy9rbUJVSUIxa090YVJiVURIVUw5V3FkSDh4N20rUDV1eWNJUU10SjY3RnhxQUFrTFNYWWZtMUx6Vjlyb21GVE9kcTZPdDN3S29xTXhBd0dtd3ltdDZnM3gxY2M1OFNLRS9RUjkyR3c2V0RTNDlQZmFmbVFsNXZIck1tek1CSVlNWHJnYUVYUW9PQUh3ZFN4cjhQMzMzNVBac2JiWTQ5U2FRWGdVVGpnMTVIVTRNa1VuOFhTOHR0N2RPNVpaU3FDdmJQM2xydkhIbmcxRUlEbWZacVhYczJwaVJpMWFSVFNJaW5yaHE3aitQTGpOT3JXQ0ltVjVKVzNYeVVNaEF5bDFhdTJxemFtWFV5UlprbEpPcEtFOVZEcjB1V2h6Qld2YmgxZDdDYmFFYlVtaXZScjZVU3ZqY2FpandWcStzL2VIMWNJMmFjZW9aNjNIbTdMNUJiWC9rUDl5ZllyMytQRFpZRUxtbmFhQkUwS0l2bEVNdm14K1poOFZyYmR3aU4zcmVTVHljVHRqcU00dHhqZDJycFk5TFhBc3AvYzZqdjVaREpKeDVQSUM4OGpabE5KSUtBRENhU2VTeVhMTDR1NDNYRklzNlZvdTJqanZzbWQwTzlEOFIva1QvclZpaytHc29LeUorZVlUVEZLTEVweHZ2TEFSSzZNQkJtWTkxQ09WZjkwT1ZtaGpLZzFVUWpVQkpoMlZnNm1vbTZoanVjZVQySTJ4WkN3TDBGNXN2OHZnNENSQVlyODllWDFzemkvbUtpMVVaWDYza3c3bS9KQitBYzBDMnFHNnpKWFhKZTU0cmJLamVaaHpkRnZxSStzV0ViR2pRekZkcEpXRFMxY2w3clNYdFllaiswZWltdnEvRkdIdW4vV2ZlWHprYVMxQk92QjFvVE1ERkZFdzBRR0Vjc2pjUDdKK2FYcnJ5NDN2SXBDMjBDYjFnTmI4K1BWSC9sOHd1ZDBtOTZONzg5OVQrdUJyZEUyckpvNE1JK1M5VHladE9kTmdLYVdKbk1YemFWVisxYUkxRVNLclhCYkIxcys3dmd4YzM2ZTg4WkUrYXZRNHFxeUY4WkV4U2cwb3RTVVZLWFFqVldONU1oa3BiOXIxQzk3RlprVUx2ZS9Ub3RMUTFva3JiUzdYbkprTWxQcVRhSFBUMzFvMHFNSm1ycWE1R2ZuYzJydEtZNHRPMGJyZ2ExcDhWV0xNcTkxck9kSXgwa2RPYnp3TUxKaUdYTXZ6WDF0N1hlZTBwbXJmMXpsd0k4SGFOS3pDVmF1VnV5WXZJTXgyOFk4WHdCSlpSU2xGVkdRVktEa1krOHd4WUdFQXduWWpMUXBaWVJYa0ZRZy81MVlVR2FkVHJPZFNOaVhnUC8vL05HdHJZdm5Icy9uS25wNVVYbnk5eW82cjlSNTYrSFdwRjVJSlc1M0hMYyt2b1gzY1c5MFBVc2I2SW4wUk5SYVc0dmJuOTdHOTB0Zm12ZzFLYmZOOHR5MWF1OTg3T3BrL0pFeFRmMmFLcDAzNjJhR1diZlNGdFZtM2Mxb0wyc3ZINWY0QW55KzhDSHhTQ0tOL20yRWJoMWRwSmxTZkwvMFJiZXVyaUxvVW5rdzYyNUc1czFNY2gvbWx2OEJHNmlCQVBMam5rODVxeG5LUC9lbnk5b010MEZzTEM0M3BuN0MvZ1IwYTVkdkNDa1FDYkFkYTB2RU1qbnJZTkRZQUxzSmRoUWtGbENZVklqZFJEdnVEN3VQZmtOOUREOHdKR3hlR0I1YlBZaFlHa0hZVDJFa0hrN0VvbzhGQWpVQmdlTURGZlZHL1JxbGNLbk1DWGxzVEpvYm1rdjBiOUhZVGJBamZHRzRVbGpvcDdkRFhoVmNGcm1RK0djaVFaT0NjTi9zVHN5bUdNeDdtbGNveTkvelVKMXVlQlVTR2lWZVNnQUxPeTVFWWlWaDJMcGgxUHlnNWt2WG5acVN5b0hmRDdCejgwNEFWaTlaVFg1ZVBsOE0rQUkxTlRYZUZDeFl2b0RXOVZvell0d0kzRDNkMmJSbUU2Ty9HZjNXTVJvdlBLSlhMMTNsOUluVGJGNjdXWEdzMTZlOStLekxaM3o1dnkrck5GUmpiR0FzLyt6OWgwczdMaW1PclIrNW50QmJvVFRvMUVDUkVmREc0UnY0blBiaDczVi9BM0tYdVI4Ky9JRjZuOVdqdzZnT0w1UVJVRk5QazU5di8weHNVQ3czajk1azM5eDk1T2ZrVTVCYmdIMGRlMFp2SFUyTEwxczhzNDdXQTF0emVPRmhhcmFvK2NKNUNWNm0vVWNNeEhlTnZtUGQwSFUwN3RhNFFneEU3STVZRWc4bklzMlI0ai9JSDlQT3B0aU1zQUVCNkRmU3gvaGpZMnkvZm14WGtIUThpYVJqU1dUZGswKzhvYk5ES1Vnc3dMeW5PUnBXajhkYXFDWEVhYTRUdmwvNUt0ekd5cVRCYzZSRXJZNGkrYTlreFlvcWFvMThOU2xwSWNHMHkrTjNxdFp2dGNpNGxVSE9neHl1ZVYvRCtHTmp6SHViSzFickNxSDlpVEhxNXVwb09XaFZlZENnaWtMZFhCMlBMUjVjcTMrTjdBZlpjbThDa1R3MnZPUE0wb21hMUMzbDVRSFVKR3FZZkdyQ1B5Ny9sSys4R0l1cHRhNFdCWEVGejgzR3ArT3VnOU04SjlML1RTZDJlMnlwc1pKbVNja0p6Q21YbFhrNjBJM05TQnRNUGpZQklSZzBNU0Q5bjhkc1IxRm1FYnBldWhUbkZ4TTJKNHo0M2ZFVXBSU2hZYUdCbHIwV212YWFSSzZJVkJMcXNpSlpxY0JLMmY3WjVEM01LNU5sS3MvWU1uWnI3T3VaT0EzVmNGdnVoazl2SDB3Nm1wQjJPUTMzemU1VlZuOTF1ZUc5S0VKdmhXS1NWSFY5bFJoSkdEeHFNSU5IRFg2ajc5dk4zWTBCd3dZd2ZlSjAxdTlhVDFabUZ2YU85cnh0ZUdFRm9HbUxwalJ0MFpTWlA4MTg1WjJ6ZExXays0enVkSi9SL1pubEduWnVTTVBPRGZuZnl2KzlkSnY5RnNrMVc0ZTZEalR0MmZTMVA1Q1hiYjh5REVSWlFVNmVoUGNKYitYSjZWTVRURDQxZWFaUWYxSklnZHhBcnp3OFNnZHNQL241SDVCSVYwU3pnR1p2elFjbTFCVGlzZFdEdTUzdUlta2xJWFpMckpJeXBjU29sTmdBS0JpVWNvd1dKUzBrZU83MnhMU0xLZEVib3ZFYjRGZG1YQU9RUjAyMG4yaVBZVXREN2crOVQreU8yRkp4L0RWdE5NdTl2anhFcllsUzJHS29tNm5qTU1WQlNYRG5CT1VnelpLU2NEQ0JoSVB5YlFVZFR4MGtyU1Z5NWU0NTI5RkNMU0ZtWGMxZXlMM1FhckFWTVJ0akVLb0xzUmxqZzkwNE93SkdCZUMreVoyZ0tVSG9lZW1oNDZaRDJ0VTBiRWZaY3EzaHkvbGxtL2N5SjNaYkxMNTlmV2thMEpUM0VYYTE3ZDRhWmFXcU1YWE9WQnE2Tm1UWWw4UFl2SGZ6VzNrUEtpUEFkeEN0QjdZR3FCUURvVUxWUTcrQlB0WkRyYm56MlIxMFBYVXJIQ2NnNlZqWklZVlRMNlhpTjhDUG5NQWNKQzBsU0xQS043NkwyUktELzFCL2l2T0tNV2hzVUdZU0gybU9GSkZlNWFucmdvUUMwbTg4WmU5UVRHbWp3R0o1SElIeWhMOXViVjJjRnpqanN0Q0ZCcGNhbEJtcm9aUUFHbStIOHdKbmFxMnRoZE5jSndVN2tIRTlBMDA3VFVTNklnSkdCSkI1STVPQ3VBSjA2K3FTY2pxRjRCbkJGS1VVdmZ5S3RiVUVrYTVJa1JqcmZjTWpvOFgzRVlZU1Evb003SU8xamJYQ0Z1Q2Rad0JVZUQ3eXMvT1Zmci9QZUJUczUybWp0TmNCYVk0VWFiYjBqUmdIbXpFMmhDOEp4L2dUNHdwZmsvNXYralBIMWErL0h3MnZONlRHN0JvRVR3c3V0Mnh1U0M1Qms0S291YVltQ1FjU1NzV2xULzhuSGNzQmxtZzVhRDNUM3VCWmVKWm5Sa1dSNVp0RjhGVDVmWWhOeEpoMWVYN1V1b2hsRVFvYkFJZUhjaFpDVml3akwxeStkWkJ3SUVHaDlPalYweU12TEkvMHEra3ZaS0NwUXZtd2NMYkF5TnJvdmIxL0RRMk50M3FScFdJQXFoaDNUOTVsLzd6OUFGdzdjSTN6Vzg1WFNZNkN0eEVwWjFPSVhCV3BtS2pUTHIrZUxIbVpkeklKbmhxTU5GTkt0bjgyNFl2RHlRbktxZGF4ZUpsZ1dVL2JOeWp1ODI0bW9iTkRzZi9XL3JtNUdhTFdScEY4TWhuM2plNEtZMENGRUYwZWdVd3F3M1o4MlZzVDZ1YnFwU0lybGdVdEo2MFhqdkZRSGdxVENrazluL3BDMXp6cHdhQndlWHVTYlpCUlphNXdpaW9ybU8zdlhZV2VpVjZaTHRIdnpRS251RmpKUzAzRkFMem44UHJJQzYrUHFqZlY0NXZDUUJpMU5YcG00SmxYTmluVjFVT3ZyaDdPQzV6ZmlIZENWaWdqOGFqY3lETHhhQ0ttSFVzYnlnckVnakpqTEJoOWFLVGsreTVVRnlyWlU0VC9ISTVwSjFOcTc2N05qVVkzRkI0WlFnMTVtU2ZMK2cvMnA2bHZVenkyZW5DdjJ6MUZESVBNMjVrRWpnL0VkYmtyaFVtRjhqRE51WExHUnR0Vkc0cytGb1RPRFZYMEUwQW9GcGJxdjhzaUYzeS84RlVzTFFRYWdsTExqVkxIbm9HYzRCeDBhK3NxV2ZrL3IveWpWTkZGNlVXdi9MbW1uazhsNFdBQ1JlbEZSSzZNeFB3TGM5Uk4xZCtyK1U1YlgvdWw4bzY4elFpOEg4amw4NWZKek1qRTU0NlBJbzJ3U2dGUW9Wb1ppRk5yVGlrWWlCcjFhOUN3YzBOMEpEcXF3YW11MWI5WWdOVWdLNndHbFE0ckxOSVRZZkdGQlVadGpWQXpVS1BPSDNVVTJ4WmlZekZHSFl5NDVuVU5iUmR0TEFkYUloQUxNTzFrU3ZvLzZjVC9FWStzVUlaZmZ6OGEzMmxNdzJzTmlWd1ZTZWF0VE96R3lmZGxiVWJhVUpSV1JNcnBGUEtqOHdrWUUwRHRIYldwZjY0K0Vjc2pTTmd2WHpWSHJvb2t5eThMaDhrT1dBK3hKamM4bC96b2ZES3VaOGc5REdSeWEvOUgrUlljWnpoaTFNNUljWC82RGZUSnZKMUpjVUV4SnArYllOaFVIc0xWdktjNThYL0VvMWRYRC9PZTVtZzVhT0U0elZHdVpEeTVMU1NrVklocGtaNEk4OTdtY2dWQThCU1Q4a2ovZU9vYTYySFdwRjE4ekRRSlJBS2xGYnBBVkhWMHJhUzFoRWJYR3IzWDc3YTZsdm9MZVZtOVMzQ3Q1Y3JKZjA2KzNYTlRpaXlsV3ZtTDA1eFdTWWhxeEcvOHBocUU2bnovQmFyMzM2eWJQTVd6VUZNbzkxSW9raUZVRjJMeXFRbkJNNEtKL3owZTI2OXRjVnZ1UnNqMEVIbGNpakUyMkk2MkpmbEVNbG4rV1FnRUFqUnNOTkQxMU9WYTNXczR6bkRFY2FZam9iTkRlYmpnSVdKak1XNnIzREQreUJpL3Ivd1VuZ21QWWpaVUY0WXg3SzErZHNIWGc5RTMxYTl3bHNHbjBaNzI3L1c3YnlRd3FsWURBcFVDb0ZJQVZJT2dVZ0RlVzZnVWdKZEQySzB3RE13TkttMElxRklBcWxjQlVDTlZVcjBqY0xxbmFoYXFWZzFBTmY3VkM1V2JaclhpdzcrcnQvMjNRUDVmdXJRVForZUdXRnE2bGpybkNCRHlNaHFZNmhXc1RxaThBTjVCcEtSRU0zU29CU2RPckZBTmhnb3FxUEJTQ0F6OEJ5TWphOVZBcUJRQUZkNEdwS2Nua0o0ZVQwU0VqMm93VkZCQmhaZENYbDQyR2hvcUkrSjNFU292Z0hjUURnNTFNVEd4bzFHamJxckJlSWZnN1gwQ1krT1BLU3hNcHFoSU9hYUNVS2lKaG9aOGxSWVFNSktvcUxYdlhQdDZldlZvM1BnbWVYbVJGQlRFS3ZuMGEydTdJQlliRVJlM0cxL2Z2cXFYNVIzR24zOGVaUDM2bGJScDA0SExsODhUSGg3RzVjdjNpSW1KWXMrZWJhU2xwWExqeGxYbXoxOU9vMGJ5c09GYnRxd2pKU1daZS9kdUl4S0pXTGx5STlyYUtxVkdwUUM4Z3hBSUJMUnBNd2d2cnc2cXdYaVhQbFkxZmU3ZTdVUmk0dEZTNXp3OHRtSnAyWitrcEQ5ZmlmQjlFOXBYVnpjaEl1SVhBZ01uS2gzWDFMU25hVk5mQ2dyaWVmQmdyT3BGcVVKa1o2ZWlxeXMzOEx0eDR6Qy8vTklMTjdkbWFHcy9EdmlVbnA1QVlPQlZMQzFkV2JUb0R1cnFXbno3clRlNXVSblkyTGdqRkQ0T00rM3ZmNUhzN0ZSR2p0eEltemFWeTkzU3RtMEhaczJheEtWTDUxaTgrRmN1WHo2SFFDQmd4b3lKYk4yNkh6VTFOWDc1WlQ3OStuWGozcjJIN051M2k5RFFZT2JPWFVSdWJnNDFhaGpUcWxVNyt2Y2ZxcHBUVksvNHU0T1ZLL3R4NmRJT0pCSkxySzFyc1dSSmQvNzc3eWphMnZwTW4zNFNaK2RHcWtGNmk1R1c5aytad3RmY3ZCZVdsdjBwS0VqQTMzL3dPOXUrV0d6TXc0Yy9QNjN1NHU2K0NaRklGeisvQVJRV0pyOXd2VGs1Z1R4OE9KK1ltQzI0dVB5TXZmM2tVbVdLaWpLNGRNa0dkWFZqWEYyWG9hUGpRVlRVS2lJaWxtTm8yQUp0YldleXN1NWhadFlkQjRlcEZCYW1rcEJ3Z0lDQTRXaHBPV05vMklMc2JIOTBkV3ZqN0x3UXNWanlWcnh6VVZIM3NiR3BCVUJtWmhMZmZMT2YrdlUvVnlvemYvNm5DQVJDUm8zYWpMcTZQQ2VDbFpVYlk4WnNRMDN0Y1dDa3dNQ3IvUGZmVWVyVy9ialN3bC9POXVoZ1pHUkMrL1lmNCtqb2hLT2pFMmZQbmlRK1BvNzE2MWNCa0pXVmlhZG5YUklTNGxtN2Rqay8vdmdMQUZwYTJ0eThHWVN4c2FscVFsRXBBTzhXdkx3NllHTlRpMDgrK1pvOWUyYnkxVmVMOFBlL3dLMWJ4ekF4c1ZNTjBGdU9oSVI5cFk1cGF0cFNxOWE2a3RYVklBb0tFdDdaOWxOU3psSlFvSnh6d01abUJFWkdiWW1QMzBOQ3dvRktDaFJYSEJ5bUVSZTNoNGlJRmRqWmpVY2dVRTVFRkJPekFabXNDQ09qOXBpYWRpNXBld3dSRWN0eGNwcUxSTkthakl3YlhML2VHSm1zR0VmSDZWaGJEeUUwZERZV0ZuMm9VV00yUlVYcFhMM3FRVzV1R1BYcS9mMVd2SFBSMGZleHRwWXJBQ0tSV2luaGYvYnNSbTdmUGtISGp0L2c1dlk0UzZlMzl5ZEt3citnSUpmVnF3ZWlwYVhIOE9Iclg3cGY4b0JRanoxb0lpUERNVEV4WmVUSThhWEtob2VIVVZoWW9QamZ5c3BHTlptVVFHVUUrQTZoWmN0K2RPMDZqZno4SEM1ZTNNSHAwK3Z3OUd6SGdBRkxNVFMwVUEzUVc0NzA5R3RQVFlKQ1BEeTJvNlptU0dUa2FwS1Nqci9UN1Q4dC9MVzBISEJ4K1ptQ2dnUUNBc2E4cEVBUlkySFJoNEtDT09MaWZsYzZKNU5KU1UyOWlKNWVIVUQweERYSzZ5ZDkvWWJvNnRZbUxtNTNtV1hVMUF3d00rdEdTc3BwQ2d1VEt0eTNTNWQyRWhzYitFckg5dTdkVTB5ZjNoUmYzN1BsS2dDdFdnMVFPcGVjSE1YV3JST3h0SFNsZCs5NVN1ZWVMcnQ3OTNSaVl3TVpNT0FYakkyclhnQmJXRmh4K2ZKNTR1TmpGY2RDUTRPSmo0L0Z5c3FHa3lmL1ZDcC84ZUpaMVlUeUlnekFsU3NYNk5peHRWeHJFQXJSMUN5ZC9qSXZMNWZpNG1KRUloSEhqbDFVR0dDOFM0aUs4bWYvL25uNCtwNmxvQ0FQQXdNejZ0YjltT2JOdnlBbzZCcU9qdlh3OEdoZEpXMFZGMHM1ZVhJMVo4OXVJajQrQkhWMUxlenNQR25hdEJmdTdpMzU4OCtsWldyVGtaRytaR1ltRVJ4OG5ZOCtHdjNDN2Via1BDQW1aZ3N4TVZzb0tKRG5ZM2QzMzRpVlZjVm9PeisvZnNURzdnQkFJbW1OaWNrbjJOaU1RU1I2OGFRaEtTbG5TVW41bTZpb3RRckRNNEZBaUZoc2dsU2FpMWdzUVVmSEF5dXJRWmliOStCOThxdTN0NStDUk5LSzdPejdCQVZOZnMvYUYxQ3Ixc1lTNm4vZ0N3blU4cUNwYVl1WldROGlJcFpnYWRsUGNUd3g4U0JtWmwySmlscFRzVWxWVGU4NXlvWVFrYWppQm1pQmdmL1FxRkdYVnlqOFR4SVo2VWZidG9QWnQyOHV0V3UzVlp6THlFaENUNi9zREpacjF3NGhMeStMMGFPM0tLai9zdkRnd1JXT0gxOWVRdjBQcXJKK0Z4ZExuMWo4dE1YSXlKZ3VYZG96YmRwY3RMUzBPWGJzRUwvOHNvNitmUWN5Yjk0MDdPMGRhZGFzSlFjTzdLRm56eThWMTZhbHBiSml4YzlJSkVZY09yU1hJMGZPTVdCQUQ0cUtDdG02ZFQ5VHBvekYzOStIMzMvL0U1bE14ckJoWDdKcDB4NkNnaDV3Nzk0dHpwMzdtMjdkdnFCUG53SGs1K2V6WnMwdjVPZm5jK1BHVlRaczJNMkJBNy96eHg4NzZkS2xGNnRYTDZGSmt3OVl1M1k3UW1IMXI3OHIzSVBrNUVTY25kMDRjK1k2aVlsRlJFVmxLZjJjT1hNZHNWaE8rWXdiTitXZEZQNysvaGVZT3JVQkFvR1FoUXR2c1hWck90OS9meFl0TFQxbXoyN050bTNmVk9uTHZXaFJWL2J0bTBldlhuUFl0Q21aZGV1aTZkaHhFcWRPcldIQ0JIZGlZNFBLdk5iUjBidmtkNzFLdGEydDdZYXo4M3c4UExZK1FhTXRwdHhFN2s4Z1B6K2F1TGc5SlpTaEx2WHFuY0xlL3R0S0NYOEFJNk8yT0R2UHg4bHBic25rcWsvcjFwbTBiQmxQcTFZSjFLanhQV2xwbC9EeDZZV2YzNkFLOWZGZGdMNStBNXljNWxCY1hJQ3Y3NWNVRitlK1YrM2IySXdzb2Y3M2twQ3d2d3FWbW0vSXpMeExTc3JqQ0kxeGNiOWpidDZuQXNycUdiS3lmTEcySGw3T3R4RkxmUHhlTEN6NklSUnFWYmhQcjlvTno4dnJJejcvZkNKdDIvNlAxTlJZN3QrLytOeHJ6cHpad04yN0ovbjg4d200dWpaOUJtdVR5NisvRHFveTZoL2czTGxUQkFjLzRPREJ2ZHk3ZDd1RURkSm03OTdqU0NSR2pCbzFrTldybHpKcDBnd0FSbzJheU9qUjM3QjgrVUlHRC82Q1JvMmFVYWVPdDZLKzA2ZFBZR3BxenRpeGt4azVjZ0k2T3JyTW1qV2Z0TFJVREF3TW1USmxOcW1wS1ZoWVdLR3VyczZBQWNQUTF6ZGd4NDZOakJvMWtWOStXY2ZreWFQSnpNemd0OTlXMEx4NUs2Wk0rUjVMU3l2V3JQbUZ0bTAvSWlRa2tBNGRQdVBLRlIrdVhyM0VrU1A3M2k0R0lDa3BrUjkrV0lLM2Q4TlM1d29MQ3hrKy9Ddnk4L1B3OHFySGxDbXozN2tKdDdoWXlxcFYvVEUzZDJMTW1HMEt5MVpqWTF2NjlQa0pKNmVHTEZuU3ZjcmFPM2R1TXpkdkhtWENoRDAwYk5oWmNkemIreE5xMTI3RDdObmxzd3c2T2hKTVRSMHFyUUE4cnFjV1FxRmNxY3ZPdms5aTRsRk1UVHM5ODVxSWlHVUloUnBJcFlXb3E1dVgya3V0L09yTVRySHllNlJNQ0lXYUpheUVESC8vSWNUR2JzWEU1R1BNemIrb2NMMUZSV25FeG00alBId3hlWG1SNk9uVnBYSGoyOCs4SmpjM2xILytjVVVtazJKdTNoTno4eS9RMWZVa0tlbFB3c0orb0xBd0JYVjFjN1MxWFpGS3N5Z3NURVpQcng0T0RsTXdNR2p5MG1NaEV1bFF1L1pPQkFJeHdjSGZrcGw1KzdWK0M5WGR2cGFXSXk0dUN5a29TQ1FnWUhTVjFxMnYzd0JEd3hhRWh5L0d5S2c5R1JuWDBkT3JwL2dPeWtKaTRpSFMwaTZUbXh1S2w5ZWhVdDlJUnNZTklpS1drcFhsaDRQRGQ5amFqbjRqNXppQlFFalhydCt4Yjk4OFpzNzhtNEtDWERRMHRNdVFCUkZzMi9ZTlZsWnVmUEhGRDgrc2M5ZXU3NGlORFdMa3lFM1BwUDYvK1dZa1c3ZitocE9USy9yNkJrL05LUTlKVEl6SHljbVZDeGR1MGFaTkI4TENTcWVLcmxuVGcrUEhMNVhCeUtneGUvWkNaczllV0diYkRSbzBvVjI3aHZqNyt6Qjl1bndybzA0ZGIvTHo4d2tPZm9DdjcxMGtFaU91WExsQVdGZ3czYnA5Z1ovZlBaS1NFdG0xYXdzQWJkcDhTRXBLTWhjdW5FRlhWNCtnb0FlWW1wcWpxYW1GdXJvNmVucjZPRG82QWRDcFV3OXUzYnBCbHk2OTNoNEZJQ01qblJZdDJwUjVidjc4V2R5N2R4c05EVTNXcnQyT1dGenhTVDh1THBoTGwzYXliOTljWkxKaXVuYWRSdXZXQTdHMGRDRTZPb0N6WnpkeTlPaGlSQ0kxZXZhY1RZc1dYMkpxNnZEYUJ5b2l3b2VrcEFpYU5PbWg1TmE4eCtPUEFBQWdBRWxFUVZUeUNJMGFkYVZ1M1krcnJMMWJ0LzRzV2VsNGxEb25GbXN5YU5BS2R1ejR0dHpycmExclltbnA4bkwwa0ZDTVVLaUZtVmxYWW1LMkVCNys4ek1WQUtrMGsram9EVmhiRHlZaVlubXBQZEtYbTV4RTVaNnp0QnhJUU1Cb2lvdnppWXZiODBJS2dKcWFJYmEyWDZPbVpvQ2YzMEF5TSsrUW5Id0NZK05QeXIwbVBId3hNcG1jZm54a2dRNWdaemVCM053d0lpTlg0dUt5R0V2THIwcStuZXZjdnYweC8vMTNERy92NHhnWnZWejhVMWZYWldocnU1S2FlcDZJaUNXdi9WdW8zdllGdUx2THFYOS8vLzlWQ2ZWZm1nV1l5TjI3WGNuSzhpVXFhaTB1TG91ZVdkN1V0QXNTU2V0bktCVU5zYk9iV0ttK3ZHNDN2Qll0dnVLUFArWVFHSGdWZFhVdHJLemNTcFY1UlAyUEdyVVpzYmo4Vk1BQkFaYzVjV0lsM3Q2ZlBKZjZ6OGhJNThpUmN6UnIxbExwZUVKQ0hNMmJleUlXaTFtL2Z0Y3I4ZDIzdGJYbnloVWZac3o0aGxhdDZuSDllZ0FHQm9iMDZOR1gvZnQvUjE5Zm4rSER4N0YzNzNacTFhcU5ycTRlUlVWRjZPam8wTGZ2UUFENjloMUlmbjQrVW1rUmpSczN4OTNkczRUMXlTYzVPVkdwUFluRVNDbUdSWFdpd2xzQTQ4ZFBSVXVydERiNDc3K1hXYkZDN3Byei9mY0xjSE56ZjZFT1dGZzQwN1BuOTFoYXVtQnA2VUtmUGo4cUJKZTFkVTM2OVZ1RW9hRUZEZzUxNmRadGVyVUlmMER4d0c3ZlBrRlVsSCtaWlpvMDZWbmw3UjA5dXJqTTg4N09qVEExdFMvM2VnTURNM1IwREt0b1Fwd0VDRWhMdTBKNitqL2xsb3VLK2cySnBDWGEyalZmODhwRmhJYUdUUWtiVlRtQklCWWJvNi9mQUlDd3NQblBvRFFUU0VrNWc3cTZHUUtCU0NIOEg5ZGpWSVlBYUlTRHczZklaSVdFaEh6L1V2ZHFhdG9GYStzaEZCV2w0ZWZYSDVtcytMV09kWFczYjJzN0NvbWtEZkh4ZnhBZi8wY1pUSkY5cGJlYkhzSEVwQlBhMnM0RUJVMUNKTkpCTERhdXRnbTZMRGU4Nzc4L3grVEpoeFEvT2pxR1picmgvZkxMZmFaTU9hb28xN256RkhKeTBwL3BoaWNTcWRHbHl4VDI3WnVyWkFENG1DNy9qWHYzL3Vienp5ZVdTZjNuNW1hVUNMNmNaMUwvajhvOWdwdWJleW5oTDVQSkdER2lQOG5KU1V5Yk5vKzZkZXUva2pFK2NtUWZPanE2Yk5pd205cTF2UWdQRHdPZ1I0KytiTnk0R2krdituVHExSjNqeHcvajVDVFBoK0RoVVljclZ5NndjK2RtRWhQajJianhWM0p6YzJqV3JCV1RKbzBpSkNTSSsvZDlPWHhZL281bVpXVXA1dlRBd1B0MDZQRFoyNlVBbElXc3JFeEdqdXhQY1hFeHJWcTFZL2p3cnl0ZGwxaXNpYnA2MlIrdWhvWU9hbXJWbTNQYXpzNFRJeU5yOHZPem1UR2pHUmN1YkMxVnBtN2RqekEzcjFFbDdYbDd5MWVnNTg5dlllSENqaVFuUjVVcTA2SER5SEt2MTlNemVhWjIvaUxRMGZIQTJGak9icFQydzM3MHNSWVJHYm1pUkZsNHZTZ3V6cU9nUUc3OXE2dGJ1OUwxR0JvMng5Q3dPV2xwbDBoTHUxSm1tY2pJRmRqWWpIcmhyUTB0TGVjU0JTS3UwdjNUMExEQzNYMERBUGZ2anlBdkw3TE1jbVptcnlZQ1pIVzNyNlhsaUxPem5QcC84S0JzR3QzS2FnREZ4WG1WVUxpTGtNbUtTaFJLSWJhMjQwaE9Qb1d0N1pnbnlrZ1ZaUjVkOCtUdjU5VmJHVlRVRGUvenp5ZFVtUnRlNjlhRGlJanc0Y0tGYlFybEErVFUvL2J0azBxby8zbGxmQnUrUEh4NEI1QlQvM0Z4d1F3WThFdVplUVF1WHR5aDlIKy9mcVhqUi96NjYxTE9uLytiRHo1b3pkaXhyODdJTkNzcms5NjlQMlBEaHRWNGVkWEQwN051eWNMSGtZNGR1OU9zV1V2MDlQVHAyclUzYmR0K1ZESy82ck5telRaKy9ua09MVnJVeGN6TUhFTkRDV1BHZklPbHBUVnQydFJuN3R6ditPeXpMaVhqbjgrcVZZdlpzR0UxalJvMXc4dXJIbThDWGtvQitPNjdjWVNIaDJGZ1lNanExVnRLZkRQZlRZaEVhb3dldlJXeFdKT2NuSFJXcng3SWpCbk5sQXhtSkJLckt2TzNiOWR1cUVJSnVIbnpUOGFQcjhtZVBiT1VOR2NYbHliUG9CMnJOdENGZzRQOEEweE1QRUpPem9OUzUrUGo5NkNoWVltaFlZdlgvbXpDd3hjamxlWWdGS3BYbW1wOWZKOVRTeFNkMGl5QVZKcEZmUHdlcksySHZIQzlxYW5uU3Q2Uk5wWGxPZkR3MklKWWJFeHM3RGJpNC9lVS9VRUx0VEF4K2ZSVjhDelYzcjU4dTBXSEJ3L0dVRkNRV0FicjFSU0pwTjBMc3hJNU9jRkVSaTRuS2VtWXd2alB5bW9RbHBaZm9hM3RobFNhUTJ6c0RyS3ovVWxOUFVOaTR1R1NhK1RKdG1KaU5wR1plVWVwenNMQ0ZLS2oxMUZRRUV0UzBqR1NrMDg5c3c5dmtodWVXS3hCeDQ2VENBaTRqSkdSaldJMXZtYk5ZUEx5c3N1ay9vdUtDdGkxNnp0c2JXdHovLzVGL3ZxcmZPci8vdjFMeE1VRkt4MHpON2RVK3YvZXZkdk1temNOUTBQSks3ZVk3OWR2Q01lUFgyTElrTkhNbWpWZlNZNHRXZkxZODJQeDRsK1Z0cmMvL1BCVDd0NTlTRUJBTEIwN2RpOVJVclhadVBGM0lpSXkyTDM3S0RvNmNvYlF5TWlZc1dNbk0yVElhSVlNZVhOc1FDcTlTWHZzMkNGMjd0d013S0pGcTkrTDRBcWVudTJZTStjQ3ExYjFKeWJtQVlHQlYvbisrMWJVcS9jWi9mb3RLa1dYdlpSbUpoUXhlZkloZHUrZXhyRmp5OGpQejJiLy9ubWNPcldHSGoxbTBxSERLRVNpOGgvZm8zM0Rxb0pFMGdaOS9mcGtaTnprNGNORmlwWGdZeUc4QkVmSDZhLzFlZVRsUlJJWnVaenc4S1dJeGNhNHUyOUdXL3ZsN0I1TVRENHJNZWc3UmxiV1BYUjE2end4R2EvSHd1TExGM0xoa2twemlJeGNTV1RrS2lTU2xyaTRMS3hVdit6dEoySms5Q0c1dVdIbGhydFZWemZEelcwVmVYbGhWVDdXMWQyK2xkVkFKSkxXeUdSUzdPd21sbEwweEdJanRMV2RpWTNkL3NKMWEyczc0K2EyOGltRlh3Y1BqMjBsZjJ0amFmbVZ3cWJqRWR6Y1Z1RG10cUljSVdxRXRmWHdjajBDbElYL20rZUcxNzc5TUh4OFRpdUU0Y1dMMi9EeE9ZMk9qb1REaHhlV0V2NFBIOTRGWk9qb0dQTHJyLzlESnBPUm5aM0dva1hLN29zWkdZa0VCdjdMMEtIbHUxVG01dVl3ZEdoZkNnb0tXTGR1aHlwd3o1dW1BQ1FteGpOK3ZEeU9jdGV1dmVuUjQvMUp2dUhzM0lqRmkrOXg3Tmd5RGg3OGlaeWNkRzdkT3NiZHU2Zm8xV3MyWGJ0T3E3cUhvNlpPdjM2TGFkbXlIMXUzVHNUWDl5eVptVWxzM2p5T3MyYzNNWEhpSCtVYSttbHE2cjRDSVRBSkg1OCt4TVh0d01scEhob2FjcTA5SmVVTVJVVVptSnAyZmVYakw1Vm1jL3YyUitUbFJaT2Q3WWRBSUtSV3JUVWxncmtxN2xtQXZmMjMrUG4xNCtIREJkU3V2YXRrQlZSSVZOUTZHamE4VXFGYVltTzNrSkN3bCtUa2s0akZKdFNyZHhxSnBEVUN3WXV2WkxTMEhIRnkrbEVoV0pvMHVWZUd3cWlCdXJvNUlNRFg5NnNxSGZQcWJsKyt5dDVNVE16bWQzSk84Zkw2Q0Mrdmo1REppamx5WkJIMzcxK2tWcTJXejd6bWtSdGV4NDdmdkJJM1BBME5iUVlOV3E3RUtEek5LZ0FzWGRxVHZMeHMxcTJMVmh4YnVUTDRwY2JqdSsvR0V4UVV3SmRmRHFKejU1NXY5Yk10TGk3bXlKSDl4TWZIY2UzYUZSbzNidjcyS3dCanh2eVA1T1FrTEMydGxTaVNsMFZTVWdTclZ3OHNkVHdqSStHTmltU25wcVpPNTg3ZjByYnRZQTRjK0pHLy9scUZWRnJJN3QzVEtTek1wMWV2T1ZVc2VMMllOZXNNdDIrZllNZU9iNG1NOUNVOC9DNnpaclZnMGFJN1pZN05CeDlVdlZKbVp0WVRMYTN2eU0xOVNHVGtjcHlkRjVTcy9oZGpieit4VXNMdFJTRVM2ZUR0ZlpLaW9uU3VYYXRIYm00b0dSazNLN1RTcWlnc0xMNGdOSFFtOGZGN2NYS2FoNWFXRTNGeHV6QTIvcWpDQm1HV2xnT3h0UHlTVzdjK0pDWGxESVdGaVpVZW45emNNTTZlMWF5Mjk3MjYyMzlmVUoxdWVHWEIzTnpwdVdXaW92ekp5a3Fwc2pINDg4K0RiTnUybmhvMW5GbXdZTVZiLzB5RlFpRWpSb3hqeEloeGIyYi9YdlNDVFp2VzhQZmZ4eEVJQkt4ZXZSbER3NnBMYW1GaVlzZm8wVnRLL2Vqcm0xWDdRT1huNTVTeS90ZlRNMmJBZ0tVc1hueFg0UzV6OE9COE1qTmYzalVwSk9TL1VzZTh2VDloMGFJN0NnVWpQVDIrRkIzM2FpY29FWFoyRTBvKy9MVklwWmxrWi91Um1Ya1RLNnRCci9WNXFLa1pVS2ZPSHdpRkdrUkhyMWNLdi9yeTk2bUduZDAzeUdUU0VxTkhHUkVSeTdDM2Y5RkFUd0k4UExZakZwdHcvLzV3OHZMQ1ZWSk9oV2VpUll1dmlJc0xKakR3S2pFeEQxNmJHMTVsMGFCQko2VTRKUytEMk5ob3hvMGJncHFhR3IvOXRsT3hmNjdDRzhJQWhJUUVNWE9tM01wNzZOQXh0Rzc5WWJsbG82TWpzYmEyZldjR0tqYzNnek5uMWpOZ3dDK2x6bGxiMTJMS2xLTk1uT2lPVkZwSVdOaHQ2dFQ1OEtYYU8zZHVFeFlXVHVqb1NKN1NLRVgwNkRHTCtQaFFMbHpZU25EdzlkYzZEbFpXZ3drTm5VTmhZUXBSVWV2SXp2YkR4bWJVQzBVMnF5cm82ZFhEMVhVcEFRR2p1WDkvT1ByNkRWN2FCdUR4TXgxTVdOaGNZbU8zb3E5ZkgxMWR6eWVDRVZVY0docVdlSGhzNXM2ZGp2ajZma245K2hlVVlocUlSSHFZbVhYRnhXVXhRcUVHaVlrSGxaUWNFNVBQT1hkT0IwMU5leXd0KytQb09JUDgvR2pTMHE0Z0Zwc2dGaHNUSGYwYlVWRy9LcTR6Tkd5T25kMUV6TXk2a1psNWw1eWMrMmhwT1NHVjVoQVdOcGVVbExMam9HdHAxY0RlZmpJYUdoWVVGaVlqa3hXVGx4ZUpRS0JHZlB4ZTFOUjBzYkVaaWFYbEFGSlRMejZ4MXkvQ3dLQWg4Zkg3Q1FtWi9zNVBtbEpwRGhjdm1tSmkwZ2sxdFVmKytNWEV4R3hHUjZjV2pScjk5OHpBUWM5bXVCNjc0YlZxMWI5Y043eU9IU2VWNjRhbnBhVmZJVGM4TFMzOWx4Nkx4bzI3a1ptWi9OTDFGQmNYTTJKRVAxSlRVNWcrL1FmcTFXdFVacG5nNEFlNHV0WkNoZGZNQUJRVkZURjgrRmZrNXViZzRsS3ozS2hLSUk4TXVHblRtbGZXNmF0WDl6SnVuQnU5ZWdrNGZseStUNVdkbmNyNjlTUDQ5bHR2ZkgzUEVoWjJtOG1UNjlLcmw0Qy8vbHFsc0F5T2lYbkF1SEd1ckY0OWdLU2tpQmRxOS9yMVErVmFHRnRhdW1CbEpmZC9mekpJUjJVaGt4VnovZnJCWjJqZUhhdXNyUmVib0hTd3NSa0J5QTMvRWhJT1ltTlRmVmF0Tmphak1EZnZqVlNhaVk5UHIwcTVnSlZOM1dsaGEvczF4Y1g1QkFTTXhzRmh5b3Mrd1NlWXJjK3h0UjFEV3RvVlFrTy9mMHFZWkJJYnU0MjB0TXNVRk1UaTV6ZFE4WFAzYmxjQ0F5Y2dFdW1Ta3hORVNNaE1aTElpNHVKK3g4ZW5ON2R1dFNNKy9uZHExbHlOamMwb1JaMXBhVmVJaUZoYW9yVFB3TWVuRHpkdU5FY3F6Y1RiK3lSNmVsNmxlbXRrMUk2R0RmOGxKZVVNZCs5MnhkOS9DUGZ2RHlNNStRUzJ0bU1SaXlXa3AxOGpQSHhwQ1FPMDVvbSs5dVBmZjcyUVNqTmVFZk1reE5wNktNMmFCYUd1WHYxYmdZV0ZpZFNxdFI1UHo5M1VxcldXV3JYV29xM3RYTUw0Ykt1MDhIK0U2bkREZXhFRUJWMmpYejlkZXZjV3NYUG5WRTZkV3NOWFgyblRwNDg2Rnk5dXIxU2RLMWN1NHRLbGN6UnQyb0lKRTc0cnM4enAweWRJU1VubVRVQ1BIaC96M1hmaitQSEhHZno0NHd5YU5hdE5zMmExS1N3c2ZEY1ZnQ1ZMZnVEV3JldW9xYW14ZHUzMk1wTUJQY0t1WFpzeE1Ya3hON1NDZ2h5azBzSnlsSTk4aW9yeUZmODNiZHFMV2JQa0ZxbEZSUVVsZ2xBZTlPYjc3ODlTdTNaYkhCMjltVFJwUCtycVd1am9TQlQ3cjZhbURyaTZObVBVcUMwdjdMS1htUGlRUTRjV2xIa3VJeU9SK1BnUUxDMWRjSEpxVUNVUForL2UyYVNsbGUwM0hoaDRGWURtemZ1OHNwZEQ3c05jV3VHeHRmMGFvVkNEZ29JNExDejZvSzV1V3VxNlI2dWlxdXpMSThYb2FiaTdyMGRiMjRYTXpEdVZEZzFiVkpST1VWSDZVOHJGYUVRaVBZeU5QMFpIeDBOSnVFdWxtY2hrVXFUU3JLZnFTU3NSRXNyN29pNHVpOURWOVNRczdLY3lMZFZsc29JeSt4VVRzNG1pb293blZrSDVUMDM2S3dGWlNTSWt5aTBuTjJKY2cwQ2dwa2huK3dqcTZoWjRldTRoSm1aVHFaUy9HUm4vRVJBd1VwRy92cngrRmhmbkV4VzF0bEpqYjJyYW1ROCtDS2Rac3lCY1haZmg2cm9NTjdkVk5HOGVocjUrUTJTeVlqSXlicFFJV1RsVDRlcTZsUGJ0WlhoNGJGZGNVNmZPSDlTdCsrZXJuelNGbWtxdWp0blpmb1NFektKR2pWbm82ZFY5NmZxcnd3M3ZSV0JzYkVQYnR2OWp3WUliZE9zMm5mYnRoN0ZvMFIwNmRCaUpuWjNuQzlkMysvWi8vUFRUVFBUMURjcDErWHY0TUpUcDB5Zmk0VkhualJDYy9mc1BZZjc4NVV5Zi9nTjkrdzdpNGNOUWxpNWQrMEpSY044RVZHZ0w0TmF0Nnl4WklyY0Nuang1RnQ3ZURjb1JndWtjT3JTWDZkTW5zblBuNFFwMUlDNHVtR3ZYOWhNWEY0eFFLT0xnd2ZrMGFkSkRFUXI0K3ZXREpDZEhrWllXejZGREMyamUvQXRNVFIwd05yYmxmLzlieVcrL0RhZHAwNTc4ODg5ZTJyWWRyRVNabTVzNy9aKzk4dzZQb3V6YStHOTNzNXRPS2lta2swb2dkREQwSWdnS2duVHBTQk1VbEk0VUJRRXBncjZnS0NKTmlrcVJKaW9LUmtWS0FnZ0dLUWtoSkNFOUliMG5tOTM5L3Boa2swMGpnWVNFajcydkt4ZnN6RE56enp3N08rYzhwekpzMkhJT0hGaEUrL2F2b3EvZmlGOSsyY0xRb1VzZnUyYkI5OTh2SXpvNmlFR0RGdUxrMUJLVlNrVkVSQ0E3ZHN4QUp0Tm56cHlEdFJZTWw1d2N4ZUxGYlJrOWVpMit2c1BSMHpNaVB6K2JNMmUrNHVlZk45T3o1eVM2ZFJ0WFp3OUhYbDRrQ2tVV2hZVVo2T2cwS2lVd3JMRzFIVTlzN080SzgrN3o4Z1RMU241K1BDcVZvc295dnRWRmJ1NkRvaFZ6K2V1UlNJeng4VG5DMWF1K3hNYnVSa2ZIRkhmM0RkVXFSVnhZbUU1Q3dpR2lvcmFTbHhlRmtaRVBGaGF2WUdqb2hWUnFocjM5ZEkzc2h1VGtYMGxNUEtFV3lrRkIwN0d5R2w2VU9uaEtMZHlqb29TZUNGWldyeUdUMlNBVzYrSGpjNURMbDl0eisvWkVFaE9QWVdzN3RzcHJzN0lhUm1ibU5YSnpJeXIvQWV1WUFDTHk4eDlkWUVoSHgxVDl2V2dxT204aWxWb1FHN3U3d3VNU0U0OVdXV0JKSkpMZzREQ2J5TWpOQUppWXZJQ2o0MXdLQ2g0aWx5Zmg2RGlQb0tEcE5HclVBVlBUcm9TSHI2WjU4NzFFUm41S2VQaGFIajQ4aVkzTmFFUWlIVUpDU3ZxNVIwZC9pVXdteFAvazVOd3Y5U3lFRVJQek5ZNk9jM253WUFOWldiYzBMRUoxRFNIYm9VU3h1blZyQWtaR0xYRjJYbEpySFBXWmh2Y29tSnZiOGNZYlFvRGVaNStOSlNzcmhhVkxUMnRrRGRRRTA2ZVBRUzZYWTJJaVkvTGtVUlhLbGZEd1VKbzBzY2ZZdUJFTkFjVUZnUUFXTEhpTFljTmV4OWUzNnpQbkFoQ2xwRHk2S0hHWExqNEVCZDBxMHI0TktoU2VTcVdTdkx5U2ptQjM3eWJRdVBHamcvZCsvLzNKYm1EOStvRWtKMGZUdS9jVVhuNjVmSDZ5UWlGbjBhSTJ0R2pSbTRFRDUzSCsvTGNNSFZwelAyVmFXanpIajYramUvZnhCQWIrU21EZ2FSSVR3OG5MeThiSXlJeldyVjltNk5CbHRkYnJldi8raFhUck5wYTR1SHRjdTNhSzRPQUw1T2ZuVUZDUWk1TlRTL3IyblVHM2JtT2ZtT2Zycjh0dnk4a0pJU0hoRUxHeGU4bk52WStwYVJjc0xWK2xTWlBKNnRWK2RuWXc5Kzh2cDJYTEgwb0p4OU1rSjU4bE9ucWIyaFJ2YnQ0WEM0dStSYXZweDIwSGZJYW9xQzlSS0RLTEJFeG5yS3dHWTJzN1FjTWtIQk96ZzZDZzZZRFFQS2h4NDBFNE95OVZweXMyUlB6K3UvQmI4dkU1aUlYRnkrb1lBQjBkTXl3dFgrSFNKWGNOQmFCWHJ5eWlvNy9pM3IwRlNLVVdORy8rRFkwYXRlZmF0ZDVrWndlcHh6VnExSjZPSGE4U0dQZ3FTVWsvWVdqb1RldldweWdvU09UYXRkNGEzZnM2ZEFqQXlLZzVmLzVwL01qck5UVDBvbE9ub0ZJeEFHSk1USHhKVDcvRTdkdVRpc1o0MDdMbFVaVEtmTUxEUDhUQ29oK0ppVWV4dFoySXVmbUxoSVd0UmlhekpEdjdycnFnVUlzV0J4Q0w5Zmp2UDAxTGhrUmlnRUtSZzBSaVJLOWVtZno5dHkwRkJmRVlHTGpSdWZNOUFnSjhOQlFBaWNRUWhTSzdCb0wyeVdxeTM3Ly9BUThlYk9TRkYvN0YwTERtSmJDblQ2OThYMExDL1dwRjR0Y25aczUwSUQ4L2g5MjdIODgwMzZjUHp6U09IVHZJb2tXenVIdzVHQXNMeThkUXB1cTNlbDYxTEFBWEw5NXNzRi9BbURIcldMQ2daYVcrY0lsRXl2VHAyMW01c2ljcEtiSE1udjE0UGlwVFV4dTFodXZxMnA1aHc1Ylg2WDJOSHk4MElIRjJiazJuVGs4M0Y5YkF3QU1YbC9keGNYbS9Ta0ZRV3ZnTHBzR1hzYkI0R1ErUFQydnRXc3pOZXhlMUJGNy95TEYyZHRPd3M1djJ6TDVNaW1NQWl1SHF1cnJDY1dabTNmRHgrWjdHalY4akptWW50MjlQTE9keUtFYVRKcE53Y3BxSHFXbDNnb0ttRVJkM0FKVkswOVdtcDJkZjZmR1ZJVHA2R3drSkI0dFd4RllhTVJMWjJYZkl5Ym1IUXBGRll1SnhFaE9QRnowelBwaVo5U1E2ZWh1UGF0dGMzSVFxUHY2N2FsOVRreVpUaUkzZGhWZ3N3OTUrRm82Tzd4SWMvQmJlM3J1NWQyOHh4c2F0TURUMEpDM05Id2VIdDdoOHVjTVRmVjhaR2Y4UUViRU9kL2VQSDB2NFB3b05YZmdET0RxMlJDN1A0M2xFWm1ZR3k1Yk5ZK1hLRFk4bC9Cc0NkSjcxTDhIUGJ5Y2pScXhnMzc3NXRHMzdDc2JHNWI4SVQ4OHVlSGwxeGQ3ZXU4cUtXVnBvMFpDUWxQUnpoZHRUVTg5ei8vNVNPbmE4aXBsWjkzSnhDS1VSRy9zTjJkbEIrUHJld01Ua2hRcUw2U2dVT1VpbGovOENLeWhJSkQzOWFsbWJZQVZCZ2NxaWE2MVkrQnNadGNETmJUMGlrUWd6c3hlSmkvdW1HZ0pvRGdVRlNVaWxwbGhhdmtwczdDNVVxa0l5TXE2Z3ArZUlSR0pFY1BBTWNuSkMwTlcxeHRwNkZHRmhxOG5QajZXdzhQSHoxNVhLUEc3Zm5vQ3BhV2NjSE41OWJwOVJaK2RXeU9YNXorVzlyMTY5RkdmbnBvd2RPL21adllkbldnSDQ1WmN0ZE8wNkdqZTNqbHkvL2pQZmZETzMwaFcram81dW5kYVQxa0tMMmtaNmVrQVZBcWlBMjdjbjBLSERGWm8yWFVsb2FPVVZLSE56NzNQdjNnSzh2TGFSbUhpc1hGMzY5UFJMMk5wT1JGL2Z1Y3A0ZzZwUWJBMTRFbVJsM1NJMFZPakZJSlZhWW1YMTJpT1BpWXpjckhZQk9Ec0wxeTZrTHdveEk0bUp4OVFXRDJQanR1VGxoWk9lN2s5NnV2OFRYV3RvNkRMeThxSm8zZnBualppZndzSU04dk5qNjhRaTBCRFJwSWtuZVhuWno5MXY4OTkvLzJILy9wMzQrVjFWdThRVkNnV3BxU2sxRG9DdlR6eXpFdkhPblhNb2xRcmMzWDBSaWNSTW4vNDFGeTkrenovLy9GamhlSlZLaVZLcFJBc3RualhZMm82dmNIdG01ZzNDd2xiaTVMUUlFeFBmS3M4UkhmMFZ5Y20vNGUyOVN4ME1XQ0pFdDZCU0tYQndtRlBoc1RLWk5lYm1qNjVyb2EvdmlvbEo1MXE1WjdrOGlkVFV2MnAwVE9rTWhwSis2Nld0RGFwYTZjT2VsbmFlcUtqTmVIaHNRbC9mUldOZlZOVFdVclVCL3YralVhUEd0ZDUzcEtGRG9WQXdmLzRNcGs5L0IyL3ZrcXlIMzM4L1RVSEJzMlVOZWVZVWdQejhISDc4Y1NQcjF3L1VhSkpSV0ppUHJxNEJYM3d4c1Z3dTZzMmJmang0OEIrM2Jnbi9hcUZGUTROSUpLMnd4YkM1ZVYrTlFFZXhXSVpZWEpJQzl1REJ4MlJrWEtWRmkrODEwakhGWXQyaWYvVktLYzFUa0VpTWFONThyMFptUm1ibXY0U0V6TUhCWVRZdUxzczFpam9aR0hoZ2J6OUQzU1d2K0JyRlltbTU2M2QzMzBobTVqL3FWNHRJcEZ2dWRWTitXK1hJeVFtdFVYdm5uSnhRUUZRbVpiTjJvVkxKdVgxN0VpS1JsUFQwcTl5NU0xWDlkLzM2UzBSR2Z0cWdnMDVyR3dZR3BuWFNkNlFoWSsvZXJ3a012RVpob1Z4ZEIyREprbmRadEdqV005ZTQ2Smx6QWVqcUdqQm8wRUlHRGRMc0QrM3U3c3ZldlJVWEl2SHhlWkVkTytMUlFvdUdCb25FR0J1YjF6RTM3NjB1YjF3Y3hTNlZXbUJ1L2hLWEw3ZkN3TUFkVzF0QjhEUnVQSWowOUVza0pCd3BFa2dUZU9HRlFEcDB1RXhVMUZZeU02L2o2Q2o0cGUzdFoxSlltRVpLeXUvazU4Y1FIRHlMRmkwTzBLN2RuMFJHYmlFeDhhaDY1WnFWZFJ0bjU0WFkyVTBsTi9jQitma3haR1JjSVR4OE5hREN4TVJYbmZicDRySWNjL01YMWNLL1VhUDJaR2IraTFKWmdLWGxRRXhOaFNwMTF0WWpTRWc0Z3JGeGE2eXRSNkN2NzR5THkxSWVQUGlrVEswQ01TQXFOemZXMXFPS1RQeWlJaTVSbWJXTDVqRjJkdE5KUy91N2xHSWlLVldYZ2lkT1NSV0pwSFRwY2wvNzRCWkJUOC93dVFzQ25EeDVKcE1uenl5M2ZkMjZMYy9jdlZRckRiQXU4YVJwZ0ZvOEdTcEtBOVRpYVQ3L291ZCtEcXlzaHVMcCtSbGlzVjVSbGtJaFlyRU1TOHRYQ0ExZFRrTENRUndjM3NIVGN3djM3eThqTWZFWTl2YXpjSEI0bStUazAyUmwzVUVrRXFHcmE0K1JrUStYTDdmR3hXVTVMaTd2RXhhMmtvaUk5VWlsRm5oNmJzWENvaCszYjQ5VFp5WThhUnJnazZLcU5NQm5BYkd4ZDhuS1NxbXlJMkZWZU5iVEFKOFU5WjBHcUZVQXRBcUFGbG9GNExtRlZnRjRNaVFraEpHZG5VclRwdTIwQ3NDenFBQ29WUFdyQU1DUmVtYXYzMzdUSTBYUHR3Q285OGZ2T1lmb2VYLys2bGtDOVQxYnp4TlF6eGZRcDgrR2V1Vi83NzMzbnV2blg1c1hwNFVXV21paGhSWmFCVUFMTGVvSHUzYnR3dFRVbEN0WHJqeVgvRnBvb1lVV1R4dlBaQ0dncTFmdnMzMzdXVUpENHpFMjFrZEhSNHkrdm96Qmd6dVFtWm1McWFraHc0ZjcxaG4vL2F0WE9idDlPL0dob2VnYkd5UFcwVUdtcjArSHdZUEp6Y3pFME5RVTMrSER0VTlYRGFDdnI0K3BxU202dXBwcFl2ZnUzV1BwMHFYRXhNU1FrNVBEblR0MzFDMDNiOTY4U1lzV0xmNWY4R3VoaFJZbHlNL1B4OS9mbjh1WEw1T2Ftb3BFSW1IUm9rV1ltRlJkWXlFcUtvb3Z2dmdDZ0taTm05SzhlWE02ZCs3Y0lGMWRPanF3WmcwMGFnUno1c0R3NFRCMUtreVlBRHQzd2krL1FIUTBORzhPbjMwR3g0OEwyenc5NGRBaHpmaTVOV3ZnL2ZkQnBSTE9kL1FvSERzRzI3ZURVZ2ttSnNMeGZuN3c4Q0YwN0FqdnZmZU1XUUFLQ3hVc1hMaWYzcjAvcEZldjV2ajVmY0NwVTRzNWZud2gyN1pONDlxMU1LWk4yMDVLU2xhZDhDc0tDOW0vY0NFZjl1NU44MTY5K01EUGo4V25Uckh3K0hHbWJkdEcyTFZyYko4MmpheVVtcFVZN2RLbEMwZVBIaTNxTEJqQmp6Lyt5T0hEaDdsNjlTcUhEeCttVzdkdTZySEd4c1pNbURDQnhNUkUwdFBUK2VhYmI5Ui94NDhmUnk2WEk1UEo4UER3WU0yYU5haFVLbUppWWpoNThpVFhybDNqekpremRPblNwVUh4QTR3Wk00YUlpQWhhdFNycFZYLzc5bTNhdFd0SDM3NTl1WFRwRW9HQmdVUkZSVEZreUpCYS8yN3JtLy8vSTF4ZFhkbStmVHZIang5WGI1czdkeTZIRHg5K0x2aTFlSHpvNnVyU3MyZFBoaGN0cEJRS0JlZlBuMy9rY2VmT25WUC9mL1RvMFhUcDBxWEJ4cmtVRnNLdFczRDlPaFFVd0pVckVCWW1DUDNRVVBqakQwR0kvKzkva0o0T0lTRnc0b1R3ZWY3OGt2T1lta0xMbHRDamgvQTVJd1B1M29YejV3WGhEeVhISHowcUJINy84SU53bm1kS0FYanZ2ZS9ZdE9rVUJ3N01adXpZYmtna0paZHZZbUxBeHgrUFk5NjhnWFdtQUh6MzNudWMyclNKMlFjTzBHM3NXTVNTa3B4aUF4TVR4bjM4TVFQbnphdXhBbkR4NGtYKzk3Ly9BVEJyMWl3R0RSckV5SkVqNmRhdEc1R1JrWnc3ZDQ2NWMrY0NrSm1aeWI1OSs3aHc0UUp4Y1hGTW1qUkovVGRreUJEbXpwMkxrWkVSSVNFaHZQLysreWlWU3ZidjM4L2d3WVB4OWZWRkxwZmo1K2Vuc1hLdGIvN0tzR25USnF5c3JKaGVLbFRhMnRxYVE0Y09hUWpxdWtKOTh6OHRkT3JVaWJObno2SlNxVGg0OENBSER4N0UzOStmd1lNSFA5RjU0K0xpVUNnVTZPdVhGQlk2ZmZvME8zYnNhRkQ4V2pSY21KaVlZR3BxaWxnczVzcVZLK1RrNUZRNk5nR0NKKzhBQUNBQVNVUkJWRGs1bWRqWVdMWEFOekF3ZUtidnZVc1hlT09ORXNGZURDY25pSXdzK2R5bWpXQTVHRDI2K3VjK2V4WjY5MzZHRklDQWdIdDg4c2twT25mMlpQRGd5cnQ0clZ3NWdzSkNSYTN6M3dzSTROUW5uK0RadVRNZHFuZ3hqVmk1RWtWaFlZM1BuNWVYVitHMkJRc1c4UDMzMzdOeDQwYmF0bTJyM2xkUVVGRGhlWGJ2M2sxR2hsQVFTYVZTcWMzVkFISzVuTTJiTjZPcnE4dllzV01iRkg5RlNFaElJQ1ltaHBDUUVJM3RVcW1VR1RObTFQa3pWOS84VHd2Ky92NGNPaVMwNVgzOTlkZDUvZlhYT1hyMEtNZU9IZE93L3RRVU9UazVSRWRIYTJ3TERnN203Tm16RFlwZmk0WUxrVWlFaVlrSkxWdTJwS0NnZ0V1WExsVTY5dSsvLzlaWThUOHJHUzZ0VzhOcnI1VlBpYng0RWZic2dZU0VrbTJEQnNIczJab1dBRTlQNk54WlVBeU1xbG1VVWFXQ3ZMeG5TQUhZdXZWWEFGNTdyZW9XbnNiRytzeVk4Vkt0OC8rNmRTc0FIVjZydWtHSnZyRXhMOVd5Y0ZpMWFoVVNpWVRaczJkWE9XN1lzR0ZZV1ZsUldJVUNVcHgybDVtWjJXRDRvNk9qV2IxNk5jN096Z1FFbERUQTZkKy9QM2w1ZVhUcDBvV0RCeldielF3WU1BQnJhMnNBUHZua0UzUjFkUkdKUkd6ZXZCbUF2WHYzWW1OamcwZ2tZdHk0Y2R5N2QwOHRiTHk4dk9qVXFaTmFPTlEzZjhNd1J4YVdVK1RFWWpHalJvMTZvdk5XdC85R2ZmTnIwYkRSbzJnWmZPblNKWTFGUlRHeXM3TUpEZzZtUTRjT3o5eTlCUVlLcHYzS2F1TGN1aVg0OVFGKy9CSGk0d1dUUDRDUGozRHNpUk5DM01ESWtlV1BOekFBQ3d2TmJiMTdDMWFBR2lzQU4yL2VaTldxVmJpNHVDQVNpUkNKUkRnNU9mSGhoeDl5OCtiTk9wdWtjK2Z1QU5Dc21kMGp4MXBhR3RjNi81MGkzNUpkczJhUEhHdHNXYnU5b2UvZXZVdFNVaEsrdnBxQmpiYTJ0bXIvKzhtVEo4c0pxYkxRMDlOajRjS0ZwS2VuYytEQWdRYkRmL3YyYmM2ZlA4K0RCdzgweHMrYU5Zc3hZOGFRbEpURTZOR2o4ZlgxeGMvUER3QUhCd2NhTnhacTM4K2ZQNTg1YzRSR05uMzdDazFySms2Y3lPclZxd0VZTldvVTd1N3VnR0J1dHJHeDRjY2ZmOFRlM3I1QjhEZGtGQ3RxUzVjdVplUEdqWHo5OWRlY09IRUNmWDE5bWpadHlzbVRKd2tNREFUQXk4dUx2Lzc2aTU5KytxbkNjelZyMW96ZHUzZHIrT1FiT3I4V0RRTzJ0clo0ZUhpUWs1TlRZYWJPeFlzWGFkKytQVEtaN0ptNUp4MGRZZlh2N1EweW1XREtkM0VCT3p0d2RZVlhYb0doUTJIZE9wQkl3TXNMMnJZVkxBQWZmZ2dEQjhLQ0JWQnM2RWhQRjRJSnZid0VxOERvMFVKQTRlYk5RaXlBbHhlOCtpcU1HQUV2dlFTTEZqMkdBdURqNDhNSEgzekEzcjE3MWR2Mjd0M0xpaFVyOFBIeHFaT0pVaXBWeE1ZS2ZuVUxDK09uL2tXcGxFcFNZbU1GNFY1V2xYcEtTRTVPeHNyS1NtTmJhUi84NE1HRFdiOStmWVhIZHV6WWtXWExsckZ6NTA1Q1FrSm8yN1l0a2FXZFNQWE0zNjlmUDE1NTVaVnl4NG5GWXI3OTlsdSsvZlpiN08zdHVYejVNbjM2OUtGZnYzN2x6UEl6WnN4QUpCTHg3YmZmcXJjTkh6NGNrVWpFbmoxNzFOdUNnNE54ZDNkWEMrK0d3TjhRTVdmT0hQTHk4dGk3ZHk5ZVhsNjgvLzc3TEZ5NGtEZmZmSk5PblRyUnAwOGZ3c0xDTklScGNIQXd2LzMyVzZYbkRBME5KU01qUThNbjMxRDV0V2g0Nk5tekp3RG56NS9Yc093VUZCUnc3ZG8xT25mdS9FemRUMkdoSU1EbnpST0NBSThjZ1JkZmhKZ1llUGxsK1BoaklRaHc3bHhJVFlXZVBlSHdZY2pPaHI1OTRhZWZZT0pFaUlzVHpuZjJyR0FaQ0E0VzlpOWJCdnYyQ2RVbWk0L2Z1RkhnV2JSSUNCWjhiQmVBblYzSlN0elIwYkZPSjBvc0ZpR1Q2UlN0Q0hLZitoY2xFb3ZSS2RJc2MydGdPcTlObUptWmtaU1VWT1dZbjMvK3VjTHRWNjVjNGFPUFBtTGN1SEhNbmoyYnNMQ3dCc2RmTnYydU5NYU1HVU5JU0FqcjE2L0gxTlNVTTJmTzBMNTlldzF6dll1TEM3MTc5MmJmdm4wb0ZFSU15SWtUSjNCemMrUFVxVlBFRmYxS2R1M2FwUkhVMTFENEd3cG16WnJGdW5YcnNMS3lvbVBIamdRSEJ4TWFHa3EvZnYwUWk4VzgvUExMcUZRcUdoWGJKTXNxeTFWVWRwVEw1U1NVZG1nMlFINHRHaTZhTm0yS2c0TURhV2xwYXFzUHdOV3JWL0gyOXNiUTBGQTdTVFdWclk5N29LUlVCTHhZWFBlaEJHM2FDSDIzNzk2TnJaZUpjbW5UQm9EWXUzZWZPcmVibXh0V1ZsYjgvZmZmVlk0TENBZ2dJaUxpbWVTdktHRG52LzlLV2pmcjYrdXplUEZpUWtOREdUeDRNSm1abWN5Y3FkbVJhOXEwYWNURXhIRG16QmxVS2hWSGpoemgwS0ZERkJZV3NtdlhMdVJ5T1RkdjNxelFUMWpmL0EwRlc3ZHVaY21TSmN5WU1VUHQwaXNzTE1UTXpJejE2OWNURVJGQlVsTFNZd2RZUGFyMDg5UG1EODdPNXUzZ1lFUy8vMDZmNjljclBTNDJQeCtabngrVzU4NnhKemFXYkVYdEJCcG5CMmNUL0hZd3Y0dCs1M3FmeXZuelkvUHhrL2x4enZJY3NYdGlVV1RYRG45T3psM3UzVnZBNzcrTCtPc3ZFd29MTXlvZG01VjFpOTkvRi9Ibm4wWkVSMitqb09EcEsxUEZzUURuenAxRHBWS2hWQ3E1ZE9uU1l3V0xpc1ZLMXErSEw3OFVUUEJqeGdpcGQvYjI4T3V2OE00N2dnbisvZmVGUFBvLy9oQlc3RHQybEEvWVc3T214QlRmcUpHd0dwODVFNHBGWS9IeHk1WUpLL0tkTzZHc3AxZ3NGc3p6Q29Xd1N0KzlXN2dPTjdlYXo5UElrVUlxWWNuaURDcDY3VHd6UVlBVEp3cGYvT0hEL284Y0d4SVNWL3NQM3NTSkFQaFhJNGM0cm94NStFbXhkT2xTQ2dvSzFLbDZqOEw0OGVQL1gvRHYyTEdqWE1DUGhZVUZodzhmeHRuWm1jREFRSTNnc1NGRGhtQmhZYUgyOHc0WU1JQTJiZHJnNit2TGpoMDdPSG55WkkxU3krcWJ2NkdnUzVjdWJOaXdnY1dMRjNQbnpoMk5mUXFGUW1NeDhLenhleGthc3RuVEV4MlJDTCtVRkc1VVl1SDdJam9hSmREYjNKdzNtalRCc0pidTJkRExFTS9Obm9oMFJLVDRwWkI1bzJMKzZDK2lRUW5tdmMxcDhrWVRKSWExdzI5ZzRJbTcreVowZGUwcExNd2dOblpucFdNakk0VUFWMVBUN3RqYnowUW1zMzdxejJMejVzMnh0TFFrSVNHQjRPQmdidDY4aVoyZEhlYm01alUrbDFJcHJ2YzhmTTNyRVFSL2NqSjg4Z2xNbmd4UlVmRGRkeldmcDFPbkJFV21HTys4SXdRYlByTUt3SlFwdmZIMWRlZkNoV0IyN3ZTcmROeUZDOEhjdmgxVjYveTlwMHpCM2RlWDRBc1g4TnRaK1k4aytNSUZvbTdmcnZINUt6SkI2K2pvc0dMRkNzYU5HOGZVcVZNMVhuNVNxUlNwVkZydW1MNTkrMkpqWTZOZTFVcWwwbXI1UE91YnZ5SmtabVpxK05TTElaUEpjSEJ3d05uWkdSMGRIWTN0NDhlUDU4Y2ZmK1NMTDc1Zzh1VEpBRXlmUHAzSXlFaVdMRmxTcmZURGhzTC9ORkY4SDZYdnB4anQyN2ZId01BQVkyTmoyclp0aTZXbEpRWUdCcmk0dUJBZkg0K0xpd3QyZG5ZMGE5YU1IajE2MExoeFkvV3pVUndvWE5yU1V0SHF2VDc1cFNJUnZjek1NSmRLK2FTQzJKaGNwWklyNmVrNDYra2hxNFBVTXBGVWhGa3ZNNlRtVWlJL0tjK3Z6RldTZmlVZFBXYzlSTEs2U1cwek1IREZ5S2dGa1pHZm9WS1Z0eTdJNVVuazVvWWhrUmdpa2RSZmZyMUlKRkpiQWY3NjZ5LysvdnR2OWVmYVZ6enJQZysvWXNXa3REd1RnZ1JyaXR3eW52TDc5NkdDNUlsblJ3SFEwWkh3ODg5TDZOalJqZW5UdjJiZXZMMUVScGI0cERNeWN0bTY5VmV1WHc5bnlKQ090YzR2MGRGaHljOC80OWF4STE5UG44N2VlZk5JS3ZVVTVHWms4T3ZXcllSZnYwN0hHbGFLNjlxMUs0c1dMUUpnN2RxMTdOMjdsNTA3ZDNMMjdGa2NIQnhvMjdZdCsvZnZCNFJLZk5PbVRhTjM3OTY0dUxodzVNZ1JkU1QrcVZPbitPbW5uemgxNmhRZUhoNnNYYnNXc1ZqTWE2Kzl4cGd4WXlvVTJBMkJIMHJxRUpTdEx6QnIxaXdOdnpyQTk5OS9UMEJBQUo5KyttbTU4MHlkT3BXQ2dnSjY5KzZ0Vmp4R2pScUZpWWtKM2J0M3I5UjMvRFQ0dTNUcFF1Zk9uZW5WcTFlNTR4NCtmTWk3Nzc3THhvMGI2ZGl4SStQR2pVTXVsN044K1hKc2JHeUlpb29pSUNBQUV4TVRQdm5rRS9VeEF3WU13Ti9mditnM2tLSE9SaWhHUkVRRTNicDFZK0RBZ2F4YXRZb1hYM3lSMjJVVTFFNmRPakc2Nk8yMWNPRkNIQndjTlBZZlBYcVVyS3dzYnQyNlJmdjI3Zm5qanorWVBIa3kyZG5aK1BuNTRlZm54My8vL2Nla1NaTTRkKzRjNmVucDlPalJBeWNuSi9yMTYwZXJWcTNvMXEwYkxpNHU5TzNiRng4Zkg0Mk1rdnJtQnpDUVNIalR6bzZEOGZIRTV1ZHI3TnNmRjhkNFc5czZmYjlKRENUWXZXbEgvTUY0OG1NMStlUDJ4MkU3M3JiTzM3R09qblBJeTN0QVl1S3g4aGFJNk8zWTI3LzUxTi83RmJtTTJyUnBnN0d4TVE4ZVBFQmZYMThqSHEzME1kWHRORnFmZWZpUFhIajJMa2tQWExkT2lQSS9kUXE2ZGhWY0RkdTNRM0ZDMWZ6NVFzcGdXYlJyQjVjdkM4ZVVrNnZQa2luUzNOeUlTNWZXc0dmUG4zei8vVVhhdDM4UG1Vd0hGeGNyWEZ5c21EbnpKVHAxOHFnemZpTnpjOVpjdXNTZmUvWnc4ZnZ2ZWE5OWUzUmtNcXhjWExCeWNlR2xtVFB4Nk5TcHh1ZTljT0VDRnk1Y3FQYXFkTWVPSGRXcVpyWmt5UktXTEZuUzRQbC8rZVVYZGhaWlZUWnUzSWlob1NIdDJnbjl4Yk96czVrNGNTTHo1czNEemMyTm5Kd2NyS3lzT0hQbWpEb3F1S3lKOEtXWFh1THR0OTh1dGJveFlQejQ4WXdiTjY1ZStZY09IY3IrL2Z1SmpJeEVwVkpwckVTM2J0MUsxNjVkR1RGaUJMTm16V0xUcGsxSXBWS1dMVnZHdG0zYmtNbGsrUHI2TW43OGVMVXkwcmh4WTNyMjdFbW5vbWZ1MjIrLzVidnZ2bVA1OHVWWUZqa1luWjJkYWRldUhjN096c3laTTRjVksxYXdZTUVDVHA4K3JlYjI5L2ZueFJkZnJQVDdpWTZPeHJ2VU11VHJyNy9XMkYvV3JWRTZHNlRzSFBXdVlObFQzL3hxWmMvQmdVMFBIdkI1VkJUcmloeXZLdUJRUWdLblc3ZG0xV01FejlZRURyTWNlTERwQVZHZlIrRzJyc2p4cTRLRVF3bTBQdDJhc0ZWMXkyOWpNNWJRMENWRVJuNkt0ZldJVXNKS1RsTFNLZHEzdjhDZE8xT2U2anMvSnllSDdPenNjdGFpcmwyN2N2cjA2WEtyLzl6Y1hMWGd6ODdPcmxUaEw0M2lQSHczTjJqZnZ2eitzbm40TFZvSUp2OUxsMHJ5OE9QamhiUytrU01GMzcybWRRWEtHa0dMOC9BclEvLyswS3VYWUduWXRBa01EWVVNZ1k0ZElTVkZzRXhNbVNLY283ZzB6Y21Ud3ZheXVIYXRpb1Uxenhna0VqRlRwNzdJMUtrdjFndS9XQ0xoeGFsVGVYSHFWTFNvSGJ6eXlpc1ZwdUVWV3hacWlvcFN3VDcvL1BNR3dkK3ZYeitjblozTG1hRmJ0MjdOdSsrK2k0R0JBUU1HREdEQ2hBbUFFSHc0Wk1nUURoNDhxTjUvNE1BQkZpMWFSR0JnSUcyS2dsT1ZTaVdwcWFtTUdUT0c3ZHUzczJ6WnNncXZMU3NyaXlaTm1tZ2Z1Z3JRUkZlWFVUWTJiSStKWWJtTEM0WVNDYjhsSjlQTHpBelpVd2gwMW0yaWk4MG9HMksyeCtDeTNBV0pvWVRrMzVJeDYyV0dXRmIzL0dLeEhuWjJieElldm9iMGRIOU1UQVRGTWlIaENJMGJEMEVrZW5yaUlqOC9uMnZYcm5IdDJqV1NrcEk0ZWZJa0hoNGVOQ3VxdytMcjY4dmR1M2ZWOVRVQUxsKytyR0hkT25Ma0NNMmJOK2VGRjE2bzBPMGtGaXRwM1ZvSXZxc3NEOS9EQTdwMWcxV3JOUFB3VDV5QUxWdUVvTDMzM2hQT2w1NE9IM3dnS0FiRmVmaDM3d29yNzhXTFMvTHdmWHlFZ0x3aW8ydUYrUFZYS0pWa0JBalhNV3FVb0FSVWtiUlVMWmZBTTZzQWFGSGFJbUxPdkhuejhQRHdZR1JGSmFEcWNyWGk0TUMyYmR2bzNyMDdjWEZ4ckY2OXVrYkZoWjRuakI0OW11VGtaTjU1NXgyMU8yRGZ2bjNzMkxGRDNlQmt5SkFoS0JRSzNucnJMWm8yYmNyMjdkdlZ4MCtZTUlINTgrY3pjK1pNYkd4c1VDZ1VCQVlHOHVlZmYvTHV1KzhXclV4K1pOQ2dRUmdZR05DclZ5OFdMMTZzNFUrL2ZmczJ1M2Z2cGxHalJxeFlzVUw3cFZTQ3VZNk9ISWlMWTA5c0xMTWNITmdlSGMyT3gzSENQaVljNXpvU2R5Q08yRDJ4T014eUlIcDdOTjQ3dkovaTcvcHRIano0bUFjUFBxVmx5eU1BeE1Uc3BHWExvMC8xZTlEVjFhVno1ODZWNXZicjZ1cVdTNmQ5NFlVWGVPR0ZGNnJOb1ZTS05ZVHdrU1BDSHdoNStNVTRkcXpZbWxTeXJhamVGNlZyVGhYbjRaZmVEMEl1ZnRuamkzbXFDME5EK1A1N1lkV3ZVSlNzK3F2cDVhaGM2ZFArNUo5TjZPam84T0tMTHpKNDhPQnFtYmxxRXlLUmlGMjdkbkhod2dWbXpwekp3NGNQMmI5L1AvMzc5Njh6enVUa1pLWk5tOGFiYjc3SjJMRmo4Zkx5MGxqVlg3MTZsV25UcHRHbVRSdlMwOU1aUFhvMHhzYkdOR3ZXN0pFVkNpdCtPU2hadTNZdG8wYU5Zc2FNR1hoN2UvUFdXMitSWCtRZmpveU01SU1QUHNEZTNwNm9xQ2crL1BCREdqZHVqTDI5UGN1WEw5ZklEZ2dORGVYbXpadjg4TU1QWEwxNmxUdDM3bkQyN0ZudWxrb3BqWXFLWXZqdzRkeTllNWV1WGJ2U3QyOWZkYkdUYnQyNmtaeWN6T2JObXhrd1lBRGp4NDlYRitJcVRzRTllL1lzLy96ekQzLy8vVGZtNXVZY1BhcjV3bTdldkRtVEowOW14WW9WVC8xNWVaYlExdGlZN21abWJJbUs0bFpXRmxZeUdaWlZ4SzdVTm96YkdtUFczWXlvTFZGazNjcENaaVZEYXZuMCtHVXlHNnl0Ui9IdzRYRnljeU5JVC9mSDBOQVRxZFRzLysxM2JtY25tTW5uenhjRTYvejUwS21Uc0VwUFQ0ZHg0MkRYTHBnMHFmeXhYMzRwVk9rcldaUUpWZm9tVGdSL2Y4R1UzN28xcEtVSjUzN3ROZmpxcTBkWllqVFBDVUpBWXVQR1FpdmZKazJFTVVaR2tKbFpFdTNmcWxWNVY4TWo1WWoySi85c29yQ3drQ05IanRDblR4K2NuSnllS25lclZxMVl0MjRkZi83NUp5QVV2QWtKQ1dIa3lKSDgrdXV2ZGNJNWZ2eDRjbk56MVp5TEZ5L21uWGZlb1UrZlBsaGJXL1Bnd1FPT0hqMktxYWtwQ3hjdTVLV1hYcUpIang0c1g3NmMwYU5IbzZlbngydVA2T05RR3BzMmJXTFZxbFdrcDZlanE2dkw2ZE9uZWVXVlYyalpzaVV6WnN6Z3hvMGJuRDE3bHBpWUdENysrR01jSEJ6NC9QUFAyYkJoQXg5OTlCRlpXVm5xdmdCWHIxNVZuL2Vqano3QzJkbVpwVXVYYXZEOThNTVB2UEhHRzVpYW1ySjY5V3IyNzk5UFhsNGVCZ1lHNm40Q3AwNmRZdEdpUll3Yk53NTNkM2QxWTVSLy8vMlhBUU1HcU4wWU5qWTJyRnExNm9ucTZEczdPek5seWhTV0wxL095Wk1uQ1MxS0t0YlgxMmZNbURFNE9qcldxSjhFQ01HbXk1Y3ZaOXUyYlp3OGVmS3A4dmZvMFlQUFAvOGNGeGNYTGwyNnhJd1pNd2dQRDY5dzdEeEhSMTY3Y1lNUk4yOXl0SGhKOXhUaE9NK1JHNi9kNE9hSW03UThXZy84am5PSmk5dFBWTlJuNU9mSDBiUnAzVnFNYnQ2OHllKy8vMDVDUWdJdUxpN282dXFTa3BLQ3Q3YzNmZnIwS1pjWmN2MzZkYVJTYVlXVlowdWZ5OWJXRmt0TFN4UUtCZW5wNmRqYjI5T3paMC9NekRTVm1aZ1lDQStIYytmZ24zK0tGREZqUWJpbXBncEJkbi85QlRkdVFHbVBZTE5tWUdzTFE0WUlhWDBndUEwS0NtRHZYaUZZcjNWckljWWdMVTF3R3dENCtWVXUrSWNORStyMkR4OHVwQTArZkZoOHo4TDIzMzRUckE2dFdvR0RBL3o5dHhBY0dCQUFXN2NLcHY0dVhZVFVSRjFkNk5kUHVEYzNOK0gvbHk1cFpoblV1d0tRa1pITC92MS9zM3IxRHlRa3BETjh1QytiTm8zSHlha3h0MjVGOGRaYk8wbE1UR2ZGaWhGMDc5Nk05OTgveEo0OWYySmpZOHFPSFc4eWNLQVFyQlVYbDhxNzczN0RiNzhGOHRGSG81azI3VVhXckRuR3laTlhlZUVGZDNYcjRMQ3dCTTZlL1k4bFM0YXdkcTBRZVh6VHo0L1B4NDJqVmI5K3lQVDBBQ2pJemVYY3ZuMTRkdW5DKzJmUDhzdVdMUno2NEFNVWNqbFR2dmlDWG0rOGdVeGZuOEtDQWs1dTJNRGhGU3NZTUhjdWZkOThrLy9PbnVXSDFhdEpUMGpBZC9od3htL2FSR01uSjZKdTNXTG5XMitSbnBqSWlCVXI2RktUdkpGS1VGRmpqTHJHblR0M05LTGxzN096dVh6NXNucDFYQmRJUzB1alM1Y3VKU3Uxb3M2RTRlSGhOR3ZXak9IRGgvUHBwNTl5OSs1ZDFxeFpveTViM0tSSkV3WVBIc3phdFd0cnBBQ2twYVhoNCtPalRvOHM1aXV1WXZqcXE2L2k3KzlQUUVBQXI3MzJtanFJcldmUG5yaTZ1ckp0MnpaV3JGaWg4YktKam81bTNicDFOR3JVaU9IRGgydlVMVTlPVHNiWDE1Y3hZOGFRbjUvUHFsV3JOTnFaVHBnd1FaMWVhVzl2ei9UcDAyblRwZzF4Y1hITW1UT0hOV3ZXcU1kYVdscmk3Ky9QeG8wYkdUcDBLUC8rK3k5UlVWRzgvdnJyNm5NOENoRVJFV3pac29YbHk1Znp6VGZmY0tMNDdZV1FmbVZzYkZ3akFXeG1ab1pFSXFGNzkrNTg5YWdsVUMzem01bVo4ZmJiYnpOdDJqUU1EQXo0NnF1dk9INzhPSzFidHdaQW9WS1JVeXJMNDFWTFMxejE5WEhTMDhPN1ZIVzVBcFdLL0tLM1o2cGN6dmFZR042L2Y1ODJ4c1ljYmRrU0J6MDl2b3lPWmtORUJGOTRlV0dxbzhPQ2UvZTRuSjdPTmk4dlp0amI4eUF2anhILy9VZEhFeE9XdTdnQU1sUUtGWXFjRW43TFZ5M1JkOVZIejBrUFErOFNmbFdCQ21XK3dKOGZuYytkcVhkSS9pMFpqODBlT0w0clZHTk5QcDNNZnlQK3czT0xKeUpkRVVIVGdqRDBOcVRsNFpib3Urb2pUNUZ6YTV3UUt1NjExWXVLRm96R3htMHdNK3RPVE13T3pNMTdZV2pvVmVuY1ptWDl4NjFiWTdHMEhLQ09FWWlQL3g0UTRldjdIN201b1ZYdUI2RzhmRUpDQWdrSkNVeVpNZ1VkSFIzQ3c4UDUrdXV2U1V0TDQvWFhYOWZndkhUcEVycTZ1aFVxQUQ0K1BqeDgrSkF6Wjg0d2MrWk05VzhzTXpPVFE0Y084Yi8vL1kvSmt5Zmo3T3hjN3RoT25RUnJRS2RPSlg3OVlyaTVRVkUvTDQxdFU2WUllZnJGQ3NEcDAwTDlnR2JOaEhpQVAvNFF0a3NrZ2pYQTBsSll1VmYwRXlpdUExQ1JleUFwU1loSEtFYnBrS2FpZUdXZ0pDTkFzTlNXL0wreXRpT1ByUUNVcnNXc2VJS3FXSTBhNmZQMjIvM28yN2NsSFRvSXMrN2tKTlJKZDNXMXh0VFVnT1BIRjZoN0FPemVQWk9IRHpPNGVER1lidDFLR3ZQWTJwcmg3bTdEdEduejZkdFgwSnBOVEF5NGVuVWR1cnJTSW1HcG9GT25aYlJ1N2N6S2xTVlJybG5KeWF3NmZ4NmJVaVdYOXJ6ekRucEdSc3phdHcrWnZqNnZ2ZmNlRWgwZDlpOWNpS09QRDdJaVc0dU9USVpieDQ0TVhiYU1VVVhOWDJ3OVBHalp0eS92RlpWZWFseTBRcmQyZGNYQTFKUUZ4NC9YVzArQjJrQkZyWUJ0YlcyckRMUjdVbHk4ZUJHUlNFUnFhaXI3OSs5WFd4cEtYNHRZTE1iTXpFeWpaOEdnUVlOd2RIVGsyclZyTlNvYXMzYnRXajc2NkNQa2NqbkhqeC9uOTZKY25MSjhBSjZlbnVwdE5qWTJEQjgrbkgzNzloRVlHS2lSOG1kaFlVRkJRUUV5bWF4YzA1STFhOVpvQ1BHeWNITnp3NjNVODdsbHl4YjF2SjhyYWxSVmpQYnQyMnVrUUpYZFh4TXJVMFU0ZWZKa3RWT3NpcEdhbXNxNWMrZUlqNDkvNnZ3ZUhoNU1uVHBWM2FiNnJiZmU0dmZmZjhmUzBwSzdPVG5zam9raElEMmRYYkd4RExPeXdsUkhoM2NkSFhFdlVzQ2k4L001R0I5UFZGNGVPUW9GMzhUR01zTGFtdmVjblpHSVJId2VGVVhqb3U4elM2SGdselp0YUY2a09QemFwZzB0L1AxUkZGMnZvVVJDTjFOVFBpbDZtK2ZjelNGbWR3enBBZW5FN29yRmFwZ1ZPcVk2T0w3cmlJRzdnVnJZeHgrTUp5OHFEMFdPZ3RodllyRWVZVTJMNzF2ZzcrbVAxS0xFUlNDemxlRzIzbzBtVTRSQXo3d0hlY1R0aTBQUFdWallTTTJsR0xnWjRMYmVEWW1CcE5SdldyUE10NFBESFA3N2J5ajI5aVhaTENxVkVxVXlENFVpcDlRQ0pKazJiWDVGVjlldVNIRytTRVRFQnRxMjlVTWlNWGprZnJVZ0tyUEtkM0Z4d2RIUmtSczNiakJzMkRCMUNuRjBkRFQ2K3ZyY3UzZVBodzhmVnRoVG82SmFFc2JHeGt5Y09KRXRXN2J3N2JmZnNtalJvbkpweWY3K2dnVWdOYlZrbTFRcVZPNGJPVkpvdmxNTUt5c2g3VThpRVZiOEhUc0toWVNTazRWTWdwa3poVUpBVTZjS1NvRkNJUVQyQVhUdlh2WHo2dVFFNjljTHFZWEZ5VmFOR3d2VkJDdHlRMVFFVjFmaEhEdDNDbGFEU3QwTmovdENqb29xS2JZVEcvdms1WGs5UEd6WnRtMGFQL3dRd01tVGdzbDA3dHk5ckZuemVya0dRRjk5TlEybFVzV1NKU1Vsa3NMREU4bk96bGNMZjRDQkE5dXFoVC9BeXBXSHVYVXJpZ01IWnF0N0N3QTR0bXlwSWZ4dm5EbkRyMXUzTW1uelpxeWJOaTA1Mzd4NXVIWHN5TzVaczFBVXJid1ZoWVg4OWMwM0RIdi9mVTJCNk9IQnRHM2JDUGpoQjY0V21UdjN6cDNMNjJ2V1BOUEN2eUo0ZVhrUkZ4ZW5Ocy9YQmZMeThsaTBhQkh6NTgrblQ1OCtOYXFuNytibWhsS3ByTEcxWk5ldVhRd2JOZ3h6YzNNMmJOaFFJejZnbkVWRVgxK2Y1czJiUDVNdFM0dlJva1VMT25ic2lGd3VwMjNidG56Ly9mZDgvZlhYYk51MmpaaVlHS1pPbmNxNWMrZDQ1NTEzdUhqeFlybnkwVS9hbnZkeCtDOWZ2cXdXL3NWV25QVDBkTkxUMC9FME1HQ0R1enNadlhveHBVa1RUSXVFeDJ3SEIvb1gvVTd0ZFhWWjRPU0Vxazhma25yMFlGS3BTb0R6SEIyeGtFclpFQkhCOWN4TURNUml0ZkFITU5YUllZdW5KeXZDd2tpUnkxa1RIczRIcGQ0cEJwNEd1Rzl3cDFkR0w1cE1hWUtPcWNEdk1Oc0JpLzRDdjY2OUxrNExuT2lqNmtPUHBCNDBtU1JVQXBTYVNYRmQ0OHI5WmZkUjVnbnpHcmMvRHZzWkpjczlwL2xPcU9RcVlyYkhBSkIrT1IyVFRpWnE0WitUYzQvdzhMVmtaOS9tL3YwUHlNNitVeVJ3Qm1OcE9RQUxpNWZVSy8zUTBFV29WQXJTMHM0VEUvTTFCUVVKR0J1M1ZRdDNwVEtYTzNmZXdNSGhiY3pNdWhjSjNxcjNQd282T2pvYVNudGdZQ0RqeG8zRDB0SlNveGRIZFNDVlN1bldyUnVabVprYVpiN0w0dSsvQlV1QW9PQUlRdmpoUTgwZ3ZpNWRCSlA3aVJOQ3FlQzVjNFh0L2ZvSi8zNzJtWkFGVUZGc2R1bnpWNFFIRHdTbElTcEtLREc4WmcyOCt5Nzg4a3RObEhkd2ROUzBBdFNLQmVEbXpac2NQMzVjbzhQWnhJa1RtVFJwRWtPR0RIbWlqb0JqeG5UbCtQRXJ6Snk1azF1M291alN4Wk9XTGN2N3QrM3N6UG40NDNITW1MR0QwYU83MEsxYk0xYXVQTUxtelpQS0NDYTdVaXZJdTJ6WWNKS1BQeDVIOCthYWhVYnN2RXBNWEZrcEtYejV4aHUwSFRpUTNsTTBjMTVGWWpFemQrOW1jZHUybk5pd2dXSExsM05xMHliNnZmMjJ1bG1RaHM5enpCaXVIRC9PenBremlicDFDODh1WFhDcUI1OWlYVUlrRWpGLy9ueW1UWnRXWnh4eXVaeGV2WHJoN2UzTjdxSWsyNUFhbEZzV2lVVFkyTmlnVitUZXFRN216WnZIcjcvK3l2WHIxOUhUMHlNdExhMUdmTVdybUlwV282VlRsNTRGakI4L0hsOWZYMlF5R1NOR2pGQVg3YmwxNnhZaWtZaHUzYm94Yk5ndy92MzNYNDRkTzhhS0ZTdm8yYk1uYjd6eGhycWVRa1BpNzlxMUsxdTNicTBWOTVsRUpPSUxMeS82WHI5T1ZGNGVYMWZRTG55WWxSVmZ4OFRRKy9wMU5ycTdZNkpUZTU3WEpsT2JFTDB0bWdlYkh0Q29ZeVBNZTVzajBpbDU2NHYxeExodmNpZm96U0NzUjF1VDhIMENIdjhyc1NVYkdMamo0cklVRjVlbFpaNWhNYTFibDRTNEd4bTF4TjE5RSs3dW15cTlsdERRcGFoVVNseGQxNVlTNENaVjdxLzhYS0ZFUmtiU3BVc1h0YVV0T3pzYlEwTkRkSFYxNmRxMUs3Lzk5aHY5Ky9ldnNzQllXUlNiL2lNakk5WFBocTB0T0RzTEpucDdlMEZ3SmlZS3ZuTkxTeUZ0YjlJa3dhZHZaUVUzYndvKytqTm5oTTU4MmRsQ2NOK3Jyd3FyOUY5K2dXKy9GWHowbjMwbVpBWllXQWdwZzRXRlFscmdsMTgreXNKZWZ0dVBQMWIvdVhqd1FLaE44RWdGamxVZTFBQUFJQUJKUkVGVXE2WVBuSStQajdvbGNGMWcyN1pwdEdneGoyUEhMblB0V3VXcnJtblRYdVRnd1l0TW5mb1ZDeGNPb24vLzFwaVpWZHdOS2pNemx3a1R0dEs5ZXpQbXpoMVFKZitPR1ROUUZoWXlvNUp5dnc3Tm16Tmt5UktPclZtRGM2dFdwTVhINDFWUmlhWGk2OXkyalhrdFduRDUyREUyVkZXUjRSbkZ2SG56MkxKbEM4bkp5WFhHY2ZueVpTNWZ2cXpPamE5cVJWbldQYUZVS2drT0RtYjQ4T0hWNWxPcFZHemR1cFhYWG51dG5OSlEwUXEyTE9mdDI3ZHAwYUtGaG11ZzlBdW9ycnRuMWpiMjc5K3Y5c0dYTGlCVVVGQkFRa0lDVjY1YzRjNmRPK3BTMFNrcEtadzZkWXFRa0pBYUtXcFBnMThxbGZMcXE2L3lSa1VWVXg0VG5VMU04RFV4SWFXd0VIRWxTNjdsTGk3MHZIYXQxak1LUkdJUm5wOTU4dThyLzJJNzNoYXZMOHY3NjYyR1doSDlSVFQvOXYwWDkwL2RvUTZxQ2FlbFhTQXFhbXM1MDM1MTl4ZmovUG56Wkdkbms1R1J3YkJod3pRVXVNREFRRHAyRktxOHRtdlhqck5uenhJWUdGZ2ppMXB4WEUzcDRrSnhjUlVYQUJJVW41TC92L1JTNmVzc3JheG9SdDlYbEExdFhNcUlYYXFEZGJVeGJKalFSMEJmWDJnbzVPa3BwQUNxVkVKc1F2SG53a0tocVpId0hxc0RCYUN1b2FNanBsa3plLzc2NnpiSGoxK3B0S3l2U0NSaXg0NForUGpNNTlDaFM1dzkrMzZsNTN6MzNXOUlUczdreno5WFZObEY3TnkrZmZnZk9jS2lreWN4S2VWSExvdWh5NVlSOE1NUGZEbDVNcCtWalF3cEE3R09EdmJObW5IN3I3KzRjdng0amNzRU4yUk1talNKZ0lBQWJwV3FQMmxvYUZpdWN0ZVRvamh3N1gvLyt4OU9UazZFaFlYeFExSFV6WVVMRjRpTGkxTlgzb3VKaVNFd01GQWQ0TFZyMXk3RVluR05jdDlGSWhIVzF0YWNPbldLdlh2M29xdXJ5NDlGNnZldFc3ZjQvUFBQbVZUS0dmZnp6ejh6ZS9ac1FBaVFQSFhxbElhZ0tnMXJhK3ZIYWx6U1VIRCsvSG1OR0F1VlNsWE9IMS9SdG9iQ3YzanhZcFl1WFZxcnorakZ0RFJldHJEZ3c3QXd6aVFuODFJRkxyNlREeDh5M2M2T1djSEJYT2pRb1ZabHNHazNVd3k5RERIeE5hbDBqT004Uis3T3ZvdFo5OXBQNTFNb2NxbzA3VDlxZjJsMDY5YXRRaCsrVXFra0tDaEl3OTFzWkdSRVFFQkFqUlNBM0tLS09LVURiQnNxbWpRUlN2OUtwVEJ0bXFBQTVPWUtzUWJEaHNFTEw0Q05qVkJncVBUbkdzbmJoblRES3BXSytmUDNjZURBYkdiTjJzWE1tVHZvMGNNYmMvT0tDeXk3dWxyajZHaFp6cVJmR2lkT1hHWFBuai9adDI4V2pvNldsWTU3K09BQnUyZlBwdGZreWJRZk5LaHFzNTlVaWxmWHJvUUVCR0JvYWxybC9leWJQNS9aQnc2d2E5WXNkc3ljaVhlUEhoalZvZ0NRU0NSUHBSMXpXY3ljT1pPbVRac1NIeDlQLy83OWtjbGtEQjA2bEJVclZ0UzZBdURtNXNiYXRXdlp1SEVqYytiTVllN2N1Unc0Y0lEMjdkdHo5ZXBWNXMyYnB5Rmd2L3p5Uy9UMTlVbE9Ua1l1bDNQaHdnVjFhZHpxWXNlT0hjeVlNWVBGaXhjemF0UW9kdXpZUVhoNE9CRVJFZmo0K0dCY1NxVVBDZ3BpNXN5WkZCUVVFQmNYeCtuVHB5dHRUMnBxYXZwTTUrSG41ZVVSR1JtSmo0K1B1bDN2czhJL2VmSmtmdnZ0TjNWS1lXMGdVNkhneE1PSGJIUjNwMUNsNHAyN2Q3blpxUlBTVWd1TnIyTmlHR05qZzZ1K1BoNlhMckUvTG80SnRkeGJRS3dycmpLaTYxSDdud1QzN3k5RnBWS1ZNKzBYRk1Rams5bFV1Yis2Q0FvS29sKy9maHA5SXVMaTR0aXlaUXRSVVZIbCtrZFVoZ2NQSGdBVnUrY2FHbUpqb1NpVG1OSlZxSE55aE9ZK0dSbkNuNk9qNXVkblZnSDQ2S05qakIzYkRUczdjN1p0bTRhMzkxeG16OTdOdDkrKzgxam5TMGhJWjlxMHJ4ZyszSmZ4NHpVMVQzLy9FSFhmQUpWU3lSY1RKMkpzWWNHazRoa3ZObDNGeDFPUW00dlZZend3eHo3NmlHNWp4Mkp1WjhlMGJkdVk2KzNON3RtemVhZUNEbk9QZzVFalI5S25UeC9Nek15WU9IRWlCdzRjZUtLTWpPcGl4b3daZkZua3hGcXdZRUhKU3VqaVJmVVByTFpSVVYrQmhJU0VDazE4Wld2RlB3NzY5KzlQUkVSRW1XZW00bGJVUzVjdXhiNnlQSnR5cGtCakRBME5ud2xoWDZ4WWxyV2F1Ymk0MEs5ZlA3VUFyaWl6b3JKc2k4cTZBZFkxLy9UcDB5a29LT0RodzRjNE96dGphMnNyOUJkNHd1ZDF4ZjM3TENueUs4OXpkR1JuVEF3Ykl5SllXdlMrdUptVlJWcGhJVzJMRk1aMWJtNHN1bmVQVnkwdE1hdEZkNEJLcVFMbDQrOS9YS1NsblM4eTdmK2hZZHBQU2ZGREpyTWlKK2RlbGZ1cmk1Q1FFSWFVc1o3YTJ0cGlaV1ZGUUVCQXRSU0F3c0pDenA4L2o0V0ZCUzJmc1ZpczRycGV0VzI0YURBS3dLRkRRbEdUM3IxYkFHQmpZOG9ubjB4Zzh1UnREQnpZanRHanUxVHlwU29vTEZSVW92Ri9pVlNxdzFkZlRTdGprbEx5M1hjWDFBckFqNXMyRVhUK1BCK2VPNGUrc1diR3dhbFBQbUZFQmVaalJXRWh5a3JTbEFBdUhUb0VRSXVpNWlPbU5qWk0rT1FUdGsyZVRMdUJBMnVsQnNEaHc0YzVmUGp3VS8rdXZ2cnFxMnJsY210Ukh2cjYrby9kSHZscHd0blptUmt6WmdCQ2g3N2lHZ3hHUmthTUdER0N2bjM3MHFKRkMzcjA2SUcxdFRXOWUvZm1qei8rb0gvLy9yaTZ1akp1M0RndVhicEVVRkFRSUpSdUhUcDBLRTJhTkdIbzBLSGN1WE5Ib3hKaVhmSy85ZFpiZlBIRkYrVTRPbmZ1TE5SWWZReEU1dVh4WG1nb2Q3T3ptVmVVNXZ0UUxzZEtKbU5sV0JqbVVpbEdFZ256NzkxalphbW9mNENFZ2dKRzNMekpGMTVld0pPLzBWUCtTQ0VuT0llazAwbVk5VFJEejFFemJxVWdvWURFWTRua3grYVQ5Rk1TbGdNdGErVVpVYW5rM0xrekdUMDlCMUpTenBDU2NxYm9uWnhPUXNJUnVuUzV6K1hMclN2ZDM3VnJKUENMV2ppREVQQmIxZ1VRSFIxZGFhQ2ZwNmNuL3Y3KzlPL2ZYMjJWcXloOU5EYzNsOE9IRDVPVGs4T1VLVk9xblE1Y1g2aElSeDQ0RVA3OXQxZzVMcXNzVis4YzVjYW82c3BaVjAxRVJIekp1blhIMmJuVGo0VUxCL0hCQjhNeE1OQWxMMC9PaGcwbldMbnlDUHI2TWxhdkhzV2JiL2JGeUVpdlNJUE00dmp4Szh5WXNRTVhGeXMyYlJyUG9FRWxrUnk3ZC8vSmxDbmJhTnZXaFRadFNsYnZjcm1DSzFkQzZkVEpnOTI3WjdJNTJJZUZyVnBoYkdGQm0xSU5ZVlFxRmZHaG9TUkhSYkcxVEJld3k4ZU9zVy8rZkZKalk1bStmVHNkaHd6QndFVHd2ejJNaU9ENHVuWDQ3ZHpKb0lVTEdmN0JCK2dhR0NEUHkrUEVoZzBjV2JrU21iNCtvMWF2cHUrYmJ6S2hqTUx4dktFMkg3OE9IVHFRa0pCQVpBVTkzZXNDQ3hjdVpOT21UZHkvZjUrbVpWN3lsZUhNbVRQWTI5dHJkTGVyM3hlTjZQbCsvc3IyZ0gzSzZIdTJuaWVnbmkrZ1Q1OE4vUGZmZjV3OWU1YUhEeC9TdVhObk9uYnNxSTc3Q1E4UDU5aXhZNGpGWWw1OTlWV05XaGl4c2JFY08zYU02T2hvbkp5Y2VPV1ZWOGpJeU9ETW1UTThmUGdRVjFkWHpNek0xSTJ5bkoyZDZkcTFxNFlGN3IyeUZYOGFBSnljaEE2QXZYckJwNThLR1FFV0ZrS3pvbGRlRWZMN1gzOGRCZ3lBMjdjMVB4Y3JDQzFiQ2dXRmZ2cEpTQ01zWGR1Z1FTa0FjS1NlMlVmVUsvL0k1LzBGWEF1UFgzUjBORHQyN0dEOSt2WEk1WEtXTFZ2R3BFbVRjSFYxclpOcmxzdmxmUEhGRjN6NjZhZEVSVVV4Y3VSSVpzK2VUZGNxc2tHSzhjY2ZmK0RrNUZSbjE2WlZBTFFLd0xPbUFOUW5HcUlDOEZSLy8xb0ZRS3NBL0greEFHaWhWUUMwQ29CV0FkQXFBRFZSQVByMFVXbC9BUFdIcy9UVnZvRHFFYi8vL3B4TFFDMjAwT0s1aGJZZHNCWmFhS0dGRmxwb0ZRQXR0TkJDQ3kyMDBPSjVnRHJmSWtlaDRNT3dNTTZscFNGWEtybVRuVTFlVWRuVHpGNjlNSkpJK0RZK25oMHhNWnhMVFVWZkxNYkwwSkJjcFJKZHNaaWhqUnV6ME5rWmZiR1k0T3hzamlVbXNpbzhuSHlsRWljOVBheGtNaElLQ21oamJNeDd6czc0bW1oV3JWTGtLQWo3TUl5MGMya281VXF5NzJTckcxejB5dXlGeEVoQy9MZnh4T3lJSWZWY0ttSjlNWVplaGloemxZaDF4VFFlMmhqbmhjNkk5Y1ZrQjJlVGVDeVI4RlhoS1BPVjZEbnBJYk9TVVpCUWdIRWJZNXpmY3k1WE5VdWh5Q0VzN0VQUzBzNmhWTXJKenI2RFVwa244UGZLUkNJeElqNytXMkppZHBDYWVnNnhXQjlEUXkrVXlsekVZbDBhTng2S3MvTkN4R0o5c3JPRFNVdzhSbmo0S3BUS2ZQVDBuSkRKcklxYVo3VEIyZms5VEV4OE5maTE4MSsvODYrRkZscG84YnhCSFFQUTUvcDFyR1F5OW5oN295c1dreXlYODJaUUVFY1RFOVVDQ09CQ1docmQvdm1IdHgwYzJPcnBpUXJZSEJuSnZKQVFlcG1aNGRldW5ick1aWi9yMS9GTFNlRmhqeDVZU3FWRTUrZnowdlhyaE9iazhIT2JOdlExTjFlN2dLLzN1WTdNU29iM0htL0V1bUxreVhLQzNnd2k4V2lpV2dBQnBGMUk0NTl1LytEd3RnT2VXejFCQlpHYkl3bVpGNEpaTHpQYStiVlQxN3ErM3VjNktYNHA5SGpZQTZtbGxQem9mSzYvZEoyYzBCemEvTndHODc3bWFoLzA5ZXQ5a01tczhQYmVnMWlzaTF5ZVRGRFFteVFtSGxVTElCQnFXdi96VHpjY0hON0cwM01yb0NJeWNqTWhJZk13TSt0RnUzWitGRi9BOWV0OVNFbnhvMGVQaDBpbGx1VG5SM1A5K2t2azVJVFNwczNQbUp2M1ZjY0FhT2UvZnVaZkd3T2doUlphUEs4UUExek55TUF2SllWbExpN29GbFVVc0pCSythNUZDenpLbEI0eUxWT2tRUVRNZFhTa2xiRXhmNmFtOGt0U1VxVmo3WFYxV2V2bWhseWxZbW1wY3B3WlZ6Tkk4VXZCWlptTFVMSVNrRnBJYWZGZEN3dzhOUG1MMjJXV3ZnREh1WTRZdHpJbTljOVVrbjVKcW5Tc3JyMHVibXZkVU1sVmhDNHR4Wjl4bFpRVVAxeGNsaUVXNndyOFVndGF0UGdPQXdNUFRYNmRzcVYvUlRnNnpzWFl1QldwcVgrU2xQUkxwV04xZGUxeGMxdUxTaVVuTkxTays1WjIvdXQzL3JYUVFnc3RubHNGSUxHb205bjVNdFVDWkdJeDQ2cFpzN3BGVVhHRjhLSm1DelVaVjVBbzhLZWUxK1FYeThUWWpxc2V2MkVMNGJ5NTRiazFIbGRRa0Nqd3A1N1g1QmZMc0xVZFZ6MStRNkdDWVc1dWVJM0hhZWUvZnVkZkN5MjAwT0s1VlFCOFRVd3drRWlZZmZjdWE4UERLU3lWbXozQ3lrcTlLcTBLOTNKeUFHaHVaRlQxdUNMQlUzcWNpYThKRWdNSmQyZmZKWHh0T0tyQ0VuNnJFVmJxVldsVnlMa244QnMxcjVvLzkxNXV1WEVtSnI1SUpBYmN2VHViOFBDMXFGUWxwU1N0ckVhb1Y2VlY4dWNJWFFHTmpKcFh6WjliZnB4Mi91dDMvclhRUWdzdG5sc0Z3RUlxWlkrM055SmcyZjM3dEF3STRLY2lVN0tYb2FGR1o2dUs4RlYwTkZjeU1oaGdhVWt2czhyYlRjWVhGTEFrTkJTcFNNUzZVaVVkcFJaU3ZQZDRnd2p1TDd0UFFNc0FrbjRTK0EyOURCRkpxK2FQL2lxYWpDc1pXQTZ3eEt4WDVmd0Y4UVdFTGdsRkpCWGh0cTRVdjlRQ2IrODlnSWo3OTVjUkVOQ1NwS1NmaWxhTVhvaEVWVGZ0aUk3K2lveU1LMWhhRHNETXJGZmwvQVh4aElZdVFTU1M0dWEyVHIxZE8vLzFPLzlhYUtHRkZzOGoxRTdha2RiV2VCZ1lNQzBvaUg4eU1uZzFNSkMrNXVac2I5WU1sd3FhbC9pbnBiSHczajBpOC9Jb1ZLbjQwc3VMNlhaMkZaS3NDZ3REQ1lUbDVOREp4SVJEUGo1NGx2RnRXNCsweHNERGdLQnBRV1Q4azBIZ3E0R1k5elduMmZabTZMdVU1MC96VCtQZXdudmtSZWFoS2xUaDlhVVhkdE1yNWc5YkZRWkt5QW5Md2FTVENUNkhmRER3TE1OdlBSSURBdytDZ3FhUmtmRVBnWUd2WW03ZWwyYk50cU92WDc0VFlGcWFQL2Z1TFNRdkx4S1ZxaEF2cnkreHM1dGVNWC9ZS2tCSlRrNFlKaWFkOFBFNWhJR0JwOFlZN2Z6WDcveHJvWVVXV2p5M0NnQkFhMk5qTG5mb3dPN1lXSmJmdjgvWmxCUTZYcm1DZjRjT3VKVVJHSjFNVGRubzdsNHRrZythTnNXeUdxMHZqVnNiMCtGeUIySjN4M0ovK1gxU3pxWndwZU1WT3ZoM3dNQ3RUREJjSjFQY04xYVB2K2tIVFpGYVZvUGZ1RFVkT2x3bU5uWTM5Kzh2SnlYbExGZXVkS1JEQjM4TUROdzArVTA3NGU2K3NYcjhUVDlBS24xMEJ5N3QvTmZ2L0d1aGhSWmFQRThRZzJBYVRwYkxoUTBpRVZQdDdBanUzSm5CalJ1VEpKZXovUDc5T3IySWd2Z0M1TWtDdjBnc3dtNnFIWjJETzlONGNHUGtTWEx1TDY5ai9vSjQ1UEprZ1Y4a3hzNXVLcDA3QjlPNDhXRGs4aVR1MzE5ZXAvemErYS9mK2RkQ0N5MjBlRzRWZ0lqY1hQeFNValJYV0RvNkhQVHh3VlJIaDhETXpEcTlpTnlJWEZMOE5QbDFUSFh3T2VpRGpxa09tWUYxeko4YlFVcUtueWEvamlrK1BnZlIwVEVsTXpPd1R2bTE4MSsvODYrRkZscG84ZHdxQUFCNzQrTEs3ZFFUaTNIUTA2TnBCVDdvbW5SeHE4N1l1TDNsK2NWNll2UWM5TkJ2K2hUNDQvYVc1eGZyb2FmbmdMNSswenJuMTg1Ly9jNi9GbHBvb2NWenF3RDhrcFRFbkpBUXNoUUs5Yzd2NHVPNWw1UER5bEs5eTlNTGhSU3QxTUxDUjU2OEptT1Rma2tpWkU0SWlxd1Mvdmp2NHNtNWw0UHJ5aEwrd25UaFhJV3BqejVuVGNZbUpmMUNTTWdjRklxc0V2NzQ3OGpKdVllcjY4cVNjeGFtRi8yYittaitHb3pWem4vOXpyOFdXbWloeGZNR2thcFBIMVZBZWpxZHJsNEZ3RkFpd2R2UWtBS1Zpc1pTS1d0Y1hYbWhxRzc4MHRCUWRzWEdxZ3ZYU0VRaTVqbzZzc3JWVlYyRGZrdFVGRjlGUjJPaW8wT1dRb0ZDcFdLZ3BTVnZOR25DVUN1cmNoZlE5eXlrQjZSenRaUEFMekdVWU9odGlLcEFoYlN4Rk5jMXJwaThJUEFIdlJsRTNONDRsUGxDalhxVEYweG91cW9wRmk5WkFFSTkrNGgxRVlSL0ZJNUlJZ0lWcUJRcUxBZGEwdVNOSmxnTkxjOVAzN09rcHdkdzlXb25nVjlpaUtHaE55cFZBVkpwWTF4ZDEyQmk4a0tSUVBxV21KaXZTVTM5R3dCZFhUdGtzc2JxUEhXRklwZXNyUDhRaWFUWTI4OGdKbVk3U21VQmxwWURhZExrRGF5c2hwYWpQMHRmS3B0L2N4MGRQQTBOK1MwNVdWMjR4MVJIaDdUQ1Fvd2xFbGE2dXFKU3FmZzhLb29IZVhtTXNiRmh2cE1UQm1JeFI0dDZBUlFvbFVoRkltYlkyL09acDJlTjVsOWlKRUhTU0VMeWFjRS9MMnNzUThkVWg1eDdPVWlNSmJpdWRFVm1LeVB5azBneXJtVmcwc21FcHU4M1JjOUZqOFNqUmIwQUNwU0lwQ0xzWjlqaitabm5ZODIvV0N6bDh1VjJTS1VXcUZRRkZCWm1JaEpKME5XMW83QXdnOExDTkd4c1J0T2l4WGNBUmIwQWpoSVc5Z0VxbFJKTHkxZG8wbVJLaGZPdkxRV3NoUlphUE5jS1FFMFAyaDhYeDRUYnR6R1RTb250MWcyOVVvVnF6cWVsTVNzNG1IUHQyNWNyUlZzUmF0b09QamM4bDRDV0FTaXlGSFMrMTdsY2REb3ErTnY2YjFvZWJZbHBOMU5xL1FLQUd6Y0c0K0h4S2ZyNnJocmI3OTZkVFZUVVZseGRWK1BpVXIzQXRlSmVBRlVobzdDUW50ZXU4VzltSnV2ZDNGanM3S3l4LzhYcjF4bHJZOFBrSmszS0hYdmk0VU9HM0xqQkFpZW5Dck1HcW5QN3dXOEhFLzFsTkRaamJXaHhvRVc1L1pHYkkwazVtMEtyazYwUTZXakswNGNuSG5KanlBMmNGamhWbkRWUWpRdElUajVEY3ZLdmVIaDhxckU5TCs4Qi92NHRrRWdNNmRUcE5sS3BoY2IreTVkYms1VjFpeDQ5VXREUmFWVGh1YlVLZ0JaYWFQRzg0ckhhQVkrM3RXV0d2VDJwY2puckl5TFUyM01VQ3Q2N2Q0OFRyVnBWUy9nL0R2UmQ5SEZiSzZTRWhhOHVYODQxNFZBQ3RoTnRxeWY4SHhObVpqM0tDZi9VMUhORVJYMkJzWEZibkozZnExVytSam82SEduWkVrT0poSTBQSHBCVWxERUE4RTFzTEMwTURTc1UvZ0I5ek0weGtrZ1laVzM5MlB6dUc5elJjOVFqNFhBQ09TRTVtdnFXUWtYQ29RU2E3V2hXVHZnRG1QY3hSMklrd1hyVTQvUEw1Y2s0T3kraXJLWjM1ODVrRklvc3ZMeStMQ2Y4QVJvM0hvS0ZSZjlLaGI4V1dtaWhoVllCZUF4c2RIZkhVVStQZFJFUkJHVm5BL0JXY0REem5ad3FMRnhUbTdCLzI1NUc3UnNSdHorT3RQTnA2dTJLYkFXUld5SnB1cUpwbmZMYjJJelYrS3hRWkhQbnptUkVJaDJhTjkrRFNGVDd5bytydmo1cjNkeElsc3VaRnhJQ3dPM3NiUGJFeFpWYjJTdFZLZ2JkdU1Ick4yOXlOenVidCt6dGtZcEV6QThKb2NPVks5ekt5cW9SdDhSSWd1Zm5ucWprS29MZkN0YllGN1UxQ3V1UjF1ZzJLU25YcTFLcXVESG9CamRmdjBuMjNXenMzN0pISkJVUk1qK0VLeDJ1a0hXclp2em01cjJSeVd3MHRrVkhmMFZLeWg5WVc0L1NNTzBuSmYzRWxTc2RpWXJhaXFYbHkxaFl2RVJDd2tHdVgzK1JrSkM1MmwrOEZscG9vY1dUS2dCR0VnbmJteldqUUtsa2VsQVFPMk5pTU5MUnFkRFBYOXNRaVVVMDI5NE1rVmhFME13Z1ZITEJpeEgyWWRqL3RYZm4wVkhWOS8vNG56Y3prNWtNU1NZSkpFUDJQY1FRRVlRUGk4aXZIcWw2V3JGZ0lhQVUyN0xvc1FYOUJpM2lWeXdCTVJDS0NGZ3NpZ3NWaTlUaWwrcng0OUhXSUNpTG1pQVFsc0VNWkpKTTlvVnNaTGJNekwyL1B6S0VMSk1oR3d3dHo4YzVuaU9aZStjMTkvMSt2ZC8zM3ZkZDNvakpqT21ZdXZaNjhmWHRlalo3OGVKS1dDd0dKQ1Q4RWY3K1k2NWIzR1ZSVWJoTG84SDdWVlg0dUs0T2kzVTZ2SnVXQnQ5dWN3VklBSXJNWnZ4dytUTDIxdFNnem03SGx3ME4rTGE1R1QrYVRHam9OSUxRVjZHL0NFWG9yRkEwSEdoQTlRZlZBTnJmSDFDN3J4YlJUMFYzUHptSHVjaU15ejljUnMzZUd0anI3R2o0c2dITjN6YkQ5S01KOWdiN29NcmJZaW5CaFF2UHdkYzNES21wMjN1TUZwak5lalEwL0J2MTlWL0FZaWxHUThNQnRMYWVoY2xVeUJaUFJIUmxYenFRZXdBNis4MjVjOWhkVllWMGYzOGNueml4VHhQWGREYUFTL0FkOU12MU1HNDFJbWxERWtKbmhrTC9qQjdqUGgrSEcvWURBRFEySHNJUFA5eUxnSUN4bURneHI5OW4vMzI1QjZDekgwMG1qUDMrZTlnbENYOU5TOE5qZlpndGNQcUpFL2pramp2Z0w1TU5hdk50NVRZY1N6c0dtVnFHdXdydlF1R3lRa1E4SG9IZy95L1k0M29ucHAvQUhaL2M0ZjdBck4vbEwrSEVpWitpb2VFcmpCbnpFY0xDWnZlNlpIMzlaMmhwK1FFSkNhdDdYWWIzQUJBUlJ3QUdLQ2NwQ1RKQlFKblYydkUydXhzbGNWMGlWTkVxRks4cnh2bkh6eVBsMVpRYkdyL3owSDlhMnZVWit1OHVkZGd3TEk2SWdDaEpPTjJIb2Z4OU5UWDRxcUVCV1VQd05rRmxsQktKNnhMUlZ0T0dncGtGZ0lCcjd2eHI5dFdnNGFzR0ZHVU56ZHNFeTh0M3VJYis1M3JjK1FQQWhRdlBvYVJrUThkMHcwUkVOSVFIQU5rbEpaaW4xYUxaNGNDeXdoczd4Q3J6bHlINVQ4bHdtcDFRajFKajJHM0RibWo4Q3hlZWc4VlNqUGo0VlFnSXVPT0d4Q3l5V0hET1pNSnR3NFpoaTlHSUU5ZDRTNkRNZFlJYjBvZTVBUG9pZWxrMGhxVU5RK1BYalVqTVRyem04b0tzUGI0aVpQRHhMWlppWExpd0VyNitvVWhOZmYzYXNRVVpBQUVLUlFoYk9oSFJVQjRBL0tPbUJrNUp3cDcwZEV3UENjRS9hMnZ4ejlvYmU3YmxsOVIrdzZFaVdIRkQ0elkySGtSNStRNEVCSXhGZlB3TE55U21UUlN4U0tmRFc3ZmRoamR2dXcyaUpPRnhuUTVPRDIrNlMvZjNCd0NNQ3dnWWt0OGd5SVNPMlFIN1V1Yis2ZTN4QThZTk5yNEVuVzR4bk01V2pCcjFlcDhtOS9IM1Q0ZS9mL29OR1praElycGxEZ0QwWmpQK1hGYUdMU250dys0N1VsT2g4dkhCc3NMQ2pqZlEvYmR5T2x1aDB5MTJEZjMvMWUxODlTYVRic2pqL3AvQ1Fqd1pHWWxrdFJyVGdvS3dNQ0lDSnk1ZnhoYWpzZGQxa3Z6OG9QTHhRV0szMlFSdjVBR2FqOG9INnNUQnhTOHIrd3NhR3c5Q3E4MkFWcHZSNDNPcnRSUk9aOWRIRkljTlMrL3h1Q1lSRVEzaUFNRHNkR0xodVhONEp5MnQ0eVZBeVdvMVZzWEhvOUptdzRvTEYvNnJDKzNxMFA4TGJvZis3ZllHTkRUa0Rtbk1QZFhWRUFFOE92THE0M0Nia3BNUjV1dUwxVVZGdUdnMnU2OWdRVUNDbngraWxFcXZsSlhnSThBdndRL0txSUhIdDFpS2NmRmkrOUQvcUZIdWgvNHJLOStEajQrcXk5L1U2bVNvVkZGczVVUkVRM0VBWUJGRlBIcjJMR2FFaGlLbDIxbmx5cmc0aFByNjRxMktDdXkvUVpjQ090NDMzM3hqUmgwYUdyNUNlZmtiQ0FpNEEvSHhxM3A4TG9vV0ZCWSs3WFlDbTRIS2JXakF5Z3NYT2taYnJnaFJLUEIvNCtKZ0VVWDg2dXhaMkVUUjdmcFJLaFdHeVdSZUszTlZsQXF5WVFPTmYrV0ZQeWFNR3JVZHZyNmhQWlpvYnY0V2pZMEhJQWhkMDluWE41VFgvNG1JZXRHdmk2TnZWVlFncDZRRUJvc0ZyVTRuN2dzSndZVEE5cmVzT1NRSlc0M0dqdUgvWDUwOWk2ZWlvN0U4SmdiaDErbnNzK3I5S2xTOFdRRUFxUDFuTFlhbEQ0TjJqaGJLeU90MXRpdmgvUG5GQUNUWTdVMDRmbnhhdDUyL0hSWkxFUnlPWmlRbXJodDB0SXRtTTdKTFN2QmVaU1ZrZ29DL2xKZmpEN0d4dVBMY1dsNUxDejZ0cisvNC81Lzg4QU9laTQzdDhTNkdvVHI3TjUwM29mYWpXalIvM3o3SmpuNjVIdUcvRHNlSUdaNnZ4dy9tN0wreThxOW9iRHdFUVpEQmFId1ZSdU9yUFVaYnpPYUxDQTkvckdkeXl6V1F5UUxZeW9tSTNCajBld0FHYTVDUDRmL0gvNEQrdmdkZ0lGWVZGU0U3TWRGcm0xKzBxcWozSndhdTR3OHdteStpcWVrd0lpSVc5ajY2d3ZjQUVORXR5b2RGOE44dlJPN2R1K0RsSWQ2Skw1T3BJSk9wbVFCRVJEd0F1RFVGZXZzQUlOQTc4UVhCdDhlTmdVUkV4QU9BVzRhL1RPYlYrTmQ3Ym9iZUR3RGtQQUFnSXVydDVJeEY4Tit2ODZPRDNYMTUzNDM0QlNPQmQ3MzVBMTdwL2FQN0pDL2ZBM09mVjNQRDY3ZmdlTDExZkhsTEY4QXRmZ3VXMTh2ZjIvY2djUVNBaUlqb0ZzUURBQ0lpSWg0QUVCRVJFUThBaUlpSTZMOVNqNXNBVzUxT2JEVWFjYXlwQ1NPVlNzZ0VBWUV5R2NZSEJxTEY0Y0JjclJiN2EydXhYSytIQkdCYVVCQXNvb2hXcHhOTG82S3dNQ0lDZXJNWnU2dXFrRjFjakFpbEVoTUNBMUZ1dFdLNFFvR3NoQVJNRFFycTlRYzVXNTB3YmpXaTZWZ1RsQ09WRUdRQ1pJRXlCSTRQaEtQRkFlMWNMV3IzMTBLL1hBOUlRTkMwSUlnV0VjNVdKNktXUmlGaVlRVE1lak9xZGxlaE9Mc1l5Z2dsQWljRXdscHVoV0s0QWdsWkNRaWE2aUcrc3hWRzQxWTBOUjJEVWprU2dpQ0RUQmFJd01EeGNEaGFvTlhPUlczdGZ1ajF5d0ZJQ0FxYUJsRzB3T2xzUlZUVVVrUkVMSVRackVkVjFXNFVGMmREcVl4QVlPQUVXSzNsVUNpR0l5RWhDMEZCVTN1TjcrM3k5M3I4VmllMmJqWGkyTEVtakJ5cGhFd21JREJRaHZIakE5SFM0c0RjdVZyczMxK0w1Y3Yxa0NSZzJyUWdXQ3dpV2x1ZFdMbzBDZ3NYUmtDdk4yUDM3aXBrWnhjaklrS0pDUk1DVVY1dXhmRGhDbVJsSldEcVZFL2IzNHF0eHEwNDFuUU1JNVVqSVJOa0NKUUZZbnpnZUxRNFdqQlhPeGY3YS9kanVYNDVKRWlZRmpRTkZ0R0NWbWNybGtZdHhjS0loZENiOWRoZHRSdlp4ZG1JVUVaZ1F1QUVsRnZMTVZ3eEhGa0pXWmpxb2Y2OW5mL2VMbit2dC8vV1ZoaTNia1hUc1dOUWpod0pRU2FETERBUWdlUEh3OUhTQXUzY3VhamR2eC82NWNzQlNVTFF0R2tRTFJZNFcxc1J0WFFwSWhZdWhGbXZSOVh1M1NqT3pvWXlJZ0tCRXliQVdsNE94ZkRoU01qS1F0RFVxVGR4LytQdC9MKzF5OStyQndCbFZpdnVQM2tTRDQwWWdVL0hqdTJZUzc2bXJRMHpUcDNDek5CUWhDZ1VXQklaaVQzVjFiQ0lJajRmTnc0QXNMNjRHSXQwT2pna0NZOUhSbUpkWWlJMmxKVGdzZkJ3NUNRbHdTNUptRlZRZ09rblR1RDR4SWtkMDlSMlppMno0dVQ5SnpIaW9SRVkrK25ZanJuazIycmFjR3JHS1lUT0RJVWlSSUhJSlpHbzNsTU4wU0ppM09mdDhZdlhGME8zU0FmSklTRllub3U5QUFBZ0FFbEVRVlR5OFVna3JrdEV5WVlTaEQ4V2pxU2NKRWgyQ1FXekNuQmkrZ2xNUEQ2eFk1cmFMdkd0WlRoNThuNk1HUEVReG83OTFEV2ZQTkRXVm9OVHAyWWdOSFFtRklvUVJFWXVRWFgxSG9paUJlUEdmZDRldjNnOWRMcEZrQ1FISWlNZlIyTGlPcFNVYkVCNCtHTklTc3FCSk5sUlVEQUxKMDVNeDhTSngrSHZuOTRqdnJmTDMrdnh5Nnk0Ly82VGVPaWhFZmowMDdHUXVlcS9wcVlOTTJhY3dzeVpvUWdKVVdESmtranMyVk1OaTBYRTU2NzZYNysrR0lzVzZlQndTSGo4OFVpc1c1ZUlEUnRLOE5oajRjakpTWUxkTG1IV3JBSk1uMzRDeDQ5UFJIcTZ1KzB2dy8wbjc4ZERJeDdDcDJNL2hjeFYvelZ0TlpoeGFnWm1oczVFaUNJRVN5S1hZRS8xSGxoRUN6NTMxZi82NHZWWXBGc0VoK1RBNDVHUFkxM2lPbXdvMllESHdoOURUbElPN0pJZHN3cG1ZZnFKNlRnKzhUalMzZFMvdC9QZjIrWHY5ZlpmVm9hVDk5K1BFUTg5aExHZmZnckI5ZmhzVzAwTlRzMllnZENaTTZFSUNVSGtraVdvM3JNSG9zV0NjWis3MnYvNjlkQXRXZ1RKNFVEazQ0OGpjZDA2bEd6WWdQREhIa05TVGc0a3V4MEZzMmJoeFBUcG1IajhPUHpUMDIvQy9zZmIrWDlybDc5WEx3RklBT2FmUFlzZ3VSd2JrNU03T244QTBQcjZZditZTVdoMU9qditwdlRwZXZYZ21kaFl5QVFCNzFaV0FnQUVBSXBPMzZFUUJHVEd4TUFtaXRoVFhkM3psMGpBMmZsbklRK1NJM2xqY2tmakJ3QmZyUy9HN0I4RFordlYrRDdLcnZGam40bUZJQk5RK1c1N2ZBaUFvTGo2SFlKQ1FFeG1ERVNiaU9vOWJ1SkR3dG16OHlHWEJ5RTVlV05INVFPQXI2OFdZOGJzaDlQWmVqVytUOWYzMjhmR1BnTkJrS0d5OHNyemJrS1hhWUlGUVlHWW1FeUlvZzNWMVh2Y2JiNVh5OS9yOFNWZy92eXpDQXFTWStQRzVJNmREd0JvdGI3WXYzOE1XanZWdjdKYi9UL3pUQ3hrTWdIdnV1cGZFQUJGcC9wWEtBUmtac2JBWmhPeFo0Kzc3WmN3Lyt4OEJNbURzREY1WTBmbjE3NzlXdXdmc3grdG5lcGYyYTMrbjRsOUJqSkJobmRkOVM5QWdLSlQvU3NFQlRKak1tRVRiZGpqcHY2OW5mL2VMbit2dDM5Snd0bjU4eUVQQ2tMeXhvMGRPNS8yK0ZxTTJiOGZ6dFpPN2IvYi9CcXh6endEUVNaRDVidnZYbW53RUJTZDJyOUNnWmpNVElnMkc2cjM3TGtKK3g5djUvK3RYZjVlUHdENHByRVJSNXFhc0RBaUF1NGVUSXhXcVRDbjJ5UXpuVjFaSjhERFMyYzhMZFA0VFNPYWpqUWhZbUVFM1AwQVZiUUtZWE42ajM5bEhWbUFiRURMTkRaK2c2YW1JNjczeHZmOEFTcFZOTUxDNXVCYVgrNTU4cG5lbC9GMitYczkvamVOT0hLa0NRc1hSc0RkazdIUjBTck04VkQvVjlZSjhGRC9ucGI1cHZFYkhHazZnb1VSQ3lHNEtZRm9WVFRtZUtqL0src0VlS2gvVDh0NE8vKzlYZjVlYi8vZmZJT21JMGNRc1hBaDNCV0FLam9hWVhNOHRIL1hPcktBZ0FFdDQvMyt4OXY1ZjJ1WHY5Y1BBRDYvZEFrQU1ONURBVjZaK2MrZDlTVWxjRW9TbGtaSHUvM2NLb3JZVkZvS2pWeU9CZUhoUFQ2LzlIbDcvSUR4dmNjUG5OQjcvSkwxSlpDY0VxS1h1bzh2V2tXVWJpcUZYQ05IK0FJMzhTOTk3dXFjeHZjZVAzQkM3L0ZMMWtPU25JaU9YdW8rdm1oRmFla215T1VhaEljdjZQRzV0OHZmNi9GZDlUL2VRLzFQOEZELzY5ZVh3T21Vc0xTWCtyZGFSV3phVkFxTlJvNEZDOXh0LytldTdSL3ZZZnNuZU5qKzlYQktUaXp0cGY2dG9oV2JTamRCSTlkZ2dadjY5M2IrZTd2OHZkNytYVVBKQWVNOXRQOEpIdHIvK3ZXUW5FNUVMKzJsL1Z1dEtOMjBDWEtOQnVFTEZ0eUUvWSszOC8vV0xuOXY2YmdIb054cUJkQSt4M3hmVmRsc0hkTUQyMFFSQjhlUHh6M0J3VjJXeVd0dVJuWnhNYzZiVEVoUnE3RWpOUlV4cXA2dlo3V1d0OGRYaFBROXZxM0tocEtjRWxnTUZvZzJFZU1Qamtmd1BWM2pOK2Mxb3ppN0dLYnpKcWhUMUVqZGtRcFZqSnY0MW5MWFVHWGY1NCszMmFwUVVwSURpOFVBVWJSaC9QaURDQTYrcDJ2ODVqd1VGMmZEWkRvUHRUb0ZxYWs3b0ZMRjlQZ3ViNWUvMStPNzZqK2tIL1ZmVldWRFRrNEpEQVlMYkRZUkJ3K094ejNkNmo4dnJ4bloyY1U0Zjk2RWxCUTFkdXhJUlV5TXUrMHZkMjEvU0QrMnZ3bzVKVGt3V0F5d2lUWWNISDhROTNTci83em1QR1FYWitPODZUeFMxQ25Za2JvRE1XN3EzOXY1NyszeTkzcjdMM2UxLzVCK3RQK3FLcFRrNU1CaU1FQzAyVEQrNEVFRTM5T3QvZWZsb1RnN0c2Yno1NkZPU1VIcWpoMVF4Y1RjaFAyUHQvUC8xaTUvcng4QXFGM0RzcGM3WGVlOWxuQ2xFcy9IeFhsY1pxSkdnMVh4OGRmOExwbTZQYjd6Y3Qvaks4T1ZpSHZlYzN6TlJBM2lWL1Vodm12V09LZnpjdC9qSzhNUkYvZTg1L2lhaVlpUFgzWE43L0oyK1hzOXZxditML2VqL3NQRGxYaitHdlUvY2FJR3ExYjFaZnZWcnUyLzNJL3REOGZ6MTZqL2lacUpXTldIK3ZkMi9udTcvTDNlL3RXdTluKzVIKzAvUEJ4eHoxK2ovVStjaVBoVnEvNEQraDl2NS8rdFhmN2UwbkVKNEM2TkJnQndvcVhGS3o5RWMxZDcvSllUWG9xdnVhczlmc3NKcjhUM2R2bDdQYjZyL2srYzhOYjIzK1hhL2hPM1pQNTd1L3k5M3Y3dmNyWC9FMTZxZjYvM1A5N08vMXU3L0wxK0FEQlhxMFdVVW9udDVlVnd1cGtmUlpRazdIVjM5LzRRMGM3VlFobWxSUG4yY2tqT252RWxVVUwxM3VzWVh6c1hTbVVVeXN1M1E1SjZub1ZJa29qcTZyM1hMYjYzeTkvcjhlZHFFUldseFBidDVYQzZxWDlSbExCMzcvWGMvcm1JVWtaaGUvbDJPTjNVdnlpSjJIc2Q2OS9iK2UvdDh2ZDYrNTg3Rjhxb0tKUnYzdzdKelNpWUpJcW8zcnYzdjdqLzhYYiszOXJsNy9VREFMVk1objFqeHFEUVpNSzhNMmRRMDliV3NWQ1R3NEUxQmdPbWQ3bytZeE5GV0R3TUYwc0E3SkxrY1ptdVEwQXlqTmszQnFaQ0U4N01PNE8ybXF2eEhVME9HTllZRURMOWFuelJKc0pwOGZEZEVpRFpKYy9MZEJzQ0dqTm1IMHltUXB3NU13OXRiVFZYNHp1YVlEQ3NRVWpJOUU0ZG9nMU9wd1dlZm9BazJhK3h6RlhlTG4rdngxZkxzRy9mR0JRV21qQnYzaG5VZEtyL3BpWUgxcXd4WUhxbityZlpSRmc4MUswa0FYYTc1SEdacnR1dnhyNHgrMUJvS3NTOE0vTlEwNm4rbXh4TldHTllnK21kNnQ4bTJtRHhVTGNTSk5nbHU4ZGxicWI4OTNiNWU3MzlxOVVZczI4ZlRJV0ZPRE52SHRwcU9yWC9waVlZMXF4QnlQUk83ZDltZzlQaW9XNGxDWkxkN25tWm02ci84WGIrMzlybDd5MWRYZ1EwV2FOQndlVEplTWxnd0tTOFBJVDUraUpXcFVLU1dvMFZzYkVJVVNqUVlMZGpYMjB0OGx0YVlCTkZiQzhydyt5d01JUjNlaTVUYnpaalYyVWxSRW5DeDNWMW1LVFJJRU9yN2ZKY3VOdGhtTWthVEM2WURNTkxCdVJOeW9Odm1DOVVzU3FvazlTSVhSRUxSWWdDOWdZN2F2ZlZvaVcvQmFKTlJObjJNb1RORG9NeS9HcDhzOTZNeWwyVmtFUUpkUi9YUVROSkEyMkd0c3R6d2U2SGdTWmo4dVFDR0F3dklTOXZFbng5dzZCU3hVS3RUa0pzN0Fvb0ZDR3cyeHRRVzdzUExTMzVFRVVieXNxMkl5eHNOcFRLcTNjV204MTZWRmJ1Z2lTSnFLdjdHQnJOSkdpMUdWMmVDM1hIMitYdjlmaVROU2dvbUl5WFhqSmcwcVE4aElYNUlqWldoYVFrTlZhc2lFVklpQUlORFhiczIxZUwvUHdXMkd3aXRtOHZ3K3paWVFqdlZQOTZ2Um03ZGxWQ0ZDVjgvSEVkSmszU0lDTkQyK1c1ZFBmYlB4a0Zrd3Z3a3VFbFRNcWJoRERmTU1TcVlwR2tUc0tLMkJVSVVZU2d3ZDZBZmJYN2tOK1NENXRvdy9heTdaZ2ROaHZobmVwZmI5WmpWK1V1aUpLSWorcyt4aVROSkdSb003bzhGMzB6NXIrM3k5L3I3WC95WkV3dUtJRGhwWmVRTjJrU2ZNUENvSXFOaFRvcENiRXJWa0FSRWdKN1F3TnE5KzFEUzM0K1JKc05aZHUzSTJ6MmJDZzdQZGxpMXV0UnVXc1hKRkZFM2NjZlF6TnBFclFaR1YyZVM3ODUreDl2NS8rdFhmN2VJRWcvL2FtWDUwUDNjZ2w0K1FkOGVSUE1pTzdsQXJpbDYvKytMKys3dFl2L1ZrL0ErOWo4YnVYeXo4Mjl4bG5SamJvRVFFUkVSTGNPdHdjQUZUWWIvbFJhQ3ZtQkF3ZytkQWp2VkZhaTJlSG9zZHloeGtZOGN1WU1oTnhjQ0xtNXlOVHJVVyszQXdDK2IyN0cxUHg4QkI4NmhBMGxKVEQzNC9FeVc0VU5wWDhxeFFINUFSd0tQb1RLZHlyaGFPNFp2L3FEYWh5T1BJeGNJUmY1VS9QUmRMaXA0ek5MaVFVRkR4ZmdnT3dBQ3A4dWhLM1MxcStDc2RrcVVGcjZKeHc0SU1laFE4R29ySHdIRGtlejIyVlBuODdBMGFOSktDaDRHS2RQejhIcDAzTnc2dFNEeU0wVjhPMjNveUdLL1l1dE41dXg4c0lGS0wvNkNrSnVMaDQ0ZVJMblRDWUFRSW5GZ2lVNkhlUUhEbUJaWVNFTWJxNXg5YlgraGpMbW9OZlhtN0Z5NVFVb2xWOUJFSEx4d0FNbmNlNmNhLzBTQzVZczBVRXVQNEJseXdwaE1QUmMvN3Z2bWpGNWNqNEVJUmNqUjM2RER6NjRlc09ZMmV6RXFsVkZFSVJjL1B6bkozSDh1UHM3elE4MUhzSWpaeDZCa0N0QXlCV1FxYzlFdmIzZWxjL2ZZMnIrVkFRZkNzYUdrZzB3TzgxdXZ5UGpkQWFTamliaDRZS0hNZWYwSE13NVBRY1Bubm9RUXE2QTBkK09ocTJQdVREUTNCWnRJaXAzVlhhc2EzakpBRXRSMzY1RGZ2QkJOU0lqRDBNUWNqRjFhajRPZDRwWlVtTEJ3dzhYUUNZN2dLZWZMa1JscDVqTnpRNjg4a29wSWlMYTE0MlBQNG92djJ6b0tQdFhYelZDRUhMeHM1K2Q3UEtkUTdYTlZxTVY1MzU5RHJsQ0xuS0ZYSlMrVXRxbHY2aitvQm9IaHgzRXNkUmpxTjFmMjJ0ODBXYURZZTFhZktWVUlsY1FvRnUwQ09hTEY2OXU1N2ZmNHR1ME5CelNhRkM2ZVRQRVR2ZkpBSURwM0RsOHBWVGl4SDMzNGZTY09SMy9IWTJQUjY0Z29Pcjk5L3ZWRDVTVnZZNnZ2eDZPVTZjZTZ1aFhUcCtlZzRNSC9mSFZWMnFZemZxZTJ5RGFVRm01QzRjUFJ5STNWNERCOEJJc2xxSSt4eHhJL3VyTmVxeThzQkxLcjVRUWNnVThjUElCbkRPZGM3WDlFaXpSTFlIOGdCekxDcGZCWURGNGpIODZJd05IazVKUThQRERIZVYzNnNFSGtTc0krSGIwYUlpMm52R2J2L3NPK1pNbkkxY1E4TTNJa2FqKzRJT096NXhtTTRwV3JVS3VJT0RrejMrT2x1UEhyMWtHQSszUEIxSmYzaVozOThkSXBSTFB4Y2JpN1lvS2pGS3JzVGdpd3UzSzl3UUg0NTdnWUVRb2xkaGlOR0pDUUFCR3VLNnpUTkpvTU1MWEY0ZFNVM0ZIUVA5ZWZhaU1WQ0wydVZoVXZGMEI5U2cxSWhhN2p6OXkva2lvazlYSW41SVB2emcvQkUyN09zdVhYNXdmUXU0TmdXYXlCbkVyNC9wZE1FcGxKR0pqbjBORnhkdFFxMGNoSW1KeHI4dXFWTkZJVDM4ZlBqNnFUanUwVEFpQ0hLTkh2OWZqdmRIWGtxSldZMk55TXFZRUJlR1hCUVdJVmlveGV0Z3dBRUNjbng5aVZDcThrWnFLSlpHUkdFejlEV1hNUWErZm9zYkdqY21ZTWlVSXYveGxBYUtqbFJnOTJyVituQjlpWWxSNDQ0MVVMRm5pZnYzSmt6WDQ5Ny9ISVQzOU8vajR0Ti9WZm9WYUxjTWpqMmh4OG1RTFB2dHNISG9iZExzbitCN2NFM3dQSXBRUjJHTGNnZ2tCRXpCQ01jS1Z6NU13d25jRURxVWV3aDBCZC9SYWp0R3FhTHlmL2o1VW5YSWhVNThKdVNESGU2UGY2L0VPOWQ0TU5MZDlsRDZJV0JpQjVtK2JVYjIzR2dtckUvcWNkL1BuajBSeXNocFRwdVFqTHM0UDB6ckZqSXZ6dzczM2htRHlaQTFXZG91cDBjanhoei9FWXZic01FeVlrQWVsVXNDOTl3WjNsUDJFQ1FGWXNDQWM3NzgvK3Jwc3N5cEdoZEc3UjhQUjRrRGRKM1VJL1VVbzVKcXJYWnMyUTR2U3phVzQ4OHM3UGI1b3lFZXBSRUpXRnVRYURmVExsME16WlFyVVNVbFh0M1BLRkF3YlBScHBiNy9kOGRoYVoyMzE5Umk5ZXplMDgrWjFPamd4NHJ2YmIwZm96SmtJZit5eGZ2VURvbWpDeElrL3dNL3Y2dmJXMVgyQzJ0ci9oNVNVTFZDclUzcHVnNDhTRVJFTDBkejhMYXFyOXlJaFlYVy9ZZzRrZjFQVUtkaVl2QkZUZ3FiZ2x3Vy9STFF5R3FPSGpYYTEvVGpFcUdMd1J1b2JXQks1NUpyeFZkSFJTSC8vZmZoMGVsbVlQak1UZ2x5TzBlKzkxMk1PQUtEOTNvRngvLzQzdmt0UEIzeDhvSjA3dCtNem1Wb043U09Qb09Ya1NZejc3RE9nRHlQdUErM1BCMUpmTitVSXdCVytndEJqMGhkM05pWW5ZMEpnSUZaZXZOaHhwcm1wdEJSenRkcCs3L3c3RTN5RkhwTitkQmY0UDRHSVdSNkRtci9Yb0NYdjZwbWRzOVdKaGk4YkVQdUgyRUVWa0NENFhuTUhQbUxFakM3SjB0ajROWXpHMXhBWHQ5TGo2eU92WlZab0tKNk9pY0d1cWlwODE5dysrbkNzdVJuVmJXMjk3a2dIVW45REdYUFE2ODhLeGROUHgyRFhyaXA4OTUxci9XUE5xSzV1NjNYbjM1RUxnWExzMkpHSzBsSXJ0bTB6ZHZrc0o2Y0ViNzU1VzEvYVB6WW1iOFNFd0FsWWVYRWxtbDJqUHB0S04yR3VkcTdIblQ4QXpCZ3hvMHZuK1hYajEzak4rQnBXeHEzMCtDclZvYzV0SDErZmE3WWRkLzduZndLeGZIa00vdjczR3VSMWl0bmE2c1NYWHpiZ0R4NWl4c2Y3NFoxMzBsQllhTWFycjdhWC82VkxkdnpwVDZYWXVmTzI2NzdOcVg5SmhUeFFEdjJ6WGMrMHlsNHZRL3lMOFgxK3kyRDAwMDhqY09KRUdOYXNnYVBUZXpGYWZ2Z0JxcWdvdHp0L0FCRGtjb1RPbW5YMUQ1SUUzYUpGRUJRSzNQYm1tLzJ1aTRDQUNWMTJKblo3UGM2ZmZ3SkJRZE1RSGYyMDU0N2R4N2ZmSng2RHpkOVpvYlB3ZE16VDJGVzFDOTgxZitkcSs4ZFEzVmJkcDUwL0FJeVlNYVBMenIveDY2OWhmTzAxeEsxYzZmRlZ3UExBUUtUdTJBRnJhU21NMjdaMSthd2tKNmU5L1B0NHVYMmcvZmxnNnV1bVBBQndaOEhaczVoMzVreVh2eWtFQWJ2UzBsQnZ0MlBGaFFzNDNOU0VFb3NGdnhvNWNzaC84TmtGWjNGbVh0ZjRDV3NUb0lwUjRmd1Q1eUU1MnU5cE5LdzFJUDdGK0M2emlnMEZTYkxqNk5GRWxKZi9wZU52SVNIM1h1Mm9uSzNRNlJiQzMvOTJ4TWV2SG5TODlZbUppRmVwc0VTblE0WE5odXppWW14TzZYa2t1Yk9pQW5GSGpzQW1pamNzcHJ0YzZNLzZ2Y1pmbjRqNGVCV1dMTkdob3NLRzdPeGliTjdzSnY2Q3M1alhMUmNlZkhBRU1qSzB5TW95b0xTMC9mV3luMzVhaDNIakFoQWRyZXBUZklXZ3dLNjBYYWkzMTJQRmhSVTQzSFFZSlpZUy9HcmtyOXlVd1FMTU8zUDFqTy9lVHJuUTZtekZRdDFDM081L08xWVBNQmY2a3R1dHAxdnhkY2pYdUh6eThwRGsrTnExQ1lpSlVlR0pKODdENFlxNWRxMEJMNzRZM3pGTDRNNmRGWWlMT3dLYlRleHhBUGZvb3lPUmxWV0VDeGZNZVBMSjg5aThPUVYrZmo1RHVzMFZPeXR3Sk80SXhFN3hsUkZLSkcxSVF2My8xcVAyby9haGZsdWxEYzNmTnlQczRiQytIL1Q3K0NEdHJiZlFWbHVMb2hkZWFHLzNvb2ppZGV1UXNIYnQxVXR0TzNmaVNGeGN4N0IwME5TcFhjNVF5MTUvSFEwSERpRDE5ZGZocTlYMnV4NDY5eXNBY1A3ODcrQjBtakI2OUM0SXd0WHlyS2pZaVNOSDR2cDlxZEdkdnVidnpvcWRpRHNTMStPU3dQckU5WWhYeFdPSmJna3FiQlhJTHM3RzVwVE5mZC9tZXp2MXBhMnQwQzFjQ1AvYmIwZjg2cTd4dTVjOUFJeDQ4RUZvTXpKZ3lNcUN0YlMwL1F6ODAwOFJNRzRjVkwzTVVYS3RjdmZVbjU4OXV3Qm5Pclg5dnRiWGYvUUJRTGhTaVFnM3d6RHAvdjU0TVQ0ZWIxZFVZSFZSVWI4Ni9INE56WWNyb1l6b0dsK21saUgxTDZtNFhIQVp4aTFHdEo1dWhXZ1RFVGd4OERyOEFobFVxcGhlM3htdDF6OExxN1hjTlZUa08raG9hcGtNNzZTbFFXY3lZV3ArUHJha3BNRFB6Vmw5c0Z5T1dEOC95SWZncHRLK3h1d3RGL3E2ZnEveDFUSzg4MDRhZERvVHBrN054NVl0N25jZzRlRktSRVQwalAvYWE2T2dVQWo0L2U5L2hObnN4RnR2VlNJenMzL3YzMDczVDhlTDhTL2k3WXEzc2Jwb2RhK2RXTGd5SEJGSzk1ZFludFUvaTNKck9kNGIvUjU4QjVnTGZjbHRIN1VQVkxFcXlJYkpoaVREMVdvWi92S1hWQlFVWE1hV0xVYWNQdDBLbTAzRXhFNHhnNFBsaUkzMWcxemVNOS8rL09kUkNBaVFZOHFVZkR6OGNCaEdqVklQK1RiTGcrWHdpL1dEMEMxKzVKT1IwRXpSb1BEcFFqaGFITGo0d2tVa3JVL3FkeG40anhtRG1HZWVRZm1PSFdqKy9udFV2UEVHUmo3NktPU0JuWDlETVB4aVl5SEllMTVKdFJRVjRlTEtsUWliTTZmTEpZR0JxcTdlaTlyYWo1Q2MvQ2Y0K1NWMlBmdVZCOFBQTHhhQ0lCL1NuczVUL2diTGd4SHJGd3Q1dDVocW1ScnZwTDBEblVtSHFmbFRzU1ZsQy94OC9BWVVYLy9zczdDV2w3Y1AvZnQyamQ5YjJZOTY3VFVJQ2dWKy9QM3Y0VFNiVWZuV1c0akp6Qnh3R1hqcXo1WEtjQ2g3YWZ1ZTZ1dG0wdStNMlpTYzNPdG56OGZGWVp2UkNLUFZDbEc2UGs4WEptOXlIMy80ejRaRCs0Z1doalVHTkJ4b3dPMS92LzI2eEJjRUg0d2ZmOUR0WjVjdS9Rc1ZGVHVSa0xBV0FRRmpoeXptVDRLRE1TTTBGRi9VMS9kNmhwK2gxU0pqQUdjWmc0bnBLUmY2c3I3SCtEOEp4b3dab2ZqaWkvb2VaNWtkOFh2SmhaRWpmWkdUazR3bm56eVBCeDQ0aVp5Y0pMYzdxbXQ1UHU1NWJETnVnOUZxaENqMVZnYWIzUDc5WDVmK2haMFZPN0UyWVMzR0RqSVhycFhiNmlRMUpwMmNOS1I1L3JPZkRjY2pqMml4Wm8wQkJ3NDA0Ty9kWW1aa2FKR1I0VDdmaGc5WFlPWEtPRHo3ckw1ZmN3djBaNXUxR1ZwbzNjUVhmQVRjdHZNMmZIL245emoxODFNWThlQUkrTVVQYkFlVXVHWU5hai82Q0xwRmkrQ2ZubzdiUC95dzIyL0lnRFlqbytjb29TamkzRzkrQTVtL1AyN2JzV1BRZFdHelZhR3djQmxDUXU1RlZOVHZlbnl1MVdaQXE4MFkwdnEvVnY1bWFET1EwVXZNbndUL0JETkNaK0NMK2kvNmZOTnJqNzcwWC85Q3hjNmRTRmk3RmdGamU4YnZyZXg5UjQ1RWNrNE96ai81SkU0KzhBQ1NjbkxjSHFEMTZUZGNvejlQN3FYdFg2dSsvcU5IQUR6WmFqVGl5YWdvbEZpdGVMR282SVp2VE1vcktYQ2FuZEJNMWtBZUpMK2hzUjJPSnVoMGl4RVFjQ2ZpNDE4WTB1OCsxdHlNU0tVU29iNitXS3pUdVgxVjcxQWJiTXhCcjMrc0daR1JTb1NHK21MeFlwM2IxOU42OHNRVGtVaEpVVU1tRXpCMWF0QUE4M2tybm94NkVpWFdFcnhZOUdLZjEydHlOR0d4YmpIdURMZ1RMd3hSTG5nanQxOTVKUVZtc3hPVEoyc1ExSStZbHk3WmNmUm9FMzcycytGNDdya0xLQyszM2RCdDlrLzNSOFJ2SXRDYzF6eW9lNEI4L1B5UStOSkxNT2wwaVBwZDN6dHk0K2JOYURwNkZLazdka0F4WXNTZzYrSDgrY2NoaW5ha3BiMExkM1BWRDdYQjV1K3g1bU9JVkVZaTFEY1VpM1dMM2I1YTJHTmYydFFFM2VMRkNManpUc1MvMFAvNGtVODhBWFZLQ2dTWkRFRlRwOTd3L3Z4RzE5ZE5jUUJ3dUtrSk5XMXRlRGt4RWN1aW9yQ3RyQXg1TjNoaUdjWHc5cHQ4ZkZRMy9ucExZZUZUc052ck1IcjBlME02RkZmWDFvWk5KU1hZbHBLQzExTlRrZC9TZ2kxRzQzWGRsc0hHSFBUNmRXM1l0S2tFMjdhbDRQWFhVNUdmMzRJdFcvcTN6WUlBQkFjcm9CcGdMaHh1T295YXRocThuUGd5bGtVdHc3YXliY2hyeWV2VHVrOFZQb1U2ZXgzZUcvMWVqeUhTLzZUY0h1NksyWjh5bENSZzJiSWY4Y29yeVhqenpkc2dpaEorOTd2ek4zeWJGY01WRUh5RWE3Nzk3OXJmTTl6MUcvcDIvNGhKcDBQUkgvK0lrZlBuSSt5WHZ4eDBIVlJXdm9QNitzK1FrcklaS2xYc0RhbjN3ZVJ2WFZzZE5wVnN3cmFVYlhnOTlYWGt0K1JqaTNGTC8vclNwNTZDdmE0T285OTdiMkJuNzRJQVJYQnduK3RzS1B0emI5U1gxdzhBYXRyYThFcHBLZFludGwvcnlFNUtRclJTaVVYbnpxRnRDRzVLdTluVjFYMkNxcXEvSVNGaExmejkwN3Q4WnJVYTBkeDhiRURmSzBvU2xoWVc0dFdVRlBqNitHQldhQ2htaDRWaGRWRVJMcHJOMTJWYkJodHowT3VMRXBZdUxjU3JyNmJBMTljSHMyYUZZdmJzTUt4ZVhZU0xGODAzcEQ1cjJtcndTdWtyV0orNDNwWFAyWWhXUm1QUnVVVm9FOXM4cnZ0SjNTZjRXOVhmc0RaaExkSzc1WUxSYXNTeEFlYkNmNHFYWHk3RzNMbGF4TWY3SVRwYWhRMGJrdkMvLzF2ZjViME0vNjBraHdQbmZ2TWJLRUpDTU9yUGYrN3hlWDhuczdGYWpkRHJuOEh3NFE4Z012THhubmxhOCtHUWI4Tmc4bGVVUkN3dFhJcFhVMTZGcjQ4dlpvWE93dXl3MlZoZHRCb1h6UmY3MXBkKzhnbXEvdlkzSkt4ZEMvLzBibjJwMFlqbVk5ZS8vUXkwUC9kR2ZWM1hBd0NiSk1IZWJlZzJVNi9Ic3NMQ2puKzNPcDE0OU13WmJIRjErQURnTDVOaGMwb0t6cGxNK09NZ0xnVklOZ21Tdld0OGZhWWVoY3NLM1NkZ1cvdkJobWdidW9NT1NiSkJrdXlkL3UzRThlUFRVRlhWL2xLUEs0OTZhRFNURUJ1N292dmFNQml5NE9lWFBLRFl5L1Y2ekFvTlJiemYxV3VZcjQwYUJTZUEzK3AwY0hTcW03M1YxYmo3K1BFdTE5dmQxZDlReHV5ZUMvMWQzMjM4NVhyTW1oV0srRTdYYlY5N2JSU2NUdUMzdjlWMTNKVU9BSm1aZWl6ckpSY0FvSzFON1BYK2dkNjBPbHZ4NkpsSHNTVmxTOGVOVC80eWYyeE8yWXh6cG5QNFk5RWZ1N1dIVEN3clhBWUFxTGZYNDRuelQyQ1NaaEpXZE1zRkNSS3lERmxJSG1BdWVNcHRzOTZNNzhaOEI1UHJ4VWxYbHV2ZWR2cXJ6UlhUWFJudTNWdU51KzgrM3VXemp6NnFSVVdGRlE5M3V1UCs5NytQd3BneC9uanFxY0orWHdyd3RNM1ZlNnR4L083anZiWjFzYzIxL1lPOFduYmxaVC91WGtCVHZYY3ZqdDk5ZDhkbnhldlhvK1g0Y2R5MmN5Y1VJU0U5UmdZdW56elpuNTRIT3QwaUFBTFMwdDUyYzZiNTE0N3V1N3A2TDQ0ZnY3dkxVd0NpMkxYZjZvdis1Ty9lNnIyNCsvamRYYTd4TDljdng2elFXWWozaSsvVTlsK0RFMDc4VnZkYk9DVFBMeU96MTlmai9CTlBRRE5wRW1KWHJPZ3h0R1RJeW9LZjY3Nmo3bVh2cnQ1Nis4empiK2hIZjY3WFo2TFExZmI3VTE4M0U3ZGpHeFUyR3o2c3FZSEJZc0VsdXgwN0t5b3dUNnVGUmk1SHBjMEd1MnNuczd1cUNtc05CbFRhYk1odmFVR0NxOU52Y1RnNm5nSGZWRm9LcXlnaU15YW15MDdCNDRGSGhRMDFIOWJBWXJEQWZzbU9pcDBWME03VFFxNlJ3MVpwZzJqdjJlaE41MHdvMzFuZWZxVDFZUTJHcFExemU1TlFYOWxzRmFpcCtSQVdpd0YyK3lWVVZPeUVWanNQUGo0cVdLMUcyTzJYWEVtd0hHMXR0VkNwb25INjlPek9LUWlUNlVjNEhNMUlTOXZWeitIbkptUVZGZUZnWXlOV3llVXdPNTFReTlydjhQN2kwaVVJQUk0Mk5lRVhwMDVoVlh3OHBnWUZvY0Z1aDlGcWhVT1NVTytoL29ZeVp1ZGNHTWo2WGVJZmJrSldWaEVPSG16RXFsVnltTTFPcU5XdTliKzRCRUVBamg1dHdpOStjUXFyVnNWajZ0UWdWRmJhWUhlVEM3VzFiZmpIUDJwdzdwd0pDb1dBdDk2cXdKdzVZUWdPOXZ3YytPNnEzVmhyV0l0S1d5WHlXL0tSNEpmZ3l1ZVdqdWVhTjVWdWdsVzBJak1tRS9GKzhhaTBWY0l1MmpzNndOcTJXa1Nyb2pHN1V5NklFUEdqNlVjME81cXhxNSs1MEpmY2RyWTZZUzJ6d3RIcWdHZ1RVZk9QR3RSL1ZnOUhpd09HTEFQQ2Z4ME92OFQrM1FoMzdwd0pPMTB4UC95d0JtbHB3N3JjOU5mUVlJZlJhSVhESWFHeTBvSU5HMHJ3emp1Vm1Ea3pGQ1VsRnNURnRjZjc1cHNtV0N3aUdocnMrT2xQZjhEcTFRbVlQMy9rb0xmWjNtQ0gxV2h0ZjB5dzA0TWdraWloNXU4MXFQdG5IU1JSUXRHTFJRai9iVGpVeWVwK2wzdkRWMStoYlB2MjlyUGZyVnZicnluZmZYZW4zOUFBcTlFSXllR0FxYmdZeFMrL0RObXdZYWg0KzIxVXZIMTFKK0M4ZkJsTng0NGg1ZFZYK3pHVS9DNGFHZzVBcFF5WTAxY0FBQUxhU1VSQlZJckZqejh1NjlZM1ZhR2xKUTlUcHVoY082MEdXSzFHU0pJRG9nalUxUHdEOWZXZndlRm9nY0dRaGZEd1gvZnBUdlQrNUcrRHZRRkdxeEVPeVlHOHBqeGtGV1hoWU9OQnJKS3ZndGxwaGxxbWRyWDlMeUJBd05HbW8vakZxVjlnVmZ3cVRBMXlmMTFldjN3NTJtcHJvWXFPeHVuWnN6c1BDOEwwNDQ5d05EY2piZGV1SG1XUFRrOGl0ZFhXb3VZZi80RHAzRGtJQ2dVcTNub0xZWFBtUUJFYzNLZHk3MDkvYnJOVlFuUzEvZjdVMTgyRWt3RnhNaUI0dVFCdTZmcm5aRUMzZUFKeU1xQmJ1dnc1R1JBUkVSSHhBSUNJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUlpSWlJaUliajMvUDBMUHhibFJ0NVd2QUFBQUFFbEZUa1N1UW1DQyJ9XSwibWF0ZXJpYWxzIjpbeyJkb3VibGVTaWRlZCI6ZmFsc2UsInBick1ldGFsbGljUm91Z2huZXNzIjp7ImJhc2VDb2xvckZhY3RvciI6WzEsMSwxLDFdLCJiYXNlQ29sb3JUZXh0dXJlIjp7ImluZGV4IjowLCJ0ZXhDb29yZCI6MH0sIm1ldGFsbGljRmFjdG9yIjowLjQsInJvdWdobmVzc0ZhY3RvciI6MC41fX0seyJkb3VibGVTaWRlZCI6dHJ1ZSwicGJyTWV0YWxsaWNSb3VnaG5lc3MiOnsiYmFzZUNvbG9yRmFjdG9yIjpbMCwwLDAsMV0sIm1ldGFsbGljRmFjdG9yIjoxLCJyb3VnaG5lc3NGYWN0b3IiOjF9fSx7ImRvdWJsZVNpZGVkIjp0cnVlLCJwYnJNZXRhbGxpY1JvdWdobmVzcyI6eyJiYXNlQ29sb3JGYWN0b3IiOlsxLDEsMSwxXSwibWV0YWxsaWNGYWN0b3IiOjAuNCwicm91Z2huZXNzRmFjdG9yIjowLjV9fSx7ImRvdWJsZVNpZGVkIjp0cnVlLCJwYnJNZXRhbGxpY1JvdWdobmVzcyI6eyJiYXNlQ29sb3JGYWN0b3IiOlswLDAsMCwxXSwibWV0YWxsaWNGYWN0b3IiOjEsInJvdWdobmVzc0ZhY3RvciI6MX19LHsiZG91YmxlU2lkZWQiOnRydWUsInBick1ldGFsbGljUm91Z2huZXNzIjp7ImJhc2VDb2xvckZhY3RvciI6WzAsMCwwLDFdLCJtZXRhbGxpY0ZhY3RvciI6MSwicm91Z2huZXNzRmFjdG9yIjoxfX0seyJkb3VibGVTaWRlZCI6dHJ1ZSwicGJyTWV0YWxsaWNSb3VnaG5lc3MiOnsiYmFzZUNvbG9yRmFjdG9yIjpbMSwwLDAsMV0sIm1ldGFsbGljRmFjdG9yIjoxLCJyb3VnaG5lc3NGYWN0b3IiOjF9fV0sIm1lc2hlcyI6W3sicHJpbWl0aXZlcyI6W3siYXR0cmlidXRlcyI6eyJQT1NJVElPTiI6MCwiVEVYQ09PUkRfMCI6MX0sIm1hdGVyaWFsIjowLCJtb2RlIjo0fV19LHsicHJpbWl0aXZlcyI6W3siYXR0cmlidXRlcyI6eyJQT1NJVElPTiI6MCwiVEVYQ09PUkRfMCI6Mn0sIm1hdGVyaWFsIjowLCJtb2RlIjo0fV19LHsicHJpbWl0aXZlcyI6W3siYXR0cmlidXRlcyI6eyJQT1NJVElPTiI6M30sIm1hdGVyaWFsIjoxLCJtb2RlIjo2fV19LHsicHJpbWl0aXZlcyI6W3siYXR0cmlidXRlcyI6eyJQT1NJVElPTiI6NH0sIm1hdGVyaWFsIjoyLCJtb2RlIjo2fSx7ImF0dHJpYnV0ZXMiOnsiUE9TSVRJT04iOjR9LCJtYXRlcmlhbCI6MywibW9kZSI6M30seyJhdHRyaWJ1dGVzIjp7IlBPU0lUSU9OIjo1fSwibWF0ZXJpYWwiOjMsIm1vZGUiOjF9XX0seyJwcmltaXRpdmVzIjpbeyJhdHRyaWJ1dGVzIjp7IlBPU0lUSU9OIjowLCJURVhDT09SRF8wIjo2fSwibWF0ZXJpYWwiOjAsIm1vZGUiOjR9XX0seyJwcmltaXRpdmVzIjpbeyJhdHRyaWJ1dGVzIjp7IlBPU0lUSU9OIjowLCJURVhDT09SRF8wIjo3fSwibWF0ZXJpYWwiOjAsIm1vZGUiOjR9XX0seyJwcmltaXRpdmVzIjpbeyJhdHRyaWJ1dGVzIjp7IlBPU0lUSU9OIjo4fSwibWF0ZXJpYWwiOjQsIm1vZGUiOjF9XX0seyJwcmltaXRpdmVzIjpbeyJhdHRyaWJ1dGVzIjp7IlBPU0lUSU9OIjo5fSwibWF0ZXJpYWwiOjUsIm1vZGUiOjF9XX1dLCJub2RlcyI6W3sibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzMuNDE0MiwtMzMuNDE0Ml19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzYuMjQyNiwtMzMuNDE0Ml19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzkuMDcxMSwtMzMuNDE0Ml19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzMuNDE0MiwtMzYuMjQyNl19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzYuMjQyNiwtMzYuMjQyNl19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzkuMDcxMSwtMzYuMjQyNl19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzMuNDE0MiwtMzkuMDcxMV19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzYuMjQyNiwtMzkuMDcxMV19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzkuMDcxMSwtMzkuMDcxMV19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlstMCwtMzQuODI4NCwtMzJdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbLTAsLTM0LjgyODQsLTM0LjgyODRdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbLTAsLTM3LjY1NjksLTM0LjgyODRdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbLTAsLTQwLjQ4NTMsLTM0LjgyODRdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbLTAsLTMyLC0zNy42NTY5XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6Wy0wLC0zNC44Mjg0LC0zNy42NTY5XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6Wy0wLC0zNy42NTY5LC0zNy42NTY5XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6Wy0wLC0zNy42NTY5LC00MC40ODUzXX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6Wy0xLC0zNC44Mjg0LC0zMl19LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOlstMSwtMzcuNjU2OSwtMzQuODI4NF19LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOlstMSwtMzQuODI4NCwtMzcuNjU2OV19LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOlstMSwtMzcuNjU2OSwtNDAuNDg1M119LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMiwtMzQuODI4NCwtMzJdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTIsLTM2LjI0MjYsLTMzLjQxNDJdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTIsLTM0LjgyODQsLTM3LjY1NjldfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTIsLTM2LjI0MjYsLTM5LjA3MTFdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTIsLTM3LjY1NjksLTM0LjgyODRdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTIsLTM5LjA3MTEsLTM2LjI0MjZdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTIsLTMzLjQxNDIsLTM5LjA3MTFdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTIsLTMyLC0zNy42NTY5XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0yLC0zNi4yNDI2LC0zNi4yNDI2XX0seyJtZXNoIjozLCJ0cmFuc2xhdGlvbiI6Wy0yLC0zNC44Mjg0LC0zNC44Mjg0XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0yLC0zOS4wNzExLC0zOS4wNzExXX0seyJtZXNoIjozLCJ0cmFuc2xhdGlvbiI6Wy0yLC0zNy42NTY5LC0zNy42NTY5XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0zLC0zNC44Mjg0LC0zMl19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMywtMzMuNDE0MiwtMzMuNDE0Ml19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMywtMzQuODI4NCwtMzcuNjU2OV19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMywtMzMuNDE0MiwtMzkuMDcxMV19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMywtMzcuNjU2OSwtMzQuODI4NF19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMywtMzYuMjQyNiwtMzYuMjQyNl19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMywtMzMuNDE0MiwtMzYuMjQyNl19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMywtMzIsLTM3LjY1NjldfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTMsLTM2LjI0MjYsLTMzLjQxNDJdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTMsLTM0LjgyODQsLTM0LjgyODRdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTMsLTM5LjA3MTEsLTM2LjI0MjZdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTMsLTM3LjY1NjksLTM3LjY1NjldfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTQsLTM0LjgyODQsLTM3LjY1NjldfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTQsLTM2LjI0MjYsLTM2LjI0MjZdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTQsLTM3LjY1NjksLTM0LjgyODRdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTQsLTM5LjA3MTEsLTMzLjQxNDJdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTQsLTM3LjY1NjksLTQwLjQ4NTNdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTQsLTM5LjA3MTEsLTM5LjA3MTFdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTQsLTMzLjQxNDIsLTM2LjI0MjZdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTQsLTM0LjgyODQsLTM0LjgyODRdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTQsLTM2LjI0MjYsLTM5LjA3MTFdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTQsLTM3LjY1NjksLTM3LjY1NjldfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTQsLTM5LjA3MTEsLTM2LjI0MjZdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTQsLTQwLjQ4NTMsLTM0LjgyODRdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTUsLTM0LjgyODQsLTM3LjY1NjldfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTUsLTMzLjQxNDIsLTM2LjI0MjZdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTUsLTM3LjY1NjksLTM0LjgyODRdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTUsLTM2LjI0MjYsLTMzLjQxNDJdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTUsLTM3LjY1NjksLTQwLjQ4NTNdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTUsLTM2LjI0MjYsLTM5LjA3MTFdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTUsLTMzLjQxNDIsLTMzLjQxNDJdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTUsLTM0LjgyODQsLTM0LjgyODRdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTUsLTM2LjI0MjYsLTM2LjI0MjZdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTUsLTM3LjY1NjksLTM3LjY1NjldfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTUsLTM5LjA3MTEsLTMzLjQxNDJdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTUsLTQwLjQ4NTMsLTM0LjgyODRdfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbLTYsLTM0LjgyODQsLTMyXX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6Wy02LC0zNy42NTY5LC0zNC44Mjg0XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6Wy02LC0zNC44Mjg0LC0zNy42NTY5XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6Wy02LC0zNy42NTY5LC00MC40ODUzXX0seyJtZXNoIjo0LCJ0cmFuc2xhdGlvbiI6Wy03LC0zNC44Mjg0LC0zMl19LHsibWVzaCI6NCwidHJhbnNsYXRpb24iOlstNywtMzQuODI4NCwtMzQuODI4NF19LHsibWVzaCI6NCwidHJhbnNsYXRpb24iOlstNywtMzcuNjU2OSwtMzQuODI4NF19LHsibWVzaCI6NCwidHJhbnNsYXRpb24iOlstNywtNDAuNDg1MywtMzQuODI4NF19LHsibWVzaCI6NCwidHJhbnNsYXRpb24iOlstNywtMzIsLTM3LjY1NjldfSx7Im1lc2giOjQsInRyYW5zbGF0aW9uIjpbLTcsLTM0LjgyODQsLTM3LjY1NjldfSx7Im1lc2giOjQsInRyYW5zbGF0aW9uIjpbLTcsLTM3LjY1NjksLTM3LjY1NjldfSx7Im1lc2giOjQsInRyYW5zbGF0aW9uIjpbLTcsLTM3LjY1NjksLTQwLjQ4NTNdfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbLTksLTM0LjgyODQsLTMyXX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6Wy05LC0zNy42NTY5LC0zNC44Mjg0XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6Wy05LC0zNC44Mjg0LC0zNy42NTY5XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6Wy05LC0zNy42NTY5LC00MC40ODUzXX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0xMCwtMzQuODI4NCwtMzJdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTEwLC0zNi4yNDI2LC0zMy40MTQyXX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0xMCwtMzQuODI4NCwtMzcuNjU2OV19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMTAsLTM2LjI0MjYsLTM5LjA3MTFdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTEwLC0zNy42NTY5LC0zNC44Mjg0XX0seyJtZXNoIjozLCJ0cmFuc2xhdGlvbiI6Wy0xMCwtMzkuMDcxMSwtMzYuMjQyNl19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMTAsLTMzLjQxNDIsLTM5LjA3MTFdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTEwLC0zMiwtMzcuNjU2OV19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMTAsLTM2LjI0MjYsLTM2LjI0MjZdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTEwLC0zNC44Mjg0LC0zNC44Mjg0XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0xMCwtMzkuMDcxMSwtMzkuMDcxMV19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMTAsLTM3LjY1NjksLTM3LjY1NjldfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTExLC0zNC44Mjg0LC0zMl19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMTEsLTMzLjQxNDIsLTMzLjQxNDJdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTExLC0zNC44Mjg0LC0zNy42NTY5XX0seyJtZXNoIjozLCJ0cmFuc2xhdGlvbiI6Wy0xMSwtMzMuNDE0MiwtMzkuMDcxMV19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMTEsLTM3LjY1NjksLTM0LjgyODRdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTExLC0zNi4yNDI2LC0zNi4yNDI2XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0xMSwtMzMuNDE0MiwtMzYuMjQyNl19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMTEsLTMyLC0zNy42NTY5XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0xMSwtMzYuMjQyNiwtMzMuNDE0Ml19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMTEsLTM0LjgyODQsLTM0LjgyODRdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTExLC0zOS4wNzExLC0zNi4yNDI2XX0seyJtZXNoIjozLCJ0cmFuc2xhdGlvbiI6Wy0xMSwtMzcuNjU2OSwtMzcuNjU2OV19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMTIsLTM0LjgyODQsLTM3LjY1NjldfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTEyLC0zNi4yNDI2LC0zNi4yNDI2XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0xMiwtMzcuNjU2OSwtMzQuODI4NF19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMTIsLTM5LjA3MTEsLTMzLjQxNDJdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTEyLC0zNy42NTY5LC00MC40ODUzXX0seyJtZXNoIjozLCJ0cmFuc2xhdGlvbiI6Wy0xMiwtMzkuMDcxMSwtMzkuMDcxMV19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMTIsLTMzLjQxNDIsLTM2LjI0MjZdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTEyLC0zNC44Mjg0LC0zNC44Mjg0XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0xMiwtMzYuMjQyNiwtMzkuMDcxMV19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMTIsLTM3LjY1NjksLTM3LjY1NjldfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTEyLC0zOS4wNzExLC0zNi4yNDI2XX0seyJtZXNoIjozLCJ0cmFuc2xhdGlvbiI6Wy0xMiwtNDAuNDg1MywtMzQuODI4NF19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMTMsLTM0LjgyODQsLTM3LjY1NjldfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTEzLC0zMy40MTQyLC0zNi4yNDI2XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0xMywtMzcuNjU2OSwtMzQuODI4NF19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMTMsLTM2LjI0MjYsLTMzLjQxNDJdfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTEzLC0zNy42NTY5LC00MC40ODUzXX0seyJtZXNoIjozLCJ0cmFuc2xhdGlvbiI6Wy0xMywtMzYuMjQyNiwtMzkuMDcxMV19LHsibWVzaCI6MiwidHJhbnNsYXRpb24iOlstMTMsLTMzLjQxNDIsLTMzLjQxNDJdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbLTEzLC0zNC44Mjg0LC0zNC44Mjg0XX0seyJtZXNoIjoyLCJ0cmFuc2xhdGlvbiI6Wy0xMywtMzYuMjQyNiwtMzYuMjQyNl19LHsibWVzaCI6MywidHJhbnNsYXRpb24iOlstMTMsLTM3LjY1NjksLTM3LjY1NjldfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbLTEzLC0zOS4wNzExLC0zMy40MTQyXX0seyJtZXNoIjozLCJ0cmFuc2xhdGlvbiI6Wy0xMywtNDAuNDg1MywtMzQuODI4NF19LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOlstMTQsLTM0LjgyODQsLTMyXX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6Wy0xNCwtMzcuNjU2OSwtMzQuODI4NF19LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOlstMTQsLTM0LjgyODQsLTM3LjY1NjldfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbLTE0LC0zNy42NTY5LC00MC40ODUzXX0seyJtZXNoIjo0LCJ0cmFuc2xhdGlvbiI6Wy0xNSwtMzQuODI4NCwtMzJdfSx7Im1lc2giOjQsInRyYW5zbGF0aW9uIjpbLTE1LC0zNC44Mjg0LC0zNC44Mjg0XX0seyJtZXNoIjo0LCJ0cmFuc2xhdGlvbiI6Wy0xNSwtMzcuNjU2OSwtMzQuODI4NF19LHsibWVzaCI6NCwidHJhbnNsYXRpb24iOlstMTUsLTQwLjQ4NTMsLTM0LjgyODRdfSx7Im1lc2giOjQsInRyYW5zbGF0aW9uIjpbLTE1LC0zMiwtMzcuNjU2OV19LHsibWVzaCI6NCwidHJhbnNsYXRpb24iOlstMTUsLTM0LjgyODQsLTM3LjY1NjldfSx7Im1lc2giOjQsInRyYW5zbGF0aW9uIjpbLTE1LC0zNy42NTY5LC0zNy42NTY5XX0seyJtZXNoIjo0LCJ0cmFuc2xhdGlvbiI6Wy0xNSwtMzcuNjU2OSwtNDAuNDg1M119LHsibWVzaCI6NSwidHJhbnNsYXRpb24iOlstMTYsLTMzLjQxNDIsLTMzLjQxNDJdfSx7Im1lc2giOjUsInRyYW5zbGF0aW9uIjpbLTE2LC0zNi4yNDI2LC0zMy40MTQyXX0seyJtZXNoIjo1LCJ0cmFuc2xhdGlvbiI6Wy0xNiwtMzkuMDcxMSwtMzMuNDE0Ml19LHsibWVzaCI6NSwidHJhbnNsYXRpb24iOlstMTYsLTMzLjQxNDIsLTM2LjI0MjZdfSx7Im1lc2giOjUsInRyYW5zbGF0aW9uIjpbLTE2LC0zNi4yNDI2LC0zNi4yNDI2XX0seyJtZXNoIjo1LCJ0cmFuc2xhdGlvbiI6Wy0xNiwtMzkuMDcxMSwtMzYuMjQyNl19LHsibWVzaCI6NSwidHJhbnNsYXRpb24iOlstMTYsLTMzLjQxNDIsLTM5LjA3MTFdfSx7Im1lc2giOjUsInRyYW5zbGF0aW9uIjpbLTE2LC0zNi4yNDI2LC0zOS4wNzExXX0seyJtZXNoIjo1LCJ0cmFuc2xhdGlvbiI6Wy0xNiwtMzkuMDcxMSwtMzkuMDcxMV19LHsibWVzaCI6NiwidHJhbnNsYXRpb24iOlswLDAsMF19LHsibWVzaCI6NywidHJhbnNsYXRpb24iOlswLDAsMF19XSwic2FtcGxlcnMiOlt7Im1hZ0ZpbHRlciI6OTcyOCwibWluRmlsdGVyIjo5NzI4LCJ3cmFwUyI6MzMwNzEsIndyYXBUIjozMzA3MX1dLCJzY2VuZSI6MCwic2NlbmVzIjpbeyJub2RlcyI6WzAsMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgsMTksMjAsMjEsMjIsMjMsMjQsMjUsMjYsMjcsMjgsMjksMzAsMzEsMzIsMzMsMzQsMzUsMzYsMzcsMzgsMzksNDAsNDEsNDIsNDMsNDQsNDUsNDYsNDcsNDgsNDksNTAsNTEsNTIsNTMsNTQsNTUsNTYsNTcsNTgsNTksNjAsNjEsNjIsNjMsNjQsNjUsNjYsNjcsNjgsNjksNzAsNzEsNzIsNzMsNzQsNzUsNzYsNzcsNzgsNzksODAsODEsODIsODMsODQsODUsODYsODcsODgsODksOTAsOTEsOTIsOTMsOTQsOTUsOTYsOTcsOTgsOTksMTAwLDEwMSwxMDIsMTAzLDEwNCwxMDUsMTA2LDEwNywxMDgsMTA5LDExMCwxMTEsMTEyLDExMywxMTQsMTE1LDExNiwxMTcsMTE4LDExOSwxMjAsMTIxLDEyMiwxMjMsMTI0LDEyNSwxMjYsMTI3LDEyOCwxMjksMTMwLDEzMSwxMzIsMTMzLDEzNCwxMzUsMTM2LDEzNywxMzgsMTM5LDE0MCwxNDEsMTQyLDE0MywxNDQsMTQ1LDE0NiwxNDcsMTQ4LDE0OSwxNTAsMTUxLDE1MiwxNTMsMTU0LDE1NV19XSwidGV4dHVyZXMiOlt7InNhbXBsZXIiOjAsInNvdXJjZSI6MH1dfQ==&quot;&gt;Download 3D Model as .GLTF File&lt;/a&gt;\\n\",\n              \"  &lt;br&gt;Mouse Wheel = Zoom. Left Drag = Orbit. Right Drag = Strafe.\\n\",\n              \"  &lt;div id=&quot;stim-3d-viewer-scene-container&quot; style=&quot;width: calc(100vw - 32px); height: calc(100vh - 64px);&quot;&gt;JavaScript Blocked?&lt;/div&gt;\\n\",\n              \"\\n\",\n              \"  &lt;script type=&quot;module&quot;&gt;\\n\",\n              \"    let container = document.getElementById(&quot;stim-3d-viewer-scene-container&quot;);\\n\",\n              \"    let downloadLink = document.getElementById(&quot;stim-3d-viewer-download-link&quot;);\\n\",\n              \"    container.textContent = &quot;Loading viewer...&quot;;\\n\",\n              \"\\n\",\n              \"    /// BEGIN TERRIBLE HACK.\\n\",\n              \"    /// Change the ID to avoid cross-cell interactions.\\n\",\n              \"    /// This is a workaround for https://github.com/jupyter/notebook/issues/6598\\n\",\n              \"    container.id = undefined;\\n\",\n              \"    downloadLink.id = undefined;\\n\",\n              \"\\n\",\n              \"    import {Box3, Scene, Color, PerspectiveCamera, WebGLRenderer, DirectionalLight, Vector3} from &quot;three&quot;;\\n\",\n              \"    import {OrbitControls} from &quot;three-orbitcontrols&quot;;\\n\",\n              \"    import {GLTFLoader} from &quot;three-gltf-loader&quot;;\\n\",\n              \"\\n\",\n              \"    try {\\n\",\n              \"      container.textContent = &quot;Loading model...&quot;;\\n\",\n              \"      let modelDataUri = downloadLink.href;\\n\",\n              \"      let gltf = await new GLTFLoader().loadAsync(modelDataUri);\\n\",\n              \"      container.textContent = &quot;Loading scene...&quot;;\\n\",\n              \"\\n\",\n              \"      // Create the scene, adding lighting for the loaded objects.\\n\",\n              \"      let scene = new Scene();\\n\",\n              \"      scene.background = new Color(&quot;white&quot;);\\n\",\n              \"      let mainLight = new DirectionalLight(0xffffff, 5);\\n\",\n              \"      mainLight.position.set(1, 1, 0);\\n\",\n              \"      let backLight = new DirectionalLight(0xffffff, 4);\\n\",\n              \"      backLight.position.set(-1, -1, 0);\\n\",\n              \"      scene.add(mainLight, backLight);\\n\",\n              \"      scene.add(gltf.scene);\\n\",\n              \"\\n\",\n              \"      // Point the camera at the center, far enough back to see everything.\\n\",\n              \"      let camera = new PerspectiveCamera(35, container.clientWidth / container.clientHeight, 0.1, 100000);\\n\",\n              \"      let controls = new OrbitControls(camera, container);\\n\",\n              \"      let bounds = new Box3().setFromObject(scene);\\n\",\n              \"      let mid = new Vector3(\\n\",\n              \"          (bounds.min.x + bounds.max.x) * 0.5,\\n\",\n              \"          (bounds.min.y + bounds.max.y) * 0.5,\\n\",\n              \"          (bounds.min.z + bounds.max.z) * 0.5,\\n\",\n              \"      );\\n\",\n              \"      let boxPoints = [];\\n\",\n              \"      for (let dx of [0, 0.5, 1]) {\\n\",\n              \"          for (let dy of [0, 0.5, 1]) {\\n\",\n              \"              for (let dz of [0, 0.5, 1]) {\\n\",\n              \"                  boxPoints.push(new Vector3(\\n\",\n              \"                      bounds.min.x + (bounds.max.x - bounds.min.x) * dx,\\n\",\n              \"                      bounds.min.y + (bounds.max.y - bounds.min.y) * dy,\\n\",\n              \"                      bounds.min.z + (bounds.max.z - bounds.min.z) * dz,\\n\",\n              \"                  ));\\n\",\n              \"              }\\n\",\n              \"          }\\n\",\n              \"      }\\n\",\n              \"      let isInView = p =&gt; {\\n\",\n              \"          p = new Vector3(p.x, p.y, p.z);\\n\",\n              \"          p.project(camera);\\n\",\n              \"          return Math.abs(p.x) &lt; 1 &amp;&amp; Math.abs(p.y) &lt; 1 &amp;&amp; p.z &gt;= 0 &amp;&amp; p.z &lt; 1;\\n\",\n              \"      };\\n\",\n              \"      let unit = new Vector3(0.3, 0.4, -1.8);\\n\",\n              \"      unit.normalize();\\n\",\n              \"      let setCameraDistance = d =&gt; {\\n\",\n              \"          controls.target.copy(mid);\\n\",\n              \"          camera.position.copy(mid);\\n\",\n              \"          camera.position.addScaledVector(unit, d);\\n\",\n              \"          controls.update();\\n\",\n              \"          return boxPoints.every(isInView);\\n\",\n              \"      };\\n\",\n              \"\\n\",\n              \"      let maxDistance = 1;\\n\",\n              \"      for (let k = 0; k &lt; 20; k++) {\\n\",\n              \"          if (setCameraDistance(maxDistance)) {\\n\",\n              \"              break;\\n\",\n              \"          }\\n\",\n              \"          maxDistance *= 2;\\n\",\n              \"      }\\n\",\n              \"      let minDistance = maxDistance;\\n\",\n              \"      for (let k = 0; k &lt; 20; k++) {\\n\",\n              \"          minDistance /= 2;\\n\",\n              \"          if (!setCameraDistance(minDistance)) {\\n\",\n              \"              break;\\n\",\n              \"          }\\n\",\n              \"      }\\n\",\n              \"      for (let k = 0; k &lt; 20; k++) {\\n\",\n              \"          let mid = (minDistance + maxDistance) / 2;\\n\",\n              \"          if (setCameraDistance(mid)) {\\n\",\n              \"              maxDistance = mid;\\n\",\n              \"          } else {\\n\",\n              \"              minDistance = mid;\\n\",\n              \"          }\\n\",\n              \"      }\\n\",\n              \"      setCameraDistance(maxDistance);\\n\",\n              \"\\n\",\n              \"      // Set up rendering.\\n\",\n              \"      let renderer = new WebGLRenderer({ antialias: true });\\n\",\n              \"      container.textContent = &quot;&quot;;\\n\",\n              \"      renderer.setSize(container.clientWidth, container.clientHeight);\\n\",\n              \"      renderer.setPixelRatio(window.devicePixelRatio);\\n\",\n              \"      renderer.physicallyCorrectLights = true;\\n\",\n              \"      container.appendChild(renderer.domElement);\\n\",\n              \"\\n\",\n              \"      // Render whenever any important changes have occurred.\\n\",\n              \"      requestAnimationFrame(() =&gt; renderer.render(scene, camera));\\n\",\n              \"      new ResizeObserver(() =&gt; {\\n\",\n              \"        let w = container.clientWidth;\\n\",\n              \"        let h = container.clientHeight;\\n\",\n              \"        camera.aspect = w / h;\\n\",\n              \"        camera.updateProjectionMatrix();\\n\",\n              \"        renderer.setSize(w, h);\\n\",\n              \"        renderer.render(scene, camera);\\n\",\n              \"      }).observe(container);\\n\",\n              \"      controls.addEventListener(&quot;change&quot;, () =&gt; {\\n\",\n              \"          renderer.render(scene, camera);\\n\",\n              \"      })\\n\",\n              \"    } catch (ex) {\\n\",\n              \"      container.textContent = &quot;Failed to show model. &quot; + ex;\\n\",\n              \"      console.error(ex);\\n\",\n              \"    }\\n\",\n              \"  &lt;/script&gt;\\n\",\n              \"&lt;/body&gt;\\n\",\n              \"\\\"></iframe>\"\n            ],\n            \"text/plain\": [\n              \"{\\\"accessors\\\":[{\\\"bufferView\\\":0,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":12,\\\"max\\\":[0,0.5,0.5],\\\"min\\\":[0,-0.5,-0.5],\\\"name\\\":\\\"cube\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":1,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":12,\\\"max\\\":[0.375,0.5625],\\\"min\\\":[0.3125,0.5],\\\"name\\\":\\\"tex_coords_gate_R\\\",\\\"type\\\":\\\"VEC2\\\"},{\\\"bufferView\\\":2,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":12,\\\"max\\\":[0.125,0.5],\\\"min\\\":[0.0625,0.4375],\\\"name\\\":\\\"tex_coords_gate_H\\\",\\\"type\\\":\\\"VEC2\\\"},{\\\"bufferView\\\":3,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":17,\\\"max\\\":[0,0.400000005960464,0.400000005960464],\\\"min\\\":[0,-0.400000005960464,-0.400000005960464],\\\"name\\\":\\\"circle_loop\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":4,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":17,\\\"max\\\":[0,0.400000005960464,0.400000005960464],\\\"min\\\":[0,-0.400000005960464,-0.400000005960464],\\\"name\\\":\\\"circle_loop\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":5,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":4,\\\"max\\\":[0,0.400000005960464,0.400000005960464],\\\"min\\\":[0,-0.400000005960464,-0.400000005960464],\\\"name\\\":\\\"control_x_line_cross\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":6,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":12,\\\"max\\\":[0.4375,0.5625],\\\"min\\\":[0.375,0.5],\\\"name\\\":\\\"tex_coords_gate_MR\\\",\\\"type\\\":\\\"VEC2\\\"},{\\\"bufferView\\\":7,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":12,\\\"max\\\":[0.3125,0.5625],\\\"min\\\":[0.25,0.5],\\\"name\\\":\\\"tex_coords_gate_M\\\",\\\"type\\\":\\\"VEC2\\\"},{\\\"bufferView\\\":8,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":130,\\\"max\\\":[1,-32,-32],\\\"min\\\":[-17,-40.4852828979492,-40.4852828979492],\\\"name\\\":\\\"buf_scattered_lines\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":9,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":30,\\\"max\\\":[0,-29.5,-31],\\\"min\\\":[-15.25,-41.4852828979492,-41.4852828979492],\\\"name\\\":\\\"buf_red_scattered_lines\\\",\\\"type\\\":\\\"VEC3\\\"}],\\\"asset\\\":{\\\"version\\\":\\\"2.0\\\"},\\\"bufferViews\\\":[{\\\"buffer\\\":0,\\\"byteLength\\\":144,\\\"byteOffset\\\":0,\\\"name\\\":\\\"cube\\\",\\\"target\\\":34962},{\\\"buffer\\\":1,\\\"byteLength\\\":96,\\\"byteOffset\\\":0,\\\"name\\\":\\\"tex_coords_gate_R\\\",\\\"target\\\":34962},{\\\"buffer\\\":2,\\\"byteLength\\\":96,\\\"byteOffset\\\":0,\\\"name\\\":\\\"tex_coords_gate_H\\\",\\\"target\\\":34962},{\\\"buffer\\\":3,\\\"byteLength\\\":204,\\\"byteOffset\\\":0,\\\"name\\\":\\\"circle_loop\\\",\\\"target\\\":34962},{\\\"buffer\\\":4,\\\"byteLength\\\":204,\\\"byteOffset\\\":0,\\\"name\\\":\\\"circle_loop\\\",\\\"target\\\":34962},{\\\"buffer\\\":5,\\\"byteLength\\\":48,\\\"byteOffset\\\":0,\\\"name\\\":\\\"control_x_line_cross\\\",\\\"target\\\":34962},{\\\"buffer\\\":6,\\\"byteLength\\\":96,\\\"byteOffset\\\":0,\\\"name\\\":\\\"tex_coords_gate_MR\\\",\\\"target\\\":34962},{\\\"buffer\\\":7,\\\"byteLength\\\":96,\\\"byteOffset\\\":0,\\\"name\\\":\\\"tex_coords_gate_M\\\",\\\"target\\\":34962},{\\\"buffer\\\":8,\\\"byteLength\\\":1560,\\\"byteOffset\\\":0,\\\"name\\\":\\\"buf_scattered_lines\\\",\\\"target\\\":34962},{\\\"buffer\\\":9,\\\"byteLength\\\":360,\\\"byteOffset\\\":0,\\\"name\\\":\\\"buf_red_scattered_lines\\\",\\\"target\\\":34962}],\\\"buffers\\\":[{\\\"byteLength\\\":144,\\\"name\\\":\\\"cube\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\\\"},{\\\"byteLength\\\":96,\\\"name\\\":\\\"tex_coords_gate_R\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AADAPgAAAD8AAKA+AAAAPwAAwD4AABA/AACgPgAAAD8AAKA+AAAQPwAAwD4AABA/AADAPgAAED8AAMA+AAAAPwAAoD4AABA/AACgPgAAED8AAMA+AAAAPwAAoD4AAAA/\\\"},{\\\"byteLength\\\":96,\\\"name\\\":\\\"tex_coords_gate_H\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAPgAA4D4AAIA9AADgPgAAAD4AAAA/AACAPQAA4D4AAIA9AAAAPwAAAD4AAAA/AAAAPgAAAD8AAAA+AADgPgAAgD0AAAA/AACAPQAAAD8AAAA+AADgPgAAgD0AAOA+\\\"},{\\\"byteLength\\\":204,\\\"name\\\":\\\"circle_loop\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\\\"},{\\\"byteLength\\\":204,\\\"name\\\":\\\"circle_loop\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\\\"},{\\\"byteLength\\\":48,\\\"name\\\":\\\"control_x_line_cross\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAAM3MzL4AAAAAAAAAAM3MzD4AAAAAAAAAAAAAAADNzMy+AAAAAAAAAADNzMw+\\\"},{\\\"byteLength\\\":96,\\\"name\\\":\\\"tex_coords_gate_MR\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AADgPgAAAD8AAMA+AAAAPwAA4D4AABA/AADAPgAAAD8AAMA+AAAQPwAA4D4AABA/AADgPgAAED8AAOA+AAAAPwAAwD4AABA/AADAPgAAED8AAOA+AAAAPwAAwD4AAAA/\\\"},{\\\"byteLength\\\":96,\\\"name\\\":\\\"tex_coords_gate_M\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AACgPgAAAD8AAIA+AAAAPwAAoD4AABA/AACAPgAAAD8AAIA+AAAQPwAAoD4AABA/AACgPgAAED8AAKA+AAAAPwAAgD4AABA/AACAPgAAED8AAKA+AAAAPwAAgD4AAAA/\\\"},{\\\"byteLength\\\":1560,\\\"name\\\":\\\"buf_scattered_lines\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,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\\\"},{\\\"byteLength\\\":360,\\\"name\\\":\\\"buf_red_scattered_lines\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAAAAA8MF3+BDCAABAwAAA8MF3+BDCAAAgwAAA9MF3+BDCAABAwAAA8MF3+BDCAAAgwAAA7MF3+BDCAABAwAAA8MF3+BDCAAD4wAAA+MEAAPjBAAD4wAAA+MHu8CXCAAD4wAAA+MEAAPjBAAD4wO7wJcIAAPjBAAD4wAAA+MEAAPjBAAB0wQAA+MEAAPjBAAD4wAAA+MHu8CXCAAD4wO7wJcLu8CXCAAD4wAAA+MHu8CXCAAB0wQAA+MHu8CXCAAD4wO7wJcIAAPjBAAD4wO7wJcLu8CXCAAD4wO7wJcIAAPjBAAB0we7wJcIAAPjBAAD4wO7wJcLu8CXCAAB0we7wJcLu8CXCAAB0wQAA+MEAAPjBAAB0wQAA+MHu8CXCAAB0wQAA+MEAAPjBAAB0we7wJcIAAPjBAAB0wQAA+MHu8CXCAAB0we7wJcLu8CXCAAB0we7wJcIAAPjBAAB0we7wJcLu8CXC\\\"}],\\\"images\\\":[{\\\"uri\\\":\\\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAgAElEQVR42uydd1RUudvHv0OVJoIiVYoCIgiiuBaw/GysYsOCDbFgWQv2XkDBioq9YlsLVtauu4qK4OrqKrooNlBRLICCIggCM/C8f+w79zhLEXXuHYR8zpkj3mTmSXKTm+9NniQiIiIwGAwGg8GoVCixImAwGAwGgwkABoPBYDAYTAAwGAwGg8FgAoDBYDAYDAYTAAwGg8FgMJgAYFQyzpw5gzdv3rCCYDAYDCYAGJWJ06dPMwHAAAC8evUKN2/e5N1OTEwMUlNTy0WePT094e7uzm4+Q+EMGTIEx44dqzwC4MOHD3BycoKjoyMyMzMFs3v79m3o6+tjzJgxAID8/Hw0bNgQ9vb2+Pjxo2Dp2LZtG0aPHi1zLTQ0FOPGjePVbm5uLgIDA9GsWTOEh4fDy8sLVlZWGDlyJK5cuSJ3e+vWrYOrqyvc3d3Rrl07JCQklBo/ISEBDg4OeP/+PS/5z8/PR0hICOrXr4/atWvDzs4Oa9euFbz+Jycnw9TUtFx0QNu3b8eaNWtQv3593m3Vq1cPAQEB2LNnj8Lzffv2bdy6dYv1PgyFkp+fj8jISHTq1Onrv0w/KCdPniQABIBOnz4tmN2NGzcSALKwsCAiooSEBC4dcXFxgqVjxIgRtHPnTplrgwcPprCwMN5sZmZmkpOTE3l4eFBmZiaNHTuW7t69S6mpqdStWzcCQJ8+fZKbvVWrVpGamholJiYSEZGnpyfZ2NiQWCwuNn5+fj41adKEoqOjecl/YWEhde7cmapUqUJXr14lIqK4uDiqWrUqhYaGClr/z507x9U7eZb51zJ37lyaOHGioDYLCgqod+/etHDhQkHtPnjwgGrUqEE+Pj706dMnGjJkCHXp0oXy8vLIx8eH9PX1BX0GSCQSkkgkxKjcnDhxgnx8fL7puz/sCICOjg73t5qammB2DQ0NAQBWVlbc/0UiEQDAyMhIsHT8/fffaNq0qcy1q1evonnz5rzZXLt2Le7cuYOFCxfKlH/NmjWxb98+mJqays1WYWEhgoOD4eTkBEtLS27INSEhAUeOHCn2O7Nnz0anTp3QsmVLXvIfGRmJ06dPo2/fvlw5Ozg4oFu3biWmiS+MjY25f6tUqaKQNrht2zaEh4djxYoVgtpVUlLCjh07sHXrVhw+fFgwu/r6+tDX18eePXvg6emJxo0bw8XFBX369MGePXtQtWpV6OnpCZaeJUuWYNWqVewVuJJz8OBB9O3b99va0o+a6Vq1anF/m5mZCWbX3t4eAODk5MQJkdq1a0NbWxvVq1cXJA05OTl48eIF7OzsuGtv375FZmYmJ0z44MaNGwCAgoKCImFaWlrfNgRVAq9fv0ZKSgpq1KjBXTMxMeGGXv/LuXPncP36dfj7+/OW/zt37nAd0Oekp6fDwMBA0Ppva2sLVVVVODo6KqT9PX36FBMnToS/vz+UlZUV8gIwd+5cDB06FC9fvhTEZs2aNfHw4UPcunULrVu3xvr163Hw4EE0adIEf/31F548ecLVUQZDCHJzc3H58mV06NChcgkAMzMz7s3b3Nxc0AevpqYmJwAAoEGDBmjQoIFgaYiJiUGjRo24/Evf/ps1a8arXWknt3z58mLDx40bB1VVVbnYUlFRAQBIJBLumvTYiv+O+Lx58wYTJkzA3r17ee2MpGLk+vXrMvciKioKU6dOFbT+q6mpwc7OTqYeCsncuXMhkUjQvXt3hT0D+vbtC4lEgoULFwpmMyoqCmvXrkVoaCjs7e1hYWGBsLAw7Nq1C5cvX2Y9EkNQzpw5g3bt2n3zKLjKj5pxNTU11KxZExKJBJqamoLZVVJSgqOjo0yH36BBA6Snp/Nqd9asWdi0aRMA4NOnT1BWVka1atW48M+vjR49GkuWLJF7GgYNGoRt27bh0KFD0NDQKPImLM/OyMjICHXq1MGrV6+4a8+ePQMANGzYUEYUDB06FEFBQbwLQemUy/3793H79m28efMG06dPx+nTp+Hk5FTEC15VVZVXYSi08JTy4sULHDx4EG3btoWWlpbCngE6OjpwcXHBjh07MG/ePG5ahC/i4uLQtm1bKCkp4cCBA4iPj0dWVhaGDBkCb29vbNmyBbGxsQoblWFUPg4dOoShQ4d++w/8yM4PjRs3JmdnZ8HtBgYGUk5ODvf/8+fP05EjRwSz37NnT/rtt99krnXt2lUQZ8jg4GDO+QwAr/kODw8nZWVliomJofz8fHJ1daUWLVpQYWGhjKPg8OHDBSt7Nzc3AkDGxsY0d+5cysrK4sKWLl3KlUu/fv3o3LlzvKZlx44ddP/+fcHr//LlywkATZ48WeHPgDFjxhAAQZwwMzMzacqUKXThwgXu+dO4cWMiIrpw4QLNnDmTMjMzBcv7ggULaPny5cwLrpKSnZ1NFhYWJTpFl4UfWgD06NGDunXrVuluvKWlJT1//lzmmrGxMaWmpgpi//Dhw1StWjUCQMrKyjR37lzevJH/+OMP6t+/Pw0aNIjmz58v4/F++/ZtatCgAWVnZ3Ne0StWrKDevXuTt7c33bx5U64rAHbt2kWWlpZcJ1/cigsdHR3q2rVrha5/Hh4eBIC2bNmi8LSEhIQQAOrevbvgtg0MDKhGjRoKyzsTAJWbgwcP0siRI7/rN35oATB+/Hjy8/OrVDc9PT2dDAwMZK69fPmSzMzMBE3H69evqUmTJlxn2Lp1a3r79q2g6rdBgwZ0+/Zt7pqvry85OTlRbm4uRUREkIaGBl2/fv27baWkpFC7du2oefPm9OTJE3J1dSUAZGhoSO/evePiJSUlkY6ODr18+bJC10EzMzMCUGQUSlEPQQBka2sruO2IiAj6/fffebdz8uRJ0tLSKvJRU1MjNTW1YsNOnjzJesgKTs+ePbnRqG/lh94JsFatWoI6AJYHYmJi4OLiInPtxo0baNy4saDpMDY2xk8//YSAgADo6uoiKioKLVu2FGwzpPHjx2Po0KFwdnYGANy9exc7duzAgAEDoK6ujvbt28PAwACzZs36LjuvXr1C06ZNkZ6ejoiICNSuXRsrV66ESCRCamoqJk6cyMUNCQnBypUr5bocsjzy9u1bbg5e0Uj9f1JSUgS33b59e3Ts2JF3O126dMHHjx+LfPz9/bFo0aJiw7p06cImyCswHz9+5FajfA8qP3IhfL4UsKIjdQLMy8sDEck4AObm5kIkEnHX+HICLA4vLy94e3ujffv2ePjwIVasWIH58+fzavPw4cNITk7G1q1buWt//PEHAKBOnTrcNWtra0RFRSE7O/ubndWGDBmC58+fY+PGjdxvNG3aFKNHj8bGjRuxe/dudOrUCbVq1UJSUhJWr15d4evi5yszFI2Ghgb3QGRUfPLz89G2bdtiwy5evCjonjCK5Pjx4/Dw8PjuVU8/tAD475twRWbJkiVYsmQJevbsCR8fH/To0YML69y5M6ZMmVJiw5Cn6tTW1i5y3dbWFhs3bkTXrl152Q74c54/f4558+YhKipKZhmk9A3w8xUhWlpaKCgowNu3b79JANy9exfnz58HAG6kQcqKFSsQFRWFe/fuYdSoUbCwsEBERESlqIsGBgZISUlBTk6OwtPy6dMnAEDVqlVZ71gJKCwsLPEZU1hYWGnK4dChQ5gyZcp3/84PPQVgbW0Na2vrStUArl+/XmS9f0xMjCBTAL/88ssXxZh0/T4fFBQUwMfHB2vWrCmy8Y6uri4AQCwWc9fy8vIA/LuBy7cQFxfH/f348eMib56HDh2ClpYWPnz4gKysLBnbUu7du1fh6qB0iiMjI0PhacnKygIA1K5dm/WOlYAqVarg/33XinwUtSOm0Hz48AF3795FixYtKq8AICKsW7cOGzdurDSV/8WLF1BVVZVZ75yYmIgaNWoI8gaUmpqKyMjIYsOuXbsG4N8pAb4ICgpCs2bNit31qlWrVgCApKQkmbKRbtz0LUi3IAaAgIAA5ObmyoQ/ffoUBgYGUFVVRWJiItzc3GTK5+jRo7h06VKFq4fSrZYTExMVnpbnz58DgOA+MJWdly9fYuzYsVi7dm2levP+nDVr1ijkILBjx46hW7duRfZh+daO9Ifk0qVLnAe6PDy9fwQOHTpEffv2lbl24MAB8vX1FcR+u3btyMzMjM6ePUtExB0GdPfuXTIzM6NBgwZRQUEBL7ajo6OpadOmlJ+fX+Iyvf/973/Upk0bKiwspJiYmBKX6n0Nnp6eXD2zt7engIAAWr58ObVv357q169PDx8+pD/++IN0dHS4eGZmZlSnTh2ytbUVdF24UEgPIurfv7/C0zJ48GACQGfOnKl0XuBLliyhVatWKcT2oEGDuPoeEhJS6cr+zz//5PJ/5coVQW136tSJO4zse/lhBcCbN2/I1taW6tWrJ7MUqyIzZcqUIg1+8uTJtHnzZkHs3759myZNmkSNGjUiR0dHMjU1pWbNmpGHhwevS8LevXtH9vb2FB8fX2q8jIwMGjhwILm7u5OzszOtWbPmu22LxWJat24dOTs7k7a2Nunq6lKLFi1o06ZNMhtwJCYm0sCBA6l69eqkp6dHXl5eRfZqqCiIxWKytrYmKysrhafF1taWzM3Nv2szFMbXs2HDBtLW1iZnZ2fq0KFDpct/Wloa2dnZUd26dSktLU0wu+np6VSnTh2ZzdC+BxHR/2+wzmB8JX5+fhg1apQg58AzyhdhYWEYOHAg7t27xx2QJTQJCQmwtbXF1q1bMXz4cHZTFEB0dDQ2b96Mffv2scL4AVFiRcD4Vjw8PL7ZwY7xY9O/f3+0b98e69atU1ga1q1bh1atWsHX15fdEAWxZ8+eUp2DGeUbNgLAYDC+iXfv3sHV1RW7du3iDkoSigcPHqBbt26IjIwU9Dhwxr/k5OQgODgYJiYmTAAwAcBgMCojSUlJGDlyJNauXQtbW1tBbL5+/Rq+vr6C2mTIEh4eDhcXF1hZWbHCYAKAwWBUVrKzs7F27Vp06NCB9+V4N2/exIkTJzBlyhRu7wcGg8EEAIPBUCCFhYXyWZusYBsMBhMADAaDwWAwKixMSjMYDAaDwQQAg8FgMBgMJgAYDAaDwWAwAcBgMBgMBoMJAAaDwWAwGEwAMBgMBoPBYAKAwWAwGAwGEwAMBoPBYDCYAGAwGAwGg/GjCYD3799j3LhxaNiwIRo1aoQBAwbg1atXgiY8NzcX69evh7m5OTIyMgSzm5OTgxkzZsDS0hJqamowNzfH+PHj8e7dO0HsSyQShISEoF69etDQ0ICFhQXmzJkDsVissEo0bNgwiEQi5ObmCmZz5syZEIlERT7//POPoHlPTk7G3Llz0alTJ4wdOxa7du3i1V7Tpk2Lzbf0Y2FhwXued+/ejZYtW6JDhw5wd3dHy5YtsXv3bsHK/OTJk2jTpg2aNWsGS0tLeHl54dGjR+xpzqgUnDhxAr6+vvD19YW9vT0cHR0RHBwMiUTy9T9GX0lqaio5OjqSt7c3icViIiKaM2cOmZiY0NOnT4lvcnNzafXq1VSnTh0CQADo/fv3JAQFBQXUqlUrUlZWJmtra6pRowaXhjp16lBycjKv9gsLC8nb25vq1atHPj4+5Orqytn39fUlRXDw4EEuDZ8+fRLEZnp6OlWtWpWUlZVlPh07dhQ078uWLSMdHR1avHgx5eXl8W7v1q1bBICUlZWpevXqZGhoKPMRiUQ0btw4XtMwbdo0MjExoUePHnHX7t+/T3p6ejRz5kzey2D58uVkYmJCd+/eJSKiDx8+UIcOHahq1ap07do1YjAqMoGBgeTt7U0FBQVERCQWi2nkyJEEgAYMGPDVv/fVAqBbt26ko6NDGRkZ3LW8vDwyNDQkNzc3Kiws5LUAxGIxvXv3jlJTU0lVVVVQAbBmzRpq3749JSYmctcOHDhAmpqaBIC8vb15tb9//34KDg6WuRYaGsp1wHwLkP+SmJhIderUoapVqwoqAObMmUNLly5VWCOUSCTUp08fUlNToz/++EMwu6NGjaIlS5ZQdnZ2sfcCAP3555+82Y+PjyeRSESrV68uEjZjxgwSiUSUlJTEm/2//vqLlJSUaPv27TLX09LSSFNTkywsLIotG4awbSM8PJxiY2MrTJ5u375NR44c4TpdRZGRkUGqqqq0bNkymes5OTmkp6dHAOjvv//mTwBERUURAPLy8ioS5uvrSwDo+PHjghWImZmZoAJg0KBBlJOTU+T6qlWrCABpaWnxar+km2tra0sA6MGDB4KVvVgsJldXVzp58iSZmpoKJgDevXtHVlZWlJWVpbCGKK3r/+2I+C7vjRs3lhgeHBxMZmZmvArw/fv3E4Bi07Fu3ToCwOtbuKenJwGgx48fFwnz8fEhALR27VrWCyuA9PR0Wrp0KVlaWlL37t3p2bNnFSZvCQkJ9L///Y+srKwoJCRE5uVXSJ4+fUoAqHbt2kXauXQ0ODQ09Kt+86t8AA4ePAgAcHFxKXZuEgDvc6Cfo6amJujci5+fHzQ0NIpc79evHwBALBaDeDxc8aeffir2es2aNeHg4IC6desKVhbz5s1DkyZN0KVLF0HvwerVq5GSkoIePXpg2bJlSE5OFtT+7t27sWPHDrRt2xa+vr6C2VVRUcHo0aNLDD906BD69OkDkUjEWxpMTU0BAJs3b0Z+fr5MWGxsLIyNjdGgQQPe7F+8eBEAYGhoWCSsdevWAIDjx4+zSWIBiYuLw8iRI1G/fn28efMGFy9exLFjxwTxRREKa2trREZG4ujRo4iLi4O1tTXGjRuH+Ph4QdNhaWmJzp07Q0VFBYWFhUX88j5vo7z4ANSuXZsA0L59+4qERUREEAAyNDQUTBFJ/QCEGgEobdhLJBJRw4YNFTIsVLNmTYqJiRHMZmRkJDVu3Jib9xZqBCAjI4OqVavGTXkAoCpVqtD8+fMFGZ77+PEjGRsbEwA6f/58uXlDefLkCQGg69ev82qnsLCQHB0dCQB169aNG26/ffs2VatWjX7//XfebOfm5nL3/MWLF0XCz549SwDI2NhYsBGZVq1akZmZmYw/hFB8+PCBnJycqHbt2vTy5UtBbRcUFNCxY8eobdu2ZGdnRxs2bKCPHz/yZu/kyZOkpaX1VZ+jR4/ylp43b95QUFAQmZiYkIeHB507d06h7T85OZlUVFTIwsKCcnNz+ZkCKCwsJGVlZQJAly5dKnZ4WtpAMzMzK5UAiIuLIwC0atUqQe1mZWVRly5daNu2bYLZTEtLo7p161J8fDx3TSgBkJmZSVeuXKHjx4/TjBkzyNLSkqtzvXr14l0E7Nmzh+tkoqOjydvbm2xsbMja2ppGjRpFqampCql/ixcvJktLS0FsxcfHcyLI2dmZzpw5Qy1btqQbN27wbltLS4sAFPtwP336NAEgbW1twR66IpGIANCuXbsEv+exsbFc3T99+rRgLxshISFUp04d6tSpE/3xxx+8+3yVZ/Ly8mj37t3k4uJC9vb2tHnzZoX4oEybNo2UlZW/6aWkzAIgLS2Nq3DFNfZ79+5x4Xw6ApVHATBnzhyysLAo1j+AD168eEELFy7kfCCUlZVp9uzZgtju1q0b7d69W+aakD4A/30rDAoK4h7EK1eu5NVejx49OAEQFBREsbGxdPv2bW5u2tLSUiEiwNnZmWbMmCGYvcTERHJwcODau1DCt3v37gSAfv755yJhUmfYWrVqCVYOe/bsoaCgIEFWgBRHaGgohYSE8C58k5OTacyYMWRsbEx+fn4y4p/xL5cvX6bevXtTzZo1acaMGZSWliaI3ZSUFNLU1CzVP0guAuDly5dcg79z506pilSoh2B5EACpqamkr69PERERgnZ8iYmJtHfvXnJxceHKfcuWLbzaXbt2LQ0aNKjIdUUJACkrV64kAGRmZsarnbp16xIA2rBhg8z1/Px8sre3JwA0ePBgQfMeHx9PAOjWrVuC2bx+/Tr17t2bAgMDSUlJiQDQ6NGjee+I7ty5w624mTJlCn348IEyMzPpwIED3LOgc+fOrDeSM8+ePSNPT08yMjKigIAASklJYYXyH7KysmjdunVkbm5OP//8syBL4omIJk2aRNOmTfvm75dZAHz8+LHUEYCrV68SABKJRCSRSCqNAOjVqxctXLhQYfYlEgkNGjSIAJC9vT1vdmJjY8nJyalY73tFC4DCwkJq2LAhAaDXr1/zZkdXV7fEIej169cTAKpataqgw6ILFiwgW1tbwexFRESQiYkJt+T0t99+oypVqnAigG+uXbvGiV4lJSWqV68erVu3jqysrAgAbdq0ifVGPPH06VOaPHky1axZk3x8fATzOzp16hTp6up+1Ueo1WiPHz+miRMnkqmpKY0ZM4YePnwo6Iugh4fHd/W3X+UEKH3QF+fsc+rUKcGH4BQtAFasWEEjRoxQeMNMS0sjNTU1UlVV5c2GdOlbWT7STVqEJDAwkADw6hAlnfsurv7fv3+fy/+HDx8Ey7ejoyP5+/sLYuvdu3ekp6dH06dPl7n++++/c3tyCLUZT3p6OjfMeuPGDQJAenp6gpZ9ZX/btbW1pZYtW1J4eLhgL33lhfPnz1PXrl3J2tpaYUsDr169SocOHfqu31D5mhUDrVq1wv79+/HkyZMiYc+ePQMAuLu7V4rlL4cPH8bNmzcRFham8LRUr14dLi4uvG6H2rhxY2RnZ5e4NeWnT5/g5eUFJSUlVKtWTfAyMDExQfXq1WFkZMSbDTs7OyQnJ+PNmzdFwszMzAAA6urq0NbWFiTPjx49wt27d7F//35B7O3fvx/v37+Hq6urzPWOHTsiMDAQs2fPxokTJ7glwXyir6/P/e3v7w8AWLhwIapWrcrW5vGMtrY2/Pz8MHbsWJw5cwZr1qzB1KlT4efnh2HDhimk/QtBTk4O9u7di7Vr18LQ0BDjx49H165doaSkmCN1nj59+v1t7WvUgtTTtrh54OHDhxMAOnXqVIUfATh16hT17NmT8vPzix2SVwT169enfv36KcS2oqcAiIh++eUXmjJlCq821q5dSwBo1KhRRcJevHhRooMan6MeDg4Ogtnz9/cvcQokOTmZAJCfn5+g9126FXXv3r0rtUe6orl37x6NHDmSDAwMaOzYsQpbEcMHb9++penTp5OpqSmNGDGC4uLiykW65FHfv3orYFdXV6pevbrMwz4vL48MDAyoadOmgjZC6b4EQgqAkydPUteuXYtdb/nq1Svy8fHhzXZ+fn6xAuPatWukra1N9+7dq9AC4OnTp3ThwoVi8+/g4MB7PcjJySFzc3PS09Mr4gtx6NAhEolExS6R5Qt7e3sKCgoSzF5kZCQBoKlTpxYJe/jwIQGgEydOCJae69evk6amJnl6eipEfG7fvp3mz5+vkFUA79+/p8mTJ1NQUNBXr/3me2pm6dKl9Ndff1UYAfDnn3/S0qVLKT09vdykKT8/nxYvXvzdS8C/WgA8efKEDA0NuYM/CgoKyM/Pj0xMTOjJkyeCFoL0MJ7nz58LYi8sLIxUVVXJxcWF3NzcuI+rqys5OTmRiooKr0uizM3NSVdXl2bPnk0JCQn07t07OnToENnY2NDZs2cVVhmFEgDS7S5btmxJhw8fpujoaJo/fz41a9ZM5nwGPomJiSEdHR0aMGAAJ8ZevnxJNjY2tGjRIkHfuAAIvgnNiBEjqEqVKhQdHc1dy87Opq5du37TYSTfyq+//ko1atSgRYsWKWSP9mfPnnE+H3v37hXcfkBAAGef7wOgGOWP8PBw7v5/zzMA3/KlxMRE6t27N7m6upKbm5vgQz4bNmyg3r17cwXg6upKS5cu5bUDOnLkCLfevKSPiooKr+UQGBhIpqampKqqSlWrViVnZ2eaOXOmwpflCCUAoqOjycXFhTQ0NEhPT49at25NoaGhxU7F8Mndu3epc+fO5OzsTF5eXtSlSxdBz8CQdgDOzs6C3+vCwkLasmULNWnShDp27EgDBgygLl260ObNm3kf/du3bx9NnTqVunXrRtOmTVPofvO5ubnUtGlTMjMzo4SEBMHtHz9+nHR0dMjFxYVsbGxYj1jJePr0KZmbm1Pjxo2/a/MhERGPm9czGAwGgzeSkpLQr18/XL16lRUG46tRYkXAYDAYPyZ79uzBqFGjWEEwvgkVVgQMBoPxYyGRSLBx40aIxWL4+PiwAmF8E2wKgMFgMH4w/vjjD5iamsLR0ZEVBoMJAAaDwWAwGGWH+QAwGAwGg8EEAIPBYDAYDCYAGAwGg8FgMAHAYDAYDAaDCQAGg8FgMBhMADAYDAaDwWACgMFgMBgMBhMADAaDwWAwmABgMBgMBoPBBACDwWAwGAwh+erDgMRiMU6ePIkzZ85ALBZDXV0dRIScnByoqKjgp59+wuDBg6Gjo8NKl8FgMBiM8gp9Bbt37yY3NzfasGEDZWRkFAkvKCig33//nTw9PemPP/4gvhk7dixdvHiRVxsXLlygmTNnkq6uLgEgAKShoUG2trbk4uJClpaWZGtrSwMGDKCzZ8+SEERFRdHgwYOpTp06ZGxsTA0bNqTmzZvTggUL6Pnz53TlyhVauHDhd9t59OgRLVy4kOrVq8flHQCpqamRsbEx6evrk6WlJbVp04ZmzZpF//zzDy/5PXz4ME2YMIE0NDQIAKmrq5OFhYXMx9TUlNTV1QkA+fv7y9X+gwcPaMGCBWRlZcWVgYmJiYx9fX19LmzBggW83fu3b99SSEgItWjRghwcHMjJyYmaNGlCbdq0oVWrVlFSUhKNGTOG8vLy5Hb/69aty+XN2NiYZsyYQTdu3ODiHTt2jCZMmEBqampcvP/973+0fPlyys7Olmv+79y5Q4GBgWRpacnZMjc3p/nz59OdO3cEaX/S+lC7dm2Z+jBv3jyKiYmRmx1p+depU0em/OfNm8e1tYyMDFq4cCFpa2sTABKJRNSlSxc6cOCA3NJx8OBBGjNmDKmqqnLpcHFxoYCAALp9+7bcy/fhw4c0c+ZMMjIy4uxt3769zN8fOGu29kwAACAASURBVHCgTD0MDg7+6nqYm5tLixYtIjc3N+63+vfvX2L8Z8+e0aJFi8jJyYkAkJOTEy1atIhevHgh17KJiYmhX375hezt7cnW1pYsLCzI3t6eJk6cSE+ePPnq3yuTAMjOzqYePXrQsGHDylSQEomEZsyYQaGhobw1woyMDNLW1qYePXoI0uhXr15NAEhLS6tI2OXLl8nR0ZEAkI+PD4nFYl7SkJmZSX369CFlZWWaPn06JSUlcWE5OTm0a9cuMjU1JWVlZZo0aZJcH7rSRhAeHk4SiYQLi42NpfHjx3MPBx8fH/r48SMv+R89ejQBIDc3txIb7eDBg2nixIm82P/777+5cnjw4EGxD+yGDRvSzJkzebF/6NAh0tHRoRYtWlB0dDQVFhZyYampqTRnzhxSUVEhAHJ98MTGxnL5PnHiRInxpk2bRgCoRo0alJ+fz7sIlqYpMjKSFME///zDpeH06dO82YmJieHsnDx5stg4jo6OZGhoSFFRUbylw9fXlwCQoaGhXATmlzh79iyX73r16snU95J4+fIl9yzS1taWSz2cP38+l47g4OAvihcAlJiYKNeyyM7OJl9fX1JTU6MlS5bQu3fvuLCEhATy9vbmwuQqAHJzc6lFixbf9FY1ZMgQunfvHi+VIyQkhACQsrIyPX/+nPfKeOzYsRIFABFReno6p1hDQkJ4ETz16tUjJSUlOnbsWInxkpKSyMzMjAYPHixX29IG8Pmb3+f8+eefpKenx6luPjqAwMDAUgWA9A15xIgRvNSBly9flioApGJpwoQJcre9YMEC7i2koKCgVJEAgG7duiU322lpaVy+S3vDlbZJR0dH3tvj48ePuTR9y5uPPEhJSeHSEBsbqzA7y5YtI0tLS3r69Cmv+ZV2hE2bNhWkfJOSkkhNTY0bWTp+/PgXvzN16lRuNKROnTpyS4t0BFhJSYl+//33UjtqADIvSd9Lbm4utW7dmgDQoUOHSozn5+dHAGj8+PFl/u0vOgGOGTMGpqamCAoK+urphdWrV8Pf31/u0xaFhYVYv349tLW1UVBQgE2bNvE+VaKsrFxquL6+Pvr27QsA2L17t9ztDx8+HA8ePMDw4cPRvXv3EuPVqlULW7Zswfv37wXLOwC4ubkhLCwMAHDp0iUsXbpU7mWgpPRln9UaNWqga9euCqkDAODo6Fjq/fkWIiIiEBAQACsrK+zcubPUcvDy8sKgQYPw5s0bXvJdmm1pWFnuk1BpqghpKM3Or7/+ig0bNiAyMhJWVlaC5FdFRUWQ8lVVVYWGhgYGDBgAAFi2bFmp8bOysrBt2zYMGzaMl3TWq1cPhYWF6N+/PxISEkptA2V5VpSVCRMmICoqCj169ICXl1eJ8YKDg2FoaIi1a9di7969ZXumlhYYGRmJY8eOYePGjd+UcF1dXdSoUQPPnj2T6404fvw4NDQ0EBgYCADYtm0bcnNzFe5PIb3pqampcv3d33//HeHh4QCAadOmfTG+h4cHzM3NBc9/p06d0LFjRwDAihUrkJWVpZD7wJcAKCtt2rSR22/l5ORg8ODBICJMnz4d6urqX/zO9OnTIZFImINTBWfnzp3w9/fH+fPnYWlpWWHzOXXqVIhEIly5cgVXr14tMV5oaChatWoFOzs7XtKxf/9+mJubIyMjA927dxfk+RYXF4etW7cCAEaPHl1qXE1NTQwcOBAAMGvWLOTl5X2fAAgICMD06dOhr69f7Fv41q1b0bdvX0yaNAmBgYE4deoUWrRogWPHjsl0RufPn5droaxZswbjxo2Dr68vNDU1kZaWhgMHDii0kubk5ODIkSMAgCZNmsj1t0NDQwEANjY2sLa2LtN35s2bp5ByGDRoEAAgMzMTp0+fFtT2/v378c8//ygk32KxGLNmzZL774aFhSE5ORkA0KtXrzJ9x8HBAZ07d2Y9ZAVm3bp18Pf3x4ULF8r8TPhRcXBw4F4sShoFkEgkWLt2LaZOncpbOgwNDXH8+HFoaWnhwYMHGDhwIIiI17yHhYWhsLAQKioqaNGixRfjt27dGgDw8uVLREZGfrsAuH//Pm7cuIGRI0cWCcvLy0OvXr0QHR2NvXv3YtWqVXBwcMCECRNw9epVNG/enItrYWFR4nDJtxAbG4vY2Fj4+PigWrVq8Pb25hqEUBQUFMj8ff36dXTq1AnPnj2Dvr4+Fi9eLFd70hvp4OBQ5u/UqFFDIY21WbNm3N83btwQzO7bt2+xYcMGhYm/xYsX49OnT3L/7ZMnTwIATE1NYWBgwHo+BhYsWIClS5fi4sWLsLW1rRR5lo58njhxAo8ePSoSfvDgQRgbG6Nly5a8psPZ2Rl79uyBSCTCiRMnEBAQwKu9y5cvAwDMzc2hoaHxxfj29vZFvlsaJU6SHD9+HG3atIGenl6Rzq9z5854//49rl69ClVVVQCAra0tnj59ip9++gmGhoZcfC0tLbkOz69ZswbDhg2DlpYWAMDPzw9bt27FrVu38Ndff8mIDz7Izs6GkZERDA0NkZ2djZcvX3LDrV26dMGqVavkqsjT0tLw4cMHhXbqX6uSpaSkpPBi49atWzLDfNnZ2Xj16hXvavxzGjRoAJFIBADIz88HEWHChAlyt/PgwQMAQPXq1UuNt2HDBly5cgXv3r2TSeO4ceNgZmYmt/T06NGjxGkIefqdMIpnxowZOHPmDNzc3OR6X8s7bdq0gYuLC2JiYrB8+XJs27ZNJjwkJARz5swRJC09evTAggULMHfuXCxatAjOzs5lHp37WqSjf9WqVStT/M/jSb/7TSMAN2/eLFZNBQcH4+LFi9ixY4fMg0A6z//focfXr1/D2NhYbm95Bw8ehJ+fH3fNycmJS6cQowBaWlp4+/Yt4uLikJiYiHfv3iE8PBz169fHuXPnMHPmTCQlJcnNXn5+Pvd3WRSgovncSUlNTY0XG40aNcLDhw+5z4sXL/DkyRPUr19fsHzGxsYiNzcXubm5yMnJwdy5c3mxI73/mZmZpcYbO3Ysli9fjqioKJw9exYaGhoIDg6Weydx9OhRmbL//MPHFAijqPBUVlbGlStX0KVLF+Tk5FSavEuH9/fu3SvTuV24cAGZmZno0aOHYGmZM2cO+vfvDyLC4MGDcffuXV7tfT7qXBqfP3PL4ohYogB4/vw56tWrJ3PtyZMnCAwMhKenJxo0aCATdvHixWIFQHx8vNwcVDZv3gx3d/civzd27FgAQHh4OG9vnSWho6ODXr164ebNm3B2dsZvv/2GZs2ayc0LW19fn+tU3759W+4b6ef5NjExEcyulZUVRo0apZA8V6lSBYGBgbzsfikdUXn9+jUKCwtLjWtqaso5fzZs2JD1lhWQAQMGYM+ePVBWVkZkZCS6du3Ky9RTecTLywuWlpbIy8vDmjVruOsrVqzA5MmTBV8NsmPHDjRp0gTZ2dno3r070tPT5W7DyMgIQNlH1z53TDQ1Nf12AfDx48ciww4rV65Efn4+Jk2aVESdHDt2DAYGBnBxcZEJO3PmDDp06PDdBSEWi7Fp0ybExMTAzs5O5uPv7w8VFRWIxWJs2bJFIZVTXV2dm/tPTk7G+vXr5da5SN9s79+/X+4b6d9//8397ebmJqhtd3d3rsEoYuRDulxJnkhHt/Lz8/Hnn39+Mb50So6v0RdG8chz2deX6N+/P/bt2wcVFRVcvHgR3bp1qxQiQFlZmet7Nm/ejKysLNy7dw8xMTEYOnSoQoT/sWPHYGpqisTERPTt27fMb+plRfoMffHixRdHAaUv6VKkDoHfJAA0NTVllhIREQ4dOgRjY+Mi3ohhYWF4/vw5fv75Z25eFPh3/loikXxx/rIsHDp0CDVr1kRSUlKRocf4+HjMmDEDALBlyxaIxWKFVNDPvf/l2Vn369cPAHDnzh0kJiaW6TvZ2dmCzol/Xhekb//t27cX1LaNjY3CBACAIiNm8mDYsGFcm5KWLaP8oaurK6i9Pn36cCLg/Pnz6N69e7lYCi3l4cOHvPzusGHDoK+vjw8fPmDLli1YsWIFxowZo7DpUWNjY5w4cQKampq4cOECpkyZIvcRH2n/WxavfukyyTp16pTJIbJEAWBhYSEznJ6YmIi0tDQZ5yfg3+UG0vlPd3d3md9YvHgxNzz/vaxZs6bUwh07dixUVVWRnJyM3377TSGV4fMhegsLC7n9rnQzJgCYPXt2mUZLZsyYIeM/IASXL1/GiRMnAAALFy5U2FtoXl4epk+fXiE6Fnt7e4wZMwbAv0OOsbGxrLctZ+jo6Mg4vwqFl5cXDhw4ABUVFURERMDT07NciID8/Pwyb0TztWhpaXFTfSEhITh69Kjc+phvpVGjRvj1118hEonkPgLt7OzMvQB+acM7iUSCnTt3AgCWL19epo2QShQAP/30E27duiXzUAWAjIwM7lpKSgqCgoLQtm1bAICrqysXdu7cObx+/Zpbv/k9REdHIykpiSuIkpSYp6cnAGDVqlVyv8llGVUICQn5t1CVlLjdqOT1dnHgwAFoamriwIEDCAoKKvHtPi8vDyNHjsSIESPKtGmMvPIeFxeHvn37orCwECNGjOBlSE46vPalkY358+fzMgf++Ry8vIf6SmPFihXw8PCARCJB//798eLFC0EfcGXNtzRMiLJRxL1IT09H3bp10bVrVxQWFnJ2O3fuzOsUwH+XHX9Or169cPDgQaioqODs2bPo3LkzbxvUSJ8DX3oeBAQEoHHjxt9tTyKRFOv3Mn78eKirqyMlJQX9+/cvsjxWOnL9JZ8ZeaTlczHG15LA0NBQODo64uzZs6WOAs6dOxePHj3C7Nmzy+4QWdIewXFxcWRtbS2zH3GNGjUIAP3yyy80d+5c6tatG71//547fenevXuUl5dHK1asIA8PD+5QmOvXr9Ply5e/aR9ksVhMTZs2JS8vry/G3bJlC7dntjxPwyIiWrFiBQEgTU1N+vDhQ5E94qUH1SgrK/N2CFJUVBRZWFhw++Hv3buX4uPjKSMjgx4/fkxbt26lDh060F9//SVXu7du3eLK9b+nL6akpNDixYtJR0eHtLW1v3hYxvcwbNgwAkCWlpbFnjXw6dMnWrRoEWlpafFyING1a9cEOfylOPLz82nq1KmkpqZGRkZGFBoaSjk5OTJ537VrF+np6ZG6urpc6//nh94cPXq0xHjjxo3jDgPi60AsKZcuXeLSFB0dLcg9uHv3Lmdz7969dP78eapZsybve/DfuHGDs3vq1Kli44wcOZKL4+joyMvZBEOGDCEApKurSwkJCTJnUuTk5ND9+/dp9OjRpKmpKZdTIK9cuUIikajI85aIaPjw4aSkpETx8fElHkqlo6Mjlz35379/X+o5KFIKCwvJy8uL8HWH7JY5DV26dCFVVVUKDg6mzMxMLuzp06fk4+NDGhoatGbNGvkdBtS2bVuZB92ZM2fI1NSUzMzMaP78+ZSbm0tERJGRkWRqakomJibk7u5OYWFhXOUoKCggd3f3Ym/il/j999+pWbNm3BG8o0ePLvEmLFmyRObYUnV1dRoxYkSxFeRruHDhAk2fPp07YAKfHctpZ2dH5ubmpKurSw4ODjRs2DC6e/curw+D7OxsWr9+PbVt25aMjY25o3lbtGhBGzZskKkY38ujR49owYIFZGNjI5N3AwMDcnBwIHt7e7KysqLOnTtTSEgIpaWl8ZLnw4cP09ixY0lJSYlLQ/Xq1alOnTrcx8zMjDsFrG/fvnK1/+DBAwoKCiJra2vOvqGhIQUEBMj1+NeykJiYSIsWLaJWrVpR7dq1ycnJierVq0eWlpbk7u5OK1eupOTkZLne/8/blZGREfn7+xc5DtjPz0/muFghjwO2srKiwMBAQY4DXrBgARkYGJChoSF5e3t/9/OlNO7fv09z5syROYbayMiIZsyYIVPvtmzZQrVq1ZJpo8rKyuTh4UGbN2/+7nQcPHiQRo0aRcrKyjI2Svp07979u+tdUFAQdwyym5sbLV26lN68eSPTJnv16iXzvTNnztCkSZOoSpUqXFo6dOhAy5Yt+6Z6+ObNG1qyZAk1adKEO5Fw4cKF9OjRoxK/k5OTQy4uLrzViYiICPL29iYbGxtycHCgevXqUYMGDWjmzJnfdAKoiEoZT7116xYGDx6MmzdvfvNw8oIFC2BsbIzhw4ezyUIGg8FgMMoJSl9ybvD19cWQIUO+aT4lNDQUycnJrPNnMBgMBuNHEgAAMGnSJDg7O8PT07PMm9t8/PgRfn5+SExMlNt6eAaDwWAwGPKj1CmAz4mOjoa/vz9atmyJQYMGFXsIxePHj7F//35ER0dj9uzZcj0WlcFgMBgMhgIEAPDv8qtz584hPDwcz58/h6qqKpSUlCASiVBQUAArKyt4eXmhVatWMnsFMBgMBoPB+IEFAIPBYDAYjIqBEisCBoPBYDCYAGAwGAwGg8EEAIPBYDAYDCYAGAwGg8FgMAHAYDAYDAaDCQAGg8FgMBhMADAYDAaDwWACgMFgMBgMBhMADAaDwWAwmABgMBgMRjnn3bt3sLa2BttAFrhx4waSkpIqvgCIj4/HwoULYWdnB5FIxH00NDSgp6cHOzs7+Pr6IiYmhvcE379/H+PHj4e9vT3MzMxQvXp1ODk5YebMmXj16pXc7V28eBGzZs2Cnp4el29lZWUYGhqiatWqsLCwgIeHBw4fPixIo7h//z769+8PQ0ND6OrqwsbGBuPGjcOVK1ewcuVKXLp0Se42w8LCZO57WT59+/b9brvnzp3DrFmzUK1aNe53GzZsiCVLluDly5cycRMTE7F48WI4OTlBJBKhVq1amD9/Ph4/fvzN9qOjo9GzZ0+ZfNWrVw+LFy8uNv7p06fRokULLm63bt3w5MmTr7a7bNkymJubc79Tu3ZtrFy5EgAQFxcHX19f7gwOkUiEjh07IiwsTOY3Ll++jJEjR0JJSQmqqqoYMWIEkpOTvyodSUlJmDRpEmrVqiVTBoaGhpgzZw6ys7O5uL/99ht69+7Nxalfvz6CgoK+6/5HRkaiXbt2MrYNDAzg7++PFy9eyMR98uQJRo0axZVL1apVMW3aNLx+/VoubSAqKkqm/Wtraxf5KCsrQyQSQUVFBVevXuXtGZCbmwuRSAQ1NTXUqFGD+/y3TPhAX18ftra2uHbtmkI6rBcvXsjkWU1NDSKRCLm5uYKmQywWY9CgQZg0adKPrWLoK7h58yYBIAB06dIlIiJKT0+nBQsWkLKyMolEIlq1ahXxQUFBAU2fPp1UVVVpypQplJSUREREEomEoqKiyM3NjbS0tGjr1q282F+7di0BoKpVq1J2djYREX369Im2b99O2traBIAGDx5MhYWFxBeXLl0iDQ0NGjBgAL18+ZKIiJKSkmjWrFmkoqJCACgyMlLudjdv3kz29vZ08+ZNysvL4/IurQt//fUXdy8ePXpEnp6e5OHhITf7wcHBnK2UlJRS4yYkJBAAun79utzsz5w5k7N/8eLFUuOKxWJSV1ensWPHfpfNR48ekZKSEgEotk1NmTKFS9OjR49K/J369evTwoULvystubm51K9fP87e1KlTi42XlpZGAGjs2LGUn58vt/KfNm0aZzsgIKDUuM2bNycLCwuKj4+Xaxs4fPgw1a1bl/7+++9i2/i9e/eoSpUqBIBmz55NfCJte+3atSNFsHPnTpowYQKVB37++WcCQJ8+fRLU7rJly8jHx4fq169P58+fpx+VrxIAqampXEO8e/euTNicOXMIAIlEIrk+fImICgsLqU+fPgSANmzYUGycvLw86tixIwGg4OBguRfUsWPHCADp6uoWCdu2bRtXLvv37+flRkkkEjI3N6f69euTRCIpEn7kyBESiUS8CIDly5dznfx/H0KfC4DPw7y8vORmPzw8nACQpqbmF+Pm5eURAHr37p3c7L979460tLQIAK1YsaLUuA8fPiRdXV3KyMj4brvu7u4EgPr06VMk7O3bt6SqqkoA6MiRI8V+Pycnh6pVqyaXshCLxdSqVSsCQDVr1qT3798XiePn50d9+/aVe/0Ti8XUsGFDAkB2dnYkFouLjZeenk56enp07do1uadh48aNdOrUqWLD8vPzufQ1atRIruKnPAqA9+/fk5WVFa8vO+VZALx+/ZrMzMwoJSWFLl68SA4ODiXWyQolAN6+fVuiAHj16hUXNnLkSLkmctGiRQSA/ve//5UaLykpiTQ0NEhJSYnOnTsn1zScPHmyRAEgkUhIXV2dAJCnpycvN+r27dsEgHr37l1inE6dOvEiAPbu3VuksZcmAIiIdu3aJTf7R48eLbHsi+ssAFBWVpZcy2DMmDEEgOzt7UuNN2fOHJo4caLcyh0AaWlp0cePH4uEd+3alQDQwIEDi/3+kSNHqGvXrnIrg5cvX5Kenh4BoCFDhsiE7d+/nxwdHbnRMT7qv3SUa+nSpcXGGTt2LE2ePJkX+0uWLCkxb9IRoipVqtC9e/d4f2grWgAQEXXp0oWio6MrpQAYMGCAzKicl5cXrVmzpnILACLi3pJ+/vlnuSUwJSWFNDU1CQCFh4d/MX7Pnj0JADk5OclVoZYmAIiI6tSpQwCoRYsWvNyoW7ducZ1BSQ+ZHTt28CIASnsIlSQA5El5EADx8fEkEokIAJ09e7bEN0FjY+NSh+S/huzsbG56KSwsrEj4+vXrCQBpa2sX2zn17t2b9u3bJ3cxKL3vZ86cISKiu3fvkrGxsdyH3YsTVwBIQ0ODEhISZMKuXbtGVlZWxQolPrl8+TI3VbN69WpB254iBcCePXvIz8+v0gmA6Ohoql+/vswb//Pnz8nExITevn1beQXAhw8fuLChQ4fKLYHLli3jfrcsQ5nbt2/n4l+9elUQAfDp0ydOpIwaNYqXGyUWi8nU1JRLw6+//lokzqtXr+j58+dMAPAgAKRvPQCoY8eOxYbv37+f2rdvL1ebgwYNIgDF+lT07t2buwf/7egzMzOpRo0avLyR9+jRgwCQmZkZPX/+nGxsbEqchpAnubm5VK9ePW40UCrw8/PzydHRscQher7IzMwkKysrrjMWaki8PAiAzMxMsrS0pIKCgkojACQSCTVo0IAuXLhQJCwoKEjuI98/lADYtGkTF1bSG9L33GBTU9OvelMG8N3OT2UVAAsWLCAApKamxutb0Pnz5zlHIwDUvHlzioqKUkjFqYwC4MKFC5yfy/3794uEt2zZUu4dYUREBAEgFRUVevPmjYzgrlatGicC/isQfv31V/L29ublfqSmplKNGjU4p9hp06YJVu+uXr3KvXFLHX4XLVpUrJ8E3wwdOpQAULVq1ejFixeCtz1FCgAiIk9Pzy86xVYkAbB27doSfZs+ffpE1tbWdOvWrcohAG7cuEFE/3rnHz58mHR0dAiA3OY/pdjZ2REAcnR0LFP8Fy9e8OKLUJwASEpKoilTppBIJKLq1avTiRMneL9h169fp7p163J5BECdO3cutkNiAkD+NGjQoNi6FRcXR7Vq1SrWQfN7KCgo4EZ+1q1bx13fuXMn9ezZk6KioooVCO7u7nT69Gne7snhw4e5+3/y5ElB697EiRO5jjc6OpqMjIwoOTlZ0DRI62RJ0zOVQQDs37+ftxHP8iYA3r59S6ampqWOsB47dozc3NwqhwDo0aMHeXp6UqNGjcjBwYG8vLx4GYIzNzcnAOTi4lKm+Dk5OVwa+/fvL3cBoKKiQu7u7uTg4EAASElJiTZv3sxbh1MceXl5FBwcTLq6ulxeVVVVadGiRUwA8CwAdu7cyc1Dp6WlcddHjx5NCxYs4MWmdBlcs2bNuGsdOnSgo0ePUmFhIVlaWhIAWrt2LRH96zdjaGjIq2fy1atXSVlZmZsK+PDhg2B1Lzs7mxt6V1FRoc2bNwv60ExJSeFGQPhY9fCjCICPHz+ShYWF3EVveR0BqIjI1QmQD1xcXAgA2dralin+u3fvuDSOGTOGtxGAjIwMql27NgGgESNGKOTmpaWl0aRJk7jlYGVZJ/0jCoATJ06UWQDk5uYSAMrJyeFNfBkaGhIATnBlZWVR9erVv7hHwbdy584drqwfP35MKSkpZGBgwO3JMHv2bAJATZo0ISKiNWvW0OjRo3ntAC0tLSk8PJwTocOGDRO07u/Zs4cTYkIvR/Pw8OCmJeW53PRHEwBE//qhREREMAHwg1LutwK2srICALx+/RqFhYVfjP/27Vvu7wYNGvCWLl1dXRw+fBjq6urYunUr9u/fz2s55OTk4P79+zLXqlevjpUrVyI2NhZ169YFACxZsgRpaWkVastNDQ0NrgzoC7stZmdnQ1lZGVWqVOElLWpqahgzZgwAYMOGDRCLxdi9ezfat28PQ0NDXmw6OjpydXnfvn04cOAAevXqBTU1NQCAj48PAODvv//G48ePsW/fPgwYMICXtEgkEvTt2xeTJ09Gr169EBISAgDYvn07zp07J1idqFat2r9bmf7/zn9CsWnTJpw5cwYikQg7d+6Enp5epd4Ot2/fvjh48CDbI7kibwWsSLp06QIA+PjxIx49evTF+LGxsQAAZWVleHh48Jq2Ro0acVu0/vLLL0hISODNVmZmJrZu3VpsWL169XDy5EmoqKhALBbj9u3bFaqS1qxZk9t+MzU19YtbhZqYmPDaKYwePRpVqlTB69evcfDgQWzatAljx47ltQyknXxYWBjCwsIwcOBALszOzg4uLi4AgKCgIKSmpsLNzY2XdEyfPh3GxsYYN24cAGDYsGHo0KEDAGDEiBHIysqqsA/LhIQETJ06FQDg5+fH5bukelgZ6Ny5M86dOweJRMJ6UyYA5E+PHj24DiA8PPyL8Y8dOwYA6NevH8zMzHhP35gxY9C3b19kZWWhT58+vO5JfezYsRJHQWxsbGBnZ8eNTlQkbG1toaWlBQBf3IM8IiICzZo14zU9BgYG8Pb2BgBMmTIFANCyZUtebQ4YMADKysp49OgR0tLSinTwUkGw97mGFQAAIABJREFUZ88e9OvXjxcBdOjQIZw9e7aIEN26dSu0tbWRlJTElUdFQyKRYODAgcjJyYGdnR2Cg4NLjCsWi7Fp06ZK0YFoaGjA1dUV58+fZ73pj8jXzBckJydzc5GxsbGCepsCICMjo1K3WE1ISCB1dXUyNDSUu1ew1BFNR0enSFhmZibZ2NgQAPL19eWlDKRlX5Kj35s3b0hDQ4NsbGwEWZublZXF1YUrV67wbi8gIIDbaKkk57bbt2+Trq4uxcTE8J6euLg4Lv8bN24UpB1Itwb29/cvdl5e6pR3584dudu+ceMGGRgYlLjaRLopEQBBVsNI26OGhoYgZT9v3jzO6VC6AqoktmzZQitXrqwUPgBE/+44+d+dIZkPQAV0Avz777+5Ri70phvSDYF69uxZbAfw/v17cnFxoerVq3+xgX4Lq1ev5taAF+fx/M8//3Br9CdPnix3D+zPxdfAgQM5AVZYWEi3bt2iJk2akL6+viCdHxHRgwcPuPQcPHiQd3u5ubnUq1cvAkCtW7emyMhIyszMpKysLLp16xZNmzaNtLW1aceOHYLVyQ4dOpCOjo5gK0Ckjm8l7TTYsWNHql+/vtztnjx5kvT09Ep19MvLy+PW5+vp6fG+Je66deu4+peens6rrevXr3PbEAcFBZUYLyMjg0JDQ0lLS4vXA2LKmwD49OkTmZubc06pTABUMAHw6NEjCgoKImtra67R1apViwIDAwXrcIj+XWdZq1YtatSoEe3du5fu3LlDN2/epDVr1pCZmRm1a9eOnjx5IlebFy5coBkzZnD7HAAgV1dXCg4OLjLKEBoaysUxNzcnPz8/ev36tdwEwPjx4+nGjRu0YMECcnV1JWNjY6patSpZWFjQqFGjBNmM5NmzZ7Rw4UKqX78+l1cTExOaN28eL8LrcwoKCmjnzp3UoUMHMjQ0JBUVFdLV1SV7e3saM2aM4HshnDlzRq4rTb7Ex48fqW3btiWGh4WF0eLFi+Vm7/Tp09SuXTvuPtesWZPmzp1Lubm5MvGio6NldiXE/29ZPWrUqCJb9n4v0dHRNGvWLO5MAgDUtGlTWrJkCaWmpvJS7p/XdU1NTdLS0iry0dDQkMk/X2kpjwKAiGjgwIGC7wfBBMD3IyIS4BB7OSIWi7Fnzx5MnDiRczhSV1fHhQsXeHN8YjAYjPJCbm4uNDQ00K5du0o/996xY0ecPXsWnz594m3lD3MCLEeoqqrC19cXly5dgqmpKQAgLy8PFy9eZHeTwWAwGIyKKgCkNGrUCHfu3EGfPn0AAIGBgTh16hS7owwGg8FgVGQBAAD6+vo4ePAgoqOj4ebmhl69emHVqlXIz89nd5bBYDAYjFL44XwASuP+/fs4dOgQnj59CltbW7Rv3573NeEMBoMhJFIfADU1NZmdCG/cuIFatWpV6Ly/ePECDRs25P6fmZkJsVhcoX0AYmJi0LRp06/6zpUrV8r0nQolABgMBoPBYJQNJVYEDAaDwWAwAcBgMBgMBoMJAAaDwWAwGEwAMBgMBoPBYAKAwWAwGAwGEwAMBoPBYDCYAGAwGAwGg8EEAIPBYDAYDCYAGAwGg8FgMAHwQxAREYEuXbqgZ8+erDA+IyMjAytWrICFhUWlO55ULBZj6dKl6NChA7S1tdGoUSP89ttvFTKvsbGxGDp0KCwtLctFevr37w9DQ0PExcUpxP7AgQNhZGSEe/fuCWLvxo0bGDJkSLnY7vfly5fw9/eHsbEx/vnnH/YQ/FGhb+DatWukoaFBAOjhw4dU0SksLKQJEyaQubk5AaDu3bsT419u3rxJXl5epKSkRAAoIiKi0uRdIpFQ+/btKTQ0lIiIrl69SlWqVCEAdP78+QqV1/Xr15OzszMBIENDw3KRJktLSwJAR44cUYh96fMgPDycd1s7d+6k9u3bEwCqXr26Qsv9ypUr5OPjQyKRiADQ7du32YPwBwXf+sXDhw+TSCSiZcuWVZrCCg8PZwKgBNzc3CqdANiwYQMBoKysLO7a7t27ycjIiP76668Kl9/Hjx+XKwHw5MkTOn36tMLsx8fH04kTJ6iwsFAQe8nJyeVCAEhxcHBgAuAH55unAHr37o0lS5bg+PHjlWa0pHr16mzIqARq1KhR6fK8f/9+qKqqQltbm7vm4+OD5OTkCnkKZXmr/7Vr14aHh4fC7NvY2KBr164QiUSC2Pv85L/yQHlLD0NgH4AZM2bA0dERb968qRSFpaKiwmoMKxuOhw8fQlVVld1jhiAoKyuz9DDk26a/9wc2bdrESpFRKcnIyIC6ujorCAaDUflGABRBYWEhtm7ditatW6NHjx6oW7cufvrpJ4SFhQmajry8PMycORNGRkbQ0dGBl5cXkpKSBLGdm5uLxYsXw9XVFU2aNEHt2rXxyy+/ICUlRRD758+fh7u7O9q0aQM3Nzf4+vri/fv3gpX9hw8fMHPmTLRo0QJmZmYwNjbG8OHDkZqaKkinb2dnBzs7O0gkEuTk5HD/HzFihCD537lzJ9zd3TFq1Cg4OztDJBLJfAICAgRJx9mzZ/HTTz9BU1MTLVq0wOPHjwWrA4mJiZgzZw6MjY1x8+ZNwZ9DSUlJCAgIgKmpKf7880+FPQ/z8vIwYMAAiEQiGBsbY+bMmYiKiqoQnZNEIsGRI0fw888/cyuvjh49ChcXF2hra6NNmzZcnXv69Ck8PT2ho6MDU1NTbNy4Ue7puXz5Mry9vWFnZwcAuHjxIpo3bw5NTU00b94cCQkJgpTLqVOn0LlzZ3Ts2BE2NjZwc3PD3r17v+3HfjSnhfHjxxMAunfvHhERZWdnk729PQGgP//8k1fbly9fJvwfe+cdFtXxNeB3d+lVEJAqEkSk2nvsGnuLLWJNxN6NLdGfJrbYey8k9hJLjBqj0ajBGnsDCxakWOi9M98fLvsBghplF8t9n4cnZu7unrlz586cOXPOGRAtW7YUX3zxhfj8889FixYtVJ7ftra2IiwsTK11iIuLE9WqVRO+vr4iPT1dCCHE7t27BSCcnJxEfHy8WuWvWrVKGBsbixMnTqjKJk6cKACNOAFGRkaKypUriwMHDgghhMjKyhJLly5V3X90dLTG+qJCoRCGhoYa7f9jx44V2tra4u7du0IIIdLT00XdunUFIHr27CkSExNFZmamWmQnJCSonABXr14t2rZtKxYsWCBatmwpAFGzZk2NtME///wj+vTpo+pzFy5c0OgzOHfunOjfv7/KC97f318jcjMyMgp0Ahw1apRo1KiRRvu+EELUr19frU6A33//vXBzc1M5Xk+ZMkV88803YuHChaJmzZoCEBUqVBAXL14UderUEbNmzRKTJk1SRaj9888/RVaXjRs3iq5duwpAODo6itWrV4tmzZqJ6dOni6ZNmwpAVK5cWe1tPnnyZOHs7CwePXqk6hNDhgwRgPD19dVcFEBxYWxsLLS1tfOUTZo0SQDip59+0ogCUKpUKXH69Ok83sC2trYCED4+PmqtQ48ePYS9vb1ITk5WlaWmpmok/Ozy5ctCS0tLzJs3L095ZmamcHBw0IgC4OPjIyZNmvRSuaenpwDEtGnTPloFICAgQMhkMtGoUaM85QcPHhSAMDMzU6v8HAVAR0dH/Pzzz3mev52dnQBEaGioxtrDy8urWBSAHKpXr17sCsDYsWNF27ZtRWpqqsbvX90KgBD/H3nl6OgoLl++rCpPSkoSJiYmAhDDhw9XLYaEEGLOnDkCEEOHDi3SuoSEhAhA6Ovr5+n/GRkZwsrKSgDi4cOHamuLv/76SwBi27ZtL/WLnPFv/fr1mokCKC5GjRrFuHHj8pQZGxsDkJycrJE61KxZk9q1a6v+38XFhVmzZgHw22+/kZGRoRa5YWFhbN26lS+++AJ9fX1Vua6uLsePH8fPz48GDRqo7b4nT55MZmYmX331VZ5yhUJBlSpV1N7u0dHR7Nixg8OHD9O+ffs8fzo6Ori6umpkG6C4OHPmDEIIrKys8pRXrFgRgJiYGFJTU9VeDzMzM/r06ZPn+bu7u6v6qKYo7qgEc3PzYt0KHTBgAKGhoezevfuj9UUpUaKEqo9XqlRJVW5gYKDqc7169crjjOvl5QVAeHh4kdYlZ56xsrLK0/+1tLSoUKECAE+ePFFbW8ycOROAxo0b5ynX0tJi8ODBAPz000//6Tc/OLfeH3/8EYD09HR27tzJ3r17CQkJUb0UxUXnzp3p3bs3ycnJhIaG4uTkpJYJIDs7u8BMYDVr1lRr6FlSUhKHDx9GV1cXOzu7l65rwiP40qVLZGVlMWrUKLp168anRs6El9/XI2ciMjU1RU9Pr1jqlqOQakIB0WSfex/lCyHo3r07e/fuJSgo6KOOznhVGxsaGqraIzc570BaWprG6mJiYqKal9RBYmIiJ06cKFTxrVevHgBBQUE8ffoUa2vrN/rdDzIVsJ+fHzVq1CAlJYWtW7fSq1evYq+Tnp7eGzf6u6yA1a1lFsajR4/IyMhALi++LpNz/w8ePOBTpFmzZtjZ2XH16lUSEhJU5cHBwQB06dKl2OqWEwtfnEr4p4JMJsPY2FjlAJiZmSk1yntCfmWkqAgNDVX9ds44mBt7e3vVv/+LJfyDUwD69u3LhAkT+P333+nXr997ZfrKzs5GR0cHGxsbtfy+qampyhJQGOrKS56j/aakpBAREVEs7ZuTcGf//v2FfubChQsf7eCir6/PoUOHKFWqFJMmTVL1uRkzZuDu7s7s2bOlEfgTYcmSJVSsWBF/f38mTJggNchHTs7Yn1vhz03OPKilpVWghfajUAD++ecf/Pz8aNWq1XtxIEZuoqKiePbsGc2aNVObGbZq1aoA3Lx5k4MHD750/eTJk2o7GMXJyUll5n3VBKzOFWDOHuD58+fZvn37S9dv3rzJ33///VEPBAYGBhgZGZGcnMzXX3+Nr68v7u7unDt3TsrM9gmhp6fHrl27MDU1Zf78+ezdu1dqlI8YGxsbXFxcAAp81jmLshYtWvynRfEHpQDkOHXcuHFDZQ7Jysri+vXrwP/v+URGRmq8buvXr0dXV5fp06erTUbZsmVp2LChyhJy+vRp1bW//vqLESNG0KZNG7XI1tXVxcfHB3jhDJh/GyIxMRF4EaOvLmxtbWndujUAffr0YdmyZao95/Pnz9O9e3eN+QYIIcjOziYrK0tjfSwlJYWmTZvi4+PD2rVr+fnnn/Hz82PChAkqByV133NRfEaT9fmYyH+/zs7O+Pn5qd6HO3fuFGt9PvZn/CaLG3XWd/z48cCLPCBJSUkvLf7kcvl/twZ9SCGA9+/fF9ra2gIQTZo0EePGjRPVq1cXXbp0EYBwdnYWPXr0UOUIKGpu3rwp9PT0hIGBgVizZo0q9GTXrl3C3Nxc7Nu3TyNtYGNjo4qBdnBwEBYWFkJbW1ucPHlSrbKjoqJEuXLlBCDs7OzEkiVLxO7du0XPnj2Fo6OjAISnp6eYMmWK2g5ICQ0NVckChLa2tjAyMhKAWLt2rUb7Yk4dnj9/rhGZt27dEoBQKBTCyclJuLq6Cjc3N+Hp6Slq1qwpBgwYoMoPoA6Cg4MFIAwNDV96vo0aNdLYyXg5eHt7C0AcOXKkWMajVq1aaTQMMOcwIF1d3Ty5Hvr37y8A4eLiIp4+faqx+885DEidocc5YYD169cvNAzz77//zlP++++/C0DUqVOnSOty584dAYgSJUq81P9zTmpUZ//Pzs4WPXv2VOVFiI2NFUIIcf36dVG6dGkxe/bsjz8PwJYtW4Sjo6MwMDAQbdu2FY8ePRIPHjwQNjY2wsPDQ5w5c0at8h89eiRGjBghnJ2dhbm5uahQoYLo1auXuHPnjsba4PHjx6JHjx7CzMxM6OvriyZNmohz585pRHZkZKQYMGCAsLCwEPr6+qJx48bi33//FZ06dRINGzYUO3fuFBkZGWqtw7Nnz8TAgQOFtbW10NHRERUrVhQ7d+7UWPvPmTNHFYMOiFq1aomFCxeKmzdvql32pEmThK2trbCxsREGBgaqY5hz/szMzMSTJ0+KXO5vv/0m6tWrp5LTqVMncejQIXH9+nUxZswYVVIcNzc34efnp/Z8CMOGDVPVxcvLS/zyyy/FpgDkzgmiLjZt2iQaNmyouueuXbuKP/74Q6SkpIiOHTvmWRDMnDlTNTmog3v37omhQ4eqZHp4eIhly5YVuZzVq1cLFxcXAQi5XC5Gjx4trly5Ii5cuCAGDRqU5/kvWrRICCHEvHnzVIsUuVwuRowYIe7fv//Oddm3b59o0KCBSuZXX30lDh8+LG7cuCHGjh2r6v/ly5cXq1atUqsSsGbNGlG5cmVRsmRJUblyZdG8efO3VoJl4lOzo0lIfKBERETQrVs3du3apYqPziE1NZVHjx4xYMAAfH196dmzp9RgaqZ169YcPHiQa9eu4e3tLTWIxAeHXGoCCYkPAx8fHxo3bvzS5A8vnMLKly9Pw4YNP8mjmYtrT1gul6sl54eEhKQASEhIAHDx4kWOHj2Kv79/ocl2rl27xrlz5/jiiy+kBlMDsbGxeZLLJCYmUrduXY04YEpIqAPpgG8JiQ8ANzc3vL29OXToEE5OTrRu3RpXV1cMDAyIi4vj4sWLREZGsmPHDumcdjWQmprKZ599hra2Ntu2bcPDw4O7d+++MiRWQuJ9R/IBkJD4gCah1atX8+uvv3Lz5k2SkpIwMzOjcuXKqhDIjzktbHHTr18/duzYQXZ2NvXr1+fHH39U5eaQkJAUAAkJCQkJCYkPAskHQEJCQkJCQlIAJCQkJCQkJD4FpA1DCQkJCQmJYkCWc4ymZAGQkJCQkJCQkBQACQkJCQkJCUkBkJCQkJCQkJAUAAkJCQkJCQlJAZCQkJCQkJCQFAAJCQkJCQkJSQGQkJCQ+Ji5f/8+ixcvJikpSWMyfX192bx5s0bvc//+/ezfv5+srCzpoUsKgISEhMSnixCCyZMns3TpUnr37o2hoeFHfb+tW7dGoVDQokULHj16JHWAd0RKBCTxTvj7+1O3bl2pISQkioFZs2Zx+vRpjh079kncr0wmo2XLlqSlpdG0aVOuXLmCkZGR1BEkC4CEprly5Qp+fn5SQ0hIFAPx8fFMmzaNhg0bfnL33qBBA4KCgli1apXUESQFQELTpKamMmDAAKTDJCUkiodLly6RkpJCVFTUJ3fvOffs7+8vdQRJAZDQJGlpafTs2ZMLFy5IjSEhUUzkpJG/evXqJ3fvOfcsl0tTmEYUgOzsbA4ePEj79u1p0aIFQghmzZqFg4MDBgYGNG/enICAAI1U+vLly3Tu3Jnq1atTrlw5atWqxbp166hRowYnTpxQu/wzZ87Qu3dvXFxcEEIwduxYTE1NadOmDdnZ2WqX7+/vT8uWLWnfvj3lypVDJpNRokQJjbS9EII+ffpw8eJFAH7//XcqVqxIxYoVCQ8PV5vcefPm4enpiUwmo2bNmqry06dP07dvX2QyGTKZjNu3b6tF/ooVK7CyslLJ6du3L6Ghoarru3fvxsvLCzMzM9asWVMkMvft24ejo6NK5vTp0wE4dOgQ9evXV5W3bdtWtRLKyspi3LhxyOVyvL29uXHjRpHUZdeuXVStWlUl09vbm1u3bpGWlkanTp2QyWRUrlyZI0eOqKX9p06dir6+PjKZDC0tLSZMmEBcXJzq+qFDh3Bzc0NXV1fVTmoZMOVyzMzM8PLyUvX7ihUrYmJigkwmo3Tp0hqzirm6ugJw8+bNT27iunXrFgDu7u7SLP6OA/obMWPGDFGhQgUBiMaNG4vhw4eLtm3bin79+gkrKysBCHNzcxEcHCzUybp164S1tbU4ceKEqmzz5s1CLpcLQBw/flyt8pcuXSpq1aolAGFnZyd++OEH0a5dO6FQKIRCoRCRkZFqlX/nzh1hbW0twsLChBBCZGdnixkzZghTU1OhSfbu3SsA0bt3b43JPHPmjABEjRo1Xrrm7u4uABEYGKg2+VeuXBEymUwAIjo6+qXrvr6+4ueffy5Smbdu3RJyuVzo6+uLjIwMVXliYqKwsLAQgLh7926e7yQnJ4uSJUuK58+fF2ldUlJSRPXq1QUgvvzyS1X54sWLRc2aNUVSUpJan/+KFSsEIKytrQu83r17dzFx4kS1yc/IyBAeHh4iJSUlT/mNGzeEnp6eUCgU4p9//tHoe2hjYyPMzc1FcdC3b1+xadOmYpH9v//9TwBi9+7d4kPmg1EAhBDir7/+EoCwtLQUW7ZsUZWHhYWJ0qVLC0B89dVXamssf39/oVAoCnzoderU0YgCIIQQwcHBAhB6enpi+fLlqoH61KlTapc9ffp0YW1tLTIzM1Vl2dnZonbt2h+9AhAYGFioApDz/NWpAAghRIsWLQQgNm/e/NKk6+7uLtLT09Um86+//spTPmrUKAGIefPm5SnfvXu3GDhwoFru//79+8LIyEgA4siRIyI0NFS4uLioFFJ1kp2dLby9vQUg/P3981xLTU0VVlZW4vHjx2qTn5ycLKZMmVLgcwfE1KlTNT6BVK5cOY8y9qkoAH///bcAxNmzZyUFQFM+ADnhFl5eXvj4+KjKbW1t+fHHH1Vmy/T0dLVUdvLkyRgZGdG+ffuXrllbW2us0XLM7UZGRgwcOFBliqpTp47aZaenp/P06VP69u1LbGysai9w7NixkjlLAwwbNgyA5cuX5ynfsWMHX375Jdra2kUu85tvvgHgl19+KbDPr127Nk+5n58fvr6+arn/zz77jLlz5wIwZMgQ+vTpw4IFC7C1tdXInveECROAF+Fv+bcoatSogYODg9rk6+vrM3HixDxlI0aMICAggIYNG750Td08ffqUiIiIl9riU6Bhw4Z07dqV48ePa0Te48ePad++PXZ2dtSqVYupU6dy586dAj/r5+fHgwcPPq4tACGEOHv2rGoLID+RkZECEIAICgoqck0pPj5eKBQKUaVKlQKvd+zYUWMWgISEBNUWgKYJCgoSxsbGAhBmZmZi0qRJRW7qlSwAr16Furi4CEBcvHhRVV67dm0REhKiFplpaWnCwsJCGBgYiLi4OCGEEOnp6aJChQqiatWqAhAnT54UQgjx5MmTQt+RoqRp06YCEF988YVG+11mZqZwdnYWgLh69aqqvG7duuLgwYMarcvOnTsFICwsLDRiAcndBv7+/mLQoEEiICCg2FavxWkByNmSGTdunFi6dKmIiopS6ztfv359sWnTJhEYGCj27NkjevbsKYyMjET16tXFkiVLVFvfV69eFY0aNRJZWVkfnwXgVZQsWRJjY2MAMjMzi7yiISEhZGVlqeW3PyScnZ35999/adiwITExMUyfPp2yZcuybt06aXmuAWQyGUOGDAFg6dKlwAunVGtra+zt7dUiU0dHh+7du5OcnMzOnTsB2LJlC+3atWPo0KEAKsfDDRs20KdPH7W3w8iRIwH4+++/VQ6hmkChUKisXTNnzgQgMDCQkJAQmjdvrrF6BAcH079/f2QyGb/88otGLCA5nDp1ioULF9KxY0fc3Nw+2Xcxxxk0JCRErVaQoKAgmjVrRo8ePShfvjwdOnRg48aNPHnyhMGDB7Nv3z6cnZ3R19fnq6++Yv78+R9OdEJRWQCEEMLQ0FDI5XLVKqUouXnzpgCEiYnJJ20ByM2xY8dUTlmadogpDgvA7du3i90CIIQQcXFxwsjISOjp6YmIiAjh6+srjh49qlaZ169fF4D4/PPPRXZ2tqhatap4/vy5SEpKEqampkJPT09ERUWJihUrFuigWNT9v1KlSmLChAkCEB4eHiI1NVVj/SA1NVXY2NgIuVwu7ty5I4YPHy5mzJih0ZVnjiPwqFGjiu39nz17thg9erTIzs7+JC0AFy9eFM2aNRMRERFqlZOSkvKS42d+0tPT36oeH6QFoKBQt4iICJKSkqhWrRomJiZFXlEnJye0tLSIj49n//79n6zWu3r1atLS0gBo1KgRZ8+eZcSIEQBs3Ljxo753HR0dgFceeKKJMEwTExN69epFamoq8+bN48qVKzRu3FitMr28vKhSpQqnTp1i0aJFVKtWDUtLSwwMDOjevTupqakMHjwYDw8PzMzM1FqXIUOGMHz4cH766SeaN2/OrVu3mDJlisb6ga6uLiNHjiQ7O5spU6awfft2+vbtqzH5U6ZM4ezZs1SpUuWllee9e/c0Vo9x48axZ88efv75509uHIyPj6dly5YMHToUCwsLtcrS09NDT0/vlZ/R1tZWez3eGwuAu7v7S9fWrFkjALFr1y61aWLt27cXgHB2dhYPHz5Uld+9e1c4ODho3AJgY2Ojca13/PjxL2ndOfVRZwRGfg4ePCgA0a5dOyHEC29odYeAJiUlCblcLgwMDPKEW27ZskWYmZkV6B2uLgICAgQgZDKZWLx4sUZkLl++XABCW1tb3Lt3T1V+5coVlRXo77//VmsdNm3aJHx8fFT/HxISIoyNjYVCoRBnzpzRWP+Lj48XJUqUEIDo3LmzRq1ucrlcGBsb53kGOfz4448aHQ+8vb2Fp6fnJ2cBWLlypUbfd3XxQSoAgFi3bp2q/N69e8LOzk7069dPrY314MEDVeyzvr6+aNmypWjVqpXw8fER7dq105gCEB4eLgCho6MjEhISNK4AmJqa5ok3PnLkiNDW1tboy5BjjjcwMBCLFy8WnTp1Ek+fPlW73BznM1dXVzF8+HDx+eefi+nTp6u2AKpVqyZmzZqlkTZo0qSJMDQ0FLGxsRqRFxMTI/T09ESnTp1eula1alXh7OysVnPw1atXhY2NjYiJiclTPn36dAGIzz777KVr6mTixIkCEMeOHdOIvIiICGFrayuAPGHQOQQFBYmWLVtqdCtCV1dXGBoafnIKwLhx4wQgVq5cKSkAmlYAatasKQYPHixatWolGjduLKpXry5WrFihkb2ou3fvitatWwsDAwNhb28vZsyYITIzMzXmA7Bz505Rt25dlSJUs2ZNsXXK+OcMAAAgAElEQVTrVo0qADmyK1asKNq3by9atWolzp8/r/HOO3nyZGFkZCS8vLw0kgNBiBc5J5o2bSr09PSEm5ubqu3r168v2rZtK/7880+N7Ynu27dP9O/fX6Nt7uPjU+CzXr16tZg5c6ba5O7atUtYWFgIhUKRJ979xo0befxQPD09xfbt2zXSFhcuXBDlypXTaNvnWGBq1KiR58/Ly0vo6OiIZs2aaaw+OX4hLi4un5wCsGjRIgEIX19fSQF4X5wAixNNOgFKSEgUP99++62YP3/+J3v/hw8f1vgWyPuiAJw8eVIAGrW4fIwKgJYU2CUhIfGhkZiYyPbt27l+/fon2walSpUCPs18+Dnhj5pMAPcx8p8UgByFRbyHR8AK6VhaCYmPmoMHD6Kjo0O9evUYP348Xbt2xdzc/JNtD29vb7y9vUlOTv7k7j0lJQWAnj17Si+GphSAnNO3cp/C9b4QExPz3tZNQkLi3fD396d169bAixP5ypcvz6lTpz7pNpHJZGzatInOnTszYsQI7OzsPpl7nzFjBuPHj6dBgwbSy/EOvFEegNTUVKZMmaKKN7906RL9+vXj5MmTxX4DN27cYMyYMaq6jB8//pPMjS0h8THj6elJtWrVMDU1xcfHh+PHj6s938GHYgU4ePAg06ZNY+7cuaocIR8rJ06cYPDgwdSqVUsa54tCiRSS7VxCQkLigycpKQldXV20tD5e1674+Hi1JJortglYJpNJCoCEhISEhMSntgIvZgVALj0CCQkJCQmJTw8tlM5zxcbRo9JTKE6Up8hJFNMKQOr/xYpo0qR4K9C//3vdPltPncLn88/VJ6C42/8TR7IAfISERUdj3a8fSw4dkhpDQkLircgWgvMaPNxIQlIAJIqA53FxPIuL48bjx1JjSEhIvBWPnj+njJWV1BAfMVImwI+QimXKUNrCgi+rV5ca4wPHWV+fQfb29LCxoZTyOOS07GwWPH7MksePeZqeDsAge3uGOjjgbmhIeFoaP4eHM/3hQ1Lf8Xjk4pYPUM7AgP52dvS3t8dYoQBgTVgYsx894kFKCqZaWgyws2OaszNZwLKQEOYFB/NcWTeJtyMwLAy39zS3wJXr15m5YAEuzs7cCAggMiqKs0eOsPO337h3/z5/nThBjSpVmP3DDwAE3LnDph07SElN5UZAAFvXrqWUpeUn/4xlIjq6eKMApD1QtfDDr7/yv44dUchfY+SRfACK9wV8w/5vpq3N4UqVqGZiwsOUFJxPnyb/izvHxYXqJia0uXqVhKysIq1nccsH8DQy4lTVqphqaVHzwgXO50r6ZaRQEFCrFm2vXeNqQsIb/6bkA1A48/bvp3PNmpwMCGDpn39y8f59tBQKlnz9NYO++AKAPefPM3DtWsyNjJjUsSNtqlRh7bFjLDhwgCcxMZSxtGTNgAE09fYmOS2NVX/9xbcbN9K8YkW+79CBusOGvVXdUlJT6dS7NzGxsaxbsoRLV6/i6uLCsZMn+W7UKGJiY7H38GD7+vU0rFuXph06cPLAAXR0dKjcoAHtWrRgyvjxxf/+m5sXaxSAZAH4iOi5dCmb/f2xMTPDzc6OjvPns//iRUwMDDg8cSLVy5aVGukDJSYjg7ZXr3K1Zk2c9PXpb2fH6rAw1fXKxsZ8YW5Og0uX1DL5Frd8gJuJiQwIDGS7lxezypal4aVLqmvLypdn5N27/2nyz+FucjI/PXrEL+HhzHFxYayj40ufic/MxN7fn5I6OiwqVw4PQ0OWhYay+PFj6pYoQVkDA64nJtLRyooJZcoQk5HBnufPGXD7NmX19albogQBSUl4Ghkxu2xZzLS13/s+9zgyktIWFvSqX58utWvT6McfuXD/Pi0qVVJ9poGHB+729uwbNw5TAwMAxrRpQ8caNag6YQK62to08vQEwEBXl6rOzvSoW5dNbznx56Cvp4e1lRUVvbxwd3XF3dWVIWPHArBo5UoAmjVuTGxcHL8dPIizkxM6SgvW4V270NfXlwYVJB+Aj4ovKlRgRrdu3F28GG9HR3aNHs2RSZP4ukEDSltYSA30gfM0PZ2vb916sTorV44yykHMQlubjZ6edLt5k9jMzI9WPsCOZ8/Y8/w5DczM+MbWFoCvbW2Jz8xkz/Pnb/Wb5QwM+L5MGfTlcpY8fkxGAalR1oWHkykETczNaWdpSVkDA4ba2wMw1dkZP3d3VpYvz8SgIGY+fIi5tja+dnbY6OjQzdqade7uHKpUiT8iI+ly48Z717dCoqJIy8jIU5adnU1OmLqetjbbRozAQEeHIevWvbCeCMGQ9etZ1a+favLPwcnKivWDBnEnPJwFBw4AEJWQwJx9+1gzYEDRrJ5lMnKH0T8ODaV+nTqMHDSIkYMGsWfjRnp27UpwSEieDImWFhYYGRpKA4qkAHxkFoB69fi+QweS09LY/M8/rD56lMZeXizo3RvrEiWkBvoIOBQVxeqwMIwUCvzc3dGWydju5cWPDx4QmJT00csHGHL7NjEZGcxzcaGxuTnf2Noy5h291bVlMrpZW/M0PZ3tT5/muZYlBP/ExOBtbIwiV7lWvhwu1UxM8DQyYluu7+f+jKmWFl9aWXE0OprIfJNtYWxV83kHUQkJjN6wgTazZrH+779fmmBz42hpydyePfnjyhW2njrFrN9+o02VKpQvxE+gfbVqdKtThyk7d3LvyRMGrl3L/F690FeuxIsam1Kl2LVvX56y85cuYWttzYnTp/MoAafPn5cGk9cpAI9DQxk1cSIOnp7IzM1Vf6VcXZk4fTpJuU6h2r1/P51691Z9xrN2babOmfNBNkpWdjZLDh2i4tixGPfqhZWvL42nTmX1X38RGBZGv9Wr32v5N0NCiExI4N+goA+ivZOzspgbHEyzK1eQHT2q+jM6fhzLkycpefIklc6f59u7dwn9yHOdvwnf3r1LUHIyDc3MOFe9OtcSE/n12bNPRv7T9HS+vXcPM21t9lesyNcBAaQXgbOhg54enaysmJ8vemZvRAQd/oM3vPFrUvHKZTIMFYrX/o4mwvC0tbQY07Ytv40bx/wDB0hXWnCexsZiU8BZC/2bNKGxlxdD1q8nJCrqtTkCln7zDcb6+tSaNIkO1avjqrTaFNlYmWu7qVvHjvy6bx/DJ0zgxKlTjP/hBwz09WnTvDlpaWl079+fcxcvMm/ZMuLi41Xfi4mN5bupU5m7dCnVGjcmMSmJ5p060bh9e2Lj4ug5cCAV69UjNDyckLAw6rVqxZNnzzhx6hQLVqygRefObNi2DYC0tDRmLVrEj7Nn07xTJ2JiY1np58fnLVqwZPVqHL296d6/P9lF0F/VrgCUtrdn4YwZBF26xFdffqkq79W1KzMmTcIwl9mnY5s2rF648IWG7uvLlZMnmTxu3Ac5+XeYO5dpu3bxY5cuRPn5EbZ6NWPatGHlkSO4jxrFvSdP3mv5lZycAKis/O/7joFCwVhHRw5VrIiFcm90urMziQ0bElG/PuerVcNSW5sFjx9T4dw5LuV6eT9FkrKy6HXrFllCUNnYmPW59uI/BfkAP4eHE5CUhL5cjms+8/M7KTeOjlxLSOBodLSqbPvTp3QrVeq13z0WHf3CT6GQFfGTtDR2PntGT2tr9OWvN75qIgzPRF8fWzMzylhaUs/NjV9OnABeHQEwp0cPYpOSiHkDi09JY2PGt2tHVEICCcojfIuCS1evcubff9n/559cvnYNgIZ167J87lz27N9P9/798ShfHi93dyxKlmTPpk3cCAigTbduCCFo2bTp/1u1jh6llKUlY4cNY9SgQRgZGvLT5MnExMZSwtSUH8aPJzomBltra3R0dOjfuzemJias37yZ0YMHs3rhQoaMHUt8QgJL1qyhfp06TBk/HlsbGxauXEmzRo24e/8+rb74ghunT+N/9iy7fv/9/VcActDV1WXTqlXUq10bgI07dhBbwLG7P8yeTdcOHVg2Zw7aH4CTS4EDy/Hj7L90ieW+vrSrVg0dLS20FQpaVKrEuZkzqeHi8t7LNzM0pIyl5RsrAOvCwqh38aJq5b3jDVZzyVlZWJw8iezoUT47fZq5wcGEvePqXC6TYa+nB5BnhVTWwIDfK1akrIEB0RkZqsnnUyYyI0PlbLfO3R25hlOKF7f8TlZW3E5KIjU7m5Xly2P0BivqN6GqiQl1S5RgXnAwAP/Gx1PZ2BidV0zYv0VEMP3hQ7Y8fcpvFSrQJ98q90J8PAseP2bS/ft8V6YM69zd36gumg7D+75DB+bs20dmVhaBoaEFyhZCsODAAYa3aMH206fZn8sRsyCiEhI4fecOLSpVYtzmzYRGRb085m3ZQr1WrVTW4zIVKrB5507V9eP+/jRu3x6ZuTl1mjdn74EDVKlYkYBz57h55gyVK1RQfXZw376E3rpFWEAAvb76SlXepH597ly4QMS9e4zN54BYs2pVps2bR99hw2igtGhU8vYmLS2NO0FBXLp2DXMzM06ePs3vhw7RrmVLrt+6RURkJL9s3crf//xD04YNiYqO5tjJk1y7eZNftm6llKUl+np66OjoYGJsjLOTEybGxnRq25YLly9/OAoAgJaWFlvXrsWsRAmeR0QwauLEPNe379nDydOn8Vu27D9X4vSdO3RfsgRZly6Yff01K48cUWmXJ27dou3s2ci6dMF2wADWHTtGYmqq2hrkgPLBeCgdfHKjp63Nkq+/VusDKSr55e3scLGxeaPP+trZcbhyZXSVg9zsR49e+5314eFEKfcxZzg7M9bRETtd3Xe+f0UhE4meXE5v5f0EJCVxMzHxk538jRQKtnl60vbqVYKSk6llasqY0qU/GfllDQwY5uCAz82bzHz4EAc9PWYUYYTLaEdHDkdFcTMxkVWhoQwo4F3MTXtLSyY5OeHn7k7bAmLLq5mYMLp0ada7uzOidOmXfAdepwBsPHmSat99h6xLF7S7dWPlkSOqz+w5fx4rX1/KjxzJZn9/4pKTmbd/P7YDBiDr0gWnIUP46/r1F0p7WhoLDhxA1qULLWbOxD8wMI88FxsbqpUty8Z//iHo6VOcra1fqtOs336jY40aLOjdm8pOTgxau5a4XFvB+ZWFoX5+zOvZk9X9+5MtBIOUDoS5+bp7d04eOIBvz54AuJUrR48uXVTXG9atS4M6dejdrRv+f/xBh9ati7Q/OTo4cOP0aZJTUqhcv75qcevTqRPbd+8m7MkTRgwYwKadO0lITMTYyIjMzEwMDQ3p4+NDHx8f9m7ahK21NZlZWdSpUYM+Pj78NHkyowcPfkmeuZkZJsbGH5YCAGBnY8PS2bMB+GXrVg4pY5hvBgYyeuJEdm/YgMFbhFfUcXVlfq9eAHSuWZNBX3yBmdJLs4GHB3OVHaP755/j27gxRspVojrIORxx3v79BV6vXrYsjmpMIFFU8q1MTSnxHzxd9eVySmpr85m+PlcSEjhcgKaeQ5YQLH78+P+9wNXk1JOfMrme+5s6Ub2O6IwM5gcHIzt6lFZXrxb6ufqXLqF97Bjrw8OJy8xk7/PnlDl1ipInTzIgMJBuN25Q5fx5te+Fy4ANHh4sDw3FPzaWrwMCyBaCqc7OuGvAs7m45evJ5fi5u+MbGEhadjazg4MJTEpiqL09NUxNi0RGWwsLyhoYMObePQwVCkoWkzUzdxie/9Sp1CpXDqDAMLzzM2fSo25dTA0MGNOmDaenTcPcyKjQMLxD339PXTe3l2RO/PJLftq7l5T0dLTzWVWO37pFZEICHapXRyGXs27gQJ7FxTF206YC6z99zx661KqFk5UVDiVL8pOPDwcuXSrQsVEmk7F87lwqeHry57FjHPf3V10LuHOHY//8w5qFC5HLi95vfdfvv2NkaMi2deuo4OnJQ6X1x6dTJ5avX0+VChXo2LYt+/74g3LOzgB4e3hw8vRpft6yhWcREaxYv57klBTq167N4DFjuHf/PjcDA/lV6ZSYmJioGtsD796llTKPwgelAAB079xZpYH1HzmSx6GhfNmrF8vnzsVF2Thv9WIrXzKDAlaRhsoyXQ28iDkv1y8nTtBm9uwCTVaD1Pjwikq+hbGxqk3/y+A+RhkDPesVVoBfnz/H29gYZ6UCoCnj7wPlHqIMimyyMdfW5ltHR5z19TkUGUlAAfualxMSuBAXRxl9ffra2mKqpUUHKysamJnhZmjIajc3tnl50dXamq43bnA6NlZtbTDRyYnn6en8HB4OwKnYWBaHhKArl7PRw+ONV5cfqvylrq6sCg3lnnLVmZ6dzYDAQGQyGevc3F5pqn8VmUKQqRyg5TIZIxwcOBIVxVAHhzyKb2auraecf2e+YjsqM993CuN9CcPzdHDAq3RpIvL52dwJD2fqrl385OOjKqvk5MTApk1Ze+wYf1y5kndSPXeOsOhoOuTKRjq4WTO8HR0Z5udX4Limo6PDz8uWoaWlxYDRo0lNSyMpORnf4cP5edkyVRx/UZOQmEirrl1Zvm4dlStUoKKX14s2dHSkY5s21KtdGxNjY7p26ECzRo0AMDE2ZuPKlfw4Zw4V69allJUVZiVK8O3QodjZ2FClYUO+mzqV9q1aAZCWns68ZctYvm4dtatXz7Nt8UEpAACr5s/HomRJQsPD8apTh/YtWxa5Waa46Ne4sWoSPnDpEuVHjmTyjh3E53JgqalGP4Cikm9pYvJW8nvZ2GCto8OJmBj+LcTZbu6jR4wrIFmKOolIT2eV0tmsj60tNkWw3ZDHClWiBK6GhsxXav+5WRESQldra/LvMuef7HrZ2CCAA5GRammDdpaWtLSwYMTdu3kn5aAg7iQnU8XEhMmffaa2Z1Dc8r93cqK0nh5b84Xp+cfG8ntEBJ5GRsx9i3czKDmZxSEhHIyMVDn/fW1rSw8bG1wNDEjOymLzkycEJCVxLCaGfRERBCUnsyQkBAC/8PCXEhBFZ2SwOiyMJ+npHIyM5EghFrX3MQxvUseOuCm3PZLT0pi6axfVvvuOZ7GxXH74UPW5u0+e8FCZe6HbokXM2bePgNBQ+q9eTdeFC3keF8ejiAjV5/8JCCAlPZ3oxESaTJtWoCWgkrc3Y4YO5d79+0ybO5fBY8YwesgQnNQ43vj27In/H38wxNeXnyZPztPuK+fP//9xYN68PL5tLZs25dG1azy5fZuObdq8WMDq67N9/XriHz9m/7ZtqnwDJc3NGTtsGEN8fRni6/vezHdvpQBYWVqqGiY+IUHlHPgxoJDL+W3sWL5t0waFXE5SWhrTdu/GeehQlhw6RKaaspwVtXxzI6O3kq8rlzNSuZ9bkBXgWHQ0Rlpa1Cwic+vryBCCPyIjqXvxIk/S0uhgZcUSV1e1mLZHli7NlqdPeZYrh3x4WhoKmUyVB/9VxCpXcFZqWKl0LlWKbV5eDAgMfCnkLSU7m2kPHryYjMuUoZUakj4Vp/zG5uYcr1KFGc7OuBoavhSS18nKigrK/j7cwYGtnp5U/Q8KcFkDA5a6unKlRg2amJu/sDoqFGz08HgxqCsU9LCxIalhQx7WqaNKBLTE1RXRpAlbPT2pmG9P11xbmwF2dmQ1bsyVGjX4omTJAmW/j2F4lZ2c6Ne4scoiO7lTJ+I3bCBg4cI8i49yNjYcmDABsXMncRs2MK5dO9zt7VkzYABZO3awZ8wYyuTarmzg4cHdxYsRO3dye9GiQus+Zfx4XMuWZdaiRWgpFHRq2xaJ90gBgBf+AArlHtGgb78l/i1ScL6v6GhpMa9nTy7Nnq3aP4tMSGDEzz9TdcKEPGF4D58/58dff6XkN98g69IFRdeuLDx4kGSlR/ztsDAGrV2LrEsXGk+dyoHXeM3+V/mF8S5+EgPt7THR0uK358+5nc8kPic4WCOr/9VhYTS+fBnzEydodfUqNrq6XKpRgz3e3i95fCdnZbE0JAT3s2dVkQwDAwN5qLSaRGdksPjxY+RHj+J8+jTLQ0IQhVg/jBUKlipXdgArQkMZkssMXBhxmZl8e+8e5Q0NVRnqioIvSpbkSOXK7PTyQl8uZ3Tp0njlU+6alSyJr3IVKJfJ2OPtzcry5V/63IcoP0fpbHjpErKjRylz6hR782X82/X8OU6nT6uevc/Nm1z8QEJF39cwvOLMHKqnq8u0iRPJzs7mZmDgexMz/zZkZ2ez+/ffefrs2XuZfOitzgJ4FhGBT79+7PDzo++wYYSGhzN64kTWLVnyzhU6cu0afZYvzzvAF9OpXhUcHTk2eTKHrlxh3ObN3AwJ4VpwMHUnT+bq3LlYlyiBk5UVUzp3pkvt2tSeNImElBQ616yp8mUob2dH5c8+o3f9+vw8ePBLZr13lV8Yr1sZvApTLS0G2tkxJziYOcHB+CnDlq4nJhKelkbLVwwOG588YWlICBfj49GSyVji6sogpTlxz/PnDLx9G3MtLSY5OdHjFVEKA+zsGFm6NMtCQhh25w4X4+MLDfUyUCgY5uBAH1tbGl+6xIX4eBqYm+Ok9FEw19amuYUFPz95wskqVTAtJFGLvlzOIHt7loeG8n2ZMshkMu4nJ+NtZMTWQuoZmprKmHv3WBsWRm8bG3Z4eRVZSBrAkaioQs3HORyOinql0+aHLP9T4vsOHWgxcybfNGxIYGioSvnPTe4wvCWHDuHz+ee0qVKl0N/MH4bXqnJl7AuxRrwNbWfPxszIiA1DhhTZb6alpbFi/XpaN2vGgcOHWbZ2LcOLKH2wxlfYcjkjBg5kxMCBH4cFIDMzk67ffMPowYPp2KYN86dPB2D95s0cOX783VccFSrwy5Ahef4WKCMENMHF+/dfKmtRqRJX587lR2VoyrO4OGbnSznpZmfHL4MHk5WdzTA/P1X5nfBwfj17ljUDBrzR5P9f5avDAgEvzOG6cjlbnj5VZd+b8+gRYx0dX+n018vGBv+qVaml3CJokWuwaWBmhruhIeerV3/l5J+boQ4OdLKyIjEriy43brzyeFljhYJfvb0poaXFuHv3iFeaU1OysxkUGMheb+9CJ/8chjg4kJSVxc/h4WwID6fXa1bz9np6zHNxob2lJQcjI9/I4UtCoiCKKwzvXcjIyiryFfqoiRMZ+PXXbFixAksLCyZOn87j0FCpg7wPCsC4KVOwKVWKYcpjLPv26EHTBg0A6DdiBAkfeHy23/HjBZrWFHI5kzt1onf9+gAFptltV60afRo04LcLF9h2+jSJqan0X72a9YMGoaOlpRb5ORaIU9OmUcLQEJlMVqgF4uj//kfrV6wWcmOjq0tPGxvSs7NZGBxMSGoqZ+Li6FbAoPSSCU8uZ5uXFwYKBUPu3HkxGPEih/uq8uVfOwnnZ727O2UNDLiWkMBI5e8VhqOeHotcXQlJTWWsMo3qwMBAxjg6qiwCr6KUjg4+1tYsfPyYI9HRNH/D1dLK8uUxVCjoc+sW/0UFMFYo6GVjw/N69Yhr0IBfPDxUf3srVCCjcWN05HJcDAyY5uyMaNKE0Lp12eHlxbHKlblaowaD88Wp1ylRgt3e3ogmTbhaowbbvLz4t3p1TlSpQiPlHndBfKavz8ry5dlboQLr3N1Z4+bG/5yc+PGzz/AwNKSGqSm/eHggmjThZJUqqnpu8vDgdu3azHiHKKAPhdOxsXS8fh3Z0aOYnzzJMaXTYHRGBhOCgjA+fpzZjx6plM//SnGF4b0tA5o25euGDYvs97bv2UN2djZdO3TA3MyM+dOmkZiUxOAxY6TZurgVgJ2//cbhv/9m7eLFecrXLl6MkaEhj0ND+XbSJLVX+klMDF0XLkTWpQt9V64kWql0RCUk8OW8eVT/7jsuKFfS5UaMYPSGDUzavp1J27fT6Mcf0fXx4Waufd7cZAvB3n//LVR2m6pVAV4Ku8lhUZ8+2JcsyTA/P7ovWcL/OnXC4T+Y3N5WflFZIHIz1tERuUzGmrAw/nf/PsMcHNB+w99w1NNjrosLf0RGsvXpU2Y9ekQbS0vKv0X4nomWFju9vNCTy1kdFsb218Ta97axoY2lJWvCwuh96xaOenqv3LYA8lgWRpcuzf2UFJqXLKmydmQVEM6VKYQqI6GBQsFub2+Ox8SoHOLehISsLDY+ecKp2FiepKfT59Yt1V+Ha9cYdfcuRgoF95KT+d/9+2QKwfanT+l64waNL19m+7NnLC9fPo8ScDo2lgXKfPaT7t+n240b1LlwgYSsLA5XqkSFApKQNDY351y1ahyLjqbDtWv4BgTQPzCQQ1FRDHNwwExbm/NxcSxQRkmsDA1V1bPnrVtUOHeOeDU5yMplMvrZ2XGvdm2sNZRzojBylKvu1takZmVRTvkemmtrIwN+q1CB8WXKYKL1dietF2cY3psSER+PRd++KLp2Zckff7Dk0CG0u3XDsm9fnhWQIfZNuX3vHkvXrGHRTz+pynp27UqT+vU5eOQIW3ftei8mzU07dmDt6oqxgwMXle3+7+XLWLq4sHjVKtKLactarQrAxStXGDpuHLs2bHjpKEVHBwdmTZnyQhnYuJH9f/75nyuSs8+fUcAgkqbUpnPiZG3MzNg0bBgeDg7I5XKVx3tJY2NszMw49P33VHN2Jis7m6ldurCgd2+mf/UV37Zpw+3wcCZ36oTnKxy7fti5k6eFxHKfVYZAdatTp8DrpgYGrBs4kKiEBJ7HxdFEGVP6X3hb+e9qgRDKvxzKGRjQ3tKSxKwsfo+MpF8+pySR77/56W9nR2Nzc4bcvk1Iaio+b2A9yJlk8xsVKxkbs0jp/d8vIIBbr3GAWl2+POba2ux89ozRr3BazAnXOhwVxbanT0nJzsbTyAgfa2t6KrcpDkdF8UdkJMGpqfgpEwHtef6c4zEx3EpMZNvTpyRlZeFiYICfuztTHjzg64AAzv6HwTC9kK0Dv/DwPKvJtHzm1qVKh8ZO+XLV5/9chhCsDA1FSyajXb5EUtY6Ouzw8sIvPJxd+RzsLsbHM+j2bdX59YXVMy07m1VvaaZtZ2lJ8Oefc692bRaVK8eicuVY5urKwzp1qGxsRasAACAASURBVGZiQrYQXIiPp6xysv1MX58F5cohmjRhk4eH6ju/entzoGJFjQycq9zcKKWry6DbtwE4GBmJubY2jV9hYXlTijMM700wNTCgT4MGnJ0xg1GtWzPxyy85PmUKfRo0oMRbnssQHBJCm27dmDdtGnr5QnznTp0KwJCxY3nwBllK1U3Prl35bcsW0tLT0VXWNSUlhdk//MCIgQPVlq9AHbyRmnrg8GF6DRrEl61b46bMRpWffr16MXzCBLKzs+k9eDCnDh3C/Q3Dtc7cucMaZVbBfRcuUNnJiS9r1MDM0JB/AgNZd+zYC/PQmTOUt7Oja+3aGOnpsbp/f+pPmUK/xo2pXrYs/oGB1ChblpK5Vjg5K2aAYX5+2JqZMb5du1fWJyQqisrjxzOzWzc61ayJkZ4eSWlprDpyhEUHD9KnQQN61K37yhfEzNCQc/fusf30ab4qRFlQh/xFffpw9MYNhvn5sf306Te2QGQJQWxmJpHp6Xli7MeXKcOe588ZZG//knNbpFJpi3iFxjvHxYUq588T8waZ+7KFIFSZ5jmsgHTPA+zsOBkTw7anT2l++TJ/VKpUqKe5rlyOra4uNxMTmXDvHqsKyHqWs3IbYGf30gEuW3I5YDUrWZJbtWrluf6llRVfFnBQS0crK0STJgDEZmayNCSEsffuMcDOjnnlyhGdkUHH69fpaWOjSm1cGB2trLiUkMCjV3hvm2ppIQOevsE5DCWUSmD+zw6wt6ektjZ+yuQ++dn9/Dmer/DoV8hkDHNwYJHS6lDD1JRRpUsTkZ5OZEYGo0uXpn9gINVMTPi8RAmmPXzIBg8PFjx+zMyHD9kXEUE3a2u0ZDJG5soxsCI0VBVSeT/XPveDlBTWhIUxqnRpZgcH50kLPfg1aXuLCiOFgnVubjS5fJlZjx4RmJTEL8qwwXelspMTFsoxLCcMb3KnTi99LicMLz9rBgwoMNlPThjeu5ITpQTQZvZsbM3MWN2/P5+XL//fF34pKcyYP5+la9aQkJjIxu3bcXRwwFa5WAgJC2PNhg0v3qe4OOq1asXwAQMYN3x4sU6cNatWZUCfPgyfMIF9W7aw58ABFueyXHwUCsAff/3FghUrOHbyJAD7Dx/mfzNnMunbb1WaD4D/2bMsWb1a5QwSExtL9caN6dm1K98OGULZ1yQHqe3qSm1XV34pwJO0npsb9dzc2Dh06MvmOFdXvmnYkIFr13J2+nS2nT7N8r59/39gkstVWQR/v3iRX8+e5dLs2Wi9wkvbWE+PK3PmcO/JE/ZfusTUXbtITksjJT0db0dHNgwZQvdXTP7P4+KYsGULF2fNovakSQzz86ORpydWbxg3/67ycywQzWfMeGMLxOYnT9gXEUFyVhZfBwTQztKSgfb2yIDqJiY0L1mS4bksJn9ERnIwMpLryoH3hwcPiEhPp3OpUtjm6hcCWBAczHAHB5aEhOBjbU2bAtIYJ2dlsTw0lD+jolTnC6xUribrmpnRPtd31ri5cTk+njvJyVQ6f57mJUvStVQp1Wo9R5H4OiCAn93d+S4oiDVhYXQuVapIVmf/hRJaWgxzcMBAoWDR48dkC8HNxETGOToWmDPeRkdHNYmYaWnR0sIClzNnCv39ktrarHZz42l6OtNyrQwLwt3QkGnOzpyLi2NTvjDSFiVLkpiVxd1CnMkyhXgp0c0ge3uaW1ggB2qamnIml7UjITOTCkZGpGVn8+PDh2x79ozozEysdXVx1NfHUU+PJSEheSb1TCFeSqwUkJTEI6UiKAqxFOVngxpP6ixo26SfnR3fBQURWKtWkWbELM4wvP/C5QcPiHyHuhro6zNj0iRmFLJ17GBnx4p581gxb957d+/TJ06kXLVqdOjZk61r1/Ih8koFoGXTpnmOTSyMurVqUTffCklTzO7RA7eRI2k0dSorfX0L3OeOTkxkwJo1rzX9A6pzByqWKUPn/3hPmVlZ9FmxgsVff81npUqxrG9fOi9YwJD16/l19Og3+o13kf+2FogeNjav9Mo/lCv3OEBLCwtaWliw/DUa/6xHj+hoZUVbS0tOxcYy6PZt6pmZveQEmHMc8Ng3yC9gpFBw+zWJpyY/eEArCwuqmpiw1s0Nz3Pn8A0M5EbNmkUaovem9LW15XBUFH0DAqhpaponvWxucnwAcphWiFNdXTMztnl50d7SknVKP4foQiwsfWxtGe3oSL0SJegXGMjmJ0/IyDd52uvpFfr9wlgZGqryxbDS0WF8mTJ5Ju57yckkZmWx9/lzVdy+l6EhDczMWBka+lpHSX25nA5WVi9l/XtdO68PD0dHLmeovT0jSpdm8O3b+Lm7M/7ePSoYG+NqaMjZ2FgGOzhQrQjisi11dLDS0WHKgwfseIvtvg8dz9KlPxhlpagxNTFhqK8vawrYFv9QkH/oD8HM0JBBX3yBQi7Hu5AJZJifH3bm5q81/b8r4zZvpkutWlRQ1qNTzZp0rFGDXefOsfPsWY20R24LRClTU4b5+fH8HRxz3pbjMTFEpqfTwcoKhUzGOnd3nqWnqzzz1cW+iAjC0tLorzTpl9HXZ1bZsjxKSWGcmmW/igXlyrHj2TM8/kNynIOFpBT2j4mh961b3E1Opp6ZGYmvcL77JTycfgEBpGZnU8PU9KXJP8cCY/wOitHz9HQu5Otj2fCSU2A2kJiVVejk72lkxKyyZZnt4oJ/1aqYv8FZFiNLl2ZW2bKscnNjqlJhyhSCf+PjKa2nh5FCwcDbt7mQkMDT9HQqGhlxNDqaSUFBRL+lp37uvmavq8tqNzd2PnvGvlz77Z+MAqB0WvwUiY6JIS09HStLS2bkShksKQAaRldbu9DzyH+7cIFd587xy5AheUz/T2JiirQOyw8f5nFkJH2UIZE5LOvbF22FgoFr1qgcdtRFQRaIyIQEhqxfr9HncSc5makPHvBTriNaKxkbM9DenrVhYfyhplz55+Li+D4oiOX5fE+GODhQwdiYlaGhL2WR0wQC2BAezg4vL/rcukXcG0485+LiCt3/T8/OptetW5Q3MOCH12yx3U9JYYzSD6GglLRn4uIw09ZWne74NmwvglMQbyYmMiEoiPH37tH8ypVX5nzIYdHjx0wICmJgYKAqg2O2EAQrtw72KC0Qt5RJrB6mpnI2Lo714eEkv0PUwoOUFP6MimKQvT3tLS3paGXF4Nu3iX1HpeJDo6y1dZ50v58SPy1cyPgRI1g2Zw4LV6zgXgE5XCQFQANkC0F2ASubqIQEBhZg+o9OTOTojRtFIvufwEBazJzJ0PXrCYuO5nyuVWZ6Zia7zp0jWwhikpJo8MMPLD10qMC6fgwWiOSsLKY+eEC18+d5lp7O5Vz7xneTk1WpebvdvMmc4OB3GoDzD8YDAwOpe/Eiz9PTOZQvxOlARITKxN395k2mPHjAkzdwmisqloWE0MPGhi+trGhlYcHAfOewv46ehWzPXEtI4IcHDxjn6PjasxlWhYZyOCqK9e7uKmfAHBY/fkyWEIwsZGuilI4OTd/Af8JZX5/aRXRGRGRGBif+o5KeO4Ih5+hVkU8RE0Xw7sVmZjLq7t08Bw8tK1+e+MxMhiijAj4VLIyNCw2J/pjx27KFlk2bYmxkRK1q1ejcvj1Dx4374O5D60N/EDdDQvjr+nUCQkM5fO0azXIdszh640aiExNJSElh0vbtqkn5wKVLLC+iE5lynBQLQkdLi6HNmzO0eXO1t0OOBWJB794vWSB+v3iRgWvWUM3ZGacCPNeLCgOFgsmffVbgiXDlDAzUFqL1mb4+q9zcCvX0b2NpWaDzobp5kpbGT48e8Tw9XZUrv4m5OR2vX8dGV5fvnZxUn9WWyQrMsdDU3DxP7LuOXI5eriNv5wQH09bSkm2enlS/cEEVkaGr/Ezuz/YNCOBmrVps8PDgy+vXVTkMriQkMPLuXRaXK0dkRgbzg4NJUa6+yxkY0M3amqnK3AY5ddTOd+yutkzGXBcXvrp5U7Wy0M13PwWVvYqg5GQ8jYzyePm/7vM5R0XHqWklvvnJEyY/eIChQsHDlBRVFMqtxER05XK2Pn2KkULBhDJl3ijx1IeOiYHBO5078qGRnJLCvKVLmb98OX8rs7GmpKZioK/PkePHGfHdd0weO5aSGnY4fltkIjq6eHOXKsP/JN7eAvHT3r38efUqNV1cWNSnDzWUK5P0zEzWHD3KyF9+ISs7m9IWFoxp04YhzZv//5bJmjVSIxbnAHr8OF9ZWzPHxQVTLS12P39OktIyUlJbmy/Mzalw/jxZQtDHxobvnZwISU1lQlAQvz57RoYQuBgYcLVGDZ6lp7MsJITLCQmMKF2a9paW/B0dzU+PHqmOue1ubc1mT0/8Y2NZ/Pgxu3OtmhuamTG2TBncDQ0JTkkhLC2Nf+PjWRISQrYQ1DQ1ZXTp0nQuVYq7ycmqPAfaMhlVTUy4kpDAVzdu0NrCgp+V0QyDb9/m12fPqGhszMry/8feWYdHdXRh/Le72bht3IUYJIQQXIpTqrgVWuzDrUihUKxIW6BI0QLFvVCcAoXiUgoUjRCixN1dNvv9sWFhSQIhBILs+zx5ktw7d2bu3HvnnHnnSE2aGBgwPSSEJeHhSrEKdtWujYZQSPd79xTH9EQivnVwYGZICHoiERlt2mB16RKx+fm4amvzoFkz6vz7Lz5PKAjDra25mJZGZlERkS1aoHn2rKKdrywtGW1jQ9MbNx6zAiUum9WGkoiqb/P8Y6qvX27ioueiuse/ugWwkZGgWttXKQDvOVQKQPVOAKr3n24lKZ41hUJ2xMZSJJOhLhTyqYkJM4KD+T0+nq9tbVnu5sb0kBAOJCQwxsaG0ba2nEhOxj8rC4FAgI2GBp66utS9do0Zjo7MdHRkdmgoCx4+xFgsZpWbGx8ZG/OVn5/CFkSlALwcrgcHY6qvX3lmUaUAqBQAFVQKgEoBUKE6oFIAXg63wsIwNzDAurKUt0oBqFYFQC1VUr0DcLqnahKqVvmvGv9qngFUQ1Cd+PDvapb/b/j4XN51mQ/6Piu1uCMvY/veXvUKViuEqiF495ASncJQi6GcWHFCNRgqqKBCpSArlhF0LUg1ECoFQIW3CekJ6aTHpxPhE6EaDBVUUKFSSHiYgJmDmWog3mGoqYbg3YNDXQdM7Exo1K2RajDeckhaSajxfQ0kbUr26mQQtS6KmA0xZNzMUC43uwaS1hJkRTKi1kQRsTyC3JDct7p9AMMPDHH52QWDpvIYA6nnU3m44CHJJx/He7AaaIXLIhfEJmLidsYRNj+MbL9s1Qv0Eoi+H411Les3sm/3bt9j6U9LcXJxwt/Hn+SkZE5dPcWhvYcICQrh/N/nqd+4PrMXzgbggf8D9mzfQ15uHv4+/qzftR5Tc9P3/hmrGIB3EAKBgDaD2uDVwUs1GG85Ui+kcrPdTeJ2yWPiF6UX8WDMAyXh+6hc8PRgivOLudX+Fg++flAlwre62wdIu5zGzdY3ybwjDywVtzNOSfgDxGyJIe1KGsHTgvH9ylcl/KtIATB3MuePOX/QV6MvvQS9WPO/NcQFP87PEHg1kAnuExhgMICjS44SFxLHqv6r6CXoRS9BL44uPkpO+uOkT5d3XaafTj/G1xzPtQOVz8XgWtOV3JxcLp+/zOyFsxk8ajC3rt8iLCSMb6Z/w/aD21m/aj1/Hf2L7Kxsxg4ey9Q5U/lp2U+kpaaxae0m1QNWMQDvFlb2W8mlHZeQWEqwrmXNku5L+O/of2jrazP95HScGzmrBulthAwCRgZg2MIQTVtNbEbYELk6slQxq/5WhMwMIfVC6rvVPlBcUIz///xpdKMR9t/aE7stluKCx3EENO01ERuJCV8Y/sJ15wTm8HD+Q2K2xODyswv2k0vnFCnKKOKSzSXUjdVxXeaKjocOUavkLIdhC0O0nbXJupeFWXczHKY6UJhaSMKBBAKGB6DlrIVhC0Oy/bPRra2L80JnxBLxG//aJUUkYeFsQc/ve6JtoM3WCVtxbeqKhbPFY0Hc1BVbD1tGbBiBWzN5CO4x28aQm5HLjcM3aNCpAdoGjyMFNu3ZlKNLjjLz75noGulWum+aWpqYWZjhWdcTN3c33NzdmDx6MgBrlq0BoN1H7UhPS+fYoWM4OjmiXhJQa9/JfWi9B0GaVAzAewavDl70+bEPywOXY1/Hnon7JjLj1AxaD2qNiZ2JaoDeYhRlFHF/qDyEsPN8ZzRtlaOv6TfSR7euLhFLI97J9gEyb2cSuSISbRdt7L9VFtKuS1wJnBCIrPjFvZq1XbVxmOaAUEtIxIoIZIWl64jZEIOsSIZReyNMO5ui7ayNzRgbAJzmOuG+yZ2aa2oSPD2YsJ/CEBuJsR5ijbqlOhZ9LHDf4I73CW+Sjifh08vnjXu/kiOTKcxXzghZXFysyK766def4tzImb2z95Kb8ZjZCb0ZirGNsUL4P8KQX4egpa/Ftm+2KR3/a/VfdJ/R/aWE/yMIBAKl7K9REVE0b9WckeNHMnL8SLYd2Ebvfr2JDI8k/4nQ3yamJujo6qgmFZUC8G6hZb+WdJ3WlfycfC7uuMjpdafxbOfJgKUDMLQwVA3QW47kk8nEbI5BpCei1rrHYY8FYgG11tQiYHgAMqnsnW0fIGRWCHmReThOd0TLSb6KM/7EmIKEglLbEi8kTMQCLPpYUBBXQNzvyimIZVIZqRdT0aujB08kTRSoKftw6jfUR7e2LnG748oso2aghlk3M1JOp1CYVLH0y5d3XX6l45mZnMnWiVtZ0HEBZzeeLSVgFX8LBQxfP5yMhAx2TdslH5diGfvn7afXnF6l6pVYSeg7vy83/7zJv/v+BSA1JpXga8E06vpqbJPMLc05vO+w0rGb125iYWXBlfNXlJSAa1euqSaU5ykAl85doku7LhgJjBQ/LqYu/DTzJ6Ijo5XKhoWEMXHERIyFxhgJjLDTt2PW5FnExcRVunOxgbEc+PEA42uOV+wpDbcazs6pOwn577H36Y3DN9gyfotin6qXoBdz2szh6OKj5Oe8eNKXYmkxJ1acYHLdyfTX688QsyHMbTeXv9f9TfT9aNYNXfdKH8rLth/pG0lmUibB14PfipdQmiMlfFE4tz+6zWnBacXPOd1zXDC9wAXjC1zzvkbgN4HkR+W/1x9s4IRA8qPzMf7EGMv+8iRBDlMdSPoricy7me98+9IsKQ/GPkCoKaTmqpoINYXUmFWDkOkvn4lN01YTsx5mRCxRZjESDyZi1rXi1vBqes/eWRUIBYh0np9++XW44amJ1eg0qRPfHvqWP5f8SVGBPIdCWlwaEkvlIDH2dez5fOLnnFpziqBrQZxae4rmfZqjpV82nd5hRAdcm7qy+evN5GbksmvaLvr81Kdq34cnEop179Odw38cZurXU+W2AVNmo6WtxccdPyY/P59hXw7jv3//Y9XiVWSkP1YW01LTmPvdXFYuWkm7hu3Izsqmx8c96NKuC+lp6YzoN4KWdVsSExVDdGQ0n7X8jPjYeC6fv8yvS3+l5yc92b11NwD5+fksW7CMhXMW0uPjHnJ7gzWb+OSDT1i3Yh117Osw7MthFFcg02W1KwAt2rTg0JlDjJ08VnFs8KjBTJs3DWtbZetQRydHlq5dSoMmDbC1t+XczXPMXTQXCyuLSnfO0tWSbtO7MWHvBMWxYeuG8eWCL3Fq4KQ41rBzQwYuG8in4z4FQM9EjxmnZtBxUkc0tDVeWPgu6rqIffP20WtOLzYlb2Jd9Do6TurIqTWnmOA+gdig2Fcq/F+2fUdveZIZx3qOb4VQE2mLsJ9sT90TdRGbyPdGnX5wok1WG1oltqLhtYaITcVELI3gX69/X2ql97ajKL2I+8PlVLzrL65IWkkw72FO2Lyw96J9gMTDiSQeSsT4Y2O8//ImekM0hamFVVK3/Tf2ZN7NJOV0iuJY3O9xmPcxf+61KWdSyPLNwnp42Zbz+bH5xO+Nx6KfBUKt55Ovr8MNT0tfC4mVBFMHU2q1rMX5LeeB8j0Aes7uiZmDGWv+twb/C/40693smYrO8N+Gk5GUwU+f/oSVmxVmjlVzP3du3uH6P9f56+hf3L11VyGvFq1exNEDRxn25TBqetTE3dMdYxNjth/Yjr+PP3069kEmk/Hhpx8q6jp94jSm5qaMnTyWkRNGoqOrw6z5s0hLTcPA0IAps6eQmpKKhZUF6urqDBg2AH0DfXZs3MGoiaP4Zd0vTB49mcyMTH5b8RvNWzVnyvdTsLSyZM0va2j7UVtCAkPo8FkHrvhc4eqlqxzZd+TNVwAeYeZPM6njXQeAg3sPUlROpq3UlFSCAoLYtGcTTi5OVdZJI2ujMv9+Go9obomlBJFYVKm2zm0+x82jNxmyeggNOzdETV0NkViE9yfe/PTvT7g0dnmlD6Qq2teR6GDqYFphBSB6QzT/tfxPsfKO3/P83O7SHCkXTC5wWnCaKzWuEL4onPzol1udC4QCNG3ke8tPrpC0nbWpe6Qu2s7aFKYU4tff75VTzW8yko4lEbs9FrGRmHp/1yNgTADFecXvTfsAAWMDkBXJ0LTRJGZTTJXVq99AH8MWhoQvlhsTZlzPQK+eHkL18qfKxEOJhP0QRtzOOLwOeWE10ErpfMaNDCKWRhAyIwSH7xxw3+Bese/yNbvhdZ3WlcM/H0ZaJCXqflSZbatrqdNrbi+i/KPoMLLDc+u0rW1L6wGtCb4eTKdJnUorRfn5/DjjR6y0rTASGGGpZcniHxaTmpKqxC4P/mIwRgIjatvWZv2q9dStX5d//f/lH99/8KrnpbRA9Yvywz/any/6f6E43qp9K248uEFQYpDSghagQZMGLJ63mLGDx/JBa3nUwzredcjPzyf4QTB3b95FYiThyoUrnDhygk87f4rfPT+SEpPYtWUXF89epM2HbUhJTuHCmQv43vVl15ZdmJqboqmlibq6Onr6ejg6OaKnr0enHp24dePW26MAqKmpsXLTStTU1AgKCGL1ktVllps/az59B/WlfuP6VdtJkVBJSDxLgDyvzPNw60/5g7HxsCl1TqwpZtCKQa/0gVRV+9Y1rbF0saxY2SHW1DtZD6GGfJwfLnz43GtiNsZQmCxfdTn96IT9ZHs0rDVe+v4ForKfnVBTiOUA+f1k+2eT5ZvF+4xHK+78mHzSLqW9d+3nR+VTnF9MYVohVLEuaD/RnuSTyWT5ZhG1Ngqb4TbPLG/axRTHGY64b3LHtFNp33L9hvrYTbTDfaM7duPsStkOPEsBeJ1ueJYuljg3dObitovEBcdh4VQ2e6tnrCdXBjTVK3Qfusa6CIXCMhdlGhoaTP9hOmu2yi33TUxNmDhtIhIjiRK7PH7qeKxtrTl38xxDxwyt0udta2/LFZ8r5Obk0qpeK9LT5Fkue/Ttwf7f9xMbHcvwccPZu30vWZlZ6OrpUlRUhI6ODn0H9qXvwL5sP7gdCysLpEVSGjdvTN+BfZk1fxajJo4q1Z7ESIKevt7bowAAeNb1ZNyUcQAsnLOQ0OBQpfM3r93k7+N/M23utLd6YpWV5Eg/uvhomeedGzljam/6xrdvYGaAjmHFLV2FWkLExmK0amiReTuzlJ+1Uh+lMiKWR6DlIN/7UzdRfy3PRtPhseV5RY2onofClELCl4RzWnCaO5/dKbfczVY3OSM+Q8zGGIrSi0g4mMBlh8tcML7A/eH38enjw7X614j/I/71vKeF1cuAVHf7rxImnUzQdtYmaFIQIh0RYuPqcdl70g3vy4VfApTrhjftxDQ6ftMRCycLxmwbQ8PODeWr2zLc8KxqWvHDPz/QuFvjUm12m96Ng/MPUpBbUGkWtTLo3LMzHbt1JDoyWrGf/iQ2r93M4l8XY2pW9XPvkX1H0NHVYcPuDdT2qk14WLhCAdi4eiNe9b3o1L0Txw8fx8lVzmx71PHgyoUr7Ny8k8T4RDb+upHcnFyatWrGpFGTCAkK4b7vfQ7/ITdKzMrKUsztgfcD6fBZhzfiXX8hL4BJMyfhWsuVvNw8xg8dr7ihwsJCxg0dx8KVC9HW0X6rP37vT7wBOL/lPAs7LiQ5qrQgrAj1Vd3t65noIdZ8wYlLAPaT5O5VDxeUzwIk/JGAXh09hRX260pokxuaq2hPx71q3HjERmLsv7FHy0mLpBNJZPuXDiCTeSuT9BvpaDloYTXYSm7N3dUMSWsJOrV0qLWuFp67PbHobYFPbx/SrqShwlum+BfJkBXJFAyi7Thbkk8lYzvGVknxfVTm0TVP/n5evc/Cm+KGZ1vbFjtPOzISy7ezeWQo+HR/n1W+qLBIIS/Kw4IVC9DV02XOlDlKWwB3b90lKSGJjz7/6JU8+6zMLHp/1psNqzfgVc8Lz7qecibI0Z6O3TvSrGUz9PT16Nq7K20/aiufX/X1WLNtDT/P+ZkWdVtgZm6GocSQMd+MwdLakjb12zD3u7l81uUzAAryC1i1eBUbVm+gUbNGStsWb40CoKGhwcqNKxEKhVw+f5kdG3cAsHLRSlxrub4xWs3LoN3QdgohfPPPm4yvOZ49s/YofXQuTVze+Pb1TfUr1b5lf0vULdRJPZ9KxvWyJ4GHix6W8sN+1ShILCB6rdzzxGqgFRqWGlVav2FzQ3TcdAhfUjqQTOSvkVj0tlByAYPSbmCW/S1BBkl/Jr36ARHwWpWvN619gViAUEuImsHLxzLLCc4hcnkkSceSFMZ/VoOssPzKEm03baQ5UmJ3xJLtn03qmVQSDyfKr1khD4YUsylGEaXwSWYpel00BbEFJB1LIvlU2Yzam+iG131Gd2xqlb3t4XvWl79W/QXAsWXHCLgcUL7yUyzj8q7LXD94HVmxjN9n/P5MA2ZLa0umzZtGUmISc6bOUTCisybN4oelP7yyd6nfkH4cv3ScIaOHMGv+LKVxX7JmieLvxb8uRix+vKj68NMPufvwLgGxAXTs3hEALW0tNv6+kYiMCHYf3a2IN2BkbMTYyWMZMnoICWKRJwAAIABJREFUQ0YPeWPk3Qt/PQ2bNmT418NZs2wNsybPwtnNmd9W/sbF2xdfS4cXdV2EWKPslW126suH/xSKhEw+NJnd03ZzbNkx8rPz2T9vP6fWnKLHzB50GNUBkdqro8aqqv3KBtoQagixG29H8NRgHi54SJ0DdZTOp5xJQU1XDYMmBq9nZVYoI/nvZAInBpIfm49ZVzPcVri9EoFmN96OB+Me4PyTM+rm8m2N/Jh8BCKBwjvhWShMk6+I1M1e/ZbIo/6IjcQIRILXbhRZne0btTXCop8FAqEAbWdtnH5wIuFAApm3KueGqO2sjdtK5XdKpCPCY5uH/G9tEZZfWWL5lbJNjdsKt3LfRbGRGOvh1uV6BCgm4BI3vE+//pS57ebSbkg71NTVnumGd2TxEVr2a0nozdDnuuFd2nGJzV9vxquDV4Xd8BzrOaJnUvYede22tandtnbFPimhgA/6fvCcdMLKGDZ2GH/s+IPtG7bz5aAvCfAL4IM2H2DnYKeiqaqbAXiEGT/OwN7RnvS0dDq37czU2VMxs3g9WaMmH5zMsoBlZf50+a5L1WhF6mr0W9yPhTcXKl72zKRMNo/bzNQGU5W02ODrwcxtN1dhdLN2yFoi/R6HSc3NyGXPzD30EvRilP0ozqw/U6XtlwdNXc1K37/NCBvU9NVIOJRAdoCyUhX+c/hrWf1Hr4vmVrtbnDc6z53P7qBhqUHjm42pc6AOIl1lBSg/Kp/7I+4rvBj+a/kfKX+nKJWJ2RzDeYPznNU+S+jcUApTCstkP0R6IiJXPn5+Ub9GYTva9vk0Z3oRQd8EoVNTB6v/Wb2ycRHpirAdY0vN1TUV/9feURuLvhav5fur7vYBUs6m4D/IX/G8Q2aEVFr4VzfeVDe86oocKhQKWbpuKUKhkHFDx7F943a+/vbrt1bAFhcXc2T/EeLj4t/I4EOVUgC0tLX4bu53Cg12wLAB76R2ZO9lz6wzs/ju+HfY1pYLgfC74cxqMYu0OPk+r3MjZ6afnK5wz2vUtRG2HrZKH/in4z/FyNqI+Tfm025ouyptvzy8iNZdSgExUMN6hDXI5AL/EbLuZZEfk4/Jp2VPDsX5xYTOCeWsxllOC07j/z9/coIfWyCnX03nqvtVzhucJ3xJuFIs96dhPdyaemfq4Txfnr8g47+MUoL/ETRsNKi1thZ2E+WrBIPGBhh9qOwuajXICq0aWnj/5U2NWTUQG5Ve0Qu1hNiMtCFqTRTSHCnFucXkhOSgW6d8NiUvKo+gSUFctruMlpMWjW40qhJaujxIs6RErorkeqPrCgHo08dHkaznVaO623+XUR1ueC+LhZ0WsnrA6iqt06ueF/2G9CPAL4DBowajoaHx1j5ToVDIiHEjiMqKonHzxu+GAgBgYGiguMEn90zedjwZYfARvD/xZtGdRYq9tvT4dA4vfBxyUqQmYtSWUYg1xOycuhNpoVTp+gM/HmDw6sEYmBlUefuvgoEAOR0u1BAStzNOEX3v4c8P5YlSynncQg0hNb6vgfNCudA2aGqAtvNjo1CDpgboeOjgfcIb+2/sn+lbrZjAxthi1sMMaZYUn14+z/Q3d/7RGW03bSJXRz42GCxB4pFEJG0kSFpKnt3eaFuk2VJiNscQszUGq/7PXs1r2mjistgF0y6mJB1LqpDBlwoqlIXqcMN7aYWwUPpKotrVcK4BgKFEFcL8jVQA3lWc23SuTFsCoUhIj1k9aDWglULwKq1Ya1rTfWZ3In0jObTgkOJ42O0wUqJTFG45Vd3+q2IgNCw1sOxnSXFBMeG/hJMXmUf6P+lY9Hk+1Wv7tS36jfQJnR1KUcbjoFEZNzPQtNHEoNmL2Q+4b3RH21mbzLuZPBj/oPyXWVOI+wZ3ivOKuT/s/uNJKlseathp3vODU6mbq2PR14KIXyJIOZWC8cfGFepjzTU1EemI8Bvo90J+6SI9EZb9LWmZ0JLW6a3x2OKh+PE66EW7wnYI1YVou2jjNM+J9rL2tIhqgeceT+qdqUfjO42xGaVssGXY3JA6++vQXtaexnca47nbk0bXG1H/fH2M2pYfSEurhhY119TE66AX7hvcqfVbLRxnOlJjTg10PHQwaGyAxxYP2svaU/9C/cd93e5Bs4BmOP3o9M7PD/F74rlocZHTgtMETQ567I4qg/DFcnfSgFEBlQ5ZXV1ueJXFh8M/pM2gNirBoVIA3g3IimVcP3i93PMNOjYAUPKtfYTOUzpj72XPgR8PEB0QjaxYxo7JOxj4y8BX2n5VMhBPwn6yPQKhgOjfogmZGYLtWFsE4uezPQKhAPf17hQkFBAyLURxX2Hzwqgxp8YLPxM1fTU893oi1BQSvS6a+N/L97U3/MAQm5E2pJxJIWazPEJcyMwQHKY6PDP++pPMgt1EO3JDcuXCv+R2n3YBgxIXrxLjN5G2iDr765B6LpXQeaEVX0FlSondFkva5TQKYgvwG+in+Lnb9S6BEwIR6YrICcohZGYIsiIZcb/H4dPbh1vtbhH/ezw1V9dUUgLSrqQpsvKFzAjBp48PN5rfQJopxfukN3pepQ28jNoZ0fDfhqScSeFu17v4D/Hn/rD7JJ9IxnasLWKJmPRr6YQvlW8JRa2JetzXfn786/Uv0gzpK/kmBUIB1kOtaRbUDHUL9WqdH8x7m+P5uycIQMtJ67FxqAAkLSXYfm1LzV9romFTOdq6Ot3wKoqMxAwGmwymt6g3x1cc58SKE/QR92Gw6WDS49PfafmQl5vHrMmzMBIYMXrgaEXQoOAHwdSxr8P3335PZsbbY49SaQXgUTjg15HU4MkUn8XS8tt7dO5ZZSqCvbP3lrvHHng1EIDmfZqXXs2piRi1aRTSIinrhq7j+PLjNOrWCImV5JW3XyUMhAyl1au2qzamXUyRZklJOpKE9VDr0uWhzBWvbh1d7CbaEbUmivRr6USvjcaijwVq+s/eH1cI2aceoZ63Hm7L5BbX/kP9yfYr3+PDZYELmnaaBE0KIvlEMvmx+Zh8VrbdwiN3reSTycTtjqM4txjd2rpY9LXAsp/c6jv5ZDJJx5PIC88jZlNJIKADCaSeSyXLL4u43XFIs6Vou2jjvsmd0O9D8R/kT/rVik+GsoKyJ+eYTTFKLEpxvvLARK6MBBmY91COVf90OVmhjKg1UQjUBJh2Vg6mom6hjuceT2I2xZCwL0F5sv8vg4CRAYr89eX1szi/mKi1UZX63kw7m/JB+Ac0C2qG6zJXXJe54rbKjeZhzdFvqI+sWEbGjQzFdpJWDS1cl7rSXtYej+0eimvq/FGHun/WfeXzkaS1BOvB1oTMDFFEw0QGEcsjcP7J+aXrry43vIpC20Cb1gNb8+PVH/l8wud0m96N7899T+uBrdE2rJo4MI+S9TyZtOdNgKaWJnMXzaVV+1aI1ESKrXBbB1s+7vgxc36e88ZE+avQ4qqyF8ZExSg0otSUVKXQjVWN5Mhkpb9r1C97FZkULve/TotLQ1okrbS7XnJkMlPqTaHPT31o0qMJmrqa5Gfnc2rtKY4tO0brga1p8VWLMq91rOdIx0kdObzwMLJiGXMvzX1t7Xee0pmrf1zlwI8HaNKzCVauVuyYvIMx28Y8XwBJZRSlFVGQVKDkY+8wxYGEAwnYjLQpZYRXkFQg/51YUGadTrOdSNiXgP///NGtrYvnHs/nKnp5UXny9yo6r9R56+HWpF5IJW53HLc+voX3cW90PUsb6In0RNRaW4vbn97G90tfmvg1KbfN8ty1au987Opk/JExTf2aKp0362aGWbfSFtVm3c1oL2svH5f4Any+8CHxSCKN/m2Ebh1dpJlSfL/0RbeuriLoUnkw625G5s1Mch/mlv8BG6iBAPLjnk85qxnKP/eny9oMt0FsLC43pn7C/gR0a5dvCCkQCbAda0vEMjnrYNDYALsJdhQkFlCYVIjdRDvuD7uPfkN9DD8wJGxeGB5bPYhYGkHYT2EkHk7Eoo8FAjUBgeMDFfVG/RqlcKnMCXlsTJobmkv0b9HYTbAjfGG4Uljop7dDXhVcFrmQ+GciQZOCcN/sTsymGMx7mlcoy9/zUJ1ueBUSGiVeSgALOy5EYiVh2Lph1Pyg5kvXnZqSyoHfD7Bz804AVi9ZTX5ePl8M+AI1NTXeFCxYvoDW9VozYtwI3D3d2bRmE6O/Gf3WMRovPKJXL13l9InTbF67WXGs16e9+KzLZ3z5vy+rNFRjbGAs/+z9h0s7LimOrR+5ntBboTTo1ECREfDG4Rv4nPbh73V/A3KXuR8+/IF6n9Wjw6gOL5QRUFNPk59v/0xsUCw3j95k39x95OfkU5BbgH0de0ZvHU2LL1s8s47WA1tzeOFharao+cJ5CV6m/UcMxHeNvmPd0HU07ta4QgxE7I5YEg8nIs2R4j/IH9POptiMsAEB6DfSx/hjY2y/fmxXkHQ8iaRjSWTdk0+8obNDKUgswLynORpWj8daqCXEaa4Tvl/5KtzGyqTBc6RErY4i+a9kxYoqao18NSlpIcG0y+N3qtZvtci4lUHOgxyueV/D+GNjzHubK1brCqH9iTHq5upoOWhVedCgikLdXB2PLR5cq3+N7AfZcm8CkTw2vOPM0oma1C3l5QHUJGqYfGrCPy7/lK+8GIupta4WBXEFz83Gp+Oug9M8J9L/TSd2e2ypsZJmSckJzCmXlXk60I3NSBtMPjYBIRg0MSD9n8dsR1FmEbpeuhTnFxM2J4z43fEUpRShYaGBlr0WmvaaRK6IVBLqsiJZqcBK2f7Z5D3MK5NlKs/YMnZr7OuZOA3VcFvuhk9vH0w6mpB2OQ33ze5VVn91ueG9KEJvhWKSVHV9lRhJGDxqMINHDX6j79vN3Y0BwwYwfeJ01u9aT1ZmFvaO9rxteGEFoGmLpjRt0ZSZP8185Z2zdLWk+4zudJ/R/ZnlGnZuSMPODfnfyv+9dJv9Fsk1W4e6DjTt2fS1P5CXbb8yDERZQU6ehPcJb+XJ6VMTTD41eaZQf1JIgdxArzw8SgdsP/n5H5BIV0SzgGZvzQcm1BTisdWDu53uImklIXZLrJIypcSolNgAKBiUcowWJS0keO72xLSLKdEbovEb4FdmXAOQR020n2iPYUtD7g+9T+yO2FJx/DVtNMu9vjxErYlS2GKom6njMMVBSXDnBOUgzZKScDCBhIPybQUdTx0krSVy5e4529FCLSFmXc1eyL3QarAVMRtjEKoLsRljg904OwJGBeC+yZ2gKUHoeemh46ZD2tU0bEfZcq3hy/llm/cyJ3ZbLL59fWka0JT3EXa17d4aZaWqMXXOVBq6NmTYl8PYvHfzW3kPKiPAdxCtB7YGqBQDoULVQ7+BPtZDrbnz2R10PXUrHCcg6VjZIYVTL6XiN8CPnMAcJC0lSLPKN76L2RKD/1B/ivOKMWhsUGYSH2mOFJFe5anrgoQC0m88Ze9QTGmjwGJ5HIHyhL9ubV2cFzjjstCFBpcalBmroZQAGm+H8wJnaq2thdNcJwU7kHE9A007TUS6IgJGBJB5I5OCuAJ06+qScjqF4BnBFKUUvfyKtbUEka5IkRjrfcMjo8X3EYYSQ/oM7IO1jbXCFuCdZwBUeD7ys/OVfr/PeBTs52mjtNcBaY4Uabb0jRgHmzE2hC8Jx/gT4wpfk/5v+jPH1a+/Hw2vN6TG7BoETwsut2xuSC5Bk4KouaYmCQcSSsWlT/8nHcsBlmg5aD3T3uBZeJZnRkWR5ZtF8FT5fYhNxJh1eX7UuohlEQobAIeHchZCViwjL1y+dZBwIEGh9OjV0yMvLI/0q+kvZKCpQvmwcLbAyNrovb1/DQ2Nt3qRpWIAqhh3T95l/7z9AFw7cI3zW85XSY6CtxEpZ1OIXBWpmKjTLr+eLHmZdzIJnhqMNFNKtn824YvDyQnKqdaxeJlgWU/bNyju824mobNDsf/W/rm5GaLWRpF8Mhn3je4KY0CFEF0egUwqw3Z82VsT6ubqpSIrlgUtJ60XjvFQHgqTCkk9n/pC1zzpwaBweXuSbZBRZa5wiiormO3vXYWeiV6ZLtHvzQKnuFjJS03FALzn8PrIC6+PqjfV45vCQBi1NXpm4JlXNinV1UOvrh7OC5zfiHdCVigj8ajcyDLxaCKmHUsbygrEgjJjLBh9aKTk+y5UFyrZU4T/HI5pJ1Nq767NjUY3FB4ZQg15mSfL+g/2p6lvUzy2enCv2z1FDIPM25kEjg/EdbkrhUmF8jDNuXLGRttVG4s+FoTODVX0E0AoFpbqv8siF3y/8FUsLQQaglLLjVLHnoGc4Bx0a+sqWfk/r/yjVNFF6UWv/Lmmnk8l4WACRelFRK6MxPwLc9RN1d+r+U5bX/ul8o68zQi8H8jl85fJzMjE546PIo2wSgFQoVoZiFNrTikYiBr1a9Cwc0N0JDqqwamu1b9YgNUgK6wGlQ4rLNITYfGFBUZtjVAzUKPOH3UU2xZiYzFGHYy45nUNbRdtLAdaIhALMO1kSvo/6cT/EY+sUIZffz8a32lMw2sNiVwVSeatTOzGyfdlbUbaUJRWRMrpFPKj8wkYE0DtHbWpf64+EcsjSNgvXzVHrookyy8Lh8kOWA+xJjc8l/zofDKuZ8g9DGRya/9H+RYcZzhi1M5IcX/6DfTJvJ1JcUExJp+bYNhUHsLVvKc58X/Eo1dXD/Oe5mg5aOE4zVGuZDy5LSSkVIhpkZ4I897mcgVA8BST8kj/eOoa62HWpF18zDQJRAKlFbpAVHV0raS1hEbXGr3X77a6lvoLeVm9S3Ct5crJf06+3XNTiiylWvmL05xWSYhqxG/8phqE6nz/Bar336ybPMWzUFMo91IokiFUF2LyqQnBM4KJ/z0e269tcVvuRsj0EHlcijE22I62JflEMln+WQgEAjRsNND11OVa3Ws4znDEcaYjobNDebjgIWJjMW6r3DD+yBi/r/wUngmPYjZUF4Yx7K1+dsHXg9E31a9wlsGn0Z727/W7byQwqlYDApUCoFIAVIOgUgDeW6gUgJdD2K0wDMwNKm0IqFIAqlcBUCNVUr0jcLqnahaqVg1ANf7VC5WbZrXiw7+rt/23QP5furQTZ+eGWFq6ljrnCBDyMhqY6hWsTqi8AN5BpKREM3SoBSdOrFANhgoqqPBSCAz8ByMja9VAqBQAFd4GpKcnkJ4eT0SEj2owVFBBhZdCXl42GhoqI+J3ESovgHcQDg51MTGxo1GjbqrBeIfg7X0CY+OPKSxMpqhIOaaCUKiJhoZ8lRYQMJKoqLXvXPt6evVo3PgmeXmRFBTEKvn0a2u7IBYbERe3G1/fvqqX5R3Gn38eZP36lbRp04HLl88THh7G5cv3iImJYs+ebaSlpXLjxlXmz19Oo0bysOFbtqwjJSWZe/duIxKJWLlyI9raKqVGpQC8gxAIBLRpMwgvrw6qwXiXPlY1fe7e7URi4tFS5zw8tmJp2Z+kpD9fifB9E9pXVzchIuIXAgMnKh3X1LSnaVNfCgriefBgrOpFqUJkZ6eiqys38Ltx4zC//NILN7dmaGs/DviUnp5AYOBVLC1dWbToDurqWnz7rTe5uRnY2LgjFD4OM+3vf5Hs7FRGjtxImzaVy93Stm0HZs2axKVL51i8+FcuXz6HQCBgxoyJbN26HzU1NX75ZT79+nXj3r2H7Nu3i9DQYObOXURubg41ahjTqlU7+vcfqppTVK/4u4OVK/tx6dIOJBJLrK1rsWRJd/777yja2vpMn34SZ+dGqkF6i5GW9k+ZwtfcvBeWlv0pKEjA33/wO9u+WGzMw4c/P63u4u6+CZFIFz+/ARQWJr9wvTk5gTx8OJ+YmC24uPyMvf3kUmWKijK4dMkGdXVjXF2XoaPjQVTUKiIilmNo2AJtbWeysu5hZtYdB4epFBamkpBwgICA4WhpOWNo2ILsbH90dWvj7LwQsVjyVrxzUVH3sbGpBUBmZhLffLOf+vU/Vyozf/6nCARCRo3ajLq6PCeClZUbY8ZsQ03tcWCkwMCr/PffUerW/bjSwl/O9uhgZGRC+/Yf4+johKOjE2fPniQ+Po7161cBkJWViadnXRIS4lm7djk//vgLAFpa2ty8GYSxsalqQlEpAO8WvLw6YGNTi08++Zo9e2by1VeL8Pe/wK1bxzAxsVMN0FuOhIR9pY5patpSq9a6ktXVIAoKEt7Z9lNSzlJQoJxzwMZmBEZGbYmP30NCwoFKChRXHBymERe3h4iIFdjZjUcgUE5EFBOzAZmsCCOj9piadi5pewwREctxcpqLRNKajIwbXL/eGJmsGEfH6VhbDyE0dDYWFn2oUWM2RUXpXL3qQW5uGPXq/f1WvHPR0fextpYrACKRWinhf/bsRm7fPkHHjt/g5vY4S6e39ydKwr+gIJfVqweipaXH8OHrX7pf8oBQjz1oIiPDMTExZeTI8aXKhoeHUVhYoPjfyspGNZmUQGUE+A6hZct+dO06jfz8HC5e3MHp0+vw9GzHgAFLMTS0UA3QW4709GtPTYJCPDy2o6ZmSGTkapKSjr/T7T8t/LW0HHBx+ZmCggQCAsa8pEARY2HRh4KCOOLiflc6J5NJSU29iJ5eHUD0xDXK6yd9/Ybo6tYmLm53mWXU1AwwM+tGSsppCguTKty3S5d2Ehsb+ErH9u7dU0yf3hRf37PlKgCtWg1QOpecHMXWrROxtHSld+95SueeLrt793RiYwMZMOAXjI2rXgBbWFhx+fJ54uNjFcdCQ4OJj4/FysqGkyf/VCp/8eJZ1YTyIgzAlSsX6NixtVxrEArR1Cyd/jIvL5fi4mJEIhHHjl1UGGC8S4iK8mf//nn4+p6loCAPAwMz6tb9mObNvyAo6BqOjvXw8GhdJW0VF0s5eXI1Z89uIj4+BHV1LezsPGnatBfu7i3588+lZWrTkZG+ZGYmERx8nY8+Gv3C7ebkPCAmZgsxMVsoKJDnY3d334iVVcVoOz+/fsTG7gBAImmNickn2NiMQSR68aQhKSlnSUn5m6iotQrDM4FAiFhsglSai1gsQUfHAyurQZib9+B98qu3t5+CRNKK7Oz7BAVNfs/aF1Cr1sYS6n/gCwnU8qCpaYuZWQ8iIpZgadlPcTwx8SBmZl2JilpTsUlVTe85yoYQkajiBmiBgf/QqFGXVyj8TxIZ6UfbtoPZt28utWu3VZzLyEhCT6/sDJZr1w4hLy+L0aO3KKj/svDgwRWOH19eQv0PqrJ+FxdLn1j8tMXIyJguXdozbdpctLS0OXbsEL/8so6+fQcyb9407O0dadasJQcO7KFnzy8V16alpbJixc9IJEYcOrSXI0fOMWBAD4qKCtm6dT9TpozF39+H33//E5lMxrBhX7Jp0x6Cgh5w794tzp37m27dvqBPnwHk5+ezZs0v5Ofnc+PGVTZs2M2BA7/zxx876dKlF6tXL6FJkw9Yu3Y7QmH1r78r3IPk5EScnd04c+Y6iYlFREVlKf2cOXMdsVhO+YwbN+WdFP7+/heYOrUBAoGQhQtvsXVrOt9/fxYtLT1mz27Ntm3fVOnLvWhRV/btm0evXnPYtCmZdeui6dhxEqdOrWHCBHdiY4PKvNbR0bvkd71Kta2t7Yaz83w8PLY+QaMtptxE7k8gPz+auLg9JZShLvXqncLe/ttKCX8AI6O2ODvPx8lpbsnkqk/r1pm0bBlPq1YJ1KjxPWlpl/Dx6YWf36AK9fFdgL5+A5yc5lBcXICv75cUF+e+V+3b2Iwsof73kpCwvwqVmm/IzLxLSsrjCI1xcb9jbt6nAsrqGbKyfLG2Hl7OtxFLfPxeLCz6IRRqVbhPr9oNz8vrIz7/fCJt2/6P1NRY7t+/+NxrzpzZwN27J/n88wm4ujZ9BmuTy6+/Dqoy6h/g3LlTBAc/4ODBvdy7d7uEDdJm797jSCRGjBo1kNWrlzJp0gwARo2ayOjR37B8+UIGD/6CRo2aUaeOt6K+06dPYGpqztixkxk5cgI6OrrMmjWftLRUDAwMmTJlNqmpKVhYWKGurs6AAcPQ1zdgx46NjBo1kV9+WcfkyaPJzMzgt99W0Lx5K6ZM+R5LSyvWrPmFtm0/IiQkkA4dPuPKFR+uXr3EkSP73i4GICkpkR9+WIK3d8NS5woLCxk+/Cvy8/Pw8qrHlCmz37kJt7hYyqpV/TE3d2LMmG0Ky1ZjY1v69PkJJ6eGLFnSvcraO3duMzdvHmXChD00bNhZcdzb+xNq127D7Nnlsww6OhJMTR0qrQA8rqcWQqFcqcvOvk9i4lFMTTs985qIiGUIhRpIpYWoq5uX2kut/OrMTrHye6RMCIWaJayEDH//IcTGbsXE5GPMzb+ocL1FRWnExm4jPHwxeXmR6OnVpXHj28+8Jjc3lH/+cUUmk2Ju3hNz8y/Q1fUkKelPwsJ+oLAwBXV1c7S1XZFKsygsTEZPrx4ODlMwMGjy0mMhEulQu/ZOBAIxwcHfkpl5+7V+C9XdvpaWIy4uCykoSCQgYHSV1q2v3wBDwxaEhy/GyKg9GRnX0dOrp/gOykJi4iHS0i6TmxuKl9ehUt9IRsYNIiKWkpXlh4PDd9jajn4j5ziBQEjXrt+xb988Zs78m4KCXDQ0tMuQBRFs2/YNVlZufPHFD8+sc9eu74iNDWLkyE3PpP6/+WYkW7f+hpOTK/r6Bk/NKQ9JTIzHycmVCxdu0aZNB8LCSqeKrlnTg+PHL5XByKgxe/ZCZs9eWGbbDRo0oV27hvj7+zB9unwro04db/Lz8wkOfoCv710kEiOuXLlAWFgw3bp9gZ/fPZKSEtm1awsAbdp8SEpKMhcunEFXV4+goAeYmpqjqamFuro6enr6ODo6AdCpUw9u3bpBly693h4FICMjnRYt2pR5bv78Wdy7dxsNDU3Wrt2OWFzxST8uLphLl3ayb99cZLJiunadRuvWA7G0dCE6OoCzZzdy9OhiRCI1evacTYsWX2Jq6vDaByoiwoekpAiaNOmh5Na8x+OPAAAgAElEQVTyCI0adaVu3Y+rrL1bt/4sWel4lDonFmsyaNAKduz4ttzrra1rYmnp8nL0kFCMUKiFmVlXYmK2EB7+8zMVAKk0k+joDVhbDyYiYnmpPdKXm5xE5Z6ztBxIQMBoiovziYvb80IKgJqaIba2X6OmZoCf30AyM++QnHwCY+NPyr0mPHwxMpmcfnxkgQ5gZzeB3NwwIiNX4uKyGEvLr0q+nevcvv0x//13DG/v4xgZvVz8U1fXZWhru5Kaep6IiCWv/Vuo3vYFuLvLqX9///9VCfVfmgWYyN27XcnK8iUqai0uLoueWd7UtAsSSetnKBUNsbObWKm+vG43vBYtvuKPP+YQGHgVdXUtrKzcSpV5RP2PGrUZsbj8VMABAZc5cWIl3t6fPJf6z8hI58iRczRr1lLpeEJCHM2beyIWi1m/ftcr8d23tbXnyhUfZsz4hlat6nH9egAGBob06NGX/ft/R19fn+HDx7F373Zq1aqNrq4eRUVF6Ojo0LfvQAD69h1Ifn4+UmkRjRs3x93ds4T1ySc5OVGpPYnESCmGRXWiwlsA48dPRUurtDb477+XWbFC7prz/fcLcHNzf6EOWFg407Pn91haumBp6UKfPj8qBJe1dU369VuEoaEFDg516dZterUIf0DxwG7fPkFUlH+ZZZo06Vnl7R09urjM887OjTA1tS/3egMDM3R0DKtoQpwECEhLu0J6+j/llouK+g2JpCXa2jVf88pFhIaGTQkbVTmBIBYbo6/fAICwsPnPoDQTSEk5g7q6GQKBSCH8H9djVIYAaISDw3fIZIWEhHz/UvdqatoFa+shFBWl4efXH5ms+LWOdXW3b2s7ComkDfHxfxAf/0cZTJF9pbebHsHEpBPa2s4EBU1CJNJBLDautgm6LDe8778/x+TJhxQ/OjqGZbrh/fLLfaZMOaoo17nzFHJy0p/phicSqdGlyxT27ZurZAD4mC7/jXv3/ubzzyeWSf3n5maUCL6cZ1L/j8o9gpubeynhL5PJGDGiP8nJSUybNo+6deu/kjE+cmQfOjq6bNiwm9q1vQgPDwOgR4++bNy4Gi+v+nTq1J3jxw/j5CTPh+DhUYcrVy6wc+dmEhPj2bjxV3Jzc2jWrBWTJo0iJCSI+/d9OXxY/o5mZWUp5vTAwPt06PDZ26UAlIWsrExGjuxPcXExrVq1Y/jwrytdl1isibp62R+uhoYOamrVm3Pazs4TIyNr8vOzmTGjGRcubC1Vpm7djzA3r1El7Xl7y1eg589vYeHCjiQnR5Uq06HDyHKv19MzeaZ2/iLQ0fHA2FjObpT2w370sRYRGbmiRFl4vSguzqOgQG79q6tbu9L1GBo2x9CwOWlpl0hLu1JmmcjIFdjYjHrhrQ0tLecSBSKu0v3T0LDC3X0DAPfvjyAvL7LMcmZmryYCZHW3r6XliLOznPp/8KBsGt3KagDFxXmVULiLkMmKShRKIba240hOPoWt7ZgnykgVZR5d8+Tv59VbGVTUDe/zzydUmRte69aDiIjw4cKFbQrlA+TU//btk0qo/3llfBu+PHx4B5BT/3FxwQwY8EuZeQQuXtyh9H+/fqXjR/z661LOn/+bDz5ozdixr87INCsrk969P2PDhtV4edXD07NuycLHkY4du9OsWUv09PTp2rU3bdt+VDK/6rNmzTZ+/nkOLVrUxczMHENDCWPGfIOlpTVt2tRn7tzv+OyzLiXjn8+qVYvZsGE1jRo1w8urHm8CXkoB+O67cYSHh2FgYMjq1VtKfDPfTYhEaowevRWxWJOcnHRWrx7IjBnNlAxmJBKrKvO3b9duqEIJuHnzT8aPr8mePbOUNGcXlybPoB2rNtCFg4P8A0xMPEJOzoNS5+Pj96ChYYmhYYvX/mzCwxcjleYgFKpXmmp9fJ9TSxSd0iyAVJpFfPwerK2HvHC9qannSt6RNpXlOfDw2IJYbExs7Dbi4/eU/UELtTAx+fRV8CzV3r58u0WHBw/GUFCQWAbr1RSJpN0LsxI5OcFERi4nKemYwvjPymoQlpZfoa3thlSaQ2zsDrKz/UlNPUNi4uGSa+TJtmJiNpGZeUepzsLCFKKj11FQEEtS0jGSk089sw9vkhueWKxBx46TCAi4jJGRjWI1vmbNYPLyssuk/ouKCti16ztsbWtz//5F/vqrfOr//v1LxMUFKx0zN7dU+v/evdvMmzcNQ0PJK7eY79dvCMePX2LIkNHMmjVfSY4tWfLY82Px4l+Vtrc//PBT7t59SEBALB07di9RUrXZuPF3IiIy2L37KDo6cobQyMiYsWMnM2TIaIYMeXNsQCq9SXvs2CF27twMwKJFq9+L4Aqenu2YM+cCq1b1JybmAYGBV/n++1bUq/cZ/fotKkWXvZRmJhQxefIhdu+exrFjy8jPz2b//nmcOrWGHj1m0qHDKESi8h/fo33DqoJE0gZ9/fpkZNzk4cNFipXgYyG8BEfH6a/1eeTlRRIZuZzw8KWIxca4u29GW/vl7B5MTD4rMeg7RlbWPXR16zwxGa/HwuLLF3LhkkpziIxcSWTkKiSSlri4LKxUv+ztJ2Jk9CG5uWHlhrtVVzfDzW0VeXlhVT7W1d2+ldVAJJLWyGRS7OwmllL0xGIjtLWdiY3d/sJ1a2s74+a28imFXwcPj20lf2tjafmVwqbjEdzcVuDmtqIcIWqEtfXwcj0ClIX/m+eG1779MHx8TiuE4cWL2/DxOY2OjoTDhxeWEv4PH94FZOjoGPLrr/9DJpORnZ3GokXK7osZGYkEBv7L0KHlu1Tm5uYwdGhfCgoKWLduhypwz5umACQmxjN+vDyOcteuvenR4/1JvuHs3IjFi+9x7NgyDh78iZycdG7dOsbdu6fo1Ws2XbtOq7qHo6ZOv36LadmyH1u3TsTX9yyZmUls3jyOs2c3MXHiH+Ua+mlq6r4CITAJH58+xMXtwMlpHhoacq09JeUMRUUZmJp2feXjL5Vmc/v2R+TlRZOd7YdAIKRWrTUlgrkq7lmAvf23+Pn14+HDBdSuvatkBVRIVNQ6Gja8UqFaYmO3kJCwl+Tkk4jFJtSrdxqJpDUCwYuvZLS0HHFy+lEhWJo0uVeGwqiBuro5IMDX96sqHfPqbl++yt5MTMzmd3JO8fL6CC+vj5DJijlyZBH371+kVq2Wz7zmkRtex47fvBI3PA0NbQYNWq7EKDzNKgAsXdqTvLxs1q2LVhxbuTL4pcbju+/GExQUwJdfDqJz555v9bMtLi7myJH9xMfHce3aFRo3bv72KwBjxvyP5OQkLC2tlSiSl0VSUgSrVw8sdTwjI+GNimSnpqZO587f0rbtYA4c+JG//lqFVFrI7t3TKSzMp1evOVUseL2YNesMt2+fYMeOb4mM9CU8/C6zZrVg0aI7ZY7NBx9UvVJmZtYTLa3vyM19SGTkcpydF5Ss/hdjbz+xUsLtRSES6eDtfZKionSuXatHbm4oGRk3K7TSqigsLL4gNHQm8fF7cXKah5aWE3FxuzA2/qjCBmGWlgOxtPySW7c+JCXlDIWFiZUen9zcMM6e1ay29726239fUJ1ueGXB3NzpuWWiovzJykqpsjH488+DbNu2nho1nFmwYMVb/0yFQiEjRoxjxIhxb2b/XvSCTZvW8PffxxEIBKxevRlDw6pLamFiYsfo0VtK/ejrm1X7QOXn55Sy/tfTM2bAgKUsXnxX4S5z8OB8MjNf3jUpJOS/Use8vT9h0aI7CgUjPT2+FB33aicoEXZ2E0o+/LVIpZlkZ/uRmXkTK6tBr/V5qKkZUKfOHwiFGkRHr1cKv/ry96mGnd03yGTSEqNHGRERy7C3f9FATwI8PLYjFptw//5w8vLCVVJOhWeiRYuviIsLJjDwKjExD16bG15l0aBBJ6U4JS+D2Nhoxo0bgpqaGr/9tlOxf67CG8IAhIQEMXOm3Mp76NAxtG79Ybllo6Mjsba2fWcGKjc3gzNn1jNgwC+lzllb12LKlKNMnOiOVFpIWNht6tT58KXaO3duExYWTujoSJ7SKEX06DGL+PhQLlzYSnDw9dc6DlZWgwkNnUNhYQpRUevIzvbDxmbUC0U2qyro6dXD1XUpAQGjuX9/OPr6DV7aBuDxMx1MWNhcYmO3oq9fH11dzyeCEVUcGhqWeHhs5s6djvj6fkn9+heUYhqIRHqYmXXFxWUxQqEGiYkHlZQcE5PPOXdOB01Neywt++PoOIP8/GjS0q4gFpsgFhsTHf0bUVG/Kq4zNGyOnd1EzMy6kZl5l5yc+2hpOSGV5hAWNpeUlLLjoGtp1cDefjIaGhYUFiYjkxWTlxeJQKBGfPxe1NR0sbEZiaXlAFJTLz6x1y/CwKAh8fH7CQmZ/s5PmlJpDhcvmmJi0gk1tUf++MXExGxGR6cWjRr998zAQc9muB674bVq1b9cN7yOHSeV64anpaVfITc8LS39lx6Lxo27kZmZ/NL1FBcXM2JEP1JTU5g+/Qfq1WtUZpng4Ae4utZChdfMABQVFTF8+Ffk5ubg4lKz3KhKII8MuGnTmlfW6atX9zJunBu9egk4fly+T5Wdncr69SP49ltvfH3PEhZ2m8mT69Krl4C//lqlsAyOiXnAuHGurF49gKSkiBdq9/r1Q+VaGFtaumBlJfd/fzJIR2UhkxVz/frBZ2jeHausrReboHSwsRkByA3/EhIOYmNTfVatNjajMDfvjVSaiY9Pr0q5gJVN3Wlha/s1xcX5BASMxsFhyos+wSeYrc+xtR1DWtoVQkO/f0qYZBIbu420tMsUFMTi5zdQ8XP3blcCAycgEumSkxNESMhMZLIi4uJ+x8enN7dutSM+/ndq1lyNjc0oRZ1paVeIiFhaorTPwMenDzduNEcqzcTb+yR6el6lemtk1I6GDf8lJeUMd+92xd9/CPfvDyM5+QS2tmMRiyWkp18jPHxpCQO05om+9uPff72QSjNeEfMkxNp6KM2aBaGuXv1bgYWFidSqtR5Pz93UqrWWWrXWoq3tXML4bKu08H+E6nDDexEEBV2jXz9devcWsXPnVE6dWsNXX2nTp486Fy9ur1SdK1cu4tKlczRt2oIJE74rs8zp0ydISUnmTUCPHh/z3Xfj+PHHGfz44wyaNatNs2a1KSwsfDcVgCVLfuDWreuoqamxdu32MpMBPcKuXZsxMXkxN7SCghyk0sJylI98ioryFf83bdqLWbPkFqlFRQUlglAe9Ob7789Su3ZbHB29mTRpP+rqWujoSBT7r6amDri6NmPUqC0v7LKXmPiQQ4cWlHkuIyOR+PgQLC1dcHJqUCUPZ+/e2aSlle03Hhh4FYDmzfu8spdD7sNcWuGxtf0aoVCDgoI4LCz6oK5uWuq6R6uiquzLI8Xoabi7r0db24XMzDuVDg1bVJROUVH6U8rFaEQiPYyNP0ZHx0NJuEulmchkUqTSrKfqSSsREsr7oi4ui9DV9SQs7KcyLdVlsoIy+xUTs4mioownVkH5T036KwFZSSIkyi0nN2Jcg0Cgpkhn+wjq6hZ4eu4hJmZTqZS/GRn/ERAwUpG/vrx+FhfnExW1tlJjb2ramQ8+CKdZsyBcXZfh6roMN7dVNG8ehr5+Q2SyYjIybpQIWTlT4eq6lPbtZXh4bFdcU6fOH9St++ernzSFmkqujtnZfoSEzKJGjVno6dV96fqrww3vRWBsbEPbtv9jwYIbdOs2nfbth7Fo0R06dBiJnZ3nC9d3+/Z//PTTTPT1Dcp1+Xv4MJTp0yfi4VHnjRCc/fsPYf785Uyf/gN9+w7i4cNQli5d+0JRcN8EVGgL4Nat6yxZIrcCnjx5Ft7eDcoRgukcOrSX6dMnsnPn4Qp1IC4umGvX9hMXF4xQKOLgwfk0adJDEQr4+vWDJCdHkZYWz6FDC2je/AtMTR0wNrblf/9byW+/Dadp0578889e2rYdrESZm5s7/Z+98w6Pouza+G93s5tOKimkk0ogdDD0IggKgnTpSBMUlI4UBQEpgr6gKCJNikqRJioKRkVKAggGKQkhJCE9Ib0nm939/phkk00jgYSEj72vKxfszDNzzzw7O+c8pzJs2HIOHFhE+/avoq/fiF9+2cLQoUsfu2bB998vIzo6iEGDFuLk1BKVSkVERCA7dsxAJtNnzpyDtRYMl5wcxeLFbRk9ei2+vsPR0zMiPz+bM2e+4uefN9Oz5yS6dRtXZw9HXl4kCkUWhYUZ6Og0KiUwrLG1HU9s7O4K8+7z8gTLSn5+PCqVosoyvtVFbu6DohVz+euRSIzx8TnC1au+xMbuRkfHFHf3DdUqRVxYmE5CwiGioraSlxeFkZEPFhavYGjohVRqhr39dI3shuTkX0lMPKEWykFB07GyGl6UOnhKLdyjooSeCFZWryGT2SAW6+Hjc5DLl9tz+/ZEEhOPYWs7tsprs7IaRmbmNXJzIyr/AeuYACLy8x9dYEhHx1T9vWgqOm8ilVoQG7u7wuMSE49WWWBJJJLg4DCbyMjNAJiYvICj41wKCh4ilyfh6DiPoKDpNGrUAVPTroSHr6Z5871ERn5KePhaHj48iY3NaEQiHUJCSvq5R0d/iUwmxP/k5Nwv9SyEERPzNY6Oc3nwYANZWbc0LEJ1DSHboUSxunVrAkZGLXF2XlJrHPWZhvcomJvb8cYbQoDeZ5+NJSsrhaVLT2tkDdQE06ePQS6XY2IiY/LkURXKlfDwUJo0scfYuBENAcUFgQAWLHiLYcNex9e36zPnAhClpDy6KHGXLj4EBd0q0r4NKhSeSqWSvLySjmB37ybQuPGjg/d+//3JbmD9+oEkJ0fTu/cUXn65fH6yQiFn0aI2tGjRm4ED53H+/LcMHVpzP2VaWjzHj6+je/fxBAb+SmDgaRITw8nLy8bIyIzWrV9m6NBltdbrev/+hXTrNpa4uHtcu3aK4OAL5OfnUFCQi5NTS/r2nUG3bmOfmOfrr8tvy8kJISHhELGxe8nNvY+paRcsLV+lSZPJ6tV+dnYw9+8vp2XLH0oJx9MkJ58lOnqb2hRvbt4XC4u+Ravpx20HfIaoqC9RKDKLBExnrKwGY2s7QcMkHBOzg6Cg6YDQPKhx40E4Oy9Vpys2RPz+u/Bb8vE5iIXFy+oYAB0dMywtX+HSJXcNBaBXryyio7/i3r0FSKUWNG/+DY0atefatd5kZwepxzVq1J6OHa8SGPgqSUk/YWjoTevWpygoSOTatd4a3fs6dAjAyKg5f/5p/MjrNTT0olOnoFIxAGJMTHxJT7/E7duTisZ407LlUZTKfMLDP8TCoh+JiUextZ2IufmLhIWtRiazJDv7rrqgUIsWBxCL9fjvP01LhkRigEKRg0RiRK9emfz9ty0FBfEYGLjRufM9AgJ8NBQAicQQhSK7BoL2yWqy37//AQ8ebOSFF/7F0LDmJbCnT698X0LC/WpF4tcnZs50ID8/h927H88036cPzzSOHTvIokWzuHw5GAsLy8dQpuq3el61LAAXL95ssF/AmDHrWLCgZaW+cIlEyvTp21m5sicpKbHMnv14PipTUxu1huvq2p5hw5bX6X2NHy80IHF2bk2nTk83F9bAwAMXl/dxcXm/SkFQWvgLpsGXsbB4GQ+PT2vtWszNexe1BF7/yLF2dtOws5v2zL5MimMAiuHqurrCcWZm3fDx+Z7GjV8jJmYnt29PLOdyKEaTJpNwcpqHqWl3goKmERd3AJVK09Wmp2df6fGVITp6GwkJB4tWxFYaMRLZ2XfIybmHQpFFYuJxEhOPFz0zPpiZ9SQ6ehuPattc3IQqPv67al9TkyZTiI3dhVgsw95+Fo6O7xIc/Bbe3ru5d28xxsatMDT0JC3NHweHt7h8ucMTfV8ZGf8QEbEOd/ePH0v4PwoNXfgDODq2RC7P43lEZmYGy5bNY+XKDY8l/BsCdJ71L8HPbycjRqxg3775tG37CsbG5b8IT88ueHl1xd7eu8qKWVpo0ZCQlPRzhdtTU89z//5SOna8iplZ93JxCKURG/sN2dlB+PrewMTkhQqL6SgUOUilj/8CKyhIJD39almbYAVBgcqia61Y+BsZtcDNbT0ikQgzsxeJi/umGgJoDgUFSUilplhavkps7C5UqkIyMq6gp+eIRGJEcPAMcnJC0NW1xtp6FGFhq8nPj6Ww8PHz15XKPG7fnoCpaWccHN59bp9RZ+dWyOX5z+W9r169FGfnpowdO/mZvYdnWgH45ZctdO06Gje3jly//jPffDO30hW+jo5undaT1kKL2kZ6ekAVAqiA27cn0KHDFZo2XUloaOUVKHNz73Pv3gK8vLaRmHisXF369PRL2NpORF/fucp4g6pQbA14EmRl3SI0VOjFIJVaYmX12iOPiYzcrHYBODsL1y6kLwoxI4mJx9QWD2PjtuTlhZOe7k96uv8TXWto6DLy8qJo3fpnjZifwsIM8vNj68Qi0BDRpIkneXnZz91v899//2H//p34+V1Vu8QVCgWpqSk1DoCvTzyzEvHOnXMolQrc3X0RicRMn/41Fy9+zz///FjheJVKiVKpRAstnjXY2o6vcHtm5g3Cwlbi5LQIExPfKs8RHf0Vycm/4e29Sx0MWCJEt6BSKXBwmFPhsTKZNebmj65roa/violJ51q5Z7k8idTUv2p0TOkMhpJ+66WtDapa6cOelnaeqKjNeHhsQl/fRWNfVNTWUrUB/v+jUaPGtd53pKFDoVAwf/4Mpk9/B2/vkqyH338/TUHBs2UNeeYUgPz8HH78cSPr1w/UaJJRWJiPrq4BX3wxsVwu6s2bfjx48B+3bgn/aqFFQ4NIJK2wxbC5eV+NQEexWIZYXJIC9uDBx2RkXKVFi+810jHFYt2if/VKKc1TkEiMaN58r0ZmRmbmv4SEzMHBYTYuLss1ijoZGHhgbz9D3SWv+BrFYmm563d330hm5j/qV4tIpFvudVN+W+XIyQmtUXvnnJxQQFQmZbN2oVLJuX17EiKRlPT0q9y5M1X9d/36S0RGftqgg05rGwYGpnXSd6QhY+/erwkMvEZhoVxdB2DJkndZtGjWM9e46JlzAejqGjBo0EIGDdLsD+3u7svevRUXIvHxeZEdO+LRQouGBonEGBub1zE3760ub1wcxS6VWmBu/hKXL7fCwMAdW1tB8DRuPIj09EskJBwpEkgTeOGFQDp0uExU1FYyM6/j6Cj4pe3tZ1JYmEZKyu/k58cQHDyLFi0O0K7dn0RGbiEx8ah65ZqVdRtn54XY2U0lN/cB+fkxZGRcITx8NaDCxMRXnfbp4rIcc/MX1cK/UaP2ZGb+i1JZgKXlQExNhSp11tYjSEg4grFxa6ytR6Cv74yLy1IePPikTK0CMSAqNzfW1qOKTPyiIi5RmbWL5jF2dtNJS/u7lGIiKVWXgidOSRWJpHTpcl/74BZBT8/wuQsCnDx5JpMnzyy3fd26Lc/cvVQrDbAu8aRpgFo8GSpKA9TiaT7/oud+DqyshuLp+RlisV5RlkIhYrEMS8tXCA1dTkLCQRwc3sHTcwv37y8jMfEY9vazcHB4m+Tk02Rl3UEkEqGra4+RkQ+XL7fGxWU5Li7vExa2koiI9UilFnh6bsXCoh+3b49TZyY8aRrgk6KqNMBnAbGxd8nKSqmyI2FVeNbTAJ8U9Z0GqFUAtAqAFloF4LmFVgF4MiQkhJGdnUrTpu20CsCzqACoVPWrAMCRemav337TI0XPtwCo98fvOYfoeX/+6lkC9T1bzxNQzxfQp8+GeuV/7733nuvnX5sXp4UWWmihhRZaBUALLeoHu3btwtTUlCtXrjyX/FpooYUWTxvPZCGgq1fvs337WUJD4zE21kdHR4y+vozBgzuQmZmLqakhw4f71hn//atXObt9O/GhoegbGyPW0UGmr0+HwYPJzczE0NQU3+HDtU9XDaCvr4+pqSm6upppYvfu3WPp0qXExMSQk5PDnTt31C03b968SYsWLf5f8GuhhRYlyM/Px9/fn8uXL5OamopEImHRokWYmFRdYyEqKoovvvgCgKZNm9K8eXM6d+7cIF1dOjqwZg00agRz5sDw4TB1KkyYADt3wi+/QHQ0NG8On30Gx48L2zw94dAhzfi5NWvg/fdBpRLOd/QoHDsG27eDUgkmJsLxfn7w8CF07AjvvfeMWQAKCxUsXLif3r0/pFev5vj5fcCpU4s5fnwh27ZN49q1MKZN205KSlad8CsKC9m/cCEf9u5N8169+MDPj8WnTrHw+HGmbdtG2LVrbJ82jayUmpUY7dKlC0ePHi3qLBjBjz/+yOHDh7l69SqHDx+mW7du6rHGxsZMmDCBxMRE0tPT+eabb9R/x48fRy6XI5PJ8PDwYM2aNahUKmJiYjh58iTXrl3jzJkzdOnSpUHxA4wZM4aIiAhatSrpVX/79m3atWtH3759uXTpEoGBgURFRTFkyJBa/27rm///I1xdXdm+fTvHjx9Xb5s7dy6HDx9+Lvi1eHzo6urSs2dPhhctpBQKBefPn3/kcefOnVP/f/To0XTp0qXBxrkUFsKtW3D9OhQUwJUrEBYmCP3QUPjjD0GI/+9/kJ4OISFw4oTwef78kvOYmkLLltCjh/A5IwPu3oXz5wXhDyXHHz0qBH7/8INwnmdKAXjvve/YtOkUBw7MZuzYbkgkJZdvYmLAxx+PY968gXWmAHz33nuc2rSJ2QcO0G3sWMSSkpxiAxMTxn38MQPnzauxAnDx4kX+97//ATBr1iwGDRrEyJEj6datG5GRkZw7d465c+cCkJmZyb59+7hw4QJxcXFMmjRJ/TdkyBDmzp2LkZERISEhvP/++yiVSvbv38/gwYPx9fVFLpfj5+ensXKtb/7KsGnTJqysrJheKlTa2tqaQ4cOaQjqukJ98z8tdOrUibNnz6JSqTh48CAHDx7E39+fwYMHP9F54+LiUCgU6OuXFBY6ffo0O3bsaFD8WjRcmJiYYGpqilgs5sqVK+Tk5FQ6NgGCJ+8AACAASURBVDk5mdjYWLXANzAweKbvvUsXeOONEsFeDCcniIws+dymjWA5GD26+uc+exZ6936GFICAgHt88skpOnf2ZPDgyrt4rVw5gsJCRa3z3wsI4NQnn+DZuTMdqngxjVi5EkVhYY3Pn5eXV+G2BQsW8P3337Nx40batm2r3ldQUFDheXbv3k1GhlAQSaVSqc3VAHK5nM2bN6Orq8vYsWMbFH9FSEhIICYmhpCQEI3tUqmUGTNm1PkzV9/8Twv+/v4cOiS05X399dd5/fXXOXr0KMeOHdOw/tQUOTk5REdHa2wLDg7m7NmzDYpfi4YLkUiEiYkJLVu2pKCggEuXLlU69u+//9ZY8T8rGS6tW8Nrr5VPibx4EfbsgYSEkm2DBsHs2ZoWAE9P6NxZUAyMqlmUUaWCvLxnSAHYuvVXAF57reoWnsbG+syY8VKt8/+6dSsAHV6rukGJvrExL9WycFi1ahUSiYTZs2dXOW7YsGFYWVlRWIUCUpx2l5mZ2WD4o6OjWb16Nc7OzgQElDTA6d+/P3l5eXTp0oWDBzWbzQwYMABra2sAPvnkE3R1dRGJRGzevBmAvXv3YmNjg0gkYty4cdy7d08tbLy8vOjUqZNaONQ3f8MwRxaWU+TEYjGjRo16ovNWt/9GffNr0bDRo2gZfOnSJY1FRTGys7MJDg6mQ4cOz9y9BQYKpv3KauLcuiX49QF+/BHi4wWTP4CPj3DsiRNC3MDIkeWPNzAACwvNbb17C1aAGisAN2/eZNWqVbi4uCASiRCJRDg5OfHhhx9y8+bNOpukc+fuANCsmd0jx1paGtc6/50i35Jds2aPHGtsWbu9oe/evUtSUhK+vpqBjba2tmr/+8mTJ8sJqbLQ09Nj4cKFpKenc+DAgQbDf/v2bc6fP8+DBw80xs+aNYsxY8aQlJTE6NGj8fX1xc/PDwAHBwcaNxZq38+fP585c4RGNn37Ck1rJk6cyOrVqwEYNWoU7u7ugGButrGx4ccff8Te3r5B8DdkFCtqS5cuZePGjXz99decOHECfX19mjZtysmTJwkMDATAy8uLv/76i59++qnCczVr1ozdu3dr+OQbOr8WDQO2trZ4eHiQk5NTYabOxYsXad++PTKZ7Jm5Jx0dYfXv7Q0ymWDKd3EBOztwdYVXXoGhQ2HdOpBIwMsL2rYVLAAffggDB8KCBVBs6EhPF4IJvbwEq8Do0UJA4ebNQiyAlxe8+iqMGAEvvQSLFj2GAuDj48MHH3zA3r171dv27t3LihUr8PHxqZOJUipVxMYKfnULC+On/kWplEpSYmMF4V5WlXpKSE5OxsrKSmNbaR/84MGDWb9+fYXHduzYkWXLlrFz505CQkJo27YtkaWdSPXM369fP1555ZVyx4nFYr799lu+/fZb7O3tuXz5Mn369KFfv37lzPIzZsxAJBLx7bffqrcNHz4ckUjEnj171NuCg4Nxd3dXC++GwN8QMWfOHPLy8ti7dy9eXl68//77LFy4kDfffJNOnTrRp08fwsLCNIRpcHAwv/32W6XnDA0NJSMjQ8Mn31D5tWh46NmzJwDnz5/XsOwUFBRw7do1Onfu/EzdT2GhIMDnzROCAI8cgRdfhJgYePll+PhjIQhw7lxITYWePeHwYcjOhr594aefYOJEiIsTznf2rGAZCA4W9i9bBvv2CdUmi4/fuFHgWbRICBZ8bBeAnV3JStzR0bFOJ0osFiGT6RStCHKf+hclEovRKdIsc2tgOq9NmJmZkZSUVOWYn3/+ucLtV65c4aOPPmLcuHHMnj2bsLCwBsdfNv2uNMaMGUNISAjr16/H1NSUM2fO0L59ew1zvYuLC71792bfvn0oFEIMyIkTJ3Bzc+PUqVPEFf1Kdu3apRHU11D4GwpmzZrFunXrsLKyomPHjgQHBxMaGkq/fv0Qi8W8/PLLqFQqGhXbJMsqy1VUdpTL5SSUdmg2QH4tGi6aNm2Kg4MDaWlpaqsPwNWrV/H29sbQ0FA7STWVrY97oKRUBLxYXPehBG3aCH23796NrZeJcmnTBoDYu3efOrebmxtWVlb8/fffVY4LCAggIiLimeSvKGDnv/9KWjfr6+uzePFiQkNDGTx4MJmZmcycqdmRa9q0acTExHDmzBlUKhVHjhzh0KFDFBYWsmvXLuRyOTdv3qzQT1jf/A0FW7duZcmSJcyYMUPt0issLMTMzIz169cTERFBUlLSYwdYPar089PmD87O5u3gYES//06f69crPS42Px+Znx+W586xJzaWbEXtBBpnB2cT/HYwv4t+53qfyvnzY/Pxk/lxzvIcsXtiUWTXDn9Ozl3u3VvA77+L+OsvEwoLMyodm5V1i99/F/Hnn0ZER2+joODpK1PFsQDnzp1DpVKhVCq5dOnSYwWLisVK1q+HL78UTPBjxgipd/b28Ouv8M47ggn+/feFPPo//hBW7Dt2lA/YW7OmxBTfqJGwGp85E4pFY/Hxy5YJK/KdO6Gsp1gsFszzCoWwSt+9W7gON7eaz9PIkUIqYcniDCp67TwzQYATJwpf/OHD/o8cGxISV/sP3sSJAPhXI4c4rox5+EmxdOlSCgoK1Kl6j8L48eP/X/Dv2LGjXMCPhYUFhw8fxtnZmcDAQI3gsSFDhmBhYaH28w4YMIA2bdrg6+vLjh07OHnyZI1Sy+qbv6GgS5cubNiwgcWLF3Pnzh2NfQqFQmMx8KzxexkastnTEx2RCL+UFG5UYuH7IjoaJdDb3Jw3mjTBsJbu2dDLEM/Nnoh0RKT4pZB5o2L+6C+iQQnmvc1p8kYTJIa1w29g4Im7+yZ0de0pLMwgNnZnpWMjI4UAV1PT7tjbz0Qms37qz2Lz5s2xtLQkISGB4OBgbt68iZ2dHebm5jU+l1Iprvc8fM3rEQR/cjJ88glMngxRUfDddzWfp1OnBEWmGO+8IwQbPrMKwJQpvfH1defChWB27vSrdNyFC8Hcvh1V6/y9p0zB3deX4AsX8NtZ+Y8k+MIFom7frvH5KzJB6+josGLFCsaNG8fUqVM1Xn5SqRSpVFrumL59+2JjY6Ne1Uql0mr5POubvyJkZmZq+NSLIZPJcHBwwNnZGR0dHY3t48eP58cff+SLL75g8uTJAEyfPp3IyEiWLFlSrfTDhsL/NFF8H6Xvpxjt27fHwMAAY2Nj2rZti6WlJQYGBri4uBAfH4+Liwt2dnY0a9aMHj160LhxY/WzURwoXNrSUtHqvT75pSIRvczMMJdK+aSC2JhcpZIr6ek46+khq4PUMpFUhFkvM6TmUiI/Kc+vzFWSfiUdPWc9RLK6SW0zMHDFyKgFkZGfoVKVty7I5Unk5oYhkRgikdRffr1IJFJbAf766y/+/vtv9efaVzzrPg+/YsWktDwTggRritwynvL796GC5IlnRwHQ0ZHw889L6NjRjenTv2bevL1ERpb4pDMyctm69VeuXw9nyJCOtc4v0dFhyc8/49axI19Pn87eefNIKvUU5GZk8OvWrYRfv07HGlaK69q1K4sWLQJg7dq17N27l507d3L27FkcHBxo27Yt+/fvB4RKfNOmTaN37964uLhw5MgRdST+qVOn+Omnnzh16hQeHh6sXbsWsVjMa6+9xpgxYyoU2A2BH0rqEJStLzBr1iwNvzrA999/T0BAAJ9++mm580ydOpWCggJ69+6tVjxGjRqFiYkJ3bt3r9R3/DT4u3TpQufOnenVq1e54x4+fMi7777Lxo0b6dixI+PGjUMul7N8+XJsbGyIiooiICAAExMTPvnkE/UxAwYMwN/fv+g3kKHORihGREQE3bp1Y+DAgaxatYoXX3yR22UU1E6dOjG66O21cOFCHBwcNPYfPXqUrKwsbt26Rfv27fnjjz+YPHky2dnZ+Pn54efnx3///cekSZM4d+4c6enp9OjRAycnJ/r160erVq3o1q0bLi4u9O3bFx8fH42MkvrmBzCQSHjTzo6D8fHE5udr7NsfF8d4W9s6fb9JDCTYvWlH/MF48mM1+eP2x2E73rbO37GOjnPIy3tAYuKx8haI6O3Y27/51N/7FbmM2rRpg7GxMQ8ePEBfX18jHq30MdXtNFqfefiPXHj2LkkPXLdOiPI/dQq6dhVcDdu3Q3FC1fz5QspgWbRrB5cvC8eUk6vPkinS3NyIS5fWsGfPn3z//UXat38PmUwHFxcrXFysmDnzJTp18qgzfiNzc9ZcusSfe/Zw8fvvea99e3RkMqxcXLByceGlmTPx6NSpxue9cOECFy5cqPaqdMeOHdWqZrZkyRKWLFnS4Pl/+eUXdhZZVTZu3IihoSHt2gn9xbOzs5k4cSLz5s3Dzc2NnJwcrKysOHPmjDoquKyJ8KWXXuLtt98utboxYPz48YwbN65e+YcOHcr+/fuJjIxEpVJprES3bt1K165dGTFiBLNmzWLTpk1IpVKWLVvGtm3bkMlk+Pr6Mn78eLUy0rhxY3r27Emnomfu22+/5bvvvmP58uVYFjkYnZ2dadeuHc7OzsyZM4cVK1awYMECTp8+reb29/fnxRdfrPT7iY6OxrvUMuTrr7/W2F/WrVE6G6TsHPWuYNlT3/xqZc/BgU0PHvB5VBTrihyvKuBQQgKnW7dm1WMEz9YEDrMceLDpAVGfR+G2rsjxq4KEQwm0Pt2asFV1y29jM5bQ0CVERn6KtfWIUsJKTlLSKdq3v8CdO1Oe6js/JyeH7Ozsctairl27cvr06XKr/9zcXLXgz87OrlThL43iPHw3N2jfvvz+snn4LVoIJv9Ll0ry8OPjhbS+kSMF372mdQXKGkGL8/ArQ//+0KuXYGnYtAkMDYUMgY4dISVFsExMmSKco7g0zcmTwvayuHatioU1zxgkEjFTp77I1Kkv1gu/WCLhxalTeXHqVLSoHbzyyisVpuEVWxZqiopSwT7//PMGwd+vXz+cnZ3LmaFbt27Nu+++i4GBAQMGDGDChAmAEHw4ZMgQDh48qN5/4MABFi1aRGBgIG2KglOVSiWpqamMGTOG7du3s2zZsgqvLSsriyZNmmgfugrQRFeXUTY2bI+JYbmLC4YSCb8lJ9PLzAzZUwh01m2ii80oG2K2x+Cy3AWJoYTk35Ix62WGWFb3/GKxHnZ2bxIevob0dH9MTATFMiHhCI0bD0EkenriIj8/n2vXrnHt2jWSkpI4efIkHh4eNCuqw+Lr68vdu3fV9TUALl++rGHdOnLkCM2bN+eFF16o0O0kFitp3VoIvqssD9/DA7p1g1WrNPPwT5yALVuEoL333hPOl54OH3wgKAbFefh37wor78WLS/LwfXyEgLwio2uF+PVXKJVkBAjXMWqUoARUkbRULZfAM6sAaFHaImLOvHnz8PDwYGRFJaDqcrXi4MC2bdvo3r07cXFxrF69ukbFhZ4njB49muTkZN555x21O2Dfvn3s2LFD3eBkyJAhKBQK3nrrLZo2bcr27dvVx0+YMIH58+czc+ZMbGxsUCgUBAYG8ueff/Luu+8WrUx+ZNCgQRgYGNCrVy8WL16s4U+/ffs2u3fvplGjRqxYsUL7pVSCuY6OHIiLY09sLLMcHNgeHc2Ox3HCPiYc5zoSdyCO2D2xOMxyIHp7NN47vJ/i7/ptHjz4mAcPPqVlyyMAxMTspGXLo0/1e9DV1aVz586V5vbr6uqWS6d94YUXeOGFF6rNoVSKNYTwkSPCHwh5+MU4dqzYmlSyrajeF6VrThXn4ZfeD0Iuftnji3mqC0ND+P57YdWvUJSs+qvp5ahc6dP+5J9N6Ojo8OKLLzJ48OBqmblqEyKRiF27dnHhwgVmzpzJw4cP2b9/P/37968zzuTkZKZNm8abb77J2LFj8fLy0ljVX716lWnTptGmTRvS09MZPXo0xsbGNGvW7JEVCit+OShZu3Yto0aNYsaMGXh7e/PWW2+RX+QfjoyM5IMPPsDe3p6oqCg+/PBDGjdujL29PcuXL9fIDggNDeXmzZv88MMPXL16lTt37nD27FnulkopjYqKYvjw4dy9e5euXbvSt29fdbGTbt26kZyczObNmxkwYADjx49XF+IqTsE9e/Ys//zzD3///Tfm5uYcPar5wm7evDmTJ09mxYoVT/15eZbQ1tiY7mZmbImK4lZWFlYyGZZVxK7UNozbGmPW3YyoLVFk3cpCZiVDavn0+GUyG6ytR/Hw4XFycyNIT/fH0NATqdTs/+13bmcnmMnnzxcE6/z50KmTsEpPT4dx42DXLpg0qfyxX34pVOkrWZQJVfomTgR/f8GU37o1pKUJ537tNfjqq0dZYjTPCUJAYuPGQivfJk2EMUZGkJlZEu3fqlV5V8Mj5Yj2J/9sorCwkCNHjtCnTx+cnJyeKnerVq1Yt24df/75JyAUvAkJCWHkyJH8+uuvdcI5fvx4cnNz1ZyLFy/mnXfeoU+fPlhbW/PgwQOOHj2KqakpCxcu5KWXXqJHjx4sX76c0aNHo6enx2uP6ONQGps2bWLVqlWkp6ejq6vL6dOneeWVV2jZsiUzZszgxo0bnD17lpiYGD7++GMcHBz4/PPP2bBhAx999BFZWVnqvgBXr15Vn/ejjz7C2dmZpUuXavD98MMPvPHGG5iamrJ69Wr2799PXl4eBgYG6n4Cp06dYtGiRYwbNw53d3d1Y5R///2XAQMGqN0YNjY2rFq16onq6Ds7OzNlyhSWL1/OyZMnCS1KKtbX12fMmDE4OjrWqJ8ECMGmy5cvZ9u2bZw8efKp8vfo0YPPP/8cFxcXLl26xIwZMwgPD69w7DxHR167cYMRN29ytHhJ9xThOM+RG6/d4OaIm7Q8Wg/8jnOJi9tPVNRn5OfH0bRp3VqMbt68ye+//05CQgIuLi7o6uqSkpKCt7c3ffr0KZcZcv36daRSaYWVZ0ufy9bWFktLSxQKBenp6djb29OzZ0/MzDSVmZgYCA+Hc+fgn3+KFDFjQbimpgpBdn/9BTduQGmPYLNmYGsLQ4YIaX0guA0KCmDvXiFYr3VrIcYgLU1wGwD4+VUu+IcNE+r2Dx8upA0+fFh8z8L2334TrA6tWoGDA/z9txAcGBAAW7cKpv4uXYTURF1d6NdPuDc3N+H/ly5pZhnUuwKQkZHL/v1/s3r1DyQkpDN8uC+bNo3Hyakxt25F8dZbO0lMTGfFihF0796M998/xJ49f2JjY8qOHW8ycKAQrBUXl8q7737Db78F8tFHo5k27UXWrDnGyZNXeeEFd3Xr4LCwBM6e/Y8lS4awdq0QeXzTz4/Px42jVb9+yPT0ACjIzeXcvn14dunC+2fP8suWLRz64AMUcjlTvviCXm+8gUxfn8KCAk5u2MDhFSsYMHcufd98k//OnuWH1atJT0jAd/hwxm/aRGMnJ6Ju3WLnW2+RnpjIiBUr6FKTvJFKUFFjjLrGnTt3NKLls7OzuXz5snp1XBdIS0ujS5cuJSu1os6E4eHhNGvWjOHDh/Ppp59y9+5d1qxZoy5b3KRJEwYPHszatWtrpACkpaXh4+OjTo8s5iuuYvjqq6/i7+9PQEAAr732mjqIrWfPnri6urJt2zZWrFih8bKJjo5m3bp1NGrUiOHDh2vULU9OTsbX15cxY8aQn5/PqlWrNNqZTpgwQZ1eaW9vz/Tp02nTpg1xcXHMmTOHNWvWqMdaWlri7+/Pxo0bGTp0KP/++y9RUVG8/vrr6nM8ChEREWzZsoXly5fzzTffcKL47YWQfmVsbFwjAWxmZoZEIqF79+589aglUC3zm5mZ8fbbbzNt2jQMDAz46quvOH78OK1btwZAoVKRUyrL41VLS1z19XHS08O7VHW5ApWK/KK3Z6pczvaYGN6/f582xsYcbdkSBz09voyOZkNEBF94eWGqo8OCe/e4nJ7ONi8vZtjb8yAvjxH//UdHExOWu7gAMlQKFYqcEn7LVy3Rd9VHz0kPQ+8SflWBCmW+wJ8fnc+dqXdI/i0Zj80eOL4rVGNNPp3MfyP+w3OLJyJdEUHTgjD0NqTl4Zbou+ojT5Fza5wQKu611YuKFozGxm0wM+tOTMwOzM17YWjoVencZmX9x61bY7G0HKCOEYiP/x4Q4ev7H7m5oVXuB6G8fEJCAgkJCUyZMgUdHR3Cw8P5+uuvSUtL4/XXX9fgvHTpErq6uhUqAD4+Pjx8+JAzZ84wc+ZM9W8sMzOTQ4cO8b///Y/Jkyfj7Oxc7thOnQRrQKdOJX79Yri5QVE/L41tU6YIefrFCsDp00L9gGbNhHiAP/4QtkskgjXA0lJYuVf0EyiuA1CReyApSYhHKEbpkKaieGWgJCNAsNSW/L+ytiOPrQCUrsWseIKqWI0a6fP22/3o27clHToIs+7kJNRJd3W1xtTUgOPHF6h7AOzePZOHDzO4eDGYbt1KGvPY2prh7m7DtGnz6dtX0JpNTAy4enUdurrSImGpoFOnZbRu7czKlSVRrlnJyaw6fx6bUiWX9rzzDnpGRszatw+Zvj6vvfceEh0d9i9ciKOPD7IiW4uOTIZbx44MXbaMUUXNX2w9PGjZty/vFZVealy0Qrd2dcXA1JQFx4/XW0+B2kBFrYBtbW2rDLR7Uly8eBGRSERqair79+9XWxpKX4tYLMbMzEyjZ8GgQYNwdHTk2rVrNSoas3btWj766CPkcjnHjx/n96JcnLJ8AJ6enuptNjY2DB8+nH379hEYGKiR8mdhYUFBQQEymaxc05I1a9ZoCPGycHNzw63U87llyxb1vJ8ralRVjPbt22ukQJXdXxMrU0U4efJktVOsipGamsq5c+eIj49/6vweHh5MnTpV3ab6rbfe4vfff8fS0pK7OTnsjokhID2dXbGxDLOywlRHh3cdHXEvUsCi8/M5GB9PVF4eOQoF38TGMsLamvecnZGIRHweFUXjou8zS6HglzZtaF6kOPzapg0t/P1RFF2voURCN1NTPil6m+fczSFmdwzpAenE7orFapgVOqY6OL7riIG7gVrYxx+MJy8qD0WOgthvYrEeYU2L71vg7+mP1KLERSCzleG23o0mU4RAz7wHecTti0PPWVjYSM2lGLgZ4LbeDYmBpNRvWrPMt4PDHP77byj29iXZLCqVEqUyD4Uip9QCJJk2bX5FV9euSHG+SETEBtq29UMiMXjkfrUgKrPKd3FxwdHRkRs3bjBs2DB1CnF0dDT6+vrcu3ePhw8fVthTo6JaEsbGxkycOJEtW7bw7bffsmjRonJpyf7+ggUgNbVkm1QqVO4bOVJovlMMKysh7U8iEVb8HTsKhYSSk4VMgpkzhUJAU6cKSoFCIQT2AXTvXvXz6uQE69cLqYXFyVaNGwvVBCtyQ1QEV1fhHDt3ClaDSt0Nj/tCjooqKbYTG/vk5Xk9PGzZtm0aP/wQwMmTgsl07ty9rFnzerkGQF99NQ2lUsWSJSUlksLDE8nOzlcLf4CBA9uqhT/AypWHuXUrigMHZqt7CwA4tmypIfxvnDnDr1u3MmnzZqybNi0537x5uHXsyO5Zs1AUrbwVhYX89c03DHv/fU2B6OHBtG3bCPjhB64WmTv3zp3L62vWPNPCvyJ4eXkRFxenNs/XBfLy8li0aBHz58+nT58+Naqn7+bmhlKprLG1ZNeuXQwbNgxzc3M2bNhQIz6gnEVEX1+f5s2bP5MtS4vRokULOnbsiFwup23btnz//fd8/fXXbNu2jZiYGKZOncq5c+d45513uHjxYrny0U/anvdx+C9fvqwW/sVWnPT0dNLT0/E0MGCDuzsZvXoxpUkTTIuEx2wHB/oX/U7tdXVZ4OSEqk8fknr0YFKpSoDzHB2xkErZEBHB9cxMDMRitfAHMNXRYYunJyvCwkiRy1kTHs4Hpd4pBp4GuG9wp1dGL5pMaYKOqcDvMNsBi/4Cv669Lk4LnOij6kOPpB40mSRUApSaSXFd48r9ZfdR5gnzGrc/DvsZJcs9p/lOqOQqYrbHAJB+OR2TTiZq4Z+Tc4/w8LVkZ9/m/v0PyM6+UyRwBmNpOQALi5fUK/3Q0EWoVArS0s4TE/M1BQUJGBu3VQt3pTKXO3fewMHhbczMuhcJ3qr3Pwo6OjoaSntgYCDjxo3D0tJSoxdHdSCVSunWrRuZmZkaZb7L4u+/BUuAoOAIQvjhQ80gvi5dBJP7iRNCqeC5c4Xt/foJ/372mZAFUFFsdunzV4QHDwSlISpKKDG8Zg28+y788ktNlHdwdNS0AtSKBeDmzZscP35co8PZxIkTmTRpEkOGDHmijoBjxnTl+PErzJy5k1u3oujSxZOWLcv7t+3szPn443HMmLGD0aO70K1bM1auPMLmzZPKCCa7UivIu2zYcJKPPx5H8+aahUbsvEpMXFkpKXz5xhu0HTiQ3lM0c15FYjEzd+9mcdu2nNiwgWHLl3Nq0yb6vf22ulmQhs9zzBiuHD/Ozpkzibp1C88uXXCqB59iXUIkEjF//nymTZtWZxxyuZxevXrh7e3N7qIk25AalFsWiUTY2NigV+TeqQ7mzZvHr7/+yvXr19HT0yMtLa1GfMWrmIpWo6VTl54FjB8/Hl9fX2QyGSNGjFAX7bl16xYikYhu3boxbNgw/v33X44dO8aKFSvo2bMnb7zxhrqeQkPi79q1K1u3bq0V95lEJOILLy/6Xr9OVF4eX1fQLnyYlRVfx8TQ+/p1Nrq7Y6JTe57XJlObEL0tmgebHtCoYyPMe5sj0il564v1xLhvcifozSCsR1uT8H0CHv8rsSUbGLjj4rIUF5elZZ5hMa1bl4S4Gxm1xN19E+7umyq9ltDQpahUSlxd15YS4CZV7q/8XKFERkbSpUsXtaUtOzsbQ0NDdHV16dq1K7/99hv9+/evssBYWRSb/iMjI9XPhq0tODsLJnp7e0FwJiYKvnNLSyFtb9IkwadvZQU3bwo++jNnhM582dlCcN+rrwqr9F9+gW+/FXz0n30mZAZYWAgpg4WFQlrgl18+ysJeftuPP1b/uXjwQKhN8EgFjlUe1AAAIABJREFUq6YPnI+Pj7olcF1g27ZptGgxj2PHLnPtWuWrrmnTXuTgwYtMnfoVCxcOon//1piZVdwNKjMzlwkTttK9ezPmzh1QJf+OGTNQFhYyo5Jyvw7NmzNkyRKOrVmDc6tWpMXH41VRiaXi69y2jXktWnD52DE2VFWR4RnFvHnz2LJlC8nJyXXGcfnyZS5fvqzOja9qRVnWPaFUKgkODmb48OHV5lOpVGzdupXXXnutnNJQ0Qq2LOft27dp0aKFhmug9Auorrtn1jb279+v9sGXLiBUUFBAQkICV65c4c6dO+pS0SkpKZw6dYqQkJAaKWpPg18qlfLqq6/yRkUVUx4TnU1M8DUxIaWwEHElS67lLi70vHat1jMKRGIRnp958u8r/2I73havL8v7662GWhH9RTT/9v0X90/doQ6qCaelXSAqams503519xfj/PnzZGdnk5GRwbBhwzQUuMDAQDp2FKq8tmvXjrNnzxIYGFgji1pxXE3p4kJxcRUXABIUn5L/v/RS6essraxoRt9XlA1tXMqIXaqDdbUxbJjQR0BfX2go5OkppACqVEJsQvHnwkKhqZHwHqsDBaCuoaMjplkze/766zbHj1+ptKyvSCRix44Z+PjM59ChS5w9+36l53z33W9ITs7kzz9XVNlF7Ny+ffgfOcKikycxKeVHLouhy5YR8MMPfDl5Mp+VjQwpA7GODvbNmnH7r7+4cvx4jcsEN2RMmjSJgIAAbpWqP2loaFiucteTojhw7X//+x9OTk6EhYXxQ1HUzYULF4iLi1NX3ouJiSEwMFAd4LVr1y7EYnGNct9FIhHW1tacOnWKvXv3oqury49F6vetW7f4/PPPmVTKGffzzz8ze/ZsQAiQPHXqlIagKg1ra+vHalzSUHD+/HmNGAuVSlXOH1/RtobCv3jxYpYuXVqrz+jFtDRetrDgw7AwziQn81IFLr6TDx8y3c6OWcHBXOjQoVZlsGk3Uwy9DDHxNal0jOM8R+7OvotZ99pP51Mocqo07T9qf2l069atQh++UqkkKChIw91sZGREQEBAjRSA3KKKOKUDbBsqmjQRSv9KpTBtmqAA5OYKsQbDhsELL4CNjVBgqPTnGsnbhnTDKpWK+fP3ceDAbGbN2sXMmTvo0cMbc/OKCyy7ulrj6GhZzqRfGidOXGXPnj/Zt28Wjo6WlY57+OABu2fPptfkybQfNKhqs59UilfXroQEBGBoalrl/eybP5/ZBw6wa9YsdsyciXePHhjVogCQSCRPpR1zWcycOZOmTZsSHx9P//79kclkDB06lBUrVtS6AuDm5sbatWvZuHEjc+bMYe7cuRw4cID27dtz9epV5s2bpyFgv/zyS/T19UlOTkYul3PhwgV1adzqYseOHcyYMYPFixczatQoduzYQXh4OBEREfj4+GBcSqUPCgpi5syZFBQUEBcXx+nTpyttT2pqavpM5+Hn5eURGRmJj4+Pul3vs8I/efJkfvvtN3VKYW0gU6HgxMOHbHR3p1Cl4p27d7nZqRPSUguNr2NiGGNjg6u+Ph6XLrE/Lo4JtdxbQKwrrjKi61H7nwT37y9FpVKVM+0XFMQjk9lUub+6CAoKol+/fhp9IuLi4tiyZQtRUVHl+kdUhgcPHgAVu+caGmJjoSiTmNJVqHNyhOY+GRnCn6Oj5udnVgH46KNjjB3bDTs7c7Ztm4a391xmz97Nt9++81jnS0hIZ9q0rxg+3Jfx4zU1T3//EHXfAJVSyRcTJ2JsYcGk4hkvNl3Fx1OQm4vVYzwwxz76iG5jx2JuZ8e0bduY6+3N7tmzeaeCDnOPg5EjR9KnTx/MzMyYOHEiBw4ceKKMjOpixowZfFnkxFqwYEHJSujiRfUPrLZRUV+BhISECk18ZWvFPw769+9PREREmWem4lbUS5cuxb6yPJtypkBjDA0NnwlhX6xYlrWaubi40K9fP7UAriizorJsi8q6AdY1//Tp0ykoKODhw4c4Oztja2sr9Bd4wud1xf37LCnyK89zdGRnTAwbIyJYWvS+uJmVRVphIW2LFMZ1bm4sunePVy0tMatFd4BKqQLl4+9/XKSlnS8y7f+hYdpPSfFDJrMiJ+delfuri5CQEIaUsZ7a2tpiZWVFQEBAtRSAwsJCzp8/j4WFBS2fsVis4rpetW24aDAKwKFDQlGT3r1bAGBjY8onn0xg8uRtDBzYjtGju1TypSooLFRUovF/iVSqw1dfTStjklLy3XcX1ArAj5s2EXT+PB+eO4e+sWbGwalPPmFEBeZjRWEhykrSlAAuHToEQIui5iOmNjZM+OQTtk2eTLuBA2ulBsDhw4c5fPjwU/+uvvrqq2rlcmtRHvr6+o/dHvlpwtnZmRkzZgBCh77iGgxGRkaMGDGCvn370qJFC3r06IG1tTW9e/fmjz/+oH///ri6ujJu3DguXbpEUFAQIJRuHTp0KE2aNGHo0KHcuXNHoxJiXfK/9dZbfPHFF+U4OnfuLNRYfQxE5uXxXmgod7OzmVeU5vtQLsdKJmNlWBjmUilGEgnz791jZamof4CEggJG3LzJF15ewJO/0VP+SCEnOIek00mY9TRDz1EzbqUgoYDEY4nkx+aT9FMSlgMta+UZUank3LkzGT09B1JSzpCScqbonZxOQsIRunS5z+XLrSvd37VrJPCLWjiDEPBb1gUQHR1daaCfp6cn/v7+9O/fX22Vqyh9NDc3l8OHD5OTk8OUKVOqnQ5cX6hIRx44EP79t1g5LqssV+8c5cao6spZV01ERHzJunXH2bnTj4ULB/HBB8MxMNAlL0/Ohg0nWLnyCPr6MlavHsWbb/bFyEivSIPM4vjxK8yYsQMXFys2bRrPoEElkRy7d//JlCnbaNvWhTZtSlbvcrmCK1dC6dTJg927Z7I52IeFrVphbGFBm1INYVQqFfGhoSRHRbG1TBewy8eOsW/+fFJjY5m+fTsdhwzBwETwvz2MiOD4unX47dzJoIULGf7BB+gaGCDPy+PEhg0cWbkSmb4+o1avpu+bbzKhjMLxvKE2H78OHTqQkJBAZAU93esCCxcuZNOmTdy/f5+mZV7yleHMmTPY29trdLer3xeN6Pl+/sr2gH3K6Hu2niegni+gT58N/Pfff5w9e5aHDx/SuXNnOnbsqI77CQ8P59ixY4jFYl599VWNWhixsbEcO3aM6OhonJyceOWVV8jIyODMmTM8fPgQV1dXzMzM1I2ynJ2d6dq1q4YF7r2yFX8aAJychA6AvXrBp58KGQEWFkKzoldeEfL7X38dBgyA27c1PxcrCC1bCgWFfvpJSCMsXdugQSkAcKSe2UfUK//I5/0FXAuPX3R0NDt27GD9+vXI5XKWLVvGpEmTcHV1rZNrlsvlfPHFF3z66adERUUxcuRIZs+eTdcqskGK8ccff+Dk5FRn16ZVALQKwLOmANQnGqIC8FR//1oFQKsA/H+xAGihVQC0CoBWAdAqADVRAPr0UWl/APWHs/TVvoDqEb///pxLQC200OK5hbYdsBZaaKGFFlpoFQAttNBCCy200OJ5gDrfIkeh4MOwMM6lpSFXKrmTnU1eUdnTzF69MJJI+DY+nh0xMZxLTUVfLMbL0JBcpRJdsZihjRuz0NkZfbGY4OxsjiUmsio8nHylEic9PaxkMhIKCmhjbMx7zs74mmhWrVLkKAj7MIy0c2ko5Uqy72SrG1z0yuyFxEhC/LfxxOyIIfVcKmJ9MYZehihzlYh1xTQe2hjnhc6I9cVkB2eTeCyR8FXhKPOV6DnpIbOSUZBQgHEbY5zfcy5XNUuhyCEs7EPS0s6hVMrJzr6DUpkn8PfKRCIxIj7+W2JidpCaeg6xWB9DQy+UylzEYl0aNx6Ks/NCxGJ9srODSUw8Rnj4KpTKfPT0nJDJrIqaZ7TB2fk9TEx8Nfi181+/86+FFlpo8bxBHQPQ5/p1rGQy9nh7oysWkyyX82ZQEEcTE9UCCOBCWhrd/vmHtx0c2OrpiQrYHBnJvJAQepmZ4deunbrMZZ/r1/FLSeFhjx5YSqVE5+fz0vXrhObk8HObNvQ1N1e7gK/3uY7MSob3Hm/EumLkyXKC3gwi8WiiWgABpF1I459u/+DwtgOeWz1BBZGbIwmZF4JZLzPa+bVT17q+3uc6KX4p9HjYA6mllPzofK6/dJ2c0Bza/NwG877mah/09et9kMms8Pbeg1isi1yeTFDQmyQmHlULIBBqWv/zTzccHN7G03MroCIycjMhIfMwM+tFu3Z+FF/A9et9SEnxo0ePh0illuTnR3P9+kvk5ITSps3PmJv3VccAaOe/fuZfGwOghRZaPK8QA1zNyMAvJYVlLi7oFlUUsJBK+a5FCzzKlB4yLVOkQQTMdXSklbExf6am8ktSUqVj7XV1WevmhlylYmmpcpwZVzNI8UvBZZmLULISkFpIafFdCww8NPmL22WWvgDHuY4YtzIm9c9Ukn5JqnSsrr0ubmvdUMlVhC4txZ9xlZQUP1xcliEW6wr8UgtatPgOAwMPTX6dsqV/RTg6zsXYuBWpqX+SlPRLpWN1de1xc1uLSiUnNLSk+5Z2/ut3/rXQQgstnlsFILGom9n5MtUCZGIx46pZs7pFUXGF8KJmCzUZV5Ao8Kee1+QXy8TYjqsev2EL4by54bk1HldQkCjwp57X5BfLsLUdVz1+Q6GCYW5ueI3Haee/fudfCy200OK5VQB8TUwwkEiYffcua8PDKSyVmz3Cykq9Kq0K93JyAGhuZFT1uCLBU3qcia8JEgMJd2ffJXxtOKrCEn6rEVbqVWlVyLkn8Bs1r5o/915uuXEmJr5IJAbcvTub8PC1qFQlpSStrEaoV6VV8ucIXQGNjJpXzZ9bfpx2/ut3/rXQQgstnlsFwEIqZY+3NyJg2f37tAwI4KciU7KXoaFGZ6uK8FV0NFcyMhhgaUkvs8rbTcYXFLAkNBSpSMS6UiUdpRZSvPd4gwjuL7tPQMsAkn4S+A29DBFJq+aP/iqajCsZWA6wxKxX5fwF8QWELglFJBXhtq4Uv9QCb+89gIj795cRENCSpKSfilaMXohEVTftiI7+ioyMK1haDsDMrFfl/AXxhIYuQSSS4ua2Tr1dO//1O/9aaKGFFs8j1E7akdbWeBgYMC0oiH8yMng1MJC+5uZsb9YMlwqal/inpbHw3j0i8/IoVKn40suL6XZ2FZKsCgtDCYTl5NDJxIRDPj54lvFtW4+0xsDDgKBpQWT8k0Hgq4GY9zWn2fZm6LuU50/zT+PewnvkReahKlTh9aUXdtMr5g9bFQZKyAnLwaSTCT6HfDDwLMNvPRIDAw+CgqaRkfEPgYGvYm7el2bNtqOvX74TYFqaP/fuLSQvLxKVqhAvry+xs5teMX/YKkBJTk4YJiad8PE5hIGBp8YY7fzX7/xroYUWWjy3CgBAa2NjLnfowO7YWJbfv8/ZlBQ6XrmCf4cOuJURGJ1MTdno7l4tkg+aNsWyGq0vjVsb0+FyB2J3x3J/+X1SzqZwpeMVOvh3wMCtTDBcJ1PcN1aPv+kHTZFaVoPfuDUdOlwmNnY39+8vJyXlLFeudKRDB38MDNw0+U074e6+sXr8TT9AKn10By7t/Nfv/GuhhRZaPE8Qg2AaTpbLhQ0iEVPt7Aju3JnBjRuTJJez/P79Or2IgvgC5MkCv0gswm6qHZ2DO9N4cGPkSXLuL69j/oJ45PJkgV8kxs5uKp07B9O48WDk8iTu319ep/za+a/f+ddCCy20eG4VgIjcXPxSUjRXWDo6HPTxwVRHh8DMzDq9iNyIXFL8NPl1THXwOeiDjqkOmYF1zJ8bQUqKnya/jik+PgfR0TElMzOwTvm181+/86+FFlpo8dwqAAB74+LK7dQTi3HQ06NpBT7omnRxq87YuL3l+cV6YvQc9NBv+hT44/aW5xfroafngL5+0zrn185//c6/FlpoocVzqwD8kpTEnJAQshQK9c7v4uO5l5PDylK9y9MLhRSt1MLCR568JmOTfkkiZE4IiqwS/vjv4sm5l4PryhL+wnThXIWpjz5nTcYmJf1CSMgcFIqsEv7478jJuYer68qScxamF/2b+mj+GozVzn/9zr8WWmihxfMGkapPH1VAejqdrl4FwFAiwdvQkAKVisZSKWtcXXmhqG780tBQdsXGqgvXSEQi5jo6ssrVVV2DfktUFF9FR2Oio0OWQoFCpWKgpSVvNGnCUCurchfQ9yykB6RztZPALzGUYOhtiKpAhbSxFNc1rpi8IPAHvRlE3N44lPlCjXqTF0xouqopFi9ZAEI9+4h1EYR/FI5IIgIVqBQqLAda0uSNJlgNLc9P37Okpwdw9WongV9iiKGhNypVAVJpY1xd12Bi8kKRQPqWmJivSU39GwBdXTtkssbqPHWFIpesrP8QiaTY288gJmY7SmUBlpYDadLkDayshpajP0tfKpt/cx0dPA0N+S05WV24x1RHh7TCQowlEla6uqJSqfg8KooHeXmMsbFhvpMTBmIxR4t6ARQolUhFImbY2/OZp2eN5l9iJEHSSELyacE/L2ssQ8dUh5x7OUiMJbiudEVmKyPyk0gyrmVg0smEpu83Rc9Fj8SjRb0ACpSIpCLsZ9jj+ZnnY82/WCzl8uV2SKUWqFQFFBZmIhJJ0NW1o7Awg8LCNGxsRtOixXcARb0AjhIW9gEqlRJLy1do0mRKhfOvLQWshRZaPNcKQE0P2h8Xx4TbtzGTSont1g29UoVqzqelMSs4mHPt25crRVsRatoOPjc8l4CWASiyFHS+17lcdDoq+Nv6b1oebYlpN1Nq/QKAGzcG4+HxKfr6rhrb796dTVTUVlxdV+PiUr3AteJeAFUho7CQnteu8W9mJuvd3Fjs7Kyx/8Xr1xlrY8PkJk3KHXvi4UOG3LjBAienCrMGqnP7wW8HE/1lNDZjbWhxoEW5/ZGbI0k5m0Krk60Q6WjK04cnHnJjyA2cFjhVnDVQjQtITj5DcvKveHh8qrE9L+8B/v4tkEgM6dTpNlKphcb+y5dbk5V1ix49UtDRaVThubUKgBZaaPG84rHaAY+3tWWGvT2pcjnrIyLU23MUCt67d48TrVpVS/g/DvRd9HFbK6SEha8uX8414VACthNtqyf8HxNmZj3KCf/U1HNERX2BsXFbnJ3fq1W+Rjo6HGnZEkOJhI0PHpBUlDEA8E1sLC0MDSsU/gB9zM0xkkgYZW392PzuG9zRc9Qj4XACOSE5mvqWQkXCoQSa7WhWTvgDmPcxR2IkwXrU4/PL5ck4Oy+irKZ3585kFIosvLy+LCf8ARo3HoKFRf9Khb8WWmihhVYBeAxsdHfHUU+PdRERBGVnA/BWcDDznZwqLFxTm7B/255G7RsRtz+OtPNp6u2KbAWRWyJpuqJpnfLb2IzV+KxQZHPnzmREIh2aN9+DSFT7yo+rvj5r3dxIlsuZFxICwO3sbPbExZVb2StVKgbduMHrN29yNzubt+ztkYpEzA8JocOVK9zKyqoRt8RIgufnnqjkKoLfCtbYF7U1CuuR1ug2KSnXq1KquDHoBjdfv0n23Wzs37JHJBURMj+EKx2ukHWrZvzm5r2RyWw0tkVHf0VKyh9YW4/SMO0nJf3ElSsdiYraiqXly1hYvERCwkGuX3+RkJC52l+8FlpoocWTKgBGEgnbmzWjQKlkelAQO2NiMNLRqdDPX9sQiUU0294MkVhE0MwgVHLBixH2Ydj/tXfn0VHV9//4nzczk5kMSSYJJEP2PcQQEYQPi8ivHql6WrFgIaAU27LosQX9Bi3iVywBMRCKCFgsigsVi9Til+rx49HWICiLmiAQlsEMZJJM9oVsZLbMzL2/PzKELJMhGwwtz8c5niOZe+c19/1+vd/33vdd3ojJjOmYuvZ68fXtejZ78eJKWCwGJCT8Ef7+Y65b3GVRUbhLo8H7VVX4uK4Oi3U6vJuWBt9ucwVIAIrMZvxw+TL21tSgzm7Hlw0N+La5GT+aTGjoNILQV6G/CEXorFA0HGhA9QfVANrfH1C7rxbRT0V3PzmHuciMyz9cRs3eGtjr7Gj4sgHN3zbD9KMJ9gb7oMrbYinBhQvPwdc3DKmp23uMFpjNejQ0/Bv19V/AYilGQ8MBtLaehclUyBZPRHRlXzqQewA6+825c9hdVYV0f38cnzixTxPXdDaAS/Ad9Mv1MG41ImlDEkJnhkL/jB7jPh+HG/YDADQ2HsIPP9yLgICxmDgxr99n/325B6CzH00mjP3+e9glCX9NS8NjfZgtcPqJE/jkjjvgL5MNavNt5TYcSzsGmVqGuwrvQuGyQkQ8HoHg/y/Y43onpp/AHZ/c4f7ArN/lL+HEiZ+ioeErjBnzEcLCZve6ZH39Z2hp+QEJCat7XYb3ABARRwAGKCcpCTJBQJnV2vE2uxslcV0iVNEqFK8rxvnHzyPl1ZQbGr/z0H9a2vUZ+u8uddgwLI6IgChJON2Hofx9NTX4qqEBWUPwNkFllBKJ6xLRVtOGgpkFgIBr7vxr9tWg4asGFGUNzdsEy8t3uIb+53rc+QPAhQvPoaRkQ8d0w0RENIQHANklJZin1aLZ4cCywhs7xCrzlyH5T8lwmp1Qj1Jj2G3Dbmj8Cxeeg8VSjPj4VQgIuOOGxCyyWHDOZMJtw4Zhi9GIE9d4S6DMdYIb0oe5APoielk0hqUNQ+PXjUjMTrzm8oKsPb4iZPDxLZZiXLiwEr6+oUhNff3asQUZAAEKRQhbOhHRUB4A/KOmBk5Jwp70dEwPCcE/a2vxz9obe7bll9R+w6EiWHFD4zY2HkR5+Q4EBIxFfPwLNySmTRSxSKfDW7fdhjdvuw2iJOFxnQ5OD2+6S/f3BwCMCwgYkt8gyISO2QH7Uub+6e3xA8YNNr4EnW4xnM5WjBr1ep8m9/H3T4e/f/oNGZkhIrplDgD0ZjP+XFaGLSntw+47UlOh8vHBssLCjjfQ/bdyOluh0y12Df3/1e189SaTbsjj/p/CQjwZGYlktRrTgoKwMCICJy5fxhajsdd1kvz8oPLxQWK32QRv5AGaj8oH6sTBxS8r+wsaGw9Cq82AVpvR43OrtRROZ9dHFIcNS+/xuCYREQ3iAMDsdGLhuXN4Jy2t4yVAyWo1VsXHo9Jmw4oLF/6rC+3q0P8Lbof+7fYGNDTkDmnMPdXVEAE8OvLq43CbkpMR5uuL1UVFuGg2u69gQUCCnx+ilEqvlJXgI8AvwQ/KqIHHt1iKcfFi+9D/qFHuh/4rK9+Dj4+qy9/U6mSoVFFs5UREQ3EAYBFFPHr2LGaEhiKl21nlyrg4hPr64q2KCuy/QZcCOt4333xjRh0aGr5CefkbCAi4A/Hxq3p8LooWFBY+7XYCm4HKbWjAygsXOkZbrghRKPB/4+JgEUX86uxZ2ETR7fpRKhWGyWReK3NVlAqyYQONf+WFPyaMGrUdvr6hPZZobv4WjY0HIAhd09nXN5TX/4mIetGvi6NvVVQgp6QEBosFrU4n7gsJwYTA9resOSQJW43GjuH/X509i6eio7E8Jgbh1+nss+r9KlS8WQEAqP1nLYalD4N2jhbKyOt1tivh/PnFACTY7U04fnxat52/HRZLERyOZiQmrht0tItmM7JLSvBeZSVkgoC/lJfjD7GxuPLcWl5LCz6tr+/4/5/88AOei43t8S6GoTr7N503ofajWjR/3z7Jjn65HuG/DseIGZ6vxw/m7L+y8q9obDwEQZDBaHwVRuOrPUZbzOaLCA9/rGdyyzWQyQLYyomI3Bj0ewAGa5CP4f/H/4D+vgdgIFYVFSE7MdFrm1+0qqj3Jwau4w8wmy+iqekwIiIW9j66wvcAENEtyodF8N8vRO7du+DlId6JL5OpIJOpmQBERDwAuDUFevsAINA78QXBt8eNgURExAOAW4a/TObV+Nd7bobeDwDkPAAgIurt5IxF8N+v86OD3X153434BSOBd735A17p/aP7JC/fA3OfV3PD67fgeL11fHlLF8AtfguW18vf2/cgcQSAiIjoFsQDACIiIh4AEBEREQ8AiIiI6L9Sj5sAW51ObDUacaypCSOVSsgEAYEyGcYHBqLF4cBcrRb7a2uxXK+HBGBaUBAsoohWpxNLo6KwMCICerMZu6uqkF1cjAilEhMCA1FutWK4QoGshARMDQrq9Qc5W50wbjWi6VgTlCOVEGQCZIEyBI4PhKPFAe1cLWr310K/XA9IQNC0IIgWEc5WJ6KWRiFiYQTMejOqdlehOLsYygglAicEwlpuhWK4AglZCQia6iG+sxVG41Y0NR2DUjkSgiCDTBaIwMDxcDhaoNXORW3tfuj1ywFICAqaBlG0wOlsRVTUUkRELITZrEdV1W4UF2dDqYxAYOAEWK3lUCiGIyEhC0FBU3uN7+3y93r8Vie2bjXi2LEmjByphEwmIDBQhvHjA9HS4sDcuVrs31+L5cv1kCRg2rQgWCwiWludWLo0CgsXRkCvN2P37ipkZxcjIkKJCRMCUV5uxfDhCmRlJWDqVE/b34qtxq041nQMI5UjIRNkCJQFYnzgeLQ4WjBXOxf7a/djuX45JEiYFjQNFtGCVmcrlkYtxcKIhdCb9dhdtRvZxdmIUEZgQuAElFvLMVwxHFkJWZjqof69nf/eLn+vt//WVhi3bkXTsWNQjhwJQSaDLDAQgePHw9HSAu3cuajdvx/65csBSULQtGkQLRY4W1sRtXQpIhYuhFmvR9Xu3SjOzoYyIgKBEybAWl4OxfDhSMjKQtDUqTdx/+Pt/L+1y9+rBwBlVivuP3kSD40YgU/Hju2YS76mrQ0zTp3CzNBQhCgUWBIZiT3V1bCIIj4fNw4AsL64GIt0OjgkCY9HRmJdYiI2lJTgsfBw5CQlwS5JmFVQgOknTuD4xIkd09R2Zi2z4uT9JzHioREY++nYjrnk22racGrGKYTODIUiRIHIJZGo3lMN0SJi3Oft8YvXF0O3SAfJISFYnou9AAAgAElEQVTy8UgkrktEyYYShD8WjqScJEh2CQWzCnBi+glMPD6xY5raLvGtZTh58n6MGPEQxo791DWfPNDWVoNTp2YgNHQmFIoQREYuQXX1HoiiBePGfd4ev3g9dLpFkCQHIiMfR2LiOpSUbEB4+GNISsqBJNlRUDALJ05Mx8SJx+Hvn94jvrfL3+vxy6y4//6TeOihEfj007GQueq/pqYNM2acwsyZoQgJUWDJkkjs2VMNi0XE5676X7++GIsW6eBwSHj88UisW5eIDRtK8Nhj4cjJSYLdLmHWrAJMn34Cx49PRHq6u+0vw/0n78dDIx7Cp2M/hcxV/zVtNZhxagZmhs5EiCIESyKXYE/1HlhECz531f/64vVYpFsEh+TA45GPY13iOmwo2YDHwh9DTlIO7JIdswpmYfqJ6Tg+8TjS3dS/t/Pf2+Xv9fZfVoaT99+PEQ89hLGffgrB9fhsW00NTs2YgdCZM6EICUHkkiWo3rMHosWCcZ+72v/69dAtWgTJ4UDk448jcd06lGzYgPDHHkNSTg4kux0Fs2bhxPTpmHj8OPzT02/C/sfb+X9rl79XLwFIAOafPYsguRwbk5M7On8A0Pr6Yv+YMWh1Ojv+pvTpevXgmdhYyAQB71ZWAgAEAIpO36EQBGTGxMAmithTXd3zl0jA2flnIQ+SI3ljckfjBwBfrS/G7B8DZ+vV+D7KrvFjn4mFIBNQ+W57fAiAoLj6HYJCQExmDESbiOo9buJDwtmz8yGXByE5eWNH5QOAr68WY8bsh9PZejW+T9f328fGPgNBkKGy8srzbkKXaYIFQYGYmEyIog3V1Xvcbb5Xy9/r8SVg/vyzCAqSY+PG5I6dDwBotb7Yv38MWjvVv7Jb/T/zTCxkMgHvuupfEABFp/pXKARkZsbAZhOxZ4+77Zcw/+x8BMmDsDF5Y0fn1779Wuwfsx+tnepf2a3+n4l9BjJBhndd9S9AgKJT/SsEBTJjMmETbdjjpv69nf/eLn+vt39Jwtn58yEPCkLyxo0dO5/2+FqM2b8fztZO7b/b/BqxzzwDQSZD5bvvXmnwEBSd2r9CgZjMTIg2G6r37LkJ+x9v5/+tXf5ePwD4prERR5qasDAiAu4eTIxWqTCn2yQznV1ZJ8DDS2c8LdP4TSOajjQhYmEE3P0AVbQKYXN6j39lHVmAbEDLNDZ+g6amI673xvf8ASpVNMLC5uBaX+558pnel/F2+Xs9/jeNOHKkCQsXRsDdk7HR0SrM8VD/V9YJ8FD/npb5pvEbHGk6goURCyG4KYFoVTTmeKj/K+sEeKh/T8t4O/+9Xf5eb//ffIOmI0cQsXAh3BWAKjoaYXM8tH/XOrKAgAEt4/3+x9v5f2uXv9cPAD6/dAkAMN5DAV6Z+c+d9SUlcEoSlkZHu/3cKorYVFoKjVyOBeHhPT6/9Hl7/IDxvccPnNB7/JL1JZCcEqKXuo8vWkWUbiqFXCNH+AI38S997uqcxvceP3BC7/FL1kOSnIiOXuo+vmhFaekmyOUahIcv6PG5t8vf6/Fd9T/eQ/1P8FD/69eXwOmUsLSX+rdaRWzaVAqNRo4FC9xt/+eu7R/vYfsneNj+9XBKTiztpf6tohWbSjdBI9dggZv693b+e7v8vd7+XUPJAeM9tP8JHtr/+vWQnE5EL+2l/VutKN20CXKNBuELFtyE/Y+38//WLn9v6bgHoNxqBdA+x3xfVdlsHdMD20QRB8ePxz3BwV2WyWtuRnZxMc6bTEhRq7EjNRUxqp6vZ7WWt8dXhPQ9vq3KhpKcElgMFog2EeMPjkfwPV3jN+c1ozi7GKbzJqhT1EjdkQpVjJv41nLXUGXf54+32apQUpIDi8UAUbRh/PiDCA6+p2v85jwUF2fDZDoPtToFqak7oFLF9Pgub5e/1+O76j+kH/VfVWVDTk4JDAYLbDYRBw+Oxz3d6j8vrxnZ2cU4f96ElBQ1duxIRUyMu+0vd21/SD+2vwo5JTkwWAywiTYcHH8Q93Sr/7zmPGQXZ+O86TxS1CnYkboDMW7q39v57+3y93r7L3e1/5B+tP+qKpTk5MBiMEC02TD+4EEE39Ot/efloTg7G6bz56FOSUHqjh1QxcTchP2Pt/P/1i5/rx8AqF3Dspc7Xee9lnClEs/HxXlcZqJGg1Xx8df8Lpm6Pb7zct/jK8OViHvec3zNRA3iV/UhvmvWOKfzct/jK8MRF/e85/iaiYiPX3XN7/J2+Xs9vqv+L/ej/sPDlXj+GvU/caIGq1b1ZfvVru2/3I/tD8fz16j/iZqJWNWH+vd2/nu7/L3e/tWu9n+5H+0/PBxxz1+j/U+ciPhVq/4D+h9v5/+tXf7e0nEJ4C6NBgBwoqXFKz9Ec1d7/JYTXoqvuas9fssJr8T3dvl7Pb6r/k+c8Nb23+Xa/hO3ZP57u/y93v7vcrX/E16qf6/3P97O/1u7/L1+ADBXq0WUUont5eVwupkfRZQk7HV39/4Q0c7VQhmlRPn2ckjOnvElUUL13usYXzsXSmUUysu3Q5J6noVIkojq6r3XLb63y9/r8edqERWlxPbt5XC6qX9RlLB37/Xc/rmIUkZhe/l2ON3UvyiJ2Hsd69/b+e/t8vd6+587F8qoKJRv3w7JzSiYJIqo3rv3v7j/8Xb+39rl7/UDALVMhn1jxqDQZMK8M2dQ09bWsVCTw4E1BgOmd7o+YxNFWDwMF0sA7JLkcZmuQ0AyjNk3BqZCE87MO4O2mqvxHU0OGNYYEDL9anzRJsJp8fDdEiDZJc/LdBsCGjNmH0ymQpw5Mw9tbTVX4zuaYDCsQUjI9E4dog1OpwWefoAk2a+xzFXeLn+vx1fLsG/fGBQWmjBv3hnUdKr/piYH1qwxYHqn+rfZRFg81K0kAXa75HGZrtuvxr4x+1BoKsS8M/NQ06n+mxxNWGNYg+md6t8m2mDxULcSJNglu8dlbqb893b5e739q9UYs28fTIWFODNvHtpqOrX/piYY1qxByPRO7d9mg9PioW4lCZLd7nmZm6r/8Xb+39rl7y1dXgQ0WaNBweTJeMlgwKS8PIT5+iJWpUKSWo0VsbEIUSjQYLdjX20t8ltaYBNFbC8rw+ywMIR3ei5TbzZjV2UlREnCx3V1mKTRIEOr7fJcuNthmMkaTC6YDMNLBuRNyoNvmC9UsSqok9SIXRELRYgC9gY7avfVoiW/BaJNRNn2MoTNDoMy/Gp8s96Myl2VkEQJdR/XQTNJA22Gtstzwe6HgSZj8uQCGAwvIS9vEnx9w6BSxUKtTkJs7AooFCGw2xtQW7sPLS35EEUbysq2IyxsNpTKq3cWm816VFbugiSJqKv7GBrNJGi1GV2eC3XH2+Xv9fiTNSgomIyXXjJg0qQ8hIX5IjZWhaQkNVasiEVIiAINDXbs21eL/PwW2Gwitm8vw+zZYQjvVP96vRm7dlVCFCV8/HEdJk3SICND2+W5dPfbPxkFkwvwkuElTMqbhDDfMMSqYpGkTsKK2BUIUYSgwd6AfbX7kN+SD5tow/ay7ZgdNhvhnepfb9ZjV+UuiJKIj+s+xiTNJGRoM7o8F30z5r+3y9/r7X/yZEwuKIDhpZeQN2kSfMPCoIqNhTopCbErVkAREgJ7QwNq9+1DS34+RJsNZdu3I2z2bCg7Pdli1utRuWsXJFFE3ccfQzNpErQZGV2eS785+x9v5/+tXf7eIEg//amX50P3cgl4+Qd8eRPMiO7lAril6/++L++7tYv/Vk/A+9j8buXyz829xlnRjboEQERERLcOtwcAFTYb/lRaCvmBAwg+dAjvVFai2eHosdyhxkY8cuYMhNxcCLm5yNTrUW+3AwC+b27G1Px8BB86hA0lJTD34/EyW4UNpX8qxQH5ARwKPoTKdyrhaO4Zv/qDahyOPIxcIRf5U/PRdLip4zNLiQUFDxfggOwACp8uhK3S1q+CsdkqUFr6Jxw4IMehQ8GorHwHDkez22VPn87A0aNJKCh4GKdPz8Hp03Nw6tSDyM0V8O23oyGK/YutN5ux8sIFKL/6CkJuLh44eRLnTCYAQInFgiU6HeQHDmBZYSEMbq5x9bX+hjLmoNfXm7Fy5QUolV9BEHLxwAMnce6ca/0SC5Ys0UEuP4BlywphMPRc/7vvmjF5cj4EIRcjR36DDz64esOY2ezEqlVFEIRc/PznJ3H8uPs7zQ81HsIjZx6BkCtAyBWQqc9Evb3elc/fY2r+VAQfCsaGkg0wO81uvyPjdAaSjibh4YKHMef0HMw5PQcPnnoQQq6A0d+Ohq2PuTDQ3BZtIip3VXasa3jJAEtR365DfvBBNSIjD0MQcjF1aj4Od4pZUmLBww8XQCY7gKefLkRlp5jNzQ688kopIiLa142PP4ovv2zoKPtXXzVCEHLxs5+d7PKdQ7XNVqMV5359DrlCLnKFXJS+Utqlv6j+oBoHhx3EsdRjqN1f22t80WaDYe1afKVUIlcQoFu0COaLF69u57ff4tu0NBzSaFC6eTPETvfJAIDp3Dl8pVTixH334fScOR3/HY2PR64goOr99/vVD5SVvY6vvx6OU6ce6uhXTp+eg4MH/fHVV2qYzfqe2yDaUFm5C4cPRyI3V4DB8BIslqI+xxxI/urNeqy8sBLKr5QQcgU8cPIBnDOdc7X9EizRLYH8gBzLCpfBYDF4jH86IwNHk5JQ8PDDHeV36sEHkSsI+Hb0aIi2nvGbv/sO+ZMnI1cQ8M3Ikaj+4IOOz5xmM4pWrUKuIODkz3+OluPHr1kGA+3PB1Jf3iZ398dIpRLPxcbi7YoKjFKrsTgiwu3K9wQH457gYEQoldhiNGJCQABGuK6zTNJoMMLXF4dSU3FHQP9efaiMVCL2uVhUvF0B9Sg1Iha7jz9y/kiok9XIn5IPvzg/BE27OsuXX5wfQu4NgWayBnEr4/pdMEplJGJjn0NFxdtQq0chImJxr8uqVNFIT38fPj6qTju0TAiCHKNHv9fjvdHXkqJWY2NyMqYEBeGXBQWIVioxetgwAECcnx9iVCq8kZqKJZGRGEz9DWXMQa+fosbGjcmYMiUIv/xlAaKjlRg92rV+nB9iYlR4441ULFnifv3JkzX497/HIT39O/j4tN/VfoVaLcMjj2hx8mQLPvtsHHobdLsn+B7cE3wPIpQR2GLcggkBEzBCMcKVz5MwwncEDqUewh0Bd/RajtGqaLyf/j5UnXIhU58JuSDHe6Pf6/EO9d4MNLd9lD6IWBiB5m+bUb23GgmrE/qcd/Pnj0RyshpTpuQjLs4P0zrFjIvzw733hmDyZA1Wdoup0cjxhz/EYvbsMEyYkAelUsC99wZ3lP2ECQFYsCAc778/+rpssypGhdG7R8PR4kDdJ3UI/UUo5JqrXZs2Q4vSzaW488s7Pb5oyEepREJWFuQaDfTLl0MzZQrUSUlXt3PKFAwbPRppb7/d8dhaZ2319Ri9eze08+Z1Ojgx4rvbb0fozJkIf+yxfvUDomjCxIk/wM/v6vbW1X2C2tr/h5SULVCrU3pug48SEREL0dz8Laqr9yIhYXW/Yg4kf1PUKdiYvBFTgqbglwW/RLQyGqOHjXa1/TjEqGLwRuobWBK55JrxVdHRSH//ffh0elmYPjMTglyO0e+912MOAKD93oFx//43vktPB3x8oJ07t+MzmVoN7SOPoOXkSYz77DOgDyPuA+3PB1JfN+UIwBW+gtBj0hd3NiYnY0JgIFZevNhxprmptBRztdp+7/w7E3yFHpN+dBf4P4GIWR6Dmr/XoCXv6pmds9WJhi8bEPuH2EEVkCD4XnMHPmLEjC7J0tj4NYzG1xAXt9Lj6yOvZVZoKJ6OicGuqip819w++nCsuRnVbW297kgHUn9DGXPQ688KxdNPx2DXrip8951r/WPNqK5u63Xn35ELgXLs2JGK0lIrtm0zdvksJ6cEb755W1/aPzYmb8SEwAlYeXElml2jPptKN2Gudq7HnT8AzBgxo0vn+XXj13jN+BpWxq30+CrVoc5tH1+fa7Ydd/7nfwKxfHkM/v73GuR1itna6sSXXzbgDx5ixsf74Z130lBYaMarr7aX/6VLdvzpT6XYufO2677NqX9JhTxQDv2zXc+0yl4vQ/yL8X1+y2D0008jcOJEGNasgaPTezFafvgBqqgotzt/ABDkcoTOmnX1D5IE3aJFEBQK3Pbmm/2ui4CACV12JnZ7Pc6ffwJBQdMQHf20547dx7ffJx6Dzd9ZobPwdMzT2FW1C981f+dq+8dQ3Vbdp50/AIyYMaPLzr/x669hfO01xK1c6fFVwPLAQKTu2AFraSmM27Z1+awkJ6e9/Pt4uX2g/flg6uumPABwZ8HZs5h35kyXvykEAbvS0lBvt2PFhQs43NSEEosFvxo5csh/8NkFZ3FmXtf4CWsToIpR4fwT5yE52u9pNKw1IP7F+C6zig0FSbLj6NFElJf/peNvISH3Xu2onK3Q6RbC3/92xMevHnS89YmJiFepsESnQ4XNhuziYmxO6XkkubOiAnFHjsAmijcsprtc6M/6vcZfn4j4eBWWLNGhosKG7OxibN7sJv6Cs5jXLRcefHAEMjK0yMoyoLS0/fWyn35ah3HjAhAdrepTfIWgwK60Xai312PFhRU43HQYJZYS/Grkr9yUwQLMO3P1jO/eTrnQ6mzFQt1C3O5/O1YPMBf6ktutp1vxdcjXuHzy8pDk+Nq1CYiJUeGJJ87D4Yq5dq0BL74Y3zFL4M6dFYiLOwKbTexxAPfooyORlVWECxfMePLJ89i8OQV+fj5Dus0VOytwJO4IxE7xlRFKJG1IQv3/1qP2o/ahflulDc3fNyPs4bC+H/T7+CDtrbfQVluLohdeaG/3oojideuQsHbt1UttO3fiSFxcx7B00NSpXc5Qy15/HQ0HDiD19dfhq9X2ux469ysAcP787+B0mjB69C4IwtXyrKjYiSNH4vp9qdGdvubvzoqdiDsS1+OSwPrE9YhXxWOJbgkqbBXILs7G5pTNfd/mezv1pa2t0C1cCP/bb0f86q7xu5c9AIx48EFoMzJgyMqCtbS0/Qz8008RMG4cVL3MUXKtcvfUn589uwBnOrX9vtbXf/QBQLhSiQg3wzDp/v54MT4eb1dUYHVRUb86/H4NzYcroYzoGl+mliH1L6m4XHAZxi1GtJ5uhWgTETgx8Dr8AhlUqphe3xmt1z8Lq7XcNVTkO+hoapkM76SlQWcyYWp+PrakpMDPzVl9sFyOWD8/yIfgptK+xuwtF/q6fq/x1TK8804adDoTpk7Nx5Yt7ncg4eFKRET0jP/aa6OgUAj4/e9/hNnsxFtvVSIzs3/v3073T8eL8S/i7Yq3sbpoda+dWLgyHBFK95dYntU/i3JrOd4b/R58B5gLfcltH7UPVLEqyIbJhiTD1WoZ/vKXVBQUXMaWLUacPt0Km03ExE4xg4PliI31g1zeM9/+/OdRCAiQY8qUfDz8cBhGjVIP+TbLg+Xwi/WD0C1+5JOR0EzRoPDpQjhaHLj4wkUkrU/qdxn4jxmDmGeeQfmOHWj+/ntUvPEGRj76KOSBnX9DMPxiYyHIe15JtRQV4eLKlQibM6fLJYGBqq7ei9raj5Cc/Cf4+SV2PfuVB8PPLxaCIB/Sns5T/gbLgxHrFwt5t5hqmRrvpL0DnUmHqflTsSVlC/x8/AYUX//ss7CWl7cP/ft2jd9b2Y967TUICgV+/P3v4TSbUfnWW4jJzBxwGXjqz5XKcCh7afue6utm0u+M2ZSc3Otnz8fFYZvRCKPVClG6Pk8XJm9yH3/4z4ZD+4gWhjUGNBxowO1/v/26xBcEH4wff9DtZ5cu/QsVFTuRkLAWAQFjhyzmT4KDMSM0FF/U1/d6hp+h1SJjAGcZg4npKRf6sr7H+D8JxowZofjii/oeZ5kd8XvJhZEjfZGTk4wnnzyPBx44iZycJLc7qmt5Pu55bDNug9FqhCj1Vgab3P79X5f+hZ0VO7E2YS3GDjIXrpXb6iQ1Jp2cNKR5/rOfDccjj2ixZo0BBw404O/dYmZkaJGR4T7fhg9XYOXKODz7rL5fcwv0Z5u1GVpo3cQXfATctvM2fH/n9zj181MY8eAI+MUPbAeUuGYNaj/6CLpFi+Cfno7bP/yw22/IgDYjo+cooSji3G9+A5m/P27bsWPQdWGzVaGwcBlCQu5FVNTvenyu1WZAq80Y0vq/Vv5maDOQ0UvMnwT/BDNCZ+CL+i/6fNNrj770X/9Cxc6dSFi7FgFje8bvrex9R45Eck4Ozj/5JE4+8ACScnLcHqD16Tdcoz9P7qXtX6u+/qNHADzZajTiyagolFiteLGo6IZvTMorKXCandBM1kAeJL+hsR2OJuh0ixEQcCfi418Y0u8+1tyMSKUSob6+WKzTuX1V71AbbMxBr3+sGZGRSoSG+mLxYp3b19N68sQTkUhJUUMmEzB1atAA83krnox6EiXWErxY9GKf12tyNGGxbjHuDLgTLwxRLngjt195JQVmsxOTJ2sQ1I+Yly7ZcfRoE372s+F47rkLKC+33dBt9k/3R8RvItCc1zyoe4B8/PyQ+NJLMOl0iPpd3zty4+bNaDp6FKk7dkAxYsSg6+H8+cchinakpb0Ld3PVD7XB5u+x5mOIVEYi1DcUi3WL3b5a2GNf2tQE3eLFCLjzTsS/0P/4kU88AXVKCgSZDEFTp97w/vxG19dNcQBwuKkJNW1teDkxEcuiorCtrAx5N3hiGcXw9pt8fFQ3/npLYeFTsNvrMHr0e0M6FFfX1oZNJSXYlpKC11NTkd/Sgi1G43XdlsHGHPT6dW3YtKkE27al4PXXU5Gf34ItW/q3zYIABAcroBpgLhxuOoyathq8nPgylkUtw7aybchryevTuk8VPoU6ex3eG/1ejyHS/6TcHu6K2Z8ylCRg2bIf8coryXjzzdsgihJ+97vzN3ybFcMVEHyEa77979rfM9z1G/p2/4hJp0PRH/+IkfPnI+yXvxx0HVRWvoP6+s+QkrIZKlXsDan3weRvXVsdNpVswraUbXg99XXkt+Rji3FL//rSp56Cva4Oo997b2Bn74IARXBwn+tsKPtzb9SX1w8Aatra8EppKdYntl/ryE5KQrRSiUXnzqFtCG5Ku9nV1X2Cqqq/ISFhLfz907t8ZrUa0dx8bEDfK0oSlhYW4tWUFPj6+GBWaChmh4VhdVERLprN12VbBhtz0OuLEpYuLcSrr6bA19cHs2aFYvbsMKxeXYSLF803pD5r2mrwSukrWJ+43pXP2YhWRmPRuUVoE9s8rvtJ3Sf4W9XfsDZhLdK75YLRasSxAebCf4qXXy7G3LlaxMf7ITpahQ0bkvC//1vf5b0M/60khwPnfvMbKEJCMOrPf+7xeX8ns7FajdDrn8Hw4Q8gMvLxnnla8+GQb8Ng8leURCwtXIpXU16Fr48vZoXOwuyw2VhdtBoXzRf71pd+8gmq/vY3JKxdC//0bn2p0YjmY9e//Qy0P/dGfV3XAwCbJMHebeg2U6/HssLCjn+3Op149MwZbHF1+ADgL5Nhc0oKzplM+OMgLgVINgmSvWt8faYehcsK3SdgW/vBhmgbuoMOSbJBkuyd/u3E8ePTUFXV/lKPK496aDSTEBu7ovvaMBiy4OeXPKDYy/V6zAoNRbzf1WuYr40aBSeA3+p0cHSqm73V1bj7+PEu19vd1d9QxuyeC/1d32385XrMmhWK+E7XbV97bRScTuC3v9V13JUOAJmZeizrJRcAoK1N7PX+gd60Olvx6JlHsSVlS8eNT/4yf2xO2YxzpnP4Y9Efu7WHTCwrXAYAqLfX44nzT2CSZhJWdMsFCRKyDFlIHmAueMpts96M78Z8B5PrxUlXluvedvqrzRXTXRnu3VuNu+8+3uWzjz6qRUWFFQ93uuP+97+Pwpgx/njqqcJ+XwrwtM3Ve6tx/O7jvbZ1sc21/YO8WnblZT/uXkBTvXcvjt99d8dnxevXo+X4cdy2cycUISE9RgYunzzZn54HOt0iAALS0t52c6b5147uu7p6L44fv7vLUwCi2LXf6ov+5O/e6r24+/jdXa7xL9cvx6zQWYj3i+/U9l+DE078VvdbOCTPLyOz19fj/BNPQDNpEmJXrOgxtGTIyoKf676j7mXvrt56+8zjb+hHf67XZ6LQ1fb7U183E7djGxU2Gz6sqYHBYsElux07KyowT6uFRi5Hpc0Gu2sns7uqCmsNBlTabMhvaUGCq9NvcTg6ngHfVFoKqygiMyamy07B44FHhQ01H9bAYrDAfsmOip0V0M7TQq6Rw1Zpg2jv2ehN50wo31nefqT1YQ2GpQ1ze5NQX9lsFaip+RAWiwF2+yVUVOyEVjsPPj4qWK1G2O2XXEmwHG1ttVCponH69OzOKQiT6Uc4HM1IS9vVz+HnJmQVFeFgYyNWyeUwO51Qy9rv8P7i0iUIAI42NeEXp05hVXw8pgYFocFuh9FqhUOSUO+h/oYyZudcGMj6XeIfbkJWVhEOHmzEqlVymM1OqNWu9b+4BEEAjh5twi9+cQqrVsVj6tQgVFbaYHeTC7W1bfjHP2pw7pwJCoWAt96qwJw5YQgO9vwc+O6q3VhrWItKWyXyW/KR4JfgyueWjueaN5VuglW0IjMmE/F+8ai0VcIu2js6wNq2WkSrojG7Uy6IEPGj6Uc0O5qxq5+50JfcdrY6YS2zwtHqgGgTUfOPGtR/Vg9HiwOGLAPCfx0Ov8T+3Qh37pwJO10xP/ywBmlpw7rc9NfQYIfRaIXDIaGy0oING0rwzjuVmDkzFCUlFsTFtcf75psmWCwiGhrs+OlPf8Dq1QmYP3/koLfZ3mCH1Whtf0yw04Mgkiih5u81qPtnHSRRQtGLRQj/bTjUyep+l3vDV1+hbPv29rPfrVvbrynffXen39AAq9EIyeGAqbgYxS+/DNmwYah4+21UvH11J+C8fBlNx44h5dVX+zGU/C4aGg5ApQyY01cAAALaSURBVIrFjz8u69Y3VaGlJQ9TpuhcO60GWK1GSJIDogjU1PwD9fWfweFogcGQhfDwX/fpTvT+5G+DvQFGqxEOyYG8pjxkFWXhYONBrJKvgtlphlqmdrX9LyBAwNGmo/jFqV9gVfwqTA1yf11ev3w52mproYqOxunZszsPC8L0449wNDcjbdeuHmWPTk8itdXWouYf/4Dp3DkICgUq3noLYXPmQBEc3Kdy709/brNVQnS1/f7U182EkwFxMiB4uQBu6frnZEC3eAJyMqBbuvw5GRARERHxAICIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIbj3/P0LPxblRt5WvAAAAAElFTkSuQmCC\\\"}],\\\"materials\\\":[{\\\"doubleSided\\\":false,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[1,1,1,1],\\\"baseColorTexture\\\":{\\\"index\\\":0,\\\"texCoord\\\":0},\\\"metallicFactor\\\":0.4,\\\"roughnessFactor\\\":0.5}},{\\\"doubleSided\\\":true,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[0,0,0,1],\\\"metallicFactor\\\":1,\\\"roughnessFactor\\\":1}},{\\\"doubleSided\\\":true,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[1,1,1,1],\\\"metallicFactor\\\":0.4,\\\"roughnessFactor\\\":0.5}},{\\\"doubleSided\\\":true,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[0,0,0,1],\\\"metallicFactor\\\":1,\\\"roughnessFactor\\\":1}},{\\\"doubleSided\\\":true,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[0,0,0,1],\\\"metallicFactor\\\":1,\\\"roughnessFactor\\\":1}},{\\\"doubleSided\\\":true,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[1,0,0,1],\\\"metallicFactor\\\":1,\\\"roughnessFactor\\\":1}}],\\\"meshes\\\":[{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":0,\\\"TEXCOORD_0\\\":1},\\\"material\\\":0,\\\"mode\\\":4}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":0,\\\"TEXCOORD_0\\\":2},\\\"material\\\":0,\\\"mode\\\":4}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":3},\\\"material\\\":1,\\\"mode\\\":6}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":4},\\\"material\\\":2,\\\"mode\\\":6},{\\\"attributes\\\":{\\\"POSITION\\\":4},\\\"material\\\":3,\\\"mode\\\":3},{\\\"attributes\\\":{\\\"POSITION\\\":5},\\\"material\\\":3,\\\"mode\\\":1}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":0,\\\"TEXCOORD_0\\\":6},\\\"material\\\":0,\\\"mode\\\":4}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":0,\\\"TEXCOORD_0\\\":7},\\\"material\\\":0,\\\"mode\\\":4}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":8},\\\"material\\\":4,\\\"mode\\\":1}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":9},\\\"material\\\":5,\\\"mode\\\":1}]}],\\\"nodes\\\":[{\\\"mesh\\\":0,\\\"translation\\\":[-0,-33.4142,-33.4142]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-36.2426,-33.4142]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-39.0711,-33.4142]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-33.4142,-36.2426]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-36.2426,-36.2426]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-39.0711,-36.2426]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-33.4142,-39.0711]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-36.2426,-39.0711]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-39.0711,-39.0711]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-34.8284,-32]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-34.8284,-34.8284]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-37.6569,-34.8284]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-40.4853,-34.8284]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-32,-37.6569]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-34.8284,-37.6569]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-37.6569,-37.6569]},{\\\"mesh\\\":0,\\\"translation\\\":[-0,-37.6569,-40.4853]},{\\\"mesh\\\":1,\\\"translation\\\":[-1,-34.8284,-32]},{\\\"mesh\\\":1,\\\"translation\\\":[-1,-37.6569,-34.8284]},{\\\"mesh\\\":1,\\\"translation\\\":[-1,-34.8284,-37.6569]},{\\\"mesh\\\":1,\\\"translation\\\":[-1,-37.6569,-40.4853]},{\\\"mesh\\\":2,\\\"translation\\\":[-2,-34.8284,-32]},{\\\"mesh\\\":3,\\\"translation\\\":[-2,-36.2426,-33.4142]},{\\\"mesh\\\":2,\\\"translation\\\":[-2,-34.8284,-37.6569]},{\\\"mesh\\\":3,\\\"translation\\\":[-2,-36.2426,-39.0711]},{\\\"mesh\\\":2,\\\"translation\\\":[-2,-37.6569,-34.8284]},{\\\"mesh\\\":3,\\\"translation\\\":[-2,-39.0711,-36.2426]},{\\\"mesh\\\":2,\\\"translation\\\":[-2,-33.4142,-39.0711]},{\\\"mesh\\\":3,\\\"translation\\\":[-2,-32,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-2,-36.2426,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-2,-34.8284,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-2,-39.0711,-39.0711]},{\\\"mesh\\\":3,\\\"translation\\\":[-2,-37.6569,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-3,-34.8284,-32]},{\\\"mesh\\\":3,\\\"translation\\\":[-3,-33.4142,-33.4142]},{\\\"mesh\\\":2,\\\"translation\\\":[-3,-34.8284,-37.6569]},{\\\"mesh\\\":3,\\\"translation\\\":[-3,-33.4142,-39.0711]},{\\\"mesh\\\":2,\\\"translation\\\":[-3,-37.6569,-34.8284]},{\\\"mesh\\\":3,\\\"translation\\\":[-3,-36.2426,-36.2426]},{\\\"mesh\\\":2,\\\"translation\\\":[-3,-33.4142,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-3,-32,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-3,-36.2426,-33.4142]},{\\\"mesh\\\":3,\\\"translation\\\":[-3,-34.8284,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-3,-39.0711,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-3,-37.6569,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-4,-34.8284,-37.6569]},{\\\"mesh\\\":3,\\\"translation\\\":[-4,-36.2426,-36.2426]},{\\\"mesh\\\":2,\\\"translation\\\":[-4,-37.6569,-34.8284]},{\\\"mesh\\\":3,\\\"translation\\\":[-4,-39.0711,-33.4142]},{\\\"mesh\\\":2,\\\"translation\\\":[-4,-37.6569,-40.4853]},{\\\"mesh\\\":3,\\\"translation\\\":[-4,-39.0711,-39.0711]},{\\\"mesh\\\":2,\\\"translation\\\":[-4,-33.4142,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-4,-34.8284,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-4,-36.2426,-39.0711]},{\\\"mesh\\\":3,\\\"translation\\\":[-4,-37.6569,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-4,-39.0711,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-4,-40.4853,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-5,-34.8284,-37.6569]},{\\\"mesh\\\":3,\\\"translation\\\":[-5,-33.4142,-36.2426]},{\\\"mesh\\\":2,\\\"translation\\\":[-5,-37.6569,-34.8284]},{\\\"mesh\\\":3,\\\"translation\\\":[-5,-36.2426,-33.4142]},{\\\"mesh\\\":2,\\\"translation\\\":[-5,-37.6569,-40.4853]},{\\\"mesh\\\":3,\\\"translation\\\":[-5,-36.2426,-39.0711]},{\\\"mesh\\\":2,\\\"translation\\\":[-5,-33.4142,-33.4142]},{\\\"mesh\\\":3,\\\"translation\\\":[-5,-34.8284,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-5,-36.2426,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-5,-37.6569,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-5,-39.0711,-33.4142]},{\\\"mesh\\\":3,\\\"translation\\\":[-5,-40.4853,-34.8284]},{\\\"mesh\\\":1,\\\"translation\\\":[-6,-34.8284,-32]},{\\\"mesh\\\":1,\\\"translation\\\":[-6,-37.6569,-34.8284]},{\\\"mesh\\\":1,\\\"translation\\\":[-6,-34.8284,-37.6569]},{\\\"mesh\\\":1,\\\"translation\\\":[-6,-37.6569,-40.4853]},{\\\"mesh\\\":4,\\\"translation\\\":[-7,-34.8284,-32]},{\\\"mesh\\\":4,\\\"translation\\\":[-7,-34.8284,-34.8284]},{\\\"mesh\\\":4,\\\"translation\\\":[-7,-37.6569,-34.8284]},{\\\"mesh\\\":4,\\\"translation\\\":[-7,-40.4853,-34.8284]},{\\\"mesh\\\":4,\\\"translation\\\":[-7,-32,-37.6569]},{\\\"mesh\\\":4,\\\"translation\\\":[-7,-34.8284,-37.6569]},{\\\"mesh\\\":4,\\\"translation\\\":[-7,-37.6569,-37.6569]},{\\\"mesh\\\":4,\\\"translation\\\":[-7,-37.6569,-40.4853]},{\\\"mesh\\\":1,\\\"translation\\\":[-9,-34.8284,-32]},{\\\"mesh\\\":1,\\\"translation\\\":[-9,-37.6569,-34.8284]},{\\\"mesh\\\":1,\\\"translation\\\":[-9,-34.8284,-37.6569]},{\\\"mesh\\\":1,\\\"translation\\\":[-9,-37.6569,-40.4853]},{\\\"mesh\\\":2,\\\"translation\\\":[-10,-34.8284,-32]},{\\\"mesh\\\":3,\\\"translation\\\":[-10,-36.2426,-33.4142]},{\\\"mesh\\\":2,\\\"translation\\\":[-10,-34.8284,-37.6569]},{\\\"mesh\\\":3,\\\"translation\\\":[-10,-36.2426,-39.0711]},{\\\"mesh\\\":2,\\\"translation\\\":[-10,-37.6569,-34.8284]},{\\\"mesh\\\":3,\\\"translation\\\":[-10,-39.0711,-36.2426]},{\\\"mesh\\\":2,\\\"translation\\\":[-10,-33.4142,-39.0711]},{\\\"mesh\\\":3,\\\"translation\\\":[-10,-32,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-10,-36.2426,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-10,-34.8284,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-10,-39.0711,-39.0711]},{\\\"mesh\\\":3,\\\"translation\\\":[-10,-37.6569,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-11,-34.8284,-32]},{\\\"mesh\\\":3,\\\"translation\\\":[-11,-33.4142,-33.4142]},{\\\"mesh\\\":2,\\\"translation\\\":[-11,-34.8284,-37.6569]},{\\\"mesh\\\":3,\\\"translation\\\":[-11,-33.4142,-39.0711]},{\\\"mesh\\\":2,\\\"translation\\\":[-11,-37.6569,-34.8284]},{\\\"mesh\\\":3,\\\"translation\\\":[-11,-36.2426,-36.2426]},{\\\"mesh\\\":2,\\\"translation\\\":[-11,-33.4142,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-11,-32,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-11,-36.2426,-33.4142]},{\\\"mesh\\\":3,\\\"translation\\\":[-11,-34.8284,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-11,-39.0711,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-11,-37.6569,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-12,-34.8284,-37.6569]},{\\\"mesh\\\":3,\\\"translation\\\":[-12,-36.2426,-36.2426]},{\\\"mesh\\\":2,\\\"translation\\\":[-12,-37.6569,-34.8284]},{\\\"mesh\\\":3,\\\"translation\\\":[-12,-39.0711,-33.4142]},{\\\"mesh\\\":2,\\\"translation\\\":[-12,-37.6569,-40.4853]},{\\\"mesh\\\":3,\\\"translation\\\":[-12,-39.0711,-39.0711]},{\\\"mesh\\\":2,\\\"translation\\\":[-12,-33.4142,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-12,-34.8284,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-12,-36.2426,-39.0711]},{\\\"mesh\\\":3,\\\"translation\\\":[-12,-37.6569,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-12,-39.0711,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-12,-40.4853,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-13,-34.8284,-37.6569]},{\\\"mesh\\\":3,\\\"translation\\\":[-13,-33.4142,-36.2426]},{\\\"mesh\\\":2,\\\"translation\\\":[-13,-37.6569,-34.8284]},{\\\"mesh\\\":3,\\\"translation\\\":[-13,-36.2426,-33.4142]},{\\\"mesh\\\":2,\\\"translation\\\":[-13,-37.6569,-40.4853]},{\\\"mesh\\\":3,\\\"translation\\\":[-13,-36.2426,-39.0711]},{\\\"mesh\\\":2,\\\"translation\\\":[-13,-33.4142,-33.4142]},{\\\"mesh\\\":3,\\\"translation\\\":[-13,-34.8284,-34.8284]},{\\\"mesh\\\":2,\\\"translation\\\":[-13,-36.2426,-36.2426]},{\\\"mesh\\\":3,\\\"translation\\\":[-13,-37.6569,-37.6569]},{\\\"mesh\\\":2,\\\"translation\\\":[-13,-39.0711,-33.4142]},{\\\"mesh\\\":3,\\\"translation\\\":[-13,-40.4853,-34.8284]},{\\\"mesh\\\":1,\\\"translation\\\":[-14,-34.8284,-32]},{\\\"mesh\\\":1,\\\"translation\\\":[-14,-37.6569,-34.8284]},{\\\"mesh\\\":1,\\\"translation\\\":[-14,-34.8284,-37.6569]},{\\\"mesh\\\":1,\\\"translation\\\":[-14,-37.6569,-40.4853]},{\\\"mesh\\\":4,\\\"translation\\\":[-15,-34.8284,-32]},{\\\"mesh\\\":4,\\\"translation\\\":[-15,-34.8284,-34.8284]},{\\\"mesh\\\":4,\\\"translation\\\":[-15,-37.6569,-34.8284]},{\\\"mesh\\\":4,\\\"translation\\\":[-15,-40.4853,-34.8284]},{\\\"mesh\\\":4,\\\"translation\\\":[-15,-32,-37.6569]},{\\\"mesh\\\":4,\\\"translation\\\":[-15,-34.8284,-37.6569]},{\\\"mesh\\\":4,\\\"translation\\\":[-15,-37.6569,-37.6569]},{\\\"mesh\\\":4,\\\"translation\\\":[-15,-37.6569,-40.4853]},{\\\"mesh\\\":5,\\\"translation\\\":[-16,-33.4142,-33.4142]},{\\\"mesh\\\":5,\\\"translation\\\":[-16,-36.2426,-33.4142]},{\\\"mesh\\\":5,\\\"translation\\\":[-16,-39.0711,-33.4142]},{\\\"mesh\\\":5,\\\"translation\\\":[-16,-33.4142,-36.2426]},{\\\"mesh\\\":5,\\\"translation\\\":[-16,-36.2426,-36.2426]},{\\\"mesh\\\":5,\\\"translation\\\":[-16,-39.0711,-36.2426]},{\\\"mesh\\\":5,\\\"translation\\\":[-16,-33.4142,-39.0711]},{\\\"mesh\\\":5,\\\"translation\\\":[-16,-36.2426,-39.0711]},{\\\"mesh\\\":5,\\\"translation\\\":[-16,-39.0711,-39.0711]},{\\\"mesh\\\":6,\\\"translation\\\":[0,0,0]},{\\\"mesh\\\":7,\\\"translation\\\":[0,0,0]}],\\\"samplers\\\":[{\\\"magFilter\\\":9728,\\\"minFilter\\\":9728,\\\"wrapS\\\":33071,\\\"wrapT\\\":33071}],\\\"scene\\\":0,\\\"scenes\\\":[{\\\"nodes\\\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155]}],\\\"textures\\\":[{\\\"sampler\\\":0,\\\"source\\\":0}]}\"\n            ]\n          },\n          \"execution_count\": 31,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"surface_code_circuit.without_noise().diagram(\\\"timeline-3d\\\")\\n\",\n        \"\\n\",\n        \"# Note: if you are viewing this notebook on GitHub, the 3d model viewer is likely blocked.\\n\",\n        \"# To view the 3d model, run this notebook locally or upload it to https://colab.google.com/\\n\",\n        \"# GLTF files can be viewed directly in online viewers such as https://gltf-viewer.donmccurdy.com/\\n\",\n        \"\\n\",\n        \"# The 3d viewer is interactive, try clicking and dragging!\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"Hgh1I4Fefztj\"\n      },\n      \"source\": [\n        \"Yet another useful type of diagram, for understanding the structure of this circuit, is a \\\"detector slice diagram\\\".\\n\",\n        \"A detslice diagram shows how the stabilizers checked by the circuit's detectors change over time.\\n\",\n        \"If you look carefully, you can see that, halfway through the measurement cycle of the surface code, its state is actually temporarily an even larger surface code!\\n\",\n        \"You can also see the stabilizers establish themselves at the beginning of the circuit, and drain away at the end.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\",\n          \"height\": 373\n        },\n        \"id\": \"BUFs-tWlfx_U\",\n        \"outputId\": \"cd940223-754c-4841-f168-fff8be898166\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/svg+xml\": [\n              \"<svg viewBox=\\\"0 0 1459.55 1459.55\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"slice:2:4_4_0:3\\\">\\n\",\n              \"<path d=\\\"M637.505,83.8822 C651.082 74.8313,651.082 74.8313,660.133 61.2548 L682.76,83.8822 C669.183 92.9332,669.183 92.9332,660.133 106.51 C646.556 115.561,646.556 115.561,637.505 129.137 L614.878,106.51 C628.454 97.4587,628.454 97.4587,637.505 83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,83.8822 C651.082 74.8313,651.082 74.8313,660.133 61.2548 L682.76,83.8822 C669.183 92.9332,669.183 92.9332,660.133 106.51 C646.556 115.561,646.556 115.561,637.505 129.137 L614.878,106.51 C628.454 97.4587,628.454 97.4587,637.505 83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:5\\\">\\n\",\n              \"<path d=\\\"M983.96,61.2548 C997.536 52.2039,997.536 52.2039,1006.59 38.6274 L1029.21,61.2548 C1015.64 70.3058,1015.64 70.3058,1006.59 83.8822 C993.011 92.9332,993.011 92.9332,983.96 106.51 L961.332,83.8822 C974.909 74.8313,974.909 74.8313,983.96 61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,61.2548 C997.536 52.2039,997.536 52.2039,1006.59 38.6274 L1029.21,61.2548 C1015.64 70.3058,1015.64 70.3058,1006.59 83.8822 C993.011 92.9332,993.011 92.9332,983.96 106.51 L961.332,83.8822 C974.909 74.8313,974.909 74.8313,983.96 61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:5\\\">\\n\",\n              \"<path d=\\\"M1029.21,61.2548 C1042.79 52.2039,1042.79 52.2039,1051.84 38.6274 L1074.47,61.2548 C1060.89 70.3058,1060.89 70.3058,1051.84 83.8822 C1038.27 92.9332,1038.27 92.9332,1029.21 106.51 L1006.59,83.8822 C1020.16 74.8313,1020.16 74.8313,1029.21 61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,61.2548 C1042.79 52.2039,1042.79 52.2039,1051.84 38.6274 L1074.47,61.2548 C1060.89 70.3058,1060.89 70.3058,1051.84 83.8822 C1038.27 92.9332,1038.27 92.9332,1029.21 106.51 L1006.59,83.8822 C1020.16 74.8313,1020.16 74.8313,1029.21 61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:10\\\">\\n\",\n              \"<path d=\\\"M407.709,268.423 C421.286 259.372,421.286 259.372,430.337 245.796 L452.964,268.423 C439.388 277.474,439.388 277.474,430.337 291.051 C416.76 300.102,416.76 300.102,407.709 313.678 L385.082,291.051 C398.658 282,398.658 282,407.709 268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,268.423 C421.286 259.372,421.286 259.372,430.337 245.796 L452.964,268.423 C439.388 277.474,439.388 277.474,430.337 291.051 C416.76 300.102,416.76 300.102,407.709 313.678 L385.082,291.051 C398.658 282,398.658 282,407.709 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:10\\\">\\n\",\n              \"<path d=\\\"M452.964,268.423 C466.541 259.372,466.541 259.372,475.592 245.796 L498.219,268.423 C484.643 277.474,484.643 277.474,475.592 291.051 C462.015 300.102,462.015 300.102,452.964 313.678 L430.337,291.051 C443.913 282,443.913 282,452.964 268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,268.423 C466.541 259.372,466.541 259.372,475.592 245.796 L498.219,268.423 C484.643 277.474,484.643 277.474,475.592 291.051 C462.015 300.102,462.015 300.102,452.964 313.678 L430.337,291.051 C443.913 282,443.913 282,452.964 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:12\\\">\\n\",\n              \"<path d=\\\"M799.419,245.796 C812.995 236.745,812.995 236.745,822.046 223.168 L844.673,245.796 C831.097 254.847,831.097 254.847,822.046 268.423 C808.47 277.474,808.47 277.474,799.419 291.051 L776.791,268.423 C790.368 259.372,790.368 259.372,799.419 245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,245.796 C812.995 236.745,812.995 236.745,822.046 223.168 L844.673,245.796 C831.097 254.847,831.097 254.847,822.046 268.423 C808.47 277.474,808.47 277.474,799.419 291.051 L776.791,268.423 C790.368 259.372,790.368 259.372,799.419 245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:12\\\">\\n\",\n              \"<path d=\\\"M844.673,245.796 C858.25 236.745,858.25 236.745,867.301 223.168 L889.928,245.796 C876.352 254.847,876.352 254.847,867.301 268.423 C853.724 277.474,853.724 277.474,844.673 291.051 L822.046,268.423 C835.622 259.372,835.622 259.372,844.673 245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M844.673,245.796 C858.25 236.745,858.25 236.745,867.301 223.168 L889.928,245.796 C876.352 254.847,876.352 254.847,867.301 268.423 C853.724 277.474,853.724 277.474,844.673 291.051 L822.046,268.423 C835.622 259.372,835.622 259.372,844.673 245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:17\\\">\\n\",\n              \"<path d=\\\"M223.168,452.964 C236.745 443.913,236.745 443.913,245.796 430.337 L268.423,452.964 C254.847 462.015,254.847 462.015,245.796 475.592 C232.219 484.643,232.219 484.643,223.168 498.219 L200.541,475.592 C214.117 466.541,214.117 466.541,223.168 452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,452.964 C236.745 443.913,236.745 443.913,245.796 430.337 L268.423,452.964 C254.847 462.015,254.847 462.015,245.796 475.592 C232.219 484.643,232.219 484.643,223.168 498.219 L200.541,475.592 C214.117 466.541,214.117 466.541,223.168 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:17\\\">\\n\",\n              \"<path d=\\\"M268.423,452.964 C282 443.913,282 443.913,291.051 430.337 L313.678,452.964 C300.102 462.015,300.102 462.015,291.051 475.592 C277.474 484.643,277.474 484.643,268.423 498.219 L245.796,475.592 C259.372 466.541,259.372 466.541,268.423 452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,452.964 C282 443.913,282 443.913,291.051 430.337 L313.678,452.964 C300.102 462.015,300.102 462.015,291.051 475.592 C277.474 484.643,277.474 484.643,268.423 498.219 L245.796,475.592 C259.372 466.541,259.372 466.541,268.423 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:19\\\">\\n\",\n              \"<path d=\\\"M614.878,430.337 C628.454 421.286,628.454 421.286,637.505 407.709 L660.133,430.337 C646.556 439.388,646.556 439.388,637.505 452.964 C623.929 462.015,623.929 462.015,614.878 475.592 L592.25,452.964 C605.827 443.913,605.827 443.913,614.878 430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,430.337 C628.454 421.286,628.454 421.286,637.505 407.709 L660.133,430.337 C646.556 439.388,646.556 439.388,637.505 452.964 C623.929 462.015,623.929 462.015,614.878 475.592 L592.25,452.964 C605.827 443.913,605.827 443.913,614.878 430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:19\\\">\\n\",\n              \"<path d=\\\"M660.133,430.337 C673.709 421.286,673.709 421.286,682.76 407.709 L705.387,430.337 C691.811 439.388,691.811 439.388,682.76 452.964 C669.183 462.015,669.183 462.015,660.133 475.592 L637.505,452.964 C651.082 443.913,651.082 443.913,660.133 430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M660.133,430.337 C673.709 421.286,673.709 421.286,682.76 407.709 L705.387,430.337 C691.811 439.388,691.811 439.388,682.76 452.964 C669.183 462.015,669.183 462.015,660.133 475.592 L637.505,452.964 C651.082 443.913,651.082 443.913,660.133 430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:24\\\">\\n\",\n              \"<path d=\\\"M38.6274,637.505 C52.2039 628.454,52.2039 628.454,61.2548 614.878 L83.8822,637.505 C70.3058 646.556,70.3058 646.556,61.2548 660.133 C47.6784 669.183,47.6784 669.183,38.6274 682.76 L16,660.133 C29.5764 651.082,29.5764 651.082,38.6274 637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,637.505 C52.2039 628.454,52.2039 628.454,61.2548 614.878 L83.8822,637.505 C70.3058 646.556,70.3058 646.556,61.2548 660.133 C47.6784 669.183,47.6784 669.183,38.6274 682.76 L16,660.133 C29.5764 651.082,29.5764 651.082,38.6274 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:24\\\">\\n\",\n              \"<path d=\\\"M83.8822,637.505 C97.4587 628.454,97.4587 628.454,106.51 614.878 L129.137,637.505 C115.561 646.556,115.561 646.556,106.51 660.133 C92.9332 669.183,92.9332 669.183,83.8822 682.76 L61.2548,660.133 C74.8313 651.082,74.8313 651.082,83.8822 637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,637.505 C97.4587 628.454,97.4587 628.454,106.51 614.878 L129.137,637.505 C115.561 646.556,115.561 646.556,106.51 660.133 C92.9332 669.183,92.9332 669.183,83.8822 682.76 L61.2548,660.133 C74.8313 651.082,74.8313 651.082,83.8822 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:26\\\">\\n\",\n              \"<path d=\\\"M430.337,614.878 C443.913 605.827,443.913 605.827,452.964 592.25 L475.592,614.878 C462.015 623.929,462.015 623.929,452.964 637.505 C439.388 646.556,439.388 646.556,430.337 660.133 L407.709,637.505 C421.286 628.454,421.286 628.454,430.337 614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M430.337,614.878 C443.913 605.827,443.913 605.827,452.964 592.25 L475.592,614.878 C462.015 623.929,462.015 623.929,452.964 637.505 C439.388 646.556,439.388 646.556,430.337 660.133 L407.709,637.505 C421.286 628.454,421.286 628.454,430.337 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:26\\\">\\n\",\n              \"<path d=\\\"M475.592,614.878 C489.168 605.827,489.168 605.827,498.219 592.25 L520.846,614.878 C507.27 623.929,507.27 623.929,498.219 637.505 C484.643 646.556,484.643 646.556,475.592 660.133 L452.964,637.505 C466.541 628.454,466.541 628.454,475.592 614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M475.592,614.878 C489.168 605.827,489.168 605.827,498.219 592.25 L520.846,614.878 C507.27 623.929,507.27 623.929,498.219 637.505 C484.643 646.556,484.643 646.556,475.592 660.133 L452.964,637.505 C466.541 628.454,466.541 628.454,475.592 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:31\\\">\\n\",\n              \"<path d=\\\"M1330.41,637.505 C1343.99 628.454,1343.99 628.454,1353.04 614.878 L1375.67,637.505 C1362.09 646.556,1362.09 646.556,1353.04 660.133 C1339.47 669.183,1339.47 669.183,1330.41 682.76 L1307.79,660.133 C1321.36 651.082,1321.36 651.082,1330.41 637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,637.505 C1343.99 628.454,1343.99 628.454,1353.04 614.878 L1375.67,637.505 C1362.09 646.556,1362.09 646.556,1353.04 660.133 C1339.47 669.183,1339.47 669.183,1330.41 682.76 L1307.79,660.133 C1321.36 651.082,1321.36 651.082,1330.41 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:31\\\">\\n\",\n              \"<path d=\\\"M1375.67,637.505 C1389.25 628.454,1389.25 628.454,1398.3 614.878 L1420.92,637.505 C1407.35 646.556,1407.35 646.556,1398.3 660.133 C1384.72 669.183,1384.72 669.183,1375.67 682.76 L1353.04,660.133 C1366.62 651.082,1366.62 651.082,1375.67 637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,637.505 C1389.25 628.454,1389.25 628.454,1398.3 614.878 L1420.92,637.505 C1407.35 646.556,1407.35 646.556,1398.3 660.133 C1384.72 669.183,1384.72 669.183,1375.67 682.76 L1353.04,660.133 C1366.62 651.082,1366.62 651.082,1375.67 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:33\\\">\\n\",\n              \"<path d=\\\"M245.796,799.419 C259.372 790.368,259.372 790.368,268.423 776.791 L291.051,799.419 C277.474 808.47,277.474 808.47,268.423 822.046 C254.847 831.097,254.847 831.097,245.796 844.673 L223.168,822.046 C236.745 812.995,236.745 812.995,245.796 799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M245.796,799.419 C259.372 790.368,259.372 790.368,268.423 776.791 L291.051,799.419 C277.474 808.47,277.474 808.47,268.423 822.046 C254.847 831.097,254.847 831.097,245.796 844.673 L223.168,822.046 C236.745 812.995,236.745 812.995,245.796 799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:33\\\">\\n\",\n              \"<path d=\\\"M291.051,799.419 C304.627 790.368,304.627 790.368,313.678 776.791 L336.305,799.419 C322.729 808.47,322.729 808.47,313.678 822.046 C300.102 831.097,300.102 831.097,291.051 844.673 L268.423,822.046 C282 812.995,282 812.995,291.051 799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M291.051,799.419 C304.627 790.368,304.627 790.368,313.678 776.791 L336.305,799.419 C322.729 808.47,322.729 808.47,313.678 822.046 C300.102 831.097,300.102 831.097,291.051 844.673 L268.423,822.046 C282 812.995,282 812.995,291.051 799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:38\\\">\\n\",\n              \"<path d=\\\"M1145.87,822.046 C1159.45 812.995,1159.45 812.995,1168.5 799.419 L1191.13,822.046 C1177.55 831.097,1177.55 831.097,1168.5 844.673 C1154.92 853.724,1154.92 853.724,1145.87 867.301 L1123.25,844.673 C1136.82 835.622,1136.82 835.622,1145.87 822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,822.046 C1159.45 812.995,1159.45 812.995,1168.5 799.419 L1191.13,822.046 C1177.55 831.097,1177.55 831.097,1168.5 844.673 C1154.92 853.724,1154.92 853.724,1145.87 867.301 L1123.25,844.673 C1136.82 835.622,1136.82 835.622,1145.87 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:38\\\">\\n\",\n              \"<path d=\\\"M1191.13,822.046 C1204.7 812.995,1204.7 812.995,1213.76 799.419 L1236.38,822.046 C1222.81 831.097,1222.81 831.097,1213.76 844.673 C1200.18 853.724,1200.18 853.724,1191.13 867.301 L1168.5,844.673 C1182.08 835.622,1182.08 835.622,1191.13 822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,822.046 C1204.7 812.995,1204.7 812.995,1213.76 799.419 L1236.38,822.046 C1222.81 831.097,1222.81 831.097,1213.76 844.673 C1200.18 853.724,1200.18 853.724,1191.13 867.301 L1168.5,844.673 C1182.08 835.622,1182.08 835.622,1191.13 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:40\\\">\\n\",\n              \"<path d=\\\"M61.2548,983.96 C74.8313 974.909,74.8313 974.909,83.8822 961.332 L106.51,983.96 C92.9332 993.011,92.9332 993.011,83.8822 1006.59 C70.3058 1015.64,70.3058 1015.64,61.2548 1029.21 L38.6274,1006.59 C52.2039 997.536,52.2039 997.536,61.2548 983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,983.96 C74.8313 974.909,74.8313 974.909,83.8822 961.332 L106.51,983.96 C92.9332 993.011,92.9332 993.011,83.8822 1006.59 C70.3058 1015.64,70.3058 1015.64,61.2548 1029.21 L38.6274,1006.59 C52.2039 997.536,52.2039 997.536,61.2548 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:40\\\">\\n\",\n              \"<path d=\\\"M106.51,983.96 C120.086 974.909,120.086 974.909,129.137 961.332 L151.764,983.96 C138.188 993.011,138.188 993.011,129.137 1006.59 C115.561 1015.64,115.561 1015.64,106.51 1029.21 L83.8822,1006.59 C97.4587 997.536,97.4587 997.536,106.51 983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M106.51,983.96 C120.086 974.909,120.086 974.909,129.137 961.332 L151.764,983.96 C138.188 993.011,138.188 993.011,129.137 1006.59 C115.561 1015.64,115.561 1015.64,106.51 1029.21 L83.8822,1006.59 C97.4587 997.536,97.4587 997.536,106.51 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:45\\\">\\n\",\n              \"<path d=\\\"M961.332,1006.59 C974.909 997.536,974.909 997.536,983.96 983.96 L1006.59,1006.59 C993.011 1015.64,993.011 1015.64,983.96 1029.21 C970.383 1038.27,970.383 1038.27,961.332 1051.84 L938.705,1029.21 C952.281 1020.16,952.281 1020.16,961.332 1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1006.59 C974.909 997.536,974.909 997.536,983.96 983.96 L1006.59,1006.59 C993.011 1015.64,993.011 1015.64,983.96 1029.21 C970.383 1038.27,970.383 1038.27,961.332 1051.84 L938.705,1029.21 C952.281 1020.16,952.281 1020.16,961.332 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:45\\\">\\n\",\n              \"<path d=\\\"M1006.59,1006.59 C1020.16 997.536,1020.16 997.536,1029.21 983.96 L1051.84,1006.59 C1038.27 1015.64,1038.27 1015.64,1029.21 1029.21 C1015.64 1038.27,1015.64 1038.27,1006.59 1051.84 L983.96,1029.21 C997.536 1020.16,997.536 1020.16,1006.59 1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1006.59 C1020.16 997.536,1020.16 997.536,1029.21 983.96 L1051.84,1006.59 C1038.27 1015.64,1038.27 1015.64,1029.21 1029.21 C1015.64 1038.27,1015.64 1038.27,1006.59 1051.84 L983.96,1029.21 C997.536 1020.16,997.536 1020.16,1006.59 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:47\\\">\\n\",\n              \"<path d=\\\"M1353.04,983.96 C1366.62 974.909,1366.62 974.909,1375.67 961.332 L1398.3,983.96 C1384.72 993.011,1384.72 993.011,1375.67 1006.59 C1362.09 1015.64,1362.09 1015.64,1353.04 1029.21 L1330.41,1006.59 C1343.99 997.536,1343.99 997.536,1353.04 983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,983.96 C1366.62 974.909,1366.62 974.909,1375.67 961.332 L1398.3,983.96 C1384.72 993.011,1384.72 993.011,1375.67 1006.59 C1362.09 1015.64,1362.09 1015.64,1353.04 1029.21 L1330.41,1006.59 C1343.99 997.536,1343.99 997.536,1353.04 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:47\\\">\\n\",\n              \"<path d=\\\"M1398.3,983.96 C1411.87 974.909,1411.87 974.909,1420.92 961.332 L1443.55,983.96 C1429.97 993.011,1429.97 993.011,1420.92 1006.59 C1407.35 1015.64,1407.35 1015.64,1398.3 1029.21 L1375.67,1006.59 C1389.25 997.536,1389.25 997.536,1398.3 983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,983.96 C1411.87 974.909,1411.87 974.909,1420.92 961.332 L1443.55,983.96 C1429.97 993.011,1429.97 993.011,1420.92 1006.59 C1407.35 1015.64,1407.35 1015.64,1398.3 1029.21 L1375.67,1006.59 C1389.25 997.536,1389.25 997.536,1398.3 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:52\\\">\\n\",\n              \"<path d=\\\"M776.791,1191.13 C790.368 1182.08,790.368 1182.08,799.419 1168.5 L822.046,1191.13 C808.47 1200.18,808.47 1200.18,799.419 1213.76 C785.842 1222.81,785.842 1222.81,776.791 1236.38 L754.164,1213.76 C767.74 1204.7,767.74 1204.7,776.791 1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1191.13 C790.368 1182.08,790.368 1182.08,799.419 1168.5 L822.046,1191.13 C808.47 1200.18,808.47 1200.18,799.419 1213.76 C785.842 1222.81,785.842 1222.81,776.791 1236.38 L754.164,1213.76 C767.74 1204.7,767.74 1204.7,776.791 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:52\\\">\\n\",\n              \"<path d=\\\"M822.046,1191.13 C835.622 1182.08,835.622 1182.08,844.673 1168.5 L867.301,1191.13 C853.724 1200.18,853.724 1200.18,844.673 1213.76 C831.097 1222.81,831.097 1222.81,822.046 1236.38 L799.419,1213.76 C812.995 1204.7,812.995 1204.7,822.046 1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1191.13 C835.622 1182.08,835.622 1182.08,844.673 1168.5 L867.301,1191.13 C853.724 1200.18,853.724 1200.18,844.673 1213.76 C831.097 1222.81,831.097 1222.81,822.046 1236.38 L799.419,1213.76 C812.995 1204.7,812.995 1204.7,822.046 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:54\\\">\\n\",\n              \"<path d=\\\"M1168.5,1168.5 C1182.08 1159.45,1182.08 1159.45,1191.13 1145.87 L1213.76,1168.5 C1200.18 1177.55,1200.18 1177.55,1191.13 1191.13 C1177.55 1200.18,1177.55 1200.18,1168.5 1213.76 L1145.87,1191.13 C1159.45 1182.08,1159.45 1182.08,1168.5 1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,1168.5 C1182.08 1159.45,1182.08 1159.45,1191.13 1145.87 L1213.76,1168.5 C1200.18 1177.55,1200.18 1177.55,1191.13 1191.13 C1177.55 1200.18,1177.55 1200.18,1168.5 1213.76 L1145.87,1191.13 C1159.45 1182.08,1159.45 1182.08,1168.5 1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:54\\\">\\n\",\n              \"<path d=\\\"M1213.76,1168.5 C1227.33 1159.45,1227.33 1159.45,1236.38 1145.87 L1259.01,1168.5 C1245.43 1177.55,1245.43 1177.55,1236.38 1191.13 C1222.81 1200.18,1222.81 1200.18,1213.76 1213.76 L1191.13,1191.13 C1204.7 1182.08,1204.7 1182.08,1213.76 1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,1168.5 C1227.33 1159.45,1227.33 1159.45,1236.38 1145.87 L1259.01,1168.5 C1245.43 1177.55,1245.43 1177.55,1236.38 1191.13 C1222.81 1200.18,1222.81 1200.18,1213.76 1213.76 L1191.13,1191.13 C1204.7 1182.08,1204.7 1182.08,1213.76 1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:59\\\">\\n\",\n              \"<path d=\\\"M592.25,1375.67 C605.827 1366.62,605.827 1366.62,614.878 1353.04 L637.505,1375.67 C623.929 1384.72,623.929 1384.72,614.878 1398.3 C601.301 1407.35,601.301 1407.35,592.25 1420.92 L569.623,1398.3 C583.199 1389.25,583.199 1389.25,592.25 1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1375.67 C605.827 1366.62,605.827 1366.62,614.878 1353.04 L637.505,1375.67 C623.929 1384.72,623.929 1384.72,614.878 1398.3 C601.301 1407.35,601.301 1407.35,592.25 1420.92 L569.623,1398.3 C583.199 1389.25,583.199 1389.25,592.25 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:59\\\">\\n\",\n              \"<path d=\\\"M637.505,1375.67 C651.082 1366.62,651.082 1366.62,660.133 1353.04 L682.76,1375.67 C669.183 1384.72,669.183 1384.72,660.133 1398.3 C646.556 1407.35,646.556 1407.35,637.505 1420.92 L614.878,1398.3 C628.454 1389.25,628.454 1389.25,637.505 1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1375.67 C651.082 1366.62,651.082 1366.62,660.133 1353.04 L682.76,1375.67 C669.183 1384.72,669.183 1384.72,660.133 1398.3 C646.556 1407.35,646.556 1407.35,637.505 1420.92 L614.878,1398.3 C628.454 1389.25,628.454 1389.25,637.505 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:61\\\">\\n\",\n              \"<path d=\\\"M983.96,1353.04 C997.536 1343.99,997.536 1343.99,1006.59 1330.41 L1029.21,1353.04 C1015.64 1362.09,1015.64 1362.09,1006.59 1375.67 C993.011 1384.72,993.011 1384.72,983.96 1398.3 L961.332,1375.67 C974.909 1366.62,974.909 1366.62,983.96 1353.04\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1353.04 C997.536 1343.99,997.536 1343.99,1006.59 1330.41 L1029.21,1353.04 C1015.64 1362.09,1015.64 1362.09,1006.59 1375.67 C993.011 1384.72,993.011 1384.72,983.96 1398.3 L961.332,1375.67 C974.909 1366.62,974.909 1366.62,983.96 1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:1\\\">\\n\",\n              \"<path d=\\\"M223.168,38.6274 L268.423,38.6274 L245.796,61.2548 L268.423,83.8822 L223.168,83.8822 L223.168,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,38.6274 L268.423,38.6274 L245.796,61.2548 L268.423,83.8822 L223.168,83.8822 L223.168,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:1\\\">\\n\",\n              \"<path d=\\\"M268.423,83.8822 L313.678,83.8822 L291.051,106.51 L313.678,129.137 L268.423,129.137 L268.423,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,83.8822 L313.678,83.8822 L291.051,106.51 L313.678,129.137 L268.423,129.137 L268.423,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:2\\\">\\n\",\n              \"<path d=\\\"M407.709,38.6274 L452.964,38.6274 L430.337,61.2548 L452.964,83.8822 L407.709,83.8822 L407.709,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,38.6274 L452.964,38.6274 L430.337,61.2548 L452.964,83.8822 L407.709,83.8822 L407.709,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:2\\\">\\n\",\n              \"<path d=\\\"M452.964,83.8822 L498.219,83.8822 L475.592,106.51 L498.219,129.137 L452.964,129.137 L452.964,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,83.8822 L498.219,83.8822 L475.592,106.51 L498.219,129.137 L452.964,129.137 L452.964,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:3\\\">\\n\",\n              \"<path d=\\\"M592.25,38.6274 L614.878,16 L637.505,38.6274 C623.929 47.6784,623.929 47.6784,614.878 61.2548 C601.301 70.3058,601.301 70.3058,592.25 83.8822 L592.25,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,38.6274 L614.878,16 L637.505,38.6274 C623.929 47.6784,623.929 47.6784,614.878 61.2548 C601.301 70.3058,601.301 70.3058,592.25 83.8822 L592.25,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:5\\\">\\n\",\n              \"<path d=\\\"M983.96,106.51 C997.536 97.4587,997.536 97.4587,1006.59 83.8822 L1029.21,106.51 L1006.59,129.137 L961.332,129.137 C974.909 120.086,974.909 120.086,983.96 106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,106.51 C997.536 97.4587,997.536 97.4587,1006.59 83.8822 L1029.21,106.51 L1006.59,129.137 L961.332,129.137 C974.909 120.086,974.909 120.086,983.96 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:5\\\">\\n\",\n              \"<path d=\\\"M1029.21,106.51 C1042.79 97.4587,1042.79 97.4587,1051.84 83.8822 L1051.84,129.137 L1029.21,151.764 L1006.59,129.137 C1020.16 120.086,1020.16 120.086,1029.21 106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,106.51 C1042.79 97.4587,1042.79 97.4587,1051.84 83.8822 L1051.84,129.137 L1029.21,151.764 L1006.59,129.137 C1020.16 120.086,1020.16 120.086,1029.21 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1145.87,38.6274 L1191.13,38.6274 L1168.5,61.2548 L1191.13,83.8822 L1145.87,83.8822 L1145.87,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,38.6274 L1191.13,38.6274 L1168.5,61.2548 L1191.13,83.8822 L1145.87,83.8822 L1145.87,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1191.13,38.6274 L1236.38,38.6274 L1213.76,61.2548 L1236.38,83.8822 L1191.13,83.8822 L1191.13,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,38.6274 L1236.38,38.6274 L1213.76,61.2548 L1236.38,83.8822 L1191.13,83.8822 L1191.13,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1145.87,83.8822 L1191.13,83.8822 L1168.5,106.51 L1191.13,129.137 L1145.87,129.137 L1145.87,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,83.8822 L1191.13,83.8822 L1168.5,106.51 L1191.13,129.137 L1145.87,129.137 L1145.87,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1191.13,83.8822 L1236.38,83.8822 L1213.76,106.51 L1236.38,129.137 L1191.13,129.137 L1191.13,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,83.8822 L1236.38,83.8822 L1213.76,106.51 L1236.38,129.137 L1191.13,129.137 L1191.13,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:7\\\">\\n\",\n              \"<path d=\\\"M1330.41,38.6274 L1375.67,38.6274 L1353.04,61.2548 L1375.67,83.8822 L1330.41,83.8822 L1330.41,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,38.6274 L1375.67,38.6274 L1353.04,61.2548 L1375.67,83.8822 L1330.41,83.8822 L1330.41,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:7\\\">\\n\",\n              \"<path d=\\\"M1375.67,38.6274 L1420.92,38.6274 L1398.3,61.2548 L1420.92,83.8822 L1375.67,83.8822 L1375.67,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip0\\\"><path d=\\\"M1375.67,38.6274 L1420.92,38.6274 L1398.3,61.2548 L1420.92,83.8822 L1375.67,83.8822 L1375.67,38.6274\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1375.67\\\" cy=\\\"38.6274\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1420.92\\\" cy=\\\"38.6274\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1375.67\\\" cy=\\\"83.8822\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1398.3\\\" cy=\\\"61.2548\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1420.92\\\" cy=\\\"83.8822\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,38.6274 L1420.92,38.6274 L1398.3,61.2548 L1420.92,83.8822 L1375.67,83.8822 L1375.67,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:7\\\">\\n\",\n              \"<path d=\\\"M1330.41,83.8822 L1375.67,83.8822 L1353.04,106.51 L1375.67,129.137 L1330.41,129.137 L1330.41,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip1\\\"><path d=\\\"M1330.41,83.8822 L1375.67,83.8822 L1353.04,106.51 L1375.67,129.137 L1330.41,129.137 L1330.41,83.8822\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1330.41\\\" cy=\\\"83.8822\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1375.67\\\" cy=\\\"83.8822\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1330.41\\\" cy=\\\"129.137\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1353.04\\\" cy=\\\"106.51\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1375.67\\\" cy=\\\"129.137\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,83.8822 L1375.67,83.8822 L1353.04,106.51 L1375.67,129.137 L1330.41,129.137 L1330.41,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:7\\\">\\n\",\n              \"<path d=\\\"M1375.67,83.8822 L1420.92,83.8822 L1398.3,106.51 L1420.92,129.137 L1375.67,129.137 L1375.67,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,83.8822 L1420.92,83.8822 L1398.3,106.51 L1420.92,129.137 L1375.67,129.137 L1375.67,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:8\\\">\\n\",\n              \"<path d=\\\"M38.6274,223.168 L83.8822,223.168 L61.2548,245.796 L83.8822,268.423 L38.6274,268.423 L38.6274,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,223.168 L83.8822,223.168 L61.2548,245.796 L83.8822,268.423 L38.6274,268.423 L38.6274,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:8\\\">\\n\",\n              \"<path d=\\\"M83.8822,223.168 L129.137,223.168 L106.51,245.796 L129.137,268.423 L83.8822,268.423 L83.8822,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip2\\\"><path d=\\\"M83.8822,223.168 L129.137,223.168 L106.51,245.796 L129.137,268.423 L83.8822,268.423 L83.8822,223.168\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"83.8822\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"129.137\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"83.8822\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"106.51\\\" cy=\\\"245.796\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"129.137\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,223.168 L129.137,223.168 L106.51,245.796 L129.137,268.423 L83.8822,268.423 L83.8822,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:8\\\">\\n\",\n              \"<path d=\\\"M38.6274,268.423 L83.8822,268.423 L61.2548,291.051 L83.8822,313.678 L38.6274,313.678 L38.6274,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip3\\\"><path d=\\\"M38.6274,268.423 L83.8822,268.423 L61.2548,291.051 L83.8822,313.678 L38.6274,313.678 L38.6274,268.423\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"38.6274\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"83.8822\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"38.6274\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"61.2548\\\" cy=\\\"291.051\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"83.8822\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,268.423 L83.8822,268.423 L61.2548,291.051 L83.8822,313.678 L38.6274,313.678 L38.6274,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:8\\\">\\n\",\n              \"<path d=\\\"M83.8822,268.423 L129.137,268.423 L106.51,291.051 L129.137,313.678 L83.8822,313.678 L83.8822,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,268.423 L129.137,268.423 L106.51,291.051 L129.137,313.678 L83.8822,313.678 L83.8822,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:9\\\">\\n\",\n              \"<path d=\\\"M223.168,223.168 L268.423,223.168 L245.796,245.796 L268.423,268.423 L223.168,268.423 L223.168,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,223.168 L268.423,223.168 L245.796,245.796 L268.423,268.423 L223.168,268.423 L223.168,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:9\\\">\\n\",\n              \"<path d=\\\"M268.423,223.168 L313.678,223.168 L291.051,245.796 L313.678,268.423 L268.423,268.423 L268.423,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,223.168 L313.678,223.168 L291.051,245.796 L313.678,268.423 L268.423,268.423 L268.423,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:9\\\">\\n\",\n              \"<path d=\\\"M223.168,268.423 L268.423,268.423 L245.796,291.051 L268.423,313.678 L223.168,313.678 L223.168,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,268.423 L268.423,268.423 L245.796,291.051 L268.423,313.678 L223.168,313.678 L223.168,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:9\\\">\\n\",\n              \"<path d=\\\"M268.423,268.423 L313.678,268.423 L291.051,291.051 L313.678,313.678 L268.423,313.678 L268.423,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,268.423 L313.678,268.423 L291.051,291.051 L313.678,313.678 L268.423,313.678 L268.423,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:10\\\">\\n\",\n              \"<path d=\\\"M407.709,223.168 L430.337,200.541 L452.964,223.168 C439.388 232.219,439.388 232.219,430.337 245.796 C416.76 254.847,416.76 254.847,407.709 268.423 L407.709,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,223.168 L430.337,200.541 L452.964,223.168 C439.388 232.219,439.388 232.219,430.337 245.796 C416.76 254.847,416.76 254.847,407.709 268.423 L407.709,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:10\\\">\\n\",\n              \"<path d=\\\"M452.964,223.168 L498.219,223.168 C484.643 232.219,484.643 232.219,475.592 245.796 C462.015 254.847,462.015 254.847,452.964 268.423 L430.337,245.796 L452.964,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,223.168 L498.219,223.168 C484.643 232.219,484.643 232.219,475.592 245.796 C462.015 254.847,462.015 254.847,452.964 268.423 L430.337,245.796 L452.964,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:12\\\">\\n\",\n              \"<path d=\\\"M799.419,291.051 C812.995 282,812.995 282,822.046 268.423 L844.673,291.051 L822.046,313.678 L776.791,313.678 C790.368 304.627,790.368 304.627,799.419 291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,291.051 C812.995 282,812.995 282,822.046 268.423 L844.673,291.051 L822.046,313.678 L776.791,313.678 C790.368 304.627,790.368 304.627,799.419 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:12\\\">\\n\",\n              \"<path d=\\\"M844.673,291.051 C858.25 282,858.25 282,867.301 268.423 L867.301,313.678 L844.673,336.305 L822.046,313.678 C835.622 304.627,835.622 304.627,844.673 291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,291.051 C858.25 282,858.25 282,867.301 268.423 L867.301,313.678 L844.673,336.305 L822.046,313.678 C835.622 304.627,835.622 304.627,844.673 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:13\\\">\\n\",\n              \"<path d=\\\"M961.332,223.168 L1006.59,223.168 L983.96,245.796 L1006.59,268.423 L961.332,268.423 L961.332,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,223.168 L1006.59,223.168 L983.96,245.796 L1006.59,268.423 L961.332,268.423 L961.332,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:13\\\">\\n\",\n              \"<path d=\\\"M1006.59,223.168 L1051.84,223.168 L1029.21,245.796 L1051.84,268.423 L1006.59,268.423 L1006.59,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,223.168 L1051.84,223.168 L1029.21,245.796 L1051.84,268.423 L1006.59,268.423 L1006.59,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:13\\\">\\n\",\n              \"<path d=\\\"M961.332,268.423 L1006.59,268.423 L983.96,291.051 L1006.59,313.678 L961.332,313.678 L961.332,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,268.423 L1006.59,268.423 L983.96,291.051 L1006.59,313.678 L961.332,313.678 L961.332,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:13\\\">\\n\",\n              \"<path d=\\\"M1006.59,268.423 L1051.84,268.423 L1029.21,291.051 L1051.84,313.678 L1006.59,313.678 L1006.59,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,268.423 L1051.84,268.423 L1029.21,291.051 L1051.84,313.678 L1006.59,313.678 L1006.59,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:14\\\">\\n\",\n              \"<path d=\\\"M1145.87,223.168 L1191.13,223.168 L1168.5,245.796 L1191.13,268.423 L1145.87,268.423 L1145.87,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,223.168 L1191.13,223.168 L1168.5,245.796 L1191.13,268.423 L1145.87,268.423 L1145.87,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:14\\\">\\n\",\n              \"<path d=\\\"M1191.13,223.168 L1236.38,223.168 L1213.76,245.796 L1236.38,268.423 L1191.13,268.423 L1191.13,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip4\\\"><path d=\\\"M1191.13,223.168 L1236.38,223.168 L1213.76,245.796 L1236.38,268.423 L1191.13,268.423 L1191.13,223.168\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1191.13\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1236.38\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1191.13\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1213.76\\\" cy=\\\"245.796\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1236.38\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,223.168 L1236.38,223.168 L1213.76,245.796 L1236.38,268.423 L1191.13,268.423 L1191.13,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:14\\\">\\n\",\n              \"<path d=\\\"M1145.87,268.423 L1191.13,268.423 L1168.5,291.051 L1191.13,313.678 L1145.87,313.678 L1145.87,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip5\\\"><path d=\\\"M1145.87,268.423 L1191.13,268.423 L1168.5,291.051 L1191.13,313.678 L1145.87,313.678 L1145.87,268.423\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1145.87\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1191.13\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1145.87\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1168.5\\\" cy=\\\"291.051\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1191.13\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,268.423 L1191.13,268.423 L1168.5,291.051 L1191.13,313.678 L1145.87,313.678 L1145.87,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:14\\\">\\n\",\n              \"<path d=\\\"M1191.13,268.423 L1236.38,268.423 L1213.76,291.051 L1236.38,313.678 L1191.13,313.678 L1191.13,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,268.423 L1236.38,268.423 L1213.76,291.051 L1236.38,313.678 L1191.13,313.678 L1191.13,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:15\\\">\\n\",\n              \"<path d=\\\"M1330.41,223.168 L1375.67,223.168 L1353.04,245.796 L1375.67,268.423 L1330.41,268.423 L1330.41,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,223.168 L1375.67,223.168 L1353.04,245.796 L1375.67,268.423 L1330.41,268.423 L1330.41,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:15\\\">\\n\",\n              \"<path d=\\\"M1375.67,223.168 L1420.92,223.168 L1398.3,245.796 L1420.92,268.423 L1375.67,268.423 L1375.67,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip6\\\"><path d=\\\"M1375.67,223.168 L1420.92,223.168 L1398.3,245.796 L1420.92,268.423 L1375.67,268.423 L1375.67,223.168\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1375.67\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1420.92\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1375.67\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1398.3\\\" cy=\\\"245.796\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1420.92\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,223.168 L1420.92,223.168 L1398.3,245.796 L1420.92,268.423 L1375.67,268.423 L1375.67,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:15\\\">\\n\",\n              \"<path d=\\\"M1330.41,268.423 L1375.67,268.423 L1353.04,291.051 L1375.67,313.678 L1330.41,313.678 L1330.41,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip7\\\"><path d=\\\"M1330.41,268.423 L1375.67,268.423 L1353.04,291.051 L1375.67,313.678 L1330.41,313.678 L1330.41,268.423\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1330.41\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1375.67\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1330.41\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1353.04\\\" cy=\\\"291.051\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1375.67\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,268.423 L1375.67,268.423 L1353.04,291.051 L1375.67,313.678 L1330.41,313.678 L1330.41,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:15\\\">\\n\",\n              \"<path d=\\\"M1375.67,268.423 L1420.92,268.423 L1398.3,291.051 L1420.92,313.678 L1375.67,313.678 L1375.67,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,268.423 L1420.92,268.423 L1398.3,291.051 L1420.92,313.678 L1375.67,313.678 L1375.67,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:16\\\">\\n\",\n              \"<path d=\\\"M38.6274,407.709 L83.8822,407.709 L61.2548,430.337 L83.8822,452.964 L38.6274,452.964 L38.6274,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,407.709 L83.8822,407.709 L61.2548,430.337 L83.8822,452.964 L38.6274,452.964 L38.6274,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:16\\\">\\n\",\n              \"<path d=\\\"M83.8822,407.709 L129.137,407.709 L106.51,430.337 L129.137,452.964 L83.8822,452.964 L83.8822,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,407.709 L129.137,407.709 L106.51,430.337 L129.137,452.964 L83.8822,452.964 L83.8822,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:16\\\">\\n\",\n              \"<path d=\\\"M38.6274,452.964 L83.8822,452.964 L61.2548,475.592 L83.8822,498.219 L38.6274,498.219 L38.6274,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,452.964 L83.8822,452.964 L61.2548,475.592 L83.8822,498.219 L38.6274,498.219 L38.6274,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:16\\\">\\n\",\n              \"<path d=\\\"M83.8822,452.964 L129.137,452.964 L106.51,475.592 L129.137,498.219 L83.8822,498.219 L83.8822,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,452.964 L129.137,452.964 L106.51,475.592 L129.137,498.219 L83.8822,498.219 L83.8822,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:17\\\">\\n\",\n              \"<path d=\\\"M223.168,407.709 L245.796,385.082 L268.423,407.709 C254.847 416.76,254.847 416.76,245.796 430.337 C232.219 439.388,232.219 439.388,223.168 452.964 L223.168,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,407.709 L245.796,385.082 L268.423,407.709 C254.847 416.76,254.847 416.76,245.796 430.337 C232.219 439.388,232.219 439.388,223.168 452.964 L223.168,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:17\\\">\\n\",\n              \"<path d=\\\"M268.423,407.709 L313.678,407.709 C300.102 416.76,300.102 416.76,291.051 430.337 C277.474 439.388,277.474 439.388,268.423 452.964 L245.796,430.337 L268.423,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,407.709 L313.678,407.709 C300.102 416.76,300.102 416.76,291.051 430.337 C277.474 439.388,277.474 439.388,268.423 452.964 L245.796,430.337 L268.423,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:19\\\">\\n\",\n              \"<path d=\\\"M614.878,475.592 C628.454 466.541,628.454 466.541,637.505 452.964 L660.133,475.592 L637.505,498.219 L592.25,498.219 C605.827 489.168,605.827 489.168,614.878 475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,475.592 C628.454 466.541,628.454 466.541,637.505 452.964 L660.133,475.592 L637.505,498.219 L592.25,498.219 C605.827 489.168,605.827 489.168,614.878 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:19\\\">\\n\",\n              \"<path d=\\\"M660.133,475.592 C673.709 466.541,673.709 466.541,682.76 452.964 L682.76,498.219 L660.133,520.846 L637.505,498.219 C651.082 489.168,651.082 489.168,660.133 475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,475.592 C673.709 466.541,673.709 466.541,682.76 452.964 L682.76,498.219 L660.133,520.846 L637.505,498.219 C651.082 489.168,651.082 489.168,660.133 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:20\\\">\\n\",\n              \"<path d=\\\"M776.791,407.709 L822.046,407.709 L799.419,430.337 L822.046,452.964 L776.791,452.964 L776.791,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,407.709 L822.046,407.709 L799.419,430.337 L822.046,452.964 L776.791,452.964 L776.791,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:20\\\">\\n\",\n              \"<path d=\\\"M822.046,407.709 L867.301,407.709 L844.673,430.337 L867.301,452.964 L822.046,452.964 L822.046,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,407.709 L867.301,407.709 L844.673,430.337 L867.301,452.964 L822.046,452.964 L822.046,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:20\\\">\\n\",\n              \"<path d=\\\"M776.791,452.964 L822.046,452.964 L799.419,475.592 L822.046,498.219 L776.791,498.219 L776.791,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,452.964 L822.046,452.964 L799.419,475.592 L822.046,498.219 L776.791,498.219 L776.791,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:20\\\">\\n\",\n              \"<path d=\\\"M822.046,452.964 L867.301,452.964 L844.673,475.592 L867.301,498.219 L822.046,498.219 L822.046,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,452.964 L867.301,452.964 L844.673,475.592 L867.301,498.219 L822.046,498.219 L822.046,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:21\\\">\\n\",\n              \"<path d=\\\"M961.332,407.709 L1006.59,407.709 L983.96,430.337 L1006.59,452.964 L961.332,452.964 L961.332,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,407.709 L1006.59,407.709 L983.96,430.337 L1006.59,452.964 L961.332,452.964 L961.332,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:21\\\">\\n\",\n              \"<path d=\\\"M1006.59,407.709 L1051.84,407.709 L1029.21,430.337 L1051.84,452.964 L1006.59,452.964 L1006.59,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip8\\\"><path d=\\\"M1006.59,407.709 L1051.84,407.709 L1029.21,430.337 L1051.84,452.964 L1006.59,452.964 L1006.59,407.709\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1006.59\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1051.84\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1006.59\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1029.21\\\" cy=\\\"430.337\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1051.84\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,407.709 L1051.84,407.709 L1029.21,430.337 L1051.84,452.964 L1006.59,452.964 L1006.59,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:21\\\">\\n\",\n              \"<path d=\\\"M961.332,452.964 L1006.59,452.964 L983.96,475.592 L1006.59,498.219 L961.332,498.219 L961.332,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip9\\\"><path d=\\\"M961.332,452.964 L1006.59,452.964 L983.96,475.592 L1006.59,498.219 L961.332,498.219 L961.332,452.964\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"961.332\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"1006.59\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"961.332\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"983.96\\\" cy=\\\"475.592\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"1006.59\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M961.332,452.964 L1006.59,452.964 L983.96,475.592 L1006.59,498.219 L961.332,498.219 L961.332,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:21\\\">\\n\",\n              \"<path d=\\\"M1006.59,452.964 L1051.84,452.964 L1029.21,475.592 L1051.84,498.219 L1006.59,498.219 L1006.59,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,452.964 L1051.84,452.964 L1029.21,475.592 L1051.84,498.219 L1006.59,498.219 L1006.59,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:22\\\">\\n\",\n              \"<path d=\\\"M1145.87,407.709 L1191.13,407.709 L1168.5,430.337 L1191.13,452.964 L1145.87,452.964 L1145.87,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,407.709 L1191.13,407.709 L1168.5,430.337 L1191.13,452.964 L1145.87,452.964 L1145.87,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:22\\\">\\n\",\n              \"<path d=\\\"M1191.13,407.709 L1236.38,407.709 L1213.76,430.337 L1236.38,452.964 L1191.13,452.964 L1191.13,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip10\\\"><path d=\\\"M1191.13,407.709 L1236.38,407.709 L1213.76,430.337 L1236.38,452.964 L1191.13,452.964 L1191.13,407.709\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1191.13\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1236.38\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1191.13\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1213.76\\\" cy=\\\"430.337\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1236.38\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,407.709 L1236.38,407.709 L1213.76,430.337 L1236.38,452.964 L1191.13,452.964 L1191.13,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:22\\\">\\n\",\n              \"<path d=\\\"M1145.87,452.964 L1191.13,452.964 L1168.5,475.592 L1191.13,498.219 L1145.87,498.219 L1145.87,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip11\\\"><path d=\\\"M1145.87,452.964 L1191.13,452.964 L1168.5,475.592 L1191.13,498.219 L1145.87,498.219 L1145.87,452.964\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1145.87\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1191.13\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1145.87\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1168.5\\\" cy=\\\"475.592\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1191.13\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,452.964 L1191.13,452.964 L1168.5,475.592 L1191.13,498.219 L1145.87,498.219 L1145.87,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:22\\\">\\n\",\n              \"<path d=\\\"M1191.13,452.964 L1236.38,452.964 L1213.76,475.592 L1236.38,498.219 L1191.13,498.219 L1191.13,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,452.964 L1236.38,452.964 L1213.76,475.592 L1236.38,498.219 L1191.13,498.219 L1191.13,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:23\\\">\\n\",\n              \"<path d=\\\"M1330.41,407.709 L1375.67,407.709 L1353.04,430.337 L1375.67,452.964 L1330.41,452.964 L1330.41,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,407.709 L1375.67,407.709 L1353.04,430.337 L1375.67,452.964 L1330.41,452.964 L1330.41,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:23\\\">\\n\",\n              \"<path d=\\\"M1375.67,407.709 L1420.92,407.709 L1398.3,430.337 L1420.92,452.964 L1375.67,452.964 L1375.67,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,407.709 L1420.92,407.709 L1398.3,430.337 L1420.92,452.964 L1375.67,452.964 L1375.67,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:23\\\">\\n\",\n              \"<path d=\\\"M1330.41,452.964 L1375.67,452.964 L1353.04,475.592 L1375.67,498.219 L1330.41,498.219 L1330.41,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,452.964 L1375.67,452.964 L1353.04,475.592 L1375.67,498.219 L1330.41,498.219 L1330.41,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:23\\\">\\n\",\n              \"<path d=\\\"M1375.67,452.964 L1420.92,452.964 L1398.3,475.592 L1420.92,498.219 L1375.67,498.219 L1375.67,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,452.964 L1420.92,452.964 L1398.3,475.592 L1420.92,498.219 L1375.67,498.219 L1375.67,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:24\\\">\\n\",\n              \"<path d=\\\"M38.6274,592.25 L61.2548,569.623 L83.8822,592.25 C70.3058 601.301,70.3058 601.301,61.2548 614.878 C47.6784 623.929,47.6784 623.929,38.6274 637.505 L38.6274,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,592.25 L61.2548,569.623 L83.8822,592.25 C70.3058 601.301,70.3058 601.301,61.2548 614.878 C47.6784 623.929,47.6784 623.929,38.6274 637.505 L38.6274,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:24\\\">\\n\",\n              \"<path d=\\\"M83.8822,592.25 L129.137,592.25 C115.561 601.301,115.561 601.301,106.51 614.878 C92.9332 623.929,92.9332 623.929,83.8822 637.505 L61.2548,614.878 L83.8822,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,592.25 L129.137,592.25 C115.561 601.301,115.561 601.301,106.51 614.878 C92.9332 623.929,92.9332 623.929,83.8822 637.505 L61.2548,614.878 L83.8822,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:26\\\">\\n\",\n              \"<path d=\\\"M430.337,660.133 C443.913 651.082,443.913 651.082,452.964 637.505 L475.592,660.133 L452.964,682.76 L407.709,682.76 C421.286 673.709,421.286 673.709,430.337 660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,660.133 C443.913 651.082,443.913 651.082,452.964 637.505 L475.592,660.133 L452.964,682.76 L407.709,682.76 C421.286 673.709,421.286 673.709,430.337 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:26\\\">\\n\",\n              \"<path d=\\\"M475.592,660.133 C489.168 651.082,489.168 651.082,498.219 637.505 L498.219,682.76 L475.592,705.387 L452.964,682.76 C466.541 673.709,466.541 673.709,475.592 660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,660.133 C489.168 651.082,489.168 651.082,498.219 637.505 L498.219,682.76 L475.592,705.387 L452.964,682.76 C466.541 673.709,466.541 673.709,475.592 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:27\\\">\\n\",\n              \"<path d=\\\"M592.25,592.25 L637.505,592.25 L614.878,614.878 L637.505,637.505 L592.25,637.505 L592.25,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,592.25 L637.505,592.25 L614.878,614.878 L637.505,637.505 L592.25,637.505 L592.25,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:27\\\">\\n\",\n              \"<path d=\\\"M637.505,592.25 L682.76,592.25 L660.133,614.878 L682.76,637.505 L637.505,637.505 L637.505,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,592.25 L682.76,592.25 L660.133,614.878 L682.76,637.505 L637.505,637.505 L637.505,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:27\\\">\\n\",\n              \"<path d=\\\"M592.25,637.505 L637.505,637.505 L614.878,660.133 L637.505,682.76 L592.25,682.76 L592.25,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,637.505 L637.505,637.505 L614.878,660.133 L637.505,682.76 L592.25,682.76 L592.25,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:27\\\">\\n\",\n              \"<path d=\\\"M637.505,637.505 L682.76,637.505 L660.133,660.133 L682.76,682.76 L637.505,682.76 L637.505,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,637.505 L682.76,637.505 L660.133,660.133 L682.76,682.76 L637.505,682.76 L637.505,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:28\\\">\\n\",\n              \"<path d=\\\"M776.791,592.25 L822.046,592.25 L799.419,614.878 L822.046,637.505 L776.791,637.505 L776.791,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,592.25 L822.046,592.25 L799.419,614.878 L822.046,637.505 L776.791,637.505 L776.791,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:28\\\">\\n\",\n              \"<path d=\\\"M822.046,592.25 L867.301,592.25 L844.673,614.878 L867.301,637.505 L822.046,637.505 L822.046,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip12\\\"><path d=\\\"M822.046,592.25 L867.301,592.25 L844.673,614.878 L867.301,637.505 L822.046,637.505 L822.046,592.25\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"822.046\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"867.301\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"822.046\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"844.673\\\" cy=\\\"614.878\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"867.301\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M822.046,592.25 L867.301,592.25 L844.673,614.878 L867.301,637.505 L822.046,637.505 L822.046,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:28\\\">\\n\",\n              \"<path d=\\\"M776.791,637.505 L822.046,637.505 L799.419,660.133 L822.046,682.76 L776.791,682.76 L776.791,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip13\\\"><path d=\\\"M776.791,637.505 L822.046,637.505 L799.419,660.133 L822.046,682.76 L776.791,682.76 L776.791,637.505\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"776.791\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"822.046\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"776.791\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"799.419\\\" cy=\\\"660.133\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"822.046\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M776.791,637.505 L822.046,637.505 L799.419,660.133 L822.046,682.76 L776.791,682.76 L776.791,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:28\\\">\\n\",\n              \"<path d=\\\"M822.046,637.505 L867.301,637.505 L844.673,660.133 L867.301,682.76 L822.046,682.76 L822.046,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,637.505 L867.301,637.505 L844.673,660.133 L867.301,682.76 L822.046,682.76 L822.046,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:29\\\">\\n\",\n              \"<path d=\\\"M961.332,592.25 L1006.59,592.25 L983.96,614.878 L1006.59,637.505 L961.332,637.505 L961.332,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,592.25 L1006.59,592.25 L983.96,614.878 L1006.59,637.505 L961.332,637.505 L961.332,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:29\\\">\\n\",\n              \"<path d=\\\"M1006.59,592.25 L1051.84,592.25 L1029.21,614.878 L1051.84,637.505 L1006.59,637.505 L1006.59,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip14\\\"><path d=\\\"M1006.59,592.25 L1051.84,592.25 L1029.21,614.878 L1051.84,637.505 L1006.59,637.505 L1006.59,592.25\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1006.59\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1051.84\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1006.59\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1029.21\\\" cy=\\\"614.878\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1051.84\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,592.25 L1051.84,592.25 L1029.21,614.878 L1051.84,637.505 L1006.59,637.505 L1006.59,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:29\\\">\\n\",\n              \"<path d=\\\"M961.332,637.505 L1006.59,637.505 L983.96,660.133 L1006.59,682.76 L961.332,682.76 L961.332,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip15\\\"><path d=\\\"M961.332,637.505 L1006.59,637.505 L983.96,660.133 L1006.59,682.76 L961.332,682.76 L961.332,637.505\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"961.332\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"1006.59\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"961.332\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"983.96\\\" cy=\\\"660.133\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"1006.59\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M961.332,637.505 L1006.59,637.505 L983.96,660.133 L1006.59,682.76 L961.332,682.76 L961.332,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:29\\\">\\n\",\n              \"<path d=\\\"M1006.59,637.505 L1051.84,637.505 L1029.21,660.133 L1051.84,682.76 L1006.59,682.76 L1006.59,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,637.505 L1051.84,637.505 L1029.21,660.133 L1051.84,682.76 L1006.59,682.76 L1006.59,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:30\\\">\\n\",\n              \"<path d=\\\"M1145.87,592.25 L1191.13,592.25 L1168.5,614.878 L1191.13,637.505 L1145.87,637.505 L1145.87,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,592.25 L1191.13,592.25 L1168.5,614.878 L1191.13,637.505 L1145.87,637.505 L1145.87,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:30\\\">\\n\",\n              \"<path d=\\\"M1191.13,592.25 L1236.38,592.25 L1213.76,614.878 L1236.38,637.505 L1191.13,637.505 L1191.13,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,592.25 L1236.38,592.25 L1213.76,614.878 L1236.38,637.505 L1191.13,637.505 L1191.13,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:30\\\">\\n\",\n              \"<path d=\\\"M1145.87,637.505 L1191.13,637.505 L1168.5,660.133 L1191.13,682.76 L1145.87,682.76 L1145.87,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,637.505 L1191.13,637.505 L1168.5,660.133 L1191.13,682.76 L1145.87,682.76 L1145.87,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:30\\\">\\n\",\n              \"<path d=\\\"M1191.13,637.505 L1236.38,637.505 L1213.76,660.133 L1236.38,682.76 L1191.13,682.76 L1191.13,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,637.505 L1236.38,637.505 L1213.76,660.133 L1236.38,682.76 L1191.13,682.76 L1191.13,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:31\\\">\\n\",\n              \"<path d=\\\"M1330.41,592.25 L1353.04,569.623 L1375.67,592.25 C1362.09 601.301,1362.09 601.301,1353.04 614.878 C1339.47 623.929,1339.47 623.929,1330.41 637.505 L1330.41,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,592.25 L1353.04,569.623 L1375.67,592.25 C1362.09 601.301,1362.09 601.301,1353.04 614.878 C1339.47 623.929,1339.47 623.929,1330.41 637.505 L1330.41,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:31\\\">\\n\",\n              \"<path d=\\\"M1375.67,592.25 L1420.92,592.25 C1407.35 601.301,1407.35 601.301,1398.3 614.878 C1384.72 623.929,1384.72 623.929,1375.67 637.505 L1353.04,614.878 L1375.67,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,592.25 L1420.92,592.25 C1407.35 601.301,1407.35 601.301,1398.3 614.878 C1384.72 623.929,1384.72 623.929,1375.67 637.505 L1353.04,614.878 L1375.67,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:33\\\">\\n\",\n              \"<path d=\\\"M245.796,844.673 C259.372 835.622,259.372 835.622,268.423 822.046 L291.051,844.673 L268.423,867.301 L223.168,867.301 C236.745 858.25,236.745 858.25,245.796 844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,844.673 C259.372 835.622,259.372 835.622,268.423 822.046 L291.051,844.673 L268.423,867.301 L223.168,867.301 C236.745 858.25,236.745 858.25,245.796 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:33\\\">\\n\",\n              \"<path d=\\\"M291.051,844.673 C304.627 835.622,304.627 835.622,313.678 822.046 L313.678,867.301 L291.051,889.928 L268.423,867.301 C282 858.25,282 858.25,291.051 844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,844.673 C304.627 835.622,304.627 835.622,313.678 822.046 L313.678,867.301 L291.051,889.928 L268.423,867.301 C282 858.25,282 858.25,291.051 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:34\\\">\\n\",\n              \"<path d=\\\"M407.709,776.791 L452.964,776.791 L430.337,799.419 L452.964,822.046 L407.709,822.046 L407.709,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,776.791 L452.964,776.791 L430.337,799.419 L452.964,822.046 L407.709,822.046 L407.709,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:34\\\">\\n\",\n              \"<path d=\\\"M452.964,776.791 L498.219,776.791 L475.592,799.419 L498.219,822.046 L452.964,822.046 L452.964,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,776.791 L498.219,776.791 L475.592,799.419 L498.219,822.046 L452.964,822.046 L452.964,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:34\\\">\\n\",\n              \"<path d=\\\"M407.709,822.046 L452.964,822.046 L430.337,844.673 L452.964,867.301 L407.709,867.301 L407.709,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,822.046 L452.964,822.046 L430.337,844.673 L452.964,867.301 L407.709,867.301 L407.709,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:34\\\">\\n\",\n              \"<path d=\\\"M452.964,822.046 L498.219,822.046 L475.592,844.673 L498.219,867.301 L452.964,867.301 L452.964,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,822.046 L498.219,822.046 L475.592,844.673 L498.219,867.301 L452.964,867.301 L452.964,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:35\\\">\\n\",\n              \"<path d=\\\"M592.25,776.791 L637.505,776.791 L614.878,799.419 L637.505,822.046 L592.25,822.046 L592.25,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,776.791 L637.505,776.791 L614.878,799.419 L637.505,822.046 L592.25,822.046 L592.25,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:35\\\">\\n\",\n              \"<path d=\\\"M637.505,776.791 L682.76,776.791 L660.133,799.419 L682.76,822.046 L637.505,822.046 L637.505,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip16\\\"><path d=\\\"M637.505,776.791 L682.76,776.791 L660.133,799.419 L682.76,822.046 L637.505,822.046 L637.505,776.791\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"637.505\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"682.76\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"637.505\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"660.133\\\" cy=\\\"799.419\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"682.76\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M637.505,776.791 L682.76,776.791 L660.133,799.419 L682.76,822.046 L637.505,822.046 L637.505,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:35\\\">\\n\",\n              \"<path d=\\\"M592.25,822.046 L637.505,822.046 L614.878,844.673 L637.505,867.301 L592.25,867.301 L592.25,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip17\\\"><path d=\\\"M592.25,822.046 L637.505,822.046 L614.878,844.673 L637.505,867.301 L592.25,867.301 L592.25,822.046\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"592.25\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"637.505\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"592.25\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"614.878\\\" cy=\\\"844.673\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"637.505\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M592.25,822.046 L637.505,822.046 L614.878,844.673 L637.505,867.301 L592.25,867.301 L592.25,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:35\\\">\\n\",\n              \"<path d=\\\"M637.505,822.046 L682.76,822.046 L660.133,844.673 L682.76,867.301 L637.505,867.301 L637.505,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,822.046 L682.76,822.046 L660.133,844.673 L682.76,867.301 L637.505,867.301 L637.505,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:36\\\">\\n\",\n              \"<path d=\\\"M776.791,776.791 L822.046,776.791 L799.419,799.419 L822.046,822.046 L776.791,822.046 L776.791,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,776.791 L822.046,776.791 L799.419,799.419 L822.046,822.046 L776.791,822.046 L776.791,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:36\\\">\\n\",\n              \"<path d=\\\"M822.046,776.791 L867.301,776.791 L844.673,799.419 L867.301,822.046 L822.046,822.046 L822.046,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip18\\\"><path d=\\\"M822.046,776.791 L867.301,776.791 L844.673,799.419 L867.301,822.046 L822.046,822.046 L822.046,776.791\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"822.046\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"867.301\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"822.046\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"844.673\\\" cy=\\\"799.419\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"867.301\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M822.046,776.791 L867.301,776.791 L844.673,799.419 L867.301,822.046 L822.046,822.046 L822.046,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:36\\\">\\n\",\n              \"<path d=\\\"M776.791,822.046 L822.046,822.046 L799.419,844.673 L822.046,867.301 L776.791,867.301 L776.791,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip19\\\"><path d=\\\"M776.791,822.046 L822.046,822.046 L799.419,844.673 L822.046,867.301 L776.791,867.301 L776.791,822.046\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"776.791\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"822.046\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"776.791\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"799.419\\\" cy=\\\"844.673\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"822.046\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M776.791,822.046 L822.046,822.046 L799.419,844.673 L822.046,867.301 L776.791,867.301 L776.791,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:36\\\">\\n\",\n              \"<path d=\\\"M822.046,822.046 L867.301,822.046 L844.673,844.673 L867.301,867.301 L822.046,867.301 L822.046,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,822.046 L867.301,822.046 L844.673,844.673 L867.301,867.301 L822.046,867.301 L822.046,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:37\\\">\\n\",\n              \"<path d=\\\"M961.332,776.791 L1006.59,776.791 L983.96,799.419 L1006.59,822.046 L961.332,822.046 L961.332,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,776.791 L1006.59,776.791 L983.96,799.419 L1006.59,822.046 L961.332,822.046 L961.332,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:37\\\">\\n\",\n              \"<path d=\\\"M1006.59,776.791 L1051.84,776.791 L1029.21,799.419 L1051.84,822.046 L1006.59,822.046 L1006.59,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,776.791 L1051.84,776.791 L1029.21,799.419 L1051.84,822.046 L1006.59,822.046 L1006.59,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:37\\\">\\n\",\n              \"<path d=\\\"M961.332,822.046 L1006.59,822.046 L983.96,844.673 L1006.59,867.301 L961.332,867.301 L961.332,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,822.046 L1006.59,822.046 L983.96,844.673 L1006.59,867.301 L961.332,867.301 L961.332,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:37\\\">\\n\",\n              \"<path d=\\\"M1006.59,822.046 L1051.84,822.046 L1029.21,844.673 L1051.84,867.301 L1006.59,867.301 L1006.59,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,822.046 L1051.84,822.046 L1029.21,844.673 L1051.84,867.301 L1006.59,867.301 L1006.59,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:38\\\">\\n\",\n              \"<path d=\\\"M1145.87,776.791 L1168.5,754.164 L1191.13,776.791 C1177.55 785.842,1177.55 785.842,1168.5 799.419 C1154.92 808.47,1154.92 808.47,1145.87 822.046 L1145.87,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,776.791 L1168.5,754.164 L1191.13,776.791 C1177.55 785.842,1177.55 785.842,1168.5 799.419 C1154.92 808.47,1154.92 808.47,1145.87 822.046 L1145.87,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:38\\\">\\n\",\n              \"<path d=\\\"M1191.13,776.791 L1236.38,776.791 C1222.81 785.842,1222.81 785.842,1213.76 799.419 C1200.18 808.47,1200.18 808.47,1191.13 822.046 L1168.5,799.419 L1191.13,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,776.791 L1236.38,776.791 C1222.81 785.842,1222.81 785.842,1213.76 799.419 C1200.18 808.47,1200.18 808.47,1191.13 822.046 L1168.5,799.419 L1191.13,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:40\\\">\\n\",\n              \"<path d=\\\"M61.2548,1029.21 C74.8313 1020.16,74.8313 1020.16,83.8822 1006.59 L106.51,1029.21 L83.8822,1051.84 L38.6274,1051.84 C52.2039 1042.79,52.2039 1042.79,61.2548 1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,1029.21 C74.8313 1020.16,74.8313 1020.16,83.8822 1006.59 L106.51,1029.21 L83.8822,1051.84 L38.6274,1051.84 C52.2039 1042.79,52.2039 1042.79,61.2548 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:40\\\">\\n\",\n              \"<path d=\\\"M106.51,1029.21 C120.086 1020.16,120.086 1020.16,129.137 1006.59 L129.137,1051.84 L106.51,1074.47 L83.8822,1051.84 C97.4587 1042.79,97.4587 1042.79,106.51 1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,1029.21 C120.086 1020.16,120.086 1020.16,129.137 1006.59 L129.137,1051.84 L106.51,1074.47 L83.8822,1051.84 C97.4587 1042.79,97.4587 1042.79,106.51 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:41\\\">\\n\",\n              \"<path d=\\\"M223.168,961.332 L268.423,961.332 L245.796,983.96 L268.423,1006.59 L223.168,1006.59 L223.168,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,961.332 L268.423,961.332 L245.796,983.96 L268.423,1006.59 L223.168,1006.59 L223.168,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:41\\\">\\n\",\n              \"<path d=\\\"M268.423,961.332 L313.678,961.332 L291.051,983.96 L313.678,1006.59 L268.423,1006.59 L268.423,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,961.332 L313.678,961.332 L291.051,983.96 L313.678,1006.59 L268.423,1006.59 L268.423,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:41\\\">\\n\",\n              \"<path d=\\\"M223.168,1006.59 L268.423,1006.59 L245.796,1029.21 L268.423,1051.84 L223.168,1051.84 L223.168,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1006.59 L268.423,1006.59 L245.796,1029.21 L268.423,1051.84 L223.168,1051.84 L223.168,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:41\\\">\\n\",\n              \"<path d=\\\"M268.423,1006.59 L313.678,1006.59 L291.051,1029.21 L313.678,1051.84 L268.423,1051.84 L268.423,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1006.59 L313.678,1006.59 L291.051,1029.21 L313.678,1051.84 L268.423,1051.84 L268.423,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:42\\\">\\n\",\n              \"<path d=\\\"M407.709,961.332 L452.964,961.332 L430.337,983.96 L452.964,1006.59 L407.709,1006.59 L407.709,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,961.332 L452.964,961.332 L430.337,983.96 L452.964,1006.59 L407.709,1006.59 L407.709,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:42\\\">\\n\",\n              \"<path d=\\\"M452.964,961.332 L498.219,961.332 L475.592,983.96 L498.219,1006.59 L452.964,1006.59 L452.964,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip20\\\"><path d=\\\"M452.964,961.332 L498.219,961.332 L475.592,983.96 L498.219,1006.59 L452.964,1006.59 L452.964,961.332\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"452.964\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"498.219\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"452.964\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"475.592\\\" cy=\\\"983.96\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"498.219\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M452.964,961.332 L498.219,961.332 L475.592,983.96 L498.219,1006.59 L452.964,1006.59 L452.964,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:42\\\">\\n\",\n              \"<path d=\\\"M407.709,1006.59 L452.964,1006.59 L430.337,1029.21 L452.964,1051.84 L407.709,1051.84 L407.709,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip21\\\"><path d=\\\"M407.709,1006.59 L452.964,1006.59 L430.337,1029.21 L452.964,1051.84 L407.709,1051.84 L407.709,1006.59\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"407.709\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"452.964\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"407.709\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"430.337\\\" cy=\\\"1029.21\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"452.964\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1006.59 L452.964,1006.59 L430.337,1029.21 L452.964,1051.84 L407.709,1051.84 L407.709,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:42\\\">\\n\",\n              \"<path d=\\\"M452.964,1006.59 L498.219,1006.59 L475.592,1029.21 L498.219,1051.84 L452.964,1051.84 L452.964,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1006.59 L498.219,1006.59 L475.592,1029.21 L498.219,1051.84 L452.964,1051.84 L452.964,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:43\\\">\\n\",\n              \"<path d=\\\"M592.25,961.332 L637.505,961.332 L614.878,983.96 L637.505,1006.59 L592.25,1006.59 L592.25,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,961.332 L637.505,961.332 L614.878,983.96 L637.505,1006.59 L592.25,1006.59 L592.25,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:43\\\">\\n\",\n              \"<path d=\\\"M637.505,961.332 L682.76,961.332 L660.133,983.96 L682.76,1006.59 L637.505,1006.59 L637.505,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip22\\\"><path d=\\\"M637.505,961.332 L682.76,961.332 L660.133,983.96 L682.76,1006.59 L637.505,1006.59 L637.505,961.332\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"637.505\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"682.76\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"637.505\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"660.133\\\" cy=\\\"983.96\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"682.76\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M637.505,961.332 L682.76,961.332 L660.133,983.96 L682.76,1006.59 L637.505,1006.59 L637.505,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:43\\\">\\n\",\n              \"<path d=\\\"M592.25,1006.59 L637.505,1006.59 L614.878,1029.21 L637.505,1051.84 L592.25,1051.84 L592.25,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip23\\\"><path d=\\\"M592.25,1006.59 L637.505,1006.59 L614.878,1029.21 L637.505,1051.84 L592.25,1051.84 L592.25,1006.59\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"592.25\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"637.505\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"592.25\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"614.878\\\" cy=\\\"1029.21\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"637.505\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1006.59 L637.505,1006.59 L614.878,1029.21 L637.505,1051.84 L592.25,1051.84 L592.25,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:43\\\">\\n\",\n              \"<path d=\\\"M637.505,1006.59 L682.76,1006.59 L660.133,1029.21 L682.76,1051.84 L637.505,1051.84 L637.505,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1006.59 L682.76,1006.59 L660.133,1029.21 L682.76,1051.84 L637.505,1051.84 L637.505,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:44\\\">\\n\",\n              \"<path d=\\\"M776.791,961.332 L822.046,961.332 L799.419,983.96 L822.046,1006.59 L776.791,1006.59 L776.791,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,961.332 L822.046,961.332 L799.419,983.96 L822.046,1006.59 L776.791,1006.59 L776.791,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:44\\\">\\n\",\n              \"<path d=\\\"M822.046,961.332 L867.301,961.332 L844.673,983.96 L867.301,1006.59 L822.046,1006.59 L822.046,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,961.332 L867.301,961.332 L844.673,983.96 L867.301,1006.59 L822.046,1006.59 L822.046,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:44\\\">\\n\",\n              \"<path d=\\\"M776.791,1006.59 L822.046,1006.59 L799.419,1029.21 L822.046,1051.84 L776.791,1051.84 L776.791,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1006.59 L822.046,1006.59 L799.419,1029.21 L822.046,1051.84 L776.791,1051.84 L776.791,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:44\\\">\\n\",\n              \"<path d=\\\"M822.046,1006.59 L867.301,1006.59 L844.673,1029.21 L867.301,1051.84 L822.046,1051.84 L822.046,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1006.59 L867.301,1006.59 L844.673,1029.21 L867.301,1051.84 L822.046,1051.84 L822.046,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:45\\\">\\n\",\n              \"<path d=\\\"M961.332,961.332 L983.96,938.705 L1006.59,961.332 C993.011 970.383,993.011 970.383,983.96 983.96 C970.383 993.011,970.383 993.011,961.332 1006.59 L961.332,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,961.332 L983.96,938.705 L1006.59,961.332 C993.011 970.383,993.011 970.383,983.96 983.96 C970.383 993.011,970.383 993.011,961.332 1006.59 L961.332,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:45\\\">\\n\",\n              \"<path d=\\\"M1006.59,961.332 L1051.84,961.332 C1038.27 970.383,1038.27 970.383,1029.21 983.96 C1015.64 993.011,1015.64 993.011,1006.59 1006.59 L983.96,983.96 L1006.59,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,961.332 L1051.84,961.332 C1038.27 970.383,1038.27 970.383,1029.21 983.96 C1015.64 993.011,1015.64 993.011,1006.59 1006.59 L983.96,983.96 L1006.59,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:47\\\">\\n\",\n              \"<path d=\\\"M1353.04,1029.21 C1366.62 1020.16,1366.62 1020.16,1375.67 1006.59 L1398.3,1029.21 L1375.67,1051.84 L1330.41,1051.84 C1343.99 1042.79,1343.99 1042.79,1353.04 1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,1029.21 C1366.62 1020.16,1366.62 1020.16,1375.67 1006.59 L1398.3,1029.21 L1375.67,1051.84 L1330.41,1051.84 C1343.99 1042.79,1343.99 1042.79,1353.04 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:47\\\">\\n\",\n              \"<path d=\\\"M1398.3,1029.21 C1411.87 1020.16,1411.87 1020.16,1420.92 1006.59 L1420.92,1051.84 L1398.3,1074.47 L1375.67,1051.84 C1389.25 1042.79,1389.25 1042.79,1398.3 1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,1029.21 C1411.87 1020.16,1411.87 1020.16,1420.92 1006.59 L1420.92,1051.84 L1398.3,1074.47 L1375.67,1051.84 C1389.25 1042.79,1389.25 1042.79,1398.3 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:48\\\">\\n\",\n              \"<path d=\\\"M38.6274,1145.87 L83.8822,1145.87 L61.2548,1168.5 L83.8822,1191.13 L38.6274,1191.13 L38.6274,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1145.87 L83.8822,1145.87 L61.2548,1168.5 L83.8822,1191.13 L38.6274,1191.13 L38.6274,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:48\\\">\\n\",\n              \"<path d=\\\"M83.8822,1145.87 L129.137,1145.87 L106.51,1168.5 L129.137,1191.13 L83.8822,1191.13 L83.8822,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1145.87 L129.137,1145.87 L106.51,1168.5 L129.137,1191.13 L83.8822,1191.13 L83.8822,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:48\\\">\\n\",\n              \"<path d=\\\"M38.6274,1191.13 L83.8822,1191.13 L61.2548,1213.76 L83.8822,1236.38 L38.6274,1236.38 L38.6274,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1191.13 L83.8822,1191.13 L61.2548,1213.76 L83.8822,1236.38 L38.6274,1236.38 L38.6274,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:48\\\">\\n\",\n              \"<path d=\\\"M83.8822,1191.13 L129.137,1191.13 L106.51,1213.76 L129.137,1236.38 L83.8822,1236.38 L83.8822,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1191.13 L129.137,1191.13 L106.51,1213.76 L129.137,1236.38 L83.8822,1236.38 L83.8822,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:49\\\">\\n\",\n              \"<path d=\\\"M223.168,1145.87 L268.423,1145.87 L245.796,1168.5 L268.423,1191.13 L223.168,1191.13 L223.168,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1145.87 L268.423,1145.87 L245.796,1168.5 L268.423,1191.13 L223.168,1191.13 L223.168,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:49\\\">\\n\",\n              \"<path d=\\\"M268.423,1145.87 L313.678,1145.87 L291.051,1168.5 L313.678,1191.13 L268.423,1191.13 L268.423,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip24\\\"><path d=\\\"M268.423,1145.87 L313.678,1145.87 L291.051,1168.5 L313.678,1191.13 L268.423,1191.13 L268.423,1145.87\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"268.423\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"313.678\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"268.423\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"291.051\\\" cy=\\\"1168.5\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"313.678\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1145.87 L313.678,1145.87 L291.051,1168.5 L313.678,1191.13 L268.423,1191.13 L268.423,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:49\\\">\\n\",\n              \"<path d=\\\"M223.168,1191.13 L268.423,1191.13 L245.796,1213.76 L268.423,1236.38 L223.168,1236.38 L223.168,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip25\\\"><path d=\\\"M223.168,1191.13 L268.423,1191.13 L245.796,1213.76 L268.423,1236.38 L223.168,1236.38 L223.168,1191.13\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"223.168\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"268.423\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"223.168\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"245.796\\\" cy=\\\"1213.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"268.423\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1191.13 L268.423,1191.13 L245.796,1213.76 L268.423,1236.38 L223.168,1236.38 L223.168,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:49\\\">\\n\",\n              \"<path d=\\\"M268.423,1191.13 L313.678,1191.13 L291.051,1213.76 L313.678,1236.38 L268.423,1236.38 L268.423,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1191.13 L313.678,1191.13 L291.051,1213.76 L313.678,1236.38 L268.423,1236.38 L268.423,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:50\\\">\\n\",\n              \"<path d=\\\"M407.709,1145.87 L452.964,1145.87 L430.337,1168.5 L452.964,1191.13 L407.709,1191.13 L407.709,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1145.87 L452.964,1145.87 L430.337,1168.5 L452.964,1191.13 L407.709,1191.13 L407.709,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:50\\\">\\n\",\n              \"<path d=\\\"M452.964,1145.87 L498.219,1145.87 L475.592,1168.5 L498.219,1191.13 L452.964,1191.13 L452.964,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip26\\\"><path d=\\\"M452.964,1145.87 L498.219,1145.87 L475.592,1168.5 L498.219,1191.13 L452.964,1191.13 L452.964,1145.87\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"452.964\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"498.219\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"452.964\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"475.592\\\" cy=\\\"1168.5\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"498.219\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1145.87 L498.219,1145.87 L475.592,1168.5 L498.219,1191.13 L452.964,1191.13 L452.964,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:50\\\">\\n\",\n              \"<path d=\\\"M407.709,1191.13 L452.964,1191.13 L430.337,1213.76 L452.964,1236.38 L407.709,1236.38 L407.709,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip27\\\"><path d=\\\"M407.709,1191.13 L452.964,1191.13 L430.337,1213.76 L452.964,1236.38 L407.709,1236.38 L407.709,1191.13\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"407.709\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"452.964\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"407.709\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"430.337\\\" cy=\\\"1213.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"452.964\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1191.13 L452.964,1191.13 L430.337,1213.76 L452.964,1236.38 L407.709,1236.38 L407.709,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:50\\\">\\n\",\n              \"<path d=\\\"M452.964,1191.13 L498.219,1191.13 L475.592,1213.76 L498.219,1236.38 L452.964,1236.38 L452.964,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1191.13 L498.219,1191.13 L475.592,1213.76 L498.219,1236.38 L452.964,1236.38 L452.964,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:51\\\">\\n\",\n              \"<path d=\\\"M592.25,1145.87 L637.505,1145.87 L614.878,1168.5 L637.505,1191.13 L592.25,1191.13 L592.25,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1145.87 L637.505,1145.87 L614.878,1168.5 L637.505,1191.13 L592.25,1191.13 L592.25,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:51\\\">\\n\",\n              \"<path d=\\\"M637.505,1145.87 L682.76,1145.87 L660.133,1168.5 L682.76,1191.13 L637.505,1191.13 L637.505,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1145.87 L682.76,1145.87 L660.133,1168.5 L682.76,1191.13 L637.505,1191.13 L637.505,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:51\\\">\\n\",\n              \"<path d=\\\"M592.25,1191.13 L637.505,1191.13 L614.878,1213.76 L637.505,1236.38 L592.25,1236.38 L592.25,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1191.13 L637.505,1191.13 L614.878,1213.76 L637.505,1236.38 L592.25,1236.38 L592.25,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:51\\\">\\n\",\n              \"<path d=\\\"M637.505,1191.13 L682.76,1191.13 L660.133,1213.76 L682.76,1236.38 L637.505,1236.38 L637.505,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1191.13 L682.76,1191.13 L660.133,1213.76 L682.76,1236.38 L637.505,1236.38 L637.505,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:52\\\">\\n\",\n              \"<path d=\\\"M776.791,1145.87 L799.419,1123.25 L822.046,1145.87 C808.47 1154.92,808.47 1154.92,799.419 1168.5 C785.842 1177.55,785.842 1177.55,776.791 1191.13 L776.791,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1145.87 L799.419,1123.25 L822.046,1145.87 C808.47 1154.92,808.47 1154.92,799.419 1168.5 C785.842 1177.55,785.842 1177.55,776.791 1191.13 L776.791,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:52\\\">\\n\",\n              \"<path d=\\\"M822.046,1145.87 L867.301,1145.87 C853.724 1154.92,853.724 1154.92,844.673 1168.5 C831.097 1177.55,831.097 1177.55,822.046 1191.13 L799.419,1168.5 L822.046,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1145.87 L867.301,1145.87 C853.724 1154.92,853.724 1154.92,844.673 1168.5 C831.097 1177.55,831.097 1177.55,822.046 1191.13 L799.419,1168.5 L822.046,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:54\\\">\\n\",\n              \"<path d=\\\"M1168.5,1213.76 C1182.08 1204.7,1182.08 1204.7,1191.13 1191.13 L1213.76,1213.76 L1191.13,1236.38 L1145.87,1236.38 C1159.45 1227.33,1159.45 1227.33,1168.5 1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,1213.76 C1182.08 1204.7,1182.08 1204.7,1191.13 1191.13 L1213.76,1213.76 L1191.13,1236.38 L1145.87,1236.38 C1159.45 1227.33,1159.45 1227.33,1168.5 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:54\\\">\\n\",\n              \"<path d=\\\"M1213.76,1213.76 C1227.33 1204.7,1227.33 1204.7,1236.38 1191.13 L1236.38,1236.38 L1213.76,1259.01 L1191.13,1236.38 C1204.7 1227.33,1204.7 1227.33,1213.76 1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,1213.76 C1227.33 1204.7,1227.33 1204.7,1236.38 1191.13 L1236.38,1236.38 L1213.76,1259.01 L1191.13,1236.38 C1204.7 1227.33,1204.7 1227.33,1213.76 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:55\\\">\\n\",\n              \"<path d=\\\"M1330.41,1145.87 L1375.67,1145.87 L1353.04,1168.5 L1375.67,1191.13 L1330.41,1191.13 L1330.41,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,1145.87 L1375.67,1145.87 L1353.04,1168.5 L1375.67,1191.13 L1330.41,1191.13 L1330.41,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:55\\\">\\n\",\n              \"<path d=\\\"M1375.67,1145.87 L1420.92,1145.87 L1398.3,1168.5 L1420.92,1191.13 L1375.67,1191.13 L1375.67,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1145.87 L1420.92,1145.87 L1398.3,1168.5 L1420.92,1191.13 L1375.67,1191.13 L1375.67,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:55\\\">\\n\",\n              \"<path d=\\\"M1330.41,1191.13 L1375.67,1191.13 L1353.04,1213.76 L1375.67,1236.38 L1330.41,1236.38 L1330.41,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,1191.13 L1375.67,1191.13 L1353.04,1213.76 L1375.67,1236.38 L1330.41,1236.38 L1330.41,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:55\\\">\\n\",\n              \"<path d=\\\"M1375.67,1191.13 L1420.92,1191.13 L1398.3,1213.76 L1420.92,1236.38 L1375.67,1236.38 L1375.67,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1191.13 L1420.92,1191.13 L1398.3,1213.76 L1420.92,1236.38 L1375.67,1236.38 L1375.67,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:56\\\">\\n\",\n              \"<path d=\\\"M38.6274,1330.41 L83.8822,1330.41 L61.2548,1353.04 L83.8822,1375.67 L38.6274,1375.67 L38.6274,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1330.41 L83.8822,1330.41 L61.2548,1353.04 L83.8822,1375.67 L38.6274,1375.67 L38.6274,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:56\\\">\\n\",\n              \"<path d=\\\"M83.8822,1330.41 L129.137,1330.41 L106.51,1353.04 L129.137,1375.67 L83.8822,1375.67 L83.8822,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip28\\\"><path d=\\\"M83.8822,1330.41 L129.137,1330.41 L106.51,1353.04 L129.137,1375.67 L83.8822,1375.67 L83.8822,1330.41\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"83.8822\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"129.137\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"83.8822\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"106.51\\\" cy=\\\"1353.04\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"129.137\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1330.41 L129.137,1330.41 L106.51,1353.04 L129.137,1375.67 L83.8822,1375.67 L83.8822,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:56\\\">\\n\",\n              \"<path d=\\\"M38.6274,1375.67 L83.8822,1375.67 L61.2548,1398.3 L83.8822,1420.92 L38.6274,1420.92 L38.6274,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip29\\\"><path d=\\\"M38.6274,1375.67 L83.8822,1375.67 L61.2548,1398.3 L83.8822,1420.92 L38.6274,1420.92 L38.6274,1375.67\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"38.6274\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"83.8822\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"38.6274\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"61.2548\\\" cy=\\\"1398.3\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"83.8822\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1375.67 L83.8822,1375.67 L61.2548,1398.3 L83.8822,1420.92 L38.6274,1420.92 L38.6274,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:56\\\">\\n\",\n              \"<path d=\\\"M83.8822,1375.67 L129.137,1375.67 L106.51,1398.3 L129.137,1420.92 L83.8822,1420.92 L83.8822,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1375.67 L129.137,1375.67 L106.51,1398.3 L129.137,1420.92 L83.8822,1420.92 L83.8822,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:57\\\">\\n\",\n              \"<path d=\\\"M223.168,1330.41 L268.423,1330.41 L245.796,1353.04 L268.423,1375.67 L223.168,1375.67 L223.168,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1330.41 L268.423,1330.41 L245.796,1353.04 L268.423,1375.67 L223.168,1375.67 L223.168,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:57\\\">\\n\",\n              \"<path d=\\\"M268.423,1330.41 L313.678,1330.41 L291.051,1353.04 L313.678,1375.67 L268.423,1375.67 L268.423,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip30\\\"><path d=\\\"M268.423,1330.41 L313.678,1330.41 L291.051,1353.04 L313.678,1375.67 L268.423,1375.67 L268.423,1330.41\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"268.423\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"313.678\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"268.423\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"291.051\\\" cy=\\\"1353.04\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"313.678\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1330.41 L313.678,1330.41 L291.051,1353.04 L313.678,1375.67 L268.423,1375.67 L268.423,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:57\\\">\\n\",\n              \"<path d=\\\"M223.168,1375.67 L268.423,1375.67 L245.796,1398.3 L268.423,1420.92 L223.168,1420.92 L223.168,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip31\\\"><path d=\\\"M223.168,1375.67 L268.423,1375.67 L245.796,1398.3 L268.423,1420.92 L223.168,1420.92 L223.168,1375.67\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"223.168\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"268.423\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"223.168\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"245.796\\\" cy=\\\"1398.3\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"268.423\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1375.67 L268.423,1375.67 L245.796,1398.3 L268.423,1420.92 L223.168,1420.92 L223.168,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:57\\\">\\n\",\n              \"<path d=\\\"M268.423,1375.67 L313.678,1375.67 L291.051,1398.3 L313.678,1420.92 L268.423,1420.92 L268.423,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1375.67 L313.678,1375.67 L291.051,1398.3 L313.678,1420.92 L268.423,1420.92 L268.423,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:58\\\">\\n\",\n              \"<path d=\\\"M407.709,1330.41 L452.964,1330.41 L430.337,1353.04 L452.964,1375.67 L407.709,1375.67 L407.709,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1330.41 L452.964,1330.41 L430.337,1353.04 L452.964,1375.67 L407.709,1375.67 L407.709,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:58\\\">\\n\",\n              \"<path d=\\\"M452.964,1330.41 L498.219,1330.41 L475.592,1353.04 L498.219,1375.67 L452.964,1375.67 L452.964,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1330.41 L498.219,1330.41 L475.592,1353.04 L498.219,1375.67 L452.964,1375.67 L452.964,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:58\\\">\\n\",\n              \"<path d=\\\"M407.709,1375.67 L452.964,1375.67 L430.337,1398.3 L452.964,1420.92 L407.709,1420.92 L407.709,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1375.67 L452.964,1375.67 L430.337,1398.3 L452.964,1420.92 L407.709,1420.92 L407.709,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:58\\\">\\n\",\n              \"<path d=\\\"M452.964,1375.67 L498.219,1375.67 L475.592,1398.3 L498.219,1420.92 L452.964,1420.92 L452.964,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1375.67 L498.219,1375.67 L475.592,1398.3 L498.219,1420.92 L452.964,1420.92 L452.964,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:59\\\">\\n\",\n              \"<path d=\\\"M592.25,1330.41 L614.878,1307.79 L637.505,1330.41 C623.929 1339.47,623.929 1339.47,614.878 1353.04 C601.301 1362.09,601.301 1362.09,592.25 1375.67 L592.25,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1330.41 L614.878,1307.79 L637.505,1330.41 C623.929 1339.47,623.929 1339.47,614.878 1353.04 C601.301 1362.09,601.301 1362.09,592.25 1375.67 L592.25,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:59\\\">\\n\",\n              \"<path d=\\\"M637.505,1330.41 L682.76,1330.41 C669.183 1339.47,669.183 1339.47,660.133 1353.04 C646.556 1362.09,646.556 1362.09,637.505 1375.67 L614.878,1353.04 L637.505,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1330.41 L682.76,1330.41 C669.183 1339.47,669.183 1339.47,660.133 1353.04 C646.556 1362.09,646.556 1362.09,637.505 1375.67 L614.878,1353.04 L637.505,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:61\\\">\\n\",\n              \"<path d=\\\"M1029.21,1398.3 C1042.79 1389.25,1042.79 1389.25,1051.84 1375.67 L1051.84,1420.92 L1029.21,1443.55 L1006.59,1420.92 C1020.16 1411.87,1020.16 1411.87,1029.21 1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,1398.3 C1042.79 1389.25,1042.79 1389.25,1051.84 1375.67 L1051.84,1420.92 L1029.21,1443.55 L1006.59,1420.92 C1020.16 1411.87,1020.16 1411.87,1029.21 1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:62\\\">\\n\",\n              \"<path d=\\\"M1145.87,1330.41 L1191.13,1330.41 L1168.5,1353.04 L1191.13,1375.67 L1145.87,1375.67 L1145.87,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1330.41 L1191.13,1330.41 L1168.5,1353.04 L1191.13,1375.67 L1145.87,1375.67 L1145.87,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:62\\\">\\n\",\n              \"<path d=\\\"M1191.13,1375.67 L1236.38,1375.67 L1213.76,1398.3 L1236.38,1420.92 L1191.13,1420.92 L1191.13,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1375.67 L1236.38,1375.67 L1213.76,1398.3 L1236.38,1420.92 L1191.13,1420.92 L1191.13,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:63\\\">\\n\",\n              \"<path d=\\\"M1330.41,1330.41 L1375.67,1330.41 L1353.04,1353.04 L1375.67,1375.67 L1330.41,1375.67 L1330.41,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,1330.41 L1375.67,1330.41 L1353.04,1353.04 L1375.67,1375.67 L1330.41,1375.67 L1330.41,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:63\\\">\\n\",\n              \"<path d=\\\"M1375.67,1375.67 L1420.92,1375.67 L1398.3,1398.3 L1420.92,1420.92 L1375.67,1420.92 L1375.67,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1375.67 L1420.92,1375.67 L1398.3,1398.3 L1420.92,1420.92 L1375.67,1420.92 L1375.67,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:3\\\">\\n\",\n              \"<path d=\\\"M660.133,61.2548 L682.76,38.6274 L705.387,61.2548 L682.76,83.8822 L660.133,61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,61.2548 L682.76,38.6274 L705.387,61.2548 L682.76,83.8822 L660.133,61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:4\\\">\\n\",\n              \"<path d=\\\"M799.419,106.51 L822.046,83.8822 L844.673,106.51 L822.046,129.137 L799.419,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,106.51 L822.046,83.8822 L844.673,106.51 L822.046,129.137 L799.419,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:4\\\">\\n\",\n              \"<path d=\\\"M844.673,61.2548 L867.301,38.6274 L889.928,61.2548 L867.301,83.8822 L844.673,61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,61.2548 L867.301,38.6274 L889.928,61.2548 L867.301,83.8822 L844.673,61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:4\\\">\\n\",\n              \"<path d=\\\"M776.791,38.6274 L799.419,16 L822.046,38.6274 L799.419,61.2548 L776.791,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,38.6274 L799.419,16 L822.046,38.6274 L799.419,61.2548 L776.791,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:4\\\">\\n\",\n              \"<path d=\\\"M799.419,61.2548 L822.046,38.6274 L844.673,61.2548 L822.046,83.8822 L799.419,61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,61.2548 L822.046,38.6274 L844.673,61.2548 L822.046,83.8822 L799.419,61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:4\\\">\\n\",\n              \"<path d=\\\"M822.046,83.8822 L844.673,61.2548 L867.301,83.8822 L844.673,106.51 L822.046,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,83.8822 L844.673,61.2548 L867.301,83.8822 L844.673,106.51 L822.046,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:4\\\">\\n\",\n              \"<path d=\\\"M754.164,106.51 L776.791,83.8822 L799.419,106.51 L776.791,129.137 L754.164,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,106.51 L776.791,83.8822 L799.419,106.51 L776.791,129.137 L754.164,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:5\\\">\\n\",\n              \"<path d=\\\"M961.332,38.6274 L983.96,16 L1006.59,38.6274 L983.96,61.2548 L961.332,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,38.6274 L983.96,16 L1006.59,38.6274 L983.96,61.2548 L961.332,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:5\\\">\\n\",\n              \"<path d=\\\"M938.705,106.51 L961.332,83.8822 L983.96,106.51 L961.332,129.137 L938.705,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,106.51 L961.332,83.8822 L983.96,106.51 L961.332,129.137 L938.705,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:10\\\">\\n\",\n              \"<path d=\\\"M475.592,245.796 L498.219,223.168 L520.846,245.796 L498.219,268.423 L475.592,245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,245.796 L498.219,223.168 L520.846,245.796 L498.219,268.423 L475.592,245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:10\\\">\\n\",\n              \"<path d=\\\"M452.964,313.678 L475.592,291.051 L498.219,313.678 L475.592,336.305 L452.964,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,313.678 L475.592,291.051 L498.219,313.678 L475.592,336.305 L452.964,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:11\\\">\\n\",\n              \"<path d=\\\"M660.133,245.796 L682.76,223.168 L705.387,245.796 L682.76,268.423 L660.133,245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,245.796 L682.76,223.168 L705.387,245.796 L682.76,268.423 L660.133,245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:11\\\">\\n\",\n              \"<path d=\\\"M592.25,268.423 L614.878,245.796 L637.505,268.423 L614.878,291.051 L592.25,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,268.423 L614.878,245.796 L637.505,268.423 L614.878,291.051 L592.25,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:11\\\">\\n\",\n              \"<path d=\\\"M614.878,291.051 L637.505,268.423 L660.133,291.051 L637.505,313.678 L614.878,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,291.051 L637.505,268.423 L660.133,291.051 L637.505,313.678 L614.878,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:11\\\">\\n\",\n              \"<path d=\\\"M637.505,313.678 L660.133,291.051 L682.76,313.678 L660.133,336.305 L637.505,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,313.678 L660.133,291.051 L682.76,313.678 L660.133,336.305 L637.505,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:11\\\">\\n\",\n              \"<path d=\\\"M592.25,223.168 L614.878,200.541 L637.505,223.168 L614.878,245.796 L592.25,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,223.168 L614.878,200.541 L637.505,223.168 L614.878,245.796 L592.25,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:11\\\">\\n\",\n              \"<path d=\\\"M614.878,245.796 L637.505,223.168 L660.133,245.796 L637.505,268.423 L614.878,245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,245.796 L637.505,223.168 L660.133,245.796 L637.505,268.423 L614.878,245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:11\\\">\\n\",\n              \"<path d=\\\"M637.505,268.423 L660.133,245.796 L682.76,268.423 L660.133,291.051 L637.505,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,268.423 L660.133,245.796 L682.76,268.423 L660.133,291.051 L637.505,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:11\\\">\\n\",\n              \"<path d=\\\"M569.623,291.051 L592.25,268.423 L614.878,291.051 L592.25,313.678 L569.623,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,291.051 L592.25,268.423 L614.878,291.051 L592.25,313.678 L569.623,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:12\\\">\\n\",\n              \"<path d=\\\"M776.791,223.168 L799.419,200.541 L822.046,223.168 L799.419,245.796 L776.791,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,223.168 L799.419,200.541 L822.046,223.168 L799.419,245.796 L776.791,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:12\\\">\\n\",\n              \"<path d=\\\"M754.164,291.051 L776.791,268.423 L799.419,291.051 L776.791,313.678 L754.164,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,291.051 L776.791,268.423 L799.419,291.051 L776.791,313.678 L754.164,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:17\\\">\\n\",\n              \"<path d=\\\"M291.051,430.337 L313.678,407.709 L336.305,430.337 L313.678,452.964 L291.051,430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,430.337 L313.678,407.709 L336.305,430.337 L313.678,452.964 L291.051,430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:17\\\">\\n\",\n              \"<path d=\\\"M268.423,498.219 L291.051,475.592 L313.678,498.219 L291.051,520.846 L268.423,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,498.219 L291.051,475.592 L313.678,498.219 L291.051,520.846 L268.423,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:18\\\">\\n\",\n              \"<path d=\\\"M475.592,430.337 L498.219,407.709 L520.846,430.337 L498.219,452.964 L475.592,430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,430.337 L498.219,407.709 L520.846,430.337 L498.219,452.964 L475.592,430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:18\\\">\\n\",\n              \"<path d=\\\"M407.709,452.964 L430.337,430.337 L452.964,452.964 L430.337,475.592 L407.709,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,452.964 L430.337,430.337 L452.964,452.964 L430.337,475.592 L407.709,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:18\\\">\\n\",\n              \"<path d=\\\"M430.337,475.592 L452.964,452.964 L475.592,475.592 L452.964,498.219 L430.337,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M430.337,475.592 L452.964,452.964 L475.592,475.592 L452.964,498.219 L430.337,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:18\\\">\\n\",\n              \"<path d=\\\"M452.964,498.219 L475.592,475.592 L498.219,498.219 L475.592,520.846 L452.964,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,498.219 L475.592,475.592 L498.219,498.219 L475.592,520.846 L452.964,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:18\\\">\\n\",\n              \"<path d=\\\"M407.709,407.709 L430.337,385.082 L452.964,407.709 L430.337,430.337 L407.709,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,407.709 L430.337,385.082 L452.964,407.709 L430.337,430.337 L407.709,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:18\\\">\\n\",\n              \"<path d=\\\"M430.337,430.337 L452.964,407.709 L475.592,430.337 L452.964,452.964 L430.337,430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M430.337,430.337 L452.964,407.709 L475.592,430.337 L452.964,452.964 L430.337,430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:18\\\">\\n\",\n              \"<path d=\\\"M452.964,452.964 L475.592,430.337 L498.219,452.964 L475.592,475.592 L452.964,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,452.964 L475.592,430.337 L498.219,452.964 L475.592,475.592 L452.964,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:18\\\">\\n\",\n              \"<path d=\\\"M385.082,475.592 L407.709,452.964 L430.337,475.592 L407.709,498.219 L385.082,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,475.592 L407.709,452.964 L430.337,475.592 L407.709,498.219 L385.082,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:19\\\">\\n\",\n              \"<path d=\\\"M592.25,407.709 L614.878,385.082 L637.505,407.709 L614.878,430.337 L592.25,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,407.709 L614.878,385.082 L637.505,407.709 L614.878,430.337 L592.25,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:19\\\">\\n\",\n              \"<path d=\\\"M569.623,475.592 L592.25,452.964 L614.878,475.592 L592.25,498.219 L569.623,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,475.592 L592.25,452.964 L614.878,475.592 L592.25,498.219 L569.623,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:24\\\">\\n\",\n              \"<path d=\\\"M106.51,614.878 L129.137,592.25 L151.764,614.878 L129.137,637.505 L106.51,614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,614.878 L129.137,592.25 L151.764,614.878 L129.137,637.505 L106.51,614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:24\\\">\\n\",\n              \"<path d=\\\"M83.8822,682.76 L106.51,660.133 L129.137,682.76 L106.51,705.387 L83.8822,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,682.76 L106.51,660.133 L129.137,682.76 L106.51,705.387 L83.8822,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:25\\\">\\n\",\n              \"<path d=\\\"M291.051,614.878 L313.678,592.25 L336.305,614.878 L313.678,637.505 L291.051,614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,614.878 L313.678,592.25 L336.305,614.878 L313.678,637.505 L291.051,614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:25\\\">\\n\",\n              \"<path d=\\\"M223.168,637.505 L245.796,614.878 L268.423,637.505 L245.796,660.133 L223.168,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,637.505 L245.796,614.878 L268.423,637.505 L245.796,660.133 L223.168,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:25\\\">\\n\",\n              \"<path d=\\\"M245.796,660.133 L268.423,637.505 L291.051,660.133 L268.423,682.76 L245.796,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M245.796,660.133 L268.423,637.505 L291.051,660.133 L268.423,682.76 L245.796,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:25\\\">\\n\",\n              \"<path d=\\\"M268.423,682.76 L291.051,660.133 L313.678,682.76 L291.051,705.387 L268.423,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,682.76 L291.051,660.133 L313.678,682.76 L291.051,705.387 L268.423,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:25\\\">\\n\",\n              \"<path d=\\\"M223.168,592.25 L245.796,569.623 L268.423,592.25 L245.796,614.878 L223.168,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,592.25 L245.796,569.623 L268.423,592.25 L245.796,614.878 L223.168,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:25\\\">\\n\",\n              \"<path d=\\\"M245.796,614.878 L268.423,592.25 L291.051,614.878 L268.423,637.505 L245.796,614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M245.796,614.878 L268.423,592.25 L291.051,614.878 L268.423,637.505 L245.796,614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:25\\\">\\n\",\n              \"<path d=\\\"M268.423,637.505 L291.051,614.878 L313.678,637.505 L291.051,660.133 L268.423,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,637.505 L291.051,614.878 L313.678,637.505 L291.051,660.133 L268.423,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:25\\\">\\n\",\n              \"<path d=\\\"M200.541,660.133 L223.168,637.505 L245.796,660.133 L223.168,682.76 L200.541,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,660.133 L223.168,637.505 L245.796,660.133 L223.168,682.76 L200.541,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:26\\\">\\n\",\n              \"<path d=\\\"M407.709,592.25 L430.337,569.623 L452.964,592.25 L430.337,614.878 L407.709,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,592.25 L430.337,569.623 L452.964,592.25 L430.337,614.878 L407.709,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:26\\\">\\n\",\n              \"<path d=\\\"M385.082,660.133 L407.709,637.505 L430.337,660.133 L407.709,682.76 L385.082,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,660.133 L407.709,637.505 L430.337,660.133 L407.709,682.76 L385.082,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:31\\\">\\n\",\n              \"<path d=\\\"M1398.3,614.878 L1420.92,592.25 L1443.55,614.878 L1420.92,637.505 L1398.3,614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,614.878 L1420.92,592.25 L1443.55,614.878 L1420.92,637.505 L1398.3,614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:31\\\">\\n\",\n              \"<path d=\\\"M1375.67,682.76 L1398.3,660.133 L1420.92,682.76 L1398.3,705.387 L1375.67,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,682.76 L1398.3,660.133 L1420.92,682.76 L1398.3,705.387 L1375.67,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:32\\\">\\n\",\n              \"<path d=\\\"M106.51,799.419 L129.137,776.791 L151.764,799.419 L129.137,822.046 L106.51,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,799.419 L129.137,776.791 L151.764,799.419 L129.137,822.046 L106.51,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:32\\\">\\n\",\n              \"<path d=\\\"M38.6274,822.046 L61.2548,799.419 L83.8822,822.046 L61.2548,844.673 L38.6274,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,822.046 L61.2548,799.419 L83.8822,822.046 L61.2548,844.673 L38.6274,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:32\\\">\\n\",\n              \"<path d=\\\"M61.2548,844.673 L83.8822,822.046 L106.51,844.673 L83.8822,867.301 L61.2548,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,844.673 L83.8822,822.046 L106.51,844.673 L83.8822,867.301 L61.2548,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:32\\\">\\n\",\n              \"<path d=\\\"M83.8822,867.301 L106.51,844.673 L129.137,867.301 L106.51,889.928 L83.8822,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,867.301 L106.51,844.673 L129.137,867.301 L106.51,889.928 L83.8822,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:32\\\">\\n\",\n              \"<path d=\\\"M38.6274,776.791 L61.2548,754.164 L83.8822,776.791 L61.2548,799.419 L38.6274,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,776.791 L61.2548,754.164 L83.8822,776.791 L61.2548,799.419 L38.6274,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:32\\\">\\n\",\n              \"<path d=\\\"M61.2548,799.419 L83.8822,776.791 L106.51,799.419 L83.8822,822.046 L61.2548,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,799.419 L83.8822,776.791 L106.51,799.419 L83.8822,822.046 L61.2548,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:32\\\">\\n\",\n              \"<path d=\\\"M83.8822,822.046 L106.51,799.419 L129.137,822.046 L106.51,844.673 L83.8822,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,822.046 L106.51,799.419 L129.137,822.046 L106.51,844.673 L83.8822,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:32\\\">\\n\",\n              \"<path d=\\\"M16,844.673 L38.6274,822.046 L61.2548,844.673 L38.6274,867.301 L16,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,844.673 L38.6274,822.046 L61.2548,844.673 L38.6274,867.301 L16,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:33\\\">\\n\",\n              \"<path d=\\\"M223.168,776.791 L245.796,754.164 L268.423,776.791 L245.796,799.419 L223.168,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,776.791 L245.796,754.164 L268.423,776.791 L245.796,799.419 L223.168,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:33\\\">\\n\",\n              \"<path d=\\\"M200.541,844.673 L223.168,822.046 L245.796,844.673 L223.168,867.301 L200.541,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,844.673 L223.168,822.046 L245.796,844.673 L223.168,867.301 L200.541,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:38\\\">\\n\",\n              \"<path d=\\\"M1213.76,799.419 L1236.38,776.791 L1259.01,799.419 L1236.38,822.046 L1213.76,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,799.419 L1236.38,776.791 L1259.01,799.419 L1236.38,822.046 L1213.76,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:38\\\">\\n\",\n              \"<path d=\\\"M1191.13,867.301 L1213.76,844.673 L1236.38,867.301 L1213.76,889.928 L1191.13,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,867.301 L1213.76,844.673 L1236.38,867.301 L1213.76,889.928 L1191.13,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:39\\\">\\n\",\n              \"<path d=\\\"M1398.3,799.419 L1420.92,776.791 L1443.55,799.419 L1420.92,822.046 L1398.3,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,799.419 L1420.92,776.791 L1443.55,799.419 L1420.92,822.046 L1398.3,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:39\\\">\\n\",\n              \"<path d=\\\"M1330.41,822.046 L1353.04,799.419 L1375.67,822.046 L1353.04,844.673 L1330.41,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,822.046 L1353.04,799.419 L1375.67,822.046 L1353.04,844.673 L1330.41,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:39\\\">\\n\",\n              \"<path d=\\\"M1353.04,844.673 L1375.67,822.046 L1398.3,844.673 L1375.67,867.301 L1353.04,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,844.673 L1375.67,822.046 L1398.3,844.673 L1375.67,867.301 L1353.04,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:39\\\">\\n\",\n              \"<path d=\\\"M1375.67,867.301 L1398.3,844.673 L1420.92,867.301 L1398.3,889.928 L1375.67,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,867.301 L1398.3,844.673 L1420.92,867.301 L1398.3,889.928 L1375.67,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:39\\\">\\n\",\n              \"<path d=\\\"M1330.41,776.791 L1353.04,754.164 L1375.67,776.791 L1353.04,799.419 L1330.41,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,776.791 L1353.04,754.164 L1375.67,776.791 L1353.04,799.419 L1330.41,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:39\\\">\\n\",\n              \"<path d=\\\"M1353.04,799.419 L1375.67,776.791 L1398.3,799.419 L1375.67,822.046 L1353.04,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,799.419 L1375.67,776.791 L1398.3,799.419 L1375.67,822.046 L1353.04,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:39\\\">\\n\",\n              \"<path d=\\\"M1375.67,822.046 L1398.3,799.419 L1420.92,822.046 L1398.3,844.673 L1375.67,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,822.046 L1398.3,799.419 L1420.92,822.046 L1398.3,844.673 L1375.67,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:39\\\">\\n\",\n              \"<path d=\\\"M1307.79,844.673 L1330.41,822.046 L1353.04,844.673 L1330.41,867.301 L1307.79,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,844.673 L1330.41,822.046 L1353.04,844.673 L1330.41,867.301 L1307.79,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:40\\\">\\n\",\n              \"<path d=\\\"M38.6274,961.332 L61.2548,938.705 L83.8822,961.332 L61.2548,983.96 L38.6274,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,961.332 L61.2548,938.705 L83.8822,961.332 L61.2548,983.96 L38.6274,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:40\\\">\\n\",\n              \"<path d=\\\"M16,1029.21 L38.6274,1006.59 L61.2548,1029.21 L38.6274,1051.84 L16,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,1029.21 L38.6274,1006.59 L61.2548,1029.21 L38.6274,1051.84 L16,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:45\\\">\\n\",\n              \"<path d=\\\"M1029.21,983.96 L1051.84,961.332 L1074.47,983.96 L1051.84,1006.59 L1029.21,983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,983.96 L1051.84,961.332 L1074.47,983.96 L1051.84,1006.59 L1029.21,983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:45\\\">\\n\",\n              \"<path d=\\\"M1006.59,1051.84 L1029.21,1029.21 L1051.84,1051.84 L1029.21,1074.47 L1006.59,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1051.84 L1029.21,1029.21 L1051.84,1051.84 L1029.21,1074.47 L1006.59,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:46\\\">\\n\",\n              \"<path d=\\\"M1213.76,983.96 L1236.38,961.332 L1259.01,983.96 L1236.38,1006.59 L1213.76,983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,983.96 L1236.38,961.332 L1259.01,983.96 L1236.38,1006.59 L1213.76,983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:46\\\">\\n\",\n              \"<path d=\\\"M1145.87,1006.59 L1168.5,983.96 L1191.13,1006.59 L1168.5,1029.21 L1145.87,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1006.59 L1168.5,983.96 L1191.13,1006.59 L1168.5,1029.21 L1145.87,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:46\\\">\\n\",\n              \"<path d=\\\"M1168.5,1029.21 L1191.13,1006.59 L1213.76,1029.21 L1191.13,1051.84 L1168.5,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,1029.21 L1191.13,1006.59 L1213.76,1029.21 L1191.13,1051.84 L1168.5,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:46\\\">\\n\",\n              \"<path d=\\\"M1191.13,1051.84 L1213.76,1029.21 L1236.38,1051.84 L1213.76,1074.47 L1191.13,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1051.84 L1213.76,1029.21 L1236.38,1051.84 L1213.76,1074.47 L1191.13,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:46\\\">\\n\",\n              \"<path d=\\\"M1145.87,961.332 L1168.5,938.705 L1191.13,961.332 L1168.5,983.96 L1145.87,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,961.332 L1168.5,938.705 L1191.13,961.332 L1168.5,983.96 L1145.87,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:46\\\">\\n\",\n              \"<path d=\\\"M1168.5,983.96 L1191.13,961.332 L1213.76,983.96 L1191.13,1006.59 L1168.5,983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,983.96 L1191.13,961.332 L1213.76,983.96 L1191.13,1006.59 L1168.5,983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:46\\\">\\n\",\n              \"<path d=\\\"M1191.13,1006.59 L1213.76,983.96 L1236.38,1006.59 L1213.76,1029.21 L1191.13,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1006.59 L1213.76,983.96 L1236.38,1006.59 L1213.76,1029.21 L1191.13,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:46\\\">\\n\",\n              \"<path d=\\\"M1123.25,1029.21 L1145.87,1006.59 L1168.5,1029.21 L1145.87,1051.84 L1123.25,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,1029.21 L1145.87,1006.59 L1168.5,1029.21 L1145.87,1051.84 L1123.25,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:47\\\">\\n\",\n              \"<path d=\\\"M1330.41,961.332 L1353.04,938.705 L1375.67,961.332 L1353.04,983.96 L1330.41,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,961.332 L1353.04,938.705 L1375.67,961.332 L1353.04,983.96 L1330.41,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:47\\\">\\n\",\n              \"<path d=\\\"M1307.79,1029.21 L1330.41,1006.59 L1353.04,1029.21 L1330.41,1051.84 L1307.79,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,1029.21 L1330.41,1006.59 L1353.04,1029.21 L1330.41,1051.84 L1307.79,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:52\\\">\\n\",\n              \"<path d=\\\"M844.673,1168.5 L867.301,1145.87 L889.928,1168.5 L867.301,1191.13 L844.673,1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1168.5 L867.301,1145.87 L889.928,1168.5 L867.301,1191.13 L844.673,1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:52\\\">\\n\",\n              \"<path d=\\\"M822.046,1236.38 L844.673,1213.76 L867.301,1236.38 L844.673,1259.01 L822.046,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1236.38 L844.673,1213.76 L867.301,1236.38 L844.673,1259.01 L822.046,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:53\\\">\\n\",\n              \"<path d=\\\"M1029.21,1168.5 L1051.84,1145.87 L1074.47,1168.5 L1051.84,1191.13 L1029.21,1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,1168.5 L1051.84,1145.87 L1074.47,1168.5 L1051.84,1191.13 L1029.21,1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:53\\\">\\n\",\n              \"<path d=\\\"M961.332,1191.13 L983.96,1168.5 L1006.59,1191.13 L983.96,1213.76 L961.332,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1191.13 L983.96,1168.5 L1006.59,1191.13 L983.96,1213.76 L961.332,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:53\\\">\\n\",\n              \"<path d=\\\"M983.96,1213.76 L1006.59,1191.13 L1029.21,1213.76 L1006.59,1236.38 L983.96,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1213.76 L1006.59,1191.13 L1029.21,1213.76 L1006.59,1236.38 L983.96,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:53\\\">\\n\",\n              \"<path d=\\\"M1006.59,1236.38 L1029.21,1213.76 L1051.84,1236.38 L1029.21,1259.01 L1006.59,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1236.38 L1029.21,1213.76 L1051.84,1236.38 L1029.21,1259.01 L1006.59,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:53\\\">\\n\",\n              \"<path d=\\\"M961.332,1145.87 L983.96,1123.25 L1006.59,1145.87 L983.96,1168.5 L961.332,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1145.87 L983.96,1123.25 L1006.59,1145.87 L983.96,1168.5 L961.332,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:53\\\">\\n\",\n              \"<path d=\\\"M983.96,1168.5 L1006.59,1145.87 L1029.21,1168.5 L1006.59,1191.13 L983.96,1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1168.5 L1006.59,1145.87 L1029.21,1168.5 L1006.59,1191.13 L983.96,1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:53\\\">\\n\",\n              \"<path d=\\\"M1006.59,1191.13 L1029.21,1168.5 L1051.84,1191.13 L1029.21,1213.76 L1006.59,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1191.13 L1029.21,1168.5 L1051.84,1191.13 L1029.21,1213.76 L1006.59,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:53\\\">\\n\",\n              \"<path d=\\\"M938.705,1213.76 L961.332,1191.13 L983.96,1213.76 L961.332,1236.38 L938.705,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,1213.76 L961.332,1191.13 L983.96,1213.76 L961.332,1236.38 L938.705,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:54\\\">\\n\",\n              \"<path d=\\\"M1145.87,1145.87 L1168.5,1123.25 L1191.13,1145.87 L1168.5,1168.5 L1145.87,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1145.87 L1168.5,1123.25 L1191.13,1145.87 L1168.5,1168.5 L1145.87,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:54\\\">\\n\",\n              \"<path d=\\\"M1123.25,1213.76 L1145.87,1191.13 L1168.5,1213.76 L1145.87,1236.38 L1123.25,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,1213.76 L1145.87,1191.13 L1168.5,1213.76 L1145.87,1236.38 L1123.25,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:59\\\">\\n\",\n              \"<path d=\\\"M660.133,1353.04 L682.76,1330.41 L705.387,1353.04 L682.76,1375.67 L660.133,1353.04\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,1353.04 L682.76,1330.41 L705.387,1353.04 L682.76,1375.67 L660.133,1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:59\\\">\\n\",\n              \"<path d=\\\"M637.505,1420.92 L660.133,1398.3 L682.76,1420.92 L660.133,1443.55 L637.505,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1420.92 L660.133,1398.3 L682.76,1420.92 L660.133,1443.55 L637.505,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:60\\\">\\n\",\n              \"<path d=\\\"M844.673,1353.04 L867.301,1330.41 L889.928,1353.04 L867.301,1375.67 L844.673,1353.04\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1353.04 L867.301,1330.41 L889.928,1353.04 L867.301,1375.67 L844.673,1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:60\\\">\\n\",\n              \"<path d=\\\"M776.791,1375.67 L799.419,1353.04 L822.046,1375.67 L799.419,1398.3 L776.791,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1375.67 L799.419,1353.04 L822.046,1375.67 L799.419,1398.3 L776.791,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:60\\\">\\n\",\n              \"<path d=\\\"M799.419,1398.3 L822.046,1375.67 L844.673,1398.3 L822.046,1420.92 L799.419,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1398.3 L822.046,1375.67 L844.673,1398.3 L822.046,1420.92 L799.419,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:60\\\">\\n\",\n              \"<path d=\\\"M822.046,1420.92 L844.673,1398.3 L867.301,1420.92 L844.673,1443.55 L822.046,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1420.92 L844.673,1398.3 L867.301,1420.92 L844.673,1443.55 L822.046,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:60\\\">\\n\",\n              \"<path d=\\\"M754.164,1398.3 L776.791,1375.67 L799.419,1398.3 L776.791,1420.92 L754.164,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,1398.3 L776.791,1375.67 L799.419,1398.3 L776.791,1420.92 L754.164,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:60\\\">\\n\",\n              \"<path d=\\\"M799.419,1353.04 L822.046,1330.41 L844.673,1353.04 L822.046,1375.67 L799.419,1353.04\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1353.04 L822.046,1330.41 L844.673,1353.04 L822.046,1375.67 L799.419,1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:61\\\">\\n\",\n              \"<path d=\\\"M938.705,1398.3 L961.332,1375.67 L983.96,1398.3 L961.332,1420.92 L938.705,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,1398.3 L961.332,1375.67 L983.96,1398.3 L961.332,1420.92 L938.705,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:1\\\">\\n\",\n              \"<path d=\\\"M200.541,106.51 L223.168,83.8822 L223.168,129.137 L200.541,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,106.51 L223.168,83.8822 L223.168,129.137 L200.541,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:1\\\">\\n\",\n              \"<path d=\\\"M313.678,38.6274 L336.305,61.2548 L313.678,83.8822 L313.678,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,38.6274 L336.305,61.2548 L313.678,83.8822 L313.678,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:2\\\">\\n\",\n              \"<path d=\\\"M385.082,106.51 L407.709,83.8822 L407.709,129.137 L385.082,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,106.51 L407.709,83.8822 L407.709,129.137 L385.082,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:2\\\">\\n\",\n              \"<path d=\\\"M498.219,38.6274 L520.846,61.2548 L498.219,83.8822 L498.219,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,38.6274 L520.846,61.2548 L498.219,83.8822 L498.219,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:4\\\">\\n\",\n              \"<path d=\\\"M776.791,38.6274 L799.419,61.2548 L776.791,83.8822 L776.791,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,38.6274 L799.419,61.2548 L776.791,83.8822 L776.791,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:4\\\">\\n\",\n              \"<path d=\\\"M799.419,106.51 L822.046,129.137 L776.791,129.137 L799.419,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,106.51 L822.046,129.137 L776.791,129.137 L799.419,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:4\\\">\\n\",\n              \"<path d=\\\"M844.673,106.51 L867.301,83.8822 L867.301,129.137 L844.673,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,106.51 L867.301,83.8822 L867.301,129.137 L844.673,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:6\\\">\\n\",\n              \"<path d=\\\"M1168.5,16 L1191.13,38.6274 L1145.87,38.6274 L1168.5,16\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,16 L1191.13,38.6274 L1145.87,38.6274 L1168.5,16\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1236.38,38.6274 L1259.01,61.2548 L1236.38,83.8822 L1236.38,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,38.6274 L1259.01,61.2548 L1236.38,83.8822 L1236.38,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1123.25,106.51 L1145.87,83.8822 L1145.87,129.137 L1123.25,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,106.51 L1145.87,83.8822 L1145.87,129.137 L1123.25,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:6\\\">\\n\",\n              \"<path d=\\\"M1191.13,129.137 L1236.38,129.137 L1213.76,151.764 L1191.13,129.137\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,129.137 L1236.38,129.137 L1213.76,151.764 L1191.13,129.137\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:7\\\">\\n\",\n              \"<path d=\\\"M1353.04,16 L1375.67,38.6274 L1330.41,38.6274 L1353.04,16\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip32\\\"><path d=\\\"M1353.04,16 L1375.67,38.6274 L1330.41,38.6274 L1353.04,16\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip32)\\\" cx=\\\"1330.41\\\" cy=\\\"38.6274\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip32)\\\" cx=\\\"1353.04\\\" cy=\\\"16\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip32)\\\" cx=\\\"1375.67\\\" cy=\\\"38.6274\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,16 L1375.67,38.6274 L1330.41,38.6274 L1353.04,16\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:7\\\">\\n\",\n              \"<path d=\\\"M1420.92,38.6274 L1443.55,61.2548 L1420.92,83.8822 L1420.92,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,38.6274 L1443.55,61.2548 L1420.92,83.8822 L1420.92,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:7\\\">\\n\",\n              \"<path d=\\\"M1307.79,106.51 L1330.41,83.8822 L1330.41,129.137 L1307.79,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,106.51 L1330.41,83.8822 L1330.41,129.137 L1307.79,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:7\\\">\\n\",\n              \"<path d=\\\"M1375.67,129.137 L1420.92,129.137 L1398.3,151.764 L1375.67,129.137\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip33\\\"><path d=\\\"M1375.67,129.137 L1420.92,129.137 L1398.3,151.764 L1375.67,129.137\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip33)\\\" cx=\\\"1375.67\\\" cy=\\\"129.137\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip33)\\\" cx=\\\"1420.92\\\" cy=\\\"129.137\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip33)\\\" cx=\\\"1398.3\\\" cy=\\\"151.764\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,129.137 L1420.92,129.137 L1398.3,151.764 L1375.67,129.137\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:8\\\">\\n\",\n              \"<path d=\\\"M61.2548,200.541 L83.8822,223.168 L38.6274,223.168 L61.2548,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip34\\\"><path d=\\\"M61.2548,200.541 L83.8822,223.168 L38.6274,223.168 L61.2548,200.541\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip34)\\\" cx=\\\"38.6274\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip34)\\\" cx=\\\"61.2548\\\" cy=\\\"200.541\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip34)\\\" cx=\\\"83.8822\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,200.541 L83.8822,223.168 L38.6274,223.168 L61.2548,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:8\\\">\\n\",\n              \"<path d=\\\"M129.137,223.168 L151.764,245.796 L129.137,268.423 L129.137,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,223.168 L151.764,245.796 L129.137,268.423 L129.137,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:8\\\">\\n\",\n              \"<path d=\\\"M16,291.051 L38.6274,268.423 L38.6274,313.678 L16,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,291.051 L38.6274,268.423 L38.6274,313.678 L16,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:8\\\">\\n\",\n              \"<path d=\\\"M83.8822,313.678 L129.137,313.678 L106.51,336.305 L83.8822,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip35\\\"><path d=\\\"M83.8822,313.678 L129.137,313.678 L106.51,336.305 L83.8822,313.678\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip35)\\\" cx=\\\"83.8822\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip35)\\\" cx=\\\"129.137\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip35)\\\" cx=\\\"106.51\\\" cy=\\\"336.305\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,313.678 L129.137,313.678 L106.51,336.305 L83.8822,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:9\\\">\\n\",\n              \"<path d=\\\"M245.796,200.541 L268.423,223.168 L223.168,223.168 L245.796,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,200.541 L268.423,223.168 L223.168,223.168 L245.796,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:9\\\">\\n\",\n              \"<path d=\\\"M313.678,223.168 L336.305,245.796 L313.678,268.423 L313.678,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,223.168 L336.305,245.796 L313.678,268.423 L313.678,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:9\\\">\\n\",\n              \"<path d=\\\"M200.541,291.051 L223.168,268.423 L223.168,313.678 L200.541,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,291.051 L223.168,268.423 L223.168,313.678 L200.541,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:9\\\">\\n\",\n              \"<path d=\\\"M268.423,313.678 L313.678,313.678 L291.051,336.305 L268.423,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,313.678 L313.678,313.678 L291.051,336.305 L268.423,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:11\\\">\\n\",\n              \"<path d=\\\"M592.25,223.168 L614.878,245.796 L592.25,268.423 L592.25,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,223.168 L614.878,245.796 L592.25,268.423 L592.25,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:11\\\">\\n\",\n              \"<path d=\\\"M637.505,223.168 L682.76,223.168 L660.133,245.796 L637.505,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,223.168 L682.76,223.168 L660.133,245.796 L637.505,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:11\\\">\\n\",\n              \"<path d=\\\"M614.878,291.051 L637.505,313.678 L592.25,313.678 L614.878,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,291.051 L637.505,313.678 L592.25,313.678 L614.878,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:11\\\">\\n\",\n              \"<path d=\\\"M660.133,291.051 L682.76,268.423 L682.76,313.678 L660.133,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,291.051 L682.76,268.423 L682.76,313.678 L660.133,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:13\\\">\\n\",\n              \"<path d=\\\"M983.96,200.541 L1006.59,223.168 L961.332,223.168 L983.96,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,200.541 L1006.59,223.168 L961.332,223.168 L983.96,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:13\\\">\\n\",\n              \"<path d=\\\"M1051.84,223.168 L1074.47,245.796 L1051.84,268.423 L1051.84,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,223.168 L1074.47,245.796 L1051.84,268.423 L1051.84,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:13\\\">\\n\",\n              \"<path d=\\\"M938.705,291.051 L961.332,268.423 L961.332,313.678 L938.705,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,291.051 L961.332,268.423 L961.332,313.678 L938.705,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:13\\\">\\n\",\n              \"<path d=\\\"M1006.59,313.678 L1051.84,313.678 L1029.21,336.305 L1006.59,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,313.678 L1051.84,313.678 L1029.21,336.305 L1006.59,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:14\\\">\\n\",\n              \"<path d=\\\"M1168.5,200.541 L1191.13,223.168 L1145.87,223.168 L1168.5,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip36\\\"><path d=\\\"M1168.5,200.541 L1191.13,223.168 L1145.87,223.168 L1168.5,200.541\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip36)\\\" cx=\\\"1145.87\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip36)\\\" cx=\\\"1168.5\\\" cy=\\\"200.541\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip36)\\\" cx=\\\"1191.13\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,200.541 L1191.13,223.168 L1145.87,223.168 L1168.5,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:14\\\">\\n\",\n              \"<path d=\\\"M1236.38,223.168 L1259.01,245.796 L1236.38,268.423 L1236.38,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,223.168 L1259.01,245.796 L1236.38,268.423 L1236.38,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:14\\\">\\n\",\n              \"<path d=\\\"M1123.25,291.051 L1145.87,268.423 L1145.87,313.678 L1123.25,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,291.051 L1145.87,268.423 L1145.87,313.678 L1123.25,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:14\\\">\\n\",\n              \"<path d=\\\"M1191.13,313.678 L1236.38,313.678 L1213.76,336.305 L1191.13,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip37\\\"><path d=\\\"M1191.13,313.678 L1236.38,313.678 L1213.76,336.305 L1191.13,313.678\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip37)\\\" cx=\\\"1191.13\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip37)\\\" cx=\\\"1236.38\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip37)\\\" cx=\\\"1213.76\\\" cy=\\\"336.305\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,313.678 L1236.38,313.678 L1213.76,336.305 L1191.13,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:15\\\">\\n\",\n              \"<path d=\\\"M1353.04,200.541 L1375.67,223.168 L1330.41,223.168 L1353.04,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip38\\\"><path d=\\\"M1353.04,200.541 L1375.67,223.168 L1330.41,223.168 L1353.04,200.541\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip38)\\\" cx=\\\"1330.41\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip38)\\\" cx=\\\"1353.04\\\" cy=\\\"200.541\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip38)\\\" cx=\\\"1375.67\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,200.541 L1375.67,223.168 L1330.41,223.168 L1353.04,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:15\\\">\\n\",\n              \"<path d=\\\"M1420.92,223.168 L1443.55,245.796 L1420.92,268.423 L1420.92,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,223.168 L1443.55,245.796 L1420.92,268.423 L1420.92,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:15\\\">\\n\",\n              \"<path d=\\\"M1307.79,291.051 L1330.41,268.423 L1330.41,313.678 L1307.79,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,291.051 L1330.41,268.423 L1330.41,313.678 L1307.79,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:15\\\">\\n\",\n              \"<path d=\\\"M1375.67,313.678 L1420.92,313.678 L1398.3,336.305 L1375.67,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip39\\\"><path d=\\\"M1375.67,313.678 L1420.92,313.678 L1398.3,336.305 L1375.67,313.678\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip39)\\\" cx=\\\"1375.67\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip39)\\\" cx=\\\"1420.92\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip39)\\\" cx=\\\"1398.3\\\" cy=\\\"336.305\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,313.678 L1420.92,313.678 L1398.3,336.305 L1375.67,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:16\\\">\\n\",\n              \"<path d=\\\"M61.2548,385.082 L83.8822,407.709 L38.6274,407.709 L61.2548,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,385.082 L83.8822,407.709 L38.6274,407.709 L61.2548,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:16\\\">\\n\",\n              \"<path d=\\\"M129.137,407.709 L151.764,430.337 L129.137,452.964 L129.137,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,407.709 L151.764,430.337 L129.137,452.964 L129.137,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:16\\\">\\n\",\n              \"<path d=\\\"M16,475.592 L38.6274,452.964 L38.6274,498.219 L16,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,475.592 L38.6274,452.964 L38.6274,498.219 L16,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:16\\\">\\n\",\n              \"<path d=\\\"M83.8822,498.219 L129.137,498.219 L106.51,520.846 L83.8822,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,498.219 L129.137,498.219 L106.51,520.846 L83.8822,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:18\\\">\\n\",\n              \"<path d=\\\"M407.709,407.709 L430.337,430.337 L407.709,452.964 L407.709,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,407.709 L430.337,430.337 L407.709,452.964 L407.709,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:18\\\">\\n\",\n              \"<path d=\\\"M452.964,407.709 L498.219,407.709 L475.592,430.337 L452.964,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,407.709 L498.219,407.709 L475.592,430.337 L452.964,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:18\\\">\\n\",\n              \"<path d=\\\"M430.337,475.592 L452.964,498.219 L407.709,498.219 L430.337,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,475.592 L452.964,498.219 L407.709,498.219 L430.337,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:18\\\">\\n\",\n              \"<path d=\\\"M475.592,475.592 L498.219,452.964 L498.219,498.219 L475.592,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,475.592 L498.219,452.964 L498.219,498.219 L475.592,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:20\\\">\\n\",\n              \"<path d=\\\"M799.419,385.082 L822.046,407.709 L776.791,407.709 L799.419,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,385.082 L822.046,407.709 L776.791,407.709 L799.419,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:20\\\">\\n\",\n              \"<path d=\\\"M867.301,407.709 L889.928,430.337 L867.301,452.964 L867.301,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,407.709 L889.928,430.337 L867.301,452.964 L867.301,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:20\\\">\\n\",\n              \"<path d=\\\"M754.164,475.592 L776.791,452.964 L776.791,498.219 L754.164,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,475.592 L776.791,452.964 L776.791,498.219 L754.164,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:20\\\">\\n\",\n              \"<path d=\\\"M822.046,498.219 L867.301,498.219 L844.673,520.846 L822.046,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,498.219 L867.301,498.219 L844.673,520.846 L822.046,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:21\\\">\\n\",\n              \"<path d=\\\"M983.96,385.082 L1006.59,407.709 L961.332,407.709 L983.96,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip40\\\"><path d=\\\"M983.96,385.082 L1006.59,407.709 L961.332,407.709 L983.96,385.082\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip40)\\\" cx=\\\"961.332\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip40)\\\" cx=\\\"983.96\\\" cy=\\\"385.082\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip40)\\\" cx=\\\"1006.59\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M983.96,385.082 L1006.59,407.709 L961.332,407.709 L983.96,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:21\\\">\\n\",\n              \"<path d=\\\"M1051.84,407.709 L1074.47,430.337 L1051.84,452.964 L1051.84,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,407.709 L1074.47,430.337 L1051.84,452.964 L1051.84,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:21\\\">\\n\",\n              \"<path d=\\\"M938.705,475.592 L961.332,452.964 L961.332,498.219 L938.705,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,475.592 L961.332,452.964 L961.332,498.219 L938.705,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:21\\\">\\n\",\n              \"<path d=\\\"M1006.59,498.219 L1051.84,498.219 L1029.21,520.846 L1006.59,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip41\\\"><path d=\\\"M1006.59,498.219 L1051.84,498.219 L1029.21,520.846 L1006.59,498.219\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip41)\\\" cx=\\\"1006.59\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip41)\\\" cx=\\\"1051.84\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip41)\\\" cx=\\\"1029.21\\\" cy=\\\"520.846\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,498.219 L1051.84,498.219 L1029.21,520.846 L1006.59,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:22\\\">\\n\",\n              \"<path d=\\\"M1168.5,385.082 L1191.13,407.709 L1145.87,407.709 L1168.5,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip42\\\"><path d=\\\"M1168.5,385.082 L1191.13,407.709 L1145.87,407.709 L1168.5,385.082\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip42)\\\" cx=\\\"1145.87\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip42)\\\" cx=\\\"1168.5\\\" cy=\\\"385.082\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip42)\\\" cx=\\\"1191.13\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,385.082 L1191.13,407.709 L1145.87,407.709 L1168.5,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:22\\\">\\n\",\n              \"<path d=\\\"M1236.38,407.709 L1259.01,430.337 L1236.38,452.964 L1236.38,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,407.709 L1259.01,430.337 L1236.38,452.964 L1236.38,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:22\\\">\\n\",\n              \"<path d=\\\"M1123.25,475.592 L1145.87,452.964 L1145.87,498.219 L1123.25,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,475.592 L1145.87,452.964 L1145.87,498.219 L1123.25,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:22\\\">\\n\",\n              \"<path d=\\\"M1191.13,498.219 L1236.38,498.219 L1213.76,520.846 L1191.13,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip43\\\"><path d=\\\"M1191.13,498.219 L1236.38,498.219 L1213.76,520.846 L1191.13,498.219\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip43)\\\" cx=\\\"1191.13\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip43)\\\" cx=\\\"1236.38\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip43)\\\" cx=\\\"1213.76\\\" cy=\\\"520.846\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,498.219 L1236.38,498.219 L1213.76,520.846 L1191.13,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:23\\\">\\n\",\n              \"<path d=\\\"M1353.04,385.082 L1375.67,407.709 L1330.41,407.709 L1353.04,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,385.082 L1375.67,407.709 L1330.41,407.709 L1353.04,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:23\\\">\\n\",\n              \"<path d=\\\"M1420.92,407.709 L1443.55,430.337 L1420.92,452.964 L1420.92,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,407.709 L1443.55,430.337 L1420.92,452.964 L1420.92,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:23\\\">\\n\",\n              \"<path d=\\\"M1307.79,475.592 L1330.41,452.964 L1330.41,498.219 L1307.79,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,475.592 L1330.41,452.964 L1330.41,498.219 L1307.79,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:23\\\">\\n\",\n              \"<path d=\\\"M1375.67,498.219 L1420.92,498.219 L1398.3,520.846 L1375.67,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,498.219 L1420.92,498.219 L1398.3,520.846 L1375.67,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:25\\\">\\n\",\n              \"<path d=\\\"M223.168,592.25 L245.796,614.878 L223.168,637.505 L223.168,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,592.25 L245.796,614.878 L223.168,637.505 L223.168,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:25\\\">\\n\",\n              \"<path d=\\\"M268.423,592.25 L313.678,592.25 L291.051,614.878 L268.423,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,592.25 L313.678,592.25 L291.051,614.878 L268.423,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:25\\\">\\n\",\n              \"<path d=\\\"M245.796,660.133 L268.423,682.76 L223.168,682.76 L245.796,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,660.133 L268.423,682.76 L223.168,682.76 L245.796,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:25\\\">\\n\",\n              \"<path d=\\\"M291.051,660.133 L313.678,637.505 L313.678,682.76 L291.051,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,660.133 L313.678,637.505 L313.678,682.76 L291.051,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:27\\\">\\n\",\n              \"<path d=\\\"M614.878,569.623 L637.505,592.25 L592.25,592.25 L614.878,569.623\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,569.623 L637.505,592.25 L592.25,592.25 L614.878,569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:27\\\">\\n\",\n              \"<path d=\\\"M682.76,592.25 L705.387,614.878 L682.76,637.505 L682.76,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,592.25 L705.387,614.878 L682.76,637.505 L682.76,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:27\\\">\\n\",\n              \"<path d=\\\"M569.623,660.133 L592.25,637.505 L592.25,682.76 L569.623,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,660.133 L592.25,637.505 L592.25,682.76 L569.623,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:27\\\">\\n\",\n              \"<path d=\\\"M637.505,682.76 L682.76,682.76 L660.133,705.387 L637.505,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,682.76 L682.76,682.76 L660.133,705.387 L637.505,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:28\\\">\\n\",\n              \"<path d=\\\"M799.419,569.623 L822.046,592.25 L776.791,592.25 L799.419,569.623\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip44\\\"><path d=\\\"M799.419,569.623 L822.046,592.25 L776.791,592.25 L799.419,569.623\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip44)\\\" cx=\\\"776.791\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip44)\\\" cx=\\\"799.419\\\" cy=\\\"569.623\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip44)\\\" cx=\\\"822.046\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M799.419,569.623 L822.046,592.25 L776.791,592.25 L799.419,569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:28\\\">\\n\",\n              \"<path d=\\\"M867.301,592.25 L889.928,614.878 L867.301,637.505 L867.301,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,592.25 L889.928,614.878 L867.301,637.505 L867.301,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:28\\\">\\n\",\n              \"<path d=\\\"M754.164,660.133 L776.791,637.505 L776.791,682.76 L754.164,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,660.133 L776.791,637.505 L776.791,682.76 L754.164,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:28\\\">\\n\",\n              \"<path d=\\\"M822.046,682.76 L867.301,682.76 L844.673,705.387 L822.046,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip45\\\"><path d=\\\"M822.046,682.76 L867.301,682.76 L844.673,705.387 L822.046,682.76\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip45)\\\" cx=\\\"822.046\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip45)\\\" cx=\\\"867.301\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip45)\\\" cx=\\\"844.673\\\" cy=\\\"705.387\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M822.046,682.76 L867.301,682.76 L844.673,705.387 L822.046,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:29\\\">\\n\",\n              \"<path d=\\\"M983.96,569.623 L1006.59,592.25 L961.332,592.25 L983.96,569.623\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip46\\\"><path d=\\\"M983.96,569.623 L1006.59,592.25 L961.332,592.25 L983.96,569.623\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip46)\\\" cx=\\\"961.332\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip46)\\\" cx=\\\"983.96\\\" cy=\\\"569.623\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip46)\\\" cx=\\\"1006.59\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M983.96,569.623 L1006.59,592.25 L961.332,592.25 L983.96,569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:29\\\">\\n\",\n              \"<path d=\\\"M1051.84,592.25 L1074.47,614.878 L1051.84,637.505 L1051.84,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,592.25 L1074.47,614.878 L1051.84,637.505 L1051.84,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:29\\\">\\n\",\n              \"<path d=\\\"M938.705,660.133 L961.332,637.505 L961.332,682.76 L938.705,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,660.133 L961.332,637.505 L961.332,682.76 L938.705,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:29\\\">\\n\",\n              \"<path d=\\\"M1006.59,682.76 L1051.84,682.76 L1029.21,705.387 L1006.59,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip47\\\"><path d=\\\"M1006.59,682.76 L1051.84,682.76 L1029.21,705.387 L1006.59,682.76\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip47)\\\" cx=\\\"1006.59\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip47)\\\" cx=\\\"1051.84\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip47)\\\" cx=\\\"1029.21\\\" cy=\\\"705.387\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,682.76 L1051.84,682.76 L1029.21,705.387 L1006.59,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:30\\\">\\n\",\n              \"<path d=\\\"M1168.5,569.623 L1191.13,592.25 L1145.87,592.25 L1168.5,569.623\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,569.623 L1191.13,592.25 L1145.87,592.25 L1168.5,569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:30\\\">\\n\",\n              \"<path d=\\\"M1236.38,592.25 L1259.01,614.878 L1236.38,637.505 L1236.38,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,592.25 L1259.01,614.878 L1236.38,637.505 L1236.38,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:30\\\">\\n\",\n              \"<path d=\\\"M1123.25,660.133 L1145.87,637.505 L1145.87,682.76 L1123.25,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,660.133 L1145.87,637.505 L1145.87,682.76 L1123.25,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:30\\\">\\n\",\n              \"<path d=\\\"M1191.13,682.76 L1236.38,682.76 L1213.76,705.387 L1191.13,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,682.76 L1236.38,682.76 L1213.76,705.387 L1191.13,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:32\\\">\\n\",\n              \"<path d=\\\"M38.6274,776.791 L61.2548,799.419 L38.6274,822.046 L38.6274,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,776.791 L61.2548,799.419 L38.6274,822.046 L38.6274,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:32\\\">\\n\",\n              \"<path d=\\\"M83.8822,776.791 L129.137,776.791 L106.51,799.419 L83.8822,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,776.791 L129.137,776.791 L106.51,799.419 L83.8822,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:32\\\">\\n\",\n              \"<path d=\\\"M61.2548,844.673 L83.8822,867.301 L38.6274,867.301 L61.2548,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,844.673 L83.8822,867.301 L38.6274,867.301 L61.2548,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:32\\\">\\n\",\n              \"<path d=\\\"M106.51,844.673 L129.137,822.046 L129.137,867.301 L106.51,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,844.673 L129.137,822.046 L129.137,867.301 L106.51,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:34\\\">\\n\",\n              \"<path d=\\\"M430.337,754.164 L452.964,776.791 L407.709,776.791 L430.337,754.164\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,754.164 L452.964,776.791 L407.709,776.791 L430.337,754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:34\\\">\\n\",\n              \"<path d=\\\"M498.219,776.791 L520.846,799.419 L498.219,822.046 L498.219,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,776.791 L520.846,799.419 L498.219,822.046 L498.219,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:34\\\">\\n\",\n              \"<path d=\\\"M385.082,844.673 L407.709,822.046 L407.709,867.301 L385.082,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,844.673 L407.709,822.046 L407.709,867.301 L385.082,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:34\\\">\\n\",\n              \"<path d=\\\"M452.964,867.301 L498.219,867.301 L475.592,889.928 L452.964,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,867.301 L498.219,867.301 L475.592,889.928 L452.964,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:35\\\">\\n\",\n              \"<path d=\\\"M614.878,754.164 L637.505,776.791 L592.25,776.791 L614.878,754.164\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip48\\\"><path d=\\\"M614.878,754.164 L637.505,776.791 L592.25,776.791 L614.878,754.164\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip48)\\\" cx=\\\"592.25\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip48)\\\" cx=\\\"614.878\\\" cy=\\\"754.164\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip48)\\\" cx=\\\"637.505\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M614.878,754.164 L637.505,776.791 L592.25,776.791 L614.878,754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:35\\\">\\n\",\n              \"<path d=\\\"M682.76,776.791 L705.387,799.419 L682.76,822.046 L682.76,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,776.791 L705.387,799.419 L682.76,822.046 L682.76,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:35\\\">\\n\",\n              \"<path d=\\\"M569.623,844.673 L592.25,822.046 L592.25,867.301 L569.623,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,844.673 L592.25,822.046 L592.25,867.301 L569.623,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:35\\\">\\n\",\n              \"<path d=\\\"M637.505,867.301 L682.76,867.301 L660.133,889.928 L637.505,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip49\\\"><path d=\\\"M637.505,867.301 L682.76,867.301 L660.133,889.928 L637.505,867.301\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip49)\\\" cx=\\\"637.505\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip49)\\\" cx=\\\"682.76\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip49)\\\" cx=\\\"660.133\\\" cy=\\\"889.928\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M637.505,867.301 L682.76,867.301 L660.133,889.928 L637.505,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:36\\\">\\n\",\n              \"<path d=\\\"M799.419,754.164 L822.046,776.791 L776.791,776.791 L799.419,754.164\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip50\\\"><path d=\\\"M799.419,754.164 L822.046,776.791 L776.791,776.791 L799.419,754.164\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip50)\\\" cx=\\\"776.791\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip50)\\\" cx=\\\"799.419\\\" cy=\\\"754.164\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip50)\\\" cx=\\\"822.046\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M799.419,754.164 L822.046,776.791 L776.791,776.791 L799.419,754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:36\\\">\\n\",\n              \"<path d=\\\"M867.301,776.791 L889.928,799.419 L867.301,822.046 L867.301,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,776.791 L889.928,799.419 L867.301,822.046 L867.301,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:36\\\">\\n\",\n              \"<path d=\\\"M754.164,844.673 L776.791,822.046 L776.791,867.301 L754.164,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,844.673 L776.791,822.046 L776.791,867.301 L754.164,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:36\\\">\\n\",\n              \"<path d=\\\"M822.046,867.301 L867.301,867.301 L844.673,889.928 L822.046,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip51\\\"><path d=\\\"M822.046,867.301 L867.301,867.301 L844.673,889.928 L822.046,867.301\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip51)\\\" cx=\\\"822.046\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip51)\\\" cx=\\\"867.301\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip51)\\\" cx=\\\"844.673\\\" cy=\\\"889.928\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M822.046,867.301 L867.301,867.301 L844.673,889.928 L822.046,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:37\\\">\\n\",\n              \"<path d=\\\"M983.96,754.164 L1006.59,776.791 L961.332,776.791 L983.96,754.164\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,754.164 L1006.59,776.791 L961.332,776.791 L983.96,754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:37\\\">\\n\",\n              \"<path d=\\\"M1051.84,776.791 L1074.47,799.419 L1051.84,822.046 L1051.84,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,776.791 L1074.47,799.419 L1051.84,822.046 L1051.84,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:37\\\">\\n\",\n              \"<path d=\\\"M938.705,844.673 L961.332,822.046 L961.332,867.301 L938.705,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,844.673 L961.332,822.046 L961.332,867.301 L938.705,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:37\\\">\\n\",\n              \"<path d=\\\"M1006.59,867.301 L1051.84,867.301 L1029.21,889.928 L1006.59,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,867.301 L1051.84,867.301 L1029.21,889.928 L1006.59,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:39\\\">\\n\",\n              \"<path d=\\\"M1330.41,776.791 L1353.04,799.419 L1330.41,822.046 L1330.41,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,776.791 L1353.04,799.419 L1330.41,822.046 L1330.41,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:39\\\">\\n\",\n              \"<path d=\\\"M1375.67,776.791 L1420.92,776.791 L1398.3,799.419 L1375.67,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,776.791 L1420.92,776.791 L1398.3,799.419 L1375.67,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:39\\\">\\n\",\n              \"<path d=\\\"M1353.04,844.673 L1375.67,867.301 L1330.41,867.301 L1353.04,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,844.673 L1375.67,867.301 L1330.41,867.301 L1353.04,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:39\\\">\\n\",\n              \"<path d=\\\"M1398.3,844.673 L1420.92,822.046 L1420.92,867.301 L1398.3,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,844.673 L1420.92,822.046 L1420.92,867.301 L1398.3,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:41\\\">\\n\",\n              \"<path d=\\\"M245.796,938.705 L268.423,961.332 L223.168,961.332 L245.796,938.705\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,938.705 L268.423,961.332 L223.168,961.332 L245.796,938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:41\\\">\\n\",\n              \"<path d=\\\"M313.678,961.332 L336.305,983.96 L313.678,1006.59 L313.678,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,961.332 L336.305,983.96 L313.678,1006.59 L313.678,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:41\\\">\\n\",\n              \"<path d=\\\"M200.541,1029.21 L223.168,1006.59 L223.168,1051.84 L200.541,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,1029.21 L223.168,1006.59 L223.168,1051.84 L200.541,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:41\\\">\\n\",\n              \"<path d=\\\"M268.423,1051.84 L313.678,1051.84 L291.051,1074.47 L268.423,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1051.84 L313.678,1051.84 L291.051,1074.47 L268.423,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:42\\\">\\n\",\n              \"<path d=\\\"M430.337,938.705 L452.964,961.332 L407.709,961.332 L430.337,938.705\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip52\\\"><path d=\\\"M430.337,938.705 L452.964,961.332 L407.709,961.332 L430.337,938.705\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip52)\\\" cx=\\\"407.709\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip52)\\\" cx=\\\"430.337\\\" cy=\\\"938.705\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip52)\\\" cx=\\\"452.964\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M430.337,938.705 L452.964,961.332 L407.709,961.332 L430.337,938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:42\\\">\\n\",\n              \"<path d=\\\"M498.219,961.332 L520.846,983.96 L498.219,1006.59 L498.219,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,961.332 L520.846,983.96 L498.219,1006.59 L498.219,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:42\\\">\\n\",\n              \"<path d=\\\"M385.082,1029.21 L407.709,1006.59 L407.709,1051.84 L385.082,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,1029.21 L407.709,1006.59 L407.709,1051.84 L385.082,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:42\\\">\\n\",\n              \"<path d=\\\"M452.964,1051.84 L498.219,1051.84 L475.592,1074.47 L452.964,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip53\\\"><path d=\\\"M452.964,1051.84 L498.219,1051.84 L475.592,1074.47 L452.964,1051.84\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip53)\\\" cx=\\\"452.964\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip53)\\\" cx=\\\"498.219\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip53)\\\" cx=\\\"475.592\\\" cy=\\\"1074.47\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1051.84 L498.219,1051.84 L475.592,1074.47 L452.964,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:43\\\">\\n\",\n              \"<path d=\\\"M614.878,938.705 L637.505,961.332 L592.25,961.332 L614.878,938.705\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip54\\\"><path d=\\\"M614.878,938.705 L637.505,961.332 L592.25,961.332 L614.878,938.705\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip54)\\\" cx=\\\"592.25\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip54)\\\" cx=\\\"614.878\\\" cy=\\\"938.705\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip54)\\\" cx=\\\"637.505\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M614.878,938.705 L637.505,961.332 L592.25,961.332 L614.878,938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:43\\\">\\n\",\n              \"<path d=\\\"M682.76,961.332 L705.387,983.96 L682.76,1006.59 L682.76,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,961.332 L705.387,983.96 L682.76,1006.59 L682.76,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:43\\\">\\n\",\n              \"<path d=\\\"M569.623,1029.21 L592.25,1006.59 L592.25,1051.84 L569.623,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,1029.21 L592.25,1006.59 L592.25,1051.84 L569.623,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:43\\\">\\n\",\n              \"<path d=\\\"M637.505,1051.84 L682.76,1051.84 L660.133,1074.47 L637.505,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip55\\\"><path d=\\\"M637.505,1051.84 L682.76,1051.84 L660.133,1074.47 L637.505,1051.84\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip55)\\\" cx=\\\"637.505\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip55)\\\" cx=\\\"682.76\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip55)\\\" cx=\\\"660.133\\\" cy=\\\"1074.47\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1051.84 L682.76,1051.84 L660.133,1074.47 L637.505,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:44\\\">\\n\",\n              \"<path d=\\\"M799.419,938.705 L822.046,961.332 L776.791,961.332 L799.419,938.705\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,938.705 L822.046,961.332 L776.791,961.332 L799.419,938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:44\\\">\\n\",\n              \"<path d=\\\"M867.301,961.332 L889.928,983.96 L867.301,1006.59 L867.301,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,961.332 L889.928,983.96 L867.301,1006.59 L867.301,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:44\\\">\\n\",\n              \"<path d=\\\"M754.164,1029.21 L776.791,1006.59 L776.791,1051.84 L754.164,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,1029.21 L776.791,1006.59 L776.791,1051.84 L754.164,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:44\\\">\\n\",\n              \"<path d=\\\"M822.046,1051.84 L867.301,1051.84 L844.673,1074.47 L822.046,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1051.84 L867.301,1051.84 L844.673,1074.47 L822.046,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:46\\\">\\n\",\n              \"<path d=\\\"M1145.87,961.332 L1168.5,983.96 L1145.87,1006.59 L1145.87,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,961.332 L1168.5,983.96 L1145.87,1006.59 L1145.87,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:46\\\">\\n\",\n              \"<path d=\\\"M1191.13,961.332 L1236.38,961.332 L1213.76,983.96 L1191.13,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,961.332 L1236.38,961.332 L1213.76,983.96 L1191.13,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:46\\\">\\n\",\n              \"<path d=\\\"M1168.5,1029.21 L1191.13,1051.84 L1145.87,1051.84 L1168.5,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,1029.21 L1191.13,1051.84 L1145.87,1051.84 L1168.5,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:46\\\">\\n\",\n              \"<path d=\\\"M1213.76,1029.21 L1236.38,1006.59 L1236.38,1051.84 L1213.76,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,1029.21 L1236.38,1006.59 L1236.38,1051.84 L1213.76,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:48\\\">\\n\",\n              \"<path d=\\\"M61.2548,1123.25 L83.8822,1145.87 L38.6274,1145.87 L61.2548,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,1123.25 L83.8822,1145.87 L38.6274,1145.87 L61.2548,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:48\\\">\\n\",\n              \"<path d=\\\"M129.137,1145.87 L151.764,1168.5 L129.137,1191.13 L129.137,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,1145.87 L151.764,1168.5 L129.137,1191.13 L129.137,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:48\\\">\\n\",\n              \"<path d=\\\"M16,1213.76 L38.6274,1191.13 L38.6274,1236.38 L16,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,1213.76 L38.6274,1191.13 L38.6274,1236.38 L16,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:48\\\">\\n\",\n              \"<path d=\\\"M83.8822,1236.38 L129.137,1236.38 L106.51,1259.01 L83.8822,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1236.38 L129.137,1236.38 L106.51,1259.01 L83.8822,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:49\\\">\\n\",\n              \"<path d=\\\"M245.796,1123.25 L268.423,1145.87 L223.168,1145.87 L245.796,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip56\\\"><path d=\\\"M245.796,1123.25 L268.423,1145.87 L223.168,1145.87 L245.796,1123.25\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip56)\\\" cx=\\\"223.168\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip56)\\\" cx=\\\"245.796\\\" cy=\\\"1123.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip56)\\\" cx=\\\"268.423\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M245.796,1123.25 L268.423,1145.87 L223.168,1145.87 L245.796,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:49\\\">\\n\",\n              \"<path d=\\\"M313.678,1145.87 L336.305,1168.5 L313.678,1191.13 L313.678,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,1145.87 L336.305,1168.5 L313.678,1191.13 L313.678,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:49\\\">\\n\",\n              \"<path d=\\\"M200.541,1213.76 L223.168,1191.13 L223.168,1236.38 L200.541,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,1213.76 L223.168,1191.13 L223.168,1236.38 L200.541,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:49\\\">\\n\",\n              \"<path d=\\\"M268.423,1236.38 L313.678,1236.38 L291.051,1259.01 L268.423,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip57\\\"><path d=\\\"M268.423,1236.38 L313.678,1236.38 L291.051,1259.01 L268.423,1236.38\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip57)\\\" cx=\\\"268.423\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip57)\\\" cx=\\\"313.678\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip57)\\\" cx=\\\"291.051\\\" cy=\\\"1259.01\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1236.38 L313.678,1236.38 L291.051,1259.01 L268.423,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:50\\\">\\n\",\n              \"<path d=\\\"M430.337,1123.25 L452.964,1145.87 L407.709,1145.87 L430.337,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip58\\\"><path d=\\\"M430.337,1123.25 L452.964,1145.87 L407.709,1145.87 L430.337,1123.25\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip58)\\\" cx=\\\"407.709\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip58)\\\" cx=\\\"430.337\\\" cy=\\\"1123.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip58)\\\" cx=\\\"452.964\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M430.337,1123.25 L452.964,1145.87 L407.709,1145.87 L430.337,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:50\\\">\\n\",\n              \"<path d=\\\"M498.219,1145.87 L520.846,1168.5 L498.219,1191.13 L498.219,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,1145.87 L520.846,1168.5 L498.219,1191.13 L498.219,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:50\\\">\\n\",\n              \"<path d=\\\"M385.082,1213.76 L407.709,1191.13 L407.709,1236.38 L385.082,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,1213.76 L407.709,1191.13 L407.709,1236.38 L385.082,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:50\\\">\\n\",\n              \"<path d=\\\"M452.964,1236.38 L498.219,1236.38 L475.592,1259.01 L452.964,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip59\\\"><path d=\\\"M452.964,1236.38 L498.219,1236.38 L475.592,1259.01 L452.964,1236.38\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip59)\\\" cx=\\\"452.964\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip59)\\\" cx=\\\"498.219\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip59)\\\" cx=\\\"475.592\\\" cy=\\\"1259.01\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1236.38 L498.219,1236.38 L475.592,1259.01 L452.964,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:51\\\">\\n\",\n              \"<path d=\\\"M614.878,1123.25 L637.505,1145.87 L592.25,1145.87 L614.878,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,1123.25 L637.505,1145.87 L592.25,1145.87 L614.878,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:51\\\">\\n\",\n              \"<path d=\\\"M682.76,1145.87 L705.387,1168.5 L682.76,1191.13 L682.76,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,1145.87 L705.387,1168.5 L682.76,1191.13 L682.76,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:51\\\">\\n\",\n              \"<path d=\\\"M569.623,1213.76 L592.25,1191.13 L592.25,1236.38 L569.623,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,1213.76 L592.25,1191.13 L592.25,1236.38 L569.623,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:51\\\">\\n\",\n              \"<path d=\\\"M637.505,1236.38 L682.76,1236.38 L660.133,1259.01 L637.505,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1236.38 L682.76,1236.38 L660.133,1259.01 L637.505,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:53\\\">\\n\",\n              \"<path d=\\\"M961.332,1145.87 L983.96,1168.5 L961.332,1191.13 L961.332,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1145.87 L983.96,1168.5 L961.332,1191.13 L961.332,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:53\\\">\\n\",\n              \"<path d=\\\"M1006.59,1145.87 L1051.84,1145.87 L1029.21,1168.5 L1006.59,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1145.87 L1051.84,1145.87 L1029.21,1168.5 L1006.59,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:53\\\">\\n\",\n              \"<path d=\\\"M983.96,1213.76 L1006.59,1236.38 L961.332,1236.38 L983.96,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1213.76 L1006.59,1236.38 L961.332,1236.38 L983.96,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:53\\\">\\n\",\n              \"<path d=\\\"M1029.21,1213.76 L1051.84,1191.13 L1051.84,1236.38 L1029.21,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,1213.76 L1051.84,1191.13 L1051.84,1236.38 L1029.21,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:55\\\">\\n\",\n              \"<path d=\\\"M1353.04,1123.25 L1375.67,1145.87 L1330.41,1145.87 L1353.04,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,1123.25 L1375.67,1145.87 L1330.41,1145.87 L1353.04,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:55\\\">\\n\",\n              \"<path d=\\\"M1420.92,1145.87 L1443.55,1168.5 L1420.92,1191.13 L1420.92,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,1145.87 L1443.55,1168.5 L1420.92,1191.13 L1420.92,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:55\\\">\\n\",\n              \"<path d=\\\"M1307.79,1213.76 L1330.41,1191.13 L1330.41,1236.38 L1307.79,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,1213.76 L1330.41,1191.13 L1330.41,1236.38 L1307.79,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:55\\\">\\n\",\n              \"<path d=\\\"M1375.67,1236.38 L1420.92,1236.38 L1398.3,1259.01 L1375.67,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1236.38 L1420.92,1236.38 L1398.3,1259.01 L1375.67,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:56\\\">\\n\",\n              \"<path d=\\\"M61.2548,1307.79 L83.8822,1330.41 L38.6274,1330.41 L61.2548,1307.79\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip60\\\"><path d=\\\"M61.2548,1307.79 L83.8822,1330.41 L38.6274,1330.41 L61.2548,1307.79\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip60)\\\" cx=\\\"38.6274\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip60)\\\" cx=\\\"61.2548\\\" cy=\\\"1307.79\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip60)\\\" cx=\\\"83.8822\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,1307.79 L83.8822,1330.41 L38.6274,1330.41 L61.2548,1307.79\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:56\\\">\\n\",\n              \"<path d=\\\"M129.137,1330.41 L151.764,1353.04 L129.137,1375.67 L129.137,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,1330.41 L151.764,1353.04 L129.137,1375.67 L129.137,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:56\\\">\\n\",\n              \"<path d=\\\"M16,1398.3 L38.6274,1375.67 L38.6274,1420.92 L16,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,1398.3 L38.6274,1375.67 L38.6274,1420.92 L16,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:56\\\">\\n\",\n              \"<path d=\\\"M83.8822,1420.92 L129.137,1420.92 L106.51,1443.55 L83.8822,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip61\\\"><path d=\\\"M83.8822,1420.92 L129.137,1420.92 L106.51,1443.55 L83.8822,1420.92\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip61)\\\" cx=\\\"83.8822\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip61)\\\" cx=\\\"129.137\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip61)\\\" cx=\\\"106.51\\\" cy=\\\"1443.55\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1420.92 L129.137,1420.92 L106.51,1443.55 L83.8822,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:57\\\">\\n\",\n              \"<path d=\\\"M245.796,1307.79 L268.423,1330.41 L223.168,1330.41 L245.796,1307.79\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip62\\\"><path d=\\\"M245.796,1307.79 L268.423,1330.41 L223.168,1330.41 L245.796,1307.79\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip62)\\\" cx=\\\"223.168\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip62)\\\" cx=\\\"245.796\\\" cy=\\\"1307.79\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip62)\\\" cx=\\\"268.423\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M245.796,1307.79 L268.423,1330.41 L223.168,1330.41 L245.796,1307.79\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:57\\\">\\n\",\n              \"<path d=\\\"M313.678,1330.41 L336.305,1353.04 L313.678,1375.67 L313.678,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,1330.41 L336.305,1353.04 L313.678,1375.67 L313.678,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:57\\\">\\n\",\n              \"<path d=\\\"M200.541,1398.3 L223.168,1375.67 L223.168,1420.92 L200.541,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,1398.3 L223.168,1375.67 L223.168,1420.92 L200.541,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:57\\\">\\n\",\n              \"<path d=\\\"M268.423,1420.92 L313.678,1420.92 L291.051,1443.55 L268.423,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip63\\\"><path d=\\\"M268.423,1420.92 L313.678,1420.92 L291.051,1443.55 L268.423,1420.92\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip63)\\\" cx=\\\"268.423\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip63)\\\" cx=\\\"313.678\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip63)\\\" cx=\\\"291.051\\\" cy=\\\"1443.55\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1420.92 L313.678,1420.92 L291.051,1443.55 L268.423,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:58\\\">\\n\",\n              \"<path d=\\\"M430.337,1307.79 L452.964,1330.41 L407.709,1330.41 L430.337,1307.79\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,1307.79 L452.964,1330.41 L407.709,1330.41 L430.337,1307.79\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:58\\\">\\n\",\n              \"<path d=\\\"M498.219,1330.41 L520.846,1353.04 L498.219,1375.67 L498.219,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,1330.41 L520.846,1353.04 L498.219,1375.67 L498.219,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:58\\\">\\n\",\n              \"<path d=\\\"M385.082,1398.3 L407.709,1375.67 L407.709,1420.92 L385.082,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,1398.3 L407.709,1375.67 L407.709,1420.92 L385.082,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:58\\\">\\n\",\n              \"<path d=\\\"M452.964,1420.92 L498.219,1420.92 L475.592,1443.55 L452.964,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1420.92 L498.219,1420.92 L475.592,1443.55 L452.964,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:60\\\">\\n\",\n              \"<path d=\\\"M776.791,1330.41 L799.419,1353.04 L776.791,1375.67 L776.791,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1330.41 L799.419,1353.04 L776.791,1375.67 L776.791,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:60\\\">\\n\",\n              \"<path d=\\\"M822.046,1330.41 L867.301,1330.41 L844.673,1353.04 L822.046,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1330.41 L867.301,1330.41 L844.673,1353.04 L822.046,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:60\\\">\\n\",\n              \"<path d=\\\"M844.673,1398.3 L867.301,1375.67 L867.301,1420.92 L844.673,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1398.3 L867.301,1375.67 L867.301,1420.92 L844.673,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:62\\\">\\n\",\n              \"<path d=\\\"M1123.25,1398.3 L1145.87,1375.67 L1145.87,1420.92 L1123.25,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,1398.3 L1145.87,1375.67 L1145.87,1420.92 L1123.25,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:62\\\">\\n\",\n              \"<path d=\\\"M1236.38,1330.41 L1259.01,1353.04 L1236.38,1375.67 L1236.38,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,1330.41 L1259.01,1353.04 L1236.38,1375.67 L1236.38,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:63\\\">\\n\",\n              \"<path d=\\\"M1307.79,1398.3 L1330.41,1375.67 L1330.41,1420.92 L1307.79,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,1398.3 L1330.41,1375.67 L1330.41,1420.92 L1307.79,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:63\\\">\\n\",\n              \"<path d=\\\"M1420.92,1330.41 L1443.55,1353.04 L1420.92,1375.67 L1420.92,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,1330.41 L1443.55,1353.04 L1420.92,1375.67 L1420.92,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:3\\\">\\n\",\n              \"<path d=\\\"M592.25,83.8822 C580.937 86.145, 571.886 95.1959, 569.623 106.51 C580.937 104.247, 589.988 95.196, 592.25 83.8822\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,83.8822 C580.937 86.145, 571.886 95.1959, 569.623 106.51 C580.937 104.247, 589.988 95.196, 592.25 83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:3\\\">\\n\",\n              \"<path d=\\\"M614.878,16 C617.14 27.3137, 626.191 36.3647, 637.505 38.6274 C635.242 27.3137, 626.191 18.2627, 614.878 16\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,16 C617.14 27.3137, 626.191 36.3647, 637.505 38.6274 C635.242 27.3137, 626.191 18.2627, 614.878 16\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:3\\\">\\n\",\n              \"<path d=\\\"M614.878,61.2548 C617.14 72.5686, 626.191 81.6195, 637.505 83.8822 C635.242 72.5685, 626.191 63.5176, 614.878 61.2548\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,61.2548 C617.14 72.5686, 626.191 81.6195, 637.505 83.8822 C635.242 72.5685, 626.191 63.5176, 614.878 61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:3\\\">\\n\",\n              \"<path d=\\\"M660.133,61.2548 C662.395 72.5686, 671.446 81.6195, 682.76 83.8822 C680.497 72.5685, 671.446 63.5176, 660.133 61.2548\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M660.133,61.2548 C662.395 72.5686, 671.446 81.6195, 682.76 83.8822 C680.497 72.5685, 671.446 63.5176, 660.133 61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:3\\\">\\n\",\n              \"<path d=\\\"M569.623,106.51 C571.886 117.823, 580.937 126.874, 592.25 129.137 C589.988 117.823, 580.937 108.772, 569.623 106.51\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,106.51 C571.886 117.823, 580.937 126.874, 592.25 129.137 C589.988 117.823, 580.937 108.772, 569.623 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:3\\\">\\n\",\n              \"<path d=\\\"M614.878,106.51 C617.14 117.823, 626.191 126.874, 637.505 129.137 C635.242 117.823, 626.191 108.772, 614.878 106.51\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,106.51 C617.14 117.823, 626.191 126.874, 637.505 129.137 C635.242 117.823, 626.191 108.772, 614.878 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:3\\\">\\n\",\n              \"<path d=\\\"M660.133,106.51 C662.395 117.823, 671.446 126.874, 682.76 129.137 C680.497 117.823, 671.446 108.772, 660.133 106.51\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,106.51 C662.395 117.823, 671.446 126.874, 682.76 129.137 C680.497 117.823, 671.446 108.772, 660.133 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:5\\\">\\n\",\n              \"<path d=\\\"M961.332,38.6274 C963.595 49.9411, 972.646 58.9921, 983.96 61.2548 C981.697 49.9411, 972.646 40.8902, 961.332 38.6274\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,38.6274 C963.595 49.9411, 972.646 58.9921, 983.96 61.2548 C981.697 49.9411, 972.646 40.8902, 961.332 38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:5\\\">\\n\",\n              \"<path d=\\\"M1006.59,83.8822 C1008.85 95.196, 1017.9 104.247, 1029.21 106.51 C1026.95 95.1959, 1017.9 86.145, 1006.59 83.8822\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,83.8822 C1008.85 95.196, 1017.9 104.247, 1029.21 106.51 C1026.95 95.1959, 1017.9 86.145, 1006.59 83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:5\\\">\\n\",\n              \"<path d=\\\"M1051.84,38.6274 C1054.1 49.9411, 1063.16 58.9921, 1074.47 61.2548 C1072.21 49.9411, 1063.16 40.8902, 1051.84 38.6274\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,38.6274 C1054.1 49.9411, 1063.16 58.9921, 1074.47 61.2548 C1072.21 49.9411, 1063.16 40.8902, 1051.84 38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:5\\\">\\n\",\n              \"<path d=\\\"M1051.84,83.8822 C1063.16 81.6195, 1072.21 72.5686, 1074.47 61.2548 C1063.16 63.5176, 1054.1 72.5685, 1051.84 83.8822\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,83.8822 C1063.16 81.6195, 1072.21 72.5686, 1074.47 61.2548 C1063.16 63.5176, 1054.1 72.5685, 1051.84 83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:5\\\">\\n\",\n              \"<path d=\\\"M1051.84,129.137 C1040.53 131.4, 1031.48 140.451, 1029.21 151.764 C1040.53 149.502, 1049.58 140.451, 1051.84 129.137\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,129.137 C1040.53 131.4, 1031.48 140.451, 1029.21 151.764 C1040.53 149.502, 1049.58 140.451, 1051.84 129.137\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:10\\\">\\n\",\n              \"<path d=\\\"M407.709,223.168 C419.023 220.906, 428.074 211.855, 430.337 200.541 C419.023 202.804, 409.972 211.855, 407.709 223.168\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,223.168 C419.023 220.906, 428.074 211.855, 430.337 200.541 C419.023 202.804, 409.972 211.855, 407.709 223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:10\\\">\\n\",\n              \"<path d=\\\"M407.709,268.423 C396.396 270.686, 387.345 279.737, 385.082 291.051 C396.396 288.788, 405.447 279.737, 407.709 268.423\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,268.423 C396.396 270.686, 387.345 279.737, 385.082 291.051 C396.396 288.788, 405.447 279.737, 407.709 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:10\\\">\\n\",\n              \"<path d=\\\"M430.337,200.541 C432.599 211.855, 441.65 220.906, 452.964 223.168 C450.701 211.855, 441.65 202.804, 430.337 200.541\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,200.541 C432.599 211.855, 441.65 220.906, 452.964 223.168 C450.701 211.855, 441.65 202.804, 430.337 200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:10\\\">\\n\",\n              \"<path d=\\\"M430.337,245.796 C432.599 257.109, 441.65 266.16, 452.964 268.423 C450.701 257.109, 441.65 248.059, 430.337 245.796\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M430.337,245.796 C432.599 257.109, 441.65 266.16, 452.964 268.423 C450.701 257.109, 441.65 248.059, 430.337 245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:10\\\">\\n\",\n              \"<path d=\\\"M475.592,245.796 C477.854 257.109, 486.905 266.16, 498.219 268.423 C495.956 257.109, 486.905 248.059, 475.592 245.796\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M475.592,245.796 C477.854 257.109, 486.905 266.16, 498.219 268.423 C495.956 257.109, 486.905 248.059, 475.592 245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:10\\\">\\n\",\n              \"<path d=\\\"M385.082,291.051 C387.345 302.364, 396.396 311.415, 407.709 313.678 C405.447 302.364, 396.396 293.313, 385.082 291.051\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,291.051 C387.345 302.364, 396.396 311.415, 407.709 313.678 C405.447 302.364, 396.396 293.313, 385.082 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:10\\\">\\n\",\n              \"<path d=\\\"M430.337,291.051 C432.599 302.364, 441.65 311.415, 452.964 313.678 C450.701 302.364, 441.65 293.313, 430.337 291.051\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,291.051 C432.599 302.364, 441.65 311.415, 452.964 313.678 C450.701 302.364, 441.65 293.313, 430.337 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:10\\\">\\n\",\n              \"<path d=\\\"M475.592,291.051 C477.854 302.364, 486.905 311.415, 498.219 313.678 C495.956 302.364, 486.905 293.313, 475.592 291.051\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,291.051 C477.854 302.364, 486.905 311.415, 498.219 313.678 C495.956 302.364, 486.905 293.313, 475.592 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:12\\\">\\n\",\n              \"<path d=\\\"M776.791,223.168 C779.054 234.482, 788.105 243.533, 799.419 245.796 C797.156 234.482, 788.105 225.431, 776.791 223.168\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,223.168 C779.054 234.482, 788.105 243.533, 799.419 245.796 C797.156 234.482, 788.105 225.431, 776.791 223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:12\\\">\\n\",\n              \"<path d=\\\"M822.046,223.168 C824.309 234.482, 833.36 243.533, 844.673 245.796 C842.411 234.482, 833.36 225.431, 822.046 223.168\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,223.168 C824.309 234.482, 833.36 243.533, 844.673 245.796 C842.411 234.482, 833.36 225.431, 822.046 223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:12\\\">\\n\",\n              \"<path d=\\\"M867.301,223.168 C869.564 234.482, 878.615 243.533, 889.928 245.796 C887.666 234.482, 878.615 225.431, 867.301 223.168\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,223.168 C869.564 234.482, 878.615 243.533, 889.928 245.796 C887.666 234.482, 878.615 225.431, 867.301 223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:12\\\">\\n\",\n              \"<path d=\\\"M776.791,268.423 C779.054 279.737, 788.105 288.788, 799.419 291.051 C797.156 279.737, 788.105 270.686, 776.791 268.423\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,268.423 C779.054 279.737, 788.105 288.788, 799.419 291.051 C797.156 279.737, 788.105 270.686, 776.791 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:12\\\">\\n\",\n              \"<path d=\\\"M822.046,268.423 C824.309 279.737, 833.36 288.788, 844.673 291.051 C842.411 279.737, 833.36 270.686, 822.046 268.423\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,268.423 C824.309 279.737, 833.36 288.788, 844.673 291.051 C842.411 279.737, 833.36 270.686, 822.046 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:12\\\">\\n\",\n              \"<path d=\\\"M822.046,313.678 C824.309 324.992, 833.36 334.043, 844.673 336.305 C842.411 324.992, 833.36 315.941, 822.046 313.678\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,313.678 C824.309 324.992, 833.36 334.043, 844.673 336.305 C842.411 324.992, 833.36 315.941, 822.046 313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:12\\\">\\n\",\n              \"<path d=\\\"M867.301,268.423 C878.615 266.16, 887.666 257.109, 889.928 245.796 C878.615 248.059, 869.564 257.109, 867.301 268.423\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,268.423 C878.615 266.16, 887.666 257.109, 889.928 245.796 C878.615 248.059, 869.564 257.109, 867.301 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:12\\\">\\n\",\n              \"<path d=\\\"M867.301,313.678 C855.987 315.941, 846.936 324.992, 844.673 336.305 C855.987 334.043, 865.038 324.992, 867.301 313.678\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M867.301,313.678 C855.987 315.941, 846.936 324.992, 844.673 336.305 C855.987 334.043, 865.038 324.992, 867.301 313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:17\\\">\\n\",\n              \"<path d=\\\"M223.168,407.709 C234.482 405.447, 243.533 396.396, 245.796 385.082 C234.482 387.345, 225.431 396.396, 223.168 407.709\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,407.709 C234.482 405.447, 243.533 396.396, 245.796 385.082 C234.482 387.345, 225.431 396.396, 223.168 407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:17\\\">\\n\",\n              \"<path d=\\\"M223.168,452.964 C211.855 455.227, 202.804 464.278, 200.541 475.592 C211.855 473.329, 220.906 464.278, 223.168 452.964\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,452.964 C211.855 455.227, 202.804 464.278, 200.541 475.592 C211.855 473.329, 220.906 464.278, 223.168 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:17\\\">\\n\",\n              \"<path d=\\\"M245.796,385.082 C248.059 396.396, 257.109 405.447, 268.423 407.709 C266.16 396.396, 257.109 387.345, 245.796 385.082\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,385.082 C248.059 396.396, 257.109 405.447, 268.423 407.709 C266.16 396.396, 257.109 387.345, 245.796 385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:17\\\">\\n\",\n              \"<path d=\\\"M245.796,430.337 C248.059 441.65, 257.109 450.701, 268.423 452.964 C266.16 441.65, 257.109 432.599, 245.796 430.337\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M245.796,430.337 C248.059 441.65, 257.109 450.701, 268.423 452.964 C266.16 441.65, 257.109 432.599, 245.796 430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:17\\\">\\n\",\n              \"<path d=\\\"M291.051,430.337 C293.313 441.65, 302.364 450.701, 313.678 452.964 C311.415 441.65, 302.364 432.599, 291.051 430.337\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M291.051,430.337 C293.313 441.65, 302.364 450.701, 313.678 452.964 C311.415 441.65, 302.364 432.599, 291.051 430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:17\\\">\\n\",\n              \"<path d=\\\"M200.541,475.592 C202.804 486.905, 211.855 495.956, 223.168 498.219 C220.906 486.905, 211.855 477.854, 200.541 475.592\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,475.592 C202.804 486.905, 211.855 495.956, 223.168 498.219 C220.906 486.905, 211.855 477.854, 200.541 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:17\\\">\\n\",\n              \"<path d=\\\"M245.796,475.592 C248.059 486.905, 257.109 495.956, 268.423 498.219 C266.16 486.905, 257.109 477.854, 245.796 475.592\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,475.592 C248.059 486.905, 257.109 495.956, 268.423 498.219 C266.16 486.905, 257.109 477.854, 245.796 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:17\\\">\\n\",\n              \"<path d=\\\"M291.051,475.592 C293.313 486.905, 302.364 495.956, 313.678 498.219 C311.415 486.905, 302.364 477.854, 291.051 475.592\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,475.592 C293.313 486.905, 302.364 495.956, 313.678 498.219 C311.415 486.905, 302.364 477.854, 291.051 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:19\\\">\\n\",\n              \"<path d=\\\"M592.25,407.709 C594.513 419.023, 603.564 428.074, 614.878 430.337 C612.615 419.023, 603.564 409.972, 592.25 407.709\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,407.709 C594.513 419.023, 603.564 428.074, 614.878 430.337 C612.615 419.023, 603.564 409.972, 592.25 407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:19\\\">\\n\",\n              \"<path d=\\\"M637.505,407.709 C639.768 419.023, 648.819 428.074, 660.133 430.337 C657.87 419.023, 648.819 409.972, 637.505 407.709\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,407.709 C639.768 419.023, 648.819 428.074, 660.133 430.337 C657.87 419.023, 648.819 409.972, 637.505 407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:19\\\">\\n\",\n              \"<path d=\\\"M682.76,407.709 C685.023 419.023, 694.074 428.074, 705.387 430.337 C703.125 419.023, 694.074 409.972, 682.76 407.709\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,407.709 C685.023 419.023, 694.074 428.074, 705.387 430.337 C703.125 419.023, 694.074 409.972, 682.76 407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:19\\\">\\n\",\n              \"<path d=\\\"M592.25,452.964 C594.513 464.278, 603.564 473.329, 614.878 475.592 C612.615 464.278, 603.564 455.227, 592.25 452.964\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,452.964 C594.513 464.278, 603.564 473.329, 614.878 475.592 C612.615 464.278, 603.564 455.227, 592.25 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:19\\\">\\n\",\n              \"<path d=\\\"M637.505,452.964 C639.768 464.278, 648.819 473.329, 660.133 475.592 C657.87 464.278, 648.819 455.227, 637.505 452.964\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,452.964 C639.768 464.278, 648.819 473.329, 660.133 475.592 C657.87 464.278, 648.819 455.227, 637.505 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:19\\\">\\n\",\n              \"<path d=\\\"M637.505,498.219 C639.768 509.533, 648.819 518.584, 660.133 520.846 C657.87 509.533, 648.819 500.482, 637.505 498.219\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,498.219 C639.768 509.533, 648.819 518.584, 660.133 520.846 C657.87 509.533, 648.819 500.482, 637.505 498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:19\\\">\\n\",\n              \"<path d=\\\"M682.76,452.964 C694.074 450.701, 703.125 441.65, 705.387 430.337 C694.074 432.599, 685.023 441.65, 682.76 452.964\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,452.964 C694.074 450.701, 703.125 441.65, 705.387 430.337 C694.074 432.599, 685.023 441.65, 682.76 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:19\\\">\\n\",\n              \"<path d=\\\"M682.76,498.219 C671.446 500.482, 662.395 509.533, 660.133 520.846 C671.446 518.584, 680.497 509.533, 682.76 498.219\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M682.76,498.219 C671.446 500.482, 662.395 509.533, 660.133 520.846 C671.446 518.584, 680.497 509.533, 682.76 498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:24\\\">\\n\",\n              \"<path d=\\\"M38.6274,592.25 C49.9411 589.988, 58.9921 580.937, 61.2548 569.623 C49.9411 571.886, 40.8902 580.937, 38.6274 592.25\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,592.25 C49.9411 589.988, 58.9921 580.937, 61.2548 569.623 C49.9411 571.886, 40.8902 580.937, 38.6274 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:24\\\">\\n\",\n              \"<path d=\\\"M38.6274,637.505 C27.3137 639.768, 18.2627 648.819, 16 660.133 C27.3137 657.87, 36.3647 648.819, 38.6274 637.505\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,637.505 C27.3137 639.768, 18.2627 648.819, 16 660.133 C27.3137 657.87, 36.3647 648.819, 38.6274 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:24\\\">\\n\",\n              \"<path d=\\\"M61.2548,569.623 C63.5176 580.937, 72.5685 589.988, 83.8822 592.25 C81.6195 580.937, 72.5686 571.886, 61.2548 569.623\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,569.623 C63.5176 580.937, 72.5685 589.988, 83.8822 592.25 C81.6195 580.937, 72.5686 571.886, 61.2548 569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:24\\\">\\n\",\n              \"<path d=\\\"M61.2548,614.878 C63.5176 626.191, 72.5685 635.242, 83.8822 637.505 C81.6195 626.191, 72.5686 617.14, 61.2548 614.878\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,614.878 C63.5176 626.191, 72.5685 635.242, 83.8822 637.505 C81.6195 626.191, 72.5686 617.14, 61.2548 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:24\\\">\\n\",\n              \"<path d=\\\"M106.51,614.878 C108.772 626.191, 117.823 635.242, 129.137 637.505 C126.874 626.191, 117.823 617.14, 106.51 614.878\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M106.51,614.878 C108.772 626.191, 117.823 635.242, 129.137 637.505 C126.874 626.191, 117.823 617.14, 106.51 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:24\\\">\\n\",\n              \"<path d=\\\"M16,660.133 C18.2627 671.446, 27.3137 680.497, 38.6274 682.76 C36.3647 671.446, 27.3137 662.395, 16 660.133\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,660.133 C18.2627 671.446, 27.3137 680.497, 38.6274 682.76 C36.3647 671.446, 27.3137 662.395, 16 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:24\\\">\\n\",\n              \"<path d=\\\"M61.2548,660.133 C63.5176 671.446, 72.5685 680.497, 83.8822 682.76 C81.6195 671.446, 72.5686 662.395, 61.2548 660.133\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,660.133 C63.5176 671.446, 72.5685 680.497, 83.8822 682.76 C81.6195 671.446, 72.5686 662.395, 61.2548 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:24\\\">\\n\",\n              \"<path d=\\\"M106.51,660.133 C108.772 671.446, 117.823 680.497, 129.137 682.76 C126.874 671.446, 117.823 662.395, 106.51 660.133\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,660.133 C108.772 671.446, 117.823 680.497, 129.137 682.76 C126.874 671.446, 117.823 662.395, 106.51 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:26\\\">\\n\",\n              \"<path d=\\\"M407.709,592.25 C409.972 603.564, 419.023 612.615, 430.337 614.878 C428.074 603.564, 419.023 594.513, 407.709 592.25\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,592.25 C409.972 603.564, 419.023 612.615, 430.337 614.878 C428.074 603.564, 419.023 594.513, 407.709 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:26\\\">\\n\",\n              \"<path d=\\\"M452.964,592.25 C455.227 603.564, 464.278 612.615, 475.592 614.878 C473.329 603.564, 464.278 594.513, 452.964 592.25\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,592.25 C455.227 603.564, 464.278 612.615, 475.592 614.878 C473.329 603.564, 464.278 594.513, 452.964 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:26\\\">\\n\",\n              \"<path d=\\\"M498.219,592.25 C500.482 603.564, 509.533 612.615, 520.846 614.878 C518.584 603.564, 509.533 594.513, 498.219 592.25\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,592.25 C500.482 603.564, 509.533 612.615, 520.846 614.878 C518.584 603.564, 509.533 594.513, 498.219 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:26\\\">\\n\",\n              \"<path d=\\\"M407.709,637.505 C409.972 648.819, 419.023 657.87, 430.337 660.133 C428.074 648.819, 419.023 639.768, 407.709 637.505\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,637.505 C409.972 648.819, 419.023 657.87, 430.337 660.133 C428.074 648.819, 419.023 639.768, 407.709 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:26\\\">\\n\",\n              \"<path d=\\\"M452.964,637.505 C455.227 648.819, 464.278 657.87, 475.592 660.133 C473.329 648.819, 464.278 639.768, 452.964 637.505\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,637.505 C455.227 648.819, 464.278 657.87, 475.592 660.133 C473.329 648.819, 464.278 639.768, 452.964 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:26\\\">\\n\",\n              \"<path d=\\\"M452.964,682.76 C455.227 694.074, 464.278 703.125, 475.592 705.387 C473.329 694.074, 464.278 685.023, 452.964 682.76\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,682.76 C455.227 694.074, 464.278 703.125, 475.592 705.387 C473.329 694.074, 464.278 685.023, 452.964 682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:26\\\">\\n\",\n              \"<path d=\\\"M498.219,637.505 C509.533 635.242, 518.584 626.191, 520.846 614.878 C509.533 617.14, 500.482 626.191, 498.219 637.505\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,637.505 C509.533 635.242, 518.584 626.191, 520.846 614.878 C509.533 617.14, 500.482 626.191, 498.219 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:26\\\">\\n\",\n              \"<path d=\\\"M498.219,682.76 C486.905 685.023, 477.854 694.074, 475.592 705.387 C486.905 703.125, 495.956 694.074, 498.219 682.76\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M498.219,682.76 C486.905 685.023, 477.854 694.074, 475.592 705.387 C486.905 703.125, 495.956 694.074, 498.219 682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:31\\\">\\n\",\n              \"<path d=\\\"M1330.41,592.25 C1341.73 589.988, 1350.78 580.937, 1353.04 569.623 C1341.73 571.886, 1332.68 580.937, 1330.41 592.25\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,592.25 C1341.73 589.988, 1350.78 580.937, 1353.04 569.623 C1341.73 571.886, 1332.68 580.937, 1330.41 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:31\\\">\\n\",\n              \"<path d=\\\"M1330.41,637.505 C1319.1 639.768, 1310.05 648.819, 1307.79 660.133 C1319.1 657.87, 1328.15 648.819, 1330.41 637.505\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,637.505 C1319.1 639.768, 1310.05 648.819, 1307.79 660.133 C1319.1 657.87, 1328.15 648.819, 1330.41 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:31\\\">\\n\",\n              \"<path d=\\\"M1353.04,569.623 C1355.3 580.937, 1364.36 589.988, 1375.67 592.25 C1373.41 580.937, 1364.36 571.886, 1353.04 569.623\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,569.623 C1355.3 580.937, 1364.36 589.988, 1375.67 592.25 C1373.41 580.937, 1364.36 571.886, 1353.04 569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:31\\\">\\n\",\n              \"<path d=\\\"M1353.04,614.878 C1355.3 626.191, 1364.36 635.242, 1375.67 637.505 C1373.41 626.191, 1364.36 617.14, 1353.04 614.878\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,614.878 C1355.3 626.191, 1364.36 635.242, 1375.67 637.505 C1373.41 626.191, 1364.36 617.14, 1353.04 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:31\\\">\\n\",\n              \"<path d=\\\"M1398.3,614.878 C1400.56 626.191, 1409.61 635.242, 1420.92 637.505 C1418.66 626.191, 1409.61 617.14, 1398.3 614.878\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,614.878 C1400.56 626.191, 1409.61 635.242, 1420.92 637.505 C1418.66 626.191, 1409.61 617.14, 1398.3 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:31\\\">\\n\",\n              \"<path d=\\\"M1307.79,660.133 C1310.05 671.446, 1319.1 680.497, 1330.41 682.76 C1328.15 671.446, 1319.1 662.395, 1307.79 660.133\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,660.133 C1310.05 671.446, 1319.1 680.497, 1330.41 682.76 C1328.15 671.446, 1319.1 662.395, 1307.79 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:31\\\">\\n\",\n              \"<path d=\\\"M1353.04,660.133 C1355.3 671.446, 1364.36 680.497, 1375.67 682.76 C1373.41 671.446, 1364.36 662.395, 1353.04 660.133\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,660.133 C1355.3 671.446, 1364.36 680.497, 1375.67 682.76 C1373.41 671.446, 1364.36 662.395, 1353.04 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:31\\\">\\n\",\n              \"<path d=\\\"M1398.3,660.133 C1400.56 671.446, 1409.61 680.497, 1420.92 682.76 C1418.66 671.446, 1409.61 662.395, 1398.3 660.133\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,660.133 C1400.56 671.446, 1409.61 680.497, 1420.92 682.76 C1418.66 671.446, 1409.61 662.395, 1398.3 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:33\\\">\\n\",\n              \"<path d=\\\"M223.168,776.791 C225.431 788.105, 234.482 797.156, 245.796 799.419 C243.533 788.105, 234.482 779.054, 223.168 776.791\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,776.791 C225.431 788.105, 234.482 797.156, 245.796 799.419 C243.533 788.105, 234.482 779.054, 223.168 776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:33\\\">\\n\",\n              \"<path d=\\\"M268.423,776.791 C270.686 788.105, 279.737 797.156, 291.051 799.419 C288.788 788.105, 279.737 779.054, 268.423 776.791\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,776.791 C270.686 788.105, 279.737 797.156, 291.051 799.419 C288.788 788.105, 279.737 779.054, 268.423 776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:33\\\">\\n\",\n              \"<path d=\\\"M313.678,776.791 C315.941 788.105, 324.992 797.156, 336.305 799.419 C334.043 788.105, 324.992 779.054, 313.678 776.791\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,776.791 C315.941 788.105, 324.992 797.156, 336.305 799.419 C334.043 788.105, 324.992 779.054, 313.678 776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:33\\\">\\n\",\n              \"<path d=\\\"M223.168,822.046 C225.431 833.36, 234.482 842.411, 245.796 844.673 C243.533 833.36, 234.482 824.309, 223.168 822.046\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,822.046 C225.431 833.36, 234.482 842.411, 245.796 844.673 C243.533 833.36, 234.482 824.309, 223.168 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:33\\\">\\n\",\n              \"<path d=\\\"M268.423,822.046 C270.686 833.36, 279.737 842.411, 291.051 844.673 C288.788 833.36, 279.737 824.309, 268.423 822.046\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,822.046 C270.686 833.36, 279.737 842.411, 291.051 844.673 C288.788 833.36, 279.737 824.309, 268.423 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:33\\\">\\n\",\n              \"<path d=\\\"M268.423,867.301 C270.686 878.615, 279.737 887.666, 291.051 889.928 C288.788 878.615, 279.737 869.564, 268.423 867.301\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,867.301 C270.686 878.615, 279.737 887.666, 291.051 889.928 C288.788 878.615, 279.737 869.564, 268.423 867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:33\\\">\\n\",\n              \"<path d=\\\"M313.678,822.046 C324.992 819.783, 334.043 810.732, 336.305 799.419 C324.992 801.681, 315.941 810.732, 313.678 822.046\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,822.046 C324.992 819.783, 334.043 810.732, 336.305 799.419 C324.992 801.681, 315.941 810.732, 313.678 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:33\\\">\\n\",\n              \"<path d=\\\"M313.678,867.301 C302.364 869.564, 293.313 878.615, 291.051 889.928 C302.364 887.666, 311.415 878.615, 313.678 867.301\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M313.678,867.301 C302.364 869.564, 293.313 878.615, 291.051 889.928 C302.364 887.666, 311.415 878.615, 313.678 867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:38\\\">\\n\",\n              \"<path d=\\\"M1145.87,776.791 C1157.19 774.529, 1166.24 765.478, 1168.5 754.164 C1157.19 756.427, 1148.14 765.478, 1145.87 776.791\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,776.791 C1157.19 774.529, 1166.24 765.478, 1168.5 754.164 C1157.19 756.427, 1148.14 765.478, 1145.87 776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:38\\\">\\n\",\n              \"<path d=\\\"M1145.87,822.046 C1134.56 824.309, 1125.51 833.36, 1123.25 844.673 C1134.56 842.411, 1143.61 833.36, 1145.87 822.046\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,822.046 C1134.56 824.309, 1125.51 833.36, 1123.25 844.673 C1134.56 842.411, 1143.61 833.36, 1145.87 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:38\\\">\\n\",\n              \"<path d=\\\"M1168.5,754.164 C1170.76 765.477, 1179.81 774.529, 1191.13 776.791 C1188.87 765.478, 1179.81 756.427, 1168.5 754.164\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,754.164 C1170.76 765.477, 1179.81 774.529, 1191.13 776.791 C1188.87 765.478, 1179.81 756.427, 1168.5 754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:38\\\">\\n\",\n              \"<path d=\\\"M1168.5,799.419 C1170.76 810.732, 1179.81 819.783, 1191.13 822.046 C1188.87 810.732, 1179.81 801.681, 1168.5 799.419\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,799.419 C1170.76 810.732, 1179.81 819.783, 1191.13 822.046 C1188.87 810.732, 1179.81 801.681, 1168.5 799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:38\\\">\\n\",\n              \"<path d=\\\"M1213.76,799.419 C1216.02 810.732, 1225.07 819.783, 1236.38 822.046 C1234.12 810.732, 1225.07 801.681, 1213.76 799.419\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,799.419 C1216.02 810.732, 1225.07 819.783, 1236.38 822.046 C1234.12 810.732, 1225.07 801.681, 1213.76 799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:38\\\">\\n\",\n              \"<path d=\\\"M1123.25,844.673 C1125.51 855.987, 1134.56 865.038, 1145.87 867.301 C1143.61 855.987, 1134.56 846.936, 1123.25 844.673\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,844.673 C1125.51 855.987, 1134.56 865.038, 1145.87 867.301 C1143.61 855.987, 1134.56 846.936, 1123.25 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:38\\\">\\n\",\n              \"<path d=\\\"M1168.5,844.673 C1170.76 855.987, 1179.81 865.038, 1191.13 867.301 C1188.87 855.987, 1179.81 846.936, 1168.5 844.673\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,844.673 C1170.76 855.987, 1179.81 865.038, 1191.13 867.301 C1188.87 855.987, 1179.81 846.936, 1168.5 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:38\\\">\\n\",\n              \"<path d=\\\"M1213.76,844.673 C1216.02 855.987, 1225.07 865.038, 1236.38 867.301 C1234.12 855.987, 1225.07 846.936, 1213.76 844.673\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,844.673 C1216.02 855.987, 1225.07 865.038, 1236.38 867.301 C1234.12 855.987, 1225.07 846.936, 1213.76 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:40\\\">\\n\",\n              \"<path d=\\\"M38.6274,961.332 C40.8902 972.646, 49.9411 981.697, 61.2548 983.96 C58.9921 972.646, 49.9411 963.595, 38.6274 961.332\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,961.332 C40.8902 972.646, 49.9411 981.697, 61.2548 983.96 C58.9921 972.646, 49.9411 963.595, 38.6274 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:40\\\">\\n\",\n              \"<path d=\\\"M83.8822,961.332 C86.145 972.646, 95.196 981.697, 106.51 983.96 C104.247 972.646, 95.1959 963.595, 83.8822 961.332\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,961.332 C86.145 972.646, 95.196 981.697, 106.51 983.96 C104.247 972.646, 95.1959 963.595, 83.8822 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:40\\\">\\n\",\n              \"<path d=\\\"M129.137,961.332 C131.4 972.646, 140.451 981.697, 151.764 983.96 C149.502 972.646, 140.451 963.595, 129.137 961.332\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,961.332 C131.4 972.646, 140.451 981.697, 151.764 983.96 C149.502 972.646, 140.451 963.595, 129.137 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:40\\\">\\n\",\n              \"<path d=\\\"M38.6274,1006.59 C40.8902 1017.9, 49.9411 1026.95, 61.2548 1029.21 C58.9921 1017.9, 49.9411 1008.85, 38.6274 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1006.59 C40.8902 1017.9, 49.9411 1026.95, 61.2548 1029.21 C58.9921 1017.9, 49.9411 1008.85, 38.6274 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:40\\\">\\n\",\n              \"<path d=\\\"M83.8822,1006.59 C86.145 1017.9, 95.1959 1026.95, 106.51 1029.21 C104.247 1017.9, 95.196 1008.85, 83.8822 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1006.59 C86.145 1017.9, 95.1959 1026.95, 106.51 1029.21 C104.247 1017.9, 95.196 1008.85, 83.8822 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:40\\\">\\n\",\n              \"<path d=\\\"M83.8822,1051.84 C86.145 1063.16, 95.1959 1072.21, 106.51 1074.47 C104.247 1063.16, 95.196 1054.1, 83.8822 1051.84\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1051.84 C86.145 1063.16, 95.1959 1072.21, 106.51 1074.47 C104.247 1063.16, 95.196 1054.1, 83.8822 1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:40\\\">\\n\",\n              \"<path d=\\\"M129.137,1006.59 C140.451 1004.32, 149.502 995.273, 151.764 983.96 C140.451 986.222, 131.4 995.273, 129.137 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,1006.59 C140.451 1004.32, 149.502 995.273, 151.764 983.96 C140.451 986.222, 131.4 995.273, 129.137 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:40\\\">\\n\",\n              \"<path d=\\\"M129.137,1051.84 C117.823 1054.1, 108.772 1063.16, 106.51 1074.47 C117.823 1072.21, 126.874 1063.16, 129.137 1051.84\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M129.137,1051.84 C117.823 1054.1, 108.772 1063.16, 106.51 1074.47 C117.823 1072.21, 126.874 1063.16, 129.137 1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:45\\\">\\n\",\n              \"<path d=\\\"M961.332,961.332 C972.646 959.069, 981.697 950.018, 983.96 938.705 C972.646 940.968, 963.595 950.019, 961.332 961.332\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,961.332 C972.646 959.069, 981.697 950.018, 983.96 938.705 C972.646 940.968, 963.595 950.019, 961.332 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:45\\\">\\n\",\n              \"<path d=\\\"M961.332,1006.59 C950.018 1008.85, 940.967 1017.9, 938.705 1029.21 C950.018 1026.95, 959.07 1017.9, 961.332 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1006.59 C950.018 1008.85, 940.967 1017.9, 938.705 1029.21 C950.018 1026.95, 959.07 1017.9, 961.332 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:45\\\">\\n\",\n              \"<path d=\\\"M983.96,938.705 C986.222 950.018, 995.273 959.07, 1006.59 961.332 C1004.32 950.018, 995.273 940.967, 983.96 938.705\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,938.705 C986.222 950.018, 995.273 959.07, 1006.59 961.332 C1004.32 950.018, 995.273 940.967, 983.96 938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:45\\\">\\n\",\n              \"<path d=\\\"M983.96,983.96 C986.222 995.273, 995.273 1004.32, 1006.59 1006.59 C1004.32 995.273, 995.273 986.222, 983.96 983.96\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,983.96 C986.222 995.273, 995.273 1004.32, 1006.59 1006.59 C1004.32 995.273, 995.273 986.222, 983.96 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:45\\\">\\n\",\n              \"<path d=\\\"M1029.21,983.96 C1031.48 995.273, 1040.53 1004.32, 1051.84 1006.59 C1049.58 995.273, 1040.53 986.222, 1029.21 983.96\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,983.96 C1031.48 995.273, 1040.53 1004.32, 1051.84 1006.59 C1049.58 995.273, 1040.53 986.222, 1029.21 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:45\\\">\\n\",\n              \"<path d=\\\"M938.705,1029.21 C940.968 1040.53, 950.019 1049.58, 961.332 1051.84 C959.069 1040.53, 950.018 1031.48, 938.705 1029.21\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,1029.21 C940.968 1040.53, 950.019 1049.58, 961.332 1051.84 C959.069 1040.53, 950.018 1031.48, 938.705 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:45\\\">\\n\",\n              \"<path d=\\\"M983.96,1029.21 C986.222 1040.53, 995.273 1049.58, 1006.59 1051.84 C1004.32 1040.53, 995.273 1031.48, 983.96 1029.21\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1029.21 C986.222 1040.53, 995.273 1049.58, 1006.59 1051.84 C1004.32 1040.53, 995.273 1031.48, 983.96 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:45\\\">\\n\",\n              \"<path d=\\\"M1029.21,1029.21 C1031.48 1040.53, 1040.53 1049.58, 1051.84 1051.84 C1049.58 1040.53, 1040.53 1031.48, 1029.21 1029.21\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,1029.21 C1031.48 1040.53, 1040.53 1049.58, 1051.84 1051.84 C1049.58 1040.53, 1040.53 1031.48, 1029.21 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:47\\\">\\n\",\n              \"<path d=\\\"M1330.41,961.332 C1332.68 972.646, 1341.73 981.697, 1353.04 983.96 C1350.78 972.646, 1341.73 963.595, 1330.41 961.332\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,961.332 C1332.68 972.646, 1341.73 981.697, 1353.04 983.96 C1350.78 972.646, 1341.73 963.595, 1330.41 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:47\\\">\\n\",\n              \"<path d=\\\"M1375.67,961.332 C1377.93 972.646, 1386.98 981.697, 1398.3 983.96 C1396.03 972.646, 1386.98 963.595, 1375.67 961.332\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,961.332 C1377.93 972.646, 1386.98 981.697, 1398.3 983.96 C1396.03 972.646, 1386.98 963.595, 1375.67 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:47\\\">\\n\",\n              \"<path d=\\\"M1420.92,961.332 C1423.19 972.646, 1432.24 981.697, 1443.55 983.96 C1441.29 972.646, 1432.24 963.595, 1420.92 961.332\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,961.332 C1423.19 972.646, 1432.24 981.697, 1443.55 983.96 C1441.29 972.646, 1432.24 963.595, 1420.92 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:47\\\">\\n\",\n              \"<path d=\\\"M1330.41,1006.59 C1332.68 1017.9, 1341.73 1026.95, 1353.04 1029.21 C1350.78 1017.9, 1341.73 1008.85, 1330.41 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,1006.59 C1332.68 1017.9, 1341.73 1026.95, 1353.04 1029.21 C1350.78 1017.9, 1341.73 1008.85, 1330.41 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:47\\\">\\n\",\n              \"<path d=\\\"M1375.67,1006.59 C1377.93 1017.9, 1386.98 1026.95, 1398.3 1029.21 C1396.03 1017.9, 1386.98 1008.85, 1375.67 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1006.59 C1377.93 1017.9, 1386.98 1026.95, 1398.3 1029.21 C1396.03 1017.9, 1386.98 1008.85, 1375.67 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:47\\\">\\n\",\n              \"<path d=\\\"M1375.67,1051.84 C1377.93 1063.16, 1386.98 1072.21, 1398.3 1074.47 C1396.03 1063.16, 1386.98 1054.1, 1375.67 1051.84\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1051.84 C1377.93 1063.16, 1386.98 1072.21, 1398.3 1074.47 C1396.03 1063.16, 1386.98 1054.1, 1375.67 1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:47\\\">\\n\",\n              \"<path d=\\\"M1420.92,1006.59 C1432.24 1004.32, 1441.29 995.273, 1443.55 983.96 C1432.24 986.222, 1423.19 995.273, 1420.92 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,1006.59 C1432.24 1004.32, 1441.29 995.273, 1443.55 983.96 C1432.24 986.222, 1423.19 995.273, 1420.92 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:47\\\">\\n\",\n              \"<path d=\\\"M1420.92,1051.84 C1409.61 1054.1, 1400.56 1063.16, 1398.3 1074.47 C1409.61 1072.21, 1418.66 1063.16, 1420.92 1051.84\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,1051.84 C1409.61 1054.1, 1400.56 1063.16, 1398.3 1074.47 C1409.61 1072.21, 1418.66 1063.16, 1420.92 1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:52\\\">\\n\",\n              \"<path d=\\\"M776.791,1145.87 C788.105 1143.61, 797.156 1134.56, 799.419 1123.25 C788.105 1125.51, 779.054 1134.56, 776.791 1145.87\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1145.87 C788.105 1143.61, 797.156 1134.56, 799.419 1123.25 C788.105 1125.51, 779.054 1134.56, 776.791 1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:52\\\">\\n\",\n              \"<path d=\\\"M776.791,1191.13 C765.478 1193.39, 756.427 1202.44, 754.164 1213.76 C765.478 1211.49, 774.529 1202.44, 776.791 1191.13\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1191.13 C765.478 1193.39, 756.427 1202.44, 754.164 1213.76 C765.478 1211.49, 774.529 1202.44, 776.791 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:52\\\">\\n\",\n              \"<path d=\\\"M799.419,1123.25 C801.681 1134.56, 810.732 1143.61, 822.046 1145.87 C819.783 1134.56, 810.732 1125.51, 799.419 1123.25\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1123.25 C801.681 1134.56, 810.732 1143.61, 822.046 1145.87 C819.783 1134.56, 810.732 1125.51, 799.419 1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:52\\\">\\n\",\n              \"<path d=\\\"M799.419,1168.5 C801.681 1179.81, 810.732 1188.87, 822.046 1191.13 C819.783 1179.81, 810.732 1170.76, 799.419 1168.5\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1168.5 C801.681 1179.81, 810.732 1188.87, 822.046 1191.13 C819.783 1179.81, 810.732 1170.76, 799.419 1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:52\\\">\\n\",\n              \"<path d=\\\"M844.673,1168.5 C846.936 1179.81, 855.987 1188.87, 867.301 1191.13 C865.038 1179.81, 855.987 1170.76, 844.673 1168.5\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1168.5 C846.936 1179.81, 855.987 1188.87, 867.301 1191.13 C865.038 1179.81, 855.987 1170.76, 844.673 1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:52\\\">\\n\",\n              \"<path d=\\\"M754.164,1213.76 C756.427 1225.07, 765.478 1234.12, 776.791 1236.38 C774.529 1225.07, 765.478 1216.02, 754.164 1213.76\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,1213.76 C756.427 1225.07, 765.478 1234.12, 776.791 1236.38 C774.529 1225.07, 765.478 1216.02, 754.164 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:52\\\">\\n\",\n              \"<path d=\\\"M799.419,1213.76 C801.681 1225.07, 810.732 1234.12, 822.046 1236.38 C819.783 1225.07, 810.732 1216.02, 799.419 1213.76\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1213.76 C801.681 1225.07, 810.732 1234.12, 822.046 1236.38 C819.783 1225.07, 810.732 1216.02, 799.419 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:52\\\">\\n\",\n              \"<path d=\\\"M844.673,1213.76 C846.936 1225.07, 855.987 1234.12, 867.301 1236.38 C865.038 1225.07, 855.987 1216.02, 844.673 1213.76\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1213.76 C846.936 1225.07, 855.987 1234.12, 867.301 1236.38 C865.038 1225.07, 855.987 1216.02, 844.673 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:54\\\">\\n\",\n              \"<path d=\\\"M1145.87,1145.87 C1148.14 1157.19, 1157.19 1166.24, 1168.5 1168.5 C1166.24 1157.19, 1157.19 1148.14, 1145.87 1145.87\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1145.87 C1148.14 1157.19, 1157.19 1166.24, 1168.5 1168.5 C1166.24 1157.19, 1157.19 1148.14, 1145.87 1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:54\\\">\\n\",\n              \"<path d=\\\"M1191.13,1145.87 C1193.39 1157.19, 1202.44 1166.24, 1213.76 1168.5 C1211.49 1157.19, 1202.44 1148.14, 1191.13 1145.87\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1145.87 C1193.39 1157.19, 1202.44 1166.24, 1213.76 1168.5 C1211.49 1157.19, 1202.44 1148.14, 1191.13 1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:54\\\">\\n\",\n              \"<path d=\\\"M1236.38,1145.87 C1238.65 1157.19, 1247.7 1166.24, 1259.01 1168.5 C1256.75 1157.19, 1247.7 1148.14, 1236.38 1145.87\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,1145.87 C1238.65 1157.19, 1247.7 1166.24, 1259.01 1168.5 C1256.75 1157.19, 1247.7 1148.14, 1236.38 1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:54\\\">\\n\",\n              \"<path d=\\\"M1145.87,1191.13 C1148.14 1202.44, 1157.19 1211.49, 1168.5 1213.76 C1166.24 1202.44, 1157.19 1193.39, 1145.87 1191.13\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1191.13 C1148.14 1202.44, 1157.19 1211.49, 1168.5 1213.76 C1166.24 1202.44, 1157.19 1193.39, 1145.87 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:54\\\">\\n\",\n              \"<path d=\\\"M1191.13,1191.13 C1193.39 1202.44, 1202.44 1211.49, 1213.76 1213.76 C1211.49 1202.44, 1202.44 1193.39, 1191.13 1191.13\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1191.13 C1193.39 1202.44, 1202.44 1211.49, 1213.76 1213.76 C1211.49 1202.44, 1202.44 1193.39, 1191.13 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:54\\\">\\n\",\n              \"<path d=\\\"M1191.13,1236.38 C1193.39 1247.7, 1202.44 1256.75, 1213.76 1259.01 C1211.49 1247.7, 1202.44 1238.65, 1191.13 1236.38\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1236.38 C1193.39 1247.7, 1202.44 1256.75, 1213.76 1259.01 C1211.49 1247.7, 1202.44 1238.65, 1191.13 1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:54\\\">\\n\",\n              \"<path d=\\\"M1236.38,1191.13 C1247.7 1188.87, 1256.75 1179.81, 1259.01 1168.5 C1247.7 1170.76, 1238.65 1179.81, 1236.38 1191.13\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,1191.13 C1247.7 1188.87, 1256.75 1179.81, 1259.01 1168.5 C1247.7 1170.76, 1238.65 1179.81, 1236.38 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:54\\\">\\n\",\n              \"<path d=\\\"M1236.38,1236.38 C1225.07 1238.65, 1216.02 1247.7, 1213.76 1259.01 C1225.07 1256.75, 1234.12 1247.7, 1236.38 1236.38\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,1236.38 C1225.07 1238.65, 1216.02 1247.7, 1213.76 1259.01 C1225.07 1256.75, 1234.12 1247.7, 1236.38 1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:59\\\">\\n\",\n              \"<path d=\\\"M592.25,1330.41 C603.564 1328.15, 612.615 1319.1, 614.878 1307.79 C603.564 1310.05, 594.513 1319.1, 592.25 1330.41\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1330.41 C603.564 1328.15, 612.615 1319.1, 614.878 1307.79 C603.564 1310.05, 594.513 1319.1, 592.25 1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:59\\\">\\n\",\n              \"<path d=\\\"M592.25,1375.67 C580.937 1377.93, 571.886 1386.98, 569.623 1398.3 C580.937 1396.03, 589.988 1386.98, 592.25 1375.67\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1375.67 C580.937 1377.93, 571.886 1386.98, 569.623 1398.3 C580.937 1396.03, 589.988 1386.98, 592.25 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:59\\\">\\n\",\n              \"<path d=\\\"M569.623,1398.3 C571.886 1409.61, 580.937 1418.66, 592.25 1420.92 C589.988 1409.61, 580.937 1400.56, 569.623 1398.3\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,1398.3 C571.886 1409.61, 580.937 1418.66, 592.25 1420.92 C589.988 1409.61, 580.937 1400.56, 569.623 1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:59\\\">\\n\",\n              \"<path d=\\\"M614.878,1353.04 C617.14 1364.36, 626.191 1373.41, 637.505 1375.67 C635.242 1364.36, 626.191 1355.3, 614.878 1353.04\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,1353.04 C617.14 1364.36, 626.191 1373.41, 637.505 1375.67 C635.242 1364.36, 626.191 1355.3, 614.878 1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:59\\\">\\n\",\n              \"<path d=\\\"M660.133,1398.3 C662.395 1409.61, 671.446 1418.66, 682.76 1420.92 C680.497 1409.61, 671.446 1400.56, 660.133 1398.3\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,1398.3 C662.395 1409.61, 671.446 1418.66, 682.76 1420.92 C680.497 1409.61, 671.446 1400.56, 660.133 1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:61\\\">\\n\",\n              \"<path d=\\\"M961.332,1330.41 C963.595 1341.73, 972.646 1350.78, 983.96 1353.04 C981.697 1341.73, 972.646 1332.68, 961.332 1330.41\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1330.41 C963.595 1341.73, 972.646 1350.78, 983.96 1353.04 C981.697 1341.73, 972.646 1332.68, 961.332 1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:61\\\">\\n\",\n              \"<path d=\\\"M1006.59,1330.41 C1008.85 1341.73, 1017.9 1350.78, 1029.21 1353.04 C1026.95 1341.73, 1017.9 1332.68, 1006.59 1330.41\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1330.41 C1008.85 1341.73, 1017.9 1350.78, 1029.21 1353.04 C1026.95 1341.73, 1017.9 1332.68, 1006.59 1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:61\\\">\\n\",\n              \"<path d=\\\"M1051.84,1330.41 C1054.1 1341.73, 1063.16 1350.78, 1074.47 1353.04 C1072.21 1341.73, 1063.16 1332.68, 1051.84 1330.41\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,1330.41 C1054.1 1341.73, 1063.16 1350.78, 1074.47 1353.04 C1072.21 1341.73, 1063.16 1332.68, 1051.84 1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:61\\\">\\n\",\n              \"<path d=\\\"M961.332,1375.67 C963.595 1386.98, 972.646 1396.03, 983.96 1398.3 C981.697 1386.98, 972.646 1377.93, 961.332 1375.67\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1375.67 C963.595 1386.98, 972.646 1396.03, 983.96 1398.3 C981.697 1386.98, 972.646 1377.93, 961.332 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:61\\\">\\n\",\n              \"<path d=\\\"M1006.59,1375.67 C1008.85 1386.98, 1017.9 1396.03, 1029.21 1398.3 C1026.95 1386.98, 1017.9 1377.93, 1006.59 1375.67\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1375.67 C1008.85 1386.98, 1017.9 1396.03, 1029.21 1398.3 C1026.95 1386.98, 1017.9 1377.93, 1006.59 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:61\\\">\\n\",\n              \"<path d=\\\"M1006.59,1420.92 C1008.85 1432.24, 1017.9 1441.29, 1029.21 1443.55 C1026.95 1432.24, 1017.9 1423.19, 1006.59 1420.92\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1420.92 C1008.85 1432.24, 1017.9 1441.29, 1029.21 1443.55 C1026.95 1432.24, 1017.9 1423.19, 1006.59 1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:61\\\">\\n\",\n              \"<path d=\\\"M1051.84,1375.67 C1063.16 1373.41, 1072.21 1364.36, 1074.47 1353.04 C1063.16 1355.3, 1054.1 1364.36, 1051.84 1375.67\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,1375.67 C1063.16 1373.41, 1072.21 1364.36, 1074.47 1353.04 C1063.16 1355.3, 1054.1 1364.36, 1051.84 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:1\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"16\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"16\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:1\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:2\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"16\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"16\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:2\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:3\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:3\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:4\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:4\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:4\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:5\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:6\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:6\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:6\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:6\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:7\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:7\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:7\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:7\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:8\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:8\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:9\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:9\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:10\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:10\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:11\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:11\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:11\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:11\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:12\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:12\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:13\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:13\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:13\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:13\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:13\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:13\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:13\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:13\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:14\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:14\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:14\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:14\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:14\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:14\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:14\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:14\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:15\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:15\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:15\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:15\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:15\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:15\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:15\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:15\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:16\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:16\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:16\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:16\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:16\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:16\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:16\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:16\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:17\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:17\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:18\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:18\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:18\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:18\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:19\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:19\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:20\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:20\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:20\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:20\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:20\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:20\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:20\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:20\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:21\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:21\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:21\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:21\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:21\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:21\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:21\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:21\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:22\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:22\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:22\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:22\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:22\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:22\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:22\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:22\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:23\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:23\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:23\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:23\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:23\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:23\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:23\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:23\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:24\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:24\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:25\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:25\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:25\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:25\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:26\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:26\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:27\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:27\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:27\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:27\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:27\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:27\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:27\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:27\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:28\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:28\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:28\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:28\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:28\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:28\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:28\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:28\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:29\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:29\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:29\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:29\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:29\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:29\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:29\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:29\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:30\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:30\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:30\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:30\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:30\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:30\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:30\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:30\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:31\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:31\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:32\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:32\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:32\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:32\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:33\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:33\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:34\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:34\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:34\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:34\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:34\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:34\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:34\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:34\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:35\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:35\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:35\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:35\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:35\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:35\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:35\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:35\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:36\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:36\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:36\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:36\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:36\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:36\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:36\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:36\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:37\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:37\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:37\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:37\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:37\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:37\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:37\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:37\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:38\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:38\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:39\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:39\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:39\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:39\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:40\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:40\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:41\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:41\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:41\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:41\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:41\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:41\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:41\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:41\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:42\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:42\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:42\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:42\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:42\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:42\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:42\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:42\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:43\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:43\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:43\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:43\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:43\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:43\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:43\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:43\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:44\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:44\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:44\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:44\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:44\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:44\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:44\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:44\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:45\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:45\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:46\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:46\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:46\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:46\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:47\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:47\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:48\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:48\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:48\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:48\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:48\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:48\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:48\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:48\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:49\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:49\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:49\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:49\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:49\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:49\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:49\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:49\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:50\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:50\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:50\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:50\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:50\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:50\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:50\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:50\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:51\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:51\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:51\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:51\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:51\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:51\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:51\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:51\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:52\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:52\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:53\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:53\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:53\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:53\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:54\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:54\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:55\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:55\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:55\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:55\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:55\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:55\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:55\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:55\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:56\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:56\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:56\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:56\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:56\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:56\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:56\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:56\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:57\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:57\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:57\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:57\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:58\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:58\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:58\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:58\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:59\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:60\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:60\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:60\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:61\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:61\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:62\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:62\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:62\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:62\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:62\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:62\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:62\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:62\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:63\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:63\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:63\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:63\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:63\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:63\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:63\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:63\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<defs>\\n\",\n              \"<radialGradient id=\\\"xgrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#FF4040\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"<radialGradient id=\\\"ygrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#59FF7A\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"<radialGradient id=\\\"zgrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#4DA6FF\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"</defs>\\n\",\n              \"<g id=\\\"qubit_dots\\\">\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"38.6274\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"61.2548\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"83.8822\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"129.137\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"38.6274\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"61.2548\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"83.8822\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"106.51\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"129.137\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"151.764\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"16\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"38.6274\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"61.2548\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"83.8822\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"106.51\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"129.137\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"106.51\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"223.168\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"245.796\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"268.423\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"313.678\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"223.168\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"245.796\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"268.423\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"291.051\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"313.678\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"336.305\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"200.541\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"223.168\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"245.796\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"268.423\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"291.051\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"313.678\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"291.051\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"407.709\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"430.337\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"452.964\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"498.219\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"407.709\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"430.337\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"452.964\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"475.592\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"498.219\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"520.846\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"385.082\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"407.709\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"430.337\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"452.964\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"475.592\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"498.219\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"475.592\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"592.25\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"614.878\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"637.505\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"682.76\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"592.25\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"614.878\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"637.505\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"660.133\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"682.76\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"705.387\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"569.623\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"592.25\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"614.878\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"637.505\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"660.133\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"682.76\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"660.133\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"776.791\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"799.419\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"822.046\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"867.301\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"776.791\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"799.419\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"822.046\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"844.673\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"867.301\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"889.928\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"754.164\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"776.791\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"799.419\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"822.046\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"844.673\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"867.301\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"844.673\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"961.332\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"983.96\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"1006.59\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"1051.84\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"961.332\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"983.96\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"1006.59\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"1029.21\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"1051.84\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"1074.47\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"938.705\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"961.332\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"983.96\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"1006.59\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"1029.21\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"1051.84\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"1029.21\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"1145.87\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"1168.5\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"1191.13\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"1236.38\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"1145.87\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"1168.5\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"1191.13\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"1213.76\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"1236.38\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"1259.01\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"1123.25\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"1145.87\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"1168.5\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"1191.13\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"1213.76\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"1236.38\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"1213.76\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"1330.41\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"1353.04\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"1375.67\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"1420.92\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"1330.41\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"1353.04\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"1375.67\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"1398.3\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"1420.92\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"1443.55\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"1307.79\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"1330.41\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"1353.04\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"1375.67\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"1398.3\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"1420.92\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"1398.3\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:8\\\" cx=\\\"38.6274\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:8\\\" cx=\\\"61.2548\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:8\\\" cx=\\\"83.8822\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:8\\\" cx=\\\"129.137\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:8\\\" cx=\\\"38.6274\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:8\\\" cx=\\\"61.2548\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:8\\\" cx=\\\"83.8822\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:8\\\" cx=\\\"106.51\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:8\\\" cx=\\\"129.137\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:8\\\" cx=\\\"151.764\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:8\\\" cx=\\\"16\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:8\\\" cx=\\\"38.6274\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:8\\\" cx=\\\"61.2548\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:8\\\" cx=\\\"83.8822\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:8\\\" cx=\\\"106.51\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:8\\\" cx=\\\"129.137\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:8\\\" cx=\\\"106.51\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:9\\\" cx=\\\"223.168\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:9\\\" cx=\\\"245.796\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:9\\\" cx=\\\"268.423\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:9\\\" cx=\\\"313.678\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:9\\\" cx=\\\"223.168\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:9\\\" cx=\\\"245.796\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:9\\\" cx=\\\"268.423\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:9\\\" cx=\\\"291.051\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:9\\\" cx=\\\"313.678\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:9\\\" cx=\\\"336.305\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:9\\\" cx=\\\"200.541\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:9\\\" cx=\\\"223.168\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:9\\\" cx=\\\"245.796\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:9\\\" cx=\\\"268.423\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:9\\\" cx=\\\"291.051\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:9\\\" cx=\\\"313.678\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:9\\\" cx=\\\"291.051\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:10\\\" cx=\\\"407.709\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:10\\\" cx=\\\"430.337\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:10\\\" cx=\\\"452.964\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:10\\\" cx=\\\"498.219\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:10\\\" cx=\\\"407.709\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:10\\\" cx=\\\"430.337\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:10\\\" cx=\\\"452.964\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:10\\\" cx=\\\"475.592\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:10\\\" cx=\\\"498.219\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:10\\\" cx=\\\"520.846\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:10\\\" cx=\\\"385.082\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:10\\\" cx=\\\"407.709\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:10\\\" cx=\\\"430.337\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:10\\\" cx=\\\"452.964\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:10\\\" cx=\\\"475.592\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:10\\\" cx=\\\"498.219\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:10\\\" cx=\\\"475.592\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:11\\\" cx=\\\"592.25\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:11\\\" cx=\\\"614.878\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:11\\\" cx=\\\"637.505\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:11\\\" cx=\\\"682.76\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:11\\\" cx=\\\"592.25\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:11\\\" cx=\\\"614.878\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:11\\\" cx=\\\"637.505\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:11\\\" cx=\\\"660.133\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:11\\\" cx=\\\"682.76\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:11\\\" cx=\\\"705.387\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:11\\\" cx=\\\"569.623\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:11\\\" cx=\\\"592.25\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:11\\\" cx=\\\"614.878\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:11\\\" cx=\\\"637.505\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:11\\\" cx=\\\"660.133\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:11\\\" cx=\\\"682.76\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:11\\\" cx=\\\"660.133\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:12\\\" cx=\\\"776.791\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:12\\\" cx=\\\"799.419\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:12\\\" cx=\\\"822.046\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:12\\\" cx=\\\"867.301\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:12\\\" cx=\\\"776.791\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:12\\\" cx=\\\"799.419\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:12\\\" cx=\\\"822.046\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:12\\\" cx=\\\"844.673\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:12\\\" cx=\\\"867.301\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:12\\\" cx=\\\"889.928\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:12\\\" cx=\\\"754.164\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:12\\\" cx=\\\"776.791\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:12\\\" cx=\\\"799.419\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:12\\\" cx=\\\"822.046\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:12\\\" cx=\\\"844.673\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:12\\\" cx=\\\"867.301\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:12\\\" cx=\\\"844.673\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:13\\\" cx=\\\"961.332\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:13\\\" cx=\\\"983.96\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:13\\\" cx=\\\"1006.59\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:13\\\" cx=\\\"1051.84\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:13\\\" cx=\\\"961.332\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:13\\\" cx=\\\"983.96\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:13\\\" cx=\\\"1006.59\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:13\\\" cx=\\\"1029.21\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:13\\\" cx=\\\"1051.84\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:13\\\" cx=\\\"1074.47\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:13\\\" cx=\\\"938.705\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:13\\\" cx=\\\"961.332\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:13\\\" cx=\\\"983.96\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:13\\\" cx=\\\"1006.59\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:13\\\" cx=\\\"1029.21\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:13\\\" cx=\\\"1051.84\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:13\\\" cx=\\\"1029.21\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:14\\\" cx=\\\"1145.87\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:14\\\" cx=\\\"1168.5\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:14\\\" cx=\\\"1191.13\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:14\\\" cx=\\\"1236.38\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:14\\\" cx=\\\"1145.87\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:14\\\" cx=\\\"1168.5\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:14\\\" cx=\\\"1191.13\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:14\\\" cx=\\\"1213.76\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:14\\\" cx=\\\"1236.38\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:14\\\" cx=\\\"1259.01\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:14\\\" cx=\\\"1123.25\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:14\\\" cx=\\\"1145.87\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:14\\\" cx=\\\"1168.5\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:14\\\" cx=\\\"1191.13\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:14\\\" cx=\\\"1213.76\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:14\\\" cx=\\\"1236.38\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:14\\\" cx=\\\"1213.76\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:15\\\" cx=\\\"1330.41\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:15\\\" cx=\\\"1353.04\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:15\\\" cx=\\\"1375.67\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:15\\\" cx=\\\"1420.92\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:15\\\" cx=\\\"1330.41\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:15\\\" cx=\\\"1353.04\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:15\\\" cx=\\\"1375.67\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:15\\\" cx=\\\"1398.3\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:15\\\" cx=\\\"1420.92\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:15\\\" cx=\\\"1443.55\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:15\\\" cx=\\\"1307.79\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:15\\\" cx=\\\"1330.41\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:15\\\" cx=\\\"1353.04\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:15\\\" cx=\\\"1375.67\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:15\\\" cx=\\\"1398.3\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:15\\\" cx=\\\"1420.92\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:15\\\" cx=\\\"1398.3\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:16\\\" cx=\\\"38.6274\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:16\\\" cx=\\\"61.2548\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:16\\\" cx=\\\"83.8822\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:16\\\" cx=\\\"129.137\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:16\\\" cx=\\\"38.6274\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:16\\\" cx=\\\"61.2548\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:16\\\" cx=\\\"83.8822\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:16\\\" cx=\\\"106.51\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:16\\\" cx=\\\"129.137\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:16\\\" cx=\\\"151.764\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:16\\\" cx=\\\"16\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:16\\\" cx=\\\"38.6274\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:16\\\" cx=\\\"61.2548\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:16\\\" cx=\\\"83.8822\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:16\\\" cx=\\\"106.51\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:16\\\" cx=\\\"129.137\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:16\\\" cx=\\\"106.51\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:17\\\" cx=\\\"223.168\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:17\\\" cx=\\\"245.796\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:17\\\" cx=\\\"268.423\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:17\\\" cx=\\\"313.678\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:17\\\" cx=\\\"223.168\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:17\\\" cx=\\\"245.796\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:17\\\" cx=\\\"268.423\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:17\\\" cx=\\\"291.051\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:17\\\" cx=\\\"313.678\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:17\\\" cx=\\\"336.305\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:17\\\" cx=\\\"200.541\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:17\\\" cx=\\\"223.168\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:17\\\" cx=\\\"245.796\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:17\\\" cx=\\\"268.423\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:17\\\" cx=\\\"291.051\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:17\\\" cx=\\\"313.678\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:17\\\" cx=\\\"291.051\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:18\\\" cx=\\\"407.709\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:18\\\" cx=\\\"430.337\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:18\\\" cx=\\\"452.964\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:18\\\" cx=\\\"498.219\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:18\\\" cx=\\\"407.709\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:18\\\" cx=\\\"430.337\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:18\\\" cx=\\\"452.964\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:18\\\" cx=\\\"475.592\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:18\\\" cx=\\\"498.219\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:18\\\" cx=\\\"520.846\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:18\\\" cx=\\\"385.082\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:18\\\" cx=\\\"407.709\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:18\\\" cx=\\\"430.337\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:18\\\" cx=\\\"452.964\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:18\\\" cx=\\\"475.592\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:18\\\" cx=\\\"498.219\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:18\\\" cx=\\\"475.592\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:19\\\" cx=\\\"592.25\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:19\\\" cx=\\\"614.878\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:19\\\" cx=\\\"637.505\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:19\\\" cx=\\\"682.76\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:19\\\" cx=\\\"592.25\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:19\\\" cx=\\\"614.878\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:19\\\" cx=\\\"637.505\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:19\\\" cx=\\\"660.133\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:19\\\" cx=\\\"682.76\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:19\\\" cx=\\\"705.387\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:19\\\" cx=\\\"569.623\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:19\\\" cx=\\\"592.25\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:19\\\" cx=\\\"614.878\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:19\\\" cx=\\\"637.505\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:19\\\" cx=\\\"660.133\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:19\\\" cx=\\\"682.76\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:19\\\" cx=\\\"660.133\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:20\\\" cx=\\\"776.791\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:20\\\" cx=\\\"799.419\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:20\\\" cx=\\\"822.046\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:20\\\" cx=\\\"867.301\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:20\\\" cx=\\\"776.791\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:20\\\" cx=\\\"799.419\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:20\\\" cx=\\\"822.046\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:20\\\" cx=\\\"844.673\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:20\\\" cx=\\\"867.301\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:20\\\" cx=\\\"889.928\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:20\\\" cx=\\\"754.164\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:20\\\" cx=\\\"776.791\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:20\\\" cx=\\\"799.419\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:20\\\" cx=\\\"822.046\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:20\\\" cx=\\\"844.673\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:20\\\" cx=\\\"867.301\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:20\\\" cx=\\\"844.673\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:21\\\" cx=\\\"961.332\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:21\\\" cx=\\\"983.96\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:21\\\" cx=\\\"1006.59\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:21\\\" cx=\\\"1051.84\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:21\\\" cx=\\\"961.332\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:21\\\" cx=\\\"983.96\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:21\\\" cx=\\\"1006.59\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:21\\\" cx=\\\"1029.21\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:21\\\" cx=\\\"1051.84\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:21\\\" cx=\\\"1074.47\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:21\\\" cx=\\\"938.705\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:21\\\" cx=\\\"961.332\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:21\\\" cx=\\\"983.96\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:21\\\" cx=\\\"1006.59\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:21\\\" cx=\\\"1029.21\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:21\\\" cx=\\\"1051.84\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:21\\\" cx=\\\"1029.21\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:22\\\" cx=\\\"1145.87\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:22\\\" cx=\\\"1168.5\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:22\\\" cx=\\\"1191.13\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:22\\\" cx=\\\"1236.38\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:22\\\" cx=\\\"1145.87\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:22\\\" cx=\\\"1168.5\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:22\\\" cx=\\\"1191.13\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:22\\\" cx=\\\"1213.76\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:22\\\" cx=\\\"1236.38\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:22\\\" cx=\\\"1259.01\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:22\\\" cx=\\\"1123.25\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:22\\\" cx=\\\"1145.87\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:22\\\" cx=\\\"1168.5\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:22\\\" cx=\\\"1191.13\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:22\\\" cx=\\\"1213.76\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:22\\\" cx=\\\"1236.38\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:22\\\" cx=\\\"1213.76\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:23\\\" cx=\\\"1330.41\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:23\\\" cx=\\\"1353.04\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:23\\\" cx=\\\"1375.67\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:23\\\" cx=\\\"1420.92\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:23\\\" cx=\\\"1330.41\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:23\\\" cx=\\\"1353.04\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:23\\\" cx=\\\"1375.67\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:23\\\" cx=\\\"1398.3\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:23\\\" cx=\\\"1420.92\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:23\\\" cx=\\\"1443.55\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:23\\\" cx=\\\"1307.79\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:23\\\" cx=\\\"1330.41\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:23\\\" cx=\\\"1353.04\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:23\\\" cx=\\\"1375.67\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:23\\\" cx=\\\"1398.3\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:23\\\" cx=\\\"1420.92\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:23\\\" cx=\\\"1398.3\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:24\\\" cx=\\\"38.6274\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:24\\\" cx=\\\"61.2548\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:24\\\" cx=\\\"83.8822\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:24\\\" cx=\\\"129.137\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:24\\\" cx=\\\"38.6274\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:24\\\" cx=\\\"61.2548\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:24\\\" cx=\\\"83.8822\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:24\\\" cx=\\\"106.51\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:24\\\" cx=\\\"129.137\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:24\\\" cx=\\\"151.764\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:24\\\" cx=\\\"16\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:24\\\" cx=\\\"38.6274\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:24\\\" cx=\\\"61.2548\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:24\\\" cx=\\\"83.8822\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:24\\\" cx=\\\"106.51\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:24\\\" cx=\\\"129.137\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:24\\\" cx=\\\"106.51\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:25\\\" cx=\\\"223.168\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:25\\\" cx=\\\"245.796\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:25\\\" cx=\\\"268.423\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:25\\\" cx=\\\"313.678\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:25\\\" cx=\\\"223.168\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:25\\\" cx=\\\"245.796\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:25\\\" cx=\\\"268.423\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:25\\\" cx=\\\"291.051\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:25\\\" cx=\\\"313.678\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:25\\\" cx=\\\"336.305\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:25\\\" cx=\\\"200.541\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:25\\\" cx=\\\"223.168\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:25\\\" cx=\\\"245.796\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:25\\\" cx=\\\"268.423\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:25\\\" cx=\\\"291.051\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:25\\\" cx=\\\"313.678\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:25\\\" cx=\\\"291.051\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:26\\\" cx=\\\"407.709\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:26\\\" cx=\\\"430.337\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:26\\\" cx=\\\"452.964\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:26\\\" cx=\\\"498.219\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:26\\\" cx=\\\"407.709\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:26\\\" cx=\\\"430.337\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:26\\\" cx=\\\"452.964\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:26\\\" cx=\\\"475.592\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:26\\\" cx=\\\"498.219\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:26\\\" cx=\\\"520.846\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:26\\\" cx=\\\"385.082\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:26\\\" cx=\\\"407.709\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:26\\\" cx=\\\"430.337\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:26\\\" cx=\\\"452.964\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:26\\\" cx=\\\"475.592\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:26\\\" cx=\\\"498.219\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:26\\\" cx=\\\"475.592\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:27\\\" cx=\\\"592.25\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:27\\\" cx=\\\"614.878\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:27\\\" cx=\\\"637.505\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:27\\\" cx=\\\"682.76\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:27\\\" cx=\\\"592.25\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:27\\\" cx=\\\"614.878\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:27\\\" cx=\\\"637.505\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:27\\\" cx=\\\"660.133\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:27\\\" cx=\\\"682.76\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:27\\\" cx=\\\"705.387\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:27\\\" cx=\\\"569.623\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:27\\\" cx=\\\"592.25\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:27\\\" cx=\\\"614.878\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:27\\\" cx=\\\"637.505\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:27\\\" cx=\\\"660.133\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:27\\\" cx=\\\"682.76\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:27\\\" cx=\\\"660.133\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:28\\\" cx=\\\"776.791\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:28\\\" cx=\\\"799.419\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:28\\\" cx=\\\"822.046\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:28\\\" cx=\\\"867.301\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:28\\\" cx=\\\"776.791\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:28\\\" cx=\\\"799.419\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:28\\\" cx=\\\"822.046\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:28\\\" cx=\\\"844.673\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:28\\\" cx=\\\"867.301\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:28\\\" cx=\\\"889.928\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:28\\\" cx=\\\"754.164\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:28\\\" cx=\\\"776.791\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:28\\\" cx=\\\"799.419\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:28\\\" cx=\\\"822.046\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:28\\\" cx=\\\"844.673\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:28\\\" cx=\\\"867.301\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:28\\\" cx=\\\"844.673\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:29\\\" cx=\\\"961.332\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:29\\\" cx=\\\"983.96\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:29\\\" cx=\\\"1006.59\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:29\\\" cx=\\\"1051.84\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:29\\\" cx=\\\"961.332\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:29\\\" cx=\\\"983.96\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:29\\\" cx=\\\"1006.59\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:29\\\" cx=\\\"1029.21\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:29\\\" cx=\\\"1051.84\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:29\\\" cx=\\\"1074.47\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:29\\\" cx=\\\"938.705\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:29\\\" cx=\\\"961.332\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:29\\\" cx=\\\"983.96\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:29\\\" cx=\\\"1006.59\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:29\\\" cx=\\\"1029.21\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:29\\\" cx=\\\"1051.84\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:29\\\" cx=\\\"1029.21\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:30\\\" cx=\\\"1145.87\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:30\\\" cx=\\\"1168.5\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:30\\\" cx=\\\"1191.13\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:30\\\" cx=\\\"1236.38\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:30\\\" cx=\\\"1145.87\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:30\\\" cx=\\\"1168.5\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:30\\\" cx=\\\"1191.13\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:30\\\" cx=\\\"1213.76\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:30\\\" cx=\\\"1236.38\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:30\\\" cx=\\\"1259.01\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:30\\\" cx=\\\"1123.25\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:30\\\" cx=\\\"1145.87\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:30\\\" cx=\\\"1168.5\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:30\\\" cx=\\\"1191.13\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:30\\\" cx=\\\"1213.76\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:30\\\" cx=\\\"1236.38\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:30\\\" cx=\\\"1213.76\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:31\\\" cx=\\\"1330.41\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:31\\\" cx=\\\"1353.04\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:31\\\" cx=\\\"1375.67\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:31\\\" cx=\\\"1420.92\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:31\\\" cx=\\\"1330.41\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:31\\\" cx=\\\"1353.04\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:31\\\" cx=\\\"1375.67\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:31\\\" cx=\\\"1398.3\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:31\\\" cx=\\\"1420.92\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:31\\\" cx=\\\"1443.55\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:31\\\" cx=\\\"1307.79\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:31\\\" cx=\\\"1330.41\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:31\\\" cx=\\\"1353.04\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:31\\\" cx=\\\"1375.67\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:31\\\" cx=\\\"1398.3\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:31\\\" cx=\\\"1420.92\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:31\\\" cx=\\\"1398.3\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:32\\\" cx=\\\"38.6274\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:32\\\" cx=\\\"61.2548\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:32\\\" cx=\\\"83.8822\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:32\\\" cx=\\\"129.137\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:32\\\" cx=\\\"38.6274\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:32\\\" cx=\\\"61.2548\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:32\\\" cx=\\\"83.8822\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:32\\\" cx=\\\"106.51\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:32\\\" cx=\\\"129.137\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:32\\\" cx=\\\"151.764\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:32\\\" cx=\\\"16\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:32\\\" cx=\\\"38.6274\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:32\\\" cx=\\\"61.2548\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:32\\\" cx=\\\"83.8822\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:32\\\" cx=\\\"106.51\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:32\\\" cx=\\\"129.137\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:32\\\" cx=\\\"106.51\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:33\\\" cx=\\\"223.168\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:33\\\" cx=\\\"245.796\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:33\\\" cx=\\\"268.423\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:33\\\" cx=\\\"313.678\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:33\\\" cx=\\\"223.168\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:33\\\" cx=\\\"245.796\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:33\\\" cx=\\\"268.423\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:33\\\" cx=\\\"291.051\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:33\\\" cx=\\\"313.678\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:33\\\" cx=\\\"336.305\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:33\\\" cx=\\\"200.541\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:33\\\" cx=\\\"223.168\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:33\\\" cx=\\\"245.796\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:33\\\" cx=\\\"268.423\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:33\\\" cx=\\\"291.051\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:33\\\" cx=\\\"313.678\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:33\\\" cx=\\\"291.051\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:34\\\" cx=\\\"407.709\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:34\\\" cx=\\\"430.337\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:34\\\" cx=\\\"452.964\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:34\\\" cx=\\\"498.219\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:34\\\" cx=\\\"407.709\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:34\\\" cx=\\\"430.337\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:34\\\" cx=\\\"452.964\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:34\\\" cx=\\\"475.592\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:34\\\" cx=\\\"498.219\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:34\\\" cx=\\\"520.846\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:34\\\" cx=\\\"385.082\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:34\\\" cx=\\\"407.709\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:34\\\" cx=\\\"430.337\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:34\\\" cx=\\\"452.964\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:34\\\" cx=\\\"475.592\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:34\\\" cx=\\\"498.219\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:34\\\" cx=\\\"475.592\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:35\\\" cx=\\\"592.25\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:35\\\" cx=\\\"614.878\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:35\\\" cx=\\\"637.505\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:35\\\" cx=\\\"682.76\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:35\\\" cx=\\\"592.25\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:35\\\" cx=\\\"614.878\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:35\\\" cx=\\\"637.505\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:35\\\" cx=\\\"660.133\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:35\\\" cx=\\\"682.76\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:35\\\" cx=\\\"705.387\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:35\\\" cx=\\\"569.623\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:35\\\" cx=\\\"592.25\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:35\\\" cx=\\\"614.878\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:35\\\" cx=\\\"637.505\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:35\\\" cx=\\\"660.133\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:35\\\" cx=\\\"682.76\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:35\\\" cx=\\\"660.133\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:36\\\" cx=\\\"776.791\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:36\\\" cx=\\\"799.419\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:36\\\" cx=\\\"822.046\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:36\\\" cx=\\\"867.301\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:36\\\" cx=\\\"776.791\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:36\\\" cx=\\\"799.419\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:36\\\" cx=\\\"822.046\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:36\\\" cx=\\\"844.673\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:36\\\" cx=\\\"867.301\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:36\\\" cx=\\\"889.928\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:36\\\" cx=\\\"754.164\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:36\\\" cx=\\\"776.791\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:36\\\" cx=\\\"799.419\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:36\\\" cx=\\\"822.046\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:36\\\" cx=\\\"844.673\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:36\\\" cx=\\\"867.301\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:36\\\" cx=\\\"844.673\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:37\\\" cx=\\\"961.332\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:37\\\" cx=\\\"983.96\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:37\\\" cx=\\\"1006.59\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:37\\\" cx=\\\"1051.84\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:37\\\" cx=\\\"961.332\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:37\\\" cx=\\\"983.96\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:37\\\" cx=\\\"1006.59\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:37\\\" cx=\\\"1029.21\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:37\\\" cx=\\\"1051.84\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:37\\\" cx=\\\"1074.47\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:37\\\" cx=\\\"938.705\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:37\\\" cx=\\\"961.332\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:37\\\" cx=\\\"983.96\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:37\\\" cx=\\\"1006.59\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:37\\\" cx=\\\"1029.21\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:37\\\" cx=\\\"1051.84\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:37\\\" cx=\\\"1029.21\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:38\\\" cx=\\\"1145.87\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:38\\\" cx=\\\"1168.5\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:38\\\" cx=\\\"1191.13\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:38\\\" cx=\\\"1236.38\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:38\\\" cx=\\\"1145.87\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:38\\\" cx=\\\"1168.5\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:38\\\" cx=\\\"1191.13\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:38\\\" cx=\\\"1213.76\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:38\\\" cx=\\\"1236.38\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:38\\\" cx=\\\"1259.01\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:38\\\" cx=\\\"1123.25\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:38\\\" cx=\\\"1145.87\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:38\\\" cx=\\\"1168.5\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:38\\\" cx=\\\"1191.13\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:38\\\" cx=\\\"1213.76\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:38\\\" cx=\\\"1236.38\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:38\\\" cx=\\\"1213.76\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:39\\\" cx=\\\"1330.41\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:39\\\" cx=\\\"1353.04\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:39\\\" cx=\\\"1375.67\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:39\\\" cx=\\\"1420.92\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:39\\\" cx=\\\"1330.41\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:39\\\" cx=\\\"1353.04\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:39\\\" cx=\\\"1375.67\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:39\\\" cx=\\\"1398.3\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:39\\\" cx=\\\"1420.92\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:39\\\" cx=\\\"1443.55\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:39\\\" cx=\\\"1307.79\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:39\\\" cx=\\\"1330.41\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:39\\\" cx=\\\"1353.04\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:39\\\" cx=\\\"1375.67\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:39\\\" cx=\\\"1398.3\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:39\\\" cx=\\\"1420.92\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:39\\\" cx=\\\"1398.3\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:40\\\" cx=\\\"38.6274\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:40\\\" cx=\\\"61.2548\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:40\\\" cx=\\\"83.8822\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:40\\\" cx=\\\"129.137\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:40\\\" cx=\\\"38.6274\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:40\\\" cx=\\\"61.2548\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:40\\\" cx=\\\"83.8822\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:40\\\" cx=\\\"106.51\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:40\\\" cx=\\\"129.137\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:40\\\" cx=\\\"151.764\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:40\\\" cx=\\\"16\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:40\\\" cx=\\\"38.6274\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:40\\\" cx=\\\"61.2548\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:40\\\" cx=\\\"83.8822\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:40\\\" cx=\\\"106.51\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:40\\\" cx=\\\"129.137\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:40\\\" cx=\\\"106.51\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:41\\\" cx=\\\"223.168\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:41\\\" cx=\\\"245.796\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:41\\\" cx=\\\"268.423\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:41\\\" cx=\\\"313.678\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:41\\\" cx=\\\"223.168\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:41\\\" cx=\\\"245.796\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:41\\\" cx=\\\"268.423\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:41\\\" cx=\\\"291.051\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:41\\\" cx=\\\"313.678\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:41\\\" cx=\\\"336.305\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:41\\\" cx=\\\"200.541\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:41\\\" cx=\\\"223.168\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:41\\\" cx=\\\"245.796\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:41\\\" cx=\\\"268.423\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:41\\\" cx=\\\"291.051\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:41\\\" cx=\\\"313.678\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:41\\\" cx=\\\"291.051\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:42\\\" cx=\\\"407.709\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:42\\\" cx=\\\"430.337\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:42\\\" cx=\\\"452.964\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:42\\\" cx=\\\"498.219\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:42\\\" cx=\\\"407.709\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:42\\\" cx=\\\"430.337\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:42\\\" cx=\\\"452.964\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:42\\\" cx=\\\"475.592\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:42\\\" cx=\\\"498.219\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:42\\\" cx=\\\"520.846\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:42\\\" cx=\\\"385.082\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:42\\\" cx=\\\"407.709\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:42\\\" cx=\\\"430.337\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:42\\\" cx=\\\"452.964\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:42\\\" cx=\\\"475.592\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:42\\\" cx=\\\"498.219\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:42\\\" cx=\\\"475.592\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:43\\\" cx=\\\"592.25\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:43\\\" cx=\\\"614.878\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:43\\\" cx=\\\"637.505\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:43\\\" cx=\\\"682.76\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:43\\\" cx=\\\"592.25\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:43\\\" cx=\\\"614.878\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:43\\\" cx=\\\"637.505\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:43\\\" cx=\\\"660.133\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:43\\\" cx=\\\"682.76\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:43\\\" cx=\\\"705.387\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:43\\\" cx=\\\"569.623\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:43\\\" cx=\\\"592.25\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:43\\\" cx=\\\"614.878\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:43\\\" cx=\\\"637.505\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:43\\\" cx=\\\"660.133\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:43\\\" cx=\\\"682.76\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:43\\\" cx=\\\"660.133\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:44\\\" cx=\\\"776.791\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:44\\\" cx=\\\"799.419\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:44\\\" cx=\\\"822.046\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:44\\\" cx=\\\"867.301\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:44\\\" cx=\\\"776.791\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:44\\\" cx=\\\"799.419\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:44\\\" cx=\\\"822.046\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:44\\\" cx=\\\"844.673\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:44\\\" cx=\\\"867.301\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:44\\\" cx=\\\"889.928\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:44\\\" cx=\\\"754.164\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:44\\\" cx=\\\"776.791\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:44\\\" cx=\\\"799.419\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:44\\\" cx=\\\"822.046\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:44\\\" cx=\\\"844.673\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:44\\\" cx=\\\"867.301\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:44\\\" cx=\\\"844.673\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:45\\\" cx=\\\"961.332\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:45\\\" cx=\\\"983.96\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:45\\\" cx=\\\"1006.59\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:45\\\" cx=\\\"1051.84\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:45\\\" cx=\\\"961.332\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:45\\\" cx=\\\"983.96\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:45\\\" cx=\\\"1006.59\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:45\\\" cx=\\\"1029.21\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:45\\\" cx=\\\"1051.84\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:45\\\" cx=\\\"1074.47\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:45\\\" cx=\\\"938.705\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:45\\\" cx=\\\"961.332\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:45\\\" cx=\\\"983.96\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:45\\\" cx=\\\"1006.59\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:45\\\" cx=\\\"1029.21\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:45\\\" cx=\\\"1051.84\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:45\\\" cx=\\\"1029.21\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:46\\\" cx=\\\"1145.87\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:46\\\" cx=\\\"1168.5\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:46\\\" cx=\\\"1191.13\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:46\\\" cx=\\\"1236.38\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:46\\\" cx=\\\"1145.87\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:46\\\" cx=\\\"1168.5\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:46\\\" cx=\\\"1191.13\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:46\\\" cx=\\\"1213.76\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:46\\\" cx=\\\"1236.38\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:46\\\" cx=\\\"1259.01\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:46\\\" cx=\\\"1123.25\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:46\\\" cx=\\\"1145.87\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:46\\\" cx=\\\"1168.5\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:46\\\" cx=\\\"1191.13\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:46\\\" cx=\\\"1213.76\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:46\\\" cx=\\\"1236.38\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:46\\\" cx=\\\"1213.76\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:47\\\" cx=\\\"1330.41\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:47\\\" cx=\\\"1353.04\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:47\\\" cx=\\\"1375.67\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:47\\\" cx=\\\"1420.92\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:47\\\" cx=\\\"1330.41\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:47\\\" cx=\\\"1353.04\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:47\\\" cx=\\\"1375.67\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:47\\\" cx=\\\"1398.3\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:47\\\" cx=\\\"1420.92\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:47\\\" cx=\\\"1443.55\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:47\\\" cx=\\\"1307.79\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:47\\\" cx=\\\"1330.41\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:47\\\" cx=\\\"1353.04\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:47\\\" cx=\\\"1375.67\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:47\\\" cx=\\\"1398.3\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:47\\\" cx=\\\"1420.92\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:47\\\" cx=\\\"1398.3\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:48\\\" cx=\\\"38.6274\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:48\\\" cx=\\\"61.2548\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:48\\\" cx=\\\"83.8822\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:48\\\" cx=\\\"129.137\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:48\\\" cx=\\\"38.6274\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:48\\\" cx=\\\"61.2548\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:48\\\" cx=\\\"83.8822\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:48\\\" cx=\\\"106.51\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:48\\\" cx=\\\"129.137\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:48\\\" cx=\\\"151.764\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:48\\\" cx=\\\"16\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:48\\\" cx=\\\"38.6274\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:48\\\" cx=\\\"61.2548\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:48\\\" cx=\\\"83.8822\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:48\\\" cx=\\\"106.51\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:48\\\" cx=\\\"129.137\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:48\\\" cx=\\\"106.51\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:49\\\" cx=\\\"223.168\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:49\\\" cx=\\\"245.796\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:49\\\" cx=\\\"268.423\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:49\\\" cx=\\\"313.678\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:49\\\" cx=\\\"223.168\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:49\\\" cx=\\\"245.796\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:49\\\" cx=\\\"268.423\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:49\\\" cx=\\\"291.051\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:49\\\" cx=\\\"313.678\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:49\\\" cx=\\\"336.305\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:49\\\" cx=\\\"200.541\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:49\\\" cx=\\\"223.168\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:49\\\" cx=\\\"245.796\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:49\\\" cx=\\\"268.423\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:49\\\" cx=\\\"291.051\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:49\\\" cx=\\\"313.678\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:49\\\" cx=\\\"291.051\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:50\\\" cx=\\\"407.709\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:50\\\" cx=\\\"430.337\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:50\\\" cx=\\\"452.964\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:50\\\" cx=\\\"498.219\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:50\\\" cx=\\\"407.709\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:50\\\" cx=\\\"430.337\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:50\\\" cx=\\\"452.964\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:50\\\" cx=\\\"475.592\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:50\\\" cx=\\\"498.219\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:50\\\" cx=\\\"520.846\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:50\\\" cx=\\\"385.082\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:50\\\" cx=\\\"407.709\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:50\\\" cx=\\\"430.337\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:50\\\" cx=\\\"452.964\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:50\\\" cx=\\\"475.592\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:50\\\" cx=\\\"498.219\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:50\\\" cx=\\\"475.592\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:51\\\" cx=\\\"592.25\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:51\\\" cx=\\\"614.878\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:51\\\" cx=\\\"637.505\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:51\\\" cx=\\\"682.76\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:51\\\" cx=\\\"592.25\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:51\\\" cx=\\\"614.878\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:51\\\" cx=\\\"637.505\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:51\\\" cx=\\\"660.133\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:51\\\" cx=\\\"682.76\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:51\\\" cx=\\\"705.387\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:51\\\" cx=\\\"569.623\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:51\\\" cx=\\\"592.25\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:51\\\" cx=\\\"614.878\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:51\\\" cx=\\\"637.505\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:51\\\" cx=\\\"660.133\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:51\\\" cx=\\\"682.76\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:51\\\" cx=\\\"660.133\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:52\\\" cx=\\\"776.791\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:52\\\" cx=\\\"799.419\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:52\\\" cx=\\\"822.046\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:52\\\" cx=\\\"867.301\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:52\\\" cx=\\\"776.791\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:52\\\" cx=\\\"799.419\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:52\\\" cx=\\\"822.046\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:52\\\" cx=\\\"844.673\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:52\\\" cx=\\\"867.301\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:52\\\" cx=\\\"889.928\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:52\\\" cx=\\\"754.164\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:52\\\" cx=\\\"776.791\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:52\\\" cx=\\\"799.419\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:52\\\" cx=\\\"822.046\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:52\\\" cx=\\\"844.673\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:52\\\" cx=\\\"867.301\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:52\\\" cx=\\\"844.673\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:53\\\" cx=\\\"961.332\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:53\\\" cx=\\\"983.96\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:53\\\" cx=\\\"1006.59\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:53\\\" cx=\\\"1051.84\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:53\\\" cx=\\\"961.332\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:53\\\" cx=\\\"983.96\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:53\\\" cx=\\\"1006.59\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:53\\\" cx=\\\"1029.21\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:53\\\" cx=\\\"1051.84\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:53\\\" cx=\\\"1074.47\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:53\\\" cx=\\\"938.705\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:53\\\" cx=\\\"961.332\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:53\\\" cx=\\\"983.96\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:53\\\" cx=\\\"1006.59\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:53\\\" cx=\\\"1029.21\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:53\\\" cx=\\\"1051.84\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:53\\\" cx=\\\"1029.21\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:54\\\" cx=\\\"1145.87\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:54\\\" cx=\\\"1168.5\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:54\\\" cx=\\\"1191.13\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:54\\\" cx=\\\"1236.38\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:54\\\" cx=\\\"1145.87\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:54\\\" cx=\\\"1168.5\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:54\\\" cx=\\\"1191.13\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:54\\\" cx=\\\"1213.76\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:54\\\" cx=\\\"1236.38\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:54\\\" cx=\\\"1259.01\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:54\\\" cx=\\\"1123.25\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:54\\\" cx=\\\"1145.87\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:54\\\" cx=\\\"1168.5\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:54\\\" cx=\\\"1191.13\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:54\\\" cx=\\\"1213.76\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:54\\\" cx=\\\"1236.38\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:54\\\" cx=\\\"1213.76\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:55\\\" cx=\\\"1330.41\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:55\\\" cx=\\\"1353.04\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:55\\\" cx=\\\"1375.67\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:55\\\" cx=\\\"1420.92\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:55\\\" cx=\\\"1330.41\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:55\\\" cx=\\\"1353.04\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:55\\\" cx=\\\"1375.67\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:55\\\" cx=\\\"1398.3\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:55\\\" cx=\\\"1420.92\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:55\\\" cx=\\\"1443.55\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:55\\\" cx=\\\"1307.79\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:55\\\" cx=\\\"1330.41\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:55\\\" cx=\\\"1353.04\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:55\\\" cx=\\\"1375.67\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:55\\\" cx=\\\"1398.3\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:55\\\" cx=\\\"1420.92\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:55\\\" cx=\\\"1398.3\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:56\\\" cx=\\\"38.6274\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:56\\\" cx=\\\"61.2548\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:56\\\" cx=\\\"83.8822\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:56\\\" cx=\\\"129.137\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:56\\\" cx=\\\"38.6274\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:56\\\" cx=\\\"61.2548\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:56\\\" cx=\\\"83.8822\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:56\\\" cx=\\\"106.51\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:56\\\" cx=\\\"129.137\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:56\\\" cx=\\\"151.764\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:56\\\" cx=\\\"16\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:56\\\" cx=\\\"38.6274\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:56\\\" cx=\\\"61.2548\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:56\\\" cx=\\\"83.8822\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:56\\\" cx=\\\"106.51\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:56\\\" cx=\\\"129.137\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:56\\\" cx=\\\"106.51\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:57\\\" cx=\\\"223.168\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:57\\\" cx=\\\"245.796\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:57\\\" cx=\\\"268.423\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:57\\\" cx=\\\"313.678\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:57\\\" cx=\\\"223.168\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:57\\\" cx=\\\"245.796\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:57\\\" cx=\\\"268.423\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:57\\\" cx=\\\"291.051\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:57\\\" cx=\\\"313.678\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:57\\\" cx=\\\"336.305\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:57\\\" cx=\\\"200.541\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:57\\\" cx=\\\"223.168\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:57\\\" cx=\\\"245.796\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:57\\\" cx=\\\"268.423\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:57\\\" cx=\\\"291.051\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:57\\\" cx=\\\"313.678\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:57\\\" cx=\\\"291.051\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:58\\\" cx=\\\"407.709\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:58\\\" cx=\\\"430.337\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:58\\\" cx=\\\"452.964\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:58\\\" cx=\\\"498.219\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:58\\\" cx=\\\"407.709\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:58\\\" cx=\\\"430.337\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:58\\\" cx=\\\"452.964\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:58\\\" cx=\\\"475.592\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:58\\\" cx=\\\"498.219\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:58\\\" cx=\\\"520.846\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:58\\\" cx=\\\"385.082\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:58\\\" cx=\\\"407.709\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:58\\\" cx=\\\"430.337\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:58\\\" cx=\\\"452.964\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:58\\\" cx=\\\"475.592\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:58\\\" cx=\\\"498.219\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:58\\\" cx=\\\"475.592\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:59\\\" cx=\\\"592.25\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:59\\\" cx=\\\"614.878\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:59\\\" cx=\\\"637.505\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:59\\\" cx=\\\"682.76\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:59\\\" cx=\\\"592.25\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:59\\\" cx=\\\"614.878\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:59\\\" cx=\\\"637.505\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:59\\\" cx=\\\"660.133\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:59\\\" cx=\\\"682.76\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:59\\\" cx=\\\"705.387\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:59\\\" cx=\\\"569.623\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:59\\\" cx=\\\"592.25\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:59\\\" cx=\\\"614.878\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:59\\\" cx=\\\"637.505\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:59\\\" cx=\\\"660.133\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:59\\\" cx=\\\"682.76\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:59\\\" cx=\\\"660.133\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:60\\\" cx=\\\"776.791\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:60\\\" cx=\\\"799.419\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:60\\\" cx=\\\"822.046\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:60\\\" cx=\\\"867.301\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:60\\\" cx=\\\"776.791\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:60\\\" cx=\\\"799.419\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:60\\\" cx=\\\"822.046\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:60\\\" cx=\\\"844.673\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:60\\\" cx=\\\"867.301\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:60\\\" cx=\\\"889.928\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:60\\\" cx=\\\"754.164\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:60\\\" cx=\\\"776.791\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:60\\\" cx=\\\"799.419\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:60\\\" cx=\\\"822.046\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:60\\\" cx=\\\"844.673\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:60\\\" cx=\\\"867.301\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:60\\\" cx=\\\"844.673\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:61\\\" cx=\\\"961.332\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:61\\\" cx=\\\"983.96\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:61\\\" cx=\\\"1006.59\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:61\\\" cx=\\\"1051.84\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:61\\\" cx=\\\"961.332\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:61\\\" cx=\\\"983.96\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:61\\\" cx=\\\"1006.59\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:61\\\" cx=\\\"1029.21\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:61\\\" cx=\\\"1051.84\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:61\\\" cx=\\\"1074.47\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:61\\\" cx=\\\"938.705\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:61\\\" cx=\\\"961.332\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:61\\\" cx=\\\"983.96\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:61\\\" cx=\\\"1006.59\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:61\\\" cx=\\\"1029.21\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:61\\\" cx=\\\"1051.84\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:61\\\" cx=\\\"1029.21\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:62\\\" cx=\\\"1145.87\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:62\\\" cx=\\\"1168.5\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:62\\\" cx=\\\"1191.13\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:62\\\" cx=\\\"1236.38\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:62\\\" cx=\\\"1145.87\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:62\\\" cx=\\\"1168.5\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:62\\\" cx=\\\"1191.13\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:62\\\" cx=\\\"1213.76\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:62\\\" cx=\\\"1236.38\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:62\\\" cx=\\\"1259.01\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:62\\\" cx=\\\"1123.25\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:62\\\" cx=\\\"1145.87\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:62\\\" cx=\\\"1168.5\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:62\\\" cx=\\\"1191.13\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:62\\\" cx=\\\"1213.76\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:62\\\" cx=\\\"1236.38\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:62\\\" cx=\\\"1213.76\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:63\\\" cx=\\\"1330.41\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:63\\\" cx=\\\"1353.04\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:63\\\" cx=\\\"1375.67\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:63\\\" cx=\\\"1420.92\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:63\\\" cx=\\\"1330.41\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:63\\\" cx=\\\"1353.04\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:63\\\" cx=\\\"1375.67\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:63\\\" cx=\\\"1398.3\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:63\\\" cx=\\\"1420.92\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:63\\\" cx=\\\"1443.55\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:63\\\" cx=\\\"1307.79\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:63\\\" cx=\\\"1330.41\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:63\\\" cx=\\\"1353.04\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:63\\\" cx=\\\"1375.67\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:63\\\" cx=\\\"1398.3\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:63\\\" cx=\\\"1420.92\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:63\\\" cx=\\\"1398.3\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"tick_borders\\\">\\n\",\n              \"<rect id=\\\"tick_border:0:0_0:0\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:1:1_0:1\\\" x=\\\"0\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:2:2_0:2\\\" x=\\\"0\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:3:3_0:3\\\" x=\\\"0\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:4:4_0:4\\\" x=\\\"0\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:5:5_0:5\\\" x=\\\"0\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:6:6_0:6\\\" x=\\\"0\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:7:7_0:7\\\" x=\\\"0\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:8:0_1:8\\\" x=\\\"184.541\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:9:1_1:9\\\" x=\\\"184.541\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:10:2_1:10\\\" x=\\\"184.541\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:11:3_1:11\\\" x=\\\"184.541\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:12:4_1:12\\\" x=\\\"184.541\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:13:5_1:13\\\" x=\\\"184.541\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:14:6_1:14\\\" x=\\\"184.541\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:15:7_1:15\\\" x=\\\"184.541\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:16:0_2:16\\\" x=\\\"369.082\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:17:1_2:17\\\" x=\\\"369.082\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:18:2_2:18\\\" x=\\\"369.082\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:19:3_2:19\\\" x=\\\"369.082\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:20:4_2:20\\\" x=\\\"369.082\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:21:5_2:21\\\" x=\\\"369.082\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:22:6_2:22\\\" x=\\\"369.082\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:23:7_2:23\\\" x=\\\"369.082\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:24:0_3:24\\\" x=\\\"553.623\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:25:1_3:25\\\" x=\\\"553.623\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:26:2_3:26\\\" x=\\\"553.623\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:27:3_3:27\\\" x=\\\"553.623\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:28:4_3:28\\\" x=\\\"553.623\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:29:5_3:29\\\" x=\\\"553.623\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:30:6_3:30\\\" x=\\\"553.623\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:31:7_3:31\\\" x=\\\"553.623\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:32:0_4:32\\\" x=\\\"738.164\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:33:1_4:33\\\" x=\\\"738.164\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:34:2_4:34\\\" x=\\\"738.164\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:35:3_4:35\\\" x=\\\"738.164\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:36:4_4:36\\\" x=\\\"738.164\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:37:5_4:37\\\" x=\\\"738.164\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:38:6_4:38\\\" x=\\\"738.164\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:39:7_4:39\\\" x=\\\"738.164\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:40:0_5:40\\\" x=\\\"922.705\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:41:1_5:41\\\" x=\\\"922.705\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:42:2_5:42\\\" x=\\\"922.705\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:43:3_5:43\\\" x=\\\"922.705\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:44:4_5:44\\\" x=\\\"922.705\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:45:5_5:45\\\" x=\\\"922.705\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:46:6_5:46\\\" x=\\\"922.705\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:47:7_5:47\\\" x=\\\"922.705\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:48:0_6:48\\\" x=\\\"1107.25\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:49:1_6:49\\\" x=\\\"1107.25\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:50:2_6:50\\\" x=\\\"1107.25\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:51:3_6:51\\\" x=\\\"1107.25\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:52:4_6:52\\\" x=\\\"1107.25\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:53:5_6:53\\\" x=\\\"1107.25\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:54:6_6:54\\\" x=\\\"1107.25\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:55:7_6:55\\\" x=\\\"1107.25\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:56:0_7:56\\\" x=\\\"1291.79\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:57:1_7:57\\\" x=\\\"1291.79\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:58:2_7:58\\\" x=\\\"1291.79\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:59:3_7:59\\\" x=\\\"1291.79\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:60:4_7:60\\\" x=\\\"1291.79\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:61:5_7:61\\\" x=\\\"1291.79\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:62:6_7:62\\\" x=\\\"1291.79\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:63:7_7:63\\\" x=\\\"1291.79\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"</svg>\"\n            ],\n            \"text/plain\": [\n              \"<svg viewBox=\\\"0 0 1459.55 1459.55\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"slice:2:4_4_0:3\\\">\\n\",\n              \"<path d=\\\"M637.505,83.8822 C651.082 74.8313,651.082 74.8313,660.133 61.2548 L682.76,83.8822 C669.183 92.9332,669.183 92.9332,660.133 106.51 C646.556 115.561,646.556 115.561,637.505 129.137 L614.878,106.51 C628.454 97.4587,628.454 97.4587,637.505 83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,83.8822 C651.082 74.8313,651.082 74.8313,660.133 61.2548 L682.76,83.8822 C669.183 92.9332,669.183 92.9332,660.133 106.51 C646.556 115.561,646.556 115.561,637.505 129.137 L614.878,106.51 C628.454 97.4587,628.454 97.4587,637.505 83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:5\\\">\\n\",\n              \"<path d=\\\"M983.96,61.2548 C997.536 52.2039,997.536 52.2039,1006.59 38.6274 L1029.21,61.2548 C1015.64 70.3058,1015.64 70.3058,1006.59 83.8822 C993.011 92.9332,993.011 92.9332,983.96 106.51 L961.332,83.8822 C974.909 74.8313,974.909 74.8313,983.96 61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,61.2548 C997.536 52.2039,997.536 52.2039,1006.59 38.6274 L1029.21,61.2548 C1015.64 70.3058,1015.64 70.3058,1006.59 83.8822 C993.011 92.9332,993.011 92.9332,983.96 106.51 L961.332,83.8822 C974.909 74.8313,974.909 74.8313,983.96 61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:5\\\">\\n\",\n              \"<path d=\\\"M1029.21,61.2548 C1042.79 52.2039,1042.79 52.2039,1051.84 38.6274 L1074.47,61.2548 C1060.89 70.3058,1060.89 70.3058,1051.84 83.8822 C1038.27 92.9332,1038.27 92.9332,1029.21 106.51 L1006.59,83.8822 C1020.16 74.8313,1020.16 74.8313,1029.21 61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,61.2548 C1042.79 52.2039,1042.79 52.2039,1051.84 38.6274 L1074.47,61.2548 C1060.89 70.3058,1060.89 70.3058,1051.84 83.8822 C1038.27 92.9332,1038.27 92.9332,1029.21 106.51 L1006.59,83.8822 C1020.16 74.8313,1020.16 74.8313,1029.21 61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:10\\\">\\n\",\n              \"<path d=\\\"M407.709,268.423 C421.286 259.372,421.286 259.372,430.337 245.796 L452.964,268.423 C439.388 277.474,439.388 277.474,430.337 291.051 C416.76 300.102,416.76 300.102,407.709 313.678 L385.082,291.051 C398.658 282,398.658 282,407.709 268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,268.423 C421.286 259.372,421.286 259.372,430.337 245.796 L452.964,268.423 C439.388 277.474,439.388 277.474,430.337 291.051 C416.76 300.102,416.76 300.102,407.709 313.678 L385.082,291.051 C398.658 282,398.658 282,407.709 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:10\\\">\\n\",\n              \"<path d=\\\"M452.964,268.423 C466.541 259.372,466.541 259.372,475.592 245.796 L498.219,268.423 C484.643 277.474,484.643 277.474,475.592 291.051 C462.015 300.102,462.015 300.102,452.964 313.678 L430.337,291.051 C443.913 282,443.913 282,452.964 268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,268.423 C466.541 259.372,466.541 259.372,475.592 245.796 L498.219,268.423 C484.643 277.474,484.643 277.474,475.592 291.051 C462.015 300.102,462.015 300.102,452.964 313.678 L430.337,291.051 C443.913 282,443.913 282,452.964 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:12\\\">\\n\",\n              \"<path d=\\\"M799.419,245.796 C812.995 236.745,812.995 236.745,822.046 223.168 L844.673,245.796 C831.097 254.847,831.097 254.847,822.046 268.423 C808.47 277.474,808.47 277.474,799.419 291.051 L776.791,268.423 C790.368 259.372,790.368 259.372,799.419 245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,245.796 C812.995 236.745,812.995 236.745,822.046 223.168 L844.673,245.796 C831.097 254.847,831.097 254.847,822.046 268.423 C808.47 277.474,808.47 277.474,799.419 291.051 L776.791,268.423 C790.368 259.372,790.368 259.372,799.419 245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:12\\\">\\n\",\n              \"<path d=\\\"M844.673,245.796 C858.25 236.745,858.25 236.745,867.301 223.168 L889.928,245.796 C876.352 254.847,876.352 254.847,867.301 268.423 C853.724 277.474,853.724 277.474,844.673 291.051 L822.046,268.423 C835.622 259.372,835.622 259.372,844.673 245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M844.673,245.796 C858.25 236.745,858.25 236.745,867.301 223.168 L889.928,245.796 C876.352 254.847,876.352 254.847,867.301 268.423 C853.724 277.474,853.724 277.474,844.673 291.051 L822.046,268.423 C835.622 259.372,835.622 259.372,844.673 245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:17\\\">\\n\",\n              \"<path d=\\\"M223.168,452.964 C236.745 443.913,236.745 443.913,245.796 430.337 L268.423,452.964 C254.847 462.015,254.847 462.015,245.796 475.592 C232.219 484.643,232.219 484.643,223.168 498.219 L200.541,475.592 C214.117 466.541,214.117 466.541,223.168 452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,452.964 C236.745 443.913,236.745 443.913,245.796 430.337 L268.423,452.964 C254.847 462.015,254.847 462.015,245.796 475.592 C232.219 484.643,232.219 484.643,223.168 498.219 L200.541,475.592 C214.117 466.541,214.117 466.541,223.168 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:17\\\">\\n\",\n              \"<path d=\\\"M268.423,452.964 C282 443.913,282 443.913,291.051 430.337 L313.678,452.964 C300.102 462.015,300.102 462.015,291.051 475.592 C277.474 484.643,277.474 484.643,268.423 498.219 L245.796,475.592 C259.372 466.541,259.372 466.541,268.423 452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,452.964 C282 443.913,282 443.913,291.051 430.337 L313.678,452.964 C300.102 462.015,300.102 462.015,291.051 475.592 C277.474 484.643,277.474 484.643,268.423 498.219 L245.796,475.592 C259.372 466.541,259.372 466.541,268.423 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:19\\\">\\n\",\n              \"<path d=\\\"M614.878,430.337 C628.454 421.286,628.454 421.286,637.505 407.709 L660.133,430.337 C646.556 439.388,646.556 439.388,637.505 452.964 C623.929 462.015,623.929 462.015,614.878 475.592 L592.25,452.964 C605.827 443.913,605.827 443.913,614.878 430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,430.337 C628.454 421.286,628.454 421.286,637.505 407.709 L660.133,430.337 C646.556 439.388,646.556 439.388,637.505 452.964 C623.929 462.015,623.929 462.015,614.878 475.592 L592.25,452.964 C605.827 443.913,605.827 443.913,614.878 430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:19\\\">\\n\",\n              \"<path d=\\\"M660.133,430.337 C673.709 421.286,673.709 421.286,682.76 407.709 L705.387,430.337 C691.811 439.388,691.811 439.388,682.76 452.964 C669.183 462.015,669.183 462.015,660.133 475.592 L637.505,452.964 C651.082 443.913,651.082 443.913,660.133 430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M660.133,430.337 C673.709 421.286,673.709 421.286,682.76 407.709 L705.387,430.337 C691.811 439.388,691.811 439.388,682.76 452.964 C669.183 462.015,669.183 462.015,660.133 475.592 L637.505,452.964 C651.082 443.913,651.082 443.913,660.133 430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:24\\\">\\n\",\n              \"<path d=\\\"M38.6274,637.505 C52.2039 628.454,52.2039 628.454,61.2548 614.878 L83.8822,637.505 C70.3058 646.556,70.3058 646.556,61.2548 660.133 C47.6784 669.183,47.6784 669.183,38.6274 682.76 L16,660.133 C29.5764 651.082,29.5764 651.082,38.6274 637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,637.505 C52.2039 628.454,52.2039 628.454,61.2548 614.878 L83.8822,637.505 C70.3058 646.556,70.3058 646.556,61.2548 660.133 C47.6784 669.183,47.6784 669.183,38.6274 682.76 L16,660.133 C29.5764 651.082,29.5764 651.082,38.6274 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:24\\\">\\n\",\n              \"<path d=\\\"M83.8822,637.505 C97.4587 628.454,97.4587 628.454,106.51 614.878 L129.137,637.505 C115.561 646.556,115.561 646.556,106.51 660.133 C92.9332 669.183,92.9332 669.183,83.8822 682.76 L61.2548,660.133 C74.8313 651.082,74.8313 651.082,83.8822 637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,637.505 C97.4587 628.454,97.4587 628.454,106.51 614.878 L129.137,637.505 C115.561 646.556,115.561 646.556,106.51 660.133 C92.9332 669.183,92.9332 669.183,83.8822 682.76 L61.2548,660.133 C74.8313 651.082,74.8313 651.082,83.8822 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:26\\\">\\n\",\n              \"<path d=\\\"M430.337,614.878 C443.913 605.827,443.913 605.827,452.964 592.25 L475.592,614.878 C462.015 623.929,462.015 623.929,452.964 637.505 C439.388 646.556,439.388 646.556,430.337 660.133 L407.709,637.505 C421.286 628.454,421.286 628.454,430.337 614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M430.337,614.878 C443.913 605.827,443.913 605.827,452.964 592.25 L475.592,614.878 C462.015 623.929,462.015 623.929,452.964 637.505 C439.388 646.556,439.388 646.556,430.337 660.133 L407.709,637.505 C421.286 628.454,421.286 628.454,430.337 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:26\\\">\\n\",\n              \"<path d=\\\"M475.592,614.878 C489.168 605.827,489.168 605.827,498.219 592.25 L520.846,614.878 C507.27 623.929,507.27 623.929,498.219 637.505 C484.643 646.556,484.643 646.556,475.592 660.133 L452.964,637.505 C466.541 628.454,466.541 628.454,475.592 614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M475.592,614.878 C489.168 605.827,489.168 605.827,498.219 592.25 L520.846,614.878 C507.27 623.929,507.27 623.929,498.219 637.505 C484.643 646.556,484.643 646.556,475.592 660.133 L452.964,637.505 C466.541 628.454,466.541 628.454,475.592 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:31\\\">\\n\",\n              \"<path d=\\\"M1330.41,637.505 C1343.99 628.454,1343.99 628.454,1353.04 614.878 L1375.67,637.505 C1362.09 646.556,1362.09 646.556,1353.04 660.133 C1339.47 669.183,1339.47 669.183,1330.41 682.76 L1307.79,660.133 C1321.36 651.082,1321.36 651.082,1330.41 637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,637.505 C1343.99 628.454,1343.99 628.454,1353.04 614.878 L1375.67,637.505 C1362.09 646.556,1362.09 646.556,1353.04 660.133 C1339.47 669.183,1339.47 669.183,1330.41 682.76 L1307.79,660.133 C1321.36 651.082,1321.36 651.082,1330.41 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:31\\\">\\n\",\n              \"<path d=\\\"M1375.67,637.505 C1389.25 628.454,1389.25 628.454,1398.3 614.878 L1420.92,637.505 C1407.35 646.556,1407.35 646.556,1398.3 660.133 C1384.72 669.183,1384.72 669.183,1375.67 682.76 L1353.04,660.133 C1366.62 651.082,1366.62 651.082,1375.67 637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,637.505 C1389.25 628.454,1389.25 628.454,1398.3 614.878 L1420.92,637.505 C1407.35 646.556,1407.35 646.556,1398.3 660.133 C1384.72 669.183,1384.72 669.183,1375.67 682.76 L1353.04,660.133 C1366.62 651.082,1366.62 651.082,1375.67 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:33\\\">\\n\",\n              \"<path d=\\\"M245.796,799.419 C259.372 790.368,259.372 790.368,268.423 776.791 L291.051,799.419 C277.474 808.47,277.474 808.47,268.423 822.046 C254.847 831.097,254.847 831.097,245.796 844.673 L223.168,822.046 C236.745 812.995,236.745 812.995,245.796 799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M245.796,799.419 C259.372 790.368,259.372 790.368,268.423 776.791 L291.051,799.419 C277.474 808.47,277.474 808.47,268.423 822.046 C254.847 831.097,254.847 831.097,245.796 844.673 L223.168,822.046 C236.745 812.995,236.745 812.995,245.796 799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:33\\\">\\n\",\n              \"<path d=\\\"M291.051,799.419 C304.627 790.368,304.627 790.368,313.678 776.791 L336.305,799.419 C322.729 808.47,322.729 808.47,313.678 822.046 C300.102 831.097,300.102 831.097,291.051 844.673 L268.423,822.046 C282 812.995,282 812.995,291.051 799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M291.051,799.419 C304.627 790.368,304.627 790.368,313.678 776.791 L336.305,799.419 C322.729 808.47,322.729 808.47,313.678 822.046 C300.102 831.097,300.102 831.097,291.051 844.673 L268.423,822.046 C282 812.995,282 812.995,291.051 799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:38\\\">\\n\",\n              \"<path d=\\\"M1145.87,822.046 C1159.45 812.995,1159.45 812.995,1168.5 799.419 L1191.13,822.046 C1177.55 831.097,1177.55 831.097,1168.5 844.673 C1154.92 853.724,1154.92 853.724,1145.87 867.301 L1123.25,844.673 C1136.82 835.622,1136.82 835.622,1145.87 822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,822.046 C1159.45 812.995,1159.45 812.995,1168.5 799.419 L1191.13,822.046 C1177.55 831.097,1177.55 831.097,1168.5 844.673 C1154.92 853.724,1154.92 853.724,1145.87 867.301 L1123.25,844.673 C1136.82 835.622,1136.82 835.622,1145.87 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:38\\\">\\n\",\n              \"<path d=\\\"M1191.13,822.046 C1204.7 812.995,1204.7 812.995,1213.76 799.419 L1236.38,822.046 C1222.81 831.097,1222.81 831.097,1213.76 844.673 C1200.18 853.724,1200.18 853.724,1191.13 867.301 L1168.5,844.673 C1182.08 835.622,1182.08 835.622,1191.13 822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,822.046 C1204.7 812.995,1204.7 812.995,1213.76 799.419 L1236.38,822.046 C1222.81 831.097,1222.81 831.097,1213.76 844.673 C1200.18 853.724,1200.18 853.724,1191.13 867.301 L1168.5,844.673 C1182.08 835.622,1182.08 835.622,1191.13 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:40\\\">\\n\",\n              \"<path d=\\\"M61.2548,983.96 C74.8313 974.909,74.8313 974.909,83.8822 961.332 L106.51,983.96 C92.9332 993.011,92.9332 993.011,83.8822 1006.59 C70.3058 1015.64,70.3058 1015.64,61.2548 1029.21 L38.6274,1006.59 C52.2039 997.536,52.2039 997.536,61.2548 983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,983.96 C74.8313 974.909,74.8313 974.909,83.8822 961.332 L106.51,983.96 C92.9332 993.011,92.9332 993.011,83.8822 1006.59 C70.3058 1015.64,70.3058 1015.64,61.2548 1029.21 L38.6274,1006.59 C52.2039 997.536,52.2039 997.536,61.2548 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:40\\\">\\n\",\n              \"<path d=\\\"M106.51,983.96 C120.086 974.909,120.086 974.909,129.137 961.332 L151.764,983.96 C138.188 993.011,138.188 993.011,129.137 1006.59 C115.561 1015.64,115.561 1015.64,106.51 1029.21 L83.8822,1006.59 C97.4587 997.536,97.4587 997.536,106.51 983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M106.51,983.96 C120.086 974.909,120.086 974.909,129.137 961.332 L151.764,983.96 C138.188 993.011,138.188 993.011,129.137 1006.59 C115.561 1015.64,115.561 1015.64,106.51 1029.21 L83.8822,1006.59 C97.4587 997.536,97.4587 997.536,106.51 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:45\\\">\\n\",\n              \"<path d=\\\"M961.332,1006.59 C974.909 997.536,974.909 997.536,983.96 983.96 L1006.59,1006.59 C993.011 1015.64,993.011 1015.64,983.96 1029.21 C970.383 1038.27,970.383 1038.27,961.332 1051.84 L938.705,1029.21 C952.281 1020.16,952.281 1020.16,961.332 1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1006.59 C974.909 997.536,974.909 997.536,983.96 983.96 L1006.59,1006.59 C993.011 1015.64,993.011 1015.64,983.96 1029.21 C970.383 1038.27,970.383 1038.27,961.332 1051.84 L938.705,1029.21 C952.281 1020.16,952.281 1020.16,961.332 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:45\\\">\\n\",\n              \"<path d=\\\"M1006.59,1006.59 C1020.16 997.536,1020.16 997.536,1029.21 983.96 L1051.84,1006.59 C1038.27 1015.64,1038.27 1015.64,1029.21 1029.21 C1015.64 1038.27,1015.64 1038.27,1006.59 1051.84 L983.96,1029.21 C997.536 1020.16,997.536 1020.16,1006.59 1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1006.59 C1020.16 997.536,1020.16 997.536,1029.21 983.96 L1051.84,1006.59 C1038.27 1015.64,1038.27 1015.64,1029.21 1029.21 C1015.64 1038.27,1015.64 1038.27,1006.59 1051.84 L983.96,1029.21 C997.536 1020.16,997.536 1020.16,1006.59 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:47\\\">\\n\",\n              \"<path d=\\\"M1353.04,983.96 C1366.62 974.909,1366.62 974.909,1375.67 961.332 L1398.3,983.96 C1384.72 993.011,1384.72 993.011,1375.67 1006.59 C1362.09 1015.64,1362.09 1015.64,1353.04 1029.21 L1330.41,1006.59 C1343.99 997.536,1343.99 997.536,1353.04 983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,983.96 C1366.62 974.909,1366.62 974.909,1375.67 961.332 L1398.3,983.96 C1384.72 993.011,1384.72 993.011,1375.67 1006.59 C1362.09 1015.64,1362.09 1015.64,1353.04 1029.21 L1330.41,1006.59 C1343.99 997.536,1343.99 997.536,1353.04 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:47\\\">\\n\",\n              \"<path d=\\\"M1398.3,983.96 C1411.87 974.909,1411.87 974.909,1420.92 961.332 L1443.55,983.96 C1429.97 993.011,1429.97 993.011,1420.92 1006.59 C1407.35 1015.64,1407.35 1015.64,1398.3 1029.21 L1375.67,1006.59 C1389.25 997.536,1389.25 997.536,1398.3 983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,983.96 C1411.87 974.909,1411.87 974.909,1420.92 961.332 L1443.55,983.96 C1429.97 993.011,1429.97 993.011,1420.92 1006.59 C1407.35 1015.64,1407.35 1015.64,1398.3 1029.21 L1375.67,1006.59 C1389.25 997.536,1389.25 997.536,1398.3 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:52\\\">\\n\",\n              \"<path d=\\\"M776.791,1191.13 C790.368 1182.08,790.368 1182.08,799.419 1168.5 L822.046,1191.13 C808.47 1200.18,808.47 1200.18,799.419 1213.76 C785.842 1222.81,785.842 1222.81,776.791 1236.38 L754.164,1213.76 C767.74 1204.7,767.74 1204.7,776.791 1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1191.13 C790.368 1182.08,790.368 1182.08,799.419 1168.5 L822.046,1191.13 C808.47 1200.18,808.47 1200.18,799.419 1213.76 C785.842 1222.81,785.842 1222.81,776.791 1236.38 L754.164,1213.76 C767.74 1204.7,767.74 1204.7,776.791 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:52\\\">\\n\",\n              \"<path d=\\\"M822.046,1191.13 C835.622 1182.08,835.622 1182.08,844.673 1168.5 L867.301,1191.13 C853.724 1200.18,853.724 1200.18,844.673 1213.76 C831.097 1222.81,831.097 1222.81,822.046 1236.38 L799.419,1213.76 C812.995 1204.7,812.995 1204.7,822.046 1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1191.13 C835.622 1182.08,835.622 1182.08,844.673 1168.5 L867.301,1191.13 C853.724 1200.18,853.724 1200.18,844.673 1213.76 C831.097 1222.81,831.097 1222.81,822.046 1236.38 L799.419,1213.76 C812.995 1204.7,812.995 1204.7,822.046 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:54\\\">\\n\",\n              \"<path d=\\\"M1168.5,1168.5 C1182.08 1159.45,1182.08 1159.45,1191.13 1145.87 L1213.76,1168.5 C1200.18 1177.55,1200.18 1177.55,1191.13 1191.13 C1177.55 1200.18,1177.55 1200.18,1168.5 1213.76 L1145.87,1191.13 C1159.45 1182.08,1159.45 1182.08,1168.5 1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,1168.5 C1182.08 1159.45,1182.08 1159.45,1191.13 1145.87 L1213.76,1168.5 C1200.18 1177.55,1200.18 1177.55,1191.13 1191.13 C1177.55 1200.18,1177.55 1200.18,1168.5 1213.76 L1145.87,1191.13 C1159.45 1182.08,1159.45 1182.08,1168.5 1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:54\\\">\\n\",\n              \"<path d=\\\"M1213.76,1168.5 C1227.33 1159.45,1227.33 1159.45,1236.38 1145.87 L1259.01,1168.5 C1245.43 1177.55,1245.43 1177.55,1236.38 1191.13 C1222.81 1200.18,1222.81 1200.18,1213.76 1213.76 L1191.13,1191.13 C1204.7 1182.08,1204.7 1182.08,1213.76 1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,1168.5 C1227.33 1159.45,1227.33 1159.45,1236.38 1145.87 L1259.01,1168.5 C1245.43 1177.55,1245.43 1177.55,1236.38 1191.13 C1222.81 1200.18,1222.81 1200.18,1213.76 1213.76 L1191.13,1191.13 C1204.7 1182.08,1204.7 1182.08,1213.76 1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:59\\\">\\n\",\n              \"<path d=\\\"M592.25,1375.67 C605.827 1366.62,605.827 1366.62,614.878 1353.04 L637.505,1375.67 C623.929 1384.72,623.929 1384.72,614.878 1398.3 C601.301 1407.35,601.301 1407.35,592.25 1420.92 L569.623,1398.3 C583.199 1389.25,583.199 1389.25,592.25 1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1375.67 C605.827 1366.62,605.827 1366.62,614.878 1353.04 L637.505,1375.67 C623.929 1384.72,623.929 1384.72,614.878 1398.3 C601.301 1407.35,601.301 1407.35,592.25 1420.92 L569.623,1398.3 C583.199 1389.25,583.199 1389.25,592.25 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:59\\\">\\n\",\n              \"<path d=\\\"M637.505,1375.67 C651.082 1366.62,651.082 1366.62,660.133 1353.04 L682.76,1375.67 C669.183 1384.72,669.183 1384.72,660.133 1398.3 C646.556 1407.35,646.556 1407.35,637.505 1420.92 L614.878,1398.3 C628.454 1389.25,628.454 1389.25,637.505 1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1375.67 C651.082 1366.62,651.082 1366.62,660.133 1353.04 L682.76,1375.67 C669.183 1384.72,669.183 1384.72,660.133 1398.3 C646.556 1407.35,646.556 1407.35,637.505 1420.92 L614.878,1398.3 C628.454 1389.25,628.454 1389.25,637.505 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:61\\\">\\n\",\n              \"<path d=\\\"M983.96,1353.04 C997.536 1343.99,997.536 1343.99,1006.59 1330.41 L1029.21,1353.04 C1015.64 1362.09,1015.64 1362.09,1006.59 1375.67 C993.011 1384.72,993.011 1384.72,983.96 1398.3 L961.332,1375.67 C974.909 1366.62,974.909 1366.62,983.96 1353.04\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1353.04 C997.536 1343.99,997.536 1343.99,1006.59 1330.41 L1029.21,1353.04 C1015.64 1362.09,1015.64 1362.09,1006.59 1375.67 C993.011 1384.72,993.011 1384.72,983.96 1398.3 L961.332,1375.67 C974.909 1366.62,974.909 1366.62,983.96 1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:1\\\">\\n\",\n              \"<path d=\\\"M223.168,38.6274 L268.423,38.6274 L245.796,61.2548 L268.423,83.8822 L223.168,83.8822 L223.168,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,38.6274 L268.423,38.6274 L245.796,61.2548 L268.423,83.8822 L223.168,83.8822 L223.168,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:1\\\">\\n\",\n              \"<path d=\\\"M268.423,83.8822 L313.678,83.8822 L291.051,106.51 L313.678,129.137 L268.423,129.137 L268.423,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,83.8822 L313.678,83.8822 L291.051,106.51 L313.678,129.137 L268.423,129.137 L268.423,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:2\\\">\\n\",\n              \"<path d=\\\"M407.709,38.6274 L452.964,38.6274 L430.337,61.2548 L452.964,83.8822 L407.709,83.8822 L407.709,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,38.6274 L452.964,38.6274 L430.337,61.2548 L452.964,83.8822 L407.709,83.8822 L407.709,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:2\\\">\\n\",\n              \"<path d=\\\"M452.964,83.8822 L498.219,83.8822 L475.592,106.51 L498.219,129.137 L452.964,129.137 L452.964,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,83.8822 L498.219,83.8822 L475.592,106.51 L498.219,129.137 L452.964,129.137 L452.964,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:3\\\">\\n\",\n              \"<path d=\\\"M592.25,38.6274 L614.878,16 L637.505,38.6274 C623.929 47.6784,623.929 47.6784,614.878 61.2548 C601.301 70.3058,601.301 70.3058,592.25 83.8822 L592.25,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,38.6274 L614.878,16 L637.505,38.6274 C623.929 47.6784,623.929 47.6784,614.878 61.2548 C601.301 70.3058,601.301 70.3058,592.25 83.8822 L592.25,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:5\\\">\\n\",\n              \"<path d=\\\"M983.96,106.51 C997.536 97.4587,997.536 97.4587,1006.59 83.8822 L1029.21,106.51 L1006.59,129.137 L961.332,129.137 C974.909 120.086,974.909 120.086,983.96 106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,106.51 C997.536 97.4587,997.536 97.4587,1006.59 83.8822 L1029.21,106.51 L1006.59,129.137 L961.332,129.137 C974.909 120.086,974.909 120.086,983.96 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:5\\\">\\n\",\n              \"<path d=\\\"M1029.21,106.51 C1042.79 97.4587,1042.79 97.4587,1051.84 83.8822 L1051.84,129.137 L1029.21,151.764 L1006.59,129.137 C1020.16 120.086,1020.16 120.086,1029.21 106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,106.51 C1042.79 97.4587,1042.79 97.4587,1051.84 83.8822 L1051.84,129.137 L1029.21,151.764 L1006.59,129.137 C1020.16 120.086,1020.16 120.086,1029.21 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1145.87,38.6274 L1191.13,38.6274 L1168.5,61.2548 L1191.13,83.8822 L1145.87,83.8822 L1145.87,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,38.6274 L1191.13,38.6274 L1168.5,61.2548 L1191.13,83.8822 L1145.87,83.8822 L1145.87,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1191.13,38.6274 L1236.38,38.6274 L1213.76,61.2548 L1236.38,83.8822 L1191.13,83.8822 L1191.13,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,38.6274 L1236.38,38.6274 L1213.76,61.2548 L1236.38,83.8822 L1191.13,83.8822 L1191.13,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1145.87,83.8822 L1191.13,83.8822 L1168.5,106.51 L1191.13,129.137 L1145.87,129.137 L1145.87,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,83.8822 L1191.13,83.8822 L1168.5,106.51 L1191.13,129.137 L1145.87,129.137 L1145.87,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1191.13,83.8822 L1236.38,83.8822 L1213.76,106.51 L1236.38,129.137 L1191.13,129.137 L1191.13,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,83.8822 L1236.38,83.8822 L1213.76,106.51 L1236.38,129.137 L1191.13,129.137 L1191.13,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:7\\\">\\n\",\n              \"<path d=\\\"M1330.41,38.6274 L1375.67,38.6274 L1353.04,61.2548 L1375.67,83.8822 L1330.41,83.8822 L1330.41,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,38.6274 L1375.67,38.6274 L1353.04,61.2548 L1375.67,83.8822 L1330.41,83.8822 L1330.41,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:7\\\">\\n\",\n              \"<path d=\\\"M1375.67,38.6274 L1420.92,38.6274 L1398.3,61.2548 L1420.92,83.8822 L1375.67,83.8822 L1375.67,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip0\\\"><path d=\\\"M1375.67,38.6274 L1420.92,38.6274 L1398.3,61.2548 L1420.92,83.8822 L1375.67,83.8822 L1375.67,38.6274\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1375.67\\\" cy=\\\"38.6274\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1420.92\\\" cy=\\\"38.6274\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1375.67\\\" cy=\\\"83.8822\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1398.3\\\" cy=\\\"61.2548\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"1420.92\\\" cy=\\\"83.8822\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,38.6274 L1420.92,38.6274 L1398.3,61.2548 L1420.92,83.8822 L1375.67,83.8822 L1375.67,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:7\\\">\\n\",\n              \"<path d=\\\"M1330.41,83.8822 L1375.67,83.8822 L1353.04,106.51 L1375.67,129.137 L1330.41,129.137 L1330.41,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip1\\\"><path d=\\\"M1330.41,83.8822 L1375.67,83.8822 L1353.04,106.51 L1375.67,129.137 L1330.41,129.137 L1330.41,83.8822\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1330.41\\\" cy=\\\"83.8822\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1375.67\\\" cy=\\\"83.8822\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1330.41\\\" cy=\\\"129.137\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1353.04\\\" cy=\\\"106.51\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"1375.67\\\" cy=\\\"129.137\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,83.8822 L1375.67,83.8822 L1353.04,106.51 L1375.67,129.137 L1330.41,129.137 L1330.41,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:7\\\">\\n\",\n              \"<path d=\\\"M1375.67,83.8822 L1420.92,83.8822 L1398.3,106.51 L1420.92,129.137 L1375.67,129.137 L1375.67,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,83.8822 L1420.92,83.8822 L1398.3,106.51 L1420.92,129.137 L1375.67,129.137 L1375.67,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:8\\\">\\n\",\n              \"<path d=\\\"M38.6274,223.168 L83.8822,223.168 L61.2548,245.796 L83.8822,268.423 L38.6274,268.423 L38.6274,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,223.168 L83.8822,223.168 L61.2548,245.796 L83.8822,268.423 L38.6274,268.423 L38.6274,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:8\\\">\\n\",\n              \"<path d=\\\"M83.8822,223.168 L129.137,223.168 L106.51,245.796 L129.137,268.423 L83.8822,268.423 L83.8822,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip2\\\"><path d=\\\"M83.8822,223.168 L129.137,223.168 L106.51,245.796 L129.137,268.423 L83.8822,268.423 L83.8822,223.168\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"83.8822\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"129.137\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"83.8822\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"106.51\\\" cy=\\\"245.796\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"129.137\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,223.168 L129.137,223.168 L106.51,245.796 L129.137,268.423 L83.8822,268.423 L83.8822,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:8\\\">\\n\",\n              \"<path d=\\\"M38.6274,268.423 L83.8822,268.423 L61.2548,291.051 L83.8822,313.678 L38.6274,313.678 L38.6274,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip3\\\"><path d=\\\"M38.6274,268.423 L83.8822,268.423 L61.2548,291.051 L83.8822,313.678 L38.6274,313.678 L38.6274,268.423\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"38.6274\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"83.8822\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"38.6274\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"61.2548\\\" cy=\\\"291.051\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"83.8822\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,268.423 L83.8822,268.423 L61.2548,291.051 L83.8822,313.678 L38.6274,313.678 L38.6274,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:8\\\">\\n\",\n              \"<path d=\\\"M83.8822,268.423 L129.137,268.423 L106.51,291.051 L129.137,313.678 L83.8822,313.678 L83.8822,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,268.423 L129.137,268.423 L106.51,291.051 L129.137,313.678 L83.8822,313.678 L83.8822,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:9\\\">\\n\",\n              \"<path d=\\\"M223.168,223.168 L268.423,223.168 L245.796,245.796 L268.423,268.423 L223.168,268.423 L223.168,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,223.168 L268.423,223.168 L245.796,245.796 L268.423,268.423 L223.168,268.423 L223.168,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:9\\\">\\n\",\n              \"<path d=\\\"M268.423,223.168 L313.678,223.168 L291.051,245.796 L313.678,268.423 L268.423,268.423 L268.423,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,223.168 L313.678,223.168 L291.051,245.796 L313.678,268.423 L268.423,268.423 L268.423,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:9\\\">\\n\",\n              \"<path d=\\\"M223.168,268.423 L268.423,268.423 L245.796,291.051 L268.423,313.678 L223.168,313.678 L223.168,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,268.423 L268.423,268.423 L245.796,291.051 L268.423,313.678 L223.168,313.678 L223.168,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:9\\\">\\n\",\n              \"<path d=\\\"M268.423,268.423 L313.678,268.423 L291.051,291.051 L313.678,313.678 L268.423,313.678 L268.423,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,268.423 L313.678,268.423 L291.051,291.051 L313.678,313.678 L268.423,313.678 L268.423,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:10\\\">\\n\",\n              \"<path d=\\\"M407.709,223.168 L430.337,200.541 L452.964,223.168 C439.388 232.219,439.388 232.219,430.337 245.796 C416.76 254.847,416.76 254.847,407.709 268.423 L407.709,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,223.168 L430.337,200.541 L452.964,223.168 C439.388 232.219,439.388 232.219,430.337 245.796 C416.76 254.847,416.76 254.847,407.709 268.423 L407.709,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:10\\\">\\n\",\n              \"<path d=\\\"M452.964,223.168 L498.219,223.168 C484.643 232.219,484.643 232.219,475.592 245.796 C462.015 254.847,462.015 254.847,452.964 268.423 L430.337,245.796 L452.964,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,223.168 L498.219,223.168 C484.643 232.219,484.643 232.219,475.592 245.796 C462.015 254.847,462.015 254.847,452.964 268.423 L430.337,245.796 L452.964,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:12\\\">\\n\",\n              \"<path d=\\\"M799.419,291.051 C812.995 282,812.995 282,822.046 268.423 L844.673,291.051 L822.046,313.678 L776.791,313.678 C790.368 304.627,790.368 304.627,799.419 291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,291.051 C812.995 282,812.995 282,822.046 268.423 L844.673,291.051 L822.046,313.678 L776.791,313.678 C790.368 304.627,790.368 304.627,799.419 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:12\\\">\\n\",\n              \"<path d=\\\"M844.673,291.051 C858.25 282,858.25 282,867.301 268.423 L867.301,313.678 L844.673,336.305 L822.046,313.678 C835.622 304.627,835.622 304.627,844.673 291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,291.051 C858.25 282,858.25 282,867.301 268.423 L867.301,313.678 L844.673,336.305 L822.046,313.678 C835.622 304.627,835.622 304.627,844.673 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:13\\\">\\n\",\n              \"<path d=\\\"M961.332,223.168 L1006.59,223.168 L983.96,245.796 L1006.59,268.423 L961.332,268.423 L961.332,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,223.168 L1006.59,223.168 L983.96,245.796 L1006.59,268.423 L961.332,268.423 L961.332,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:13\\\">\\n\",\n              \"<path d=\\\"M1006.59,223.168 L1051.84,223.168 L1029.21,245.796 L1051.84,268.423 L1006.59,268.423 L1006.59,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,223.168 L1051.84,223.168 L1029.21,245.796 L1051.84,268.423 L1006.59,268.423 L1006.59,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:13\\\">\\n\",\n              \"<path d=\\\"M961.332,268.423 L1006.59,268.423 L983.96,291.051 L1006.59,313.678 L961.332,313.678 L961.332,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,268.423 L1006.59,268.423 L983.96,291.051 L1006.59,313.678 L961.332,313.678 L961.332,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:13\\\">\\n\",\n              \"<path d=\\\"M1006.59,268.423 L1051.84,268.423 L1029.21,291.051 L1051.84,313.678 L1006.59,313.678 L1006.59,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,268.423 L1051.84,268.423 L1029.21,291.051 L1051.84,313.678 L1006.59,313.678 L1006.59,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:14\\\">\\n\",\n              \"<path d=\\\"M1145.87,223.168 L1191.13,223.168 L1168.5,245.796 L1191.13,268.423 L1145.87,268.423 L1145.87,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,223.168 L1191.13,223.168 L1168.5,245.796 L1191.13,268.423 L1145.87,268.423 L1145.87,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:14\\\">\\n\",\n              \"<path d=\\\"M1191.13,223.168 L1236.38,223.168 L1213.76,245.796 L1236.38,268.423 L1191.13,268.423 L1191.13,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip4\\\"><path d=\\\"M1191.13,223.168 L1236.38,223.168 L1213.76,245.796 L1236.38,268.423 L1191.13,268.423 L1191.13,223.168\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1191.13\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1236.38\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1191.13\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1213.76\\\" cy=\\\"245.796\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"1236.38\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,223.168 L1236.38,223.168 L1213.76,245.796 L1236.38,268.423 L1191.13,268.423 L1191.13,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:14\\\">\\n\",\n              \"<path d=\\\"M1145.87,268.423 L1191.13,268.423 L1168.5,291.051 L1191.13,313.678 L1145.87,313.678 L1145.87,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip5\\\"><path d=\\\"M1145.87,268.423 L1191.13,268.423 L1168.5,291.051 L1191.13,313.678 L1145.87,313.678 L1145.87,268.423\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1145.87\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1191.13\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1145.87\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1168.5\\\" cy=\\\"291.051\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"1191.13\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,268.423 L1191.13,268.423 L1168.5,291.051 L1191.13,313.678 L1145.87,313.678 L1145.87,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:14\\\">\\n\",\n              \"<path d=\\\"M1191.13,268.423 L1236.38,268.423 L1213.76,291.051 L1236.38,313.678 L1191.13,313.678 L1191.13,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,268.423 L1236.38,268.423 L1213.76,291.051 L1236.38,313.678 L1191.13,313.678 L1191.13,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:15\\\">\\n\",\n              \"<path d=\\\"M1330.41,223.168 L1375.67,223.168 L1353.04,245.796 L1375.67,268.423 L1330.41,268.423 L1330.41,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,223.168 L1375.67,223.168 L1353.04,245.796 L1375.67,268.423 L1330.41,268.423 L1330.41,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:15\\\">\\n\",\n              \"<path d=\\\"M1375.67,223.168 L1420.92,223.168 L1398.3,245.796 L1420.92,268.423 L1375.67,268.423 L1375.67,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip6\\\"><path d=\\\"M1375.67,223.168 L1420.92,223.168 L1398.3,245.796 L1420.92,268.423 L1375.67,268.423 L1375.67,223.168\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1375.67\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1420.92\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1375.67\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1398.3\\\" cy=\\\"245.796\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"1420.92\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,223.168 L1420.92,223.168 L1398.3,245.796 L1420.92,268.423 L1375.67,268.423 L1375.67,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:15\\\">\\n\",\n              \"<path d=\\\"M1330.41,268.423 L1375.67,268.423 L1353.04,291.051 L1375.67,313.678 L1330.41,313.678 L1330.41,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip7\\\"><path d=\\\"M1330.41,268.423 L1375.67,268.423 L1353.04,291.051 L1375.67,313.678 L1330.41,313.678 L1330.41,268.423\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1330.41\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1375.67\\\" cy=\\\"268.423\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1330.41\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1353.04\\\" cy=\\\"291.051\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"1375.67\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,268.423 L1375.67,268.423 L1353.04,291.051 L1375.67,313.678 L1330.41,313.678 L1330.41,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:15\\\">\\n\",\n              \"<path d=\\\"M1375.67,268.423 L1420.92,268.423 L1398.3,291.051 L1420.92,313.678 L1375.67,313.678 L1375.67,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,268.423 L1420.92,268.423 L1398.3,291.051 L1420.92,313.678 L1375.67,313.678 L1375.67,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:16\\\">\\n\",\n              \"<path d=\\\"M38.6274,407.709 L83.8822,407.709 L61.2548,430.337 L83.8822,452.964 L38.6274,452.964 L38.6274,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,407.709 L83.8822,407.709 L61.2548,430.337 L83.8822,452.964 L38.6274,452.964 L38.6274,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:16\\\">\\n\",\n              \"<path d=\\\"M83.8822,407.709 L129.137,407.709 L106.51,430.337 L129.137,452.964 L83.8822,452.964 L83.8822,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,407.709 L129.137,407.709 L106.51,430.337 L129.137,452.964 L83.8822,452.964 L83.8822,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:16\\\">\\n\",\n              \"<path d=\\\"M38.6274,452.964 L83.8822,452.964 L61.2548,475.592 L83.8822,498.219 L38.6274,498.219 L38.6274,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,452.964 L83.8822,452.964 L61.2548,475.592 L83.8822,498.219 L38.6274,498.219 L38.6274,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:16\\\">\\n\",\n              \"<path d=\\\"M83.8822,452.964 L129.137,452.964 L106.51,475.592 L129.137,498.219 L83.8822,498.219 L83.8822,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,452.964 L129.137,452.964 L106.51,475.592 L129.137,498.219 L83.8822,498.219 L83.8822,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:17\\\">\\n\",\n              \"<path d=\\\"M223.168,407.709 L245.796,385.082 L268.423,407.709 C254.847 416.76,254.847 416.76,245.796 430.337 C232.219 439.388,232.219 439.388,223.168 452.964 L223.168,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,407.709 L245.796,385.082 L268.423,407.709 C254.847 416.76,254.847 416.76,245.796 430.337 C232.219 439.388,232.219 439.388,223.168 452.964 L223.168,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:17\\\">\\n\",\n              \"<path d=\\\"M268.423,407.709 L313.678,407.709 C300.102 416.76,300.102 416.76,291.051 430.337 C277.474 439.388,277.474 439.388,268.423 452.964 L245.796,430.337 L268.423,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,407.709 L313.678,407.709 C300.102 416.76,300.102 416.76,291.051 430.337 C277.474 439.388,277.474 439.388,268.423 452.964 L245.796,430.337 L268.423,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:19\\\">\\n\",\n              \"<path d=\\\"M614.878,475.592 C628.454 466.541,628.454 466.541,637.505 452.964 L660.133,475.592 L637.505,498.219 L592.25,498.219 C605.827 489.168,605.827 489.168,614.878 475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,475.592 C628.454 466.541,628.454 466.541,637.505 452.964 L660.133,475.592 L637.505,498.219 L592.25,498.219 C605.827 489.168,605.827 489.168,614.878 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:19\\\">\\n\",\n              \"<path d=\\\"M660.133,475.592 C673.709 466.541,673.709 466.541,682.76 452.964 L682.76,498.219 L660.133,520.846 L637.505,498.219 C651.082 489.168,651.082 489.168,660.133 475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,475.592 C673.709 466.541,673.709 466.541,682.76 452.964 L682.76,498.219 L660.133,520.846 L637.505,498.219 C651.082 489.168,651.082 489.168,660.133 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:20\\\">\\n\",\n              \"<path d=\\\"M776.791,407.709 L822.046,407.709 L799.419,430.337 L822.046,452.964 L776.791,452.964 L776.791,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,407.709 L822.046,407.709 L799.419,430.337 L822.046,452.964 L776.791,452.964 L776.791,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:20\\\">\\n\",\n              \"<path d=\\\"M822.046,407.709 L867.301,407.709 L844.673,430.337 L867.301,452.964 L822.046,452.964 L822.046,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,407.709 L867.301,407.709 L844.673,430.337 L867.301,452.964 L822.046,452.964 L822.046,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:20\\\">\\n\",\n              \"<path d=\\\"M776.791,452.964 L822.046,452.964 L799.419,475.592 L822.046,498.219 L776.791,498.219 L776.791,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,452.964 L822.046,452.964 L799.419,475.592 L822.046,498.219 L776.791,498.219 L776.791,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:20\\\">\\n\",\n              \"<path d=\\\"M822.046,452.964 L867.301,452.964 L844.673,475.592 L867.301,498.219 L822.046,498.219 L822.046,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,452.964 L867.301,452.964 L844.673,475.592 L867.301,498.219 L822.046,498.219 L822.046,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:21\\\">\\n\",\n              \"<path d=\\\"M961.332,407.709 L1006.59,407.709 L983.96,430.337 L1006.59,452.964 L961.332,452.964 L961.332,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,407.709 L1006.59,407.709 L983.96,430.337 L1006.59,452.964 L961.332,452.964 L961.332,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:21\\\">\\n\",\n              \"<path d=\\\"M1006.59,407.709 L1051.84,407.709 L1029.21,430.337 L1051.84,452.964 L1006.59,452.964 L1006.59,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip8\\\"><path d=\\\"M1006.59,407.709 L1051.84,407.709 L1029.21,430.337 L1051.84,452.964 L1006.59,452.964 L1006.59,407.709\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1006.59\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1051.84\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1006.59\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1029.21\\\" cy=\\\"430.337\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip8)\\\" cx=\\\"1051.84\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,407.709 L1051.84,407.709 L1029.21,430.337 L1051.84,452.964 L1006.59,452.964 L1006.59,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:21\\\">\\n\",\n              \"<path d=\\\"M961.332,452.964 L1006.59,452.964 L983.96,475.592 L1006.59,498.219 L961.332,498.219 L961.332,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip9\\\"><path d=\\\"M961.332,452.964 L1006.59,452.964 L983.96,475.592 L1006.59,498.219 L961.332,498.219 L961.332,452.964\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"961.332\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"1006.59\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"961.332\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"983.96\\\" cy=\\\"475.592\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip9)\\\" cx=\\\"1006.59\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M961.332,452.964 L1006.59,452.964 L983.96,475.592 L1006.59,498.219 L961.332,498.219 L961.332,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:21\\\">\\n\",\n              \"<path d=\\\"M1006.59,452.964 L1051.84,452.964 L1029.21,475.592 L1051.84,498.219 L1006.59,498.219 L1006.59,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,452.964 L1051.84,452.964 L1029.21,475.592 L1051.84,498.219 L1006.59,498.219 L1006.59,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:22\\\">\\n\",\n              \"<path d=\\\"M1145.87,407.709 L1191.13,407.709 L1168.5,430.337 L1191.13,452.964 L1145.87,452.964 L1145.87,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,407.709 L1191.13,407.709 L1168.5,430.337 L1191.13,452.964 L1145.87,452.964 L1145.87,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:22\\\">\\n\",\n              \"<path d=\\\"M1191.13,407.709 L1236.38,407.709 L1213.76,430.337 L1236.38,452.964 L1191.13,452.964 L1191.13,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip10\\\"><path d=\\\"M1191.13,407.709 L1236.38,407.709 L1213.76,430.337 L1236.38,452.964 L1191.13,452.964 L1191.13,407.709\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1191.13\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1236.38\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1191.13\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1213.76\\\" cy=\\\"430.337\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip10)\\\" cx=\\\"1236.38\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,407.709 L1236.38,407.709 L1213.76,430.337 L1236.38,452.964 L1191.13,452.964 L1191.13,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:22\\\">\\n\",\n              \"<path d=\\\"M1145.87,452.964 L1191.13,452.964 L1168.5,475.592 L1191.13,498.219 L1145.87,498.219 L1145.87,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip11\\\"><path d=\\\"M1145.87,452.964 L1191.13,452.964 L1168.5,475.592 L1191.13,498.219 L1145.87,498.219 L1145.87,452.964\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1145.87\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1191.13\\\" cy=\\\"452.964\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1145.87\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1168.5\\\" cy=\\\"475.592\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip11)\\\" cx=\\\"1191.13\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,452.964 L1191.13,452.964 L1168.5,475.592 L1191.13,498.219 L1145.87,498.219 L1145.87,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:22\\\">\\n\",\n              \"<path d=\\\"M1191.13,452.964 L1236.38,452.964 L1213.76,475.592 L1236.38,498.219 L1191.13,498.219 L1191.13,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,452.964 L1236.38,452.964 L1213.76,475.592 L1236.38,498.219 L1191.13,498.219 L1191.13,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:23\\\">\\n\",\n              \"<path d=\\\"M1330.41,407.709 L1375.67,407.709 L1353.04,430.337 L1375.67,452.964 L1330.41,452.964 L1330.41,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,407.709 L1375.67,407.709 L1353.04,430.337 L1375.67,452.964 L1330.41,452.964 L1330.41,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:23\\\">\\n\",\n              \"<path d=\\\"M1375.67,407.709 L1420.92,407.709 L1398.3,430.337 L1420.92,452.964 L1375.67,452.964 L1375.67,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,407.709 L1420.92,407.709 L1398.3,430.337 L1420.92,452.964 L1375.67,452.964 L1375.67,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:23\\\">\\n\",\n              \"<path d=\\\"M1330.41,452.964 L1375.67,452.964 L1353.04,475.592 L1375.67,498.219 L1330.41,498.219 L1330.41,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,452.964 L1375.67,452.964 L1353.04,475.592 L1375.67,498.219 L1330.41,498.219 L1330.41,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:23\\\">\\n\",\n              \"<path d=\\\"M1375.67,452.964 L1420.92,452.964 L1398.3,475.592 L1420.92,498.219 L1375.67,498.219 L1375.67,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,452.964 L1420.92,452.964 L1398.3,475.592 L1420.92,498.219 L1375.67,498.219 L1375.67,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:24\\\">\\n\",\n              \"<path d=\\\"M38.6274,592.25 L61.2548,569.623 L83.8822,592.25 C70.3058 601.301,70.3058 601.301,61.2548 614.878 C47.6784 623.929,47.6784 623.929,38.6274 637.505 L38.6274,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,592.25 L61.2548,569.623 L83.8822,592.25 C70.3058 601.301,70.3058 601.301,61.2548 614.878 C47.6784 623.929,47.6784 623.929,38.6274 637.505 L38.6274,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:24\\\">\\n\",\n              \"<path d=\\\"M83.8822,592.25 L129.137,592.25 C115.561 601.301,115.561 601.301,106.51 614.878 C92.9332 623.929,92.9332 623.929,83.8822 637.505 L61.2548,614.878 L83.8822,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,592.25 L129.137,592.25 C115.561 601.301,115.561 601.301,106.51 614.878 C92.9332 623.929,92.9332 623.929,83.8822 637.505 L61.2548,614.878 L83.8822,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:26\\\">\\n\",\n              \"<path d=\\\"M430.337,660.133 C443.913 651.082,443.913 651.082,452.964 637.505 L475.592,660.133 L452.964,682.76 L407.709,682.76 C421.286 673.709,421.286 673.709,430.337 660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,660.133 C443.913 651.082,443.913 651.082,452.964 637.505 L475.592,660.133 L452.964,682.76 L407.709,682.76 C421.286 673.709,421.286 673.709,430.337 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:26\\\">\\n\",\n              \"<path d=\\\"M475.592,660.133 C489.168 651.082,489.168 651.082,498.219 637.505 L498.219,682.76 L475.592,705.387 L452.964,682.76 C466.541 673.709,466.541 673.709,475.592 660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,660.133 C489.168 651.082,489.168 651.082,498.219 637.505 L498.219,682.76 L475.592,705.387 L452.964,682.76 C466.541 673.709,466.541 673.709,475.592 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:27\\\">\\n\",\n              \"<path d=\\\"M592.25,592.25 L637.505,592.25 L614.878,614.878 L637.505,637.505 L592.25,637.505 L592.25,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,592.25 L637.505,592.25 L614.878,614.878 L637.505,637.505 L592.25,637.505 L592.25,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:27\\\">\\n\",\n              \"<path d=\\\"M637.505,592.25 L682.76,592.25 L660.133,614.878 L682.76,637.505 L637.505,637.505 L637.505,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,592.25 L682.76,592.25 L660.133,614.878 L682.76,637.505 L637.505,637.505 L637.505,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:27\\\">\\n\",\n              \"<path d=\\\"M592.25,637.505 L637.505,637.505 L614.878,660.133 L637.505,682.76 L592.25,682.76 L592.25,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,637.505 L637.505,637.505 L614.878,660.133 L637.505,682.76 L592.25,682.76 L592.25,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:27\\\">\\n\",\n              \"<path d=\\\"M637.505,637.505 L682.76,637.505 L660.133,660.133 L682.76,682.76 L637.505,682.76 L637.505,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,637.505 L682.76,637.505 L660.133,660.133 L682.76,682.76 L637.505,682.76 L637.505,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:28\\\">\\n\",\n              \"<path d=\\\"M776.791,592.25 L822.046,592.25 L799.419,614.878 L822.046,637.505 L776.791,637.505 L776.791,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,592.25 L822.046,592.25 L799.419,614.878 L822.046,637.505 L776.791,637.505 L776.791,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:28\\\">\\n\",\n              \"<path d=\\\"M822.046,592.25 L867.301,592.25 L844.673,614.878 L867.301,637.505 L822.046,637.505 L822.046,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip12\\\"><path d=\\\"M822.046,592.25 L867.301,592.25 L844.673,614.878 L867.301,637.505 L822.046,637.505 L822.046,592.25\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"822.046\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"867.301\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"822.046\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"844.673\\\" cy=\\\"614.878\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip12)\\\" cx=\\\"867.301\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M822.046,592.25 L867.301,592.25 L844.673,614.878 L867.301,637.505 L822.046,637.505 L822.046,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:28\\\">\\n\",\n              \"<path d=\\\"M776.791,637.505 L822.046,637.505 L799.419,660.133 L822.046,682.76 L776.791,682.76 L776.791,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip13\\\"><path d=\\\"M776.791,637.505 L822.046,637.505 L799.419,660.133 L822.046,682.76 L776.791,682.76 L776.791,637.505\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"776.791\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"822.046\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"776.791\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"799.419\\\" cy=\\\"660.133\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip13)\\\" cx=\\\"822.046\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M776.791,637.505 L822.046,637.505 L799.419,660.133 L822.046,682.76 L776.791,682.76 L776.791,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:28\\\">\\n\",\n              \"<path d=\\\"M822.046,637.505 L867.301,637.505 L844.673,660.133 L867.301,682.76 L822.046,682.76 L822.046,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,637.505 L867.301,637.505 L844.673,660.133 L867.301,682.76 L822.046,682.76 L822.046,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:29\\\">\\n\",\n              \"<path d=\\\"M961.332,592.25 L1006.59,592.25 L983.96,614.878 L1006.59,637.505 L961.332,637.505 L961.332,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,592.25 L1006.59,592.25 L983.96,614.878 L1006.59,637.505 L961.332,637.505 L961.332,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:29\\\">\\n\",\n              \"<path d=\\\"M1006.59,592.25 L1051.84,592.25 L1029.21,614.878 L1051.84,637.505 L1006.59,637.505 L1006.59,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip14\\\"><path d=\\\"M1006.59,592.25 L1051.84,592.25 L1029.21,614.878 L1051.84,637.505 L1006.59,637.505 L1006.59,592.25\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1006.59\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1051.84\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1006.59\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1029.21\\\" cy=\\\"614.878\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip14)\\\" cx=\\\"1051.84\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,592.25 L1051.84,592.25 L1029.21,614.878 L1051.84,637.505 L1006.59,637.505 L1006.59,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:29\\\">\\n\",\n              \"<path d=\\\"M961.332,637.505 L1006.59,637.505 L983.96,660.133 L1006.59,682.76 L961.332,682.76 L961.332,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip15\\\"><path d=\\\"M961.332,637.505 L1006.59,637.505 L983.96,660.133 L1006.59,682.76 L961.332,682.76 L961.332,637.505\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"961.332\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"1006.59\\\" cy=\\\"637.505\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"961.332\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"983.96\\\" cy=\\\"660.133\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip15)\\\" cx=\\\"1006.59\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M961.332,637.505 L1006.59,637.505 L983.96,660.133 L1006.59,682.76 L961.332,682.76 L961.332,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:29\\\">\\n\",\n              \"<path d=\\\"M1006.59,637.505 L1051.84,637.505 L1029.21,660.133 L1051.84,682.76 L1006.59,682.76 L1006.59,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,637.505 L1051.84,637.505 L1029.21,660.133 L1051.84,682.76 L1006.59,682.76 L1006.59,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:30\\\">\\n\",\n              \"<path d=\\\"M1145.87,592.25 L1191.13,592.25 L1168.5,614.878 L1191.13,637.505 L1145.87,637.505 L1145.87,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,592.25 L1191.13,592.25 L1168.5,614.878 L1191.13,637.505 L1145.87,637.505 L1145.87,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:30\\\">\\n\",\n              \"<path d=\\\"M1191.13,592.25 L1236.38,592.25 L1213.76,614.878 L1236.38,637.505 L1191.13,637.505 L1191.13,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,592.25 L1236.38,592.25 L1213.76,614.878 L1236.38,637.505 L1191.13,637.505 L1191.13,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:30\\\">\\n\",\n              \"<path d=\\\"M1145.87,637.505 L1191.13,637.505 L1168.5,660.133 L1191.13,682.76 L1145.87,682.76 L1145.87,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,637.505 L1191.13,637.505 L1168.5,660.133 L1191.13,682.76 L1145.87,682.76 L1145.87,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:30\\\">\\n\",\n              \"<path d=\\\"M1191.13,637.505 L1236.38,637.505 L1213.76,660.133 L1236.38,682.76 L1191.13,682.76 L1191.13,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,637.505 L1236.38,637.505 L1213.76,660.133 L1236.38,682.76 L1191.13,682.76 L1191.13,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:31\\\">\\n\",\n              \"<path d=\\\"M1330.41,592.25 L1353.04,569.623 L1375.67,592.25 C1362.09 601.301,1362.09 601.301,1353.04 614.878 C1339.47 623.929,1339.47 623.929,1330.41 637.505 L1330.41,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,592.25 L1353.04,569.623 L1375.67,592.25 C1362.09 601.301,1362.09 601.301,1353.04 614.878 C1339.47 623.929,1339.47 623.929,1330.41 637.505 L1330.41,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:31\\\">\\n\",\n              \"<path d=\\\"M1375.67,592.25 L1420.92,592.25 C1407.35 601.301,1407.35 601.301,1398.3 614.878 C1384.72 623.929,1384.72 623.929,1375.67 637.505 L1353.04,614.878 L1375.67,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,592.25 L1420.92,592.25 C1407.35 601.301,1407.35 601.301,1398.3 614.878 C1384.72 623.929,1384.72 623.929,1375.67 637.505 L1353.04,614.878 L1375.67,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:33\\\">\\n\",\n              \"<path d=\\\"M245.796,844.673 C259.372 835.622,259.372 835.622,268.423 822.046 L291.051,844.673 L268.423,867.301 L223.168,867.301 C236.745 858.25,236.745 858.25,245.796 844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,844.673 C259.372 835.622,259.372 835.622,268.423 822.046 L291.051,844.673 L268.423,867.301 L223.168,867.301 C236.745 858.25,236.745 858.25,245.796 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:33\\\">\\n\",\n              \"<path d=\\\"M291.051,844.673 C304.627 835.622,304.627 835.622,313.678 822.046 L313.678,867.301 L291.051,889.928 L268.423,867.301 C282 858.25,282 858.25,291.051 844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,844.673 C304.627 835.622,304.627 835.622,313.678 822.046 L313.678,867.301 L291.051,889.928 L268.423,867.301 C282 858.25,282 858.25,291.051 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:34\\\">\\n\",\n              \"<path d=\\\"M407.709,776.791 L452.964,776.791 L430.337,799.419 L452.964,822.046 L407.709,822.046 L407.709,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,776.791 L452.964,776.791 L430.337,799.419 L452.964,822.046 L407.709,822.046 L407.709,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:34\\\">\\n\",\n              \"<path d=\\\"M452.964,776.791 L498.219,776.791 L475.592,799.419 L498.219,822.046 L452.964,822.046 L452.964,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,776.791 L498.219,776.791 L475.592,799.419 L498.219,822.046 L452.964,822.046 L452.964,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:34\\\">\\n\",\n              \"<path d=\\\"M407.709,822.046 L452.964,822.046 L430.337,844.673 L452.964,867.301 L407.709,867.301 L407.709,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,822.046 L452.964,822.046 L430.337,844.673 L452.964,867.301 L407.709,867.301 L407.709,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:34\\\">\\n\",\n              \"<path d=\\\"M452.964,822.046 L498.219,822.046 L475.592,844.673 L498.219,867.301 L452.964,867.301 L452.964,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,822.046 L498.219,822.046 L475.592,844.673 L498.219,867.301 L452.964,867.301 L452.964,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:35\\\">\\n\",\n              \"<path d=\\\"M592.25,776.791 L637.505,776.791 L614.878,799.419 L637.505,822.046 L592.25,822.046 L592.25,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,776.791 L637.505,776.791 L614.878,799.419 L637.505,822.046 L592.25,822.046 L592.25,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:35\\\">\\n\",\n              \"<path d=\\\"M637.505,776.791 L682.76,776.791 L660.133,799.419 L682.76,822.046 L637.505,822.046 L637.505,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip16\\\"><path d=\\\"M637.505,776.791 L682.76,776.791 L660.133,799.419 L682.76,822.046 L637.505,822.046 L637.505,776.791\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"637.505\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"682.76\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"637.505\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"660.133\\\" cy=\\\"799.419\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip16)\\\" cx=\\\"682.76\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M637.505,776.791 L682.76,776.791 L660.133,799.419 L682.76,822.046 L637.505,822.046 L637.505,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:35\\\">\\n\",\n              \"<path d=\\\"M592.25,822.046 L637.505,822.046 L614.878,844.673 L637.505,867.301 L592.25,867.301 L592.25,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip17\\\"><path d=\\\"M592.25,822.046 L637.505,822.046 L614.878,844.673 L637.505,867.301 L592.25,867.301 L592.25,822.046\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"592.25\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"637.505\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"592.25\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"614.878\\\" cy=\\\"844.673\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip17)\\\" cx=\\\"637.505\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M592.25,822.046 L637.505,822.046 L614.878,844.673 L637.505,867.301 L592.25,867.301 L592.25,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:35\\\">\\n\",\n              \"<path d=\\\"M637.505,822.046 L682.76,822.046 L660.133,844.673 L682.76,867.301 L637.505,867.301 L637.505,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,822.046 L682.76,822.046 L660.133,844.673 L682.76,867.301 L637.505,867.301 L637.505,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:36\\\">\\n\",\n              \"<path d=\\\"M776.791,776.791 L822.046,776.791 L799.419,799.419 L822.046,822.046 L776.791,822.046 L776.791,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,776.791 L822.046,776.791 L799.419,799.419 L822.046,822.046 L776.791,822.046 L776.791,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:36\\\">\\n\",\n              \"<path d=\\\"M822.046,776.791 L867.301,776.791 L844.673,799.419 L867.301,822.046 L822.046,822.046 L822.046,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip18\\\"><path d=\\\"M822.046,776.791 L867.301,776.791 L844.673,799.419 L867.301,822.046 L822.046,822.046 L822.046,776.791\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"822.046\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"867.301\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"822.046\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"844.673\\\" cy=\\\"799.419\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip18)\\\" cx=\\\"867.301\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M822.046,776.791 L867.301,776.791 L844.673,799.419 L867.301,822.046 L822.046,822.046 L822.046,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:36\\\">\\n\",\n              \"<path d=\\\"M776.791,822.046 L822.046,822.046 L799.419,844.673 L822.046,867.301 L776.791,867.301 L776.791,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip19\\\"><path d=\\\"M776.791,822.046 L822.046,822.046 L799.419,844.673 L822.046,867.301 L776.791,867.301 L776.791,822.046\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"776.791\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"822.046\\\" cy=\\\"822.046\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"776.791\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"799.419\\\" cy=\\\"844.673\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip19)\\\" cx=\\\"822.046\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M776.791,822.046 L822.046,822.046 L799.419,844.673 L822.046,867.301 L776.791,867.301 L776.791,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:36\\\">\\n\",\n              \"<path d=\\\"M822.046,822.046 L867.301,822.046 L844.673,844.673 L867.301,867.301 L822.046,867.301 L822.046,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,822.046 L867.301,822.046 L844.673,844.673 L867.301,867.301 L822.046,867.301 L822.046,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:37\\\">\\n\",\n              \"<path d=\\\"M961.332,776.791 L1006.59,776.791 L983.96,799.419 L1006.59,822.046 L961.332,822.046 L961.332,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,776.791 L1006.59,776.791 L983.96,799.419 L1006.59,822.046 L961.332,822.046 L961.332,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:37\\\">\\n\",\n              \"<path d=\\\"M1006.59,776.791 L1051.84,776.791 L1029.21,799.419 L1051.84,822.046 L1006.59,822.046 L1006.59,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,776.791 L1051.84,776.791 L1029.21,799.419 L1051.84,822.046 L1006.59,822.046 L1006.59,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:37\\\">\\n\",\n              \"<path d=\\\"M961.332,822.046 L1006.59,822.046 L983.96,844.673 L1006.59,867.301 L961.332,867.301 L961.332,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,822.046 L1006.59,822.046 L983.96,844.673 L1006.59,867.301 L961.332,867.301 L961.332,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:37\\\">\\n\",\n              \"<path d=\\\"M1006.59,822.046 L1051.84,822.046 L1029.21,844.673 L1051.84,867.301 L1006.59,867.301 L1006.59,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,822.046 L1051.84,822.046 L1029.21,844.673 L1051.84,867.301 L1006.59,867.301 L1006.59,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:38\\\">\\n\",\n              \"<path d=\\\"M1145.87,776.791 L1168.5,754.164 L1191.13,776.791 C1177.55 785.842,1177.55 785.842,1168.5 799.419 C1154.92 808.47,1154.92 808.47,1145.87 822.046 L1145.87,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,776.791 L1168.5,754.164 L1191.13,776.791 C1177.55 785.842,1177.55 785.842,1168.5 799.419 C1154.92 808.47,1154.92 808.47,1145.87 822.046 L1145.87,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:38\\\">\\n\",\n              \"<path d=\\\"M1191.13,776.791 L1236.38,776.791 C1222.81 785.842,1222.81 785.842,1213.76 799.419 C1200.18 808.47,1200.18 808.47,1191.13 822.046 L1168.5,799.419 L1191.13,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,776.791 L1236.38,776.791 C1222.81 785.842,1222.81 785.842,1213.76 799.419 C1200.18 808.47,1200.18 808.47,1191.13 822.046 L1168.5,799.419 L1191.13,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:40\\\">\\n\",\n              \"<path d=\\\"M61.2548,1029.21 C74.8313 1020.16,74.8313 1020.16,83.8822 1006.59 L106.51,1029.21 L83.8822,1051.84 L38.6274,1051.84 C52.2039 1042.79,52.2039 1042.79,61.2548 1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,1029.21 C74.8313 1020.16,74.8313 1020.16,83.8822 1006.59 L106.51,1029.21 L83.8822,1051.84 L38.6274,1051.84 C52.2039 1042.79,52.2039 1042.79,61.2548 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:40\\\">\\n\",\n              \"<path d=\\\"M106.51,1029.21 C120.086 1020.16,120.086 1020.16,129.137 1006.59 L129.137,1051.84 L106.51,1074.47 L83.8822,1051.84 C97.4587 1042.79,97.4587 1042.79,106.51 1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,1029.21 C120.086 1020.16,120.086 1020.16,129.137 1006.59 L129.137,1051.84 L106.51,1074.47 L83.8822,1051.84 C97.4587 1042.79,97.4587 1042.79,106.51 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:41\\\">\\n\",\n              \"<path d=\\\"M223.168,961.332 L268.423,961.332 L245.796,983.96 L268.423,1006.59 L223.168,1006.59 L223.168,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,961.332 L268.423,961.332 L245.796,983.96 L268.423,1006.59 L223.168,1006.59 L223.168,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:41\\\">\\n\",\n              \"<path d=\\\"M268.423,961.332 L313.678,961.332 L291.051,983.96 L313.678,1006.59 L268.423,1006.59 L268.423,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,961.332 L313.678,961.332 L291.051,983.96 L313.678,1006.59 L268.423,1006.59 L268.423,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:41\\\">\\n\",\n              \"<path d=\\\"M223.168,1006.59 L268.423,1006.59 L245.796,1029.21 L268.423,1051.84 L223.168,1051.84 L223.168,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1006.59 L268.423,1006.59 L245.796,1029.21 L268.423,1051.84 L223.168,1051.84 L223.168,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:41\\\">\\n\",\n              \"<path d=\\\"M268.423,1006.59 L313.678,1006.59 L291.051,1029.21 L313.678,1051.84 L268.423,1051.84 L268.423,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1006.59 L313.678,1006.59 L291.051,1029.21 L313.678,1051.84 L268.423,1051.84 L268.423,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:42\\\">\\n\",\n              \"<path d=\\\"M407.709,961.332 L452.964,961.332 L430.337,983.96 L452.964,1006.59 L407.709,1006.59 L407.709,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,961.332 L452.964,961.332 L430.337,983.96 L452.964,1006.59 L407.709,1006.59 L407.709,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:42\\\">\\n\",\n              \"<path d=\\\"M452.964,961.332 L498.219,961.332 L475.592,983.96 L498.219,1006.59 L452.964,1006.59 L452.964,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip20\\\"><path d=\\\"M452.964,961.332 L498.219,961.332 L475.592,983.96 L498.219,1006.59 L452.964,1006.59 L452.964,961.332\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"452.964\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"498.219\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"452.964\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"475.592\\\" cy=\\\"983.96\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip20)\\\" cx=\\\"498.219\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M452.964,961.332 L498.219,961.332 L475.592,983.96 L498.219,1006.59 L452.964,1006.59 L452.964,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:42\\\">\\n\",\n              \"<path d=\\\"M407.709,1006.59 L452.964,1006.59 L430.337,1029.21 L452.964,1051.84 L407.709,1051.84 L407.709,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip21\\\"><path d=\\\"M407.709,1006.59 L452.964,1006.59 L430.337,1029.21 L452.964,1051.84 L407.709,1051.84 L407.709,1006.59\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"407.709\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"452.964\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"407.709\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"430.337\\\" cy=\\\"1029.21\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip21)\\\" cx=\\\"452.964\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1006.59 L452.964,1006.59 L430.337,1029.21 L452.964,1051.84 L407.709,1051.84 L407.709,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:42\\\">\\n\",\n              \"<path d=\\\"M452.964,1006.59 L498.219,1006.59 L475.592,1029.21 L498.219,1051.84 L452.964,1051.84 L452.964,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1006.59 L498.219,1006.59 L475.592,1029.21 L498.219,1051.84 L452.964,1051.84 L452.964,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:43\\\">\\n\",\n              \"<path d=\\\"M592.25,961.332 L637.505,961.332 L614.878,983.96 L637.505,1006.59 L592.25,1006.59 L592.25,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,961.332 L637.505,961.332 L614.878,983.96 L637.505,1006.59 L592.25,1006.59 L592.25,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:43\\\">\\n\",\n              \"<path d=\\\"M637.505,961.332 L682.76,961.332 L660.133,983.96 L682.76,1006.59 L637.505,1006.59 L637.505,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip22\\\"><path d=\\\"M637.505,961.332 L682.76,961.332 L660.133,983.96 L682.76,1006.59 L637.505,1006.59 L637.505,961.332\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"637.505\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"682.76\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"637.505\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"660.133\\\" cy=\\\"983.96\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip22)\\\" cx=\\\"682.76\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M637.505,961.332 L682.76,961.332 L660.133,983.96 L682.76,1006.59 L637.505,1006.59 L637.505,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:43\\\">\\n\",\n              \"<path d=\\\"M592.25,1006.59 L637.505,1006.59 L614.878,1029.21 L637.505,1051.84 L592.25,1051.84 L592.25,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip23\\\"><path d=\\\"M592.25,1006.59 L637.505,1006.59 L614.878,1029.21 L637.505,1051.84 L592.25,1051.84 L592.25,1006.59\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"592.25\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"637.505\\\" cy=\\\"1006.59\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"592.25\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"614.878\\\" cy=\\\"1029.21\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip23)\\\" cx=\\\"637.505\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1006.59 L637.505,1006.59 L614.878,1029.21 L637.505,1051.84 L592.25,1051.84 L592.25,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:43\\\">\\n\",\n              \"<path d=\\\"M637.505,1006.59 L682.76,1006.59 L660.133,1029.21 L682.76,1051.84 L637.505,1051.84 L637.505,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1006.59 L682.76,1006.59 L660.133,1029.21 L682.76,1051.84 L637.505,1051.84 L637.505,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:44\\\">\\n\",\n              \"<path d=\\\"M776.791,961.332 L822.046,961.332 L799.419,983.96 L822.046,1006.59 L776.791,1006.59 L776.791,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,961.332 L822.046,961.332 L799.419,983.96 L822.046,1006.59 L776.791,1006.59 L776.791,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:44\\\">\\n\",\n              \"<path d=\\\"M822.046,961.332 L867.301,961.332 L844.673,983.96 L867.301,1006.59 L822.046,1006.59 L822.046,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,961.332 L867.301,961.332 L844.673,983.96 L867.301,1006.59 L822.046,1006.59 L822.046,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:44\\\">\\n\",\n              \"<path d=\\\"M776.791,1006.59 L822.046,1006.59 L799.419,1029.21 L822.046,1051.84 L776.791,1051.84 L776.791,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1006.59 L822.046,1006.59 L799.419,1029.21 L822.046,1051.84 L776.791,1051.84 L776.791,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:44\\\">\\n\",\n              \"<path d=\\\"M822.046,1006.59 L867.301,1006.59 L844.673,1029.21 L867.301,1051.84 L822.046,1051.84 L822.046,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1006.59 L867.301,1006.59 L844.673,1029.21 L867.301,1051.84 L822.046,1051.84 L822.046,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:45\\\">\\n\",\n              \"<path d=\\\"M961.332,961.332 L983.96,938.705 L1006.59,961.332 C993.011 970.383,993.011 970.383,983.96 983.96 C970.383 993.011,970.383 993.011,961.332 1006.59 L961.332,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,961.332 L983.96,938.705 L1006.59,961.332 C993.011 970.383,993.011 970.383,983.96 983.96 C970.383 993.011,970.383 993.011,961.332 1006.59 L961.332,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:45\\\">\\n\",\n              \"<path d=\\\"M1006.59,961.332 L1051.84,961.332 C1038.27 970.383,1038.27 970.383,1029.21 983.96 C1015.64 993.011,1015.64 993.011,1006.59 1006.59 L983.96,983.96 L1006.59,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,961.332 L1051.84,961.332 C1038.27 970.383,1038.27 970.383,1029.21 983.96 C1015.64 993.011,1015.64 993.011,1006.59 1006.59 L983.96,983.96 L1006.59,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:47\\\">\\n\",\n              \"<path d=\\\"M1353.04,1029.21 C1366.62 1020.16,1366.62 1020.16,1375.67 1006.59 L1398.3,1029.21 L1375.67,1051.84 L1330.41,1051.84 C1343.99 1042.79,1343.99 1042.79,1353.04 1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,1029.21 C1366.62 1020.16,1366.62 1020.16,1375.67 1006.59 L1398.3,1029.21 L1375.67,1051.84 L1330.41,1051.84 C1343.99 1042.79,1343.99 1042.79,1353.04 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:47\\\">\\n\",\n              \"<path d=\\\"M1398.3,1029.21 C1411.87 1020.16,1411.87 1020.16,1420.92 1006.59 L1420.92,1051.84 L1398.3,1074.47 L1375.67,1051.84 C1389.25 1042.79,1389.25 1042.79,1398.3 1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,1029.21 C1411.87 1020.16,1411.87 1020.16,1420.92 1006.59 L1420.92,1051.84 L1398.3,1074.47 L1375.67,1051.84 C1389.25 1042.79,1389.25 1042.79,1398.3 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:48\\\">\\n\",\n              \"<path d=\\\"M38.6274,1145.87 L83.8822,1145.87 L61.2548,1168.5 L83.8822,1191.13 L38.6274,1191.13 L38.6274,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1145.87 L83.8822,1145.87 L61.2548,1168.5 L83.8822,1191.13 L38.6274,1191.13 L38.6274,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:48\\\">\\n\",\n              \"<path d=\\\"M83.8822,1145.87 L129.137,1145.87 L106.51,1168.5 L129.137,1191.13 L83.8822,1191.13 L83.8822,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1145.87 L129.137,1145.87 L106.51,1168.5 L129.137,1191.13 L83.8822,1191.13 L83.8822,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:48\\\">\\n\",\n              \"<path d=\\\"M38.6274,1191.13 L83.8822,1191.13 L61.2548,1213.76 L83.8822,1236.38 L38.6274,1236.38 L38.6274,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1191.13 L83.8822,1191.13 L61.2548,1213.76 L83.8822,1236.38 L38.6274,1236.38 L38.6274,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:48\\\">\\n\",\n              \"<path d=\\\"M83.8822,1191.13 L129.137,1191.13 L106.51,1213.76 L129.137,1236.38 L83.8822,1236.38 L83.8822,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1191.13 L129.137,1191.13 L106.51,1213.76 L129.137,1236.38 L83.8822,1236.38 L83.8822,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:49\\\">\\n\",\n              \"<path d=\\\"M223.168,1145.87 L268.423,1145.87 L245.796,1168.5 L268.423,1191.13 L223.168,1191.13 L223.168,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1145.87 L268.423,1145.87 L245.796,1168.5 L268.423,1191.13 L223.168,1191.13 L223.168,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:49\\\">\\n\",\n              \"<path d=\\\"M268.423,1145.87 L313.678,1145.87 L291.051,1168.5 L313.678,1191.13 L268.423,1191.13 L268.423,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip24\\\"><path d=\\\"M268.423,1145.87 L313.678,1145.87 L291.051,1168.5 L313.678,1191.13 L268.423,1191.13 L268.423,1145.87\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"268.423\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"313.678\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"268.423\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"291.051\\\" cy=\\\"1168.5\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip24)\\\" cx=\\\"313.678\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1145.87 L313.678,1145.87 L291.051,1168.5 L313.678,1191.13 L268.423,1191.13 L268.423,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:49\\\">\\n\",\n              \"<path d=\\\"M223.168,1191.13 L268.423,1191.13 L245.796,1213.76 L268.423,1236.38 L223.168,1236.38 L223.168,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip25\\\"><path d=\\\"M223.168,1191.13 L268.423,1191.13 L245.796,1213.76 L268.423,1236.38 L223.168,1236.38 L223.168,1191.13\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"223.168\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"268.423\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"223.168\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"245.796\\\" cy=\\\"1213.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip25)\\\" cx=\\\"268.423\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1191.13 L268.423,1191.13 L245.796,1213.76 L268.423,1236.38 L223.168,1236.38 L223.168,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:49\\\">\\n\",\n              \"<path d=\\\"M268.423,1191.13 L313.678,1191.13 L291.051,1213.76 L313.678,1236.38 L268.423,1236.38 L268.423,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1191.13 L313.678,1191.13 L291.051,1213.76 L313.678,1236.38 L268.423,1236.38 L268.423,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:50\\\">\\n\",\n              \"<path d=\\\"M407.709,1145.87 L452.964,1145.87 L430.337,1168.5 L452.964,1191.13 L407.709,1191.13 L407.709,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1145.87 L452.964,1145.87 L430.337,1168.5 L452.964,1191.13 L407.709,1191.13 L407.709,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:50\\\">\\n\",\n              \"<path d=\\\"M452.964,1145.87 L498.219,1145.87 L475.592,1168.5 L498.219,1191.13 L452.964,1191.13 L452.964,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip26\\\"><path d=\\\"M452.964,1145.87 L498.219,1145.87 L475.592,1168.5 L498.219,1191.13 L452.964,1191.13 L452.964,1145.87\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"452.964\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"498.219\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"452.964\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"475.592\\\" cy=\\\"1168.5\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip26)\\\" cx=\\\"498.219\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1145.87 L498.219,1145.87 L475.592,1168.5 L498.219,1191.13 L452.964,1191.13 L452.964,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:50\\\">\\n\",\n              \"<path d=\\\"M407.709,1191.13 L452.964,1191.13 L430.337,1213.76 L452.964,1236.38 L407.709,1236.38 L407.709,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip27\\\"><path d=\\\"M407.709,1191.13 L452.964,1191.13 L430.337,1213.76 L452.964,1236.38 L407.709,1236.38 L407.709,1191.13\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"407.709\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"452.964\\\" cy=\\\"1191.13\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"407.709\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"430.337\\\" cy=\\\"1213.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip27)\\\" cx=\\\"452.964\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1191.13 L452.964,1191.13 L430.337,1213.76 L452.964,1236.38 L407.709,1236.38 L407.709,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:50\\\">\\n\",\n              \"<path d=\\\"M452.964,1191.13 L498.219,1191.13 L475.592,1213.76 L498.219,1236.38 L452.964,1236.38 L452.964,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1191.13 L498.219,1191.13 L475.592,1213.76 L498.219,1236.38 L452.964,1236.38 L452.964,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:51\\\">\\n\",\n              \"<path d=\\\"M592.25,1145.87 L637.505,1145.87 L614.878,1168.5 L637.505,1191.13 L592.25,1191.13 L592.25,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1145.87 L637.505,1145.87 L614.878,1168.5 L637.505,1191.13 L592.25,1191.13 L592.25,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:51\\\">\\n\",\n              \"<path d=\\\"M637.505,1145.87 L682.76,1145.87 L660.133,1168.5 L682.76,1191.13 L637.505,1191.13 L637.505,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1145.87 L682.76,1145.87 L660.133,1168.5 L682.76,1191.13 L637.505,1191.13 L637.505,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:51\\\">\\n\",\n              \"<path d=\\\"M592.25,1191.13 L637.505,1191.13 L614.878,1213.76 L637.505,1236.38 L592.25,1236.38 L592.25,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1191.13 L637.505,1191.13 L614.878,1213.76 L637.505,1236.38 L592.25,1236.38 L592.25,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:51\\\">\\n\",\n              \"<path d=\\\"M637.505,1191.13 L682.76,1191.13 L660.133,1213.76 L682.76,1236.38 L637.505,1236.38 L637.505,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1191.13 L682.76,1191.13 L660.133,1213.76 L682.76,1236.38 L637.505,1236.38 L637.505,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:52\\\">\\n\",\n              \"<path d=\\\"M776.791,1145.87 L799.419,1123.25 L822.046,1145.87 C808.47 1154.92,808.47 1154.92,799.419 1168.5 C785.842 1177.55,785.842 1177.55,776.791 1191.13 L776.791,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1145.87 L799.419,1123.25 L822.046,1145.87 C808.47 1154.92,808.47 1154.92,799.419 1168.5 C785.842 1177.55,785.842 1177.55,776.791 1191.13 L776.791,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:52\\\">\\n\",\n              \"<path d=\\\"M822.046,1145.87 L867.301,1145.87 C853.724 1154.92,853.724 1154.92,844.673 1168.5 C831.097 1177.55,831.097 1177.55,822.046 1191.13 L799.419,1168.5 L822.046,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1145.87 L867.301,1145.87 C853.724 1154.92,853.724 1154.92,844.673 1168.5 C831.097 1177.55,831.097 1177.55,822.046 1191.13 L799.419,1168.5 L822.046,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:54\\\">\\n\",\n              \"<path d=\\\"M1168.5,1213.76 C1182.08 1204.7,1182.08 1204.7,1191.13 1191.13 L1213.76,1213.76 L1191.13,1236.38 L1145.87,1236.38 C1159.45 1227.33,1159.45 1227.33,1168.5 1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,1213.76 C1182.08 1204.7,1182.08 1204.7,1191.13 1191.13 L1213.76,1213.76 L1191.13,1236.38 L1145.87,1236.38 C1159.45 1227.33,1159.45 1227.33,1168.5 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:54\\\">\\n\",\n              \"<path d=\\\"M1213.76,1213.76 C1227.33 1204.7,1227.33 1204.7,1236.38 1191.13 L1236.38,1236.38 L1213.76,1259.01 L1191.13,1236.38 C1204.7 1227.33,1204.7 1227.33,1213.76 1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,1213.76 C1227.33 1204.7,1227.33 1204.7,1236.38 1191.13 L1236.38,1236.38 L1213.76,1259.01 L1191.13,1236.38 C1204.7 1227.33,1204.7 1227.33,1213.76 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:55\\\">\\n\",\n              \"<path d=\\\"M1330.41,1145.87 L1375.67,1145.87 L1353.04,1168.5 L1375.67,1191.13 L1330.41,1191.13 L1330.41,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,1145.87 L1375.67,1145.87 L1353.04,1168.5 L1375.67,1191.13 L1330.41,1191.13 L1330.41,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:55\\\">\\n\",\n              \"<path d=\\\"M1375.67,1145.87 L1420.92,1145.87 L1398.3,1168.5 L1420.92,1191.13 L1375.67,1191.13 L1375.67,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1145.87 L1420.92,1145.87 L1398.3,1168.5 L1420.92,1191.13 L1375.67,1191.13 L1375.67,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:55\\\">\\n\",\n              \"<path d=\\\"M1330.41,1191.13 L1375.67,1191.13 L1353.04,1213.76 L1375.67,1236.38 L1330.41,1236.38 L1330.41,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,1191.13 L1375.67,1191.13 L1353.04,1213.76 L1375.67,1236.38 L1330.41,1236.38 L1330.41,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:55\\\">\\n\",\n              \"<path d=\\\"M1375.67,1191.13 L1420.92,1191.13 L1398.3,1213.76 L1420.92,1236.38 L1375.67,1236.38 L1375.67,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1191.13 L1420.92,1191.13 L1398.3,1213.76 L1420.92,1236.38 L1375.67,1236.38 L1375.67,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:56\\\">\\n\",\n              \"<path d=\\\"M38.6274,1330.41 L83.8822,1330.41 L61.2548,1353.04 L83.8822,1375.67 L38.6274,1375.67 L38.6274,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1330.41 L83.8822,1330.41 L61.2548,1353.04 L83.8822,1375.67 L38.6274,1375.67 L38.6274,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:56\\\">\\n\",\n              \"<path d=\\\"M83.8822,1330.41 L129.137,1330.41 L106.51,1353.04 L129.137,1375.67 L83.8822,1375.67 L83.8822,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip28\\\"><path d=\\\"M83.8822,1330.41 L129.137,1330.41 L106.51,1353.04 L129.137,1375.67 L83.8822,1375.67 L83.8822,1330.41\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"83.8822\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"129.137\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"83.8822\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"106.51\\\" cy=\\\"1353.04\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip28)\\\" cx=\\\"129.137\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1330.41 L129.137,1330.41 L106.51,1353.04 L129.137,1375.67 L83.8822,1375.67 L83.8822,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:56\\\">\\n\",\n              \"<path d=\\\"M38.6274,1375.67 L83.8822,1375.67 L61.2548,1398.3 L83.8822,1420.92 L38.6274,1420.92 L38.6274,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip29\\\"><path d=\\\"M38.6274,1375.67 L83.8822,1375.67 L61.2548,1398.3 L83.8822,1420.92 L38.6274,1420.92 L38.6274,1375.67\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"38.6274\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"83.8822\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"38.6274\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"61.2548\\\" cy=\\\"1398.3\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip29)\\\" cx=\\\"83.8822\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1375.67 L83.8822,1375.67 L61.2548,1398.3 L83.8822,1420.92 L38.6274,1420.92 L38.6274,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:56\\\">\\n\",\n              \"<path d=\\\"M83.8822,1375.67 L129.137,1375.67 L106.51,1398.3 L129.137,1420.92 L83.8822,1420.92 L83.8822,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1375.67 L129.137,1375.67 L106.51,1398.3 L129.137,1420.92 L83.8822,1420.92 L83.8822,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:57\\\">\\n\",\n              \"<path d=\\\"M223.168,1330.41 L268.423,1330.41 L245.796,1353.04 L268.423,1375.67 L223.168,1375.67 L223.168,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1330.41 L268.423,1330.41 L245.796,1353.04 L268.423,1375.67 L223.168,1375.67 L223.168,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:57\\\">\\n\",\n              \"<path d=\\\"M268.423,1330.41 L313.678,1330.41 L291.051,1353.04 L313.678,1375.67 L268.423,1375.67 L268.423,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip30\\\"><path d=\\\"M268.423,1330.41 L313.678,1330.41 L291.051,1353.04 L313.678,1375.67 L268.423,1375.67 L268.423,1330.41\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"268.423\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"313.678\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"268.423\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"291.051\\\" cy=\\\"1353.04\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip30)\\\" cx=\\\"313.678\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1330.41 L313.678,1330.41 L291.051,1353.04 L313.678,1375.67 L268.423,1375.67 L268.423,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:57\\\">\\n\",\n              \"<path d=\\\"M223.168,1375.67 L268.423,1375.67 L245.796,1398.3 L268.423,1420.92 L223.168,1420.92 L223.168,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip31\\\"><path d=\\\"M223.168,1375.67 L268.423,1375.67 L245.796,1398.3 L268.423,1420.92 L223.168,1420.92 L223.168,1375.67\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"223.168\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"268.423\\\" cy=\\\"1375.67\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"223.168\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"245.796\\\" cy=\\\"1398.3\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip31)\\\" cx=\\\"268.423\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M223.168,1375.67 L268.423,1375.67 L245.796,1398.3 L268.423,1420.92 L223.168,1420.92 L223.168,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:57\\\">\\n\",\n              \"<path d=\\\"M268.423,1375.67 L313.678,1375.67 L291.051,1398.3 L313.678,1420.92 L268.423,1420.92 L268.423,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1375.67 L313.678,1375.67 L291.051,1398.3 L313.678,1420.92 L268.423,1420.92 L268.423,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:58\\\">\\n\",\n              \"<path d=\\\"M407.709,1330.41 L452.964,1330.41 L430.337,1353.04 L452.964,1375.67 L407.709,1375.67 L407.709,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1330.41 L452.964,1330.41 L430.337,1353.04 L452.964,1375.67 L407.709,1375.67 L407.709,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:58\\\">\\n\",\n              \"<path d=\\\"M452.964,1330.41 L498.219,1330.41 L475.592,1353.04 L498.219,1375.67 L452.964,1375.67 L452.964,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1330.41 L498.219,1330.41 L475.592,1353.04 L498.219,1375.67 L452.964,1375.67 L452.964,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:58\\\">\\n\",\n              \"<path d=\\\"M407.709,1375.67 L452.964,1375.67 L430.337,1398.3 L452.964,1420.92 L407.709,1420.92 L407.709,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,1375.67 L452.964,1375.67 L430.337,1398.3 L452.964,1420.92 L407.709,1420.92 L407.709,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:58\\\">\\n\",\n              \"<path d=\\\"M452.964,1375.67 L498.219,1375.67 L475.592,1398.3 L498.219,1420.92 L452.964,1420.92 L452.964,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1375.67 L498.219,1375.67 L475.592,1398.3 L498.219,1420.92 L452.964,1420.92 L452.964,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:59\\\">\\n\",\n              \"<path d=\\\"M592.25,1330.41 L614.878,1307.79 L637.505,1330.41 C623.929 1339.47,623.929 1339.47,614.878 1353.04 C601.301 1362.09,601.301 1362.09,592.25 1375.67 L592.25,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1330.41 L614.878,1307.79 L637.505,1330.41 C623.929 1339.47,623.929 1339.47,614.878 1353.04 C601.301 1362.09,601.301 1362.09,592.25 1375.67 L592.25,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:59\\\">\\n\",\n              \"<path d=\\\"M637.505,1330.41 L682.76,1330.41 C669.183 1339.47,669.183 1339.47,660.133 1353.04 C646.556 1362.09,646.556 1362.09,637.505 1375.67 L614.878,1353.04 L637.505,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1330.41 L682.76,1330.41 C669.183 1339.47,669.183 1339.47,660.133 1353.04 C646.556 1362.09,646.556 1362.09,637.505 1375.67 L614.878,1353.04 L637.505,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:61\\\">\\n\",\n              \"<path d=\\\"M1029.21,1398.3 C1042.79 1389.25,1042.79 1389.25,1051.84 1375.67 L1051.84,1420.92 L1029.21,1443.55 L1006.59,1420.92 C1020.16 1411.87,1020.16 1411.87,1029.21 1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,1398.3 C1042.79 1389.25,1042.79 1389.25,1051.84 1375.67 L1051.84,1420.92 L1029.21,1443.55 L1006.59,1420.92 C1020.16 1411.87,1020.16 1411.87,1029.21 1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:62\\\">\\n\",\n              \"<path d=\\\"M1145.87,1330.41 L1191.13,1330.41 L1168.5,1353.04 L1191.13,1375.67 L1145.87,1375.67 L1145.87,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1330.41 L1191.13,1330.41 L1168.5,1353.04 L1191.13,1375.67 L1145.87,1375.67 L1145.87,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:62\\\">\\n\",\n              \"<path d=\\\"M1191.13,1375.67 L1236.38,1375.67 L1213.76,1398.3 L1236.38,1420.92 L1191.13,1420.92 L1191.13,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1375.67 L1236.38,1375.67 L1213.76,1398.3 L1236.38,1420.92 L1191.13,1420.92 L1191.13,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:63\\\">\\n\",\n              \"<path d=\\\"M1330.41,1330.41 L1375.67,1330.41 L1353.04,1353.04 L1375.67,1375.67 L1330.41,1375.67 L1330.41,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,1330.41 L1375.67,1330.41 L1353.04,1353.04 L1375.67,1375.67 L1330.41,1375.67 L1330.41,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:63\\\">\\n\",\n              \"<path d=\\\"M1375.67,1375.67 L1420.92,1375.67 L1398.3,1398.3 L1420.92,1420.92 L1375.67,1420.92 L1375.67,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1375.67 L1420.92,1375.67 L1398.3,1398.3 L1420.92,1420.92 L1375.67,1420.92 L1375.67,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:3\\\">\\n\",\n              \"<path d=\\\"M660.133,61.2548 L682.76,38.6274 L705.387,61.2548 L682.76,83.8822 L660.133,61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,61.2548 L682.76,38.6274 L705.387,61.2548 L682.76,83.8822 L660.133,61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:4\\\">\\n\",\n              \"<path d=\\\"M799.419,106.51 L822.046,83.8822 L844.673,106.51 L822.046,129.137 L799.419,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,106.51 L822.046,83.8822 L844.673,106.51 L822.046,129.137 L799.419,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:4\\\">\\n\",\n              \"<path d=\\\"M844.673,61.2548 L867.301,38.6274 L889.928,61.2548 L867.301,83.8822 L844.673,61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,61.2548 L867.301,38.6274 L889.928,61.2548 L867.301,83.8822 L844.673,61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:4\\\">\\n\",\n              \"<path d=\\\"M776.791,38.6274 L799.419,16 L822.046,38.6274 L799.419,61.2548 L776.791,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,38.6274 L799.419,16 L822.046,38.6274 L799.419,61.2548 L776.791,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:4\\\">\\n\",\n              \"<path d=\\\"M799.419,61.2548 L822.046,38.6274 L844.673,61.2548 L822.046,83.8822 L799.419,61.2548\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,61.2548 L822.046,38.6274 L844.673,61.2548 L822.046,83.8822 L799.419,61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:4\\\">\\n\",\n              \"<path d=\\\"M822.046,83.8822 L844.673,61.2548 L867.301,83.8822 L844.673,106.51 L822.046,83.8822\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,83.8822 L844.673,61.2548 L867.301,83.8822 L844.673,106.51 L822.046,83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:4\\\">\\n\",\n              \"<path d=\\\"M754.164,106.51 L776.791,83.8822 L799.419,106.51 L776.791,129.137 L754.164,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,106.51 L776.791,83.8822 L799.419,106.51 L776.791,129.137 L754.164,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:5\\\">\\n\",\n              \"<path d=\\\"M961.332,38.6274 L983.96,16 L1006.59,38.6274 L983.96,61.2548 L961.332,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,38.6274 L983.96,16 L1006.59,38.6274 L983.96,61.2548 L961.332,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:5\\\">\\n\",\n              \"<path d=\\\"M938.705,106.51 L961.332,83.8822 L983.96,106.51 L961.332,129.137 L938.705,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,106.51 L961.332,83.8822 L983.96,106.51 L961.332,129.137 L938.705,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:10\\\">\\n\",\n              \"<path d=\\\"M475.592,245.796 L498.219,223.168 L520.846,245.796 L498.219,268.423 L475.592,245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,245.796 L498.219,223.168 L520.846,245.796 L498.219,268.423 L475.592,245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:10\\\">\\n\",\n              \"<path d=\\\"M452.964,313.678 L475.592,291.051 L498.219,313.678 L475.592,336.305 L452.964,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,313.678 L475.592,291.051 L498.219,313.678 L475.592,336.305 L452.964,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:11\\\">\\n\",\n              \"<path d=\\\"M660.133,245.796 L682.76,223.168 L705.387,245.796 L682.76,268.423 L660.133,245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,245.796 L682.76,223.168 L705.387,245.796 L682.76,268.423 L660.133,245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:11\\\">\\n\",\n              \"<path d=\\\"M592.25,268.423 L614.878,245.796 L637.505,268.423 L614.878,291.051 L592.25,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,268.423 L614.878,245.796 L637.505,268.423 L614.878,291.051 L592.25,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:11\\\">\\n\",\n              \"<path d=\\\"M614.878,291.051 L637.505,268.423 L660.133,291.051 L637.505,313.678 L614.878,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,291.051 L637.505,268.423 L660.133,291.051 L637.505,313.678 L614.878,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:11\\\">\\n\",\n              \"<path d=\\\"M637.505,313.678 L660.133,291.051 L682.76,313.678 L660.133,336.305 L637.505,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,313.678 L660.133,291.051 L682.76,313.678 L660.133,336.305 L637.505,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:11\\\">\\n\",\n              \"<path d=\\\"M592.25,223.168 L614.878,200.541 L637.505,223.168 L614.878,245.796 L592.25,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,223.168 L614.878,200.541 L637.505,223.168 L614.878,245.796 L592.25,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:11\\\">\\n\",\n              \"<path d=\\\"M614.878,245.796 L637.505,223.168 L660.133,245.796 L637.505,268.423 L614.878,245.796\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,245.796 L637.505,223.168 L660.133,245.796 L637.505,268.423 L614.878,245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:11\\\">\\n\",\n              \"<path d=\\\"M637.505,268.423 L660.133,245.796 L682.76,268.423 L660.133,291.051 L637.505,268.423\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,268.423 L660.133,245.796 L682.76,268.423 L660.133,291.051 L637.505,268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:11\\\">\\n\",\n              \"<path d=\\\"M569.623,291.051 L592.25,268.423 L614.878,291.051 L592.25,313.678 L569.623,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,291.051 L592.25,268.423 L614.878,291.051 L592.25,313.678 L569.623,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:12\\\">\\n\",\n              \"<path d=\\\"M776.791,223.168 L799.419,200.541 L822.046,223.168 L799.419,245.796 L776.791,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,223.168 L799.419,200.541 L822.046,223.168 L799.419,245.796 L776.791,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:12\\\">\\n\",\n              \"<path d=\\\"M754.164,291.051 L776.791,268.423 L799.419,291.051 L776.791,313.678 L754.164,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,291.051 L776.791,268.423 L799.419,291.051 L776.791,313.678 L754.164,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:17\\\">\\n\",\n              \"<path d=\\\"M291.051,430.337 L313.678,407.709 L336.305,430.337 L313.678,452.964 L291.051,430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,430.337 L313.678,407.709 L336.305,430.337 L313.678,452.964 L291.051,430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:17\\\">\\n\",\n              \"<path d=\\\"M268.423,498.219 L291.051,475.592 L313.678,498.219 L291.051,520.846 L268.423,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,498.219 L291.051,475.592 L313.678,498.219 L291.051,520.846 L268.423,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:18\\\">\\n\",\n              \"<path d=\\\"M475.592,430.337 L498.219,407.709 L520.846,430.337 L498.219,452.964 L475.592,430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,430.337 L498.219,407.709 L520.846,430.337 L498.219,452.964 L475.592,430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:18\\\">\\n\",\n              \"<path d=\\\"M407.709,452.964 L430.337,430.337 L452.964,452.964 L430.337,475.592 L407.709,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,452.964 L430.337,430.337 L452.964,452.964 L430.337,475.592 L407.709,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:18\\\">\\n\",\n              \"<path d=\\\"M430.337,475.592 L452.964,452.964 L475.592,475.592 L452.964,498.219 L430.337,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M430.337,475.592 L452.964,452.964 L475.592,475.592 L452.964,498.219 L430.337,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:18\\\">\\n\",\n              \"<path d=\\\"M452.964,498.219 L475.592,475.592 L498.219,498.219 L475.592,520.846 L452.964,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,498.219 L475.592,475.592 L498.219,498.219 L475.592,520.846 L452.964,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:18\\\">\\n\",\n              \"<path d=\\\"M407.709,407.709 L430.337,385.082 L452.964,407.709 L430.337,430.337 L407.709,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,407.709 L430.337,385.082 L452.964,407.709 L430.337,430.337 L407.709,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:18\\\">\\n\",\n              \"<path d=\\\"M430.337,430.337 L452.964,407.709 L475.592,430.337 L452.964,452.964 L430.337,430.337\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M430.337,430.337 L452.964,407.709 L475.592,430.337 L452.964,452.964 L430.337,430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:18\\\">\\n\",\n              \"<path d=\\\"M452.964,452.964 L475.592,430.337 L498.219,452.964 L475.592,475.592 L452.964,452.964\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,452.964 L475.592,430.337 L498.219,452.964 L475.592,475.592 L452.964,452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:18\\\">\\n\",\n              \"<path d=\\\"M385.082,475.592 L407.709,452.964 L430.337,475.592 L407.709,498.219 L385.082,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,475.592 L407.709,452.964 L430.337,475.592 L407.709,498.219 L385.082,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:19\\\">\\n\",\n              \"<path d=\\\"M592.25,407.709 L614.878,385.082 L637.505,407.709 L614.878,430.337 L592.25,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,407.709 L614.878,385.082 L637.505,407.709 L614.878,430.337 L592.25,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:19\\\">\\n\",\n              \"<path d=\\\"M569.623,475.592 L592.25,452.964 L614.878,475.592 L592.25,498.219 L569.623,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,475.592 L592.25,452.964 L614.878,475.592 L592.25,498.219 L569.623,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:24\\\">\\n\",\n              \"<path d=\\\"M106.51,614.878 L129.137,592.25 L151.764,614.878 L129.137,637.505 L106.51,614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,614.878 L129.137,592.25 L151.764,614.878 L129.137,637.505 L106.51,614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:24\\\">\\n\",\n              \"<path d=\\\"M83.8822,682.76 L106.51,660.133 L129.137,682.76 L106.51,705.387 L83.8822,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,682.76 L106.51,660.133 L129.137,682.76 L106.51,705.387 L83.8822,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:25\\\">\\n\",\n              \"<path d=\\\"M291.051,614.878 L313.678,592.25 L336.305,614.878 L313.678,637.505 L291.051,614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,614.878 L313.678,592.25 L336.305,614.878 L313.678,637.505 L291.051,614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:25\\\">\\n\",\n              \"<path d=\\\"M223.168,637.505 L245.796,614.878 L268.423,637.505 L245.796,660.133 L223.168,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,637.505 L245.796,614.878 L268.423,637.505 L245.796,660.133 L223.168,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:25\\\">\\n\",\n              \"<path d=\\\"M245.796,660.133 L268.423,637.505 L291.051,660.133 L268.423,682.76 L245.796,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M245.796,660.133 L268.423,637.505 L291.051,660.133 L268.423,682.76 L245.796,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:25\\\">\\n\",\n              \"<path d=\\\"M268.423,682.76 L291.051,660.133 L313.678,682.76 L291.051,705.387 L268.423,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,682.76 L291.051,660.133 L313.678,682.76 L291.051,705.387 L268.423,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:25\\\">\\n\",\n              \"<path d=\\\"M223.168,592.25 L245.796,569.623 L268.423,592.25 L245.796,614.878 L223.168,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,592.25 L245.796,569.623 L268.423,592.25 L245.796,614.878 L223.168,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:25\\\">\\n\",\n              \"<path d=\\\"M245.796,614.878 L268.423,592.25 L291.051,614.878 L268.423,637.505 L245.796,614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M245.796,614.878 L268.423,592.25 L291.051,614.878 L268.423,637.505 L245.796,614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:25\\\">\\n\",\n              \"<path d=\\\"M268.423,637.505 L291.051,614.878 L313.678,637.505 L291.051,660.133 L268.423,637.505\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,637.505 L291.051,614.878 L313.678,637.505 L291.051,660.133 L268.423,637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:25\\\">\\n\",\n              \"<path d=\\\"M200.541,660.133 L223.168,637.505 L245.796,660.133 L223.168,682.76 L200.541,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,660.133 L223.168,637.505 L245.796,660.133 L223.168,682.76 L200.541,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:26\\\">\\n\",\n              \"<path d=\\\"M407.709,592.25 L430.337,569.623 L452.964,592.25 L430.337,614.878 L407.709,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,592.25 L430.337,569.623 L452.964,592.25 L430.337,614.878 L407.709,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:26\\\">\\n\",\n              \"<path d=\\\"M385.082,660.133 L407.709,637.505 L430.337,660.133 L407.709,682.76 L385.082,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,660.133 L407.709,637.505 L430.337,660.133 L407.709,682.76 L385.082,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:31\\\">\\n\",\n              \"<path d=\\\"M1398.3,614.878 L1420.92,592.25 L1443.55,614.878 L1420.92,637.505 L1398.3,614.878\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,614.878 L1420.92,592.25 L1443.55,614.878 L1420.92,637.505 L1398.3,614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:31\\\">\\n\",\n              \"<path d=\\\"M1375.67,682.76 L1398.3,660.133 L1420.92,682.76 L1398.3,705.387 L1375.67,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,682.76 L1398.3,660.133 L1420.92,682.76 L1398.3,705.387 L1375.67,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:32\\\">\\n\",\n              \"<path d=\\\"M106.51,799.419 L129.137,776.791 L151.764,799.419 L129.137,822.046 L106.51,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,799.419 L129.137,776.791 L151.764,799.419 L129.137,822.046 L106.51,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:32\\\">\\n\",\n              \"<path d=\\\"M38.6274,822.046 L61.2548,799.419 L83.8822,822.046 L61.2548,844.673 L38.6274,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,822.046 L61.2548,799.419 L83.8822,822.046 L61.2548,844.673 L38.6274,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:32\\\">\\n\",\n              \"<path d=\\\"M61.2548,844.673 L83.8822,822.046 L106.51,844.673 L83.8822,867.301 L61.2548,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,844.673 L83.8822,822.046 L106.51,844.673 L83.8822,867.301 L61.2548,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:32\\\">\\n\",\n              \"<path d=\\\"M83.8822,867.301 L106.51,844.673 L129.137,867.301 L106.51,889.928 L83.8822,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,867.301 L106.51,844.673 L129.137,867.301 L106.51,889.928 L83.8822,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:32\\\">\\n\",\n              \"<path d=\\\"M38.6274,776.791 L61.2548,754.164 L83.8822,776.791 L61.2548,799.419 L38.6274,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,776.791 L61.2548,754.164 L83.8822,776.791 L61.2548,799.419 L38.6274,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:32\\\">\\n\",\n              \"<path d=\\\"M61.2548,799.419 L83.8822,776.791 L106.51,799.419 L83.8822,822.046 L61.2548,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,799.419 L83.8822,776.791 L106.51,799.419 L83.8822,822.046 L61.2548,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:32\\\">\\n\",\n              \"<path d=\\\"M83.8822,822.046 L106.51,799.419 L129.137,822.046 L106.51,844.673 L83.8822,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,822.046 L106.51,799.419 L129.137,822.046 L106.51,844.673 L83.8822,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:32\\\">\\n\",\n              \"<path d=\\\"M16,844.673 L38.6274,822.046 L61.2548,844.673 L38.6274,867.301 L16,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,844.673 L38.6274,822.046 L61.2548,844.673 L38.6274,867.301 L16,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:33\\\">\\n\",\n              \"<path d=\\\"M223.168,776.791 L245.796,754.164 L268.423,776.791 L245.796,799.419 L223.168,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,776.791 L245.796,754.164 L268.423,776.791 L245.796,799.419 L223.168,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:33\\\">\\n\",\n              \"<path d=\\\"M200.541,844.673 L223.168,822.046 L245.796,844.673 L223.168,867.301 L200.541,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,844.673 L223.168,822.046 L245.796,844.673 L223.168,867.301 L200.541,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:38\\\">\\n\",\n              \"<path d=\\\"M1213.76,799.419 L1236.38,776.791 L1259.01,799.419 L1236.38,822.046 L1213.76,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,799.419 L1236.38,776.791 L1259.01,799.419 L1236.38,822.046 L1213.76,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:38\\\">\\n\",\n              \"<path d=\\\"M1191.13,867.301 L1213.76,844.673 L1236.38,867.301 L1213.76,889.928 L1191.13,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,867.301 L1213.76,844.673 L1236.38,867.301 L1213.76,889.928 L1191.13,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:39\\\">\\n\",\n              \"<path d=\\\"M1398.3,799.419 L1420.92,776.791 L1443.55,799.419 L1420.92,822.046 L1398.3,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,799.419 L1420.92,776.791 L1443.55,799.419 L1420.92,822.046 L1398.3,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:39\\\">\\n\",\n              \"<path d=\\\"M1330.41,822.046 L1353.04,799.419 L1375.67,822.046 L1353.04,844.673 L1330.41,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,822.046 L1353.04,799.419 L1375.67,822.046 L1353.04,844.673 L1330.41,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:39\\\">\\n\",\n              \"<path d=\\\"M1353.04,844.673 L1375.67,822.046 L1398.3,844.673 L1375.67,867.301 L1353.04,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,844.673 L1375.67,822.046 L1398.3,844.673 L1375.67,867.301 L1353.04,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:39\\\">\\n\",\n              \"<path d=\\\"M1375.67,867.301 L1398.3,844.673 L1420.92,867.301 L1398.3,889.928 L1375.67,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,867.301 L1398.3,844.673 L1420.92,867.301 L1398.3,889.928 L1375.67,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:39\\\">\\n\",\n              \"<path d=\\\"M1330.41,776.791 L1353.04,754.164 L1375.67,776.791 L1353.04,799.419 L1330.41,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,776.791 L1353.04,754.164 L1375.67,776.791 L1353.04,799.419 L1330.41,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:39\\\">\\n\",\n              \"<path d=\\\"M1353.04,799.419 L1375.67,776.791 L1398.3,799.419 L1375.67,822.046 L1353.04,799.419\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,799.419 L1375.67,776.791 L1398.3,799.419 L1375.67,822.046 L1353.04,799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:39\\\">\\n\",\n              \"<path d=\\\"M1375.67,822.046 L1398.3,799.419 L1420.92,822.046 L1398.3,844.673 L1375.67,822.046\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,822.046 L1398.3,799.419 L1420.92,822.046 L1398.3,844.673 L1375.67,822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:39\\\">\\n\",\n              \"<path d=\\\"M1307.79,844.673 L1330.41,822.046 L1353.04,844.673 L1330.41,867.301 L1307.79,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,844.673 L1330.41,822.046 L1353.04,844.673 L1330.41,867.301 L1307.79,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:40\\\">\\n\",\n              \"<path d=\\\"M38.6274,961.332 L61.2548,938.705 L83.8822,961.332 L61.2548,983.96 L38.6274,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,961.332 L61.2548,938.705 L83.8822,961.332 L61.2548,983.96 L38.6274,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:40\\\">\\n\",\n              \"<path d=\\\"M16,1029.21 L38.6274,1006.59 L61.2548,1029.21 L38.6274,1051.84 L16,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,1029.21 L38.6274,1006.59 L61.2548,1029.21 L38.6274,1051.84 L16,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:45\\\">\\n\",\n              \"<path d=\\\"M1029.21,983.96 L1051.84,961.332 L1074.47,983.96 L1051.84,1006.59 L1029.21,983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,983.96 L1051.84,961.332 L1074.47,983.96 L1051.84,1006.59 L1029.21,983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:45\\\">\\n\",\n              \"<path d=\\\"M1006.59,1051.84 L1029.21,1029.21 L1051.84,1051.84 L1029.21,1074.47 L1006.59,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1051.84 L1029.21,1029.21 L1051.84,1051.84 L1029.21,1074.47 L1006.59,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:46\\\">\\n\",\n              \"<path d=\\\"M1213.76,983.96 L1236.38,961.332 L1259.01,983.96 L1236.38,1006.59 L1213.76,983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,983.96 L1236.38,961.332 L1259.01,983.96 L1236.38,1006.59 L1213.76,983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:46\\\">\\n\",\n              \"<path d=\\\"M1145.87,1006.59 L1168.5,983.96 L1191.13,1006.59 L1168.5,1029.21 L1145.87,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1006.59 L1168.5,983.96 L1191.13,1006.59 L1168.5,1029.21 L1145.87,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:46\\\">\\n\",\n              \"<path d=\\\"M1168.5,1029.21 L1191.13,1006.59 L1213.76,1029.21 L1191.13,1051.84 L1168.5,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,1029.21 L1191.13,1006.59 L1213.76,1029.21 L1191.13,1051.84 L1168.5,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:46\\\">\\n\",\n              \"<path d=\\\"M1191.13,1051.84 L1213.76,1029.21 L1236.38,1051.84 L1213.76,1074.47 L1191.13,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1051.84 L1213.76,1029.21 L1236.38,1051.84 L1213.76,1074.47 L1191.13,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:46\\\">\\n\",\n              \"<path d=\\\"M1145.87,961.332 L1168.5,938.705 L1191.13,961.332 L1168.5,983.96 L1145.87,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,961.332 L1168.5,938.705 L1191.13,961.332 L1168.5,983.96 L1145.87,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:46\\\">\\n\",\n              \"<path d=\\\"M1168.5,983.96 L1191.13,961.332 L1213.76,983.96 L1191.13,1006.59 L1168.5,983.96\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,983.96 L1191.13,961.332 L1213.76,983.96 L1191.13,1006.59 L1168.5,983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:46\\\">\\n\",\n              \"<path d=\\\"M1191.13,1006.59 L1213.76,983.96 L1236.38,1006.59 L1213.76,1029.21 L1191.13,1006.59\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1006.59 L1213.76,983.96 L1236.38,1006.59 L1213.76,1029.21 L1191.13,1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:46\\\">\\n\",\n              \"<path d=\\\"M1123.25,1029.21 L1145.87,1006.59 L1168.5,1029.21 L1145.87,1051.84 L1123.25,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,1029.21 L1145.87,1006.59 L1168.5,1029.21 L1145.87,1051.84 L1123.25,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:47\\\">\\n\",\n              \"<path d=\\\"M1330.41,961.332 L1353.04,938.705 L1375.67,961.332 L1353.04,983.96 L1330.41,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,961.332 L1353.04,938.705 L1375.67,961.332 L1353.04,983.96 L1330.41,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:47\\\">\\n\",\n              \"<path d=\\\"M1307.79,1029.21 L1330.41,1006.59 L1353.04,1029.21 L1330.41,1051.84 L1307.79,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,1029.21 L1330.41,1006.59 L1353.04,1029.21 L1330.41,1051.84 L1307.79,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:52\\\">\\n\",\n              \"<path d=\\\"M844.673,1168.5 L867.301,1145.87 L889.928,1168.5 L867.301,1191.13 L844.673,1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1168.5 L867.301,1145.87 L889.928,1168.5 L867.301,1191.13 L844.673,1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:52\\\">\\n\",\n              \"<path d=\\\"M822.046,1236.38 L844.673,1213.76 L867.301,1236.38 L844.673,1259.01 L822.046,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1236.38 L844.673,1213.76 L867.301,1236.38 L844.673,1259.01 L822.046,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:53\\\">\\n\",\n              \"<path d=\\\"M1029.21,1168.5 L1051.84,1145.87 L1074.47,1168.5 L1051.84,1191.13 L1029.21,1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,1168.5 L1051.84,1145.87 L1074.47,1168.5 L1051.84,1191.13 L1029.21,1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:53\\\">\\n\",\n              \"<path d=\\\"M961.332,1191.13 L983.96,1168.5 L1006.59,1191.13 L983.96,1213.76 L961.332,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1191.13 L983.96,1168.5 L1006.59,1191.13 L983.96,1213.76 L961.332,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:53\\\">\\n\",\n              \"<path d=\\\"M983.96,1213.76 L1006.59,1191.13 L1029.21,1213.76 L1006.59,1236.38 L983.96,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1213.76 L1006.59,1191.13 L1029.21,1213.76 L1006.59,1236.38 L983.96,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:53\\\">\\n\",\n              \"<path d=\\\"M1006.59,1236.38 L1029.21,1213.76 L1051.84,1236.38 L1029.21,1259.01 L1006.59,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1236.38 L1029.21,1213.76 L1051.84,1236.38 L1029.21,1259.01 L1006.59,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:53\\\">\\n\",\n              \"<path d=\\\"M961.332,1145.87 L983.96,1123.25 L1006.59,1145.87 L983.96,1168.5 L961.332,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1145.87 L983.96,1123.25 L1006.59,1145.87 L983.96,1168.5 L961.332,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:53\\\">\\n\",\n              \"<path d=\\\"M983.96,1168.5 L1006.59,1145.87 L1029.21,1168.5 L1006.59,1191.13 L983.96,1168.5\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1168.5 L1006.59,1145.87 L1029.21,1168.5 L1006.59,1191.13 L983.96,1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:53\\\">\\n\",\n              \"<path d=\\\"M1006.59,1191.13 L1029.21,1168.5 L1051.84,1191.13 L1029.21,1213.76 L1006.59,1191.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1191.13 L1029.21,1168.5 L1051.84,1191.13 L1029.21,1213.76 L1006.59,1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:53\\\">\\n\",\n              \"<path d=\\\"M938.705,1213.76 L961.332,1191.13 L983.96,1213.76 L961.332,1236.38 L938.705,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,1213.76 L961.332,1191.13 L983.96,1213.76 L961.332,1236.38 L938.705,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:54\\\">\\n\",\n              \"<path d=\\\"M1145.87,1145.87 L1168.5,1123.25 L1191.13,1145.87 L1168.5,1168.5 L1145.87,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1145.87 L1168.5,1123.25 L1191.13,1145.87 L1168.5,1168.5 L1145.87,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:54\\\">\\n\",\n              \"<path d=\\\"M1123.25,1213.76 L1145.87,1191.13 L1168.5,1213.76 L1145.87,1236.38 L1123.25,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,1213.76 L1145.87,1191.13 L1168.5,1213.76 L1145.87,1236.38 L1123.25,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:59\\\">\\n\",\n              \"<path d=\\\"M660.133,1353.04 L682.76,1330.41 L705.387,1353.04 L682.76,1375.67 L660.133,1353.04\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,1353.04 L682.76,1330.41 L705.387,1353.04 L682.76,1375.67 L660.133,1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:59\\\">\\n\",\n              \"<path d=\\\"M637.505,1420.92 L660.133,1398.3 L682.76,1420.92 L660.133,1443.55 L637.505,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1420.92 L660.133,1398.3 L682.76,1420.92 L660.133,1443.55 L637.505,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:60\\\">\\n\",\n              \"<path d=\\\"M844.673,1353.04 L867.301,1330.41 L889.928,1353.04 L867.301,1375.67 L844.673,1353.04\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1353.04 L867.301,1330.41 L889.928,1353.04 L867.301,1375.67 L844.673,1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:60\\\">\\n\",\n              \"<path d=\\\"M776.791,1375.67 L799.419,1353.04 L822.046,1375.67 L799.419,1398.3 L776.791,1375.67\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1375.67 L799.419,1353.04 L822.046,1375.67 L799.419,1398.3 L776.791,1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:60\\\">\\n\",\n              \"<path d=\\\"M799.419,1398.3 L822.046,1375.67 L844.673,1398.3 L822.046,1420.92 L799.419,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1398.3 L822.046,1375.67 L844.673,1398.3 L822.046,1420.92 L799.419,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:60\\\">\\n\",\n              \"<path d=\\\"M822.046,1420.92 L844.673,1398.3 L867.301,1420.92 L844.673,1443.55 L822.046,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1420.92 L844.673,1398.3 L867.301,1420.92 L844.673,1443.55 L822.046,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:60\\\">\\n\",\n              \"<path d=\\\"M754.164,1398.3 L776.791,1375.67 L799.419,1398.3 L776.791,1420.92 L754.164,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,1398.3 L776.791,1375.67 L799.419,1398.3 L776.791,1420.92 L754.164,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:60\\\">\\n\",\n              \"<path d=\\\"M799.419,1353.04 L822.046,1330.41 L844.673,1353.04 L822.046,1375.67 L799.419,1353.04\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1353.04 L822.046,1330.41 L844.673,1353.04 L822.046,1375.67 L799.419,1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:61\\\">\\n\",\n              \"<path d=\\\"M938.705,1398.3 L961.332,1375.67 L983.96,1398.3 L961.332,1420.92 L938.705,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,1398.3 L961.332,1375.67 L983.96,1398.3 L961.332,1420.92 L938.705,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:1\\\">\\n\",\n              \"<path d=\\\"M200.541,106.51 L223.168,83.8822 L223.168,129.137 L200.541,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,106.51 L223.168,83.8822 L223.168,129.137 L200.541,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:1\\\">\\n\",\n              \"<path d=\\\"M313.678,38.6274 L336.305,61.2548 L313.678,83.8822 L313.678,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,38.6274 L336.305,61.2548 L313.678,83.8822 L313.678,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:2\\\">\\n\",\n              \"<path d=\\\"M385.082,106.51 L407.709,83.8822 L407.709,129.137 L385.082,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,106.51 L407.709,83.8822 L407.709,129.137 L385.082,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:2\\\">\\n\",\n              \"<path d=\\\"M498.219,38.6274 L520.846,61.2548 L498.219,83.8822 L498.219,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,38.6274 L520.846,61.2548 L498.219,83.8822 L498.219,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:4\\\">\\n\",\n              \"<path d=\\\"M776.791,38.6274 L799.419,61.2548 L776.791,83.8822 L776.791,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,38.6274 L799.419,61.2548 L776.791,83.8822 L776.791,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:4\\\">\\n\",\n              \"<path d=\\\"M799.419,106.51 L822.046,129.137 L776.791,129.137 L799.419,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,106.51 L822.046,129.137 L776.791,129.137 L799.419,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:4\\\">\\n\",\n              \"<path d=\\\"M844.673,106.51 L867.301,83.8822 L867.301,129.137 L844.673,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,106.51 L867.301,83.8822 L867.301,129.137 L844.673,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:6\\\">\\n\",\n              \"<path d=\\\"M1168.5,16 L1191.13,38.6274 L1145.87,38.6274 L1168.5,16\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,16 L1191.13,38.6274 L1145.87,38.6274 L1168.5,16\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1236.38,38.6274 L1259.01,61.2548 L1236.38,83.8822 L1236.38,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,38.6274 L1259.01,61.2548 L1236.38,83.8822 L1236.38,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1123.25,106.51 L1145.87,83.8822 L1145.87,129.137 L1123.25,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,106.51 L1145.87,83.8822 L1145.87,129.137 L1123.25,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:6\\\">\\n\",\n              \"<path d=\\\"M1191.13,129.137 L1236.38,129.137 L1213.76,151.764 L1191.13,129.137\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,129.137 L1236.38,129.137 L1213.76,151.764 L1191.13,129.137\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:7\\\">\\n\",\n              \"<path d=\\\"M1353.04,16 L1375.67,38.6274 L1330.41,38.6274 L1353.04,16\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip32\\\"><path d=\\\"M1353.04,16 L1375.67,38.6274 L1330.41,38.6274 L1353.04,16\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip32)\\\" cx=\\\"1330.41\\\" cy=\\\"38.6274\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip32)\\\" cx=\\\"1353.04\\\" cy=\\\"16\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip32)\\\" cx=\\\"1375.67\\\" cy=\\\"38.6274\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,16 L1375.67,38.6274 L1330.41,38.6274 L1353.04,16\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:7\\\">\\n\",\n              \"<path d=\\\"M1420.92,38.6274 L1443.55,61.2548 L1420.92,83.8822 L1420.92,38.6274\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,38.6274 L1443.55,61.2548 L1420.92,83.8822 L1420.92,38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:7\\\">\\n\",\n              \"<path d=\\\"M1307.79,106.51 L1330.41,83.8822 L1330.41,129.137 L1307.79,106.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,106.51 L1330.41,83.8822 L1330.41,129.137 L1307.79,106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:7\\\">\\n\",\n              \"<path d=\\\"M1375.67,129.137 L1420.92,129.137 L1398.3,151.764 L1375.67,129.137\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip33\\\"><path d=\\\"M1375.67,129.137 L1420.92,129.137 L1398.3,151.764 L1375.67,129.137\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip33)\\\" cx=\\\"1375.67\\\" cy=\\\"129.137\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip33)\\\" cx=\\\"1420.92\\\" cy=\\\"129.137\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip33)\\\" cx=\\\"1398.3\\\" cy=\\\"151.764\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,129.137 L1420.92,129.137 L1398.3,151.764 L1375.67,129.137\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:8\\\">\\n\",\n              \"<path d=\\\"M61.2548,200.541 L83.8822,223.168 L38.6274,223.168 L61.2548,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip34\\\"><path d=\\\"M61.2548,200.541 L83.8822,223.168 L38.6274,223.168 L61.2548,200.541\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip34)\\\" cx=\\\"38.6274\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip34)\\\" cx=\\\"61.2548\\\" cy=\\\"200.541\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip34)\\\" cx=\\\"83.8822\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,200.541 L83.8822,223.168 L38.6274,223.168 L61.2548,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:8\\\">\\n\",\n              \"<path d=\\\"M129.137,223.168 L151.764,245.796 L129.137,268.423 L129.137,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,223.168 L151.764,245.796 L129.137,268.423 L129.137,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:8\\\">\\n\",\n              \"<path d=\\\"M16,291.051 L38.6274,268.423 L38.6274,313.678 L16,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,291.051 L38.6274,268.423 L38.6274,313.678 L16,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:8\\\">\\n\",\n              \"<path d=\\\"M83.8822,313.678 L129.137,313.678 L106.51,336.305 L83.8822,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip35\\\"><path d=\\\"M83.8822,313.678 L129.137,313.678 L106.51,336.305 L83.8822,313.678\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip35)\\\" cx=\\\"83.8822\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip35)\\\" cx=\\\"129.137\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip35)\\\" cx=\\\"106.51\\\" cy=\\\"336.305\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,313.678 L129.137,313.678 L106.51,336.305 L83.8822,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:9\\\">\\n\",\n              \"<path d=\\\"M245.796,200.541 L268.423,223.168 L223.168,223.168 L245.796,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,200.541 L268.423,223.168 L223.168,223.168 L245.796,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:9\\\">\\n\",\n              \"<path d=\\\"M313.678,223.168 L336.305,245.796 L313.678,268.423 L313.678,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,223.168 L336.305,245.796 L313.678,268.423 L313.678,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:9\\\">\\n\",\n              \"<path d=\\\"M200.541,291.051 L223.168,268.423 L223.168,313.678 L200.541,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,291.051 L223.168,268.423 L223.168,313.678 L200.541,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:9\\\">\\n\",\n              \"<path d=\\\"M268.423,313.678 L313.678,313.678 L291.051,336.305 L268.423,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,313.678 L313.678,313.678 L291.051,336.305 L268.423,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:11\\\">\\n\",\n              \"<path d=\\\"M592.25,223.168 L614.878,245.796 L592.25,268.423 L592.25,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,223.168 L614.878,245.796 L592.25,268.423 L592.25,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:11\\\">\\n\",\n              \"<path d=\\\"M637.505,223.168 L682.76,223.168 L660.133,245.796 L637.505,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,223.168 L682.76,223.168 L660.133,245.796 L637.505,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:11\\\">\\n\",\n              \"<path d=\\\"M614.878,291.051 L637.505,313.678 L592.25,313.678 L614.878,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,291.051 L637.505,313.678 L592.25,313.678 L614.878,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:11\\\">\\n\",\n              \"<path d=\\\"M660.133,291.051 L682.76,268.423 L682.76,313.678 L660.133,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,291.051 L682.76,268.423 L682.76,313.678 L660.133,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:13\\\">\\n\",\n              \"<path d=\\\"M983.96,200.541 L1006.59,223.168 L961.332,223.168 L983.96,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,200.541 L1006.59,223.168 L961.332,223.168 L983.96,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:13\\\">\\n\",\n              \"<path d=\\\"M1051.84,223.168 L1074.47,245.796 L1051.84,268.423 L1051.84,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,223.168 L1074.47,245.796 L1051.84,268.423 L1051.84,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:13\\\">\\n\",\n              \"<path d=\\\"M938.705,291.051 L961.332,268.423 L961.332,313.678 L938.705,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,291.051 L961.332,268.423 L961.332,313.678 L938.705,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:13\\\">\\n\",\n              \"<path d=\\\"M1006.59,313.678 L1051.84,313.678 L1029.21,336.305 L1006.59,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,313.678 L1051.84,313.678 L1029.21,336.305 L1006.59,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:14\\\">\\n\",\n              \"<path d=\\\"M1168.5,200.541 L1191.13,223.168 L1145.87,223.168 L1168.5,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip36\\\"><path d=\\\"M1168.5,200.541 L1191.13,223.168 L1145.87,223.168 L1168.5,200.541\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip36)\\\" cx=\\\"1145.87\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip36)\\\" cx=\\\"1168.5\\\" cy=\\\"200.541\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip36)\\\" cx=\\\"1191.13\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,200.541 L1191.13,223.168 L1145.87,223.168 L1168.5,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:14\\\">\\n\",\n              \"<path d=\\\"M1236.38,223.168 L1259.01,245.796 L1236.38,268.423 L1236.38,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,223.168 L1259.01,245.796 L1236.38,268.423 L1236.38,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:14\\\">\\n\",\n              \"<path d=\\\"M1123.25,291.051 L1145.87,268.423 L1145.87,313.678 L1123.25,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,291.051 L1145.87,268.423 L1145.87,313.678 L1123.25,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:14\\\">\\n\",\n              \"<path d=\\\"M1191.13,313.678 L1236.38,313.678 L1213.76,336.305 L1191.13,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip37\\\"><path d=\\\"M1191.13,313.678 L1236.38,313.678 L1213.76,336.305 L1191.13,313.678\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip37)\\\" cx=\\\"1191.13\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip37)\\\" cx=\\\"1236.38\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip37)\\\" cx=\\\"1213.76\\\" cy=\\\"336.305\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,313.678 L1236.38,313.678 L1213.76,336.305 L1191.13,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:15\\\">\\n\",\n              \"<path d=\\\"M1353.04,200.541 L1375.67,223.168 L1330.41,223.168 L1353.04,200.541\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip38\\\"><path d=\\\"M1353.04,200.541 L1375.67,223.168 L1330.41,223.168 L1353.04,200.541\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip38)\\\" cx=\\\"1330.41\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip38)\\\" cx=\\\"1353.04\\\" cy=\\\"200.541\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip38)\\\" cx=\\\"1375.67\\\" cy=\\\"223.168\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,200.541 L1375.67,223.168 L1330.41,223.168 L1353.04,200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:15\\\">\\n\",\n              \"<path d=\\\"M1420.92,223.168 L1443.55,245.796 L1420.92,268.423 L1420.92,223.168\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,223.168 L1443.55,245.796 L1420.92,268.423 L1420.92,223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:15\\\">\\n\",\n              \"<path d=\\\"M1307.79,291.051 L1330.41,268.423 L1330.41,313.678 L1307.79,291.051\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,291.051 L1330.41,268.423 L1330.41,313.678 L1307.79,291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:15\\\">\\n\",\n              \"<path d=\\\"M1375.67,313.678 L1420.92,313.678 L1398.3,336.305 L1375.67,313.678\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip39\\\"><path d=\\\"M1375.67,313.678 L1420.92,313.678 L1398.3,336.305 L1375.67,313.678\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip39)\\\" cx=\\\"1375.67\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip39)\\\" cx=\\\"1420.92\\\" cy=\\\"313.678\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip39)\\\" cx=\\\"1398.3\\\" cy=\\\"336.305\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,313.678 L1420.92,313.678 L1398.3,336.305 L1375.67,313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:16\\\">\\n\",\n              \"<path d=\\\"M61.2548,385.082 L83.8822,407.709 L38.6274,407.709 L61.2548,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,385.082 L83.8822,407.709 L38.6274,407.709 L61.2548,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:16\\\">\\n\",\n              \"<path d=\\\"M129.137,407.709 L151.764,430.337 L129.137,452.964 L129.137,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,407.709 L151.764,430.337 L129.137,452.964 L129.137,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:16\\\">\\n\",\n              \"<path d=\\\"M16,475.592 L38.6274,452.964 L38.6274,498.219 L16,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,475.592 L38.6274,452.964 L38.6274,498.219 L16,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:16\\\">\\n\",\n              \"<path d=\\\"M83.8822,498.219 L129.137,498.219 L106.51,520.846 L83.8822,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,498.219 L129.137,498.219 L106.51,520.846 L83.8822,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:18\\\">\\n\",\n              \"<path d=\\\"M407.709,407.709 L430.337,430.337 L407.709,452.964 L407.709,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,407.709 L430.337,430.337 L407.709,452.964 L407.709,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:18\\\">\\n\",\n              \"<path d=\\\"M452.964,407.709 L498.219,407.709 L475.592,430.337 L452.964,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,407.709 L498.219,407.709 L475.592,430.337 L452.964,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:18\\\">\\n\",\n              \"<path d=\\\"M430.337,475.592 L452.964,498.219 L407.709,498.219 L430.337,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,475.592 L452.964,498.219 L407.709,498.219 L430.337,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:18\\\">\\n\",\n              \"<path d=\\\"M475.592,475.592 L498.219,452.964 L498.219,498.219 L475.592,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,475.592 L498.219,452.964 L498.219,498.219 L475.592,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:20\\\">\\n\",\n              \"<path d=\\\"M799.419,385.082 L822.046,407.709 L776.791,407.709 L799.419,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,385.082 L822.046,407.709 L776.791,407.709 L799.419,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:20\\\">\\n\",\n              \"<path d=\\\"M867.301,407.709 L889.928,430.337 L867.301,452.964 L867.301,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,407.709 L889.928,430.337 L867.301,452.964 L867.301,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:20\\\">\\n\",\n              \"<path d=\\\"M754.164,475.592 L776.791,452.964 L776.791,498.219 L754.164,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,475.592 L776.791,452.964 L776.791,498.219 L754.164,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:20\\\">\\n\",\n              \"<path d=\\\"M822.046,498.219 L867.301,498.219 L844.673,520.846 L822.046,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,498.219 L867.301,498.219 L844.673,520.846 L822.046,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:21\\\">\\n\",\n              \"<path d=\\\"M983.96,385.082 L1006.59,407.709 L961.332,407.709 L983.96,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip40\\\"><path d=\\\"M983.96,385.082 L1006.59,407.709 L961.332,407.709 L983.96,385.082\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip40)\\\" cx=\\\"961.332\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip40)\\\" cx=\\\"983.96\\\" cy=\\\"385.082\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip40)\\\" cx=\\\"1006.59\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M983.96,385.082 L1006.59,407.709 L961.332,407.709 L983.96,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:21\\\">\\n\",\n              \"<path d=\\\"M1051.84,407.709 L1074.47,430.337 L1051.84,452.964 L1051.84,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,407.709 L1074.47,430.337 L1051.84,452.964 L1051.84,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:21\\\">\\n\",\n              \"<path d=\\\"M938.705,475.592 L961.332,452.964 L961.332,498.219 L938.705,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,475.592 L961.332,452.964 L961.332,498.219 L938.705,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:21\\\">\\n\",\n              \"<path d=\\\"M1006.59,498.219 L1051.84,498.219 L1029.21,520.846 L1006.59,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip41\\\"><path d=\\\"M1006.59,498.219 L1051.84,498.219 L1029.21,520.846 L1006.59,498.219\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip41)\\\" cx=\\\"1006.59\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip41)\\\" cx=\\\"1051.84\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip41)\\\" cx=\\\"1029.21\\\" cy=\\\"520.846\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,498.219 L1051.84,498.219 L1029.21,520.846 L1006.59,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:22\\\">\\n\",\n              \"<path d=\\\"M1168.5,385.082 L1191.13,407.709 L1145.87,407.709 L1168.5,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip42\\\"><path d=\\\"M1168.5,385.082 L1191.13,407.709 L1145.87,407.709 L1168.5,385.082\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip42)\\\" cx=\\\"1145.87\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip42)\\\" cx=\\\"1168.5\\\" cy=\\\"385.082\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip42)\\\" cx=\\\"1191.13\\\" cy=\\\"407.709\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,385.082 L1191.13,407.709 L1145.87,407.709 L1168.5,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:22\\\">\\n\",\n              \"<path d=\\\"M1236.38,407.709 L1259.01,430.337 L1236.38,452.964 L1236.38,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,407.709 L1259.01,430.337 L1236.38,452.964 L1236.38,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:22\\\">\\n\",\n              \"<path d=\\\"M1123.25,475.592 L1145.87,452.964 L1145.87,498.219 L1123.25,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,475.592 L1145.87,452.964 L1145.87,498.219 L1123.25,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:22\\\">\\n\",\n              \"<path d=\\\"M1191.13,498.219 L1236.38,498.219 L1213.76,520.846 L1191.13,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip43\\\"><path d=\\\"M1191.13,498.219 L1236.38,498.219 L1213.76,520.846 L1191.13,498.219\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip43)\\\" cx=\\\"1191.13\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip43)\\\" cx=\\\"1236.38\\\" cy=\\\"498.219\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip43)\\\" cx=\\\"1213.76\\\" cy=\\\"520.846\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,498.219 L1236.38,498.219 L1213.76,520.846 L1191.13,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:23\\\">\\n\",\n              \"<path d=\\\"M1353.04,385.082 L1375.67,407.709 L1330.41,407.709 L1353.04,385.082\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,385.082 L1375.67,407.709 L1330.41,407.709 L1353.04,385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:23\\\">\\n\",\n              \"<path d=\\\"M1420.92,407.709 L1443.55,430.337 L1420.92,452.964 L1420.92,407.709\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,407.709 L1443.55,430.337 L1420.92,452.964 L1420.92,407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:23\\\">\\n\",\n              \"<path d=\\\"M1307.79,475.592 L1330.41,452.964 L1330.41,498.219 L1307.79,475.592\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,475.592 L1330.41,452.964 L1330.41,498.219 L1307.79,475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:23\\\">\\n\",\n              \"<path d=\\\"M1375.67,498.219 L1420.92,498.219 L1398.3,520.846 L1375.67,498.219\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,498.219 L1420.92,498.219 L1398.3,520.846 L1375.67,498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:25\\\">\\n\",\n              \"<path d=\\\"M223.168,592.25 L245.796,614.878 L223.168,637.505 L223.168,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,592.25 L245.796,614.878 L223.168,637.505 L223.168,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:25\\\">\\n\",\n              \"<path d=\\\"M268.423,592.25 L313.678,592.25 L291.051,614.878 L268.423,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,592.25 L313.678,592.25 L291.051,614.878 L268.423,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:25\\\">\\n\",\n              \"<path d=\\\"M245.796,660.133 L268.423,682.76 L223.168,682.76 L245.796,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,660.133 L268.423,682.76 L223.168,682.76 L245.796,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:25\\\">\\n\",\n              \"<path d=\\\"M291.051,660.133 L313.678,637.505 L313.678,682.76 L291.051,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,660.133 L313.678,637.505 L313.678,682.76 L291.051,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:27\\\">\\n\",\n              \"<path d=\\\"M614.878,569.623 L637.505,592.25 L592.25,592.25 L614.878,569.623\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,569.623 L637.505,592.25 L592.25,592.25 L614.878,569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:27\\\">\\n\",\n              \"<path d=\\\"M682.76,592.25 L705.387,614.878 L682.76,637.505 L682.76,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,592.25 L705.387,614.878 L682.76,637.505 L682.76,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:27\\\">\\n\",\n              \"<path d=\\\"M569.623,660.133 L592.25,637.505 L592.25,682.76 L569.623,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,660.133 L592.25,637.505 L592.25,682.76 L569.623,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:27\\\">\\n\",\n              \"<path d=\\\"M637.505,682.76 L682.76,682.76 L660.133,705.387 L637.505,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,682.76 L682.76,682.76 L660.133,705.387 L637.505,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:28\\\">\\n\",\n              \"<path d=\\\"M799.419,569.623 L822.046,592.25 L776.791,592.25 L799.419,569.623\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip44\\\"><path d=\\\"M799.419,569.623 L822.046,592.25 L776.791,592.25 L799.419,569.623\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip44)\\\" cx=\\\"776.791\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip44)\\\" cx=\\\"799.419\\\" cy=\\\"569.623\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip44)\\\" cx=\\\"822.046\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M799.419,569.623 L822.046,592.25 L776.791,592.25 L799.419,569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:28\\\">\\n\",\n              \"<path d=\\\"M867.301,592.25 L889.928,614.878 L867.301,637.505 L867.301,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,592.25 L889.928,614.878 L867.301,637.505 L867.301,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:28\\\">\\n\",\n              \"<path d=\\\"M754.164,660.133 L776.791,637.505 L776.791,682.76 L754.164,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,660.133 L776.791,637.505 L776.791,682.76 L754.164,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:28\\\">\\n\",\n              \"<path d=\\\"M822.046,682.76 L867.301,682.76 L844.673,705.387 L822.046,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip45\\\"><path d=\\\"M822.046,682.76 L867.301,682.76 L844.673,705.387 L822.046,682.76\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip45)\\\" cx=\\\"822.046\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip45)\\\" cx=\\\"867.301\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip45)\\\" cx=\\\"844.673\\\" cy=\\\"705.387\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M822.046,682.76 L867.301,682.76 L844.673,705.387 L822.046,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:29\\\">\\n\",\n              \"<path d=\\\"M983.96,569.623 L1006.59,592.25 L961.332,592.25 L983.96,569.623\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip46\\\"><path d=\\\"M983.96,569.623 L1006.59,592.25 L961.332,592.25 L983.96,569.623\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip46)\\\" cx=\\\"961.332\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip46)\\\" cx=\\\"983.96\\\" cy=\\\"569.623\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip46)\\\" cx=\\\"1006.59\\\" cy=\\\"592.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M983.96,569.623 L1006.59,592.25 L961.332,592.25 L983.96,569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:29\\\">\\n\",\n              \"<path d=\\\"M1051.84,592.25 L1074.47,614.878 L1051.84,637.505 L1051.84,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,592.25 L1074.47,614.878 L1051.84,637.505 L1051.84,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:29\\\">\\n\",\n              \"<path d=\\\"M938.705,660.133 L961.332,637.505 L961.332,682.76 L938.705,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,660.133 L961.332,637.505 L961.332,682.76 L938.705,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:29\\\">\\n\",\n              \"<path d=\\\"M1006.59,682.76 L1051.84,682.76 L1029.21,705.387 L1006.59,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip47\\\"><path d=\\\"M1006.59,682.76 L1051.84,682.76 L1029.21,705.387 L1006.59,682.76\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip47)\\\" cx=\\\"1006.59\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip47)\\\" cx=\\\"1051.84\\\" cy=\\\"682.76\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip47)\\\" cx=\\\"1029.21\\\" cy=\\\"705.387\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,682.76 L1051.84,682.76 L1029.21,705.387 L1006.59,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:30\\\">\\n\",\n              \"<path d=\\\"M1168.5,569.623 L1191.13,592.25 L1145.87,592.25 L1168.5,569.623\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,569.623 L1191.13,592.25 L1145.87,592.25 L1168.5,569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:30\\\">\\n\",\n              \"<path d=\\\"M1236.38,592.25 L1259.01,614.878 L1236.38,637.505 L1236.38,592.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,592.25 L1259.01,614.878 L1236.38,637.505 L1236.38,592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:30\\\">\\n\",\n              \"<path d=\\\"M1123.25,660.133 L1145.87,637.505 L1145.87,682.76 L1123.25,660.133\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,660.133 L1145.87,637.505 L1145.87,682.76 L1123.25,660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:30\\\">\\n\",\n              \"<path d=\\\"M1191.13,682.76 L1236.38,682.76 L1213.76,705.387 L1191.13,682.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,682.76 L1236.38,682.76 L1213.76,705.387 L1191.13,682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:32\\\">\\n\",\n              \"<path d=\\\"M38.6274,776.791 L61.2548,799.419 L38.6274,822.046 L38.6274,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,776.791 L61.2548,799.419 L38.6274,822.046 L38.6274,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:32\\\">\\n\",\n              \"<path d=\\\"M83.8822,776.791 L129.137,776.791 L106.51,799.419 L83.8822,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,776.791 L129.137,776.791 L106.51,799.419 L83.8822,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:32\\\">\\n\",\n              \"<path d=\\\"M61.2548,844.673 L83.8822,867.301 L38.6274,867.301 L61.2548,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,844.673 L83.8822,867.301 L38.6274,867.301 L61.2548,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:32\\\">\\n\",\n              \"<path d=\\\"M106.51,844.673 L129.137,822.046 L129.137,867.301 L106.51,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,844.673 L129.137,822.046 L129.137,867.301 L106.51,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:34\\\">\\n\",\n              \"<path d=\\\"M430.337,754.164 L452.964,776.791 L407.709,776.791 L430.337,754.164\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,754.164 L452.964,776.791 L407.709,776.791 L430.337,754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:34\\\">\\n\",\n              \"<path d=\\\"M498.219,776.791 L520.846,799.419 L498.219,822.046 L498.219,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,776.791 L520.846,799.419 L498.219,822.046 L498.219,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:34\\\">\\n\",\n              \"<path d=\\\"M385.082,844.673 L407.709,822.046 L407.709,867.301 L385.082,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,844.673 L407.709,822.046 L407.709,867.301 L385.082,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:34\\\">\\n\",\n              \"<path d=\\\"M452.964,867.301 L498.219,867.301 L475.592,889.928 L452.964,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,867.301 L498.219,867.301 L475.592,889.928 L452.964,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:35\\\">\\n\",\n              \"<path d=\\\"M614.878,754.164 L637.505,776.791 L592.25,776.791 L614.878,754.164\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip48\\\"><path d=\\\"M614.878,754.164 L637.505,776.791 L592.25,776.791 L614.878,754.164\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip48)\\\" cx=\\\"592.25\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip48)\\\" cx=\\\"614.878\\\" cy=\\\"754.164\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip48)\\\" cx=\\\"637.505\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M614.878,754.164 L637.505,776.791 L592.25,776.791 L614.878,754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:35\\\">\\n\",\n              \"<path d=\\\"M682.76,776.791 L705.387,799.419 L682.76,822.046 L682.76,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,776.791 L705.387,799.419 L682.76,822.046 L682.76,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:35\\\">\\n\",\n              \"<path d=\\\"M569.623,844.673 L592.25,822.046 L592.25,867.301 L569.623,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,844.673 L592.25,822.046 L592.25,867.301 L569.623,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:35\\\">\\n\",\n              \"<path d=\\\"M637.505,867.301 L682.76,867.301 L660.133,889.928 L637.505,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip49\\\"><path d=\\\"M637.505,867.301 L682.76,867.301 L660.133,889.928 L637.505,867.301\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip49)\\\" cx=\\\"637.505\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip49)\\\" cx=\\\"682.76\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip49)\\\" cx=\\\"660.133\\\" cy=\\\"889.928\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M637.505,867.301 L682.76,867.301 L660.133,889.928 L637.505,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:36\\\">\\n\",\n              \"<path d=\\\"M799.419,754.164 L822.046,776.791 L776.791,776.791 L799.419,754.164\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip50\\\"><path d=\\\"M799.419,754.164 L822.046,776.791 L776.791,776.791 L799.419,754.164\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip50)\\\" cx=\\\"776.791\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip50)\\\" cx=\\\"799.419\\\" cy=\\\"754.164\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip50)\\\" cx=\\\"822.046\\\" cy=\\\"776.791\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M799.419,754.164 L822.046,776.791 L776.791,776.791 L799.419,754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:36\\\">\\n\",\n              \"<path d=\\\"M867.301,776.791 L889.928,799.419 L867.301,822.046 L867.301,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,776.791 L889.928,799.419 L867.301,822.046 L867.301,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:36\\\">\\n\",\n              \"<path d=\\\"M754.164,844.673 L776.791,822.046 L776.791,867.301 L754.164,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,844.673 L776.791,822.046 L776.791,867.301 L754.164,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:36\\\">\\n\",\n              \"<path d=\\\"M822.046,867.301 L867.301,867.301 L844.673,889.928 L822.046,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip51\\\"><path d=\\\"M822.046,867.301 L867.301,867.301 L844.673,889.928 L822.046,867.301\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip51)\\\" cx=\\\"822.046\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip51)\\\" cx=\\\"867.301\\\" cy=\\\"867.301\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip51)\\\" cx=\\\"844.673\\\" cy=\\\"889.928\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M822.046,867.301 L867.301,867.301 L844.673,889.928 L822.046,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:37\\\">\\n\",\n              \"<path d=\\\"M983.96,754.164 L1006.59,776.791 L961.332,776.791 L983.96,754.164\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,754.164 L1006.59,776.791 L961.332,776.791 L983.96,754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:37\\\">\\n\",\n              \"<path d=\\\"M1051.84,776.791 L1074.47,799.419 L1051.84,822.046 L1051.84,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,776.791 L1074.47,799.419 L1051.84,822.046 L1051.84,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:37\\\">\\n\",\n              \"<path d=\\\"M938.705,844.673 L961.332,822.046 L961.332,867.301 L938.705,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,844.673 L961.332,822.046 L961.332,867.301 L938.705,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:37\\\">\\n\",\n              \"<path d=\\\"M1006.59,867.301 L1051.84,867.301 L1029.21,889.928 L1006.59,867.301\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,867.301 L1051.84,867.301 L1029.21,889.928 L1006.59,867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:39\\\">\\n\",\n              \"<path d=\\\"M1330.41,776.791 L1353.04,799.419 L1330.41,822.046 L1330.41,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,776.791 L1353.04,799.419 L1330.41,822.046 L1330.41,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:39\\\">\\n\",\n              \"<path d=\\\"M1375.67,776.791 L1420.92,776.791 L1398.3,799.419 L1375.67,776.791\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,776.791 L1420.92,776.791 L1398.3,799.419 L1375.67,776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:39\\\">\\n\",\n              \"<path d=\\\"M1353.04,844.673 L1375.67,867.301 L1330.41,867.301 L1353.04,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,844.673 L1375.67,867.301 L1330.41,867.301 L1353.04,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:39\\\">\\n\",\n              \"<path d=\\\"M1398.3,844.673 L1420.92,822.046 L1420.92,867.301 L1398.3,844.673\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,844.673 L1420.92,822.046 L1420.92,867.301 L1398.3,844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:41\\\">\\n\",\n              \"<path d=\\\"M245.796,938.705 L268.423,961.332 L223.168,961.332 L245.796,938.705\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,938.705 L268.423,961.332 L223.168,961.332 L245.796,938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:41\\\">\\n\",\n              \"<path d=\\\"M313.678,961.332 L336.305,983.96 L313.678,1006.59 L313.678,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,961.332 L336.305,983.96 L313.678,1006.59 L313.678,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:41\\\">\\n\",\n              \"<path d=\\\"M200.541,1029.21 L223.168,1006.59 L223.168,1051.84 L200.541,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,1029.21 L223.168,1006.59 L223.168,1051.84 L200.541,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:41\\\">\\n\",\n              \"<path d=\\\"M268.423,1051.84 L313.678,1051.84 L291.051,1074.47 L268.423,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1051.84 L313.678,1051.84 L291.051,1074.47 L268.423,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:42\\\">\\n\",\n              \"<path d=\\\"M430.337,938.705 L452.964,961.332 L407.709,961.332 L430.337,938.705\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip52\\\"><path d=\\\"M430.337,938.705 L452.964,961.332 L407.709,961.332 L430.337,938.705\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip52)\\\" cx=\\\"407.709\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip52)\\\" cx=\\\"430.337\\\" cy=\\\"938.705\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip52)\\\" cx=\\\"452.964\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M430.337,938.705 L452.964,961.332 L407.709,961.332 L430.337,938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:42\\\">\\n\",\n              \"<path d=\\\"M498.219,961.332 L520.846,983.96 L498.219,1006.59 L498.219,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,961.332 L520.846,983.96 L498.219,1006.59 L498.219,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:42\\\">\\n\",\n              \"<path d=\\\"M385.082,1029.21 L407.709,1006.59 L407.709,1051.84 L385.082,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,1029.21 L407.709,1006.59 L407.709,1051.84 L385.082,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:42\\\">\\n\",\n              \"<path d=\\\"M452.964,1051.84 L498.219,1051.84 L475.592,1074.47 L452.964,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip53\\\"><path d=\\\"M452.964,1051.84 L498.219,1051.84 L475.592,1074.47 L452.964,1051.84\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip53)\\\" cx=\\\"452.964\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip53)\\\" cx=\\\"498.219\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip53)\\\" cx=\\\"475.592\\\" cy=\\\"1074.47\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1051.84 L498.219,1051.84 L475.592,1074.47 L452.964,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:43\\\">\\n\",\n              \"<path d=\\\"M614.878,938.705 L637.505,961.332 L592.25,961.332 L614.878,938.705\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip54\\\"><path d=\\\"M614.878,938.705 L637.505,961.332 L592.25,961.332 L614.878,938.705\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip54)\\\" cx=\\\"592.25\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip54)\\\" cx=\\\"614.878\\\" cy=\\\"938.705\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip54)\\\" cx=\\\"637.505\\\" cy=\\\"961.332\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M614.878,938.705 L637.505,961.332 L592.25,961.332 L614.878,938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:43\\\">\\n\",\n              \"<path d=\\\"M682.76,961.332 L705.387,983.96 L682.76,1006.59 L682.76,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,961.332 L705.387,983.96 L682.76,1006.59 L682.76,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:43\\\">\\n\",\n              \"<path d=\\\"M569.623,1029.21 L592.25,1006.59 L592.25,1051.84 L569.623,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,1029.21 L592.25,1006.59 L592.25,1051.84 L569.623,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:43\\\">\\n\",\n              \"<path d=\\\"M637.505,1051.84 L682.76,1051.84 L660.133,1074.47 L637.505,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip55\\\"><path d=\\\"M637.505,1051.84 L682.76,1051.84 L660.133,1074.47 L637.505,1051.84\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip55)\\\" cx=\\\"637.505\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip55)\\\" cx=\\\"682.76\\\" cy=\\\"1051.84\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip55)\\\" cx=\\\"660.133\\\" cy=\\\"1074.47\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1051.84 L682.76,1051.84 L660.133,1074.47 L637.505,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:44\\\">\\n\",\n              \"<path d=\\\"M799.419,938.705 L822.046,961.332 L776.791,961.332 L799.419,938.705\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,938.705 L822.046,961.332 L776.791,961.332 L799.419,938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:44\\\">\\n\",\n              \"<path d=\\\"M867.301,961.332 L889.928,983.96 L867.301,1006.59 L867.301,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,961.332 L889.928,983.96 L867.301,1006.59 L867.301,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:44\\\">\\n\",\n              \"<path d=\\\"M754.164,1029.21 L776.791,1006.59 L776.791,1051.84 L754.164,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,1029.21 L776.791,1006.59 L776.791,1051.84 L754.164,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:44\\\">\\n\",\n              \"<path d=\\\"M822.046,1051.84 L867.301,1051.84 L844.673,1074.47 L822.046,1051.84\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1051.84 L867.301,1051.84 L844.673,1074.47 L822.046,1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:46\\\">\\n\",\n              \"<path d=\\\"M1145.87,961.332 L1168.5,983.96 L1145.87,1006.59 L1145.87,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,961.332 L1168.5,983.96 L1145.87,1006.59 L1145.87,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:46\\\">\\n\",\n              \"<path d=\\\"M1191.13,961.332 L1236.38,961.332 L1213.76,983.96 L1191.13,961.332\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,961.332 L1236.38,961.332 L1213.76,983.96 L1191.13,961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:46\\\">\\n\",\n              \"<path d=\\\"M1168.5,1029.21 L1191.13,1051.84 L1145.87,1051.84 L1168.5,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,1029.21 L1191.13,1051.84 L1145.87,1051.84 L1168.5,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:46\\\">\\n\",\n              \"<path d=\\\"M1213.76,1029.21 L1236.38,1006.59 L1236.38,1051.84 L1213.76,1029.21\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,1029.21 L1236.38,1006.59 L1236.38,1051.84 L1213.76,1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:48\\\">\\n\",\n              \"<path d=\\\"M61.2548,1123.25 L83.8822,1145.87 L38.6274,1145.87 L61.2548,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,1123.25 L83.8822,1145.87 L38.6274,1145.87 L61.2548,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:48\\\">\\n\",\n              \"<path d=\\\"M129.137,1145.87 L151.764,1168.5 L129.137,1191.13 L129.137,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,1145.87 L151.764,1168.5 L129.137,1191.13 L129.137,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:48\\\">\\n\",\n              \"<path d=\\\"M16,1213.76 L38.6274,1191.13 L38.6274,1236.38 L16,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,1213.76 L38.6274,1191.13 L38.6274,1236.38 L16,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:48\\\">\\n\",\n              \"<path d=\\\"M83.8822,1236.38 L129.137,1236.38 L106.51,1259.01 L83.8822,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1236.38 L129.137,1236.38 L106.51,1259.01 L83.8822,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:49\\\">\\n\",\n              \"<path d=\\\"M245.796,1123.25 L268.423,1145.87 L223.168,1145.87 L245.796,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip56\\\"><path d=\\\"M245.796,1123.25 L268.423,1145.87 L223.168,1145.87 L245.796,1123.25\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip56)\\\" cx=\\\"223.168\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip56)\\\" cx=\\\"245.796\\\" cy=\\\"1123.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip56)\\\" cx=\\\"268.423\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M245.796,1123.25 L268.423,1145.87 L223.168,1145.87 L245.796,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:49\\\">\\n\",\n              \"<path d=\\\"M313.678,1145.87 L336.305,1168.5 L313.678,1191.13 L313.678,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,1145.87 L336.305,1168.5 L313.678,1191.13 L313.678,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:49\\\">\\n\",\n              \"<path d=\\\"M200.541,1213.76 L223.168,1191.13 L223.168,1236.38 L200.541,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,1213.76 L223.168,1191.13 L223.168,1236.38 L200.541,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:49\\\">\\n\",\n              \"<path d=\\\"M268.423,1236.38 L313.678,1236.38 L291.051,1259.01 L268.423,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip57\\\"><path d=\\\"M268.423,1236.38 L313.678,1236.38 L291.051,1259.01 L268.423,1236.38\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip57)\\\" cx=\\\"268.423\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip57)\\\" cx=\\\"313.678\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip57)\\\" cx=\\\"291.051\\\" cy=\\\"1259.01\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1236.38 L313.678,1236.38 L291.051,1259.01 L268.423,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:50\\\">\\n\",\n              \"<path d=\\\"M430.337,1123.25 L452.964,1145.87 L407.709,1145.87 L430.337,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip58\\\"><path d=\\\"M430.337,1123.25 L452.964,1145.87 L407.709,1145.87 L430.337,1123.25\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip58)\\\" cx=\\\"407.709\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip58)\\\" cx=\\\"430.337\\\" cy=\\\"1123.25\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip58)\\\" cx=\\\"452.964\\\" cy=\\\"1145.87\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M430.337,1123.25 L452.964,1145.87 L407.709,1145.87 L430.337,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:50\\\">\\n\",\n              \"<path d=\\\"M498.219,1145.87 L520.846,1168.5 L498.219,1191.13 L498.219,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,1145.87 L520.846,1168.5 L498.219,1191.13 L498.219,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:50\\\">\\n\",\n              \"<path d=\\\"M385.082,1213.76 L407.709,1191.13 L407.709,1236.38 L385.082,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,1213.76 L407.709,1191.13 L407.709,1236.38 L385.082,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:50\\\">\\n\",\n              \"<path d=\\\"M452.964,1236.38 L498.219,1236.38 L475.592,1259.01 L452.964,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip59\\\"><path d=\\\"M452.964,1236.38 L498.219,1236.38 L475.592,1259.01 L452.964,1236.38\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip59)\\\" cx=\\\"452.964\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip59)\\\" cx=\\\"498.219\\\" cy=\\\"1236.38\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip59)\\\" cx=\\\"475.592\\\" cy=\\\"1259.01\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1236.38 L498.219,1236.38 L475.592,1259.01 L452.964,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:51\\\">\\n\",\n              \"<path d=\\\"M614.878,1123.25 L637.505,1145.87 L592.25,1145.87 L614.878,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,1123.25 L637.505,1145.87 L592.25,1145.87 L614.878,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:51\\\">\\n\",\n              \"<path d=\\\"M682.76,1145.87 L705.387,1168.5 L682.76,1191.13 L682.76,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,1145.87 L705.387,1168.5 L682.76,1191.13 L682.76,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:51\\\">\\n\",\n              \"<path d=\\\"M569.623,1213.76 L592.25,1191.13 L592.25,1236.38 L569.623,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,1213.76 L592.25,1191.13 L592.25,1236.38 L569.623,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:51\\\">\\n\",\n              \"<path d=\\\"M637.505,1236.38 L682.76,1236.38 L660.133,1259.01 L637.505,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,1236.38 L682.76,1236.38 L660.133,1259.01 L637.505,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:53\\\">\\n\",\n              \"<path d=\\\"M961.332,1145.87 L983.96,1168.5 L961.332,1191.13 L961.332,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1145.87 L983.96,1168.5 L961.332,1191.13 L961.332,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:53\\\">\\n\",\n              \"<path d=\\\"M1006.59,1145.87 L1051.84,1145.87 L1029.21,1168.5 L1006.59,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1145.87 L1051.84,1145.87 L1029.21,1168.5 L1006.59,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:53\\\">\\n\",\n              \"<path d=\\\"M983.96,1213.76 L1006.59,1236.38 L961.332,1236.38 L983.96,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1213.76 L1006.59,1236.38 L961.332,1236.38 L983.96,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:53\\\">\\n\",\n              \"<path d=\\\"M1029.21,1213.76 L1051.84,1191.13 L1051.84,1236.38 L1029.21,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,1213.76 L1051.84,1191.13 L1051.84,1236.38 L1029.21,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:55\\\">\\n\",\n              \"<path d=\\\"M1353.04,1123.25 L1375.67,1145.87 L1330.41,1145.87 L1353.04,1123.25\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,1123.25 L1375.67,1145.87 L1330.41,1145.87 L1353.04,1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:55\\\">\\n\",\n              \"<path d=\\\"M1420.92,1145.87 L1443.55,1168.5 L1420.92,1191.13 L1420.92,1145.87\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,1145.87 L1443.55,1168.5 L1420.92,1191.13 L1420.92,1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:55\\\">\\n\",\n              \"<path d=\\\"M1307.79,1213.76 L1330.41,1191.13 L1330.41,1236.38 L1307.79,1213.76\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,1213.76 L1330.41,1191.13 L1330.41,1236.38 L1307.79,1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:55\\\">\\n\",\n              \"<path d=\\\"M1375.67,1236.38 L1420.92,1236.38 L1398.3,1259.01 L1375.67,1236.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1236.38 L1420.92,1236.38 L1398.3,1259.01 L1375.67,1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:56\\\">\\n\",\n              \"<path d=\\\"M61.2548,1307.79 L83.8822,1330.41 L38.6274,1330.41 L61.2548,1307.79\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip60\\\"><path d=\\\"M61.2548,1307.79 L83.8822,1330.41 L38.6274,1330.41 L61.2548,1307.79\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip60)\\\" cx=\\\"38.6274\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip60)\\\" cx=\\\"61.2548\\\" cy=\\\"1307.79\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip60)\\\" cx=\\\"83.8822\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,1307.79 L83.8822,1330.41 L38.6274,1330.41 L61.2548,1307.79\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:56\\\">\\n\",\n              \"<path d=\\\"M129.137,1330.41 L151.764,1353.04 L129.137,1375.67 L129.137,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,1330.41 L151.764,1353.04 L129.137,1375.67 L129.137,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:56\\\">\\n\",\n              \"<path d=\\\"M16,1398.3 L38.6274,1375.67 L38.6274,1420.92 L16,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,1398.3 L38.6274,1375.67 L38.6274,1420.92 L16,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:56\\\">\\n\",\n              \"<path d=\\\"M83.8822,1420.92 L129.137,1420.92 L106.51,1443.55 L83.8822,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip61\\\"><path d=\\\"M83.8822,1420.92 L129.137,1420.92 L106.51,1443.55 L83.8822,1420.92\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip61)\\\" cx=\\\"83.8822\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip61)\\\" cx=\\\"129.137\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip61)\\\" cx=\\\"106.51\\\" cy=\\\"1443.55\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1420.92 L129.137,1420.92 L106.51,1443.55 L83.8822,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:57\\\">\\n\",\n              \"<path d=\\\"M245.796,1307.79 L268.423,1330.41 L223.168,1330.41 L245.796,1307.79\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip62\\\"><path d=\\\"M245.796,1307.79 L268.423,1330.41 L223.168,1330.41 L245.796,1307.79\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip62)\\\" cx=\\\"223.168\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip62)\\\" cx=\\\"245.796\\\" cy=\\\"1307.79\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip62)\\\" cx=\\\"268.423\\\" cy=\\\"1330.41\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M245.796,1307.79 L268.423,1330.41 L223.168,1330.41 L245.796,1307.79\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:57\\\">\\n\",\n              \"<path d=\\\"M313.678,1330.41 L336.305,1353.04 L313.678,1375.67 L313.678,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,1330.41 L336.305,1353.04 L313.678,1375.67 L313.678,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:57\\\">\\n\",\n              \"<path d=\\\"M200.541,1398.3 L223.168,1375.67 L223.168,1420.92 L200.541,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,1398.3 L223.168,1375.67 L223.168,1420.92 L200.541,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:57\\\">\\n\",\n              \"<path d=\\\"M268.423,1420.92 L313.678,1420.92 L291.051,1443.55 L268.423,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip63\\\"><path d=\\\"M268.423,1420.92 L313.678,1420.92 L291.051,1443.55 L268.423,1420.92\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip63)\\\" cx=\\\"268.423\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip63)\\\" cx=\\\"313.678\\\" cy=\\\"1420.92\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip63)\\\" cx=\\\"291.051\\\" cy=\\\"1443.55\\\" r=\\\"20\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M268.423,1420.92 L313.678,1420.92 L291.051,1443.55 L268.423,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:58\\\">\\n\",\n              \"<path d=\\\"M430.337,1307.79 L452.964,1330.41 L407.709,1330.41 L430.337,1307.79\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,1307.79 L452.964,1330.41 L407.709,1330.41 L430.337,1307.79\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:58\\\">\\n\",\n              \"<path d=\\\"M498.219,1330.41 L520.846,1353.04 L498.219,1375.67 L498.219,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,1330.41 L520.846,1353.04 L498.219,1375.67 L498.219,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:58\\\">\\n\",\n              \"<path d=\\\"M385.082,1398.3 L407.709,1375.67 L407.709,1420.92 L385.082,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,1398.3 L407.709,1375.67 L407.709,1420.92 L385.082,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:58\\\">\\n\",\n              \"<path d=\\\"M452.964,1420.92 L498.219,1420.92 L475.592,1443.55 L452.964,1420.92\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,1420.92 L498.219,1420.92 L475.592,1443.55 L452.964,1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:60\\\">\\n\",\n              \"<path d=\\\"M776.791,1330.41 L799.419,1353.04 L776.791,1375.67 L776.791,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1330.41 L799.419,1353.04 L776.791,1375.67 L776.791,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:60\\\">\\n\",\n              \"<path d=\\\"M822.046,1330.41 L867.301,1330.41 L844.673,1353.04 L822.046,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,1330.41 L867.301,1330.41 L844.673,1353.04 L822.046,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:60\\\">\\n\",\n              \"<path d=\\\"M844.673,1398.3 L867.301,1375.67 L867.301,1420.92 L844.673,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1398.3 L867.301,1375.67 L867.301,1420.92 L844.673,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:62\\\">\\n\",\n              \"<path d=\\\"M1123.25,1398.3 L1145.87,1375.67 L1145.87,1420.92 L1123.25,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,1398.3 L1145.87,1375.67 L1145.87,1420.92 L1123.25,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:62\\\">\\n\",\n              \"<path d=\\\"M1236.38,1330.41 L1259.01,1353.04 L1236.38,1375.67 L1236.38,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,1330.41 L1259.01,1353.04 L1236.38,1375.67 L1236.38,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:63\\\">\\n\",\n              \"<path d=\\\"M1307.79,1398.3 L1330.41,1375.67 L1330.41,1420.92 L1307.79,1398.3\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,1398.3 L1330.41,1375.67 L1330.41,1420.92 L1307.79,1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:63\\\">\\n\",\n              \"<path d=\\\"M1420.92,1330.41 L1443.55,1353.04 L1420.92,1375.67 L1420.92,1330.41\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,1330.41 L1443.55,1353.04 L1420.92,1375.67 L1420.92,1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:3\\\">\\n\",\n              \"<path d=\\\"M592.25,83.8822 C580.937 86.145, 571.886 95.1959, 569.623 106.51 C580.937 104.247, 589.988 95.196, 592.25 83.8822\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,83.8822 C580.937 86.145, 571.886 95.1959, 569.623 106.51 C580.937 104.247, 589.988 95.196, 592.25 83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:3\\\">\\n\",\n              \"<path d=\\\"M614.878,16 C617.14 27.3137, 626.191 36.3647, 637.505 38.6274 C635.242 27.3137, 626.191 18.2627, 614.878 16\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,16 C617.14 27.3137, 626.191 36.3647, 637.505 38.6274 C635.242 27.3137, 626.191 18.2627, 614.878 16\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:3\\\">\\n\",\n              \"<path d=\\\"M614.878,61.2548 C617.14 72.5686, 626.191 81.6195, 637.505 83.8822 C635.242 72.5685, 626.191 63.5176, 614.878 61.2548\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,61.2548 C617.14 72.5686, 626.191 81.6195, 637.505 83.8822 C635.242 72.5685, 626.191 63.5176, 614.878 61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:3\\\">\\n\",\n              \"<path d=\\\"M660.133,61.2548 C662.395 72.5686, 671.446 81.6195, 682.76 83.8822 C680.497 72.5685, 671.446 63.5176, 660.133 61.2548\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M660.133,61.2548 C662.395 72.5686, 671.446 81.6195, 682.76 83.8822 C680.497 72.5685, 671.446 63.5176, 660.133 61.2548\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:3\\\">\\n\",\n              \"<path d=\\\"M569.623,106.51 C571.886 117.823, 580.937 126.874, 592.25 129.137 C589.988 117.823, 580.937 108.772, 569.623 106.51\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,106.51 C571.886 117.823, 580.937 126.874, 592.25 129.137 C589.988 117.823, 580.937 108.772, 569.623 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:3\\\">\\n\",\n              \"<path d=\\\"M614.878,106.51 C617.14 117.823, 626.191 126.874, 637.505 129.137 C635.242 117.823, 626.191 108.772, 614.878 106.51\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M614.878,106.51 C617.14 117.823, 626.191 126.874, 637.505 129.137 C635.242 117.823, 626.191 108.772, 614.878 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:3\\\">\\n\",\n              \"<path d=\\\"M660.133,106.51 C662.395 117.823, 671.446 126.874, 682.76 129.137 C680.497 117.823, 671.446 108.772, 660.133 106.51\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,106.51 C662.395 117.823, 671.446 126.874, 682.76 129.137 C680.497 117.823, 671.446 108.772, 660.133 106.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:5\\\">\\n\",\n              \"<path d=\\\"M961.332,38.6274 C963.595 49.9411, 972.646 58.9921, 983.96 61.2548 C981.697 49.9411, 972.646 40.8902, 961.332 38.6274\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,38.6274 C963.595 49.9411, 972.646 58.9921, 983.96 61.2548 C981.697 49.9411, 972.646 40.8902, 961.332 38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:5\\\">\\n\",\n              \"<path d=\\\"M1006.59,83.8822 C1008.85 95.196, 1017.9 104.247, 1029.21 106.51 C1026.95 95.1959, 1017.9 86.145, 1006.59 83.8822\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,83.8822 C1008.85 95.196, 1017.9 104.247, 1029.21 106.51 C1026.95 95.1959, 1017.9 86.145, 1006.59 83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:5\\\">\\n\",\n              \"<path d=\\\"M1051.84,38.6274 C1054.1 49.9411, 1063.16 58.9921, 1074.47 61.2548 C1072.21 49.9411, 1063.16 40.8902, 1051.84 38.6274\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,38.6274 C1054.1 49.9411, 1063.16 58.9921, 1074.47 61.2548 C1072.21 49.9411, 1063.16 40.8902, 1051.84 38.6274\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:5\\\">\\n\",\n              \"<path d=\\\"M1051.84,83.8822 C1063.16 81.6195, 1072.21 72.5686, 1074.47 61.2548 C1063.16 63.5176, 1054.1 72.5685, 1051.84 83.8822\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,83.8822 C1063.16 81.6195, 1072.21 72.5686, 1074.47 61.2548 C1063.16 63.5176, 1054.1 72.5685, 1051.84 83.8822\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:5\\\">\\n\",\n              \"<path d=\\\"M1051.84,129.137 C1040.53 131.4, 1031.48 140.451, 1029.21 151.764 C1040.53 149.502, 1049.58 140.451, 1051.84 129.137\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,129.137 C1040.53 131.4, 1031.48 140.451, 1029.21 151.764 C1040.53 149.502, 1049.58 140.451, 1051.84 129.137\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:10\\\">\\n\",\n              \"<path d=\\\"M407.709,223.168 C419.023 220.906, 428.074 211.855, 430.337 200.541 C419.023 202.804, 409.972 211.855, 407.709 223.168\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,223.168 C419.023 220.906, 428.074 211.855, 430.337 200.541 C419.023 202.804, 409.972 211.855, 407.709 223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:10\\\">\\n\",\n              \"<path d=\\\"M407.709,268.423 C396.396 270.686, 387.345 279.737, 385.082 291.051 C396.396 288.788, 405.447 279.737, 407.709 268.423\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,268.423 C396.396 270.686, 387.345 279.737, 385.082 291.051 C396.396 288.788, 405.447 279.737, 407.709 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:10\\\">\\n\",\n              \"<path d=\\\"M430.337,200.541 C432.599 211.855, 441.65 220.906, 452.964 223.168 C450.701 211.855, 441.65 202.804, 430.337 200.541\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,200.541 C432.599 211.855, 441.65 220.906, 452.964 223.168 C450.701 211.855, 441.65 202.804, 430.337 200.541\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:10\\\">\\n\",\n              \"<path d=\\\"M430.337,245.796 C432.599 257.109, 441.65 266.16, 452.964 268.423 C450.701 257.109, 441.65 248.059, 430.337 245.796\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M430.337,245.796 C432.599 257.109, 441.65 266.16, 452.964 268.423 C450.701 257.109, 441.65 248.059, 430.337 245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:10\\\">\\n\",\n              \"<path d=\\\"M475.592,245.796 C477.854 257.109, 486.905 266.16, 498.219 268.423 C495.956 257.109, 486.905 248.059, 475.592 245.796\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M475.592,245.796 C477.854 257.109, 486.905 266.16, 498.219 268.423 C495.956 257.109, 486.905 248.059, 475.592 245.796\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:10\\\">\\n\",\n              \"<path d=\\\"M385.082,291.051 C387.345 302.364, 396.396 311.415, 407.709 313.678 C405.447 302.364, 396.396 293.313, 385.082 291.051\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M385.082,291.051 C387.345 302.364, 396.396 311.415, 407.709 313.678 C405.447 302.364, 396.396 293.313, 385.082 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:10\\\">\\n\",\n              \"<path d=\\\"M430.337,291.051 C432.599 302.364, 441.65 311.415, 452.964 313.678 C450.701 302.364, 441.65 293.313, 430.337 291.051\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M430.337,291.051 C432.599 302.364, 441.65 311.415, 452.964 313.678 C450.701 302.364, 441.65 293.313, 430.337 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:10\\\">\\n\",\n              \"<path d=\\\"M475.592,291.051 C477.854 302.364, 486.905 311.415, 498.219 313.678 C495.956 302.364, 486.905 293.313, 475.592 291.051\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M475.592,291.051 C477.854 302.364, 486.905 311.415, 498.219 313.678 C495.956 302.364, 486.905 293.313, 475.592 291.051\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:12\\\">\\n\",\n              \"<path d=\\\"M776.791,223.168 C779.054 234.482, 788.105 243.533, 799.419 245.796 C797.156 234.482, 788.105 225.431, 776.791 223.168\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,223.168 C779.054 234.482, 788.105 243.533, 799.419 245.796 C797.156 234.482, 788.105 225.431, 776.791 223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:12\\\">\\n\",\n              \"<path d=\\\"M822.046,223.168 C824.309 234.482, 833.36 243.533, 844.673 245.796 C842.411 234.482, 833.36 225.431, 822.046 223.168\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,223.168 C824.309 234.482, 833.36 243.533, 844.673 245.796 C842.411 234.482, 833.36 225.431, 822.046 223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:12\\\">\\n\",\n              \"<path d=\\\"M867.301,223.168 C869.564 234.482, 878.615 243.533, 889.928 245.796 C887.666 234.482, 878.615 225.431, 867.301 223.168\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,223.168 C869.564 234.482, 878.615 243.533, 889.928 245.796 C887.666 234.482, 878.615 225.431, 867.301 223.168\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:12\\\">\\n\",\n              \"<path d=\\\"M776.791,268.423 C779.054 279.737, 788.105 288.788, 799.419 291.051 C797.156 279.737, 788.105 270.686, 776.791 268.423\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,268.423 C779.054 279.737, 788.105 288.788, 799.419 291.051 C797.156 279.737, 788.105 270.686, 776.791 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:12\\\">\\n\",\n              \"<path d=\\\"M822.046,268.423 C824.309 279.737, 833.36 288.788, 844.673 291.051 C842.411 279.737, 833.36 270.686, 822.046 268.423\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M822.046,268.423 C824.309 279.737, 833.36 288.788, 844.673 291.051 C842.411 279.737, 833.36 270.686, 822.046 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:12\\\">\\n\",\n              \"<path d=\\\"M822.046,313.678 C824.309 324.992, 833.36 334.043, 844.673 336.305 C842.411 324.992, 833.36 315.941, 822.046 313.678\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M822.046,313.678 C824.309 324.992, 833.36 334.043, 844.673 336.305 C842.411 324.992, 833.36 315.941, 822.046 313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:12\\\">\\n\",\n              \"<path d=\\\"M867.301,268.423 C878.615 266.16, 887.666 257.109, 889.928 245.796 C878.615 248.059, 869.564 257.109, 867.301 268.423\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M867.301,268.423 C878.615 266.16, 887.666 257.109, 889.928 245.796 C878.615 248.059, 869.564 257.109, 867.301 268.423\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:12\\\">\\n\",\n              \"<path d=\\\"M867.301,313.678 C855.987 315.941, 846.936 324.992, 844.673 336.305 C855.987 334.043, 865.038 324.992, 867.301 313.678\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M867.301,313.678 C855.987 315.941, 846.936 324.992, 844.673 336.305 C855.987 334.043, 865.038 324.992, 867.301 313.678\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:17\\\">\\n\",\n              \"<path d=\\\"M223.168,407.709 C234.482 405.447, 243.533 396.396, 245.796 385.082 C234.482 387.345, 225.431 396.396, 223.168 407.709\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,407.709 C234.482 405.447, 243.533 396.396, 245.796 385.082 C234.482 387.345, 225.431 396.396, 223.168 407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:17\\\">\\n\",\n              \"<path d=\\\"M223.168,452.964 C211.855 455.227, 202.804 464.278, 200.541 475.592 C211.855 473.329, 220.906 464.278, 223.168 452.964\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,452.964 C211.855 455.227, 202.804 464.278, 200.541 475.592 C211.855 473.329, 220.906 464.278, 223.168 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:17\\\">\\n\",\n              \"<path d=\\\"M245.796,385.082 C248.059 396.396, 257.109 405.447, 268.423 407.709 C266.16 396.396, 257.109 387.345, 245.796 385.082\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,385.082 C248.059 396.396, 257.109 405.447, 268.423 407.709 C266.16 396.396, 257.109 387.345, 245.796 385.082\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:17\\\">\\n\",\n              \"<path d=\\\"M245.796,430.337 C248.059 441.65, 257.109 450.701, 268.423 452.964 C266.16 441.65, 257.109 432.599, 245.796 430.337\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M245.796,430.337 C248.059 441.65, 257.109 450.701, 268.423 452.964 C266.16 441.65, 257.109 432.599, 245.796 430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:17\\\">\\n\",\n              \"<path d=\\\"M291.051,430.337 C293.313 441.65, 302.364 450.701, 313.678 452.964 C311.415 441.65, 302.364 432.599, 291.051 430.337\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M291.051,430.337 C293.313 441.65, 302.364 450.701, 313.678 452.964 C311.415 441.65, 302.364 432.599, 291.051 430.337\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:17\\\">\\n\",\n              \"<path d=\\\"M200.541,475.592 C202.804 486.905, 211.855 495.956, 223.168 498.219 C220.906 486.905, 211.855 477.854, 200.541 475.592\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M200.541,475.592 C202.804 486.905, 211.855 495.956, 223.168 498.219 C220.906 486.905, 211.855 477.854, 200.541 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:17\\\">\\n\",\n              \"<path d=\\\"M245.796,475.592 C248.059 486.905, 257.109 495.956, 268.423 498.219 C266.16 486.905, 257.109 477.854, 245.796 475.592\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M245.796,475.592 C248.059 486.905, 257.109 495.956, 268.423 498.219 C266.16 486.905, 257.109 477.854, 245.796 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:17\\\">\\n\",\n              \"<path d=\\\"M291.051,475.592 C293.313 486.905, 302.364 495.956, 313.678 498.219 C311.415 486.905, 302.364 477.854, 291.051 475.592\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M291.051,475.592 C293.313 486.905, 302.364 495.956, 313.678 498.219 C311.415 486.905, 302.364 477.854, 291.051 475.592\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:19\\\">\\n\",\n              \"<path d=\\\"M592.25,407.709 C594.513 419.023, 603.564 428.074, 614.878 430.337 C612.615 419.023, 603.564 409.972, 592.25 407.709\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,407.709 C594.513 419.023, 603.564 428.074, 614.878 430.337 C612.615 419.023, 603.564 409.972, 592.25 407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:19\\\">\\n\",\n              \"<path d=\\\"M637.505,407.709 C639.768 419.023, 648.819 428.074, 660.133 430.337 C657.87 419.023, 648.819 409.972, 637.505 407.709\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,407.709 C639.768 419.023, 648.819 428.074, 660.133 430.337 C657.87 419.023, 648.819 409.972, 637.505 407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:19\\\">\\n\",\n              \"<path d=\\\"M682.76,407.709 C685.023 419.023, 694.074 428.074, 705.387 430.337 C703.125 419.023, 694.074 409.972, 682.76 407.709\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,407.709 C685.023 419.023, 694.074 428.074, 705.387 430.337 C703.125 419.023, 694.074 409.972, 682.76 407.709\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:19\\\">\\n\",\n              \"<path d=\\\"M592.25,452.964 C594.513 464.278, 603.564 473.329, 614.878 475.592 C612.615 464.278, 603.564 455.227, 592.25 452.964\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,452.964 C594.513 464.278, 603.564 473.329, 614.878 475.592 C612.615 464.278, 603.564 455.227, 592.25 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:19\\\">\\n\",\n              \"<path d=\\\"M637.505,452.964 C639.768 464.278, 648.819 473.329, 660.133 475.592 C657.87 464.278, 648.819 455.227, 637.505 452.964\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M637.505,452.964 C639.768 464.278, 648.819 473.329, 660.133 475.592 C657.87 464.278, 648.819 455.227, 637.505 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:19\\\">\\n\",\n              \"<path d=\\\"M637.505,498.219 C639.768 509.533, 648.819 518.584, 660.133 520.846 C657.87 509.533, 648.819 500.482, 637.505 498.219\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M637.505,498.219 C639.768 509.533, 648.819 518.584, 660.133 520.846 C657.87 509.533, 648.819 500.482, 637.505 498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:19\\\">\\n\",\n              \"<path d=\\\"M682.76,452.964 C694.074 450.701, 703.125 441.65, 705.387 430.337 C694.074 432.599, 685.023 441.65, 682.76 452.964\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M682.76,452.964 C694.074 450.701, 703.125 441.65, 705.387 430.337 C694.074 432.599, 685.023 441.65, 682.76 452.964\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:19\\\">\\n\",\n              \"<path d=\\\"M682.76,498.219 C671.446 500.482, 662.395 509.533, 660.133 520.846 C671.446 518.584, 680.497 509.533, 682.76 498.219\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M682.76,498.219 C671.446 500.482, 662.395 509.533, 660.133 520.846 C671.446 518.584, 680.497 509.533, 682.76 498.219\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:24\\\">\\n\",\n              \"<path d=\\\"M38.6274,592.25 C49.9411 589.988, 58.9921 580.937, 61.2548 569.623 C49.9411 571.886, 40.8902 580.937, 38.6274 592.25\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,592.25 C49.9411 589.988, 58.9921 580.937, 61.2548 569.623 C49.9411 571.886, 40.8902 580.937, 38.6274 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:24\\\">\\n\",\n              \"<path d=\\\"M38.6274,637.505 C27.3137 639.768, 18.2627 648.819, 16 660.133 C27.3137 657.87, 36.3647 648.819, 38.6274 637.505\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,637.505 C27.3137 639.768, 18.2627 648.819, 16 660.133 C27.3137 657.87, 36.3647 648.819, 38.6274 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:24\\\">\\n\",\n              \"<path d=\\\"M61.2548,569.623 C63.5176 580.937, 72.5685 589.988, 83.8822 592.25 C81.6195 580.937, 72.5686 571.886, 61.2548 569.623\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,569.623 C63.5176 580.937, 72.5685 589.988, 83.8822 592.25 C81.6195 580.937, 72.5686 571.886, 61.2548 569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:24\\\">\\n\",\n              \"<path d=\\\"M61.2548,614.878 C63.5176 626.191, 72.5685 635.242, 83.8822 637.505 C81.6195 626.191, 72.5686 617.14, 61.2548 614.878\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,614.878 C63.5176 626.191, 72.5685 635.242, 83.8822 637.505 C81.6195 626.191, 72.5686 617.14, 61.2548 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:24\\\">\\n\",\n              \"<path d=\\\"M106.51,614.878 C108.772 626.191, 117.823 635.242, 129.137 637.505 C126.874 626.191, 117.823 617.14, 106.51 614.878\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M106.51,614.878 C108.772 626.191, 117.823 635.242, 129.137 637.505 C126.874 626.191, 117.823 617.14, 106.51 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:24\\\">\\n\",\n              \"<path d=\\\"M16,660.133 C18.2627 671.446, 27.3137 680.497, 38.6274 682.76 C36.3647 671.446, 27.3137 662.395, 16 660.133\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M16,660.133 C18.2627 671.446, 27.3137 680.497, 38.6274 682.76 C36.3647 671.446, 27.3137 662.395, 16 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:24\\\">\\n\",\n              \"<path d=\\\"M61.2548,660.133 C63.5176 671.446, 72.5685 680.497, 83.8822 682.76 C81.6195 671.446, 72.5686 662.395, 61.2548 660.133\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M61.2548,660.133 C63.5176 671.446, 72.5685 680.497, 83.8822 682.76 C81.6195 671.446, 72.5686 662.395, 61.2548 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:24\\\">\\n\",\n              \"<path d=\\\"M106.51,660.133 C108.772 671.446, 117.823 680.497, 129.137 682.76 C126.874 671.446, 117.823 662.395, 106.51 660.133\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M106.51,660.133 C108.772 671.446, 117.823 680.497, 129.137 682.76 C126.874 671.446, 117.823 662.395, 106.51 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:26\\\">\\n\",\n              \"<path d=\\\"M407.709,592.25 C409.972 603.564, 419.023 612.615, 430.337 614.878 C428.074 603.564, 419.023 594.513, 407.709 592.25\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M407.709,592.25 C409.972 603.564, 419.023 612.615, 430.337 614.878 C428.074 603.564, 419.023 594.513, 407.709 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:26\\\">\\n\",\n              \"<path d=\\\"M452.964,592.25 C455.227 603.564, 464.278 612.615, 475.592 614.878 C473.329 603.564, 464.278 594.513, 452.964 592.25\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,592.25 C455.227 603.564, 464.278 612.615, 475.592 614.878 C473.329 603.564, 464.278 594.513, 452.964 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:26\\\">\\n\",\n              \"<path d=\\\"M498.219,592.25 C500.482 603.564, 509.533 612.615, 520.846 614.878 C518.584 603.564, 509.533 594.513, 498.219 592.25\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,592.25 C500.482 603.564, 509.533 612.615, 520.846 614.878 C518.584 603.564, 509.533 594.513, 498.219 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:26\\\">\\n\",\n              \"<path d=\\\"M407.709,637.505 C409.972 648.819, 419.023 657.87, 430.337 660.133 C428.074 648.819, 419.023 639.768, 407.709 637.505\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M407.709,637.505 C409.972 648.819, 419.023 657.87, 430.337 660.133 C428.074 648.819, 419.023 639.768, 407.709 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:26\\\">\\n\",\n              \"<path d=\\\"M452.964,637.505 C455.227 648.819, 464.278 657.87, 475.592 660.133 C473.329 648.819, 464.278 639.768, 452.964 637.505\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M452.964,637.505 C455.227 648.819, 464.278 657.87, 475.592 660.133 C473.329 648.819, 464.278 639.768, 452.964 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:26\\\">\\n\",\n              \"<path d=\\\"M452.964,682.76 C455.227 694.074, 464.278 703.125, 475.592 705.387 C473.329 694.074, 464.278 685.023, 452.964 682.76\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M452.964,682.76 C455.227 694.074, 464.278 703.125, 475.592 705.387 C473.329 694.074, 464.278 685.023, 452.964 682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:26\\\">\\n\",\n              \"<path d=\\\"M498.219,637.505 C509.533 635.242, 518.584 626.191, 520.846 614.878 C509.533 617.14, 500.482 626.191, 498.219 637.505\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M498.219,637.505 C509.533 635.242, 518.584 626.191, 520.846 614.878 C509.533 617.14, 500.482 626.191, 498.219 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:26\\\">\\n\",\n              \"<path d=\\\"M498.219,682.76 C486.905 685.023, 477.854 694.074, 475.592 705.387 C486.905 703.125, 495.956 694.074, 498.219 682.76\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M498.219,682.76 C486.905 685.023, 477.854 694.074, 475.592 705.387 C486.905 703.125, 495.956 694.074, 498.219 682.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:31\\\">\\n\",\n              \"<path d=\\\"M1330.41,592.25 C1341.73 589.988, 1350.78 580.937, 1353.04 569.623 C1341.73 571.886, 1332.68 580.937, 1330.41 592.25\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,592.25 C1341.73 589.988, 1350.78 580.937, 1353.04 569.623 C1341.73 571.886, 1332.68 580.937, 1330.41 592.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:31\\\">\\n\",\n              \"<path d=\\\"M1330.41,637.505 C1319.1 639.768, 1310.05 648.819, 1307.79 660.133 C1319.1 657.87, 1328.15 648.819, 1330.41 637.505\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,637.505 C1319.1 639.768, 1310.05 648.819, 1307.79 660.133 C1319.1 657.87, 1328.15 648.819, 1330.41 637.505\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:31\\\">\\n\",\n              \"<path d=\\\"M1353.04,569.623 C1355.3 580.937, 1364.36 589.988, 1375.67 592.25 C1373.41 580.937, 1364.36 571.886, 1353.04 569.623\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,569.623 C1355.3 580.937, 1364.36 589.988, 1375.67 592.25 C1373.41 580.937, 1364.36 571.886, 1353.04 569.623\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:31\\\">\\n\",\n              \"<path d=\\\"M1353.04,614.878 C1355.3 626.191, 1364.36 635.242, 1375.67 637.505 C1373.41 626.191, 1364.36 617.14, 1353.04 614.878\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,614.878 C1355.3 626.191, 1364.36 635.242, 1375.67 637.505 C1373.41 626.191, 1364.36 617.14, 1353.04 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:31\\\">\\n\",\n              \"<path d=\\\"M1398.3,614.878 C1400.56 626.191, 1409.61 635.242, 1420.92 637.505 C1418.66 626.191, 1409.61 617.14, 1398.3 614.878\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,614.878 C1400.56 626.191, 1409.61 635.242, 1420.92 637.505 C1418.66 626.191, 1409.61 617.14, 1398.3 614.878\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:31\\\">\\n\",\n              \"<path d=\\\"M1307.79,660.133 C1310.05 671.446, 1319.1 680.497, 1330.41 682.76 C1328.15 671.446, 1319.1 662.395, 1307.79 660.133\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1307.79,660.133 C1310.05 671.446, 1319.1 680.497, 1330.41 682.76 C1328.15 671.446, 1319.1 662.395, 1307.79 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:31\\\">\\n\",\n              \"<path d=\\\"M1353.04,660.133 C1355.3 671.446, 1364.36 680.497, 1375.67 682.76 C1373.41 671.446, 1364.36 662.395, 1353.04 660.133\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1353.04,660.133 C1355.3 671.446, 1364.36 680.497, 1375.67 682.76 C1373.41 671.446, 1364.36 662.395, 1353.04 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:31\\\">\\n\",\n              \"<path d=\\\"M1398.3,660.133 C1400.56 671.446, 1409.61 680.497, 1420.92 682.76 C1418.66 671.446, 1409.61 662.395, 1398.3 660.133\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1398.3,660.133 C1400.56 671.446, 1409.61 680.497, 1420.92 682.76 C1418.66 671.446, 1409.61 662.395, 1398.3 660.133\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:33\\\">\\n\",\n              \"<path d=\\\"M223.168,776.791 C225.431 788.105, 234.482 797.156, 245.796 799.419 C243.533 788.105, 234.482 779.054, 223.168 776.791\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M223.168,776.791 C225.431 788.105, 234.482 797.156, 245.796 799.419 C243.533 788.105, 234.482 779.054, 223.168 776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:33\\\">\\n\",\n              \"<path d=\\\"M268.423,776.791 C270.686 788.105, 279.737 797.156, 291.051 799.419 C288.788 788.105, 279.737 779.054, 268.423 776.791\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,776.791 C270.686 788.105, 279.737 797.156, 291.051 799.419 C288.788 788.105, 279.737 779.054, 268.423 776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:33\\\">\\n\",\n              \"<path d=\\\"M313.678,776.791 C315.941 788.105, 324.992 797.156, 336.305 799.419 C334.043 788.105, 324.992 779.054, 313.678 776.791\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,776.791 C315.941 788.105, 324.992 797.156, 336.305 799.419 C334.043 788.105, 324.992 779.054, 313.678 776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:33\\\">\\n\",\n              \"<path d=\\\"M223.168,822.046 C225.431 833.36, 234.482 842.411, 245.796 844.673 C243.533 833.36, 234.482 824.309, 223.168 822.046\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M223.168,822.046 C225.431 833.36, 234.482 842.411, 245.796 844.673 C243.533 833.36, 234.482 824.309, 223.168 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:33\\\">\\n\",\n              \"<path d=\\\"M268.423,822.046 C270.686 833.36, 279.737 842.411, 291.051 844.673 C288.788 833.36, 279.737 824.309, 268.423 822.046\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M268.423,822.046 C270.686 833.36, 279.737 842.411, 291.051 844.673 C288.788 833.36, 279.737 824.309, 268.423 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:33\\\">\\n\",\n              \"<path d=\\\"M268.423,867.301 C270.686 878.615, 279.737 887.666, 291.051 889.928 C288.788 878.615, 279.737 869.564, 268.423 867.301\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M268.423,867.301 C270.686 878.615, 279.737 887.666, 291.051 889.928 C288.788 878.615, 279.737 869.564, 268.423 867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:33\\\">\\n\",\n              \"<path d=\\\"M313.678,822.046 C324.992 819.783, 334.043 810.732, 336.305 799.419 C324.992 801.681, 315.941 810.732, 313.678 822.046\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M313.678,822.046 C324.992 819.783, 334.043 810.732, 336.305 799.419 C324.992 801.681, 315.941 810.732, 313.678 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:33\\\">\\n\",\n              \"<path d=\\\"M313.678,867.301 C302.364 869.564, 293.313 878.615, 291.051 889.928 C302.364 887.666, 311.415 878.615, 313.678 867.301\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M313.678,867.301 C302.364 869.564, 293.313 878.615, 291.051 889.928 C302.364 887.666, 311.415 878.615, 313.678 867.301\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:38\\\">\\n\",\n              \"<path d=\\\"M1145.87,776.791 C1157.19 774.529, 1166.24 765.478, 1168.5 754.164 C1157.19 756.427, 1148.14 765.478, 1145.87 776.791\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,776.791 C1157.19 774.529, 1166.24 765.478, 1168.5 754.164 C1157.19 756.427, 1148.14 765.478, 1145.87 776.791\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:38\\\">\\n\",\n              \"<path d=\\\"M1145.87,822.046 C1134.56 824.309, 1125.51 833.36, 1123.25 844.673 C1134.56 842.411, 1143.61 833.36, 1145.87 822.046\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,822.046 C1134.56 824.309, 1125.51 833.36, 1123.25 844.673 C1134.56 842.411, 1143.61 833.36, 1145.87 822.046\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:38\\\">\\n\",\n              \"<path d=\\\"M1168.5,754.164 C1170.76 765.477, 1179.81 774.529, 1191.13 776.791 C1188.87 765.478, 1179.81 756.427, 1168.5 754.164\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,754.164 C1170.76 765.477, 1179.81 774.529, 1191.13 776.791 C1188.87 765.478, 1179.81 756.427, 1168.5 754.164\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:38\\\">\\n\",\n              \"<path d=\\\"M1168.5,799.419 C1170.76 810.732, 1179.81 819.783, 1191.13 822.046 C1188.87 810.732, 1179.81 801.681, 1168.5 799.419\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,799.419 C1170.76 810.732, 1179.81 819.783, 1191.13 822.046 C1188.87 810.732, 1179.81 801.681, 1168.5 799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:38\\\">\\n\",\n              \"<path d=\\\"M1213.76,799.419 C1216.02 810.732, 1225.07 819.783, 1236.38 822.046 C1234.12 810.732, 1225.07 801.681, 1213.76 799.419\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,799.419 C1216.02 810.732, 1225.07 819.783, 1236.38 822.046 C1234.12 810.732, 1225.07 801.681, 1213.76 799.419\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:38\\\">\\n\",\n              \"<path d=\\\"M1123.25,844.673 C1125.51 855.987, 1134.56 865.038, 1145.87 867.301 C1143.61 855.987, 1134.56 846.936, 1123.25 844.673\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1123.25,844.673 C1125.51 855.987, 1134.56 865.038, 1145.87 867.301 C1143.61 855.987, 1134.56 846.936, 1123.25 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:38\\\">\\n\",\n              \"<path d=\\\"M1168.5,844.673 C1170.76 855.987, 1179.81 865.038, 1191.13 867.301 C1188.87 855.987, 1179.81 846.936, 1168.5 844.673\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1168.5,844.673 C1170.76 855.987, 1179.81 865.038, 1191.13 867.301 C1188.87 855.987, 1179.81 846.936, 1168.5 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:38\\\">\\n\",\n              \"<path d=\\\"M1213.76,844.673 C1216.02 855.987, 1225.07 865.038, 1236.38 867.301 C1234.12 855.987, 1225.07 846.936, 1213.76 844.673\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1213.76,844.673 C1216.02 855.987, 1225.07 865.038, 1236.38 867.301 C1234.12 855.987, 1225.07 846.936, 1213.76 844.673\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:40\\\">\\n\",\n              \"<path d=\\\"M38.6274,961.332 C40.8902 972.646, 49.9411 981.697, 61.2548 983.96 C58.9921 972.646, 49.9411 963.595, 38.6274 961.332\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,961.332 C40.8902 972.646, 49.9411 981.697, 61.2548 983.96 C58.9921 972.646, 49.9411 963.595, 38.6274 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:40\\\">\\n\",\n              \"<path d=\\\"M83.8822,961.332 C86.145 972.646, 95.196 981.697, 106.51 983.96 C104.247 972.646, 95.1959 963.595, 83.8822 961.332\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,961.332 C86.145 972.646, 95.196 981.697, 106.51 983.96 C104.247 972.646, 95.1959 963.595, 83.8822 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:40\\\">\\n\",\n              \"<path d=\\\"M129.137,961.332 C131.4 972.646, 140.451 981.697, 151.764 983.96 C149.502 972.646, 140.451 963.595, 129.137 961.332\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,961.332 C131.4 972.646, 140.451 981.697, 151.764 983.96 C149.502 972.646, 140.451 963.595, 129.137 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:40\\\">\\n\",\n              \"<path d=\\\"M38.6274,1006.59 C40.8902 1017.9, 49.9411 1026.95, 61.2548 1029.21 C58.9921 1017.9, 49.9411 1008.85, 38.6274 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M38.6274,1006.59 C40.8902 1017.9, 49.9411 1026.95, 61.2548 1029.21 C58.9921 1017.9, 49.9411 1008.85, 38.6274 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:40\\\">\\n\",\n              \"<path d=\\\"M83.8822,1006.59 C86.145 1017.9, 95.1959 1026.95, 106.51 1029.21 C104.247 1017.9, 95.196 1008.85, 83.8822 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1006.59 C86.145 1017.9, 95.1959 1026.95, 106.51 1029.21 C104.247 1017.9, 95.196 1008.85, 83.8822 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:40\\\">\\n\",\n              \"<path d=\\\"M83.8822,1051.84 C86.145 1063.16, 95.1959 1072.21, 106.51 1074.47 C104.247 1063.16, 95.196 1054.1, 83.8822 1051.84\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M83.8822,1051.84 C86.145 1063.16, 95.1959 1072.21, 106.51 1074.47 C104.247 1063.16, 95.196 1054.1, 83.8822 1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:40\\\">\\n\",\n              \"<path d=\\\"M129.137,1006.59 C140.451 1004.32, 149.502 995.273, 151.764 983.96 C140.451 986.222, 131.4 995.273, 129.137 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M129.137,1006.59 C140.451 1004.32, 149.502 995.273, 151.764 983.96 C140.451 986.222, 131.4 995.273, 129.137 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:40\\\">\\n\",\n              \"<path d=\\\"M129.137,1051.84 C117.823 1054.1, 108.772 1063.16, 106.51 1074.47 C117.823 1072.21, 126.874 1063.16, 129.137 1051.84\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M129.137,1051.84 C117.823 1054.1, 108.772 1063.16, 106.51 1074.47 C117.823 1072.21, 126.874 1063.16, 129.137 1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:45\\\">\\n\",\n              \"<path d=\\\"M961.332,961.332 C972.646 959.069, 981.697 950.018, 983.96 938.705 C972.646 940.968, 963.595 950.019, 961.332 961.332\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,961.332 C972.646 959.069, 981.697 950.018, 983.96 938.705 C972.646 940.968, 963.595 950.019, 961.332 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:45\\\">\\n\",\n              \"<path d=\\\"M961.332,1006.59 C950.018 1008.85, 940.967 1017.9, 938.705 1029.21 C950.018 1026.95, 959.07 1017.9, 961.332 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1006.59 C950.018 1008.85, 940.967 1017.9, 938.705 1029.21 C950.018 1026.95, 959.07 1017.9, 961.332 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:45\\\">\\n\",\n              \"<path d=\\\"M983.96,938.705 C986.222 950.018, 995.273 959.07, 1006.59 961.332 C1004.32 950.018, 995.273 940.967, 983.96 938.705\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,938.705 C986.222 950.018, 995.273 959.07, 1006.59 961.332 C1004.32 950.018, 995.273 940.967, 983.96 938.705\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:45\\\">\\n\",\n              \"<path d=\\\"M983.96,983.96 C986.222 995.273, 995.273 1004.32, 1006.59 1006.59 C1004.32 995.273, 995.273 986.222, 983.96 983.96\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M983.96,983.96 C986.222 995.273, 995.273 1004.32, 1006.59 1006.59 C1004.32 995.273, 995.273 986.222, 983.96 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:45\\\">\\n\",\n              \"<path d=\\\"M1029.21,983.96 C1031.48 995.273, 1040.53 1004.32, 1051.84 1006.59 C1049.58 995.273, 1040.53 986.222, 1029.21 983.96\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,983.96 C1031.48 995.273, 1040.53 1004.32, 1051.84 1006.59 C1049.58 995.273, 1040.53 986.222, 1029.21 983.96\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:45\\\">\\n\",\n              \"<path d=\\\"M938.705,1029.21 C940.968 1040.53, 950.019 1049.58, 961.332 1051.84 C959.069 1040.53, 950.018 1031.48, 938.705 1029.21\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M938.705,1029.21 C940.968 1040.53, 950.019 1049.58, 961.332 1051.84 C959.069 1040.53, 950.018 1031.48, 938.705 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:45\\\">\\n\",\n              \"<path d=\\\"M983.96,1029.21 C986.222 1040.53, 995.273 1049.58, 1006.59 1051.84 C1004.32 1040.53, 995.273 1031.48, 983.96 1029.21\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M983.96,1029.21 C986.222 1040.53, 995.273 1049.58, 1006.59 1051.84 C1004.32 1040.53, 995.273 1031.48, 983.96 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:45\\\">\\n\",\n              \"<path d=\\\"M1029.21,1029.21 C1031.48 1040.53, 1040.53 1049.58, 1051.84 1051.84 C1049.58 1040.53, 1040.53 1031.48, 1029.21 1029.21\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.21,1029.21 C1031.48 1040.53, 1040.53 1049.58, 1051.84 1051.84 C1049.58 1040.53, 1040.53 1031.48, 1029.21 1029.21\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:47\\\">\\n\",\n              \"<path d=\\\"M1330.41,961.332 C1332.68 972.646, 1341.73 981.697, 1353.04 983.96 C1350.78 972.646, 1341.73 963.595, 1330.41 961.332\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,961.332 C1332.68 972.646, 1341.73 981.697, 1353.04 983.96 C1350.78 972.646, 1341.73 963.595, 1330.41 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:47\\\">\\n\",\n              \"<path d=\\\"M1375.67,961.332 C1377.93 972.646, 1386.98 981.697, 1398.3 983.96 C1396.03 972.646, 1386.98 963.595, 1375.67 961.332\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,961.332 C1377.93 972.646, 1386.98 981.697, 1398.3 983.96 C1396.03 972.646, 1386.98 963.595, 1375.67 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:47\\\">\\n\",\n              \"<path d=\\\"M1420.92,961.332 C1423.19 972.646, 1432.24 981.697, 1443.55 983.96 C1441.29 972.646, 1432.24 963.595, 1420.92 961.332\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,961.332 C1423.19 972.646, 1432.24 981.697, 1443.55 983.96 C1441.29 972.646, 1432.24 963.595, 1420.92 961.332\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:47\\\">\\n\",\n              \"<path d=\\\"M1330.41,1006.59 C1332.68 1017.9, 1341.73 1026.95, 1353.04 1029.21 C1350.78 1017.9, 1341.73 1008.85, 1330.41 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1330.41,1006.59 C1332.68 1017.9, 1341.73 1026.95, 1353.04 1029.21 C1350.78 1017.9, 1341.73 1008.85, 1330.41 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:47\\\">\\n\",\n              \"<path d=\\\"M1375.67,1006.59 C1377.93 1017.9, 1386.98 1026.95, 1398.3 1029.21 C1396.03 1017.9, 1386.98 1008.85, 1375.67 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1006.59 C1377.93 1017.9, 1386.98 1026.95, 1398.3 1029.21 C1396.03 1017.9, 1386.98 1008.85, 1375.67 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:47\\\">\\n\",\n              \"<path d=\\\"M1375.67,1051.84 C1377.93 1063.16, 1386.98 1072.21, 1398.3 1074.47 C1396.03 1063.16, 1386.98 1054.1, 1375.67 1051.84\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1375.67,1051.84 C1377.93 1063.16, 1386.98 1072.21, 1398.3 1074.47 C1396.03 1063.16, 1386.98 1054.1, 1375.67 1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:47\\\">\\n\",\n              \"<path d=\\\"M1420.92,1006.59 C1432.24 1004.32, 1441.29 995.273, 1443.55 983.96 C1432.24 986.222, 1423.19 995.273, 1420.92 1006.59\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,1006.59 C1432.24 1004.32, 1441.29 995.273, 1443.55 983.96 C1432.24 986.222, 1423.19 995.273, 1420.92 1006.59\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:47\\\">\\n\",\n              \"<path d=\\\"M1420.92,1051.84 C1409.61 1054.1, 1400.56 1063.16, 1398.3 1074.47 C1409.61 1072.21, 1418.66 1063.16, 1420.92 1051.84\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1420.92,1051.84 C1409.61 1054.1, 1400.56 1063.16, 1398.3 1074.47 C1409.61 1072.21, 1418.66 1063.16, 1420.92 1051.84\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:52\\\">\\n\",\n              \"<path d=\\\"M776.791,1145.87 C788.105 1143.61, 797.156 1134.56, 799.419 1123.25 C788.105 1125.51, 779.054 1134.56, 776.791 1145.87\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1145.87 C788.105 1143.61, 797.156 1134.56, 799.419 1123.25 C788.105 1125.51, 779.054 1134.56, 776.791 1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:52\\\">\\n\",\n              \"<path d=\\\"M776.791,1191.13 C765.478 1193.39, 756.427 1202.44, 754.164 1213.76 C765.478 1211.49, 774.529 1202.44, 776.791 1191.13\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M776.791,1191.13 C765.478 1193.39, 756.427 1202.44, 754.164 1213.76 C765.478 1211.49, 774.529 1202.44, 776.791 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:52\\\">\\n\",\n              \"<path d=\\\"M799.419,1123.25 C801.681 1134.56, 810.732 1143.61, 822.046 1145.87 C819.783 1134.56, 810.732 1125.51, 799.419 1123.25\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1123.25 C801.681 1134.56, 810.732 1143.61, 822.046 1145.87 C819.783 1134.56, 810.732 1125.51, 799.419 1123.25\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:52\\\">\\n\",\n              \"<path d=\\\"M799.419,1168.5 C801.681 1179.81, 810.732 1188.87, 822.046 1191.13 C819.783 1179.81, 810.732 1170.76, 799.419 1168.5\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1168.5 C801.681 1179.81, 810.732 1188.87, 822.046 1191.13 C819.783 1179.81, 810.732 1170.76, 799.419 1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:52\\\">\\n\",\n              \"<path d=\\\"M844.673,1168.5 C846.936 1179.81, 855.987 1188.87, 867.301 1191.13 C865.038 1179.81, 855.987 1170.76, 844.673 1168.5\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1168.5 C846.936 1179.81, 855.987 1188.87, 867.301 1191.13 C865.038 1179.81, 855.987 1170.76, 844.673 1168.5\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:52\\\">\\n\",\n              \"<path d=\\\"M754.164,1213.76 C756.427 1225.07, 765.478 1234.12, 776.791 1236.38 C774.529 1225.07, 765.478 1216.02, 754.164 1213.76\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M754.164,1213.76 C756.427 1225.07, 765.478 1234.12, 776.791 1236.38 C774.529 1225.07, 765.478 1216.02, 754.164 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:52\\\">\\n\",\n              \"<path d=\\\"M799.419,1213.76 C801.681 1225.07, 810.732 1234.12, 822.046 1236.38 C819.783 1225.07, 810.732 1216.02, 799.419 1213.76\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M799.419,1213.76 C801.681 1225.07, 810.732 1234.12, 822.046 1236.38 C819.783 1225.07, 810.732 1216.02, 799.419 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:52\\\">\\n\",\n              \"<path d=\\\"M844.673,1213.76 C846.936 1225.07, 855.987 1234.12, 867.301 1236.38 C865.038 1225.07, 855.987 1216.02, 844.673 1213.76\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M844.673,1213.76 C846.936 1225.07, 855.987 1234.12, 867.301 1236.38 C865.038 1225.07, 855.987 1216.02, 844.673 1213.76\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:54\\\">\\n\",\n              \"<path d=\\\"M1145.87,1145.87 C1148.14 1157.19, 1157.19 1166.24, 1168.5 1168.5 C1166.24 1157.19, 1157.19 1148.14, 1145.87 1145.87\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1145.87 C1148.14 1157.19, 1157.19 1166.24, 1168.5 1168.5 C1166.24 1157.19, 1157.19 1148.14, 1145.87 1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:54\\\">\\n\",\n              \"<path d=\\\"M1191.13,1145.87 C1193.39 1157.19, 1202.44 1166.24, 1213.76 1168.5 C1211.49 1157.19, 1202.44 1148.14, 1191.13 1145.87\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1145.87 C1193.39 1157.19, 1202.44 1166.24, 1213.76 1168.5 C1211.49 1157.19, 1202.44 1148.14, 1191.13 1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:54\\\">\\n\",\n              \"<path d=\\\"M1236.38,1145.87 C1238.65 1157.19, 1247.7 1166.24, 1259.01 1168.5 C1256.75 1157.19, 1247.7 1148.14, 1236.38 1145.87\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,1145.87 C1238.65 1157.19, 1247.7 1166.24, 1259.01 1168.5 C1256.75 1157.19, 1247.7 1148.14, 1236.38 1145.87\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:54\\\">\\n\",\n              \"<path d=\\\"M1145.87,1191.13 C1148.14 1202.44, 1157.19 1211.49, 1168.5 1213.76 C1166.24 1202.44, 1157.19 1193.39, 1145.87 1191.13\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1145.87,1191.13 C1148.14 1202.44, 1157.19 1211.49, 1168.5 1213.76 C1166.24 1202.44, 1157.19 1193.39, 1145.87 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:54\\\">\\n\",\n              \"<path d=\\\"M1191.13,1191.13 C1193.39 1202.44, 1202.44 1211.49, 1213.76 1213.76 C1211.49 1202.44, 1202.44 1193.39, 1191.13 1191.13\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1191.13 C1193.39 1202.44, 1202.44 1211.49, 1213.76 1213.76 C1211.49 1202.44, 1202.44 1193.39, 1191.13 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:54\\\">\\n\",\n              \"<path d=\\\"M1191.13,1236.38 C1193.39 1247.7, 1202.44 1256.75, 1213.76 1259.01 C1211.49 1247.7, 1202.44 1238.65, 1191.13 1236.38\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1191.13,1236.38 C1193.39 1247.7, 1202.44 1256.75, 1213.76 1259.01 C1211.49 1247.7, 1202.44 1238.65, 1191.13 1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:54\\\">\\n\",\n              \"<path d=\\\"M1236.38,1191.13 C1247.7 1188.87, 1256.75 1179.81, 1259.01 1168.5 C1247.7 1170.76, 1238.65 1179.81, 1236.38 1191.13\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,1191.13 C1247.7 1188.87, 1256.75 1179.81, 1259.01 1168.5 C1247.7 1170.76, 1238.65 1179.81, 1236.38 1191.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:54\\\">\\n\",\n              \"<path d=\\\"M1236.38,1236.38 C1225.07 1238.65, 1216.02 1247.7, 1213.76 1259.01 C1225.07 1256.75, 1234.12 1247.7, 1236.38 1236.38\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1236.38,1236.38 C1225.07 1238.65, 1216.02 1247.7, 1213.76 1259.01 C1225.07 1256.75, 1234.12 1247.7, 1236.38 1236.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:59\\\">\\n\",\n              \"<path d=\\\"M592.25,1330.41 C603.564 1328.15, 612.615 1319.1, 614.878 1307.79 C603.564 1310.05, 594.513 1319.1, 592.25 1330.41\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1330.41 C603.564 1328.15, 612.615 1319.1, 614.878 1307.79 C603.564 1310.05, 594.513 1319.1, 592.25 1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:59\\\">\\n\",\n              \"<path d=\\\"M592.25,1375.67 C580.937 1377.93, 571.886 1386.98, 569.623 1398.3 C580.937 1396.03, 589.988 1386.98, 592.25 1375.67\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M592.25,1375.67 C580.937 1377.93, 571.886 1386.98, 569.623 1398.3 C580.937 1396.03, 589.988 1386.98, 592.25 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:59\\\">\\n\",\n              \"<path d=\\\"M569.623,1398.3 C571.886 1409.61, 580.937 1418.66, 592.25 1420.92 C589.988 1409.61, 580.937 1400.56, 569.623 1398.3\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M569.623,1398.3 C571.886 1409.61, 580.937 1418.66, 592.25 1420.92 C589.988 1409.61, 580.937 1400.56, 569.623 1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:59\\\">\\n\",\n              \"<path d=\\\"M614.878,1353.04 C617.14 1364.36, 626.191 1373.41, 637.505 1375.67 C635.242 1364.36, 626.191 1355.3, 614.878 1353.04\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M614.878,1353.04 C617.14 1364.36, 626.191 1373.41, 637.505 1375.67 C635.242 1364.36, 626.191 1355.3, 614.878 1353.04\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:59\\\">\\n\",\n              \"<path d=\\\"M660.133,1398.3 C662.395 1409.61, 671.446 1418.66, 682.76 1420.92 C680.497 1409.61, 671.446 1400.56, 660.133 1398.3\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M660.133,1398.3 C662.395 1409.61, 671.446 1418.66, 682.76 1420.92 C680.497 1409.61, 671.446 1400.56, 660.133 1398.3\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:61\\\">\\n\",\n              \"<path d=\\\"M961.332,1330.41 C963.595 1341.73, 972.646 1350.78, 983.96 1353.04 C981.697 1341.73, 972.646 1332.68, 961.332 1330.41\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1330.41 C963.595 1341.73, 972.646 1350.78, 983.96 1353.04 C981.697 1341.73, 972.646 1332.68, 961.332 1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:61\\\">\\n\",\n              \"<path d=\\\"M1006.59,1330.41 C1008.85 1341.73, 1017.9 1350.78, 1029.21 1353.04 C1026.95 1341.73, 1017.9 1332.68, 1006.59 1330.41\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1330.41 C1008.85 1341.73, 1017.9 1350.78, 1029.21 1353.04 C1026.95 1341.73, 1017.9 1332.68, 1006.59 1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:61\\\">\\n\",\n              \"<path d=\\\"M1051.84,1330.41 C1054.1 1341.73, 1063.16 1350.78, 1074.47 1353.04 C1072.21 1341.73, 1063.16 1332.68, 1051.84 1330.41\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,1330.41 C1054.1 1341.73, 1063.16 1350.78, 1074.47 1353.04 C1072.21 1341.73, 1063.16 1332.68, 1051.84 1330.41\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:61\\\">\\n\",\n              \"<path d=\\\"M961.332,1375.67 C963.595 1386.98, 972.646 1396.03, 983.96 1398.3 C981.697 1386.98, 972.646 1377.93, 961.332 1375.67\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M961.332,1375.67 C963.595 1386.98, 972.646 1396.03, 983.96 1398.3 C981.697 1386.98, 972.646 1377.93, 961.332 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:61\\\">\\n\",\n              \"<path d=\\\"M1006.59,1375.67 C1008.85 1386.98, 1017.9 1396.03, 1029.21 1398.3 C1026.95 1386.98, 1017.9 1377.93, 1006.59 1375.67\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1375.67 C1008.85 1386.98, 1017.9 1396.03, 1029.21 1398.3 C1026.95 1386.98, 1017.9 1377.93, 1006.59 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:61\\\">\\n\",\n              \"<path d=\\\"M1006.59,1420.92 C1008.85 1432.24, 1017.9 1441.29, 1029.21 1443.55 C1026.95 1432.24, 1017.9 1423.19, 1006.59 1420.92\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1006.59,1420.92 C1008.85 1432.24, 1017.9 1441.29, 1029.21 1443.55 C1026.95 1432.24, 1017.9 1423.19, 1006.59 1420.92\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:61\\\">\\n\",\n              \"<path d=\\\"M1051.84,1375.67 C1063.16 1373.41, 1072.21 1364.36, 1074.47 1353.04 C1063.16 1355.3, 1054.1 1364.36, 1051.84 1375.67\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1051.84,1375.67 C1063.16 1373.41, 1072.21 1364.36, 1074.47 1353.04 C1063.16 1355.3, 1054.1 1364.36, 1051.84 1375.67\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:1\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"16\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"16\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:1\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:2\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"16\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"16\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:2\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:3\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:3\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:4\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:4\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:4\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"151.764\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:5\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:6\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:6\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:6\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:6\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:7\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:7\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:7\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"106.51\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:7\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"61.2548\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:8\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:8\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:9\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:9\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:10\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:10\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:11\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:11\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:11\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:11\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:12\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:12\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:13\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:13\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:13\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:13\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:13\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:13\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:13\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:13\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:14\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:14\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:14\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:14\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:14\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:14\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:14\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:14\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:15\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"200.541\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:15\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:15\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:15\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"245.796\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:15\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:15\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:15\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"291.051\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:15\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"336.305\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:16\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:16\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:16\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:16\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:16\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:16\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:16\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:16\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:17\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:17\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:18\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:18\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:18\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:18\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:19\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:19\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:20\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:20\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:20\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:20\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:20\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:20\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:20\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:20\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:21\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:21\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:21\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:21\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:21\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:21\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:21\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:21\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:22\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:22\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:22\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:22\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:22\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:22\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:22\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:22\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:23\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"385.082\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:23\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:23\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:23\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"430.337\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:23\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:23\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:23\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"475.592\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:23\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"520.846\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:24\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:24\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:25\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:25\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:25\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:25\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:26\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:26\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:27\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:27\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:27\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:27\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:27\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:27\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:27\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:27\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:20:2_0_3:28\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:21:2_2_3:28\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:22:4_2_3:28\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:23:6_2_3:28\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:24:0_4_3:28\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:25:2_4_3:28\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:26:4_4_3:28\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:27:4_6_3:28\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:29\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:29\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:29\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:29\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:29\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:29\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:29\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:29\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:30\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"569.623\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:30\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:30\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:30\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:30\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:30\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:30\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"660.133\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:30\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:31\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"614.878\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:31\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"705.387\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:32\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:32\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:32\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:32\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:33\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:33\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:34\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:34\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:34\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:34\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:34\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:34\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:34\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:34\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:28:2_0_4:35\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:29:2_2_4:35\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:30:4_2_4:35\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:31:6_2_4:35\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:32:0_4_4:35\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:33:2_4_4:35\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:34:4_4_4:35\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:35:4_6_4:35\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:36\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:36\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:36\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:36\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:36\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:36\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:36\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:36\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:37\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:37\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:37\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:37\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:37\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:37\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:37\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:37\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:38\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:38\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:39\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"754.164\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:39\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"844.673\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:39\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"799.419\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:39\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"889.928\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:40\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:40\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:41\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:41\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:41\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:41\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:41\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:41\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:41\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:41\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:36:2_0_5:42\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:37:2_2_5:42\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:38:4_2_5:42\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:39:6_2_5:42\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:40:0_4_5:42\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:41:2_4_5:42\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:42:4_4_5:42\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:43:4_6_5:42\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:43\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:43\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:43\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:43\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:43\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:43\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:43\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:43\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:44\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:44\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:44\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:44\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:44\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:44\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:44\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:44\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:45\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:45\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:46\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:46\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:46\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"983.96\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:46\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1074.47\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:47\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"938.705\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:47\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1029.21\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:48\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:48\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:48\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:48\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:48\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:48\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:48\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:48\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:44:2_0_6:49\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:45:2_2_6:49\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:46:4_2_6:49\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:47:6_2_6:49\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:48:0_4_6:49\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:49:2_4_6:49\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:50:4_4_6:49\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:51:4_6_6:49\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:50\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:50\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:50\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:50\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:50\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:50\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:50\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:50\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:51\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:51\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:51\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:51\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:51\\\">\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"569.623\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:51\\\">\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"614.878\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:51\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:51\\\">\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"660.133\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:52\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:52\\\">\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"844.673\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:53\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:53\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:53\\\">\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1074.47\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:53\\\">\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1029.21\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:54\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:54\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:55\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1123.25\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:55\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:55\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:55\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"1168.5\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:55\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:55\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:55\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1213.76\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:55\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1259.01\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:52:2_0_7:56\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:53:2_2_7:56\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:54:4_2_7:56\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:55:6_2_7:56\\\">\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"151.764\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:56:0_4_7:56\\\">\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"16\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:57:2_4_7:56\\\">\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"61.2548\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:58:4_4_7:56\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:59:4_6_7:56\\\">\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"106.51\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:57\\\">\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"200.541\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:57\\\">\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"245.796\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:57\\\">\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"291.051\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:57\\\">\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"336.305\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:68:0_4_9:58\\\">\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"385.082\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:69:2_2_9:58\\\">\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"430.337\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:70:4_4_9:58\\\">\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"475.592\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:58\\\">\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"520.846\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:59\\\">\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"705.387\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:60\\\">\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"799.419\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:60\\\">\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"754.164\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:71:6_2_9:60\\\">\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"889.928\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:61\\\">\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"983.96\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:61\\\">\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"938.705\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:62\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:62\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:62\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:62\\\">\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1259.01\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:62\\\">\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1123.25\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:62\\\">\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1168.5\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:62\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:62\\\">\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1213.76\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:60:2_0_8:63\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1307.79\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:61:2_2_8:63\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:62:4_2_8:63\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:63:6_2_8:63\\\">\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1443.55\\\" cy=\\\"1353.04\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:64:0_4_8:63\\\">\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1307.79\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:65:2_4_8:63\\\">\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1353.04\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:66:4_4_8:63\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1398.3\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:67:4_6_8:63\\\">\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1398.3\\\" cy=\\\"1443.55\\\" r=\\\"6\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<defs>\\n\",\n              \"<radialGradient id=\\\"xgrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#FF4040\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"<radialGradient id=\\\"ygrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#59FF7A\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"<radialGradient id=\\\"zgrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#4DA6FF\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"</defs>\\n\",\n              \"<g id=\\\"qubit_dots\\\">\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"38.6274\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"61.2548\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"83.8822\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"129.137\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"38.6274\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"61.2548\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"83.8822\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"106.51\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"129.137\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"151.764\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"16\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"38.6274\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"61.2548\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"83.8822\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"106.51\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"129.137\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"106.51\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"223.168\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"245.796\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"268.423\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"313.678\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"223.168\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"245.796\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"268.423\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"291.051\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"313.678\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"336.305\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"200.541\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"223.168\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"245.796\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"268.423\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"291.051\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"313.678\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"291.051\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"407.709\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"430.337\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"452.964\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"498.219\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"407.709\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"430.337\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"452.964\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"475.592\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"498.219\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"520.846\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"385.082\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"407.709\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"430.337\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"452.964\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"475.592\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"498.219\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"475.592\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:3\\\" cx=\\\"592.25\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:3\\\" cx=\\\"614.878\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:3\\\" cx=\\\"637.505\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:3\\\" cx=\\\"682.76\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:3\\\" cx=\\\"592.25\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:3\\\" cx=\\\"614.878\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:3\\\" cx=\\\"637.505\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:3\\\" cx=\\\"660.133\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:3\\\" cx=\\\"682.76\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:3\\\" cx=\\\"705.387\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:3\\\" cx=\\\"569.623\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:3\\\" cx=\\\"592.25\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:3\\\" cx=\\\"614.878\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:3\\\" cx=\\\"637.505\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:3\\\" cx=\\\"660.133\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:3\\\" cx=\\\"682.76\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:3\\\" cx=\\\"660.133\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:4\\\" cx=\\\"776.791\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:4\\\" cx=\\\"799.419\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:4\\\" cx=\\\"822.046\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:4\\\" cx=\\\"867.301\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:4\\\" cx=\\\"776.791\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:4\\\" cx=\\\"799.419\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:4\\\" cx=\\\"822.046\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:4\\\" cx=\\\"844.673\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:4\\\" cx=\\\"867.301\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:4\\\" cx=\\\"889.928\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:4\\\" cx=\\\"754.164\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:4\\\" cx=\\\"776.791\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:4\\\" cx=\\\"799.419\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:4\\\" cx=\\\"822.046\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:4\\\" cx=\\\"844.673\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:4\\\" cx=\\\"867.301\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:4\\\" cx=\\\"844.673\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:5\\\" cx=\\\"961.332\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:5\\\" cx=\\\"983.96\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:5\\\" cx=\\\"1006.59\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:5\\\" cx=\\\"1051.84\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:5\\\" cx=\\\"961.332\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:5\\\" cx=\\\"983.96\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:5\\\" cx=\\\"1006.59\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:5\\\" cx=\\\"1029.21\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:5\\\" cx=\\\"1051.84\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:5\\\" cx=\\\"1074.47\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:5\\\" cx=\\\"938.705\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:5\\\" cx=\\\"961.332\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:5\\\" cx=\\\"983.96\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:5\\\" cx=\\\"1006.59\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:5\\\" cx=\\\"1029.21\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:5\\\" cx=\\\"1051.84\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:5\\\" cx=\\\"1029.21\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:6\\\" cx=\\\"1145.87\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:6\\\" cx=\\\"1168.5\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:6\\\" cx=\\\"1191.13\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:6\\\" cx=\\\"1236.38\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:6\\\" cx=\\\"1145.87\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:6\\\" cx=\\\"1168.5\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:6\\\" cx=\\\"1191.13\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:6\\\" cx=\\\"1213.76\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:6\\\" cx=\\\"1236.38\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:6\\\" cx=\\\"1259.01\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:6\\\" cx=\\\"1123.25\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:6\\\" cx=\\\"1145.87\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:6\\\" cx=\\\"1168.5\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:6\\\" cx=\\\"1191.13\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:6\\\" cx=\\\"1213.76\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:6\\\" cx=\\\"1236.38\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:6\\\" cx=\\\"1213.76\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:7\\\" cx=\\\"1330.41\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:7\\\" cx=\\\"1353.04\\\" cy=\\\"16\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:7\\\" cx=\\\"1375.67\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:7\\\" cx=\\\"1420.92\\\" cy=\\\"38.6274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:7\\\" cx=\\\"1330.41\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:7\\\" cx=\\\"1353.04\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:7\\\" cx=\\\"1375.67\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:7\\\" cx=\\\"1398.3\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:7\\\" cx=\\\"1420.92\\\" cy=\\\"83.8822\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:7\\\" cx=\\\"1443.55\\\" cy=\\\"61.2548\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:7\\\" cx=\\\"1307.79\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:7\\\" cx=\\\"1330.41\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:7\\\" cx=\\\"1353.04\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:7\\\" cx=\\\"1375.67\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:7\\\" cx=\\\"1398.3\\\" cy=\\\"106.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:7\\\" cx=\\\"1420.92\\\" cy=\\\"129.137\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:7\\\" cx=\\\"1398.3\\\" cy=\\\"151.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:8\\\" cx=\\\"38.6274\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:8\\\" cx=\\\"61.2548\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:8\\\" cx=\\\"83.8822\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:8\\\" cx=\\\"129.137\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:8\\\" cx=\\\"38.6274\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:8\\\" cx=\\\"61.2548\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:8\\\" cx=\\\"83.8822\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:8\\\" cx=\\\"106.51\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:8\\\" cx=\\\"129.137\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:8\\\" cx=\\\"151.764\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:8\\\" cx=\\\"16\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:8\\\" cx=\\\"38.6274\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:8\\\" cx=\\\"61.2548\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:8\\\" cx=\\\"83.8822\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:8\\\" cx=\\\"106.51\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:8\\\" cx=\\\"129.137\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:8\\\" cx=\\\"106.51\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:9\\\" cx=\\\"223.168\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:9\\\" cx=\\\"245.796\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:9\\\" cx=\\\"268.423\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:9\\\" cx=\\\"313.678\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:9\\\" cx=\\\"223.168\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:9\\\" cx=\\\"245.796\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:9\\\" cx=\\\"268.423\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:9\\\" cx=\\\"291.051\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:9\\\" cx=\\\"313.678\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:9\\\" cx=\\\"336.305\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:9\\\" cx=\\\"200.541\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:9\\\" cx=\\\"223.168\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:9\\\" cx=\\\"245.796\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:9\\\" cx=\\\"268.423\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:9\\\" cx=\\\"291.051\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:9\\\" cx=\\\"313.678\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:9\\\" cx=\\\"291.051\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:10\\\" cx=\\\"407.709\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:10\\\" cx=\\\"430.337\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:10\\\" cx=\\\"452.964\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:10\\\" cx=\\\"498.219\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:10\\\" cx=\\\"407.709\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:10\\\" cx=\\\"430.337\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:10\\\" cx=\\\"452.964\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:10\\\" cx=\\\"475.592\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:10\\\" cx=\\\"498.219\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:10\\\" cx=\\\"520.846\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:10\\\" cx=\\\"385.082\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:10\\\" cx=\\\"407.709\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:10\\\" cx=\\\"430.337\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:10\\\" cx=\\\"452.964\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:10\\\" cx=\\\"475.592\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:10\\\" cx=\\\"498.219\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:10\\\" cx=\\\"475.592\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:11\\\" cx=\\\"592.25\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:11\\\" cx=\\\"614.878\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:11\\\" cx=\\\"637.505\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:11\\\" cx=\\\"682.76\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:11\\\" cx=\\\"592.25\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:11\\\" cx=\\\"614.878\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:11\\\" cx=\\\"637.505\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:11\\\" cx=\\\"660.133\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:11\\\" cx=\\\"682.76\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:11\\\" cx=\\\"705.387\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:11\\\" cx=\\\"569.623\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:11\\\" cx=\\\"592.25\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:11\\\" cx=\\\"614.878\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:11\\\" cx=\\\"637.505\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:11\\\" cx=\\\"660.133\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:11\\\" cx=\\\"682.76\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:11\\\" cx=\\\"660.133\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:12\\\" cx=\\\"776.791\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:12\\\" cx=\\\"799.419\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:12\\\" cx=\\\"822.046\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:12\\\" cx=\\\"867.301\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:12\\\" cx=\\\"776.791\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:12\\\" cx=\\\"799.419\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:12\\\" cx=\\\"822.046\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:12\\\" cx=\\\"844.673\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:12\\\" cx=\\\"867.301\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:12\\\" cx=\\\"889.928\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:12\\\" cx=\\\"754.164\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:12\\\" cx=\\\"776.791\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:12\\\" cx=\\\"799.419\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:12\\\" cx=\\\"822.046\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:12\\\" cx=\\\"844.673\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:12\\\" cx=\\\"867.301\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:12\\\" cx=\\\"844.673\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:13\\\" cx=\\\"961.332\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:13\\\" cx=\\\"983.96\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:13\\\" cx=\\\"1006.59\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:13\\\" cx=\\\"1051.84\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:13\\\" cx=\\\"961.332\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:13\\\" cx=\\\"983.96\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:13\\\" cx=\\\"1006.59\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:13\\\" cx=\\\"1029.21\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:13\\\" cx=\\\"1051.84\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:13\\\" cx=\\\"1074.47\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:13\\\" cx=\\\"938.705\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:13\\\" cx=\\\"961.332\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:13\\\" cx=\\\"983.96\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:13\\\" cx=\\\"1006.59\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:13\\\" cx=\\\"1029.21\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:13\\\" cx=\\\"1051.84\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:13\\\" cx=\\\"1029.21\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:14\\\" cx=\\\"1145.87\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:14\\\" cx=\\\"1168.5\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:14\\\" cx=\\\"1191.13\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:14\\\" cx=\\\"1236.38\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:14\\\" cx=\\\"1145.87\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:14\\\" cx=\\\"1168.5\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:14\\\" cx=\\\"1191.13\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:14\\\" cx=\\\"1213.76\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:14\\\" cx=\\\"1236.38\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:14\\\" cx=\\\"1259.01\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:14\\\" cx=\\\"1123.25\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:14\\\" cx=\\\"1145.87\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:14\\\" cx=\\\"1168.5\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:14\\\" cx=\\\"1191.13\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:14\\\" cx=\\\"1213.76\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:14\\\" cx=\\\"1236.38\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:14\\\" cx=\\\"1213.76\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:15\\\" cx=\\\"1330.41\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:15\\\" cx=\\\"1353.04\\\" cy=\\\"200.541\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:15\\\" cx=\\\"1375.67\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:15\\\" cx=\\\"1420.92\\\" cy=\\\"223.168\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:15\\\" cx=\\\"1330.41\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:15\\\" cx=\\\"1353.04\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:15\\\" cx=\\\"1375.67\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:15\\\" cx=\\\"1398.3\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:15\\\" cx=\\\"1420.92\\\" cy=\\\"268.423\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:15\\\" cx=\\\"1443.55\\\" cy=\\\"245.796\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:15\\\" cx=\\\"1307.79\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:15\\\" cx=\\\"1330.41\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:15\\\" cx=\\\"1353.04\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:15\\\" cx=\\\"1375.67\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:15\\\" cx=\\\"1398.3\\\" cy=\\\"291.051\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:15\\\" cx=\\\"1420.92\\\" cy=\\\"313.678\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:15\\\" cx=\\\"1398.3\\\" cy=\\\"336.305\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:16\\\" cx=\\\"38.6274\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:16\\\" cx=\\\"61.2548\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:16\\\" cx=\\\"83.8822\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:16\\\" cx=\\\"129.137\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:16\\\" cx=\\\"38.6274\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:16\\\" cx=\\\"61.2548\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:16\\\" cx=\\\"83.8822\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:16\\\" cx=\\\"106.51\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:16\\\" cx=\\\"129.137\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:16\\\" cx=\\\"151.764\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:16\\\" cx=\\\"16\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:16\\\" cx=\\\"38.6274\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:16\\\" cx=\\\"61.2548\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:16\\\" cx=\\\"83.8822\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:16\\\" cx=\\\"106.51\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:16\\\" cx=\\\"129.137\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:16\\\" cx=\\\"106.51\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:17\\\" cx=\\\"223.168\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:17\\\" cx=\\\"245.796\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:17\\\" cx=\\\"268.423\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:17\\\" cx=\\\"313.678\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:17\\\" cx=\\\"223.168\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:17\\\" cx=\\\"245.796\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:17\\\" cx=\\\"268.423\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:17\\\" cx=\\\"291.051\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:17\\\" cx=\\\"313.678\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:17\\\" cx=\\\"336.305\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:17\\\" cx=\\\"200.541\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:17\\\" cx=\\\"223.168\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:17\\\" cx=\\\"245.796\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:17\\\" cx=\\\"268.423\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:17\\\" cx=\\\"291.051\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:17\\\" cx=\\\"313.678\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:17\\\" cx=\\\"291.051\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:18\\\" cx=\\\"407.709\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:18\\\" cx=\\\"430.337\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:18\\\" cx=\\\"452.964\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:18\\\" cx=\\\"498.219\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:18\\\" cx=\\\"407.709\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:18\\\" cx=\\\"430.337\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:18\\\" cx=\\\"452.964\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:18\\\" cx=\\\"475.592\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:18\\\" cx=\\\"498.219\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:18\\\" cx=\\\"520.846\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:18\\\" cx=\\\"385.082\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:18\\\" cx=\\\"407.709\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:18\\\" cx=\\\"430.337\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:18\\\" cx=\\\"452.964\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:18\\\" cx=\\\"475.592\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:18\\\" cx=\\\"498.219\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:18\\\" cx=\\\"475.592\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:19\\\" cx=\\\"592.25\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:19\\\" cx=\\\"614.878\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:19\\\" cx=\\\"637.505\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:19\\\" cx=\\\"682.76\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:19\\\" cx=\\\"592.25\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:19\\\" cx=\\\"614.878\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:19\\\" cx=\\\"637.505\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:19\\\" cx=\\\"660.133\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:19\\\" cx=\\\"682.76\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:19\\\" cx=\\\"705.387\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:19\\\" cx=\\\"569.623\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:19\\\" cx=\\\"592.25\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:19\\\" cx=\\\"614.878\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:19\\\" cx=\\\"637.505\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:19\\\" cx=\\\"660.133\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:19\\\" cx=\\\"682.76\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:19\\\" cx=\\\"660.133\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:20\\\" cx=\\\"776.791\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:20\\\" cx=\\\"799.419\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:20\\\" cx=\\\"822.046\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:20\\\" cx=\\\"867.301\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:20\\\" cx=\\\"776.791\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:20\\\" cx=\\\"799.419\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:20\\\" cx=\\\"822.046\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:20\\\" cx=\\\"844.673\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:20\\\" cx=\\\"867.301\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:20\\\" cx=\\\"889.928\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:20\\\" cx=\\\"754.164\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:20\\\" cx=\\\"776.791\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:20\\\" cx=\\\"799.419\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:20\\\" cx=\\\"822.046\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:20\\\" cx=\\\"844.673\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:20\\\" cx=\\\"867.301\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:20\\\" cx=\\\"844.673\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:21\\\" cx=\\\"961.332\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:21\\\" cx=\\\"983.96\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:21\\\" cx=\\\"1006.59\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:21\\\" cx=\\\"1051.84\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:21\\\" cx=\\\"961.332\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:21\\\" cx=\\\"983.96\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:21\\\" cx=\\\"1006.59\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:21\\\" cx=\\\"1029.21\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:21\\\" cx=\\\"1051.84\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:21\\\" cx=\\\"1074.47\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:21\\\" cx=\\\"938.705\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:21\\\" cx=\\\"961.332\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:21\\\" cx=\\\"983.96\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:21\\\" cx=\\\"1006.59\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:21\\\" cx=\\\"1029.21\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:21\\\" cx=\\\"1051.84\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:21\\\" cx=\\\"1029.21\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:22\\\" cx=\\\"1145.87\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:22\\\" cx=\\\"1168.5\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:22\\\" cx=\\\"1191.13\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:22\\\" cx=\\\"1236.38\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:22\\\" cx=\\\"1145.87\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:22\\\" cx=\\\"1168.5\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:22\\\" cx=\\\"1191.13\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:22\\\" cx=\\\"1213.76\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:22\\\" cx=\\\"1236.38\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:22\\\" cx=\\\"1259.01\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:22\\\" cx=\\\"1123.25\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:22\\\" cx=\\\"1145.87\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:22\\\" cx=\\\"1168.5\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:22\\\" cx=\\\"1191.13\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:22\\\" cx=\\\"1213.76\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:22\\\" cx=\\\"1236.38\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:22\\\" cx=\\\"1213.76\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:23\\\" cx=\\\"1330.41\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:23\\\" cx=\\\"1353.04\\\" cy=\\\"385.082\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:23\\\" cx=\\\"1375.67\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:23\\\" cx=\\\"1420.92\\\" cy=\\\"407.709\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:23\\\" cx=\\\"1330.41\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:23\\\" cx=\\\"1353.04\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:23\\\" cx=\\\"1375.67\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:23\\\" cx=\\\"1398.3\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:23\\\" cx=\\\"1420.92\\\" cy=\\\"452.964\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:23\\\" cx=\\\"1443.55\\\" cy=\\\"430.337\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:23\\\" cx=\\\"1307.79\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:23\\\" cx=\\\"1330.41\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:23\\\" cx=\\\"1353.04\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:23\\\" cx=\\\"1375.67\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:23\\\" cx=\\\"1398.3\\\" cy=\\\"475.592\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:23\\\" cx=\\\"1420.92\\\" cy=\\\"498.219\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:23\\\" cx=\\\"1398.3\\\" cy=\\\"520.846\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:24\\\" cx=\\\"38.6274\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:24\\\" cx=\\\"61.2548\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:24\\\" cx=\\\"83.8822\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:24\\\" cx=\\\"129.137\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:24\\\" cx=\\\"38.6274\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:24\\\" cx=\\\"61.2548\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:24\\\" cx=\\\"83.8822\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:24\\\" cx=\\\"106.51\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:24\\\" cx=\\\"129.137\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:24\\\" cx=\\\"151.764\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:24\\\" cx=\\\"16\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:24\\\" cx=\\\"38.6274\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:24\\\" cx=\\\"61.2548\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:24\\\" cx=\\\"83.8822\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:24\\\" cx=\\\"106.51\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:24\\\" cx=\\\"129.137\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:24\\\" cx=\\\"106.51\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:25\\\" cx=\\\"223.168\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:25\\\" cx=\\\"245.796\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:25\\\" cx=\\\"268.423\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:25\\\" cx=\\\"313.678\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:25\\\" cx=\\\"223.168\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:25\\\" cx=\\\"245.796\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:25\\\" cx=\\\"268.423\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:25\\\" cx=\\\"291.051\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:25\\\" cx=\\\"313.678\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:25\\\" cx=\\\"336.305\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:25\\\" cx=\\\"200.541\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:25\\\" cx=\\\"223.168\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:25\\\" cx=\\\"245.796\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:25\\\" cx=\\\"268.423\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:25\\\" cx=\\\"291.051\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:25\\\" cx=\\\"313.678\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:25\\\" cx=\\\"291.051\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:26\\\" cx=\\\"407.709\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:26\\\" cx=\\\"430.337\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:26\\\" cx=\\\"452.964\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:26\\\" cx=\\\"498.219\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:26\\\" cx=\\\"407.709\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:26\\\" cx=\\\"430.337\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:26\\\" cx=\\\"452.964\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:26\\\" cx=\\\"475.592\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:26\\\" cx=\\\"498.219\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:26\\\" cx=\\\"520.846\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:26\\\" cx=\\\"385.082\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:26\\\" cx=\\\"407.709\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:26\\\" cx=\\\"430.337\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:26\\\" cx=\\\"452.964\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:26\\\" cx=\\\"475.592\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:26\\\" cx=\\\"498.219\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:26\\\" cx=\\\"475.592\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:27\\\" cx=\\\"592.25\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:27\\\" cx=\\\"614.878\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:27\\\" cx=\\\"637.505\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:27\\\" cx=\\\"682.76\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:27\\\" cx=\\\"592.25\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:27\\\" cx=\\\"614.878\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:27\\\" cx=\\\"637.505\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:27\\\" cx=\\\"660.133\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:27\\\" cx=\\\"682.76\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:27\\\" cx=\\\"705.387\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:27\\\" cx=\\\"569.623\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:27\\\" cx=\\\"592.25\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:27\\\" cx=\\\"614.878\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:27\\\" cx=\\\"637.505\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:27\\\" cx=\\\"660.133\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:27\\\" cx=\\\"682.76\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:27\\\" cx=\\\"660.133\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:28\\\" cx=\\\"776.791\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:28\\\" cx=\\\"799.419\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:28\\\" cx=\\\"822.046\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:28\\\" cx=\\\"867.301\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:28\\\" cx=\\\"776.791\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:28\\\" cx=\\\"799.419\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:28\\\" cx=\\\"822.046\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:28\\\" cx=\\\"844.673\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:28\\\" cx=\\\"867.301\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:28\\\" cx=\\\"889.928\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:28\\\" cx=\\\"754.164\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:28\\\" cx=\\\"776.791\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:28\\\" cx=\\\"799.419\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:28\\\" cx=\\\"822.046\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:28\\\" cx=\\\"844.673\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:28\\\" cx=\\\"867.301\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:28\\\" cx=\\\"844.673\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:29\\\" cx=\\\"961.332\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:29\\\" cx=\\\"983.96\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:29\\\" cx=\\\"1006.59\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:29\\\" cx=\\\"1051.84\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:29\\\" cx=\\\"961.332\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:29\\\" cx=\\\"983.96\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:29\\\" cx=\\\"1006.59\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:29\\\" cx=\\\"1029.21\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:29\\\" cx=\\\"1051.84\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:29\\\" cx=\\\"1074.47\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:29\\\" cx=\\\"938.705\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:29\\\" cx=\\\"961.332\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:29\\\" cx=\\\"983.96\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:29\\\" cx=\\\"1006.59\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:29\\\" cx=\\\"1029.21\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:29\\\" cx=\\\"1051.84\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:29\\\" cx=\\\"1029.21\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:30\\\" cx=\\\"1145.87\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:30\\\" cx=\\\"1168.5\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:30\\\" cx=\\\"1191.13\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:30\\\" cx=\\\"1236.38\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:30\\\" cx=\\\"1145.87\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:30\\\" cx=\\\"1168.5\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:30\\\" cx=\\\"1191.13\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:30\\\" cx=\\\"1213.76\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:30\\\" cx=\\\"1236.38\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:30\\\" cx=\\\"1259.01\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:30\\\" cx=\\\"1123.25\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:30\\\" cx=\\\"1145.87\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:30\\\" cx=\\\"1168.5\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:30\\\" cx=\\\"1191.13\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:30\\\" cx=\\\"1213.76\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:30\\\" cx=\\\"1236.38\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:30\\\" cx=\\\"1213.76\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:31\\\" cx=\\\"1330.41\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:31\\\" cx=\\\"1353.04\\\" cy=\\\"569.623\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:31\\\" cx=\\\"1375.67\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:31\\\" cx=\\\"1420.92\\\" cy=\\\"592.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:31\\\" cx=\\\"1330.41\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:31\\\" cx=\\\"1353.04\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:31\\\" cx=\\\"1375.67\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:31\\\" cx=\\\"1398.3\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:31\\\" cx=\\\"1420.92\\\" cy=\\\"637.505\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:31\\\" cx=\\\"1443.55\\\" cy=\\\"614.878\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:31\\\" cx=\\\"1307.79\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:31\\\" cx=\\\"1330.41\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:31\\\" cx=\\\"1353.04\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:31\\\" cx=\\\"1375.67\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:31\\\" cx=\\\"1398.3\\\" cy=\\\"660.133\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:31\\\" cx=\\\"1420.92\\\" cy=\\\"682.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:31\\\" cx=\\\"1398.3\\\" cy=\\\"705.387\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:32\\\" cx=\\\"38.6274\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:32\\\" cx=\\\"61.2548\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:32\\\" cx=\\\"83.8822\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:32\\\" cx=\\\"129.137\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:32\\\" cx=\\\"38.6274\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:32\\\" cx=\\\"61.2548\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:32\\\" cx=\\\"83.8822\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:32\\\" cx=\\\"106.51\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:32\\\" cx=\\\"129.137\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:32\\\" cx=\\\"151.764\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:32\\\" cx=\\\"16\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:32\\\" cx=\\\"38.6274\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:32\\\" cx=\\\"61.2548\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:32\\\" cx=\\\"83.8822\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:32\\\" cx=\\\"106.51\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:32\\\" cx=\\\"129.137\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:32\\\" cx=\\\"106.51\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:33\\\" cx=\\\"223.168\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:33\\\" cx=\\\"245.796\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:33\\\" cx=\\\"268.423\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:33\\\" cx=\\\"313.678\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:33\\\" cx=\\\"223.168\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:33\\\" cx=\\\"245.796\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:33\\\" cx=\\\"268.423\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:33\\\" cx=\\\"291.051\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:33\\\" cx=\\\"313.678\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:33\\\" cx=\\\"336.305\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:33\\\" cx=\\\"200.541\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:33\\\" cx=\\\"223.168\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:33\\\" cx=\\\"245.796\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:33\\\" cx=\\\"268.423\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:33\\\" cx=\\\"291.051\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:33\\\" cx=\\\"313.678\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:33\\\" cx=\\\"291.051\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:34\\\" cx=\\\"407.709\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:34\\\" cx=\\\"430.337\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:34\\\" cx=\\\"452.964\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:34\\\" cx=\\\"498.219\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:34\\\" cx=\\\"407.709\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:34\\\" cx=\\\"430.337\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:34\\\" cx=\\\"452.964\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:34\\\" cx=\\\"475.592\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:34\\\" cx=\\\"498.219\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:34\\\" cx=\\\"520.846\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:34\\\" cx=\\\"385.082\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:34\\\" cx=\\\"407.709\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:34\\\" cx=\\\"430.337\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:34\\\" cx=\\\"452.964\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:34\\\" cx=\\\"475.592\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:34\\\" cx=\\\"498.219\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:34\\\" cx=\\\"475.592\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:35\\\" cx=\\\"592.25\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:35\\\" cx=\\\"614.878\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:35\\\" cx=\\\"637.505\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:35\\\" cx=\\\"682.76\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:35\\\" cx=\\\"592.25\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:35\\\" cx=\\\"614.878\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:35\\\" cx=\\\"637.505\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:35\\\" cx=\\\"660.133\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:35\\\" cx=\\\"682.76\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:35\\\" cx=\\\"705.387\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:35\\\" cx=\\\"569.623\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:35\\\" cx=\\\"592.25\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:35\\\" cx=\\\"614.878\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:35\\\" cx=\\\"637.505\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:35\\\" cx=\\\"660.133\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:35\\\" cx=\\\"682.76\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:35\\\" cx=\\\"660.133\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:36\\\" cx=\\\"776.791\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:36\\\" cx=\\\"799.419\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:36\\\" cx=\\\"822.046\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:36\\\" cx=\\\"867.301\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:36\\\" cx=\\\"776.791\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:36\\\" cx=\\\"799.419\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:36\\\" cx=\\\"822.046\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:36\\\" cx=\\\"844.673\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:36\\\" cx=\\\"867.301\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:36\\\" cx=\\\"889.928\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:36\\\" cx=\\\"754.164\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:36\\\" cx=\\\"776.791\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:36\\\" cx=\\\"799.419\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:36\\\" cx=\\\"822.046\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:36\\\" cx=\\\"844.673\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:36\\\" cx=\\\"867.301\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:36\\\" cx=\\\"844.673\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:37\\\" cx=\\\"961.332\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:37\\\" cx=\\\"983.96\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:37\\\" cx=\\\"1006.59\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:37\\\" cx=\\\"1051.84\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:37\\\" cx=\\\"961.332\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:37\\\" cx=\\\"983.96\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:37\\\" cx=\\\"1006.59\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:37\\\" cx=\\\"1029.21\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:37\\\" cx=\\\"1051.84\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:37\\\" cx=\\\"1074.47\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:37\\\" cx=\\\"938.705\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:37\\\" cx=\\\"961.332\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:37\\\" cx=\\\"983.96\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:37\\\" cx=\\\"1006.59\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:37\\\" cx=\\\"1029.21\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:37\\\" cx=\\\"1051.84\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:37\\\" cx=\\\"1029.21\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:38\\\" cx=\\\"1145.87\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:38\\\" cx=\\\"1168.5\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:38\\\" cx=\\\"1191.13\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:38\\\" cx=\\\"1236.38\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:38\\\" cx=\\\"1145.87\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:38\\\" cx=\\\"1168.5\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:38\\\" cx=\\\"1191.13\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:38\\\" cx=\\\"1213.76\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:38\\\" cx=\\\"1236.38\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:38\\\" cx=\\\"1259.01\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:38\\\" cx=\\\"1123.25\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:38\\\" cx=\\\"1145.87\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:38\\\" cx=\\\"1168.5\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:38\\\" cx=\\\"1191.13\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:38\\\" cx=\\\"1213.76\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:38\\\" cx=\\\"1236.38\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:38\\\" cx=\\\"1213.76\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:39\\\" cx=\\\"1330.41\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:39\\\" cx=\\\"1353.04\\\" cy=\\\"754.164\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:39\\\" cx=\\\"1375.67\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:39\\\" cx=\\\"1420.92\\\" cy=\\\"776.791\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:39\\\" cx=\\\"1330.41\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:39\\\" cx=\\\"1353.04\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:39\\\" cx=\\\"1375.67\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:39\\\" cx=\\\"1398.3\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:39\\\" cx=\\\"1420.92\\\" cy=\\\"822.046\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:39\\\" cx=\\\"1443.55\\\" cy=\\\"799.419\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:39\\\" cx=\\\"1307.79\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:39\\\" cx=\\\"1330.41\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:39\\\" cx=\\\"1353.04\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:39\\\" cx=\\\"1375.67\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:39\\\" cx=\\\"1398.3\\\" cy=\\\"844.673\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:39\\\" cx=\\\"1420.92\\\" cy=\\\"867.301\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:39\\\" cx=\\\"1398.3\\\" cy=\\\"889.928\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:40\\\" cx=\\\"38.6274\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:40\\\" cx=\\\"61.2548\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:40\\\" cx=\\\"83.8822\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:40\\\" cx=\\\"129.137\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:40\\\" cx=\\\"38.6274\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:40\\\" cx=\\\"61.2548\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:40\\\" cx=\\\"83.8822\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:40\\\" cx=\\\"106.51\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:40\\\" cx=\\\"129.137\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:40\\\" cx=\\\"151.764\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:40\\\" cx=\\\"16\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:40\\\" cx=\\\"38.6274\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:40\\\" cx=\\\"61.2548\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:40\\\" cx=\\\"83.8822\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:40\\\" cx=\\\"106.51\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:40\\\" cx=\\\"129.137\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:40\\\" cx=\\\"106.51\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:41\\\" cx=\\\"223.168\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:41\\\" cx=\\\"245.796\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:41\\\" cx=\\\"268.423\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:41\\\" cx=\\\"313.678\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:41\\\" cx=\\\"223.168\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:41\\\" cx=\\\"245.796\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:41\\\" cx=\\\"268.423\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:41\\\" cx=\\\"291.051\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:41\\\" cx=\\\"313.678\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:41\\\" cx=\\\"336.305\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:41\\\" cx=\\\"200.541\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:41\\\" cx=\\\"223.168\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:41\\\" cx=\\\"245.796\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:41\\\" cx=\\\"268.423\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:41\\\" cx=\\\"291.051\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:41\\\" cx=\\\"313.678\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:41\\\" cx=\\\"291.051\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:42\\\" cx=\\\"407.709\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:42\\\" cx=\\\"430.337\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:42\\\" cx=\\\"452.964\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:42\\\" cx=\\\"498.219\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:42\\\" cx=\\\"407.709\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:42\\\" cx=\\\"430.337\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:42\\\" cx=\\\"452.964\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:42\\\" cx=\\\"475.592\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:42\\\" cx=\\\"498.219\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:42\\\" cx=\\\"520.846\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:42\\\" cx=\\\"385.082\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:42\\\" cx=\\\"407.709\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:42\\\" cx=\\\"430.337\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:42\\\" cx=\\\"452.964\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:42\\\" cx=\\\"475.592\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:42\\\" cx=\\\"498.219\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:42\\\" cx=\\\"475.592\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:43\\\" cx=\\\"592.25\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:43\\\" cx=\\\"614.878\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:43\\\" cx=\\\"637.505\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:43\\\" cx=\\\"682.76\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:43\\\" cx=\\\"592.25\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:43\\\" cx=\\\"614.878\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:43\\\" cx=\\\"637.505\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:43\\\" cx=\\\"660.133\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:43\\\" cx=\\\"682.76\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:43\\\" cx=\\\"705.387\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:43\\\" cx=\\\"569.623\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:43\\\" cx=\\\"592.25\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:43\\\" cx=\\\"614.878\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:43\\\" cx=\\\"637.505\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:43\\\" cx=\\\"660.133\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:43\\\" cx=\\\"682.76\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:43\\\" cx=\\\"660.133\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:44\\\" cx=\\\"776.791\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:44\\\" cx=\\\"799.419\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:44\\\" cx=\\\"822.046\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:44\\\" cx=\\\"867.301\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:44\\\" cx=\\\"776.791\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:44\\\" cx=\\\"799.419\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:44\\\" cx=\\\"822.046\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:44\\\" cx=\\\"844.673\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:44\\\" cx=\\\"867.301\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:44\\\" cx=\\\"889.928\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:44\\\" cx=\\\"754.164\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:44\\\" cx=\\\"776.791\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:44\\\" cx=\\\"799.419\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:44\\\" cx=\\\"822.046\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:44\\\" cx=\\\"844.673\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:44\\\" cx=\\\"867.301\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:44\\\" cx=\\\"844.673\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:45\\\" cx=\\\"961.332\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:45\\\" cx=\\\"983.96\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:45\\\" cx=\\\"1006.59\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:45\\\" cx=\\\"1051.84\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:45\\\" cx=\\\"961.332\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:45\\\" cx=\\\"983.96\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:45\\\" cx=\\\"1006.59\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:45\\\" cx=\\\"1029.21\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:45\\\" cx=\\\"1051.84\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:45\\\" cx=\\\"1074.47\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:45\\\" cx=\\\"938.705\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:45\\\" cx=\\\"961.332\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:45\\\" cx=\\\"983.96\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:45\\\" cx=\\\"1006.59\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:45\\\" cx=\\\"1029.21\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:45\\\" cx=\\\"1051.84\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:45\\\" cx=\\\"1029.21\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:46\\\" cx=\\\"1145.87\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:46\\\" cx=\\\"1168.5\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:46\\\" cx=\\\"1191.13\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:46\\\" cx=\\\"1236.38\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:46\\\" cx=\\\"1145.87\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:46\\\" cx=\\\"1168.5\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:46\\\" cx=\\\"1191.13\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:46\\\" cx=\\\"1213.76\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:46\\\" cx=\\\"1236.38\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:46\\\" cx=\\\"1259.01\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:46\\\" cx=\\\"1123.25\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:46\\\" cx=\\\"1145.87\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:46\\\" cx=\\\"1168.5\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:46\\\" cx=\\\"1191.13\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:46\\\" cx=\\\"1213.76\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:46\\\" cx=\\\"1236.38\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:46\\\" cx=\\\"1213.76\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:47\\\" cx=\\\"1330.41\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:47\\\" cx=\\\"1353.04\\\" cy=\\\"938.705\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:47\\\" cx=\\\"1375.67\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:47\\\" cx=\\\"1420.92\\\" cy=\\\"961.332\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:47\\\" cx=\\\"1330.41\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:47\\\" cx=\\\"1353.04\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:47\\\" cx=\\\"1375.67\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:47\\\" cx=\\\"1398.3\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:47\\\" cx=\\\"1420.92\\\" cy=\\\"1006.59\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:47\\\" cx=\\\"1443.55\\\" cy=\\\"983.96\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:47\\\" cx=\\\"1307.79\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:47\\\" cx=\\\"1330.41\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:47\\\" cx=\\\"1353.04\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:47\\\" cx=\\\"1375.67\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:47\\\" cx=\\\"1398.3\\\" cy=\\\"1029.21\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:47\\\" cx=\\\"1420.92\\\" cy=\\\"1051.84\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:47\\\" cx=\\\"1398.3\\\" cy=\\\"1074.47\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:48\\\" cx=\\\"38.6274\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:48\\\" cx=\\\"61.2548\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:48\\\" cx=\\\"83.8822\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:48\\\" cx=\\\"129.137\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:48\\\" cx=\\\"38.6274\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:48\\\" cx=\\\"61.2548\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:48\\\" cx=\\\"83.8822\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:48\\\" cx=\\\"106.51\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:48\\\" cx=\\\"129.137\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:48\\\" cx=\\\"151.764\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:48\\\" cx=\\\"16\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:48\\\" cx=\\\"38.6274\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:48\\\" cx=\\\"61.2548\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:48\\\" cx=\\\"83.8822\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:48\\\" cx=\\\"106.51\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:48\\\" cx=\\\"129.137\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:48\\\" cx=\\\"106.51\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:49\\\" cx=\\\"223.168\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:49\\\" cx=\\\"245.796\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:49\\\" cx=\\\"268.423\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:49\\\" cx=\\\"313.678\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:49\\\" cx=\\\"223.168\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:49\\\" cx=\\\"245.796\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:49\\\" cx=\\\"268.423\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:49\\\" cx=\\\"291.051\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:49\\\" cx=\\\"313.678\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:49\\\" cx=\\\"336.305\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:49\\\" cx=\\\"200.541\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:49\\\" cx=\\\"223.168\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:49\\\" cx=\\\"245.796\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:49\\\" cx=\\\"268.423\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:49\\\" cx=\\\"291.051\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:49\\\" cx=\\\"313.678\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:49\\\" cx=\\\"291.051\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:50\\\" cx=\\\"407.709\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:50\\\" cx=\\\"430.337\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:50\\\" cx=\\\"452.964\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:50\\\" cx=\\\"498.219\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:50\\\" cx=\\\"407.709\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:50\\\" cx=\\\"430.337\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:50\\\" cx=\\\"452.964\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:50\\\" cx=\\\"475.592\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:50\\\" cx=\\\"498.219\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:50\\\" cx=\\\"520.846\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:50\\\" cx=\\\"385.082\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:50\\\" cx=\\\"407.709\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:50\\\" cx=\\\"430.337\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:50\\\" cx=\\\"452.964\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:50\\\" cx=\\\"475.592\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:50\\\" cx=\\\"498.219\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:50\\\" cx=\\\"475.592\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:51\\\" cx=\\\"592.25\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:51\\\" cx=\\\"614.878\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:51\\\" cx=\\\"637.505\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:51\\\" cx=\\\"682.76\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:51\\\" cx=\\\"592.25\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:51\\\" cx=\\\"614.878\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:51\\\" cx=\\\"637.505\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:51\\\" cx=\\\"660.133\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:51\\\" cx=\\\"682.76\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:51\\\" cx=\\\"705.387\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:51\\\" cx=\\\"569.623\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:51\\\" cx=\\\"592.25\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:51\\\" cx=\\\"614.878\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:51\\\" cx=\\\"637.505\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:51\\\" cx=\\\"660.133\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:51\\\" cx=\\\"682.76\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:51\\\" cx=\\\"660.133\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:52\\\" cx=\\\"776.791\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:52\\\" cx=\\\"799.419\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:52\\\" cx=\\\"822.046\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:52\\\" cx=\\\"867.301\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:52\\\" cx=\\\"776.791\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:52\\\" cx=\\\"799.419\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:52\\\" cx=\\\"822.046\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:52\\\" cx=\\\"844.673\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:52\\\" cx=\\\"867.301\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:52\\\" cx=\\\"889.928\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:52\\\" cx=\\\"754.164\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:52\\\" cx=\\\"776.791\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:52\\\" cx=\\\"799.419\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:52\\\" cx=\\\"822.046\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:52\\\" cx=\\\"844.673\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:52\\\" cx=\\\"867.301\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:52\\\" cx=\\\"844.673\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:53\\\" cx=\\\"961.332\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:53\\\" cx=\\\"983.96\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:53\\\" cx=\\\"1006.59\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:53\\\" cx=\\\"1051.84\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:53\\\" cx=\\\"961.332\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:53\\\" cx=\\\"983.96\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:53\\\" cx=\\\"1006.59\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:53\\\" cx=\\\"1029.21\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:53\\\" cx=\\\"1051.84\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:53\\\" cx=\\\"1074.47\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:53\\\" cx=\\\"938.705\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:53\\\" cx=\\\"961.332\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:53\\\" cx=\\\"983.96\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:53\\\" cx=\\\"1006.59\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:53\\\" cx=\\\"1029.21\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:53\\\" cx=\\\"1051.84\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:53\\\" cx=\\\"1029.21\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:54\\\" cx=\\\"1145.87\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:54\\\" cx=\\\"1168.5\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:54\\\" cx=\\\"1191.13\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:54\\\" cx=\\\"1236.38\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:54\\\" cx=\\\"1145.87\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:54\\\" cx=\\\"1168.5\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:54\\\" cx=\\\"1191.13\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:54\\\" cx=\\\"1213.76\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:54\\\" cx=\\\"1236.38\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:54\\\" cx=\\\"1259.01\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:54\\\" cx=\\\"1123.25\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:54\\\" cx=\\\"1145.87\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:54\\\" cx=\\\"1168.5\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:54\\\" cx=\\\"1191.13\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:54\\\" cx=\\\"1213.76\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:54\\\" cx=\\\"1236.38\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:54\\\" cx=\\\"1213.76\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:55\\\" cx=\\\"1330.41\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:55\\\" cx=\\\"1353.04\\\" cy=\\\"1123.25\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:55\\\" cx=\\\"1375.67\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:55\\\" cx=\\\"1420.92\\\" cy=\\\"1145.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:55\\\" cx=\\\"1330.41\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:55\\\" cx=\\\"1353.04\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:55\\\" cx=\\\"1375.67\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:55\\\" cx=\\\"1398.3\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:55\\\" cx=\\\"1420.92\\\" cy=\\\"1191.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:55\\\" cx=\\\"1443.55\\\" cy=\\\"1168.5\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:55\\\" cx=\\\"1307.79\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:55\\\" cx=\\\"1330.41\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:55\\\" cx=\\\"1353.04\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:55\\\" cx=\\\"1375.67\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:55\\\" cx=\\\"1398.3\\\" cy=\\\"1213.76\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:55\\\" cx=\\\"1420.92\\\" cy=\\\"1236.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:55\\\" cx=\\\"1398.3\\\" cy=\\\"1259.01\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:56\\\" cx=\\\"38.6274\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:56\\\" cx=\\\"61.2548\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:56\\\" cx=\\\"83.8822\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:56\\\" cx=\\\"129.137\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:56\\\" cx=\\\"38.6274\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:56\\\" cx=\\\"61.2548\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:56\\\" cx=\\\"83.8822\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:56\\\" cx=\\\"106.51\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:56\\\" cx=\\\"129.137\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:56\\\" cx=\\\"151.764\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:56\\\" cx=\\\"16\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:56\\\" cx=\\\"38.6274\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:56\\\" cx=\\\"61.2548\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:56\\\" cx=\\\"83.8822\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:56\\\" cx=\\\"106.51\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:56\\\" cx=\\\"129.137\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:56\\\" cx=\\\"106.51\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:57\\\" cx=\\\"223.168\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:57\\\" cx=\\\"245.796\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:57\\\" cx=\\\"268.423\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:57\\\" cx=\\\"313.678\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:57\\\" cx=\\\"223.168\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:57\\\" cx=\\\"245.796\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:57\\\" cx=\\\"268.423\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:57\\\" cx=\\\"291.051\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:57\\\" cx=\\\"313.678\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:57\\\" cx=\\\"336.305\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:57\\\" cx=\\\"200.541\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:57\\\" cx=\\\"223.168\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:57\\\" cx=\\\"245.796\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:57\\\" cx=\\\"268.423\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:57\\\" cx=\\\"291.051\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:57\\\" cx=\\\"313.678\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:57\\\" cx=\\\"291.051\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:58\\\" cx=\\\"407.709\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:58\\\" cx=\\\"430.337\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:58\\\" cx=\\\"452.964\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:58\\\" cx=\\\"498.219\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:58\\\" cx=\\\"407.709\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:58\\\" cx=\\\"430.337\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:58\\\" cx=\\\"452.964\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:58\\\" cx=\\\"475.592\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:58\\\" cx=\\\"498.219\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:58\\\" cx=\\\"520.846\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:58\\\" cx=\\\"385.082\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:58\\\" cx=\\\"407.709\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:58\\\" cx=\\\"430.337\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:58\\\" cx=\\\"452.964\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:58\\\" cx=\\\"475.592\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:58\\\" cx=\\\"498.219\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:58\\\" cx=\\\"475.592\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:59\\\" cx=\\\"592.25\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:59\\\" cx=\\\"614.878\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:59\\\" cx=\\\"637.505\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:59\\\" cx=\\\"682.76\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:59\\\" cx=\\\"592.25\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:59\\\" cx=\\\"614.878\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:59\\\" cx=\\\"637.505\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:59\\\" cx=\\\"660.133\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:59\\\" cx=\\\"682.76\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:59\\\" cx=\\\"705.387\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:59\\\" cx=\\\"569.623\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:59\\\" cx=\\\"592.25\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:59\\\" cx=\\\"614.878\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:59\\\" cx=\\\"637.505\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:59\\\" cx=\\\"660.133\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:59\\\" cx=\\\"682.76\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:59\\\" cx=\\\"660.133\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:60\\\" cx=\\\"776.791\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:60\\\" cx=\\\"799.419\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:60\\\" cx=\\\"822.046\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:60\\\" cx=\\\"867.301\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:60\\\" cx=\\\"776.791\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:60\\\" cx=\\\"799.419\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:60\\\" cx=\\\"822.046\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:60\\\" cx=\\\"844.673\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:60\\\" cx=\\\"867.301\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:60\\\" cx=\\\"889.928\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:60\\\" cx=\\\"754.164\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:60\\\" cx=\\\"776.791\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:60\\\" cx=\\\"799.419\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:60\\\" cx=\\\"822.046\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:60\\\" cx=\\\"844.673\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:60\\\" cx=\\\"867.301\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:60\\\" cx=\\\"844.673\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:61\\\" cx=\\\"961.332\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:61\\\" cx=\\\"983.96\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:61\\\" cx=\\\"1006.59\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:61\\\" cx=\\\"1051.84\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:61\\\" cx=\\\"961.332\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:61\\\" cx=\\\"983.96\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:61\\\" cx=\\\"1006.59\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:61\\\" cx=\\\"1029.21\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:61\\\" cx=\\\"1051.84\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:61\\\" cx=\\\"1074.47\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:61\\\" cx=\\\"938.705\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:61\\\" cx=\\\"961.332\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:61\\\" cx=\\\"983.96\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:61\\\" cx=\\\"1006.59\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:61\\\" cx=\\\"1029.21\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:61\\\" cx=\\\"1051.84\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:61\\\" cx=\\\"1029.21\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:62\\\" cx=\\\"1145.87\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:62\\\" cx=\\\"1168.5\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:62\\\" cx=\\\"1191.13\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:62\\\" cx=\\\"1236.38\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:62\\\" cx=\\\"1145.87\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:62\\\" cx=\\\"1168.5\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:62\\\" cx=\\\"1191.13\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:62\\\" cx=\\\"1213.76\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:62\\\" cx=\\\"1236.38\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:62\\\" cx=\\\"1259.01\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:62\\\" cx=\\\"1123.25\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:62\\\" cx=\\\"1145.87\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:62\\\" cx=\\\"1168.5\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:62\\\" cx=\\\"1191.13\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:62\\\" cx=\\\"1213.76\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:62\\\" cx=\\\"1236.38\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:62\\\" cx=\\\"1213.76\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:63\\\" cx=\\\"1330.41\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:63\\\" cx=\\\"1353.04\\\" cy=\\\"1307.79\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:63\\\" cx=\\\"1375.67\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:63\\\" cx=\\\"1420.92\\\" cy=\\\"1330.41\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:63\\\" cx=\\\"1330.41\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:63\\\" cx=\\\"1353.04\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:63\\\" cx=\\\"1375.67\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:63\\\" cx=\\\"1398.3\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:63\\\" cx=\\\"1420.92\\\" cy=\\\"1375.67\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:63\\\" cx=\\\"1443.55\\\" cy=\\\"1353.04\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:63\\\" cx=\\\"1307.79\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:63\\\" cx=\\\"1330.41\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:63\\\" cx=\\\"1353.04\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:63\\\" cx=\\\"1375.67\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:63\\\" cx=\\\"1398.3\\\" cy=\\\"1398.3\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:63\\\" cx=\\\"1420.92\\\" cy=\\\"1420.92\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:63\\\" cx=\\\"1398.3\\\" cy=\\\"1443.55\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"tick_borders\\\">\\n\",\n              \"<rect id=\\\"tick_border:0:0_0:0\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:1:1_0:1\\\" x=\\\"0\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:2:2_0:2\\\" x=\\\"0\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:3:3_0:3\\\" x=\\\"0\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:4:4_0:4\\\" x=\\\"0\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:5:5_0:5\\\" x=\\\"0\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:6:6_0:6\\\" x=\\\"0\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:7:7_0:7\\\" x=\\\"0\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:8:0_1:8\\\" x=\\\"184.541\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:9:1_1:9\\\" x=\\\"184.541\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:10:2_1:10\\\" x=\\\"184.541\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:11:3_1:11\\\" x=\\\"184.541\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:12:4_1:12\\\" x=\\\"184.541\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:13:5_1:13\\\" x=\\\"184.541\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:14:6_1:14\\\" x=\\\"184.541\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:15:7_1:15\\\" x=\\\"184.541\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:16:0_2:16\\\" x=\\\"369.082\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:17:1_2:17\\\" x=\\\"369.082\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:18:2_2:18\\\" x=\\\"369.082\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:19:3_2:19\\\" x=\\\"369.082\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:20:4_2:20\\\" x=\\\"369.082\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:21:5_2:21\\\" x=\\\"369.082\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:22:6_2:22\\\" x=\\\"369.082\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:23:7_2:23\\\" x=\\\"369.082\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:24:0_3:24\\\" x=\\\"553.623\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:25:1_3:25\\\" x=\\\"553.623\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:26:2_3:26\\\" x=\\\"553.623\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:27:3_3:27\\\" x=\\\"553.623\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:28:4_3:28\\\" x=\\\"553.623\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:29:5_3:29\\\" x=\\\"553.623\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:30:6_3:30\\\" x=\\\"553.623\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:31:7_3:31\\\" x=\\\"553.623\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:32:0_4:32\\\" x=\\\"738.164\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:33:1_4:33\\\" x=\\\"738.164\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:34:2_4:34\\\" x=\\\"738.164\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:35:3_4:35\\\" x=\\\"738.164\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:36:4_4:36\\\" x=\\\"738.164\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:37:5_4:37\\\" x=\\\"738.164\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:38:6_4:38\\\" x=\\\"738.164\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:39:7_4:39\\\" x=\\\"738.164\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:40:0_5:40\\\" x=\\\"922.705\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:41:1_5:41\\\" x=\\\"922.705\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:42:2_5:42\\\" x=\\\"922.705\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:43:3_5:43\\\" x=\\\"922.705\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:44:4_5:44\\\" x=\\\"922.705\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:45:5_5:45\\\" x=\\\"922.705\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:46:6_5:46\\\" x=\\\"922.705\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:47:7_5:47\\\" x=\\\"922.705\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:48:0_6:48\\\" x=\\\"1107.25\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:49:1_6:49\\\" x=\\\"1107.25\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:50:2_6:50\\\" x=\\\"1107.25\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:51:3_6:51\\\" x=\\\"1107.25\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:52:4_6:52\\\" x=\\\"1107.25\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:53:5_6:53\\\" x=\\\"1107.25\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:54:6_6:54\\\" x=\\\"1107.25\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:55:7_6:55\\\" x=\\\"1107.25\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:56:0_7:56\\\" x=\\\"1291.79\\\" y=\\\"0\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:57:1_7:57\\\" x=\\\"1291.79\\\" y=\\\"184.541\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:58:2_7:58\\\" x=\\\"1291.79\\\" y=\\\"369.082\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:59:3_7:59\\\" x=\\\"1291.79\\\" y=\\\"553.623\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:60:4_7:60\\\" x=\\\"1291.79\\\" y=\\\"738.164\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:61:5_7:61\\\" x=\\\"1291.79\\\" y=\\\"922.705\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:62:6_7:62\\\" x=\\\"1291.79\\\" y=\\\"1107.25\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<rect id=\\\"tick_border:63:7_7:63\\\" x=\\\"1291.79\\\" y=\\\"1291.79\\\" width=\\\"167.764\\\" height=\\\"167.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"</svg>\"\n            ]\n          },\n          \"execution_count\": 32,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"surface_code_circuit.diagram(\\\"detslice-svg\\\")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"pWcO6j68-qOW\"\n      },\n      \"source\": [\n        \"There is also the diagram type `detslice-with-ops-svg`, which overlays the time slice and detslice diagrams. For example, `detslice-with-ops-svg` shows how the first round gradually projects the system into the surface code state.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"aRPHBfk--qOW\",\n        \"outputId\": \"759ce9ba-6f21-4618-ee24-f31e5607ba0c\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/svg+xml\": [\n              \"<svg viewBox=\\\"0 0 1380.89 1380.89\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"slice:2:4_4_0:3\\\">\\n\",\n              \"<path d=\\\"M1165.13,215.764 C1192.28 197.663,1192.28 197.663,1210.38 170.51 L1255.64,215.764 C1228.48 233.866,1228.48 233.866,1210.38 261.019 C1183.23 279.121,1183.23 279.121,1165.13 306.274 L1119.87,261.019 C1147.03 242.917,1147.03 242.917,1165.13 215.764\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,215.764 C1192.28 197.663,1192.28 197.663,1210.38 170.51 L1255.64,215.764 C1228.48 233.866,1228.48 233.866,1210.38 261.019 C1183.23 279.121,1183.23 279.121,1165.13 306.274 L1119.87,261.019 C1147.03 242.917,1147.03 242.917,1165.13 215.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:5\\\">\\n\",\n              \"<path d=\\\"M645.192,645.192 C672.344 627.09,672.344 627.09,690.446 599.937 L735.701,645.192 C708.548 663.293,708.548 663.293,690.446 690.446 C663.293 708.548,663.293 708.548,645.192 735.701 L599.937,690.446 C627.09 672.344,627.09 672.344,645.192 645.192\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M645.192,645.192 C672.344 627.09,672.344 627.09,690.446 599.937 L735.701,645.192 C708.548 663.293,708.548 663.293,690.446 690.446 C663.293 708.548,663.293 708.548,645.192 735.701 L599.937,690.446 C627.09 672.344,627.09 672.344,645.192 645.192\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:5\\\">\\n\",\n              \"<path d=\\\"M735.701,645.192 C762.854 627.09,762.854 627.09,780.956 599.937 L826.211,645.192 C799.058 663.293,799.058 663.293,780.956 690.446 C753.803 708.548,753.803 708.548,735.701 735.701 L690.446,690.446 C717.599 672.344,717.599 672.344,735.701 645.192\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M735.701,645.192 C762.854 627.09,762.854 627.09,780.956 599.937 L826.211,645.192 C799.058 663.293,799.058 663.293,780.956 690.446 C753.803 708.548,753.803 708.548,735.701 735.701 L690.446,690.446 C717.599 672.344,717.599 672.344,735.701 645.192\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:1\\\">\\n\",\n              \"<path d=\\\"M125.255,125.255 L215.764,125.255 L170.51,170.51 L215.764,215.764 L125.255,215.764 L125.255,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M125.255,125.255 L215.764,125.255 L170.51,170.51 L215.764,215.764 L125.255,215.764 L125.255,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:1\\\">\\n\",\n              \"<path d=\\\"M215.764,215.764 L306.274,215.764 L261.019,261.019 L306.274,306.274 L215.764,306.274 L215.764,215.764\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M215.764,215.764 L306.274,215.764 L261.019,261.019 L306.274,306.274 L215.764,306.274 L215.764,215.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:2\\\">\\n\",\n              \"<path d=\\\"M599.937,125.255 L690.446,125.255 L645.192,170.51 L690.446,215.764 L599.937,215.764 L599.937,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M599.937,125.255 L690.446,125.255 L645.192,170.51 L690.446,215.764 L599.937,215.764 L599.937,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:2\\\">\\n\",\n              \"<path d=\\\"M690.446,215.764 L780.956,215.764 L735.701,261.019 L780.956,306.274 L690.446,306.274 L690.446,215.764\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M690.446,215.764 L780.956,215.764 L735.701,261.019 L780.956,306.274 L690.446,306.274 L690.446,215.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:3\\\">\\n\",\n              \"<path d=\\\"M1074.62,125.255 L1119.87,80 L1165.13,125.255 C1137.98 143.357,1137.98 143.357,1119.87 170.51 C1092.72 188.612,1092.72 188.612,1074.62 215.764 L1074.62,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,125.255 L1119.87,80 L1165.13,125.255 C1137.98 143.357,1137.98 143.357,1119.87 170.51 C1092.72 188.612,1092.72 188.612,1074.62 215.764 L1074.62,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:5\\\">\\n\",\n              \"<path d=\\\"M645.192,735.701 C672.344 717.599,672.344 717.599,690.446 690.446 L735.701,735.701 L690.446,780.956 L599.937,780.956 C627.09 762.854,627.09 762.854,645.192 735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M645.192,735.701 C672.344 717.599,672.344 717.599,690.446 690.446 L735.701,735.701 L690.446,780.956 L599.937,780.956 C627.09 762.854,627.09 762.854,645.192 735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:5\\\">\\n\",\n              \"<path d=\\\"M735.701,735.701 C762.854 717.599,762.854 717.599,780.956 690.446 L780.956,780.956 L735.701,826.211 L690.446,780.956 C717.599 762.854,717.599 762.854,735.701 735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M735.701,735.701 C762.854 717.599,762.854 717.599,780.956 690.446 L780.956,780.956 L735.701,826.211 L690.446,780.956 C717.599 762.854,717.599 762.854,735.701 735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1074.62,599.937 L1165.13,599.937 L1119.87,645.192 L1165.13,690.446 L1074.62,690.446 L1074.62,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,599.937 L1165.13,599.937 L1119.87,645.192 L1165.13,690.446 L1074.62,690.446 L1074.62,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1165.13,599.937 L1255.64,599.937 L1210.38,645.192 L1255.64,690.446 L1165.13,690.446 L1165.13,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,599.937 L1255.64,599.937 L1210.38,645.192 L1255.64,690.446 L1165.13,690.446 L1165.13,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1074.62,690.446 L1165.13,690.446 L1119.87,735.701 L1165.13,780.956 L1074.62,780.956 L1074.62,690.446\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,690.446 L1165.13,690.446 L1119.87,735.701 L1165.13,780.956 L1074.62,780.956 L1074.62,690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1165.13,690.446 L1255.64,690.446 L1210.38,735.701 L1255.64,780.956 L1165.13,780.956 L1165.13,690.446\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,690.446 L1255.64,690.446 L1210.38,735.701 L1255.64,780.956 L1165.13,780.956 L1165.13,690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:7\\\">\\n\",\n              \"<path d=\\\"M125.255,1074.62 L215.764,1074.62 L170.51,1119.87 L215.764,1165.13 L125.255,1165.13 L125.255,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M125.255,1074.62 L215.764,1074.62 L170.51,1119.87 L215.764,1165.13 L125.255,1165.13 L125.255,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:7\\\">\\n\",\n              \"<path d=\\\"M215.764,1074.62 L306.274,1074.62 L261.019,1119.87 L306.274,1165.13 L215.764,1165.13 L215.764,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip0\\\"><path d=\\\"M215.764,1074.62 L306.274,1074.62 L261.019,1119.87 L306.274,1165.13 L215.764,1165.13 L215.764,1074.62\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"306.274\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"261.019\\\" cy=\\\"1119.87\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"306.274\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1074.62 L306.274,1074.62 L261.019,1119.87 L306.274,1165.13 L215.764,1165.13 L215.764,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:7\\\">\\n\",\n              \"<path d=\\\"M125.255,1165.13 L215.764,1165.13 L170.51,1210.38 L215.764,1255.64 L125.255,1255.64 L125.255,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip1\\\"><path d=\\\"M125.255,1165.13 L215.764,1165.13 L170.51,1210.38 L215.764,1255.64 L125.255,1255.64 L125.255,1165.13\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"125.255\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"125.255\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"170.51\\\" cy=\\\"1210.38\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M125.255,1165.13 L215.764,1165.13 L170.51,1210.38 L215.764,1255.64 L125.255,1255.64 L125.255,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:7\\\">\\n\",\n              \"<path d=\\\"M215.764,1165.13 L306.274,1165.13 L261.019,1210.38 L306.274,1255.64 L215.764,1255.64 L215.764,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1165.13 L306.274,1165.13 L261.019,1210.38 L306.274,1255.64 L215.764,1255.64 L215.764,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:8\\\">\\n\",\n              \"<path d=\\\"M599.937,1074.62 L690.446,1074.62 L645.192,1119.87 L690.446,1165.13 L599.937,1165.13 L599.937,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M599.937,1074.62 L690.446,1074.62 L645.192,1119.87 L690.446,1165.13 L599.937,1165.13 L599.937,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:8\\\">\\n\",\n              \"<path d=\\\"M690.446,1074.62 L780.956,1074.62 L735.701,1119.87 L780.956,1165.13 L690.446,1165.13 L690.446,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip2\\\"><path d=\\\"M690.446,1074.62 L780.956,1074.62 L735.701,1119.87 L780.956,1165.13 L690.446,1165.13 L690.446,1074.62\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"780.956\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"780.956\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1074.62 L780.956,1074.62 L735.701,1119.87 L780.956,1165.13 L690.446,1165.13 L690.446,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:8\\\">\\n\",\n              \"<path d=\\\"M599.937,1165.13 L690.446,1165.13 L645.192,1210.38 L690.446,1255.64 L599.937,1255.64 L599.937,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip3\\\"><path d=\\\"M599.937,1165.13 L690.446,1165.13 L645.192,1210.38 L690.446,1255.64 L599.937,1255.64 L599.937,1165.13\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"599.937\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"599.937\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"690.446\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M599.937,1165.13 L690.446,1165.13 L645.192,1210.38 L690.446,1255.64 L599.937,1255.64 L599.937,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:8\\\">\\n\",\n              \"<path d=\\\"M690.446,1165.13 L780.956,1165.13 L735.701,1210.38 L780.956,1255.64 L690.446,1255.64 L690.446,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1165.13 L780.956,1165.13 L735.701,1210.38 L780.956,1255.64 L690.446,1255.64 L690.446,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:9\\\">\\n\",\n              \"<path d=\\\"M1074.62,1074.62 L1165.13,1074.62 L1119.87,1119.87 L1165.13,1165.13 L1074.62,1165.13 L1074.62,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,1074.62 L1165.13,1074.62 L1119.87,1119.87 L1165.13,1165.13 L1074.62,1165.13 L1074.62,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:9\\\">\\n\",\n              \"<path d=\\\"M1165.13,1074.62 L1255.64,1074.62 L1210.38,1119.87 L1255.64,1165.13 L1165.13,1165.13 L1165.13,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1074.62 L1255.64,1074.62 L1210.38,1119.87 L1255.64,1165.13 L1165.13,1165.13 L1165.13,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:9\\\">\\n\",\n              \"<path d=\\\"M1074.62,1165.13 L1165.13,1165.13 L1119.87,1210.38 L1165.13,1255.64 L1074.62,1255.64 L1074.62,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,1165.13 L1165.13,1165.13 L1119.87,1210.38 L1165.13,1255.64 L1074.62,1255.64 L1074.62,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:9\\\">\\n\",\n              \"<path d=\\\"M1165.13,1165.13 L1255.64,1165.13 L1210.38,1210.38 L1255.64,1255.64 L1165.13,1255.64 L1165.13,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1165.13 L1255.64,1165.13 L1210.38,1210.38 L1255.64,1255.64 L1165.13,1255.64 L1165.13,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:3\\\">\\n\",\n              \"<path d=\\\"M1210.38,170.51 L1255.64,125.255 L1300.89,170.51 L1255.64,215.764 L1210.38,170.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,170.51 L1255.64,125.255 L1300.89,170.51 L1255.64,215.764 L1210.38,170.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:4\\\">\\n\",\n              \"<path d=\\\"M170.51,735.701 L215.764,690.446 L261.019,735.701 L215.764,780.956 L170.51,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M170.51,735.701 L215.764,690.446 L261.019,735.701 L215.764,780.956 L170.51,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:4\\\">\\n\",\n              \"<path d=\\\"M261.019,645.192 L306.274,599.937 L351.529,645.192 L306.274,690.446 L261.019,645.192\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M261.019,645.192 L306.274,599.937 L351.529,645.192 L306.274,690.446 L261.019,645.192\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:4\\\">\\n\",\n              \"<path d=\\\"M125.255,599.937 L170.51,554.682 L215.764,599.937 L170.51,645.192 L125.255,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M125.255,599.937 L170.51,554.682 L215.764,599.937 L170.51,645.192 L125.255,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:4\\\">\\n\",\n              \"<path d=\\\"M170.51,645.192 L215.764,599.937 L261.019,645.192 L215.764,690.446 L170.51,645.192\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M170.51,645.192 L215.764,599.937 L261.019,645.192 L215.764,690.446 L170.51,645.192\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:4\\\">\\n\",\n              \"<path d=\\\"M215.764,690.446 L261.019,645.192 L306.274,690.446 L261.019,735.701 L215.764,690.446\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M215.764,690.446 L261.019,645.192 L306.274,690.446 L261.019,735.701 L215.764,690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:4\\\">\\n\",\n              \"<path d=\\\"M80,735.701 L125.255,690.446 L170.51,735.701 L125.255,780.956 L80,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M80,735.701 L125.255,690.446 L170.51,735.701 L125.255,780.956 L80,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:5\\\">\\n\",\n              \"<path d=\\\"M599.937,599.937 L645.192,554.682 L690.446,599.937 L645.192,645.192 L599.937,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M599.937,599.937 L645.192,554.682 L690.446,599.937 L645.192,645.192 L599.937,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:5\\\">\\n\",\n              \"<path d=\\\"M554.682,735.701 L599.937,690.446 L645.192,735.701 L599.937,780.956 L554.682,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M554.682,735.701 L599.937,690.446 L645.192,735.701 L599.937,780.956 L554.682,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:1\\\">\\n\",\n              \"<path d=\\\"M80,261.019 L125.255,215.764 L125.255,306.274 L80,261.019\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M80,261.019 L125.255,215.764 L125.255,306.274 L80,261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:1\\\">\\n\",\n              \"<path d=\\\"M306.274,125.255 L351.529,170.51 L306.274,215.764 L306.274,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M306.274,125.255 L351.529,170.51 L306.274,215.764 L306.274,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:2\\\">\\n\",\n              \"<path d=\\\"M554.682,261.019 L599.937,215.764 L599.937,306.274 L554.682,261.019\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M554.682,261.019 L599.937,215.764 L599.937,306.274 L554.682,261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:2\\\">\\n\",\n              \"<path d=\\\"M780.956,125.255 L826.211,170.51 L780.956,215.764 L780.956,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M780.956,125.255 L826.211,170.51 L780.956,215.764 L780.956,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:4\\\">\\n\",\n              \"<path d=\\\"M125.255,599.937 L170.51,645.192 L125.255,690.446 L125.255,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M125.255,599.937 L170.51,645.192 L125.255,690.446 L125.255,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:4\\\">\\n\",\n              \"<path d=\\\"M170.51,735.701 L215.764,780.956 L125.255,780.956 L170.51,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M170.51,735.701 L215.764,780.956 L125.255,780.956 L170.51,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:4\\\">\\n\",\n              \"<path d=\\\"M261.019,735.701 L306.274,690.446 L306.274,780.956 L261.019,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M261.019,735.701 L306.274,690.446 L306.274,780.956 L261.019,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:6\\\">\\n\",\n              \"<path d=\\\"M1119.87,554.682 L1165.13,599.937 L1074.62,599.937 L1119.87,554.682\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,554.682 L1165.13,599.937 L1074.62,599.937 L1119.87,554.682\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1255.64,599.937 L1300.89,645.192 L1255.64,690.446 L1255.64,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,599.937 L1300.89,645.192 L1255.64,690.446 L1255.64,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1029.36,735.701 L1074.62,690.446 L1074.62,780.956 L1029.36,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.36,735.701 L1074.62,690.446 L1074.62,780.956 L1029.36,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:6\\\">\\n\",\n              \"<path d=\\\"M1165.13,780.956 L1255.64,780.956 L1210.38,826.211 L1165.13,780.956\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,780.956 L1255.64,780.956 L1210.38,826.211 L1165.13,780.956\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:7\\\">\\n\",\n              \"<path d=\\\"M170.51,1029.36 L215.764,1074.62 L125.255,1074.62 L170.51,1029.36\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip4\\\"><path d=\\\"M170.51,1029.36 L215.764,1074.62 L125.255,1074.62 L170.51,1029.36\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"125.255\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"170.51\\\" cy=\\\"1029.36\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M170.51,1029.36 L215.764,1074.62 L125.255,1074.62 L170.51,1029.36\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:7\\\">\\n\",\n              \"<path d=\\\"M306.274,1074.62 L351.529,1119.87 L306.274,1165.13 L306.274,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M306.274,1074.62 L351.529,1119.87 L306.274,1165.13 L306.274,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:7\\\">\\n\",\n              \"<path d=\\\"M80,1210.38 L125.255,1165.13 L125.255,1255.64 L80,1210.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M80,1210.38 L125.255,1165.13 L125.255,1255.64 L80,1210.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:7\\\">\\n\",\n              \"<path d=\\\"M215.764,1255.64 L306.274,1255.64 L261.019,1300.89 L215.764,1255.64\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip5\\\"><path d=\\\"M215.764,1255.64 L306.274,1255.64 L261.019,1300.89 L215.764,1255.64\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"306.274\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"261.019\\\" cy=\\\"1300.89\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1255.64 L306.274,1255.64 L261.019,1300.89 L215.764,1255.64\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:8\\\">\\n\",\n              \"<path d=\\\"M645.192,1029.36 L690.446,1074.62 L599.937,1074.62 L645.192,1029.36\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip6\\\"><path d=\\\"M645.192,1029.36 L690.446,1074.62 L599.937,1074.62 L645.192,1029.36\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"599.937\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M645.192,1029.36 L690.446,1074.62 L599.937,1074.62 L645.192,1029.36\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:8\\\">\\n\",\n              \"<path d=\\\"M780.956,1074.62 L826.211,1119.87 L780.956,1165.13 L780.956,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M780.956,1074.62 L826.211,1119.87 L780.956,1165.13 L780.956,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:8\\\">\\n\",\n              \"<path d=\\\"M554.682,1210.38 L599.937,1165.13 L599.937,1255.64 L554.682,1210.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M554.682,1210.38 L599.937,1165.13 L599.937,1255.64 L554.682,1210.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:8\\\">\\n\",\n              \"<path d=\\\"M690.446,1255.64 L780.956,1255.64 L735.701,1300.89 L690.446,1255.64\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip7\\\"><path d=\\\"M690.446,1255.64 L780.956,1255.64 L735.701,1300.89 L690.446,1255.64\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"690.446\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"780.956\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1255.64 L780.956,1255.64 L735.701,1300.89 L690.446,1255.64\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:9\\\">\\n\",\n              \"<path d=\\\"M1119.87,1029.36 L1165.13,1074.62 L1074.62,1074.62 L1119.87,1029.36\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,1029.36 L1165.13,1074.62 L1074.62,1074.62 L1119.87,1029.36\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:9\\\">\\n\",\n              \"<path d=\\\"M1255.64,1074.62 L1300.89,1119.87 L1255.64,1165.13 L1255.64,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,1074.62 L1300.89,1119.87 L1255.64,1165.13 L1255.64,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:9\\\">\\n\",\n              \"<path d=\\\"M1029.36,1210.38 L1074.62,1165.13 L1074.62,1255.64 L1029.36,1210.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.36,1210.38 L1074.62,1165.13 L1074.62,1255.64 L1029.36,1210.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:9\\\">\\n\",\n              \"<path d=\\\"M1165.13,1255.64 L1255.64,1255.64 L1210.38,1300.89 L1165.13,1255.64\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1255.64 L1255.64,1255.64 L1210.38,1300.89 L1165.13,1255.64\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:3\\\">\\n\",\n              \"<path d=\\\"M1074.62,215.764 C1051.99 220.29, 1033.89 238.392, 1029.36 261.019 C1051.99 256.494, 1070.09 238.392, 1074.62 215.764\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,215.764 C1051.99 220.29, 1033.89 238.392, 1029.36 261.019 C1051.99 256.494, 1070.09 238.392, 1074.62 215.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:3\\\">\\n\",\n              \"<path d=\\\"M1119.87,80 C1124.4 102.627, 1142.5 120.729, 1165.13 125.255 C1160.6 102.627, 1142.5 84.5255, 1119.87 80\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,80 C1124.4 102.627, 1142.5 120.729, 1165.13 125.255 C1160.6 102.627, 1142.5 84.5255, 1119.87 80\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:3\\\">\\n\",\n              \"<path d=\\\"M1119.87,170.51 C1124.4 193.137, 1142.5 211.239, 1165.13 215.764 C1160.6 193.137, 1142.5 175.035, 1119.87 170.51\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,170.51 C1124.4 193.137, 1142.5 211.239, 1165.13 215.764 C1160.6 193.137, 1142.5 175.035, 1119.87 170.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:3\\\">\\n\",\n              \"<path d=\\\"M1210.38,170.51 C1214.91 193.137, 1233.01 211.239, 1255.64 215.764 C1251.11 193.137, 1233.01 175.035, 1210.38 170.51\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,170.51 C1214.91 193.137, 1233.01 211.239, 1255.64 215.764 C1251.11 193.137, 1233.01 175.035, 1210.38 170.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:3\\\">\\n\",\n              \"<path d=\\\"M1029.36,261.019 C1033.89 283.647, 1051.99 301.749, 1074.62 306.274 C1070.09 283.647, 1051.99 265.545, 1029.36 261.019\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.36,261.019 C1033.89 283.647, 1051.99 301.749, 1074.62 306.274 C1070.09 283.647, 1051.99 265.545, 1029.36 261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:3\\\">\\n\",\n              \"<path d=\\\"M1119.87,261.019 C1124.4 283.647, 1142.5 301.749, 1165.13 306.274 C1160.6 283.647, 1142.5 265.545, 1119.87 261.019\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,261.019 C1124.4 283.647, 1142.5 301.749, 1165.13 306.274 C1160.6 283.647, 1142.5 265.545, 1119.87 261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:3\\\">\\n\",\n              \"<path d=\\\"M1210.38,261.019 C1214.91 283.647, 1233.01 301.749, 1255.64 306.274 C1251.11 283.647, 1233.01 265.545, 1210.38 261.019\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,261.019 C1214.91 283.647, 1233.01 301.749, 1255.64 306.274 C1251.11 283.647, 1233.01 265.545, 1210.38 261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:5\\\">\\n\",\n              \"<path d=\\\"M599.937,599.937 C604.462 622.564, 622.564 640.666, 645.192 645.192 C640.666 622.564, 622.564 604.462, 599.937 599.937\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M599.937,599.937 C604.462 622.564, 622.564 640.666, 645.192 645.192 C640.666 622.564, 622.564 604.462, 599.937 599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:5\\\">\\n\",\n              \"<path d=\\\"M690.446,690.446 C694.972 713.074, 713.074 731.176, 735.701 735.701 C731.176 713.074, 713.074 694.972, 690.446 690.446\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M690.446,690.446 C694.972 713.074, 713.074 731.176, 735.701 735.701 C731.176 713.074, 713.074 694.972, 690.446 690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:5\\\">\\n\",\n              \"<path d=\\\"M780.956,599.937 C785.482 622.564, 803.583 640.666, 826.211 645.192 C821.685 622.564, 803.583 604.462, 780.956 599.937\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M780.956,599.937 C785.482 622.564, 803.583 640.666, 826.211 645.192 C821.685 622.564, 803.583 604.462, 780.956 599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:5\\\">\\n\",\n              \"<path d=\\\"M780.956,690.446 C803.583 685.921, 821.685 667.819, 826.211 645.192 C803.583 649.717, 785.482 667.819, 780.956 690.446\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M780.956,690.446 C803.583 685.921, 821.685 667.819, 826.211 645.192 C803.583 649.717, 785.482 667.819, 780.956 690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:5\\\">\\n\",\n              \"<path d=\\\"M780.956,780.956 C758.329 785.482, 740.227 803.583, 735.701 826.211 C758.329 821.685, 776.431 803.583, 780.956 780.956\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M780.956,780.956 C758.329 785.482, 740.227 803.583, 735.701 826.211 C758.329 821.685, 776.431 803.583, 780.956 780.956\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:1\\\">\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"80\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"80\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:1\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:2\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"80\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"80\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:2\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:3\\\">\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:3\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:4\\\">\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:4\\\">\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:4\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"826.211\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"826.211\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:5\\\">\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:6\\\">\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:6\\\">\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:6\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:6\\\">\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:7\\\">\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:7\\\">\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:7\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:7\\\">\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:8\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:8\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:9\\\">\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1029.36\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1029.36\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:9\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<defs>\\n\",\n              \"<radialGradient id=\\\"xgrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#FF4040\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"<radialGradient id=\\\"ygrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#59FF7A\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"<radialGradient id=\\\"zgrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#4DA6FF\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"</defs>\\n\",\n              \"<g id=\\\"qubit_dots\\\">\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"80\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"335.529\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"351.529\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"80\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"351.529\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"80\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"170.51\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"261.019\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"351.529\\\">H</text>\\n\",\n              \"<path d=\\\"M1119.87,80 L1165.13,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,125.255 L1177.13,125.255 M1165.13,113.255 L1165.13,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,261.019 L1165.13,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,306.274 L1177.13,306.274 M1165.13,294.274 L1165.13,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,170.51 L1255.64,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,215.764 L1267.64,215.764 M1255.64,203.764 L1255.64,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,306.274 L1029.36,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1017.36,261.019 L1041.36,261.019 M1029.36,249.019 L1029.36,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,215.764 L1119.87,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,170.51 L1131.87,170.51 M1119.87,158.51 L1119.87,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,306.274 L1210.38,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,261.019 L1222.38,261.019 M1210.38,249.019 L1210.38,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,554.682 L125.255,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"554.682\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,599.937 L137.255,599.937 M125.255,587.937 L125.255,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,735.701 L125.255,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,780.956 L137.255,780.956 M125.255,768.956 L125.255,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,645.192 L215.764,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,690.446 L227.764,690.446 M215.764,678.446 L215.764,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,690.446 L80,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M68,735.701 L92,735.701 M80,723.701 L80,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,599.937 L170.51,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,645.192 L182.51,645.192 M170.51,633.192 L170.51,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,690.446 L261.019,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,735.701 L273.019,735.701 M261.019,723.701 L261.019,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,735.701 L690.446,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,690.446 L702.446,690.446 M690.446,678.446 L690.446,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,645.192 L780.956,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,599.937 L792.956,599.937 M780.956,587.937 L780.956,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,826.211 L780.956,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"826.211\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,780.956 L792.956,780.956 M780.956,768.956 L780.956,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,690.446 L645.192,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,645.192 L657.192,645.192 M645.192,633.192 L645.192,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,780.956 L735.701,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,735.701 L747.701,735.701 M735.701,723.701 L735.701,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,690.446 L826.211,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M814.211,645.192 L838.211,645.192 M826.211,633.192 L826.211,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,735.701 L1074.62,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1062.62,690.446 L1086.62,690.446 M1074.62,678.446 L1074.62,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,645.192 L1165.13,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,599.937 L1177.13,599.937 M1165.13,587.937 L1165.13,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,826.211 L1165.13,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"826.211\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,780.956 L1177.13,780.956 M1165.13,768.956 L1165.13,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,599.937 L1119.87,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,645.192 L1131.87,645.192 M1119.87,633.192 L1119.87,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,690.446 L1210.38,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,735.701 L1222.38,735.701 M1210.38,723.701 L1210.38,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,599.937 L1300.89,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1288.89,645.192 L1312.89,645.192 M1300.89,633.192 L1300.89,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"1029.36\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"1119.87\\\">H</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"1210.38\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"1300.89\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"1029.36\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"810.211\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"826.211\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"538.682\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"554.682\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"1300.89\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"1029.36\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"1119.87\\\">H</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"1210.38\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"1300.89\\\">H</text>\\n\",\n              \"<g id=\\\"tick_borders\\\">\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-425.529\\\">Tick 0</text>\\n\",\n              \"<rect id=\\\"tick_border:0:0_0:0\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-900.211\\\">Tick 1</text>\\n\",\n              \"<rect id=\\\"tick_border:1:0_1:1\\\" x=\\\"474.682\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-1374.89\\\">Tick 2</text>\\n\",\n              \"<rect id=\\\"tick_border:2:0_2:2\\\" x=\\\"949.364\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-425.529\\\">Tick 3</text>\\n\",\n              \"<rect id=\\\"tick_border:3:1_0:3\\\" x=\\\"0\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-900.211\\\">Tick 4</text>\\n\",\n              \"<rect id=\\\"tick_border:4:1_1:4\\\" x=\\\"474.682\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-1374.89\\\">Tick 5</text>\\n\",\n              \"<rect id=\\\"tick_border:5:1_2:5\\\" x=\\\"949.364\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-425.529\\\">Tick 6</text>\\n\",\n              \"<rect id=\\\"tick_border:6:2_0:6\\\" x=\\\"0\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-900.211\\\">Tick 7</text>\\n\",\n              \"<rect id=\\\"tick_border:7:2_1:7\\\" x=\\\"474.682\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-1374.89\\\">Tick 8</text>\\n\",\n              \"<rect id=\\\"tick_border:8:2_2:8\\\" x=\\\"949.364\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"</svg>\"\n            ],\n            \"text/plain\": [\n              \"<svg viewBox=\\\"0 0 1380.89 1380.89\\\"  version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n\",\n              \"<g id=\\\"slice:2:4_4_0:3\\\">\\n\",\n              \"<path d=\\\"M1165.13,215.764 C1192.28 197.663,1192.28 197.663,1210.38 170.51 L1255.64,215.764 C1228.48 233.866,1228.48 233.866,1210.38 261.019 C1183.23 279.121,1183.23 279.121,1165.13 306.274 L1119.87,261.019 C1147.03 242.917,1147.03 242.917,1165.13 215.764\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,215.764 C1192.28 197.663,1192.28 197.663,1210.38 170.51 L1255.64,215.764 C1228.48 233.866,1228.48 233.866,1210.38 261.019 C1183.23 279.121,1183.23 279.121,1165.13 306.274 L1119.87,261.019 C1147.03 242.917,1147.03 242.917,1165.13 215.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:5\\\">\\n\",\n              \"<path d=\\\"M645.192,645.192 C672.344 627.09,672.344 627.09,690.446 599.937 L735.701,645.192 C708.548 663.293,708.548 663.293,690.446 690.446 C663.293 708.548,663.293 708.548,645.192 735.701 L599.937,690.446 C627.09 672.344,627.09 672.344,645.192 645.192\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M645.192,645.192 C672.344 627.09,672.344 627.09,690.446 599.937 L735.701,645.192 C708.548 663.293,708.548 663.293,690.446 690.446 C663.293 708.548,663.293 708.548,645.192 735.701 L599.937,690.446 C627.09 672.344,627.09 672.344,645.192 645.192\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:5\\\">\\n\",\n              \"<path d=\\\"M735.701,645.192 C762.854 627.09,762.854 627.09,780.956 599.937 L826.211,645.192 C799.058 663.293,799.058 663.293,780.956 690.446 C753.803 708.548,753.803 708.548,735.701 735.701 L690.446,690.446 C717.599 672.344,717.599 672.344,735.701 645.192\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M735.701,645.192 C762.854 627.09,762.854 627.09,780.956 599.937 L826.211,645.192 C799.058 663.293,799.058 663.293,780.956 690.446 C753.803 708.548,753.803 708.548,735.701 735.701 L690.446,690.446 C717.599 672.344,717.599 672.344,735.701 645.192\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:1\\\">\\n\",\n              \"<path d=\\\"M125.255,125.255 L215.764,125.255 L170.51,170.51 L215.764,215.764 L125.255,215.764 L125.255,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M125.255,125.255 L215.764,125.255 L170.51,170.51 L215.764,215.764 L125.255,215.764 L125.255,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:1\\\">\\n\",\n              \"<path d=\\\"M215.764,215.764 L306.274,215.764 L261.019,261.019 L306.274,306.274 L215.764,306.274 L215.764,215.764\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M215.764,215.764 L306.274,215.764 L261.019,261.019 L306.274,306.274 L215.764,306.274 L215.764,215.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:2\\\">\\n\",\n              \"<path d=\\\"M599.937,125.255 L690.446,125.255 L645.192,170.51 L690.446,215.764 L599.937,215.764 L599.937,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M599.937,125.255 L690.446,125.255 L645.192,170.51 L690.446,215.764 L599.937,215.764 L599.937,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:2\\\">\\n\",\n              \"<path d=\\\"M690.446,215.764 L780.956,215.764 L735.701,261.019 L780.956,306.274 L690.446,306.274 L690.446,215.764\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M690.446,215.764 L780.956,215.764 L735.701,261.019 L780.956,306.274 L690.446,306.274 L690.446,215.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:3\\\">\\n\",\n              \"<path d=\\\"M1074.62,125.255 L1119.87,80 L1165.13,125.255 C1137.98 143.357,1137.98 143.357,1119.87 170.51 C1092.72 188.612,1092.72 188.612,1074.62 215.764 L1074.62,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,125.255 L1119.87,80 L1165.13,125.255 C1137.98 143.357,1137.98 143.357,1119.87 170.51 C1092.72 188.612,1092.72 188.612,1074.62 215.764 L1074.62,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:5\\\">\\n\",\n              \"<path d=\\\"M645.192,735.701 C672.344 717.599,672.344 717.599,690.446 690.446 L735.701,735.701 L690.446,780.956 L599.937,780.956 C627.09 762.854,627.09 762.854,645.192 735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M645.192,735.701 C672.344 717.599,672.344 717.599,690.446 690.446 L735.701,735.701 L690.446,780.956 L599.937,780.956 C627.09 762.854,627.09 762.854,645.192 735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:5\\\">\\n\",\n              \"<path d=\\\"M735.701,735.701 C762.854 717.599,762.854 717.599,780.956 690.446 L780.956,780.956 L735.701,826.211 L690.446,780.956 C717.599 762.854,717.599 762.854,735.701 735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M735.701,735.701 C762.854 717.599,762.854 717.599,780.956 690.446 L780.956,780.956 L735.701,826.211 L690.446,780.956 C717.599 762.854,717.599 762.854,735.701 735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1074.62,599.937 L1165.13,599.937 L1119.87,645.192 L1165.13,690.446 L1074.62,690.446 L1074.62,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,599.937 L1165.13,599.937 L1119.87,645.192 L1165.13,690.446 L1074.62,690.446 L1074.62,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1165.13,599.937 L1255.64,599.937 L1210.38,645.192 L1255.64,690.446 L1165.13,690.446 L1165.13,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,599.937 L1255.64,599.937 L1210.38,645.192 L1255.64,690.446 L1165.13,690.446 L1165.13,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1074.62,690.446 L1165.13,690.446 L1119.87,735.701 L1165.13,780.956 L1074.62,780.956 L1074.62,690.446\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,690.446 L1165.13,690.446 L1119.87,735.701 L1165.13,780.956 L1074.62,780.956 L1074.62,690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1165.13,690.446 L1255.64,690.446 L1210.38,735.701 L1255.64,780.956 L1165.13,780.956 L1165.13,690.446\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,690.446 L1255.64,690.446 L1210.38,735.701 L1255.64,780.956 L1165.13,780.956 L1165.13,690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:7\\\">\\n\",\n              \"<path d=\\\"M125.255,1074.62 L215.764,1074.62 L170.51,1119.87 L215.764,1165.13 L125.255,1165.13 L125.255,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M125.255,1074.62 L215.764,1074.62 L170.51,1119.87 L215.764,1165.13 L125.255,1165.13 L125.255,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:7\\\">\\n\",\n              \"<path d=\\\"M215.764,1074.62 L306.274,1074.62 L261.019,1119.87 L306.274,1165.13 L215.764,1165.13 L215.764,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip0\\\"><path d=\\\"M215.764,1074.62 L306.274,1074.62 L261.019,1119.87 L306.274,1165.13 L215.764,1165.13 L215.764,1074.62\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"306.274\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"261.019\\\" cy=\\\"1119.87\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip0)\\\" cx=\\\"306.274\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1074.62 L306.274,1074.62 L261.019,1119.87 L306.274,1165.13 L215.764,1165.13 L215.764,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:7\\\">\\n\",\n              \"<path d=\\\"M125.255,1165.13 L215.764,1165.13 L170.51,1210.38 L215.764,1255.64 L125.255,1255.64 L125.255,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip1\\\"><path d=\\\"M125.255,1165.13 L215.764,1165.13 L170.51,1210.38 L215.764,1255.64 L125.255,1255.64 L125.255,1165.13\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"125.255\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"125.255\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"170.51\\\" cy=\\\"1210.38\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip1)\\\" cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M125.255,1165.13 L215.764,1165.13 L170.51,1210.38 L215.764,1255.64 L125.255,1255.64 L125.255,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:7\\\">\\n\",\n              \"<path d=\\\"M215.764,1165.13 L306.274,1165.13 L261.019,1210.38 L306.274,1255.64 L215.764,1255.64 L215.764,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1165.13 L306.274,1165.13 L261.019,1210.38 L306.274,1255.64 L215.764,1255.64 L215.764,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:8\\\">\\n\",\n              \"<path d=\\\"M599.937,1074.62 L690.446,1074.62 L645.192,1119.87 L690.446,1165.13 L599.937,1165.13 L599.937,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M599.937,1074.62 L690.446,1074.62 L645.192,1119.87 L690.446,1165.13 L599.937,1165.13 L599.937,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:8\\\">\\n\",\n              \"<path d=\\\"M690.446,1074.62 L780.956,1074.62 L735.701,1119.87 L780.956,1165.13 L690.446,1165.13 L690.446,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip2\\\"><path d=\\\"M690.446,1074.62 L780.956,1074.62 L735.701,1119.87 L780.956,1165.13 L690.446,1165.13 L690.446,1074.62\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"780.956\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip2)\\\" cx=\\\"780.956\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1074.62 L780.956,1074.62 L735.701,1119.87 L780.956,1165.13 L690.446,1165.13 L690.446,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:8\\\">\\n\",\n              \"<path d=\\\"M599.937,1165.13 L690.446,1165.13 L645.192,1210.38 L690.446,1255.64 L599.937,1255.64 L599.937,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip3\\\"><path d=\\\"M599.937,1165.13 L690.446,1165.13 L645.192,1210.38 L690.446,1255.64 L599.937,1255.64 L599.937,1165.13\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"599.937\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"599.937\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip3)\\\" cx=\\\"690.446\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M599.937,1165.13 L690.446,1165.13 L645.192,1210.38 L690.446,1255.64 L599.937,1255.64 L599.937,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:8\\\">\\n\",\n              \"<path d=\\\"M690.446,1165.13 L780.956,1165.13 L735.701,1210.38 L780.956,1255.64 L690.446,1255.64 L690.446,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1165.13 L780.956,1165.13 L735.701,1210.38 L780.956,1255.64 L690.446,1255.64 L690.446,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:9\\\">\\n\",\n              \"<path d=\\\"M1074.62,1074.62 L1165.13,1074.62 L1119.87,1119.87 L1165.13,1165.13 L1074.62,1165.13 L1074.62,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,1074.62 L1165.13,1074.62 L1119.87,1119.87 L1165.13,1165.13 L1074.62,1165.13 L1074.62,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:9\\\">\\n\",\n              \"<path d=\\\"M1165.13,1074.62 L1255.64,1074.62 L1210.38,1119.87 L1255.64,1165.13 L1165.13,1165.13 L1165.13,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1074.62 L1255.64,1074.62 L1210.38,1119.87 L1255.64,1165.13 L1165.13,1165.13 L1165.13,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:9\\\">\\n\",\n              \"<path d=\\\"M1074.62,1165.13 L1165.13,1165.13 L1119.87,1210.38 L1165.13,1255.64 L1074.62,1255.64 L1074.62,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,1165.13 L1165.13,1165.13 L1119.87,1210.38 L1165.13,1255.64 L1074.62,1255.64 L1074.62,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:9\\\">\\n\",\n              \"<path d=\\\"M1165.13,1165.13 L1255.64,1165.13 L1210.38,1210.38 L1255.64,1255.64 L1165.13,1255.64 L1165.13,1165.13\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1165.13 L1255.64,1165.13 L1210.38,1210.38 L1255.64,1255.64 L1165.13,1255.64 L1165.13,1165.13\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:3\\\">\\n\",\n              \"<path d=\\\"M1210.38,170.51 L1255.64,125.255 L1300.89,170.51 L1255.64,215.764 L1210.38,170.51\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,170.51 L1255.64,125.255 L1300.89,170.51 L1255.64,215.764 L1210.38,170.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:4\\\">\\n\",\n              \"<path d=\\\"M170.51,735.701 L215.764,690.446 L261.019,735.701 L215.764,780.956 L170.51,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M170.51,735.701 L215.764,690.446 L261.019,735.701 L215.764,780.956 L170.51,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:4\\\">\\n\",\n              \"<path d=\\\"M261.019,645.192 L306.274,599.937 L351.529,645.192 L306.274,690.446 L261.019,645.192\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M261.019,645.192 L306.274,599.937 L351.529,645.192 L306.274,690.446 L261.019,645.192\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:4\\\">\\n\",\n              \"<path d=\\\"M125.255,599.937 L170.51,554.682 L215.764,599.937 L170.51,645.192 L125.255,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M125.255,599.937 L170.51,554.682 L215.764,599.937 L170.51,645.192 L125.255,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:4\\\">\\n\",\n              \"<path d=\\\"M170.51,645.192 L215.764,599.937 L261.019,645.192 L215.764,690.446 L170.51,645.192\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M170.51,645.192 L215.764,599.937 L261.019,645.192 L215.764,690.446 L170.51,645.192\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:4\\\">\\n\",\n              \"<path d=\\\"M215.764,690.446 L261.019,645.192 L306.274,690.446 L261.019,735.701 L215.764,690.446\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M215.764,690.446 L261.019,645.192 L306.274,690.446 L261.019,735.701 L215.764,690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:4\\\">\\n\",\n              \"<path d=\\\"M80,735.701 L125.255,690.446 L170.51,735.701 L125.255,780.956 L80,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M80,735.701 L125.255,690.446 L170.51,735.701 L125.255,780.956 L80,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:5\\\">\\n\",\n              \"<path d=\\\"M599.937,599.937 L645.192,554.682 L690.446,599.937 L645.192,645.192 L599.937,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M599.937,599.937 L645.192,554.682 L690.446,599.937 L645.192,645.192 L599.937,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:5\\\">\\n\",\n              \"<path d=\\\"M554.682,735.701 L599.937,690.446 L645.192,735.701 L599.937,780.956 L554.682,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M554.682,735.701 L599.937,690.446 L645.192,735.701 L599.937,780.956 L554.682,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:1\\\">\\n\",\n              \"<path d=\\\"M80,261.019 L125.255,215.764 L125.255,306.274 L80,261.019\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M80,261.019 L125.255,215.764 L125.255,306.274 L80,261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:1\\\">\\n\",\n              \"<path d=\\\"M306.274,125.255 L351.529,170.51 L306.274,215.764 L306.274,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M306.274,125.255 L351.529,170.51 L306.274,215.764 L306.274,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:2\\\">\\n\",\n              \"<path d=\\\"M554.682,261.019 L599.937,215.764 L599.937,306.274 L554.682,261.019\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M554.682,261.019 L599.937,215.764 L599.937,306.274 L554.682,261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:2\\\">\\n\",\n              \"<path d=\\\"M780.956,125.255 L826.211,170.51 L780.956,215.764 L780.956,125.255\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M780.956,125.255 L826.211,170.51 L780.956,215.764 L780.956,125.255\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:4\\\">\\n\",\n              \"<path d=\\\"M125.255,599.937 L170.51,645.192 L125.255,690.446 L125.255,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M125.255,599.937 L170.51,645.192 L125.255,690.446 L125.255,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:4\\\">\\n\",\n              \"<path d=\\\"M170.51,735.701 L215.764,780.956 L125.255,780.956 L170.51,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M170.51,735.701 L215.764,780.956 L125.255,780.956 L170.51,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:4\\\">\\n\",\n              \"<path d=\\\"M261.019,735.701 L306.274,690.446 L306.274,780.956 L261.019,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M261.019,735.701 L306.274,690.446 L306.274,780.956 L261.019,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:6\\\">\\n\",\n              \"<path d=\\\"M1119.87,554.682 L1165.13,599.937 L1074.62,599.937 L1119.87,554.682\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,554.682 L1165.13,599.937 L1074.62,599.937 L1119.87,554.682\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:6\\\">\\n\",\n              \"<path d=\\\"M1255.64,599.937 L1300.89,645.192 L1255.64,690.446 L1255.64,599.937\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,599.937 L1300.89,645.192 L1255.64,690.446 L1255.64,599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:6\\\">\\n\",\n              \"<path d=\\\"M1029.36,735.701 L1074.62,690.446 L1074.62,780.956 L1029.36,735.701\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.36,735.701 L1074.62,690.446 L1074.62,780.956 L1029.36,735.701\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:6\\\">\\n\",\n              \"<path d=\\\"M1165.13,780.956 L1255.64,780.956 L1210.38,826.211 L1165.13,780.956\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,780.956 L1255.64,780.956 L1210.38,826.211 L1165.13,780.956\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:7\\\">\\n\",\n              \"<path d=\\\"M170.51,1029.36 L215.764,1074.62 L125.255,1074.62 L170.51,1029.36\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip4\\\"><path d=\\\"M170.51,1029.36 L215.764,1074.62 L125.255,1074.62 L170.51,1029.36\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"125.255\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"170.51\\\" cy=\\\"1029.36\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip4)\\\" cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M170.51,1029.36 L215.764,1074.62 L125.255,1074.62 L170.51,1029.36\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:7\\\">\\n\",\n              \"<path d=\\\"M306.274,1074.62 L351.529,1119.87 L306.274,1165.13 L306.274,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M306.274,1074.62 L351.529,1119.87 L306.274,1165.13 L306.274,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:7\\\">\\n\",\n              \"<path d=\\\"M80,1210.38 L125.255,1165.13 L125.255,1255.64 L80,1210.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M80,1210.38 L125.255,1165.13 L125.255,1255.64 L80,1210.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:7\\\">\\n\",\n              \"<path d=\\\"M215.764,1255.64 L306.274,1255.64 L261.019,1300.89 L215.764,1255.64\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip5\\\"><path d=\\\"M215.764,1255.64 L306.274,1255.64 L261.019,1300.89 L215.764,1255.64\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"306.274\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip5)\\\" cx=\\\"261.019\\\" cy=\\\"1300.89\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M215.764,1255.64 L306.274,1255.64 L261.019,1300.89 L215.764,1255.64\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:8\\\">\\n\",\n              \"<path d=\\\"M645.192,1029.36 L690.446,1074.62 L599.937,1074.62 L645.192,1029.36\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip6\\\"><path d=\\\"M645.192,1029.36 L690.446,1074.62 L599.937,1074.62 L645.192,1029.36\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"599.937\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip6)\\\" cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<path d=\\\"M645.192,1029.36 L690.446,1074.62 L599.937,1074.62 L645.192,1029.36\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:8\\\">\\n\",\n              \"<path d=\\\"M780.956,1074.62 L826.211,1119.87 L780.956,1165.13 L780.956,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M780.956,1074.62 L826.211,1119.87 L780.956,1165.13 L780.956,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:8\\\">\\n\",\n              \"<path d=\\\"M554.682,1210.38 L599.937,1165.13 L599.937,1255.64 L554.682,1210.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M554.682,1210.38 L599.937,1165.13 L599.937,1255.64 L554.682,1210.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:8\\\">\\n\",\n              \"<path d=\\\"M690.446,1255.64 L780.956,1255.64 L735.701,1300.89 L690.446,1255.64\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#AAAAAA\\\"/>\\n\",\n              \"<clipPath id=\\\"clip7\\\"><path d=\\\"M690.446,1255.64 L780.956,1255.64 L735.701,1300.89 L690.446,1255.64\\\"/></clipPath>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"690.446\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"780.956\\\" cy=\\\"1255.64\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#xgrad')\\\"/>\\n\",\n              \"<circle clip-path=\\\"url(#clip7)\\\" cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"43\\\" stroke=\\\"none\\\" fill=\\\"url('#zgrad')\\\"/>\\n\",\n              \"<path d=\\\"M690.446,1255.64 L780.956,1255.64 L735.701,1300.89 L690.446,1255.64\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:9\\\">\\n\",\n              \"<path d=\\\"M1119.87,1029.36 L1165.13,1074.62 L1074.62,1074.62 L1119.87,1029.36\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,1029.36 L1165.13,1074.62 L1074.62,1074.62 L1119.87,1029.36\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:9\\\">\\n\",\n              \"<path d=\\\"M1255.64,1074.62 L1300.89,1119.87 L1255.64,1165.13 L1255.64,1074.62\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,1074.62 L1300.89,1119.87 L1255.64,1165.13 L1255.64,1074.62\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:9\\\">\\n\",\n              \"<path d=\\\"M1029.36,1210.38 L1074.62,1165.13 L1074.62,1255.64 L1029.36,1210.38\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.36,1210.38 L1074.62,1165.13 L1074.62,1255.64 L1029.36,1210.38\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:9\\\">\\n\",\n              \"<path d=\\\"M1165.13,1255.64 L1255.64,1255.64 L1210.38,1300.89 L1165.13,1255.64\\\" stroke=\\\"none\\\" fill-opacity=\\\"0.75\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,1255.64 L1255.64,1255.64 L1210.38,1300.89 L1165.13,1255.64\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:3\\\">\\n\",\n              \"<path d=\\\"M1074.62,215.764 C1051.99 220.29, 1033.89 238.392, 1029.36 261.019 C1051.99 256.494, 1070.09 238.392, 1074.62 215.764\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,215.764 C1051.99 220.29, 1033.89 238.392, 1029.36 261.019 C1051.99 256.494, 1070.09 238.392, 1074.62 215.764\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:3\\\">\\n\",\n              \"<path d=\\\"M1119.87,80 C1124.4 102.627, 1142.5 120.729, 1165.13 125.255 C1160.6 102.627, 1142.5 84.5255, 1119.87 80\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,80 C1124.4 102.627, 1142.5 120.729, 1165.13 125.255 C1160.6 102.627, 1142.5 84.5255, 1119.87 80\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:3\\\">\\n\",\n              \"<path d=\\\"M1119.87,170.51 C1124.4 193.137, 1142.5 211.239, 1165.13 215.764 C1160.6 193.137, 1142.5 175.035, 1119.87 170.51\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,170.51 C1124.4 193.137, 1142.5 211.239, 1165.13 215.764 C1160.6 193.137, 1142.5 175.035, 1119.87 170.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:3\\\">\\n\",\n              \"<path d=\\\"M1210.38,170.51 C1214.91 193.137, 1233.01 211.239, 1255.64 215.764 C1251.11 193.137, 1233.01 175.035, 1210.38 170.51\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,170.51 C1214.91 193.137, 1233.01 211.239, 1255.64 215.764 C1251.11 193.137, 1233.01 175.035, 1210.38 170.51\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:3\\\">\\n\",\n              \"<path d=\\\"M1029.36,261.019 C1033.89 283.647, 1051.99 301.749, 1074.62 306.274 C1070.09 283.647, 1051.99 265.545, 1029.36 261.019\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1029.36,261.019 C1033.89 283.647, 1051.99 301.749, 1074.62 306.274 C1070.09 283.647, 1051.99 265.545, 1029.36 261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:3\\\">\\n\",\n              \"<path d=\\\"M1119.87,261.019 C1124.4 283.647, 1142.5 301.749, 1165.13 306.274 C1160.6 283.647, 1142.5 265.545, 1119.87 261.019\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,261.019 C1124.4 283.647, 1142.5 301.749, 1165.13 306.274 C1160.6 283.647, 1142.5 265.545, 1119.87 261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:3\\\">\\n\",\n              \"<path d=\\\"M1210.38,261.019 C1214.91 283.647, 1233.01 301.749, 1255.64 306.274 C1251.11 283.647, 1233.01 265.545, 1210.38 261.019\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,261.019 C1214.91 283.647, 1233.01 301.749, 1255.64 306.274 C1251.11 283.647, 1233.01 265.545, 1210.38 261.019\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:5\\\">\\n\",\n              \"<path d=\\\"M599.937,599.937 C604.462 622.564, 622.564 640.666, 645.192 645.192 C640.666 622.564, 622.564 604.462, 599.937 599.937\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M599.937,599.937 C604.462 622.564, 622.564 640.666, 645.192 645.192 C640.666 622.564, 622.564 604.462, 599.937 599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:5\\\">\\n\",\n              \"<path d=\\\"M690.446,690.446 C694.972 713.074, 713.074 731.176, 735.701 735.701 C731.176 713.074, 713.074 694.972, 690.446 690.446\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M690.446,690.446 C694.972 713.074, 713.074 731.176, 735.701 735.701 C731.176 713.074, 713.074 694.972, 690.446 690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:5\\\">\\n\",\n              \"<path d=\\\"M780.956,599.937 C785.482 622.564, 803.583 640.666, 826.211 645.192 C821.685 622.564, 803.583 604.462, 780.956 599.937\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M780.956,599.937 C785.482 622.564, 803.583 640.666, 826.211 645.192 C821.685 622.564, 803.583 604.462, 780.956 599.937\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:5\\\">\\n\",\n              \"<path d=\\\"M780.956,690.446 C803.583 685.921, 821.685 667.819, 826.211 645.192 C803.583 649.717, 785.482 667.819, 780.956 690.446\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<path d=\\\"M780.956,690.446 C803.583 685.921, 821.685 667.819, 826.211 645.192 C803.583 649.717, 785.482 667.819, 780.956 690.446\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:5\\\">\\n\",\n              \"<path d=\\\"M780.956,780.956 C758.329 785.482, 740.227 803.583, 735.701 826.211 C758.329 821.685, 776.431 803.583, 780.956 780.956\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<path d=\\\"M780.956,780.956 C758.329 785.482, 740.227 803.583, 735.701 826.211 C758.329 821.685, 776.431 803.583, 780.956 780.956\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:1\\\">\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"80\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"80\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:1\\\">\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:1\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:1\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:4:2_0_1:2\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"80\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"80\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:5:2_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:6:4_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:2\\\">\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:8:0_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:9:2_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:10:4_4_1:2\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"261.019\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:2\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:3\\\">\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"170.51\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:3\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"351.529\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:4\\\">\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:7:6_2_1:4\\\">\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:11:4_6_1:4\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"826.211\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"826.211\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:5\\\">\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:6\\\">\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:6\\\">\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:6\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:6\\\">\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:0:0_4_0:7\\\">\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:1:2_2_0:7\\\">\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:2:4_4_0:7\\\">\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:3:6_2_0:7\\\">\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"351.529\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:8\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:8\\\">\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:8\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:8\\\">\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:12:2_0_2:9\\\">\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1029.36\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1029.36\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:13:2_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:14:4_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:15:6_2_2:9\\\">\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:16:0_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:17:2_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:18:4_4_2:9\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#4DA6FF\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<g id=\\\"slice:19:4_6_2:9\\\">\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"24\\\" stroke=\\\"none\\\" fill=\\\"#FF4040\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"24\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<defs>\\n\",\n              \"<radialGradient id=\\\"xgrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#FF4040\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"<radialGradient id=\\\"ygrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#59FF7A\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"<radialGradient id=\\\"zgrad\\\"><stop offset=\\\"50%\\\" stop-color=\\\"#4DA6FF\\\" stop-opacity=\\\"1\\\"/><stop offset=\\\"100%\\\" stop-color=\\\"#AAAAAA\\\" stop-opacity=\\\"0\\\"/></radialGradient>\\n\",\n              \"</defs>\\n\",\n              \"<g id=\\\"qubit_dots\\\">\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:0\\\" cx=\\\"125.255\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:0\\\" cx=\\\"170.51\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:0\\\" cx=\\\"215.764\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:0\\\" cx=\\\"306.274\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:0\\\" cx=\\\"125.255\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:0\\\" cx=\\\"170.51\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:0\\\" cx=\\\"215.764\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:0\\\" cx=\\\"261.019\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:0\\\" cx=\\\"306.274\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:0\\\" cx=\\\"351.529\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:0\\\" cx=\\\"80\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:0\\\" cx=\\\"125.255\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:0\\\" cx=\\\"170.51\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:0\\\" cx=\\\"215.764\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:0\\\" cx=\\\"261.019\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:0\\\" cx=\\\"306.274\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:0\\\" cx=\\\"261.019\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:1\\\" cx=\\\"599.937\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:1\\\" cx=\\\"645.192\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:1\\\" cx=\\\"690.446\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:1\\\" cx=\\\"780.956\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:1\\\" cx=\\\"599.937\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:1\\\" cx=\\\"645.192\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:1\\\" cx=\\\"690.446\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:1\\\" cx=\\\"735.701\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:1\\\" cx=\\\"780.956\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:1\\\" cx=\\\"826.211\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:1\\\" cx=\\\"554.682\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:1\\\" cx=\\\"599.937\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:1\\\" cx=\\\"645.192\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:1\\\" cx=\\\"690.446\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:1\\\" cx=\\\"735.701\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:1\\\" cx=\\\"780.956\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:1\\\" cx=\\\"735.701\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"80\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"125.255\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"215.764\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"170.51\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"261.019\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"306.274\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"351.529\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"554.682\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"599.937\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"690.446\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"780.956\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"826.211\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:1:1_1:2\\\" cx=\\\"1074.62\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:2:2_0:2\\\" cx=\\\"1119.87\\\" cy=\\\"1029.36\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:3:3_1:2\\\" cx=\\\"1165.13\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:5:5_1:2\\\" cx=\\\"1255.64\\\" cy=\\\"1074.62\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:8:1_3:2\\\" cx=\\\"1074.62\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:9:2_2:2\\\" cx=\\\"1119.87\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:10:3_3:2\\\" cx=\\\"1165.13\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:11:4_2:2\\\" cx=\\\"1210.38\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:12:5_3:2\\\" cx=\\\"1255.64\\\" cy=\\\"1165.13\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:13:6_2:2\\\" cx=\\\"1300.89\\\" cy=\\\"1119.87\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:14:0_4:2\\\" cx=\\\"1029.36\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:15:1_5:2\\\" cx=\\\"1074.62\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:16:2_4:2\\\" cx=\\\"1119.87\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:17:3_5:2\\\" cx=\\\"1165.13\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:18:4_4:2\\\" cx=\\\"1210.38\\\" cy=\\\"1210.38\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:19:5_5:2\\\" cx=\\\"1255.64\\\" cy=\\\"1255.64\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle id=\\\"qubit_dot:25:4_6:2\\\" cx=\\\"1210.38\\\" cy=\\\"1300.89\\\" r=\\\"2\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"</g>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"109.255\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"125.255\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"199.764\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"215.764\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"109.255\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"125.255\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"199.764\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"215.764\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"290.274\\\" y=\\\"290.274\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"306.274\\\" y=\\\"306.274\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"80\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"335.529\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"351.529\\\" y=\\\"170.51\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"64\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"80\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"261.019\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"351.529\\\" fill=\\\"white\\\">R</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"64\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"80\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"154.51\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"170.51\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"245.019\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"645.192\\\" y=\\\"261.019\\\">H</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"335.529\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"735.701\\\" y=\\\"351.529\\\">H</text>\\n\",\n              \"<path d=\\\"M1119.87,80 L1165.13,125.255 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"80\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"125.255\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,125.255 L1177.13,125.255 M1165.13,113.255 L1165.13,137.255 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,261.019 L1165.13,306.274 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,306.274 L1177.13,306.274 M1165.13,294.274 L1165.13,318.274 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,170.51 L1255.64,215.764 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1243.64,215.764 L1267.64,215.764 M1255.64,203.764 L1255.64,227.764 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,306.274 L1029.36,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1029.36\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1017.36,261.019 L1041.36,261.019 M1029.36,249.019 L1029.36,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,215.764 L1119.87,170.51 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"215.764\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"170.51\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,170.51 L1131.87,170.51 M1119.87,158.51 L1119.87,182.51 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,306.274 L1210.38,261.019 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"306.274\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"261.019\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,261.019 L1222.38,261.019 M1210.38,249.019 L1210.38,273.019 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,554.682 L125.255,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"554.682\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,599.937 L137.255,599.937 M125.255,587.937 L125.255,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M170.51,735.701 L125.255,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M113.255,780.956 L137.255,780.956 M125.255,768.956 L125.255,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M261.019,645.192 L215.764,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M203.764,690.446 L227.764,690.446 M215.764,678.446 L215.764,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M125.255,690.446 L80,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"125.255\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"80\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M68,735.701 L92,735.701 M80,723.701 L80,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M215.764,599.937 L170.51,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"215.764\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"170.51\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M158.51,645.192 L182.51,645.192 M170.51,633.192 L170.51,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M306.274,690.446 L261.019,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"306.274\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"261.019\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M249.019,735.701 L273.019,735.701 M261.019,723.701 L261.019,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M645.192,735.701 L690.446,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M678.446,690.446 L702.446,690.446 M690.446,678.446 L690.446,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,645.192 L780.956,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,599.937 L792.956,599.937 M780.956,587.937 L780.956,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M735.701,826.211 L780.956,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"826.211\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M768.956,780.956 L792.956,780.956 M780.956,768.956 L780.956,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M599.937,690.446 L645.192,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"599.937\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"645.192\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M633.192,645.192 L657.192,645.192 M645.192,633.192 L645.192,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M690.446,780.956 L735.701,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"690.446\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"735.701\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M723.701,735.701 L747.701,735.701 M735.701,723.701 L735.701,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M780.956,690.446 L826.211,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"780.956\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"826.211\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M814.211,645.192 L838.211,645.192 M826.211,633.192 L826.211,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1119.87,735.701 L1074.62,690.446 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1062.62,690.446 L1086.62,690.446 M1074.62,678.446 L1074.62,702.446 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,645.192 L1165.13,599.937 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,599.937 L1177.13,599.937 M1165.13,587.937 L1165.13,611.937 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1210.38,826.211 L1165.13,780.956 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"826.211\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"780.956\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1153.13,780.956 L1177.13,780.956 M1165.13,768.956 L1165.13,792.956 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1074.62,599.937 L1119.87,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1074.62\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1119.87\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1107.87,645.192 L1131.87,645.192 M1119.87,633.192 L1119.87,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1165.13,690.446 L1210.38,735.701 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1165.13\\\" cy=\\\"690.446\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1210.38\\\" cy=\\\"735.701\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1198.38,735.701 L1222.38,735.701 M1210.38,723.701 L1210.38,747.701 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<path d=\\\"M1255.64,599.937 L1300.89,645.192 \\\" fill=\\\"none\\\" stroke=\\\"black\\\" stroke-width=\\\"5\\\"/>\\n\",\n              \"<circle cx=\\\"1255.64\\\" cy=\\\"599.937\\\" r=\\\"12\\\" stroke=\\\"none\\\" fill=\\\"black\\\"/>\\n\",\n              \"<circle cx=\\\"1300.89\\\" cy=\\\"645.192\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<path d=\\\"M1288.89,645.192 L1312.89,645.192 M1300.89,633.192 L1300.89,657.192 \\\" stroke=\\\"black\\\"/>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"1029.36\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"1119.87\\\">H</text>\\n\",\n              \"<rect x=\\\"154.51\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"170.51\\\" y=\\\"1210.38\\\">H</text>\\n\",\n              \"<rect x=\\\"245.019\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"261.019\\\" y=\\\"1300.89\\\">H</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"1029.36\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"810.211\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"826.211\\\" y=\\\"1119.87\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"538.682\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"554.682\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"629.192\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"645.192\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"1210.38\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"719.701\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"black\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"24\\\" x=\\\"735.701\\\" y=\\\"1300.89\\\" fill=\\\"white\\\">MR</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"1013.36\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"1029.36\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"1103.87\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"1119.87\\\">H</text>\\n\",\n              \"<rect x=\\\"1103.87\\\" y=\\\"1194.38\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1119.87\\\" y=\\\"1210.38\\\">H</text>\\n\",\n              \"<rect x=\\\"1194.38\\\" y=\\\"1284.89\\\" width=\\\"32\\\" height=\\\"32\\\" stroke=\\\"black\\\" fill=\\\"white\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"central\\\" text-anchor=\\\"middle\\\" font-family=\\\"monospace\\\" font-size=\\\"30\\\" x=\\\"1210.38\\\" y=\\\"1300.89\\\">H</text>\\n\",\n              \"<g id=\\\"tick_borders\\\">\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-425.529\\\">Tick 0</text>\\n\",\n              \"<rect id=\\\"tick_border:0:0_0:0\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-900.211\\\">Tick 1</text>\\n\",\n              \"<rect id=\\\"tick_border:1:0_1:1\\\" x=\\\"474.682\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"215.764\\\" y=\\\"-1374.89\\\">Tick 2</text>\\n\",\n              \"<rect id=\\\"tick_border:2:0_2:2\\\" x=\\\"949.364\\\" y=\\\"0\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-425.529\\\">Tick 3</text>\\n\",\n              \"<rect id=\\\"tick_border:3:1_0:3\\\" x=\\\"0\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-900.211\\\">Tick 4</text>\\n\",\n              \"<rect id=\\\"tick_border:4:1_1:4\\\" x=\\\"474.682\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"690.446\\\" y=\\\"-1374.89\\\">Tick 5</text>\\n\",\n              \"<rect id=\\\"tick_border:5:1_2:5\\\" x=\\\"949.364\\\" y=\\\"474.682\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-425.529\\\">Tick 6</text>\\n\",\n              \"<rect id=\\\"tick_border:6:2_0:6\\\" x=\\\"0\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-900.211\\\">Tick 7</text>\\n\",\n              \"<rect id=\\\"tick_border:7:2_1:7\\\" x=\\\"474.682\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"<text dominant-baseline=\\\"hanging\\\" text-anchor=\\\"middle\\\" font-family=\\\"serif\\\" font-size=\\\"18\\\" transform=\\\"rotate(90)\\\" x=\\\"1165.13\\\" y=\\\"-1374.89\\\">Tick 8</text>\\n\",\n              \"<rect id=\\\"tick_border:8:2_2:8\\\" x=\\\"949.364\\\" y=\\\"949.364\\\" width=\\\"431.529\\\" height=\\\"431.529\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\",\n              \"</g>\\n\",\n              \"</svg>\"\n            ]\n          },\n          \"execution_count\": 33,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"surface_code_circuit.without_noise().diagram(\\n\",\n        \"    \\\"detslice-with-ops-svg\\\",\\n\",\n        \"    tick=range(0, 9),\\n\",\n        \")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"K75kGz3IWYAW\"\n      },\n      \"source\": [\n        \"Notice that when you created this surface code circuit, you specified a lot more error parameters.\\n\",\n        \"These parameters are adding full circuit noise, instead of just phenomenological noise.\\n\",\n        \"Because the noise is richer, and because this is a quantum code instead of a classical code, the decoding problem is much harder and threshold is going to be noticeably lower.\\n\",\n        \"Looking at the match graph, you can see `pymatching` has a much more complicated problem to solve than before!\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\",\n          \"height\": 404\n        },\n        \"id\": \"VWqbGm3ygkkp\",\n        \"outputId\": \"d95d3bed-f7bf-4925-a0dc-2fecc2fb8e91\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"text/html\": [\n              \"<iframe style=\\\"width: 100%; height: 300px; overflow: hidden; resize: both; border: 1px dashed gray;\\\" frameBorder=\\\"0\\\" srcdoc=\\\"\\n\",\n              \"&lt;!DOCTYPE html&gt;\\n\",\n              \"&lt;html&gt;\\n\",\n              \"&lt;head&gt;\\n\",\n              \"  &lt;meta charset=&quot;UTF-8&quot; /&gt;\\n\",\n              \"  &lt;script type=&quot;importmap&quot;&gt;\\n\",\n              \"    {\\n\",\n              \"      &quot;imports&quot;: {\\n\",\n              \"        &quot;three&quot;: &quot;https://unpkg.com/three@0.138.0/build/three.module.js&quot;,\\n\",\n              \"        &quot;three-orbitcontrols&quot;: &quot;https://unpkg.com/three@0.138.0/examples/jsm/controls/OrbitControls.js&quot;,\\n\",\n              \"        &quot;three-gltf-loader&quot;: &quot;https://unpkg.com/three@0.138.0/examples/jsm/loaders/GLTFLoader.js&quot;\\n\",\n              \"      }\\n\",\n              \"    }\\n\",\n              \"  &lt;/script&gt;\\n\",\n              \"&lt;/head&gt;\\n\",\n              \"&lt;body&gt;\\n\",\n              \"  &lt;a download=&quot;model.gltf&quot; id=&quot;stim-3d-viewer-download-link&quot; href=&quot;data:text/plain;base64,eyJhY2Nlc3NvcnMiOlt7ImJ1ZmZlclZpZXciOjAsImJ5dGVPZmZzZXQiOjAsImNvbXBvbmVudFR5cGUiOjUxMjYsImNvdW50Ijo5LCJtYXgiOlswLDAuNDAwMDAwMDA1OTYwNDY0LDAuNDAwMDAwMDA1OTYwNDY0XSwibWluIjpbMCwtMC40MDAwMDAwMDU5NjA0NjQsLTAuNDAwMDAwMDA1OTYwNDY0XSwibmFtZSI6ImNpcmNsZV9sb29wIiwidHlwZSI6IlZFQzMifSx7ImJ1ZmZlclZpZXciOjEsImJ5dGVPZmZzZXQiOjAsImNvbXBvbmVudFR5cGUiOjUxMjYsImNvdW50Ijo5LCJtYXgiOlswLjQwMDAwMDAwNTk2MDQ2NCwwLDAuNDAwMDAwMDA1OTYwNDY0XSwibWluIjpbLTAuNDAwMDAwMDA1OTYwNDY0LDAsLTAuNDAwMDAwMDA1OTYwNDY0XSwibmFtZSI6ImNpcmNsZV9sb29wIiwidHlwZSI6IlZFQzMifSx7ImJ1ZmZlclZpZXciOjIsImJ5dGVPZmZzZXQiOjAsImNvbXBvbmVudFR5cGUiOjUxMjYsImNvdW50Ijo5LCJtYXgiOlswLjQwMDAwMDAwNTk2MDQ2NCwwLjQwMDAwMDAwNTk2MDQ2NCwwXSwibWluIjpbLTAuNDAwMDAwMDA1OTYwNDY0LC0wLjQwMDAwMDAwNTk2MDQ2NCwwXSwibmFtZSI6ImNpcmNsZV9sb29wIiwidHlwZSI6IlZFQzMifSx7ImJ1ZmZlclZpZXciOjMsImJ5dGVPZmZzZXQiOjAsImNvbXBvbmVudFR5cGUiOjUxMjYsImNvdW50Ijo5LCJtYXgiOlswLDAuNDAwMDAwMDA1OTYwNDY0LDAuNDAwMDAwMDA1OTYwNDY0XSwibWluIjpbMCwtMC40MDAwMDAwMDU5NjA0NjQsLTAuNDAwMDAwMDA1OTYwNDY0XSwibmFtZSI6ImNpcmNsZV9sb29wIiwidHlwZSI6IlZFQzMifSx7ImJ1ZmZlclZpZXciOjQsImJ5dGVPZmZzZXQiOjAsImNvbXBvbmVudFR5cGUiOjUxMjYsImNvdW50Ijo5LCJtYXgiOlswLjQwMDAwMDAwNTk2MDQ2NCwwLDAuNDAwMDAwMDA1OTYwNDY0XSwibWluIjpbLTAuNDAwMDAwMDA1OTYwNDY0LDAsLTAuNDAwMDAwMDA1OTYwNDY0XSwibmFtZSI6ImNpcmNsZV9sb29wIiwidHlwZSI6IlZFQzMifSx7ImJ1ZmZlclZpZXciOjUsImJ5dGVPZmZzZXQiOjAsImNvbXBvbmVudFR5cGUiOjUxMjYsImNvdW50Ijo5LCJtYXgiOlswLjQwMDAwMDAwNTk2MDQ2NCwwLjQwMDAwMDAwNTk2MDQ2NCwwXSwibWluIjpbLTAuNDAwMDAwMDA1OTYwNDY0LC0wLjQwMDAwMDAwNTk2MDQ2NCwwXSwibmFtZSI6ImNpcmNsZV9sb29wIiwidHlwZSI6IlZFQzMifSx7ImJ1ZmZlclZpZXciOjYsImJ5dGVPZmZzZXQiOjAsImNvbXBvbmVudFR5cGUiOjUxMjYsImNvdW50Ijo0MTAyLCJtYXgiOlsxOC42NjY2Njc5MzgyMzI0LDI3LjM3MDQyNjE3Nzk3ODUsMzYuNTM5OTgxODQyMDQxXSwibWluIjpbLTkuMzcwNDI1MjI0MzA0MiwtOS4zNzA0MjUyMjQzMDQyLC05LjUzOTk4MDg4ODM2NjddLCJuYW1lIjoiYnVmX3NjYXR0ZXJlZF9saW5lcyIsInR5cGUiOiJWRUMzIn0seyJidWZmZXJWaWV3Ijo3LCJieXRlT2Zmc2V0IjowLCJjb21wb25lbnRUeXBlIjo1MTI2LCJjb3VudCI6NzE4LCJtYXgiOlsyNy4zNzA0MjYxNzc5Nzg1LDYsMzYuNTM5OTgxODQyMDQxXSwibWluIjpbLTAuNjY2NjY2OTg0NTU4MTA1LC0wLjY2NjY2Njk4NDU1ODEwNSwtOS41Mzk5ODA4ODgzNjY3XSwibmFtZSI6ImJ1Zl9yZWRfc2NhdHRlcmVkX2xpbmVzIiwidHlwZSI6IlZFQzMifV0sImFzc2V0Ijp7InZlcnNpb24iOiIyLjAifSwiYnVmZmVyVmlld3MiOlt7ImJ1ZmZlciI6MCwiYnl0ZUxlbmd0aCI6MTA4LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ0YXJnZXQiOjM0OTYyfSx7ImJ1ZmZlciI6MSwiYnl0ZUxlbmd0aCI6MTA4LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ0YXJnZXQiOjM0OTYyfSx7ImJ1ZmZlciI6MiwiYnl0ZUxlbmd0aCI6MTA4LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ0YXJnZXQiOjM0OTYyfSx7ImJ1ZmZlciI6MywiYnl0ZUxlbmd0aCI6MTA4LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ0YXJnZXQiOjM0OTYyfSx7ImJ1ZmZlciI6NCwiYnl0ZUxlbmd0aCI6MTA4LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ0YXJnZXQiOjM0OTYyfSx7ImJ1ZmZlciI6NSwiYnl0ZUxlbmd0aCI6MTA4LCJieXRlT2Zmc2V0IjowLCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ0YXJnZXQiOjM0OTYyfSx7ImJ1ZmZlciI6NiwiYnl0ZUxlbmd0aCI6NDkyMjQsImJ5dGVPZmZzZXQiOjAsIm5hbWUiOiJidWZfc2NhdHRlcmVkX2xpbmVzIiwidGFyZ2V0IjozNDk2Mn0seyJidWZmZXIiOjcsImJ5dGVMZW5ndGgiOjg2MTYsImJ5dGVPZmZzZXQiOjAsIm5hbWUiOiJidWZfcmVkX3NjYXR0ZXJlZF9saW5lcyIsInRhcmdldCI6MzQ5NjJ9XSwiYnVmZmVycyI6W3siYnl0ZUxlbmd0aCI6MTA4LCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ1cmkiOiJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsQUFBQUFNM016RDRBQUFBQUFBQUFBTVBRa0Q3RDBKQStBQUFBQVBJd2xyTE56TXcrQUFBQUFNUFFrTDdEMEpBK0FBQUFBTTNNekw3eU1CYXpBQUFBQU1IUWtMN0UwSkMrQUFBQUFQTGtvekhOek15K0FBQUFBTWJRa0Q2LzBKQytBQUFBQU0zTXpENEFBQUFBIn0seyJieXRlTGVuZ3RoIjoxMDgsIm5hbWUiOiJjaXJjbGVfbG9vcCIsInVyaSI6ImRhdGE6YXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtO2Jhc2U2NCxBQUFBQUFBQUFBRE56TXcrdzlDUVBnQUFBQUREMEpBK3pjek1QZ0FBQUFEeU1KYXl3OUNRUGdBQUFBREQwSkMrOGpBV3N3QUFBQUROek15K3hOQ1F2Z0FBQUFEQjBKQyt6Y3pNdmdBQUFBRHk1S014djlDUXZnQUFBQURHMEpBK0FBQUFBQUFBQUFETnpNdysifSx7ImJ5dGVMZW5ndGgiOjEwOCwibmFtZSI6ImNpcmNsZV9sb29wIiwidXJpIjoiZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LHpjek1QZ0FBQUFBQUFBQUF3OUNRUHNQUWtENEFBQUFBOGpDV3NzM016RDRBQUFBQXc5Q1F2c1BRa0Q0QUFBQUF6Y3pNdnZJd0ZyTUFBQUFBd2RDUXZzVFFrTDRBQUFBQTh1U2pNYzNNekw0QUFBQUF4dENRUHIvUWtMNEFBQUFBemN6TVBnQUFBQUFBQUFBQSJ9LHsiYnl0ZUxlbmd0aCI6MTA4LCJuYW1lIjoiY2lyY2xlX2xvb3AiLCJ1cmkiOiJkYXRhOmFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTtiYXNlNjQsQUFBQUFNM016RDRBQUFBQUFBQUFBTVBRa0Q3RDBKQStBQUFBQVBJd2xyTE56TXcrQUFBQUFNUFFrTDdEMEpBK0FBQUFBTTNNekw3eU1CYXpBQUFBQU1IUWtMN0UwSkMrQUFBQUFQTGtvekhOek15K0FBQUFBTWJRa0Q2LzBKQytBQUFBQU0zTXpENEFBQUFBIn0seyJieXRlTGVuZ3RoIjoxMDgsIm5hbWUiOiJjaXJjbGVfbG9vcCIsInVyaSI6ImRhdGE6YXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtO2Jhc2U2NCxBQUFBQUFBQUFBRE56TXcrdzlDUVBnQUFBQUREMEpBK3pjek1QZ0FBQUFEeU1KYXl3OUNRUGdBQUFBREQwSkMrOGpBV3N3QUFBQUROek15K3hOQ1F2Z0FBQUFEQjBKQyt6Y3pNdmdBQUFBRHk1S014djlDUXZnQUFBQURHMEpBK0FBQUFBQUFBQUFETnpNdysifSx7ImJ5dGVMZW5ndGgiOjEwOCwibmFtZSI6ImNpcmNsZV9sb29wIiwidXJpIjoiZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LHpjek1QZ0FBQUFBQUFBQUF3OUNRUHNQUWtENEFBQUFBOGpDV3NzM016RDRBQUFBQXc5Q1F2c1BRa0Q0QUFBQUF6Y3pNdnZJd0ZyTUFBQUFBd2RDUXZzVFFrTDRBQUFBQTh1U2pNYzNNekw0QUFBQUF4dENRUHIvUWtMNEFBQUFBemN6TVBnQUFBQUFBQUFBQSJ9LHsiYnl0ZUxlbmd0aCI6NDkyMjQsIm5hbWUiOiJidWZfc2NhdHRlcmVkX2xpbmVzIiwidXJpIjoiZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LEFBQUFBQUFBUUVFQUFBQUFvNHV1d0VZWFhVRzY2QUxCQUFBQUFBQUFRRUVBQUFBQUFBREFRQUFBd0VBQUFBQUFBQUFBQUFBQVFFRUFBQUFBQUFBQUFBQUFRRUVBQUVCQUFBREFRQUFBd0VBQUFBQUFBQUJBUVFBQVFFRUFBQUFBQUFEQVFBQUF3RUFBQUFBQUFBREFRQUFBd0VBQUFFQkFBQURBUUFBQXdFQUFBQUFBQUFEQVFBQUF3RUFBQUVCQUFBREFRQUFBQUFBQUFFQkEvVkY0UUFTRnk4Q0djSTNBQUFEQVFBQUF3RUFBQUFBQUFBQUFBQUFBUUVFQUFFQkFBQURBUUFBQXdFQUFBQUFBQUFBQUFBQUFRRUVBQUVCQUFBREFRQUFBQUFBQUFFQkEvVkY0UUFTRnk4Q0djSTNBQUFCQVFRQUFRRUVBQUFBQWdldGhRWUhyWVVIRG94akJBQUJBUVFBQVFFRUFBQUFBQUFDUVFRQUF3RUFBQUFBQUFBQkFRUUFBUUVFQUFBQUFBQUNRUVFBQXdFQUFBQUFBQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQUJBUVFBQVFFRUFBQUFBQUFEQVFBQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFBQUFBQURBUUFBQXdFQUFBRUJBQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQUJBUVFBQVFFRUFBQUFBQUFEQVFBQUF3RUFBQUVCQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQVFFRUFBRUJBQUFCQVFRQUFRRUVBQUFBQUFBREFRQUFBd0VBQUFFQkFBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBQkFRUUFBUUVFQUFBQUFBQURBUUFBQXdFQUFBRUJBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBUUVFQUFBQUFBQUFBQUFBQVFFRUFBRUJBQUFCQVFRQUFRRUVBQUFBQUFBQUFBQUFBUUVFQUFFQkFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBUUVFQUFBQUFBQUFBQUFBQVFFRUFBRUJBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQUJBUVFBQVFFRUFBQUFBQUFBQUFBQUFRRUVBQUVCQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQUJBUVFBQVFFRUFBQUFBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBUUVFQUFBQUFBQUJBUVFBQVFFRUFBRUJBQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQUJBUVFBQVFFRUFBQUFBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQVFFRUFBRUJBQUFDUVFRQUF3RUFBQUFBQUFBREFRQUFBd0VBQUFFQkFBQUNRUVFBQXdFQUFBQUFBQUFEQVFBQUF3RUFBQUVCQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFDUVFRQUF3RUFBQUFBQUFBQ1FRUUFBd0VBQUFFQkFBQUNRUVFBQXdFQUFBQUFBQUFDUVFRQUF3RUFBQUVCQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFDUVFRQUF3RUFBQUFBQUFBQkFRUUFBUUVFQUFFQkFBQUNRUVFBQXdFQUFBQUFBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFEQVFBQUFBQUFBQUVCQS9WRjRRQVNGeThDR2NJM0FBQURBUUFBQUFBQUFBRUJBQUFEQVFBQUFBQUFBQU1CQUFBREFRQUFBQUFBQUFFQkEvVkY0UUFTRnk4Q0djSTNBQUFEQVFBQUFBQUFBQUVCQS9WRjRRQVNGeThDR2NJM0FBQURBUUFBQUFBQUFBRUJBL1ZGNFFBU0Z5OENHY0kzQUFBREFRQUFBd0VBQUFFQkFBQUFBQUFBQVFFRUFBRUJBQUFEQVFBQUF3RUFBQUVCQUFBQUFBQUFBUUVFQUFFQkFBQURBUUFBQUFBQUFBRUJBL1ZGNFFBU0Z5OENHY0kzQUFBREFRQUFBd0VBQUFFQkFBQUFBQUFBQVFFRUFBRUJBQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQURBUUFBQXdFQUFBRUJBQUFBQUFBQUFRRUVBQUVCQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFEQVFBQUF3RUFBQUVCQUFBQUFBQUFBUUVFQUFFQkFBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFEQVFBQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFFQkFBQURBUUFBQXdFQUFBRUJBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQVFFRUFBRUJBQUFEQVFBQUF3RUFBQUVCQUFBREFRQUFBd0VBQUFNQkFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQVFFRUFBRUJBQUFCQVFRQUF3RUFBQUVCQUFBQkFRUUFBd0VBQUFNQkFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBUUVFQUFBQUFnZXRoUVlIcllVSERveGpCQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBREFRQUFBQUFBQUFFQkEvVkY0UUFTRnk4Q0djSTNBQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQURBUUFBQUFBQUFBRUJBL1ZGNFFBU0Z5OENHY0kzQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFDUVFRQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFFQkFBQUNRUVFBQXdFQUFBRUJBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFDUVFRQUF3RUFBQUVCQUFBQ1FRUUFBd0VBQUFNQkFBQUFBQUFBQVFFRUFBRUJBQklYTHdJSHJZVUdHY0kzQUFBQUFBQUFBUUVFQUFFQkFBQUFBQUFBQVFFRUFBTUJBQUFBQUFBQUFRRUVBQUVCQUJJWEx3SUhyWVVHR2NJM0FBQUFBQUFBQVFFRUFBQUFBbzR1dXdFWVhYVUc2NkFMQkFBQUFBQUFBUUVFQUFFQkFCSVhMd0lIcllVR0djSTNBQUFCQVFRQUFRRUVBQUFBQWdldGhRWUhyWVVIRG94akJBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBREFRQUFBUUVFQUFFQkFBQURBUUFBQVFFRUFBTUJBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQUJBUVFBQVFFRUFBQUFBZ2V0aFFZSHJZVUhEb3hqQkFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFCQVFRQUFRRUVBQUFBQWdldGhRWUhyWVVIRG94akJBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBQUFBQUFBUUVFQUFFQkFCSVhMd0lIcllVR0djSTNBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQUFBQUFBQVFFRUFBRUJBQklYTHdJSHJZVUdHY0kzQUFBQkFRUUFBUUVFQUFBQUFnZXRoUVlIcllVSERveGpCQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQUJBUVFBQVFFRUFBRUJBa21KcVFaSmlha0g4c2NqQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQVFFRUFBQUFBZ2V0aFFZSHJZVUhEb3hqQkFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBUUVFQUFBQUFnZXRoUVlIcllVSERveGpCQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQVFFRUFBRUJBQUFCQVFRQUFRRUVBQU1CQUFBQkFRUUFBUUVFQUFFQkFrbUpxUVpKaWFrSDhzY2pBQUFCQVFRQUFRRUVBQUFBQWdldGhRWUhyWVVIRG94akJBQUJBUVFBQVFFRUFBRUJBa21KcVFaSmlha0g4c2NqQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBUUVFQUFBQUFnZXRoUVlIcllVSERveGpCQUFCQVFRQUFrRUVBQUVCQWdldGhRVUhod2tHR2NJM0FBQUJBUVFBQWtFRUFBRUJBQUFCQVFRQUFrRUVBQU1CQUFBQkFRUUFBa0VFQUFFQkFnZXRoUVVIaHdrR0djSTNBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQUJBUVFBQWtFRUFBRUJBZ2V0aFFVSGh3a0dHY0kzQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQWtFRUFBRUJBZ2V0aFFVSGh3a0dHY0kzQUFBQkFRUUFBUUVFQUFFQkFrbUpxUVpKaWFrSDhzY2pBQUFEQVFBQUFBQUFBQUVCQS9WRjRRQVNGeThDR2NJM0FBQURBUUFBQUFBQUFBRUJBQUFCQVFRQUF3RUFBQUVCQUFBREFRQUFBQUFBQUFFQkFBQUJBUVFBQXdFQUFBRUJBQUFEQVFBQUFBQUFBQUVCQUFBREFRQUFBQUFBQUFNQkFBQURBUUFBQUFBQUFBRUJBQUFEQVFBQUFBQUFBQU1CQUFBREFRQUFBQUFBQUFFQkEvVkY0UUFTRnk4Q0djSTNBQUFEQVFBQUF3RUFBQUVCQUFBQUFBQUFBUUVFQUFFQkFBQURBUUFBQXdFQUFBRUJBQUFBQUFBQUFRRUVBQUVCQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFEQVFBQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFFQkFBQURBUUFBQXdFQUFBRUJBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQVFFRUFBRUJBQUFEQVFBQUF3RUFBQUVCQUFBREFRQUFBd0VBQUFNQkFBQURBUUFBQXdFQUFBRUJBQUFEQVFBQUF3RUFBQU1CQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQVFFRUFBRUJBQUFEQVFBQUF3RUFBQUVCQUFBREFRQUFBd0VBQUFNQkFBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBREFRQUFBd0VBQUFFQkFBQURBUUFBQXdFQUFBTUJBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQURBUUFBQUFBQUFBTUJBVER4aFFJMGw3c0FnbEU2K0FBREFRQUFBd0VBQUFFQkFBQURBUUFBQXdFQUFBTUJBQUFEQVFBQUFBQUFBQU1CQVREeGhRSTBsN3NBZ2xFNitBQURBUUFBQXdFQUFBRUJBQUFBQUFBQUFRRUVBQU1CQUFBREFRQUFBd0VBQUFFQkFBQUFBQUFBQVFFRUFBTUJBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQURBUUFBQXdFQUFBRUJBQUFBQUFBQUFRRUVBQU1CQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFEQVFBQUFBQUFBQU1CQVREeGhRSTBsN3NBZ2xFNitBQURBUUFBQXdFQUFBRUJBQUFBQUFBQUFRRUVBQU1CQUFBREFRQUFBQUFBQUFNQkFURHhoUUkwbDdzQWdsRTYrQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQUJBUVFBQXdFQUFBRUJBQUFEQVFBQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQVFFRUFBRUJBQUFCQVFRQUF3RUFBQUVCQUFBREFRQUFBUUVFQUFFQkFBQUNRUVFBQXdFQUFBRUJBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQVFFRUFBRUJBQUFDUVFRQUF3RUFBQUVCQUFBREFRQUFBd0VBQUFNQkFBQUJBUVFBQXdFQUFBRUJBQUFEQVFBQUFRRUVBQUVCQUFBQkFRUUFBUUVFQUFFQkFBQURBUUFBQXdFQUFBTUJBQUFCQVFRQUF3RUFBQUVCQUFBREFRQUFBUUVFQUFFQkFBQUJBUVFBQXdFQUFBRUJBQUFEQVFBQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQUFBQUFBTUJBQUFCQVFRQUF3RUFBQUVCQUFBREFRQUFBQUFBQUFNQkFBQUJBUVFBQXdFQUFBRUJBQUFEQVFBQUFBQUFBQU1CQUFBQkFRUUFBd0VBQUFFQkFBQURBUUFBQUFBQUFBTUJBQUFCQVFRQUF3RUFBQUVCQUFBQkFRUUFBd0VBQUFNQkFBQUJBUVFBQXdFQUFBRUJBQUFCQVFRQUF3RUFBQU1CQUFBQ1FRUUFBd0VBQUFFQkFBQUJBUVFBQVFFRUFBRUJBQUFCQVFRQUF3RUFBQUVCQUFBQkFRUUFBd0VBQUFNQkFBQUNRUVFBQXdFQUFBRUJBQUFEQVFBQUF3RUFBQU1CQUFBQkFRUUFBd0VBQUFFQkFBQUJBUVFBQXdFQUFBTUJBQUFCQVFRQUFRRUVBQUVCQUFBREFRQUFBd0VBQUFNQkFBQUJBUVFBQXdFQUFBRUJBQUFCQVFRQUF3RUFBQU1CQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFDUVFRQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFFQkFBQUNRUVFBQXdFQUFBRUJBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFDUVFRQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFFQkFBQURBUUFBQVFFRUFBRUJBQUFCQVFRQUF3RUFBQU1CQUFBQ1FRUUFBd0VBQUFFQkFBQUJBUVFBQVFFRUFBRUJBQUFCQVFRQUFrRUVBQUVCQWdldGhRVUhod2tHR2NJM0FBQUNRUVFBQXdFQUFBRUJBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFNQkFjYlIzUVQwdUlVQm9EQzNBQUFDUVFRQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFFQkFBQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFDUVFRQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFFQkFBQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQkFRUUFBa0VFQUFFQkFnZXRoUVVIaHdrR0djSTNBQUFDUVFRQUF3RUFBQUVCQUFBREFRQUFBd0VBQUFNQkFBQUNRUVFBQXdFQUFBRUJBQUFEQVFBQUF3RUFBQU1CQUFBREFRQUFBUUVFQUFFQkFBQUJBUVFBQXdFQUFBTUJBQUFDUVFRQUF3RUFBQUVCQUFBQ1FRUUFBd0VBQUFNQkFBQUNRUVFBQXdFQUFBRUJBQUFDUVFRQUF3RUFBQU1CQUFBQkFRUUFBd0VBQUFNQkFjYlIzUVQwdUlVQm9EQzNBQUFDUVFRQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFNQkFBQUNRUVFBQXdFQUFBRUJBQUFCQVFRQUFRRUVBQU1CQUFBQkFRUUFBa0VFQUFFQkFnZXRoUVVIaHdrR0djSTNBQUFDUVFRQUF3RUFBQUVCQUFBQkFRUUFBUUVFQUFNQkFBQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQ1FRUUFBd0VBQUFFQkFBQUJBUVFBQVFFRUFBTUJBQUFCQVFRQUF3RUFBQU1CQWNiUjNRVDB1SVVCb0RDM0FBQUJBUVFBQWtFRUFBRUJBZ2V0aFFVSGh3a0dHY0kzQUFBQUFBQUFBUUVFQUFFQkFCSVhMd0lIcllVR0djSTNBQUFBQUFBQUFRRUVBQUVCQUFBQUFBQUFBUUVFQUFNQkFBQUFBQUFBQVFFRUFBRUJBQUFBQUFBQUFRRUVBQU1CQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQURBUUFBQVFFRUFBRUJBQUFCQVFRQUFrRUVBQUVCQUFBREFRQUFBUUVFQUFFQkFBQUJBUVFBQWtFRUFBRUJBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQURBUUFBQVFFRUFBRUJBQUFEQVFBQUFBQUFBQU1CQUFBREFRQUFBUUVFQUFFQkFBQURBUUFBQUFBQUFBTUJBQUFEQVFBQUFRRUVBQUVCQUFBREFRQUFBQUFBQUFNQkFBQURBUUFBQVFFRUFBRUJBQUFEQVFBQUFBQUFBQU1CQUFBREFRQUFBUUVFQUFFQkFBQUJBUVFBQXdFQUFBTUJBQUFEQVFBQUFRRUVBQUVCQUFBQkFRUUFBd0VBQUFNQkFBQUJBUVFBQVFFRUFBRUJBQUFEQVFBQUF3RUFBQU1CQUFBREFRQUFBUUVFQUFFQkFBQUJBUVFBQXdFQUFBTUJBQUFCQVFRQUFRRUVBQUVCQUFBQUFBQUFBUUVFQUFNQkFBQURBUUFBQVFFRUFBRUJBQUFCQVFRQUF3RUFBQU1CQUFBREFRQUFBd0VBQUFNQkFBQUFBQUFBQVFFRUFBTUJBQUFEQVFBQUFRRUVBQUVCQUFBREFRQUFBUUVFQUFNQkFBQURBUUFBQVFFRUFBRUJBQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBUUVFQUFFQkFrbUpxUVpKaWFrSDhzY2pBQUFEQVFBQUFRRUVBQUVCQUFBREFRQUFBUUVFQUFNQkFBQUJBUVFBQVFFRUFBRUJBQUFEQVFBQUF3RUFBQU1CQUFBREFRQUFBUUVFQUFFQkFBQURBUUFBQVFFRUFBTUJBQUFCQVFRQUFRRUVBQUVCQUFBQUFBQUFBUUVFQUFNQkFBQURBUUFBQVFFRUFBRUJBQUFEQVFBQUFRRUVBQU1CQUFBREFRQUFBd0VBQUFNQkFBQUFBQUFBQVFFRUFBTUJBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQUFBQUFBQVFFRUFBRUJBQklYTHdJSHJZVUdHY0kzQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBREFRQUFBQUFBQUFNQkFURHhoUUkwbDdzQWdsRTYrQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQUFBQUFBQVFFRUFBTUJBalNYdXdPMndaMEVnbEU2K0FBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFBQUFBQUFRRUVBQU1CQWpTWHV3TzJ3WjBFZ2xFNitBQUFBQUFBQVFFRUFBRUJBQklYTHdJSHJZVUdHY0kzQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFBQUFBQUFRRUVBQU1CQWpTWHV3TzJ3WjBFZ2xFNitBQUJBUVFBQVFFRUFBRUJBa21KcVFaSmlha0g4c2NqQUFBQkFRUUFBUUVFQUFFQkFrbUpxUVpKaWFrSDhzY2pBQUFCQVFRQUFRRUVBQUVCQUFBREFRQUFBd0VBQUFNQkFBQUJBUVFBQVFFRUFBRUJBQUFEQVFBQUF3RUFBQU1CQUFBQkFRUUFBd0VBQUFNQkFBQURBUUFBQVFFRUFBTUJBQUFCQVFRQUFRRUVBQUVCQUFBQUFBQUFBUUVFQUFNQkFBQUJBUVFBQVFFRUFBRUJBQUFBQUFBQUFRRUVBQU1CQUFBQkFRUUFBd0VBQUFNQkFBQURBUUFBQVFFRUFBTUJBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBUUVFQUFNQkFBQUJBUVFBQVFFRUFBRUJBQUFCQVFRQUFRRUVBQU1CQUFBQkFRUUFBa0VFQUFFQkFnZXRoUVVIaHdrR0djSTNBQUFCQVFRQUFRRUVBQUVCQUFBQkFRUUFBUUVFQUFNQkFBQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQkFRUUFBUUVFQUFFQkFBQUJBUVFBQVFFRUFBTUJBQUFCQVFRQUF3RUFBQU1CQUFBREFRQUFBUUVFQUFNQkFBQUJBUVFBQVFFRUFBRUJBQUFCQVFRQUFRRUVBQU1CQUFBQkFRUUFBd0VBQUFNQkFjYlIzUVQwdUlVQm9EQzNBQUFCQVFRQUFrRUVBQUVCQWdldGhRVUhod2tHR2NJM0FBQUJBUVFBQWtFRUFBRUJBZ2V0aFFVSGh3a0dHY0kzQUFBQkFRUUFBa0VFQUFFQkFBQUJBUVFBQXdFQUFBTUJBQUFCQVFRQUFrRUVBQUVCQUFBQkFRUUFBd0VBQUFNQkFBQUJBUVFBQVFFRUFBRUJBa21KcVFaSmlha0g4c2NqQUFBQkFRUUFBa0VFQUFFQkFBQUJBUVFBQXdFQUFBTUJBQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQUJBUVFBQWtFRUFBRUJBQUFCQVFRQUF3RUFBQU1CQUFBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQWtFRUFBRUJBQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBa0VFQUFFQkFBQURBUUFBQVFFRUFBTUJBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQWtFRUFBRUJBQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFCQVFRQUFrRUVBQUVCQUFBREFRQUFBUUVFQUFNQkFBQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBQkFRUUFBUUVFQUFFQkFrbUpxUVpKaWFrSDhzY2pBQUFCQVFRQUFrRUVBQUVCQUFBQkFRUUFBa0VFQUFNQkFBQUJBUVFBQWtFRUFBRUJBQUFCQVFRQUFrRUVBQU1CQUFBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFCQVFRQUFrRUVBQUVCQWdldGhRVUhod2tHR2NJM0FBQUJBUVFBQVFFRUFBRUJBa21KcVFaSmlha0g4c2NqQUFBQkFRUUFBa0VFQUFFQkFnZXRoUVVIaHdrR0djSTNBQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQUJBUVFBQWtFRUFBRUJBZ2V0aFFVSGh3a0dHY0kzQUFBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQURBUUFBQUFBQUFBTUJBVER4aFFJMGw3c0FnbEU2K0FBREFRQUFBQUFBQUFNQkFBQUJBUVFBQXdFQUFBTUJBQUFEQVFBQUFBQUFBQU1CQUFBQkFRUUFBd0VBQUFNQkFBQURBUUFBQUFBQUFBTUJBQUFEQVFBQUFBQUFBQUJCQkFBREFRQUFBQUFBQUFNQkFBQURBUUFBQUFBQUFBQkJCQUFEQVFBQUFBQUFBQU1CQVREeGhRSTBsN3NBZ2xFNitBQURBUUFBQUFBQUFBRUJBL1ZGNFFBU0Z5OENHY0kzQUFBREFRQUFBQUFBQUFNQkFURHhoUUkwbDdzQWdsRTYrQUFEQVFBQUFBQUFBQUVCQS9WRjRRQVNGeThDR2NJM0FBQURBUUFBQUFBQUFBTUJBVER4aFFJMGw3c0FnbEU2K0FBREFRQUFBQUFBQUFNQkFURHhoUUkwbDdzQWdsRTYrQUFEQVFBQUFBQUFBQU1CQVREeGhRSTBsN3NBZ2xFNitBQURBUUFBQXdFQUFBTUJBQUFBQUFBQUFRRUVBQU1CQUFBREFRQUFBd0VBQUFNQkFBQUFBQUFBQVFFRUFBTUJBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQURBUUFBQXdFQUFBTUJBQUFBQUFBQUFRRUVBQU1CQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFEQVFBQUFBQUFBQU1CQVREeGhRSTBsN3NBZ2xFNitBQURBUUFBQXdFQUFBTUJBQUFBQUFBQUFRRUVBQU1CQUFBREFRQUFBQUFBQUFNQkFURHhoUUkwbDdzQWdsRTYrQUFEQVFBQUF3RUFBQU1CQUFBQUFBQUFBUUVFQUFNQkFBQUJBUVFBQXdFQUFBTUJBQUFEQVFBQUFRRUVBQU1CQUFBREFRQUFBd0VBQUFNQkFBQUFBQUFBQVFFRUFBTUJBQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQURBUUFBQXdFQUFBTUJBQUFBQUFBQUFRRUVBQU1CQUFBREFRQUFBUUVFQUFNQkFQUzRoUUhHMGQwRm9EQzNBQUFEQVFBQUFRRUVBQUVCQXVuVldRSkppYWtIOHNjakFBQURBUUFBQXdFQUFBTUJBQUFCQVFRQUFRRUVBQU1CQUFBREFRQUFBd0VBQUFNQkFBQUJBUVFBQVFFRUFBTUJBQUFCQVFRQUF3RUFBQU1CQUFBREFRQUFBUUVFQUFNQkFBQURBUUFBQXdFQUFBTUJBQUFEQVFBQUF3RUFBQUJCQkFBREFRQUFBd0VBQUFNQkFBQURBUUFBQXdFQUFBQkJCQUFCQVFRQUF3RUFBQU1CQUFBREFRQUFBUUVFQUFNQkFBQURBUUFBQXdFQUFBTUJBQUFEQVFBQUF3RUFBQUJCQkFBREFRQUFBUUVFQUFNQkFQUzRoUUhHMGQwRm9EQzNBQUFEQVFBQUF3RUFBQU1CQUFBREFRQUFBd0VBQUFCQkJBQURBUUFBQVFFRUFBTUJBUFM0aFFIRzBkMEZvREMzQUFBREFRQUFBQUFBQUFCQkJraVJKUUpJa0NjRnUyNVpBQUFEQVFBQUF3RUFBQU1CQUFBREFRQUFBd0VBQUFCQkJBQURBUUFBQUFBQUFBQkJCa2lSSlFKSWtDY0Z1MjVaQUFBREFRQUFBd0VBQUFNQkFBQUFBQUFBQVFFRUFBQkJCQUFEQVFBQUF3RUFBQU1CQUFBQUFBQUFBUUVFQUFCQkJBQURBUUFBQVFFRUFBTUJBUFM0aFFIRzBkMEZvREMzQUFBREFRQUFBd0VBQUFNQkFBQUFBQUFBQVFFRUFBQkJCQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQURBUUFBQUFBQUFBQkJCa2lSSlFKSWtDY0Z1MjVaQUFBREFRQUFBd0VBQUFNQkFBQUFBQUFBQVFFRUFBQkJCQUFEQVFBQUFBQUFBQUJCQmtpUkpRSklrQ2NGdTI1WkFBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFCQVFRQUF3RUFBQU1CQWNiUjNRVDB1SVVCb0RDM0FBQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQkFRUUFBd0VBQUFFQkFrbUpxUWJwMVZrRDhzY2pBQUFCQVFRQUF3RUFBQU1CQWNiUjNRVDB1SVVCb0RDM0FBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBd0VBQUFNQkFjYlIzUVQwdUlVQm9EQzNBQUFCQVFRQUF3RUFBQU1CQWNiUjNRVDB1SVVCb0RDM0FBQUJBUVFBQXdFQUFBTUJBQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBd0VBQUFNQkFBQURBUUFBQVFFRUFBTUJBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQXdFQUFBTUJBQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBd0VBQUFNQkFBQURBUUFBQVFFRUFBTUJBQUFDUVFRQUF3RUFBQU1CQUFBQkFRUUFBUUVFQUFNQkFBQUJBUVFBQXdFQUFBTUJBQUFEQVFBQUFRRUVBQU1CQUFBQ1FRUUFBd0VBQUFNQkFBQURBUUFBQXdFQUFBQkJCQUFCQVFRQUF3RUFBQU1CQUFBREFRQUFBUUVFQUFNQkFBQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBQkFRUUFBd0VBQUFNQkFBQURBUUFBQVFFRUFBTUJBQUFCQVFRQUFRRUVBQU1CQUFBREFRQUFBd0VBQUFCQkJBQUJBUVFBQXdFQUFBTUJBQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQUJBUVFBQXdFQUFBTUJBQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBd0VBQUFNQkFBQURBUUFBQVFFRUFBTUJBQUFCQVFRQUF3RUFBQU1CQUFBREFRQUFBQUFBQUFCQkJBQUJBUVFBQXdFQUFBTUJBQUFEQVFBQUFBQUFBQUJCQkFBQkFRUUFBd0VBQUFNQkFBQURBUUFBQUFBQUFBQkJCQUFCQVFRQUF3RUFBQU1CQUFBREFRQUFBQUFBQUFCQkJBQUJBUVFBQXdFQUFBTUJBQUFCQVFRQUF3RUFBQUJCQkFBQkFRUUFBd0VBQUFNQkFBQUJBUVFBQXdFQUFBQkJCQUFDUVFRQUF3RUFBQU1CQUFBQkFRUUFBUUVFQUFNQkFBQUJBUVFBQXdFQUFBTUJBQUFCQVFRQUF3RUFBQUJCQkFBQ1FRUUFBd0VBQUFNQkFBQURBUUFBQXdFQUFBQkJCQUFCQVFRQUF3RUFBQU1CQUFBQkFRUUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBTUJBQUFEQVFBQUF3RUFBQUJCQkFBQkFRUUFBd0VBQUFNQkFBQUJBUVFBQXdFQUFBQkJCQUFCQVFRQUF3RUFBQU1CQWNiUjNRVDB1SVVCb0RDM0FBQUJBUVFBQXdFQUFBRUJBa21KcVFicDFWa0Q4c2NqQUFBQkFRUUFBd0VBQUFNQkFjYlIzUVQwdUlVQm9EQzNBQUFCQVFRQUF3RUFBQUVCQWttSnFRYnAxVmtEOHNjakFBQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQkFRUUFBd0VBQUFNQkFjYlIzUVQwdUlVQm9EQzNBQUFCQVFRQUFrRUVBQUVCQWdldGhRVUhod2tHR2NJM0FBQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQkFRUUFBd0VBQUFNQkFjYlIzUVQwdUlVQm9EQzNBQUFDUVFRQUF3RUFBQU1CQUFBQkFRUUFBUUVFQUFNQkFBQUNRUVFBQXdFQUFBTUJBQUFCQVFRQUFRRUVBQU1CQUFBQkFRUUFBd0VBQUFNQkFjYlIzUVQwdUlVQm9EQzNBQUFDUVFRQUF3RUFBQU1CQUFBQkFRUUFBUUVFQUFNQkFBQURBUUFBQVFFRUFBTUJBQUFCQVFRQUF3RUFBQUJCQkFBQ1FRUUFBd0VBQUFNQkFBQUJBUVFBQVFFRUFBTUJBQUFCQVFRQUFrRUVBQU1CQTdiQm5RV09KeTBFZ2xFNitBQUNRUVFBQXdFQUFBTUJBQUFCQVFRQUFRRUVBQU1CQUFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFDUVFRQUF3RUFBQU1CQUFBQkFRUUFBUUVFQUFNQkFBQUJBUVFBQXdFQUFBQkJCUXM2R1Fkd2Jrei9JcWR3L0FBQkFRUUFBd0VBQUFNQkFjYlIzUVQwdUlVQm9EQzNBQUFDUVFRQUF3RUFBQU1CQUFBQkFRUUFBUUVFQUFNQkFBQUJBUVFBQXdFQUFBQkJCUXM2R1Fkd2Jrei9JcWR3L0FBQkFRUUFBa0VFQUFNQkE3YkJuUVdPSnkwRWdsRTYrQUFDUVFRQUF3RUFBQU1CQUFBREFRQUFBd0VBQUFCQkJBQUNRUVFBQXdFQUFBTUJBQUFEQVFBQUF3RUFBQUJCQkFBREFRQUFBUUVFQUFNQkFBQUJBUVFBQXdFQUFBQkJCQUFDUVFRQUF3RUFBQU1CQUFBQ1FRUUFBd0VBQUFCQkJBQUNRUVFBQXdFQUFBTUJBQUFDUVFRQUF3RUFBQUJCQkFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFDUVFRQUF3RUFBQU1CQUFBQkFRUUFBUUVFQUFCQkJBQUNRUVFBQXdFQUFBTUJBQUFCQVFRQUFRRUVBQUJCQkFBQkFRUUFBa0VFQUFNQkE3YkJuUVdPSnkwRWdsRTYrQUFDUVFRQUF3RUFBQU1CQUFBQkFRUUFBUUVFQUFCQkJBQUJBUVFBQXdFQUFBQkJCUXM2R1Fkd2Jrei9JcWR3L0FBQ1FRUUFBd0VBQUFNQkFBQUJBUVFBQVFFRUFBQkJCQUFCQVFRQUF3RUFBQUJCQlFzNkdRZHdia3ovSXFkdy9BQUJBUVFBQWtFRUFBTUJBN2JCblFXT0p5MEVnbEU2K0FBQUFBQUFBUUVFQUFNQkFqU1h1d08yd1owRWdsRTYrQUFBQUFBQUFRRUVBQU1CQUFBQUFBQUFBUUVFQUFCQkJBQUFBQUFBQVFFRUFBTUJBQUFBQUFBQUFRRUVBQUJCQkFBREFRQUFBUUVFQUFNQkFQUzRoUUhHMGQwRm9EQzNBQUFBQUFBQUFRRUVBQU1CQWpTWHV3TzJ3WjBFZ2xFNitBQUFBQUFBQVFFRUFBRUJBQklYTHdJSHJZVUdHY0kzQUFBQUFBQUFBUUVFQUFNQkFqU1h1d08yd1owRWdsRTYrQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQURBUUFBQVFFRUFBTUJBUFM0aFFIRzBkMEZvREMzQUFBREFRQUFBUUVFQUFNQkFBQUJBUVFBQWtFRUFBTUJBQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBa0VFQUFNQkFBQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBREFRQUFBUUVFQUFNQkFBQURBUUFBQUFBQUFBQkJCQUFEQVFBQUFRRUVBQU1CQUFBREFRQUFBQUFBQUFCQkJBQURBUUFBQVFFRUFBTUJBQUFEQVFBQUFBQUFBQUJCQkFBREFRQUFBUUVFQUFNQkFBQURBUUFBQUFBQUFBQkJCQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBd0VBQUFCQkJBQURBUUFBQVFFRUFBTUJBQUFCQVFRQUF3RUFBQUJCQkFBQkFRUUFBUUVFQUFNQkFBQURBUUFBQXdFQUFBQkJCQUFEQVFBQUFRRUVBQU1CQUFBQkFRUUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBTUJBQUFBQUFBQUFRRUVBQUJCQkFBREFRQUFBUUVFQUFNQkFBQUJBUVFBQXdFQUFBQkJCQUFEQVFBQUF3RUFBQUJCQkFBQUFBQUFBUUVFQUFCQkJBQURBUUFBQVFFRUFBTUJBQUFEQVFBQUFRRUVBQUJCQkFBREFRQUFBUUVFQUFNQkFBQURBUUFBQVFFRUFBQkJCQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQURBUUFBQVFFRUFBTUJBQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBUUVFQUFNQkFBQURBUUFBQXdFQUFBQkJCQUFEQVFBQUFRRUVBQU1CQUFBREFRQUFBUUVFQUFCQkJBQUJBUVFBQVFFRUFBTUJBQUFBQUFBQUFRRUVBQUJCQkFBREFRQUFBUUVFQUFNQkFBQURBUUFBQVFFRUFBQkJCQUFEQVFBQUF3RUFBQUJCQkFBQUFBQUFBUUVFQUFCQkJBQURBUUFBQVFFRUFBTUJBUFM0aFFIRzBkMEZvREMzQUFBREFRQUFBUUVFQUFFQkF1blZXUUpKaWFrSDhzY2pBQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBQkFRUUFBUUVFQUFFQkFrbUpxUVpKaWFrSDhzY2pBQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBQUFBQUFBUUVFQUFNQkFqU1h1d08yd1owRWdsRTYrQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQURBUUFBQVFFRUFBRUJBdW5WV1FKSmlha0g4c2NqQUFBQUFBQUFBUUVFQUFNQkFqU1h1d08yd1owRWdsRTYrQUFCQVFRQUFRRUVBQUVCQWttSnFRWkppYWtIOHNjakFBQURBUUFBQVFFRUFBTUJBUFM0aFFIRzBkMEZvREMzQUFBQkFRUUFBUUVFQUFFQkFrbUpxUVpKaWFrSDhzY2pBQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQUFBQUFBQVFFRUFBTUJBalNYdXdPMndaMEVnbEU2K0FBREFRQUFBUUVFQUFNQkFQUzRoUUhHMGQwRm9EQzNBQUFBQUFBQUFRRUVBQU1CQWpTWHV3TzJ3WjBFZ2xFNitBQUJBUVFBQVFFRUFBRUJBa21KcVFaSmlha0g4c2NqQUFBREFRQUFBUUVFQUFNQkFQUzRoUUhHMGQwRm9EQzNBQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQURBUUFBQVFFRUFBTUJBUFM0aFFIRzBkMEZvREMzQUFBREFRQUFBQUFBQUFCQkJraVJKUUpJa0NjRnUyNVpBQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQUFBQUFBQVFFRUFBQkJCa2lRSndkeTJiVUZ1MjVaQUFBREFRQUFBUUVFQUFNQkFQUzRoUUhHMGQwRm9EQzNBQUFBQUFBQUFRRUVBQUJCQmtpUUp3ZHkyYlVGdTI1WkFBQUFBQUFBQVFFRUFBTUJBalNYdXdPMndaMEVnbEU2K0FBREFRQUFBUUVFQUFNQkFQUzRoUUhHMGQwRm9EQzNBQUFBQUFBQUFRRUVBQUJCQmtpUUp3ZHkyYlVGdTI1WkFBQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFCQVFRQUFRRUVBQU1CQUFBREFRQUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBTUJBQUFEQVFBQUF3RUFBQUJCQkFBQkFRUUFBd0VBQUFCQkJBQURBUUFBQVFFRUFBQkJCQUFCQVFRQUFRRUVBQU1CQUFBQUFBQUFBUUVFQUFCQkJBQUJBUVFBQVFFRUFBTUJBQUFBQUFBQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFCQkJBQURBUUFBQVFFRUFBQkJCQUFCQVFRQUFRRUVBQU1CQUFBQkFRUUFBUUVFQUFCQkJBQUJBUVFBQVFFRUFBTUJBQUFCQVFRQUFRRUVBQUJCQkFBQkFRUUFBa0VFQUFNQkE3YkJuUVdPSnkwRWdsRTYrQUFCQVFRQUFRRUVBQU1CQUFBQkFRUUFBUUVFQUFCQkJBQUJBUVFBQXdFQUFBQkJCUXM2R1Fkd2Jrei9JcWR3L0FBQkFRUUFBUUVFQUFNQkFBQUJBUVFBQVFFRUFBQkJCQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBUUVFQUFCQkJBQUJBUVFBQVFFRUFBTUJBQUFCQVFRQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFCQVFRQUFrRUVBQU1CQTdiQm5RV09KeTBFZ2xFNitBQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBQkFRUUFBUUVFQUFFQkFrbUpxUVpKaWFrSDhzY2pBQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQUJBUVFBQWtFRUFBRUJBZ2V0aFFVSGh3a0dHY0kzQUFBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFCQVFRQUFrRUVBQU1CQTdiQm5RV09KeTBFZ2xFNitBQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBQkFRUUFBa0VFQUFNQkE3YkJuUVdPSnkwRWdsRTYrQUFCQVFRQUFrRUVBQUVCQWdldGhRVUhod2tHR2NJM0FBQUJBUVFBQWtFRUFBTUJBN2JCblFXT0p5MEVnbEU2K0FBQkFRUUFBa0VFQUFNQkFBQUJBUVFBQXdFQUFBQkJCQUFCQVFRQUFrRUVBQU1CQUFBQkFRUUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBQkFRUUFBa0VFQUFNQkFBQUJBUVFBQXdFQUFBQkJCQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQUJBUVFBQWtFRUFBTUJBQUFCQVFRQUF3RUFBQUJCQkFBQkFRUUFBUUVFQUFCQkJRczZHUVVMT2hrSElxZHcvQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQUJBUVFBQWtFRUFBTUJBQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBa0VFQUFNQkFBQURBUUFBQVFFRUFBQkJCQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQUJBUVFBQWtFRUFBTUJBQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBUUVFQUFCQkJRczZHUVVMT2hrSElxZHcvQUFCQVFRQUFrRUVBQU1CQUFBREFRQUFBUUVFQUFCQkJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFCQVFRQUFrRUVBQU1CQUFBQkFRUUFBa0VFQUFCQkJBQUJBUVFBQWtFRUFBTUJBQUFCQVFRQUFrRUVBQUJCQkFBQkFRUUFBUUVFQUFCQkJRczZHUVVMT2hrSElxZHcvQUFCQVFRQUFrRUVBQU1CQTdiQm5RV09KeTBFZ2xFNitBQUJBUVFBQWtFRUFBRUJBZ2V0aFFVSGh3a0dHY0kzQUFBQkFRUUFBa0VFQUFNQkE3YkJuUVdPSnkwRWdsRTYrQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQUJBUVFBQWtFRUFBTUJBN2JCblFXT0p5MEVnbEU2K0FBQkFRUUFBUUVFQUFCQkJRczZHUVVMT2hrSElxZHcvQUFCQVFRQUFrRUVBQU1CQTdiQm5RV09KeTBFZ2xFNitBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFEQVFBQUFBQUFBQUJCQmtpUkpRSklrQ2NGdTI1WkFBQURBUUFBQUFBQUFBQkJCQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBQUFBQUFCQkJBQUJBUVFBQXdFQUFBQkJCQUFEQVFBQUFBQUFBQUJCQkFBREFRQUFBQUFBQUFFQkJBQURBUUFBQUFBQUFBQkJCa2lSSlFKSWtDY0Z1MjVaQUFBREFRQUFBQUFBQUFNQkFURHhoUUkwbDdzQWdsRTYrQUFEQVFBQUFBQUFBQUJCQmtpUkpRSklrQ2NGdTI1WkFBQURBUUFBQUFBQUFBTUJBVER4aFFJMGw3c0FnbEU2K0FBREFRQUFBQUFBQUFCQkJraVJKUUpJa0NjRnUyNVpBQUFEQVFBQUFBQUFBQUJCQmtpUkpRSklrQ2NGdTI1WkFBQURBUUFBQUFBQUFBQkJCa2lSSlFKSWtDY0Z1MjVaQUFBREFRQUFBd0VBQUFCQkJBQUFBQUFBQVFFRUFBQkJCQUFEQVFBQUF3RUFBQUJCQkFBQUFBQUFBUUVFQUFCQkJBQURBUUFBQVFFRUFBTUJBUFM0aFFIRzBkMEZvREMzQUFBREFRQUFBd0VBQUFCQkJBQUFBQUFBQVFFRUFBQkJCQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQURBUUFBQUFBQUFBQkJCa2lSSlFKSWtDY0Z1MjVaQUFBREFRQUFBd0VBQUFCQkJBQUFBQUFBQVFFRUFBQkJCQUFEQVFBQUFBQUFBQUJCQmtpUkpRSklrQ2NGdTI1WkFBQURBUUFBQXdFQUFBQkJCQUFBQUFBQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFCQkJBQURBUUFBQVFFRUFBQkJCQUFEQVFBQUF3RUFBQUJCQkFBQUFBQUFBUUVFQUFCQkJBQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBREFRQUFBd0VBQUFCQkJBQUFBQUFBQVFFRUFBQkJCQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQURBUUFBQVFFRUFBTUJBUFM0aFFIRzBkMEZvREMzQUFBREFRQUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBQkJCQUFEQVFBQUF3RUFBQUJCQkFBQkFRUUFBUUVFQUFCQkJBQUJBUVFBQXdFQUFBQkJCQUFEQVFBQUFRRUVBQUJCQkFBREFRQUFBd0VBQUFCQkJBQURBUUFBQXdFQUFBRUJCQUFCQVFRQUF3RUFBQU1CQWNiUjNRVDB1SVVCb0RDM0FBQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFCQVFRQUF3RUFBQUJCQlFzNkdRZHdia3ovSXFkdy9BQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFCQVFRQUF3RUFBQU1CQWNiUjNRVDB1SVVCb0RDM0FBQUJBUVFBQXdFQUFBQkJCUXM2R1Fkd2Jrei9JcWR3L0FBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBUUVFQUFCQkJBQUJBUVFBQXdFQUFBQkJCQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBUUVFQUFCQkJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBQkFRUUFBd0VBQUFCQkJBQURBUUFBQVFFRUFBQkJCQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBQkFRUUFBd0VBQUFCQkJBQUJBUVFBQXdFQUFBRUJCQUFCQVFRQUF3RUFBQUJCQlFzNkdRZHdia3ovSXFkdy9BQUJBUVFBQXdFQUFBTUJBY2JSM1FUMHVJVUJvREMzQUFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFCQVFRQUF3RUFBQU1CQWNiUjNRVDB1SVVCb0RDM0FBQUJBUVFBQXdFQUFBQkJCUXM2R1Fkd2Jrei9JcWR3L0FBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFCQVFRQUFrRUVBQU1CQTdiQm5RV09KeTBFZ2xFNitBQUJBUVFBQXdFQUFBQkJCUXM2R1Fkd2Jrei9JcWR3L0FBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFDUVFRQUF3RUFBQUJCQkFBQkFRUUFBUUVFQUFCQkJBQUNRUVFBQXdFQUFBQkJCQUFCQVFRQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFDUVFRQUF3RUFBQUJCQkFBQ1FRUUFBd0VBQUFFQkJBQUFBQUFBQVFFRUFBQkJCa2lRSndkeTJiVUZ1MjVaQUFBQUFBQUFBUUVFQUFCQkJBQUFBQUFBQVFFRUFBRUJCQUFBQUFBQUFRRUVBQUJCQmtpUUp3ZHkyYlVGdTI1WkFBQUFBQUFBQVFFRUFBTUJBalNYdXdPMndaMEVnbEU2K0FBQUFBQUFBUUVFQUFCQkJraVFKd2R5MmJVRnUyNVpBQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBREFRQUFBUUVFQUFCQkJBQUJBUVFBQWtFRUFBQkJCQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBa0VFQUFCQkJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBREFRQUFBUUVFQUFCQkJBQURBUUFBQVFFRUFBRUJCQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQURBUUFBQVFFRUFBTUJBUFM0aFFIRzBkMEZvREMzQUFBREFRQUFBUUVFQUFCQkIzQnVUUDBMT2hrSElxZHcvQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBREFRQUFBUUVFQUFCQkIzQnVUUDBMT2hrSElxZHcvQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQUFBQUFBQVFFRUFBQkJCa2lRSndkeTJiVUZ1MjVaQUFBREFRQUFBUUVFQUFCQkIzQnVUUDBMT2hrSElxZHcvQUFEQVFBQUFRRUVBQU1CQVBTNGhRSEcwZDBGb0RDM0FBQUFBQUFBQVFFRUFBQkJCa2lRSndkeTJiVUZ1MjVaQUFBQkFRUUFBUUVFQUFNQkFjYlIzUVhHMGQwRm9EQzNBQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBREFRQUFBUUVFQUFCQkIzQnVUUDBMT2hrSElxZHcvQUFBQUFBQUFRRUVBQUJCQmtpUUp3ZHkyYlVGdTI1WkFBQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBQUFBQUFBUUVFQUFCQkJraVFKd2R5MmJVRnUyNVpBQUFCQVFRQUFRRUVBQU1CQWNiUjNRWEcwZDBGb0RDM0FBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBQkFRUUFBUUVFQUFCQkJBQUJBUVFBQVFFRUFBRUJCQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQUJBUVFBQVFFRUFBTUJBY2JSM1FYRzBkMEZvREMzQUFBQkFRUUFBUUVFQUFCQkJRczZHUVVMT2hrSElxZHcvQUFCQVFRQUFrRUVBQU1CQTdiQm5RV09KeTBFZ2xFNitBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBQkFRUUFBa0VFQUFCQkIzTFp0UVVtUzFFRnUyNVpBQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQUJBUVFBQWtFRUFBQkJCM0xadFFVbVMxRUZ1MjVaQUFBQkFRUUFBa0VFQUFNQkE3YkJuUVdPSnkwRWdsRTYrQUFCQVFRQUFrRUVBQUJCQjNMWnRRVW1TMUVGdTI1WkFBQUJBUVFBQWtFRUFBQkJCQUFCQVFRQUFrRUVBQUVCQkFBQkFRUUFBa0VFQUFCQkIzTFp0UVVtUzFFRnUyNVpBQUFCQVFRQUFrRUVBQU1CQTdiQm5RV09KeTBFZ2xFNitBQURBUUFBQUFBQUFBQkJCa2lSSlFKSWtDY0Z1MjVaQUFBREFRQUFBQUFBQUFCQkJBQUJBUVFBQXdFQUFBQkJCQUFEQVFBQUFBQUFBQUJCQkFBQkFRUUFBd0VBQUFCQkJBQURBUUFBQUFBQUFBQkJCQUFEQVFBQUFBQUFBQUVCQkFBREFRQUFBQUFBQUFCQkJBQURBUUFBQUFBQUFBRUJCQUFEQVFBQUFBQUFBQUJCQmtpUkpRSklrQ2NGdTI1WkFBQURBUUFBQXdFQUFBQkJCQUFBQUFBQUFRRUVBQUJCQkFBREFRQUFBd0VBQUFCQkJBQUFBQUFBQVFFRUFBQkJCQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQURBUUFBQXdFQUFBQkJCQUFCQVFRQUFRRUVBQUJCQkFBREFRQUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBQkJCQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBUUVFQUFCQkJBQURBUUFBQXdFQUFBQkJCQUFEQVFBQUF3RUFBQUVCQkFBREFRQUFBd0VBQUFCQkJBQURBUUFBQXdFQUFBRUJCQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBUUVFQUFCQkJBQURBUUFBQXdFQUFBQkJCQUFEQVFBQUF3RUFBQUVCQkFBREFRQUFBUUVFQUFCQkIzQnVUUDBMT2hrSElxZHcvQUFEQVFBQUF3RUFBQUJCQkFBREFRQUFBd0VBQUFFQkJBQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBREFRQUFBQUFBQUFFQkIvQmc0UUVQdEZjRWdBeWRCQUFEQVFBQUF3RUFBQUJCQkFBREFRQUFBd0VBQUFFQkJBQURBUUFBQUFBQUFBRUJCL0JnNFFFUHRGY0VnQXlkQkFBREFRQUFBd0VBQUFCQkJBQUFBQUFBQVFFRUFBRUJCQUFEQVFBQUF3RUFBQUJCQkFBQUFBQUFBUUVFQUFFQkJBQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBREFRQUFBd0VBQUFCQkJBQUFBQUFBQVFFRUFBRUJCQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQURBUUFBQUFBQUFBRUJCL0JnNFFFUHRGY0VnQXlkQkFBREFRQUFBd0VBQUFCQkJBQUFBQUFBQVFFRUFBRUJCQUFEQVFBQUFBQUFBQUVCQi9CZzRRRVB0RmNFZ0F5ZEJBQUJBUVFBQXdFQUFBQkJCUXM2R1Fkd2Jrei9JcWR3L0FBQkFRUUFBd0VBQUFCQkJBQURBUUFBQVFFRUFBQkJCQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBUUVFQUFCQkJBQUJBUVFBQXdFQUFBQkJCQUFEQVFBQUFRRUVBQUJCQkFBQ1FRUUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBQkJCQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBUUVFQUFCQkJBQUNRUVFBQXdFQUFBQkJCQUFEQVFBQUF3RUFBQUVCQkFBQkFRUUFBd0VBQUFCQkJBQURBUUFBQVFFRUFBQkJCQUFCQVFRQUFRRUVBQUJCQkFBREFRQUFBd0VBQUFFQkJBQUJBUVFBQXdFQUFBQkJCQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFCQkJBQURBUUFBQVFFRUFBQkJCQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBQUFBQUFFQkJBQUJBUVFBQXdFQUFBQkJCQUFEQVFBQUFBQUFBQUVCQkFBQkFRUUFBd0VBQUFCQkJBQURBUUFBQUFBQUFBRUJCQUFCQVFRQUF3RUFBQUJCQkFBREFRQUFBQUFBQUFFQkJBQUJBUVFBQXdFQUFBQkJCQUFCQVFRQUF3RUFBQUVCQkFBQkFRUUFBd0VBQUFCQkJBQUJBUVFBQXdFQUFBRUJCQUFDUVFRQUF3RUFBQUJCQkFBQkFRUUFBUUVFQUFCQkJBQUJBUVFBQXdFQUFBQkJCQUFCQVFRQUF3RUFBQUVCQkFBQ1FRUUFBd0VBQUFCQkJBQURBUUFBQXdFQUFBRUJCQUFCQVFRQUF3RUFBQUJCQkFBQkFRUUFBd0VBQUFFQkJBQUJBUVFBQVFFRUFBQkJCQUFEQVFBQUF3RUFBQUVCQkFBQkFRUUFBd0VBQUFCQkJBQUJBUVFBQXdFQUFBRUJCQUFCQVFRQUF3RUFBQUJCQlFzNkdRZHdia3ovSXFkdy9BQUNRUVFBQXdFQUFBQkJCQUFCQVFRQUFRRUVBQUJCQkFBQ1FRUUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBQkJCQUFCQVFRQUF3RUFBQUJCQlFzNkdRZHdia3ovSXFkdy9BQUNRUVFBQXdFQUFBQkJCQUFCQVFRQUFRRUVBQUJCQkFBREFRQUFBUUVFQUFCQkJBQUJBUVFBQXdFQUFBRUJCQUFDUVFRQUF3RUFBQUJCQkFBQkFRUUFBUUVFQUFCQkJBQUJBUVFBQWtFRUFBQkJCM0xadFFVbVMxRUZ1MjVaQUFBQ1FRUUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBQkJCQUFCQVFRQUF3RUFBQUVCQlZsV1ZRYkNxS3IrcXFncEJBQUNRUVFBQXdFQUFBQkJCQUFCQVFRQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFCQVFRQUF3RUFBQUJCQlFzNkdRZHdia3ovSXFkdy9BQUNRUVFBQXdFQUFBQkJCQUFCQVFRQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFCQVFRQUFrRUVBQUJCQjNMWnRRVW1TMUVGdTI1WkFBQUNRUVFBQXdFQUFBQkJCQUFEQVFBQUF3RUFBQUVCQkFBQ1FRUUFBd0VBQUFCQkJBQURBUUFBQXdFQUFBRUJCQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFFQkJBQUNRUVFBQXdFQUFBQkJCQUFDUVFRQUF3RUFBQUVCQkFBQ1FRUUFBd0VBQUFCQkJBQUNRUVFBQXdFQUFBRUJCQUFCQVFRQUF3RUFBQUVCQlZsV1ZRYkNxS3IrcXFncEJBQUNRUVFBQXdFQUFBQkJCQUFCQVFRQUFRRUVBQUVCQkFBQ1FRUUFBd0VBQUFCQkJBQUJBUVFBQVFFRUFBRUJCQUFCQVFRQUFrRUVBQUJCQjNMWnRRVW1TMUVGdTI1WkFBQUNRUVFBQXdFQUFBQkJCQUFCQVFRQUFRRUVBQUVCQkFBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFDUVFRQUF3RUFBQUJCQkFBQkFRUUFBUUVFQUFFQkJBQUJBUVFBQXdFQUFBRUJCVmxXVlFiQ3FLcitxcWdwQkFBQkFRUUFBa0VFQUFCQkIzTFp0UVVtUzFFRnUyNVpBQUFBQUFBQUFRRUVBQUJCQmtpUUp3ZHkyYlVGdTI1WkFBQUFBQUFBQVFFRUFBQkJCQUFBQUFBQUFRRUVBQUVCQkFBQUFBQUFBUUVFQUFCQkJBQUFBQUFBQVFFRUFBRUJCQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBREFRQUFBUUVFQUFCQkJBQUJBUVFBQWtFRUFBQkJCQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBa0VFQUFCQkJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBREFRQUFBUUVFQUFCQkJBQURBUUFBQUFBQUFBRUJCQUFEQVFBQUFRRUVBQUJCQkFBREFRQUFBQUFBQUFFQkJBQURBUUFBQVFFRUFBQkJCQUFEQVFBQUFBQUFBQUVCQkFBREFRQUFBUUVFQUFCQkJBQURBUUFBQUFBQUFBRUJCQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFFQkJBQURBUUFBQVFFRUFBQkJCQUFCQVFRQUF3RUFBQUVCQkFBQkFRUUFBUUVFQUFCQkJBQURBUUFBQXdFQUFBRUJCQUFEQVFBQUFRRUVBQUJCQkFBQkFRUUFBd0VBQUFFQkJBQUJBUVFBQVFFRUFBQkJCQUFBQUFBQUFRRUVBQUVCQkFBREFRQUFBUUVFQUFCQkJBQUJBUVFBQXdFQUFBRUJCQUFEQVFBQUF3RUFBQUVCQkFBQUFBQUFBUUVFQUFFQkJBQURBUUFBQVFFRUFBQkJCQUFEQVFBQUFRRUVBQUVCQkFBREFRQUFBUUVFQUFCQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQURBUUFBQVFFRUFBQkJCQUFEQVFBQUFRRUVBQUVCQkFBQkFRUUFBUUVFQUFCQkJBQURBUUFBQXdFQUFBRUJCQUFEQVFBQUFRRUVBQUJCQkFBREFRQUFBUUVFQUFFQkJBQUJBUVFBQVFFRUFBQkJCQUFBQUFBQUFRRUVBQUVCQkFBREFRQUFBUUVFQUFCQkJBQURBUUFBQVFFRUFBRUJCQUFEQVFBQUF3RUFBQUVCQkFBQUFBQUFBUUVFQUFFQkJBQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBQUFBQUFBUUVFQUFCQkJraVFKd2R5MmJVRnUyNVpBQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBREFRQUFBUUVFQUFCQkIzQnVUUDBMT2hrSElxZHcvQUFEQVFBQUFBQUFBQUVCQi9CZzRRRVB0RmNFZ0F5ZEJBQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBQUFBQUFBUUVFQUFFQkJRKzBWd2NINWNVRWdBeWRCQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQUFBQUFBQVFFRUFBRUJCUSswVndjSDVjVUVnQXlkQkFBQUFBQUFBUUVFQUFCQkJraVFKd2R5MmJVRnUyNVpBQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQUFBQUFBQVFFRUFBRUJCUSswVndjSDVjVUVnQXlkQkFBQkFRUUFBUUVFQUFCQkJRczZHUVVMT2hrSElxZHcvQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQUJBUVFBQVFFRUFBQkJCQUFEQVFBQUF3RUFBQUVCQkFBQkFRUUFBUUVFQUFCQkJBQURBUUFBQXdFQUFBRUJCQUFCQVFRQUF3RUFBQUVCQkFBREFRQUFBUUVFQUFFQkJBQUJBUVFBQVFFRUFBQkJCQUFBQUFBQUFRRUVBQUVCQkFBQkFRUUFBUUVFQUFCQkJBQUFBQUFBQVFFRUFBRUJCQUFCQVFRQUF3RUFBQUVCQkFBREFRQUFBUUVFQUFFQkJBQUJBUVFBQVFFRUFBQkJCQUFCQVFRQUFRRUVBQUVCQkFBQkFRUUFBUUVFQUFCQkJBQUJBUVFBQVFFRUFBRUJCQUFCQVFRQUFrRUVBQUJCQjNMWnRRVW1TMUVGdTI1WkFBQUJBUVFBQVFFRUFBQkJCQUFCQVFRQUFRRUVBQUVCQkFBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFCQVFRQUFRRUVBQUJCQkFBQkFRUUFBUUVFQUFFQkJBQUJBUVFBQXdFQUFBRUJCQUFEQVFBQUFRRUVBQUVCQkFBQkFRUUFBUUVFQUFCQkJBQUJBUVFBQVFFRUFBRUJCQUFCQVFRQUF3RUFBQUVCQlZsV1ZRYkNxS3IrcXFncEJBQUJBUVFBQWtFRUFBQkJCM0xadFFVbVMxRUZ1MjVaQUFBQkFRUUFBa0VFQUFCQkIzTFp0UVVtUzFFRnUyNVpBQUFCQVFRQUFrRUVBQUJCQkFBQkFRUUFBd0VBQUFFQkJBQUJBUVFBQWtFRUFBQkJCQUFCQVFRQUF3RUFBQUVCQkFBQkFRUUFBUUVFQUFCQkJRczZHUVVMT2hrSElxZHcvQUFCQVFRQUFrRUVBQUJCQkFBQkFRUUFBd0VBQUFFQkJBQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBQkFRUUFBa0VFQUFCQkJBQUJBUVFBQXdFQUFBRUJCQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBQkFRUUFBa0VFQUFCQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUFrRUVBQUJCQkFBREFRQUFBUUVFQUFFQkJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBQkFRUUFBa0VFQUFCQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQUJBUVFBQWtFRUFBQkJCQUFEQVFBQUFRRUVBQUVCQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQUJBUVFBQWtFRUFBQkJCQUFCQVFRQUFrRUVBQUVCQkFBQkFRUUFBa0VFQUFCQkJBQUJBUVFBQWtFRUFBRUJCQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQUJBUVFBQWtFRUFBQkJCM0xadFFVbVMxRUZ1MjVaQUFBQkFRUUFBUUVFQUFCQkJRczZHUVVMT2hrSElxZHcvQUFCQVFRQUFrRUVBQUJCQjNMWnRRVW1TMUVGdTI1WkFBQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBQkFRUUFBa0VFQUFCQkIzTFp0UVVtUzFFRnUyNVpBQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBREFRQUFBQUFBQUFFQkIvQmc0UUVQdEZjRWdBeWRCQUFEQVFBQUFBQUFBQUVCQkFBQkFRUUFBd0VBQUFFQkJBQURBUUFBQUFBQUFBRUJCQUFCQVFRQUF3RUFBQUVCQkFBREFRQUFBQUFBQUFFQkJBQURBUUFBQUFBQUFBSEJCQUFEQVFBQUFBQUFBQUVCQkFBREFRQUFBQUFBQUFIQkJBQURBUUFBQUFBQUFBRUJCL0JnNFFFUHRGY0VnQXlkQkFBREFRQUFBQUFBQUFCQkJraVJKUUpJa0NjRnUyNVpBQUFEQVFBQUFBQUFBQUVCQi9CZzRRRVB0RmNFZ0F5ZEJBQURBUUFBQUFBQUFBQkJCa2lSSlFKSWtDY0Z1MjVaQUFBREFRQUFBQUFBQUFFQkIvQmc0UUVQdEZjRWdBeWRCQUFEQVFBQUFBQUFBQUVCQi9CZzRRRVB0RmNFZ0F5ZEJBQURBUUFBQUFBQUFBRUJCL0JnNFFFUHRGY0VnQXlkQkFBREFRQUFBd0VBQUFFQkJBQUFBQUFBQVFFRUFBRUJCQUFEQVFBQUF3RUFBQUVCQkFBQUFBQUFBUUVFQUFFQkJBQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBREFRQUFBd0VBQUFFQkJBQUFBQUFBQVFFRUFBRUJCQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQURBUUFBQUFBQUFBRUJCL0JnNFFFUHRGY0VnQXlkQkFBREFRQUFBd0VBQUFFQkJBQUFBQUFBQVFFRUFBRUJCQUFEQVFBQUFBQUFBQUVCQi9CZzRRRVB0RmNFZ0F5ZEJBQURBUUFBQXdFQUFBRUJCQUFBQUFBQUFRRUVBQUVCQkFBQkFRUUFBd0VBQUFFQkJBQURBUUFBQVFFRUFBRUJCQUFEQVFBQUF3RUFBQUVCQkFBQUFBQUFBUUVFQUFFQkJBQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBREFRQUFBd0VBQUFFQkJBQUFBQUFBQVFFRUFBRUJCQUFEQVFBQUFRRUVBQUVCQnNLb3F2MVpWbFVHcXFncEJBQURBUUFBQVFFRUFBQkJCM0J1VFAwTE9oa0hJcWR3L0FBREFRQUFBd0VBQUFFQkJBQUJBUVFBQVFFRUFBRUJCQUFEQVFBQUF3RUFBQUVCQkFBQkFRUUFBUUVFQUFFQkJBQUJBUVFBQXdFQUFBRUJCQUFEQVFBQUFRRUVBQUVCQkFBREFRQUFBd0VBQUFFQkJBQURBUUFBQXdFQUFBSEJCQUFEQVFBQUF3RUFBQUVCQkFBREFRQUFBd0VBQUFIQkJBQUJBUVFBQXdFQUFBRUJCQUFEQVFBQUFRRUVBQUVCQkFBREFRQUFBd0VBQUFFQkJBQURBUUFBQXdFQUFBSEJCQUFEQVFBQUFRRUVBQUVCQnNLb3F2MVpWbFVHcXFncEJBQURBUUFBQXdFQUFBRUJCQUFEQVFBQUF3RUFBQUhCQkFBREFRQUFBUUVFQUFFQkJzS29xdjFaVmxVR3FxZ3BCQUFEQVFBQUFBQUFBQUhCQi9CZzRRRVB0RmNGd2ZvUkJBQURBUUFBQXdFQUFBRUJCQUFEQVFBQUF3RUFBQUhCQkFBREFRQUFBQUFBQUFIQkIvQmc0UUVQdEZjRndmb1JCQUFEQVFBQUF3RUFBQUVCQkFBQUFBQUFBUUVFQUFIQkJBQURBUUFBQXdFQUFBRUJCQUFBQUFBQUFRRUVBQUhCQkFBREFRQUFBUUVFQUFFQkJzS29xdjFaVmxVR3FxZ3BCQUFEQVFBQUF3RUFBQUVCQkFBQUFBQUFBUUVFQUFIQkJBQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBREFRQUFBQUFBQUFIQkIvQmc0UUVQdEZjRndmb1JCQUFEQVFBQUF3RUFBQUVCQkFBQUFBQUFBUUVFQUFIQkJBQURBUUFBQUFBQUFBSEJCL0JnNFFFUHRGY0Z3Zm9SQkFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFCQVFRQUF3RUFBQUJCQlFzNkdRZHdia3ovSXFkdy9BQUJBUVFBQXdFQUFBRUJCVmxXVlFiQ3FLcitxcWdwQkFBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFCQVFRQUF3RUFBQUJCQlFzNkdRZHdia3ovSXFkdy9BQUJBUVFBQXdFQUFBRUJCVmxXVlFiQ3FLcitxcWdwQkFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFCQVFRQUF3RUFBQUVCQlZsV1ZRYkNxS3IrcXFncEJBQUJBUVFBQXdFQUFBRUJCVmxXVlFiQ3FLcitxcWdwQkFBQkFRUUFBd0VBQUFFQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUF3RUFBQUVCQkFBREFRQUFBUUVFQUFFQkJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBQkFRUUFBd0VBQUFFQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUF3RUFBQUVCQkFBREFRQUFBUUVFQUFFQkJBQUNRUVFBQXdFQUFBRUJCQUFCQVFRQUFRRUVBQUVCQkFBQkFRUUFBd0VBQUFFQkJBQURBUUFBQVFFRUFBRUJCQUFDUVFRQUF3RUFBQUVCQkFBREFRQUFBd0VBQUFIQkJBQUJBUVFBQXdFQUFBRUJCQUFEQVFBQUFRRUVBQUVCQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFCQVFRQUF3RUFBQUVCQkFBREFRQUFBUUVFQUFFQkJBQUJBUVFBQVFFRUFBRUJCQUFEQVFBQUF3RUFBQUhCQkFBQkFRUUFBd0VBQUFFQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBQkFRUUFBd0VBQUFFQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUF3RUFBQUVCQkFBREFRQUFBUUVFQUFFQkJBQUJBUVFBQXdFQUFBRUJCQUFEQVFBQUFBQUFBQUhCQkFBQkFRUUFBd0VBQUFFQkJBQURBUUFBQUFBQUFBSEJCQUFCQVFRQUF3RUFBQUVCQkFBREFRQUFBQUFBQUFIQkJBQUJBUVFBQXdFQUFBRUJCQUFEQVFBQUFBQUFBQUhCQkFBQkFRUUFBd0VBQUFFQkJBQUJBUVFBQXdFQUFBSEJCQUFCQVFRQUF3RUFBQUVCQkFBQkFRUUFBd0VBQUFIQkJBQUNRUVFBQXdFQUFBRUJCQUFCQVFRQUFRRUVBQUVCQkFBQkFRUUFBd0VBQUFFQkJBQUJBUVFBQXdFQUFBSEJCQUFDUVFRQUF3RUFBQUVCQkFBREFRQUFBd0VBQUFIQkJBQUJBUVFBQXdFQUFBRUJCQUFCQVFRQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFFQkJBQURBUUFBQXdFQUFBSEJCQUFCQVFRQUF3RUFBQUVCQkFBQkFRUUFBd0VBQUFIQkJBQUJBUVFBQXdFQUFBRUJCVmxXVlFiQ3FLcitxcWdwQkFBQkFRUUFBd0VBQUFCQkJRczZHUWR3Ymt6L0lxZHcvQUFCQVFRQUF3RUFBQUVCQlZsV1ZRYkNxS3IrcXFncEJBQUJBUVFBQXdFQUFBQkJCUXM2R1Fkd2Jrei9JcWR3L0FBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFCQVFRQUF3RUFBQUVCQlZsV1ZRYkNxS3IrcXFncEJBQUJBUVFBQWtFRUFBQkJCM0xadFFVbVMxRUZ1MjVaQUFBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFCQVFRQUF3RUFBQUVCQlZsV1ZRYkNxS3IrcXFncEJBQUNRUVFBQXdFQUFBRUJCQUFCQVFRQUFRRUVBQUVCQkFBQ1FRUUFBd0VBQUFFQkJBQUJBUVFBQVFFRUFBRUJCQUFCQVFRQUF3RUFBQUVCQlZsV1ZRYkNxS3IrcXFncEJBQUNRUVFBQXdFQUFBRUJCQUFCQVFRQUFRRUVBQUVCQkFBREFRQUFBUUVFQUFFQkJBQUJBUVFBQXdFQUFBSEJCQUFDUVFRQUF3RUFBQUVCQkFBQkFRUUFBUUVFQUFFQkJBQUJBUVFBQWtFRUFBRUJCd2ZseFFhTDIya0VnQXlkQkFBQ1FRUUFBd0VBQUFFQkJBQUJBUVFBQVFFRUFBRUJCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUNRUVFBQXdFQUFBRUJCQUFCQVFRQUFRRUVBQUVCQkFBQkFRUUFBd0VBQUFIQkJWbFdWUWJDcUtyK3JxcEpCQUFCQVFRQUF3RUFBQUVCQlZsV1ZRYkNxS3IrcXFncEJBQUNRUVFBQXdFQUFBRUJCQUFCQVFRQUFRRUVBQUVCQkFBQkFRUUFBd0VBQUFIQkJWbFdWUWJDcUtyK3JxcEpCQUFCQVFRQUFrRUVBQUVCQndmbHhRYUwyMmtFZ0F5ZEJBQUNRUVFBQXdFQUFBRUJCQUFEQVFBQUF3RUFBQUhCQkFBQ1FRUUFBd0VBQUFFQkJBQURBUUFBQXdFQUFBSEJCQUFEQVFBQUFRRUVBQUVCQkFBQkFRUUFBd0VBQUFIQkJBQUNRUVFBQXdFQUFBRUJCQUFDUVFRQUF3RUFBQUhCQkFBQ1FRUUFBd0VBQUFFQkJBQUNRUVFBQXdFQUFBSEJCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUNRUVFBQXdFQUFBRUJCQUFCQVFRQUFRRUVBQUhCQkFBQ1FRUUFBd0VBQUFFQkJBQUJBUVFBQVFFRUFBSEJCQUFCQVFRQUFrRUVBQUVCQndmbHhRYUwyMmtFZ0F5ZEJBQUNRUVFBQXdFQUFBRUJCQUFCQVFRQUFRRUVBQUhCQkFBQkFRUUFBd0VBQUFIQkJWbFdWUWJDcUtyK3JxcEpCQUFDUVFRQUF3RUFBQUVCQkFBQkFRUUFBUUVFQUFIQkJBQUJBUVFBQXdFQUFBSEJCVmxXVlFiQ3FLcitycXBKQkFBQkFRUUFBa0VFQUFFQkJ3Zmx4UWFMMjJrRWdBeWRCQUFBQUFBQUFRRUVBQUVCQlErMFZ3Y0g1Y1VFZ0F5ZEJBQUFBQUFBQVFFRUFBRUJCQUFBQUFBQUFRRUVBQUhCQkFBQUFBQUFBUUVFQUFFQkJBQUFBQUFBQVFFRUFBSEJCQUFEQVFBQUFRRUVBQUVCQnNLb3F2MVpWbFVHcXFncEJBQUFBQUFBQVFFRUFBRUJCUSswVndjSDVjVUVnQXlkQkFBQUFBQUFBUUVFQUFCQkJraVFKd2R5MmJVRnUyNVpBQUFBQUFBQUFRRUVBQUVCQlErMFZ3Y0g1Y1VFZ0F5ZEJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBREFRQUFBUUVFQUFFQkJzS29xdjFaVmxVR3FxZ3BCQUFEQVFBQUFRRUVBQUVCQkFBQkFRUUFBa0VFQUFFQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUFrRUVBQUVCQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFEQVFBQUFRRUVBQUVCQkFBREFRQUFBQUFBQUFIQkJBQURBUUFBQVFFRUFBRUJCQUFEQVFBQUFBQUFBQUhCQkFBREFRQUFBUUVFQUFFQkJBQURBUUFBQUFBQUFBSEJCQUFEQVFBQUFRRUVBQUVCQkFBREFRQUFBQUFBQUFIQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBUUVFQUFFQkJBQUJBUVFBQXdFQUFBSEJCQUFCQVFRQUFRRUVBQUVCQkFBREFRQUFBd0VBQUFIQkJBQURBUUFBQVFFRUFBRUJCQUFCQVFRQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFFQkJBQUFBQUFBQVFFRUFBSEJCQUFEQVFBQUFRRUVBQUVCQkFBQkFRUUFBd0VBQUFIQkJBQURBUUFBQXdFQUFBSEJCQUFBQUFBQUFRRUVBQUhCQkFBREFRQUFBUUVFQUFFQkJBQURBUUFBQVFFRUFBSEJCQUFEQVFBQUFRRUVBQUVCQkFBREFRQUFBUUVFQUFIQkJBQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBREFRQUFBUUVFQUFFQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUFRRUVBQUVCQkFBREFRQUFBd0VBQUFIQkJBQURBUUFBQVFFRUFBRUJCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBUUVFQUFFQkJBQUFBQUFBQVFFRUFBSEJCQUFEQVFBQUFRRUVBQUVCQkFBREFRQUFBUUVFQUFIQkJBQURBUUFBQXdFQUFBSEJCQUFBQUFBQUFRRUVBQUhCQkFBREFRQUFBUUVFQUFFQkJzS29xdjFaVmxVR3FxZ3BCQUFEQVFBQUFRRUVBQUJCQjNCdVRQMExPaGtISXFkdy9BQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBREFRQUFBUUVFQUFCQkIzQnVUUDBMT2hrSElxZHcvQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBREFRQUFBUUVFQUFCQkIzQnVUUDBMT2hrSElxZHcvQUFBQUFBQUFRRUVBQUVCQlErMFZ3Y0g1Y1VFZ0F5ZEJBQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBREFRQUFBUUVFQUFCQkIzQnVUUDBMT2hrSElxZHcvQUFBQUFBQUFRRUVBQUVCQlErMFZ3Y0g1Y1VFZ0F5ZEJBQUJBUVFBQVFFRUFBQkJCUXM2R1FVTE9oa0hJcWR3L0FBREFRQUFBUUVFQUFFQkJzS29xdjFaVmxVR3FxZ3BCQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBQUFBQUFBUUVFQUFFQkJRKzBWd2NINWNVRWdBeWRCQUFEQVFBQUFRRUVBQUVCQnNLb3F2MVpWbFVHcXFncEJBQUFBQUFBQVFFRUFBRUJCUSswVndjSDVjVUVnQXlkQkFBQkFRUUFBUUVFQUFCQkJRczZHUVVMT2hrSElxZHcvQUFEQVFBQUFRRUVBQUVCQnNLb3F2MVpWbFVHcXFncEJBQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBREFRQUFBUUVFQUFFQkJzS29xdjFaVmxVR3FxZ3BCQUFEQVFBQUFBQUFBQUhCQi9CZzRRRVB0RmNGd2ZvUkJBQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBQUFBQUFBUUVFQUFIQkJRKzBWd2NINWNVRndmb1JCQUFEQVFBQUFRRUVBQUVCQnNLb3F2MVpWbFVHcXFncEJBQUFBQUFBQVFFRUFBSEJCUSswVndjSDVjVUZ3Zm9SQkFBQUFBQUFBUUVFQUFFQkJRKzBWd2NINWNVRWdBeWRCQUFEQVFBQUFRRUVBQUVCQnNLb3F2MVpWbFVHcXFncEJBQUFBQUFBQVFFRUFBSEJCUSswVndjSDVjVUZ3Zm9SQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQUJBUVFBQVFFRUFBRUJCQUFEQVFBQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFFQkJBQURBUUFBQXdFQUFBSEJCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBUUVFQUFIQkJBQUJBUVFBQVFFRUFBRUJCQUFBQUFBQUFRRUVBQUhCQkFBQkFRUUFBUUVFQUFFQkJBQUFBQUFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBUUVFQUFIQkJBQUJBUVFBQVFFRUFBRUJCQUFCQVFRQUFRRUVBQUhCQkFBQkFRUUFBUUVFQUFFQkJBQUJBUVFBQVFFRUFBSEJCQUFCQVFRQUFrRUVBQUVCQndmbHhRYUwyMmtFZ0F5ZEJBQUJBUVFBQVFFRUFBRUJCQUFCQVFRQUFRRUVBQUhCQkFBQkFRUUFBd0VBQUFIQkJWbFdWUWJDcUtyK3JxcEpCQUFCQVFRQUFRRUVBQUVCQkFBQkFRUUFBUUVFQUFIQkJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBUUVFQUFFQkJBQUJBUVFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUJBUVFBQWtFRUFBRUJCd2ZseFFhTDIya0VnQXlkQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFCQVFRQUFRRUVBQUJCQlFzNkdRVUxPaGtISXFkdy9BQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBQkFRUUFBa0VFQUFCQkIzTFp0UVVtUzFFRnUyNVpBQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQUJBUVFBQWtFRUFBRUJCd2ZseFFhTDIya0VnQXlkQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFCQVFRQUFrRUVBQUVCQndmbHhRYUwyMmtFZ0F5ZEJBQUJBUVFBQWtFRUFBQkJCM0xadFFVbVMxRUZ1MjVaQUFBQkFRUUFBa0VFQUFFQkJ3Zmx4UWFMMjJrRWdBeWRCQUFCQVFRQUFrRUVBQUVCQkFBQkFRUUFBd0VBQUFIQkJBQUJBUVFBQWtFRUFBRUJCQUFCQVFRQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFCQVFRQUFrRUVBQUVCQkFBQkFRUUFBd0VBQUFIQkJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBQkFRUUFBa0VFQUFFQkJBQUJBUVFBQXdFQUFBSEJCQUFCQVFRQUFRRUVBQUhCQlZsV1ZRVlpWbFVHcnFwSkJBQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBQkFRUUFBa0VFQUFFQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUFrRUVBQUVCQkFBREFRQUFBUUVFQUFIQkJBQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBQkFRUUFBa0VFQUFFQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUFRRUVBQUhCQlZsV1ZRVlpWbFVHcnFwSkJBQUJBUVFBQWtFRUFBRUJCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQUJBUVFBQWtFRUFBRUJCQUFCQVFRQUFrRUVBQUhCQkFBQkFRUUFBa0VFQUFFQkJBQUJBUVFBQWtFRUFBSEJCQUFCQVFRQUFRRUVBQUhCQlZsV1ZRVlpWbFVHcnFwSkJBQUJBUVFBQWtFRUFBRUJCd2ZseFFhTDIya0VnQXlkQkFBQkFRUUFBa0VFQUFCQkIzTFp0UVVtUzFFRnUyNVpBQUFCQVFRQUFrRUVBQUVCQndmbHhRYUwyMmtFZ0F5ZEJBQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBQkFRUUFBa0VFQUFFQkJ3Zmx4UWFMMjJrRWdBeWRCQUFCQVFRQUFRRUVBQUhCQlZsV1ZRVlpWbFVHcnFwSkJBQUJBUVFBQWtFRUFBRUJCd2ZseFFhTDIya0VnQXlkQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQURBUUFBQUFBQUFBSEJCL0JnNFFFUHRGY0Z3Zm9SQkFBREFRQUFBQUFBQUFIQkJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFBQUFBQUhCQkFBQkFRUUFBd0VBQUFIQkJBQURBUUFBQUFBQUFBSEJCQUFEQVFBQUFBQUFBQUpCQkFBREFRQUFBQUFBQUFIQkIvQmc0UUVQdEZjRndmb1JCQUFEQVFBQUFBQUFBQUVCQi9CZzRRRVB0RmNFZ0F5ZEJBQURBUUFBQUFBQUFBSEJCL0JnNFFFUHRGY0Z3Zm9SQkFBREFRQUFBQUFBQUFFQkIvQmc0UUVQdEZjRWdBeWRCQUFEQVFBQUFBQUFBQUhCQi9CZzRRRVB0RmNGd2ZvUkJBQURBUUFBQUFBQUFBSEJCL0JnNFFFUHRGY0Z3Zm9SQkFBREFRQUFBQUFBQUFIQkIvQmc0UUVQdEZjRndmb1JCQUFEQVFBQUF3RUFBQUhCQkFBQUFBQUFBUUVFQUFIQkJBQURBUUFBQXdFQUFBSEJCQUFBQUFBQUFRRUVBQUhCQkFBREFRQUFBUUVFQUFFQkJzS29xdjFaVmxVR3FxZ3BCQUFEQVFBQUF3RUFBQUhCQkFBQUFBQUFBUUVFQUFIQkJBQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBREFRQUFBQUFBQUFIQkIvQmc0UUVQdEZjRndmb1JCQUFEQVFBQUF3RUFBQUhCQkFBQUFBQUFBUUVFQUFIQkJBQURBUUFBQUFBQUFBSEJCL0JnNFFFUHRGY0Z3Zm9SQkFBREFRQUFBd0VBQUFIQkJBQUFBQUFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBUUVFQUFIQkJBQURBUUFBQXdFQUFBSEJCQUFBQUFBQUFRRUVBQUhCQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFEQVFBQUF3RUFBQUhCQkFBQUFBQUFBUUVFQUFIQkJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBREFRQUFBUUVFQUFFQkJzS29xdjFaVmxVR3FxZ3BCQUFEQVFBQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFIQkJBQURBUUFBQXdFQUFBSEJCQUFCQVFRQUFRRUVBQUhCQkFBQkFRUUFBd0VBQUFIQkJBQURBUUFBQVFFRUFBSEJCQUFEQVFBQUF3RUFBQUhCQkFBREFRQUFBd0VBQUFKQkJBQUJBUVFBQXdFQUFBRUJCVmxXVlFiQ3FLcitxcWdwQkFBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUJBUVFBQXdFQUFBSEJCVmxXVlFiQ3FLcitycXBKQkFBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUJBUVFBQXdFQUFBRUJCVmxXVlFiQ3FLcitxcWdwQkFBQkFRUUFBd0VBQUFIQkJWbFdWUWJDcUtyK3JxcEpCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBd0VBQUFIQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBUUVFQUFIQkJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFCQVFRQUF3RUFBQUhCQkFBQkFRUUFBd0VBQUFKQkJBQUJBUVFBQXdFQUFBSEJCVmxXVlFiQ3FLcitycXBKQkFBQkFRUUFBd0VBQUFFQkJWbFdWUWJDcUtyK3FxZ3BCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUJBUVFBQXdFQUFBRUJCVmxXVlFiQ3FLcitxcWdwQkFBQkFRUUFBd0VBQUFIQkJWbFdWUWJDcUtyK3JxcEpCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUJBUVFBQWtFRUFBRUJCd2ZseFFhTDIya0VnQXlkQkFBQkFRUUFBd0VBQUFIQkJWbFdWUWJDcUtyK3JxcEpCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUNRUVFBQXdFQUFBSEJCQUFCQVFRQUFRRUVBQUhCQkFBQ1FRUUFBd0VBQUFIQkJBQUJBUVFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUNRUVFBQXdFQUFBSEJCQUFDUVFRQUF3RUFBQUpCQkFBQUFBQUFBUUVFQUFIQkJRKzBWd2NINWNVRndmb1JCQUFBQUFBQUFRRUVBQUhCQkFBQUFBQUFBUUVFQUFKQkJBQUFBQUFBQVFFRUFBSEJCUSswVndjSDVjVUZ3Zm9SQkFBQUFBQUFBUUVFQUFFQkJRKzBWd2NINWNVRWdBeWRCQUFBQUFBQUFRRUVBQUhCQlErMFZ3Y0g1Y1VGd2ZvUkJBQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBa0VFQUFIQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUFrRUVBQUhCQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFEQVFBQUFRRUVBQUhCQkFBREFRQUFBUUVFQUFKQkJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBREFRQUFBUUVFQUFFQkJzS29xdjFaVmxVR3FxZ3BCQUFEQVFBQUFRRUVBQUhCQnNLb3F2MVpWbFVHcnFwSkJBQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFEQVFBQUFRRUVBQUhCQnNLb3F2MVpWbFVHcnFwSkJBQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBQUFBQUFBUUVFQUFIQkJRKzBWd2NINWNVRndmb1JCQUFEQVFBQUFRRUVBQUhCQnNLb3F2MVpWbFVHcnFwSkJBQURBUUFBQVFFRUFBRUJCc0tvcXYxWlZsVUdxcWdwQkFBQUFBQUFBUUVFQUFIQkJRKzBWd2NINWNVRndmb1JCQUFCQVFRQUFRRUVBQUVCQlZsV1ZRVlpWbFVHcXFncEJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFEQVFBQUFRRUVBQUhCQnNLb3F2MVpWbFVHcnFwSkJBQUFBQUFBQVFFRUFBSEJCUSswVndjSDVjVUZ3Zm9SQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFBQUFBQUFRRUVBQUhCQlErMFZ3Y0g1Y1VGd2ZvUkJBQUJBUVFBQVFFRUFBRUJCVmxXVlFWWlZsVUdxcWdwQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFCQVFRQUFRRUVBQUhCQkFBQkFRUUFBUUVFQUFKQkJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBQkFRUUFBUUVFQUFFQkJWbFdWUVZaVmxVR3FxZ3BCQUFCQVFRQUFRRUVBQUhCQlZsV1ZRVlpWbFVHcnFwSkJBQUJBUVFBQWtFRUFBRUJCd2ZseFFhTDIya0VnQXlkQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFCQVFRQUFrRUVBQUhCQndmbHhRYUwyMmtGd2ZvUkJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBQkFRUUFBa0VFQUFIQkJ3Zmx4UWFMMjJrRndmb1JCQUFCQVFRQUFrRUVBQUVCQndmbHhRYUwyMmtFZ0F5ZEJBQUJBUVFBQWtFRUFBSEJCd2ZseFFhTDIya0Z3Zm9SQkFBQkFRUUFBa0VFQUFIQkJBQUJBUVFBQWtFRUFBSkJCQUFCQVFRQUFrRUVBQUhCQndmbHhRYUwyMmtGd2ZvUkJBQUJBUVFBQWtFRUFBRUJCd2ZseFFhTDIya0VnQXlkQkFBREFRQUFBQUFBQUFIQkIvQmc0UUVQdEZjRndmb1JCQUFEQVFBQUFBQUFBQUhCQkFBQkFRUUFBd0VBQUFIQkJBQURBUUFBQUFBQUFBSEJCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBQUFBQUFIQkJBQURBUUFBQUFBQUFBSkJCQUFEQVFBQUFBQUFBQUhCQkFBREFRQUFBQUFBQUFKQkJBQURBUUFBQUFBQUFBSEJCL0JnNFFFUHRGY0Z3Zm9SQkFBREFRQUFBd0VBQUFIQkJBQUFBQUFBQVFFRUFBSEJCQUFEQVFBQUF3RUFBQUhCQkFBQUFBQUFBUUVFQUFIQkJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBREFRQUFBd0VBQUFIQkJBQUJBUVFBQVFFRUFBSEJCQUFEQVFBQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFIQkJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFRRUVBQUhCQkFBREFRQUFBd0VBQUFIQkJBQURBUUFBQXdFQUFBSkJCQUFEQVFBQUF3RUFBQUhCQkFBREFRQUFBd0VBQUFKQkJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFRRUVBQUhCQkFBREFRQUFBd0VBQUFIQkJBQURBUUFBQXdFQUFBSkJCQUFEQVFBQUFRRUVBQUhCQnNLb3F2MVpWbFVHcnFwSkJBQURBUUFBQXdFQUFBSEJCQUFEQVFBQUF3RUFBQUpCQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFEQVFBQUFBQUFBQUpCQmtpUkpRSklrQ2NFa1NiSkJBQURBUUFBQXdFQUFBSEJCQUFEQVFBQUF3RUFBQUpCQkFBREFRQUFBQUFBQUFKQkJraVJKUUpJa0NjRWtTYkpCQUFEQVFBQUF3RUFBQUhCQkFBQUFBQUFBUUVFQUFKQkJBQURBUUFBQXdFQUFBSEJCQUFBQUFBQUFRRUVBQUpCQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFEQVFBQUF3RUFBQUhCQkFBQUFBQUFBUUVFQUFKQkJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBREFRQUFBQUFBQUFKQkJraVJKUUpJa0NjRWtTYkpCQUFEQVFBQUF3RUFBQUhCQkFBQUFBQUFBUUVFQUFKQkJBQURBUUFBQUFBQUFBSkJCa2lSSlFKSWtDY0VrU2JKQkFBQkFRUUFBd0VBQUFIQkJWbFdWUWJDcUtyK3JxcEpCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBUUVFQUFIQkJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBd0VBQUFIQkJBQURBUUFBQVFFRUFBSEJCQUFDUVFRQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFIQkJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFRRUVBQUhCQkFBQ1FRUUFBd0VBQUFIQkJBQURBUUFBQXdFQUFBSkJCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBUUVFQUFIQkJBQUJBUVFBQVFFRUFBSEJCQUFEQVFBQUF3RUFBQUpCQkFBQkFRUUFBd0VBQUFIQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBUUVFQUFIQkJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFBQUFBQUpCQkFBQkFRUUFBd0VBQUFIQkJBQURBUUFBQUFBQUFBSkJCQUFCQVFRQUF3RUFBQUhCQkFBREFRQUFBQUFBQUFKQkJBQUJBUVFBQXdFQUFBSEJCQUFEQVFBQUFBQUFBQUpCQkFBQkFRUUFBd0VBQUFIQkJBQUJBUVFBQXdFQUFBSkJCQUFCQVFRQUF3RUFBQUhCQkFBQkFRUUFBd0VBQUFKQkJBQUNRUVFBQXdFQUFBSEJCQUFCQVFRQUFRRUVBQUhCQkFBQkFRUUFBd0VBQUFIQkJBQUJBUVFBQXdFQUFBSkJCQUFDUVFRQUF3RUFBQUhCQkFBREFRQUFBd0VBQUFKQkJBQUJBUVFBQXdFQUFBSEJCQUFCQVFRQUF3RUFBQUpCQkFBQkFRUUFBUUVFQUFIQkJBQURBUUFBQXdFQUFBSkJCQUFCQVFRQUF3RUFBQUhCQkFBQkFRUUFBd0VBQUFKQkJBQUJBUVFBQXdFQUFBSEJCVmxXVlFiQ3FLcitycXBKQkFBQ1FRUUFBd0VBQUFIQkJBQUJBUVFBQVFFRUFBSEJCQUFDUVFRQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFIQkJBQUJBUVFBQXdFQUFBSEJCVmxXVlFiQ3FLcitycXBKQkFBQ1FRUUFBd0VBQUFIQkJBQUJBUVFBQVFFRUFBSEJCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBd0VBQUFKQkJBQUNRUVFBQXdFQUFBSEJCQUFCQVFRQUFRRUVBQUhCQkFBQkFRUUFBa0VFQUFIQkJ3Zmx4UWFMMjJrRndmb1JCQUFDUVFRQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFIQkJBQUJBUVFBQXdFQUFBSkJCUXM2R1Fkd2JrejlrTmNwQkFBQ1FRUUFBd0VBQUFIQkJBQUJBUVFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUJBUVFBQXdFQUFBSEJCVmxXVlFiQ3FLcitycXBKQkFBQ1FRUUFBd0VBQUFIQkJBQUJBUVFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUJBUVFBQWtFRUFBSEJCd2ZseFFhTDIya0Z3Zm9SQkFBQ1FRUUFBd0VBQUFIQkJBQURBUUFBQXdFQUFBSkJCQUFDUVFRQUF3RUFBQUhCQkFBREFRQUFBd0VBQUFKQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUpCQkFBQ1FRUUFBd0VBQUFIQkJBQUNRUVFBQXdFQUFBSkJCQUFDUVFRQUF3RUFBQUhCQkFBQ1FRUUFBd0VBQUFKQkJBQUJBUVFBQXdFQUFBSkJCUXM2R1Fkd2JrejlrTmNwQkFBQ1FRUUFBd0VBQUFIQkJBQUJBUVFBQVFFRUFBSkJCQUFDUVFRQUF3RUFBQUhCQkFBQkFRUUFBUUVFQUFKQkJBQUJBUVFBQWtFRUFBSEJCd2ZseFFhTDIya0Z3Zm9SQkFBQ1FRUUFBd0VBQUFIQkJBQUJBUVFBQVFFRUFBSkJCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUNRUVFBQXdFQUFBSEJCQUFCQVFRQUFRRUVBQUpCQkFBQkFRUUFBd0VBQUFKQkJRczZHUWR3Ymt6OWtOY3BCQUFCQVFRQUFrRUVBQUhCQndmbHhRYUwyMmtGd2ZvUkJBQUFBQUFBQVFFRUFBSEJCUSswVndjSDVjVUZ3Zm9SQkFBQUFBQUFBUUVFQUFIQkJBQUFBQUFBQVFFRUFBSkJCQUFBQUFBQUFRRUVBQUhCQkFBQUFBQUFBUUVFQUFKQkJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBa0VFQUFIQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUFrRUVBQUhCQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFEQVFBQUFRRUVBQUhCQkFBREFRQUFBQUFBQUFKQkJBQURBUUFBQVFFRUFBSEJCQUFEQVFBQUFBQUFBQUpCQkFBREFRQUFBUUVFQUFIQkJBQURBUUFBQUFBQUFBSkJCQUFEQVFBQUFRRUVBQUhCQkFBREFRQUFBQUFBQUFKQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUpCQkFBREFRQUFBUUVFQUFIQkJBQUJBUVFBQXdFQUFBSkJCQUFCQVFRQUFRRUVBQUhCQkFBREFRQUFBd0VBQUFKQkJBQURBUUFBQVFFRUFBSEJCQUFCQVFRQUF3RUFBQUpCQkFBQkFRUUFBUUVFQUFIQkJBQUFBQUFBQVFFRUFBSkJCQUFEQVFBQUFRRUVBQUhCQkFBQkFRUUFBd0VBQUFKQkJBQURBUUFBQXdFQUFBSkJCQUFBQUFBQUFRRUVBQUpCQkFBREFRQUFBUUVFQUFIQkJBQURBUUFBQVFFRUFBSkJCQUFEQVFBQUFRRUVBQUhCQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBREFRQUFBUUVFQUFIQkJBQURBUUFBQVFFRUFBSkJCQUFCQVFRQUFRRUVBQUhCQkFBREFRQUFBd0VBQUFKQkJBQURBUUFBQVFFRUFBSEJCQUFEQVFBQUFRRUVBQUpCQkFBQkFRUUFBUUVFQUFIQkJBQUFBQUFBQVFFRUFBSkJCQUFEQVFBQUFRRUVBQUhCQkFBREFRQUFBUUVFQUFKQkJBQURBUUFBQXdFQUFBSkJCQUFBQUFBQUFRRUVBQUpCQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFBQUFBQUFRRUVBQUhCQlErMFZ3Y0g1Y1VGd2ZvUkJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFEQVFBQUFRRUVBQUhCQnNLb3F2MVpWbFVHcnFwSkJBQURBUUFBQUFBQUFBSkJCa2lSSlFKSWtDY0VrU2JKQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFBQUFBQUFRRUVBQUpCQmtpUUp3ZHkyYlVFa1NiSkJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBQUFBQUFBUUVFQUFKQkJraVFKd2R5MmJVRWtTYkpCQUFBQUFBQUFRRUVBQUhCQlErMFZ3Y0g1Y1VGd2ZvUkJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBQUFBQUFBUUVFQUFKQkJraVFKd2R5MmJVRWtTYkpCQUFCQVFRQUFRRUVBQUhCQlZsV1ZRVlpWbFVHcnFwSkJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBQkFRUUFBUUVFQUFIQkJBQURBUUFBQXdFQUFBSkJCQUFCQVFRQUFRRUVBQUhCQkFBREFRQUFBd0VBQUFKQkJBQUJBUVFBQXdFQUFBSkJCQUFEQVFBQUFRRUVBQUpCQkFBQkFRUUFBUUVFQUFIQkJBQUFBQUFBQVFFRUFBSkJCQUFCQVFRQUFRRUVBQUhCQkFBQUFBQUFBUUVFQUFKQkJBQUJBUVFBQXdFQUFBSkJCQUFEQVFBQUFRRUVBQUpCQkFBQkFRUUFBUUVFQUFIQkJBQUJBUVFBQVFFRUFBSkJCQUFCQVFRQUFRRUVBQUhCQkFBQkFRUUFBUUVFQUFKQkJBQUJBUVFBQWtFRUFBSEJCd2ZseFFhTDIya0Z3Zm9SQkFBQkFRUUFBUUVFQUFIQkJBQUJBUVFBQVFFRUFBSkJCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUJBUVFBQVFFRUFBSEJCQUFCQVFRQUFRRUVBQUpCQkFBQkFRUUFBd0VBQUFKQkJBQURBUUFBQVFFRUFBSkJCQUFCQVFRQUFRRUVBQUhCQkFBQkFRUUFBUUVFQUFKQkJBQUJBUVFBQXdFQUFBSkJCUXM2R1Fkd2JrejlrTmNwQkFBQkFRUUFBa0VFQUFIQkJ3Zmx4UWFMMjJrRndmb1JCQUFCQVFRQUFrRUVBQUhCQndmbHhRYUwyMmtGd2ZvUkJBQUJBUVFBQWtFRUFBSEJCQUFCQVFRQUF3RUFBQUpCQkFBQkFRUUFBa0VFQUFIQkJBQUJBUVFBQXdFQUFBSkJCQUFCQVFRQUFRRUVBQUhCQlZsV1ZRVlpWbFVHcnFwSkJBQUJBUVFBQWtFRUFBSEJCQUFCQVFRQUF3RUFBQUpCQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFCQVFRQUFrRUVBQUhCQkFBQkFRUUFBd0VBQUFKQkJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFCQVFRQUFrRUVBQUhCQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQWtFRUFBSEJCQUFEQVFBQUFRRUVBQUpCQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFCQVFRQUFrRUVBQUhCQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBQkFRUUFBa0VFQUFIQkJBQURBUUFBQVFFRUFBSkJCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBQkFRUUFBa0VFQUFIQkJBQUJBUVFBQWtFRUFBSkJCQUFCQVFRQUFrRUVBQUhCQkFBQkFRUUFBa0VFQUFKQkJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBQkFRUUFBa0VFQUFIQkJ3Zmx4UWFMMjJrRndmb1JCQUFCQVFRQUFRRUVBQUhCQlZsV1ZRVlpWbFVHcnFwSkJBQUJBUVFBQWtFRUFBSEJCd2ZseFFhTDIya0Z3Zm9SQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFCQVFRQUFrRUVBQUhCQndmbHhRYUwyMmtGd2ZvUkJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFEQVFBQUFBQUFBQUpCQmtpUkpRSklrQ2NFa1NiSkJBQURBUUFBQUFBQUFBSkJCQUFCQVFRQUF3RUFBQUpCQkFBREFRQUFBQUFBQUFKQkJBQUJBUVFBQXdFQUFBSkJCQUFEQVFBQUFBQUFBQUpCQkFBREFRQUFBQUFBQUFLaEJBQURBUUFBQUFBQUFBSkJCQUFEQVFBQUFBQUFBQUtoQkFBREFRQUFBQUFBQUFKQkJraVJKUUpJa0NjRWtTYkpCQUFEQVFBQUFBQUFBQUhCQi9CZzRRRVB0RmNGd2ZvUkJBQURBUUFBQUFBQUFBSkJCa2lSSlFKSWtDY0VrU2JKQkFBREFRQUFBQUFBQUFIQkIvQmc0UUVQdEZjRndmb1JCQUFEQVFBQUFBQUFBQUpCQmtpUkpRSklrQ2NFa1NiSkJBQURBUUFBQUFBQUFBSkJCa2lSSlFKSWtDY0VrU2JKQkFBREFRQUFBQUFBQUFKQkJraVJKUUpJa0NjRWtTYkpCQUFEQVFBQUF3RUFBQUpCQkFBQUFBQUFBUUVFQUFKQkJBQURBUUFBQXdFQUFBSkJCQUFBQUFBQUFRRUVBQUpCQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFEQVFBQUF3RUFBQUpCQkFBQUFBQUFBUUVFQUFKQkJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBREFRQUFBQUFBQUFKQkJraVJKUUpJa0NjRWtTYkpCQUFEQVFBQUF3RUFBQUpCQkFBQUFBQUFBUUVFQUFKQkJBQURBUUFBQUFBQUFBSkJCa2lSSlFKSWtDY0VrU2JKQkFBREFRQUFBd0VBQUFKQkJBQUFBQUFBQVFFRUFBSkJCQUFCQVFRQUF3RUFBQUpCQkFBREFRQUFBUUVFQUFKQkJBQURBUUFBQXdFQUFBSkJCQUFBQUFBQUFRRUVBQUpCQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFEQVFBQUF3RUFBQUpCQkFBQUFBQUFBUUVFQUFKQkJBQURBUUFBQVFFRUFBSkJCM0J1VFAwTE9oa0ZrTmNwQkFBREFRQUFBUUVFQUFIQkJzS29xdjFaVmxVR3JxcEpCQUFEQVFBQUF3RUFBQUpCQkFBQkFRUUFBUUVFQUFKQkJBQURBUUFBQXdFQUFBSkJCQUFCQVFRQUFRRUVBQUpCQkFBQkFRUUFBd0VBQUFKQkJBQURBUUFBQVFFRUFBSkJCQUFEQVFBQUF3RUFBQUpCQkFBREFRQUFBd0VBQUFLaEJBQURBUUFBQXdFQUFBSkJCQUFEQVFBQUF3RUFBQUtoQkFBQkFRUUFBd0VBQUFKQkJBQURBUUFBQVFFRUFBSkJCQUFEQVFBQUF3RUFBQUpCQkFBREFRQUFBd0VBQUFLaEJBQURBUUFBQVFFRUFBSkJCM0J1VFAwTE9oa0ZrTmNwQkFBREFRQUFBd0VBQUFKQkJBQURBUUFBQXdFQUFBS2hCQUFEQVFBQUFRRUVBQUpCQjNCdVRQMExPaGtGa05jcEJBQURBUUFBQUFBQUFBS2hCVER4aFFJMGw3c0FvbmRsQkFBREFRQUFBd0VBQUFKQkJBQURBUUFBQXdFQUFBS2hCQUFEQVFBQUFBQUFBQUtoQlREeGhRSTBsN3NBb25kbEJBQURBUUFBQXdFQUFBSkJCQUFBQUFBQUFRRUVBQUtoQkFBREFRQUFBd0VBQUFKQkJBQUFBQUFBQVFFRUFBS2hCQUFEQVFBQUFRRUVBQUpCQjNCdVRQMExPaGtGa05jcEJBQURBUUFBQXdFQUFBSkJCQUFBQUFBQUFRRUVBQUtoQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFEQVFBQUFBQUFBQUtoQlREeGhRSTBsN3NBb25kbEJBQURBUUFBQXdFQUFBSkJCQUFBQUFBQUFRRUVBQUtoQkFBREFRQUFBQUFBQUFLaEJURHhoUUkwbDdzQW9uZGxCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUJBUVFBQXdFQUFBSEJCVmxXVlFiQ3FLcitycXBKQkFBQkFRUUFBd0VBQUFKQkJRczZHUWR3Ymt6OWtOY3BCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUJBUVFBQXdFQUFBSEJCVmxXVlFiQ3FLcitycXBKQkFBQkFRUUFBd0VBQUFKQkJRczZHUWR3Ymt6OWtOY3BCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUJBUVFBQXdFQUFBSkJCUXM2R1Fkd2JrejlrTmNwQkFBQkFRUUFBd0VBQUFKQkJRczZHUWR3Ymt6OWtOY3BCQUFCQVFRQUF3RUFBQUpCQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQXdFQUFBSkJCQUFEQVFBQUFRRUVBQUpCQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFCQVFRQUF3RUFBQUpCQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQXdFQUFBSkJCQUFEQVFBQUFRRUVBQUpCQkFBQ1FRUUFBd0VBQUFKQkJBQUJBUVFBQVFFRUFBSkJCQUFCQVFRQUF3RUFBQUpCQkFBREFRQUFBUUVFQUFKQkJBQUNRUVFBQXdFQUFBSkJCQUFEQVFBQUF3RUFBQUtoQkFBQkFRUUFBd0VBQUFKQkJBQURBUUFBQVFFRUFBSkJCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQUJBUVFBQXdFQUFBSkJCQUFEQVFBQUFRRUVBQUpCQkFBQkFRUUFBUUVFQUFKQkJBQURBUUFBQXdFQUFBS2hCQUFCQVFRQUF3RUFBQUpCQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFCQVFRQUF3RUFBQUpCQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQXdFQUFBSkJCQUFEQVFBQUFRRUVBQUpCQkFBQkFRUUFBd0VBQUFKQkJBQURBUUFBQUFBQUFBS2hCQUFCQVFRQUF3RUFBQUpCQkFBREFRQUFBQUFBQUFLaEJBQUJBUVFBQXdFQUFBSkJCQUFEQVFBQUFBQUFBQUtoQkFBQkFRUUFBd0VBQUFKQkJBQURBUUFBQUFBQUFBS2hCQUFCQVFRQUF3RUFBQUpCQkFBQkFRUUFBd0VBQUFLaEJBQUJBUVFBQXdFQUFBSkJCQUFCQVFRQUF3RUFBQUtoQkFBQ1FRUUFBd0VBQUFKQkJBQUJBUVFBQVFFRUFBSkJCQUFCQVFRQUF3RUFBQUpCQkFBQkFRUUFBd0VBQUFLaEJBQUNRUVFBQXdFQUFBSkJCQUFEQVFBQUF3RUFBQUtoQkFBQkFRUUFBd0VBQUFKQkJBQUJBUVFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQUpCQkFBREFRQUFBd0VBQUFLaEJBQUJBUVFBQXdFQUFBSkJCQUFCQVFRQUF3RUFBQUtoQkFBQkFRUUFBd0VBQUFKQkJRczZHUWR3Ymt6OWtOY3BCQUFCQVFRQUF3RUFBQUhCQlZsV1ZRYkNxS3IrcnFwSkJBQUJBUVFBQXdFQUFBSkJCUXM2R1Fkd2JrejlrTmNwQkFBQkFRUUFBd0VBQUFIQkJWbFdWUWJDcUtyK3JxcEpCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUJBUVFBQXdFQUFBSkJCUXM2R1Fkd2JrejlrTmNwQkFBQkFRUUFBa0VFQUFIQkJ3Zmx4UWFMMjJrRndmb1JCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUJBUVFBQXdFQUFBSkJCUXM2R1Fkd2JrejlrTmNwQkFBQ1FRUUFBd0VBQUFKQkJBQUJBUVFBQVFFRUFBSkJCQUFDUVFRQUF3RUFBQUpCQkFBQkFRUUFBUUVFQUFKQkJBQUJBUVFBQXdFQUFBSkJCUXM2R1Fkd2JrejlrTmNwQkFBQ1FRUUFBd0VBQUFKQkJBQUJBUVFBQVFFRUFBSkJCQUFEQVFBQUFRRUVBQUpCQkFBQkFRUUFBd0VBQUFLaEJBQUNRUVFBQXdFQUFBSkJCQUFCQVFRQUFRRUVBQUpCQkFBQkFRUUFBa0VFQUFKQkIzTFp0UVVtUzFFRWtTYkpCQUFDUVFRQUF3RUFBQUpCQkFBQkFRUUFBUUVFQUFKQkJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQ1FRUUFBd0VBQUFKQkJBQUJBUVFBQVFFRUFBSkJCQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQXdFQUFBSkJCUXM2R1Fkd2JrejlrTmNwQkFBQ1FRUUFBd0VBQUFKQkJBQUJBUVFBQVFFRUFBSkJCQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQWtFRUFBSkJCM0xadFFVbVMxRUVrU2JKQkFBQ1FRUUFBd0VBQUFKQkJBQURBUUFBQXdFQUFBS2hCQUFDUVFRQUF3RUFBQUpCQkFBREFRQUFBd0VBQUFLaEJBQURBUUFBQVFFRUFBSkJCQUFCQVFRQUF3RUFBQUtoQkFBQ1FRUUFBd0VBQUFKQkJBQUNRUVFBQXdFQUFBS2hCQUFDUVFRQUF3RUFBQUpCQkFBQ1FRUUFBd0VBQUFLaEJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQ1FRUUFBd0VBQUFKQkJBQUJBUVFBQVFFRUFBS2hCQUFDUVFRQUF3RUFBQUpCQkFBQkFRUUFBUUVFQUFLaEJBQUJBUVFBQWtFRUFBSkJCM0xadFFVbVMxRUVrU2JKQkFBQ1FRUUFBd0VBQUFKQkJBQUJBUVFBQVFFRUFBS2hCQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUNRUVFBQXdFQUFBSkJCQUFCQVFRQUFRRUVBQUtoQkFBQkFRUUFBd0VBQUFLaEJjYlIzUVQwdUlVQ05vZTFCQUFCQVFRQUFrRUVBQUpCQjNMWnRRVW1TMUVFa1NiSkJBQUFBQUFBQVFFRUFBSkJCa2lRSndkeTJiVUVrU2JKQkFBQUFBQUFBUUVFQUFKQkJBQUFBQUFBQVFFRUFBS2hCQUFBQUFBQUFRRUVBQUpCQkFBQUFBQUFBUUVFQUFLaEJBQURBUUFBQVFFRUFBSkJCM0J1VFAwTE9oa0ZrTmNwQkFBQUFBQUFBUUVFQUFKQkJraVFKd2R5MmJVRWtTYkpCQUFBQUFBQUFRRUVBQUhCQlErMFZ3Y0g1Y1VGd2ZvUkJBQUFBQUFBQVFFRUFBSkJCa2lRSndkeTJiVUVrU2JKQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFEQVFBQUFRRUVBQUpCQjNCdVRQMExPaGtGa05jcEJBQURBUUFBQVFFRUFBSkJCQUFCQVFRQUFrRUVBQUpCQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQWtFRUFBSkJCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQURBUUFBQVFFRUFBSkJCQUFEQVFBQUFBQUFBQUtoQkFBREFRQUFBUUVFQUFKQkJBQURBUUFBQUFBQUFBS2hCQUFEQVFBQUFRRUVBQUpCQkFBREFRQUFBQUFBQUFLaEJBQURBUUFBQVFFRUFBSkJCQUFEQVFBQUFBQUFBQUtoQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFRRUVBQUpCQkFBQkFRUUFBd0VBQUFLaEJBQUJBUVFBQVFFRUFBSkJCQUFEQVFBQUF3RUFBQUtoQkFBREFRQUFBUUVFQUFKQkJBQUJBUVFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQUpCQkFBQUFBQUFBUUVFQUFLaEJBQURBUUFBQVFFRUFBSkJCQUFCQVFRQUF3RUFBQUtoQkFBREFRQUFBd0VBQUFLaEJBQUFBQUFBQVFFRUFBS2hCQUFEQVFBQUFRRUVBQUpCQkFBREFRQUFBUUVFQUFLaEJBQURBUUFBQVFFRUFBSkJCQUFEQVFBQUFRRUVBQUtoQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFEQVFBQUFRRUVBQUpCQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQVFFRUFBSkJCQUFEQVFBQUF3RUFBQUtoQkFBREFRQUFBUUVFQUFKQkJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUFRRUVBQUpCQkFBQUFBQUFBUUVFQUFLaEJBQURBUUFBQVFFRUFBSkJCQUFEQVFBQUFRRUVBQUtoQkFBREFRQUFBd0VBQUFLaEJBQUFBQUFBQVFFRUFBS2hCQUFEQVFBQUFRRUVBQUpCQjNCdVRQMExPaGtGa05jcEJBQURBUUFBQVFFRUFBSEJCc0tvcXYxWlZsVUdycXBKQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFEQVFBQUFRRUVBQUhCQnNLb3F2MVpWbFVHcnFwSkJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFEQVFBQUFRRUVBQUhCQnNLb3F2MVpWbFVHcnFwSkJBQUFBQUFBQVFFRUFBSkJCa2lRSndkeTJiVUVrU2JKQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFEQVFBQUFRRUVBQUhCQnNLb3F2MVpWbFVHcnFwSkJBQUFBQUFBQVFFRUFBSkJCa2lRSndkeTJiVUVrU2JKQkFBQkFRUUFBUUVFQUFIQkJWbFdWUVZaVmxVR3JxcEpCQUFEQVFBQUFRRUVBQUpCQjNCdVRQMExPaGtGa05jcEJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFBQUFBQUFRRUVBQUpCQmtpUUp3ZHkyYlVFa1NiSkJBQURBUUFBQVFFRUFBSkJCM0J1VFAwTE9oa0ZrTmNwQkFBQUFBQUFBUUVFQUFKQkJraVFKd2R5MmJVRWtTYkpCQUFCQVFRQUFRRUVBQUhCQlZsV1ZRVlpWbFVHcnFwSkJBQURBUUFBQVFFRUFBSkJCM0J1VFAwTE9oa0ZrTmNwQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFEQVFBQUFRRUVBQUpCQjNCdVRQMExPaGtGa05jcEJBQURBUUFBQUFBQUFBS2hCVER4aFFJMGw3c0FvbmRsQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFBQUFBQUFRRUVBQUtoQmpTWHV3TzJ3WjBFb25kbEJBQURBUUFBQVFFRUFBSkJCM0J1VFAwTE9oa0ZrTmNwQkFBQUFBQUFBUUVFQUFLaEJqU1h1d08yd1owRW9uZGxCQUFBQUFBQUFRRUVBQUpCQmtpUUp3ZHkyYlVFa1NiSkJBQURBUUFBQVFFRUFBSkJCM0J1VFAwTE9oa0ZrTmNwQkFBQUFBQUFBUUVFQUFLaEJqU1h1d08yd1owRW9uZGxCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBQkFRUUFBUUVFQUFKQkJBQURBUUFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQUpCQkFBREFRQUFBd0VBQUFLaEJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFRRUVBQUtoQkFBQkFRUUFBUUVFQUFKQkJBQUFBQUFBQVFFRUFBS2hCQUFCQVFRQUFRRUVBQUpCQkFBQUFBQUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFRRUVBQUtoQkFBQkFRUUFBUUVFQUFKQkJBQUJBUVFBQVFFRUFBS2hCQUFCQVFRQUFRRUVBQUpCQkFBQkFRUUFBUUVFQUFLaEJBQUJBUVFBQWtFRUFBSkJCM0xadFFVbVMxRUVrU2JKQkFBQkFRUUFBUUVFQUFKQkJBQUJBUVFBQVFFRUFBS2hCQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQVFFRUFBSkJCQUFCQVFRQUFRRUVBQUtoQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUFRRUVBQUpCQkFBQkFRUUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQkFRUUFBa0VFQUFKQkIzTFp0UVVtUzFFRWtTYkpCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQUJBUVFBQVFFRUFBSEJCVmxXVlFWWlZsVUdycXBKQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFCQVFRQUFrRUVBQUhCQndmbHhRYUwyMmtGd2ZvUkJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBQkFRUUFBa0VFQUFKQkIzTFp0UVVtUzFFRWtTYkpCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQUJBUVFBQWtFRUFBSkJCM0xadFFVbVMxRUVrU2JKQkFBQkFRUUFBa0VFQUFIQkJ3Zmx4UWFMMjJrRndmb1JCQUFCQVFRQUFrRUVBQUpCQjNMWnRRVW1TMUVFa1NiSkJBQUJBUVFBQWtFRUFBSkJCQUFCQVFRQUF3RUFBQUtoQkFBQkFRUUFBa0VFQUFKQkJBQUJBUVFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQUJBUVFBQWtFRUFBSkJCQUFCQVFRQUF3RUFBQUtoQkFBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFCQVFRQUFrRUVBQUpCQkFBQkFRUUFBd0VBQUFLaEJBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFCQVFRQUFrRUVBQUpCQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQWtFRUFBSkJCQUFEQVFBQUFRRUVBQUtoQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFCQVFRQUFrRUVBQUpCQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBa0VFQUFKQkJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBQkFRUUFBa0VFQUFKQkJBQUJBUVFBQWtFRUFBS2hCQUFCQVFRQUFrRUVBQUpCQkFBQkFRUUFBa0VFQUFLaEJBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBa0VFQUFKQkIzTFp0UVVtUzFFRWtTYkpCQUFCQVFRQUFrRUVBQUhCQndmbHhRYUwyMmtGd2ZvUkJBQUJBUVFBQWtFRUFBSkJCM0xadFFVbVMxRUVrU2JKQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFCQVFRQUFrRUVBQUpCQjNMWnRRVW1TMUVFa1NiSkJBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBa0VFQUFKQkIzTFp0UVVtUzFFRWtTYkpCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBREFRQUFBQUFBQUFLaEJURHhoUUkwbDdzQW9uZGxCQUFEQVFBQUFBQUFBQUtoQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQUFBQUFBS2hCQUFCQVFRQUF3RUFBQUtoQkFBREFRQUFBQUFBQUFLaEJBQURBUUFBQUFBQUFBTUJCQUFEQVFBQUFBQUFBQUtoQlREeGhRSTBsN3NBb25kbEJBQURBUUFBQUFBQUFBSkJCa2lSSlFKSWtDY0VrU2JKQkFBREFRQUFBQUFBQUFLaEJURHhoUUkwbDdzQW9uZGxCQUFEQVFBQUFBQUFBQUpCQmtpUkpRSklrQ2NFa1NiSkJBQURBUUFBQUFBQUFBS2hCVER4aFFJMGw3c0FvbmRsQkFBREFRQUFBQUFBQUFLaEJURHhoUUkwbDdzQW9uZGxCQUFEQVFBQUFBQUFBQUtoQlREeGhRSTBsN3NBb25kbEJBQURBUUFBQXdFQUFBS2hCQUFBQUFBQUFRRUVBQUtoQkFBREFRQUFBd0VBQUFLaEJBQUFBQUFBQVFFRUFBS2hCQUFEQVFBQUFRRUVBQUpCQjNCdVRQMExPaGtGa05jcEJBQURBUUFBQXdFQUFBS2hCQUFBQUFBQUFRRUVBQUtoQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFEQVFBQUFBQUFBQUtoQlREeGhRSTBsN3NBb25kbEJBQURBUUFBQXdFQUFBS2hCQUFBQUFBQUFRRUVBQUtoQkFBREFRQUFBQUFBQUFLaEJURHhoUUkwbDdzQW9uZGxCQUFEQVFBQUF3RUFBQUtoQkFBQUFBQUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFRRUVBQUtoQkFBREFRQUFBd0VBQUFLaEJBQUFBQUFBQVFFRUFBS2hCQUFEQVFBQUFRRUVBQUtoQlBTNGhRSEcwZDBHTm9lMUJBQURBUUFBQXdFQUFBS2hCQUFBQUFBQUFRRUVBQUtoQkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFEQVFBQUFRRUVBQUpCQjNCdVRQMExPaGtGa05jcEJBQURBUUFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQUtoQkFBREFRQUFBd0VBQUFLaEJBQUJBUVFBQVFFRUFBS2hCQUFCQVFRQUF3RUFBQUtoQkFBREFRQUFBUUVFQUFLaEJBQURBUUFBQXdFQUFBS2hCQUFEQVFBQUF3RUFBQU1CQkFBQkFRUUFBd0VBQUFKQkJRczZHUWR3Ymt6OWtOY3BCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQkFRUUFBd0VBQUFLaEJjYlIzUVQwdUlVQ05vZTFCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQkFRUUFBd0VBQUFKQkJRczZHUWR3Ymt6OWtOY3BCQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUF3RUFBQUtoQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFRRUVBQUtoQkFBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQUJBUVFBQXdFQUFBS2hCQUFCQVFRQUF3RUFBQU1CQkFBQkFRUUFBd0VBQUFLaEJjYlIzUVQwdUlVQ05vZTFCQUFCQVFRQUF3RUFBQUpCQlFzNkdRZHdia3o5a05jcEJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQkFRUUFBd0VBQUFKQkJRczZHUWR3Ymt6OWtOY3BCQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQkFRUUFBa0VFQUFKQkIzTFp0UVVtUzFFRWtTYkpCQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQ1FRUUFBd0VBQUFLaEJBQUJBUVFBQVFFRUFBS2hCQUFDUVFRQUF3RUFBQUtoQkFBQkFRUUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQ1FRUUFBd0VBQUFLaEJBQUNRUVFBQXdFQUFBTUJCQUFBQUFBQUFRRUVBQUtoQmpTWHV3TzJ3WjBFb25kbEJBQUFBQUFBQVFFRUFBS2hCQUFBQUFBQUFRRUVBQU1CQkFBQUFBQUFBUUVFQUFLaEJqU1h1d08yd1owRW9uZGxCQUFBQUFBQUFRRUVBQUpCQmtpUUp3ZHkyYlVFa1NiSkJBQUFBQUFBQVFFRUFBS2hCalNYdXdPMndaMEVvbmRsQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFEQVFBQUFRRUVBQUtoQlBTNGhRSEcwZDBHTm9lMUJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUFrRUVBQUtoQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQWtFRUFBS2hCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQURBUUFBQVFFRUFBS2hCQUFEQVFBQUFRRUVBQU1CQkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFEQVFBQUFRRUVBQUpCQjNCdVRQMExPaGtGa05jcEJBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFBQUFBQUFRRUVBQUtoQmpTWHV3TzJ3WjBFb25kbEJBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBREFRQUFBUUVFQUFKQkIzQnVUUDBMT2hrRmtOY3BCQUFBQUFBQUFRRUVBQUtoQmpTWHV3TzJ3WjBFb25kbEJBQUJBUVFBQVFFRUFBSkJCUXM2R1FVTE9oa0ZrTmNwQkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBQUFBQUFBUUVFQUFLaEJqU1h1d08yd1owRW9uZGxCQUFEQVFBQUFRRUVBQUtoQlBTNGhRSEcwZDBHTm9lMUJBQUFBQUFBQVFFRUFBS2hCalNYdXdPMndaMEVvbmRsQkFBQkFRUUFBUUVFQUFKQkJRczZHUVVMT2hrRmtOY3BCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQUJBUVFBQVFFRUFBS2hCQUFCQVFRQUFRRUVBQU1CQkFBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFCQVFRQUFRRUVBQUpCQlFzNkdRVUxPaGtGa05jcEJBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBa0VFQUFKQkIzTFp0UVVtUzFFRWtTYkpCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQUJBUVFBQWtFRUFBS2hCN2JCblFXT0p5MEVvbmRsQkFBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFCQVFRQUFrRUVBQUtoQjdiQm5RV09KeTBFb25kbEJBQUJBUVFBQWtFRUFBSkJCM0xadFFVbVMxRUVrU2JKQkFBQkFRUUFBa0VFQUFLaEI3YkJuUVdPSnkwRW9uZGxCQUFCQVFRQUFrRUVBQUtoQkFBQkFRUUFBa0VFQUFNQkJBQUJBUVFBQWtFRUFBS2hCN2JCblFXT0p5MEVvbmRsQkFBQkFRUUFBa0VFQUFKQkIzTFp0UVVtUzFFRWtTYkpCQUFEQVFBQUFBQUFBQUtoQlREeGhRSTBsN3NBb25kbEJBQURBUUFBQUFBQUFBS2hCQUFCQVFRQUF3RUFBQUtoQkFBREFRQUFBQUFBQUFLaEJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFBQUFBQUtoQkFBREFRQUFBQUFBQUFNQkJBQURBUUFBQUFBQUFBS2hCQUFEQVFBQUFBQUFBQU1CQkFBREFRQUFBQUFBQUFLaEJURHhoUUkwbDdzQW9uZGxCQUFEQVFBQUF3RUFBQUtoQkFBQUFBQUFBUUVFQUFLaEJBQURBUUFBQXdFQUFBS2hCQUFBQUFBQUFRRUVBQUtoQkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFEQVFBQUF3RUFBQUtoQkFBQkFRUUFBUUVFQUFLaEJBQURBUUFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQUtoQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQVFFRUFBS2hCQUFEQVFBQUF3RUFBQUtoQkFBREFRQUFBd0VBQUFNQkJBQURBUUFBQXdFQUFBS2hCQUFEQVFBQUF3RUFBQU1CQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQVFFRUFBS2hCQUFEQVFBQUF3RUFBQUtoQkFBREFRQUFBd0VBQUFNQkJBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBREFRQUFBd0VBQUFLaEJBQURBUUFBQXdFQUFBTUJCQUFEQVFBQUFRRUVBQUtoQlBTNGhRSEcwZDBHTm9lMUJBQURBUUFBQUFBQUFBTUJCL1ZGNFFBU0Z5OEFpWFB0QkFBREFRQUFBd0VBQUFLaEJBQURBUUFBQXdFQUFBTUJCQUFEQVFBQUFBQUFBQU1CQi9WRjRRQVNGeThBaVhQdEJBQURBUUFBQXdFQUFBS2hCQUFBQUFBQUFRRUVBQU1CQkFBREFRQUFBd0VBQUFLaEJBQUFBQUFBQVFFRUFBTUJCQUFEQVFBQUFRRUVBQUtoQlBTNGhRSEcwZDBHTm9lMUJBQURBUUFBQXdFQUFBS2hCQUFBQUFBQUFRRUVBQU1CQkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFEQVFBQUFBQUFBQU1CQi9WRjRRQVNGeThBaVhQdEJBQURBUUFBQXdFQUFBS2hCQUFBQUFBQUFRRUVBQU1CQkFBREFRQUFBQUFBQUFNQkIvVkY0UUFTRnk4QWlYUHRCQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFRRUVBQUtoQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUF3RUFBQUtoQkFBREFRQUFBUUVFQUFLaEJBQUNRUVFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQUtoQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQVFFRUFBS2hCQUFDUVFRQUF3RUFBQUtoQkFBREFRQUFBd0VBQUFNQkJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFRRUVBQUtoQkFBQkFRUUFBUUVFQUFLaEJBQURBUUFBQXdFQUFBTUJCQUFCQVFRQUF3RUFBQUtoQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFRRUVBQUtoQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQUFBQUFBTUJCQUFCQVFRQUF3RUFBQUtoQkFBREFRQUFBQUFBQUFNQkJBQUJBUVFBQXdFQUFBS2hCQUFEQVFBQUFBQUFBQU1CQkFBQkFRUUFBd0VBQUFLaEJBQURBUUFBQUFBQUFBTUJCQUFCQVFRQUF3RUFBQUtoQkFBQkFRUUFBd0VBQUFNQkJBQUJBUVFBQXdFQUFBS2hCQUFCQVFRQUF3RUFBQU1CQkFBQ1FRUUFBd0VBQUFLaEJBQUJBUVFBQVFFRUFBS2hCQUFCQVFRQUF3RUFBQUtoQkFBQkFRUUFBd0VBQUFNQkJBQUNRUVFBQXdFQUFBS2hCQUFEQVFBQUF3RUFBQU1CQkFBQkFRUUFBd0VBQUFLaEJBQUJBUVFBQXdFQUFBTUJCQUFCQVFRQUFRRUVBQUtoQkFBREFRQUFBd0VBQUFNQkJBQUJBUVFBQXdFQUFBS2hCQUFCQVFRQUF3RUFBQU1CQkFBQkFRUUFBd0VBQUFLaEJjYlIzUVQwdUlVQ05vZTFCQUFDUVFRQUF3RUFBQUtoQkFBQkFRUUFBUUVFQUFLaEJBQUNRUVFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQUtoQkFBQkFRUUFBd0VBQUFLaEJjYlIzUVQwdUlVQ05vZTFCQUFDUVFRQUF3RUFBQUtoQkFBQkFRUUFBUUVFQUFLaEJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUF3RUFBQU1CQkFBQ1FRUUFBd0VBQUFLaEJBQUJBUVFBQVFFRUFBS2hCQUFCQVFRQUFrRUVBQUtoQjdiQm5RV09KeTBFb25kbEJBQUNRUVFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQUtoQkFBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFDUVFRQUF3RUFBQUtoQkFBQkFRUUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQkFRUUFBd0VBQUFLaEJjYlIzUVQwdUlVQ05vZTFCQUFDUVFRQUF3RUFBQUtoQkFBQkFRUUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQkFRUUFBa0VFQUFLaEI3YkJuUVdPSnkwRW9uZGxCQUFDUVFRQUF3RUFBQUtoQkFBREFRQUFBd0VBQUFNQkJBQUNRUVFBQXdFQUFBS2hCQUFEQVFBQUF3RUFBQU1CQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBTUJCQUFDUVFRQUF3RUFBQUtoQkFBQ1FRUUFBd0VBQUFNQkJBQUNRUVFBQXdFQUFBS2hCQUFDUVFRQUF3RUFBQU1CQkFBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFDUVFRQUF3RUFBQUtoQkFBQkFRUUFBUUVFQUFNQkJBQUNRUVFBQXdFQUFBS2hCQUFCQVFRQUFRRUVBQU1CQkFBQkFRUUFBa0VFQUFLaEI3YkJuUVdPSnkwRW9uZGxCQUFDUVFRQUF3RUFBQUtoQkFBQkFRUUFBUUVFQUFNQkJBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQ1FRUUFBd0VBQUFLaEJBQUJBUVFBQVFFRUFBTUJCQUFCQVFRQUF3RUFBQU1CQmttSnFRYnAxVmtCQUZnVkNBQUJBUVFBQWtFRUFBS2hCN2JCblFXT0p5MEVvbmRsQkFBQUFBQUFBUUVFQUFLaEJqU1h1d08yd1owRW9uZGxCQUFBQUFBQUFRRUVBQUtoQkFBQUFBQUFBUUVFQUFNQkJBQUFBQUFBQVFFRUFBS2hCQUFBQUFBQUFRRUVBQU1CQkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFEQVFBQUFRRUVBQUtoQlBTNGhRSEcwZDBHTm9lMUJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUFrRUVBQUtoQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQWtFRUFBS2hCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQURBUUFBQVFFRUFBS2hCQUFEQVFBQUFBQUFBQU1CQkFBREFRQUFBUUVFQUFLaEJBQURBUUFBQUFBQUFBTUJCQUFEQVFBQUFRRUVBQUtoQkFBREFRQUFBQUFBQUFNQkJBQURBUUFBQVFFRUFBS2hCQUFEQVFBQUFBQUFBQU1CQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBTUJCQUFEQVFBQUFRRUVBQUtoQkFBQkFRUUFBd0VBQUFNQkJBQUJBUVFBQVFFRUFBS2hCQUFEQVFBQUF3RUFBQU1CQkFBREFRQUFBUUVFQUFLaEJBQUJBUVFBQXdFQUFBTUJCQUFCQVFRQUFRRUVBQUtoQkFBQUFBQUFBUUVFQUFNQkJBQURBUUFBQVFFRUFBS2hCQUFCQVFRQUF3RUFBQU1CQkFBREFRQUFBd0VBQUFNQkJBQUFBQUFBQVFFRUFBTUJCQUFEQVFBQUFRRUVBQUtoQkFBREFRQUFBUUVFQUFNQkJBQURBUUFBQVFFRUFBS2hCQUFEQVFBQUFRRUVBQU1CQkFBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFEQVFBQUFRRUVBQUtoQkFBREFRQUFBUUVFQUFNQkJBQUJBUVFBQVFFRUFBS2hCQUFEQVFBQUF3RUFBQU1CQkFBREFRQUFBUUVFQUFLaEJBQURBUUFBQVFFRUFBTUJCQUFCQVFRQUFRRUVBQUtoQkFBQUFBQUFBUUVFQUFNQkJBQURBUUFBQVFFRUFBS2hCQUFEQVFBQUFRRUVBQU1CQkFBREFRQUFBd0VBQUFNQkJBQUFBQUFBQVFFRUFBTUJCQUFEQVFBQUFRRUVBQUtoQlBTNGhRSEcwZDBHTm9lMUJBQUFBQUFBQVFFRUFBS2hCalNYdXdPMndaMEVvbmRsQkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBREFRQUFBQUFBQUFNQkIvVkY0UUFTRnk4QWlYUHRCQUFEQVFBQUFRRUVBQUtoQlBTNGhRSEcwZDBHTm9lMUJBQUFBQUFBQVFFRUFBTUJCQklYTHdJSHJZVUVpWFB0QkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFBQUFBQUFRRUVBQU1CQkJJWEx3SUhyWVVFaVhQdEJBQUFBQUFBQVFFRUFBS2hCalNYdXdPMndaMEVvbmRsQkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFBQUFBQUFRRUVBQU1CQkJJWEx3SUhyWVVFaVhQdEJBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFCQVFRQUFRRUVBQUtoQkFBREFRQUFBd0VBQUFNQkJBQUJBUVFBQVFFRUFBS2hCQUFEQVFBQUF3RUFBQU1CQkFBQkFRUUFBd0VBQUFNQkJBQURBUUFBQVFFRUFBTUJCQUFCQVFRQUFRRUVBQUtoQkFBQUFBQUFBUUVFQUFNQkJBQUJBUVFBQVFFRUFBS2hCQUFBQUFBQUFRRUVBQU1CQkFBQkFRUUFBd0VBQUFNQkJBQURBUUFBQVFFRUFBTUJCQUFCQVFRQUFRRUVBQUtoQkFBQkFRUUFBUUVFQUFNQkJBQUJBUVFBQVFFRUFBS2hCQUFCQVFRQUFRRUVBQU1CQkFBQkFRUUFBa0VFQUFLaEI3YkJuUVdPSnkwRW9uZGxCQUFCQVFRQUFRRUVBQUtoQkFBQkFRUUFBUUVFQUFNQkJBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQkFRUUFBUUVFQUFLaEJBQUJBUVFBQVFFRUFBTUJCQUFCQVFRQUF3RUFBQU1CQkFBREFRQUFBUUVFQUFNQkJBQUJBUVFBQVFFRUFBS2hCQUFCQVFRQUFRRUVBQU1CQkFBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFCQVFRQUFrRUVBQUtoQjdiQm5RV09KeTBFb25kbEJBQUJBUVFBQWtFRUFBS2hCN2JCblFXT0p5MEVvbmRsQkFBQkFRUUFBa0VFQUFLaEJBQUJBUVFBQXdFQUFBTUJCQUFCQVFRQUFrRUVBQUtoQkFBQkFRUUFBd0VBQUFNQkJBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBa0VFQUFLaEJBQUJBUVFBQXdFQUFBTUJCQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkNBQUJBUVFBQWtFRUFBS2hCQUFCQVFRQUF3RUFBQU1CQkFBQkFRUUFBUUVFQUFNQkJrbUpxUVpKaWFrRkFGZ1ZDQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQUJBUVFBQWtFRUFBS2hCQUFEQVFBQUFRRUVBQU1CQkFBQkFRUUFBa0VFQUFLaEJBQURBUUFBQVFFRUFBTUJCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQUJBUVFBQWtFRUFBS2hCQUFEQVFBQUFRRUVBQU1CQkFBQkFRUUFBUUVFQUFNQkJrbUpxUVpKaWFrRkFGZ1ZDQUFCQVFRQUFrRUVBQUtoQkFBREFRQUFBUUVFQUFNQkJBQUJBUVFBQVFFRUFBTUJCa21KcVFaSmlha0ZBRmdWQ0FBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFCQVFRQUFrRUVBQUtoQkFBQkFRUUFBa0VFQUFNQkJBQUJBUVFBQWtFRUFBS2hCQUFCQVFRQUFrRUVBQU1CQkFBQkFRUUFBUUVFQUFNQkJrbUpxUVpKaWFrRkFGZ1ZDQUFCQVFRQUFrRUVBQUtoQjdiQm5RV09KeTBFb25kbEJBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBa0VFQUFLaEI3YkJuUVdPSnkwRW9uZGxCQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkNBQUJBUVFBQWtFRUFBS2hCN2JCblFXT0p5MEVvbmRsQkFBQkFRUUFBUUVFQUFNQkJrbUpxUVpKaWFrRkFGZ1ZDQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQURBUUFBQUFBQUFBTUJCL1ZGNFFBU0Z5OEFpWFB0QkFBREFRQUFBQUFBQUFNQkJBQUJBUVFBQXdFQUFBTUJCQUFEQVFBQUFBQUFBQU1CQkFBQkFRUUFBd0VBQUFNQkJBQURBUUFBQUFBQUFBTUJCL1ZGNFFBU0Z5OEFpWFB0QkFBREFRQUFBQUFBQUFLaEJURHhoUUkwbDdzQW9uZGxCQUFEQVFBQUFBQUFBQU1CQi9WRjRRQVNGeThBaVhQdEJBQURBUUFBQUFBQUFBS2hCVER4aFFJMGw3c0FvbmRsQkFBREFRQUFBQUFBQUFNQkIvVkY0UUFTRnk4QWlYUHRCQUFEQVFBQUFBQUFBQU1CQi9WRjRRQVNGeThBaVhQdEJBQURBUUFBQUFBQUFBTUJCL1ZGNFFBU0Z5OEFpWFB0QkFBREFRQUFBQUFBQUFNQkIvVkY0UUFTRnk4QWlYUHRCQUFCQVFRQUF3RUFBQU1CQmttSnFRYnAxVmtCQUZnVkNBQURBUUFBQUFBQUFBTUJCL1ZGNFFBU0Z5OEFpWFB0QkFBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFEQVFBQUF3RUFBQU1CQkFBQUFBQUFBUUVFQUFNQkJBQURBUUFBQXdFQUFBTUJCQUFBQUFBQUFRRUVBQU1CQkFBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFEQVFBQUF3RUFBQU1CQkFBQUFBQUFBUUVFQUFNQkJBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBREFRQUFBQUFBQUFNQkIvVkY0UUFTRnk4QWlYUHRCQUFEQVFBQUF3RUFBQU1CQkFBQUFBQUFBUUVFQUFNQkJBQURBUUFBQUFBQUFBTUJCL1ZGNFFBU0Z5OEFpWFB0QkFBREFRQUFBd0VBQUFNQkJBQUFBQUFBQVFFRUFBTUJCQUFCQVFRQUF3RUFBQU1CQkFBREFRQUFBUUVFQUFNQkJBQURBUUFBQXdFQUFBTUJCQUFBQUFBQUFRRUVBQU1CQkFBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFEQVFBQUF3RUFBQU1CQkFBQUFBQUFBUUVFQUFNQkJBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFEQVFBQUF3RUFBQU1CQkFBQkFRUUFBUUVFQUFNQkJBQURBUUFBQXdFQUFBTUJCQUFCQVFRQUFRRUVBQU1CQkFBQkFRUUFBd0VBQUFNQkJBQURBUUFBQVFFRUFBTUJCQUFEQVFBQUF3RUFBQU1CQkFBQUFBQUFBUUVFQUFOaEJBQURBUUFBQXdFQUFBTUJCQUFBQUFBQUFRRUVBQU5oQkFBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFEQVFBQUF3RUFBQU1CQkFBREFRQUFBd0VBQUFOaEJBQURBUUFBQXdFQUFBTUJCQUFEQVFBQUF3RUFBQU5oQkFBQkFRUUFBd0VBQUFNQkJBQURBUUFBQVFFRUFBTUJCQUFEQVFBQUF3RUFBQU1CQkFBREFRQUFBd0VBQUFOaEJBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBQkFRUUFBd0VBQUFLaEJjYlIzUVQwdUlVQ05vZTFCQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQkFRUUFBd0VBQUFLaEJjYlIzUVQwdUlVQ05vZTFCQUFCQVFRQUF3RUFBQU1CQmttSnFRYnAxVmtCQUZnVkNBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQkFRUUFBd0VBQUFNQkJBQURBUUFBQVFFRUFBTUJCQUFCQVFRQUF3RUFBQU1CQkFBREFRQUFBUUVFQUFNQkJBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBd0VBQUFNQkJBQURBUUFBQVFFRUFBTUJCQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkNBQUJBUVFBQXdFQUFBTUJCQUFEQVFBQUFRRUVBQU1CQkFBQkFRUUFBUUVFQUFNQkJBQURBUUFBQXdFQUFBTmhCQUFCQVFRQUF3RUFBQU1CQkFBREFRQUFBUUVFQUFNQkJBQUJBUVFBQVFFRUFBTUJCa21KcVFaSmlha0ZBRmdWQ0FBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFCQVFRQUF3RUFBQU1CQmttSnFRYnAxVmtCQUZnVkNBQUJBUVFBQXdFQUFBS2hCY2JSM1FUMHVJVUNOb2UxQkFBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFCQVFRQUF3RUFBQUtoQmNiUjNRVDB1SVVDTm9lMUJBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFCQVFRQUFrRUVBQUtoQjdiQm5RV09KeTBFb25kbEJBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFCQVFRQUF3RUFBQU1CQmttSnFRYnAxVmtCQUZnVkNBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFCQVFRQUF3RUFBQU1CQmttSnFRYnAxVmtCQUZnVkNBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFCQVFRQUF3RUFBQU1CQmttSnFRYnAxVmtCQUZnVkNBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFDUVFRQUF3RUFBQU1CQkFBQkFRUUFBUUVFQUFNQkJBQUNRUVFBQXdFQUFBTUJCQUFCQVFRQUFRRUVBQU1CQkFBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFDUVFRQUF3RUFBQU1CQkFBQkFRUUFBUUVFQUFNQkJBQUJBUVFBQXdFQUFBTUJCa21KcVFicDFWa0JBRmdWQ0FBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFDUVFRQUF3RUFBQU1CQkFBQkFRUUFBUUVFQUFNQkJBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBQ1FRUUFBd0VBQUFNQkJBQUJBUVFBQVFFRUFBTUJCQUFCQVFRQUFrRUVBQU1CQmdldGhRVUhod2tFaVhQdEJBQUNRUVFBQXdFQUFBTUJCQUFEQVFBQUF3RUFBQU5oQkFBQ1FRUUFBd0VBQUFNQkJBQURBUUFBQXdFQUFBTmhCQUFCQVFRQUF3RUFBQU1CQmttSnFRYnAxVmtCQUZnVkNBQUNRUVFBQXdFQUFBTUJCQUFEQVFBQUF3RUFBQU5oQkFBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQUNRUVFBQXdFQUFBTUJCQUFEQVFBQUF3RUFBQU5oQkFBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFDUVFRQUF3RUFBQU1CQkFBQkFRUUFBUUVFQUFOaEJBQUNRUVFBQXdFQUFBTUJCQUFCQVFRQUFRRUVBQU5oQkFBQkFRUUFBa0VFQUFNQkJnZXRoUVVIaHdrRWlYUHRCQUFDUVFRQUF3RUFBQU1CQkFBQ1FRUUFBd0VBQUFOaEJBQUFBQUFBQVFFRUFBTUJCQklYTHdJSHJZVUVpWFB0QkFBQUFBQUFBUUVFQUFNQkJBQUFBQUFBQVFFRUFBTmhCQUFBQUFBQUFRRUVBQU1CQkFBQUFBQUFBUUVFQUFOaEJBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBQUFBQUFBUUVFQUFNQkJCSVhMd0lIcllVRWlYUHRCQUFBQUFBQUFRRUVBQUtoQmpTWHV3TzJ3WjBFb25kbEJBQUFBQUFBQVFFRUFBTUJCQklYTHdJSHJZVUVpWFB0QkFBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQURBUUFBQVFFRUFBTUJCQUFCQVFRQUFrRUVBQU1CQkFBREFRQUFBUUVFQUFNQkJBQUJBUVFBQWtFRUFBTUJCQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkNBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBREFRQUFBUUVFQUFLaEJQUzRoUUhHMGQwR05vZTFCQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBQUFBQUFBUUVFQUFNQkJCSVhMd0lIcllVRWlYUHRCQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQURBUUFBQVFFRUFBS2hCUFM0aFFIRzBkMEdOb2UxQkFBQUFBQUFBUUVFQUFNQkJCSVhMd0lIcllVRWlYUHRCQUFCQVFRQUFRRUVBQUtoQmNiUjNRWEcwZDBHTm9lMUJBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBQUFBQUFBUUVFQUFNQkJCSVhMd0lIcllVRWlYUHRCQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQUFBQUFBQVFFRUFBTUJCQklYTHdJSHJZVUVpWFB0QkFBQkFRUUFBUUVFQUFLaEJjYlIzUVhHMGQwR05vZTFCQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQUJBUVFBQVFFRUFBTUJCa21KcVFaSmlha0ZBRmdWQ0FBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkNBQUJBUVFBQWtFRUFBTUJCZ2V0aFFVSGh3a0VpWFB0QkFBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFCQVFRQUFrRUVBQU1CQmdldGhRVUhod2tFaVhQdEJBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBQUFBQUFBUUVFQUFOaEJvNHV1d0VZWFhVRXV1Z3hDQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQUFBQUFBQVFFRUFBTmhCbzR1dXdFWVhYVUV1dWd4Q0FBQUFBQUFBUUVFQUFNQkJCSVhMd0lIcllVRWlYUHRCQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQUFBQUFBQVFFRUFBTmhCbzR1dXdFWVhYVUV1dWd4Q0FBQkFRUUFBUUVFQUFNQkJrbUpxUVpKaWFrRkFGZ1ZDQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkNBQUJBUVFBQVFFRUFBTUJCQUFBQUFBQUFRRUVBQU5oQkFBQkFRUUFBUUVFQUFNQkJBQUFBQUFBQVFFRUFBTmhCQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQUJBUVFBQVFFRUFBTUJCQUFEQVFBQUF3RUFBQU5oQkFBQkFRUUFBUUVFQUFNQkJBQURBUUFBQXdFQUFBTmhCQUFCQVFRQUF3RUFBQU1CQmttSnFRYnAxVmtCQUZnVkNBQUJBUVFBQVFFRUFBTUJCQUFEQVFBQUF3RUFBQU5oQkFBQkFRUUFBd0VBQUFNQkJrbUpxUWJwMVZrQkFGZ1ZDQUFEQVFBQUFRRUVBQU1CQnVuVldRSkppYWtGQUZnVkNBQUJBUVFBQVFFRUFBTUJCQUFEQVFBQUF3RUFBQU5oQkFBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFCQVFRQUFRRUVBQU1CQkFBQkFRUUFBUUVFQUFOaEJBQUJBUVFBQVFFRUFBTUJCQUFCQVFRQUFRRUVBQU5oQkFBQkFRUUFBa0VFQUFNQkJnZXRoUVVIaHdrRWlYUHRCQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkNBQUJBUVFBQVFFRUFBS2hCY2JSM1FYRzBkMEdOb2UxQkFBQkFRUUFBUUVFQUFNQkJrbUpxUVpKaWFrRkFGZ1ZDQUFCQVFRQUFrRUVBQUtoQjdiQm5RV09KeTBFb25kbEJBQUJBUVFBQVFFRUFBTUJCa21KcVFaSmlha0ZBRmdWQ0FBQkFRUUFBa0VFQUFNQkJnZXRoUVVIaHdrRWlYUHRCQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkNBQUJBUVFBQWtFRUFBTUJCZ2V0aFFVSGh3a0VpWFB0QkFBQkFRUUFBa0VFQUFLaEI3YkJuUVdPSnkwRW9uZGxCQUFCQVFRQUFrRUVBQU1CQmdldGhRVUhod2tFaVhQdEJBQUJBUVFBQWtFRUFBTUJCZ2V0aFFVSGh3a0VpWFB0QkFBQkFRUUFBa0VFQUFLaEI3YkJuUVdPSnkwRW9uZGxCQUFCQVFRQUFrRUVBQU1CQmdldGhRVUhod2tFaVhQdEJBQUJBUVFBQVFFRUFBTUJCa21KcVFaSmlha0ZBRmdWQ0FBQkFRUUFBa0VFQUFNQkJnZXRoUVVIaHdrRWlYUHRCQUFCQVFRQUFRRUVBQU5oQmdldGhRWUhyWVVIeEtCSkNBQUJBUVFBQWtFRUFBTUJCZ2V0aFFVSGh3a0VpWFB0QkFBQkFRUUFBUUVFQUFOaEJnZXRoUVlIcllVSHhLQkpDQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkNBQUFBQUFBQVFFRUFBTmhCbzR1dXdFWVhYVUV1dWd4Q0FBQUFBQUFBUUVFQUFOaEJBQURBUUFBQXdFQUFBTmhCQUFBQUFBQUFRRUVBQU5oQkFBREFRQUFBd0VBQUFOaEJBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBQUFBQUFBUUVFQUFOaEJvNHV1d0VZWFhVRXV1Z3hDQUFBQUFBQUFRRUVBQU1CQkJJWEx3SUhyWVVFaVhQdEJBQUFBQUFBQVFFRUFBTmhCbzR1dXdFWVhYVUV1dWd4Q0FBQkFRUUFBUUVFQUFNQkJrbUpxUVpKaWFrRkFGZ1ZDQUFEQVFBQUF3RUFBQU5oQkFBQkFRUUFBUUVFQUFOaEJBQURBUUFBQVFFRUFBTUJCdW5WV1FKSmlha0ZBRmdWQ0FBREFRQUFBUUVFQUFNQkJ1blZXUUpKaWFrRkFGZ1ZDQUFCQVFRQUFRRUVBQU5oQmdldGhRWUhyWVVIeEtCSkNBQUJBUVFBQVFFRUFBTmhCQUFDUVFRQUF3RUFBQU5oQkFBQkFRUUFBUUVFQUFOaEJnZXRoUVlIcllVSHhLQkpDQUFCQVFRQUFRRUVBQU1CQmttSnFRWkppYWtGQUZnVkMifSx7ImJ5dGVMZW5ndGgiOjg2MTYsIm5hbWUiOiJidWZfcmVkX3NjYXR0ZXJlZF9saW5lcyIsInVyaSI6ImRhdGE6YXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtO2Jhc2U2NCxBQURBUUFBQXdFQUFBQUFBL1ZGNFFQMVJlRUREb3hqQkFBQ1FRUUFBd0VBQUFBQUE2YUs3UVhUUmhVQzY2QUxCQUFEQVFBQUF3RUFBQUFBQS9WRjRRUDFSZUVERG94akJBQURBUUFBQXdFQUFBRUJBdW5WV1FMcDFWa0Q4c2NqQUFBREFRQUFBd0VBQUFFQkF1blZXUUxwMVZrRDhzY2pBQUFEQVFBQUF3RUFBQUFBQS9WRjRRUDFSZUVERG94akJBQURBUUFBQXdFQUFBRUJBdW5WV1FMcDFWa0Q4c2NqQUFBREFRQUFBd0VBQUFFQkF1blZXUUxwMVZrRDhzY2pBQUFEQVFBQUF3RUFBQUFBQS9WRjRRUDFSZUVERG94akJBQURBUUFBQXdFQUFBRUJBdW5WV1FMcDFWa0Q4c2NqQUFBQ1FRUUFBd0VBQUFBQUE2YUs3UVhUUmhVQzY2QUxCQUFDUVFRQUF3RUFBQUFBQTZhSzdRWFRSaFVDNjZBTEJBQURBUUFBQXdFQUFBRUJBdW5WV1FMcDFWa0Q4c2NqQUFBREFRQUFBd0VBQUFFQkF1blZXUUxwMVZrRDhzY2pBQUFEQVFBQUF3RUFBQUVCQXVuVldRTHAxVmtEOHNjakFBQUNRUVFBQXdFQUFBQUFBNmFLN1FYVFJoVUM2NkFMQkFBQ1FRUUFBd0VBQUFFQkFRZUhDUWYxUmVFQ0djSTNBQUFDUVFRQUF3RUFBQUVCQVFlSENRZjFSZUVDR2NJM0FBQUNRUVFBQXdFQUFBQUFBNmFLN1FYVFJoVUM2NkFMQkFBQ1FRUUFBd0VBQUFFQkFRZUhDUWYxUmVFQ0djSTNBQUFDUVFRQUF3RUFBQUVCQVFlSENRZjFSZUVDR2NJM0FBQUNRUVFBQXdFQUFBQUFBNmFLN1FYVFJoVUM2NkFMQkFBREFRQUFBd0VBQUFFQkF1blZXUUxwMVZrRDhzY2pBQUFEQVFBQUF3RUFBQUVCQXVuVldRTHAxVmtEOHNjakFBQURBUUFBQXdFQUFBRUJBdW5WV1FMcDFWa0Q4c2NqQUFBREFRQUFBd0VBQUFFQkF1blZXUUxwMVZrRDhzY2pBQUFEQVFBQUF3RUFBQUVCQXVuVldRTHAxVmtEOHNjakFBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFEQVFBQUF3RUFBQUVCQXVuVldRTHAxVmtEOHNjakFBQURBUUFBQXdFQUFBRUJBdW5WV1FMcDFWa0Q4c2NqQUFBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFEQVFBQUF3RUFBQU1CQVBTNGhRRDB1SVVCb0RDM0FBQURBUUFBQXdFQUFBRUJBdW5WV1FMcDFWa0Q4c2NqQUFBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFDUVFRQUF3RUFBQUVCQVFlSENRZjFSZUVDR2NJM0FBQUNRUVFBQXdFQUFBRUJBUWVIQ1FmMVJlRUNHY0kzQUFBREFRQUFBd0VBQUFFQkF1blZXUUxwMVZrRDhzY2pBQUFEQVFBQUF3RUFBQU1CQVBTNGhRRDB1SVVCb0RDM0FBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFFQkF1blZXUUxwMVZrRDhzY2pBQUFEQVFBQUF3RUFBQU1CQVBTNGhRRDB1SVVCb0RDM0FBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFFQkF1blZXUUxwMVZrRDhzY2pBQUFEQVFBQUF3RUFBQUVCQXVuVldRTHAxVmtEOHNjakFBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFEQVFBQUF3RUFBQUVCQXVuVldRTHAxVmtEOHNjakFBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFEQVFBQUF3RUFBQUVCQXVuVldRTHAxVmtEOHNjakFBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFDUVFRQUF3RUFBQUVCQVFlSENRZjFSZUVDR2NJM0FBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBQ1FRUUFBd0VBQUFFQkFRZUhDUWYxUmVFQ0djSTNBQUFEQVFBQUF3RUFBQU1CQVBTNGhRRDB1SVVCb0RDM0FBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFDUVFRQUF3RUFBQUVCQVFlSENRZjFSZUVDR2NJM0FBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBQ1FRUUFBd0VBQUFFQkFRZUhDUWYxUmVFQ0djSTNBQUFEQVFBQUF3RUFBQU1CQVBTNGhRRDB1SVVCb0RDM0FBQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFEQVFBQUF3RUFBQU1CQVBTNGhRRDB1SVVCb0RDM0FBQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFDUVFRQUF3RUFBQUVCQVFlSENRZjFSZUVDR2NJM0FBQUNRUVFBQXdFQUFBRUJBUWVIQ1FmMVJlRUNHY0kzQUFBQ1FRUUFBd0VBQUFNQkFZNG5MUVV3OFlVQWdsRTYrQUFDUVFRQUF3RUFBQU1CQVk0bkxRVXc4WVVBZ2xFNitBQUNRUVFBQXdFQUFBRUJBUWVIQ1FmMVJlRUNHY0kzQUFBQ1FRUUFBd0VBQUFNQkFZNG5MUVV3OFlVQWdsRTYrQUFDUVFRQUF3RUFBQU1CQVk0bkxRVXc4WVVBZ2xFNitBQUNRUVFBQXdFQUFBRUJBUWVIQ1FmMVJlRUNHY0kzQUFBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBTUJBUFM0aFFEMHVJVUJvREMzQUFBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBREFRQUFBd0VBQUFNQkFQUzRoUUQwdUlVQm9EQzNBQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBQ1FRUUFBd0VBQUFNQkFZNG5MUVV3OFlVQWdsRTYrQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQUNRUVFBQXdFQUFBTUJBWTRuTFFVdzhZVUFnbEU2K0FBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBQ1FRUUFBd0VBQUFNQkFZNG5MUVV3OFlVQWdsRTYrQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQUNRUVFBQXdFQUFBTUJBWTRuTFFVdzhZVUFnbEU2K0FBQ1FRUUFBd0VBQUFNQkFZNG5MUVV3OFlVQWdsRTYrQUFDUVFRQUF3RUFBQU1CQVk0bkxRVXc4WVVBZ2xFNitBQUNRUVFBQXdFQUFBQkJCU1pMVVFaSWtTVUJ1MjVaQUFBQ1FRUUFBd0VBQUFCQkJTWkxVUVpJa1NVQnUyNVpBQUFDUVFRQUF3RUFBQU1CQVk0bkxRVXc4WVVBZ2xFNitBQUNRUVFBQXdFQUFBQkJCU1pMVVFaSWtTVUJ1MjVaQUFBQ1FRUUFBd0VBQUFCQkJTWkxVUVpJa1NVQnUyNVpBQUFDUVFRQUF3RUFBQU1CQVk0bkxRVXc4WVVBZ2xFNitBQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBREFRQUFBd0VBQUFFQkJzS29xdjdDcUtyK3FxZ3BCQUFEQVFBQUF3RUFBQUJCQjNCdVRQOXdia3ovSXFkdy9BQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBQ1FRUUFBd0VBQUFCQkJTWkxVUVpJa1NVQnUyNVpBQUFDUVFRQUF3RUFBQUJCQlNaTFVRWklrU1VCdTI1WkFBQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBREFRQUFBd0VBQUFFQkJzS29xdjdDcUtyK3FxZ3BCQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBREFRQUFBd0VBQUFFQkJzS29xdjdDcUtyK3FxZ3BCQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBQkJCM0J1VFA5d2Jrei9JcWR3L0FBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBREFRQUFBd0VBQUFCQkIzQnVUUDl3Ymt6L0lxZHcvQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBQ1FRUUFBd0VBQUFCQkJTWkxVUVpJa1NVQnUyNVpBQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQUNRUVFBQXdFQUFBQkJCU1pMVVFaSWtTVUJ1MjVaQUFBREFRQUFBd0VBQUFFQkJzS29xdjdDcUtyK3FxZ3BCQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBQ1FRUUFBd0VBQUFCQkJTWkxVUVpJa1NVQnUyNVpBQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQUNRUVFBQXdFQUFBQkJCU1pMVVFaSWtTVUJ1MjVaQUFBREFRQUFBd0VBQUFFQkJzS29xdjdDcUtyK3FxZ3BCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBREFRQUFBd0VBQUFFQkJzS29xdjdDcUtyK3FxZ3BCQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBQ1FRUUFBd0VBQUFCQkJTWkxVUVpJa1NVQnUyNVpBQUFDUVFRQUF3RUFBQUJCQlNaTFVRWklrU1VCdTI1WkFBQUNRUVFBQXdFQUFBRUJCb3ZiYVFmd1lPRUFnQXlkQkFBQ1FRUUFBd0VBQUFFQkJvdmJhUWZ3WU9FQWdBeWRCQUFDUVFRQUF3RUFBQUJCQlNaTFVRWklrU1VCdTI1WkFBQUNRUVFBQXdFQUFBRUJCb3ZiYVFmd1lPRUFnQXlkQkFBQ1FRUUFBd0VBQUFFQkJvdmJhUWZ3WU9FQWdBeWRCQUFDUVFRQUF3RUFBQUJCQlNaTFVRWklrU1VCdTI1WkFBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUVCQnNLb3F2N0NxS3IrcXFncEJBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQURBUUFBQXdFQUFBRUJCc0tvcXY3Q3FLcitxcWdwQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQUNRUVFBQXdFQUFBRUJCb3ZiYVFmd1lPRUFnQXlkQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFDUVFRQUF3RUFBQUVCQm92YmFRZndZT0VBZ0F5ZEJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQUNRUVFBQXdFQUFBRUJCb3ZiYVFmd1lPRUFnQXlkQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFDUVFRQUF3RUFBQUVCQm92YmFRZndZT0VBZ0F5ZEJBQUNRUVFBQXdFQUFBRUJCb3ZiYVFmd1lPRUFnQXlkQkFBQ1FRUUFBd0VBQUFFQkJvdmJhUWZ3WU9FQWdBeWRCQUFDUVFRQUF3RUFBQUhCQm92YmFRZndZT0VCd2ZvUkJBQUNRUVFBQXdFQUFBSEJCb3ZiYVFmd1lPRUJ3Zm9SQkFBQ1FRUUFBd0VBQUFFQkJvdmJhUWZ3WU9FQWdBeWRCQUFDUVFRQUF3RUFBQUhCQm92YmFRZndZT0VCd2ZvUkJBQUNRUVFBQXdFQUFBSEJCb3ZiYVFmd1lPRUJ3Zm9SQkFBQ1FRUUFBd0VBQUFFQkJvdmJhUWZ3WU9FQWdBeWRCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQURBUUFBQXdFQUFBSkJCM0J1VFA5d2JrejlrTmNwQkFBREFRQUFBd0VBQUFIQkJzS29xdjdDcUtyK3JxcEpCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQUNRUVFBQXdFQUFBSEJCb3ZiYVFmd1lPRUJ3Zm9SQkFBQ1FRUUFBd0VBQUFIQkJvdmJhUWZ3WU9FQndmb1JCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQURBUUFBQXdFQUFBSkJCM0J1VFA5d2JrejlrTmNwQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQURBUUFBQXdFQUFBSkJCM0J1VFA5d2JrejlrTmNwQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUhCQnNLb3F2N0NxS3IrcnFwSkJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQURBUUFBQXdFQUFBSEJCc0tvcXY3Q3FLcitycXBKQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQUNRUVFBQXdFQUFBSEJCb3ZiYVFmd1lPRUJ3Zm9SQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFDUVFRQUF3RUFBQUhCQm92YmFRZndZT0VCd2ZvUkJBQURBUUFBQXdFQUFBSkJCM0J1VFA5d2JrejlrTmNwQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQUNRUVFBQXdFQUFBSEJCb3ZiYVFmd1lPRUJ3Zm9SQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFDUVFRQUF3RUFBQUhCQm92YmFRZndZT0VCd2ZvUkJBQURBUUFBQXdFQUFBSkJCM0J1VFA5d2JrejlrTmNwQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQUtoQlBTNGhRRDB1SVVDTm9lMUJBQURBUUFBQXdFQUFBSkJCM0J1VFA5d2JrejlrTmNwQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUtoQlBTNGhRRDB1SVVDTm9lMUJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUtoQlBTNGhRRDB1SVVDTm9lMUJBQUNRUVFBQXdFQUFBSEJCb3ZiYVFmd1lPRUJ3Zm9SQkFBQ1FRUUFBd0VBQUFIQkJvdmJhUWZ3WU9FQndmb1JCQUFDUVFRQUF3RUFBQUpCQlNaTFVRWklrU1VBa1NiSkJBQUNRUVFBQXdFQUFBSkJCU1pMVVFaSWtTVUFrU2JKQkFBQ1FRUUFBd0VBQUFIQkJvdmJhUWZ3WU9FQndmb1JCQUFDUVFRQUF3RUFBQUpCQlNaTFVRWklrU1VBa1NiSkJBQUNRUVFBQXdFQUFBSkJCU1pMVVFaSWtTVUFrU2JKQkFBQ1FRUUFBd0VBQUFIQkJvdmJhUWZ3WU9FQndmb1JCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFKQkIzQnVUUDl3Ymt6OWtOY3BCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQUpCQjNCdVRQOXdia3o5a05jcEJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFDUVFRQUF3RUFBQUpCQlNaTFVRWklrU1VBa1NiSkJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBQ1FRUUFBd0VBQUFKQkJTWkxVUVpJa1NVQWtTYkpCQUFEQVFBQUF3RUFBQUtoQlBTNGhRRDB1SVVDTm9lMUJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFDUVFRQUF3RUFBQUpCQlNaTFVRWklrU1VBa1NiSkJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBQ1FRUUFBd0VBQUFKQkJTWkxVUVpJa1NVQWtTYkpCQUFDUVFRQUF3RUFBQUpCQlNaTFVRWklrU1VBa1NiSkJBQUNRUVFBQXdFQUFBSkJCU1pMVVFaSWtTVUFrU2JKQkFBQ1FRUUFBd0VBQUFLaEJZNG5MUVV3OFlVQW9uZGxCQUFDUVFRQUF3RUFBQUtoQlk0bkxRVXc4WVVBb25kbEJBQUNRUVFBQXdFQUFBSkJCU1pMVVFaSWtTVUFrU2JKQkFBQ1FRUUFBd0VBQUFLaEJZNG5MUVV3OFlVQW9uZGxCQUFDUVFRQUF3RUFBQUtoQlk0bkxRVXc4WVVBb25kbEJBQUNRUVFBQXdFQUFBSkJCU1pMVVFaSWtTVUFrU2JKQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQUtoQlBTNGhRRDB1SVVDTm9lMUJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQUtoQlBTNGhRRDB1SVVDTm9lMUJBQURBUUFBQXdFQUFBTUJCdW5WV1FMcDFWa0JBRmdWQ0FBREFRQUFBd0VBQUFNQkJ1blZXUUxwMVZrQkFGZ1ZDQUFEQVFBQUF3RUFBQUtoQlBTNGhRRDB1SVVDTm9lMUJBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFNQkJ1blZXUUxwMVZrQkFGZ1ZDQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFNQkJ1blZXUUxwMVZrQkFGZ1ZDQUFDUVFRQUF3RUFBQUtoQlk0bkxRVXc4WVVBb25kbEJBQUNRUVFBQXdFQUFBS2hCWTRuTFFVdzhZVUFvbmRsQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBTUJCdW5WV1FMcDFWa0JBRmdWQ0FBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBS2hCUFM0aFFEMHVJVUNOb2UxQkFBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBTUJCdW5WV1FMcDFWa0JBRmdWQ0FBREFRQUFBd0VBQUFLaEJQUzRoUUQwdUlVQ05vZTFCQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBTUJCdW5WV1FMcDFWa0JBRmdWQ0FBREFRQUFBd0VBQUFNQkJ1blZXUUxwMVZrQkFGZ1ZDQUFEQVFBQUF3RUFBQUtoQlBTNGhRRDB1SVVDTm9lMUJBQURBUUFBQXdFQUFBTUJCdW5WV1FMcDFWa0JBRmdWQ0FBREFRQUFBd0VBQUFNQkJ1blZXUUxwMVZrQkFGZ1ZDQUFDUVFRQUF3RUFBQUtoQlk0bkxRVXc4WVVBb25kbEJBQURBUUFBQXdFQUFBTUJCdW5WV1FMcDFWa0JBRmdWQ0FBQ1FRUUFBd0VBQUFLaEJZNG5MUVV3OFlVQW9uZGxCQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBTUJCdW5WV1FMcDFWa0JBRmdWQ0FBREFRQUFBd0VBQUFNQkJ1blZXUUxwMVZrQkFGZ1ZDQUFDUVFRQUF3RUFBQUtoQlk0bkxRVXc4WVVBb25kbEJBQURBUUFBQXdFQUFBTUJCdW5WV1FMcDFWa0JBRmdWQ0FBQ1FRUUFBd0VBQUFLaEJZNG5MUVV3OFlVQW9uZGxCQUFDUVFRQUF3RUFBQUtoQlk0bkxRVXc4WVVBb25kbEJBQUNRUVFBQXdFQUFBS2hCWTRuTFFVdzhZVUFvbmRsQkFBREFRQUFBd0VBQUFNQkJ1blZXUUxwMVZrQkFGZ1ZDQUFDUVFRQUF3RUFBQU1CQlFlSENRZjFSZUVBaVhQdEJBQUNRUVFBQXdFQUFBTUJCUWVIQ1FmMVJlRUFpWFB0QkFBQ1FRUUFBd0VBQUFLaEJZNG5MUVV3OFlVQW9uZGxCQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBTmhCL1ZGNFFQMVJlRUR4S0JKQ0FBREFRQUFBd0VBQUFOaEIvVkY0UVAxUmVFRHhLQkpDQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBTmhCL1ZGNFFQMVJlRUR4S0JKQ0FBQ1FRUUFBd0VBQUFNQkJRZUhDUWYxUmVFQWlYUHRCQUFEQVFBQUF3RUFBQU5oQi9WRjRRUDFSZUVEeEtCSkNBQURBUUFBQXdFQUFBTmhCL1ZGNFFQMVJlRUR4S0JKQ0FBREFRQUFBd0VBQUFNQkJ1blZXUUxwMVZrQkFGZ1ZDQUFDUVFRQUF3RUFBQU1CQlFlSENRZjFSZUVBaVhQdEJBQUNRUVFBQXdFQUFBTUJCUWVIQ1FmMVJlRUFpWFB0QkFBQ1FRUUFBd0VBQUFLaEJZNG5MUVV3OFlVQW9uZGxCQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBTmhCL1ZGNFFQMVJlRUR4S0JKQ0FBREFRQUFBd0VBQUFOaEIvVkY0UVAxUmVFRHhLQkpDQUFEQVFBQUF3RUFBQU1CQnVuVldRTHAxVmtCQUZnVkNBQURBUUFBQXdFQUFBTmhCL1ZGNFFQMVJlRUR4S0JKQ0FBQ1FRUUFBd0VBQUFNQkJRZUhDUWYxUmVFQWlYUHRCQUFEQVFBQUF3RUFBQU5oQi9WRjRRUDFSZUVEeEtCSkNBQURBUUFBQXdFQUFBTmhCL1ZGNFFQMVJlRUR4S0JKQ0FBREFRQUFBd0VBQUFNQkJ1blZXUUxwMVZrQkFGZ1ZDQUFDUVFRQUF3RUFBQU5oQjZhSzdRWFRSaFVBdXVneENBQUNRUVFBQXdFQUFBTmhCNmFLN1FYVFJoVUF1dWd4Q0FBQ1FRUUFBd0VBQUFNQkJRZUhDUWYxUmVFQWlYUHRCIn1dLCJtYXRlcmlhbHMiOlt7ImRvdWJsZVNpZGVkIjp0cnVlLCJwYnJNZXRhbGxpY1JvdWdobmVzcyI6eyJiYXNlQ29sb3JGYWN0b3IiOlswLDAsMCwxXSwibWV0YWxsaWNGYWN0b3IiOjEsInJvdWdobmVzc0ZhY3RvciI6MX19LHsiZG91YmxlU2lkZWQiOnRydWUsInBick1ldGFsbGljUm91Z2huZXNzIjp7ImJhc2VDb2xvckZhY3RvciI6WzEsMC41LDAuNSwxXSwibWV0YWxsaWNGYWN0b3IiOjEsInJvdWdobmVzc0ZhY3RvciI6MX19LHsiZG91YmxlU2lkZWQiOnRydWUsInBick1ldGFsbGljUm91Z2huZXNzIjp7ImJhc2VDb2xvckZhY3RvciI6WzAsMCwwLDFdLCJtZXRhbGxpY0ZhY3RvciI6MSwicm91Z2huZXNzRmFjdG9yIjoxfX0seyJkb3VibGVTaWRlZCI6dHJ1ZSwicGJyTWV0YWxsaWNSb3VnaG5lc3MiOnsiYmFzZUNvbG9yRmFjdG9yIjpbMSwwLDAsMV0sIm1ldGFsbGljRmFjdG9yIjoxLCJyb3VnaG5lc3NGYWN0b3IiOjF9fV0sIm1lc2hlcyI6W3sicHJpbWl0aXZlcyI6W3siYXR0cmlidXRlcyI6eyJQT1NJVElPTiI6MH0sIm1hdGVyaWFsIjowLCJtb2RlIjo2fSx7ImF0dHJpYnV0ZXMiOnsiUE9TSVRJT04iOjF9LCJtYXRlcmlhbCI6MCwibW9kZSI6Nn0seyJhdHRyaWJ1dGVzIjp7IlBPU0lUSU9OIjoyfSwibWF0ZXJpYWwiOjAsIm1vZGUiOjZ9XX0seyJwcmltaXRpdmVzIjpbeyJhdHRyaWJ1dGVzIjp7IlBPU0lUSU9OIjozfSwibWF0ZXJpYWwiOjEsIm1vZGUiOjZ9LHsiYXR0cmlidXRlcyI6eyJQT1NJVElPTiI6NH0sIm1hdGVyaWFsIjoxLCJtb2RlIjo2fSx7ImF0dHJpYnV0ZXMiOnsiUE9TSVRJT04iOjV9LCJtYXRlcmlhbCI6MSwibW9kZSI6Nn1dfSx7InByaW1pdGl2ZXMiOlt7ImF0dHJpYnV0ZXMiOnsiUE9TSVRJT04iOjZ9LCJtYXRlcmlhbCI6MiwibW9kZSI6MX1dfSx7InByaW1pdGl2ZXMiOlt7ImF0dHJpYnV0ZXMiOnsiUE9TSVRJT04iOjd9LCJtYXRlcmlhbCI6MywibW9kZSI6MX1dfV0sIm5vZGVzIjpbeyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzAsMTIsMF19LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOls2LDYsMF19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlsxMiwxMiwwXX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6WzE4LDYsMF19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOls2LDAsM119LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOls2LDYsM119LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlsxMiw2LDNdfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbMTgsNiwzXX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzAsMTIsM119LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOls2LDEyLDNdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMTIsMTIsM119LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlsxMiwxOCwzXX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzYsMCw2XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6WzYsNiw2XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDYsNl19LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOlsxOCw2LDZdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMCwxMiw2XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzYsMTIsNl19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlsxMiwxMiw2XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDE4LDZdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbNiwwLDldfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbNiw2LDldfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMTIsNiw5XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6WzE4LDYsOV19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlswLDEyLDldfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbNiwxMiw5XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDEyLDldfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMTIsMTgsOV19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOls2LDAsMTJdfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbNiw2LDEyXX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDYsMTJdfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbMTgsNiwxMl19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlswLDEyLDEyXX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzYsMTIsMTJdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMTIsMTIsMTJdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMTIsMTgsMTJdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbNiwwLDE1XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6WzYsNiwxNV19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlsxMiw2LDE1XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6WzE4LDYsMTVdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMCwxMiwxNV19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOls2LDEyLDE1XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDEyLDE1XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDE4LDE1XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzYsMCwxOF19LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOls2LDYsMThdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMTIsNiwxOF19LHsibWVzaCI6MSwidHJhbnNsYXRpb24iOlsxOCw2LDE4XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzAsMTIsMThdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbNiwxMiwxOF19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlsxMiwxMiwxOF19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlsxMiwxOCwxOF19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOls2LDAsMjFdfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbNiw2LDIxXX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDYsMjFdfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbMTgsNiwyMV19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlswLDEyLDIxXX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzYsMTIsMjFdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMTIsMTIsMjFdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMTIsMTgsMjFdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbNiwwLDI0XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6WzYsNiwyNF19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOlsxMiw2LDI0XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6WzE4LDYsMjRdfSx7Im1lc2giOjAsInRyYW5zbGF0aW9uIjpbMCwxMiwyNF19LHsibWVzaCI6MCwidHJhbnNsYXRpb24iOls2LDEyLDI0XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDEyLDI0XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDE4LDI0XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzAsMTIsMjddfSx7Im1lc2giOjEsInRyYW5zbGF0aW9uIjpbNiw2LDI3XX0seyJtZXNoIjowLCJ0cmFuc2xhdGlvbiI6WzEyLDEyLDI3XX0seyJtZXNoIjoxLCJ0cmFuc2xhdGlvbiI6WzE4LDYsMjddfSx7Im1lc2giOjIsInRyYW5zbGF0aW9uIjpbMCwwLDBdfSx7Im1lc2giOjMsInRyYW5zbGF0aW9uIjpbMCwwLDBdfV0sInNjZW5lIjowLCJzY2VuZXMiOlt7Im5vZGVzIjpbMCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwxOSwyMCwyMSwyMiwyMywyNCwyNSwyNiwyNywyOCwyOSwzMCwzMSwzMiwzMywzNCwzNSwzNiwzNywzOCwzOSw0MCw0MSw0Miw0Myw0NCw0NSw0Niw0Nyw0OCw0OSw1MCw1MSw1Miw1Myw1NCw1NSw1Niw1Nyw1OCw1OSw2MCw2MSw2Miw2Myw2NCw2NSw2Niw2Nyw2OCw2OSw3MCw3MSw3Miw3M119XX0=&quot;&gt;Download 3D Model as .GLTF File&lt;/a&gt;\\n\",\n              \"  &lt;br&gt;Mouse Wheel = Zoom. Left Drag = Orbit. Right Drag = Strafe.\\n\",\n              \"  &lt;div id=&quot;stim-3d-viewer-scene-container&quot; style=&quot;width: calc(100vw - 32px); height: calc(100vh - 64px);&quot;&gt;JavaScript Blocked?&lt;/div&gt;\\n\",\n              \"\\n\",\n              \"  &lt;script type=&quot;module&quot;&gt;\\n\",\n              \"    let container = document.getElementById(&quot;stim-3d-viewer-scene-container&quot;);\\n\",\n              \"    let downloadLink = document.getElementById(&quot;stim-3d-viewer-download-link&quot;);\\n\",\n              \"    container.textContent = &quot;Loading viewer...&quot;;\\n\",\n              \"\\n\",\n              \"    /// BEGIN TERRIBLE HACK.\\n\",\n              \"    /// Change the ID to avoid cross-cell interactions.\\n\",\n              \"    /// This is a workaround for https://github.com/jupyter/notebook/issues/6598\\n\",\n              \"    container.id = undefined;\\n\",\n              \"    downloadLink.id = undefined;\\n\",\n              \"\\n\",\n              \"    import {Box3, Scene, Color, PerspectiveCamera, WebGLRenderer, DirectionalLight, Vector3} from &quot;three&quot;;\\n\",\n              \"    import {OrbitControls} from &quot;three-orbitcontrols&quot;;\\n\",\n              \"    import {GLTFLoader} from &quot;three-gltf-loader&quot;;\\n\",\n              \"\\n\",\n              \"    try {\\n\",\n              \"      container.textContent = &quot;Loading model...&quot;;\\n\",\n              \"      let modelDataUri = downloadLink.href;\\n\",\n              \"      let gltf = await new GLTFLoader().loadAsync(modelDataUri);\\n\",\n              \"      container.textContent = &quot;Loading scene...&quot;;\\n\",\n              \"\\n\",\n              \"      // Create the scene, adding lighting for the loaded objects.\\n\",\n              \"      let scene = new Scene();\\n\",\n              \"      scene.background = new Color(&quot;white&quot;);\\n\",\n              \"      let mainLight = new DirectionalLight(0xffffff, 5);\\n\",\n              \"      mainLight.position.set(1, 1, 0);\\n\",\n              \"      let backLight = new DirectionalLight(0xffffff, 4);\\n\",\n              \"      backLight.position.set(-1, -1, 0);\\n\",\n              \"      scene.add(mainLight, backLight);\\n\",\n              \"      scene.add(gltf.scene);\\n\",\n              \"\\n\",\n              \"      // Point the camera at the center, far enough back to see everything.\\n\",\n              \"      let camera = new PerspectiveCamera(35, container.clientWidth / container.clientHeight, 0.1, 100000);\\n\",\n              \"      let controls = new OrbitControls(camera, container);\\n\",\n              \"      let bounds = new Box3().setFromObject(scene);\\n\",\n              \"      let mid = new Vector3(\\n\",\n              \"          (bounds.min.x + bounds.max.x) * 0.5,\\n\",\n              \"          (bounds.min.y + bounds.max.y) * 0.5,\\n\",\n              \"          (bounds.min.z + bounds.max.z) * 0.5,\\n\",\n              \"      );\\n\",\n              \"      let boxPoints = [];\\n\",\n              \"      for (let dx of [0, 0.5, 1]) {\\n\",\n              \"          for (let dy of [0, 0.5, 1]) {\\n\",\n              \"              for (let dz of [0, 0.5, 1]) {\\n\",\n              \"                  boxPoints.push(new Vector3(\\n\",\n              \"                      bounds.min.x + (bounds.max.x - bounds.min.x) * dx,\\n\",\n              \"                      bounds.min.y + (bounds.max.y - bounds.min.y) * dy,\\n\",\n              \"                      bounds.min.z + (bounds.max.z - bounds.min.z) * dz,\\n\",\n              \"                  ));\\n\",\n              \"              }\\n\",\n              \"          }\\n\",\n              \"      }\\n\",\n              \"      let isInView = p =&gt; {\\n\",\n              \"          p = new Vector3(p.x, p.y, p.z);\\n\",\n              \"          p.project(camera);\\n\",\n              \"          return Math.abs(p.x) &lt; 1 &amp;&amp; Math.abs(p.y) &lt; 1 &amp;&amp; p.z &gt;= 0 &amp;&amp; p.z &lt; 1;\\n\",\n              \"      };\\n\",\n              \"      let unit = new Vector3(0.3, 0.4, -1.8);\\n\",\n              \"      unit.normalize();\\n\",\n              \"      let setCameraDistance = d =&gt; {\\n\",\n              \"          controls.target.copy(mid);\\n\",\n              \"          camera.position.copy(mid);\\n\",\n              \"          camera.position.addScaledVector(unit, d);\\n\",\n              \"          controls.update();\\n\",\n              \"          return boxPoints.every(isInView);\\n\",\n              \"      };\\n\",\n              \"\\n\",\n              \"      let maxDistance = 1;\\n\",\n              \"      for (let k = 0; k &lt; 20; k++) {\\n\",\n              \"          if (setCameraDistance(maxDistance)) {\\n\",\n              \"              break;\\n\",\n              \"          }\\n\",\n              \"          maxDistance *= 2;\\n\",\n              \"      }\\n\",\n              \"      let minDistance = maxDistance;\\n\",\n              \"      for (let k = 0; k &lt; 20; k++) {\\n\",\n              \"          minDistance /= 2;\\n\",\n              \"          if (!setCameraDistance(minDistance)) {\\n\",\n              \"              break;\\n\",\n              \"          }\\n\",\n              \"      }\\n\",\n              \"      for (let k = 0; k &lt; 20; k++) {\\n\",\n              \"          let mid = (minDistance + maxDistance) / 2;\\n\",\n              \"          if (setCameraDistance(mid)) {\\n\",\n              \"              maxDistance = mid;\\n\",\n              \"          } else {\\n\",\n              \"              minDistance = mid;\\n\",\n              \"          }\\n\",\n              \"      }\\n\",\n              \"      setCameraDistance(maxDistance);\\n\",\n              \"\\n\",\n              \"      // Set up rendering.\\n\",\n              \"      let renderer = new WebGLRenderer({ antialias: true });\\n\",\n              \"      container.textContent = &quot;&quot;;\\n\",\n              \"      renderer.setSize(container.clientWidth, container.clientHeight);\\n\",\n              \"      renderer.setPixelRatio(window.devicePixelRatio);\\n\",\n              \"      renderer.physicallyCorrectLights = true;\\n\",\n              \"      container.appendChild(renderer.domElement);\\n\",\n              \"\\n\",\n              \"      // Render whenever any important changes have occurred.\\n\",\n              \"      requestAnimationFrame(() =&gt; renderer.render(scene, camera));\\n\",\n              \"      new ResizeObserver(() =&gt; {\\n\",\n              \"        let w = container.clientWidth;\\n\",\n              \"        let h = container.clientHeight;\\n\",\n              \"        camera.aspect = w / h;\\n\",\n              \"        camera.updateProjectionMatrix();\\n\",\n              \"        renderer.setSize(w, h);\\n\",\n              \"        renderer.render(scene, camera);\\n\",\n              \"      }).observe(container);\\n\",\n              \"      controls.addEventListener(&quot;change&quot;, () =&gt; {\\n\",\n              \"          renderer.render(scene, camera);\\n\",\n              \"      })\\n\",\n              \"    } catch (ex) {\\n\",\n              \"      container.textContent = &quot;Failed to show model. &quot; + ex;\\n\",\n              \"      console.error(ex);\\n\",\n              \"    }\\n\",\n              \"  &lt;/script&gt;\\n\",\n              \"&lt;/body&gt;\\n\",\n              \"\\\"></iframe>\"\n            ],\n            \"text/plain\": [\n              \"{\\\"accessors\\\":[{\\\"bufferView\\\":0,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":9,\\\"max\\\":[0,0.400000005960464,0.400000005960464],\\\"min\\\":[0,-0.400000005960464,-0.400000005960464],\\\"name\\\":\\\"circle_loop\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":1,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":9,\\\"max\\\":[0.400000005960464,0,0.400000005960464],\\\"min\\\":[-0.400000005960464,0,-0.400000005960464],\\\"name\\\":\\\"circle_loop\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":2,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":9,\\\"max\\\":[0.400000005960464,0.400000005960464,0],\\\"min\\\":[-0.400000005960464,-0.400000005960464,0],\\\"name\\\":\\\"circle_loop\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":3,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":9,\\\"max\\\":[0,0.400000005960464,0.400000005960464],\\\"min\\\":[0,-0.400000005960464,-0.400000005960464],\\\"name\\\":\\\"circle_loop\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":4,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":9,\\\"max\\\":[0.400000005960464,0,0.400000005960464],\\\"min\\\":[-0.400000005960464,0,-0.400000005960464],\\\"name\\\":\\\"circle_loop\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":5,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":9,\\\"max\\\":[0.400000005960464,0.400000005960464,0],\\\"min\\\":[-0.400000005960464,-0.400000005960464,0],\\\"name\\\":\\\"circle_loop\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":6,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":4102,\\\"max\\\":[18.6666679382324,27.3704261779785,36.539981842041],\\\"min\\\":[-9.3704252243042,-9.3704252243042,-9.5399808883667],\\\"name\\\":\\\"buf_scattered_lines\\\",\\\"type\\\":\\\"VEC3\\\"},{\\\"bufferView\\\":7,\\\"byteOffset\\\":0,\\\"componentType\\\":5126,\\\"count\\\":718,\\\"max\\\":[27.3704261779785,6,36.539981842041],\\\"min\\\":[-0.666666984558105,-0.666666984558105,-9.5399808883667],\\\"name\\\":\\\"buf_red_scattered_lines\\\",\\\"type\\\":\\\"VEC3\\\"}],\\\"asset\\\":{\\\"version\\\":\\\"2.0\\\"},\\\"bufferViews\\\":[{\\\"buffer\\\":0,\\\"byteLength\\\":108,\\\"byteOffset\\\":0,\\\"name\\\":\\\"circle_loop\\\",\\\"target\\\":34962},{\\\"buffer\\\":1,\\\"byteLength\\\":108,\\\"byteOffset\\\":0,\\\"name\\\":\\\"circle_loop\\\",\\\"target\\\":34962},{\\\"buffer\\\":2,\\\"byteLength\\\":108,\\\"byteOffset\\\":0,\\\"name\\\":\\\"circle_loop\\\",\\\"target\\\":34962},{\\\"buffer\\\":3,\\\"byteLength\\\":108,\\\"byteOffset\\\":0,\\\"name\\\":\\\"circle_loop\\\",\\\"target\\\":34962},{\\\"buffer\\\":4,\\\"byteLength\\\":108,\\\"byteOffset\\\":0,\\\"name\\\":\\\"circle_loop\\\",\\\"target\\\":34962},{\\\"buffer\\\":5,\\\"byteLength\\\":108,\\\"byteOffset\\\":0,\\\"name\\\":\\\"circle_loop\\\",\\\"target\\\":34962},{\\\"buffer\\\":6,\\\"byteLength\\\":49224,\\\"byteOffset\\\":0,\\\"name\\\":\\\"buf_scattered_lines\\\",\\\"target\\\":34962},{\\\"buffer\\\":7,\\\"byteLength\\\":8616,\\\"byteOffset\\\":0,\\\"name\\\":\\\"buf_red_scattered_lines\\\",\\\"target\\\":34962}],\\\"buffers\\\":[{\\\"byteLength\\\":108,\\\"name\\\":\\\"circle_loop\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAMPQkD7D0JA+AAAAAPIwlrLNzMw+AAAAAMPQkL7D0JA+AAAAAM3MzL7yMBazAAAAAMHQkL7E0JC+AAAAAPLkozHNzMy+AAAAAMbQkD6/0JC+AAAAAM3MzD4AAAAA\\\"},{\\\"byteLength\\\":108,\\\"name\\\":\\\"circle_loop\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAAAAAAADNzMw+w9CQPgAAAADD0JA+zczMPgAAAADyMJayw9CQPgAAAADD0JC+8jAWswAAAADNzMy+xNCQvgAAAADB0JC+zczMvgAAAADy5KMxv9CQvgAAAADG0JA+AAAAAAAAAADNzMw+\\\"},{\\\"byteLength\\\":108,\\\"name\\\":\\\"circle_loop\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,zczMPgAAAAAAAAAAw9CQPsPQkD4AAAAA8jCWss3MzD4AAAAAw9CQvsPQkD4AAAAAzczMvvIwFrMAAAAAwdCQvsTQkL4AAAAA8uSjMc3MzL4AAAAAxtCQPr/QkL4AAAAAzczMPgAAAAAAAAAA\\\"},{\\\"byteLength\\\":108,\\\"name\\\":\\\"circle_loop\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAMPQkD7D0JA+AAAAAPIwlrLNzMw+AAAAAMPQkL7D0JA+AAAAAM3MzL7yMBazAAAAAMHQkL7E0JC+AAAAAPLkozHNzMy+AAAAAMbQkD6/0JC+AAAAAM3MzD4AAAAA\\\"},{\\\"byteLength\\\":108,\\\"name\\\":\\\"circle_loop\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,AAAAAAAAAADNzMw+w9CQPgAAAADD0JA+zczMPgAAAADyMJayw9CQPgAAAADD0JC+8jAWswAAAADNzMy+xNCQvgAAAADB0JC+zczMvgAAAADy5KMxv9CQvgAAAADG0JA+AAAAAAAAAADNzMw+\\\"},{\\\"byteLength\\\":108,\\\"name\\\":\\\"circle_loop\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,zczMPgAAAAAAAAAAw9CQPsPQkD4AAAAA8jCWss3MzD4AAAAAw9CQvsPQkD4AAAAAzczMvvIwFrMAAAAAwdCQvsTQkL4AAAAA8uSjMc3MzL4AAAAAxtCQPr/QkL4AAAAAzczMPgAAAAAAAAAA\\\"},{\\\"byteLength\\\":49224,\\\"name\\\":\\\"buf_scattered_lines\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,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AADAQAAAwEAAAEBAAADAQAAAwEAAAMBAAADAQAAAQEEAAEBAunVWQJJiakH8scjAAADAQAAAAAAAAMBATDxhQI0l7sAglE6+AADAQAAAwEAAAEBAAADAQAAAwEAAAMBAAADAQAAAAAAAAMBATDxhQI0l7sAglE6+AADAQAAAwEAAAEBAAAAAAAAAQEEAAMBAAADAQAAAwEAAAEBAAAAAAAAAQEEAAMBAAADAQAAAQEEAAEBAunVWQJJiakH8scjAAADAQAAAwEAAAEBAAAAAAAAAQEEAAMBAAADAQAAAQEEAAEBAunVWQJJiakH8scjAAADAQAAAAAAAAMBATDxhQI0l7sAglE6+AADAQAAAwEAAAEBAAAAAAAAAQEEAAMBAAADAQAAAAAAAAMBATDxhQI0l7sAglE6+AABAQQAAwEAAAEBAkmJqQbp1VkD8scjAAABAQQAAwEAAAEBAAADAQAAAQEEAAEBAAABAQQAAwEAAAEBAAADAQAAAQEEAAEBAAABAQQAAwEAAAEBAAADAQAAAQEEAAEBAAACQQQAAwEAAAEBAAABAQQAAQEEAAEBAAABAQQAAwEAAAEBAAADAQAAAQEEAAEBAAACQQQAAwEAAAEBAAADAQAAAwEAAAMBAAABAQQAAwEAAAEBAAADAQAAAQEEAAEBAAABAQQAAQEEAAEBAAADAQAAAwEAAAMBAAABAQQAAwEAAAEBAAADAQAAAQEEAAEBAAABAQQAAwEAAAEBAAADAQAAAQEEAAEBAAABAQQAAwEAAAEBAAADAQAAAAAAAAMBAAABAQQAAwEAAAEBAAADAQAAAAAAAAMBAAABAQQAAwEAAAEBAAADAQAAAAAAAAMBAAABAQQAAwEAAAEBAAADAQAAAAAAAAMBAAABAQQAAwEAAAEBAAABAQQAAwEAAAMBAAABAQQAAwEAAAEBAAABAQQAAwEAAAMBAAACQQQAAwEAAAEBAAABAQQAAQEEAAEBAAABAQQAAwEAAAEBAAABAQQAAwEAAAMBAAACQQQAAwEAAAEBAAADAQAAAwEAAAMBAAABAQQAAwEAAAEBAAABAQQAAwEAAAMBAAABAQQAAQEEAAEBAAADAQAAAwEAAAMBAAABAQQAAwEAAAEBAAABAQQAAwEAAAMBAAABAQQAAwEAAAEBAkmJqQbp1VkD8scjAAACQQQAAwEAAAEBA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AAAAAAAAQEEAAMBAAABAQQAAQEEAAEBAAAAAAAAAQEEAAMBAAABAQQAAwEAAAMBAAADAQAAAQEEAAMBAAABAQQAAQEEAAEBAAABAQQAAQEEAAMBAAABAQQAAQEEAAEBAAABAQQAAQEEAAMBAAABAQQAAkEEAAEBAgethQUHhwkGGcI3AAABAQQAAQEEAAEBAAABAQQAAQEEAAMBAAABAQQAAwEAAAMBAcbR3QT0uIUBoDC3AAABAQQAAQEEAAEBAAABAQQAAQEEAAMBAAABAQQAAwEAAAMBAAADAQAAAQEEAAMBAAABAQQAAQEEAAEBAAABAQQAAQEEAAMBAAABAQQAAwEAAAMBAcbR3QT0uIUBoDC3AAABAQQAAkEEAAEBAgethQUHhwkGGcI3AAABAQQAAkEEAAEBAgethQUHhwkGGcI3AAABAQQAAkEEAAEBAAABAQQAAwEAAAMBAAABAQQAAkEEAAEBAAABAQQAAwEAAAMBAAABAQQAAQEEAAEBAkmJqQZJiakH8scjAAABAQQAAkEEAAEBAAABAQQAAwEAAAMBAAABAQQAAQEEAAMBAcbR3QXG0d0FoDC3AAABAQQAAkEEAAEBAAABAQQAAwEAAAMBAAABAQQAAQEEAAMBAcbR3QXG0d0FoDC3AAABAQQAAQEEAAEBAkmJqQZJiakH8scjAAABAQQAAkEEAAEBAAADAQAAAQEEAAMBAAABAQQAAkEEAAEBAAADAQAAAQEEAAMBAAABAQQAAQEEAAEBAkmJqQZJiakH8scjAAABAQQAAkEEAAEBAAADAQAAAQEEAAMBAAABAQQAAQEEAAMBAcbR3QXG0d0FoDC3AAABAQQAAkEEAAEBAAADAQAAAQEEAAMBAAABAQQAAQEEAAMBAcbR3QXG0d0FoDC3AAABAQQAAQEEAAEBAkmJqQZJiakH8scjAAABAQQAAkEEAAEBAAABAQQAAkEEAAMBAAABAQQAAkEEAAEBAAABAQQAAkEEAAMBAAABAQQAAQEEAAMBAcbR3QXG0d0FoDC3AAABAQQAAkEEAAEBAgethQUHhwkGGcI3AAABAQQAAQEEAAEBAkmJqQZJiakH8scjAAABAQQAAkEEAAEBAgethQUHhwkGGcI3AAABAQQAAQEEAAMBAcbR3QXG0d0FoDC3AAABAQQAAkEEAAEBAgethQUHhwkGGcI3A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AADAQAAAwEAAABBBAAAAAAAAQEEAAEBBAADAQAAAQEEAABBB3BuTP0LOhkHIqdw/AADAQAAAAAAAAEBB/Bg4QEPtFcEgAydBAADAQAAAwEAAABBBAAAAAAAAQEEAAEBBAADAQAAAAAAAAEBB/Bg4QEPtFcEgAydBAABAQQAAwEAAABBBQs6GQdwbkz/Iqdw/AABAQQAAwEAAABBBAADAQAAAQEEAABBBAABAQQAAwEAAABBBAADAQAAAQEEAABBBAABAQQAAwEAAABBBAADAQAAAQEEAABBBAACQQQAAwEAAABBBAABAQQAAQEEAABBBAABAQQAAwEAAABBBAADAQAAAQEEAABBBAACQQQAAwEAAABBBAADAQAAAwEAAAEBBAABAQQAAwEAAABBBAADAQAAAQEEAABBBAABAQQAAQEEAABBBAADAQAAAwEAAAEBBAABAQQAAwEAAABBBAADAQAAAQEEAABBBAABAQQAAwEAAABBBAADAQAAAQEEAABBBAABAQQAAwEAAABBBAADAQAAAAAAAAEBBAABAQQAAwEAAABBBAADAQAAAAAAAAEBBAABAQQAAwEAAABBBAADAQAAAAAAAAEBBAABAQQAAwEAAABBBAADAQAAAAAAAAEBBAABAQQAAwEAAABBBAABAQQAAwEAAAEBBAABAQQAAwEAAABBBAABAQQAAwEAAAEBBAACQQQAAwEAAABBBAABAQQAAQEEAABBBAABAQQAAwEAAABBBAABAQQAAwEAAAEBBAACQQQAAwEAAABBBAADAQAAAwEAAAEBBAABAQQAAwEAAABBBAABAQQAAwEAAAEBBAABAQQAAQEEAABBBAADAQAAAwEAAAEBBAABAQQAAwEAAABBBAABAQQAAwEAAAEBBAABAQQAAwEAAABBBQs6GQdwbkz/Iqdw/AACQQQAAwEAAABBBAABAQQAAQEEAABBBAACQQQAAwEAAABBBAABAQQAAQEEAABBBAABAQQAAwEAAABBBQs6GQdwbkz/Iqdw/AACQQQAAwEAAABBBAABAQQAAQEEAABBBAADAQAAAQEEAABBBAABAQQAAwEAAAEBBAACQQQAAwEAAABBBAABAQQAAQEEAABBBAABAQQAAkEEAABBB3LZtQUmS1EFu25ZAAACQQQAAwEAAABBBAABAQQAAQEEAABBBAABAQQAAwEAAAEBB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AABAQQAAQEEAAHBBAADAQAAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAADAQAAAwEAAAHBBAADAQAAAwEAAAJBBAABAQQAAwEAAAEBBVlWVQbCqKr+qqgpBAABAQQAAwEAAAEBBVlWVQbCqKr+qqgpBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAEBBVlWVQbCqKr+qqgpBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAEBBVlWVQbCqKr+qqgpBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAABAQQAAQEEAAEBBVlWVQVZVlUGqqgpBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAQEEAAEBBVlWVQVZVlUGqqgpBAABAQQAAwEAAAHBBAABAQQAAwEAAAJBBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAEBBVlWVQbCqKr+qqgpBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAEBBVlWVQbCqKr+qqgpBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAkEEAAEBBwflxQaL22kEgAydBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAACQQQAAwEAAAHBBAACQQQAAwEAAAJBBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAAAAAAAAQEEAAHBBAAAAAAAAQEEAAJBBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAAAAAAAAQEEAAEBBQ+0VwcH5cUEgAydBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAABAQQAAQEEAAEBBVlWVQVZVlUGqqgpBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAQEEAAHBBAABAQQAAkEEAAHBBAADAQAAAQEEAAHBBAABAQQAAkEEAAHBBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAADAQAAAQEEAAHBBAADAQAAAQEEAAJBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAQEEAAEBBsKoqv1ZVlUGqqgpBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAQEEAAEBBsKoqv1ZVlUGqqgpBAABAQQAAQEEAAEBBVlWVQVZVlUGqqgpBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAQEEAAEBBsKoqv1ZVlUGqqgpBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAQEEAAEBBsKoqv1ZVlUGqqgpBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAABAQQAAQEEAAEBBVlWVQVZVlUGqqgpBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAABAQQAAQEEAAEBBVlWVQVZVlUGqqgpBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAABAQQAAQEEAAEBBVlWVQVZVlUGqqgpBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAQEEAAHBBAABAQQAAQEEAAJBBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAQEEAAEBBVlWVQVZVlUGqqgpBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAkEEAAEBBwflxQaL22kEgAydBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAkEEAAEBBwflxQaL22kEgAydBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAkEEAAHBBAABAQQAAkEEAAJBBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAkEEAAEBBwflxQaL22kEgAydBAADAQAAAAAAAAHBB/Bg4QEPtFcFwfoRBAADAQAAAAAAAAHBBAABAQQAAwEAAAHBBAADAQAAAAAAAAHBBAABAQQAAwEAAAHBBAADAQAAAAAAAAHBBAADAQAAAAAAAAJBBAADAQAAAAAAAAHBBAADAQAAAAAAAAJBBAADAQAAAAAAAAHBB/Bg4QEPtFcFwfoRBAADAQAAAwEAAAHBBAAAAAAAAQEEAAHBBAADAQAAAwEAAAHBBAAAAAAAAQEEAAHBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAwEAAAHBBAABAQQAAQEEAAHBBAADAQAAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAADAQAAAwEAAAHBBAADAQAAAwEAAAJBBAADAQAAAwEAAAHBBAADAQAAAwEAAAJBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAADAQAAAwEAAAHBBAADAQAAAwEAAAJBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAwEAAAHBBAADAQAAAwEAAAJBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAwEAAAHBBAADAQAAAwEAAAJBBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAwEAAAHBBAAAAAAAAQEEAAJBBAADAQAAAwEAAAHBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAwEAAAHBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAwEAAAHBBAAAAAAAAQEEAAJBBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAACQQQAAwEAAAHBBAADAQAAAwEAAAJBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAABAQQAAQEEAAHBBAADAQAAAwEAAAJBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAABAQQAAwEAAAHBBAADAQAAAQEEAAHBBAABAQQAAwEAAAHBBAADAQAAAAAAAAJBBAABAQQAAwEAAAHBBAADAQAAAAAAAAJBBAABAQQAAwEAAAHBBAADAQAAAAAAAAJBBAABAQQAAwEAAAHBBAADAQAAAAAAAAJBBAABAQQAAwEAAAHBBAABAQQAAwEAAAJBBAABAQQAAwEAAAHBBAABAQQAAwEAAAJBBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAwEAAAHBBAABAQQAAwEAAAJBBAACQQQAAwEAAAHBBAADAQAAAwEAAAJBBAABAQQAAwEAAAHBBAABAQQAAwEAAAJBBAABAQQAAQEEAAHBBAADAQAAAwEAAAJBBAABAQQAAwEAAAHBBAABAQQAAwEAAAJBBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAADAQAAAQEEAAHBBAABAQQAAwEAAAJBBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAACQQQAAwEAAAHBBAABAQQAAQEEAAHBBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAACQQQAAwEAAAHBBAADAQAAAwEAAAJBBAACQQQAAwEAAAHBBAADAQAAAwEAAAJBBAADAQAAAQEEAAHBBAABAQQAAwEAAAJBBAACQQQAAwEAAAHBBAACQQQAAwEAAAJBBAACQQQAAwEAAAHBBAACQQQAAwEAAAJBBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAACQQQAAwEAAAHBBAABAQQAAQEEAAJBBAACQQQAAwEAAAHBBAABAQQAAQEEAAJBBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAACQQQAAwEAAAHBBAABAQQAAQEEAAJBBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAACQQQAAwEAAAHBBAABAQQAAQEEAAJBBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAAAAAAAAQEEAAHBBAAAAAAAAQEEAAJBBAAAAAAAAQEEAAHBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAQEEAAHBBAABAQQAAkEEAAHBBAADAQAAAQEEAAHBBAABAQQAAkEEAAHBBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAADAQAAAQEEAAHBBAADAQAAAAAAAAJBBAADAQAAAQEEAAHBBAADAQAAAAAAAAJBBAADAQAAAQEEAAHBBAADAQAAAAAAAAJBBAADAQAAAQEEAAHBBAADAQAAAAAAAAJBBAADAQAAAQEEAAHBBAABAQQAAwEAAAJBBAADAQAAAQEEAAHBBAABAQQAAwEAAAJBBAABAQQAAQEEAAHBBAADAQAAAwEAAAJBBAADAQAAAQEEAAHBBAABAQQAAwEAAAJBBAABAQQAAQEEAAHBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAHBBAABAQQAAwEAAAJBBAADAQAAAwEAAAJBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAHBBAADAQAAAQEEAAJBBAADAQAAAQEEAAHBBAADAQAAAQEEAAJBBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAADAQAAAQEEAAHBBAADAQAAAQEEAAJBBAABAQQAAQEEAAHBBAADAQAAAwEAAAJBBAADAQAAAQEEAAHBBAADAQAAAQEEAAJBBAABAQQAAQEEAAHBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAHBBAADAQAAAQEEAAJBBAADAQAAAwEAAAJBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAAAAAAAAQEEAAJBBkiQJwdy2bUEkSbJBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAAAAAAAAQEEAAJBBkiQJwdy2bUEkSbJBAAAAAAAAQEEAAHBBQ+0VwcH5cUFwfoRBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAAAAAAAAQEEAAJBBkiQJwdy2bUEkSbJBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAQEEAAHBBAADAQAAAwEAAAJBBAABAQQAAQEEAAHBBAADAQAAAwEAAAJBBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAQEEAAHBBAAAAAAAAQEEAAJBBAABAQQAAQEEAAHBBAAAAAAAAQEEAAJBBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAQEEAAHBBAABAQQAAQEEAAJBBAABAQQAAQEEAAHBBAABAQQAAQEEAAJBBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAQEEAAHBBAABAQQAAQEEAAJBBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAQEEAAHBBAABAQQAAQEEAAJBBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAQEEAAHBBAABAQQAAQEEAAJBBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAkEEAAHBBAABAQQAAwEAAAJBBAABAQQAAkEEAAHBBAABAQQAAwEAAAJBBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAkEEAAHBBAABAQQAAwEAAAJBBAABAQQAAQEEAAJBBQs6GQULOhkFkNcpBAABAQQAAkEEAAHBBAABAQQAAwEAAAJBBAABAQQAAQEEAAJBBQs6GQULOhkFkNcpBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAkEEAAHBBAADAQAAAQEEAAJBBAABAQQAAkEEAAHBBAADAQAAAQEEAAJBBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAkEEAAHBBAADAQAAAQEEAAJBBAABAQQAAQEEAAJBBQs6GQULOhkFkNcpBAABAQQAAkEEAAHBBAADAQAAAQEEAAJBBAABAQQAAQEEAAJBBQs6GQULOhkFkNcpBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAkEEAAHBBAABAQQAAkEEAAJBBAABAQQAAkEEAAHBBAABAQQAAkEEAAJBBAABAQQAAQEEAAJBBQs6GQULOhkFkNcpBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAQEEAAJBBQs6GQULOhkFkNcpBAABAQQAAkEEAAHBBwflxQaL22kFwfoRBAABAQQAAQEEAAJBBQs6GQULOhkFkNcpBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAAAAAAJBBAABAQQAAwEAAAJBBAADAQAAAAAAAAJBBAABAQQAAwEAAAJBBAADAQAAAAAAAAJBBAADAQAAAAAAAAKhBAADAQAAAAAAAAJBBAADAQAAAAAAAAKhBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAAAAAAHBB/Bg4QEPtFcFwfoRBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAAAAAAHBB/Bg4QEPtFcFwfoRBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAwEAAAJBBAAAAAAAAQEEAAJBBAADAQAAAwEAAAJBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAwEAAAJBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAwEAAAJBBAAAAAAAAQEEAAJBBAADAQAAAAAAAAJBBkiRJQJIkCcEkSbJBAADAQAAAwEAAAJBBAAAAAAAAQEEAAJBBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAADAQAAAwEAAAJBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAJBB3BuTP0LOhkFkNcpBAADAQAAAwEAAAJBBAAAAAAAAQEEAAJBBAADAQAAAQEEAAJBB3BuTP0LOhkFkNcpBAADAQAAAQEEAAHBBsKoqv1ZVlUGrqpJBAADAQAAAwEAAAJBBAABAQQAAQEEAAJBBAADAQAAAwEAAAJBBAABAQQAAQEEAAJBBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAADAQAAAwEAAAJBBAADAQAAAwEAAAKhBAADAQAAAwEAAAJBBAADAQAAAwEAAAKhBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAADAQAAAwEAAAJBBAADAQAAAwEAAAKhBAADAQAAAQEEAAJBB3BuTP0LOhkFkNcpBAADAQAAAwEAAAJBBAADAQAAAwEAAAKhBAADAQAAAQEEAAJBB3BuTP0LOhkFkNcpBAADAQAAAAAAAAKhBTDxhQI0l7sAondlBAADAQAAAwEAAAJBBAADAQAAAwEAAAKhBAADAQAAAAAAAAKhBTDxhQI0l7sAondlBAADAQAAAwEAAAJBBAAAAAAAAQEEAAKhBAADAQAAAwEAAAJBBAAAAAAAAQEEAAKhBAADAQAAAQEEAAJBB3BuTP0LOhkFkNcpBAADAQAAAwEAAAJBBAAAAAAAAQEEAAKhBAADAQAAAQEEAAJBB3BuTP0LOhkFkNcpBAADAQAAAAAAAAKhBTDxhQI0l7sAondlBAADAQAAAwEAAAJBBAAAAAAAAQEEAAKhBAADAQAAAAAAAAKhBTDxhQI0l7sAondlBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAACQQQAAwEAAAJBBAABAQQAAQEEAAJBBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAACQQQAAwEAAAJBBAADAQAAAwEAAAKhBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAQEEAAJBBQs6GQULOhkFkNcpBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAQEEAAJBBAADAQAAAwEAAAKhBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAQEEAAJBBQs6GQULOhkFkNcpBAABAQQAAQEEAAHBBVlWVQVZVlUGrqpJBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAwEAAAJBBAADAQAAAQEEAAJBBAABAQQAAwEAAAJBBAADAQAAAAAAAAKhBAABAQQAAwEAAAJBBAADAQAAAAAAAAKhBAABAQQAAwEAAAJBBAADAQAAAAAAAAKhBAABAQQAAwEAAAJBBAADAQAAAAAAAAKhBAABAQQAAwEAAAJBBAABAQQAAwEAAAKhBAABAQQAAwEAAAJBBAABAQQAAwEAAAKhBAACQQQAAwEAAAJBBAABAQQAAQEEAAJBBAABAQQAAwEAAAJBBAABAQQAAwEAAAKhBAACQQQAAwEAAAJBBAADAQAAAwEAAAKhBAABAQQAAwEAAAJBBAABAQQAAwEAAAKhBAABAQQAAQEEAAJBBAADAQAAAwEAAAKhBAABAQQAAwEAAAJBBAABAQQAAwEAAAKhBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpBAABAQQAAwEAAAHBBVlWVQbCqKr+rqpJBAABAQQAAwEAAAJBBQs6GQdwbkz9kNcpB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AABAQQAAwEAAAKhBAADAQAAAAAAAAMBBAABAQQAAwEAAAKhBAADAQAAAAAAAAMBBAABAQQAAwEAAAKhBAADAQAAAAAAAAMBBAABAQQAAwEAAAKhBAADAQAAAAAAAAMBBAABAQQAAwEAAAKhBAABAQQAAwEAAAMBBAABAQQAAwEAAAKhBAABAQQAAwEAAAMBBAACQQQAAwEAAAKhBAABAQQAAQEEAAKhBAABAQQAAwEAAAKhBAABAQQAAwEAAAMBBAACQQQAAwEAAAKhBAADAQAAAwEAAAMBBAABAQQAAwEAAAKhBAABAQQAAwEAAAMBBAABAQQAAQEEAAKhBAADAQAAAwEAAAMBBAABAQQAAwEAAAKhBAABAQQAAwEAAAMBBAABAQQAAwEAAAKhBcbR3QT0uIUCNoe1BAACQQQAAwEAAAKhBAABAQQAAQEEAAKhBAACQQQAAwEAAAKhBAABAQQAAQEEAAKhBAABAQQAAwEAAAKhBcbR3QT0uIUCNoe1BAACQQQAAwEAAAKhBAABAQQAAQEEAAKhBAADAQAAAQEEAAKhBAABAQQAAwEAAAMBBAACQQQAAwEAAAKhBAABAQQAAQEEAAKhBAABAQQAAkEEAAKhB7bBnQWOJy0EondlBAACQQQAAwEAAAKhBAABAQQAAQEEAAKhBAABAQQAAwEAAAMBBkmJqQbp1VkBAFgVCAACQQQAAwEAAAKhBAABAQQAAQEEAAKhBAABAQQAAwEAAAMBBkmJqQbp1VkBAFgVCAABAQQAAwEAAAKhBcbR3QT0uIUCNoe1BAACQQQAAwEAAAKhBAABAQQAAQEEAAKhBAABAQQAAwEAAAMBBkmJqQbp1VkBAFgVCAABAQQAAkEEAAKhB7bBnQWOJy0EondlBAACQQQAAwEAAAKhBAADAQAAAwEAAAMBBAACQQQAAwEAAAKhBAADAQAAAwEAAAMBBAADAQAAAQEEAAKhBAABAQQAAwEAAAMBBAACQQQAAwEAAAKhBAACQQQAAwEAAAMBBAACQQQAAwEAAAKhBAACQQQAAwEAAAMBBAABAQQAAwEAAAMBBkmJqQbp1VkBAFgVCAACQQQAAwEAAAKhBAABAQQAAQEEAAMBBAACQQQAAwEAAAKhBAABAQQAAQEEAAMBBAABAQQAAkEEAAKhB7bBnQWOJy0EondlBAACQQQAAwEAAAKhB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unVWQJJiakFAFgVCAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAAAAAAAAQEEAANhBo4uuwEYXXUEuugxCAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAAAAAAAAQEEAANhBo4uuwEYXXUEuugxCAAAAAAAAQEEAAMBBBIXLwIHrYUEiXPtBAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAAAAAAAAQEEAANhBo4uuwEYXXUEuugxCAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAABAQQAAQEEAAMBBAAAAAAAAQEEAANhBAABAQQAAQEEAAMBBAAAAAAAAQEEAANhBAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAABAQQAAQEEAAMBBAADAQAAAwEAAANhBAABAQQAAQEEAAMBBAADAQAAAwEAAANhBAABAQQAAwEAAAMBBkmJqQbp1VkBAFgVCAABAQQAAQEEAAMBBAADAQAAAwEAAANhBAABAQQAAwEAAAMBBkmJqQbp1VkBAFgVCAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAABAQQAAQEEAAMBBAADAQAAAwEAAANhBAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAABAQQAAQEEAAMBBAABAQQAAQEEAANhBAABAQQAAQEEAAMBBAABAQQAAQEEAANhBAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAABAQQAAQEEAAKhBcbR3QXG0d0GNoe1BAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAABAQQAAkEEAAKhB7bBnQWOJy0EondlBAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAABAQQAAkEEAAKhB7bBnQWOJy0EondlBAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAABAQQAAkEEAAKhB7bBnQWOJy0EondlBAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAABAQQAAQEEAANhBgethQYHrYUHxKBJCAABAQQAAkEEAAMBBgethQUHhwkEiXPtBAABAQQAAQEEAANhBgethQYHrYUHxKBJCAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAAAAAAAAQEEAANhBo4uuwEYXXUEuugxCAAAAAAAAQEEAANhBAADAQAAAwEAAANhBAAAAAAAAQEEAANhBAADAQAAAwEAAANhBAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAAAAAAAAQEEAANhBo4uuwEYXXUEuugxCAAAAAAAAQEEAAMBBBIXLwIHrYUEiXPtBAAAAAAAAQEEAANhBo4uuwEYXXUEuugxCAABAQQAAQEEAAMBBkmJqQZJiakFAFgVCAADAQAAAwEAAANhBAABAQQAAQEEAANhBAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAADAQAAAQEEAAMBBunVWQJJiakFAFgVCAABAQQAAQEEAANhBgethQYHrYUHxKBJCAABAQQAAQEEAANhBAACQQQAAwEAAANhBAABAQQAAQEEAANhBgethQYHrYUHxKBJCAABAQQAAQEEAAMBBkmJqQZJiakFAFgVC\\\"},{\\\"byteLength\\\":8616,\\\"name\\\":\\\"buf_red_scattered_lines\\\",\\\"uri\\\":\\\"data:application/octet-stream;base64,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3BuTP9wbkz/Iqdw/AADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAABBB3BuTP9wbkz/Iqdw/AADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAACQQQAAwEAAABBBSZLUQZIkSUBu25ZAAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAEBBsKoqv7CqKr+qqgpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAACQQQAAwEAAAHBBovbaQfwYOEBwfoRBAACQQQAAwEAAAHBBovbaQfwYOEBwfoRBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAACQQQAAwEAAAHBBovbaQfwYOEBwfoRBAACQQQAAwEAAAHBBovbaQfwYOEBwfoRBAACQQQAAwEAAAEBBovbaQfwYOEAgAydBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAACQQQAAwEAAAHBBovbaQfwYOEBwfoRBAACQQQAAwEAAAHBBovbaQfwYOEBwfoRBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAHBBsKoqv7CqKr+rqpJBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpBAADAQAAAwEAAAJBB3BuTP9wbkz9kNcpB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\\\"}],\\\"materials\\\":[{\\\"doubleSided\\\":true,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[0,0,0,1],\\\"metallicFactor\\\":1,\\\"roughnessFactor\\\":1}},{\\\"doubleSided\\\":true,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[1,0.5,0.5,1],\\\"metallicFactor\\\":1,\\\"roughnessFactor\\\":1}},{\\\"doubleSided\\\":true,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[0,0,0,1],\\\"metallicFactor\\\":1,\\\"roughnessFactor\\\":1}},{\\\"doubleSided\\\":true,\\\"pbrMetallicRoughness\\\":{\\\"baseColorFactor\\\":[1,0,0,1],\\\"metallicFactor\\\":1,\\\"roughnessFactor\\\":1}}],\\\"meshes\\\":[{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":0},\\\"material\\\":0,\\\"mode\\\":6},{\\\"attributes\\\":{\\\"POSITION\\\":1},\\\"material\\\":0,\\\"mode\\\":6},{\\\"attributes\\\":{\\\"POSITION\\\":2},\\\"material\\\":0,\\\"mode\\\":6}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":3},\\\"material\\\":1,\\\"mode\\\":6},{\\\"attributes\\\":{\\\"POSITION\\\":4},\\\"material\\\":1,\\\"mode\\\":6},{\\\"attributes\\\":{\\\"POSITION\\\":5},\\\"material\\\":1,\\\"mode\\\":6}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":6},\\\"material\\\":2,\\\"mode\\\":1}]},{\\\"primitives\\\":[{\\\"attributes\\\":{\\\"POSITION\\\":7},\\\"material\\\":3,\\\"mode\\\":1}]}],\\\"nodes\\\":[{\\\"mesh\\\":0,\\\"translation\\\":[0,12,0]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,0]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,0]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,0]},{\\\"mesh\\\":0,\\\"translation\\\":[6,0,3]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,3]},{\\\"mesh\\\":0,\\\"translation\\\":[12,6,3]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,3]},{\\\"mesh\\\":0,\\\"translation\\\":[0,12,3]},{\\\"mesh\\\":0,\\\"translation\\\":[6,12,3]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,3]},{\\\"mesh\\\":0,\\\"translation\\\":[12,18,3]},{\\\"mesh\\\":0,\\\"translation\\\":[6,0,6]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,6]},{\\\"mesh\\\":0,\\\"translation\\\":[12,6,6]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,6]},{\\\"mesh\\\":0,\\\"translation\\\":[0,12,6]},{\\\"mesh\\\":0,\\\"translation\\\":[6,12,6]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,6]},{\\\"mesh\\\":0,\\\"translation\\\":[12,18,6]},{\\\"mesh\\\":0,\\\"translation\\\":[6,0,9]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,9]},{\\\"mesh\\\":0,\\\"translation\\\":[12,6,9]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,9]},{\\\"mesh\\\":0,\\\"translation\\\":[0,12,9]},{\\\"mesh\\\":0,\\\"translation\\\":[6,12,9]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,9]},{\\\"mesh\\\":0,\\\"translation\\\":[12,18,9]},{\\\"mesh\\\":0,\\\"translation\\\":[6,0,12]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,12]},{\\\"mesh\\\":0,\\\"translation\\\":[12,6,12]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,12]},{\\\"mesh\\\":0,\\\"translation\\\":[0,12,12]},{\\\"mesh\\\":0,\\\"translation\\\":[6,12,12]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,12]},{\\\"mesh\\\":0,\\\"translation\\\":[12,18,12]},{\\\"mesh\\\":0,\\\"translation\\\":[6,0,15]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,15]},{\\\"mesh\\\":0,\\\"translation\\\":[12,6,15]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,15]},{\\\"mesh\\\":0,\\\"translation\\\":[0,12,15]},{\\\"mesh\\\":0,\\\"translation\\\":[6,12,15]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,15]},{\\\"mesh\\\":0,\\\"translation\\\":[12,18,15]},{\\\"mesh\\\":0,\\\"translation\\\":[6,0,18]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,18]},{\\\"mesh\\\":0,\\\"translation\\\":[12,6,18]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,18]},{\\\"mesh\\\":0,\\\"translation\\\":[0,12,18]},{\\\"mesh\\\":0,\\\"translation\\\":[6,12,18]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,18]},{\\\"mesh\\\":0,\\\"translation\\\":[12,18,18]},{\\\"mesh\\\":0,\\\"translation\\\":[6,0,21]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,21]},{\\\"mesh\\\":0,\\\"translation\\\":[12,6,21]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,21]},{\\\"mesh\\\":0,\\\"translation\\\":[0,12,21]},{\\\"mesh\\\":0,\\\"translation\\\":[6,12,21]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,21]},{\\\"mesh\\\":0,\\\"translation\\\":[12,18,21]},{\\\"mesh\\\":0,\\\"translation\\\":[6,0,24]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,24]},{\\\"mesh\\\":0,\\\"translation\\\":[12,6,24]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,24]},{\\\"mesh\\\":0,\\\"translation\\\":[0,12,24]},{\\\"mesh\\\":0,\\\"translation\\\":[6,12,24]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,24]},{\\\"mesh\\\":0,\\\"translation\\\":[12,18,24]},{\\\"mesh\\\":0,\\\"translation\\\":[0,12,27]},{\\\"mesh\\\":1,\\\"translation\\\":[6,6,27]},{\\\"mesh\\\":0,\\\"translation\\\":[12,12,27]},{\\\"mesh\\\":1,\\\"translation\\\":[18,6,27]},{\\\"mesh\\\":2,\\\"translation\\\":[0,0,0]},{\\\"mesh\\\":3,\\\"translation\\\":[0,0,0]}],\\\"scene\\\":0,\\\"scenes\\\":[{\\\"nodes\\\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73]}]}\"\n            ]\n          },\n          \"execution_count\": 34,\n          \"metadata\": {},\n          \"output_type\": \"execute_result\"\n        }\n      ],\n      \"source\": [\n        \"surface_code_circuit.diagram(\\\"matchgraph-3d\\\")\\n\",\n        \"\\n\",\n        \"# Note: if you are viewing this notebook on GitHub, the 3d model viewer is likely blocked.\\n\",\n        \"# To view the 3d model, run this notebook locally or upload it to https://colab.google.com/\\n\",\n        \"# GLTF files can be viewed directly in online viewers such as https://gltf-viewer.donmccurdy.com/\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"_aw3w686hJCa\"\n      },\n      \"source\": [\n        \"Okay, enough looking at the circuits, time to collect.\\n\",\n        \"\\n\",\n        \"Collecting data using [`sinter.collect`](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md#sinter.collect) will take a bit longer this time.\\n\",\n        \"You can specify `print_progress=True` to get progress updates while the collection runs.\\n\",\n        \"Another useful argument (not used here) is `save_resume_filepath`, which allows you to cancel and restart collection without losing the work that was done.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"p4hgivJmeG0G\",\n        \"scrolled\": true\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"import os\\n\",\n        \"\\n\",\n        \"surface_code_tasks = [\\n\",\n        \"    sinter.Task(\\n\",\n        \"        circuit = stim.Circuit.generated(\\n\",\n        \"            \\\"surface_code:rotated_memory_z\\\",\\n\",\n        \"            rounds=d * 3,\\n\",\n        \"            distance=d,\\n\",\n        \"            after_clifford_depolarization=noise,\\n\",\n        \"            after_reset_flip_probability=noise,\\n\",\n        \"            before_measure_flip_probability=noise,\\n\",\n        \"            before_round_data_depolarization=noise,\\n\",\n        \"        ),\\n\",\n        \"        json_metadata={'d': d, 'r': d * 3, 'p': noise},\\n\",\n        \"    )\\n\",\n        \"    for d in [3, 5, 7]\\n\",\n        \"    for noise in [0.008, 0.009, 0.01, 0.011, 0.012]\\n\",\n        \"]\\n\",\n        \"\\n\",\n        \"collected_surface_code_stats: List[sinter.TaskStats] = sinter.collect(\\n\",\n        \"    num_workers=os.cpu_count(),\\n\",\n        \"    tasks=surface_code_tasks,\\n\",\n        \"    decoders=['pymatching'],\\n\",\n        \"    max_shots=1_000_000,\\n\",\n        \"    max_errors=5_000,\\n\",\n        \"    print_progress=True,\\n\",\n        \")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"w3JgGXrSe5r-\"\n      },\n      \"source\": [\n        \"You can now plot the collected data.\\n\",\n        \"Try using the `failure_units_per_shot_func` argument to plot per round error rates instead of per shot error rates, by retrieving the `'r'` entry (short for rounds) that you put in the metadata:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\",\n          \"height\": 484\n        },\n        \"id\": \"kJSbrfBDe8tQ\",\n        \"outputId\": \"abc40cb7-b334-4458-f69e-5016890c5635\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAAtMAAAIkCAYAAADcY6eQAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAABJ0AAASdAHeZh94AAEAAElEQVR4nOzdd5iU1dn48e/0ujPbgaUqVaRJFURAUTSoiIoVC2mWFGMSX33VGNGYqNFoLDGv+WkIGmtsscQCBlEQKSKISIelLmyfmZ3+PM/5/TG7yw47u2yjKPfnuvbSecp5zhRm7jlzn/uYlFIKIYQQQgghRKuZj3QHhBBCCCGE+LaSYFoIIYQQQog2kmBaCCGEEEKINpJgWgghhBBCiDaSYFoIIYQQQog2kmBaCCGEEEKINpJgWgghhBBCiDaSYFoIIYQQQog2kmBaCCGEEEKINpJgWgghhBBCiDaSYFoIIYQQQog2kmBafCskk0nuuusu+vbti8PhwGQy8eabbx7pbn3rzJ49G5PJxMcff3ykuyKEaKXi4mJMJhOzZs060l1psW/ze06vXr3o1avXke5GmkmTJmEymY50N9rk29z3g5FgWjRL13X+3//7f0ycOJHc3FxsNhuFhYUMGTKEH/3oR7z11luHpR9/+tOfuOeeeygqKuLmm2/mrrvuYsCAAYfl2h1t586d/O///i8jRowgJyen/jE944wzePTRRwkEAke6i21W92F/sL/i4uIj3dU2mTVrVqP74na7GThwIL/+9a8pKyvrkOuYTCYmTZrUIW0dKw58XiwWC7m5uUyaNIl//OMfKKWOdBfFEVZRUcHvfvc7xo0bR35+Pjabjby8PE499VT+8Ic/sG/fviPdxTb5+OOPMZlMzJ49u9Xn9urVC5PJRFZWVpP3vy4I3rx5czt7+t1lPdIdEEcvXdc599xzef/998nOzuacc86hW7duJBIJ1q5dywsvvMD69euZNm3aIe/LO++8g9frZd68edjt9kN+vUPl6aef5mc/+xnxeJyhQ4dy+eWXk5OTQ0VFBYsWLeKmm27id7/7HeXl5Ue6q+3i9/u56aabmtyfnZ192PpyKJx//vkMGzYMgH379vGf//yHhx9+mNdee40vvviCvLy8I9vBY9hdd90FpH7N2rx5M2+88QYLFy5kxYoVPPHEE0e4d+JIeeedd7jyyisJBAL06dOHCy64gMLCQgKBAEuXLuU3v/kNf/jDH9i8eTOdO3cG4KOPPjrCvW7s2WefJRKJdHi7NTU13HXXXfzf//1fh7dd51D1/WggwbRo0osvvsj777/P0KFDWbhwIX6/P21/JBJh6dKlh6Uve/bsIS8v71sdSD///PP8+Mc/Jicnh9dee41zzjmn0TGLFy/mpz/96RHoXcfKzs5u0yjJt8X06dPTfmqPxWKcfPLJrF69mieeeKI+oBOH34Gvu8WLFzNhwgSefPJJfv3rX3PccccdmY6JI2bhwoVccMEFWK1W5syZwzXXXNMo3WDNmjX84he/IBaL1W/r3bv34e7qQfXo0eOQtNunTx+efvppfvGLX3DCCScckmscqr4fDSTNQzTps88+A1I/bR8YSAO43W5OO+20tG3N5cc1le9X99P51q1befzxxxkyZAgul4tJkybV79u2bRvbt2+v/wm3YR7bP/7xDy666CKOP/54XC4XPp+PU045hX/+859N3rfKykruuOMOBg0ahNvtxu/3M3ToUP73f/+XcDjc6NjbbruNE044AZfLhd/vZ/LkyXz44YcHeQT3C4VC3HjjjQC89NJLGQNpgFNOOSXjF5SPPvqIs88+m9zcXBwOB/369eN///d/m0wJ+eKLLzj77LPJysrC5/NxxhlnsGTJkmb7uH79embNmkX37t2x2+106tSJK664gg0bNrT4frZFc89/S/YDbNq0iauvvpquXbtit9spKiri6quvZtOmTY2u1/A1+sILLzBmzBi8Xm+7ciOdTiczZ84EYPny5Wn7AoEADz74IKeffjrdunXDbrdTUFDAtGnTGj0n//jHP+o/5BcuXJiWtnBgkLh06VJmzJhB586dsdvtdO/eneuuu449e/Y06t/WrVu59tpr6dOnDy6Xi9zcXAYPHsz1119PRUVFi+5jXerJnj17uOqqqygsLMTlcjFixAheeOGFJs/74IMPmDp1Kvn5+TgcDnr37s3//M//UF1d3ejYuhzVYDDIr371K3r16oXNZmvXF7NTTjmFAQMGoJTiiy++aLT/lVdeYcKECfj9flwuF4MHD+a+++4jHo83+RhkUvc6bZjC1PA9r7i4mMsuu4z8/HycTicjR47knXfeydhWKBTiV7/6Fd26dcPpdDJgwAAefvhhDMNo1X2vez394x//yLg/0/1p+O/j1VdfZfTo0bjdbnJzc7nsssvYvXt3xrYO9XtOS94HMjEMg+uuuw5N03j00Ufr2znQ4MGDmT9/Pl27dq3flilnuuFj+v777zNp0iT8fn9am7qu83//93+ccsop9a+rPn368KMf/SjtPSnTa6ZOU6kbB+Ydz5o1q/5z+O677057z2hNnvp9992HruvccsstLT4HWvfZlClnWinF3LlzGTduHAUFBTidTrp3785ZZ53Fyy+/3KiNXbt28bOf/Yzjjz8eh8NBXl4e06ZNa/S+e7jJyLRoUt1P1Rs3bjws1/vFL37Bp59+yjnnnMPUqVOxWCyMGjWKXr168ec//xmgPnWgYZrADTfcwIknnsiECRPo0qULFRUV/Oc//+Gqq65iw4YN/O53v0u7zrZt2zjttNPYvn07I0aM4IYbbsAwDDZu3MgjjzzC9ddfj8fjAWD79u1MmjSJ4uJiTj31VM4++2zC4TDvvPMOZ599Nk899RQ//vGPD3rfXn31VSorKzn55JOZMmVKs8c6HI6020899RQ33HADHo+Hiy++mMLCQj7++GMeeOAB3n77bRYvXpz2eHz22WecccYZJBIJLrzwQvr06cOqVauYNGkSp59+esZrvv/++1x44YUkk0nOO+88+vTpw65du3j99dd59913WbBgAcOHDz/o/WyPTM9/S/YvX76cM844g1AoxLRp0xg4cCDr16/nn//8J//+97+ZP38+o0aNanS9P/3pT8ybN4/zzjuP0047rcNy1W02W9rtdevWcccddzBhwgTOOecccnJy2LFjB2+99Rbvvfceb7/9NmeffTYAw4YN46677uLuu++mZ8+eaV88GwYNf//737n22mtxOBxMmzaN7t27s2nTJp5++mnefvttPv/88/pRoJKSEkaNGkUwGGTq1KlcdNFFxGIxtm3bxnPPPcfPfvazFqelVFVVMW7cOLKzs/n+979PdXU1r7zyCjNnzmT37t38z//8T9rxd999N7NnzyY3N5dzzz2XwsJCvvrqKx566CH+85//sGTJEnw+X9o5iUSC008/ncrKSqZMmYLP5+uw0eQDn5vbb7+d++67j/z8fK644gq8Xi/vvfcet99+Ox988AEffvhhh/watn37dkaPHs3xxx/PVVddRWVlJS+//DLnn38+8+fPTxuUiMfjTJ48meXLlzN06FBmzpxJdXU1v/vd71i4cGG7+9JSTz75JG+99RbTpk1j4sSJLF26lJdffpnVq1ezatWqtPepw/mec7D3iQMtXLiQDRs20LVrV374wx82e6zZbMZsbtkY46uvvsr777/P9773Pa6//nq2b98OpF6/5557LvPmzaN79+5cccUV+Hw+iouLeeONNxg/fjx9+/Zt0TVaYvr06QDMnTuXiRMnpr1PtGaAYPr06UyYMIF33nmHBQsWNBooy6S1n02Z3HHHHdx3330cd9xxXHLJJfj9fkpKSli+fDn/+te/uPTSS+uPXblyJVOmTKGyspKzzjqLCy+8kPLyct58803Gjx/PG2+8wdSpU1t8nzuUEqIJK1euVDabTZlMJnXllVeq1157TRUXFzd7zl133aUAtWDBgkb7tm3bpgB1zTXXpG2/5pprFKCKiorU1q1bM7bbs2dP1bNnz4z7Nm/e3GhbPB5Xp59+urJarWrXrl1p+8aOHasA9Yc//KHReWVlZSoajdbfnjhxojKZTOrFF19MO66qqkoNHTpUOZ1OtXfv3oz9augHP/iBAtQdd9xx0GMbKi4uVna7XWVlZal169al7bvhhhsUoH784x/XbzMMQ/Xv318B6s0330w7/s9//rMCGj0/lZWVKjs7W+Xl5am1a9emnbNmzRrl8XjUSSed1KL+1j3Hfr9f3XXXXRn//vrXv6adc7Dnv7n9hmGoAQMGKED985//TNv30ksvKUD1799f6bpev73uNep2u9XKlStbdL8O7MucOXPStkciETV48GAFqIceeihtX3V1tSorK2vU1s6dO1WXLl3UgAEDGu0D1MSJEzP2YcOGDcpms6nevXs3em3Pnz9fmc1mNX369Pptjz32mALUn//850Zt1dTUqEgk0tTdbdQnQF188cVpj+fWrVtVTk6OstlsasuWLfXb//vf/ypAjR07VlVVVaW1NWfOHAWom266KW17z549FaAmT56sampqWtSvA/t3oIULFyqz2azsdrvas2dP/fbPPvtMAap79+6qpKSkfnsymVTnnnuuAtTvf//7Rtdo6nmpe21s27atflvdvwdAzZ49O+34999/XwHqe9/7Xtr23//+9wpQF154YcbHOdN7aFPqHucDX6/N3Z+6fx9ZWVnqq6++Stt3+eWXK0C9/PLL9dsO13tOSz4nMrnnnnsUoGbOnNnic+pk+type0xNJpN67733Gp1z2223KUCdd955KhaLpe2LxWKqtLS0/nam10ydBQsWKEDdddddadsnTpzY6HXe1LEtUfdvLplMqmXLlimTyaRGjBihDMNodM1NmzbVb2vtZ1NTfc/NzVVdu3ZV4XC4Ud8avm8mk0nVu3dv5XA41Mcff5x23O7du1VRUZHq3Llzo8f8cJFgWjTr5ZdfVp07d65/QwRUbm6umj59unrrrbcaHd+eYDrTh32d5oLpprz22msKUHPnzq3ftmLFCgWoYcOGpX1QZbJq1SoFqBkzZmTc/+abbypA/eUvfzloX773ve8poFEgeTD33nuvAtRtt93WaF9lZaXKyspSTqez/g1k0aJFClATJkxodLymaap3796Nnp+6D7wnnngiYx9uuukmBTT60MukYfDQ1N/QoUPTzjnY89/c/rr7O3bs2Iznjh8/XgFq4cKF9dvqXqMHBnItUdeX888/v/7LwQ033KC6d+9e/7hn+lBoys9//nMFqO3bt6dtby5oq3s+3nnnnYz7p0+friwWiwoGg0qp/cH0U0891eJ+ZQIoi8WSMZCpe0wbBozTp09XgPr6668ztjds2DBVUFCQtq3ug33VqlVt6l9dQHHXXXep22+/XV1yySX1AwKPPfZY2vE/+tGPmnxcNmzYoMxmszruuOMaXaMtwXTPnj2VpmmNzunRo4fKy8tL29anTx9lNpszDhLUPc6HI5jO9MW/7gvSr3/96/pth+s9pyWfE5nUBXa33nprq85TqvlguuEX1jqapim/369cLpfavXv3Qds/2oJppZS67LLLFKCee+65RtdsGEy39rOpqb7n5uaqXr16HTQIrvu8vfnmmzPur3tNvfvuuwe/04eApHmIZl1yySVccMEFLFiwgEWLFvHll1+yaNEi3nzzTd58802uvvrqtDzP9hg9enSbztuxYwcPPPAAH330ETt27CAajabtb5jj9/nnnwNw1llnHfTnvLp8v0AgkDFns64M2rp169rU75ZYuXIlQMafSnNycjjppJP45JNPWL9+PUOHDq0/fuLEiY2Ot1gsjB8/ni1btqRtr7ufq1evzng/69J81q1bx8CBA1vU7549e7a6/N3Bnv9M+5t7fOq2171uJ0yY0KrrNeff//43//73v9O2nXnmmbz77ruNUgkgNQnu0UcfZcmSJZSWlpJIJNL27969u8WTc+qer4ULF2bMEywtLUXXdTZu3MiIESOYNm0at99+Oz/96U/54IMPOOusszjllFMYOHBgq//d9ujRI2PKxaRJk7j77rv58ssv0/pps9n417/+xb/+9a9G5yQSCcrKyqioqEhLM3E6nQwZMqRV/Wro7rvvTrttMpl45pln+P73v5+2vbnXTr9+/ejWrRvbtm0jEAhknDPSGsOGDcuYjtC9e/e0vOJQKMTmzZvp3r17xslvdY/z4TBy5MhG27p37w6k0n3qHO73nPb8u+1Imfqxfv16AoEAY8aMoaio6Aj0qv3uu+8+3njjDe644w5mzJiB0+nMeFxrP5uaMnPmTB5//HEGDhzIJZdcwsSJExk7dmyjf3N1r5nt27dnfM3U5aKvW7fuiKR6SDAtDspmszFlypT6XF9d13nttdf4wQ9+wLPPPssFF1xQn7fVHnXliFpj69atjB49mqqqKk499VSmTJmC3+/HYrFQXFzM3Llz0yYS1U16ajjJpCl1E7PmzZvHvHnzmjyupqbmoG116dIFoMnJO02py+OtO7+pduvuV93xnTp1ynh8pse47n7+v//3/5rtS0vuZ3sc7PnPtL+1j09rrtecOXPmMGvWLHRdZ+vWrdx55528/PLL3HDDDTz99NNpx77xxhv1H0pnnnkmvXv3xuPxYDab+fjjj1m4cGHGyW5NqXu+HnzwwWaPq3u+evbsybJly5g9ezbvv/8+r7/+OpAKjG6++eb6ibEtcbDXVcO884qKCjRNO2jwV1NTkxZMFxYWtuvLuaqtJx0Oh1myZAk//OEPuf766+nZs2faB39LXjs7duygurq63cF0U3mjVqs1bVJhW/79HiqZ+my1pkIGXdfrtx3u95zWPgZtfe89mEz9aM3ny9GqV69e/PznP+ehhx7i0Ucf5dZbb814XHveext65JFHOP7445kzZw73338/999/P1arlalTp/KnP/2JPn36APtfM5m+mDd0qD+nmiLVPESrWSwWLrnkEn75y18C8N///rd+X91or6Zpjc472D+qtnyAPvzww1RUVPDMM8/w8ccf89hjj/G73/2O2bNnc9ZZZzU6vu4DoiVvrHUfoI8++igqlRKV8W/OnDkHbWv8+PFA6+uW1vVh7969GfeXlJSkHVf336aK72dqp+6c1atXN3s/r7nmmlb1vbUO9vxn2t/ax6c112sJi8VC375966uCPPPMM40WMrrzzjux2+2sWLGCN998s34BotmzZ9O/f/9WX7PuvgQCgWafr4YjhSeccAIvv/wyFRUVrFixgvvvvx/DMPjFL37BM8880+JrH+x11fBx9vv95OTkNNtHpRQ9e/ZMa6ujVkjzeDycccYZvP322+i6zjXXXJNW47Ytrx2TyZTxvQ0O/v7WEm3599uc9rwft9Thfs9p7euj7r33448/TvsS0F6Z+tGazxc4PM9PW9xxxx3k5uZy3333NbnmQXveexuyWCzcdNNNrF69mn379vHaa69xwQUX8NZbb3H22WfXDzTUtfPvf/+72dfMkSpLKsG0aLOsrCxg/0gQpH7egdQqfwdasWJFh/ehbkWmiy66qNG+TDPfTz75ZCBVrutgZabqjv3000/b201mzJhBbm4uS5YsYf78+c0e23CU8qSTTgLIWOKourqaVatW4XQ66+uC1s1+z3TfdV1n0aJFjbZ35P083Jp7fAAWLFgAcMgrkZjNZh599FEAbr311rQP7c2bNzNw4MBGtVsNw8j4fNS119QHf3ueL6vVyogRI7j11lt58cUXAXjzzTdbfP6OHTuaLOMF+5+Pun5WVVWxdu3aVvezIw0ZMoQf//jH7Nq1i0ceeaR+e3Ovnc2bN7Nr1y6OO+64tBHanJycjO9tuq6zatWqdvc1KyuLPn36sHv37kapEU31tTmH4/34aH/PmThxIv3792fXrl0HHfgwDINkMtnmaw0YMIDs7Gy++uqrjCUqD9RRz09dClFHfVnIzs7mzjvvJBAINPnLUms/m1qisLCQCy+8kFdeeYXTTz+dLVu28PXXXwNH/+eUBNOiSS+++CLz5s3LGHTu3bu3/ie6hrmodXlkc+bMSfu2vXPnTu65554O72Nd6Z8D/0F/8MEHjX5uBxgxYgTjxo1j1apVPPDAA432V1RU1BftHzlyJKeeeiqvv/46f//73zNef82aNZSWlh60n1lZWTz22GMAXHrppXzwwQcZj/v8888ZO3Zs/e0rr7wSm83G448/3mgp1zvvvJNgMMiVV15ZX6Zq3Lhx9O/fn08++aRRTu8TTzyR8QP6+9//PtnZ2dx9990sW7as0X7DMFr9IX64nHLKKfTv359Fixbx6quvpu179dVX+fTTT+nXr1/96NShNGbMGM4991zWr1/Ps88+W7+9V69ebNq0Ke3DVSnF7Nmz+eabbzK2lZeXl/EDFuBnP/sZNpuNX/7ylxnLViYSibQPnC+++CJj2b+6kUS3292yO0jqw/rWW29Ne0/Ytm0bjz32GFarlSuvvLJ+e90vVz/+8Y8zBhbhcLh+DsOh9pvf/AaHw8FDDz1Un+/7gx/8AIB77703bRl4Xde5+eabMQyjUSm10aNHs2PHjkY15u+999760mjt9f3vfx/DMJp8nFtj5MiRmM1mXnjhhbRR+crKylbXE27K0f6eYzabeeqpp7Bardx4443885//zLi0/DfffMOUKVPalQ5isVj4yU9+QjQa5frrr2+UvlU3T6BO3eflgekua9asqf9y3hJ1aVI7duxoa9cb+clPfkLv3r156qmnMn6Bbu1nUybxeJzFixc32p5MJqmsrAT2vz+df/759O7dm7/85S/85z//ydjekiVLjtgKi5IzLZq0dOlSHn30UTp37sz48ePrJx5t27aNd999l2g0yvnnn8+MGTPqzxkzZgwTJkzgk08+YfTo0Zx++uns27ePt99+m7POOqvJAKGtfvKTnzBnzhwuvvhiZsyYQVFREV9//TXvv/8+l1xyScai7//85z+ZNGkSt99+O6+99hqTJk1CKcWmTZv48MMPWb9+fX2Q/sILL3D66afzwx/+kMcee4wxY8aQnZ3Nrl27+Oqrr/j6669ZsmQJhYWFB+3rzJkziUaj/OxnP+Pss89m2LBhjBs3rn458SVLlrB69Wry8/Prz6mrsf3Tn/6U4cOHc8kll1BQUMDChQtZsmQJAwYMSPtSUDfZ6swzz+Siiy5Kq/laV1z//fffT+tXXl4er776KhdccAEnn3wykydP5sQTT8RkMrFz506WLFmS9iWjJaqrq5tdaGPWrFntWiSljslkYu7cuZx55plceumlnH/++QwYMIANGzbw5ptvkpWVxbPPPtvi2rHtdc899/Duu+9y9913M3PmTOx2O7/85S+5/vrrOemkk7jooouw2WwsXryYb775hvPOO4+33367UTuTJ0/mpZde4rzzzmP48OHYbDYmTJjAhAkTGDBgAH//+9/5wQ9+wIknnsjZZ59Nv379SCaT7Nixg08//ZSCggLWr18PwHPPPcdTTz3F+PHj6d27Nzk5OWzZsoW3334bh8PR7LLvBxoyZAhLly5lxIgRTJkypb7OdHV1NX/84x/TJs1NnjyZ+++/n9tuu42+ffsydepUjjvuOGpqati+fTsLFy5k/PjxjV6Ph0LXrl25/vrrefTRR/njH//Ifffdx7hx47jlllv44x//yKBBg5gxYwYej4f33nuPr7/+mvHjxzeqm33zzTfzwQcfcP7553PppZeSm5vLZ599xrZt25g0aVKHBIC//vWvefPNN3nttdcYPnw4Z511Vv3jPGHChEZpRM3p0qULM2fO5LnnnmPYsGGcc845BINB/vOf/zBhwoS0CaNtdbS85zRn4sSJvP7661x11VVcddVV/O53v2PSpEkUFBQQCARYsWIFS5cuxePx4HK52nWtu+66i6VLl/L222/Tr18/zj33XLKysti5cycffvghDz74YH39+PPPP5++ffvy4osvsmvXLsaMGcOOHTv497//zfnnn88rr7zSomv279+frl278tJLL2Gz2ejZsycmk4mrrrqqURpVS9ntdu677z4uueSSjF8UW/vZlEk0GmX8+PH06dOHESNG0LNnT2KxGPPmzWPdunVMmzatfmTbZrPx+uuvc9ZZZ3HOOecwbtw4hg0bhtvtZufOnSxfvpytW7dSUlLSqgGCDtPxBULEd8WOHTvUE088oaZPn6769eunsrKylM1mU507d1bf+9731HPPPZexvFxVVZX60Y9+pAoKCpTdblcnnniieuqppw5aGi9TeaA6zZXGW7x4sTrttNNUdna28nq96pRTTlFvvPFGs+WCysvL1S233KL69eunHA6H8vv9aujQoer2229vVNosGAyq3//+92r48OHK4/Eop9OpevXqpaZOnaqeeuqpVtfD3bFjh7rlllvUSSedpPx+v7JarSo/P19NmjRJPfLIIyoQCDQ654MPPlBnnnmmys7OVna7XfXu3Vv9z//8T6P6vXVWrFihzjrrLOX1epXX61WTJ09Wn3322UFLF/70pz9Vffr0UQ6HQ2VlZan+/furK6+8Ur3xxhstum8tKY134PUP9vy35PWxfv16deWVV6rOnTsrq9WqOnfurGbOnKnWr1/f6NjmHoODaarOdEMXXnihAtJKsc2ZM0cNHTpUud1ulZeXp6ZPn66++uqrJvuyb98+dfnll6vCwkJlNpszvo6/+uordc0116gePXoou92ucnJy1IknnqiuvfZa9dFHH9Uf9/nnn6vrr79eDRkyROXk5Cin06l69+6tZs2apdasWdPi+05tGbXdu3ermTNnqoKC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\",\n            \"text/plain\": [\n              \"<Figure size 768x576 with 1 Axes>\"\n            ]\n          },\n          \"metadata\": {},\n          \"output_type\": \"display_data\"\n        }\n      ],\n      \"source\": [\n        \"fig, ax = plt.subplots(1, 1)\\n\",\n        \"sinter.plot_error_rate(\\n\",\n        \"    ax=ax,\\n\",\n        \"    stats=collected_surface_code_stats,\\n\",\n        \"    x_func=lambda stat: stat.json_metadata['p'],\\n\",\n        \"    group_func=lambda stat: stat.json_metadata['d'],\\n\",\n        \"    failure_units_per_shot_func=lambda stat: stat.json_metadata['r'],\\n\",\n        \")\\n\",\n        \"ax.set_ylim(5e-3, 5e-2)\\n\",\n        \"ax.set_xlim(0.008, 0.012)\\n\",\n        \"ax.loglog()\\n\",\n        \"ax.set_title(\\\"Surface Code Error Rates per Round under Circuit Noise\\\")\\n\",\n        \"ax.set_xlabel(\\\"Phyical Error Rate\\\")\\n\",\n        \"ax.set_ylabel(\\\"Logical Error Rate per Round\\\")\\n\",\n        \"ax.grid(which='major')\\n\",\n        \"ax.grid(which='minor')\\n\",\n        \"ax.legend()\\n\",\n        \"fig.set_dpi(120)  # Show it bigger\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"6bPcsxWhZebc\"\n      },\n      \"source\": [\n        \"You can see from the plot that the threshold of the surface code is roughly 1%.\\n\",\n        \"\\n\",\n        \"There is a problem here, though.\\n\",\n        \"The problem is that the threshold isn't the only metric you care about.\\n\",\n        \"The threshold tells you the absolute worse qubit quality that could possibly work, but it doesn't tell you how many of those qubits you would need to hit a target logical error rate.\\n\",\n        \"What you **really** want to estimate is the quality *and corresponding quantity* of qubits needed to do fault tolerant computation.\\n\",\n        \"\\n\",\n        \"Suppose, for the sake of example, that you have qubits with a physical error rate of 0.1% according to the noise model you are using.\\n\",\n        \"Collect logical error rates from a variety of code distances so you can predict the code distance needed to achieve a target logical error rate.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"OVjDeVXzkEO2\",\n        \"scrolled\": true\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"noise = 1e-3\\n\",\n        \"\\n\",\n        \"surface_code_tasks = [\\n\",\n        \"    sinter.Task(\\n\",\n        \"        circuit = stim.Circuit.generated(\\n\",\n        \"            \\\"surface_code:rotated_memory_z\\\",\\n\",\n        \"            rounds=d * 3,\\n\",\n        \"            distance=d,\\n\",\n        \"            after_clifford_depolarization=noise,\\n\",\n        \"            after_reset_flip_probability=noise,\\n\",\n        \"            before_measure_flip_probability=noise,\\n\",\n        \"            before_round_data_depolarization=noise,\\n\",\n        \"        ),\\n\",\n        \"        json_metadata={'d': d, 'r': d * 3, 'p': noise},\\n\",\n        \"    )\\n\",\n        \"    for d in [3, 5, 7, 9]\\n\",\n        \"]\\n\",\n        \"\\n\",\n        \"collected_surface_code_stats: List[sinter.TaskStats] = sinter.collect(\\n\",\n        \"    num_workers=os.cpu_count(),\\n\",\n        \"    tasks=surface_code_tasks,\\n\",\n        \"    decoders=['pymatching'],\\n\",\n        \"    max_shots=5_000_000,\\n\",\n        \"    max_errors=100,\\n\",\n        \"    print_progress=True,\\n\",\n        \")\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"41iMwGAQqYz2\"\n      },\n      \"source\": [\n        \"To a good first approximation, logical error rates decrease exponentially with code distance.\\n\",\n        \"Use [SciPy](https://scipy.org/)'s [linear regression facilities](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.linregress.html) to get a line fit of code distance versus log error rate.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"w7QmBLpTkzxr\",\n        \"outputId\": \"8db9ac92-e3ec-4043-cdc9-64cde485af8e\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"LinregressResult(slope=-1.1895861614770902, intercept=-4.615053480324744, rvalue=-0.998930299836957, pvalue=0.0010697001630429748, stderr=0.0389381734731575, intercept_stderr=0.24932596232733958)\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"import scipy.stats\\n\",\n        \"\\n\",\n        \"# Compute the line fit.\\n\",\n        \"xs = []\\n\",\n        \"ys = []\\n\",\n        \"log_ys = []\\n\",\n        \"for stats in collected_surface_code_stats:\\n\",\n        \"    d = stats.json_metadata['d']\\n\",\n        \"    if not stats.errors:\\n\",\n        \"        print(f\\\"Didn't see any errors for d={d}\\\")\\n\",\n        \"        continue\\n\",\n        \"    per_shot = stats.errors / stats.shots\\n\",\n        \"    per_round = sinter.shot_error_rate_to_piece_error_rate(per_shot, pieces=stats.json_metadata['r'])\\n\",\n        \"    xs.append(d)\\n\",\n        \"    ys.append(per_round)\\n\",\n        \"    log_ys.append(np.log(per_round))\\n\",\n        \"fit = scipy.stats.linregress(xs, log_ys)\\n\",\n        \"print(fit)\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"bt6fVetwq0os\"\n      },\n      \"source\": [\n        \"Plot the collected points and the line fit, to get a projection of the distance needed to achieve a per-round error rate below one in a trillion.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\",\n          \"height\": 482\n        },\n        \"id\": \"fWTvZ_Xmqv9M\",\n        \"outputId\": \"3ef3584c-1ad8-49ee-d68f-0ee15e4ea7a0\"\n      },\n      \"outputs\": [\n        {\n          \"data\": {\n            \"image/png\": \"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27FjRyxZsgSffvopBgwYAHNzc1hZWWHy5Mlo1qwZWrdujQMHDqBVq1bw8PDA69evceLECdSsWbPQbqD08fGBn58f1q1bhwsXLqBLly4wMDBAcHAwTp48iSNHjihv/PLx8cHTp08xd+5c7NixAx4eHqhQoQJevXqFgIAA3Lx5E7t37y6UeqNZ1apVC5s3b8bYsWNRt25ddO3aFTVq1EB6ejqeP3+Oy5cvw9bWFo8ePVK+Z9euXejQoQM++eQTrFy5Eu7u7rCyskJYWBju378PPz8/XL16VVlL9T//+Q8OHTqEP/74A02aNEGXLl0QGxurPJ6OHDmicfvlZ5sU1nEGAGZmZnB3d8fly5cxfPhw1KhRAzKZDL1790aDBg0wbNgwHD58GL///jvq1q2Lvn37QiKR4NChQwgODsbHH3+cpyTz9OnTmDlzJlq2bIkaNWrAzs4OYWFhOHz4MKRSKWbOnKns6+DggOHDh2PHjh1o1KgRevTogfj4eBw/fhxt27bN042C2WndujVcXV2xb98+pKeno1evXsp9lx+jRo3CnDlz8N1332WbaBfkHJkdb29vbNmyBYMGDcLAgQPh6OgIPz8//PXXXxg8eDD27t2b59hbtmwJExMTLF++HFFRUcoxuFOmTNHpk1VbtWqFL774Aj/99BPq1auHgQMHwtTUFCdOnICfnx88PDxUjpMPyczMDJs3b8agQYPQrl07DBo0CJUrV8bt27dx6tQp2NvbK+8dyTRmzBgsWbIEixYtwj///IM6dergyZMnOHHiBPr164c//vhD67hat26NKVOmYNWqVcptllknuVy5cmpjqF++fInGjRujfv36aNCgAZycnBAfH49jx47h33//xdSpU3P97i8xdFxdgz4wZFMnWZPcyqcJIURYWJj47LPPROXKlYW+vr4oX7686NOnj7hx44Za35xKBr1+/Vp8+eWXom7dusLY2FiYmpoKV1dXMWDAALFjxw6VskpCvCuXs2rVKtGsWTNhamoqTExMhKurq/j000/Vyt7s2LFDWYs26/rnp9xQpuxK8sTExIgpU6YIBwcHYWBgIGrWrCl+/vlncf36dQFAfP7559lux6xSU1PFggULRNWqVYWBgYFwdnYWs2fPFikpKXkuAbd3714xZMgQ4erqKkxNTYW5ubmoW7eumD17tkot6UxLly4VtWrVEgYGBmol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\",\n            \"text/plain\": [\n              \"<Figure size 768x576 with 1 Axes>\"\n            ]\n          },\n          \"metadata\": {},\n          \"output_type\": \"display_data\"\n        }\n      ],\n      \"source\": [\n        \"fig, ax = plt.subplots(1, 1)\\n\",\n        \"ax.scatter(xs, ys, label=f\\\"sampled logical error rate at p={noise}\\\")\\n\",\n        \"ax.plot([0, 25],\\n\",\n        \"        [np.exp(fit.intercept), np.exp(fit.intercept + fit.slope * 25)],\\n\",\n        \"        linestyle='--',\\n\",\n        \"        label='least squares line fit')\\n\",\n        \"ax.set_ylim(1e-12, 1e-0)\\n\",\n        \"ax.set_xlim(0, 25)\\n\",\n        \"ax.semilogy()\\n\",\n        \"ax.set_title(\\\"Projecting distance needed to survive a trillion rounds\\\")\\n\",\n        \"ax.set_xlabel(\\\"Code Distance\\\")\\n\",\n        \"ax.set_ylabel(\\\"Logical Error Rate per Round\\\")\\n\",\n        \"ax.grid(which='major')\\n\",\n        \"ax.grid(which='minor')\\n\",\n        \"ax.legend()\\n\",\n        \"fig.set_dpi(120)  # Show it bigger\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"F7fFfO-akgqF\"\n      },\n      \"source\": [\n        \"Based on this data, it looks like a distance 20 patch would be sufficient to survive a trillion rounds.\\n\",\n        \"That's a surface code with around 800 physical qubits.\\n\",\n        \"\\n\",\n        \"Beware that this line fit is being extrapolated quite far. It would be wise to sample a few more code distances. Also, keep in mind that the footprint you just estimated is for a **specific realization of the surface code circuit**, using a **specific choice of circuit-level noise**, and using **a specific kind of decoder**. Also, you only estimated the error of memory in one basis (Z); to be thorough you have to also check the X basis.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"lYPJMxqyEQvy\"\n      },\n      \"source\": [\n        \"<a class=\\\"anchor\\\" id=\\\"end-of-tutorial\\\"></a>\\n\",\n        \"# 11. Conclusion\\n\",\n        \"\\n\",\n        \"Congratulations for making it this far! Historically, estimating the threshold of a quantum error-correcting code under circuit noise would have taken weeks or months of work.\\n\",\n        \"By leveraging open-source tools, you just did it in a single sitting.\\n\",\n        \"Nicely done!\\n\",\n        \"\\n\",\n        \"<a class=\\\"anchor\\\" id=\\\"additional-resources\\\"></a>\\n\",\n        \"# 12. Additional resources\\n\",\n        \"\\n\",\n        \"## Getting help\\n\",\n        \"\\n\",\n        \"- You can ask questions about quantum circuits, Stim, error correction, and related topics on the [Quantum Computing Stack Exchange](https://quantumcomputing.stackexchange.com/).\\n\",\n        \"Use the tag `stim`.\\n\",\n        \"\\n\",\n        \"## Stim reference material\\n\",\n        \"\\n\",\n        \"- [Stim Python API Reference](https://github.com/quantumlib/Stim/blob/main/doc/python_api_reference_vDev.md)\\n\",\n        \"- [Stim Supported Gates Reference](https://github.com/quantumlib/Stim/blob/main/doc/gates.md)\\n\",\n        \"- [Stim Command Line Reference](https://github.com/quantumlib/Stim/blob/main/doc/usage_command_line.md)\\n\",\n        \"- [Stim Circuit File Format (.stim)](https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md)\\n\",\n        \"- [Stim Detector Error model Format (.dem)](https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md)\\n\",\n        \"- [Stim Results Format Reference](https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md)\\n\",\n        \"\\n\",\n        \"## Talks and videos\\n\",\n        \"\\n\",\n        \"- [\\\"Software and the Honeycomb Code\\\"](https://www.youtube.com/watch?v=O3NaTGmY0Rw) by Craig Gidney at the weekly Duke/Pratt quantum computing seminar\\n\",\n        \"- [\\\"Estimating overheads for quantum fault-tolerance in the honeycomb code\\\"](https://www.youtube.com/watch?v=ND9OoqJ0NMw) by Mike Newman at the [APS March Meeting 2022](https://web.archive.org/web/20240716155117/https://meetings.aps.org/Meeting/MAR22/Content/4178)\\n\",\n        \"- [\\\"(Demo/Tutorial) Estimating the threshold of a new quantum code using Stim and PyMatching\\\"](https://www.youtube.com/watch?v=E9yj0o1LGII) by Craig Gidney\\n\",\n        \"- [\\\"Relaxing Hardware Requirements for Surface Code Circuits using Time Dynamics\\\"](https://www.youtube.com/watch?v=FuP1exdZJkg) by Matt McEwen at [QEC 2023](https://web.archive.org/web/20241013042627/https://quantum.sydney.edu.au/qec23)\\n\",\n        \"\\n\",\n        \"## Papers with Stim circuits\\n\",\n        \"\\n\",\n        \"- A list of papers known to have included downloadable Stim circuits is available from the [doc/circuit_data_references.md](circuit_data_references.md) file in the [Stim repository on GitHub](https://github.com/quantumlib/stim).\\n\",\n        \"\\n\",\n        \"## Learning Python\\n\",\n        \"\\n\",\n        \"- [Google's Python class](https://developers.google.com/edu/python)\\n\",\n        \"- [Google's Crash Course on Python](https://www.coursera.org/learn/python-crash-course) at Coursera\\n\",\n        \"- University of Michigan's [Python for Everybody](https://www.coursera.org/specializations/python) at Coursera\\n\",\n        \"- Python.org's [Python Tutorial](https://docs.python.org/3/tutorial/)\\n\",\n        \"\\n\",\n        \"## Learning quantum computing\\n\",\n        \"\\n\",\n        \"\\n\",\n        \"- [Quantum computing for the very curious](https://quantum.country/qcvc) by Andy Matuschak and Michael Nielsen\\n\",\n        \"- [Building Google's quantum computer](https://www.youtube.com/watch?v=dUdqfqS9Dvg) by Marissa Giustina (2018)\\n\",\n        \"- MIT's [Quantum Information Science I](https://openlearninglibrary.mit.edu/courses/course-v1:MITx+8.370.1x+1T2018/about)\\n\",\n        \"- John Preskill's [Ph/CS 219A Quantum Computation](https://www.youtube.com/playlist?list=PL0ojjrEqIyPy-1RRD8cTD_lF1hflo89Iu) on YouTube\\n\",\n        \"- Quantum AI's YouTube content:\\n\",\n        \"  - [Quantum Programming with Cirq](https://www.youtube.com/playlist?list=PLpO2pyKisOjLVt_tDJ2K6ZTapZtHXPLB4)\\n\",\n        \"  - [QuantumCasts](https://www.youtube.com/playlist?list=PLQY2H8rRoyvwcpm6Nf-fL4sIYQUXtq3HR)\\n\",\n        \"- [Quantum computing for the determined](https://michaelnielsen.org/blog/quantum-computing-for-the-determined/) by Michael Nielsen\\n\",\n        \"- Michael Nielsen and Isaac Chuang's [Quantum Computation And Quantum Information](https://archive.org/embed/QuantumComputationAndQuantumInformation10thAnniversaryEdition)\\n\",\n        \"\\n\",\n        \"\\n\",\n        \"## Learning quantum error correction\\n\",\n        \"\\n\",\n        \"- Quantum AI's [quantum computing journey](https://quantumai.google/learn/map)\\n\",\n        \"- Coursera course [Hands-on quantum error correction with Google Quantum AI](https://www.coursera.org/learn/quantum-error-correction) by Austin Fowler\"\n      ]\n    }\n  ],\n  \"metadata\": {\n    \"colab\": {\n      \"provenance\": []\n    },\n    \"kernelspec\": {\n      \"display_name\": \"Python 3 (ipykernel)\",\n      \"language\": \"python\",\n      \"name\": \"python3\"\n    },\n    \"language_info\": {\n      \"codemirror_mode\": {\n        \"name\": \"ipython\",\n        \"version\": 3\n      },\n      \"file_extension\": \".py\",\n      \"mimetype\": \"text/x-python\",\n      \"name\": \"python\",\n      \"nbconvert_exporter\": \"python\",\n      \"pygments_lexer\": \"ipython3\",\n      \"version\": \"3.11.0\"\n    }\n  },\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0\n}\n"
  },
  {
    "path": "doc/python_api_reference_vDev.md",
    "content": "# Stim (Development Version) API Reference\n\n*CAUTION*: this API reference is for the in-development version of stim.\nMethods and arguments mentioned here may not be accessible in stable versions, yet.\nAPI references for stable versions are kept on the [stim github wiki](https://github.com/quantumlib/Stim/wiki)\n\n## Index\n- [`stim.Circuit`](#stim.Circuit)\n    - [`stim.Circuit.__add__`](#stim.Circuit.__add__)\n    - [`stim.Circuit.__eq__`](#stim.Circuit.__eq__)\n    - [`stim.Circuit.__getitem__`](#stim.Circuit.__getitem__)\n    - [`stim.Circuit.__iadd__`](#stim.Circuit.__iadd__)\n    - [`stim.Circuit.__imul__`](#stim.Circuit.__imul__)\n    - [`stim.Circuit.__init__`](#stim.Circuit.__init__)\n    - [`stim.Circuit.__len__`](#stim.Circuit.__len__)\n    - [`stim.Circuit.__mul__`](#stim.Circuit.__mul__)\n    - [`stim.Circuit.__ne__`](#stim.Circuit.__ne__)\n    - [`stim.Circuit.__repr__`](#stim.Circuit.__repr__)\n    - [`stim.Circuit.__rmul__`](#stim.Circuit.__rmul__)\n    - [`stim.Circuit.__str__`](#stim.Circuit.__str__)\n    - [`stim.Circuit.append`](#stim.Circuit.append)\n    - [`stim.Circuit.append_from_stim_program_text`](#stim.Circuit.append_from_stim_program_text)\n    - [`stim.Circuit.approx_equals`](#stim.Circuit.approx_equals)\n    - [`stim.Circuit.clear`](#stim.Circuit.clear)\n    - [`stim.Circuit.compile_detector_sampler`](#stim.Circuit.compile_detector_sampler)\n    - [`stim.Circuit.compile_m2d_converter`](#stim.Circuit.compile_m2d_converter)\n    - [`stim.Circuit.compile_sampler`](#stim.Circuit.compile_sampler)\n    - [`stim.Circuit.copy`](#stim.Circuit.copy)\n    - [`stim.Circuit.count_determined_measurements`](#stim.Circuit.count_determined_measurements)\n    - [`stim.Circuit.decomposed`](#stim.Circuit.decomposed)\n    - [`stim.Circuit.detecting_regions`](#stim.Circuit.detecting_regions)\n    - [`stim.Circuit.detector_error_model`](#stim.Circuit.detector_error_model)\n    - [`stim.Circuit.diagram`](#stim.Circuit.diagram)\n    - [`stim.Circuit.explain_detector_error_model_errors`](#stim.Circuit.explain_detector_error_model_errors)\n    - [`stim.Circuit.flattened`](#stim.Circuit.flattened)\n    - [`stim.Circuit.flow_generators`](#stim.Circuit.flow_generators)\n    - [`stim.Circuit.from_file`](#stim.Circuit.from_file)\n    - [`stim.Circuit.generated`](#stim.Circuit.generated)\n    - [`stim.Circuit.get_detector_coordinates`](#stim.Circuit.get_detector_coordinates)\n    - [`stim.Circuit.get_final_qubit_coordinates`](#stim.Circuit.get_final_qubit_coordinates)\n    - [`stim.Circuit.has_all_flows`](#stim.Circuit.has_all_flows)\n    - [`stim.Circuit.has_flow`](#stim.Circuit.has_flow)\n    - [`stim.Circuit.insert`](#stim.Circuit.insert)\n    - [`stim.Circuit.inverse`](#stim.Circuit.inverse)\n    - [`stim.Circuit.likeliest_error_sat_problem`](#stim.Circuit.likeliest_error_sat_problem)\n    - [`stim.Circuit.missing_detectors`](#stim.Circuit.missing_detectors)\n    - [`stim.Circuit.num_detectors`](#stim.Circuit.num_detectors)\n    - [`stim.Circuit.num_measurements`](#stim.Circuit.num_measurements)\n    - [`stim.Circuit.num_observables`](#stim.Circuit.num_observables)\n    - [`stim.Circuit.num_qubits`](#stim.Circuit.num_qubits)\n    - [`stim.Circuit.num_sweep_bits`](#stim.Circuit.num_sweep_bits)\n    - [`stim.Circuit.num_ticks`](#stim.Circuit.num_ticks)\n    - [`stim.Circuit.pop`](#stim.Circuit.pop)\n    - [`stim.Circuit.reference_detector_and_observable_signs`](#stim.Circuit.reference_detector_and_observable_signs)\n    - [`stim.Circuit.reference_sample`](#stim.Circuit.reference_sample)\n    - [`stim.Circuit.search_for_undetectable_logical_errors`](#stim.Circuit.search_for_undetectable_logical_errors)\n    - [`stim.Circuit.shortest_error_sat_problem`](#stim.Circuit.shortest_error_sat_problem)\n    - [`stim.Circuit.shortest_graphlike_error`](#stim.Circuit.shortest_graphlike_error)\n    - [`stim.Circuit.solve_flow_measurements`](#stim.Circuit.solve_flow_measurements)\n    - [`stim.Circuit.time_reversed_for_flows`](#stim.Circuit.time_reversed_for_flows)\n    - [`stim.Circuit.to_crumble_url`](#stim.Circuit.to_crumble_url)\n    - [`stim.Circuit.to_file`](#stim.Circuit.to_file)\n    - [`stim.Circuit.to_qasm`](#stim.Circuit.to_qasm)\n    - [`stim.Circuit.to_quirk_url`](#stim.Circuit.to_quirk_url)\n    - [`stim.Circuit.to_tableau`](#stim.Circuit.to_tableau)\n    - [`stim.Circuit.with_inlined_feedback`](#stim.Circuit.with_inlined_feedback)\n    - [`stim.Circuit.without_noise`](#stim.Circuit.without_noise)\n    - [`stim.Circuit.without_tags`](#stim.Circuit.without_tags)\n- [`stim.CircuitErrorLocation`](#stim.CircuitErrorLocation)\n    - [`stim.CircuitErrorLocation.__init__`](#stim.CircuitErrorLocation.__init__)\n    - [`stim.CircuitErrorLocation.flipped_measurement`](#stim.CircuitErrorLocation.flipped_measurement)\n    - [`stim.CircuitErrorLocation.flipped_pauli_product`](#stim.CircuitErrorLocation.flipped_pauli_product)\n    - [`stim.CircuitErrorLocation.instruction_targets`](#stim.CircuitErrorLocation.instruction_targets)\n    - [`stim.CircuitErrorLocation.noise_tag`](#stim.CircuitErrorLocation.noise_tag)\n    - [`stim.CircuitErrorLocation.stack_frames`](#stim.CircuitErrorLocation.stack_frames)\n    - [`stim.CircuitErrorLocation.tick_offset`](#stim.CircuitErrorLocation.tick_offset)\n- [`stim.CircuitErrorLocationStackFrame`](#stim.CircuitErrorLocationStackFrame)\n    - [`stim.CircuitErrorLocationStackFrame.__init__`](#stim.CircuitErrorLocationStackFrame.__init__)\n    - [`stim.CircuitErrorLocationStackFrame.instruction_offset`](#stim.CircuitErrorLocationStackFrame.instruction_offset)\n    - [`stim.CircuitErrorLocationStackFrame.instruction_repetitions_arg`](#stim.CircuitErrorLocationStackFrame.instruction_repetitions_arg)\n    - [`stim.CircuitErrorLocationStackFrame.iteration_index`](#stim.CircuitErrorLocationStackFrame.iteration_index)\n- [`stim.CircuitInstruction`](#stim.CircuitInstruction)\n    - [`stim.CircuitInstruction.__eq__`](#stim.CircuitInstruction.__eq__)\n    - [`stim.CircuitInstruction.__init__`](#stim.CircuitInstruction.__init__)\n    - [`stim.CircuitInstruction.__ne__`](#stim.CircuitInstruction.__ne__)\n    - [`stim.CircuitInstruction.__repr__`](#stim.CircuitInstruction.__repr__)\n    - [`stim.CircuitInstruction.__str__`](#stim.CircuitInstruction.__str__)\n    - [`stim.CircuitInstruction.gate_args_copy`](#stim.CircuitInstruction.gate_args_copy)\n    - [`stim.CircuitInstruction.name`](#stim.CircuitInstruction.name)\n    - [`stim.CircuitInstruction.num_measurements`](#stim.CircuitInstruction.num_measurements)\n    - [`stim.CircuitInstruction.tag`](#stim.CircuitInstruction.tag)\n    - [`stim.CircuitInstruction.target_groups`](#stim.CircuitInstruction.target_groups)\n    - [`stim.CircuitInstruction.targets_copy`](#stim.CircuitInstruction.targets_copy)\n- [`stim.CircuitRepeatBlock`](#stim.CircuitRepeatBlock)\n    - [`stim.CircuitRepeatBlock.__eq__`](#stim.CircuitRepeatBlock.__eq__)\n    - [`stim.CircuitRepeatBlock.__init__`](#stim.CircuitRepeatBlock.__init__)\n    - [`stim.CircuitRepeatBlock.__ne__`](#stim.CircuitRepeatBlock.__ne__)\n    - [`stim.CircuitRepeatBlock.__repr__`](#stim.CircuitRepeatBlock.__repr__)\n    - [`stim.CircuitRepeatBlock.body_copy`](#stim.CircuitRepeatBlock.body_copy)\n    - [`stim.CircuitRepeatBlock.name`](#stim.CircuitRepeatBlock.name)\n    - [`stim.CircuitRepeatBlock.num_measurements`](#stim.CircuitRepeatBlock.num_measurements)\n    - [`stim.CircuitRepeatBlock.repeat_count`](#stim.CircuitRepeatBlock.repeat_count)\n    - [`stim.CircuitRepeatBlock.tag`](#stim.CircuitRepeatBlock.tag)\n- [`stim.CircuitTargetsInsideInstruction`](#stim.CircuitTargetsInsideInstruction)\n    - [`stim.CircuitTargetsInsideInstruction.__init__`](#stim.CircuitTargetsInsideInstruction.__init__)\n    - [`stim.CircuitTargetsInsideInstruction.args`](#stim.CircuitTargetsInsideInstruction.args)\n    - [`stim.CircuitTargetsInsideInstruction.gate`](#stim.CircuitTargetsInsideInstruction.gate)\n    - [`stim.CircuitTargetsInsideInstruction.tag`](#stim.CircuitTargetsInsideInstruction.tag)\n    - [`stim.CircuitTargetsInsideInstruction.target_range_end`](#stim.CircuitTargetsInsideInstruction.target_range_end)\n    - [`stim.CircuitTargetsInsideInstruction.target_range_start`](#stim.CircuitTargetsInsideInstruction.target_range_start)\n    - [`stim.CircuitTargetsInsideInstruction.targets_in_range`](#stim.CircuitTargetsInsideInstruction.targets_in_range)\n- [`stim.CliffordString`](#stim.CliffordString)\n    - [`stim.CliffordString.__add__`](#stim.CliffordString.__add__)\n    - [`stim.CliffordString.__eq__`](#stim.CliffordString.__eq__)\n    - [`stim.CliffordString.__getitem__`](#stim.CliffordString.__getitem__)\n    - [`stim.CliffordString.__iadd__`](#stim.CliffordString.__iadd__)\n    - [`stim.CliffordString.__imul__`](#stim.CliffordString.__imul__)\n    - [`stim.CliffordString.__init__`](#stim.CliffordString.__init__)\n    - [`stim.CliffordString.__ipow__`](#stim.CliffordString.__ipow__)\n    - [`stim.CliffordString.__len__`](#stim.CliffordString.__len__)\n    - [`stim.CliffordString.__mul__`](#stim.CliffordString.__mul__)\n    - [`stim.CliffordString.__ne__`](#stim.CliffordString.__ne__)\n    - [`stim.CliffordString.__pow__`](#stim.CliffordString.__pow__)\n    - [`stim.CliffordString.__repr__`](#stim.CliffordString.__repr__)\n    - [`stim.CliffordString.__rmul__`](#stim.CliffordString.__rmul__)\n    - [`stim.CliffordString.__setitem__`](#stim.CliffordString.__setitem__)\n    - [`stim.CliffordString.__str__`](#stim.CliffordString.__str__)\n    - [`stim.CliffordString.all_cliffords_string`](#stim.CliffordString.all_cliffords_string)\n    - [`stim.CliffordString.copy`](#stim.CliffordString.copy)\n    - [`stim.CliffordString.random`](#stim.CliffordString.random)\n    - [`stim.CliffordString.x_outputs`](#stim.CliffordString.x_outputs)\n    - [`stim.CliffordString.y_outputs`](#stim.CliffordString.y_outputs)\n    - [`stim.CliffordString.z_outputs`](#stim.CliffordString.z_outputs)\n- [`stim.CompiledDemSampler`](#stim.CompiledDemSampler)\n    - [`stim.CompiledDemSampler.sample`](#stim.CompiledDemSampler.sample)\n    - [`stim.CompiledDemSampler.sample_write`](#stim.CompiledDemSampler.sample_write)\n- [`stim.CompiledDetectorSampler`](#stim.CompiledDetectorSampler)\n    - [`stim.CompiledDetectorSampler.__init__`](#stim.CompiledDetectorSampler.__init__)\n    - [`stim.CompiledDetectorSampler.__repr__`](#stim.CompiledDetectorSampler.__repr__)\n    - [`stim.CompiledDetectorSampler.sample`](#stim.CompiledDetectorSampler.sample)\n    - [`stim.CompiledDetectorSampler.sample_write`](#stim.CompiledDetectorSampler.sample_write)\n- [`stim.CompiledMeasurementSampler`](#stim.CompiledMeasurementSampler)\n    - [`stim.CompiledMeasurementSampler.__init__`](#stim.CompiledMeasurementSampler.__init__)\n    - [`stim.CompiledMeasurementSampler.__repr__`](#stim.CompiledMeasurementSampler.__repr__)\n    - [`stim.CompiledMeasurementSampler.sample`](#stim.CompiledMeasurementSampler.sample)\n    - [`stim.CompiledMeasurementSampler.sample_write`](#stim.CompiledMeasurementSampler.sample_write)\n- [`stim.CompiledMeasurementsToDetectionEventsConverter`](#stim.CompiledMeasurementsToDetectionEventsConverter)\n    - [`stim.CompiledMeasurementsToDetectionEventsConverter.__init__`](#stim.CompiledMeasurementsToDetectionEventsConverter.__init__)\n    - [`stim.CompiledMeasurementsToDetectionEventsConverter.__repr__`](#stim.CompiledMeasurementsToDetectionEventsConverter.__repr__)\n    - [`stim.CompiledMeasurementsToDetectionEventsConverter.convert`](#stim.CompiledMeasurementsToDetectionEventsConverter.convert)\n    - [`stim.CompiledMeasurementsToDetectionEventsConverter.convert_file`](#stim.CompiledMeasurementsToDetectionEventsConverter.convert_file)\n- [`stim.DemInstruction`](#stim.DemInstruction)\n    - [`stim.DemInstruction.__eq__`](#stim.DemInstruction.__eq__)\n    - [`stim.DemInstruction.__init__`](#stim.DemInstruction.__init__)\n    - [`stim.DemInstruction.__ne__`](#stim.DemInstruction.__ne__)\n    - [`stim.DemInstruction.__repr__`](#stim.DemInstruction.__repr__)\n    - [`stim.DemInstruction.__str__`](#stim.DemInstruction.__str__)\n    - [`stim.DemInstruction.args_copy`](#stim.DemInstruction.args_copy)\n    - [`stim.DemInstruction.tag`](#stim.DemInstruction.tag)\n    - [`stim.DemInstruction.target_groups`](#stim.DemInstruction.target_groups)\n    - [`stim.DemInstruction.targets_copy`](#stim.DemInstruction.targets_copy)\n    - [`stim.DemInstruction.type`](#stim.DemInstruction.type)\n- [`stim.DemRepeatBlock`](#stim.DemRepeatBlock)\n    - [`stim.DemRepeatBlock.__eq__`](#stim.DemRepeatBlock.__eq__)\n    - [`stim.DemRepeatBlock.__init__`](#stim.DemRepeatBlock.__init__)\n    - [`stim.DemRepeatBlock.__ne__`](#stim.DemRepeatBlock.__ne__)\n    - [`stim.DemRepeatBlock.__repr__`](#stim.DemRepeatBlock.__repr__)\n    - [`stim.DemRepeatBlock.body_copy`](#stim.DemRepeatBlock.body_copy)\n    - [`stim.DemRepeatBlock.repeat_count`](#stim.DemRepeatBlock.repeat_count)\n    - [`stim.DemRepeatBlock.type`](#stim.DemRepeatBlock.type)\n- [`stim.DemTarget`](#stim.DemTarget)\n    - [`stim.DemTarget.__eq__`](#stim.DemTarget.__eq__)\n    - [`stim.DemTarget.__init__`](#stim.DemTarget.__init__)\n    - [`stim.DemTarget.__ne__`](#stim.DemTarget.__ne__)\n    - [`stim.DemTarget.__repr__`](#stim.DemTarget.__repr__)\n    - [`stim.DemTarget.__str__`](#stim.DemTarget.__str__)\n    - [`stim.DemTarget.is_logical_observable_id`](#stim.DemTarget.is_logical_observable_id)\n    - [`stim.DemTarget.is_relative_detector_id`](#stim.DemTarget.is_relative_detector_id)\n    - [`stim.DemTarget.is_separator`](#stim.DemTarget.is_separator)\n    - [`stim.DemTarget.logical_observable_id`](#stim.DemTarget.logical_observable_id)\n    - [`stim.DemTarget.relative_detector_id`](#stim.DemTarget.relative_detector_id)\n    - [`stim.DemTarget.separator`](#stim.DemTarget.separator)\n    - [`stim.DemTarget.val`](#stim.DemTarget.val)\n- [`stim.DemTargetWithCoords`](#stim.DemTargetWithCoords)\n    - [`stim.DemTargetWithCoords.__init__`](#stim.DemTargetWithCoords.__init__)\n    - [`stim.DemTargetWithCoords.coords`](#stim.DemTargetWithCoords.coords)\n    - [`stim.DemTargetWithCoords.dem_target`](#stim.DemTargetWithCoords.dem_target)\n- [`stim.DetectorErrorModel`](#stim.DetectorErrorModel)\n    - [`stim.DetectorErrorModel.__add__`](#stim.DetectorErrorModel.__add__)\n    - [`stim.DetectorErrorModel.__eq__`](#stim.DetectorErrorModel.__eq__)\n    - [`stim.DetectorErrorModel.__getitem__`](#stim.DetectorErrorModel.__getitem__)\n    - [`stim.DetectorErrorModel.__iadd__`](#stim.DetectorErrorModel.__iadd__)\n    - [`stim.DetectorErrorModel.__imul__`](#stim.DetectorErrorModel.__imul__)\n    - [`stim.DetectorErrorModel.__init__`](#stim.DetectorErrorModel.__init__)\n    - [`stim.DetectorErrorModel.__len__`](#stim.DetectorErrorModel.__len__)\n    - [`stim.DetectorErrorModel.__mul__`](#stim.DetectorErrorModel.__mul__)\n    - [`stim.DetectorErrorModel.__ne__`](#stim.DetectorErrorModel.__ne__)\n    - [`stim.DetectorErrorModel.__repr__`](#stim.DetectorErrorModel.__repr__)\n    - [`stim.DetectorErrorModel.__rmul__`](#stim.DetectorErrorModel.__rmul__)\n    - [`stim.DetectorErrorModel.__str__`](#stim.DetectorErrorModel.__str__)\n    - [`stim.DetectorErrorModel.append`](#stim.DetectorErrorModel.append)\n    - [`stim.DetectorErrorModel.approx_equals`](#stim.DetectorErrorModel.approx_equals)\n    - [`stim.DetectorErrorModel.clear`](#stim.DetectorErrorModel.clear)\n    - [`stim.DetectorErrorModel.compile_sampler`](#stim.DetectorErrorModel.compile_sampler)\n    - [`stim.DetectorErrorModel.copy`](#stim.DetectorErrorModel.copy)\n    - [`stim.DetectorErrorModel.diagram`](#stim.DetectorErrorModel.diagram)\n    - [`stim.DetectorErrorModel.flattened`](#stim.DetectorErrorModel.flattened)\n    - [`stim.DetectorErrorModel.from_file`](#stim.DetectorErrorModel.from_file)\n    - [`stim.DetectorErrorModel.get_detector_coordinates`](#stim.DetectorErrorModel.get_detector_coordinates)\n    - [`stim.DetectorErrorModel.num_detectors`](#stim.DetectorErrorModel.num_detectors)\n    - [`stim.DetectorErrorModel.num_errors`](#stim.DetectorErrorModel.num_errors)\n    - [`stim.DetectorErrorModel.num_observables`](#stim.DetectorErrorModel.num_observables)\n    - [`stim.DetectorErrorModel.rounded`](#stim.DetectorErrorModel.rounded)\n    - [`stim.DetectorErrorModel.shortest_graphlike_error`](#stim.DetectorErrorModel.shortest_graphlike_error)\n    - [`stim.DetectorErrorModel.to_file`](#stim.DetectorErrorModel.to_file)\n    - [`stim.DetectorErrorModel.without_tags`](#stim.DetectorErrorModel.without_tags)\n- [`stim.ExplainedError`](#stim.ExplainedError)\n    - [`stim.ExplainedError.__init__`](#stim.ExplainedError.__init__)\n    - [`stim.ExplainedError.circuit_error_locations`](#stim.ExplainedError.circuit_error_locations)\n    - [`stim.ExplainedError.dem_error_terms`](#stim.ExplainedError.dem_error_terms)\n- [`stim.FlipSimulator`](#stim.FlipSimulator)\n    - [`stim.FlipSimulator.__init__`](#stim.FlipSimulator.__init__)\n    - [`stim.FlipSimulator.append_measurement_flips`](#stim.FlipSimulator.append_measurement_flips)\n    - [`stim.FlipSimulator.batch_size`](#stim.FlipSimulator.batch_size)\n    - [`stim.FlipSimulator.broadcast_pauli_errors`](#stim.FlipSimulator.broadcast_pauli_errors)\n    - [`stim.FlipSimulator.clear`](#stim.FlipSimulator.clear)\n    - [`stim.FlipSimulator.copy`](#stim.FlipSimulator.copy)\n    - [`stim.FlipSimulator.do`](#stim.FlipSimulator.do)\n    - [`stim.FlipSimulator.generate_bernoulli_samples`](#stim.FlipSimulator.generate_bernoulli_samples)\n    - [`stim.FlipSimulator.get_detector_flips`](#stim.FlipSimulator.get_detector_flips)\n    - [`stim.FlipSimulator.get_measurement_flips`](#stim.FlipSimulator.get_measurement_flips)\n    - [`stim.FlipSimulator.get_observable_flips`](#stim.FlipSimulator.get_observable_flips)\n    - [`stim.FlipSimulator.num_detectors`](#stim.FlipSimulator.num_detectors)\n    - [`stim.FlipSimulator.num_measurements`](#stim.FlipSimulator.num_measurements)\n    - [`stim.FlipSimulator.num_observables`](#stim.FlipSimulator.num_observables)\n    - [`stim.FlipSimulator.num_qubits`](#stim.FlipSimulator.num_qubits)\n    - [`stim.FlipSimulator.peek_pauli_flips`](#stim.FlipSimulator.peek_pauli_flips)\n    - [`stim.FlipSimulator.set_pauli_flip`](#stim.FlipSimulator.set_pauli_flip)\n    - [`stim.FlipSimulator.to_numpy`](#stim.FlipSimulator.to_numpy)\n- [`stim.FlippedMeasurement`](#stim.FlippedMeasurement)\n    - [`stim.FlippedMeasurement.__init__`](#stim.FlippedMeasurement.__init__)\n    - [`stim.FlippedMeasurement.observable`](#stim.FlippedMeasurement.observable)\n    - [`stim.FlippedMeasurement.record_index`](#stim.FlippedMeasurement.record_index)\n- [`stim.Flow`](#stim.Flow)\n    - [`stim.Flow.__eq__`](#stim.Flow.__eq__)\n    - [`stim.Flow.__init__`](#stim.Flow.__init__)\n    - [`stim.Flow.__mul__`](#stim.Flow.__mul__)\n    - [`stim.Flow.__ne__`](#stim.Flow.__ne__)\n    - [`stim.Flow.__repr__`](#stim.Flow.__repr__)\n    - [`stim.Flow.__str__`](#stim.Flow.__str__)\n    - [`stim.Flow.included_observables_copy`](#stim.Flow.included_observables_copy)\n    - [`stim.Flow.input_copy`](#stim.Flow.input_copy)\n    - [`stim.Flow.measurements_copy`](#stim.Flow.measurements_copy)\n    - [`stim.Flow.output_copy`](#stim.Flow.output_copy)\n- [`stim.GateData`](#stim.GateData)\n    - [`stim.GateData.__eq__`](#stim.GateData.__eq__)\n    - [`stim.GateData.__init__`](#stim.GateData.__init__)\n    - [`stim.GateData.__ne__`](#stim.GateData.__ne__)\n    - [`stim.GateData.__repr__`](#stim.GateData.__repr__)\n    - [`stim.GateData.__str__`](#stim.GateData.__str__)\n    - [`stim.GateData.aliases`](#stim.GateData.aliases)\n    - [`stim.GateData.flows`](#stim.GateData.flows)\n    - [`stim.GateData.generalized_inverse`](#stim.GateData.generalized_inverse)\n    - [`stim.GateData.hadamard_conjugated`](#stim.GateData.hadamard_conjugated)\n    - [`stim.GateData.inverse`](#stim.GateData.inverse)\n    - [`stim.GateData.is_noisy_gate`](#stim.GateData.is_noisy_gate)\n    - [`stim.GateData.is_reset`](#stim.GateData.is_reset)\n    - [`stim.GateData.is_single_qubit_gate`](#stim.GateData.is_single_qubit_gate)\n    - [`stim.GateData.is_symmetric_gate`](#stim.GateData.is_symmetric_gate)\n    - [`stim.GateData.is_two_qubit_gate`](#stim.GateData.is_two_qubit_gate)\n    - [`stim.GateData.is_unitary`](#stim.GateData.is_unitary)\n    - [`stim.GateData.name`](#stim.GateData.name)\n    - [`stim.GateData.num_parens_arguments_range`](#stim.GateData.num_parens_arguments_range)\n    - [`stim.GateData.produces_measurements`](#stim.GateData.produces_measurements)\n    - [`stim.GateData.tableau`](#stim.GateData.tableau)\n    - [`stim.GateData.takes_measurement_record_targets`](#stim.GateData.takes_measurement_record_targets)\n    - [`stim.GateData.takes_pauli_targets`](#stim.GateData.takes_pauli_targets)\n    - [`stim.GateData.unitary_matrix`](#stim.GateData.unitary_matrix)\n- [`stim.GateTarget`](#stim.GateTarget)\n    - [`stim.GateTarget.__eq__`](#stim.GateTarget.__eq__)\n    - [`stim.GateTarget.__init__`](#stim.GateTarget.__init__)\n    - [`stim.GateTarget.__ne__`](#stim.GateTarget.__ne__)\n    - [`stim.GateTarget.__repr__`](#stim.GateTarget.__repr__)\n    - [`stim.GateTarget.is_combiner`](#stim.GateTarget.is_combiner)\n    - [`stim.GateTarget.is_inverted_result_target`](#stim.GateTarget.is_inverted_result_target)\n    - [`stim.GateTarget.is_measurement_record_target`](#stim.GateTarget.is_measurement_record_target)\n    - [`stim.GateTarget.is_qubit_target`](#stim.GateTarget.is_qubit_target)\n    - [`stim.GateTarget.is_sweep_bit_target`](#stim.GateTarget.is_sweep_bit_target)\n    - [`stim.GateTarget.is_x_target`](#stim.GateTarget.is_x_target)\n    - [`stim.GateTarget.is_y_target`](#stim.GateTarget.is_y_target)\n    - [`stim.GateTarget.is_z_target`](#stim.GateTarget.is_z_target)\n    - [`stim.GateTarget.pauli_type`](#stim.GateTarget.pauli_type)\n    - [`stim.GateTarget.qubit_value`](#stim.GateTarget.qubit_value)\n    - [`stim.GateTarget.value`](#stim.GateTarget.value)\n- [`stim.GateTargetWithCoords`](#stim.GateTargetWithCoords)\n    - [`stim.GateTargetWithCoords.__init__`](#stim.GateTargetWithCoords.__init__)\n    - [`stim.GateTargetWithCoords.coords`](#stim.GateTargetWithCoords.coords)\n    - [`stim.GateTargetWithCoords.gate_target`](#stim.GateTargetWithCoords.gate_target)\n- [`stim.PauliString`](#stim.PauliString)\n    - [`stim.PauliString.__add__`](#stim.PauliString.__add__)\n    - [`stim.PauliString.__eq__`](#stim.PauliString.__eq__)\n    - [`stim.PauliString.__getitem__`](#stim.PauliString.__getitem__)\n    - [`stim.PauliString.__iadd__`](#stim.PauliString.__iadd__)\n    - [`stim.PauliString.__imul__`](#stim.PauliString.__imul__)\n    - [`stim.PauliString.__init__`](#stim.PauliString.__init__)\n    - [`stim.PauliString.__itruediv__`](#stim.PauliString.__itruediv__)\n    - [`stim.PauliString.__len__`](#stim.PauliString.__len__)\n    - [`stim.PauliString.__mul__`](#stim.PauliString.__mul__)\n    - [`stim.PauliString.__ne__`](#stim.PauliString.__ne__)\n    - [`stim.PauliString.__neg__`](#stim.PauliString.__neg__)\n    - [`stim.PauliString.__pos__`](#stim.PauliString.__pos__)\n    - [`stim.PauliString.__repr__`](#stim.PauliString.__repr__)\n    - [`stim.PauliString.__rmul__`](#stim.PauliString.__rmul__)\n    - [`stim.PauliString.__setitem__`](#stim.PauliString.__setitem__)\n    - [`stim.PauliString.__str__`](#stim.PauliString.__str__)\n    - [`stim.PauliString.__truediv__`](#stim.PauliString.__truediv__)\n    - [`stim.PauliString.after`](#stim.PauliString.after)\n    - [`stim.PauliString.before`](#stim.PauliString.before)\n    - [`stim.PauliString.commutes`](#stim.PauliString.commutes)\n    - [`stim.PauliString.copy`](#stim.PauliString.copy)\n    - [`stim.PauliString.from_numpy`](#stim.PauliString.from_numpy)\n    - [`stim.PauliString.from_unitary_matrix`](#stim.PauliString.from_unitary_matrix)\n    - [`stim.PauliString.iter_all`](#stim.PauliString.iter_all)\n    - [`stim.PauliString.pauli_indices`](#stim.PauliString.pauli_indices)\n    - [`stim.PauliString.random`](#stim.PauliString.random)\n    - [`stim.PauliString.sign`](#stim.PauliString.sign)\n    - [`stim.PauliString.to_numpy`](#stim.PauliString.to_numpy)\n    - [`stim.PauliString.to_tableau`](#stim.PauliString.to_tableau)\n    - [`stim.PauliString.to_unitary_matrix`](#stim.PauliString.to_unitary_matrix)\n    - [`stim.PauliString.weight`](#stim.PauliString.weight)\n- [`stim.PauliStringIterator`](#stim.PauliStringIterator)\n    - [`stim.PauliStringIterator.__iter__`](#stim.PauliStringIterator.__iter__)\n    - [`stim.PauliStringIterator.__next__`](#stim.PauliStringIterator.__next__)\n- [`stim.Tableau`](#stim.Tableau)\n    - [`stim.Tableau.__add__`](#stim.Tableau.__add__)\n    - [`stim.Tableau.__call__`](#stim.Tableau.__call__)\n    - [`stim.Tableau.__eq__`](#stim.Tableau.__eq__)\n    - [`stim.Tableau.__iadd__`](#stim.Tableau.__iadd__)\n    - [`stim.Tableau.__init__`](#stim.Tableau.__init__)\n    - [`stim.Tableau.__len__`](#stim.Tableau.__len__)\n    - [`stim.Tableau.__mul__`](#stim.Tableau.__mul__)\n    - [`stim.Tableau.__ne__`](#stim.Tableau.__ne__)\n    - [`stim.Tableau.__pow__`](#stim.Tableau.__pow__)\n    - [`stim.Tableau.__repr__`](#stim.Tableau.__repr__)\n    - [`stim.Tableau.__str__`](#stim.Tableau.__str__)\n    - [`stim.Tableau.append`](#stim.Tableau.append)\n    - [`stim.Tableau.copy`](#stim.Tableau.copy)\n    - [`stim.Tableau.from_circuit`](#stim.Tableau.from_circuit)\n    - [`stim.Tableau.from_conjugated_generators`](#stim.Tableau.from_conjugated_generators)\n    - [`stim.Tableau.from_named_gate`](#stim.Tableau.from_named_gate)\n    - [`stim.Tableau.from_numpy`](#stim.Tableau.from_numpy)\n    - [`stim.Tableau.from_stabilizers`](#stim.Tableau.from_stabilizers)\n    - [`stim.Tableau.from_state_vector`](#stim.Tableau.from_state_vector)\n    - [`stim.Tableau.from_unitary_matrix`](#stim.Tableau.from_unitary_matrix)\n    - [`stim.Tableau.inverse`](#stim.Tableau.inverse)\n    - [`stim.Tableau.inverse_x_output`](#stim.Tableau.inverse_x_output)\n    - [`stim.Tableau.inverse_x_output_pauli`](#stim.Tableau.inverse_x_output_pauli)\n    - [`stim.Tableau.inverse_y_output`](#stim.Tableau.inverse_y_output)\n    - [`stim.Tableau.inverse_y_output_pauli`](#stim.Tableau.inverse_y_output_pauli)\n    - [`stim.Tableau.inverse_z_output`](#stim.Tableau.inverse_z_output)\n    - [`stim.Tableau.inverse_z_output_pauli`](#stim.Tableau.inverse_z_output_pauli)\n    - [`stim.Tableau.iter_all`](#stim.Tableau.iter_all)\n    - [`stim.Tableau.prepend`](#stim.Tableau.prepend)\n    - [`stim.Tableau.random`](#stim.Tableau.random)\n    - [`stim.Tableau.then`](#stim.Tableau.then)\n    - [`stim.Tableau.to_circuit`](#stim.Tableau.to_circuit)\n    - [`stim.Tableau.to_numpy`](#stim.Tableau.to_numpy)\n    - [`stim.Tableau.to_pauli_string`](#stim.Tableau.to_pauli_string)\n    - [`stim.Tableau.to_stabilizers`](#stim.Tableau.to_stabilizers)\n    - [`stim.Tableau.to_state_vector`](#stim.Tableau.to_state_vector)\n    - [`stim.Tableau.to_unitary_matrix`](#stim.Tableau.to_unitary_matrix)\n    - [`stim.Tableau.x_output`](#stim.Tableau.x_output)\n    - [`stim.Tableau.x_output_pauli`](#stim.Tableau.x_output_pauli)\n    - [`stim.Tableau.x_sign`](#stim.Tableau.x_sign)\n    - [`stim.Tableau.y_output`](#stim.Tableau.y_output)\n    - [`stim.Tableau.y_output_pauli`](#stim.Tableau.y_output_pauli)\n    - [`stim.Tableau.y_sign`](#stim.Tableau.y_sign)\n    - [`stim.Tableau.z_output`](#stim.Tableau.z_output)\n    - [`stim.Tableau.z_output_pauli`](#stim.Tableau.z_output_pauli)\n    - [`stim.Tableau.z_sign`](#stim.Tableau.z_sign)\n- [`stim.TableauIterator`](#stim.TableauIterator)\n    - [`stim.TableauIterator.__iter__`](#stim.TableauIterator.__iter__)\n    - [`stim.TableauIterator.__next__`](#stim.TableauIterator.__next__)\n- [`stim.TableauSimulator`](#stim.TableauSimulator)\n    - [`stim.TableauSimulator.__init__`](#stim.TableauSimulator.__init__)\n    - [`stim.TableauSimulator.c_xyz`](#stim.TableauSimulator.c_xyz)\n    - [`stim.TableauSimulator.c_zyx`](#stim.TableauSimulator.c_zyx)\n    - [`stim.TableauSimulator.canonical_stabilizers`](#stim.TableauSimulator.canonical_stabilizers)\n    - [`stim.TableauSimulator.cnot`](#stim.TableauSimulator.cnot)\n    - [`stim.TableauSimulator.copy`](#stim.TableauSimulator.copy)\n    - [`stim.TableauSimulator.current_inverse_tableau`](#stim.TableauSimulator.current_inverse_tableau)\n    - [`stim.TableauSimulator.current_measurement_record`](#stim.TableauSimulator.current_measurement_record)\n    - [`stim.TableauSimulator.cx`](#stim.TableauSimulator.cx)\n    - [`stim.TableauSimulator.cy`](#stim.TableauSimulator.cy)\n    - [`stim.TableauSimulator.cz`](#stim.TableauSimulator.cz)\n    - [`stim.TableauSimulator.depolarize1`](#stim.TableauSimulator.depolarize1)\n    - [`stim.TableauSimulator.depolarize2`](#stim.TableauSimulator.depolarize2)\n    - [`stim.TableauSimulator.do`](#stim.TableauSimulator.do)\n    - [`stim.TableauSimulator.do_circuit`](#stim.TableauSimulator.do_circuit)\n    - [`stim.TableauSimulator.do_pauli_string`](#stim.TableauSimulator.do_pauli_string)\n    - [`stim.TableauSimulator.do_tableau`](#stim.TableauSimulator.do_tableau)\n    - [`stim.TableauSimulator.h`](#stim.TableauSimulator.h)\n    - [`stim.TableauSimulator.h_xy`](#stim.TableauSimulator.h_xy)\n    - [`stim.TableauSimulator.h_xz`](#stim.TableauSimulator.h_xz)\n    - [`stim.TableauSimulator.h_yz`](#stim.TableauSimulator.h_yz)\n    - [`stim.TableauSimulator.iswap`](#stim.TableauSimulator.iswap)\n    - [`stim.TableauSimulator.iswap_dag`](#stim.TableauSimulator.iswap_dag)\n    - [`stim.TableauSimulator.measure`](#stim.TableauSimulator.measure)\n    - [`stim.TableauSimulator.measure_kickback`](#stim.TableauSimulator.measure_kickback)\n    - [`stim.TableauSimulator.measure_many`](#stim.TableauSimulator.measure_many)\n    - [`stim.TableauSimulator.measure_observable`](#stim.TableauSimulator.measure_observable)\n    - [`stim.TableauSimulator.num_qubits`](#stim.TableauSimulator.num_qubits)\n    - [`stim.TableauSimulator.peek_bloch`](#stim.TableauSimulator.peek_bloch)\n    - [`stim.TableauSimulator.peek_observable_expectation`](#stim.TableauSimulator.peek_observable_expectation)\n    - [`stim.TableauSimulator.peek_x`](#stim.TableauSimulator.peek_x)\n    - [`stim.TableauSimulator.peek_y`](#stim.TableauSimulator.peek_y)\n    - [`stim.TableauSimulator.peek_z`](#stim.TableauSimulator.peek_z)\n    - [`stim.TableauSimulator.postselect_observable`](#stim.TableauSimulator.postselect_observable)\n    - [`stim.TableauSimulator.postselect_x`](#stim.TableauSimulator.postselect_x)\n    - [`stim.TableauSimulator.postselect_y`](#stim.TableauSimulator.postselect_y)\n    - [`stim.TableauSimulator.postselect_z`](#stim.TableauSimulator.postselect_z)\n    - [`stim.TableauSimulator.reset`](#stim.TableauSimulator.reset)\n    - [`stim.TableauSimulator.reset_x`](#stim.TableauSimulator.reset_x)\n    - [`stim.TableauSimulator.reset_y`](#stim.TableauSimulator.reset_y)\n    - [`stim.TableauSimulator.reset_z`](#stim.TableauSimulator.reset_z)\n    - [`stim.TableauSimulator.s`](#stim.TableauSimulator.s)\n    - [`stim.TableauSimulator.s_dag`](#stim.TableauSimulator.s_dag)\n    - [`stim.TableauSimulator.set_inverse_tableau`](#stim.TableauSimulator.set_inverse_tableau)\n    - [`stim.TableauSimulator.set_num_qubits`](#stim.TableauSimulator.set_num_qubits)\n    - [`stim.TableauSimulator.set_state_from_stabilizers`](#stim.TableauSimulator.set_state_from_stabilizers)\n    - [`stim.TableauSimulator.set_state_from_state_vector`](#stim.TableauSimulator.set_state_from_state_vector)\n    - [`stim.TableauSimulator.sqrt_x`](#stim.TableauSimulator.sqrt_x)\n    - [`stim.TableauSimulator.sqrt_x_dag`](#stim.TableauSimulator.sqrt_x_dag)\n    - [`stim.TableauSimulator.sqrt_y`](#stim.TableauSimulator.sqrt_y)\n    - [`stim.TableauSimulator.sqrt_y_dag`](#stim.TableauSimulator.sqrt_y_dag)\n    - [`stim.TableauSimulator.state_vector`](#stim.TableauSimulator.state_vector)\n    - [`stim.TableauSimulator.swap`](#stim.TableauSimulator.swap)\n    - [`stim.TableauSimulator.x`](#stim.TableauSimulator.x)\n    - [`stim.TableauSimulator.x_error`](#stim.TableauSimulator.x_error)\n    - [`stim.TableauSimulator.xcx`](#stim.TableauSimulator.xcx)\n    - [`stim.TableauSimulator.xcy`](#stim.TableauSimulator.xcy)\n    - [`stim.TableauSimulator.xcz`](#stim.TableauSimulator.xcz)\n    - [`stim.TableauSimulator.y`](#stim.TableauSimulator.y)\n    - [`stim.TableauSimulator.y_error`](#stim.TableauSimulator.y_error)\n    - [`stim.TableauSimulator.ycx`](#stim.TableauSimulator.ycx)\n    - [`stim.TableauSimulator.ycy`](#stim.TableauSimulator.ycy)\n    - [`stim.TableauSimulator.ycz`](#stim.TableauSimulator.ycz)\n    - [`stim.TableauSimulator.z`](#stim.TableauSimulator.z)\n    - [`stim.TableauSimulator.z_error`](#stim.TableauSimulator.z_error)\n    - [`stim.TableauSimulator.zcx`](#stim.TableauSimulator.zcx)\n    - [`stim.TableauSimulator.zcy`](#stim.TableauSimulator.zcy)\n    - [`stim.TableauSimulator.zcz`](#stim.TableauSimulator.zcz)\n- [`stim.gate_data`](#stim.gate_data)\n- [`stim.main`](#stim.main)\n- [`stim.read_shot_data_file`](#stim.read_shot_data_file)\n- [`stim.target_combined_paulis`](#stim.target_combined_paulis)\n- [`stim.target_combiner`](#stim.target_combiner)\n- [`stim.target_inv`](#stim.target_inv)\n- [`stim.target_logical_observable_id`](#stim.target_logical_observable_id)\n- [`stim.target_pauli`](#stim.target_pauli)\n- [`stim.target_rec`](#stim.target_rec)\n- [`stim.target_relative_detector_id`](#stim.target_relative_detector_id)\n- [`stim.target_separator`](#stim.target_separator)\n- [`stim.target_sweep_bit`](#stim.target_sweep_bit)\n- [`stim.target_x`](#stim.target_x)\n- [`stim.target_y`](#stim.target_y)\n- [`stim.target_z`](#stim.target_z)\n- [`stim.write_shot_data_file`](#stim.write_shot_data_file)\n```python\n# Types used by the method definitions.\nfrom typing import overload, TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, Union\nimport io\nimport pathlib\nimport numpy as np\n```\n\n<a name=\"stim.Circuit\"></a>\n```python\n# stim.Circuit\n\n# (at top-level in the stim module)\nclass Circuit:\n    \"\"\"A mutable stabilizer circuit.\n\n    The stim.Circuit class is arguably the most important object in the\n    entire library. It is the interface through which you explain a\n    noisy quantum computation to Stim, in order to do fast bulk sampling\n    or fast error analysis.\n\n    For example, suppose you want to use a matching-based decoder on a\n    new quantum error correction construction. Stim can help you do this\n    but the very first step is to create a circuit implementing the\n    construction. Once you have the circuit you can then use methods like\n    stim.Circuit.detector_error_model() to create an object that can be\n    used to configure the decoder, or like\n    stim.Circuit.compile_detector_sampler() to produce problems for the\n    decoder to solve, or like stim.Circuit.shortest_graphlike_error() to\n    check for mistakes in the implementation of the code.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit()\n        >>> c.append(\"X\", 0)\n        >>> c.append(\"M\", 0)\n        >>> c.compile_sampler().sample(shots=1)\n        array([[ True]])\n\n        >>> stim.Circuit('''\n        ...    H 0\n        ...    CNOT 0 1\n        ...    M 0 1\n        ...    DETECTOR rec[-1] rec[-2]\n        ... ''').compile_detector_sampler().sample(shots=1)\n        array([[False]])\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__add__\"></a>\n```python\n# stim.Circuit.__add__\n\n# (in class stim.Circuit)\ndef __add__(\n    self,\n    second: stim.Circuit,\n) -> stim.Circuit:\n    \"\"\"Creates a circuit by appending two circuits.\n\n    Examples:\n        >>> import stim\n        >>> c1 = stim.Circuit('''\n        ...    X 0\n        ...    Y 1 2\n        ... ''')\n        >>> c2 = stim.Circuit('''\n        ...    M 0 1 2\n        ... ''')\n        >>> c1 + c2\n        stim.Circuit('''\n            X 0\n            Y 1 2\n            M 0 1 2\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__eq__\"></a>\n```python\n# stim.Circuit.__eq__\n\n# (in class stim.Circuit)\ndef __eq__(\n    self,\n    arg0: stim.Circuit,\n) -> bool:\n    \"\"\"Determines if two circuits have identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__getitem__\"></a>\n```python\n# stim.Circuit.__getitem__\n\n# (in class stim.Circuit)\n@overload\ndef __getitem__(\n    self,\n    index_or_slice: int,\n) -> Union[stim.CircuitInstruction, stim.CircuitRepeatBlock]:\n    pass\n@overload\ndef __getitem__(\n    self,\n    index_or_slice: slice,\n) -> stim.Circuit:\n    pass\ndef __getitem__(\n    self,\n    index_or_slice: object,\n) -> object:\n    \"\"\"Returns copies of instructions from the circuit.\n\n    Args:\n        index_or_slice: An integer index picking out an instruction to return, or a\n            slice picking out a range of instructions to return as a circuit.\n\n    Returns:\n        If the index was an integer, then an instruction from the circuit.\n        If the index was a slice, then a circuit made up of the instructions in that\n        slice.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...    X 0\n        ...    X_ERROR(0.5) 2\n        ...    REPEAT 100 {\n        ...        X 0\n        ...        Y 1 2\n        ...    }\n        ...    TICK\n        ...    M 0\n        ...    DETECTOR rec[-1]\n        ... ''')\n        >>> circuit[1]\n        stim.CircuitInstruction('X_ERROR', [stim.GateTarget(2)], [0.5])\n        >>> circuit[2]\n        stim.CircuitRepeatBlock(100, stim.Circuit('''\n            X 0\n            Y 1 2\n        '''))\n        >>> circuit[1::2]\n        stim.Circuit('''\n            X_ERROR(0.5) 2\n            TICK\n            DETECTOR rec[-1]\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__iadd__\"></a>\n```python\n# stim.Circuit.__iadd__\n\n# (in class stim.Circuit)\ndef __iadd__(\n    self,\n    second: stim.Circuit,\n) -> stim.Circuit:\n    \"\"\"Appends a circuit into the receiving circuit (mutating it).\n\n    Examples:\n        >>> import stim\n        >>> c1 = stim.Circuit('''\n        ...    X 0\n        ...    Y 1 2\n        ... ''')\n        >>> c2 = stim.Circuit('''\n        ...    M 0 1 2\n        ... ''')\n        >>> c1 += c2\n        >>> print(repr(c1))\n        stim.Circuit('''\n            X 0\n            Y 1 2\n            M 0 1 2\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__imul__\"></a>\n```python\n# stim.Circuit.__imul__\n\n# (in class stim.Circuit)\ndef __imul__(\n    self,\n    repetitions: int,\n) -> stim.Circuit:\n    \"\"\"Mutates the circuit by putting its contents into a REPEAT block.\n\n    Special case: if the repetition count is 0, the circuit is cleared.\n    Special case: if the repetition count is 1, nothing happens.\n\n    Args:\n        repetitions: The number of times the REPEAT block should repeat.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    X 0\n        ...    Y 1 2\n        ... ''')\n        >>> c *= 3\n        >>> print(repr(c))\n        stim.Circuit('''\n            REPEAT 3 {\n                X 0\n                Y 1 2\n            }\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__init__\"></a>\n```python\n# stim.Circuit.__init__\n\n# (in class stim.Circuit)\ndef __init__(\n    self,\n    stim_program_text: str = '',\n) -> None:\n    \"\"\"Creates a stim.Circuit.\n\n    Args:\n        stim_program_text: Defaults to empty. Describes operations to append into\n            the circuit.\n\n    Examples:\n        >>> import stim\n        >>> empty = stim.Circuit()\n        >>> not_empty = stim.Circuit('''\n        ...    X 0\n        ...    CNOT 0 1\n        ...    M 1\n        ... ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__len__\"></a>\n```python\n# stim.Circuit.__len__\n\n# (in class stim.Circuit)\ndef __len__(\n    self,\n) -> int:\n    \"\"\"Returns the number of top-level instructions and blocks in the circuit.\n\n    Instructions inside of blocks are not included in this count.\n\n    Examples:\n        >>> import stim\n        >>> len(stim.Circuit())\n        0\n        >>> len(stim.Circuit('''\n        ...    X 0\n        ...    X_ERROR(0.5) 1 2\n        ...    TICK\n        ...    M 0\n        ...    DETECTOR rec[-1]\n        ... '''))\n        5\n        >>> len(stim.Circuit('''\n        ...    REPEAT 100 {\n        ...        X 0\n        ...        Y 1 2\n        ...    }\n        ... '''))\n        1\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__mul__\"></a>\n```python\n# stim.Circuit.__mul__\n\n# (in class stim.Circuit)\ndef __mul__(\n    self,\n    repetitions: int,\n) -> stim.Circuit:\n    \"\"\"Repeats the circuit using a REPEAT block.\n\n    Has special cases for 0 repetitions and 1 repetitions.\n\n    Args:\n        repetitions: The number of times the REPEAT block should repeat.\n\n    Returns:\n        repetitions=0: An empty circuit.\n        repetitions=1: A copy of this circuit.\n        repetitions>=2: A circuit with a single REPEAT block, where the contents of\n            that repeat block are this circuit.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    X 0\n        ...    Y 1 2\n        ... ''')\n        >>> c * 3\n        stim.Circuit('''\n            REPEAT 3 {\n                X 0\n                Y 1 2\n            }\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__ne__\"></a>\n```python\n# stim.Circuit.__ne__\n\n# (in class stim.Circuit)\ndef __ne__(\n    self,\n    arg0: stim.Circuit,\n) -> bool:\n    \"\"\"Determines if two circuits have non-identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__repr__\"></a>\n```python\n# stim.Circuit.__repr__\n\n# (in class stim.Circuit)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.Circuit`.\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__rmul__\"></a>\n```python\n# stim.Circuit.__rmul__\n\n# (in class stim.Circuit)\ndef __rmul__(\n    self,\n    repetitions: int,\n) -> stim.Circuit:\n    \"\"\"Repeats the circuit using a REPEAT block.\n\n    Has special cases for 0 repetitions and 1 repetitions.\n\n    Args:\n        repetitions: The number of times the REPEAT block should repeat.\n\n    Returns:\n        repetitions=0: An empty circuit.\n        repetitions=1: A copy of this circuit.\n        repetitions>=2: A circuit with a single REPEAT block, where the contents of\n            that repeat block are this circuit.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    X 0\n        ...    Y 1 2\n        ... ''')\n        >>> 3 * c\n        stim.Circuit('''\n            REPEAT 3 {\n                X 0\n                Y 1 2\n            }\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.__str__\"></a>\n```python\n# stim.Circuit.__str__\n\n# (in class stim.Circuit)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns stim instructions (that can be saved to a file and parsed by stim) for the current circuit.\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.append\"></a>\n```python\n# stim.Circuit.append\n\n# (in class stim.Circuit)\n@overload\ndef append(\n    self,\n    name: str,\n    targets: Union[int, stim.GateTarget, stim.PauliString, Iterable[Union[int, stim.GateTarget, stim.PauliString]]],\n    arg: Union[float, Iterable[float], None] = None,\n    *,\n    tag: str = \"\",\n) -> None:\n    pass\n@overload\ndef append(\n    self,\n    name: Union[stim.CircuitInstruction, stim.CircuitRepeatBlock, stim.Circuit],\n) -> None:\n    pass\ndef append(\n    self,\n    name: object,\n    targets: object = (),\n    arg: object = None,\n    *,\n    tag: str = '',\n) -> None:\n    \"\"\"Appends an operation into the circuit.\n\n    Note: `stim.Circuit.append_operation` is an alias of `stim.Circuit.append`.\n\n    Args:\n        name: The name of the operation's gate (e.g. \"H\" or \"M\" or \"CNOT\").\n\n            This argument can also be set to a `stim.CircuitInstruction` or\n            `stim.CircuitInstructionBlock`, which results in the instruction or\n            block being appended to the circuit. The other arguments (targets\n            and arg) can't be specified when doing so.\n\n            (The argument being called `name` is no longer quite right, but\n            is being kept for backwards compatibility.)\n        targets: The objects operated on by the gate. This can be either a\n            single target or an iterable of multiple targets.\n\n            Each target can be:\n                An int: The index of a targeted qubit.\n                A `stim.GateTarget`: Could be a variety of things. Methods like\n                    `stim.target_rec`, `stim.target_sweet`, `stim.target_x`, and\n                    `stim.CircuitInstruction.__getitem__` all return this type.\n                A `stim.PauliString`: This will automatically be expanded into\n                    a product of pauli targets like `X1*Y2*Z3`.\n        arg: The \"parens arguments\" for the gate, such as the probability for a\n            noise operation. A double or list of doubles parameterizing the\n            gate. Different gates take different parens arguments. For example,\n            X_ERROR takes a probability, OBSERVABLE_INCLUDE takes an observable\n            index, and PAULI_CHANNEL_1 takes three disjoint probabilities.\n\n            Note: Defaults to no parens arguments. Except, for backwards\n            compatibility reasons, `cirq.append_operation` (but not\n            `cirq.append`) will default to a single 0.0 argument for gates that\n            take exactly one argument.\n        tag: A customizable string attached to the instruction.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit()\n        >>> c.append(\"X\", 0)\n        >>> c.append(\"H\", [0, 1])\n        >>> c.append(\"M\", [0, stim.target_inv(1)])\n        >>> c.append(\"CNOT\", [stim.target_rec(-1), 0])\n        >>> c.append(\"X_ERROR\", [0], 0.125)\n        >>> c.append(\"CORRELATED_ERROR\", [stim.target_x(0), stim.target_y(2)], 0.25)\n        >>> c.append(\"MPP\", [stim.PauliString(\"X1*Y2\"), stim.GateTarget(\"Z3\")])\n        >>> print(repr(c))\n        stim.Circuit('''\n            X 0\n            H 0 1\n            M 0 !1\n            CX rec[-1] 0\n            X_ERROR(0.125) 0\n            E(0.25) X0 Y2\n            MPP X1*Y2 Z3\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.append_from_stim_program_text\"></a>\n```python\n# stim.Circuit.append_from_stim_program_text\n\n# (in class stim.Circuit)\ndef append_from_stim_program_text(\n    self,\n    stim_program_text: str,\n) -> None:\n    \"\"\"Appends operations described by a STIM format program into the circuit.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit()\n        >>> c.append_from_stim_program_text('''\n        ...    H 0  # comment\n        ...    CNOT 0 2\n        ...\n        ...    M 2\n        ...    CNOT rec[-1] 1\n        ... ''')\n        >>> print(c)\n        H 0\n        CX 0 2\n        M 2\n        CX rec[-1] 1\n\n    Args:\n        stim_program_text: The STIM program text containing the circuit operations\n            to append.\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.approx_equals\"></a>\n```python\n# stim.Circuit.approx_equals\n\n# (in class stim.Circuit)\ndef approx_equals(\n    self,\n    other: object,\n    *,\n    atol: float,\n) -> bool:\n    \"\"\"Checks if a circuit is approximately equal to another circuit.\n\n    Two circuits are approximately equal if they are equal up to slight\n    perturbations of instruction arguments such as probabilities. For example,\n    `X_ERROR(0.100) 0` is approximately equal to `X_ERROR(0.099)` within an absolute\n    tolerance of 0.002. All other details of the circuits (such as the ordering of\n    instructions and targets) must be exactly the same.\n\n    Args:\n        other: The circuit, or other object, to compare to this one.\n        atol: The absolute error tolerance. The maximum amount each probability may\n            have been perturbed by.\n\n    Returns:\n        True if the given object is a circuit approximately equal up to the\n        receiving circuit up to the given tolerance, otherwise False.\n\n    Examples:\n        >>> import stim\n        >>> base = stim.Circuit('''\n        ...    X_ERROR(0.099) 0 1 2\n        ...    M 0 1 2\n        ... ''')\n\n        >>> base.approx_equals(base, atol=0)\n        True\n\n        >>> base.approx_equals(stim.Circuit('''\n        ...    X_ERROR(0.101) 0 1 2\n        ...    M 0 1 2\n        ... '''), atol=0)\n        False\n\n        >>> base.approx_equals(stim.Circuit('''\n        ...    X_ERROR(0.101) 0 1 2\n        ...    M 0 1 2\n        ... '''), atol=0.0001)\n        False\n\n        >>> base.approx_equals(stim.Circuit('''\n        ...    X_ERROR(0.101) 0 1 2\n        ...    M 0 1 2\n        ... '''), atol=0.01)\n        True\n\n        >>> base.approx_equals(stim.Circuit('''\n        ...    DEPOLARIZE1(0.099) 0 1 2\n        ...    MRX 0 1 2\n        ... '''), atol=9999)\n        False\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.clear\"></a>\n```python\n# stim.Circuit.clear\n\n# (in class stim.Circuit)\ndef clear(\n    self,\n) -> None:\n    \"\"\"Clears the contents of the circuit.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    X 0\n        ...    Y 1 2\n        ... ''')\n        >>> c.clear()\n        >>> c\n        stim.Circuit()\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.compile_detector_sampler\"></a>\n```python\n# stim.Circuit.compile_detector_sampler\n\n# (in class stim.Circuit)\ndef compile_detector_sampler(\n    self,\n    *,\n    seed: object = None,\n) -> stim.CompiledDetectorSampler:\n    \"\"\"Returns an object that can batch sample detection events from the circuit.\n\n    Args:\n        seed: PARTIALLY determines simulation results by deterministically seeding\n            the random number generator.\n\n            Must be None or an integer in range(2**64).\n\n            Defaults to None. When None, the prng is seeded from system entropy.\n\n            When set to an integer, making the exact same series calls on the exact\n            same machine with the exact same version of Stim will produce the exact\n            same simulation results.\n\n            CAUTION: simulation results *WILL NOT* be consistent between versions of\n            Stim. This restriction is present to make it possible to have future\n            optimizations to the random sampling, and is enforced by introducing\n            intentional differences in the seeding strategy from version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines that\n            differ in the width of supported SIMD instructions. For example, using\n            the same seed on a machine that supports AVX instructions and one that\n            only supports SSE instructions may produce different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n            shots are taken. For example, taking 10 shots and then 90 shots will\n            give different results from taking 100 shots in one call.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    H 0\n        ...    CNOT 0 1\n        ...    M 0 1\n        ...    DETECTOR rec[-1] rec[-2]\n        ... ''')\n        >>> s = c.compile_detector_sampler()\n        >>> s.sample(shots=1)\n        array([[False]])\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.compile_m2d_converter\"></a>\n```python\n# stim.Circuit.compile_m2d_converter\n\n# (in class stim.Circuit)\ndef compile_m2d_converter(\n    self,\n    *,\n    skip_reference_sample: bool = False,\n) -> stim.CompiledMeasurementsToDetectionEventsConverter:\n    \"\"\"Creates a measurement-to-detection-event converter for the given circuit.\n\n    The converter can efficiently compute detection events and observable flips\n    from raw measurement data.\n\n    The converter uses a noiseless reference sample, collected from the circuit\n    using stim's Tableau simulator during initialization of the converter, as a\n    baseline for determining what the expected value of a detector is.\n\n    Note that the expected behavior of gauge detectors (detectors that are not\n    actually deterministic under noiseless execution) can vary depending on the\n    reference sample. Stim mitigates this by always generating the same reference\n    sample for a given circuit.\n\n    Args:\n        skip_reference_sample: Defaults to False. When set to True, the reference\n            sample used by the converter is initialized to all-zeroes instead of\n            being collected from the circuit. This should only be used if it's known\n            that the all-zeroes sample is actually a possible result from the\n            circuit (under noiseless execution).\n\n    Returns:\n        An initialized stim.CompiledMeasurementsToDetectionEventsConverter.\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n        >>> converter = stim.Circuit('''\n        ...    X 0\n        ...    M 0\n        ...    DETECTOR rec[-1]\n        ... ''').compile_m2d_converter()\n        >>> converter.convert(\n        ...     measurements=np.array([[0], [1]], dtype=np.bool_),\n        ...     append_observables=False,\n        ... )\n        array([[ True],\n               [False]])\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.compile_sampler\"></a>\n```python\n# stim.Circuit.compile_sampler\n\n# (in class stim.Circuit)\ndef compile_sampler(\n    self,\n    *,\n    skip_reference_sample: bool = False,\n    seed: Optional[int] = None,\n    reference_sample: Optional[np.ndarray] = None,\n) -> stim.CompiledMeasurementSampler:\n    \"\"\"Returns an object that can quickly batch sample measurements from the circuit.\n\n    Args:\n        skip_reference_sample: Defaults to False. When set to True, the reference\n            sample used by the sampler is initialized to all-zeroes instead of being\n            collected from the circuit. This means that the results returned by the\n            sampler are actually whether or not each measurement was *flipped*,\n            instead of true measurement results.\n\n            Forcing an all-zero reference sample is useful when you are only\n            interested in error propagation and don't want to have to deal with the\n            fact that some measurements want to be On when no errors occur. It is\n            also useful when you know for sure that the all-zero result is actually\n            a possible result from the circuit (under noiseless execution), meaning\n            it is a valid reference sample as good as any other. Computing the\n            reference sample is the most time consuming and memory intensive part of\n            simulating the circuit, so promising that the simulator can safely skip\n            that step is an effective optimization.\n        seed: PARTIALLY determines simulation results by deterministically seeding\n            the random number generator.\n\n            Must be None or an integer in range(2**64).\n\n            Defaults to None. When None, the prng is seeded from system entropy.\n\n            When set to an integer, making the exact same series calls on the exact\n            same machine with the exact same version of Stim will produce the exact\n            same simulation results.\n\n            CAUTION: simulation results *WILL NOT* be consistent between versions of\n            Stim. This restriction is present to make it possible to have future\n            optimizations to the random sampling, and is enforced by introducing\n            intentional differences in the seeding strategy from version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines that\n            differ in the width of supported SIMD instructions. For example, using\n            the same seed on a machine that supports AVX instructions and one that\n            only supports SSE instructions may produce different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n            shots are taken. For example, taking 10 shots and then 90 shots will\n            give different results from taking 100 shots in one call.\n        reference_sample: The data to xor into the measurement flips produced by the\n            frame simulator, in order to produce proper measurement results.\n            This can either be specified as an `np.bool_` array or a bit packed\n            `np.uint8` array (little endian). Under normal conditions, the reference\n            sample should be a valid noiseless sample of the circuit, such as the\n            one returned by `circuit.reference_sample()`. If this argument is not\n            provided, the reference sample will be set to\n            `circuit.reference_sample()`, unless `skip_reference_sample=True`\n            is used, in which case it will be set to all-zeros.\n\n    Raises:\n        ValueError: skip_reference_sample is True and reference_sample is not None.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    X 2\n        ...    M 0 1 2\n        ... ''')\n        >>> s = c.compile_sampler()\n        >>> s.sample(shots=1)\n        array([[False, False,  True]])\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.copy\"></a>\n```python\n# stim.Circuit.copy\n\n# (in class stim.Circuit)\ndef copy(\n    self,\n) -> stim.Circuit:\n    \"\"\"Returns a copy of the circuit. An independent circuit with the same contents.\n\n    Examples:\n        >>> import stim\n\n        >>> c1 = stim.Circuit(\"H 0\")\n        >>> c2 = c1.copy()\n        >>> c2 is c1\n        False\n        >>> c2 == c1\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.count_determined_measurements\"></a>\n```python\n# stim.Circuit.count_determined_measurements\n\n# (in class stim.Circuit)\ndef count_determined_measurements(\n    self,\n    *,\n    unknown_input: bool = False,\n) -> int:\n    \"\"\"Counts the number of predictable measurements in the circuit.\n\n    This method ignores any noise in the circuit.\n\n    This method works by performing a tableau stabilizer simulation of the circuit\n    and, before each measurement is simulated, checking if its expectation is\n    non-zero.\n\n    A measurement is predictable if its result can be predicted by using other\n    measurements that have already been performed, assuming the circuit is executed\n    without any noise.\n\n    Note that, when multiple measurements occur at the same time, re-ordering the\n    order they are resolved can change which specific measurements are predictable\n    but won't change how many of them were predictable in total.\n\n    The number of predictable measurements is a useful quantity because it's\n    related to the number of detectors and observables that a circuit should\n    declare. If circuit.num_detectors + circuit.num_observables is less than\n    circuit.count_determined_measurements(), this is a warning sign that you've\n    missed some detector declarations.\n\n    The exact relationship between the number of determined measurements and the\n    number of detectors and observables can differ from code to code. For example,\n    the toric code has an extra redundant measurement compared to the surface code\n    because in the toric code the last X stabilizer to be measured is equal to the\n    product of all other X stabilizers even in the first round when initializing in\n    the Z basis. Typically this relationship is not declared as a detector, because\n    it's not local, or as an observable, because it doesn't store a qubit.\n\n    Args:\n        unknown_input: Defaults to False (inputs assumed to be in the |0> state).\n            When set to True, the inputs are instead treated as being in unknown\n            random states. For example, this means that Z-basis measurements at\n            the very beginning of the circuit will be considered random rather\n            than determined.\n\n    Returns:\n        The number of measurements that were predictable.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     R 0\n        ...     M 0\n        ... ''').count_determined_measurements()\n        1\n\n        >>> stim.Circuit('''\n        ...     R 0\n        ...     H 0\n        ...     M 0\n        ... ''').count_determined_measurements()\n        0\n\n        >>> stim.Circuit('''\n        ...     M 0\n        ... ''').count_determined_measurements()\n        1\n\n        >>> stim.Circuit('''\n        ...     M 0\n        ... ''').count_determined_measurements(unknown_input=True)\n        0\n\n        >>> stim.Circuit('''\n        ...     M 0\n        ...     M 0 1\n        ...     M 0 1 2\n        ...     M 0 1 2 3\n        ... ''').count_determined_measurements(unknown_input=True)\n        6\n\n        >>> stim.Circuit('''\n        ...     R 0 1\n        ...     MZZ 0 1\n        ...     MYY 0 1\n        ...     MXX 0 1\n        ... ''').count_determined_measurements()\n        2\n\n        >>> circuit = stim.Circuit.generated(\n        ...     \"surface_code:rotated_memory_x\",\n        ...     distance=5,\n        ...     rounds=9,\n        ... )\n        >>> circuit.count_determined_measurements()\n        217\n        >>> circuit.num_detectors + circuit.num_observables\n        217\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.decomposed\"></a>\n```python\n# stim.Circuit.decomposed\n\n# (in class stim.Circuit)\ndef decomposed(\n    self,\n) -> stim.Circuit:\n    \"\"\"Recreates the circuit using (mostly) the {H,S,CX,M,R} gate set.\n\n    The intent of this method is to simplify the circuit to use fewer gate types,\n    so it's easier for other tools to consume. Currently, this method performs the\n    following simplifications:\n\n    - Single qubit cliffords are decomposed into {H,S}.\n    - Multi-qubit cliffords are decomposed into {H,S,CX}.\n    - Single qubit dissipative gates are decomposed into {H,S,M,R}.\n    - Multi-qubit dissipative gates are decomposed into {H,S,CX,M,R}.\n\n    Currently, the following types of gate *aren't* simplified, but they may be\n    in the future:\n\n    - Noise instructions (like X_ERROR, DEPOLARIZE2, and E).\n    - Annotations (like TICK, DETECTOR, and SHIFT_COORDS).\n    - The MPAD instruction.\n    - Repeat blocks are not flattened.\n\n    Returns:\n        A `stim.Circuit` whose function is equivalent to the original circuit,\n        but with most gates decomposed into the {H,S,CX,M,R} gate set.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     SWAP 0 1\n        ... ''').decomposed()\n        stim.Circuit('''\n            CX 0 1 1 0 0 1\n        ''')\n\n        >>> stim.Circuit('''\n        ...     ISWAP 0 1 2 1\n        ...     TICK\n        ...     MPP !X1*Y2*Z3\n        ... ''').decomposed()\n        stim.Circuit('''\n            H 0\n            CX 0 1 1 0\n            H 1\n            S 1 0\n            H 2\n            CX 2 1 1 2\n            H 1\n            S 1 2\n            TICK\n            H 1 2\n            S 2\n            H 2\n            S 2 2\n            CX 2 1 3 1\n            M !1\n            CX 2 1 3 1\n            H 2\n            S 2\n            H 2\n            S 2 2\n            H 1\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.detecting_regions\"></a>\n```python\n# stim.Circuit.detecting_regions\n\n# (in class stim.Circuit)\ndef detecting_regions(\n    self,\n    *,\n    targets: Optional[Iterable[stim.DemTarget | str | Iterable[float]]] = None,\n    ticks: Optional[Iterable[int]] = None,\n) -> Dict[stim.DemTarget, Dict[int, stim.PauliString]]:\n    \"\"\"Records where detectors and observables are sensitive to errors over time.\n\n    The result of this method is a nested dictionary, mapping detectors/observables\n    and ticks to Pauli sensitivities for that detector/observable at that time.\n\n    For example, if observable 2 has Z-type sensitivity on qubits 5 and 6 during\n    tick 3, then `result[stim.target_logical_observable_id(2)][3]` will be equal to\n    `stim.PauliString(\"Z5*Z6\")`.\n\n    If you want sensitivities from more places in the circuit, besides just at the\n    TICK instructions, you can work around this by making a version of the circuit\n    with more TICKs.\n\n    Args:\n        targets: Defaults to everything (None).\n\n            When specified, this should be an iterable of filters where items\n            matching any one filter are included.\n\n            A variety of filters are supported:\n                stim.DemTarget: Includes the targeted detector or observable.\n                Iterable[float]: Coordinate prefix match. Includes detectors whose\n                    coordinate data begins with the same floats.\n                \"D\": Includes all detectors.\n                \"L\": Includes all observables.\n                \"D#\" (e.g. \"D5\"): Includes the detector with the specified index.\n                \"L#\" (e.g. \"L5\"): Includes the observable with the specified index.\n\n        ticks: Defaults to everything (None).\n            When specified, this should be a list of integers corresponding to\n            the tick indices to report sensitivities for.\n\n        ignore_anticommutation_errors: Defaults to False.\n            When set to False, invalid detecting regions that anticommute with a\n            reset will cause the method to raise an exception. When set to True,\n            the offending component will simply be silently dropped. This can\n            result in broken detectors having apparently enormous detecting\n            regions.\n\n    Returns:\n        Nested dictionaries keyed first by a `stim.DemTarget` identifying the\n        detector or observable, then by the index of the tick, leading to a\n        PauliString with that target's error sensitivity at that tick.\n\n        Note you can use `stim.PauliString.pauli_indices` to quickly get to the\n        non-identity terms in the sensitivity.\n\n    Examples:\n        >>> import stim\n\n        >>> detecting_regions = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     H 0\n        ...     TICK\n        ...     CX 0 1\n        ...     TICK\n        ...     MX 0 1\n        ...     DETECTOR rec[-1] rec[-2]\n        ... ''').detecting_regions()\n        >>> for target, tick_regions in detecting_regions.items():\n        ...     print(\"target\", target)\n        ...     for tick, sensitivity in tick_regions.items():\n        ...         print(\"    tick\", tick, \"=\", sensitivity)\n        target D0\n            tick 0 = +Z_\n            tick 1 = +X_\n            tick 2 = +XX\n\n        >>> circuit = stim.Circuit.generated(\n        ...     \"surface_code:rotated_memory_x\",\n        ...     rounds=5,\n        ...     distance=4,\n        ... )\n\n        >>> detecting_regions = circuit.detecting_regions(\n        ...     targets=[\"L0\", (2, 4), stim.DemTarget.relative_detector_id(5)],\n        ...     ticks=range(5, 15),\n        ... )\n        >>> for target, tick_regions in detecting_regions.items():\n        ...     print(\"target\", target)\n        ...     for tick, sensitivity in tick_regions.items():\n        ...         print(\"    tick\", tick, \"=\", sensitivity)\n        target D1\n            tick 5 = +____________________X______________________\n            tick 6 = +____________________Z______________________\n        target D5\n            tick 5 = +______X____________________________________\n            tick 6 = +______Z____________________________________\n        target D14\n            tick 5 = +__________X_X______XXX_____________________\n            tick 6 = +__________X_X______XZX_____________________\n            tick 7 = +__________X_X______XZX_____________________\n            tick 8 = +__________X_X______XXX_____________________\n            tick 9 = +__________XXX_____XXX______________________\n            tick 10 = +__________XXX_______X______________________\n            tick 11 = +__________X_________X______________________\n            tick 12 = +____________________X______________________\n            tick 13 = +____________________Z______________________\n        target D29\n            tick 7 = +____________________Z______________________\n            tick 8 = +____________________X______________________\n            tick 9 = +____________________XX_____________________\n            tick 10 = +___________________XXX_______X_____________\n            tick 11 = +____________X______XXXX______X_____________\n            tick 12 = +__________X_X______XXX_____________________\n            tick 13 = +__________X_X______XZX_____________________\n            tick 14 = +__________X_X______XZX_____________________\n        target D44\n            tick 14 = +____________________Z______________________\n        target L0\n            tick 5 = +_X________X________X________X______________\n            tick 6 = +_X________X________X________X______________\n            tick 7 = +_X________X________X________X______________\n            tick 8 = +_X________X________X________X______________\n            tick 9 = +_X________X_______XX________X______________\n            tick 10 = +_X________X________X________X______________\n            tick 11 = +_X________XX_______X________XX_____________\n            tick 12 = +_X________X________X________X______________\n            tick 13 = +_X________X________X________X______________\n            tick 14 = +_X________X________X________X______________\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.detector_error_model\"></a>\n```python\n# stim.Circuit.detector_error_model\n\n# (in class stim.Circuit)\ndef detector_error_model(\n    self,\n    *,\n    decompose_errors: bool = False,\n    flatten_loops: bool = False,\n    allow_gauge_detectors: bool = False,\n    approximate_disjoint_errors: float = False,\n    ignore_decomposition_failures: bool = False,\n    block_decomposition_from_introducing_remnant_edges: bool = False,\n) -> stim.DetectorErrorModel:\n    \"\"\"Returns a stim.DetectorErrorModel describing the error processes in the circuit.\n\n    Args:\n        decompose_errors: Defaults to false. When set to true, the error analysis\n            attempts to decompose the components of composite error mechanisms (such\n            as depolarization errors) into simpler errors, and suggest this\n            decomposition via `stim.target_separator()` between the components. For\n            example, in an XZ surface code, single qubit depolarization has a Y\n            error term which can be decomposed into simpler X and Z error terms.\n            Decomposition fails (causing this method to throw) if it's not possible\n            to decompose large errors into simple errors that affect at most two\n            detectors.\n        flatten_loops: Defaults to false. When set to True, the output will not\n            contain any `repeat` blocks. When set to False, the error analysis\n            watches for loops in the circuit reaching a periodic steady state with\n            respect to the detectors being introduced, the error mechanisms that\n            affect them, and the locations of the logical observables. When it\n            identifies such a steady state, it outputs a repeat block. This is\n            massively more efficient than flattening for circuits that contain\n            loops, but creates a more complex output.\n        allow_gauge_detectors: Defaults to false. When set to false, the error\n            analysis verifies that detectors in the circuit are actually\n            deterministic under noiseless execution of the circuit. When set to\n            True, these detectors are instead considered to be part of degrees\n            freedom that can be removed from the error model. For example, if\n            detectors D1 and D3 both anti-commute with a reset, then the error model\n            has a gauge `error(0.5) D1 D3`. When gauges are identified, one of the\n            involved detectors is removed from the system using Gaussian\n            elimination.\n\n            Note that logical observables are still verified to be deterministic,\n            even if this option is set.\n        approximate_disjoint_errors: Defaults to false. When set to false, composite\n            error mechanisms with disjoint components (such as\n            `PAULI_CHANNEL_1(0.1, 0.2, 0.0)`) can cause the error analysis to throw\n            exceptions (because detector error models can only contain independent\n            error mechanisms). When set to true, the probabilities of the disjoint\n            cases are instead assumed to be independent probabilities. For example,\n            a `PAULI_CHANNEL_1(0.1, 0.2, 0.0)` becomes equivalent to an\n            `X_ERROR(0.1)` followed by a `Y_ERROR(0.2)`. This assumption is an\n            approximation, but it is a good approximation for small probabilities.\n\n            This argument can also be set to a probability between 0 and 1, setting\n            a threshold below which the approximation is acceptable. Any error\n            mechanisms that have a component probability above the threshold will\n            cause an exception to be thrown.\n        ignore_decomposition_failures: Defaults to False.\n            When this is set to True, circuit errors that fail to decompose into\n            graphlike detector error model errors no longer cause the conversion\n            process to abort. Instead, the undecomposed error is inserted into the\n            output. Whatever tool the detector error model is then given to is\n            responsible for dealing with the undecomposed errors (e.g. a tool may\n            choose to simply ignore them).\n\n            Irrelevant unless decompose_errors=True.\n        block_decomposition_from_introducing_remnant_edges: Defaults to False.\n            Requires that both A B and C D be present elsewhere in the detector\n            error model in order to decompose A B C D into A B ^ C D. Normally, only\n            one of A B or C D needs to appear to allow this decomposition.\n\n            Remnant edges can be a useful feature for ensuring decomposition\n            succeeds, but they can also reduce the effective code distance by giving\n            the decoder single edges that actually represent multiple errors in the\n            circuit (resulting in the decoder making misinformed choices when\n            decoding).\n\n            Irrelevant unless decompose_errors=True.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     X_ERROR(0.125) 0\n        ...     X_ERROR(0.25) 1\n        ...     CORRELATED_ERROR(0.375) X0 X1\n        ...     M 0 1\n        ...     DETECTOR rec[-2]\n        ...     DETECTOR rec[-1]\n        ... ''').detector_error_model()\n        stim.DetectorErrorModel('''\n            error(0.125) D0\n            error(0.375) D0 D1\n            error(0.25) D1\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.diagram\"></a>\n```python\n# stim.Circuit.diagram\n\n# (in class stim.Circuit)\ndef diagram(\n    self,\n    type: Literal[\"timeline-text\", \"timeline-svg\", \"timeline-svg-html\", \"timeline-3d\", \"timeline-3d-html\", \"detslice-text\", \"detslice-svg\", \"detslice-svg-html\", \"matchgraph-svg\", \"matchgraph-svg-html\", \"matchgraph-3d\", \"matchgraph-3d-html\", \"timeslice-svg\", \"timeslice-svg-html\", \"detslice-with-ops-svg\", \"detslice-with-ops-svg-html\", \"interactive\", \"interactive-html\"] = 'timeline-text',\n    *,\n    tick: Union[None, int, range] = None,\n    filter_coords: Iterable[Union[Iterable[float], stim.DemTarget]] = ((),),\n    rows: int | None = None,\n) -> 'stim._DiagramHelper':\n    \"\"\"Returns a diagram of the circuit, from a variety of options.\n\n    Args:\n        type: The type of diagram. Available types are:\n            \"timeline-text\" (default): An ASCII diagram of the\n                operations applied by the circuit over time. Includes\n                annotations showing the measurement record index that\n                each measurement writes to, and the measurements used\n                by detectors.\n            \"timeline-svg\": An SVG image of the operations applied by\n                the circuit over time. Includes annotations showing the\n                measurement record index that each measurement writes\n                to, and the measurements used by detectors.\n            \"timeline-svg-html\": A resizable SVG image viewer of the\n                operations applied by the circuit over time. Includes\n                annotations showing the measurement record index that\n                each measurement writes to, and the measurements used\n                by detectors.\n            \"timeline-3d\": A 3d model, in GLTF format, of the operations\n                applied by the circuit over time.\n            \"timeline-3d-html\": Same 3d model as 'timeline-3d' but\n                embedded into an HTML web page containing an interactive\n                THREE.js viewer for the 3d model.\n            \"detslice-text\": An ASCII diagram of the stabilizers\n                that detectors declared by the circuit correspond to\n                during the TICK instruction identified by the `tick`\n                argument.\n            \"detslice-svg\": An SVG image of the stabilizers\n                that detectors declared by the circuit correspond to\n                during the TICK instruction identified by the `tick`\n                argument. For example, a detector slice diagram of a\n                CSS surface code circuit during the TICK between a\n                measurement layer and a reset layer will produce the\n                usual diagram of a surface code.\n\n                Uses the Pauli color convention XYZ=RGB.\n            \"detslice-svg-html\": Same as detslice-svg but the SVG image\n                is inside a resizable HTML iframe.\n            \"matchgraph-svg\": An SVG image of the match graph extracted\n                from the circuit by stim.Circuit.detector_error_model.\n            \"matchgraph-svg-html\": Same as matchgraph-svg but the SVG image\n                is inside a resizable HTML iframe.\n            \"matchgraph-3d\": An 3D model of the match graph extracted\n                from the circuit by stim.Circuit.detector_error_model.\n            \"matchgraph-3d-html\": Same 3d model as 'match-graph-3d' but\n                embedded into an HTML web page containing an interactive\n                THREE.js viewer for the 3d model.\n            \"timeslice-svg\": An SVG image of the operations applied\n                between two TICK instructions in the circuit, with the\n                operations laid out in 2d.\n            \"timeslice-svg-html\": Same as timeslice-svg but the SVG image\n                is inside a resizable HTML iframe.\n            \"detslice-with-ops-svg\": A combination of timeslice-svg\n                and detslice-svg, with the operations overlaid\n                over the detector slices taken from the TICK after the\n                operations were applied.\n            \"detslice-with-ops-svg-html\": Same as detslice-with-ops-svg\n                but the SVG image is inside a resizable HTML iframe.\n            \"interactive\" or \"interactive-html\": An HTML web page\n                containing Crumble (an interactive editor for 2D\n                stabilizer circuits) initialized with the given circuit\n                as its default contents.\n        tick: Required for detector and time slice diagrams. Specifies\n            which TICK instruction, or range of TICK instructions, to\n            slice at. Note that the first TICK instruction in the\n            circuit corresponds tick=1. The value tick=0 refers to the\n            very start of the circuit.\n\n            Passing `range(A, B)` for a detector slice will show the\n            slices for ticks A through B including A but excluding B.\n\n            Passing `range(A, B)` for a time slice will show the\n            operations between tick A and tick B.\n        rows: In diagrams that have multiple separate pieces, such as timeslice\n            diagrams and detslice diagrams, this controls how many rows of\n            pieces there will be. If not specified, a number of rows that creates\n            a roughly square layout will be chosen.\n        filter_coords: A list of things to include in the diagram. Different\n            effects depending on the diagram.\n\n            For detslice diagrams, the filter defaults to showing all detectors\n            and no observables. When specified, each list entry can be a collection\n            of floats (detectors whose coordinates start with the same numbers will\n            be included), a stim.DemTarget (specifying a detector or observable\n            to include), a string like \"D5\" or \"L0\" specifying a detector or\n            observable to include.\n\n    Returns:\n        An object whose `__str__` method returns the diagram, so that\n        writing the diagram to a file works correctly. The returned\n        object may also define methods such as `_repr_html_`, so that\n        ipython notebooks recognize it can be shown using a specialized\n        viewer instead of as raw text.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     CNOT 0 1 1 2\n        ... ''')\n\n        >>> print(circuit.diagram())\n        q0: -H-@---\n               |\n        q1: ---X-@-\n                 |\n        q2: -----X-\n\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     CNOT 0 1\n        ...     TICK\n        ...     M 0 1\n        ...     DETECTOR rec[-1] rec[-2]\n        ... ''')\n\n        >>> print(circuit.diagram(\"detslice-text\", tick=1))\n        q0: -Z:D0-\n             |\n        q1: -Z:D0-\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.explain_detector_error_model_errors\"></a>\n```python\n# stim.Circuit.explain_detector_error_model_errors\n\n# (in class stim.Circuit)\ndef explain_detector_error_model_errors(\n    self,\n    *,\n    dem_filter: object = None,\n    reduce_to_one_representative_error: bool = False,\n) -> List[stim.ExplainedError]:\n    \"\"\"Explains how detector error model errors are produced by circuit errors.\n\n    Args:\n        dem_filter: Defaults to None (unused). When used, the output will only\n            contain detector error model errors that appear in the given\n            `stim.DetectorErrorModel`. Any error mechanisms from the detector error\n            model that can't be reproduced using one error from the circuit will\n            also be included in the result, but with an empty list of associated\n            circuit error mechanisms.\n        reduce_to_one_representative_error: Defaults to False. When True, the items\n            in the result will contain at most one circuit error mechanism.\n\n    Returns:\n        A `List[stim.ExplainedError]` (see `stim.ExplainedError` for more\n        information). Each item in the list describes how a detector error model\n        error can be produced by individual circuit errors.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     # Create Bell pair.\n        ...     H 0\n        ...     CNOT 0 1\n        ...\n        ...     # Noise.\n        ...     DEPOLARIZE1(0.01) 0\n        ...\n        ...     # Bell basis measurement.\n        ...     CNOT 0 1\n        ...     H 0\n        ...     M 0 1\n        ...\n        ...     # Both measurements should be False under noiseless execution.\n        ...     DETECTOR rec[-1]\n        ...     DETECTOR rec[-2]\n        ... ''')\n        >>> explained_errors = circuit.explain_detector_error_model_errors(\n        ...     dem_filter=stim.DetectorErrorModel('error(1) D0 D1'),\n        ...     reduce_to_one_representative_error=True,\n        ... )\n        >>> print(explained_errors[0].circuit_error_locations[0])\n        CircuitErrorLocation {\n            flipped_pauli_product: Y0\n            Circuit location stack trace:\n                (after 0 TICKs)\n                at instruction #3 (DEPOLARIZE1) in the circuit\n                at target #1 of the instruction\n                resolving to DEPOLARIZE1(0.01) 0\n        }\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.flattened\"></a>\n```python\n# stim.Circuit.flattened\n\n# (in class stim.Circuit)\ndef flattened(\n    self,\n) -> stim.Circuit:\n    \"\"\"Creates an equivalent circuit without REPEAT or SHIFT_COORDS.\n\n    Returns:\n        A `stim.Circuit` with the same instructions in the same order,\n        but with loops flattened into repeated instructions and with\n        all coordinate shifts inlined.\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...     REPEAT 5 {\n        ...         MR 0 1\n        ...         DETECTOR(0, 0) rec[-2]\n        ...         DETECTOR(1, 0) rec[-1]\n        ...         SHIFT_COORDS(0, 1)\n        ...     }\n        ... ''').flattened()\n        stim.Circuit('''\n            MR 0 1\n            DETECTOR(0, 0) rec[-2]\n            DETECTOR(1, 0) rec[-1]\n            MR 0 1\n            DETECTOR(0, 1) rec[-2]\n            DETECTOR(1, 1) rec[-1]\n            MR 0 1\n            DETECTOR(0, 2) rec[-2]\n            DETECTOR(1, 2) rec[-1]\n            MR 0 1\n            DETECTOR(0, 3) rec[-2]\n            DETECTOR(1, 3) rec[-1]\n            MR 0 1\n            DETECTOR(0, 4) rec[-2]\n            DETECTOR(1, 4) rec[-1]\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.flow_generators\"></a>\n```python\n# stim.Circuit.flow_generators\n\n# (in class stim.Circuit)\ndef flow_generators(\n    self,\n) -> List[stim.Flow]:\n    \"\"\"Returns a list of flows that generate all of the circuit's flows.\n\n    Every stabilizer flow that the circuit implements is a product of some\n    subset of the returned generators. Every returned flow will be a flow\n    of the circuit.\n\n    Returns:\n        A list of flow generators for the circuit.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit(\"H 0\").flow_generators()\n        [stim.Flow(\"X -> Z\"), stim.Flow(\"Z -> X\")]\n\n        >>> stim.Circuit(\"M 0\").flow_generators()\n        [stim.Flow(\"1 -> Z xor rec[0]\"), stim.Flow(\"Z -> rec[0]\")]\n\n        >>> stim.Circuit(\"RX 0\").flow_generators()\n        [stim.Flow(\"1 -> X\")]\n\n        >>> for flow in stim.Circuit(\"MXX 0 1\").flow_generators():\n        ...     print(flow)\n        1 -> XX xor rec[0]\n        _X -> _X\n        X_ -> _X xor rec[0]\n        ZZ -> ZZ\n\n        >>> for flow in stim.Circuit.generated(\n        ...     \"repetition_code:memory\",\n        ...     rounds=2,\n        ...     distance=3,\n        ...     after_clifford_depolarization=1e-3,\n        ... ).flow_generators():\n        ...     print(flow)\n        1 -> rec[0]\n        1 -> rec[1]\n        1 -> rec[2]\n        1 -> rec[3]\n        1 -> rec[4]\n        1 -> rec[5]\n        1 -> rec[6]\n        1 -> ____Z\n        1 -> ___Z_\n        1 -> __Z__\n        1 -> _Z___\n        1 -> Z____\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.from_file\"></a>\n```python\n# stim.Circuit.from_file\n\n# (in class stim.Circuit)\n@staticmethod\ndef from_file(\n    file: Union[io.TextIOBase, str, pathlib.Path],\n) -> stim.Circuit:\n    \"\"\"Reads a stim circuit from a file.\n\n    The file format is defined at\n    https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n    Args:\n        file: A file path or open file object to read from.\n\n    Returns:\n        The circuit parsed from the file.\n\n    Examples:\n        >>> import stim\n        >>> import tempfile\n\n        >>> with tempfile.TemporaryDirectory() as tmpdir:\n        ...     path = tmpdir + '/tmp.stim'\n        ...     with open(path, 'w') as f:\n        ...         print('H 5', file=f)\n        ...     circuit = stim.Circuit.from_file(path)\n        >>> circuit\n        stim.Circuit('''\n            H 5\n        ''')\n\n        >>> with tempfile.TemporaryDirectory() as tmpdir:\n        ...     path = tmpdir + '/tmp.stim'\n        ...     with open(path, 'w') as f:\n        ...         print('CNOT 4 5', file=f)\n        ...     with open(path) as f:\n        ...         circuit = stim.Circuit.from_file(f)\n        >>> circuit\n        stim.Circuit('''\n            CX 4 5\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.generated\"></a>\n```python\n# stim.Circuit.generated\n\n# (in class stim.Circuit)\n@staticmethod\ndef generated(\n    code_task: str,\n    *,\n    distance: int,\n    rounds: int,\n    after_clifford_depolarization: float = 0.0,\n    before_round_data_depolarization: float = 0.0,\n    before_measure_flip_probability: float = 0.0,\n    after_reset_flip_probability: float = 0.0,\n) -> stim.Circuit:\n    \"\"\"Generates common circuits.\n\n    The generated circuits can include configurable noise.\n\n    The generated circuits include DETECTOR and OBSERVABLE_INCLUDE annotations so\n    that their detection events and logical observables can be sampled.\n\n    The generated circuits include TICK annotations to mark the progression of time.\n    (E.g. so that converting them using `stimcirq.stim_circuit_to_cirq_circuit` will\n    produce a `cirq.Circuit` with the intended moment structure.)\n\n    Args:\n        code_task: A string identifying the type of circuit to generate. Available\n            code tasks are:\n                - \"repetition_code:memory\"\n                - \"surface_code:rotated_memory_x\"\n                - \"surface_code:rotated_memory_z\"\n                - \"surface_code:unrotated_memory_x\"\n                - \"surface_code:unrotated_memory_z\"\n                - \"color_code:memory_xyz\"\n        distance: The desired code distance of the generated circuit. The code\n            distance is the minimum number of physical errors needed to cause a\n            logical error. This parameter indirectly determines how many qubits the\n            generated circuit uses.\n        rounds: How many times the measurement qubits in the generated circuit will\n            be measured. Indirectly determines the duration of the generated\n            circuit.\n        after_clifford_depolarization: Defaults to 0. The probability (p) of\n            `DEPOLARIZE1(p)` operations to add after every single-qubit Clifford\n            operation and `DEPOLARIZE2(p)` operations to add after every two-qubit\n            Clifford operation. The after-Clifford depolarizing operations are only\n            included if this probability is not 0.\n        before_round_data_depolarization: Defaults to 0. The probability (p) of\n            `DEPOLARIZE1(p)` operations to apply to every data qubit at the start of\n            a round of stabilizer measurements. The start-of-round depolarizing\n            operations are only included if this probability is not 0.\n        before_measure_flip_probability: Defaults to 0. The probability (p) of\n            `X_ERROR(p)` operations applied to qubits before each measurement (X\n            basis measurements use `Z_ERROR(p)` instead). The before-measurement\n            flips are only included if this probability is not 0.\n        after_reset_flip_probability: Defaults to 0. The probability (p) of\n            `X_ERROR(p)` operations applied to qubits after each reset (X basis\n            resets use `Z_ERROR(p)` instead). The after-reset flips are only\n            included if this probability is not 0.\n\n    Returns:\n        The generated circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit.generated(\n        ...     \"repetition_code:memory\",\n        ...     distance=4,\n        ...     rounds=10000,\n        ...     after_clifford_depolarization=0.0125)\n        >>> print(circuit)\n        R 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        DEPOLARIZE2(0.0125) 0 1 2 3 4 5\n        TICK\n        CX 2 1 4 3 6 5\n        DEPOLARIZE2(0.0125) 2 1 4 3 6 5\n        TICK\n        MR 1 3 5\n        DETECTOR(1, 0) rec[-3]\n        DETECTOR(3, 0) rec[-2]\n        DETECTOR(5, 0) rec[-1]\n        REPEAT 9999 {\n            TICK\n            CX 0 1 2 3 4 5\n            DEPOLARIZE2(0.0125) 0 1 2 3 4 5\n            TICK\n            CX 2 1 4 3 6 5\n            DEPOLARIZE2(0.0125) 2 1 4 3 6 5\n            TICK\n            MR 1 3 5\n            SHIFT_COORDS(0, 1)\n            DETECTOR(1, 0) rec[-3] rec[-6]\n            DETECTOR(3, 0) rec[-2] rec[-5]\n            DETECTOR(5, 0) rec[-1] rec[-4]\n        }\n        M 0 2 4 6\n        DETECTOR(1, 1) rec[-3] rec[-4] rec[-7]\n        DETECTOR(3, 1) rec[-2] rec[-3] rec[-6]\n        DETECTOR(5, 1) rec[-1] rec[-2] rec[-5]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.get_detector_coordinates\"></a>\n```python\n# stim.Circuit.get_detector_coordinates\n\n# (in class stim.Circuit)\ndef get_detector_coordinates(\n    self,\n    only: object = None,\n) -> Dict[int, List[float]]:\n    \"\"\"Returns the coordinate metadata of detectors in the circuit.\n\n    Args:\n        only: Defaults to None (meaning include all detectors). A list of detector\n            indices to include in the result. Detector indices beyond the end of the\n            detector error model of the circuit cause an error.\n\n    Returns:\n        A dictionary mapping integers (detector indices) to lists of floats\n        (coordinates).\n\n        Detectors with no specified coordinate data are mapped to an empty tuple.\n        If `only` is specified, then `set(result.keys()) == set(only)`.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...    M 0\n        ...    DETECTOR rec[-1]\n        ...    DETECTOR(1, 2, 3) rec[-1]\n        ...    REPEAT 3 {\n        ...        DETECTOR(42) rec[-1]\n        ...        SHIFT_COORDS(100)\n        ...    }\n        ... ''')\n        >>> circuit.get_detector_coordinates()\n        {0: [], 1: [1.0, 2.0, 3.0], 2: [42.0], 3: [142.0], 4: [242.0]}\n        >>> circuit.get_detector_coordinates(only=[1])\n        {1: [1.0, 2.0, 3.0]}\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.get_final_qubit_coordinates\"></a>\n```python\n# stim.Circuit.get_final_qubit_coordinates\n\n# (in class stim.Circuit)\ndef get_final_qubit_coordinates(\n    self,\n) -> Dict[int, List[float]]:\n    \"\"\"Returns the coordinate metadata of qubits in the circuit.\n\n    If a qubit's coordinates are specified multiple times, only the last specified\n    coordinates are returned.\n\n    Returns:\n        A dictionary mapping qubit indices (integers) to coordinates (lists of\n        floats). Qubits that never had their coordinates specified are not included\n        in the result.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...    QUBIT_COORDS(1, 2, 3) 1\n        ... ''')\n        >>> circuit.get_final_qubit_coordinates()\n        {1: [1.0, 2.0, 3.0]}\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.has_all_flows\"></a>\n```python\n# stim.Circuit.has_all_flows\n\n# (in class stim.Circuit)\ndef has_all_flows(\n    self,\n    flows: Iterable[stim.Flow],\n    *,\n    unsigned: bool = False,\n) -> bool:\n    \"\"\"Determines if the circuit has all the given stabilizer flow or not.\n\n    This is a faster version of `all(c.has_flow(f) for f in flows)`. It's faster\n    because, behind the scenes, the circuit can be iterated once instead of once\n    per flow.\n\n    This method ignores any noise in the circuit.\n\n    Args:\n        flows: An iterable of `stim.Flow` instances representing the flows to check.\n        unsigned: Defaults to False. When False, the flows must be correct including\n            the sign of the Pauli strings. When True, only the Pauli terms need to\n            be correct; the signs are permitted to be inverted. In effect, this\n            requires the circuit to be correct up to Pauli gates.\n\n    Returns:\n        True if the circuit has the given flow; False otherwise.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('H 0').has_all_flows([\n        ...     stim.Flow('X -> Z'),\n        ...     stim.Flow('Y -> Y'),\n        ...     stim.Flow('Z -> X'),\n        ... ])\n        False\n\n        >>> stim.Circuit('H 0').has_all_flows([\n        ...     stim.Flow('X -> Z'),\n        ...     stim.Flow('Y -> -Y'),\n        ...     stim.Flow('Z -> X'),\n        ... ])\n        True\n\n        >>> stim.Circuit('H 0').has_all_flows([\n        ...     stim.Flow('X -> Z'),\n        ...     stim.Flow('Y -> Y'),\n        ...     stim.Flow('Z -> X'),\n        ... ], unsigned=True)\n        True\n\n    Caveats:\n        Currently, the unsigned=False version of this method is implemented by\n        performing 256 randomized tests. Each test has a 50% chance of a false\n        positive, and a 0% chance of a false negative. So, when the method returns\n        True, there is technically still a 2^-256 chance the circuit doesn't have\n        the flow. This is lower than the chance of a cosmic ray flipping the result.\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.has_flow\"></a>\n```python\n# stim.Circuit.has_flow\n\n# (in class stim.Circuit)\ndef has_flow(\n    self,\n    flow: stim.Flow,\n    *,\n    unsigned: bool = False,\n) -> bool:\n    \"\"\"Determines if the circuit has the given stabilizer flow or not.\n\n    A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer\n    P at the start of the circuit to the instantaneous stabilizer Q at the end of\n    the circuit. The flow may be mediated by certain measurements. For example,\n    a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and\n    the CNOT flows implemented by the circuit involve these measurements.\n\n    A flow like P -> Q means the circuit transforms P into Q.\n    A flow like 1 -> P means the circuit prepares P.\n    A flow like P -> 1 means the circuit measures P.\n    A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR).\n\n    This method ignores any noise in the circuit.\n\n    Args:\n        flow: The flow to check for.\n        unsigned: Defaults to False. When False, the flows must be correct including\n            the sign of the Pauli strings. When True, only the Pauli terms need to\n            be correct; the signs are permitted to be inverted. In effect, this\n            requires the circuit to be correct up to Pauli gates.\n\n    Returns:\n        True if the circuit has the given flow; False otherwise.\n\n    Examples:\n        >>> import stim\n\n        >>> m = stim.Circuit('M 0')\n        >>> m.has_flow(stim.Flow('Z -> Z'))\n        True\n        >>> m.has_flow(stim.Flow('X -> X'))\n        False\n        >>> m.has_flow(stim.Flow('Z -> I'))\n        False\n        >>> m.has_flow(stim.Flow('Z -> I xor rec[-1]'))\n        True\n        >>> m.has_flow(stim.Flow('Z -> rec[-1]'))\n        True\n\n        >>> cx58 = stim.Circuit('CX 5 8')\n        >>> cx58.has_flow(stim.Flow('X5 -> X5*X8'))\n        True\n        >>> cx58.has_flow(stim.Flow('X_ -> XX'))\n        False\n        >>> cx58.has_flow(stim.Flow('_____X___ -> _____X__X'))\n        True\n\n        >>> stim.Circuit('''\n        ...     RY 0\n        ... ''').has_flow(stim.Flow(\n        ...     output=stim.PauliString(\"Y\"),\n        ... ))\n        True\n\n        >>> stim.Circuit('''\n        ...     RY 0\n        ...     X_ERROR(0.1) 0\n        ... ''').has_flow(stim.Flow(\n        ...     output=stim.PauliString(\"Y\"),\n        ... ))\n        True\n\n        >>> stim.Circuit('''\n        ...     RY 0\n        ... ''').has_flow(stim.Flow(\n        ...     output=stim.PauliString(\"X\"),\n        ... ))\n        False\n\n        >>> stim.Circuit('''\n        ...     CX 0 1\n        ... ''').has_flow(stim.Flow(\n        ...     input=stim.PauliString(\"+X_\"),\n        ...     output=stim.PauliString(\"+XX\"),\n        ... ))\n        True\n\n        >>> stim.Circuit('''\n        ...     # Lattice surgery CNOT\n        ...     R 1\n        ...     MXX 0 1\n        ...     MZZ 1 2\n        ...     MX 1\n        ... ''').has_flow(stim.Flow(\n        ...     input=stim.PauliString(\"+X_X\"),\n        ...     output=stim.PauliString(\"+__X\"),\n        ...     measurements=[0, 2],\n        ... ))\n        True\n\n        >>> stim.Circuit('''\n        ...     H 0\n        ... ''').has_flow(\n        ...     stim.Flow(\"Y -> Y\"),\n        ...     unsigned=True,\n        ... )\n        True\n\n        >>> stim.Circuit('''\n        ...     H 0\n        ... ''').has_flow(\n        ...     stim.Flow(\"Y -> Y\"),\n        ...     unsigned=False,\n        ... )\n        False\n\n    Caveats:\n        Currently, the unsigned=False version of this method is implemented by\n        performing 256 randomized tests. Each test has a 50% chance of a false\n        positive, and a 0% chance of a false negative. So, when the method returns\n        True, there is technically still a 2^-256 chance the circuit doesn't have\n        the flow. This is lower than the chance of a cosmic ray flipping the result.\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.insert\"></a>\n```python\n# stim.Circuit.insert\n\n# (in class stim.Circuit)\ndef insert(\n    self,\n    index: int,\n    operation: Union[stim.CircuitInstruction, stim.Circuit],\n) -> None:\n    \"\"\"Inserts an operation at the given index, pushing existing operations forward.\n\n    Beware that inserted operations are automatically fused with the preceding\n    and following operations, if possible. This can make it complex to reason\n    about how the indices of operations change in response to insertions.\n\n    Args:\n        index: The index to insert at.\n\n            Must satisfy -len(circuit) <= index < len(circuit). Negative indices\n            are made non-negative by adding len(circuit) to them, so they refer to\n            indices relative to the end of the circuit instead of the start.\n\n            Instructions before the index are not shifted. Instructions that\n            were at or after the index are shifted forwards as needed.\n        operation: The object to insert. This can be a single\n            stim.CircuitInstruction or an entire stim.Circuit.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...     H 0\n        ...     S 1\n        ...     X 2\n        ... ''')\n        >>> c.insert(1, stim.CircuitInstruction(\"Y\", [3, 4, 5]))\n        >>> c\n        stim.Circuit('''\n            H 0\n            Y 3 4 5\n            S 1\n            X 2\n        ''')\n        >>> c.insert(-1, stim.Circuit(\"S 999\\nCX 0 1\\nCZ 2 3\"))\n        >>> c\n        stim.Circuit('''\n            H 0\n            Y 3 4 5\n            S 1 999\n            CX 0 1\n            CZ 2 3\n            X 2\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.inverse\"></a>\n```python\n# stim.Circuit.inverse\n\n# (in class stim.Circuit)\ndef inverse(\n    self,\n) -> stim.Circuit:\n    \"\"\"Returns a circuit that applies the same operations but inverted and in reverse.\n\n    If circuit starts with QUBIT_COORDS instructions, the returned circuit will\n    still have the same QUBIT_COORDS instructions in the same order at the start.\n\n    Returns:\n        A `stim.Circuit` that applies inverted operations in the reverse order.\n\n    Raises:\n        ValueError: The circuit contains operations that don't have an inverse,\n            such as measurements. There are also some unsupported operations\n            such as SHIFT_COORDS.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     S 0 1\n        ...     ISWAP 0 1 1 2\n        ... ''').inverse()\n        stim.Circuit('''\n            ISWAP_DAG 1 2 0 1\n            S_DAG 1 0\n        ''')\n\n        >>> stim.Circuit('''\n        ...     QUBIT_COORDS(1, 2) 0\n        ...     QUBIT_COORDS(4, 3) 1\n        ...     QUBIT_COORDS(9, 5) 2\n        ...     H 0 1\n        ...     REPEAT 100 {\n        ...         CX 0 1 1 2\n        ...         TICK\n        ...         S 1 2\n        ...     }\n        ... ''').inverse()\n        stim.Circuit('''\n            QUBIT_COORDS(1, 2) 0\n            QUBIT_COORDS(4, 3) 1\n            QUBIT_COORDS(9, 5) 2\n            REPEAT 100 {\n                S_DAG 2 1\n                TICK\n                CX 1 2 0 1\n            }\n            H 1 0\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.likeliest_error_sat_problem\"></a>\n```python\n# stim.Circuit.likeliest_error_sat_problem\n\n# (in class stim.Circuit)\ndef likeliest_error_sat_problem(\n    self,\n    *,\n    quantization: int = 100,\n    format: str = 'WDIMACS',\n) -> str:\n    \"\"\"Makes a maxSAT problem for the circuit's likeliest undetectable logical error.\n\n    The output is a string describing the maxSAT problem in WDIMACS format\n    (see https://jix.github.io/varisat/manual/0.2.0/formats/dimacs.html). The\n    optimal solution to the problem is the highest likelihood set of error\n    mechanisms that combine to flip any logical observable while producing no\n    detection events).\n\n    If there are any errors with probability p > 0.5, they are inverted so\n    that the resulting weight ends up being positive. If there are errors\n    with weight close or equal to 0.5, they can end up with 0 weight meaning\n    that they can be included or not in the solution with no affect on the\n    likelihood.\n\n    There are many tools that can solve maxSAT problems in WDIMACS format.\n    One quick way to get started is to install pysat by running this BASH\n    terminal command:\n\n        pip install python-sat\n\n    Afterwards, you can run the included maxSAT solver \"RC2\" with this\n    Python code:\n\n        from pysat.examples.rc2 import RC2\n        from pysat.formula import WCNF\n\n        wcnf = WCNF(from_string=\"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\")\n\n        with RC2(wcnf) as rc2:\n        print(rc2.compute())\n        print(rc2.cost)\n\n    Much faster solvers are available online. For example, you can download\n    one of the entries in the 2023 maxSAT competition (see\n    https://maxsat-evaluations.github.io/2023) and run it on your problem by\n    running these BASH terminal commands:\n\n        wget https://maxsat-evaluations.github.io/2023/mse23-solver-src/exact/CASHWMaxSAT-CorePlus.zip\n        unzip CASHWMaxSAT-CorePlus.zip\n        ./CASHWMaxSAT-CorePlus/bin/cashwmaxsatcoreplus -bm -m your_problem.wcnf\n\n    Args:\n        format: Defaults to \"WDIMACS\", corresponding to WDIMACS format which is\n            described here: http://www.maxhs.org/docs/wdimacs.html\n        quantization: Defaults to 10. Error probabilities are converted to log-odds\n            and scaled/rounded to be positive integers at most this large. Setting\n            this argument to a larger number results in more accurate quantization\n            such that the returned error set should have a likelihood closer to the\n            true most likely solution. This comes at the cost of making some maxSAT\n            solvers slower.\n\n    Returns:\n        A string corresponding to the contents of a maxSAT problem file in the\n        requested format.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...   X_ERROR(0.1) 0\n        ...   M 0\n        ...   OBSERVABLE_INCLUDE(0) rec[-1]\n        ...   X_ERROR(0.4) 0\n        ...   M 0\n        ...   DETECTOR rec[-1] rec[-2]\n        ... ''')\n        >>> print(circuit.likeliest_error_sat_problem(\n        ...   quantization=1000\n        ... ), end='')\n        p wcnf 2 4 4001\n        185 -1 0\n        1000 -2 0\n        4001 -1 0\n        4001 2 0\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.missing_detectors\"></a>\n```python\n# stim.Circuit.missing_detectors\n\n# (in class stim.Circuit)\ndef missing_detectors(\n    self,\n    *,\n    unknown_input: bool = False,\n) -> int:\n    \"\"\"Finds deterministic measurements independent of declared detectors/observables.\n\n    This method is useful for debugging missing detectors in a circuit, because it\n    identifies generators for uncovered degrees of freedom.\n\n    It's not recommended to use this method to solve for the detectors of a circuit.\n    The returned detectors are not guaranteed to be stable across versions, and\n    aren't optimized to be \"good\" (e.g. form a low weight basis or be matchable\n    if possible). It will also identify things that are technically determined\n    but that the user may not want to use as a detector, such as the fact that\n    in the first round after transversal Z basis initialization of a toric code\n    the product of all X stabilizer measurements is deterministic even though the\n    individual measurements are all random.\n\n    Args:\n        unknown_input: Defaults to False (inputs assumed to be in the |0> state).\n            When set to True, the inputs are instead treated as being in unknown\n            random states. For example, this means that Z-basis measurements at\n            the very beginning of the circuit will be considered random rather\n            than determined.\n\n    Returns:\n        A circuit containing DETECTOR instructions that specify the uncovered\n        degrees of freedom in the deterministic measurement sets of the input\n        circuit. The returned circuit can be appended to the input circuit to\n        get a circuit with no missing detectors.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     R 0\n        ...     M 0\n        ... ''').missing_detectors()\n        stim.Circuit('''\n            DETECTOR rec[-1]\n        ''')\n\n        >>> stim.Circuit('''\n        ...     MZZ 0 1\n        ...     MYY 0 1\n        ...     MXX 0 1\n        ...     DEPOLARIZE1(0.1) 0 1\n        ...     MZZ 0 1\n        ...     MYY 0 1\n        ...     MXX 0 1\n        ...     DETECTOR rec[-1] rec[-4]\n        ...     DETECTOR rec[-2] rec[-5]\n        ...     DETECTOR rec[-3] rec[-6]\n        ... ''').missing_detectors(unknown_input=True)\n        stim.Circuit('''\n            DETECTOR rec[-3] rec[-2] rec[-1]\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.num_detectors\"></a>\n```python\n# stim.Circuit.num_detectors\n\n# (in class stim.Circuit)\n@property\ndef num_detectors(\n    self,\n) -> int:\n    \"\"\"Counts the number of bits produced when sampling the circuit's detectors.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    M 0\n        ...    DETECTOR rec[-1]\n        ...    REPEAT 100 {\n        ...        M 0 1 2\n        ...        DETECTOR rec[-1]\n        ...        DETECTOR rec[-2]\n        ...    }\n        ... ''')\n        >>> c.num_detectors\n        201\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.num_measurements\"></a>\n```python\n# stim.Circuit.num_measurements\n\n# (in class stim.Circuit)\n@property\ndef num_measurements(\n    self,\n) -> int:\n    \"\"\"Counts the number of bits produced when sampling the circuit's measurements.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    M 0\n        ...    REPEAT 100 {\n        ...        M 0 1\n        ...    }\n        ... ''')\n        >>> c.num_measurements\n        201\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.num_observables\"></a>\n```python\n# stim.Circuit.num_observables\n\n# (in class stim.Circuit)\n@property\ndef num_observables(\n    self,\n) -> int:\n    \"\"\"Counts the number of logical observables defined by the circuit.\n\n    This is one more than the largest index that appears as an argument to an\n    OBSERVABLE_INCLUDE instruction.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    M 0\n        ...    OBSERVABLE_INCLUDE(2) rec[-1]\n        ...    OBSERVABLE_INCLUDE(5) rec[-1]\n        ... ''')\n        >>> c.num_observables\n        6\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.num_qubits\"></a>\n```python\n# stim.Circuit.num_qubits\n\n# (in class stim.Circuit)\n@property\ndef num_qubits(\n    self,\n) -> int:\n    \"\"\"Counts the number of qubits used when simulating the circuit.\n\n    This is always one more than the largest qubit index used by the circuit.\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...    X 0\n        ...    M 0 1\n        ... ''').num_qubits\n        2\n        >>> stim.Circuit('''\n        ...    X 0\n        ...    M 0 1\n        ...    H 100\n        ... ''').num_qubits\n        101\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.num_sweep_bits\"></a>\n```python\n# stim.Circuit.num_sweep_bits\n\n# (in class stim.Circuit)\n@property\ndef num_sweep_bits(\n    self,\n) -> int:\n    \"\"\"Returns the number of sweep bits needed to completely configure the circuit.\n\n    This is always one more than the largest sweep bit index used by the circuit.\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...    CX sweep[2] 0\n        ... ''').num_sweep_bits\n        3\n        >>> stim.Circuit('''\n        ...    CZ sweep[5] 0\n        ...    CX sweep[2] 0\n        ... ''').num_sweep_bits\n        6\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.num_ticks\"></a>\n```python\n# stim.Circuit.num_ticks\n\n# (in class stim.Circuit)\n@property\ndef num_ticks(\n    self,\n) -> int:\n    \"\"\"Counts the number of TICK instructions executed when running the circuit.\n\n    TICKs in loops are counted once per iteration.\n\n    Returns:\n        The number of ticks executed by the circuit.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit().num_ticks\n        0\n\n        >>> stim.Circuit('''\n        ...    TICK\n        ... ''').num_ticks\n        1\n\n        >>> stim.Circuit('''\n        ...    H 0\n        ...    TICK\n        ...    CX 0 1\n        ...    TICK\n        ... ''').num_ticks\n        2\n\n        >>> stim.Circuit('''\n        ...    H 0\n        ...    TICK\n        ...    REPEAT 100 {\n        ...        CX 0 1\n        ...        TICK\n        ...    }\n        ... ''').num_ticks\n        101\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.pop\"></a>\n```python\n# stim.Circuit.pop\n\n# (in class stim.Circuit)\ndef pop(\n    self,\n    index: int = -1,\n) -> Union[stim.CircuitInstruction, stim.CircuitRepeatBlock]:\n    \"\"\"Pops an operation from the end of the circuit, or at the given index.\n\n    Args:\n        index: Defaults to -1 (end of circuit). The index to pop from.\n\n    Returns:\n        The popped instruction.\n\n    Raises:\n        IndexError: The given index is outside the bounds of the circuit.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...     H 0\n        ...     S 1\n        ...     X 2\n        ...     Y 3\n        ... ''')\n        >>> c.pop()\n        stim.CircuitInstruction('Y', [stim.GateTarget(3)], [])\n        >>> c.pop(1)\n        stim.CircuitInstruction('S', [stim.GateTarget(1)], [])\n        >>> c\n        stim.Circuit('''\n            H 0\n            X 2\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.reference_detector_and_observable_signs\"></a>\n```python\n# stim.Circuit.reference_detector_and_observable_signs\n\n# (in class stim.Circuit)\ndef reference_detector_and_observable_signs(\n    self,\n    *,\n    bit_packed: bool = False,\n) -> Tuple[np.ndarray, np.ndarray]:\n    \"\"\"Determines noiseless parities of the measurement sets of detectors/observables.\n\n    BEWARE: the returned values are NOT the \"expected value of the\n    detector/observable\". Stim consistently defines the value of a\n    detector/observable as whether or not it flipped, so the expected value of a\n    detector/observable is vacuously always 0 (not flipped). This method instead\n    returns the \"sign\"; the expected parity of the measurement set declared by the\n    detector/observable. The sign is the baseline used to determine if a flip\n    occurred. A detector/observable's value is whether its sign disagrees with the\n    measured parity of its measurement set.\n\n    Note that this method doesn't account for sweep bits. It will effectively ignore\n    instructions like `CX sweep[0] 0`.\n\n    Args:\n        bit_packed: Defaults to False. Determines whether the output numpy arrays\n            use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n    Returns:\n        A (det, obs) tuple with numpy arrays containing the reference parities.\n\n        if bit_packed:\n            det.shape == (math.ceil(num_detectors / 8),)\n            det.dtype == np.uint8\n            obs.shape == (math.ceil(num_observables / 8),)\n            obs.dtype == np.uint8\n        else:\n            det.shape == (num_detectors,)\n            det.dtype == np.bool_\n            obs.shape == (num_observables,)\n            obs.dtype == np.bool_\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...     X 1\n        ...     M 0 1\n        ...     DETECTOR rec[-1]\n        ...     DETECTOR rec[-2]\n        ...     OBSERVABLE_INCLUDE(3) rec[-1] rec[-2]\n        ... ''').reference_detector_and_observable_signs()\n        (array([ True, False]), array([False, False, False,  True]))\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.reference_sample\"></a>\n```python\n# stim.Circuit.reference_sample\n\n# (in class stim.Circuit)\ndef reference_sample(\n    self,\n    *,\n    bit_packed: bool = False,\n) -> np.ndarray:\n    \"\"\"Samples the given circuit in a deterministic fashion.\n\n    Discards all noisy operations, and biases all collapse events\n    towards +Z instead of randomly +Z/-Z.\n\n    Args:\n        bit_packed: Defaults to False. Determines whether the output numpy arrays\n            use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n    Returns:\n        A numpy array containing the reference sample.\n\n        if bit_packed:\n            shape == (math.ceil(num_measurements / 8),)\n            dtype == np.uint8\n        else:\n            shape == (num_measurements,)\n            dtype == np.bool_\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...     X 1\n        ...     M 0 1\n        ... ''').reference_sample()\n        array([False,  True])\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.search_for_undetectable_logical_errors\"></a>\n```python\n# stim.Circuit.search_for_undetectable_logical_errors\n\n# (in class stim.Circuit)\ndef search_for_undetectable_logical_errors(\n    self,\n    *,\n    dont_explore_detection_event_sets_with_size_above: int,\n    dont_explore_edges_with_degree_above: int,\n    dont_explore_edges_increasing_symptom_degree: bool,\n    canonicalize_circuit_errors: bool = False,\n) -> List[stim.ExplainedError]:\n    \"\"\"Searches for small sets of errors that form an undetectable logical error.\n\n    THIS IS A HEURISTIC METHOD. It does not guarantee that it will find errors of\n    particular sizes, or with particular properties. The errors it finds are a\n    tangled combination of the truncation parameters you specify, internal\n    optimizations which are correct when not truncating, and minutia of the circuit\n    being considered.\n\n    If you want a well behaved method that does provide guarantees of finding errors\n    of a particular type, use `stim.Circuit.shortest_graphlike_error`. This method\n    is more thorough than that (assuming you don't truncate so hard you omit\n    graphlike edges), but exactly how thorough is difficult to describe. It's also\n    not guaranteed that the behavior of this method will not be changed in the\n    future in a way that permutes which logical errors are found and which are\n    missed.\n\n    This search method considers hyper errors, so it has worst case exponential\n    runtime. It is important to carefully consider the arguments you are providing,\n    which truncate the search space and trade cost for quality.\n\n    The search progresses by starting from each error that crosses a logical\n    observable, noting which detection events each error produces, and then\n    iteratively adding in errors touching those detection events attempting to\n    cancel out the detection event with the lowest index.\n\n    Beware that the choice of logical observable can interact with the truncation\n    options. Using different observables can change whether or not the search\n    succeeds, even if those observables are equal modulo the stabilizers of the\n    code. This is because the edges crossing logical observables are used as\n    starting points for the search, and starting from different places along a path\n    will result in different numbers of symptoms in intermediate states as the\n    search progresses. For example, if the logical observable is next to a boundary,\n    then the starting edges are likely boundary edges (degree 1) with 'room to\n    grow', whereas if the observable was running through the bulk then the starting\n    edges will have degree at least 2.\n\n    Args:\n        dont_explore_detection_event_sets_with_size_above: Truncates the search\n            space by refusing to cross an edge (i.e. add an error) when doing so\n            would produce an intermediate state that has more detection events than\n            this limit.\n        dont_explore_edges_with_degree_above: Truncates the search space by refusing\n            to consider errors that cause a lot of detection events. For example,\n            you may only want to consider graphlike errors which have two or fewer\n            detection events.\n        dont_explore_edges_increasing_symptom_degree: Truncates the search space by\n            refusing to cross an edge (i.e. add an error) when doing so would\n            produce an intermediate state that has more detection events that the\n            previous intermediate state. This massively improves the efficiency of\n            the search because instead of, for example, exploring all n^4 possible\n            detection event sets with 4 symptoms, the search will attempt to cancel\n            out symptoms one by one.\n        canonicalize_circuit_errors: Whether or not to use one representative for\n            equal-symptom circuit errors.\n\n            False (default): Each DEM error lists every possible circuit error that\n                single handedly produces those symptoms as a potential match. This\n                is verbose but gives complete information.\n            True: Each DEM error is matched with one possible circuit error that\n                single handedly produces those symptoms, with a preference towards\n                errors that are simpler (e.g. apply Paulis to fewer qubits). This\n                discards mostly-redundant information about different ways to\n                produce the same symptoms in order to give a succinct result.\n\n    Returns:\n        A list of error mechanisms that cause an undetected logical error.\n\n        Each entry in the list is a `stim.ExplainedError` detailing the location\n        and effects of a single physical error. The effects of the entire list\n        combine to produce a logical frame change without any detection events.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit.generated(\n        ...     \"surface_code:rotated_memory_x\",\n        ...     rounds=5,\n        ...     distance=5,\n        ...     after_clifford_depolarization=0.001)\n        >>> print(len(circuit.search_for_undetectable_logical_errors(\n        ...     dont_explore_detection_event_sets_with_size_above=4,\n        ...     dont_explore_edges_with_degree_above=4,\n        ...     dont_explore_edges_increasing_symptom_degree=True,\n        ... )))\n        5\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.shortest_error_sat_problem\"></a>\n```python\n# stim.Circuit.shortest_error_sat_problem\n\n# (in class stim.Circuit)\ndef shortest_error_sat_problem(\n    self,\n    *,\n    format: str = 'WDIMACS',\n) -> str:\n    \"\"\"Makes a maxSAT problem of the circuit's distance, that other tools can solve.\n\n    The output is a string describing the maxSAT problem in WDIMACS format\n    (see https://jix.github.io/varisat/manual/0.2.0/formats/dimacs.html). The\n    optimal solution to the problem is the fault distance of the circuit (the\n    minimum number of error mechanisms that combine to flip any logical observable\n    while producing no detection events). This method ignores the probabilities of\n    the error mechanisms since it only cares about minimizing the number of errors\n    triggered.\n\n    There are many tools that can solve maxSAT problems in WDIMACS format.\n    One quick way to get started is to install pysat by running this BASH\n    terminal command:\n\n        pip install python-sat\n\n    Afterwards, you can run the included maxSAT solver \"RC2\" with this\n    Python code:\n\n        from pysat.examples.rc2 import RC2\n        from pysat.formula import WCNF\n\n        wcnf = WCNF(from_string=\"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\")\n\n        with RC2(wcnf) as rc2:\n        print(rc2.compute())\n        print(rc2.cost)\n\n    Much faster solvers are available online. For example, you can download\n    one of the entries in the 2023 maxSAT competition (see\n    https://maxsat-evaluations.github.io/2023) and run it on your problem by\n    running these BASH terminal commands:\n\n        wget https://maxsat-evaluations.github.io/2023/mse23-solver-src/exact/CASHWMaxSAT-CorePlus.zip\n        unzip CASHWMaxSAT-CorePlus.zip\n        ./CASHWMaxSAT-CorePlus/bin/cashwmaxsatcoreplus -bm -m your_problem.wcnf\n\n    Args:\n        format: Defaults to \"WDIMACS\", corresponding to WDIMACS format which is\n            described here: http://www.maxhs.org/docs/wdimacs.html\n\n    Returns:\n        A string corresponding to the contents of a maxSAT problem file in the\n        requested format.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...   X_ERROR(0.1) 0\n        ...   M 0\n        ...   OBSERVABLE_INCLUDE(0) rec[-1]\n        ...   X_ERROR(0.4) 0\n        ...   M 0\n        ...   DETECTOR rec[-1] rec[-2]\n        ... ''')\n        >>> print(circuit.shortest_error_sat_problem(), end='')\n        p wcnf 2 4 5\n        1 -1 0\n        1 -2 0\n        5 -1 0\n        5 2 0\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.shortest_graphlike_error\"></a>\n```python\n# stim.Circuit.shortest_graphlike_error\n\n# (in class stim.Circuit)\ndef shortest_graphlike_error(\n    self,\n    *,\n    ignore_ungraphlike_errors: bool = True,\n    canonicalize_circuit_errors: bool = False,\n) -> List[stim.ExplainedError]:\n    \"\"\"Finds a minimum set of graphlike errors to produce an undetected logical error.\n\n    A \"graphlike error\" is an error that creates at most two detection events\n    (causes a change in the parity of the measurement sets of at most two DETECTOR\n    annotations).\n\n    Note that this method does not pay attention to error probabilities (other than\n    ignoring errors with probability 0). It searches for a logical error with the\n    minimum *number* of physical errors, not the maximum probability of those\n    physical errors all occurring.\n\n    This method works by converting the circuit into a `stim.DetectorErrorModel`\n    using `circuit.detector_error_model(...)`, computing the shortest graphlike\n    error of the error model, and then converting the physical errors making up that\n    logical error back into representative circuit errors.\n\n    Args:\n        ignore_ungraphlike_errors:\n            False: Attempt to decompose any ungraphlike errors in the circuit into\n                graphlike parts. If this fails, raise an exception instead of\n                continuing.\n\n                Note: in some cases, graphlike errors only appear as parts of\n                decomposed ungraphlike errors. This can produce a result that lists\n                DEM errors with zero matching circuit errors, because the only way\n                to achieve those errors is by combining a decomposed error with a\n                graphlike error. As a result, when using this option it is NOT\n                guaranteed that the length of the result is an upper bound on the\n                true code distance. That is only the case if every item in the\n                result lists at least one matching circuit error.\n            True (default): Ungraphlike errors are simply skipped as if they weren't\n                present, even if they could become graphlike if decomposed. This\n                guarantees the length of the result is an upper bound on the true\n                code distance.\n        canonicalize_circuit_errors: Whether or not to use one representative for\n            equal-symptom circuit errors.\n\n            False (default): Each DEM error lists every possible circuit error that\n                single handedly produces those symptoms as a potential match. This\n                is verbose but gives complete information.\n            True: Each DEM error is matched with one possible circuit error that\n                single handedly produces those symptoms, with a preference towards\n                errors that are simpler (e.g. apply Paulis to fewer qubits). This\n                discards mostly-redundant information about different ways to\n                produce the same symptoms in order to give a succinct result.\n\n    Returns:\n        A list of error mechanisms that cause an undetected logical error.\n\n        Each entry in the list is a `stim.ExplainedError` detailing the location\n        and effects of a single physical error. The effects of the entire list\n        combine to produce a logical frame change without any detection events.\n\n    Examples:\n        >>> import stim\n\n        >>> circuit = stim.Circuit.generated(\n        ...     \"repetition_code:memory\",\n        ...     rounds=10,\n        ...     distance=7,\n        ...     before_round_data_depolarization=0.01)\n        >>> len(circuit.shortest_graphlike_error())\n        7\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.solve_flow_measurements\"></a>\n```python\n# stim.Circuit.solve_flow_measurements\n\n# (in class stim.Circuit)\ndef solve_flow_measurements(\n    self,\n    flows: List[stim.Flow],\n) -> List[Optional[List[int]]]:\n    \"\"\"Finds measurements to explain the starts/ends of the given flows, ignoring sign.\n\n    CAUTION: it's not guaranteed that the solutions returned by this method are\n    minimal. It may use 20 measurements when only 2 are needed. The method applies\n    some simple heuristics that attempt to reduce the size, but these heuristics\n    aren't perfect and don't make any strong guarantees.\n\n    The recommended way to use this method is on small parts of a circuit, such as a\n    single surface code round. The ideal use case is when there is exactly one\n    solution for each flow, because then the method behaves predictably and\n    consistently. When there are multiple solutions, the method has no real way to\n    pick out a \"good\" solution rather than a \"cataclysmic trash fire of a\" solution.\n    For example, if you have a multi-round surface code circuit with open time\n    boundaries and solve the flow 1 -> Z1*Z2*Z3*Z4, then there's a good solution\n    (the Z1*Z2*Z3*Z4 measurement from the last round), various mediocre solutions\n    (a Z1*Z2*Z3*Z4 measurement from a different round), and lots of terrible\n    solutions (a combination of multiple Z1*Z2*Z3*Z4 measurements from an odd number\n    of rounds, times a random combination of unrelated detectors). The method is\n    permitted to return any of those solutions.\n\n    Args:\n        flows: A list of flows, each of which to be solved. Measurements and signs\n            are entirely ignored.\n\n            An error is raised if one of the given flows has an identity pauli\n            string as its input and as its output, despite the fact that this case\n            has a vacuous solution (no measurements). This error is only present as\n            a safety check that catches some possible bugs in the calling code, such\n            as accidentally applying this method to detector flows. This error may\n            be removed in the future, so that the vacuous case succeeds vacuously.\n\n    Returns:\n        A list of solutions for each given flow.\n\n        If no solution exists for flows[k], then solutions[k] is None.\n        Otherwise, solutions[k] is a list of measurement indices for flows[k].\n\n        When solutions[k] is not None, it's guaranteed that\n\n            circuit.has_flow(stim.Flow(\n                input=flows[k].input,\n                output=flows[k].output,\n                measurements=solutions[k],\n            ), unsigned=True)\n\n    Raises:\n        ValueError:\n            A flow had an empty input and output.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     M 2\n        ... ''').solve_flow_measurements([\n        ...     stim.Flow(\"Z2 -> 1\"),\n        ... ])\n        [[0]]\n\n        >>> stim.Circuit('''\n        ...     M 2\n        ... ''').solve_flow_measurements([\n        ...     stim.Flow(\"X2 -> X2\"),\n        ... ])\n        [None]\n\n        >>> stim.Circuit('''\n        ...     MXX 0 1\n        ... ''').solve_flow_measurements([\n        ...     stim.Flow(\"YY -> ZZ\"),\n        ... ])\n        [[0]]\n\n        >>> # Rep code cycle\n        >>> stim.Circuit('''\n        ...     R 1 3\n        ...     CX 0 1 2 3\n        ...     CX 4 3 2 1\n        ...     M 1 3\n        ... ''').solve_flow_measurements([\n        ...     stim.Flow(\"1 -> Z0*Z4\"),\n        ...     stim.Flow(\"Z0 -> Z2\"),\n        ...     stim.Flow(\"X0*X2*X4 -> X0*X2*X4\"),\n        ...     stim.Flow(\"Y0 -> Y0\"),\n        ... ])\n        [[0, 1], [0], [], None]\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.time_reversed_for_flows\"></a>\n```python\n# stim.Circuit.time_reversed_for_flows\n\n# (in class stim.Circuit)\ndef time_reversed_for_flows(\n    self,\n    flows: Iterable[stim.Flow],\n    *,\n    dont_turn_measurements_into_resets: bool = False,\n) -> Tuple[stim.Circuit, List[stim.Flow]]:\n    \"\"\"Time-reverses the circuit while preserving error correction structure.\n\n    This method returns a circuit that has the same internal detecting regions\n    as the given circuit, as well as the same internal-to-external flows given\n    in the `flows` argument, except they are all time-reversed. For example, if\n    you pass a fault tolerant preparation circuit into this method (1 -> Z), the\n    result will be a fault tolerant *measurement* circuit (Z -> 1). Or, if you\n    pass a fault tolerant C_XYZ circuit into this method (X->Y, Y->Z, and Z->X),\n    the result will be a fault tolerant C_ZYX circuit (X->Z, Y->X, and Z->Y).\n\n    Note that this method doesn't guarantee that it will preserve the *sign* of the\n    detecting regions or stabilizer flows. For example, inverting a memory circuit\n    that preserves a logical observable (X->X and Z->Z) may produce a\n    memory circuit that always bit flips the logical observable (X->X and Z->-Z) or\n    that dynamically adjusts the logical observable in response to measurements\n    (like \"X -> X xor rec[-1]\" and \"Z -> Z xor rec[-2]\").\n\n    This method will turn time-reversed resets into measurements, and attempts to\n    turn time-reversed measurements into resets. A measurement will time-reverse\n    into a reset if some annotated detectors, annotated observables, or given flows\n    have detecting regions with sensitivity just before the measurement but none\n    have detecting regions with sensitivity after the measurement.\n\n    In some cases this method will have to introduce new operations. In particular,\n    when a measurement-reset operation has a noisy result, time-reversing this\n    measurement noise produces reset noise. But the measure-reset operations don't\n    have built-in reset noise, so the reset noise is specified by adding an X_ERROR\n    or Z_ERROR noise instruction after the time-reversed measure-reset operation.\n\n    Args:\n        flows: Flows you care about, that reach past the start/end of the given\n            circuit. The result will contain an inverted flow for each of these\n            given flows. You need this information because it reveals the\n            measurements needed to produce the inverted flows that you care\n            about.\n\n            An exception will be raised if the circuit doesn't have all these\n            flows. The inverted circuit will have the inverses of these flows\n            (ignoring sign).\n        dont_turn_measurements_into_resets: Defaults to False. When set to\n            True, measurements will time-reverse into measurements even if\n            nothing is sensitive to the measured qubit after the measurement\n            completes. This guarantees the output circuit has *all* flows\n            that the input circuit has (up to sign and feedback), even ones\n            that aren't annotated.\n\n    Returns:\n        An (inverted_circuit, inverted_flows) tuple.\n\n        inverted_circuit is the qec inverse of the given circuit.\n\n        inverted_flows is a list of flows, matching up by index with the flows\n        given as arguments to the method. The input, output, and sign fields\n        of these flows are boring. The useful field is measurement_indices,\n        because it's difficult to predict which measurements are needed for\n        the inverted flow due to effects such as implicitly-included resets\n        inverting into explicitly-included measurements.\n\n    Caveats:\n        Currently, this method doesn't compute the sign of the inverted flows.\n        It unconditionally sets the sign to False.\n\n    Examples:\n        >>> import stim\n\n        >>> inv_circuit, inv_flows = stim.Circuit('''\n        ...     R 0\n        ...     H 0\n        ...     S 0\n        ...     MY 0\n        ...     DETECTOR rec[-1]\n        ... ''').time_reversed_for_flows([])\n        >>> inv_circuit\n        stim.Circuit('''\n            RY 0\n            S_DAG 0\n            H 0\n            M 0\n            DETECTOR rec[-1]\n        ''')\n        >>> inv_flows\n        []\n\n        >>> inv_circuit, inv_flows = stim.Circuit('''\n        ...     M 0\n        ... ''').time_reversed_for_flows([\n        ...     stim.Flow(\"Z -> rec[-1]\"),\n        ... ])\n        >>> inv_circuit\n        stim.Circuit('''\n            R 0\n        ''')\n        >>> inv_flows\n        [stim.Flow(\"1 -> Z\")]\n        >>> inv_circuit.has_all_flows(inv_flows, unsigned=True)\n        True\n\n        >>> inv_circuit, inv_flows = stim.Circuit('''\n        ...     R 0\n        ... ''').time_reversed_for_flows([\n        ...     stim.Flow(\"1 -> Z\"),\n        ... ])\n        >>> inv_circuit\n        stim.Circuit('''\n            M 0\n        ''')\n        >>> inv_flows\n        [stim.Flow(\"Z -> rec[-1]\")]\n\n        >>> inv_circuit, inv_flows = stim.Circuit('''\n        ...     M 0\n        ... ''').time_reversed_for_flows([\n        ...     stim.Flow(\"1 -> Z xor rec[-1]\"),\n        ... ])\n        >>> inv_circuit\n        stim.Circuit('''\n            M 0\n        ''')\n        >>> inv_flows\n        [stim.Flow(\"Z -> rec[-1]\")]\n\n        >>> inv_circuit, inv_flows = stim.Circuit('''\n        ...     M 0\n        ... ''').time_reversed_for_flows(\n        ...     flows=[stim.Flow(\"Z -> rec[-1]\")],\n        ...     dont_turn_measurements_into_resets=True,\n        ... )\n        >>> inv_circuit\n        stim.Circuit('''\n            M 0\n        ''')\n        >>> inv_flows\n        [stim.Flow(\"1 -> Z xor rec[-1]\")]\n\n        >>> inv_circuit, inv_flows = stim.Circuit('''\n        ...     MR(0.125) 0\n        ... ''').time_reversed_for_flows([])\n        >>> inv_circuit\n        stim.Circuit('''\n            MR 0\n            X_ERROR(0.125) 0\n        ''')\n        >>> inv_flows\n        []\n\n        >>> inv_circuit, inv_flows = stim.Circuit('''\n        ...     MXX 0 1\n        ...     H 0\n        ... ''').time_reversed_for_flows([\n        ...     stim.Flow(\"ZZ -> YY xor rec[-1]\"),\n        ...     stim.Flow(\"ZZ -> XZ\"),\n        ... ])\n        >>> inv_circuit\n        stim.Circuit('''\n            H 0\n            MXX 0 1\n        ''')\n        >>> inv_flows\n        [stim.Flow(\"YY -> ZZ xor rec[-1]\"), stim.Flow(\"XZ -> ZZ\")]\n\n        >>> stim.Circuit.generated(\n        ...     \"surface_code:rotated_memory_x\",\n        ...     distance=2,\n        ...     rounds=1,\n        ... ).time_reversed_for_flows([])[0]\n        stim.Circuit('''\n            QUBIT_COORDS(1, 1) 1\n            QUBIT_COORDS(2, 0) 2\n            QUBIT_COORDS(3, 1) 3\n            QUBIT_COORDS(1, 3) 6\n            QUBIT_COORDS(2, 2) 7\n            QUBIT_COORDS(3, 3) 8\n            QUBIT_COORDS(2, 4) 12\n            RX 8 6 3 1\n            MR 12 7 2\n            TICK\n            H 12 2\n            TICK\n            CX 1 7 12 6\n            TICK\n            CX 6 7 12 8\n            TICK\n            CX 3 7 2 1\n            TICK\n            CX 8 7 2 3\n            TICK\n            H 12 2\n            TICK\n            M 12 7 2\n            DETECTOR(2, 0, 1) rec[-1]\n            DETECTOR(2, 4, 1) rec[-3]\n            MX 8 6 3 1\n            DETECTOR(2, 0, 0) rec[-5] rec[-2] rec[-1]\n            DETECTOR(2, 4, 0) rec[-7] rec[-4] rec[-3]\n            OBSERVABLE_INCLUDE(0) rec[-3] rec[-1]\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.to_crumble_url\"></a>\n```python\n# stim.Circuit.to_crumble_url\n\n# (in class stim.Circuit)\ndef to_crumble_url(\n    self,\n    *,\n    skip_detectors: bool = False,\n    mark: Optional[Dict[int, List[stim.ExplainedError]]] = None,\n) -> str:\n    \"\"\"Returns a URL that opens up crumble and loads this circuit into it.\n\n    Crumble is a tool for editing stabilizer circuits, and visualizing their\n    stabilizer flows. Its source code is in the `glue/crumble` directory of\n    the stim code repository on github. A prebuilt version is made available\n    at https://algassert.com/crumble, which is what the URL returned by this\n    method will point to.\n\n    Args:\n        skip_detectors: Defaults to False. If set to True, detectors from the\n            circuit aren't included in the crumble URL. This can reduce visual\n            clutter in crumble, and improve its performance, since it doesn't\n            need to indicate or track the sensitivity regions of detectors.\n        mark: Defaults to None (no marks). If set to a dictionary from int to\n            errors, such as `mark={1: circuit.shortest_graphlike_error()}`,\n            then the errors will be highlighted and tracked forward by crumble.\n\n    Returns:\n        A URL that can be opened in a web browser.\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...     H 0\n        ...     CNOT 0 1\n        ...     S 1\n        ... ''').to_crumble_url()\n        'https://algassert.com/crumble#circuit=H_0;CX_0_1;S_1_'\n\n        >>> circuit = stim.Circuit('''\n        ...     M(0.25) 0 1 2\n        ...     DETECTOR rec[-1] rec[-2]\n        ...     DETECTOR rec[-2] rec[-3]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''')\n        >>> err = circuit.shortest_graphlike_error(canonicalize_circuit_errors=True)\n        >>> circuit.to_crumble_url(skip_detectors=True, mark={1: err})\n        'https://algassert.com/crumble#circuit=;TICK;MARKX(1)1;MARKX(1)2;MARKX(1)0;TICK;M(0.25)0_1_2;OI(0)rec[-1]_'\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.to_file\"></a>\n```python\n# stim.Circuit.to_file\n\n# (in class stim.Circuit)\ndef to_file(\n    self,\n    file: Union[io.TextIOBase, str, pathlib.Path],\n) -> None:\n    \"\"\"Writes the stim circuit to a file.\n\n    The file format is defined at\n    https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n    Args:\n        file: A file path or an open file to write to.\n\n    Examples:\n        >>> import stim\n        >>> import tempfile\n        >>> c = stim.Circuit('H 5\\nX 0')\n\n        >>> with tempfile.TemporaryDirectory() as tmpdir:\n        ...     path = tmpdir + '/tmp.stim'\n        ...     with open(path, 'w') as f:\n        ...         c.to_file(f)\n        ...     with open(path) as f:\n        ...         contents = f.read()\n        >>> contents\n        'H 5\\nX 0\\n'\n\n        >>> with tempfile.TemporaryDirectory() as tmpdir:\n        ...     path = tmpdir + '/tmp.stim'\n        ...     c.to_file(path)\n        ...     with open(path) as f:\n        ...         contents = f.read()\n        >>> contents\n        'H 5\\nX 0\\n'\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.to_qasm\"></a>\n```python\n# stim.Circuit.to_qasm\n\n# (in class stim.Circuit)\ndef to_qasm(\n    self,\n    *,\n    open_qasm_version: int,\n    skip_dets_and_obs: bool = False,\n) -> str:\n    \"\"\"Creates an equivalent OpenQASM implementation of the circuit.\n\n    Args:\n        open_qasm_version: The version of OpenQASM to target.\n            This should be set to 2 or to 3.\n\n            Differences between the versions are:\n                - Support for operations on classical bits (only version 3).\n                    This means DETECTOR and OBSERVABLE_INCLUDE only work with\n                    version 3.\n                - Support for feedback operations (only version 3).\n                - Support for subroutines (only version 3). Without subroutines,\n                    non-standard dissipative gates like MR and RX need to decompose\n                    inline every single time they're used.\n                - Minor name changes (e.g. creg -> bit, qelib1.inc -> stdgates.inc).\n        skip_dets_and_obs: Defaults to False. When set to False, the output will\n            include a `dets` register and an `obs` register (assuming the circuit\n            has detectors and observables). These registers will be computed as part\n            of running the circuit. This requires performing a simulation of the\n            circuit, in order to correctly account for the expected value of\n            measurements.\n\n            When set to True, the `dets` and `obs` registers are not included in the\n            output, and no simulation of the circuit is performed.\n\n    Returns:\n        The OpenQASM code as a string.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     R 0 1\n        ...     X 1\n        ...     H 0\n        ...     CX 0 1\n        ...     M 0 1\n        ...     DETECTOR rec[-1] rec[-2]\n        ... ''');\n        >>> qasm = circuit.to_qasm(open_qasm_version=3);\n        >>> print(qasm.strip().replace('\\n\\n', '\\n'))\n        OPENQASM 3.0;\n        include \"stdgates.inc\";\n        qreg q[2];\n        creg rec[2];\n        creg dets[1];\n        reset q[0];\n        reset q[1];\n        x q[1];\n        h q[0];\n        cx q[0], q[1];\n        measure q[0] -> rec[0];\n        measure q[1] -> rec[1];\n        dets[0] = rec[1] ^ rec[0] ^ 1;\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.to_quirk_url\"></a>\n```python\n# stim.Circuit.to_quirk_url\n\n# (in class stim.Circuit)\ndef to_quirk_url(\n    self,\n) -> str:\n    \"\"\"Returns a URL that opens up quirk and loads this circuit into it.\n\n    Quirk is an open source drag and drop circuit editor with support for up to 16\n    qubits. Its source code is available at https://github.com/strilanc/quirk\n    and a prebuilt version is available at https://algassert.com/quirk, which is\n    what the URL returned by this method will point to.\n\n    Quirk doesn't support features like noise, feedback, or detectors. This method\n    will simply drop any unsupported operations from the circuit when producing\n    the URL.\n\n    Returns:\n        A URL that can be opened in a web browser.\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...     H 0\n        ...     CNOT 0 1\n        ...     S 1\n        ... ''').to_quirk_url()\n        'https://algassert.com/quirk#circuit={\"cols\":[[\"H\"],[\"•\",\"X\"],[1,\"Z^½\"]]}'\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.to_tableau\"></a>\n```python\n# stim.Circuit.to_tableau\n\n# (in class stim.Circuit)\ndef to_tableau(\n    self,\n    *,\n    ignore_noise: bool = False,\n    ignore_measurement: bool = False,\n    ignore_reset: bool = False,\n) -> stim.Tableau:\n    \"\"\"Converts the circuit into an equivalent stabilizer tableau.\n\n    Args:\n        ignore_noise: Defaults to False. When False, any noise operations in the\n            circuit will cause the conversion to fail with an exception. When True,\n            noise operations are skipped over as if they weren't even present in the\n            circuit.\n        ignore_measurement: Defaults to False. When False, any measurement\n            operations in the circuit will cause the conversion to fail with an\n            exception. When True, measurement operations are skipped over as if they\n            weren't even present in the circuit.\n        ignore_reset: Defaults to False. When False, any reset operations in the\n            circuit will cause the conversion to fail with an exception. When True,\n            reset operations are skipped over as if they weren't even present in the\n            circuit.\n\n    Returns:\n        A tableau equivalent to the circuit (up to global phase).\n\n    Raises:\n        ValueError:\n            The circuit contains noise operations but ignore_noise=False.\n            OR\n            The circuit contains measurement operations but\n            ignore_measurement=False.\n            OR\n            The circuit contains reset operations but ignore_reset=False.\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...     H 0\n        ...     CNOT 0 1\n        ... ''').to_tableau()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z_\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+XX\"),\n                stim.PauliString(\"+ZZ\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.with_inlined_feedback\"></a>\n```python\n# stim.Circuit.with_inlined_feedback\n\n# (in class stim.Circuit)\ndef with_inlined_feedback(\n    self,\n) -> stim.Circuit:\n    \"\"\"Returns a circuit without feedback with rewritten detectors/observables.\n\n    When a feedback operation affects the expected parity of a detector or\n    observable, the measurement controlling that feedback operation is implicitly\n    part of the measurement set that defines the detector or observable. This\n    method removes all feedback, but avoids changing the meaning of detectors or\n    observables by turning these implicit measurement dependencies into explicit\n    measurement dependencies added to the observable or detector.\n\n    This method guarantees that the detector error model derived from the original\n    circuit, and the transformed circuit, will be equivalent (modulo floating point\n    rounding errors and variations in where loops are placed). Specifically, the\n    following should be true for any circuit:\n\n        dem1 = circuit.flattened().detector_error_model()\n        dem2 = circuit.with_inlined_feedback().flattened().detector_error_model()\n        assert dem1.approx_equals(dem2, 1e-5)\n\n    Returns:\n        A `stim.Circuit` with feedback operations removed, with rewritten DETECTOR\n        instructions (as needed to avoid changing the meaning of each detector), and\n        with additional OBSERVABLE_INCLUDE instructions (as needed to avoid changing\n        the meaning of each observable).\n\n        The circuit's function is permitted to differ from the original in that\n        any feedback operation can be pushed to the end of the circuit and\n        discarded. All non-feedback operations must stay where they are, preserving\n        the structure of the circuit.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     CX 0 1        # copy to measure qubit\n        ...     M 1           # measure first time\n        ...     CX rec[-1] 1  # use feedback to reset measurement qubit\n        ...     CX 0 1        # copy to measure qubit\n        ...     M 1           # measure second time\n        ...     DETECTOR rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').with_inlined_feedback()\n        stim.Circuit('''\n            CX 0 1\n            M 1\n            OBSERVABLE_INCLUDE(0) rec[-1]\n            CX 0 1\n            M 1\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(0) rec[-1]\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.without_noise\"></a>\n```python\n# stim.Circuit.without_noise\n\n# (in class stim.Circuit)\ndef without_noise(\n    self,\n) -> stim.Circuit:\n    \"\"\"Returns a copy of the circuit with all noise processes removed.\n\n    Pure noise instructions, such as X_ERROR and DEPOLARIZE2, are not\n    included in the result.\n\n    Noisy measurement instructions, like `M(0.001)`, have their noise\n    parameter removed.\n\n    Returns:\n        A `stim.Circuit` with the same instructions except all noise\n        processes have been removed.\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...     X_ERROR(0.25) 0\n        ...     CNOT 0 1\n        ...     M(0.125) 0\n        ... ''').without_noise()\n        stim.Circuit('''\n            CX 0 1\n            M 0\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Circuit.without_tags\"></a>\n```python\n# stim.Circuit.without_tags\n\n# (in class stim.Circuit)\ndef without_tags(\n    self,\n) -> stim.Circuit:\n    \"\"\"Returns a copy of the circuit with all tags removed.\n\n    Returns:\n        A `stim.Circuit` with the same instructions except all tags have been\n        removed.\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit('''\n        ...     X[test-tag] 0\n        ...     M[test-tag-2](0.125) 0\n        ... ''').without_tags()\n        stim.Circuit('''\n            X 0\n            M(0.125) 0\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocation\"></a>\n```python\n# stim.CircuitErrorLocation\n\n# (at top-level in the stim module)\nclass CircuitErrorLocation:\n    \"\"\"Describes the location of an error mechanism from a stim circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit.generated(\n        ...     \"repetition_code:memory\",\n        ...     distance=5,\n        ...     rounds=5,\n        ...     before_round_data_depolarization=1e-3,\n        ... )\n        >>> logical_error = circuit.shortest_graphlike_error()\n        >>> error_location = logical_error[0].circuit_error_locations[0]\n        >>> print(error_location)\n        CircuitErrorLocation {\n            flipped_pauli_product: X0\n            Circuit location stack trace:\n                (after 1 TICKs)\n                at instruction #3 (DEPOLARIZE1) in the circuit\n                at target #1 of the instruction\n                resolving to DEPOLARIZE1(0.001) 0\n        }\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocation.__init__\"></a>\n```python\n# stim.CircuitErrorLocation.__init__\n\n# (in class stim.CircuitErrorLocation)\ndef __init__(\n    self,\n    *,\n    tick_offset: int,\n    flipped_pauli_product: List[stim.GateTargetWithCoords],\n    flipped_measurement: object,\n    instruction_targets: stim.CircuitTargetsInsideInstruction,\n    stack_frames: List[stim.CircuitErrorLocationStackFrame],\n    noise_tag: str = '',\n) -> None:\n    \"\"\"Creates a stim.CircuitErrorLocation.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.CircuitErrorLocation(\n        ...     tick_offset=1,\n        ...     flipped_pauli_product=(\n        ...         stim.GateTargetWithCoords(\n        ...             gate_target=stim.target_x(0),\n        ...             coords=[],\n        ...         ),\n        ...     ),\n        ...     flipped_measurement=stim.FlippedMeasurement(\n        ...         record_index=None,\n        ...         observable=(),\n        ...     ),\n        ...     instruction_targets=stim.CircuitTargetsInsideInstruction(\n        ...         gate='DEPOLARIZE1',\n        ...         args=[0.001],\n        ...         target_range_start=0,\n        ...         target_range_end=1,\n        ...         targets_in_range=(stim.GateTargetWithCoords(\n        ...             gate_target=0,\n        ...             coords=[],\n        ...         ),)\n        ...     ),\n        ...     stack_frames=(\n        ...         stim.CircuitErrorLocationStackFrame(\n        ...             instruction_offset=2,\n        ...             iteration_index=0,\n        ...             instruction_repetitions_arg=0,\n        ...         ),\n        ...     ),\n        ...     noise_tag='test-tag',\n        ... )\n        >>> print(err)\n        CircuitErrorLocation {\n            noise_tag: test-tag\n            flipped_pauli_product: X0\n            Circuit location stack trace:\n                (after 1 TICKs)\n                at instruction #3 (DEPOLARIZE1) in the circuit\n                at target #1 of the instruction\n                resolving to DEPOLARIZE1(0.001) 0\n        }\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocation.flipped_measurement\"></a>\n```python\n# stim.CircuitErrorLocation.flipped_measurement\n\n# (in class stim.CircuitErrorLocation)\n@property\ndef flipped_measurement(\n    self,\n) -> Optional[stim.FlippedMeasurement]:\n    \"\"\"The measurement that was flipped by the error mechanism.\n\n    If the error isn't a measurement error, this will be None.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     M(0.125) 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].flipped_measurement\n        stim.FlippedMeasurement(\n            record_index=0,\n            observable=(stim.GateTargetWithCoords(stim.target_z(0), []),),\n        )\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocation.flipped_pauli_product\"></a>\n```python\n# stim.CircuitErrorLocation.flipped_pauli_product\n\n# (in class stim.CircuitErrorLocation)\n@property\ndef flipped_pauli_product(\n    self,\n) -> List[stim.GateTargetWithCoords]:\n    \"\"\"The Pauli errors that the error mechanism applied to qubits.\n\n    When the error is a measurement error, this will be an empty list.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].flipped_pauli_product\n        [stim.GateTargetWithCoords(stim.target_y(0), [])]\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocation.instruction_targets\"></a>\n```python\n# stim.CircuitErrorLocation.instruction_targets\n\n# (in class stim.CircuitErrorLocation)\n@property\ndef instruction_targets(\n    self,\n) -> stim.CircuitTargetsInsideInstruction:\n    \"\"\"Within the error instruction, which may have hundreds of\n    targets, which specific targets were being executed to\n    produce the error.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> targets = err[0].circuit_error_locations[0].instruction_targets\n        >>> targets == stim.CircuitTargetsInsideInstruction(\n        ...     gate='Y_ERROR',\n        ...     args=[0.125],\n        ...     target_range_start=0,\n        ...     target_range_end=1,\n        ...     targets_in_range=(stim.GateTargetWithCoords(0, []),),\n        ... )\n        True\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocation.noise_tag\"></a>\n```python\n# stim.CircuitErrorLocation.noise_tag\n\n# (in class stim.CircuitErrorLocation)\n@property\ndef noise_tag(\n    self,\n) -> str:\n    \"\"\"The tag on the noise instruction that caused the error.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     Y_ERROR[test-tag](0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].noise_tag\n        'test-tag'\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocation.stack_frames\"></a>\n```python\n# stim.CircuitErrorLocation.stack_frames\n\n# (in class stim.CircuitErrorLocation)\n@property\ndef stack_frames(\n    self,\n) -> List[stim.CircuitErrorLocationStackFrame]:\n    \"\"\"Describes where in the circuit's execution the error happened.\n\n    Multiple frames are needed because the error may occur within a loop,\n    or a loop nested inside a loop, or etc.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].stack_frames\n        [stim.CircuitErrorLocationStackFrame(\n            instruction_offset=2,\n            iteration_index=0,\n            instruction_repetitions_arg=0,\n        )]\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocation.tick_offset\"></a>\n```python\n# stim.CircuitErrorLocation.tick_offset\n\n# (in class stim.CircuitErrorLocation)\n@property\ndef tick_offset(\n    self,\n) -> int:\n    \"\"\"The number of TICKs that executed before the error happened.\n\n    This counts TICKs occurring multiple times during loops.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     TICK\n        ...     TICK\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].tick_offset\n        3\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocationStackFrame\"></a>\n```python\n# stim.CircuitErrorLocationStackFrame\n\n# (at top-level in the stim module)\nclass CircuitErrorLocationStackFrame:\n    \"\"\"Describes the location of an instruction being executed within a\n    circuit or loop, distinguishing between separate loop iterations.\n\n    The full location of an instruction is a list of these frames,\n    drilling down from the top level circuit to the inner-most loop\n    that the instruction is within.\n\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     REPEAT 5 {\n        ...         R 0\n        ...         Y_ERROR(0.125) 0\n        ...         M 0\n        ...     }\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].stack_frames[0]\n        stim.CircuitErrorLocationStackFrame(\n            instruction_offset=0,\n            iteration_index=0,\n            instruction_repetitions_arg=5,\n        )\n        >>> err[0].circuit_error_locations[0].stack_frames[1]\n        stim.CircuitErrorLocationStackFrame(\n            instruction_offset=1,\n            iteration_index=4,\n            instruction_repetitions_arg=0,\n        )\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocationStackFrame.__init__\"></a>\n```python\n# stim.CircuitErrorLocationStackFrame.__init__\n\n# (in class stim.CircuitErrorLocationStackFrame)\ndef __init__(\n    self,\n    *,\n    instruction_offset: int,\n    iteration_index: int,\n    instruction_repetitions_arg: int,\n) -> None:\n    \"\"\"Creates a stim.CircuitErrorLocationStackFrame.\n\n    Examples:\n        >>> import stim\n        >>> frame = stim.CircuitErrorLocationStackFrame(\n        ...     instruction_offset=1,\n        ...     iteration_index=2,\n        ...     instruction_repetitions_arg=3,\n        ... )\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocationStackFrame.instruction_offset\"></a>\n```python\n# stim.CircuitErrorLocationStackFrame.instruction_offset\n\n# (in class stim.CircuitErrorLocationStackFrame)\n@property\ndef instruction_offset(\n    self,\n) -> int:\n    \"\"\"The index of the instruction within the circuit, or within the\n    instruction's parent REPEAT block. This is slightly different\n    from the line number, because blank lines and commented lines\n    don't count and also because the offset of the first instruction\n    is 0 instead of 1.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].stack_frames[0].instruction_offset\n        2\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocationStackFrame.instruction_repetitions_arg\"></a>\n```python\n# stim.CircuitErrorLocationStackFrame.instruction_repetitions_arg\n\n# (in class stim.CircuitErrorLocationStackFrame)\n@property\ndef instruction_repetitions_arg(\n    self,\n) -> int:\n    \"\"\"If the instruction being referred to is a REPEAT block,\n    this is the repetition count of that REPEAT block. Otherwise\n    this field defaults to 0.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     REPEAT 5 {\n        ...         R 0\n        ...         Y_ERROR(0.125) 0\n        ...         M 0\n        ...     }\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> full = err[0].circuit_error_locations[0].stack_frames[0]\n        >>> loop = err[0].circuit_error_locations[0].stack_frames[1]\n        >>> full.instruction_repetitions_arg\n        5\n        >>> loop.instruction_repetitions_arg\n        0\n    \"\"\"\n```\n\n<a name=\"stim.CircuitErrorLocationStackFrame.iteration_index\"></a>\n```python\n# stim.CircuitErrorLocationStackFrame.iteration_index\n\n# (in class stim.CircuitErrorLocationStackFrame)\n@property\ndef iteration_index(\n    self,\n) -> int:\n    \"\"\"Disambiguates which iteration of the loop containing this instruction\n    is being referred to. If the instruction isn't in a REPEAT block, this\n    field defaults to 0.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     REPEAT 5 {\n        ...         R 0\n        ...         Y_ERROR(0.125) 0\n        ...         M 0\n        ...     }\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> full = err[0].circuit_error_locations[0].stack_frames[0]\n        >>> loop = err[0].circuit_error_locations[0].stack_frames[1]\n        >>> full.iteration_index\n        0\n        >>> loop.iteration_index\n        4\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction\"></a>\n```python\n# stim.CircuitInstruction\n\n# (at top-level in the stim module)\nclass CircuitInstruction:\n    \"\"\"An instruction, like `H 0 1` or `CNOT rec[-1] 5`, from a circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     M 0 1\n        ...     X_ERROR(0.125) 5\n        ... ''')\n        >>> circuit[0]\n        stim.CircuitInstruction('H', [stim.GateTarget(0)], [])\n        >>> circuit[1]\n        stim.CircuitInstruction('M', [stim.GateTarget(0), stim.GateTarget(1)], [])\n        >>> circuit[2]\n        stim.CircuitInstruction('X_ERROR', [stim.GateTarget(5)], [0.125])\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.__eq__\"></a>\n```python\n# stim.CircuitInstruction.__eq__\n\n# (in class stim.CircuitInstruction)\ndef __eq__(\n    self,\n    arg0: stim.CircuitInstruction,\n) -> bool:\n    \"\"\"Determines if two `stim.CircuitInstruction`s are identical.\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.__init__\"></a>\n```python\n# stim.CircuitInstruction.__init__\n\n# (in class stim.CircuitInstruction)\ndef __init__(\n    self,\n    name: str,\n    targets: Optional[Iterable[Union[int, stim.GateTarget]]] = None,\n    gate_args: Optional[Iterable[float]] = None,\n    *,\n    tag: str = \"\",\n) -> None:\n    \"\"\"Creates or parses a `stim.CircuitInstruction`.\n\n    Args:\n        name: The name of the instruction being applied.\n            If `targets` and `gate_args` aren't specified, this can be a full\n            instruction line from a stim Circuit file, like \"CX 0 1\".\n        targets: The targets the instruction is being applied to. These can be raw\n            values like `0` and `stim.target_rec(-1)`, or instances of\n            `stim.GateTarget`.\n        gate_args: The sequence of numeric arguments parameterizing a gate. For\n            noise gates this is their probabilities. For `OBSERVABLE_INCLUDE`\n            instructions it's the index of the logical observable to affect.\n        tag: Defaults to \"\". A custom string attached to the instruction. For\n            example, for a TICK instruction, this could a string specifying an\n            amount of time which is used by custom code for adding noise to a\n            circuit. In general, stim will attempt to propagate tags across circuit\n            transformations but will otherwise completely ignore them.\n\n    Examples:\n        >>> import stim\n\n        >>> print(stim.CircuitInstruction('DEPOLARIZE1', [5], [0.25]))\n        DEPOLARIZE1(0.25) 5\n\n        >>> stim.CircuitInstruction('CX rec[-1] 5  # comment')\n        stim.CircuitInstruction('CX', [stim.target_rec(-1), stim.GateTarget(5)], [])\n\n        >>> print(stim.CircuitInstruction('I', [2], tag='100ns'))\n        I[100ns] 2\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.__ne__\"></a>\n```python\n# stim.CircuitInstruction.__ne__\n\n# (in class stim.CircuitInstruction)\ndef __ne__(\n    self,\n    arg0: stim.CircuitInstruction,\n) -> bool:\n    \"\"\"Determines if two `stim.CircuitInstruction`s are different.\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.__repr__\"></a>\n```python\n# stim.CircuitInstruction.__repr__\n\n# (in class stim.CircuitInstruction)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CircuitInstruction`.\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.__str__\"></a>\n```python\n# stim.CircuitInstruction.__str__\n\n# (in class stim.CircuitInstruction)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns a text description of the instruction as a stim circuit file line.\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.gate_args_copy\"></a>\n```python\n# stim.CircuitInstruction.gate_args_copy\n\n# (in class stim.CircuitInstruction)\ndef gate_args_copy(\n    self,\n) -> List[float]:\n    \"\"\"Returns the gate's arguments (numbers parameterizing the instruction).\n\n    For noisy gates this typically a list of probabilities.\n    For OBSERVABLE_INCLUDE it's a singleton list containing the logical observable\n    index.\n\n    Examples:\n        >>> import stim\n        >>> instruction = stim.CircuitInstruction('X_ERROR', [2, 3], [0.125])\n        >>> instruction.gate_args_copy()\n        [0.125]\n\n        >>> instruction.gate_args_copy() == instruction.gate_args_copy()\n        True\n        >>> instruction.gate_args_copy() is instruction.gate_args_copy()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.name\"></a>\n```python\n# stim.CircuitInstruction.name\n\n# (in class stim.CircuitInstruction)\n@property\ndef name(\n    self,\n) -> str:\n    \"\"\"The name of the instruction (e.g. `H` or `X_ERROR` or `DETECTOR`).\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.num_measurements\"></a>\n```python\n# stim.CircuitInstruction.num_measurements\n\n# (in class stim.CircuitInstruction)\n@property\ndef num_measurements(\n    self,\n) -> int:\n    \"\"\"Returns the number of bits produced when running this instruction.\n\n    Examples:\n        >>> import stim\n        >>> stim.CircuitInstruction('H', [0]).num_measurements\n        0\n        >>> stim.CircuitInstruction('M', [0]).num_measurements\n        1\n        >>> stim.CircuitInstruction('M', [2, 3, 5, 7, 11]).num_measurements\n        5\n        >>> stim.CircuitInstruction('MXX', [0, 1, 4, 5, 11, 13]).num_measurements\n        3\n        >>> stim.Circuit('MPP X0*X1 X0*Z1*Y2')[0].num_measurements\n        2\n        >>> stim.CircuitInstruction('HERALDED_ERASE', [0], [0.25]).num_measurements\n        1\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.tag\"></a>\n```python\n# stim.CircuitInstruction.tag\n\n# (in class stim.CircuitInstruction)\n@property\ndef tag(\n    self,\n) -> str:\n    \"\"\"The custom tag attached to the instruction.\n\n    The tag is an arbitrary string.\n    The default tag, when none is specified, is the empty string.\n\n    Examples:\n        >>> import stim\n        >>> stim.Circuit(\"H[test] 0\")[0].tag\n        'test'\n        >>> stim.Circuit(\"H 0\")[0].tag\n        ''\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.target_groups\"></a>\n```python\n# stim.CircuitInstruction.target_groups\n\n# (in class stim.CircuitInstruction)\ndef target_groups(\n    self,\n) -> List[List[stim.GateTarget]]:\n    \"\"\"Splits the instruction's targets into groups depending on the type of gate.\n\n    Single qubit gates like H get one group per target.\n    Two qubit gates like CX get one group per pair of targets.\n    Pauli product gates like MPP get one group per combined product.\n\n    Returns:\n        A list of groups of targets.\n\n    Examples:\n        >>> import stim\n        >>> for g in stim.Circuit('H 0 1 2')[0].target_groups():\n        ...     print(repr(g))\n        [stim.GateTarget(0)]\n        [stim.GateTarget(1)]\n        [stim.GateTarget(2)]\n\n        >>> for g in stim.Circuit('CX 0 1 2 3')[0].target_groups():\n        ...     print(repr(g))\n        [stim.GateTarget(0), stim.GateTarget(1)]\n        [stim.GateTarget(2), stim.GateTarget(3)]\n\n        >>> for g in stim.Circuit('MPP X0*Y1*Z2 X5*X6')[0].target_groups():\n        ...     print(repr(g))\n        [stim.target_x(0), stim.target_y(1), stim.target_z(2)]\n        [stim.target_x(5), stim.target_x(6)]\n\n        >>> for g in stim.Circuit('DETECTOR rec[-1] rec[-2]')[0].target_groups():\n        ...     print(repr(g))\n        [stim.target_rec(-1)]\n        [stim.target_rec(-2)]\n\n        >>> for g in stim.Circuit('CORRELATED_ERROR(0.1) X0 Y1')[0].target_groups():\n        ...     print(repr(g))\n        [stim.target_x(0), stim.target_y(1)]\n    \"\"\"\n```\n\n<a name=\"stim.CircuitInstruction.targets_copy\"></a>\n```python\n# stim.CircuitInstruction.targets_copy\n\n# (in class stim.CircuitInstruction)\ndef targets_copy(\n    self,\n) -> List[stim.GateTarget]:\n    \"\"\"Returns a copy of the targets of the instruction.\n\n    Examples:\n        >>> import stim\n        >>> instruction = stim.CircuitInstruction('X_ERROR', [2, 3], [0.125])\n        >>> instruction.targets_copy()\n        [stim.GateTarget(2), stim.GateTarget(3)]\n\n        >>> instruction.targets_copy() == instruction.targets_copy()\n        True\n        >>> instruction.targets_copy() is instruction.targets_copy()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock\"></a>\n```python\n# stim.CircuitRepeatBlock\n\n# (at top-level in the stim module)\nclass CircuitRepeatBlock:\n    \"\"\"A REPEAT block from a circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     REPEAT 5 {\n        ...         CX 0 1\n        ...         CZ 1 2\n        ...     }\n        ... ''')\n        >>> repeat_block = circuit[1]\n        >>> repeat_block.repeat_count\n        5\n        >>> repeat_block.body_copy()\n        stim.Circuit('''\n            CX 0 1\n            CZ 1 2\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock.__eq__\"></a>\n```python\n# stim.CircuitRepeatBlock.__eq__\n\n# (in class stim.CircuitRepeatBlock)\ndef __eq__(\n    self,\n    arg0: stim.CircuitRepeatBlock,\n) -> bool:\n    \"\"\"Determines if two `stim.CircuitRepeatBlock`s are identical.\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock.__init__\"></a>\n```python\n# stim.CircuitRepeatBlock.__init__\n\n# (in class stim.CircuitRepeatBlock)\ndef __init__(\n    self,\n    repeat_count: int,\n    body: stim.Circuit,\n    *,\n    tag: str = '',\n) -> None:\n    \"\"\"Initializes a `stim.CircuitRepeatBlock`.\n\n    Args:\n        repeat_count: The number of times to repeat the block.\n        body: The body of the block, as a circuit.\n        tag: Defaults to empty. A custom string attached to the REPEAT instruction.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit()\n        >>> c.append(stim.CircuitRepeatBlock(100, stim.Circuit(\"M 0\")))\n        >>> c\n        stim.Circuit('''\n            REPEAT 100 {\n                M 0\n            }\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock.__ne__\"></a>\n```python\n# stim.CircuitRepeatBlock.__ne__\n\n# (in class stim.CircuitRepeatBlock)\ndef __ne__(\n    self,\n    arg0: stim.CircuitRepeatBlock,\n) -> bool:\n    \"\"\"Determines if two `stim.CircuitRepeatBlock`s are different.\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock.__repr__\"></a>\n```python\n# stim.CircuitRepeatBlock.__repr__\n\n# (in class stim.CircuitRepeatBlock)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns valid python code evaluating to an equivalent `stim.CircuitRepeatBlock`.\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock.body_copy\"></a>\n```python\n# stim.CircuitRepeatBlock.body_copy\n\n# (in class stim.CircuitRepeatBlock)\ndef body_copy(\n    self,\n) -> stim.Circuit:\n    \"\"\"Returns a copy of the body of the repeat block.\n\n    (Making a copy is enforced to make it clear that editing the result won't change\n    the block's body.)\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     REPEAT 5 {\n        ...         CX 0 1\n        ...         CZ 1 2\n        ...     }\n        ... ''')\n        >>> repeat_block = circuit[1]\n        >>> repeat_block.body_copy()\n        stim.Circuit('''\n            CX 0 1\n            CZ 1 2\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock.name\"></a>\n```python\n# stim.CircuitRepeatBlock.name\n\n# (in class stim.CircuitRepeatBlock)\n@property\ndef name(\n    self,\n) -> str:\n    \"\"\"Returns the name \"REPEAT\".\n\n    This is a duck-typing convenience method. It exists so that code that doesn't\n    know whether it has a `stim.CircuitInstruction` or a `stim.CircuitRepeatBlock`\n    can check the object's name without having to do an `instanceof` check first.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     REPEAT 5 {\n        ...         CX 1 2\n        ...     }\n        ...     S 1\n        ... ''')\n        >>> [instruction.name for instruction in circuit]\n        ['H', 'REPEAT', 'S']\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock.num_measurements\"></a>\n```python\n# stim.CircuitRepeatBlock.num_measurements\n\n# (in class stim.CircuitRepeatBlock)\n@property\ndef num_measurements(\n    self,\n) -> int:\n    \"\"\"Returns the number of bits produced when running this loop.\n\n    Examples:\n        >>> import stim\n        >>> stim.CircuitRepeatBlock(\n        ...     body=stim.Circuit(\"M 0 1\"),\n        ...     repeat_count=25,\n        ... ).num_measurements\n        50\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock.repeat_count\"></a>\n```python\n# stim.CircuitRepeatBlock.repeat_count\n\n# (in class stim.CircuitRepeatBlock)\n@property\ndef repeat_count(\n    self,\n) -> int:\n    \"\"\"The repetition count of the repeat block.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     REPEAT 5 {\n        ...         CX 0 1\n        ...         CZ 1 2\n        ...     }\n        ... ''')\n        >>> repeat_block = circuit[1]\n        >>> repeat_block.repeat_count\n        5\n    \"\"\"\n```\n\n<a name=\"stim.CircuitRepeatBlock.tag\"></a>\n```python\n# stim.CircuitRepeatBlock.tag\n\n# (in class stim.CircuitRepeatBlock)\n@property\ndef tag(\n    self,\n) -> str:\n    \"\"\"The custom tag attached to the REPEAT instruction.\n\n    The tag is an arbitrary string.\n    The default tag, when none is specified, is the empty string.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     REPEAT[test] 5 {\n        ...         H 0\n        ...     }\n        ... ''')[0].tag\n        'test'\n\n        >>> stim.Circuit('''\n        ...     REPEAT 5 {\n        ...         H 0\n        ...     }\n        ... ''')[0].tag\n        ''\n    \"\"\"\n```\n\n<a name=\"stim.CircuitTargetsInsideInstruction\"></a>\n```python\n# stim.CircuitTargetsInsideInstruction\n\n# (at top-level in the stim module)\nclass CircuitTargetsInsideInstruction:\n    \"\"\"Describes a range of targets within a circuit instruction.\n    \"\"\"\n```\n\n<a name=\"stim.CircuitTargetsInsideInstruction.__init__\"></a>\n```python\n# stim.CircuitTargetsInsideInstruction.__init__\n\n# (in class stim.CircuitTargetsInsideInstruction)\ndef __init__(\n    self,\n    *,\n    gate: str,\n    tag: str = '',\n    args: List[float],\n    target_range_start: int,\n    target_range_end: int,\n    targets_in_range: List[stim.GateTargetWithCoords],\n) -> None:\n    \"\"\"Creates a stim.CircuitTargetsInsideInstruction.\n\n    Examples:\n        >>> import stim\n        >>> val = stim.CircuitTargetsInsideInstruction(\n        ...     gate='X_ERROR',\n        ...     tag='',\n        ...     args=[0.25],\n        ...     target_range_start=0,\n        ...     target_range_end=1,\n        ...     targets_in_range=[stim.GateTargetWithCoords(0, [])],\n        ... )\n    \"\"\"\n```\n\n<a name=\"stim.CircuitTargetsInsideInstruction.args\"></a>\n```python\n# stim.CircuitTargetsInsideInstruction.args\n\n# (in class stim.CircuitTargetsInsideInstruction)\n@property\ndef args(\n    self,\n) -> List[float]:\n    \"\"\"Returns parens arguments of the gate / instruction that was being executed.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0 1\n        ...     X_ERROR(0.25) 0 1\n        ...     M 0 1\n        ...     DETECTOR(2, 3) rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n        >>> loc.instruction_targets.args\n        [0.25]\n    \"\"\"\n```\n\n<a name=\"stim.CircuitTargetsInsideInstruction.gate\"></a>\n```python\n# stim.CircuitTargetsInsideInstruction.gate\n\n# (in class stim.CircuitTargetsInsideInstruction)\n@property\ndef gate(\n    self,\n) -> Optional[str]:\n    \"\"\"Returns the name of the gate / instruction that was being executed.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0 1\n        ...     X_ERROR(0.25) 0 1\n        ...     M 0 1\n        ...     DETECTOR(2, 3) rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n        >>> loc.instruction_targets.gate\n        'X_ERROR'\n    \"\"\"\n```\n\n<a name=\"stim.CircuitTargetsInsideInstruction.tag\"></a>\n```python\n# stim.CircuitTargetsInsideInstruction.tag\n\n# (in class stim.CircuitTargetsInsideInstruction)\n@property\ndef tag(\n    self,\n) -> str:\n    \"\"\"Returns the tag of the gate / instruction that was being executed.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0 1\n        ...     X_ERROR[look-at-me-imma-tag](0.25) 0 1\n        ...     M 0 1\n        ...     DETECTOR(2, 3) rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n        >>> loc.instruction_targets.tag\n        'look-at-me-imma-tag'\n    \"\"\"\n```\n\n<a name=\"stim.CircuitTargetsInsideInstruction.target_range_end\"></a>\n```python\n# stim.CircuitTargetsInsideInstruction.target_range_end\n\n# (in class stim.CircuitTargetsInsideInstruction)\n@property\ndef target_range_end(\n    self,\n) -> int:\n    \"\"\"Returns the exclusive end of the range of targets that were executing\n    within the gate / instruction.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0 1\n        ...     X_ERROR(0.25) 0 1\n        ...     M 0 1\n        ...     DETECTOR(2, 3) rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n        >>> loc.instruction_targets.target_range_start\n        0\n        >>> loc.instruction_targets.target_range_end\n        1\n    \"\"\"\n```\n\n<a name=\"stim.CircuitTargetsInsideInstruction.target_range_start\"></a>\n```python\n# stim.CircuitTargetsInsideInstruction.target_range_start\n\n# (in class stim.CircuitTargetsInsideInstruction)\n@property\ndef target_range_start(\n    self,\n) -> int:\n    \"\"\"Returns the inclusive start of the range of targets that were executing\n    within the gate / instruction.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0 1\n        ...     X_ERROR(0.25) 0 1\n        ...     M 0 1\n        ...     DETECTOR(2, 3) rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n        >>> loc.instruction_targets.target_range_start\n        0\n        >>> loc.instruction_targets.target_range_end\n        1\n    \"\"\"\n```\n\n<a name=\"stim.CircuitTargetsInsideInstruction.targets_in_range\"></a>\n```python\n# stim.CircuitTargetsInsideInstruction.targets_in_range\n\n# (in class stim.CircuitTargetsInsideInstruction)\n@property\ndef targets_in_range(\n    self,\n) -> List[stim.GateTargetWithCoords]:\n    \"\"\"Returns the subset of targets of the gate/instruction that were being executed.\n\n    Includes coordinate data with the targets.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0 1\n        ...     X_ERROR(0.25) 0 1\n        ...     M 0 1\n        ...     DETECTOR(2, 3) rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n        >>> loc.instruction_targets.targets_in_range\n        [stim.GateTargetWithCoords(0, [])]\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString\"></a>\n```python\n# stim.CliffordString\n\n# (at top-level in the stim module)\nclass CliffordString:\n    \"\"\"A tensor product of single qubit Clifford gates (e.g. \"H \\u2297 X \\u2297 S\").\n\n    Represents a collection of Clifford operations applied pairwise to a\n    collection of qubits. Ignores global phase.\n\n    Examples:\n        >>> import stim\n        >>> stim.CliffordString(\"H,S,C_XYZ\") * stim.CliffordString(\"H,H,H\")\n        stim.CliffordString(\"I,C_ZYX,SQRT_X_DAG\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__add__\"></a>\n```python\n# stim.CliffordString.__add__\n\n# (in class stim.CliffordString)\ndef __add__(\n    self,\n    rhs: stim.CliffordString,\n) -> stim.CliffordString:\n    \"\"\"Concatenates two CliffordStrings.\n\n    Args:\n        rhs: The suffix of the concatenation.\n\n    Returns:\n        The concatenated Clifford string.\n\n    Examples:\n        >>> import stim\n        >>> stim.CliffordString(\"I,X,H\") + stim.CliffordString(\"Y,S\")\n        stim.CliffordString(\"I,X,H,Y,S\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__eq__\"></a>\n```python\n# stim.CliffordString.__eq__\n\n# (in class stim.CliffordString)\ndef __eq__(\n    self,\n    arg0: stim.CliffordString,\n) -> bool:\n    \"\"\"Determines if two Clifford strings have identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__getitem__\"></a>\n```python\n# stim.CliffordString.__getitem__\n\n# (in class stim.CliffordString)\n@overload\ndef __getitem__(\n    self,\n    index_or_slice: int,\n) -> stim.GateData:\n    pass\n@overload\ndef __getitem__(\n    self,\n    index_or_slice: slice,\n) -> stim.CliffordString:\n    pass\ndef __getitem__(\n    self,\n    index_or_slice: Union[int, slice],\n) -> Union[stim.GateData, stim.CliffordString]:\n    \"\"\"Returns a Clifford or substring from the CliffordString.\n\n    Args:\n        index_or_slice: The index of the Clifford to return, or the slice\n            corresponding to the sub CliffordString to return.\n\n    Returns:\n        The indexed Clifford (as a stim.GateData instance) or the sliced\n        CliffordString.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.CliffordString(\"I,X,Y,Z,H\")\n\n        >>> s[2]\n        stim.gate_data('Y')\n\n        >>> s[-1]\n        stim.gate_data('H')\n\n        >>> s[:-1]\n        stim.CliffordString(\"I,X,Y,Z\")\n\n        >>> s[::2]\n        stim.CliffordString(\"I,Y,H\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__iadd__\"></a>\n```python\n# stim.CliffordString.__iadd__\n\n# (in class stim.CliffordString)\ndef __iadd__(\n    self,\n    rhs: stim.CliffordString,\n) -> stim.CliffordString:\n    \"\"\"Mutates the CliffordString by concatenating onto it.\n\n    Args:\n        rhs: The suffix to concatenate onto the target CliffordString.\n\n    Returns:\n        The mutated Clifford string.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.CliffordString(\"I,X,H\")\n        >>> alias = c\n        >>> alias += stim.CliffordString(\"Y,S\")\n        >>> c\n        stim.CliffordString(\"I,X,H,Y,S\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__imul__\"></a>\n```python\n# stim.CliffordString.__imul__\n\n# (in class stim.CliffordString)\ndef __imul__(\n    self,\n    rhs: Union[stim.CliffordString, int],\n) -> stim.CliffordString:\n    \"\"\"Inplace CliffordString multiplication.\n\n    Mutates the CliffordString into itself multiplied by another CliffordString\n    (via pairwise Clifford multipliation) or by an integer (via repeating the\n    contents).\n\n    Args:\n        rhs: Either a stim.CliffordString or an int. If rhs is a\n            stim.CliffordString, then the Cliffords from each string are multiplied\n            pairwise. If rhs is an int, it is the number of times to repeat the\n            Clifford string's contents.\n\n    Returns:\n        The mutated Clifford string.\n\n    Examples:\n        >>> import stim\n\n        >>> c = stim.CliffordString(\"S,X,X\")\n        >>> alias = c\n        >>> alias *= stim.CliffordString(\"S,Z,H,Z\")\n        >>> c\n        stim.CliffordString(\"Z,Y,SQRT_Y,Z\")\n\n        >>> c = stim.CliffordString(\"I,X,H\")\n        >>> alias = c\n        >>> alias *= 2\n        >>> c\n        stim.CliffordString(\"I,X,H,I,X,H\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__init__\"></a>\n```python\n# stim.CliffordString.__init__\n\n# (in class stim.CliffordString)\ndef __init__(\n    self,\n    arg: Union[int, str, stim.CliffordString, stim.PauliString, stim.Circuit],\n    /,\n) -> None:\n    \"\"\"Initializes a stim.CliffordString from the given argument.\n\n    Args:\n        arg [position-only]: This can be a variety of types, including:\n            int: initializes an identity Clifford string of the given length.\n            str: initializes by parsing a comma-separated list of gate names.\n            stim.CliffordString: initializes by copying the given Clifford string.\n            stim.PauliString: initializes by copying from the given Pauli string\n                (ignores the sign of the Pauli string).\n            stim.Circuit: initializes a CliffordString equivalent to the action\n                of the circuit (as long as the circuit only contains single qubit\n                unitary operations and annotations).\n            Iterable: initializes by interpreting each item as a Clifford.\n                Each item can be a single-qubit Clifford gate name (like \"SQRT_X\")\n                or stim.GateData instance.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.CliffordString(5)\n        stim.CliffordString(\"I,I,I,I,I\")\n\n        >>> stim.CliffordString(\"X,Y,Z,SQRT_X\")\n        stim.CliffordString(\"X,Y,Z,SQRT_X\")\n\n        >>> stim.CliffordString([\"H\", stim.gate_data(\"S\")])\n        stim.CliffordString(\"H,S\")\n\n        >>> stim.CliffordString(stim.PauliString(\"XYZ\"))\n        stim.CliffordString(\"X,Y,Z\")\n\n        >>> stim.CliffordString(stim.CliffordString(\"X,Y,Z\"))\n        stim.CliffordString(\"X,Y,Z\")\n\n        >>> stim.CliffordString(stim.Circuit('''\n        ...     H 0 1 2\n        ...     S 2 3\n        ...     TICK\n        ...     S 3\n        ...     I 6\n        ... '''))\n        stim.CliffordString(\"H,H,C_ZYX,Z,I,I,I\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__ipow__\"></a>\n```python\n# stim.CliffordString.__ipow__\n\n# (in class stim.CliffordString)\ndef __ipow__(\n    self,\n    num_qubits: int,\n) -> object:\n    \"\"\"Mutates the CliffordString into itself raised to a power.\n\n    Args:\n        power: The power to raise the CliffordString's Cliffords to.\n            This value can be negative (e.g. -1 inverts the string).\n\n    Returns:\n        The mutated Clifford string.\n\n    Examples:\n        >>> import stim\n\n        >>> p = stim.CliffordString(\"I,X,H,S,C_XYZ\")\n        >>> p **= 3\n        >>> p\n        stim.CliffordString(\"I,X,H,S_DAG,I\")\n\n        >>> p **= 2\n        >>> p\n        stim.CliffordString(\"I,I,I,Z,I\")\n\n        >>> alias = p\n        >>> alias **= 2\n        >>> p\n        stim.CliffordString(\"I,I,I,I,I\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__len__\"></a>\n```python\n# stim.CliffordString.__len__\n\n# (in class stim.CliffordString)\ndef __len__(\n    self,\n) -> int:\n    \"\"\"Returns the number of Clifford operations in the string.\n\n    Examples:\n        >>> import stim\n        >>> len(stim.CliffordString(\"I,X,Y,Z,H\"))\n        5\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__mul__\"></a>\n```python\n# stim.CliffordString.__mul__\n\n# (in class stim.CliffordString)\ndef __mul__(\n    self,\n    rhs: Union[stim.CliffordString, int],\n) -> stim.CliffordString:\n    \"\"\"CliffordString multiplication.\n\n    Args:\n        rhs: Either a stim.CliffordString or an int. If rhs is a\n            stim.CliffordString, then the Cliffords from each string are multiplied\n            pairwise. If rhs is an int, it is the number of times to repeat the\n            Clifford string's contents.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.CliffordString(\"S,X,X\") * stim.CliffordString(\"S,Z,H,Z\")\n        stim.CliffordString(\"Z,Y,SQRT_Y,Z\")\n\n        >>> stim.CliffordString(\"I,X,H\") * 3\n        stim.CliffordString(\"I,X,H,I,X,H,I,X,H\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__ne__\"></a>\n```python\n# stim.CliffordString.__ne__\n\n# (in class stim.CliffordString)\ndef __ne__(\n    self,\n    arg0: stim.CliffordString,\n) -> bool:\n    \"\"\"Determines if two Clifford strings have non-identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__pow__\"></a>\n```python\n# stim.CliffordString.__pow__\n\n# (in class stim.CliffordString)\ndef __pow__(\n    self,\n    power: int,\n) -> stim.CliffordString:\n    \"\"\"Returns the CliffordString raised to a power.\n\n    Args:\n        power: The power to raise the CliffordString's Cliffords to.\n            This value can be negative (e.g. -1 returns the inverse string).\n\n    Returns:\n        The Clifford string raised to the power.\n\n    Examples:\n        >>> import stim\n\n        >>> p = stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n        >>> p**0\n        stim.CliffordString(\"I,I,I,I,I\")\n\n        >>> p**1\n        stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n        >>> p**12000001\n        stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n        >>> p**2\n        stim.CliffordString(\"I,I,I,Z,C_ZYX\")\n\n        >>> p**3\n        stim.CliffordString(\"I,X,H,S_DAG,I\")\n\n        >>> p**-1\n        stim.CliffordString(\"I,X,H,S_DAG,C_ZYX\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__repr__\"></a>\n```python\n# stim.CliffordString.__repr__\n\n# (in class stim.CliffordString)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CliffordString`.\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__rmul__\"></a>\n```python\n# stim.CliffordString.__rmul__\n\n# (in class stim.CliffordString)\ndef __rmul__(\n    self,\n    lhs: int,\n) -> stim.CliffordString:\n    \"\"\"CliffordString left-multiplication.\n\n    Args:\n        lhs: The number of times to repeat the Clifford string's contents.\n\n    Returns:\n        The repeated Clifford string.\n\n    Examples:\n        >>> import stim\n\n        >>> 2 * stim.CliffordString(\"I,X,H\")\n        stim.CliffordString(\"I,X,H,I,X,H\")\n\n        >>> 0 * stim.CliffordString(\"I,X,H\")\n        stim.CliffordString(\"\")\n\n        >>> 5 * stim.CliffordString(\"I\")\n        stim.CliffordString(\"I,I,I,I,I\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__setitem__\"></a>\n```python\n# stim.CliffordString.__setitem__\n\n# (in class stim.CliffordString)\ndef __setitem__(\n    self,\n    index_or_slice: Union[int, slice],\n    new_value: Union[str, stim.GateData, stim.CliffordString, stim.PauliString, stim.Tableau],\n) -> None:\n    \"\"\"Overwrites an indexed Clifford, or slice of Cliffords, with the given value.\n\n    Args:\n        index_or_slice: The index of the Clifford to overwrite, or the slice\n            of Cliffords to overwrite.\n        new_value: Specifies the value to write into the Clifford string. This can\n            be set to a few different types of values:\n            - str: Name of the single qubit Clifford gate to write to the index or\n                broadcast over the slice.\n            - stim.GateData: The single qubit Clifford gate to write to the index\n                or broadcast over the slice.\n            - stim.Tableau: Must be a single qubit tableau. Specifies the single\n                qubit Clifford gate to write to the index or broadcast over the\n                slice.\n            - stim.CliffordString: String of Cliffords to write into the slice.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.CliffordString(\"I,I,I,I,I\")\n\n        >>> s[1] = 'H'\n        >>> s\n        stim.CliffordString(\"I,H,I,I,I\")\n\n        >>> s[2:] = 'SQRT_X'\n        >>> s\n        stim.CliffordString(\"I,H,SQRT_X,SQRT_X,SQRT_X\")\n\n        >>> s[0] = stim.gate_data('S_DAG').inverse\n        >>> s\n        stim.CliffordString(\"S,H,SQRT_X,SQRT_X,SQRT_X\")\n\n        >>> s[:] = 'I'\n        >>> s\n        stim.CliffordString(\"I,I,I,I,I\")\n\n        >>> s[::2] = stim.CliffordString(\"X,Y,Z\")\n        >>> s\n        stim.CliffordString(\"X,I,Y,I,Z\")\n\n        >>> s[0] = stim.Tableau.from_named_gate(\"H\")\n        >>> s\n        stim.CliffordString(\"H,I,Y,I,Z\")\n\n        >>> s[:] = stim.Tableau.from_named_gate(\"S\")\n        >>> s\n        stim.CliffordString(\"S,S,S,S,S\")\n\n        >>> s[:4] = stim.PauliString(\"IXYZ\")\n        >>> s\n        stim.CliffordString(\"I,X,Y,Z,S\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.__str__\"></a>\n```python\n# stim.CliffordString.__str__\n\n# (in class stim.CliffordString)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns a string representation of the CliffordString's operations.\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.all_cliffords_string\"></a>\n```python\n# stim.CliffordString.all_cliffords_string\n\n# (in class stim.CliffordString)\n@staticmethod\ndef all_cliffords_string(\n) -> stim.CliffordString:\n    \"\"\"Returns a stim.CliffordString containing each single qubit Clifford once.\n\n    Useful for things like testing that a method works on every single Clifford.\n\n    Examples:\n        >>> import stim\n        >>> cliffords = stim.CliffordString.all_cliffords_string()\n        >>> len(cliffords)\n        24\n\n        >>> print(cliffords[:8])\n        I,X,Y,Z,H_XY,S,S_DAG,H_NXY\n\n        >>> print(cliffords[8:16])\n        H,SQRT_Y_DAG,H_NXZ,SQRT_Y,H_YZ,H_NYZ,SQRT_X,SQRT_X_DAG\n\n        >>> print(cliffords[16:])\n        C_XYZ,C_XYNZ,C_NXYZ,C_XNYZ,C_ZYX,C_ZNYX,C_NZYX,C_ZYNX\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.copy\"></a>\n```python\n# stim.CliffordString.copy\n\n# (in class stim.CliffordString)\ndef copy(\n    self,\n) -> stim.CliffordString:\n    \"\"\"Returns a copy of the CliffordString.\n\n    Returns:\n        The copy.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.CliffordString(\"H,X\")\n        >>> alias = c\n        >>> copy = c.copy()\n        >>> c *= 5\n        >>> alias\n        stim.CliffordString(\"H,X,H,X,H,X,H,X,H,X\")\n        >>> copy\n        stim.CliffordString(\"H,X\")\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.random\"></a>\n```python\n# stim.CliffordString.random\n\n# (in class stim.CliffordString)\n@staticmethod\ndef random(\n    num_qubits: int,\n) -> stim.CliffordString:\n    \"\"\"Samples a uniformly random CliffordString.\n\n    Args:\n        num_qubits: The number of qubits the CliffordString should act upon.\n\n    Examples:\n        >>> import stim\n        >>> p = stim.CliffordString.random(5)\n        >>> len(p)\n        5\n\n    Returns:\n        The sampled Clifford string.\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.x_outputs\"></a>\n```python\n# stim.CliffordString.x_outputs\n\n# (in class stim.CliffordString)\ndef x_outputs(\n    self,\n    *,\n    bit_packed_signs: bool = False,\n) -> Tuple[stim.PauliString, np.ndarray]:\n    \"\"\"Returns what each Clifford in the CliffordString conjugates an X input into.\n\n    For example, H conjugates X into +Z and S_DAG conjugates X into -Y.\n\n    Combined with `z_outputs`, the results of this method completely specify\n    the single qubit Clifford applied to each qubit.\n\n    Args:\n        bit_packed_signs: Defaults to False. When False, the sign data is returned\n            in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n            `np.uint8` and 8 bits are packed into each byte (in little endian\n            order).\n\n    Returns:\n        A (paulis, signs) tuple.\n\n        `paulis` has type stim.PauliString. Its sign is always positive.\n\n        `signs` has type np.ndarray and an argument-dependent shape:\n            bit_packed_signs=False:\n                dtype=np.bool_\n                shape=(num_qubits,)\n            bit_packed_signs=True:\n                dtype=np.uint8\n                shape=(math.ceil(num_qubits / 8),)\n\n    Examples:\n        >>> import stim\n        >>> x_paulis, x_signs = stim.CliffordString(\"I,Y,H,S\").x_outputs()\n        >>> x_paulis\n        stim.PauliString(\"+XXZY\")\n        >>> x_signs\n        array([False,  True, False, False])\n\n        >>> stim.CliffordString(\"I,Y,H,S\").x_outputs(bit_packed_signs=True)[1]\n        array([2], dtype=uint8)\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.y_outputs\"></a>\n```python\n# stim.CliffordString.y_outputs\n\n# (in class stim.CliffordString)\ndef y_outputs(\n    self,\n    *,\n    bit_packed_signs: bool = False,\n) -> Tuple[stim.PauliString, np.ndarray]:\n    \"\"\"Returns what each Clifford in the CliffordString conjugates a Y input into.\n\n    For example, H conjugates Y into -Y and S_DAG conjugates Y into +X.\n\n    Args:\n        bit_packed_signs: Defaults to False. When False, the sign data is returned\n            in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n            `np.uint8` and 8 bits are packed into each byte (in little endian\n            order).\n\n    Returns:\n        A (paulis, signs) tuple.\n\n        `paulis` has type stim.PauliString. Its sign is always positive.\n\n        `signs` has type np.ndarray and an argument-dependent shape:\n            bit_packed_signs=False:\n                dtype=np.bool_\n                shape=(num_qubits,)\n            bit_packed_signs=True:\n                dtype=np.uint8\n                shape=(math.ceil(num_qubits / 8),)\n\n    Examples:\n        >>> import stim\n        >>> y_paulis, y_signs = stim.CliffordString(\"I,X,H,S\").y_outputs()\n        >>> y_paulis\n        stim.PauliString(\"+YYYX\")\n        >>> y_signs\n        array([False,  True,  True,  True])\n\n        >>> stim.CliffordString(\"I,X,H,S\").y_outputs(bit_packed_signs=True)[1]\n        array([14], dtype=uint8)\n    \"\"\"\n```\n\n<a name=\"stim.CliffordString.z_outputs\"></a>\n```python\n# stim.CliffordString.z_outputs\n\n# (in class stim.CliffordString)\ndef z_outputs(\n    self,\n    *,\n    bit_packed_signs: bool = False,\n) -> Tuple[stim.PauliString, np.ndarray]:\n    \"\"\"Returns what each Clifford in the CliffordString conjugates a Z input into.\n\n    For example, H conjugates Z into +X and SQRT_X conjugates Z into -Y.\n\n    Combined with `x_outputs`, the results of this method completely specify\n    the single qubit Clifford applied to each qubit.\n\n    Args:\n        bit_packed_signs: Defaults to False. When False, the sign data is returned\n            in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n            `np.uint8` and 8 bits are packed into each byte (in little endian\n            order).\n\n    Returns:\n        A (paulis, signs) tuple.\n\n        `paulis` has type stim.PauliString. Its sign is always positive.\n\n        `signs` has type np.ndarray and an argument-dependent shape:\n            bit_packed_signs=False:\n                dtype=np.bool_\n                shape=(num_qubits,)\n            bit_packed_signs=True:\n                dtype=np.uint8\n                shape=(math.ceil(num_qubits / 8),)\n\n    Examples:\n        >>> import stim\n        >>> z_paulis, z_signs = stim.CliffordString(\"I,Y,H,S\").z_outputs()\n        >>> z_paulis\n        stim.PauliString(\"+ZZXZ\")\n        >>> z_signs\n        array([False,  True, False, False])\n\n        >>> stim.CliffordString(\"I,Y,H,S\").z_outputs(bit_packed_signs=True)[1]\n        array([2], dtype=uint8)\n    \"\"\"\n```\n\n<a name=\"stim.CompiledDemSampler\"></a>\n```python\n# stim.CompiledDemSampler\n\n# (at top-level in the stim module)\nclass CompiledDemSampler:\n    \"\"\"A helper class for efficiently sampler from a detector error model.\n\n    Examples:\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...    error(0) D0\n        ...    error(1) D1 D2 L0\n        ... ''')\n        >>> sampler = dem.compile_sampler()\n        >>> det_data, obs_data, err_data = sampler.sample(\n        ...     shots=4,\n        ...     return_errors=True)\n        >>> det_data\n        array([[False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True]])\n        >>> obs_data\n        array([[ True],\n               [ True],\n               [ True],\n               [ True]])\n        >>> err_data\n        array([[False,  True],\n               [False,  True],\n               [False,  True],\n               [False,  True]])\n    \"\"\"\n```\n\n<a name=\"stim.CompiledDemSampler.sample\"></a>\n```python\n# stim.CompiledDemSampler.sample\n\n# (in class stim.CompiledDemSampler)\ndef sample(\n    self,\n    shots: int,\n    *,\n    bit_packed: bool = False,\n    return_errors: bool = False,\n    recorded_errors_to_replay: Optional[np.ndarray] = None,\n) -> Tuple[np.ndarray, np.ndarray, Optional[np.ndarray]]:\n    \"\"\"Samples the detector error model's error mechanisms to produce sample data.\n\n    Args:\n        shots: The number of times to sample from the model.\n        bit_packed: Defaults to false.\n            False: the returned numpy arrays have dtype=np.bool_.\n            True: the returned numpy arrays have dtype=np.uint8 and pack 8 bits into\n                each byte.\n\n            Setting this to True is equivalent to running\n            `np.packbits(data, bitorder='little', axis=1)` on each output value, but\n            has the performance benefit of the data never being expanded into an\n            unpacked form.\n        return_errors: Defaults to False.\n            False: the third entry of the returned tuple is None.\n            True: the third entry of the returned tuple is a numpy array recording\n            which errors were sampled.\n        recorded_errors_to_replay: Defaults to None, meaning sample errors randomly.\n            If not None, this is expected to be a 2d numpy array specifying which\n            errors to apply (e.g. one returned from a previous call to the sample\n            method). The array must have dtype=np.bool_ and\n            shape=(num_shots, num_errors) or dtype=np.uint8 and\n            shape=(num_shots, math.ceil(num_errors / 8)).\n\n    Returns:\n        A tuple (detector_data, obs_data, error_data).\n\n        Assuming bit_packed is False and return_errors is True:\n            - If error_data[s, k] is True, then the error with index k fired in the\n                shot with index s.\n            - If detector_data[s, k] is True, then the detector with index k ended\n                up flipped in the shot with index s.\n            - If obs_data[s, k] is True, then the observable with index k ended up\n                flipped in the shot with index s.\n\n        The dtype and shape of the data depends on the arguments:\n            if bit_packed:\n                detector_data.shape == (num_shots, math.ceil(num_detectors / 8))\n                detector_data.dtype == np.uint8\n                obs_data.shape == (num_shots, math.ceil(num_observables / 8))\n                obs_data.dtype == np.uint8\n                if return_errors:\n                    error_data.shape = (num_shots, math.ceil(num_errors / 8))\n                    error_data.dtype = np.uint8\n                else:\n                    error_data is None\n            else:\n                detector_data.shape == (num_shots, num_detectors)\n                detector_data.dtype == np.bool_\n                obs_data.shape == (num_shots, num_observables)\n                obs_data.dtype == np.bool_\n                if return_errors:\n                    error_data.shape = (num_shots, num_errors)\n                    error_data.dtype = np.bool_\n                else:\n                    error_data is None\n\n        Note that bit packing is done using little endian order on the last axis\n        (i.e. like `np.packbits(data, bitorder='little', axis=1)`).\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n        >>> dem = stim.DetectorErrorModel('''\n        ...    error(0) D0\n        ...    error(1) D1 D2 L0\n        ... ''')\n        >>> sampler = dem.compile_sampler()\n\n        >>> # Taking samples.\n        >>> det_data, obs_data, err_data_not_requested = sampler.sample(shots=4)\n        >>> det_data\n        array([[False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True]])\n        >>> obs_data\n        array([[ True],\n               [ True],\n               [ True],\n               [ True]])\n        >>> err_data_not_requested is None\n        True\n\n        >>> # Recording errors.\n        >>> det_data, obs_data, err_data = sampler.sample(\n        ...     shots=4,\n        ...     return_errors=True)\n        >>> det_data\n        array([[False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True]])\n        >>> obs_data\n        array([[ True],\n               [ True],\n               [ True],\n               [ True]])\n        >>> err_data\n        array([[False,  True],\n               [False,  True],\n               [False,  True],\n               [False,  True]])\n\n        >>> # Bit packing.\n        >>> det_data, obs_data, err_data = sampler.sample(\n        ...     shots=4,\n        ...     return_errors=True,\n        ...     bit_packed=True)\n        >>> det_data\n        array([[6],\n               [6],\n               [6],\n               [6]], dtype=uint8)\n        >>> obs_data\n        array([[1],\n               [1],\n               [1],\n               [1]], dtype=uint8)\n        >>> err_data\n        array([[2],\n               [2],\n               [2],\n               [2]], dtype=uint8)\n\n        >>> # Recording and replaying errors.\n        >>> noisy_dem = stim.DetectorErrorModel('''\n        ...    error(0.125) D0\n        ...    error(0.25) D1\n        ... ''')\n        >>> noisy_sampler = noisy_dem.compile_sampler()\n        >>> det_data, obs_data, err_data = noisy_sampler.sample(\n        ...     shots=100,\n        ...     return_errors=True)\n        >>> replay_det_data, replay_obs_data, _ = noisy_sampler.sample(\n        ...     shots=100,\n        ...     recorded_errors_to_replay=err_data)\n        >>> np.array_equal(det_data, replay_det_data)\n        True\n        >>> np.array_equal(obs_data, replay_obs_data)\n        True\n    \"\"\"\n```\n\n<a name=\"stim.CompiledDemSampler.sample_write\"></a>\n```python\n# stim.CompiledDemSampler.sample_write\n\n# (in class stim.CompiledDemSampler)\ndef sample_write(\n    self,\n    shots: int,\n    *,\n    det_out_file: Union[None, str, pathlib.Path],\n    det_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    obs_out_file: Union[None, str, pathlib.Path],\n    obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    err_out_file: Union[None, str, pathlib.Path] = None,\n    err_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    replay_err_in_file: Union[None, str, pathlib.Path] = None,\n    replay_err_in_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n) -> None:\n    \"\"\"Samples the detector error model and writes the results to disk.\n\n    Args:\n        shots: The number of times to sample from the model.\n        det_out_file: Where to write detection event data.\n            If None: detection event data is not written.\n            If str or pathlib.Path: opens and overwrites the file at the given path.\n            NOT IMPLEMENTED: io.IOBase\n        det_out_format: The format to write the detection event data in\n            (e.g. \"01\" or \"b8\").\n        obs_out_file: Where to write observable flip data.\n            If None: observable flip data is not written.\n            If str or pathlib.Path: opens and overwrites the file at the given path.\n            NOT IMPLEMENTED: io.IOBase\n        obs_out_format: The format to write the observable flip data in\n            (e.g. \"01\" or \"b8\").\n        err_out_file: Where to write errors-that-occurred data.\n            If None: errors-that-occurred data is not written.\n            If str or pathlib.Path: opens and overwrites the file at the given path.\n            NOT IMPLEMENTED: io.IOBase\n        err_out_format: The format to write the errors-that-occurred data in\n            (e.g. \"01\" or \"b8\").\n        replay_err_in_file: If this is specified, errors are replayed from data\n            instead of generated randomly. The following types are supported:\n            - None: errors are generated randomly according to the probabilities\n                in the detector error model.\n            - str or pathlib.Path: the file at the given path is opened and\n                errors-to-apply data is read from there.\n            - io.IOBase: NOT IMPLEMENTED\n        replay_err_in_format: The format to write the errors-that-occurred data in\n            (e.g. \"01\" or \"b8\").\n\n    Returns:\n        Nothing. Results are written to disk.\n\n    Examples:\n        >>> import stim\n        >>> import tempfile\n        >>> import pathlib\n        >>> dem = stim.DetectorErrorModel('''\n        ...    error(0) D0\n        ...    error(0) D1\n        ...    error(0) D0\n        ...    error(1) D1 D2 L0\n        ...    error(0) D0\n        ... ''')\n        >>> sampler = dem.compile_sampler()\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     d = pathlib.Path(d)\n        ...     sampler.sample_write(\n        ...         shots=1,\n        ...         det_out_file=d / 'dets.01',\n        ...         det_out_format='01',\n        ...         obs_out_file=d / 'obs.01',\n        ...         obs_out_format='01',\n        ...         err_out_file=d / 'err.hits',\n        ...         err_out_format='hits',\n        ...     )\n        ...     with open(d / 'dets.01') as f:\n        ...         assert f.read() == \"011\\n\"\n        ...     with open(d / 'obs.01') as f:\n        ...         assert f.read() == \"1\\n\"\n        ...     with open(d / 'err.hits') as f:\n        ...         assert f.read() == \"3\\n\"\n    \"\"\"\n```\n\n<a name=\"stim.CompiledDetectorSampler\"></a>\n```python\n# stim.CompiledDetectorSampler\n\n# (at top-level in the stim module)\nclass CompiledDetectorSampler:\n    \"\"\"An analyzed stabilizer circuit whose detection events can be sampled quickly.\n    \"\"\"\n```\n\n<a name=\"stim.CompiledDetectorSampler.__init__\"></a>\n```python\n# stim.CompiledDetectorSampler.__init__\n\n# (in class stim.CompiledDetectorSampler)\ndef __init__(\n    self,\n    circuit: stim.Circuit,\n    *,\n    seed: object = None,\n) -> None:\n    \"\"\"Creates an object that can sample the detection events from a circuit.\n\n    Args:\n        circuit: The circuit to sample from.\n        seed: PARTIALLY determines simulation results by deterministically seeding\n            the random number generator.\n\n            Must be None or an integer in range(2**64).\n\n            Defaults to None. When None, the prng is seeded from system entropy.\n\n            When set to an integer, making the exact same series calls on the exact\n            same machine with the exact same version of Stim will produce the exact\n            same simulation results.\n\n            CAUTION: simulation results *WILL NOT* be consistent between versions of\n            Stim. This restriction is present to make it possible to have future\n            optimizations to the random sampling, and is enforced by introducing\n            intentional differences in the seeding strategy from version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines that\n            differ in the width of supported SIMD instructions. For example, using\n            the same seed on a machine that supports AVX instructions and one that\n            only supports SSE instructions may produce different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n            shots are taken. For example, taking 10 shots and then 90 shots will\n            give different results from taking 100 shots in one call.\n\n    Returns:\n        An initialized stim.CompiledDetectorSampler.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    H 0\n        ...    CNOT 0 1\n        ...    X_ERROR(1.0) 0\n        ...    M 0 1\n        ...    DETECTOR rec[-1] rec[-2]\n        ... ''')\n        >>> s = c.compile_detector_sampler()\n        >>> s.sample(shots=1)\n        array([[ True]])\n    \"\"\"\n```\n\n<a name=\"stim.CompiledDetectorSampler.__repr__\"></a>\n```python\n# stim.CompiledDetectorSampler.__repr__\n\n# (in class stim.CompiledDetectorSampler)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns valid python code evaluating to an equivalent `stim.CompiledDetectorSampler`.\n    \"\"\"\n```\n\n<a name=\"stim.CompiledDetectorSampler.sample\"></a>\n```python\n# stim.CompiledDetectorSampler.sample\n\n# (in class stim.CompiledDetectorSampler)\ndef sample(\n    self,\n    shots: int,\n    *,\n    prepend_observables: bool = False,\n    append_observables: bool = False,\n    separate_observables: bool = False,\n    bit_packed: bool = False,\n    dets_out: Optional[np.ndarray] = None,\n    obs_out: Optional[np.ndarray] = None,\n) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:\n    \"\"\"Returns a numpy array containing a batch of detector samples from the circuit.\n\n    The circuit must define the detectors using DETECTOR instructions. Observables\n    defined by OBSERVABLE_INCLUDE instructions can also be included in the results\n    as honorary detectors.\n\n    Args:\n        shots: The number of times to sample every detector in the circuit.\n        separate_observables: Defaults to False. When set to True, the return value\n            is a (detection_events, observable_flips) tuple instead of a flat\n            detection_events array.\n        prepend_observables: Defaults to false. When set, observables are included\n            with the detectors and are placed at the start of the results.\n        append_observables: Defaults to false. When set, observables are included\n            with the detectors and are placed at the end of the results.\n        bit_packed: Returns a uint8 numpy array with 8 bits per byte, instead of\n            a bool_ numpy array with 1 bit per byte. Uses little endian packing.\n        dets_out: Defaults to None. Specifies a pre-allocated numpy array to write\n            the detection event data into. This array must have the correct shape\n            and dtype.\n        obs_out: Defaults to None. Specifies a pre-allocated numpy array to write\n            the observable flip data into. This array must have the correct shape\n            and dtype.\n\n    Returns:\n        A numpy array or tuple of numpy arrays containing the samples.\n\n        if separate_observables=False and bit_packed=False:\n            A single numpy array.\n            dtype=bool_\n            shape=(\n                shots,\n                num_detectors + num_observables * (\n                    append_observables + prepend_observables),\n            )\n            The bit for detection event `m` in shot `s` is at\n                result[s, m]\n\n        if separate_observables=False and bit_packed=True:\n            A single numpy array.\n            dtype=uint8\n            shape=(\n                shots,\n                math.ceil((num_detectors + num_observables * (\n                    append_observables + prepend_observables)) / 8),\n            )\n            The bit for detection event `m` in shot `s` is at\n                (result[s, m // 8] >> (m % 8)) & 1\n\n        if separate_observables=True and bit_packed=False:\n            A (dets, obs) tuple.\n            dets.dtype=bool_\n            dets.shape=(shots, num_detectors)\n            obs.dtype=bool_\n            obs.shape=(shots, num_observables)\n            The bit for detection event `m` in shot `s` is at\n                dets[s, m]\n            The bit for observable `m` in shot `s` is at\n                obs[s, m]\n\n        if separate_observables=True and bit_packed=True:\n            A (dets, obs) tuple.\n            dets.dtype=uint8\n            dets.shape=(shots, math.ceil(num_detectors / 8))\n            obs.dtype=uint8\n            obs.shape=(shots, math.ceil(num_observables / 8))\n            The bit for detection event `m` in shot `s` is at\n                (dets[s, m // 8] >> (m % 8)) & 1\n            The bit for observable `m` in shot `s` is at\n                (obs[s, m // 8] >> (m % 8)) & 1\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    H 0\n        ...    CNOT 0 1\n        ...    X_ERROR(1.0) 0\n        ...    M 0 1\n        ...    DETECTOR rec[-1] rec[-2]\n        ... ''')\n        >>> s = c.compile_detector_sampler()\n        >>> s.sample(shots=1)\n        array([[ True]])\n    \"\"\"\n```\n\n<a name=\"stim.CompiledDetectorSampler.sample_write\"></a>\n```python\n# stim.CompiledDetectorSampler.sample_write\n\n# (in class stim.CompiledDetectorSampler)\ndef sample_write(\n    self,\n    shots: int,\n    *,\n    filepath: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    obs_out_filepath: Optional[Union[str, pathlib.Path]] = None,\n    obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    prepend_observables: bool = False,\n    append_observables: bool = False,\n) -> None:\n    \"\"\"Samples detection events from the circuit and writes them to a file.\n\n    Args:\n        shots: The number of times to sample every measurement in the circuit.\n        filepath: The file to write the results to.\n        format: The output format to write the results with.\n            Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n            Defaults to \"01\".\n        obs_out_filepath: Sample observables as part of each shot, and write them to\n            this file. This keeps the observable data separate from the detector\n            data.\n        obs_out_format: If writing the observables to a file, this is the format to\n            write them in.\n\n            Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n            Defaults to \"01\".\n        prepend_observables: Sample observables as part of each shot, and put them\n            at the start of the detector data.\n        append_observables: Sample observables as part of each shot, and put them at\n            the end of the detector data.\n\n    Returns:\n        None.\n\n    Examples:\n        >>> import stim\n        >>> import tempfile\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = f\"{d}/tmp.dat\"\n        ...     c = stim.Circuit('''\n        ...         X_ERROR(1) 0\n        ...         M 0 1\n        ...         DETECTOR rec[-2]\n        ...         DETECTOR rec[-1]\n        ...     ''')\n        ...     c.compile_detector_sampler().sample_write(\n        ...         shots=3,\n        ...         filepath=path,\n        ...         format=\"dets\")\n        ...     with open(path) as f:\n        ...         print(f.read(), end='')\n        shot D0\n        shot D0\n        shot D0\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementSampler\"></a>\n```python\n# stim.CompiledMeasurementSampler\n\n# (at top-level in the stim module)\nclass CompiledMeasurementSampler:\n    \"\"\"An analyzed stabilizer circuit whose measurements can be sampled quickly.\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementSampler.__init__\"></a>\n```python\n# stim.CompiledMeasurementSampler.__init__\n\n# (in class stim.CompiledMeasurementSampler)\ndef __init__(\n    self,\n    circuit: stim.Circuit,\n    *,\n    skip_reference_sample: bool = False,\n    seed: object = None,\n    reference_sample: object = None,\n) -> None:\n    \"\"\"Creates a measurement sampler for the given circuit.\n\n    The sampler uses a noiseless reference sample, collected from the circuit using\n    stim's Tableau simulator during initialization of the sampler, as a baseline for\n    deriving more samples using an error propagation simulator.\n\n    Args:\n        circuit: The stim circuit to sample from.\n        skip_reference_sample: Defaults to False. When set to True, the reference\n            sample used by the sampler is initialized to all-zeroes instead of being\n            collected from the circuit. This means that the results returned by the\n            sampler are actually whether or not each measurement was *flipped*,\n            instead of true measurement results.\n\n            Forcing an all-zero reference sample is useful when you are only\n            interested in error propagation and don't want to have to deal with the\n            fact that some measurements want to be On when no errors occur. It is\n            also useful when you know for sure that the all-zero result is actually\n            a possible result from the circuit (under noiseless execution), meaning\n            it is a valid reference sample as good as any other. Computing the\n            reference sample is the most time consuming and memory intensive part of\n            simulating the circuit, so promising that the simulator can safely skip\n            that step is an effective optimization.\n        seed: PARTIALLY determines simulation results by deterministically seeding\n            the random number generator.\n\n            Must be None or an integer in range(2**64).\n\n            Defaults to None. When None, the prng is seeded from system entropy.\n\n            When set to an integer, making the exact same series calls on the exact\n            same machine with the exact same version of Stim will produce the exact\n            same simulation results.\n\n            CAUTION: simulation results *WILL NOT* be consistent between versions of\n            Stim. This restriction is present to make it possible to have future\n            optimizations to the random sampling, and is enforced by introducing\n            intentional differences in the seeding strategy from version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines that\n            differ in the width of supported SIMD instructions. For example, using\n            the same seed on a machine that supports AVX instructions and one that\n            only supports SSE instructions may produce different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n            shots are taken. For example, taking 10 shots and then 90 shots will\n            give different results from taking 100 shots in one call.\n        reference_sample: The data to xor into the measurement flips produced by the\n            frame simulator, in order to produce proper measurement results.\n            This can either be specified as an `np.bool_` array or a bit packed\n            `np.uint8` array (little endian). Under normal conditions, the reference\n            sample should be a valid noiseless sample of the circuit, such as the\n            one returned by `circuit.reference_sample()`. If this argument is not\n            provided, the reference sample will be set to\n            `circuit.reference_sample()`, unless `skip_reference_sample=True`\n            is used, in which case it will be set to all-zeros.\n\n    Returns:\n        An initialized stim.CompiledMeasurementSampler.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    X 0   2 3\n        ...    M 0 1 2 3\n        ... ''')\n        >>> s = c.compile_sampler()\n        >>> s.sample(shots=1)\n        array([[ True, False,  True,  True]])\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementSampler.__repr__\"></a>\n```python\n# stim.CompiledMeasurementSampler.__repr__\n\n# (in class stim.CompiledMeasurementSampler)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CompiledMeasurementSampler`.\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementSampler.sample\"></a>\n```python\n# stim.CompiledMeasurementSampler.sample\n\n# (in class stim.CompiledMeasurementSampler)\ndef sample(\n    self,\n    shots: int,\n    *,\n    bit_packed: bool = False,\n) -> np.ndarray:\n    \"\"\"Samples a batch of measurement samples from the circuit.\n\n    Args:\n        shots: The number of times to sample every measurement in the circuit.\n        bit_packed: Returns a uint8 numpy array with 8 bits per byte, instead of\n            a bool_ numpy array with 1 bit per byte. Uses little endian packing.\n\n    Returns:\n        A numpy array containing the samples.\n\n        If bit_packed=False:\n            dtype=bool_\n            shape=(shots, circuit.num_measurements)\n            The bit for measurement `m` in shot `s` is at\n                result[s, m]\n        If bit_packed=True:\n            dtype=uint8\n            shape=(shots, math.ceil(circuit.num_measurements / 8))\n            The bit for measurement `m` in shot `s` is at\n                (result[s, m // 8] >> (m % 8)) & 1\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit('''\n        ...    X 0   2 3\n        ...    M 0 1 2 3\n        ... ''')\n        >>> s = c.compile_sampler()\n        >>> s.sample(shots=1)\n        array([[ True, False,  True,  True]])\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementSampler.sample_write\"></a>\n```python\n# stim.CompiledMeasurementSampler.sample_write\n\n# (in class stim.CompiledMeasurementSampler)\ndef sample_write(\n    self,\n    shots: int,\n    *,\n    filepath: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n) -> None:\n    \"\"\"Samples measurements from the circuit and writes them to a file.\n\n    Examples:\n        >>> import stim\n        >>> import tempfile\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = f\"{d}/tmp.dat\"\n        ...     c = stim.Circuit('''\n        ...         X 0   2 3\n        ...         M 0 1 2 3\n        ...     ''')\n        ...     c.compile_sampler().sample_write(5, filepath=path, format=\"01\")\n        ...     with open(path) as f:\n        ...         print(f.read(), end='')\n        1011\n        1011\n        1011\n        1011\n        1011\n\n    Args:\n        shots: The number of times to sample every measurement in the circuit.\n        filepath: The file to write the results to.\n        format: The output format to write the results with.\n            Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n            Defaults to \"01\".\n\n    Returns:\n        None.\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementsToDetectionEventsConverter\"></a>\n```python\n# stim.CompiledMeasurementsToDetectionEventsConverter\n\n# (at top-level in the stim module)\nclass CompiledMeasurementsToDetectionEventsConverter:\n    \"\"\"A tool for quickly converting measurements from an analyzed stabilizer circuit into detection events.\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementsToDetectionEventsConverter.__init__\"></a>\n```python\n# stim.CompiledMeasurementsToDetectionEventsConverter.__init__\n\n# (in class stim.CompiledMeasurementsToDetectionEventsConverter)\ndef __init__(\n    self,\n    circuit: stim.Circuit,\n    *,\n    skip_reference_sample: bool = False,\n) -> None:\n    \"\"\"Creates a measurement-to-detection-events converter for the given circuit.\n\n    The converter uses a noiseless reference sample, collected from the circuit\n    using stim's Tableau simulator during initialization of the converter, as a\n    baseline for determining what the expected value of a detector is.\n\n    Note that the expected behavior of gauge detectors (detectors that are not\n    actually deterministic under noiseless execution) can vary depending on the\n    reference sample. Stim mitigates this by always generating the same reference\n    sample for a given circuit.\n\n    Args:\n        circuit: The stim circuit to use for conversions.\n        skip_reference_sample: Defaults to False. When set to True, the reference\n            sample used by the converter is initialized to all-zeroes instead of\n            being collected from the circuit. This should only be used if it's known\n            that the all-zeroes sample is actually a possible result from the\n            circuit (under noiseless execution).\n\n    Returns:\n        An initialized stim.CompiledMeasurementsToDetectionEventsConverter.\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n        >>> converter = stim.Circuit('''\n        ...    X 0\n        ...    M 0\n        ...    DETECTOR rec[-1]\n        ... ''').compile_m2d_converter()\n        >>> converter.convert(\n        ...     measurements=np.array([[0], [1]], dtype=np.bool_),\n        ...     append_observables=False,\n        ... )\n        array([[ True],\n               [False]])\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementsToDetectionEventsConverter.__repr__\"></a>\n```python\n# stim.CompiledMeasurementsToDetectionEventsConverter.__repr__\n\n# (in class stim.CompiledMeasurementsToDetectionEventsConverter)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CompiledMeasurementsToDetectionEventsConverter`.\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementsToDetectionEventsConverter.convert\"></a>\n```python\n# stim.CompiledMeasurementsToDetectionEventsConverter.convert\n\n# (in class stim.CompiledMeasurementsToDetectionEventsConverter)\n@overload\ndef convert(\n    self,\n    *,\n    measurements: np.ndarray,\n    sweep_bits: Optional[np.ndarray] = None,\n    append_observables: bool = False,\n    bit_packed: bool = False,\n) -> np.ndarray:\n    pass\n@overload\ndef convert(\n    self,\n    *,\n    measurements: np.ndarray,\n    sweep_bits: Optional[np.ndarray] = None,\n    separate_observables: Literal[True],\n    append_observables: bool = False,\n    bit_packed: bool = False,\n) -> Tuple[np.ndarray, np.ndarray]:\n    pass\ndef convert(\n    self,\n    *,\n    measurements: np.ndarray,\n    sweep_bits: Optional[np.ndarray] = None,\n    separate_observables: bool = False,\n    append_observables: bool = False,\n    bit_packed: bool = False,\n) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:\n    \"\"\"Converts measurement data into detection event data.\n\n    Args:\n        measurements: A numpy array containing measurement data.\n\n            The dtype of the array is used to determine if it is bit packed or not.\n            dtype=np.bool_ (unpacked data):\n                shape=(num_shots, circuit.num_measurements)\n            dtype=np.uint8 (bit packed data):\n                shape=(num_shots, math.ceil(circuit.num_measurements / 8))\n        sweep_bits: Optional. A numpy array containing sweep data for the `sweep[k]`\n            controls in the circuit.\n\n            The dtype of the array is used to determine if it is bit packed or not.\n            dtype=np.bool_ (unpacked data):\n                shape=(num_shots, circuit.num_sweep_bits)\n            dtype=np.uint8 (bit packed data):\n                shape=(num_shots, math.ceil(circuit.num_sweep_bits / 8))\n        separate_observables: Defaults to False. When set to True, two numpy arrays\n            are returned instead of one, with the second array containing the\n            observable flip data.\n        append_observables: Defaults to False. When set to True, the observables in\n            the circuit are treated as if they were additional detectors. Their\n            results are appended to the end of the detection event data.\n        bit_packed: Defaults to False. When set to True, the returned numpy\n            array contains bit packed data (dtype=np.uint8 with 8 bits per item)\n            instead of unpacked data (dtype=np.bool_).\n\n    Returns:\n        The detection event data and (optionally) observable data. The result is a\n        single numpy array if separate_observables is false, otherwise it's a tuple\n        of two numpy arrays.\n\n        When returning two numpy arrays, the first array is the detection event data\n        and the second is the observable flip data.\n\n        The dtype of the returned arrays is np.bool_ if bit_packed is false,\n        otherwise they're np.uint8 arrays.\n\n        shape[0] of the array(s) is the number of shots.\n        shape[1] of the array(s) is the number of bits per shot (divided by 8 if bit\n        packed) (e.g. for just detection event data it would be\n        circuit.num_detectors).\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n        >>> converter = stim.Circuit('''\n        ...    X 0\n        ...    M 0 1\n        ...    DETECTOR rec[-1]\n        ...    DETECTOR rec[-2]\n        ...    OBSERVABLE_INCLUDE(0) rec[-2]\n        ... ''').compile_m2d_converter()\n        >>> dets, obs = converter.convert(\n        ...     measurements=np.array([[1, 0],\n        ...                            [1, 0],\n        ...                            [1, 0],\n        ...                            [0, 0],\n        ...                            [1, 0]], dtype=np.bool_),\n        ...     separate_observables=True,\n        ... )\n        >>> dets\n        array([[False, False],\n               [False, False],\n               [False, False],\n               [False,  True],\n               [False, False]])\n        >>> obs\n        array([[False],\n               [False],\n               [False],\n               [ True],\n               [False]])\n    \"\"\"\n```\n\n<a name=\"stim.CompiledMeasurementsToDetectionEventsConverter.convert_file\"></a>\n```python\n# stim.CompiledMeasurementsToDetectionEventsConverter.convert_file\n\n# (in class stim.CompiledMeasurementsToDetectionEventsConverter)\ndef convert_file(\n    self,\n    *,\n    measurements_filepath: Union[str, pathlib.Path],\n    measurements_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    sweep_bits_filepath: Optional[Union[str, pathlib.Path]] = None,\n    sweep_bits_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    detection_events_filepath: Union[str, pathlib.Path],\n    detection_events_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    append_observables: bool = False,\n    obs_out_filepath: Optional[Union[str, pathlib.Path]] = None,\n    obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n) -> None:\n    \"\"\"Reads measurement data from a file and writes detection events to another file.\n\n    Args:\n        measurements_filepath: A file containing measurement data to be converted.\n        measurements_format: The format the measurement data is stored in.\n            Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n            Defaults to \"01\".\n        detection_events_filepath: Where to save detection event data to.\n        detection_events_format: The format to save the detection event data in.\n            Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n            Defaults to \"01\".\n        sweep_bits_filepath: Defaults to None. A file containing sweep data, or\n            None. When specified, sweep data (used for `sweep[k]` controls in the\n            circuit, which can vary from shot to shot) will be read from the given\n            file. When not specified, all sweep bits default to False and no\n            sweep-controlled operations occur.\n        sweep_bits_format: The format the sweep data is stored in.\n            Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n            Defaults to \"01\".\n        obs_out_filepath: Sample observables as part of each shot, and write them to\n            this file. This keeps the observable data separate from the detector\n            data.\n        obs_out_format: If writing the observables to a file, this is the format to\n            write them in.\n            Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n            Defaults to \"01\".\n        append_observables: When True, the observables in the circuit are included\n            as part of the detection event data. Specifically, they are treated as\n            if they were additional detectors at the end of the circuit. When False,\n            observable data is not output.\n\n    Examples:\n        >>> import stim\n        >>> import tempfile\n        >>> converter = stim.Circuit('''\n        ...    X 0\n        ...    M 0\n        ...    DETECTOR rec[-1]\n        ... ''').compile_m2d_converter()\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...    with open(f\"{d}/measurements.01\", \"w\") as f:\n        ...        print(\"0\", file=f)\n        ...        print(\"1\", file=f)\n        ...    converter.convert_file(\n        ...        measurements_filepath=f\"{d}/measurements.01\",\n        ...        detection_events_filepath=f\"{d}/detections.01\",\n        ...        append_observables=False,\n        ...    )\n        ...    with open(f\"{d}/detections.01\") as f:\n        ...        print(f.read(), end=\"\")\n        1\n        0\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction\"></a>\n```python\n# stim.DemInstruction\n\n# (at top-level in the stim module)\nclass DemInstruction:\n    \"\"\"An instruction from a detector error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ...     error(0.125) D0 D1 L0\n        ...     error(0.125) D1 D2\n        ...     error(0.125) D2 D3\n        ...     error(0.125) D3\n        ... ''')\n        >>> instruction = model[0]\n        >>> instruction\n        stim.DemInstruction('error', [0.125], [stim.target_relative_detector_id(0)])\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.__eq__\"></a>\n```python\n# stim.DemInstruction.__eq__\n\n# (in class stim.DemInstruction)\ndef __eq__(\n    self,\n    arg0: stim.DemInstruction,\n) -> bool:\n    \"\"\"Determines if two instructions have identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.__init__\"></a>\n```python\n# stim.DemInstruction.__init__\n\n# (in class stim.DemInstruction)\ndef __init__(\n    self,\n    type: str,\n    args: Optional[Iterable[float]] = None,\n    targets: Optional[Iterable[stim.DemTarget]] = None,\n    *,\n    tag: str = \"\",\n) -> None:\n    \"\"\"Creates or parses a stim.DemInstruction.\n\n    Args:\n        type: The name of the instruction type (e.g. \"error\" or \"shift_detectors\").\n            If `args` and `targets` aren't specified, this can also be set to a\n            full line of text from a dem file, like \"error(0.25) D0\".\n        args: Numeric values parameterizing the instruction (e.g. the 0.1 in\n            \"error(0.1)\").\n        targets: The objects the instruction involves (e.g. the \"D0\" and \"L1\" in\n            \"error(0.1) D0 L1\").\n        tag: An arbitrary piece of text attached to the instruction.\n\n    Examples:\n        >>> import stim\n        >>> instruction = stim.DemInstruction(\n        ...     'error',\n        ...     [0.125],\n        ...     [stim.target_relative_detector_id(5)],\n        ...     tag='test-tag',\n        ... )\n        >>> print(instruction)\n        error[test-tag](0.125) D5\n\n        >>> print(stim.DemInstruction('error(0.125) D5 L6 ^ D4  # comment'))\n        error(0.125) D5 L6 ^ D4\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.__ne__\"></a>\n```python\n# stim.DemInstruction.__ne__\n\n# (in class stim.DemInstruction)\ndef __ne__(\n    self,\n    arg0: stim.DemInstruction,\n) -> bool:\n    \"\"\"Determines if two instructions have non-identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.__repr__\"></a>\n```python\n# stim.DemInstruction.__repr__\n\n# (in class stim.DemInstruction)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.DetectorErrorModel`.\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.__str__\"></a>\n```python\n# stim.DemInstruction.__str__\n\n# (in class stim.DemInstruction)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns detector error model (.dem) instructions (that can be parsed by stim) for the model.\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.args_copy\"></a>\n```python\n# stim.DemInstruction.args_copy\n\n# (in class stim.DemInstruction)\ndef args_copy(\n    self,\n) -> List[float]:\n    \"\"\"Returns a copy of the list of numbers parameterizing the instruction.\n\n    For example, this would be coordinates of a detector instruction or the\n    probability of an error instruction. The result is a copy, meaning that\n    editing it won't change the instruction's targets or future copies.\n\n    Examples:\n        >>> import stim\n        >>> instruction = stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ... ''')[0]\n        >>> instruction.args_copy()\n        [0.125]\n\n        >>> instruction.args_copy() == instruction.args_copy()\n        True\n        >>> instruction.args_copy() is instruction.args_copy()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.tag\"></a>\n```python\n# stim.DemInstruction.tag\n\n# (in class stim.DemInstruction)\n@property\ndef tag(\n    self,\n) -> str:\n    \"\"\"Returns the arbitrary text tag attached to the instruction.\n\n    Examples:\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     error[test-tag](0.125) D0\n        ...     error(0.125) D0\n        ... ''')\n        >>> dem[0].tag\n        'test-tag'\n        >>> dem[1].tag\n        ''\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.target_groups\"></a>\n```python\n# stim.DemInstruction.target_groups\n\n# (in class stim.DemInstruction)\ndef target_groups(\n    self,\n) -> List[List[stim.DemTarget]]:\n    \"\"\"Returns a copy of the instruction's targets, split by target separators.\n\n    When a detector error model instruction contains a suggested decomposition,\n    its targets contain separators (`stim.DemTarget(\"^\")`). This method splits the\n    targets into groups based the separators, similar to how `str.split` works.\n\n    Returns:\n        A list of groups of targets.\n\n    Examples:\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     error(0.01) D0 D1 ^ D2\n        ...     error(0.01) D0 L0\n        ...     error(0.01)\n        ... ''')\n\n        >>> dem[0].target_groups()\n        [[stim.DemTarget('D0'), stim.DemTarget('D1')], [stim.DemTarget('D2')]]\n\n        >>> dem[1].target_groups()\n        [[stim.DemTarget('D0'), stim.DemTarget('L0')]]\n\n        >>> dem[2].target_groups()\n        [[]]\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.targets_copy\"></a>\n```python\n# stim.DemInstruction.targets_copy\n\n# (in class stim.DemInstruction)\ndef targets_copy(\n    self,\n) -> List[Union[int, stim.DemTarget]]:\n    \"\"\"Returns a copy of the instruction's targets.\n\n    The result is a copy, meaning that editing it won't change the instruction's\n    targets or future copies.\n\n    Examples:\n        >>> import stim\n        >>> instruction = stim.DetectorErrorModel('''\n        ...     error(0.125) D0 L2\n        ... ''')[0]\n        >>> instruction.targets_copy()\n        [stim.DemTarget('D0'), stim.DemTarget('L2')]\n\n        >>> instruction.targets_copy() == instruction.targets_copy()\n        True\n        >>> instruction.targets_copy() is instruction.targets_copy()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.DemInstruction.type\"></a>\n```python\n# stim.DemInstruction.type\n\n# (in class stim.DemInstruction)\n@property\ndef type(\n    self,\n) -> str:\n    \"\"\"The name of the instruction type (e.g. \"error\" or \"shift_detectors\").\n    \"\"\"\n```\n\n<a name=\"stim.DemRepeatBlock\"></a>\n```python\n# stim.DemRepeatBlock\n\n# (at top-level in the stim module)\nclass DemRepeatBlock:\n    \"\"\"A repeat block from a detector error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...     repeat 100 {\n        ...         error(0.125) D0 D1\n        ...         shift_detectors 1\n        ...     }\n        ... ''')\n        >>> model[0]\n        stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n            error(0.125) D0 D1\n            shift_detectors 1\n        '''))\n    \"\"\"\n```\n\n<a name=\"stim.DemRepeatBlock.__eq__\"></a>\n```python\n# stim.DemRepeatBlock.__eq__\n\n# (in class stim.DemRepeatBlock)\ndef __eq__(\n    self,\n    arg0: stim.DemRepeatBlock,\n) -> bool:\n    \"\"\"Determines if two repeat blocks are identical.\n    \"\"\"\n```\n\n<a name=\"stim.DemRepeatBlock.__init__\"></a>\n```python\n# stim.DemRepeatBlock.__init__\n\n# (in class stim.DemRepeatBlock)\ndef __init__(\n    self,\n    repeat_count: int,\n    block: stim.DetectorErrorModel,\n) -> None:\n    \"\"\"Creates a stim.DemRepeatBlock.\n\n    Args:\n        repeat_count: The number of times the repeat block's body is supposed to\n            execute.\n        block: The body of the repeat block as a DetectorErrorModel containing the\n            instructions to repeat.\n\n    Examples:\n        >>> import stim\n        >>> repeat_block = stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n        ...     error(0.125) D0 D1\n        ...     shift_detectors 1\n        ... '''))\n    \"\"\"\n```\n\n<a name=\"stim.DemRepeatBlock.__ne__\"></a>\n```python\n# stim.DemRepeatBlock.__ne__\n\n# (in class stim.DemRepeatBlock)\ndef __ne__(\n    self,\n    arg0: stim.DemRepeatBlock,\n) -> bool:\n    \"\"\"Determines if two repeat blocks are different.\n    \"\"\"\n```\n\n<a name=\"stim.DemRepeatBlock.__repr__\"></a>\n```python\n# stim.DemRepeatBlock.__repr__\n\n# (in class stim.DemRepeatBlock)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.DemRepeatBlock`.\n    \"\"\"\n```\n\n<a name=\"stim.DemRepeatBlock.body_copy\"></a>\n```python\n# stim.DemRepeatBlock.body_copy\n\n# (in class stim.DemRepeatBlock)\ndef body_copy(\n    self,\n) -> stim.DetectorErrorModel:\n    \"\"\"Returns a copy of the block's body, as a stim.DetectorErrorModel.\n\n    Examples:\n        >>> import stim\n        >>> body = stim.DetectorErrorModel('''\n        ...     error(0.125) D0 D1\n        ...     shift_detectors 1\n        ... ''')\n        >>> repeat_block = stim.DemRepeatBlock(100, body)\n        >>> repeat_block.body_copy() == body\n        True\n        >>> repeat_block.body_copy() is repeat_block.body_copy()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.DemRepeatBlock.repeat_count\"></a>\n```python\n# stim.DemRepeatBlock.repeat_count\n\n# (in class stim.DemRepeatBlock)\n@property\ndef repeat_count(\n    self,\n) -> int:\n    \"\"\"The number of times the repeat block's body is supposed to execute.\n    \"\"\"\n```\n\n<a name=\"stim.DemRepeatBlock.type\"></a>\n```python\n# stim.DemRepeatBlock.type\n\n# (in class stim.DemRepeatBlock)\n@property\ndef type(\n    self,\n) -> object:\n    \"\"\"Returns the type name \"repeat\".\n\n    This is a duck-typing convenience method. It exists so that code that doesn't\n    know whether it has a `stim.DemInstruction` or a `stim.DemRepeatBlock`\n    can check the type field without having to do an `instanceof` check first.\n\n    Examples:\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     error(0.1) D0 L0\n        ...     repeat 5 {\n        ...         error(0.1) D0 D1\n        ...         shift_detectors 1\n        ...     }\n        ...     logical_observable L0\n        ... ''')\n        >>> [instruction.type for instruction in dem]\n        ['error', 'repeat', 'logical_observable']\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget\"></a>\n```python\n# stim.DemTarget\n\n# (at top-level in the stim module)\nclass DemTarget:\n    \"\"\"An instruction target from a detector error model (.dem) file.\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.__eq__\"></a>\n```python\n# stim.DemTarget.__eq__\n\n# (in class stim.DemTarget)\ndef __eq__(\n    self,\n    arg0: stim.DemTarget,\n) -> bool:\n    \"\"\"Determines if two `stim.DemTarget`s are identical.\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.__init__\"></a>\n```python\n# stim.DemTarget.__init__\n\n# (in class stim.DemTarget)\ndef __init__(\n    self,\n    arg: object,\n    /,\n) -> None:\n    \"\"\"Creates a stim.DemTarget from the given object.\n\n    Args:\n        arg: A string to parse as a stim.DemTarget, or some other object to\n            convert into a stim.DemTarget.\n\n    Examples:\n        >>> import stim\n        >>> stim.DemTarget(\"D5\") == stim.target_relative_detector_id(5)\n        True\n        >>> stim.DemTarget(\"L2\") == stim.target_logical_observable_id(2)\n        True\n        >>> stim.DemTarget(\"^\") == stim.target_separator()\n        True\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.__ne__\"></a>\n```python\n# stim.DemTarget.__ne__\n\n# (in class stim.DemTarget)\ndef __ne__(\n    self,\n    arg0: stim.DemTarget,\n) -> bool:\n    \"\"\"Determines if two `stim.DemTarget`s are different.\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.__repr__\"></a>\n```python\n# stim.DemTarget.__repr__\n\n# (in class stim.DemTarget)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns valid python code evaluating to an equivalent `stim.DemTarget`.\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.__str__\"></a>\n```python\n# stim.DemTarget.__str__\n\n# (in class stim.DemTarget)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns a text description of the detector error model target.\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.is_logical_observable_id\"></a>\n```python\n# stim.DemTarget.is_logical_observable_id\n\n# (in class stim.DemTarget)\ndef is_logical_observable_id(\n    self,\n) -> bool:\n    \"\"\"Determines if the detector error model target is a logical observable id target.\n\n    In a detector error model file, observable targets are prefixed by `L`. For\n    example, in `error(0.25) D0 L1` the `L1` is an observable target.\n\n    Examples:\n        >>> import stim\n        >>> stim.DemTarget(\"L2\").is_logical_observable_id()\n        True\n        >>> stim.DemTarget(\"D3\").is_logical_observable_id()\n        False\n        >>> stim.DemTarget(\"^\").is_logical_observable_id()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.is_relative_detector_id\"></a>\n```python\n# stim.DemTarget.is_relative_detector_id\n\n# (in class stim.DemTarget)\ndef is_relative_detector_id(\n    self,\n) -> bool:\n    \"\"\"Determines if the detector error model target is a relative detector id target.\n\n    In a detector error model file, detectors are prefixed by `D`. For\n    example, in `error(0.25) D0 L1` the `D0` is a relative detector target.\n\n    Examples:\n        >>> import stim\n        >>> stim.DemTarget(\"L2\").is_relative_detector_id()\n        False\n        >>> stim.DemTarget(\"D3\").is_relative_detector_id()\n        True\n        >>> stim.DemTarget(\"^\").is_relative_detector_id()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.is_separator\"></a>\n```python\n# stim.DemTarget.is_separator\n\n# (in class stim.DemTarget)\ndef is_separator(\n    self,\n) -> bool:\n    \"\"\"Determines if the detector error model target is a separator.\n\n    Separates separate the components of a suggested decompositions within an error.\n    For example, the `^` in `error(0.25) D1 D2 ^ D3 D4` is the separator.\n\n    Examples:\n        >>> import stim\n        >>> stim.DemTarget(\"L2\").is_separator()\n        False\n        >>> stim.DemTarget(\"D3\").is_separator()\n        False\n        >>> stim.DemTarget(\"^\").is_separator()\n        True\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.logical_observable_id\"></a>\n```python\n# stim.DemTarget.logical_observable_id\n\n# (in class stim.DemTarget)\n@staticmethod\ndef logical_observable_id(\n    index: int,\n) -> stim.DemTarget:\n    \"\"\"Returns a logical observable id identifying a frame change.\n\n    Args:\n        index: The index of the observable.\n\n    Returns:\n        The logical observable target.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.DemTarget.logical_observable_id(13)\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) L13\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.relative_detector_id\"></a>\n```python\n# stim.DemTarget.relative_detector_id\n\n# (in class stim.DemTarget)\n@staticmethod\ndef relative_detector_id(\n    index: int,\n) -> stim.DemTarget:\n    \"\"\"Returns a relative detector id (e.g. \"D5\" in a .dem file).\n\n    Args:\n        index: The index of the detector, relative to the current detector offset.\n\n    Returns:\n        The relative detector target.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.DemTarget.relative_detector_id(13)\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) D13\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.separator\"></a>\n```python\n# stim.DemTarget.separator\n\n# (in class stim.DemTarget)\n@staticmethod\ndef separator(\n) -> stim.DemTarget:\n    \"\"\"Returns a target separator (e.g. \"^\" in a .dem file).\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.DemTarget.relative_detector_id(1),\n        ...     stim.DemTarget.separator(),\n        ...     stim.DemTarget.relative_detector_id(2),\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) D1 ^ D2\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DemTarget.val\"></a>\n```python\n# stim.DemTarget.val\n\n# (in class stim.DemTarget)\n@property\ndef val(\n    self,\n) -> int:\n    \"\"\"Returns the target's integer value.\n\n    Example:\n        >>> import stim\n        >>> stim.DemTarget(\"D5\").val\n        5\n        >>> stim.DemTarget(\"L6\").val\n        6\n    \"\"\"\n```\n\n<a name=\"stim.DemTargetWithCoords\"></a>\n```python\n# stim.DemTargetWithCoords\n\n# (at top-level in the stim module)\nclass DemTargetWithCoords:\n    \"\"\"A detector error model instruction target with associated coords.\n\n    It is also guaranteed that, if the type of the DEM target is a\n    relative detector id, it is actually absolute (i.e. relative to\n    0).\n\n    For example, if the DEM target is a detector from a circuit with\n    coordinate arguments given to detectors, the coords field will\n    contain the coordinate data for the detector.\n\n    This is helpful information to have available when debugging a\n    problem in a circuit, instead of having to constantly manually\n    look up the coordinates of a detector index in order to understand\n    what is happening.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.DemTargetWithCoords(stim.DemTarget(\"D1\"), [1.5, 2.0])\n        >>> t.dem_target\n        stim.DemTarget('D1')\n        >>> t.coords\n        [1.5, 2.0]\n    \"\"\"\n```\n\n<a name=\"stim.DemTargetWithCoords.__init__\"></a>\n```python\n# stim.DemTargetWithCoords.__init__\n\n# (in class stim.DemTargetWithCoords)\ndef __init__(\n    self,\n    dem_target: stim.DemTarget,\n    coords: List[float],\n) -> None:\n    \"\"\"Creates a stim.DemTargetWithCoords.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0 1\n        ...     X_ERROR(0.25) 0 1\n        ...     M 0 1\n        ...     DETECTOR(2, 3) rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].dem_error_terms[0]\n        stim.DemTargetWithCoords(dem_target=stim.DemTarget('D0'), coords=[2, 3])\n    \"\"\"\n```\n\n<a name=\"stim.DemTargetWithCoords.coords\"></a>\n```python\n# stim.DemTargetWithCoords.coords\n\n# (in class stim.DemTargetWithCoords)\n@property\ndef coords(\n    self,\n) -> List[float]:\n    \"\"\"Returns the associated coordinate information as a list of floats.\n\n    If there is no coordinate information, returns an empty list.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0 1\n        ...     X_ERROR(0.25) 0 1\n        ...     M 0 1\n        ...     DETECTOR(2, 3) rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].dem_error_terms[0].coords\n        [2.0, 3.0]\n    \"\"\"\n```\n\n<a name=\"stim.DemTargetWithCoords.dem_target\"></a>\n```python\n# stim.DemTargetWithCoords.dem_target\n\n# (in class stim.DemTargetWithCoords)\n@property\ndef dem_target(\n    self,\n) -> stim.DemTarget:\n    \"\"\"Returns the actual DEM target as a `stim.DemTarget`.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0 1\n        ...     X_ERROR(0.25) 0 1\n        ...     M 0 1\n        ...     DETECTOR(2, 3) rec[-1] rec[-2]\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].dem_error_terms[0].dem_target\n        stim.DemTarget('D0')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel\"></a>\n```python\n# stim.DetectorErrorModel\n\n# (at top-level in the stim module)\nclass DetectorErrorModel:\n    \"\"\"An error model built out of independent error mechanics.\n\n    This class is one of the most important classes in Stim, because it is the\n    mechanism used to explain circuits to decoders. A typical workflow would\n    look something like:\n\n        1. Create a quantum error correction circuit annotated with detectors\n            and observables.\n        2. Fail at configuring your favorite decoder using the circuit, because\n            it's a pain to convert circuit error mechanisms into a format\n            understood by the decoder.\n        2a. Call circuit.detector_error_model(), with decompose_errors=True\n            if working with a matching-based code. This converts the circuit\n            errors into a straightforward list of independent \"with\n            probability p these detectors and observables get flipped\" terms.\n        3. Write tedious but straightforward glue code to create whatever\n            graph-like object the decoder needs from the detector error model.\n        3a. Actually, ideally, someone has already done that for you. For\n            example, pymatching can take detector error models directly and\n            sinter knows how to explain a detector error model to fusion_blossom.\n        4. Get samples using circuit.compile_detector_sampler(), feed them to\n            the decoder, and compare its observable flip predictions to the\n            actual flips recorded in the samples.\n        4a. Actually, sinter will basically handle steps 2 through 4 for you.\n            So you should probably have just generated your circuits, called\n            `sinter collect` on them, then `sinter plot` on the results.\n        5. Write the paper.\n\n    Error mechanisms are described in terms of the visible detection events and the\n    hidden observable frame changes that they causes. Error mechanisms can also\n    suggest decompositions of their effects into components, which can be helpful\n    for decoders that want to work with a simpler decomposed error model instead of\n    the full error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ...     error(0.125) D0 D1 L0\n        ...     error(0.125) D1 D2\n        ...     error(0.125) D2 D3\n        ...     error(0.125) D3\n        ... ''')\n        >>> len(model)\n        5\n\n        >>> stim.Circuit('''\n        ...     X_ERROR(0.125) 0\n        ...     X_ERROR(0.25) 1\n        ...     CORRELATED_ERROR(0.375) X0 X1\n        ...     M 0 1\n        ...     DETECTOR rec[-2]\n        ...     DETECTOR rec[-1]\n        ... ''').detector_error_model()\n        stim.DetectorErrorModel('''\n            error(0.125) D0\n            error(0.375) D0 D1\n            error(0.25) D1\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__add__\"></a>\n```python\n# stim.DetectorErrorModel.__add__\n\n# (in class stim.DetectorErrorModel)\ndef __add__(\n    self,\n    second: stim.DetectorErrorModel,\n) -> stim.DetectorErrorModel:\n    \"\"\"Creates a detector error model by appending two models.\n\n    Examples:\n        >>> import stim\n        >>> m1 = stim.DetectorErrorModel('''\n        ...    error(0.125) D0\n        ... ''')\n        >>> m2 = stim.DetectorErrorModel('''\n        ...    error(0.25) D1\n        ... ''')\n        >>> m1 + m2\n        stim.DetectorErrorModel('''\n            error(0.125) D0\n            error(0.25) D1\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__eq__\"></a>\n```python\n# stim.DetectorErrorModel.__eq__\n\n# (in class stim.DetectorErrorModel)\ndef __eq__(\n    self,\n    arg0: stim.DetectorErrorModel,\n) -> bool:\n    \"\"\"Determines if two detector error models have identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__getitem__\"></a>\n```python\n# stim.DetectorErrorModel.__getitem__\n\n# (in class stim.DetectorErrorModel)\n@overload\ndef __getitem__(\n    self,\n    index_or_slice: int,\n) -> Union[stim.DemInstruction, stim.DemRepeatBlock]:\n    pass\n@overload\ndef __getitem__(\n    self,\n    index_or_slice: slice,\n) -> stim.DetectorErrorModel:\n    pass\ndef __getitem__(\n    self,\n    index_or_slice: object,\n) -> object:\n    \"\"\"Returns copies of instructions from the detector error model.\n\n    Args:\n        index_or_slice: An integer index picking out an instruction to return, or a\n            slice picking out a range of instructions to return as a detector error\n            model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...    error(0.125) D0\n        ...    error(0.125) D1 L1\n        ...    repeat 100 {\n        ...        error(0.125) D1 D2\n        ...        shift_detectors 1\n        ...    }\n        ...    error(0.125) D2\n        ...    logical_observable L0\n        ...    detector D5\n        ... ''')\n        >>> model[0]\n        stim.DemInstruction('error', [0.125], [stim.target_relative_detector_id(0)])\n        >>> model[2]\n        stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n            error(0.125) D1 D2\n            shift_detectors 1\n        '''))\n        >>> model[1::2]\n        stim.DetectorErrorModel('''\n            error(0.125) D1 L1\n            error(0.125) D2\n            detector D5\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__iadd__\"></a>\n```python\n# stim.DetectorErrorModel.__iadd__\n\n# (in class stim.DetectorErrorModel)\ndef __iadd__(\n    self,\n    second: stim.DetectorErrorModel,\n) -> stim.DetectorErrorModel:\n    \"\"\"Appends a detector error model into the receiving model (mutating it).\n\n    Examples:\n        >>> import stim\n        >>> m1 = stim.DetectorErrorModel('''\n        ...    error(0.125) D0\n        ... ''')\n        >>> m2 = stim.DetectorErrorModel('''\n        ...    error(0.25) D1\n        ... ''')\n        >>> m1 += m2\n        >>> print(repr(m1))\n        stim.DetectorErrorModel('''\n            error(0.125) D0\n            error(0.25) D1\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__imul__\"></a>\n```python\n# stim.DetectorErrorModel.__imul__\n\n# (in class stim.DetectorErrorModel)\ndef __imul__(\n    self,\n    repetitions: int,\n) -> stim.DetectorErrorModel:\n    \"\"\"Mutates the detector error model by putting its contents into a repeat block.\n\n    Special case: if the repetition count is 0, the model is cleared.\n    Special case: if the repetition count is 1, nothing happens.\n\n    Args:\n        repetitions: The number of times the repeat block should repeat.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel('''\n        ...    error(0.25) D0\n        ...    shift_detectors 1\n        ... ''')\n        >>> m *= 3\n        >>> print(m)\n        repeat 3 {\n            error(0.25) D0\n            shift_detectors 1\n        }\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__init__\"></a>\n```python\n# stim.DetectorErrorModel.__init__\n\n# (in class stim.DetectorErrorModel)\ndef __init__(\n    self,\n    detector_error_model_text: str = '',\n) -> None:\n    \"\"\"Creates a stim.DetectorErrorModel.\n\n    Args:\n        detector_error_model_text: Defaults to empty. Describes instructions to\n            append into the circuit in the detector error model (.dem) format.\n\n    Examples:\n        >>> import stim\n        >>> empty = stim.DetectorErrorModel()\n        >>> not_empty = stim.DetectorErrorModel('''\n        ...    error(0.125) D0 L0\n        ... ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__len__\"></a>\n```python\n# stim.DetectorErrorModel.__len__\n\n# (in class stim.DetectorErrorModel)\ndef __len__(\n    self,\n) -> int:\n    \"\"\"Returns the number of top-level instructions/blocks in the detector error model.\n\n    Instructions inside of blocks are not included in this count.\n\n    Examples:\n        >>> import stim\n        >>> len(stim.DetectorErrorModel())\n        0\n        >>> len(stim.DetectorErrorModel('''\n        ...    error(0.1) D0 D1\n        ...    shift_detectors 100\n        ...    logical_observable L5\n        ... '''))\n        3\n        >>> len(stim.DetectorErrorModel('''\n        ...    repeat 100 {\n        ...        error(0.1) D0 D1\n        ...        error(0.1) D1 D2\n        ...    }\n        ... '''))\n        1\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__mul__\"></a>\n```python\n# stim.DetectorErrorModel.__mul__\n\n# (in class stim.DetectorErrorModel)\ndef __mul__(\n    self,\n    repetitions: int,\n) -> stim.DetectorErrorModel:\n    \"\"\"Repeats the detector error model using a repeat block.\n\n    Has special cases for 0 repetitions and 1 repetitions.\n\n    Args:\n        repetitions: The number of times the repeat block should repeat.\n\n    Returns:\n        repetitions=0: An empty detector error model.\n        repetitions=1: A copy of this detector error model.\n        repetitions>=2: A detector error model with a single repeat block, where the\n        contents of that repeat block are this detector error model.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel('''\n        ...    error(0.25) D0\n        ...    shift_detectors 1\n        ... ''')\n        >>> m * 3\n        stim.DetectorErrorModel('''\n            repeat 3 {\n                error(0.25) D0\n                shift_detectors 1\n            }\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__ne__\"></a>\n```python\n# stim.DetectorErrorModel.__ne__\n\n# (in class stim.DetectorErrorModel)\ndef __ne__(\n    self,\n    arg0: stim.DetectorErrorModel,\n) -> bool:\n    \"\"\"Determines if two detector error models have non-identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__repr__\"></a>\n```python\n# stim.DetectorErrorModel.__repr__\n\n# (in class stim.DetectorErrorModel)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns valid python code evaluating to an equivalent `stim.DetectorErrorModel`.\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__rmul__\"></a>\n```python\n# stim.DetectorErrorModel.__rmul__\n\n# (in class stim.DetectorErrorModel)\ndef __rmul__(\n    self,\n    repetitions: int,\n) -> stim.DetectorErrorModel:\n    \"\"\"Repeats the detector error model using a repeat block.\n\n    Has special cases for 0 repetitions and 1 repetitions.\n\n    Args:\n        repetitions: The number of times the repeat block should repeat.\n\n    Returns:\n        repetitions=0: An empty detector error model.\n        repetitions=1: A copy of this detector error model.\n        repetitions>=2: A detector error model with a single repeat block, where the\n        contents of that repeat block are this detector error model.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel('''\n        ...    error(0.25) D0\n        ...    shift_detectors 1\n        ... ''')\n        >>> 3 * m\n        stim.DetectorErrorModel('''\n            repeat 3 {\n                error(0.25) D0\n                shift_detectors 1\n            }\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.__str__\"></a>\n```python\n# stim.DetectorErrorModel.__str__\n\n# (in class stim.DetectorErrorModel)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns the contents of a detector error model file (.dem) encoding the model.\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.append\"></a>\n```python\n# stim.DetectorErrorModel.append\n\n# (in class stim.DetectorErrorModel)\ndef append(\n    self,\n    instruction: object,\n    parens_arguments: object = None,\n    targets: List[object] = (),\n    *,\n    tag: str = '',\n) -> None:\n    \"\"\"Appends an instruction to the detector error model.\n\n    Args:\n        instruction: Either the name of an instruction, a stim.DemInstruction, a\n            stim.DemRepeatBlock. or a stim.DetectorErrorModel. The\n            `parens_arguments`, `targets`, and 'tag' arguments should be given iff\n            the instruction is a name.\n        parens_arguments: Numeric values parameterizing the instruction. The numbers\n            inside parentheses in a detector error model file (eg. the `0.25` in\n            `error(0.25) D0`). This argument can be given either a list of doubles,\n            or a single double (which will be implicitly wrapped into a list).\n        targets: The instruction targets, such as the `D0` in `error(0.25) D0`.\n        tag: An arbitrary piece of text attached to the repeat instruction.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.125, [\n        ...     stim.DemTarget.relative_detector_id(1),\n        ... ])\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.DemTarget.relative_detector_id(1),\n        ...     stim.DemTarget.separator(),\n        ...     stim.DemTarget.relative_detector_id(2),\n        ...     stim.DemTarget.logical_observable_id(3),\n        ... ], tag='test-tag')\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.125) D1\n            error[test-tag](0.25) D1 ^ D2 L3\n        ''')\n\n        >>> m.append(\"shift_detectors\", (1, 2, 3), [5])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.125) D1\n            error[test-tag](0.25) D1 ^ D2 L3\n            shift_detectors(1, 2, 3) 5\n        ''')\n\n        >>> m += m * 3\n        >>> m.append(m[0])\n        >>> m.append(m[-2])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.125) D1\n            error[test-tag](0.25) D1 ^ D2 L3\n            shift_detectors(1, 2, 3) 5\n            repeat 3 {\n                error(0.125) D1\n                error[test-tag](0.25) D1 ^ D2 L3\n                shift_detectors(1, 2, 3) 5\n            }\n            error(0.125) D1\n            repeat 3 {\n                error(0.125) D1\n                error[test-tag](0.25) D1 ^ D2 L3\n                shift_detectors(1, 2, 3) 5\n            }\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.approx_equals\"></a>\n```python\n# stim.DetectorErrorModel.approx_equals\n\n# (in class stim.DetectorErrorModel)\ndef approx_equals(\n    self,\n    other: object,\n    *,\n    atol: float,\n) -> bool:\n    \"\"\"Checks if detector error models are approximately equal.\n\n    Two detector error model are approximately equal if they are equal up to slight\n    perturbations of instruction arguments such as probabilities. For example\n    `error(0.100) D0` is approximately equal to `error(0.099) D0` within an absolute\n    tolerance of 0.002. All other details of the models (such as the ordering of\n    errors and their targets) must be exactly the same.\n\n    Args:\n        other: The detector error model, or other object, to compare to this one.\n        atol: The absolute error tolerance. The maximum amount each probability may\n            have been perturbed by.\n\n    Returns:\n        True if the given object is a detector error model approximately equal up to\n        the receiving circuit up to the given tolerance, otherwise False.\n\n    Examples:\n        >>> import stim\n        >>> base = stim.DetectorErrorModel('''\n        ...    error(0.099) D0 D1\n        ... ''')\n\n        >>> base.approx_equals(base, atol=0)\n        True\n\n        >>> base.approx_equals(stim.DetectorErrorModel('''\n        ...    error(0.101) D0 D1\n        ... '''), atol=0)\n        False\n\n        >>> base.approx_equals(stim.DetectorErrorModel('''\n        ...    error(0.101) D0 D1\n        ... '''), atol=0.0001)\n        False\n\n        >>> base.approx_equals(stim.DetectorErrorModel('''\n        ...    error(0.101) D0 D1\n        ... '''), atol=0.01)\n        True\n\n        >>> base.approx_equals(stim.DetectorErrorModel('''\n        ...    error(0.099) D0 D1 L0 L1 L2 L3 L4\n        ... '''), atol=9999)\n        False\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.clear\"></a>\n```python\n# stim.DetectorErrorModel.clear\n\n# (in class stim.DetectorErrorModel)\ndef clear(\n    self,\n) -> None:\n    \"\"\"Clears the contents of the detector error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...    error(0.1) D0 D1\n        ... ''')\n        >>> model.clear()\n        >>> model\n        stim.DetectorErrorModel()\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.compile_sampler\"></a>\n```python\n# stim.DetectorErrorModel.compile_sampler\n\n# (in class stim.DetectorErrorModel)\ndef compile_sampler(\n    self,\n    *,\n    seed: object = None,\n) -> stim.CompiledDemSampler:\n    \"\"\"Returns a CompiledDemSampler that can batch sample from detector error models.\n\n    Args:\n        seed: PARTIALLY determines simulation results by deterministically seeding\n            the random number generator.\n\n            Must be None or an integer in range(2**64).\n\n            Defaults to None. When None, the prng is seeded from system entropy.\n\n            When set to an integer, making the exact same series calls on the exact\n            same machine with the exact same version of Stim will produce the exact\n            same simulation results.\n\n            CAUTION: simulation results *WILL NOT* be consistent between versions of\n            Stim. This restriction is present to make it possible to have future\n            optimizations to the random sampling, and is enforced by introducing\n            intentional differences in the seeding strategy from version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines that\n            differ in the width of supported SIMD instructions. For example, using\n            the same seed on a machine that supports AVX instructions and one that\n            only supports SSE instructions may produce different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n            shots are taken. For example, taking 10 shots and then 90 shots will\n            give different results from taking 100 shots in one call.\n\n    Returns:\n        A seeded stim.CompiledDemSampler for the given detector error model.\n\n    Examples:\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...    error(0) D0\n        ...    error(1) D1 D2 L0\n        ... ''')\n        >>> sampler = dem.compile_sampler()\n        >>> det_data, obs_data, err_data = sampler.sample(\n        ...     shots=4,\n        ...     return_errors=True)\n        >>> det_data\n        array([[False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True]])\n        >>> obs_data\n        array([[ True],\n               [ True],\n               [ True],\n               [ True]])\n        >>> err_data\n        array([[False,  True],\n               [False,  True],\n               [False,  True],\n               [False,  True]])\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.copy\"></a>\n```python\n# stim.DetectorErrorModel.copy\n\n# (in class stim.DetectorErrorModel)\ndef copy(\n    self,\n) -> stim.DetectorErrorModel:\n    \"\"\"Returns a copy of the detector error model.\n\n    The copy is an independent detector error model with the same contents.\n\n    Examples:\n        >>> import stim\n\n        >>> c1 = stim.DetectorErrorModel(\"error(0.1) D0 D1\")\n        >>> c2 = c1.copy()\n        >>> c2 is c1\n        False\n        >>> c2 == c1\n        True\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.diagram\"></a>\n```python\n# stim.DetectorErrorModel.diagram\n\n# (in class stim.DetectorErrorModel)\ndef diagram(\n    self,\n    type: Literal[\"matchgraph-svg\", \"matchgraph-svg-html\", \"matchgraph-3d\", \"matchgraph-3d-html\"] = 'matchgraph-svg',\n) -> Any:\n    \"\"\"Returns a diagram of the circuit, from a variety of options.\n\n    Args:\n        type: The type of diagram. Available types are:\n            \"matchgraph-svg\": An image of the decoding graph of the\n                detector error model. Red lines are errors crossing a\n                logical observable. Blue lines are undecomposed hyper\n                errors.\n            \"matchgraph-svg-html\": Same as matchgraph-svg but with the\n                SVG wrapped in a resizable HTML iframe.\n            \"matchgraph-3d\": A 3d model of the decoding graph of the\n                detector error model. Red lines are errors crossing a\n                logical observable. Blue lines are undecomposed hyper\n                errors.\n\n                GLTF files can be opened with a variety of programs, or\n                opened online in viewers such as\n                https://gltf-viewer.donmccurdy.com/ . Red lines are\n                errors crossing a logical observable.\n            \"matchgraph-3d-html\": Same 3d model as 'match-graph-3d' but\n                embedded into an HTML web page containing an interactive\n                THREE.js viewer for the 3d model.\n\n    Returns:\n        An object whose `__str__` method returns the diagram, so that\n        writing the diagram to a file works correctly. The returned\n        object also defines a `_repr_html_` method, so that ipython\n        notebooks recognize it can be shown using a specialized\n        viewer instead of as raw text.\n\n    Examples:\n        >>> import stim\n        >>> import tempfile\n        >>> circuit = stim.Circuit.generated(\n        ...     \"repetition_code:memory\",\n        ...     rounds=10,\n        ...     distance=7,\n        ...     after_clifford_depolarization=0.01)\n        >>> dem = circuit.detector_error_model(decompose_errors=True)\n\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     diagram = circuit.diagram(\"match-graph-svg\")\n        ...     with open(f\"{d}/dem_image.svg\", \"w\") as f:\n        ...         print(diagram, file=f)\n\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     diagram = circuit.diagram(\"match-graph-3d\")\n        ...     with open(f\"{d}/dem_3d_model.gltf\", \"w\") as f:\n        ...         print(diagram, file=f)\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.flattened\"></a>\n```python\n# stim.DetectorErrorModel.flattened\n\n# (in class stim.DetectorErrorModel)\ndef flattened(\n    self,\n) -> stim.DetectorErrorModel:\n    \"\"\"Returns the detector error model without repeat or detector_shift instructions.\n\n    Returns:\n        A `stim.DetectorErrorModel` with the same errors in the same order, but with\n        repeat loops flattened into actually repeated instructions and with all\n        coordinate/index shifts inlined.\n\n    Examples:\n        >>> import stim\n        >>> stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ...     REPEAT 5 {\n        ...         error(0.25) D0 D1\n        ...         shift_detectors 1\n        ...     }\n        ...     error(0.125) D0 L0\n        ... ''').flattened()\n        stim.DetectorErrorModel('''\n            error(0.125) D0\n            error(0.25) D0 D1\n            error(0.25) D1 D2\n            error(0.25) D2 D3\n            error(0.25) D3 D4\n            error(0.25) D4 D5\n            error(0.125) D5 L0\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.from_file\"></a>\n```python\n# stim.DetectorErrorModel.from_file\n\n# (in class stim.DetectorErrorModel)\n@staticmethod\ndef from_file(\n    file: Union[io.TextIOBase, str, pathlib.Path],\n) -> stim.DetectorErrorModel:\n    \"\"\"Reads a detector error model from a file.\n\n    The file format is defined at\n    https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n    Args:\n        file: A file path or open file object to read from.\n\n    Returns:\n        The circuit parsed from the file.\n\n    Examples:\n        >>> import stim\n        >>> import tempfile\n\n        >>> with tempfile.TemporaryDirectory() as tmpdir:\n        ...     path = tmpdir + '/tmp.stim'\n        ...     with open(path, 'w') as f:\n        ...         print('error(0.25) D2 D3', file=f)\n        ...     circuit = stim.DetectorErrorModel.from_file(path)\n        >>> circuit\n        stim.DetectorErrorModel('''\n            error(0.25) D2 D3\n        ''')\n\n        >>> with tempfile.TemporaryDirectory() as tmpdir:\n        ...     path = tmpdir + '/tmp.stim'\n        ...     with open(path, 'w') as f:\n        ...         print('error(0.25) D2 D3', file=f)\n        ...     with open(path) as f:\n        ...         circuit = stim.DetectorErrorModel.from_file(f)\n        >>> circuit\n        stim.DetectorErrorModel('''\n            error(0.25) D2 D3\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.get_detector_coordinates\"></a>\n```python\n# stim.DetectorErrorModel.get_detector_coordinates\n\n# (in class stim.DetectorErrorModel)\ndef get_detector_coordinates(\n    self,\n    only: object = None,\n) -> Dict[int, List[float]]:\n    \"\"\"Returns the coordinate metadata of detectors in the detector error model.\n\n    Args:\n        only: Defaults to None (meaning include all detectors). A list of detector\n            indices to include in the result. Detector indices beyond the end of the\n            detector error model cause an error.\n\n    Returns:\n        A dictionary mapping integers (detector indices) to lists of floats\n        (coordinates). Detectors with no specified coordinate data are mapped to an\n        empty tuple. If `only` is specified, then `set(result.keys()) == set(only)`.\n\n    Examples:\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...    error(0.25) D0 D1\n        ...    detector(1, 2, 3) D1\n        ...    shift_detectors(5) 1\n        ...    detector(1, 2) D2\n        ... ''')\n        >>> dem.get_detector_coordinates()\n        {0: [], 1: [1.0, 2.0, 3.0], 2: [], 3: [6.0, 2.0]}\n        >>> dem.get_detector_coordinates(only=[1])\n        {1: [1.0, 2.0, 3.0]}\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.num_detectors\"></a>\n```python\n# stim.DetectorErrorModel.num_detectors\n\n# (in class stim.DetectorErrorModel)\n@property\ndef num_detectors(\n    self,\n) -> int:\n    \"\"\"Counts the number of detectors (e.g. `D2`) in the error model.\n\n    Detector indices are assumed to be contiguous from 0 up to whatever the maximum\n    detector id is. If the largest detector's absolute id is n-1, then the number of\n    detectors is n.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     X_ERROR(0.125) 0\n        ...     X_ERROR(0.25) 1\n        ...     CORRELATED_ERROR(0.375) X0 X1\n        ...     M 0 1\n        ...     DETECTOR rec[-2]\n        ...     DETECTOR rec[-1]\n        ... ''').detector_error_model().num_detectors\n        2\n\n        >>> stim.DetectorErrorModel('''\n        ...    error(0.1) D0 D199\n        ... ''').num_detectors\n        200\n\n        >>> stim.DetectorErrorModel('''\n        ...    shift_detectors 1000\n        ...    error(0.1) D0 D199\n        ... ''').num_detectors\n        1200\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.num_errors\"></a>\n```python\n# stim.DetectorErrorModel.num_errors\n\n# (in class stim.DetectorErrorModel)\n@property\ndef num_errors(\n    self,\n) -> int:\n    \"\"\"Counts the number of errors (e.g. `error(0.1) D0`) in the error model.\n\n    Error instructions inside repeat blocks count once per repetition.\n    Redundant errors with the same targets count as separate errors.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ...     repeat 100 {\n        ...         repeat 5 {\n        ...             error(0.25) D1\n        ...         }\n        ...     }\n        ... ''').num_errors\n        501\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.num_observables\"></a>\n```python\n# stim.DetectorErrorModel.num_observables\n\n# (in class stim.DetectorErrorModel)\n@property\ndef num_observables(\n    self,\n) -> int:\n    \"\"\"Counts the number of frame changes (e.g. `L2`) in the error model.\n\n    Observable indices are assumed to be contiguous from 0 up to whatever the\n    maximum observable id is. If the largest observable's id is n-1, then the number\n    of observables is n.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Circuit('''\n        ...     X_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(99) rec[-1]\n        ... ''').detector_error_model().num_observables\n        100\n\n        >>> stim.DetectorErrorModel('''\n        ...    error(0.1) L399\n        ... ''').num_observables\n        400\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.rounded\"></a>\n```python\n# stim.DetectorErrorModel.rounded\n\n# (in class stim.DetectorErrorModel)\ndef rounded(\n    self,\n    arg0: int,\n) -> stim.DetectorErrorModel:\n    \"\"\"Creates an equivalent detector error model but with rounded error probabilities.\n\n    Args:\n        digits: The number of digits to round to.\n\n    Returns:\n        A `stim.DetectorErrorModel` with the same instructions in the same order,\n        but with the parens arguments of error instructions rounded to the given\n        precision.\n\n        Instructions whose error probability was rounded to zero are still\n        included in the output.\n\n    Examples:\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     error(0.019499) D0\n        ...     error(0.000001) D0 D1\n        ... ''')\n\n        >>> dem.rounded(2)\n        stim.DetectorErrorModel('''\n            error(0.02) D0\n            error(0) D0 D1\n        ''')\n\n        >>> dem.rounded(3)\n        stim.DetectorErrorModel('''\n            error(0.019) D0\n            error(0) D0 D1\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.shortest_graphlike_error\"></a>\n```python\n# stim.DetectorErrorModel.shortest_graphlike_error\n\n# (in class stim.DetectorErrorModel)\ndef shortest_graphlike_error(\n    self,\n    ignore_ungraphlike_errors: bool = True,\n) -> stim.DetectorErrorModel:\n    \"\"\"Finds a minimum set of graphlike errors to produce an undetected logical error.\n\n    Note that this method does not pay attention to error probabilities (other than\n    ignoring errors with probability 0). It searches for a logical error with the\n    minimum *number* of physical errors, not the maximum probability of those\n    physical errors all occurring.\n\n    This method works by looking for errors that have frame changes (eg.\n    \"error(0.1) D0 D1 L5\" flips the frame of observable 5). These errors are\n    converted into one or two symptoms and a net frame change. The symptoms can then\n    be moved around by following errors touching that symptom. Each symptom is moved\n    until it disappears into a boundary or cancels against another remaining\n    symptom, while leaving the other symptoms alone (ensuring only one symptom is\n    allowed to move significantly reduces waste in the search space). Eventually a\n    path or cycle of errors is found that cancels out the symptoms, and if there is\n    still a frame change at that point then that path or cycle is a logical error\n    (otherwise all that was found was a stabilizer of the system; a dead end). The\n    search process advances like a breadth first search, seeded from all the\n    frame-change errors and branching them outward in tandem, until one of them wins\n    the race to find a solution.\n\n    Args:\n        ignore_ungraphlike_errors: Defaults to True. When False, an exception is\n            raised if there are any errors in the model that are not graphlike. When\n            True, those errors are skipped as if they weren't present.\n\n            A graphlike error is an error with less than two symptoms. For the\n            purposes of this method, errors are also considered graphlike if they\n            are decomposed into graphlike components:\n\n            graphlike:\n                error(0.1) D0\n                error(0.1) D0 D1\n                error(0.1) D0 D1 L0\n            not graphlike but decomposed into graphlike components:\n                error(0.1) D0 D1 ^ D2\n            not graphlike, not decomposed into graphlike components:\n                error(0.1) D0 D1 D2\n                error(0.1) D0 D1 D2 ^ D3\n\n    Returns:\n        A detector error model containing just the error instructions corresponding\n        to an undetectable logical error. There will be no other kinds of\n        instructions (no `repeat`s, no `shift_detectors`, etc). The error\n        probabilities will all be set to 1.\n\n        The `len` of the returned model is the graphlike code distance of the\n        circuit. But beware that in general the true code distance may be smaller.\n        For example, in the XZ surface code with twists, the true minimum sized\n        logical error is likely to use Y errors. But each Y error decomposes into\n        two graphlike components (the X part and the Z part). As a result, the\n        graphlike code distance in that context is likely to be nearly twice as\n        large as the true code distance.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ...     error(0.125) D0 D1\n        ...     error(0.125) D1 L55\n        ...     error(0.125) D1\n        ... ''').shortest_graphlike_error()\n        stim.DetectorErrorModel('''\n            error(1) D1\n            error(1) D1 L55\n        ''')\n\n        >>> stim.DetectorErrorModel('''\n        ...     error(0.125) D0 D1 D2\n        ...     error(0.125) L0\n        ... ''').shortest_graphlike_error(ignore_ungraphlike_errors=True)\n        stim.DetectorErrorModel('''\n            error(1) L0\n        ''')\n\n        >>> circuit = stim.Circuit.generated(\n        ...     \"repetition_code:memory\",\n        ...     rounds=10,\n        ...     distance=7,\n        ...     before_round_data_depolarization=0.01)\n        >>> model = circuit.detector_error_model(decompose_errors=True)\n        >>> len(model.shortest_graphlike_error())\n        7\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.to_file\"></a>\n```python\n# stim.DetectorErrorModel.to_file\n\n# (in class stim.DetectorErrorModel)\ndef to_file(\n    self,\n    file: Union[io.TextIOBase, str, pathlib.Path],\n) -> None:\n    \"\"\"Writes the detector error model to a file.\n\n    The file format is defined at\n    https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n    Args:\n        file: A file path or an open file to write to.\n\n    Examples:\n        >>> import stim\n        >>> import tempfile\n        >>> c = stim.DetectorErrorModel('error(0.25) D2 D3')\n\n        >>> with tempfile.TemporaryDirectory() as tmpdir:\n        ...     path = tmpdir + '/tmp.stim'\n        ...     with open(path, 'w') as f:\n        ...         c.to_file(f)\n        ...     with open(path) as f:\n        ...         contents = f.read()\n        >>> contents\n        'error(0.25) D2 D3\\n'\n\n        >>> with tempfile.TemporaryDirectory() as tmpdir:\n        ...     path = tmpdir + '/tmp.stim'\n        ...     c.to_file(path)\n        ...     with open(path) as f:\n        ...         contents = f.read()\n        >>> contents\n        'error(0.25) D2 D3\\n'\n    \"\"\"\n```\n\n<a name=\"stim.DetectorErrorModel.without_tags\"></a>\n```python\n# stim.DetectorErrorModel.without_tags\n\n# (in class stim.DetectorErrorModel)\ndef without_tags(\n    self,\n) -> stim.DetectorErrorModel:\n    \"\"\"Returns a copy of the detector error model with all tags removed.\n\n    Returns:\n        A `stim.DetectorErrorModel` with the same instructions except all tags have\n        been removed.\n\n    Examples:\n        >>> import stim\n        >>> stim.DetectorErrorModel('''\n        ...     error[test-tag](0.25) D0\n        ... ''').without_tags()\n        stim.DetectorErrorModel('''\n            error(0.25) D0\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.ExplainedError\"></a>\n```python\n# stim.ExplainedError\n\n# (at top-level in the stim module)\nclass ExplainedError:\n    \"\"\"Describes the location of an error mechanism from a stim circuit.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> print(err[0])\n        ExplainedError {\n            dem_error_terms: L0\n            CircuitErrorLocation {\n                flipped_pauli_product: Y0\n                Circuit location stack trace:\n                    (after 1 TICKs)\n                    at instruction #3 (Y_ERROR) in the circuit\n                    at target #1 of the instruction\n                    resolving to Y_ERROR(0.125) 0\n            }\n        }\n    \"\"\"\n```\n\n<a name=\"stim.ExplainedError.__init__\"></a>\n```python\n# stim.ExplainedError.__init__\n\n# (in class stim.ExplainedError)\ndef __init__(\n    self,\n    *,\n    dem_error_terms: List[stim.DemTargetWithCoords],\n    circuit_error_locations: List[stim.CircuitErrorLocation],\n) -> None:\n    \"\"\"Creates a stim.ExplainedError.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> print(err[0])\n        ExplainedError {\n            dem_error_terms: L0\n            CircuitErrorLocation {\n                flipped_pauli_product: Y0\n                Circuit location stack trace:\n                    (after 1 TICKs)\n                    at instruction #3 (Y_ERROR) in the circuit\n                    at target #1 of the instruction\n                    resolving to Y_ERROR(0.125) 0\n            }\n        }\n    \"\"\"\n```\n\n<a name=\"stim.ExplainedError.circuit_error_locations\"></a>\n```python\n# stim.ExplainedError.circuit_error_locations\n\n# (in class stim.ExplainedError)\n@property\ndef circuit_error_locations(\n    self,\n) -> List[stim.CircuitErrorLocation]:\n    \"\"\"The locations of circuit errors that produce the symptoms in dem_error_terms.\n\n    Note: if this list contains a single entry, it may be because a result\n    with a single representative error was requested (as opposed to all possible\n    errors).\n\n    Note: if this list is empty, it may be because there was a DEM error decomposed\n    into parts where one of the parts is impossible to make on its own from a single\n    circuit error.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> print(err[0].circuit_error_locations[0])\n        CircuitErrorLocation {\n            flipped_pauli_product: Y0\n            Circuit location stack trace:\n                (after 1 TICKs)\n                at instruction #3 (Y_ERROR) in the circuit\n                at target #1 of the instruction\n                resolving to Y_ERROR(0.125) 0\n        }\n    \"\"\"\n```\n\n<a name=\"stim.ExplainedError.dem_error_terms\"></a>\n```python\n# stim.ExplainedError.dem_error_terms\n\n# (in class stim.ExplainedError)\n@property\ndef dem_error_terms(\n    self,\n) -> List[stim.DemTargetWithCoords]:\n    \"\"\"The detectors and observables flipped by this error mechanism.\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator\"></a>\n```python\n# stim.FlipSimulator\n\n# (at top-level in the stim module)\nclass FlipSimulator:\n    \"\"\"A simulator that tracks whether things are flipped, instead of what they are.\n\n    Tracking flips is significantly cheaper than tracking actual values, requiring\n    O(1) work per gate (compared to O(n) for unitary operations and O(n^2) for\n    collapsing operations in the tableau simulator, where n is the qubit count).\n\n    Supports interactive usage, where gates and measurements are applied on demand.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.__init__\"></a>\n```python\n# stim.FlipSimulator.__init__\n\n# (in class stim.FlipSimulator)\ndef __init__(\n    self,\n    *,\n    batch_size: int,\n    disable_stabilizer_randomization: bool = False,\n    num_qubits: int = 0,\n    seed: Optional[int] = None,\n) -> None:\n    \"\"\"Initializes a stim.FlipSimulator.\n\n    Args:\n        batch_size: For speed, the flip simulator simulates many instances in\n            parallel. This argument determines the number of parallel instances.\n\n            It's recommended to use a multiple of 256, because internally the state\n            of the instances is striped across SSE (128 bit) or AVX (256 bit)\n            words with one bit in the word belonging to each instance. The result is\n            that, even if you only ask for 1 instance, probably the same amount of\n            work is being done as if you'd asked for 256 instances. The extra\n            results just aren't being used, creating waste.\n\n        disable_stabilizer_randomization: Determines whether or not the flip\n            simulator uses stabilizer randomization. Defaults to False (stabilizer\n            randomization used). Set to True to disable stabilizer randomization.\n\n            Stabilizer randomization means that, when a qubit is initialized or\n            measured in the Z basis, a Z error is added to the qubit with 50%\n            probability. More generally, anytime a stabilizer is introduced into\n            the system by any means, an error equal to that stabilizer is applied\n            with 50% probability. This ensures that observables anticommuting with\n            stabilizers of the system must be maximally uncertain. In other words,\n            this feature enforces Heisenberg's uncertainty principle.\n\n            This is a safety feature that you should not turn off unless you have a\n            reason to do so. Stabilizer randomization is turned on by default\n            because it catches mistakes. For example, suppose you are trying to\n            create a stabilizer code but you accidentally have the code measure two\n            anticommuting stabilizers. With stabilizer randomization turned off, it\n            will look like this code works. With stabilizer randomization turned on,\n            the two measurements will correctly randomize each other revealing that\n            the code doesn't work.\n\n            In some use cases, stabilizer randomization is a hindrance instead of\n            helpful. For example, if you are using the flip simulator to understand\n            how an error propagates through the system, the stabilizer randomization\n            will be introducing error terms that you don't want.\n\n        num_qubits: Sets the initial number of qubits tracked by the simulation.\n            The simulator will still automatically resize as needed when qubits\n            beyond this limit are touched.\n\n            This parameter exists as a way to hint at the desired size of the\n            simulator's state for performance, and to ensure methods that\n            peek at the size have the expected size from the start instead of\n            only after the relevant qubits have been touched.\n\n        seed: PARTIALLY determines simulation results by deterministically seeding\n            the random number generator.\n\n            Must be None or an integer in range(2**64).\n\n            Defaults to None. When None, the prng is seeded from system entropy.\n\n            When set to an integer, making the exact same series calls on the exact\n            same machine with the exact same version of Stim will produce the exact\n            same simulation results.\n\n            CAUTION: simulation results *WILL NOT* be consistent between versions of\n            Stim. This restriction is present to make it possible to have future\n            optimizations to the random sampling, and is enforced by introducing\n            intentional differences in the seeding strategy from version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines that\n            differ in the width of supported SIMD instructions. For example, using\n            the same seed on a machine that supports AVX instructions and one that\n            only supports SSE instructions may produce different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n            circuit is executed. For example, reordering whether a reset on one\n            qubit happens before or after a reset on another qubit can result in\n            different measurement results being observed starting from the same\n            seed.\n\n    Returns:\n        An initialized stim.FlipSimulator.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.append_measurement_flips\"></a>\n```python\n# stim.FlipSimulator.append_measurement_flips\n\n# (in class stim.FlipSimulator)\ndef append_measurement_flips(\n    self,\n    measurement_flip_data: np.ndarray,\n) -> None:\n    \"\"\"Appends measurement flip data to the simulator's measurement record.\n\n    Args:\n        measurement_flip_data: The flip data to append. The following shape/dtype\n            combinations are supported.\n\n            Single measurement without bit packing:\n                shape=(self.batch_size,)\n                dtype=np.bool_\n\n            Single measurement with bit packing:\n                shape=(math.ceil(self.batch_size / 8),)\n                dtype=np.uint8\n\n            Multiple measurements without bit packing:\n                shape=(num_measurements, self.batch_size)\n                dtype=np.bool_\n\n            Multiple measurements with bit packing:\n                shape=(num_measurements, math.ceil(self.batch_size / 8))\n                dtype=np.uint8\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n        >>> sim = stim.FlipSimulator(batch_size=9)\n        >>> sim.append_measurement_flips(np.array(\n        ...     [0, 1, 0, 0, 1, 0, 0, 1, 1],\n        ...     dtype=np.bool_,\n        ... ))\n\n        >>> sim.get_measurement_flips()\n        array([[False,  True, False, False,  True, False, False,  True,  True]])\n\n        >>> sim.append_measurement_flips(np.array(\n        ...     [0b11001001, 0],\n        ...     dtype=np.uint8,\n        ... ))\n\n        >>> sim.get_measurement_flips()\n        array([[False,  True, False, False,  True, False, False,  True,  True],\n               [ True, False, False,  True, False, False,  True,  True, False]])\n\n        >>> sim.append_measurement_flips(np.array(\n        ...     [[0b11111111, 0b1], [0b00000000, 0b0], [0b11111111, 0b1]],\n        ...     dtype=np.uint8,\n        ... ))\n\n        >>> sim.get_measurement_flips()\n        array([[False,  True, False, False,  True, False, False,  True,  True],\n               [ True, False, False,  True, False, False,  True,  True, False],\n               [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n               [False, False, False, False, False, False, False, False, False],\n               [ True,  True,  True,  True,  True,  True,  True,  True,  True]])\n\n        >>> sim.append_measurement_flips(np.array(\n        ...     [[1, 0, 1, 0, 1, 0, 1, 0, 1], [0, 1, 0, 1, 0, 1, 0, 1, 0]],\n        ...     dtype=np.bool_,\n        ... ))\n\n        >>> sim.get_measurement_flips()\n        array([[False,  True, False, False,  True, False, False,  True,  True],\n               [ True, False, False,  True, False, False,  True,  True, False],\n               [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n               [False, False, False, False, False, False, False, False, False],\n               [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n               [ True, False,  True, False,  True, False,  True, False,  True],\n               [False,  True, False,  True, False,  True, False,  True, False]])\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.batch_size\"></a>\n```python\n# stim.FlipSimulator.batch_size\n\n# (in class stim.FlipSimulator)\n@property\ndef batch_size(\n    self,\n) -> int:\n    \"\"\"Returns the number of instances being simulated by the simulator.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n        >>> sim.batch_size\n        256\n        >>> sim = stim.FlipSimulator(batch_size=42)\n        >>> sim.batch_size\n        42\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.broadcast_pauli_errors\"></a>\n```python\n# stim.FlipSimulator.broadcast_pauli_errors\n\n# (in class stim.FlipSimulator)\ndef broadcast_pauli_errors(\n    self,\n    *,\n    pauli: Union[str, int],\n    mask: np.ndarray,\n    p: float = 1,\n) -> None:\n    \"\"\"Applies a pauli error to all qubits in all instances, filtered by a mask.\n\n    Args:\n        pauli: The pauli, specified as an integer or string.\n            Uses the convention 0=I, 1=X, 2=Y, 3=Z.\n            Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.\n        mask: A 2d numpy array specifying where to apply errors. The first axis\n            is qubits, the second axis is simulation instances. The first axis\n            can have a length less than the current number of qubits (or more,\n            which adds qubits to the simulation). The length of the second axis\n            must match the simulator's `batch_size`. The array must satisfy\n\n                mask.dtype == np.bool_\n                len(mask.shape) == 2\n                mask.shape[1] == flip_sim.batch_size\n\n            The error is only applied to qubit q in instance k when\n\n                mask[q, k] == True.\n        p: Defaults to 1 (no effect). When specified, the error is applied\n            probabilistically instead of deterministically to each (instance, qubit)\n            pair matching the mask. This argument specifies the probability.\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n        >>> sim = stim.FlipSimulator(\n        ...     batch_size=2,\n        ...     num_qubits=3,\n        ...     disable_stabilizer_randomization=True,\n        ... )\n        >>> sim.broadcast_pauli_errors(\n        ...     pauli='X',\n        ...     mask=np.asarray([[True, False],[False, False],[True, True]]),\n        ... )\n        >>> sim.peek_pauli_flips()\n        [stim.PauliString(\"+X_X\"), stim.PauliString(\"+__X\")]\n\n        >>> sim.broadcast_pauli_errors(\n        ...     pauli='Z',\n        ...     mask=np.asarray([[False, True],[False, False],[True, True]]),\n        ... )\n        >>> sim.peek_pauli_flips()\n        [stim.PauliString(\"+X_Y\"), stim.PauliString(\"+Z_Y\")]\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.clear\"></a>\n```python\n# stim.FlipSimulator.clear\n\n# (in class stim.FlipSimulator)\ndef clear(\n    self,\n) -> None:\n    \"\"\"Clears the simulator's state, so it can be reused for another simulation.\n\n    This clears the measurement flip history, clears the detector flip history,\n    and zeroes the observable flip state. It also resets all qubits to |0>. If\n    stabilizer randomization is disabled, this zeros all pauli flip data. Otherwise\n    it randomizes all pauli flips to be I or Z with equal probability.\n\n    Behind the scenes, this doesn't free memory or resize the simulator. So,\n    repeating the same simulation with calls to `clear` in between will be faster\n    than allocating a new simulator each time (by avoiding re-allocations).\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n        >>> sim.do(stim.Circuit(\"M(0.1) 9\"))\n        >>> sim.num_qubits\n        10\n        >>> sim.get_measurement_flips().shape\n        (1, 256)\n\n        >>> sim.clear()\n        >>> sim.num_qubits\n        10\n        >>> sim.get_measurement_flips().shape\n        (0, 256)\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.copy\"></a>\n```python\n# stim.FlipSimulator.copy\n\n# (in class stim.FlipSimulator)\ndef copy(\n    self,\n    *,\n    copy_rng: bool = False,\n    seed: Optional[int] = None,\n) -> stim.FlipSimulator:\n    \"\"\"Returns a simulator with the same internal state, except perhaps its prng.\n\n    Args:\n        copy_rng: Defaults to False. When False, the copy's pseudo random number\n            generator is reinitialized with a random seed instead of being a copy\n            of the original simulator's pseudo random number generator. This\n            causes the copy and the original to sample independent randomness,\n            instead of identical randomness, for future random operations. When set\n            to true, the copy will have the exact same pseudo random number\n            generator state as the original, and so will produce identical results\n            if told to do the same noisy operations. This argument is incompatible\n            with the `seed` argument.\n\n        seed: PARTIALLY determines simulation results by deterministically seeding\n            the random number generator.\n\n            Must be None or an integer in range(2**64).\n\n            Defaults to None. When None, the prng state is either copied from the\n            original simulator or reseeded from system entropy, depending on the\n            copy_rng argument.\n\n            When set to an integer, making the exact same series calls on the exact\n            same machine with the exact same version of Stim will produce the exact\n            same simulation results.\n\n            CAUTION: simulation results *WILL NOT* be consistent between versions of\n            Stim. This restriction is present to make it possible to have future\n            optimizations to the random sampling, and is enforced by introducing\n            intentional differences in the seeding strategy from version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines that\n            differ in the width of supported SIMD instructions. For example, using\n            the same seed on a machine that supports AVX instructions and one that\n            only supports SSE instructions may produce different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n            circuit is executed. For example, reordering whether a reset on one\n            qubit happens before or after a reset on another qubit can result in\n            different measurement results being observed starting from the same\n            seed.\n\n    Returns:\n        The copy of the simulator.\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n\n        >>> s1 = stim.FlipSimulator(batch_size=256)\n        >>> s1.set_pauli_flip('X', qubit_index=2, instance_index=3)\n        >>> s2 = s1.copy()\n        >>> s2 is s1\n        False\n        >>> s2.peek_pauli_flips() == s1.peek_pauli_flips()\n        True\n\n        >>> s1 = stim.FlipSimulator(batch_size=256)\n        >>> s2 = s1.copy(copy_rng=True)\n        >>> s1.do(stim.Circuit(\"X_ERROR(0.25) 0 \\n M 0\"))\n        >>> s2.do(stim.Circuit(\"X_ERROR(0.25) 0 \\n M 0\"))\n        >>> np.array_equal(s1.get_measurement_flips(), s2.get_measurement_flips())\n        True\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.do\"></a>\n```python\n# stim.FlipSimulator.do\n\n# (in class stim.FlipSimulator)\ndef do(\n    self,\n    obj: Union[stim.Circuit, stim.CircuitInstruction, stim.CircuitRepeatBlock],\n) -> None:\n    \"\"\"Applies a circuit or circuit instruction to the simulator's state.\n\n    The results of any measurements performed can be retrieved using the\n    `get_measurement_flips` method.\n\n    Args:\n        obj: The circuit or instruction to apply to the simulator's state.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(\n        ...     batch_size=1,\n        ...     disable_stabilizer_randomization=True,\n        ... )\n        >>> circuit = stim.Circuit('''\n        ...     X_ERROR(1) 0 1 3\n        ...     REPEAT 5 {\n        ...         H 0\n        ...         C_XYZ 1\n        ...     }\n        ... ''')\n        >>> sim.do(circuit)\n        >>> sim.peek_pauli_flips()\n        [stim.PauliString(\"+ZZ_X\")]\n\n        >>> sim.do(circuit[0])\n        >>> sim.peek_pauli_flips()\n        [stim.PauliString(\"+YY__\")]\n\n        >>> sim.do(circuit[1])\n        >>> sim.peek_pauli_flips()\n        [stim.PauliString(\"+YX__\")]\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.generate_bernoulli_samples\"></a>\n```python\n# stim.FlipSimulator.generate_bernoulli_samples\n\n# (in class stim.FlipSimulator)\ndef generate_bernoulli_samples(\n    self,\n    num_samples: int,\n    *,\n    p: float,\n    bit_packed: bool = False,\n    out: Optional[np.ndarray] = None,\n) -> np.ndarray:\n    \"\"\"Uses the simulator's random number generator to produce biased coin flips.\n\n    This method has best performance when specifying `bit_packed=True` and\n    when specifying an `out=` parameter pointing to a numpy array that has\n    contiguous data aligned to a 64 bit boundary. (If `out` isn't specified,\n    the returned numpy array will have this property.)\n\n    Args:\n        num_samples: The number of samples to produce.\n        p: The probability of each sample being True instead of False.\n        bit_packed: Defaults to False (no bit packing). When True, the result\n            has type np.uint8 instead of np.bool_ and 8 samples are packed into\n            each byte as if by np.packbits(bitorder='little'). (The bit order\n            is relevant when producing a number of samples that isn't a multiple\n            of 8.)\n        out: Defaults to None (allocate new). A numpy array to write the samples\n            into. Must have the correct size and dtype.\n\n    Returns:\n        A numpy array containing the samples. The shape and dtype depends on\n        the bit_packed argument:\n\n            if not bit_packed:\n                shape = (num_samples,)\n                dtype = np.bool_\n            elif not transpose and bit_packed:\n                shape = (math.ceil(num_samples / 8),)\n                dtype = np.uint8\n\n    Raises:\n        ValueError:\n            The given `out` argument had a shape or dtype inconsistent with the\n            requested data.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n        >>> r = sim.generate_bernoulli_samples(1001, p=0.25)\n        >>> r.dtype\n        dtype('bool')\n        >>> r.shape\n        (1001,)\n\n        >>> r = sim.generate_bernoulli_samples(53, p=0.1, bit_packed=True)\n        >>> r.dtype\n        dtype('uint8')\n        >>> r.shape\n        (7,)\n        >>> r[6] & 0b1110_0000  # zero'd padding bits\n        np.uint8(0)\n\n        >>> r2 = sim.generate_bernoulli_samples(53, p=0.2, bit_packed=True, out=r)\n        >>> r is r2  # Check request to reuse r worked.\n        True\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.get_detector_flips\"></a>\n```python\n# stim.FlipSimulator.get_detector_flips\n\n# (in class stim.FlipSimulator)\ndef get_detector_flips(\n    self,\n    *,\n    detector_index: Optional[int] = None,\n    instance_index: Optional[int] = None,\n    bit_packed: bool = False,\n) -> np.ndarray:\n    \"\"\"Retrieves detector flip data from the simulator's detection event record.\n\n    Args:\n        record_index: Identifies a detector to read results from.\n            Setting this to None (default) returns results from all detectors.\n            Otherwise this should be an integer in range(0, self.num_detectors).\n        instance_index: Identifies a simulation instance to read results from.\n            Setting this to None (the default) returns results from all instances.\n            Otherwise this should be an integer in range(0, self.batch_size).\n        bit_packed: Defaults to False. Determines whether the result is bit packed.\n            If this is set to true, the returned numpy array will be bit packed as\n            if by applying\n\n                out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n            Behind the scenes the data is always bit packed, so setting this\n            argument avoids ever unpacking in the first place. This substantially\n            improves performance when there is a lot of data.\n\n    Returns:\n        A numpy array containing the requested data. By default this is a 2d array\n        of shape (self.num_detectors, self.batch_size), where the first index is\n        the detector_index and the second index is the instance_index and the\n        dtype is np.bool_.\n\n        Specifying detector_index slices away the first index, leaving a 1d array\n        with only an instance_index.\n\n        Specifying instance_index slices away the last index, leaving a 1d array\n        with only a detector_index (or a 0d array, a boolean, if detector_index\n        was also specified).\n\n        Specifying bit_packed=True bit packs the last remaining index, changing\n        the dtype to np.uint8.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=9)\n        >>> sim.do(stim.Circuit('''\n        ...     M 0 0 0\n        ...     DETECTOR rec[-2] rec[-3]\n        ...     DETECTOR rec[-1] rec[-2]\n        ... '''))\n\n        >>> sim.get_detector_flips()\n        array([[False, False, False, False, False, False, False, False, False],\n               [False, False, False, False, False, False, False, False, False]])\n\n        >>> sim.get_detector_flips(bit_packed=True)\n        array([[0, 0],\n               [0, 0]], dtype=uint8)\n\n        >>> sim.get_detector_flips(instance_index=2)\n        array([False, False])\n\n        >>> sim.get_detector_flips(detector_index=1)\n        array([False, False, False, False, False, False, False, False, False])\n\n        >>> sim.get_detector_flips(instance_index=2, detector_index=1)\n        array(False)\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.get_measurement_flips\"></a>\n```python\n# stim.FlipSimulator.get_measurement_flips\n\n# (in class stim.FlipSimulator)\ndef get_measurement_flips(\n    self,\n    *,\n    record_index: Optional[int] = None,\n    instance_index: Optional[int] = None,\n    bit_packed: bool = False,\n) -> np.ndarray:\n    \"\"\"Retrieves measurement flip data from the simulator's measurement record.\n\n    Args:\n        record_index: Identifies a measurement to read results from.\n            Setting this to None (default) returns results from all measurements.\n            Setting this to a non-negative integer indexes measurements by the order\n                they occurred. For example, record index 0 is the first measurement.\n            Setting this to a negative integer indexes measurements by recency.\n                For example, recording index -1 is the most recent measurement.\n        instance_index: Identifies a simulation instance to read results from.\n            Setting this to None (the default) returns results from all instances.\n            Otherwise this should be set to an integer in range(0, self.batch_size).\n        bit_packed: Defaults to False. Determines whether the result is bit packed.\n            If this is set to true, the returned numpy array will be bit packed as\n            if by applying\n\n                out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n            Behind the scenes the data is always bit packed, so setting this\n            argument avoids ever unpacking in the first place. This substantially\n            improves performance when there is a lot of data.\n\n    Returns:\n        A numpy array containing the requested data. By default this is a 2d array\n        of shape (self.num_measurements, self.batch_size), where the first index is\n        the measurement_index and the second index is the instance_index and the\n        dtype is np.bool_.\n\n        Specifying record_index slices away the first index, leaving a 1d array\n        with only an instance_index.\n\n        Specifying instance_index slices away the last index, leaving a 1d array\n        with only a measurement_index (or a 0d array, a boolean, if record_index\n        was also specified).\n\n        Specifying bit_packed=True bit packs the last remaining index, changing\n        the dtype to np.uint8.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=9)\n        >>> sim.do(stim.Circuit('M 0 1 2'))\n\n        >>> sim.get_measurement_flips()\n        array([[False, False, False, False, False, False, False, False, False],\n               [False, False, False, False, False, False, False, False, False],\n               [False, False, False, False, False, False, False, False, False]])\n\n        >>> sim.get_measurement_flips(bit_packed=True)\n        array([[0, 0],\n               [0, 0],\n               [0, 0]], dtype=uint8)\n\n        >>> sim.get_measurement_flips(instance_index=1)\n        array([False, False, False])\n\n        >>> sim.get_measurement_flips(record_index=2)\n        array([False, False, False, False, False, False, False, False, False])\n\n        >>> sim.get_measurement_flips(instance_index=1, record_index=2)\n        array(False)\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.get_observable_flips\"></a>\n```python\n# stim.FlipSimulator.get_observable_flips\n\n# (in class stim.FlipSimulator)\ndef get_observable_flips(\n    self,\n    *,\n    observable_index: Optional[int] = None,\n    instance_index: Optional[int] = None,\n    bit_packed: bool = False,\n) -> np.ndarray:\n    \"\"\"Retrieves observable flip data from the simulator's detection event record.\n\n    Args:\n        record_index: Identifies a observable to read results from.\n            Setting this to None (default) returns results from all observables.\n            Otherwise this should be an integer in range(0, self.num_observables).\n        instance_index: Identifies a simulation instance to read results from.\n            Setting this to None (the default) returns results from all instances.\n            Otherwise this should be an integer in range(0, self.batch_size).\n        bit_packed: Defaults to False. Determines whether the result is bit packed.\n            If this is set to true, the returned numpy array will be bit packed as\n            if by applying\n\n                out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n            Behind the scenes the data is always bit packed, so setting this\n            argument avoids ever unpacking in the first place. This substantially\n            improves performance when there is a lot of data.\n\n    Returns:\n        A numpy array containing the requested data. By default this is a 2d array\n        of shape (self.num_observables, self.batch_size), where the first index is\n        the observable_index and the second index is the instance_index and the\n        dtype is np.bool_.\n\n        Specifying observable_index slices away the first index, leaving a 1d array\n        with only an instance_index.\n\n        Specifying instance_index slices away the last index, leaving a 1d array\n        with only a observable_index (or a 0d array, a boolean, if observable_index\n        was also specified).\n\n        Specifying bit_packed=True bit packs the last remaining index, changing\n        the dtype to np.uint8.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=9)\n        >>> sim.do(stim.Circuit('''\n        ...     M 0 0 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-2]\n        ...     OBSERVABLE_INCLUDE(1) rec[-1]\n        ... '''))\n\n        >>> sim.get_observable_flips()\n        array([[False, False, False, False, False, False, False, False, False],\n               [False, False, False, False, False, False, False, False, False]])\n\n        >>> sim.get_observable_flips(bit_packed=True)\n        array([[0, 0],\n               [0, 0]], dtype=uint8)\n\n        >>> sim.get_observable_flips(instance_index=2)\n        array([False, False])\n\n        >>> sim.get_observable_flips(observable_index=1)\n        array([False, False, False, False, False, False, False, False, False])\n\n        >>> sim.get_observable_flips(instance_index=2, observable_index=1)\n        array(False)\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.num_detectors\"></a>\n```python\n# stim.FlipSimulator.num_detectors\n\n# (in class stim.FlipSimulator)\n@property\ndef num_detectors(\n    self,\n) -> int:\n    \"\"\"Returns the number of detectors that have been simulated and stored.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n        >>> sim.num_detectors\n        0\n        >>> sim.do(stim.Circuit('''\n        ...     M 0 0\n        ...     DETECTOR rec[-1] rec[-2]\n        ... '''))\n        >>> sim.num_detectors\n        1\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.num_measurements\"></a>\n```python\n# stim.FlipSimulator.num_measurements\n\n# (in class stim.FlipSimulator)\n@property\ndef num_measurements(\n    self,\n) -> int:\n    \"\"\"Returns the number of measurements that have been simulated and stored.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n        >>> sim.num_measurements\n        0\n        >>> sim.do(stim.Circuit('M 3 5'))\n        >>> sim.num_measurements\n        2\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.num_observables\"></a>\n```python\n# stim.FlipSimulator.num_observables\n\n# (in class stim.FlipSimulator)\n@property\ndef num_observables(\n    self,\n) -> int:\n    \"\"\"Returns the number of observables currently tracked by the simulator.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n        >>> sim.num_observables\n        0\n        >>> sim.do(stim.Circuit('''\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(4) rec[-1]\n        ... '''))\n        >>> sim.num_observables\n        5\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.num_qubits\"></a>\n```python\n# stim.FlipSimulator.num_qubits\n\n# (in class stim.FlipSimulator)\n@property\ndef num_qubits(\n    self,\n) -> int:\n    \"\"\"Returns the number of qubits currently tracked by the simulator.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n        >>> sim.num_qubits\n        0\n        >>> sim = stim.FlipSimulator(batch_size=256, num_qubits=4)\n        >>> sim.num_qubits\n        4\n        >>> sim.do(stim.Circuit('H 5'))\n        >>> sim.num_qubits\n        6\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.peek_pauli_flips\"></a>\n```python\n# stim.FlipSimulator.peek_pauli_flips\n\n# (in class stim.FlipSimulator)\n@overload\ndef peek_pauli_flips(\n    self,\n) -> List[stim.PauliString]:\n    pass\n@overload\ndef peek_pauli_flips(\n    self,\n    *,\n    instance_index: int,\n) -> stim.PauliString:\n    pass\ndef peek_pauli_flips(\n    self,\n    *,\n    instance_index: Optional[int] = None,\n) -> Union[stim.PauliString, List[stim.PauliString]]:\n    \"\"\"Returns the current pauli errors packed into stim.PauliString instances.\n\n    Args:\n        instance_index: Defaults to None. When set to None, the pauli errors from\n            all instances are returned as a list of `stim.PauliString`. When set to\n            an integer, a single `stim.PauliString` is returned containing the\n            errors for the indexed instance.\n\n    Returns:\n        if instance_index is None:\n            A list of stim.PauliString, with the k'th entry being the errors from\n            the k'th simulation instance.\n        else:\n            A stim.PauliString with the errors from the k'th simulation instance.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(\n        ...     batch_size=2,\n        ...     disable_stabilizer_randomization=True,\n        ...     num_qubits=10,\n        ... )\n\n        >>> sim.peek_pauli_flips()\n        [stim.PauliString(\"+__________\"), stim.PauliString(\"+__________\")]\n\n        >>> sim.peek_pauli_flips(instance_index=0)\n        stim.PauliString(\"+__________\")\n\n        >>> sim.do(stim.Circuit('''\n        ...     X_ERROR(1) 0 3 5\n        ...     Z_ERROR(1) 3 6\n        ... '''))\n\n        >>> sim.peek_pauli_flips()\n        [stim.PauliString(\"+X__Y_XZ___\"), stim.PauliString(\"+X__Y_XZ___\")]\n\n        >>> sim = stim.FlipSimulator(\n        ...     batch_size=1,\n        ...     num_qubits=100,\n        ... )\n        >>> flips: stim.PauliString = sim.peek_pauli_flips(instance_index=0)\n        >>> sorted(set(str(flips)))  # Should have Zs from stabilizer randomization\n        ['+', 'Z', '_']\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.set_pauli_flip\"></a>\n```python\n# stim.FlipSimulator.set_pauli_flip\n\n# (in class stim.FlipSimulator)\ndef set_pauli_flip(\n    self,\n    pauli: Union[str, int],\n    *,\n    qubit_index: int,\n    instance_index: int,\n) -> None:\n    \"\"\"Sets the pauli flip on a given qubit in a given simulation instance.\n\n    Args:\n        pauli: The pauli, specified as an integer or string.\n            Uses the convention 0=I, 1=X, 2=Y, 3=Z.\n            Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.\n        qubit_index: The qubit to put the error on. Must be non-negative. The state\n            will automatically expand as needed to store the error.\n        instance_index: The simulation index to put the error inside. Use negative\n            indices to index from the end of the list.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(\n        ...     batch_size=2,\n        ...     num_qubits=3,\n        ...     disable_stabilizer_randomization=True,\n        ... )\n        >>> sim.set_pauli_flip('X', qubit_index=2, instance_index=1)\n        >>> sim.peek_pauli_flips()\n        [stim.PauliString(\"+___\"), stim.PauliString(\"+__X\")]\n    \"\"\"\n```\n\n<a name=\"stim.FlipSimulator.to_numpy\"></a>\n```python\n# stim.FlipSimulator.to_numpy\n\n# (in class stim.FlipSimulator)\ndef to_numpy(\n    self,\n    *,\n    bit_packed: bool = False,\n    transpose: bool = False,\n    output_xs: Union[bool, np.ndarray] = False,\n    output_zs: Union[bool, np.ndarray] = False,\n    output_measure_flips: Union[bool, np.ndarray] = False,\n    output_detector_flips: Union[bool, np.ndarray] = False,\n    output_observable_flips: Union[bool, np.ndarray] = False,\n) -> Optional[Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]]:\n    \"\"\"Writes the simulator state into numpy arrays.\n\n    Args:\n        bit_packed: Whether or not the result is bit packed, storing 8 bits per\n            byte instead of 1 bit per byte. Bit packing always applies to\n            the second index of the result. Bits are packed in little endian\n            order (as if by `np.packbits(X, axis=1, order='little')`).\n        transpose: Defaults to False. When set to False, the second index of the\n            returned array (the index affected by bit packing) is the shot index\n            (meaning the first index is the qubit index or measurement index or\n            etc). When set to True, results are transposed so that the first\n            index is the shot index.\n        output_xs: Defaults to False. When set to False, the X flip data is not\n            generated and the corresponding array in the result tuple is set to\n            None. When set to True, a new array is allocated to hold the X flip\n            data and this array is returned via the result tuple. When set to\n            a numpy array, the results are written into that array (the shape and\n            dtype of the array must be exactly correct).\n        output_zs: Defaults to False. When set to False, the Z flip data is not\n            generated and the corresponding array in the result tuple is set to\n            None. When set to True, a new array is allocated to hold the Z flip\n            data and this array is returned via the result tuple. When set to\n            a numpy array, the results are written into that array (the shape and\n            dtype of the array must be exactly correct).\n        output_measure_flips: Defaults to False. When set to False, the measure\n            flip data is not generated and the corresponding array in the result\n            tuple is set to None. When set to True, a new array is allocated to\n            hold the measure flip data and this array is returned via the result\n            tuple. When set to a numpy array, the results are written into that\n            array (the shape and dtype of the array must be exactly correct).\n        output_detector_flips: Defaults to False. When set to False, the detector\n            flip data is not generated and the corresponding array in the result\n            tuple is set to None. When set to True, a new array is allocated to\n            hold the detector flip data and this array is returned via the result\n            tuple. When set to a numpy array, the results are written into that\n            array (the shape and dtype of the array must be exactly correct).\n        output_observable_flips: Defaults to False. When set to False, the obs\n            flip data is not generated and the corresponding array in the result\n            tuple is set to None. When set to True, a new array is allocated to\n            hold the obs flip data and this array is returned via the result\n            tuple. When set to a numpy array, the results are written into that\n            array (the shape and dtype of the array must be exactly correct).\n\n    Returns:\n        A tuple (xs, zs, ms, ds, os) of numpy arrays. The xs and zs arrays are\n        the pauli flip data specified using XZ encoding (00=I, 10=X, 11=Y, 01=Z).\n        The ms array is the measure flip data, the ds array is the detector flip\n        data, and the os array is the obs flip data. The arrays default to\n        `None` when the corresponding `output_*` argument was left False.\n\n        The shape and dtype of the data depends on arguments given to the function.\n        The following specifies each array's shape and dtype for each case:\n\n            if not transpose and not bit_packed:\n                xs.shape = (sim.batch_size, sim.num_qubits)\n                zs.shape = (sim.batch_size, sim.num_qubits)\n                ms.shape = (sim.batch_size, sim.num_measurements)\n                ds.shape = (sim.batch_size, sim.num_detectors)\n                os.shape = (sim.batch_size, sim.num_observables)\n                xs.dtype = np.bool_\n                zs.dtype = np.bool_\n                ms.dtype = np.bool_\n                ds.dtype = np.bool_\n                os.dtype = np.bool_\n            elif not transpose and bit_packed:\n                xs.shape = (sim.batch_size, math.ceil(sim.num_qubits / 8))\n                zs.shape = (sim.batch_size, math.ceil(sim.num_qubits / 8))\n                ms.shape = (sim.batch_size, math.ceil(sim.num_measurements / 8))\n                ds.shape = (sim.batch_size, math.ceil(sim.num_detectors / 8))\n                os.shape = (sim.batch_size, math.ceil(sim.num_observables / 8))\n                xs.dtype = np.uint8\n                zs.dtype = np.uint8\n                ms.dtype = np.uint8\n                ds.dtype = np.uint8\n                os.dtype = np.uint8\n            elif transpose and not bit_packed:\n                xs.shape = (sim.num_qubits, sim.batch_size)\n                zs.shape = (sim.num_qubits, sim.batch_size)\n                ms.shape = (sim.num_measurements, sim.batch_size)\n                ds.shape = (sim.num_detectors, sim.batch_size)\n                os.shape = (sim.num_observables, sim.batch_size)\n                xs.dtype = np.bool_\n                zs.dtype = np.bool_\n                ms.dtype = np.bool_\n                ds.dtype = np.bool_\n                os.dtype = np.bool_\n            elif transpose and bit_packed:\n                xs.shape = (sim.num_qubits, math.ceil(sim.batch_size / 8))\n                zs.shape = (sim.num_qubits, math.ceil(sim.batch_size / 8))\n                ms.shape = (sim.num_measurements, math.ceil(sim.batch_size / 8))\n                ds.shape = (sim.num_detectors, math.ceil(sim.batch_size / 8))\n                os.shape = (sim.num_observables, math.ceil(sim.batch_size / 8))\n                xs.dtype = np.uint8\n                zs.dtype = np.uint8\n                ms.dtype = np.uint8\n                ds.dtype = np.uint8\n                os.dtype = np.uint8\n\n    Raises:\n        ValueError:\n            All the `output_*` arguments were False, or an `output_*` argument\n            had a shape or dtype inconsistent with the requested data.\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n        >>> sim = stim.FlipSimulator(batch_size=9)\n        >>> sim.do(stim.Circuit('M(1) 0 1 2'))\n\n        >>> ms_buf = np.empty(shape=(9, 1), dtype=np.uint8)\n        >>> xs, zs, ms, ds, os = sim.to_numpy(\n        ...     transpose=True,\n        ...     bit_packed=True,\n        ...     output_xs=True,\n        ...     output_measure_flips=ms_buf,\n        ... )\n        >>> assert ms is ms_buf\n        >>> xs\n        array([[0],\n               [0],\n               [0],\n               [0],\n               [0],\n               [0],\n               [0],\n               [0],\n               [0]], dtype=uint8)\n        >>> zs\n        >>> ms\n        array([[7],\n               [7],\n               [7],\n               [7],\n               [7],\n               [7],\n               [7],\n               [7],\n               [7]], dtype=uint8)\n        >>> ds\n        >>> os\n    \"\"\"\n```\n\n<a name=\"stim.FlippedMeasurement\"></a>\n```python\n# stim.FlippedMeasurement\n\n# (at top-level in the stim module)\nclass FlippedMeasurement:\n    \"\"\"Describes a measurement that was flipped.\n\n    Gives the measurement's index in the measurement record, and also\n    the observable of the measurement.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     M(0.25) 1 10\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].flipped_measurement\n        stim.FlippedMeasurement(\n            record_index=1,\n            observable=(stim.GateTargetWithCoords(stim.target_z(10), []),),\n        )\n    \"\"\"\n```\n\n<a name=\"stim.FlippedMeasurement.__init__\"></a>\n```python\n# stim.FlippedMeasurement.__init__\n\n# (in class stim.FlippedMeasurement)\ndef __init__(\n    self,\n    measurement_record_index: Optional[int],\n    measured_observable: Iterable[stim.GateTargetWithCoords],\n):\n    \"\"\"Creates a stim.FlippedMeasurement.\n\n    Examples:\n        >>> import stim\n        >>> print(stim.FlippedMeasurement(\n        ...     record_index=5,\n        ...     observable=[],\n        ... ))\n        stim.FlippedMeasurement(\n            record_index=5,\n            observable=(),\n        )\n    \"\"\"\n```\n\n<a name=\"stim.FlippedMeasurement.observable\"></a>\n```python\n# stim.FlippedMeasurement.observable\n\n# (in class stim.FlippedMeasurement)\n@property\ndef observable(\n    self,\n) -> List[stim.GateTargetWithCoords]:\n    \"\"\"Returns the observable of the flipped measurement.\n\n    For example, an `MX 5` measurement will have the observable X5.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     M(0.25) 1 10\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].flipped_measurement.observable\n        [stim.GateTargetWithCoords(stim.target_z(10), [])]\n    \"\"\"\n```\n\n<a name=\"stim.FlippedMeasurement.record_index\"></a>\n```python\n# stim.FlippedMeasurement.record_index\n\n# (in class stim.FlippedMeasurement)\n@property\ndef record_index(\n    self,\n) -> int:\n    \"\"\"The measurement record index of the flipped measurement.\n    For example, the fifth measurement in a circuit has a measurement\n    record index of 4.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     M(0.25) 1 10\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].flipped_measurement.record_index\n        1\n    \"\"\"\n```\n\n<a name=\"stim.Flow\"></a>\n```python\n# stim.Flow\n\n# (at top-level in the stim module)\nclass Flow:\n    \"\"\"A stabilizer flow (e.g. \"XI -> XX xor rec[-1]\").\n\n    Stabilizer circuits implement, and can be defined by, how they turn input\n    stabilizers into output stabilizers mediated by measurements. These\n    relationships are called stabilizer flows, and `stim.Flow` is a representation\n    of such a flow. For example, a `stim.Flow` can be given to\n    `stim.Circuit.has_flow` to verify that a circuit implements the flow.\n\n    A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer\n    P at the start of the circuit to the instantaneous stabilizer Q at the end of\n    the circuit. The flow may be mediated by certain measurements. For example,\n    a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and\n    the CNOT flows implemented by the circuit involve these measurements.\n\n    A flow like P -> Q means the circuit transforms P into Q.\n    A flow like 1 -> P means the circuit prepares P.\n    A flow like P -> 1 means the circuit measures P.\n    A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR).\n\n    References:\n        Stim's gate documentation includes the stabilizer flows of each gate.\n\n        Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are\n        defined and provides a circuit construction for experimentally verifying\n        their presence.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit(\"CNOT 2 4\")\n\n        >>> c.has_flow(stim.Flow(\"__X__ -> __X_X\"))\n        True\n\n        >>> c.has_flow(stim.Flow(\"X2*X4 -> X2\"))\n        True\n\n        >>> c.has_flow(stim.Flow(\"Z4 -> Z4\"))\n        False\n    \"\"\"\n```\n\n<a name=\"stim.Flow.__eq__\"></a>\n```python\n# stim.Flow.__eq__\n\n# (in class stim.Flow)\ndef __eq__(\n    self,\n    arg0: stim.Flow,\n) -> bool:\n    \"\"\"Determines if two flows have identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.Flow.__init__\"></a>\n```python\n# stim.Flow.__init__\n\n# (in class stim.Flow)\ndef __init__(\n    self,\n    arg: Union[None, str, stim.Flow] = None,\n    /,\n    *,\n    input: Optional[stim.PauliString] = None,\n    output: Optional[stim.PauliString] = None,\n    measurements: Optional[Iterable[Union[int, GateTarget]]] = None,\n    included_observables: Optional[Iterable[int]] = None,\n) -> None:\n    \"\"\"Initializes a stim.Flow.\n\n    When given a string, the string is parsed as flow shorthand. For example,\n    the string \"X_ -> ZZ xor rec[-1]\" will result in a flow with input pauli string\n    \"X_\", output pauli string \"ZZ\", and measurement indices [-1].\n\n    Args:\n        arg [position-only]: Defaults to None. Must be specified by itself if used.\n            str: Initializes a flow by parsing the given shorthand text.\n            stim.Flow: Initializes a copy of the given flow.\n            None (default): Initializes an empty flow.\n        input: Defaults to None. Can be set to a stim.PauliString to directly\n            specify the flow's input stabilizer.\n        output: Defaults to None. Can be set to a stim.PauliString to directly\n            specify the flow's output stabilizer.\n        measurements: Defaults to None. Can be set to a list of integers or gate\n            targets like `stim.target_rec(-1)`, to specify the measurements that\n            mediate the flow. Negative and positive measurement indices are allowed.\n            Indexes follow the python convention where -1 is the last measurement in\n            a circuit and 0 is the first measurement in a circuit.\n        included_observables: Defaults to None. `OBSERVABLE_INCLUDE` instructions\n            that target an observable index from this list will be implicitly\n            included in the flow. This allows flows to refer to observables. For\n            example, the flow \"X5 -> obs[3]\" says \"At the start of the circuit,\n            observable 3 should be an X term on qubit 5. By the end of the circuit\n            it will be measured. The `OBSERVABLE_INCLUDE(3)` instructions in the\n            circuit should explain how this happened.\".\n\n    Examples:\n        >>> import stim\n\n        >>> stim.Flow(\"X2 -> -Y2*Z4 xor rec[-1]\")\n        stim.Flow(\"__X -> -__Y_Z xor rec[-1]\")\n\n        >>> stim.Flow(\"Z -> 1 xor rec[-1]\")\n        stim.Flow(\"Z -> rec[-1]\")\n\n        >>> stim.Flow(\n        ...     input=stim.PauliString(\"XX\"),\n        ...     output=stim.PauliString(\"_X\"),\n        ...     measurements=[],\n        ... )\n        stim.Flow(\"XX -> _X\")\n\n        >>> # Identical terms cancel.\n        >>> stim.Flow(\"X2 -> Y2*Y2 xor rec[-2] xor rec[-2]\")\n        stim.Flow(\"__X -> ___\")\n\n        >>> stim.Flow(\"X -> Y xor obs[3] xor obs[3] xor obs[3]\")\n        stim.Flow(\"X -> Y xor obs[3]\")\n    \"\"\"\n```\n\n<a name=\"stim.Flow.__mul__\"></a>\n```python\n# stim.Flow.__mul__\n\n# (in class stim.Flow)\ndef __mul__(\n    self,\n    rhs: stim.Flow,\n) -> stim.Flow:\n    \"\"\"Computes the product of two flows.\n\n    Args:\n        rhs: The right hand side of the multiplication.\n\n    Returns:\n        The product of the two flows.\n\n    Raises:\n        ValueError: The inputs anti-commute (their product would be anti-Hermitian).\n            For example, 1 -> X times 1 -> Y fails because it would give 1 -> iZ.\n\n    Examples:\n        >>> import stim\n        >>> stim.Flow(\"X -> X\") * stim.Flow(\"Z -> Z\")\n        stim.Flow(\"Y -> Y\")\n\n        >>> stim.Flow(\"1 -> XX\") * stim.Flow(\"1 -> ZZ\")\n        stim.Flow(\"1 -> -YY\")\n\n        >>> stim.Flow(\"X -> rec[-1]\") * stim.Flow(\"X -> rec[-2]\")\n        stim.Flow(\"_ -> rec[-2] xor rec[-1]\")\n    \"\"\"\n```\n\n<a name=\"stim.Flow.__ne__\"></a>\n```python\n# stim.Flow.__ne__\n\n# (in class stim.Flow)\ndef __ne__(\n    self,\n    arg0: stim.Flow,\n) -> bool:\n    \"\"\"Determines if two flows have non-identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.Flow.__repr__\"></a>\n```python\n# stim.Flow.__repr__\n\n# (in class stim.Flow)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns valid python code evaluating to an equivalent `stim.Flow`.\n    \"\"\"\n```\n\n<a name=\"stim.Flow.__str__\"></a>\n```python\n# stim.Flow.__str__\n\n# (in class stim.Flow)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns a shorthand description of the flow.\n    \"\"\"\n```\n\n<a name=\"stim.Flow.included_observables_copy\"></a>\n```python\n# stim.Flow.included_observables_copy\n\n# (in class stim.Flow)\ndef included_observables_copy(\n    self,\n) -> List[int]:\n    \"\"\"Returns a copy of the flow's included observable indices.\n\n    When an observable is included in a flow, the flow implicitly includes all\n    measurements and pauli terms from `OBSERVABLE_INCLUDE` instructions targeting\n    that observable index.\n\n    Examples:\n        >>> import stim\n        >>> f = stim.Flow(included_observables=[3, 2])\n        >>> f.included_observables_copy()\n        [2, 3]\n\n        >>> f.included_observables_copy() is f.included_observables_copy()\n        False\n\n        >>> f = stim.Flow(\"X2 -> obs[3]\")\n        >>> f.included_observables_copy()\n        [3]\n        >>> stim.Circuit(\"OBSERVABLE_INCLUDE(3) X2\").has_flow(f)\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Flow.input_copy\"></a>\n```python\n# stim.Flow.input_copy\n\n# (in class stim.Flow)\ndef input_copy(\n    self,\n) -> stim.PauliString:\n    \"\"\"Returns a copy of the flow's input stabilizer.\n\n    Examples:\n        >>> import stim\n        >>> f = stim.Flow(input=stim.PauliString('XX'))\n        >>> f.input_copy()\n        stim.PauliString(\"+XX\")\n\n        >>> f.input_copy() is f.input_copy()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.Flow.measurements_copy\"></a>\n```python\n# stim.Flow.measurements_copy\n\n# (in class stim.Flow)\ndef measurements_copy(\n    self,\n) -> List[int]:\n    \"\"\"Returns a copy of the flow's measurement indices.\n\n    Examples:\n        >>> import stim\n        >>> f = stim.Flow(measurements=[-1, 2])\n        >>> f.measurements_copy()\n        [-1, 2]\n\n        >>> f.measurements_copy() is f.measurements_copy()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.Flow.output_copy\"></a>\n```python\n# stim.Flow.output_copy\n\n# (in class stim.Flow)\ndef output_copy(\n    self,\n) -> stim.PauliString:\n    \"\"\"Returns a copy of the flow's output stabilizer.\n\n    Examples:\n        >>> import stim\n        >>> f = stim.Flow(output=stim.PauliString('XX'))\n        >>> f.output_copy()\n        stim.PauliString(\"+XX\")\n\n        >>> f.output_copy() is f.output_copy()\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData\"></a>\n```python\n# stim.GateData\n\n# (at top-level in the stim module)\nclass GateData:\n    \"\"\"Details about a gate supported by stim.\n\n    Examples:\n        >>> import stim\n        >>> stim.gate_data('h').name\n        'H'\n        >>> stim.gate_data('h').is_unitary\n        True\n        >>> stim.gate_data('h').tableau\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.GateData.__eq__\"></a>\n```python\n# stim.GateData.__eq__\n\n# (in class stim.GateData)\ndef __eq__(\n    self,\n    arg0: stim.GateData,\n) -> bool:\n    \"\"\"Determines if two GateData instances are identical.\n    \"\"\"\n```\n\n<a name=\"stim.GateData.__init__\"></a>\n```python\n# stim.GateData.__init__\n\n# (in class stim.GateData)\ndef __init__(\n    self,\n    name: str,\n) -> None:\n    \"\"\"Finds gate data for the named gate.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateData('H').is_unitary\n        True\n    \"\"\"\n```\n\n<a name=\"stim.GateData.__ne__\"></a>\n```python\n# stim.GateData.__ne__\n\n# (in class stim.GateData)\ndef __ne__(\n    self,\n    arg0: stim.GateData,\n) -> bool:\n    \"\"\"Determines if two GateData instances are not identical.\n    \"\"\"\n```\n\n<a name=\"stim.GateData.__repr__\"></a>\n```python\n# stim.GateData.__repr__\n\n# (in class stim.GateData)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.GateData`.\n    \"\"\"\n```\n\n<a name=\"stim.GateData.__str__\"></a>\n```python\n# stim.GateData.__str__\n\n# (in class stim.GateData)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns text describing the gate data.\n    \"\"\"\n```\n\n<a name=\"stim.GateData.aliases\"></a>\n```python\n# stim.GateData.aliases\n\n# (in class stim.GateData)\n@property\ndef aliases(\n    self,\n) -> List[str]:\n    \"\"\"Returns all aliases that can be used to name the gate.\n\n    Although gates can be referred to by lower case and mixed\n    case named, the result only includes upper cased aliases.\n\n    Examples:\n        >>> import stim\n        >>> stim.gate_data('H').aliases\n        ['H', 'H_XZ']\n        >>> stim.gate_data('cnot').aliases\n        ['CNOT', 'CX', 'ZCX']\n    \"\"\"\n```\n\n<a name=\"stim.GateData.flows\"></a>\n```python\n# stim.GateData.flows\n\n# (in class stim.GateData)\n@property\ndef flows(\n    self,\n) -> Optional[List[stim.Flow]]:\n    \"\"\"Returns stabilizer flow generators for the gate, or else None.\n\n    A stabilizer flow describes an input-output relationship that the gate\n    satisfies, where an input pauli string is transformed into an output\n    pauli string mediated by certain measurement results.\n\n    Caution: this method returns None for variable-target-count gates like MPP.\n    Not because MPP has no stabilizer flows, but because its stabilizer flows\n    depend on how many qubits it targets and what basis it targets them in.\n\n    Returns:\n        A list of stim.Flow instances representing the generators.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('H').flows\n        [stim.Flow(\"X -> Z\"), stim.Flow(\"Z -> X\")]\n\n        >>> for e in stim.gate_data('ISWAP').flows:\n        ...     print(e)\n        X_ -> ZY\n        Z_ -> _Z\n        _X -> YZ\n        _Z -> Z_\n\n        >>> for e in stim.gate_data('MXX').flows:\n        ...     print(e)\n        X_ -> X_\n        _X -> _X\n        ZZ -> ZZ\n        XX -> rec[-1]\n    \"\"\"\n```\n\n<a name=\"stim.GateData.generalized_inverse\"></a>\n```python\n# stim.GateData.generalized_inverse\n\n# (in class stim.GateData)\n@property\ndef generalized_inverse(\n    self,\n) -> stim.GateData:\n    \"\"\"The closest-thing-to-an-inverse for the gate, if forced to pick something.\n\n    The generalized inverse of a unitary gate U is its actual inverse U^-1.\n\n    The generalized inverse of a reset or measurement gate U is a gate V such that,\n    for every stabilizer flow that U has, V has the time reverse of that flow (up\n    to Pauli feedback, with potentially more flows). For example, the time-reverse\n    of R is MR because R has the single flow 1 -> Z and MR has the time reversed\n    flow Z -> rec[-1].\n\n    The generalized inverse of noise like X_ERROR is just the same noise.\n\n    The generalized inverse of an annotation like TICK is just the same annotation.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('H').generalized_inverse\n        stim.gate_data('H')\n\n        >>> stim.gate_data('CXSWAP').generalized_inverse\n        stim.gate_data('SWAPCX')\n\n        >>> stim.gate_data('X_ERROR').generalized_inverse\n        stim.gate_data('X_ERROR')\n\n        >>> stim.gate_data('MX').generalized_inverse\n        stim.gate_data('MX')\n\n        >>> stim.gate_data('MRY').generalized_inverse\n        stim.gate_data('MRY')\n\n        >>> stim.gate_data('R').generalized_inverse\n        stim.gate_data('M')\n\n        >>> stim.gate_data('DETECTOR').generalized_inverse\n        stim.gate_data('DETECTOR')\n\n        >>> stim.gate_data('TICK').generalized_inverse\n        stim.gate_data('TICK')\n    \"\"\"\n```\n\n<a name=\"stim.GateData.hadamard_conjugated\"></a>\n```python\n# stim.GateData.hadamard_conjugated\n\n# (in class stim.GateData)\ndef hadamard_conjugated(\n    self,\n    *,\n    unsigned: bool = False,\n) -> Optional[stim.GateData]:\n    \"\"\"Returns a stim gate equivalent to this gate conjugated by Hadamard gates.\n\n    The Hadamard conjugate can be thought of as the XZ dual of the gate; the gate\n    you get by exchanging the X and Z bases. For example, a SQRT_X will become a\n    SQRT_Z and a CX gate will switch directions into an XCZ.\n\n    If stim doesn't define a gate equivalent to conjugating this gate by Hadamards,\n    the value `None` is returned.\n\n    Args:\n        unsigned: Defaults to False. When False, the returned gate must be *exactly*\n            the Hadamard conjugation of this gate. When True, the returned gate must\n            have the same flows but the sign of the flows can be different (i.e.\n            the returned gate must be the Hadamard conjugate up to Pauli gate\n            differences).\n\n    Returns:\n        A stim.GateData instance of the Hadamard conjugate, if it exists in stim.\n\n        None, if stim doesn't define a gate equal to the Hadamard conjugate.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('X').hadamard_conjugated()\n        stim.gate_data('Z')\n        >>> stim.gate_data('CX').hadamard_conjugated()\n        stim.gate_data('XCZ')\n        >>> stim.gate_data('RY').hadamard_conjugated() is None\n        True\n        >>> stim.gate_data('RY').hadamard_conjugated(unsigned=True)\n        stim.gate_data('RY')\n        >>> stim.gate_data('ISWAP').hadamard_conjugated(unsigned=True) is None\n        True\n        >>> stim.gate_data('SWAP').hadamard_conjugated()\n        stim.gate_data('SWAP')\n        >>> stim.gate_data('CXSWAP').hadamard_conjugated()\n        stim.gate_data('SWAPCX')\n        >>> stim.gate_data('MXX').hadamard_conjugated()\n        stim.gate_data('MZZ')\n        >>> stim.gate_data('DEPOLARIZE1').hadamard_conjugated()\n        stim.gate_data('DEPOLARIZE1')\n        >>> stim.gate_data('X_ERROR').hadamard_conjugated()\n        stim.gate_data('Z_ERROR')\n        >>> stim.gate_data('H_XY').hadamard_conjugated()\n        stim.gate_data('H_NYZ')\n        >>> stim.gate_data('DETECTOR').hadamard_conjugated(unsigned=True)\n        stim.gate_data('DETECTOR')\n    \"\"\"\n```\n\n<a name=\"stim.GateData.inverse\"></a>\n```python\n# stim.GateData.inverse\n\n# (in class stim.GateData)\n@property\ndef inverse(\n    self,\n) -> Optional[stim.GateData]:\n    \"\"\"The inverse of the gate, or None if it has no inverse.\n\n    The inverse V of a gate U must have the property that V undoes the effects of U\n    and that U undoes the effects of V. In particular, the circuit\n\n        U 0 1\n        V 0 1\n\n    should be equivalent to doing nothing at all.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('H').inverse\n        stim.gate_data('H')\n\n        >>> stim.gate_data('CX').inverse\n        stim.gate_data('CX')\n\n        >>> stim.gate_data('S').inverse\n        stim.gate_data('S_DAG')\n\n        >>> stim.gate_data('CXSWAP').inverse\n        stim.gate_data('SWAPCX')\n\n        >>> stim.gate_data('X_ERROR').inverse is None\n        True\n        >>> stim.gate_data('M').inverse is None\n        True\n        >>> stim.gate_data('R').inverse is None\n        True\n        >>> stim.gate_data('DETECTOR').inverse is None\n        True\n        >>> stim.gate_data('TICK').inverse is None\n        True\n    \"\"\"\n```\n\n<a name=\"stim.GateData.is_noisy_gate\"></a>\n```python\n# stim.GateData.is_noisy_gate\n\n# (in class stim.GateData)\n@property\ndef is_noisy_gate(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not the gate can produce noise.\n\n    Note that measurement operations are considered noisy,\n    because for example `M(0.001) 2 3 5` will include\n    noise that flips its result 0.1% of the time.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('M').is_noisy_gate\n        True\n        >>> stim.gate_data('MXX').is_noisy_gate\n        True\n        >>> stim.gate_data('X_ERROR').is_noisy_gate\n        True\n        >>> stim.gate_data('CORRELATED_ERROR').is_noisy_gate\n        True\n        >>> stim.gate_data('MPP').is_noisy_gate\n        True\n\n        >>> stim.gate_data('H').is_noisy_gate\n        False\n        >>> stim.gate_data('CX').is_noisy_gate\n        False\n        >>> stim.gate_data('R').is_noisy_gate\n        False\n        >>> stim.gate_data('DETECTOR').is_noisy_gate\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData.is_reset\"></a>\n```python\n# stim.GateData.is_reset\n\n# (in class stim.GateData)\n@property\ndef is_reset(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not the gate resets qubits in any basis.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('R').is_reset\n        True\n        >>> stim.gate_data('RX').is_reset\n        True\n        >>> stim.gate_data('MR').is_reset\n        True\n\n        >>> stim.gate_data('M').is_reset\n        False\n        >>> stim.gate_data('MXX').is_reset\n        False\n        >>> stim.gate_data('MPP').is_reset\n        False\n        >>> stim.gate_data('H').is_reset\n        False\n        >>> stim.gate_data('CX').is_reset\n        False\n        >>> stim.gate_data('HERALDED_ERASE').is_reset\n        False\n        >>> stim.gate_data('DEPOLARIZE2').is_reset\n        False\n        >>> stim.gate_data('X_ERROR').is_reset\n        False\n        >>> stim.gate_data('CORRELATED_ERROR').is_reset\n        False\n        >>> stim.gate_data('DETECTOR').is_reset\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData.is_single_qubit_gate\"></a>\n```python\n# stim.GateData.is_single_qubit_gate\n\n# (in class stim.GateData)\n@property\ndef is_single_qubit_gate(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not the gate is a single qubit gate.\n\n    Single qubit gates apply separately to each of their targets.\n\n    Variable-qubit gates like CORRELATED_ERROR and MPP are not\n    considered single qubit gates.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('H').is_single_qubit_gate\n        True\n        >>> stim.gate_data('R').is_single_qubit_gate\n        True\n        >>> stim.gate_data('M').is_single_qubit_gate\n        True\n        >>> stim.gate_data('X_ERROR').is_single_qubit_gate\n        True\n\n        >>> stim.gate_data('CX').is_single_qubit_gate\n        False\n        >>> stim.gate_data('MXX').is_single_qubit_gate\n        False\n        >>> stim.gate_data('CORRELATED_ERROR').is_single_qubit_gate\n        False\n        >>> stim.gate_data('MPP').is_single_qubit_gate\n        False\n        >>> stim.gate_data('DETECTOR').is_single_qubit_gate\n        False\n        >>> stim.gate_data('TICK').is_single_qubit_gate\n        False\n        >>> stim.gate_data('REPEAT').is_single_qubit_gate\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData.is_symmetric_gate\"></a>\n```python\n# stim.GateData.is_symmetric_gate\n\n# (in class stim.GateData)\n@property\ndef is_symmetric_gate(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not the gate is the same when its targets are swapped.\n\n    A two qubit gate is symmetric if it doesn't matter if you swap its targets. It\n    is unaffected when conjugated by the SWAP gate.\n\n    Single qubit gates are vacuously symmetric. A multi-qubit gate is symmetric if\n    swapping any two of its targets has no effect.\n\n    Note that this method is for symmetry *without broadcasting*. For example, SWAP\n    is symmetric even though SWAP 1 2 3 4 isn't equal to SWAP 1 3 2 4.\n\n    Returns:\n        True if the gate is symmetric.\n        False if the gate isn't symmetric.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('CX').is_symmetric_gate\n        False\n        >>> stim.gate_data('CZ').is_symmetric_gate\n        True\n        >>> stim.gate_data('ISWAP').is_symmetric_gate\n        True\n        >>> stim.gate_data('CXSWAP').is_symmetric_gate\n        False\n        >>> stim.gate_data('MXX').is_symmetric_gate\n        True\n        >>> stim.gate_data('DEPOLARIZE2').is_symmetric_gate\n        True\n        >>> stim.gate_data('PAULI_CHANNEL_2').is_symmetric_gate\n        False\n        >>> stim.gate_data('H').is_symmetric_gate\n        True\n        >>> stim.gate_data('R').is_symmetric_gate\n        True\n        >>> stim.gate_data('X_ERROR').is_symmetric_gate\n        True\n        >>> stim.gate_data('CORRELATED_ERROR').is_symmetric_gate\n        False\n        >>> stim.gate_data('MPP').is_symmetric_gate\n        False\n        >>> stim.gate_data('DETECTOR').is_symmetric_gate\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData.is_two_qubit_gate\"></a>\n```python\n# stim.GateData.is_two_qubit_gate\n\n# (in class stim.GateData)\n@property\ndef is_two_qubit_gate(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not the gate is a two qubit gate.\n\n    Two qubit gates must be given an even number of targets.\n\n    Variable-qubit gates like CORRELATED_ERROR and MPP are not\n    considered two qubit gates.\n\n    Returns:\n        True if the gate is a two qubit gate.\n        False if the gate isn't a two qubit gate.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('CX').is_two_qubit_gate\n        True\n        >>> stim.gate_data('MXX').is_two_qubit_gate\n        True\n\n        >>> stim.gate_data('H').is_two_qubit_gate\n        False\n        >>> stim.gate_data('R').is_two_qubit_gate\n        False\n        >>> stim.gate_data('M').is_two_qubit_gate\n        False\n        >>> stim.gate_data('X_ERROR').is_two_qubit_gate\n        False\n        >>> stim.gate_data('CORRELATED_ERROR').is_two_qubit_gate\n        False\n        >>> stim.gate_data('MPP').is_two_qubit_gate\n        False\n        >>> stim.gate_data('DETECTOR').is_two_qubit_gate\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData.is_unitary\"></a>\n```python\n# stim.GateData.is_unitary\n\n# (in class stim.GateData)\n@property\ndef is_unitary(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not the gate is a unitary gate.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('H').is_unitary\n        True\n        >>> stim.gate_data('CX').is_unitary\n        True\n\n        >>> stim.gate_data('R').is_unitary\n        False\n        >>> stim.gate_data('M').is_unitary\n        False\n        >>> stim.gate_data('MXX').is_unitary\n        False\n        >>> stim.gate_data('X_ERROR').is_unitary\n        False\n        >>> stim.gate_data('CORRELATED_ERROR').is_unitary\n        False\n        >>> stim.gate_data('MPP').is_unitary\n        False\n        >>> stim.gate_data('DETECTOR').is_unitary\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData.name\"></a>\n```python\n# stim.GateData.name\n\n# (in class stim.GateData)\n@property\ndef name(\n    self,\n) -> str:\n    \"\"\"Returns the canonical name of the gate.\n\n    Examples:\n        >>> import stim\n        >>> stim.gate_data('H').name\n        'H'\n        >>> stim.gate_data('cnot').name\n        'CX'\n    \"\"\"\n```\n\n<a name=\"stim.GateData.num_parens_arguments_range\"></a>\n```python\n# stim.GateData.num_parens_arguments_range\n\n# (in class stim.GateData)\n@property\ndef num_parens_arguments_range(\n    self,\n) -> range:\n    \"\"\"Returns the min/max parens arguments taken by the gate, as a python range.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('M').num_parens_arguments_range\n        range(0, 2)\n        >>> list(stim.gate_data('M').num_parens_arguments_range)\n        [0, 1]\n        >>> list(stim.gate_data('R').num_parens_arguments_range)\n        [0]\n        >>> list(stim.gate_data('H').num_parens_arguments_range)\n        [0]\n        >>> list(stim.gate_data('X_ERROR').num_parens_arguments_range)\n        [1]\n        >>> list(stim.gate_data('PAULI_CHANNEL_1').num_parens_arguments_range)\n        [3]\n        >>> list(stim.gate_data('PAULI_CHANNEL_2').num_parens_arguments_range)\n        [15]\n        >>> stim.gate_data('DETECTOR').num_parens_arguments_range\n        range(0, 256)\n        >>> list(stim.gate_data('OBSERVABLE_INCLUDE').num_parens_arguments_range)\n        [1]\n    \"\"\"\n```\n\n<a name=\"stim.GateData.produces_measurements\"></a>\n```python\n# stim.GateData.produces_measurements\n\n# (in class stim.GateData)\n@property\ndef produces_measurements(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not the gate produces measurement results.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('M').produces_measurements\n        True\n        >>> stim.gate_data('MRY').produces_measurements\n        True\n        >>> stim.gate_data('MXX').produces_measurements\n        True\n        >>> stim.gate_data('MPP').produces_measurements\n        True\n        >>> stim.gate_data('HERALDED_ERASE').produces_measurements\n        True\n\n        >>> stim.gate_data('H').produces_measurements\n        False\n        >>> stim.gate_data('CX').produces_measurements\n        False\n        >>> stim.gate_data('R').produces_measurements\n        False\n        >>> stim.gate_data('X_ERROR').produces_measurements\n        False\n        >>> stim.gate_data('CORRELATED_ERROR').produces_measurements\n        False\n        >>> stim.gate_data('DETECTOR').produces_measurements\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData.tableau\"></a>\n```python\n# stim.GateData.tableau\n\n# (in class stim.GateData)\n@property\ndef tableau(\n    self,\n) -> Optional[stim.Tableau]:\n    \"\"\"Returns the gate's tableau, or None if the gate has no tableau.\n\n    Examples:\n        >>> import stim\n        >>> print(stim.gate_data('M').tableau)\n        None\n        >>> stim.gate_data('H').tableau\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X\"),\n            ],\n        )\n        >>> stim.gate_data('ISWAP').tableau\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+ZY\"),\n                stim.PauliString(\"+YZ\"),\n            ],\n            zs=[\n                stim.PauliString(\"+_Z\"),\n                stim.PauliString(\"+Z_\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.GateData.takes_measurement_record_targets\"></a>\n```python\n# stim.GateData.takes_measurement_record_targets\n\n# (in class stim.GateData)\n@property\ndef takes_measurement_record_targets(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not the gate can accept rec targets.\n\n    For example, `CX` can take a measurement record target\n    like `CX rec[-1] 1`.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('CX').takes_measurement_record_targets\n        True\n        >>> stim.gate_data('DETECTOR').takes_measurement_record_targets\n        True\n\n        >>> stim.gate_data('H').takes_measurement_record_targets\n        False\n        >>> stim.gate_data('SWAP').takes_measurement_record_targets\n        False\n        >>> stim.gate_data('R').takes_measurement_record_targets\n        False\n        >>> stim.gate_data('M').takes_measurement_record_targets\n        False\n        >>> stim.gate_data('MRY').takes_measurement_record_targets\n        False\n        >>> stim.gate_data('MXX').takes_measurement_record_targets\n        False\n        >>> stim.gate_data('X_ERROR').takes_measurement_record_targets\n        False\n        >>> stim.gate_data('CORRELATED_ERROR').takes_measurement_record_targets\n        False\n        >>> stim.gate_data('MPP').takes_measurement_record_targets\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData.takes_pauli_targets\"></a>\n```python\n# stim.GateData.takes_pauli_targets\n\n# (in class stim.GateData)\n@property\ndef takes_pauli_targets(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not the gate expects pauli targets.\n\n    For example, `CORRELATED_ERROR` takes targets like `X0` and `Y1`\n    instead of `0` or `1`.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.gate_data('CORRELATED_ERROR').takes_pauli_targets\n        True\n        >>> stim.gate_data('MPP').takes_pauli_targets\n        True\n\n        >>> stim.gate_data('H').takes_pauli_targets\n        False\n        >>> stim.gate_data('CX').takes_pauli_targets\n        False\n        >>> stim.gate_data('R').takes_pauli_targets\n        False\n        >>> stim.gate_data('M').takes_pauli_targets\n        False\n        >>> stim.gate_data('MRY').takes_pauli_targets\n        False\n        >>> stim.gate_data('MXX').takes_pauli_targets\n        False\n        >>> stim.gate_data('X_ERROR').takes_pauli_targets\n        False\n        >>> stim.gate_data('DETECTOR').takes_pauli_targets\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateData.unitary_matrix\"></a>\n```python\n# stim.GateData.unitary_matrix\n\n# (in class stim.GateData)\n@property\ndef unitary_matrix(\n    self,\n) -> Optional[np.ndarray]:\n    \"\"\"Returns the gate's unitary matrix, or None if the gate isn't unitary.\n\n    Examples:\n        >>> import stim\n\n        >>> print(stim.gate_data('M').unitary_matrix)\n        None\n\n        >>> stim.gate_data('X').unitary_matrix\n        array([[0.+0.j, 1.+0.j],\n               [1.+0.j, 0.+0.j]], dtype=complex64)\n\n        >>> stim.gate_data('ISWAP').unitary_matrix\n        array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n               [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j],\n               [0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j],\n               [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]], dtype=complex64)\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget\"></a>\n```python\n# stim.GateTarget\n\n# (at top-level in the stim module)\nclass GateTarget:\n    \"\"\"Represents a gate target, like `0` or `rec[-1]`, from a circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     M 0 !1\n        ... ''')\n        >>> circuit[0].targets_copy()[0]\n        stim.GateTarget(0)\n        >>> circuit[0].targets_copy()[1]\n        stim.target_inv(1)\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.__eq__\"></a>\n```python\n# stim.GateTarget.__eq__\n\n# (in class stim.GateTarget)\ndef __eq__(\n    self,\n    arg0: stim.GateTarget,\n) -> bool:\n    \"\"\"Determines if two `stim.GateTarget`s are identical.\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.__init__\"></a>\n```python\n# stim.GateTarget.__init__\n\n# (in class stim.GateTarget)\ndef __init__(\n    self,\n    value: object,\n) -> None:\n    \"\"\"Initializes a `stim.GateTarget`.\n\n    Args:\n        value: A value to convert into a gate target, like an integer\n            to interpret as a qubit target or a string to parse.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(stim.GateTarget(5))\n        stim.GateTarget(5)\n        >>> stim.GateTarget(\"X7\")\n        stim.target_x(7)\n        >>> stim.GateTarget(\"rec[-3]\")\n        stim.target_rec(-3)\n        >>> stim.GateTarget(\"!Z7\")\n        stim.target_z(7, invert=True)\n        >>> stim.GateTarget(\"*\")\n        stim.GateTarget.combiner()\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.__ne__\"></a>\n```python\n# stim.GateTarget.__ne__\n\n# (in class stim.GateTarget)\ndef __ne__(\n    self,\n    arg0: stim.GateTarget,\n) -> bool:\n    \"\"\"Determines if two `stim.GateTarget`s are different.\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.__repr__\"></a>\n```python\n# stim.GateTarget.__repr__\n\n# (in class stim.GateTarget)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.GateTarget`.\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.is_combiner\"></a>\n```python\n# stim.GateTarget.is_combiner\n\n# (in class stim.GateTarget)\n@property\ndef is_combiner(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not this is a combiner target like `*`.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).is_combiner\n        False\n        >>> stim.target_inv(7).is_combiner\n        False\n        >>> stim.target_x(8).is_combiner\n        False\n        >>> stim.target_y(2).is_combiner\n        False\n        >>> stim.target_z(3).is_combiner\n        False\n        >>> stim.target_sweep_bit(9).is_combiner\n        False\n        >>> stim.target_rec(-5).is_combiner\n        False\n        >>> stim.target_combiner().is_combiner\n        True\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.is_inverted_result_target\"></a>\n```python\n# stim.GateTarget.is_inverted_result_target\n\n# (in class stim.GateTarget)\n@property\ndef is_inverted_result_target(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not this is an inverted target like `!5` or `!X4`.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).is_inverted_result_target\n        False\n        >>> stim.target_inv(7).is_inverted_result_target\n        True\n        >>> stim.target_x(8).is_inverted_result_target\n        False\n        >>> stim.target_x(8, invert=True).is_inverted_result_target\n        True\n        >>> stim.target_y(2).is_inverted_result_target\n        False\n        >>> stim.target_z(3).is_inverted_result_target\n        False\n        >>> stim.target_sweep_bit(9).is_inverted_result_target\n        False\n        >>> stim.target_rec(-5).is_inverted_result_target\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.is_measurement_record_target\"></a>\n```python\n# stim.GateTarget.is_measurement_record_target\n\n# (in class stim.GateTarget)\n@property\ndef is_measurement_record_target(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not this is a measurement record target like `rec[-5]`.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).is_measurement_record_target\n        False\n        >>> stim.target_inv(7).is_measurement_record_target\n        False\n        >>> stim.target_x(8).is_measurement_record_target\n        False\n        >>> stim.target_y(2).is_measurement_record_target\n        False\n        >>> stim.target_z(3).is_measurement_record_target\n        False\n        >>> stim.target_sweep_bit(9).is_measurement_record_target\n        False\n        >>> stim.target_rec(-5).is_measurement_record_target\n        True\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.is_qubit_target\"></a>\n```python\n# stim.GateTarget.is_qubit_target\n\n# (in class stim.GateTarget)\n@property\ndef is_qubit_target(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not this is a qubit target like `5` or `!6`.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).is_qubit_target\n        True\n        >>> stim.target_inv(7).is_qubit_target\n        True\n        >>> stim.target_x(8).is_qubit_target\n        False\n        >>> stim.target_y(2).is_qubit_target\n        False\n        >>> stim.target_z(3).is_qubit_target\n        False\n        >>> stim.target_sweep_bit(9).is_qubit_target\n        False\n        >>> stim.target_rec(-5).is_qubit_target\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.is_sweep_bit_target\"></a>\n```python\n# stim.GateTarget.is_sweep_bit_target\n\n# (in class stim.GateTarget)\n@property\ndef is_sweep_bit_target(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not this is a sweep bit target like `sweep[4]`.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).is_sweep_bit_target\n        False\n        >>> stim.target_inv(7).is_sweep_bit_target\n        False\n        >>> stim.target_x(8).is_sweep_bit_target\n        False\n        >>> stim.target_y(2).is_sweep_bit_target\n        False\n        >>> stim.target_z(3).is_sweep_bit_target\n        False\n        >>> stim.target_sweep_bit(9).is_sweep_bit_target\n        True\n        >>> stim.target_rec(-5).is_sweep_bit_target\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.is_x_target\"></a>\n```python\n# stim.GateTarget.is_x_target\n\n# (in class stim.GateTarget)\n@property\ndef is_x_target(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not this is an X pauli target like `X2` or `!X7`.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).is_x_target\n        False\n        >>> stim.target_inv(7).is_x_target\n        False\n        >>> stim.target_x(8).is_x_target\n        True\n        >>> stim.target_y(2).is_x_target\n        False\n        >>> stim.target_z(3).is_x_target\n        False\n        >>> stim.target_sweep_bit(9).is_x_target\n        False\n        >>> stim.target_rec(-5).is_x_target\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.is_y_target\"></a>\n```python\n# stim.GateTarget.is_y_target\n\n# (in class stim.GateTarget)\n@property\ndef is_y_target(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not this is a Y pauli target like `Y2` or `!Y7`.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).is_y_target\n        False\n        >>> stim.target_inv(7).is_y_target\n        False\n        >>> stim.target_x(8).is_y_target\n        False\n        >>> stim.target_y(2).is_y_target\n        True\n        >>> stim.target_z(3).is_y_target\n        False\n        >>> stim.target_sweep_bit(9).is_y_target\n        False\n        >>> stim.target_rec(-5).is_y_target\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.is_z_target\"></a>\n```python\n# stim.GateTarget.is_z_target\n\n# (in class stim.GateTarget)\n@property\ndef is_z_target(\n    self,\n) -> bool:\n    \"\"\"Returns whether or not this is a Z pauli target like `Z2` or `!Z7`.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).is_z_target\n        False\n        >>> stim.target_inv(7).is_z_target\n        False\n        >>> stim.target_x(8).is_z_target\n        False\n        >>> stim.target_y(2).is_z_target\n        False\n        >>> stim.target_z(3).is_z_target\n        True\n        >>> stim.target_sweep_bit(9).is_z_target\n        False\n        >>> stim.target_rec(-5).is_z_target\n        False\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.pauli_type\"></a>\n```python\n# stim.GateTarget.pauli_type\n\n# (in class stim.GateTarget)\n@property\ndef pauli_type(\n    self,\n) -> str:\n    \"\"\"Returns whether this is an 'X', 'Y', or 'Z' target.\n\n    For non-pauli targets, this property evaluates to 'I'.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).pauli_type\n        'I'\n        >>> stim.target_inv(7).pauli_type\n        'I'\n        >>> stim.target_x(8).pauli_type\n        'X'\n        >>> stim.target_y(2).pauli_type\n        'Y'\n        >>> stim.target_z(3).pauli_type\n        'Z'\n        >>> stim.target_sweep_bit(9).pauli_type\n        'I'\n        >>> stim.target_rec(-5).pauli_type\n        'I'\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.qubit_value\"></a>\n```python\n# stim.GateTarget.qubit_value\n\n# (in class stim.GateTarget)\n@property\ndef qubit_value(\n    self,\n) -> Optional[int]:\n    \"\"\"Returns the integer value of the targeted qubit, or else None.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).qubit_value\n        6\n        >>> stim.target_inv(7).qubit_value\n        7\n        >>> stim.target_x(8).qubit_value\n        8\n        >>> stim.target_y(2).qubit_value\n        2\n        >>> stim.target_z(3).qubit_value\n        3\n        >>> print(stim.target_sweep_bit(9).qubit_value)\n        None\n        >>> print(stim.target_rec(-5).qubit_value)\n        None\n    \"\"\"\n```\n\n<a name=\"stim.GateTarget.value\"></a>\n```python\n# stim.GateTarget.value\n\n# (in class stim.GateTarget)\n@property\ndef value(\n    self,\n) -> int:\n    \"\"\"The numeric part of the target.\n\n    This is non-negative integer for qubit targets, and a negative integer for\n    measurement record targets.\n\n    Examples:\n        >>> import stim\n        >>> stim.GateTarget(6).value\n        6\n        >>> stim.target_inv(7).value\n        7\n        >>> stim.target_x(8).value\n        8\n        >>> stim.target_y(2).value\n        2\n        >>> stim.target_z(3).value\n        3\n        >>> stim.target_sweep_bit(9).value\n        9\n        >>> stim.target_rec(-5).value\n        -5\n    \"\"\"\n```\n\n<a name=\"stim.GateTargetWithCoords\"></a>\n```python\n# stim.GateTargetWithCoords\n\n# (at top-level in the stim module)\nclass GateTargetWithCoords:\n    \"\"\"A gate target with associated coordinate information.\n\n    For example, if the gate target is a qubit from a circuit with\n    QUBIT_COORDS instructions, the coords field will contain the\n    coordinate data from the QUBIT_COORDS instruction for the qubit.\n\n    This is helpful information to have available when debugging a\n    problem in a circuit, instead of having to constantly manually\n    look up the coordinates of a qubit index in order to understand\n    what is happening.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n        >>> t.gate_target\n        stim.GateTarget(0)\n        >>> t.coords\n        [1.5, 2.0]\n    \"\"\"\n```\n\n<a name=\"stim.GateTargetWithCoords.__init__\"></a>\n```python\n# stim.GateTargetWithCoords.__init__\n\n# (in class stim.GateTargetWithCoords)\ndef __init__(\n    self,\n    gate_target: object,\n    coords: List[float],\n) -> None:\n    \"\"\"Creates a stim.GateTargetWithCoords.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n        >>> t.gate_target\n        stim.GateTarget(0)\n        >>> t.coords\n        [1.5, 2.0]\n    \"\"\"\n```\n\n<a name=\"stim.GateTargetWithCoords.coords\"></a>\n```python\n# stim.GateTargetWithCoords.coords\n\n# (in class stim.GateTargetWithCoords)\n@property\ndef coords(\n    self,\n) -> List[float]:\n    \"\"\"Returns the associated coordinate information as a list of floats.\n\n    If there is no coordinate information, returns an empty list.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n        >>> t.coords\n        [1.5, 2.0]\n    \"\"\"\n```\n\n<a name=\"stim.GateTargetWithCoords.gate_target\"></a>\n```python\n# stim.GateTargetWithCoords.gate_target\n\n# (in class stim.GateTargetWithCoords)\n@property\ndef gate_target(\n    self,\n) -> stim.GateTarget:\n    \"\"\"Returns the actual gate target as a `stim.GateTarget`.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n        >>> t.gate_target\n        stim.GateTarget(0)\n    \"\"\"\n```\n\n<a name=\"stim.PauliString\"></a>\n```python\n# stim.PauliString\n\n# (at top-level in the stim module)\nclass PauliString:\n    \"\"\"A signed Pauli tensor product (e.g. \"+X \\u2297 X \\u2297 X\" or \"-Y \\u2297 Z\".\n\n    Represents a collection of Pauli operations (I, X, Y, Z) applied pairwise to a\n    collection of qubits.\n\n    Examples:\n        >>> import stim\n        >>> stim.PauliString(\"XX\") * stim.PauliString(\"YY\")\n        stim.PauliString(\"-ZZ\")\n        >>> print(stim.PauliString(5))\n        +_____\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__add__\"></a>\n```python\n# stim.PauliString.__add__\n\n# (in class stim.PauliString)\ndef __add__(\n    self,\n    rhs: stim.PauliString,\n) -> stim.PauliString:\n    \"\"\"Returns the tensor product of two Pauli strings.\n\n    Concatenates the Pauli strings and multiplies their signs.\n\n    Args:\n        rhs: A second stim.PauliString.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.PauliString(\"X\") + stim.PauliString(\"YZ\")\n        stim.PauliString(\"+XYZ\")\n\n        >>> stim.PauliString(\"iX\") + stim.PauliString(\"-X\")\n        stim.PauliString(\"-iXX\")\n\n    Returns:\n        The tensor product.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__eq__\"></a>\n```python\n# stim.PauliString.__eq__\n\n# (in class stim.PauliString)\ndef __eq__(\n    self,\n    arg0: stim.PauliString,\n) -> bool:\n    \"\"\"Determines if two Pauli strings have identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__getitem__\"></a>\n```python\n# stim.PauliString.__getitem__\n\n# (in class stim.PauliString)\n@overload\ndef __getitem__(\n    self,\n    index_or_slice: int,\n) -> int:\n    pass\n@overload\ndef __getitem__(\n    self,\n    index_or_slice: slice,\n) -> stim.PauliString:\n    pass\ndef __getitem__(\n    self,\n    index_or_slice: object,\n) -> object:\n    \"\"\"Returns an individual Pauli or Pauli string slice from the pauli string.\n\n    Individual Paulis are returned as an int using the encoding 0=I, 1=X, 2=Y, 3=Z.\n    Slices are returned as a stim.PauliString (always with positive sign).\n\n    Examples:\n        >>> import stim\n        >>> p = stim.PauliString(\"_XYZ\")\n        >>> p[2]\n        2\n        >>> p[-1]\n        3\n        >>> p[:2]\n        stim.PauliString(\"+_X\")\n        >>> p[::-1]\n        stim.PauliString(\"+ZYX_\")\n\n    Args:\n        index_or_slice: The index of the pauli to return, or the slice of paulis to\n            return.\n\n    Returns:\n        0: Identity.\n        1: Pauli X.\n        2: Pauli Y.\n        3: Pauli Z.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__iadd__\"></a>\n```python\n# stim.PauliString.__iadd__\n\n# (in class stim.PauliString)\ndef __iadd__(\n    self,\n    rhs: stim.PauliString,\n) -> stim.PauliString:\n    \"\"\"Performs an inplace tensor product.\n\n    Concatenates the given Pauli string onto the receiving string and multiplies\n    their signs.\n\n    Args:\n        rhs: A second stim.PauliString.\n\n    Examples:\n        >>> import stim\n\n        >>> p = stim.PauliString(\"iX\")\n        >>> alias = p\n        >>> p += stim.PauliString(\"-YY\")\n        >>> p\n        stim.PauliString(\"-iXYY\")\n        >>> alias is p\n        True\n\n    Returns:\n        The mutated pauli string.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__imul__\"></a>\n```python\n# stim.PauliString.__imul__\n\n# (in class stim.PauliString)\ndef __imul__(\n    self,\n    rhs: object,\n) -> stim.PauliString:\n    \"\"\"Inplace right-multiplies the Pauli string.\n\n    Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n    Args:\n        rhs: The right hand side of the multiplication. This can be:\n            - A stim.PauliString to right-multiply term-by-term into the paulis of\n                the pauli string.\n            - A complex unit (1, -1, 1j, -1j) to multiply into the sign of the pauli\n                string.\n            - A non-negative integer indicating the tensor power to raise the pauli\n                string to (how many times to repeat it).\n\n    Examples:\n        >>> import stim\n\n        >>> p = stim.PauliString(\"X\")\n        >>> p *= 1j\n        >>> p\n        stim.PauliString(\"+iX\")\n\n        >>> p = stim.PauliString(\"iXY_\")\n        >>> p *= 3\n        >>> p\n        stim.PauliString(\"-iXY_XY_XY_\")\n\n        >>> p = stim.PauliString(\"X\")\n        >>> alias = p\n        >>> p *= stim.PauliString(\"Y\")\n        >>> alias\n        stim.PauliString(\"+iZ\")\n\n        >>> p = stim.PauliString(\"X\")\n        >>> p *= stim.PauliString(\"_YY\")\n        >>> p\n        stim.PauliString(\"+XYY\")\n\n    Returns:\n        The mutated Pauli string.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__init__\"></a>\n```python\n# stim.PauliString.__init__\n\n# (in class stim.PauliString)\ndef __init__(\n    self,\n    arg: Union[None, int, str, stim.PauliString, Iterable[Union[int, Literal[\"_\", \"I\", \"X\", \"Y\", \"Z\"]]]] = None,\n    /,\n) -> None:\n    \"\"\"Initializes a stim.PauliString from the given argument.\n\n    When given a string, the string is parsed as a pauli string. The string can\n    optionally start with a sign ('+', '-', 'i', '+i', or '-i'). The rest of the\n    string should be either a dense pauli string or a sparse pauli string. A dense\n    pauli string is made up of characters from '_IXYZ' where '_' and 'I' mean\n    identity, 'X' means Pauli X, 'Y' means Pauli Y, and 'Z' means Pauli Z. A sparse\n    pauli string is a series of integers seperated by '*' and prefixed by 'I', 'X',\n    'Y', or 'Z'.\n\n    Args:\n        arg [position-only]: This can be a variety of types, including:\n            None (default): initializes an empty Pauli string.\n            int: initializes an identity Pauli string of the given length.\n            str: initializes by parsing the given text.\n            stim.PauliString: initializes a copy of the given Pauli string.\n            Iterable: initializes by interpreting each item as a Pauli.\n                Each item can be a single-qubit Pauli string (like \"X\"),\n                or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n            Dict[int, Union[int, str]]: initializes by interpreting keys as\n                the qubit index and values as the Pauli for that index.\n                Each value can be a single-qubit Pauli string (like \"X\"),\n                or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n            Dict[Union[int, str], Iterable[int]]: initializes by interpreting keys\n                as Pauli operators and values as the qubit indices for that Pauli.\n                Each key can be a single-qubit Pauli string (like \"X\"),\n                or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.PauliString(\"-XYZ\")\n        stim.PauliString(\"-XYZ\")\n\n        >>> stim.PauliString()\n        stim.PauliString(\"+\")\n\n        >>> stim.PauliString(5)\n        stim.PauliString(\"+_____\")\n\n        >>> stim.PauliString(stim.PauliString(\"XX\"))\n        stim.PauliString(\"+XX\")\n\n        >>> stim.PauliString([0, 1, 3, 2])\n        stim.PauliString(\"+_XZY\")\n\n        >>> stim.PauliString(\"X\" for _ in range(4))\n        stim.PauliString(\"+XXXX\")\n\n        >>> stim.PauliString(\"-X2*Y6\")\n        stim.PauliString(\"-__X___Y\")\n\n        >>> stim.PauliString(\"X6*Y6\")\n        stim.PauliString(\"+i______Z\")\n\n        >>> stim.PauliString({0: \"X\", 2: \"Y\", 3: \"X\"})\n        stim.PauliString(\"+X_YX\")\n\n        >>> stim.PauliString({0: \"X\", 2: 2, 3: 1})\n        stim.PauliString(\"+X_YX\")\n\n        >>> stim.PauliString({\"X\": [1], 2: [4], \"Z\": [0, 3]})\n        stim.PauliString(\"+ZX_ZY\")\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__itruediv__\"></a>\n```python\n# stim.PauliString.__itruediv__\n\n# (in class stim.PauliString)\ndef __itruediv__(\n    self,\n    rhs: complex,\n) -> stim.PauliString:\n    \"\"\"Inplace divides the Pauli string by a complex unit.\n\n    Args:\n        rhs: The divisor. Can be 1, -1, 1j, or -1j.\n\n    Examples:\n        >>> import stim\n\n        >>> p = stim.PauliString(\"X\")\n        >>> p /= 1j\n        >>> p\n        stim.PauliString(\"-iX\")\n\n    Returns:\n        The mutated Pauli string.\n\n    Raises:\n        ValueError: The divisor isn't 1, -1, 1j, or -1j.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__len__\"></a>\n```python\n# stim.PauliString.__len__\n\n# (in class stim.PauliString)\ndef __len__(\n    self,\n) -> int:\n    \"\"\"Returns the length the pauli string; the number of qubits it operates on.\n\n    Examples:\n        >>> import stim\n        >>> len(stim.PauliString(\"XY_ZZ\"))\n        5\n        >>> len(stim.PauliString(\"X0*Z99\"))\n        100\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__mul__\"></a>\n```python\n# stim.PauliString.__mul__\n\n# (in class stim.PauliString)\ndef __mul__(\n    self,\n    rhs: object,\n) -> stim.PauliString:\n    \"\"\"Right-multiplies the Pauli string.\n\n    Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n    Args:\n        rhs: The right hand side of the multiplication. This can be:\n            - A stim.PauliString to right-multiply term-by-term with the paulis of\n                the pauli string.\n            - A complex unit (1, -1, 1j, -1j) to multiply with the sign of the pauli\n                string.\n            - A non-negative integer indicating the tensor power to raise the pauli\n                string to (how many times to repeat it).\n\n    Examples:\n        >>> import stim\n\n        >>> stim.PauliString(\"X\") * 1\n        stim.PauliString(\"+X\")\n        >>> stim.PauliString(\"X\") * -1\n        stim.PauliString(\"-X\")\n        >>> stim.PauliString(\"X\") * 1j\n        stim.PauliString(\"+iX\")\n\n        >>> stim.PauliString(\"X\") * 2\n        stim.PauliString(\"+XX\")\n        >>> stim.PauliString(\"-X\") * 2\n        stim.PauliString(\"+XX\")\n        >>> stim.PauliString(\"iX\") * 2\n        stim.PauliString(\"-XX\")\n        >>> stim.PauliString(\"X\") * 3\n        stim.PauliString(\"+XXX\")\n        >>> stim.PauliString(\"iX\") * 3\n        stim.PauliString(\"-iXXX\")\n\n        >>> stim.PauliString(\"X\") * stim.PauliString(\"Y\")\n        stim.PauliString(\"+iZ\")\n        >>> stim.PauliString(\"X\") * stim.PauliString(\"XX_\")\n        stim.PauliString(\"+_X_\")\n        >>> stim.PauliString(\"XXXX\") * stim.PauliString(\"_XYZ\")\n        stim.PauliString(\"+X_ZY\")\n\n    Returns:\n        The product or tensor power.\n\n    Raises:\n        TypeError: The right hand side isn't a stim.PauliString, a non-negative\n            integer, or a complex unit (1, -1, 1j, or -1j).\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__ne__\"></a>\n```python\n# stim.PauliString.__ne__\n\n# (in class stim.PauliString)\ndef __ne__(\n    self,\n    arg0: stim.PauliString,\n) -> bool:\n    \"\"\"Determines if two Pauli strings have non-identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__neg__\"></a>\n```python\n# stim.PauliString.__neg__\n\n# (in class stim.PauliString)\ndef __neg__(\n    self,\n) -> stim.PauliString:\n    \"\"\"Returns the negation of the pauli string.\n\n    Examples:\n        >>> import stim\n        >>> -stim.PauliString(\"X\")\n        stim.PauliString(\"-X\")\n        >>> -stim.PauliString(\"-Y\")\n        stim.PauliString(\"+Y\")\n        >>> -stim.PauliString(\"iZZZ\")\n        stim.PauliString(\"-iZZZ\")\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__pos__\"></a>\n```python\n# stim.PauliString.__pos__\n\n# (in class stim.PauliString)\ndef __pos__(\n    self,\n) -> stim.PauliString:\n    \"\"\"Returns a pauli string with the same contents.\n\n    Examples:\n        >>> import stim\n        >>> +stim.PauliString(\"+X\")\n        stim.PauliString(\"+X\")\n        >>> +stim.PauliString(\"-YY\")\n        stim.PauliString(\"-YY\")\n        >>> +stim.PauliString(\"iZZZ\")\n        stim.PauliString(\"+iZZZ\")\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__repr__\"></a>\n```python\n# stim.PauliString.__repr__\n\n# (in class stim.PauliString)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns valid python code evaluating to an equivalent `stim.PauliString`.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__rmul__\"></a>\n```python\n# stim.PauliString.__rmul__\n\n# (in class stim.PauliString)\ndef __rmul__(\n    self,\n    lhs: object,\n) -> stim.PauliString:\n    \"\"\"Left-multiplies the Pauli string.\n\n    Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n    Args:\n        lhs: The left hand side of the multiplication. This can be:\n            - A stim.PauliString to right-multiply term-by-term with the paulis of\n                the pauli string.\n            - A complex unit (1, -1, 1j, -1j) to multiply with the sign of the pauli\n                string.\n            - A non-negative integer indicating the tensor power to raise the pauli\n                string to (how many times to repeat it).\n\n    Examples:\n        >>> import stim\n\n        >>> 1 * stim.PauliString(\"X\")\n        stim.PauliString(\"+X\")\n        >>> -1 * stim.PauliString(\"X\")\n        stim.PauliString(\"-X\")\n        >>> 1j * stim.PauliString(\"X\")\n        stim.PauliString(\"+iX\")\n\n        >>> 2 * stim.PauliString(\"X\")\n        stim.PauliString(\"+XX\")\n        >>> 2 * stim.PauliString(\"-X\")\n        stim.PauliString(\"+XX\")\n        >>> 2 * stim.PauliString(\"iX\")\n        stim.PauliString(\"-XX\")\n        >>> 3 * stim.PauliString(\"X\")\n        stim.PauliString(\"+XXX\")\n        >>> 3 * stim.PauliString(\"iX\")\n        stim.PauliString(\"-iXXX\")\n\n        >>> stim.PauliString(\"X\") * stim.PauliString(\"Y\")\n        stim.PauliString(\"+iZ\")\n        >>> stim.PauliString(\"X\") * stim.PauliString(\"XX_\")\n        stim.PauliString(\"+_X_\")\n        >>> stim.PauliString(\"XXXX\") * stim.PauliString(\"_XYZ\")\n        stim.PauliString(\"+X_ZY\")\n\n    Returns:\n        The product.\n\n    Raises:\n        ValueError: The scalar phase factor isn't 1, -1, 1j, or -1j.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__setitem__\"></a>\n```python\n# stim.PauliString.__setitem__\n\n# (in class stim.PauliString)\ndef __setitem__(\n    self,\n    index: int,\n    new_pauli: object,\n) -> None:\n    \"\"\"Mutates an entry in the pauli string using the encoding 0=I, 1=X, 2=Y, 3=Z.\n\n    Args:\n        index: The index of the pauli to overwrite.\n        new_pauli: Either a character from '_IXYZ' or an integer from range(4).\n\n    Examples:\n        >>> import stim\n        >>> p = stim.PauliString(4)\n        >>> p[2] = 1\n        >>> print(p)\n        +__X_\n        >>> p[0] = 3\n        >>> p[1] = 2\n        >>> p[3] = 0\n        >>> print(p)\n        +ZYX_\n        >>> p[0] = 'I'\n        >>> p[1] = 'X'\n        >>> p[2] = 'Y'\n        >>> p[3] = 'Z'\n        >>> print(p)\n        +_XYZ\n        >>> p[-1] = 'Y'\n        >>> print(p)\n        +_XYY\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__str__\"></a>\n```python\n# stim.PauliString.__str__\n\n# (in class stim.PauliString)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns a text description.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.__truediv__\"></a>\n```python\n# stim.PauliString.__truediv__\n\n# (in class stim.PauliString)\ndef __truediv__(\n    self,\n    rhs: complex,\n) -> stim.PauliString:\n    \"\"\"Divides the Pauli string by a complex unit.\n\n    Args:\n        rhs: The divisor. Can be 1, -1, 1j, or -1j.\n\n    Examples:\n        >>> import stim\n\n        >>> stim.PauliString(\"X\") / 1j\n        stim.PauliString(\"-iX\")\n\n    Returns:\n        The quotient.\n\n    Raises:\n        ValueError: The divisor isn't 1, -1, 1j, or -1j.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.after\"></a>\n```python\n# stim.PauliString.after\n\n# (in class stim.PauliString)\n@overload\ndef after(\n    self,\n    operation: Union[stim.Circuit, stim.CircuitInstruction],\n) -> stim.PauliString:\n    pass\n@overload\ndef after(\n    self,\n    operation: stim.Tableau,\n    targets: Iterable[int],\n) -> stim.PauliString:\n    pass\ndef after(\n    self,\n    operation: Union[stim.Circuit, stim.Tableau, stim.CircuitInstruction],\n    targets: Optional[Iterable[int]] = None,\n) -> stim.PauliString:\n    \"\"\"Returns the result of conjugating the Pauli string by an operation.\n\n    Args:\n        operation: A circuit, tableau, or circuit instruction to\n            conjugate the Pauli string by. Must be Clifford (e.g.\n            if it's a circuit, the circuit can't have noise or\n            measurements).\n        targets: Required if and only if the operation is a tableau.\n            Specifies which qubits to target.\n\n    Examples:\n        >>> import stim\n        >>> p = stim.PauliString(\"_XYZ\")\n\n        >>> p.after(stim.CircuitInstruction(\"H\", [1]))\n        stim.PauliString(\"+_ZYZ\")\n\n        >>> p.after(stim.Circuit('''\n        ...     C_XYZ 1 2 3\n        ... '''))\n        stim.PauliString(\"+_YZX\")\n\n        >>> p.after(stim.Tableau.from_named_gate('CZ'), targets=[0, 1])\n        stim.PauliString(\"+ZXYZ\")\n\n    Returns:\n        The conjugated Pauli string. The Pauli string after the\n        operation that is exactly equivalent to the given Pauli\n        string before the operation.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.before\"></a>\n```python\n# stim.PauliString.before\n\n# (in class stim.PauliString)\n@overload\ndef before(\n    self,\n    operation: Union[stim.Circuit, stim.CircuitInstruction],\n) -> stim.PauliString:\n    pass\n@overload\ndef before(\n    self,\n    operation: stim.Tableau,\n    targets: Iterable[int],\n) -> stim.PauliString:\n    pass\ndef before(\n    self,\n    operation: Union[stim.Circuit, stim.Tableau, stim.CircuitInstruction],\n    targets: Optional[Iterable[int]] = None,\n) -> stim.PauliString:\n    \"\"\"Returns the result of conjugating the Pauli string by an operation.\n\n    Args:\n        operation: A circuit, tableau, or circuit instruction to\n            anti-conjugate the Pauli string by. Must be Clifford (e.g.\n            if it's a circuit, the circuit can't have noise or\n            measurements).\n        targets: Required if and only if the operation is a tableau.\n            Specifies which qubits to target.\n\n    Examples:\n        >>> import stim\n        >>> p = stim.PauliString(\"_XYZ\")\n\n        >>> p.before(stim.CircuitInstruction(\"H\", [1]))\n        stim.PauliString(\"+_ZYZ\")\n\n        >>> p.before(stim.Circuit('''\n        ...     C_XYZ 1 2 3\n        ... '''))\n        stim.PauliString(\"+_ZXY\")\n\n        >>> p.before(stim.Tableau.from_named_gate('CZ'), targets=[0, 1])\n        stim.PauliString(\"+ZXYZ\")\n\n    Returns:\n        The conjugated Pauli string. The Pauli string before the\n        operation that is exactly equivalent to the given Pauli\n        string after the operation.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.commutes\"></a>\n```python\n# stim.PauliString.commutes\n\n# (in class stim.PauliString)\ndef commutes(\n    self,\n    other: stim.PauliString,\n) -> bool:\n    \"\"\"Determines if two Pauli strings commute or not.\n\n    Two Pauli strings commute if they have an even number of matched\n    non-equal non-identity Pauli terms. Otherwise they anticommute.\n\n    Args:\n        other: The other Pauli string.\n\n    Examples:\n        >>> import stim\n        >>> xx = stim.PauliString(\"XX\")\n        >>> xx.commutes(stim.PauliString(\"X_\"))\n        True\n        >>> xx.commutes(stim.PauliString(\"XX\"))\n        True\n        >>> xx.commutes(stim.PauliString(\"XY\"))\n        False\n        >>> xx.commutes(stim.PauliString(\"XZ\"))\n        False\n        >>> xx.commutes(stim.PauliString(\"ZZ\"))\n        True\n        >>> xx.commutes(stim.PauliString(\"X_Y__\"))\n        True\n        >>> xx.commutes(stim.PauliString(\"\"))\n        True\n\n    Returns:\n        True if the Pauli strings commute, False if they anti-commute.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.copy\"></a>\n```python\n# stim.PauliString.copy\n\n# (in class stim.PauliString)\ndef copy(\n    self,\n) -> stim.PauliString:\n    \"\"\"Returns a copy of the pauli string.\n\n    The copy is an independent pauli string with the same contents.\n\n    Examples:\n        >>> import stim\n        >>> p1 = stim.PauliString.random(2)\n        >>> p2 = p1.copy()\n        >>> p2 is p1\n        False\n        >>> p2 == p1\n        True\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.from_numpy\"></a>\n```python\n# stim.PauliString.from_numpy\n\n# (in class stim.PauliString)\n@staticmethod\ndef from_numpy(\n    *,\n    xs: np.ndarray,\n    zs: np.ndarray,\n    sign: Union[int, float, complex] = +1,\n    num_qubits: Optional[int] = None,\n) -> stim.PauliString:\n    \"\"\"Creates a pauli string from X bit and Z bit numpy arrays, using the encoding:\n\n        x=0 and z=0 -> P=I\n        x=1 and z=0 -> P=X\n        x=1 and z=1 -> P=Y\n        x=0 and z=1 -> P=Z\n\n    Args:\n        xs: The X bits of the pauli string. This array can either be a 1-dimensional\n            numpy array with dtype=np.bool_, or a bit packed 1-dimensional numpy\n            array with dtype=np.uint8. If the dtype is np.uint8 then the array is\n            assumed to be bit packed in little endian order and the \"num_qubits\"\n            argument must be specified. When bit packed, the x bit with offset k is\n            stored at (xs[k // 8] >> (k % 8)) & 1.\n        zs: The Z bits of the pauli string. This array can either be a 1-dimensional\n            numpy array with dtype=np.bool_, or a bit packed 1-dimensional numpy\n            array with dtype=np.uint8. If the dtype is np.uint8 then the array is\n            assumed to be bit packed in little endian order and the \"num_qubits\"\n            argument must be specified. When bit packed, the x bit with offset k is\n            stored at (xs[k // 8] >> (k % 8)) & 1.\n        sign: Defaults to +1. Set to +1, -1, 1j, or -1j to control the sign of the\n            returned Pauli string.\n        num_qubits: Must be specified if xs or zs is a bit packed array. Specifies\n            the expected length of the Pauli string.\n\n    Returns:\n        The created pauli string.\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n\n        >>> xs = np.array([1, 1, 1, 1, 1, 1, 1, 0, 0], dtype=np.bool_)\n        >>> zs = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1], dtype=np.bool_)\n        >>> stim.PauliString.from_numpy(xs=xs, zs=zs, sign=-1)\n        stim.PauliString(\"-XXXXYYYZZ\")\n\n        >>> xs = np.array([127, 0], dtype=np.uint8)\n        >>> zs = np.array([240, 1], dtype=np.uint8)\n        >>> stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=9)\n        stim.PauliString(\"+XXXXYYYZZ\")\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.from_unitary_matrix\"></a>\n```python\n# stim.PauliString.from_unitary_matrix\n\n# (in class stim.PauliString)\n@staticmethod\ndef from_unitary_matrix(\n    matrix: Iterable[Iterable[Union[int, float, complex]]],\n    *,\n    endian: Literal[\"little\", \"big\"] = 'little',\n    unsigned: bool = False,\n) -> stim.PauliString:\n    \"\"\"Creates a stim.PauliString from the unitary matrix of a Pauli group member.\n\n    Args:\n        matrix: A unitary matrix specified as an iterable of rows, with each row is\n            an iterable of amplitudes. The unitary matrix must correspond to a\n            Pauli string, including global phase.\n        endian:\n            \"little\": matrix entries are in little endian order, where higher index\n                qubits correspond to larger changes in row/col indices.\n            \"big\": matrix entries are in big endian order, where higher index\n                qubits correspond to smaller changes in row/col indices.\n        unsigned: When False, the input must only contain the values\n            [0, 1, -1, 1j, -1j] and the output will have the correct global phase.\n            When True, the input is permitted to be scaled by an arbitrary unit\n            complex value and the output will always have positive sign.\n            False is stricter but provides more information, while True is more\n            flexible but provides less information.\n\n    Returns:\n        The pauli string equal to the given unitary matrix.\n\n    Raises:\n        ValueError: The given matrix isn't the unitary matrix of a Pauli string.\n\n    Examples:\n        >>> import stim\n        >>> stim.PauliString.from_unitary_matrix([\n        ...     [1j, 0],\n        ...     [0, -1j],\n        ... ], endian='little')\n        stim.PauliString(\"+iZ\")\n\n        >>> stim.PauliString.from_unitary_matrix([\n        ...     [1j**0.1, 0],\n        ...     [0, -(1j**0.1)],\n        ... ], endian='little', unsigned=True)\n        stim.PauliString(\"+Z\")\n\n        >>> stim.PauliString.from_unitary_matrix([\n        ...     [0, 1, 0, 0],\n        ...     [1, 0, 0, 0],\n        ...     [0, 0, 0, -1],\n        ...     [0, 0, -1, 0],\n        ... ], endian='little')\n        stim.PauliString(\"+XZ\")\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.iter_all\"></a>\n```python\n# stim.PauliString.iter_all\n\n# (in class stim.PauliString)\n@staticmethod\ndef iter_all(\n    num_qubits: int,\n    *,\n    min_weight: int = 0,\n    max_weight: object = None,\n    allowed_paulis: str = 'XYZ',\n) -> stim.PauliStringIterator:\n    \"\"\"Returns an iterator that iterates over all matching pauli strings.\n\n    Args:\n        num_qubits: The desired number of qubits in the pauli strings.\n        min_weight: Defaults to 0. The minimum number of non-identity terms that\n            must be present in each yielded pauli string.\n        max_weight: Defaults to None (unused). The maximum number of non-identity\n            terms that must be present in each yielded pauli string.\n        allowed_paulis: Defaults to \"XYZ\". Set this to a string containing the\n            non-identity paulis that are allowed to appear in each yielded pauli\n            string. This argument must be a string made up of only \"X\", \"Y\", and\n            \"Z\" characters. A non-identity Pauli is allowed if it appears in the\n            string, and not allowed if it doesn't. Identity Paulis are always\n            allowed.\n\n    Returns:\n        An Iterable[stim.PauliString] that yields the requested pauli strings.\n\n    Examples:\n        >>> import stim\n        >>> pauli_string_iterator = stim.PauliString.iter_all(\n        ...     num_qubits=3,\n        ...     min_weight=1,\n        ...     max_weight=2,\n        ...     allowed_paulis=\"XZ\",\n        ... )\n        >>> for p in pauli_string_iterator:\n        ...     print(p)\n        +X__\n        +Z__\n        +_X_\n        +_Z_\n        +__X\n        +__Z\n        +XX_\n        +XZ_\n        +ZX_\n        +ZZ_\n        +X_X\n        +X_Z\n        +Z_X\n        +Z_Z\n        +_XX\n        +_XZ\n        +_ZX\n        +_ZZ\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.pauli_indices\"></a>\n```python\n# stim.PauliString.pauli_indices\n\n# (in class stim.PauliString)\ndef pauli_indices(\n    self,\n    included_paulis: str = \"XYZ\",\n) -> List[int]:\n    \"\"\"Returns the indices of non-identity Paulis, or of specified Paulis.\n\n    Args:\n        include: A string containing the Pauli types to include.\n            X type Pauli indices are included if \"X\" or \"x\" is in the string.\n            Y type Pauli indices are included if \"Y\" or \"y\" is in the string.\n            Z type Pauli indices are included if \"Z\" or \"z\" is in the string.\n            I type Pauli indices are included if \"I\" or \"_\" is in the string.\n            An exception is thrown if other characters are in the string.\n\n    Returns:\n        A list containing the ascending indices of matching Pauli terms.\n\n    Examples:\n        >>> import stim\n        >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices()\n        [5, 9, 14]\n\n        >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"XZ\")\n        [5, 14]\n\n        >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"X\")\n        [5]\n\n        >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"Y\")\n        [9]\n\n        >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"IY\")\n        [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17]\n\n        >>> stim.PauliString(\"-X103*Y100\").pauli_indices()\n        [100, 103]\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.random\"></a>\n```python\n# stim.PauliString.random\n\n# (in class stim.PauliString)\n@staticmethod\ndef random(\n    num_qubits: int,\n    *,\n    allow_imaginary: bool = False,\n) -> stim.PauliString:\n    \"\"\"Samples a uniformly random Hermitian Pauli string.\n\n    Args:\n        num_qubits: The number of qubits the Pauli string should act on.\n        allow_imaginary: Defaults to False. If True, the sign of the result may be\n            1j or -1j in addition to +1 or -1. In other words, setting this to True\n            allows the result to be non-Hermitian.\n\n    Examples:\n        >>> import stim\n        >>> p = stim.PauliString.random(5)\n        >>> len(p)\n        5\n        >>> p.sign in [-1, +1]\n        True\n\n        >>> p2 = stim.PauliString.random(3, allow_imaginary=True)\n        >>> len(p2)\n        3\n        >>> p2.sign in [-1, +1, 1j, -1j]\n        True\n\n    Returns:\n        The sampled Pauli string.\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.sign\"></a>\n```python\n# stim.PauliString.sign\n\n# (in class stim.PauliString)\n@property\ndef sign(\n    self,\n) -> complex:\n    \"\"\"The sign of the Pauli string. Can be +1, -1, 1j, or -1j.\n\n    Examples:\n        >>> import stim\n        >>> stim.PauliString(\"X\").sign\n        (1+0j)\n        >>> stim.PauliString(\"-X\").sign\n        (-1+0j)\n        >>> stim.PauliString(\"iX\").sign\n        1j\n        >>> stim.PauliString(\"-iX\").sign\n        (-0-1j)\n    \"\"\"\n@sign.setter\ndef sign(self, value: complex):\n    pass\n```\n\n<a name=\"stim.PauliString.to_numpy\"></a>\n```python\n# stim.PauliString.to_numpy\n\n# (in class stim.PauliString)\ndef to_numpy(\n    self,\n    *,\n    bit_packed: bool = False,\n) -> Tuple[np.ndarray, np.ndarray]:\n    \"\"\"Decomposes the contents of the pauli string into X bit and Z bit numpy arrays.\n\n    Args:\n        bit_packed: Defaults to False. Determines whether the output numpy arrays\n            use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n    Returns:\n        An (xs, zs) tuple encoding the paulis from the string. The k'th Pauli from\n        the string is encoded into k'th bit of xs and the k'th bit of zs using\n        the \"xz\" encoding:\n\n            P=I -> x=0 and z=0\n            P=X -> x=1 and z=0\n            P=Y -> x=1 and z=1\n            P=Z -> x=0 and z=1\n\n        The dtype and shape of the result depends on the bit_packed argument.\n\n        If bit_packed=False:\n            Each bit gets its own byte.\n            xs.dtype = zs.dtype = np.bool_\n            xs.shape = zs.shape = len(self)\n            xs_k = xs[k]\n            zs_k = zs[k]\n\n        If bit_packed=True:\n            Equivalent to applying np.packbits(bitorder='little') to the result.\n            xs.dtype = zs.dtype = np.uint8\n            xs.shape = zs.shape = math.ceil(len(self) / 8)\n            xs_k = (xs[k // 8] >> (k % 8)) & 1\n            zs_k = (zs[k // 8] >> (k % 8)) & 1\n\n    Examples:\n        >>> import stim\n\n        >>> xs, zs = stim.PauliString(\"XXXXYYYZZ\").to_numpy()\n        >>> xs\n        array([ True,  True,  True,  True,  True,  True,  True, False, False])\n        >>> zs\n        array([False, False, False, False,  True,  True,  True,  True,  True])\n\n        >>> xs, zs = stim.PauliString(\"XXXXYYYZZ\").to_numpy(bit_packed=True)\n        >>> xs\n        array([127,   0], dtype=uint8)\n        >>> zs\n        array([240,   1], dtype=uint8)\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.to_tableau\"></a>\n```python\n# stim.PauliString.to_tableau\n\n# (in class stim.PauliString)\ndef to_tableau(\n    self,\n) -> stim.Tableau:\n    \"\"\"Creates a Tableau equivalent to this Pauli string.\n\n    The tableau represents a Clifford operation that multiplies qubits\n    by the corresponding Pauli operations from this Pauli string.\n    The global phase of the pauli operation is lost in the conversion.\n\n    Returns:\n        The created tableau.\n\n    Examples:\n        >>> import stim\n        >>> p = stim.PauliString(\"ZZ\")\n        >>> p.to_tableau()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"-X_\"),\n                stim.PauliString(\"-_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+Z_\"),\n                stim.PauliString(\"+_Z\"),\n            ],\n        )\n        >>> q = stim.PauliString(\"YX_Z\")\n        >>> q.to_tableau()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"-X___\"),\n                stim.PauliString(\"+_X__\"),\n                stim.PauliString(\"+__X_\"),\n                stim.PauliString(\"-___X\"),\n            ],\n            zs=[\n                stim.PauliString(\"-Z___\"),\n                stim.PauliString(\"-_Z__\"),\n                stim.PauliString(\"+__Z_\"),\n                stim.PauliString(\"+___Z\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.to_unitary_matrix\"></a>\n```python\n# stim.PauliString.to_unitary_matrix\n\n# (in class stim.PauliString)\ndef to_unitary_matrix(\n    self,\n    *,\n    endian: Literal[\"little\", \"big\"],\n) -> np.ndarray[np.complex64]:\n    \"\"\"Converts the pauli string into a unitary matrix.\n\n    Args:\n        endian:\n            \"little\": The first qubit is the least significant (corresponds\n                to an offset of 1 in the matrix).\n            \"big\": The first qubit is the most significant (corresponds\n                to an offset of 2**(n - 1) in the matrix).\n\n    Returns:\n        A numpy array with dtype=np.complex64 and\n        shape=(1 << len(pauli_string), 1 << len(pauli_string)).\n\n    Example:\n        >>> import stim\n        >>> stim.PauliString(\"-YZ\").to_unitary_matrix(endian=\"little\")\n        array([[0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j],\n               [0.-1.j, 0.+0.j, 0.+0.j, 0.+0.j],\n               [0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j],\n               [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j]], dtype=complex64)\n    \"\"\"\n```\n\n<a name=\"stim.PauliString.weight\"></a>\n```python\n# stim.PauliString.weight\n\n# (in class stim.PauliString)\n@property\ndef weight(\n    self,\n) -> int:\n    \"\"\"Returns the number of non-identity pauli terms in the pauli string.\n\n    Examples:\n        >>> import stim\n        >>> stim.PauliString(\"+___\").weight\n        0\n        >>> stim.PauliString(\"+__X\").weight\n        1\n        >>> stim.PauliString(\"+XYZ\").weight\n        3\n        >>> stim.PauliString(\"-XXX___XXYZ\").weight\n        7\n    \"\"\"\n```\n\n<a name=\"stim.PauliStringIterator\"></a>\n```python\n# stim.PauliStringIterator\n\n# (at top-level in the stim module)\nclass PauliStringIterator:\n    \"\"\"Iterates over all pauli strings matching specified patterns.\n\n    Examples:\n        >>> import stim\n        >>> pauli_string_iterator = stim.PauliString.iter_all(\n        ...     2,\n        ...     min_weight=1,\n        ...     max_weight=1,\n        ...     allowed_paulis=\"XZ\",\n        ... )\n        >>> for p in pauli_string_iterator:\n        ...     print(p)\n        +X_\n        +Z_\n        +_X\n        +_Z\n    \"\"\"\n```\n\n<a name=\"stim.PauliStringIterator.__iter__\"></a>\n```python\n# stim.PauliStringIterator.__iter__\n\n# (in class stim.PauliStringIterator)\ndef __iter__(\n    self,\n) -> stim.PauliStringIterator:\n    \"\"\"Returns an independent copy of the pauli string iterator.\n\n    Since for-loops and loop-comprehensions call `iter` on things they\n    iterate, this effectively allows the iterator to be iterated\n    multiple times.\n    \"\"\"\n```\n\n<a name=\"stim.PauliStringIterator.__next__\"></a>\n```python\n# stim.PauliStringIterator.__next__\n\n# (in class stim.PauliStringIterator)\ndef __next__(\n    self,\n) -> stim.PauliString:\n    \"\"\"Returns the next iterated pauli string.\n    \"\"\"\n```\n\n<a name=\"stim.Tableau\"></a>\n```python\n# stim.Tableau\n\n# (at top-level in the stim module)\nclass Tableau:\n    \"\"\"A stabilizer tableau.\n\n    Represents a Clifford operation by explicitly storing how that operation\n    conjugates a list of Pauli group generators into composite Pauli products.\n\n    Examples:\n        >>> import stim\n        >>> stim.Tableau.from_named_gate(\"H\")\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X\"),\n            ],\n        )\n\n        >>> t = stim.Tableau.random(5)\n        >>> t_inv = t**-1\n        >>> print(t * t_inv)\n        +-xz-xz-xz-xz-xz-\n        | ++ ++ ++ ++ ++\n        | XZ __ __ __ __\n        | __ XZ __ __ __\n        | __ __ XZ __ __\n        | __ __ __ XZ __\n        | __ __ __ __ XZ\n\n        >>> x2z3 = t.x_output(2) * t.z_output(3)\n        >>> t_inv(x2z3)\n        stim.PauliString(\"+__XZ_\")\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__add__\"></a>\n```python\n# stim.Tableau.__add__\n\n# (in class stim.Tableau)\ndef __add__(\n    self,\n    rhs: stim.Tableau,\n) -> stim.Tableau:\n    \"\"\"Returns the direct sum (diagonal concatenation) of two Tableaus.\n\n    Args:\n        rhs: A second stim.Tableau.\n\n    Examples:\n        >>> import stim\n\n        >>> s = stim.Tableau.from_named_gate(\"S\")\n        >>> cz = stim.Tableau.from_named_gate(\"CZ\")\n        >>> print(s + cz)\n        +-xz-xz-xz-\n        | ++ ++ ++\n        | YZ __ __\n        | __ XZ Z_\n        | __ Z_ XZ\n\n    Returns:\n        The direct sum.\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__call__\"></a>\n```python\n# stim.Tableau.__call__\n\n# (in class stim.Tableau)\ndef __call__(\n    self,\n    pauli_string: stim.PauliString,\n) -> stim.PauliString:\n    \"\"\"Returns the equivalent PauliString after the Tableau's Clifford operation.\n\n    If P is a Pauli product before a Clifford operation C, then this method returns\n    Q = C * P * C**-1 (the conjugation of P by C). Q is the equivalent Pauli product\n    after C. This works because:\n\n        C*P\n        = C*P * I\n        = C*P * (C**-1 * C)\n        = (C*P*C**-1) * C\n        = Q*C\n\n    (Keep in mind that A*B means first B is applied, then A is applied.)\n\n    Args:\n        pauli_string: The pauli string to conjugate.\n\n    Returns:\n        The new conjugated pauli string.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n        >>> p = stim.PauliString(\"XX\")\n        >>> result = t(p)\n        >>> print(result)\n        +X_\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__eq__\"></a>\n```python\n# stim.Tableau.__eq__\n\n# (in class stim.Tableau)\ndef __eq__(\n    self,\n    arg0: stim.Tableau,\n) -> bool:\n    \"\"\"Determines if two tableaus have identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__iadd__\"></a>\n```python\n# stim.Tableau.__iadd__\n\n# (in class stim.Tableau)\ndef __iadd__(\n    self,\n    rhs: stim.Tableau,\n) -> stim.Tableau:\n    \"\"\"Performs an inplace direct sum (diagonal concatenation).\n\n    Args:\n        rhs: A second stim.Tableau.\n\n    Examples:\n        >>> import stim\n\n        >>> s = stim.Tableau.from_named_gate(\"S\")\n        >>> cz = stim.Tableau.from_named_gate(\"CZ\")\n        >>> alias = s\n        >>> s += cz\n        >>> alias is s\n        True\n        >>> print(s)\n        +-xz-xz-xz-\n        | ++ ++ ++\n        | YZ __ __\n        | __ XZ Z_\n        | __ Z_ XZ\n\n    Returns:\n        The mutated tableau.\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__init__\"></a>\n```python\n# stim.Tableau.__init__\n\n# (in class stim.Tableau)\ndef __init__(\n    self,\n    num_qubits: int,\n) -> None:\n    \"\"\"Creates an identity tableau over the given number of qubits.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.Tableau(3)\n        >>> print(t)\n        +-xz-xz-xz-\n        | ++ ++ ++\n        | XZ __ __\n        | __ XZ __\n        | __ __ XZ\n\n    Args:\n        num_qubits: The number of qubits the tableau's operation acts on.\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__len__\"></a>\n```python\n# stim.Tableau.__len__\n\n# (in class stim.Tableau)\ndef __len__(\n    self,\n) -> int:\n    \"\"\"Returns the number of qubits operated on by the tableau.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n        >>> len(t)\n        2\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__mul__\"></a>\n```python\n# stim.Tableau.__mul__\n\n# (in class stim.Tableau)\ndef __mul__(\n    self,\n    rhs: stim.Tableau,\n) -> stim.Tableau:\n    \"\"\"Returns the product of two tableaus.\n\n    If the tableau T1 represents the Clifford operation with unitary C1,\n    and the tableau T2 represents the Clifford operation with unitary C2,\n    then the tableau T1*T2 represents the Clifford operation with unitary C1*C2.\n\n    Args:\n        rhs: The tableau  on the right hand side of the multiplication.\n\n    Examples:\n        >>> import stim\n        >>> t1 = stim.Tableau.random(4)\n        >>> t2 = stim.Tableau.random(4)\n        >>> t3 = t2 * t1\n        >>> p = stim.PauliString.random(4)\n        >>> t3(p) == t2(t1(p))\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__ne__\"></a>\n```python\n# stim.Tableau.__ne__\n\n# (in class stim.Tableau)\ndef __ne__(\n    self,\n    arg0: stim.Tableau,\n) -> bool:\n    \"\"\"Determines if two tableaus have non-identical contents.\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__pow__\"></a>\n```python\n# stim.Tableau.__pow__\n\n# (in class stim.Tableau)\ndef __pow__(\n    self,\n    exponent: int,\n) -> stim.Tableau:\n    \"\"\"Raises the tableau to an integer power.\n\n    Large powers are reached efficiently using repeated squaring.\n    Negative powers are reached by inverting the tableau.\n\n    Args:\n        exponent: The power to raise to. Can be negative, zero, or positive.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.Tableau.from_named_gate(\"S\")\n        >>> s**0 == stim.Tableau(1)\n        True\n        >>> s**1 == s\n        True\n        >>> s**2 == stim.Tableau.from_named_gate(\"Z\")\n        True\n        >>> s**-1 == s**3 == stim.Tableau.from_named_gate(\"S_DAG\")\n        True\n        >>> s**5 == s\n        True\n        >>> s**(400000000 + 1) == s\n        True\n        >>> s**(-400000000 + 1) == s\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__repr__\"></a>\n```python\n# stim.Tableau.__repr__\n\n# (in class stim.Tableau)\ndef __repr__(\n    self,\n) -> str:\n    \"\"\"Returns valid python code evaluating to an equal `stim.Tableau`.\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.__str__\"></a>\n```python\n# stim.Tableau.__str__\n\n# (in class stim.Tableau)\ndef __str__(\n    self,\n) -> str:\n    \"\"\"Returns a text description.\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.append\"></a>\n```python\n# stim.Tableau.append\n\n# (in class stim.Tableau)\ndef append(\n    self,\n    gate: stim.Tableau,\n    targets: Sequence[int],\n) -> None:\n    \"\"\"Appends an operation's effect into this tableau, mutating this tableau.\n\n    Time cost is O(n*m*m) where n=len(self) and m=len(gate).\n\n    Args:\n        gate: The tableau of the operation being appended into this tableau.\n        targets: The qubits being targeted by the gate.\n\n    Examples:\n        >>> import stim\n        >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n        >>> t = stim.Tableau(2)\n        >>> t.append(cnot, [0, 1])\n        >>> t.append(cnot, [1, 0])\n        >>> t.append(cnot, [0, 1])\n        >>> t == stim.Tableau.from_named_gate(\"SWAP\")\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.copy\"></a>\n```python\n# stim.Tableau.copy\n\n# (in class stim.Tableau)\ndef copy(\n    self,\n) -> stim.Tableau:\n    \"\"\"Returns a copy of the tableau. An independent tableau with the same contents.\n\n    Examples:\n        >>> import stim\n        >>> t1 = stim.Tableau.random(2)\n        >>> t2 = t1.copy()\n        >>> t2 is t1\n        False\n        >>> t2 == t1\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.from_circuit\"></a>\n```python\n# stim.Tableau.from_circuit\n\n# (in class stim.Tableau)\n@staticmethod\ndef from_circuit(\n    circuit: stim.Circuit,\n    *,\n    ignore_noise: bool = False,\n    ignore_measurement: bool = False,\n    ignore_reset: bool = False,\n) -> stim.Tableau:\n    \"\"\"Converts a circuit into an equivalent stabilizer tableau.\n\n    Args:\n        circuit: The circuit to compile into a tableau.\n        ignore_noise: Defaults to False. When False, any noise operations in the\n            circuit will cause the conversion to fail with an exception. When True,\n            noise operations are skipped over as if they weren't even present in the\n            circuit.\n        ignore_measurement: Defaults to False. When False, any measurement\n            operations in the circuit will cause the conversion to fail with an\n            exception. When True, measurement operations are skipped over as if they\n            weren't even present in the circuit.\n        ignore_reset: Defaults to False. When False, any reset operations in the\n            circuit will cause the conversion to fail with an exception. When True,\n            reset operations are skipped over as if they weren't even present in the\n            circuit.\n\n    Returns:\n        The tableau equivalent to the given circuit (up to global phase).\n\n    Raises:\n        ValueError:\n            The circuit contains noise operations but ignore_noise=False.\n            OR\n            The circuit contains measurement operations but\n            ignore_measurement=False.\n            OR\n            The circuit contains reset operations but ignore_reset=False.\n\n    Examples:\n        >>> import stim\n        >>> stim.Tableau.from_circuit(stim.Circuit('''\n        ...     H 0\n        ...     CNOT 0 1\n        ... '''))\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z_\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+XX\"),\n                stim.PauliString(\"+ZZ\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.from_conjugated_generators\"></a>\n```python\n# stim.Tableau.from_conjugated_generators\n\n# (in class stim.Tableau)\n@staticmethod\ndef from_conjugated_generators(\n    *,\n    xs: List[stim.PauliString],\n    zs: List[stim.PauliString],\n) -> stim.Tableau:\n    \"\"\"Creates a tableau from the given outputs for each generator.\n\n    Verifies that the tableau is well formed.\n\n    Args:\n        xs: A List[stim.PauliString] with the results of conjugating X0, X1, etc.\n        zs: A List[stim.PauliString] with the results of conjugating Z0, Z1, etc.\n\n    Returns:\n        The created tableau.\n\n    Raises:\n        ValueError: The given outputs are malformed. Their lengths are inconsistent,\n            or they don't satisfy the required commutation relationships.\n\n    Examples:\n        >>> import stim\n        >>> identity3 = stim.Tableau.from_conjugated_generators(\n        ...     xs=[\n        ...         stim.PauliString(\"X__\"),\n        ...         stim.PauliString(\"_X_\"),\n        ...         stim.PauliString(\"__X\"),\n        ...     ],\n        ...     zs=[\n        ...         stim.PauliString(\"Z__\"),\n        ...         stim.PauliString(\"_Z_\"),\n        ...         stim.PauliString(\"__Z\"),\n        ...     ],\n        ... )\n        >>> identity3 == stim.Tableau(3)\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.from_named_gate\"></a>\n```python\n# stim.Tableau.from_named_gate\n\n# (in class stim.Tableau)\n@staticmethod\ndef from_named_gate(\n    name: str,\n) -> stim.Tableau:\n    \"\"\"Returns the tableau of a named Clifford gate.\n\n    Args:\n        name: The name of the Clifford gate.\n\n    Returns:\n        The gate's tableau.\n\n    Examples:\n        >>> import stim\n        >>> print(stim.Tableau.from_named_gate(\"H\"))\n        +-xz-\n        | ++\n        | ZX\n        >>> print(stim.Tableau.from_named_gate(\"CNOT\"))\n        +-xz-xz-\n        | ++ ++\n        | XZ _Z\n        | X_ XZ\n        >>> print(stim.Tableau.from_named_gate(\"S\"))\n        +-xz-\n        | ++\n        | YZ\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.from_numpy\"></a>\n```python\n# stim.Tableau.from_numpy\n\n# (in class stim.Tableau)\ndef from_numpy(\n    self,\n    *,\n    x2x: np.ndarray,\n    x2z: np.ndarray,\n    z2x: np.ndarray,\n    z2z: np.ndarray,\n    x_signs: Optional[np.ndarray] = None,\n    z_signs: Optional[np.ndarray] = None,\n) -> stim.Tableau:\n    \"\"\"Creates a tableau from numpy arrays x2x, x2z, z2x, z2z, x_signs, and z_signs.\n\n    The x2x, x2z, z2x, z2z arrays are the four quadrants of the table defined in\n    Aaronson and Gottesman's \"Improved Simulation of Stabilizer Circuits\"\n    ( https://arxiv.org/abs/quant-ph/0406196 ).\n\n    Args:\n        x2x: A 2d numpy array containing the x-to-x coupling bits. The bits can be\n            bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n            result will satisfy result.x_output_pauli(i, j) in [1, 2] == x2x[i, j].\n            Bit packing must be in little endian order and only applies to the\n            second axis.\n        x2z: A 2d numpy array containing the x-to-z coupling bits. The bits can be\n            bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n            result will satisfy result.x_output_pauli(i, j) in [2, 3] == x2z[i, j].\n            Bit packing must be in little endian order and only applies to the\n            second axis.\n        z2x: A 2d numpy array containing the z-to-x coupling bits. The bits can be\n            bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n            result will satisfy result.z_output_pauli(i, j) in [1, 2] == z2x[i, j].\n            Bit packing must be in little endian order and only applies to the\n            second axis.\n        z2z: A 2d numpy array containing the z-to-z coupling bits. The bits can be\n            bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n            result will satisfy result.z_output_pauli(i, j) in [2, 3] == z2z[i, j].\n            Bit packing must be in little endian order and only applies to the\n            second axis.\n        x_signs: Defaults to all-positive if not specified. A 1d numpy array\n            containing the sign bits for the X generator outputs. False means\n            positive and True means negative. The bits can be bit packed\n            (dtype=uint8) or not (dtype=bool_). Bit packing must be in little endian\n            order.\n        z_signs: Defaults to all-positive if not specified. A 1d numpy array\n            containing the sign bits for the Z generator outputs. False means\n            positive and True means negative. The bits can be bit packed\n            (dtype=uint8) or not (dtype=bool_). Bit packing must be in little endian\n            order.\n\n    Returns:\n        The tableau created from the numpy data.\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n\n        >>> tableau = stim.Tableau.from_numpy(\n        ...     x2x=np.array([[1, 1], [0, 1]], dtype=np.bool_),\n        ...     z2x=np.array([[0, 0], [0, 0]], dtype=np.bool_),\n        ...     x2z=np.array([[0, 0], [0, 0]], dtype=np.bool_),\n        ...     z2z=np.array([[1, 0], [1, 1]], dtype=np.bool_),\n        ... )\n        >>> tableau\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+XX\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+Z_\"),\n                stim.PauliString(\"+ZZ\"),\n            ],\n        )\n        >>> tableau == stim.Tableau.from_named_gate(\"CNOT\")\n        True\n\n        >>> stim.Tableau.from_numpy(\n        ...     x2x=np.array([[9], [5], [7], [6]], dtype=np.uint8),\n        ...     x2z=np.array([[13], [13], [0], [3]], dtype=np.uint8),\n        ...     z2x=np.array([[8], [5], [9], [15]], dtype=np.uint8),\n        ...     z2z=np.array([[6], [11], [2], [3]], dtype=np.uint8),\n        ...     x_signs=np.array([7], dtype=np.uint8),\n        ...     z_signs=np.array([9], dtype=np.uint8),\n        ... )\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"-Y_ZY\"),\n                stim.PauliString(\"-Y_YZ\"),\n                stim.PauliString(\"-XXX_\"),\n                stim.PauliString(\"+ZYX_\"),\n            ],\n            zs=[\n                stim.PauliString(\"-_ZZX\"),\n                stim.PauliString(\"+YZXZ\"),\n                stim.PauliString(\"+XZ_X\"),\n                stim.PauliString(\"-YYXX\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.from_stabilizers\"></a>\n```python\n# stim.Tableau.from_stabilizers\n\n# (in class stim.Tableau)\n@staticmethod\ndef from_stabilizers(\n    stabilizers: Iterable[stim.PauliString],\n    *,\n    allow_redundant: bool = False,\n    allow_underconstrained: bool = False,\n) -> stim.Tableau:\n    \"\"\"Creates a tableau representing a state with the given stabilizers.\n\n    Args:\n        stabilizers: A list of `stim.PauliString`s specifying the stabilizers that\n            the state must have. It is permitted for stabilizers to have different\n            lengths. All stabilizers are padded up to the length of the longest\n            stabilizer by appending identity terms.\n        allow_redundant: Defaults to False. If set to False, then the given\n            stabilizers must all be independent. If any one of them is a product of\n            the others (including the empty product), an exception will be raised.\n            If set to True, then redundant stabilizers are simply ignored.\n        allow_underconstrained: Defaults to False. If set to False, then the given\n            stabilizers must form a complete set of generators. They must exactly\n            specify the desired stabilizer state, with no degrees of freedom left\n            over. For an n-qubit state there must be n independent stabilizers. If\n            set to True, then there can be leftover degrees of freedom which can be\n            set arbitrarily.\n\n    Returns:\n        A tableau which, when applied to the all-zeroes state, produces a state\n        with the given stabilizers.\n\n        Guarantees that result.z_output(k) will be equal to the k'th independent\n        stabilizer from the `stabilizers` argument.\n\n    Raises:\n        ValueError:\n            A stabilizer is redundant but allow_redundant=True wasn't set.\n            OR\n            The given stabilizers are contradictory (e.g. \"+Z\" and \"-Z\" both\n            specified).\n            OR\n            The given stabilizers anticommute (e.g. \"+Z\" and \"+X\" both specified).\n            OR\n            The stabilizers left behind a degree of freedom but\n            allow_underconstrained=True wasn't set.\n            OR\n            A stabilizer has an imaginary sign (i or -i).\n\n    Examples:\n\n        >>> import stim\n        >>> stim.Tableau.from_stabilizers([\n        ...     stim.PauliString(\"XX\"),\n        ...     stim.PauliString(\"ZZ\"),\n        ... ])\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z_\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+XX\"),\n                stim.PauliString(\"+ZZ\"),\n            ],\n        )\n\n        >>> stim.Tableau.from_stabilizers([\n        ...     stim.PauliString(\"XX_\"),\n        ...     stim.PauliString(\"ZZ_\"),\n        ...     stim.PauliString(\"-YY_\"),\n        ...     stim.PauliString(\"\"),\n        ... ], allow_underconstrained=True, allow_redundant=True)\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z__\"),\n                stim.PauliString(\"+_X_\"),\n                stim.PauliString(\"+__X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+XX_\"),\n                stim.PauliString(\"+ZZ_\"),\n                stim.PauliString(\"+__Z\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.from_state_vector\"></a>\n```python\n# stim.Tableau.from_state_vector\n\n# (in class stim.Tableau)\n@staticmethod\ndef from_state_vector(\n    state_vector: Iterable[float],\n    *,\n    endian: Literal[\"little\", \"big\"],\n) -> stim.Tableau:\n    \"\"\"Creates a tableau representing the stabilizer state of the given state vector.\n\n    Args:\n        state_vector: A list of complex amplitudes specifying a superposition. The\n            vector must correspond to a state that is reachable using Clifford\n            operations, and can be unnormalized.\n        endian:\n            \"little\": state vector is in little endian order, where higher index\n                qubits correspond to larger changes in the state index.\n            \"big\": state vector is in big endian order, where higher index qubits\n                correspond to smaller changes in the state index.\n\n    Returns:\n        A tableau which, when applied to the all-zeroes state, produces a state\n        with the given state vector.\n\n    Raises:\n        ValueError:\n            The given state vector isn't a list of complex values specifying a\n            stabilizer state.\n            OR\n            The given endian value isn't 'little' or 'big'.\n\n    Examples:\n\n        >>> import stim\n        >>> stim.Tableau.from_state_vector([\n        ...     0.5**0.5,\n        ...     0.5**0.5 * 1j,\n        ... ], endian='little')\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+Y\"),\n            ],\n        )\n        >>> stim.Tableau.from_state_vector([\n        ...     0.5**0.5,\n        ...     0,\n        ...     0,\n        ...     0.5**0.5,\n        ... ], endian='little')\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z_\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+XX\"),\n                stim.PauliString(\"+ZZ\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.from_unitary_matrix\"></a>\n```python\n# stim.Tableau.from_unitary_matrix\n\n# (in class stim.Tableau)\n@staticmethod\ndef from_unitary_matrix(\n    matrix: Iterable[Iterable[float]],\n    *,\n    endian: Literal[\"little\", \"big\"] = 'little',\n) -> stim.Tableau:\n    \"\"\"Creates a tableau from the unitary matrix of a Clifford operation.\n\n    Args:\n        matrix: A unitary matrix specified as an iterable of rows, with each row is\n            an iterable of amplitudes. The unitary matrix must correspond to a\n            Clifford operation.\n        endian:\n            \"little\": matrix entries are in little endian order, where higher index\n                qubits correspond to larger changes in row/col indices.\n            \"big\": matrix entries are in big endian order, where higher index\n                qubits correspond to smaller changes in row/col indices.\n    Returns:\n        The tableau equivalent to the given unitary matrix (up to global phase).\n\n    Raises:\n        ValueError: The given matrix isn't the unitary matrix of a Clifford\n            operation.\n\n    Examples:\n        >>> import stim\n        >>> stim.Tableau.from_unitary_matrix([\n        ...     [1, 0],\n        ...     [0, 1j],\n        ... ], endian='little')\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Y\"),\n            ],\n            zs=[\n                stim.PauliString(\"+Z\"),\n            ],\n        )\n\n        >>> stim.Tableau.from_unitary_matrix([\n        ...     [1, 0, 0, 0],\n        ...     [0, 1, 0, 0],\n        ...     [0, 0, 0, -1j],\n        ...     [0, 0, 1j, 0],\n        ... ], endian='little')\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+XZ\"),\n                stim.PauliString(\"+YX\"),\n            ],\n            zs=[\n                stim.PauliString(\"+ZZ\"),\n                stim.PauliString(\"+_Z\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.inverse\"></a>\n```python\n# stim.Tableau.inverse\n\n# (in class stim.Tableau)\ndef inverse(\n    self,\n    *,\n    unsigned: bool = False,\n) -> stim.Tableau:\n    \"\"\"Computes the inverse of the tableau.\n\n    The inverse T^-1 of a tableau T is the unique tableau with the property that\n    T * T^-1 = T^-1 * T = I where I is the identity tableau.\n\n    Args:\n        unsigned: Defaults to false. When set to true, skips computing the signs of\n            the output observables and instead just set them all to be positive.\n            This is beneficial because computing the signs takes O(n^3) time and the\n            rest of the inverse computation is O(n^2) where n is the number of\n            qubits in the tableau. So, if you only need the Pauli terms (not the\n            signs), it is significantly cheaper.\n\n    Returns:\n        The inverse tableau.\n\n    Examples:\n        >>> import stim\n\n        >>> # Check that the inverse agrees with hard-coded tableaus.\n        >>> s = stim.Tableau.from_named_gate(\"S\")\n        >>> s_dag = stim.Tableau.from_named_gate(\"S_DAG\")\n        >>> s.inverse() == s_dag\n        True\n        >>> z = stim.Tableau.from_named_gate(\"Z\")\n        >>> z.inverse() == z\n        True\n\n        >>> # Check that multiplying by the inverse produces the identity.\n        >>> t = stim.Tableau.random(10)\n        >>> t_inv = t.inverse()\n        >>> identity = stim.Tableau(10)\n        >>> t * t_inv == t_inv * t == identity\n        True\n\n        >>> # Check a manual case.\n        >>> t = stim.Tableau.from_conjugated_generators(\n        ...     xs=[\n        ...         stim.PauliString(\"-__Z\"),\n        ...         stim.PauliString(\"+XZ_\"),\n        ...         stim.PauliString(\"+_ZZ\"),\n        ...     ],\n        ...     zs=[\n        ...         stim.PauliString(\"-YYY\"),\n        ...         stim.PauliString(\"+Z_Z\"),\n        ...         stim.PauliString(\"-ZYZ\")\n        ...     ],\n        ... )\n        >>> print(t.inverse())\n        +-xz-xz-xz-\n        | -- +- --\n        | XX XX YX\n        | XZ Z_ X_\n        | X_ YX Y_\n        >>> print(t.inverse(unsigned=True))\n        +-xz-xz-xz-\n        | ++ ++ ++\n        | XX XX YX\n        | XZ Z_ X_\n        | X_ YX Y_\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.inverse_x_output\"></a>\n```python\n# stim.Tableau.inverse_x_output\n\n# (in class stim.Tableau)\ndef inverse_x_output(\n    self,\n    input_index: int,\n    *,\n    unsigned: bool = False,\n) -> stim.PauliString:\n    \"\"\"Conjugates a single-qubit X Pauli generator by the inverse of the tableau.\n\n    A faster version of `tableau.inverse(unsigned).x_output(input_index)`.\n\n    Args:\n        input_index: Identifies the column (the qubit of the X generator) to return\n            from the inverse tableau.\n        unsigned: Defaults to false. When set to true, skips computing the result's\n            sign and instead just sets it to positive. This is beneficial because\n            computing the sign takes O(n^2) time whereas all other parts of the\n            computation take O(n) time where n is the number of qubits in the\n            tableau.\n\n    Returns:\n        The result of conjugating an X generator by the inverse of the tableau.\n\n    Examples:\n        >>> import stim\n\n        # Check equivalence with the inverse's x_output.\n        >>> t = stim.Tableau.random(4)\n        >>> expected = t.inverse().x_output(0)\n        >>> t.inverse_x_output(0) == expected\n        True\n        >>> expected.sign = +1\n        >>> t.inverse_x_output(0, unsigned=True) == expected\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.inverse_x_output_pauli\"></a>\n```python\n# stim.Tableau.inverse_x_output_pauli\n\n# (in class stim.Tableau)\ndef inverse_x_output_pauli(\n    self,\n    input_index: int,\n    output_index: int,\n) -> int:\n    \"\"\"Constant-time version of `tableau.inverse().x_output(input_index)[output_index]`\n\n    Args:\n        input_index: Identifies the column (the qubit of the input X generator) in\n            the inverse tableau.\n        output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n    Returns:\n        An integer identifying Pauli at the given location in the inverse tableau:\n\n            0: I\n            1: X\n            2: Y\n            3: Z\n\n    Examples:\n        >>> import stim\n\n        >>> t_inv = stim.Tableau.from_conjugated_generators(\n        ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n        ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n        ... ).inverse()\n        >>> t_inv.inverse_x_output_pauli(0, 0)\n        2\n        >>> t_inv.inverse_x_output_pauli(0, 1)\n        0\n        >>> t_inv.inverse_x_output_pauli(1, 0)\n        2\n        >>> t_inv.inverse_x_output_pauli(1, 1)\n        3\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.inverse_y_output\"></a>\n```python\n# stim.Tableau.inverse_y_output\n\n# (in class stim.Tableau)\ndef inverse_y_output(\n    self,\n    input_index: int,\n    *,\n    unsigned: bool = False,\n) -> stim.PauliString:\n    \"\"\"Conjugates a single-qubit Y Pauli generator by the inverse of the tableau.\n\n    A faster version of `tableau.inverse(unsigned).y_output(input_index)`.\n\n    Args:\n        input_index: Identifies the column (the qubit of the Y generator) to return\n            from the inverse tableau.\n        unsigned: Defaults to false. When set to true, skips computing the result's\n            sign and instead just sets it to positive. This is beneficial because\n            computing the sign takes O(n^2) time whereas all other parts of the\n            computation take O(n) time where n is the number of qubits in the\n            tableau.\n\n    Returns:\n        The result of conjugating a Y generator by the inverse of the tableau.\n\n    Examples:\n        >>> import stim\n\n        # Check equivalence with the inverse's y_output.\n        >>> t = stim.Tableau.random(4)\n        >>> expected = t.inverse().y_output(0)\n        >>> t.inverse_y_output(0) == expected\n        True\n        >>> expected.sign = +1\n        >>> t.inverse_y_output(0, unsigned=True) == expected\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.inverse_y_output_pauli\"></a>\n```python\n# stim.Tableau.inverse_y_output_pauli\n\n# (in class stim.Tableau)\ndef inverse_y_output_pauli(\n    self,\n    input_index: int,\n    output_index: int,\n) -> int:\n    \"\"\"Constant-time version of `tableau.inverse().y_output(input_index)[output_index]`\n\n    Args:\n        input_index: Identifies the column (the qubit of the input Y generator) in\n            the inverse tableau.\n        output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n    Returns:\n        An integer identifying Pauli at the given location in the inverse tableau:\n\n            0: I\n            1: X\n            2: Y\n            3: Z\n\n    Examples:\n        >>> import stim\n\n        >>> t_inv = stim.Tableau.from_conjugated_generators(\n        ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n        ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n        ... ).inverse()\n        >>> t_inv.inverse_y_output_pauli(0, 0)\n        1\n        >>> t_inv.inverse_y_output_pauli(0, 1)\n        2\n        >>> t_inv.inverse_y_output_pauli(1, 0)\n        0\n        >>> t_inv.inverse_y_output_pauli(1, 1)\n        2\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.inverse_z_output\"></a>\n```python\n# stim.Tableau.inverse_z_output\n\n# (in class stim.Tableau)\ndef inverse_z_output(\n    self,\n    input_index: int,\n    *,\n    unsigned: bool = False,\n) -> stim.PauliString:\n    \"\"\"Conjugates a single-qubit Z Pauli generator by the inverse of the tableau.\n\n    A faster version of `tableau.inverse(unsigned).z_output(input_index)`.\n\n    Args:\n        input_index: Identifies the column (the qubit of the Z generator) to return\n            from the inverse tableau.\n        unsigned: Defaults to false. When set to true, skips computing the result's\n            sign and instead just sets it to positive. This is beneficial because\n            computing the sign takes O(n^2) time whereas all other parts of the\n            computation take O(n) time where n is the number of qubits in the\n            tableau.\n\n    Returns:\n        The result of conjugating a Z generator by the inverse of the tableau.\n\n    Examples:\n        >>> import stim\n\n        >>> import stim\n\n        # Check equivalence with the inverse's z_output.\n        >>> t = stim.Tableau.random(4)\n        >>> expected = t.inverse().z_output(0)\n        >>> t.inverse_z_output(0) == expected\n        True\n        >>> expected.sign = +1\n        >>> t.inverse_z_output(0, unsigned=True) == expected\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.inverse_z_output_pauli\"></a>\n```python\n# stim.Tableau.inverse_z_output_pauli\n\n# (in class stim.Tableau)\ndef inverse_z_output_pauli(\n    self,\n    input_index: int,\n    output_index: int,\n) -> int:\n    \"\"\"Constant-time version of `tableau.inverse().z_output(input_index)[output_index]`\n\n    Args:\n        input_index: Identifies the column (the qubit of the input Z generator) in\n            the inverse tableau.\n        output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n    Returns:\n        An integer identifying Pauli at the given location in the inverse tableau:\n\n            0: I\n            1: X\n            2: Y\n            3: Z\n\n    Examples:\n        >>> import stim\n\n        >>> t_inv = stim.Tableau.from_conjugated_generators(\n        ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n        ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n        ... ).inverse()\n        >>> t_inv.inverse_z_output_pauli(0, 0)\n        3\n        >>> t_inv.inverse_z_output_pauli(0, 1)\n        2\n        >>> t_inv.inverse_z_output_pauli(1, 0)\n        2\n        >>> t_inv.inverse_z_output_pauli(1, 1)\n        1\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.iter_all\"></a>\n```python\n# stim.Tableau.iter_all\n\n# (in class stim.Tableau)\n@staticmethod\ndef iter_all(\n    num_qubits: int,\n    *,\n    unsigned: bool = False,\n) -> stim.TableauIterator:\n    \"\"\"Returns an iterator that iterates over all Tableaus of a given size.\n\n    Args:\n        num_qubits: The size of tableau to iterate over.\n        unsigned: Defaults to False. If set to True, only tableaus where\n            all columns have positive sign are yielded by the iterator.\n            This substantially reduces the total number of tableaus to\n            iterate over.\n\n    Returns:\n        An Iterable[stim.Tableau] that yields the requested tableaus.\n\n    Examples:\n        >>> import stim\n        >>> single_qubit_gate_reprs = set()\n        >>> for t in stim.Tableau.iter_all(1):\n        ...     single_qubit_gate_reprs.add(repr(t))\n        >>> len(single_qubit_gate_reprs)\n        24\n\n        >>> num_2q_gates_mod_paulis = 0\n        >>> for _ in stim.Tableau.iter_all(2, unsigned=True):\n        ...     num_2q_gates_mod_paulis += 1\n        >>> num_2q_gates_mod_paulis\n        720\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.prepend\"></a>\n```python\n# stim.Tableau.prepend\n\n# (in class stim.Tableau)\ndef prepend(\n    self,\n    gate: stim.Tableau,\n    targets: Sequence[int],\n) -> None:\n    \"\"\"Prepends an operation's effect into this tableau, mutating this tableau.\n\n    Time cost is O(n*m*m) where n=len(self) and m=len(gate).\n\n    Args:\n        gate: The tableau of the operation being prepended into this tableau.\n        targets: The qubits being targeted by the gate.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.Tableau.from_named_gate(\"H\")\n        >>> t.prepend(stim.Tableau.from_named_gate(\"X\"), [0])\n        >>> t == stim.Tableau.from_named_gate(\"SQRT_Y_DAG\")\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.random\"></a>\n```python\n# stim.Tableau.random\n\n# (in class stim.Tableau)\n@staticmethod\ndef random(\n    num_qubits: int,\n) -> stim.Tableau:\n    \"\"\"Samples a uniformly random Clifford operation and returns its tableau.\n\n    Args:\n        num_qubits: The number of qubits the tableau should act on.\n\n    Returns:\n        The sampled tableau.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.Tableau.random(42)\n\n    References:\n        \"Hadamard-free circuits expose the structure of the Clifford group\"\n        Sergey Bravyi, Dmitri Maslov\n        https://arxiv.org/abs/2003.09412\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.then\"></a>\n```python\n# stim.Tableau.then\n\n# (in class stim.Tableau)\ndef then(\n    self,\n    second: stim.Tableau,\n) -> stim.Tableau:\n    \"\"\"Returns the result of composing two tableaus.\n\n    If the tableau T1 represents the Clifford operation with unitary C1,\n    and the tableau T2 represents the Clifford operation with unitary C2,\n    then the tableau T1.then(T2) represents the Clifford operation with unitary\n    C2*C1.\n\n    Args:\n        second: The result is equivalent to applying the second tableau after\n            the receiving tableau.\n\n    Examples:\n        >>> import stim\n        >>> t1 = stim.Tableau.random(4)\n        >>> t2 = stim.Tableau.random(4)\n        >>> t3 = t1.then(t2)\n        >>> p = stim.PauliString.random(4)\n        >>> t3(p) == t2(t1(p))\n        True\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.to_circuit\"></a>\n```python\n# stim.Tableau.to_circuit\n\n# (in class stim.Tableau)\ndef to_circuit(\n    self,\n    method: Literal[\"elimination\", \"graph_state\"] = 'elimination',\n) -> stim.Circuit:\n    \"\"\"Synthesizes a circuit that implements the tableau's Clifford operation.\n\n    The circuits returned by this method are not guaranteed to be stable\n    from version to version, and may be produced using randomization.\n\n    Args:\n        method: The method to use when synthesizing the circuit. Available values:\n            \"elimination\": Cancels off-diagonal terms using Gaussian elimination.\n                Gate set: H, S, CX\n                Circuit qubit count: n\n                Circuit operation count: O(n^2)\n                Circuit depth: O(n^2)\n            \"graph_state\": Prepares the tableau's state using a graph state circuit.\n                Gate set: RX, CZ, H, S, X, Y, Z\n                Circuit qubit count: n\n                Circuit operation count: O(n^2)\n\n                The circuit will be made up of three layers:\n                    1. An RX layer initializing all qubits.\n                    2. A CZ layer coupling the qubits.\n                        (Each CZ is an edge in the graph state.)\n                    3. A single qubit rotation layer.\n\n                Note: \"graph_state\" treats the tableau as a state instead of as a\n                Clifford operation. It will preserve the set of stabilizers, but\n                not the exact choice of generators.\n            \"mpp_state\": Prepares the tableau's state using MPP and feedback.\n                Gate set: MPP, CX rec, CY rec, CZ rec\n                Circuit qubit count: n\n                Circuit operation count: O(n^2)\n\n                The circuit will be made up of two layers:\n                    1. An MPP layer measuring each of the tableau's stabilizers.\n                    2. A feedback layer using the measurement results to control\n                        whether or not to apply each of the tableau's destabilizers\n                        in order to get the correct sign for each stabilizer.\n\n                Note: \"mpp_state\" treats the tableau as a state instead of as a\n                Clifford operation. It will preserve the set of stabilizers, but\n                not the exact choice of generators.\n            \"mpp_state_unsigned\": Prepares the tableau's state up to sign using MPP.\n                Gate set: MPP\n                Circuit qubit count: n\n                Circuit operation count: O(n^2)\n\n                The circuit will contain a series of MPP measurements measuring each\n                of the tableau's stabilizers. The stabilizers are measured in the\n                order used by the tableau (i.e. tableau.z_output(k) is the k'th\n                stabilizer measured).\n\n                Note: \"mpp_state_unsigned\" treats the tableau as a state instead of\n                as a Clifford operation. It will preserve the set of stabilizers,\n                but not the exact choice of generators.\n    Returns:\n        The synthesized circuit.\n\n    Example:\n        >>> import stim\n        >>> tableau = stim.Tableau.from_conjugated_generators(\n        ...     xs=[\n        ...         stim.PauliString(\"+YZ__\"),\n        ...         stim.PauliString(\"-Y_XY\"),\n        ...         stim.PauliString(\"+___Y\"),\n        ...         stim.PauliString(\"+YZX_\"),\n        ...     ],\n        ...     zs=[\n        ...         stim.PauliString(\"+XZYY\"),\n        ...         stim.PauliString(\"-XYX_\"),\n        ...         stim.PauliString(\"-ZXXZ\"),\n        ...         stim.PauliString(\"+XXZ_\"),\n        ...     ],\n        ... )\n\n        >>> tableau.to_circuit()\n        stim.Circuit('''\n            S 0\n            H 0 1 3\n            CX 0 1 0 2 0 3\n            S 1 3\n            H 1 3\n            CX 1 0 3 0 3 1 1 3 3 1\n            H 1\n            S 1\n            CX 1 3\n            H 2 3\n            CX 2 1 3 1 3 2 2 3 3 2\n            H 3\n            CX 2 3\n            S 3\n            H 3 0 1 2\n            S 0 0 1 1 2 2\n            H 0 1 2\n            S 3 3\n        ''')\n\n        >>> tableau.to_circuit(\"graph_state\")\n        stim.Circuit('''\n            RX 0 1 2 3\n            TICK\n            CZ 0 3 1 2 1 3\n            TICK\n            X 0 1\n            Z 2\n            S 2 3\n            H 3\n            S 3\n        ''')\n\n        >>> tableau.to_circuit(\"mpp_state_unsigned\")\n        stim.Circuit('''\n            MPP X0*Z1*Y2*Y3 !X0*Y1*X2 !Z0*X1*X2*Z3 X0*X1*Z2\n        ''')\n\n        >>> tableau.to_circuit(\"mpp_state\")\n        stim.Circuit('''\n            MPP X0*Z1*Y2*Y3 !X0*Y1*X2 !Z0*X1*X2*Z3 X0*X1*Z2\n            CX rec[-3] 2 rec[-1] 2\n            CY rec[-4] 0 rec[-3] 0 rec[-3] 3 rec[-2] 3 rec[-1] 0\n            CZ rec[-4] 1 rec[-1] 1\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.to_numpy\"></a>\n```python\n# stim.Tableau.to_numpy\n\n# (in class stim.Tableau)\ndef to_numpy(\n    self,\n    *,\n    bit_packed: bool = False,\n) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:\n    \"\"\"Decomposes the contents of the tableau into six numpy arrays.\n\n    The first four numpy arrays correspond to the four quadrants of the table\n    defined in Aaronson and Gottesman's \"Improved Simulation of Stabilizer Circuits\"\n    ( https://arxiv.org/abs/quant-ph/0406196 ).\n\n    The last two numpy arrays are the X and Z sign bit vectors of the tableau.\n\n    Args:\n        bit_packed: Defaults to False. Determines whether the output numpy arrays\n            use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n    Returns:\n        An (x2x, x2z, z2x, z2z, x_signs, z_signs) tuple encoding the tableau.\n\n        x2x: A 2d table of whether tableau(X_i)_j is X or Y (instead of I or Z).\n        x2z: A 2d table of whether tableau(X_i)_j is Z or Y (instead of I or X).\n        z2x: A 2d table of whether tableau(Z_i)_j is X or Y (instead of I or Z).\n        z2z: A 2d table of whether tableau(Z_i)_j is Z or Y (instead of I or X).\n        x_signs: A vector of whether tableau(X_i) is negative.\n        z_signs: A vector of whether tableau(Z_i) is negative.\n\n        If bit_packed=False then:\n            x2x.dtype = np.bool_\n            x2z.dtype = np.bool_\n            z2x.dtype = np.bool_\n            z2z.dtype = np.bool_\n            x_signs.dtype = np.bool_\n            z_signs.dtype = np.bool_\n            x2x.shape = (len(tableau), len(tableau))\n            x2z.shape = (len(tableau), len(tableau))\n            z2x.shape = (len(tableau), len(tableau))\n            z2z.shape = (len(tableau), len(tableau))\n            x_signs.shape = len(tableau)\n            z_signs.shape = len(tableau)\n            x2x[i, j] = tableau.x_output_pauli(i, j) in [1, 2]\n            x2z[i, j] = tableau.x_output_pauli(i, j) in [2, 3]\n            z2x[i, j] = tableau.z_output_pauli(i, j) in [1, 2]\n            z2z[i, j] = tableau.z_output_pauli(i, j) in [2, 3]\n\n        If bit_packed=True then:\n            x2x.dtype = np.uint8\n            x2z.dtype = np.uint8\n            z2x.dtype = np.uint8\n            z2z.dtype = np.uint8\n            x_signs.dtype = np.uint8\n            z_signs.dtype = np.uint8\n            x2x.shape = (len(tableau), math.ceil(len(tableau) / 8))\n            x2z.shape = (len(tableau), math.ceil(len(tableau) / 8))\n            z2x.shape = (len(tableau), math.ceil(len(tableau) / 8))\n            z2z.shape = (len(tableau), math.ceil(len(tableau) / 8))\n            x_signs.shape = math.ceil(len(tableau) / 8)\n            z_signs.shape = math.ceil(len(tableau) / 8)\n            (x2x[i, j // 8] >> (j % 8)) & 1 = tableau.x_output_pauli(i, j) in [1, 2]\n            (x2z[i, j // 8] >> (j % 8)) & 1 = tableau.x_output_pauli(i, j) in [2, 3]\n            (z2x[i, j // 8] >> (j % 8)) & 1 = tableau.z_output_pauli(i, j) in [1, 2]\n            (z2z[i, j // 8] >> (j % 8)) & 1 = tableau.z_output_pauli(i, j) in [2, 3]\n\n    Examples:\n        >>> import stim\n        >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n        >>> print(repr(cnot))\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+XX\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+Z_\"),\n                stim.PauliString(\"+ZZ\"),\n            ],\n        )\n        >>> x2x, x2z, z2x, z2z, x_signs, z_signs = cnot.to_numpy()\n        >>> x2x\n        array([[ True,  True],\n               [False,  True]])\n        >>> x2z\n        array([[False, False],\n               [False, False]])\n        >>> z2x\n        array([[False, False],\n               [False, False]])\n        >>> z2z\n        array([[ True, False],\n               [ True,  True]])\n        >>> x_signs\n        array([False, False])\n        >>> z_signs\n        array([False, False])\n\n        >>> t = stim.Tableau.from_conjugated_generators(\n        ...     xs=[\n        ...         stim.PauliString(\"-Y_ZY\"),\n        ...         stim.PauliString(\"-Y_YZ\"),\n        ...         stim.PauliString(\"-XXX_\"),\n        ...         stim.PauliString(\"+ZYX_\"),\n        ...     ],\n        ...     zs=[\n        ...         stim.PauliString(\"-_ZZX\"),\n        ...         stim.PauliString(\"+YZXZ\"),\n        ...         stim.PauliString(\"+XZ_X\"),\n        ...         stim.PauliString(\"-YYXX\"),\n        ...     ],\n        ... )\n\n        >>> x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy()\n        >>> x2x\n        array([[ True, False, False,  True],\n               [ True, False,  True, False],\n               [ True,  True,  True, False],\n               [False,  True,  True, False]])\n        >>> x2z\n        array([[ True, False,  True,  True],\n               [ True, False,  True,  True],\n               [False, False, False, False],\n               [ True,  True, False, False]])\n        >>> z2x\n        array([[False, False, False,  True],\n               [ True, False,  True, False],\n               [ True, False, False,  True],\n               [ True,  True,  True,  True]])\n        >>> z2z\n        array([[False,  True,  True, False],\n               [ True,  True, False,  True],\n               [False,  True, False, False],\n               [ True,  True, False, False]])\n        >>> x_signs\n        array([ True,  True,  True, False])\n        >>> z_signs\n        array([ True, False, False,  True])\n\n        >>> x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy(bit_packed=True)\n        >>> x2x\n        array([[9],\n               [5],\n               [7],\n               [6]], dtype=uint8)\n        >>> x2z\n        array([[13],\n               [13],\n               [ 0],\n               [ 3]], dtype=uint8)\n        >>> z2x\n        array([[ 8],\n               [ 5],\n               [ 9],\n               [15]], dtype=uint8)\n        >>> z2z\n        array([[ 6],\n               [11],\n               [ 2],\n               [ 3]], dtype=uint8)\n        >>> x_signs\n        array([7], dtype=uint8)\n        >>> z_signs\n        array([9], dtype=uint8)\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.to_pauli_string\"></a>\n```python\n# stim.Tableau.to_pauli_string\n\n# (in class stim.Tableau)\ndef to_pauli_string(\n    self,\n) -> stim.PauliString:\n    \"\"\"Return a Pauli string equivalent to the tableau.\n\n    If the tableau is equivalent to a pauli product, creates\n    an equivalent pauli string. If not, then an error is raised.\n\n    Returns:\n        The created pauli string\n\n    Raises:\n        ValueError: The Tableau isn't equivalent to a Pauli product.\n\n    Example:\n        >>> import stim\n        >>> t = (stim.Tableau.from_named_gate(\"Z\") +\n        ...      stim.Tableau.from_named_gate(\"Y\") +\n        ...      stim.Tableau.from_named_gate(\"I\") +\n        ...      stim.Tableau.from_named_gate(\"X\"))\n        >>> print(t)\n        +-xz-xz-xz-xz-\n        | -+ -- ++ +-\n        | XZ __ __ __\n        | __ XZ __ __\n        | __ __ XZ __\n        | __ __ __ XZ\n        >>> print(t.to_pauli_string())\n        +ZY_X\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.to_stabilizers\"></a>\n```python\n# stim.Tableau.to_stabilizers\n\n# (in class stim.Tableau)\ndef to_stabilizers(\n    self,\n    *,\n    canonicalize: bool = False,\n) -> List[stim.PauliString]:\n    \"\"\"Returns the stabilizer generators of the tableau, optionally canonicalized.\n\n    The stabilizer generators of the tableau are its Z outputs. Canonicalizing\n    standardizes the generators, so that states that are equal will produce the\n    same generators. For example, [ZI, IZ], [ZI, ZZ], amd [ZZ, ZI] describe equal\n    states and all canonicalize to [ZI, IZ].\n\n    The canonical form is computed as follows:\n\n        1. Get a list of stabilizers using `tableau.z_output(k)` for each k.\n        2. Perform Gaussian elimination. pivoting on standard generators.\n            2a) Pivot on g=X0 first, then Z0, X1, Z1, X2, Z2, etc.\n            2b) Find a stabilizer that uses the generator g. If there are none,\n                go to the next g.\n            2c) Multiply that stabilizer into all other stabilizers that use the\n                generator g.\n            2d) Swap that stabilizer with the stabilizer at position `r` then\n                increment `r`. `r` starts at 0.\n\n    Args:\n        canonicalize: Defaults to False. When False, the tableau's Z outputs\n            are returned unchanged. When True, the Z outputs are rewritten\n            into a standard form. Two stabilizer states have the same standard\n            form if and only if they describe equivalent quantum states.\n\n    Returns:\n        A List[stim.PauliString] of the tableau's stabilizer generators.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n\n        >>> raw_stabilizers = t.to_stabilizers()\n        >>> for e in raw_stabilizers:\n        ...     print(repr(e))\n        stim.PauliString(\"+Z_\")\n        stim.PauliString(\"+ZZ\")\n\n        >>> canonical_stabilizers = t.to_stabilizers(canonicalize=True)\n        >>> for e in canonical_stabilizers:\n        ...     print(repr(e))\n        stim.PauliString(\"+Z_\")\n        stim.PauliString(\"+_Z\")\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.to_state_vector\"></a>\n```python\n# stim.Tableau.to_state_vector\n\n# (in class stim.Tableau)\ndef to_state_vector(\n    self,\n    *,\n    endian: Literal[\"little\", \"big\"] = 'little',\n) -> np.ndarray[np.complex64]:\n    \"\"\"Returns the state vector produced by applying the tableau to the |0..0> state.\n\n    This function takes O(n * 2**n) time and O(2**n) space, where n is the number of\n    qubits. The computation is done by initialization a random state vector and\n    iteratively projecting it into the +1 eigenspace of each stabilizer of the\n    state. The state is then canonicalized so that zero values are actually exactly\n    0, and so that the first non-zero entry is positive.\n\n    Args:\n        endian:\n            \"little\" (default): state vector is in little endian order, where higher\n                index qubits correspond to larger changes in the state index.\n            \"big\": state vector is in big endian order, where higher index qubits\n                correspond to smaller changes in the state index.\n\n    Returns:\n        A `numpy.ndarray[numpy.complex64]` of computational basis amplitudes.\n\n        If the result is in little endian order then the amplitude at offset\n        b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n        computational basis state where the qubit with index 0 is storing the bit\n        b_0, the qubit with index 1 is storing the bit b_1, etc.\n\n        If the result is in big endian order then the amplitude at offset\n        b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n        computational basis state where the qubit with index 0 is storing the bit\n        b_{n-1}, the qubit with index 1 is storing the bit b_{n-2}, etc.\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n        >>> i2 = stim.Tableau.from_named_gate('I')\n        >>> x = stim.Tableau.from_named_gate('X')\n        >>> h = stim.Tableau.from_named_gate('H')\n\n        >>> (x + i2).to_state_vector(endian='little')\n        array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)\n\n        >>> (i2 + x).to_state_vector(endian='little')\n        array([0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], dtype=complex64)\n\n        >>> (i2 + x).to_state_vector(endian='big')\n        array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)\n\n        >>> (h + h).to_state_vector(endian='little')\n        array([0.5+0.j, 0.5+0.j, 0.5+0.j, 0.5+0.j], dtype=complex64)\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.to_unitary_matrix\"></a>\n```python\n# stim.Tableau.to_unitary_matrix\n\n# (in class stim.Tableau)\ndef to_unitary_matrix(\n    self,\n    *,\n    endian: Literal[\"little\", \"big\"],\n) -> np.ndarray[np.complex64]:\n    \"\"\"Converts the tableau into a unitary matrix.\n\n    For an n-qubit tableau, this method performs O(n 4^n) work. It uses the state\n    channel duality to transform the tableau into a list of stabilizers, then\n    generates a random state vector and projects it into the +1 eigenspace of each\n    stabilizer.\n\n    Note that tableaus don't have a defined global phase, so the result's global\n    phase may be different from what you expect. For example, the square of\n    SQRT_X's unitary might equal -X instead of +X.\n\n    Args:\n        endian:\n            \"little\": The first qubit is the least significant (corresponds\n                to an offset of 1 in the state vector).\n            \"big\": The first qubit is the most significant (corresponds\n                to an offset of 2**(n - 1) in the state vector).\n\n    Returns:\n        A numpy array with dtype=np.complex64 and\n        shape=(1 << len(tableau), 1 << len(tableau)).\n\n    Example:\n        >>> import stim\n        >>> cnot = stim.Tableau.from_conjugated_generators(\n        ...     xs=[\n        ...         stim.PauliString(\"XX\"),\n        ...         stim.PauliString(\"_X\"),\n        ...     ],\n        ...     zs=[\n        ...         stim.PauliString(\"Z_\"),\n        ...         stim.PauliString(\"ZZ\"),\n        ...     ],\n        ... )\n        >>> cnot.to_unitary_matrix(endian='big')\n        array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n               [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\n               [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n               [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]], dtype=complex64)\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.x_output\"></a>\n```python\n# stim.Tableau.x_output\n\n# (in class stim.Tableau)\ndef x_output(\n    self,\n    target: int,\n) -> stim.PauliString:\n    \"\"\"Returns the result of conjugating a Pauli X by the tableau's Clifford operation.\n\n    Args:\n        target: The qubit targeted by the Pauli X operation.\n\n    Examples:\n        >>> import stim\n        >>> h = stim.Tableau.from_named_gate(\"H\")\n        >>> h.x_output(0)\n        stim.PauliString(\"+Z\")\n\n        >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n        >>> cnot.x_output(0)\n        stim.PauliString(\"+XX\")\n        >>> cnot.x_output(1)\n        stim.PauliString(\"+_X\")\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.x_output_pauli\"></a>\n```python\n# stim.Tableau.x_output_pauli\n\n# (in class stim.Tableau)\ndef x_output_pauli(\n    self,\n    input_index: int,\n    output_index: int,\n) -> int:\n    \"\"\"Constant-time version of `tableau.x_output(input_index)[output_index]`\n\n    Args:\n        input_index: Identifies the tableau column (the qubit of the input X\n            generator).\n        output_index: Identifies the tableau row (the output qubit).\n\n    Returns:\n        An integer identifying Pauli at the given location in the tableau:\n\n            0: I\n            1: X\n            2: Y\n            3: Z\n\n    Examples:\n        >>> import stim\n\n        >>> t = stim.Tableau.from_conjugated_generators(\n        ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n        ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n        ... )\n        >>> t.x_output_pauli(0, 0)\n        2\n        >>> t.x_output_pauli(0, 1)\n        0\n        >>> t.x_output_pauli(1, 0)\n        2\n        >>> t.x_output_pauli(1, 1)\n        3\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.x_sign\"></a>\n```python\n# stim.Tableau.x_sign\n\n# (in class stim.Tableau)\ndef x_sign(\n    self,\n    target: int,\n) -> int:\n    \"\"\"Returns just the sign of the result of conjugating an X generator.\n\n    This operation runs in constant time.\n\n    Args:\n        target: The qubit the X generator applies to.\n\n    Examples:\n        >>> import stim\n        >>> stim.Tableau.from_named_gate(\"S_DAG\").x_sign(0)\n        -1\n        >>> stim.Tableau.from_named_gate(\"S\").x_sign(0)\n        1\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.y_output\"></a>\n```python\n# stim.Tableau.y_output\n\n# (in class stim.Tableau)\ndef y_output(\n    self,\n    target: int,\n) -> stim.PauliString:\n    \"\"\"Returns the result of conjugating a Pauli Y by the tableau's Clifford operation.\n\n    Args:\n        target: The qubit targeted by the Pauli Y operation.\n\n    Examples:\n        >>> import stim\n        >>> h = stim.Tableau.from_named_gate(\"H\")\n        >>> h.y_output(0)\n        stim.PauliString(\"-Y\")\n\n        >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n        >>> cnot.y_output(0)\n        stim.PauliString(\"+YX\")\n        >>> cnot.y_output(1)\n        stim.PauliString(\"+ZY\")\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.y_output_pauli\"></a>\n```python\n# stim.Tableau.y_output_pauli\n\n# (in class stim.Tableau)\ndef y_output_pauli(\n    self,\n    input_index: int,\n    output_index: int,\n) -> int:\n    \"\"\"Constant-time version of `tableau.y_output(input_index)[output_index]`\n\n    Args:\n        input_index: Identifies the tableau column (the qubit of the input Y\n            generator).\n        output_index: Identifies the tableau row (the output qubit).\n\n    Returns:\n        An integer identifying Pauli at the given location in the tableau:\n\n            0: I\n            1: X\n            2: Y\n            3: Z\n\n    Examples:\n        >>> import stim\n\n        >>> t = stim.Tableau.from_conjugated_generators(\n        ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n        ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n        ... )\n        >>> t.y_output_pauli(0, 0)\n        1\n        >>> t.y_output_pauli(0, 1)\n        2\n        >>> t.y_output_pauli(1, 0)\n        0\n        >>> t.y_output_pauli(1, 1)\n        2\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.y_sign\"></a>\n```python\n# stim.Tableau.y_sign\n\n# (in class stim.Tableau)\ndef y_sign(\n    self,\n    target: int,\n) -> int:\n    \"\"\"Returns just the sign of the result of conjugating a Y generator.\n\n    Unlike x_sign and z_sign, this operation runs in linear time.\n    The Y generator has to be computed by multiplying the X and Z\n    outputs and the sign depends on all terms.\n\n    Args:\n        target: The qubit the Y generator applies to.\n\n    Examples:\n        >>> import stim\n        >>> stim.Tableau.from_named_gate(\"S_DAG\").y_sign(0)\n        1\n        >>> stim.Tableau.from_named_gate(\"S\").y_sign(0)\n        -1\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.z_output\"></a>\n```python\n# stim.Tableau.z_output\n\n# (in class stim.Tableau)\ndef z_output(\n    self,\n    target: int,\n) -> stim.PauliString:\n    \"\"\"Returns the result of conjugating a Pauli Z by the tableau's Clifford operation.\n\n    Args:\n        target: The qubit targeted by the Pauli Z operation.\n\n    Examples:\n        >>> import stim\n        >>> h = stim.Tableau.from_named_gate(\"H\")\n        >>> h.z_output(0)\n        stim.PauliString(\"+X\")\n\n        >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n        >>> cnot.z_output(0)\n        stim.PauliString(\"+Z_\")\n        >>> cnot.z_output(1)\n        stim.PauliString(\"+ZZ\")\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.z_output_pauli\"></a>\n```python\n# stim.Tableau.z_output_pauli\n\n# (in class stim.Tableau)\ndef z_output_pauli(\n    self,\n    input_index: int,\n    output_index: int,\n) -> int:\n    \"\"\"Constant-time version of `tableau.z_output(input_index)[output_index]`\n\n    Args:\n        input_index: Identifies the tableau column (the qubit of the input Z\n            generator).\n        output_index: Identifies the tableau row (the output qubit).\n\n    Returns:\n        An integer identifying Pauli at the given location in the tableau:\n\n            0: I\n            1: X\n            2: Y\n            3: Z\n\n    Examples:\n        >>> import stim\n\n        >>> t = stim.Tableau.from_conjugated_generators(\n        ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n        ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n        ... )\n        >>> t.z_output_pauli(0, 0)\n        3\n        >>> t.z_output_pauli(0, 1)\n        2\n        >>> t.z_output_pauli(1, 0)\n        2\n        >>> t.z_output_pauli(1, 1)\n        1\n    \"\"\"\n```\n\n<a name=\"stim.Tableau.z_sign\"></a>\n```python\n# stim.Tableau.z_sign\n\n# (in class stim.Tableau)\ndef z_sign(\n    self,\n    target: int,\n) -> int:\n    \"\"\"Returns just the sign of the result of conjugating a Z generator.\n\n    This operation runs in constant time.\n\n    Args:\n        target: The qubit the Z generator applies to.\n\n    Examples:\n        >>> import stim\n        >>> stim.Tableau.from_named_gate(\"SQRT_X_DAG\").z_sign(0)\n        1\n        >>> stim.Tableau.from_named_gate(\"SQRT_X\").z_sign(0)\n        -1\n    \"\"\"\n```\n\n<a name=\"stim.TableauIterator\"></a>\n```python\n# stim.TableauIterator\n\n# (at top-level in the stim module)\nclass TableauIterator:\n    \"\"\"Iterates over all stabilizer tableaus of a specified size.\n\n    Examples:\n        >>> import stim\n        >>> tableau_iterator = stim.Tableau.iter_all(1)\n        >>> n = 0\n        >>> for single_qubit_clifford in tableau_iterator:\n        ...     n += 1\n        >>> n\n        24\n    \"\"\"\n```\n\n<a name=\"stim.TableauIterator.__iter__\"></a>\n```python\n# stim.TableauIterator.__iter__\n\n# (in class stim.TableauIterator)\ndef __iter__(\n    self,\n) -> stim.TableauIterator:\n    \"\"\"Returns an independent copy of the tableau iterator.\n\n    Since for-loops and loop-comprehensions call `iter` on things they\n    iterate, this effectively allows the iterator to be iterated\n    multiple times.\n    \"\"\"\n```\n\n<a name=\"stim.TableauIterator.__next__\"></a>\n```python\n# stim.TableauIterator.__next__\n\n# (in class stim.TableauIterator)\ndef __next__(\n    self,\n) -> stim.Tableau:\n    \"\"\"Returns the next iterated tableau.\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator\"></a>\n```python\n# stim.TableauSimulator\n\n# (at top-level in the stim module)\nclass TableauSimulator:\n    \"\"\"A stabilizer circuit simulator that tracks an inverse stabilizer tableau.\n\n    Supports interactive usage, where gates and measurements are applied on demand.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> if s.measure(0):\n        ...     s.h(1)\n        ...     s.cnot(1, 2)\n        >>> s.measure(1) == s.measure(2)\n        True\n\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> s.cnot(0, 1)\n        >>> s.current_inverse_tableau()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+ZX\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X_\"),\n                stim.PauliString(\"+XZ\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.__init__\"></a>\n```python\n# stim.TableauSimulator.__init__\n\n# (in class stim.TableauSimulator)\ndef __init__(\n    self,\n    *,\n    seed: Optional[int] = None,\n) -> None:\n    \"\"\"Initializes a stim.TableauSimulator.\n\n    Args:\n        seed: PARTIALLY determines simulation results by deterministically seeding\n            the random number generator.\n\n            Must be None or an integer in range(2**64).\n\n            Defaults to None. When None, the prng is seeded from system entropy.\n\n            When set to an integer, making the exact same series calls on the exact\n            same machine with the exact same version of Stim will produce the exact\n            same simulation results.\n\n            CAUTION: simulation results *WILL NOT* be consistent between versions of\n            Stim. This restriction is present to make it possible to have future\n            optimizations to the random sampling, and is enforced by introducing\n            intentional differences in the seeding strategy from version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines that\n            differ in the width of supported SIMD instructions. For example, using\n            the same seed on a machine that supports AVX instructions and one that\n            only supports SSE instructions may produce different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n            circuit is executed. For example, reordering whether a reset on one\n            qubit happens before or after a reset on another qubit can result in\n            different measurement results being observed starting from the same\n            seed.\n\n    Returns:\n        An initialized stim.TableauSimulator.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator(seed=0)\n        >>> s2 = stim.TableauSimulator(seed=0)\n        >>> s.h(0)\n        >>> s2.h(0)\n        >>> s.measure(0) == s2.measure(0)\n        True\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.c_xyz\"></a>\n```python\n# stim.TableauSimulator.c_xyz\n\n# (in class stim.TableauSimulator)\ndef c_xyz(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a C_XYZ gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.c_xyz(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +Y +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.c_zyx\"></a>\n```python\n# stim.TableauSimulator.c_zyx\n\n# (in class stim.TableauSimulator)\ndef c_zyx(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a C_ZYX gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.c_zyx(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +Z +X +Y\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.canonical_stabilizers\"></a>\n```python\n# stim.TableauSimulator.canonical_stabilizers\n\n# (in class stim.TableauSimulator)\ndef canonical_stabilizers(\n    self,\n) -> List[stim.PauliString]:\n    \"\"\"Returns a standardized list of the simulator's current stabilizer generators.\n\n    Two simulators have the same canonical stabilizers if and only if their current\n    quantum state is equal (and tracking the same number of qubits).\n\n    The canonical form is computed as follows:\n\n        1. Get a list of stabilizers using the `z_output`s of\n            `simulator.current_inverse_tableau()**-1`.\n        2. Perform Gaussian elimination on each generator g.\n            2a) The generators are considered in order X0, Z0, X1, Z1, X2, Z2, etc.\n            2b) Pick any stabilizer that uses the generator g. If there are none,\n                go to the next g.\n            2c) Multiply that stabilizer into all other stabilizers that use the\n                generator g.\n            2d) Swap that stabilizer with the stabilizer at position `next_output`\n                then increment `next_output`.\n\n    Returns:\n        A List[stim.PauliString] of the simulator's state's stabilizers.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> s.cnot(0, 1)\n        >>> s.x(2)\n        >>> for e in s.canonical_stabilizers():\n        ...     print(repr(e))\n        stim.PauliString(\"+XX_\")\n        stim.PauliString(\"+ZZ_\")\n        stim.PauliString(\"-__Z\")\n\n        >>> # Scramble the stabilizers then check the canonical form is unchanged.\n        >>> s.set_inverse_tableau(s.current_inverse_tableau()**-1)\n        >>> s.cnot(0, 1)\n        >>> s.cz(0, 2)\n        >>> s.s(0, 2)\n        >>> s.cy(2, 1)\n        >>> s.set_inverse_tableau(s.current_inverse_tableau()**-1)\n        >>> for e in s.canonical_stabilizers():\n        ...     print(repr(e))\n        stim.PauliString(\"+XX_\")\n        stim.PauliString(\"+ZZ_\")\n        stim.PauliString(\"-__Z\")\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.cnot\"></a>\n```python\n# stim.TableauSimulator.cnot\n\n# (in class stim.TableauSimulator)\ndef cnot(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a controlled X gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.cnot(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +_ +_ +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.copy\"></a>\n```python\n# stim.TableauSimulator.copy\n\n# (in class stim.TableauSimulator)\ndef copy(\n    self,\n    *,\n    copy_rng: bool = False,\n    seed: Optional[int] = None,\n) -> stim.TableauSimulator:\n    \"\"\"Returns a simulator with the same internal state, except perhaps its prng.\n\n    Args:\n        copy_rng: By default, new simulator's prng is reinitialized with a random\n            seed. However, one can set this argument to True in order to have the\n            prng state copied together with the rest of the original simulator's\n            state. Consequently, in this case the two simulators will produce the\n            same measurement outcomes for the same quantum circuits.  If both seed\n            and copy_rng are set, an exception is raised. Defaults to False.\n        seed: PARTIALLY determines simulation results by deterministically seeding\n            the random number generator.\n\n            Must be None or an integer in range(2**64).\n\n            Defaults to None. When None, the prng state is either copied from the\n            original simulator or reseeded from system entropy, depending on the\n            copy_rng argument.\n\n            When set to an integer, making the exact same series calls on the exact\n            same machine with the exact same version of Stim will produce the exact\n            same simulation results.\n\n            CAUTION: simulation results *WILL NOT* be consistent between versions of\n            Stim. This restriction is present to make it possible to have future\n            optimizations to the random sampling, and is enforced by introducing\n            intentional differences in the seeding strategy from version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines that\n            differ in the width of supported SIMD instructions. For example, using\n            the same seed on a machine that supports AVX instructions and one that\n            only supports SSE instructions may produce different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n            circuit is executed. For example, reordering whether a reset on one\n            qubit happens before or after a reset on another qubit can result in\n            different measurement results being observed starting from the same\n            seed.\n\n    Examples:\n        >>> import stim\n\n        >>> s1 = stim.TableauSimulator()\n        >>> s1.set_inverse_tableau(stim.Tableau.random(1))\n        >>> s2 = s1.copy()\n        >>> s2 is s1\n        False\n        >>> s2.current_inverse_tableau() == s1.current_inverse_tableau()\n        True\n\n        >>> s1 = stim.TableauSimulator()\n        >>> s2 = s1.copy(copy_rng=True)\n        >>> s1.h(0)\n        >>> s2.h(0)\n        >>> assert s1.measure(0) == s2.measure(0)\n\n        >>> s = stim.TableauSimulator()\n        >>> def brute_force_post_select(qubit, desired_result):\n        ...     global s\n        ...     while True:\n        ...         s2 = s.copy()\n        ...         if s2.measure(qubit) == desired_result:\n        ...             s = s2\n        ...             break\n        >>> s.h(0)\n        >>> brute_force_post_select(qubit=0, desired_result=True)\n        >>> s.measure(0)\n        True\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.current_inverse_tableau\"></a>\n```python\n# stim.TableauSimulator.current_inverse_tableau\n\n# (in class stim.TableauSimulator)\ndef current_inverse_tableau(\n    self,\n) -> stim.Tableau:\n    \"\"\"Returns a copy of the internal state of the simulator as a stim.Tableau.\n\n    Returns:\n        A stim.Tableau copy of the simulator's state.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> s.current_inverse_tableau()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X\"),\n            ],\n        )\n        >>> s.cnot(0, 1)\n        >>> s.current_inverse_tableau()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+ZX\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X_\"),\n                stim.PauliString(\"+XZ\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.current_measurement_record\"></a>\n```python\n# stim.TableauSimulator.current_measurement_record\n\n# (in class stim.TableauSimulator)\ndef current_measurement_record(\n    self,\n) -> List[bool]:\n    \"\"\"Returns a copy of the record of all measurements performed by the simulator.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.current_measurement_record()\n        []\n        >>> s.measure(0)\n        False\n        >>> s.x(0)\n        >>> s.measure(0)\n        True\n        >>> s.current_measurement_record()\n        [False, True]\n        >>> s.do(stim.Circuit(\"M 0\"))\n        >>> s.current_measurement_record()\n        [False, True, True]\n\n    Returns:\n        A list of booleans containing the result of every measurement performed by\n        the simulator so far.\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.cx\"></a>\n```python\n# stim.TableauSimulator.cx\n\n# (in class stim.TableauSimulator)\ndef cx(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a controlled X gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.cx(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +_ +_ +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.cy\"></a>\n```python\n# stim.TableauSimulator.cy\n\n# (in class stim.TableauSimulator)\ndef cy(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a controlled Y gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.cy(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.cz\"></a>\n```python\n# stim.TableauSimulator.cz\n\n# (in class stim.TableauSimulator)\ndef cz(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a controlled Z gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.cz(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +_ +_ +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.depolarize1\"></a>\n```python\n# stim.TableauSimulator.depolarize1\n\n# (in class stim.TableauSimulator)\ndef depolarize1(\n    self,\n    *targets: int,\n    p: float,\n):\n    \"\"\"Probabilistically applies single-qubit depolarization to targets.\n\n    Args:\n        *targets: The indices of the qubits to target with the noise.\n        p: The chance of the error being applied,\n            independently, to each qubit.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.depolarize1(0, 1, 2, p=0.01)\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.depolarize2\"></a>\n```python\n# stim.TableauSimulator.depolarize2\n\n# (in class stim.TableauSimulator)\ndef depolarize2(\n    self,\n    *targets: int,\n    p: float,\n):\n    \"\"\"Probabilistically applies two-qubit depolarization to targets.\n\n    Args:\n        *targets: The indices of the qubits to target with the noise.\n            The pairs of qubits are formed by\n            zip(targets[::1], targets[1::2]).\n        p: The chance of the error being applied,\n            independently, to each qubit pair.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.depolarize1(0, 1, 4, 5, p=0.01)\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.do\"></a>\n```python\n# stim.TableauSimulator.do\n\n# (in class stim.TableauSimulator)\ndef do(\n    self,\n    circuit_or_pauli_string: Union[stim.Circuit, stim.PauliString, stim.CircuitInstruction, stim.CircuitRepeatBlock],\n) -> None:\n    \"\"\"Applies a circuit or pauli string to the simulator's state.\n\n    Args:\n        circuit_or_pauli_string: A stim.Circuit, stim.PauliString,\n            stim.CircuitInstruction, or stim.CircuitRepeatBlock\n            with operations to apply to the simulator's state.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.do(stim.Circuit('''\n        ...     X 0\n        ...     M 0\n        ... '''))\n        >>> s.current_measurement_record()\n        [True]\n\n        >>> s = stim.TableauSimulator()\n        >>> s.do(stim.PauliString(\"IXYZ\"))\n        >>> s.measure_many(0, 1, 2, 3)\n        [False, True, True, False]\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.do_circuit\"></a>\n```python\n# stim.TableauSimulator.do_circuit\n\n# (in class stim.TableauSimulator)\ndef do_circuit(\n    self,\n    circuit: stim.Circuit,\n) -> None:\n    \"\"\"Applies a circuit to the simulator's state.\n\n    Args:\n        circuit: A stim.Circuit containing operations to apply.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.do_circuit(stim.Circuit('''\n        ...     X 0\n        ...     M 0\n        ... '''))\n        >>> s.current_measurement_record()\n        [True]\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.do_pauli_string\"></a>\n```python\n# stim.TableauSimulator.do_pauli_string\n\n# (in class stim.TableauSimulator)\ndef do_pauli_string(\n    self,\n    pauli_string: stim.PauliString,\n) -> None:\n    \"\"\"Applies the paulis from a pauli string to the simulator's state.\n\n    Args:\n        pauli_string: A stim.PauliString containing Paulis to apply.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.do_pauli_string(stim.PauliString(\"IXYZ\"))\n        >>> s.measure_many(0, 1, 2, 3)\n        [False, True, True, False]\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.do_tableau\"></a>\n```python\n# stim.TableauSimulator.do_tableau\n\n# (in class stim.TableauSimulator)\ndef do_tableau(\n    self,\n    tableau: stim.Tableau,\n    targets: List[int],\n) -> None:\n    \"\"\"Applies a custom tableau operation to qubits in the simulator.\n\n    Note that this method has to compute the inverse of the tableau, because the\n    simulator's internal state is an inverse tableau.\n\n    Args:\n        tableau: A stim.Tableau representing the Clifford operation to apply.\n        targets: The indices of the qubits to operate on.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.TableauSimulator()\n        >>> sim.h(1)\n        >>> sim.h_yz(2)\n        >>> [str(sim.peek_bloch(k)) for k in range(4)]\n        ['+Z', '+X', '+Y', '+Z']\n        >>> rot3 = stim.Tableau.from_conjugated_generators(\n        ...     xs=[\n        ...         stim.PauliString(\"_X_\"),\n        ...         stim.PauliString(\"__X\"),\n        ...         stim.PauliString(\"X__\"),\n        ...     ],\n        ...     zs=[\n        ...         stim.PauliString(\"_Z_\"),\n        ...         stim.PauliString(\"__Z\"),\n        ...         stim.PauliString(\"Z__\"),\n        ...     ],\n        ... )\n\n        >>> sim.do_tableau(rot3, [1, 2, 3])\n        >>> [str(sim.peek_bloch(k)) for k in range(4)]\n        ['+Z', '+Z', '+X', '+Y']\n\n        >>> sim.do_tableau(rot3, [1, 2, 3])\n        >>> [str(sim.peek_bloch(k)) for k in range(4)]\n        ['+Z', '+Y', '+Z', '+X']\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.h\"></a>\n```python\n# stim.TableauSimulator.h\n\n# (in class stim.TableauSimulator)\ndef h(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a Hadamard gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.h(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +Z -Y +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.h_xy\"></a>\n```python\n# stim.TableauSimulator.h_xy\n\n# (in class stim.TableauSimulator)\ndef h_xy(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies an operation that swaps the X and Y axes to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.h_xy(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +Y +X -Z\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.h_xz\"></a>\n```python\n# stim.TableauSimulator.h_xz\n\n# (in class stim.TableauSimulator)\ndef h_xz(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a Hadamard gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.h_xz(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +Z -Y +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.h_yz\"></a>\n```python\n# stim.TableauSimulator.h_yz\n\n# (in class stim.TableauSimulator)\ndef h_yz(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies an operation that swaps the Y and Z axes to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.h_yz(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        -X +Z +Y\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.iswap\"></a>\n```python\n# stim.TableauSimulator.iswap\n\n# (in class stim.TableauSimulator)\ndef iswap(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies an ISWAP gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.iswap(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +_ +_ +Y +Z\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.iswap_dag\"></a>\n```python\n# stim.TableauSimulator.iswap_dag\n\n# (in class stim.TableauSimulator)\ndef iswap_dag(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies an ISWAP_DAG gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.iswap_dag(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +_ +_ -Y +Z\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.measure\"></a>\n```python\n# stim.TableauSimulator.measure\n\n# (in class stim.TableauSimulator)\ndef measure(\n    self,\n    target: int,\n) -> bool:\n    \"\"\"Measures a single qubit.\n\n    Unlike the other methods on TableauSimulator, this one does not broadcast\n    over multiple targets. This is to avoid returning a list, which would\n    create a pitfall where typing `if sim.measure(qubit)` would be a bug.\n\n    To measure multiple qubits, use `TableauSimulator.measure_many`.\n\n    Args:\n        target: The index of the qubit to measure.\n\n    Returns:\n        The measurement result as a bool.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.x(1)\n        >>> s.measure(0)\n        False\n        >>> s.measure(1)\n        True\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.measure_kickback\"></a>\n```python\n# stim.TableauSimulator.measure_kickback\n\n# (in class stim.TableauSimulator)\ndef measure_kickback(\n    self,\n    target: int,\n) -> tuple:\n    \"\"\"Measures a qubit and returns the result as well as its Pauli kickback (if any).\n\n    The \"Pauli kickback\" of a stabilizer circuit measurement is a set of Pauli\n    operations that flip the post-measurement system state between the two possible\n    post-measurement states. For example, consider measuring one of the qubits in\n    the state |00>+|11> in the Z basis. If the measurement result is False, then the\n    system projects into the state |00>. If the measurement result is True, then the\n    system projects into the state |11>. Applying a Pauli X operation to both qubits\n    flips between |00> and |11>. Therefore the Pauli kickback of the measurement is\n    `stim.PauliString(\"XX\")`. Note that there are often many possible equivalent\n    Pauli kickbacks. For example, if in the previous example there was a third qubit\n    in the |0> state, then both `stim.PauliString(\"XX_\")` and\n    `stim.PauliString(\"XXZ\")` are valid kickbacks.\n\n    Measurements with deterministic results don't have a Pauli kickback.\n\n    Args:\n        target: The index of the qubit to measure.\n\n    Returns:\n        A (result, kickback) tuple.\n        The result is a bool containing the measurement's output.\n        The kickback is either None (meaning the measurement was deterministic) or a\n        stim.PauliString (meaning the measurement was random, and the operations in\n        the Pauli string flip between the two possible post-measurement states).\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n\n        >>> s.measure_kickback(0)\n        (False, None)\n\n        >>> s.h(0)\n        >>> s.measure_kickback(0)[1]\n        stim.PauliString(\"+X\")\n\n        >>> def pseudo_post_select(qubit, desired_result):\n        ...     m, kick = s.measure_kickback(qubit)\n        ...     if m != desired_result:\n        ...         if kick is None:\n        ...             raise ValueError(\"Post-selected the impossible!\")\n        ...         s.do(kick)\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> s.cnot(0, 1)\n        >>> s.cnot(0, 2)\n        >>> pseudo_post_select(qubit=2, desired_result=True)\n        >>> s.measure_many(0, 1, 2)\n        [True, True, True]\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.measure_many\"></a>\n```python\n# stim.TableauSimulator.measure_many\n\n# (in class stim.TableauSimulator)\ndef measure_many(\n    self,\n    *targets,\n) -> List[bool]:\n    \"\"\"Measures multiple qubits.\n\n    Args:\n        *targets: The indices of the qubits to measure.\n\n    Returns:\n        The measurement results as a list of bools.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.x(1)\n        >>> s.measure_many(0, 1)\n        [False, True]\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.measure_observable\"></a>\n```python\n# stim.TableauSimulator.measure_observable\n\n# (in class stim.TableauSimulator)\ndef measure_observable(\n    self,\n    observable: stim.PauliString,\n    *,\n    flip_probability: float = 0.0,\n) -> bool:\n    \"\"\"Measures an pauli string observable, as if by an MPP instruction.\n\n    Args:\n        observable: The observable to measure, specified as a stim.PauliString.\n        flip_probability: Probability of the recorded measurement result being\n            flipped.\n\n    Returns:\n        The result of the measurement.\n\n        The result is also recorded into the measurement record.\n\n    Raises:\n        ValueError: The given pauli string isn't Hermitian, or the given probability\n            isn't a valid probability.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> s.cnot(0, 1)\n\n        >>> s.measure_observable(stim.PauliString(\"XX\"))\n        False\n\n        >>> s.measure_observable(stim.PauliString(\"YY\"))\n        True\n\n        >>> s.measure_observable(stim.PauliString(\"-ZZ\"))\n        True\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.num_qubits\"></a>\n```python\n# stim.TableauSimulator.num_qubits\n\n# (in class stim.TableauSimulator)\n@property\ndef num_qubits(\n    self,\n) -> int:\n    \"\"\"Returns the number of qubits currently being tracked by the simulator.\n\n    Note that the number of qubits being tracked will implicitly increase if qubits\n    beyond the current limit are touched. Untracked qubits are always assumed to be\n    in the |0> state.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.num_qubits\n        0\n        >>> s.h(2)\n        >>> s.num_qubits\n        3\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.peek_bloch\"></a>\n```python\n# stim.TableauSimulator.peek_bloch\n\n# (in class stim.TableauSimulator)\ndef peek_bloch(\n    self,\n    target: int,\n) -> stim.PauliString:\n    \"\"\"Returns the state of the qubit as a single-qubit stim.PauliString stabilizer.\n\n    This is a non-physical operation. It reports information about the qubit without\n    disturbing it.\n\n    Args:\n        target: The qubit to peek at.\n\n    Returns:\n        stim.PauliString(\"I\"):\n            The qubit is entangled. Its bloch vector is x=y=z=0.\n        stim.PauliString(\"+Z\"):\n            The qubit is in the |0> state. Its bloch vector is z=+1, x=y=0.\n        stim.PauliString(\"-Z\"):\n            The qubit is in the |1> state. Its bloch vector is z=-1, x=y=0.\n        stim.PauliString(\"+Y\"):\n            The qubit is in the |i> state. Its bloch vector is y=+1, x=z=0.\n        stim.PauliString(\"-Y\"):\n            The qubit is in the |-i> state. Its bloch vector is y=-1, x=z=0.\n        stim.PauliString(\"+X\"):\n            The qubit is in the |+> state. Its bloch vector is x=+1, y=z=0.\n        stim.PauliString(\"-X\"):\n            The qubit is in the |-> state. Its bloch vector is x=-1, y=z=0.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.peek_bloch(0)\n        stim.PauliString(\"+Z\")\n        >>> s.x(0)\n        >>> s.peek_bloch(0)\n        stim.PauliString(\"-Z\")\n        >>> s.h(0)\n        >>> s.peek_bloch(0)\n        stim.PauliString(\"-X\")\n        >>> s.sqrt_x(1)\n        >>> s.peek_bloch(1)\n        stim.PauliString(\"-Y\")\n        >>> s.cz(0, 1)\n        >>> s.peek_bloch(0)\n        stim.PauliString(\"+_\")\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.peek_observable_expectation\"></a>\n```python\n# stim.TableauSimulator.peek_observable_expectation\n\n# (in class stim.TableauSimulator)\ndef peek_observable_expectation(\n    self,\n    observable: stim.PauliString,\n) -> int:\n    \"\"\"Determines the expected value of an observable.\n\n    Because the simulator's state is always a stabilizer state, the expectation will\n    always be exactly -1, 0, or +1.\n\n    This is a non-physical operation.\n    It reports information about the quantum state without disturbing it.\n\n    Args:\n        observable: The observable to determine the expected value of.\n            This observable must have a real sign, not an imaginary sign.\n\n    Returns:\n        +1: Observable will be deterministically false when measured.\n        -1: Observable will be deterministically true when measured.\n        0: Observable will be random when measured.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.peek_observable_expectation(stim.PauliString(\"+Z\"))\n        1\n        >>> s.peek_observable_expectation(stim.PauliString(\"+X\"))\n        0\n        >>> s.peek_observable_expectation(stim.PauliString(\"-Z\"))\n        -1\n\n        >>> s.do(stim.Circuit('''\n        ...     H 0\n        ...     CNOT 0 1\n        ... '''))\n        >>> queries = ['XX', 'YY', 'ZZ', '-ZZ', 'ZI', 'II', 'IIZ']\n        >>> for q in queries:\n        ...     print(q, s.peek_observable_expectation(stim.PauliString(q)))\n        XX 1\n        YY -1\n        ZZ 1\n        -ZZ -1\n        ZI 0\n        II 1\n        IIZ 1\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.peek_x\"></a>\n```python\n# stim.TableauSimulator.peek_x\n\n# (in class stim.TableauSimulator)\ndef peek_x(\n    self,\n    target: int,\n) -> int:\n    \"\"\"Returns the expected value of a qubit's X observable.\n\n    Because the simulator's state is always a stabilizer state, the expectation will\n    always be exactly -1, 0, or +1.\n\n    This is a non-physical operation.\n    It reports information about the quantum state without disturbing it.\n\n    Args:\n        target: The qubit to analyze.\n\n    Returns:\n        +1: Qubit is in the |+> state.\n        -1: Qubit is in the |-> state.\n        0: Qubit is in some other state.\n\n    Example:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_z(0)\n        >>> s.peek_x(0)\n        0\n        >>> s.reset_x(0)\n        >>> s.peek_x(0)\n        1\n        >>> s.z(0)\n        >>> s.peek_x(0)\n        -1\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.peek_y\"></a>\n```python\n# stim.TableauSimulator.peek_y\n\n# (in class stim.TableauSimulator)\ndef peek_y(\n    self,\n    target: int,\n) -> int:\n    \"\"\"Returns the expected value of a qubit's Y observable.\n\n    Because the simulator's state is always a stabilizer state, the expectation will\n    always be exactly -1, 0, or +1.\n\n    This is a non-physical operation.\n    It reports information about the quantum state without disturbing it.\n\n    Args:\n        target: The qubit to analyze.\n\n    Returns:\n        +1: Qubit is in the |i> state.\n        -1: Qubit is in the |-i> state.\n        0: Qubit is in some other state.\n\n    Example:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_z(0)\n        >>> s.peek_y(0)\n        0\n        >>> s.reset_y(0)\n        >>> s.peek_y(0)\n        1\n        >>> s.z(0)\n        >>> s.peek_y(0)\n        -1\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.peek_z\"></a>\n```python\n# stim.TableauSimulator.peek_z\n\n# (in class stim.TableauSimulator)\ndef peek_z(\n    self,\n    target: int,\n) -> int:\n    \"\"\"Returns the expected value of a qubit's Z observable.\n\n    Because the simulator's state is always a stabilizer state, the expectation will\n    always be exactly -1, 0, or +1.\n\n    This is a non-physical operation.\n    It reports information about the quantum state without disturbing it.\n\n    Args:\n        target: The qubit to analyze.\n\n    Returns:\n        +1: Qubit is in the |0> state.\n        -1: Qubit is in the |1> state.\n        0: Qubit is in some other state.\n\n    Example:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.peek_z(0)\n        0\n        >>> s.reset_z(0)\n        >>> s.peek_z(0)\n        1\n        >>> s.x(0)\n        >>> s.peek_z(0)\n        -1\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.postselect_observable\"></a>\n```python\n# stim.TableauSimulator.postselect_observable\n\n# (in class stim.TableauSimulator)\ndef postselect_observable(\n    self,\n    observable: stim.PauliString,\n    *,\n    desired_value: bool = False,\n) -> None:\n    \"\"\"Projects into a desired observable, or raises an exception if it was impossible.\n\n    Postselecting an observable forces it to collapse to a specific eigenstate,\n    as if it was measured and that state was the result of the measurement.\n\n    Args:\n        observable: The observable to postselect, specified as a pauli string.\n            The pauli string's sign must be -1 or +1 (not -i or +i).\n        desired_value:\n            False (default): Postselect into the +1 eigenstate of the observable.\n            True: Postselect into the -1 eigenstate of the observable.\n\n    Raises:\n        ValueError:\n            The given observable had an imaginary sign.\n            OR\n            The postselection was impossible. The observable was in the opposite\n            eigenstate, so measuring it would never ever return the desired result.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.postselect_observable(stim.PauliString(\"+XX\"))\n        >>> s.postselect_observable(stim.PauliString(\"+ZZ\"))\n        >>> s.peek_observable_expectation(stim.PauliString(\"+YY\"))\n        -1\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.postselect_x\"></a>\n```python\n# stim.TableauSimulator.postselect_x\n\n# (in class stim.TableauSimulator)\ndef postselect_x(\n    self,\n    targets: Union[int, Iterable[int]],\n    *,\n    desired_value: bool,\n) -> None:\n    \"\"\"Postselects qubits in the X basis, or raises an exception.\n\n    Postselecting a qubit forces it to collapse to a specific state, as\n    if it was measured and that state was the result of the measurement.\n\n    Args:\n        targets: The qubit index or indices to postselect.\n        desired_value:\n            False: postselect targets into the |+> state.\n            True: postselect targets into the |-> state.\n\n    Raises:\n        ValueError:\n            The postselection failed. One of the qubits was in a state\n            orthogonal to the desired state, so it was literally\n            impossible for a measurement of the qubit to return the\n            desired result.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.peek_x(0)\n        0\n        >>> s.postselect_x(0, desired_value=False)\n        >>> s.peek_x(0)\n        1\n        >>> s.h(0)\n        >>> s.peek_x(0)\n        0\n        >>> s.postselect_x(0, desired_value=True)\n        >>> s.peek_x(0)\n        -1\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.postselect_y\"></a>\n```python\n# stim.TableauSimulator.postselect_y\n\n# (in class stim.TableauSimulator)\ndef postselect_y(\n    self,\n    targets: Union[int, Iterable[int]],\n    *,\n    desired_value: bool,\n) -> None:\n    \"\"\"Postselects qubits in the Y basis, or raises an exception.\n\n    Postselecting a qubit forces it to collapse to a specific state, as\n    if it was measured and that state was the result of the measurement.\n\n    Args:\n        targets: The qubit index or indices to postselect.\n        desired_value:\n            False: postselect targets into the |i> state.\n            True: postselect targets into the |-i> state.\n\n    Raises:\n        ValueError:\n            The postselection failed. One of the qubits was in a state\n            orthogonal to the desired state, so it was literally\n            impossible for a measurement of the qubit to return the\n            desired result.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.peek_y(0)\n        0\n        >>> s.postselect_y(0, desired_value=False)\n        >>> s.peek_y(0)\n        1\n        >>> s.reset_x(0)\n        >>> s.peek_y(0)\n        0\n        >>> s.postselect_y(0, desired_value=True)\n        >>> s.peek_y(0)\n        -1\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.postselect_z\"></a>\n```python\n# stim.TableauSimulator.postselect_z\n\n# (in class stim.TableauSimulator)\ndef postselect_z(\n    self,\n    targets: Union[int, Iterable[int]],\n    *,\n    desired_value: bool,\n) -> None:\n    \"\"\"Postselects qubits in the Z basis, or raises an exception.\n\n    Postselecting a qubit forces it to collapse to a specific state, as if it was\n    measured and that state was the result of the measurement.\n\n    Args:\n        targets: The qubit index or indices to postselect.\n        desired_value:\n            False: postselect targets into the |0> state.\n            True: postselect targets into the |1> state.\n\n    Raises:\n        ValueError:\n            The postselection failed. One of the qubits was in a state\n            orthogonal to the desired state, so it was literally\n            impossible for a measurement of the qubit to return the\n            desired result.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> s.peek_z(0)\n        0\n        >>> s.postselect_z(0, desired_value=False)\n        >>> s.peek_z(0)\n        1\n        >>> s.h(0)\n        >>> s.peek_z(0)\n        0\n        >>> s.postselect_z(0, desired_value=True)\n        >>> s.peek_z(0)\n        -1\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.reset\"></a>\n```python\n# stim.TableauSimulator.reset\n\n# (in class stim.TableauSimulator)\ndef reset(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Resets qubits to the |0> state.\n\n    Args:\n        *targets: The indices of the qubits to reset.\n\n    Example:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.x(0)\n        >>> s.reset(0)\n        >>> s.peek_bloch(0)\n        stim.PauliString(\"+Z\")\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.reset_x\"></a>\n```python\n# stim.TableauSimulator.reset_x\n\n# (in class stim.TableauSimulator)\ndef reset_x(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Resets qubits to the |+> state.\n\n    Args:\n        *targets: The indices of the qubits to reset.\n\n    Example:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.peek_bloch(0)\n        stim.PauliString(\"+X\")\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.reset_y\"></a>\n```python\n# stim.TableauSimulator.reset_y\n\n# (in class stim.TableauSimulator)\ndef reset_y(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Resets qubits to the |i> state.\n\n    Args:\n        *targets: The indices of the qubits to reset.\n\n    Example:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_y(0)\n        >>> s.peek_bloch(0)\n        stim.PauliString(\"+Y\")\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.reset_z\"></a>\n```python\n# stim.TableauSimulator.reset_z\n\n# (in class stim.TableauSimulator)\ndef reset_z(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Resets qubits to the |0> state.\n\n    Args:\n        *targets: The indices of the qubits to reset.\n\n    Example:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> s.reset_z(0)\n        >>> s.peek_bloch(0)\n        stim.PauliString(\"+Z\")\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.s\"></a>\n```python\n# stim.TableauSimulator.s\n\n# (in class stim.TableauSimulator)\ndef s(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a SQRT_Z gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.s(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +Y -X +Z\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.s_dag\"></a>\n```python\n# stim.TableauSimulator.s_dag\n\n# (in class stim.TableauSimulator)\ndef s_dag(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a SQRT_Z_DAG gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.s_dag(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        -Y +X +Z\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.set_inverse_tableau\"></a>\n```python\n# stim.TableauSimulator.set_inverse_tableau\n\n# (in class stim.TableauSimulator)\ndef set_inverse_tableau(\n    self,\n    new_inverse_tableau: stim.Tableau,\n) -> None:\n    \"\"\"Overwrites the simulator's internal state with the given inverse tableau.\n\n    The inverse tableau specifies how Pauli product observables of qubits at the\n    current time transform into equivalent Pauli product observables at the\n    beginning of time, when all qubits were in the |0> state. For example, if the Z\n    observable on qubit 5 maps to a product of Z observables at the start of time\n    then a Z basis measurement on qubit 5 will be deterministic and equal to the\n    sign of the product. Whereas if it mapped to a product of observables including\n    an X or a Y then the Z basis measurement would be random.\n\n    Any qubits not within the length of the tableau are implicitly in the |0> state.\n\n    Args:\n        new_inverse_tableau: The tableau to overwrite the internal state with.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> t = stim.Tableau.random(4)\n        >>> s.set_inverse_tableau(t)\n        >>> s.current_inverse_tableau() == t\n        True\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.set_num_qubits\"></a>\n```python\n# stim.TableauSimulator.set_num_qubits\n\n# (in class stim.TableauSimulator)\ndef set_num_qubits(\n    self,\n    new_num_qubits: int,\n) -> None:\n    \"\"\"Resizes the simulator's internal state.\n\n    This forces the simulator's internal state to track exactly the qubits whose\n    indices are in `range(new_num_qubits)`.\n\n    Note that untracked qubits are always assumed to be in the |0> state. Therefore,\n    calling this method will effectively force any qubit whose index is outside\n    `range(new_num_qubits)` to be reset to |0>.\n\n    Note that this method does not prevent future operations from implicitly\n    expanding the size of the tracked state (e.g. setting the number of qubits to 5\n    will not prevent a Hadamard from then being applied to qubit 100, increasing the\n    number of qubits back to 101).\n\n    Args:\n        new_num_qubits: The length of the range of qubits the internal simulator\n            should be tracking.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> len(s.current_inverse_tableau())\n        0\n\n        >>> s.set_num_qubits(5)\n        >>> len(s.current_inverse_tableau())\n        5\n\n        >>> s.x(0, 1, 2, 3)\n        >>> s.set_num_qubits(2)\n        >>> s.measure_many(0, 1, 2, 3)\n        [True, True, False, False]\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.set_state_from_stabilizers\"></a>\n```python\n# stim.TableauSimulator.set_state_from_stabilizers\n\n# (in class stim.TableauSimulator)\ndef set_state_from_stabilizers(\n    self,\n    stabilizers: Iterable[stim.PauliString],\n    *,\n    allow_redundant: bool = False,\n    allow_underconstrained: bool = False,\n) -> None:\n    \"\"\"Sets the tableau simulator's state to a state satisfying the given stabilizers.\n\n    The old quantum state is completely overwritten, even if the new state is\n    underconstrained by the given stabilizers. The number of qubits is changed to\n    exactly match the number of qubits in the longest given stabilizer.\n\n    Args:\n        stabilizers: A list of `stim.PauliString`s specifying the stabilizers that\n            the new state must have. It is permitted for stabilizers to have\n            different lengths. All stabilizers are padded up to the length of the\n            longest stabilizer by appending identity terms.\n        allow_redundant: Defaults to False. If set to False, then the given\n            stabilizers must all be independent. If any one of them is a product of\n            the others (including the empty product), an exception will be raised.\n            If set to True, then redundant stabilizers are simply ignored.\n        allow_underconstrained: Defaults to False. If set to False, then the given\n            stabilizers must form a complete set of generators. They must exactly\n            specify the desired stabilizer state, with no degrees of freedom left\n            over. For an n-qubit state there must be n independent stabilizers. If\n            set to True, then there can be leftover degrees of freedom which can be\n            set arbitrarily.\n\n    Returns:\n        Nothing. Mutates the states of the simulator to match the desired\n        stabilizers.\n\n        Guarantees that self.current_inverse_tableau().inverse_z_output(k) will be\n        equal to the k'th independent stabilizer from the `stabilizers` argument.\n\n    Raises:\n        ValueError:\n            A stabilizer is redundant but allow_redundant=True wasn't set.\n            OR\n            The given stabilizers are contradictory (e.g. \"+Z\" and \"-Z\" both\n            specified).\n            OR\n            The given stabilizers anticommute (e.g. \"+Z\" and \"+X\" both specified).\n            OR\n            The stabilizers left behind a degree of freedom but\n            allow_underconstrained=True wasn't set.\n            OR\n            A stabilizer has an imaginary sign (i or -i).\n\n    Examples:\n\n        >>> import stim\n        >>> tab_sim = stim.TableauSimulator()\n        >>> tab_sim.set_state_from_stabilizers([\n        ...     stim.PauliString(\"XX\"),\n        ...     stim.PauliString(\"ZZ\"),\n        ... ])\n        >>> tab_sim.current_inverse_tableau().inverse()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z_\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+XX\"),\n                stim.PauliString(\"+ZZ\"),\n            ],\n        )\n\n        >>> tab_sim.set_state_from_stabilizers([\n        ...     stim.PauliString(\"XX_\"),\n        ...     stim.PauliString(\"ZZ_\"),\n        ...     stim.PauliString(\"-YY_\"),\n        ...     stim.PauliString(\"\"),\n        ... ], allow_underconstrained=True, allow_redundant=True)\n        >>> tab_sim.current_inverse_tableau().inverse()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z__\"),\n                stim.PauliString(\"+_X_\"),\n                stim.PauliString(\"+__X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+XX_\"),\n                stim.PauliString(\"+ZZ_\"),\n                stim.PauliString(\"+__Z\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.set_state_from_state_vector\"></a>\n```python\n# stim.TableauSimulator.set_state_from_state_vector\n\n# (in class stim.TableauSimulator)\ndef set_state_from_state_vector(\n    self,\n    state_vector: Iterable[float],\n    *,\n    endian: Literal[\"little\", \"big\"],\n) -> None:\n    \"\"\"Sets the simulator's state to a superposition specified by an amplitude vector.\n\n    Args:\n        state_vector: A list of complex amplitudes specifying a superposition. The\n            vector must correspond to a state that is reachable using Clifford\n            operations, and must be normalized (i.e. it must be a unit vector).\n        endian:\n            \"little\": state vector is in little endian order, where higher index\n                qubits correspond to larger changes in the state index.\n            \"big\": state vector is in big endian order, where higher index qubits\n                correspond to smaller changes in the state index.\n\n    Returns:\n        Nothing. Mutates the states of the simulator to match the desired state.\n\n    Raises:\n        ValueError:\n            The given state vector isn't a list of complex values specifying a\n            stabilizer state.\n            OR\n            The given endian value isn't 'little' or 'big'.\n\n    Examples:\n\n        >>> import stim\n        >>> tab_sim = stim.TableauSimulator()\n        >>> tab_sim.set_state_from_state_vector([\n        ...     0.5**0.5,\n        ...     0.5**0.5 * 1j,\n        ... ], endian='little')\n        >>> tab_sim.current_inverse_tableau().inverse()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+Y\"),\n            ],\n        )\n        >>> tab_sim.set_state_from_state_vector([\n        ...     0.5**0.5,\n        ...     0,\n        ...     0,\n        ...     0.5**0.5,\n        ... ], endian='little')\n        >>> tab_sim.current_inverse_tableau().inverse()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z_\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+XX\"),\n                stim.PauliString(\"+ZZ\"),\n            ],\n        )\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.sqrt_x\"></a>\n```python\n# stim.TableauSimulator.sqrt_x\n\n# (in class stim.TableauSimulator)\ndef sqrt_x(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a SQRT_X gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.sqrt_x(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Z -Y\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.sqrt_x_dag\"></a>\n```python\n# stim.TableauSimulator.sqrt_x_dag\n\n# (in class stim.TableauSimulator)\ndef sqrt_x_dag(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a SQRT_X_DAG gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.sqrt_x_dag(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X -Z +Y\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.sqrt_y\"></a>\n```python\n# stim.TableauSimulator.sqrt_y\n\n# (in class stim.TableauSimulator)\ndef sqrt_y(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a SQRT_Y gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.sqrt_y(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        -Z +Y +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.sqrt_y_dag\"></a>\n```python\n# stim.TableauSimulator.sqrt_y_dag\n\n# (in class stim.TableauSimulator)\ndef sqrt_y_dag(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a SQRT_Y_DAG gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.sqrt_y_dag(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +Z +Y -X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.state_vector\"></a>\n```python\n# stim.TableauSimulator.state_vector\n\n# (in class stim.TableauSimulator)\ndef state_vector(\n    self,\n    *,\n    endian: Literal[\"little\", \"big\"] = 'little',\n) -> np.ndarray[np.complex64]:\n    \"\"\"Returns a wavefunction for the simulator's current state.\n\n    This function takes O(n * 2**n) time and O(2**n) space, where n is the number of\n    qubits. The computation is done by initialization a random state vector and\n    iteratively projecting it into the +1 eigenspace of each stabilizer of the\n    state. The state is then canonicalized so that zero values are actually exactly\n    0, and so that the first non-zero entry is positive.\n\n    Args:\n        endian:\n            \"little\" (default): state vector is in little endian order, where higher\n                index qubits correspond to larger changes in the state index.\n            \"big\": state vector is in big endian order, where higher index qubits\n                correspond to smaller changes in the state index.\n\n    Returns:\n        A `numpy.ndarray[numpy.complex64]` of computational basis amplitudes.\n\n        If the result is in little endian order then the amplitude at offset\n        b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n        computational basis state where the qubit with index 0 is storing the bit\n        b_0, the qubit with index 1 is storing the bit b_1, etc.\n\n        If the result is in big endian order then the amplitude at offset\n        b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n        computational basis state where the qubit with index 0 is storing the bit\n        b_{n-1}, the qubit with index 1 is storing the bit b_{n-2}, etc.\n\n    Examples:\n        >>> import stim\n        >>> import numpy as np\n        >>> s = stim.TableauSimulator()\n        >>> s.x(2)\n        >>> s.state_vector(endian='little')\n        array([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n              dtype=complex64)\n\n        >>> s.state_vector(endian='big')\n        array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n              dtype=complex64)\n\n        >>> s.sqrt_x(1, 2)\n        >>> s.state_vector()\n        array([0.5+0.j , 0. +0.j , 0. -0.5j, 0. +0.j , 0. +0.5j, 0. +0.j ,\n               0.5+0.j , 0. +0.j ], dtype=complex64)\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.swap\"></a>\n```python\n# stim.TableauSimulator.swap\n\n# (in class stim.TableauSimulator)\ndef swap(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a swap gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.swap(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +Y +X +X +Z\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.x\"></a>\n```python\n# stim.TableauSimulator.x\n\n# (in class stim.TableauSimulator)\ndef x(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a Pauli X gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.x(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X -Y -Z\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.x_error\"></a>\n```python\n# stim.TableauSimulator.x_error\n\n# (in class stim.TableauSimulator)\ndef x_error(\n    self,\n    *targets: int,\n    p: float,\n):\n    \"\"\"Probabilistically applies X errors to targets.\n\n    Args:\n        *targets: The indices of the qubits to target with the noise.\n        p: The chance of the X error being applied,\n            independently, to each qubit.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.x_error(0, 1, 2, p=0.01)\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.xcx\"></a>\n```python\n# stim.TableauSimulator.xcx\n\n# (in class stim.TableauSimulator)\ndef xcx(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies an X-controlled X gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.xcx(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.xcy\"></a>\n```python\n# stim.TableauSimulator.xcy\n\n# (in class stim.TableauSimulator)\ndef xcy(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies an X-controlled Y gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.xcy(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +_ +_\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.xcz\"></a>\n```python\n# stim.TableauSimulator.xcz\n\n# (in class stim.TableauSimulator)\ndef xcz(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies an X-controlled Z gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.xcz(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +_ +_\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.y\"></a>\n```python\n# stim.TableauSimulator.y\n\n# (in class stim.TableauSimulator)\ndef y(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a Pauli Y gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.y(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        -X +Y -Z\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.y_error\"></a>\n```python\n# stim.TableauSimulator.y_error\n\n# (in class stim.TableauSimulator)\ndef y_error(\n    self,\n    *targets: int,\n    p: float,\n):\n    \"\"\"Probabilistically applies Y errors to targets.\n\n    Args:\n        *targets: The indices of the qubits to target with the noise.\n        p: The chance of the Y error being applied,\n            independently, to each qubit.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.y_error(0, 1, 2, p=0.01)\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.ycx\"></a>\n```python\n# stim.TableauSimulator.ycx\n\n# (in class stim.TableauSimulator)\ndef ycx(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a Y-controlled X gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.ycx(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +_ +_ +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.ycy\"></a>\n```python\n# stim.TableauSimulator.ycy\n\n# (in class stim.TableauSimulator)\ndef ycy(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a Y-controlled Y gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.ycy(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +_ +_\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.ycz\"></a>\n```python\n# stim.TableauSimulator.ycz\n\n# (in class stim.TableauSimulator)\ndef ycz(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a Y-controlled Z gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.ycz(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +_ +_ +_ +_\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.z\"></a>\n```python\n# stim.TableauSimulator.z\n\n# (in class stim.TableauSimulator)\ndef z(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a Pauli Z gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        +X +Y +Z\n        >>> s.z(0, 1, 2)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n        -X -Y +Z\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.z_error\"></a>\n```python\n# stim.TableauSimulator.z_error\n\n# (in class stim.TableauSimulator)\ndef z_error(\n    self,\n    *targets: int,\n    p: float,\n):\n    \"\"\"Probabilistically applies Z errors to targets.\n\n    Args:\n        *targets: The indices of the qubits to target with the noise.\n        p: The chance of the Z error being applied,\n            independently, to each qubit.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.z_error(0, 1, 2, p=0.01)\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.zcx\"></a>\n```python\n# stim.TableauSimulator.zcx\n\n# (in class stim.TableauSimulator)\ndef zcx(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a controlled X gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.zcx(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +_ +_ +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.zcy\"></a>\n```python\n# stim.TableauSimulator.zcy\n\n# (in class stim.TableauSimulator)\ndef zcy(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a controlled Y gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.zcy(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.TableauSimulator.zcz\"></a>\n```python\n# stim.TableauSimulator.zcz\n\n# (in class stim.TableauSimulator)\ndef zcz(\n    self,\n    *targets,\n) -> None:\n    \"\"\"Applies a controlled Z gate to the simulator's state.\n\n    Args:\n        *targets: The indices of the qubits to target with the gate.\n            Applies the gate to the first two targets, then the next two targets,\n            and so forth. There must be an even number of targets.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.reset_x(0, 3)\n        >>> s.reset_y(1)\n\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +X +Y +Z +X\n        >>> s.zcz(0, 1, 2, 3)\n        >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n        +_ +_ +Z +X\n    \"\"\"\n```\n\n<a name=\"stim.gate_data\"></a>\n```python\n# stim.gate_data\n\n# (at top-level in the stim module)\n@overload\ndef gate_data(\n    name: str,\n) -> stim.GateData:\n    pass\n@overload\ndef gate_data(\n) -> Dict[str, stim.GateData]:\n    pass\ndef gate_data(\n    name: Optional[str] = None,\n) -> Union[str, Dict[str, stim.GateData]]:\n    \"\"\"Returns gate data for the given named gate, or all gates.\n\n    Examples:\n        >>> import stim\n        >>> stim.gate_data('cnot').aliases\n        ['CNOT', 'CX', 'ZCX']\n        >>> stim.gate_data('cnot').is_two_qubit_gate\n        True\n        >>> gate_dict = stim.gate_data()\n        >>> len(gate_dict) > 50\n        True\n        >>> gate_dict['MX'].produces_measurements\n        True\n    \"\"\"\n```\n\n<a name=\"stim.main\"></a>\n```python\n# stim.main\n\n# (at top-level in the stim module)\ndef main(\n    *,\n    command_line_args: List[str],\n) -> int:\n    \"\"\"Runs the command line tool version of stim on the given arguments.\n\n    Note that by default any input will be read from stdin, any output\n    will print to stdout (as opposed to being intercepted). For most\n    commands, you can use arguments like `--out` to write to a file\n    instead of stdout and `--in` to read from a file instead of stdin.\n\n    Returns:\n        An exit code (0 means success, not zero means failure).\n\n    Raises:\n        A large variety of errors, depending on what you are doing and\n        how it failed! Beware that many errors are caught by the main\n        method itself and printed to stderr, with the only indication\n        that something went wrong being the return code.\n\n    Example:\n        >>> import stim\n        >>> import tempfile\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = f'{d}/tmp.out'\n        ...     return_code = stim.main(command_line_args=[\n        ...         \"gen\",\n        ...         \"--code=repetition_code\",\n        ...         \"--task=memory\",\n        ...         \"--rounds=1000\",\n        ...         \"--distance=2\",\n        ...         \"--out\",\n        ...         path,\n        ...     ])\n        ...     assert return_code == 0\n        ...     with open(path) as f:\n        ...         print(f.read(), end='')\n        # Generated repetition_code circuit.\n        # task: memory\n        # rounds: 1000\n        # distance: 2\n        # before_round_data_depolarization: 0\n        # before_measure_flip_probability: 0\n        # after_reset_flip_probability: 0\n        # after_clifford_depolarization: 0\n        # layout:\n        # L0 Z1 d2\n        # Legend:\n        #     d# = data qubit\n        #     L# = data qubit with logical observable crossing\n        #     Z# = measurement qubit\n        R 0 1 2\n        TICK\n        CX 0 1\n        TICK\n        CX 2 1\n        TICK\n        MR 1\n        DETECTOR(1, 0) rec[-1]\n        REPEAT 999 {\n            TICK\n            CX 0 1\n            TICK\n            CX 2 1\n            TICK\n            MR 1\n            SHIFT_COORDS(0, 1)\n            DETECTOR(1, 0) rec[-1] rec[-2]\n        }\n        M 0 2\n        DETECTOR(1, 1) rec[-1] rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\"\n```\n\n<a name=\"stim.read_shot_data_file\"></a>\n```python\n# stim.read_shot_data_file\n\n# (at top-level in the stim module)\n@overload\ndef read_shot_data_file(\n    *,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    bit_packed: bool = False,\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n) -> np.ndarray:\n    pass\n@overload\ndef read_shot_data_file(\n    *,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    bit_packed: bool = False,\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n    separate_observables: Literal[True],\n) -> Tuple[np.ndarray, np.ndarray]:\n    pass\ndef read_shot_data_file(\n    *,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    bit_packed: bool = False,\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n    separate_observables: bool = False,\n) -> Union[Tuple[np.ndarray, np.ndarray], np.ndarray]:\n    \"\"\"Reads shot data, such as measurement samples, from a file.\n\n    Args:\n        path: The path to the file to read the data from.\n        format: The format that the data is stored in, such as 'b8'.\n            See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        bit_packed: Defaults to false. Determines whether the result is a bool_\n            numpy array with one bit per byte, or a uint8 numpy array with 8 bits\n            per byte.\n        num_measurements: How many measurements there are per shot.\n        num_detectors: How many detectors there are per shot.\n        num_observables: How many observables there are per shot.\n            Note that this only refers to observables *stored in the file*, not to\n            observables from the original circuit that was sampled.\n        separate_observables: When set to True, the result is a tuple of two arrays,\n            one containing the detection event data and the other containing the\n            observable data, instead of a single array.\n\n    Returns:\n        If separate_observables=True:\n            A tuple (dets, obs) of numpy arrays containing the loaded data.\n\n            If bit_packed=False:\n                dets.dtype = np.bool_\n                dets.shape = (num_shots, num_measurements + num_detectors)\n                det bit b from shot s is at dets[s, b]\n                obs.dtype = np.bool_\n                obs.shape = (num_shots, num_observables)\n                obs bit b from shot s is at dets[s, b]\n            If bit_packed=True:\n                dets.dtype = np.uint8\n                dets.shape = (num_shots, math.ceil(\n                    (num_measurements + num_detectors) / 8))\n                obs.dtype = np.uint8\n                obs.shape = (num_shots, math.ceil(num_observables / 8))\n                det bit b from shot s is at dets[s, b // 8] & (1 << (b % 8))\n                obs bit b from shot s is at obs[s, b // 8] & (1 << (b % 8))\n\n        If separate_observables=False:\n            A numpy array containing the loaded data.\n\n            If bit_packed=False:\n                dtype = np.bool_\n                shape = (num_shots,\n                         num_measurements + num_detectors + num_observables)\n                bit b from shot s is at result[s, b]\n            If bit_packed=True:\n                dtype = np.uint8\n                shape = (num_shots, math.ceil(\n                    (num_measurements + num_detectors + num_observables) / 8))\n                bit b from shot s is at result[s, b // 8] & (1 << (b % 8))\n\n    Examples:\n        >>> import stim\n        >>> import pathlib\n        >>> import tempfile\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = pathlib.Path(d) / 'shots'\n        ...     with open(path, 'w') as f:\n        ...         print(\"0000\", file=f)\n        ...         print(\"0101\", file=f)\n        ...\n        ...     read = stim.read_shot_data_file(\n        ...         path=str(path),\n        ...         format='01',\n        ...         num_measurements=4)\n        >>> read\n        array([[False, False, False, False],\n               [False,  True, False,  True]])\n    \"\"\"\n```\n\n<a name=\"stim.target_combined_paulis\"></a>\n```python\n# stim.target_combined_paulis\n\n# (at top-level in the stim module)\ndef target_combined_paulis(\n    paulis: Union[stim.PauliString, List[stim.GateTarget]],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a list of targets encoding a pauli product for instructions like MPP.\n\n    Args:\n        paulis: The paulis to encode into the targets. This can be a\n            `stim.PauliString` or a list of pauli targets from `stim.target_x`,\n            `stim.target_pauli`, etc.\n        invert: Defaults to False. If True, the product is inverted (like \"!X2*Y3\").\n            Note that this is in addition to any inversions specified by the\n            `paulis` argument.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     *stim.target_combined_paulis(stim.PauliString(\"-XYZ\")),\n        ...     *stim.target_combined_paulis([stim.target_x(2), stim.target_y(5)]),\n        ...     *stim.target_combined_paulis([stim.target_z(9)], invert=True),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP !X0*Y1*Z2 X2*Y5 !Z9\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_combiner\"></a>\n```python\n# stim.target_combiner\n\n# (at top-level in the stim module)\ndef target_combiner(\n) -> stim.GateTarget:\n    \"\"\"Returns a target combiner that can be used to build Pauli products.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*Y3*Z5\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_inv\"></a>\n```python\n# stim.target_inv\n\n# (at top-level in the stim module)\ndef target_inv(\n    qubit_index: Union[int, stim.GateTarget],\n) -> stim.GateTarget:\n    \"\"\"Returns a target flagged as inverted.\n\n    Inverted targets are used to indicate measurement results should be flipped.\n\n    Args:\n        qubit_index: The underlying qubit index of the inverted target.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"M\", [2, stim.target_inv(3)])\n        >>> circuit\n        stim.Circuit('''\n            M 2 !3\n        ''')\n\n    For example, the '!1' in 'M 0 !1 2' is qubit 1 flagged as inverted,\n    meaning the measurement result from qubit 1 should be inverted when reported.\n    \"\"\"\n```\n\n<a name=\"stim.target_logical_observable_id\"></a>\n```python\n# stim.target_logical_observable_id\n\n# (at top-level in the stim module)\ndef target_logical_observable_id(\n    index: int,\n) -> stim.DemTarget:\n    \"\"\"Returns a logical observable id identifying a frame change.\n\n    Args:\n        index: The index of the observable.\n\n    Returns:\n        The logical observable target.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.target_logical_observable_id(13)\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) L13\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_pauli\"></a>\n```python\n# stim.target_pauli\n\n# (at top-level in the stim module)\ndef target_pauli(\n    qubit_index: int,\n    pauli: Union[str, int],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a pauli target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        pauli: The pauli gate to use. This can either be a string identifying the\n            pauli by name (\"x\", \"X\", \"y\", \"Y\", \"z\", or \"Z\") or an integer following\n            the convention (1=X, 2=Y, 3=Z). Setting this argument to \"I\" or to\n            0 will return a qubit target instead of a pauli target.\n        invert: Defaults to False. If True, the target is inverted (like \"!X10\"),\n            indicating that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_pauli(2, \"X\"),\n        ...     stim.target_combiner(),\n        ...     stim.target_pauli(3, \"y\", invert=True),\n        ...     stim.target_pauli(5, 3),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3 Z5\n        ''')\n\n        >>> circuit.append(\"M\", [\n        ...     stim.target_pauli(7, \"I\"),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3 Z5\n            M 7\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_rec\"></a>\n```python\n# stim.target_rec\n\n# (at top-level in the stim module)\ndef target_rec(\n    lookback_index: int,\n) -> stim.GateTarget:\n    \"\"\"Returns a measurement record target with the given lookback.\n\n    Measurement record targets are used to refer back to the measurement record;\n    the list of measurements that have been performed so far. Measurement record\n    targets always specify an index relative to the *end* of the measurement record.\n    The latest measurement is `stim.target_rec(-1)`, the next most recent\n    measurement is `stim.target_rec(-2)`, and so forth. Indexing is done this way\n    in order to make it possible to write loops.\n\n    Args:\n        lookback_index: A negative integer indicating how far to look back, relative\n            to the end of the measurement record.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"M\", [5, 7, 11])\n        >>> circuit.append(\"CX\", [stim.target_rec(-2), 3])\n        >>> circuit\n        stim.Circuit('''\n            M 5 7 11\n            CX rec[-2] 3\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_relative_detector_id\"></a>\n```python\n# stim.target_relative_detector_id\n\n# (at top-level in the stim module)\ndef target_relative_detector_id(\n    index: int,\n) -> stim.DemTarget:\n    \"\"\"Returns a relative detector id (e.g. \"D5\" in a .dem file).\n\n    Args:\n        index: The index of the detector, relative to the current detector offset.\n\n    Returns:\n        The relative detector target.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.target_relative_detector_id(13)\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) D13\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_separator\"></a>\n```python\n# stim.target_separator\n\n# (at top-level in the stim module)\ndef target_separator(\n) -> stim.DemTarget:\n    \"\"\"Returns a target separator (e.g. \"^\" in a .dem file).\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.target_relative_detector_id(1),\n        ...     stim.target_separator(),\n        ...     stim.target_relative_detector_id(2),\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) D1 ^ D2\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_sweep_bit\"></a>\n```python\n# stim.target_sweep_bit\n\n# (at top-level in the stim module)\ndef target_sweep_bit(\n    sweep_bit_index: int,\n) -> stim.GateTarget:\n    \"\"\"Returns a sweep bit target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        sweep_bit_index: The index of the sweep bit to target.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"CX\", [stim.target_sweep_bit(2), 5])\n        >>> circuit\n        stim.Circuit('''\n            CX sweep[2] 5\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_x\"></a>\n```python\n# stim.target_x\n\n# (at top-level in the stim module)\ndef target_x(\n    qubit_index: Union[int, stim.GateTarget],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a Pauli X target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        invert: Defaults to False. If True, the target is inverted (indicating\n            that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3, invert=True),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3*Z5\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_y\"></a>\n```python\n# stim.target_y\n\n# (at top-level in the stim module)\ndef target_y(\n    qubit_index: Union[int, stim.GateTarget],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a Pauli Y target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        invert: Defaults to False. If True, the target is inverted (indicating\n            that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3, invert=True),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3*Z5\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.target_z\"></a>\n```python\n# stim.target_z\n\n# (at top-level in the stim module)\ndef target_z(\n    qubit_index: Union[int, stim.GateTarget],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a Pauli Z target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        invert: Defaults to False. If True, the target is inverted (indicating\n            that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3, invert=True),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3*Z5\n        ''')\n    \"\"\"\n```\n\n<a name=\"stim.write_shot_data_file\"></a>\n```python\n# stim.write_shot_data_file\n\n# (at top-level in the stim module)\ndef write_shot_data_file(\n    *,\n    data: np.ndarray,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n) -> None:\n    \"\"\"Writes shot data, such as measurement samples, to a file.\n\n    Args:\n        data: The data to write to the file. This must be a numpy array. The dtype\n            of the array determines whether or not the data is bit packed, and the\n            shape must match the bits per shot.\n\n            dtype=np.bool_: Not bit packed. Shape must be\n                (num_shots, num_measurements + num_detectors + num_observables).\n            dtype=np.uint8: Yes bit packed. Shape must be\n                (num_shots, math.ceil(\n                    (num_measurements + num_detectors + num_observables) / 8)).\n        path: The path to the file to write the data to.\n        format: The format that the data is stored in, such as 'b8'.\n            See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        num_measurements: How many measurements there are per shot.\n        num_detectors: How many detectors there are per shot.\n        num_observables: How many observables there are per shot.\n            Note that this only refers to observables *in the given shot data*, not\n            to observables from the original circuit that was sampled.\n\n    Examples:\n        >>> import stim\n        >>> import pathlib\n        >>> import tempfile\n        >>> import numpy as np\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = pathlib.Path(d) / 'shots'\n        ...     shot_data = np.array([\n        ...         [0, 1, 0],\n        ...         [0, 1, 1],\n        ...     ], dtype=np.bool_)\n        ...\n        ...     stim.write_shot_data_file(\n        ...         path=str(path),\n        ...         data=shot_data,\n        ...         format='01',\n        ...         num_measurements=3)\n        ...\n        ...     with open(path) as f:\n        ...         written = f.read()\n        >>> written\n        '010\\n011\\n'\n    \"\"\"\n```\n"
  },
  {
    "path": "doc/result_formats.md",
    "content": "# Introduction\n\nA *result format* is a way of representing bits from shots sampled from a circuit.\nIt is some way of converting between a list-of-list-of-bits (a list-of-shots) and\na flat string of bytes or characters.\n\nGenerally, the result data formats supported by Stim are extremely minimalist.\nThey do not contain metadata about which circuit was run,\nhow many shots were taken,\nhow many bits are in each shot,\nor even self-identifying information like a header with magic bytes.\nThey produce *raw* data.\nEven details about which bits are measurements, which are detection events,\nand which are observable frame changes must be determined from context.\n\nThe major driver for having multiple formats is context-dependent preferences for\nbinary-vs-human-readable and dense-vs-sparse.\nFor example, '`01`' is a dense text format and '`r8`' is a sparse binary format.\nSometimes you want to be able to eyeball your data, so you want a text format.\nOther times you want maximum efficiency, so you want a binary format.\nSometimes your data is high entropy, with as many 1s as 0s, so you use a dense format.\nOther times the data is highly biased, with 1s being much rarer and more interesting\nthan 0s, so you use a sparse format.\n\n# Index\n- [The **01** Format](#01)\n- [The **b8** Format](#b8)\n- [The **dets** Format](#dets)\n- [The **hits** Format](#hits)\n- [The **ptb64** Format](#ptb64)\n- [The **r8** Format](#r8)\n\n\n# <a name=\"01\"></a>The `01` Format\n\nThe 01 format is a dense human readable format that stores shots as lines of '0' and '1' characters.\n\nThe data from each shot is terminated by a newline character '\\n'. Each character in the line is a '0' (indicating\nFalse) or a '1' (indicating True) corresponding to a measurement result (or a detector result) from a circuit.\n\nThis is the default format used by Stim, because it's the easiest to understand.\n\n*Example of producing 01 format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"01\")\n    ...     with open(path) as f:\n    ...         print(f.read().strip())\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n\n*Example 01 parsing code (python)*:\n```python\nfrom typing import List\n\ndef parse_01(data: str) -> List[List[bool]]:\n    shots = []\n    for line in data.split('\\n'):\n        if not line:\n            continue\n        shot = []\n        for c in line:\n            assert c in '01'\n            shot.append(c == '1')\n        shots.append(shot)\n    return shots\n```\n*Example 01 saving code (python):*\n```python\nfrom typing import List\n\ndef save_01(shots: List[List[bool]]) -> str:\n    output = \"\"\n    for shot in shots:\n        for sample in shot:\n            output += '1' if sample else '0'\n        output += \"\\n\"\n    return output\n```\n\n# <a name=\"b8\"></a>The `b8` Format\n\nThe b8 format is a dense binary format that stores shots as bit-packed bytes.\n\nEach shot is stored into ceil(n / 8) bytes, where n is the number of bits in the shot. Effectively, each shot is padded\nup to a multiple of 8 by appending False bits, so that shots always start on a byte boundary. Bits are packed into bytes\nin significance order (the 1s bit is the first bit, the 2s bit is the second, the 4s bit is the third, and so forth\nuntil the 128s bit which is the eighth bit).\n\nThis format requires the reader to know the number of bits in each shot.\n\n*Example of producing b8 format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"b8\")\n    ...     with open(path, 'rb') as f:\n    ...         print(' '.join(hex(e)[2:] for e in f.read()))\n    f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c\n\n*Example b8 parsing code (python)*:\n```python\nfrom typing import List\n\ndef parse_b8(data: bytes, bits_per_shot: int) -> List[List[bool]]:\n    shots = []\n    bytes_per_shot = (bits_per_shot + 7) // 8\n    for offset in range(0, len(data), bytes_per_shot):\n        shot = []\n        for k in range(bits_per_shot):\n            byte = data[offset + k // 8]\n            bit = (byte >> (k % 8)) % 2 == 1\n            shot.append(bit)\n        shots.append(shot)\n    return shots\n```\n*Example b8 saving code (python):*\n```python\nfrom typing import List\n\ndef save_b8(shots: List[List[bool]]) -> bytes:\n    output = b\"\"\n    for shot in shots:\n        bytes_per_shot = (len(shot) + 7) // 8\n        v = 0\n        for b in reversed(shot):\n            v <<= 1\n            v += int(b)\n        output += v.to_bytes(bytes_per_shot, 'little')\n    return output\n```\n\n# <a name=\"dets\"></a>The `dets` Format\n\nThe dets format is a sparse human readable format that stores shots as lines starting with the word 'shot'\nand then containing space-separated prefixed values like 'D5' and 'L2'. Each value's prefix indicates whether\nit is a measurement (M), a detector (D), or observable frame change (L) and its integer indicates that\nthe corresponding measurement/detection-event/frame-change was True instead of False.\n\nThe data from each shot is started with the text 'shot' and terminated by a newline character '\\n'. The rest of the\nline is a series of integers, separated by spaces and prefixed by a single letter. The prefix letter indicates the type\nof value ('M' for measurement, 'D' for detector, and 'L' for logical observable). The integer indicates the index of the\nvalue. For example, \"D1 D3 L0\" indicates detectors 1 and 3 fired, and logical observable 0 was flipped.\n\nThis format requires the reader to know the number of measurements/detectors/observables in each shot, if the reader\nwants to produce vectors of bits instead of sets.\n\n*Example of producing dets format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=3, filepath=path, format=\"dets\")\n    ...     with open(path) as f:\n    ...         print(f.read().strip())\n    shot M4 M5 M6 M7 M10 M11 M13 M15\n    shot M4 M5 M6 M7 M10 M11 M13 M15\n    shot M4 M5 M6 M7 M10 M11 M13 M15\n\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X_ERROR(1) 1\n    ...         M 0 1 2\n    ...         DETECTOR rec[-1]\n    ...         DETECTOR rec[-2]\n    ...         DETECTOR rec[-3]\n    ...         OBSERVABLE_INCLUDE(5) rec[-2]\n    ...     \"\"\").compile_detector_sampler().sample_write(shots=2, filepath=path, format=\"dets\", append_observables=True)\n    ...     with open(path) as f:\n    ...         print(f.read().strip())\n    shot D1 L5\n    shot D1 L5\n\n*Example dets parsing code (python)*:\n```python\nfrom typing import List\n\ndef parse_dets(data: str, num_detectors: int, num_observables: int) -> List[List[bool]]:\n    shots = []\n    for line in data.split('\\n'):\n        if not line.strip():\n            continue\n        assert line.startswith('shot')\n        line = line[4:].strip()\n\n        shot = [False] * (num_detectors + num_observables)\n        if line:\n            for term in line.split(' '):\n                c = term[0]\n                v = int(term[1:])\n                if c == 'D':\n                    assert 0 <= v < num_detectors\n                    shot[v] = True\n                elif c == 'L':\n                    assert 0 <= v < num_observables\n                    shot[num_detectors + v] = True\n                else:\n                    raise NotImplementedError(c)\n        shots.append(shot)\n    return shots\n```\n*Example dets saving code (python):*\n```python\nfrom typing import List\n\ndef save_dets(shots: List[List[bool]], num_detectors: int, num_observables: int):\n    output = \"\"\n    for shot in shots:\n        assert len(shot) == num_detectors + num_observables\n        detectors = shot[:num_detectors]\n        observables = shot[num_detectors:]\n        output += \"shot\"\n        for k in range(num_detectors):\n            if shot[k]:\n                output += \" D\" + str(k)\n        for k in range(num_observables):\n            if shot[num_detectors + k]:\n                output += \" L\" + str(k)\n        output += \"\\n\"\n    return output\n```\n\n# <a name=\"hits\"></a>The `hits` Format\n\nThe hits format is a dense human readable format that stores shots as a comma-separated list of integers.\nEach integer indicates the position of a bit that was True.\nPositions that aren't mentioned had bits that were False.\n\nThe data from each shot is terminated by a newline character '\\n'. The line is a series of non-negative integers\nseparated by commas, with each integer indicating a bit from the shot that was true.\n\nThis format requires the reader to know the number of bits in each shot (if they want to get a list instead of a set).\nThis format requires the reader to know how many trailing newlines, that don't correspond to shots with no hit, are in\nthe text data.\n\nThis format is useful in contexts where the number of set bits is expected to be low, e.g. when sampling detection\nevents.\n\n*Example of producing hits format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"hits\")\n    ...     with open(path) as f:\n    ...         print(f.read().strip())\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n\n*Example hits parsing code (python)*:\n```python\nfrom typing import List\n\ndef parse_hits(data: str, bits_per_shot: int) -> List[List[bool]]:\n    shots = []\n    if data.endswith('\\n'):\n        data = data[:-1]\n    for line in data.split('\\n'):\n        shot = [False] * bits_per_shot\n        if line:\n            for term in line.split(','):\n                shot[int(term)] = True\n        shots.append(shot)\n    return shots\n```\n*Example hits saving code (python):*\n```python\nfrom typing import List\n\ndef save_hits(shots: List[List[bool]]) -> str:\n    output = \"\"\n    for shot in shots:\n        output += \",\".join(str(index) for index, bit in enumerate(shot) if bit) + \"\\n\"\n    return output\n```\n\n# <a name=\"ptb64\"></a>The `ptb64` Format\n\nThe ptb64 format is a dense SIMD-focused binary format that stores shots as partially transposed bit-packed data.\n\nEach 64 bit word (8 bytes) of the data contains bits from the same measurement result across 64 separate shots. The next\n8 bytes contain bits for the next measurement result from the 64 separate shots. This continues until the 8 bytes\ncontaining the bits from the last measurement result, and then starts over again with data from the next 64 shots (if\nthere are more).\n\nThe shots are stored by byte order then significance order. The first shot's data goes into the least significant bit of\nthe first byte of each 8 byte group.\n\nThis format requires the number of shots to be a multiple of 64.\nThis format requires the reader to know the number of shots that were taken.\n\nThis format is generally more tedious to work with, but useful for achieving good performance on data processing tasks\nwhere it is possible to parallelize across shots using SIMD instructions.\n\n*Example of producing ptb64 format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=64, filepath=path, format=\"ptb64\")\n    ...     with open(path, 'rb') as f:\n    ...         print(' '.join(hex(e)[2:] for e in f.read()))\n    0 0 0 0 0 0 0 0 ff ff ff ff ff ff ff ff\n\n*Example ptb64 parsing code (python)*:\n```python\nfrom typing import List\n\ndef parse_ptb64(data: bytes, bits_per_shot: int) -> List[List[bool]]:\n    num_shot_groups = int(len(data) * 8 / bits_per_shot / 64)\n    if len(data) * 8 != num_shot_groups * 64 * bits_per_shot:\n        raise ValueError(\"Number of shots must be a multiple of 64.\")\n\n    result = [[False] * bits_per_shot for _ in range(num_shot_groups * 64)]\n    for group_index in range(num_shot_groups):\n        group_bit_offset = 64 * bits_per_shot * group_index\n        for m in range(bits_per_shot):\n            m_bit_offset = m * 64\n            for shot in range(64):\n                bit_offset = group_bit_offset + m_bit_offset + shot\n                bit = data[bit_offset // 8] & (1 << (bit_offset % 8)) != 0\n                s = group_index * 64 + shot\n                result[s][m] = bit\n    return result\n```\n*Example ptb64 saving code (python):*\n```python\nfrom typing import List\n\ndef save_ptb64(shots: List[List[bool]]):\n    if len(shots) % 64 != 0:\n        raise ValueError(\"Number of shots must be a multiple of 64.\")\n\n    output = []\n    for shot_offset in range(0, len(shots), 64):\n        bits_per_shot = len(shots[0])\n        for measure_index in range(bits_per_shot):\n            v = 0\n            for k in range(64)[::-1]:\n                v <<= 1\n                v += int(shots[shot_offset + k][measure_index])\n            output.append(v.to_bytes(8, 'little'))\n    return b''.join(output)\n```\n\n# <a name=\"r8\"></a>The `r8` Format\n\nThe r8 format is a sparse binary format that stores shots as a series of lengths of runs between 1s.\n\nEach byte in the data indicates how many False bits there are before the next True bit. The maximum byte value (255) is\nspecial; it indicates to include 255 False bits but not follow them by a True bit. A shot always has a terminating True\nbit appended to it before encoding. Decoding of the shot ends (and the next shot begin) when this True bit just past the\nend of the shot data is reached.\n\nThis format requires the reader to know the number of bits in each shot.\n\nThis format is useful in contexts where the number of set bits is expected to be low, e.g. when sampling detection\nevents.\n\n*Example of producing r8 format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"r8\")\n    ...     with open(path, 'rb') as f:\n    ...         print(' '.join(hex(e)[2:] for e in f.read()))\n    4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0\n\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"r8\")\n    ...     with open(path, 'rb') as f:\n    ...         print(' '.join(hex(e)[2:] for e in f.read()))\n    9 1f 9 1f 9 1f 9 1f 9 1f 9 1f 9 1f 9 1f 9 1f 9 1f\n\n*Example r8 parsing code (python)*:\n```python\nfrom typing import List\n\ndef parse_r8(data: bytes, bits_per_shot: int) -> List[List[bool]]:\n    shots = []\n    shot = []\n    for byte in data:\n        shot += [False] * byte\n        if byte != 255:\n            shot.append(True)\n        if len(shot) > bits_per_shot:\n            assert len(shot) == bits_per_shot + 1 and shot[-1]\n            shot.pop()\n            shots.append(shot)\n            shot = []\n    assert len(shot) == 0\n    return shots\n```\n*Example r8 saving code (python):*\n```python\nfrom typing import List\n\ndef save_r8(shots: List[List[bool]]) -> bytes:\n    output = []\n    for shot in shots:\n        gap = 0\n        for b in list(shot) + [True]:\n            if b:\n                while gap >= 255:\n                    gap -= 255\n                    output.append((255).to_bytes(1, 'big'))\n                output.append(gap.to_bytes(1, 'big'))\n                gap = 0\n            else:\n                gap += 1\n    return b''.join(output)\n```\n\n"
  },
  {
    "path": "doc/sinter_api.md",
    "content": "# Sinter (Development Version) API Reference\n\n*CAUTION*: this API reference is for the in-development version of sinter.\nMethods and arguments mentioned here may not be accessible in stable versions, yet.\nAPI references for stable versions are kept on the [stim github wiki](https://github.com/quantumlib/Stim/wiki)\n\n## Index\n- [`sinter.AnonTaskStats`](#sinter.AnonTaskStats)\n    - [`sinter.AnonTaskStats.__add__`](#sinter.AnonTaskStats.__add__)\n- [`sinter.CSV_HEADER`](#sinter.CSV_HEADER)\n- [`sinter.CollectionOptions`](#sinter.CollectionOptions)\n    - [`sinter.CollectionOptions.combine`](#sinter.CollectionOptions.combine)\n- [`sinter.CompiledDecoder`](#sinter.CompiledDecoder)\n    - [`sinter.CompiledDecoder.decode_shots_bit_packed`](#sinter.CompiledDecoder.decode_shots_bit_packed)\n- [`sinter.CompiledSampler`](#sinter.CompiledSampler)\n    - [`sinter.CompiledSampler.handles_throttling`](#sinter.CompiledSampler.handles_throttling)\n    - [`sinter.CompiledSampler.sample`](#sinter.CompiledSampler.sample)\n- [`sinter.Decoder`](#sinter.Decoder)\n    - [`sinter.Decoder.compile_decoder_for_dem`](#sinter.Decoder.compile_decoder_for_dem)\n    - [`sinter.Decoder.decode_via_files`](#sinter.Decoder.decode_via_files)\n- [`sinter.Fit`](#sinter.Fit)\n- [`sinter.Progress`](#sinter.Progress)\n- [`sinter.Sampler`](#sinter.Sampler)\n    - [`sinter.Sampler.compiled_sampler_for_task`](#sinter.Sampler.compiled_sampler_for_task)\n- [`sinter.Task`](#sinter.Task)\n    - [`sinter.Task.__init__`](#sinter.Task.__init__)\n    - [`sinter.Task.strong_id`](#sinter.Task.strong_id)\n    - [`sinter.Task.strong_id_bytes`](#sinter.Task.strong_id_bytes)\n    - [`sinter.Task.strong_id_text`](#sinter.Task.strong_id_text)\n    - [`sinter.Task.strong_id_value`](#sinter.Task.strong_id_value)\n- [`sinter.TaskStats`](#sinter.TaskStats)\n    - [`sinter.TaskStats.to_anon_stats`](#sinter.TaskStats.to_anon_stats)\n    - [`sinter.TaskStats.to_csv_line`](#sinter.TaskStats.to_csv_line)\n    - [`sinter.TaskStats.with_edits`](#sinter.TaskStats.with_edits)\n- [`sinter.better_sorted_str_terms`](#sinter.better_sorted_str_terms)\n- [`sinter.collect`](#sinter.collect)\n- [`sinter.comma_separated_key_values`](#sinter.comma_separated_key_values)\n- [`sinter.fit_binomial`](#sinter.fit_binomial)\n- [`sinter.fit_line_slope`](#sinter.fit_line_slope)\n- [`sinter.fit_line_y_at_x`](#sinter.fit_line_y_at_x)\n- [`sinter.group_by`](#sinter.group_by)\n- [`sinter.iter_collect`](#sinter.iter_collect)\n- [`sinter.log_binomial`](#sinter.log_binomial)\n- [`sinter.log_factorial`](#sinter.log_factorial)\n- [`sinter.plot_custom`](#sinter.plot_custom)\n- [`sinter.plot_discard_rate`](#sinter.plot_discard_rate)\n- [`sinter.plot_error_rate`](#sinter.plot_error_rate)\n- [`sinter.post_selection_mask_from_4th_coord`](#sinter.post_selection_mask_from_4th_coord)\n- [`sinter.predict_discards_bit_packed`](#sinter.predict_discards_bit_packed)\n- [`sinter.predict_observables`](#sinter.predict_observables)\n- [`sinter.predict_observables_bit_packed`](#sinter.predict_observables_bit_packed)\n- [`sinter.predict_on_disk`](#sinter.predict_on_disk)\n- [`sinter.read_stats_from_csv_files`](#sinter.read_stats_from_csv_files)\n- [`sinter.shot_error_rate_to_piece_error_rate`](#sinter.shot_error_rate_to_piece_error_rate)\n- [`sinter.stats_from_csv_files`](#sinter.stats_from_csv_files)\n```python\n# Types used by the method definitions.\nfrom typing import overload, TYPE_CHECKING, Any, Counter, Dict, Iterable, List, Optional, Tuple, Union\nimport abc\nimport dataclasses\nimport io\nimport numpy as np\nimport pathlib\nimport stim\n```\n\n<a name=\"sinter.AnonTaskStats\"></a>\n```python\n# sinter.AnonTaskStats\n\n# (at top-level in the sinter module)\n@dataclasses.dataclass(frozen=True)\nclass AnonTaskStats:\n    \"\"\"Statistics sampled from an unspecified task.\n\n    Attributes:\n        shots: Number of times the task was sampled.\n        errors: Number of times a sample resulted in an error.\n        discards: Number of times a sample resulted in a discard. Note that\n            discarded a task is not an error.\n        seconds: The amount of CPU core time spent sampling the tasks, in\n            seconds.\n        custom_counts: A counter mapping string keys to integer values. Used for\n            tracking arbitrary values, such as per-observable error counts or\n            the number of times detectors fired. The meaning of the information\n            in the counts is not specified; the only requirement is that it\n            should be correct to add each key's counts when merging statistics.\n\n            Although this field is an editable object, it's invalid to edit the\n            counter after the stats object is initialized.\n    \"\"\"\n    shots: int = 0\n    errors: int = 0\n    discards: int = 0\n    seconds: float = 0\n    custom_counts: Counter[str]\n```\n\n<a name=\"sinter.AnonTaskStats.__add__\"></a>\n```python\n# sinter.AnonTaskStats.__add__\n\n# (in class sinter.AnonTaskStats)\ndef __add__(\n    self,\n    other: sinter.AnonTaskStats,\n) -> sinter.AnonTaskStats:\n    \"\"\"Returns the sum of the statistics from both anonymous stats.\n\n    Adds the shots, the errors, the discards, and the seconds.\n\n    Examples:\n        >>> import sinter\n        >>> a = sinter.AnonTaskStats(\n        ...    shots=100,\n        ...    errors=20,\n        ... )\n        >>> b = sinter.AnonTaskStats(\n        ...    shots=1000,\n        ...    errors=200,\n        ... )\n        >>> a + b\n        sinter.AnonTaskStats(shots=1100, errors=220)\n    \"\"\"\n```\n\n<a name=\"sinter.CSV_HEADER\"></a>\n```python\n# sinter.CSV_HEADER\n\n# (at top-level in the sinter module)\nCSV_HEADER: str = '     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts'\n```\n\n<a name=\"sinter.CollectionOptions\"></a>\n```python\n# sinter.CollectionOptions\n\n# (at top-level in the sinter module)\n@dataclasses.dataclass(frozen=True)\nclass CollectionOptions:\n    \"\"\"Describes options for how data is collected for a decoding problem.\n\n    Attributes:\n        max_shots: Defaults to None (unused). Stops the sampling process\n            after this many samples have been taken from the circuit.\n        max_errors: Defaults to None (unused). Stops the sampling process\n            after this many errors have been seen in samples taken from the\n            circuit. The actual number sampled errors may be larger due to\n            batching.\n        start_batch_size: Defaults to None (collector's choice). The very\n            first shots taken from the circuit will use a batch of this\n            size, and no other batches will be taken in parallel. Once this\n            initial fact finding batch is done, batches can be taken in\n            parallel and the normal batch size limiting processes take over.\n        max_batch_size: Defaults to None (unused). Limits batches from\n            taking more than this many shots at once. For example, this can\n            be used to ensure memory usage stays below some limit.\n        max_batch_seconds: Defaults to None (unused). When set, the recorded\n            data from previous shots is used to estimate how much time is\n            taken per shot. This information is then used to predict the\n            biggest batch size that can finish in under the given number of\n            seconds. Limits each batch to be no larger than that.\n    \"\"\"\n    max_shots: Optional[int] = None\n    max_errors: Optional[int] = None\n    start_batch_size: Optional[int] = None\n    max_batch_size: Optional[int] = None\n    max_batch_seconds: Optional[float] = None\n```\n\n<a name=\"sinter.CollectionOptions.combine\"></a>\n```python\n# sinter.CollectionOptions.combine\n\n# (in class sinter.CollectionOptions)\ndef combine(\n    self,\n    other: sinter.CollectionOptions,\n) -> sinter.CollectionOptions:\n    \"\"\"Returns a combination of multiple collection options.\n\n    All fields are combined by taking the minimum from both collection\n    options objects, with None treated as being infinitely large.\n\n    Args:\n        other: The collections options to combine with.\n\n    Returns:\n        The combined collection options.\n\n    Examples:\n        >>> import sinter\n        >>> a = sinter.CollectionOptions(\n        ...    max_shots=1_000_000,\n        ...    start_batch_size=100,\n        ... )\n        >>> b = sinter.CollectionOptions(\n        ...    max_shots=100_000,\n        ...    max_errors=100,\n        ... )\n        >>> a.combine(b)\n        sinter.CollectionOptions(max_shots=100000, max_errors=100, start_batch_size=100)\n    \"\"\"\n```\n\n<a name=\"sinter.CompiledDecoder\"></a>\n```python\n# sinter.CompiledDecoder\n\n# (at top-level in the sinter module)\nclass CompiledDecoder(metaclass=abc.ABCMeta):\n    \"\"\"Abstract class for decoders preconfigured to a specific decoding task.\n\n    This is the type returned by `sinter.Decoder.compile_decoder_for_dem`. The\n    idea is that, when many shots of the same decoding task are going to be\n    performed, it is valuable to pay the cost of configuring the decoder only\n    once instead of once per batch of shots. Custom decoders can optionally\n    implement that method, and return this type, to increase sampling\n    efficiency.\n    \"\"\"\n```\n\n<a name=\"sinter.CompiledDecoder.decode_shots_bit_packed\"></a>\n```python\n# sinter.CompiledDecoder.decode_shots_bit_packed\n\n# (in class sinter.CompiledDecoder)\n@abc.abstractmethod\ndef decode_shots_bit_packed(\n    self,\n    *,\n    bit_packed_detection_event_data: np.ndarray,\n) -> np.ndarray:\n    \"\"\"Predicts observable flips from the given detection events.\n\n    All data taken and returned must be bit packed with bitorder='little'.\n\n    Args:\n        bit_packed_detection_event_data: Detection event data stored as a\n            bit packed numpy array. The numpy array will have the following\n            dtype/shape:\n\n                dtype: uint8\n                shape: (num_shots, ceil(dem.num_detectors / 8))\n\n            where `num_shots` is the number of shots to decoder and `dem` is\n            the detector error model this instance was compiled to decode.\n\n            It's guaranteed that the data will be laid out in memory so that\n            detection events within a shot are contiguous in memory (i.e.\n            that bit_packed_detection_event_data.strides[1] == 1).\n\n    Returns:\n        Bit packed observable flip data stored as a bit packed numpy array.\n        The numpy array must have the following dtype/shape:\n\n            dtype: uint8\n            shape: (num_shots, ceil(dem.num_observables / 8))\n\n        where `num_shots` is bit_packed_detection_event_data.shape[0] and\n        `dem` is the detector error model this instance was compiled to\n        decode.\n    \"\"\"\n```\n\n<a name=\"sinter.CompiledSampler\"></a>\n```python\n# sinter.CompiledSampler\n\n# (at top-level in the sinter module)\nclass CompiledSampler(metaclass=abc.ABCMeta):\n    \"\"\"A sampler that has been configured for efficiently sampling some task.\n    \"\"\"\n```\n\n<a name=\"sinter.CompiledSampler.handles_throttling\"></a>\n```python\n# sinter.CompiledSampler.handles_throttling\n\n# (in class sinter.CompiledSampler)\ndef handles_throttling(\n    self,\n) -> bool:\n    \"\"\"Return True to disable sinter wrapping samplers with throttling.\n\n    By default, sinter will wrap samplers so that they initially only do\n    a small number of shots then slowly ramp up. Sometimes this behavior\n    is not desired (e.g. in unit tests). Override this method to return True\n    to disable it.\n    \"\"\"\n```\n\n<a name=\"sinter.CompiledSampler.sample\"></a>\n```python\n# sinter.CompiledSampler.sample\n\n# (in class sinter.CompiledSampler)\n@abc.abstractmethod\ndef sample(\n    self,\n    suggested_shots: int,\n) -> sinter.AnonTaskStats:\n    \"\"\"Samples shots and returns statistics.\n\n    Args:\n        suggested_shots: The number of shots being requested. The sampler\n            may perform more shots or fewer shots than this, so technically\n            this argument can just be ignored. If a sampler is optimized for\n            a specific batch size, it can simply return one batch per call\n            regardless of this parameter.\n\n            However, this parameter is a useful hint about the amount of\n            work being done. The sampler can use this to optimize its\n            behavior. For example, it could adjust its batch size downward\n            if the suggested shots is very small. Whereas if the suggested\n            shots is very high, the sampler should focus entirely on\n            achieving the best possible throughput.\n\n            Note that, in typical workloads, the sampler will be called\n            repeatedly with the same value of suggested_shots. Therefore it\n            is reasonable to allocate buffers sized to accomodate the\n            current suggested_shots, expecting them to be useful again for\n            the next shot.\n\n    Returns:\n        A sinter.AnonTaskStats saying how many shots were actually taken,\n        how many errors were seen, etc.\n\n        The returned stats must have at least one shot.\n    \"\"\"\n```\n\n<a name=\"sinter.Decoder\"></a>\n```python\n# sinter.Decoder\n\n# (at top-level in the sinter module)\nclass Decoder:\n    \"\"\"Abstract base class for custom decoders.\n\n    Custom decoders can be explained to sinter by inheriting from this class and\n    implementing its methods.\n\n    Decoder classes MUST be serializable (e.g. via pickling), so that they can\n    be given to worker processes when using python multiprocessing.\n\n    Child classes should implement `compile_decoder_for_dem`, but (for legacy\n    reasons) can alternatively implement `decode_via_files`. At least one of\n    the two methods must be implemented.\n    \"\"\"\n```\n\n<a name=\"sinter.Decoder.compile_decoder_for_dem\"></a>\n```python\n# sinter.Decoder.compile_decoder_for_dem\n\n# (in class sinter.Decoder)\ndef compile_decoder_for_dem(\n    self,\n    *,\n    dem: stim.DetectorErrorModel,\n) -> sinter.CompiledDecoder:\n    \"\"\"Creates a decoder preconfigured for the given detector error model.\n\n    This method is optional to implement. By default, it will raise a\n    NotImplementedError. When sampling, sinter will attempt to use this\n    method first and otherwise fallback to using `decode_via_files`.\n\n    The idea is that the preconfigured decoder amortizes the cost of\n    configuration over more calls. This makes smaller batch sizes efficient,\n    reducing the amount of memory used for storing each batch, improving\n    overall efficiency.\n\n    Args:\n        dem: A detector error model for the samples that will need to be\n            decoded. What to configure the decoder to decode.\n\n    Returns:\n        An instance of `sinter.CompiledDecoder` that can be used to invoke\n        the preconfigured decoder.\n\n    Raises:\n        NotImplementedError: This `sinter.Decoder` doesn't support compiling\n            for a dem.\n    \"\"\"\n```\n\n<a name=\"sinter.Decoder.decode_via_files\"></a>\n```python\n# sinter.Decoder.decode_via_files\n\n# (in class sinter.Decoder)\ndef decode_via_files(\n    self,\n    *,\n    num_shots: int,\n    num_dets: int,\n    num_obs: int,\n    dem_path: pathlib.Path,\n    dets_b8_in_path: pathlib.Path,\n    obs_predictions_b8_out_path: pathlib.Path,\n    tmp_dir: pathlib.Path,\n) -> None:\n    \"\"\"Performs decoding by reading/writing problems and answers from disk.\n\n    Args:\n        num_shots: The number of times the circuit was sampled. The number\n            of problems to be solved.\n        num_dets: The number of detectors in the circuit. The number of\n            detection event bits in each shot.\n        num_obs: The number of observables in the circuit. The number of\n            predicted bits in each shot.\n        dem_path: The file path where the detector error model should be\n            read from, e.g. using `stim.DetectorErrorModel.from_file`. The\n            error mechanisms specified by the detector error model should be\n            used to configure the decoder.\n        dets_b8_in_path: The file path that detection event data should be\n            read from. Note that the file may be a named pipe instead of a\n            fixed size object. The detection events will be in b8 format\n            (see\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n            ). The number of detection events per shot is available via the\n            `num_dets` argument or via the detector error model at\n            `dem_path`.\n        obs_predictions_b8_out_path: The file path that decoder predictions\n            must be written to. The predictions must be written in b8 format\n            (see\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n            ). The number of observables per shot is available via the\n            `num_obs` argument or via the detector error model at\n            `dem_path`.\n        tmp_dir: Any temporary files generated by the decoder during its\n            operation MUST be put into this directory. The reason for this\n            requirement is because sinter is allowed to kill the decoding\n            process without warning, without giving it time to clean up any\n            temporary objects. All cleanup should be done via sinter\n            deleting this directory after killing the decoder.\n    \"\"\"\n```\n\n<a name=\"sinter.Fit\"></a>\n```python\n# sinter.Fit\n\n# (at top-level in the sinter module)\n@dataclasses.dataclass(frozen=True)\nclass Fit:\n    \"\"\"The result of a fitting process.\n\n    Attributes:\n        low: The hypothesis with the smallest parameter whose cost or score was\n            still \"close to\" the cost of the best hypothesis. For example, this\n            could be a hypothesis whose squared error was within some tolerance\n            of the best fit's square error, or whose likelihood was within some\n            maximum Bayes factor of the max likelihood hypothesis.\n        best: The max likelihood hypothesis. The hypothesis that had the lowest\n            squared error, or the best fitting score.\n        high: The hypothesis with the larger parameter whose cost or score was\n            still \"close to\" the cost of the best hypothesis. For example, this\n            could be a hypothesis whose squared error was within some tolerance\n            of the best fit's square error, or whose likelihood was within some\n            maximum Bayes factor of the max likelihood hypothesis.\n    \"\"\"\n    low: Optional[float]\n    best: Optional[float]\n    high: Optional[float]\n```\n\n<a name=\"sinter.Progress\"></a>\n```python\n# sinter.Progress\n\n# (at top-level in the sinter module)\n@dataclasses.dataclass(frozen=True)\nclass Progress:\n    \"\"\"Describes statistics and status messages from ongoing sampling.\n\n    This is the type yielded by `sinter.iter_collect`, and given to the\n    `progress_callback` argument of `sinter.collect`.\n\n    Attributes:\n        new_stats: New sampled statistics collected since the last progress\n            update.\n        status_message: A free form human readable string describing the current\n            collection status, such as the number of tasks left and the\n            estimated time to completion for each task.\n    \"\"\"\n    new_stats: Tuple[sinter.TaskStats, ...]\n    status_message: str\n```\n\n<a name=\"sinter.Sampler\"></a>\n```python\n# sinter.Sampler\n\n# (at top-level in the sinter module)\nclass Sampler(metaclass=abc.ABCMeta):\n    \"\"\"A strategy for producing stats from tasks.\n\n    Call `sampler.compiled_sampler_for_task(task)` to get a compiled sampler for\n    a task, then call `compiled_sampler.sample(shots)` to collect statistics.\n\n    A sampler differs from a `sinter.Decoder` because the sampler is responsible\n    for the full sampling process (e.g. simulating the circuit), whereas a\n    decoder can do nothing except predict observable flips from detection event\n    data. This prevents the decoders from cheating, but makes them less flexible\n    overall. A sampler can do things like use simulators other than stim, or\n    really anything at all as long as it ends with returning statistics about\n    shot counts, error counts, and etc.\n    \"\"\"\n```\n\n<a name=\"sinter.Sampler.compiled_sampler_for_task\"></a>\n```python\n# sinter.Sampler.compiled_sampler_for_task\n\n# (in class sinter.Sampler)\n@abc.abstractmethod\ndef compiled_sampler_for_task(\n    self,\n    task: sinter.Task,\n) -> sinter.CompiledSampler:\n    \"\"\"Creates, configures, and returns an object for sampling the task.\n    \"\"\"\n```\n\n<a name=\"sinter.Task\"></a>\n```python\n# sinter.Task\n\n# (at top-level in the sinter module)\nclass Task:\n    \"\"\"A decoding problem that sinter can sample from.\n\n    Attributes:\n        circuit: The annotated noisy circuit to sample detection event data\n            and logical observable data form.\n        decoder: The decoder to use to predict the logical observable data\n            from the detection event data. This can be set to None if it\n            will be specified later (e.g. by the call to `collect`).\n        detector_error_model: Specifies the error model to give to the decoder.\n            Defaults to None, indicating that it should be automatically derived\n            using `stim.Circuit.detector_error_model`.\n        postselection_mask: Defaults to None (unused). A bit packed bitmask\n            identifying detectors that must not fire. Shots where the\n            indicated detectors fire are discarded.\n        postselected_observables_mask: Defaults to None (unused). A bit\n            packed bitmask identifying observable indices to postselect on.\n            Anytime the decoder's predicted flip for one of these\n            observables doesn't agree with the actual measured flip value of\n            the observable, the shot is discarded instead of counting as an\n            error.\n        json_metadata: Defaults to None. Custom additional data describing\n            the problem. Must be JSON serializable. For example, this could\n            be a dictionary with \"physical_error_rate\" and \"code_distance\"\n            keys.\n        collection_options: Specifies custom options for collecting this\n            single task. These options are merged with the global options\n            to determine what happens.\n\n            For example, if a task has `collection_options` set to\n            `sinter.CollectionOptions(max_shots=1000, max_errors=100)` and\n            `sinter.collect` was called with `max_shots=500` and\n            `max_errors=200`, then either 500 shots or 100 errors will be\n            collected for the task (whichever comes first).\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> task = sinter.Task(\n        ...     circuit=stim.Circuit.generated(\n        ...         'repetition_code:memory',\n        ...         rounds=10,\n        ...         distance=10,\n        ...         before_round_data_depolarization=1e-3,\n        ...     ),\n        ... )\n    \"\"\"\n```\n\n<a name=\"sinter.Task.__init__\"></a>\n```python\n# sinter.Task.__init__\n\n# (in class sinter.Task)\ndef __init__(\n    self,\n    *,\n    circuit: Optional[stim.Circuit] = None,\n    decoder: Optional[str] = None,\n    detector_error_model: Optional[stim.DetectorErrorModel] = None,\n    postselection_mask: Optional[np.ndarray] = None,\n    postselected_observables_mask: Optional[np.ndarray] = None,\n    json_metadata: Any = None,\n    collection_options: sinter.CollectionOptions = sinter.CollectionOptions(),\n    skip_validation: bool = False,\n    circuit_path: Union[str, pathlib.Path, NoneType] = None,\n    _unvalidated_strong_id: Optional[str] = None,\n) -> None:\n    \"\"\"\n    Args:\n        circuit: The annotated noisy circuit to sample detection event data\n            and logical observable data form.\n        decoder: The decoder to use to predict the logical observable data\n            from the detection event data. This can be set to None if it\n            will be specified later (e.g. by the call to `collect`).\n        detector_error_model: Specifies the error model to give to the decoder.\n            Defaults to None, indicating that it should be automatically derived\n            using `stim.Circuit.detector_error_model`.\n        postselection_mask: Defaults to None (unused). A bit packed bitmask\n            identifying detectors that must not fire. Shots where the\n            indicated detectors fire are discarded.\n        postselected_observables_mask: Defaults to None (unused). A bit\n            packed bitmask identifying observable indices to postselect on.\n            Anytime the decoder's predicted flip for one of these\n            observables doesn't agree with the actual measured flip value of\n            the observable, the shot is discarded instead of counting as an\n            error.\n        json_metadata: Defaults to None. Custom additional data describing\n            the problem. Must be JSON serializable. For example, this could\n            be a dictionary with \"physical_error_rate\" and \"code_distance\"\n            keys.\n        collection_options: Specifies custom options for collecting this\n            single task. These options are merged with the global options\n            to determine what happens.\n\n            For example, if a task has `collection_options` set to\n            `sinter.CollectionOptions(max_shots=1000, max_errors=100)` and\n            `sinter.collect` was called with `max_shots=500` and\n            `max_errors=200`, then either 500 shots or 100 errors will be\n            collected for the task (whichever comes first).\n        skip_validation: Defaults to False. Normally the arguments given to\n            this method are checked for consistency (e.g. the detector error\n            model should have the same number of detectors as the circuit).\n            Setting this argument to True will skip doing the consistency\n            checks. Note that this can result in confusing errors later, if\n            the arguments are not actually consistent.\n        circuit_path: Typically set to None. If the circuit isn't specified,\n            this is the filepath to read it from. Not included in the strong\n            id.\n        _unvalidated_strong_id: Must be set to None unless `skip_validation`\n            is set to True. Otherwise, if this is specified then it should\n            be equal to the value returned by self.strong_id().\n    \"\"\"\n```\n\n<a name=\"sinter.Task.strong_id\"></a>\n```python\n# sinter.Task.strong_id\n\n# (in class sinter.Task)\ndef strong_id(\n    self,\n) -> str:\n    \"\"\"Computes a cryptographically unique identifier for this task.\n\n    This value is affected by:\n        - The exact circuit.\n        - The exact detector error model.\n        - The decoder.\n        - The json metadata.\n        - The postselection mask.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> task = sinter.Task(\n        ...     circuit=stim.Circuit(),\n        ...     detector_error_model=stim.DetectorErrorModel(),\n        ...     decoder='pymatching',\n        ... )\n        >>> task.strong_id()\n        '7424ea021693d4abc1c31c12e655a48779f61a7c2969e457ae4fe400c852bee5'\n    \"\"\"\n```\n\n<a name=\"sinter.Task.strong_id_bytes\"></a>\n```python\n# sinter.Task.strong_id_bytes\n\n# (in class sinter.Task)\ndef strong_id_bytes(\n    self,\n) -> bytes:\n    \"\"\"The bytes that are hashed to get the strong id.\n\n    This value is converted into the actual strong id by:\n        - Hashing these bytes using SHA256.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> task = sinter.Task(\n        ...     circuit=stim.Circuit('H 0'),\n        ...     detector_error_model=stim.DetectorErrorModel(),\n        ...     decoder='pymatching',\n        ... )\n        >>> task.strong_id_bytes()\n        b'{\"circuit\": \"H 0\", \"decoder\": \"pymatching\", \"decoder_error_model\": \"\", \"postselection_mask\": null, \"json_metadata\": null}'\n    \"\"\"\n```\n\n<a name=\"sinter.Task.strong_id_text\"></a>\n```python\n# sinter.Task.strong_id_text\n\n# (in class sinter.Task)\ndef strong_id_text(\n    self,\n) -> str:\n    \"\"\"The text that is serialized and hashed to get the strong id.\n\n    This value is converted into the actual strong id by:\n        - Serializing into bytes using UTF8.\n        - Hashing the UTF8 bytes using SHA256.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> task = sinter.Task(\n        ...     circuit=stim.Circuit('H 0'),\n        ...     detector_error_model=stim.DetectorErrorModel(),\n        ...     decoder='pymatching',\n        ... )\n        >>> task.strong_id_text()\n        '{\"circuit\": \"H 0\", \"decoder\": \"pymatching\", \"decoder_error_model\": \"\", \"postselection_mask\": null, \"json_metadata\": null}'\n    \"\"\"\n```\n\n<a name=\"sinter.Task.strong_id_value\"></a>\n```python\n# sinter.Task.strong_id_value\n\n# (in class sinter.Task)\ndef strong_id_value(\n    self,\n) -> Dict[str, Any]:\n    \"\"\"Contains all raw values that affect the strong id.\n\n    This value is converted into the actual strong id by:\n        - Serializing it into text using JSON.\n        - Serializing the JSON text into bytes using UTF8.\n        - Hashing the UTF8 bytes using SHA256.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> task = sinter.Task(\n        ...     circuit=stim.Circuit('H 0'),\n        ...     detector_error_model=stim.DetectorErrorModel(),\n        ...     decoder='pymatching',\n        ... )\n        >>> task.strong_id_value()\n        {'circuit': 'H 0', 'decoder': 'pymatching', 'decoder_error_model': '', 'postselection_mask': None, 'json_metadata': None}\n    \"\"\"\n```\n\n<a name=\"sinter.TaskStats\"></a>\n```python\n# sinter.TaskStats\n\n# (at top-level in the sinter module)\n@dataclasses.dataclass(frozen=True)\nclass TaskStats:\n    \"\"\"Statistics sampled from a task.\n\n    The rows in the CSV files produced by sinter correspond to instances of\n    `sinter.TaskStats`. For example, a row can be produced by printing a\n    `sinter.TaskStats`.\n\n    Attributes:\n        strong_id: The cryptographically unique identifier of the task, from\n            `sinter.Task.strong_id()`.\n        decoder: The name of the decoder that was used to decode the task.\n            Errors are counted when this decoder made a wrong prediction.\n        json_metadata: A JSON-encodable value (such as a dictionary from strings\n            to integers) that were included with the task in order to describe\n            what the task was. This value can be a huge variety of things, but\n            typically it will be a dictionary with fields such as 'd' for the\n            code distance.\n        shots: Number of times the task was sampled.\n        errors: Number of times a sample resulted in an error.\n        discards: Number of times a sample resulted in a discard. Note that\n            discarded a task is not an error.\n        seconds: The amount of CPU core time spent sampling the tasks, in\n            seconds.\n        custom_counts: A counter mapping string keys to integer values. Used for\n            tracking arbitrary values, such as per-observable error counts or\n            the number of times detectors fired. The meaning of the information\n            in the counts is not specified; the only requirement is that it\n            should be correct to add each key's counts when merging statistics.\n\n            Although this field is an editable object, it's invalid to edit the\n            counter after the stats object is initialized.\n    \"\"\"\n    strong_id: str\n    decoder: str\n    json_metadata: Any\n    shots: int = 0\n    errors: int = 0\n    discards: int = 0\n    seconds: float = 0\n    custom_counts: Counter[str]\n```\n\n<a name=\"sinter.TaskStats.to_anon_stats\"></a>\n```python\n# sinter.TaskStats.to_anon_stats\n\n# (in class sinter.TaskStats)\ndef to_anon_stats(\n    self,\n) -> sinter.AnonTaskStats:\n    \"\"\"Returns a `sinter.AnonTaskStats` with the same statistics.\n\n    Examples:\n        >>> import sinter\n        >>> stat = sinter.TaskStats(\n        ...     strong_id='test',\n        ...     json_metadata={'a': [1, 2, 3]},\n        ...     decoder='pymatching',\n        ...     shots=22,\n        ...     errors=3,\n        ...     discards=4,\n        ...     seconds=5,\n        ... )\n        >>> stat.to_anon_stats()\n        sinter.AnonTaskStats(shots=22, errors=3, discards=4, seconds=5)\n    \"\"\"\n```\n\n<a name=\"sinter.TaskStats.to_csv_line\"></a>\n```python\n# sinter.TaskStats.to_csv_line\n\n# (in class sinter.TaskStats)\ndef to_csv_line(\n    self,\n) -> str:\n    \"\"\"Converts into a line that can be printed into a CSV file.\n\n    Examples:\n        >>> import sinter\n        >>> stat = sinter.TaskStats(\n        ...     strong_id='test',\n        ...     json_metadata={'a': [1, 2, 3]},\n        ...     decoder='pymatching',\n        ...     shots=22,\n        ...     errors=3,\n        ...     seconds=5,\n        ... )\n        >>> print(sinter.CSV_HEADER)\n             shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts\n        >>> print(stat.to_csv_line())\n                22,         3,         0,    5.00,pymatching,test,\"{\"\"a\"\":[1,2,3]}\",\n    \"\"\"\n```\n\n<a name=\"sinter.TaskStats.with_edits\"></a>\n```python\n# sinter.TaskStats.with_edits\n\n# (in class sinter.TaskStats)\ndef with_edits(\n    self,\n    *,\n    strong_id: Optional[str] = None,\n    decoder: Optional[str] = None,\n    json_metadata: Optional[Any] = None,\n    shots: Optional[int] = None,\n    errors: Optional[int] = None,\n    discards: Optional[int] = None,\n    seconds: Optional[float] = None,\n    custom_counts: Optional[Counter[str]] = None,\n) -> sinter.TaskStats:\n```\n\n<a name=\"sinter.better_sorted_str_terms\"></a>\n```python\n# sinter.better_sorted_str_terms\n\n# (at top-level in the sinter module)\ndef better_sorted_str_terms(\n    val: Any,\n) -> Any:\n    \"\"\"A function that orders \"a10000\" after \"a9\", instead of before.\n\n    Normally, sorting strings sorts them lexicographically, treating numbers so\n    that \"1999999\" ends up being less than \"2\". This method splits the string\n    into a tuple of text pairs and parsed number parts, so that sorting by this\n    key puts \"2\" before \"1999999\".\n\n    Because this method is intended for use in plotting, where it's more\n    important to see a bad result than to see nothing, it returns a type that\n    tries to be comparable to everything.\n\n    Args:\n        val: The value to convert into a value with a better sorting order.\n\n    Returns:\n        A custom type of object with a better sorting order.\n\n    Examples:\n        >>> import sinter\n        >>> items = [\n        ...    \"distance=199999, rounds=3\",\n        ...    \"distance=2, rounds=3\",\n        ...    \"distance=199999, rounds=199999\",\n        ...    \"distance=2, rounds=199999\",\n        ... ]\n        >>> for e in sorted(items, key=sinter.better_sorted_str_terms):\n        ...    print(e)\n        distance=2, rounds=3\n        distance=2, rounds=199999\n        distance=199999, rounds=3\n        distance=199999, rounds=199999\n    \"\"\"\n```\n\n<a name=\"sinter.collect\"></a>\n```python\n# sinter.collect\n\n# (at top-level in the sinter module)\ndef collect(\n    *,\n    num_workers: int,\n    tasks: Union[Iterator[sinter.Task], Iterable[sinter.Task]],\n    existing_data_filepaths: Iterable[Union[str, pathlib.Path]] = (),\n    save_resume_filepath: Union[NoneType, str, pathlib.Path] = None,\n    progress_callback: Optional[Callable[[sinter.Progress], NoneType]] = None,\n    max_shots: Optional[int] = None,\n    max_errors: Optional[int] = None,\n    count_observable_error_combos: bool = False,\n    count_detection_events: bool = False,\n    decoders: Optional[Iterable[str]] = None,\n    max_batch_seconds: Optional[int] = None,\n    max_batch_size: Optional[int] = None,\n    start_batch_size: Optional[int] = None,\n    print_progress: bool = False,\n    hint_num_tasks: Optional[int] = None,\n    custom_decoders: Optional[Dict[str, Union[sinter.Decoder, sinter.Sampler]]] = None,\n    custom_error_count_key: Optional[str] = None,\n    allowed_cpu_affinity_ids: Optional[Iterable[int]] = None,\n) -> List[sinter.TaskStats]:\n    \"\"\"Collects statistics from the given tasks, using multiprocessing.\n\n    Args:\n        num_workers: The number of worker processes to use.\n        tasks: Decoding problems to sample.\n        save_resume_filepath: Defaults to None (unused). If set to a filepath,\n            results will be saved to that file while they are collected. If the\n            python interpreter is stopped or killed, calling this method again\n            with the same save_resume_filepath will load the previous results\n            from the file so it can resume where it left off.\n\n            The stats in this file will be counted in addition to each task's\n            previous_stats field (as opposed to overriding the field).\n        existing_data_filepaths: CSV data saved to these files will be loaded,\n            included in the returned results, and count towards things like\n            max_shots and max_errors.\n        progress_callback: Defaults to None (unused). If specified, then each\n            time new sample statistics are acquired from a worker this method\n            will be invoked with the new `sinter.TaskStats`.\n        hint_num_tasks: If `tasks` is an iterator or a generator, its length\n            can be given here so that progress printouts can say how many cases\n            are left.\n        decoders: Defaults to None (specified by each Task). The names of the\n            decoders to use on each Task. It must either be the case that each\n            Task specifies a decoder and this is set to None, or this is an\n            iterable and each Task has its decoder set to None.\n        count_observable_error_combos: Defaults to False. When set to to True,\n            the returned stats will have a custom counts field with keys\n            like `obs_mistake_mask=E_E__` counting how many times specific\n            combinations of observables were mispredicted by the decoder.\n        count_detection_events: Defaults to False. When set to True, the\n            returned stats will have a custom counts field withs the\n            key `detection_events` counting the number of times a detector fired\n            and also `detectors_checked` counting the number of detectors that\n            were executed. The detection fraction is the ratio of these two\n            numbers.\n        max_shots: Defaults to None (unused). Stops the sampling process\n            after this many samples have been taken from the circuit.\n        max_errors: Defaults to None (unused). Stops the sampling process\n            after this many errors have been seen in samples taken from the\n            circuit. The actual number sampled errors may be larger due to\n            batching.\n        start_batch_size: Defaults to None (collector's choice). The very\n            first shots taken from the circuit will use a batch of this\n            size, and no other batches will be taken in parallel. Once this\n            initial fact finding batch is done, batches can be taken in\n            parallel and the normal batch size limiting processes take over.\n        max_batch_size: Defaults to None (unused). Limits batches from\n            taking more than this many shots at once. For example, this can\n            be used to ensure memory usage stays below some limit.\n        print_progress: When True, progress is printed to stderr while\n            collection runs.\n        max_batch_seconds: Defaults to None (unused). When set, the recorded\n            data from previous shots is used to estimate how much time is\n            taken per shot. This information is then used to predict the\n            biggest batch size that can finish in under the given number of\n            seconds. Limits each batch to be no larger than that.\n        custom_decoders: Named child classes of `sinter.decoder`, that can be\n            used if requested by name by a task or by the decoders list.\n            If not specified, only decoders with support built into sinter, such\n            as 'pymatching' and 'fusion_blossom', can be used.\n        custom_error_count_key: Makes `max_errors` apply to `stat.custom_counts[key]`\n            instead of `stat.errors`.\n        allowed_cpu_affinity_ids: Controls which CPUs the workers can be pinned to. The\n            set of allowed IDs should be at least as large as the number of workers, though\n            this is not strictly required. If not set, defaults to all CPUs being allowed.\n\n    Returns:\n        A list of sample statistics, one from each problem. The list is not in\n        any specific order. This is the same data that would have been written\n        to a CSV file, but aggregated so that each problem has exactly one\n        sample statistic instead of potentially multiple.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> tasks = [\n        ...     sinter.Task(\n        ...         circuit=stim.Circuit.generated(\n        ...             'repetition_code:memory',\n        ...             distance=5,\n        ...             rounds=5,\n        ...             before_round_data_depolarization=1e-3,\n        ...         ),\n        ...         json_metadata={'d': 5},\n        ...     ),\n        ...     sinter.Task(\n        ...         circuit=stim.Circuit.generated(\n        ...             'repetition_code:memory',\n        ...             distance=7,\n        ...             rounds=5,\n        ...             before_round_data_depolarization=1e-3,\n        ...         ),\n        ...         json_metadata={'d': 7},\n        ...     ),\n        ... ]\n        >>> stats = sinter.collect(\n        ...     tasks=tasks,\n        ...     decoders=['vacuous'],\n        ...     num_workers=2,\n        ...     max_shots=100,\n        ... )\n        >>> for stat in sorted(stats, key=lambda e: e.json_metadata['d']):\n        ...     print(stat.json_metadata, stat.shots)\n        {'d': 5} 100\n        {'d': 7} 100\n    \"\"\"\n```\n\n<a name=\"sinter.comma_separated_key_values\"></a>\n```python\n# sinter.comma_separated_key_values\n\n# (at top-level in the sinter module)\ndef comma_separated_key_values(\n    path: str,\n) -> Dict[str, Any]:\n    \"\"\"Converts paths like 'folder/d=5,r=3.stim' into dicts like {'d':5,'r':3}.\n\n    On the command line, specifying `--metadata_func auto` results in this\n    method being used to extra metadata from the circuit file paths. Integers\n    and floats will be parsed into their values, instead of being stored as\n    strings.\n\n    Args:\n        path: A file path where the name of the file has a series of terms like\n            'a=b' separated by commas and ending in '.stim'.\n\n    Returns:\n        A dictionary from named keys to parsed values.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.comma_separated_key_values(\"folder/d=5,r=3.5,x=abc.stim\")\n        {'d': 5, 'r': 3.5, 'x': 'abc'}\n    \"\"\"\n```\n\n<a name=\"sinter.fit_binomial\"></a>\n```python\n# sinter.fit_binomial\n\n# (at top-level in the sinter module)\ndef fit_binomial(\n    *,\n    num_shots: int,\n    num_hits: int,\n    max_likelihood_factor: float,\n) -> sinter.Fit:\n    \"\"\"Determine hypothesis probabilities compatible with the given hit ratio.\n\n    The result includes the best fit (the max likelihood hypothis) as well as\n    the smallest and largest probabilities whose likelihood is within the given\n    factor of the maximum likelihood hypothesis.\n\n    Args:\n        num_shots: The number of samples that were taken.\n        num_hits: The number of hits that were seen in the samples.\n        max_likelihood_factor: The maximum Bayes factor between the low/high\n            hypotheses and the best hypothesis (the max likelihood hypothesis).\n            This value should be larger than 1 (as opposed to between 0 and 1).\n\n    Returns:\n        A `sinter.Fit` with the low, best, and high hypothesis probabilities.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.fit_binomial(\n        ...     num_shots=100_000_000,\n        ...     num_hits=2,\n        ...     max_likelihood_factor=1000,\n        ... )\n        sinter.Fit(low=2e-10, best=2e-08, high=1.259e-07)\n        >>> sinter.fit_binomial(\n        ...     num_shots=10,\n        ...     num_hits=5,\n        ...     max_likelihood_factor=9,\n        ... )\n        sinter.Fit(low=0.202, best=0.5, high=0.798)\n    \"\"\"\n```\n\n<a name=\"sinter.fit_line_slope\"></a>\n```python\n# sinter.fit_line_slope\n\n# (at top-level in the sinter module)\ndef fit_line_slope(\n    *,\n    xs: Sequence[float],\n    ys: Sequence[float],\n    max_extra_squared_error: float,\n) -> sinter.Fit:\n    \"\"\"Performs a line fit of the given points, focusing on the line's slope.\n\n    Finds the slope of the best fit, but also the minimum and maximum slopes\n    for line fits whose squared error cost is within the given\n    `max_extra_squared_error` cost of the best fit.\n\n    Note that the extra squared error is computed while including a specific\n    offset of some specific line. So the low/high estimates are for specific\n    lines, not for the general class of lines with a given slope, adding\n    together the contributions of all lines in that class.\n\n    Args:\n        xs: The x coordinates of points to fit.\n        ys: The y coordinates of points to fit.\n        max_extra_squared_error: When computing the low and high fits, this is\n            the maximum additional squared error that can be introduced by\n            varying the slope away from the best fit.\n\n    Returns:\n        A sinter.Fit containing the best fit, as well as low and high fits that\n        are as far as possible from the best fit while respective the given\n        max_extra_squared_error.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.fit_line_slope(\n        ...     xs=[1, 2, 3],\n        ...     ys=[10, 12, 14],\n        ...     max_extra_squared_error=1,\n        ... )\n        sinter.Fit(low=1.2928924560546875, best=2.0, high=2.7071075439453125)\n    \"\"\"\n```\n\n<a name=\"sinter.fit_line_y_at_x\"></a>\n```python\n# sinter.fit_line_y_at_x\n\n# (at top-level in the sinter module)\ndef fit_line_y_at_x(\n    *,\n    xs: Sequence[float],\n    ys: Sequence[float],\n    target_x: float,\n    max_extra_squared_error: float,\n) -> sinter.Fit:\n    \"\"\"Performs a line fit, focusing on the line's y coord at a given x coord.\n\n    Finds the y value at the given x of the best fit, but also the minimum and\n    maximum values for y at the given x amongst all possible line fits whose\n    squared error cost is within the given `max_extra_squared_error` cost of the\n    best fit.\n\n    Args:\n        xs: The x coordinates of points to fit.\n        ys: The y coordinates of points to fit.\n        target_x: The fit values are the value of y at this x coordinate.\n        max_extra_squared_error: When computing the low and high fits, this is\n            the maximum additional squared error that can be introduced by\n            varying the slope away from the best fit.\n\n    Returns:\n        A sinter.Fit containing the best fit for y at the given x, as well as\n        low and high fits that are as far as possible from the best fit while\n        respecting the given max_extra_squared_error.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.fit_line_y_at_x(\n        ...     xs=[1, 2, 3],\n        ...     ys=[10, 12, 14],\n        ...     target_x=4,\n        ...     max_extra_squared_error=1,\n        ... )\n        sinter.Fit(low=14.47247314453125, best=16.0, high=17.52752685546875)\n    \"\"\"\n```\n\n<a name=\"sinter.group_by\"></a>\n```python\n# sinter.group_by\n\n# (at top-level in the sinter module)\ndef group_by(\n    items: Iterable[~TVal],\n    *,\n    key: Callable[[~TVal], ~TKey],\n) -> Dict[~TKey, List[~TVal]]:\n    \"\"\"Groups items based on whether they produce the same key from a function.\n\n    Args:\n        items: The items to group.\n        key: Items that produce the same value from this function get grouped together.\n\n    Returns:\n        A dictionary mapping outputs that were produced by the grouping function to\n        the list of items that produced that output.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.group_by([1, 2, 3], key=lambda i: i == 2)\n        {False: [1, 3], True: [2]}\n\n        >>> sinter.group_by(range(10), key=lambda i: i % 3)\n        {0: [0, 3, 6, 9], 1: [1, 4, 7], 2: [2, 5, 8]}\n    \"\"\"\n```\n\n<a name=\"sinter.iter_collect\"></a>\n```python\n# sinter.iter_collect\n\n# (at top-level in the sinter module)\ndef iter_collect(\n    *,\n    num_workers: int,\n    tasks: Union[Iterator[sinter.Task], Iterable[sinter.Task]],\n    hint_num_tasks: Optional[int] = None,\n    additional_existing_data: Union[NoneType, Dict[str, sinter.TaskStats], Iterable[sinter.TaskStats]] = None,\n    max_shots: Optional[int] = None,\n    max_errors: Optional[int] = None,\n    decoders: Optional[Iterable[str]] = None,\n    max_batch_seconds: Optional[int] = None,\n    max_batch_size: Optional[int] = None,\n    start_batch_size: Optional[int] = None,\n    count_observable_error_combos: bool = False,\n    count_detection_events: bool = False,\n    custom_decoders: Optional[Dict[str, Union[sinter.Decoder, sinter.Sampler]]] = None,\n    custom_error_count_key: Optional[str] = None,\n    allowed_cpu_affinity_ids: Optional[Iterable[int]] = None,\n) -> Iterator[sinter.Progress]:\n    \"\"\"Iterates error correction statistics collected from worker processes.\n\n    It is important to iterate until the sequence ends, or worker processes will\n    be left alive. The values yielded during iteration are progress updates from\n    the workers.\n\n    Note: if max_batch_size and max_batch_seconds are both not used (or\n    explicitly set to None), a default batch-size-limiting mechanism will be\n    chosen.\n\n    Args:\n        num_workers: The number of worker processes to use.\n        tasks: Decoding problems to sample.\n        hint_num_tasks: If `tasks` is an iterator or a generator, its length\n            can be given here so that progress printouts can say how many cases\n            are left.\n        additional_existing_data: Defaults to None (no additional data).\n            Statistical data that has already been collected, in addition to\n            anything included in each task's `previous_stats` field.\n        decoders: Defaults to None (specified by each Task). The names of the\n            decoders to use on each Task. It must either be the case that each\n            Task specifies a decoder and this is set to None, or this is an\n            iterable and each Task has its decoder set to None.\n        max_shots: Defaults to None (unused). Stops the sampling process\n            after this many samples have been taken from the circuit.\n        max_errors: Defaults to None (unused). Stops the sampling process\n            after this many errors have been seen in samples taken from the\n            circuit. The actual number sampled errors may be larger due to\n            batching.\n        count_observable_error_combos: Defaults to False. When set to to True,\n            the returned stats will have a custom counts field with keys\n            like `obs_mistake_mask=E_E__` counting how many times specific\n            combinations of observables were mispredicted by the decoder.\n        count_detection_events: Defaults to False. When set to True, the\n            returned stats will have a custom counts field withs the\n            key `detection_events` counting the number of times a detector fired\n            and also `detectors_checked` counting the number of detectors that\n            were executed. The detection fraction is the ratio of these two\n            numbers.\n        start_batch_size: Defaults to None (collector's choice). The very\n            first shots taken from the circuit will use a batch of this\n            size, and no other batches will be taken in parallel. Once this\n            initial fact finding batch is done, batches can be taken in\n            parallel and the normal batch size limiting processes take over.\n        max_batch_size: Defaults to None (unused). Limits batches from\n            taking more than this many shots at once. For example, this can\n            be used to ensure memory usage stays below some limit.\n        max_batch_seconds: Defaults to None (unused). When set, the recorded\n            data from previous shots is used to estimate how much time is\n            taken per shot. This information is then used to predict the\n            biggest batch size that can finish in under the given number of\n            seconds. Limits each batch to be no larger than that.\n        custom_decoders: Custom decoders that can be used if requested by name.\n            If not specified, only decoders built into sinter, such as\n            'pymatching' and 'fusion_blossom', can be used.\n        custom_error_count_key: Makes `max_errors` apply to `stat.custom_counts[key]`\n            instead of `stat.errors`.\n        allowed_cpu_affinity_ids: Controls which CPUs the workers can be pinned to. The\n            set of allowed IDs should be at least as large as the number of workers, though\n            this is not strictly required. If not set, defaults to all CPUs being allowed.\n\n    Yields:\n        sinter.Progress instances recording incremental statistical data as it\n        is collected by workers.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> tasks = [\n        ...     sinter.Task(\n        ...         circuit=stim.Circuit.generated(\n        ...             'repetition_code:memory',\n        ...             distance=5,\n        ...             rounds=5,\n        ...             before_round_data_depolarization=1e-3,\n        ...         ),\n        ...         json_metadata={'d': 5},\n        ...     ),\n        ...     sinter.Task(\n        ...         circuit=stim.Circuit.generated(\n        ...             'repetition_code:memory',\n        ...             distance=7,\n        ...             rounds=5,\n        ...             before_round_data_depolarization=1e-3,\n        ...         ),\n        ...         json_metadata={'d': 7},\n        ...     ),\n        ... ]\n        >>> iterator = sinter.iter_collect(\n        ...     tasks=tasks,\n        ...     decoders=['vacuous'],\n        ...     num_workers=2,\n        ...     max_shots=100,\n        ... )\n        >>> total_shots = 0\n        >>> for progress in iterator:\n        ...     for stat in progress.new_stats:\n        ...         total_shots += stat.shots\n        >>> print(total_shots)\n        200\n    \"\"\"\n```\n\n<a name=\"sinter.log_binomial\"></a>\n```python\n# sinter.log_binomial\n\n# (at top-level in the sinter module)\ndef log_binomial(\n    *,\n    p: Union[float, np.ndarray],\n    n: int,\n    hits: int,\n) -> np.ndarray:\n    \"\"\"Approximates the natural log of a binomial distribution's probability.\n\n    When working with large binomials, it's often necessary to work in log space\n    to represent the result. For example, suppose that out of two million\n    samples 200_000 are hits. The maximum likelihood estimate is p=0.2. Even if\n    this is the true probability, the chance of seeing *exactly* 20% hits out of\n    a million shots is roughly 10^-217322. Whereas the smallest representable\n    double is roughly 10^-324. But ln(10^-217322) ~= -500402.4 is representable.\n\n    This method evaluates $\\ln(P(hits = B(n, p)))$, with all computations done\n    in log space to ensure intermediate values can be represented as floating\n    point numbers without underflowing to 0 or overflowing to infinity. This\n    method can be broadcast over multiple hypothesis probabilities by giving a\n    numpy array for `p` instead of a single float.\n\n    Args:\n        p: The hypotehsis probability. The independent probability of a hit\n            occurring for each sample. This can also be an array of\n            probabilities, in which case the function is broadcast over the\n            array.\n        n: The number of samples that were taken.\n        hits: The number of hits that were observed amongst the samples that\n            were taken.\n\n    Returns:\n        $\\ln(P(hits = B(n, p)))$\n\n    Examples:\n        >>> import sinter\n        >>> sinter.log_binomial(p=0.5, n=100, hits=50)\n        array(-2.5308762, dtype=float32)\n        >>> sinter.log_binomial(p=0.2, n=1_000_000, hits=1_000)\n        array(-216626.97, dtype=float32)\n        >>> sinter.log_binomial(p=0.1, n=1_000_000, hits=1_000)\n        array(-99654.86, dtype=float32)\n        >>> sinter.log_binomial(p=0.01, n=1_000_000, hits=1_000)\n        array(-6742.573, dtype=float32)\n        >>> sinter.log_binomial(p=[0.01, 0.1, 0.2], n=1_000_000, hits=1_000)\n        array([  -6742.573,  -99654.86 , -216626.97 ], dtype=float32)\n    \"\"\"\n```\n\n<a name=\"sinter.log_factorial\"></a>\n```python\n# sinter.log_factorial\n\n# (at top-level in the sinter module)\ndef log_factorial(\n    n: int,\n) -> float:\n    \"\"\"Approximates $\\ln(n!)$; the natural logarithm of a factorial.\n\n    Args:\n        n: The input to the factorial.\n\n    Returns:\n        Evaluates $ln(n!)$ using `math.lgamma(n+1)`.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.log_factorial(0)\n        0.0\n        >>> sinter.log_factorial(1)\n        0.0\n        >>> sinter.log_factorial(2)\n        0.693147180559945\n        >>> sinter.log_factorial(100)\n        363.73937555556347\n    \"\"\"\n```\n\n<a name=\"sinter.plot_custom\"></a>\n```python\n# sinter.plot_custom\n\n# (at top-level in the sinter module)\ndef plot_custom(\n    *,\n    ax: 'plt.Axes',\n    stats: 'Iterable[sinter.TaskStats]',\n    x_func: Callable[[sinter.TaskStats], Any],\n    y_func: Callable[[sinter.TaskStats], Union[sinter.Fit, float, int]],\n    group_func: Callable[[sinter.TaskStats], ~TCurveId] = lambda _: None,\n    point_label_func: Callable[[sinter.TaskStats], Any] = lambda _: None,\n    filter_func: Callable[[sinter.TaskStats], Any] = lambda _: True,\n    plot_args_func: Callable[[int, ~TCurveId, List[sinter.TaskStats]], Dict[str, Any]] = lambda index, group_key, group_stats: dict(),\n    line_fits: Optional[Tuple[Literal['linear', 'log', 'sqrt'], Literal['linear', 'log', 'sqrt']]] = None,\n) -> None:\n    \"\"\"Plots error rates in curves with uncertainty highlights.\n\n    Args:\n        ax: The plt.Axes to plot onto. For example, the `ax` value from `fig, ax = plt.subplots(1, 1)`.\n        stats: The collected statistics to plot.\n        x_func: The X coordinate to use for each stat's data point. For example, this could be\n            `x_func=lambda stat: stat.json_metadata['physical_error_rate']`.\n        y_func: The Y value to use for each stat's data point. This can be a float or it can be a\n            sinter.Fit value, in which case the curve will follow the fit.best value and a\n            highlighted area will be shown from fit.low to fit.high.\n        group_func: Optional. When specified, multiple curves will be plotted instead of one curve.\n            The statistics are grouped into curves based on whether or not they get the same result\n            out of this function. For example, this could be `group_func=lambda stat: stat.decoder`.\n            If the result of the function is a dictionary, then optional keys in the dictionary will\n            also control the plotting of each curve. Available keys are:\n                'label': the label added to the legend for the curve\n                'color': the color used for plotting the curve\n                'marker': the marker used for the curve\n                'linestyle': the linestyle used for the curve\n                'sort': the order in which the curves will be plotted and added to the legend\n            e.g. if two curves (with different resulting dictionaries from group_func) share the same\n            value for key 'marker', they will be plotted with the same marker.\n            Colors, markers and linestyles are assigned in order, sorted by the values for those keys.\n        point_label_func: Optional. Specifies text to draw next to data points.\n        filter_func: Optional. When specified, some curves will not be plotted.\n            The statistics are filtered and only plotted if filter_func(stat) returns True.\n            For example, `filter_func=lambda s: s.json_metadata['basis'] == 'x'` would plot only stats\n            where the saved metadata indicates the basis was 'x'.\n        plot_args_func: Optional. Specifies additional arguments to give the underlying calls to\n            `plot` and `fill_between` used to do the actual plotting. For example, this can be used\n            to specify markers and colors. Takes the index of the curve in sorted order and also a\n            curve_id (these will be 0 and None respectively if group_func is not specified). For example,\n            this could be:\n\n                plot_args_func=lambda index, group_key, group_stats: {\n                    'color': (\n                        'red'\n                        if group_key == 'decoder=pymatching p=0.001'\n                        else 'blue'\n                    ),\n                }\n        line_fits: Defaults to None. Set this to a tuple (x_scale, y_scale) to include a dashed line\n            fit to every curve. The scales determine how to transform the coordinates before\n            performing the fit, and can be set to 'linear', 'sqrt', or 'log'.\n    \"\"\"\n```\n\n<a name=\"sinter.plot_discard_rate\"></a>\n```python\n# sinter.plot_discard_rate\n\n# (at top-level in the sinter module)\ndef plot_discard_rate(\n    *,\n    ax: 'plt.Axes',\n    stats: 'Iterable[sinter.TaskStats]',\n    x_func: Callable[[sinter.TaskStats], Any],\n    failure_units_per_shot_func: Callable[[sinter.TaskStats], Any] = lambda _: 1,\n    group_func: Callable[[sinter.TaskStats], ~TCurveId] = lambda _: None,\n    filter_func: Callable[[sinter.TaskStats], Any] = lambda _: True,\n    plot_args_func: Callable[[int, ~TCurveId, List[sinter.TaskStats]], Dict[str, Any]] = lambda index, group_key, group_stats: dict(),\n    highlight_max_likelihood_factor: Optional[float] = 1000.0,\n    point_label_func: Callable[[sinter.TaskStats], Any] = lambda _: None,\n) -> None:\n    \"\"\"Plots discard rates in curves with uncertainty highlights.\n\n    Args:\n        ax: The plt.Axes to plot onto. For example, the `ax` value from `fig, ax = plt.subplots(1, 1)`.\n        stats: The collected statistics to plot.\n        x_func: The X coordinate to use for each stat's data point. For example, this could be\n            `x_func=lambda stat: stat.json_metadata['physical_error_rate']`.\n        failure_units_per_shot_func: How many discard chances there are per shot. This rescales what the\n            discard rate means. By default, it is the discard rate per shot, but this allows\n            you to instead make it the discard rate per round. For example, if the metadata\n            associated with a shot has a field 'r' which is the number of rounds, then this can be\n            achieved with `failure_units_per_shot_func=lambda stats: stats.metadata['r']`.\n        group_func: Optional. When specified, multiple curves will be plotted instead of one curve.\n            The statistics are grouped into curves based on whether or not they get the same result\n            out of this function. For example, this could be `group_func=lambda stat: stat.decoder`.\n            If the result of the function is a dictionary, then optional keys in the dictionary will\n            also control the plotting of each curve. Available keys are:\n                'label': the label added to the legend for the curve\n                'color': the color used for plotting the curve\n                'marker': the marker used for the curve\n                'linestyle': the linestyle used for the curve\n                'sort': the order in which the curves will be plotted and added to the legend\n            e.g. if two curves (with different resulting dictionaries from group_func) share the same\n            value for key 'marker', they will be plotted with the same marker.\n            Colors, markers and linestyles are assigned in order, sorted by the values for those keys.\n        filter_func: Optional. When specified, some curves will not be plotted.\n            The statistics are filtered and only plotted if filter_func(stat) returns True.\n            For example, `filter_func=lambda s: s.json_metadata['basis'] == 'x'` would plot only stats\n            where the saved metadata indicates the basis was 'x'.\n        plot_args_func: Optional. Specifies additional arguments to give the underlying calls to\n            `plot` and `fill_between` used to do the actual plotting. For example, this can be used\n            to specify markers and colors. Takes the index of the curve in sorted order and also a\n            curve_id (these will be 0 and None respectively if group_func is not specified). For example,\n            this could be:\n\n                plot_args_func=lambda index, curve_id: {'color': 'red'\n                                                        if curve_id == 'pymatching'\n                                                        else 'blue'}\n\n        highlight_max_likelihood_factor: Controls how wide the uncertainty highlight region around curves is.\n            Must be 1 or larger. Hypothesis probabilities at most that many times as unlikely as the max likelihood\n            hypothesis will be highlighted.\n        point_label_func: Optional. Specifies text to draw next to data points.\n    \"\"\"\n```\n\n<a name=\"sinter.plot_error_rate\"></a>\n```python\n# sinter.plot_error_rate\n\n# (at top-level in the sinter module)\ndef plot_error_rate(\n    *,\n    ax: 'plt.Axes',\n    stats: 'Iterable[sinter.TaskStats]',\n    x_func: Callable[[sinter.TaskStats], Any],\n    failure_units_per_shot_func: Callable[[sinter.TaskStats], Any] = lambda _: 1,\n    failure_values_func: Callable[[sinter.TaskStats], Any] = lambda _: 1,\n    group_func: Callable[[sinter.TaskStats], ~TCurveId] = lambda _: None,\n    filter_func: Callable[[sinter.TaskStats], Any] = lambda _: True,\n    plot_args_func: Callable[[int, ~TCurveId, List[sinter.TaskStats]], Dict[str, Any]] = lambda index, group_key, group_stats: dict(),\n    highlight_max_likelihood_factor: Optional[float] = 1000.0,\n    line_fits: Optional[Tuple[Literal['linear', 'log', 'sqrt'], Literal['linear', 'log', 'sqrt']]] = None,\n    point_label_func: Callable[[sinter.TaskStats], Any] = lambda _: None,\n) -> None:\n    \"\"\"Plots error rates in curves with uncertainty highlights.\n\n    Args:\n        ax: The plt.Axes to plot onto. For example, the `ax` value from `fig, ax = plt.subplots(1, 1)`.\n        stats: The collected statistics to plot.\n        x_func: The X coordinate to use for each stat's data point. For example, this could be\n            `x_func=lambda stat: stat.json_metadata['physical_error_rate']`.\n        failure_units_per_shot_func: How many error chances there are per shot. This rescales what the\n            logical error rate means. By default, it is the logical error rate per shot, but this allows\n            you to instead make it the logical error rate per round. For example, if the metadata\n            associated with a shot has a field 'r' which is the number of rounds, then this can be\n            achieved with `failure_units_per_shot_func=lambda stats: stats.metadata['r']`.\n        failure_values_func: How many independent ways there are for a shot to fail, such as\n            the number of independent observables in a memory experiment. This affects how the failure\n            units rescaling plays out (e.g. with 1 independent failure the \"center\" of the conversion\n            is at 50% whereas for 2 independent failures the \"center\" is at 75%).\n        group_func: Optional. When specified, multiple curves will be plotted instead of one curve.\n            The statistics are grouped into curves based on whether or not they get the same result\n            out of this function. For example, this could be `group_func=lambda stat: stat.decoder`.\n            If the result of the function is a dictionary, then optional keys in the dictionary will\n            also control the plotting of each curve. Available keys are:\n                'label': the label added to the legend for the curve\n                'color': the color used for plotting the curve\n                'marker': the marker used for the curve\n                'linestyle': the linestyle used for the curve\n                'sort': the order in which the curves will be plotted and added to the legend\n            e.g. if two curves (with different resulting dictionaries from group_func) share the same\n            value for key 'marker', they will be plotted with the same marker.\n            Colors, markers and linestyles are assigned in order, sorted by the values for those keys.\n        filter_func: Optional. When specified, some curves will not be plotted.\n            The statistics are filtered and only plotted if filter_func(stat) returns True.\n            For example, `filter_func=lambda s: s.json_metadata['basis'] == 'x'` would plot only stats\n            where the saved metadata indicates the basis was 'x'.\n        plot_args_func: Optional. Specifies additional arguments to give the underlying calls to\n            `plot` and `fill_between` used to do the actual plotting. For example, this can be used\n            to specify markers and colors. Takes the index of the curve in sorted order and also a\n            curve_id (these will be 0 and None respectively if group_func is not specified). For example,\n            this could be:\n\n                plot_args_func=lambda index, curve_id: {'color': 'red'\n                                                        if curve_id == 'pymatching'\n                                                        else 'blue'}\n\n        highlight_max_likelihood_factor: Controls how wide the uncertainty highlight region around curves is.\n            Must be 1 or larger. Hypothesis probabilities at most that many times as unlikely as the max likelihood\n            hypothesis will be highlighted.\n        line_fits: Defaults to None. Set this to a tuple (x_scale, y_scale) to include a dashed line\n            fit to every curve. The scales determine how to transform the coordinates before\n            performing the fit, and can be set to 'linear', 'sqrt', or 'log'.\n        point_label_func: Optional. Specifies text to draw next to data points.\n    \"\"\"\n```\n\n<a name=\"sinter.post_selection_mask_from_4th_coord\"></a>\n```python\n# sinter.post_selection_mask_from_4th_coord\n\n# (at top-level in the sinter module)\ndef post_selection_mask_from_4th_coord(\n    dem: Union[stim.Circuit, stim.DetectorErrorModel],\n) -> np.ndarray:\n    \"\"\"Returns a mask that postselects detector's with non-zero 4th coordinate.\n\n    This method is a leftover from before the existence of the command line\n    argument `--postselected_detectors_predicate`, when\n    `--postselect_detectors_with_non_zero_4th_coord` was the only way to do\n    post selection of detectors.\n\n    Args:\n        dem: The detector error model to pull coordinate data from.\n\n    Returns:\n        A bit packed numpy array where detectors with non-zero 4th coordinate\n        data have a True bit at their corresponding index.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     detector(1, 2, 3) D0\n        ...     detector(1, 1, 1, 1) D1\n        ...     detector(1, 1, 1, 0) D2\n        ...     detector(1, 1, 1, 999) D80\n        ... ''')\n        >>> sinter.post_selection_mask_from_4th_coord(dem)\n        array([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], dtype=uint8)\n    \"\"\"\n```\n\n<a name=\"sinter.predict_discards_bit_packed\"></a>\n```python\n# sinter.predict_discards_bit_packed\n\n# (at top-level in the sinter module)\ndef predict_discards_bit_packed(\n    *,\n    dem: stim.DetectorErrorModel,\n    dets_bit_packed: np.ndarray,\n    postselect_detectors_with_non_zero_4th_coord: bool,\n) -> np.ndarray:\n    \"\"\"Determines which shots to discard due to postselected detectors firing.\n\n    Args:\n        dem: The detector error model the detector data applies to.\n            This is also where coordinate data is read from, in order to\n            determine which detectors to postselect as not having fired.\n        dets_bit_packed: A uint8 numpy array with shape\n            (num_shots, math.ceil(num_dets / 8)). Contains bit packed detection\n            event data.\n        postselect_detectors_with_non_zero_4th_coord: Determines how\n            postselection is done. Currently, this is the only option so it has\n            to be set to True. Any detector from the detector error model that\n            specifies coordinate data with at least four coordinates where the\n            fourth coordinate (coord index 3) is non-zero will be postselected.\n\n    Returns:\n        A numpy bool_ array with shape (num_shots,) where False means not discarded and\n        True means yes discarded.\n    \"\"\"\n```\n\n<a name=\"sinter.predict_observables\"></a>\n```python\n# sinter.predict_observables\n\n# (at top-level in the sinter module)\ndef predict_observables(\n    *,\n    dem: stim.DetectorErrorModel,\n    dets: np.ndarray,\n    decoder: str,\n    bit_pack_result: bool = False,\n    custom_decoders: Optional[Dict[str, sinter.Decoder]] = None,\n) -> np.ndarray:\n    \"\"\"Predicts which observables were flipped based on detection event data.\n\n    Args:\n        dem: The detector error model the detector data applies to.\n            This is also where coordinate data is read from, in order to\n            determine which detectors to postselect as not having fired.\n        dets: The detection event data. Can be bit packed or not bit packed.\n            If dtype=np.bool_ then shape=(num_shots, num_detectors)\n            If dtype=np.uint8 then shape=(num_shots, math.ceil(num_detectors/8))\n        decoder: The decoder to use for decoding, e.g. \"pymatching\".\n        bit_pack_result: Defaults to False. Determines if the result is bit packed\n            or not.\n        custom_decoders: Custom decoders that can be used if requested by name.\n            If not specified, only decoders built into sinter, such as\n            'pymatching' and 'fusion_blossom', can be used.\n\n    Returns:\n        If bit_packed_result=False (default):\n            dtype=np.bool_\n            shape=(num_shots, num_observables)\n        If bit_packed_result=True:\n            dtype=np.uint8\n            shape=(num_shots, math.ceil(num_observables / 8))\n\n    Examples:\n        >>> import numpy as np\n        >>> import sinter\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     error(0.1) D0 L0\n        ...     error(0.1) D0 D1\n        ...     error(0.1) D1\n        ... ''')\n        >>> sinter.predict_observables(\n        ...     dem=dem,\n        ...     dets=np.array([\n        ...         [False, False],\n        ...         [True, False],\n        ...         [False, True],\n        ...         [True, True],\n        ...     ], dtype=np.bool_),\n        ...     decoder='vacuous',  # try replacing with 'pymatching'\n        ...     bit_pack_result=False,\n        ... )\n        array([[False],\n               [False],\n               [False],\n               [False]])\n    \"\"\"\n```\n\n<a name=\"sinter.predict_observables_bit_packed\"></a>\n```python\n# sinter.predict_observables_bit_packed\n\n# (at top-level in the sinter module)\ndef predict_observables_bit_packed(\n    *,\n    dem: stim.DetectorErrorModel,\n    dets_bit_packed: np.ndarray,\n    decoder: str,\n    custom_decoders: Optional[Dict[str, sinter.Decoder]] = None,\n) -> np.ndarray:\n    \"\"\"Predicts which observables were flipped based on detection event data.\n\n    This method predates `sinter.predict_observables` gaining optional bit\n    packing arguments.\n\n    Args:\n        dem: The detector error model the detector data applies to.\n            This is also where coordinate data is read from, in order to\n            determine which detectors to postselect as not having fired.\n        dets_bit_packed: A uint8 numpy array with shape\n            (num_shots, math.ceil(num_dets / 8)). Contains bit packed detection\n            event data.\n        decoder: The decoder to use for decoding, e.g. \"pymatching\".\n        custom_decoders: Custom decoders that can be used if requested by name.\n            If not specified, only decoders built into sinter, such as\n            'pymatching' and 'fusion_blossom', can be used.\n\n    Returns:\n        A numpy uint8 array with shape (num_shots, math.ceil(num_obs / 8)).\n        Contains bit packed observable prediction data.\n\n    Examples:\n        >>> import numpy as np\n        >>> import sinter\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     error(0.1) D0 L0\n        ...     error(0.1) D0 D1\n        ...     error(0.1) D1\n        ... ''')\n        >>> sinter.predict_observables_bit_packed(\n        ...     dem=dem,\n        ...     dets_bit_packed=np.array([\n        ...         [0b00],\n        ...         [0b01],\n        ...         [0b10],\n        ...         [0b11],\n        ...     ], dtype=np.uint8),\n        ...     decoder='vacuous',  # try replacing with 'pymatching'\n        ... )\n        array([[0],\n               [0],\n               [0],\n               [0]], dtype=uint8)\n    \"\"\"\n```\n\n<a name=\"sinter.predict_on_disk\"></a>\n```python\n# sinter.predict_on_disk\n\n# (at top-level in the sinter module)\ndef predict_on_disk(\n    *,\n    decoder: str,\n    dem_path: Union[str, pathlib.Path],\n    dets_path: Union[str, pathlib.Path],\n    dets_format: str,\n    obs_out_path: Union[str, pathlib.Path],\n    obs_out_format: str,\n    postselect_detectors_with_non_zero_4th_coord: bool = False,\n    discards_out_path: Union[str, pathlib.Path, NoneType] = None,\n    discards_out_format: Optional[str] = None,\n    custom_decoders: Dict[str, sinter.Decoder] = None,\n) -> None:\n    \"\"\"Performs decoding and postselection on disk.\n\n    Args:\n        decoder: The decoder to use for decoding.\n        dem_path: The detector error model to use to configure the decoder.\n        dets_path: Where the detection event data is stored on disk.\n        dets_format: The format the detection event data is stored in (e.g. '01' or 'b8').\n        obs_out_path: Where to write predicted observable flip data on disk.\n            Note that the predicted observable flip data will not included data from shots discarded by postselection.\n            Use the data in discards_out_path to determine which shots were discarded.\n        obs_out_format: The format to write the observable flip data in (e.g. '01' or 'b8').\n        postselect_detectors_with_non_zero_4th_coord: Activates postselection. Detectors that have a non-zero 4th\n            coordinate will be postselected. Any shot where a postselected detector fires will be discarded.\n            Requires specifying discards_out_path, for indicating which shots were discarded.\n        discards_out_path: Only used if postselection is being used. Where to write discard data on disk.\n        discards_out_format: The format to write discard data in (e.g. '01' or 'b8').\n        custom_decoders: Custom decoders that can be used if requested by name.\n    \"\"\"\n```\n\n<a name=\"sinter.read_stats_from_csv_files\"></a>\n```python\n# sinter.read_stats_from_csv_files\n\n# (at top-level in the sinter module)\ndef read_stats_from_csv_files(\n    *paths_or_files: Any,\n) -> List[sinter.TaskStats]:\n    \"\"\"Reads and aggregates shot statistics from CSV files.\n\n    Assumes the CSV file was written by printing `sinter.CSV_HEADER` and then\n    a list of `sinter.TaskStats`. When statistics from the same task appear\n    in multiple files (identified by the strong id being the same), the\n    statistics for that task are folded together (so only the total shots,\n    total errors, etc for each task are included in the results).\n\n    Args:\n        *paths_or_files: Each argument should be either a path (in the form of\n            a string or a pathlib.Path) or a TextIO object (e.g. as returned by\n            `open`). File data is read from each argument.\n\n    Returns:\n        A list of task stats, where each task appears only once in the list and\n        the stats associated with it are the totals aggregated from all files.\n\n    Examples:\n        >>> import sinter\n        >>> import io\n        >>> in_memory_file = io.StringIO()\n        >>> _ = in_memory_file.write('''\n        ...     shots,errors,discards,seconds,decoder,strong_id,json_metadata\n        ...     1000,42,0,0.125,pymatching,9c31908e2b,\"{\"\"d\"\":9}\"\n        ...     3000,24,0,0.125,pymatching,9c31908e2b,\"{\"\"d\"\":9}\"\n        ...     1000,250,0,0.125,pymatching,deadbeef08,\"{\"\"d\"\":7}\"\n        ... '''.strip())\n        >>> _ = in_memory_file.seek(0)\n        >>> stats = sinter.read_stats_from_csv_files(in_memory_file)\n        >>> for stat in stats:\n        ...     print(repr(stat))\n        sinter.TaskStats(strong_id='9c31908e2b', decoder='pymatching', json_metadata={'d': 9}, shots=4000, errors=66, seconds=0.25)\n        sinter.TaskStats(strong_id='deadbeef08', decoder='pymatching', json_metadata={'d': 7}, shots=1000, errors=250, seconds=0.125)\n    \"\"\"\n```\n\n<a name=\"sinter.shot_error_rate_to_piece_error_rate\"></a>\n```python\n# sinter.shot_error_rate_to_piece_error_rate\n\n# (at top-level in the sinter module)\ndef shot_error_rate_to_piece_error_rate(\n    shot_error_rate: Union[float, sinter.Fit],\n    *,\n    pieces: float,\n    values: float = 1,\n) -> Union[float, sinter.Fit]:\n    \"\"\"Convert from total error rate to per-piece error rate.\n\n    Args:\n        shot_error_rate: The rate at which shots fail. If this is set to a sinter.Fit,\n            the conversion broadcasts over the low,best,high of the fit.\n        pieces: The number of xor-pieces we want to subdivide each shot into,\n            as if each piece was an independent chance for the shot to fail and\n            the total chance of a shot failing was the xor of each piece\n            failing.\n        values: The number of or-pieces each shot's failure is being formed out\n            of.\n\n    Returns:\n        Let N = `pieces` (number of rounds)\n        Let V = `values` (number of observables)\n        Let S = `shot_error_rate`\n        Let R = the returned result\n\n        R satisfies the following property. Let X be the probability of each\n        observable flipping, each round. R will be the probability that any of\n        the observables is flipped after 1 round, given this X. X is chosen to\n        satisfy the following condition. If a Bernoulli distribution with\n        probability X is sampled V*N times, and the results grouped into V\n        groups of N, and each group is reduced to a single value using XOR, and\n        then the reduced group values are reduced to a single final value using\n        OR, then this final value will be True with probability S.\n\n        Or, in other words, if a shot consists of N rounds which V independent\n        observables must survive, then R is like the per-round failure for\n        any of the observables.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.shot_error_rate_to_piece_error_rate(\n        ...     shot_error_rate=0.1,\n        ...     pieces=2,\n        ... )\n        0.05278640450004207\n        >>> sinter.shot_error_rate_to_piece_error_rate(\n        ...     shot_error_rate=0.05278640450004207,\n        ...     pieces=1 / 2,\n        ... )\n        0.10000000000000003\n        >>> sinter.shot_error_rate_to_piece_error_rate(\n        ...     shot_error_rate=1e-9,\n        ...     pieces=100,\n        ... )\n        1.000000082740371e-11\n        >>> sinter.shot_error_rate_to_piece_error_rate(\n        ...     shot_error_rate=0.6,\n        ...     pieces=10,\n        ...     values=2,\n        ... )\n        0.12052311142021144\n    \"\"\"\n```\n\n<a name=\"sinter.stats_from_csv_files\"></a>\n```python\n# sinter.stats_from_csv_files\n\n# (at top-level in the sinter module)\ndef stats_from_csv_files(\n    *paths_or_files: Any,\n) -> List[sinter.TaskStats]:\n    \"\"\"Reads and aggregates shot statistics from CSV files.\n\n    (An old alias of `read_stats_from_csv_files`, kept around for backwards\n    compatibility.)\n\n    Assumes the CSV file was written by printing `sinter.CSV_HEADER` and then\n    a list of `sinter.TaskStats`. When statistics from the same task appear\n    in multiple files (identified by the strong id being the same), the\n    statistics for that task are folded together (so only the total shots,\n    total errors, etc for each task are included in the results).\n\n    Args:\n        *paths_or_files: Each argument should be either a path (in the form of\n            a string or a pathlib.Path) or a TextIO object (e.g. as returned by\n            `open`). File data is read from each argument.\n\n    Returns:\n        A list of task stats, where each task appears only once in the list and\n        the stats associated with it are the totals aggregated from all files.\n\n    Examples:\n        >>> import sinter\n        >>> import io\n        >>> in_memory_file = io.StringIO()\n        >>> _ = in_memory_file.write('''\n        ...     shots,errors,discards,seconds,decoder,strong_id,json_metadata\n        ...     1000,42,0,0.125,pymatching,9c31908e2b,\"{\"\"d\"\":9}\"\n        ...     3000,24,0,0.125,pymatching,9c31908e2b,\"{\"\"d\"\":9}\"\n        ...     1000,250,0,0.125,pymatching,deadbeef08,\"{\"\"d\"\":7}\"\n        ... '''.strip())\n        >>> _ = in_memory_file.seek(0)\n        >>> stats = sinter.stats_from_csv_files(in_memory_file)\n        >>> for stat in stats:\n        ...     print(repr(stat))\n        sinter.TaskStats(strong_id='9c31908e2b', decoder='pymatching', json_metadata={'d': 9}, shots=4000, errors=66, seconds=0.25)\n        sinter.TaskStats(strong_id='deadbeef08', decoder='pymatching', json_metadata={'d': 7}, shots=1000, errors=250, seconds=0.125)\n    \"\"\"\n```\n"
  },
  {
    "path": "doc/sinter_command_line.md",
    "content": "# Sinter command line reference\n\n## Index\n\n- [sinter collect](#collect)\n- [sinter combine](#combine)\n- [sinter plot](#plot)\n\n## Commands\n\n<a name=\"collect\"></a>\n### sinter collect\n\n```\nNAME\n    sinter collect\n\nSYNOPSIS\n    sinter collect \\\n        --circuits FILEPATH [...] \\\n        --decoders pymatching|fusion_blossom|...  [...] \\\n        --processes int|\"auto\" \\\n        [--max_shots int] \\\n        [--max_errors int] \\\n        [--save_resume_filepath FILEPATH] \\\n        [--metadata_func auto|PYTHON_EXPRESSION] \\\n        \\\n        [--also_print_results_to_stdout] \\\n        [--custom_decoders_module_function PYTHON_EXPRESSION] \\\n        [--existing_data_filepaths FILEPATH [...]] \\\n        [--max_batch_size int] \\\n        [--max_batch_seconds int] \\\n        [--postselected_detectors_predicate PYTHON_EXPRESSION] \\\n        [--postselected_observables_predicate PYTHON_EXPRESSION] \\\n        [--quiet] \\\n        [--count_detection_events] \\\n        [--count_observable_error_combos] \\\n        [--start_batch_size int] \\\n        [--custom_error_count_key NAME] \\\n        [--allowed_cpu_affinity_ids PYTHON_EXPRESSION [ANOTHER_PYTHON_EXPRESSION ...]]\n\nDESCRIPTION\n    Uses python multiprocessing to collect shots from the given circuit, decode\n    them using the given decoders, and report CSV statistics on error rates.\n\nOPTIONS\n    --circuits FILEPATH [ANOTHER_FILEPATH ...]\n        Circuit files to sample from and decode. This parameter can be given\n        multiple arguments.\n    --decoders NAME [ANOTHER_NAME ...]\n        The decoder to use to predict observables from detection events.\n    --custom_decoders_module_function MODULE_NAME:FUNCTION_NAME\n        Use the syntax \"module:function\" to \"import function from module\" and\n        use the result of \"function()\" as the custom_decoders dictionary. The\n        dictionary must map strings to stim.Decoder instances.\n    --max_shots INT\n        Sampling of a circuit will stop if this many shots have been taken.\n    --max_errors INT\n        Sampling of a circuit will stop if this many errors have been seen.\n    --processes INT\n        Number of processes to use for simultaneous sampling and decoding.\n    --save_resume_filepath FILEPATH\n        Activates MERGE mode. If save_resume_filepath doesn't exist, initializes\n        it with a CSV header. CSV data already at save_resume_filepath counts\n        towards max_shots and max_errors.\n        Collected data is appended to save_resume_filepath. Note that MERGE mode\n        is tolerant to failures: if the process is killed, it can simply be\n        restarted and it will pick up where it left off. Note that MERGE mode is\n        idempotent: if sufficient data has been collected, no additional work is\n        done when run again.\n    --start_batch_size INT\n        Initial number of samples to batch together into one job. Starting small\n        prevents over-sampling of circuits above threshold. The allowed batch\n        size increases exponentially from this starting point.\n    --max_batch_size INT\n        Maximum number of samples to batch together into one job. Bigger values\n        increase the delay between jobs finishing. Smaller values decrease the\n        amount of aggregation of results, increasing the amount of output\n        information.\n    --max_batch_seconds INT\n        Limits number of shots in a batch so that the estimated runtime of the\n        batch is below this amount.\n    --postselect_detectors_with_non_zero_4th_coord\n        Turns on detector postselection. If any detector with a non-zero 4th\n        coordinate fires, the shot is discarded.\n    --postselected_detectors_predicate PYTHON_EXPRESSION\n        Specifies a predicate used to decide which detectors to postselect. When\n        a postselected detector produces a detection event, the shot is\n        discarded instead of being given to the decoder. The number of discarded\n        shots is tracked as a statistic.\n        \n        Available values:\n            index: The unique number identifying the detector, determined by the\n                order of detectors in the circuit file.\n            coords: The coordinate data associated with the detector. An empty\n                tuple, if the circuit file did not specify detector coordinates.\n            metadata: The metadata associated with the task being sampled.\n\n        Expected expression type: Something that can be given to `bool` to get\n            False (do not postselect) or True (yes postselect).\n\n        Examples:\n            --postselected_detectors_predicate \"coords[2] == 0\"\n            --postselected_detectors_predicate \"coords[3] < metadata['postselection_level']\"\n    --postselected_observables_predicate PYTHON_EXPRESSION\n        Specifies a predicate used to decide which observables to postselect.\n        When a decoder mispredicts a postselected observable, the shot is\n        discarded instead of counting as an error.\n        \n        Available values:\n            index: The index of the observable to postselect or not.\n            metadata: The metadata associated with the task.\n\n        Expected expression type:\n            Something that can be given to `bool` to get False (do not\n            postselect) or True (yes postselect).\n\n        Examples:\n            --postselected_observables_predicate \"False\"\n            --postselected_observables_predicate \"metadata['d'] == 5 and index >= 2\"\n    --count_observable_error_combos\n        When set, the returned stats will include custom counts like\n        `obs_mistake_mask=E_E__` counting how many times the decoder made each\n        pattern of observable mistakes.\n    --count_detection_events\n        When set, the returned stats will include custom counts\n        `detectors_checked` and `detection_events`. The detection fraction is\n        the ratio of these two numbers.\n    --quiet\n        Disables writing progress to stderr.\n    --also_print_results_to_stdout\n        Even if writing to a file, also write results to stdout.\n    --existing_data_filepaths [FILEPATH ...]\n        CSV data from these files counts towards max_shots and max_errors. This\n        parameter can be given multiple arguments.\n    --metadata_func PYTHON_EXPRESSION\n        A python expression that associates json metadata with a circuit's\n        results. Set to \"auto\" to use \"sinter.comma_separated_key_values(path)\".\n        \n        Values available to the expression:\n            path: Relative path to the circuit file, from the command line\n                arguments.\n            circuit: The circuit itself, parsed from the file, as a\n                stim.Circuit.\n        \n        Expected type:\n            A value that can be serialized into JSON, like a Dict[str, int].\n\n        Note that the decoder field is already recorded separately, so storing\n        it in the metadata as well would be redundant. But something like\n        decoder version could be usefully added.\n        \n        Examples:\n            --metadata_func \"{'path': path}\"\n            --metadata_func \"auto\"\n            --metadata_func \"{'n': circuit.num_qubits, 'p': float(path.split('/')[-1].split('.')[0])}\"\n    --custom_error_count_key NAME\n        Makes `--max_errors` apply to `stat.custom_counts[key]` instead of to `stat.errors`.\n    --allowed_cpu_affinity_ids PYTHON_EXPRESSION [ANOTHER_PYTHON_EXPRESSION ...],\n        Controls which CPUs workers can be pinned to. By default, any CPU can be pinned to.\n        Specifying this argument makes it so that only the given CPU ids can be pinned. The\n        given arguments will be evaluated as python expressions. The expressions \n        should be integers or iterables of integers. So values like \"1\" and \"[1, 2, 4]\" and\n        \"range(5, 30)\" all work.\n\nEXAMPLES\n    Example #1\n        >>> stim gen --out \"d=5,r=5,p=0.01.stim\" --code repetition_code --task memory --distance 5 --rounds 5 --before_round_data_depolarization 0.01\n        >>> stim gen --out \"d=7,r=5,p=0.01.stim\" --code repetition_code --task memory --distance 7 --rounds 5 --before_round_data_depolarization 0.01\n        >>> sinter collect \\\n                --processes 4 \\\n                --circuits *.stim \\\n                --metadata_func auto \\\n                --decoders pymatching \\\n                --max_shots 1_000_000 \\\n                --max_errors 1_000 \\\n                --save_resume_filepath stats.csv\n        >>> sinter combine stats.csv\n             shots,    errors,  discards, seconds,decoder,strong_id,json_metadata\n           1000000,        12,         0,   0.716,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n           1000000,         1,         0,   0.394,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n```\n\n<a name=\"combine\"></a>\n### sinter combine\n\n```\nNAME\n    sinter combine\n\nSYNOPSIS\n    sinter combine \\\n        FILEPATH [...] \\\n        \\\n        [--order preserve|metadata|error] \\\n        [--strip_custom_counts]\n\nDESCRIPTION\n    Loads sample statistics from one or more CSV statistics files (produced by\n    `sinter collect`), and aggregates rows corresponding to the same circuit\n    together.\n\nOPTIONS\n    filepaths\n        The locations of statistics files with rows aggregate together.\n    --order\n        Decides how to sort the output data.\n        The options are:\n            metadata (default): Orders by the json_metadata column.\n            preserve: Keeps the same order as the input.\n            error: Orders by the error rate.\n    --strip_custom_counts\n        Removes custom_counts data from the output. \n\n\nEXAMPLES\n    Example #1\n        >>> sinter combine stats.csv\n             shots,    errors,  discards, seconds,decoder,strong_id,json_metadata\n           1000000,        12,         0,   0.716,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n           1000000,         1,         0,   0.394,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n        >>> cat stats.csv\n             shots,    errors,  discards, seconds,decoder,strong_id,json_metadata\n               100,         0,         0,   0.174,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n               100,         0,         0,   0.000,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n               400,         0,         0,   0.000,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n              1200,         0,         0,   0.000,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n               100,         0,         0,   0.178,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n              3600,         0,         0,   0.001,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n              3600,         0,         0,   0.001,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n             10800,         0,         0,   0.002,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n             18000,         0,         0,   0.003,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n             39600,         0,         0,   0.007,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n             75600,         0,         0,   0.012,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n            154800,         2,         0,   0.028,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n            306000,         5,         0,   0.051,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n               200,         0,         0,   0.000,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n               600,         0,         0,   0.001,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n              1800,         0,         0,   0.001,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n              5400,         0,         0,   0.002,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n             16200,         0,         0,   0.004,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n             48600,         1,         0,   0.010,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n            385800,         5,         0,   0.071,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n            145800,         0,         0,   0.030,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n            145800,         0,         0,   0.032,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n               200,         0,         0,   0.178,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n               200,         0,         0,   0.188,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n            198100,         0,         0,   0.044,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n            437400,         0,         0,   0.092,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n```\n\n<a name=\"plot\"></a>\n### sinter plot\n\n```\nNAME\n    sinter plot\n\nSYNOPSIS\n    sinter plot \\\n        --in FILEPATH [...] \\\n        [--x_func PYTHON_EXPRESSION] \\\n        [--group_func PYTHON_EXPRESSION] \\\n        [--out FILEPATH] \\\n        [--show] \\\n        \\\n        [--filter_func PYTHON_EXPRESSION] \\\n        [--y_func PYTHON_EXPRESSION] \\\n        [--failure_unit_name string] \\\n        [--failure_units_per_shot_func PYTHON_EXPRESSION] \\\n        [--failure_values_func PYTHON_EXPRESSION] \\\n        [--fig_size float float] \\\n        [--highlight_max_likelihood_factor float] \\\n        [--plot_args_func PYTHON_EXPRESSION] \\\n        [--custom_error_count_keys] \\\n        [--subtitle \"{common}\"|text] \\\n        [--title text] \\\n        [--type \"error_rate\"|\"discard_rate\"|\"custom_y\" [...] \\\n        [--xaxis \"text\"|\"[log]text\"|\"[sqrt]text\"] \\\n        [--yaxis \"text\"|\"[log]text\"|\"[sqrt]text\"] \\\n        [--xmin float] \\\n        [--xmax float] \\\n        [--ymin float] \\\n        [--line_fits]\n\nDESCRIPTION\n    Creates a plot of statistics collected by `sinter collect` by grouping data\n    into curves according to `--group_func`, and laying out points along that\n    curve according to `--x_func`. Plots error rates by default, and also\n    discard rates if there are any discards, but this can be customized by using\n    `--y_func`.\n\nOPTIONS\n    --filter_func PYTHON_EXPRESSION\n        A python expression that determines whether a case is kept or not.\n        \n        Values available to the python expression:\n            metadata: The parsed value from the json_metadata for the data\n                point.\n            m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\n            decoder: The decoder that decoded the data for the data point.\n            strong_id: The cryptographic hash of the case that was sampled for\n                the data point.\n            stat: The sinter.TaskStats object for the data point.\n            \n        Expected expression type: Something that can be given to `bool` to get\n            True or False.\n            \n        Examples:\n            --filter_func \"decoder=='pymatching'\"\n            --filter_func \"0.001 < metadata['p'] < 0.005\"\n    --x_func PYTHON_EXPRESSION\n        A python expression that determines where points go on the x axis.\n        \n        Values available to the python expression:\n            metadata: The parsed value from the json_metadata for the data\n                point.\n            m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\n            decoder: The decoder that decoded the data for the data point.\n            strong_id: The cryptographic hash of the case that was sampled for\n                the data point.\n            stat: The sinter.TaskStats object for the data point.\n\n        Expected expression type: Something that can be given to `float` to get\n            a float.\n\n        Examples:\n            --x_func \"metadata['p']\"\n            --x_func m.p\n            --x_func \"metadata['path'].split('/')[-1].split('.')[0]\"\n    --y_func PYTHON_EXPRESSION\n        A python expression that determines where points go on the y axis. This\n        argument is not used by error rate or discard rate plots; only by the\n        \"custom_y\" type plot.\n\n        Values available to the python expression:\n            metadata: The parsed value from the json_metadata for the data\n                point.\n            m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\n            decoder: The decoder that decoded the data for the data point.\n            strong_id: The cryptographic hash of the case that was sampled for\n                the data point.\n            stat: The sinter.TaskStats object for the data point.\n\n        Expected expression type: Something that can be given to `float` to get\n            a float.\n\n        Examples:\n            --y_func \"metadata['p']\"\n            --y_func m.p\n            --y_func \"metadata['path'].split('/')[-1].split('.')[0]\"\n    --fig_size WIDTH HEIGHT\n        Desired figure width and height in pixels.\n    --group_func PYTHON_EXPRESSION\n        A python expression that determines how points are grouped into curves.\n        \n        Values available to the python expression:\n            metadata: The parsed value from the json_metadata for the data\n                point.\n            m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\n            decoder: The decoder that decoded the data for the data point.\n            strong_id: The cryptographic hash of the case that was sampled for\n                the data point.\n            stat: The sinter.TaskStats object for the data point.\n\n        Expected expression type:\n            Something that can be given to `str` to get a useful string.\n            \n        Examples:\n            --group_func \"(decoder, metadata['d'])\"\n            --group_func m.d\n            --group_func \"metadata['path'].split('/')[-2]\"\n    --failure_unit_name FAILURE_UNIT_NAME\n        The unit of failure, typically either \"shot\" (the default) or \"round\".\n        If this argument is specified, --failure_units_per_shot_func must also\n        be specified.\n    --failure_units_per_shot_func PYTHON_EXPRESSION\n        A python expression that evaluates to the number of failure units there\n        are per shot. For example, if the failure unit is rounds, this should be\n        an expression that returns the number of rounds in a shot. Sinter has no\n        way of knowing what you consider a round to be, otherwise. This value is\n        used to rescale the logical error rate plots. For example, if there are 4\n        failure units per shot then a shot error rate of 10% corresponds to a\n        unit failure rate of 2.7129%. The conversion formula (assuming less than\n        50% error rates) is:\n        \n            P_unit = 0.5 - 0.5 * (1 - 2 * P_shot)**(1/units_per_shot)\n\n        Values available to the python expression:\n            metadata: The parsed value from the json_metadata for the data\n                point.\n            m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\n            decoder: The decoder that decoded the data for the data point.\n            strong_id: The cryptographic hash of the case that was sampled for\n                the data point.\n            stat: The sinter.TaskStats object for the data point.\n        \n        Expected expression type: float.\n        \n        Examples:\n            --failure_units_per_shot_func \"metadata['rounds']\"\n            --failure_units_per_shot_func m.r\n            --failure_units_per_shot_func \"m.distance * 3\"\n            --failure_units_per_shot_func \"10\"\n    --failure_values_func FAILURE_VALUES_FUNC\n        A python expression that evaluates to the number of independent ways a\n        shot can fail. For example, if a shot corresponds to a memory experiment\n        preserving two observables, then the failure unions is 2. This value is\n        necessary to correctly rescale the logical error rate plots when using\n        --failure_values_func. By default it is assumed to be 1.\n        \n        Values available to the python expression:\n            metadata: The parsed value from the json_metadata for the data\n                point.\n            m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\n            decoder: The decoder that decoded the data for the data point.\n            strong_id: The cryptographic hash of the case that was sampled for\n                the data point.\n            stat: The sinter.TaskStats object for the data point.\n\n        Expected expression type: float.\n        \n        Examples:\n            --failure_values_func \"metadata['num_obs']\"\n            --failure_values_func \"2\"\n    --plot_args_func PLOT_ARGS_FUNC\n        A python expression used to customize the look of curves.\n        \n        Values available to the python expression:\n            index: A unique integer identifying the curve.\n            key: The group key (returned from --group_func) identifying the curve.\n            stats: The list of sinter.TaskStats object in the group.\n            metadata: (From one arbitrary data point in the group.) The parsed value from the json_metadata for the data point.\n            m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\n            decoder: (From one arbitrary data point in the group.) The decoder that decoded the data for the data point.\n            strong_id: (From one arbitrary data point in the group.) The cryptographic hash of the case that was sampled for the data point.\n            stat: (From one arbitrary data point in the group.) The sinter.TaskStats object for the data point.\n\n        Expected expression type:\n            A dictionary to give to matplotlib plotting functions as a **kwargs argument.\n\n        Examples:\n            --plot_args_func \"{'label': 'curve #' + str(index), 'linewidth': 5}\"\n            --plot_args_func \"{'marker': 'ov*sp^<>8PhH+xXDd|'[index % 18]}\"\n    --in IN [IN ...]      Input files to get data from.\n    --type {error_rate,discard_rate,custom_y} [{error_rate,discard_rate,custom_y} ...]\n        Picks the figures to include.\n    --out OUT\n        Output file to write the plot to.\n        The file extension determines the type of image.\n        Either this or --show must be specified.\n    --xaxis XAXIS\n        Customize the X axis label.\n        Prefix [log] for logarithmic scale.\n        Prefix [sqrt] for square root scale.\n    --yaxis YAXIS\n        Customize the Y axis label.\n        Prefix [log] for logarithmic scale.\n        Prefix [sqrt] for square root scale.\n    --split_custom_counts\n        When a stat has custom counts, this splits it into multiple copies of\n        the stat with each one having exactly one of the custom counts.\n    --show\n        Displays the plot in a window. Either this or --out must be specified.\n    --ymin float\n        Sets the minimum value of the y axis (max always 1).\n    --xmin float\n        Forces the minimum value of the x axis.\n    --xmax float\n        Forces the maximum value of the x axis.\n    --title text\n        Sets the title of the plot.\n    --subtitle SUBTITLE\n        Sets the subtitle of the plot. Note: The pattern \"{common}\" will expand\n        to text including all json metadata values that are the same across all\n        stats.\n    --highlight_max_likelihood_factor HIGHLIGHT_MAX_LIKELIHOOD_FACTOR\n        The relative likelihood ratio that determines the color highlights\n        around curves. Set this to 1 or larger. Set to 1 to disable\n        highlighting.\n    --line_fits: Adds a least-squared line fit to each curve. Note that the fit\n        is always done according to the scaling of the plot. For example, on\n        a semilog y plot it will be fitting a line to (x, log(y)). Data points\n        are not weighted in any way. On a log plot, data points at infinity are\n        not included in the fit.\n\nEXAMPLES\n    Example #1\n        >>> cat stats.csv\n             shots,    errors,  discards, seconds,decoder,strong_id,json_metadata\n           1000000,        12,         0,   0.716,pymatching,41fe89ff6c51e598d51846cb7a2b626fbfcaa76adcd1be9e0f1e2dff1fe87f1c,\"{\"\"d\"\":5,\"\"p\"\":0.01,\"\"r\"\":5}\"\n           1000000,         1,         0,   0.394,pymatching,639d47a421d2a7661bb5b19255295767fc7cf0be7592fe4bcbc2639068e21349,\"{\"\"d\"\":7,\"\"p\"\":0.01,\"\"r\"\":5}\"\n        >>> sinter plot \\\n            --in stats.csv \\\n            --show \\\n            --x_func m.d \\\n            --group_func \"f'''rounds={m.r}'''\" \\\n            --xaxis \"[log]distance\"\n```\n"
  },
  {
    "path": "doc/stim.pyi",
    "content": "\"\"\"Stim (Development Version): a fast quantum stabilizer circuit library.\"\"\"\n# (This is a stubs file describing the classes and methods in stim.)\nfrom __future__ import annotations\nfrom typing import overload, TYPE_CHECKING, List, Dict, Tuple, Any, Union, Iterable, Optional, Sequence, Literal\nif TYPE_CHECKING:\n    import io\n    import pathlib\n    import numpy as np\n    import stim\nclass Circuit:\n    \"\"\"A mutable stabilizer circuit.\n\n    The stim.Circuit class is arguably the most important object in the\n    entire library. It is the interface through which you explain a\n    noisy quantum computation to Stim, in order to do fast bulk sampling\n    or fast error analysis.\n\n    For example, suppose you want to use a matching-based decoder on a\n    new quantum error correction construction. Stim can help you do this\n    but the very first step is to create a circuit implementing the\n    construction. Once you have the circuit you can then use methods like\n    stim.Circuit.detector_error_model() to create an object that can be\n    used to configure the decoder, or like\n    stim.Circuit.compile_detector_sampler() to produce problems for the\n    decoder to solve, or like stim.Circuit.shortest_graphlike_error() to\n    check for mistakes in the implementation of the code.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit()\n        >>> c.append(\"X\", 0)\n        >>> c.append(\"M\", 0)\n        >>> c.compile_sampler().sample(shots=1)\n        array([[ True]])\n\n        >>> stim.Circuit('''\n        ...    H 0\n        ...    CNOT 0 1\n        ...    M 0 1\n        ...    DETECTOR rec[-1] rec[-2]\n        ... ''').compile_detector_sampler().sample(shots=1)\n        array([[False]])\n    \"\"\"\n    def __add__(\n        self,\n        second: stim.Circuit,\n    ) -> stim.Circuit:\n        \"\"\"Creates a circuit by appending two circuits.\n\n        Examples:\n            >>> import stim\n            >>> c1 = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c2 = stim.Circuit('''\n            ...    M 0 1 2\n            ... ''')\n            >>> c1 + c2\n            stim.Circuit('''\n                X 0\n                Y 1 2\n                M 0 1 2\n            ''')\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.Circuit,\n    ) -> bool:\n        \"\"\"Determines if two circuits have identical contents.\n        \"\"\"\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: int,\n    ) -> Union[stim.CircuitInstruction, stim.CircuitRepeatBlock]:\n        pass\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: slice,\n    ) -> stim.Circuit:\n        pass\n    def __getitem__(\n        self,\n        index_or_slice: object,\n    ) -> object:\n        \"\"\"Returns copies of instructions from the circuit.\n\n        Args:\n            index_or_slice: An integer index picking out an instruction to return, or a\n                slice picking out a range of instructions to return as a circuit.\n\n        Returns:\n            If the index was an integer, then an instruction from the circuit.\n            If the index was a slice, then a circuit made up of the instructions in that\n            slice.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...    X 0\n            ...    X_ERROR(0.5) 2\n            ...    REPEAT 100 {\n            ...        X 0\n            ...        Y 1 2\n            ...    }\n            ...    TICK\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... ''')\n            >>> circuit[1]\n            stim.CircuitInstruction('X_ERROR', [stim.GateTarget(2)], [0.5])\n            >>> circuit[2]\n            stim.CircuitRepeatBlock(100, stim.Circuit('''\n                X 0\n                Y 1 2\n            '''))\n            >>> circuit[1::2]\n            stim.Circuit('''\n                X_ERROR(0.5) 2\n                TICK\n                DETECTOR rec[-1]\n            ''')\n        \"\"\"\n    def __iadd__(\n        self,\n        second: stim.Circuit,\n    ) -> stim.Circuit:\n        \"\"\"Appends a circuit into the receiving circuit (mutating it).\n\n        Examples:\n            >>> import stim\n            >>> c1 = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c2 = stim.Circuit('''\n            ...    M 0 1 2\n            ... ''')\n            >>> c1 += c2\n            >>> print(repr(c1))\n            stim.Circuit('''\n                X 0\n                Y 1 2\n                M 0 1 2\n            ''')\n        \"\"\"\n    def __imul__(\n        self,\n        repetitions: int,\n    ) -> stim.Circuit:\n        \"\"\"Mutates the circuit by putting its contents into a REPEAT block.\n\n        Special case: if the repetition count is 0, the circuit is cleared.\n        Special case: if the repetition count is 1, nothing happens.\n\n        Args:\n            repetitions: The number of times the REPEAT block should repeat.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c *= 3\n            >>> print(repr(c))\n            stim.Circuit('''\n                REPEAT 3 {\n                    X 0\n                    Y 1 2\n                }\n            ''')\n        \"\"\"\n    def __init__(\n        self,\n        stim_program_text: str = '',\n    ) -> None:\n        \"\"\"Creates a stim.Circuit.\n\n        Args:\n            stim_program_text: Defaults to empty. Describes operations to append into\n                the circuit.\n\n        Examples:\n            >>> import stim\n            >>> empty = stim.Circuit()\n            >>> not_empty = stim.Circuit('''\n            ...    X 0\n            ...    CNOT 0 1\n            ...    M 1\n            ... ''')\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of top-level instructions and blocks in the circuit.\n\n        Instructions inside of blocks are not included in this count.\n\n        Examples:\n            >>> import stim\n            >>> len(stim.Circuit())\n            0\n            >>> len(stim.Circuit('''\n            ...    X 0\n            ...    X_ERROR(0.5) 1 2\n            ...    TICK\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... '''))\n            5\n            >>> len(stim.Circuit('''\n            ...    REPEAT 100 {\n            ...        X 0\n            ...        Y 1 2\n            ...    }\n            ... '''))\n            1\n        \"\"\"\n    def __mul__(\n        self,\n        repetitions: int,\n    ) -> stim.Circuit:\n        \"\"\"Repeats the circuit using a REPEAT block.\n\n        Has special cases for 0 repetitions and 1 repetitions.\n\n        Args:\n            repetitions: The number of times the REPEAT block should repeat.\n\n        Returns:\n            repetitions=0: An empty circuit.\n            repetitions=1: A copy of this circuit.\n            repetitions>=2: A circuit with a single REPEAT block, where the contents of\n                that repeat block are this circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c * 3\n            stim.Circuit('''\n                REPEAT 3 {\n                    X 0\n                    Y 1 2\n                }\n            ''')\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.Circuit,\n    ) -> bool:\n        \"\"\"Determines if two circuits have non-identical contents.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.Circuit`.\n        \"\"\"\n    def __rmul__(\n        self,\n        repetitions: int,\n    ) -> stim.Circuit:\n        \"\"\"Repeats the circuit using a REPEAT block.\n\n        Has special cases for 0 repetitions and 1 repetitions.\n\n        Args:\n            repetitions: The number of times the REPEAT block should repeat.\n\n        Returns:\n            repetitions=0: An empty circuit.\n            repetitions=1: A copy of this circuit.\n            repetitions>=2: A circuit with a single REPEAT block, where the contents of\n                that repeat block are this circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> 3 * c\n            stim.Circuit('''\n                REPEAT 3 {\n                    X 0\n                    Y 1 2\n                }\n            ''')\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns stim instructions (that can be saved to a file and parsed by stim) for the current circuit.\n        \"\"\"\n    @overload\n    def append(\n        self,\n        name: str,\n        targets: Union[int, stim.GateTarget, stim.PauliString, Iterable[Union[int, stim.GateTarget, stim.PauliString]]],\n        arg: Union[float, Iterable[float], None] = None,\n        *,\n        tag: str = \"\",\n    ) -> None:\n        pass\n    @overload\n    def append(\n        self,\n        name: Union[stim.CircuitInstruction, stim.CircuitRepeatBlock, stim.Circuit],\n    ) -> None:\n        pass\n    def append(\n        self,\n        name: object,\n        targets: object = (),\n        arg: object = None,\n        *,\n        tag: str = '',\n    ) -> None:\n        \"\"\"Appends an operation into the circuit.\n\n        Note: `stim.Circuit.append_operation` is an alias of `stim.Circuit.append`.\n\n        Args:\n            name: The name of the operation's gate (e.g. \"H\" or \"M\" or \"CNOT\").\n\n                This argument can also be set to a `stim.CircuitInstruction` or\n                `stim.CircuitInstructionBlock`, which results in the instruction or\n                block being appended to the circuit. The other arguments (targets\n                and arg) can't be specified when doing so.\n\n                (The argument being called `name` is no longer quite right, but\n                is being kept for backwards compatibility.)\n            targets: The objects operated on by the gate. This can be either a\n                single target or an iterable of multiple targets.\n\n                Each target can be:\n                    An int: The index of a targeted qubit.\n                    A `stim.GateTarget`: Could be a variety of things. Methods like\n                        `stim.target_rec`, `stim.target_sweet`, `stim.target_x`, and\n                        `stim.CircuitInstruction.__getitem__` all return this type.\n                    A `stim.PauliString`: This will automatically be expanded into\n                        a product of pauli targets like `X1*Y2*Z3`.\n            arg: The \"parens arguments\" for the gate, such as the probability for a\n                noise operation. A double or list of doubles parameterizing the\n                gate. Different gates take different parens arguments. For example,\n                X_ERROR takes a probability, OBSERVABLE_INCLUDE takes an observable\n                index, and PAULI_CHANNEL_1 takes three disjoint probabilities.\n\n                Note: Defaults to no parens arguments. Except, for backwards\n                compatibility reasons, `cirq.append_operation` (but not\n                `cirq.append`) will default to a single 0.0 argument for gates that\n                take exactly one argument.\n            tag: A customizable string attached to the instruction.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit()\n            >>> c.append(\"X\", 0)\n            >>> c.append(\"H\", [0, 1])\n            >>> c.append(\"M\", [0, stim.target_inv(1)])\n            >>> c.append(\"CNOT\", [stim.target_rec(-1), 0])\n            >>> c.append(\"X_ERROR\", [0], 0.125)\n            >>> c.append(\"CORRELATED_ERROR\", [stim.target_x(0), stim.target_y(2)], 0.25)\n            >>> c.append(\"MPP\", [stim.PauliString(\"X1*Y2\"), stim.GateTarget(\"Z3\")])\n            >>> print(repr(c))\n            stim.Circuit('''\n                X 0\n                H 0 1\n                M 0 !1\n                CX rec[-1] 0\n                X_ERROR(0.125) 0\n                E(0.25) X0 Y2\n                MPP X1*Y2 Z3\n            ''')\n        \"\"\"\n    def append_from_stim_program_text(\n        self,\n        stim_program_text: str,\n    ) -> None:\n        \"\"\"Appends operations described by a STIM format program into the circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit()\n            >>> c.append_from_stim_program_text('''\n            ...    H 0  # comment\n            ...    CNOT 0 2\n            ...\n            ...    M 2\n            ...    CNOT rec[-1] 1\n            ... ''')\n            >>> print(c)\n            H 0\n            CX 0 2\n            M 2\n            CX rec[-1] 1\n\n        Args:\n            stim_program_text: The STIM program text containing the circuit operations\n                to append.\n        \"\"\"\n    def append_operation(\n        self,\n        name: object,\n        targets: object = (),\n        arg: object = None,\n        *,\n        tag: str = '',\n    ) -> None:\n        \"\"\"[DEPRECATED] use stim.Circuit.append instead\n        \"\"\"\n    def approx_equals(\n        self,\n        other: object,\n        *,\n        atol: float,\n    ) -> bool:\n        \"\"\"Checks if a circuit is approximately equal to another circuit.\n\n        Two circuits are approximately equal if they are equal up to slight\n        perturbations of instruction arguments such as probabilities. For example,\n        `X_ERROR(0.100) 0` is approximately equal to `X_ERROR(0.099)` within an absolute\n        tolerance of 0.002. All other details of the circuits (such as the ordering of\n        instructions and targets) must be exactly the same.\n\n        Args:\n            other: The circuit, or other object, to compare to this one.\n            atol: The absolute error tolerance. The maximum amount each probability may\n                have been perturbed by.\n\n        Returns:\n            True if the given object is a circuit approximately equal up to the\n            receiving circuit up to the given tolerance, otherwise False.\n\n        Examples:\n            >>> import stim\n            >>> base = stim.Circuit('''\n            ...    X_ERROR(0.099) 0 1 2\n            ...    M 0 1 2\n            ... ''')\n\n            >>> base.approx_equals(base, atol=0)\n            True\n\n            >>> base.approx_equals(stim.Circuit('''\n            ...    X_ERROR(0.101) 0 1 2\n            ...    M 0 1 2\n            ... '''), atol=0)\n            False\n\n            >>> base.approx_equals(stim.Circuit('''\n            ...    X_ERROR(0.101) 0 1 2\n            ...    M 0 1 2\n            ... '''), atol=0.0001)\n            False\n\n            >>> base.approx_equals(stim.Circuit('''\n            ...    X_ERROR(0.101) 0 1 2\n            ...    M 0 1 2\n            ... '''), atol=0.01)\n            True\n\n            >>> base.approx_equals(stim.Circuit('''\n            ...    DEPOLARIZE1(0.099) 0 1 2\n            ...    MRX 0 1 2\n            ... '''), atol=9999)\n            False\n        \"\"\"\n    def clear(\n        self,\n    ) -> None:\n        \"\"\"Clears the contents of the circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c.clear()\n            >>> c\n            stim.Circuit()\n        \"\"\"\n    def compile_detector_sampler(\n        self,\n        *,\n        seed: object = None,\n    ) -> stim.CompiledDetectorSampler:\n        \"\"\"Returns an object that can batch sample detection events from the circuit.\n\n        Args:\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    H 0\n            ...    CNOT 0 1\n            ...    M 0 1\n            ...    DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> s = c.compile_detector_sampler()\n            >>> s.sample(shots=1)\n            array([[False]])\n        \"\"\"\n    def compile_m2d_converter(\n        self,\n        *,\n        skip_reference_sample: bool = False,\n    ) -> stim.CompiledMeasurementsToDetectionEventsConverter:\n        \"\"\"Creates a measurement-to-detection-event converter for the given circuit.\n\n        The converter can efficiently compute detection events and observable flips\n        from raw measurement data.\n\n        The converter uses a noiseless reference sample, collected from the circuit\n        using stim's Tableau simulator during initialization of the converter, as a\n        baseline for determining what the expected value of a detector is.\n\n        Note that the expected behavior of gauge detectors (detectors that are not\n        actually deterministic under noiseless execution) can vary depending on the\n        reference sample. Stim mitigates this by always generating the same reference\n        sample for a given circuit.\n\n        Args:\n            skip_reference_sample: Defaults to False. When set to True, the reference\n                sample used by the converter is initialized to all-zeroes instead of\n                being collected from the circuit. This should only be used if it's known\n                that the all-zeroes sample is actually a possible result from the\n                circuit (under noiseless execution).\n\n        Returns:\n            An initialized stim.CompiledMeasurementsToDetectionEventsConverter.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> converter = stim.Circuit('''\n            ...    X 0\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... ''').compile_m2d_converter()\n            >>> converter.convert(\n            ...     measurements=np.array([[0], [1]], dtype=np.bool_),\n            ...     append_observables=False,\n            ... )\n            array([[ True],\n                   [False]])\n        \"\"\"\n    def compile_sampler(\n        self,\n        *,\n        skip_reference_sample: bool = False,\n        seed: Optional[int] = None,\n        reference_sample: Optional[np.ndarray] = None,\n    ) -> stim.CompiledMeasurementSampler:\n        \"\"\"Returns an object that can quickly batch sample measurements from the circuit.\n\n        Args:\n            skip_reference_sample: Defaults to False. When set to True, the reference\n                sample used by the sampler is initialized to all-zeroes instead of being\n                collected from the circuit. This means that the results returned by the\n                sampler are actually whether or not each measurement was *flipped*,\n                instead of true measurement results.\n\n                Forcing an all-zero reference sample is useful when you are only\n                interested in error propagation and don't want to have to deal with the\n                fact that some measurements want to be On when no errors occur. It is\n                also useful when you know for sure that the all-zero result is actually\n                a possible result from the circuit (under noiseless execution), meaning\n                it is a valid reference sample as good as any other. Computing the\n                reference sample is the most time consuming and memory intensive part of\n                simulating the circuit, so promising that the simulator can safely skip\n                that step is an effective optimization.\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n            reference_sample: The data to xor into the measurement flips produced by the\n                frame simulator, in order to produce proper measurement results.\n                This can either be specified as an `np.bool_` array or a bit packed\n                `np.uint8` array (little endian). Under normal conditions, the reference\n                sample should be a valid noiseless sample of the circuit, such as the\n                one returned by `circuit.reference_sample()`. If this argument is not\n                provided, the reference sample will be set to\n                `circuit.reference_sample()`, unless `skip_reference_sample=True`\n                is used, in which case it will be set to all-zeros.\n\n        Raises:\n            ValueError: skip_reference_sample is True and reference_sample is not None.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 2\n            ...    M 0 1 2\n            ... ''')\n            >>> s = c.compile_sampler()\n            >>> s.sample(shots=1)\n            array([[False, False,  True]])\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a copy of the circuit. An independent circuit with the same contents.\n\n        Examples:\n            >>> import stim\n\n            >>> c1 = stim.Circuit(\"H 0\")\n            >>> c2 = c1.copy()\n            >>> c2 is c1\n            False\n            >>> c2 == c1\n            True\n        \"\"\"\n    def count_determined_measurements(\n        self,\n        *,\n        unknown_input: bool = False,\n    ) -> int:\n        \"\"\"Counts the number of predictable measurements in the circuit.\n\n        This method ignores any noise in the circuit.\n\n        This method works by performing a tableau stabilizer simulation of the circuit\n        and, before each measurement is simulated, checking if its expectation is\n        non-zero.\n\n        A measurement is predictable if its result can be predicted by using other\n        measurements that have already been performed, assuming the circuit is executed\n        without any noise.\n\n        Note that, when multiple measurements occur at the same time, re-ordering the\n        order they are resolved can change which specific measurements are predictable\n        but won't change how many of them were predictable in total.\n\n        The number of predictable measurements is a useful quantity because it's\n        related to the number of detectors and observables that a circuit should\n        declare. If circuit.num_detectors + circuit.num_observables is less than\n        circuit.count_determined_measurements(), this is a warning sign that you've\n        missed some detector declarations.\n\n        The exact relationship between the number of determined measurements and the\n        number of detectors and observables can differ from code to code. For example,\n        the toric code has an extra redundant measurement compared to the surface code\n        because in the toric code the last X stabilizer to be measured is equal to the\n        product of all other X stabilizers even in the first round when initializing in\n        the Z basis. Typically this relationship is not declared as a detector, because\n        it's not local, or as an observable, because it doesn't store a qubit.\n\n        Args:\n            unknown_input: Defaults to False (inputs assumed to be in the |0> state).\n                When set to True, the inputs are instead treated as being in unknown\n                random states. For example, this means that Z-basis measurements at\n                the very beginning of the circuit will be considered random rather\n                than determined.\n\n        Returns:\n            The number of measurements that were predictable.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     R 0\n            ...     M 0\n            ... ''').count_determined_measurements()\n            1\n\n            >>> stim.Circuit('''\n            ...     R 0\n            ...     H 0\n            ...     M 0\n            ... ''').count_determined_measurements()\n            0\n\n            >>> stim.Circuit('''\n            ...     M 0\n            ... ''').count_determined_measurements()\n            1\n\n            >>> stim.Circuit('''\n            ...     M 0\n            ... ''').count_determined_measurements(unknown_input=True)\n            0\n\n            >>> stim.Circuit('''\n            ...     M 0\n            ...     M 0 1\n            ...     M 0 1 2\n            ...     M 0 1 2 3\n            ... ''').count_determined_measurements(unknown_input=True)\n            6\n\n            >>> stim.Circuit('''\n            ...     R 0 1\n            ...     MZZ 0 1\n            ...     MYY 0 1\n            ...     MXX 0 1\n            ... ''').count_determined_measurements()\n            2\n\n            >>> circuit = stim.Circuit.generated(\n            ...     \"surface_code:rotated_memory_x\",\n            ...     distance=5,\n            ...     rounds=9,\n            ... )\n            >>> circuit.count_determined_measurements()\n            217\n            >>> circuit.num_detectors + circuit.num_observables\n            217\n        \"\"\"\n    def decomposed(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Recreates the circuit using (mostly) the {H,S,CX,M,R} gate set.\n\n        The intent of this method is to simplify the circuit to use fewer gate types,\n        so it's easier for other tools to consume. Currently, this method performs the\n        following simplifications:\n\n        - Single qubit cliffords are decomposed into {H,S}.\n        - Multi-qubit cliffords are decomposed into {H,S,CX}.\n        - Single qubit dissipative gates are decomposed into {H,S,M,R}.\n        - Multi-qubit dissipative gates are decomposed into {H,S,CX,M,R}.\n\n        Currently, the following types of gate *aren't* simplified, but they may be\n        in the future:\n\n        - Noise instructions (like X_ERROR, DEPOLARIZE2, and E).\n        - Annotations (like TICK, DETECTOR, and SHIFT_COORDS).\n        - The MPAD instruction.\n        - Repeat blocks are not flattened.\n\n        Returns:\n            A `stim.Circuit` whose function is equivalent to the original circuit,\n            but with most gates decomposed into the {H,S,CX,M,R} gate set.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     SWAP 0 1\n            ... ''').decomposed()\n            stim.Circuit('''\n                CX 0 1 1 0 0 1\n            ''')\n\n            >>> stim.Circuit('''\n            ...     ISWAP 0 1 2 1\n            ...     TICK\n            ...     MPP !X1*Y2*Z3\n            ... ''').decomposed()\n            stim.Circuit('''\n                H 0\n                CX 0 1 1 0\n                H 1\n                S 1 0\n                H 2\n                CX 2 1 1 2\n                H 1\n                S 1 2\n                TICK\n                H 1 2\n                S 2\n                H 2\n                S 2 2\n                CX 2 1 3 1\n                M !1\n                CX 2 1 3 1\n                H 2\n                S 2\n                H 2\n                S 2 2\n                H 1\n            ''')\n        \"\"\"\n    def detecting_regions(\n        self,\n        *,\n        targets: Optional[Iterable[stim.DemTarget | str | Iterable[float]]] = None,\n        ticks: Optional[Iterable[int]] = None,\n    ) -> Dict[stim.DemTarget, Dict[int, stim.PauliString]]:\n        \"\"\"Records where detectors and observables are sensitive to errors over time.\n\n        The result of this method is a nested dictionary, mapping detectors/observables\n        and ticks to Pauli sensitivities for that detector/observable at that time.\n\n        For example, if observable 2 has Z-type sensitivity on qubits 5 and 6 during\n        tick 3, then `result[stim.target_logical_observable_id(2)][3]` will be equal to\n        `stim.PauliString(\"Z5*Z6\")`.\n\n        If you want sensitivities from more places in the circuit, besides just at the\n        TICK instructions, you can work around this by making a version of the circuit\n        with more TICKs.\n\n        Args:\n            targets: Defaults to everything (None).\n\n                When specified, this should be an iterable of filters where items\n                matching any one filter are included.\n\n                A variety of filters are supported:\n                    stim.DemTarget: Includes the targeted detector or observable.\n                    Iterable[float]: Coordinate prefix match. Includes detectors whose\n                        coordinate data begins with the same floats.\n                    \"D\": Includes all detectors.\n                    \"L\": Includes all observables.\n                    \"D#\" (e.g. \"D5\"): Includes the detector with the specified index.\n                    \"L#\" (e.g. \"L5\"): Includes the observable with the specified index.\n\n            ticks: Defaults to everything (None).\n                When specified, this should be a list of integers corresponding to\n                the tick indices to report sensitivities for.\n\n            ignore_anticommutation_errors: Defaults to False.\n                When set to False, invalid detecting regions that anticommute with a\n                reset will cause the method to raise an exception. When set to True,\n                the offending component will simply be silently dropped. This can\n                result in broken detectors having apparently enormous detecting\n                regions.\n\n        Returns:\n            Nested dictionaries keyed first by a `stim.DemTarget` identifying the\n            detector or observable, then by the index of the tick, leading to a\n            PauliString with that target's error sensitivity at that tick.\n\n            Note you can use `stim.PauliString.pauli_indices` to quickly get to the\n            non-identity terms in the sensitivity.\n\n        Examples:\n            >>> import stim\n\n            >>> detecting_regions = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     H 0\n            ...     TICK\n            ...     CX 0 1\n            ...     TICK\n            ...     MX 0 1\n            ...     DETECTOR rec[-1] rec[-2]\n            ... ''').detecting_regions()\n            >>> for target, tick_regions in detecting_regions.items():\n            ...     print(\"target\", target)\n            ...     for tick, sensitivity in tick_regions.items():\n            ...         print(\"    tick\", tick, \"=\", sensitivity)\n            target D0\n                tick 0 = +Z_\n                tick 1 = +X_\n                tick 2 = +XX\n\n            >>> circuit = stim.Circuit.generated(\n            ...     \"surface_code:rotated_memory_x\",\n            ...     rounds=5,\n            ...     distance=4,\n            ... )\n\n            >>> detecting_regions = circuit.detecting_regions(\n            ...     targets=[\"L0\", (2, 4), stim.DemTarget.relative_detector_id(5)],\n            ...     ticks=range(5, 15),\n            ... )\n            >>> for target, tick_regions in detecting_regions.items():\n            ...     print(\"target\", target)\n            ...     for tick, sensitivity in tick_regions.items():\n            ...         print(\"    tick\", tick, \"=\", sensitivity)\n            target D1\n                tick 5 = +____________________X______________________\n                tick 6 = +____________________Z______________________\n            target D5\n                tick 5 = +______X____________________________________\n                tick 6 = +______Z____________________________________\n            target D14\n                tick 5 = +__________X_X______XXX_____________________\n                tick 6 = +__________X_X______XZX_____________________\n                tick 7 = +__________X_X______XZX_____________________\n                tick 8 = +__________X_X______XXX_____________________\n                tick 9 = +__________XXX_____XXX______________________\n                tick 10 = +__________XXX_______X______________________\n                tick 11 = +__________X_________X______________________\n                tick 12 = +____________________X______________________\n                tick 13 = +____________________Z______________________\n            target D29\n                tick 7 = +____________________Z______________________\n                tick 8 = +____________________X______________________\n                tick 9 = +____________________XX_____________________\n                tick 10 = +___________________XXX_______X_____________\n                tick 11 = +____________X______XXXX______X_____________\n                tick 12 = +__________X_X______XXX_____________________\n                tick 13 = +__________X_X______XZX_____________________\n                tick 14 = +__________X_X______XZX_____________________\n            target D44\n                tick 14 = +____________________Z______________________\n            target L0\n                tick 5 = +_X________X________X________X______________\n                tick 6 = +_X________X________X________X______________\n                tick 7 = +_X________X________X________X______________\n                tick 8 = +_X________X________X________X______________\n                tick 9 = +_X________X_______XX________X______________\n                tick 10 = +_X________X________X________X______________\n                tick 11 = +_X________XX_______X________XX_____________\n                tick 12 = +_X________X________X________X______________\n                tick 13 = +_X________X________X________X______________\n                tick 14 = +_X________X________X________X______________\n        \"\"\"\n    def detector_error_model(\n        self,\n        *,\n        decompose_errors: bool = False,\n        flatten_loops: bool = False,\n        allow_gauge_detectors: bool = False,\n        approximate_disjoint_errors: float = False,\n        ignore_decomposition_failures: bool = False,\n        block_decomposition_from_introducing_remnant_edges: bool = False,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns a stim.DetectorErrorModel describing the error processes in the circuit.\n\n        Args:\n            decompose_errors: Defaults to false. When set to true, the error analysis\n                attempts to decompose the components of composite error mechanisms (such\n                as depolarization errors) into simpler errors, and suggest this\n                decomposition via `stim.target_separator()` between the components. For\n                example, in an XZ surface code, single qubit depolarization has a Y\n                error term which can be decomposed into simpler X and Z error terms.\n                Decomposition fails (causing this method to throw) if it's not possible\n                to decompose large errors into simple errors that affect at most two\n                detectors.\n            flatten_loops: Defaults to false. When set to True, the output will not\n                contain any `repeat` blocks. When set to False, the error analysis\n                watches for loops in the circuit reaching a periodic steady state with\n                respect to the detectors being introduced, the error mechanisms that\n                affect them, and the locations of the logical observables. When it\n                identifies such a steady state, it outputs a repeat block. This is\n                massively more efficient than flattening for circuits that contain\n                loops, but creates a more complex output.\n            allow_gauge_detectors: Defaults to false. When set to false, the error\n                analysis verifies that detectors in the circuit are actually\n                deterministic under noiseless execution of the circuit. When set to\n                True, these detectors are instead considered to be part of degrees\n                freedom that can be removed from the error model. For example, if\n                detectors D1 and D3 both anti-commute with a reset, then the error model\n                has a gauge `error(0.5) D1 D3`. When gauges are identified, one of the\n                involved detectors is removed from the system using Gaussian\n                elimination.\n\n                Note that logical observables are still verified to be deterministic,\n                even if this option is set.\n            approximate_disjoint_errors: Defaults to false. When set to false, composite\n                error mechanisms with disjoint components (such as\n                `PAULI_CHANNEL_1(0.1, 0.2, 0.0)`) can cause the error analysis to throw\n                exceptions (because detector error models can only contain independent\n                error mechanisms). When set to true, the probabilities of the disjoint\n                cases are instead assumed to be independent probabilities. For example,\n                a `PAULI_CHANNEL_1(0.1, 0.2, 0.0)` becomes equivalent to an\n                `X_ERROR(0.1)` followed by a `Y_ERROR(0.2)`. This assumption is an\n                approximation, but it is a good approximation for small probabilities.\n\n                This argument can also be set to a probability between 0 and 1, setting\n                a threshold below which the approximation is acceptable. Any error\n                mechanisms that have a component probability above the threshold will\n                cause an exception to be thrown.\n            ignore_decomposition_failures: Defaults to False.\n                When this is set to True, circuit errors that fail to decompose into\n                graphlike detector error model errors no longer cause the conversion\n                process to abort. Instead, the undecomposed error is inserted into the\n                output. Whatever tool the detector error model is then given to is\n                responsible for dealing with the undecomposed errors (e.g. a tool may\n                choose to simply ignore them).\n\n                Irrelevant unless decompose_errors=True.\n            block_decomposition_from_introducing_remnant_edges: Defaults to False.\n                Requires that both A B and C D be present elsewhere in the detector\n                error model in order to decompose A B C D into A B ^ C D. Normally, only\n                one of A B or C D needs to appear to allow this decomposition.\n\n                Remnant edges can be a useful feature for ensuring decomposition\n                succeeds, but they can also reduce the effective code distance by giving\n                the decoder single edges that actually represent multiple errors in the\n                circuit (resulting in the decoder making misinformed choices when\n                decoding).\n\n                Irrelevant unless decompose_errors=True.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     X_ERROR(0.125) 0\n            ...     X_ERROR(0.25) 1\n            ...     CORRELATED_ERROR(0.375) X0 X1\n            ...     M 0 1\n            ...     DETECTOR rec[-2]\n            ...     DETECTOR rec[-1]\n            ... ''').detector_error_model()\n            stim.DetectorErrorModel('''\n                error(0.125) D0\n                error(0.375) D0 D1\n                error(0.25) D1\n            ''')\n        \"\"\"\n    def diagram(\n        self,\n        type: Literal[\"timeline-text\", \"timeline-svg\", \"timeline-svg-html\", \"timeline-3d\", \"timeline-3d-html\", \"detslice-text\", \"detslice-svg\", \"detslice-svg-html\", \"matchgraph-svg\", \"matchgraph-svg-html\", \"matchgraph-3d\", \"matchgraph-3d-html\", \"timeslice-svg\", \"timeslice-svg-html\", \"detslice-with-ops-svg\", \"detslice-with-ops-svg-html\", \"interactive\", \"interactive-html\"] = 'timeline-text',\n        *,\n        tick: Union[None, int, range] = None,\n        filter_coords: Iterable[Union[Iterable[float], stim.DemTarget]] = ((),),\n        rows: int | None = None,\n    ) -> 'stim._DiagramHelper':\n        \"\"\"Returns a diagram of the circuit, from a variety of options.\n\n        Args:\n            type: The type of diagram. Available types are:\n                \"timeline-text\" (default): An ASCII diagram of the\n                    operations applied by the circuit over time. Includes\n                    annotations showing the measurement record index that\n                    each measurement writes to, and the measurements used\n                    by detectors.\n                \"timeline-svg\": An SVG image of the operations applied by\n                    the circuit over time. Includes annotations showing the\n                    measurement record index that each measurement writes\n                    to, and the measurements used by detectors.\n                \"timeline-svg-html\": A resizable SVG image viewer of the\n                    operations applied by the circuit over time. Includes\n                    annotations showing the measurement record index that\n                    each measurement writes to, and the measurements used\n                    by detectors.\n                \"timeline-3d\": A 3d model, in GLTF format, of the operations\n                    applied by the circuit over time.\n                \"timeline-3d-html\": Same 3d model as 'timeline-3d' but\n                    embedded into an HTML web page containing an interactive\n                    THREE.js viewer for the 3d model.\n                \"detslice-text\": An ASCII diagram of the stabilizers\n                    that detectors declared by the circuit correspond to\n                    during the TICK instruction identified by the `tick`\n                    argument.\n                \"detslice-svg\": An SVG image of the stabilizers\n                    that detectors declared by the circuit correspond to\n                    during the TICK instruction identified by the `tick`\n                    argument. For example, a detector slice diagram of a\n                    CSS surface code circuit during the TICK between a\n                    measurement layer and a reset layer will produce the\n                    usual diagram of a surface code.\n\n                    Uses the Pauli color convention XYZ=RGB.\n                \"detslice-svg-html\": Same as detslice-svg but the SVG image\n                    is inside a resizable HTML iframe.\n                \"matchgraph-svg\": An SVG image of the match graph extracted\n                    from the circuit by stim.Circuit.detector_error_model.\n                \"matchgraph-svg-html\": Same as matchgraph-svg but the SVG image\n                    is inside a resizable HTML iframe.\n                \"matchgraph-3d\": An 3D model of the match graph extracted\n                    from the circuit by stim.Circuit.detector_error_model.\n                \"matchgraph-3d-html\": Same 3d model as 'match-graph-3d' but\n                    embedded into an HTML web page containing an interactive\n                    THREE.js viewer for the 3d model.\n                \"timeslice-svg\": An SVG image of the operations applied\n                    between two TICK instructions in the circuit, with the\n                    operations laid out in 2d.\n                \"timeslice-svg-html\": Same as timeslice-svg but the SVG image\n                    is inside a resizable HTML iframe.\n                \"detslice-with-ops-svg\": A combination of timeslice-svg\n                    and detslice-svg, with the operations overlaid\n                    over the detector slices taken from the TICK after the\n                    operations were applied.\n                \"detslice-with-ops-svg-html\": Same as detslice-with-ops-svg\n                    but the SVG image is inside a resizable HTML iframe.\n                \"interactive\" or \"interactive-html\": An HTML web page\n                    containing Crumble (an interactive editor for 2D\n                    stabilizer circuits) initialized with the given circuit\n                    as its default contents.\n            tick: Required for detector and time slice diagrams. Specifies\n                which TICK instruction, or range of TICK instructions, to\n                slice at. Note that the first TICK instruction in the\n                circuit corresponds tick=1. The value tick=0 refers to the\n                very start of the circuit.\n\n                Passing `range(A, B)` for a detector slice will show the\n                slices for ticks A through B including A but excluding B.\n\n                Passing `range(A, B)` for a time slice will show the\n                operations between tick A and tick B.\n            rows: In diagrams that have multiple separate pieces, such as timeslice\n                diagrams and detslice diagrams, this controls how many rows of\n                pieces there will be. If not specified, a number of rows that creates\n                a roughly square layout will be chosen.\n            filter_coords: A list of things to include in the diagram. Different\n                effects depending on the diagram.\n\n                For detslice diagrams, the filter defaults to showing all detectors\n                and no observables. When specified, each list entry can be a collection\n                of floats (detectors whose coordinates start with the same numbers will\n                be included), a stim.DemTarget (specifying a detector or observable\n                to include), a string like \"D5\" or \"L0\" specifying a detector or\n                observable to include.\n\n        Returns:\n            An object whose `__str__` method returns the diagram, so that\n            writing the diagram to a file works correctly. The returned\n            object may also define methods such as `_repr_html_`, so that\n            ipython notebooks recognize it can be shown using a specialized\n            viewer instead of as raw text.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1 1 2\n            ... ''')\n\n            >>> print(circuit.diagram())\n            q0: -H-@---\n                   |\n            q1: ---X-@-\n                     |\n            q2: -----X-\n\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ...     TICK\n            ...     M 0 1\n            ...     DETECTOR rec[-1] rec[-2]\n            ... ''')\n\n            >>> print(circuit.diagram(\"detslice-text\", tick=1))\n            q0: -Z:D0-\n                 |\n            q1: -Z:D0-\n        \"\"\"\n    def explain_detector_error_model_errors(\n        self,\n        *,\n        dem_filter: object = None,\n        reduce_to_one_representative_error: bool = False,\n    ) -> List[stim.ExplainedError]:\n        \"\"\"Explains how detector error model errors are produced by circuit errors.\n\n        Args:\n            dem_filter: Defaults to None (unused). When used, the output will only\n                contain detector error model errors that appear in the given\n                `stim.DetectorErrorModel`. Any error mechanisms from the detector error\n                model that can't be reproduced using one error from the circuit will\n                also be included in the result, but with an empty list of associated\n                circuit error mechanisms.\n            reduce_to_one_representative_error: Defaults to False. When True, the items\n                in the result will contain at most one circuit error mechanism.\n\n        Returns:\n            A `List[stim.ExplainedError]` (see `stim.ExplainedError` for more\n            information). Each item in the list describes how a detector error model\n            error can be produced by individual circuit errors.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     # Create Bell pair.\n            ...     H 0\n            ...     CNOT 0 1\n            ...\n            ...     # Noise.\n            ...     DEPOLARIZE1(0.01) 0\n            ...\n            ...     # Bell basis measurement.\n            ...     CNOT 0 1\n            ...     H 0\n            ...     M 0 1\n            ...\n            ...     # Both measurements should be False under noiseless execution.\n            ...     DETECTOR rec[-1]\n            ...     DETECTOR rec[-2]\n            ... ''')\n            >>> explained_errors = circuit.explain_detector_error_model_errors(\n            ...     dem_filter=stim.DetectorErrorModel('error(1) D0 D1'),\n            ...     reduce_to_one_representative_error=True,\n            ... )\n            >>> print(explained_errors[0].circuit_error_locations[0])\n            CircuitErrorLocation {\n                flipped_pauli_product: Y0\n                Circuit location stack trace:\n                    (after 0 TICKs)\n                    at instruction #3 (DEPOLARIZE1) in the circuit\n                    at target #1 of the instruction\n                    resolving to DEPOLARIZE1(0.01) 0\n            }\n        \"\"\"\n    def flattened(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Creates an equivalent circuit without REPEAT or SHIFT_COORDS.\n\n        Returns:\n            A `stim.Circuit` with the same instructions in the same order,\n            but with loops flattened into repeated instructions and with\n            all coordinate shifts inlined.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     REPEAT 5 {\n            ...         MR 0 1\n            ...         DETECTOR(0, 0) rec[-2]\n            ...         DETECTOR(1, 0) rec[-1]\n            ...         SHIFT_COORDS(0, 1)\n            ...     }\n            ... ''').flattened()\n            stim.Circuit('''\n                MR 0 1\n                DETECTOR(0, 0) rec[-2]\n                DETECTOR(1, 0) rec[-1]\n                MR 0 1\n                DETECTOR(0, 1) rec[-2]\n                DETECTOR(1, 1) rec[-1]\n                MR 0 1\n                DETECTOR(0, 2) rec[-2]\n                DETECTOR(1, 2) rec[-1]\n                MR 0 1\n                DETECTOR(0, 3) rec[-2]\n                DETECTOR(1, 3) rec[-1]\n                MR 0 1\n                DETECTOR(0, 4) rec[-2]\n                DETECTOR(1, 4) rec[-1]\n            ''')\n        \"\"\"\n    def flattened_operations(\n        self,\n    ) -> list:\n        \"\"\"[DEPRECATED]\n\n        Returns a list of tuples encoding the contents of the circuit.\n        Instead of this method, use `for instruction in circuit` or, to\n        avoid REPEAT blocks, `for instruction in circuit.flattened()`.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...    H 0\n            ...    X_ERROR(0.125) 1\n            ...    M 0 !1\n            ... ''').flattened_operations()\n            [('H', [0], 0), ('X_ERROR', [1], 0.125), ('M', [0, ('inv', 1)], 0)]\n\n            >>> stim.Circuit('''\n            ...    REPEAT 2 {\n            ...        H 6\n            ...    }\n            ... ''').flattened_operations()\n            [('H', [6], 0), ('H', [6], 0)]\n        \"\"\"\n    def flow_generators(\n        self,\n    ) -> List[stim.Flow]:\n        \"\"\"Returns a list of flows that generate all of the circuit's flows.\n\n        Every stabilizer flow that the circuit implements is a product of some\n        subset of the returned generators. Every returned flow will be a flow\n        of the circuit.\n\n        Returns:\n            A list of flow generators for the circuit.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit(\"H 0\").flow_generators()\n            [stim.Flow(\"X -> Z\"), stim.Flow(\"Z -> X\")]\n\n            >>> stim.Circuit(\"M 0\").flow_generators()\n            [stim.Flow(\"1 -> Z xor rec[0]\"), stim.Flow(\"Z -> rec[0]\")]\n\n            >>> stim.Circuit(\"RX 0\").flow_generators()\n            [stim.Flow(\"1 -> X\")]\n\n            >>> for flow in stim.Circuit(\"MXX 0 1\").flow_generators():\n            ...     print(flow)\n            1 -> XX xor rec[0]\n            _X -> _X\n            X_ -> _X xor rec[0]\n            ZZ -> ZZ\n\n            >>> for flow in stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     rounds=2,\n            ...     distance=3,\n            ...     after_clifford_depolarization=1e-3,\n            ... ).flow_generators():\n            ...     print(flow)\n            1 -> rec[0]\n            1 -> rec[1]\n            1 -> rec[2]\n            1 -> rec[3]\n            1 -> rec[4]\n            1 -> rec[5]\n            1 -> rec[6]\n            1 -> ____Z\n            1 -> ___Z_\n            1 -> __Z__\n            1 -> _Z___\n            1 -> Z____\n        \"\"\"\n    @staticmethod\n    def from_file(\n        file: Union[io.TextIOBase, str, pathlib.Path],\n    ) -> stim.Circuit:\n        \"\"\"Reads a stim circuit from a file.\n\n        The file format is defined at\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n        Args:\n            file: A file path or open file object to read from.\n\n        Returns:\n            The circuit parsed from the file.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         print('H 5', file=f)\n            ...     circuit = stim.Circuit.from_file(path)\n            >>> circuit\n            stim.Circuit('''\n                H 5\n            ''')\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         print('CNOT 4 5', file=f)\n            ...     with open(path) as f:\n            ...         circuit = stim.Circuit.from_file(f)\n            >>> circuit\n            stim.Circuit('''\n                CX 4 5\n            ''')\n        \"\"\"\n    @staticmethod\n    def generated(\n        code_task: str,\n        *,\n        distance: int,\n        rounds: int,\n        after_clifford_depolarization: float = 0.0,\n        before_round_data_depolarization: float = 0.0,\n        before_measure_flip_probability: float = 0.0,\n        after_reset_flip_probability: float = 0.0,\n    ) -> stim.Circuit:\n        \"\"\"Generates common circuits.\n\n        The generated circuits can include configurable noise.\n\n        The generated circuits include DETECTOR and OBSERVABLE_INCLUDE annotations so\n        that their detection events and logical observables can be sampled.\n\n        The generated circuits include TICK annotations to mark the progression of time.\n        (E.g. so that converting them using `stimcirq.stim_circuit_to_cirq_circuit` will\n        produce a `cirq.Circuit` with the intended moment structure.)\n\n        Args:\n            code_task: A string identifying the type of circuit to generate. Available\n                code tasks are:\n                    - \"repetition_code:memory\"\n                    - \"surface_code:rotated_memory_x\"\n                    - \"surface_code:rotated_memory_z\"\n                    - \"surface_code:unrotated_memory_x\"\n                    - \"surface_code:unrotated_memory_z\"\n                    - \"color_code:memory_xyz\"\n            distance: The desired code distance of the generated circuit. The code\n                distance is the minimum number of physical errors needed to cause a\n                logical error. This parameter indirectly determines how many qubits the\n                generated circuit uses.\n            rounds: How many times the measurement qubits in the generated circuit will\n                be measured. Indirectly determines the duration of the generated\n                circuit.\n            after_clifford_depolarization: Defaults to 0. The probability (p) of\n                `DEPOLARIZE1(p)` operations to add after every single-qubit Clifford\n                operation and `DEPOLARIZE2(p)` operations to add after every two-qubit\n                Clifford operation. The after-Clifford depolarizing operations are only\n                included if this probability is not 0.\n            before_round_data_depolarization: Defaults to 0. The probability (p) of\n                `DEPOLARIZE1(p)` operations to apply to every data qubit at the start of\n                a round of stabilizer measurements. The start-of-round depolarizing\n                operations are only included if this probability is not 0.\n            before_measure_flip_probability: Defaults to 0. The probability (p) of\n                `X_ERROR(p)` operations applied to qubits before each measurement (X\n                basis measurements use `Z_ERROR(p)` instead). The before-measurement\n                flips are only included if this probability is not 0.\n            after_reset_flip_probability: Defaults to 0. The probability (p) of\n                `X_ERROR(p)` operations applied to qubits after each reset (X basis\n                resets use `Z_ERROR(p)` instead). The after-reset flips are only\n                included if this probability is not 0.\n\n        Returns:\n            The generated circuit.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     distance=4,\n            ...     rounds=10000,\n            ...     after_clifford_depolarization=0.0125)\n            >>> print(circuit)\n            R 0 1 2 3 4 5 6\n            TICK\n            CX 0 1 2 3 4 5\n            DEPOLARIZE2(0.0125) 0 1 2 3 4 5\n            TICK\n            CX 2 1 4 3 6 5\n            DEPOLARIZE2(0.0125) 2 1 4 3 6 5\n            TICK\n            MR 1 3 5\n            DETECTOR(1, 0) rec[-3]\n            DETECTOR(3, 0) rec[-2]\n            DETECTOR(5, 0) rec[-1]\n            REPEAT 9999 {\n                TICK\n                CX 0 1 2 3 4 5\n                DEPOLARIZE2(0.0125) 0 1 2 3 4 5\n                TICK\n                CX 2 1 4 3 6 5\n                DEPOLARIZE2(0.0125) 2 1 4 3 6 5\n                TICK\n                MR 1 3 5\n                SHIFT_COORDS(0, 1)\n                DETECTOR(1, 0) rec[-3] rec[-6]\n                DETECTOR(3, 0) rec[-2] rec[-5]\n                DETECTOR(5, 0) rec[-1] rec[-4]\n            }\n            M 0 2 4 6\n            DETECTOR(1, 1) rec[-3] rec[-4] rec[-7]\n            DETECTOR(3, 1) rec[-2] rec[-3] rec[-6]\n            DETECTOR(5, 1) rec[-1] rec[-2] rec[-5]\n            OBSERVABLE_INCLUDE(0) rec[-1]\n        \"\"\"\n    def get_detector_coordinates(\n        self,\n        only: object = None,\n    ) -> Dict[int, List[float]]:\n        \"\"\"Returns the coordinate metadata of detectors in the circuit.\n\n        Args:\n            only: Defaults to None (meaning include all detectors). A list of detector\n                indices to include in the result. Detector indices beyond the end of the\n                detector error model of the circuit cause an error.\n\n        Returns:\n            A dictionary mapping integers (detector indices) to lists of floats\n            (coordinates).\n\n            Detectors with no specified coordinate data are mapped to an empty tuple.\n            If `only` is specified, then `set(result.keys()) == set(only)`.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ...    DETECTOR(1, 2, 3) rec[-1]\n            ...    REPEAT 3 {\n            ...        DETECTOR(42) rec[-1]\n            ...        SHIFT_COORDS(100)\n            ...    }\n            ... ''')\n            >>> circuit.get_detector_coordinates()\n            {0: [], 1: [1.0, 2.0, 3.0], 2: [42.0], 3: [142.0], 4: [242.0]}\n            >>> circuit.get_detector_coordinates(only=[1])\n            {1: [1.0, 2.0, 3.0]}\n        \"\"\"\n    def get_final_qubit_coordinates(\n        self,\n    ) -> Dict[int, List[float]]:\n        \"\"\"Returns the coordinate metadata of qubits in the circuit.\n\n        If a qubit's coordinates are specified multiple times, only the last specified\n        coordinates are returned.\n\n        Returns:\n            A dictionary mapping qubit indices (integers) to coordinates (lists of\n            floats). Qubits that never had their coordinates specified are not included\n            in the result.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...    QUBIT_COORDS(1, 2, 3) 1\n            ... ''')\n            >>> circuit.get_final_qubit_coordinates()\n            {1: [1.0, 2.0, 3.0]}\n        \"\"\"\n    def has_all_flows(\n        self,\n        flows: Iterable[stim.Flow],\n        *,\n        unsigned: bool = False,\n    ) -> bool:\n        \"\"\"Determines if the circuit has all the given stabilizer flow or not.\n\n        This is a faster version of `all(c.has_flow(f) for f in flows)`. It's faster\n        because, behind the scenes, the circuit can be iterated once instead of once\n        per flow.\n\n        This method ignores any noise in the circuit.\n\n        Args:\n            flows: An iterable of `stim.Flow` instances representing the flows to check.\n            unsigned: Defaults to False. When False, the flows must be correct including\n                the sign of the Pauli strings. When True, only the Pauli terms need to\n                be correct; the signs are permitted to be inverted. In effect, this\n                requires the circuit to be correct up to Pauli gates.\n\n        Returns:\n            True if the circuit has the given flow; False otherwise.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('H 0').has_all_flows([\n            ...     stim.Flow('X -> Z'),\n            ...     stim.Flow('Y -> Y'),\n            ...     stim.Flow('Z -> X'),\n            ... ])\n            False\n\n            >>> stim.Circuit('H 0').has_all_flows([\n            ...     stim.Flow('X -> Z'),\n            ...     stim.Flow('Y -> -Y'),\n            ...     stim.Flow('Z -> X'),\n            ... ])\n            True\n\n            >>> stim.Circuit('H 0').has_all_flows([\n            ...     stim.Flow('X -> Z'),\n            ...     stim.Flow('Y -> Y'),\n            ...     stim.Flow('Z -> X'),\n            ... ], unsigned=True)\n            True\n\n        Caveats:\n            Currently, the unsigned=False version of this method is implemented by\n            performing 256 randomized tests. Each test has a 50% chance of a false\n            positive, and a 0% chance of a false negative. So, when the method returns\n            True, there is technically still a 2^-256 chance the circuit doesn't have\n            the flow. This is lower than the chance of a cosmic ray flipping the result.\n        \"\"\"\n    def has_flow(\n        self,\n        flow: stim.Flow,\n        *,\n        unsigned: bool = False,\n    ) -> bool:\n        \"\"\"Determines if the circuit has the given stabilizer flow or not.\n\n        A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer\n        P at the start of the circuit to the instantaneous stabilizer Q at the end of\n        the circuit. The flow may be mediated by certain measurements. For example,\n        a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and\n        the CNOT flows implemented by the circuit involve these measurements.\n\n        A flow like P -> Q means the circuit transforms P into Q.\n        A flow like 1 -> P means the circuit prepares P.\n        A flow like P -> 1 means the circuit measures P.\n        A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR).\n\n        This method ignores any noise in the circuit.\n\n        Args:\n            flow: The flow to check for.\n            unsigned: Defaults to False. When False, the flows must be correct including\n                the sign of the Pauli strings. When True, only the Pauli terms need to\n                be correct; the signs are permitted to be inverted. In effect, this\n                requires the circuit to be correct up to Pauli gates.\n\n        Returns:\n            True if the circuit has the given flow; False otherwise.\n\n        Examples:\n            >>> import stim\n\n            >>> m = stim.Circuit('M 0')\n            >>> m.has_flow(stim.Flow('Z -> Z'))\n            True\n            >>> m.has_flow(stim.Flow('X -> X'))\n            False\n            >>> m.has_flow(stim.Flow('Z -> I'))\n            False\n            >>> m.has_flow(stim.Flow('Z -> I xor rec[-1]'))\n            True\n            >>> m.has_flow(stim.Flow('Z -> rec[-1]'))\n            True\n\n            >>> cx58 = stim.Circuit('CX 5 8')\n            >>> cx58.has_flow(stim.Flow('X5 -> X5*X8'))\n            True\n            >>> cx58.has_flow(stim.Flow('X_ -> XX'))\n            False\n            >>> cx58.has_flow(stim.Flow('_____X___ -> _____X__X'))\n            True\n\n            >>> stim.Circuit('''\n            ...     RY 0\n            ... ''').has_flow(stim.Flow(\n            ...     output=stim.PauliString(\"Y\"),\n            ... ))\n            True\n\n            >>> stim.Circuit('''\n            ...     RY 0\n            ...     X_ERROR(0.1) 0\n            ... ''').has_flow(stim.Flow(\n            ...     output=stim.PauliString(\"Y\"),\n            ... ))\n            True\n\n            >>> stim.Circuit('''\n            ...     RY 0\n            ... ''').has_flow(stim.Flow(\n            ...     output=stim.PauliString(\"X\"),\n            ... ))\n            False\n\n            >>> stim.Circuit('''\n            ...     CX 0 1\n            ... ''').has_flow(stim.Flow(\n            ...     input=stim.PauliString(\"+X_\"),\n            ...     output=stim.PauliString(\"+XX\"),\n            ... ))\n            True\n\n            >>> stim.Circuit('''\n            ...     # Lattice surgery CNOT\n            ...     R 1\n            ...     MXX 0 1\n            ...     MZZ 1 2\n            ...     MX 1\n            ... ''').has_flow(stim.Flow(\n            ...     input=stim.PauliString(\"+X_X\"),\n            ...     output=stim.PauliString(\"+__X\"),\n            ...     measurements=[0, 2],\n            ... ))\n            True\n\n            >>> stim.Circuit('''\n            ...     H 0\n            ... ''').has_flow(\n            ...     stim.Flow(\"Y -> Y\"),\n            ...     unsigned=True,\n            ... )\n            True\n\n            >>> stim.Circuit('''\n            ...     H 0\n            ... ''').has_flow(\n            ...     stim.Flow(\"Y -> Y\"),\n            ...     unsigned=False,\n            ... )\n            False\n\n        Caveats:\n            Currently, the unsigned=False version of this method is implemented by\n            performing 256 randomized tests. Each test has a 50% chance of a false\n            positive, and a 0% chance of a false negative. So, when the method returns\n            True, there is technically still a 2^-256 chance the circuit doesn't have\n            the flow. This is lower than the chance of a cosmic ray flipping the result.\n        \"\"\"\n    def insert(\n        self,\n        index: int,\n        operation: Union[stim.CircuitInstruction, stim.Circuit],\n    ) -> None:\n        \"\"\"Inserts an operation at the given index, pushing existing operations forward.\n\n        Beware that inserted operations are automatically fused with the preceding\n        and following operations, if possible. This can make it complex to reason\n        about how the indices of operations change in response to insertions.\n\n        Args:\n            index: The index to insert at.\n\n                Must satisfy -len(circuit) <= index < len(circuit). Negative indices\n                are made non-negative by adding len(circuit) to them, so they refer to\n                indices relative to the end of the circuit instead of the start.\n\n                Instructions before the index are not shifted. Instructions that\n                were at or after the index are shifted forwards as needed.\n            operation: The object to insert. This can be a single\n                stim.CircuitInstruction or an entire stim.Circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...     H 0\n            ...     S 1\n            ...     X 2\n            ... ''')\n            >>> c.insert(1, stim.CircuitInstruction(\"Y\", [3, 4, 5]))\n            >>> c\n            stim.Circuit('''\n                H 0\n                Y 3 4 5\n                S 1\n                X 2\n            ''')\n            >>> c.insert(-1, stim.Circuit(\"S 999\\nCX 0 1\\nCZ 2 3\"))\n            >>> c\n            stim.Circuit('''\n                H 0\n                Y 3 4 5\n                S 1 999\n                CX 0 1\n                CZ 2 3\n                X 2\n            ''')\n        \"\"\"\n    def inverse(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a circuit that applies the same operations but inverted and in reverse.\n\n        If circuit starts with QUBIT_COORDS instructions, the returned circuit will\n        still have the same QUBIT_COORDS instructions in the same order at the start.\n\n        Returns:\n            A `stim.Circuit` that applies inverted operations in the reverse order.\n\n        Raises:\n            ValueError: The circuit contains operations that don't have an inverse,\n                such as measurements. There are also some unsupported operations\n                such as SHIFT_COORDS.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     S 0 1\n            ...     ISWAP 0 1 1 2\n            ... ''').inverse()\n            stim.Circuit('''\n                ISWAP_DAG 1 2 0 1\n                S_DAG 1 0\n            ''')\n\n            >>> stim.Circuit('''\n            ...     QUBIT_COORDS(1, 2) 0\n            ...     QUBIT_COORDS(4, 3) 1\n            ...     QUBIT_COORDS(9, 5) 2\n            ...     H 0 1\n            ...     REPEAT 100 {\n            ...         CX 0 1 1 2\n            ...         TICK\n            ...         S 1 2\n            ...     }\n            ... ''').inverse()\n            stim.Circuit('''\n                QUBIT_COORDS(1, 2) 0\n                QUBIT_COORDS(4, 3) 1\n                QUBIT_COORDS(9, 5) 2\n                REPEAT 100 {\n                    S_DAG 2 1\n                    TICK\n                    CX 1 2 0 1\n                }\n                H 1 0\n            ''')\n        \"\"\"\n    def likeliest_error_sat_problem(\n        self,\n        *,\n        quantization: int = 100,\n        format: str = 'WDIMACS',\n    ) -> str:\n        \"\"\"Makes a maxSAT problem for the circuit's likeliest undetectable logical error.\n\n        The output is a string describing the maxSAT problem in WDIMACS format\n        (see https://jix.github.io/varisat/manual/0.2.0/formats/dimacs.html). The\n        optimal solution to the problem is the highest likelihood set of error\n        mechanisms that combine to flip any logical observable while producing no\n        detection events).\n\n        If there are any errors with probability p > 0.5, they are inverted so\n        that the resulting weight ends up being positive. If there are errors\n        with weight close or equal to 0.5, they can end up with 0 weight meaning\n        that they can be included or not in the solution with no affect on the\n        likelihood.\n\n        There are many tools that can solve maxSAT problems in WDIMACS format.\n        One quick way to get started is to install pysat by running this BASH\n        terminal command:\n\n            pip install python-sat\n\n        Afterwards, you can run the included maxSAT solver \"RC2\" with this\n        Python code:\n\n            from pysat.examples.rc2 import RC2\n            from pysat.formula import WCNF\n\n            wcnf = WCNF(from_string=\"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\")\n\n            with RC2(wcnf) as rc2:\n            print(rc2.compute())\n            print(rc2.cost)\n\n        Much faster solvers are available online. For example, you can download\n        one of the entries in the 2023 maxSAT competition (see\n        https://maxsat-evaluations.github.io/2023) and run it on your problem by\n        running these BASH terminal commands:\n\n            wget https://maxsat-evaluations.github.io/2023/mse23-solver-src/exact/CASHWMaxSAT-CorePlus.zip\n            unzip CASHWMaxSAT-CorePlus.zip\n            ./CASHWMaxSAT-CorePlus/bin/cashwmaxsatcoreplus -bm -m your_problem.wcnf\n\n        Args:\n            format: Defaults to \"WDIMACS\", corresponding to WDIMACS format which is\n                described here: http://www.maxhs.org/docs/wdimacs.html\n            quantization: Defaults to 10. Error probabilities are converted to log-odds\n                and scaled/rounded to be positive integers at most this large. Setting\n                this argument to a larger number results in more accurate quantization\n                such that the returned error set should have a likelihood closer to the\n                true most likely solution. This comes at the cost of making some maxSAT\n                solvers slower.\n\n        Returns:\n            A string corresponding to the contents of a maxSAT problem file in the\n            requested format.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...   X_ERROR(0.1) 0\n            ...   M 0\n            ...   OBSERVABLE_INCLUDE(0) rec[-1]\n            ...   X_ERROR(0.4) 0\n            ...   M 0\n            ...   DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> print(circuit.likeliest_error_sat_problem(\n            ...   quantization=1000\n            ... ), end='')\n            p wcnf 2 4 4001\n            185 -1 0\n            1000 -2 0\n            4001 -1 0\n            4001 2 0\n        \"\"\"\n    def missing_detectors(\n        self,\n        *,\n        unknown_input: bool = False,\n    ) -> int:\n        \"\"\"Finds deterministic measurements independent of declared detectors/observables.\n\n        This method is useful for debugging missing detectors in a circuit, because it\n        identifies generators for uncovered degrees of freedom.\n\n        It's not recommended to use this method to solve for the detectors of a circuit.\n        The returned detectors are not guaranteed to be stable across versions, and\n        aren't optimized to be \"good\" (e.g. form a low weight basis or be matchable\n        if possible). It will also identify things that are technically determined\n        but that the user may not want to use as a detector, such as the fact that\n        in the first round after transversal Z basis initialization of a toric code\n        the product of all X stabilizer measurements is deterministic even though the\n        individual measurements are all random.\n\n        Args:\n            unknown_input: Defaults to False (inputs assumed to be in the |0> state).\n                When set to True, the inputs are instead treated as being in unknown\n                random states. For example, this means that Z-basis measurements at\n                the very beginning of the circuit will be considered random rather\n                than determined.\n\n        Returns:\n            A circuit containing DETECTOR instructions that specify the uncovered\n            degrees of freedom in the deterministic measurement sets of the input\n            circuit. The returned circuit can be appended to the input circuit to\n            get a circuit with no missing detectors.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     R 0\n            ...     M 0\n            ... ''').missing_detectors()\n            stim.Circuit('''\n                DETECTOR rec[-1]\n            ''')\n\n            >>> stim.Circuit('''\n            ...     MZZ 0 1\n            ...     MYY 0 1\n            ...     MXX 0 1\n            ...     DEPOLARIZE1(0.1) 0 1\n            ...     MZZ 0 1\n            ...     MYY 0 1\n            ...     MXX 0 1\n            ...     DETECTOR rec[-1] rec[-4]\n            ...     DETECTOR rec[-2] rec[-5]\n            ...     DETECTOR rec[-3] rec[-6]\n            ... ''').missing_detectors(unknown_input=True)\n            stim.Circuit('''\n                DETECTOR rec[-3] rec[-2] rec[-1]\n            ''')\n        \"\"\"\n    @property\n    def num_detectors(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of bits produced when sampling the circuit's detectors.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ...    REPEAT 100 {\n            ...        M 0 1 2\n            ...        DETECTOR rec[-1]\n            ...        DETECTOR rec[-2]\n            ...    }\n            ... ''')\n            >>> c.num_detectors\n            201\n        \"\"\"\n    @property\n    def num_measurements(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of bits produced when sampling the circuit's measurements.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    M 0\n            ...    REPEAT 100 {\n            ...        M 0 1\n            ...    }\n            ... ''')\n            >>> c.num_measurements\n            201\n        \"\"\"\n    @property\n    def num_observables(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of logical observables defined by the circuit.\n\n        This is one more than the largest index that appears as an argument to an\n        OBSERVABLE_INCLUDE instruction.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    M 0\n            ...    OBSERVABLE_INCLUDE(2) rec[-1]\n            ...    OBSERVABLE_INCLUDE(5) rec[-1]\n            ... ''')\n            >>> c.num_observables\n            6\n        \"\"\"\n    @property\n    def num_qubits(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of qubits used when simulating the circuit.\n\n        This is always one more than the largest qubit index used by the circuit.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...    X 0\n            ...    M 0 1\n            ... ''').num_qubits\n            2\n            >>> stim.Circuit('''\n            ...    X 0\n            ...    M 0 1\n            ...    H 100\n            ... ''').num_qubits\n            101\n        \"\"\"\n    @property\n    def num_sweep_bits(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of sweep bits needed to completely configure the circuit.\n\n        This is always one more than the largest sweep bit index used by the circuit.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...    CX sweep[2] 0\n            ... ''').num_sweep_bits\n            3\n            >>> stim.Circuit('''\n            ...    CZ sweep[5] 0\n            ...    CX sweep[2] 0\n            ... ''').num_sweep_bits\n            6\n        \"\"\"\n    @property\n    def num_ticks(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of TICK instructions executed when running the circuit.\n\n        TICKs in loops are counted once per iteration.\n\n        Returns:\n            The number of ticks executed by the circuit.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit().num_ticks\n            0\n\n            >>> stim.Circuit('''\n            ...    TICK\n            ... ''').num_ticks\n            1\n\n            >>> stim.Circuit('''\n            ...    H 0\n            ...    TICK\n            ...    CX 0 1\n            ...    TICK\n            ... ''').num_ticks\n            2\n\n            >>> stim.Circuit('''\n            ...    H 0\n            ...    TICK\n            ...    REPEAT 100 {\n            ...        CX 0 1\n            ...        TICK\n            ...    }\n            ... ''').num_ticks\n            101\n        \"\"\"\n    def pop(\n        self,\n        index: int = -1,\n    ) -> Union[stim.CircuitInstruction, stim.CircuitRepeatBlock]:\n        \"\"\"Pops an operation from the end of the circuit, or at the given index.\n\n        Args:\n            index: Defaults to -1 (end of circuit). The index to pop from.\n\n        Returns:\n            The popped instruction.\n\n        Raises:\n            IndexError: The given index is outside the bounds of the circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...     H 0\n            ...     S 1\n            ...     X 2\n            ...     Y 3\n            ... ''')\n            >>> c.pop()\n            stim.CircuitInstruction('Y', [stim.GateTarget(3)], [])\n            >>> c.pop(1)\n            stim.CircuitInstruction('S', [stim.GateTarget(1)], [])\n            >>> c\n            stim.Circuit('''\n                H 0\n                X 2\n            ''')\n        \"\"\"\n    def reference_detector_and_observable_signs(\n        self,\n        *,\n        bit_packed: bool = False,\n    ) -> Tuple[np.ndarray, np.ndarray]:\n        \"\"\"Determines noiseless parities of the measurement sets of detectors/observables.\n\n        BEWARE: the returned values are NOT the \"expected value of the\n        detector/observable\". Stim consistently defines the value of a\n        detector/observable as whether or not it flipped, so the expected value of a\n        detector/observable is vacuously always 0 (not flipped). This method instead\n        returns the \"sign\"; the expected parity of the measurement set declared by the\n        detector/observable. The sign is the baseline used to determine if a flip\n        occurred. A detector/observable's value is whether its sign disagrees with the\n        measured parity of its measurement set.\n\n        Note that this method doesn't account for sweep bits. It will effectively ignore\n        instructions like `CX sweep[0] 0`.\n\n        Args:\n            bit_packed: Defaults to False. Determines whether the output numpy arrays\n                use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n        Returns:\n            A (det, obs) tuple with numpy arrays containing the reference parities.\n\n            if bit_packed:\n                det.shape == (math.ceil(num_detectors / 8),)\n                det.dtype == np.uint8\n                obs.shape == (math.ceil(num_observables / 8),)\n                obs.dtype == np.uint8\n            else:\n                det.shape == (num_detectors,)\n                det.dtype == np.bool_\n                obs.shape == (num_observables,)\n                obs.dtype == np.bool_\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     X 1\n            ...     M 0 1\n            ...     DETECTOR rec[-1]\n            ...     DETECTOR rec[-2]\n            ...     OBSERVABLE_INCLUDE(3) rec[-1] rec[-2]\n            ... ''').reference_detector_and_observable_signs()\n            (array([ True, False]), array([False, False, False,  True]))\n        \"\"\"\n    def reference_sample(\n        self,\n        *,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Samples the given circuit in a deterministic fashion.\n\n        Discards all noisy operations, and biases all collapse events\n        towards +Z instead of randomly +Z/-Z.\n\n        Args:\n            bit_packed: Defaults to False. Determines whether the output numpy arrays\n                use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n        Returns:\n            A numpy array containing the reference sample.\n\n            if bit_packed:\n                shape == (math.ceil(num_measurements / 8),)\n                dtype == np.uint8\n            else:\n                shape == (num_measurements,)\n                dtype == np.bool_\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     X 1\n            ...     M 0 1\n            ... ''').reference_sample()\n            array([False,  True])\n        \"\"\"\n    def search_for_undetectable_logical_errors(\n        self,\n        *,\n        dont_explore_detection_event_sets_with_size_above: int,\n        dont_explore_edges_with_degree_above: int,\n        dont_explore_edges_increasing_symptom_degree: bool,\n        canonicalize_circuit_errors: bool = False,\n    ) -> List[stim.ExplainedError]:\n        \"\"\"Searches for small sets of errors that form an undetectable logical error.\n\n        THIS IS A HEURISTIC METHOD. It does not guarantee that it will find errors of\n        particular sizes, or with particular properties. The errors it finds are a\n        tangled combination of the truncation parameters you specify, internal\n        optimizations which are correct when not truncating, and minutia of the circuit\n        being considered.\n\n        If you want a well behaved method that does provide guarantees of finding errors\n        of a particular type, use `stim.Circuit.shortest_graphlike_error`. This method\n        is more thorough than that (assuming you don't truncate so hard you omit\n        graphlike edges), but exactly how thorough is difficult to describe. It's also\n        not guaranteed that the behavior of this method will not be changed in the\n        future in a way that permutes which logical errors are found and which are\n        missed.\n\n        This search method considers hyper errors, so it has worst case exponential\n        runtime. It is important to carefully consider the arguments you are providing,\n        which truncate the search space and trade cost for quality.\n\n        The search progresses by starting from each error that crosses a logical\n        observable, noting which detection events each error produces, and then\n        iteratively adding in errors touching those detection events attempting to\n        cancel out the detection event with the lowest index.\n\n        Beware that the choice of logical observable can interact with the truncation\n        options. Using different observables can change whether or not the search\n        succeeds, even if those observables are equal modulo the stabilizers of the\n        code. This is because the edges crossing logical observables are used as\n        starting points for the search, and starting from different places along a path\n        will result in different numbers of symptoms in intermediate states as the\n        search progresses. For example, if the logical observable is next to a boundary,\n        then the starting edges are likely boundary edges (degree 1) with 'room to\n        grow', whereas if the observable was running through the bulk then the starting\n        edges will have degree at least 2.\n\n        Args:\n            dont_explore_detection_event_sets_with_size_above: Truncates the search\n                space by refusing to cross an edge (i.e. add an error) when doing so\n                would produce an intermediate state that has more detection events than\n                this limit.\n            dont_explore_edges_with_degree_above: Truncates the search space by refusing\n                to consider errors that cause a lot of detection events. For example,\n                you may only want to consider graphlike errors which have two or fewer\n                detection events.\n            dont_explore_edges_increasing_symptom_degree: Truncates the search space by\n                refusing to cross an edge (i.e. add an error) when doing so would\n                produce an intermediate state that has more detection events that the\n                previous intermediate state. This massively improves the efficiency of\n                the search because instead of, for example, exploring all n^4 possible\n                detection event sets with 4 symptoms, the search will attempt to cancel\n                out symptoms one by one.\n            canonicalize_circuit_errors: Whether or not to use one representative for\n                equal-symptom circuit errors.\n\n                False (default): Each DEM error lists every possible circuit error that\n                    single handedly produces those symptoms as a potential match. This\n                    is verbose but gives complete information.\n                True: Each DEM error is matched with one possible circuit error that\n                    single handedly produces those symptoms, with a preference towards\n                    errors that are simpler (e.g. apply Paulis to fewer qubits). This\n                    discards mostly-redundant information about different ways to\n                    produce the same symptoms in order to give a succinct result.\n\n        Returns:\n            A list of error mechanisms that cause an undetected logical error.\n\n            Each entry in the list is a `stim.ExplainedError` detailing the location\n            and effects of a single physical error. The effects of the entire list\n            combine to produce a logical frame change without any detection events.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit.generated(\n            ...     \"surface_code:rotated_memory_x\",\n            ...     rounds=5,\n            ...     distance=5,\n            ...     after_clifford_depolarization=0.001)\n            >>> print(len(circuit.search_for_undetectable_logical_errors(\n            ...     dont_explore_detection_event_sets_with_size_above=4,\n            ...     dont_explore_edges_with_degree_above=4,\n            ...     dont_explore_edges_increasing_symptom_degree=True,\n            ... )))\n            5\n        \"\"\"\n    def shortest_error_sat_problem(\n        self,\n        *,\n        format: str = 'WDIMACS',\n    ) -> str:\n        \"\"\"Makes a maxSAT problem of the circuit's distance, that other tools can solve.\n\n        The output is a string describing the maxSAT problem in WDIMACS format\n        (see https://jix.github.io/varisat/manual/0.2.0/formats/dimacs.html). The\n        optimal solution to the problem is the fault distance of the circuit (the\n        minimum number of error mechanisms that combine to flip any logical observable\n        while producing no detection events). This method ignores the probabilities of\n        the error mechanisms since it only cares about minimizing the number of errors\n        triggered.\n\n        There are many tools that can solve maxSAT problems in WDIMACS format.\n        One quick way to get started is to install pysat by running this BASH\n        terminal command:\n\n            pip install python-sat\n\n        Afterwards, you can run the included maxSAT solver \"RC2\" with this\n        Python code:\n\n            from pysat.examples.rc2 import RC2\n            from pysat.formula import WCNF\n\n            wcnf = WCNF(from_string=\"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\")\n\n            with RC2(wcnf) as rc2:\n            print(rc2.compute())\n            print(rc2.cost)\n\n        Much faster solvers are available online. For example, you can download\n        one of the entries in the 2023 maxSAT competition (see\n        https://maxsat-evaluations.github.io/2023) and run it on your problem by\n        running these BASH terminal commands:\n\n            wget https://maxsat-evaluations.github.io/2023/mse23-solver-src/exact/CASHWMaxSAT-CorePlus.zip\n            unzip CASHWMaxSAT-CorePlus.zip\n            ./CASHWMaxSAT-CorePlus/bin/cashwmaxsatcoreplus -bm -m your_problem.wcnf\n\n        Args:\n            format: Defaults to \"WDIMACS\", corresponding to WDIMACS format which is\n                described here: http://www.maxhs.org/docs/wdimacs.html\n\n        Returns:\n            A string corresponding to the contents of a maxSAT problem file in the\n            requested format.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...   X_ERROR(0.1) 0\n            ...   M 0\n            ...   OBSERVABLE_INCLUDE(0) rec[-1]\n            ...   X_ERROR(0.4) 0\n            ...   M 0\n            ...   DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> print(circuit.shortest_error_sat_problem(), end='')\n            p wcnf 2 4 5\n            1 -1 0\n            1 -2 0\n            5 -1 0\n            5 2 0\n        \"\"\"\n    def shortest_graphlike_error(\n        self,\n        *,\n        ignore_ungraphlike_errors: bool = True,\n        canonicalize_circuit_errors: bool = False,\n    ) -> List[stim.ExplainedError]:\n        \"\"\"Finds a minimum set of graphlike errors to produce an undetected logical error.\n\n        A \"graphlike error\" is an error that creates at most two detection events\n        (causes a change in the parity of the measurement sets of at most two DETECTOR\n        annotations).\n\n        Note that this method does not pay attention to error probabilities (other than\n        ignoring errors with probability 0). It searches for a logical error with the\n        minimum *number* of physical errors, not the maximum probability of those\n        physical errors all occurring.\n\n        This method works by converting the circuit into a `stim.DetectorErrorModel`\n        using `circuit.detector_error_model(...)`, computing the shortest graphlike\n        error of the error model, and then converting the physical errors making up that\n        logical error back into representative circuit errors.\n\n        Args:\n            ignore_ungraphlike_errors:\n                False: Attempt to decompose any ungraphlike errors in the circuit into\n                    graphlike parts. If this fails, raise an exception instead of\n                    continuing.\n\n                    Note: in some cases, graphlike errors only appear as parts of\n                    decomposed ungraphlike errors. This can produce a result that lists\n                    DEM errors with zero matching circuit errors, because the only way\n                    to achieve those errors is by combining a decomposed error with a\n                    graphlike error. As a result, when using this option it is NOT\n                    guaranteed that the length of the result is an upper bound on the\n                    true code distance. That is only the case if every item in the\n                    result lists at least one matching circuit error.\n                True (default): Ungraphlike errors are simply skipped as if they weren't\n                    present, even if they could become graphlike if decomposed. This\n                    guarantees the length of the result is an upper bound on the true\n                    code distance.\n            canonicalize_circuit_errors: Whether or not to use one representative for\n                equal-symptom circuit errors.\n\n                False (default): Each DEM error lists every possible circuit error that\n                    single handedly produces those symptoms as a potential match. This\n                    is verbose but gives complete information.\n                True: Each DEM error is matched with one possible circuit error that\n                    single handedly produces those symptoms, with a preference towards\n                    errors that are simpler (e.g. apply Paulis to fewer qubits). This\n                    discards mostly-redundant information about different ways to\n                    produce the same symptoms in order to give a succinct result.\n\n        Returns:\n            A list of error mechanisms that cause an undetected logical error.\n\n            Each entry in the list is a `stim.ExplainedError` detailing the location\n            and effects of a single physical error. The effects of the entire list\n            combine to produce a logical frame change without any detection events.\n\n        Examples:\n            >>> import stim\n\n            >>> circuit = stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     rounds=10,\n            ...     distance=7,\n            ...     before_round_data_depolarization=0.01)\n            >>> len(circuit.shortest_graphlike_error())\n            7\n        \"\"\"\n    def solve_flow_measurements(\n        self,\n        flows: List[stim.Flow],\n    ) -> List[Optional[List[int]]]:\n        \"\"\"Finds measurements to explain the starts/ends of the given flows, ignoring sign.\n\n        CAUTION: it's not guaranteed that the solutions returned by this method are\n        minimal. It may use 20 measurements when only 2 are needed. The method applies\n        some simple heuristics that attempt to reduce the size, but these heuristics\n        aren't perfect and don't make any strong guarantees.\n\n        The recommended way to use this method is on small parts of a circuit, such as a\n        single surface code round. The ideal use case is when there is exactly one\n        solution for each flow, because then the method behaves predictably and\n        consistently. When there are multiple solutions, the method has no real way to\n        pick out a \"good\" solution rather than a \"cataclysmic trash fire of a\" solution.\n        For example, if you have a multi-round surface code circuit with open time\n        boundaries and solve the flow 1 -> Z1*Z2*Z3*Z4, then there's a good solution\n        (the Z1*Z2*Z3*Z4 measurement from the last round), various mediocre solutions\n        (a Z1*Z2*Z3*Z4 measurement from a different round), and lots of terrible\n        solutions (a combination of multiple Z1*Z2*Z3*Z4 measurements from an odd number\n        of rounds, times a random combination of unrelated detectors). The method is\n        permitted to return any of those solutions.\n\n        Args:\n            flows: A list of flows, each of which to be solved. Measurements and signs\n                are entirely ignored.\n\n                An error is raised if one of the given flows has an identity pauli\n                string as its input and as its output, despite the fact that this case\n                has a vacuous solution (no measurements). This error is only present as\n                a safety check that catches some possible bugs in the calling code, such\n                as accidentally applying this method to detector flows. This error may\n                be removed in the future, so that the vacuous case succeeds vacuously.\n\n        Returns:\n            A list of solutions for each given flow.\n\n            If no solution exists for flows[k], then solutions[k] is None.\n            Otherwise, solutions[k] is a list of measurement indices for flows[k].\n\n            When solutions[k] is not None, it's guaranteed that\n\n                circuit.has_flow(stim.Flow(\n                    input=flows[k].input,\n                    output=flows[k].output,\n                    measurements=solutions[k],\n                ), unsigned=True)\n\n        Raises:\n            ValueError:\n                A flow had an empty input and output.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     M 2\n            ... ''').solve_flow_measurements([\n            ...     stim.Flow(\"Z2 -> 1\"),\n            ... ])\n            [[0]]\n\n            >>> stim.Circuit('''\n            ...     M 2\n            ... ''').solve_flow_measurements([\n            ...     stim.Flow(\"X2 -> X2\"),\n            ... ])\n            [None]\n\n            >>> stim.Circuit('''\n            ...     MXX 0 1\n            ... ''').solve_flow_measurements([\n            ...     stim.Flow(\"YY -> ZZ\"),\n            ... ])\n            [[0]]\n\n            >>> # Rep code cycle\n            >>> stim.Circuit('''\n            ...     R 1 3\n            ...     CX 0 1 2 3\n            ...     CX 4 3 2 1\n            ...     M 1 3\n            ... ''').solve_flow_measurements([\n            ...     stim.Flow(\"1 -> Z0*Z4\"),\n            ...     stim.Flow(\"Z0 -> Z2\"),\n            ...     stim.Flow(\"X0*X2*X4 -> X0*X2*X4\"),\n            ...     stim.Flow(\"Y0 -> Y0\"),\n            ... ])\n            [[0, 1], [0], [], None]\n        \"\"\"\n    def time_reversed_for_flows(\n        self,\n        flows: Iterable[stim.Flow],\n        *,\n        dont_turn_measurements_into_resets: bool = False,\n    ) -> Tuple[stim.Circuit, List[stim.Flow]]:\n        \"\"\"Time-reverses the circuit while preserving error correction structure.\n\n        This method returns a circuit that has the same internal detecting regions\n        as the given circuit, as well as the same internal-to-external flows given\n        in the `flows` argument, except they are all time-reversed. For example, if\n        you pass a fault tolerant preparation circuit into this method (1 -> Z), the\n        result will be a fault tolerant *measurement* circuit (Z -> 1). Or, if you\n        pass a fault tolerant C_XYZ circuit into this method (X->Y, Y->Z, and Z->X),\n        the result will be a fault tolerant C_ZYX circuit (X->Z, Y->X, and Z->Y).\n\n        Note that this method doesn't guarantee that it will preserve the *sign* of the\n        detecting regions or stabilizer flows. For example, inverting a memory circuit\n        that preserves a logical observable (X->X and Z->Z) may produce a\n        memory circuit that always bit flips the logical observable (X->X and Z->-Z) or\n        that dynamically adjusts the logical observable in response to measurements\n        (like \"X -> X xor rec[-1]\" and \"Z -> Z xor rec[-2]\").\n\n        This method will turn time-reversed resets into measurements, and attempts to\n        turn time-reversed measurements into resets. A measurement will time-reverse\n        into a reset if some annotated detectors, annotated observables, or given flows\n        have detecting regions with sensitivity just before the measurement but none\n        have detecting regions with sensitivity after the measurement.\n\n        In some cases this method will have to introduce new operations. In particular,\n        when a measurement-reset operation has a noisy result, time-reversing this\n        measurement noise produces reset noise. But the measure-reset operations don't\n        have built-in reset noise, so the reset noise is specified by adding an X_ERROR\n        or Z_ERROR noise instruction after the time-reversed measure-reset operation.\n\n        Args:\n            flows: Flows you care about, that reach past the start/end of the given\n                circuit. The result will contain an inverted flow for each of these\n                given flows. You need this information because it reveals the\n                measurements needed to produce the inverted flows that you care\n                about.\n\n                An exception will be raised if the circuit doesn't have all these\n                flows. The inverted circuit will have the inverses of these flows\n                (ignoring sign).\n            dont_turn_measurements_into_resets: Defaults to False. When set to\n                True, measurements will time-reverse into measurements even if\n                nothing is sensitive to the measured qubit after the measurement\n                completes. This guarantees the output circuit has *all* flows\n                that the input circuit has (up to sign and feedback), even ones\n                that aren't annotated.\n\n        Returns:\n            An (inverted_circuit, inverted_flows) tuple.\n\n            inverted_circuit is the qec inverse of the given circuit.\n\n            inverted_flows is a list of flows, matching up by index with the flows\n            given as arguments to the method. The input, output, and sign fields\n            of these flows are boring. The useful field is measurement_indices,\n            because it's difficult to predict which measurements are needed for\n            the inverted flow due to effects such as implicitly-included resets\n            inverting into explicitly-included measurements.\n\n        Caveats:\n            Currently, this method doesn't compute the sign of the inverted flows.\n            It unconditionally sets the sign to False.\n\n        Examples:\n            >>> import stim\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     R 0\n            ...     H 0\n            ...     S 0\n            ...     MY 0\n            ...     DETECTOR rec[-1]\n            ... ''').time_reversed_for_flows([])\n            >>> inv_circuit\n            stim.Circuit('''\n                RY 0\n                S_DAG 0\n                H 0\n                M 0\n                DETECTOR rec[-1]\n            ''')\n            >>> inv_flows\n            []\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     M 0\n            ... ''').time_reversed_for_flows([\n            ...     stim.Flow(\"Z -> rec[-1]\"),\n            ... ])\n            >>> inv_circuit\n            stim.Circuit('''\n                R 0\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"1 -> Z\")]\n            >>> inv_circuit.has_all_flows(inv_flows, unsigned=True)\n            True\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     R 0\n            ... ''').time_reversed_for_flows([\n            ...     stim.Flow(\"1 -> Z\"),\n            ... ])\n            >>> inv_circuit\n            stim.Circuit('''\n                M 0\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"Z -> rec[-1]\")]\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     M 0\n            ... ''').time_reversed_for_flows([\n            ...     stim.Flow(\"1 -> Z xor rec[-1]\"),\n            ... ])\n            >>> inv_circuit\n            stim.Circuit('''\n                M 0\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"Z -> rec[-1]\")]\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     M 0\n            ... ''').time_reversed_for_flows(\n            ...     flows=[stim.Flow(\"Z -> rec[-1]\")],\n            ...     dont_turn_measurements_into_resets=True,\n            ... )\n            >>> inv_circuit\n            stim.Circuit('''\n                M 0\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"1 -> Z xor rec[-1]\")]\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     MR(0.125) 0\n            ... ''').time_reversed_for_flows([])\n            >>> inv_circuit\n            stim.Circuit('''\n                MR 0\n                X_ERROR(0.125) 0\n            ''')\n            >>> inv_flows\n            []\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     MXX 0 1\n            ...     H 0\n            ... ''').time_reversed_for_flows([\n            ...     stim.Flow(\"ZZ -> YY xor rec[-1]\"),\n            ...     stim.Flow(\"ZZ -> XZ\"),\n            ... ])\n            >>> inv_circuit\n            stim.Circuit('''\n                H 0\n                MXX 0 1\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"YY -> ZZ xor rec[-1]\"), stim.Flow(\"XZ -> ZZ\")]\n\n            >>> stim.Circuit.generated(\n            ...     \"surface_code:rotated_memory_x\",\n            ...     distance=2,\n            ...     rounds=1,\n            ... ).time_reversed_for_flows([])[0]\n            stim.Circuit('''\n                QUBIT_COORDS(1, 1) 1\n                QUBIT_COORDS(2, 0) 2\n                QUBIT_COORDS(3, 1) 3\n                QUBIT_COORDS(1, 3) 6\n                QUBIT_COORDS(2, 2) 7\n                QUBIT_COORDS(3, 3) 8\n                QUBIT_COORDS(2, 4) 12\n                RX 8 6 3 1\n                MR 12 7 2\n                TICK\n                H 12 2\n                TICK\n                CX 1 7 12 6\n                TICK\n                CX 6 7 12 8\n                TICK\n                CX 3 7 2 1\n                TICK\n                CX 8 7 2 3\n                TICK\n                H 12 2\n                TICK\n                M 12 7 2\n                DETECTOR(2, 0, 1) rec[-1]\n                DETECTOR(2, 4, 1) rec[-3]\n                MX 8 6 3 1\n                DETECTOR(2, 0, 0) rec[-5] rec[-2] rec[-1]\n                DETECTOR(2, 4, 0) rec[-7] rec[-4] rec[-3]\n                OBSERVABLE_INCLUDE(0) rec[-3] rec[-1]\n            ''')\n        \"\"\"\n    def to_crumble_url(\n        self,\n        *,\n        skip_detectors: bool = False,\n        mark: Optional[Dict[int, List[stim.ExplainedError]]] = None,\n    ) -> str:\n        \"\"\"Returns a URL that opens up crumble and loads this circuit into it.\n\n        Crumble is a tool for editing stabilizer circuits, and visualizing their\n        stabilizer flows. Its source code is in the `glue/crumble` directory of\n        the stim code repository on github. A prebuilt version is made available\n        at https://algassert.com/crumble, which is what the URL returned by this\n        method will point to.\n\n        Args:\n            skip_detectors: Defaults to False. If set to True, detectors from the\n                circuit aren't included in the crumble URL. This can reduce visual\n                clutter in crumble, and improve its performance, since it doesn't\n                need to indicate or track the sensitivity regions of detectors.\n            mark: Defaults to None (no marks). If set to a dictionary from int to\n                errors, such as `mark={1: circuit.shortest_graphlike_error()}`,\n                then the errors will be highlighted and tracked forward by crumble.\n\n        Returns:\n            A URL that can be opened in a web browser.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ...     S 1\n            ... ''').to_crumble_url()\n            'https://algassert.com/crumble#circuit=H_0;CX_0_1;S_1_'\n\n            >>> circuit = stim.Circuit('''\n            ...     M(0.25) 0 1 2\n            ...     DETECTOR rec[-1] rec[-2]\n            ...     DETECTOR rec[-2] rec[-3]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''')\n            >>> err = circuit.shortest_graphlike_error(canonicalize_circuit_errors=True)\n            >>> circuit.to_crumble_url(skip_detectors=True, mark={1: err})\n            'https://algassert.com/crumble#circuit=;TICK;MARKX(1)1;MARKX(1)2;MARKX(1)0;TICK;M(0.25)0_1_2;OI(0)rec[-1]_'\n        \"\"\"\n    def to_file(\n        self,\n        file: Union[io.TextIOBase, str, pathlib.Path],\n    ) -> None:\n        \"\"\"Writes the stim circuit to a file.\n\n        The file format is defined at\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n        Args:\n            file: A file path or an open file to write to.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> c = stim.Circuit('H 5\\nX 0')\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         c.to_file(f)\n            ...     with open(path) as f:\n            ...         contents = f.read()\n            >>> contents\n            'H 5\\nX 0\\n'\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     c.to_file(path)\n            ...     with open(path) as f:\n            ...         contents = f.read()\n            >>> contents\n            'H 5\\nX 0\\n'\n        \"\"\"\n    def to_qasm(\n        self,\n        *,\n        open_qasm_version: int,\n        skip_dets_and_obs: bool = False,\n    ) -> str:\n        \"\"\"Creates an equivalent OpenQASM implementation of the circuit.\n\n        Args:\n            open_qasm_version: The version of OpenQASM to target.\n                This should be set to 2 or to 3.\n\n                Differences between the versions are:\n                    - Support for operations on classical bits (only version 3).\n                        This means DETECTOR and OBSERVABLE_INCLUDE only work with\n                        version 3.\n                    - Support for feedback operations (only version 3).\n                    - Support for subroutines (only version 3). Without subroutines,\n                        non-standard dissipative gates like MR and RX need to decompose\n                        inline every single time they're used.\n                    - Minor name changes (e.g. creg -> bit, qelib1.inc -> stdgates.inc).\n            skip_dets_and_obs: Defaults to False. When set to False, the output will\n                include a `dets` register and an `obs` register (assuming the circuit\n                has detectors and observables). These registers will be computed as part\n                of running the circuit. This requires performing a simulation of the\n                circuit, in order to correctly account for the expected value of\n                measurements.\n\n                When set to True, the `dets` and `obs` registers are not included in the\n                output, and no simulation of the circuit is performed.\n\n        Returns:\n            The OpenQASM code as a string.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     R 0 1\n            ...     X 1\n            ...     H 0\n            ...     CX 0 1\n            ...     M 0 1\n            ...     DETECTOR rec[-1] rec[-2]\n            ... ''');\n            >>> qasm = circuit.to_qasm(open_qasm_version=3);\n            >>> print(qasm.strip().replace('\\n\\n', '\\n'))\n            OPENQASM 3.0;\n            include \"stdgates.inc\";\n            qreg q[2];\n            creg rec[2];\n            creg dets[1];\n            reset q[0];\n            reset q[1];\n            x q[1];\n            h q[0];\n            cx q[0], q[1];\n            measure q[0] -> rec[0];\n            measure q[1] -> rec[1];\n            dets[0] = rec[1] ^ rec[0] ^ 1;\n        \"\"\"\n    def to_quirk_url(\n        self,\n    ) -> str:\n        \"\"\"Returns a URL that opens up quirk and loads this circuit into it.\n\n        Quirk is an open source drag and drop circuit editor with support for up to 16\n        qubits. Its source code is available at https://github.com/strilanc/quirk\n        and a prebuilt version is available at https://algassert.com/quirk, which is\n        what the URL returned by this method will point to.\n\n        Quirk doesn't support features like noise, feedback, or detectors. This method\n        will simply drop any unsupported operations from the circuit when producing\n        the URL.\n\n        Returns:\n            A URL that can be opened in a web browser.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ...     S 1\n            ... ''').to_quirk_url()\n            'https://algassert.com/quirk#circuit={\"cols\":[[\"H\"],[\"•\",\"X\"],[1,\"Z^½\"]]}'\n        \"\"\"\n    def to_tableau(\n        self,\n        *,\n        ignore_noise: bool = False,\n        ignore_measurement: bool = False,\n        ignore_reset: bool = False,\n    ) -> stim.Tableau:\n        \"\"\"Converts the circuit into an equivalent stabilizer tableau.\n\n        Args:\n            ignore_noise: Defaults to False. When False, any noise operations in the\n                circuit will cause the conversion to fail with an exception. When True,\n                noise operations are skipped over as if they weren't even present in the\n                circuit.\n            ignore_measurement: Defaults to False. When False, any measurement\n                operations in the circuit will cause the conversion to fail with an\n                exception. When True, measurement operations are skipped over as if they\n                weren't even present in the circuit.\n            ignore_reset: Defaults to False. When False, any reset operations in the\n                circuit will cause the conversion to fail with an exception. When True,\n                reset operations are skipped over as if they weren't even present in the\n                circuit.\n\n        Returns:\n            A tableau equivalent to the circuit (up to global phase).\n\n        Raises:\n            ValueError:\n                The circuit contains noise operations but ignore_noise=False.\n                OR\n                The circuit contains measurement operations but\n                ignore_measurement=False.\n                OR\n                The circuit contains reset operations but ignore_reset=False.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ... ''').to_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n        \"\"\"\n    def with_inlined_feedback(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a circuit without feedback with rewritten detectors/observables.\n\n        When a feedback operation affects the expected parity of a detector or\n        observable, the measurement controlling that feedback operation is implicitly\n        part of the measurement set that defines the detector or observable. This\n        method removes all feedback, but avoids changing the meaning of detectors or\n        observables by turning these implicit measurement dependencies into explicit\n        measurement dependencies added to the observable or detector.\n\n        This method guarantees that the detector error model derived from the original\n        circuit, and the transformed circuit, will be equivalent (modulo floating point\n        rounding errors and variations in where loops are placed). Specifically, the\n        following should be true for any circuit:\n\n            dem1 = circuit.flattened().detector_error_model()\n            dem2 = circuit.with_inlined_feedback().flattened().detector_error_model()\n            assert dem1.approx_equals(dem2, 1e-5)\n\n        Returns:\n            A `stim.Circuit` with feedback operations removed, with rewritten DETECTOR\n            instructions (as needed to avoid changing the meaning of each detector), and\n            with additional OBSERVABLE_INCLUDE instructions (as needed to avoid changing\n            the meaning of each observable).\n\n            The circuit's function is permitted to differ from the original in that\n            any feedback operation can be pushed to the end of the circuit and\n            discarded. All non-feedback operations must stay where they are, preserving\n            the structure of the circuit.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     CX 0 1        # copy to measure qubit\n            ...     M 1           # measure first time\n            ...     CX rec[-1] 1  # use feedback to reset measurement qubit\n            ...     CX 0 1        # copy to measure qubit\n            ...     M 1           # measure second time\n            ...     DETECTOR rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').with_inlined_feedback()\n            stim.Circuit('''\n                CX 0 1\n                M 1\n                OBSERVABLE_INCLUDE(0) rec[-1]\n                CX 0 1\n                M 1\n                DETECTOR rec[-1]\n                OBSERVABLE_INCLUDE(0) rec[-1]\n            ''')\n        \"\"\"\n    def without_noise(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a copy of the circuit with all noise processes removed.\n\n        Pure noise instructions, such as X_ERROR and DEPOLARIZE2, are not\n        included in the result.\n\n        Noisy measurement instructions, like `M(0.001)`, have their noise\n        parameter removed.\n\n        Returns:\n            A `stim.Circuit` with the same instructions except all noise\n            processes have been removed.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     X_ERROR(0.25) 0\n            ...     CNOT 0 1\n            ...     M(0.125) 0\n            ... ''').without_noise()\n            stim.Circuit('''\n                CX 0 1\n                M 0\n            ''')\n        \"\"\"\n    def without_tags(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a copy of the circuit with all tags removed.\n\n        Returns:\n            A `stim.Circuit` with the same instructions except all tags have been\n            removed.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     X[test-tag] 0\n            ...     M[test-tag-2](0.125) 0\n            ... ''').without_tags()\n            stim.Circuit('''\n                X 0\n                M(0.125) 0\n            ''')\n        \"\"\"\nclass CircuitErrorLocation:\n    \"\"\"Describes the location of an error mechanism from a stim circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit.generated(\n        ...     \"repetition_code:memory\",\n        ...     distance=5,\n        ...     rounds=5,\n        ...     before_round_data_depolarization=1e-3,\n        ... )\n        >>> logical_error = circuit.shortest_graphlike_error()\n        >>> error_location = logical_error[0].circuit_error_locations[0]\n        >>> print(error_location)\n        CircuitErrorLocation {\n            flipped_pauli_product: X0\n            Circuit location stack trace:\n                (after 1 TICKs)\n                at instruction #3 (DEPOLARIZE1) in the circuit\n                at target #1 of the instruction\n                resolving to DEPOLARIZE1(0.001) 0\n        }\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        tick_offset: int,\n        flipped_pauli_product: List[stim.GateTargetWithCoords],\n        flipped_measurement: object,\n        instruction_targets: stim.CircuitTargetsInsideInstruction,\n        stack_frames: List[stim.CircuitErrorLocationStackFrame],\n        noise_tag: str = '',\n    ) -> None:\n        \"\"\"Creates a stim.CircuitErrorLocation.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.CircuitErrorLocation(\n            ...     tick_offset=1,\n            ...     flipped_pauli_product=(\n            ...         stim.GateTargetWithCoords(\n            ...             gate_target=stim.target_x(0),\n            ...             coords=[],\n            ...         ),\n            ...     ),\n            ...     flipped_measurement=stim.FlippedMeasurement(\n            ...         record_index=None,\n            ...         observable=(),\n            ...     ),\n            ...     instruction_targets=stim.CircuitTargetsInsideInstruction(\n            ...         gate='DEPOLARIZE1',\n            ...         args=[0.001],\n            ...         target_range_start=0,\n            ...         target_range_end=1,\n            ...         targets_in_range=(stim.GateTargetWithCoords(\n            ...             gate_target=0,\n            ...             coords=[],\n            ...         ),)\n            ...     ),\n            ...     stack_frames=(\n            ...         stim.CircuitErrorLocationStackFrame(\n            ...             instruction_offset=2,\n            ...             iteration_index=0,\n            ...             instruction_repetitions_arg=0,\n            ...         ),\n            ...     ),\n            ...     noise_tag='test-tag',\n            ... )\n            >>> print(err)\n            CircuitErrorLocation {\n                noise_tag: test-tag\n                flipped_pauli_product: X0\n                Circuit location stack trace:\n                    (after 1 TICKs)\n                    at instruction #3 (DEPOLARIZE1) in the circuit\n                    at target #1 of the instruction\n                    resolving to DEPOLARIZE1(0.001) 0\n            }\n        \"\"\"\n    @property\n    def flipped_measurement(\n        self,\n    ) -> Optional[stim.FlippedMeasurement]:\n        \"\"\"The measurement that was flipped by the error mechanism.\n\n        If the error isn't a measurement error, this will be None.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     M(0.125) 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].flipped_measurement\n            stim.FlippedMeasurement(\n                record_index=0,\n                observable=(stim.GateTargetWithCoords(stim.target_z(0), []),),\n            )\n        \"\"\"\n    @property\n    def flipped_pauli_product(\n        self,\n    ) -> List[stim.GateTargetWithCoords]:\n        \"\"\"The Pauli errors that the error mechanism applied to qubits.\n\n        When the error is a measurement error, this will be an empty list.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].flipped_pauli_product\n            [stim.GateTargetWithCoords(stim.target_y(0), [])]\n        \"\"\"\n    @property\n    def instruction_targets(\n        self,\n    ) -> stim.CircuitTargetsInsideInstruction:\n        \"\"\"Within the error instruction, which may have hundreds of\n        targets, which specific targets were being executed to\n        produce the error.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> targets = err[0].circuit_error_locations[0].instruction_targets\n            >>> targets == stim.CircuitTargetsInsideInstruction(\n            ...     gate='Y_ERROR',\n            ...     args=[0.125],\n            ...     target_range_start=0,\n            ...     target_range_end=1,\n            ...     targets_in_range=(stim.GateTargetWithCoords(0, []),),\n            ... )\n            True\n        \"\"\"\n    @property\n    def noise_tag(\n        self,\n    ) -> str:\n        \"\"\"The tag on the noise instruction that caused the error.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     Y_ERROR[test-tag](0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].noise_tag\n            'test-tag'\n        \"\"\"\n    @property\n    def stack_frames(\n        self,\n    ) -> List[stim.CircuitErrorLocationStackFrame]:\n        \"\"\"Describes where in the circuit's execution the error happened.\n\n        Multiple frames are needed because the error may occur within a loop,\n        or a loop nested inside a loop, or etc.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].stack_frames\n            [stim.CircuitErrorLocationStackFrame(\n                instruction_offset=2,\n                iteration_index=0,\n                instruction_repetitions_arg=0,\n            )]\n        \"\"\"\n    @property\n    def tick_offset(\n        self,\n    ) -> int:\n        \"\"\"The number of TICKs that executed before the error happened.\n\n        This counts TICKs occurring multiple times during loops.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     TICK\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].tick_offset\n            3\n        \"\"\"\nclass CircuitErrorLocationStackFrame:\n    \"\"\"Describes the location of an instruction being executed within a\n    circuit or loop, distinguishing between separate loop iterations.\n\n    The full location of an instruction is a list of these frames,\n    drilling down from the top level circuit to the inner-most loop\n    that the instruction is within.\n\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     REPEAT 5 {\n        ...         R 0\n        ...         Y_ERROR(0.125) 0\n        ...         M 0\n        ...     }\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].stack_frames[0]\n        stim.CircuitErrorLocationStackFrame(\n            instruction_offset=0,\n            iteration_index=0,\n            instruction_repetitions_arg=5,\n        )\n        >>> err[0].circuit_error_locations[0].stack_frames[1]\n        stim.CircuitErrorLocationStackFrame(\n            instruction_offset=1,\n            iteration_index=4,\n            instruction_repetitions_arg=0,\n        )\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        instruction_offset: int,\n        iteration_index: int,\n        instruction_repetitions_arg: int,\n    ) -> None:\n        \"\"\"Creates a stim.CircuitErrorLocationStackFrame.\n\n        Examples:\n            >>> import stim\n            >>> frame = stim.CircuitErrorLocationStackFrame(\n            ...     instruction_offset=1,\n            ...     iteration_index=2,\n            ...     instruction_repetitions_arg=3,\n            ... )\n        \"\"\"\n    @property\n    def instruction_offset(\n        self,\n    ) -> int:\n        \"\"\"The index of the instruction within the circuit, or within the\n        instruction's parent REPEAT block. This is slightly different\n        from the line number, because blank lines and commented lines\n        don't count and also because the offset of the first instruction\n        is 0 instead of 1.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].stack_frames[0].instruction_offset\n            2\n        \"\"\"\n    @property\n    def instruction_repetitions_arg(\n        self,\n    ) -> int:\n        \"\"\"If the instruction being referred to is a REPEAT block,\n        this is the repetition count of that REPEAT block. Otherwise\n        this field defaults to 0.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     REPEAT 5 {\n            ...         R 0\n            ...         Y_ERROR(0.125) 0\n            ...         M 0\n            ...     }\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> full = err[0].circuit_error_locations[0].stack_frames[0]\n            >>> loop = err[0].circuit_error_locations[0].stack_frames[1]\n            >>> full.instruction_repetitions_arg\n            5\n            >>> loop.instruction_repetitions_arg\n            0\n        \"\"\"\n    @property\n    def iteration_index(\n        self,\n    ) -> int:\n        \"\"\"Disambiguates which iteration of the loop containing this instruction\n        is being referred to. If the instruction isn't in a REPEAT block, this\n        field defaults to 0.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     REPEAT 5 {\n            ...         R 0\n            ...         Y_ERROR(0.125) 0\n            ...         M 0\n            ...     }\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> full = err[0].circuit_error_locations[0].stack_frames[0]\n            >>> loop = err[0].circuit_error_locations[0].stack_frames[1]\n            >>> full.iteration_index\n            0\n            >>> loop.iteration_index\n            4\n        \"\"\"\nclass CircuitInstruction:\n    \"\"\"An instruction, like `H 0 1` or `CNOT rec[-1] 5`, from a circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     M 0 1\n        ...     X_ERROR(0.125) 5\n        ... ''')\n        >>> circuit[0]\n        stim.CircuitInstruction('H', [stim.GateTarget(0)], [])\n        >>> circuit[1]\n        stim.CircuitInstruction('M', [stim.GateTarget(0), stim.GateTarget(1)], [])\n        >>> circuit[2]\n        stim.CircuitInstruction('X_ERROR', [stim.GateTarget(5)], [0.125])\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.CircuitInstruction,\n    ) -> bool:\n        \"\"\"Determines if two `stim.CircuitInstruction`s are identical.\n        \"\"\"\n    def __init__(\n        self,\n        name: str,\n        targets: Optional[Iterable[Union[int, stim.GateTarget]]] = None,\n        gate_args: Optional[Iterable[float]] = None,\n        *,\n        tag: str = \"\",\n    ) -> None:\n        \"\"\"Creates or parses a `stim.CircuitInstruction`.\n\n        Args:\n            name: The name of the instruction being applied.\n                If `targets` and `gate_args` aren't specified, this can be a full\n                instruction line from a stim Circuit file, like \"CX 0 1\".\n            targets: The targets the instruction is being applied to. These can be raw\n                values like `0` and `stim.target_rec(-1)`, or instances of\n                `stim.GateTarget`.\n            gate_args: The sequence of numeric arguments parameterizing a gate. For\n                noise gates this is their probabilities. For `OBSERVABLE_INCLUDE`\n                instructions it's the index of the logical observable to affect.\n            tag: Defaults to \"\". A custom string attached to the instruction. For\n                example, for a TICK instruction, this could a string specifying an\n                amount of time which is used by custom code for adding noise to a\n                circuit. In general, stim will attempt to propagate tags across circuit\n                transformations but will otherwise completely ignore them.\n\n        Examples:\n            >>> import stim\n\n            >>> print(stim.CircuitInstruction('DEPOLARIZE1', [5], [0.25]))\n            DEPOLARIZE1(0.25) 5\n\n            >>> stim.CircuitInstruction('CX rec[-1] 5  # comment')\n            stim.CircuitInstruction('CX', [stim.target_rec(-1), stim.GateTarget(5)], [])\n\n            >>> print(stim.CircuitInstruction('I', [2], tag='100ns'))\n            I[100ns] 2\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.CircuitInstruction,\n    ) -> bool:\n        \"\"\"Determines if two `stim.CircuitInstruction`s are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CircuitInstruction`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a text description of the instruction as a stim circuit file line.\n        \"\"\"\n    def gate_args_copy(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns the gate's arguments (numbers parameterizing the instruction).\n\n        For noisy gates this typically a list of probabilities.\n        For OBSERVABLE_INCLUDE it's a singleton list containing the logical observable\n        index.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.CircuitInstruction('X_ERROR', [2, 3], [0.125])\n            >>> instruction.gate_args_copy()\n            [0.125]\n\n            >>> instruction.gate_args_copy() == instruction.gate_args_copy()\n            True\n            >>> instruction.gate_args_copy() is instruction.gate_args_copy()\n            False\n        \"\"\"\n    @property\n    def name(\n        self,\n    ) -> str:\n        \"\"\"The name of the instruction (e.g. `H` or `X_ERROR` or `DETECTOR`).\n        \"\"\"\n    @property\n    def num_measurements(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of bits produced when running this instruction.\n\n        Examples:\n            >>> import stim\n            >>> stim.CircuitInstruction('H', [0]).num_measurements\n            0\n            >>> stim.CircuitInstruction('M', [0]).num_measurements\n            1\n            >>> stim.CircuitInstruction('M', [2, 3, 5, 7, 11]).num_measurements\n            5\n            >>> stim.CircuitInstruction('MXX', [0, 1, 4, 5, 11, 13]).num_measurements\n            3\n            >>> stim.Circuit('MPP X0*X1 X0*Z1*Y2')[0].num_measurements\n            2\n            >>> stim.CircuitInstruction('HERALDED_ERASE', [0], [0.25]).num_measurements\n            1\n        \"\"\"\n    @property\n    def tag(\n        self,\n    ) -> str:\n        \"\"\"The custom tag attached to the instruction.\n\n        The tag is an arbitrary string.\n        The default tag, when none is specified, is the empty string.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit(\"H[test] 0\")[0].tag\n            'test'\n            >>> stim.Circuit(\"H 0\")[0].tag\n            ''\n        \"\"\"\n    def target_groups(\n        self,\n    ) -> List[List[stim.GateTarget]]:\n        \"\"\"Splits the instruction's targets into groups depending on the type of gate.\n\n        Single qubit gates like H get one group per target.\n        Two qubit gates like CX get one group per pair of targets.\n        Pauli product gates like MPP get one group per combined product.\n\n        Returns:\n            A list of groups of targets.\n\n        Examples:\n            >>> import stim\n            >>> for g in stim.Circuit('H 0 1 2')[0].target_groups():\n            ...     print(repr(g))\n            [stim.GateTarget(0)]\n            [stim.GateTarget(1)]\n            [stim.GateTarget(2)]\n\n            >>> for g in stim.Circuit('CX 0 1 2 3')[0].target_groups():\n            ...     print(repr(g))\n            [stim.GateTarget(0), stim.GateTarget(1)]\n            [stim.GateTarget(2), stim.GateTarget(3)]\n\n            >>> for g in stim.Circuit('MPP X0*Y1*Z2 X5*X6')[0].target_groups():\n            ...     print(repr(g))\n            [stim.target_x(0), stim.target_y(1), stim.target_z(2)]\n            [stim.target_x(5), stim.target_x(6)]\n\n            >>> for g in stim.Circuit('DETECTOR rec[-1] rec[-2]')[0].target_groups():\n            ...     print(repr(g))\n            [stim.target_rec(-1)]\n            [stim.target_rec(-2)]\n\n            >>> for g in stim.Circuit('CORRELATED_ERROR(0.1) X0 Y1')[0].target_groups():\n            ...     print(repr(g))\n            [stim.target_x(0), stim.target_y(1)]\n        \"\"\"\n    def targets_copy(\n        self,\n    ) -> List[stim.GateTarget]:\n        \"\"\"Returns a copy of the targets of the instruction.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.CircuitInstruction('X_ERROR', [2, 3], [0.125])\n            >>> instruction.targets_copy()\n            [stim.GateTarget(2), stim.GateTarget(3)]\n\n            >>> instruction.targets_copy() == instruction.targets_copy()\n            True\n            >>> instruction.targets_copy() is instruction.targets_copy()\n            False\n        \"\"\"\nclass CircuitRepeatBlock:\n    \"\"\"A REPEAT block from a circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     REPEAT 5 {\n        ...         CX 0 1\n        ...         CZ 1 2\n        ...     }\n        ... ''')\n        >>> repeat_block = circuit[1]\n        >>> repeat_block.repeat_count\n        5\n        >>> repeat_block.body_copy()\n        stim.Circuit('''\n            CX 0 1\n            CZ 1 2\n        ''')\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.CircuitRepeatBlock,\n    ) -> bool:\n        \"\"\"Determines if two `stim.CircuitRepeatBlock`s are identical.\n        \"\"\"\n    def __init__(\n        self,\n        repeat_count: int,\n        body: stim.Circuit,\n        *,\n        tag: str = '',\n    ) -> None:\n        \"\"\"Initializes a `stim.CircuitRepeatBlock`.\n\n        Args:\n            repeat_count: The number of times to repeat the block.\n            body: The body of the block, as a circuit.\n            tag: Defaults to empty. A custom string attached to the REPEAT instruction.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit()\n            >>> c.append(stim.CircuitRepeatBlock(100, stim.Circuit(\"M 0\")))\n            >>> c\n            stim.Circuit('''\n                REPEAT 100 {\n                    M 0\n                }\n            ''')\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.CircuitRepeatBlock,\n    ) -> bool:\n        \"\"\"Determines if two `stim.CircuitRepeatBlock`s are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.CircuitRepeatBlock`.\n        \"\"\"\n    def body_copy(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a copy of the body of the repeat block.\n\n        (Making a copy is enforced to make it clear that editing the result won't change\n        the block's body.)\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     REPEAT 5 {\n            ...         CX 0 1\n            ...         CZ 1 2\n            ...     }\n            ... ''')\n            >>> repeat_block = circuit[1]\n            >>> repeat_block.body_copy()\n            stim.Circuit('''\n                CX 0 1\n                CZ 1 2\n            ''')\n        \"\"\"\n    @property\n    def name(\n        self,\n    ) -> str:\n        \"\"\"Returns the name \"REPEAT\".\n\n        This is a duck-typing convenience method. It exists so that code that doesn't\n        know whether it has a `stim.CircuitInstruction` or a `stim.CircuitRepeatBlock`\n        can check the object's name without having to do an `instanceof` check first.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     REPEAT 5 {\n            ...         CX 1 2\n            ...     }\n            ...     S 1\n            ... ''')\n            >>> [instruction.name for instruction in circuit]\n            ['H', 'REPEAT', 'S']\n        \"\"\"\n    @property\n    def num_measurements(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of bits produced when running this loop.\n\n        Examples:\n            >>> import stim\n            >>> stim.CircuitRepeatBlock(\n            ...     body=stim.Circuit(\"M 0 1\"),\n            ...     repeat_count=25,\n            ... ).num_measurements\n            50\n        \"\"\"\n    @property\n    def repeat_count(\n        self,\n    ) -> int:\n        \"\"\"The repetition count of the repeat block.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     REPEAT 5 {\n            ...         CX 0 1\n            ...         CZ 1 2\n            ...     }\n            ... ''')\n            >>> repeat_block = circuit[1]\n            >>> repeat_block.repeat_count\n            5\n        \"\"\"\n    @property\n    def tag(\n        self,\n    ) -> str:\n        \"\"\"The custom tag attached to the REPEAT instruction.\n\n        The tag is an arbitrary string.\n        The default tag, when none is specified, is the empty string.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     REPEAT[test] 5 {\n            ...         H 0\n            ...     }\n            ... ''')[0].tag\n            'test'\n\n            >>> stim.Circuit('''\n            ...     REPEAT 5 {\n            ...         H 0\n            ...     }\n            ... ''')[0].tag\n            ''\n        \"\"\"\nclass CircuitTargetsInsideInstruction:\n    \"\"\"Describes a range of targets within a circuit instruction.\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        gate: str,\n        tag: str = '',\n        args: List[float],\n        target_range_start: int,\n        target_range_end: int,\n        targets_in_range: List[stim.GateTargetWithCoords],\n    ) -> None:\n        \"\"\"Creates a stim.CircuitTargetsInsideInstruction.\n\n        Examples:\n            >>> import stim\n            >>> val = stim.CircuitTargetsInsideInstruction(\n            ...     gate='X_ERROR',\n            ...     tag='',\n            ...     args=[0.25],\n            ...     target_range_start=0,\n            ...     target_range_end=1,\n            ...     targets_in_range=[stim.GateTargetWithCoords(0, [])],\n            ... )\n        \"\"\"\n    @property\n    def args(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns parens arguments of the gate / instruction that was being executed.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.args\n            [0.25]\n        \"\"\"\n    @property\n    def gate(\n        self,\n    ) -> Optional[str]:\n        \"\"\"Returns the name of the gate / instruction that was being executed.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.gate\n            'X_ERROR'\n        \"\"\"\n    @property\n    def tag(\n        self,\n    ) -> str:\n        \"\"\"Returns the tag of the gate / instruction that was being executed.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR[look-at-me-imma-tag](0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.tag\n            'look-at-me-imma-tag'\n        \"\"\"\n    @property\n    def target_range_end(\n        self,\n    ) -> int:\n        \"\"\"Returns the exclusive end of the range of targets that were executing\n        within the gate / instruction.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.target_range_start\n            0\n            >>> loc.instruction_targets.target_range_end\n            1\n        \"\"\"\n    @property\n    def target_range_start(\n        self,\n    ) -> int:\n        \"\"\"Returns the inclusive start of the range of targets that were executing\n        within the gate / instruction.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.target_range_start\n            0\n            >>> loc.instruction_targets.target_range_end\n            1\n        \"\"\"\n    @property\n    def targets_in_range(\n        self,\n    ) -> List[stim.GateTargetWithCoords]:\n        \"\"\"Returns the subset of targets of the gate/instruction that were being executed.\n\n        Includes coordinate data with the targets.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.targets_in_range\n            [stim.GateTargetWithCoords(0, [])]\n        \"\"\"\nclass CliffordString:\n    \"\"\"A tensor product of single qubit Clifford gates (e.g. \"H \\u2297 X \\u2297 S\").\n\n    Represents a collection of Clifford operations applied pairwise to a\n    collection of qubits. Ignores global phase.\n\n    Examples:\n        >>> import stim\n        >>> stim.CliffordString(\"H,S,C_XYZ\") * stim.CliffordString(\"H,H,H\")\n        stim.CliffordString(\"I,C_ZYX,SQRT_X_DAG\")\n    \"\"\"\n    def __add__(\n        self,\n        rhs: stim.CliffordString,\n    ) -> stim.CliffordString:\n        \"\"\"Concatenates two CliffordStrings.\n\n        Args:\n            rhs: The suffix of the concatenation.\n\n        Returns:\n            The concatenated Clifford string.\n\n        Examples:\n            >>> import stim\n            >>> stim.CliffordString(\"I,X,H\") + stim.CliffordString(\"Y,S\")\n            stim.CliffordString(\"I,X,H,Y,S\")\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.CliffordString,\n    ) -> bool:\n        \"\"\"Determines if two Clifford strings have identical contents.\n        \"\"\"\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: int,\n    ) -> stim.GateData:\n        pass\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: slice,\n    ) -> stim.CliffordString:\n        pass\n    def __getitem__(\n        self,\n        index_or_slice: Union[int, slice],\n    ) -> Union[stim.GateData, stim.CliffordString]:\n        \"\"\"Returns a Clifford or substring from the CliffordString.\n\n        Args:\n            index_or_slice: The index of the Clifford to return, or the slice\n                corresponding to the sub CliffordString to return.\n\n        Returns:\n            The indexed Clifford (as a stim.GateData instance) or the sliced\n            CliffordString.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.CliffordString(\"I,X,Y,Z,H\")\n\n            >>> s[2]\n            stim.gate_data('Y')\n\n            >>> s[-1]\n            stim.gate_data('H')\n\n            >>> s[:-1]\n            stim.CliffordString(\"I,X,Y,Z\")\n\n            >>> s[::2]\n            stim.CliffordString(\"I,Y,H\")\n        \"\"\"\n    def __iadd__(\n        self,\n        rhs: stim.CliffordString,\n    ) -> stim.CliffordString:\n        \"\"\"Mutates the CliffordString by concatenating onto it.\n\n        Args:\n            rhs: The suffix to concatenate onto the target CliffordString.\n\n        Returns:\n            The mutated Clifford string.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.CliffordString(\"I,X,H\")\n            >>> alias = c\n            >>> alias += stim.CliffordString(\"Y,S\")\n            >>> c\n            stim.CliffordString(\"I,X,H,Y,S\")\n        \"\"\"\n    def __imul__(\n        self,\n        rhs: Union[stim.CliffordString, int],\n    ) -> stim.CliffordString:\n        \"\"\"Inplace CliffordString multiplication.\n\n        Mutates the CliffordString into itself multiplied by another CliffordString\n        (via pairwise Clifford multipliation) or by an integer (via repeating the\n        contents).\n\n        Args:\n            rhs: Either a stim.CliffordString or an int. If rhs is a\n                stim.CliffordString, then the Cliffords from each string are multiplied\n                pairwise. If rhs is an int, it is the number of times to repeat the\n                Clifford string's contents.\n\n        Returns:\n            The mutated Clifford string.\n\n        Examples:\n            >>> import stim\n\n            >>> c = stim.CliffordString(\"S,X,X\")\n            >>> alias = c\n            >>> alias *= stim.CliffordString(\"S,Z,H,Z\")\n            >>> c\n            stim.CliffordString(\"Z,Y,SQRT_Y,Z\")\n\n            >>> c = stim.CliffordString(\"I,X,H\")\n            >>> alias = c\n            >>> alias *= 2\n            >>> c\n            stim.CliffordString(\"I,X,H,I,X,H\")\n        \"\"\"\n    def __init__(\n        self,\n        arg: Union[int, str, stim.CliffordString, stim.PauliString, stim.Circuit],\n        /,\n    ) -> None:\n        \"\"\"Initializes a stim.CliffordString from the given argument.\n\n        Args:\n            arg [position-only]: This can be a variety of types, including:\n                int: initializes an identity Clifford string of the given length.\n                str: initializes by parsing a comma-separated list of gate names.\n                stim.CliffordString: initializes by copying the given Clifford string.\n                stim.PauliString: initializes by copying from the given Pauli string\n                    (ignores the sign of the Pauli string).\n                stim.Circuit: initializes a CliffordString equivalent to the action\n                    of the circuit (as long as the circuit only contains single qubit\n                    unitary operations and annotations).\n                Iterable: initializes by interpreting each item as a Clifford.\n                    Each item can be a single-qubit Clifford gate name (like \"SQRT_X\")\n                    or stim.GateData instance.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.CliffordString(5)\n            stim.CliffordString(\"I,I,I,I,I\")\n\n            >>> stim.CliffordString(\"X,Y,Z,SQRT_X\")\n            stim.CliffordString(\"X,Y,Z,SQRT_X\")\n\n            >>> stim.CliffordString([\"H\", stim.gate_data(\"S\")])\n            stim.CliffordString(\"H,S\")\n\n            >>> stim.CliffordString(stim.PauliString(\"XYZ\"))\n            stim.CliffordString(\"X,Y,Z\")\n\n            >>> stim.CliffordString(stim.CliffordString(\"X,Y,Z\"))\n            stim.CliffordString(\"X,Y,Z\")\n\n            >>> stim.CliffordString(stim.Circuit('''\n            ...     H 0 1 2\n            ...     S 2 3\n            ...     TICK\n            ...     S 3\n            ...     I 6\n            ... '''))\n            stim.CliffordString(\"H,H,C_ZYX,Z,I,I,I\")\n        \"\"\"\n    def __ipow__(\n        self,\n        num_qubits: int,\n    ) -> object:\n        \"\"\"Mutates the CliffordString into itself raised to a power.\n\n        Args:\n            power: The power to raise the CliffordString's Cliffords to.\n                This value can be negative (e.g. -1 inverts the string).\n\n        Returns:\n            The mutated Clifford string.\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.CliffordString(\"I,X,H,S,C_XYZ\")\n            >>> p **= 3\n            >>> p\n            stim.CliffordString(\"I,X,H,S_DAG,I\")\n\n            >>> p **= 2\n            >>> p\n            stim.CliffordString(\"I,I,I,Z,I\")\n\n            >>> alias = p\n            >>> alias **= 2\n            >>> p\n            stim.CliffordString(\"I,I,I,I,I\")\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of Clifford operations in the string.\n\n        Examples:\n            >>> import stim\n            >>> len(stim.CliffordString(\"I,X,Y,Z,H\"))\n            5\n        \"\"\"\n    def __mul__(\n        self,\n        rhs: Union[stim.CliffordString, int],\n    ) -> stim.CliffordString:\n        \"\"\"CliffordString multiplication.\n\n        Args:\n            rhs: Either a stim.CliffordString or an int. If rhs is a\n                stim.CliffordString, then the Cliffords from each string are multiplied\n                pairwise. If rhs is an int, it is the number of times to repeat the\n                Clifford string's contents.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.CliffordString(\"S,X,X\") * stim.CliffordString(\"S,Z,H,Z\")\n            stim.CliffordString(\"Z,Y,SQRT_Y,Z\")\n\n            >>> stim.CliffordString(\"I,X,H\") * 3\n            stim.CliffordString(\"I,X,H,I,X,H,I,X,H\")\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.CliffordString,\n    ) -> bool:\n        \"\"\"Determines if two Clifford strings have non-identical contents.\n        \"\"\"\n    def __pow__(\n        self,\n        power: int,\n    ) -> stim.CliffordString:\n        \"\"\"Returns the CliffordString raised to a power.\n\n        Args:\n            power: The power to raise the CliffordString's Cliffords to.\n                This value can be negative (e.g. -1 returns the inverse string).\n\n        Returns:\n            The Clifford string raised to the power.\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n            >>> p**0\n            stim.CliffordString(\"I,I,I,I,I\")\n\n            >>> p**1\n            stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n            >>> p**12000001\n            stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n            >>> p**2\n            stim.CliffordString(\"I,I,I,Z,C_ZYX\")\n\n            >>> p**3\n            stim.CliffordString(\"I,X,H,S_DAG,I\")\n\n            >>> p**-1\n            stim.CliffordString(\"I,X,H,S_DAG,C_ZYX\")\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CliffordString`.\n        \"\"\"\n    def __rmul__(\n        self,\n        lhs: int,\n    ) -> stim.CliffordString:\n        \"\"\"CliffordString left-multiplication.\n\n        Args:\n            lhs: The number of times to repeat the Clifford string's contents.\n\n        Returns:\n            The repeated Clifford string.\n\n        Examples:\n            >>> import stim\n\n            >>> 2 * stim.CliffordString(\"I,X,H\")\n            stim.CliffordString(\"I,X,H,I,X,H\")\n\n            >>> 0 * stim.CliffordString(\"I,X,H\")\n            stim.CliffordString(\"\")\n\n            >>> 5 * stim.CliffordString(\"I\")\n            stim.CliffordString(\"I,I,I,I,I\")\n        \"\"\"\n    def __setitem__(\n        self,\n        index_or_slice: Union[int, slice],\n        new_value: Union[str, stim.GateData, stim.CliffordString, stim.PauliString, stim.Tableau],\n    ) -> None:\n        \"\"\"Overwrites an indexed Clifford, or slice of Cliffords, with the given value.\n\n        Args:\n            index_or_slice: The index of the Clifford to overwrite, or the slice\n                of Cliffords to overwrite.\n            new_value: Specifies the value to write into the Clifford string. This can\n                be set to a few different types of values:\n                - str: Name of the single qubit Clifford gate to write to the index or\n                    broadcast over the slice.\n                - stim.GateData: The single qubit Clifford gate to write to the index\n                    or broadcast over the slice.\n                - stim.Tableau: Must be a single qubit tableau. Specifies the single\n                    qubit Clifford gate to write to the index or broadcast over the\n                    slice.\n                - stim.CliffordString: String of Cliffords to write into the slice.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.CliffordString(\"I,I,I,I,I\")\n\n            >>> s[1] = 'H'\n            >>> s\n            stim.CliffordString(\"I,H,I,I,I\")\n\n            >>> s[2:] = 'SQRT_X'\n            >>> s\n            stim.CliffordString(\"I,H,SQRT_X,SQRT_X,SQRT_X\")\n\n            >>> s[0] = stim.gate_data('S_DAG').inverse\n            >>> s\n            stim.CliffordString(\"S,H,SQRT_X,SQRT_X,SQRT_X\")\n\n            >>> s[:] = 'I'\n            >>> s\n            stim.CliffordString(\"I,I,I,I,I\")\n\n            >>> s[::2] = stim.CliffordString(\"X,Y,Z\")\n            >>> s\n            stim.CliffordString(\"X,I,Y,I,Z\")\n\n            >>> s[0] = stim.Tableau.from_named_gate(\"H\")\n            >>> s\n            stim.CliffordString(\"H,I,Y,I,Z\")\n\n            >>> s[:] = stim.Tableau.from_named_gate(\"S\")\n            >>> s\n            stim.CliffordString(\"S,S,S,S,S\")\n\n            >>> s[:4] = stim.PauliString(\"IXYZ\")\n            >>> s\n            stim.CliffordString(\"I,X,Y,Z,S\")\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a string representation of the CliffordString's operations.\n        \"\"\"\n    @staticmethod\n    def all_cliffords_string(\n    ) -> stim.CliffordString:\n        \"\"\"Returns a stim.CliffordString containing each single qubit Clifford once.\n\n        Useful for things like testing that a method works on every single Clifford.\n\n        Examples:\n            >>> import stim\n            >>> cliffords = stim.CliffordString.all_cliffords_string()\n            >>> len(cliffords)\n            24\n\n            >>> print(cliffords[:8])\n            I,X,Y,Z,H_XY,S,S_DAG,H_NXY\n\n            >>> print(cliffords[8:16])\n            H,SQRT_Y_DAG,H_NXZ,SQRT_Y,H_YZ,H_NYZ,SQRT_X,SQRT_X_DAG\n\n            >>> print(cliffords[16:])\n            C_XYZ,C_XYNZ,C_NXYZ,C_XNYZ,C_ZYX,C_ZNYX,C_NZYX,C_ZYNX\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.CliffordString:\n        \"\"\"Returns a copy of the CliffordString.\n\n        Returns:\n            The copy.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.CliffordString(\"H,X\")\n            >>> alias = c\n            >>> copy = c.copy()\n            >>> c *= 5\n            >>> alias\n            stim.CliffordString(\"H,X,H,X,H,X,H,X,H,X\")\n            >>> copy\n            stim.CliffordString(\"H,X\")\n        \"\"\"\n    @staticmethod\n    def random(\n        num_qubits: int,\n    ) -> stim.CliffordString:\n        \"\"\"Samples a uniformly random CliffordString.\n\n        Args:\n            num_qubits: The number of qubits the CliffordString should act upon.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.CliffordString.random(5)\n            >>> len(p)\n            5\n\n        Returns:\n            The sampled Clifford string.\n        \"\"\"\n    def x_outputs(\n        self,\n        *,\n        bit_packed_signs: bool = False,\n    ) -> Tuple[stim.PauliString, np.ndarray]:\n        \"\"\"Returns what each Clifford in the CliffordString conjugates an X input into.\n\n        For example, H conjugates X into +Z and S_DAG conjugates X into -Y.\n\n        Combined with `z_outputs`, the results of this method completely specify\n        the single qubit Clifford applied to each qubit.\n\n        Args:\n            bit_packed_signs: Defaults to False. When False, the sign data is returned\n                in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n                `np.uint8` and 8 bits are packed into each byte (in little endian\n                order).\n\n        Returns:\n            A (paulis, signs) tuple.\n\n            `paulis` has type stim.PauliString. Its sign is always positive.\n\n            `signs` has type np.ndarray and an argument-dependent shape:\n                bit_packed_signs=False:\n                    dtype=np.bool_\n                    shape=(num_qubits,)\n                bit_packed_signs=True:\n                    dtype=np.uint8\n                    shape=(math.ceil(num_qubits / 8),)\n\n        Examples:\n            >>> import stim\n            >>> x_paulis, x_signs = stim.CliffordString(\"I,Y,H,S\").x_outputs()\n            >>> x_paulis\n            stim.PauliString(\"+XXZY\")\n            >>> x_signs\n            array([False,  True, False, False])\n\n            >>> stim.CliffordString(\"I,Y,H,S\").x_outputs(bit_packed_signs=True)[1]\n            array([2], dtype=uint8)\n        \"\"\"\n    def y_outputs(\n        self,\n        *,\n        bit_packed_signs: bool = False,\n    ) -> Tuple[stim.PauliString, np.ndarray]:\n        \"\"\"Returns what each Clifford in the CliffordString conjugates a Y input into.\n\n        For example, H conjugates Y into -Y and S_DAG conjugates Y into +X.\n\n        Args:\n            bit_packed_signs: Defaults to False. When False, the sign data is returned\n                in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n                `np.uint8` and 8 bits are packed into each byte (in little endian\n                order).\n\n        Returns:\n            A (paulis, signs) tuple.\n\n            `paulis` has type stim.PauliString. Its sign is always positive.\n\n            `signs` has type np.ndarray and an argument-dependent shape:\n                bit_packed_signs=False:\n                    dtype=np.bool_\n                    shape=(num_qubits,)\n                bit_packed_signs=True:\n                    dtype=np.uint8\n                    shape=(math.ceil(num_qubits / 8),)\n\n        Examples:\n            >>> import stim\n            >>> y_paulis, y_signs = stim.CliffordString(\"I,X,H,S\").y_outputs()\n            >>> y_paulis\n            stim.PauliString(\"+YYYX\")\n            >>> y_signs\n            array([False,  True,  True,  True])\n\n            >>> stim.CliffordString(\"I,X,H,S\").y_outputs(bit_packed_signs=True)[1]\n            array([14], dtype=uint8)\n        \"\"\"\n    def z_outputs(\n        self,\n        *,\n        bit_packed_signs: bool = False,\n    ) -> Tuple[stim.PauliString, np.ndarray]:\n        \"\"\"Returns what each Clifford in the CliffordString conjugates a Z input into.\n\n        For example, H conjugates Z into +X and SQRT_X conjugates Z into -Y.\n\n        Combined with `x_outputs`, the results of this method completely specify\n        the single qubit Clifford applied to each qubit.\n\n        Args:\n            bit_packed_signs: Defaults to False. When False, the sign data is returned\n                in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n                `np.uint8` and 8 bits are packed into each byte (in little endian\n                order).\n\n        Returns:\n            A (paulis, signs) tuple.\n\n            `paulis` has type stim.PauliString. Its sign is always positive.\n\n            `signs` has type np.ndarray and an argument-dependent shape:\n                bit_packed_signs=False:\n                    dtype=np.bool_\n                    shape=(num_qubits,)\n                bit_packed_signs=True:\n                    dtype=np.uint8\n                    shape=(math.ceil(num_qubits / 8),)\n\n        Examples:\n            >>> import stim\n            >>> z_paulis, z_signs = stim.CliffordString(\"I,Y,H,S\").z_outputs()\n            >>> z_paulis\n            stim.PauliString(\"+ZZXZ\")\n            >>> z_signs\n            array([False,  True, False, False])\n\n            >>> stim.CliffordString(\"I,Y,H,S\").z_outputs(bit_packed_signs=True)[1]\n            array([2], dtype=uint8)\n        \"\"\"\nclass CompiledDemSampler:\n    \"\"\"A helper class for efficiently sampler from a detector error model.\n\n    Examples:\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...    error(0) D0\n        ...    error(1) D1 D2 L0\n        ... ''')\n        >>> sampler = dem.compile_sampler()\n        >>> det_data, obs_data, err_data = sampler.sample(\n        ...     shots=4,\n        ...     return_errors=True)\n        >>> det_data\n        array([[False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True]])\n        >>> obs_data\n        array([[ True],\n               [ True],\n               [ True],\n               [ True]])\n        >>> err_data\n        array([[False,  True],\n               [False,  True],\n               [False,  True],\n               [False,  True]])\n    \"\"\"\n    def sample(\n        self,\n        shots: int,\n        *,\n        bit_packed: bool = False,\n        return_errors: bool = False,\n        recorded_errors_to_replay: Optional[np.ndarray] = None,\n    ) -> Tuple[np.ndarray, np.ndarray, Optional[np.ndarray]]:\n        \"\"\"Samples the detector error model's error mechanisms to produce sample data.\n\n        Args:\n            shots: The number of times to sample from the model.\n            bit_packed: Defaults to false.\n                False: the returned numpy arrays have dtype=np.bool_.\n                True: the returned numpy arrays have dtype=np.uint8 and pack 8 bits into\n                    each byte.\n\n                Setting this to True is equivalent to running\n                `np.packbits(data, bitorder='little', axis=1)` on each output value, but\n                has the performance benefit of the data never being expanded into an\n                unpacked form.\n            return_errors: Defaults to False.\n                False: the third entry of the returned tuple is None.\n                True: the third entry of the returned tuple is a numpy array recording\n                which errors were sampled.\n            recorded_errors_to_replay: Defaults to None, meaning sample errors randomly.\n                If not None, this is expected to be a 2d numpy array specifying which\n                errors to apply (e.g. one returned from a previous call to the sample\n                method). The array must have dtype=np.bool_ and\n                shape=(num_shots, num_errors) or dtype=np.uint8 and\n                shape=(num_shots, math.ceil(num_errors / 8)).\n\n        Returns:\n            A tuple (detector_data, obs_data, error_data).\n\n            Assuming bit_packed is False and return_errors is True:\n                - If error_data[s, k] is True, then the error with index k fired in the\n                    shot with index s.\n                - If detector_data[s, k] is True, then the detector with index k ended\n                    up flipped in the shot with index s.\n                - If obs_data[s, k] is True, then the observable with index k ended up\n                    flipped in the shot with index s.\n\n            The dtype and shape of the data depends on the arguments:\n                if bit_packed:\n                    detector_data.shape == (num_shots, math.ceil(num_detectors / 8))\n                    detector_data.dtype == np.uint8\n                    obs_data.shape == (num_shots, math.ceil(num_observables / 8))\n                    obs_data.dtype == np.uint8\n                    if return_errors:\n                        error_data.shape = (num_shots, math.ceil(num_errors / 8))\n                        error_data.dtype = np.uint8\n                    else:\n                        error_data is None\n                else:\n                    detector_data.shape == (num_shots, num_detectors)\n                    detector_data.dtype == np.bool_\n                    obs_data.shape == (num_shots, num_observables)\n                    obs_data.dtype == np.bool_\n                    if return_errors:\n                        error_data.shape = (num_shots, num_errors)\n                        error_data.dtype = np.bool_\n                    else:\n                        error_data is None\n\n            Note that bit packing is done using little endian order on the last axis\n            (i.e. like `np.packbits(data, bitorder='little', axis=1)`).\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> dem = stim.DetectorErrorModel('''\n            ...    error(0) D0\n            ...    error(1) D1 D2 L0\n            ... ''')\n            >>> sampler = dem.compile_sampler()\n\n            >>> # Taking samples.\n            >>> det_data, obs_data, err_data_not_requested = sampler.sample(shots=4)\n            >>> det_data\n            array([[False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True]])\n            >>> obs_data\n            array([[ True],\n                   [ True],\n                   [ True],\n                   [ True]])\n            >>> err_data_not_requested is None\n            True\n\n            >>> # Recording errors.\n            >>> det_data, obs_data, err_data = sampler.sample(\n            ...     shots=4,\n            ...     return_errors=True)\n            >>> det_data\n            array([[False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True]])\n            >>> obs_data\n            array([[ True],\n                   [ True],\n                   [ True],\n                   [ True]])\n            >>> err_data\n            array([[False,  True],\n                   [False,  True],\n                   [False,  True],\n                   [False,  True]])\n\n            >>> # Bit packing.\n            >>> det_data, obs_data, err_data = sampler.sample(\n            ...     shots=4,\n            ...     return_errors=True,\n            ...     bit_packed=True)\n            >>> det_data\n            array([[6],\n                   [6],\n                   [6],\n                   [6]], dtype=uint8)\n            >>> obs_data\n            array([[1],\n                   [1],\n                   [1],\n                   [1]], dtype=uint8)\n            >>> err_data\n            array([[2],\n                   [2],\n                   [2],\n                   [2]], dtype=uint8)\n\n            >>> # Recording and replaying errors.\n            >>> noisy_dem = stim.DetectorErrorModel('''\n            ...    error(0.125) D0\n            ...    error(0.25) D1\n            ... ''')\n            >>> noisy_sampler = noisy_dem.compile_sampler()\n            >>> det_data, obs_data, err_data = noisy_sampler.sample(\n            ...     shots=100,\n            ...     return_errors=True)\n            >>> replay_det_data, replay_obs_data, _ = noisy_sampler.sample(\n            ...     shots=100,\n            ...     recorded_errors_to_replay=err_data)\n            >>> np.array_equal(det_data, replay_det_data)\n            True\n            >>> np.array_equal(obs_data, replay_obs_data)\n            True\n        \"\"\"\n    def sample_write(\n        self,\n        shots: int,\n        *,\n        det_out_file: Union[None, str, pathlib.Path],\n        det_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        obs_out_file: Union[None, str, pathlib.Path],\n        obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        err_out_file: Union[None, str, pathlib.Path] = None,\n        err_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        replay_err_in_file: Union[None, str, pathlib.Path] = None,\n        replay_err_in_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    ) -> None:\n        \"\"\"Samples the detector error model and writes the results to disk.\n\n        Args:\n            shots: The number of times to sample from the model.\n            det_out_file: Where to write detection event data.\n                If None: detection event data is not written.\n                If str or pathlib.Path: opens and overwrites the file at the given path.\n                NOT IMPLEMENTED: io.IOBase\n            det_out_format: The format to write the detection event data in\n                (e.g. \"01\" or \"b8\").\n            obs_out_file: Where to write observable flip data.\n                If None: observable flip data is not written.\n                If str or pathlib.Path: opens and overwrites the file at the given path.\n                NOT IMPLEMENTED: io.IOBase\n            obs_out_format: The format to write the observable flip data in\n                (e.g. \"01\" or \"b8\").\n            err_out_file: Where to write errors-that-occurred data.\n                If None: errors-that-occurred data is not written.\n                If str or pathlib.Path: opens and overwrites the file at the given path.\n                NOT IMPLEMENTED: io.IOBase\n            err_out_format: The format to write the errors-that-occurred data in\n                (e.g. \"01\" or \"b8\").\n            replay_err_in_file: If this is specified, errors are replayed from data\n                instead of generated randomly. The following types are supported:\n                - None: errors are generated randomly according to the probabilities\n                    in the detector error model.\n                - str or pathlib.Path: the file at the given path is opened and\n                    errors-to-apply data is read from there.\n                - io.IOBase: NOT IMPLEMENTED\n            replay_err_in_format: The format to write the errors-that-occurred data in\n                (e.g. \"01\" or \"b8\").\n\n        Returns:\n            Nothing. Results are written to disk.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> import pathlib\n            >>> dem = stim.DetectorErrorModel('''\n            ...    error(0) D0\n            ...    error(0) D1\n            ...    error(0) D0\n            ...    error(1) D1 D2 L0\n            ...    error(0) D0\n            ... ''')\n            >>> sampler = dem.compile_sampler()\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     d = pathlib.Path(d)\n            ...     sampler.sample_write(\n            ...         shots=1,\n            ...         det_out_file=d / 'dets.01',\n            ...         det_out_format='01',\n            ...         obs_out_file=d / 'obs.01',\n            ...         obs_out_format='01',\n            ...         err_out_file=d / 'err.hits',\n            ...         err_out_format='hits',\n            ...     )\n            ...     with open(d / 'dets.01') as f:\n            ...         assert f.read() == \"011\\n\"\n            ...     with open(d / 'obs.01') as f:\n            ...         assert f.read() == \"1\\n\"\n            ...     with open(d / 'err.hits') as f:\n            ...         assert f.read() == \"3\\n\"\n        \"\"\"\nclass CompiledDetectorSampler:\n    \"\"\"An analyzed stabilizer circuit whose detection events can be sampled quickly.\n    \"\"\"\n    def __init__(\n        self,\n        circuit: stim.Circuit,\n        *,\n        seed: object = None,\n    ) -> None:\n        \"\"\"Creates an object that can sample the detection events from a circuit.\n\n        Args:\n            circuit: The circuit to sample from.\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n\n        Returns:\n            An initialized stim.CompiledDetectorSampler.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    H 0\n            ...    CNOT 0 1\n            ...    X_ERROR(1.0) 0\n            ...    M 0 1\n            ...    DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> s = c.compile_detector_sampler()\n            >>> s.sample(shots=1)\n            array([[ True]])\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.CompiledDetectorSampler`.\n        \"\"\"\n    def sample(\n        self,\n        shots: int,\n        *,\n        prepend_observables: bool = False,\n        append_observables: bool = False,\n        separate_observables: bool = False,\n        bit_packed: bool = False,\n        dets_out: Optional[np.ndarray] = None,\n        obs_out: Optional[np.ndarray] = None,\n    ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:\n        \"\"\"Returns a numpy array containing a batch of detector samples from the circuit.\n\n        The circuit must define the detectors using DETECTOR instructions. Observables\n        defined by OBSERVABLE_INCLUDE instructions can also be included in the results\n        as honorary detectors.\n\n        Args:\n            shots: The number of times to sample every detector in the circuit.\n            separate_observables: Defaults to False. When set to True, the return value\n                is a (detection_events, observable_flips) tuple instead of a flat\n                detection_events array.\n            prepend_observables: Defaults to false. When set, observables are included\n                with the detectors and are placed at the start of the results.\n            append_observables: Defaults to false. When set, observables are included\n                with the detectors and are placed at the end of the results.\n            bit_packed: Returns a uint8 numpy array with 8 bits per byte, instead of\n                a bool_ numpy array with 1 bit per byte. Uses little endian packing.\n            dets_out: Defaults to None. Specifies a pre-allocated numpy array to write\n                the detection event data into. This array must have the correct shape\n                and dtype.\n            obs_out: Defaults to None. Specifies a pre-allocated numpy array to write\n                the observable flip data into. This array must have the correct shape\n                and dtype.\n\n        Returns:\n            A numpy array or tuple of numpy arrays containing the samples.\n\n            if separate_observables=False and bit_packed=False:\n                A single numpy array.\n                dtype=bool_\n                shape=(\n                    shots,\n                    num_detectors + num_observables * (\n                        append_observables + prepend_observables),\n                )\n                The bit for detection event `m` in shot `s` is at\n                    result[s, m]\n\n            if separate_observables=False and bit_packed=True:\n                A single numpy array.\n                dtype=uint8\n                shape=(\n                    shots,\n                    math.ceil((num_detectors + num_observables * (\n                        append_observables + prepend_observables)) / 8),\n                )\n                The bit for detection event `m` in shot `s` is at\n                    (result[s, m // 8] >> (m % 8)) & 1\n\n            if separate_observables=True and bit_packed=False:\n                A (dets, obs) tuple.\n                dets.dtype=bool_\n                dets.shape=(shots, num_detectors)\n                obs.dtype=bool_\n                obs.shape=(shots, num_observables)\n                The bit for detection event `m` in shot `s` is at\n                    dets[s, m]\n                The bit for observable `m` in shot `s` is at\n                    obs[s, m]\n\n            if separate_observables=True and bit_packed=True:\n                A (dets, obs) tuple.\n                dets.dtype=uint8\n                dets.shape=(shots, math.ceil(num_detectors / 8))\n                obs.dtype=uint8\n                obs.shape=(shots, math.ceil(num_observables / 8))\n                The bit for detection event `m` in shot `s` is at\n                    (dets[s, m // 8] >> (m % 8)) & 1\n                The bit for observable `m` in shot `s` is at\n                    (obs[s, m // 8] >> (m % 8)) & 1\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    H 0\n            ...    CNOT 0 1\n            ...    X_ERROR(1.0) 0\n            ...    M 0 1\n            ...    DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> s = c.compile_detector_sampler()\n            >>> s.sample(shots=1)\n            array([[ True]])\n        \"\"\"\n    def sample_bit_packed(\n        self,\n        shots: int,\n        *,\n        prepend_observables: bool = False,\n        append_observables: bool = False,\n    ) -> object:\n        \"\"\"[DEPRECATED] Use sampler.sample(..., bit_packed=True) instead.\n\n        Returns a numpy array containing bit packed detector samples from the circuit.\n\n        The circuit must define the detectors using DETECTOR instructions. Observables\n        defined by OBSERVABLE_INCLUDE instructions can also be included in the results\n        as honorary detectors.\n\n        Args:\n            shots: The number of times to sample every detector in the circuit.\n            prepend_observables: Defaults to false. When set, observables are included\n                with the detectors and are placed at the start of the results.\n            append_observables: Defaults to false. When set, observables are included\n                with the detectors and are placed at the end of the results.\n\n        Returns:\n            A numpy array with `dtype=uint8` and `shape=(shots, n)` where `n` is\n            `num_detectors + num_observables*(append_observables+prepend_observables)`.\n            The bit for detection event `m` in shot `s` is at\n            `result[s, (m // 8)] & 2**(m % 8)`.\n        \"\"\"\n    def sample_write(\n        self,\n        shots: int,\n        *,\n        filepath: Union[str, pathlib.Path],\n        format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        obs_out_filepath: Optional[Union[str, pathlib.Path]] = None,\n        obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        prepend_observables: bool = False,\n        append_observables: bool = False,\n    ) -> None:\n        \"\"\"Samples detection events from the circuit and writes them to a file.\n\n        Args:\n            shots: The number of times to sample every measurement in the circuit.\n            filepath: The file to write the results to.\n            format: The output format to write the results with.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            obs_out_filepath: Sample observables as part of each shot, and write them to\n                this file. This keeps the observable data separate from the detector\n                data.\n            obs_out_format: If writing the observables to a file, this is the format to\n                write them in.\n\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            prepend_observables: Sample observables as part of each shot, and put them\n                at the start of the detector data.\n            append_observables: Sample observables as part of each shot, and put them at\n                the end of the detector data.\n\n        Returns:\n            None.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     path = f\"{d}/tmp.dat\"\n            ...     c = stim.Circuit('''\n            ...         X_ERROR(1) 0\n            ...         M 0 1\n            ...         DETECTOR rec[-2]\n            ...         DETECTOR rec[-1]\n            ...     ''')\n            ...     c.compile_detector_sampler().sample_write(\n            ...         shots=3,\n            ...         filepath=path,\n            ...         format=\"dets\")\n            ...     with open(path) as f:\n            ...         print(f.read(), end='')\n            shot D0\n            shot D0\n            shot D0\n        \"\"\"\nclass CompiledMeasurementSampler:\n    \"\"\"An analyzed stabilizer circuit whose measurements can be sampled quickly.\n    \"\"\"\n    def __init__(\n        self,\n        circuit: stim.Circuit,\n        *,\n        skip_reference_sample: bool = False,\n        seed: object = None,\n        reference_sample: object = None,\n    ) -> None:\n        \"\"\"Creates a measurement sampler for the given circuit.\n\n        The sampler uses a noiseless reference sample, collected from the circuit using\n        stim's Tableau simulator during initialization of the sampler, as a baseline for\n        deriving more samples using an error propagation simulator.\n\n        Args:\n            circuit: The stim circuit to sample from.\n            skip_reference_sample: Defaults to False. When set to True, the reference\n                sample used by the sampler is initialized to all-zeroes instead of being\n                collected from the circuit. This means that the results returned by the\n                sampler are actually whether or not each measurement was *flipped*,\n                instead of true measurement results.\n\n                Forcing an all-zero reference sample is useful when you are only\n                interested in error propagation and don't want to have to deal with the\n                fact that some measurements want to be On when no errors occur. It is\n                also useful when you know for sure that the all-zero result is actually\n                a possible result from the circuit (under noiseless execution), meaning\n                it is a valid reference sample as good as any other. Computing the\n                reference sample is the most time consuming and memory intensive part of\n                simulating the circuit, so promising that the simulator can safely skip\n                that step is an effective optimization.\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n            reference_sample: The data to xor into the measurement flips produced by the\n                frame simulator, in order to produce proper measurement results.\n                This can either be specified as an `np.bool_` array or a bit packed\n                `np.uint8` array (little endian). Under normal conditions, the reference\n                sample should be a valid noiseless sample of the circuit, such as the\n                one returned by `circuit.reference_sample()`. If this argument is not\n                provided, the reference sample will be set to\n                `circuit.reference_sample()`, unless `skip_reference_sample=True`\n                is used, in which case it will be set to all-zeros.\n\n        Returns:\n            An initialized stim.CompiledMeasurementSampler.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0   2 3\n            ...    M 0 1 2 3\n            ... ''')\n            >>> s = c.compile_sampler()\n            >>> s.sample(shots=1)\n            array([[ True, False,  True,  True]])\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CompiledMeasurementSampler`.\n        \"\"\"\n    def sample(\n        self,\n        shots: int,\n        *,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Samples a batch of measurement samples from the circuit.\n\n        Args:\n            shots: The number of times to sample every measurement in the circuit.\n            bit_packed: Returns a uint8 numpy array with 8 bits per byte, instead of\n                a bool_ numpy array with 1 bit per byte. Uses little endian packing.\n\n        Returns:\n            A numpy array containing the samples.\n\n            If bit_packed=False:\n                dtype=bool_\n                shape=(shots, circuit.num_measurements)\n                The bit for measurement `m` in shot `s` is at\n                    result[s, m]\n            If bit_packed=True:\n                dtype=uint8\n                shape=(shots, math.ceil(circuit.num_measurements / 8))\n                The bit for measurement `m` in shot `s` is at\n                    (result[s, m // 8] >> (m % 8)) & 1\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0   2 3\n            ...    M 0 1 2 3\n            ... ''')\n            >>> s = c.compile_sampler()\n            >>> s.sample(shots=1)\n            array([[ True, False,  True,  True]])\n        \"\"\"\n    def sample_bit_packed(\n        self,\n        shots: int,\n    ) -> np.ndarray:\n        \"\"\"[DEPRECATED] Use sampler.sample(..., bit_packed=True) instead.\n\n        Samples a bit packed batch of measurement samples from the circuit.\n\n        Args:\n            shots: The number of times to sample every measurement in the circuit.\n\n        Returns:\n            A numpy array with `dtype=uint8` and\n            `shape=(shots, (num_measurements + 7) // 8)`.\n\n            The bit for measurement `m` in shot `s` is at\n            `result[s, (m // 8)] & 2**(m % 8)`.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0 1 2 3 4 5 6 7     10\n            ...    M 0 1 2 3 4 5 6 7 8 9 10\n            ... ''')\n            >>> s = c.compile_sampler()\n            >>> s.sample_bit_packed(shots=1)\n            array([[255,   4]], dtype=uint8)\n        \"\"\"\n    def sample_write(\n        self,\n        shots: int,\n        *,\n        filepath: Union[str, pathlib.Path],\n        format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    ) -> None:\n        \"\"\"Samples measurements from the circuit and writes them to a file.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     path = f\"{d}/tmp.dat\"\n            ...     c = stim.Circuit('''\n            ...         X 0   2 3\n            ...         M 0 1 2 3\n            ...     ''')\n            ...     c.compile_sampler().sample_write(5, filepath=path, format=\"01\")\n            ...     with open(path) as f:\n            ...         print(f.read(), end='')\n            1011\n            1011\n            1011\n            1011\n            1011\n\n        Args:\n            shots: The number of times to sample every measurement in the circuit.\n            filepath: The file to write the results to.\n            format: The output format to write the results with.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n\n        Returns:\n            None.\n        \"\"\"\nclass CompiledMeasurementsToDetectionEventsConverter:\n    \"\"\"A tool for quickly converting measurements from an analyzed stabilizer circuit into detection events.\n    \"\"\"\n    def __init__(\n        self,\n        circuit: stim.Circuit,\n        *,\n        skip_reference_sample: bool = False,\n    ) -> None:\n        \"\"\"Creates a measurement-to-detection-events converter for the given circuit.\n\n        The converter uses a noiseless reference sample, collected from the circuit\n        using stim's Tableau simulator during initialization of the converter, as a\n        baseline for determining what the expected value of a detector is.\n\n        Note that the expected behavior of gauge detectors (detectors that are not\n        actually deterministic under noiseless execution) can vary depending on the\n        reference sample. Stim mitigates this by always generating the same reference\n        sample for a given circuit.\n\n        Args:\n            circuit: The stim circuit to use for conversions.\n            skip_reference_sample: Defaults to False. When set to True, the reference\n                sample used by the converter is initialized to all-zeroes instead of\n                being collected from the circuit. This should only be used if it's known\n                that the all-zeroes sample is actually a possible result from the\n                circuit (under noiseless execution).\n\n        Returns:\n            An initialized stim.CompiledMeasurementsToDetectionEventsConverter.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> converter = stim.Circuit('''\n            ...    X 0\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... ''').compile_m2d_converter()\n            >>> converter.convert(\n            ...     measurements=np.array([[0], [1]], dtype=np.bool_),\n            ...     append_observables=False,\n            ... )\n            array([[ True],\n                   [False]])\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CompiledMeasurementsToDetectionEventsConverter`.\n        \"\"\"\n    @overload\n    def convert(\n        self,\n        *,\n        measurements: np.ndarray,\n        sweep_bits: Optional[np.ndarray] = None,\n        append_observables: bool = False,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        pass\n    @overload\n    def convert(\n        self,\n        *,\n        measurements: np.ndarray,\n        sweep_bits: Optional[np.ndarray] = None,\n        separate_observables: Literal[True],\n        append_observables: bool = False,\n        bit_packed: bool = False,\n    ) -> Tuple[np.ndarray, np.ndarray]:\n        pass\n    def convert(\n        self,\n        *,\n        measurements: np.ndarray,\n        sweep_bits: Optional[np.ndarray] = None,\n        separate_observables: bool = False,\n        append_observables: bool = False,\n        bit_packed: bool = False,\n    ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:\n        \"\"\"Converts measurement data into detection event data.\n\n        Args:\n            measurements: A numpy array containing measurement data.\n\n                The dtype of the array is used to determine if it is bit packed or not.\n                dtype=np.bool_ (unpacked data):\n                    shape=(num_shots, circuit.num_measurements)\n                dtype=np.uint8 (bit packed data):\n                    shape=(num_shots, math.ceil(circuit.num_measurements / 8))\n            sweep_bits: Optional. A numpy array containing sweep data for the `sweep[k]`\n                controls in the circuit.\n\n                The dtype of the array is used to determine if it is bit packed or not.\n                dtype=np.bool_ (unpacked data):\n                    shape=(num_shots, circuit.num_sweep_bits)\n                dtype=np.uint8 (bit packed data):\n                    shape=(num_shots, math.ceil(circuit.num_sweep_bits / 8))\n            separate_observables: Defaults to False. When set to True, two numpy arrays\n                are returned instead of one, with the second array containing the\n                observable flip data.\n            append_observables: Defaults to False. When set to True, the observables in\n                the circuit are treated as if they were additional detectors. Their\n                results are appended to the end of the detection event data.\n            bit_packed: Defaults to False. When set to True, the returned numpy\n                array contains bit packed data (dtype=np.uint8 with 8 bits per item)\n                instead of unpacked data (dtype=np.bool_).\n\n        Returns:\n            The detection event data and (optionally) observable data. The result is a\n            single numpy array if separate_observables is false, otherwise it's a tuple\n            of two numpy arrays.\n\n            When returning two numpy arrays, the first array is the detection event data\n            and the second is the observable flip data.\n\n            The dtype of the returned arrays is np.bool_ if bit_packed is false,\n            otherwise they're np.uint8 arrays.\n\n            shape[0] of the array(s) is the number of shots.\n            shape[1] of the array(s) is the number of bits per shot (divided by 8 if bit\n            packed) (e.g. for just detection event data it would be\n            circuit.num_detectors).\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> converter = stim.Circuit('''\n            ...    X 0\n            ...    M 0 1\n            ...    DETECTOR rec[-1]\n            ...    DETECTOR rec[-2]\n            ...    OBSERVABLE_INCLUDE(0) rec[-2]\n            ... ''').compile_m2d_converter()\n            >>> dets, obs = converter.convert(\n            ...     measurements=np.array([[1, 0],\n            ...                            [1, 0],\n            ...                            [1, 0],\n            ...                            [0, 0],\n            ...                            [1, 0]], dtype=np.bool_),\n            ...     separate_observables=True,\n            ... )\n            >>> dets\n            array([[False, False],\n                   [False, False],\n                   [False, False],\n                   [False,  True],\n                   [False, False]])\n            >>> obs\n            array([[False],\n                   [False],\n                   [False],\n                   [ True],\n                   [False]])\n        \"\"\"\n    def convert_file(\n        self,\n        *,\n        measurements_filepath: Union[str, pathlib.Path],\n        measurements_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        sweep_bits_filepath: Optional[Union[str, pathlib.Path]] = None,\n        sweep_bits_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        detection_events_filepath: Union[str, pathlib.Path],\n        detection_events_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        append_observables: bool = False,\n        obs_out_filepath: Optional[Union[str, pathlib.Path]] = None,\n        obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    ) -> None:\n        \"\"\"Reads measurement data from a file and writes detection events to another file.\n\n        Args:\n            measurements_filepath: A file containing measurement data to be converted.\n            measurements_format: The format the measurement data is stored in.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            detection_events_filepath: Where to save detection event data to.\n            detection_events_format: The format to save the detection event data in.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            sweep_bits_filepath: Defaults to None. A file containing sweep data, or\n                None. When specified, sweep data (used for `sweep[k]` controls in the\n                circuit, which can vary from shot to shot) will be read from the given\n                file. When not specified, all sweep bits default to False and no\n                sweep-controlled operations occur.\n            sweep_bits_format: The format the sweep data is stored in.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            obs_out_filepath: Sample observables as part of each shot, and write them to\n                this file. This keeps the observable data separate from the detector\n                data.\n            obs_out_format: If writing the observables to a file, this is the format to\n                write them in.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            append_observables: When True, the observables in the circuit are included\n                as part of the detection event data. Specifically, they are treated as\n                if they were additional detectors at the end of the circuit. When False,\n                observable data is not output.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> converter = stim.Circuit('''\n            ...    X 0\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... ''').compile_m2d_converter()\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...    with open(f\"{d}/measurements.01\", \"w\") as f:\n            ...        print(\"0\", file=f)\n            ...        print(\"1\", file=f)\n            ...    converter.convert_file(\n            ...        measurements_filepath=f\"{d}/measurements.01\",\n            ...        detection_events_filepath=f\"{d}/detections.01\",\n            ...        append_observables=False,\n            ...    )\n            ...    with open(f\"{d}/detections.01\") as f:\n            ...        print(f.read(), end=\"\")\n            1\n            0\n        \"\"\"\nclass DemInstruction:\n    \"\"\"An instruction from a detector error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ...     error(0.125) D0 D1 L0\n        ...     error(0.125) D1 D2\n        ...     error(0.125) D2 D3\n        ...     error(0.125) D3\n        ... ''')\n        >>> instruction = model[0]\n        >>> instruction\n        stim.DemInstruction('error', [0.125], [stim.target_relative_detector_id(0)])\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.DemInstruction,\n    ) -> bool:\n        \"\"\"Determines if two instructions have identical contents.\n        \"\"\"\n    def __init__(\n        self,\n        type: str,\n        args: Optional[Iterable[float]] = None,\n        targets: Optional[Iterable[stim.DemTarget]] = None,\n        *,\n        tag: str = \"\",\n    ) -> None:\n        \"\"\"Creates or parses a stim.DemInstruction.\n\n        Args:\n            type: The name of the instruction type (e.g. \"error\" or \"shift_detectors\").\n                If `args` and `targets` aren't specified, this can also be set to a\n                full line of text from a dem file, like \"error(0.25) D0\".\n            args: Numeric values parameterizing the instruction (e.g. the 0.1 in\n                \"error(0.1)\").\n            targets: The objects the instruction involves (e.g. the \"D0\" and \"L1\" in\n                \"error(0.1) D0 L1\").\n            tag: An arbitrary piece of text attached to the instruction.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.DemInstruction(\n            ...     'error',\n            ...     [0.125],\n            ...     [stim.target_relative_detector_id(5)],\n            ...     tag='test-tag',\n            ... )\n            >>> print(instruction)\n            error[test-tag](0.125) D5\n\n            >>> print(stim.DemInstruction('error(0.125) D5 L6 ^ D4  # comment'))\n            error(0.125) D5 L6 ^ D4\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.DemInstruction,\n    ) -> bool:\n        \"\"\"Determines if two instructions have non-identical contents.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.DetectorErrorModel`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns detector error model (.dem) instructions (that can be parsed by stim) for the model.\n        \"\"\"\n    def args_copy(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns a copy of the list of numbers parameterizing the instruction.\n\n        For example, this would be coordinates of a detector instruction or the\n        probability of an error instruction. The result is a copy, meaning that\n        editing it won't change the instruction's targets or future copies.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.DetectorErrorModel('''\n            ...     error(0.125) D0\n            ... ''')[0]\n            >>> instruction.args_copy()\n            [0.125]\n\n            >>> instruction.args_copy() == instruction.args_copy()\n            True\n            >>> instruction.args_copy() is instruction.args_copy()\n            False\n        \"\"\"\n    @property\n    def tag(\n        self,\n    ) -> str:\n        \"\"\"Returns the arbitrary text tag attached to the instruction.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...     error[test-tag](0.125) D0\n            ...     error(0.125) D0\n            ... ''')\n            >>> dem[0].tag\n            'test-tag'\n            >>> dem[1].tag\n            ''\n        \"\"\"\n    def target_groups(\n        self,\n    ) -> List[List[stim.DemTarget]]:\n        \"\"\"Returns a copy of the instruction's targets, split by target separators.\n\n        When a detector error model instruction contains a suggested decomposition,\n        its targets contain separators (`stim.DemTarget(\"^\")`). This method splits the\n        targets into groups based the separators, similar to how `str.split` works.\n\n        Returns:\n            A list of groups of targets.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...     error(0.01) D0 D1 ^ D2\n            ...     error(0.01) D0 L0\n            ...     error(0.01)\n            ... ''')\n\n            >>> dem[0].target_groups()\n            [[stim.DemTarget('D0'), stim.DemTarget('D1')], [stim.DemTarget('D2')]]\n\n            >>> dem[1].target_groups()\n            [[stim.DemTarget('D0'), stim.DemTarget('L0')]]\n\n            >>> dem[2].target_groups()\n            [[]]\n        \"\"\"\n    def targets_copy(\n        self,\n    ) -> List[Union[int, stim.DemTarget]]:\n        \"\"\"Returns a copy of the instruction's targets.\n\n        The result is a copy, meaning that editing it won't change the instruction's\n        targets or future copies.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.DetectorErrorModel('''\n            ...     error(0.125) D0 L2\n            ... ''')[0]\n            >>> instruction.targets_copy()\n            [stim.DemTarget('D0'), stim.DemTarget('L2')]\n\n            >>> instruction.targets_copy() == instruction.targets_copy()\n            True\n            >>> instruction.targets_copy() is instruction.targets_copy()\n            False\n        \"\"\"\n    @property\n    def type(\n        self,\n    ) -> str:\n        \"\"\"The name of the instruction type (e.g. \"error\" or \"shift_detectors\").\n        \"\"\"\nclass DemRepeatBlock:\n    \"\"\"A repeat block from a detector error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...     repeat 100 {\n        ...         error(0.125) D0 D1\n        ...         shift_detectors 1\n        ...     }\n        ... ''')\n        >>> model[0]\n        stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n            error(0.125) D0 D1\n            shift_detectors 1\n        '''))\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.DemRepeatBlock,\n    ) -> bool:\n        \"\"\"Determines if two repeat blocks are identical.\n        \"\"\"\n    def __init__(\n        self,\n        repeat_count: int,\n        block: stim.DetectorErrorModel,\n    ) -> None:\n        \"\"\"Creates a stim.DemRepeatBlock.\n\n        Args:\n            repeat_count: The number of times the repeat block's body is supposed to\n                execute.\n            block: The body of the repeat block as a DetectorErrorModel containing the\n                instructions to repeat.\n\n        Examples:\n            >>> import stim\n            >>> repeat_block = stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n            ...     error(0.125) D0 D1\n            ...     shift_detectors 1\n            ... '''))\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.DemRepeatBlock,\n    ) -> bool:\n        \"\"\"Determines if two repeat blocks are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.DemRepeatBlock`.\n        \"\"\"\n    def body_copy(\n        self,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns a copy of the block's body, as a stim.DetectorErrorModel.\n\n        Examples:\n            >>> import stim\n            >>> body = stim.DetectorErrorModel('''\n            ...     error(0.125) D0 D1\n            ...     shift_detectors 1\n            ... ''')\n            >>> repeat_block = stim.DemRepeatBlock(100, body)\n            >>> repeat_block.body_copy() == body\n            True\n            >>> repeat_block.body_copy() is repeat_block.body_copy()\n            False\n        \"\"\"\n    @property\n    def repeat_count(\n        self,\n    ) -> int:\n        \"\"\"The number of times the repeat block's body is supposed to execute.\n        \"\"\"\n    @property\n    def type(\n        self,\n    ) -> object:\n        \"\"\"Returns the type name \"repeat\".\n\n        This is a duck-typing convenience method. It exists so that code that doesn't\n        know whether it has a `stim.DemInstruction` or a `stim.DemRepeatBlock`\n        can check the type field without having to do an `instanceof` check first.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...     error(0.1) D0 L0\n            ...     repeat 5 {\n            ...         error(0.1) D0 D1\n            ...         shift_detectors 1\n            ...     }\n            ...     logical_observable L0\n            ... ''')\n            >>> [instruction.type for instruction in dem]\n            ['error', 'repeat', 'logical_observable']\n        \"\"\"\nclass DemTarget:\n    \"\"\"An instruction target from a detector error model (.dem) file.\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.DemTarget,\n    ) -> bool:\n        \"\"\"Determines if two `stim.DemTarget`s are identical.\n        \"\"\"\n    def __init__(\n        self,\n        arg: object,\n        /,\n    ) -> None:\n        \"\"\"Creates a stim.DemTarget from the given object.\n\n        Args:\n            arg: A string to parse as a stim.DemTarget, or some other object to\n                convert into a stim.DemTarget.\n\n        Examples:\n            >>> import stim\n            >>> stim.DemTarget(\"D5\") == stim.target_relative_detector_id(5)\n            True\n            >>> stim.DemTarget(\"L2\") == stim.target_logical_observable_id(2)\n            True\n            >>> stim.DemTarget(\"^\") == stim.target_separator()\n            True\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.DemTarget,\n    ) -> bool:\n        \"\"\"Determines if two `stim.DemTarget`s are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.DemTarget`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a text description of the detector error model target.\n        \"\"\"\n    def is_logical_observable_id(\n        self,\n    ) -> bool:\n        \"\"\"Determines if the detector error model target is a logical observable id target.\n\n        In a detector error model file, observable targets are prefixed by `L`. For\n        example, in `error(0.25) D0 L1` the `L1` is an observable target.\n\n        Examples:\n            >>> import stim\n            >>> stim.DemTarget(\"L2\").is_logical_observable_id()\n            True\n            >>> stim.DemTarget(\"D3\").is_logical_observable_id()\n            False\n            >>> stim.DemTarget(\"^\").is_logical_observable_id()\n            False\n        \"\"\"\n    def is_relative_detector_id(\n        self,\n    ) -> bool:\n        \"\"\"Determines if the detector error model target is a relative detector id target.\n\n        In a detector error model file, detectors are prefixed by `D`. For\n        example, in `error(0.25) D0 L1` the `D0` is a relative detector target.\n\n        Examples:\n            >>> import stim\n            >>> stim.DemTarget(\"L2\").is_relative_detector_id()\n            False\n            >>> stim.DemTarget(\"D3\").is_relative_detector_id()\n            True\n            >>> stim.DemTarget(\"^\").is_relative_detector_id()\n            False\n        \"\"\"\n    def is_separator(\n        self,\n    ) -> bool:\n        \"\"\"Determines if the detector error model target is a separator.\n\n        Separates separate the components of a suggested decompositions within an error.\n        For example, the `^` in `error(0.25) D1 D2 ^ D3 D4` is the separator.\n\n        Examples:\n            >>> import stim\n            >>> stim.DemTarget(\"L2\").is_separator()\n            False\n            >>> stim.DemTarget(\"D3\").is_separator()\n            False\n            >>> stim.DemTarget(\"^\").is_separator()\n            True\n        \"\"\"\n    @staticmethod\n    def logical_observable_id(\n        index: int,\n    ) -> stim.DemTarget:\n        \"\"\"Returns a logical observable id identifying a frame change.\n\n        Args:\n            index: The index of the observable.\n\n        Returns:\n            The logical observable target.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel()\n            >>> m.append(\"error\", 0.25, [\n            ...     stim.DemTarget.logical_observable_id(13)\n            ... ])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.25) L13\n            ''')\n        \"\"\"\n    @staticmethod\n    def relative_detector_id(\n        index: int,\n    ) -> stim.DemTarget:\n        \"\"\"Returns a relative detector id (e.g. \"D5\" in a .dem file).\n\n        Args:\n            index: The index of the detector, relative to the current detector offset.\n\n        Returns:\n            The relative detector target.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel()\n            >>> m.append(\"error\", 0.25, [\n            ...     stim.DemTarget.relative_detector_id(13)\n            ... ])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.25) D13\n            ''')\n        \"\"\"\n    @staticmethod\n    def separator(\n    ) -> stim.DemTarget:\n        \"\"\"Returns a target separator (e.g. \"^\" in a .dem file).\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel()\n            >>> m.append(\"error\", 0.25, [\n            ...     stim.DemTarget.relative_detector_id(1),\n            ...     stim.DemTarget.separator(),\n            ...     stim.DemTarget.relative_detector_id(2),\n            ... ])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.25) D1 ^ D2\n            ''')\n        \"\"\"\n    @property\n    def val(\n        self,\n    ) -> int:\n        \"\"\"Returns the target's integer value.\n\n        Example:\n            >>> import stim\n            >>> stim.DemTarget(\"D5\").val\n            5\n            >>> stim.DemTarget(\"L6\").val\n            6\n        \"\"\"\nclass DemTargetWithCoords:\n    \"\"\"A detector error model instruction target with associated coords.\n\n    It is also guaranteed that, if the type of the DEM target is a\n    relative detector id, it is actually absolute (i.e. relative to\n    0).\n\n    For example, if the DEM target is a detector from a circuit with\n    coordinate arguments given to detectors, the coords field will\n    contain the coordinate data for the detector.\n\n    This is helpful information to have available when debugging a\n    problem in a circuit, instead of having to constantly manually\n    look up the coordinates of a detector index in order to understand\n    what is happening.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.DemTargetWithCoords(stim.DemTarget(\"D1\"), [1.5, 2.0])\n        >>> t.dem_target\n        stim.DemTarget('D1')\n        >>> t.coords\n        [1.5, 2.0]\n    \"\"\"\n    def __init__(\n        self,\n        dem_target: stim.DemTarget,\n        coords: List[float],\n    ) -> None:\n        \"\"\"Creates a stim.DemTargetWithCoords.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].dem_error_terms[0]\n            stim.DemTargetWithCoords(dem_target=stim.DemTarget('D0'), coords=[2, 3])\n        \"\"\"\n    @property\n    def coords(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns the associated coordinate information as a list of floats.\n\n        If there is no coordinate information, returns an empty list.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].dem_error_terms[0].coords\n            [2.0, 3.0]\n        \"\"\"\n    @property\n    def dem_target(\n        self,\n    ) -> stim.DemTarget:\n        \"\"\"Returns the actual DEM target as a `stim.DemTarget`.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].dem_error_terms[0].dem_target\n            stim.DemTarget('D0')\n        \"\"\"\nclass DetectorErrorModel:\n    \"\"\"An error model built out of independent error mechanics.\n\n    This class is one of the most important classes in Stim, because it is the\n    mechanism used to explain circuits to decoders. A typical workflow would\n    look something like:\n\n        1. Create a quantum error correction circuit annotated with detectors\n            and observables.\n        2. Fail at configuring your favorite decoder using the circuit, because\n            it's a pain to convert circuit error mechanisms into a format\n            understood by the decoder.\n        2a. Call circuit.detector_error_model(), with decompose_errors=True\n            if working with a matching-based code. This converts the circuit\n            errors into a straightforward list of independent \"with\n            probability p these detectors and observables get flipped\" terms.\n        3. Write tedious but straightforward glue code to create whatever\n            graph-like object the decoder needs from the detector error model.\n        3a. Actually, ideally, someone has already done that for you. For\n            example, pymatching can take detector error models directly and\n            sinter knows how to explain a detector error model to fusion_blossom.\n        4. Get samples using circuit.compile_detector_sampler(), feed them to\n            the decoder, and compare its observable flip predictions to the\n            actual flips recorded in the samples.\n        4a. Actually, sinter will basically handle steps 2 through 4 for you.\n            So you should probably have just generated your circuits, called\n            `sinter collect` on them, then `sinter plot` on the results.\n        5. Write the paper.\n\n    Error mechanisms are described in terms of the visible detection events and the\n    hidden observable frame changes that they causes. Error mechanisms can also\n    suggest decompositions of their effects into components, which can be helpful\n    for decoders that want to work with a simpler decomposed error model instead of\n    the full error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ...     error(0.125) D0 D1 L0\n        ...     error(0.125) D1 D2\n        ...     error(0.125) D2 D3\n        ...     error(0.125) D3\n        ... ''')\n        >>> len(model)\n        5\n\n        >>> stim.Circuit('''\n        ...     X_ERROR(0.125) 0\n        ...     X_ERROR(0.25) 1\n        ...     CORRELATED_ERROR(0.375) X0 X1\n        ...     M 0 1\n        ...     DETECTOR rec[-2]\n        ...     DETECTOR rec[-1]\n        ... ''').detector_error_model()\n        stim.DetectorErrorModel('''\n            error(0.125) D0\n            error(0.375) D0 D1\n            error(0.25) D1\n        ''')\n    \"\"\"\n    def __add__(\n        self,\n        second: stim.DetectorErrorModel,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Creates a detector error model by appending two models.\n\n        Examples:\n            >>> import stim\n            >>> m1 = stim.DetectorErrorModel('''\n            ...    error(0.125) D0\n            ... ''')\n            >>> m2 = stim.DetectorErrorModel('''\n            ...    error(0.25) D1\n            ... ''')\n            >>> m1 + m2\n            stim.DetectorErrorModel('''\n                error(0.125) D0\n                error(0.25) D1\n            ''')\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.DetectorErrorModel,\n    ) -> bool:\n        \"\"\"Determines if two detector error models have identical contents.\n        \"\"\"\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: int,\n    ) -> Union[stim.DemInstruction, stim.DemRepeatBlock]:\n        pass\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: slice,\n    ) -> stim.DetectorErrorModel:\n        pass\n    def __getitem__(\n        self,\n        index_or_slice: object,\n    ) -> object:\n        \"\"\"Returns copies of instructions from the detector error model.\n\n        Args:\n            index_or_slice: An integer index picking out an instruction to return, or a\n                slice picking out a range of instructions to return as a detector error\n                model.\n\n        Examples:\n            >>> import stim\n            >>> model = stim.DetectorErrorModel('''\n            ...    error(0.125) D0\n            ...    error(0.125) D1 L1\n            ...    repeat 100 {\n            ...        error(0.125) D1 D2\n            ...        shift_detectors 1\n            ...    }\n            ...    error(0.125) D2\n            ...    logical_observable L0\n            ...    detector D5\n            ... ''')\n            >>> model[0]\n            stim.DemInstruction('error', [0.125], [stim.target_relative_detector_id(0)])\n            >>> model[2]\n            stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n                error(0.125) D1 D2\n                shift_detectors 1\n            '''))\n            >>> model[1::2]\n            stim.DetectorErrorModel('''\n                error(0.125) D1 L1\n                error(0.125) D2\n                detector D5\n            ''')\n        \"\"\"\n    def __iadd__(\n        self,\n        second: stim.DetectorErrorModel,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Appends a detector error model into the receiving model (mutating it).\n\n        Examples:\n            >>> import stim\n            >>> m1 = stim.DetectorErrorModel('''\n            ...    error(0.125) D0\n            ... ''')\n            >>> m2 = stim.DetectorErrorModel('''\n            ...    error(0.25) D1\n            ... ''')\n            >>> m1 += m2\n            >>> print(repr(m1))\n            stim.DetectorErrorModel('''\n                error(0.125) D0\n                error(0.25) D1\n            ''')\n        \"\"\"\n    def __imul__(\n        self,\n        repetitions: int,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Mutates the detector error model by putting its contents into a repeat block.\n\n        Special case: if the repetition count is 0, the model is cleared.\n        Special case: if the repetition count is 1, nothing happens.\n\n        Args:\n            repetitions: The number of times the repeat block should repeat.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel('''\n            ...    error(0.25) D0\n            ...    shift_detectors 1\n            ... ''')\n            >>> m *= 3\n            >>> print(m)\n            repeat 3 {\n                error(0.25) D0\n                shift_detectors 1\n            }\n        \"\"\"\n    def __init__(\n        self,\n        detector_error_model_text: str = '',\n    ) -> None:\n        \"\"\"Creates a stim.DetectorErrorModel.\n\n        Args:\n            detector_error_model_text: Defaults to empty. Describes instructions to\n                append into the circuit in the detector error model (.dem) format.\n\n        Examples:\n            >>> import stim\n            >>> empty = stim.DetectorErrorModel()\n            >>> not_empty = stim.DetectorErrorModel('''\n            ...    error(0.125) D0 L0\n            ... ''')\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of top-level instructions/blocks in the detector error model.\n\n        Instructions inside of blocks are not included in this count.\n\n        Examples:\n            >>> import stim\n            >>> len(stim.DetectorErrorModel())\n            0\n            >>> len(stim.DetectorErrorModel('''\n            ...    error(0.1) D0 D1\n            ...    shift_detectors 100\n            ...    logical_observable L5\n            ... '''))\n            3\n            >>> len(stim.DetectorErrorModel('''\n            ...    repeat 100 {\n            ...        error(0.1) D0 D1\n            ...        error(0.1) D1 D2\n            ...    }\n            ... '''))\n            1\n        \"\"\"\n    def __mul__(\n        self,\n        repetitions: int,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Repeats the detector error model using a repeat block.\n\n        Has special cases for 0 repetitions and 1 repetitions.\n\n        Args:\n            repetitions: The number of times the repeat block should repeat.\n\n        Returns:\n            repetitions=0: An empty detector error model.\n            repetitions=1: A copy of this detector error model.\n            repetitions>=2: A detector error model with a single repeat block, where the\n            contents of that repeat block are this detector error model.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel('''\n            ...    error(0.25) D0\n            ...    shift_detectors 1\n            ... ''')\n            >>> m * 3\n            stim.DetectorErrorModel('''\n                repeat 3 {\n                    error(0.25) D0\n                    shift_detectors 1\n                }\n            ''')\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.DetectorErrorModel,\n    ) -> bool:\n        \"\"\"Determines if two detector error models have non-identical contents.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.DetectorErrorModel`.\n        \"\"\"\n    def __rmul__(\n        self,\n        repetitions: int,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Repeats the detector error model using a repeat block.\n\n        Has special cases for 0 repetitions and 1 repetitions.\n\n        Args:\n            repetitions: The number of times the repeat block should repeat.\n\n        Returns:\n            repetitions=0: An empty detector error model.\n            repetitions=1: A copy of this detector error model.\n            repetitions>=2: A detector error model with a single repeat block, where the\n            contents of that repeat block are this detector error model.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel('''\n            ...    error(0.25) D0\n            ...    shift_detectors 1\n            ... ''')\n            >>> 3 * m\n            stim.DetectorErrorModel('''\n                repeat 3 {\n                    error(0.25) D0\n                    shift_detectors 1\n                }\n            ''')\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns the contents of a detector error model file (.dem) encoding the model.\n        \"\"\"\n    def append(\n        self,\n        instruction: object,\n        parens_arguments: object = None,\n        targets: List[object] = (),\n        *,\n        tag: str = '',\n    ) -> None:\n        \"\"\"Appends an instruction to the detector error model.\n\n        Args:\n            instruction: Either the name of an instruction, a stim.DemInstruction, a\n                stim.DemRepeatBlock. or a stim.DetectorErrorModel. The\n                `parens_arguments`, `targets`, and 'tag' arguments should be given iff\n                the instruction is a name.\n            parens_arguments: Numeric values parameterizing the instruction. The numbers\n                inside parentheses in a detector error model file (eg. the `0.25` in\n                `error(0.25) D0`). This argument can be given either a list of doubles,\n                or a single double (which will be implicitly wrapped into a list).\n            targets: The instruction targets, such as the `D0` in `error(0.25) D0`.\n            tag: An arbitrary piece of text attached to the repeat instruction.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel()\n            >>> m.append(\"error\", 0.125, [\n            ...     stim.DemTarget.relative_detector_id(1),\n            ... ])\n            >>> m.append(\"error\", 0.25, [\n            ...     stim.DemTarget.relative_detector_id(1),\n            ...     stim.DemTarget.separator(),\n            ...     stim.DemTarget.relative_detector_id(2),\n            ...     stim.DemTarget.logical_observable_id(3),\n            ... ], tag='test-tag')\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.125) D1\n                error[test-tag](0.25) D1 ^ D2 L3\n            ''')\n\n            >>> m.append(\"shift_detectors\", (1, 2, 3), [5])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.125) D1\n                error[test-tag](0.25) D1 ^ D2 L3\n                shift_detectors(1, 2, 3) 5\n            ''')\n\n            >>> m += m * 3\n            >>> m.append(m[0])\n            >>> m.append(m[-2])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.125) D1\n                error[test-tag](0.25) D1 ^ D2 L3\n                shift_detectors(1, 2, 3) 5\n                repeat 3 {\n                    error(0.125) D1\n                    error[test-tag](0.25) D1 ^ D2 L3\n                    shift_detectors(1, 2, 3) 5\n                }\n                error(0.125) D1\n                repeat 3 {\n                    error(0.125) D1\n                    error[test-tag](0.25) D1 ^ D2 L3\n                    shift_detectors(1, 2, 3) 5\n                }\n            ''')\n        \"\"\"\n    def approx_equals(\n        self,\n        other: object,\n        *,\n        atol: float,\n    ) -> bool:\n        \"\"\"Checks if detector error models are approximately equal.\n\n        Two detector error model are approximately equal if they are equal up to slight\n        perturbations of instruction arguments such as probabilities. For example\n        `error(0.100) D0` is approximately equal to `error(0.099) D0` within an absolute\n        tolerance of 0.002. All other details of the models (such as the ordering of\n        errors and their targets) must be exactly the same.\n\n        Args:\n            other: The detector error model, or other object, to compare to this one.\n            atol: The absolute error tolerance. The maximum amount each probability may\n                have been perturbed by.\n\n        Returns:\n            True if the given object is a detector error model approximately equal up to\n            the receiving circuit up to the given tolerance, otherwise False.\n\n        Examples:\n            >>> import stim\n            >>> base = stim.DetectorErrorModel('''\n            ...    error(0.099) D0 D1\n            ... ''')\n\n            >>> base.approx_equals(base, atol=0)\n            True\n\n            >>> base.approx_equals(stim.DetectorErrorModel('''\n            ...    error(0.101) D0 D1\n            ... '''), atol=0)\n            False\n\n            >>> base.approx_equals(stim.DetectorErrorModel('''\n            ...    error(0.101) D0 D1\n            ... '''), atol=0.0001)\n            False\n\n            >>> base.approx_equals(stim.DetectorErrorModel('''\n            ...    error(0.101) D0 D1\n            ... '''), atol=0.01)\n            True\n\n            >>> base.approx_equals(stim.DetectorErrorModel('''\n            ...    error(0.099) D0 D1 L0 L1 L2 L3 L4\n            ... '''), atol=9999)\n            False\n        \"\"\"\n    def clear(\n        self,\n    ) -> None:\n        \"\"\"Clears the contents of the detector error model.\n\n        Examples:\n            >>> import stim\n            >>> model = stim.DetectorErrorModel('''\n            ...    error(0.1) D0 D1\n            ... ''')\n            >>> model.clear()\n            >>> model\n            stim.DetectorErrorModel()\n        \"\"\"\n    def compile_sampler(\n        self,\n        *,\n        seed: object = None,\n    ) -> stim.CompiledDemSampler:\n        \"\"\"Returns a CompiledDemSampler that can batch sample from detector error models.\n\n        Args:\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n\n        Returns:\n            A seeded stim.CompiledDemSampler for the given detector error model.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...    error(0) D0\n            ...    error(1) D1 D2 L0\n            ... ''')\n            >>> sampler = dem.compile_sampler()\n            >>> det_data, obs_data, err_data = sampler.sample(\n            ...     shots=4,\n            ...     return_errors=True)\n            >>> det_data\n            array([[False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True]])\n            >>> obs_data\n            array([[ True],\n                   [ True],\n                   [ True],\n                   [ True]])\n            >>> err_data\n            array([[False,  True],\n                   [False,  True],\n                   [False,  True],\n                   [False,  True]])\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns a copy of the detector error model.\n\n        The copy is an independent detector error model with the same contents.\n\n        Examples:\n            >>> import stim\n\n            >>> c1 = stim.DetectorErrorModel(\"error(0.1) D0 D1\")\n            >>> c2 = c1.copy()\n            >>> c2 is c1\n            False\n            >>> c2 == c1\n            True\n        \"\"\"\n    def diagram(\n        self,\n        type: Literal[\"matchgraph-svg\", \"matchgraph-svg-html\", \"matchgraph-3d\", \"matchgraph-3d-html\"] = 'matchgraph-svg',\n    ) -> Any:\n        \"\"\"Returns a diagram of the circuit, from a variety of options.\n\n        Args:\n            type: The type of diagram. Available types are:\n                \"matchgraph-svg\": An image of the decoding graph of the\n                    detector error model. Red lines are errors crossing a\n                    logical observable. Blue lines are undecomposed hyper\n                    errors.\n                \"matchgraph-svg-html\": Same as matchgraph-svg but with the\n                    SVG wrapped in a resizable HTML iframe.\n                \"matchgraph-3d\": A 3d model of the decoding graph of the\n                    detector error model. Red lines are errors crossing a\n                    logical observable. Blue lines are undecomposed hyper\n                    errors.\n\n                    GLTF files can be opened with a variety of programs, or\n                    opened online in viewers such as\n                    https://gltf-viewer.donmccurdy.com/ . Red lines are\n                    errors crossing a logical observable.\n                \"matchgraph-3d-html\": Same 3d model as 'match-graph-3d' but\n                    embedded into an HTML web page containing an interactive\n                    THREE.js viewer for the 3d model.\n\n        Returns:\n            An object whose `__str__` method returns the diagram, so that\n            writing the diagram to a file works correctly. The returned\n            object also defines a `_repr_html_` method, so that ipython\n            notebooks recognize it can be shown using a specialized\n            viewer instead of as raw text.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> circuit = stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     rounds=10,\n            ...     distance=7,\n            ...     after_clifford_depolarization=0.01)\n            >>> dem = circuit.detector_error_model(decompose_errors=True)\n\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     diagram = circuit.diagram(\"match-graph-svg\")\n            ...     with open(f\"{d}/dem_image.svg\", \"w\") as f:\n            ...         print(diagram, file=f)\n\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     diagram = circuit.diagram(\"match-graph-3d\")\n            ...     with open(f\"{d}/dem_3d_model.gltf\", \"w\") as f:\n            ...         print(diagram, file=f)\n        \"\"\"\n    def flattened(\n        self,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns the detector error model without repeat or detector_shift instructions.\n\n        Returns:\n            A `stim.DetectorErrorModel` with the same errors in the same order, but with\n            repeat loops flattened into actually repeated instructions and with all\n            coordinate/index shifts inlined.\n\n        Examples:\n            >>> import stim\n            >>> stim.DetectorErrorModel('''\n            ...     error(0.125) D0\n            ...     REPEAT 5 {\n            ...         error(0.25) D0 D1\n            ...         shift_detectors 1\n            ...     }\n            ...     error(0.125) D0 L0\n            ... ''').flattened()\n            stim.DetectorErrorModel('''\n                error(0.125) D0\n                error(0.25) D0 D1\n                error(0.25) D1 D2\n                error(0.25) D2 D3\n                error(0.25) D3 D4\n                error(0.25) D4 D5\n                error(0.125) D5 L0\n            ''')\n        \"\"\"\n    @staticmethod\n    def from_file(\n        file: Union[io.TextIOBase, str, pathlib.Path],\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Reads a detector error model from a file.\n\n        The file format is defined at\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n        Args:\n            file: A file path or open file object to read from.\n\n        Returns:\n            The circuit parsed from the file.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         print('error(0.25) D2 D3', file=f)\n            ...     circuit = stim.DetectorErrorModel.from_file(path)\n            >>> circuit\n            stim.DetectorErrorModel('''\n                error(0.25) D2 D3\n            ''')\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         print('error(0.25) D2 D3', file=f)\n            ...     with open(path) as f:\n            ...         circuit = stim.DetectorErrorModel.from_file(f)\n            >>> circuit\n            stim.DetectorErrorModel('''\n                error(0.25) D2 D3\n            ''')\n        \"\"\"\n    def get_detector_coordinates(\n        self,\n        only: object = None,\n    ) -> Dict[int, List[float]]:\n        \"\"\"Returns the coordinate metadata of detectors in the detector error model.\n\n        Args:\n            only: Defaults to None (meaning include all detectors). A list of detector\n                indices to include in the result. Detector indices beyond the end of the\n                detector error model cause an error.\n\n        Returns:\n            A dictionary mapping integers (detector indices) to lists of floats\n            (coordinates). Detectors with no specified coordinate data are mapped to an\n            empty tuple. If `only` is specified, then `set(result.keys()) == set(only)`.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...    error(0.25) D0 D1\n            ...    detector(1, 2, 3) D1\n            ...    shift_detectors(5) 1\n            ...    detector(1, 2) D2\n            ... ''')\n            >>> dem.get_detector_coordinates()\n            {0: [], 1: [1.0, 2.0, 3.0], 2: [], 3: [6.0, 2.0]}\n            >>> dem.get_detector_coordinates(only=[1])\n            {1: [1.0, 2.0, 3.0]}\n        \"\"\"\n    @property\n    def num_detectors(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of detectors (e.g. `D2`) in the error model.\n\n        Detector indices are assumed to be contiguous from 0 up to whatever the maximum\n        detector id is. If the largest detector's absolute id is n-1, then the number of\n        detectors is n.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     X_ERROR(0.125) 0\n            ...     X_ERROR(0.25) 1\n            ...     CORRELATED_ERROR(0.375) X0 X1\n            ...     M 0 1\n            ...     DETECTOR rec[-2]\n            ...     DETECTOR rec[-1]\n            ... ''').detector_error_model().num_detectors\n            2\n\n            >>> stim.DetectorErrorModel('''\n            ...    error(0.1) D0 D199\n            ... ''').num_detectors\n            200\n\n            >>> stim.DetectorErrorModel('''\n            ...    shift_detectors 1000\n            ...    error(0.1) D0 D199\n            ... ''').num_detectors\n            1200\n        \"\"\"\n    @property\n    def num_errors(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of errors (e.g. `error(0.1) D0`) in the error model.\n\n        Error instructions inside repeat blocks count once per repetition.\n        Redundant errors with the same targets count as separate errors.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.DetectorErrorModel('''\n            ...     error(0.125) D0\n            ...     repeat 100 {\n            ...         repeat 5 {\n            ...             error(0.25) D1\n            ...         }\n            ...     }\n            ... ''').num_errors\n            501\n        \"\"\"\n    @property\n    def num_observables(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of frame changes (e.g. `L2`) in the error model.\n\n        Observable indices are assumed to be contiguous from 0 up to whatever the\n        maximum observable id is. If the largest observable's id is n-1, then the number\n        of observables is n.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     X_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(99) rec[-1]\n            ... ''').detector_error_model().num_observables\n            100\n\n            >>> stim.DetectorErrorModel('''\n            ...    error(0.1) L399\n            ... ''').num_observables\n            400\n        \"\"\"\n    def rounded(\n        self,\n        arg0: int,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Creates an equivalent detector error model but with rounded error probabilities.\n\n        Args:\n            digits: The number of digits to round to.\n\n        Returns:\n            A `stim.DetectorErrorModel` with the same instructions in the same order,\n            but with the parens arguments of error instructions rounded to the given\n            precision.\n\n            Instructions whose error probability was rounded to zero are still\n            included in the output.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...     error(0.019499) D0\n            ...     error(0.000001) D0 D1\n            ... ''')\n\n            >>> dem.rounded(2)\n            stim.DetectorErrorModel('''\n                error(0.02) D0\n                error(0) D0 D1\n            ''')\n\n            >>> dem.rounded(3)\n            stim.DetectorErrorModel('''\n                error(0.019) D0\n                error(0) D0 D1\n            ''')\n        \"\"\"\n    def shortest_graphlike_error(\n        self,\n        ignore_ungraphlike_errors: bool = True,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Finds a minimum set of graphlike errors to produce an undetected logical error.\n\n        Note that this method does not pay attention to error probabilities (other than\n        ignoring errors with probability 0). It searches for a logical error with the\n        minimum *number* of physical errors, not the maximum probability of those\n        physical errors all occurring.\n\n        This method works by looking for errors that have frame changes (eg.\n        \"error(0.1) D0 D1 L5\" flips the frame of observable 5). These errors are\n        converted into one or two symptoms and a net frame change. The symptoms can then\n        be moved around by following errors touching that symptom. Each symptom is moved\n        until it disappears into a boundary or cancels against another remaining\n        symptom, while leaving the other symptoms alone (ensuring only one symptom is\n        allowed to move significantly reduces waste in the search space). Eventually a\n        path or cycle of errors is found that cancels out the symptoms, and if there is\n        still a frame change at that point then that path or cycle is a logical error\n        (otherwise all that was found was a stabilizer of the system; a dead end). The\n        search process advances like a breadth first search, seeded from all the\n        frame-change errors and branching them outward in tandem, until one of them wins\n        the race to find a solution.\n\n        Args:\n            ignore_ungraphlike_errors: Defaults to True. When False, an exception is\n                raised if there are any errors in the model that are not graphlike. When\n                True, those errors are skipped as if they weren't present.\n\n                A graphlike error is an error with less than two symptoms. For the\n                purposes of this method, errors are also considered graphlike if they\n                are decomposed into graphlike components:\n\n                graphlike:\n                    error(0.1) D0\n                    error(0.1) D0 D1\n                    error(0.1) D0 D1 L0\n                not graphlike but decomposed into graphlike components:\n                    error(0.1) D0 D1 ^ D2\n                not graphlike, not decomposed into graphlike components:\n                    error(0.1) D0 D1 D2\n                    error(0.1) D0 D1 D2 ^ D3\n\n        Returns:\n            A detector error model containing just the error instructions corresponding\n            to an undetectable logical error. There will be no other kinds of\n            instructions (no `repeat`s, no `shift_detectors`, etc). The error\n            probabilities will all be set to 1.\n\n            The `len` of the returned model is the graphlike code distance of the\n            circuit. But beware that in general the true code distance may be smaller.\n            For example, in the XZ surface code with twists, the true minimum sized\n            logical error is likely to use Y errors. But each Y error decomposes into\n            two graphlike components (the X part and the Z part). As a result, the\n            graphlike code distance in that context is likely to be nearly twice as\n            large as the true code distance.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.DetectorErrorModel('''\n            ...     error(0.125) D0\n            ...     error(0.125) D0 D1\n            ...     error(0.125) D1 L55\n            ...     error(0.125) D1\n            ... ''').shortest_graphlike_error()\n            stim.DetectorErrorModel('''\n                error(1) D1\n                error(1) D1 L55\n            ''')\n\n            >>> stim.DetectorErrorModel('''\n            ...     error(0.125) D0 D1 D2\n            ...     error(0.125) L0\n            ... ''').shortest_graphlike_error(ignore_ungraphlike_errors=True)\n            stim.DetectorErrorModel('''\n                error(1) L0\n            ''')\n\n            >>> circuit = stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     rounds=10,\n            ...     distance=7,\n            ...     before_round_data_depolarization=0.01)\n            >>> model = circuit.detector_error_model(decompose_errors=True)\n            >>> len(model.shortest_graphlike_error())\n            7\n        \"\"\"\n    def to_file(\n        self,\n        file: Union[io.TextIOBase, str, pathlib.Path],\n    ) -> None:\n        \"\"\"Writes the detector error model to a file.\n\n        The file format is defined at\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n        Args:\n            file: A file path or an open file to write to.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> c = stim.DetectorErrorModel('error(0.25) D2 D3')\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         c.to_file(f)\n            ...     with open(path) as f:\n            ...         contents = f.read()\n            >>> contents\n            'error(0.25) D2 D3\\n'\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     c.to_file(path)\n            ...     with open(path) as f:\n            ...         contents = f.read()\n            >>> contents\n            'error(0.25) D2 D3\\n'\n        \"\"\"\n    def without_tags(\n        self,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns a copy of the detector error model with all tags removed.\n\n        Returns:\n            A `stim.DetectorErrorModel` with the same instructions except all tags have\n            been removed.\n\n        Examples:\n            >>> import stim\n            >>> stim.DetectorErrorModel('''\n            ...     error[test-tag](0.25) D0\n            ... ''').without_tags()\n            stim.DetectorErrorModel('''\n                error(0.25) D0\n            ''')\n        \"\"\"\nclass ExplainedError:\n    \"\"\"Describes the location of an error mechanism from a stim circuit.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> print(err[0])\n        ExplainedError {\n            dem_error_terms: L0\n            CircuitErrorLocation {\n                flipped_pauli_product: Y0\n                Circuit location stack trace:\n                    (after 1 TICKs)\n                    at instruction #3 (Y_ERROR) in the circuit\n                    at target #1 of the instruction\n                    resolving to Y_ERROR(0.125) 0\n            }\n        }\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        dem_error_terms: List[stim.DemTargetWithCoords],\n        circuit_error_locations: List[stim.CircuitErrorLocation],\n    ) -> None:\n        \"\"\"Creates a stim.ExplainedError.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> print(err[0])\n            ExplainedError {\n                dem_error_terms: L0\n                CircuitErrorLocation {\n                    flipped_pauli_product: Y0\n                    Circuit location stack trace:\n                        (after 1 TICKs)\n                        at instruction #3 (Y_ERROR) in the circuit\n                        at target #1 of the instruction\n                        resolving to Y_ERROR(0.125) 0\n                }\n            }\n        \"\"\"\n    @property\n    def circuit_error_locations(\n        self,\n    ) -> List[stim.CircuitErrorLocation]:\n        \"\"\"The locations of circuit errors that produce the symptoms in dem_error_terms.\n\n        Note: if this list contains a single entry, it may be because a result\n        with a single representative error was requested (as opposed to all possible\n        errors).\n\n        Note: if this list is empty, it may be because there was a DEM error decomposed\n        into parts where one of the parts is impossible to make on its own from a single\n        circuit error.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> print(err[0].circuit_error_locations[0])\n            CircuitErrorLocation {\n                flipped_pauli_product: Y0\n                Circuit location stack trace:\n                    (after 1 TICKs)\n                    at instruction #3 (Y_ERROR) in the circuit\n                    at target #1 of the instruction\n                    resolving to Y_ERROR(0.125) 0\n            }\n        \"\"\"\n    @property\n    def dem_error_terms(\n        self,\n    ) -> List[stim.DemTargetWithCoords]:\n        \"\"\"The detectors and observables flipped by this error mechanism.\n        \"\"\"\nclass FlipSimulator:\n    \"\"\"A simulator that tracks whether things are flipped, instead of what they are.\n\n    Tracking flips is significantly cheaper than tracking actual values, requiring\n    O(1) work per gate (compared to O(n) for unitary operations and O(n^2) for\n    collapsing operations in the tableau simulator, where n is the qubit count).\n\n    Supports interactive usage, where gates and measurements are applied on demand.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        batch_size: int,\n        disable_stabilizer_randomization: bool = False,\n        num_qubits: int = 0,\n        seed: Optional[int] = None,\n    ) -> None:\n        \"\"\"Initializes a stim.FlipSimulator.\n\n        Args:\n            batch_size: For speed, the flip simulator simulates many instances in\n                parallel. This argument determines the number of parallel instances.\n\n                It's recommended to use a multiple of 256, because internally the state\n                of the instances is striped across SSE (128 bit) or AVX (256 bit)\n                words with one bit in the word belonging to each instance. The result is\n                that, even if you only ask for 1 instance, probably the same amount of\n                work is being done as if you'd asked for 256 instances. The extra\n                results just aren't being used, creating waste.\n\n            disable_stabilizer_randomization: Determines whether or not the flip\n                simulator uses stabilizer randomization. Defaults to False (stabilizer\n                randomization used). Set to True to disable stabilizer randomization.\n\n                Stabilizer randomization means that, when a qubit is initialized or\n                measured in the Z basis, a Z error is added to the qubit with 50%\n                probability. More generally, anytime a stabilizer is introduced into\n                the system by any means, an error equal to that stabilizer is applied\n                with 50% probability. This ensures that observables anticommuting with\n                stabilizers of the system must be maximally uncertain. In other words,\n                this feature enforces Heisenberg's uncertainty principle.\n\n                This is a safety feature that you should not turn off unless you have a\n                reason to do so. Stabilizer randomization is turned on by default\n                because it catches mistakes. For example, suppose you are trying to\n                create a stabilizer code but you accidentally have the code measure two\n                anticommuting stabilizers. With stabilizer randomization turned off, it\n                will look like this code works. With stabilizer randomization turned on,\n                the two measurements will correctly randomize each other revealing that\n                the code doesn't work.\n\n                In some use cases, stabilizer randomization is a hindrance instead of\n                helpful. For example, if you are using the flip simulator to understand\n                how an error propagates through the system, the stabilizer randomization\n                will be introducing error terms that you don't want.\n\n            num_qubits: Sets the initial number of qubits tracked by the simulation.\n                The simulator will still automatically resize as needed when qubits\n                beyond this limit are touched.\n\n                This parameter exists as a way to hint at the desired size of the\n                simulator's state for performance, and to ensure methods that\n                peek at the size have the expected size from the start instead of\n                only after the relevant qubits have been touched.\n\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                circuit is executed. For example, reordering whether a reset on one\n                qubit happens before or after a reset on another qubit can result in\n                different measurement results being observed starting from the same\n                seed.\n\n        Returns:\n            An initialized stim.FlipSimulator.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n        \"\"\"\n    def append_measurement_flips(\n        self,\n        measurement_flip_data: np.ndarray,\n    ) -> None:\n        \"\"\"Appends measurement flip data to the simulator's measurement record.\n\n        Args:\n            measurement_flip_data: The flip data to append. The following shape/dtype\n                combinations are supported.\n\n                Single measurement without bit packing:\n                    shape=(self.batch_size,)\n                    dtype=np.bool_\n\n                Single measurement with bit packing:\n                    shape=(math.ceil(self.batch_size / 8),)\n                    dtype=np.uint8\n\n                Multiple measurements without bit packing:\n                    shape=(num_measurements, self.batch_size)\n                    dtype=np.bool_\n\n                Multiple measurements with bit packing:\n                    shape=(num_measurements, math.ceil(self.batch_size / 8))\n                    dtype=np.uint8\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.append_measurement_flips(np.array(\n            ...     [0, 1, 0, 0, 1, 0, 0, 1, 1],\n            ...     dtype=np.bool_,\n            ... ))\n\n            >>> sim.get_measurement_flips()\n            array([[False,  True, False, False,  True, False, False,  True,  True]])\n\n            >>> sim.append_measurement_flips(np.array(\n            ...     [0b11001001, 0],\n            ...     dtype=np.uint8,\n            ... ))\n\n            >>> sim.get_measurement_flips()\n            array([[False,  True, False, False,  True, False, False,  True,  True],\n                   [ True, False, False,  True, False, False,  True,  True, False]])\n\n            >>> sim.append_measurement_flips(np.array(\n            ...     [[0b11111111, 0b1], [0b00000000, 0b0], [0b11111111, 0b1]],\n            ...     dtype=np.uint8,\n            ... ))\n\n            >>> sim.get_measurement_flips()\n            array([[False,  True, False, False,  True, False, False,  True,  True],\n                   [ True, False, False,  True, False, False,  True,  True, False],\n                   [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n                   [False, False, False, False, False, False, False, False, False],\n                   [ True,  True,  True,  True,  True,  True,  True,  True,  True]])\n\n            >>> sim.append_measurement_flips(np.array(\n            ...     [[1, 0, 1, 0, 1, 0, 1, 0, 1], [0, 1, 0, 1, 0, 1, 0, 1, 0]],\n            ...     dtype=np.bool_,\n            ... ))\n\n            >>> sim.get_measurement_flips()\n            array([[False,  True, False, False,  True, False, False,  True,  True],\n                   [ True, False, False,  True, False, False,  True,  True, False],\n                   [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n                   [False, False, False, False, False, False, False, False, False],\n                   [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n                   [ True, False,  True, False,  True, False,  True, False,  True],\n                   [False,  True, False,  True, False,  True, False,  True, False]])\n        \"\"\"\n    @property\n    def batch_size(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of instances being simulated by the simulator.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.batch_size\n            256\n            >>> sim = stim.FlipSimulator(batch_size=42)\n            >>> sim.batch_size\n            42\n        \"\"\"\n    def broadcast_pauli_errors(\n        self,\n        *,\n        pauli: Union[str, int],\n        mask: np.ndarray,\n        p: float = 1,\n    ) -> None:\n        \"\"\"Applies a pauli error to all qubits in all instances, filtered by a mask.\n\n        Args:\n            pauli: The pauli, specified as an integer or string.\n                Uses the convention 0=I, 1=X, 2=Y, 3=Z.\n                Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.\n            mask: A 2d numpy array specifying where to apply errors. The first axis\n                is qubits, the second axis is simulation instances. The first axis\n                can have a length less than the current number of qubits (or more,\n                which adds qubits to the simulation). The length of the second axis\n                must match the simulator's `batch_size`. The array must satisfy\n\n                    mask.dtype == np.bool_\n                    len(mask.shape) == 2\n                    mask.shape[1] == flip_sim.batch_size\n\n                The error is only applied to qubit q in instance k when\n\n                    mask[q, k] == True.\n            p: Defaults to 1 (no effect). When specified, the error is applied\n                probabilistically instead of deterministically to each (instance, qubit)\n                pair matching the mask. This argument specifies the probability.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=2,\n            ...     num_qubits=3,\n            ...     disable_stabilizer_randomization=True,\n            ... )\n            >>> sim.broadcast_pauli_errors(\n            ...     pauli='X',\n            ...     mask=np.asarray([[True, False],[False, False],[True, True]]),\n            ... )\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+X_X\"), stim.PauliString(\"+__X\")]\n\n            >>> sim.broadcast_pauli_errors(\n            ...     pauli='Z',\n            ...     mask=np.asarray([[False, True],[False, False],[True, True]]),\n            ... )\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+X_Y\"), stim.PauliString(\"+Z_Y\")]\n        \"\"\"\n    def clear(\n        self,\n    ) -> None:\n        \"\"\"Clears the simulator's state, so it can be reused for another simulation.\n\n        This clears the measurement flip history, clears the detector flip history,\n        and zeroes the observable flip state. It also resets all qubits to |0>. If\n        stabilizer randomization is disabled, this zeros all pauli flip data. Otherwise\n        it randomizes all pauli flips to be I or Z with equal probability.\n\n        Behind the scenes, this doesn't free memory or resize the simulator. So,\n        repeating the same simulation with calls to `clear` in between will be faster\n        than allocating a new simulator each time (by avoiding re-allocations).\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.do(stim.Circuit(\"M(0.1) 9\"))\n            >>> sim.num_qubits\n            10\n            >>> sim.get_measurement_flips().shape\n            (1, 256)\n\n            >>> sim.clear()\n            >>> sim.num_qubits\n            10\n            >>> sim.get_measurement_flips().shape\n            (0, 256)\n        \"\"\"\n    def copy(\n        self,\n        *,\n        copy_rng: bool = False,\n        seed: Optional[int] = None,\n    ) -> stim.FlipSimulator:\n        \"\"\"Returns a simulator with the same internal state, except perhaps its prng.\n\n        Args:\n            copy_rng: Defaults to False. When False, the copy's pseudo random number\n                generator is reinitialized with a random seed instead of being a copy\n                of the original simulator's pseudo random number generator. This\n                causes the copy and the original to sample independent randomness,\n                instead of identical randomness, for future random operations. When set\n                to true, the copy will have the exact same pseudo random number\n                generator state as the original, and so will produce identical results\n                if told to do the same noisy operations. This argument is incompatible\n                with the `seed` argument.\n\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng state is either copied from the\n                original simulator or reseeded from system entropy, depending on the\n                copy_rng argument.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                circuit is executed. For example, reordering whether a reset on one\n                qubit happens before or after a reset on another qubit can result in\n                different measurement results being observed starting from the same\n                seed.\n\n        Returns:\n            The copy of the simulator.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n\n            >>> s1 = stim.FlipSimulator(batch_size=256)\n            >>> s1.set_pauli_flip('X', qubit_index=2, instance_index=3)\n            >>> s2 = s1.copy()\n            >>> s2 is s1\n            False\n            >>> s2.peek_pauli_flips() == s1.peek_pauli_flips()\n            True\n\n            >>> s1 = stim.FlipSimulator(batch_size=256)\n            >>> s2 = s1.copy(copy_rng=True)\n            >>> s1.do(stim.Circuit(\"X_ERROR(0.25) 0 \\n M 0\"))\n            >>> s2.do(stim.Circuit(\"X_ERROR(0.25) 0 \\n M 0\"))\n            >>> np.array_equal(s1.get_measurement_flips(), s2.get_measurement_flips())\n            True\n        \"\"\"\n    def do(\n        self,\n        obj: Union[stim.Circuit, stim.CircuitInstruction, stim.CircuitRepeatBlock],\n    ) -> None:\n        \"\"\"Applies a circuit or circuit instruction to the simulator's state.\n\n        The results of any measurements performed can be retrieved using the\n        `get_measurement_flips` method.\n\n        Args:\n            obj: The circuit or instruction to apply to the simulator's state.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=1,\n            ...     disable_stabilizer_randomization=True,\n            ... )\n            >>> circuit = stim.Circuit('''\n            ...     X_ERROR(1) 0 1 3\n            ...     REPEAT 5 {\n            ...         H 0\n            ...         C_XYZ 1\n            ...     }\n            ... ''')\n            >>> sim.do(circuit)\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+ZZ_X\")]\n\n            >>> sim.do(circuit[0])\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+YY__\")]\n\n            >>> sim.do(circuit[1])\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+YX__\")]\n        \"\"\"\n    def generate_bernoulli_samples(\n        self,\n        num_samples: int,\n        *,\n        p: float,\n        bit_packed: bool = False,\n        out: Optional[np.ndarray] = None,\n    ) -> np.ndarray:\n        \"\"\"Uses the simulator's random number generator to produce biased coin flips.\n\n        This method has best performance when specifying `bit_packed=True` and\n        when specifying an `out=` parameter pointing to a numpy array that has\n        contiguous data aligned to a 64 bit boundary. (If `out` isn't specified,\n        the returned numpy array will have this property.)\n\n        Args:\n            num_samples: The number of samples to produce.\n            p: The probability of each sample being True instead of False.\n            bit_packed: Defaults to False (no bit packing). When True, the result\n                has type np.uint8 instead of np.bool_ and 8 samples are packed into\n                each byte as if by np.packbits(bitorder='little'). (The bit order\n                is relevant when producing a number of samples that isn't a multiple\n                of 8.)\n            out: Defaults to None (allocate new). A numpy array to write the samples\n                into. Must have the correct size and dtype.\n\n        Returns:\n            A numpy array containing the samples. The shape and dtype depends on\n            the bit_packed argument:\n\n                if not bit_packed:\n                    shape = (num_samples,)\n                    dtype = np.bool_\n                elif not transpose and bit_packed:\n                    shape = (math.ceil(num_samples / 8),)\n                    dtype = np.uint8\n\n        Raises:\n            ValueError:\n                The given `out` argument had a shape or dtype inconsistent with the\n                requested data.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> r = sim.generate_bernoulli_samples(1001, p=0.25)\n            >>> r.dtype\n            dtype('bool')\n            >>> r.shape\n            (1001,)\n\n            >>> r = sim.generate_bernoulli_samples(53, p=0.1, bit_packed=True)\n            >>> r.dtype\n            dtype('uint8')\n            >>> r.shape\n            (7,)\n            >>> r[6] & 0b1110_0000  # zero'd padding bits\n            np.uint8(0)\n\n            >>> r2 = sim.generate_bernoulli_samples(53, p=0.2, bit_packed=True, out=r)\n            >>> r is r2  # Check request to reuse r worked.\n            True\n        \"\"\"\n    def get_detector_flips(\n        self,\n        *,\n        detector_index: Optional[int] = None,\n        instance_index: Optional[int] = None,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Retrieves detector flip data from the simulator's detection event record.\n\n        Args:\n            record_index: Identifies a detector to read results from.\n                Setting this to None (default) returns results from all detectors.\n                Otherwise this should be an integer in range(0, self.num_detectors).\n            instance_index: Identifies a simulation instance to read results from.\n                Setting this to None (the default) returns results from all instances.\n                Otherwise this should be an integer in range(0, self.batch_size).\n            bit_packed: Defaults to False. Determines whether the result is bit packed.\n                If this is set to true, the returned numpy array will be bit packed as\n                if by applying\n\n                    out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n                Behind the scenes the data is always bit packed, so setting this\n                argument avoids ever unpacking in the first place. This substantially\n                improves performance when there is a lot of data.\n\n        Returns:\n            A numpy array containing the requested data. By default this is a 2d array\n            of shape (self.num_detectors, self.batch_size), where the first index is\n            the detector_index and the second index is the instance_index and the\n            dtype is np.bool_.\n\n            Specifying detector_index slices away the first index, leaving a 1d array\n            with only an instance_index.\n\n            Specifying instance_index slices away the last index, leaving a 1d array\n            with only a detector_index (or a 0d array, a boolean, if detector_index\n            was also specified).\n\n            Specifying bit_packed=True bit packs the last remaining index, changing\n            the dtype to np.uint8.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.do(stim.Circuit('''\n            ...     M 0 0 0\n            ...     DETECTOR rec[-2] rec[-3]\n            ...     DETECTOR rec[-1] rec[-2]\n            ... '''))\n\n            >>> sim.get_detector_flips()\n            array([[False, False, False, False, False, False, False, False, False],\n                   [False, False, False, False, False, False, False, False, False]])\n\n            >>> sim.get_detector_flips(bit_packed=True)\n            array([[0, 0],\n                   [0, 0]], dtype=uint8)\n\n            >>> sim.get_detector_flips(instance_index=2)\n            array([False, False])\n\n            >>> sim.get_detector_flips(detector_index=1)\n            array([False, False, False, False, False, False, False, False, False])\n\n            >>> sim.get_detector_flips(instance_index=2, detector_index=1)\n            array(False)\n        \"\"\"\n    def get_measurement_flips(\n        self,\n        *,\n        record_index: Optional[int] = None,\n        instance_index: Optional[int] = None,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Retrieves measurement flip data from the simulator's measurement record.\n\n        Args:\n            record_index: Identifies a measurement to read results from.\n                Setting this to None (default) returns results from all measurements.\n                Setting this to a non-negative integer indexes measurements by the order\n                    they occurred. For example, record index 0 is the first measurement.\n                Setting this to a negative integer indexes measurements by recency.\n                    For example, recording index -1 is the most recent measurement.\n            instance_index: Identifies a simulation instance to read results from.\n                Setting this to None (the default) returns results from all instances.\n                Otherwise this should be set to an integer in range(0, self.batch_size).\n            bit_packed: Defaults to False. Determines whether the result is bit packed.\n                If this is set to true, the returned numpy array will be bit packed as\n                if by applying\n\n                    out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n                Behind the scenes the data is always bit packed, so setting this\n                argument avoids ever unpacking in the first place. This substantially\n                improves performance when there is a lot of data.\n\n        Returns:\n            A numpy array containing the requested data. By default this is a 2d array\n            of shape (self.num_measurements, self.batch_size), where the first index is\n            the measurement_index and the second index is the instance_index and the\n            dtype is np.bool_.\n\n            Specifying record_index slices away the first index, leaving a 1d array\n            with only an instance_index.\n\n            Specifying instance_index slices away the last index, leaving a 1d array\n            with only a measurement_index (or a 0d array, a boolean, if record_index\n            was also specified).\n\n            Specifying bit_packed=True bit packs the last remaining index, changing\n            the dtype to np.uint8.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.do(stim.Circuit('M 0 1 2'))\n\n            >>> sim.get_measurement_flips()\n            array([[False, False, False, False, False, False, False, False, False],\n                   [False, False, False, False, False, False, False, False, False],\n                   [False, False, False, False, False, False, False, False, False]])\n\n            >>> sim.get_measurement_flips(bit_packed=True)\n            array([[0, 0],\n                   [0, 0],\n                   [0, 0]], dtype=uint8)\n\n            >>> sim.get_measurement_flips(instance_index=1)\n            array([False, False, False])\n\n            >>> sim.get_measurement_flips(record_index=2)\n            array([False, False, False, False, False, False, False, False, False])\n\n            >>> sim.get_measurement_flips(instance_index=1, record_index=2)\n            array(False)\n        \"\"\"\n    def get_observable_flips(\n        self,\n        *,\n        observable_index: Optional[int] = None,\n        instance_index: Optional[int] = None,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Retrieves observable flip data from the simulator's detection event record.\n\n        Args:\n            record_index: Identifies a observable to read results from.\n                Setting this to None (default) returns results from all observables.\n                Otherwise this should be an integer in range(0, self.num_observables).\n            instance_index: Identifies a simulation instance to read results from.\n                Setting this to None (the default) returns results from all instances.\n                Otherwise this should be an integer in range(0, self.batch_size).\n            bit_packed: Defaults to False. Determines whether the result is bit packed.\n                If this is set to true, the returned numpy array will be bit packed as\n                if by applying\n\n                    out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n                Behind the scenes the data is always bit packed, so setting this\n                argument avoids ever unpacking in the first place. This substantially\n                improves performance when there is a lot of data.\n\n        Returns:\n            A numpy array containing the requested data. By default this is a 2d array\n            of shape (self.num_observables, self.batch_size), where the first index is\n            the observable_index and the second index is the instance_index and the\n            dtype is np.bool_.\n\n            Specifying observable_index slices away the first index, leaving a 1d array\n            with only an instance_index.\n\n            Specifying instance_index slices away the last index, leaving a 1d array\n            with only a observable_index (or a 0d array, a boolean, if observable_index\n            was also specified).\n\n            Specifying bit_packed=True bit packs the last remaining index, changing\n            the dtype to np.uint8.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.do(stim.Circuit('''\n            ...     M 0 0 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-2]\n            ...     OBSERVABLE_INCLUDE(1) rec[-1]\n            ... '''))\n\n            >>> sim.get_observable_flips()\n            array([[False, False, False, False, False, False, False, False, False],\n                   [False, False, False, False, False, False, False, False, False]])\n\n            >>> sim.get_observable_flips(bit_packed=True)\n            array([[0, 0],\n                   [0, 0]], dtype=uint8)\n\n            >>> sim.get_observable_flips(instance_index=2)\n            array([False, False])\n\n            >>> sim.get_observable_flips(observable_index=1)\n            array([False, False, False, False, False, False, False, False, False])\n\n            >>> sim.get_observable_flips(instance_index=2, observable_index=1)\n            array(False)\n        \"\"\"\n    @property\n    def num_detectors(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of detectors that have been simulated and stored.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.num_detectors\n            0\n            >>> sim.do(stim.Circuit('''\n            ...     M 0 0\n            ...     DETECTOR rec[-1] rec[-2]\n            ... '''))\n            >>> sim.num_detectors\n            1\n        \"\"\"\n    @property\n    def num_measurements(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of measurements that have been simulated and stored.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.num_measurements\n            0\n            >>> sim.do(stim.Circuit('M 3 5'))\n            >>> sim.num_measurements\n            2\n        \"\"\"\n    @property\n    def num_observables(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of observables currently tracked by the simulator.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.num_observables\n            0\n            >>> sim.do(stim.Circuit('''\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(4) rec[-1]\n            ... '''))\n            >>> sim.num_observables\n            5\n        \"\"\"\n    @property\n    def num_qubits(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of qubits currently tracked by the simulator.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.num_qubits\n            0\n            >>> sim = stim.FlipSimulator(batch_size=256, num_qubits=4)\n            >>> sim.num_qubits\n            4\n            >>> sim.do(stim.Circuit('H 5'))\n            >>> sim.num_qubits\n            6\n        \"\"\"\n    @overload\n    def peek_pauli_flips(\n        self,\n    ) -> List[stim.PauliString]:\n        pass\n    @overload\n    def peek_pauli_flips(\n        self,\n        *,\n        instance_index: int,\n    ) -> stim.PauliString:\n        pass\n    def peek_pauli_flips(\n        self,\n        *,\n        instance_index: Optional[int] = None,\n    ) -> Union[stim.PauliString, List[stim.PauliString]]:\n        \"\"\"Returns the current pauli errors packed into stim.PauliString instances.\n\n        Args:\n            instance_index: Defaults to None. When set to None, the pauli errors from\n                all instances are returned as a list of `stim.PauliString`. When set to\n                an integer, a single `stim.PauliString` is returned containing the\n                errors for the indexed instance.\n\n        Returns:\n            if instance_index is None:\n                A list of stim.PauliString, with the k'th entry being the errors from\n                the k'th simulation instance.\n            else:\n                A stim.PauliString with the errors from the k'th simulation instance.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=2,\n            ...     disable_stabilizer_randomization=True,\n            ...     num_qubits=10,\n            ... )\n\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+__________\"), stim.PauliString(\"+__________\")]\n\n            >>> sim.peek_pauli_flips(instance_index=0)\n            stim.PauliString(\"+__________\")\n\n            >>> sim.do(stim.Circuit('''\n            ...     X_ERROR(1) 0 3 5\n            ...     Z_ERROR(1) 3 6\n            ... '''))\n\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+X__Y_XZ___\"), stim.PauliString(\"+X__Y_XZ___\")]\n\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=1,\n            ...     num_qubits=100,\n            ... )\n            >>> flips: stim.PauliString = sim.peek_pauli_flips(instance_index=0)\n            >>> sorted(set(str(flips)))  # Should have Zs from stabilizer randomization\n            ['+', 'Z', '_']\n        \"\"\"\n    def set_pauli_flip(\n        self,\n        pauli: Union[str, int],\n        *,\n        qubit_index: int,\n        instance_index: int,\n    ) -> None:\n        \"\"\"Sets the pauli flip on a given qubit in a given simulation instance.\n\n        Args:\n            pauli: The pauli, specified as an integer or string.\n                Uses the convention 0=I, 1=X, 2=Y, 3=Z.\n                Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.\n            qubit_index: The qubit to put the error on. Must be non-negative. The state\n                will automatically expand as needed to store the error.\n            instance_index: The simulation index to put the error inside. Use negative\n                indices to index from the end of the list.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=2,\n            ...     num_qubits=3,\n            ...     disable_stabilizer_randomization=True,\n            ... )\n            >>> sim.set_pauli_flip('X', qubit_index=2, instance_index=1)\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+___\"), stim.PauliString(\"+__X\")]\n        \"\"\"\n    def to_numpy(\n        self,\n        *,\n        bit_packed: bool = False,\n        transpose: bool = False,\n        output_xs: Union[bool, np.ndarray] = False,\n        output_zs: Union[bool, np.ndarray] = False,\n        output_measure_flips: Union[bool, np.ndarray] = False,\n        output_detector_flips: Union[bool, np.ndarray] = False,\n        output_observable_flips: Union[bool, np.ndarray] = False,\n    ) -> Optional[Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]]:\n        \"\"\"Writes the simulator state into numpy arrays.\n\n        Args:\n            bit_packed: Whether or not the result is bit packed, storing 8 bits per\n                byte instead of 1 bit per byte. Bit packing always applies to\n                the second index of the result. Bits are packed in little endian\n                order (as if by `np.packbits(X, axis=1, order='little')`).\n            transpose: Defaults to False. When set to False, the second index of the\n                returned array (the index affected by bit packing) is the shot index\n                (meaning the first index is the qubit index or measurement index or\n                etc). When set to True, results are transposed so that the first\n                index is the shot index.\n            output_xs: Defaults to False. When set to False, the X flip data is not\n                generated and the corresponding array in the result tuple is set to\n                None. When set to True, a new array is allocated to hold the X flip\n                data and this array is returned via the result tuple. When set to\n                a numpy array, the results are written into that array (the shape and\n                dtype of the array must be exactly correct).\n            output_zs: Defaults to False. When set to False, the Z flip data is not\n                generated and the corresponding array in the result tuple is set to\n                None. When set to True, a new array is allocated to hold the Z flip\n                data and this array is returned via the result tuple. When set to\n                a numpy array, the results are written into that array (the shape and\n                dtype of the array must be exactly correct).\n            output_measure_flips: Defaults to False. When set to False, the measure\n                flip data is not generated and the corresponding array in the result\n                tuple is set to None. When set to True, a new array is allocated to\n                hold the measure flip data and this array is returned via the result\n                tuple. When set to a numpy array, the results are written into that\n                array (the shape and dtype of the array must be exactly correct).\n            output_detector_flips: Defaults to False. When set to False, the detector\n                flip data is not generated and the corresponding array in the result\n                tuple is set to None. When set to True, a new array is allocated to\n                hold the detector flip data and this array is returned via the result\n                tuple. When set to a numpy array, the results are written into that\n                array (the shape and dtype of the array must be exactly correct).\n            output_observable_flips: Defaults to False. When set to False, the obs\n                flip data is not generated and the corresponding array in the result\n                tuple is set to None. When set to True, a new array is allocated to\n                hold the obs flip data and this array is returned via the result\n                tuple. When set to a numpy array, the results are written into that\n                array (the shape and dtype of the array must be exactly correct).\n\n        Returns:\n            A tuple (xs, zs, ms, ds, os) of numpy arrays. The xs and zs arrays are\n            the pauli flip data specified using XZ encoding (00=I, 10=X, 11=Y, 01=Z).\n            The ms array is the measure flip data, the ds array is the detector flip\n            data, and the os array is the obs flip data. The arrays default to\n            `None` when the corresponding `output_*` argument was left False.\n\n            The shape and dtype of the data depends on arguments given to the function.\n            The following specifies each array's shape and dtype for each case:\n\n                if not transpose and not bit_packed:\n                    xs.shape = (sim.batch_size, sim.num_qubits)\n                    zs.shape = (sim.batch_size, sim.num_qubits)\n                    ms.shape = (sim.batch_size, sim.num_measurements)\n                    ds.shape = (sim.batch_size, sim.num_detectors)\n                    os.shape = (sim.batch_size, sim.num_observables)\n                    xs.dtype = np.bool_\n                    zs.dtype = np.bool_\n                    ms.dtype = np.bool_\n                    ds.dtype = np.bool_\n                    os.dtype = np.bool_\n                elif not transpose and bit_packed:\n                    xs.shape = (sim.batch_size, math.ceil(sim.num_qubits / 8))\n                    zs.shape = (sim.batch_size, math.ceil(sim.num_qubits / 8))\n                    ms.shape = (sim.batch_size, math.ceil(sim.num_measurements / 8))\n                    ds.shape = (sim.batch_size, math.ceil(sim.num_detectors / 8))\n                    os.shape = (sim.batch_size, math.ceil(sim.num_observables / 8))\n                    xs.dtype = np.uint8\n                    zs.dtype = np.uint8\n                    ms.dtype = np.uint8\n                    ds.dtype = np.uint8\n                    os.dtype = np.uint8\n                elif transpose and not bit_packed:\n                    xs.shape = (sim.num_qubits, sim.batch_size)\n                    zs.shape = (sim.num_qubits, sim.batch_size)\n                    ms.shape = (sim.num_measurements, sim.batch_size)\n                    ds.shape = (sim.num_detectors, sim.batch_size)\n                    os.shape = (sim.num_observables, sim.batch_size)\n                    xs.dtype = np.bool_\n                    zs.dtype = np.bool_\n                    ms.dtype = np.bool_\n                    ds.dtype = np.bool_\n                    os.dtype = np.bool_\n                elif transpose and bit_packed:\n                    xs.shape = (sim.num_qubits, math.ceil(sim.batch_size / 8))\n                    zs.shape = (sim.num_qubits, math.ceil(sim.batch_size / 8))\n                    ms.shape = (sim.num_measurements, math.ceil(sim.batch_size / 8))\n                    ds.shape = (sim.num_detectors, math.ceil(sim.batch_size / 8))\n                    os.shape = (sim.num_observables, math.ceil(sim.batch_size / 8))\n                    xs.dtype = np.uint8\n                    zs.dtype = np.uint8\n                    ms.dtype = np.uint8\n                    ds.dtype = np.uint8\n                    os.dtype = np.uint8\n\n        Raises:\n            ValueError:\n                All the `output_*` arguments were False, or an `output_*` argument\n                had a shape or dtype inconsistent with the requested data.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.do(stim.Circuit('M(1) 0 1 2'))\n\n            >>> ms_buf = np.empty(shape=(9, 1), dtype=np.uint8)\n            >>> xs, zs, ms, ds, os = sim.to_numpy(\n            ...     transpose=True,\n            ...     bit_packed=True,\n            ...     output_xs=True,\n            ...     output_measure_flips=ms_buf,\n            ... )\n            >>> assert ms is ms_buf\n            >>> xs\n            array([[0],\n                   [0],\n                   [0],\n                   [0],\n                   [0],\n                   [0],\n                   [0],\n                   [0],\n                   [0]], dtype=uint8)\n            >>> zs\n            >>> ms\n            array([[7],\n                   [7],\n                   [7],\n                   [7],\n                   [7],\n                   [7],\n                   [7],\n                   [7],\n                   [7]], dtype=uint8)\n            >>> ds\n            >>> os\n        \"\"\"\nclass FlippedMeasurement:\n    \"\"\"Describes a measurement that was flipped.\n\n    Gives the measurement's index in the measurement record, and also\n    the observable of the measurement.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     M(0.25) 1 10\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].flipped_measurement\n        stim.FlippedMeasurement(\n            record_index=1,\n            observable=(stim.GateTargetWithCoords(stim.target_z(10), []),),\n        )\n    \"\"\"\n    def __init__(\n        self,\n        measurement_record_index: Optional[int],\n        measured_observable: Iterable[stim.GateTargetWithCoords],\n    ):\n        \"\"\"Creates a stim.FlippedMeasurement.\n\n        Examples:\n            >>> import stim\n            >>> print(stim.FlippedMeasurement(\n            ...     record_index=5,\n            ...     observable=[],\n            ... ))\n            stim.FlippedMeasurement(\n                record_index=5,\n                observable=(),\n            )\n        \"\"\"\n    @property\n    def observable(\n        self,\n    ) -> List[stim.GateTargetWithCoords]:\n        \"\"\"Returns the observable of the flipped measurement.\n\n        For example, an `MX 5` measurement will have the observable X5.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     M(0.25) 1 10\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].flipped_measurement.observable\n            [stim.GateTargetWithCoords(stim.target_z(10), [])]\n        \"\"\"\n    @property\n    def record_index(\n        self,\n    ) -> int:\n        \"\"\"The measurement record index of the flipped measurement.\n        For example, the fifth measurement in a circuit has a measurement\n        record index of 4.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     M(0.25) 1 10\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].flipped_measurement.record_index\n            1\n        \"\"\"\nclass Flow:\n    \"\"\"A stabilizer flow (e.g. \"XI -> XX xor rec[-1]\").\n\n    Stabilizer circuits implement, and can be defined by, how they turn input\n    stabilizers into output stabilizers mediated by measurements. These\n    relationships are called stabilizer flows, and `stim.Flow` is a representation\n    of such a flow. For example, a `stim.Flow` can be given to\n    `stim.Circuit.has_flow` to verify that a circuit implements the flow.\n\n    A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer\n    P at the start of the circuit to the instantaneous stabilizer Q at the end of\n    the circuit. The flow may be mediated by certain measurements. For example,\n    a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and\n    the CNOT flows implemented by the circuit involve these measurements.\n\n    A flow like P -> Q means the circuit transforms P into Q.\n    A flow like 1 -> P means the circuit prepares P.\n    A flow like P -> 1 means the circuit measures P.\n    A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR).\n\n    References:\n        Stim's gate documentation includes the stabilizer flows of each gate.\n\n        Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are\n        defined and provides a circuit construction for experimentally verifying\n        their presence.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit(\"CNOT 2 4\")\n\n        >>> c.has_flow(stim.Flow(\"__X__ -> __X_X\"))\n        True\n\n        >>> c.has_flow(stim.Flow(\"X2*X4 -> X2\"))\n        True\n\n        >>> c.has_flow(stim.Flow(\"Z4 -> Z4\"))\n        False\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.Flow,\n    ) -> bool:\n        \"\"\"Determines if two flows have identical contents.\n        \"\"\"\n    def __init__(\n        self,\n        arg: Union[None, str, stim.Flow] = None,\n        /,\n        *,\n        input: Optional[stim.PauliString] = None,\n        output: Optional[stim.PauliString] = None,\n        measurements: Optional[Iterable[Union[int, GateTarget]]] = None,\n        included_observables: Optional[Iterable[int]] = None,\n    ) -> None:\n        \"\"\"Initializes a stim.Flow.\n\n        When given a string, the string is parsed as flow shorthand. For example,\n        the string \"X_ -> ZZ xor rec[-1]\" will result in a flow with input pauli string\n        \"X_\", output pauli string \"ZZ\", and measurement indices [-1].\n\n        Args:\n            arg [position-only]: Defaults to None. Must be specified by itself if used.\n                str: Initializes a flow by parsing the given shorthand text.\n                stim.Flow: Initializes a copy of the given flow.\n                None (default): Initializes an empty flow.\n            input: Defaults to None. Can be set to a stim.PauliString to directly\n                specify the flow's input stabilizer.\n            output: Defaults to None. Can be set to a stim.PauliString to directly\n                specify the flow's output stabilizer.\n            measurements: Defaults to None. Can be set to a list of integers or gate\n                targets like `stim.target_rec(-1)`, to specify the measurements that\n                mediate the flow. Negative and positive measurement indices are allowed.\n                Indexes follow the python convention where -1 is the last measurement in\n                a circuit and 0 is the first measurement in a circuit.\n            included_observables: Defaults to None. `OBSERVABLE_INCLUDE` instructions\n                that target an observable index from this list will be implicitly\n                included in the flow. This allows flows to refer to observables. For\n                example, the flow \"X5 -> obs[3]\" says \"At the start of the circuit,\n                observable 3 should be an X term on qubit 5. By the end of the circuit\n                it will be measured. The `OBSERVABLE_INCLUDE(3)` instructions in the\n                circuit should explain how this happened.\".\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Flow(\"X2 -> -Y2*Z4 xor rec[-1]\")\n            stim.Flow(\"__X -> -__Y_Z xor rec[-1]\")\n\n            >>> stim.Flow(\"Z -> 1 xor rec[-1]\")\n            stim.Flow(\"Z -> rec[-1]\")\n\n            >>> stim.Flow(\n            ...     input=stim.PauliString(\"XX\"),\n            ...     output=stim.PauliString(\"_X\"),\n            ...     measurements=[],\n            ... )\n            stim.Flow(\"XX -> _X\")\n\n            >>> # Identical terms cancel.\n            >>> stim.Flow(\"X2 -> Y2*Y2 xor rec[-2] xor rec[-2]\")\n            stim.Flow(\"__X -> ___\")\n\n            >>> stim.Flow(\"X -> Y xor obs[3] xor obs[3] xor obs[3]\")\n            stim.Flow(\"X -> Y xor obs[3]\")\n        \"\"\"\n    def __mul__(\n        self,\n        rhs: stim.Flow,\n    ) -> stim.Flow:\n        \"\"\"Computes the product of two flows.\n\n        Args:\n            rhs: The right hand side of the multiplication.\n\n        Returns:\n            The product of the two flows.\n\n        Raises:\n            ValueError: The inputs anti-commute (their product would be anti-Hermitian).\n                For example, 1 -> X times 1 -> Y fails because it would give 1 -> iZ.\n\n        Examples:\n            >>> import stim\n            >>> stim.Flow(\"X -> X\") * stim.Flow(\"Z -> Z\")\n            stim.Flow(\"Y -> Y\")\n\n            >>> stim.Flow(\"1 -> XX\") * stim.Flow(\"1 -> ZZ\")\n            stim.Flow(\"1 -> -YY\")\n\n            >>> stim.Flow(\"X -> rec[-1]\") * stim.Flow(\"X -> rec[-2]\")\n            stim.Flow(\"_ -> rec[-2] xor rec[-1]\")\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.Flow,\n    ) -> bool:\n        \"\"\"Determines if two flows have non-identical contents.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.Flow`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a shorthand description of the flow.\n        \"\"\"\n    def included_observables_copy(\n        self,\n    ) -> List[int]:\n        \"\"\"Returns a copy of the flow's included observable indices.\n\n        When an observable is included in a flow, the flow implicitly includes all\n        measurements and pauli terms from `OBSERVABLE_INCLUDE` instructions targeting\n        that observable index.\n\n        Examples:\n            >>> import stim\n            >>> f = stim.Flow(included_observables=[3, 2])\n            >>> f.included_observables_copy()\n            [2, 3]\n\n            >>> f.included_observables_copy() is f.included_observables_copy()\n            False\n\n            >>> f = stim.Flow(\"X2 -> obs[3]\")\n            >>> f.included_observables_copy()\n            [3]\n            >>> stim.Circuit(\"OBSERVABLE_INCLUDE(3) X2\").has_flow(f)\n            True\n        \"\"\"\n    def input_copy(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns a copy of the flow's input stabilizer.\n\n        Examples:\n            >>> import stim\n            >>> f = stim.Flow(input=stim.PauliString('XX'))\n            >>> f.input_copy()\n            stim.PauliString(\"+XX\")\n\n            >>> f.input_copy() is f.input_copy()\n            False\n        \"\"\"\n    def measurements_copy(\n        self,\n    ) -> List[int]:\n        \"\"\"Returns a copy of the flow's measurement indices.\n\n        Examples:\n            >>> import stim\n            >>> f = stim.Flow(measurements=[-1, 2])\n            >>> f.measurements_copy()\n            [-1, 2]\n\n            >>> f.measurements_copy() is f.measurements_copy()\n            False\n        \"\"\"\n    def output_copy(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns a copy of the flow's output stabilizer.\n\n        Examples:\n            >>> import stim\n            >>> f = stim.Flow(output=stim.PauliString('XX'))\n            >>> f.output_copy()\n            stim.PauliString(\"+XX\")\n\n            >>> f.output_copy() is f.output_copy()\n            False\n        \"\"\"\nclass GateData:\n    \"\"\"Details about a gate supported by stim.\n\n    Examples:\n        >>> import stim\n        >>> stim.gate_data('h').name\n        'H'\n        >>> stim.gate_data('h').is_unitary\n        True\n        >>> stim.gate_data('h').tableau\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X\"),\n            ],\n        )\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.GateData,\n    ) -> bool:\n        \"\"\"Determines if two GateData instances are identical.\n        \"\"\"\n    def __init__(\n        self,\n        name: str,\n    ) -> None:\n        \"\"\"Finds gate data for the named gate.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateData('H').is_unitary\n            True\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.GateData,\n    ) -> bool:\n        \"\"\"Determines if two GateData instances are not identical.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.GateData`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns text describing the gate data.\n        \"\"\"\n    @property\n    def aliases(\n        self,\n    ) -> List[str]:\n        \"\"\"Returns all aliases that can be used to name the gate.\n\n        Although gates can be referred to by lower case and mixed\n        case named, the result only includes upper cased aliases.\n\n        Examples:\n            >>> import stim\n            >>> stim.gate_data('H').aliases\n            ['H', 'H_XZ']\n            >>> stim.gate_data('cnot').aliases\n            ['CNOT', 'CX', 'ZCX']\n        \"\"\"\n    @property\n    def flows(\n        self,\n    ) -> Optional[List[stim.Flow]]:\n        \"\"\"Returns stabilizer flow generators for the gate, or else None.\n\n        A stabilizer flow describes an input-output relationship that the gate\n        satisfies, where an input pauli string is transformed into an output\n        pauli string mediated by certain measurement results.\n\n        Caution: this method returns None for variable-target-count gates like MPP.\n        Not because MPP has no stabilizer flows, but because its stabilizer flows\n        depend on how many qubits it targets and what basis it targets them in.\n\n        Returns:\n            A list of stim.Flow instances representing the generators.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').flows\n            [stim.Flow(\"X -> Z\"), stim.Flow(\"Z -> X\")]\n\n            >>> for e in stim.gate_data('ISWAP').flows:\n            ...     print(e)\n            X_ -> ZY\n            Z_ -> _Z\n            _X -> YZ\n            _Z -> Z_\n\n            >>> for e in stim.gate_data('MXX').flows:\n            ...     print(e)\n            X_ -> X_\n            _X -> _X\n            ZZ -> ZZ\n            XX -> rec[-1]\n        \"\"\"\n    @property\n    def generalized_inverse(\n        self,\n    ) -> stim.GateData:\n        \"\"\"The closest-thing-to-an-inverse for the gate, if forced to pick something.\n\n        The generalized inverse of a unitary gate U is its actual inverse U^-1.\n\n        The generalized inverse of a reset or measurement gate U is a gate V such that,\n        for every stabilizer flow that U has, V has the time reverse of that flow (up\n        to Pauli feedback, with potentially more flows). For example, the time-reverse\n        of R is MR because R has the single flow 1 -> Z and MR has the time reversed\n        flow Z -> rec[-1].\n\n        The generalized inverse of noise like X_ERROR is just the same noise.\n\n        The generalized inverse of an annotation like TICK is just the same annotation.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').generalized_inverse\n            stim.gate_data('H')\n\n            >>> stim.gate_data('CXSWAP').generalized_inverse\n            stim.gate_data('SWAPCX')\n\n            >>> stim.gate_data('X_ERROR').generalized_inverse\n            stim.gate_data('X_ERROR')\n\n            >>> stim.gate_data('MX').generalized_inverse\n            stim.gate_data('MX')\n\n            >>> stim.gate_data('MRY').generalized_inverse\n            stim.gate_data('MRY')\n\n            >>> stim.gate_data('R').generalized_inverse\n            stim.gate_data('M')\n\n            >>> stim.gate_data('DETECTOR').generalized_inverse\n            stim.gate_data('DETECTOR')\n\n            >>> stim.gate_data('TICK').generalized_inverse\n            stim.gate_data('TICK')\n        \"\"\"\n    def hadamard_conjugated(\n        self,\n        *,\n        unsigned: bool = False,\n    ) -> Optional[stim.GateData]:\n        \"\"\"Returns a stim gate equivalent to this gate conjugated by Hadamard gates.\n\n        The Hadamard conjugate can be thought of as the XZ dual of the gate; the gate\n        you get by exchanging the X and Z bases. For example, a SQRT_X will become a\n        SQRT_Z and a CX gate will switch directions into an XCZ.\n\n        If stim doesn't define a gate equivalent to conjugating this gate by Hadamards,\n        the value `None` is returned.\n\n        Args:\n            unsigned: Defaults to False. When False, the returned gate must be *exactly*\n                the Hadamard conjugation of this gate. When True, the returned gate must\n                have the same flows but the sign of the flows can be different (i.e.\n                the returned gate must be the Hadamard conjugate up to Pauli gate\n                differences).\n\n        Returns:\n            A stim.GateData instance of the Hadamard conjugate, if it exists in stim.\n\n            None, if stim doesn't define a gate equal to the Hadamard conjugate.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('X').hadamard_conjugated()\n            stim.gate_data('Z')\n            >>> stim.gate_data('CX').hadamard_conjugated()\n            stim.gate_data('XCZ')\n            >>> stim.gate_data('RY').hadamard_conjugated() is None\n            True\n            >>> stim.gate_data('RY').hadamard_conjugated(unsigned=True)\n            stim.gate_data('RY')\n            >>> stim.gate_data('ISWAP').hadamard_conjugated(unsigned=True) is None\n            True\n            >>> stim.gate_data('SWAP').hadamard_conjugated()\n            stim.gate_data('SWAP')\n            >>> stim.gate_data('CXSWAP').hadamard_conjugated()\n            stim.gate_data('SWAPCX')\n            >>> stim.gate_data('MXX').hadamard_conjugated()\n            stim.gate_data('MZZ')\n            >>> stim.gate_data('DEPOLARIZE1').hadamard_conjugated()\n            stim.gate_data('DEPOLARIZE1')\n            >>> stim.gate_data('X_ERROR').hadamard_conjugated()\n            stim.gate_data('Z_ERROR')\n            >>> stim.gate_data('H_XY').hadamard_conjugated()\n            stim.gate_data('H_NYZ')\n            >>> stim.gate_data('DETECTOR').hadamard_conjugated(unsigned=True)\n            stim.gate_data('DETECTOR')\n        \"\"\"\n    @property\n    def inverse(\n        self,\n    ) -> Optional[stim.GateData]:\n        \"\"\"The inverse of the gate, or None if it has no inverse.\n\n        The inverse V of a gate U must have the property that V undoes the effects of U\n        and that U undoes the effects of V. In particular, the circuit\n\n            U 0 1\n            V 0 1\n\n        should be equivalent to doing nothing at all.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').inverse\n            stim.gate_data('H')\n\n            >>> stim.gate_data('CX').inverse\n            stim.gate_data('CX')\n\n            >>> stim.gate_data('S').inverse\n            stim.gate_data('S_DAG')\n\n            >>> stim.gate_data('CXSWAP').inverse\n            stim.gate_data('SWAPCX')\n\n            >>> stim.gate_data('X_ERROR').inverse is None\n            True\n            >>> stim.gate_data('M').inverse is None\n            True\n            >>> stim.gate_data('R').inverse is None\n            True\n            >>> stim.gate_data('DETECTOR').inverse is None\n            True\n            >>> stim.gate_data('TICK').inverse is None\n            True\n        \"\"\"\n    @property\n    def is_noisy_gate(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate can produce noise.\n\n        Note that measurement operations are considered noisy,\n        because for example `M(0.001) 2 3 5` will include\n        noise that flips its result 0.1% of the time.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('M').is_noisy_gate\n            True\n            >>> stim.gate_data('MXX').is_noisy_gate\n            True\n            >>> stim.gate_data('X_ERROR').is_noisy_gate\n            True\n            >>> stim.gate_data('CORRELATED_ERROR').is_noisy_gate\n            True\n            >>> stim.gate_data('MPP').is_noisy_gate\n            True\n\n            >>> stim.gate_data('H').is_noisy_gate\n            False\n            >>> stim.gate_data('CX').is_noisy_gate\n            False\n            >>> stim.gate_data('R').is_noisy_gate\n            False\n            >>> stim.gate_data('DETECTOR').is_noisy_gate\n            False\n        \"\"\"\n    @property\n    def is_reset(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate resets qubits in any basis.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('R').is_reset\n            True\n            >>> stim.gate_data('RX').is_reset\n            True\n            >>> stim.gate_data('MR').is_reset\n            True\n\n            >>> stim.gate_data('M').is_reset\n            False\n            >>> stim.gate_data('MXX').is_reset\n            False\n            >>> stim.gate_data('MPP').is_reset\n            False\n            >>> stim.gate_data('H').is_reset\n            False\n            >>> stim.gate_data('CX').is_reset\n            False\n            >>> stim.gate_data('HERALDED_ERASE').is_reset\n            False\n            >>> stim.gate_data('DEPOLARIZE2').is_reset\n            False\n            >>> stim.gate_data('X_ERROR').is_reset\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').is_reset\n            False\n            >>> stim.gate_data('DETECTOR').is_reset\n            False\n        \"\"\"\n    @property\n    def is_single_qubit_gate(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate is a single qubit gate.\n\n        Single qubit gates apply separately to each of their targets.\n\n        Variable-qubit gates like CORRELATED_ERROR and MPP are not\n        considered single qubit gates.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').is_single_qubit_gate\n            True\n            >>> stim.gate_data('R').is_single_qubit_gate\n            True\n            >>> stim.gate_data('M').is_single_qubit_gate\n            True\n            >>> stim.gate_data('X_ERROR').is_single_qubit_gate\n            True\n\n            >>> stim.gate_data('CX').is_single_qubit_gate\n            False\n            >>> stim.gate_data('MXX').is_single_qubit_gate\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').is_single_qubit_gate\n            False\n            >>> stim.gate_data('MPP').is_single_qubit_gate\n            False\n            >>> stim.gate_data('DETECTOR').is_single_qubit_gate\n            False\n            >>> stim.gate_data('TICK').is_single_qubit_gate\n            False\n            >>> stim.gate_data('REPEAT').is_single_qubit_gate\n            False\n        \"\"\"\n    @property\n    def is_symmetric_gate(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate is the same when its targets are swapped.\n\n        A two qubit gate is symmetric if it doesn't matter if you swap its targets. It\n        is unaffected when conjugated by the SWAP gate.\n\n        Single qubit gates are vacuously symmetric. A multi-qubit gate is symmetric if\n        swapping any two of its targets has no effect.\n\n        Note that this method is for symmetry *without broadcasting*. For example, SWAP\n        is symmetric even though SWAP 1 2 3 4 isn't equal to SWAP 1 3 2 4.\n\n        Returns:\n            True if the gate is symmetric.\n            False if the gate isn't symmetric.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('CX').is_symmetric_gate\n            False\n            >>> stim.gate_data('CZ').is_symmetric_gate\n            True\n            >>> stim.gate_data('ISWAP').is_symmetric_gate\n            True\n            >>> stim.gate_data('CXSWAP').is_symmetric_gate\n            False\n            >>> stim.gate_data('MXX').is_symmetric_gate\n            True\n            >>> stim.gate_data('DEPOLARIZE2').is_symmetric_gate\n            True\n            >>> stim.gate_data('PAULI_CHANNEL_2').is_symmetric_gate\n            False\n            >>> stim.gate_data('H').is_symmetric_gate\n            True\n            >>> stim.gate_data('R').is_symmetric_gate\n            True\n            >>> stim.gate_data('X_ERROR').is_symmetric_gate\n            True\n            >>> stim.gate_data('CORRELATED_ERROR').is_symmetric_gate\n            False\n            >>> stim.gate_data('MPP').is_symmetric_gate\n            False\n            >>> stim.gate_data('DETECTOR').is_symmetric_gate\n            False\n        \"\"\"\n    @property\n    def is_two_qubit_gate(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate is a two qubit gate.\n\n        Two qubit gates must be given an even number of targets.\n\n        Variable-qubit gates like CORRELATED_ERROR and MPP are not\n        considered two qubit gates.\n\n        Returns:\n            True if the gate is a two qubit gate.\n            False if the gate isn't a two qubit gate.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('CX').is_two_qubit_gate\n            True\n            >>> stim.gate_data('MXX').is_two_qubit_gate\n            True\n\n            >>> stim.gate_data('H').is_two_qubit_gate\n            False\n            >>> stim.gate_data('R').is_two_qubit_gate\n            False\n            >>> stim.gate_data('M').is_two_qubit_gate\n            False\n            >>> stim.gate_data('X_ERROR').is_two_qubit_gate\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').is_two_qubit_gate\n            False\n            >>> stim.gate_data('MPP').is_two_qubit_gate\n            False\n            >>> stim.gate_data('DETECTOR').is_two_qubit_gate\n            False\n        \"\"\"\n    @property\n    def is_unitary(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate is a unitary gate.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').is_unitary\n            True\n            >>> stim.gate_data('CX').is_unitary\n            True\n\n            >>> stim.gate_data('R').is_unitary\n            False\n            >>> stim.gate_data('M').is_unitary\n            False\n            >>> stim.gate_data('MXX').is_unitary\n            False\n            >>> stim.gate_data('X_ERROR').is_unitary\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').is_unitary\n            False\n            >>> stim.gate_data('MPP').is_unitary\n            False\n            >>> stim.gate_data('DETECTOR').is_unitary\n            False\n        \"\"\"\n    @property\n    def name(\n        self,\n    ) -> str:\n        \"\"\"Returns the canonical name of the gate.\n\n        Examples:\n            >>> import stim\n            >>> stim.gate_data('H').name\n            'H'\n            >>> stim.gate_data('cnot').name\n            'CX'\n        \"\"\"\n    @property\n    def num_parens_arguments_range(\n        self,\n    ) -> range:\n        \"\"\"Returns the min/max parens arguments taken by the gate, as a python range.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('M').num_parens_arguments_range\n            range(0, 2)\n            >>> list(stim.gate_data('M').num_parens_arguments_range)\n            [0, 1]\n            >>> list(stim.gate_data('R').num_parens_arguments_range)\n            [0]\n            >>> list(stim.gate_data('H').num_parens_arguments_range)\n            [0]\n            >>> list(stim.gate_data('X_ERROR').num_parens_arguments_range)\n            [1]\n            >>> list(stim.gate_data('PAULI_CHANNEL_1').num_parens_arguments_range)\n            [3]\n            >>> list(stim.gate_data('PAULI_CHANNEL_2').num_parens_arguments_range)\n            [15]\n            >>> stim.gate_data('DETECTOR').num_parens_arguments_range\n            range(0, 256)\n            >>> list(stim.gate_data('OBSERVABLE_INCLUDE').num_parens_arguments_range)\n            [1]\n        \"\"\"\n    @property\n    def produces_measurements(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate produces measurement results.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('M').produces_measurements\n            True\n            >>> stim.gate_data('MRY').produces_measurements\n            True\n            >>> stim.gate_data('MXX').produces_measurements\n            True\n            >>> stim.gate_data('MPP').produces_measurements\n            True\n            >>> stim.gate_data('HERALDED_ERASE').produces_measurements\n            True\n\n            >>> stim.gate_data('H').produces_measurements\n            False\n            >>> stim.gate_data('CX').produces_measurements\n            False\n            >>> stim.gate_data('R').produces_measurements\n            False\n            >>> stim.gate_data('X_ERROR').produces_measurements\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').produces_measurements\n            False\n            >>> stim.gate_data('DETECTOR').produces_measurements\n            False\n        \"\"\"\n    @property\n    def tableau(\n        self,\n    ) -> Optional[stim.Tableau]:\n        \"\"\"Returns the gate's tableau, or None if the gate has no tableau.\n\n        Examples:\n            >>> import stim\n            >>> print(stim.gate_data('M').tableau)\n            None\n            >>> stim.gate_data('H').tableau\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+X\"),\n                ],\n            )\n            >>> stim.gate_data('ISWAP').tableau\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+ZY\"),\n                    stim.PauliString(\"+YZ\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+_Z\"),\n                    stim.PauliString(\"+Z_\"),\n                ],\n            )\n        \"\"\"\n    @property\n    def takes_measurement_record_targets(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate can accept rec targets.\n\n        For example, `CX` can take a measurement record target\n        like `CX rec[-1] 1`.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('CX').takes_measurement_record_targets\n            True\n            >>> stim.gate_data('DETECTOR').takes_measurement_record_targets\n            True\n\n            >>> stim.gate_data('H').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('SWAP').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('R').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('M').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('MRY').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('MXX').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('X_ERROR').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('MPP').takes_measurement_record_targets\n            False\n        \"\"\"\n    @property\n    def takes_pauli_targets(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate expects pauli targets.\n\n        For example, `CORRELATED_ERROR` takes targets like `X0` and `Y1`\n        instead of `0` or `1`.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('CORRELATED_ERROR').takes_pauli_targets\n            True\n            >>> stim.gate_data('MPP').takes_pauli_targets\n            True\n\n            >>> stim.gate_data('H').takes_pauli_targets\n            False\n            >>> stim.gate_data('CX').takes_pauli_targets\n            False\n            >>> stim.gate_data('R').takes_pauli_targets\n            False\n            >>> stim.gate_data('M').takes_pauli_targets\n            False\n            >>> stim.gate_data('MRY').takes_pauli_targets\n            False\n            >>> stim.gate_data('MXX').takes_pauli_targets\n            False\n            >>> stim.gate_data('X_ERROR').takes_pauli_targets\n            False\n            >>> stim.gate_data('DETECTOR').takes_pauli_targets\n            False\n        \"\"\"\n    @property\n    def unitary_matrix(\n        self,\n    ) -> Optional[np.ndarray]:\n        \"\"\"Returns the gate's unitary matrix, or None if the gate isn't unitary.\n\n        Examples:\n            >>> import stim\n\n            >>> print(stim.gate_data('M').unitary_matrix)\n            None\n\n            >>> stim.gate_data('X').unitary_matrix\n            array([[0.+0.j, 1.+0.j],\n                   [1.+0.j, 0.+0.j]], dtype=complex64)\n\n            >>> stim.gate_data('ISWAP').unitary_matrix\n            array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j],\n                   [0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]], dtype=complex64)\n        \"\"\"\nclass GateTarget:\n    \"\"\"Represents a gate target, like `0` or `rec[-1]`, from a circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     M 0 !1\n        ... ''')\n        >>> circuit[0].targets_copy()[0]\n        stim.GateTarget(0)\n        >>> circuit[0].targets_copy()[1]\n        stim.target_inv(1)\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.GateTarget,\n    ) -> bool:\n        \"\"\"Determines if two `stim.GateTarget`s are identical.\n        \"\"\"\n    def __init__(\n        self,\n        value: object,\n    ) -> None:\n        \"\"\"Initializes a `stim.GateTarget`.\n\n        Args:\n            value: A value to convert into a gate target, like an integer\n                to interpret as a qubit target or a string to parse.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(stim.GateTarget(5))\n            stim.GateTarget(5)\n            >>> stim.GateTarget(\"X7\")\n            stim.target_x(7)\n            >>> stim.GateTarget(\"rec[-3]\")\n            stim.target_rec(-3)\n            >>> stim.GateTarget(\"!Z7\")\n            stim.target_z(7, invert=True)\n            >>> stim.GateTarget(\"*\")\n            stim.GateTarget.combiner()\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.GateTarget,\n    ) -> bool:\n        \"\"\"Determines if two `stim.GateTarget`s are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.GateTarget`.\n        \"\"\"\n    @property\n    def is_combiner(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a combiner target like `*`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_combiner\n            False\n            >>> stim.target_inv(7).is_combiner\n            False\n            >>> stim.target_x(8).is_combiner\n            False\n            >>> stim.target_y(2).is_combiner\n            False\n            >>> stim.target_z(3).is_combiner\n            False\n            >>> stim.target_sweep_bit(9).is_combiner\n            False\n            >>> stim.target_rec(-5).is_combiner\n            False\n            >>> stim.target_combiner().is_combiner\n            True\n        \"\"\"\n    @property\n    def is_inverted_result_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is an inverted target like `!5` or `!X4`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_inverted_result_target\n            False\n            >>> stim.target_inv(7).is_inverted_result_target\n            True\n            >>> stim.target_x(8).is_inverted_result_target\n            False\n            >>> stim.target_x(8, invert=True).is_inverted_result_target\n            True\n            >>> stim.target_y(2).is_inverted_result_target\n            False\n            >>> stim.target_z(3).is_inverted_result_target\n            False\n            >>> stim.target_sweep_bit(9).is_inverted_result_target\n            False\n            >>> stim.target_rec(-5).is_inverted_result_target\n            False\n        \"\"\"\n    @property\n    def is_measurement_record_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a measurement record target like `rec[-5]`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_measurement_record_target\n            False\n            >>> stim.target_inv(7).is_measurement_record_target\n            False\n            >>> stim.target_x(8).is_measurement_record_target\n            False\n            >>> stim.target_y(2).is_measurement_record_target\n            False\n            >>> stim.target_z(3).is_measurement_record_target\n            False\n            >>> stim.target_sweep_bit(9).is_measurement_record_target\n            False\n            >>> stim.target_rec(-5).is_measurement_record_target\n            True\n        \"\"\"\n    @property\n    def is_qubit_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a qubit target like `5` or `!6`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_qubit_target\n            True\n            >>> stim.target_inv(7).is_qubit_target\n            True\n            >>> stim.target_x(8).is_qubit_target\n            False\n            >>> stim.target_y(2).is_qubit_target\n            False\n            >>> stim.target_z(3).is_qubit_target\n            False\n            >>> stim.target_sweep_bit(9).is_qubit_target\n            False\n            >>> stim.target_rec(-5).is_qubit_target\n            False\n        \"\"\"\n    @property\n    def is_sweep_bit_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a sweep bit target like `sweep[4]`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_sweep_bit_target\n            False\n            >>> stim.target_inv(7).is_sweep_bit_target\n            False\n            >>> stim.target_x(8).is_sweep_bit_target\n            False\n            >>> stim.target_y(2).is_sweep_bit_target\n            False\n            >>> stim.target_z(3).is_sweep_bit_target\n            False\n            >>> stim.target_sweep_bit(9).is_sweep_bit_target\n            True\n            >>> stim.target_rec(-5).is_sweep_bit_target\n            False\n        \"\"\"\n    @property\n    def is_x_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is an X pauli target like `X2` or `!X7`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_x_target\n            False\n            >>> stim.target_inv(7).is_x_target\n            False\n            >>> stim.target_x(8).is_x_target\n            True\n            >>> stim.target_y(2).is_x_target\n            False\n            >>> stim.target_z(3).is_x_target\n            False\n            >>> stim.target_sweep_bit(9).is_x_target\n            False\n            >>> stim.target_rec(-5).is_x_target\n            False\n        \"\"\"\n    @property\n    def is_y_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a Y pauli target like `Y2` or `!Y7`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_y_target\n            False\n            >>> stim.target_inv(7).is_y_target\n            False\n            >>> stim.target_x(8).is_y_target\n            False\n            >>> stim.target_y(2).is_y_target\n            True\n            >>> stim.target_z(3).is_y_target\n            False\n            >>> stim.target_sweep_bit(9).is_y_target\n            False\n            >>> stim.target_rec(-5).is_y_target\n            False\n        \"\"\"\n    @property\n    def is_z_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a Z pauli target like `Z2` or `!Z7`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_z_target\n            False\n            >>> stim.target_inv(7).is_z_target\n            False\n            >>> stim.target_x(8).is_z_target\n            False\n            >>> stim.target_y(2).is_z_target\n            False\n            >>> stim.target_z(3).is_z_target\n            True\n            >>> stim.target_sweep_bit(9).is_z_target\n            False\n            >>> stim.target_rec(-5).is_z_target\n            False\n        \"\"\"\n    @property\n    def pauli_type(\n        self,\n    ) -> str:\n        \"\"\"Returns whether this is an 'X', 'Y', or 'Z' target.\n\n        For non-pauli targets, this property evaluates to 'I'.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).pauli_type\n            'I'\n            >>> stim.target_inv(7).pauli_type\n            'I'\n            >>> stim.target_x(8).pauli_type\n            'X'\n            >>> stim.target_y(2).pauli_type\n            'Y'\n            >>> stim.target_z(3).pauli_type\n            'Z'\n            >>> stim.target_sweep_bit(9).pauli_type\n            'I'\n            >>> stim.target_rec(-5).pauli_type\n            'I'\n        \"\"\"\n    @property\n    def qubit_value(\n        self,\n    ) -> Optional[int]:\n        \"\"\"Returns the integer value of the targeted qubit, or else None.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).qubit_value\n            6\n            >>> stim.target_inv(7).qubit_value\n            7\n            >>> stim.target_x(8).qubit_value\n            8\n            >>> stim.target_y(2).qubit_value\n            2\n            >>> stim.target_z(3).qubit_value\n            3\n            >>> print(stim.target_sweep_bit(9).qubit_value)\n            None\n            >>> print(stim.target_rec(-5).qubit_value)\n            None\n        \"\"\"\n    @property\n    def value(\n        self,\n    ) -> int:\n        \"\"\"The numeric part of the target.\n\n        This is non-negative integer for qubit targets, and a negative integer for\n        measurement record targets.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).value\n            6\n            >>> stim.target_inv(7).value\n            7\n            >>> stim.target_x(8).value\n            8\n            >>> stim.target_y(2).value\n            2\n            >>> stim.target_z(3).value\n            3\n            >>> stim.target_sweep_bit(9).value\n            9\n            >>> stim.target_rec(-5).value\n            -5\n        \"\"\"\nclass GateTargetWithCoords:\n    \"\"\"A gate target with associated coordinate information.\n\n    For example, if the gate target is a qubit from a circuit with\n    QUBIT_COORDS instructions, the coords field will contain the\n    coordinate data from the QUBIT_COORDS instruction for the qubit.\n\n    This is helpful information to have available when debugging a\n    problem in a circuit, instead of having to constantly manually\n    look up the coordinates of a qubit index in order to understand\n    what is happening.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n        >>> t.gate_target\n        stim.GateTarget(0)\n        >>> t.coords\n        [1.5, 2.0]\n    \"\"\"\n    def __init__(\n        self,\n        gate_target: object,\n        coords: List[float],\n    ) -> None:\n        \"\"\"Creates a stim.GateTargetWithCoords.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n            >>> t.gate_target\n            stim.GateTarget(0)\n            >>> t.coords\n            [1.5, 2.0]\n        \"\"\"\n    @property\n    def coords(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns the associated coordinate information as a list of floats.\n\n        If there is no coordinate information, returns an empty list.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n            >>> t.coords\n            [1.5, 2.0]\n        \"\"\"\n    @property\n    def gate_target(\n        self,\n    ) -> stim.GateTarget:\n        \"\"\"Returns the actual gate target as a `stim.GateTarget`.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n            >>> t.gate_target\n            stim.GateTarget(0)\n        \"\"\"\nclass PauliString:\n    \"\"\"A signed Pauli tensor product (e.g. \"+X \\u2297 X \\u2297 X\" or \"-Y \\u2297 Z\".\n\n    Represents a collection of Pauli operations (I, X, Y, Z) applied pairwise to a\n    collection of qubits.\n\n    Examples:\n        >>> import stim\n        >>> stim.PauliString(\"XX\") * stim.PauliString(\"YY\")\n        stim.PauliString(\"-ZZ\")\n        >>> print(stim.PauliString(5))\n        +_____\n    \"\"\"\n    def __add__(\n        self,\n        rhs: stim.PauliString,\n    ) -> stim.PauliString:\n        \"\"\"Returns the tensor product of two Pauli strings.\n\n        Concatenates the Pauli strings and multiplies their signs.\n\n        Args:\n            rhs: A second stim.PauliString.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.PauliString(\"X\") + stim.PauliString(\"YZ\")\n            stim.PauliString(\"+XYZ\")\n\n            >>> stim.PauliString(\"iX\") + stim.PauliString(\"-X\")\n            stim.PauliString(\"-iXX\")\n\n        Returns:\n            The tensor product.\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.PauliString,\n    ) -> bool:\n        \"\"\"Determines if two Pauli strings have identical contents.\n        \"\"\"\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: int,\n    ) -> int:\n        pass\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: slice,\n    ) -> stim.PauliString:\n        pass\n    def __getitem__(\n        self,\n        index_or_slice: object,\n    ) -> object:\n        \"\"\"Returns an individual Pauli or Pauli string slice from the pauli string.\n\n        Individual Paulis are returned as an int using the encoding 0=I, 1=X, 2=Y, 3=Z.\n        Slices are returned as a stim.PauliString (always with positive sign).\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(\"_XYZ\")\n            >>> p[2]\n            2\n            >>> p[-1]\n            3\n            >>> p[:2]\n            stim.PauliString(\"+_X\")\n            >>> p[::-1]\n            stim.PauliString(\"+ZYX_\")\n\n        Args:\n            index_or_slice: The index of the pauli to return, or the slice of paulis to\n                return.\n\n        Returns:\n            0: Identity.\n            1: Pauli X.\n            2: Pauli Y.\n            3: Pauli Z.\n        \"\"\"\n    def __iadd__(\n        self,\n        rhs: stim.PauliString,\n    ) -> stim.PauliString:\n        \"\"\"Performs an inplace tensor product.\n\n        Concatenates the given Pauli string onto the receiving string and multiplies\n        their signs.\n\n        Args:\n            rhs: A second stim.PauliString.\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.PauliString(\"iX\")\n            >>> alias = p\n            >>> p += stim.PauliString(\"-YY\")\n            >>> p\n            stim.PauliString(\"-iXYY\")\n            >>> alias is p\n            True\n\n        Returns:\n            The mutated pauli string.\n        \"\"\"\n    def __imul__(\n        self,\n        rhs: object,\n    ) -> stim.PauliString:\n        \"\"\"Inplace right-multiplies the Pauli string.\n\n        Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n        Args:\n            rhs: The right hand side of the multiplication. This can be:\n                - A stim.PauliString to right-multiply term-by-term into the paulis of\n                    the pauli string.\n                - A complex unit (1, -1, 1j, -1j) to multiply into the sign of the pauli\n                    string.\n                - A non-negative integer indicating the tensor power to raise the pauli\n                    string to (how many times to repeat it).\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.PauliString(\"X\")\n            >>> p *= 1j\n            >>> p\n            stim.PauliString(\"+iX\")\n\n            >>> p = stim.PauliString(\"iXY_\")\n            >>> p *= 3\n            >>> p\n            stim.PauliString(\"-iXY_XY_XY_\")\n\n            >>> p = stim.PauliString(\"X\")\n            >>> alias = p\n            >>> p *= stim.PauliString(\"Y\")\n            >>> alias\n            stim.PauliString(\"+iZ\")\n\n            >>> p = stim.PauliString(\"X\")\n            >>> p *= stim.PauliString(\"_YY\")\n            >>> p\n            stim.PauliString(\"+XYY\")\n\n        Returns:\n            The mutated Pauli string.\n        \"\"\"\n    def __init__(\n        self,\n        arg: Union[None, int, str, stim.PauliString, Iterable[Union[int, Literal[\"_\", \"I\", \"X\", \"Y\", \"Z\"]]]] = None,\n        /,\n    ) -> None:\n        \"\"\"Initializes a stim.PauliString from the given argument.\n\n        When given a string, the string is parsed as a pauli string. The string can\n        optionally start with a sign ('+', '-', 'i', '+i', or '-i'). The rest of the\n        string should be either a dense pauli string or a sparse pauli string. A dense\n        pauli string is made up of characters from '_IXYZ' where '_' and 'I' mean\n        identity, 'X' means Pauli X, 'Y' means Pauli Y, and 'Z' means Pauli Z. A sparse\n        pauli string is a series of integers seperated by '*' and prefixed by 'I', 'X',\n        'Y', or 'Z'.\n\n        Args:\n            arg [position-only]: This can be a variety of types, including:\n                None (default): initializes an empty Pauli string.\n                int: initializes an identity Pauli string of the given length.\n                str: initializes by parsing the given text.\n                stim.PauliString: initializes a copy of the given Pauli string.\n                Iterable: initializes by interpreting each item as a Pauli.\n                    Each item can be a single-qubit Pauli string (like \"X\"),\n                    or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n                Dict[int, Union[int, str]]: initializes by interpreting keys as\n                    the qubit index and values as the Pauli for that index.\n                    Each value can be a single-qubit Pauli string (like \"X\"),\n                    or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n                Dict[Union[int, str], Iterable[int]]: initializes by interpreting keys\n                    as Pauli operators and values as the qubit indices for that Pauli.\n                    Each key can be a single-qubit Pauli string (like \"X\"),\n                    or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.PauliString(\"-XYZ\")\n            stim.PauliString(\"-XYZ\")\n\n            >>> stim.PauliString()\n            stim.PauliString(\"+\")\n\n            >>> stim.PauliString(5)\n            stim.PauliString(\"+_____\")\n\n            >>> stim.PauliString(stim.PauliString(\"XX\"))\n            stim.PauliString(\"+XX\")\n\n            >>> stim.PauliString([0, 1, 3, 2])\n            stim.PauliString(\"+_XZY\")\n\n            >>> stim.PauliString(\"X\" for _ in range(4))\n            stim.PauliString(\"+XXXX\")\n\n            >>> stim.PauliString(\"-X2*Y6\")\n            stim.PauliString(\"-__X___Y\")\n\n            >>> stim.PauliString(\"X6*Y6\")\n            stim.PauliString(\"+i______Z\")\n\n            >>> stim.PauliString({0: \"X\", 2: \"Y\", 3: \"X\"})\n            stim.PauliString(\"+X_YX\")\n\n            >>> stim.PauliString({0: \"X\", 2: 2, 3: 1})\n            stim.PauliString(\"+X_YX\")\n\n            >>> stim.PauliString({\"X\": [1], 2: [4], \"Z\": [0, 3]})\n            stim.PauliString(\"+ZX_ZY\")\n        \"\"\"\n    def __itruediv__(\n        self,\n        rhs: complex,\n    ) -> stim.PauliString:\n        \"\"\"Inplace divides the Pauli string by a complex unit.\n\n        Args:\n            rhs: The divisor. Can be 1, -1, 1j, or -1j.\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.PauliString(\"X\")\n            >>> p /= 1j\n            >>> p\n            stim.PauliString(\"-iX\")\n\n        Returns:\n            The mutated Pauli string.\n\n        Raises:\n            ValueError: The divisor isn't 1, -1, 1j, or -1j.\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the length the pauli string; the number of qubits it operates on.\n\n        Examples:\n            >>> import stim\n            >>> len(stim.PauliString(\"XY_ZZ\"))\n            5\n            >>> len(stim.PauliString(\"X0*Z99\"))\n            100\n        \"\"\"\n    def __mul__(\n        self,\n        rhs: object,\n    ) -> stim.PauliString:\n        \"\"\"Right-multiplies the Pauli string.\n\n        Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n        Args:\n            rhs: The right hand side of the multiplication. This can be:\n                - A stim.PauliString to right-multiply term-by-term with the paulis of\n                    the pauli string.\n                - A complex unit (1, -1, 1j, -1j) to multiply with the sign of the pauli\n                    string.\n                - A non-negative integer indicating the tensor power to raise the pauli\n                    string to (how many times to repeat it).\n\n        Examples:\n            >>> import stim\n\n            >>> stim.PauliString(\"X\") * 1\n            stim.PauliString(\"+X\")\n            >>> stim.PauliString(\"X\") * -1\n            stim.PauliString(\"-X\")\n            >>> stim.PauliString(\"X\") * 1j\n            stim.PauliString(\"+iX\")\n\n            >>> stim.PauliString(\"X\") * 2\n            stim.PauliString(\"+XX\")\n            >>> stim.PauliString(\"-X\") * 2\n            stim.PauliString(\"+XX\")\n            >>> stim.PauliString(\"iX\") * 2\n            stim.PauliString(\"-XX\")\n            >>> stim.PauliString(\"X\") * 3\n            stim.PauliString(\"+XXX\")\n            >>> stim.PauliString(\"iX\") * 3\n            stim.PauliString(\"-iXXX\")\n\n            >>> stim.PauliString(\"X\") * stim.PauliString(\"Y\")\n            stim.PauliString(\"+iZ\")\n            >>> stim.PauliString(\"X\") * stim.PauliString(\"XX_\")\n            stim.PauliString(\"+_X_\")\n            >>> stim.PauliString(\"XXXX\") * stim.PauliString(\"_XYZ\")\n            stim.PauliString(\"+X_ZY\")\n\n        Returns:\n            The product or tensor power.\n\n        Raises:\n            TypeError: The right hand side isn't a stim.PauliString, a non-negative\n                integer, or a complex unit (1, -1, 1j, or -1j).\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.PauliString,\n    ) -> bool:\n        \"\"\"Determines if two Pauli strings have non-identical contents.\n        \"\"\"\n    def __neg__(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns the negation of the pauli string.\n\n        Examples:\n            >>> import stim\n            >>> -stim.PauliString(\"X\")\n            stim.PauliString(\"-X\")\n            >>> -stim.PauliString(\"-Y\")\n            stim.PauliString(\"+Y\")\n            >>> -stim.PauliString(\"iZZZ\")\n            stim.PauliString(\"-iZZZ\")\n        \"\"\"\n    def __pos__(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns a pauli string with the same contents.\n\n        Examples:\n            >>> import stim\n            >>> +stim.PauliString(\"+X\")\n            stim.PauliString(\"+X\")\n            >>> +stim.PauliString(\"-YY\")\n            stim.PauliString(\"-YY\")\n            >>> +stim.PauliString(\"iZZZ\")\n            stim.PauliString(\"+iZZZ\")\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.PauliString`.\n        \"\"\"\n    def __rmul__(\n        self,\n        lhs: object,\n    ) -> stim.PauliString:\n        \"\"\"Left-multiplies the Pauli string.\n\n        Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n        Args:\n            lhs: The left hand side of the multiplication. This can be:\n                - A stim.PauliString to right-multiply term-by-term with the paulis of\n                    the pauli string.\n                - A complex unit (1, -1, 1j, -1j) to multiply with the sign of the pauli\n                    string.\n                - A non-negative integer indicating the tensor power to raise the pauli\n                    string to (how many times to repeat it).\n\n        Examples:\n            >>> import stim\n\n            >>> 1 * stim.PauliString(\"X\")\n            stim.PauliString(\"+X\")\n            >>> -1 * stim.PauliString(\"X\")\n            stim.PauliString(\"-X\")\n            >>> 1j * stim.PauliString(\"X\")\n            stim.PauliString(\"+iX\")\n\n            >>> 2 * stim.PauliString(\"X\")\n            stim.PauliString(\"+XX\")\n            >>> 2 * stim.PauliString(\"-X\")\n            stim.PauliString(\"+XX\")\n            >>> 2 * stim.PauliString(\"iX\")\n            stim.PauliString(\"-XX\")\n            >>> 3 * stim.PauliString(\"X\")\n            stim.PauliString(\"+XXX\")\n            >>> 3 * stim.PauliString(\"iX\")\n            stim.PauliString(\"-iXXX\")\n\n            >>> stim.PauliString(\"X\") * stim.PauliString(\"Y\")\n            stim.PauliString(\"+iZ\")\n            >>> stim.PauliString(\"X\") * stim.PauliString(\"XX_\")\n            stim.PauliString(\"+_X_\")\n            >>> stim.PauliString(\"XXXX\") * stim.PauliString(\"_XYZ\")\n            stim.PauliString(\"+X_ZY\")\n\n        Returns:\n            The product.\n\n        Raises:\n            ValueError: The scalar phase factor isn't 1, -1, 1j, or -1j.\n        \"\"\"\n    def __setitem__(\n        self,\n        index: int,\n        new_pauli: object,\n    ) -> None:\n        \"\"\"Mutates an entry in the pauli string using the encoding 0=I, 1=X, 2=Y, 3=Z.\n\n        Args:\n            index: The index of the pauli to overwrite.\n            new_pauli: Either a character from '_IXYZ' or an integer from range(4).\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(4)\n            >>> p[2] = 1\n            >>> print(p)\n            +__X_\n            >>> p[0] = 3\n            >>> p[1] = 2\n            >>> p[3] = 0\n            >>> print(p)\n            +ZYX_\n            >>> p[0] = 'I'\n            >>> p[1] = 'X'\n            >>> p[2] = 'Y'\n            >>> p[3] = 'Z'\n            >>> print(p)\n            +_XYZ\n            >>> p[-1] = 'Y'\n            >>> print(p)\n            +_XYY\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a text description.\n        \"\"\"\n    def __truediv__(\n        self,\n        rhs: complex,\n    ) -> stim.PauliString:\n        \"\"\"Divides the Pauli string by a complex unit.\n\n        Args:\n            rhs: The divisor. Can be 1, -1, 1j, or -1j.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.PauliString(\"X\") / 1j\n            stim.PauliString(\"-iX\")\n\n        Returns:\n            The quotient.\n\n        Raises:\n            ValueError: The divisor isn't 1, -1, 1j, or -1j.\n        \"\"\"\n    @overload\n    def after(\n        self,\n        operation: Union[stim.Circuit, stim.CircuitInstruction],\n    ) -> stim.PauliString:\n        pass\n    @overload\n    def after(\n        self,\n        operation: stim.Tableau,\n        targets: Iterable[int],\n    ) -> stim.PauliString:\n        pass\n    def after(\n        self,\n        operation: Union[stim.Circuit, stim.Tableau, stim.CircuitInstruction],\n        targets: Optional[Iterable[int]] = None,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating the Pauli string by an operation.\n\n        Args:\n            operation: A circuit, tableau, or circuit instruction to\n                conjugate the Pauli string by. Must be Clifford (e.g.\n                if it's a circuit, the circuit can't have noise or\n                measurements).\n            targets: Required if and only if the operation is a tableau.\n                Specifies which qubits to target.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(\"_XYZ\")\n\n            >>> p.after(stim.CircuitInstruction(\"H\", [1]))\n            stim.PauliString(\"+_ZYZ\")\n\n            >>> p.after(stim.Circuit('''\n            ...     C_XYZ 1 2 3\n            ... '''))\n            stim.PauliString(\"+_YZX\")\n\n            >>> p.after(stim.Tableau.from_named_gate('CZ'), targets=[0, 1])\n            stim.PauliString(\"+ZXYZ\")\n\n        Returns:\n            The conjugated Pauli string. The Pauli string after the\n            operation that is exactly equivalent to the given Pauli\n            string before the operation.\n        \"\"\"\n    @overload\n    def before(\n        self,\n        operation: Union[stim.Circuit, stim.CircuitInstruction],\n    ) -> stim.PauliString:\n        pass\n    @overload\n    def before(\n        self,\n        operation: stim.Tableau,\n        targets: Iterable[int],\n    ) -> stim.PauliString:\n        pass\n    def before(\n        self,\n        operation: Union[stim.Circuit, stim.Tableau, stim.CircuitInstruction],\n        targets: Optional[Iterable[int]] = None,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating the Pauli string by an operation.\n\n        Args:\n            operation: A circuit, tableau, or circuit instruction to\n                anti-conjugate the Pauli string by. Must be Clifford (e.g.\n                if it's a circuit, the circuit can't have noise or\n                measurements).\n            targets: Required if and only if the operation is a tableau.\n                Specifies which qubits to target.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(\"_XYZ\")\n\n            >>> p.before(stim.CircuitInstruction(\"H\", [1]))\n            stim.PauliString(\"+_ZYZ\")\n\n            >>> p.before(stim.Circuit('''\n            ...     C_XYZ 1 2 3\n            ... '''))\n            stim.PauliString(\"+_ZXY\")\n\n            >>> p.before(stim.Tableau.from_named_gate('CZ'), targets=[0, 1])\n            stim.PauliString(\"+ZXYZ\")\n\n        Returns:\n            The conjugated Pauli string. The Pauli string before the\n            operation that is exactly equivalent to the given Pauli\n            string after the operation.\n        \"\"\"\n    def commutes(\n        self,\n        other: stim.PauliString,\n    ) -> bool:\n        \"\"\"Determines if two Pauli strings commute or not.\n\n        Two Pauli strings commute if they have an even number of matched\n        non-equal non-identity Pauli terms. Otherwise they anticommute.\n\n        Args:\n            other: The other Pauli string.\n\n        Examples:\n            >>> import stim\n            >>> xx = stim.PauliString(\"XX\")\n            >>> xx.commutes(stim.PauliString(\"X_\"))\n            True\n            >>> xx.commutes(stim.PauliString(\"XX\"))\n            True\n            >>> xx.commutes(stim.PauliString(\"XY\"))\n            False\n            >>> xx.commutes(stim.PauliString(\"XZ\"))\n            False\n            >>> xx.commutes(stim.PauliString(\"ZZ\"))\n            True\n            >>> xx.commutes(stim.PauliString(\"X_Y__\"))\n            True\n            >>> xx.commutes(stim.PauliString(\"\"))\n            True\n\n        Returns:\n            True if the Pauli strings commute, False if they anti-commute.\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns a copy of the pauli string.\n\n        The copy is an independent pauli string with the same contents.\n\n        Examples:\n            >>> import stim\n            >>> p1 = stim.PauliString.random(2)\n            >>> p2 = p1.copy()\n            >>> p2 is p1\n            False\n            >>> p2 == p1\n            True\n        \"\"\"\n    def extended_product(\n        self,\n        other: stim.PauliString,\n    ) -> Tuple[complex, stim.PauliString]:\n        \"\"\"[DEPRECATED] Use multiplication (__mul__ or *) instead.\n        \"\"\"\n    @staticmethod\n    def from_numpy(\n        *,\n        xs: np.ndarray,\n        zs: np.ndarray,\n        sign: Union[int, float, complex] = +1,\n        num_qubits: Optional[int] = None,\n    ) -> stim.PauliString:\n        \"\"\"Creates a pauli string from X bit and Z bit numpy arrays, using the encoding:\n\n            x=0 and z=0 -> P=I\n            x=1 and z=0 -> P=X\n            x=1 and z=1 -> P=Y\n            x=0 and z=1 -> P=Z\n\n        Args:\n            xs: The X bits of the pauli string. This array can either be a 1-dimensional\n                numpy array with dtype=np.bool_, or a bit packed 1-dimensional numpy\n                array with dtype=np.uint8. If the dtype is np.uint8 then the array is\n                assumed to be bit packed in little endian order and the \"num_qubits\"\n                argument must be specified. When bit packed, the x bit with offset k is\n                stored at (xs[k // 8] >> (k % 8)) & 1.\n            zs: The Z bits of the pauli string. This array can either be a 1-dimensional\n                numpy array with dtype=np.bool_, or a bit packed 1-dimensional numpy\n                array with dtype=np.uint8. If the dtype is np.uint8 then the array is\n                assumed to be bit packed in little endian order and the \"num_qubits\"\n                argument must be specified. When bit packed, the x bit with offset k is\n                stored at (xs[k // 8] >> (k % 8)) & 1.\n            sign: Defaults to +1. Set to +1, -1, 1j, or -1j to control the sign of the\n                returned Pauli string.\n            num_qubits: Must be specified if xs or zs is a bit packed array. Specifies\n                the expected length of the Pauli string.\n\n        Returns:\n            The created pauli string.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n\n            >>> xs = np.array([1, 1, 1, 1, 1, 1, 1, 0, 0], dtype=np.bool_)\n            >>> zs = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1], dtype=np.bool_)\n            >>> stim.PauliString.from_numpy(xs=xs, zs=zs, sign=-1)\n            stim.PauliString(\"-XXXXYYYZZ\")\n\n            >>> xs = np.array([127, 0], dtype=np.uint8)\n            >>> zs = np.array([240, 1], dtype=np.uint8)\n            >>> stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=9)\n            stim.PauliString(\"+XXXXYYYZZ\")\n        \"\"\"\n    @staticmethod\n    def from_unitary_matrix(\n        matrix: Iterable[Iterable[Union[int, float, complex]]],\n        *,\n        endian: Literal[\"little\", \"big\"] = 'little',\n        unsigned: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Creates a stim.PauliString from the unitary matrix of a Pauli group member.\n\n        Args:\n            matrix: A unitary matrix specified as an iterable of rows, with each row is\n                an iterable of amplitudes. The unitary matrix must correspond to a\n                Pauli string, including global phase.\n            endian:\n                \"little\": matrix entries are in little endian order, where higher index\n                    qubits correspond to larger changes in row/col indices.\n                \"big\": matrix entries are in big endian order, where higher index\n                    qubits correspond to smaller changes in row/col indices.\n            unsigned: When False, the input must only contain the values\n                [0, 1, -1, 1j, -1j] and the output will have the correct global phase.\n                When True, the input is permitted to be scaled by an arbitrary unit\n                complex value and the output will always have positive sign.\n                False is stricter but provides more information, while True is more\n                flexible but provides less information.\n\n        Returns:\n            The pauli string equal to the given unitary matrix.\n\n        Raises:\n            ValueError: The given matrix isn't the unitary matrix of a Pauli string.\n\n        Examples:\n            >>> import stim\n            >>> stim.PauliString.from_unitary_matrix([\n            ...     [1j, 0],\n            ...     [0, -1j],\n            ... ], endian='little')\n            stim.PauliString(\"+iZ\")\n\n            >>> stim.PauliString.from_unitary_matrix([\n            ...     [1j**0.1, 0],\n            ...     [0, -(1j**0.1)],\n            ... ], endian='little', unsigned=True)\n            stim.PauliString(\"+Z\")\n\n            >>> stim.PauliString.from_unitary_matrix([\n            ...     [0, 1, 0, 0],\n            ...     [1, 0, 0, 0],\n            ...     [0, 0, 0, -1],\n            ...     [0, 0, -1, 0],\n            ... ], endian='little')\n            stim.PauliString(\"+XZ\")\n        \"\"\"\n    @staticmethod\n    def iter_all(\n        num_qubits: int,\n        *,\n        min_weight: int = 0,\n        max_weight: object = None,\n        allowed_paulis: str = 'XYZ',\n    ) -> stim.PauliStringIterator:\n        \"\"\"Returns an iterator that iterates over all matching pauli strings.\n\n        Args:\n            num_qubits: The desired number of qubits in the pauli strings.\n            min_weight: Defaults to 0. The minimum number of non-identity terms that\n                must be present in each yielded pauli string.\n            max_weight: Defaults to None (unused). The maximum number of non-identity\n                terms that must be present in each yielded pauli string.\n            allowed_paulis: Defaults to \"XYZ\". Set this to a string containing the\n                non-identity paulis that are allowed to appear in each yielded pauli\n                string. This argument must be a string made up of only \"X\", \"Y\", and\n                \"Z\" characters. A non-identity Pauli is allowed if it appears in the\n                string, and not allowed if it doesn't. Identity Paulis are always\n                allowed.\n\n        Returns:\n            An Iterable[stim.PauliString] that yields the requested pauli strings.\n\n        Examples:\n            >>> import stim\n            >>> pauli_string_iterator = stim.PauliString.iter_all(\n            ...     num_qubits=3,\n            ...     min_weight=1,\n            ...     max_weight=2,\n            ...     allowed_paulis=\"XZ\",\n            ... )\n            >>> for p in pauli_string_iterator:\n            ...     print(p)\n            +X__\n            +Z__\n            +_X_\n            +_Z_\n            +__X\n            +__Z\n            +XX_\n            +XZ_\n            +ZX_\n            +ZZ_\n            +X_X\n            +X_Z\n            +Z_X\n            +Z_Z\n            +_XX\n            +_XZ\n            +_ZX\n            +_ZZ\n        \"\"\"\n    def pauli_indices(\n        self,\n        included_paulis: str = \"XYZ\",\n    ) -> List[int]:\n        \"\"\"Returns the indices of non-identity Paulis, or of specified Paulis.\n\n        Args:\n            include: A string containing the Pauli types to include.\n                X type Pauli indices are included if \"X\" or \"x\" is in the string.\n                Y type Pauli indices are included if \"Y\" or \"y\" is in the string.\n                Z type Pauli indices are included if \"Z\" or \"z\" is in the string.\n                I type Pauli indices are included if \"I\" or \"_\" is in the string.\n                An exception is thrown if other characters are in the string.\n\n        Returns:\n            A list containing the ascending indices of matching Pauli terms.\n\n        Examples:\n            >>> import stim\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices()\n            [5, 9, 14]\n\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"XZ\")\n            [5, 14]\n\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"X\")\n            [5]\n\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"Y\")\n            [9]\n\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"IY\")\n            [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17]\n\n            >>> stim.PauliString(\"-X103*Y100\").pauli_indices()\n            [100, 103]\n        \"\"\"\n    @staticmethod\n    def random(\n        num_qubits: int,\n        *,\n        allow_imaginary: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Samples a uniformly random Hermitian Pauli string.\n\n        Args:\n            num_qubits: The number of qubits the Pauli string should act on.\n            allow_imaginary: Defaults to False. If True, the sign of the result may be\n                1j or -1j in addition to +1 or -1. In other words, setting this to True\n                allows the result to be non-Hermitian.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString.random(5)\n            >>> len(p)\n            5\n            >>> p.sign in [-1, +1]\n            True\n\n            >>> p2 = stim.PauliString.random(3, allow_imaginary=True)\n            >>> len(p2)\n            3\n            >>> p2.sign in [-1, +1, 1j, -1j]\n            True\n\n        Returns:\n            The sampled Pauli string.\n        \"\"\"\n    @property\n    def sign(\n        self,\n    ) -> complex:\n        \"\"\"The sign of the Pauli string. Can be +1, -1, 1j, or -1j.\n\n        Examples:\n            >>> import stim\n            >>> stim.PauliString(\"X\").sign\n            (1+0j)\n            >>> stim.PauliString(\"-X\").sign\n            (-1+0j)\n            >>> stim.PauliString(\"iX\").sign\n            1j\n            >>> stim.PauliString(\"-iX\").sign\n            (-0-1j)\n        \"\"\"\n    @sign.setter\n    def sign(self, value: complex):\n        pass\n    def to_numpy(\n        self,\n        *,\n        bit_packed: bool = False,\n    ) -> Tuple[np.ndarray, np.ndarray]:\n        \"\"\"Decomposes the contents of the pauli string into X bit and Z bit numpy arrays.\n\n        Args:\n            bit_packed: Defaults to False. Determines whether the output numpy arrays\n                use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n        Returns:\n            An (xs, zs) tuple encoding the paulis from the string. The k'th Pauli from\n            the string is encoded into k'th bit of xs and the k'th bit of zs using\n            the \"xz\" encoding:\n\n                P=I -> x=0 and z=0\n                P=X -> x=1 and z=0\n                P=Y -> x=1 and z=1\n                P=Z -> x=0 and z=1\n\n            The dtype and shape of the result depends on the bit_packed argument.\n\n            If bit_packed=False:\n                Each bit gets its own byte.\n                xs.dtype = zs.dtype = np.bool_\n                xs.shape = zs.shape = len(self)\n                xs_k = xs[k]\n                zs_k = zs[k]\n\n            If bit_packed=True:\n                Equivalent to applying np.packbits(bitorder='little') to the result.\n                xs.dtype = zs.dtype = np.uint8\n                xs.shape = zs.shape = math.ceil(len(self) / 8)\n                xs_k = (xs[k // 8] >> (k % 8)) & 1\n                zs_k = (zs[k // 8] >> (k % 8)) & 1\n\n        Examples:\n            >>> import stim\n\n            >>> xs, zs = stim.PauliString(\"XXXXYYYZZ\").to_numpy()\n            >>> xs\n            array([ True,  True,  True,  True,  True,  True,  True, False, False])\n            >>> zs\n            array([False, False, False, False,  True,  True,  True,  True,  True])\n\n            >>> xs, zs = stim.PauliString(\"XXXXYYYZZ\").to_numpy(bit_packed=True)\n            >>> xs\n            array([127,   0], dtype=uint8)\n            >>> zs\n            array([240,   1], dtype=uint8)\n        \"\"\"\n    def to_tableau(\n        self,\n    ) -> stim.Tableau:\n        \"\"\"Creates a Tableau equivalent to this Pauli string.\n\n        The tableau represents a Clifford operation that multiplies qubits\n        by the corresponding Pauli operations from this Pauli string.\n        The global phase of the pauli operation is lost in the conversion.\n\n        Returns:\n            The created tableau.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(\"ZZ\")\n            >>> p.to_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"-X_\"),\n                    stim.PauliString(\"-_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_Z\"),\n                ],\n            )\n            >>> q = stim.PauliString(\"YX_Z\")\n            >>> q.to_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"-X___\"),\n                    stim.PauliString(\"+_X__\"),\n                    stim.PauliString(\"+__X_\"),\n                    stim.PauliString(\"-___X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"-Z___\"),\n                    stim.PauliString(\"-_Z__\"),\n                    stim.PauliString(\"+__Z_\"),\n                    stim.PauliString(\"+___Z\"),\n                ],\n            )\n        \"\"\"\n    def to_unitary_matrix(\n        self,\n        *,\n        endian: Literal[\"little\", \"big\"],\n    ) -> np.ndarray[np.complex64]:\n        \"\"\"Converts the pauli string into a unitary matrix.\n\n        Args:\n            endian:\n                \"little\": The first qubit is the least significant (corresponds\n                    to an offset of 1 in the matrix).\n                \"big\": The first qubit is the most significant (corresponds\n                    to an offset of 2**(n - 1) in the matrix).\n\n        Returns:\n            A numpy array with dtype=np.complex64 and\n            shape=(1 << len(pauli_string), 1 << len(pauli_string)).\n\n        Example:\n            >>> import stim\n            >>> stim.PauliString(\"-YZ\").to_unitary_matrix(endian=\"little\")\n            array([[0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j],\n                   [0.-1.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j],\n                   [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j]], dtype=complex64)\n        \"\"\"\n    @property\n    def weight(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of non-identity pauli terms in the pauli string.\n\n        Examples:\n            >>> import stim\n            >>> stim.PauliString(\"+___\").weight\n            0\n            >>> stim.PauliString(\"+__X\").weight\n            1\n            >>> stim.PauliString(\"+XYZ\").weight\n            3\n            >>> stim.PauliString(\"-XXX___XXYZ\").weight\n            7\n        \"\"\"\nclass PauliStringIterator:\n    \"\"\"Iterates over all pauli strings matching specified patterns.\n\n    Examples:\n        >>> import stim\n        >>> pauli_string_iterator = stim.PauliString.iter_all(\n        ...     2,\n        ...     min_weight=1,\n        ...     max_weight=1,\n        ...     allowed_paulis=\"XZ\",\n        ... )\n        >>> for p in pauli_string_iterator:\n        ...     print(p)\n        +X_\n        +Z_\n        +_X\n        +_Z\n    \"\"\"\n    def __iter__(\n        self,\n    ) -> stim.PauliStringIterator:\n        \"\"\"Returns an independent copy of the pauli string iterator.\n\n        Since for-loops and loop-comprehensions call `iter` on things they\n        iterate, this effectively allows the iterator to be iterated\n        multiple times.\n        \"\"\"\n    def __next__(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns the next iterated pauli string.\n        \"\"\"\nclass Tableau:\n    \"\"\"A stabilizer tableau.\n\n    Represents a Clifford operation by explicitly storing how that operation\n    conjugates a list of Pauli group generators into composite Pauli products.\n\n    Examples:\n        >>> import stim\n        >>> stim.Tableau.from_named_gate(\"H\")\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X\"),\n            ],\n        )\n\n        >>> t = stim.Tableau.random(5)\n        >>> t_inv = t**-1\n        >>> print(t * t_inv)\n        +-xz-xz-xz-xz-xz-\n        | ++ ++ ++ ++ ++\n        | XZ __ __ __ __\n        | __ XZ __ __ __\n        | __ __ XZ __ __\n        | __ __ __ XZ __\n        | __ __ __ __ XZ\n\n        >>> x2z3 = t.x_output(2) * t.z_output(3)\n        >>> t_inv(x2z3)\n        stim.PauliString(\"+__XZ_\")\n    \"\"\"\n    def __add__(\n        self,\n        rhs: stim.Tableau,\n    ) -> stim.Tableau:\n        \"\"\"Returns the direct sum (diagonal concatenation) of two Tableaus.\n\n        Args:\n            rhs: A second stim.Tableau.\n\n        Examples:\n            >>> import stim\n\n            >>> s = stim.Tableau.from_named_gate(\"S\")\n            >>> cz = stim.Tableau.from_named_gate(\"CZ\")\n            >>> print(s + cz)\n            +-xz-xz-xz-\n            | ++ ++ ++\n            | YZ __ __\n            | __ XZ Z_\n            | __ Z_ XZ\n\n        Returns:\n            The direct sum.\n        \"\"\"\n    def __call__(\n        self,\n        pauli_string: stim.PauliString,\n    ) -> stim.PauliString:\n        \"\"\"Returns the equivalent PauliString after the Tableau's Clifford operation.\n\n        If P is a Pauli product before a Clifford operation C, then this method returns\n        Q = C * P * C**-1 (the conjugation of P by C). Q is the equivalent Pauli product\n        after C. This works because:\n\n            C*P\n            = C*P * I\n            = C*P * (C**-1 * C)\n            = (C*P*C**-1) * C\n            = Q*C\n\n        (Keep in mind that A*B means first B is applied, then A is applied.)\n\n        Args:\n            pauli_string: The pauli string to conjugate.\n\n        Returns:\n            The new conjugated pauli string.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> p = stim.PauliString(\"XX\")\n            >>> result = t(p)\n            >>> print(result)\n            +X_\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.Tableau,\n    ) -> bool:\n        \"\"\"Determines if two tableaus have identical contents.\n        \"\"\"\n    def __iadd__(\n        self,\n        rhs: stim.Tableau,\n    ) -> stim.Tableau:\n        \"\"\"Performs an inplace direct sum (diagonal concatenation).\n\n        Args:\n            rhs: A second stim.Tableau.\n\n        Examples:\n            >>> import stim\n\n            >>> s = stim.Tableau.from_named_gate(\"S\")\n            >>> cz = stim.Tableau.from_named_gate(\"CZ\")\n            >>> alias = s\n            >>> s += cz\n            >>> alias is s\n            True\n            >>> print(s)\n            +-xz-xz-xz-\n            | ++ ++ ++\n            | YZ __ __\n            | __ XZ Z_\n            | __ Z_ XZ\n\n        Returns:\n            The mutated tableau.\n        \"\"\"\n    def __init__(\n        self,\n        num_qubits: int,\n    ) -> None:\n        \"\"\"Creates an identity tableau over the given number of qubits.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau(3)\n            >>> print(t)\n            +-xz-xz-xz-\n            | ++ ++ ++\n            | XZ __ __\n            | __ XZ __\n            | __ __ XZ\n\n        Args:\n            num_qubits: The number of qubits the tableau's operation acts on.\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of qubits operated on by the tableau.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> len(t)\n            2\n        \"\"\"\n    def __mul__(\n        self,\n        rhs: stim.Tableau,\n    ) -> stim.Tableau:\n        \"\"\"Returns the product of two tableaus.\n\n        If the tableau T1 represents the Clifford operation with unitary C1,\n        and the tableau T2 represents the Clifford operation with unitary C2,\n        then the tableau T1*T2 represents the Clifford operation with unitary C1*C2.\n\n        Args:\n            rhs: The tableau  on the right hand side of the multiplication.\n\n        Examples:\n            >>> import stim\n            >>> t1 = stim.Tableau.random(4)\n            >>> t2 = stim.Tableau.random(4)\n            >>> t3 = t2 * t1\n            >>> p = stim.PauliString.random(4)\n            >>> t3(p) == t2(t1(p))\n            True\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.Tableau,\n    ) -> bool:\n        \"\"\"Determines if two tableaus have non-identical contents.\n        \"\"\"\n    def __pow__(\n        self,\n        exponent: int,\n    ) -> stim.Tableau:\n        \"\"\"Raises the tableau to an integer power.\n\n        Large powers are reached efficiently using repeated squaring.\n        Negative powers are reached by inverting the tableau.\n\n        Args:\n            exponent: The power to raise to. Can be negative, zero, or positive.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.Tableau.from_named_gate(\"S\")\n            >>> s**0 == stim.Tableau(1)\n            True\n            >>> s**1 == s\n            True\n            >>> s**2 == stim.Tableau.from_named_gate(\"Z\")\n            True\n            >>> s**-1 == s**3 == stim.Tableau.from_named_gate(\"S_DAG\")\n            True\n            >>> s**5 == s\n            True\n            >>> s**(400000000 + 1) == s\n            True\n            >>> s**(-400000000 + 1) == s\n            True\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equal `stim.Tableau`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a text description.\n        \"\"\"\n    def append(\n        self,\n        gate: stim.Tableau,\n        targets: Sequence[int],\n    ) -> None:\n        \"\"\"Appends an operation's effect into this tableau, mutating this tableau.\n\n        Time cost is O(n*m*m) where n=len(self) and m=len(gate).\n\n        Args:\n            gate: The tableau of the operation being appended into this tableau.\n            targets: The qubits being targeted by the gate.\n\n        Examples:\n            >>> import stim\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> t = stim.Tableau(2)\n            >>> t.append(cnot, [0, 1])\n            >>> t.append(cnot, [1, 0])\n            >>> t.append(cnot, [0, 1])\n            >>> t == stim.Tableau.from_named_gate(\"SWAP\")\n            True\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.Tableau:\n        \"\"\"Returns a copy of the tableau. An independent tableau with the same contents.\n\n        Examples:\n            >>> import stim\n            >>> t1 = stim.Tableau.random(2)\n            >>> t2 = t1.copy()\n            >>> t2 is t1\n            False\n            >>> t2 == t1\n            True\n        \"\"\"\n    @staticmethod\n    def from_circuit(\n        circuit: stim.Circuit,\n        *,\n        ignore_noise: bool = False,\n        ignore_measurement: bool = False,\n        ignore_reset: bool = False,\n    ) -> stim.Tableau:\n        \"\"\"Converts a circuit into an equivalent stabilizer tableau.\n\n        Args:\n            circuit: The circuit to compile into a tableau.\n            ignore_noise: Defaults to False. When False, any noise operations in the\n                circuit will cause the conversion to fail with an exception. When True,\n                noise operations are skipped over as if they weren't even present in the\n                circuit.\n            ignore_measurement: Defaults to False. When False, any measurement\n                operations in the circuit will cause the conversion to fail with an\n                exception. When True, measurement operations are skipped over as if they\n                weren't even present in the circuit.\n            ignore_reset: Defaults to False. When False, any reset operations in the\n                circuit will cause the conversion to fail with an exception. When True,\n                reset operations are skipped over as if they weren't even present in the\n                circuit.\n\n        Returns:\n            The tableau equivalent to the given circuit (up to global phase).\n\n        Raises:\n            ValueError:\n                The circuit contains noise operations but ignore_noise=False.\n                OR\n                The circuit contains measurement operations but\n                ignore_measurement=False.\n                OR\n                The circuit contains reset operations but ignore_reset=False.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_circuit(stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ... '''))\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n        \"\"\"\n    @staticmethod\n    def from_conjugated_generators(\n        *,\n        xs: List[stim.PauliString],\n        zs: List[stim.PauliString],\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau from the given outputs for each generator.\n\n        Verifies that the tableau is well formed.\n\n        Args:\n            xs: A List[stim.PauliString] with the results of conjugating X0, X1, etc.\n            zs: A List[stim.PauliString] with the results of conjugating Z0, Z1, etc.\n\n        Returns:\n            The created tableau.\n\n        Raises:\n            ValueError: The given outputs are malformed. Their lengths are inconsistent,\n                or they don't satisfy the required commutation relationships.\n\n        Examples:\n            >>> import stim\n            >>> identity3 = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"X__\"),\n            ...         stim.PauliString(\"_X_\"),\n            ...         stim.PauliString(\"__X\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"Z__\"),\n            ...         stim.PauliString(\"_Z_\"),\n            ...         stim.PauliString(\"__Z\"),\n            ...     ],\n            ... )\n            >>> identity3 == stim.Tableau(3)\n            True\n        \"\"\"\n    @staticmethod\n    def from_named_gate(\n        name: str,\n    ) -> stim.Tableau:\n        \"\"\"Returns the tableau of a named Clifford gate.\n\n        Args:\n            name: The name of the Clifford gate.\n\n        Returns:\n            The gate's tableau.\n\n        Examples:\n            >>> import stim\n            >>> print(stim.Tableau.from_named_gate(\"H\"))\n            +-xz-\n            | ++\n            | ZX\n            >>> print(stim.Tableau.from_named_gate(\"CNOT\"))\n            +-xz-xz-\n            | ++ ++\n            | XZ _Z\n            | X_ XZ\n            >>> print(stim.Tableau.from_named_gate(\"S\"))\n            +-xz-\n            | ++\n            | YZ\n        \"\"\"\n    def from_numpy(\n        self,\n        *,\n        x2x: np.ndarray,\n        x2z: np.ndarray,\n        z2x: np.ndarray,\n        z2z: np.ndarray,\n        x_signs: Optional[np.ndarray] = None,\n        z_signs: Optional[np.ndarray] = None,\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau from numpy arrays x2x, x2z, z2x, z2z, x_signs, and z_signs.\n\n        The x2x, x2z, z2x, z2z arrays are the four quadrants of the table defined in\n        Aaronson and Gottesman's \"Improved Simulation of Stabilizer Circuits\"\n        ( https://arxiv.org/abs/quant-ph/0406196 ).\n\n        Args:\n            x2x: A 2d numpy array containing the x-to-x coupling bits. The bits can be\n                bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                result will satisfy result.x_output_pauli(i, j) in [1, 2] == x2x[i, j].\n                Bit packing must be in little endian order and only applies to the\n                second axis.\n            x2z: A 2d numpy array containing the x-to-z coupling bits. The bits can be\n                bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                result will satisfy result.x_output_pauli(i, j) in [2, 3] == x2z[i, j].\n                Bit packing must be in little endian order and only applies to the\n                second axis.\n            z2x: A 2d numpy array containing the z-to-x coupling bits. The bits can be\n                bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                result will satisfy result.z_output_pauli(i, j) in [1, 2] == z2x[i, j].\n                Bit packing must be in little endian order and only applies to the\n                second axis.\n            z2z: A 2d numpy array containing the z-to-z coupling bits. The bits can be\n                bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                result will satisfy result.z_output_pauli(i, j) in [2, 3] == z2z[i, j].\n                Bit packing must be in little endian order and only applies to the\n                second axis.\n            x_signs: Defaults to all-positive if not specified. A 1d numpy array\n                containing the sign bits for the X generator outputs. False means\n                positive and True means negative. The bits can be bit packed\n                (dtype=uint8) or not (dtype=bool_). Bit packing must be in little endian\n                order.\n            z_signs: Defaults to all-positive if not specified. A 1d numpy array\n                containing the sign bits for the Z generator outputs. False means\n                positive and True means negative. The bits can be bit packed\n                (dtype=uint8) or not (dtype=bool_). Bit packing must be in little endian\n                order.\n\n        Returns:\n            The tableau created from the numpy data.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n\n            >>> tableau = stim.Tableau.from_numpy(\n            ...     x2x=np.array([[1, 1], [0, 1]], dtype=np.bool_),\n            ...     z2x=np.array([[0, 0], [0, 0]], dtype=np.bool_),\n            ...     x2z=np.array([[0, 0], [0, 0]], dtype=np.bool_),\n            ...     z2z=np.array([[1, 0], [1, 1]], dtype=np.bool_),\n            ... )\n            >>> tableau\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n            >>> tableau == stim.Tableau.from_named_gate(\"CNOT\")\n            True\n\n            >>> stim.Tableau.from_numpy(\n            ...     x2x=np.array([[9], [5], [7], [6]], dtype=np.uint8),\n            ...     x2z=np.array([[13], [13], [0], [3]], dtype=np.uint8),\n            ...     z2x=np.array([[8], [5], [9], [15]], dtype=np.uint8),\n            ...     z2z=np.array([[6], [11], [2], [3]], dtype=np.uint8),\n            ...     x_signs=np.array([7], dtype=np.uint8),\n            ...     z_signs=np.array([9], dtype=np.uint8),\n            ... )\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"-Y_ZY\"),\n                    stim.PauliString(\"-Y_YZ\"),\n                    stim.PauliString(\"-XXX_\"),\n                    stim.PauliString(\"+ZYX_\"),\n                ],\n                zs=[\n                    stim.PauliString(\"-_ZZX\"),\n                    stim.PauliString(\"+YZXZ\"),\n                    stim.PauliString(\"+XZ_X\"),\n                    stim.PauliString(\"-YYXX\"),\n                ],\n            )\n        \"\"\"\n    @staticmethod\n    def from_stabilizers(\n        stabilizers: Iterable[stim.PauliString],\n        *,\n        allow_redundant: bool = False,\n        allow_underconstrained: bool = False,\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau representing a state with the given stabilizers.\n\n        Args:\n            stabilizers: A list of `stim.PauliString`s specifying the stabilizers that\n                the state must have. It is permitted for stabilizers to have different\n                lengths. All stabilizers are padded up to the length of the longest\n                stabilizer by appending identity terms.\n            allow_redundant: Defaults to False. If set to False, then the given\n                stabilizers must all be independent. If any one of them is a product of\n                the others (including the empty product), an exception will be raised.\n                If set to True, then redundant stabilizers are simply ignored.\n            allow_underconstrained: Defaults to False. If set to False, then the given\n                stabilizers must form a complete set of generators. They must exactly\n                specify the desired stabilizer state, with no degrees of freedom left\n                over. For an n-qubit state there must be n independent stabilizers. If\n                set to True, then there can be leftover degrees of freedom which can be\n                set arbitrarily.\n\n        Returns:\n            A tableau which, when applied to the all-zeroes state, produces a state\n            with the given stabilizers.\n\n            Guarantees that result.z_output(k) will be equal to the k'th independent\n            stabilizer from the `stabilizers` argument.\n\n        Raises:\n            ValueError:\n                A stabilizer is redundant but allow_redundant=True wasn't set.\n                OR\n                The given stabilizers are contradictory (e.g. \"+Z\" and \"-Z\" both\n                specified).\n                OR\n                The given stabilizers anticommute (e.g. \"+Z\" and \"+X\" both specified).\n                OR\n                The stabilizers left behind a degree of freedom but\n                allow_underconstrained=True wasn't set.\n                OR\n                A stabilizer has an imaginary sign (i or -i).\n\n        Examples:\n\n            >>> import stim\n            >>> stim.Tableau.from_stabilizers([\n            ...     stim.PauliString(\"XX\"),\n            ...     stim.PauliString(\"ZZ\"),\n            ... ])\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n\n            >>> stim.Tableau.from_stabilizers([\n            ...     stim.PauliString(\"XX_\"),\n            ...     stim.PauliString(\"ZZ_\"),\n            ...     stim.PauliString(\"-YY_\"),\n            ...     stim.PauliString(\"\"),\n            ... ], allow_underconstrained=True, allow_redundant=True)\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z__\"),\n                    stim.PauliString(\"+_X_\"),\n                    stim.PauliString(\"+__X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX_\"),\n                    stim.PauliString(\"+ZZ_\"),\n                    stim.PauliString(\"+__Z\"),\n                ],\n            )\n        \"\"\"\n    @staticmethod\n    def from_state_vector(\n        state_vector: Iterable[float],\n        *,\n        endian: Literal[\"little\", \"big\"],\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau representing the stabilizer state of the given state vector.\n\n        Args:\n            state_vector: A list of complex amplitudes specifying a superposition. The\n                vector must correspond to a state that is reachable using Clifford\n                operations, and can be unnormalized.\n            endian:\n                \"little\": state vector is in little endian order, where higher index\n                    qubits correspond to larger changes in the state index.\n                \"big\": state vector is in big endian order, where higher index qubits\n                    correspond to smaller changes in the state index.\n\n        Returns:\n            A tableau which, when applied to the all-zeroes state, produces a state\n            with the given state vector.\n\n        Raises:\n            ValueError:\n                The given state vector isn't a list of complex values specifying a\n                stabilizer state.\n                OR\n                The given endian value isn't 'little' or 'big'.\n\n        Examples:\n\n            >>> import stim\n            >>> stim.Tableau.from_state_vector([\n            ...     0.5**0.5,\n            ...     0.5**0.5 * 1j,\n            ... ], endian='little')\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Y\"),\n                ],\n            )\n            >>> stim.Tableau.from_state_vector([\n            ...     0.5**0.5,\n            ...     0,\n            ...     0,\n            ...     0.5**0.5,\n            ... ], endian='little')\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n        \"\"\"\n    @staticmethod\n    def from_unitary_matrix(\n        matrix: Iterable[Iterable[float]],\n        *,\n        endian: Literal[\"little\", \"big\"] = 'little',\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau from the unitary matrix of a Clifford operation.\n\n        Args:\n            matrix: A unitary matrix specified as an iterable of rows, with each row is\n                an iterable of amplitudes. The unitary matrix must correspond to a\n                Clifford operation.\n            endian:\n                \"little\": matrix entries are in little endian order, where higher index\n                    qubits correspond to larger changes in row/col indices.\n                \"big\": matrix entries are in big endian order, where higher index\n                    qubits correspond to smaller changes in row/col indices.\n        Returns:\n            The tableau equivalent to the given unitary matrix (up to global phase).\n\n        Raises:\n            ValueError: The given matrix isn't the unitary matrix of a Clifford\n                operation.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_unitary_matrix([\n            ...     [1, 0],\n            ...     [0, 1j],\n            ... ], endian='little')\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Y\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n            )\n\n            >>> stim.Tableau.from_unitary_matrix([\n            ...     [1, 0, 0, 0],\n            ...     [0, 1, 0, 0],\n            ...     [0, 0, 0, -1j],\n            ...     [0, 0, 1j, 0],\n            ... ], endian='little')\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+XZ\"),\n                    stim.PauliString(\"+YX\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+ZZ\"),\n                    stim.PauliString(\"+_Z\"),\n                ],\n            )\n        \"\"\"\n    def inverse(\n        self,\n        *,\n        unsigned: bool = False,\n    ) -> stim.Tableau:\n        \"\"\"Computes the inverse of the tableau.\n\n        The inverse T^-1 of a tableau T is the unique tableau with the property that\n        T * T^-1 = T^-1 * T = I where I is the identity tableau.\n\n        Args:\n            unsigned: Defaults to false. When set to true, skips computing the signs of\n                the output observables and instead just set them all to be positive.\n                This is beneficial because computing the signs takes O(n^3) time and the\n                rest of the inverse computation is O(n^2) where n is the number of\n                qubits in the tableau. So, if you only need the Pauli terms (not the\n                signs), it is significantly cheaper.\n\n        Returns:\n            The inverse tableau.\n\n        Examples:\n            >>> import stim\n\n            >>> # Check that the inverse agrees with hard-coded tableaus.\n            >>> s = stim.Tableau.from_named_gate(\"S\")\n            >>> s_dag = stim.Tableau.from_named_gate(\"S_DAG\")\n            >>> s.inverse() == s_dag\n            True\n            >>> z = stim.Tableau.from_named_gate(\"Z\")\n            >>> z.inverse() == z\n            True\n\n            >>> # Check that multiplying by the inverse produces the identity.\n            >>> t = stim.Tableau.random(10)\n            >>> t_inv = t.inverse()\n            >>> identity = stim.Tableau(10)\n            >>> t * t_inv == t_inv * t == identity\n            True\n\n            >>> # Check a manual case.\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"-__Z\"),\n            ...         stim.PauliString(\"+XZ_\"),\n            ...         stim.PauliString(\"+_ZZ\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"-YYY\"),\n            ...         stim.PauliString(\"+Z_Z\"),\n            ...         stim.PauliString(\"-ZYZ\")\n            ...     ],\n            ... )\n            >>> print(t.inverse())\n            +-xz-xz-xz-\n            | -- +- --\n            | XX XX YX\n            | XZ Z_ X_\n            | X_ YX Y_\n            >>> print(t.inverse(unsigned=True))\n            +-xz-xz-xz-\n            | ++ ++ ++\n            | XX XX YX\n            | XZ Z_ X_\n            | X_ YX Y_\n        \"\"\"\n    def inverse_x_output(\n        self,\n        input_index: int,\n        *,\n        unsigned: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Conjugates a single-qubit X Pauli generator by the inverse of the tableau.\n\n        A faster version of `tableau.inverse(unsigned).x_output(input_index)`.\n\n        Args:\n            input_index: Identifies the column (the qubit of the X generator) to return\n                from the inverse tableau.\n            unsigned: Defaults to false. When set to true, skips computing the result's\n                sign and instead just sets it to positive. This is beneficial because\n                computing the sign takes O(n^2) time whereas all other parts of the\n                computation take O(n) time where n is the number of qubits in the\n                tableau.\n\n        Returns:\n            The result of conjugating an X generator by the inverse of the tableau.\n\n        Examples:\n            >>> import stim\n\n            # Check equivalence with the inverse's x_output.\n            >>> t = stim.Tableau.random(4)\n            >>> expected = t.inverse().x_output(0)\n            >>> t.inverse_x_output(0) == expected\n            True\n            >>> expected.sign = +1\n            >>> t.inverse_x_output(0, unsigned=True) == expected\n            True\n        \"\"\"\n    def inverse_x_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.inverse().x_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the column (the qubit of the input X generator) in\n                the inverse tableau.\n            output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n        Returns:\n            An integer identifying Pauli at the given location in the inverse tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t_inv = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... ).inverse()\n            >>> t_inv.inverse_x_output_pauli(0, 0)\n            2\n            >>> t_inv.inverse_x_output_pauli(0, 1)\n            0\n            >>> t_inv.inverse_x_output_pauli(1, 0)\n            2\n            >>> t_inv.inverse_x_output_pauli(1, 1)\n            3\n        \"\"\"\n    def inverse_y_output(\n        self,\n        input_index: int,\n        *,\n        unsigned: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Conjugates a single-qubit Y Pauli generator by the inverse of the tableau.\n\n        A faster version of `tableau.inverse(unsigned).y_output(input_index)`.\n\n        Args:\n            input_index: Identifies the column (the qubit of the Y generator) to return\n                from the inverse tableau.\n            unsigned: Defaults to false. When set to true, skips computing the result's\n                sign and instead just sets it to positive. This is beneficial because\n                computing the sign takes O(n^2) time whereas all other parts of the\n                computation take O(n) time where n is the number of qubits in the\n                tableau.\n\n        Returns:\n            The result of conjugating a Y generator by the inverse of the tableau.\n\n        Examples:\n            >>> import stim\n\n            # Check equivalence with the inverse's y_output.\n            >>> t = stim.Tableau.random(4)\n            >>> expected = t.inverse().y_output(0)\n            >>> t.inverse_y_output(0) == expected\n            True\n            >>> expected.sign = +1\n            >>> t.inverse_y_output(0, unsigned=True) == expected\n            True\n        \"\"\"\n    def inverse_y_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.inverse().y_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the column (the qubit of the input Y generator) in\n                the inverse tableau.\n            output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n        Returns:\n            An integer identifying Pauli at the given location in the inverse tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t_inv = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... ).inverse()\n            >>> t_inv.inverse_y_output_pauli(0, 0)\n            1\n            >>> t_inv.inverse_y_output_pauli(0, 1)\n            2\n            >>> t_inv.inverse_y_output_pauli(1, 0)\n            0\n            >>> t_inv.inverse_y_output_pauli(1, 1)\n            2\n        \"\"\"\n    def inverse_z_output(\n        self,\n        input_index: int,\n        *,\n        unsigned: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Conjugates a single-qubit Z Pauli generator by the inverse of the tableau.\n\n        A faster version of `tableau.inverse(unsigned).z_output(input_index)`.\n\n        Args:\n            input_index: Identifies the column (the qubit of the Z generator) to return\n                from the inverse tableau.\n            unsigned: Defaults to false. When set to true, skips computing the result's\n                sign and instead just sets it to positive. This is beneficial because\n                computing the sign takes O(n^2) time whereas all other parts of the\n                computation take O(n) time where n is the number of qubits in the\n                tableau.\n\n        Returns:\n            The result of conjugating a Z generator by the inverse of the tableau.\n\n        Examples:\n            >>> import stim\n\n            >>> import stim\n\n            # Check equivalence with the inverse's z_output.\n            >>> t = stim.Tableau.random(4)\n            >>> expected = t.inverse().z_output(0)\n            >>> t.inverse_z_output(0) == expected\n            True\n            >>> expected.sign = +1\n            >>> t.inverse_z_output(0, unsigned=True) == expected\n            True\n        \"\"\"\n    def inverse_z_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.inverse().z_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the column (the qubit of the input Z generator) in\n                the inverse tableau.\n            output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n        Returns:\n            An integer identifying Pauli at the given location in the inverse tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t_inv = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... ).inverse()\n            >>> t_inv.inverse_z_output_pauli(0, 0)\n            3\n            >>> t_inv.inverse_z_output_pauli(0, 1)\n            2\n            >>> t_inv.inverse_z_output_pauli(1, 0)\n            2\n            >>> t_inv.inverse_z_output_pauli(1, 1)\n            1\n        \"\"\"\n    @staticmethod\n    def iter_all(\n        num_qubits: int,\n        *,\n        unsigned: bool = False,\n    ) -> stim.TableauIterator:\n        \"\"\"Returns an iterator that iterates over all Tableaus of a given size.\n\n        Args:\n            num_qubits: The size of tableau to iterate over.\n            unsigned: Defaults to False. If set to True, only tableaus where\n                all columns have positive sign are yielded by the iterator.\n                This substantially reduces the total number of tableaus to\n                iterate over.\n\n        Returns:\n            An Iterable[stim.Tableau] that yields the requested tableaus.\n\n        Examples:\n            >>> import stim\n            >>> single_qubit_gate_reprs = set()\n            >>> for t in stim.Tableau.iter_all(1):\n            ...     single_qubit_gate_reprs.add(repr(t))\n            >>> len(single_qubit_gate_reprs)\n            24\n\n            >>> num_2q_gates_mod_paulis = 0\n            >>> for _ in stim.Tableau.iter_all(2, unsigned=True):\n            ...     num_2q_gates_mod_paulis += 1\n            >>> num_2q_gates_mod_paulis\n            720\n        \"\"\"\n    def prepend(\n        self,\n        gate: stim.Tableau,\n        targets: Sequence[int],\n    ) -> None:\n        \"\"\"Prepends an operation's effect into this tableau, mutating this tableau.\n\n        Time cost is O(n*m*m) where n=len(self) and m=len(gate).\n\n        Args:\n            gate: The tableau of the operation being prepended into this tableau.\n            targets: The qubits being targeted by the gate.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.from_named_gate(\"H\")\n            >>> t.prepend(stim.Tableau.from_named_gate(\"X\"), [0])\n            >>> t == stim.Tableau.from_named_gate(\"SQRT_Y_DAG\")\n            True\n        \"\"\"\n    @staticmethod\n    def random(\n        num_qubits: int,\n    ) -> stim.Tableau:\n        \"\"\"Samples a uniformly random Clifford operation and returns its tableau.\n\n        Args:\n            num_qubits: The number of qubits the tableau should act on.\n\n        Returns:\n            The sampled tableau.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.random(42)\n\n        References:\n            \"Hadamard-free circuits expose the structure of the Clifford group\"\n            Sergey Bravyi, Dmitri Maslov\n            https://arxiv.org/abs/2003.09412\n        \"\"\"\n    def then(\n        self,\n        second: stim.Tableau,\n    ) -> stim.Tableau:\n        \"\"\"Returns the result of composing two tableaus.\n\n        If the tableau T1 represents the Clifford operation with unitary C1,\n        and the tableau T2 represents the Clifford operation with unitary C2,\n        then the tableau T1.then(T2) represents the Clifford operation with unitary\n        C2*C1.\n\n        Args:\n            second: The result is equivalent to applying the second tableau after\n                the receiving tableau.\n\n        Examples:\n            >>> import stim\n            >>> t1 = stim.Tableau.random(4)\n            >>> t2 = stim.Tableau.random(4)\n            >>> t3 = t1.then(t2)\n            >>> p = stim.PauliString.random(4)\n            >>> t3(p) == t2(t1(p))\n            True\n        \"\"\"\n    def to_circuit(\n        self,\n        method: Literal[\"elimination\", \"graph_state\"] = 'elimination',\n    ) -> stim.Circuit:\n        \"\"\"Synthesizes a circuit that implements the tableau's Clifford operation.\n\n        The circuits returned by this method are not guaranteed to be stable\n        from version to version, and may be produced using randomization.\n\n        Args:\n            method: The method to use when synthesizing the circuit. Available values:\n                \"elimination\": Cancels off-diagonal terms using Gaussian elimination.\n                    Gate set: H, S, CX\n                    Circuit qubit count: n\n                    Circuit operation count: O(n^2)\n                    Circuit depth: O(n^2)\n                \"graph_state\": Prepares the tableau's state using a graph state circuit.\n                    Gate set: RX, CZ, H, S, X, Y, Z\n                    Circuit qubit count: n\n                    Circuit operation count: O(n^2)\n\n                    The circuit will be made up of three layers:\n                        1. An RX layer initializing all qubits.\n                        2. A CZ layer coupling the qubits.\n                            (Each CZ is an edge in the graph state.)\n                        3. A single qubit rotation layer.\n\n                    Note: \"graph_state\" treats the tableau as a state instead of as a\n                    Clifford operation. It will preserve the set of stabilizers, but\n                    not the exact choice of generators.\n                \"mpp_state\": Prepares the tableau's state using MPP and feedback.\n                    Gate set: MPP, CX rec, CY rec, CZ rec\n                    Circuit qubit count: n\n                    Circuit operation count: O(n^2)\n\n                    The circuit will be made up of two layers:\n                        1. An MPP layer measuring each of the tableau's stabilizers.\n                        2. A feedback layer using the measurement results to control\n                            whether or not to apply each of the tableau's destabilizers\n                            in order to get the correct sign for each stabilizer.\n\n                    Note: \"mpp_state\" treats the tableau as a state instead of as a\n                    Clifford operation. It will preserve the set of stabilizers, but\n                    not the exact choice of generators.\n                \"mpp_state_unsigned\": Prepares the tableau's state up to sign using MPP.\n                    Gate set: MPP\n                    Circuit qubit count: n\n                    Circuit operation count: O(n^2)\n\n                    The circuit will contain a series of MPP measurements measuring each\n                    of the tableau's stabilizers. The stabilizers are measured in the\n                    order used by the tableau (i.e. tableau.z_output(k) is the k'th\n                    stabilizer measured).\n\n                    Note: \"mpp_state_unsigned\" treats the tableau as a state instead of\n                    as a Clifford operation. It will preserve the set of stabilizers,\n                    but not the exact choice of generators.\n        Returns:\n            The synthesized circuit.\n\n        Example:\n            >>> import stim\n            >>> tableau = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"+YZ__\"),\n            ...         stim.PauliString(\"-Y_XY\"),\n            ...         stim.PauliString(\"+___Y\"),\n            ...         stim.PauliString(\"+YZX_\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"+XZYY\"),\n            ...         stim.PauliString(\"-XYX_\"),\n            ...         stim.PauliString(\"-ZXXZ\"),\n            ...         stim.PauliString(\"+XXZ_\"),\n            ...     ],\n            ... )\n\n            >>> tableau.to_circuit()\n            stim.Circuit('''\n                S 0\n                H 0 1 3\n                CX 0 1 0 2 0 3\n                S 1 3\n                H 1 3\n                CX 1 0 3 0 3 1 1 3 3 1\n                H 1\n                S 1\n                CX 1 3\n                H 2 3\n                CX 2 1 3 1 3 2 2 3 3 2\n                H 3\n                CX 2 3\n                S 3\n                H 3 0 1 2\n                S 0 0 1 1 2 2\n                H 0 1 2\n                S 3 3\n            ''')\n\n            >>> tableau.to_circuit(\"graph_state\")\n            stim.Circuit('''\n                RX 0 1 2 3\n                TICK\n                CZ 0 3 1 2 1 3\n                TICK\n                X 0 1\n                Z 2\n                S 2 3\n                H 3\n                S 3\n            ''')\n\n            >>> tableau.to_circuit(\"mpp_state_unsigned\")\n            stim.Circuit('''\n                MPP X0*Z1*Y2*Y3 !X0*Y1*X2 !Z0*X1*X2*Z3 X0*X1*Z2\n            ''')\n\n            >>> tableau.to_circuit(\"mpp_state\")\n            stim.Circuit('''\n                MPP X0*Z1*Y2*Y3 !X0*Y1*X2 !Z0*X1*X2*Z3 X0*X1*Z2\n                CX rec[-3] 2 rec[-1] 2\n                CY rec[-4] 0 rec[-3] 0 rec[-3] 3 rec[-2] 3 rec[-1] 0\n                CZ rec[-4] 1 rec[-1] 1\n            ''')\n        \"\"\"\n    def to_numpy(\n        self,\n        *,\n        bit_packed: bool = False,\n    ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:\n        \"\"\"Decomposes the contents of the tableau into six numpy arrays.\n\n        The first four numpy arrays correspond to the four quadrants of the table\n        defined in Aaronson and Gottesman's \"Improved Simulation of Stabilizer Circuits\"\n        ( https://arxiv.org/abs/quant-ph/0406196 ).\n\n        The last two numpy arrays are the X and Z sign bit vectors of the tableau.\n\n        Args:\n            bit_packed: Defaults to False. Determines whether the output numpy arrays\n                use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n        Returns:\n            An (x2x, x2z, z2x, z2z, x_signs, z_signs) tuple encoding the tableau.\n\n            x2x: A 2d table of whether tableau(X_i)_j is X or Y (instead of I or Z).\n            x2z: A 2d table of whether tableau(X_i)_j is Z or Y (instead of I or X).\n            z2x: A 2d table of whether tableau(Z_i)_j is X or Y (instead of I or Z).\n            z2z: A 2d table of whether tableau(Z_i)_j is Z or Y (instead of I or X).\n            x_signs: A vector of whether tableau(X_i) is negative.\n            z_signs: A vector of whether tableau(Z_i) is negative.\n\n            If bit_packed=False then:\n                x2x.dtype = np.bool_\n                x2z.dtype = np.bool_\n                z2x.dtype = np.bool_\n                z2z.dtype = np.bool_\n                x_signs.dtype = np.bool_\n                z_signs.dtype = np.bool_\n                x2x.shape = (len(tableau), len(tableau))\n                x2z.shape = (len(tableau), len(tableau))\n                z2x.shape = (len(tableau), len(tableau))\n                z2z.shape = (len(tableau), len(tableau))\n                x_signs.shape = len(tableau)\n                z_signs.shape = len(tableau)\n                x2x[i, j] = tableau.x_output_pauli(i, j) in [1, 2]\n                x2z[i, j] = tableau.x_output_pauli(i, j) in [2, 3]\n                z2x[i, j] = tableau.z_output_pauli(i, j) in [1, 2]\n                z2z[i, j] = tableau.z_output_pauli(i, j) in [2, 3]\n\n            If bit_packed=True then:\n                x2x.dtype = np.uint8\n                x2z.dtype = np.uint8\n                z2x.dtype = np.uint8\n                z2z.dtype = np.uint8\n                x_signs.dtype = np.uint8\n                z_signs.dtype = np.uint8\n                x2x.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                x2z.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                z2x.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                z2z.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                x_signs.shape = math.ceil(len(tableau) / 8)\n                z_signs.shape = math.ceil(len(tableau) / 8)\n                (x2x[i, j // 8] >> (j % 8)) & 1 = tableau.x_output_pauli(i, j) in [1, 2]\n                (x2z[i, j // 8] >> (j % 8)) & 1 = tableau.x_output_pauli(i, j) in [2, 3]\n                (z2x[i, j // 8] >> (j % 8)) & 1 = tableau.z_output_pauli(i, j) in [1, 2]\n                (z2z[i, j // 8] >> (j % 8)) & 1 = tableau.z_output_pauli(i, j) in [2, 3]\n\n        Examples:\n            >>> import stim\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> print(repr(cnot))\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n            >>> x2x, x2z, z2x, z2z, x_signs, z_signs = cnot.to_numpy()\n            >>> x2x\n            array([[ True,  True],\n                   [False,  True]])\n            >>> x2z\n            array([[False, False],\n                   [False, False]])\n            >>> z2x\n            array([[False, False],\n                   [False, False]])\n            >>> z2z\n            array([[ True, False],\n                   [ True,  True]])\n            >>> x_signs\n            array([False, False])\n            >>> z_signs\n            array([False, False])\n\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"-Y_ZY\"),\n            ...         stim.PauliString(\"-Y_YZ\"),\n            ...         stim.PauliString(\"-XXX_\"),\n            ...         stim.PauliString(\"+ZYX_\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"-_ZZX\"),\n            ...         stim.PauliString(\"+YZXZ\"),\n            ...         stim.PauliString(\"+XZ_X\"),\n            ...         stim.PauliString(\"-YYXX\"),\n            ...     ],\n            ... )\n\n            >>> x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy()\n            >>> x2x\n            array([[ True, False, False,  True],\n                   [ True, False,  True, False],\n                   [ True,  True,  True, False],\n                   [False,  True,  True, False]])\n            >>> x2z\n            array([[ True, False,  True,  True],\n                   [ True, False,  True,  True],\n                   [False, False, False, False],\n                   [ True,  True, False, False]])\n            >>> z2x\n            array([[False, False, False,  True],\n                   [ True, False,  True, False],\n                   [ True, False, False,  True],\n                   [ True,  True,  True,  True]])\n            >>> z2z\n            array([[False,  True,  True, False],\n                   [ True,  True, False,  True],\n                   [False,  True, False, False],\n                   [ True,  True, False, False]])\n            >>> x_signs\n            array([ True,  True,  True, False])\n            >>> z_signs\n            array([ True, False, False,  True])\n\n            >>> x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy(bit_packed=True)\n            >>> x2x\n            array([[9],\n                   [5],\n                   [7],\n                   [6]], dtype=uint8)\n            >>> x2z\n            array([[13],\n                   [13],\n                   [ 0],\n                   [ 3]], dtype=uint8)\n            >>> z2x\n            array([[ 8],\n                   [ 5],\n                   [ 9],\n                   [15]], dtype=uint8)\n            >>> z2z\n            array([[ 6],\n                   [11],\n                   [ 2],\n                   [ 3]], dtype=uint8)\n            >>> x_signs\n            array([7], dtype=uint8)\n            >>> z_signs\n            array([9], dtype=uint8)\n        \"\"\"\n    def to_pauli_string(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Return a Pauli string equivalent to the tableau.\n\n        If the tableau is equivalent to a pauli product, creates\n        an equivalent pauli string. If not, then an error is raised.\n\n        Returns:\n            The created pauli string\n\n        Raises:\n            ValueError: The Tableau isn't equivalent to a Pauli product.\n\n        Example:\n            >>> import stim\n            >>> t = (stim.Tableau.from_named_gate(\"Z\") +\n            ...      stim.Tableau.from_named_gate(\"Y\") +\n            ...      stim.Tableau.from_named_gate(\"I\") +\n            ...      stim.Tableau.from_named_gate(\"X\"))\n            >>> print(t)\n            +-xz-xz-xz-xz-\n            | -+ -- ++ +-\n            | XZ __ __ __\n            | __ XZ __ __\n            | __ __ XZ __\n            | __ __ __ XZ\n            >>> print(t.to_pauli_string())\n            +ZY_X\n        \"\"\"\n    def to_stabilizers(\n        self,\n        *,\n        canonicalize: bool = False,\n    ) -> List[stim.PauliString]:\n        \"\"\"Returns the stabilizer generators of the tableau, optionally canonicalized.\n\n        The stabilizer generators of the tableau are its Z outputs. Canonicalizing\n        standardizes the generators, so that states that are equal will produce the\n        same generators. For example, [ZI, IZ], [ZI, ZZ], amd [ZZ, ZI] describe equal\n        states and all canonicalize to [ZI, IZ].\n\n        The canonical form is computed as follows:\n\n            1. Get a list of stabilizers using `tableau.z_output(k)` for each k.\n            2. Perform Gaussian elimination. pivoting on standard generators.\n                2a) Pivot on g=X0 first, then Z0, X1, Z1, X2, Z2, etc.\n                2b) Find a stabilizer that uses the generator g. If there are none,\n                    go to the next g.\n                2c) Multiply that stabilizer into all other stabilizers that use the\n                    generator g.\n                2d) Swap that stabilizer with the stabilizer at position `r` then\n                    increment `r`. `r` starts at 0.\n\n        Args:\n            canonicalize: Defaults to False. When False, the tableau's Z outputs\n                are returned unchanged. When True, the Z outputs are rewritten\n                into a standard form. Two stabilizer states have the same standard\n                form if and only if they describe equivalent quantum states.\n\n        Returns:\n            A List[stim.PauliString] of the tableau's stabilizer generators.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n\n            >>> raw_stabilizers = t.to_stabilizers()\n            >>> for e in raw_stabilizers:\n            ...     print(repr(e))\n            stim.PauliString(\"+Z_\")\n            stim.PauliString(\"+ZZ\")\n\n            >>> canonical_stabilizers = t.to_stabilizers(canonicalize=True)\n            >>> for e in canonical_stabilizers:\n            ...     print(repr(e))\n            stim.PauliString(\"+Z_\")\n            stim.PauliString(\"+_Z\")\n        \"\"\"\n    def to_state_vector(\n        self,\n        *,\n        endian: Literal[\"little\", \"big\"] = 'little',\n    ) -> np.ndarray[np.complex64]:\n        \"\"\"Returns the state vector produced by applying the tableau to the |0..0> state.\n\n        This function takes O(n * 2**n) time and O(2**n) space, where n is the number of\n        qubits. The computation is done by initialization a random state vector and\n        iteratively projecting it into the +1 eigenspace of each stabilizer of the\n        state. The state is then canonicalized so that zero values are actually exactly\n        0, and so that the first non-zero entry is positive.\n\n        Args:\n            endian:\n                \"little\" (default): state vector is in little endian order, where higher\n                    index qubits correspond to larger changes in the state index.\n                \"big\": state vector is in big endian order, where higher index qubits\n                    correspond to smaller changes in the state index.\n\n        Returns:\n            A `numpy.ndarray[numpy.complex64]` of computational basis amplitudes.\n\n            If the result is in little endian order then the amplitude at offset\n            b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n            computational basis state where the qubit with index 0 is storing the bit\n            b_0, the qubit with index 1 is storing the bit b_1, etc.\n\n            If the result is in big endian order then the amplitude at offset\n            b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n            computational basis state where the qubit with index 0 is storing the bit\n            b_{n-1}, the qubit with index 1 is storing the bit b_{n-2}, etc.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> i2 = stim.Tableau.from_named_gate('I')\n            >>> x = stim.Tableau.from_named_gate('X')\n            >>> h = stim.Tableau.from_named_gate('H')\n\n            >>> (x + i2).to_state_vector(endian='little')\n            array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)\n\n            >>> (i2 + x).to_state_vector(endian='little')\n            array([0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], dtype=complex64)\n\n            >>> (i2 + x).to_state_vector(endian='big')\n            array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)\n\n            >>> (h + h).to_state_vector(endian='little')\n            array([0.5+0.j, 0.5+0.j, 0.5+0.j, 0.5+0.j], dtype=complex64)\n        \"\"\"\n    def to_unitary_matrix(\n        self,\n        *,\n        endian: Literal[\"little\", \"big\"],\n    ) -> np.ndarray[np.complex64]:\n        \"\"\"Converts the tableau into a unitary matrix.\n\n        For an n-qubit tableau, this method performs O(n 4^n) work. It uses the state\n        channel duality to transform the tableau into a list of stabilizers, then\n        generates a random state vector and projects it into the +1 eigenspace of each\n        stabilizer.\n\n        Note that tableaus don't have a defined global phase, so the result's global\n        phase may be different from what you expect. For example, the square of\n        SQRT_X's unitary might equal -X instead of +X.\n\n        Args:\n            endian:\n                \"little\": The first qubit is the least significant (corresponds\n                    to an offset of 1 in the state vector).\n                \"big\": The first qubit is the most significant (corresponds\n                    to an offset of 2**(n - 1) in the state vector).\n\n        Returns:\n            A numpy array with dtype=np.complex64 and\n            shape=(1 << len(tableau), 1 << len(tableau)).\n\n        Example:\n            >>> import stim\n            >>> cnot = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"XX\"),\n            ...         stim.PauliString(\"_X\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"Z_\"),\n            ...         stim.PauliString(\"ZZ\"),\n            ...     ],\n            ... )\n            >>> cnot.to_unitary_matrix(endian='big')\n            array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n                   [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]], dtype=complex64)\n        \"\"\"\n    def x_output(\n        self,\n        target: int,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating a Pauli X by the tableau's Clifford operation.\n\n        Args:\n            target: The qubit targeted by the Pauli X operation.\n\n        Examples:\n            >>> import stim\n            >>> h = stim.Tableau.from_named_gate(\"H\")\n            >>> h.x_output(0)\n            stim.PauliString(\"+Z\")\n\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> cnot.x_output(0)\n            stim.PauliString(\"+XX\")\n            >>> cnot.x_output(1)\n            stim.PauliString(\"+_X\")\n        \"\"\"\n    def x_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.x_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the tableau column (the qubit of the input X\n                generator).\n            output_index: Identifies the tableau row (the output qubit).\n\n        Returns:\n            An integer identifying Pauli at the given location in the tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... )\n            >>> t.x_output_pauli(0, 0)\n            2\n            >>> t.x_output_pauli(0, 1)\n            0\n            >>> t.x_output_pauli(1, 0)\n            2\n            >>> t.x_output_pauli(1, 1)\n            3\n        \"\"\"\n    def x_sign(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns just the sign of the result of conjugating an X generator.\n\n        This operation runs in constant time.\n\n        Args:\n            target: The qubit the X generator applies to.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_named_gate(\"S_DAG\").x_sign(0)\n            -1\n            >>> stim.Tableau.from_named_gate(\"S\").x_sign(0)\n            1\n        \"\"\"\n    def y_output(\n        self,\n        target: int,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating a Pauli Y by the tableau's Clifford operation.\n\n        Args:\n            target: The qubit targeted by the Pauli Y operation.\n\n        Examples:\n            >>> import stim\n            >>> h = stim.Tableau.from_named_gate(\"H\")\n            >>> h.y_output(0)\n            stim.PauliString(\"-Y\")\n\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> cnot.y_output(0)\n            stim.PauliString(\"+YX\")\n            >>> cnot.y_output(1)\n            stim.PauliString(\"+ZY\")\n        \"\"\"\n    def y_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.y_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the tableau column (the qubit of the input Y\n                generator).\n            output_index: Identifies the tableau row (the output qubit).\n\n        Returns:\n            An integer identifying Pauli at the given location in the tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... )\n            >>> t.y_output_pauli(0, 0)\n            1\n            >>> t.y_output_pauli(0, 1)\n            2\n            >>> t.y_output_pauli(1, 0)\n            0\n            >>> t.y_output_pauli(1, 1)\n            2\n        \"\"\"\n    def y_sign(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns just the sign of the result of conjugating a Y generator.\n\n        Unlike x_sign and z_sign, this operation runs in linear time.\n        The Y generator has to be computed by multiplying the X and Z\n        outputs and the sign depends on all terms.\n\n        Args:\n            target: The qubit the Y generator applies to.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_named_gate(\"S_DAG\").y_sign(0)\n            1\n            >>> stim.Tableau.from_named_gate(\"S\").y_sign(0)\n            -1\n        \"\"\"\n    def z_output(\n        self,\n        target: int,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating a Pauli Z by the tableau's Clifford operation.\n\n        Args:\n            target: The qubit targeted by the Pauli Z operation.\n\n        Examples:\n            >>> import stim\n            >>> h = stim.Tableau.from_named_gate(\"H\")\n            >>> h.z_output(0)\n            stim.PauliString(\"+X\")\n\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> cnot.z_output(0)\n            stim.PauliString(\"+Z_\")\n            >>> cnot.z_output(1)\n            stim.PauliString(\"+ZZ\")\n        \"\"\"\n    def z_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.z_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the tableau column (the qubit of the input Z\n                generator).\n            output_index: Identifies the tableau row (the output qubit).\n\n        Returns:\n            An integer identifying Pauli at the given location in the tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... )\n            >>> t.z_output_pauli(0, 0)\n            3\n            >>> t.z_output_pauli(0, 1)\n            2\n            >>> t.z_output_pauli(1, 0)\n            2\n            >>> t.z_output_pauli(1, 1)\n            1\n        \"\"\"\n    def z_sign(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns just the sign of the result of conjugating a Z generator.\n\n        This operation runs in constant time.\n\n        Args:\n            target: The qubit the Z generator applies to.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_named_gate(\"SQRT_X_DAG\").z_sign(0)\n            1\n            >>> stim.Tableau.from_named_gate(\"SQRT_X\").z_sign(0)\n            -1\n        \"\"\"\nclass TableauIterator:\n    \"\"\"Iterates over all stabilizer tableaus of a specified size.\n\n    Examples:\n        >>> import stim\n        >>> tableau_iterator = stim.Tableau.iter_all(1)\n        >>> n = 0\n        >>> for single_qubit_clifford in tableau_iterator:\n        ...     n += 1\n        >>> n\n        24\n    \"\"\"\n    def __iter__(\n        self,\n    ) -> stim.TableauIterator:\n        \"\"\"Returns an independent copy of the tableau iterator.\n\n        Since for-loops and loop-comprehensions call `iter` on things they\n        iterate, this effectively allows the iterator to be iterated\n        multiple times.\n        \"\"\"\n    def __next__(\n        self,\n    ) -> stim.Tableau:\n        \"\"\"Returns the next iterated tableau.\n        \"\"\"\nclass TableauSimulator:\n    \"\"\"A stabilizer circuit simulator that tracks an inverse stabilizer tableau.\n\n    Supports interactive usage, where gates and measurements are applied on demand.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> if s.measure(0):\n        ...     s.h(1)\n        ...     s.cnot(1, 2)\n        >>> s.measure(1) == s.measure(2)\n        True\n\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> s.cnot(0, 1)\n        >>> s.current_inverse_tableau()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+ZX\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X_\"),\n                stim.PauliString(\"+XZ\"),\n            ],\n        )\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        seed: Optional[int] = None,\n    ) -> None:\n        \"\"\"Initializes a stim.TableauSimulator.\n\n        Args:\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                circuit is executed. For example, reordering whether a reset on one\n                qubit happens before or after a reset on another qubit can result in\n                different measurement results being observed starting from the same\n                seed.\n\n        Returns:\n            An initialized stim.TableauSimulator.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator(seed=0)\n            >>> s2 = stim.TableauSimulator(seed=0)\n            >>> s.h(0)\n            >>> s2.h(0)\n            >>> s.measure(0) == s2.measure(0)\n            True\n        \"\"\"\n    def c_xyz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a C_XYZ gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.c_xyz(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Y +Z +X\n        \"\"\"\n    def c_zyx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a C_ZYX gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.c_zyx(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Z +X +Y\n        \"\"\"\n    def canonical_stabilizers(\n        self,\n    ) -> List[stim.PauliString]:\n        \"\"\"Returns a standardized list of the simulator's current stabilizer generators.\n\n        Two simulators have the same canonical stabilizers if and only if their current\n        quantum state is equal (and tracking the same number of qubits).\n\n        The canonical form is computed as follows:\n\n            1. Get a list of stabilizers using the `z_output`s of\n                `simulator.current_inverse_tableau()**-1`.\n            2. Perform Gaussian elimination on each generator g.\n                2a) The generators are considered in order X0, Z0, X1, Z1, X2, Z2, etc.\n                2b) Pick any stabilizer that uses the generator g. If there are none,\n                    go to the next g.\n                2c) Multiply that stabilizer into all other stabilizers that use the\n                    generator g.\n                2d) Swap that stabilizer with the stabilizer at position `next_output`\n                    then increment `next_output`.\n\n        Returns:\n            A List[stim.PauliString] of the simulator's state's stabilizers.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.cnot(0, 1)\n            >>> s.x(2)\n            >>> for e in s.canonical_stabilizers():\n            ...     print(repr(e))\n            stim.PauliString(\"+XX_\")\n            stim.PauliString(\"+ZZ_\")\n            stim.PauliString(\"-__Z\")\n\n            >>> # Scramble the stabilizers then check the canonical form is unchanged.\n            >>> s.set_inverse_tableau(s.current_inverse_tableau()**-1)\n            >>> s.cnot(0, 1)\n            >>> s.cz(0, 2)\n            >>> s.s(0, 2)\n            >>> s.cy(2, 1)\n            >>> s.set_inverse_tableau(s.current_inverse_tableau()**-1)\n            >>> for e in s.canonical_stabilizers():\n            ...     print(repr(e))\n            stim.PauliString(\"+XX_\")\n            stim.PauliString(\"+ZZ_\")\n            stim.PauliString(\"-__Z\")\n        \"\"\"\n    def cnot(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.cnot(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def copy(\n        self,\n        *,\n        copy_rng: bool = False,\n        seed: Optional[int] = None,\n    ) -> stim.TableauSimulator:\n        \"\"\"Returns a simulator with the same internal state, except perhaps its prng.\n\n        Args:\n            copy_rng: By default, new simulator's prng is reinitialized with a random\n                seed. However, one can set this argument to True in order to have the\n                prng state copied together with the rest of the original simulator's\n                state. Consequently, in this case the two simulators will produce the\n                same measurement outcomes for the same quantum circuits.  If both seed\n                and copy_rng are set, an exception is raised. Defaults to False.\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng state is either copied from the\n                original simulator or reseeded from system entropy, depending on the\n                copy_rng argument.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                circuit is executed. For example, reordering whether a reset on one\n                qubit happens before or after a reset on another qubit can result in\n                different measurement results being observed starting from the same\n                seed.\n\n        Examples:\n            >>> import stim\n\n            >>> s1 = stim.TableauSimulator()\n            >>> s1.set_inverse_tableau(stim.Tableau.random(1))\n            >>> s2 = s1.copy()\n            >>> s2 is s1\n            False\n            >>> s2.current_inverse_tableau() == s1.current_inverse_tableau()\n            True\n\n            >>> s1 = stim.TableauSimulator()\n            >>> s2 = s1.copy(copy_rng=True)\n            >>> s1.h(0)\n            >>> s2.h(0)\n            >>> assert s1.measure(0) == s2.measure(0)\n\n            >>> s = stim.TableauSimulator()\n            >>> def brute_force_post_select(qubit, desired_result):\n            ...     global s\n            ...     while True:\n            ...         s2 = s.copy()\n            ...         if s2.measure(qubit) == desired_result:\n            ...             s = s2\n            ...             break\n            >>> s.h(0)\n            >>> brute_force_post_select(qubit=0, desired_result=True)\n            >>> s.measure(0)\n            True\n        \"\"\"\n    def current_inverse_tableau(\n        self,\n    ) -> stim.Tableau:\n        \"\"\"Returns a copy of the internal state of the simulator as a stim.Tableau.\n\n        Returns:\n            A stim.Tableau copy of the simulator's state.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.current_inverse_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+X\"),\n                ],\n            )\n            >>> s.cnot(0, 1)\n            >>> s.current_inverse_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+ZX\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+X_\"),\n                    stim.PauliString(\"+XZ\"),\n                ],\n            )\n        \"\"\"\n    def current_measurement_record(\n        self,\n    ) -> List[bool]:\n        \"\"\"Returns a copy of the record of all measurements performed by the simulator.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.current_measurement_record()\n            []\n            >>> s.measure(0)\n            False\n            >>> s.x(0)\n            >>> s.measure(0)\n            True\n            >>> s.current_measurement_record()\n            [False, True]\n            >>> s.do(stim.Circuit(\"M 0\"))\n            >>> s.current_measurement_record()\n            [False, True, True]\n\n        Returns:\n            A list of booleans containing the result of every measurement performed by\n            the simulator so far.\n        \"\"\"\n    def cx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.cx(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def cy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.cy(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n        \"\"\"\n    def cz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.cz(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def depolarize1(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies single-qubit depolarization to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n            p: The chance of the error being applied,\n                independently, to each qubit.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.depolarize1(0, 1, 2, p=0.01)\n        \"\"\"\n    def depolarize2(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies two-qubit depolarization to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n                The pairs of qubits are formed by\n                zip(targets[::1], targets[1::2]).\n            p: The chance of the error being applied,\n                independently, to each qubit pair.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.depolarize1(0, 1, 4, 5, p=0.01)\n        \"\"\"\n    def do(\n        self,\n        circuit_or_pauli_string: Union[stim.Circuit, stim.PauliString, stim.CircuitInstruction, stim.CircuitRepeatBlock],\n    ) -> None:\n        \"\"\"Applies a circuit or pauli string to the simulator's state.\n\n        Args:\n            circuit_or_pauli_string: A stim.Circuit, stim.PauliString,\n                stim.CircuitInstruction, or stim.CircuitRepeatBlock\n                with operations to apply to the simulator's state.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.do(stim.Circuit('''\n            ...     X 0\n            ...     M 0\n            ... '''))\n            >>> s.current_measurement_record()\n            [True]\n\n            >>> s = stim.TableauSimulator()\n            >>> s.do(stim.PauliString(\"IXYZ\"))\n            >>> s.measure_many(0, 1, 2, 3)\n            [False, True, True, False]\n        \"\"\"\n    def do_circuit(\n        self,\n        circuit: stim.Circuit,\n    ) -> None:\n        \"\"\"Applies a circuit to the simulator's state.\n\n        Args:\n            circuit: A stim.Circuit containing operations to apply.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.do_circuit(stim.Circuit('''\n            ...     X 0\n            ...     M 0\n            ... '''))\n            >>> s.current_measurement_record()\n            [True]\n        \"\"\"\n    def do_pauli_string(\n        self,\n        pauli_string: stim.PauliString,\n    ) -> None:\n        \"\"\"Applies the paulis from a pauli string to the simulator's state.\n\n        Args:\n            pauli_string: A stim.PauliString containing Paulis to apply.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.do_pauli_string(stim.PauliString(\"IXYZ\"))\n            >>> s.measure_many(0, 1, 2, 3)\n            [False, True, True, False]\n        \"\"\"\n    def do_tableau(\n        self,\n        tableau: stim.Tableau,\n        targets: List[int],\n    ) -> None:\n        \"\"\"Applies a custom tableau operation to qubits in the simulator.\n\n        Note that this method has to compute the inverse of the tableau, because the\n        simulator's internal state is an inverse tableau.\n\n        Args:\n            tableau: A stim.Tableau representing the Clifford operation to apply.\n            targets: The indices of the qubits to operate on.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.TableauSimulator()\n            >>> sim.h(1)\n            >>> sim.h_yz(2)\n            >>> [str(sim.peek_bloch(k)) for k in range(4)]\n            ['+Z', '+X', '+Y', '+Z']\n            >>> rot3 = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"_X_\"),\n            ...         stim.PauliString(\"__X\"),\n            ...         stim.PauliString(\"X__\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"_Z_\"),\n            ...         stim.PauliString(\"__Z\"),\n            ...         stim.PauliString(\"Z__\"),\n            ...     ],\n            ... )\n\n            >>> sim.do_tableau(rot3, [1, 2, 3])\n            >>> [str(sim.peek_bloch(k)) for k in range(4)]\n            ['+Z', '+Z', '+X', '+Y']\n\n            >>> sim.do_tableau(rot3, [1, 2, 3])\n            >>> [str(sim.peek_bloch(k)) for k in range(4)]\n            ['+Z', '+Y', '+Z', '+X']\n        \"\"\"\n    def h(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Hadamard gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.h(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Z -Y +X\n        \"\"\"\n    def h_xy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an operation that swaps the X and Y axes to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.h_xy(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Y +X -Z\n        \"\"\"\n    def h_xz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Hadamard gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.h_xz(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Z -Y +X\n        \"\"\"\n    def h_yz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an operation that swaps the Y and Z axes to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.h_yz(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -X +Z +Y\n        \"\"\"\n    def iswap(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an ISWAP gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.iswap(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Y +Z\n        \"\"\"\n    def iswap_dag(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an ISWAP_DAG gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.iswap_dag(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ -Y +Z\n        \"\"\"\n    def measure(\n        self,\n        target: int,\n    ) -> bool:\n        \"\"\"Measures a single qubit.\n\n        Unlike the other methods on TableauSimulator, this one does not broadcast\n        over multiple targets. This is to avoid returning a list, which would\n        create a pitfall where typing `if sim.measure(qubit)` would be a bug.\n\n        To measure multiple qubits, use `TableauSimulator.measure_many`.\n\n        Args:\n            target: The index of the qubit to measure.\n\n        Returns:\n            The measurement result as a bool.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.x(1)\n            >>> s.measure(0)\n            False\n            >>> s.measure(1)\n            True\n        \"\"\"\n    def measure_kickback(\n        self,\n        target: int,\n    ) -> tuple:\n        \"\"\"Measures a qubit and returns the result as well as its Pauli kickback (if any).\n\n        The \"Pauli kickback\" of a stabilizer circuit measurement is a set of Pauli\n        operations that flip the post-measurement system state between the two possible\n        post-measurement states. For example, consider measuring one of the qubits in\n        the state |00>+|11> in the Z basis. If the measurement result is False, then the\n        system projects into the state |00>. If the measurement result is True, then the\n        system projects into the state |11>. Applying a Pauli X operation to both qubits\n        flips between |00> and |11>. Therefore the Pauli kickback of the measurement is\n        `stim.PauliString(\"XX\")`. Note that there are often many possible equivalent\n        Pauli kickbacks. For example, if in the previous example there was a third qubit\n        in the |0> state, then both `stim.PauliString(\"XX_\")` and\n        `stim.PauliString(\"XXZ\")` are valid kickbacks.\n\n        Measurements with deterministic results don't have a Pauli kickback.\n\n        Args:\n            target: The index of the qubit to measure.\n\n        Returns:\n            A (result, kickback) tuple.\n            The result is a bool containing the measurement's output.\n            The kickback is either None (meaning the measurement was deterministic) or a\n            stim.PauliString (meaning the measurement was random, and the operations in\n            the Pauli string flip between the two possible post-measurement states).\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n\n            >>> s.measure_kickback(0)\n            (False, None)\n\n            >>> s.h(0)\n            >>> s.measure_kickback(0)[1]\n            stim.PauliString(\"+X\")\n\n            >>> def pseudo_post_select(qubit, desired_result):\n            ...     m, kick = s.measure_kickback(qubit)\n            ...     if m != desired_result:\n            ...         if kick is None:\n            ...             raise ValueError(\"Post-selected the impossible!\")\n            ...         s.do(kick)\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.cnot(0, 1)\n            >>> s.cnot(0, 2)\n            >>> pseudo_post_select(qubit=2, desired_result=True)\n            >>> s.measure_many(0, 1, 2)\n            [True, True, True]\n        \"\"\"\n    def measure_many(\n        self,\n        *targets,\n    ) -> List[bool]:\n        \"\"\"Measures multiple qubits.\n\n        Args:\n            *targets: The indices of the qubits to measure.\n\n        Returns:\n            The measurement results as a list of bools.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.x(1)\n            >>> s.measure_many(0, 1)\n            [False, True]\n        \"\"\"\n    def measure_observable(\n        self,\n        observable: stim.PauliString,\n        *,\n        flip_probability: float = 0.0,\n    ) -> bool:\n        \"\"\"Measures an pauli string observable, as if by an MPP instruction.\n\n        Args:\n            observable: The observable to measure, specified as a stim.PauliString.\n            flip_probability: Probability of the recorded measurement result being\n                flipped.\n\n        Returns:\n            The result of the measurement.\n\n            The result is also recorded into the measurement record.\n\n        Raises:\n            ValueError: The given pauli string isn't Hermitian, or the given probability\n                isn't a valid probability.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.cnot(0, 1)\n\n            >>> s.measure_observable(stim.PauliString(\"XX\"))\n            False\n\n            >>> s.measure_observable(stim.PauliString(\"YY\"))\n            True\n\n            >>> s.measure_observable(stim.PauliString(\"-ZZ\"))\n            True\n        \"\"\"\n    @property\n    def num_qubits(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of qubits currently being tracked by the simulator.\n\n        Note that the number of qubits being tracked will implicitly increase if qubits\n        beyond the current limit are touched. Untracked qubits are always assumed to be\n        in the |0> state.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.num_qubits\n            0\n            >>> s.h(2)\n            >>> s.num_qubits\n            3\n        \"\"\"\n    def peek_bloch(\n        self,\n        target: int,\n    ) -> stim.PauliString:\n        \"\"\"Returns the state of the qubit as a single-qubit stim.PauliString stabilizer.\n\n        This is a non-physical operation. It reports information about the qubit without\n        disturbing it.\n\n        Args:\n            target: The qubit to peek at.\n\n        Returns:\n            stim.PauliString(\"I\"):\n                The qubit is entangled. Its bloch vector is x=y=z=0.\n            stim.PauliString(\"+Z\"):\n                The qubit is in the |0> state. Its bloch vector is z=+1, x=y=0.\n            stim.PauliString(\"-Z\"):\n                The qubit is in the |1> state. Its bloch vector is z=-1, x=y=0.\n            stim.PauliString(\"+Y\"):\n                The qubit is in the |i> state. Its bloch vector is y=+1, x=z=0.\n            stim.PauliString(\"-Y\"):\n                The qubit is in the |-i> state. Its bloch vector is y=-1, x=z=0.\n            stim.PauliString(\"+X\"):\n                The qubit is in the |+> state. Its bloch vector is x=+1, y=z=0.\n            stim.PauliString(\"-X\"):\n                The qubit is in the |-> state. Its bloch vector is x=-1, y=z=0.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+Z\")\n            >>> s.x(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"-Z\")\n            >>> s.h(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"-X\")\n            >>> s.sqrt_x(1)\n            >>> s.peek_bloch(1)\n            stim.PauliString(\"-Y\")\n            >>> s.cz(0, 1)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+_\")\n        \"\"\"\n    def peek_observable_expectation(\n        self,\n        observable: stim.PauliString,\n    ) -> int:\n        \"\"\"Determines the expected value of an observable.\n\n        Because the simulator's state is always a stabilizer state, the expectation will\n        always be exactly -1, 0, or +1.\n\n        This is a non-physical operation.\n        It reports information about the quantum state without disturbing it.\n\n        Args:\n            observable: The observable to determine the expected value of.\n                This observable must have a real sign, not an imaginary sign.\n\n        Returns:\n            +1: Observable will be deterministically false when measured.\n            -1: Observable will be deterministically true when measured.\n            0: Observable will be random when measured.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.peek_observable_expectation(stim.PauliString(\"+Z\"))\n            1\n            >>> s.peek_observable_expectation(stim.PauliString(\"+X\"))\n            0\n            >>> s.peek_observable_expectation(stim.PauliString(\"-Z\"))\n            -1\n\n            >>> s.do(stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ... '''))\n            >>> queries = ['XX', 'YY', 'ZZ', '-ZZ', 'ZI', 'II', 'IIZ']\n            >>> for q in queries:\n            ...     print(q, s.peek_observable_expectation(stim.PauliString(q)))\n            XX 1\n            YY -1\n            ZZ 1\n            -ZZ -1\n            ZI 0\n            II 1\n            IIZ 1\n        \"\"\"\n    def peek_x(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns the expected value of a qubit's X observable.\n\n        Because the simulator's state is always a stabilizer state, the expectation will\n        always be exactly -1, 0, or +1.\n\n        This is a non-physical operation.\n        It reports information about the quantum state without disturbing it.\n\n        Args:\n            target: The qubit to analyze.\n\n        Returns:\n            +1: Qubit is in the |+> state.\n            -1: Qubit is in the |-> state.\n            0: Qubit is in some other state.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_z(0)\n            >>> s.peek_x(0)\n            0\n            >>> s.reset_x(0)\n            >>> s.peek_x(0)\n            1\n            >>> s.z(0)\n            >>> s.peek_x(0)\n            -1\n        \"\"\"\n    def peek_y(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns the expected value of a qubit's Y observable.\n\n        Because the simulator's state is always a stabilizer state, the expectation will\n        always be exactly -1, 0, or +1.\n\n        This is a non-physical operation.\n        It reports information about the quantum state without disturbing it.\n\n        Args:\n            target: The qubit to analyze.\n\n        Returns:\n            +1: Qubit is in the |i> state.\n            -1: Qubit is in the |-i> state.\n            0: Qubit is in some other state.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_z(0)\n            >>> s.peek_y(0)\n            0\n            >>> s.reset_y(0)\n            >>> s.peek_y(0)\n            1\n            >>> s.z(0)\n            >>> s.peek_y(0)\n            -1\n        \"\"\"\n    def peek_z(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns the expected value of a qubit's Z observable.\n\n        Because the simulator's state is always a stabilizer state, the expectation will\n        always be exactly -1, 0, or +1.\n\n        This is a non-physical operation.\n        It reports information about the quantum state without disturbing it.\n\n        Args:\n            target: The qubit to analyze.\n\n        Returns:\n            +1: Qubit is in the |0> state.\n            -1: Qubit is in the |1> state.\n            0: Qubit is in some other state.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.peek_z(0)\n            0\n            >>> s.reset_z(0)\n            >>> s.peek_z(0)\n            1\n            >>> s.x(0)\n            >>> s.peek_z(0)\n            -1\n        \"\"\"\n    def postselect_observable(\n        self,\n        observable: stim.PauliString,\n        *,\n        desired_value: bool = False,\n    ) -> None:\n        \"\"\"Projects into a desired observable, or raises an exception if it was impossible.\n\n        Postselecting an observable forces it to collapse to a specific eigenstate,\n        as if it was measured and that state was the result of the measurement.\n\n        Args:\n            observable: The observable to postselect, specified as a pauli string.\n                The pauli string's sign must be -1 or +1 (not -i or +i).\n            desired_value:\n                False (default): Postselect into the +1 eigenstate of the observable.\n                True: Postselect into the -1 eigenstate of the observable.\n\n        Raises:\n            ValueError:\n                The given observable had an imaginary sign.\n                OR\n                The postselection was impossible. The observable was in the opposite\n                eigenstate, so measuring it would never ever return the desired result.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.postselect_observable(stim.PauliString(\"+XX\"))\n            >>> s.postselect_observable(stim.PauliString(\"+ZZ\"))\n            >>> s.peek_observable_expectation(stim.PauliString(\"+YY\"))\n            -1\n        \"\"\"\n    def postselect_x(\n        self,\n        targets: Union[int, Iterable[int]],\n        *,\n        desired_value: bool,\n    ) -> None:\n        \"\"\"Postselects qubits in the X basis, or raises an exception.\n\n        Postselecting a qubit forces it to collapse to a specific state, as\n        if it was measured and that state was the result of the measurement.\n\n        Args:\n            targets: The qubit index or indices to postselect.\n            desired_value:\n                False: postselect targets into the |+> state.\n                True: postselect targets into the |-> state.\n\n        Raises:\n            ValueError:\n                The postselection failed. One of the qubits was in a state\n                orthogonal to the desired state, so it was literally\n                impossible for a measurement of the qubit to return the\n                desired result.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.peek_x(0)\n            0\n            >>> s.postselect_x(0, desired_value=False)\n            >>> s.peek_x(0)\n            1\n            >>> s.h(0)\n            >>> s.peek_x(0)\n            0\n            >>> s.postselect_x(0, desired_value=True)\n            >>> s.peek_x(0)\n            -1\n        \"\"\"\n    def postselect_y(\n        self,\n        targets: Union[int, Iterable[int]],\n        *,\n        desired_value: bool,\n    ) -> None:\n        \"\"\"Postselects qubits in the Y basis, or raises an exception.\n\n        Postselecting a qubit forces it to collapse to a specific state, as\n        if it was measured and that state was the result of the measurement.\n\n        Args:\n            targets: The qubit index or indices to postselect.\n            desired_value:\n                False: postselect targets into the |i> state.\n                True: postselect targets into the |-i> state.\n\n        Raises:\n            ValueError:\n                The postselection failed. One of the qubits was in a state\n                orthogonal to the desired state, so it was literally\n                impossible for a measurement of the qubit to return the\n                desired result.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.peek_y(0)\n            0\n            >>> s.postselect_y(0, desired_value=False)\n            >>> s.peek_y(0)\n            1\n            >>> s.reset_x(0)\n            >>> s.peek_y(0)\n            0\n            >>> s.postselect_y(0, desired_value=True)\n            >>> s.peek_y(0)\n            -1\n        \"\"\"\n    def postselect_z(\n        self,\n        targets: Union[int, Iterable[int]],\n        *,\n        desired_value: bool,\n    ) -> None:\n        \"\"\"Postselects qubits in the Z basis, or raises an exception.\n\n        Postselecting a qubit forces it to collapse to a specific state, as if it was\n        measured and that state was the result of the measurement.\n\n        Args:\n            targets: The qubit index or indices to postselect.\n            desired_value:\n                False: postselect targets into the |0> state.\n                True: postselect targets into the |1> state.\n\n        Raises:\n            ValueError:\n                The postselection failed. One of the qubits was in a state\n                orthogonal to the desired state, so it was literally\n                impossible for a measurement of the qubit to return the\n                desired result.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.peek_z(0)\n            0\n            >>> s.postselect_z(0, desired_value=False)\n            >>> s.peek_z(0)\n            1\n            >>> s.h(0)\n            >>> s.peek_z(0)\n            0\n            >>> s.postselect_z(0, desired_value=True)\n            >>> s.peek_z(0)\n            -1\n        \"\"\"\n    def reset(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Resets qubits to the |0> state.\n\n        Args:\n            *targets: The indices of the qubits to reset.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.x(0)\n            >>> s.reset(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+Z\")\n        \"\"\"\n    def reset_x(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Resets qubits to the |+> state.\n\n        Args:\n            *targets: The indices of the qubits to reset.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+X\")\n        \"\"\"\n    def reset_y(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Resets qubits to the |i> state.\n\n        Args:\n            *targets: The indices of the qubits to reset.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_y(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+Y\")\n        \"\"\"\n    def reset_z(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Resets qubits to the |0> state.\n\n        Args:\n            *targets: The indices of the qubits to reset.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.reset_z(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+Z\")\n        \"\"\"\n    def s(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.s(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Y -X +Z\n        \"\"\"\n    def s_dag(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_Z_DAG gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.s_dag(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -Y +X +Z\n        \"\"\"\n    def set_inverse_tableau(\n        self,\n        new_inverse_tableau: stim.Tableau,\n    ) -> None:\n        \"\"\"Overwrites the simulator's internal state with the given inverse tableau.\n\n        The inverse tableau specifies how Pauli product observables of qubits at the\n        current time transform into equivalent Pauli product observables at the\n        beginning of time, when all qubits were in the |0> state. For example, if the Z\n        observable on qubit 5 maps to a product of Z observables at the start of time\n        then a Z basis measurement on qubit 5 will be deterministic and equal to the\n        sign of the product. Whereas if it mapped to a product of observables including\n        an X or a Y then the Z basis measurement would be random.\n\n        Any qubits not within the length of the tableau are implicitly in the |0> state.\n\n        Args:\n            new_inverse_tableau: The tableau to overwrite the internal state with.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> t = stim.Tableau.random(4)\n            >>> s.set_inverse_tableau(t)\n            >>> s.current_inverse_tableau() == t\n            True\n        \"\"\"\n    def set_num_qubits(\n        self,\n        new_num_qubits: int,\n    ) -> None:\n        \"\"\"Resizes the simulator's internal state.\n\n        This forces the simulator's internal state to track exactly the qubits whose\n        indices are in `range(new_num_qubits)`.\n\n        Note that untracked qubits are always assumed to be in the |0> state. Therefore,\n        calling this method will effectively force any qubit whose index is outside\n        `range(new_num_qubits)` to be reset to |0>.\n\n        Note that this method does not prevent future operations from implicitly\n        expanding the size of the tracked state (e.g. setting the number of qubits to 5\n        will not prevent a Hadamard from then being applied to qubit 100, increasing the\n        number of qubits back to 101).\n\n        Args:\n            new_num_qubits: The length of the range of qubits the internal simulator\n                should be tracking.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> len(s.current_inverse_tableau())\n            0\n\n            >>> s.set_num_qubits(5)\n            >>> len(s.current_inverse_tableau())\n            5\n\n            >>> s.x(0, 1, 2, 3)\n            >>> s.set_num_qubits(2)\n            >>> s.measure_many(0, 1, 2, 3)\n            [True, True, False, False]\n        \"\"\"\n    def set_state_from_stabilizers(\n        self,\n        stabilizers: Iterable[stim.PauliString],\n        *,\n        allow_redundant: bool = False,\n        allow_underconstrained: bool = False,\n    ) -> None:\n        \"\"\"Sets the tableau simulator's state to a state satisfying the given stabilizers.\n\n        The old quantum state is completely overwritten, even if the new state is\n        underconstrained by the given stabilizers. The number of qubits is changed to\n        exactly match the number of qubits in the longest given stabilizer.\n\n        Args:\n            stabilizers: A list of `stim.PauliString`s specifying the stabilizers that\n                the new state must have. It is permitted for stabilizers to have\n                different lengths. All stabilizers are padded up to the length of the\n                longest stabilizer by appending identity terms.\n            allow_redundant: Defaults to False. If set to False, then the given\n                stabilizers must all be independent. If any one of them is a product of\n                the others (including the empty product), an exception will be raised.\n                If set to True, then redundant stabilizers are simply ignored.\n            allow_underconstrained: Defaults to False. If set to False, then the given\n                stabilizers must form a complete set of generators. They must exactly\n                specify the desired stabilizer state, with no degrees of freedom left\n                over. For an n-qubit state there must be n independent stabilizers. If\n                set to True, then there can be leftover degrees of freedom which can be\n                set arbitrarily.\n\n        Returns:\n            Nothing. Mutates the states of the simulator to match the desired\n            stabilizers.\n\n            Guarantees that self.current_inverse_tableau().inverse_z_output(k) will be\n            equal to the k'th independent stabilizer from the `stabilizers` argument.\n\n        Raises:\n            ValueError:\n                A stabilizer is redundant but allow_redundant=True wasn't set.\n                OR\n                The given stabilizers are contradictory (e.g. \"+Z\" and \"-Z\" both\n                specified).\n                OR\n                The given stabilizers anticommute (e.g. \"+Z\" and \"+X\" both specified).\n                OR\n                The stabilizers left behind a degree of freedom but\n                allow_underconstrained=True wasn't set.\n                OR\n                A stabilizer has an imaginary sign (i or -i).\n\n        Examples:\n\n            >>> import stim\n            >>> tab_sim = stim.TableauSimulator()\n            >>> tab_sim.set_state_from_stabilizers([\n            ...     stim.PauliString(\"XX\"),\n            ...     stim.PauliString(\"ZZ\"),\n            ... ])\n            >>> tab_sim.current_inverse_tableau().inverse()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n\n            >>> tab_sim.set_state_from_stabilizers([\n            ...     stim.PauliString(\"XX_\"),\n            ...     stim.PauliString(\"ZZ_\"),\n            ...     stim.PauliString(\"-YY_\"),\n            ...     stim.PauliString(\"\"),\n            ... ], allow_underconstrained=True, allow_redundant=True)\n            >>> tab_sim.current_inverse_tableau().inverse()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z__\"),\n                    stim.PauliString(\"+_X_\"),\n                    stim.PauliString(\"+__X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX_\"),\n                    stim.PauliString(\"+ZZ_\"),\n                    stim.PauliString(\"+__Z\"),\n                ],\n            )\n        \"\"\"\n    def set_state_from_state_vector(\n        self,\n        state_vector: Iterable[float],\n        *,\n        endian: Literal[\"little\", \"big\"],\n    ) -> None:\n        \"\"\"Sets the simulator's state to a superposition specified by an amplitude vector.\n\n        Args:\n            state_vector: A list of complex amplitudes specifying a superposition. The\n                vector must correspond to a state that is reachable using Clifford\n                operations, and must be normalized (i.e. it must be a unit vector).\n            endian:\n                \"little\": state vector is in little endian order, where higher index\n                    qubits correspond to larger changes in the state index.\n                \"big\": state vector is in big endian order, where higher index qubits\n                    correspond to smaller changes in the state index.\n\n        Returns:\n            Nothing. Mutates the states of the simulator to match the desired state.\n\n        Raises:\n            ValueError:\n                The given state vector isn't a list of complex values specifying a\n                stabilizer state.\n                OR\n                The given endian value isn't 'little' or 'big'.\n\n        Examples:\n\n            >>> import stim\n            >>> tab_sim = stim.TableauSimulator()\n            >>> tab_sim.set_state_from_state_vector([\n            ...     0.5**0.5,\n            ...     0.5**0.5 * 1j,\n            ... ], endian='little')\n            >>> tab_sim.current_inverse_tableau().inverse()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Y\"),\n                ],\n            )\n            >>> tab_sim.set_state_from_state_vector([\n            ...     0.5**0.5,\n            ...     0,\n            ...     0,\n            ...     0.5**0.5,\n            ... ], endian='little')\n            >>> tab_sim.current_inverse_tableau().inverse()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n        \"\"\"\n    def sqrt_x(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.sqrt_x(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Z -Y\n        \"\"\"\n    def sqrt_x_dag(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_X_DAG gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.sqrt_x_dag(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X -Z +Y\n        \"\"\"\n    def sqrt_y(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.sqrt_y(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -Z +Y +X\n        \"\"\"\n    def sqrt_y_dag(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_Y_DAG gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.sqrt_y_dag(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Z +Y -X\n        \"\"\"\n    def state_vector(\n        self,\n        *,\n        endian: Literal[\"little\", \"big\"] = 'little',\n    ) -> np.ndarray[np.complex64]:\n        \"\"\"Returns a wavefunction for the simulator's current state.\n\n        This function takes O(n * 2**n) time and O(2**n) space, where n is the number of\n        qubits. The computation is done by initialization a random state vector and\n        iteratively projecting it into the +1 eigenspace of each stabilizer of the\n        state. The state is then canonicalized so that zero values are actually exactly\n        0, and so that the first non-zero entry is positive.\n\n        Args:\n            endian:\n                \"little\" (default): state vector is in little endian order, where higher\n                    index qubits correspond to larger changes in the state index.\n                \"big\": state vector is in big endian order, where higher index qubits\n                    correspond to smaller changes in the state index.\n\n        Returns:\n            A `numpy.ndarray[numpy.complex64]` of computational basis amplitudes.\n\n            If the result is in little endian order then the amplitude at offset\n            b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n            computational basis state where the qubit with index 0 is storing the bit\n            b_0, the qubit with index 1 is storing the bit b_1, etc.\n\n            If the result is in big endian order then the amplitude at offset\n            b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n            computational basis state where the qubit with index 0 is storing the bit\n            b_{n-1}, the qubit with index 1 is storing the bit b_{n-2}, etc.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> s = stim.TableauSimulator()\n            >>> s.x(2)\n            >>> s.state_vector(endian='little')\n            array([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                  dtype=complex64)\n\n            >>> s.state_vector(endian='big')\n            array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                  dtype=complex64)\n\n            >>> s.sqrt_x(1, 2)\n            >>> s.state_vector()\n            array([0.5+0.j , 0. +0.j , 0. -0.5j, 0. +0.j , 0. +0.5j, 0. +0.j ,\n                   0.5+0.j , 0. +0.j ], dtype=complex64)\n        \"\"\"\n    def swap(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a swap gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.swap(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +Y +X +X +Z\n        \"\"\"\n    def x(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Pauli X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.x(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X -Y -Z\n        \"\"\"\n    def x_error(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies X errors to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n            p: The chance of the X error being applied,\n                independently, to each qubit.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.x_error(0, 1, 2, p=0.01)\n        \"\"\"\n    def xcx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an X-controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.xcx(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n        \"\"\"\n    def xcy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an X-controlled Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.xcy(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +_ +_\n        \"\"\"\n    def xcz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an X-controlled Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.xcz(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +_ +_\n        \"\"\"\n    def y(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Pauli Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.y(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -X +Y -Z\n        \"\"\"\n    def y_error(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies Y errors to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n            p: The chance of the Y error being applied,\n                independently, to each qubit.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.y_error(0, 1, 2, p=0.01)\n        \"\"\"\n    def ycx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Y-controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.ycx(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def ycy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Y-controlled Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.ycy(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +_ +_\n        \"\"\"\n    def ycz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Y-controlled Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.ycz(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +_ +_\n        \"\"\"\n    def z(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Pauli Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.z(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -X -Y +Z\n        \"\"\"\n    def z_error(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies Z errors to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n            p: The chance of the Z error being applied,\n                independently, to each qubit.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.z_error(0, 1, 2, p=0.01)\n        \"\"\"\n    def zcx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.zcx(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def zcy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.zcy(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n        \"\"\"\n    def zcz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.zcz(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n@overload\ndef gate_data(\n    name: str,\n) -> stim.GateData:\n    pass\n@overload\ndef gate_data(\n) -> Dict[str, stim.GateData]:\n    pass\ndef gate_data(\n    name: Optional[str] = None,\n) -> Union[str, Dict[str, stim.GateData]]:\n    \"\"\"Returns gate data for the given named gate, or all gates.\n\n    Examples:\n        >>> import stim\n        >>> stim.gate_data('cnot').aliases\n        ['CNOT', 'CX', 'ZCX']\n        >>> stim.gate_data('cnot').is_two_qubit_gate\n        True\n        >>> gate_dict = stim.gate_data()\n        >>> len(gate_dict) > 50\n        True\n        >>> gate_dict['MX'].produces_measurements\n        True\n    \"\"\"\ndef main(\n    *,\n    command_line_args: List[str],\n) -> int:\n    \"\"\"Runs the command line tool version of stim on the given arguments.\n\n    Note that by default any input will be read from stdin, any output\n    will print to stdout (as opposed to being intercepted). For most\n    commands, you can use arguments like `--out` to write to a file\n    instead of stdout and `--in` to read from a file instead of stdin.\n\n    Returns:\n        An exit code (0 means success, not zero means failure).\n\n    Raises:\n        A large variety of errors, depending on what you are doing and\n        how it failed! Beware that many errors are caught by the main\n        method itself and printed to stderr, with the only indication\n        that something went wrong being the return code.\n\n    Example:\n        >>> import stim\n        >>> import tempfile\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = f'{d}/tmp.out'\n        ...     return_code = stim.main(command_line_args=[\n        ...         \"gen\",\n        ...         \"--code=repetition_code\",\n        ...         \"--task=memory\",\n        ...         \"--rounds=1000\",\n        ...         \"--distance=2\",\n        ...         \"--out\",\n        ...         path,\n        ...     ])\n        ...     assert return_code == 0\n        ...     with open(path) as f:\n        ...         print(f.read(), end='')\n        # Generated repetition_code circuit.\n        # task: memory\n        # rounds: 1000\n        # distance: 2\n        # before_round_data_depolarization: 0\n        # before_measure_flip_probability: 0\n        # after_reset_flip_probability: 0\n        # after_clifford_depolarization: 0\n        # layout:\n        # L0 Z1 d2\n        # Legend:\n        #     d# = data qubit\n        #     L# = data qubit with logical observable crossing\n        #     Z# = measurement qubit\n        R 0 1 2\n        TICK\n        CX 0 1\n        TICK\n        CX 2 1\n        TICK\n        MR 1\n        DETECTOR(1, 0) rec[-1]\n        REPEAT 999 {\n            TICK\n            CX 0 1\n            TICK\n            CX 2 1\n            TICK\n            MR 1\n            SHIFT_COORDS(0, 1)\n            DETECTOR(1, 0) rec[-1] rec[-2]\n        }\n        M 0 2\n        DETECTOR(1, 1) rec[-1] rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\"\n@overload\ndef read_shot_data_file(\n    *,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    bit_packed: bool = False,\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n) -> np.ndarray:\n    pass\n@overload\ndef read_shot_data_file(\n    *,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    bit_packed: bool = False,\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n    separate_observables: Literal[True],\n) -> Tuple[np.ndarray, np.ndarray]:\n    pass\ndef read_shot_data_file(\n    *,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    bit_packed: bool = False,\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n    separate_observables: bool = False,\n) -> Union[Tuple[np.ndarray, np.ndarray], np.ndarray]:\n    \"\"\"Reads shot data, such as measurement samples, from a file.\n\n    Args:\n        path: The path to the file to read the data from.\n        format: The format that the data is stored in, such as 'b8'.\n            See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        bit_packed: Defaults to false. Determines whether the result is a bool_\n            numpy array with one bit per byte, or a uint8 numpy array with 8 bits\n            per byte.\n        num_measurements: How many measurements there are per shot.\n        num_detectors: How many detectors there are per shot.\n        num_observables: How many observables there are per shot.\n            Note that this only refers to observables *stored in the file*, not to\n            observables from the original circuit that was sampled.\n        separate_observables: When set to True, the result is a tuple of two arrays,\n            one containing the detection event data and the other containing the\n            observable data, instead of a single array.\n\n    Returns:\n        If separate_observables=True:\n            A tuple (dets, obs) of numpy arrays containing the loaded data.\n\n            If bit_packed=False:\n                dets.dtype = np.bool_\n                dets.shape = (num_shots, num_measurements + num_detectors)\n                det bit b from shot s is at dets[s, b]\n                obs.dtype = np.bool_\n                obs.shape = (num_shots, num_observables)\n                obs bit b from shot s is at dets[s, b]\n            If bit_packed=True:\n                dets.dtype = np.uint8\n                dets.shape = (num_shots, math.ceil(\n                    (num_measurements + num_detectors) / 8))\n                obs.dtype = np.uint8\n                obs.shape = (num_shots, math.ceil(num_observables / 8))\n                det bit b from shot s is at dets[s, b // 8] & (1 << (b % 8))\n                obs bit b from shot s is at obs[s, b // 8] & (1 << (b % 8))\n\n        If separate_observables=False:\n            A numpy array containing the loaded data.\n\n            If bit_packed=False:\n                dtype = np.bool_\n                shape = (num_shots,\n                         num_measurements + num_detectors + num_observables)\n                bit b from shot s is at result[s, b]\n            If bit_packed=True:\n                dtype = np.uint8\n                shape = (num_shots, math.ceil(\n                    (num_measurements + num_detectors + num_observables) / 8))\n                bit b from shot s is at result[s, b // 8] & (1 << (b % 8))\n\n    Examples:\n        >>> import stim\n        >>> import pathlib\n        >>> import tempfile\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = pathlib.Path(d) / 'shots'\n        ...     with open(path, 'w') as f:\n        ...         print(\"0000\", file=f)\n        ...         print(\"0101\", file=f)\n        ...\n        ...     read = stim.read_shot_data_file(\n        ...         path=str(path),\n        ...         format='01',\n        ...         num_measurements=4)\n        >>> read\n        array([[False, False, False, False],\n               [False,  True, False,  True]])\n    \"\"\"\ndef target_combined_paulis(\n    paulis: Union[stim.PauliString, List[stim.GateTarget]],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a list of targets encoding a pauli product for instructions like MPP.\n\n    Args:\n        paulis: The paulis to encode into the targets. This can be a\n            `stim.PauliString` or a list of pauli targets from `stim.target_x`,\n            `stim.target_pauli`, etc.\n        invert: Defaults to False. If True, the product is inverted (like \"!X2*Y3\").\n            Note that this is in addition to any inversions specified by the\n            `paulis` argument.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     *stim.target_combined_paulis(stim.PauliString(\"-XYZ\")),\n        ...     *stim.target_combined_paulis([stim.target_x(2), stim.target_y(5)]),\n        ...     *stim.target_combined_paulis([stim.target_z(9)], invert=True),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP !X0*Y1*Z2 X2*Y5 !Z9\n        ''')\n    \"\"\"\ndef target_combiner(\n) -> stim.GateTarget:\n    \"\"\"Returns a target combiner that can be used to build Pauli products.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*Y3*Z5\n        ''')\n    \"\"\"\ndef target_inv(\n    qubit_index: Union[int, stim.GateTarget],\n) -> stim.GateTarget:\n    \"\"\"Returns a target flagged as inverted.\n\n    Inverted targets are used to indicate measurement results should be flipped.\n\n    Args:\n        qubit_index: The underlying qubit index of the inverted target.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"M\", [2, stim.target_inv(3)])\n        >>> circuit\n        stim.Circuit('''\n            M 2 !3\n        ''')\n\n    For example, the '!1' in 'M 0 !1 2' is qubit 1 flagged as inverted,\n    meaning the measurement result from qubit 1 should be inverted when reported.\n    \"\"\"\ndef target_logical_observable_id(\n    index: int,\n) -> stim.DemTarget:\n    \"\"\"Returns a logical observable id identifying a frame change.\n\n    Args:\n        index: The index of the observable.\n\n    Returns:\n        The logical observable target.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.target_logical_observable_id(13)\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) L13\n        ''')\n    \"\"\"\ndef target_pauli(\n    qubit_index: int,\n    pauli: Union[str, int],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a pauli target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        pauli: The pauli gate to use. This can either be a string identifying the\n            pauli by name (\"x\", \"X\", \"y\", \"Y\", \"z\", or \"Z\") or an integer following\n            the convention (1=X, 2=Y, 3=Z). Setting this argument to \"I\" or to\n            0 will return a qubit target instead of a pauli target.\n        invert: Defaults to False. If True, the target is inverted (like \"!X10\"),\n            indicating that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_pauli(2, \"X\"),\n        ...     stim.target_combiner(),\n        ...     stim.target_pauli(3, \"y\", invert=True),\n        ...     stim.target_pauli(5, 3),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3 Z5\n        ''')\n\n        >>> circuit.append(\"M\", [\n        ...     stim.target_pauli(7, \"I\"),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3 Z5\n            M 7\n        ''')\n    \"\"\"\ndef target_rec(\n    lookback_index: int,\n) -> stim.GateTarget:\n    \"\"\"Returns a measurement record target with the given lookback.\n\n    Measurement record targets are used to refer back to the measurement record;\n    the list of measurements that have been performed so far. Measurement record\n    targets always specify an index relative to the *end* of the measurement record.\n    The latest measurement is `stim.target_rec(-1)`, the next most recent\n    measurement is `stim.target_rec(-2)`, and so forth. Indexing is done this way\n    in order to make it possible to write loops.\n\n    Args:\n        lookback_index: A negative integer indicating how far to look back, relative\n            to the end of the measurement record.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"M\", [5, 7, 11])\n        >>> circuit.append(\"CX\", [stim.target_rec(-2), 3])\n        >>> circuit\n        stim.Circuit('''\n            M 5 7 11\n            CX rec[-2] 3\n        ''')\n    \"\"\"\ndef target_relative_detector_id(\n    index: int,\n) -> stim.DemTarget:\n    \"\"\"Returns a relative detector id (e.g. \"D5\" in a .dem file).\n\n    Args:\n        index: The index of the detector, relative to the current detector offset.\n\n    Returns:\n        The relative detector target.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.target_relative_detector_id(13)\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) D13\n        ''')\n    \"\"\"\ndef target_separator(\n) -> stim.DemTarget:\n    \"\"\"Returns a target separator (e.g. \"^\" in a .dem file).\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.target_relative_detector_id(1),\n        ...     stim.target_separator(),\n        ...     stim.target_relative_detector_id(2),\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) D1 ^ D2\n        ''')\n    \"\"\"\ndef target_sweep_bit(\n    sweep_bit_index: int,\n) -> stim.GateTarget:\n    \"\"\"Returns a sweep bit target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        sweep_bit_index: The index of the sweep bit to target.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"CX\", [stim.target_sweep_bit(2), 5])\n        >>> circuit\n        stim.Circuit('''\n            CX sweep[2] 5\n        ''')\n    \"\"\"\ndef target_x(\n    qubit_index: Union[int, stim.GateTarget],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a Pauli X target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        invert: Defaults to False. If True, the target is inverted (indicating\n            that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3, invert=True),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3*Z5\n        ''')\n    \"\"\"\ndef target_y(\n    qubit_index: Union[int, stim.GateTarget],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a Pauli Y target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        invert: Defaults to False. If True, the target is inverted (indicating\n            that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3, invert=True),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3*Z5\n        ''')\n    \"\"\"\ndef target_z(\n    qubit_index: Union[int, stim.GateTarget],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a Pauli Z target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        invert: Defaults to False. If True, the target is inverted (indicating\n            that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3, invert=True),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3*Z5\n        ''')\n    \"\"\"\ndef write_shot_data_file(\n    *,\n    data: np.ndarray,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n) -> None:\n    \"\"\"Writes shot data, such as measurement samples, to a file.\n\n    Args:\n        data: The data to write to the file. This must be a numpy array. The dtype\n            of the array determines whether or not the data is bit packed, and the\n            shape must match the bits per shot.\n\n            dtype=np.bool_: Not bit packed. Shape must be\n                (num_shots, num_measurements + num_detectors + num_observables).\n            dtype=np.uint8: Yes bit packed. Shape must be\n                (num_shots, math.ceil(\n                    (num_measurements + num_detectors + num_observables) / 8)).\n        path: The path to the file to write the data to.\n        format: The format that the data is stored in, such as 'b8'.\n            See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        num_measurements: How many measurements there are per shot.\n        num_detectors: How many detectors there are per shot.\n        num_observables: How many observables there are per shot.\n            Note that this only refers to observables *in the given shot data*, not\n            to observables from the original circuit that was sampled.\n\n    Examples:\n        >>> import stim\n        >>> import pathlib\n        >>> import tempfile\n        >>> import numpy as np\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = pathlib.Path(d) / 'shots'\n        ...     shot_data = np.array([\n        ...         [0, 1, 0],\n        ...         [0, 1, 1],\n        ...     ], dtype=np.bool_)\n        ...\n        ...     stim.write_shot_data_file(\n        ...         path=str(path),\n        ...         data=shot_data,\n        ...         format='01',\n        ...         num_measurements=3)\n        ...\n        ...     with open(path) as f:\n        ...         written = f.read()\n        >>> written\n        '010\\n011\\n'\n    \"\"\"\n"
  },
  {
    "path": "doc/usage_command_line.md",
    "content": "# Stim command line reference\n\n## Index\n\n- [stim analyze_errors](#analyze_errors)\n- [stim convert](#convert)\n- [stim detect](#detect)\n- [stim diagram](#diagram)\n- [stim explain_errors](#explain_errors)\n- [stim gen](#gen)\n- [stim help](#help)\n- [stim m2d](#m2d)\n- [stim repl](#repl)\n- [stim sample](#sample)\n- [stim sample_dem](#sample_dem)\n## Commands\n\n<a name=\"analyze_errors\"></a>\n### stim analyze_errors\n\n```\nNAME\n    stim analyze_errors\n\nSYNOPSIS\n    stim analyze_errors \\\n        [--allow_gauge_detectors] \\\n        [--approximate_disjoint_errors [probability]] \\\n        [--block_decompose_from_introducing_remnant_edges] \\\n        [--decompose_errors] \\\n        [--fold_loops] \\\n        [--ignore_decomposition_failures] \\\n        [--in filepath] \\\n        [--out filepath]\n\nDESCRIPTION\n    Converts a circuit into a detector error model.\n\nOPTIONS\n    --allow_gauge_detectors\n        Allows non-deterministic detectors to appear in the circuit.\n\n        Normally (without `--allow_gauge_detectors`), when a detector's\n        detecting region anti-commutes with a reset or measurement, stim\n        will raise an exception when analyzing the circuit. When\n        `--allow_gauge_detectors` is set, stim will instead append an error\n        mechanism into the detector error model that has a probability of\n        50% and flips all the detectors that anticommute with the operation.\n\n        This is potentially useful in situations where the layout of\n        detectors is supposed to stay fixed despite variations in the\n        circuit structure. Decoders can interpret the existence of the 50%\n        error as a weight 0 edge saying that the detectors should be fused\n        together.\n\n        For example, in the following stim circuit, the two detectors each\n        anticommute with the reset operation:\n\n            R 0\n            H 0\n            CNOT 0 1\n            M 0 1\n            DETECTOR rec[-1]\n            DETECTOR rec[-2]\n\n        Without `--allow_gauge_detectors`, stim will raise an exception when\n        analyzing this circuit. With `--allow_gauge_detectors`, stim will\n        add `error(0.5) D1 D2` to the output detector error model.\n\n        BEWARE that gauge detectors are very tricky to work with, and not\n        necessarily supported by all tools (even within stim itself). For\n        example, when converting from measurements to detection events,\n        there isn't a single choice for whether or not each individual gauge\n        detector produced a detection event. This means that it is valid\n        behavior for one conversion from measurements to detection events\n        to give different results from another, as long as the gauge\n        detectors that anticommute with the same operations flip together in\n        a consistent fashion that respects the structure of the circuit.\n\n\n    --approximate_disjoint_errors\n        Allows disjoint errors to be approximated during the conversion.\n\n        Detector error models require that all error mechanisms be\n        specified as independent mechanisms. But some of the circuit error\n        mechanisms that Stim allows can express errors that don't correspond\n        to independent mechanisms. For example, the custom error channel\n        `PAULI_CHANNEL_1(0.1, 0.2, 0.0)` can't be expressed exactly as a set\n        of independent error mechanisms. But it can be approximated as an\n        `X_ERROR(0.1)` followed by a `Y_ERROR(0.2)`.\n\n        This flag can be set to any probability between 0 (the default when\n        not specified) and 1 (the default when specified without a value).\n        When set to a value strictly between 0 and 1, this determines the\n        maximum disjoint probability that is allowed to be approximated as\n        an independent probability.\n\n        Without `--approximate_disjoint_errors`, attempting to convert a\n        circuit containing `PAULI_CHANNEL_1(0.1, 0.2, 0.0)` will fail with\n        an error stating an approximation is needed. With\n        `--approximate_disjoint_errors`, the conversion will succeed by\n        approximating the error into an `X_ERROR(0.1)` followed by an\n        independent `Y_ERROR(0.2)`.\n\n        Note that, although `DEPOLARIZE1` and `DEPOLARIZE2` are often\n        defined in terms of disjoint errors, they can be exactly converted\n        into a set of independent errors (unless the probability of the\n        depolarizing error occurring exceeds maximum mixing, which is 75%\n        for `DEPOLARIZE1` and 93.75% for `DEPOLARIZE2`). So the\n        `--approximate_disjoint_errors` flag isn't needed for depolarizing\n        errors that appear in practice.\n\n        The error mechanisms that require approximations are:\n        - PAULI_CHANNEL_1\n        - PAULI_CHANNEL_2\n        - ELSE_CORRELATED_ERROR\n\n        In principle some custom Pauli channels can be converted exactly,\n        but Stim does not currently contain logic that attempts to do this.\n\n\n    --block_decompose_from_introducing_remnant_edges\n        Prevents A*B from being decomposed unless A,B BOTH appear elsewhere.\n\n        Irrelevant unless `--decompose_errors` is specified.\n\n        When `--decompose_errors` is specified, any circuit error that\n        causes more than two detection events must be decomposed into a\n        set of errors with at most two detection events. The main constraint\n        on this process is that it must not use errors that couldn't\n        otherwise occur, since introducing such errors could violate\n        important properties that are used for decoding. For example, in the\n        normal surface code, it is very important that the decoding graphs\n        for X errors and Z errors are disjoint in the bulk, and decomposing\n        an error into a set of errors that violated this property would be\n        disastrous.\n\n        However, a corner case in this logic occurs if an error E1 that\n        produces detection events A*B needs to be decomposed when an error\n        E2 that produces detection events A appears elsewhere but no error\n        producing detection events B appears elsewhere. The detection events\n        B can be produced by both E1 and E2 occurring, but this a\n        combination of two errors and so treating it as one error can cause\n        problems. For example, it can result in the code distance appearing\n        to be smaller than it actually is. Introducing B is referred to as\n        introducing a \"remnant edge\" because B *only* appears in the\n        detector error model as a remnant of removing A from A*B.\n\n        By default, Stim does allow remnant edges to be introduced. Stim\n        will only do this if it is absolutely necessary, but it *will* do\n        it. And there are in fact QEC circuits where the decomposition\n        requires these edges to succeed. But sometimes the presence of a\n        remnant edge is a hint that the DETECTOR declarations in the circuit\n        are subtly wrong. To cause the decomposition process to fail in\n        this case, the `--block_decompose_from_introducing_remnant_edges`\n        can be specified.\n\n\n    --decompose_errors\n        Decomposes errors with many detection events into \"graphlike\" parts.\n\n        When `--decompose_errors` is specified, Stim will suggest how errors\n        that cause more than 2 detection events (non-graphlike errors) can\n        be decomposed into errors with at most 2 detection events (graphlike\n        errors). For example, an error like `error(0.1) D0 D1 D2 D3` may be\n        instead output as `error(0.1) D0 D1 ^ D2 D3` or as\n        `error(0.1) D0 D3 ^ D1 ^ D2`.\n\n        The purpose of this feature is to make matching apply to more cases.\n        A common decoding strategy is \"matching\", where detection events are\n        paired up in order to determine which errors occurred. Matching only\n        works when the Tanner graph of the problem is a graph, not a\n        hypergraph. In other words, it requires all errors to produce at\n        most two detection events. This is a problem, because in practice\n        there are essentially always circuit error mechanisms that produce\n        more than two detection events. For example, in a CSS surface code,\n        Y type errors on the data qubits will produce four detection events.\n        For matching to work in these cases, non-graphlike errors (errors\n        with more than two detection events) need to be approximated as a\n        combination of graphlike errors.\n\n        When Stim is decomposing errors, the main guarantee that it provides\n        is that it will not introduce error mechanisms with symptoms that\n        are otherwise impossible or that would require a combination of\n        non-local errors to actually achieve. Informally, Stim guarantees it\n        will preserve the \"structure\" of the detector error model when\n        suggesting decompositions.\n\n        It's also worth noting that the suggested decompositions are\n        information preserving: the undecomposed model can always be\n        recovered by simply filtering out all `^` characters splitting the\n        errors into suggested components.\n\n        Stim uses two strategies for decomposing errors: intra-channel and\n        inter-channel.\n\n        The *intra-channel* strategy is always applied first, and works by\n        looking at the various detector/observable sets produced by each\n        case of a single noise channel. If some cases are products of other\n        cases, that product is *always* decomposed. For example, suppose\n        that a single qubit depolarizing channel has a `Y5` case that\n        produces four detection events `D0 D1 D2 D3`, an `X5` case that\n        produces two detection events `D0 D1`, and a `Z5` case that produces\n        two detection events `D2 D3`. Because `D0 D1 D2 D3` is the\n        combination of `D0 D1` and `D2 D3`, the `Y5` case will be decomposed\n        into `D0 D1 ^ D2 D3`. An important corner case here is the corner of\n        the CSS surface code, where a Y error has two symptoms which is\n        graphlike but because the intra-channel strategy is aggressive the\n        Y error will still be decomposed into X and Z pieces. This can keep\n        the X and Z decoding graphs disjoint.\n\n        The *inter-channel* strategy is used when an error component is\n        still not graphlike after the intra-channel strategy was applied.\n        This strategy searches over all other error mechanisms looking for a\n        combination that explains the error. If\n        `--block_decompose_from_introducing_remnant_edges` is specified then\n        this must be an exact match, otherwise the match can omit up to two\n        of the symptoms in the error (resulting in the producing of a\n        \"remnant edge\").\n\n        Note that the code implementing these strategies does not special\n        case any Pauli basis. For example, it does not prefer to decompose\n        Y into X*Z as opposed to X into Y*Z. It also does not prefer to\n        decompose YY into IY*YI as opposed to IY into YY*YI. The code\n        operates purely in terms of the sets of symptoms produced by the\n        various cases, with little regard for how those sets were produced.\n\n        If these strategies fail to decompose error into graphlike pieces,\n        Stim will throw an error saying it failed to find a satisfying\n        decomposition.\n\n\n    --fold_loops\n        Allows the output to contain `repeat` blocks.\n\n        This flag substantially improves performance on circuits with\n        `REPEAT` blocks with large repetition counts. The analysis will take\n        less time and the output will be more compact. This option is only\n        OFF by default to maintain strict backwards compatibility of the\n        output.\n\n        When a circuit contains a `REPEAT` block, the structure of the\n        detectors often settles into a form that is identical from iteration\n        to iteration. Specifying the `--fold_loops` option tells Stim to\n        watch for periodicity in the structure of detectors by using a\n        \"tortoise and hare\" algorithm (see\n        https://en.wikipedia.org/wiki/Cycle_detection ).\n        This improves the asymptotic complexity of analyzing the loop from\n        O(total_repetitions) to O(cycle_period).\n\n        Note that, although logical observables can \"cross\" from the end of\n        the loop to the start of the loop without preventing loop folding,\n        detectors CANNOT. If there is any detector introduced after the\n        loop, whose sensitivity region extends to before the loop, loop\n        folding will fail and the code will fall back to flattening the\n        loop. This is disastrous for loops with huge repetition counts (e.g.\n        in the billions) because in that case loop folding is the difference\n        between the error analysis finishing in seconds instead of in days.\n\n\n    --ignore_decomposition_failures\n        Allows non-graphlike errors into the output when decomposing errors.\n\n        Irrelevant unless `--decompose_errors` is specified.\n\n        Without `--ignore_decomposition_failures`, circuit errors that fail\n        to decompose into graphlike detector error model errors will cause\n        an error and abort the conversion process.\n\n        When `--ignore_decomposition_failures` is specified, circuit errors\n        that fail to decompose into graphlike detector error model errors\n        produce non-graphlike detector error models. Whatever processes\n        the detector error model is then responsible for dealing with the\n        undecomposed errors (e.g. a tool may choose to simply ignore them).\n\n\n    --in\n        Chooses the stim circuit file to read the circuit to convert from.\n\n        By default, the circuit is read from stdin. When `--in $FILEPATH` is\n        specified, the circuit is instead read from the file at $FILEPATH.\n\n        The input should be a stim circuit. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n\n    --out\n        Chooses where to write the output detector error model.\n\n        By default, the output is written to stdout. When `--out $FILEPATH`\n        is specified, the output is instead written to the file at $FILEPATH.\n\n        The output is a stim detector error model. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n\nEXAMPLES\n    Example #1\n        >>> cat example_circuit.stim\n        R 0 1\n        X_ERROR(0.125) 0 1\n        CNOT 0 1\n        M 0 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n\n        >>> stim analyze_errors --in example_circuit.stim\n        error(0.125) D0\n        error(0.125) D0 D1\n\n\n    Example #2\n        >>> stim gen \\\n                --code repetition_code \\\n                --task memory \\\n                --distance 3 \\\n                --rounds 1000 \\\n                --after_reset_flip_probability 0.125 \\\n                > rep_code.stim\n        >>> stim analyze_errors --fold_loops --in rep_code.stim\n        error(0.125) D0\n        error(0.125) D0 D1\n        error(0.125) D0 D2\n        error(0.125) D1 D3\n        error(0.125) D1 L0\n        error(0.125) D2 D4\n        error(0.125) D3 D5\n        detector(1, 0) D0\n        detector(3, 0) D1\n        repeat 998 {\n            error(0.125) D4 D6\n            error(0.125) D5 D7\n            shift_detectors(0, 1) 0\n            detector(1, 0) D2\n            detector(3, 0) D3\n            shift_detectors 2\n        }\n        shift_detectors(0, 1) 0\n        detector(1, 0) D2\n        detector(3, 0) D3\n        detector(1, 1) D4\n        detector(3, 1) D5\n```\n\n<a name=\"convert\"></a>\n### stim convert\n\n```\nNAME\n    stim convert\n\nSYNOPSIS\n    stim convert \\\n        --bits_per_shot int \\\n        [--circuit filepath] \\\n        [--in filepath] \\\n        [--in_format 01|b8|r8|ptb64|hits|dets] \\\n        --num_detectors int \\\n        --num_measurements int \\\n        --num_observables int \\\n        [--obs_out filepath] \\\n        [--obs_out_format 01|b8|r8|ptb64|hits|dets] \\\n        [--out filepath] \\\n        [--out_format 01|b8|r8|ptb64|hits|dets] \\\n        --types M|D|L\n\nDESCRIPTION\n    Convert data between result formats.\n\n    See the various formats here:\n    https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n    To read and write data, the size of the records must be known.\n    If writing to a dets file, then the number of measurements, detectors\n    and observables per record must also be known.\n\n    Both of these pieces of information can either be given directly, or\n    inferred from various data sources, such as circuit or dem files.\n\n\nOPTIONS\n    --bits_per_shot\n        Specifies the number of bits per shot in the input/output files.\n\n        This argument is required if the circuit, dem or num_* flags\n        are not given, and not supported when writing to a dets file.\n\n        In this case we just treat the bits aas arbitrary data. It is up\n        to the user to interpert it correctly.\n\n\n    --circuit\n        Specifies where the circuit that generated the data is.\n\n        This argument is optional, but can be used to infer the number of\n        measurements, detectors and observables to use per record.\n\n        The circuit file should be a stim circuit. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n\n    --in\n        Chooses the file to read data from.\n\n        By default, the circuit is read from stdin. When `--in $FILEPATH` is\n        specified, the circuit is instead read from the file at $FILEPATH.\n\n        The input's format is specified by `--in_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --in_format\n        Specifies the data format to use when reading data.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --num_detectors\n        Specifies the number of detectors in the input/output files.\n\n        This argument is required if writing to a dets file and the circuit\n        or dem is not given.\n\n\n    --num_measurements\n        Specifies the number of measurements in the input/output files.\n\n        This argument is required if writing to a dets file and the circuit\n        is not given.\n\n\n    --num_observables\n        Specifies the number of observables in the input/output files.\n\n        This argument is required if writing to a dets file and the circuit\n        or dem is not given.\n\n\n    --obs_out\n        Specifies the file to write observable flip data to.\n\n        When producing detection event data, the goal is typically to\n        predict whether or not the logical observables were flipped by using\n        the detection events. This argument specifies where to write that\n        observable flip data.\n\n        If this argument isn't specified, the observable flip data isn't\n        written to a file.\n\n        The output is in a format specified by `--obs_out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --obs_out_format\n        Specifies the data format to use when writing observable flip data.\n\n        Irrelevant unless `--obs_out` is specified.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --out\n        Chooses where to write the data to.\n\n        By default, the output is written to stdout. When `--out $FILEPATH`\n        is specified, the output is instead written to the file at $FILEPATH.\n\n        The output's format is specified by `--out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --out_format\n        Specifies the data format to use when writing output data.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --types\n        Specifies the types of events in the files.\n\n        This argument is required if a circuit is given as the circuit can\n        give the number of each type of event, but not which events are\n        contained within an input file.\n\n        Note that in most cases, a file will have either measurements only,\n        detections only, or detections and observables.\n\n        The type values (M, D, L) correspond to the value prefix letters\n        in dets files. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md#dets\n\n\nEXAMPLES\n    Example #1\n        >>> cat example.01\n        10000\n        11001\n        00000\n        01001\n\n        >>> stim convert \\\n            --in example.01 \\\n            --in_format 01 \\\n            --out_format dets\n            --num_measurements 5\n        shot M0\n        shot M0 M1 M4\n        shot\n        shot M1 M4\n\n\n    Example #2\n        >>> cat example.dem\n        detector D0\n        detector D1\n        logical_observable L2\n\n        >>> cat example.dets\n        shot D0\n        shot D0 D1 L2\n        shot\n        shot D1 L2\n\n        >>> stim convert \\\n            --in example.dets \\\n            --in_format dets \\\n            --out_format 01\n            --dem example.dem\n        10000\n        11001\n        00000\n        01001\n\n\n    Example #3\n        >>> cat example_circuit.stim\n        X 0\n        M 0 1\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(2) rec[-1]\n\n        >>> cat example_measure_data.01\n        00\n        01\n        10\n        11\n\n        >>> stim convert \\\n            --in example_measure_data.01 \\\n            --in_format 01 \\\n            --out_format dets\n            --circuit example_circuit.stim \\\n            --types M\n        shot\n        shot M1\n        shot M0\n        shot M0 M1\n\n\n    Example #4\n        >>> cat example.01\n        0010\n        0111\n        1000\n        1110\n\n        >>> stim convert \\\n            --in example.01 \\\n            --in_format 01 \\\n            --out_format hits\n            --bits_per_shot 4\n        2\n        1,2,3\n        0\n        0,1,2\n```\n\n<a name=\"detect\"></a>\n### stim detect\n\n```\nNAME\n    stim detect\n\nSYNOPSIS\n    stim detect \\\n        [--append_observables] \\\n        [--in filepath] \\\n        [--obs_out filepath] \\\n        [--obs_out_format 01|b8|r8|ptb64|hits|dets] \\\n        [--out filepath] \\\n        [--out_format 01|b8|r8|ptb64|hits|dets] \\\n        [--seed int] \\\n        [--shots int]\n\nDESCRIPTION\n    Sample detection events and observable flips from a circuit.\n\nOPTIONS\n    --append_observables\n        Appends observable flips to the end of samples as extra detectors.\n\n        PREFER --obs_out OVER THIS FLAG. Mixing the observable flip data\n        into detection event data tends to require simply separating them\n        again immediately, creating unnecessary work. For example, when\n        testing a decoder, you do not want to give the observable flips to\n        the decoder because that is the information the decoder is supposed\n        to be predicting from the detection events.\n\n        This flag causes observable flip data to be appended to each sample,\n        as if the observables were extra detectors at the end of the\n        circuit. For example, if there are 100 detectors and 10 observables\n        in the circuit, then the output will contain 110 detectors and the\n        last 10 are the observables.\n\n        Note that, when using `--out_format dets`, this option is implicitly\n        activated but observables are not appended as if they were\n        detectors (because `dets` has type hinting information). For\n        example, in the example from the last paragraph, the observables\n        would be named `L0` through `L9` instead of `D100` through `D109`.\n\n\n    --in\n        Chooses the stim circuit file to read the circuit to sample from.\n\n        By default, the circuit is read from stdin. When `--in $FILEPATH` is\n        specified, the circuit is instead read from the file at $FILEPATH.\n\n        The input should be a stim circuit. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n\n    --obs_out\n        Specifies the file to write observable flip data to.\n\n        When sampling detection event data, the goal is typically to predict\n        whether or not the logical observables were flipped by using the\n        detection events. This argument specifies where to write that\n        observable flip data.\n\n        If this argument isn't specified, the observable flip data isn't\n        written to a file.\n\n        The output is in a format specified by `--obs_out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --obs_out_format\n        Specifies the data format to use when writing observable flip data.\n\n        Irrelevant unless `--obs_out` is specified.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --out\n        Chooses where to write the sampled data to.\n\n        By default, the output is written to stdout. When `--out $FILEPATH`\n        is specified, the output is instead written to the file at $FILEPATH.\n\n        The output is in a format specified by `--out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --out_format\n        Specifies the data format to use when writing output data.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --seed\n        Makes simulation results PARTIALLY deterministic.\n\n        The seed integer must be a non-negative 64 bit signed integer.\n\n        When `--seed` isn't specified, the random number generator is seeded\n        using fresh entropy requested from the operating system.\n\n        When `--seed #` is set, the exact same simulation results will be\n        produced every time ASSUMING:\n\n        - the exact same other flags are specified\n        - the exact same version of Stim is being used\n        - the exact same machine architecture is being used (for example,\n            you're not switching from a machine that has AVX2 instructions\n            to one that doesn't).\n\n        CAUTION: simulation results *WILL NOT* be consistent between\n        versions of Stim. This restriction is present to make it possible to\n        have future optimizations to the random sampling, and is enforced by\n        introducing intentional differences in the seeding strategy from\n        version to version.\n\n        CAUTION: simulation results *MAY NOT* be consistent across machines.\n        For example, using the same seed on a machine that supports AVX\n        instructions and one that only supports SSE instructions may produce\n        different simulation results.\n\n        CAUTION: simulation results *MAY NOT* be consistent if you vary\n        other flags and modes. For example, `--skip_reference_sample` may\n        result in fewer calls the to the random number generator before\n        reported sampling begins. More generally, using the same seed for\n        `stim sample` and `stim detect` will not result in detection events\n        corresponding to the measurement results.\n\n\n    --shots\n        Specifies the number of samples to take from the circuit.\n\n        Defaults to 1.\n        Must be an integer between 0 and a quintillion (10^18).\n\n\nEXAMPLES\n    Example #1\n        >>> cat example.stim\n        H 0\n        CNOT 0 1\n        X_ERROR(0.1) 0 1\n        M 0 1\n        DETECTOR rec[-1] rec[-2]\n\n        >>> stim detect --shots 5 --in example.stim\n        0\n        1\n        0\n        0\n        0\n\n\n    Example #2\n        >>> cat example.stim\n        # Single-shot X-basis rep code circuit.\n        RX 0 1 2 3 4 5 6\n        MPP X0*X1 X1*X2 X2*X3 X3*X4 X4*X5 X5*X6\n        Z_ERROR(0.1) 0 1 2 3 4 5 6\n        MPP X0 X1 X2 X3 X4 X5 X6\n        DETECTOR rec[-1] rec[-2] rec[-8]   # X6 X5 now = X5*X6 before\n        DETECTOR rec[-2] rec[-3] rec[-9]   # X5 X4 now = X4*X5 before\n        DETECTOR rec[-3] rec[-4] rec[-10]  # X4 X3 now = X3*X4 before\n        DETECTOR rec[-4] rec[-5] rec[-11]  # X3 X2 now = X2*X3 before\n        DETECTOR rec[-5] rec[-6] rec[-12]  # X2 X1 now = X1*X2 before\n        DETECTOR rec[-6] rec[-7] rec[-13]  # X1 X0 now = X0*X1 before\n        OBSERVABLE_INCLUDE(0) rec[-1]\n\n        >>> stim detect \\\n            --in example.stim \\\n            --out_format dets \\\n            --shots 10\n        shot\n        shot\n        shot L0 D0 D5\n        shot D1 D2\n        shot\n        shot L0 D0\n        shot D5\n        shot\n        shot D3 D4\n        shot D0 D1\n```\n\n<a name=\"diagram\"></a>\n### stim diagram\n\n```\nNAME\n    stim diagram\n\nSYNOPSIS\n    stim diagram \\\n        [--filter_coords (float.seperatedby(',') | L# | D#).seperatedby(':')] \\\n        [--in filepath] \\\n        [--out filepath] \\\n        [--remove_noise] \\\n        [--tick int | int:int] \\\n        --type name\n\nDESCRIPTION\n    Produces various kinds of diagrams.\n\n\nOPTIONS\n    --filter_coords\n        Specifies coordinate filters that determine what appears in the diagram.\n\n        A coordinate is a double precision floating point number.\n        A point is a tuple of coordinates.\n        The coordinates of a point are separate by commas (',').\n        A filter is a set of points.\n        Points are separated by colons (':').\n\n        Filters can also be set to specific detector or observable indices,\n        like D0 or L0.\n\n        Example:\n            --filter-coords 2,3:4,5,6\n                In a detector slice diagram this means that only detectors whose\n                first two coordinates are (2,3), or whose first three coordinate\n                are (4,5,6), should be included in the diagram.\n            --filter-coords L0\n                In a detector slice diagram this means that logical observable 0\n                should be included. Logical observables are only included if\n                explicitly filtered in.\n\n\n    --in\n        Where to read the object to diagram from.\n\n        By default, the object is read from stdin. When `--in $FILEPATH` is\n        specified, the object is instead read from the file at $FILEPATH.\n\n        The expected type of object depends on the type of diagram.\n\n\n    --out\n        Chooses where to write the diagram to.\n\n        By default, the output is written to stdout. When `--out $FILEPATH`\n        is specified, the output is instead written to the file at $FILEPATH.\n\n        The type of output produced depends on the type of diagram.\n\n\n    --remove_noise\n        Removes noise from the input before turning it into a diagram.\n\n        For example, if the input is a noisy circuit and you aren't\n        interested in the details of the noise but rather in the structure\n        of the circuit, you can specify this flag in order to filter out\n        the noise.\n\n\n    --tick\n        Specifies that the diagram should apply to a specific TICK or range\n        of TICKS from the input circuit.\n\n        To specify a single tick, pass an integer like `--tick=5`.\n        To specify a range, pass two integers separated by a colon like\n        `--tick=start:end`. Note that the range is half open.\n\n        In detector and time slice diagrams, `--tick` identifies which ticks\n        to include in the diagram. Note that `--tick=0` is the very\n        beginning of the circuit and `--tick=1` is the instant of the first\n        TICK instruction.\n\n\n    --type\n        The type of diagram to make.\n\n        The available diagram types are:\n\n        \"timeline-text\": Produces an ASCII text diagram of the operations\n            performed by a circuit over time. The qubits are laid out into\n            a line top to bottom, and time advances left to right. The input\n            object should be a stim circuit.\n\n            INPUT MUST BE A CIRCUIT.\n\n        \"timeline-svg\": Produces an SVG image diagram of the operations\n            performed by a circuit over time. The qubits are laid out into\n            a line top to bottom, and time advances left to right. The input\n            object should be a stim circuit.\n\n            INPUT MUST BE A CIRCUIT.\n\n        \"timeline-3d\": Produces a 3d model, in GLTF format, of the\n            operations applied by a stim circuit over time.\n\n            GLTF files can be opened with a variety of programs, or\n            opened online in viewers such as\n            https://gltf-viewer.donmccurdy.com/ .\n\n            INPUT MUST BE A CIRCUIT.\n\n        \"timeline-3d-html\": A web page containing a 3d model\n            viewer of the operations applied by a stim circuit\n            over time.\n\n            INPUT MUST BE A CIRCUIT.\n\n        \"matchgraph-svg\": An image of the decoding graph of a detector\n            error model. Red lines are errors crossing a logical observable.\n\n            INPUT MUST BE A DETECTOR ERROR MODEL OR A CIRCUIT.\n\n        \"matchgraph-3d\": A 3d model, in GLTF format, of the\n            decoding graph of a detector error model. Red lines are\n            errors crossing a logical observable.\n\n            GLTF files can be opened with a variety of programs, or\n            opened online in viewers such as\n            https://gltf-viewer.donmccurdy.com/ .\n\n            INPUT MUST BE A DETECTOR ERROR MODEL OR A CIRCUIT.\n\n        \"matchgraph-3d-html\": A web page containing a 3d model\n            viewer of the decoding graph of a detector error\n            model or circuit.\n\n            INPUT MUST BE A DETECTOR ERROR MODEL OR A CIRCUIT.\n\n        \"detslice-text\": An ASCII diagram of the stabilizers\n            that detectors declared by the circuit correspond to\n            during the TICK instruction identified by the `tick`\n            argument.\n\n            INPUT MUST BE A CIRCUIT.\n\n        \"detslice-svg\": An SVG image of the stabilizers\n            that detectors declared by the circuit correspond to\n            during the TICK instruction identified by the `tick`\n            argument. For example, a detector slice diagram of a\n            CSS surface code circuit during the TICK between a\n            measurement layer and a reset layer will produce the\n            usual diagram of a surface code. Uses the Pauli color convention\n            XYZ=RGB.\n\n            INPUT MUST BE A CIRCUIT.\n\n        \"timeslice-svg\": An SVG image of the operations that a circuit\n            applies during the specified tick or range of ticks.\n\n            INPUT MUST BE A CIRCUIT.\n\n        \"detslice-with-ops-svg\": An SVG image of the operations that a\n            circuit applies during the specified tick or range of ticks,\n            combined with the detector slices after those operations are\n            applied.\n\n            INPUT MUST BE A CIRCUIT.\n\n\nEXAMPLES\n    Example #1\n        >>> cat example_circuit.stim\n        H 0\n        CNOT 0 1\n\n        >>> stim diagram \\\n            --in example_circuit.stim \\\n            --type timeline-text\n        q0: -H-@-\n               |\n        q1: ---X-\n\n\n    Example #2\n        >>> # Making a video of detector slices moving around\n\n        >>> # First, make a circuit to animate.\n        >>> stim gen \\\n                --code surface_code \\\n                --task rotated_memory_x \\\n                --distance 5 \\\n                --rounds 100 \\\n                > surface_code.stim\n\n        >>> # Second, use gnu-parallel and stim diagram to make video frames.\n        >>> parallel stim diagram \\\n            --filter_coords 2,2:4,2 \\\n            --type detector-slice-svg \\\n            --tick {} \\\n            --in surface_code.stim \\\n            --out video_frame_{}.svg \\\n            ::: {0050..0150}\n\n        >>> # Third, use ffmpeg to turn the frames into a GIF.\n        >>> # (note: the complex filter argument is optional; it turns the background white)\n        >>> ffmpeg output_animation.gif \\\n            -framerate 5 \\\n            -pattern_type glob -i 'video_frame_*.svg' \\\n            -pix_fmt rgb8 \\\n            -filter_complex \"[0]split=2[bg][fg];[bg]drawbox=c=white@1:t=fill[bg];[bg][fg]overlay=format=auto\"\n\n        >>> # Alternatively, make an MP4 video instead of a GIF.\n        >>> ffmpeg output_video.mp4 \\\n            -framerate 5 \\\n            -pattern_type glob -i 'video_frame_*.svg' \\\n            -vf scale=1024:-1 \\\n            -c:v libx264 \\\n            -vf format=yuv420p \\\n            -vf \"pad=ceil(iw/2)*2:ceil(ih/2)*2\"\n```\n\n<a name=\"explain_errors\"></a>\n### stim explain_errors\n\n```\nNAME\n    stim explain_errors\n\nSYNOPSIS\n    stim explain_errors \\\n        [--dem_filter filepath] \\\n        [--in filepath] \\\n        [--out filepath] \\\n        [--single]\n\nDESCRIPTION\n    Find circuit errors that produce certain detection events.\n\n    Note that this command does not attempt to explain detection events\n    by using multiple errors. This command can only tell you how to\n    produce a set of detection events if they correspond to a specific\n    single physical error annotated into the circuit.\n\n    If you need to explain a detection event set using multiple errors,\n    use a decoder such as pymatching to find the set of single detector\n    error model errors that are needed and then use this command to\n    convert those specific errors into circuit errors.\n\n\nOPTIONS\n    --dem_filter\n        Specifies a detector error model to use as a filter.\n\n        If `--dem_filter` isn't specified, an explanation of every single\n        set of symptoms that can be produced by the circuit.\n\n        If `--dem_filter` is specified, only explanations of the error\n        mechanisms present in the filter will be output. This is useful when\n        you are interested in a specific set of detection events.\n\n        The filter is specified as a detector error model file. See\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n\n    --in\n        Chooses the stim circuit file to read the explanatory circuit from.\n\n        By default, the circuit is read from stdin. When `--in $FILEPATH` is\n        specified, the circuit is instead read from the file at $FILEPATH.\n\n        The input should be a stim circuit. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n\n    --out\n        Chooses where to write the explanations to.\n\n        By default, the output is written to stdout. When `--out $FILEPATH`\n        is specified, the output is instead written to the file at $FILEPATH.\n\n        The output is in an arbitrary semi-human-readable format.\n\n\n    --single\n        Explain using a single simple error instead of all possible errors.\n\n        When `--single` isn't specified, every single circuit error that\n        produces a specific detector error model is output as a possible\n        explanation of that error.\n\n        When `--single` is specified, only the simplest circuit error is\n        output. The \"simplest\" error is chosen by using heuristics such as\n        \"has fewer Pauli terms\" and \"happens earlier\".\n\n\nEXAMPLES\n    Example #1\n        >>> stim gen \\\n            --code surface_code \\\n            --task rotated_memory_z \\\n            --distance 5 \\\n            --rounds 10 \\\n            --after_clifford_depolarization 0.001 \\\n            > example.stim\n        >>> echo \"error(1) D97 D102\" > example.dem\n\n        >>> stim explain_errors \\\n            --single \\\n            --in example.stim \\\n            --dem_filter example.dem\n        ExplainedError {\n            dem_error_terms: D97[coords 4,6,4] D102[coords 2,8,4]\n            CircuitErrorLocation {\n                flipped_pauli_product: Z36[coords 3,7]\n                Circuit location stack trace:\n                    (after 25 TICKs)\n                    at instruction #83 (a REPEAT 9 block) in the circuit\n                    after 2 completed iterations\n                    at instruction #12 (DEPOLARIZE2) in the REPEAT block\n                    at targets #3 to #4 of the instruction\n                    resolving to DEPOLARIZE2(0.001) 46[coords 2,8] 36[coords 3,7]\n            }\n        }\n```\n\n<a name=\"gen\"></a>\n### stim gen\n\n```\nNAME\n    stim gen\n\nSYNOPSIS\n    stim gen \\\n        [--after_clifford_depolarization probability] \\\n        [--after_reset_flip_probability probability] \\\n        [--before_measure_flip_probability probability] \\\n        [--before_round_data_depolarization probability] \\\n        --code surface_code|repetition_code|color_code \\\n        --distance int \\\n        [--out filepath] \\\n        --rounds int \\\n        --task name\n\nDESCRIPTION\n    Generates example circuits.\n\n    The generated circuits include annotations for noise, detectors, logical\n    observables, the spatial locations of qubits, the spacetime locations\n    of detectors, and the inexorable passage of TICKs.\n\n    Note that the generated circuits are not intended to be sufficient for\n    research. They are really just examples to make it easier to get started\n    using Stim, so you can try things without having to first go through\n    the entire effort of making a correctly annotated quantum error\n    correction circuit.\n\n\nOPTIONS\n    --after_clifford_depolarization\n        Specifies a depolarizing noise level for unitary gates.\n\n        Defaults to 0 when not specified.\n        Must be a probability (a number between 0 and 1).\n\n        Adds a `DEPOLARIZE1(p)` operation after every single-qubit Clifford\n        operation, and a `DEPOLARIZE2(p)` noise operation after every\n        two-qubit Clifford operation. When set to 0 or not set, these noise\n        operations are not inserted at all.\n\n\n    --after_reset_flip_probability\n        Specifies a reset noise level.\n\n        Defaults to 0 when not specified.\n        Must be a probability (a number between 0 and 1).\n\n        Adds an `X_ERROR(p)` after `R` and `RY` operations, and a\n        `Z_ERROR(p)` after `RX` operations. When set to 0 or not set,\n        these noise operations are not inserted at all.\n\n\n    --before_measure_flip_probability\n        Specifies a measurement noise level.\n\n        Defaults to 0 when not specified.\n        Must be a probability (a number between 0 and 1).\n\n        Adds an `X_ERROR(p)` before `M` and `MY` operations, and a\n        `Z_ERROR(p)` before `MX` operations. When set to 0 or not set,\n        these noise operations are not inserted at all.\n\n\n    --before_round_data_depolarization\n        Specifies a quantum phenomenological noise level.\n\n        Defaults to 0 when not specified.\n        Must be a probability (a number between 0 and 1).\n\n        Adds a `DEPOLARIZE1(p)` operation to each data qubit at the start of\n        each round of stabilizer measurements. When set to 0 or not set,\n        these noise operations are not inserted at all.\n\n\n    --code\n        The error correcting code to use.\n\n        The available error correcting codes are:\n\n        `surface_code`\n            The surface code. A quantum code with a checkerboard pattern of\n            alternating X and Z stabilizers.\n        `repetition_code`\n            The repetition code. The simplest classical code.\n        `color_code`\n            The color code. A quantum code with a hexagonal pattern of\n            overlapping X and Z stabilizers.\n\n\n    --distance\n        The minimum number of physical errors that cause a logical error.\n\n        The code distance determines how spatially large the generated\n        circuit has to be. Conventionally, the code distance specifically\n        refers to single-qubit errors between rounds instead of circuit\n        errors during rounds.\n\n        The distance must always be a positive integer. Different\n        codes/tasks may place additional constraints on the distance (e.g.\n        must be larger than 2 or must be odd or etc).\n\n\n    --out\n        Chooses where to write the generated circuit to.\n\n        By default, the output is written to stdout. When `--out $FILEPATH`\n        is specified, the output is instead written to the file at $FILEPATH.\n\n        The output is a stim circuit. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n\n    --rounds\n        The number of times the circuit's measurement qubits are measured.\n\n        The number of rounds must be an integer between 1 and a quintillion\n        (10^18). Different codes/tasks may place additional constraints on\n        the number of rounds (e.g. enough rounds to have measured all the\n        stabilizers at least once).\n\n\n    --task\n        What the generated circuit should do; the experiment it should run.\n\n        Different error correcting codes support different tasks. The\n        available tasks are:\n\n        `memory` (repetition_code):\n            Initialize a logical `|0>`,\n            preserve it against noise for the given number of rounds,\n            then measure.\n        `rotated_memory_x` (surface_code):\n            Initialize a logical `|+>` in a rotated surface code,\n            preserve it against noise for the given number of rounds,\n            then measure in the X basis.\n        `rotated_memory_z` (surface_code):\n            Initialize a logical `|0>` in a rotated surface code,\n            preserve it against noise for the given number of rounds,\n            then measure in the X basis.\n        `unrotated_memory_x` (surface_code):\n            Initialize a logical `|+>` in an unrotated surface code,\n            preserve it against noise for the given number of rounds,\n            then measure in the Z basis.\n        `unrotated_memory_z` (surface_code):\n            Initialize a logical `|0>` in an unrotated surface code,\n            preserve it against noise for the given number of rounds,\n            then measure in the Z basis.\n        `memory_xyz` (color_code):\n            Initialize a logical `|0>`,\n            preserve it against noise for the given number of rounds,\n            then measure. Use a color code that alternates between measuring\n            X, then Y, then Z stabilizers.\n\n\nEXAMPLES\n    Example #1\n        >>> stim gen \\\n            --code repetition_code \\\n            --task memory \\\n            --distance 3 \\\n            --rounds 100 \\\n            --after_clifford_depolarization 0.001\n        # Generated repetition_code circuit.\n        # task: memory\n        # rounds: 100\n        # distance: 3\n        # before_round_data_depolarization: 0\n        # before_measure_flip_probability: 0\n        # after_reset_flip_probability: 0\n        # after_clifford_depolarization: 0.001\n        # layout:\n        # L0 Z1 d2 Z3 d4\n        # Legend:\n        #     d# = data qubit\n        #     L# = data qubit with logical observable crossing\n        #     Z# = measurement qubit\n        R 0 1 2 3 4\n        TICK\n        CX 0 1 2 3\n        DEPOLARIZE2(0.001) 0 1 2 3\n        TICK\n        CX 2 1 4 3\n        DEPOLARIZE2(0.001) 2 1 4 3\n        TICK\n        MR 1 3\n        DETECTOR(1, 0) rec[-2]\n        DETECTOR(3, 0) rec[-1]\n        REPEAT 99 {\n            TICK\n            CX 0 1 2 3\n            DEPOLARIZE2(0.001) 0 1 2 3\n            TICK\n            CX 2 1 4 3\n            DEPOLARIZE2(0.001) 2 1 4 3\n            TICK\n            MR 1 3\n            SHIFT_COORDS(0, 1)\n            DETECTOR(1, 0) rec[-2] rec[-4]\n            DETECTOR(3, 0) rec[-1] rec[-3]\n        }\n        M 0 2 4\n        DETECTOR(1, 1) rec[-2] rec[-3] rec[-5]\n        DETECTOR(3, 1) rec[-1] rec[-2] rec[-4]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n```\n\n<a name=\"help\"></a>\n### stim help\n\n```\nNAME\n    stim help\n\nSYNOPSIS\n    stim help\n\nDESCRIPTION\n    Prints helpful information about using stim.\n\n```\n\n<a name=\"m2d\"></a>\n### stim m2d\n\n```\nNAME\n    stim m2d\n\nSYNOPSIS\n    stim m2d \\\n        [--append_observables] \\\n        --circuit filepath \\\n        [--in filepath] \\\n        [--in_format 01|b8|r8|ptb64|hits|dets] \\\n        [--obs_out filepath] \\\n        [--obs_out_format 01|b8|r8|ptb64|hits|dets] \\\n        [--out filepath] \\\n        [--out_format 01|b8|r8|ptb64|hits|dets] \\\n        [--ran_without_feedback] \\\n        [--skip_reference_sample] \\\n        --sweep filepath \\\n        [--sweep_format 01|b8|r8|ptb64|hits|dets]\n\nDESCRIPTION\n    Convert measurement data into detection event data.\n\n    When sampling data from hardware, instead of from simulators, it's\n    necessary to convert the measurement data into detection event data that\n    can be fed into a decoder. This is necessary both because of\n    complexities in the exact sets of measurements being compared by a\n    circuit to produce detection events and also because the expected parity\n    of a detector's measurement set can vary due to (for example) spin echo\n    operations in the circuit.\n\n    Stim performs this conversion by simulating taking a reference sample\n    from the circuit, in order to determine the expected parity of the\n    measurements sets defining detectors and observables, and then comparing\n    the sampled measurement data to these expectations.\n\n\nOPTIONS\n    --append_observables\n        Appends observable flips to the end of samples as extra detectors.\n\n        PREFER --obs_out OVER THIS FLAG. Mixing the observable flip data\n        into detection event data tends to require simply separating them\n        again immediately, creating unnecessary work. For example, when\n        testing a decoder, you do not want to give the observable flips to\n        the decoder because that is the information the decoder is supposed\n        to be predicting from the detection events.\n\n        This flag causes observable flip data to be appended to each sample,\n        as if the observables were extra detectors at the end of the\n        circuit. For example, if there are 100 detectors and 10 observables\n        in the circuit, then the output will contain 110 detectors and the\n        last 10 are the observables.\n\n\n    --circuit\n        Specifies where the circuit that generated the measurements is.\n\n        This argument is required, because the circuit is what specifies how\n        to derive detection event data from measurement data.\n\n        The circuit file should be a stim circuit. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n\n    --in\n        Chooses the file to read measurement data from.\n\n        By default, the circuit is read from stdin. When `--in $FILEPATH` is\n        specified, the circuit is instead read from the file at $FILEPATH.\n\n        The input's format is specified by `--in_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --in_format\n        Specifies the data format to use when reading measurement data.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --obs_out\n        Specifies the file to write observable flip data to.\n\n        When producing detection event data, the goal is typically to\n        predict whether or not the logical observables were flipped by using\n        the detection events. This argument specifies where to write that\n        observable flip data.\n\n        If this argument isn't specified, the observable flip data isn't\n        written to a file.\n\n        The output is in a format specified by `--obs_out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --obs_out_format\n        Specifies the data format to use when writing observable flip data.\n\n        Irrelevant unless `--obs_out` is specified.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --out\n        Chooses where to write the sampled data to.\n\n        By default, the output is written to stdout. When `--out $FILEPATH`\n        is specified, the output is instead written to the file at $FILEPATH.\n\n        The output's format is specified by `--out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --out_format\n        Specifies the data format to use when writing output detection data.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --ran_without_feedback\n        Converts the results assuming all feedback operations were skipped.\n\n        Pauli feedback operations don't need to be performed on the quantum\n        computer. They can be performed within the classical control system.\n        As such, it often makes sense to skip them when sampling from the\n        circuit on hardware, and then account for this later during data\n        analysis. Turning on this flag means that the quantum computer\n        didn't apply the feedback operations, and it's the job of the m2d\n        conversion to read the measurement data, rewrite it to account for\n        feedback effects, then convert to detection events.\n\n        In the python API, the same effect can be achieved by using\n        stim.Circuit.with_inlined_feedback().compile_m2d_converter().\n\n\n    --skip_reference_sample\n        Asserts the circuit can produce a noiseless sample that is just 0s.\n\n        When this argument is specified, the reference sample (that the\n        measurement data will be compared to) is generated by simply setting\n        all measurements to 0 instead of by simulating the circuit without\n        noise.\n\n        Skipping the reference sample can significantly improve performance,\n        because acquiring the reference sample requires using the tableau\n        simulator. If the vacuous reference sample is actually a result that\n        can be produced by the circuit, under noiseless execution, then\n        specifying this flag has no observable outcome other than improving\n        performance.\n\n        CAUTION. When the all-zero sample isn't a result that can be\n        produced by the circuit under noiseless execution, specifying this\n        flag will cause incorrect output to be produced.\n\n\n    --sweep\n        Specifies a file to read sweep configuration data from.\n\n        Sweep bits are used to vary whether certain Pauli gates are included\n        in a circuit, or not, from shot to shot. For example, if a circuit\n        contains the instruction \"CX sweep[5] 0\" then there is an X pauli\n        that is included only in shots where the corresponding sweep data\n        has the bit at index 5 set to True.\n\n        If `--sweep` is not specified, all sweep bits default to OFF. If\n        `--sweep` is specified, each shot's sweep configuratoin data is\n        read from the specified file.\n\n        The sweep data's format is specified by `--sweep_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --sweep_format\n        Specifies the data format to use when reading sweep config data.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\nEXAMPLES\n    Example #1\n        >>> cat example_circuit.stim\n        X 0\n        M 0 1\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(2) rec[-1]\n\n        >>> cat example_measure_data.01\n        00\n        01\n        10\n        11\n\n        >>> stim m2d \\\n            --append_observables \\\n            --circuit example_circuit.stim \\\n            --in example_measure_data.01 \\\n            --in_format 01 \\\n            --out_format dets\n        shot D0\n        shot D0 D1 L2\n        shot\n        shot D1 L2\n```\n\n<a name=\"repl\"></a>\n### stim repl\n\n```\nNAME\n    stim repl\n\nSYNOPSIS\n    stim repl\n\nDESCRIPTION\n    Runs stim in interactive read-evaluate-print (REPL) mode.\n\n    Reads operations from stdin while immediately writing measurement\n    results to stdout.\n\n\nEXAMPLES\n    Example #1\n        >>> stim repl\n        ... M 0\n        0\n        ... X 0\n        ... M 0\n        1\n        ... X 2 3 9\n        ... M 0 1 2 3 4 5 6 7 8 9\n        1 0 1 1 0 0 0 0 0 1\n        ... REPEAT 5 {\n        ...     R 0 1\n        ...     H 0\n        ...     CNOT 0 1\n        ...     M 0 1\n        ... }\n        00\n        11\n        11\n        00\n        11\n```\n\n<a name=\"sample\"></a>\n### stim sample\n\n```\nNAME\n    stim sample\n\nSYNOPSIS\n    stim sample \\\n        [--in filepath] \\\n        [--out filepath] \\\n        [--out_format 01|b8|r8|ptb64|hits|dets] \\\n        [--seed int] \\\n        [--shots int] \\\n        [--skip_loop_folding] \\\n        [--skip_reference_sample]\n\nDESCRIPTION\n    Samples measurements from a circuit.\n\nOPTIONS\n    --in\n        Chooses the stim circuit file to read the circuit to sample from.\n\n        By default, the circuit is read from stdin. When `--in $FILEPATH` is\n        specified, the circuit is instead read from the file at $FILEPATH.\n\n        The input should be a stim circuit. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n\n    --out\n        Chooses where to write the sampled data to.\n\n        By default, the output is written to stdout. When `--out $FILEPATH`\n        is specified, the output is instead written to the file at $FILEPATH.\n\n        The output is in a format specified by `--out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --out_format\n        Specifies the data format to use when writing output data.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --seed\n        Makes simulation results PARTIALLY deterministic.\n\n        The seed integer must be a non-negative 64 bit signed integer.\n\n        When `--seed` isn't specified, the random number generator is seeded\n        using fresh entropy requested from the operating system.\n\n        When `--seed #` is set, the exact same simulation results will be\n        produced every time ASSUMING:\n\n        - the exact same other flags are specified\n        - the exact same version of Stim is being used\n        - the exact same machine architecture is being used (for example,\n            you're not switching from a machine that has AVX2 instructions\n            to one that doesn't).\n\n        CAUTION: simulation results *WILL NOT* be consistent between\n        versions of Stim. This restriction is present to make it possible to\n        have future optimizations to the random sampling, and is enforced by\n        introducing intentional differences in the seeding strategy from\n        version to version.\n\n        CAUTION: simulation results *MAY NOT* be consistent across machines.\n        For example, using the same seed on a machine that supports AVX\n        instructions and one that only supports SSE instructions may produce\n        different simulation results.\n\n        CAUTION: simulation results *MAY NOT* be consistent if you vary\n        other flags and modes. For example, `--skip_reference_sample` may\n        result in fewer calls the to the random number generator before\n        reported sampling begins. More generally, using the same seed for\n        `stim sample` and `stim detect` will not result in detection events\n        corresponding to the measurement results.\n\n\n    --shots\n        Specifies the number of samples to take from the circuit.\n\n        Defaults to 1.\n        Must be an integer between 0 and a quintillion (10^18).\n\n\n    --skip_loop_folding\n        Skips loop folding logic on the reference sample calculation.\n\n        When this argument is specified, the reference sample (that is used\n        to convert measurement flip data from frame simulations into actual\n        measurement data) is generated by iterating through the entire\n        flattened circuit with no loop detection.\n\n        Loop folding can enormously improve performance for circuits\n        containing REPEAT blocks with large repeat counts, by detecting\n        periodicity in loops and fast-forwarding across them when computing\n        the reference sample for the circuit. However, in some cases the\n        analysis is not able to detect the periodicity that is present. For\n        example, this has been observed in honeycomb code circuits. When\n        this happens, the folding-capable analysis is slower than simply\n        analyzing the flattened circuit without any specialized loop logic.\n        The `--skip_loop_folding` flag can be used to just analyze the\n        flattened circuit, bypassing this slowdown for circuits such as\n        honeycomb code circuits.\n\n        By default, loop detection is enabled. Pass this flag to disable\n        it (when appropriate by use case).\n\n\n    --skip_reference_sample\n        Asserts the circuit can produce a noiseless sample that is just 0s.\n\n        When this argument is specified, the reference sample (that is used\n        to convert measurement flip data from frame simulations into actual\n        measurement data) is generated by simply setting all measurements to\n        0 instead of by performing a stabilizer tableau simulation of the\n        circuit without noise.\n\n        Skipping the reference sample can significantly improve performance,\n        because acquiring the reference sample requires using the tableau\n        simulator. If the vacuous reference sample is actually a result that\n        can be produced by the circuit, under noiseless execution, then\n        specifying this flag has no observable outcome other than improving\n        performance.\n\n        CAUTION. When the all-zero sample isn't a result that can be\n        produced by the circuit under noiseless execution, specifying this\n        flag will cause incorrect output to be produced. Specifically, the\n        output measurement bits will be whether each measurement was\n        *FLIPPED* instead of the actual absolute value of the measurement.\n\n\nEXAMPLES\n    Example #1\n        >>> cat example_circuit.stim\n        H 0\n        CNOT 0 1\n        M 0 1\n\n        >>> stim sample --shots 5 < example_circuit.stim\n        00\n        11\n        11\n        00\n        11\n\n\n\n    Example #2\n        >>> cat example_circuit.stim\n        X 2 3 5\n        M 0 1 2 3 4 5 6 7 8 9\n\n        >>> stim sample --in example_circuit.stim --out_format dets\n        shot M2 M3 M5\n```\n\n<a name=\"sample_dem\"></a>\n### stim sample_dem\n\n```\nNAME\n    stim sample_dem\n\nSYNOPSIS\n    stim sample_dem \\\n        [--err_out filepath] \\\n        [--err_out_format 01|b8|r8|ptb64|hits|dets] \\\n        [--in filepath] \\\n        [--obs_out filepath] \\\n        [--obs_out_format 01|b8|r8|ptb64|hits|dets] \\\n        [--out filepath] \\\n        [--out_format 01|b8|r8|ptb64|hits|dets] \\\n        [--replay_err_in filepath] \\\n        [--replay_err_in_format 01|b8|r8|ptb64|hits|dets] \\\n        [--seed int] \\\n        [--shots int]\n\nDESCRIPTION\n    Samples detection events from a detector error model.\n\n    Supports recording and replaying the errors that occurred.\n\n\nOPTIONS\n    --err_out\n        Specifies a file to write a record of which errors occurred.\n\n        For example, the errors that occurred can be analyzed, modified, and\n        then given to `--replay_err_in` to see the effects of changes.\n\n        The output is in a format specified by `--err_out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --err_out_format\n        Specifies the data format to use when writing recorded error data.\n\n        Irrelevant unless `--err_out` is specified.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --in\n        Chooses the file to read the detector error model to sample from.\n\n        By default, the detector error model is read from stdin. When\n        `--in $FILEPATH` is specified, the detector error model is instead\n        read from the file at $FILEPATH.\n\n        The input should be a stim detector error model. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n\n    --obs_out\n        Specifies the file to write observable flip data to.\n\n        When sampling detection event data, the goal is typically to predict\n        whether or not the logical observables were flipped by using the\n        detection events. This argument specifies where to write that\n        observable flip data.\n\n        If this argument isn't specified, the observable flip data isn't\n        written to a file.\n\n        The output is in a format specified by `--obs_out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --obs_out_format\n        Specifies the data format to use when writing observable flip data.\n\n        Irrelevant unless `--obs_out` is specified.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --out\n        Chooses where to write the sampled data to.\n\n        By default, the output is written to stdout. When `--out $FILEPATH`\n        is specified, the output is instead written to the file at $FILEPATH.\n\n        The output is in a format specified by `--out_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --out_format\n        Specifies the data format to use when writing output data.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --replay_err_in\n        Specifies a file to read error data to replay from.\n\n        When replaying error information, errors are no longer sampled\n        randomly but are instead driven by the file data. For example, this\n        file data could come from a previous run that wrote error data using\n        `--err_out`.\n\n        The input is in a format specified by `--err_in_format`. See:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --replay_err_in_format\n        Specifies the data format to use when reading error data to replay.\n\n        Irrelevant unless `--replay_err_in` is specified.\n\n        The available formats are:\n\n            01 (default): dense human readable\n            b8: bit packed binary\n            r8: run length binary\n            ptb64: partially transposed bit packed binary for SIMD\n            hits: sparse human readable\n            dets: sparse human readable with type hints\n\n        For a detailed description of each result format, see the result\n        format reference:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n\n    --seed\n        Makes simulation results PARTIALLY deterministic.\n\n        The seed integer must be a non-negative 64 bit signed integer.\n\n        When `--seed` isn't specified, the random number generator is seeded\n        using fresh entropy requested from the operating system.\n\n        When `--seed #` is set, the exact same simulation results will be\n        produced every time ASSUMING:\n\n        - the exact same other flags are specified\n        - the exact same version of Stim is being used\n        - the exact same machine architecture is being used (for example,\n            you're not switching from a machine that has AVX2 instructions\n            to one that doesn't).\n\n        CAUTION: simulation results *WILL NOT* be consistent between\n        versions of Stim. This restriction is present to make it possible to\n        have future optimizations to the random sampling, and is enforced by\n        introducing intentional differences in the seeding strategy from\n        version to version.\n\n        CAUTION: simulation results *MAY NOT* be consistent across machines.\n        For example, using the same seed on a machine that supports AVX\n        instructions and one that only supports SSE instructions may produce\n        different simulation results.\n\n        CAUTION: simulation results *MAY NOT* be consistent if you vary\n        other flags and modes. For example, `--skip_reference_sample` may\n        result in fewer calls the to the random number generator before\n        reported sampling begins. More generally, using the same seed for\n        `stim sample` and `stim detect` will not result in detection events\n        corresponding to the measurement results.\n\n\n    --shots\n        Specifies the number of samples to take from the detector error model.\n\n        Defaults to 1.\n        Must be an integer between 0 and a quintillion (10^18).\n\n\nEXAMPLES\n    Example #1\n        >>> cat example.dem\n        error(0) D0\n        error(0.5) D1 L0\n        error(1) D2 D3\n\n        >>> stim sample_dem \\\n            --shots 5 \\\n            --in example.dem \\\n            --out dets.01 \\\n            --out_format 01 \\\n            --obs_out obs_flips.01 \\\n            --obs_out_format 01\n\n        >>> cat dets.01\n        0111\n        0011\n        0011\n        0111\n        0111\n\n        >>> cat obs_flips.01\n        1\n        0\n        0\n        1\n        1\n```\n\n"
  },
  {
    "path": "file_lists/perf_files",
    "content": "src/stim/circuit/circuit.perf.cc\nsrc/stim/gates/gates.perf.cc\nsrc/stim/io/measure_record_reader.perf.cc\nsrc/stim/main.perf.cc\nsrc/stim/main_namespaced.perf.cc\nsrc/stim/mem/simd_bit_table.perf.cc\nsrc/stim/mem/simd_bits.perf.cc\nsrc/stim/mem/simd_word.perf.cc\nsrc/stim/mem/sparse_xor_vec.perf.cc\nsrc/stim/search/graphlike/algo.perf.cc\nsrc/stim/simulators/dem_sampler.perf.cc\nsrc/stim/simulators/error_analyzer.perf.cc\nsrc/stim/simulators/frame_simulator.perf.cc\nsrc/stim/simulators/tableau_simulator.perf.cc\nsrc/stim/stabilizers/clifford_string.perf.cc\nsrc/stim/stabilizers/pauli_string.perf.cc\nsrc/stim/stabilizers/pauli_string_iter.perf.cc\nsrc/stim/stabilizers/tableau.perf.cc\nsrc/stim/stabilizers/tableau_iter.perf.cc\nsrc/stim/util_bot/error_decomp.perf.cc\nsrc/stim/util_bot/probability_util.perf.cc\nsrc/stim/util_top/reference_sample_tree.perf.cc\nsrc/stim/util_top/stabilizers_to_tableau.perf.cc\n"
  },
  {
    "path": "file_lists/pybind_files",
    "content": "src/stim/circuit/circuit.pybind.cc\nsrc/stim/circuit/circuit2.pybind.cc\nsrc/stim/circuit/circuit_instruction.pybind.cc\nsrc/stim/circuit/circuit_repeat_block.pybind.cc\nsrc/stim/circuit/gate_target.pybind.cc\nsrc/stim/cmd/command_diagram.pybind.cc\nsrc/stim/dem/dem_instruction.pybind.cc\nsrc/stim/dem/detector_error_model.pybind.cc\nsrc/stim/dem/detector_error_model_repeat_block.pybind.cc\nsrc/stim/dem/detector_error_model_target.pybind.cc\nsrc/stim/gates/gates.pybind.cc\nsrc/stim/io/read_write.pybind.cc\nsrc/stim/py/base.pybind.cc\nsrc/stim/py/compiled_detector_sampler.pybind.cc\nsrc/stim/py/compiled_measurement_sampler.pybind.cc\nsrc/stim/py/march.pybind.cc\nsrc/stim/py/numpy.pybind.cc\nsrc/stim/py/stim.pybind.cc\nsrc/stim/simulators/dem_sampler.pybind.cc\nsrc/stim/simulators/frame_simulator.pybind.cc\nsrc/stim/simulators/matched_error.pybind.cc\nsrc/stim/simulators/measurements_to_detection_events.pybind.cc\nsrc/stim/simulators/tableau_simulator.pybind.cc\nsrc/stim/stabilizers/clifford_string.pybind.cc\nsrc/stim/stabilizers/flow.pybind.cc\nsrc/stim/stabilizers/pauli_string.pybind.cc\nsrc/stim/stabilizers/pauli_string_iter.pybind.cc\nsrc/stim/stabilizers/tableau.pybind.cc\nsrc/stim/stabilizers/tableau_iter.pybind.cc\n"
  },
  {
    "path": "file_lists/source_files_no_main",
    "content": "src/stim.cc\nsrc/stim/circuit/circuit.cc\nsrc/stim/circuit/circuit_instruction.cc\nsrc/stim/circuit/gate_decomposition.cc\nsrc/stim/circuit/gate_target.cc\nsrc/stim/cmd/command_analyze_errors.cc\nsrc/stim/cmd/command_convert.cc\nsrc/stim/cmd/command_detect.cc\nsrc/stim/cmd/command_diagram.cc\nsrc/stim/cmd/command_explain_errors.cc\nsrc/stim/cmd/command_gen.cc\nsrc/stim/cmd/command_help.cc\nsrc/stim/cmd/command_m2d.cc\nsrc/stim/cmd/command_repl.cc\nsrc/stim/cmd/command_sample.cc\nsrc/stim/cmd/command_sample_dem.cc\nsrc/stim/dem/dem_instruction.cc\nsrc/stim/dem/detector_error_model.cc\nsrc/stim/diagram/ascii_diagram.cc\nsrc/stim/diagram/base64.cc\nsrc/stim/diagram/basic_3d_diagram.cc\nsrc/stim/diagram/circuit_timeline_helper.cc\nsrc/stim/diagram/crumble.cc\nsrc/stim/diagram/crumble_data.cc\nsrc/stim/diagram/detector_slice/detector_slice_set.cc\nsrc/stim/diagram/diagram_util.cc\nsrc/stim/diagram/gate_data_3d.cc\nsrc/stim/diagram/gate_data_3d_texture_data.cc\nsrc/stim/diagram/gate_data_svg.cc\nsrc/stim/diagram/gltf.cc\nsrc/stim/diagram/graph/match_graph_3d_drawer.cc\nsrc/stim/diagram/graph/match_graph_svg_drawer.cc\nsrc/stim/diagram/json_obj.cc\nsrc/stim/diagram/lattice_map.cc\nsrc/stim/diagram/timeline/timeline_3d_drawer.cc\nsrc/stim/diagram/timeline/timeline_ascii_drawer.cc\nsrc/stim/diagram/timeline/timeline_svg_drawer.cc\nsrc/stim/gates/gate_data_annotations.cc\nsrc/stim/gates/gate_data_blocks.cc\nsrc/stim/gates/gate_data_collapsing.cc\nsrc/stim/gates/gate_data_controlled.cc\nsrc/stim/gates/gate_data_hada.cc\nsrc/stim/gates/gate_data_heralded.cc\nsrc/stim/gates/gate_data_noisy.cc\nsrc/stim/gates/gate_data_pair_measure.cc\nsrc/stim/gates/gate_data_pauli.cc\nsrc/stim/gates/gate_data_pauli_product.cc\nsrc/stim/gates/gate_data_period_3.cc\nsrc/stim/gates/gate_data_period_4.cc\nsrc/stim/gates/gate_data_pp.cc\nsrc/stim/gates/gate_data_swaps.cc\nsrc/stim/gates/gates.cc\nsrc/stim/gen/circuit_gen_params.cc\nsrc/stim/gen/gen_color_code.cc\nsrc/stim/gen/gen_rep_code.cc\nsrc/stim/gen/gen_surface_code.cc\nsrc/stim/io/measure_record.cc\nsrc/stim/io/measure_record_batch_writer.cc\nsrc/stim/io/measure_record_writer.cc\nsrc/stim/io/raii_file.cc\nsrc/stim/io/sparse_shot.cc\nsrc/stim/io/stim_data_formats.cc\nsrc/stim/main_namespaced.cc\nsrc/stim/mem/bit_ref.cc\nsrc/stim/mem/simd_util.cc\nsrc/stim/mem/simd_word.cc\nsrc/stim/mem/sparse_xor_vec.cc\nsrc/stim/search/graphlike/algo.cc\nsrc/stim/search/graphlike/edge.cc\nsrc/stim/search/graphlike/graph.cc\nsrc/stim/search/graphlike/node.cc\nsrc/stim/search/graphlike/search_state.cc\nsrc/stim/search/hyper/algo.cc\nsrc/stim/search/hyper/edge.cc\nsrc/stim/search/hyper/graph.cc\nsrc/stim/search/hyper/node.cc\nsrc/stim/search/hyper/search_state.cc\nsrc/stim/search/sat/wcnf.cc\nsrc/stim/simulators/error_analyzer.cc\nsrc/stim/simulators/error_matcher.cc\nsrc/stim/simulators/force_streaming.cc\nsrc/stim/simulators/graph_simulator.cc\nsrc/stim/simulators/matched_error.cc\nsrc/stim/simulators/sparse_rev_frame_tracker.cc\nsrc/stim/simulators/vector_simulator.cc\nsrc/stim/stabilizers/flex_pauli_string.cc\nsrc/stim/util_bot/arg_parse.cc\nsrc/stim/util_bot/error_decomp.cc\nsrc/stim/util_bot/probability_util.cc\nsrc/stim/util_top/circuit_inverse_qec.cc\nsrc/stim/util_top/circuit_inverse_unitary.cc\nsrc/stim/util_top/circuit_to_detecting_regions.cc\nsrc/stim/util_top/circuit_vs_amplitudes.cc\nsrc/stim/util_top/export_crumble_url.cc\nsrc/stim/util_top/export_qasm.cc\nsrc/stim/util_top/export_quirk_url.cc\nsrc/stim/util_top/has_flow.cc\nsrc/stim/util_top/mbqc_decomposition.cc\nsrc/stim/util_top/missing_detectors.cc\nsrc/stim/util_top/reference_sample_tree.cc\nsrc/stim/util_top/simplified_circuit.cc\nsrc/stim/util_top/transform_without_feedback.cc\n"
  },
  {
    "path": "file_lists/test_files",
    "content": "src/stim.test.cc\nsrc/stim/circuit/circuit.test.cc\nsrc/stim/circuit/circuit_instruction.test.cc\nsrc/stim/circuit/gate_decomposition.test.cc\nsrc/stim/circuit/gate_target.test.cc\nsrc/stim/cmd/command_analyze_errors.test.cc\nsrc/stim/cmd/command_convert.test.cc\nsrc/stim/cmd/command_detect.test.cc\nsrc/stim/cmd/command_diagram.test.cc\nsrc/stim/cmd/command_explain_errors.test.cc\nsrc/stim/cmd/command_gen.test.cc\nsrc/stim/cmd/command_m2d.test.cc\nsrc/stim/cmd/command_sample.test.cc\nsrc/stim/cmd/command_sample_dem.test.cc\nsrc/stim/dem/dem_instruction.test.cc\nsrc/stim/dem/detector_error_model.test.cc\nsrc/stim/diagram/ascii_diagram.test.cc\nsrc/stim/diagram/base64.test.cc\nsrc/stim/diagram/coord.test.cc\nsrc/stim/diagram/detector_slice/detector_slice_set.test.cc\nsrc/stim/diagram/graph/match_graph_3d_drawer.test.cc\nsrc/stim/diagram/graph/match_graph_svg_drawer.test.cc\nsrc/stim/diagram/json_obj.test.cc\nsrc/stim/diagram/timeline/timeline_3d_drawer.test.cc\nsrc/stim/diagram/timeline/timeline_ascii_drawer.test.cc\nsrc/stim/diagram/timeline/timeline_svg_drawer.test.cc\nsrc/stim/gates/gates.test.cc\nsrc/stim/gen/circuit_gen_params.test.cc\nsrc/stim/gen/gen_color_code.test.cc\nsrc/stim/gen/gen_rep_code.test.cc\nsrc/stim/gen/gen_surface_code.test.cc\nsrc/stim/io/measure_record.test.cc\nsrc/stim/io/measure_record_batch.test.cc\nsrc/stim/io/measure_record_batch_writer.test.cc\nsrc/stim/io/measure_record_reader.test.cc\nsrc/stim/io/measure_record_writer.test.cc\nsrc/stim/io/sparse_shot.test.cc\nsrc/stim/main_namespaced.test.cc\nsrc/stim/mem/bit_ref.test.cc\nsrc/stim/mem/fixed_cap_vector.test.cc\nsrc/stim/mem/monotonic_buffer.test.cc\nsrc/stim/mem/simd_bit_table.test.cc\nsrc/stim/mem/simd_bits.test.cc\nsrc/stim/mem/simd_bits_range_ref.test.cc\nsrc/stim/mem/simd_util.test.cc\nsrc/stim/mem/simd_word.test.cc\nsrc/stim/mem/sparse_xor_vec.test.cc\nsrc/stim/search/graphlike/algo.test.cc\nsrc/stim/search/graphlike/edge.test.cc\nsrc/stim/search/graphlike/graph.test.cc\nsrc/stim/search/graphlike/node.test.cc\nsrc/stim/search/graphlike/search_state.test.cc\nsrc/stim/search/hyper/algo.test.cc\nsrc/stim/search/hyper/edge.test.cc\nsrc/stim/search/hyper/graph.test.cc\nsrc/stim/search/hyper/node.test.cc\nsrc/stim/search/hyper/search_state.test.cc\nsrc/stim/search/sat/wcnf.test.cc\nsrc/stim/simulators/dem_sampler.test.cc\nsrc/stim/simulators/error_analyzer.test.cc\nsrc/stim/simulators/error_matcher.test.cc\nsrc/stim/simulators/frame_simulator.test.cc\nsrc/stim/simulators/frame_simulator_util.test.cc\nsrc/stim/simulators/graph_simulator.test.cc\nsrc/stim/simulators/matched_error.test.cc\nsrc/stim/simulators/measurements_to_detection_events.test.cc\nsrc/stim/simulators/sparse_rev_frame_tracker.test.cc\nsrc/stim/simulators/tableau_simulator.test.cc\nsrc/stim/simulators/vector_simulator.test.cc\nsrc/stim/stabilizers/clifford_string.test.cc\nsrc/stim/stabilizers/flex_pauli_string.test.cc\nsrc/stim/stabilizers/flow.test.cc\nsrc/stim/stabilizers/pauli_string.test.cc\nsrc/stim/stabilizers/pauli_string_iter.test.cc\nsrc/stim/stabilizers/pauli_string_ref.test.cc\nsrc/stim/stabilizers/tableau.test.cc\nsrc/stim/stabilizers/tableau_iter.test.cc\nsrc/stim/util_bot/arg_parse.test.cc\nsrc/stim/util_bot/error_decomp.test.cc\nsrc/stim/util_bot/probability_util.test.cc\nsrc/stim/util_bot/str_util.test.cc\nsrc/stim/util_bot/test_util.test.cc\nsrc/stim/util_bot/twiddle.test.cc\nsrc/stim/util_top/circuit_flow_generators.test.cc\nsrc/stim/util_top/circuit_inverse_qec.test.cc\nsrc/stim/util_top/circuit_inverse_unitary.test.cc\nsrc/stim/util_top/circuit_to_dem.test.cc\nsrc/stim/util_top/circuit_to_detecting_regions.test.cc\nsrc/stim/util_top/circuit_vs_amplitudes.test.cc\nsrc/stim/util_top/circuit_vs_tableau.test.cc\nsrc/stim/util_top/count_determined_measurements.test.cc\nsrc/stim/util_top/export_crumble_url.test.cc\nsrc/stim/util_top/export_qasm.test.cc\nsrc/stim/util_top/export_quirk_url.test.cc\nsrc/stim/util_top/has_flow.test.cc\nsrc/stim/util_top/mbqc_decomposition.test.cc\nsrc/stim/util_top/missing_detectors.test.cc\nsrc/stim/util_top/reference_sample_tree.test.cc\nsrc/stim/util_top/simplified_circuit.test.cc\nsrc/stim/util_top/stabilizers_to_tableau.test.cc\nsrc/stim/util_top/stabilizers_vs_amplitudes.test.cc\nsrc/stim/util_top/transform_without_feedback.test.cc\nsrc/stim_included_twice.test.cc\n"
  },
  {
    "path": "glue/cirq/README.md",
    "content": "# stimcirq\n\nTools for interop between the quantum python package `cirq` and the stabilizer simulator `stim`.\n\nIncludes:\n\n- `stimcirq.StimSampler`\n- `stimcirq.cirq_circuit_to_stim_circuit`\n- `stimcirq.stim_circuit_to_cirq_circuit`\n\n# Examples\n\nSampling with `stimcirq.Sampler`:\n\n```python\nimport cirq\na, b = cirq.LineQubit.range(2)\nc = cirq.Circuit(\n    cirq.H(a),\n    cirq.CNOT(a, b),\n    cirq.measure(a, key=\"a\"),\n    cirq.measure(b, key=\"b\"),\n)\n\nimport stimcirq\nsampler = stimcirq.StimSampler()\nresult = sampler.run(c, repetitions=30)\n\nprint(result)\n# prints something like:\n# a=000010100101000011001100110011\n# b=000010100101000011001100110011\n```\n\n# API Reference\n\n## `stimcirq.StimSampler`\n\n```\nA `cirq.Sampler` backed by `stim`.\n\nSupports circuits that contain Clifford operations, measurement operations, reset operations, and noise operations\nthat can be decomposed into probabilistic Pauli operations. Unknown operations are supported as long as they provide\na decomposition into supported operations via `cirq.decompose` (i.e. via a `_decompose_` method).\n\nNote that batch sampling is significantly faster (as in potentially thousands of times faster) than individual\nsampling, because it amortizes the cost of parsing and analyzing the circuit.\n```\n\n## `stimcirq.stim_circuit_to_cirq_circuit(circuit: stim.Circuit) -> cirq.Circuit`\n\n```\nConverts a stim circuit into an equivalent cirq circuit.\n\nQubit indices are turned into cirq.LineQubit instances. Measurements are\nkeyed by their ordering (e.g. the first measurement is keyed \"0\", the second\nis keyed \"1\", etc).\n\nNot all circuits can be converted:\n    - ELSE_CORRELATED_ERROR instructions are not supported.\n\nNot all circuits can be converted with perfect 1:1 fidelity:\n    - DETECTOR annotations are discarded.\n    - OBSERVABLE_INCLUDE annotations are discarded.\n\nArgs:\n    circuit: The stim circuit to convert into a cirq circuit.\n\nReturns:\n    The converted circuit.\n\nExamples:\n\n    >>> import stimcirq\n    >>> import stim\n    >>> print(stimcirq.stim_circuit_to_cirq_circuit(stim.Circuit('''\n    ...     H 0\n    ...     CNOT 0 1\n    ...     X_ERROR(0.25) 0\n    ...     TICK\n    ...     M !1 0\n    ... ''')))\n    0: ───H───@───X[prob=0.25]───M('1')────\n              │\n    1: ───────X──────────────────!M('0')───\n```\n\n## `def cirq_circuit_to_stim_circuit(circuit: cirq.Circuit, *, qubit_to_index_dict: Optional[Dict[cirq.Qid, int]] = None) -> stim.Circuit`\n\n```\nConverts a cirq circuit into an equivalent stim circuit.\n\nNot all circuits can be converted. In order for a circuit to be convertible, all of its operations must be\nconvertible.\n\nAn operation is convertible if:\n    - It is a stabilizer gate or probabilistic Pauli gate from cirq\n        - cirq.H\n        - cirq.S\n        - cirq.X\n        - cirq.X**0.5\n        - cirq.CNOT\n        - cirq.ResetChannel()\n        - cirq.X.with_probability(p)\n        - cirq.DepolarizingChannel(p, n_qubits=1 or 2)\n        - etc\n    - Or it has a _decompose_ method that yields convertible operations.\n    - Or it has a correctly implemented _stim_conversion_ method.\n\nArgs:\n    circuit: The circuit to convert.\n    qubit_to_index_dict: Optional. Which integer each qubit should get mapped to. If not specified, defaults to\n        indexing qubits in the circuit in sorted order.\n\nReturns:\n    The converted circuit.\n\nExamples:\n    >>> import cirq, stimcirq\n    >>> a = cirq.NamedQubit(\"zero\")\n    >>> b = cirq.NamedQubit(\"two\")\n    >>> stimcirq.cirq_circuit_to_stim_circuit(cirq.Circuit(\n    ...     cirq.Moment(cirq.H(a)),\n    ...     cirq.Moment(cirq.CNOT(a, b)),\n    ...     cirq.Moment(\n    ...         cirq.X(a).with_probability(0.25),\n    ...         cirq.Z(b).with_probability(0.25),\n    ...     ),\n    ...     cirq.Moment(),\n    ...     cirq.Moment(),\n    ...     cirq.Moment(cirq.DepolarizingChannel(0.125, n_qubits=2).on(b, a)),\n    ...     cirq.Moment(cirq.measure(a, b)),\n    ... ), qubit_to_index_dict={a: 0, b: 2})\n    stim.Circuit('''\n    H 0\n    TICK\n    CX 0 2\n    TICK\n    X_ERROR(0.25) 0\n    Z_ERROR(0.25) 2\n    TICK\n    TICK\n    TICK\n    DEPOLARIZE2(0.125) 2 0\n    TICK\n    M 0 2\n    TICK\n    ''')\n\nHere is an example of a _stim_conversion_ method:\n\n    def _stim_conversion_(\n            self,\n\n            # The stim circuit being built. Add onto it.\n            edit_circuit: stim.Circuit,\n\n            # Metadata about measurement groupings needed by stimcirq.StimSampler.\n            # If your gate contains a measurement, it has to append how many qubits\n            # that measurement measures (and its key) into this list.\n            edit_measurement_key_lengths: List[Tuple[str, int]],\n\n            # The indices of qubits the gate is operating on.\n            targets: List[int],\n\n            # Forward compatibility with future arguments.\n            **kwargs):\n\n        edit_circuit.append_operation(\"H\", targets)\n```\n"
  },
  {
    "path": "glue/cirq/setup.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom setuptools import setup\n\nwith open('README.md', encoding='UTF-8') as f:\n    long_description = f.read()\n\n__version__ = '1.16.dev0'\n\nsetup(\n    name='stimcirq',\n    version=__version__,\n    author='Craig Gidney',\n    author_email='craig.gidney@gmail.com',\n    url='https://github.com/quantumlib/stim',\n    license='Apache 2',\n    packages=['stimcirq'],\n    description='Implements a cirq.Sampler backed by stim.',\n    long_description=long_description,\n    long_description_content_type='text/markdown',\n    python_requires='>=3.6.0',\n    data_files=['README.md'],\n    install_requires=['stim', 'cirq-core'],\n    tests_require=['pytest', 'python3-distutils'],\n)\n"
  },
  {
    "path": "glue/cirq/stimcirq/__init__.py",
    "content": "__version__ = '1.16.dev0'\nfrom ._cirq_to_stim import cirq_circuit_to_stim_circuit\nfrom ._cx_swap_gate import CXSwapGate\nfrom ._cz_swap_gate import CZSwapGate\nfrom ._det_annotation import DetAnnotation\nfrom ._obs_annotation import CumulativeObservableAnnotation\nfrom ._shift_coords_annotation import ShiftCoordsAnnotation\nfrom ._stim_sampler import StimSampler\nfrom ._stim_to_cirq import (\n    MeasureAndOrResetGate,\n    stim_circuit_to_cirq_circuit,\n)\nfrom ._sweep_pauli import SweepPauli\nfrom ._two_qubit_asymmetric_depolarize import TwoQubitAsymmetricDepolarizingChannel\nfrom ._i_error_gate import IErrorGate\nfrom ._ii_error_gate import IIErrorGate\nfrom ._ii_gate import IIGate\n\nJSON_RESOLVERS_DICT = {\n    \"CumulativeObservableAnnotation\": CumulativeObservableAnnotation,\n    \"DetAnnotation\": DetAnnotation,\n    \"MeasureAndOrResetGate\": MeasureAndOrResetGate,\n    \"ShiftCoordsAnnotation\": ShiftCoordsAnnotation,\n    \"SweepPauli\": SweepPauli,\n    \"TwoQubitAsymmetricDepolarizingChannel\": TwoQubitAsymmetricDepolarizingChannel,\n    \"CXSwapGate\": CXSwapGate,\n    \"CZSwapGate\": CZSwapGate,\n    \"IIGate\": IIGate,\n    \"IIErrorGate\": IIErrorGate,\n    \"IErrorGate\": IErrorGate,\n}\nJSON_RESOLVER = JSON_RESOLVERS_DICT.get\n"
  },
  {
    "path": "glue/cirq/stimcirq/_cirq_to_stim.py",
    "content": "import functools\nimport itertools\nimport math\nfrom typing import Callable, cast, Dict, Iterable, List, Optional, Sequence, Tuple, Type\n\nimport cirq\nimport stim\n\nfrom ._i_error_gate import IErrorGate\nfrom ._ii_error_gate import IIErrorGate\nfrom ._ii_gate import IIGate\n\n\ndef _forward_single_str_tag(op: cirq.CircuitOperation) -> str:\n    tags = [tag for tag in op.tags if isinstance(tag, str)]\n    if len(tags) == 1:\n        return tags[0]\n    return \"\"\n\n\ndef cirq_circuit_to_stim_circuit(\n    circuit: cirq.AbstractCircuit,\n    *,\n    qubit_to_index_dict: Optional[Dict[cirq.Qid, int]] = None,\n    tag_func: Callable[[cirq.Operation], str] = _forward_single_str_tag,\n) -> stim.Circuit:\n    \"\"\"Converts a cirq circuit into an equivalent stim circuit.\n\n    Not all circuits can be converted. In order for a circuit to be convertible, all of its operations must be\n    convertible.\n\n    An operation is convertible if:\n        - It is a stabilizer gate or probabilistic Pauli gate from cirq\n            - cirq.H\n            - cirq.S\n            - cirq.X\n            - cirq.X**0.5\n            - cirq.CNOT\n            - cirq.ResetChannel()\n            - cirq.X.with_probability(p)\n            - cirq.DepolarizingChannel(p, n_qubits=1 or 2)\n            - etc\n        - Or it has a _decompose_ method that yields convertible operations.\n        - Or it has a correctly implemented _stim_conversion_ method.\n\n    Args:\n        circuit: The circuit to convert.\n        qubit_to_index_dict: Optional. Which integer each qubit should get mapped to. If not specified, defaults to\n            indexing qubits in the circuit in sorted order.\n        tag_func: Controls the tag attached to the stim instructions the cirq operation turns\n            into. If not specified, defaults to checking for string tags on the circuit operation\n            and if there is exactly one string tag then using that tag (otherwise not specifying a\n            tag).\n\n    Returns:\n        The converted circuit.\n\n    Examples:\n        >>> import cirq, stimcirq\n        >>> a = cirq.NamedQubit(\"zero\")\n        >>> b = cirq.NamedQubit(\"two\")\n        >>> stimcirq.cirq_circuit_to_stim_circuit(cirq.Circuit(\n        ...     cirq.Moment(cirq.H(a)),\n        ...     cirq.Moment(cirq.CNOT(a, b)),\n        ...     cirq.Moment(\n        ...         cirq.X(a).with_probability(0.25),\n        ...         cirq.Z(b).with_probability(0.25),\n        ...     ),\n        ...     cirq.Moment(),\n        ...     cirq.Moment(),\n        ...     cirq.Moment(cirq.DepolarizingChannel(0.125, n_qubits=2).on(b, a)),\n        ...     cirq.Moment(cirq.measure(a, b)),\n        ... ), qubit_to_index_dict={a: 0, b: 2})\n        stim.Circuit('''\n            H 0\n            TICK\n            CX 0 2\n            TICK\n            X_ERROR(0.25) 0\n            Z_ERROR(0.25) 2\n            TICK\n            TICK\n            TICK\n            DEPOLARIZE2(0.125) 2 0\n            TICK\n            M 0 2\n            TICK\n        ''')\n\n    Here is an example of a _stim_conversion_ method:\n\n        def _stim_conversion_(\n                self,\n\n                # The stim circuit being built. Add onto it.\n                edit_circuit: stim.Circuit,\n\n                # Metadata about measurement groupings needed by stimcirq.StimSampler.\n                # If your gate contains a measurement, it has to append how many qubits\n                # that measurement measures (and its key) into this list.\n                edit_measurement_key_lengths: List[Tuple[str, int]],\n\n                # The indices of qubits the gate is operating on.\n                targets: List[int],\n\n                # A custom string associated with the operation, which can be tagged\n                # onto any operations appended to the stim circuit.\n                tag: str,\n\n                # Forward compatibility with future arguments.\n                **kwargs):\n\n            edit_circuit.append_operation(\"H\", targets)\n    \"\"\"\n    return cirq_circuit_to_stim_data(circuit, q2i=qubit_to_index_dict, flatten=False, tag_func=tag_func)[0]\n\n\ndef cirq_circuit_to_stim_data(\n    circuit: cirq.AbstractCircuit,\n    *,\n    q2i: Optional[Dict[cirq.Qid, int]] = None,\n    flatten: bool = False,\n    tag_func: Callable[[cirq.Operation], str] = _forward_single_str_tag,\n) -> Tuple[stim.Circuit, List[Tuple[str, int]]]:\n    \"\"\"Converts a Cirq circuit into a Stim circuit and also metadata about where measurements go.\"\"\"\n    if q2i is None:\n        q2i = {q: i for i, q in enumerate(sorted(circuit.all_qubits()))}\n    helper = CirqToStimHelper(tag_func=tag_func)\n    helper.q2i = q2i\n    helper.flatten = flatten\n\n    for q in sorted(circuit.all_qubits()):\n        if isinstance(q, cirq.LineQubit):\n            i = q2i[q]\n            if i != q.x:\n                helper.out.append_operation(\"QUBIT_COORDS\", [i], [q.x])\n        elif isinstance(q, cirq.GridQubit):\n            helper.out.append_operation(\"QUBIT_COORDS\", [q2i[q]], [q.row, q.col])\n\n    helper.process_moments(circuit)\n    return helper.out, helper.key_out\n\n\nStimTypeHandler = Callable[[stim.Circuit, cirq.Gate, List[int], str], None]\n\n\n@functools.lru_cache(maxsize=1)\ndef gate_to_stim_append_func() -> Dict[cirq.Gate, Callable[[stim.Circuit, List[int], str], None]]:\n    \"\"\"A dictionary mapping specific gate instances to stim circuit appending functions.\"\"\"\n    x = (cirq.X, False)\n    y = (cirq.Y, False)\n    z = (cirq.Z, False)\n    nx = (cirq.X, True)\n    ny = (cirq.Y, True)\n    nz = (cirq.Z, True)\n\n    def do_nothing(_gates, _targets, tag):\n        pass\n\n    def use(\n        *gates: str, individuals: Sequence[Tuple[str, int]] = ()\n    ) -> Callable[[stim.Circuit, List[int], str], None]:\n        if len(gates) == 1 and not individuals:\n            (g,) = gates\n            return lambda c, t, tag: c.append(g, t, tag=tag)\n\n        if not individuals:\n\n            def do(c, t, tag: str):\n                for g in gates:\n                    c.append(g, t, tag=tag)\n\n        else:\n\n            def do(c, t, tag: str):\n                for g in gates:\n                    c.append(g, t, tag=tag)\n                for g, k in individuals:\n                    c.append(g, [t[k]], tag=tag)\n\n        return do\n\n    sqcg = cirq.SingleQubitCliffordGate.from_xz_map\n    paulis = cast(List[cirq.Pauli], [cirq.X, cirq.Y, cirq.Z])\n\n    return {\n        cirq.ResetChannel(): use(\"R\"),\n        # Identities.\n        cirq.I: use(\"I\"),\n        cirq.H ** 0: do_nothing,\n        cirq.X ** 0: do_nothing,\n        cirq.Y ** 0: do_nothing,\n        cirq.Z ** 0: do_nothing,\n        cirq.ISWAP ** 0: do_nothing,\n        cirq.SWAP ** 0: do_nothing,\n        # Common named gates.\n        cirq.H: use(\"H\"),\n        cirq.X: use(\"X\"),\n        cirq.Y: use(\"Y\"),\n        cirq.Z: use(\"Z\"),\n        cirq.X ** 0.5: use(\"SQRT_X\"),\n        cirq.X ** -0.5: use(\"SQRT_X_DAG\"),\n        cirq.Y ** 0.5: use(\"SQRT_Y\"),\n        cirq.Y ** -0.5: use(\"SQRT_Y_DAG\"),\n        cirq.Z ** 0.5: use(\"SQRT_Z\"),\n        cirq.Z ** -0.5: use(\"SQRT_Z_DAG\"),\n        cirq.CNOT: use(\"CNOT\"),\n        cirq.CZ: use(\"CZ\"),\n        cirq.ISWAP: use(\"ISWAP\"),\n        cirq.ISWAP ** -1: use(\"ISWAP_DAG\"),\n        cirq.ISWAP ** 2: use(\"Z\"),\n        cirq.SWAP: use(\"SWAP\"),\n        cirq.X.controlled(1): use(\"CX\"),\n        cirq.Y.controlled(1): use(\"CY\"),\n        cirq.Z.controlled(1): use(\"CZ\"),\n        cirq.XX ** 0.5: use(\"SQRT_XX\"),\n        cirq.YY ** 0.5: use(\"SQRT_YY\"),\n        cirq.ZZ ** 0.5: use(\"SQRT_ZZ\"),\n        cirq.XX ** -0.5: use(\"SQRT_XX_DAG\"),\n        cirq.YY ** -0.5: use(\"SQRT_YY_DAG\"),\n        cirq.ZZ ** -0.5: use(\"SQRT_ZZ_DAG\"),\n        # All 24 cirq.SingleQubitCliffordGate instances.\n        sqcg(x, y): use(\"SQRT_X_DAG\"),\n        sqcg(x, ny): use(\"SQRT_X\"),\n        sqcg(nx, y): use(\"H_YZ\"),\n        sqcg(nx, ny): use(\"H_NYZ\"),\n        sqcg(x, z): do_nothing,\n        sqcg(x, nz): use(\"X\"),\n        sqcg(nx, z): use(\"Z\"),\n        sqcg(nx, nz): use(\"Y\"),\n        sqcg(y, x): use(\"C_XYZ\"),\n        sqcg(y, nx): use(\"C_XYNZ\"),\n        sqcg(ny, x): use(\"C_XNYZ\"),\n        sqcg(ny, nx): use(\"C_NXYZ\"),\n        sqcg(y, z): use(\"S\"),\n        sqcg(y, nz): use(\"H_XY\"),\n        sqcg(ny, z): use(\"S_DAG\"),\n        sqcg(ny, nz): use(\"H_NXY\"),\n        sqcg(z, x): use(\"H\"),\n        sqcg(z, nx): use(\"SQRT_Y_DAG\"),\n        sqcg(nz, x): use(\"SQRT_Y\"),\n        sqcg(nz, nx): use(\"H_NXZ\"),\n        sqcg(z, y): use(\"C_ZYX\"),\n        sqcg(z, ny): use(\"C_ZNYX\"),\n        sqcg(nz, y): use(\"C_ZYNX\"),\n        sqcg(nz, ny): use(\"C_NZYX\"),\n        # All 36 cirq.PauliInteractionGate instances.\n        **{\n            cirq.PauliInteractionGate(p0, s0, p1, s1): use(\n                f\"{p0}C{p1}\", individuals=[(str(p1), 1)] * s0 + [(str(p0), 0)] * s1\n            )\n            for p0, s0, p1, s1 in itertools.product(paulis, [False, True], repeat=2)\n        },\n    }\n\n\n@functools.lru_cache()\ndef gate_type_to_stim_append_func() -> Dict[Type[cirq.Gate], StimTypeHandler]:\n    \"\"\"A dictionary mapping specific gate types to stim circuit appending functions.\"\"\"\n    return {\n        cirq.ControlledGate: cast(StimTypeHandler, _stim_append_controlled_gate),\n        cirq.DensePauliString: cast(StimTypeHandler, _stim_append_dense_pauli_string_gate),\n        cirq.MutableDensePauliString: cast(StimTypeHandler, _stim_append_dense_pauli_string_gate),\n        cirq.AsymmetricDepolarizingChannel: cast(\n            StimTypeHandler, _stim_append_asymmetric_depolarizing_channel\n        ),\n        cirq.BitFlipChannel: lambda c, g, t, tag: c.append(\n            \"X_ERROR\", t, cast(cirq.BitFlipChannel, g).p, tag=tag\n        ),\n        cirq.PhaseFlipChannel: lambda c, g, t, tag: c.append(\n            \"Z_ERROR\", t, cast(cirq.PhaseFlipChannel, g).p, tag=tag\n        ),\n        cirq.PhaseDampingChannel: lambda c, g, t, tag: c.append(\n            \"Z_ERROR\", t, 0.5 - math.sqrt(1 - cast(cirq.PhaseDampingChannel, g).gamma) / 2, tag=tag\n        ),\n        cirq.RandomGateChannel: cast(StimTypeHandler, _stim_append_random_gate_channel),\n        cirq.DepolarizingChannel: cast(StimTypeHandler, _stim_append_depolarizing_channel),\n    }\n\n\ndef _stim_append_measurement_gate(\n    circuit: stim.Circuit, gate: cirq.MeasurementGate, targets: List[int], tag: str\n):\n    for i, b in enumerate(gate.invert_mask):\n        if b:\n            targets[i] = stim.target_inv(targets[i])\n    circuit.append(\"M\", targets, tag=tag)\n\n\ndef _stim_append_pauli_measurement_gate(\n    circuit: stim.Circuit, gate: cirq.PauliMeasurementGate, targets: List[int], tag: str\n):\n    obs: cirq.DensePauliString = gate.observable()\n\n    # Convert to stim Pauli product targets.\n    if len(targets) == 0:\n        raise NotImplementedError(f\"len(targets)={len(targets)} == 0\")\n    new_targets = []\n    for t, p in zip(targets, obs.pauli_mask):\n        if p == 1:\n            t = stim.target_x(t, invert=not new_targets and obs.coefficient == -1)\n        elif p == 2:\n            t = stim.target_y(t, invert=not new_targets and obs.coefficient == -1)\n        elif p == 3:\n            t = stim.target_z(t, invert=not new_targets and obs.coefficient == -1)\n        else:\n            raise NotImplementedError(f\"obs={obs!r}\")\n        new_targets.append(t)\n        new_targets.append(stim.target_combiner())\n    new_targets.pop()\n\n    # Inverted result?\n    if obs.coefficient != 1 and obs.coefficient != -1:\n        raise NotImplementedError(f\"obs.coefficient={obs.coefficient!r} not in [1, -1]\")\n\n    circuit.append(\"MPP\", new_targets, tag=tag)\n\n\ndef _stim_append_spp_gate(\n    circuit: stim.Circuit, gate: cirq.PauliStringPhasorGate, targets: List[int], tag: str\n):\n    obs: cirq.DensePauliString = gate.dense_pauli_string\n    a = gate.exponent_neg\n    b = gate.exponent_pos\n    d = (a - b) % 2\n    if obs.coefficient == -1:\n        d += 1\n        d %= 2\n    if d != 0.5 and d != 1.5:\n        return False\n\n    new_targets = []\n    for t, p in zip(targets, obs.pauli_mask):\n        if p:\n            new_targets.append(stim.target_pauli(t, p))\n            new_targets.append(stim.target_combiner())\n    if len(new_targets) == 0:\n        return False\n    new_targets.pop()\n\n    circuit.append(\"SPP\" if d == 0.5 else \"SPP_DAG\", new_targets, tag=tag)\n    return True\n\n\ndef _stim_append_dense_pauli_string_gate(\n    c: stim.Circuit, g: cirq.BaseDensePauliString, t: List[int], tag: str\n):\n    gates = [None, \"X\", \"Y\", \"Z\"]\n    for p, k in zip(g.pauli_mask, t):\n        if p:\n            c.append(gates[p], [k], tag=tag)\n\n\ndef _stim_append_asymmetric_depolarizing_channel(\n    c: stim.Circuit, g: cirq.AsymmetricDepolarizingChannel, t: List[int], tag: str\n):\n    if cirq.num_qubits(g) == 1:\n        c.append(\"PAULI_CHANNEL_1\", t, [g.p_x, g.p_y, g.p_z], tag=tag)\n    elif cirq.num_qubits(g) == 2:\n        c.append(\n            \"PAULI_CHANNEL_2\",\n            t,\n            [\n                g.error_probabilities.get('IX', 0),\n                g.error_probabilities.get('IY', 0),\n                g.error_probabilities.get('IZ', 0),\n                g.error_probabilities.get('XI', 0),\n                g.error_probabilities.get('XX', 0),\n                g.error_probabilities.get('XY', 0),\n                g.error_probabilities.get('XZ', 0),\n                g.error_probabilities.get('YI', 0),\n                g.error_probabilities.get('YX', 0),\n                g.error_probabilities.get('YY', 0),\n                g.error_probabilities.get('YZ', 0),\n                g.error_probabilities.get('ZI', 0),\n                g.error_probabilities.get('ZX', 0),\n                g.error_probabilities.get('ZY', 0),\n                g.error_probabilities.get('ZZ', 0),\n            ],\n            tag=tag,\n        )\n    else:\n        raise NotImplementedError(f'cirq-to-stim gate {g!r}')\n\n\ndef _stim_append_depolarizing_channel(c: stim.Circuit, g: cirq.DepolarizingChannel, t: List[int], tag: str):\n    if g.num_qubits() == 1:\n        c.append(\"DEPOLARIZE1\", t, g.p, tag=tag)\n    elif g.num_qubits() == 2:\n        c.append(\"DEPOLARIZE2\", t, g.p, tag=tag)\n    else:\n        raise TypeError(f\"Don't know how to turn {g!r} into Stim operations.\")\n\n\ndef _stim_append_controlled_gate(c: stim.Circuit, g: cirq.ControlledGate, t: List[int], tag: str):\n    if isinstance(g.sub_gate, cirq.BaseDensePauliString) and g.num_controls() == 1:\n        gates = [None, \"CX\", \"CY\", \"CZ\"]\n        for p, k in zip(g.sub_gate.pauli_mask, t[1:]):\n            if p:\n                c.append(gates[p], [t[0], k], tag=tag)\n        if g.sub_gate.coefficient == 1j:\n            c.append(\"S\", t[:1], tag=tag)\n        elif g.sub_gate.coefficient == -1:\n            c.append(\"Z\", t[:1], tag=tag)\n        elif g.sub_gate.coefficient == -1j:\n            c.append(\"S_DAG\", t[:1], tag=tag)\n        elif g.sub_gate.coefficient == 1:\n            pass\n        else:\n            raise TypeError(f\"Phase kickback from {g!r} isn't a stabilizer operation.\")\n        return\n\n    raise TypeError(f\"Don't know how to turn controlled gate {g!r} into Stim operations.\")\n\n\ndef _stim_append_random_gate_channel(c: stim.Circuit, g: cirq.RandomGateChannel, t: List[int], tag: str):\n    if g.sub_gate in [cirq.X, cirq.Y, cirq.Z, cirq.I]:\n        c.append(f\"{g.sub_gate}_ERROR\", t, g.probability, tag=tag)\n    elif isinstance(g.sub_gate, IIGate):\n        c.append(f\"II_ERROR\", t, g.probability, tag=tag)\n    elif isinstance(g.sub_gate, cirq.DensePauliString):\n        target_p = [None, stim.target_x, stim.target_y, stim.target_z]\n        pauli_targets = [target_p[p](t) for t, p in zip(t, g.sub_gate.pauli_mask) if p]\n        c.append(f\"CORRELATED_ERROR\", pauli_targets, g.probability, tag=tag)\n    else:\n        raise NotImplementedError(\n            f\"Don't know how to turn probabilistic {g!r} into Stim operations.\"\n        )\n\n\nclass CirqToStimHelper:\n    def __init__(self, tag_func: Callable[[cirq.Operation], str]):\n        self.key_out: List[Tuple[str, int]] = []\n        self.out = stim.Circuit()\n        self.q2i = {}\n        self.have_seen_loop = False\n        self.flatten = False\n        self.tag_func = tag_func\n\n    def process_circuit_operation_into_repeat_block(self, op: cirq.CircuitOperation, tag: str) -> None:\n        if self.flatten or op.repetitions == 1:\n            moments = cirq.unroll_circuit_op(cirq.Circuit(op), deep=False, tags_to_check=None).moments\n            self.process_moments(moments)\n            self.out = self.out[:-1] # Remove a trailing TICK (to avoid double TICK)\n            return\n\n        child = CirqToStimHelper(tag_func=self.tag_func)\n        child.key_out = self.key_out\n        child.q2i = self.q2i\n        child.have_seen_loop = True\n        self.have_seen_loop = True\n        child.process_moments(op.transform_qubits(lambda q: op.qubit_map.get(q, q)).circuit)\n        self.out.append(stim.CircuitRepeatBlock(op.repetitions, child.out, tag=tag))\n\n    def process_operations(self, operations: Iterable[cirq.Operation]) -> None:\n        g2f = gate_to_stim_append_func()\n        t2f = gate_type_to_stim_append_func()\n        for op in operations:\n            assert isinstance(op, cirq.Operation)\n            tag = self.tag_func(op)\n            op = op.untagged\n            gate = op.gate\n            targets = [self.q2i[q] for q in op.qubits]\n\n            custom_method = getattr(\n                op, '_stim_conversion_', getattr(gate, '_stim_conversion_', None)\n            )\n            if custom_method is not None:\n                custom_method(\n                    dont_forget_your_star_star_kwargs=True,\n                    edit_circuit=self.out,\n                    edit_measurement_key_lengths=self.key_out,\n                    targets=targets,\n                    have_seen_loop=self.have_seen_loop,\n                    tag=tag,\n                )\n                continue\n\n            if isinstance(op, cirq.CircuitOperation):\n                self.process_circuit_operation_into_repeat_block(op, tag=tag)\n                continue\n\n            # Special case measurement, because of its metadata.\n            if isinstance(gate, cirq.PauliStringPhasorGate):\n                if _stim_append_spp_gate(self.out, gate, targets, tag=tag):\n                    continue\n            if isinstance(gate, cirq.PauliMeasurementGate):\n                self.key_out.append((gate.key, len(targets)))\n                _stim_append_pauli_measurement_gate(self.out, gate, targets, tag=tag)\n                continue\n            if isinstance(gate, cirq.MeasurementGate):\n                self.key_out.append((gate.key, len(targets)))\n                _stim_append_measurement_gate(self.out, gate, targets, tag=tag)\n                continue\n\n            # Look for recognized gate values like cirq.H.\n            val_append_func = g2f.get(gate)\n            if val_append_func is not None:\n                val_append_func(self.out, targets, tag=tag)\n                continue\n\n            # Look for recognized gate types like cirq.DepolarizingChannel.\n            type_append_func = t2f.get(type(gate))\n            if type_append_func is not None:\n                type_append_func(self.out, gate, targets, tag=tag)\n                continue\n\n            # Ask unrecognized operations to decompose themselves into simpler operations.\n            try:\n                self.process_operations(cirq.decompose_once(op))\n            except TypeError as ex:\n                raise TypeError(\n                    f\"Don't know how to translate {op!r} into stim gates.\\n\"\n                    f\"- It doesn't have a _decompose_ method that returns stim-compatible operations.\\n\"\n                    f\"- It doesn't have a _stim_conversion_ method.\\n\"\n                ) from ex\n\n    def process_moment(self, moment: cirq.Moment):\n        length_before = len(self.out)\n        self.process_operations(moment)\n\n        # Append a TICK, unless it was already handled by an internal REPEAT block.\n        if length_before == len(self.out) or not isinstance(self.out[-1], stim.CircuitRepeatBlock):\n            self.out.append(\"TICK\", [])\n\n    def process_moments(self, moments: Iterable[cirq.Moment]):\n        for moment in moments:\n            self.process_moment(moment)\n"
  },
  {
    "path": "glue/cirq/stimcirq/_cirq_to_stim_test.py",
    "content": "import itertools\nfrom typing import Dict, List, Sequence, Tuple, Union\n\nimport cirq\nimport numpy as np\nimport pytest\nimport stim\nimport stimcirq\nfrom stimcirq._cirq_to_stim import cirq_circuit_to_stim_data, gate_to_stim_append_func\n\n\ndef solve_tableau(gate: cirq.Gate) -> Dict[cirq.PauliString, cirq.PauliString]:\n    \"\"\"Computes a stabilizer tableau for the given gate.\"\"\"\n\n    result = {}\n\n    n = gate.num_qubits()\n    qs = cirq.LineQubit.range(n)\n    for inp in [g(q) for g in [cirq.X, cirq.Z] for q in qs]:\n        # Use superdense coding to extract X and Z flips from the generator conjugated by the gate.\n        c = cirq.Circuit(\n            cirq.H.on_each(qs),\n            [cirq.CNOT(q, q + n) for q in qs],\n            gate(*qs) ** -1,\n            inp,\n            gate(*qs),\n            [cirq.CNOT(q, q + n) for q in qs],\n            cirq.H.on_each(qs),\n            [cirq.measure(q, q + n, key=str(q)) for q in qs],\n        )\n\n        # Extract X/Y/Z data from sample result (which should be deterministic).\n        s = cirq.Simulator().sample(c)\n        out: cirq.PauliString = cirq.PauliString({q: \"IXZY\"[s[str(q)][0]] for q in qs})\n\n        # Use phase kickback to determine the sign of the output stabilizer.\n        sign = cirq.NamedQubit('a')\n        c = cirq.Circuit(\n            cirq.H(sign),\n            inp.controlled_by(sign),\n            gate(*qs),\n            out.controlled_by(sign),\n            cirq.H(sign),\n            cirq.measure(sign, key='sign'),\n        )\n        if cirq.Simulator().sample(c)['sign'][0]:\n            out *= -1\n\n        result[inp] = out\n    return result\n\n\ndef test_solve_tableau():\n    a, b = cirq.LineQubit.range(2)\n    assert solve_tableau(cirq.I) == {cirq.X(a): cirq.X(a), cirq.Z(a): cirq.Z(a)}\n    assert solve_tableau(cirq.S) == {cirq.X(a): cirq.Y(a), cirq.Z(a): cirq.Z(a)}\n    assert solve_tableau(cirq.S ** -1) == {cirq.X(a): -cirq.Y(a), cirq.Z(a): cirq.Z(a)}\n    assert solve_tableau(cirq.H) == {cirq.X(a): cirq.Z(a), cirq.Z(a): cirq.X(a)}\n    assert solve_tableau(\n        cirq.SingleQubitCliffordGate.from_xz_map((cirq.Y, False), (cirq.X, False))\n    ) == {cirq.X(a): cirq.Y(a), cirq.Z(a): cirq.X(a)}\n    assert solve_tableau(cirq.CZ) == {\n        cirq.X(a): cirq.X(a) * cirq.Z(b),\n        cirq.Z(a): cirq.Z(a),\n        cirq.X(b): cirq.Z(a) * cirq.X(b),\n        cirq.Z(b): cirq.Z(b),\n    }\n\n\ndef assert_unitary_gate_converts_correctly(gate: cirq.Gate):\n    n = gate.num_qubits()\n    for pre, post in solve_tableau(gate).items():\n        # Create a circuit that measures pre before the gate times post after the gate.\n        # If the gate is translated correctly, the measurement will always be zero.\n\n        c = stim.Circuit()\n        c.append(\"H\", range(n))\n        for i in range(n):\n            c.append(\"CNOT\", [i, i + n])\n        c.append(\"H\", [2 * n])\n        for q, p in pre.items():\n            c.append(f\"C{p}\", [2 * n, q.x])\n        qs = cirq.LineQubit.range(n)\n        conv_gate, _ = cirq_circuit_to_stim_data(cirq.Circuit(gate(*qs)), q2i={q: q.x for q in qs})\n        c += conv_gate\n        for q, p in post.items():\n            c.append(f\"C{p}\", [2 * n, q.x])\n        if post.coefficient == -1:\n            c.append(\"Z\", [2 * n])\n        c.append(\"H\", [2 * n])\n        c.append(\"M\", [2 * n])\n        correct = np.count_nonzero(c.compile_sampler().sample_bit_packed(10)) == 0\n        assert correct, f\"{gate!r} failed to turn {pre} into {post}.\\nConverted to:\\n{conv_gate}\\n\"\n\n\n@pytest.mark.parametrize(\"gate\", gate_to_stim_append_func().keys())\ndef test_unitary_gate_conversions(gate: cirq.Gate):\n    # Note: filtering in the parametrize annotation causes a false 'gate undefined' lint error.\n    if cirq.has_unitary(gate):\n        assert_unitary_gate_converts_correctly(gate)\n\n\ndef test_more_unitary_gate_conversions():\n    for p in [1, 1j, -1, -1j]:\n        assert_unitary_gate_converts_correctly(p * cirq.DensePauliString(\"IXYZ\"))\n        assert_unitary_gate_converts_correctly((p * cirq.DensePauliString(\"IXYZ\")).controlled(1))\n\n    a, b = cirq.LineQubit.range(2)\n    c, _ = cirq_circuit_to_stim_data(\n        cirq.Circuit(cirq.H(a), cirq.CNOT(a, b), cirq.measure(a, b), cirq.reset(a))\n    )\n    assert (\n        str(c).strip()\n        == \"\"\"\nH 0\nTICK\nCX 0 1\nTICK\nM 0 1\nTICK\nR 0\nTICK\n    \"\"\".strip()\n    )\n\n\nROUND_TRIP_NOISY_GATES = [\n    cirq.BitFlipChannel(0.1),\n    cirq.BitFlipChannel(0.2),\n    cirq.PhaseFlipChannel(0.1),\n    cirq.PhaseFlipChannel(0.2),\n    cirq.PhaseDampingChannel(0.1),\n    cirq.PhaseDampingChannel(0.2),\n    cirq.X.with_probability(0.1),\n    cirq.X.with_probability(0.2),\n    cirq.Y.with_probability(0.1),\n    cirq.Y.with_probability(0.2),\n    cirq.Z.with_probability(0.1),\n    cirq.Z.with_probability(0.2),\n    cirq.DepolarizingChannel(0.1),\n    cirq.DepolarizingChannel(0.2),\n    cirq.DepolarizingChannel(0.1, n_qubits=2),\n    cirq.DepolarizingChannel(0.2, n_qubits=2),\n    cirq.AsymmetricDepolarizingChannel(p_x=0, p_y=0, p_z=0),\n    cirq.AsymmetricDepolarizingChannel(p_x=0.2, p_y=0.1, p_z=0.3),\n    cirq.AsymmetricDepolarizingChannel(p_x=0.1, p_y=0, p_z=0),\n    cirq.AsymmetricDepolarizingChannel(p_x=0, p_y=0.1, p_z=0),\n    cirq.AsymmetricDepolarizingChannel(p_x=0, p_y=0, p_z=0.1),\n    *[\n        cirq.asymmetric_depolarize(error_probabilities={a + b: 0.1})\n        for a, b in list(itertools.product('IXYZ', repeat=2))[1:]\n    ],\n    cirq.asymmetric_depolarize(error_probabilities={'IX': 0.125, 'ZY': 0.375}),\n]\n\n\n@pytest.mark.parametrize(\"gate\", ROUND_TRIP_NOISY_GATES)\ndef test_frame_simulator_sampling_noisy_gates_agrees_with_cirq_data(gate: cirq.Gate):\n    # Create test circuit that uses superdense coding to quantify arbitrary Pauli error mixtures.\n    n = cirq.num_qubits(gate)\n    qs = cirq.LineQubit.range(n)\n    circuit = cirq.Circuit(\n        cirq.H.on_each(qs),\n        [cirq.CNOT(q, q + n) for q in qs],\n        gate(*qs),\n        [cirq.CNOT(q, q + n) for q in qs],\n        cirq.H.on_each(qs),\n    )\n    expected_rates = cirq.final_density_matrix(circuit).diagonal().real\n\n    # Convert test circuit to Stim and sample from it.\n    stim_circuit, _ = cirq_circuit_to_stim_data(\n        circuit + cirq.measure(*sorted(circuit.all_qubits())[::-1])\n    )\n    sample_count = 10000\n    samples = stim_circuit.compile_sampler().sample_bit_packed(sample_count).flat\n    unique, counts = np.unique(samples, return_counts=True)\n\n    # Compare sample rates to expected rates.\n    for value, count in zip(unique, counts):\n        expected_rate = expected_rates[value]\n        actual_rate = count / sample_count\n        allowed_variation = 5 * (expected_rate * (1 - expected_rate) / sample_count) ** 0.5\n        if not 0 <= expected_rate - allowed_variation <= 1:\n            raise ValueError(\"Not enough samples to bound results away from extremes.\")\n        assert abs(expected_rate - actual_rate) <= allowed_variation, (\n            f\"Sample rate {actual_rate} is over 5 standard deviations away from {expected_rate}.\\n\"\n            f\"Gate: {gate}\\n\"\n            f\"Test circuit:\\n{circuit}\\n\"\n            f\"Converted circuit:\\n{stim_circuit}\\n\"\n        )\n\n\n@pytest.mark.parametrize(\"gate\", ROUND_TRIP_NOISY_GATES)\ndef test_tableau_simulator_sampling_noisy_gates_agrees_with_cirq_data(gate: cirq.Gate):\n    # Technically this be a test of the `stim` package itself, but it's so convenient to compare to cirq.\n\n    # Create test circuit that uses superdense coding to quantify arbitrary Pauli error mixtures.\n    n = cirq.num_qubits(gate)\n    qs = cirq.LineQubit.range(n)\n    circuit = cirq.Circuit(\n        cirq.H.on_each(qs),\n        [cirq.CNOT(q, q + n) for q in qs],\n        gate(*qs),\n        [cirq.CNOT(q, q + n) for q in qs],\n        cirq.H.on_each(qs),\n    )\n    expected_rates = cirq.final_density_matrix(circuit).diagonal().real\n\n    # Convert test circuit to Stim and sample from it.\n    stim_circuit, _ = cirq_circuit_to_stim_data(\n        circuit + cirq.measure(*sorted(circuit.all_qubits())[::-1])\n    )\n    sample_count = 10000\n    samples = []\n    for _ in range(sample_count):\n        sim = stim.TableauSimulator()\n        sim.do(stim_circuit)\n        s = 0\n        for k, v in enumerate(sim.current_measurement_record()):\n            s |= v << k\n        samples.append(s)\n\n    unique, counts = np.unique(samples, return_counts=True)\n\n    # Compare sample rates to expected rates.\n    for value, count in zip(unique, counts):\n        expected_rate = expected_rates[value]\n        actual_rate = count / sample_count\n        allowed_variation = 5 * (expected_rate * (1 - expected_rate) / sample_count) ** 0.5\n        if not 0 <= expected_rate - allowed_variation <= 1:\n            raise ValueError(\"Not enough samples to bound results away from extremes.\")\n        assert abs(expected_rate - actual_rate) <= allowed_variation, (\n            f\"Sample rate {actual_rate} is over 5 standard deviations away from {expected_rate}.\\n\"\n            f\"Gate: {gate}\\n\"\n            f\"Test circuit:\\n{circuit}\\n\"\n            f\"Converted circuit:\\n{stim_circuit}\\n\"\n        )\n\n\ndef test_cirq_circuit_to_stim_circuit_custom_stim_method():\n    class DetectorGate(cirq.Gate):\n        def _num_qubits_(self):\n            return 1\n\n        def _measure_keys_(self):\n            return (\"custom\",)\n\n        def _stim_conversion_(\n            self,\n            edit_circuit: stim.Circuit,\n            edit_measurement_key_lengths: List[Tuple[str, int]],\n            targets: Sequence[int],\n            **kwargs,\n        ):\n            edit_measurement_key_lengths.append((\"custom\", 2))\n            edit_circuit.append(\"M\", [stim.target_inv(targets[0])])\n            edit_circuit.append(\"M\", [targets[0]])\n            edit_circuit.append(\"DETECTOR\", [stim.target_rec(-1)])\n\n    class SecondLastMeasurementWasDeterministicOperation(cirq.Operation):\n        def _stim_conversion_(self, edit_circuit: stim.Circuit, tag: str, **kwargs):\n            edit_circuit.append(\"DETECTOR\", [stim.target_rec(-2)], tag=tag)\n\n        def with_qubits(self, *new_qubits):\n            raise NotImplementedError()\n\n        @property\n        def qubits(self) -> Tuple['cirq.Qid', ...]:\n            return ()\n\n    a, b, c = cirq.LineQubit.range(3)\n    cirq_circuit = cirq.Circuit(\n        cirq.measure(a, key=\"a\"),\n        cirq.measure(b, key=\"b\"),\n        cirq.measure(c, key=\"c\"),\n        cirq.Moment(SecondLastMeasurementWasDeterministicOperation()),\n        cirq.Moment(DetectorGate().on(b)),\n    )\n\n    stim_circuit = stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit)\n    assert (\n        str(stim_circuit).strip()\n        == \"\"\"\nM 0 1 2\nTICK\nDETECTOR rec[-2]\nTICK\nM !1 1\nDETECTOR rec[-1]\nTICK\n    \"\"\".strip()\n    )\n\n    class BadGate(cirq.Gate):\n        def num_qubits(self) -> int:\n            return 1\n\n        def _stim_conversion_(self):\n            pass\n\n    with pytest.raises(TypeError, match=\"dont_forget_your_star_star_kwargs\"):\n        stimcirq.cirq_circuit_to_stim_circuit(cirq.Circuit(BadGate().on(a)))\n\n    sample = stimcirq.StimSampler().sample(cirq_circuit)\n    assert len(sample.columns) == 4\n    np.testing.assert_array_equal(sample[\"a\"], [0])\n    np.testing.assert_array_equal(sample[\"b\"], [0])\n    np.testing.assert_array_equal(sample[\"c\"], [0])\n    np.testing.assert_array_equal(sample[\"custom\"], [2])\n\n\ndef test_custom_qubit_indexing():\n    a = cirq.NamedQubit(\"a\")\n    b = cirq.NamedQubit(\"b\")\n    actual = stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(cirq.CNOT(a, b)), qubit_to_index_dict={a: 10, b: 15}\n    )\n    assert actual == stim.Circuit('CX 10 15\\nTICK')\n    actual = stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.FrozenCircuit(cirq.CNOT(a, b)), qubit_to_index_dict={a: 10, b: 15}\n    )\n    assert actual == stim.Circuit('CX 10 15\\nTICK')\n\n\ndef test_on_loop():\n    a, b = cirq.LineQubit.range(2)\n    c = cirq.Circuit(\n        cirq.CircuitOperation(\n            cirq.FrozenCircuit(\n                cirq.X(a),\n                cirq.X(b),\n                cirq.measure(a, key=\"a\"),\n                cirq.measure(b, key=\"b\"),\n            ),\n            repetitions=3,\n        )\n    )\n    result_normal = cirq.Simulator().run(c)\n    result_stim = stimcirq.StimSampler().run(c)\n    assert result_normal.records.keys() == result_stim.records.keys()\n    for k in result_normal.records.keys():\n        assert result_stim.records[k].shape == result_normal.records[k].shape\n\n\ndef test_multi_moment_circuit_operation():\n    q0 = cirq.LineQubit(0)\n    cc = cirq.Circuit(\n        cirq.CircuitOperation(\n            cirq.FrozenCircuit(\n                cirq.Moment(cirq.H(q0)),\n                cirq.Moment(cirq.H(q0)),\n                cirq.Moment(cirq.H(q0)),\n                cirq.Moment(cirq.H(q0)),\n            )\n        )\n    )\n    assert stimcirq.cirq_circuit_to_stim_circuit(cc) == stim.Circuit(\"\"\"\n        H 0\n        TICK\n        H 0\n        TICK\n        H 0\n        TICK\n        H 0\n        TICK\n    \"\"\")\n\n\ndef test_on_tagged_loop():\n    a, b = cirq.LineQubit.range(2)\n    c = cirq.Circuit(\n        cirq.CircuitOperation(\n            cirq.FrozenCircuit(\n                cirq.X(a),\n                cirq.X(b),\n                cirq.measure(a, key=\"a\"),\n                cirq.measure(b, key=\"b\"),\n            ),\n            repetitions=3,\n        ).with_tags('my_tag')\n    )\n\n    stim_circuit = stimcirq.cirq_circuit_to_stim_circuit(c)\n    assert stim.CircuitRepeatBlock in {type(instr) for instr in stim_circuit}\n\n\ndef test_random_gate_channel():\n    q0, q1 = cirq.LineQubit.range(2)\n\n    circuit = cirq.Circuit(cirq.RandomGateChannel(\n        sub_gate=cirq.DensePauliString((0, 1)),\n        probability=0.25).on(q0, q1))\n    assert stimcirq.cirq_circuit_to_stim_circuit(circuit) == stim.Circuit(\"\"\"\n        E(0.25) X1\n        TICK\n    \"\"\")\n\n\ndef test_custom_tagging():\n    assert stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            cirq.X(cirq.LineQubit(0)).with_tags('test'),\n            cirq.X(cirq.LineQubit(0)).with_tags((2, 3, 4)),\n            cirq.H(cirq.LineQubit(0)).with_tags('a', 'b'),\n        ),\n        tag_func=lambda op: \"PAIR\" if len(op.tags) == 2 else repr(op.tags),\n    ) == stim.Circuit(\"\"\"\n        X[('test',)] 0\n        TICK\n        X[((2, 3, 4),)] 0\n        TICK\n        H[PAIR] 0\n        TICK\n    \"\"\")\n\n\ndef test_round_trip_example_circuit():\n    stim_circuit = stim.Circuit.generated(\n        \"surface_code:rotated_memory_x\",\n        distance=3,\n        rounds=1,\n        after_clifford_depolarization=0.01,\n    )\n    cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit.flattened())\n    circuit_back = stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit)\n    assert len(circuit_back.shortest_graphlike_error()) == 3\n"
  },
  {
    "path": "glue/cirq/stimcirq/_cx_swap_gate.py",
    "content": "from typing import Any, Dict, List\n\nimport cirq\nimport stim\n\n\n@cirq.value_equality\nclass CXSwapGate(cirq.Gate):\n    \"\"\"Handles explaining stim's CXSWAP and SWAPCX gates to cirq.\"\"\"\n\n    def __init__(\n        self,\n        *,\n        inverted: bool,\n    ):\n        self.inverted = inverted\n\n    def _num_qubits_(self) -> int:\n        return 2\n\n    def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> List[str]:\n        return ['ZSWAP', 'XSWAP'][::-1 if self.inverted else +1]\n\n    def _value_equality_values_(self):\n        return (\n            self.inverted,\n        )\n\n    def _decompose_(self, qubits):\n        a, b = qubits\n        if self.inverted:\n            yield cirq.SWAP(a, b)\n            yield cirq.CNOT(a, b)\n        else:\n            yield cirq.CNOT(a, b)\n            yield cirq.SWAP(a, b)\n\n    def _stim_conversion_(self, edit_circuit: stim.Circuit, targets: List[int], tag: str, **kwargs):\n        edit_circuit.append('SWAPCX' if self.inverted else 'CXSWAP', targets, tag=tag)\n\n    def __pow__(self, power: int) -> 'CXSwapGate':\n        if power == +1:\n            return self\n        if power == -1:\n            return CXSwapGate(inverted=not self.inverted)\n        return NotImplemented\n\n    def __str__(self) -> str:\n        return 'SWAPCX' if self.inverted else 'CXSWAP'\n\n    def __repr__(self):\n        return f'stimcirq.CXSwapGate(inverted={self.inverted!r})'\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        return {\n            'inverted': self.inverted,\n        }\n"
  },
  {
    "path": "glue/cirq/stimcirq/_cx_swap_test.py",
    "content": "import cirq\nimport stim\nimport stimcirq\n\n\ndef test_stim_conversion():\n    a, b, c = cirq.LineQubit.range(3)\n\n    cirq_circuit = cirq.Circuit(\n        stimcirq.CXSwapGate(inverted=False).on(a, b),\n        stimcirq.CXSwapGate(inverted=True).on(b, c),\n    )\n    stim_circuit = stim.Circuit(\n        \"\"\"\n        CXSWAP 0 1\n        TICK\n        SWAPCX 1 2\n        TICK\n        \"\"\"\n    )\n    assert stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit) == stim_circuit\n    assert stimcirq.stim_circuit_to_cirq_circuit(stim_circuit) == cirq_circuit\n\n\ndef test_diagram():\n    a, b = cirq.LineQubit.range(2)\n    cirq.testing.assert_has_diagram(\n        cirq.Circuit(\n            stimcirq.CXSwapGate(inverted=False)(a, b),\n            stimcirq.CXSwapGate(inverted=True)(a, b),\n        ),\n        \"\"\"\n0: ---ZSWAP---XSWAP---\n      |       |\n1: ---XSWAP---ZSWAP---\n        \"\"\",\n        use_unicode_characters=False,\n    )\n\n\ndef test_inverse():\n    a = stimcirq.CXSwapGate(inverted=True)\n    b = stimcirq.CXSwapGate(inverted=False)\n    assert a**+1 == a\n    assert a**-1 == b\n    assert b**+1 == b\n    assert b**-1 == a\n\n\ndef test_repr():\n    val = stimcirq.CXSwapGate(inverted=True)\n    assert eval(repr(val), {\"stimcirq\": stimcirq}) == val\n    val = stimcirq.CXSwapGate(inverted=False)\n    assert eval(repr(val), {\"stimcirq\": stimcirq}) == val\n\n\ndef test_equality():\n    eq = cirq.testing.EqualsTester()\n    eq.add_equality_group(stimcirq.CXSwapGate(inverted=False), stimcirq.CXSwapGate(inverted=False))\n    eq.add_equality_group(stimcirq.CXSwapGate(inverted=True))\n\n\ndef test_json_serialization():\n    a, b, d = cirq.LineQubit.range(3)\n    c = cirq.Circuit(\n        stimcirq.CXSwapGate(inverted=False)(a, b),\n        stimcirq.CXSwapGate(inverted=False)(b, d),\n    )\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.CXSwapGate(inverted=True)\n    packed = '{\\n  \"cirq_type\": \"CXSwapGate\",\\n  \"inverted\": true\\n}'\n    assert cirq.to_json(raw) == packed\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n"
  },
  {
    "path": "glue/cirq/stimcirq/_cz_swap_gate.py",
    "content": "from typing import Any, Dict, List\n\nimport cirq\nimport stim\n\n\n@cirq.value_equality\nclass CZSwapGate(cirq.Gate):\n    \"\"\"Handles explaining stim's CZSWAP gates to cirq.\"\"\"\n\n    def _num_qubits_(self) -> int:\n        return 2\n\n    def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> List[str]:\n        return ['ZSWAP', 'ZSWAP']\n\n    def _value_equality_values_(self):\n        return ()\n\n    def _decompose_(self, qubits):\n        a, b = qubits\n        yield cirq.SWAP(a, b)\n        yield cirq.CZ(a, b)\n\n    def _stim_conversion_(self, edit_circuit: stim.Circuit, targets: List[int], tag: str, **kwargs):\n        edit_circuit.append('CZSWAP', targets, tag=tag)\n\n    def __pow__(self, power: int) -> 'CZSwapGate':\n        if power == +1:\n            return self\n        if power == -1:\n            return self\n        return NotImplemented\n\n    def __str__(self) -> str:\n        return 'CZSWAP'\n\n    def __repr__(self):\n        return f'stimcirq.CZSwapGate()'\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        return {}\n"
  },
  {
    "path": "glue/cirq/stimcirq/_cz_swap_test.py",
    "content": "import cirq\nimport stim\nimport stimcirq\n\n\ndef test_stim_conversion():\n    a, b, c = cirq.LineQubit.range(3)\n\n    cirq_circuit = cirq.Circuit(\n        stimcirq.CZSwapGate().on(a, b),\n        stimcirq.CZSwapGate().on(b, c),\n    )\n    stim_circuit = stim.Circuit(\n        \"\"\"\n        CZSWAP 0 1\n        TICK\n        CZSWAP 1 2\n        TICK\n        \"\"\"\n    )\n    assert stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit) == stim_circuit\n    assert stimcirq.stim_circuit_to_cirq_circuit(stim_circuit) == cirq_circuit\n\n\ndef test_diagram():\n    a, b = cirq.LineQubit.range(2)\n    cirq.testing.assert_has_diagram(\n        cirq.Circuit(\n            stimcirq.CZSwapGate()(a, b),\n            stimcirq.CZSwapGate()(a, b),\n        ),\n        \"\"\"\n0: ---ZSWAP---ZSWAP---\n      |       |\n1: ---ZSWAP---ZSWAP---\n        \"\"\",\n        use_unicode_characters=False,\n    )\n\n\ndef test_inverse():\n    a = stimcirq.CZSwapGate()\n    assert a**+1 == a\n    assert a**-1 == a\n\n\ndef test_repr():\n    val = stimcirq.CZSwapGate()\n    assert eval(repr(val), {\"stimcirq\": stimcirq}) == val\n\n\ndef test_equality():\n    eq = cirq.testing.EqualsTester()\n    eq.add_equality_group(stimcirq.CZSwapGate(), stimcirq.CZSwapGate())\n\n\ndef test_json_serialization():\n    a, b, d = cirq.LineQubit.range(3)\n    c = cirq.Circuit(\n        stimcirq.CZSwapGate()(a, b),\n        stimcirq.CZSwapGate()(b, d),\n    )\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.CZSwapGate()\n    packed = '{\\n  \"cirq_type\": \"CZSwapGate\"\\n}'\n    assert cirq.to_json(raw) == packed\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n"
  },
  {
    "path": "glue/cirq/stimcirq/_det_annotation.py",
    "content": "from typing import Any, Dict, Iterable, List, Tuple\n\nimport cirq\nimport stim\n\n\n@cirq.value_equality\nclass DetAnnotation(cirq.Operation):\n    \"\"\"Annotates that a particular combination of measurements is deterministic.\n\n    Creates a DETECTOR operation when converting to a stim circuit.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        parity_keys: Iterable[str] = (),\n        relative_keys: Iterable[int] = (),\n        coordinate_metadata: Iterable[float] = (),\n    ):\n        \"\"\"\n\n        Args:\n            parity_keys: The keys of some measurements with the property that their parity is always\n                the same under noiseless execution of the circuit.\n            relative_keys: Refers to measurements relative to this operation. For example,\n                relative key -1 is the previous measurement. All entries must be negative.\n            coordinate_metadata: An optional location for the detector. This has no effect on the\n                function of the circuit, but can be used by plotting tools.\n        \"\"\"\n        self.parity_keys = frozenset(parity_keys)\n        self.relative_keys = frozenset(relative_keys)\n        self.coordinate_metadata = tuple(coordinate_metadata)\n\n    @property\n    def qubits(self) -> Tuple[cirq.Qid, ...]:\n        return ()\n\n    def with_qubits(self, *new_qubits) -> 'DetAnnotation':\n        return self\n\n    def _value_equality_values_(self) -> Any:\n        return self.parity_keys, self.relative_keys, self.coordinate_metadata\n\n    def _circuit_diagram_info_(self, args: Any) -> str:\n        items: List[str] = [repr(e) for e in sorted(self.parity_keys)]\n        items += [f'rec[{e}]' for e in sorted(self.relative_keys)]\n        k = \",\".join(str(e) for e in items)\n        return f\"Det({k})\"\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        result = {\n            'parity_keys': sorted(self.parity_keys),\n            'coordinate_metadata': self.coordinate_metadata,\n        }\n        if self.relative_keys:\n            result['relative_keys'] = sorted(self.relative_keys)\n        return result\n\n    def __repr__(self) -> str:\n        return (\n            f'stimcirq.DetAnnotation('\n            f'parity_keys={sorted(self.parity_keys)}, '\n            f'relative_keys={sorted(self.relative_keys)}, '\n            f'coordinate_metadata={self.coordinate_metadata!r})'\n        )\n\n    def _decompose_(self):\n        return []\n\n    def _is_comment_(self) -> bool:\n        return True\n\n    def _stim_conversion_(\n        self,\n        *,\n        edit_circuit: stim.Circuit,\n        edit_measurement_key_lengths: List[Tuple[str, int]],\n        tag: str,\n        have_seen_loop: bool = False,\n        **kwargs,\n    ):\n        # Ideally these references would all be resolved ahead of time, to avoid the redundant\n        # linear search overhead and also to avoid the detectors and measurements being interleaved\n        # instead of grouped (grouping measurements is helpful for stabilizer simulation). But that\n        # didn't happen and this is the context we're called in and we're going to make it work.\n\n        if have_seen_loop and self.parity_keys:\n            raise NotImplementedError(\n                \"Measurement key conversion is not reliable when loops are present.\"\n            )\n\n        # Find indices of measurement record targets.\n        remaining = set(self.parity_keys)\n        rec_targets = [stim.target_rec(k) for k in sorted(self.relative_keys, reverse=True)]\n        for offset in range(len(edit_measurement_key_lengths)):\n            m_key, m_len = edit_measurement_key_lengths[-1 - offset]\n            if m_len != 1:\n                raise NotImplementedError(f\"multi-qubit measurement {m_key!r}\")\n            if m_key in remaining:\n                remaining.discard(m_key)\n                rec_targets.append(stim.target_rec(-1 - offset))\n                if not remaining:\n                    break\n        if remaining:\n            raise ValueError(\n                f\"{self!r} was processed before measurements it referenced ({sorted(remaining)!r}).\"\n                f\" Make sure the referenced measurements keys are actually in the circuit, and come\"\n                f\" in an earlier moment (or earlier in the same moment's operation order).\"\n            )\n\n        edit_circuit.append(\"DETECTOR\", rec_targets, self.coordinate_metadata, tag=tag)\n"
  },
  {
    "path": "glue/cirq/stimcirq/_det_annotation_test.py",
    "content": "import cirq\nimport numpy as np\nimport pytest\nimport stim\nimport stimcirq\n\n\ndef test_stim_conversion():\n    a, b, c = cirq.LineQubit.range(3)\n\n    with pytest.raises(ValueError, match=\"earlier\"):\n        stimcirq.cirq_circuit_to_stim_circuit(\n            cirq.Circuit(cirq.Moment(stimcirq.DetAnnotation(parity_keys=[\"unknown\"])))\n        )\n    with pytest.raises(ValueError, match=\"earlier\"):\n        stimcirq.cirq_circuit_to_stim_circuit(\n            cirq.Circuit(\n                cirq.Moment(\n                    stimcirq.DetAnnotation(parity_keys=[\"later\"]), cirq.measure(b, key=\"later\")\n                )\n            )\n        )\n    with pytest.raises(ValueError, match=\"earlier\"):\n        stimcirq.cirq_circuit_to_stim_circuit(\n            cirq.Circuit(\n                cirq.Moment(stimcirq.DetAnnotation(parity_keys=[\"later\"])),\n                cirq.Moment(cirq.measure(b, key=\"later\")),\n            )\n        )\n    assert stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            cirq.Moment(cirq.measure(b, key=\"earlier\")),\n            cirq.Moment(stimcirq.DetAnnotation(parity_keys=[\"earlier\"])),\n        )\n    ) == stim.Circuit(\n        \"\"\"\n        QUBIT_COORDS(1) 0\n        M 0\n        TICK\n        DETECTOR rec[-1]\n        TICK\n    \"\"\"\n    )\n    assert stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            cirq.Moment(\n                cirq.measure(b, key=\"earlier\"), stimcirq.DetAnnotation(parity_keys=[\"earlier\"])\n            )\n        )\n    ) == stim.Circuit(\n        \"\"\"\n        QUBIT_COORDS(1) 0\n        M 0\n        DETECTOR rec[-1]\n        TICK\n    \"\"\"\n    )\n\n    assert stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            cirq.Moment(cirq.measure(a, key=\"a\"), cirq.measure(b, key=\"b\")),\n            cirq.Moment(\n                stimcirq.DetAnnotation(parity_keys=[\"a\", \"b\"], coordinate_metadata=(1, 2, 3.5))\n            ),\n        )\n    ) == stim.Circuit(\n        \"\"\"\n        M 0 1\n        TICK\n        DETECTOR(1, 2, 3.5) rec[-1] rec[-2]\n        TICK\n    \"\"\"\n    )\n\n    assert stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            cirq.H(a),\n            cirq.CNOT(a, b),\n            cirq.CNOT(a, c),\n            cirq.Moment(\n                cirq.measure(a, key=\"a\"),\n                cirq.measure(b, key=\"b\"),\n                stimcirq.DetAnnotation(parity_keys=[\"a\", \"b\"]),\n                cirq.measure(c, key=\"c\"),\n                stimcirq.DetAnnotation(parity_keys=[\"a\", \"c\"]),\n            ),\n        )\n    ) == stim.Circuit(\n        \"\"\"\n        H 0\n        TICK\n        CNOT 0 1\n        TICK\n        CNOT 0 2\n        TICK\n        M 0 1\n        DETECTOR rec[-1] rec[-2]\n        M 2\n        DETECTOR rec[-1] rec[-3]\n        TICK\n    \"\"\"\n    )\n\n\ndef test_simulation():\n    a = cirq.LineQubit(0)\n    s = cirq.Simulator().sample(\n        cirq.Circuit(\n            cirq.X(a), cirq.measure(a, key=\"a\"), stimcirq.DetAnnotation(parity_keys=[\"a\"])\n        ),\n        repetitions=3,\n    )\n    np.testing.assert_array_equal(s[\"a\"], [1, 1, 1])\n\n\ndef test_diagram():\n    a, b = cirq.LineQubit.range(2)\n    cirq.testing.assert_has_diagram(\n        cirq.Circuit(\n            cirq.measure(a, key=\"a\"),\n            cirq.measure(b, key=\"b\"),\n            stimcirq.DetAnnotation(parity_keys=[\"a\", \"b\"]),\n        ),\n        \"\"\"\n0: ---M('a')---------\n\n1: ---M('b')---------\n      Det('a','b')\n        \"\"\",\n        use_unicode_characters=False,\n    )\n\n\ndef test_repr():\n    val = stimcirq.DetAnnotation(parity_keys=[\"a\", \"b\"], coordinate_metadata=(1, 2))\n    assert eval(repr(val), {\"stimcirq\": stimcirq}) == val\n\n\ndef test_equality():\n    eq = cirq.testing.EqualsTester()\n    eq.add_equality_group(stimcirq.DetAnnotation(), stimcirq.DetAnnotation())\n    eq.add_equality_group(stimcirq.DetAnnotation(parity_keys=[\"a\"]))\n    eq.add_equality_group(\n        stimcirq.DetAnnotation(parity_keys=[\"a\"], coordinate_metadata=[1, 2]),\n        stimcirq.DetAnnotation(parity_keys=[\"a\"], coordinate_metadata=(1, 2)),\n    )\n    eq.add_equality_group(stimcirq.DetAnnotation(parity_keys=[\"a\"], coordinate_metadata=(2, 1)))\n    eq.add_equality_group(stimcirq.DetAnnotation(parity_keys=[\"b\"]))\n    eq.add_equality_group(\n        stimcirq.DetAnnotation(parity_keys=[\"a\", \"b\"]),\n        stimcirq.DetAnnotation(parity_keys=[\"b\", \"a\"]),\n    )\n\n\ndef test_json_serialization():\n    c = cirq.Circuit(\n        stimcirq.DetAnnotation(parity_keys=[\"a\", \"b\"]),\n        stimcirq.DetAnnotation(parity_keys=[\"a\", \"b\"], relative_keys=[-3, -5]),\n        stimcirq.DetAnnotation(coordinate_metadata=(1, 2)),\n        stimcirq.DetAnnotation(parity_keys=[\"d\", \"c\"], coordinate_metadata=(1, 2, 3)),\n    )\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.DetAnnotation(parity_keys=['a'], relative_keys=[-2], coordinate_metadata=(3, 5))\n    packed = '{\\n  \"cirq_type\": \"DetAnnotation\",\\n  \"parity_keys\": [\\n    \"a\"\\n  ],\\n  \"coordinate_metadata\": [\\n    3,\\n    5\\n  ],\\n  \"relative_keys\": [\\n    -2\\n  ]\\n}'\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed\n"
  },
  {
    "path": "glue/cirq/stimcirq/_i_error_gate.py",
    "content": "from typing import Any, Dict, List, Iterable\n\nimport cirq\nimport stim\n\n\n\n@cirq.value_equality\nclass IErrorGate(cirq.Gate):\n    \"\"\"Handles explaining stim's I_ERROR gate to cirq.\"\"\"\n\n    def __init__(self, gate_args: Iterable[float]):\n        self.gate_args = tuple(gate_args)\n\n    def _num_qubits_(self) -> int:\n        return 1\n\n    def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> List[str]:\n        return [f'I_ERROR({self.gate_args})']\n\n    def _value_equality_values_(self):\n        return self.gate_args\n\n    def _decompose_(self, qubits):\n        pass\n\n    def _stim_conversion_(self, edit_circuit: stim.Circuit, targets: List[int], tag: str, **kwargs):\n        edit_circuit.append('I_ERROR', targets, arg=self.gate_args, tag=tag)\n\n    def __str__(self) -> str:\n        return 'I_ERROR(' + \",\".join(str(e) for e in self.gate_args) + ')'\n\n    def __repr__(self):\n        return f'stimcirq.IErrorGate({self.gate_args!r})'\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        return {'gate_args': self.gate_args}\n"
  },
  {
    "path": "glue/cirq/stimcirq/_i_error_gate_test.py",
    "content": "import cirq\nimport stimcirq\n\n\ndef test_repr():\n    r = stimcirq.IErrorGate([0.25, 0.125])\n    assert eval(repr(r), {'stimcirq': stimcirq}) == r\n    r = stimcirq.IErrorGate([])\n    assert eval(repr(r), {'stimcirq': stimcirq}) == r\n\n\ndef test_json_serialization():\n    r = stimcirq.IErrorGate([0.25, 0.125])\n    c = cirq.Circuit(r(cirq.LineQubit(1)))\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.IErrorGate([0.25, 0.125])\n    packed = '{\\n  \"cirq_type\": \"IErrorGate\",\\n  \"gate_args\": [\\n    0.25,\\n    0.125\\n  ]\\n}'\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed\n"
  },
  {
    "path": "glue/cirq/stimcirq/_ii_error_gate.py",
    "content": "from typing import Any, Dict, List, Iterable\n\nimport cirq\nimport stim\n\n\n\n@cirq.value_equality\nclass IIErrorGate(cirq.Gate):\n    \"\"\"Handles explaining stim's II_ERROR gate to cirq.\"\"\"\n\n    def __init__(self, gate_args: Iterable[float]):\n        self.gate_args = tuple(gate_args)\n\n    def _num_qubits_(self) -> int:\n        return 2\n\n    def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> List[str]:\n        return [f'II_ERROR({self.gate_args})', f'II_ERROR({self.gate_args})']\n\n    def _value_equality_values_(self):\n        return self.gate_args\n\n    def _decompose_(self, qubits):\n        pass\n\n    def _stim_conversion_(self, edit_circuit: stim.Circuit, targets: List[int], tag: str, **kwargs):\n        edit_circuit.append('II_ERROR', targets, arg=self.gate_args, tag=tag)\n\n    def __str__(self) -> str:\n        return 'II_ERROR(' + \",\".join(str(e) for e in self.gate_args) + ')'\n\n    def __repr__(self):\n        return f'stimcirq.IIErrorGate({self.gate_args!r})'\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        return {'gate_args': self.gate_args}\n"
  },
  {
    "path": "glue/cirq/stimcirq/_ii_error_gate_test.py",
    "content": "import cirq\nimport stimcirq\n\n\ndef test_repr():\n    r = stimcirq.IIErrorGate([0.25, 0.125])\n    assert eval(repr(r), {'stimcirq': stimcirq}) == r\n    r = stimcirq.IIErrorGate([])\n    assert eval(repr(r), {'stimcirq': stimcirq}) == r\n\n\ndef test_json_serialization():\n    r = stimcirq.IIErrorGate([0.25, 0.125])\n    c = cirq.Circuit(r(cirq.LineQubit(1), cirq.LineQubit(3)))\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.IIErrorGate([0.25, 0.125])\n    packed = '{\\n  \"cirq_type\": \"IIErrorGate\",\\n  \"gate_args\": [\\n    0.25,\\n    0.125\\n  ]\\n}'\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed\n"
  },
  {
    "path": "glue/cirq/stimcirq/_ii_gate.py",
    "content": "from typing import Any, Dict, List\n\nimport cirq\nimport stim\n\n@cirq.value_equality\nclass IIGate(cirq.Gate):\n    \"\"\"Handles explaining stim's II gate to cirq.\"\"\"\n\n    def _num_qubits_(self) -> int:\n        return 2\n\n    def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> List[str]:\n        return ['II', 'II']\n\n    def _value_equality_values_(self):\n        return ()\n\n    def _decompose_(self, qubits):\n        pass\n\n    def _stim_conversion_(self, edit_circuit: stim.Circuit, targets: List[int], tag: str, **kwargs):\n        edit_circuit.append('II', targets, tag=tag)\n\n    def __pow__(self, power: int) -> 'IIGate':\n        return self\n\n    def __str__(self) -> str:\n        return 'II'\n\n    def __repr__(self):\n        return f'stimcirq.IIGate()'\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        return {}\n"
  },
  {
    "path": "glue/cirq/stimcirq/_ii_gate_test.py",
    "content": "import cirq\nimport stimcirq\n\n\ndef test_repr():\n    r = stimcirq.IIGate()\n    assert eval(repr(r), {'stimcirq': stimcirq}) == r\n\n\ndef test_json_serialization():\n    r = stimcirq.IIGate()\n    c = cirq.Circuit(r(cirq.LineQubit(1), cirq.LineQubit(3)))\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.IIGate()\n    packed = '{\\n  \"cirq_type\": \"IIGate\"\\n}'\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed\n"
  },
  {
    "path": "glue/cirq/stimcirq/_measure_and_or_reset_gate.py",
    "content": "from typing import Any, Dict, List, Tuple\n\nimport cirq\nimport stim\n\n\n@cirq.value_equality\nclass MeasureAndOrResetGate(cirq.Gate):\n    \"\"\"Handles explaining stim's MX/MY/MZ/MRX/MRY/MRZ/RX/RY/RZ gates to cirq.\"\"\"\n\n    def __init__(\n        self,\n        measure: bool,\n        reset: bool,\n        basis: str,\n        invert_measure: bool,\n        key: str,\n        measure_flip_probability: float = 0,\n    ):\n        self.measure = measure\n        self.reset = reset\n        self.basis = basis\n        self.invert_measure = invert_measure\n        self.key = key\n        self.measure_flip_probability = measure_flip_probability\n\n    def _num_qubits_(self) -> int:\n        return 1\n\n    def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> str:\n        return str(self)\n\n    def resolve(self, target: cirq.Qid) -> cirq.Operation:\n        if (\n            self.basis == 'Z'\n            and self.measure\n            and self.measure_flip_probability == 0\n            and not self.reset\n        ):\n            return cirq.MeasurementGate(\n                num_qubits=1, key=self.key, invert_mask=(1,) if self.invert_measure else ()\n            ).on(target)\n\n        return MeasureAndOrResetGate(\n            measure=self.measure,\n            reset=self.reset,\n            basis=self.basis,\n            invert_measure=self.invert_measure,\n            key=self.key,\n            measure_flip_probability=self.measure_flip_probability,\n        ).on(target)\n\n    def _value_equality_values_(self):\n        return (\n            self.measure,\n            self.reset,\n            self.basis,\n            self.invert_measure,\n            self.key,\n            self.measure_flip_probability,\n        )\n\n    def _decompose_(self, qubits):\n        (q,) = qubits\n        if self.measure:\n            if self.basis == 'X':\n                yield cirq.H(q)\n            elif self.basis == 'Y':\n                yield cirq.X(q) ** 0.5\n            if self.measure_flip_probability:\n                raise NotImplementedError(\"Noisy measurement as a cirq operation.\")\n            else:\n                yield cirq.measure(\n                    q, key=self.key, invert_mask=(True,) if self.invert_measure else ()\n                )\n        if self.reset:\n            yield cirq.ResetChannel().on(q)\n        if self.measure or self.reset:\n            if self.basis == 'X':\n                yield cirq.H(q)\n            elif self.basis == 'Y':\n                yield cirq.X(q) ** -0.5\n\n    def _stim_op_name(self) -> str:\n        result = ''\n        if self.measure:\n            result += \"M\"\n        if self.reset:\n            result += \"R\"\n        if self.basis != 'Z':\n            result += self.basis\n        return result\n\n    def _stim_conversion_(self, *, edit_circuit: stim.Circuit, targets: List[int], tag: str, edit_measurement_key_lengths: List[Tuple[str, int]], **kwargs):\n        if self.measure:\n            edit_measurement_key_lengths.append((self.key, 1))\n        if self.invert_measure:\n            targets[0] = stim.target_inv(targets[0])\n        if self.measure_flip_probability:\n            edit_circuit.append_operation(\n                self._stim_op_name(), targets, self.measure_flip_probability, tag=tag\n            )\n        else:\n            edit_circuit.append_operation(self._stim_op_name(), targets, tag=tag)\n\n    def __str__(self) -> str:\n        result = self._stim_op_name()\n        if self.invert_measure:\n            result = \"!\" + result\n        if self.measure:\n            result += f\"('{self.key}')\"\n        if self.measure_flip_probability:\n            result += f\"^{self.measure_flip_probability:%}\"\n        return result\n\n    def __repr__(self):\n        return (\n            f'stimcirq.MeasureAndOrResetGate('\n            f'measure={self.measure!r}, '\n            f'reset={self.reset!r}, '\n            f'basis={self.basis!r}, '\n            f'invert_measure={self.invert_measure!r}, '\n            f'key={self.key!r}, '\n            f'measure_flip_probability={self.measure_flip_probability!r})'\n        )\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        return {\n            'measure': self.measure,\n            'reset': self.reset,\n            'basis': self.basis,\n            'invert_measure': self.invert_measure,\n            'key': self.key,\n            'measure_flip_probability': self.measure_flip_probability,\n        }\n"
  },
  {
    "path": "glue/cirq/stimcirq/_measure_and_or_reset_gate_test.py",
    "content": "import cirq\nimport stimcirq\n\n\ndef test_repr():\n    r = stimcirq.MeasureAndOrResetGate(\n        measure=True,\n        reset=True,\n        basis='Y',\n        key='result',\n        invert_measure=True,\n        measure_flip_probability=0.125,\n    )\n    assert eval(repr(r), {'stimcirq': stimcirq}) == r\n\n\ndef test_json_serialization():\n    r = stimcirq.MeasureAndOrResetGate(\n        measure=True,\n        reset=True,\n        basis='Y',\n        key='result',\n        invert_measure=True,\n        measure_flip_probability=0.125,\n    )\n    c = cirq.Circuit(r(cirq.LineQubit(1)))\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.MeasureAndOrResetGate(\n        measure=True,\n        reset=True,\n        basis='X',\n        key='res',\n        invert_measure=True,\n        measure_flip_probability=0.25,\n    )\n    packed = '{\\n  \"cirq_type\": \"MeasureAndOrResetGate\",\\n  \"measure\": true,\\n  \"reset\": true,\\n  \"basis\": \"X\",\\n  \"invert_measure\": true,\\n  \"key\": \"res\",\\n  \"measure_flip_probability\": 0.25\\n}'\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed\n"
  },
  {
    "path": "glue/cirq/stimcirq/_obs_annotation.py",
    "content": "from typing import Any, Dict, Iterable, List, Tuple\n\nimport cirq\nimport stim\n\n\n@cirq.value_equality\nclass CumulativeObservableAnnotation(cirq.Operation):\n    \"\"\"Annotates that a particular combination of measurements is part of a logical observable.\n\n    Creates an OBSERVABLE_INCLUDE operation when converting to a stim circuit.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        parity_keys: Iterable[str] = (),\n        relative_keys: Iterable[int] = (),\n        pauli_keys: Iterable[str] = (),\n        observable_index: int,\n    ):\n        \"\"\"\n\n        Args:\n            parity_keys: The keys of some measurements to include in the logical observable.\n            relative_keys: Refers to measurements relative to this operation. For example,\n                relative key -1 is the previous measurement. All entries must be negative.\n            observable_index: A unique index for the logical observable.\n        \"\"\"\n        self.parity_keys = frozenset(parity_keys)\n        self.relative_keys = frozenset(relative_keys)\n        self.pauli_keys = frozenset(pauli_keys)\n        self.observable_index = observable_index\n\n    @property\n    def qubits(self) -> Tuple[cirq.Qid, ...]:\n        return ()\n\n    def with_qubits(self, *new_qubits) -> 'CumulativeObservableAnnotation':\n        return self\n\n    def _value_equality_values_(self) -> Any:\n        return self.parity_keys, self.relative_keys, self.pauli_keys, self.observable_index\n\n    def _circuit_diagram_info_(self, args: Any) -> str:\n        items: List[str] = [repr(e) for e in sorted(self.parity_keys)]\n        items += [f'rec[{e}]' for e in sorted(self.relative_keys)]\n        items += sorted(self.pauli_keys)\n        k = \",\".join(str(e) for e in items)\n        return f\"Obs{self.observable_index}({k})\"\n\n    def __repr__(self) -> str:\n        return (\n            f'stimcirq.CumulativeObservableAnnotation('\n            f'parity_keys={sorted(self.parity_keys)}, '\n            f'relative_keys={sorted(self.relative_keys)}, '\n            f'pauli_keys={sorted(self.pauli_keys)}, '\n            f'observable_index={self.observable_index!r})'\n        )\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        result = {\n            'parity_keys': sorted(self.parity_keys),\n            'observable_index': self.observable_index,\n            'pauli_keys': sorted(self.pauli_keys),\n        }\n        if self.relative_keys:\n            result['relative_keys'] = sorted(self.relative_keys)\n        return result\n\n    def _decompose_(self):\n        return []\n\n    def _is_comment_(self) -> bool:\n        return True\n\n    def _stim_conversion_(\n        self,\n        *,\n        edit_circuit: stim.Circuit,\n        edit_measurement_key_lengths: List[Tuple[str, int]],\n        have_seen_loop: bool = False,\n        tag: str,\n        **kwargs,\n    ):\n        # Ideally these references would all be resolved ahead of time, to avoid the redundant\n        # linear search overhead and also to avoid the detectors and measurements being interleaved\n        # instead of grouped (grouping measurements is helpful for stabilizer simulation). But that\n        # didn't happen and this is the context we're called in and we're going to make it work.\n\n        if have_seen_loop and self.parity_keys:\n            raise NotImplementedError(\n                \"Measurement key conversion is not reliable when loops are present.\"\n            )\n\n        # Find indices of measurement record targets.\n        remaining = set(self.parity_keys)\n        rec_targets = [stim.target_rec(k) for k in sorted(self.relative_keys, reverse=True)]\n        for offset in range(len(edit_measurement_key_lengths)):\n            m_key, m_len = edit_measurement_key_lengths[-1 - offset]\n            if m_len != 1:\n                raise NotImplementedError(f\"multi-qubit measurement {m_key!r}\")\n            if m_key in remaining:\n                remaining.discard(m_key)\n                rec_targets.append(stim.target_rec(-1 - offset))\n                if not remaining:\n                    break\n        rec_targets.extend(\n            [\n                stim.target_pauli(qubit_index=int(k[1:]), pauli=k[0]) \n                for k in sorted(self.pauli_keys)\n            ]\n        )\n        if remaining:\n            raise ValueError(\n                f\"{self!r} was processed before measurements it referenced ({sorted(remaining)!r}).\"\n                f\" Make sure the referenced measurements keys are actually in the circuit, and come\"\n                f\" in an earlier moment (or earlier in the same moment's operation order).\"\n            )\n\n        edit_circuit.append(\"OBSERVABLE_INCLUDE\", rec_targets, self.observable_index, tag=tag)\n"
  },
  {
    "path": "glue/cirq/stimcirq/_obs_annotation_test.py",
    "content": "import cirq\nimport numpy as np\nimport pytest\nimport stim\nimport stimcirq\n\n\ndef test_stim_conversion():\n    a, b, c = cirq.LineQubit.range(3)\n\n    with pytest.raises(ValueError, match=\"earlier\"):\n        stimcirq.cirq_circuit_to_stim_circuit(\n            cirq.Circuit(\n                cirq.Moment(\n                    stimcirq.CumulativeObservableAnnotation(\n                        parity_keys=[\"unknown\"], observable_index=0\n                    )\n                )\n            )\n        )\n    with pytest.raises(ValueError, match=\"earlier\"):\n        stimcirq.cirq_circuit_to_stim_circuit(\n            cirq.Circuit(\n                cirq.Moment(\n                    stimcirq.CumulativeObservableAnnotation(\n                        parity_keys=[\"later\"], observable_index=0\n                    ),\n                    cirq.measure(b, key=\"later\"),\n                )\n            )\n        )\n    with pytest.raises(ValueError, match=\"earlier\"):\n        stimcirq.cirq_circuit_to_stim_circuit(\n            cirq.Circuit(\n                cirq.Moment(\n                    stimcirq.CumulativeObservableAnnotation(\n                        parity_keys=[\"later\"], observable_index=0\n                    )\n                ),\n                cirq.Moment(cirq.measure(b, key=\"later\")),\n            )\n        )\n    assert stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            cirq.Moment(cirq.measure(b, key=\"earlier\")),\n            cirq.Moment(\n                stimcirq.CumulativeObservableAnnotation(parity_keys=[\"earlier\"], observable_index=0)\n            ),\n        )\n    ) == stim.Circuit(\n        \"\"\"\n        QUBIT_COORDS(1) 0\n        M 0\n        TICK\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        TICK\n    \"\"\"\n    )\n    assert stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            cirq.Moment(\n                cirq.measure(b, key=\"earlier\"),\n                stimcirq.CumulativeObservableAnnotation(\n                    parity_keys=[\"earlier\"], observable_index=0\n                ),\n            )\n        )\n    ) == stim.Circuit(\n        \"\"\"\n        QUBIT_COORDS(1) 0\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        TICK\n    \"\"\"\n    )\n\n    assert stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            cirq.Moment(cirq.measure(a, key=\"a\"), cirq.measure(b, key=\"b\")),\n            cirq.Moment(\n                stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\", \"b\"], observable_index=2)\n            ),\n        )\n    ) == stim.Circuit(\n        \"\"\"\n        M 0 1\n        TICK\n        OBSERVABLE_INCLUDE(2) rec[-1] rec[-2]\n        TICK\n    \"\"\"\n    )\n\n    assert stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            cirq.H(a),\n            cirq.CNOT(a, b),\n            cirq.CNOT(a, c),\n            cirq.Moment(\n                cirq.measure(a, key=\"a\"),\n                cirq.measure(b, key=\"b\"),\n                stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\", \"b\"], observable_index=0),\n                cirq.measure(c, key=\"c\"),\n                stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\", \"c\"], observable_index=0),\n            ),\n        )\n    ) == stim.Circuit(\n        \"\"\"\n        H 0\n        TICK\n        CNOT 0 1\n        TICK\n        CNOT 0 2\n        TICK\n        M 0 1\n        OBSERVABLE_INCLUDE(0) rec[-1] rec[-2]\n        M 2\n        OBSERVABLE_INCLUDE(0) rec[-1] rec[-3]\n        TICK\n    \"\"\"\n    )\n\n\ndef test_simulation():\n    a = cirq.LineQubit(0)\n    s = cirq.Simulator().sample(\n        cirq.Circuit(\n            cirq.X(a),\n            cirq.measure(a, key=\"a\"),\n            stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\"], observable_index=0),\n        ),\n        repetitions=3,\n    )\n    np.testing.assert_array_equal(s[\"a\"], [1, 1, 1])\n\n\ndef test_diagram():\n    a, b = cirq.LineQubit.range(2)\n    cirq.testing.assert_has_diagram(\n        cirq.Circuit(\n            cirq.measure(a, key=\"a\"),\n            cirq.measure(b, key=\"b\"),\n            stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\", \"b\"], observable_index=2),\n        ),\n        \"\"\"\n0: ---M('a')----------\n\n1: ---M('b')----------\n      Obs2('a','b')\n        \"\"\",\n        use_unicode_characters=False,\n    )\n\n\ndef test_repr():\n    val = stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\", \"b\"], observable_index=2)\n    assert eval(repr(val), {\"stimcirq\": stimcirq}) == val\n\n\ndef test_equality():\n    eq = cirq.testing.EqualsTester()\n    eq.add_equality_group(\n        stimcirq.CumulativeObservableAnnotation(observable_index=0),\n        stimcirq.CumulativeObservableAnnotation(observable_index=0),\n    )\n    eq.add_equality_group(stimcirq.CumulativeObservableAnnotation(observable_index=1))\n    eq.add_equality_group(\n        stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\"], observable_index=0)\n    )\n    eq.add_equality_group(\n        stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\"], observable_index=1)\n    )\n    eq.add_equality_group(\n        stimcirq.CumulativeObservableAnnotation(parity_keys=[\"b\"], observable_index=0)\n    )\n    eq.add_equality_group(\n        stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\", \"b\"], observable_index=0),\n        stimcirq.CumulativeObservableAnnotation(parity_keys=[\"b\", \"a\"], observable_index=0),\n    )\n\n\ndef test_json_serialization():\n    c = cirq.Circuit(\n        stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\", \"b\"], observable_index=5),\n        stimcirq.CumulativeObservableAnnotation(\n            parity_keys=[\"a\", \"b\"], relative_keys=[-1, -3], observable_index=5\n        ),\n        stimcirq.CumulativeObservableAnnotation(observable_index=2),\n        stimcirq.CumulativeObservableAnnotation(parity_keys=[\"d\", \"c\"], observable_index=5),\n    )\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\ndef test_json_serialization_with_pauli_keys():\n    c = cirq.Circuit(\n        stimcirq.CumulativeObservableAnnotation(parity_keys=[\"a\", \"b\"], observable_index=5, pauli_keys=[\"X0\", \"Y1\", \"Z2\"]),\n        stimcirq.CumulativeObservableAnnotation(\n            parity_keys=[\"a\", \"b\"], relative_keys=[-1, -3], observable_index=5, pauli_keys=[\"X0\", \"Y1\", \"Z2\"]\n        ),\n        stimcirq.CumulativeObservableAnnotation(observable_index=2, pauli_keys=[\"X0\", \"Y1\", \"Z2\"]),\n        stimcirq.CumulativeObservableAnnotation(parity_keys=[\"d\", \"c\"], observable_index=5, pauli_keys=[\"X0\", \"Y1\", \"Z2\"]),\n    )\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.CumulativeObservableAnnotation(parity_keys=['z'], relative_keys=[-2], observable_index=5)\n    packed_v1 = '{\\n  \"cirq_type\": \"CumulativeObservableAnnotation\",\\n  \"parity_keys\": [\\n    \"z\"\\n  ],\\n  \"observable_index\": 5,\\n  \"relative_keys\": [\\n    -2\\n  ]\\n}'\n    packed_v2 ='{\\n  \"cirq_type\": \"CumulativeObservableAnnotation\",\\n  \"parity_keys\": [\\n    \"z\"\\n  ],\\n  \"observable_index\": 5,\\n  \"pauli_keys\": [],\\n  \"relative_keys\": [\\n    -2\\n  ]\\n}'\n    assert cirq.read_json(json_text=packed_v1, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.read_json(json_text=packed_v2, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed_v2\n\n    # With pauli_keys\n    raw = stimcirq.CumulativeObservableAnnotation(parity_keys=['z'], relative_keys=[-2], observable_index=5, pauli_keys=[\"X0\", \"Y1\", \"Z2\"])\n    packed_v2 ='{\\n  \"cirq_type\": \"CumulativeObservableAnnotation\",\\n  \"parity_keys\": [\\n    \"z\"\\n  ],\\n  \"observable_index\": 5,\\n  \"pauli_keys\": [\\n    \"X0\",\\n    \"Y1\",\\n    \"Z2\"\\n  ],\\n  \"relative_keys\": [\\n    -2\\n  ]\\n}'\n    assert cirq.read_json(json_text=packed_v2, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed_v2"
  },
  {
    "path": "glue/cirq/stimcirq/_shift_coords_annotation.py",
    "content": "from typing import Any, Dict, Iterable, List, Tuple\n\nimport cirq\nimport stim\n\n\n@cirq.value_equality\nclass ShiftCoordsAnnotation(cirq.Operation):\n    \"\"\"Annotates that the qubit/detector coordinate origin is being moved.\n\n    Creates a SHIFT_COORDS operation when converting to a stim circuit.\n    \"\"\"\n\n    def __init__(self, shift: Iterable[float]):\n        \"\"\"\n\n        Args:\n            shift: How much to shift each coordinate..\n        \"\"\"\n        self.shift = tuple(shift)\n\n    @property\n    def qubits(self) -> Tuple[cirq.Qid, ...]:\n        return ()\n\n    def with_qubits(self, *new_qubits) -> 'ShiftCoordsAnnotation':\n        return self\n\n    def _value_equality_values_(self) -> Any:\n        return self.shift\n\n    def _circuit_diagram_info_(self, args: Any) -> str:\n        k = \",\".join(repr(e) for e in self.shift)\n        return f\"ShiftCoords({k})\"\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        return {'shift': self.shift}\n\n    def __repr__(self) -> str:\n        return f'stimcirq.ShiftCoordsAnnotation({self.shift!r})'\n\n    def _decompose_(self):\n        return []\n\n    def _is_comment_(self) -> bool:\n        return True\n\n    def _stim_conversion_(self, *, edit_circuit: stim.Circuit, tag: str, **kwargs):\n        edit_circuit.append_operation(\"SHIFT_COORDS\", [], self.shift, tag=tag)\n"
  },
  {
    "path": "glue/cirq/stimcirq/_shift_coords_annotation_test.py",
    "content": "import cirq\nimport numpy as np\nimport stim\nimport stimcirq\n\n\ndef test_conversion():\n    stim_circuit = stim.Circuit(\"\"\"\n        M 0\n        DETECTOR(4) rec[-1]\n        SHIFT_COORDS(1, 2, 3)\n        DETECTOR(5) rec[-1]\n        TICK\n    \"\"\")\n    cirq_circuit = cirq.Circuit(\n        cirq.measure(cirq.LineQubit(0), key=\"0\"),\n        stimcirq.DetAnnotation(parity_keys=[\"0\"], coordinate_metadata=[4]),\n        stimcirq.ShiftCoordsAnnotation((1, 2, 3)),\n        stimcirq.DetAnnotation(parity_keys=[\"0\"], coordinate_metadata=[5]),\n    )\n    assert stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit) == stim_circuit\n    assert stimcirq.stim_circuit_to_cirq_circuit(stim_circuit) == cirq_circuit\n    assert stimcirq.stim_circuit_to_cirq_circuit(stim_circuit, flatten=False) == cirq_circuit\n    assert stimcirq.stim_circuit_to_cirq_circuit(stim_circuit, flatten=True) == cirq.Circuit(\n        cirq.measure(cirq.LineQubit(0), key=\"0\"),\n        stimcirq.DetAnnotation(parity_keys=[\"0\"], coordinate_metadata=[4]),\n        stimcirq.DetAnnotation(parity_keys=[\"0\"], coordinate_metadata=[6]),\n    )\n\n\ndef test_simulation():\n    a = cirq.LineQubit(0)\n    s = cirq.Simulator().sample(\n        cirq.Circuit(\n            cirq.X(a), cirq.measure(a, key=\"a\"), stimcirq.ShiftCoordsAnnotation((1, 2, 3))\n        ),\n        repetitions=3,\n    )\n    np.testing.assert_array_equal(s[\"a\"], [1, 1, 1])\n\n\ndef test_diagram():\n    a, b = cirq.LineQubit.range(2)\n    cirq.testing.assert_has_diagram(\n        cirq.Circuit(\n            cirq.measure(a, key=\"a\"),\n            cirq.measure(b, key=\"b\"),\n            stimcirq.ShiftCoordsAnnotation([1, 2, 3]),\n        ),\n        \"\"\"\n0: ---M('a')---------------\n\n1: ---M('b')---------------\n      ShiftCoords(1,2,3)\n        \"\"\",\n        use_unicode_characters=False,\n    )\n\n\ndef test_repr():\n    val = stimcirq.ShiftCoordsAnnotation([1, 2, 3])\n    assert eval(repr(val), {\"stimcirq\": stimcirq}) == val\n\n\ndef test_equality():\n    eq = cirq.testing.EqualsTester()\n    eq.add_equality_group(stimcirq.ShiftCoordsAnnotation([]))\n    eq.add_equality_group(\n        stimcirq.ShiftCoordsAnnotation([1, 2]), stimcirq.ShiftCoordsAnnotation((1, 2))\n    )\n\n\ndef test_json_serialization():\n    c = cirq.Circuit(stimcirq.ShiftCoordsAnnotation([1, 2, 3]))\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.ShiftCoordsAnnotation([2, 3, 5])\n    packed = '{\\n  \"cirq_type\": \"ShiftCoordsAnnotation\",\\n  \"shift\": [\\n    2,\\n    3,\\n    5\\n  ]\\n}'\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed\n"
  },
  {
    "path": "glue/cirq/stimcirq/_stim_sampler.py",
    "content": "import collections\nfrom typing import Dict, List, Sequence\n\nimport cirq\n\nfrom ._cirq_to_stim import cirq_circuit_to_stim_data\n\n\ntry:\n    ResultImpl = cirq.ResultDict  # For cirq >= 0.14\nexcept AttributeError:\n    ResultImpl = cirq.Result  # For cirq < 0.14\n\n\nclass StimSampler(cirq.Sampler):\n    \"\"\"Samples stabilizer circuits using Stim.\n\n    Supports circuits that contain Clifford operations, measurement operations, reset operations, and noise operations\n    that can be decomposed into probabilistic Pauli operations. Unknown operations are supported as long as they provide\n    a decomposition into supported operations via `cirq.decompose` (i.e. via a `_decompose_` method).\n\n    Note that batch sampling is significantly faster (as in potentially thousands of times faster) than individual\n    sampling, because it amortizes the cost of parsing and analyzing the circuit.\n    \"\"\"\n\n    def run_sweep(\n        self, program: cirq.Circuit, params: cirq.Sweepable, repetitions: int = 1\n    ) -> Sequence[cirq.Result]:\n        results: List[cirq.Result] = []\n        for param_resolver in cirq.to_resolvers(params):\n            # Request samples from stim.\n            instance = cirq.resolve_parameters(program, param_resolver)\n            converted_circuit, key_ranges = cirq_circuit_to_stim_data(instance, flatten=True)\n            samples = converted_circuit.compile_sampler().sample(repetitions)\n\n            # Find number of qubits (length), number of instances, and indices for each measurement key.\n            lengths: Dict[str, int] = {}\n            instances: Dict[str, int] = collections.Counter()\n            indices: Dict[str, int] = collections.defaultdict(list)\n            k = 0\n            for key, length in key_ranges:\n                prev_length = lengths.get(key)\n                if prev_length is None:\n                    lengths[key] = length\n                elif length != prev_length:\n                    raise ValueError(f\"different numbers of qubits for key {key}: {prev_length} != {length}\")\n                instances[key] += 1\n                indices[key].extend(range(k, k + length))\n                k += length\n\n            # Convert unlabelled samples into keyed results.\n            records = {\n                key: samples[:, indices[key]].reshape((repetitions, instances[key], length))\n                for key, length in lengths.items()\n            }\n            results.append(ResultImpl(params=param_resolver, records=records))\n\n        return results\n"
  },
  {
    "path": "glue/cirq/stimcirq/_stim_sampler_test.py",
    "content": "import cirq\nimport numpy as np\nimport pytest\nimport stimcirq\n\n\ndef test_end_to_end():\n    sampler = stimcirq.StimSampler()\n    a, b = cirq.LineQubit.range(2)\n    result = sampler.run(\n        cirq.Circuit(\n            cirq.H(a),\n            cirq.CNOT(a, b),\n            cirq.X(a) ** 0.5,\n            cirq.X(b) ** 0.5,\n            cirq.measure(a, key='a'),\n            cirq.measure(b, key='b'),\n        ),\n        repetitions=1000,\n    )\n    np.testing.assert_array_equal(result.measurements['a'], result.measurements['b'] ^ 1)\n\n\ndef test_end_to_end_repeated_keys():\n    sampler = stimcirq.StimSampler()\n    a, b = cirq.LineQubit.range(2)\n    result = sampler.run(\n        cirq.Circuit(\n            cirq.CircuitOperation(\n                cirq.FrozenCircuit(\n                    cirq.H(a),\n                    cirq.CNOT(a, b),\n                    cirq.X(a) ** 0.5,\n                    cirq.X(b) ** 0.5,\n                    cirq.measure(a, b, key='m'),\n                    cirq.reset_each(a, b),\n                ),\n                repetitions=10,\n                use_repetition_ids=False,\n            ),\n        ),\n        repetitions=1000,\n    )\n    with pytest.raises(ValueError, match='Cannot extract 2D measurements for repeated keys'):\n        _ = result.measurements['m']\n    data = result.records['m']\n    assert data.shape == (1000, 10, 2)\n    np.testing.assert_array_equal(data[:,:,0], data[:,:,1] ^ 1)\n\n\ndef test_endian():\n    a, b = cirq.LineQubit.range(2)\n    circuit = cirq.Circuit(cirq.X(a), cirq.measure(a, b, key='out'))\n    s1 = cirq.Simulator().sample(circuit)\n    s2 = stimcirq.StimSampler().sample(circuit)\n    assert s1['out'][0] == s2['out'][0]\n\n\ndef test_custom_gates():\n    s = stimcirq.StimSampler()\n    a, b, c, d = cirq.LineQubit.range(4)\n\n    class GoodGate(cirq.Gate):\n        def _num_qubits_(self) -> int:\n            return 1\n\n        def _decompose_(self, qubits):\n            return [cirq.X.on_each(*qubits)]\n\n    class IndirectlyGoodGate(cirq.Gate):\n        def _num_qubits_(self) -> int:\n            return 1\n\n        def _decompose_(self, qubits):\n            return [GoodGate().on_each(*qubits)]\n\n    class BadGate(cirq.Gate):\n        def _num_qubits_(self) -> int:\n            return 1\n\n    class IndirectlyBadGate(cirq.Gate):\n        def _num_qubits_(self) -> int:\n            return 1\n\n        def _decompose_(self):\n            return [BadGate()]\n\n    np.testing.assert_array_equal(\n        s.sample(cirq.Circuit(GoodGate().on(a), cirq.measure(a, key='out')))['out'], [True]\n    )\n\n    np.testing.assert_array_equal(\n        s.sample(cirq.Circuit(IndirectlyGoodGate().on(a), cirq.measure(a, key='out')))['out'],\n        [True],\n    )\n\n    with pytest.raises(TypeError, match=\"BadGate.+into stim\"):\n        s.sample(cirq.Circuit(BadGate().on(a)))\n\n    with pytest.raises(TypeError, match=\"IndirectlyBadGate.+into stim\"):\n        s.sample(cirq.Circuit(IndirectlyBadGate().on(a)))\n\n    with pytest.raises(TypeError, match=\"into stim\"):\n        s.sample(cirq.Circuit(cirq.TOFFOLI(a, b, c)))\n\n\ndef test_custom_measurement():\n    class XBasisMeasurement(cirq.Gate):\n        def __init__(self, key: str):\n            self.key = key\n\n        def _num_qubits_(self) -> int:\n            return 1\n\n        def _decompose_(self, qubits):\n            (q,) = qubits\n            return [cirq.H(q), cirq.measure(q, key=self.key), cirq.H(q)]\n\n    s = stimcirq.StimSampler()\n    a, b = cirq.LineQubit.range(2)\n    out = s.sample(\n        cirq.Circuit(\n            cirq.H(a),\n            cirq.X(b),\n            cirq.H(b),\n            XBasisMeasurement(\"a\").on(a),\n            XBasisMeasurement(\"b\").on(b),\n        )\n    )\n    np.testing.assert_array_equal(out[\"a\"], [0])\n    np.testing.assert_array_equal(out[\"b\"], [1])\n\n\ndef test_correlated_error():\n    s = stimcirq.StimSampler()\n    a, b = cirq.LineQubit.range(2)\n    s.run(cirq.Circuit((cirq.X(a) * cirq.Y(b)).with_probability(0.1)))\n"
  },
  {
    "path": "glue/cirq/stimcirq/_stim_to_cirq.py",
    "content": "import collections\nimport functools\nfrom typing import (\n    Any,\n    Callable,\n    cast,\n    DefaultDict,\n    Dict,\n    Iterable,\n    List,\n    Optional,\n    Tuple,\n    Union,\n)\n\nimport cirq\nimport stim\n\nfrom ._cx_swap_gate import CXSwapGate\nfrom ._cz_swap_gate import CZSwapGate\nfrom ._det_annotation import DetAnnotation\nfrom ._ii_error_gate import IIErrorGate\nfrom ._i_error_gate import IErrorGate\nfrom ._ii_gate import IIGate\nfrom ._measure_and_or_reset_gate import MeasureAndOrResetGate\nfrom ._obs_annotation import CumulativeObservableAnnotation\nfrom ._shift_coords_annotation import ShiftCoordsAnnotation\nfrom ._sweep_pauli import SweepPauli\n\n\ndef _stim_targets_to_dense_pauli_string(\n    targets: List[stim.GateTarget],\n) -> cirq.BaseDensePauliString:\n    obs = cirq.MutableDensePauliString(\"I\" * len(targets))\n    for k, target in enumerate(targets):\n        if target.is_inverted_result_target:\n            obs *= -1\n        if target.is_x_target:\n            obs.pauli_mask[k] = 1\n        elif target.is_y_target:\n            obs.pauli_mask[k] = 2\n        elif target.is_z_target:\n            obs.pauli_mask[k] = 3\n        else:\n            raise NotImplementedError(f\"target={target!r}\")\n    return obs.frozen()\n\n\ndef _proper_transform_circuit_qubits(circuit: cirq.AbstractCircuit, remap: Dict[cirq.Qid, cirq.Qid]) -> cirq.Circuit:\n    # Note: doing this the hard way because cirq.CircuitOperation otherwise remembers the old indices in\n    # its `remap` entry, instead of completely expunging those indices.\n    return cirq.Circuit(\n        cirq.Moment(\n            cirq.CircuitOperation(\n                circuit=_proper_transform_circuit_qubits(op.circuit, remap).freeze(),\n                repetitions=op.repetitions,\n                use_repetition_ids=False,\n            )\n            if isinstance(op, cirq.CircuitOperation)\n            else op.with_qubits(*[remap[q] for q in op.qubits])\n            for op in moment\n        )\n        for moment in circuit\n    )\n\n\nclass CircuitTranslationTracker:\n    def __init__(self, flatten: bool, single_measure_key: Optional[str] = None):\n        self.qubit_coords: Dict[int, cirq.Qid] = {}\n        self.origin: DefaultDict[float] = collections.defaultdict(float)\n        self.num_measurements_seen = 0\n        self.full_circuit = cirq.Circuit()\n        self.tick_circuit = cirq.Circuit()\n        self.flatten = flatten\n        self.have_seen_loop = False\n        self.single_measure_key = single_measure_key\n\n    def get_next_measure_id(self) -> int:\n        self.num_measurements_seen += 1\n        return self.num_measurements_seen - 1\n\n    def get_next_measure_key(self) -> str:\n        if self.single_measure_key is None:\n            return str(self.get_next_measure_id())\n        return self.single_measure_key\n\n    def append_operation(self, op: cirq.Operation) -> None:\n        self.tick_circuit.append(op, strategy=cirq.InsertStrategy.INLINE)\n\n    def process_gate_instruction(\n        self, gate: cirq.Gate, instruction: stim.CircuitInstruction\n    ) -> None:\n        targets: List[stim.GateTarget] = instruction.targets_copy()\n        m = cirq.num_qubits(gate)\n        if not all(t.is_qubit_target for t in targets) or len(targets) % m != 0:\n            raise NotImplementedError(f\"instruction={instruction!r}\")\n        if instruction.tag:\n            tags = [instruction.tag]\n        else:\n            tags = ()\n        for k in range(0, len(targets), m):\n            self.append_operation(gate(*[cirq.LineQubit(t.value) for t in targets[k : k + m]]).with_tags(*tags))\n\n    def process_tick(self, instruction: stim.CircuitInstruction) -> None:\n        self.full_circuit += self.tick_circuit or cirq.Moment()\n        self.tick_circuit = cirq.Circuit()\n\n    def process_pauli_channel_1(self, instruction: stim.CircuitInstruction) -> None:\n        args = instruction.gate_args_copy()\n        if len(args) != 3:\n            raise ValueError(f\"len(args={args!r}) != 3\")\n        self.process_gate_instruction(\n            cirq.AsymmetricDepolarizingChannel(p_x=args[0], p_y=args[1], p_z=args[2]), instruction\n        )\n\n    def process_pauli_channel_2(self, instruction: stim.CircuitInstruction) -> None:\n        args = instruction.gate_args_copy()\n        if len(args) != 15:\n            raise ValueError(f\"len(args={args!r}) != 15\")\n\n        ps = {\n            'IX': args[0],\n            'IY': args[1],\n            'IZ': args[2],\n            'XI': args[3],\n            'XX': args[4],\n            'XY': args[5],\n            'XZ': args[6],\n            'YI': args[7],\n            'YX': args[8],\n            'YY': args[9],\n            'YZ': args[10],\n            'ZI': args[11],\n            'ZX': args[12],\n            'ZY': args[13],\n            'ZZ': args[14],\n        }\n        ps = {k: v for k, v in ps.items() if v}\n        if not ps:\n            ps['II'] = 1\n        gate = cirq.asymmetric_depolarize(error_probabilities=ps)\n        self.process_gate_instruction(gate, instruction)\n\n    def process_repeat_block(self, block: stim.CircuitRepeatBlock):\n        if self.flatten or (block.repeat_count == 1 and block.tag == \"\"):\n            self.process_circuit(block.repeat_count, block.body_copy())\n            return\n\n        self.have_seen_loop = True\n        child = CircuitTranslationTracker(flatten=self.flatten)\n        child.origin = self.origin.copy()\n        child.num_measurements_seen = self.num_measurements_seen\n        child.qubit_coords = self.qubit_coords.copy()\n        child.have_seen_loop = True\n        child.process_circuit(1, block.body_copy())\n\n        # Circuit operation will always be in their own cirq.Moment\n        if block.tag == \"\":\n            tags = ()\n        else:\n            tags = (block.tag,)\n        if len(self.tick_circuit):\n            self.full_circuit += self.tick_circuit\n        self.full_circuit += cirq.Moment(\n            cirq.CircuitOperation(\n                cirq.FrozenCircuit(child.full_circuit + child.tick_circuit),\n                repetitions=block.repeat_count,\n                use_repetition_ids=False,\n            ).with_tags(*tags)\n        )\n        self.tick_circuit = cirq.Circuit()\n\n        self.qubit_coords = child.qubit_coords\n        self.num_measurements_seen += (\n            child.num_measurements_seen - self.num_measurements_seen\n        ) * block.repeat_count\n        for k, v in child.origin.items():\n            self.origin[k] += (v - self.origin[k]) * block.repeat_count\n\n    def process_measurement_instruction(\n        self, instruction: stim.CircuitInstruction, measure: bool, reset: bool, basis: str\n    ) -> None:\n        args = instruction.gate_args_copy()\n        flip_probability = 0\n        if args:\n            flip_probability = args[0]\n\n        targets: List[stim.GateTarget] = instruction.targets_copy()\n        if instruction.tag:\n            tags = [instruction.tag]\n        else:\n            tags = ()\n        for t in targets:\n            if not t.is_qubit_target:\n                raise NotImplementedError(f\"instruction={instruction!r}\")\n            key = self.get_next_measure_key()\n            self.append_operation(\n                MeasureAndOrResetGate(\n                    measure=measure,\n                    reset=reset,\n                    basis=basis,\n                    invert_measure=t.is_inverted_result_target,\n                    key=key,\n                    measure_flip_probability=flip_probability,\n                ).resolve(cirq.LineQubit(t.value)).with_tags(*tags)\n            )\n\n    def process_circuit(self, repetitions: int, circuit: stim.Circuit) -> None:\n        handler_table = CircuitTranslationTracker.get_handler_table()\n        for _ in range(repetitions):\n            for instruction in circuit:\n                if isinstance(instruction, stim.CircuitInstruction):\n                    handler = handler_table.get(instruction.name)\n                    if handler is None:\n                        raise NotImplementedError(f\"{instruction!r}\")\n                    handler(self, instruction)\n                elif isinstance(instruction, stim.CircuitRepeatBlock):\n                    self.process_repeat_block(instruction)\n                else:\n                    raise NotImplementedError(f\"instruction={instruction!r}\")\n\n    def output(self) -> cirq.Circuit:\n        out = self.full_circuit + self.tick_circuit\n\n        if self.qubit_coords:\n            remap: Dict[cirq.Qid, cirq.Qid] = {\n                q: self.qubit_coords.get(cast(cirq.LineQubit, q).x, q) for q in out.all_qubits()\n            }\n\n            # Only remap if there are no collisions.\n            if len(set(remap.values())) == len(remap):\n                # Note: doing this the hard way because cirq.CircuitOperation otherwise remembers the old indices in\n                # its `remap` entry, instead of completely expunging those indices.\n                out = _proper_transform_circuit_qubits(out, remap)\n\n        return out\n\n    def process_mpp(self, instruction: stim.CircuitInstruction) -> None:\n        args = instruction.gate_args_copy()\n        if args and args[0]:\n            raise NotImplementedError(\"Noisy MPP\")\n\n        targets: List[stim.GateTarget] = instruction.targets_copy()\n        if instruction.tag:\n            tags = [instruction.tag]\n        else:\n            tags = ()\n        start = 0\n        while start < len(targets):\n            next_start = start + 1\n            while next_start < len(targets) and targets[next_start].is_combiner:\n                next_start += 2\n            group = targets[start:next_start:2]\n            start = next_start\n\n            obs = _stim_targets_to_dense_pauli_string(group)\n            qubits = [cirq.LineQubit(t.value) for t in group]\n            key = self.get_next_measure_key()\n            self.append_operation(cirq.PauliMeasurementGate(obs, key=key).on(*qubits).with_tags(*tags))\n\n    def process_spp_dag(self, instruction: stim.CircuitInstruction) -> None:\n        self.process_spp(instruction, dag=True)\n\n    def process_spp(self, instruction: stim.CircuitInstruction, dag: bool = False) -> None:\n        targets: List[stim.GateTarget] = instruction.targets_copy()\n        if instruction.tag:\n            tags = [instruction.tag]\n        else:\n            tags = ()\n        start = 0\n        while start < len(targets):\n            next_start = start + 1\n            while next_start < len(targets) and targets[next_start].is_combiner:\n                next_start += 2\n            group = targets[start:next_start:2]\n            start = next_start\n\n            obs = _stim_targets_to_dense_pauli_string(group)\n            qubits = [cirq.LineQubit(t.value) for t in group]\n            self.append_operation(cirq.PauliStringPhasorGate(\n                obs,\n                exponent_neg=-0.5 if dag else 0.5,\n            ).on(*qubits).with_tags(*tags))\n\n    def process_m_pair(self, instruction: stim.CircuitInstruction, basis: str) -> None:\n        args = instruction.gate_args_copy()\n        if args and args[0]:\n            raise NotImplementedError(\"Noisy M\" + basis*2)\n\n        if instruction.tag:\n            tags = [instruction.tag]\n        else:\n            tags = ()\n        targets: List[stim.GateTarget] = instruction.targets_copy()\n        for k in range(0, len(targets), 2):\n            obs = cirq.DensePauliString(basis * 2)\n            if targets[0].is_inverted_result_target ^ targets[1].is_inverted_result_target:\n                obs *= -1\n            qubits = [cirq.LineQubit(targets[0].value), cirq.LineQubit(targets[1].value)]\n            key = self.get_next_measure_key()\n            self.append_operation(cirq.PauliMeasurementGate(obs, key=key).on(*qubits).with_tags(*tags))\n\n    def process_mxx(self, instruction: stim.CircuitInstruction) -> None:\n        self.process_m_pair(instruction, \"X\")\n\n    def process_myy(self, instruction: stim.CircuitInstruction) -> None:\n        self.process_m_pair(instruction, \"Y\")\n\n    def process_mzz(self, instruction: stim.CircuitInstruction) -> None:\n        self.process_m_pair(instruction, \"Z\")\n\n    def process_mpad(self, instruction: stim.CircuitInstruction) -> None:\n        targets: List[stim.GateTarget] = instruction.targets_copy()\n        for t in targets:\n            obs = cirq.DensePauliString(\"\")\n            if t.value == 1:\n                obs *= -1\n            qubits = []\n            key = self.get_next_measure_key()\n            self.append_operation(cirq.PauliMeasurementGate(obs, key=key).on(*qubits))\n\n    def process_correlated_error(self, instruction: stim.CircuitInstruction) -> None:\n        if instruction.tag:\n            tags = [instruction.tag]\n        else:\n            tags = ()\n        args = instruction.gate_args_copy()\n        probability = args[0] if args else 0\n        targets = instruction.targets_copy()\n        qubits = [cirq.LineQubit(t.value) for t in targets]\n        self.append_operation(\n            _stim_targets_to_dense_pauli_string(targets).on(*qubits).with_probability(probability).with_tags(*tags)\n        )\n\n    def coords_after_offset(\n        self, relative_coords: List[float], *, even_if_flattening: bool = False\n    ) -> List[Union[float, int]]:\n        if not self.flatten and not even_if_flattening:\n            return list(relative_coords)\n        result = []\n        for k in range(len(relative_coords)):\n            t = relative_coords[k] + self.origin[k]\n            if t == int(t):\n                t = int(t)\n            result.append(t)\n        return result\n\n    def resolve_measurement_record_keys(\n        self, targets: Iterable[stim.GateTarget]\n    ) -> Tuple[List[str], List[int], List[str]]:\n        pauli_targets, meas_targets = [], []\n        for t in targets:\n            if t.is_measurement_record_target:\n                meas_targets.append(t)\n            else:\n                pauli_targets.append(f'{t.pauli_type}{t.value}')\n\n        if self.have_seen_loop:\n            return [], [t.value for t in meas_targets], pauli_targets\n        else:\n            return [str(self.num_measurements_seen + t.value) for t in meas_targets], [], pauli_targets\n\n    def process_detector(self, instruction: stim.CircuitInstruction) -> None:\n        if instruction.tag:\n            tags = [instruction.tag]\n        else:\n            tags = ()\n        coords = self.coords_after_offset(instruction.gate_args_copy())\n        keys, rels, _ = self.resolve_measurement_record_keys(instruction.targets_copy())\n        self.append_operation(\n            DetAnnotation(parity_keys=keys, relative_keys=rels, coordinate_metadata=coords).with_tags(*tags)\n        )\n\n    def process_observable_include(self, instruction: stim.CircuitInstruction) -> None:\n        if instruction.tag:\n            tags = [instruction.tag]\n        else:\n            tags = ()\n        args = instruction.gate_args_copy()\n        index = 0 if not args else int(args[0])\n        keys, rels, paulis = self.resolve_measurement_record_keys(instruction.targets_copy())\n        self.append_operation(\n            CumulativeObservableAnnotation(\n                parity_keys=keys, relative_keys=rels, pauli_keys=paulis, observable_index=index\n            ).with_tags(*tags)\n        )\n\n    def process_qubit_coords(self, instruction: stim.CircuitInstruction) -> None:\n        coords = self.coords_after_offset(instruction.gate_args_copy(), even_if_flattening=True)\n        for t in instruction.targets_copy():\n            if len(coords) == 1:\n                self.qubit_coords[t.value] = cirq.LineQubit(*coords)\n            elif len(coords) == 2:\n                self.qubit_coords[t.value] = cirq.GridQubit(*coords)\n\n    def process_shift_coords(self, instruction: stim.CircuitInstruction) -> None:\n        if instruction.tag:\n            tags = [instruction.tag]\n        else:\n            tags = ()\n        args = instruction.gate_args_copy()\n        if not self.flatten:\n            self.append_operation(ShiftCoordsAnnotation(args).with_tags(*tags))\n        for k, a in enumerate(args):\n            self.origin[k] += a\n\n    class OneToOneGateHandler:\n        def __init__(self, gate: cirq.Gate):\n            self.gate = gate\n\n        def __call__(\n            self, tracker: 'CircuitTranslationTracker', instruction: stim.CircuitInstruction\n        ) -> None:\n            tracker.process_gate_instruction(gate=self.gate, instruction=instruction)\n\n    class SweepableGateHandler:\n        def __init__(self, pauli_gate: cirq.Pauli, gate: cirq.Gate):\n            self.pauli_gate = pauli_gate\n            self.gate = gate\n\n        def __call__(\n            self, tracker: 'CircuitTranslationTracker', instruction: stim.CircuitInstruction\n        ) -> None:\n            if instruction.tag:\n                tags = [instruction.tag]\n            else:\n                tags = ()\n            targets: List[stim.GateTarget] = instruction.targets_copy()\n            for k in range(0, len(targets), 2):\n                a = targets[k]\n                b = targets[k + 1]\n                if not a.is_qubit_target and not b.is_qubit_target:\n                    raise NotImplementedError(f\"instruction={instruction!r}\")\n                if a.is_sweep_bit_target or b.is_sweep_bit_target:\n                    if b.is_sweep_bit_target:\n                        a, b = b, a\n                    assert not a.is_inverted_result_target\n                    tracker.append_operation(\n                        SweepPauli(\n                            stim_sweep_bit_index=a.value,\n                            cirq_sweep_symbol=f'sweep[{a.value}]',\n                            pauli=self.pauli_gate,\n                        ).on(cirq.LineQubit(b.value)).with_tags(*tags)\n                    )\n                else:\n                    if not a.is_qubit_target or not b.is_qubit_target:\n                        raise NotImplementedError(f\"instruction={instruction!r}\")\n                    tracker.append_operation(\n                        self.gate(cirq.LineQubit(a.value), cirq.LineQubit(b.value)).with_tags(*tags)\n                    )\n\n    class OneToOneMeasurementHandler:\n        def __init__(self, *, reset: bool, measure: bool, basis: str):\n            self.reset = reset\n            self.measure = measure\n            self.basis = basis\n\n        def __call__(\n            self, tracker: 'CircuitTranslationTracker', instruction: stim.CircuitInstruction\n        ) -> None:\n            tracker.process_measurement_instruction(\n                measure=self.measure, reset=self.reset, basis=self.basis, instruction=instruction\n            )\n\n    class OneToOneNoisyGateHandler:\n        def __init__(self, prob_to_gate: Callable[[float], cirq.Gate]):\n            self.prob_to_gate = prob_to_gate\n\n        def __call__(\n            self, tracker: 'CircuitTranslationTracker', instruction: stim.CircuitInstruction\n        ) -> None:\n            tracker.process_gate_instruction(\n                self.prob_to_gate(instruction.gate_args_copy()[0]), instruction\n            )\n\n    class MultiArgumentGateHandler:\n        def __init__(self, args_to_gate: Callable[[List[float]], cirq.Gate]):\n            self.args_to_gate = args_to_gate\n\n        def __call__(\n            self, tracker: 'CircuitTranslationTracker', instruction: stim.CircuitInstruction\n        ) -> None:\n            tracker.process_gate_instruction(\n                self.args_to_gate(instruction.gate_args_copy()), instruction\n            )\n\n    @staticmethod\n    @functools.lru_cache(maxsize=1)\n    def get_handler_table() -> Dict[\n        str, Callable[['CircuitTranslationTracker', stim.Circuit], None]\n    ]:\n        gate = CircuitTranslationTracker.OneToOneGateHandler\n        measure_gate = CircuitTranslationTracker.OneToOneMeasurementHandler\n        noise = CircuitTranslationTracker.OneToOneNoisyGateHandler\n        multi_arg = CircuitTranslationTracker.MultiArgumentGateHandler\n        sweep_gate = CircuitTranslationTracker.SweepableGateHandler\n\n        def not_impl(message) -> Callable[[Any, Any], None]:\n            def handler(\n                tracker: CircuitTranslationTracker, instruction: stim.CircuitInstruction\n            ) -> None:\n                raise NotImplementedError(message)\n\n            return handler\n\n        return {\n            \"M\": measure_gate(measure=True, reset=False, basis='Z'),\n            \"MX\": measure_gate(measure=True, reset=False, basis='X'),\n            \"MY\": measure_gate(measure=True, reset=False, basis='Y'),\n            \"MZ\": measure_gate(measure=True, reset=False, basis='Z'),\n            \"MR\": measure_gate(measure=True, reset=True, basis='Z'),\n            \"MRX\": measure_gate(measure=True, reset=True, basis='X'),\n            \"MRY\": measure_gate(measure=True, reset=True, basis='Y'),\n            \"MRZ\": measure_gate(measure=True, reset=True, basis='Z'),\n            \"R\": gate(cirq.ResetChannel()),\n            \"RX\": gate(\n                MeasureAndOrResetGate(\n                    measure=False, reset=True, basis='X', invert_measure=False, key=''\n                )\n            ),\n            \"CZSWAP\": gate(CZSwapGate()),\n            \"CXSWAP\": gate(CXSwapGate(inverted=False)),\n            \"SWAPCX\": gate(CXSwapGate(inverted=True)),\n            \"RY\": gate(\n                MeasureAndOrResetGate(\n                    measure=False, reset=True, basis='Y', invert_measure=False, key=''\n                )\n            ),\n            \"RZ\": gate(cirq.ResetChannel()),\n            \"I\": gate(cirq.I),\n            \"II\": gate(IIGate()),\n            \"X\": gate(cirq.X),\n            \"Y\": gate(cirq.Y),\n            \"Z\": gate(cirq.Z),\n            \"H_XY\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Y, False), z_to=(cirq.Z, True))\n            ),\n            \"H\": gate(cirq.H),\n            \"H_XZ\": gate(cirq.H),\n            \"H_NXZ\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Z, True), z_to=(cirq.X, True))\n            ),\n            \"H_YZ\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.X, True), z_to=(cirq.Y, False))\n            ),\n            \"H_NXY\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Y, True), z_to=(cirq.Z, True))\n            ),\n            \"H_NYZ\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.X, True), z_to=(cirq.Y, True))\n            ),\n            \"SQRT_X\": gate(cirq.X ** 0.5),\n            \"SQRT_X_DAG\": gate(cirq.X ** -0.5),\n            \"SQRT_Y\": gate(cirq.Y ** 0.5),\n            \"SQRT_Y_DAG\": gate(cirq.Y ** -0.5),\n            \"C_XYZ\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Y, False), z_to=(cirq.X, False))\n            ),\n            \"C_NXYZ\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Y, True), z_to=(cirq.X, True))\n            ),\n            \"C_XNYZ\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Y, True), z_to=(cirq.X, False))\n            ),\n            \"C_XYNZ\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Y, False), z_to=(cirq.X, True))\n            ),\n            \"C_ZYX\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Z, False), z_to=(cirq.Y, False))\n            ),\n            \"C_NZYX\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Z, True), z_to=(cirq.Y, True))\n            ),\n            \"C_ZNYX\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Z, False), z_to=(cirq.Y, True))\n            ),\n            \"C_ZYNX\": gate(\n                cirq.SingleQubitCliffordGate.from_xz_map(x_to=(cirq.Z, True), z_to=(cirq.Y, False))\n            ),\n            \"SQRT_XX\": gate(cirq.XX ** 0.5),\n            \"SQRT_YY\": gate(cirq.YY ** 0.5),\n            \"SQRT_ZZ\": gate(cirq.ZZ ** 0.5),\n            \"SQRT_XX_DAG\": gate(cirq.XX ** -0.5),\n            \"SQRT_YY_DAG\": gate(cirq.YY ** -0.5),\n            \"SQRT_ZZ_DAG\": gate(cirq.ZZ ** -0.5),\n            \"S\": gate(cirq.S),\n            \"S_DAG\": gate(cirq.S ** -1),\n            \"SQRT_Z\": gate(cirq.S),\n            \"SQRT_Z_DAG\": gate(cirq.S ** -1),\n            \"SWAP\": gate(cirq.SWAP),\n            \"ISWAP\": gate(cirq.ISWAP),\n            \"ISWAP_DAG\": gate(cirq.ISWAP ** -1),\n            \"XCX\": gate(cirq.PauliInteractionGate(cirq.X, False, cirq.X, False)),\n            \"XCY\": gate(cirq.PauliInteractionGate(cirq.X, False, cirq.Y, False)),\n            \"XCZ\": sweep_gate(cirq.X, cirq.PauliInteractionGate(cirq.X, False, cirq.Z, False)),\n            \"YCX\": gate(cirq.PauliInteractionGate(cirq.Y, False, cirq.X, False)),\n            \"YCY\": gate(cirq.PauliInteractionGate(cirq.Y, False, cirq.Y, False)),\n            \"YCZ\": sweep_gate(cirq.Y, cirq.PauliInteractionGate(cirq.Y, False, cirq.Z, False)),\n            \"CX\": sweep_gate(cirq.X, cirq.CNOT),\n            \"CNOT\": sweep_gate(cirq.X, cirq.CNOT),\n            \"ZCX\": sweep_gate(cirq.X, cirq.CNOT),\n            \"CY\": sweep_gate(cirq.Y, cirq.Y.controlled(1)),\n            \"ZCY\": sweep_gate(cirq.Y, cirq.Y.controlled(1)),\n            \"CZ\": sweep_gate(cirq.Z, cirq.CZ),\n            \"ZCZ\": sweep_gate(cirq.Z, cirq.CZ),\n            \"DEPOLARIZE1\": noise(lambda p: cirq.DepolarizingChannel(p, 1)),\n            \"DEPOLARIZE2\": noise(lambda p: cirq.DepolarizingChannel(p, 2)),\n            \"X_ERROR\": noise(cirq.X.with_probability),\n            \"Y_ERROR\": noise(cirq.Y.with_probability),\n            \"Z_ERROR\": noise(cirq.Z.with_probability),\n            \"I_ERROR\": multi_arg(IErrorGate),\n            \"II_ERROR\": multi_arg(IIErrorGate),\n            \"PAULI_CHANNEL_1\": CircuitTranslationTracker.process_pauli_channel_1,\n            \"PAULI_CHANNEL_2\": CircuitTranslationTracker.process_pauli_channel_2,\n            \"ELSE_CORRELATED_ERROR\": not_impl(\n                \"Converting ELSE_CORRELATED_ERROR to cirq is not supported.\"\n            ),\n            \"REPEAT\": not_impl(\"[handled special]\"),\n            \"TICK\": CircuitTranslationTracker.process_tick,\n            \"SHIFT_COORDS\": CircuitTranslationTracker.process_shift_coords,\n            \"QUBIT_COORDS\": CircuitTranslationTracker.process_qubit_coords,\n            \"E\": CircuitTranslationTracker.process_correlated_error,\n            \"CORRELATED_ERROR\": CircuitTranslationTracker.process_correlated_error,\n            \"MPP\": CircuitTranslationTracker.process_mpp,\n            \"SPP\": CircuitTranslationTracker.process_spp,\n            \"SPP_DAG\": CircuitTranslationTracker.process_spp_dag,\n            \"MXX\": CircuitTranslationTracker.process_mxx,\n            \"MYY\": CircuitTranslationTracker.process_myy,\n            \"MZZ\": CircuitTranslationTracker.process_mzz,\n            \"MPAD\": CircuitTranslationTracker.process_mpad,\n            \"DETECTOR\": CircuitTranslationTracker.process_detector,\n            \"OBSERVABLE_INCLUDE\": CircuitTranslationTracker.process_observable_include,\n            \"HERALDED_ERASE\": not_impl(\n                \"Converting HERALDED_ERASE to cirq is not supported.\"\n            ),\n            \"HERALDED_PAULI_CHANNEL_1\": not_impl(\n                \"Converting HERALDED_PAULI_CHANNEL_1 to cirq is not supported.\"\n            ),\n        }\n\n\ndef stim_circuit_to_cirq_circuit(\n    circuit: stim.Circuit,\n    *,\n    flatten: bool = False,\n    single_measure_key: Optional[str] = None,\n) -> cirq.Circuit:\n    \"\"\"Converts a stim circuit into an equivalent cirq circuit.\n\n    Qubit indices are turned into cirq.LineQubit instances. Measurements are\n    keyed by their ordering (e.g. the first measurement is keyed \"0\", the second\n    is keyed \"1\", etc) unless a fixed measure_key is provided.\n\n    Not all circuits can be converted:\n        - ELSE_CORRELATED_ERROR instructions are not supported.\n\n    Not all circuits can be converted with perfect 1:1 fidelity:\n        - DETECTOR annotations are discarded.\n        - OBSERVABLE_INCLUDE annotations are discarded.\n\n    Args:\n        circuit: The stim circuit to convert into a cirq circuit.\n        flatten: Defaults to False. When set to True, REPEAT blocks are removed by\n            explicitly repeating their instructions multiple times. Also,\n            SHIFT_COORDS instructions are removed by appropriately adjusting the\n            coordinate metadata of later instructions.\n        single_measure_key: Defaults to None. If provided, all measurements are\n            keyed with this string instead of sequentially generated numbers.\n\n    Returns:\n        The converted circuit.\n\n    Examples:\n\n        >>> import stimcirq\n        >>> import stim\n        >>> print(stimcirq.stim_circuit_to_cirq_circuit(stim.Circuit('''\n        ...     H 0\n        ...     CNOT 0 1\n        ...     X_ERROR(0.25) 0\n        ...     TICK\n        ...     M !1 0\n        ... ''')))\n        0: ───H───@───X[prob=0.25]───M('1')────\n                  │\n        1: ───────X──────────────────!M('0')───\n    \"\"\"\n    tracker = CircuitTranslationTracker(\n        flatten=flatten, single_measure_key=single_measure_key\n    )\n    tracker.process_circuit(repetitions=1, circuit=circuit)\n    return tracker.output()\n"
  },
  {
    "path": "glue/cirq/stimcirq/_stim_to_cirq_test.py",
    "content": "import itertools\nfrom typing import cast\n\nimport cirq\nimport pytest\nimport stim\n\nimport stimcirq\nfrom ._stim_to_cirq import CircuitTranslationTracker\n\n\ndef test_stim_circuit_to_cirq_circuit():\n    circuit = stimcirq.stim_circuit_to_cirq_circuit(\n        stim.Circuit(\n            \"\"\"\n        X 0\n        CNOT 0 1\n        X_ERROR(0.125) 0 1\n        CORRELATED_ERROR(0.25) X0 Y1 Z2\n        M 1\n        M !1\n        TICK\n        MR 0 !1\n    \"\"\"\n        )\n    )\n    a, b, c = cirq.LineQubit.range(3)\n    assert circuit == cirq.Circuit(\n        cirq.Moment(cirq.X(a)),\n        cirq.Moment(cirq.CNOT(a, b)),\n        cirq.Moment(cirq.X.with_probability(0.125).on(a), cirq.X.with_probability(0.125).on(b)),\n        cirq.Moment(cirq.PauliString({a: cirq.X, b: cirq.Y, c: cirq.Z}).with_probability(0.25)),\n        cirq.Moment(cirq.measure(b, key=\"0\")),\n        cirq.Moment(cirq.measure(b, key=\"1\", invert_mask=(True,))),\n        cirq.Moment(\n            stimcirq.MeasureAndOrResetGate(\n                measure=True, reset=True, basis='Z', invert_measure=False, key='2'\n            ).on(a),\n            stimcirq.MeasureAndOrResetGate(\n                measure=True, reset=True, basis='Z', invert_measure=True, key='3'\n            ).on(b),\n        ),\n    )\n\n\ndef assert_circuits_are_equivalent_and_convert(\n    cirq_circuit: cirq.Circuit, stim_circuit: stim.Circuit\n):\n    assert cirq_circuit == stimcirq.stim_circuit_to_cirq_circuit(stim_circuit)\n    assert stim_circuit == stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit)\n\n\n@pytest.mark.parametrize(\n    \"name\",\n    [\n        k\n        for k, v in CircuitTranslationTracker.get_handler_table().items()\n        if isinstance(v, CircuitTranslationTracker.OneToOneGateHandler)\n    ],\n)\ndef test_gates_converted_using_OneToOneGateHandler(name: str):\n    handler = cast(\n        CircuitTranslationTracker.OneToOneGateHandler,\n        CircuitTranslationTracker.get_handler_table()[name],\n    )\n    gate = handler.gate\n    n = cirq.num_qubits(gate)\n    qs = cirq.LineQubit.range(n)\n\n    cirq_original = cirq.Circuit(gate.on(*qs))\n    stim_targets = \" \".join(str(e) for e in range(n))\n    stim_original = stim.Circuit(f\"{name} {stim_targets}\\nTICK\")\n    assert_circuits_are_equivalent_and_convert(cirq_original, stim_original)\n\n\n@pytest.mark.parametrize(\n    \"name\",\n    [\n        k\n        for k, v in CircuitTranslationTracker.get_handler_table().items()\n        if isinstance(v, CircuitTranslationTracker.SweepableGateHandler)\n    ],\n)\ndef test_gates_converted_using_SweepableGateHandler(name: str):\n    handler = cast(\n        CircuitTranslationTracker.SweepableGateHandler,\n        CircuitTranslationTracker.get_handler_table()[name],\n    )\n    gate = handler.gate\n    n = cirq.num_qubits(gate)\n    qs = cirq.LineQubit.range(n)\n\n    # Without sweeping.\n    cirq_original = cirq.Circuit(gate.on(*qs))\n    stim_targets = \" \".join(str(e) for e in range(n))\n    stim_original = stim.Circuit(f\"{name} {stim_targets}\\nTICK\")\n    assert_circuits_are_equivalent_and_convert(cirq_original, stim_original)\n\n    # With sweeping.\n    q = qs[0]\n    cirq_original = cirq.Circuit(\n        stimcirq.SweepPauli(\n            stim_sweep_bit_index=3, cirq_sweep_symbol=\"sweep[3]\", pauli=handler.pauli_gate\n        ).on(q)\n    )\n    if name.startswith(\"C\") or name.startswith(\"Z\"):\n        stim_original = stim.Circuit(f\"{name} sweep[3] 0\\nTICK\")\n        assert_circuits_are_equivalent_and_convert(cirq_original, stim_original)\n    else:\n        stim_original = stim.Circuit(f\"{name} 0 sweep[3]\\nTICK\")\n        # Round trip loses distinction between ZCX and XCZ.\n        assert stimcirq.stim_circuit_to_cirq_circuit(stim_original) == cirq_original\n\n\n@pytest.mark.parametrize(\n    \"name,probability\",\n    itertools.product(\n        [\n            k\n            for k, v in CircuitTranslationTracker.get_handler_table().items()\n            if isinstance(v, CircuitTranslationTracker.OneToOneNoisyGateHandler)\n        ],\n        [0, 0.125],\n    ),\n)\ndef test_gates_converted_using_OneToOneNoisyGateHandler(name: str, probability: float):\n    handler = cast(\n        CircuitTranslationTracker.OneToOneNoisyGateHandler,\n        CircuitTranslationTracker.get_handler_table()[name],\n    )\n    gate = handler.prob_to_gate(probability)\n    n = cirq.num_qubits(gate)\n    qs = cirq.LineQubit.range(n)\n\n    cirq_original = cirq.Circuit(gate.on(*qs))\n    stim_targets = \" \".join(str(e) for e in range(n))\n    stim_original = stim.Circuit(f\"{name}({probability}) {stim_targets}\\nTICK\")\n    assert_circuits_are_equivalent_and_convert(cirq_original, stim_original)\n\n\n@pytest.mark.parametrize(\n    \"name,invert,probability\",\n    itertools.product(\n        [\n            k\n            for k, v in CircuitTranslationTracker.get_handler_table().items()\n            if isinstance(v, CircuitTranslationTracker.OneToOneMeasurementHandler)\n        ],\n        [False, True],\n        [0, 0.125],\n    ),\n)\ndef test_gates_converted_using_OneToOneMeasurementHandler(\n    name: str, invert: bool, probability: float\n):\n    handler = cast(\n        CircuitTranslationTracker.OneToOneMeasurementHandler,\n        CircuitTranslationTracker.get_handler_table()[name],\n    )\n    if handler.basis == 'Z' and not handler.reset and not probability:\n        cirq_original = cirq.Circuit(\n            cirq.measure(cirq.LineQubit(5), key=\"0\", invert_mask=(1,) * invert)\n        )\n    else:\n        cirq_original = cirq.Circuit(\n            stimcirq.MeasureAndOrResetGate(\n                basis=handler.basis,\n                key=\"0\",\n                invert_measure=invert,\n                reset=handler.reset,\n                measure_flip_probability=probability,\n                measure=handler.measure,\n            ).on(cirq.LineQubit(5))\n        )\n    inverted = \"!\" if invert else \"\"\n    p_str = f\"({probability})\" if probability else \"\"\n    stim_original = stim.Circuit(f\"QUBIT_COORDS(5) 0\\n{name}{p_str} {inverted}0\\nTICK\")\n    assert_circuits_are_equivalent_and_convert(cirq_original, stim_original)\n\n\ndef test_round_trip_preserves_moment_structure():\n    a, b = cirq.LineQubit.range(2)\n    circuit = cirq.Circuit(\n        cirq.Moment(),\n        cirq.Moment(cirq.H(a)),\n        cirq.Moment(cirq.H(b)),\n        cirq.Moment(),\n        cirq.Moment(),\n        cirq.Moment(cirq.CNOT(a, b)),\n        cirq.Moment(),\n    )\n    converted = stimcirq.cirq_circuit_to_stim_circuit(circuit)\n    restored = stimcirq.stim_circuit_to_cirq_circuit(converted)\n    assert restored == circuit\n\n\ndef test_circuit_diagram():\n    cirq.testing.assert_has_diagram(\n        stimcirq.stim_circuit_to_cirq_circuit(\n            stim.Circuit(\n                \"\"\"\n            M 9\n            MX 9\n            MY 9\n            MZ 9\n            R 9\n            RX 9\n            RY 9\n            RZ 9\n            MR 9\n            MRX 9\n            MRY 9\n            MRZ 9\n        \"\"\"\n            )\n        ),\n        \"\"\"\n9: ---M('0')---MX('1')---MY('2')---M('3')---R---RX---RY---R---MR('4')---MRX('5')---MRY('6')---MR('7')---\n        \"\"\",\n        use_unicode_characters=False,\n    )\n\n\ndef test_all_known_gates_explicitly_handled():\n    gates = stim.gate_data()\n    handled = CircuitTranslationTracker.get_handler_table().keys()\n    for gate_name in gates:\n        assert gate_name in handled, gate_name\n\n\ndef test_line_grid_qubit_round_trip():\n    c = cirq.Circuit(\n        cirq.H(cirq.LineQubit(101)),\n        cirq.Z(cirq.LineQubit(200.5)),\n        cirq.X(cirq.GridQubit(2, 3.5)),\n        cirq.Y(cirq.GridQubit(-2, 5)),\n    )\n    s = stimcirq.cirq_circuit_to_stim_circuit(c)\n    assert s == stim.Circuit(\n        \"\"\"\n        QUBIT_COORDS(-2, 5) 0\n        QUBIT_COORDS(2, 3.5) 1\n        QUBIT_COORDS(101) 2\n        QUBIT_COORDS(200.5) 3\n        H 2\n        Z 3\n        X 1\n        Y 0\n        TICK\n    \"\"\"\n    )\n    c2 = stimcirq.stim_circuit_to_cirq_circuit(s)\n    for q in c2.all_qubits():\n        if q == cirq.LineQubit(101):\n            assert isinstance(cast(cirq.LineQubit, q).x, int)\n        if q == cirq.GridQubit(2, 3.5):\n            assert isinstance(cast(cirq.GridQubit, q).row, int)\n    assert c2 == c\n\n    assert (\n        stimcirq.stim_circuit_to_cirq_circuit(\n            stim.Circuit(\n                \"\"\"\n        QUBIT_COORDS(10) 0\n        SHIFT_COORDS(1, 2, 3)\n        QUBIT_COORDS(20, 30) 1\n        H 0 1\n    \"\"\"\n            )\n        )\n        == cirq.Circuit(\n            stimcirq.ShiftCoordsAnnotation([1, 2, 3]),\n            cirq.H(cirq.LineQubit(10)),\n            cirq.H(cirq.GridQubit(21, 32)),\n        )\n    )\n\n\ndef test_noisy_measurements():\n    s = stim.Circuit(\n        \"\"\"\n        MX(0.125) 0\n        MY(0.125) 1\n        MZ(0.125) 2\n        MRX(0.125) 3\n        MRY(0.125) 4\n        MRZ(0.25) 5\n        TICK\n    \"\"\"\n    )\n    c = stimcirq.stim_circuit_to_cirq_circuit(s)\n    assert c == cirq.Circuit(\n        stimcirq.MeasureAndOrResetGate(\n            measure=True,\n            reset=False,\n            basis='X',\n            invert_measure=False,\n            key='0',\n            measure_flip_probability=0.125,\n        ).on(cirq.LineQubit(0)),\n        stimcirq.MeasureAndOrResetGate(\n            measure=True,\n            reset=False,\n            basis='Y',\n            invert_measure=False,\n            key='1',\n            measure_flip_probability=0.125,\n        ).on(cirq.LineQubit(1)),\n        stimcirq.MeasureAndOrResetGate(\n            measure=True,\n            reset=False,\n            basis='Z',\n            invert_measure=False,\n            key='2',\n            measure_flip_probability=0.125,\n        ).on(cirq.LineQubit(2)),\n        stimcirq.MeasureAndOrResetGate(\n            measure=True,\n            reset=True,\n            basis='X',\n            invert_measure=False,\n            key='3',\n            measure_flip_probability=0.125,\n        ).on(cirq.LineQubit(3)),\n        stimcirq.MeasureAndOrResetGate(\n            measure=True,\n            reset=True,\n            basis='Y',\n            invert_measure=False,\n            key='4',\n            measure_flip_probability=0.125,\n        ).on(cirq.LineQubit(4)),\n        stimcirq.MeasureAndOrResetGate(\n            measure=True,\n            reset=True,\n            basis='Z',\n            invert_measure=False,\n            key='5',\n            measure_flip_probability=0.25,\n        ).on(cirq.LineQubit(5)),\n    )\n    assert stimcirq.cirq_circuit_to_stim_circuit(c) == s\n    cirq.testing.assert_equivalent_repr(c, global_vals={'stimcirq': stimcirq})\n\n\ndef test_convert_mpp():\n    s = stim.Circuit(\n        \"\"\"\n        MPP X2*Y5*Z3\n        TICK\n        MPP Y2 X1 Z3*Z4\n        X 0\n        TICK\n    \"\"\"\n    )\n    c = cirq.Circuit(\n        cirq.Moment(\n            cirq.PauliMeasurementGate(cirq.DensePauliString(\"XYZ\", coefficient=+1), key='0').on(\n                cirq.LineQubit(2), cirq.LineQubit(5), cirq.LineQubit(3)\n            )\n        ),\n        cirq.Moment(\n            cirq.PauliMeasurementGate(cirq.DensePauliString(\"Y\"), key='1').on(cirq.LineQubit(2)),\n            cirq.PauliMeasurementGate(cirq.DensePauliString(\"X\"), key='2').on(cirq.LineQubit(1)),\n            cirq.PauliMeasurementGate(cirq.DensePauliString(\"ZZ\"), key='3').on(\n                cirq.LineQubit(3), cirq.LineQubit(4)\n            ),\n            cirq.X(cirq.LineQubit(0)),\n        ),\n    )\n    assert_circuits_are_equivalent_and_convert(c, s)\n    cirq.testing.assert_has_diagram(\n        c,\n        \"\"\"\n0: ---------------X-----------\n\n1: ---------------M(X)('2')---\n\n2: ---M(X)('0')---M(Y)('1')---\n      |\n3: ---M(Z)--------M(Z)('3')---\n      |           |\n4: ---|-----------M(Z)--------\n      |\n5: ---M(Y)--------------------\n        \"\"\",\n        use_unicode_characters=False,\n    )\n\n\ndef test_convert_detector():\n    s = stim.Circuit(\n        \"\"\"\n        H 0\n        TICK\n        CNOT 0 1\n        TICK\n        M 1 0\n        DETECTOR(2, 3, 5) rec[-1] rec[-2]\n        TICK\n    \"\"\"\n    )\n    a, b = cirq.LineQubit.range(2)\n    c = cirq.Circuit(\n        cirq.H(a),\n        cirq.CNOT(a, b),\n        cirq.Moment(\n            cirq.measure(b, key='0'),\n            cirq.measure(a, key='1'),\n            stimcirq.DetAnnotation(parity_keys=['0', '1'], coordinate_metadata=(2, 3, 5)),\n        ),\n    )\n    cirq.testing.assert_has_diagram(\n        c,\n        \"\"\"\n0: ---H---@---M('1')---------\n          |\n1: -------X---M('0')---------\n              Det('0','1')\n        \"\"\",\n        use_unicode_characters=False,\n    )\n    assert_circuits_are_equivalent_and_convert(c, s)\n\n\ndef test_convert_observable():\n    s = stim.Circuit(\n        \"\"\"\n        H 0\n        TICK\n        CNOT 0 1\n        TICK\n        M 1 0\n        OBSERVABLE_INCLUDE(5) rec[-1] rec[-2]\n        TICK\n    \"\"\"\n    )\n    a, b = cirq.LineQubit.range(2)\n    c = cirq.Circuit(\n        cirq.H(a),\n        cirq.CNOT(a, b),\n        cirq.Moment(\n            cirq.measure(b, key='0'),\n            cirq.measure(a, key='1'),\n            stimcirq.CumulativeObservableAnnotation(parity_keys=['0', '1'], observable_index=5),\n        ),\n    )\n    cirq.testing.assert_has_diagram(\n        c,\n        \"\"\"\n0: ---H---@---M('1')----------\n          |\n1: -------X---M('0')----------\n              Obs5('0','1')\n        \"\"\",\n        use_unicode_characters=False,\n    )\n    assert_circuits_are_equivalent_and_convert(c, s)\n\n\ndef test_sweep_target():\n    stim_circuit = stim.Circuit(\n        \"\"\"\n        CX sweep[2] 0\n        CY sweep[3] 1\n        CZ sweep[5] 2 sweep[7] 3\n        TICK\n    \"\"\"\n    )\n    a, b, c, d = cirq.LineQubit.range(4)\n    cirq_circuit = cirq.Circuit(\n        stimcirq.SweepPauli(stim_sweep_bit_index=2, cirq_sweep_symbol=\"sweep[2]\", pauli=cirq.X).on(\n            a\n        ),\n        stimcirq.SweepPauli(stim_sweep_bit_index=3, cirq_sweep_symbol=\"sweep[3]\", pauli=cirq.Y).on(\n            b\n        ),\n        stimcirq.SweepPauli(stim_sweep_bit_index=5, cirq_sweep_symbol=\"sweep[5]\", pauli=cirq.Z).on(\n            c\n        ),\n        stimcirq.SweepPauli(stim_sweep_bit_index=7, cirq_sweep_symbol=\"sweep[7]\", pauli=cirq.Z).on(\n            d\n        ),\n    )\n    cirq.testing.assert_has_diagram(\n        cirq_circuit,\n        \"\"\"\n0: ---X^sweep[2]='sweep[2]'---\n\n1: ---Y^sweep[3]='sweep[3]'---\n\n2: ---Z^sweep[5]='sweep[5]'---\n\n3: ---Z^sweep[7]='sweep[7]'---\n        \"\"\",\n        use_unicode_characters=False,\n    )\n    assert_circuits_are_equivalent_and_convert(cirq_circuit, stim_circuit)\n\n\ndef test_convert_repeat_simple():\n    stim_circuit = stim.Circuit(\n        \"\"\"\n        REPEAT 1000000 {\n            H 0\n            TICK\n            CNOT 0 1\n            TICK\n        }\n        M 0\n        TICK\n    \"\"\"\n    )\n    a, b = cirq.LineQubit.range(2)\n    cirq_circuit = cirq.Circuit(\n        cirq.CircuitOperation(\n            cirq.FrozenCircuit(cirq.H(a), cirq.CNOT(a, b)),\n            repetitions=1000000,\n            use_repetition_ids=False,\n        ),\n        cirq.measure(a, key=\"0\"),\n    )\n    assert stimcirq.stim_circuit_to_cirq_circuit(stim_circuit) == cirq_circuit\n    assert stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit) == stim_circuit\n\n\ndef test_convert_repeat_measurements():\n    stim_circuit = stim.Circuit(\n        \"\"\"\n        QUBIT_COORDS(2, 3) 0\n        QUBIT_COORDS(4, 5) 1\n        REPEAT 1000000 {\n            H 0\n            TICK\n            CNOT 0 1\n            TICK\n            M 0 1\n            DETECTOR(5) rec[-1] rec[-2]\n            SHIFT_COORDS(2)\n            TICK\n        }\n        M 0\n        DETECTOR(7) rec[-1] rec[-3]\n        TICK\n    \"\"\"\n    )\n    a, b = cirq.GridQubit(2, 3), cirq.GridQubit(4, 5)\n    cirq_circuit = cirq.Circuit(\n        cirq.Moment(\n            cirq.CircuitOperation(\n                cirq.FrozenCircuit(\n                    cirq.Moment(cirq.H(a)),\n                    cirq.Moment(cirq.CNOT(a, b)),\n                    cirq.Moment(\n                        cirq.measure(a, key=cirq.MeasurementKey(\"0\")),\n                        cirq.measure(b, key=cirq.MeasurementKey(\"1\")),\n                        stimcirq.DetAnnotation(relative_keys=[-1, -2], coordinate_metadata=[5]),\n                        stimcirq.ShiftCoordsAnnotation([2]),\n                    ),\n                ),\n                repetitions=1000000,\n                use_repetition_ids=False,\n            )\n        ),\n        cirq.Moment(\n            cirq.measure(a, key=\"2000000\"),\n            stimcirq.DetAnnotation(relative_keys=[-1, -3], coordinate_metadata=[7]),\n        ),\n    )\n    assert stimcirq.stim_circuit_to_cirq_circuit(stim_circuit) == cirq_circuit\n    assert stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit) == stim_circuit\n\n\ndef test_single_repeat_loops_always_flattened():\n    assert stimcirq.stim_circuit_to_cirq_circuit(stim.Circuit(\n        \"\"\"\n        REPEAT 1 {\n            H 0\n        }\n        \"\"\")) == cirq.Circuit(cirq.H(cirq.LineQubit(0)))\n    assert stimcirq.cirq_circuit_to_stim_circuit(cirq.Circuit(\n        cirq.CircuitOperation(\n            cirq.FrozenCircuit(\n                cirq.H(cirq.LineQubit(0)),\n            ),\n            repetitions=1,\n        ),\n    )) == stim.Circuit(\"H 0\\nTICK\")\n\n\ndef test_circuit_operations_always_in_isolated_moment():\n    stim_circuit = stim.Circuit(\n        \"\"\"\n        REPEAT 2 {\n            H 0 1\n        }\n        H 2 3\n        \"\"\"\n    )\n    cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit)\n    qs = cirq.LineQubit.range(4)\n    expected_cirq_circuit = cirq.Circuit(\n        cirq.CircuitOperation(\n            circuit=cirq.FrozenCircuit([cirq.H(qs[0]),cirq.H(qs[1])]),\n            repetitions=2,\n            use_repetition_ids=False\n        ),\n        cirq.Moment(cirq.H(qs[2]),cirq.H(qs[3])),\n    )\n    assert cirq_circuit == expected_cirq_circuit\n\n\n@pytest.mark.skip(reason=\"blocked by https://github.com/quantumlib/Cirq/issues/6136\")\ndef test_stim_circuit_to_cirq_circuit_mpad():\n    stim_circuit = stim.Circuit(\"\"\"\n        MPAD 0 1\n    \"\"\")\n    cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit)\n    assert cirq_circuit == cirq.Circuit(\n        cirq.PauliMeasurementGate(cirq.DensePauliString(\"\"), key=\"0\").on(),\n        cirq.PauliMeasurementGate(cirq.DensePauliString(\"\", coefficient=-1), key=\"1\").on(),\n    )\n\n\ndef test_stim_circuit_to_cirq_circuit_mxx_myy_mzz():\n    stim_circuit = stim.Circuit(\"\"\"\n        MXX 0 1\n        MYY 0 !1\n        MZZ !0 1\n    \"\"\")\n    cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit)\n    a, b = cirq.LineQubit.range(2)\n    assert cirq_circuit == cirq.Circuit(\n        cirq.PauliMeasurementGate(cirq.DensePauliString(\"XX\"), key='0').on(a, b),\n        cirq.PauliMeasurementGate(cirq.DensePauliString(\"YY\", coefficient=-1), key='1').on(a, b),\n        cirq.PauliMeasurementGate(cirq.DensePauliString(\"ZZ\", coefficient=-1), key='2').on(a, b),\n    )\n    assert stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit) == stim.Circuit(\"\"\"\n        MPP X0*X1\n        TICK\n        MPP !Y0*Y1\n        TICK\n        MPP !Z0*Z1\n        TICK\n    \"\"\")\n\n\ndef test_stim_circuit_to_cirq_circuit_spp():\n    stim_circuit = stim.Circuit(\"\"\"\n        SPP X1*Y2*Z3\n        SPP !Y4\n        SPP_DAG X5\n        SPP_DAG !Z0\n    \"\"\")\n    cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit)\n    assert cirq_circuit.to_text_diagram(use_unicode_characters=False).strip() == \"\"\"\n0: ---[Z]^0.5----\n\n1: ---[X]--------\n      |\n2: ---[Y]--------\n      |\n3: ---[Z]^0.5----\n\n4: ---[Y]^-0.5---\n\n5: ---[X]^-0.5---\n    \"\"\".strip()\n    q0, q1, q2, q3, q4, q5 = cirq.LineQubit.range(6)\n    assert cirq_circuit == cirq.Circuit([\n        cirq.Moment(\n            cirq.PauliStringPhasor(cirq.X(q1)*cirq.Y(q2)*cirq.Z(q3), exponent_neg=0.5),\n            cirq.PauliStringPhasor(cirq.Y(q4), exponent_neg=0, exponent_pos=0.5),\n            cirq.PauliStringPhasor(cirq.X(q5), exponent_neg=-0.5),\n            cirq.PauliStringPhasor(cirq.Z(q0), exponent_neg=0, exponent_pos=-0.5),\n        ),\n    ])\n    assert stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit) == stim.Circuit(\"\"\"\n        SPP X1*Y2*Z3\n        SPP_DAG Y4 X5\n        SPP Z0\n        TICK\n    \"\"\")\n\n\ndef test_tags_convert():\n    assert stimcirq.stim_circuit_to_cirq_circuit(stim.Circuit(\"\"\"\n        H[my_tag] 0\n    \"\"\")) == cirq.Circuit(\n        cirq.H(cirq.LineQubit(0)).with_tags('my_tag'),\n    )\n\n\n@pytest.mark.parametrize('gate', sorted(stim.gate_data().keys()))\ndef test_every_operation_converts_tags(gate: str):\n    if gate in [\n        \"ELSE_CORRELATED_ERROR\",\n        \"HERALDED_ERASE\",\n        \"HERALDED_PAULI_CHANNEL_1\",\n        \"TICK\",\n        \"REPEAT\",\n        \"MPAD\",\n        \"QUBIT_COORDS\",\n    ]:\n        pytest.skip()\n\n    data = stim.gate_data(gate)\n    stim_circuit = stim.Circuit()\n    arg = None\n    targets = [0, 1]\n    if data.num_parens_arguments_range.start:\n        arg = [2**-6] * data.num_parens_arguments_range.start\n    if data.takes_pauli_targets:\n        targets = [stim.target_x(0), stim.target_y(1)]\n    if data.takes_measurement_record_targets and not data.is_unitary:\n        stim_circuit.append(\"M\", [0], tag='custom_tag')\n        targets = [stim.target_rec(-1)]\n    if gate == 'SHIFT_COORDS':\n        targets = []\n    if gate == 'OBSERVABLE_INCLUDE':\n        arg = [1]\n    stim_circuit.append(gate, targets, arg, tag='custom_tag')\n    cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit)\n    assert any(cirq_circuit.all_operations())\n    for op in cirq_circuit.all_operations():\n        assert op.tags == ('custom_tag',)\n    restored_circuit = stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit)\n    assert restored_circuit.pop() == stim.CircuitInstruction(\"TICK\")\n    assert all(instruction.tag == 'custom_tag' for instruction in restored_circuit)\n    if gate not in ['MXX', 'MYY', 'MZZ']:\n        assert restored_circuit == stim_circuit\n\n\ndef test_loop_tagging():\n    stim_circuit = stim.Circuit(\"\"\"\n        REPEAT[custom-tag] 5 {\n            H[tag2] 0\n            TICK\n        }\n    \"\"\")\n    cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit)\n    assert cirq_circuit == cirq.Circuit(\n        cirq.CircuitOperation(\n            cirq.FrozenCircuit(\n                cirq.H(cirq.LineQubit(0)).with_tags('tag2'),\n            ),\n            repetitions=5,\n            use_repetition_ids=False,\n        ).with_tags('custom-tag')\n    )\n    restored_circuit = stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit)\n    assert restored_circuit == stim_circuit\n\n\ndef test_id_error_round_trip():\n    stim_circuit = stim.Circuit(\"\"\"\n        I_ERROR 0\n        I_ERROR(0.125, 0.25) 1\n        II_ERROR(0.25, 0.125) 2 3\n        II_ERROR 4 5\n        TICK\n    \"\"\")\n    cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit)\n    restored_circuit = stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit)\n    assert restored_circuit == stim_circuit\n\ndef test_round_trip_with_pauli_obs():\n    stim_circuit = stim.Circuit(\"\"\"\n        QUBIT_COORDS(5, 5) 0\n        R 0\n        OBSERVABLE_INCLUDE(0) X0\n        TICK\n        H 0\n        TICK\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        TICK\n    \"\"\")\n    cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit)\n    restored_circuit = stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit)\n    assert restored_circuit == stim_circuit\n\n\ndef test_single_measure_key_order():\n    stim_circuits = [\n        stim.Circuit(\n            \"\"\"\n            X 1\n            X 1 3\n            X 1 3\n            X 1 3 2\n            M 1\n            M 3\n            M 2\n            M 0\n            \"\"\"\n        ),\n        stim.Circuit(\n            \"\"\"\n            X 1\n            X 1\n            X 1\n            X 1\n            M 1 3\n            X 2\n            M 2 0\n            \"\"\"\n        )\n    ]\n    measure_key = \"m\"\n    for stim_circuit in stim_circuits:\n        cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(\n            stim_circuit, single_measure_key=measure_key\n        )\n        qubits = cirq.LineQubit.range(4)\n        expected_order = [\n            qubits[targ.qubit_value] \n            for inst in stim_circuit if inst.name == \"M\" \n            for targ in inst.targets_copy()\n        ]\n        actual_order = []\n        for op in cirq_circuit.all_operations():\n            if isinstance(op.gate, cirq.MeasurementGate):\n                assert op.gate.key == measure_key\n                assert len(op.qubits) == 1\n                actual_order.append(op.qubits[0])\n        assert expected_order == actual_order\n"
  },
  {
    "path": "glue/cirq/stimcirq/_sweep_pauli.py",
    "content": "from typing import AbstractSet, Any, Dict, List, Optional, Union\n\nimport cirq\nimport stim\nimport sympy\n\n\n@cirq.value_equality\nclass SweepPauli(cirq.Gate):\n    \"\"\"A Pauli gate included depending on sweep data, with compatibility across stim and cirq.\n\n    Includes a sweep bit index for stim and a sweep symbol for cirq.\n    Creates sweep-controlled operations like `CX sweep[5] 0` when converting to a stim circuit.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        stim_sweep_bit_index: int,\n        cirq_sweep_symbol: Optional[Union[str, sympy.Symbol]] = None,\n        pauli: cirq.Pauli,\n    ):\n        r\"\"\"\n\n        Args:\n            stim_sweep_bit_index: The bit position, in some unspecified array, controlling the Pauli.\n            cirq_sweep_symbol: The symbol used by cirq. Defaults to f\"sweep_{sweep_bit_index}\".\n            pauli: The cirq Pauli operation to apply when the bit is True.\n        \"\"\"\n        if cirq_sweep_symbol is None:\n            cirq_sweep_symbol = f\"sweep[{stim_sweep_bit_index}]\"\n        self.stim_sweep_bit_index = stim_sweep_bit_index\n        self.cirq_sweep_symbol = cirq_sweep_symbol\n        self.pauli = pauli\n\n    def _decomposed_into_pauli(self) -> cirq.Gate:\n        return self.pauli ** self.cirq_sweep_symbol\n\n    def _resolve_parameters_(self, resolver: cirq.ParamResolver, recursive: bool) -> cirq.Gate:\n        new_value = resolver.value_of(self.cirq_sweep_symbol, recursive=recursive)\n        if str(new_value) == str(self.cirq_sweep_symbol):\n            return self\n        return self.pauli ** new_value\n\n    def _is_parameterized_(self) -> bool:\n        return True\n\n    def _parameter_names_(self) -> AbstractSet[str]:\n        return {str(self.cirq_sweep_symbol)}\n\n    def _decompose_(self, qubits) -> cirq.OP_TREE:\n        return self.pauli.on(*qubits) ** self.cirq_sweep_symbol\n\n    def _num_qubits_(self) -> int:\n        return 1\n\n    def _value_equality_values_(self) -> Any:\n        return self.pauli, self.stim_sweep_bit_index, self.cirq_sweep_symbol\n\n    def _circuit_diagram_info_(self, args: Any) -> str:\n        return f\"{self.pauli}^sweep[{self.stim_sweep_bit_index}]='{self.cirq_sweep_symbol}'\"\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        return {\n            'pauli': self.pauli,\n            'stim_sweep_bit_index': self.stim_sweep_bit_index,\n            'cirq_sweep_symbol': self.cirq_sweep_symbol,\n        }\n\n    def __repr__(self) -> str:\n        return (\n            f'stimcirq.SweepPauli('\n            f'pauli={self.pauli!r}, '\n            f'stim_sweep_bit_index={self.stim_sweep_bit_index!r}, '\n            f'cirq_sweep_symbol={self.cirq_sweep_symbol!r})'\n        )\n\n    def _stim_conversion_(self, edit_circuit: stim.Circuit, targets: List[int], **kwargs):\n        edit_circuit.append_operation(\n            f\"C{self.pauli}\", [stim.target_sweep_bit(self.stim_sweep_bit_index)] + targets\n        )\n"
  },
  {
    "path": "glue/cirq/stimcirq/_sweep_pauli_test.py",
    "content": "import cirq\nimport numpy as np\nimport stim\nimport stimcirq\n\n\ndef test_repr():\n    cirq.testing.assert_equivalent_repr(\n        stimcirq.SweepPauli(stim_sweep_bit_index=1, pauli=cirq.X, cirq_sweep_symbol=\"a\"),\n        global_vals={\"stimcirq\": stimcirq},\n    )\n    cirq.testing.assert_equivalent_repr(\n        stimcirq.SweepPauli(stim_sweep_bit_index=2, pauli=cirq.Y, cirq_sweep_symbol=\"b\"),\n        global_vals={\"stimcirq\": stimcirq},\n    )\n\n\ndef test_stim_conversion():\n    actual = stimcirq.cirq_circuit_to_stim_circuit(\n        cirq.Circuit(\n            stimcirq.SweepPauli(\n                stim_sweep_bit_index=5, pauli=cirq.X, cirq_sweep_symbol=\"init_66\"\n            ).on(cirq.GridQubit(1, 3)),\n            stimcirq.SweepPauli(\n                stim_sweep_bit_index=7, pauli=cirq.Y, cirq_sweep_symbol=\"init_63\"\n            ).on(cirq.GridQubit(2, 4)),\n            stimcirq.SweepPauli(\n                stim_sweep_bit_index=5, pauli=cirq.Z, cirq_sweep_symbol=\"init_66\"\n            ).on(cirq.GridQubit(2, 4)),\n        )\n    )\n    assert actual == stim.Circuit(\n        \"\"\"\n        QUBIT_COORDS(1, 3) 0\n        QUBIT_COORDS(2, 4) 1\n        CX sweep[5] 0\n        CY sweep[7] 1\n        TICK\n        CZ sweep[5] 1\n        TICK\n    \"\"\"\n    )\n\ndef test_resolving_without_sweep_resolver():\n    cirq_circuit = cirq.Circuit(\n        stimcirq.SweepPauli(\n            stim_sweep_bit_index=0, pauli=cirq.X, cirq_sweep_symbol=\"init_0\"\n        ).on(cirq.LineQubit(0)),\n        stimcirq.SweepPauli(\n            stim_sweep_bit_index=1, pauli=cirq.X, cirq_sweep_symbol=\"init_1\"\n        ).on(cirq.LineQubit(1)),\n    )\n    # Resolve the cirq circuit without specifying the sweep_symbol (this should leave the op \n    # unchanged).\n    resolved_circuit = cirq.resolve_parameters(cirq_circuit, {\"init_1\":1})\n    op0, op1, = resolved_circuit.all_operations()\n    assert isinstance(op0.gate, stimcirq.SweepPauli) # Operation should still be a SweepPauli\n    assert isinstance(op1.gate, type(cirq.X)) # Operation should be converted to a cirq.X\n    # Conversion to stim still possible\n    assert stimcirq.cirq_circuit_to_stim_circuit(resolved_circuit) \n\ndef test_parameter_names():\n    cirq_circuit = cirq.Circuit(\n        stimcirq.SweepPauli(\n            stim_sweep_bit_index=0, pauli=cirq.X, cirq_sweep_symbol=\"init_0\"\n        ).on(cirq.LineQubit(0)),\n        stimcirq.SweepPauli(\n            stim_sweep_bit_index=1, pauli=cirq.X, cirq_sweep_symbol=\"init_1\"\n        ).on(cirq.LineQubit(1)),\n    )\n    assert cirq.parameter_names(cirq_circuit) == {'init_0', 'init_1'} \n\n\ndef test_cirq_compatibility():\n    circuit = cirq.Circuit(\n        stimcirq.SweepPauli(stim_sweep_bit_index=5, pauli=cirq.X, cirq_sweep_symbol=\"xx\").on(\n            cirq.LineQubit(0)\n        ),\n        cirq.measure(cirq.LineQubit(0), key=\"k\"),\n    )\n    np.testing.assert_array_equal(\n        cirq.Simulator().sample(circuit, params={\"xx\": 0}, repetitions=3)[\"k\"], [0, 0, 0]\n    )\n    np.testing.assert_array_equal(\n        cirq.Simulator().sample(circuit, params={\"xx\": 1}, repetitions=3)[\"k\"], [1, 1, 1]\n    )\n\n    circuit = cirq.Circuit(\n        stimcirq.SweepPauli(stim_sweep_bit_index=5, pauli=cirq.Z, cirq_sweep_symbol=\"xx\").on(\n            cirq.LineQubit(0)\n        ),\n        cirq.measure(cirq.LineQubit(0), key=\"k\"),\n    )\n    np.testing.assert_array_equal(\n        cirq.Simulator().sample(circuit, params={\"xx\": 0}, repetitions=3)[\"k\"], [0, 0, 0]\n    )\n    np.testing.assert_array_equal(\n        cirq.Simulator().sample(circuit, params={\"xx\": 1}, repetitions=3)[\"k\"], [0, 0, 0]\n    )\n\n    circuit = cirq.Circuit(\n        cirq.H(cirq.LineQubit(0)),\n        stimcirq.SweepPauli(stim_sweep_bit_index=5, pauli=cirq.Z, cirq_sweep_symbol=\"xx\").on(\n            cirq.LineQubit(0)\n        ),\n        cirq.H(cirq.LineQubit(0)),\n        cirq.measure(cirq.LineQubit(0), key=\"k\"),\n    )\n    np.testing.assert_array_equal(\n        cirq.Simulator().sample(circuit, params={\"xx\": 0}, repetitions=3)[\"k\"], [0, 0, 0]\n    )\n    np.testing.assert_array_equal(\n        cirq.Simulator().sample(circuit, params={\"xx\": 1}, repetitions=3)[\"k\"], [1, 1, 1]\n    )\n\n\ndef test_json_serialization():\n    c = cirq.Circuit(\n        stimcirq.SweepPauli(stim_sweep_bit_index=5, pauli=cirq.X, cirq_sweep_symbol=\"init_66\").on(\n            cirq.GridQubit(1, 3)\n        ),\n        stimcirq.SweepPauli(stim_sweep_bit_index=7, pauli=cirq.Y, cirq_sweep_symbol=\"init_63\").on(\n            cirq.GridQubit(2, 4)\n        ),\n    )\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.SweepPauli(stim_sweep_bit_index=2, pauli=cirq.Z, cirq_sweep_symbol=\"abc\")\n    packed = '{\\n  \"cirq_type\": \"SweepPauli\",\\n  \"pauli\": {\\n    \"cirq_type\": \"_PauliZ\",\\n    \"exponent\": 1.0,\\n    \"global_shift\": 0.0\\n  },\\n  \"stim_sweep_bit_index\": 2,\\n  \"cirq_sweep_symbol\": \"abc\"\\n}'\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed\n"
  },
  {
    "path": "glue/cirq/stimcirq/_two_qubit_asymmetric_depolarize.py",
    "content": "from typing import Any, Dict, List, Sequence, Tuple\n\nimport cirq\nimport stim\n\n\n@cirq.value_equality\nclass TwoQubitAsymmetricDepolarizingChannel(cirq.Gate):\n    \"\"\"A two qubit error channel that applies Pauli pairs according to the given probability\n    distribution.\n\n    The 15 probabilities are in IX, IY, ... ZY, ZZ order. II is skipped; it's the leftover.\n\n    This class is no longer used by stimcirq, but is kept around for backwards\n    compatibility of json-serialized circuits.\n    \"\"\"\n\n    def __init__(self, probabilities: Sequence[float]):\n        if len(probabilities) != 15:\n            raise ValueError(f\"len(probabilities={probabilities}) != 15\")\n        if sum(probabilities) > 1.000001:\n            raise ValueError(f\"sum(probabilities={probabilities}) > 1\")\n        self.probabilities = tuple(probabilities)\n\n    def _num_qubits_(self):\n        return 2\n\n    def _value_equality_values_(self):\n        return self.probabilities\n\n    def _has_mixture_(self):\n        return True\n\n    def _dense_mixture_(self):\n        result = [(1 - sum(self.probabilities), cirq.DensePauliString([0, 0]))]\n        result.extend(\n            [\n                (p, cirq.DensePauliString([((k + 1) >> 2) & 3, (k + 1) & 3]))\n                for k, p in enumerate(self.probabilities)\n            ]\n        )\n        return [(p, g) for p, g in result if p]\n\n    def _mixture_(self):\n        return [(p, cirq.unitary(g)) for p, g in self._dense_mixture_()]\n\n    def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs):\n        result = []\n        for p, d in self._dense_mixture_():\n            result.append(str(d)[1:] + \":\" + args.format_real(p))\n        return \"PauliMix(\" + \",\".join(result) + \")\", \"#2\"\n\n    def _stim_conversion_(self, edit_circuit: stim.Circuit, targets: List[int], **kwargs):\n        edit_circuit.append_operation(\"PAULI_CHANNEL_2\", targets, self.probabilities)\n\n    def __repr__(self):\n        return f\"stimcirq.TwoQubitAsymmetricDepolarizingChannel({self.probabilities!r})\"\n\n    @staticmethod\n    def _json_namespace_() -> str:\n        return ''\n\n    def _json_dict_(self) -> Dict[str, Any]:\n        return {'probabilities': list(self.probabilities)}\n"
  },
  {
    "path": "glue/cirq/stimcirq/_two_qubit_asymmetric_depolarize_test.py",
    "content": "import cirq\nimport stim\nimport stimcirq\n\n\ndef test_mixture():\n    r = stimcirq.TwoQubitAsymmetricDepolarizingChannel(\n        [0.125, 0, 0, 0, 0, 0, 0.375, 0, 0, 0, 0, 0, 0, 0.25, 0]\n    )\n    assert r._dense_mixture_() == [\n        (0.25, cirq.DensePauliString(\"II\")),\n        (0.125, cirq.DensePauliString(\"IX\")),\n        (0.375, cirq.DensePauliString(\"XZ\")),\n        (0.25, cirq.DensePauliString(\"ZY\")),\n    ]\n\n\ndef test_diagram():\n    r = stimcirq.TwoQubitAsymmetricDepolarizingChannel(\n        [0.125, 0, 0, 0, 0, 0, 0.375, 0, 0, 0, 0, 0, 0, 0.25, 0]\n    )\n    cirq.testing.assert_has_diagram(\n        cirq.Circuit(r.on(*cirq.LineQubit.range(2))),\n        \"\"\"\n0: ---PauliMix(II:0.25,IX:0.125,XZ:0.375,ZY:0.25)---\n      |\n1: ---#2--------------------------------------------\n        \"\"\",\n        use_unicode_characters=False,\n    )\n\n\ndef test_repr():\n    r = stimcirq.TwoQubitAsymmetricDepolarizingChannel(\n        [0.125, 0, 0, 0, 0, 0, 0.375, 0, 0, 0, 0, 0, 0, 0.25, 0]\n    )\n    assert eval(repr(r), {'stimcirq': stimcirq}) == r\n\n\ndef test_json_serialization():\n    r = stimcirq.TwoQubitAsymmetricDepolarizingChannel(\n        [0.0125, 0.1, 0, 0.23, 0, 0, 0.0375, 0, 0, 0, 0, 0, 0, 0.25, 0]\n    )\n    c = cirq.Circuit(r(cirq.LineQubit(0), cirq.LineQubit(1)))\n    json = cirq.to_json(c)\n    c2 = cirq.read_json(json_text=json, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER])\n    assert c == c2\n\n\ndef test_json_backwards_compat_exact():\n    raw = stimcirq.TwoQubitAsymmetricDepolarizingChannel([0.0125, 0.1, 0, 0.23, 0, 0, 0.0375, 0, 0.01, 0, 0, 0, 0, 0.25, 0])\n    packed = '{\\n  \"cirq_type\": \"TwoQubitAsymmetricDepolarizingChannel\",\\n  \"probabilities\": [\\n    0.0125,\\n    0.1,\\n    0,\\n    0.23,\\n    0,\\n    0,\\n    0.0375,\\n    0,\\n    0.01,\\n    0,\\n    0,\\n    0,\\n    0,\\n    0.25,\\n    0\\n  ]\\n}'\n    assert cirq.read_json(json_text=packed, resolvers=[*cirq.DEFAULT_RESOLVERS, stimcirq.JSON_RESOLVER]) == raw\n    assert cirq.to_json(raw) == packed\n\n\ndef test_native_cirq_gate_converts():\n    c = cirq.Circuit(cirq.asymmetric_depolarize(\n        error_probabilities={\n            'IX': 0.125,\n            'ZY': 0.25\n        }).on(cirq.LineQubit(0), cirq.LineQubit(1)))\n    s = stim.Circuit(\"\"\"\n        PAULI_CHANNEL_2(0.125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.25, 0) 0 1\n        TICK\n    \"\"\")\n    assert stimcirq.cirq_circuit_to_stim_circuit(c) == s\n    assert stimcirq.stim_circuit_to_cirq_circuit(s) == c\n"
  },
  {
    "path": "glue/crumble/README.md",
    "content": "# Crumble\n\nCrumble is an in-development tool for exploring and inspecting 2D stabilizer circuits, with a\nfocus on quantum error correction.\nIn particular, crumble automates the process of propagating and verifying the\nflow of Pauli products across the layers of the circuit.\n\n**Crumble is still being prototyped and developed.\nCrumble is not stable.\nCrumble is not polished.**\n\n## Index\n\n- [Accessing Crumble](#accessing-crumble)\n- [Using Crumble](#using-crumble)\n    - [Loading and Saving Circuits](#loading-saving)\n    - [Keyboard Controls](#keyboard-commands)\n    - [Mouse Controls](#mouse-commands)\n- [Building Crumble](#building-crumble)\n- [Testing Crumble](#testing-crumble)\n\n<a name=\"accessing-crumble\"></a>\n# Accessing Crumble\n\nCrumble can be accessed by installing stim `1.11` or later (e.g. by `pip install stim~=1.11`), printing the output of `stim.Circuit().diagram(\"interactive\")` to an HTML file, and then opening the HTML file in a browser.\n\nCrumble can also be accessed by [building it](#building-crumble).\n\n<a name=\"using-crumble\"></a>\n# Using Crumble\n\nThere are two core pieces to using crumble effectively:\n(1) editing the circuit\nand (2) propagating Paulis.\n\nEditing the circuit is done by selecting qubits with the mouse and hitting\nkeyboard keys to place gates.\nThe layers of the circuit can be navigated using the Q/E keys.\n\nPropagating Paulis is done by placing *markers* to indicate where to add terms.\nEach marker has a type (X, Y, or Z) and an index (0-9) indicating which indexed\nPauli product the marker is modifying.\nFor example, to place a Z term after a reset gate into the Pauli product with\nindex 1, select the reset gate and press `Z`+`1`. This introduces a Z term into\nthe Pauli product, and advancing through the circuit will show how the now\nnon-empty Pauli product changes as it is rewritten by the circuit's stabilizer\noperations.\n\nThe simplest way to use markers is as a method for seeing how errors propagate\nthrough the circuit.\nBut the far more useful case is for seeing how *knowledge*\npropagates through the circuit.\nAfter a qubit is reset, its Z observable is in a known state.\nAs the circuit executes, this piece of knowledge is transformed into different\nforms; it may later correspond to knowing a multi-qubit Pauli product or to\nknowing what the result of a measurement must be.\nPauli propagation shows how these pieces of knowledge move\nthrough the circuit.\n\nOf particular interest is finding small sets of resets that match small sets of\nnearby measurements (i.e. resets that prepare knowledge predicting the parity\nof a set of measurements).\nThese local reset-vs-measurement tautologies correspond to detectors, which can\nbe used to correct errors.\nThe path that the Pauli product takes, starting from the various resets and\nterminating on the various measurements, forms the detecting region of the\ndetector.\n\n<a name=\"loading-saving\"></a>\n## Loading and Saving Circuits\n\n- **Bookmarking**:\nAs crumble runs, it constantly updates the web page's address so that it encodes\nthe current circuit.\nFor example, for an empty circuit, the URL will end with `#circuit=` whereas\na circuit with a single Hadamard gate would end with `#circuit=Q(0,0)0;H_0`.\nThus, the current circuit can be saved by bookmarking the page and loaded again\nlater by opening the bookmark.\n- **Importing and Exporting**: In the top left of the page, there is a button\n\"Show Import/Export\".\nClicking this button will reveal a large textbox containing the current circuit\nencoded as a Stim circuit.\nTo save the circuit, copy this text and write it to a text file on your computer.\nThe saved circuit can later be loaded by copying the file's contents to your\nclipboard, pasting over the contents of the textbox, and hitting the\n\"↓ Import from Stim Circuit ↓\" button below the textbox.\nThe import/export text box can be hidden by clicking the \"Show Import/Export\"\nbutton (now labelled \"Hide Import/Export\") again.\n\n<a name=\"keyboard-commands\"></a>\n## Keyboard Controls\n\n**Pauli Propagation**\n\n- `spacebar`: Clear all Pauli propagation markers at current selection.\n- `#`: Puts a Pauli propagation marker at the current selection for the indexed Pauli product.\n    `#` can be any of 1, 2, 3, etc and determines which of the tracked Pauli products the marker goes into.\n    For example, `2` will place a marker that multiplies a Pauli term into tracked Pauli product #2.\n    The basis of the marker is inferred from context (e.g. if an `RX` gate is selected, it will be an `X` marker).\n- `x+#`: Put an X-type Pauli propagation marker at the current selection for the indexed Pauli product.\n- `y+#`: Put a Y-type Pauli propagation marker at the current selection for the indexed Pauli product.\n- `z+#`: Put a Z-type Pauli propagation marker at the current selection for the indexed Pauli product.\n- `d+#`: Converts the indexed Pauli product into a circuit `DETECTOR` declaration.\n- `o+#`: Converts the indexed Pauli product into a circuit `OBSERVABLE_INCLUDE` declaration.\n- `j+#`: Picks a `DETECTOR` or `OBSERVABLE_INCLUDE` declaration touching the current selection and converts it into a tracked Pauli product.\n- `k+#`: Add a marker to any dissipative gate that the indexed Pauli product overlaps in the current layer.\n\n**Editing**\n\n- `p`: Add a background polygon with corners at the current selection.\n    The color of the polygon is affected by modifier keys: X, Y, Z, alt, shift.\n- `e`: Move to next layer.\n- `q`: Move to previous layer.\n- `shift+e`: Move forward 5 layers.\n- `shift+q`: Move backward 5 layers.\n- `escape`: Unselect. Set current selection to the empty set.\n- `delete`: Delete gates at current selection.\n- `backspace`: Delete gates at current selection.\n- `ctrl+delete`: Delete current circuit layer.\n- `ctrl+backspace`: Delete current circuit layer.\n- `ctrl+insert`: Insert empty layer at current circuit layer, pushing current circuit layer ahead in time.\n- `ctrl+z`: Undo\n- `ctrl+y`: Redo\n- `ctrl+shift+z`: Redo\n- `ctrl+c`: Copy selection to clipboard (or entire layer if nothing selected).\n- `ctrl+v`: Past clipboard contents at current selection (or entire layer if nothing selected).\n- `ctrl+x`: Cut selection to clipboard (or entire layer if nothing selected).\n- `f`: Reverse direction of selected two qubit gates (e.g. exchange the controls and targets of a CNOT).\n- `g`: Reverse order of circuit layers, from the current layer to the next empty layer.\n- `home`: Jump to the first layer of the circuit.\n- `end`: Jump to the last layer of the circuit.\n- `t`: Rotate circuit 45 degrees clockwise.\n- `shift+t`: Rotate circuit 45 degrees counter-clockwise.\n- `v`: Translate circuit down one step.\n- `^`: Translate circuit up one step.\n- `>`: Translate circuit right one step.\n- `<`: Translate circuit left one step.\n- `.`: Translate circuit down and right by a half step.\n\n**Single Qubit Gates**\n\nNote: use `shift` to get the inverse of a gate.\n\n- `h`: Overwrite selection with `H` gate\n- `s`: Overwrite selection with `SQRT_Z` gate\n- `r`: Overwrite selection with `R` gate\n- `m`: Overwrite selection with `M` gate\n- `h+z` or `h+x+y`: Overwrite selection with `H_XY` gate\n- `h+x` or `h+y+z`: Overwrite selection with `H_YZ` gate\n- `s+x`: Overwrite selection with `SQRT_X` gate\n- `s+y`: Overwrite selection with `SQRT_Y` gate\n- `r+x`: Overwrite selection with `RX` gate\n- `r+y`: Overwrite selection with `RY` gate\n- `m+x`: Overwrite selection with `MX` gate\n- `m+y`: Overwrite selection with `MY` gate\n- `m+r+x`: Overwrite selection with `MRX` gate\n- `m+r+y`: Overwrite selection with `MRY` gate\n- `m+r`: Overwrite selection with `MR` gate\n- `c+t`: Overwrite selection with `C_XYZ` gate\n- `j+x`: Overwrite selection with **j**ust a Pauli `X` gate\n- `j+y`: Overwrite selection with **j**ust a Pauli `Y` gate\n- `j+z`: Overwrite selection with **j**ust a Pauli `Z` gate\n- `shift+c+t`: Overwrite selection with `C_ZYX` gate\n\n**Two Qubit Gates**\n\nNote: when a single qubit is selected and a two qubit gate is placed, the gate\nspans between the selected qubit and *the qubit the mouse is hovering over*.\nWhen multiple qubits are selected, the difference between the topmost leftmost\nqubit and *the qubit the mouse is hovering over* is computed, and then each selected qubit\ntargets its position offset by that difference.\n\nNote: use `shift` to get the inverse of a gate.\n\n- `w`: Overwrite selection with `SWAP` gate targeting mouse\n- `w+i`: Overwrite selection with `ISWAP` gate targeting mouse\n- `w+x`: Overwrite selection with `CXSWAP` gate targeting mouse\n- `c+x`: Overwrite selection with `CX` gate targeting mouse\n- `c+y`: Overwrite selection with `CY` gate targeting mouse\n- `c+z`: Overwrite selection with `CZ` gate targeting mouse\n- `c+x+y`: Overwrite selection with `XCY` gate targeting mouse\n- `alt+c+x`: Overwrite selection with `XCX` gate targeting mouse\n- `alt+c+y`: Overwrite selection with `YCY` gate targeting mouse\n- `c+s+x`: Overwrite selection with `SQRT_XX` gate targeting mouse\n- `c+s+y`: Overwrite selection with `SQRT_YY` gate targeting mouse\n- `c+s+z`: Overwrite selection with `SQRT_ZZ` gate targeting mouse\n- `c+m+x`: Overwrite selection with `MXX` gate targeting mouse\n- `c+m+y`: Overwrite selection with `MYY` gate targeting mouse\n- `c+m+z`: Overwrite selection with `MZZ` gate targeting mouse\n\n**Multi Qubit Gates**\n\n- `m+p+x`: Overwrite selection with a single `MPP` gate targeting the tensor product of X on each selected qubit.\n- `m+p+y`: Overwrite selection with a single `MPP` gate targeting the tensor product of Y on each selected qubit.\n- `m+p+z`: Overwrite selection with a single `MPP` gate targeting the tensor product of Z on each selected qubit.\n\n**Keyboard Buttons as Gate Adjectives**\n\nRoughly speaking, the \"keyboard language\" for gates used by Crumble has the following \"adjectives\":\n\n- `x` means \"X basis\"\n- `y` means \"Y basis\"\n- `z` means \"Z basis\"\n- `shift` means \"inverse\"\n- `c` means \"controlled gate\" or more generally \"two qubit variant of gate\"\n- `s` means \"square root\"\n- `m` means \"measure\"\n- `r` means \"reset\"\n- `w` means \"swap\"\n- `alt` means \"no not that one, a different one\"\n\nHere are some examples:\n\n- `r+x` is the **X basis variant** of the **reset operation** (i.e. the gate `RX 0`).\n- `m+r` is the **measure** (m) and **reset** (r) operation (i.e. the gate `MR 0`).\n- `m+r+y` is the **Y basis variant** of the **measure** (m) and **reset** (r) operation (i.e. the gate `MRY 0`).\n- `c+m+x` is the **two qubit variant** (c)\nof **measurement** (m)\nin the **X basis** (x) (i.e. the gate `MXX 1 2`).\n- `shift+c+s+y` is the **inverse** (shift)\nof the **two qubit variant** (c)\nof the **square root** (s)\nof the **Y gate** (y) (i.e. the gate `SQRT_YY_DAG 1 2`).\n\n<a name=\"mouse-commands\"></a>\n### Mouse Controls\n\nNote: to `BoxSelect` means to press down the left mouse button, drag the mouse\nwhile holding the button down to outline a rectangular region, and then release\nthe mouse button.\n\nNote: using `shift` modifies how the mouse updates the current selection. When\n`shift` is being held and selection S1 would be replaced by selection S2, the new\nselection will instead be set to the union of S1 and S2.\n\nNote: using `ctrl` modifies how the mouse updates the current selection. When\n`ctrl` is being held and selection S1 would be replaced by selection S2, the new\nselection will instead be set to the symmetric difference of S1 and S2.\n\n- `LeftClick`: Set current selection to clicked qubit (or to nothing, if clicking empty space).\n- `BoxSelect`: Set current selection to boxed area.\n- `Alt+BoxSelect`: Set current selection to boxed area, but only including the\nqubits with the same parity as the initially clicked qubit at the start of the\nbox selection action. The specific parity being used depends on context. For\nexample, when selecting a column of qubits, the row parity is used. When\nselecting a 2d region, the subgrid parity is used.\n\n<a name=\"building-crumble\"></a>\n# Building Crumble\n\nCrumble's source code can be served directly by a webserver.\nFor example, serve crumble using python's built-in web server:\n\n```bash\n# from the root of Stim's git repository:\npython -m http.server --directory glue/crumble\n```\n\nthen open [http://localhost:8000/crumble.html](http://localhost:8000/crumble.html) in a web browser.\n\nA single-page version of crumble can be created using rollup-js and uglify-js:\n\n```base\n# npm install -g rollup uglify-js\n\n# from the root of Stim's git repository:\n{\n    cat glue/crumble/crumble.html | grep -v \"^<script\";\n    echo \"<script>\";\n    rollup glue/crumble/main.js | uglifyjs -c -m --mangle-props --toplevel;\n    echo \"</script>\";\n} > crumble_single_page.html\n```\n\n<a name=\"testing-crumble\"></a>\n# Testing Crumble\n\nCrumble's unit tests can be executed by opening the page `test/test.html` in a\nweb browser:\n\n```bash\n# from the root of Stim's git repository:\npython -m http.server --directory glue/crumble &\nfirefox localhost:8000/test/test.html\n\n# if page says \"All X tests passed\" then tests passed.\n# see the browser console for a log of tests that were run\n```\n\nUnit tests can also be run headless using NodeJS.\nUnit tests for functionality such as canvas drawing will be skipped when running\nheadless:\n\n```\n# from the root of Stim's git repository:\n\nnode glue/crumble/run_tests_headless.js\n# will end with 'all tests passed' if all tests passed\n```\n"
  },
  {
    "path": "glue/crumble/base/cooldown_throttle.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Performs an action when triggered, but defers the action if it happens too soon after the last one.\n *\n * Triggering multiple times during the cooldown period only results in one action being performed.\n */\nclass CooldownThrottle {\n    /**\n     * @param {!function() : void} action\n     * @param {!number} cooldownMs\n     * @param {!number} slowActionCooldownPumpUpFactor\n     * @param {!boolean=false} waitWithRequestAnimationFrame\n     * @constructor\n     */\n    constructor(action, cooldownMs, slowActionCooldownPumpUpFactor=0, waitWithRequestAnimationFrame=false) {\n        /** @type {!function() : void} */\n        this.action = action;\n        /** @type {!number} */\n        this.cooldownDuration = cooldownMs;\n        /** @type {!number} */\n        this.slowActionCooldownPumpupFactor = slowActionCooldownPumpUpFactor;\n        /** @type {!boolean} */\n        this._waitWithRequestAnimationFrame = waitWithRequestAnimationFrame;\n\n        /**\n         * @type {!string}\n         * @private\n         */\n        this._state = 'idle';\n        /**\n         * @type {!number}\n         * @private\n         */\n        this._cooldownStartTime = -Infinity;\n    }\n\n    _triggerIdle() {\n        // Still cooling down?\n        let remainingCooldownDuration = this.cooldownDuration - (performance.now() - this._cooldownStartTime);\n        if (remainingCooldownDuration > 0) {\n            this._forceIdleTriggerAfter(remainingCooldownDuration);\n            return;\n        }\n\n        // Go go go!\n        this._state = 'running';\n        let t0 = performance.now();\n        try {\n            this.action();\n        } finally {\n            let dt = performance.now() - t0;\n            this._cooldownStartTime = performance.now() + (dt * this.slowActionCooldownPumpupFactor);\n            // Were there any triggers while we were running?\n            if (this._state === 'running-and-triggered') {\n                this._forceIdleTriggerAfter(this.cooldownDuration);\n            } else {\n                this._state = 'idle';\n            }\n        }\n    }\n\n    /**\n     * Asks for the action to be performed as soon as possible.\n     * (No effect if the action was already requested but not performed yet.)\n     */\n    trigger() {\n        switch (this._state) {\n            case 'idle':\n                this._triggerIdle();\n                break;\n            case 'waiting':\n                // Already triggered. Do nothing.\n                break;\n            case 'running':\n                // Re-trigger.\n                this._state = 'running-and-triggered';\n                break;\n            case 'running-and-triggered':\n                // Already re-triggered. Do nothing.\n                break;\n            default:\n                throw new Error('Unrecognized throttle state: ' + this._state);\n        }\n    }\n\n    /**\n     * @private\n     */\n    _forceIdleTriggerAfter(duration) {\n        this._state = 'waiting';\n\n        // setTimeout seems to refuse to run while I'm scrolling with my mouse wheel on chrome in windows.\n        // So, for stuff that really has to come back in that case, we also support requestAnimationFrame looping.\n        if (this._waitWithRequestAnimationFrame) {\n            let iter;\n            let start = performance.now();\n            iter = () => {\n                if (performance.now() < start + duration) {\n                    requestAnimationFrame(iter);\n                    return;\n                }\n                this._state = 'idle';\n                this._cooldownStartTime = -Infinity;\n                this.trigger()\n            };\n            iter();\n        } else {\n            setTimeout(() => {\n                this._state = 'idle';\n                this._cooldownStartTime = -Infinity;\n                this.trigger()\n            }, duration);\n        }\n    }\n\n\n}\n\nexport {CooldownThrottle}\n"
  },
  {
    "path": "glue/crumble/base/describe.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst COLLECTION_CUTOFF = 1000;\nconst BAD_TO_STRING_RESULT = new (function(){})().toString();\nconst RECURSE_LIMIT_DESCRIPTION = \"!recursion-limit!\";\nconst DEFAULT_RECURSION_LIMIT = 10;\n\nfunction try_describe_atomic(value) {\n    if (value === null) {\n        return \"null\";\n    }\n    if (value === undefined) {\n        return \"undefined\";\n    }\n    if (typeof value === \"string\") {\n        return `\"${value}\"`;\n    }\n    if (typeof value === \"number\") {\n        return \"\" + value;\n    }\n    return undefined;\n}\nfunction try_describe_collection(value, recursionLimit) {\n    if (recursionLimit === 0) {\n        return RECURSE_LIMIT_DESCRIPTION;\n    }\n    if (value instanceof Map) {\n        return describe_Map(value, recursionLimit);\n    }\n    if (value instanceof Set) {\n        return describe_Set(value, recursionLimit);\n    }\n    if (value[Symbol.iterator] !== undefined) {\n        return describe_Iterable(value, recursionLimit);\n    }\n    return undefined;\n}\nfunction describe_fallback(value, recursionLimit) {\n    try {\n        let defaultString = String(value);\n        if (defaultString !== BAD_TO_STRING_RESULT) {\n            return defaultString;\n        }\n    } catch {\n    }\n    return describe_Object(value, recursionLimit);\n}\n\n/**\n * Attempts to give a useful and unambiguous description of the given value.\n *\n * @param {*} value\n * @param {!int=} recursionLimit\n * @returns {!string}\n */\nfunction describe(value, recursionLimit = DEFAULT_RECURSION_LIMIT) {\n    return try_describe_atomic(value) ||\n        try_describe_collection(value, recursionLimit) ||\n        describe_fallback(value, recursionLimit);\n}\n\n/**\n * @param {!Map} map\n * @param {!int} limit\n * @returns {!string}\n */\nfunction describe_Map(map, limit) {\n    let entries = [];\n    for (let [k, v] of map.entries()) {\n        if (entries.length > COLLECTION_CUTOFF) {\n            entries.push(\"[...]\");\n            break;\n        }\n        //noinspection JSUnusedAssignment\n        let keyDesc = describe(k, limit - 1);\n        //noinspection JSUnusedAssignment\n        let valDesc = describe(v, limit - 1);\n        entries.push(`${keyDesc}: ${valDesc}`);\n    }\n    return `Map{${entries.join(\", \")}}`;\n}\n\n/**\n * @param {!Set} set\n * @param {!int} limit\n * @returns {!string}\n */\nfunction describe_Set(set, limit) {\n    let entries = [];\n    for (let e of set) {\n        if (entries.length > COLLECTION_CUTOFF) {\n            entries.push(\"[...]\");\n            break;\n        }\n        entries.push(describe(e, limit - 1));\n    }\n    return `Set{${entries.join(\", \")}}`;\n}\n\n/**\n * @param {!Iterable} seq\n * @param {!int} limit\n * @returns {!string}\n */\nfunction describe_Iterable(seq, limit) {\n    let entries = [];\n    for (let e of seq) {\n        if (entries.length > COLLECTION_CUTOFF) {\n            entries.push(\"[...]\");\n            break;\n        }\n        entries.push(describe(e, limit - 1));\n    }\n    let prefix = Array.isArray(seq) ? \"\" : seq.constructor.name;\n    return `${prefix}[${entries.join(\", \")}]`;\n}\n\n/**\n * @param {*} value\n * @param {!int} limit\n * @returns {!string}\n */\nfunction describe_Object(value, limit) {\n    let entries = [];\n    for (let k in value) {\n        if (!value.hasOwnProperty(k)) {\n            continue;\n        }\n        if (entries.length > COLLECTION_CUTOFF) {\n            entries.push(\"[...]\");\n            break;\n        }\n        let v = value[k];\n        let keyDesc = describe(k, limit - 1);\n        let valDesc = describe(v, limit - 1);\n        entries.push(`${keyDesc}: ${valDesc}`);\n    }\n\n    if (value.constructor === undefined) {\n        return `[an unknown non-primitive value with no constructor]`;\n    }\n    let typeName = value.constructor.name;\n    let prefix = typeName === {}.constructor.name ? \"\" : `(Type: ${typeName})`;\n    return `${prefix}{${entries.join(\", \")}}`;\n}\n\nexport {describe}\n"
  },
  {
    "path": "glue/crumble/base/describe.test.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {assertThat, test} from \"../test/test_util.js\"\nimport {describe} from \"./describe.js\"\n\nclass DescribableClass {\n    constructor() { this.x = 1; }\n}\nclass DescribedClass {\n    constructor() { this.x = 1; }\n    toString() { return \"described\"; }\n}\nclass SomeIterable {\n    constructor() {}\n\n    //noinspection JSMethodCanBeStatic,JSUnusedGlobalSymbols\n    [Symbol.iterator]() {\n        return [1, 2, 3][Symbol.iterator]();\n    }\n}\n\ntest(\"describe.trivial\", () => {\n    assertThat(describe(undefined)).isEqualTo(\"undefined\");\n    assertThat(describe(null)).isEqualTo(\"null\");\n    assertThat(describe(false)).isEqualTo(\"false\");\n    assertThat(describe(\"\")).isEqualTo('\"\"');\n    assertThat(describe(0)).isEqualTo(\"0\");\n    assertThat(describe(Symbol())).isEqualTo(\"Symbol()\");\n\n    assertThat(describe([])).isEqualTo(\"[]\");\n    assertThat(describe({})).isEqualTo(\"{}\");\n    assertThat(describe(new Float32Array(0))).isEqualTo(\"Float32Array[]\");\n    assertThat(describe(new Int8Array(0))).isEqualTo(\"Int8Array[]\");\n    assertThat(describe(new Map())).isEqualTo(\"Map{}\");\n    assertThat(describe(new Set())).isEqualTo(\"Set{}\");\n});\n\ntest(\"describe.simple\", () => {\n    assertThat(describe(true)).isEqualTo(\"true\");\n    assertThat(describe(1.5)).isEqualTo(\"1.5\");\n    assertThat(describe(\"b\")).isEqualTo('\"b\"');\n    assertThat(describe(Symbol(\"a\"))).isEqualTo('Symbol(a)');\n    assertThat(describe(Infinity)).isEqualTo(\"Infinity\");\n    assertThat(describe(-Infinity)).isEqualTo(\"-Infinity\");\n    assertThat(describe(NaN)).isEqualTo(\"NaN\");\n\n    assertThat(describe([1, 2, 3])).isEqualTo(\"[1, 2, 3]\");\n    assertThat(describe(new Float32Array([1, 2, 3]))).isEqualTo(\"Float32Array[1, 2, 3]\");\n    assertThat(describe(new Int8Array([1, 2, 3]))).isEqualTo(\"Int8Array[1, 2, 3]\");\n    assertThat(describe(new Set([2]))).isEqualTo(\"Set{2}\");\n    assertThat(describe(new Map([[2, \"b\"]]))).isEqualTo('Map{2: \"b\"}');\n    assertThat(describe({2: \"b\"})).isEqualTo('{\"2\": \"b\"}');\n\n    assertThat(describe(new DescribedClass())).isEqualTo(\"described\");\n    assertThat(describe(new DescribableClass())).isEqualTo('(Type: DescribableClass){\"x\": 1}');\n    assertThat(describe(new SomeIterable())).isEqualTo(\"SomeIterable[1, 2, 3]\");\n});\n\ntest(\"describe.recursion\", () => {\n    let a = [];\n    a.push(a);\n    assertThat(describe(a, 2)).isEqualTo(\n        \"[[!recursion-limit!]]\");\n    assertThat(describe(a, 10)).isEqualTo(\n        \"[[[[[[[[[[!recursion-limit!]]]]]]]]]]\");\n\n    let m = new Map();\n    m.set(1, m);\n    assertThat(describe(m, 2)).isEqualTo(\n        \"Map{1: Map{1: !recursion-limit!}}\");\n    assertThat(describe(m, 10)).isEqualTo(\n        \"Map{1: Map{1: Map{1: Map{1: Map{1: Map{1: Map{1: Map{1: Map{1: Map{1: !recursion-limit!}}}}}}}}}}\");\n\n    let s = new Set();\n    s.add(s);\n    assertThat(describe(s, 2)).isEqualTo(\n        \"Set{Set{!recursion-limit!}}\");\n    assertThat(describe(s, 10)).isEqualTo(\n        \"Set{Set{Set{Set{Set{Set{Set{Set{Set{Set{!recursion-limit!}}}}}}}}}}\");\n\n    let o = {};\n    o[2] = o;\n    assertThat(describe(o, 2)).isEqualTo(\n        '{\"2\": {\"2\": !recursion-limit!}}');\n    assertThat(describe(o, 10)).isEqualTo(\n        '{\"2\": {\"2\": {\"2\": {\"2\": {\"2\": {\"2\": {\"2\": {\"2\": {\"2\": {\"2\": !recursion-limit!}}}}}}}}}}');\n\n    // Default terminates.\n    assertThat(describe(a)).isNotEqualTo(undefined);\n    assertThat(describe(m)).isNotEqualTo(undefined);\n    assertThat(describe(s)).isNotEqualTo(undefined);\n    assertThat(describe(o)).isNotEqualTo(undefined);\n});\n"
  },
  {
    "path": "glue/crumble/base/equate.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Determines if two values are currently equivalent.\n *\n * Values that are equal according to === are currently equivalent.\n * NaN is currently equivalent to NaN.\n * Values with an `isEqualTo` method are currently equivalent to values that return true when passed to that method.\n * Collections of the same type that contain currently equivalent entries are currently equivalent.\n * Objects of the same type with equivalent same own properties and iterables are currently equivalent.\n *\n * @param {*} subject\n * @param {*} other\n * @returns {!boolean}\n */\nfunction equate(subject, other) {\n    if (subject === other || (isExactlyNaN(subject) && isExactlyNaN(other))) {\n        return true;\n    }\n\n    // Custom equality.\n    let customEquality = tryEquate_custom(subject, other);\n    if (customEquality !== undefined) {\n        return customEquality;\n    }\n    if (isAtomic(subject) || isAtomic(other) || !eqType(subject, other)) {\n        return false;\n    }\n\n    // Collection equality.\n    if (subject instanceof Map) {\n        return equate_Maps(subject, other);\n    }\n    if (subject instanceof Set) {\n        return equate_Sets(subject, other);\n    }\n    if (isIndexable(subject)) {\n        return equate_Indexables(subject, other);\n    }\n\n    // Object equality.\n    return equate_Objects(subject, other);\n}\n\nconst GENERIC_ARRAY_TYPES = [\n    Float32Array,\n    Float64Array,\n    Int8Array,\n    Int16Array,\n    Int32Array,\n    Uint8Array,\n    Uint16Array,\n    Uint32Array,\n    Uint8ClampedArray\n];\n\n/**\n * @param {*} v\n * @returns {!boolean}\n */\nfunction isExactlyNaN(v) {\n    return typeof v === \"number\" && isNaN(v);\n}\n\n/**\n * @param {*} subject\n * @param {*} other\n * @returns {undefined|!boolean}\n */\nfunction tryEquate_custom(subject, other) {\n    if (!isAtomic(subject) && subject.constructor !== undefined && subject.constructor.prototype.hasOwnProperty(\"isEqualTo\")) {\n        return subject.isEqualTo(other);\n    }\n    if (!isAtomic(other) && other.constructor !== undefined && other.constructor.prototype.hasOwnProperty(\"isEqualTo\")) {\n        return other.isEqualTo(subject);\n    }\n    return undefined;\n}\n\n/**\n * @param {*} value\n * @returns {!boolean}\n */\nfunction isAtomic(value) {\n    return value === null ||\n        value === undefined ||\n        typeof value === \"string\" ||\n        typeof value === \"number\" ||\n        typeof value === \"boolean\";\n}\n\n/**\n * @param {*} value\n * @returns {!boolean}\n */\nfunction isIndexable(value) {\n    return Array.isArray(value) || !GENERIC_ARRAY_TYPES.every(t => !(value instanceof t));\n}\n\n/**\n * @param {*} subject\n * @param {*} other\n * @returns {!boolean}\n */\nfunction eqType(subject, other) {\n    return subject.constructor.name === other.constructor.name;\n}\n\n/**\n * @param {!(*[])} subject\n * @param {!(*[])} other\n * @returns {!boolean}\n */\nfunction equate_Indexables(subject, other) {\n    if (subject.length !== other.length) {\n        return false;\n    }\n    for (let i = 0; i < subject.length; i++) {\n        if (!equate(subject[i], other[i])) {\n            return false;\n        }\n    }\n    return true;\n}\n\n/**\n * @param {!Iterable} subject\n * @param {!Iterable} other\n * @returns {!boolean}\n */\nfunction equate_Iterables(subject, other) {\n    let otherIter = other[Symbol.iterator]();\n    for (let subjectItem of subject) {\n        let otherItemDone = otherIter.next();\n        if (otherItemDone.done || !equate(subjectItem, otherItemDone.value)) {\n            return false;\n        }\n    }\n    return otherIter.next().done;\n}\n\n/**\n * @param {!Map} subject\n * @param {!Map} other\n * @returns {!boolean}\n */\nfunction equate_Maps(subject, other) {\n    if (subject.size !== other.size) {\n        return false;\n    }\n    for (let [k, v] of subject) {\n        //noinspection JSUnusedAssignment\n        if (!other.has(k)) {\n            return false;\n        }\n        //noinspection JSUnusedAssignment\n        let otherV = other.get(k);\n        //noinspection JSUnusedAssignment\n        if (!equate(v, otherV)) {\n            return false;\n        }\n    }\n    return true;\n}\n\n/**\n * @param {!Set} subject\n * @param {!Set} other\n * @returns {!boolean}\n */\nfunction equate_Sets(subject, other) {\n    if (subject.size !== other.size) {\n        return false;\n    }\n    for (let k of subject) {\n        if (!other.has(k)) {\n            return false;\n        }\n    }\n    return true;\n}\n\n/**\n * @param {!object} obj\n * @returns {!Set}\n */\nfunction objectKeys(obj) {\n    let result = new Set();\n    for (let k in obj) {\n        if (obj.hasOwnProperty(k)) {\n            result.add(k);\n        }\n    }\n    return result;\n}\n\n/**\n * @param {!object} subject\n * @param {!object} other\n * @returns {!boolean}\n */\nfunction equate_Objects(subject, other) {\n    let keys = objectKeys(subject);\n    if (!equate_Sets(keys, objectKeys(other))) {\n        return false;\n    }\n\n    for (let k of keys) {\n        if (k === Symbol.iterator) {\n            continue;\n        }\n        if (!equate(subject[k], other[k])) {\n            return false;\n        }\n    }\n\n    let hasSubjectIter = subject[Symbol.iterator] !== undefined;\n    let hasOtherIter = other[Symbol.iterator] !== undefined;\n    if (hasSubjectIter !== hasOtherIter) {\n        return false;\n    }\n    if (hasSubjectIter && hasOtherIter) {\n        if (!equate_Iterables(/** @type {!Iterable} */ subject, /** @type {!Iterable} */ other)) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nexport {equate, equate_Maps}\n"
  },
  {
    "path": "glue/crumble/base/equate.test.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {assertThat, test} from \"../test/test_util.js\"\nimport {equate} from \"./equate.js\"\nimport {describe} from \"./describe.js\";\n\nclass EmptyClass {\n    constructor() { }\n}\nclass EmptyClass2 {\n    constructor() { }\n}\nclass PropClass {\n    constructor(v) {\n        //noinspection JSUnusedGlobalSymbols\n        this.v = v;\n    }\n}\nclass SomeIterable {\n    constructor() {}\n\n    //noinspection JSMethodCanBeStatic,JSUnusedGlobalSymbols\n    [Symbol.iterator]() { return [1, 2, 3][Symbol.iterator](); }\n}\nclass One {\n    constructor() {}\n    isEqualTo(other) {\n        return this !== null && other === 1 || other instanceof One;\n    }\n}\nclass First {\n    constructor(x, y) {\n        this.x = x;\n        this.y = y;\n    }\n    isEqualTo(other) {\n        return other instanceof First && this.x === other.x;\n    }\n}\nclass Iter {\n    constructor(items) {\n        this[Symbol.iterator] = () => items[Symbol.iterator]();\n    }\n}\nclass Iter2 {\n    constructor(items) {\n        this[Symbol.iterator] = () => items[Symbol.iterator]();\n    }\n}\n\ntest(\"Equate.groups\", () => {\n    let groups = [\n        [null, null],\n        [undefined, undefined],\n        [true, true],\n        [false, false],\n        [0, 0.0, 0],\n        [1, 1.0, 1, new One(), new One()],\n        [-1, -1.0, -1],\n        [2, 2.0, 2],\n        [Infinity, Infinity],\n        [-Infinity, -Infinity],\n        [NaN, NaN],\n        [\"\", \"\"],\n        [\"0\", \"0\"],\n        [[], []],\n        [[[]], [[]]],\n        [new Iter([]), new Iter([])],\n        [new Iter([1]), new Iter([1])],\n        [new Iter([1, 2, 3]), new Iter([1, 2, 3])],\n        [new Iter2([]), new Iter2([])],\n        [new Float32Array(0), new Float32Array(0)],\n        [new Int32Array(0), new Int32Array(0)],\n        [new Int32Array([1, 2, 3]), new Int32Array([1, 2, 3])],\n        [[1, 2, 3], [1, 2, 3]],\n        [[1, 4, 3], [1, 4, 3]],\n        [{}, {}],\n        [{0: {}}, {0: {}}],\n        [{a: 2}, {a: 2}],\n        [new Map(), new Map()],\n        [new Map([[1, 2]]), new Map([[1, 2]])],\n        [new Map([[1, 3]]), new Map([[1, 3]])],\n        [new Map([[3, 2]]), new Map([[3, 2]])],\n        [new Map([[2, 1]]), new Map([[2, 1]])],\n        [new Map([[\"2\", 1]]), new Map([[\"2\", 1]])],\n        [new Map([[1, 2], [\"a\", 2]]), new Map([[\"a\", 2], [1, 2]])],\n        [new Set(), new Set()],\n        [new Set([\"a\"]), new Set([\"a\"])],\n        [new Set([\"b\"]), new Set([\"b\"])],\n        [new Set([2, \"a\"]), new Set([\"a\", 2])],\n        [new SomeIterable(), new SomeIterable()],\n        [new EmptyClass(), new EmptyClass()],\n        [new EmptyClass2(), new EmptyClass2()],\n        [new PropClass(1), new PropClass(1)],\n        [new PropClass(2), new PropClass(2)],\n        [Symbol(\"a\")],\n        [new First(1, 2), new First(1, 3), new First(1, 2), new First(1, 3)],\n        [new First(2, 2), new First(2, 3), new First(2, 2), new First(2, 3)],\n        [\n            {frump: new Map([[\"trump\", [1, new Set([2, \"a\"]), new Float32Array(5)]]])},\n            {frump: new Map([[\"trump\", [1, new Set([2, \"a\"]), new Float32Array(5)]]])}\n        ]\n    ];\n\n    assertThat(equate(1, 1)).isEqualTo(true);\n    assertThat(equate(1, 2)).isEqualTo(false);\n\n    for (let g1 of groups) {\n        for (let g2 of groups) {\n            for (let e1 of g1) {\n                for (let e2 of g2) {\n                    let actual = equate(e1, e2);\n                    let expected = g1 === g2;\n                    let eq = expected ? \"equal\" : \"NOT equal\";\n                    if (actual !== expected) {\n                        // Note: not using assertThat because assertThat's correctness depends on equate\n                        throw new Error(`Expected <${describe(e1)}> to ${eq} <${describe(e2)}>.`);\n                    }\n                }\n            }\n        }\n    }\n});\n"
  },
  {
    "path": "glue/crumble/base/history_pusher.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @return {!boolean}\n */\nfunction shouldControlURL() {\n    try {\n        return window.self === window.top;\n    } catch (_) {\n        return false;\n    }\n}\n\n/**\n * Manages interactions with the browser's history as the app's state changes and frequently updates the URL.\n */\nclass HistoryPusher {\n    constructor() {\n        /**\n         * @type {!boolean}\n         * @private\n         */\n        this._historyActionsNotWorking = false;\n        /**\n         * @type {undefined|*}\n         * @private\n         */\n        this._currentMemorableStateObj = undefined;\n    }\n\n    /**\n     * Indicates that the current state should be preserved in the browser history if the user transitions away from it.\n     *\n     * Because the state isn't known, any transition will trigger the preservation (possibly creating a duplicate\n     * history entry).\n     */\n    currentStateIsMemorableButUnknown() {\n        this._currentMemorableStateObj = {wont_equal_this: true};\n    }\n\n    /**\n     * Indicates that the current state should be preserved in the browser history if the user transitions away from it.\n     * @param {*} stateObj An ===-able object representing the current state, for identifying spurious transitions.\n     */\n    currentStateIsMemorableAndEqualTo(stateObj) {\n        this._currentMemorableStateObj = stateObj;\n    }\n\n    /**\n     * Indicates that the current state should not be preserved in the browser history if the user transitions away.\n     * States are not-memorable by default.\n     */\n    currentStateIsNotMemorable() {\n        this._currentMemorableStateObj = undefined;\n    }\n\n    /**\n     * @param {*} stateObj An equatable (by ===) object representing the latest state.\n     * @param {!string} stateUrlHash A document.location.hash value that will lead to the latest state.\n     */\n    stateChange(stateObj, stateUrlHash) {\n        if (!stateUrlHash.startsWith('#')) {\n            throw new Error(`\"Expected a hash URL: ${{stateObj, stateUrlHash}}`);\n        }\n        if (!shouldControlURL()) {\n            return;\n        }\n        if (this._currentMemorableStateObj === stateObj) {\n            return;\n        }\n        if (this._historyActionsNotWorking) {\n            // This is worse than using the history API, since it inserts junk after every state change, but it's also\n            // better than just randomly losing the circuit.\n            document.location.hash = stateUrlHash;\n            return;\n        }\n\n        try {\n            // 'Memorable' states should stay in the history instead of being replaced.\n            if (this._currentMemorableStateObj === undefined) {\n                history.replaceState(stateObj, \"\", stateUrlHash);\n            } else {\n                history.pushState(stateObj, \"\", stateUrlHash);\n                this._currentMemorableStateObj = undefined;\n            }\n        } catch (ex) {\n            // E.g. this happens when running from the filesystem due to same-origin constraints.\n            console.warn(\n                \"Calling 'history.replaceState/pushState' failed. Falling back to setting location.hash.\",\n                ex);\n            this._historyActionsNotWorking = true;\n            document.location.hash = stateUrlHash;\n        }\n    }\n}\n\nexport {HistoryPusher}\n"
  },
  {
    "path": "glue/crumble/base/obs.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {CooldownThrottle} from \"./cooldown_throttle.js\"\n\n/**\n * An observable sequence of events.\n *\n * WARNING: this class is not written to be re-entrant safe! If an observable ends up triggering itself, there may be\n * unexpected bugs.\n */\nclass Observable {\n    /**\n     * @param {!function(!function(T):void): (!function():void)} subscribe\n     * @template T\n     */\n    constructor(subscribe) {\n        /**\n         * @type {!(function(!(function(T): void)): !(function(): void))}\n         * @template T\n         * @private\n         */\n        this._subscribe = subscribe;\n    }\n\n    /**\n     * @param {!function(T):void} observer\n     * @returns {!function():void} unsubscriber\n     * @template T\n     */\n    subscribe(observer) {\n        return this._subscribe(observer);\n    }\n\n    /**\n     * @param {T} items\n     * @returns {!Observable.<T>} An observable that immediately forwards all the given items to any new subscriber.\n     * @template T\n     */\n    static of(...items) {\n        return new Observable(observer => {\n            for (let item of items) {\n                observer(item);\n            }\n            return () => {};\n        });\n    }\n\n    /**\n     * Subscribes to the receiving observable for a moment and returns any collected items.\n     * @returns {!Array.<T>}\n     * @template T\n     */\n    snapshot() {\n        let result = [];\n        let unsub = this.subscribe(e => result.push(e));\n        unsub();\n        return result;\n    }\n\n    /**\n     * @param {!function(TIn) : TOut} transformFunc\n     * @returns {!Observable.<TOut>} An observable with the same items, but transformed by the given function.\n     * @template TIn, TOut\n     */\n    map(transformFunc) {\n        return new Observable(observer => this.subscribe(item => observer(transformFunc(item))));\n    }\n\n    /**\n     * @param {!function(T) : !boolean} predicate\n     * @returns {!Observable.<T>} An observable with the same items, but skipping items that don't match the predicate.\n     * @template T\n     */\n    filter(predicate) {\n        return new Observable(observer => this.subscribe(item => { if (predicate(item)) { observer(item); }}));\n    }\n\n    /**\n     * @param {!Observable.<T2>} other\n     * @param {!function(T1, T2): TOut} mergeFunc\n     * @returns {!Observable.<TOut>}\n     * @template T1, T2, TOut\n     */\n    zipLatest(other, mergeFunc) {\n        return new Observable(observer => {\n            let has1 = false;\n            let has2 = false;\n            let last1;\n            let last2;\n            let unreg1 = this.subscribe(e1 => {\n                last1 = e1;\n                has1 = true;\n                if (has2) {\n                    observer(mergeFunc(last1, last2));\n                }\n            });\n            let unreg2 = other.subscribe(e2 => {\n                last2 = e2;\n                has2 = true;\n                if (has1) {\n                    observer(mergeFunc(last1, last2));\n                }\n            });\n            return () => { unreg1(); unreg2(); };\n        });\n    }\n\n    /**\n     * Returns an observable that keeps requesting animations frame callbacks and calling observers when they arrive.\n     * @returns {!Observable.<undefined>}\n     */\n    static requestAnimationTicker() {\n        return new Observable(observer => {\n            let iter;\n            let isDone = false;\n            iter = () => {\n                if (!isDone) {\n                    observer(undefined);\n                    window.requestAnimationFrame(iter);\n                }\n            };\n            iter();\n            return () => { isDone = true; };\n        });\n    }\n\n    /**\n     * @returns {!Observable.<T>} An observable that subscribes to each sub-observables arriving on this observable\n     * in turns, only forwarding items from the latest sub-observable.\n     * @template T\n     */\n    flattenLatest() {\n        return new Observable(observer => {\n            let unregLatest = () => {};\n            let isDone = false;\n            let unregAll = this.subscribe(subObservable => {\n                if (isDone) {\n                    return;\n                }\n                let prevUnreg = unregLatest;\n                unregLatest = subObservable.subscribe(observer);\n                prevUnreg();\n            });\n            return () => {\n                isDone = true;\n                unregLatest();\n                unregAll();\n            }\n        });\n    }\n\n    /**\n     * @param {!function(T):void} action\n     * @returns {!Observable.<T>}\n     * @template T\n     */\n    peek(action) {\n        return this.map(e => { action(e); return e; });\n    }\n\n    /**\n     * @returns {!Observable.<T>} An observable that forwards all the items from all the observables observed by the\n     * receiving observable of observables.\n     * @template T\n     */\n    flatten() {\n        return new Observable(observer => {\n            let unsubs = [];\n            unsubs.push(this.subscribe(observable => unsubs.push(observable.subscribe(observer))));\n            return () => {\n                for (let unsub of unsubs) {\n                    unsub()\n                }\n            }\n        });\n    }\n\n    /**\n     * Starts a timer after each completed send, delays sending any more values until the timer expires, and skips\n     * intermediate values when a newer value arrives from the source while the timer is still running down.\n     * @param {!number} cooldownMillis\n     * @returns {!Observable.<T>}\n     * @template T\n     */\n    throttleLatest(cooldownMillis) {\n        return new Observable(observer => {\n            let latest = undefined;\n            let isKilled = false;\n            let throttle = new CooldownThrottle(() => {\n                if (!isKilled) {\n                    observer(latest);\n                }\n            }, cooldownMillis);\n            let unsub = this.subscribe(e => {\n                latest = e;\n                throttle.trigger();\n            });\n            return () => {\n                isKilled = true;\n                unsub();\n            };\n        });\n    }\n\n    /**\n     * @param {!HTMLElement|!HTMLDocument} element\n     * @param {!string} eventKey\n     * @returns {!Observable.<*>} An observable corresponding to an event fired from an element.\n     */\n    static elementEvent(element, eventKey) {\n        return new Observable(observer => {\n            element.addEventListener(eventKey, observer);\n            return () => element.removeEventListener(eventKey, observer);\n        });\n    }\n\n    /**\n     *\n     * @param {!int} count\n     * @returns {!Observable.<T>}\n     * @template T\n     */\n    skip(count) {\n        return new Observable(observer => {\n            let remaining = count;\n            return this.subscribe(item => {\n                if (remaining > 0) {\n                    remaining -= 1;\n                } else {\n                    observer(item);\n                }\n            })\n        })\n    }\n\n    /**\n     * @returns {!Observable.<T>} An observable with the same events, but filtering out any event value that's the same\n     * as the previous one.\n     * @template T\n     */\n    whenDifferent(equater = undefined) {\n        let eq = equater || ((e1, e2) => e1 === e2);\n        return new Observable(observer => {\n            let hasLast = false;\n            let last = undefined;\n            return this.subscribe(item => {\n                if (!hasLast || !eq(last, item)) {\n                    last = item;\n                    hasLast = true;\n                    observer(item);\n                }\n            });\n        });\n    }\n}\n\nclass ObservableSource {\n    constructor() {\n        /**\n         * @type {!Array.<!function(T):void>}\n         * @private\n         * @template T\n         */\n        this._observers = [];\n        /**\n         * @type {!Observable.<T>}\n         * @private\n         * @template T\n         */\n        this._observable = new Observable(observer => {\n            this._observers.push(observer);\n            let didRun = false;\n            return () => {\n                if (!didRun) {\n                    didRun = true;\n                    this._observers.splice(this._observers.indexOf(observer), 1);\n                }\n            };\n        });\n    }\n\n    /**\n     * @returns {!Observable.<T>}\n     * @template T\n     */\n    observable() {\n        return this._observable;\n    }\n\n    /**\n     * @param {T} eventValue\n     * @template T\n     */\n    send(eventValue) {\n        for (let obs of this._observers) {\n            obs(eventValue);\n        }\n    }\n}\n\nclass ObservableValue {\n    /**\n     * @param {T=undefined} initialValue\n     * @template T\n     */\n    constructor(initialValue=undefined) {\n        this._value = initialValue;\n        this._source = new ObservableSource();\n        this._observable = new Observable(observer => {\n            observer(this._value);\n            return this._source.observable().subscribe(observer);\n        });\n    }\n\n    /**\n     * @returns {!Observable}\n     */\n    observable() {\n        return this._observable;\n    }\n\n    /**\n     * @param {T} newValue\n     * @template T\n     */\n    set(newValue) {\n        this._value = newValue;\n        this._source.send(newValue);\n    }\n\n    /**\n     * @returns {T} The current value.\n     * @template T\n     */\n    get() {\n        return this._value;\n    }\n}\n\nexport {Observable, ObservableSource, ObservableValue}\n"
  },
  {
    "path": "glue/crumble/base/obs.test.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {assertThat, test} from \"../test/test_util.js\"\nimport {Observable, ObservableValue, ObservableSource} from \"./obs.js\"\n\nlet record = observable => {\n    let out = [];\n    let stop = observable.subscribe(e => out.push(e));\n    return {out, stop};\n};\n\ntest(\"Observable.of\", () => {\n    assertThat(record(Observable.of()).out).isEqualTo([]);\n    assertThat(record(Observable.of(1, 2, 3)).out).isEqualTo([1, 2, 3]);\n});\n\ntest(\"Observable.snapshot\", () => {\n    assertThat(Observable.of().snapshot()).isEqualTo([]);\n    assertThat(Observable.of(1, 2, 3).snapshot()).isEqualTo([1, 2, 3]);\n});\n\ntest(\"Observable.map\", () => {\n    assertThat(Observable.of(1, 2, 3).map(e => e * 2).snapshot()).isEqualTo([2, 4, 6]);\n});\n\ntest(\"Observable.filter\", () => {\n    assertThat(Observable.of(1, 2, 3).filter(e => e !== 2).snapshot()).isEqualTo([1, 3]);\n});\n\ntest(\"Observable.zipLatest\", () => {\n    let v1 = new ObservableSource();\n    let v2 = new ObservableSource();\n    let seen = [];\n    let unreg = v1.observable().zipLatest(v2.observable(), (e1, e2) => e1 + e2).subscribe(e => seen.push(e));\n\n    assertThat(seen).isEqualTo([]);\n    v1.send(1);\n    assertThat(seen).isEqualTo([]);\n    v1.send(2);\n    assertThat(seen).isEqualTo([]);\n    v2.send(10);\n    assertThat(seen).isEqualTo([12]);\n    v1.send(3);\n    assertThat(seen).isEqualTo([12, 13]);\n    v1.send(4);\n    assertThat(seen).isEqualTo([12, 13, 14]);\n    v2.send(20);\n    assertThat(seen).isEqualTo([12, 13, 14, 24]);\n    unreg();\n    v2.send(30);\n    assertThat(seen).isEqualTo([12, 13, 14, 24]);\n});\n\ntest(\"Observable.flattenLatest\", () => {\n    let c = new ObservableSource();\n    let v1 = new ObservableSource();\n    let v2 = new ObservableSource();\n    let v3 = new ObservableSource();\n    let seen = [];\n    let unreg = c.observable().flattenLatest().subscribe(e => seen.push(e));\n\n    assertThat(seen).isEqualTo([]);\n    c.send(v1.observable());\n    assertThat(seen).isEqualTo([]);\n    v1.send(1);\n    assertThat(seen).isEqualTo([1]);\n    v1.send(2);\n    assertThat(seen).isEqualTo([1, 2]);\n    c.send(v2.observable());\n    assertThat(seen).isEqualTo([1, 2]);\n    v1.send(3);\n    assertThat(seen).isEqualTo([1, 2]);\n    v2.send(4);\n    assertThat(seen).isEqualTo([1, 2, 4]);\n    c.send(v1.observable());\n    c.send(v2.observable());\n    c.send(v3.observable());\n    assertThat(seen).isEqualTo([1, 2, 4]);\n    v1.send(5);\n    v2.send(6);\n    v3.send(7);\n    assertThat(seen).isEqualTo([1, 2, 4, 7]);\n    unreg();\n    v1.send(8);\n    v2.send(9);\n    v3.send(10);\n    assertThat(seen).isEqualTo([1, 2, 4, 7]);\n});\n\ntest(\"Observable.whenDifferent\", () => {\n    assertThat(Observable.of(1, 2, 2, 3).whenDifferent().snapshot()).isEqualTo([1, 2, 3]);\n    assertThat(Observable.of(undefined, 2, 2, 3).whenDifferent().snapshot()).isEqualTo([undefined, 2, 3]);\n    assertThat(Observable.of(2, 3, 5, 7, 10, 13, 17, 19, 23).whenDifferent((e1, e2) => e1 % 3 === e2 % 3).snapshot()).\n        isEqualTo([2, 3, 5, 7, 17, 19, 23]);\n});\n\ntest(\"Observable.skip\", () => {\n    assertThat(Observable.of(1, 2, 3).skip(0).snapshot()).isEqualTo([1, 2, 3]);\n    assertThat(Observable.of(1, 2, 3).skip(1).snapshot()).isEqualTo([2, 3]);\n    assertThat(Observable.of(1, 2, 3).skip(2).snapshot()).isEqualTo([3]);\n    assertThat(Observable.of(1, 2, 3).skip(3).snapshot()).isEqualTo([]);\n    assertThat(Observable.of(1, 2, 3).skip(5).snapshot()).isEqualTo([]);\n});\n\ntest(\"Observable.flatten\", () => {\n    assertThat(Observable.of(\n        Observable.of(1, 2, 3),\n        Observable.of(4, 5, 6),\n        Observable.of(7, 8)).flatten().snapshot()).isEqualTo([1, 2, 3, 4, 5, 6, 7, 8]);\n\n    let v1 = new ObservableSource();\n    let v2 = new ObservableSource();\n    let c = new ObservableSource();\n    let {out, stop} = record(c.observable().flatten());\n    assertThat(out).isEqualTo([]);\n    c.send(v1.observable());\n    assertThat(out).isEqualTo([]);\n    v1.send('a');\n    assertThat(out).isEqualTo(['a']);\n    c.send(v2.observable());\n    assertThat(out).isEqualTo(['a']);\n    c.send(v2.observable());\n    assertThat(out).isEqualTo(['a']);\n    v2.send('b');\n    assertThat(out).isEqualTo(['a', 'b', 'b']);\n    stop();\n    v1.send('c');\n    v2.send('c');\n    c.send(new ObservableValue('c').observable());\n    assertThat(out).isEqualTo(['a', 'b', 'b']);\n});\n\ntest(\"ObservableValue_setVsGet\", () => {\n    let v = new ObservableValue('a');\n    assertThat(v.get()).isEqualTo('a');\n    v.set('b');\n    assertThat(v.get()).isEqualTo('b');\n});\n\ntest(\"ObservableValue_observable\", () => {\n    let v = new ObservableValue('a');\n    let {out, stop} = record(v.observable());\n    assertThat(out).isEqualTo(['a']);\n    v.set('b');\n    assertThat(out).isEqualTo(['a', 'b']);\n    v.set('c');\n    assertThat(out).isEqualTo(['a', 'b', 'c']);\n    stop();\n    v.set('d');\n    assertThat(out).isEqualTo(['a', 'b', 'c']);\n});\n\ntest(\"ObservableValue_observable_multiple\", () => {\n    let v = new ObservableValue('a');\n    let {out: out1, stop: stop1} = record(v.observable());\n    let {out: out2, stop: stop2} = record(v.observable());\n    assertThat(out1).isEqualTo(['a']);\n    assertThat(out2).isEqualTo(['a']);\n    stop2();\n    assertThat(out1).isEqualTo(['a']);\n    assertThat(out2).isEqualTo(['a']);\n    v.set('b');\n    assertThat(out1).isEqualTo(['a', 'b']);\n    assertThat(out2).isEqualTo(['a']);\n    stop1();\n    assertThat(out1).isEqualTo(['a', 'b']);\n    assertThat(out2).isEqualTo(['a']);\n});\n\ntest(\"ObservableSource_observable\", () => {\n    let v = new ObservableSource();\n    let {out, stop} = record(v.observable());\n    assertThat(out).isEqualTo([]);\n    v.send('b');\n    assertThat(out).isEqualTo(['b']);\n    v.send('c');\n    assertThat(out).isEqualTo(['b', 'c']);\n    stop();\n    v.send('d');\n    assertThat(out).isEqualTo(['b', 'c']);\n});\n\ntest(\"Observable.observable_multiple\", () => {\n    let v = new ObservableSource();\n    let {out: out1, stop: stop1} = record(v.observable());\n    let {out: out2, stop: stop2} = record(v.observable());\n    assertThat(out1).isEqualTo([]);\n    assertThat(out2).isEqualTo([]);\n    v.send('a');\n    assertThat(out1).isEqualTo(['a']);\n    assertThat(out2).isEqualTo(['a']);\n    stop2();\n    assertThat(out1).isEqualTo(['a']);\n    assertThat(out2).isEqualTo(['a']);\n    v.send('b');\n    assertThat(out1).isEqualTo(['a', 'b']);\n    assertThat(out2).isEqualTo(['a']);\n    stop1();\n    assertThat(out1).isEqualTo(['a', 'b']);\n    assertThat(out2).isEqualTo(['a']);\n});\n\ntest(\"Observable.peek\", () => {\n    let a = [];\n    let v = new ObservableSource();\n    v.observable().peek(e => a.push(e)).subscribe(() => {});\n    assertThat(a).isEqualTo([]);\n    v.send(2);\n    assertThat(a).isEqualTo([2]);\n});\n"
  },
  {
    "path": "glue/crumble/base/revision.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {describe} from \"./describe.js\"\nimport {equate} from \"./equate.js\"\nimport {ObservableSource, ObservableValue} from \"./obs.js\"\n\n/**\n * A simple linear revision history tracker, for supporting undo and redo functionality.\n */\nclass Revision {\n    /**\n     * @param {!Array.<*>} history\n     * @param {!int} index\n     * @param {!boolean} isWorkingOnCommit\n     */\n    constructor(history, index, isWorkingOnCommit) {\n        if (index < 0 || index >= history.length) {\n            throw new Error(`Bad index: ${{history, index, isWorkingOnCommit}}`);\n        }\n        if (!Array.isArray(history)) {\n            throw new Error(`Bad history: ${{history, index, isWorkingOnCommit}}`);\n        }\n\n        /** @type {!Array.<*>} */\n        this.history = history;\n        /** @type {!int} */\n        this.index = index;\n        /** @type {!boolean} */\n        this.isWorkingOnCommit = isWorkingOnCommit;\n        /** @type {!ObservableSource} */\n        this._changes = new ObservableSource();\n        /** @type {!ObservableValue} */\n        this._latestActiveCommit = new ObservableValue(this.history[this.index]);\n    }\n\n    /**\n     * @returns {!Observable.<*>}\n     */\n    changes() {\n        return this._changes.observable();\n    }\n\n    /**\n     * @returns {!Observable.<*>}\n     */\n    latestActiveCommit() {\n        return this._latestActiveCommit.observable();\n    }\n\n    /**\n     * Returns a snapshot of the current commit.\n     * @returns {*}\n     */\n    peekActiveCommit() {\n        return this._latestActiveCommit.get();\n    }\n\n    /**\n     * Returns a cleared revision history, starting at the given state.\n     * @param {*} state\n     */\n    static startingAt(state) {\n        return new Revision([state], 0, false);\n    }\n\n    /**\n     * @returns {!boolean}\n     */\n    isAtBeginningOfHistory() {\n        return this.index === 0 && !this.isWorkingOnCommit;\n    }\n\n    /**\n     * @returns {!boolean}\n     */\n    isAtEndOfHistory() {\n        return this.index === this.history.length - 1;\n    }\n\n    /**\n     * Throws away all revisions and resets the given state.\n     * @param {*} state\n     * @returns {void}\n     */\n    clear(state) {\n        this.history = [state];\n        this.index = 0;\n        this.isWorkingOnCommit = false;\n        this._latestActiveCommit.set(state);\n        this._changes.send(state);\n    }\n\n    /**\n     * Indicates that there are pending changes, so that a following 'undo' will return to the current state instead of\n     * the previous state.\n     * @returns {void}\n     */\n    startedWorkingOnCommit(newCheckpoint) {\n        this.isWorkingOnCommit = newCheckpoint !== this.history[this.index];\n        this._changes.send(undefined);\n    }\n\n    /**\n     * Indicates that pending changes were discarded, so that a following 'undo' should return to the previous state\n     * instead of the current state.\n     * @returns {*} The new current state.\n     */\n    cancelCommitBeingWorkedOn() {\n        this.isWorkingOnCommit = false;\n        let result = this.history[this.index];\n        this._latestActiveCommit.set(result);\n        this._changes.send(result);\n        return result;\n    }\n\n    /**\n     * Throws away future states, appends the given state, and marks it as the current state\n     * @param {*} newCheckpoint\n     * @returns {void}\n     */\n    commit(newCheckpoint) {\n        if (newCheckpoint === this.history[this.index]) {\n            this.cancelCommitBeingWorkedOn();\n            return;\n        }\n        this.isWorkingOnCommit = false;\n        this.index += 1;\n        this.history.splice(this.index, this.history.length - this.index);\n        this.history.push(newCheckpoint);\n        this._latestActiveCommit.set(newCheckpoint);\n        this._changes.send(newCheckpoint);\n    }\n\n    /**\n     * Marks the previous state as the current state and returns it (or resets to the current state if\n     * 'working on a commit' was indicated).\n     * @returns {undefined|*} The new current state, or undefined if there's nothing to undo.\n     */\n    undo() {\n        if (!this.isWorkingOnCommit) {\n            if (this.index === 0) {\n                return undefined;\n            }\n            this.index -= 1;\n        }\n        this.isWorkingOnCommit = false;\n        let result = this.history[this.index];\n        this._latestActiveCommit.set(result);\n        this._changes.send(result);\n        return result;\n    }\n\n    /**\n     * Marks the next state as the current state and returns it (or does nothing if there is no next state).\n     * @returns {undefined|*} The new current state, or undefined if there's nothing to redo.\n     */\n    redo() {\n        if (this.index + 1 === this.history.length) {\n            return undefined;\n        }\n        this.index += 1;\n        this.isWorkingOnCommit = false;\n        let result = this.history[this.index];\n        this._latestActiveCommit.set(result);\n        this._changes.send(result);\n        return result;\n    }\n\n    /**\n     * @returns {!string} A description of the revision.\n     */\n    toString() {\n        return 'Revision(' + describe({\n            index: this.index,\n            count: this.history.length,\n            workingOnCommit: this.isWorkingOnCommit,\n            head: this.history[this.index]\n        }) + ')';\n    }\n\n    /**\n     * Determines if two revisions currently have the same state.\n     * @param {*|!Revision} other\n     * @returns {!boolean}\n     */\n    isEqualTo(other) {\n        return other instanceof Revision &&\n            this.index === other.index &&\n            this.isWorkingOnCommit === other.isWorkingOnCommit &&\n            equate(this.history, other.history);\n    }\n}\n\nexport {Revision}\n"
  },
  {
    "path": "glue/crumble/base/revision.test.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {assertThat, test} from \"../test/test_util.js\"\nimport {Revision} from \"./revision.js\"\n\ntest(\"Revision.constructor_isEqualTo\", () => {\n    assertThat(() => new Revision([], 0, false)).throwsAnExceptionThat().matches(/Bad index/);\n    assertThat(() => new Revision([\"a\"], -1, false)).throwsAnExceptionThat().matches(/Bad index/);\n    assertThat(() => new Revision([\"a\"], 1, false)).throwsAnExceptionThat().matches(/Bad index/);\n    assertThat(() => new Revision([\"a\", \"b\"], 2, false)).throwsAnExceptionThat().matches(/Bad index/);\n\n    let r = new Revision([\"a\", \"b\", \"c\"], 1, true);\n    assertThat(r).isEqualTo(new Revision([\"a\", \"b\", \"c\"], 1, true));\n    assertThat(r).isNotEqualTo(new Revision([\"a\", \"b\"], 1, true));\n    assertThat(r).isNotEqualTo(new Revision([\"a\", \"b\", \"d\"], 1, true));\n    assertThat(r).isNotEqualTo(new Revision([\"a\", \"b\", \"c\"], 2, true));\n    assertThat(r).isNotEqualTo(new Revision([\"a\", \"b\", \"c\"], 1, false));\n    assertThat(r).isNotEqualTo(undefined);\n    assertThat(r).isNotEqualTo(5);\n\n    let groups = [\n        [\n            new Revision([\"a\"], 0, false),\n            new Revision([\"a\"], 0, false)\n        ],\n        [\n            new Revision([\"a\"], 0, true),\n            new Revision([\"a\"], 0, true)\n        ],\n        [\n            new Revision([\"a\", \"b\"], 0, false),\n            new Revision([\"a\", \"b\"], 0, false)\n        ],\n        [\n            new Revision([\"b\", \"a\"], 0, false),\n            new Revision([\"b\", \"a\"], 0, false)\n        ],\n        [\n            new Revision([\"b\", \"a\"], 1, false),\n            new Revision([\"b\", \"a\"], 1, false)\n        ]\n    ];\n    for (let g1 of groups) {\n        for (let g2 of groups) {\n            for (let e1 of g1) {\n                for (let e2 of g2) {\n                    if (g1 === g2) {\n                        assertThat(e1).isEqualTo(e2);\n                    } else {\n                        assertThat(e1).isNotEqualTo(e2);\n                    }\n                }\n            }\n        }\n    }\n});\n\ntest(\"Revision.toString_exists\", () => {\n    assertThat(new Revision([\"a\", \"b\"], 1, false).toString()).isNotEqualTo(undefined);\n});\n\ntest(\"Revision.startingAt\", () => {\n    assertThat(Revision.startingAt(\"abc\")).isEqualTo(new Revision([\"abc\"], 0, false));\n});\n\ntest(\"Revision.clear\", () => {\n    let r;\n\n    r = new Revision([\"abc\"], 0, false);\n    r.clear(\"xyz\");\n    assertThat(r).isEqualTo(new Revision([\"xyz\"], 0, false));\n\n    r = new Revision([\"r\", \"s\", \"t\"], 2, true);\n    r.clear(\"wxyz\");\n    assertThat(r).isEqualTo(new Revision([\"wxyz\"], 0, false));\n});\n\ntest(\"Revision.undo\", () => {\n    let r;\n\n    r = new Revision([\"abc\"], 0, false);\n    assertThat(r.undo()).isEqualTo(undefined);\n    assertThat(r).isEqualTo(new Revision([\"abc\"], 0, false));\n\n    r = new Revision([\"abc\", \"def\"], 0, false);\n    assertThat(r.undo()).isEqualTo(undefined);\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 0, false));\n\n    r = new Revision([\"abc\", \"def\"], 0, true);\n    assertThat(r.undo()).isEqualTo(\"abc\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 0, false));\n\n    r = new Revision([\"abc\", \"def\"], 1, false);\n    assertThat(r.undo()).isEqualTo(\"abc\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 0, false));\n\n    r = new Revision([\"abc\", \"def\"], 1, true);\n    assertThat(r.undo()).isEqualTo(\"def\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, false));\n\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 2, true).undo()).isEqualTo(\"xyz\");\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 2, false).undo()).isEqualTo(\"def\");\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 1, true).undo()).isEqualTo(\"def\");\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 1, false).undo()).isEqualTo(\"abc\");\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 0, true).undo()).isEqualTo(\"abc\");\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 0, false).undo()).isEqualTo(undefined);\n});\n\ntest(\"Revision.isAtBeginningOfHistory\", () => {\n    assertThat(new Revision([\"abc\"], 0, false).isAtBeginningOfHistory()).isEqualTo(true);\n    assertThat(new Revision([\"abc\"], 0, true).isAtBeginningOfHistory()).isEqualTo(false);\n\n    assertThat(new Revision([\"abc\", \"123\"], 0, false).isAtBeginningOfHistory()).isEqualTo(true);\n    assertThat(new Revision([\"abc\", \"123\"], 0, true).isAtBeginningOfHistory()).isEqualTo(false);\n    assertThat(new Revision([\"abc\", \"123\"], 1, false).isAtBeginningOfHistory()).isEqualTo(false);\n    assertThat(new Revision([\"abc\", \"123\"], 1, true).isAtBeginningOfHistory()).isEqualTo(false);\n});\n\ntest(\"Revision.isAtEndOfHistory\", () => {\n    assertThat(new Revision([\"abc\"], 0, false).isAtEndOfHistory()).isEqualTo(true);\n    assertThat(new Revision([\"abc\"], 0, true).isAtEndOfHistory()).isEqualTo(true);\n\n    assertThat(new Revision([\"abc\", \"123\"], 0, false).isAtEndOfHistory()).isEqualTo(false);\n    assertThat(new Revision([\"abc\", \"123\"], 0, true).isAtEndOfHistory()).isEqualTo(false);\n    assertThat(new Revision([\"abc\", \"123\"], 1, false).isAtEndOfHistory()).isEqualTo(true);\n    assertThat(new Revision([\"abc\", \"123\"], 1, true).isAtEndOfHistory()).isEqualTo(true);\n});\n\ntest(\"Revision.redo\", () => {\n    let r;\n\n    r = new Revision([\"abc\"], 0, false);\n    assertThat(r.redo()).isEqualTo(undefined);\n    assertThat(r).isEqualTo(new Revision([\"abc\"], 0, false));\n\n    r = new Revision([\"abc\", \"def\"], 0, false);\n    assertThat(r.redo()).isEqualTo(\"def\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, false));\n\n    r = new Revision([\"abc\", \"def\"], 0, true);\n    assertThat(r.redo()).isEqualTo(\"def\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, false));\n\n    r = new Revision([\"abc\", \"def\"], 1, false);\n    assertThat(r.redo()).isEqualTo(undefined);\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, false));\n\n    // Redo-ing when working on a commit with no future state shouldn't lose the in-progress work.\n    r = new Revision([\"abc\", \"def\"], 1, true);\n    assertThat(r.redo()).isEqualTo(undefined);\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, true));\n\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 0, false).redo()).isEqualTo(\"def\");\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 0, true).redo()).isEqualTo(\"def\");\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 1, false).redo()).isEqualTo(\"xyz\");\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 1, true).redo()).isEqualTo(\"xyz\");\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 2, false).redo()).isEqualTo(undefined);\n    assertThat(new Revision([\"abc\", \"def\", \"xyz\"], 2, true).redo()).isEqualTo(undefined);\n});\n\ntest(\"Revision.startedWorkingOnCommit\", () => {\n    let r;\n\n    r = new Revision([\"abc\"], 0, false);\n    r.startedWorkingOnCommit();\n    assertThat(r).isEqualTo(new Revision([\"abc\"], 0, true));\n    r.startedWorkingOnCommit();\n    assertThat(r).isEqualTo(new Revision([\"abc\"], 0, true));\n\n    r = new Revision([\"abc\", \"def\"], 0, false);\n    r.startedWorkingOnCommit();\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 0, true));\n    r.startedWorkingOnCommit();\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 0, true));\n\n    r = new Revision([\"abc\", \"def\"], 1, false);\n    r.startedWorkingOnCommit();\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, true));\n    r.startedWorkingOnCommit();\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, true));\n});\n\ntest(\"Revision.cancelCommitBeingWorkedOn\", () => {\n    let r;\n\n    r = new Revision([\"abc\"], 0, true);\n    r.cancelCommitBeingWorkedOn();\n    assertThat(r).isEqualTo(new Revision([\"abc\"], 0, false));\n    r.cancelCommitBeingWorkedOn();\n    assertThat(r).isEqualTo(new Revision([\"abc\"], 0, false));\n\n    r = new Revision([\"abc\", \"def\"], 0, true);\n    r.cancelCommitBeingWorkedOn();\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 0, false));\n    r.cancelCommitBeingWorkedOn();\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 0, false));\n\n    r = new Revision([\"abc\", \"def\"], 1, true);\n    r.cancelCommitBeingWorkedOn();\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, false));\n    r.cancelCommitBeingWorkedOn();\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, false));\n});\n\ntest(\"Revision.commit\", () => {\n    let r;\n\n    r = new Revision([\"abc\"], 0, false);\n    r.commit(\"def\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, false));\n    r.commit(\"xyz\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\", \"xyz\"], 2, false));\n\n    r = new Revision([\"abc\"], 0, true);\n    r.commit(\"def\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\"], 1, false));\n\n    r = new Revision([\"abc\", \"def\"], 0, true);\n    r.commit(\"xyz\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"xyz\"], 1, false));\n\n    r = new Revision([\"abc\", \"def\", \"so\", \"long\"], 1, true);\n    r.commit(\"t\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\", \"t\"], 2, false));\n\n    r = new Revision([\"abc\", \"def\", \"so\", \"long\"], 1, false);\n    r.commit(\"t\");\n    assertThat(r).isEqualTo(new Revision([\"abc\", \"def\", \"t\"], 2, false));\n});\n\ntest(\"Revision.changes\", () => {\n    let r = Revision.startingAt('abc');\n    let a = [];\n    let s = r.changes().subscribe(e => a.push(e));\n    assertThat(a).isEqualTo([]);\n    r.commit('123');\n    assertThat(a).isEqualTo(['123']);\n    r.undo();\n    assertThat(a).isEqualTo(['123', 'abc']);\n    r.undo();\n    assertThat(a).isEqualTo(['123', 'abc']);\n    r.redo();\n    assertThat(a).isEqualTo(['123', 'abc', '123']);\n    r.redo();\n    assertThat(a).isEqualTo(['123', 'abc', '123']);\n    r.startedWorkingOnCommit();\n    assertThat(a).isEqualTo(['123', 'abc', '123', undefined]);\n    r.cancelCommitBeingWorkedOn();\n    assertThat(a).isEqualTo(['123', 'abc', '123', undefined, '123']);\n    r.clear('xyz');\n    assertThat(a).isEqualTo(['123', 'abc', '123', undefined, '123', 'xyz']);\n    s();\n    r.clear('nope');\n    assertThat(a).isEqualTo(['123', 'abc', '123', undefined, '123', 'xyz']);\n});\n\ntest(\"Revision.latestActiveCommit\", () => {\n    let r = Revision.startingAt('abc');\n    let a = [];\n    let s = r.latestActiveCommit().subscribe(e => a.push(e));\n    assertThat(a).isEqualTo(['abc']);\n    r.commit('123');\n    assertThat(a).isEqualTo(['abc', '123']);\n    r.undo();\n    assertThat(a).isEqualTo(['abc', '123', 'abc']);\n    r.undo();\n    assertThat(a).isEqualTo(['abc', '123', 'abc']);\n    r.redo();\n    assertThat(a).isEqualTo(['abc', '123', 'abc', '123']);\n    r.redo();\n    assertThat(a).isEqualTo(['abc', '123', 'abc', '123']);\n    r.startedWorkingOnCommit();\n    assertThat(a).isEqualTo(['abc', '123', 'abc', '123']);\n    r.cancelCommitBeingWorkedOn();\n    assertThat(a).isEqualTo(['abc', '123', 'abc', '123', '123']);\n    r.clear('xyz');\n    assertThat(a).isEqualTo(['abc', '123', 'abc', '123', '123', 'xyz']);\n    s();\n    r.clear('nope');\n    assertThat(a).isEqualTo(['abc', '123', 'abc', '123', '123', 'xyz']);\n});\n"
  },
  {
    "path": "glue/crumble/base/seq.js",
    "content": "/**\n * @param {!Iterable<TItem> | !Iterator<TItem>}items\n * @param {!function(item: TItem): TKey} func\n * @returns {!Map<TKey, !Array<TItem>>}\n * @template TItem\n * @template TKey\n */\nfunction groupBy(items, func) {\n    let result = new Map();\n    for (let item of items) {\n        let key = func(item);\n        let group = result.get(key);\n        if (group === undefined) {\n            result.set(key, [item]);\n        } else {\n            group.push(item);\n        }\n    }\n    return result;\n}\n\nexport {groupBy};\n"
  },
  {
    "path": "glue/crumble/base/seq.test.js",
    "content": "import {assertThat, test} from \"../test/test_util.js\"\nimport {groupBy} from \"./seq.js\"\n\ntest(\"seq.groupBy\", () => {\n    assertThat(groupBy([], e => e)).isEqualTo(new Map([]))\n    assertThat(groupBy([2, 3, 5, 11, 15, 17, 2], e => e % 5)).isEqualTo(new Map([\n        [1, [11]],\n        [2, [2, 17, 2]],\n        [3, [3]],\n        [0, [5, 15]],\n    ]))\n});\n"
  },
  {
    "path": "glue/crumble/circuit/circuit.js",
    "content": "import {Operation} from \"./operation.js\"\nimport {GATE_ALIAS_MAP, GATE_MAP} from \"../gates/gateset.js\"\nimport {Layer} from \"./layer.js\"\nimport {make_mpp_gate, make_spp_gate} from '../gates/gateset_mpp.js';\nimport {describe} from \"../base/describe.js\";\n\n/**\n * @param {!string} targetText\n * @returns {!Array.<!string>}\n */\nfunction processTargetsTextIntoTargets(targetText) {\n    let targets = [];\n    let flush = () => {\n        if (curTarget !== '') {\n            targets.push(curTarget)\n            curTarget = '';\n        }\n    }\n    let curTarget = '';\n    for (let c of targetText) {\n        if (c === ' ') {\n            flush();\n        } else if (c === '*') {\n            flush();\n            targets.push('*');\n        } else {\n            curTarget += c;\n        }\n    }\n    flush();\n\n    return targets;\n}\n\n/**\n * @param {!Array.<!string>} targets\n * @returns {!Array.<!Array.<!string>>}\n */\nfunction splitUncombinedTargets(targets) {\n    let result = [];\n    let start = 0;\n    while (start < targets.length) {\n        let end = start + 1;\n        while (end < targets.length && targets[end] === '*') {\n            end += 2;\n        }\n        if (end > targets.length) {\n            throw Error(`Dangling combiner in ${targets}.`);\n        }\n        let term = [];\n        for (let k = start; k < end; k += 2) {\n            if (targets[k] === '*') {\n                if (k === 0) {\n                    throw Error(`Leading combiner in ${targets}.`);\n                }\n                throw Error(`Adjacent combiners in ${targets}.`);\n            }\n            term.push(targets[k]);\n        }\n        result.push(term);\n        start = end;\n    }\n    return result;\n}\n\n/**\n * @param {!string} tag\n * @param {!Float32Array} args\n * @param {!Array.<!string>} combinedTargets\n * @param {!boolean} convertIntoOtherGates\n * @returns {!Operation}\n */\nfunction simplifiedMPP(tag, args, combinedTargets, convertIntoOtherGates) {\n    let bases = '';\n    let qubits = [];\n    for (let t of combinedTargets) {\n        if (t[0] === '!') {\n            t = t.substring(1);\n        }\n        if (t[0] === 'X' || t[0] === 'Y' || t[0] === 'Z') {\n            bases += t[0];\n            let v = parseInt(t.substring(1));\n            if (v !== v) {\n                throw Error(`Non-Pauli target given to MPP: ${combinedTargets}`);\n            }\n            qubits.push(v);\n        } else {\n            throw Error(`Non-Pauli target given to MPP: ${combinedTargets}`);\n        }\n    }\n\n    let gate = undefined;\n    if (convertIntoOtherGates) {\n        gate = GATE_MAP.get('M' + bases);\n    }\n    if (gate === undefined) {\n        gate = GATE_MAP.get('MPP:' + bases);\n    }\n    if (gate === undefined) {\n        gate = make_mpp_gate(bases);\n    }\n    return new Operation(gate, tag, args, new Uint32Array(qubits));\n}\n\n/**\n * @param {!string} tag\n * @param {!Float32Array} args\n * @param {!boolean} dag\n * @param {!Array.<!string>} combinedTargets\n * @returns {!Operation}\n */\nfunction simplifiedSPP(tag, args, dag, combinedTargets) {\n    let bases = '';\n    let qubits = [];\n    for (let t of combinedTargets) {\n        if (t[0] === '!') {\n            t = t.substring(1);\n        }\n        if (t[0] === 'X' || t[0] === 'Y' || t[0] === 'Z') {\n            bases += t[0];\n            let v = parseInt(t.substring(1));\n            if (v !== v) {\n                throw Error(`Non-Pauli target given to SPP: ${combinedTargets}`);\n            }\n            qubits.push(v);\n        } else {\n            throw Error(`Non-Pauli target given to SPP: ${combinedTargets}`);\n        }\n    }\n\n    let gate = GATE_MAP.get((dag ? 'SPP_DAG:' : 'SPP:') + bases);\n    if (gate === undefined) {\n        gate = make_spp_gate(bases, dag);\n    }\n    return new Operation(gate, tag, args, new Uint32Array(qubits));\n}\n\n\nclass Circuit {\n    /**\n     * @param {!Float64Array} qubitCoordData\n     * @param {!Array<!Layer>} layers\n     */\n    constructor(qubitCoordData, layers = []) {\n        if (!(qubitCoordData instanceof Float64Array)) {\n            throw new Error('!(qubitCoords instanceof Float64Array)');\n        }\n        if (!Array.isArray(layers)) {\n            throw new Error('!Array.isArray(layers)');\n        }\n        if (!layers.every(e => e instanceof Layer)) {\n            throw new Error('!layers.every(e => e instanceof Layer)');\n        }\n        this.qubitCoordData = qubitCoordData;\n        this.layers = layers;\n    }\n\n    /**\n     * @param {!string} stimCircuit\n     * @returns {!Circuit}\n     */\n    static fromStimCircuit(stimCircuit) {\n        let lines = stimCircuit.replaceAll(';', '\\n').\n            replaceAll('#!pragma ERR', 'ERR').\n            replaceAll('#!pragma MARK', 'MARK').\n            replaceAll('#!pragma POLYGON', 'POLYGON').\n            replaceAll('_', ' ').\n            replaceAll('Q(', 'QUBIT_COORDS(').\n            replaceAll('DT', 'DETECTOR').\n            replaceAll('OI', 'OBSERVABLE_INCLUDE').\n            replaceAll(' COORDS', '_COORDS').\n            replaceAll(' ERROR', '_ERROR').\n            replaceAll('C XYZ', 'C_XYZ').\n            replaceAll('C NXYZ', 'C_NXYZ').\n            replaceAll('C XNYZ', 'C_XNYZ').\n            replaceAll('C XYNZ', 'C_XYNZ').\n            replaceAll('H XY', 'H_XY').\n            replaceAll('H XZ', 'H_XZ').\n            replaceAll('H YZ', 'H_YZ').\n            replaceAll('H NXY', 'H_NXY').\n            replaceAll('H NXZ', 'H_NXZ').\n            replaceAll('H NYZ', 'H_NYZ').\n            replaceAll(' INCLUDE', '_INCLUDE').\n            replaceAll('SQRT ', 'SQRT_').\n            replaceAll(' DAG ', '_DAG ').\n            replaceAll('C ZYX', 'C_ZYX').\n            replaceAll('C NZYX', 'C_NZYX').\n            replaceAll('C ZNYX', 'C_ZNYX').\n            replaceAll('C ZYNX', 'C_ZYNX').\n            split('\\n');\n        let layers = [new Layer()];\n        let num_detectors = 0;\n        let i2q = new Map();\n        let used_positions = new Set();\n\n        let findEndOfBlock = (lines, startIndex, endIndex) => {\n            let nestLevel = 0;\n            for (let k = startIndex; k < endIndex; k++) {\n                let line = lines[k];\n                line = line.split('#')[0].trim();\n                if (line.toLowerCase().startsWith(\"repeat \")) {\n                    nestLevel++;\n                } else if (line === '}') {\n                    nestLevel--;\n                    if (nestLevel === 0) {\n                        return k;\n                    }\n                }\n            }\n            throw Error(\"Repeat block didn't end\");\n        };\n\n        let processLineChunk = (lines, startIndex, endIndex, repetitions) => {\n            if (!layers[layers.length - 1].empty()) {\n                layers.push(new Layer());\n            }\n            for (let rep = 0; rep < repetitions; rep++) {\n                for (let k = startIndex; k < endIndex; k++) {\n                    let line = lines[k];\n                    line = line.split('#')[0].trim();\n                    if (line.toLowerCase().startsWith(\"repeat \")) {\n                        let reps = parseInt(line.split(\" \")[1]);\n                        let k2 = findEndOfBlock(lines, k, endIndex);\n                        processLineChunk(lines, k + 1, k2, reps);\n                        k = k2;\n                    } else {\n                        processLine(line);\n                    }\n                }\n                if (!layers[layers.length - 1].empty()) {\n                    layers.push(new Layer());\n                }\n            }\n        };\n\n        let measurement_locs = [];\n        let processLine = line => {\n            let args = [];\n            let targets = [];\n            let tag = '';\n            let name = '';\n            let firstSpace = line.indexOf(' ');\n            let firstParens = line.indexOf('(');\n            let tagStart = line.indexOf('[');\n            let tagEnd = line.indexOf(']');\n            if (tagStart !== -1 && firstSpace !== -1 && firstSpace < tagStart) {\n                tagStart = -1;\n            }\n            if (tagStart !== -1 && firstParens !== -1 && firstParens < tagStart) {\n                tagStart = -1;\n            }\n            if (tagStart !== -1 && tagEnd > tagStart) {\n                tag = line.substring(tagStart + 1, tagEnd).replaceAll('\\\\C', ']').replaceAll('\\\\r', '\\r').replaceAll('\\\\n', '\\n').replaceAll('\\\\B', '\\\\');\n                line = line.substring(0, tagStart) + ' ' + line.substring(tagEnd + 1)\n            }\n            if (line.indexOf(')') !== -1) {\n                let [ab, c] = line.split(')');\n                let [a, b] = ab.split('(');\n                name = a.trim();\n                args = b.split(',').map(e => e.trim()).map(parseFloat);\n                targets = processTargetsTextIntoTargets(c);\n            } else {\n                let ab = line.split(' ').map(e => e.trim()).filter(e => e !== '');\n                if (ab.length === 0) {\n                    return;\n                }\n                let [a, ...b] = ab;\n                name = a.trim();\n                args = [];\n                targets = b.flatMap(processTargetsTextIntoTargets);\n            }\n            let reverse_pairs = false;\n            if (name === '') {\n                return;\n            }\n            if (args.length > 0 && ['M', 'MX', 'MY', 'MZ', 'MR', 'MRX', 'MRY', 'MRZ', 'MPP', 'MPAD'].indexOf(name) !== -1) {\n                args = [];\n            }\n            let alias = GATE_ALIAS_MAP.get(name);\n            if (alias !== undefined) {\n                if (alias.ignore) {\n                    return;\n                } else if (alias.name !== undefined) {\n                    reverse_pairs = alias.rev_pair !== undefined && alias.rev_pair;\n                    name = alias.name;\n                } else {\n                    throw new Error(`Unimplemented alias ${name}: ${describe(alias)}.`);\n                }\n            } else if (name === 'TICK') {\n                layers.push(new Layer());\n                return;\n            } else if (name === 'MPP') {\n                let combinedTargets = splitUncombinedTargets(targets);\n                let layer = layers[layers.length - 1]\n                for (let combo of combinedTargets) {\n                    let op = simplifiedMPP(tag, new Float32Array(args), combo, false);\n                    try {\n                        layer.put(op, false);\n                    } catch (_) {\n                        layers.push(new Layer());\n                        layer = layers[layers.length - 1];\n                        layer.put(op, false);\n                    }\n                    measurement_locs.push({layer: layers.length - 1, targets: op.id_targets});\n                }\n                return;\n            } else if (name === 'DETECTOR' || name === 'OBSERVABLE_INCLUDE') {\n                let isDet = name === 'DETECTOR';\n                let argIndex = isDet ? num_detectors : args.length > 0 ? Math.round(args[0]) : 0;\n                for (let target of targets) {\n                    if (!target.startsWith(\"rec[-\") || ! target.endsWith(\"]\")) {\n                        console.warn(\"Ignoring instruction due to non-record target: \" + line);\n                        return;\n                    }\n                    let index = measurement_locs.length + Number.parseInt(target.substring(4, target.length - 1));\n                    if (index < 0 || index >= measurement_locs.length) {\n                        console.warn(\"Ignoring instruction due to out of range record target: \" + line);\n                        return;\n                    }\n                    let loc = measurement_locs[index];\n                    layers[loc.layer].markers.push(\n                        new Operation(GATE_MAP.get(name),\n                            tag,\n                            new Float32Array([argIndex]),\n                            new Uint32Array([loc.targets[0]]),\n                        ));\n                }\n                num_detectors += isDet;\n                return;\n            } else if (name === 'SPP' || name === 'SPP_DAG') {\n                let dag = name === 'SPP_DAG';\n                let combinedTargets = splitUncombinedTargets(targets);\n                let layer = layers[layers.length - 1]\n                for (let combo of combinedTargets) {\n                    try {\n                        layer.put(simplifiedSPP(tag, new Float32Array(args), dag, combo), false);\n                    } catch (_) {\n                        layers.push(new Layer());\n                        layer = layers[layers.length - 1];\n                        layer.put(simplifiedSPP(tag, new Float32Array(args), dag, combo), false);\n                    }\n                }\n                return;\n            } else if (name.startsWith('QUBIT_COORDS')) {\n                let x = args.length < 1 ? 0 : args[0];\n                let y = args.length < 2 ? 0 : args[1];\n                for (let targ of targets) {\n                    let t = parseInt(targ);\n                    if (i2q.has(t)) {\n                        console.warn(`Ignoring \"${line}\" because there's already coordinate data for qubit ${t}.`);\n                    } else if (used_positions.has(`${x},${y}`)) {\n                        console.warn(`Ignoring \"${line}\" because there's already a qubit placed at ${x},${y}.`);\n                    } else {\n                        i2q.set(t, [x, y]);\n                        used_positions.add(`${x},${y}`);\n                    }\n                }\n                return;\n            }\n\n            let has_feedback = false;\n            for (let targ of targets) {\n                if (targ.startsWith(\"rec[\")) {\n                    if (name === \"CX\" || name === \"CY\" || name === \"CZ\" || name === \"ZCX\" || name === \"ZCY\") {\n                        has_feedback = true;\n                    }\n                } else if (typeof parseInt(targ) !== 'number') {\n                    throw new Error(line);\n                }\n            }\n            if (has_feedback) {\n                let clean_targets = [];\n                for (let k = 0; k < targets.length; k += 2) {\n                    let b0 = targets[k].startsWith(\"rec[\");\n                    let b1 = targets[k + 1].startsWith(\"rec[\");\n                    if (b0 || b1) {\n                        if (!b0) {\n                            layers[layers.length - 1].put(new Operation(\n                                GATE_MAP.get(\"ERR\"),\n                                tag,\n                                new Float32Array([]),\n                                new Uint32Array([targets[k]]),\n                            ));\n                        }\n                        if (!b1) {\n                            layers[layers.length - 1].put(new Operation(\n                                GATE_MAP.get(\"ERR\"),\n                                tag,\n                                new Float32Array([]),\n                                new Uint32Array([targets[k + 1]]),\n                            ));\n                        }\n                        console.warn(\"Feedback isn't supported yet. Ignoring\", name, targets[k], targets[k + 1]);\n                    } else {\n                        clean_targets.push(targets[k]);\n                        clean_targets.push(targets[k + 1]);\n                    }\n                }\n                targets = clean_targets;\n                if (targets.length === 0) {\n                    return;\n                }\n            }\n\n            let gate = GATE_MAP.get(name);\n            if (gate === undefined) {\n                console.warn(\"Ignoring unrecognized instruction: \" + line);\n                return;\n            }\n            let a = new Float32Array(args);\n\n            let layer = layers[layers.length - 1];\n            if (gate.num_qubits === undefined) {\n                layer.put(new Operation(gate, tag, a, new Uint32Array(targets)));\n            } else {\n                if (targets.length % gate.num_qubits !== 0) {\n                    throw new Error(\"Incorrect number of targets in line \" + line);\n                }\n                for (let k = 0; k < targets.length; k += gate.num_qubits) {\n                    let sub_targets = targets.slice(k, k + gate.num_qubits);\n                    if (reverse_pairs) {\n                        sub_targets.reverse();\n                    }\n                    let qs = new Uint32Array(sub_targets);\n                    let op = new Operation(gate, tag, a, qs);\n                    try {\n                        layer.put(op, false);\n                    } catch (_) {\n                        layers.push(new Layer());\n                        layer = layers[layers.length - 1];\n                        layer.put(op, false);\n                    }\n                    if (op.countMeasurements() > 0) {\n                        measurement_locs.push({layer: layers.length - 1, targets: op.id_targets});\n                    }\n                }\n            }\n        };\n\n        processLineChunk(lines, 0, lines.length, 1);\n        if (layers.length > 0 && layers[layers.length - 1].isEmpty()) {\n            layers.pop();\n        }\n\n        let next_auto_position_x = 0;\n        let ensure_has_coords = (t) => {\n            let b = true;\n            while (!i2q.has(t)) {\n                let x = b ? t : next_auto_position_x;\n                let k = `${x},0`;\n                if (!used_positions.has(k)) {\n                    used_positions.add(k);\n                    i2q.set(t, [x, 0]);\n                }\n                next_auto_position_x += !b;\n                b = false;\n            }\n        };\n\n        for (let layer of layers) {\n            for (let op of layer.iter_gates_and_markers()) {\n                for (let t of op.id_targets) {\n                    ensure_has_coords(t);\n                }\n            }\n        }\n\n        let numQubits = Math.max(...i2q.keys(), 0) + 1;\n        let qubitCoords = new Float64Array(numQubits*2);\n        for (let q = 0; q < numQubits; q++) {\n            ensure_has_coords(q);\n            let [x, y] = i2q.get(q);\n            qubitCoords[2*q] = x;\n            qubitCoords[2*q + 1] = y;\n        }\n\n        return new Circuit(qubitCoords, layers);\n    }\n\n    /**\n     * @returns {!Set<!int>}\n     */\n    allQubits() {\n        let result = new Set();\n        for (let layer of this.layers) {\n            for (let op of layer.iter_gates_and_markers()) {\n                for (let t of op.id_targets) {\n                    result.add(t);\n                }\n            }\n         }\n        return result;\n    }\n\n    /**\n     * @returns {!Circuit}\n     */\n    rotated45() {\n        return this.afterCoordTransform((x, y) => [x - y, x + y]);\n    }\n\n    coordTransformForRectification() {\n        let coordSet = new Map();\n        for (let k = 0; k < this.qubitCoordData.length; k += 2) {\n            let x = this.qubitCoordData[k];\n            let y = this.qubitCoordData[k+1];\n            coordSet.set(`${x},${y}`, [x, y]);\n        }\n        let minX = Infinity;\n        let minY = Infinity;\n        let step = 256;\n        for (let [x, y] of coordSet.values()) {\n            minX = Math.min(x, minX);\n            minY = Math.min(y, minY);\n            while ((x % step !== 0 || y % step !== 0) && step > 1 / 256) {\n                step /= 2;\n            }\n        }\n        let scale;\n        if (step <= 1 / 256) {\n            scale = 1;\n        } else {\n            scale = 1 / step;\n            let mask = 0;\n            for (let [x, y] of coordSet.values()) {\n                let b1 = (x - minX + y - minY) % (2 * step);\n                let b2 = (x - minX - y + minY) % (2 * step);\n                mask |= b1 === 0 ? 1 : 2;\n                mask |= b2 === 0 ? 4 : 8;\n            }\n            if (mask === (1 | 4)) {\n                scale /= 2;\n            } else if (mask === (2 | 8)) {\n                minX -= step;\n                scale /= 2;\n            }\n        }\n\n        let offsetX = -minX;\n        let offsetY = -minY;\n        return (x, y) => [(x + offsetX) * scale, (y + offsetY) * scale];\n    }\n\n    /**\n     * @returns {!Circuit}\n     */\n    afterRectification() {\n        return this.afterCoordTransform(this.coordTransformForRectification());\n    }\n\n    /**\n     * @param {!number} dx\n     * @param {!number} dy\n     * @returns {!Circuit}\n     */\n    shifted(dx, dy) {\n        return this.afterCoordTransform((x, y) => [x + dx, y + dy]);\n    }\n\n    /**\n     * @return {!Circuit}\n     */\n    copy() {\n        return this.shifted(0, 0);\n    }\n\n    /**\n     * @param {!function(!number, !number): ![!number, !number]} coordTransform\n     * @returns {!Circuit}\n     */\n    afterCoordTransform(coordTransform) {\n        let newCoords = new Float64Array(this.qubitCoordData.length);\n        for (let k = 0; k < this.qubitCoordData.length; k += 2) {\n            let x = this.qubitCoordData[k];\n            let y = this.qubitCoordData[k + 1];\n            let [x2, y2] = coordTransform(x, y);\n            newCoords[k] = x2;\n            newCoords[k + 1] = y2;\n        }\n        let newLayers = this.layers.map(e => e.copy());\n        return new Circuit(newCoords, newLayers);\n    }\n\n    /**\n     * @param {!boolean} orderForToStimCircuit\n     * @returns {!{dets: !Array<!{mids: !Array<!int>, qids: !Array<!int>}>, obs: !Map<!int, !Array.<!int>>}}\n     */\n    collectDetectorsAndObservables(orderForToStimCircuit) {\n        // Index measurements.\n        let m2d = new Map();\n        for (let k = 0; k < this.layers.length; k++) {\n            let layer = this.layers[k];\n            if (orderForToStimCircuit) {\n                for (let group of layer.opsGroupedByNameWithArgs().values()) {\n                    for (let op of group) {\n                        if (op.countMeasurements() > 0) {\n                            let target_id = op.id_targets[0];\n                            m2d.set(`${k}:${target_id}`, {mid: m2d.size, qids: op.id_targets});\n                        }\n                    }\n                }\n            } else {\n                for (let [target_id, op] of layer.id_ops.entries()) {\n                    if (op.id_targets[0] === target_id) {\n                        if (op.countMeasurements() > 0) {\n                            m2d.set(`${k}:${target_id}`, {mid: m2d.size, qids: op.id_targets});\n                        }\n                    }\n                }\n            }\n        }\n\n        let detectors = [];\n        let observables = new Map();\n        for (let k = 0; k < this.layers.length; k++) {\n            let layer = this.layers[k];\n            for (let op of layer.markers) {\n                if (op.gate.name === 'DETECTOR') {\n                    let d = Math.round(op.args[0]);\n                    while (detectors.length <= d) {\n                        detectors.push({mids: [], qids: []});\n                    }\n                    let det_entry = detectors[d];\n                    let key = `${k}:${op.id_targets[0]}`;\n                    let v = m2d.get(key);\n                    if (v !== undefined) {\n                        det_entry.mids.push(v.mid - m2d.size);\n                        det_entry.qids.push(...v.qids);\n                    }\n                } else if (op.gate.name === 'OBSERVABLE_INCLUDE') {\n                    let d = Math.round(op.args[0]);\n                    let entries = observables.get(d);\n                    if (entries === undefined) {\n                        entries = []\n                        observables.set(d, entries);\n                    }\n                    let key = `${k}:${op.id_targets[0]}`;\n                    if (m2d.has(key)) {\n                        entries.push(m2d.get(key).mid - m2d.size);\n                    }\n                }\n            }\n        }\n        let seen = new Set();\n        let keptDetectors = [];\n        for (let ds of detectors) {\n            if (ds.mids.length > 0) {\n                ds.mids = [...new Set(ds.mids)];\n                ds.mids.sort((a, b) => b - a);\n                let key = ds.mids.join(':');\n                if (!seen.has(key)) {\n                    seen.add(key);\n                    keptDetectors.push(ds);\n                }\n            }\n        }\n        for (let [k, vs] of observables.entries()) {\n            vs = [...new Set(vs)]\n            vs.sort((a, b) => b - a);\n            observables.set(k, vs);\n        }\n        keptDetectors.sort((a, b) => a.mids[0] - b.mids[0]);\n        return {dets: keptDetectors, obs: observables};\n    }\n\n    /**\n     * @returns {!string}\n     */\n    toStimCircuit() {\n        let usedQubits = new Set();\n        for (let layer of this.layers) {\n            for (let op of layer.iter_gates_and_markers()) {\n                for (let t of op.id_targets) {\n                    usedQubits.add(t);\n                }\n            }\n        }\n\n        let {dets: remainingDetectors, obs: remainingObservables} = this.collectDetectorsAndObservables(true);\n        remainingDetectors.reverse();\n        let seenMeasurements = 0;\n        let totalMeasurements = this.countMeasurements();\n\n        let packedQubitCoords = [];\n        for (let q of usedQubits) {\n            let x = this.qubitCoordData[2*q];\n            let y = this.qubitCoordData[2*q+1];\n            packedQubitCoords.push({q, x, y});\n        }\n        packedQubitCoords.sort((a, b) => {\n            if (a.x !== b.x) {\n                return a.x - b.x;\n            }\n            if (a.y !== b.y) {\n                return a.y - b.y;\n            }\n            return a.q - b.q;\n        });\n        let old2new = new Map();\n        let out = [];\n        for (let q = 0; q < packedQubitCoords.length; q++) {\n            let {q: old_q, x, y} = packedQubitCoords[q];\n            old2new.set(old_q, q);\n            out.push(`QUBIT_COORDS(${x}, ${y}) ${q}`);\n        }\n        let detectorLayer = 0;\n        let usedDetectorCoords = new Set();\n\n        for (let layer of this.layers) {\n            let opsByName = layer.opsGroupedByNameWithArgs();\n\n            for (let [nameWithArgs, group] of opsByName.entries()) {\n                let targetGroups = [];\n\n                let gateName = nameWithArgs.split('(')[0].split('[')[0];\n                if (gateName === 'DETECTOR' || gateName === 'OBSERVABLE_INCLUDE') {\n                    continue;\n                }\n\n                let gate = GATE_MAP.get(gateName);\n                if (gate === undefined && (gateName === 'MPP' || gateName === 'SPP' || gateName === 'SPP_DAG')) {\n                    let line = [gateName + ' '];\n                    for (let op of group) {\n                        seenMeasurements += op.countMeasurements();\n                        let bases = op.gate.name.substring(gateName.length + 1);\n                        for (let k = 0; k < op.id_targets.length; k++) {\n                            line.push(bases[k] + old2new.get(op.id_targets[k]));\n                            line.push('*');\n                        }\n                        line.pop();\n                        line.push(' ');\n                    }\n                    out.push(line.join('').trim());\n                } else {\n                    if (gate !== undefined && gate.can_fuse) {\n                        let flatTargetGroups = [];\n                        for (let op of group) {\n                            seenMeasurements += op.countMeasurements();\n                            flatTargetGroups.push(...op.id_targets)\n                        }\n                        targetGroups.push(flatTargetGroups);\n                    } else {\n                        for (let op of group) {\n                            seenMeasurements += op.countMeasurements();\n                            targetGroups.push([...op.id_targets])\n                        }\n                    }\n\n                    for (let targetGroup of targetGroups) {\n                        let line = [nameWithArgs];\n                        for (let t of targetGroup) {\n                            line.push(old2new.get(t));\n                        }\n                        out.push(line.join(' '));\n                    }\n                }\n            }\n\n            // Output DETECTOR lines immediately after the last measurement layer they use.\n            let nextDetectorLayer = detectorLayer;\n            while (remainingDetectors.length > 0) {\n                let candidate = remainingDetectors[remainingDetectors.length - 1];\n                let offset = totalMeasurements - seenMeasurements;\n                if (candidate.mids[0] + offset >= 0) {\n                    break;\n                }\n                remainingDetectors.pop();\n                let cxs = [];\n                let cys = [];\n                let sx = 0;\n                let sy = 0;\n                for (let q of candidate.qids) {\n                    let cx = this.qubitCoordData[2 * q];\n                    let cy = this.qubitCoordData[2 * q + 1];\n                    sx += cx;\n                    sy += cy;\n                    cxs.push(cx);\n                    cys.push(cy);\n                }\n                if (candidate.qids.length > 0) {\n                    sx /= candidate.qids.length;\n                    sy /= candidate.qids.length;\n                    sx = Math.round(sx * 2) / 2;\n                    sy = Math.round(sy * 2) / 2;\n                }\n                cxs.push(sx);\n                cys.push(sy);\n                let name;\n                let dt = detectorLayer;\n                for (let k = 0; ; k++) {\n                    if (k >= cxs.length) {\n                        k = 0;\n                        dt += 1;\n                    }\n                    name = `DETECTOR(${cxs[k]}, ${cys[k]}, ${dt})`;\n                    if (!usedDetectorCoords.has(name)) {\n                        break;\n                    }\n                }\n                usedDetectorCoords.add(name);\n                let line = [name];\n                for (let d of candidate.mids) {\n                    line.push(`rec[${d + offset}]`)\n                }\n                out.push(line.join(' '));\n                nextDetectorLayer = Math.max(nextDetectorLayer, dt + 1);\n            }\n            detectorLayer = nextDetectorLayer;\n\n            // Output OBSERVABLE_INCLUDE lines immediately after the last measurement layer they use.\n            for (let [obsIndex, candidate] of [...remainingObservables.entries()]) {\n                let offset = totalMeasurements - seenMeasurements;\n                if (candidate[0] + offset >= 0) {\n                    continue;\n                }\n                remainingObservables.delete(obsIndex);\n                let line = [`OBSERVABLE_INCLUDE(${obsIndex})`];\n                for (let d of candidate) {\n                    line.push(`rec[${d + offset}]`)\n                }\n                out.push(line.join(' '));\n            }\n\n            out.push(`TICK`);\n        }\n        while (out.length > 0 && out[out.length - 1] === 'TICK') {\n            out.pop();\n        }\n\n        return out.join('\\n');\n    }\n\n    /**\n     * @returns {!int}\n     */\n    countMeasurements() {\n        let total = 0;\n        for (let layer of this.layers) {\n            total += layer.countMeasurements();\n        }\n        return total;\n    }\n\n    /**\n     * @param {!Iterable<![!number, !number]>} coords\n     */\n    withCoordsIncluded(coords) {\n        let coordMap = this.coordToQubitMap();\n        let extraCoordData = [];\n        for (let [x, y] of coords) {\n            let key = `${x},${y}`;\n            if (!coordMap.has(key)) {\n                coordMap.set(key, coordMap.size);\n                extraCoordData.push(x, y);\n            }\n        }\n        return new Circuit(\n            new Float64Array([...this.qubitCoordData, ...extraCoordData]),\n            this.layers.map(e => e.copy()),\n        );\n    }\n\n    /**\n     * @returns {!Map<!string, !int>}\n     */\n    coordToQubitMap() {\n        let result = new Map();\n        for (let q = 0; q < this.qubitCoordData.length; q += 2) {\n            let x = this.qubitCoordData[q];\n            let y = this.qubitCoordData[q + 1];\n            result.set(`${x},${y}`, q / 2);\n        }\n        return result;\n    }\n\n    /**\n     * @returns {!string}\n     */\n    toString() {\n        return this.toStimCircuit();\n    }\n\n    /**\n     * @param {*} other\n     * @returns {!boolean}\n     */\n    isEqualTo(other) {\n        if (!(other instanceof Circuit)) {\n            return false;\n        }\n        return this.toStimCircuit() === other.toStimCircuit();\n    }\n}\n\nexport {Circuit, processTargetsTextIntoTargets, splitUncombinedTargets};\n"
  },
  {
    "path": "glue/crumble/circuit/circuit.test.js",
    "content": "import {test, assertThat} from \"../test/test_util.js\"\nimport {Circuit, processTargetsTextIntoTargets, splitUncombinedTargets} from \"./circuit.js\"\nimport {Operation} from \"./operation.js\";\nimport {GATE_MAP} from \"../gates/gateset.js\";\nimport {make_mpp_gate} from '../gates/gateset_mpp.js';\n\ntest(\"circuit.fromStimCircuit\", () => {\n    let c1 = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 2) 0\n        QUBIT_COORDS(3, 4) 1\n        QUBIT_COORDS(5, 6) 2\n        H 0\n        S 1 2\n        TICK\n        CX 2 0\n    `);\n    assertThat(c1.qubitCoordData).isEqualTo(new Float64Array([1, 2, 3, 4, 5, 6]));\n\n    let c2 = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        QUBIT_COORDS(2, 0) 2\n        QUBIT_COORDS(2, 4) 3\n        QUBIT_COORDS(2, 3) 4\n        QUBIT_COORDS(3, 5) 5\n        QUBIT_COORDS(3, 6) 6\n        H 0\n        S 3 4\n        S[test] 1 2\n        CX 5 6\n    `);\n    assertThat(c2.qubitCoordData).isEqualTo(new Float64Array([0, 0, 0, 1, 2, 0, 2, 4, 2, 3, 3, 5, 3, 6]));\n    assertThat(c2.layers.length).isEqualTo(1);\n    assertThat(c2.layers[0].id_ops).isEqualTo(new Map([\n        [0, new Operation(GATE_MAP.get('H'), '', new Float32Array(), new Uint32Array([0]))],\n        [1, new Operation(GATE_MAP.get('S'), 'test', new Float32Array(), new Uint32Array([1]))],\n        [2, new Operation(GATE_MAP.get('S'), 'test', new Float32Array(), new Uint32Array([2]))],\n        [3, new Operation(GATE_MAP.get('S'), '', new Float32Array(), new Uint32Array([3]))],\n        [4, new Operation(GATE_MAP.get('S'), '', new Float32Array(), new Uint32Array([4]))],\n        [5, new Operation(GATE_MAP.get('CX'), '', new Float32Array(), new Uint32Array([5, 6]))],\n        [6, new Operation(GATE_MAP.get('CX'), '', new Float32Array(), new Uint32Array([5, 6]))],\n    ]));\n    assertThat(c2.toStimCircuit()).isEqualTo(`\nQUBIT_COORDS(0, 0) 0\nQUBIT_COORDS(0, 1) 1\nQUBIT_COORDS(2, 0) 2\nQUBIT_COORDS(2, 3) 3\nQUBIT_COORDS(2, 4) 4\nQUBIT_COORDS(3, 5) 5\nQUBIT_COORDS(3, 6) 6\nCX 5 6\nH 0\nS 4 3\nS[test] 1 2\n    `.trim());\n});\n\ntest(\"circuit.fromStimCircuit_strip_measurement_noise\", () => {\n    let c1 = Circuit.fromStimCircuit(`\n        M(0.1) 0\n    `);\n    assertThat(c1.toStimCircuit()).isEqualTo(`\nQUBIT_COORDS(0, 0) 0\nM 0\n    `.trim());\n});\n\ntest(\"circuit.fromStimCircuit_detector\", () => {\n    let c = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(2, 3) 0\n        R 0\n        M 0\n        R 0\n        DETECTOR rec[-1]\n    `);\n    assertThat(c.toStimCircuit()).isEqualTo(`\nQUBIT_COORDS(2, 3) 0\nR 0\nTICK\nM 0\nDETECTOR(2, 3, 0) rec[-1]\nTICK\nR 0\n    `.trim());\n})\n\ntest(\"circuit.fromStimCircuit_observable\", () => {\n    let c = Circuit.fromStimCircuit(`\n        R 0\n        M 0\n        OBSERVABLE_INCLUDE(3) rec[-1]\n        R 0\n    `);\n    assertThat(c.toStimCircuit()).isEqualTo(`\nQUBIT_COORDS(0, 0) 0\nR 0\nTICK\nM 0\nOBSERVABLE_INCLUDE(3) rec[-1]\nTICK\nR 0\n    `.trim());\n})\n\ntest(\"circuit.fromStimCircuit_mpp\", () => {\n    let c1 = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 2) 0\n        QUBIT_COORDS(3, 4) 1\n        QUBIT_COORDS(5, 6) 2\n        MPP X0*Z1*Y2 X2*Y1\n    `);\n    assertThat(c1.qubitCoordData).isEqualTo(\n        new Float64Array([1, 2, 3, 4, 5, 6]));\n    assertThat(c1.layers.length).isEqualTo(2);\n    let op1 = new Operation(make_mpp_gate(\"XZY\"), '', new Float32Array([]), new Uint32Array([0, 1, 2]));\n    assertThat(c1.layers[0].id_ops).isEqualTo(new Map([\n        [0, op1],\n        [1, op1],\n        [2, op1],\n    ]));\n    let op2 = new Operation(make_mpp_gate(\"XY\"), '', new Float32Array([]), new Uint32Array([2, 1]));\n    assertThat(c1.layers[1].id_ops).isEqualTo(new Map([\n        [1, op2],\n        [2, op2],\n    ]));\n    assertThat(c1.toStimCircuit()).isEqualTo(`\nQUBIT_COORDS(1, 2) 0\nQUBIT_COORDS(3, 4) 1\nQUBIT_COORDS(5, 6) 2\nMPP X0*Z1*Y2\nTICK\nMPP X2*Y1\n    `.trim());\n});\n\ntest('circuit.coordToQubitMap', () => {\n    let c = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(5, 6) 1\n        QUBIT_COORDS(10, 7) 2\n        QUBIT_COORDS(20, 17) 0\n    `);\n    assertThat(c.qubitCoordData).isEqualTo(new Float64Array([20, 17, 5, 6, 10, 7]));\n    assertThat(c.coordToQubitMap()).isEqualTo(new Map([\n        ['5,6', 1],\n        ['10,7', 2],\n        ['20,17', 0],\n    ]));\n});\n\ntest('circuit.processTargetsTextIntoTargets', () => {\n    assertThat(processTargetsTextIntoTargets('')).isEqualTo([]);\n    assertThat(processTargetsTextIntoTargets(' X0*X1')).isEqualTo(['X0', '*', 'X1']);\n    assertThat(processTargetsTextIntoTargets(' 0 1 2')).isEqualTo(['0', '1', '2']);\n    assertThat(processTargetsTextIntoTargets(' X0*X1*Z3 Y1 Y2*Y4')).isEqualTo(['X0', '*', 'X1', '*', 'Z3', 'Y1', 'Y2', '*', 'Y4']);\n});\n\ntest('circuit.splitUncombinedTargets', () => {\n    assertThat(splitUncombinedTargets([])).isEqualTo([]);\n    assertThat(splitUncombinedTargets(['X1'])).isEqualTo([['X1']]);\n    assertThat(splitUncombinedTargets(['X1', 'X2'])).isEqualTo([['X1'], ['X2']]);\n    assertThat(splitUncombinedTargets(['X1', '*', 'X2'])).isEqualTo([['X1', 'X2']]);\n    assertThat(splitUncombinedTargets(['X1', '*', 'X2', 'Y1', '*', 'Y2', '*', 'Y3', 'Z1', 'Z2', '*', 'Z3'])).isEqualTo([['X1', 'X2'], ['Y1', 'Y2', 'Y3'], ['Z1'], ['Z2', 'Z3']]);\n    assertThat(() => splitUncombinedTargets(['X1', '*', '*', 'X2'])).throwsAnExceptionThat().matches(/Adjacent combiners/);\n    assertThat(() => splitUncombinedTargets(['X1', '*'])).throwsAnExceptionThat().matches(/Dangling combiner/);\n    assertThat(() => splitUncombinedTargets(['*', 'X1'])).throwsAnExceptionThat().matches(/Leading combiner/);\n});\n\ntest('circuit.withCoordsIncluded', () => {\n    let c = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(10, 7) 1\n        QUBIT_COORDS(5, 6) 0\n    `);\n    assertThat(c.qubitCoordData).isEqualTo(new Float64Array([5, 6, 10, 7]));\n    let c2 = c.withCoordsIncluded([[5, 6], [2, 4], [2, 4]])\n    assertThat(c2.qubitCoordData).isEqualTo(new Float64Array([5, 6, 10, 7, 2, 4]));\n});\n\ntest(\"circuit.isEqualTo\", () => {\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        H 0\n    `)).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        H 0\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        H 0\n    `)).isNotEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        X 0\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        H 0\n    `)).isNotEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 0) 0\n        H 0\n    `));\n});\n\ntest(\"circuit.copy\", () => {\n    let c = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(2, 3) 1\n        H 0\n        CNOT 0 1\n        S 1\n    `);\n    let c2 = c.copy();\n    assertThat(c !== c2).isEqualTo(true);\n    assertThat(c).isEqualTo(c2);\n});\n\ntest(\"circuit.afterRectification\", () => {\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 2) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 0.5) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0.5, 0) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(2, 0) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0.5, 0.5) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0.5, 0.5) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0.5, 0) 0\n        QUBIT_COORDS(1, 0.5) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0.5, 0.5) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0.5) 0\n        QUBIT_COORDS(0.5, 0) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0.5, 0.5) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 2) 0\n        QUBIT_COORDS(2, 1) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0.5, 0.5) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0.5, 0.5) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0.5, 0.5) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0.25, 0.25) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0.5, 0.5) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 1) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0.5, 0.5) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 1) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0.5, 0.5) 0\n        QUBIT_COORDS(1, 0) 1\n        X 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(10, 20) 0\n        QUBIT_COORDS(12, 20) 1\n        QUBIT_COORDS(12, 21) 2\n        QUBIT_COORDS(10, 21) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(2, 0) 1\n        QUBIT_COORDS(2, 1) 2\n        QUBIT_COORDS(0, 1) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(-2, 0) 1\n        QUBIT_COORDS(-2, -1) 2\n        QUBIT_COORDS(0, -1) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(2, 1) 0\n        QUBIT_COORDS(0, 1) 1\n        QUBIT_COORDS(0, 0) 2\n        QUBIT_COORDS(2, 0) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 4) 0\n        QUBIT_COORDS(2, 0) 1\n        QUBIT_COORDS(0, 0) 2\n        QUBIT_COORDS(4, 0) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 2) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(0, 0) 2\n        QUBIT_COORDS(2, 0) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0.5) 0\n        QUBIT_COORDS(0.25, 0) 1\n        QUBIT_COORDS(0, 0) 2\n        QUBIT_COORDS(0.5, 0) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 2) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(0, 0) 2\n        QUBIT_COORDS(2, 0) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0.5, 0.5) 1\n        QUBIT_COORDS(1, 1) 2\n        QUBIT_COORDS(0.5, 1.5) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `).afterRectification()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0.5, 0.5) 1\n        QUBIT_COORDS(1, 1) 2\n        QUBIT_COORDS(0.5, 1.5) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `));\n});\n\ntest(\"circuit.rotated45\", () => {\n    let circuit = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(2, 0) 1\n        QUBIT_COORDS(2, 1) 2\n        QUBIT_COORDS(0, 1) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `);\n    let c45 = circuit.rotated45().afterRectification();\n    let c90 = c45.rotated45().afterRectification();\n    let c180 = c90.rotated45().rotated45().afterRectification();\n\n    assertThat(circuit.rotated45().rotated45().rotated45().rotated45()).isEqualTo(\n        circuit.afterCoordTransform((x, y) => [-4*x, -4*y]));\n    assertThat(c180).isEqualTo(\n        circuit.afterCoordTransform((x, y) => [2-x, 1-y]));\n\n    assertThat(c90).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 0) 0\n        QUBIT_COORDS(1, 2) 1\n        QUBIT_COORDS(0, 2) 2\n        QUBIT_COORDS(0, 0) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `));\n\n    assertThat(c45).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 0) 0\n        QUBIT_COORDS(2, 1) 1\n        QUBIT_COORDS(1.5, 1.5) 2\n        QUBIT_COORDS(0.5, 0.5) 3\n        H 0\n        X 1\n        Y 2\n        Z 3\n    `));\n});\n\ntest(\"circuit.fromStimCircuit.automaticTicks\", () => {\n    assertThat(Circuit.fromStimCircuit(`\n        H 0\n        CX 0 1\n    `)).isEqualTo(Circuit.fromStimCircuit(`\n        H 0\n        TICK\n        CX 0 1\n    `));\n});\n\ntest(\"circuit.inferAndConvertCoordinates\", () => {\n    assertThat(Circuit.fromStimCircuit(`\n        H 0 1 2 3\n    `)).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(2, 0) 2\n        QUBIT_COORDS(3, 0) 3\n        H 0 1 2 3\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        H 0 3 2 1\n    `)).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(2, 0) 2\n        QUBIT_COORDS(3, 0) 3\n        H 0 3 2 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(2) 0\n        QUBIT_COORDS(3) 1\n        QUBIT_COORDS(5) 2\n        QUBIT_COORDS(7) 3\n        H 0 3 2 1\n    `)).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(2, 0) 0\n        QUBIT_COORDS(3, 0) 1\n        QUBIT_COORDS(5, 0) 2\n        QUBIT_COORDS(7, 0) 3\n        H 0 3 2 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(2, 1, 9, 9, 9) 0\n        QUBIT_COORDS(3, 1) 1\n        QUBIT_COORDS(5, 1, 9) 2\n        QUBIT_COORDS(7, 1, 9, 9) 3\n        H 0 3 2 1\n    `)).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(2, 1) 0\n        QUBIT_COORDS(3, 1) 1\n        QUBIT_COORDS(5, 1) 2\n        QUBIT_COORDS(7, 1) 3\n        H 0 3 2 1\n    `));\n});\n\ntest(\"circuit.parse_mpp\", () => {\n    assertThat(Circuit.fromStimCircuit(`\n        MPP Z0*Z1*Z2 Z3*Z4*Z6\n    `).toString()).isEqualTo(`\nQUBIT_COORDS(0, 0) 0\nQUBIT_COORDS(1, 0) 1\nQUBIT_COORDS(2, 0) 2\nQUBIT_COORDS(3, 0) 3\nQUBIT_COORDS(4, 0) 4\nQUBIT_COORDS(6, 0) 5\nMPP Z0*Z1*Z2 Z3*Z4*Z5\n    `.trim())\n\n    assertThat(Circuit.fromStimCircuit(`\n        MPP Z0*Z1*Z2 Z3*Z4*Z5*X6\n    `).toString()).isEqualTo(`\nQUBIT_COORDS(0, 0) 0\nQUBIT_COORDS(1, 0) 1\nQUBIT_COORDS(2, 0) 2\nQUBIT_COORDS(3, 0) 3\nQUBIT_COORDS(4, 0) 4\nQUBIT_COORDS(5, 0) 5\nQUBIT_COORDS(6, 0) 6\nMPP Z0*Z1*Z2 Z3*Z4*Z5*X6\n    `.trim())\n});\n\ntest(\"circuit.fromStimCircuit_manygates\", () => {\n    let c = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 2, 3) 0\n\n        # Pauli gates\n        I 0\n        X 1\n        Y 2\n        Z 3\n        TICK\n\n        # Single Qubit Clifford Gates\n        C_XYZ 0\n        C_ZYX 1\n        H_XY 2\n        H_XZ 3\n        H_YZ 4\n        SQRT_X 0\n        SQRT_X_DAG 1\n        SQRT_Y 2\n        SQRT_Y_DAG 3\n        SQRT_Z 4\n        SQRT_Z_DAG 5\n        TICK\n\n        # Two Qubit Clifford Gates\n        CXSWAP 0 1\n        ISWAP 2 3\n        ISWAP_DAG 4 5\n        SWAP 6 7\n        SWAPCX 8 9\n        CZSWAP 10 11\n        SQRT_XX 0 1\n        SQRT_XX_DAG 2 3\n        SQRT_YY 4 5\n        SQRT_YY_DAG 6 7\n        SQRT_ZZ 8 9\n        SQRT_ZZ_DAG 10 11\n        XCX 0 1\n        XCY 2 3\n        XCZ 4 5\n        YCX 6 7\n        YCY 8 9\n        YCZ 10 11\n        ZCX 12 13\n        ZCY 14 15\n        ZCZ 16 17\n        TICK\n\n        # Noise Channels\n        CORRELATED_ERROR(0.01) X1 Y2 Z3\n        ELSE_CORRELATED_ERROR(0.02) X4 Y7 Z6\n        DEPOLARIZE1(0.02) 0\n        DEPOLARIZE2(0.03) 1 2\n        PAULI_CHANNEL_1(0.01, 0.02, 0.03) 3\n        PAULI_CHANNEL_2(0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.010, 0.011, 0.012, 0.013, 0.014, 0.015) 4 5\n        X_ERROR(0.01) 0\n        Y_ERROR(0.02) 1\n        Z_ERROR(0.03) 2\n        HERALDED_ERASE(0.04) 3\n        HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.04) 6\n        TICK\n\n        # Pauli Product Gates\n        MPP X0*Y1*Z2 Z0*Z1\n        SPP X0*Y1*Z2 X3\n        SPP_DAG X0*Y1*Z2 X2\n        TICK\n\n        # Collapsing Gates\n        MRX 0\n        MRY 1\n        MRZ 2\n        MX 3\n        MY 4\n        MZ 5 6\n        RX 7\n        RY 8\n        RZ 9\n        TICK\n\n        # Pair Measurement Gates\n        MXX 0 1 2 3\n        MYY 4 5\n        MZZ 6 7\n        TICK\n\n        # Control Flow\n        REPEAT 3 {\n            H 0\n            CX 0 1\n            S 1\n            TICK\n        }\n        TICK\n\n        # Annotations\n        MR 0\n        X_ERROR(0.1) 0\n        MR(0.01) 0\n        SHIFT_COORDS(1, 2, 3)\n        DETECTOR(1, 2, 3) rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        MPAD 0 1 0\n        TICK\n\n        # Inverted measurements.\n        MRX !0\n        MY !1\n        MZZ !2 3\n        MYY !4 !5\n        MPP X6*!Y7*Z8\n        TICK\n\n        # Feedback\n        CX rec[-1] 0\n        CY sweep[0] 1\n        CZ 2 rec[-1]\n    `);\n    assertThat(c).isNotEqualTo(undefined);\n\n    let c2 = Circuit.fromStimCircuit(`Q(1,2,3)0;I_0;X_1;Y_2;Z_3;TICK;C_XYZ_0;C_ZYX_1;H_XY_2;H_3;H_YZ_4;SQRT_X_0;SQRT_X_DAG_1;SQRT_Y_2;SQRT_Y_DAG_3;S_4;S_DAG_5;TICK;CXSWAP_0_1;ISWAP_2_3;ISWAP_DAG_4_5;SWAP_6_7;SWAPCX_8_9;CZSWAP_10_11;SQRT_XX_0_1;SQRT_XX_DAG_2_3;SQRT_YY_4_5;SQRT_YY_DAG_6_7;SQRT_ZZ_8_9;SQRT_ZZ_DAG_10_11;XCX_0_1;XCY_2_3;XCZ_4_5;YCX_6_7;YCY_8_9;YCZ_10_11;CX_12_13;CY_14_15;CZ_16_17;TICK;E(0.01)X1_Y2_Z3;ELSE_CORRELATED_ERROR(0.02)X4_Y7_Z6;DEPOLARIZE1(0.02)0;DEPOLARIZE2(0.03)1_2;PAULI_CHANNEL_1(0.01,0.02,0.03)3;PAULI_CHANNEL_2(0.001,0.002,0.003,0.004,0.005,0.006,0.007,0.008,0.009,0.01,0.011,0.012,0.013,0.014,0.015)4_5;X_ERROR(0.01)0;Y_ERROR(0.02)1;Z_ERROR(0.03)2;HERALDED_ERASE(0.04)3;HERALDED_PAULI_CHANNEL_1(0.01,0.02,0.03,0.04)6;TICK;MPP_X0*Y1*Z2_Z0*Z1;SPP_X0*Y1*Z2_X3;SPP_DAG_X0*Y1*Z2_X2;TICK;MRX_0;MRY_1;MR_2;MX_3;MY_4;M_5_6;RX_7;RY_8;R_9;TICK;MXX_0_1_2_3;MYY_4_5;MZZ_6_7;TICK;REPEAT_3_{;H_0;CX_0_1;S_1;TICK;};TICK;MR_0;X_ERROR(0.1)0;MR(0.01)0;SHIFT_COORDS(1,2,3);DETECTOR(1,2,3)rec[-1];OBSERVABLE_INCLUDE(0)rec[-1];MPAD_0_1_0;TICK;MRX_!0;MY_!1;MZZ_!2_3;MYY_!4_!5;MPP_X6*!Y7*Z8;TICK;CX_rec[-1]_0;CY_sweep[0]_1;CZ_2_rec[-1]`);\n    assertThat(c2).isNotEqualTo(undefined);\n    assertThat(c).isEqualTo(c2);\n});\n\ntest(\"circuit.fromStimCircuit_cx_ordering\", () => {\n    assertThat(Circuit.fromStimCircuit(`\n        CX 0 1\n    `)).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        CX 0 1\n    `));\n\n    assertThat(Circuit.fromStimCircuit(`\n        XCZ 1 0\n    `)).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        CX 0 1\n    `));\n});\n"
  },
  {
    "path": "glue/crumble/circuit/layer.js",
    "content": "import {Operation} from \"./operation.js\"\nimport {GATE_MAP} from \"../gates/gateset.js\";\nimport {groupBy} from \"../base/seq.js\";\n\nclass Layer {\n    constructor() {\n        this.id_ops = /** @type {!Map<!int, !Operation>} */ new Map();\n        this.markers /** @type {!Array<!Operation>} */ = [];\n    }\n\n    /**\n     * @returns {!string}\n     */\n    toString() {\n        let result = 'Layer {\\n';\n        result += \"    id_ops {\\n\";\n        for (let [key, val] of this.id_ops.entries()) {\n            result += `        ${key}: ${val}\\n`\n        }\n        result += '    }\\n';\n        result += \"    markers {\\n\";\n        for (let val of this.markers) {\n            result += `        ${val}\\n`\n        }\n        result += '    }\\n';\n        result += '}';\n        return result;\n    }\n\n    /**\n     * @returns {Map<!string, !Array<!Operation>>}\n     */\n    opsGroupedByNameWithArgs() {\n        let opsByName = groupBy(this.iter_gates_and_markers(), op => {\n            let key = op.gate.name;\n            if (key.startsWith('MPP:') && !GATE_MAP.has(key)) {\n                key = 'MPP';\n            }\n            if (key.startsWith('SPP:') && !GATE_MAP.has(key)) {\n                key = 'SPP';\n            }\n            if (key.startsWith('SPP_DAG:') && !GATE_MAP.has(key)) {\n                key = 'SPP_DAG';\n            }\n            if (op.tag !== '') {\n                key += '[' + op.tag.replace('\\\\', '\\\\B').replace('\\r', '\\\\r').replace('\\n', '\\\\n').replace(']', '\\\\C') + ']';\n            }\n            if (op.args.length > 0) {\n                key += '(' + [...op.args].join(',') + ')';\n            }\n            return key;\n        });\n        let namesWithArgs = [...opsByName.keys()];\n        namesWithArgs.sort((a, b) => {\n            let ma = a.startsWith('MARK') || a.startsWith('POLY');\n            let mb = b.startsWith('MARK') || b.startsWith('POLY');\n            if (ma !== mb) {\n                return ma < mb ? -1 : +1;\n            }\n            return a < b ? -1 : a > b ? +1 : 0;\n        });\n        return new Map(namesWithArgs.map(e => [e, opsByName.get(e)]));\n    }\n\n    /**\n     * @returns {!Layer}\n     */\n    copy() {\n        let result = new Layer();\n        result.id_ops = new Map(this.id_ops);\n        result.markers = [...this.markers];\n        return result;\n    }\n\n    /**\n     * @returns {!int}\n     */\n    countMeasurements() {\n        let total = 0;\n        for (let [target_id, op] of this.id_ops.entries()) {\n            if (op.id_targets[0] === target_id) {\n                total += op.countMeasurements();\n            }\n        }\n        return total;\n    }\n\n    /**\n     * @returns {!boolean}\n     */\n    hasDissipativeOperations() {\n        let dissipative_gate_names = [\n            'M',\n            'MX',\n            'MY',\n            'MR',\n            'MRX',\n            'MRY',\n            'MXX',\n            'MYY',\n            'MZZ',\n            'RX',\n            'RY',\n            'R',\n        ]\n        for (let op of this.id_ops.values()) {\n            if (op.gate.name.startsWith('MPP:') || dissipative_gate_names.indexOf(op.gate.name) !== -1) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    hasSingleQubitCliffords() {\n        let dissipative_gate_names = [\n            'M',\n            'MX',\n            'MY',\n            'MR',\n            'MRX',\n            'MRY',\n            'MXX',\n            'MYY',\n            'MZZ',\n            'RX',\n            'RY',\n            'R',\n        ]\n        for (let op of this.id_ops.values()) {\n            if (op.id_targets.length === 1 && dissipative_gate_names.indexOf(op.gate.name) === -1 && op.countMeasurements() === 0) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * @returns {!boolean}\n     */\n    hasResetOperations() {\n        let gateNames = [\n            'MR',\n            'MRX',\n            'MRY',\n            'RX',\n            'RY',\n            'R',\n        ]\n        for (let op of this.id_ops.values()) {\n            if (gateNames.indexOf(op.gate.name) !== -1) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * @returns {!boolean}\n     */\n    hasMeasurementOperations() {\n        let gateNames = [\n            'M',\n            'MX',\n            'MY',\n            'MR',\n            'MRX',\n            'MRY',\n            'MXX',\n            'MYY',\n            'MZZ',\n        ]\n        for (let op of this.id_ops.values()) {\n            if (op.gate.name.startsWith('MPP:') || gateNames.indexOf(op.gate.name) !== -1) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * @return {!boolean}\n     */\n    empty() {\n        return this.id_ops.size === 0 && this.markers.length === 0;\n    }\n\n    /**\n     * @param {!function(op: !Operation): !boolean} predicate\n     * @returns {!Layer}\n     */\n    id_filtered(predicate) {\n        let newLayer = new Layer();\n        for (let op of this.id_ops.values()) {\n            if (predicate(op)) {\n                newLayer.put(op);\n            }\n        }\n        for (let op of this.markers) {\n            if (predicate(op)) {\n                newLayer.markers.push(op);\n            }\n        }\n        return newLayer;\n    }\n\n    /**\n     * @param {!function(qubit: !int): !boolean} predicate\n     * @returns {!Layer}\n     */\n    id_filteredByQubit(predicate) {\n        return this.id_filtered(op => !op.id_targets.every(q => !predicate(q)));\n    }\n\n    /**\n     * @param {!Map<!int, !string>} before\n     * @param {!int} marker_index\n     * @returns {!Map<!int, !string>}\n     */\n    id_pauliFrameAfter(before, marker_index) {\n        let after = new Map();\n        let handled = new Set();\n\n        for (let k of before.keys()) {\n            let v = before.get(k);\n            let op = this.id_ops.get(k);\n            if (op !== undefined) {\n                let already_done = false;\n                let b = '';\n                for (let q of op.id_targets) {\n                    if (handled.has(q)) {\n                        already_done = true;\n                    }\n                    handled.add(q);\n                    let r = before.get(q);\n                    if (r === undefined) {\n                        r = 'I';\n                    }\n                    b += r;\n                }\n                let a = op.pauliFrameAfter(b);\n                let hasErr = a.startsWith('ERR:');\n                for (let qi = 0; qi < op.id_targets.length; qi++) {\n                    let q = op.id_targets[qi];\n                    if (hasErr) {\n                        after.set(q, 'ERR:' + a[4 + qi]);\n                    } else {\n                        after.set(q, a[qi]);\n                    }\n                }\n            } else {\n                after.set(k, v);\n            }\n        }\n\n        for (let op of this.markers) {\n            if (op.gate.name === 'MARKX' && op.args[0] === marker_index) {\n                let key = op.id_targets[0];\n                let pauli = after.get(key);\n                if (pauli === undefined || pauli === 'I') {\n                    pauli = 'X';\n                } else if (pauli === 'X') {\n                    pauli = 'I';\n                } else if (pauli === 'Y') {\n                    pauli = 'Z';\n                } else if (pauli === 'Z') {\n                    pauli = 'Y';\n                }\n                after.set(key, pauli);\n            } else if (op.gate.name === 'MARKY' && op.args[0] === marker_index) {\n                let key = op.id_targets[0];\n                let pauli = after.get(key);\n                if (pauli === undefined || pauli === 'I') {\n                    pauli = 'Y';\n                } else if (pauli === 'X') {\n                    pauli = 'Z';\n                } else if (pauli === 'Y') {\n                    pauli = 'I';\n                } else if (pauli === 'Z') {\n                    pauli = 'X';\n                }\n                after.set(key, pauli);\n            } else if (op.gate.name === 'MARKZ' && op.args[0] === marker_index) {\n                let key = op.id_targets[0];\n                let pauli = after.get(key);\n                if (pauli === undefined || pauli === 'I') {\n                    pauli = 'Z';\n                } else if (pauli === 'X') {\n                    pauli = 'Y';\n                } else if (pauli === 'Y') {\n                    pauli = 'X';\n                } else if (pauli === 'Z') {\n                    pauli = 'I';\n                }\n                after.set(key, pauli);\n            }\n        }\n\n        return after;\n    }\n\n    /**\n     * @returns {!boolean}\n     */\n    isEmpty() {\n        return this.id_ops.size === 0 && this.markers.length === 0;\n    }\n\n    /**\n     * @param {!int} qubit\n     * @returns {!Operation|undefined}\n     */\n    id_pop_at(qubit) {\n        this.markers = this.markers.filter(op => op.id_targets.indexOf(qubit) === -1);\n        if (this.id_ops.has(qubit)) {\n            let op = this.id_ops.get(qubit);\n            for (let t of op.id_targets) {\n                this.id_ops.delete(t);\n            }\n            return op;\n        }\n        return undefined;\n    }\n\n    /**\n     * @param {!int} q\n     * @param {undefined|!int} index\n     */\n    id_dropMarkersAt(q, index=undefined) {\n        this.markers = this.markers.filter(op => {\n            if (index !== undefined && op.args[0] !== index) {\n                return true;\n            }\n            if (op.gate.name !== 'MARKX' && op.gate.name !== 'MARKY' && op.gate.name !== 'MARKZ') {\n                return true;\n            }\n            return op.id_targets[0] !== q;\n        });\n    }\n\n    /**\n     * @param {!Operation} op\n     * @param {!boolean=true} allow_overwrite\n     */\n    put(op, allow_overwrite=true) {\n        if (op.gate.is_marker) {\n            if (op.gate.name === 'MARKX' || op.gate.name === 'MARKY' || op.gate.name === 'MARKZ') {\n                this.id_dropMarkersAt(op.id_targets[0], op.args[0]);\n            }\n            this.markers.push(op);\n            return;\n        }\n\n        for (let t of op.id_targets) {\n            if (this.id_ops.has(t)) {\n                if (allow_overwrite) {\n                    this.id_pop_at(t);\n                } else {\n                    throw new Error(\"Collision\");\n                }\n            }\n        }\n        for (let t of op.id_targets) {\n            this.id_ops.set(t, op);\n        }\n    }\n\n    /**\n     * @returns {!Iterator<!Operation>}\n     */\n    *iter_gates_and_markers() {\n        for (let t of this.id_ops.keys()) {\n            let op = this.id_ops.get(t);\n            if (op.id_targets[0] === t) {\n                yield op;\n            }\n        }\n        yield *this.markers;\n    }\n}\n\n/**\n * @param {!Iterable<![!number, !number]>} xys\n * @returns {![undefined | !number, undefined | !number]}\n */\nfunction minXY(xys) {\n    let minX = undefined;\n    let minY = undefined;\n    for (let [vx, vy] of xys) {\n        if (minX === undefined || vx < minX || (vx === minX && vy < minY)) {\n            minX = vx;\n            minY = vy;\n        }\n    }\n    return [minX, minY];\n}\n\nexport {Layer, minXY};\n"
  },
  {
    "path": "glue/crumble/circuit/layer.test.js",
    "content": "import {test, assertThat} from \"../test/test_util.js\"\nimport {PauliFrame} from \"./pauli_frame.js\"\nimport {GATE_MAP} from \"../gates/gateset.js\"\nimport {Operation} from \"./operation.js\";\nimport {Layer} from \"./layer.js\";\nimport {Circuit} from \"./circuit.js\";\n\ntest(\"layer.put_get\", () => {\n    let layer = new Layer();\n    assertThat(layer.id_ops).isEqualTo(new Map());\n    assertThat(layer.markers).isEqualTo([]);\n\n    let op = new Operation(GATE_MAP.get(\"CX\"), '', new Float32Array(), new Uint32Array([2, 3]));\n    layer.put(op);\n    assertThat(layer.id_ops).isEqualTo(new Map([\n        [2, op],\n        [3, op],\n    ]));\n    assertThat(layer.markers).isEqualTo([]);\n\n    let marker1 = new Operation(GATE_MAP.get(\"MARKX\"), '', new Float32Array([0]), new Uint32Array([4]));\n    let marker2 = new Operation(GATE_MAP.get(\"MARKZ\"), '', new Float32Array([1]), new Uint32Array([5]));\n    layer.put(marker1);\n    layer.put(marker2);\n    assertThat(layer.id_ops).isEqualTo(new Map([\n        [2, op],\n        [3, op],\n    ]));\n    assertThat(layer.markers).isEqualTo([marker1, marker2]);\n});\n\ntest(\"layer.filtered\", () => {\n    let circuit = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 1) 1\n        QUBIT_COORDS(2, 2) 2\n        QUBIT_COORDS(3, 3) 3\n        H 0 1 2\n        S 3\n        TICK\n        CNOT 0 1\n        CZ 2 3\n        TICK\n    `);\n    let c0 = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 1) 1\n        QUBIT_COORDS(2, 2) 2\n        QUBIT_COORDS(3, 3) 3\n        H 0\n        TICK\n        CNOT 0 1\n        TICK\n    `);\n    let c01 = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 1) 1\n        QUBIT_COORDS(2, 2) 2\n        QUBIT_COORDS(3, 3) 3\n        H 0 1\n        TICK\n        CNOT 0 1\n        TICK\n    `);\n    assertThat(circuit.layers[0].id_filteredByQubit(q => q === 0)).isEqualTo(c0.layers[0]);\n    assertThat(circuit.layers[1].id_filteredByQubit(q => q === 0)).isEqualTo(c0.layers[1]);\n    assertThat(circuit.layers[0].id_filteredByQubit(q => q === 0 || q === 1)).isEqualTo(c01.layers[0]);\n    assertThat(circuit.layers[1].id_filteredByQubit(q => q === 0 || q === 1)).isEqualTo(c01.layers[1]);\n});\n"
  },
  {
    "path": "glue/crumble/circuit/operation.js",
    "content": "import {Gate} from \"../gates/gate.js\"\n\n/**\n * @param {!string} base\n * @returns {!Array<!string>}\n */\nfunction expandBase(base) {\n    let result = [];\n    for (let k = 0; k < base.length; k++) {\n        let prefix = 'I'.repeat(k);\n        let suffix = 'I'.repeat(base.length - k - 1);\n        if (base[k] === 'X' || base[k] === 'Y') {\n            result.push(prefix + 'X' + suffix);\n        }\n        if (base[k] === 'Z' || base[k] === 'Y') {\n            result.push(prefix + 'Z' + suffix);\n        }\n    }\n    return result;\n}\n\nclass Operation {\n    /**\n     * @param {!Gate} gate\n     * @param {!string} tag\n     * @param {!Float32Array} args\n     * @param {!Uint32Array} targets\n     */\n    constructor(gate, tag, args, targets) {\n        if (!(gate instanceof Gate)) {\n            throw new Error(`!(gate instanceof Gate) gate=${gate}`);\n        }\n        if (!(args instanceof Float32Array)) {\n            throw new Error('!(args instanceof Float32Array)');\n        }\n        if (!(targets instanceof Uint32Array)) {\n            throw new Error('!(targets instanceof Uint32Array)');\n        }\n        this.gate = gate;\n        this.tag = tag;\n        this.args = args;\n        this.id_targets = targets;\n    }\n\n    /**\n     * @returns {!string}\n     */\n    toString() {\n        return `${this.gate.name}[${this.tag}](${[...this.args].join(', ')}) ${[...this.id_targets].join(' ')}`;\n    }\n\n    /**\n     * @returns {!int}\n     */\n    countMeasurements() {\n        if (this.gate.name === 'M' || this.gate.name === 'MX' || this.gate.name === 'MY' || this.gate.name === 'MR' || this.gate.name === 'MRX' || this.gate.name === 'MRY') {\n            return this.id_targets.length;\n        }\n        if (this.gate.name === 'MXX' || this.gate.name === 'MYY' || this.gate.name === 'MZZ') {\n            return this.id_targets.length / 2;\n        }\n        if (this.gate.name.startsWith('MPP:')) {\n            return 1;\n        }\n        return 0;\n    }\n\n    /**\n     * @param {!string} before\n     * @returns {!string}\n     */\n    pauliFrameAfter(before) {\n        let m = this.gate.tableau_map;\n        if (m === undefined) {\n            if (this.gate.name.startsWith('M')) {\n                let bases;\n                if (this.gate.name.startsWith('MPP:')) {\n                    bases = this.gate.name.substring(4);\n                } else {\n                    bases = this.gate.name.substring(1);\n                }\n                let differences = 0;\n                for (let k = 0; k < before.length; k++) {\n                    let a = 'XYZ'.indexOf(before[k]);\n                    let b = 'XYZ'.indexOf(bases[k]);\n                    if (a >= 0 && b >= 0 && a !== b) {\n                        differences++;\n                    }\n                }\n                if (differences % 2 !== 0) {\n                    return 'ERR:' + before;\n                }\n                return before;\n            } else if (this.gate.name.startsWith('SPP:') || this.gate.name.startsWith('SPP_DAG:')) {\n                let dag = this.gate.name.startsWith('SPP_DAG:');\n                let bases = this.gate.name.substring(dag ? 8 : 4);\n                let differences = 0;\n                let flipped = '';\n                for (let k = 0; k < before.length; k++) {\n                    let a = 'IXYZ'.indexOf(before[k]);\n                    let b = 'IXYZ'.indexOf(bases[k]);\n                    if (a > 0 && b > 0 && a !== b) {\n                        differences++;\n                    }\n                    flipped += 'IXYZ'[a ^ b]\n                }\n                if (differences % 2 !== 0) {\n                    return flipped;\n                }\n                return before;\n            } else if (this.gate.name === 'POLYGON') {\n                // Do nothing.\n                return before;\n            } else {\n                throw new Error(this.gate.name);\n            }\n        }\n        if (before.length !== this.gate.num_qubits) {\n            throw new Error(`before.length !== this.gate.num_qubits`);\n        }\n        if (m.has(before)) {\n            return m.get(before);\n        }\n        let bases = expandBase(before);\n        bases = bases.map(e => m.get(e));\n        let out = [0, 0];\n        for (let b of bases) {\n            for (let k = 0; k < before.length; k++) {\n                if (b[k] === 'X') {\n                    out[k] ^= 1;\n                }\n                if (b[k] === 'Y') {\n                    out[k] ^= 3;\n                }\n                if (b[k] === 'Z') {\n                    out[k] ^= 2;\n                }\n            }\n        }\n        let result = '';\n        for (let k = 0; k < before.length; k++) {\n            result += 'IXZY'[out[k]];\n        }\n        return result;\n    }\n\n    /**\n     * @param {!function(qubit: !int): ![!number, !number]} qubitCoordsFunc\n     * @param {!CanvasRenderingContext2D} ctx\n     */\n    id_draw(qubitCoordsFunc, ctx) {\n        ctx.save();\n        try {\n            this.gate.drawer(this, qubitCoordsFunc, ctx);\n            if (this.tag !== '' && this.id_targets.length > 0) {\n                let [x, y] = qubitCoordsFunc(this.id_targets[0]);\n                ctx.fillText(this.tag, x, y + 16);\n            }\n        } finally {\n            ctx.restore();\n        }\n    }\n}\n\nexport {Operation};\n"
  },
  {
    "path": "glue/crumble/circuit/pauli_frame.js",
    "content": "import {describe} from \"../base/describe.js\";\n\nclass PauliFrame {\n    /**\n     * @param {!int} num_frames\n     * @param {!int} num_qubits\n     */\n    constructor(num_frames, num_qubits) {\n        if (num_frames > 32) {\n            throw new Error('num_frames > 32');\n        }\n        this.num_qubits = num_qubits;\n        this.num_frames = num_frames;\n        this.xs = new Uint32Array(num_qubits);\n        this.zs = new Uint32Array(num_qubits);\n        this.flags = new Uint32Array(num_qubits);\n    }\n\n    /**\n     * @returns {!PauliFrame}\n     */\n    copy() {\n        let result = new PauliFrame(this.num_frames, this.num_qubits);\n        for (let q = 0; q < this.num_qubits; q++) {\n            result.xs[q] = this.xs[q];\n            result.zs[q] = this.zs[q];\n            result.flags[q] = this.flags[q];\n        }\n        return result;\n    }\n\n    /**\n     * @param {!Array<!string>} qubit_keys\n     * @returns {!Array<!Map<!string, !string>>}\n     */\n    to_dicts(qubit_keys) {\n        if (qubit_keys.length !== this.num_qubits) {\n            throw new Error(\"qubit_keys.length !== this.num_qubits\");\n        }\n        let result = [];\n        for (let k = 0; k < this.num_frames; k++) {\n            result.push(new Map());\n        }\n        for (let q = 0; q < this.num_qubits; q++) {\n            let key = qubit_keys[q];\n            let x = this.xs[q];\n            let z = this.zs[q];\n            let f = this.flags[q];\n            let m = x | z | f;\n            let k = 0;\n            while (m) {\n                if (m & 1) {\n                    if (f & 1) {\n                        result[k].set(key, 'ERR:flag');\n                    } else if (x & z & 1) {\n                        result[k].set(key, 'Y');\n                    } else if (x & 1) {\n                        result[k].set(key, 'X');\n                    } else {\n                        result[k].set(key, 'Z');\n                    }\n                }\n                k++;\n                x >>= 1;\n                z >>= 1;\n                f >>= 1;\n                m >>= 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @param {!Array<!string>} strings\n     * @returns {!PauliFrame}\n     */\n    static from_strings(strings) {\n        let num_frames = strings.length;\n        if (num_frames === 0) {\n            throw new Error(\"strings.length === 0\");\n        }\n        let num_qubits = strings[0].length;\n        for (let s of strings) {\n            if (s.length !== num_qubits) {\n                throw new Error(\"Inconsistent string length.\");\n            }\n        }\n\n        let result = new PauliFrame(num_frames, num_qubits);\n        for (let f = 0; f < num_frames; f++) {\n            for (let q = 0; q < num_qubits; q++) {\n                let c = strings[f][q];\n                if (c === 'X') {\n                    result.xs[q] |= 1 << f;\n                } else if (c === 'Y') {\n                    result.xs[q] |= 1 << f;\n                    result.zs[q] |= 1 << f;\n                } else if (c === 'Z') {\n                    result.zs[q] |= 1 << f;\n                } else if (c === 'I' || c === '_') {\n                    // Identity.\n                } else if (c === '!') {\n                    result.flags[q] |= 1 << f;\n                } else if (c === '%') {\n                    result.flags[q] |= 1 << f;\n                    result.xs[q] |= 1 << f;\n                } else if (c === '&') {\n                    result.flags[q] |= 1 << f;\n                    result.xs[q] |= 1 << f;\n                    result.zs[q] |= 1 << f;\n                } else if (c === '$') {\n                    result.flags[q] |= 1 << f;\n                    result.zs[q] |= 1 << f;\n                } else {\n                    throw new Error(\"Unrecognized pauli string character: '\" + c + \"'\");\n                }\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @returns {!Array<!string>}\n     */\n    to_strings() {\n        let result = [];\n        for (let f = 0; f < this.num_frames; f++) {\n            let s = '';\n            for (let q = 0; q < this.num_qubits; q++) {\n                let flag = (this.flags[q] >> f) & 1;\n                let x = (this.xs[q] >> f) & 1;\n                let z = (this.zs[q] >> f) & 1;\n                s += '_XZY!%$&'[x + 2*z + 4*flag];\n            }\n            result.push(s);\n        }\n        return result;\n    }\n\n    /**\n     * @param {!Array<!Map<!string, !string>>} dicts\n     * @param {!Array<!string>} qubit_keys\n     * @returns {!PauliFrame}\n     */\n    static from_dicts(dicts, qubit_keys) {\n        let result = new PauliFrame(dicts.length, qubit_keys.length);\n        for (let f = 0; f < dicts.length; f++) {\n            for (let q = 0; q < qubit_keys.length; q++) {\n                let p = dicts[f].get(qubit_keys[q]);\n                if (p === 'X') {\n                    result.xs[q] |= 1 << f;\n                } else if (p === 'Z') {\n                    result.zs[q] |= 1 << f;\n                } else if (p === 'Y') {\n                    result.xs[q] |= 1 << f;\n                    result.zs[q] |= 1 << f;\n                } else if (p !== 'I' && p !== undefined) {\n                    result.flags[q] |= 1 << f;\n                }\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_exchange_xz(targets) {\n        for (let t of targets) {\n            let x = this.xs[t];\n            let z = this.zs[t];\n            this.zs[t] = x;\n            this.xs[t] = z;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_exchange_xy(targets) {\n        for (let t of targets) {\n            this.zs[t] ^= this.xs[t];\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_exchange_yz(targets) {\n        for (let t of targets) {\n            this.xs[t] ^= this.zs[t];\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_discard(targets) {\n        for (let t of targets) {\n            this.flags[t] |= this.xs[t];\n            this.flags[t] |= this.zs[t];\n            this.xs[t] = 0;\n            this.zs[t] = 0;\n        }\n    }\n\n    /**\n     * @param {!string} observable\n     * @param {!Array<!int>} targets\n     */\n    do_measure(observable, targets) {\n        for (let k = 0; k < targets.length; k += observable.length) {\n            let anticommutes = 0;\n            for (let k2 = 0; k2 < observable.length; k2++) {\n                let t = targets[k + k2];\n                let obs = observable[k2];\n                if (obs === 'X') {\n                    anticommutes ^= this.zs[t];\n                } else if (obs === 'Z') {\n                    anticommutes ^= this.xs[t];\n                } else if (obs === 'Y') {\n                    anticommutes ^= this.xs[t] ^ this.zs[t];\n                } else {\n                    throw new Error(`Unrecognized measure obs: '${obs}'`);\n                }\n            }\n            for (let k2 = 0; k2 < observable.length; k2++) {\n                let t = targets[k + k2];\n                this.flags[t] |= anticommutes;\n            }\n        }\n    }\n\n    /**\n     * @param {!string} bases\n     * @param {!Uint32Array|!Array.<!int>} targets\n     */\n    do_mpp(bases, targets) {\n        if (bases.length !== targets.length) {\n            throw new Error('bases.length !== targets.length');\n        }\n        let anticommutes = 0;\n        for (let k = 0; k < bases.length; k++) {\n            let t = targets[k];\n            let obs = bases[k];\n            if (obs === 'X') {\n                anticommutes ^= this.zs[t];\n            } else if (obs === 'Z') {\n                anticommutes ^= this.xs[t];\n            } else if (obs === 'Y') {\n                anticommutes ^= this.xs[t] ^ this.zs[t];\n            } else {\n                throw new Error(`Unrecognized measure obs: '${obs}'`);\n            }\n        }\n        for (let k = 0; k < bases.length; k++) {\n            let t = targets[k];\n            this.flags[t] |= anticommutes;\n        }\n    }\n\n    /**\n     * @param {!string} bases\n     * @param {!Uint32Array|!Array.<!int>} targets\n     */\n    do_spp(bases, targets) {\n        if (bases.length !== targets.length) {\n            throw new Error('bases.length !== targets.length');\n        }\n        let anticommutes = 0;\n        for (let k = 0; k < bases.length; k++) {\n            let t = targets[k];\n            let obs = bases[k];\n            if (obs === 'X') {\n                anticommutes ^= this.zs[t];\n            } else if (obs === 'Z') {\n                anticommutes ^= this.xs[t];\n            } else if (obs === 'Y') {\n                anticommutes ^= this.xs[t] ^ this.zs[t];\n            } else {\n                throw new Error(`Unrecognized spp obs: '${obs}'`);\n            }\n        }\n        for (let k = 0; k < bases.length; k++) {\n            let t = targets[k];\n            let obs = bases[k];\n            let x = 0;\n            let z = 0;\n            if (obs === 'X') {\n                x = 1;\n            } else if (obs === 'Z') {\n                z = 1;\n            } else if (obs === 'Y') {\n                x = 1;\n                z = 1;\n            } else {\n                throw new Error(`Unrecognized spp obs: '${obs}'`);\n            }\n            if (x) {\n                this.xs[t] ^= anticommutes;\n            }\n            if (z) {\n                this.zs[t] ^= anticommutes;\n            }\n        }\n    }\n\n    /**\n     * @param {!string} observable\n     * @param {!Array<!int>} targets\n     */\n    do_demolition_measure(observable, targets) {\n        if (observable === 'X') {\n            for (let q of targets) {\n                this.flags[q] |= this.zs[q];\n                this.xs[q] = 0;\n                this.zs[q] = 0;\n            }\n        } else if (observable === 'Z') {\n            for (let q of targets) {\n                this.flags[q] |= this.xs[q];\n                this.xs[q] = 0;\n                this.zs[q] = 0;\n            }\n        } else if (observable === 'Y') {\n            for (let q of targets) {\n                this.flags[q] |= this.xs[q] ^ this.zs[q];\n                this.xs[q] = 0;\n                this.zs[q] = 0;\n            }\n        } else {\n            throw new Error(\"Unrecognized demolition obs\");\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_cycle_xyz(targets) {\n        for (let t of targets) {\n            this.xs[t] ^= this.zs[t];\n            this.zs[t] ^= this.xs[t];\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_cycle_zyx(targets) {\n        for (let t of targets) {\n            this.zs[t] ^= this.xs[t];\n            this.xs[t] ^= this.zs[t];\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_swap(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let a = targets[k];\n            let b = targets[k + 1];\n            let xa = this.xs[a];\n            let za = this.zs[a];\n            let xb = this.xs[b];\n            let zb = this.zs[b];\n            this.xs[a] = xb;\n            this.zs[a] = zb;\n            this.xs[b] = xa;\n            this.zs[b] = za;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_iswap(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let a = targets[k];\n            let b = targets[k + 1];\n\n            let xa = this.xs[a];\n            let za = this.zs[a];\n            let xb = this.xs[b];\n            let zb = this.zs[b];\n            let xab = xa ^ xb;\n            this.xs[a] = xb;\n            this.zs[a] = zb ^ xab;\n            this.xs[b] = xa;\n            this.zs[b] = za ^ xab;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_sqrt_xx(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let a = targets[k];\n            let b = targets[k + 1];\n            let zab = this.zs[a] ^ this.zs[b];\n            this.xs[a] ^= zab;\n            this.xs[b] ^= zab;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_sqrt_yy(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let a = targets[k];\n            let b = targets[k + 1];\n\n            let xa = this.xs[a];\n            let za = this.zs[a];\n            let xb = this.xs[b];\n            let zb = this.zs[b];\n\n            za ^= xa;\n            zb ^= xb;\n            xa ^= zb;\n            xb ^= za;\n            zb ^= xb;\n            za ^= xa;\n\n            this.xs[a] = za;\n            this.zs[a] = xa;\n            this.xs[b] = zb;\n            this.zs[b] = xb;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_sqrt_zz(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let a = targets[k];\n            let b = targets[k + 1];\n            let xab = this.xs[a] ^ this.xs[b];\n            this.zs[a] ^= xab;\n            this.zs[b] ^= xab;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_xcx(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let control = targets[k];\n            let target = targets[k + 1];\n            this.xs[target] ^= this.zs[control];\n            this.xs[control] ^= this.zs[target];\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_xcy(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let control = targets[k];\n            let target = targets[k + 1];\n            this.xs[target] ^= this.zs[control];\n            this.zs[target] ^= this.zs[control];\n            this.xs[control] ^= this.xs[target];\n            this.xs[control] ^= this.zs[target];\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_ycy(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let control = targets[k];\n            let target = targets[k + 1];\n            let y = this.xs[control] ^ this.zs[control];\n            this.xs[target] ^= y;\n            this.zs[target] ^= y;\n            y = this.xs[target] ^ this.zs[target];\n            this.xs[control] ^= y;\n            this.zs[control] ^= y;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_cx(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let control = targets[k];\n            let target = targets[k + 1];\n            this.xs[target] ^= this.xs[control];\n            this.zs[control] ^= this.zs[target];\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_cx_swap(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let c = targets[k];\n            let t = targets[k + 1];\n            let xc = this.xs[c];\n            let zc = this.zs[c];\n            let xt = this.xs[t];\n            let zt = this.zs[t];\n            this.xs[c] = xt ^ xc;\n            this.zs[c] = zt;\n            this.xs[t] = xc;\n            this.zs[t] = zc ^ zt;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_swap_cx(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let c = targets[k];\n            let t = targets[k + 1];\n            let xc = this.xs[c];\n            let zc = this.zs[c];\n            let xt = this.xs[t];\n            let zt = this.zs[t];\n            this.xs[c] = xt;\n            this.zs[c] = zc ^ zt;\n            this.xs[t] = xt ^ xc;\n            this.zs[t] = zc;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_cz_swap(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let c = targets[k];\n            let t = targets[k + 1];\n            let xc = this.xs[c];\n            let zc = this.zs[c];\n            let xt = this.xs[t];\n            let zt = this.zs[t];\n            this.xs[c] = xt;\n            this.zs[c] = zt ^ xc;\n            this.xs[t] = xc;\n            this.zs[t] = zc ^ xt;\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_cy(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let control = targets[k];\n            let target = targets[k + 1];\n            this.xs[target] ^= this.xs[control];\n            this.zs[target] ^= this.xs[control];\n            this.zs[control] ^= this.zs[target];\n            this.zs[control] ^= this.xs[target];\n        }\n    }\n\n    /**\n     * @param {!Array<!int>} targets\n     */\n    do_cz(targets) {\n        for (let k = 0; k < targets.length; k += 2) {\n            let control = targets[k];\n            let target = targets[k + 1];\n            this.zs[target] ^= this.xs[control];\n            this.zs[control] ^= this.xs[target];\n        }\n    }\n\n    /**\n     * @param {!Gate} gate\n     * @param {!Array<!int>} targets\n     */\n    do_gate(gate, targets) {\n        gate.frameDo(this, targets);\n    }\n\n    /**\n     * @param {!Gate} gate\n     * @param {!Array<!int>} targets\n     */\n    undo_gate(gate, targets) {\n        gate.frameUndo(this, targets);\n    }\n\n    /**\n     * @param {*} other\n     * @returns {!boolean}\n     */\n    isEqualTo(other) {\n        if (!(other instanceof PauliFrame) || other.num_frames !== this.num_frames || other.num_qubits !== this.num_qubits) {\n            return false;\n        }\n        for (let q = 0; q < this.num_qubits; q++) {\n            if (this.xs[q] !== other.xs[q] || this.zs[q] !== other.zs[q] || this.flags[q] !== other.flags[q]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * @returns {!string}\n     */\n    toString() {\n        return this.to_strings().join('\\n');\n    }\n}\n\nexport {PauliFrame}\n"
  },
  {
    "path": "glue/crumble/circuit/pauli_frame.test.js",
    "content": "import {test, assertThat} from \"../test/test_util.js\"\nimport {PauliFrame} from \"./pauli_frame.js\"\nimport {GATE_MAP} from \"../gates/gateset.js\"\nimport {make_mpp_gate, make_spp_gate} from \"../gates/gateset_mpp.js\"\nimport {Operation} from \"./operation.js\";\n\ntest(\"pauli_frame.to_from\", () => {\n    let strings = [\n        \"_XYZ\",\n        \"XXXX\",\n        \"!&$%\",\n    ];\n    let frame = PauliFrame.from_strings(strings);\n    assertThat(frame.num_frames).isEqualTo(3);\n    assertThat(frame.num_qubits).isEqualTo(4);\n    assertThat(frame.toString()).isEqualTo(strings.join('\\n'));\n});\n\ntest(\"pauli_frame.to_from_dicts\", () => {\n    let frame = PauliFrame.from_strings([\n        \"_XYZ\",\n        \"XXX!\",\n    ]);\n    let qubit_keys = [\"A\", \"B\", \"C\", \"D\"];\n    let dicts = frame.to_dicts(qubit_keys);\n    assertThat(dicts).isEqualTo([\n        new Map([[\"B\", \"X\"], [\"C\", \"Y\"], [\"D\", \"Z\"]]),\n        new Map([[\"A\", \"X\"], [\"B\", \"X\"], [\"C\", \"X\"], [\"D\", \"ERR:flag\"]]),\n    ]);\n    assertThat(PauliFrame.from_dicts(dicts, qubit_keys)).isEqualTo(frame);\n});\n\ntest(\"pauli_frame.do_gate_vs_old_frame_updates\", () => {\n    let gates = [...GATE_MAP.values(), make_mpp_gate(\"XYY\"), make_spp_gate(\"XYY\")];\n    for (let g of gates) {\n        if (g.name === 'DETECTOR' || g.name === 'OBSERVABLE_INCLUDE') {\n            continue;\n        }\n        let before, after, returned;\n        if (g.num_qubits === 1) {\n            before = new PauliFrame(4, g.num_qubits);\n            before.xs[0] = 0b0011;\n            before.zs[0] = 0b0101;\n            after = before.copy();\n            after.do_gate(g, [0]);\n            returned = after.copy();\n            returned.undo_gate(g, [0]);\n        } else {\n            before = new PauliFrame(16, g.num_qubits);\n            before.xs[0] = 0b0000000011111111;\n            before.zs[0] = 0b0000111100001111;\n            before.xs[1] = 0b0011001100110011;\n            before.zs[1] = 0b0101010101010101;\n            let targets = [0, 1];\n            for (let k = 2; k < g.num_qubits; k++) {\n                targets.push(k);\n            }\n            after = before.copy();\n            after.do_gate(g, targets);\n            returned = after.copy();\n            returned.undo_gate(g, targets);\n        }\n        if (!returned.flags[0]) {\n            assertThat(returned).withInfo({'gate': g.name}).isEqualTo(before);\n        }\n\n        let before_strings = before.to_strings();\n        let actual_after_strings = after.to_strings();\n\n        // Broadcast failure.\n        for (let k = 0; k < actual_after_strings.length; k++) {\n            let a = actual_after_strings[k];\n            if (a.indexOf('&') !== -1 || a.indexOf('!') !== -1 || a.indexOf('%') !== -1 || a.indexOf('$') !== -1) {\n                a = a.replaceAll('_', '!')\n                a = a.replaceAll('X', '%')\n                a = a.replaceAll('Y', '&')\n                a = a.replaceAll('Z', '$')\n                actual_after_strings[k] = a;\n            }\n        }\n\n        let op = new Operation(g, '', new Float32Array(0), new Uint32Array([0, 1]));\n        let expected_after_strings = [];\n        for (let f = 0; f < before_strings.length; f++) {\n            let t = op.pauliFrameAfter(before_strings[f].replaceAll('_', 'I'));\n            t = t.replaceAll('I', '_');\n            if (t.startsWith('ERR:')) {\n                t = t.substring(4);\n                t = t.replaceAll('_', '!')\n                t = t.replaceAll('X', '%')\n                t = t.replaceAll('Y', '&')\n                t = t.replaceAll('Z', '$')\n            }\n            expected_after_strings.push(t);\n        }\n\n        assertThat(actual_after_strings).withInfo(`gate = ${g.name}`).isEqualTo(expected_after_strings);\n    }\n});\n"
  },
  {
    "path": "glue/crumble/circuit/propagated_pauli_frames.js",
    "content": "import {PauliFrame} from './pauli_frame.js';\nimport {equate} from '../base/equate.js';\nimport {Layer} from './layer.js';\n\nclass PropagatedPauliFrameLayer {\n    /**\n     * @param {!Map<!int, !string>} bases\n     * @param {!Set<!int>} errors\n     * @param {!Array<!{q1: !int, q2: !int, color: !string}>} crossings\n     */\n    constructor(bases, errors, crossings) {\n        this.bases = bases;\n        this.errors = errors;\n        this.crossings = crossings;\n    }\n\n    /**\n     * @param {!Set<!int>} qids\n     * @returns {!boolean}\n     */\n    touchesQidSet(qids) {\n        for (let q of this.bases.keys()) {\n            if (qids.has(q)) {\n                return true;\n            }\n        }\n        for (let q of this.errors.keys()) {\n            if (qids.has(q)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * @param {!PropagatedPauliFrameLayer} other\n     * @returns {!PropagatedPauliFrameLayer}\n     */\n    mergedWith(other) {\n        return new PropagatedPauliFrameLayer(\n            new Map([...this.bases.entries(), ...other.bases.entries()]),\n            new Set([...this.errors, ...other.errors]),\n            [...this.crossings, ...other.crossings],\n        );\n    }\n\n    /**\n     * @returns {!string}\n     */\n    toString() {\n        let num_qubits = 0;\n        for (let q of this.bases.keys()) {\n            num_qubits = Math.max(num_qubits, q + 1);\n        }\n        for (let q of this.errors) {\n            num_qubits = Math.max(num_qubits, q + 1);\n        }\n        for (let [q1, q2] of this.crossings) {\n            num_qubits = Math.max(num_qubits, q1 + 1);\n            num_qubits = Math.max(num_qubits, q2 + 1);\n        }\n        let result = '\"';\n        for (let q = 0; q < num_qubits; q++) {\n            let b = this.bases.get(q);\n            if (b === undefined) {\n                b = '_';\n            }\n            if (this.errors.has(q)) {\n                b = 'E';\n            }\n            result += b;\n        }\n        result += '\"';\n        return result;\n    }\n}\n\nclass PropagatedPauliFrames {\n    /**\n     * @param {!Map<!int, !PropagatedPauliFrameLayer>} layers\n     */\n    constructor(layers) {\n        this.id_layers = layers;\n    }\n\n    /**\n     * @param {*} other\n     * @returns {!boolean}\n     */\n    isEqualTo(other) {\n        return other instanceof PropagatedPauliFrames && equate(this.id_layers, other.id_layers);\n    }\n\n    /**\n     * @returns {!string}\n     */\n    toString() {\n        let layers = [...this.id_layers.keys()];\n        layers.sort((a, b) => a - b);\n        let lines = ['PropagatedPauliFrames {'];\n        for (let k of layers) {\n            lines.push(`    ${k}: ${this.id_layers.get(k)}`);\n        }\n        lines.push('}');\n        return lines.join('\\n');\n    }\n\n    /**\n     * @param {!int} layer\n     * @returns {!PropagatedPauliFrameLayer}\n     */\n    atLayer(layer) {\n        let result = this.id_layers.get(layer);\n        if (result === undefined) {\n            result = new PropagatedPauliFrameLayer(new Map(), new Set(), []);\n        }\n        return result;\n    }\n\n    /**\n     * @param {!Circuit} circuit\n     * @param {!int} marker_index\n     * @returns {!PropagatedPauliFrames}\n     */\n    static fromCircuit(circuit, marker_index) {\n        let result = new PropagatedPauliFrames(new Map());\n\n        let bases = /** @type {!Map<!int, !string>} */ new Map();\n        for (let k = 0; k < circuit.layers.length; k++) {\n            let layer = circuit.layers[k];\n            let prevBases = bases;\n            bases = layer.id_pauliFrameAfter(bases, marker_index);\n\n            let errors = new Set();\n            for (let key of [...bases.keys()]) {\n                let val = bases.get(key);\n                if (val.startsWith('ERR:')) {\n                    errors.add(key);\n                    bases.set(key, val.substring(4));\n                }\n                if (bases.get(key) === 'I') {\n                    bases.delete(key);\n                }\n            }\n\n            let crossings = /** @type {!Array<!{q1: !int, q2: !int, color: !string}>} */ [];\n            for (let op of layer.iter_gates_and_markers()) {\n                if (op.gate.num_qubits === 2 && !op.gate.is_marker) {\n                    let [q1, q2] = op.id_targets;\n                    let differences = new Set();\n                    for (let t of op.id_targets) {\n                        let b1 = bases.get(t);\n                        let b2 = prevBases.get(t);\n                        if (b1 !== b2) {\n                            if (b1 !== undefined) {\n                                differences.add(b1);\n                            }\n                            if (b2 !== undefined) {\n                                differences.add(b2);\n                            }\n                        }\n                    }\n                    if (differences.size > 0) {\n                        let color = 'I';\n                        if (differences.size === 1) {\n                            color = [...differences][0];\n                        }\n                        crossings.push({q1, q2, color});\n                    }\n                }\n            }\n\n            if (bases.size > 0) {\n                result.id_layers.set(k + 0.5, new PropagatedPauliFrameLayer(bases, new Set(), []));\n            }\n            if (errors.size > 0 || crossings.length > 0) {\n                result.id_layers.set(k, new PropagatedPauliFrameLayer(new Map(), errors, crossings));\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @param {!Circuit} circuit\n     * @param {!Array<!int>} measurements\n     * @returns {!PropagatedPauliFrames}\n     */\n    static fromMeasurements(circuit, measurements) {\n        return PropagatedPauliFrames.batchFromMeasurements(circuit, [measurements])[0];\n    }\n\n    /**\n     * @param {!Circuit} circuit\n     * @param {!Array<!Array<!int>>} batchMeasurements\n     * @returns {!Array<!PropagatedPauliFrames>}\n     */\n    static batchFromMeasurements(circuit, batchMeasurements) {\n        let result = [];\n        for (let k = 0; k < batchMeasurements.length; k += 32) {\n            let batch = [];\n            for (let j = k; j < k + 32 && j < batchMeasurements.length; j++) {\n                batch.push(batchMeasurements[j]);\n            }\n            result.push(...PropagatedPauliFrames.batch32FromMeasurements(circuit, batch));\n        }\n        return result;\n    }\n\n    /**\n     * @param {!Circuit} circuit\n     * @param {!Array<!Array<!int>>} batchMeasurements\n     * @returns {!Array<!PropagatedPauliFrames>}\n     */\n    static batch32FromMeasurements(circuit, batchMeasurements) {\n        let results = [];\n        for (let k = 0; k < batchMeasurements.length; k++) {\n            results.push(new PropagatedPauliFrames(new Map()));\n        }\n\n        let frame = new PauliFrame(batchMeasurements.length, circuit.allQubits().size);\n        let measurementsBack = 0;\n        let events = [];\n        for (let k = 0; k < batchMeasurements.length; k++) {\n            for (let k2 = 0; k2 < batchMeasurements[k].length; k2++) {\n                events.push([k, batchMeasurements[k][k2]]);\n            }\n        }\n        events.sort((a, b) => a[1] - b[1]);\n\n        for (let k = circuit.layers.length - 1; k >= -1; k--) {\n            let layer = k >= 0 ? circuit.layers[k] : new Layer();\n            let targets = [...layer.id_ops.keys()];\n            targets.reverse();\n\n            for (let id of targets) {\n                let op = layer.id_ops.get(id);\n                if (op.id_targets[0] !== id) {\n                    continue;\n                }\n                frame.undo_gate(op.gate, [...op.id_targets]);\n                for (let nm = op.countMeasurements(); nm > 0; nm -= 1) {\n                    measurementsBack -= 1;\n                    let target_mask = 0;\n                    while (events.length > 0 && events[events.length - 1][1] === measurementsBack) {\n                        let ev = events[events.length - 1];\n                        events.pop();\n                        target_mask ^= 1 << ev[0];\n                    }\n                    if (target_mask === 0) {\n                        continue;\n                    }\n                    for (let t_id = 0; t_id < op.id_targets.length; t_id++) {\n                        let t = op.id_targets[t_id];\n                        let basis;\n                        if (op.gate.name === 'MX' || op.gate.name === 'MRX' || op.gate.name === 'MXX') {\n                            basis = 'X';\n                        } else if (op.gate.name === 'MY' || op.gate.name === 'MRY' || op.gate.name === 'MYY') {\n                            basis = 'Y';\n                        } else if (op.gate.name === 'M' || op.gate.name === 'MR' || op.gate.name === 'MZZ') {\n                            basis = 'Z';\n                        } else if (op.gate.name === 'MPAD') {\n                            continue;\n                        } else if (op.gate.name.startsWith('MPP:')) {\n                            basis = op.gate.name[t_id + 4];\n                        } else {\n                            throw new Error('Unhandled measurement gate: ' + op.gate.name);\n                        }\n                        if (basis === 'X') {\n                            frame.xs[t] ^= target_mask;\n                        } else if (basis === 'Y') {\n                            frame.xs[t] ^= target_mask;\n                            frame.zs[t] ^= target_mask;\n                        } else if (basis === 'Z') {\n                            frame.zs[t] ^= target_mask;\n                        } else {\n                            throw new Error('Unhandled measurement gate: ' + op.gate.name);\n                        }\n                    }\n                }\n            }\n\n            for (let t = 0; t < batchMeasurements.length; t++) {\n                let m = 1 << t;\n                let bases = new Map();\n                let errors = new Set();\n                for (let q = 0; q < frame.xs.length; q++) {\n                    let x = (frame.xs[q] & m) !== 0;\n                    let z = (frame.zs[q] & m) !== 0;\n                    if (x | z) {\n                        bases.set(q, '_XZY'[x + 2 * z]);\n                    }\n                    if (frame.flags[q] & m) {\n                        errors.add(q);\n                    }\n                }\n                if (bases.size > 0) {\n                    results[t].id_layers.set(k - 0.5, new PropagatedPauliFrameLayer(bases, new Set(), []));\n                }\n                 if (errors.size > 0) {\n                    results[t].id_layers.set(k, new PropagatedPauliFrameLayer(new Map(), errors, []));\n                }\n            }\n            for (let q = 0; q < frame.xs.length; q++) {\n                frame.flags[q] = 0;\n            }\n       }\n        return results;\n    }\n}\n\nexport {PropagatedPauliFrames, PropagatedPauliFrameLayer};\n"
  },
  {
    "path": "glue/crumble/circuit/propagated_pauli_frames.test.js",
    "content": "import {test, assertThat} from \"../test/test_util.js\"\nimport {Circuit} from \"./circuit.js\";\nimport {PropagatedPauliFrames, PropagatedPauliFrameLayer} from './propagated_pauli_frames.js';\n\ntest(\"propagated_pauli_frames.fromMeasurements\", () => {\n    let propagated = PropagatedPauliFrames.fromMeasurements(Circuit.fromStimCircuit(`\n        R 0\n        TICK\n        H 0\n        TICK\n        MX 0\n    `), [-1]);\n    assertThat(propagated).isEqualTo(new PropagatedPauliFrames(new Map([\n        [0.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'Z']]),\n            new Set(),\n            [],\n        )],\n        [1.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'X']]),\n            new Set(),\n            [],\n        )],\n    ])));\n\n    propagated = PropagatedPauliFrames.fromMeasurements(Circuit.fromStimCircuit(`\n        RX 0\n        TICK\n        H 0\n        TICK\n        MX 0\n    `), [-1]);\n    assertThat(propagated).isEqualTo(new PropagatedPauliFrames(new Map([\n        [0, new PropagatedPauliFrameLayer(\n            new Map(),\n            new Set([0]),\n            [],\n        )],\n        [0.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'Z']]),\n            new Set(),\n            [],\n        )],\n        [1.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'X']]),\n            new Set(),\n            [],\n        )],\n    ])));\n\n    propagated = PropagatedPauliFrames.fromMeasurements(Circuit.fromStimCircuit(`\n        MX 0\n        TICK\n        H 0\n        TICK\n        MX 0\n    `), [-1]);\n    assertThat(propagated).isEqualTo(new PropagatedPauliFrames(new Map([\n        [-0.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'Z']]),\n            new Set(),\n            [],\n        )],\n        [-1.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'Z']]),\n            new Set(),\n            [],\n        )],\n        [0, new PropagatedPauliFrameLayer(\n            new Map(),\n            new Set([0]),\n            [],\n        )],\n        [0.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'Z']]),\n            new Set(),\n            [],\n        )],\n        [1.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'X']]),\n            new Set(),\n            [],\n        )],\n    ])));\n\n    propagated = PropagatedPauliFrames.fromMeasurements(Circuit.fromStimCircuit(`\n        RX 0 1\n        TICK\n        CX 0 1\n        TICK\n        MX 0\n    `), [-1]);\n    assertThat(propagated).isEqualTo(new PropagatedPauliFrames(new Map([\n        [0.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'X'], [1, 'X']]),\n            new Set(),\n            [],\n        )],\n        [1.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'X']]),\n            new Set(),\n            [],\n        )],\n    ])));\n\n    propagated = PropagatedPauliFrames.fromMeasurements(Circuit.fromStimCircuit(`\n        CX 1 0\n        MX 1\n    `), [-1]);\n    assertThat(propagated).isEqualTo(new PropagatedPauliFrames(new Map([\n        [-1.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'X'], [1, 'X']]),\n            new Set(),\n            [],\n        )],\n        [-0.5, new PropagatedPauliFrameLayer(\n            new Map([[0, 'X'], [1, 'X']]),\n            new Set(),\n            [],\n        )],\n        [0.5, new PropagatedPauliFrameLayer(\n            new Map([[1, 'X']]),\n            new Set(),\n            [],\n        )],\n    ])));\n});\n"
  },
  {
    "path": "glue/crumble/crumble.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Crumble</title>\n    <link rel=\"shortcut icon\" href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABgWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kTlIA0EUhj+j4kHEwhQiFluolQFREUuNgggRQlTwKtzdnJBdw27ExlKwDVh4NF6FjbW2FraCIHiAWFpZKdpIWN8kgQQxDgzz8c/8j/f+Ad9RxrTchgGw7JwTnQppC4tLWtMrrfiAAC266WbHI5EwNdfXPXXqvAuqWrXf/bnaYnHXhDpNeMzMOjnhVeGRjVxW8Z7qwkzpMeFz4X5HGhR+VLpR4jfFySKrpgk4c9EJ4YCwlqxio4rNlGMJDwv3xCxb6vsWShxTvKnYyqyb5T7VhP64PT+rdNndTDHNDBE0DNZJkyFHUE5bFJeo3Idq+LuK/oi4DHGlMcUxyRoWetGP+oPf2bqJocFSJX8IGl8876MXmnagkPe872PPK5xA/TNc2RX/2hGMfoqer2g9h9C+BRfXFc3Yhctt6HzK6o5elOpl+xIJeD+Tb1qEjltoXS7lVr7n9AHmJKvwDewfQF9Saq/UmLu5Ord/35Tz+wHVp3JoxsjWZAAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+YKAhYQLxXIct8AAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAx0lEQVRYw+2XwQ7EIAhEB+N/E76cnkgIa6OuWTFxvTWxdRgKDwmAYu+i+KDKPP62CJjHNYsQ7Psk8iGk7AxdmeGC1e0CvBBbKQK8ljQB5kK2AxcLsJLMdoBKZvQAULMOtk5IR7Dg294+yw4RymUBs3qQ5bHAO34vC8yFPwvSBFhJ3skC35Bq1sHHsKDGKfUX94J46HllGDjd5XnI5WjOXwXQSg5X95eXaaU3zXSjG3XJ79LW1ak1RsX9/qdsldqsPTppo66k6QGRuElWZ7d4CQAAAABJRU5ErkJggg==\">\n</head>\n<style>\n    table tr {\n        border: 1px solid black;\n    }\n    table td {\n        border: 1px solid black;\n        padding-left: 5px;\n        padding-right: 5px;\n    }\n    table th {\n        border: 1px solid black;\n        padding-left: 5px;\n        padding-right: 5px;\n    }\n</style>\n<body style=\"margin: 0\">\n    <div style=\"display: inline-block\">\n        <div>\n            <div style=\"display: inline-block\">\n                Crumble is a prototype stabilizer circuit editor.<br>\n                <br>\n                <a href=\"https://github.com/quantumlib/Stim/blob/main/glue/crumble/README.md\">Read the manual</a>\n                <br>\n                <br>\n                <button id=\"btnShowExamples\">Show Example Circuits</button><br>\n                <br>\n            </div>\n            <div style=\"display: inline-block\">\n                <canvas id=\"toolbox\" style=\"width: 370px; height: 110px; border: 1px solid black; margin: 0; padding: 0;\">\n                </canvas>\n            </div>\n            <div id='examples-div' style=\"border: 1px solid black; margin: 10px; display: none; width: fit-content\">\n                <strong>Example Circuits</strong>\n                <table style=\"border: 1px solid black; margin: 10px; text-align: left; border-collapse: collapse;\">\n                    <thead>\n                        <tr>\n                            <th scope=\"col\">Code</th>\n                            <th scope=\"col\">Style</th>\n                            <th scope=\"col\">Task</th>\n                            <th scope=\"col\">Size</th>\n                            <th scope=\"col\">Link</th>\n                        </tr>\n                    </thead>\n                    <tbody>\n                        <tr>\n                            <td>Bacon-Shor Code</td>\n                            <td>Interleaved (XZXZ)</td>\n                            <td>Memory (H)</td>\n                            <td>5x5x3</td>\n                            <td><a href=\"\n                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,2)2;Q(0,3)3;Q(0,4)4;Q(1,0)5;Q(1,1)6;Q(1,2)7;Q(1,3)8;Q(1,4)9;Q(2,0)10;Q(2,1)11;Q(2,2)12;Q(2,3)13;Q(2,4)14;Q(3,0)15;Q(3,1)16;Q(3,2)17;Q(3,3)18;Q(3,4)19;Q(4,0)20;Q(4,1)21;Q(4,2)22;Q(4,3)23;Q(4,4)24;POLYGON(0,0,1,0.25)23_24;POLYGON(0,0,1,0.25)18_19;POLYGON(0,0,1,0.25)13_14;POLYGON(0,0,1,0.25)8_9;POLYGON(0,0,1,0.25)3_4;POLYGON(0,0,1,0.25)22_23;POLYGON(0,0,1,0.25)17_18;POLYGON(0,0,1,0.25)12_13;POLYGON(0,0,1,0.25)7_8;POLYGON(0,0,1,0.25)2_3;POLYGON(0,0,1,0.25)21_22;POLYGON(0,0,1,0.25)16_17;POLYGON(0,0,1,0.25)11_12;POLYGON(0,0,1,0.25)6_7;POLYGON(0,0,1,0.25)1_2;POLYGON(0,0,1,0.25)20_21;POLYGON(0,0,1,0.25)15_16;POLYGON(0,0,1,0.25)10_11;POLYGON(0,0,1,0.25)5_6;POLYGON(0,0,1,0.25)0_1;POLYGON(1,0,0,0.25)24_19;POLYGON(1,0,0,0.25)19_14;POLYGON(1,0,0,0.25)14_9;POLYGON(1,0,0,0.25)9_4;POLYGON(1,0,0,0.25)23_18;POLYGON(1,0,0,0.25)18_13;POLYGON(1,0,0,0.25)13_8;POLYGON(1,0,0,0.25)8_3;POLYGON(1,0,0,0.25)22_17;POLYGON(1,0,0,0.25)17_12;POLYGON(1,0,0,0.25)12_7;POLYGON(1,0,0,0.25)7_2;POLYGON(1,0,0,0.25)21_16;POLYGON(1,0,0,0.25)16_11;POLYGON(1,0,0,0.25)11_6;POLYGON(1,0,0,0.25)6_1;POLYGON(1,0,0,0.25)20_15;POLYGON(1,0,0,0.25)15_10;POLYGON(1,0,0,0.25)10_5;POLYGON(1,0,0,0.25)5_0;TICK;R_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24;MARKZ(0)1_2_6_7_11_12_16_17_21_22;TICK;TICK;MZZ_0_1_5_6_10_11_15_16_20_21_2_3_7_8_12_13_17_18_22_23;DT(0,0,0)rec[-10];DT(1,0,0)rec[-9];DT(2,0,0)rec[-8];DT(3,0,0)rec[-7];DT(4,0,0)rec[-6];DT(0,2,0)rec[-5];DT(1,2,0)rec[-4];DT(2,2,0)rec[-3];DT(3,2,0)rec[-2];DT(4,2,0)rec[-1];TICK;MXX_0_5_1_6_2_7_3_8_4_9_10_15_11_16_12_17_13_18_14_19;MARKX(1)10_11_12_13_14_15_16_17_18_19;TICK;MZZ_1_2_6_7_11_12_16_17_21_22_3_4_8_9_13_14_18_19_23_24;MARKZ(0)1_2_6_7_11_12_16_17_21_22;DT(4,1,1)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10];DT(4,3,1)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5];TICK;MXX_5_10_6_11_7_12_8_13_9_14_15_20_16_21_17_22_18_23_19_24;TICK;TICK;MZZ_0_1_5_6_10_11_15_16_20_21_2_3_7_8_12_13_17_18_22_23;DT(4,0,2)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(4,2,2)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MXX_0_5_1_6_2_7_3_8_4_9_10_15_11_16_12_17_13_18_14_19;MARKX(1)10_11_12_13_14_15_16_17_18_19;DT(0,4,3)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(2,4,3)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MZZ_1_2_6_7_11_12_16_17_21_22_3_4_8_9_13_14_18_19_23_24;DT(4,1,4)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(4,3,4)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MXX_5_10_6_11_7_12_8_13_9_14_15_20_16_21_17_22_18_23_19_24;DT(1,4,5)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(3,4,5)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;TICK;MZZ_0_1_5_6_10_11_15_16_20_21_2_3_7_8_12_13_17_18_22_23;DT(4,0,6)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(4,2,6)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MXX_0_5_1_6_2_7_3_8_4_9_10_15_11_16_12_17_13_18_14_19;DT(0,4,7)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(2,4,7)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MZZ_1_2_6_7_11_12_16_17_21_22_3_4_8_9_13_14_18_19_23_24;DT(4,1,8)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(4,3,8)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MXX_5_10_6_11_7_12_8_13_9_14_15_20_16_21_17_22_18_23_19_24;DT(1,4,9)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(3,4,9)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;TICK;M_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24;DT(4,0,10)rec[-4]_rec[-5]_rec[-9]_rec[-10]_rec[-14]_rec[-15]_rec[-19]_rec[-20]_rec[-24]_rec[-25]_rec[-61]_rec[-62]_rec[-63]_rec[-64]_rec[-65];DT(4,1,10)rec[-3]_rec[-4]_rec[-8]_rec[-9]_rec[-13]_rec[-14]_rec[-18]_rec[-19]_rec[-23]_rec[-24]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];DT(4,2,10)rec[-2]_rec[-3]_rec[-7]_rec[-8]_rec[-12]_rec[-13]_rec[-17]_rec[-18]_rec[-22]_rec[-23]_rec[-56]_rec[-57]_rec[-58]_rec[-59]_rec[-60];DT(4,3,10)rec[-1]_rec[-2]_rec[-6]_rec[-7]_rec[-11]_rec[-12]_rec[-16]_rec[-17]_rec[-21]_rec[-22]_rec[-36]_rec[-37]_rec[-38]_rec[-39]_rec[-40];OI(0)rec[-5]_rec[-10]_rec[-15]_rec[-20]_rec[-25]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr>\n                            <td>Color Code</td>\n                            <td>Superdense</td>\n                            <td>Memory (Z)</td>\n                            <td>5x7x3</td>\n                            <td><a href=\"\n                                #circuit=Q(0,0)0;Q(1,0)1;Q(1,1)2;Q(1,2)3;Q(2,0)4;Q(2,1)5;Q(2,2)6;Q(2,3)7;Q(3,0)8;Q(3,1)9;Q(3,2)10;Q(3,3)11;Q(3,4)12;Q(3,5)13;Q(4,0)14;Q(4,1)15;Q(4,2)16;Q(4,3)17;Q(4,4)18;Q(4,5)19;Q(4,6)20;Q(5,0)21;Q(5,1)22;Q(5,2)23;Q(5,3)24;Q(5,4)25;Q(5,5)26;Q(6,0)27;Q(6,1)28;Q(6,2)29;Q(6,3)30;Q(6,4)31;Q(7,0)32;Q(7,1)33;Q(7,2)34;Q(8,0)35;Q(8,1)36;POLYGON(0,1,1,0.25)18_26_30_24;POLYGON(0,1,1,0.25)28_34_35_32;POLYGON(0,1,1,0.25)10_16_22_14_8_5;POLYGON(1,0,1,0.25)12_18_24_16_10_7;POLYGON(1,0,1,0.25)22_28_32_14;POLYGON(1,0,1,0.25)2_5_8_0;POLYGON(1,1,0,0.25)20_26_18_12;POLYGON(1,1,0,0.25)24_30_34_28_22_16;POLYGON(1,1,0,0.25)7_10_5_2;TICK;R_0_2_5_8_14_22_28_32_35_34_24_30_10_16_7_12_18_26_20;MARKZ(0)24_30_34_28_22_16;TICK;R_4_27_36_29_6_15_17_31_19;RX_1_21_33_23_3_9_11_25_13;MARKX(1)11;MARKZ(0)31_27;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;CX_1_2_21_22_33_34_23_24_9_10_11_12_25_26_4_5_27_28_29_30_6_7_15_16_17_18_19_20;TICK;CX_1_0_21_14_33_28_23_16_9_5_11_7_25_18_4_8_27_32_29_34_6_10_15_22_17_24_19_26;TICK;CX_33_32_23_22_3_2_9_8_11_10_25_24_13_12_36_35_29_28_6_5_15_14_17_16_31_30_19_18;TICK;CX_32_33_22_23_2_3_8_9_10_11_24_25_12_13_35_36_28_29_5_6_14_15_16_17_30_31_18_19;TICK;CX_0_1_14_21_28_33_16_23_5_9_7_11_18_25_8_4_32_27_34_29_10_6_22_15_24_17_26_19;TICK;CX_2_1_22_21_34_33_24_23_10_9_12_11_26_25_5_4_28_27_30_29_7_6_16_15_18_17_20_19;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;M_4_27_36_29_6_15_17_31_19;MX_1_21_33_23_3_9_11_25_13;MARKX(1)13_9;MARKZ(0)29;DT(2,0,0)rec[-18];DT(6,0,0)rec[-17];DT(8,1,0)rec[-16];DT(6,2,0)rec[-15];DT(2,2,0)rec[-14];DT(4,1,0)rec[-13];DT(4,3,0)rec[-12];DT(6,4,0)rec[-11];DT(4,5,0)rec[-10];TICK;R_4_27_36_29_6_15_17_31_19;RX_1_21_33_23_3_9_11_25_13;MARKX(1)11;MARKZ(3)15;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;CX_1_2_21_22_33_34_23_24_9_10_11_12_25_26_4_5_27_28_29_30_6_7_15_16_17_18_19_20;TICK;CX_1_0_21_14_33_28_23_16_9_5_11_7_25_18_4_8_27_32_29_34_6_10_15_22_17_24_19_26;TICK;CX_33_32_23_22_3_2_9_8_11_10_25_24_13_12_36_35_29_28_6_5_15_14_17_16_31_30_19_18;TICK;CX_32_33_22_23_2_3_8_9_10_11_24_25_12_13_35_36_28_29_5_6_14_15_16_17_30_31_18_19;TICK;CX_0_1_14_21_28_33_16_23_5_9_7_11_18_25_8_4_32_27_34_29_10_6_22_15_24_17_26_19;TICK;CX_2_1_22_21_34_33_24_23_10_9_12_11_26_25_5_4_28_27_30_29_7_6_16_15_18_17_20_19;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;M_4_27_36_29_6_15_17_31_19;MX_1_21_33_23_3_9_11_25_13;MARKX(1)11;MARKZ(3)15;DT(2,0,1)rec[-18]_rec[-36];DT(6,0,1)rec[-17]_rec[-35];DT(8,1,1)rec[-16]_rec[-34];DT(6,2,1)rec[-15]_rec[-33];DT(2,2,1)rec[-14]_rec[-32];DT(4,1,1)rec[-13]_rec[-31];DT(4,3,1)rec[-12]_rec[-30];DT(6,4,1)rec[-11]_rec[-29];DT(4,5,1)rec[-10]_rec[-28];DT(1,2,1)rec[-9]_rec[-23]_rec[-27];DT(5,2,1)rec[-8]_rec[-24]_rec[-26];DT(7,1,1)rec[-7];DT(5,4,1)rec[-6]_rec[-20]_rec[-26];DT(1,0,1)rec[-5]_rec[-27];DT(3,3,1)rec[-4]_rec[-21];DT(3,5,1)rec[-3]_rec[-19]_rec[-22];DT(5,3,1)rec[-2]_rec[-24];DT(3,4,1)rec[-1]_rec[-21];TICK;R_4_27_36_29_6_15_17_31_19;RX_1_21_33_23_3_9_11_25_13;MARKZ(2)27;MARKZ(3)17;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;CX_1_2_21_22_33_34_23_24_9_10_11_12_25_26_4_5_27_28_29_30_6_7_15_16_17_18_19_20;TICK;CX_1_0_21_14_33_28_23_16_9_5_11_7_25_18_4_8_27_32_29_34_6_10_15_22_17_24_19_26;TICK;CX_33_32_23_22_3_2_9_8_11_10_25_24_13_12_36_35_29_28_6_5_15_14_17_16_31_30_19_18;TICK;CX_32_33_22_23_2_3_8_9_10_11_24_25_12_13_35_36_28_29_5_6_14_15_16_17_30_31_18_19;TICK;CX_0_1_14_21_28_33_16_23_5_9_7_11_18_25_8_4_32_27_34_29_10_6_22_15_24_17_26_19;TICK;CX_2_1_22_21_34_33_24_23_10_9_12_11_26_25_5_4_28_27_30_29_7_6_16_15_18_17_20_19;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;M_4_27_36_29_6_15_17_31_19;MX_1_21_33_23_3_9_11_25_13;MARKZ(3)15;DT(2,0,2)rec[-18]_rec[-36];DT(6,0,2)rec[-17]_rec[-35];DT(8,1,2)rec[-16]_rec[-34];DT(6,2,2)rec[-15]_rec[-33];DT(2,2,2)rec[-14]_rec[-32];DT(4,1,2)rec[-13]_rec[-31];DT(4,3,2)rec[-12]_rec[-30];DT(6,4,2)rec[-11]_rec[-29];DT(4,5,2)rec[-10]_rec[-28];DT(1,2,2)rec[-9]_rec[-23]_rec[-27];DT(5,2,2)rec[-8]_rec[-24]_rec[-26];DT(7,1,2)rec[-7];DT(5,4,2)rec[-6]_rec[-20]_rec[-26];DT(1,0,2)rec[-5]_rec[-27];DT(3,3,2)rec[-4]_rec[-21];DT(3,5,2)rec[-3]_rec[-19]_rec[-22];DT(5,3,2)rec[-2]_rec[-24];DT(3,4,2)rec[-1]_rec[-21];TICK;M_0_2_5_8_14_22_28_32_35_34_24_30_10_16_7_12_18_26_20;MARKZ(2)28_22_14_32;DT(2,0,3)rec[-16]_rec[-17]_rec[-18]_rec[-19]_rec[-37];DT(6,0,3)rec[-12]_rec[-13]_rec[-14]_rec[-15]_rec[-36];DT(8,1,3)rec[-10]_rec[-11]_rec[-12]_rec[-13]_rec[-35];DT(6,2,3)rec[-6]_rec[-8]_rec[-9]_rec[-10]_rec[-13]_rec[-14]_rec[-34];DT(4,1,3)rec[-6]_rec[-7]_rec[-14]_rec[-15]_rec[-16]_rec[-17]_rec[-32];DT(2,2,3)rec[-5]_rec[-7]_rec[-17]_rec[-18]_rec[-33];DT(4,3,3)rec[-3]_rec[-4]_rec[-5]_rec[-6]_rec[-7]_rec[-9]_rec[-31];DT(6,4,3)rec[-2]_rec[-3]_rec[-8]_rec[-9]_rec[-30];DT(4,5,3)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-29];OI(0)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-11]_rec[-12]_rec[-13]_rec[-14]_rec[-15]_rec[-16]_rec[-17]_rec[-18]_rec[-19]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr>\n                            <td>Honeycomb Code</td>\n                            <td>YXZ-YZX</td>\n                            <td>Memory (H)</td>\n                            <td>7x9x3</td>\n                            <td><a href=\"\n                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,5)2;Q(0,6)3;Q(0,7)4;Q(1,0)5;Q(1,1)6;Q(1,2)7;Q(1,3)8;Q(1,4)9;Q(1,5)10;Q(1,6)11;Q(1,7)12;Q(1,8)13;Q(2,0)14;Q(2,1)15;Q(2,2)16;Q(2,3)17;Q(2,4)18;Q(2,5)19;Q(2,6)20;Q(2,7)21;Q(2,8)22;Q(3,0)23;Q(3,1)24;Q(3,2)25;Q(3,3)26;Q(3,4)27;Q(3,5)28;Q(3,6)29;Q(3,7)30;Q(3,8)31;Q(4,0)32;Q(4,1)33;Q(4,2)34;Q(4,3)35;Q(4,4)36;Q(4,5)37;Q(4,6)38;Q(4,7)39;Q(4,8)40;Q(5,0)41;Q(5,1)42;Q(5,2)43;Q(5,3)44;Q(5,4)45;Q(5,5)46;Q(5,6)47;Q(5,7)48;Q(5,8)49;Q(6,2)50;Q(6,3)51;Q(6,4)52;Q(6,8)53;POLYGON(0,0,1,0.25)11_20_21_22_13_12;POLYGON(0,0,1,0.25)17_26_27_28_19_18;POLYGON(0,0,1,0.25)5_14_15_16_7_6;POLYGON(0,0,1,0.25)29_38_39_40_31_30;POLYGON(0,0,1,0.25)35_44_45_46_37_36;POLYGON(0,0,1,0.25)48_47_53_49;POLYGON(0,0,1,0.25)8_9_10_2;POLYGON(0,0,1,0.25)23_32_33_34_25_24;POLYGON(0,0,1,0.25)42_41_50_43;POLYGON(0,1,0,0.25)9_18_19_20_11_10;POLYGON(0,1,0,0.25)15_24_25_26_17_16;POLYGON(0,1,0,0.25)27_36_37_38_29_28;POLYGON(0,1,0,0.25)21_30_31_22;POLYGON(0,1,0,0.25)39_48_49_40;POLYGON(0,1,0,0.25)45_52_47_46;POLYGON(0,1,0,0.25)4_12_13;POLYGON(0,1,0,0.25)1_6_7_8;POLYGON(0,1,0,0.25)33_42_43_44_35_34;POLYGON(0,1,0,0.25)14_5;POLYGON(0,1,0,0.25)32_23;POLYGON(1,0,0,0.25)2_10_11_12_4_3;POLYGON(1,0,0,0.25)19_28_29_30_21_20;POLYGON(1,0,0,0.25)7_16_17_18_9_8;POLYGON(1,0,0,0.25)25_34_35_36_27_26;POLYGON(1,0,0,0.25)43_50_51_52_45_44;POLYGON(1,0,0,0.25)37_46_47_48_39_38;POLYGON(1,0,0,0.25)22_13;POLYGON(1,0,0,0.25)40_31;POLYGON(1,0,0,0.25)53_49;POLYGON(1,0,0,0.25)0_5_6_1;POLYGON(1,0,0,0.25)14_23_24_15;POLYGON(1,0,0,0.25)32_41_42_33;TICK;R_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40_41_42_43_44_45_46_47_48_49_50_51_52_53;MARKZ(0)8_9_17_18_26_27_35_36_44_45_51_52;TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;MARKY(0)8_9_17_18_26_27_35_36_44_45_51_52;TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,0,0)rec[-32]_rec[-33]_rec[-49];DT(0,6,0)rec[-29]_rec[-30]_rec[-40];DT(6,3,0)rec[-25]_rec[-27]_rec[-55];DT(5,8,0)rec[-21]_rec[-22]_rec[-23]_rec[-34]_rec[-41];DT(0,5,0)rec[-20]_rec[-28]_rec[-31]_rec[-37]_rec[-60];DT(5,2,0)rec[-9]_rec[-24]_rec[-26]_rec[-46]_rec[-50];DT(1,8,0)rec[-7]_rec[-8]_rec[-15]_rec[-39]_rec[-44]_rec[-45];DT(3,8,0)rec[-5]_rec[-6]_rec[-14]_rec[-38]_rec[-42]_rec[-43];DT(1,2,0)rec[-4]_rec[-12]_rec[-13]_rec[-48]_rec[-53]_rec[-54];DT(3,2,0)rec[-3]_rec[-10]_rec[-11]_rec[-47]_rec[-51]_rec[-52];DT(2,5,0)rec[-2]_rec[-18]_rec[-19]_rec[-36]_rec[-58]_rec[-59];DT(4,5,0)rec[-1]_rec[-16]_rec[-17]_rec[-35]_rec[-56]_rec[-57];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,1)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-108]_rec[-119]_rec[-120];DT(3,2,1)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-107]_rec[-117]_rec[-118];DT(5,2,1)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-106]_rec[-115]_rec[-116];DT(0,5,1)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-97]_rec[-100]_rec[-105];DT(2,5,1)rec[-3]_rec[-10]_rec[-11]_rec[-43]_rec[-47]_rec[-48]_rec[-96]_rec[-103]_rec[-104];DT(4,5,1)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-95]_rec[-101]_rec[-102];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,8,2)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,2)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,2)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,2)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,2)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,2)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,2)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,2)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,2)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,2)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,2)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,2)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,6,3)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,3)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,3)rec[-16]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,3)rec[-15]_rec[-19]_rec[-20]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,3)rec[-14]_rec[-17]_rec[-18]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,3)rec[-13]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,3)rec[-2]_rec[-11]_rec[-12]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,3)rec[-1]_rec[-9]_rec[-10]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,4)rec[-15]_rec[-20]_rec[-21]_rec[-31]_rec[-39]_rec[-40]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,4)rec[-14]_rec[-18]_rec[-19]_rec[-30]_rec[-37]_rec[-38]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,4)rec[-6]_rec[-11]_rec[-12]_rec[-34]_rec[-35]_rec[-42]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,4)rec[-5]_rec[-9]_rec[-10]_rec[-32]_rec[-33]_rec[-41]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,4)rec[-3]_rec[-25]_rec[-26]_rec[-29]_rec[-45]_rec[-46]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,4)rec[-2]_rec[-23]_rec[-24]_rec[-28]_rec[-43]_rec[-44]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,1,5)rec[-32]_rec[-33]_rec[-92]_rec[-93];DT(0,7,5)rec[-29]_rec[-30]_rec[-89]_rec[-90];DT(6,4,5)rec[-25]_rec[-27]_rec[-85]_rec[-87];DT(5,7,5)rec[-21]_rec[-22]_rec[-23]_rec[-81]_rec[-82]_rec[-83];DT(1,4,5)rec[-20]_rec[-28]_rec[-31]_rec[-80]_rec[-88]_rec[-91];DT(5,1,5)rec[-9]_rec[-24]_rec[-26]_rec[-69]_rec[-84]_rec[-86];DT(2,7,5)rec[-7]_rec[-8]_rec[-15]_rec[-67]_rec[-68]_rec[-75];DT(4,7,5)rec[-5]_rec[-6]_rec[-14]_rec[-65]_rec[-66]_rec[-74];DT(1,0,5)rec[-4]_rec[-12]_rec[-13]_rec[-64]_rec[-72]_rec[-73];DT(3,0,5)rec[-3]_rec[-10]_rec[-11]_rec[-63]_rec[-70]_rec[-71];DT(2,3,5)rec[-2]_rec[-18]_rec[-19]_rec[-62]_rec[-78]_rec[-79];DT(4,3,5)rec[-1]_rec[-16]_rec[-17]_rec[-61]_rec[-76]_rec[-77];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,0,6)rec[-31]_rec[-32]_rec[-37]_rec[-97]_rec[-157]_rec[-158];DT(4,0,6)rec[-29]_rec[-30]_rec[-36]_rec[-96]_rec[-155]_rec[-156];DT(2,7,6)rec[-16]_rec[-25]_rec[-26]_rec[-39]_rec[-40]_rec[-99]_rec[-100]_rec[-142]_rec[-151]_rec[-152];DT(4,7,6)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54]_rec[-98]_rec[-114]_rec[-139]_rec[-149]_rec[-150];DT(2,1,6)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45]_rec[-95]_rec[-104]_rec[-105]_rec[-132]_rec[-137]_rec[-138];DT(4,1,6)rec[-4]_rec[-9]_rec[-10]_rec[-34]_rec[-42]_rec[-43]_rec[-94]_rec[-102]_rec[-103]_rec[-130]_rec[-135]_rec[-136];DT(1,4,6)rec[-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53]_rec[-108]_rec[-112]_rec[-113]_rec[-129]_rec[-143]_rec[-147];DT(3,4,6)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51]_rec[-107]_rec[-110]_rec[-111]_rec[-128]_rec[-145]_rec[-146];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,7)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-156]_rec[-160]_rec[-165]_rec[-201]_rec[-212]_rec[-213];DT(3,2,7)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-155]_rec[-163]_rec[-164]_rec[-200]_rec[-210]_rec[-211];DT(5,2,7)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-154]_rec[-161]_rec[-162]_rec[-199]_rec[-208]_rec[-209];DT(0,5,7)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-167]_rec[-168]_rec[-170]_rec[-190]_rec[-193]_rec[-198];DT(2,5,7)rec[-3]_rec[-10]_rec[-11]_rec[-43]_rec[-47]_rec[-48]_rec[-169]_rec[-173]_rec[-174]_rec[-189]_rec[-196]_rec[-197];DT(4,5,7)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-166]_rec[-171]_rec[-172]_rec[-188]_rec[-194]_rec[-195];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,8,8)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,8)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,8)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,8)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,8)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,8)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,8)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,8)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,8)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,8)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,8)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,8)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,6,9)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,9)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,9)rec[-16]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,9)rec[-15]_rec[-19]_rec[-20]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,9)rec[-14]_rec[-17]_rec[-18]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,9)rec[-13]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,9)rec[-2]_rec[-11]_rec[-12]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,9)rec[-1]_rec[-9]_rec[-10]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,10)rec[-15]_rec[-20]_rec[-21]_rec[-31]_rec[-39]_rec[-40]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,10)rec[-14]_rec[-18]_rec[-19]_rec[-30]_rec[-37]_rec[-38]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,10)rec[-6]_rec[-11]_rec[-12]_rec[-34]_rec[-35]_rec[-42]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,10)rec[-5]_rec[-9]_rec[-10]_rec[-32]_rec[-33]_rec[-41]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,10)rec[-3]_rec[-25]_rec[-26]_rec[-29]_rec[-45]_rec[-46]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,10)rec[-2]_rec[-23]_rec[-24]_rec[-28]_rec[-43]_rec[-44]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,1,11)rec[-32]_rec[-33]_rec[-92]_rec[-93];DT(0,7,11)rec[-29]_rec[-30]_rec[-89]_rec[-90];DT(6,4,11)rec[-25]_rec[-27]_rec[-85]_rec[-87];DT(5,7,11)rec[-21]_rec[-22]_rec[-23]_rec[-81]_rec[-82]_rec[-83];DT(1,4,11)rec[-20]_rec[-28]_rec[-31]_rec[-80]_rec[-88]_rec[-91];DT(5,1,11)rec[-9]_rec[-24]_rec[-26]_rec[-69]_rec[-84]_rec[-86];DT(2,7,11)rec[-7]_rec[-8]_rec[-15]_rec[-67]_rec[-68]_rec[-75];DT(4,7,11)rec[-5]_rec[-6]_rec[-14]_rec[-65]_rec[-66]_rec[-74];DT(1,0,11)rec[-4]_rec[-12]_rec[-13]_rec[-64]_rec[-72]_rec[-73];DT(3,0,11)rec[-3]_rec[-10]_rec[-11]_rec[-63]_rec[-70]_rec[-71];DT(2,3,11)rec[-2]_rec[-18]_rec[-19]_rec[-62]_rec[-78]_rec[-79];DT(4,3,11)rec[-1]_rec[-16]_rec[-17]_rec[-61]_rec[-76]_rec[-77];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,0,12)rec[-31]_rec[-32]_rec[-37]_rec[-97]_rec[-157]_rec[-158];DT(4,0,12)rec[-29]_rec[-30]_rec[-36]_rec[-96]_rec[-155]_rec[-156];DT(2,7,12)rec[-16]_rec[-25]_rec[-26]_rec[-39]_rec[-40]_rec[-99]_rec[-100]_rec[-142]_rec[-151]_rec[-152];DT(4,7,12)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54]_rec[-98]_rec[-114]_rec[-139]_rec[-149]_rec[-150];DT(2,1,12)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45]_rec[-95]_rec[-104]_rec[-105]_rec[-132]_rec[-137]_rec[-138];DT(4,1,12)rec[-4]_rec[-9]_rec[-10]_rec[-34]_rec[-42]_rec[-43]_rec[-94]_rec[-102]_rec[-103]_rec[-130]_rec[-135]_rec[-136];DT(1,4,12)rec[-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53]_rec[-108]_rec[-112]_rec[-113]_rec[-129]_rec[-143]_rec[-147];DT(3,4,12)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51]_rec[-107]_rec[-110]_rec[-111]_rec[-128]_rec[-145]_rec[-146];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,13)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-156]_rec[-160]_rec[-165]_rec[-201]_rec[-212]_rec[-213];DT(3,2,13)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-155]_rec[-163]_rec[-164]_rec[-200]_rec[-210]_rec[-211];DT(5,2,13)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-154]_rec[-161]_rec[-162]_rec[-199]_rec[-208]_rec[-209];DT(0,5,13)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-167]_rec[-168]_rec[-170]_rec[-190]_rec[-193]_rec[-198];DT(2,5,13)rec[-3]_rec[-10]_rec[-11]_rec[-43]_rec[-47]_rec[-48]_rec[-169]_rec[-173]_rec[-174]_rec[-189]_rec[-196]_rec[-197];DT(4,5,13)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-166]_rec[-171]_rec[-172]_rec[-188]_rec[-194]_rec[-195];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,8,14)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,14)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,14)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,14)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,14)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,14)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,14)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,14)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,14)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,14)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,14)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,14)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44_48_49;MARKX(0)8_17_26_35_44_51;DT(0,6,15)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,15)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,15)rec[-17]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,15)rec[-16]_rec[-20]_rec[-21]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,15)rec[-15]_rec[-18]_rec[-19]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,15)rec[-14]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,15)rec[-3]_rec[-12]_rec[-13]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,15)rec[-2]_rec[-10]_rec[-11]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;MARKY(0)9_18_27_36_45_52_8_17_26_35_44_51;DT(1,2,16)rec[-15]_rec[-20]_rec[-21]_rec[-32]_rec[-40]_rec[-41]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,16)rec[-14]_rec[-18]_rec[-19]_rec[-31]_rec[-38]_rec[-39]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,16)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-36]_rec[-43]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,16)rec[-5]_rec[-9]_rec[-10]_rec[-33]_rec[-34]_rec[-42]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,16)rec[-3]_rec[-25]_rec[-26]_rec[-30]_rec[-46]_rec[-47]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,16)rec[-2]_rec[-23]_rec[-24]_rec[-29]_rec[-44]_rec[-45]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;M_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40_41_42_43_44_45_46_47_48_49_50_51_52_53;MARKZ(0)8_9_17_18_26_27_35_36_44_45_51_52;DT(0,1,17)rec[-53]_rec[-54]_rec[-70]_rec[-113]_rec[-114];DT(0,7,17)rec[-50]_rec[-51]_rec[-61]_rec[-110]_rec[-111];DT(1,4,17)rec[-44]_rec[-45]_rec[-46]_rec[-52]_rec[-58]_rec[-81]_rec[-102]_rec[-109]_rec[-112];DT(0,5,17)rec[-42]_rec[-43]_rec[-44]_rec[-50]_rec[-51]_rec[-52]_rec[-58]_rec[-61]_rec[-66]_rec[-128]_rec[-129]_rec[-131]_rec[-151]_rec[-154]_rec[-159];DT(1,0,17)rec[-38]_rec[-39]_rec[-40]_rec[-47]_rec[-48]_rec[-49]_rec[-69]_rec[-74]_rec[-75]_rec[-86]_rec[-94]_rec[-95];DT(1,2,17)rec[-36]_rec[-37]_rec[-38]_rec[-45]_rec[-46]_rec[-47]_rec[-69]_rec[-80]_rec[-81]_rec[-117]_rec[-121]_rec[-126]_rec[-162]_rec[-173]_rec[-174];DT(2,7,17)rec[-32]_rec[-33]_rec[-34]_rec[-41]_rec[-42]_rec[-43]_rec[-60]_rec[-65]_rec[-66]_rec[-89]_rec[-90]_rec[-97];DT(2,3,17)rec[-26]_rec[-27]_rec[-28]_rec[-35]_rec[-36]_rec[-37]_rec[-57]_rec[-79]_rec[-80]_rec[-84]_rec[-100]_rec[-101];DT(2,5,17)rec[-24]_rec[-25]_rec[-26]_rec[-33]_rec[-34]_rec[-35]_rec[-57]_rec[-64]_rec[-65]_rec[-130]_rec[-134]_rec[-135]_rec[-150]_rec[-157]_rec[-158];DT(3,0,17)rec[-20]_rec[-21]_rec[-22]_rec[-29]_rec[-30]_rec[-31]_rec[-68]_rec[-72]_rec[-73]_rec[-85]_rec[-92]_rec[-93];DT(3,2,17)rec[-18]_rec[-19]_rec[-20]_rec[-27]_rec[-28]_rec[-29]_rec[-68]_rec[-78]_rec[-79]_rec[-116]_rec[-124]_rec[-125]_rec[-161]_rec[-171]_rec[-172];DT(4,7,17)rec[-14]_rec[-15]_rec[-16]_rec[-23]_rec[-24]_rec[-25]_rec[-59]_rec[-63]_rec[-64]_rec[-87]_rec[-88]_rec[-96];DT(4,3,17)rec[-8]_rec[-9]_rec[-10]_rec[-17]_rec[-18]_rec[-19]_rec[-56]_rec[-77]_rec[-78]_rec[-83]_rec[-98]_rec[-99];DT(4,5,17)rec[-6]_rec[-7]_rec[-8]_rec[-15]_rec[-16]_rec[-17]_rec[-56]_rec[-62]_rec[-63]_rec[-127]_rec[-132]_rec[-133]_rec[-149]_rec[-155]_rec[-156];DT(5,1,17)rec[-4]_rec[-11]_rec[-12]_rec[-13]_rec[-67]_rec[-71]_rec[-91]_rec[-105]_rec[-107];DT(6,4,17)rec[-2]_rec[-3]_rec[-76]_rec[-106]_rec[-108];DT(5,2,17)rec[-2]_rec[-3]_rec[-4]_rec[-9]_rec[-10]_rec[-11]_rec[-67]_rec[-76]_rec[-77]_rec[-115]_rec[-122]_rec[-123]_rec[-160]_rec[-169]_rec[-170];DT(5,7,17)rec[-1]_rec[-5]_rec[-6]_rec[-7]_rec[-55]_rec[-62]_rec[-82]_rec[-103]_rec[-104];OI(0)rec[-2]_rec[-3]_rec[-9]_rec[-10]_rec[-18]_rec[-19]_rec[-27]_rec[-28]_rec[-36]_rec[-37]_rec[-45]_rec[-46]_rec[-76]_rec[-77]_rec[-78]_rec[-79]_rec[-80]_rec[-81]_rec[-83]_rec[-84]_rec[-108]_rec[-109]_rec[-115]_rec[-116]_rec[-117]_rec[-175]_rec[-176]_rec[-177]_rec[-208]_rec[-209]_rec[-234]_rec[-235]_rec[-268]_rec[-269]_rec[-294]_rec[-295]_rec[-301]_rec[-302]_rec[-303]_rec[-361]_rec[-362]_rec[-363]_rec[-394]_rec[-395]_rec[-420]_rec[-421]_rec[-454]_rec[-455]_rec[-480]_rec[-481]_rec[-487]_rec[-488]_rec[-489]_rec[-547]_rec[-548]_rec[-549]_rec[-580]_rec[-581]_rec[-606]_rec[-607]_rec[-634]_rec[-635]_rec[-636]_rec[-637]_rec[-638]_rec[-639]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr>\n                            <td>Honeycomb Code</td>\n                            <td>YXZ-YZX</td>\n                            <td>Memory (V)</td>\n                            <td>7x9x3</td>\n                            <td><a href=\"\n                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,5)2;Q(0,6)3;Q(0,7)4;Q(1,0)5;Q(1,1)6;Q(1,2)7;Q(1,3)8;Q(1,4)9;Q(1,5)10;Q(1,6)11;Q(1,7)12;Q(1,8)13;Q(2,0)14;Q(2,1)15;Q(2,2)16;Q(2,3)17;Q(2,4)18;Q(2,5)19;Q(2,6)20;Q(2,7)21;Q(2,8)22;Q(3,0)23;Q(3,1)24;Q(3,2)25;Q(3,3)26;Q(3,4)27;Q(3,5)28;Q(3,6)29;Q(3,7)30;Q(3,8)31;Q(4,0)32;Q(4,1)33;Q(4,2)34;Q(4,3)35;Q(4,4)36;Q(4,5)37;Q(4,6)38;Q(4,7)39;Q(4,8)40;Q(5,0)41;Q(5,1)42;Q(5,2)43;Q(5,3)44;Q(5,4)45;Q(5,5)46;Q(5,6)47;Q(5,7)48;Q(5,8)49;Q(6,2)50;Q(6,3)51;Q(6,4)52;Q(6,8)53;POLYGON(0,0,1,0.25)11_20_21_22_13_12;POLYGON(0,0,1,0.25)17_26_27_28_19_18;POLYGON(0,0,1,0.25)5_14_15_16_7_6;POLYGON(0,0,1,0.25)29_38_39_40_31_30;POLYGON(0,0,1,0.25)35_44_45_46_37_36;POLYGON(0,0,1,0.25)48_47_53_49;POLYGON(0,0,1,0.25)8_9_10_2;POLYGON(0,0,1,0.25)23_32_33_34_25_24;POLYGON(0,0,1,0.25)42_41_50_43;POLYGON(0,1,0,0.25)9_18_19_20_11_10;POLYGON(0,1,0,0.25)15_24_25_26_17_16;POLYGON(0,1,0,0.25)27_36_37_38_29_28;POLYGON(0,1,0,0.25)21_30_31_22;POLYGON(0,1,0,0.25)39_48_49_40;POLYGON(0,1,0,0.25)45_52_47_46;POLYGON(0,1,0,0.25)4_12_13;POLYGON(0,1,0,0.25)1_6_7_8;POLYGON(0,1,0,0.25)33_42_43_44_35_34;POLYGON(0,1,0,0.25)14_5;POLYGON(0,1,0,0.25)32_23;POLYGON(1,0,0,0.25)2_10_11_12_4_3;POLYGON(1,0,0,0.25)19_28_29_30_21_20;POLYGON(1,0,0,0.25)7_16_17_18_9_8;POLYGON(1,0,0,0.25)25_34_35_36_27_26;POLYGON(1,0,0,0.25)43_50_51_52_45_44;POLYGON(1,0,0,0.25)37_46_47_48_39_38;POLYGON(1,0,0,0.25)22_13;POLYGON(1,0,0,0.25)40_31;POLYGON(1,0,0,0.25)53_49;POLYGON(1,0,0,0.25)0_5_6_1;POLYGON(1,0,0,0.25)14_23_24_15;POLYGON(1,0,0,0.25)32_41_42_33;TICK;RY_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40_41_42_43_44_45_46_47_48_49_50_51_52_53;MARKY(0)24_25_27_28_30_31;TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,3,0)rec[-27];DT(2,3,0)rec[-26];DT(3,3,0)rec[-25];DT(4,3,0)rec[-24];DT(5,3,0)rec[-23];DT(6,3,0)rec[-22];DT(1,0,0)rec[-21];DT(2,0,0)rec[-20];DT(3,0,0)rec[-19];DT(4,0,0)rec[-18];DT(5,0,0)rec[-17];DT(0,0,0)rec[-16];DT(1,2,0)rec[-15];DT(3,2,0)rec[-14];DT(5,2,0)rec[-13];DT(1,6,0)rec[-12];DT(2,6,0)rec[-11];DT(3,6,0)rec[-10];DT(4,6,0)rec[-9];DT(5,6,0)rec[-8];DT(0,6,0)rec[-7];DT(1,8,0)rec[-6];DT(3,8,0)rec[-5];DT(0,5,0)rec[-4];DT(2,5,0)rec[-3];DT(4,5,0)rec[-2];DT(5,8,0)rec[-1];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(1,0,1)rec[-31]_rec[-32]_rec[-37];DT(3,0,1)rec[-29]_rec[-30]_rec[-36];DT(3,7,1)rec[-16]_rec[-25]_rec[-26]_rec[-39]_rec[-40];DT(4,7,1)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54];DT(2,3,1)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45];DT(4,3,1)rec[-4]_rec[-9]_rec[-10]_rec[-34]_rec[-42]_rec[-43];DT(1,6,1)rec[-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53];DT(3,6,1)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,8,2)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,2)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,2)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,2)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,2)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,2)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,2)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,2)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,2)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,2)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,2)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,2)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;DT(0,6,3)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,3)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,3)rec[-16]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,3)rec[-15]_rec[-19]_rec[-20]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,3)rec[-14]_rec[-17]_rec[-18]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,3)rec[-13]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,3)rec[-2]_rec[-11]_rec[-12]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,3)rec[-1]_rec[-9]_rec[-10]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,4)rec[-15]_rec[-20]_rec[-21]_rec[-31]_rec[-39]_rec[-40]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,4)rec[-14]_rec[-18]_rec[-19]_rec[-30]_rec[-37]_rec[-38]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,4)rec[-6]_rec[-11]_rec[-12]_rec[-34]_rec[-35]_rec[-42]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,4)rec[-5]_rec[-9]_rec[-10]_rec[-32]_rec[-33]_rec[-41]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,4)rec[-3]_rec[-25]_rec[-26]_rec[-29]_rec[-45]_rec[-46]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,4)rec[-2]_rec[-23]_rec[-24]_rec[-28]_rec[-43]_rec[-44]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;DT(0,1,5)rec[-32]_rec[-33]_rec[-92]_rec[-93];DT(0,7,5)rec[-29]_rec[-30]_rec[-89]_rec[-90];DT(6,4,5)rec[-25]_rec[-27]_rec[-85]_rec[-87];DT(5,7,5)rec[-21]_rec[-22]_rec[-23]_rec[-81]_rec[-82]_rec[-83];DT(1,4,5)rec[-20]_rec[-28]_rec[-31]_rec[-80]_rec[-88]_rec[-91];DT(5,1,5)rec[-9]_rec[-24]_rec[-26]_rec[-69]_rec[-84]_rec[-86];DT(2,7,5)rec[-7]_rec[-8]_rec[-15]_rec[-67]_rec[-68]_rec[-75];DT(4,7,5)rec[-5]_rec[-6]_rec[-14]_rec[-65]_rec[-66]_rec[-74];DT(1,0,5)rec[-4]_rec[-12]_rec[-13]_rec[-64]_rec[-72]_rec[-73];DT(3,0,5)rec[-3]_rec[-10]_rec[-11]_rec[-63]_rec[-70]_rec[-71];DT(2,3,5)rec[-2]_rec[-18]_rec[-19]_rec[-62]_rec[-78]_rec[-79];DT(4,3,5)rec[-1]_rec[-16]_rec[-17]_rec[-61]_rec[-76]_rec[-77];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,0,6)rec[-31]_rec[-32]_rec[-37]_rec[-97]_rec[-157]_rec[-158];DT(4,0,6)rec[-29]_rec[-30]_rec[-36]_rec[-96]_rec[-155]_rec[-156];DT(2,7,6)rec[-16]_rec[-25]_rec[-26]_rec[-39]_rec[-40]_rec[-99]_rec[-100]_rec[-142]_rec[-151]_rec[-152];DT(4,7,6)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54]_rec[-98]_rec[-114]_rec[-139]_rec[-149]_rec[-150];DT(2,1,6)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45]_rec[-95]_rec[-104]_rec[-105]_rec[-132]_rec[-137]_rec[-138];DT(4,1,6)rec[-4]_rec[-9]_rec[-10]_rec[-34]_rec[-42]_rec[-43]_rec[-94]_rec[-102]_rec[-103]_rec[-130]_rec[-135]_rec[-136];DT(1,4,6)rec[-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53]_rec[-108]_rec[-112]_rec[-113]_rec[-129]_rec[-143]_rec[-147];DT(3,4,6)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51]_rec[-107]_rec[-110]_rec[-111]_rec[-128]_rec[-145]_rec[-146];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,7)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-156]_rec[-160]_rec[-165]_rec[-201]_rec[-212]_rec[-213];DT(3,2,7)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-155]_rec[-163]_rec[-164]_rec[-200]_rec[-210]_rec[-211];DT(5,2,7)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-154]_rec[-161]_rec[-162]_rec[-199]_rec[-208]_rec[-209];DT(0,5,7)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-167]_rec[-168]_rec[-170]_rec[-190]_rec[-193]_rec[-198];DT(2,5,7)rec[-3]_rec[-10]_rec[-11]_rec[-43]_rec[-47]_rec[-48]_rec[-169]_rec[-173]_rec[-174]_rec[-189]_rec[-196]_rec[-197];DT(4,5,7)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-166]_rec[-171]_rec[-172]_rec[-188]_rec[-194]_rec[-195];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,8,8)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,8)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,8)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,8)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,8)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,8)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,8)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,8)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,8)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,8)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,8)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,8)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;DT(0,6,9)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,9)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,9)rec[-16]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,9)rec[-15]_rec[-19]_rec[-20]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,9)rec[-14]_rec[-17]_rec[-18]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,9)rec[-13]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,9)rec[-2]_rec[-11]_rec[-12]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,9)rec[-1]_rec[-9]_rec[-10]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,10)rec[-15]_rec[-20]_rec[-21]_rec[-31]_rec[-39]_rec[-40]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,10)rec[-14]_rec[-18]_rec[-19]_rec[-30]_rec[-37]_rec[-38]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,10)rec[-6]_rec[-11]_rec[-12]_rec[-34]_rec[-35]_rec[-42]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,10)rec[-5]_rec[-9]_rec[-10]_rec[-32]_rec[-33]_rec[-41]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,10)rec[-3]_rec[-25]_rec[-26]_rec[-29]_rec[-45]_rec[-46]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,10)rec[-2]_rec[-23]_rec[-24]_rec[-28]_rec[-43]_rec[-44]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;DT(0,1,11)rec[-32]_rec[-33]_rec[-92]_rec[-93];DT(0,7,11)rec[-29]_rec[-30]_rec[-89]_rec[-90];DT(6,4,11)rec[-25]_rec[-27]_rec[-85]_rec[-87];DT(5,7,11)rec[-21]_rec[-22]_rec[-23]_rec[-81]_rec[-82]_rec[-83];DT(1,4,11)rec[-20]_rec[-28]_rec[-31]_rec[-80]_rec[-88]_rec[-91];DT(5,1,11)rec[-9]_rec[-24]_rec[-26]_rec[-69]_rec[-84]_rec[-86];DT(2,7,11)rec[-7]_rec[-8]_rec[-15]_rec[-67]_rec[-68]_rec[-75];DT(4,7,11)rec[-5]_rec[-6]_rec[-14]_rec[-65]_rec[-66]_rec[-74];DT(1,0,11)rec[-4]_rec[-12]_rec[-13]_rec[-64]_rec[-72]_rec[-73];DT(3,0,11)rec[-3]_rec[-10]_rec[-11]_rec[-63]_rec[-70]_rec[-71];DT(2,3,11)rec[-2]_rec[-18]_rec[-19]_rec[-62]_rec[-78]_rec[-79];DT(4,3,11)rec[-1]_rec[-16]_rec[-17]_rec[-61]_rec[-76]_rec[-77];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,0,12)rec[-31]_rec[-32]_rec[-37]_rec[-97]_rec[-157]_rec[-158];DT(4,0,12)rec[-29]_rec[-30]_rec[-36]_rec[-96]_rec[-155]_rec[-156];DT(2,7,12)rec[-16]_rec[-25]_rec[-26]_rec[-39]_rec[-40]_rec[-99]_rec[-100]_rec[-142]_rec[-151]_rec[-152];DT(4,7,12)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54]_rec[-98]_rec[-114]_rec[-139]_rec[-149]_rec[-150];DT(2,1,12)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45]_rec[-95]_rec[-104]_rec[-105]_rec[-132]_rec[-137]_rec[-138];DT(4,1,12)rec[-4]_rec[-9]_rec[-10]_rec[-34]_rec[-42]_rec[-43]_rec[-94]_rec[-102]_rec[-103]_rec[-130]_rec[-135]_rec[-136];DT(1,4,12)rec[-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53]_rec[-108]_rec[-112]_rec[-113]_rec[-129]_rec[-143]_rec[-147];DT(3,4,12)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51]_rec[-107]_rec[-110]_rec[-111]_rec[-128]_rec[-145]_rec[-146];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,13)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-156]_rec[-160]_rec[-165]_rec[-201]_rec[-212]_rec[-213];DT(3,2,13)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-155]_rec[-163]_rec[-164]_rec[-200]_rec[-210]_rec[-211];DT(5,2,13)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-154]_rec[-161]_rec[-162]_rec[-199]_rec[-208]_rec[-209];DT(0,5,13)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-167]_rec[-168]_rec[-170]_rec[-190]_rec[-193]_rec[-198];DT(2,5,13)rec[-3]_rec[-10]_rec[-11]_rec[-43]_rec[-47]_rec[-48]_rec[-169]_rec[-173]_rec[-174]_rec[-189]_rec[-196]_rec[-197];DT(4,5,13)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-166]_rec[-171]_rec[-172]_rec[-188]_rec[-194]_rec[-195];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,8,14)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,14)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,14)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,14)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,14)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,14)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,14)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,14)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,14)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,14)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,14)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,14)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44_48_49;MARKX(0)24_25_27_28_30_31;DT(0,6,15)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,15)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,15)rec[-17]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,15)rec[-16]_rec[-20]_rec[-21]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,15)rec[-15]_rec[-18]_rec[-19]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,15)rec[-14]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,15)rec[-3]_rec[-12]_rec[-13]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,15)rec[-2]_rec[-10]_rec[-11]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MY_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40_41_42_43_44_45_46_47_48_49_50_51_52_53;MARKY(0)24_25_27_28_30_31;DT(2,0,16)rec[-40]_rec[-49]_rec[-59]_rec[-118]_rec[-119];DT(1,2,16)rec[-38]_rec[-39]_rec[-40]_rec[-47]_rec[-48]_rec[-49]_rec[-59]_rec[-67]_rec[-68]_rec[-184]_rec[-192]_rec[-193]_rec[-228]_rec[-233]_rec[-234];DT(1,4,16)rec[-34]_rec[-35]_rec[-36]_rec[-43]_rec[-44]_rec[-45]_rec[-70]_rec[-74]_rec[-75]_rec[-90]_rec[-104]_rec[-108];DT(1,8,16)rec[-32]_rec[-33]_rec[-34]_rec[-41]_rec[-42]_rec[-43]_rec[-62]_rec[-63]_rec[-70]_rec[-187]_rec[-188]_rec[-195]_rec[-219]_rec[-224]_rec[-225];DT(2,1,16)rec[-28]_rec[-29]_rec[-30]_rec[-37]_rec[-38]_rec[-39]_rec[-57]_rec[-66]_rec[-67]_rec[-93]_rec[-98]_rec[-99];DT(2,5,16)rec[-26]_rec[-27]_rec[-28]_rec[-35]_rec[-36]_rec[-37]_rec[-57]_rec[-73]_rec[-74]_rec[-182]_rec[-198]_rec[-199]_rec[-216]_rec[-238]_rec[-239];DT(2,7,16)rec[-23]_rec[-24]_rec[-32]_rec[-33]_rec[-61]_rec[-62]_rec[-103]_rec[-112]_rec[-113];DT(4,0,16)rec[-22]_rec[-31]_rec[-58]_rec[-116]_rec[-117];DT(3,2,16)rec[-20]_rec[-21]_rec[-22]_rec[-29]_rec[-30]_rec[-31]_rec[-58]_rec[-65]_rec[-66]_rec[-183]_rec[-190]_rec[-191]_rec[-227]_rec[-231]_rec[-232];DT(3,4,16)rec[-16]_rec[-17]_rec[-18]_rec[-25]_rec[-26]_rec[-27]_rec[-69]_rec[-72]_rec[-73]_rec[-89]_rec[-106]_rec[-107];DT(3,8,16)rec[-14]_rec[-15]_rec[-16]_rec[-23]_rec[-24]_rec[-25]_rec[-60]_rec[-61]_rec[-69]_rec[-185]_rec[-186]_rec[-194]_rec[-218]_rec[-222]_rec[-223];DT(4,1,16)rec[-10]_rec[-11]_rec[-12]_rec[-19]_rec[-20]_rec[-21]_rec[-56]_rec[-64]_rec[-65]_rec[-91]_rec[-96]_rec[-97];DT(4,5,16)rec[-8]_rec[-9]_rec[-10]_rec[-17]_rec[-18]_rec[-19]_rec[-56]_rec[-71]_rec[-72]_rec[-181]_rec[-196]_rec[-197]_rec[-215]_rec[-236]_rec[-237];DT(4,7,16)rec[-5]_rec[-6]_rec[-14]_rec[-15]_rec[-55]_rec[-60]_rec[-100]_rec[-110]_rec[-111];OI(0)rec[-23]_rec[-24]_rec[-26]_rec[-27]_rec[-29]_rec[-30]_rec[-61]_rec[-66]_rec[-73]_rec[-98]_rec[-107]_rec[-112]_rec[-117]_rec[-158]_rec[-167]_rec[-172]_rec[-177]_rec[-186]_rec[-191]_rec[-198]_rec[-246]_rec[-251]_rec[-258]_rec[-284]_rec[-293]_rec[-298]_rec[-303]_rec[-344]_rec[-353]_rec[-358]_rec[-363]_rec[-372]_rec[-377]_rec[-384]_rec[-432]_rec[-437]_rec[-444]_rec[-470]_rec[-479]_rec[-484]_rec[-489]_rec[-530]_rec[-539]_rec[-544]_rec[-549]_rec[-558]_rec[-563]_rec[-570]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr>\n                            <td>Surface Code</td>\n                            <td>Standard (ИZ)</td>\n                            <td>Memory (V)</td>\n                            <td>5x5x3</td>\n                            <td><a href=\"\n                                #circuit=Q(0,2)0;Q(0,4)1;Q(0.5,0.5)2;Q(0.5,1.5)3;Q(0.5,2.5)4;Q(0.5,3.5)5;Q(0.5,4.5)6;Q(1,0)7;Q(1,1)8;Q(1,2)9;Q(1,3)10;Q(1,4)11;Q(1.5,0.5)12;Q(1.5,1.5)13;Q(1.5,2.5)14;Q(1.5,3.5)15;Q(1.5,4.5)16;Q(2,1)17;Q(2,2)18;Q(2,3)19;Q(2,4)20;Q(2,5)21;Q(2.5,0.5)22;Q(2.5,1.5)23;Q(2.5,2.5)24;Q(2.5,3.5)25;Q(2.5,4.5)26;Q(3,0)27;Q(3,1)28;Q(3,2)29;Q(3,3)30;Q(3,4)31;Q(3.5,0.5)32;Q(3.5,1.5)33;Q(3.5,2.5)34;Q(3.5,3.5)35;Q(3.5,4.5)36;Q(4,1)37;Q(4,2)38;Q(4,3)39;Q(4,4)40;Q(4,5)41;Q(4.5,0.5)42;Q(4.5,1.5)43;Q(4.5,2.5)44;Q(4.5,3.5)45;Q(4.5,4.5)46;Q(5,1)47;Q(5,3)48;POLYGON(0,0,1,0.25)12_22_23_13;POLYGON(0,0,1,0.25)3_13_14_4;POLYGON(0,0,1,0.25)14_24_25_15;POLYGON(0,0,1,0.25)5_15_16_6;POLYGON(0,0,1,0.25)34_44_45_35;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)32_42_43_33;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)12_2;POLYGON(0,0,1,0.25)32_22;POLYGON(0,0,1,0.25)46_36;POLYGON(0,0,1,0.25)26_16;POLYGON(1,0,0,0.25)2_12_13_3;POLYGON(1,0,0,0.25)13_23_24_14;POLYGON(1,0,0,0.25)4_14_15_5;POLYGON(1,0,0,0.25)15_25_26_16;POLYGON(1,0,0,0.25)24_34_35_25;POLYGON(1,0,0,0.25)35_45_46_36;POLYGON(1,0,0,0.25)22_32_33_23;POLYGON(1,0,0,0.25)33_43_44_34;POLYGON(1,0,0,0.25)42_43;POLYGON(1,0,0,0.25)44_45;POLYGON(1,0,0,0.25)5_6;POLYGON(1,0,0,0.25)3_4;TICK;R_2_3_4_5_6_12_13_14_15_16_22_23_24_25_26_32_33_34_35_36_42_43_44_45_46;MARKZ(0)2_3_4_5_6;TICK;R_9_11_17_19_21_29_31_37_39_41_27_7;RX_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(1)28;TICK;CX_8_2_3_9_10_4_5_11_12_17_18_13_14_19_20_15_16_21_28_22_23_29_30_24_25_31_32_37_38_33_34_39_40_35_36_41_47_42_48_44;TICK;CX_13_9_15_11_22_17_24_19_26_21_33_29_35_31_42_37_44_39_46_41_8_3_10_5_18_14_20_16_28_23_30_25_38_34_40_36_47_43_48_45;TICK;CX_4_9_6_11_13_17_15_19_24_29_26_31_33_37_35_39_2_7_22_27_8_12_10_14_1_5_0_3_18_23_20_25_28_32_30_34_38_43_40_45;TICK;CX_8_13_14_9_10_15_16_11_23_17_18_24_25_19_20_26_28_33_34_29_30_35_36_31_43_37_38_44_45_39_40_46_0_4_1_6_12_7_32_27;TICK;M_9_11_17_19_21_29_31_37_39_41_27_7;MX_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(1)28;DT(1,2,0)rec[-24];DT(1,4,0)rec[-23];DT(2,1,0)rec[-22];DT(2,3,0)rec[-21];DT(2,5,0)rec[-20];DT(3,2,0)rec[-19];DT(3,4,0)rec[-18];DT(4,1,0)rec[-17];DT(4,3,0)rec[-16];DT(4,5,0)rec[-15];DT(3,0,0)rec[-14];DT(1,0,0)rec[-13];TICK;R_9_11_17_19_21_29_31_37_39_41_7_27;RX_8_10_18_20_28_30_38_40_47_48_1_0;MARKX(1)28;MARKZ(2)29;TICK;CX_8_2_3_9_10_4_5_11_12_17_18_13_14_19_20_15_16_21_28_22_23_29_30_24_25_31_32_37_38_33_34_39_40_35_36_41_47_42_48_44;TICK;CX_13_9_15_11_22_17_24_19_26_21_33_29_35_31_42_37_44_39_46_41_8_3_10_5_18_14_20_16_28_23_30_25_38_34_40_36_47_43_48_45;TICK;CX_4_9_6_11_13_17_15_19_24_29_26_31_33_37_35_39_2_7_22_27_8_12_10_14_1_5_0_3_18_23_20_25_28_32_30_34_38_43_40_45;TICK;CX_8_13_14_9_10_15_16_11_23_17_18_24_25_19_20_26_28_33_34_29_30_35_36_31_43_37_38_44_45_39_40_46_0_4_1_6_12_7_32_27;TICK;M_9_11_17_19_21_29_31_37_39_41_7_27;MX_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(1)28;MARKZ(2)29;DT(1,2,1)rec[-24]_rec[-48];DT(1,4,1)rec[-23]_rec[-47];DT(2,1,1)rec[-22]_rec[-46];DT(2,3,1)rec[-21]_rec[-45];DT(2,5,1)rec[-20]_rec[-44];DT(3,2,1)rec[-19]_rec[-43];DT(3,4,1)rec[-18]_rec[-42];DT(4,1,1)rec[-17]_rec[-41];DT(4,3,1)rec[-16]_rec[-40];DT(4,5,1)rec[-15]_rec[-39];DT(1,0,1)rec[-14]_rec[-37];DT(3,0,1)rec[-13]_rec[-38];DT(1,1,1)rec[-12]_rec[-36];DT(1,3,1)rec[-11]_rec[-35];DT(2,2,1)rec[-10]_rec[-34];DT(2,4,1)rec[-9]_rec[-33];DT(3,1,1)rec[-8]_rec[-32];DT(3,3,1)rec[-7]_rec[-31];DT(4,2,1)rec[-6]_rec[-30];DT(4,4,1)rec[-5]_rec[-29];DT(5,1,1)rec[-4]_rec[-28];DT(5,3,1)rec[-3]_rec[-27];DT(0,2,1)rec[-2]_rec[-26];DT(0,4,1)rec[-1]_rec[-25];TICK;R_9_11_17_19_21_29_31_37_39_41_7_27;RX_8_10_18_20_28_30_38_40_47_48_0_1;MARKZ(2)29;TICK;CX_8_2_3_9_10_4_5_11_12_17_18_13_14_19_20_15_16_21_28_22_23_29_30_24_25_31_32_37_38_33_34_39_40_35_36_41_47_42_48_44;TICK;CX_13_9_15_11_22_17_24_19_26_21_33_29_35_31_42_37_44_39_46_41_8_3_10_5_18_14_20_16_28_23_30_25_38_34_40_36_47_43_48_45;TICK;CX_4_9_6_11_13_17_15_19_24_29_26_31_33_37_35_39_2_7_22_27_8_12_10_14_1_5_0_3_18_23_20_25_28_32_30_34_38_43_40_45;TICK;CX_8_13_14_9_10_15_16_11_23_17_18_24_25_19_20_26_28_33_34_29_30_35_36_31_43_37_38_44_45_39_40_46_0_4_1_6_12_7_32_27;TICK;M_9_11_17_19_21_29_31_37_39_41_7_27;MX_8_10_18_20_28_30_38_40_47_48_0_1;MARKZ(2)29;DT(1,2,2)rec[-24]_rec[-48];DT(1,4,2)rec[-23]_rec[-47];DT(2,1,2)rec[-22]_rec[-46];DT(2,3,2)rec[-21]_rec[-45];DT(2,5,2)rec[-20]_rec[-44];DT(3,2,2)rec[-19]_rec[-43];DT(3,4,2)rec[-18]_rec[-42];DT(4,1,2)rec[-17]_rec[-41];DT(4,3,2)rec[-16]_rec[-40];DT(4,5,2)rec[-15]_rec[-39];DT(1,0,2)rec[-14]_rec[-38];DT(3,0,2)rec[-13]_rec[-37];DT(1,1,2)rec[-12]_rec[-36];DT(1,3,2)rec[-11]_rec[-35];DT(2,2,2)rec[-10]_rec[-34];DT(2,4,2)rec[-9]_rec[-33];DT(3,1,2)rec[-8]_rec[-32];DT(3,3,2)rec[-7]_rec[-31];DT(4,2,2)rec[-6]_rec[-30];DT(4,4,2)rec[-5]_rec[-29];DT(5,1,2)rec[-4]_rec[-28];DT(5,3,2)rec[-3]_rec[-27];DT(0,2,2)rec[-2]_rec[-26];DT(0,4,2)rec[-1]_rec[-25];TICK;M_2_3_4_5_6_12_13_14_15_16_22_23_24_25_26_32_33_34_35_36_42_43_44_45_46;MARKZ(0)2_3_4_5_6;DT(1,0,3)rec[-20]_rec[-25]_rec[-39];DT(1,2,3)rec[-18]_rec[-19]_rec[-23]_rec[-24]_rec[-49];DT(1,4,3)rec[-16]_rec[-17]_rec[-21]_rec[-22]_rec[-48];DT(2,1,3)rec[-14]_rec[-15]_rec[-19]_rec[-20]_rec[-47];DT(2,3,3)rec[-12]_rec[-13]_rec[-17]_rec[-18]_rec[-46];DT(2,5,3)rec[-11]_rec[-16]_rec[-45];DT(3,0,3)rec[-10]_rec[-15]_rec[-38];DT(3,2,3)rec[-8]_rec[-9]_rec[-13]_rec[-14]_rec[-44];DT(3,4,3)rec[-6]_rec[-7]_rec[-11]_rec[-12]_rec[-43];DT(4,1,3)rec[-4]_rec[-5]_rec[-9]_rec[-10]_rec[-42];DT(4,3,3)rec[-2]_rec[-3]_rec[-7]_rec[-8]_rec[-41];DT(4,5,3)rec[-1]_rec[-6]_rec[-40];OI(0)rec[-21]_rec[-22]_rec[-23]_rec[-24]_rec[-25]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr>\n                            <td>Surface Code</td>\n                            <td>3-Coupler</td>\n                            <td>Memory (V)</td>\n                            <td>5x5x4</td>\n                            <td><a href=\"\n                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,2)2;Q(0,3)3;Q(0,4)4;Q(0.5,0.5)5;Q(0.5,1.5)6;Q(0.5,2.5)7;Q(0.5,3.5)8;Q(0.5,4.5)9;Q(1,0)10;Q(1,1)11;Q(1,2)12;Q(1,3)13;Q(1,4)14;Q(1.5,0.5)15;Q(1.5,1.5)16;Q(1.5,2.5)17;Q(1.5,3.5)18;Q(1.5,4.5)19;Q(2,0)20;Q(2,1)21;Q(2,2)22;Q(2,3)23;Q(2,4)24;Q(2.5,0.5)25;Q(2.5,1.5)26;Q(2.5,2.5)27;Q(2.5,3.5)28;Q(2.5,4.5)29;Q(3,0)30;Q(3,1)31;Q(3,2)32;Q(3,3)33;Q(3,4)34;Q(3.5,0.5)35;Q(3.5,1.5)36;Q(3.5,2.5)37;Q(3.5,3.5)38;Q(3.5,4.5)39;Q(4,0)40;Q(4,1)41;Q(4,2)42;Q(4,3)43;Q(4,4)44;Q(4.5,0.5)45;Q(4.5,1.5)46;Q(4.5,2.5)47;Q(4.5,3.5)48;POLYGON(0,0,1,0.25)27_22_26_32;POLYGON(0,0,1,0.25)17_12_16_22;POLYGON(0,0,1,0.25)16_11_15_21;POLYGON(0,0,1,0.25)7_2_6_12;POLYGON(0,0,1,0.25)6_1_5_11;POLYGON(0,0,1,0.25)35_30_40;POLYGON(0,0,1,0.25)25_20_30;POLYGON(0,0,1,0.25)15_10_20;POLYGON(0,0,1,0.25)5_0_10;POLYGON(0,0,1,0.25)26_21_25_31;POLYGON(0,0,1,0.25)37_32_36_42;POLYGON(0,0,1,0.25)36_31_35_41;POLYGON(0,0,1,0.25)28_23_27_33;POLYGON(0,0,1,0.25)18_13_17_23;POLYGON(0,0,1,0.25)9_4_8_14;POLYGON(0,0,1,0.25)8_3_7_13;POLYGON(0,0,1,0.25)38_33_37_43;POLYGON(0,0,1,0.25)9;POLYGON(0,0,1,0.25)19_14_18_24;POLYGON(0,0,1,0.25)19;POLYGON(0,0,1,0.25)29_24_28_34;POLYGON(0,0,1,0.25)29;POLYGON(0,0,1,0.25)39_34_38_44;POLYGON(0,0,1,0.25)39;POLYGON(1,0,0,0.25)12_6_11_16;POLYGON(1,0,0,0.25)22_16_21_26;POLYGON(1,0,0,0.25)13_7_12_17;POLYGON(1,0,0,0.25)23_17_22_27;POLYGON(1,0,0,0.25)33_27_32_37;POLYGON(1,0,0,0.25)3_2_7;POLYGON(1,0,0,0.25)2_1_6;POLYGON(1,0,0,0.25)1_0_5;POLYGON(1,0,0,0.25)21_15_20_25;POLYGON(1,0,0,0.25)11_5_10_15;POLYGON(1,0,0,0.25)32_26_31_36;POLYGON(1,0,0,0.25)31_25_30_35;POLYGON(1,0,0,0.25)48;POLYGON(1,0,0,0.25)43_37_42_47;POLYGON(1,0,0,0.25)47;POLYGON(1,0,0,0.25)42_36_41_46;POLYGON(1,0,0,0.25)46;POLYGON(1,0,0,0.25)41_35_40_45;POLYGON(1,0,0,0.25)45;POLYGON(1,0,0,0.25)14_8_13_18;POLYGON(1,0,0,0.25)24_18_23_28;POLYGON(1,0,0,0.25)34_28_33_38;POLYGON(1,0,0,0.25)4_3_8;POLYGON(1,0,0,0.25)44_38_43_48;TICK;R_0_1_2_3_4_10_11_12_13_14_20_21_22_23_24_30_31_32_33_34_40_41_42_43_44;TICK;R_37_35_28_26_17_15_8_6_9_19_29_39;RX_38_36_27_25_18_16_7_5_45_46_47_48;MARKX(1)27;MARKZ(0)17;TICK;CX_38_33_32_37_36_31_30_35_23_28_27_22_21_26_25_20_18_13_12_17_16_11_10_15_3_8_7_2_1_6_5_0_45_40_47_42_43_48_41_46_9_4_14_19_29_24_34_39;TICK;CX_42_37_40_35_33_28_31_26_22_17_20_15_13_8_11_6_38_34_36_32_27_23_25_21_18_14_16_12_7_3_5_1_47_43_45_41_24_19_44_39;TICK;CX_21_16_26_22_32_27_37_33_43_38_10_5_15_11_23_18_28_24_17_13_6_2_12_7_8_4_41_36_35_31_30_25_46_42_48_44_14_9_34_29;TICK;CX_26_21_17_12_2_7_22_27_33_38_37_32_15_10_0_5_6_1_28_23_13_18_8_3_31_36_11_16_20_25_35_30_46_41_48_43_42_47_40_45_19_14_39_34_24_29_4_9;TICK;M_38_36_27_25_18_16_7_5_9_19_29_39;MX_37_35_28_26_17_15_8_6_45_46_47_48;MARKX(1)17;MARKZ(0)16;DT(3.5,3.5,0)rec[-24];DT(3.5,1.5,0)rec[-23];DT(2.5,2.5,0)rec[-22];DT(2.5,0.5,0)rec[-21];DT(1.5,3.5,0)rec[-20];DT(1.5,1.5,0)rec[-19];DT(0.5,2.5,0)rec[-18];DT(0.5,0.5,0)rec[-17];DT(0.5,4.5,0)rec[-16];DT(1.5,4.5,0)rec[-15];DT(2.5,4.5,0)rec[-14];DT(3.5,4.5,0)rec[-13];TICK;R_38_36_27_25_18_16_7_5_9_19_29_39;RX_37_35_28_26_17_15_8_6_45_46_47_48;MARKX(1)17;MARKX(3)26;MARKZ(0)16;MARKZ(2)27;TICK;CX_26_21_17_12_2_7_22_27_33_38_37_32_15_10_0_5_6_1_28_23_13_18_8_3_31_36_11_16_20_25_35_30_46_41_48_43_42_47_40_45_39_34_24_29_19_14_4_9;TICK;CX_21_16_26_22_32_27_37_33_43_38_10_5_15_11_23_18_28_24_17_13_6_2_12_7_8_4_41_36_35_31_30_25_46_42_48_44_14_9_34_29;TICK;CX_42_37_40_35_33_28_31_26_22_17_20_15_13_8_11_6_38_34_36_32_27_23_25_21_18_14_16_12_7_3_5_1_47_43_45_41_24_19_44_39;TICK;CX_38_33_32_37_36_31_30_35_23_28_27_22_21_26_25_20_18_13_12_17_16_11_10_15_3_8_7_2_1_6_5_0_45_40_47_42_43_48_41_46_14_19_34_39_29_24_9_4;TICK;M_37_35_28_26_17_15_8_6_9_19_29_39;MX_38_36_27_25_18_16_7_5_45_46_47_48;MARKX(1)27;MARKX(3)16;MARKZ(0)17;MARKZ(2)26;DT(3.5,1.5,1)rec[-24]_rec[-47];DT(3.5,0.5,1)rec[-23];DT(2.5,2.5,1)rec[-22]_rec[-46];DT(2.5,0.5,1)rec[-21]_rec[-45];DT(1.5,1.5,1)rec[-20]_rec[-43];DT(1.5,0.5,1)rec[-19];DT(0.5,2.5,1)rec[-18]_rec[-42];DT(0.5,0.5,1)rec[-17]_rec[-41];DT(1.5,4.5,1)rec[-16]_rec[-39]_rec[-40];DT(1.5,3.5,1)rec[-15]_rec[-44];DT(3.5,4.5,1)rec[-14]_rec[-37]_rec[-38];DT(3.5,3.5,1)rec[-13]_rec[-48];DT(2.5,3.5,1)rec[-12]_rec[-34];DT(2.5,1.5,1)rec[-11]_rec[-33];DT(1.5,2.5,1)rec[-10]_rec[-32];DT(2,0.5,1)rec[-9]_rec[-31];DT(0.5,3.5,1)rec[-8]_rec[-30];DT(0.5,1.5,1)rec[-7]_rec[-29];DT(0.5,2.5,2)rec[-6];DT(0.5,0.5,2)rec[-5];DT(4.5,0.5,1)rec[-4]_rec[-35];DT(4.5,2.5,1)rec[-3]_rec[-26]_rec[-27];DT(3.5,2.5,1)rec[-2]_rec[-36];DT(4.5,3.5,1)rec[-1]_rec[-25];TICK;R_37_35_28_26_17_15_8_6_9_19_29_39;RX_38_36_27_25_18_16_7_5_45_46_47_48;MARKX(3)16;MARKZ(2)26;TICK;CX_38_33_32_37_36_31_30_35_23_28_27_22_21_26_25_20_18_13_12_17_16_11_10_15_3_8_7_2_1_6_5_0_45_40_47_42_43_48_41_46_9_4_14_19_29_24_34_39;TICK;CX_42_37_40_35_33_28_31_26_22_17_20_15_13_8_11_6_38_34_36_32_27_23_25_21_18_14_16_12_7_3_5_1_47_43_45_41_24_19_44_39;TICK;CX_21_16_26_22_32_27_37_33_43_38_10_5_15_11_23_18_28_24_17_13_6_2_12_7_8_4_41_36_35_31_30_25_46_42_48_44_14_9_34_29;TICK;CX_26_21_17_12_2_7_22_27_33_38_37_32_15_10_0_5_6_1_28_23_13_18_8_3_31_36_11_16_20_25_35_30_46_41_48_43_42_47_40_45_19_14_39_34_24_29_4_9;TICK;M_38_36_27_25_18_16_7_5_9_19_29_39;MX_37_35_28_26_17_15_8_6_45_46_47_48;MARKX(3)26;MARKZ(2)27;DT(3.5,2.5,3)rec[-24]_rec[-48];DT(3.5,0.5,3)rec[-23]_rec[-47];DT(2.5,1.5,3)rec[-22]_rec[-45];DT(2.5,0.5,3)rec[-21];DT(1.5,2.5,3)rec[-20]_rec[-44];DT(1.5,0.5,3)rec[-19]_rec[-43];DT(0.5,1.5,3)rec[-18]_rec[-41];DT(0.5,0.5,3)rec[-17];DT(0.5,3.5,3)rec[-16]_rec[-42];DT(2.5,4.5,3)rec[-15]_rec[-38]_rec[-39];DT(2.5,3.5,3)rec[-14]_rec[-46];DT(3.5,4.5,3)rec[-13]_rec[-37];DT(2.5,2.5,3)rec[-12]_rec[-34];DT(3,0.5,3)rec[-11]_rec[-33];DT(1.5,3.5,3)rec[-10]_rec[-32];DT(1.5,1.5,3)rec[-9]_rec[-31];DT(0.5,2.5,3)rec[-8]_rec[-30];DT(1,0.5,3)rec[-7]_rec[-29];DT(0.5,3.5,4)rec[-6];DT(0.5,1.5,4)rec[-5];DT(4.5,1.5,3)rec[-4]_rec[-27]_rec[-28];DT(3.5,1.5,3)rec[-3]_rec[-35];DT(4.5,3.5,3)rec[-2]_rec[-25]_rec[-26];DT(3.5,3.5,3)rec[-1]_rec[-36];TICK;R_38_36_27_25_18_16_7_5_9_19_29_39;RX_37_35_28_26_17_15_8_6_45_46_47_48;TICK;CX_26_21_17_12_2_7_22_27_33_38_37_32_15_10_0_5_6_1_28_23_13_18_8_3_31_36_11_16_20_25_35_30_46_41_48_43_42_47_40_45_39_34_24_29_19_14_4_9;TICK;CX_21_16_26_22_32_27_37_33_43_38_10_5_15_11_23_18_28_24_17_13_6_2_12_7_8_4_41_36_35_31_30_25_46_42_48_44_14_9_34_29;TICK;CX_42_37_40_35_33_28_31_26_22_17_20_15_13_8_11_6_38_34_36_32_27_23_25_21_18_14_16_12_7_3_5_1_47_43_45_41_24_19_44_39;TICK;CX_38_33_32_37_36_31_30_35_23_28_27_22_21_26_25_20_18_13_12_17_16_11_10_15_3_8_7_2_1_6_5_0_45_40_47_42_43_48_41_46_14_19_34_39_29_24_9_4;TICK;M_37_35_28_26_17_15_8_6_9_19_29_39;MX_38_36_27_25_18_16_7_5_45_46_47_48;DT(3.5,1.5,5)rec[-24]_rec[-47];DT(3.5,0.5,5)rec[-23];DT(2.5,2.5,5)rec[-22]_rec[-46];DT(2.5,0.5,5)rec[-21]_rec[-45];DT(1.5,1.5,5)rec[-20]_rec[-43];DT(1.5,0.5,5)rec[-19];DT(0.5,2.5,5)rec[-18]_rec[-42];DT(0.5,0.5,5)rec[-17]_rec[-41];DT(1.5,4.5,5)rec[-16]_rec[-39]_rec[-40];DT(1.5,3.5,5)rec[-15]_rec[-44];DT(3.5,4.5,5)rec[-14]_rec[-37]_rec[-38];DT(3.5,3.5,5)rec[-13]_rec[-48];DT(2.5,3.5,5)rec[-12]_rec[-34];DT(2.5,1.5,5)rec[-11]_rec[-33];DT(1.5,2.5,5)rec[-10]_rec[-32];DT(2,0.5,5)rec[-9]_rec[-31];DT(0.5,3.5,5)rec[-8]_rec[-30];DT(0.5,1.5,5)rec[-7]_rec[-29];DT(0.5,2.5,6)rec[-6];DT(0.5,0.5,6)rec[-5];DT(4.5,0.5,5)rec[-4]_rec[-35];DT(4.5,2.5,5)rec[-3]_rec[-26]_rec[-27];DT(3.5,2.5,5)rec[-2]_rec[-36];DT(4.5,3.5,5)rec[-1]_rec[-25];TICK;M_0_1_2_3_4_10_11_12_13_14_20_21_22_23_24_30_31_32_33_34_40_41_42_43_44;DT(1,0,7)rec[-20]_rec[-25];DT(0.5,1.5,7)rec[-18]_rec[-19]_rec[-23]_rec[-24]_rec[-42];DT(0.5,3.5,7)rec[-16]_rec[-17]_rec[-21]_rec[-22]_rec[-43];DT(1.5,0.5,7)rec[-14]_rec[-15]_rec[-19]_rec[-20]_rec[-44];DT(1.5,2.5,7)rec[-12]_rec[-13]_rec[-17]_rec[-18]_rec[-45];DT(2.5,4.5,7)rec[-11]_rec[-16]_rec[-39]_rec[-40];DT(3,0,7)rec[-10]_rec[-15];DT(2.5,1.5,7)rec[-8]_rec[-9]_rec[-13]_rec[-14]_rec[-46];DT(2.5,3.5,7)rec[-6]_rec[-7]_rec[-11]_rec[-12]_rec[-47];DT(3.5,0.5,7)rec[-4]_rec[-5]_rec[-9]_rec[-10]_rec[-48];DT(3.5,2.5,7)rec[-2]_rec[-3]_rec[-7]_rec[-8]_rec[-49];DT(3.5,4.5,7)rec[-1]_rec[-6]_rec[-38];OI(0)rec[-21]_rec[-22]_rec[-23]_rec[-24]_rec[-25]_rec[-41]_rec[-89]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr>\n                            <td>Surface Code</td>\n                            <td>Biased (XZZX)</td>\n                            <td>Memory (V)</td>\n                            <td>5x5x3</td>\n                            <td><a href=\"\n                                #circuit=Q(0,2)0;Q(0,4)1;Q(0.5,0.5)2;Q(0.5,1.5)3;Q(0.5,2.5)4;Q(0.5,3.5)5;Q(0.5,4.5)6;Q(1,0)7;Q(1,1)8;Q(1,2)9;Q(1,3)10;Q(1,4)11;Q(1.5,0.5)12;Q(1.5,1.5)13;Q(1.5,2.5)14;Q(1.5,3.5)15;Q(1.5,4.5)16;Q(2,1)17;Q(2,2)18;Q(2,3)19;Q(2,4)20;Q(2,5)21;Q(2.5,0.5)22;Q(2.5,1.5)23;Q(2.5,2.5)24;Q(2.5,3.5)25;Q(2.5,4.5)26;Q(3,0)27;Q(3,1)28;Q(3,2)29;Q(3,3)30;Q(3,4)31;Q(3.5,0.5)32;Q(3.5,1.5)33;Q(3.5,2.5)34;Q(3.5,3.5)35;Q(3.5,4.5)36;Q(4,1)37;Q(4,2)38;Q(4,3)39;Q(4,4)40;Q(4,5)41;Q(4.5,0.5)42;Q(4.5,1.5)43;Q(4.5,2.5)44;Q(4.5,3.5)45;Q(4.5,4.5)46;Q(5,1)47;Q(5,3)48;POLYGON(0,0,1,0.25)12_22_23_13;POLYGON(0,0,1,0.25)3_13_14_4;POLYGON(0,0,1,0.25)14_24_25_15;POLYGON(0,0,1,0.25)5_15_16_6;POLYGON(0,0,1,0.25)34_44_45_35;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)32_42_43_33;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)12_2;POLYGON(0,0,1,0.25)32_22;POLYGON(0,0,1,0.25)46_36;POLYGON(0,0,1,0.25)26_16;POLYGON(1,0,0,0.25)2_12_13_3;POLYGON(1,0,0,0.25)13_23_24_14;POLYGON(1,0,0,0.25)4_14_15_5;POLYGON(1,0,0,0.25)15_25_26_16;POLYGON(1,0,0,0.25)24_34_35_25;POLYGON(1,0,0,0.25)35_45_46_36;POLYGON(1,0,0,0.25)22_32_33_23;POLYGON(1,0,0,0.25)33_43_44_34;POLYGON(1,0,0,0.25)42_43;POLYGON(1,0,0,0.25)44_45;POLYGON(1,0,0,0.25)5_6;POLYGON(1,0,0,0.25)3_4;TICK;R_2_4_6_13_15_22_24_26_33_35_42_44_46;RX_12_3_14_5_16_25_36_45_34_23_43_32;MARKX(1)14_25;MARKZ(1)15_24;TICK;RX_9_11_17_19_21_29_31_37_39_41_27_7_10_18_8_28_38_48_47_30_40_20_0_1;MARKX(0)8;MARKX(1)19;TICK;CX_9_3_17_12_19_14_21_16_29_23_31_25_37_32_39_34_41_36_48_44_47_42_40_35_38_33_28_22_30_24_20_15_18_13_8_2_11_5_10_4;TICK;CZ_19_24_29_33_9_13_11_15_21_26_17_22_31_35_41_46_39_44_37_42_43_47_45_48_36_40_34_38_25_30_23_28_16_20_14_18_5_10_3_8;TICK;CZ_24_29_33_37_2_7_4_9_6_11_15_19_13_17_26_31_22_27_35_39_40_45_38_43_30_34_28_32_20_25_18_23_10_14_8_12_0_3_1_5;TICK;CX_9_14_11_16_17_23_19_25_29_34_31_36_37_43_39_45_7_12_27_32_40_46_38_44_30_35_28_33_20_26_18_24_8_13_10_15_1_6_0_4;TICK;MX_9_11_17_19_21_29_31_37_39_41_27_7_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(0)8;MARKX(1)19;DT(1,2,0)rec[-24];DT(1,4,0)rec[-23];DT(2,1,0)rec[-22];DT(2,3,0)rec[-21];DT(2,5,0)rec[-20];DT(3,2,0)rec[-19];DT(3,4,0)rec[-18];DT(4,1,0)rec[-17];DT(4,3,0)rec[-16];DT(4,5,0)rec[-15];DT(3,0,0)rec[-14];DT(1,0,0)rec[-13];TICK;RX_9_11_17_19_21_29_31_37_39_41_27_7_10_18_8_28_38_48_47_30_40_20_0_1;MARKX(0)8;TICK;CX_9_3_17_12_19_14_21_16_29_23_31_25_37_32_39_34_41_36_48_44_47_42_40_35_38_33_28_22_30_24_20_15_18_13_8_2_11_5_10_4;TICK;CZ_19_24_29_33_9_13_11_15_21_26_17_22_31_35_41_46_39_44_37_42_43_47_45_48_36_40_34_38_25_30_23_28_16_20_14_18_5_10_3_8;TICK;CZ_24_29_33_37_2_7_4_9_6_11_15_19_13_17_26_31_22_27_35_39_40_45_38_43_30_34_28_32_20_25_18_23_10_14_8_12_0_3_1_5;TICK;CX_9_14_11_16_17_23_19_25_29_34_31_36_37_43_39_45_7_12_27_32_40_46_38_44_30_35_28_33_20_26_18_24_8_13_10_15_1_6_0_4;TICK;MX_9_11_17_19_21_29_31_37_39_41_7_27_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(0)8;DT(1,2,1)rec[-24]_rec[-48];DT(1,4,1)rec[-23]_rec[-47];DT(2,1,1)rec[-22]_rec[-46];DT(2,3,1)rec[-21]_rec[-45];DT(2,5,1)rec[-20]_rec[-44];DT(3,2,1)rec[-19]_rec[-43];DT(3,4,1)rec[-18]_rec[-42];DT(4,1,1)rec[-17]_rec[-41];DT(4,3,1)rec[-16]_rec[-40];DT(4,5,1)rec[-15]_rec[-39];DT(1,0,1)rec[-14]_rec[-37];DT(3,0,1)rec[-13]_rec[-38];DT(1,1,1)rec[-12]_rec[-36];DT(1,3,1)rec[-11]_rec[-35];DT(2,2,1)rec[-10]_rec[-34];DT(2,4,1)rec[-9]_rec[-33];DT(3,1,1)rec[-8]_rec[-32];DT(3,3,1)rec[-7]_rec[-31];DT(4,2,1)rec[-6]_rec[-30];DT(4,4,1)rec[-5]_rec[-29];DT(5,1,1)rec[-4]_rec[-28];DT(5,3,1)rec[-3]_rec[-27];DT(0,2,1)rec[-2]_rec[-26];DT(0,4,1)rec[-1]_rec[-25];TICK;RX_9_11_17_19_21_29_31_37_39_41_27_7_10_18_8_28_38_48_47_30_40_20_0_1;TICK;CX_9_3_17_12_19_14_21_16_29_23_31_25_37_32_39_34_41_36_48_44_47_42_40_35_38_33_28_22_30_24_20_15_18_13_8_2_11_5_10_4;TICK;CZ_19_24_29_33_9_13_11_15_21_26_17_22_31_35_41_46_39_44_37_42_43_47_45_48_36_40_34_38_25_30_23_28_16_20_14_18_5_10_3_8;TICK;CZ_24_29_33_37_2_7_4_9_6_11_15_19_13_17_26_31_22_27_35_39_40_45_38_43_30_34_28_32_20_25_18_23_10_14_8_12_0_3_1_5;TICK;CX_9_14_11_16_17_23_19_25_29_34_31_36_37_43_39_45_7_12_27_32_40_46_38_44_30_35_28_33_20_26_18_24_8_13_10_15_1_6_0_4;TICK;MX_9_11_17_19_21_29_31_37_39_41_7_27_8_10_18_20_28_30_38_40_47_48_0_1;DT(1,2,2)rec[-24]_rec[-48];DT(1,4,2)rec[-23]_rec[-47];DT(2,1,2)rec[-22]_rec[-46];DT(2,3,2)rec[-21]_rec[-45];DT(2,5,2)rec[-20]_rec[-44];DT(3,2,2)rec[-19]_rec[-43];DT(3,4,2)rec[-18]_rec[-42];DT(4,1,2)rec[-17]_rec[-41];DT(4,3,2)rec[-16]_rec[-40];DT(4,5,2)rec[-15]_rec[-39];DT(3,0,2)rec[-14]_rec[-37];DT(1,0,2)rec[-13]_rec[-38];DT(1,1,2)rec[-12]_rec[-36];DT(1,3,2)rec[-11]_rec[-35];DT(2,2,2)rec[-10]_rec[-34];DT(2,4,2)rec[-9]_rec[-33];DT(3,1,2)rec[-8]_rec[-32];DT(3,3,2)rec[-7]_rec[-31];DT(4,2,2)rec[-6]_rec[-30];DT(4,4,2)rec[-5]_rec[-29];DT(5,1,2)rec[-4]_rec[-28];DT(5,3,2)rec[-3]_rec[-27];DT(0,2,2)rec[-2]_rec[-26];DT(0,4,2)rec[-1]_rec[-25];TICK;M_2_4_6_13_15_22_24_26_33_35_42_44_46;MX_3_5_12_14_16_23_25_32_34_36_43_45;DT(1,0,3)rec[-10]_rec[-25]_rec[-39];DT(1,2,3)rec[-9]_rec[-12]_rec[-22]_rec[-24]_rec[-49];DT(1,4,3)rec[-8]_rec[-11]_rec[-21]_rec[-23]_rec[-48];DT(2,5,3)rec[-8]_rec[-18]_rec[-45];DT(2,1,3)rec[-7]_rec[-10]_rec[-20]_rec[-22]_rec[-47];DT(2,3,3)rec[-6]_rec[-9]_rec[-19]_rec[-21]_rec[-46];DT(3,0,3)rec[-5]_rec[-20]_rec[-38];DT(3,2,3)rec[-4]_rec[-7]_rec[-17]_rec[-19]_rec[-44];DT(3,4,3)rec[-3]_rec[-6]_rec[-16]_rec[-18]_rec[-43];DT(4,5,3)rec[-3]_rec[-13]_rec[-40];DT(4,1,3)rec[-2]_rec[-5]_rec[-15]_rec[-17]_rec[-42];DT(4,3,3)rec[-1]_rec[-4]_rec[-14]_rec[-16]_rec[-41];OI(0)rec[-11]_rec[-12]_rec[-23]_rec[-24]_rec[-25]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr>\n                            <td>Toric Code</td>\n                            <td>Standard (ZZ)</td>\n                            <td>Memory (ZH+ZV)</td>\n                            <td>6x6x3</td>\n                            <td><a href=\"\n                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,2)2;Q(0,3)3;Q(0,4)4;Q(0,5)5;Q(0,6)6;Q(0.5,0.5)7;Q(0.5,1.5)8;Q(0.5,2.5)9;Q(0.5,3.5)10;Q(0.5,4.5)11;Q(0.5,5.5)12;Q(1,0)13;Q(1,1)14;Q(1,2)15;Q(1,3)16;Q(1,4)17;Q(1,5)18;Q(1,6)19;Q(1.5,0.5)20;Q(1.5,1.5)21;Q(1.5,2.5)22;Q(1.5,3.5)23;Q(1.5,4.5)24;Q(1.5,5.5)25;Q(2,0)26;Q(2,1)27;Q(2,2)28;Q(2,3)29;Q(2,4)30;Q(2,5)31;Q(2,6)32;Q(2.5,0.5)33;Q(2.5,1.5)34;Q(2.5,2.5)35;Q(2.5,3.5)36;Q(2.5,4.5)37;Q(2.5,5.5)38;Q(3,0)39;Q(3,1)40;Q(3,2)41;Q(3,3)42;Q(3,4)43;Q(3,5)44;Q(3,6)45;Q(3.5,0.5)46;Q(3.5,1.5)47;Q(3.5,2.5)48;Q(3.5,3.5)49;Q(3.5,4.5)50;Q(3.5,5.5)51;Q(4,0)52;Q(4,1)53;Q(4,2)54;Q(4,3)55;Q(4,4)56;Q(4,5)57;Q(4,6)58;Q(4.5,0.5)59;Q(4.5,1.5)60;Q(4.5,2.5)61;Q(4.5,3.5)62;Q(4.5,4.5)63;Q(4.5,5.5)64;Q(5,0)65;Q(5,1)66;Q(5,2)67;Q(5,3)68;Q(5,4)69;Q(5,5)70;Q(5,6)71;Q(5.5,0.5)72;Q(5.5,1.5)73;Q(5.5,2.5)74;Q(5.5,3.5)75;Q(5.5,4.5)76;Q(5.5,5.5)77;Q(6,0)78;Q(6,1)79;Q(6,2)80;Q(6,3)81;Q(6,4)82;Q(6,5)83;Q(6,6)84;POLYGON(0,0,1,0.25)13_26_27_14;POLYGON(0,0,1,0.25)1_14_15_2;POLYGON(0,0,1,0.25)15_28_29_16;POLYGON(0,0,1,0.25)3_16_17_4;POLYGON(0,0,1,0.25)41_54_55_42;POLYGON(0,0,1,0.25)29_42_43_30;POLYGON(0,0,1,0.25)39_52_53_40;POLYGON(0,0,1,0.25)27_40_41_28;POLYGON(0,0,1,0.25)65_78_79_66;POLYGON(0,0,1,0.25)53_66_67_54;POLYGON(0,0,1,0.25)67_80_81_68;POLYGON(0,0,1,0.25)55_68_69_56;POLYGON(0,0,1,0.25)69_82_83_70;POLYGON(0,0,1,0.25)57_70_71_58;POLYGON(0,0,1,0.25)43_56_57_44;POLYGON(0,0,1,0.25)31_44_45_32;POLYGON(0,0,1,0.25)17_30_31_18;POLYGON(0,0,1,0.25)5_18_19_6;POLYGON(1,0,0,0.25)0_13_14_1;POLYGON(1,0,0,0.25)14_27_28_15;POLYGON(1,0,0,0.25)2_15_16_3;POLYGON(1,0,0,0.25)16_29_30_17;POLYGON(1,0,0,0.25)28_41_42_29;POLYGON(1,0,0,0.25)42_55_56_43;POLYGON(1,0,0,0.25)26_39_40_27;POLYGON(1,0,0,0.25)40_53_54_41;POLYGON(1,0,0,0.25)52_65_66_53;POLYGON(1,0,0,0.25)66_79_80_67;POLYGON(1,0,0,0.25)54_67_68_55;POLYGON(1,0,0,0.25)68_81_82_69;POLYGON(1,0,0,0.25)56_69_70_57;POLYGON(1,0,0,0.25)70_83_84_71;POLYGON(1,0,0,0.25)30_43_44_31;POLYGON(1,0,0,0.25)44_57_58_45;POLYGON(1,0,0,0.25)4_17_18_5;POLYGON(1,0,0,0.25)18_31_32_19;TICK;R_0_1_2_3_4_5_13_14_15_16_17_18_26_27_28_29_30_31_39_40_41_42_43_44_52_53_54_55_56_57_65_66_67_68_69_70;MARKZ(0)39_40_41_42_43_44;TICK;R_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;RX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKZ(1)60;TICK;CX_7_0_1_8_9_2_3_10_11_4_5_12_13_20_21_14_15_22_23_16_17_24_25_18_33_26_27_34_35_28_29_36_37_30_31_38_39_46_47_40_41_48_49_42_43_50_51_44_59_52_53_60_61_54_55_62_63_56_57_64_65_72_73_66_67_74_75_68_69_76_77_70;TICK;CX_7_13_14_8_9_15_16_10_11_17_18_12_26_20_21_27_28_22_23_29_30_24_25_31_33_39_40_34_35_41_42_36_37_43_44_38_52_46_47_53_54_48_49_55_56_50_51_57_59_65_66_60_61_67_68_62_63_69_70_64_0_72_2_74_4_76_73_1_75_3_77_5;TICK;CX_7_1_2_8_9_3_4_10_11_5_14_20_21_15_16_22_23_17_18_24_33_27_28_34_35_29_30_36_37_31_40_46_47_41_42_48_49_43_44_50_59_53_54_60_61_55_56_62_63_57_66_72_73_67_68_74_75_69_70_76_0_12_26_38_52_64_25_13_51_39_77_65;TICK;CX_7_14_15_8_9_16_17_10_11_18_27_20_21_28_29_22_23_30_31_24_33_40_41_34_35_42_43_36_37_44_53_46_47_54_55_48_49_56_57_50_59_66_67_60_61_68_69_62_63_70_13_12_39_38_65_64_25_26_51_52_1_72_3_74_5_76_73_2_75_4_77_0;TICK;M_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;MX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKZ(1)60;DT(0.5,1.5,0)rec[-36];DT(0.5,3.5,0)rec[-35];DT(0.5,5.5,0)rec[-34];DT(1.5,0.5,0)rec[-33];DT(1.5,2.5,0)rec[-32];DT(1.5,4.5,0)rec[-31];DT(2.5,1.5,0)rec[-30];DT(2.5,3.5,0)rec[-29];DT(2.5,5.5,0)rec[-28];DT(3.5,0.5,0)rec[-27];DT(3.5,2.5,0)rec[-26];DT(3.5,4.5,0)rec[-25];DT(4.5,1.5,0)rec[-24];DT(4.5,3.5,0)rec[-23];DT(4.5,5.5,0)rec[-22];DT(5.5,0.5,0)rec[-21];DT(5.5,2.5,0)rec[-20];DT(5.5,4.5,0)rec[-19];TICK;R_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;RX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKX(2)25;MARKZ(1)60;TICK;CX_7_0_1_8_9_2_3_10_11_4_5_12_13_20_21_14_15_22_23_16_17_24_25_18_33_26_27_34_35_28_29_36_37_30_31_38_39_46_47_40_41_48_49_42_43_50_51_44_59_52_53_60_61_54_55_62_63_56_57_64_65_72_73_66_67_74_75_68_69_76_77_70;TICK;CX_7_13_14_8_9_15_16_10_11_17_18_12_26_20_21_27_28_22_23_29_30_24_25_31_33_39_40_34_35_41_42_36_37_43_44_38_52_46_47_53_54_48_49_55_56_50_51_57_59_65_66_60_61_67_68_62_63_69_70_64_0_72_2_74_4_76_73_1_75_3_77_5;TICK;CX_7_1_2_8_9_3_4_10_11_5_14_20_21_15_16_22_23_17_18_24_33_27_28_34_35_29_30_36_37_31_40_46_47_41_42_48_49_43_44_50_59_53_54_60_61_55_56_62_63_57_66_72_73_67_68_74_75_69_70_76_0_12_26_38_52_64_25_13_51_39_77_65;TICK;CX_7_14_15_8_9_16_17_10_11_18_27_20_21_28_29_22_23_30_31_24_33_40_41_34_35_42_43_36_37_44_53_46_47_54_55_48_49_56_57_50_59_66_67_60_61_68_69_62_63_70_13_12_39_38_65_64_25_26_51_52_1_72_3_74_5_76_73_2_75_4_77_0;TICK;M_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;MX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKX(2)25;MARKZ(1)60;DT(0.5,1.5,1)rec[-36]_rec[-72];DT(0.5,3.5,1)rec[-35]_rec[-71];DT(0.5,5.5,1)rec[-34]_rec[-70];DT(1.5,0.5,1)rec[-33]_rec[-69];DT(1.5,2.5,1)rec[-32]_rec[-68];DT(1.5,4.5,1)rec[-31]_rec[-67];DT(2.5,1.5,1)rec[-30]_rec[-66];DT(2.5,3.5,1)rec[-29]_rec[-65];DT(2.5,5.5,1)rec[-28]_rec[-64];DT(3.5,0.5,1)rec[-27]_rec[-63];DT(3.5,2.5,1)rec[-26]_rec[-62];DT(3.5,4.5,1)rec[-25]_rec[-61];DT(4.5,1.5,1)rec[-24]_rec[-60];DT(4.5,3.5,1)rec[-23]_rec[-59];DT(4.5,5.5,1)rec[-22]_rec[-58];DT(5.5,0.5,1)rec[-21]_rec[-57];DT(5.5,2.5,1)rec[-20]_rec[-56];DT(5.5,4.5,1)rec[-19]_rec[-55];DT(0.5,0.5,1)rec[-18]_rec[-54];DT(0.5,2.5,1)rec[-17]_rec[-53];DT(0.5,4.5,1)rec[-16]_rec[-52];DT(1.5,1.5,1)rec[-15]_rec[-51];DT(1.5,3.5,1)rec[-14]_rec[-50];DT(1.5,5.5,1)rec[-13]_rec[-49];DT(2.5,0.5,1)rec[-12]_rec[-48];DT(2.5,2.5,1)rec[-11]_rec[-47];DT(2.5,4.5,1)rec[-10]_rec[-46];DT(3.5,1.5,1)rec[-9]_rec[-45];DT(3.5,3.5,1)rec[-8]_rec[-44];DT(3.5,5.5,1)rec[-7]_rec[-43];DT(4.5,0.5,1)rec[-6]_rec[-42];DT(4.5,2.5,1)rec[-5]_rec[-41];DT(4.5,4.5,1)rec[-4]_rec[-40];DT(5.5,1.5,1)rec[-3]_rec[-39];DT(5.5,3.5,1)rec[-2]_rec[-38];DT(5.5,5.5,1)rec[-1]_rec[-37];TICK;R_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;RX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKX(2)25;TICK;CX_7_0_1_8_9_2_3_10_11_4_5_12_13_20_21_14_15_22_23_16_17_24_25_18_33_26_27_34_35_28_29_36_37_30_31_38_39_46_47_40_41_48_49_42_43_50_51_44_59_52_53_60_61_54_55_62_63_56_57_64_65_72_73_66_67_74_75_68_69_76_77_70;TICK;CX_7_13_14_8_9_15_16_10_11_17_18_12_26_20_21_27_28_22_23_29_30_24_25_31_33_39_40_34_35_41_42_36_37_43_44_38_52_46_47_53_54_48_49_55_56_50_51_57_59_65_66_60_61_67_68_62_63_69_70_64_0_72_2_74_4_76_73_1_75_3_77_5;TICK;CX_7_1_2_8_9_3_4_10_11_5_14_20_21_15_16_22_23_17_18_24_33_27_28_34_35_29_30_36_37_31_40_46_47_41_42_48_49_43_44_50_59_53_54_60_61_55_56_62_63_57_66_72_73_67_68_74_75_69_70_76_0_12_26_38_52_64_25_13_51_39_77_65;TICK;CX_7_14_15_8_9_16_17_10_11_18_27_20_21_28_29_22_23_30_31_24_33_40_41_34_35_42_43_36_37_44_53_46_47_54_55_48_49_56_57_50_59_66_67_60_61_68_69_62_63_70_13_12_39_38_65_64_25_26_51_52_1_72_3_74_5_76_73_2_75_4_77_0;TICK;M_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;MX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKX(2)25;DT(0.5,1.5,2)rec[-36]_rec[-72];DT(0.5,3.5,2)rec[-35]_rec[-71];DT(0.5,5.5,2)rec[-34]_rec[-70];DT(1.5,0.5,2)rec[-33]_rec[-69];DT(1.5,2.5,2)rec[-32]_rec[-68];DT(1.5,4.5,2)rec[-31]_rec[-67];DT(2.5,1.5,2)rec[-30]_rec[-66];DT(2.5,3.5,2)rec[-29]_rec[-65];DT(2.5,5.5,2)rec[-28]_rec[-64];DT(3.5,0.5,2)rec[-27]_rec[-63];DT(3.5,2.5,2)rec[-26]_rec[-62];DT(3.5,4.5,2)rec[-25]_rec[-61];DT(4.5,1.5,2)rec[-24]_rec[-60];DT(4.5,3.5,2)rec[-23]_rec[-59];DT(4.5,5.5,2)rec[-22]_rec[-58];DT(5.5,0.5,2)rec[-21]_rec[-57];DT(5.5,2.5,2)rec[-20]_rec[-56];DT(5.5,4.5,2)rec[-19]_rec[-55];DT(0.5,0.5,2)rec[-18]_rec[-54];DT(0.5,2.5,2)rec[-17]_rec[-53];DT(0.5,4.5,2)rec[-16]_rec[-52];DT(1.5,1.5,2)rec[-15]_rec[-51];DT(1.5,3.5,2)rec[-14]_rec[-50];DT(1.5,5.5,2)rec[-13]_rec[-49];DT(2.5,0.5,2)rec[-12]_rec[-48];DT(2.5,2.5,2)rec[-11]_rec[-47];DT(2.5,4.5,2)rec[-10]_rec[-46];DT(3.5,1.5,2)rec[-9]_rec[-45];DT(3.5,3.5,2)rec[-8]_rec[-44];DT(3.5,5.5,2)rec[-7]_rec[-43];DT(4.5,0.5,2)rec[-6]_rec[-42];DT(4.5,2.5,2)rec[-5]_rec[-41];DT(4.5,4.5,2)rec[-4]_rec[-40];DT(5.5,1.5,2)rec[-3]_rec[-39];DT(5.5,3.5,2)rec[-2]_rec[-38];DT(5.5,5.5,2)rec[-1]_rec[-37];TICK;M_0_1_2_3_4_5_13_14_15_16_17_18_26_27_28_29_30_31_39_40_41_42_43_44_52_53_54_55_56_57_65_66_67_68_69_70;MARKZ(0)39_40_41_42_43_44;DT(0.5,1.5,3)rec[-28]_rec[-29]_rec[-34]_rec[-35]_rec[-72];DT(0.5,3.5,3)rec[-26]_rec[-27]_rec[-32]_rec[-33]_rec[-71];DT(0.5,5.5,3)rec[-25]_rec[-30]_rec[-31]_rec[-36]_rec[-70];DT(1.5,0.5,3)rec[-23]_rec[-24]_rec[-29]_rec[-30]_rec[-69];DT(1.5,2.5,3)rec[-21]_rec[-22]_rec[-27]_rec[-28]_rec[-68];DT(1.5,4.5,3)rec[-19]_rec[-20]_rec[-25]_rec[-26]_rec[-67];DT(2.5,1.5,3)rec[-16]_rec[-17]_rec[-22]_rec[-23]_rec[-66];DT(2.5,3.5,3)rec[-14]_rec[-15]_rec[-20]_rec[-21]_rec[-65];DT(2.5,5.5,3)rec[-13]_rec[-18]_rec[-19]_rec[-24]_rec[-64];DT(3.5,0.5,3)rec[-11]_rec[-12]_rec[-17]_rec[-18]_rec[-63];DT(3.5,2.5,3)rec[-9]_rec[-10]_rec[-15]_rec[-16]_rec[-62];DT(3.5,4.5,3)rec[-7]_rec[-8]_rec[-13]_rec[-14]_rec[-61];DT(5.5,0.5,3)rec[-5]_rec[-6]_rec[-35]_rec[-36]_rec[-57];DT(4.5,1.5,3)rec[-4]_rec[-5]_rec[-10]_rec[-11]_rec[-60];DT(5.5,2.5,3)rec[-3]_rec[-4]_rec[-33]_rec[-34]_rec[-56];DT(4.5,3.5,3)rec[-2]_rec[-3]_rec[-8]_rec[-9]_rec[-59];DT(5.5,4.5,3)rec[-1]_rec[-2]_rec[-31]_rec[-32]_rec[-55];DT(4.5,5.5,3)rec[-1]_rec[-6]_rec[-7]_rec[-12]_rec[-58];OI(0)rec[-3]_rec[-9]_rec[-15]_rec[-21]_rec[-27]_rec[-33];OI(1)rec[-13]_rec[-14]_rec[-15]_rec[-16]_rec[-17]_rec[-18]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr style=\"border-top: 3px solid black;\">\n                            <td>Color Code</td>\n                            <td>Superdense</td>\n                            <td>Stability (X+Z)</td>\n                            <td>6x4x4</td>\n                            <td><a href=\"\n                                #circuit=Q(0,1)0;Q(0,2)1;Q(0,3)2;Q(1,0)3;Q(1,1)4;Q(1,2)5;Q(1,3)6;Q(1,4)7;Q(2,0)8;Q(2,1)9;Q(2,2)10;Q(2,3)11;Q(2,4)12;Q(3,0)13;Q(3,1)14;Q(3,2)15;Q(3,3)16;Q(3,4)17;Q(4,0)18;Q(4,1)19;Q(4,2)20;Q(4,3)21;Q(4,4)22;Q(5,1)23;Q(5,2)24;Q(5,3)25;POLYGON(0,1,1,0.25)14_18_24_20;POLYGON(0,1,1,0.25)11_16_22_7;POLYGON(0,1,1,0.25)3_9_5_1;POLYGON(1,0,1,0.25)9_14_20_16_11_5;POLYGON(1,1,0,0.25)3_18_14_9;POLYGON(1,1,0,0.25)20_24_22_16;POLYGON(1,1,0,0.25)1_5_11_7;TICK;R_13_6_17_15_23_25_4;RX_21_2_12_10_19_8_0;MARKZ(0)15;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;CX_21_20_12_11_10_9_19_18_25_24_17_16_15_14_2_1_6_5_4_3;TICK;CX_21_16_12_7_10_5_19_14_6_11_17_22_15_20_13_18_8_3_4_9;TICK;CX_6_7_10_11_15_16_21_22_19_20_23_24_8_9_13_14_0_1_4_5;TICK;CX_20_21_11_12_9_10_18_19_24_25_16_17_14_15_1_2_5_6_3_4;TICK;CX_16_21_7_12_5_10_14_19_11_6_22_17_20_15_18_13_3_8_9_4;TICK;CX_7_6_11_10_16_15_22_21_20_19_24_23_9_8_14_13_1_0_5_4;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;M_25_6_17_15_23_13_4;MX_21_2_12_10_19_8_0;MARKZ(0)15;OI(0)rec[-1]_rec[-2]_rec[-3]_rec[-5]_rec[-6]_rec[-7];OI(1)rec[-8]_rec[-9]_rec[-10]_rec[-12]_rec[-13]_rec[-14];TICK;R_13_6_17_15_23_25_4;RX_21_2_12_10_19_8_0;MARKX(1)0_2_12_21_19_8;MARKZ(0)17_13;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;CX_21_20_12_11_10_9_19_18_25_24_17_16_15_14_2_1_6_5_4_3;TICK;CX_21_16_12_7_10_5_19_14_6_11_17_22_15_20_13_18_8_3_4_9;TICK;CX_6_7_10_11_15_16_21_22_19_20_23_24_8_9_13_14_0_1_4_5;TICK;CX_20_21_11_12_9_10_18_19_24_25_16_17_14_15_1_2_5_6_3_4;TICK;CX_16_21_7_12_5_10_14_19_11_6_22_17_20_15_18_13_3_8_9_4;TICK;CX_7_6_11_10_16_15_22_21_20_19_24_23_9_8_14_13_1_0_5_4;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;M_25_6_17_15_23_13_4;MX_21_2_12_10_19_8_0;MARKX(1)8_0_2_12_21_19;MARKZ(0)15;DT(5,3,0)rec[-14]_rec[-28];DT(1,3,0)rec[-13]_rec[-27];DT(3,4,0)rec[-12]_rec[-26];DT(3,2,0)rec[-11]_rec[-25];DT(5,1,0)rec[-10]_rec[-24];DT(3,0,0)rec[-9]_rec[-23];DT(1,1,0)rec[-8]_rec[-22];DT(4,1,0)rec[-7]_rec[-17];DT(0,1,0)rec[-6]_rec[-15];DT(2,2,0)rec[-5]_rec[-18]_rec[-19];DT(2,0,0)rec[-4]_rec[-16]_rec[-19];DT(4,3,0)rec[-3]_rec[-21];DT(2,0.5,0)rec[-2]_rec[-16]_rec[-18];DT(0,3,0)rec[-1]_rec[-20];TICK;R_13_6_17_15_23_25_4;RX_21_2_12_10_19_8_0;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;CX_21_20_12_11_10_9_19_18_25_24_17_16_15_14_2_1_6_5_4_3;TICK;CX_21_16_12_7_10_5_19_14_6_11_17_22_15_20_13_18_8_3_4_9;TICK;CX_6_7_10_11_15_16_21_22_19_20_23_24_8_9_13_14_0_1_4_5;TICK;CX_20_21_11_12_9_10_18_19_24_25_16_17_14_15_1_2_5_6_3_4;TICK;CX_16_21_7_12_5_10_14_19_11_6_22_17_20_15_18_13_3_8_9_4;TICK;CX_7_6_11_10_16_15_22_21_20_19_24_23_9_8_14_13_1_0_5_4;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;M_25_6_17_15_23_13_4;MX_21_2_12_10_19_8_0;DT(5,3,1)rec[-14]_rec[-28];DT(1,3,1)rec[-13]_rec[-27];DT(3,4,1)rec[-12]_rec[-26];DT(3,2,1)rec[-11]_rec[-25];DT(5,1,1)rec[-10]_rec[-24];DT(3,0,1)rec[-9]_rec[-23];DT(1,1,1)rec[-8]_rec[-22];DT(4,1,1)rec[-7]_rec[-17];DT(0,1,1)rec[-6]_rec[-15];DT(2,2,1)rec[-5]_rec[-18]_rec[-19];DT(2,0,1)rec[-4]_rec[-16]_rec[-19];DT(4,3,1)rec[-3]_rec[-21];DT(2,0.5,1)rec[-2]_rec[-16]_rec[-18];DT(0,3,1)rec[-1]_rec[-20];TICK;R_13_6_17_15_23_25_4;RX_21_2_12_10_19_8_0;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;CX_21_20_12_11_10_9_19_18_25_24_17_16_15_14_2_1_6_5_4_3;TICK;CX_21_16_12_7_10_5_19_14_6_11_17_22_15_20_13_18_8_3_4_9;TICK;CX_6_7_10_11_15_16_21_22_19_20_23_24_8_9_13_14_0_1_4_5;TICK;CX_20_21_11_12_9_10_18_19_24_25_16_17_14_15_1_2_5_6_3_4;TICK;CX_16_21_7_12_5_10_14_19_11_6_22_17_20_15_18_13_3_8_9_4;TICK;CX_7_6_11_10_16_15_22_21_20_19_24_23_9_8_14_13_1_0_5_4;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;M_25_6_17_15_23_13_4;MX_21_2_12_10_19_8_0;DT(5,3,2)rec[-14]_rec[-28];DT(1,3,2)rec[-13]_rec[-27];DT(3,4,2)rec[-12]_rec[-26];DT(3,2,2)rec[-11]_rec[-25];DT(5,1,2)rec[-10]_rec[-24];DT(3,0,2)rec[-9]_rec[-23];DT(1,1,2)rec[-8]_rec[-22];DT(4,1,2)rec[-7]_rec[-17];DT(0,1,2)rec[-6]_rec[-15];DT(2,2,2)rec[-5]_rec[-18]_rec[-19];DT(2,0,2)rec[-4]_rec[-16]_rec[-19];DT(4,3,2)rec[-3]_rec[-21];DT(2,0.5,2)rec[-2]_rec[-16]_rec[-18];DT(0,3,2)rec[-1]_rec[-20]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr>\n                            <td>Surface Code</td>\n                            <td>Standard (ИZ)</td>\n                            <td>Stability (Z)</td>\n                            <td>4x4x5</td>\n                            <td><a href=\"\n                                #circuit=Q(0,1)0;Q(0,3)1;Q(0.5,0.5)2;Q(0.5,1.5)3;Q(0.5,2.5)4;Q(0.5,3.5)5;Q(1,0)6;Q(1,1)7;Q(1,2)8;Q(1,3)9;Q(1,4)10;Q(1.5,0.5)11;Q(1.5,1.5)12;Q(1.5,2.5)13;Q(1.5,3.5)14;Q(2,1)15;Q(2,2)16;Q(2,3)17;Q(2.5,0.5)18;Q(2.5,1.5)19;Q(2.5,2.5)20;Q(2.5,3.5)21;Q(3,0)22;Q(3,1)23;Q(3,2)24;Q(3,3)25;Q(3,4)26;Q(3.5,0.5)27;Q(3.5,1.5)28;Q(3.5,2.5)29;Q(3.5,3.5)30;Q(4,1)31;Q(4,3)32;POLYGON(0,0,1,0.25)11_2;POLYGON(0,0,1,0.25)3_12_13_4;POLYGON(0,0,1,0.25)2_3;POLYGON(0,0,1,0.25)13_20_21_14;POLYGON(0,0,1,0.25)19_28_29_20;POLYGON(0,0,1,0.25)11_18_19_12;POLYGON(0,0,1,0.25)27_18;POLYGON(0,0,1,0.25)27_28;POLYGON(0,0,1,0.25)4_5;POLYGON(0,0,1,0.25)14_5;POLYGON(0,0,1,0.25)30_21;POLYGON(0,0,1,0.25)29_30;POLYGON(1,0,0,0.25)2_11_12_3;POLYGON(1,0,0,0.25)12_19_20_13;POLYGON(1,0,0,0.25)18_27_28_19;POLYGON(1,0,0,0.25)20_29_30_21;POLYGON(1,0,0,0.25)4_13_14_5;TICK;RY_2_3_4_5_11_12_13_14_18_19_20_21_27_28_29_30;TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;OI(0)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-11]_rec[-12]_rec[-13]_rec[-14]_rec[-15]_rec[-16]_rec[-17];TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;MARKZ(0)6_8_10_15_17_22_24_26_31_32_0_1;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;MARKZ(0)6_8_10_15_17_22_24_26_31_32_0_1;DT(0,1,0)rec[-17]_rec[-34];DT(0,3,0)rec[-16]_rec[-33];DT(1,0,0)rec[-15]_rec[-32];DT(1,2,0)rec[-14]_rec[-31];DT(1,4,0)rec[-13]_rec[-30];DT(2,1,0)rec[-12]_rec[-29];DT(2,3,0)rec[-11]_rec[-28];DT(3,0,0)rec[-10]_rec[-27];DT(3,2,0)rec[-9]_rec[-26];DT(3,4,0)rec[-8]_rec[-25];DT(4,1,0)rec[-7]_rec[-24];DT(4,3,0)rec[-6]_rec[-23];DT(1,1,0)rec[-5]_rec[-22];DT(1,3,0)rec[-4]_rec[-21];DT(3,3,0)rec[-3]_rec[-20];DT(3,1,0)rec[-2]_rec[-19];DT(2,2,0)rec[-1]_rec[-18];TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;DT(0,1,1)rec[-17]_rec[-34];DT(0,3,1)rec[-16]_rec[-33];DT(1,0,1)rec[-15]_rec[-32];DT(1,2,1)rec[-14]_rec[-31];DT(1,4,1)rec[-13]_rec[-30];DT(2,1,1)rec[-12]_rec[-29];DT(2,3,1)rec[-11]_rec[-28];DT(3,0,1)rec[-10]_rec[-27];DT(3,2,1)rec[-9]_rec[-26];DT(3,4,1)rec[-8]_rec[-25];DT(4,1,1)rec[-7]_rec[-24];DT(4,3,1)rec[-6]_rec[-23];DT(1,1,1)rec[-5]_rec[-22];DT(1,3,1)rec[-4]_rec[-21];DT(3,3,1)rec[-3]_rec[-20];DT(3,1,1)rec[-2]_rec[-19];DT(2,2,1)rec[-1]_rec[-18];TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;DT(0,1,2)rec[-17]_rec[-34];DT(0,3,2)rec[-16]_rec[-33];DT(1,0,2)rec[-15]_rec[-32];DT(1,2,2)rec[-14]_rec[-31];DT(1,4,2)rec[-13]_rec[-30];DT(2,1,2)rec[-12]_rec[-29];DT(2,3,2)rec[-11]_rec[-28];DT(3,0,2)rec[-10]_rec[-27];DT(3,2,2)rec[-9]_rec[-26];DT(3,4,2)rec[-8]_rec[-25];DT(4,1,2)rec[-7]_rec[-24];DT(4,3,2)rec[-6]_rec[-23];DT(1,1,2)rec[-5]_rec[-22];DT(1,3,2)rec[-4]_rec[-21];DT(3,3,2)rec[-3]_rec[-20];DT(3,1,2)rec[-2]_rec[-19];DT(2,2,2)rec[-1]_rec[-18];TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;DT(0,1,3)rec[-17]_rec[-34];DT(0,3,3)rec[-16]_rec[-33];DT(1,0,3)rec[-15]_rec[-32];DT(1,2,3)rec[-14]_rec[-31];DT(1,4,3)rec[-13]_rec[-30];DT(2,1,3)rec[-12]_rec[-29];DT(2,3,3)rec[-11]_rec[-28];DT(3,0,3)rec[-10]_rec[-27];DT(3,2,3)rec[-9]_rec[-26];DT(3,4,3)rec[-8]_rec[-25];DT(4,1,3)rec[-7]_rec[-24];DT(4,3,3)rec[-6]_rec[-23];DT(1,1,3)rec[-5]_rec[-22];DT(1,3,3)rec[-4]_rec[-21];DT(3,3,3)rec[-3]_rec[-20];DT(3,1,3)rec[-2]_rec[-19];DT(2,2,3)rec[-1]_rec[-18];TICK;MY_2_3_4_5_11_12_13_14_18_19_20_21_27_28_29_30\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr style=\"border-top: 3px solid black;\">\n                            <td>Surface Code</td>\n                            <td>Standard (ИZ)</td>\n                            <td>Prepare (RY)</td>\n                            <td>5x5x4</td>\n                            <td><a href=\"\n                                #circuit=Q(0,2)0;Q(0,4)1;Q(0.5,0.5)2;Q(0.5,1.5)3;Q(0.5,2.5)4;Q(0.5,3.5)5;Q(0.5,4.5)6;Q(1,0)7;Q(1,1)8;Q(1,2)9;Q(1,3)10;Q(1,4)11;Q(1.5,0.5)12;Q(1.5,1.5)13;Q(1.5,2.5)14;Q(1.5,3.5)15;Q(1.5,4.5)16;Q(2,0)17;Q(2,1)18;Q(2,2)19;Q(2,3)20;Q(2,4)21;Q(2,5)22;Q(2.5,0.5)23;Q(2.5,1.5)24;Q(2.5,2.5)25;Q(2.5,3.5)26;Q(2.5,4.5)27;Q(3,0)28;Q(3,1)29;Q(3,2)30;Q(3,3)31;Q(3,4)32;Q(3.5,0.5)33;Q(3.5,1.5)34;Q(3.5,2.5)35;Q(3.5,3.5)36;Q(3.5,4.5)37;Q(4,0)38;Q(4,1)39;Q(4,2)40;Q(4,3)41;Q(4,4)42;Q(4,5)43;Q(4.5,0.5)44;Q(4.5,1.5)45;Q(4.5,2.5)46;Q(4.5,3.5)47;Q(4.5,4.5)48;Q(5,1)49;Q(5,2)50;Q(5,3)51;Q(5,4)52;POLYGON(0,0,1,0.25)12_13_3;POLYGON(0,0,1,0.25)4_14_15_5;POLYGON(0,0,1,0.25)13_24_25_14;POLYGON(0,0,1,0.25)15_26_27_16;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)34_45_46_35;POLYGON(0,0,1,0.25)36_47_48_37;POLYGON(0,0,1,0.25)3_4;POLYGON(0,0,1,0.25)5_6;POLYGON(0,0,1,0.25)23_12;POLYGON(0,0,1,0.25)44_33;POLYGON(1,0,0,0.25)3_13_14_4;POLYGON(1,0,0,0.25)5_15_16_6;POLYGON(1,0,0,0.25)12_23_24_13;POLYGON(1,0,0,0.25)14_25_26_15;POLYGON(1,0,0,0.25)24_34_35_25;POLYGON(1,0,0,0.25)26_36_37_27;POLYGON(1,0,0,0.25)33_44_45_34;POLYGON(1,0,0,0.25)35_46_47_36;POLYGON(1,0,0,0.25)27_16;POLYGON(1,0,0,0.25)48_37;POLYGON(1,0,0,0.25)47_48;POLYGON(1,0,0,0.25)45_46;TICK;R_25_15_14_13_24_34_44_33_23_12_3_4_5_6;RX_45_46_35_47_36_26_48_37_27_16;TICK;R_0_1_42_40_38_31_29_21_19_17_10_8;RX_52_50_43_41_39_32_30_22_20_18_11_9;TICK;CX_37_42_35_40_33_38_26_31_24_29_16_21_14_19_12_17_5_10_3_8_52_48_50_46_41_36_39_34_32_27_30_25_20_15_18_13_11_6_9_4;TICK;CX_41_47_39_45_32_37_30_35_20_26_18_24_11_16_9_14_36_42_34_40_25_31_23_29_15_21_13_19_4_10;TICK;CX_52_47_50_45_43_37_41_35_39_33_32_26_30_24_22_16_20_14_18_12_11_5_9_3_4_0_6_1_48_42_46_40_44_38_36_31_34_29_27_21_25_19_23_17_15_10_13_8;TICK;CX_43_48_41_46_39_44_32_36_30_34_22_27_20_25_18_23_11_15_9_13_3_0_5_1_47_42_45_40_35_31_33_29_26_21_24_19_14_10_12_8;TICK;M_1_0_42_40_38_31_29_21_19_17_10_8;MX_52_50_43_41_39_32_30_22_20_18_11_9;DT(0,4,0)rec[-24];DT(0,2,0)rec[-23];DT(4,0,0)rec[-20];DT(3,1,0)rec[-18];DT(2,2,0)rec[-16];DT(2,0,0)rec[-15];DT(1,3,0)rec[-14];DT(1,1,0)rec[-13];DT(5,4,0)rec[-12];DT(5,2,0)rec[-11];DT(4,5,0)rec[-10];DT(4,3,0)rec[-9];DT(3,4,0)rec[-7];DT(2,5,0)rec[-5];TICK;R_0_1_42_40_38_31_29_21_19_17_10_8;RX_52_50_43_41_39_32_30_22_20_18_11_9;TICK;CX_37_42_35_40_33_38_26_31_24_29_16_21_14_19_12_17_5_10_3_8_52_48_50_46_41_36_39_34_32_27_30_25_20_15_18_13_11_6_9_4;TICK;CX_41_47_39_45_32_37_30_35_20_26_18_24_11_16_9_14_36_42_34_40_25_31_23_29_15_21_13_19_4_10;TICK;CX_52_47_50_45_43_37_41_35_39_33_32_26_30_24_22_16_20_14_18_12_11_5_9_3_4_0_6_1_48_42_46_40_44_38_36_31_34_29_27_21_25_19_23_17_15_10_13_8;TICK;CX_43_48_41_46_39_44_32_36_30_34_22_27_20_25_18_23_11_15_9_13_3_0_5_1_47_42_45_40_35_31_33_29_26_21_24_19_14_10_12_8;TICK;M_1_0_42_40_38_31_29_21_19_17_10_8;MX_52_50_43_41_39_32_30_22_20_18_11_9;DT(0,4,1)rec[-24]_rec[-48];DT(0,2,1)rec[-23]_rec[-47];DT(4,4,1)rec[-22]_rec[-46];DT(4,2,1)rec[-21]_rec[-45];DT(4,0,1)rec[-20]_rec[-44];DT(3,3,1)rec[-19]_rec[-43];DT(3,1,1)rec[-18]_rec[-42];DT(2,4,1)rec[-17]_rec[-41];DT(2,2,1)rec[-16]_rec[-40];DT(2,0,1)rec[-15]_rec[-39];DT(1,3,1)rec[-14]_rec[-38];DT(1,1,1)rec[-13]_rec[-37];DT(5,4,1)rec[-12]_rec[-36];DT(5,2,1)rec[-11]_rec[-35];DT(4,5,1)rec[-10]_rec[-34];DT(4,3,1)rec[-9]_rec[-33];DT(4,1,1)rec[-8]_rec[-32];DT(3,4,1)rec[-7]_rec[-31];DT(3,2,1)rec[-6]_rec[-30];DT(2,5,1)rec[-5]_rec[-29];DT(2,3,1)rec[-4]_rec[-28];DT(2,1,1)rec[-3]_rec[-27];DT(1,4,1)rec[-2]_rec[-26];DT(1,2,1)rec[-1]_rec[-25];TICK;POLYGON(0,0,1,0.25)13_24_25_14;POLYGON(0,0,1,0.25)4_14_15_5;POLYGON(0,0,1,0.25)15_26_27_16;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)3_4;POLYGON(0,0,1,0.25)5_6;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)2_12_13_3;POLYGON(0,0,1,0.25)34_45_46_35;POLYGON(0,0,1,0.25)36_47_48_37;POLYGON(0,0,1,0.25)38;POLYGON(0,0,1,0.25)28;POLYGON(0,0,1,0.25)17;POLYGON(0,0,1,0.25)7;POLYGON(0,0.5,0,1)2_48;POLYGON(1,0,0,0.25)3_13_14_4;POLYGON(1,0,0,0.25)14_25_26_15;POLYGON(1,0,0,0.25)5_15_16_6;POLYGON(1,0,0,0.25)26_36_37_27;POLYGON(1,0,0,0.25)24_34_35_25;POLYGON(1,0,0,0.25)27_16;POLYGON(1,0,0,0.25)48_37;POLYGON(1,0,0,0.25)12_23_24_13;POLYGON(1,0,0,0.25)33_44_45_34;POLYGON(1,0,0,0.25)35_46_47_36;POLYGON(1,0,0,0.25)52;POLYGON(1,0,0,0.25)51;POLYGON(1,0,0,0.25)50;POLYGON(1,0,0,0.25)49;TICK;R_42_40_38_31_29_28_21_19_17_10_8_7_1_0;RX_52_51_50_49_43_41_39_32_30_22_20_18_11_9;RY_2;TICK;H_52_51_50_49_41_40_39_38_30_29_28_18_17_7_47_46_45_44_35_34_33_24_23_12;SQRT_X_DAG_42_31_19_8;TICK;XCY_48_52_36_41_25_30_13_18;TICK;CX_26_21_14_10_5_1_3_0_43_48_32_36_22_27_20_25_11_15_9_13_51_47_49_45_40_35_38_33_29_24_17_12_46_50_34_39_23_28;TICK;CX_27_21_15_10_6_1_4_0_43_37_32_26_22_16_20_14_11_5_9_3_40_46_38_44_29_34_17_23_47_52_45_50_35_41_33_39_24_30_12_18;XCY_42_48_31_36_19_25_8_13;TICK;CX_46_51_44_49_36_42_34_40_25_31_23_29_15_21_13_19_4_10_2_8_41_47_39_45_32_37_30_35_28_33_20_26_18_24_11_16_9_14_7_12;TICK;CX_47_51_45_49_37_42_35_40_26_31_24_29_16_21_14_19_5_10_3_8_41_36_39_34_32_27_30_25_28_23_20_15_18_13_11_6_9_4_7_2;TICK;M_52_51_50_49_42_40_31_29_21_19_10_8_1_0;MX_43_41_39_38_32_30_28_22_20_18_17_11_9_7;DT(5,4,2)rec[-28]_rec[-40];DT(4,3,2)rec[-27]_rec[-37];DT(5,2,2)rec[-26]_rec[-39];DT(4,1,2)rec[-25]_rec[-36];DT(3,2,2)rec[-23]_rec[-34];DT(2,1,2)rec[-21]_rec[-31];DT(2,4,2)rec[-20]_rec[-45];DT(1,3,2)rec[-18]_rec[-42];DT(0,4,2)rec[-16]_rec[-52];DT(0,2,2)rec[-15]_rec[-51];DT(4,5,2)rec[-14]_rec[-38];DT(4,4,2)rec[-13]_rec[-24]_rec[-50];DT(4,2,2)rec[-12]_rec[-49];DT(4,0,2)rec[-11]_rec[-48];DT(3,4,2)rec[-10]_rec[-35];DT(3,3,2)rec[-9]_rec[-22]_rec[-47];DT(3,1,2)rec[-8]_rec[-46];DT(2,5,2)rec[-7]_rec[-33];DT(2,3,2)rec[-6]_rec[-32];DT(2,2,2)rec[-5]_rec[-19]_rec[-44];DT(2,0,2)rec[-4]_rec[-43];DT(1,4,2)rec[-3]_rec[-30];DT(1,2,2)rec[-2]_rec[-29];DT(1,1,2)rec[-1]_rec[-17]_rec[-41];TICK;POLYGON(0,0,1,0.25)2_12_13_3;POLYGON(0,0,1,0.25)13_24_25_14;POLYGON(0,0,1,0.25)4_14_15_5;POLYGON(0,0,1,0.25)15_26_27_16;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)36_47_48_37;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)34_45_46_35;POLYGON(0,0,1,0.25)44_45;POLYGON(0,0,1,0.25)3_4;POLYGON(0,0,1,0.25)5_6;POLYGON(0,0,1,0.25)46_47;POLYGON(1,0,0,0.25)12_23_24_13;POLYGON(1,0,0,0.25)3_13_14_4;POLYGON(1,0,0,0.25)14_25_26_15;POLYGON(1,0,0,0.25)5_15_16_6;POLYGON(1,0,0,0.25)35_46_47_36;POLYGON(1,0,0,0.25)26_36_37_27;POLYGON(1,0,0,0.25)33_44_45_34;POLYGON(1,0,0,0.25)24_34_35_25;POLYGON(1,0,0,0.25)12_2;POLYGON(1,0,0,0.25)33_23;POLYGON(1,0,0,0.25)27_16;POLYGON(1,0,0,0.25)48_37;TICK;MPP_X33*X23_X12*X2_X27*X37*X36*X26_X25*X35*X34*X24_X4*X14*X13*X3_X6*X16*X15*X5;DT(3,0,3)rec[-6]_rec[-14];DT(1,0,3)rec[-5]_rec[-7];DT(3,4,3)rec[-4]_rec[-16];DT(3,2,3)rec[-3]_rec[-15];DT(1,2,3)rec[-2]_rec[-8];DT(1,4,3)rec[-1]_rec[-9];TICK;MPP_X48*X37_X27*X16_X36*X47*X46*X35_X34*X45*X44*X33_X13*X24*X23*X12_X15*X26*X25*X14;DT(4,5,4)rec[-6]_rec[-26];DT(2,5,4)rec[-5]_rec[-19];DT(4,3,4)rec[-4]_rec[-25];DT(4,0,4)rec[-3]_rec[-23]_rec[-24];DT(2,0,4)rec[-2]_rec[-16]_rec[-17];DT(2,3,4)rec[-1]_rec[-18];TICK;MPP_Z6*Z5_Z4*Z3_Z35*Z46*Z45*Z34_Z37*Z48*Z47*Z36_Z16*Z27*Z26*Z15_Z14*Z25*Z24*Z13;DT(0,4,5)rec[-6]_rec[-34];DT(0,2,5)rec[-5]_rec[-33];DT(4,2,5)rec[-4]_rec[-41]_rec[-44];DT(4,4,5)rec[-3]_rec[-42]_rec[-46];DT(2,4,5)rec[-2]_rec[-38];DT(2,2,5)rec[-1]_rec[-37];TICK;MPP_Z47*Z46_Z45*Z44_Z24*Z34*Z33*Z23_Z26*Z36*Z35*Z25_Z5*Z15*Z14*Z4_Z3*Z13*Z12*Z2;DT(5,3,6)rec[-6]_rec[-51];DT(5,1,6)rec[-5]_rec[-49];DT(3,1,6)rec[-4]_rec[-45];DT(3,3,6)rec[-3]_rec[-46];DT(1,3,6)rec[-2]_rec[-42];DT(1,1,6)rec[-1]_rec[-41];TICK;MPP_X6*X5*X4*X3*Y2*Z23*Z12*Z44*Z33;OI(0)rec[-1]_rec[-54]_rec[-55]_rec[-56]_rec[-57]_rec[-58]_rec[-59]_rec[-60]_rec[-61]_rec[-62]_rec[-63]_rec[-64]_rec[-65]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                        <tr>\n                            <td>Surface Code</td>\n                            <td>Standard (ИZ)</td>\n                            <td>Surgery (MZZ)</td>\n                            <td>7x3x5</td>\n                            <td><a href=\"\n                                #circuit=Q(0,2)0;Q(0.5,0.5)1;Q(0.5,1.5)2;Q(0.5,2.5)3;Q(1,0)4;Q(1,1)5;Q(1,2)6;Q(1.5,0.5)7;Q(1.5,1.5)8;Q(1.5,2.5)9;Q(2,1)10;Q(2,2)11;Q(2,3)12;Q(2.5,0.5)13;Q(2.5,1.5)14;Q(2.5,2.5)15;Q(3,0)16;Q(3,1)17;Q(3,2)18;Q(3.5,0.5)19;Q(3.5,1.5)20;Q(3.5,2.5)21;Q(4,1)22;Q(4,2)23;Q(4,3)24;Q(4.5,0.5)25;Q(4.5,1.5)26;Q(4.5,2.5)27;Q(5,0)28;Q(5,1)29;Q(5,2)30;Q(5.5,0.5)31;Q(5.5,1.5)32;Q(5.5,2.5)33;Q(6,1)34;Q(6,2)35;Q(6,3)36;Q(6.5,0.5)37;Q(6.5,1.5)38;Q(6.5,2.5)39;Q(7,1)40;POLYGON(0,0,1,0.25)7_13_14_8;POLYGON(0,0,1,0.25)2_8_9_3;POLYGON(0,0,1,0.25)7_1;POLYGON(0,0,1,0.25)15_9;POLYGON(0,0,1,0.25)31_37_38_32;POLYGON(0,0,1,0.25)26_32_33_27;POLYGON(0,0,1,0.25)31_25;POLYGON(0,0,1,0.25)39_33;POLYGON(1,0,0,0.25)1_7_8_2;POLYGON(1,0,0,0.25)8_14_15_9;POLYGON(1,0,0,0.25)2_3;POLYGON(1,0,0,0.25)13_14;POLYGON(1,0,0,0.25)25_31_32_26;POLYGON(1,0,0,0.25)32_38_39_33;POLYGON(1,0,0,0.25)26_27;POLYGON(1,0,0,0.25)37_38;TICK;R_1_2_3_7_8_9_13_14_15_25_26_27_31_32_33_37_38_39;MARKZ(1)25_26_27_13_14_15;TICK;R_6_10_4_12_30_34_28_36;RX_5_11_0_17_29_35_23_40;MARKX(0)1_7_13_25_31_37;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38;TICK;CX_5_8_9_6_14_10_11_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28;TICK;M_6_10_4_12_30_34_28_36;MX_5_11_0_17_29_35_23_40;DT(1,2,0)rec[-16];DT(2,1,0)rec[-15];DT(1,0,0)rec[-14];DT(2,3,0)rec[-13];DT(5,2,0)rec[-12];DT(6,1,0)rec[-11];DT(5,0,0)rec[-10];DT(6,3,0)rec[-9];TICK;POLYGON(0,0,1,0.25)2_8_9_3;POLYGON(0,0,1,0.25)7_1;POLYGON(0,0,1,0.25)15_9;POLYGON(0,0,1,0.25)31_37_38_32;POLYGON(0,0,1,0.25)31_25;POLYGON(0,0,1,0.25)39_33;POLYGON(0,0,1,0.25)7_13_14_8;POLYGON(0,0,1,0.25)26_32_33_27;POLYGON(1,0,0,0.25)1_7_8_2;POLYGON(1,0,0,0.25)8_14_15_9;POLYGON(1,0,0,0.25)2_3;POLYGON(1,0,0,0.25)25_31_32_26;POLYGON(1,0,0,0.25)32_38_39_33;POLYGON(1,0,0,0.25)37_38;POLYGON(1,0,0,0.25)20;POLYGON(1,0,0,0.25)19;POLYGON(1,0,0,0.25)21;POLYGON(1,0,0,0.25)13_19_20_14;POLYGON(1,0,0,0.25)20_26_27_21;TICK;R_6_10_4_12_30_34_28_36_18_22_24_16;RX_5_11_0_17_29_35_23_40_19_20_21;MARKX(0)19;MARKZ(1)18_16_24_22;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37_14_18_19_22_23_20_21_24;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38_20_18_23_21_27_24_25_22;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38_15_18_20_22_17_19_13_16;TICK;CX_5_8_9_6_14_10_11_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28_17_20_26_22_19_16_21_18;TICK;M_6_10_4_12_30_34_28_36_24_16_22_18;MX_5_11_0_17_29_35_23_40;MARKZ(1)24_16_22_18;DT(1,2,1)rec[-20]_rec[-36];DT(2,1,1)rec[-19]_rec[-35];DT(1,0,1)rec[-18]_rec[-34];DT(2,3,1)rec[-17]_rec[-33];DT(5,2,1)rec[-16]_rec[-32];DT(6,1,1)rec[-15]_rec[-31];DT(5,0,1)rec[-14]_rec[-30];DT(6,3,1)rec[-13]_rec[-29];DT(1,1,1)rec[-8]_rec[-28];DT(2,2,1)rec[-7]_rec[-27];DT(0,2,1)rec[-6]_rec[-26];DT(3,1,1)rec[-5]_rec[-25];DT(5,1,1)rec[-4]_rec[-24];DT(6,2,1)rec[-3]_rec[-23];DT(4,2,1)rec[-2]_rec[-22];DT(7,1,1)rec[-1]_rec[-21];OI(0)rec[-9]_rec[-10]_rec[-11]_rec[-12]_rec[-17]_rec[-18]_rec[-19]_rec[-20];TICK;POLYGON(0,0,1,0.25)2_8_9_3;POLYGON(0,0,1,0.25)7_1;POLYGON(0,0,1,0.25)15_9;POLYGON(0,0,1,0.25)31_37_38_32;POLYGON(0,0,1,0.25)31_25;POLYGON(0,0,1,0.25)39_33;POLYGON(0,0,1,0.25)7_13_14_8;POLYGON(0,0,1,0.25)26_32_33_27;POLYGON(0,0,1,0.25)19_25_26_20;POLYGON(0,0,1,0.25)19_13;POLYGON(0,0,1,0.25)27_21;POLYGON(0,0,1,0.25)14_20_21_15;POLYGON(1,0,0,0.25)1_7_8_2;POLYGON(1,0,0,0.25)8_14_15_9;POLYGON(1,0,0,0.25)2_3;POLYGON(1,0,0,0.25)25_31_32_26;POLYGON(1,0,0,0.25)32_38_39_33;POLYGON(1,0,0,0.25)37_38;POLYGON(1,0,0,0.25)13_19_20_14;POLYGON(1,0,0,0.25)20_26_27_21;TICK;R_6_10_4_12_30_34_28_36_18_22_24_16;RX_5_11_0_17_29_35_23_40;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37_14_18_19_22_23_20_21_24;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38_20_18_23_21_27_24_25_22;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38_15_18_20_22_17_19_13_16;TICK;CX_5_8_9_6_14_10_11_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28_17_20_26_22_19_16_21_18;TICK;M_6_10_4_12_30_34_28_36_24_16_22_18;MX_5_11_0_17_29_35_23_40;DT(1,2,2)rec[-20]_rec[-40];DT(2,1,2)rec[-19]_rec[-39];DT(1,0,2)rec[-18]_rec[-38];DT(2,3,2)rec[-17]_rec[-37];DT(5,2,2)rec[-16]_rec[-36];DT(6,1,2)rec[-15]_rec[-35];DT(5,0,2)rec[-14]_rec[-34];DT(6,3,2)rec[-13]_rec[-33];DT(4,3,2)rec[-12]_rec[-32];DT(3,0,2)rec[-11]_rec[-31];DT(4,1,2)rec[-10]_rec[-30];DT(3,2,2)rec[-9]_rec[-29];DT(1,1,2)rec[-8]_rec[-28];DT(2,2,2)rec[-7]_rec[-27];DT(0,2,2)rec[-6]_rec[-26];DT(3,1,2)rec[-5]_rec[-25];DT(5,1,2)rec[-4]_rec[-24];DT(6,2,2)rec[-3]_rec[-23];DT(4,2,2)rec[-2]_rec[-22];DT(7,1,2)rec[-1]_rec[-21];TICK;R_6_10_4_12_30_34_28_36_18_22_24_16;RX_5_11_0_17_29_35_23_40;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37_14_18_19_22_23_20_21_24;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38_20_18_23_21_27_24_25_22;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38_15_18_20_22_17_19_13_16;TICK;CX_5_8_9_6_14_10_11_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28_17_20_26_22_19_16_21_18;TICK;M_6_10_4_12_30_34_28_36_24_16_22_18;MX_5_11_0_17_29_35_23_40_19_20_21;MARKX(0)19;DT(1,2,3)rec[-23]_rec[-43];DT(2,1,3)rec[-22]_rec[-42];DT(1,0,3)rec[-21]_rec[-41];DT(2,3,3)rec[-20]_rec[-40];DT(5,2,3)rec[-19]_rec[-39];DT(6,1,3)rec[-18]_rec[-38];DT(5,0,3)rec[-17]_rec[-37];DT(6,3,3)rec[-16]_rec[-36];DT(4,3,3)rec[-15]_rec[-35];DT(3,0,3)rec[-14]_rec[-34];DT(4,1,3)rec[-13]_rec[-33];DT(3,2,3)rec[-12]_rec[-32];DT(1,1,3)rec[-11]_rec[-31];DT(2,2,3)rec[-10]_rec[-30];DT(0,2,3)rec[-9]_rec[-29];DT(3,1,3)rec[-8]_rec[-28];DT(5,1,3)rec[-7]_rec[-27];DT(6,2,3)rec[-6]_rec[-26];DT(4,2,3)rec[-5]_rec[-25];DT(7,1,3)rec[-4]_rec[-24];TICK;POLYGON(0,0,1,0.25)7_13_14_8;POLYGON(0,0,1,0.25)2_8_9_3;POLYGON(0,0,1,0.25)7_1;POLYGON(0,0,1,0.25)15_9;POLYGON(0,0,1,0.25)31_37_38_32;POLYGON(0,0,1,0.25)26_32_33_27;POLYGON(0,0,1,0.25)31_25;POLYGON(0,0,1,0.25)39_33;POLYGON(1,0,0,0.25)1_7_8_2;POLYGON(1,0,0,0.25)8_14_15_9;POLYGON(1,0,0,0.25)2_3;POLYGON(1,0,0,0.25)13_14;POLYGON(1,0,0,0.25)25_31_32_26;POLYGON(1,0,0,0.25)32_38_39_33;POLYGON(1,0,0,0.25)26_27;POLYGON(1,0,0,0.25)37_38;TICK;R_6_10_4_12_30_34_28_36;RX_5_11_0_17_29_35_23_40;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38;TICK;CX_5_8_9_6_14_10_11_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28;TICK;M_6_10_4_12_30_34_28_36;MX_5_11_0_17_29_35_23_40;MARKX(0)1_7_13_25_31_37;DT(1,2,4)rec[-16]_rec[-39];DT(2,1,4)rec[-15]_rec[-38];DT(1,0,4)rec[-14]_rec[-37];DT(2,3,4)rec[-13]_rec[-36];DT(5,2,4)rec[-12]_rec[-35];DT(6,1,4)rec[-11]_rec[-34];DT(5,0,4)rec[-10]_rec[-33];DT(6,3,4)rec[-9]_rec[-32];DT(1,1,4)rec[-8]_rec[-27];DT(2,2,4)rec[-7]_rec[-26];DT(0,2,4)rec[-6]_rec[-25];DT(3.5,1.5,4)rec[-5]_rec[-18]_rec[-19]_rec[-24];DT(5,1,4)rec[-4]_rec[-23];DT(6,2,4)rec[-3]_rec[-22];DT(3.5,2.5,4)rec[-2]_rec[-17]_rec[-18]_rec[-21];DT(7,1,4)rec[-1]_rec[-20];TICK;M_1_2_3_7_8_9_13_14_15_25_26_27_31_32_33_37_38_39;DT(1,0,5)rec[-15]_rec[-18]_rec[-32];DT(1,2,5)rec[-13]_rec[-14]_rec[-16]_rec[-17]_rec[-34];DT(2,1,5)rec[-11]_rec[-12]_rec[-14]_rec[-15]_rec[-33];DT(2,3,5)rec[-10]_rec[-13]_rec[-31];DT(5,0,5)rec[-6]_rec[-9]_rec[-28];DT(5,2,5)rec[-4]_rec[-5]_rec[-7]_rec[-8]_rec[-30];DT(6,1,5)rec[-2]_rec[-3]_rec[-5]_rec[-6]_rec[-29];DT(6,3,5)rec[-1]_rec[-4]_rec[-27];OI(1)rec[-16]_rec[-17]_rec[-18];OI(2)rec[-7]_rec[-8]_rec[-9]\n                            \">\n                                Open Circuit\n                            </a></td>\n                        </tr>\n                    </tbody>\n                </table>\n            </div>\n        </div>\n        <div style=\"display: inline-block\">\n            <div>\n                <button id=\"btnShowHideImportExport\">Show Import/Export</button><br>\n                <button id=\"clear\">Clear All</button><br>\n            </div>\n        </div>\n        <div style=\"display: inline-block\">\n            <div>\n                <button id=\"btnClearMarkers\">Clear All Pauli Marks</button><br>\n                <button id=\"btnClearSelectedMarkers\">Clear Selected Marks (space)</button>\n            </div>\n        </div>\n        <div style=\"display: inline-block\">\n            <div>\n                <button id=\"btnRedo\">Redo (ctrl+Y)</button><br>\n                <button id=\"btnUndo\">Undo (ctrl+Z)</button>\n            </div>\n        </div>\n        <div style=\"display: inline-block\">\n            <div>\n                <button id=\"btnNextLayer\">Next Layer (e)</button><br>\n                <button id=\"btnPrevLayer\">Prev Layer (q)</button>\n            </div>\n        </div>\n        <div style=\"display: inline-block\">\n            <div>\n                <button id=\"btnRotate45\">Rotate 45 Clockwise ↻ (t)</button><br>\n                <button id=\"btnRotate45Counter\">Rotate 45 Mathwise ↺ (shift+t)</button>\n            </div>\n        </div>\n        <div style=\"display: inline-block\">\n            <div>\n                <button id=\"btnTimelineFocus\">Set Timeline Focus (L)</button><br>\n                <button id=\"btnClearTimelineFocus\">Clear Timeline Focus</button>\n            </div>\n        </div>\n        <div style=\"display: inline-block\">\n            <div>\n                <button id=\"btnInsertLayer\">Insert Layer (ctrl+insert)</button><br>\n                <button id=\"btnDeleteLayer\">Delete Layer (ctrl+delete)</button>\n            </div>\n        </div>\n        <textarea id=\"txtDefaultCircuit\" style=\"display: none\">[[[DEFAULT_CIRCUIT_CONTENT_LITERAL]]]</textarea>\n    </div>\n    <div id=\"divImportExport\" style=\"display: none\">\n        <div>\n            <textarea id=\"txtStimCircuit\" style=\"width: 95vw; height: 300px; background-color: #FFFFB0\">\n            </textarea>\n        </div>\n        <button id=\"btnExport\" style=\"background-color: red\">↑ Export to Stim Circuit ↑</button>\n        <button id=\"btnImport\" style=\"background-color: red\">↓ Import from Stim Circuit ↓</button>\n    </div>\n    <canvas id=\"cvn\" style=\"width: calc(100vw - 32px); height: calc(100vh - 150px); border: 1px solid black; margin: 0; padding: 0;\" tabindex=\"0\">\n    </canvas>\n</body>\n</html>\n<script type=\"module\" src=\"main.js\"></script>\n"
  },
  {
    "path": "glue/crumble/draw/config.js",
    "content": "const pitch = 50;\nconst rad = 10;\nconst OFFSET_X = -pitch + Math.floor(pitch / 4) + 0.5;\nconst OFFSET_Y = -pitch + Math.floor(pitch / 4) + 0.5;\n\nexport {pitch, rad, OFFSET_X, OFFSET_Y};\n"
  },
  {
    "path": "glue/crumble/draw/draw_util.js",
    "content": "import {rad} from './config.js';\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {!Array<![!number, !number]>} coords\n */\nfunction beginPathPolygon(ctx, coords) {\n    ctx.beginPath();\n    if (coords.length === 0) {\n        return;\n    }\n    let n = coords.length;\n    if (n === 1) {\n        let [[x0, y0]] = coords;\n        ctx.arc(x0, y0, rad * 1.7, 0, 2 * Math.PI);\n    } else if (n === 2) {\n        let [[x0, y0], [x1, y1]] = coords;\n        let dx = x1 - x0;\n        let dy = y1 - y0;\n        let cx = (x1 + x0) / 2;\n        let cy = (y1 + y0) / 2;\n        let px = -dy;\n        let py = dx;\n        let pa = px*px + py*py;\n        if (pa > 50*50) {\n            let s = 50 / Math.sqrt(pa);\n            px *= s;\n            py *= s;\n        }\n        let ac1x = cx + px * 0.2 - dx * 0.2;\n        let ac1y = cy + py * 0.2 - dy * 0.2;\n        let ac2x = cx + px * 0.2 + dx * 0.2;\n        let ac2y = cy + py * 0.2 + dy * 0.2;\n        let bc1x = cx - px * 0.2 - dx * 0.2;\n        let bc1y = cy - py * 0.2 - dy * 0.2;\n        let bc2x = cx - px * 0.2 + dx * 0.2;\n        let bc2y = cy - py * 0.2 + dy * 0.2;\n        ctx.moveTo(x0, y0);\n        ctx.bezierCurveTo(ac1x, ac1y, ac2x, ac2y, x1, y1);\n        ctx.bezierCurveTo(bc2x, bc2y, bc1x, bc1y, x0, y0);\n    } else {\n        let [xn, yn] = coords[n - 1];\n        ctx.moveTo(xn, yn);\n        for (let k = 0; k < n; k++) {\n            let [xk, yk] = coords[k];\n            ctx.lineTo(xk, yk);\n        }\n    }\n}\n\nexport {beginPathPolygon}\n"
  },
  {
    "path": "glue/crumble/draw/main_draw.js",
    "content": "import {pitch, rad, OFFSET_X, OFFSET_Y} from \"./config.js\"\nimport {marker_placement} from \"../gates/gateset_markers.js\";\nimport {drawTimeline} from \"./timeline_viewer.js\";\nimport {PropagatedPauliFrames} from \"../circuit/propagated_pauli_frames.js\";\nimport {stroke_connector_to} from \"../gates/gate_draw_util.js\"\nimport {beginPathPolygon} from './draw_util.js';\n\n/**\n * @param {!number|undefined} x\n * @param {!number|undefined} y\n * @return {![undefined, undefined]|![!number, !number]}\n */\nfunction xyToPos(x, y) {\n    if (x === undefined || y === undefined) {\n        return [undefined, undefined];\n    }\n    let focusX = x / pitch;\n    let focusY = y / pitch;\n    let roundedX = Math.floor(focusX * 2 + 0.5) / 2;\n    let roundedY = Math.floor(focusY * 2 + 0.5) / 2;\n    let centerX = roundedX*pitch;\n    let centerY = roundedY*pitch;\n    if (Math.abs(centerX - x) <= rad && Math.abs(centerY - y) <= rad && roundedX % 1 === roundedY % 1) {\n        return [roundedX, roundedY];\n    }\n    return [undefined, undefined];\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {!StateSnapshot} snap\n * @param {!function(q: !int): ![!number, !number]} qubitCoordsFunc\n * @param {!PropagatedPauliFrames} propagatedMarkers\n * @param {!int} mi\n */\nfunction drawCrossMarkers(ctx, snap, qubitCoordsFunc, propagatedMarkers, mi) {\n    let crossings = propagatedMarkers.atLayer(snap.curLayer).crossings;\n    if (crossings !== undefined) {\n        for (let {q1, q2, color} of crossings) {\n            let [x1, y1] = qubitCoordsFunc(q1);\n            let [x2, y2] = qubitCoordsFunc(q2);\n            if (color === 'X') {\n                ctx.strokeStyle = 'red';\n            } else if (color === 'Y') {\n                ctx.strokeStyle = 'green';\n            } else if (color === 'Z') {\n                ctx.strokeStyle = 'blue';\n            } else {\n                ctx.strokeStyle = 'purple'\n            }\n            ctx.lineWidth = 8;\n            stroke_connector_to(ctx, x1, y1, x2, y2);\n            ctx.lineWidth = 1;\n        }\n    }\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {!StateSnapshot} snap\n * @param {!function(q: !int): ![!number, !number]} qubitCoordsFunc\n * @param {!Map<!int, !PropagatedPauliFrames>} propagatedMarkerLayers\n */\nfunction drawMarkers(ctx, snap, qubitCoordsFunc, propagatedMarkerLayers) {\n    let obsCount = new Map();\n    let detCount = new Map();\n    for (let [mi, p] of propagatedMarkerLayers.entries()) {\n        drawSingleMarker(ctx, snap, qubitCoordsFunc, p, mi, obsCount, detCount);\n    }\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {!StateSnapshot} snap\n * @param {!function(q: !int): ![!number, !number]} qubitCoordsFunc\n * @param {!PropagatedPauliFrames} propagatedMarkers\n * @param {!int} mi\n * @param {!Map} hitCount\n */\nfunction drawSingleMarker(ctx, snap, qubitCoordsFunc, propagatedMarkers, mi, hitCount) {\n    let basesQubitMap = propagatedMarkers.atLayer(snap.curLayer + 0.5).bases;\n\n    // Convert qubit indices to draw coordinates.\n    let basisCoords = [];\n    for (let [q, b] of basesQubitMap.entries()) {\n        basisCoords.push([b, qubitCoordsFunc(q)]);\n    }\n\n    // Draw a polygon for the marker set.\n    if (mi >= 0 && basisCoords.length > 0) {\n        if (basisCoords.every(e => e[0] === 'X')) {\n            ctx.fillStyle = 'red';\n        } else if (basisCoords.every(e => e[0] === 'Y')) {\n            ctx.fillStyle = 'green';\n        } else if (basisCoords.every(e => e[0] === 'Z')) {\n            ctx.fillStyle = 'blue';\n        } else {\n            ctx.fillStyle = 'black';\n        }\n        ctx.strokeStyle = ctx.fillStyle;\n        let coords = basisCoords.map(e => e[1]);\n        let cx = 0;\n        let cy = 0;\n        for (let [x, y] of coords) {\n            cx += x;\n            cy += y;\n        }\n        cx /= coords.length;\n        cy /= coords.length;\n        coords.sort((a, b) => {\n            let [ax, ay] = a;\n            let [bx, by] = b;\n            let av = Math.atan2(ay - cy, ax - cx);\n            let bv = Math.atan2(by - cy, bx - cx);\n            if (ax === cx && ay === cy) {\n                av = -100;\n            }\n            if (bx === cx && by === cy) {\n                bv = -100;\n            }\n            return av - bv;\n        })\n        beginPathPolygon(ctx, coords);\n        ctx.globalAlpha *= 0.25;\n        ctx.fill();\n        ctx.globalAlpha *= 4;\n        ctx.lineWidth = 2;\n        ctx.stroke();\n        ctx.lineWidth = 1;\n    }\n\n    // Draw individual qubit markers.\n    for (let [b, [x, y]] of basisCoords) {\n        let {dx, dy, wx, wy} = marker_placement(mi, `${x}:${y}`, hitCount);\n        if (b === 'X') {\n            ctx.fillStyle = 'red'\n        } else if (b === 'Y') {\n            ctx.fillStyle = 'green'\n        } else if (b === 'Z') {\n            ctx.fillStyle = 'blue'\n        } else {\n            throw new Error('Not a pauli: ' + b);\n        }\n        ctx.fillRect(x - dx, y - dy, wx, wy);\n    }\n\n    // Show error highlights.\n    let errorsQubitSet = propagatedMarkers.atLayer(snap.curLayer).errors;\n    for (let q of errorsQubitSet) {\n        let [x, y] = qubitCoordsFunc(q);\n        let {dx, dy, wx, wy} = marker_placement(mi, `${x}:${y}`, hitCount);\n        if (mi < 0) {\n            ctx.lineWidth = 2;\n        } else {\n            ctx.lineWidth = 8;\n        }\n        ctx.strokeStyle = 'magenta'\n        ctx.strokeRect(x - dx, y - dy, wx, wy);\n        ctx.lineWidth = 1;\n        ctx.fillStyle = 'black'\n        ctx.fillRect(x - dx, y - dy, wx, wy);\n    }\n}\n\nlet _defensive_draw_enabled = true;\n\n/**\n * @param {!boolean} val\n */\nfunction setDefensiveDrawEnabled(val) {\n    _defensive_draw_enabled = val;\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {!function} body\n */\nfunction defensiveDraw(ctx, body) {\n    ctx.save();\n    try {\n        if (_defensive_draw_enabled) {\n            body();\n        } else {\n            try {\n                body();\n            } catch (ex) {\n                console.error(ex);\n            }\n        }\n    } finally {\n        ctx.restore();\n    }\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {!StateSnapshot} snap\n */\nfunction draw(ctx, snap) {\n    let circuit = snap.circuit;\n\n    let numPropagatedLayers = 0;\n    for (let layer of circuit.layers) {\n        for (let op of layer.markers) {\n            let gate = op.gate;\n            if (gate.name === \"MARKX\" || gate.name === \"MARKY\" || gate.name === \"MARKZ\") {\n                numPropagatedLayers = Math.max(numPropagatedLayers, op.args[0] + 1);\n            }\n        }\n    }\n\n    let c2dCoordTransform = (x, y) => [x*pitch - OFFSET_X, y*pitch - OFFSET_Y];\n    let qubitDrawCoords = q => {\n        let x = circuit.qubitCoordData[2 * q];\n        let y = circuit.qubitCoordData[2 * q + 1];\n        return c2dCoordTransform(x, y);\n    };\n    let propagatedMarkerLayers = /** @type {!Map<!int, !PropagatedPauliFrames>} */ new Map();\n    for (let mi = 0; mi < numPropagatedLayers; mi++) {\n        propagatedMarkerLayers.set(mi, PropagatedPauliFrames.fromCircuit(circuit, mi));\n    }\n    let {dets: dets, obs: obs} = circuit.collectDetectorsAndObservables(false);\n    let batch_input = [];\n    for (let mi = 0; mi < dets.length; mi++) {\n        batch_input.push(dets[mi].mids);\n    }\n    for (let mi of obs.keys()) {\n        batch_input.push(obs.get(mi));\n    }\n    let batch_output = PropagatedPauliFrames.batchFromMeasurements(circuit, batch_input);\n    let batch_index = 0;\n    for (let mi = 0; mi < dets.length; mi++) {\n        propagatedMarkerLayers.set(~mi, batch_output[batch_index++]);\n    }\n    for (let mi of obs.keys()) {\n        propagatedMarkerLayers.set(~mi ^ (1 << 30), batch_output[batch_index++]);\n    }\n\n    let operatedOnQubits = new Set();\n    for (let layer of circuit.layers) {\n        for (let t of layer.id_ops.keys()) {\n            operatedOnQubits.add(t);\n        }\n    }\n    let usedQubitCoordSet = new Set();\n    let operatedOnQubitSet = new Set();\n    for (let q of circuit.allQubits()) {\n        let qx = circuit.qubitCoordData[q * 2];\n        let qy = circuit.qubitCoordData[q * 2 + 1];\n        usedQubitCoordSet.add(`${qx},${qy}`);\n        if (operatedOnQubits.has(q)) {\n            operatedOnQubitSet.add(`${qx},${qy}`);\n        }\n    }\n\n    defensiveDraw(ctx, () => {\n        ctx.fillStyle = 'white';\n        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n        let [focusX, focusY] = xyToPos(snap.curMouseX, snap.curMouseY);\n\n        // Draw the background polygons.\n        let lastPolygonLayer = snap.curLayer;\n        for (let r = 0; r <= snap.curLayer; r++) {\n            for (let op of circuit.layers[r].markers) {\n                if (op.gate.name === 'POLYGON') {\n                    lastPolygonLayer = r;\n                    break;\n                }\n            }\n        }\n        let polygonMarkers = [...circuit.layers[lastPolygonLayer].markers];\n        polygonMarkers.sort((a, b) => b.id_targets.length - a.id_targets.length);\n        for (let op of polygonMarkers) {\n            if (op.gate.name === 'POLYGON') {\n                op.id_draw(qubitDrawCoords, ctx);\n            }\n        }\n\n        // Draw the grid of qubits.\n        defensiveDraw(ctx, () => {\n            for (let qx = 0; qx < 100; qx += 0.5) {\n                let [x, _] = c2dCoordTransform(qx, 0);\n                let s = `${qx}`;\n                ctx.fillStyle = 'black';\n                ctx.fillText(s, x - ctx.measureText(s).width / 2, 15);\n            }\n            for (let qy = 0; qy < 100; qy += 0.5) {\n                let [_, y] = c2dCoordTransform(0, qy);\n                let s = `${qy}`;\n                ctx.fillStyle = 'black';\n                ctx.fillText(s, 18 - ctx.measureText(s).width, y);\n            }\n\n            ctx.strokeStyle = 'black';\n            for (let qx = 0; qx < 100; qx += 0.5) {\n                let [x, _] = c2dCoordTransform(qx, 0);\n                let s = `${qx}`;\n                ctx.fillStyle = 'black';\n                ctx.fillText(s, x - ctx.measureText(s).width / 2, 15);\n                for (let qy = qx % 1; qy < 100; qy += 1) {\n                    let [x, y] = c2dCoordTransform(qx, qy);\n                    ctx.fillStyle = 'white';\n                    let isUnused = !usedQubitCoordSet.has(`${qx},${qy}`);\n                    let isVeryUnused = !operatedOnQubitSet.has(`${qx},${qy}`);\n                    if (isUnused) {\n                        ctx.globalAlpha *= 0.25;\n                    }\n                    if (isVeryUnused) {\n                        ctx.globalAlpha *= 0.25;\n                    }\n                    ctx.fillRect(x - rad, y - rad, 2*rad, 2*rad);\n                    ctx.strokeRect(x - rad, y - rad, 2*rad, 2*rad);\n                    if (isUnused) {\n                        ctx.globalAlpha *= 4;\n                    }\n                    if (isVeryUnused) {\n                        ctx.globalAlpha *= 4;\n                    }\n                }\n            }\n        });\n\n        for (let [mi, p] of propagatedMarkerLayers.entries()) {\n            drawCrossMarkers(ctx, snap, qubitDrawCoords, p, mi);\n        }\n\n        for (let op of circuit.layers[snap.curLayer].iter_gates_and_markers()) {\n            if (op.gate.name !== 'POLYGON') {\n                op.id_draw(qubitDrawCoords, ctx);\n            }\n        }\n\n        defensiveDraw(ctx, () => {\n            ctx.globalAlpha *= 0.25\n            for (let [qx, qy] of snap.timelineSet.values()) {\n                let [x, y] = c2dCoordTransform(qx, qy);\n                ctx.fillStyle = 'yellow';\n                ctx.fillRect(x - rad * 1.25, y - rad * 1.25, 2.5*rad, 2.5*rad);\n            }\n        });\n\n        defensiveDraw(ctx, () => {\n            ctx.globalAlpha *= 0.5\n            for (let [qx, qy] of snap.focusedSet.values()) {\n                let [x, y] = c2dCoordTransform(qx, qy);\n                ctx.fillStyle = 'blue';\n                ctx.fillRect(x - rad * 1.25, y - rad * 1.25, 2.5*rad, 2.5*rad);\n            }\n        });\n\n        drawMarkers(ctx, snap, qubitDrawCoords, propagatedMarkerLayers);\n\n        if (focusX !== undefined) {\n            ctx.save();\n            ctx.globalAlpha *= 0.5;\n            let [x, y] = c2dCoordTransform(focusX, focusY);\n            ctx.fillStyle = 'red';\n            ctx.fillRect(x - rad, y - rad, 2*rad, 2*rad);\n            ctx.restore();\n        }\n\n        defensiveDraw(ctx, () => {\n            ctx.globalAlpha *= 0.25;\n            ctx.fillStyle = 'blue';\n            if (snap.mouseDownX !== undefined && snap.curMouseX !== undefined) {\n                let x1 = Math.min(snap.curMouseX, snap.mouseDownX);\n                let x2 = Math.max(snap.curMouseX, snap.mouseDownX);\n                let y1 = Math.min(snap.curMouseY, snap.mouseDownY);\n                let y2 = Math.max(snap.curMouseY, snap.mouseDownY);\n                x1 -= 1;\n                x2 += 1;\n                y1 -= 1;\n                y2 += 1;\n                x1 -= OFFSET_X;\n                x2 -= OFFSET_X;\n                y1 -= OFFSET_Y;\n                y2 -= OFFSET_Y;\n                ctx.fillRect(x1, y1, x2 - x1, y2 - y1);\n            }\n            for (let [qx, qy] of snap.boxHighlightPreview) {\n                let [x, y] = c2dCoordTransform(qx, qy);\n                ctx.fillRect(x - rad, y - rad, rad*2, rad*2);\n            }\n        });\n    });\n\n    drawTimeline(ctx, snap, propagatedMarkerLayers, qubitDrawCoords, circuit.layers.length);\n\n    // Draw scrubber.\n    ctx.save();\n    try {\n        ctx.strokeStyle = 'black';\n        ctx.translate(Math.floor(ctx.canvas.width / 2), 0);\n        for (let k = 0; k < circuit.layers.length; k++) {\n            let hasPolygons = false;\n            let hasXMarker = false;\n            let hasYMarker = false;\n            let hasZMarker = false;\n            let hasResetOperations = circuit.layers[k].hasResetOperations();\n            let hasMeasurements = circuit.layers[k].hasMeasurementOperations();\n            let hasTwoQubitGate = false;\n            let hasMultiQubitGate = false;\n            let hasSingleQubitClifford = circuit.layers[k].hasSingleQubitCliffords();\n            for (let op of circuit.layers[k].markers) {\n                hasPolygons |= op.gate.name === \"POLYGON\";\n                hasXMarker |= op.gate.name === \"MARKX\";\n                hasYMarker |= op.gate.name === \"MARKY\";\n                hasZMarker |= op.gate.name === \"MARKZ\";\n            }\n            for (let op of circuit.layers[k].id_ops.values()) {\n                hasTwoQubitGate |= op.id_targets.length === 2;\n                hasMultiQubitGate |= op.id_targets.length > 2;\n            }\n            ctx.fillStyle = 'white';\n            ctx.fillRect(k * 8, 0, 8, 20);\n            if (hasSingleQubitClifford) {\n                ctx.fillStyle = '#FF0';\n                ctx.fillRect(k * 8, 0, 8, 20);\n            } else if (hasPolygons) {\n                ctx.fillStyle = '#FBB';\n                ctx.fillRect(k * 8, 0, 8, 7);\n                ctx.fillStyle = '#BFB';\n                ctx.fillRect(k * 8, 7, 8, 7);\n                ctx.fillStyle = '#BBF';\n                ctx.fillRect(k * 8, 14, 8, 6);\n            }\n            if (hasMeasurements) {\n                ctx.fillStyle = '#DDD';\n                ctx.fillRect(k * 8, 0, 8, 20);\n            } else if (hasResetOperations) {\n                ctx.fillStyle = '#DDD';\n                ctx.fillRect(k * 8, 0, 4, 20);\n            }\n            if (hasXMarker) {\n                ctx.fillStyle = 'red';\n                ctx.fillRect(k * 8 + 3, 14, 3, 3);\n            }\n            if (hasYMarker) {\n                ctx.fillStyle = 'green';\n                ctx.fillRect(k * 8 + 3, 9, 3, 3);\n            }\n            if (hasZMarker) {\n                ctx.fillStyle = 'blue';\n                ctx.fillRect(k * 8 + 3, 3, 3, 3);\n            }\n            if (hasMultiQubitGate) {\n                ctx.strokeStyle = 'black';\n                ctx.beginPath();\n                let x = k * 8 + 0.5;\n                for (let dx of [3, 5]) {\n                    ctx.moveTo(x + dx, 6);\n                    ctx.lineTo(x + dx, 15);\n                }\n                ctx.stroke();\n            }\n            if (hasTwoQubitGate) {\n                ctx.strokeStyle = 'black';\n                ctx.beginPath();\n                ctx.moveTo(k * 8 + 0.5 + 4, 6);\n                ctx.lineTo(k * 8 + 0.5 + 4, 15);\n                ctx.stroke();\n            }\n        }\n        ctx.fillStyle = 'black';\n        ctx.beginPath();\n        ctx.moveTo(snap.curLayer * 8 + 0.5 + 4, 16);\n        ctx.lineTo(snap.curLayer * 8 + 0.5 - 2, 28);\n        ctx.lineTo(snap.curLayer * 8 + 0.5 + 10, 28);\n        ctx.closePath();\n        ctx.fill();\n\n        for (let k = 0; k < circuit.layers.length; k++) {\n            let has_errors = ![...propagatedMarkerLayers.values()].every(p => p.atLayer(k).errors.size === 0);\n            let hasOps = circuit.layers[k].id_ops.size > 0 || circuit.layers[k].markers.length > 0;\n            if (has_errors) {\n                ctx.strokeStyle = 'magenta';\n                ctx.lineWidth = 4;\n                ctx.strokeRect(k*8 + 0.5 - 1, 0.5 - 1, 7 + 2, 20 + 2);\n                ctx.lineWidth = 1;\n            } else {\n                ctx.strokeStyle = '#000';\n                ctx.strokeRect(k*8 + 0.5, 0.5, 8, 20);\n            }\n        }\n    } finally {\n        ctx.restore();\n    }\n}\n\nexport {xyToPos, draw, setDefensiveDrawEnabled, OFFSET_X, OFFSET_Y}\n"
  },
  {
    "path": "glue/crumble/draw/main_draw.test.js",
    "content": "import {draw, setDefensiveDrawEnabled} from './main_draw.js';\nimport {StateSnapshot} from './state_snapshot.js';\nimport {test, assertThat, skipRestOfTestIfHeadless} from \"../test/test_util.js\";\nimport {Circuit} from \"../circuit/circuit.js\";\n\ntest(\"main_draw.drawRuns\", () => {\n    skipRestOfTestIfHeadless();\n    setDefensiveDrawEnabled(false);\n\n    let ctx = document.createElement('canvas').getContext('2d');\n    let circuit = Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(0, 1) 2\n        QUBIT_COORDS(1, 1) 3\n        MARKX(0) 1\n        CX 1 2\n        TICK\n        H 0\n        CY 2 3\n        TICK\n        S 0 1 2 3\n    `);\n    let curLayer = 1;\n    let focusedSet = new Set(['0,0', '1,0', '2,0']);\n    let timelineSet = new Set(['0,1', '1,0']);\n    let curMouseX = 0;\n    let curMouseY = 0;\n    let mouseDownX = 0;\n    let mouseDownY = 0;\n    let boxHighlightPreview = [[1, 1], [1, 2]];\n    let snap = new StateSnapshot(\n        circuit,\n        curLayer,\n        focusedSet,\n        timelineSet,\n        curMouseX,\n        curMouseY,\n        mouseDownX,\n        mouseDownY,\n        boxHighlightPreview,\n    );\n    draw(ctx, snap);\n    assertThat(() => draw(ctx, snap)).runsWithoutThrowingAnException();\n});\n"
  },
  {
    "path": "glue/crumble/draw/state_snapshot.js",
    "content": "import {Circuit} from \"../circuit/circuit.js\";\nimport {Layer} from \"../circuit/layer.js\";\n\n/**\n * A copy of the editor state which can be used for tasks such as drawing previews of changes.\n *\n * Technically not immutable, but should be treated as immutable. Should never be mutated.\n */\nclass StateSnapshot {\n    /**\n     * @param {!Circuit} circuit\n     * @param {!int} curLayer\n     * @param {!Map<!string, ![!number, !number]>} focusedSet\n     * @param {!Map<!string, ![!number, !number]>} timelineSet\n     * @param {!number} curMouseX\n     * @param {!number} curMouseY\n     * @param {!number} mouseDownX\n     * @param {!number} mouseDownY\n     * @param {!Array<![!number, !number]>} boxHighlightPreview\n     */\n    constructor(circuit, curLayer, focusedSet, timelineSet, curMouseX, curMouseY, mouseDownX, mouseDownY, boxHighlightPreview) {\n        this.circuit = circuit.copy();\n        this.curLayer = curLayer;\n        this.focusedSet = new Map(focusedSet.entries());\n        this.timelineSet = new Map(timelineSet.entries());\n        this.curMouseX = curMouseX;\n        this.curMouseY = curMouseY;\n        this.mouseDownX = mouseDownX;\n        this.mouseDownY = mouseDownY;\n        this.boxHighlightPreview = [...boxHighlightPreview];\n\n        while (this.circuit.layers.length <= this.curLayer) {\n            this.circuit.layers.push(new Layer());\n        }\n    }\n\n    /**\n     * @returns {!Set<!int>}\n     */\n    id_usedQubits() {\n        return this.circuit.allQubits();\n    }\n\n    /**\n     * @returns {!Array<!int>}\n     */\n    timelineQubits() {\n        let used = this.id_usedQubits();\n        let qubits = [];\n        if (this.timelineSet.size > 0) {\n            let c2q = this.circuit.coordToQubitMap();\n            for (let key of this.timelineSet.keys()) {\n                let q = c2q.get(key);\n                if (q !== undefined) {\n                    qubits.push(q);\n                }\n            }\n        } else {\n            qubits.push(...used.values());\n        }\n        return qubits.filter(q => used.has(q));\n    }\n}\n\nexport {StateSnapshot}\n"
  },
  {
    "path": "glue/crumble/draw/timeline_viewer.js",
    "content": "import {OFFSET_Y, rad} from \"./config.js\";\nimport {stroke_connector_to} from \"../gates/gate_draw_util.js\"\nimport {marker_placement} from '../gates/gateset_markers.js';\n\nlet TIMELINE_PITCH = 32;\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {!StateSnapshot} ds\n * @param {!function(!int, !number): ![!number, !number]} qubitTimeCoordFunc\n * @param {!PropagatedPauliFrames} propagatedMarkers\n * @param {!int} mi\n * @param {!int} min_t\n * @param {!int} max_t\n * @param {!number} x_pitch\n * @param {!Map} hitCounts\n */\nfunction drawTimelineMarkers(ctx, ds, qubitTimeCoordFunc, propagatedMarkers, mi, min_t, max_t, x_pitch, hitCounts) {\n    for (let t = min_t - 1; t <= max_t; t++) {\n        if (!hitCounts.has(t)) {\n            hitCounts.set(t, new Map());\n        }\n        let hitCount = hitCounts.get(t);\n        let p1 = propagatedMarkers.atLayer(t + 0.5);\n        let p0 = propagatedMarkers.atLayer(t);\n        for (let [q, b] of p1.bases.entries()) {\n            let {dx, dy, wx, wy} = marker_placement(mi, q, hitCount);\n            if (mi >= 0 && mi < 4) {\n                dx = 0;\n                wx = x_pitch;\n                wy = 5;\n                if (mi === 0) {\n                    dy = 10;\n                } else if (mi === 1) {\n                    dy = 5;\n                } else if (mi === 2) {\n                    dy = 0;\n                } else if (mi === 3) {\n                    dy = -5;\n                }\n            } else {\n                dx -= x_pitch / 2;\n            }\n            let [x, y] = qubitTimeCoordFunc(q, t);\n            if (x === undefined || y === undefined) {\n                continue;\n            }\n            if (b === 'X') {\n                ctx.fillStyle = 'red'\n            } else if (b === 'Y') {\n                ctx.fillStyle = 'green'\n            } else if (b === 'Z') {\n                ctx.fillStyle = 'blue'\n            } else {\n                throw new Error('Not a pauli: ' + b);\n            }\n            ctx.fillRect(x - dx, y - dy, wx, wy);\n        }\n        for (let q of p0.errors) {\n            let {dx, dy, wx, wy} = marker_placement(mi, q, hitCount);\n            dx -= x_pitch / 2;\n\n            let [x, y] = qubitTimeCoordFunc(q, t - 0.5);\n            if (x === undefined || y === undefined) {\n                continue;\n            }\n            ctx.strokeStyle = 'magenta';\n            ctx.lineWidth = 8;\n            ctx.strokeRect(x - dx, y - dy, wx, wy);\n            ctx.lineWidth = 1;\n            ctx.fillStyle = 'black';\n            ctx.fillRect(x - dx, y - dy, wx, wy);\n        }\n        for (let {q1, q2, color} of p0.crossings) {\n            let [x1, y1] = qubitTimeCoordFunc(q1, t);\n            let [x2, y2] = qubitTimeCoordFunc(q2, t);\n            if (color === 'X') {\n                ctx.strokeStyle = 'red';\n            } else if (color === 'Y') {\n                ctx.strokeStyle = 'green';\n            } else if (color === 'Z') {\n                ctx.strokeStyle = 'blue';\n            } else {\n                ctx.strokeStyle = 'purple'\n            }\n            ctx.lineWidth = 8;\n            stroke_connector_to(ctx, x1, y1, x2, y2);\n            ctx.lineWidth = 1;\n        }\n    }\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {!StateSnapshot} snap\n * @param {!Map<!int, !PropagatedPauliFrames>} propagatedMarkerLayers\n * @param {!function(!int): ![!number, !number]} timesliceQubitCoordsFunc\n * @param {!int} numLayers\n */\nfunction drawTimeline(ctx, snap, propagatedMarkerLayers, timesliceQubitCoordsFunc, numLayers) {\n    let w = Math.floor(ctx.canvas.width / 2);\n\n    let qubits = snap.timelineQubits();\n    qubits.sort((a, b) => {\n        let [x1, y1] = timesliceQubitCoordsFunc(a);\n        let [x2, y2] = timesliceQubitCoordsFunc(b);\n        if (y1 !== y2) {\n            return y1 - y2;\n        }\n        return x1 - x2;\n    });\n\n    let base_y2xy = new Map();\n    let prev_y = undefined;\n    let cur_x = 0;\n    let cur_y = 0;\n    let max_run = 0;\n    let cur_run = 0;\n    for (let q of qubits) {\n        let [x, y] = timesliceQubitCoordsFunc(q);\n        cur_y += TIMELINE_PITCH;\n        if (prev_y !== y) {\n            prev_y = y;\n            cur_x = w * 1.5;\n            max_run = Math.max(max_run, cur_run);\n            cur_run = 0;\n            cur_y += TIMELINE_PITCH * 0.25;\n        } else {\n            cur_x += rad * 0.25;\n            cur_run++;\n        }\n        base_y2xy.set(`${x},${y}`, [Math.round(cur_x) + 0.5, Math.round(cur_y) + 0.5]);\n    }\n\n    let x_pitch = TIMELINE_PITCH + Math.ceil(rad*max_run*0.25);\n    let num_cols_half = Math.floor(ctx.canvas.width / 4 / x_pitch);\n    let min_t_free = snap.curLayer - num_cols_half + 1;\n    let min_t_clamp = Math.max(0, Math.min(min_t_free, numLayers - num_cols_half*2 + 1));\n    let max_t = Math.min(min_t_clamp + num_cols_half*2 + 2, numLayers);\n    let t2t = t => {\n        let dt = t - snap.curLayer;\n        dt -= min_t_clamp - min_t_free;\n        return dt*x_pitch;\n    }\n    let coordTransform_t = ([x, y, t]) => {\n        let key = `${x},${y}`;\n        if (!base_y2xy.has(key)) {\n            return [undefined, undefined];\n        }\n        let [xb, yb] = base_y2xy.get(key);\n        return [xb + t2t(t), yb];\n    };\n    let qubitTimeCoords = (q, t) => {\n        let [x, y] = timesliceQubitCoordsFunc(q);\n        return coordTransform_t([x, y, t]);\n    }\n\n    ctx.save();\n    try {\n        ctx.clearRect(w, 0, w, ctx.canvas.height);\n\n        // Draw colored indicators showing Pauli propagation.\n        let hitCounts = new Map();\n        for (let [mi, p] of propagatedMarkerLayers.entries()) {\n            drawTimelineMarkers(ctx, snap, qubitTimeCoords, p, mi, min_t_clamp, max_t, x_pitch, hitCounts);\n        }\n\n        // Draw highlight of current layer.\n        ctx.globalAlpha *= 0.5;\n        ctx.fillStyle = 'black';\n        {\n            let x1 = t2t(snap.curLayer) + w * 1.5 - x_pitch / 2;\n            ctx.fillRect(x1, 0, x_pitch, ctx.canvas.height);\n        }\n        ctx.globalAlpha *= 2;\n\n        ctx.strokeStyle = 'black';\n        ctx.fillStyle = 'black';\n\n        // Draw wire lines.\n        for (let q of qubits) {\n            let [x0, y0] = qubitTimeCoords(q, min_t_clamp - 1);\n            let [x1, y1] = qubitTimeCoords(q, max_t + 1);\n            ctx.beginPath();\n            ctx.moveTo(x0, y0);\n            ctx.lineTo(x1, y1);\n            ctx.stroke();\n        }\n\n        // Draw wire labels.\n        ctx.textAlign = 'right';\n        ctx.textBaseline = 'middle';\n        for (let q of qubits) {\n            let [x, y] = qubitTimeCoords(q, min_t_clamp - 1);\n            let qx = snap.circuit.qubitCoordData[q * 2];\n            let qy = snap.circuit.qubitCoordData[q * 2 + 1];\n            ctx.fillText(`${qx},${qy}:`, x, y);\n        }\n\n        // Draw layers of gates.\n        for (let time = min_t_clamp; time <= max_t; time++) {\n            let qubitsCoordsFuncForLayer = q => qubitTimeCoords(q, time);\n            let layer = snap.circuit.layers[time];\n            if (layer === undefined) {\n                continue;\n            }\n            for (let op of layer.iter_gates_and_markers()) {\n                op.id_draw(qubitsCoordsFuncForLayer, ctx);\n            }\n        }\n\n        // Draw links to timeslice viewer.\n        ctx.globalAlpha = 0.5;\n        for (let q of qubits) {\n            let [x0, y0] = qubitTimeCoords(q, min_t_clamp - 1);\n            let [x1, y1] = timesliceQubitCoordsFunc(q);\n            if (snap.curMouseX > ctx.canvas.width / 2 && snap.curMouseY >= y0 + OFFSET_Y - TIMELINE_PITCH * 0.55 && snap.curMouseY <= y0 + TIMELINE_PITCH * 0.55 + OFFSET_Y) {\n                ctx.beginPath();\n                ctx.moveTo(x0, y0);\n                ctx.lineTo(x1, y1);\n                ctx.stroke();\n                ctx.fillStyle = 'black';\n                ctx.fillRect(x1 - 20, y1 - 20, 40, 40);\n                ctx.fillRect(ctx.canvas.width / 2, y0 - TIMELINE_PITCH / 3, ctx.canvas.width / 2, TIMELINE_PITCH * 2 / 3);\n            }\n        }\n    } finally {\n        ctx.restore();\n    }\n}\n\nexport {drawTimeline}"
  },
  {
    "path": "glue/crumble/editor/editor_state.js",
    "content": "import {Circuit} from \"../circuit/circuit.js\";\nimport {Chorder} from \"../keyboard/chord.js\";\nimport {Layer, minXY} from \"../circuit/layer.js\";\nimport {Revision} from \"../base/revision.js\";\nimport {ObservableValue} from \"../base/obs.js\";\nimport {pitch, rad} from \"../draw/config.js\";\nimport {xyToPos} from \"../draw/main_draw.js\";\nimport {StateSnapshot} from \"../draw/state_snapshot.js\";\nimport {Operation} from \"../circuit/operation.js\";\nimport {GATE_MAP} from \"../gates/gateset.js\";\nimport {\n    PropagatedPauliFrameLayer,\n    PropagatedPauliFrames\n} from '../circuit/propagated_pauli_frames.js';\n\n/**\n * @param {!int} steps\n * @return {!function(x: !number, y: !number): ![!number, !number]}\n */\nfunction rotated45Transform(steps) {\n    let vx = [1, 0];\n    let vy = [0, 1];\n    let s = (x, y) => [x - y, x + y];\n    steps %= 8;\n    steps += 8;\n    steps %= 8;\n    for (let k = 0; k < steps; k++) {\n        vx = s(vx[0], vx[1]);\n        vy = s(vy[0], vy[1]);\n    }\n    return (x, y) => [vx[0]*x + vy[0]*y, vx[1]*x + vy[1]*y];\n}\n\nclass EditorState {\n    /**\n     * @param {!HTMLCanvasElement} canvas\n     */\n    constructor(canvas) {\n        this.rev = Revision.startingAt('');\n        this.canvas = canvas;\n        this.curMouseY = /** @type {undefined|!number} */ undefined;\n        this.curMouseX = /** @type {undefined|!number} */ undefined;\n        this.chorder = new Chorder();\n        this.curLayer = 0;\n        this.focusedSet = /** @type {!Map<!string, ![!number, !number]>} */  new Map();\n        this.timelineSet = /** @type {!Map<!string, ![!number, !number]>} */ new Map();\n        this.mouseDownX = /** @type {undefined|!number} */ undefined;\n        this.mouseDownY = /** @type {undefined|!number} */ undefined;\n        this.obs_val_draw_state = /** @type {!ObservableValue<StateSnapshot>} */ new ObservableValue(this.toSnapshot(undefined));\n    }\n\n    flipTwoQubitGateOrderAtFocus(preview) {\n        let newCircuit = this.copyOfCurCircuit();\n        let layer = newCircuit.layers[this.curLayer];\n        let flipped_op_first_targets = new Set();\n        let pairs = [\n            ['CX', 'reverse'],\n            ['CY', 'reverse'],\n            ['XCY', 'reverse'],\n            ['CXSWAP', 'reverse'],\n            ['XCZ', 'reverse'],\n            ['XCY', 'reverse'],\n            ['YCX', 'reverse'],\n            ['SWAPCX', 'reverse'],\n            ['RX', 'MX'],\n            ['R', 'M'],\n            ['RY', 'MY'],\n        ];\n        let rev = new Map();\n        for (let p of pairs) {\n            rev.set(p[0], p[1]);\n            rev.set(p[1], p[0]);\n        }\n        for (let q of this.focusedSet.keys()) {\n            let op = layer.id_ops.get(newCircuit.coordToQubitMap().get(q));\n            if (op !== undefined && rev.has(op.gate.name)) {\n                flipped_op_first_targets.add(op.id_targets[0]);\n            }\n        }\n        for (let q of flipped_op_first_targets) {\n            let op = layer.id_ops.get(q);\n            let other = rev.get(op.gate.name);\n            if (other === 'reverse') {\n                layer.id_ops.get(q).id_targets.reverse();\n            } else {\n                op.gate = GATE_MAP.get(other);\n            }\n        }\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    reverseLayerOrderFromFocusToEmptyLayer(preview) {\n        let newCircuit = this.copyOfCurCircuit();\n        let end = this.curLayer;\n        while (end < newCircuit.layers.length && !newCircuit.layers[end].empty()) {\n            end += 1;\n        }\n        let layers = [];\n        for (let k = this.curLayer; k < end; k++) {\n            layers.push(newCircuit.layers[k]);\n        }\n        layers.reverse();\n        for (let k = this.curLayer; k < end; k++) {\n            newCircuit.layers[k] = layers[k - this.curLayer];\n        }\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    /**\n     * @return {!Circuit}\n     */\n    copyOfCurCircuit() {\n        let result = Circuit.fromStimCircuit(this.rev.peekActiveCommit());\n        while (result.layers.length <= this.curLayer) {\n            result.layers.push(new Layer());\n        }\n        return result;\n    }\n\n    clearFocus() {\n        this.focusedSet.clear();\n        this.force_redraw();\n    }\n\n    /**\n     * @param {!boolean} preview\n     */\n    deleteAtFocus(preview) {\n        let newCircuit = this.copyOfCurCircuit();\n        let c2q = newCircuit.coordToQubitMap();\n        for (let key of this.focusedSet.keys()) {\n            let q = c2q.get(key);\n            if (q !== undefined) {\n                newCircuit.layers[this.curLayer].id_pop_at(q);\n            }\n        }\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    /**\n     * @param {!boolean} preview\n     */\n    deleteCurLayer(preview) {\n        let c = this.copyOfCurCircuit();\n        c.layers.splice(this.curLayer, 1);\n        this.commit_or_preview(c, preview);\n    }\n\n    /**\n     * @param {!boolean} preview\n     */\n    insertLayer(preview) {\n        let c = this.copyOfCurCircuit();\n        c.layers.splice(this.curLayer, 0, new Layer());\n        this.commit_or_preview(c, preview);\n    }\n\n    undo() {\n        this.rev.undo();\n    }\n\n    redo() {\n        this.rev.redo();\n    }\n\n    /**\n     * @param {!Circuit} newCircuit\n     * @param {!boolean} preview\n     */\n    commit_or_preview(newCircuit, preview) {\n        if (preview) {\n            this.preview(newCircuit);\n        } else {\n            this.commit(newCircuit);\n        }\n    }\n\n    /**\n     * @param {!Circuit} newCircuit\n     */\n    commit(newCircuit) {\n        while (newCircuit.layers.length > 0 && newCircuit.layers[newCircuit.layers.length - 1].isEmpty()) {\n            newCircuit.layers.pop();\n        }\n        this.rev.commit(newCircuit.toStimCircuit());\n    }\n\n    /**\n     * @param {!Circuit} newCircuit\n     */\n    preview(newCircuit) {\n        this.rev.startedWorkingOnCommit(newCircuit.toStimCircuit());\n        this.obs_val_draw_state.set(this.toSnapshot(newCircuit));\n    }\n\n    /**\n     * @param {undefined|!Circuit} previewCircuit\n     * @returns {!StateSnapshot}\n     */\n    toSnapshot(previewCircuit) {\n        if (previewCircuit === undefined) {\n            previewCircuit = this.copyOfCurCircuit();\n        }\n        return new StateSnapshot(\n            previewCircuit,\n            this.curLayer,\n            this.focusedSet,\n            this.timelineSet,\n            this.curMouseX,\n            this.curMouseY,\n            this.mouseDownX,\n            this.mouseDownY,\n            this.currentPositionsBoxesByMouseDrag(this.chorder.curModifiers.has(\"alt\")),\n        );\n    }\n\n    force_redraw() {\n        let previewedCircuit = this.obs_val_draw_state.get().circuit;\n        this.obs_val_draw_state.set(this.toSnapshot(previewedCircuit));\n    }\n\n    clearCircuit() {\n        this.commit(new Circuit(new Float64Array([]), []));\n    }\n\n    clearMarkers() {\n        let c = this.copyOfCurCircuit();\n        for (let layer of c.layers) {\n            layer.markers = layer.markers.filter(e => e.gate.name !== 'MARKX' && e.gate.name !== 'MARKY' && e.gate.name !== 'MARKZ');\n        }\n        this.commit(c);\n    }\n\n    /**\n     * @param {!boolean} parityLock\n     * @returns {!Array<![!int, !int]>}\n     */\n    currentPositionsBoxesByMouseDrag(parityLock) {\n        let curMouseX = this.curMouseX;\n        let curMouseY = this.curMouseY;\n        let mouseDownX = this.mouseDownX;\n        let mouseDownY = this.mouseDownY;\n        let result = [];\n        if (curMouseX !== undefined && mouseDownX !== undefined) {\n            let [sx, sy] = xyToPos(mouseDownX, mouseDownY);\n            let x1 = Math.min(curMouseX, mouseDownX);\n            let x2 = Math.max(curMouseX, mouseDownX);\n            let y1 = Math.min(curMouseY, mouseDownY);\n            let y2 = Math.max(curMouseY, mouseDownY);\n            let gap = pitch/4 - rad;\n            x1 += gap;\n            x2 -= gap;\n            y1 += gap;\n            y2 -= gap;\n            x1 = Math.floor(x1 * 2 / pitch + 0.5) / 2;\n            x2 = Math.floor(x2 * 2 / pitch + 0.5) / 2;\n            y1 = Math.floor(y1 * 2 / pitch + 0.5) / 2;\n            y2 = Math.floor(y2 * 2 / pitch + 0.5) / 2;\n            let b = 1;\n            if (x1 === x2 || y1 === y2) {\n                b = 2;\n            }\n            for (let x = x1; x <= x2; x += 0.5) {\n                for (let y = y1; y <= y2; y += 0.5) {\n                    if (x % 1 === y % 1) {\n                        if (!parityLock || (sx % b === x % b && sy % b === y % b)) {\n                            result.push([x, y]);\n                        }\n                    }\n                }\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @param {!function(!number, !number): ![!number, !number]} coordTransform\n     * @param {!boolean} preview\n     * @param {!boolean} moveFocus\n     */\n    applyCoordinateTransform(coordTransform, preview, moveFocus) {\n        let c = this.copyOfCurCircuit();\n        c = c.afterCoordTransform(coordTransform);\n        if (!preview && moveFocus) {\n            let trans = m => {\n                let new_m = new Map();\n                for (let [x, y] of m.values()) {\n                    [x, y] = coordTransform(x, y);\n                    new_m.set(`${x},${y}`, [x, y]);\n                }\n                return new_m;\n            }\n            this.timelineSet = trans(this.timelineSet);\n            this.focusedSet = trans(this.focusedSet);\n        }\n        this.commit_or_preview(c, preview);\n    }\n\n    /**\n     * @param {!int} steps\n     * @param {!boolean} preview\n     */\n    rotate45(steps, preview) {\n        let t1 = rotated45Transform(steps);\n        let t2 = this.copyOfCurCircuit().afterCoordTransform(t1).coordTransformForRectification();\n        this.applyCoordinateTransform((x, y) => {\n            [x, y] = t1(x, y);\n            return t2(x, y);\n        }, preview, true);\n    }\n\n    /**\n     * @param {!int} newLayer\n     */\n    changeCurLayerTo(newLayer) {\n        this.curLayer = Math.max(newLayer, 0);\n        this.force_redraw();\n    }\n\n    /**\n     * @param {!Array<![!number, !number]>} newFocus\n     * @param {!boolean} unionMode\n     * @param {!boolean} xorMode\n     */\n    changeFocus(newFocus, unionMode, xorMode) {\n        if (!unionMode && !xorMode) {\n            this.focusedSet.clear();\n        }\n        for (let [x, y] of newFocus) {\n            let k = `${x},${y}`;\n            if (xorMode && this.focusedSet.has(k)) {\n                this.focusedSet.delete(k);\n            } else {\n                this.focusedSet.set(k, [x, y]);\n            }\n        }\n        this.force_redraw();\n    }\n\n    /**\n     * @param {!Iterable<int>} affectedQubits\n     * @returns {!Map<!int, !string>}\n     * @private\n     */\n    _inferBases(affectedQubits) {\n        let inferredBases = new Map();\n        let layer = this.copyOfCurCircuit().layers[this.curLayer];\n        for (let q of [...affectedQubits]) {\n            let op = layer.id_ops.get(q);\n            if (op !== undefined) {\n                if (op.gate.name === 'RX' || op.gate.name === 'MX' || op.gate.name === 'MRX') {\n                    inferredBases.set(q, 'X');\n                } else if (op.gate.name === 'RY' || op.gate.name === 'MY' || op.gate.name === 'MRY') {\n                    inferredBases.set(q, 'Y');\n                } else if (op.gate.name === 'R' || op.gate.name === 'M' || op.gate.name === 'MR') {\n                    inferredBases.set(q, 'Z');\n                } else if (op.gate.name === 'MXX' || op.gate.name === 'MYY' || op.gate.name === 'MZZ') {\n                    let opBasis = op.gate.name[1];\n                    for (let q of op.id_targets) {\n                        inferredBases.set(q, opBasis);\n                    }\n                } else if (op.gate.name.startsWith('MPP:') && op.gate.tableau_map === undefined && op.id_targets.length === op.gate.name.length - 4) {\n                    // MPP special case.\n                    let bases = op.gate.name.substring(4);\n                    for (let k = 0; k < op.id_targets.length; k++) {\n                        let q = op.id_targets[k];\n                        inferredBases.set(q, bases[k]);\n                    }\n                }\n            }\n        }\n        return inferredBases;\n    }\n\n    /**\n     * @param {!boolean} preview\n     * @param {!int} markIndex\n     */\n    markFocusInferBasis(preview, markIndex) {\n        let newCircuit = this.copyOfCurCircuit().withCoordsIncluded(this.focusedSet.values());\n        let c2q = newCircuit.coordToQubitMap();\n        let affectedQubits = new Set();\n        for (let key of this.focusedSet.keys()) {\n            affectedQubits.add(c2q.get(key));\n        }\n\n        // Determine which qubits have forced basis based on their operation.\n        let forcedBases = this._inferBases(affectedQubits);\n        for (let q of forcedBases.keys()) {\n            affectedQubits.add(q);\n        }\n\n        // Pick a default basis for unforced qubits.\n        let seenBases = new Set(forcedBases.values());\n        seenBases.delete(undefined);\n        let defaultBasis;\n        if (seenBases.size === 1) {\n            defaultBasis = [...seenBases][0];\n        } else {\n            defaultBasis = 'Z';\n        }\n\n        // Mark each qubit with its inferred basis.\n        let layer = newCircuit.layers[this.curLayer];\n        for (let q of affectedQubits) {\n            let basis = forcedBases.get(q);\n            if (basis === undefined) {\n                basis = defaultBasis;\n            }\n            let gate = GATE_MAP.get(`MARK${basis}`).withDefaultArgument(markIndex);\n            layer.put(new Operation(\n                gate,\n                '',\n                new Float32Array([markIndex]),\n                new Uint32Array([q]),\n            ));\n        }\n\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    /**\n     * @param {!boolean} preview\n     */\n    unmarkFocusInferBasis(preview) {\n        let newCircuit = this.copyOfCurCircuit().withCoordsIncluded(this.focusedSet.values());\n        let c2q = newCircuit.coordToQubitMap();\n        let affectedQubits = new Set();\n        for (let key of this.focusedSet.keys()) {\n            affectedQubits.add(c2q.get(key));\n        }\n\n        let inferredBases = this._inferBases(affectedQubits);\n        for (let q of inferredBases.keys()) {\n            affectedQubits.add(q);\n        }\n\n        for (let q of affectedQubits) {\n            if (q !== undefined) {\n                newCircuit.layers[this.curLayer].id_dropMarkersAt(q);\n            }\n        }\n\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    /**\n     * @param {!boolean} preview\n     * @param {!Gate} gate\n     * @param {!Array<!number>} gate_args\n     */\n    _writeSingleQubitGateToFocus(preview, gate, gate_args) {\n        let newCircuit = this.copyOfCurCircuit().withCoordsIncluded(this.focusedSet.values());\n        let c2q = newCircuit.coordToQubitMap();\n        for (let key of this.focusedSet.keys()) {\n            newCircuit.layers[this.curLayer].put(new Operation(\n                gate,\n                '',\n                new Float32Array(gate_args),\n                new Uint32Array([c2q.get(key)]),\n            ));\n        }\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    /**\n     * @param {!boolean} preview\n     * @param {!Gate} gate\n     * @param {!Array<!number>} gate_args\n     */\n    _writeTwoQubitGateToFocus(preview, gate, gate_args) {\n        let newCircuit = this.copyOfCurCircuit();\n        let [x, y] = xyToPos(this.curMouseX, this.curMouseY);\n        let [minX, minY] = minXY(this.focusedSet.values());\n        let coords = [];\n        if (x !== undefined && minX !== undefined && !this.focusedSet.has(`${x},${y}`)) {\n            let dx = x - minX;\n            let dy = y - minY;\n\n            for (let [vx, vy] of this.focusedSet.values()) {\n                coords.push([vx, vy]);\n                coords.push([vx + dx, vy + dy]);\n            }\n        } else if (this.focusedSet.size === 2) {\n            for (let [vx, vy] of this.focusedSet.values()) {\n                coords.push([vx, vy]);\n            }\n        }\n        if (coords.length > 0) {\n            newCircuit = newCircuit.withCoordsIncluded(coords)\n            let c2q = newCircuit.coordToQubitMap();\n            for (let k = 0; k < coords.length; k += 2) {\n                let [x0, y0] = coords[k];\n                let [x1, y1] = coords[k + 1];\n                let q0 = c2q.get(`${x0},${y0}`);\n                let q1 = c2q.get(`${x1},${y1}`);\n                newCircuit.layers[this.curLayer].put(new Operation(\n                    gate,\n                    '',\n                    new Float32Array(gate_args),\n                    new Uint32Array([q0, q1]),\n                ));\n            }\n        }\n\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    /**\n     * @param {!boolean} preview\n     * @param {!Gate} gate\n     * @param {!Array<!number>} gate_args\n     */\n    _writeVariableQubitGateToFocus(preview, gate, gate_args) {\n        if (this.focusedSet.size === 0) {\n            return;\n        }\n\n        let pairs = [];\n        let cx = 0;\n        let cy = 0;\n        for (let xy of this.focusedSet.values()) {\n            pairs.push(xy);\n            cx += xy[0];\n            cy += xy[1];\n        }\n        cx /= pairs.length;\n        cy /= pairs.length;\n        pairs.sort((a, b) => {\n            let [x1, y1] = a;\n            let [x2, y2] = b;\n            return Math.atan2(y1 - cy, x1 - cx) - Math.atan2(y2 - cy, x2 - cx);\n        });\n\n        let newCircuit = this.copyOfCurCircuit().withCoordsIncluded(this.focusedSet.values());\n        let c2q = newCircuit.coordToQubitMap();\n        let qs = new Uint32Array(this.focusedSet.size);\n        for (let k = 0; k < pairs.length; k++) {\n            let [x, y] = pairs[k];\n            qs[k] = c2q.get(`${x},${y}`);\n        }\n\n        newCircuit.layers[this.curLayer].put(new Operation(gate, '', new Float32Array(gate_args), qs));\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    /**\n     * @param {!boolean} preview\n     * @param {!Gate} gate\n     * @param {undefined|!Array<!number>=} gate_args\n     */\n    writeGateToFocus(preview, gate, gate_args=undefined) {\n        if (gate_args === undefined) {\n            if (gate.defaultArgument === undefined) {\n                gate_args = [];\n            } else {\n                gate_args = [gate.defaultArgument];\n            }\n        }\n        if (gate.num_qubits === 1) {\n            this._writeSingleQubitGateToFocus(preview, gate, gate_args);\n        } else if (gate.num_qubits === 2) {\n            this._writeTwoQubitGateToFocus(preview, gate, gate_args);\n        } else {\n            this._writeVariableQubitGateToFocus(preview, gate, gate_args);\n        }\n    }\n\n    writeMarkerToObservable(preview, marker_index) {\n        this._writeMarkerToDetOrObs(preview, marker_index, false);\n    }\n\n    writeMarkerToDetector(preview, marker_index) {\n        this._writeMarkerToDetOrObs(preview, marker_index, true);\n    }\n\n    _writeMarkerToDetOrObs(preview, marker_index, isDet) {\n        let newCircuit = this.copyOfCurCircuit();\n        let argIndex = isDet ? newCircuit.collectDetectorsAndObservables(false).dets.length : marker_index;\n        let prop = PropagatedPauliFrames.fromCircuit(newCircuit, marker_index);\n\n        for (let k = 0; k < newCircuit.layers.length; k++) {\n            let before = k === 0 ? new PropagatedPauliFrameLayer(new Map(), new Set(), []) : prop.atLayer(k - 0.5);\n            let after = prop.atLayer(k + 0.5);\n            let layer = newCircuit.layers[k];\n            for (let q of new Set([...before.bases.keys(), ...after.bases.keys()])) {\n                let b1 = before.bases.get(q);\n                let b2 = after.bases.get(q);\n                let op = layer.id_ops.get(q);\n                let name = op !== undefined ? op.gate.name : undefined;\n                let transition = undefined;\n                if (name === 'MR' || name === 'MRX' || name === 'MRY') {\n                    transition = b1;\n                } else if (op !== undefined && op.countMeasurements() > 0) {\n                    if (b1 === undefined) {\n                        transition = b2;\n                    } else if (b2 === undefined) {\n                        transition = b1;\n                    } else if (b1 !== b2) {\n                        let s = new Set(['X', 'Y', 'Z']);\n                        s.delete(b1);\n                        s.delete(b2);\n                        transition = [...s][0];\n                    }\n                }\n                if (transition !== undefined) {\n                    layer.markers.push(new Operation(\n                        GATE_MAP.get(isDet ? 'DETECTOR' : 'OBSERVABLE_INCLUDE'),\n                        '',\n                        new Float32Array([argIndex]),\n                        op.id_targets,\n                    ));\n                }\n            }\n            layer.markers = layer.markers.filter(op => !op.gate.name.startsWith('MARK') || op.args[0] !== marker_index);\n        }\n\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    addDissipativeOverlapToMarkers(preview, marker_index) {\n        let newCircuit = this.copyOfCurCircuit();\n        let prop = PropagatedPauliFrames.fromCircuit(newCircuit, marker_index);\n\n        let k = this.curLayer;\n        let before = k === 0 ? new PropagatedPauliFrameLayer(new Map(), new Set(), []) : prop.atLayer(k - 0.5);\n        let after = prop.atLayer(k + 0.5);\n        let layer = newCircuit.layers[k];\n        let processedQubits = new Set();\n        for (let q of new Set([...before.bases.keys(), ...after.bases.keys()])) {\n            if (processedQubits.has(q)) {\n                continue;\n            }\n            let b1 = before.bases.get(q);\n            let b2 = after.bases.get(q);\n            let op = layer.id_ops.get(q);\n            if (op === undefined) {\n                continue;\n            }\n            let name = op.gate.name;\n            let basis = undefined;\n            if (name === 'R' || name === 'M' || name === 'MR') {\n                basis = 'Z';\n            } else if (name === 'RX' || name === 'MX' || name === 'MRX') {\n                basis = 'X';\n            } else if (name === 'RY' || name === 'MY' || name === 'MRY') {\n                basis = 'Y';\n            } else if (name === 'MXX' || name === 'MYY' || name === 'MZZ') {\n                basis = name[1];\n                let score = 0;\n                for (let q2 of op.id_targets) {\n                    if (processedQubits.has(q2)) {\n                        score = -1;\n                        break;\n                    }\n                    score += before.bases.get(q2) === basis;\n                }\n                if (score === 2) {\n                    for (let q2 of op.id_targets) {\n                        processedQubits.add(q2);\n                        layer.markers.push(new Operation(\n                            GATE_MAP.get(`MARK${basis}`),\n                            '',\n                            new Float32Array([marker_index]),\n                            new Uint32Array([q2]),\n                        ));\n                    }\n                }\n                continue;\n            } else if (name.startsWith('MPP:')) {\n                let score = 0;\n                for (let k = 0; k < op.id_targets.length; k++) {\n                    let q2 = op.id_targets[k];\n                    basis = name[k + 4];\n                    if (processedQubits.has(q2)) {\n                        score = -1;\n                        break;\n                    }\n                    score += before.bases.get(q2) === basis;\n                }\n                if (score > op.id_targets.length / 2) {\n                    for (let k = 0; k < op.id_targets.length; k++) {\n                        let q2 = op.id_targets[k];\n                        basis = name[k + 4];\n                        processedQubits.add(q2);\n                        layer.markers.push(new Operation(\n                            GATE_MAP.get(`MARK${basis}`),\n                            '',\n                            new Float32Array([marker_index]),\n                            new Uint32Array([q2]),\n                        ));\n                    }\n                }\n                continue;\n            } else {\n                continue;\n            }\n            if (b1 !== undefined || b2 !== undefined) {\n                layer.markers.push(new Operation(\n                    GATE_MAP.get(`MARK${basis}`),\n                    '',\n                    new Float32Array([marker_index]),\n                    new Uint32Array([q]),\n                ));\n                processedQubits.add(q);\n            }\n        }\n\n        this.commit_or_preview(newCircuit, preview);\n    }\n\n    moveDetOrObsAtFocusIntoMarker(preview, marker_index) {\n        let circuit = this.copyOfCurCircuit();\n\n        let focusSetQids = new Set();\n        let c2q = circuit.coordToQubitMap();\n        for (let s of this.focusedSet.keys()) {\n            focusSetQids.add(c2q.get(s));\n        }\n\n        let find_overlapping_region = () => {\n            let {dets: dets, obs: obs} = circuit.collectDetectorsAndObservables(false);\n            for (let det_id = 0; det_id < dets.length; det_id++) {\n                let prop = PropagatedPauliFrames.fromMeasurements(circuit, dets[det_id].mids);\n                if (prop.atLayer(this.curLayer + 0.5).touchesQidSet(focusSetQids)) {\n                    return [prop, new Operation(GATE_MAP.get('DETECTOR'), '', new Float32Array([det_id]), new Uint32Array([]))];\n                }\n            }\n            for (let [obs_id, obs_val] of obs.entries()) {\n                let prop = PropagatedPauliFrames.fromMeasurements(circuit, obs_val);\n                if (prop.atLayer(this.curLayer + 0.5).touchesQidSet(focusSetQids)) {\n                    return [prop, new Operation(GATE_MAP.get('OBSERVABLE_INCLUDE'), '', new Float32Array([obs_id]), new Uint32Array([]))];\n                }\n            }\n            return undefined;\n        }\n        let overlap = find_overlapping_region();\n        if (overlap === undefined) {\n            return;\n        }\n        let [prop, rep_op] = overlap;\n\n        let newCircuit = this.copyOfCurCircuit();\n        for (let k = 0; k < newCircuit.layers.length; k++) {\n            let before = k === 0 ? new PropagatedPauliFrameLayer(new Map(), new Set(), []) : prop.atLayer(k - 0.5);\n            let after = prop.atLayer(k + 0.5);\n            let layer = newCircuit.layers[k];\n            for (let q of new Set([...before.bases.keys(), ...after.bases.keys()])) {\n                let b1 = before.bases.get(q);\n                let b2 = after.bases.get(q);\n                let op = layer.id_ops.get(q);\n                let name = op !== undefined ? op.gate.name : undefined;\n                let transition = undefined;\n                if (name === 'MR' || name === 'MRX' || name === 'MRY' || name === 'R' || name === 'RX' || name === 'RY') {\n                    transition = b2;\n                } else if (op !== undefined && op.countMeasurements() > 0) {\n                    if (b1 === undefined) {\n                        transition = b2;\n                    } else if (b2 === undefined) {\n                        transition = b1;\n                    } else if (b1 !== b2) {\n                        let s = new Set(['X', 'Y', 'Z']);\n                        s.delete(b1);\n                        s.delete(b2);\n                        transition = [...s][0];\n                    }\n                }\n                if (transition !== undefined) {\n                    layer.markers.push(new Operation(\n                        GATE_MAP.get(`MARK${transition}`),\n                        '',\n                        new Float32Array([marker_index]),\n                        new Uint32Array([q]),\n                    ))\n                }\n            }\n            layer.markers = layer.markers.filter(op => op.gate.name !== rep_op.gate.name || op.args[0] !== rep_op.args[0]);\n        }\n        this.commit_or_preview(newCircuit, preview);\n    }\n}\n\nexport {EditorState, StateSnapshot}\n"
  },
  {
    "path": "glue/crumble/editor/editor_state.test.js",
    "content": "import {test, assertThat} from \"../test/test_util.js\";\nimport {EditorState} from \"./editor_state.js\";\nimport {GATE_MAP} from \"../gates/gateset.js\";\nimport {Circuit} from \"../circuit/circuit.js\";\nimport {pitch} from \"../draw/config.js\";\nimport {Operation} from '../circuit/operation.js';\n\ntest(\"editor_state.changeFocus\", () => {\n    let state = new EditorState(undefined);\n    assertThat(state.focusedSet).isEqualTo(new Map());\n\n    state.changeFocus([[0, 0], [0, 1]], false, false);\n    assertThat(state.focusedSet).isEqualTo(new Map([\n        ['0,0', [0, 0]],\n        ['0,1', [0, 1]],\n    ]));\n\n    state.changeFocus([[0, 0], [2, 1]], false, false);\n    assertThat(state.focusedSet).isEqualTo(new Map([\n        ['0,0', [0, 0]],\n        ['2,1', [2, 1]],\n    ]));\n\n    state.changeFocus([[0, 0], [1, 0]], false, true);\n    assertThat(state.focusedSet).isEqualTo(new Map([\n        ['2,1', [2, 1]],\n        ['1,0', [1, 0]],\n    ]));\n\n    state.changeFocus([[0, 0], [1, 0]], true, false);\n    assertThat(state.focusedSet).isEqualTo(new Map([\n        ['0,0', [0, 0]],\n        ['2,1', [2, 1]],\n        ['1,0', [1, 0]],\n    ]));\n});\n\ntest(\"editor_state.markFocusInferBasis\", () => {\n    let state = new EditorState(undefined);\n    state.commit(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        QUBIT_COORDS(0, 2) 2\n        QUBIT_COORDS(1, 0) 3\n        QUBIT_COORDS(1, 1) 4\n        QUBIT_COORDS(2, 2) 5\n        H 0 1\n        RX 2\n        RY 3\n        RZ 4\n        RX 5\n    `));\n\n    state.changeFocus([[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]], false, false);\n    state.markFocusInferBasis(false, 1);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        QUBIT_COORDS(1, 1) 2\n        QUBIT_COORDS(0, 2) 3\n        QUBIT_COORDS(2, 2) 4\n        QUBIT_COORDS(1, 0) 5\n        QUBIT_COORDS(1, 2) 6\n        H 0 1\n        R 2\n        RX 3 4\n        RY 5\n        MARKX(1) 3\n        MARKY(1) 5\n        MARKZ(1) 0 1 2 6\n    `));\n\n    state.changeFocus([[0, 0], [0, 1], [0, 2], [1, 2]], false, false);\n    state.markFocusInferBasis(false, 1);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        QUBIT_COORDS(1, 1) 2\n        QUBIT_COORDS(0, 2) 3\n        QUBIT_COORDS(2, 2) 4\n        QUBIT_COORDS(1, 0) 5\n        QUBIT_COORDS(1, 2) 6\n        H 0 1\n        R 2\n        RX 3 4\n        RY 5\n        MARKX(1) 0 1 3 6\n        MARKY(1) 5\n        MARKZ(1) 2\n    `));\n});\n\ntest(\"editor_state.writeGateToFocus\", () => {\n    let state = new EditorState(undefined);\n    state.changeFocus([[0, 0], [0, 1]], false, false);\n    state.writeGateToFocus(false, GATE_MAP.get('H'), undefined);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        H 0 1\n    `));\n    state.changeFocus([[2, 0], [0, 1]], false, false);\n    state.writeGateToFocus(false, GATE_MAP.get('S'), undefined);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(2, 0) 1\n        QUBIT_COORDS(0, 1) 2\n        H 0\n        S 1 2\n    `));\n\n    state.curMouseX = 5 * pitch;\n    state.curMouseY = 6 * pitch;\n    state.writeGateToFocus(false, GATE_MAP.get('CX'), undefined);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(2, 0) 0\n        QUBIT_COORDS(7, 5) 1\n        QUBIT_COORDS(0, 1) 2\n        QUBIT_COORDS(5, 6) 3\n        QUBIT_COORDS(0, 0) 4\n        CX 0 1 2 3\n        H 4\n    `));\n\n    state.clearCircuit();\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(''));\n    state.writeGateToFocus(false, GATE_MAP.get(\"POLYGON\"), [1, 1, 0, 0.5]);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(2, 0) 0\n        QUBIT_COORDS(0, 1) 1\n        POLYGON(1,1,0,0.5) 0 1\n    `));\n});\n\ntest('editor_state.writeMarkerToDetector', () => {\n    let state = new EditorState(undefined);\n    state.commit(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        #!pragma MARKZ(0) 0\n        TICK\n        M 0\n        #!pragma MARKZ(0) 0\n    `));\n    assertThat(state.copyOfCurCircuit().layers[0].markers.length).isNotEqualTo(0);\n    state.writeMarkerToDetector(false, 0);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        TICK\n        M 0\n        DETECTOR(0, 0, 0) rec[-1]\n    `));\n});\n\ntest('editor_state.moveDetOrObsAtFocusIntoMarker_det', () => {\n    let state = new EditorState(undefined);\n    state.commit(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        TICK\n        TICK\n        TICK\n        M 0\n        DETECTOR(0, 0, 0) rec[-1]\n    `));\n    state.changeCurLayerTo(2);\n    state.changeFocus([[0, 0]], false, false);\n    state.moveDetOrObsAtFocusIntoMarker(false, 2);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        #!pragma MARKZ(2) 0\n        TICK\n        TICK\n        TICK\n        M 0\n        #!pragma MARKZ(2) 0\n    `));\n});\n\ntest('editor_state.moveDetOrObsAtFocusIntoMarker_obs', () => {\n    let state = new EditorState(undefined);\n    state.commit(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        TICK\n        TICK\n        TICK\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    `));\n    state.changeCurLayerTo(2);\n    state.changeFocus([[0, 0]], false, false);\n    state.moveDetOrObsAtFocusIntoMarker(false, 2);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        #!pragma MARKZ(2) 0\n        TICK\n        TICK\n        TICK\n        M 0\n        #!pragma MARKZ(2) 0\n    `));\n});\n\ntest('editor_state.moveDetOrObsAtFocusIntoMarker_mr', () => {\n    let state = new EditorState(undefined);\n    state.commit(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        TICK\n        TICK\n        TICK\n        MR 0\n        DETECTOR(0, 0, 0) rec[-1]\n    `));\n    state.changeCurLayerTo(2);\n    state.changeFocus([[0, 0]], false, false);\n    state.moveDetOrObsAtFocusIntoMarker(false, 2);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        #!pragma MARKZ(2) 0\n        TICK\n        TICK\n        TICK\n        MR 0\n    `));\n});\n\ntest('editor_state.writeMarkerToDetector_mr', () => {\n    let state = new EditorState(undefined);\n    state.commit(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        #!pragma MARKZ(2) 0\n        TICK\n        TICK\n        TICK\n        MR 0\n    `));\n    state.writeMarkerToDetector(false, 2);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        R 0\n        TICK\n        TICK\n        TICK\n        MR 0\n        DETECTOR(0, 0, 0) rec[-1]\n    `));\n});\n\ntest('editor_state.writeMarkerToDetector_mxx', () => {\n    let state = new EditorState(undefined);\n    state.commit(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 1) 0\n        QUBIT_COORDS(1, 2) 1\n        QUBIT_COORDS(2, 1) 2\n        QUBIT_COORDS(2, 2) 3\n        R 0 1 2 3\n        #!pragma MARKZ(0) 0 1 2 3\n        TICK\n        MXX 0 2 1 3\n        #!pragma MARKX(0) 0 2 3 1\n        TICK\n        MYY 3 2 1 0\n        #!pragma MARKY(0) 1 0 3 2\n    `));\n    state.writeMarkerToDetector(false, 0);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 1) 0\n        QUBIT_COORDS(1, 2) 1\n        QUBIT_COORDS(2, 1) 2\n        QUBIT_COORDS(2, 2) 3\n        R 0 1 2 3\n        TICK\n        MXX 0 2 1 3\n        TICK\n        MYY 3 2 1 0\n        DETECTOR(1, 2, 0) rec[-1] rec[-2] rec[-3] rec[-4]\n    `));\n});\n\ntest('editor_state.writeMarkerToObservable_mxx', () => {\n    let state = new EditorState(undefined);\n    state.commit(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 1) 0\n        QUBIT_COORDS(1, 2) 1\n        QUBIT_COORDS(2, 1) 2\n        QUBIT_COORDS(2, 2) 3\n        R 0 1 2 3\n        #!pragma MARKZ(0) 0 1 2 3\n        TICK\n        MXX 0 2 1 3\n        #!pragma MARKX(0) 0 2 3 1\n        TICK\n        MYY 3 2 1 0\n        #!pragma MARKY(0) 1 0 3 2\n    `));\n    state.writeMarkerToObservable(false, 0);\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(1, 1) 0\n        QUBIT_COORDS(1, 2) 1\n        QUBIT_COORDS(2, 1) 2\n        QUBIT_COORDS(2, 2) 3\n        R 0 1 2 3\n        TICK\n        MXX 0 2 1 3\n        TICK\n        MYY 3 2 1 0\n        OBSERVABLE_INCLUDE(0) rec[-1] rec[-2] rec[-3] rec[-4]\n    `));\n});\n\ntest('editor_state.edit_measurement_near_observables', () => {\n    let state = new EditorState(undefined);\n    state.commit(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(2, 0) 2\n        RX 1\n        TICK\n        MX 2\n        TICK\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1] rec[-2]\n    `));\n    state.changeFocus([[1, 0]], false, false);\n    state.changeCurLayerTo(1);\n    state.writeGateToFocus(false, GATE_MAP.get('M'));\n    assertThat(state.copyOfCurCircuit()).isEqualTo(Circuit.fromStimCircuit(`\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(2, 0) 2\n        RX 1\n        TICK\n        M 1\n        MX 2\n        TICK\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1] rec[-2]\n    `));\n});\n"
  },
  {
    "path": "glue/crumble/editor/sync_url_to_state.js",
    "content": "/**\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {HistoryPusher} from \"../base/history_pusher.js\"\nimport {Circuit} from \"../circuit/circuit.js\";\n\n/**\n * @param {!string} text\n * @return {!string}\n */\nfunction urlWithCircuitHash(text) {\n    text = text.\n        replaceAll('QUBIT_COORDS', 'Q').\n        replaceAll('DETECTOR', 'DT').\n        replaceAll('OBSERVABLE_INCLUDE', 'OI').\n        replaceAll(', ', ',').\n        replaceAll(') ', ')').\n        replaceAll(' ', '_').\n        replaceAll('\\n', ';');\n    if (text.indexOf('%') !== -1 || text.indexOf('&') !== -1) {\n        text = encodeURIComponent(text);\n    }\n    return \"#circuit=\" + text;\n}\n\n/**\n * @param {!Revision} revision\n */\nfunction initUrlCircuitSync(revision) {\n    // Pull initial circuit out of URL '#x=y' arguments.\n    const getHashParameters = () => {\n        let hashText = document.location.hash.substring(1);\n        let paramsMap = new Map();\n        if (hashText !== \"\") {\n            for (let keyVal of hashText.split(\"&\")) {\n                let eq = keyVal.indexOf(\"=\");\n                if (eq === -1) {\n                    continue;\n                }\n                let key = keyVal.substring(0, eq);\n                let val = decodeURIComponent(keyVal.substring(eq + 1));\n                paramsMap.set(key, val);\n            }\n        }\n        return paramsMap;\n    };\n\n    const historyPusher = new HistoryPusher();\n    const loadCircuitFromUrl = () => {\n        try {\n            // Extract the circuit parameter.\n            let params = getHashParameters();\n            if (!params.has(\"circuit\")) {\n                let txtDefault = /** @type {!HTMLTextAreaElement} */ document.getElementById('txtDefaultCircuit');\n                if (txtDefault.value.replaceAll('_', '-') === \"[[[DEFAULT-CIRCUIT-CONTENT-LITERAL]]]\") {\n                    params.set(\"circuit\", \"\");\n                } else {\n                    params.set(\"circuit\", txtDefault.value);\n                }\n            }\n\n            // Repack the circuit data, so we can tell if there are round trip changes.\n            let circuit = Circuit.fromStimCircuit(params.get(\"circuit\"));\n            let cleanedState = circuit.toStimCircuit();\n            revision.clear(cleanedState);\n\n            // If the initial state is an empty circuit without any round trip spandrels, no need to put it in history.\n            if (circuit.layers.every(e => e.isEmpty()) && params.size === 1 && cleanedState === params.get('circuit')) {\n                historyPusher.currentStateIsNotMemorable();\n            } else {\n                historyPusher.stateChange(cleanedState, urlWithCircuitHash(cleanedState));\n            }\n        } catch (ex) {\n            // TODO: HANDLE BETTER.\n            throw new Error(ex);\n        }\n    };\n\n    window.addEventListener('popstate', loadCircuitFromUrl);\n    loadCircuitFromUrl();\n\n    revision.latestActiveCommit().whenDifferent().skip(1).subscribe(jsonText => {\n        historyPusher.stateChange(jsonText, urlWithCircuitHash(jsonText));\n    });\n}\n\nexport {initUrlCircuitSync}\n"
  },
  {
    "path": "glue/crumble/gates/gate.js",
    "content": "/**\n * Gate drawing callback.\n *\n * @callback gateDrawCallback\n * @param {!Operation} op\n * @param {!function(qubit: !int): ![!number, !number]} qubitCoordsFunc\n * @param {!CanvasRenderingContext2D} ctx\n */\n\n/**\n * An operation without specified targets.\n */\nclass Gate {\n    /**\n     * @param {!string} name\n     * @param {!int|undefined} num_qubits\n     * @param {!boolean} can_fuse\n     * @param {!boolean} is_marker\n     * @param {!Map<!string, !string>|undefined} tableau_map\n     * @param {!function(!PauliFrame, !Array<!int>)} frameDo,\n     * @param {!function(!PauliFrame, !Array<!int>)} frameUndo,\n     * @param {!gateDrawCallback} drawer\n     * @param {undefined|!number=undefined} defaultArgument\n     */\n    constructor(name,\n                num_qubits,\n                can_fuse,\n                is_marker,\n                tableau_map,\n                frameDo,\n                frameUndo,\n                drawer,\n                defaultArgument = undefined) {\n        this.name = name;\n        this.num_qubits = num_qubits;\n        this.is_marker = is_marker;\n        this.can_fuse = can_fuse;\n        this.tableau_map = tableau_map;\n        this.frameDo = frameDo;\n        this.frameUndo = frameUndo;\n        this.drawer = drawer;\n        this.defaultArgument = defaultArgument;\n    }\n\n    /**\n     * @param {!number} newDefaultArgument\n     */\n    withDefaultArgument(newDefaultArgument) {\n        return new Gate(\n            this.name,\n            this.num_qubits,\n            this.can_fuse,\n            this.is_marker,\n            this.tableau_map,\n            this.frameDo,\n            this.frameUndo,\n            this.drawer,\n            newDefaultArgument);\n    }\n}\n\nexport {Gate};\n"
  },
  {
    "path": "glue/crumble/gates/gate_draw_util.js",
    "content": "import {pitch, rad} from \"../draw/config.js\"\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x\n * @param {undefined|!number} y\n */\nfunction draw_x_control(ctx, x, y) {\n    if (x === undefined || y === undefined) {\n        return;\n    }\n\n    ctx.strokeStyle = 'black';\n    ctx.fillStyle = 'white';\n    ctx.beginPath();\n    ctx.arc(x, y, rad, 0, 2 * Math.PI);\n    ctx.fill();\n    ctx.stroke();\n\n    ctx.beginPath();\n    ctx.moveTo(x, y - rad);\n    ctx.lineTo(x, y + rad);\n    ctx.stroke();\n    ctx.beginPath();\n    ctx.moveTo(x - rad, y);\n    ctx.lineTo(x + rad, y);\n    ctx.stroke();\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x\n * @param {undefined|!number} y\n */\nfunction draw_y_control(ctx, x, y) {\n    if (x === undefined || y === undefined) {\n        return;\n    }\n    ctx.strokeStyle = 'black';\n    ctx.fillStyle = '#AAA';\n    ctx.beginPath();\n    ctx.moveTo(x, y + rad);\n    ctx.lineTo(x + rad, y - rad);\n    ctx.lineTo(x - rad, y - rad);\n    ctx.lineTo(x, y + rad);\n    ctx.stroke();\n    ctx.fill();\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x\n * @param {undefined|!number} y\n */\nfunction draw_z_control(ctx, x, y) {\n    if (x === undefined || y === undefined) {\n        return;\n    }\n    ctx.fillStyle = 'black';\n    ctx.beginPath();\n    ctx.arc(x, y, rad, 0, 2 * Math.PI);\n    ctx.fill();\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x\n * @param {undefined|!number} y\n */\nfunction draw_xswap_control(ctx, x, y) {\n    if (x === undefined || y === undefined) {\n        return;\n    }\n    ctx.fillStyle = 'white';\n    ctx.strokeStyle = 'black';\n    ctx.beginPath();\n    ctx.arc(x, y, rad, 0, 2 * Math.PI);\n    ctx.fill();\n    ctx.stroke();\n\n    let r = rad * 0.4;\n    ctx.strokeStyle = 'black';\n    ctx.lineWidth = 3;\n    ctx.beginPath();\n    ctx.moveTo(x - r, y - r);\n    ctx.lineTo(x + r, y + r);\n    ctx.stroke();\n    ctx.moveTo(x - r, y + r);\n    ctx.lineTo(x + r, y - r);\n    ctx.stroke();\n    ctx.lineWidth = 1;\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x\n * @param {undefined|!number} y\n */\nfunction draw_zswap_control(ctx, x, y) {\n    if (x === undefined || y === undefined) {\n        return;\n    }\n    ctx.fillStyle = 'black';\n    ctx.strokeStyle = 'black';\n    ctx.beginPath();\n    ctx.arc(x, y, rad, 0, 2 * Math.PI);\n    ctx.fill();\n    ctx.stroke();\n\n    let r = rad * 0.4;\n    ctx.strokeStyle = 'white';\n    ctx.lineWidth = 3;\n    ctx.beginPath();\n    ctx.moveTo(x - r, y - r);\n    ctx.lineTo(x + r, y + r);\n    ctx.stroke();\n    ctx.moveTo(x - r, y + r);\n    ctx.lineTo(x + r, y - r);\n    ctx.stroke();\n    ctx.lineWidth = 1;\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x\n * @param {undefined|!number} y\n */\nfunction draw_iswap_control(ctx, x, y) {\n    if (x === undefined || y === undefined) {\n        return;\n    }\n    ctx.fillStyle = '#888';\n    ctx.strokeStyle = '#222';\n    ctx.beginPath();\n    ctx.arc(x, y, rad, 0, 2 * Math.PI);\n    ctx.fill();\n    ctx.stroke();\n\n    let r = rad * 0.4;\n    ctx.lineWidth = 3;\n    ctx.strokeStyle = 'black';\n    ctx.beginPath();\n    ctx.moveTo(x - r, y - r);\n    ctx.lineTo(x + r, y + r);\n    ctx.stroke();\n    ctx.moveTo(x - r, y + r);\n    ctx.lineTo(x + r, y - r);\n    ctx.stroke();\n    ctx.lineWidth = 1;\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x\n * @param {undefined|!number} y\n */\nfunction draw_swap_control(ctx, x, y) {\n    if (x === undefined || y === undefined) {\n        return;\n    }\n    let r = rad / 3;\n    ctx.strokeStyle = 'black';\n    ctx.beginPath();\n    ctx.moveTo(x - r, y - r);\n    ctx.lineTo(x + r, y + r);\n    ctx.stroke();\n    ctx.moveTo(x - r, y + r);\n    ctx.lineTo(x + r, y - r);\n    ctx.stroke();\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x\n * @param {undefined|!number} y\n */\nfunction stroke_degenerate_connector(ctx, x, y) {\n    if (x === undefined || y === undefined) {\n        return;\n    }\n    let r = rad * 1.1;\n    ctx.strokeRect(x - r, y - r, r * 2, r * 2);\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x1\n * @param {undefined|!number} y1\n * @param {undefined|!number} x2\n * @param {undefined|!number} y2\n */\nfunction stroke_connector_to(ctx, x1, y1, x2, y2) {\n    if (x1 === undefined || y1 === undefined || x2 === undefined || y2 === undefined) {\n        stroke_degenerate_connector(ctx, x1, y1);\n        stroke_degenerate_connector(ctx, x2, y2);\n        return;\n    }\n    if (x2 < x1 || (x2 === x1 && y2 < y1)) {\n        stroke_connector_to(ctx, x2, y2, x1, y1);\n        return;\n    }\n\n    let dx = x2 - x1;\n    let dy = y2 - y1;\n    let d = Math.sqrt(dx*dx + dy*dy);\n    let ux = dx / d * 14;\n    let uy = dy / d * 14;\n    let px = uy;\n    let py = -ux;\n\n    ctx.beginPath();\n    ctx.moveTo(x1, y1);\n    if (d < pitch * 1.1) {\n        ctx.lineTo(x2, y2);\n    } else {\n        ctx.bezierCurveTo(x1 + ux + px, y1 + uy + py, x2 - ux + px, y2 - uy + py, x2, y2);\n    }\n    ctx.stroke();\n}\n\n/**\n * @param {!CanvasRenderingContext2D} ctx\n * @param {undefined|!number} x1\n * @param {undefined|!number} y1\n * @param {undefined|!number} x2\n * @param {undefined|!number} y2\n */\nfunction draw_connector(ctx, x1, y1, x2, y2) {\n    ctx.lineWidth = 2;\n    ctx.strokeStyle = 'black';\n    stroke_connector_to(ctx, x1, y1, x2, y2);\n    ctx.lineWidth = 1;\n}\n\nexport {\n    draw_x_control,\n    draw_y_control,\n    draw_z_control,\n    draw_swap_control,\n    draw_iswap_control,\n    stroke_connector_to,\n    draw_connector,\n    draw_xswap_control,\n    draw_zswap_control,\n};\n"
  },
  {
    "path": "glue/crumble/gates/gateset.js",
    "content": "import {Gate} from \"./gate.js\"\nimport {iter_gates_controlled_paulis} from \"./gateset_controlled_paulis.js\";\nimport {iter_gates_demolition_measurements} from \"./gateset_demolition_measurements.js\";\nimport {iter_gates_hadamard_likes} from \"./gateset_hadamard_likes.js\";\nimport {iter_gates_markers} from \"./gateset_markers.js\";\nimport {iter_gates_pair_measurements} from \"./gateset_pair_measurements.js\";\nimport {iter_gates_paulis} from \"./gateset_paulis.js\";\nimport {iter_gates_quarter_turns} from \"./gateset_quarter_turns.js\";\nimport {iter_gates_resets} from \"./gateset_resets.js\";\nimport {iter_gates_solo_measurements} from \"./gateset_solo_measurements.js\";\nimport {iter_gates_sqrt_pauli_pairs} from \"./gateset_sqrt_pauli_pairs.js\";\nimport {iter_gates_swaps} from \"./gateset_swaps.js\";\nimport {iter_gates_third_turns} from \"./gateset_third_turns.js\";\n\nfunction *iter_gates() {\n    yield *iter_gates_controlled_paulis();\n    yield *iter_gates_demolition_measurements();\n    yield *iter_gates_hadamard_likes();\n    yield *iter_gates_markers();\n    yield *iter_gates_pair_measurements();\n    yield *iter_gates_paulis();\n    yield *iter_gates_quarter_turns();\n    yield *iter_gates_resets();\n    yield *iter_gates_solo_measurements();\n    yield *iter_gates_sqrt_pauli_pairs();\n    yield *iter_gates_swaps();\n    yield *iter_gates_third_turns();\n}\n\n/**\n * @returns {!Map<!string, !Gate>}\n */\nfunction make_gate_map() {\n    let result = new Map();\n    for (let gate of iter_gates()) {\n        result.set(gate.name, gate);\n    }\n    result.set('MZ', result.get('M'))\n    result.set('RZ', result.get('R'))\n    result.set('MRZ', result.get('MR'))\n    return result;\n}\n\n/**\n * @returns {!Map<!string, !{name: undefined|!string, rev_pair: undefined|!boolean, ignore: undefined|!boolean}>}\n */\nfunction make_gate_alias_map() {\n    let result = new Map();\n\n    result.set(\"CNOT\", {name: \"CX\"});\n    result.set(\"MZ\", {name: \"M\"});\n    result.set(\"MRZ\", {name: \"MR\"});\n    result.set(\"RZ\", {name: \"R\"});\n    result.set(\"H_XZ\", {name: \"H\"});\n    result.set(\"SQRT_Z\", {name: \"S\"});\n    result.set(\"SQRT_Z_DAG\", {name: \"S_DAG\"});\n    result.set(\"ZCX\", {name: \"CX\"});\n    result.set(\"ZCY\", {name: \"CY\"});\n    result.set(\"ZCZ\", {name: \"CZ\"});\n    result.set(\"SWAPCZ\", {name: \"CZSWAP\"});\n\n    // Ordered-flipped aliases.\n    result.set(\"XCZ\", {name: \"CX\", rev_pair: true});\n    result.set(\"YCX\", {name: \"XCY\", rev_pair: true});\n    result.set(\"YCZ\", {name: \"CY\", rev_pair: true});\n    result.set(\"SWAPCX\", {name: \"CXSWAP\", rev_pair: true});\n\n    // Noise.\n    result.set(\"CORRELATED_ERROR\", {ignore: true});\n    result.set(\"DEPOLARIZE1\", {ignore: true});\n    result.set(\"DEPOLARIZE2\", {ignore: true});\n    result.set(\"E\", {ignore: true});\n    result.set(\"ELSE_CORRELATED_ERROR\", {ignore: true});\n    result.set(\"PAULI_CHANNEL_1\", {ignore: true});\n    result.set(\"PAULI_CHANNEL_2\", {ignore: true});\n    result.set(\"X_ERROR\", {ignore: true});\n    result.set(\"I_ERROR\", {ignore: true});\n    result.set(\"II_ERROR\", {ignore: true});\n    result.set(\"Y_ERROR\", {ignore: true});\n    result.set(\"Z_ERROR\", {ignore: true});\n    result.set(\"HERALDED_ERASE\", {ignore: true});\n    result.set(\"HERALDED_PAULI_CHANNEL_1\", {ignore: true});\n\n    // Annotations.\n    result.set(\"MPAD\", {ignore: true});\n    result.set(\"SHIFT_COORDS\", {ignore: true});\n\n    return result;\n}\n\nconst GATE_MAP = /** @type {Map<!string, !Gate>} */ make_gate_map();\nconst GATE_ALIAS_MAP = /** @type {!Map<!string, !{name: undefined|!string, rev_pair: undefined|!boolean, ignore: undefined|!boolean}>} */ make_gate_alias_map();\n\nexport {GATE_MAP, GATE_ALIAS_MAP};\n"
  },
  {
    "path": "glue/crumble/gates/gateset.test.js",
    "content": "import {GATE_MAP, GATE_ALIAS_MAP} from \"./gateset.js\"\nimport {test, assertThat, skipRestOfTestIfHeadless} from \"../test/test_util.js\";\nimport {Operation} from '../circuit/operation.js';\nimport {KNOWN_GATE_NAMES_FROM_STIM} from '../test/generated_gate_name_list.test.js';\n\ntest(\"gateset.expected_gates\", () => {\n    let expectedGates = new Set();\n    for (let e of KNOWN_GATE_NAMES_FROM_STIM.split(\"\\n\")) {\n        if (e.length > 0) {\n            expectedGates.add(e);\n        }\n    }\n    for (let e of GATE_ALIAS_MAP.keys()) {\n        expectedGates.delete(e);\n    }\n\n    // Special cased.\n    expectedGates.delete(\"REPEAT\");\n    expectedGates.delete(\"QUBIT_COORDS\");\n    expectedGates.delete(\"SHIFT_COORDS\");\n    expectedGates.delete(\"TICK\");\n\n    // Custom crumble gates and markers.\n    expectedGates.add(\"POLYGON\");\n    expectedGates.add(\"MARKX\");\n    expectedGates.add(\"MARKY\");\n    expectedGates.add(\"MARKZ\");\n    expectedGates.add(\"MARK\");\n    expectedGates.add(\"RZ\");\n    expectedGates.add(\"MZ\");\n    expectedGates.add(\"MRZ\");\n    expectedGates.add(\"ERR\");\n\n    // Special handling.\n    expectedGates.delete(\"MPP\");\n    expectedGates.delete(\"SPP\");\n    expectedGates.delete(\"SPP_DAG\");\n\n    assertThat(new Set([...GATE_MAP.keys()])).isEqualTo(expectedGates);\n});\n\ntest(\"gateset.allDrawCallsRun\", () => {\n    skipRestOfTestIfHeadless();\n\n    let ctx = document.createElement('canvas').getContext('2d');\n    for (let gate of GATE_MAP.values()) {\n        let op = new Operation(\n            gate,\n            '',\n            new Float32Array([1e-3]),\n            new Uint32Array([5, 6]),\n        );\n        assertThat(() => {\n            gate.drawer(op, q => [2 * q, q + 1], ctx);\n        }).withInfo(gate.name).runsWithoutThrowingAnException();\n    }\n});\n"
  },
  {
    "path": "glue/crumble/gates/gateset_controlled_paulis.js",
    "content": "import {Gate} from \"./gate.js\"\nimport {\n    draw_x_control,\n    draw_y_control,\n    draw_z_control,\n    draw_connector,\n    draw_xswap_control,\n    draw_zswap_control,\n} from \"./gate_draw_util.js\"\n\nfunction *iter_gates_controlled_paulis() {\n    yield new Gate(\n        'CX',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'IX'],\n            ['IZ', 'ZZ'],\n            ['XI', 'XX'],\n            ['ZI', 'ZI'],\n        ]),\n        (frame, targets) => frame.do_cx(targets),\n        (frame, targets) => frame.do_cx(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_z_control(ctx, x1, y1);\n            draw_x_control(ctx, x2, y2);\n        },\n    )\n    yield new Gate(\n        'CY',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'ZX'],\n            ['IZ', 'ZZ'],\n            ['XI', 'XY'],\n            ['ZI', 'ZI'],\n        ]),\n        (frame, targets) => frame.do_cy(targets),\n        (frame, targets) => frame.do_cy(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_z_control(ctx, x1, y1);\n            draw_y_control(ctx, x2, y2);\n        },\n    )\n    yield new Gate(\n        'XCX',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'IX'],\n            ['IZ', 'XZ'],\n            ['XI', 'XI'],\n            ['ZI', 'ZX'],\n        ]),\n        (frame, targets) => frame.do_xcx(targets),\n        (frame, targets) => frame.do_xcx(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_x_control(ctx, x1, y1);\n            draw_x_control(ctx, x2, y2);\n        },\n    )\n    yield new Gate(\n        'XCY',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'XX'],\n            ['IZ', 'XZ'],\n            ['XI', 'XI'],\n            ['ZI', 'ZY'],\n        ]),\n        (frame, targets) => frame.do_xcy(targets),\n        (frame, targets) => frame.do_xcy(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_x_control(ctx, x1, y1);\n            draw_y_control(ctx, x2, y2);\n        },\n    )\n    yield new Gate(\n        'YCY',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'YX'],\n            ['IZ', 'YZ'],\n            ['XI', 'XY'],\n            ['ZI', 'ZY'],\n        ]),\n        (frame, targets) => frame.do_ycy(targets),\n        (frame, targets) => frame.do_ycy(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_y_control(ctx, x1, y1);\n            draw_y_control(ctx, x2, y2);\n        },\n    )\n    yield new Gate(\n        'CZ',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'ZX'],\n            ['IZ', 'IZ'],\n            ['XI', 'XZ'],\n            ['ZI', 'ZI'],\n        ]),\n        (frame, targets) => frame.do_cz(targets),\n        (frame, targets) => frame.do_cz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_z_control(ctx, x1, y1);\n            draw_z_control(ctx, x2, y2);\n        },\n    )\n}\n\nexport {iter_gates_controlled_paulis};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_demolition_measurements.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\n\nfunction *iter_gates_demolition_measurements() {\n    yield new Gate(\n        'MR',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'ERR:I'],\n            ['Y', 'ERR:I'],\n            ['Z', 'I'],\n        ]),\n        (frame, targets) => frame.do_demolition_measure('Z', targets),\n        (frame, targets) => frame.do_demolition_measure('Z', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('MR', x1, y1);\n        },\n    );\n    yield new Gate(\n        'MRY',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'ERR:I'],\n            ['Y', 'I'],\n            ['Z', 'ERR:I'],\n        ]),\n        (frame, targets) => frame.do_demolition_measure('Y', targets),\n        (frame, targets) => frame.do_demolition_measure('Y', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('MRY', x1, y1);\n        },\n    );\n    yield new Gate(\n        'MRX',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'I'],\n            ['Y', 'ERR:I'],\n            ['Z', 'ERR:I'],\n        ]),\n        (frame, targets) => frame.do_demolition_measure('X', targets),\n        (frame, targets) => frame.do_demolition_measure('X', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('MRX', x1, y1);\n        },\n    );\n}\n\nexport {iter_gates_demolition_measurements};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_hadamard_likes.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\n\nfunction *iter_gates_hadamard_likes() {\n    yield new Gate(\n        'H',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Z'],\n            ['Z', 'X'],\n        ]),\n        (frame, targets) => frame.do_exchange_xz(targets),\n        (frame, targets) => frame.do_exchange_xz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('H', x1, y1);\n        },\n    );\n    yield new Gate(\n        'H_NXZ',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Z'],\n            ['Z', 'X'],\n        ]),\n        (frame, targets) => frame.do_exchange_xz(targets),\n        (frame, targets) => frame.do_exchange_xz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('H', x1, y1 - rad / 3);\n            ctx.fillText(\"NXZ\", x1, y1 + rad / 3);\n        },\n    );\n    yield new Gate(\n        'H_XY',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Y'],\n            ['Z', 'Z'],  // -Z technically\n        ]),\n        (frame, targets) => frame.do_exchange_xy(targets),\n        (frame, targets) => frame.do_exchange_xy(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('H', x1, y1 - rad / 3);\n            ctx.fillText(\"XY\", x1, y1 + rad / 3);\n        },\n    );\n    yield new Gate(\n        'H_NXY',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Y'],\n            ['Z', 'Z'],\n        ]),\n        (frame, targets) => frame.do_exchange_xy(targets),\n        (frame, targets) => frame.do_exchange_xy(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('H', x1, y1 - rad / 3);\n            ctx.fillText(\"NXY\", x1, y1 + rad / 3);\n        },\n    );\n    yield new Gate(\n        'H_YZ',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],  // -X technically\n            ['Z', 'Y'],\n        ]),\n        (frame, targets) => frame.do_exchange_yz(targets),\n        (frame, targets) => frame.do_exchange_yz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('H', x1, y1 - rad / 3);\n            ctx.fillText(\"YZ\", x1, y1 + rad / 3);\n        },\n    );\n    yield new Gate(\n        'H_NYZ',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],  // -X technically\n            ['Z', 'Y'],\n        ]),\n        (frame, targets) => frame.do_exchange_yz(targets),\n        (frame, targets) => frame.do_exchange_yz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('H', x1, y1 - rad / 3);\n            ctx.fillText(\"NYZ\", x1, y1 + rad / 3);\n        },\n    );\n}\n\nexport {iter_gates_hadamard_likes};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_markers.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\nimport {beginPathPolygon} from '../draw/draw_util.js';\n\n/**\n * @param {!int} mi\n * @param {* | undefined} key\n * @param {!Map<!string, !int> | undefined} hitCount\n * @returns {!{wx: !number, wy: !number, dx: !number, dy: !number}}\n */\nfunction marker_placement(mi, key, hitCount) {\n    let dx, dy, wx, wy;\n    if (mi < 0 && hitCount !== undefined) {\n        // Detector.\n        let d = hitCount.get(key)\n        if (d === undefined) {\n            d = 0;\n        }\n        hitCount.set(key, d + 1);\n        dx = 9.5 - Math.round(d % 3.9 * 5);\n        dy = 9.5 - Math.round(Math.floor(d / 4) % 3.8 * 5);\n        wx = 3;\n        wy = 3;\n        if (mi < (-1 << 28)) {\n            // Observable.\n            dx += 2;\n            wx += 4;\n            dy += 2;\n            wy += 4;\n        }\n    } else if (mi === 0) {\n        dx = rad;\n        dy = rad + 5;\n        wx = rad * 2;\n        wy = 5;\n    } else if (mi === 1) {\n        dx = -rad;\n        dy = rad;\n        wx = 5;\n        wy = rad * 2;\n    } else if (mi === 2) {\n        dx = rad;\n        dy = -rad;\n        wx = rad * 2;\n        wy = 5;\n    } else if (mi === 3) {\n        dx = rad + 5;\n        dy = rad;\n        wx = 5;\n        wy = rad * 2;\n    } else {\n        dx = Math.cos(mi * 0.6) * rad * 1.7;\n        dy = Math.sin(mi * 0.6) * rad * 1.7;\n        wx = 5;\n        wy = 5;\n        dx += wx / 2;\n        dy += wy / 2;\n    }\n    return {dx, dy, wx, wy};\n}\n\n/**\n * @param {!string} color\n * @returns {!function}\n */\nfunction make_marker_drawer(color) {\n    return (op, coordFunc, ctx) => {\n        let [x1, y1] = coordFunc(op.id_targets[0]);\n        if (x1 === undefined || y1 === undefined) {\n            return;\n        }\n        let {dx, dy, wx, wy} = marker_placement(op.args[0]);\n        ctx.fillStyle = color\n        if (wx === wy) {\n            ctx.fillRect(x1 - dx - 2, y1 - dy - 2, wx + 4, wy + 4);\n        } else {\n            let x2 = x1 + (dx < 0 ? +1 : -1) * rad;\n            let y2 = y1 + (dy < 0 ? +1 : -1) * rad;\n            let x3 = x2 + (wx > rad ? +1 : 0) * rad * 2;\n            let y3 = y2 + (wy > rad ? +1 : 0) * rad * 2;\n            ctx.beginPath();\n            ctx.moveTo(x1, y1);\n            ctx.lineTo(x2, y2);\n            ctx.lineTo(x3, y3);\n            ctx.lineTo(x1, y1);\n            ctx.fill();\n        }\n    };\n}\n\nfunction *iter_gates_markers() {\n    yield new Gate(\n        'POLYGON',\n        undefined,\n        false,\n        true,\n        undefined,\n        () => {},\n        () => {},\n        (op, coordFunc, ctx) => {\n            let transformedCoords = []\n            for (let t of op.id_targets) {\n                let [x, y] = coordFunc(t);\n                x -= 0.5;\n                y -= 0.5;\n                transformedCoords.push([x, y]);\n            }\n            beginPathPolygon(ctx, transformedCoords);\n            ctx.globalAlpha *= op.args[3];\n            ctx.fillStyle = `rgb(${op.args[0]*255},${op.args[1]*255},${op.args[2]*255})`\n            ctx.fill();\n        },\n    );\n    yield new Gate(\n        'DETECTOR',\n        undefined,\n        false,\n        true,\n        undefined,\n        () => {},\n        () => {},\n        (op, coordFunc, ctx) => {\n        },\n    );\n    yield new Gate(\n        'OBSERVABLE_INCLUDE',\n        undefined,\n        false,\n        true,\n        undefined,\n        () => {},\n        () => {},\n        (op, coordFunc, ctx) => {\n        },\n    );\n    yield new Gate(\n        'MARKX',\n        1,\n        true,\n        true,\n        undefined,\n        () => {},\n        () => {},\n        make_marker_drawer('red'),\n    );\n    yield new Gate(\n        'MARKY',\n        1,\n        true,\n        true,\n        undefined,\n        () => {},\n        () => {},\n        make_marker_drawer('green'),\n    );\n    yield new Gate(\n        'MARKZ',\n        1,\n        true,\n        true,\n        undefined,\n        () => {},\n        () => {},\n        make_marker_drawer('blue'),\n    );\n    yield new Gate(\n        'MARK',\n        1,\n        false,\n        true,\n        undefined,\n        () => {},\n        () => {},\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            if (x1 === undefined || y1 === undefined) {\n                return;\n            }\n            ctx.fillStyle = 'magenta'\n            ctx.fillRect(x1 - rad, y1 - rad, rad, rad);\n        }\n    );\n}\n\nexport {iter_gates_markers, marker_placement};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_mpp.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\nimport {draw_connector} from \"./gate_draw_util.js\";\n\n/**\n * @param {!string} bases\n * @returns {!Gate}\n */\nfunction make_mpp_gate(bases) {\n    return new Gate(\n        'MPP:' + bases,\n        bases.length,\n        true,\n        false,\n        undefined,\n        (frame, targets) => frame.do_mpp(bases, targets),\n        (frame, targets) => frame.do_mpp(bases, targets),\n        (op, coordFunc, ctx) => {\n            let prev_x = undefined;\n            let prev_y = undefined;\n            for (let k = 0; k < op.id_targets.length; k++) {\n                let t = op.id_targets[k];\n                let [x, y] = coordFunc(t);\n                if (prev_x !== undefined) {\n                    draw_connector(ctx, x, y, prev_x, prev_y);\n                }\n\n                prev_x = x;\n                prev_y = y;\n            }\n\n            for (let k = 0; k < op.id_targets.length; k++) {\n                let t = op.id_targets[k];\n                let [x, y] = coordFunc(t);\n                ctx.fillStyle = 'gray';\n                ctx.fillRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.strokeStyle = 'black';\n                ctx.strokeRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.fillStyle = 'black';\n                ctx.textAlign = \"center\";\n                ctx.textBaseline = 'middle';\n                ctx.font = 'bold 12pt monospace'\n                ctx.fillText(bases[k], x, y - 1);\n                ctx.font = '5pt monospace'\n                ctx.fillText('MPP', x, y + 8);\n            }\n        },\n    );\n}\n\n/**\n * @param {!string} bases\n * @param {!boolean} dag\n * @returns {!Gate}\n */\nfunction make_spp_gate(bases, dag) {\n    return new Gate(\n        (dag ? 'SPP_DAG:' : 'SPP:') + bases,\n        bases.length,\n        true,\n        false,\n        undefined,\n        (frame, targets) => frame.do_spp(bases, targets),\n        (frame, targets) => frame.do_spp(bases, targets),\n        (op, coordFunc, ctx) => {\n            let prev_x = undefined;\n            let prev_y = undefined;\n            for (let k = 0; k < op.id_targets.length; k++) {\n                let t = op.id_targets[k];\n                let [x, y] = coordFunc(t);\n                if (prev_x !== undefined) {\n                    draw_connector(ctx, x, y, prev_x, prev_y);\n                }\n\n                prev_x = x;\n                prev_y = y;\n            }\n\n            for (let k = 0; k < op.id_targets.length; k++) {\n                let t = op.id_targets[k];\n                let [x, y] = coordFunc(t);\n                ctx.fillStyle = 'gray';\n                ctx.fillRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.strokeStyle = 'black';\n                ctx.strokeRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.fillStyle = 'black';\n                ctx.textAlign = \"center\";\n                ctx.textBaseline = 'middle';\n                ctx.font = 'bold 12pt monospace'\n                ctx.fillText(bases[k], x, y - 1);\n                ctx.font = '5pt monospace'\n                ctx.fillText(dag ? 'SPP†' : 'SPP', x, y + 8);\n            }\n        },\n    );\n}\n\nexport {make_mpp_gate, make_spp_gate};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_pair_measurements.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\nimport {draw_connector} from \"./gate_draw_util.js\";\n\nfunction *iter_gates_pair_measurements() {\n    yield new Gate(\n        'MXX',\n        2,\n        true,\n        false,\n        new Map([\n            ['II', 'II'],\n            ['IX', 'IX'],\n            ['IY', 'ERR:IY'],\n            ['IZ', 'ERR:IZ'],\n\n            ['XI', 'XI'],\n            ['XX', 'XX'],\n            ['XY', 'ERR:XY'],\n            ['XZ', 'ERR:XZ'],\n\n            ['YI', 'ERR:YI'],\n            ['YX', 'ERR:YX'],\n            ['YY', 'YY'],\n            ['YZ', 'YZ'],\n\n            ['ZI', 'ERR:ZI'],\n            ['ZX', 'ERR:ZX'],\n            ['ZY', 'ZY'],\n            ['ZZ', 'ZZ'],\n        ]),\n        (frame, targets) => frame.do_measure('XX', targets),\n        (frame, targets) => frame.do_measure('XX', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillRect(x2 - rad, y2 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeRect(x2 - rad, y2 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('MXX', x1, y1);\n            ctx.fillText('MXX', x2, y2);\n        },\n    );\n    yield new Gate(\n        'MYY',\n        2,\n        true,\n        false,\n        new Map([\n            ['II', 'II'],\n            ['IX', 'ERR:IX'],\n            ['IY', 'IY'],\n            ['IZ', 'ERR:IZ'],\n\n            ['XI', 'ERR:XI'],\n            ['XX', 'XX'],\n            ['XY', 'ERR:XY'],\n            ['XZ', 'XZ'],\n\n            ['YI', 'YI'],\n            ['YX', 'ERR:YX'],\n            ['YY', 'YY'],\n            ['YZ', 'ERR:YZ'],\n\n            ['ZI', 'ERR:ZI'],\n            ['ZX', 'ZX'],\n            ['ZY', 'ERR:ZY'],\n            ['ZZ', 'ZZ'],\n        ]),\n        (frame, targets) => frame.do_measure('YY', targets),\n        (frame, targets) => frame.do_measure('YY', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillRect(x2 - rad, y2 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeRect(x2 - rad, y2 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('MYY', x1, y1);\n            ctx.fillText('MYY', x2, y2);\n        },\n    );\n    yield new Gate(\n        'MZZ',\n        2,\n        true,\n        false,\n        new Map([\n            ['II', 'II'],\n            ['IX', 'ERR:IX'],\n            ['IY', 'ERR:IY'],\n            ['IZ', 'IZ'],\n\n            ['XI', 'ERR:XI'],\n            ['XX', 'XX'],\n            ['XY', 'XY'],\n            ['XZ', 'ERR:XZ'],\n\n            ['YI', 'ERR:YI'],\n            ['YX', 'YX'],\n            ['YY', 'YY'],\n            ['YZ', 'ERR:YZ'],\n\n            ['ZI', 'ZI'],\n            ['ZX', 'ERR:ZX'],\n            ['ZY', 'ERR:ZY'],\n            ['ZZ', 'ZZ'],\n        ]),\n        (frame, targets) => frame.do_measure('ZZ', targets),\n        (frame, targets) => frame.do_measure('ZZ', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillRect(x2 - rad, y2 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeRect(x2 - rad, y2 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('MZZ', x1, y1);\n            ctx.fillText('MZZ', x2, y2);\n        },\n    );\n}\n\nexport {iter_gates_pair_measurements};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_paulis.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\n\nfunction *iter_gates_paulis() {\n    yield new Gate(\n        'ERR',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],\n            ['Z', 'Z'],\n        ]),\n        () => {},\n        () => {},\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'red';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('ERR', x1, y1);\n        },\n    );\n    yield new Gate(\n        'I',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],\n            ['Z', 'Z'],\n        ]),\n        () => {},\n        () => {},\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'white';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('I', x1, y1);\n        },\n    );\n    yield new Gate(\n        'X',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],\n            ['Z', 'Z'],\n        ]),\n        () => {},\n        () => {},\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'white';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('X', x1, y1);\n        },\n    );\n    yield new Gate(\n        'Y',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],\n            ['Z', 'Z'],\n        ]),\n        () => {},\n        () => {},\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'white';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('Y', x1, y1);\n        },\n    );\n    yield new Gate(\n        'Z',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],\n            ['Z', 'Z'],\n        ]),\n        () => {},\n        () => {},\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'white';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('Z', x1, y1);\n        },\n    );\n}\n\nexport {iter_gates_paulis};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_quarter_turns.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\n\nfunction *iter_gates_quarter_turns() {\n    yield new Gate(\n        'S',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Y'],\n            ['Z', 'Z'],\n        ]),\n        (frame, targets) => frame.do_exchange_xy(targets),\n        (frame, targets) => frame.do_exchange_xy(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('S', x1, y1);\n        },\n    )\n    yield new Gate(\n        'S_DAG',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Y'],\n            ['Z', 'Z'],\n        ]),\n        (frame, targets) => frame.do_exchange_xy(targets),\n        (frame, targets) => frame.do_exchange_xy(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('S†', x1, y1);\n        },\n    )\n\n    yield new Gate(\n        'SQRT_X',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],\n            ['Z', 'Y'],\n        ]),\n        (frame, targets) => frame.do_exchange_yz(targets),\n        (frame, targets) => frame.do_exchange_yz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('√X', x1, y1);\n        },\n    )\n    yield new Gate(\n        'SQRT_X_DAG',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],\n            ['Z', 'Y'],\n        ]),\n        (frame, targets) => frame.do_exchange_yz(targets),\n        (frame, targets) => frame.do_exchange_yz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('√X†', x1, y1);\n        },\n    )\n\n    yield new Gate(\n        'SQRT_Y',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Z'],\n            ['Z', 'X'],\n        ]),\n        (frame, targets) => frame.do_exchange_xz(targets),\n        (frame, targets) => frame.do_exchange_xz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('√Y', x1, y1);\n        },\n    )\n    yield new Gate(\n        'SQRT_Y_DAG',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Z'],\n            ['Z', 'X'],\n        ]),\n        (frame, targets) => frame.do_exchange_xz(targets),\n        (frame, targets) => frame.do_exchange_xz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'yellow';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('√Y†', x1, y1);\n        },\n    )\n}\n\nexport {iter_gates_quarter_turns};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_resets.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\n\nfunction *iter_gates_resets() {\n    yield new Gate(\n        'R',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'ERR:I'],\n            ['Y', 'ERR:I'],\n            ['Z', 'ERR:I'],\n        ]),\n        (frame, targets) => frame.do_discard(targets),\n        (frame, targets) => frame.do_demolition_measure('Z', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('R', x1, y1);\n        },\n    );\n    yield new Gate(\n        'RX',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'ERR:I'],\n            ['Y', 'ERR:I'],\n            ['Z', 'ERR:I'],\n        ]),\n        (frame, targets) => frame.do_discard(targets),\n        (frame, targets) => frame.do_demolition_measure('X', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('RX', x1, y1);\n        },\n    );\n    yield new Gate(\n        'RY',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'ERR:I'],\n            ['Y', 'ERR:I'],\n            ['Z', 'ERR:I'],\n        ]),\n        (frame, targets) => frame.do_discard(targets),\n        (frame, targets) => frame.do_demolition_measure('Y', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('RY', x1, y1);\n        },\n    );\n}\n\nexport {iter_gates_resets};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_solo_measurements.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\n\nfunction *iter_gates_solo_measurements() {\n    yield new Gate(\n        'M',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'ERR:X'],\n            ['Y', 'ERR:Y'],\n            ['Z', 'Z'],\n        ]),\n        (frame, targets) => frame.do_measure('Z', targets),\n        (frame, targets) => frame.do_measure('Z', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('M', x1, y1);\n            ctx.textAlign = \"left\";\n        },\n    );\n    yield new Gate(\n        'MX',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'X'],\n            ['Y', 'ERR:Y'],\n            ['Z', 'ERR:Z'],\n        ]),\n        (frame, targets) => frame.do_measure('X', targets),\n        (frame, targets) => frame.do_measure('X', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('MX', x1, y1);\n            ctx.textAlign = \"left\";\n        },\n    );\n    yield new Gate(\n        'MY',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'ERR:X'],\n            ['Y', 'Y'],\n            ['Z', 'ERR:Z'],\n        ]),\n        (frame, targets) => frame.do_measure('Y', targets),\n        (frame, targets) => frame.do_measure('Y', targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'gray';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('MY', x1, y1);\n            ctx.textAlign = \"left\";\n        },\n    );\n}\n\nexport {iter_gates_solo_measurements};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_sqrt_pauli_pairs.js",
    "content": "import {Gate} from \"./gate.js\"\nimport {draw_connector} from \"./gate_draw_util.js\";\nimport {rad} from \"../draw/config.js\";\n\nfunction *iter_gates_sqrt_pauli_pairs() {\n    yield new Gate(\n        'II',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'IX'],\n            ['IZ', 'IZ'],\n            ['XI', 'XI'],\n            ['ZI', 'ZI'],\n        ]),\n        (frame, targets) => undefined,\n        (frame, targets) => undefined,\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            for (let [x, y] of [[x1, y1], [x2, y2]]) {\n                ctx.fillStyle = 'white';\n                ctx.fillRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.strokeStyle = 'black';\n                ctx.strokeRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.fillStyle = 'black';\n                ctx.textAlign = \"center\";\n                ctx.textBaseline = 'middle';\n                ctx.fillText('II', x, y);\n            }\n        },\n    )\n    yield new Gate(\n        'SQRT_XX',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'IX'],\n            ['IZ', 'XY'],\n            ['XI', 'XI'],\n            ['ZI', 'YX'],\n        ]),\n        (frame, targets) => frame.do_sqrt_xx(targets),\n        (frame, targets) => frame.do_sqrt_xx(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            for (let [x, y] of [[x1, y1], [x2, y2]]) {\n                ctx.fillStyle = 'yellow';\n                ctx.fillRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.strokeStyle = 'black';\n                ctx.strokeRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.fillStyle = 'black';\n                ctx.textAlign = \"center\";\n                ctx.textBaseline = 'middle';\n                ctx.fillText('√XX', x, y);\n            }\n        },\n    )\n    yield new Gate(\n        'SQRT_XX_DAG',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'IX'],\n            ['IZ', 'XY'],\n            ['XI', 'XI'],\n            ['ZI', 'YX'],\n        ]),\n        (frame, targets) => frame.do_sqrt_xx(targets),\n        (frame, targets) => frame.do_sqrt_xx(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            for (let [x, y] of [[x1, y1], [x2, y2]]) {\n                ctx.fillStyle = 'yellow';\n                ctx.fillRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.strokeStyle = 'black';\n                ctx.strokeRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.fillStyle = 'black';\n                ctx.textAlign = \"center\";\n                ctx.textBaseline = 'middle';\n                ctx.fillText('√XX†', x, y);\n            }\n        },\n    )\n\n    yield new Gate(\n        'SQRT_YY',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'YZ'],\n            ['IZ', 'YX'],\n            ['XI', 'ZY'],\n            ['ZI', 'XY'],\n        ]),\n        (frame, targets) => frame.do_sqrt_yy(targets),\n        (frame, targets) => frame.do_sqrt_yy(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            for (let [x, y] of [[x1, y1], [x2, y2]]) {\n                ctx.fillStyle = 'yellow';\n                ctx.fillRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.strokeStyle = 'black';\n                ctx.strokeRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.fillStyle = 'black';\n                ctx.textAlign = \"center\";\n                ctx.textBaseline = 'middle';\n                ctx.fillText('√YY', x, y);\n            }\n        },\n    )\n    yield new Gate(\n        'SQRT_YY_DAG',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'YZ'],\n            ['IZ', 'YX'],\n            ['XI', 'ZY'],\n            ['ZI', 'XY'],\n        ]),\n        (frame, targets) => frame.do_sqrt_yy(targets),\n        (frame, targets) => frame.do_sqrt_yy(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            for (let [x, y] of [[x1, y1], [x2, y2]]) {\n                ctx.fillStyle = 'yellow';\n                ctx.fillRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.strokeStyle = 'black';\n                ctx.strokeRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.fillStyle = 'black';\n                ctx.textAlign = \"center\";\n                ctx.textBaseline = 'middle';\n                ctx.fillText('√YY†', x, y);\n            }\n        },\n    )\n\n    yield new Gate(\n        'SQRT_ZZ',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'ZY'],\n            ['IZ', 'IZ'],\n            ['XI', 'YZ'],\n            ['ZI', 'ZI'],\n        ]),\n        (frame, targets) => frame.do_sqrt_zz(targets),\n        (frame, targets) => frame.do_sqrt_zz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            for (let [x, y] of [[x1, y1], [x2, y2]]) {\n                ctx.fillStyle = 'yellow';\n                ctx.fillRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.strokeStyle = 'black';\n                ctx.strokeRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.fillStyle = 'black';\n                ctx.textAlign = \"center\";\n                ctx.textBaseline = 'middle';\n                ctx.fillText('√ZZ', x, y);\n            }\n        },\n    )\n    yield new Gate(\n        'SQRT_ZZ_DAG',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'ZY'],\n            ['IZ', 'IZ'],\n            ['XI', 'YZ'],\n            ['ZI', 'ZI'],\n        ]),\n        (frame, targets) => frame.do_sqrt_zz(targets),\n        (frame, targets) => frame.do_sqrt_zz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n\n            draw_connector(ctx, x1, y1, x2, y2);\n\n            for (let [x, y] of [[x1, y1], [x2, y2]]) {\n                ctx.fillStyle = 'yellow';\n                ctx.fillRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.strokeStyle = 'black';\n                ctx.strokeRect(x - rad, y - rad, rad * 2, rad * 2);\n                ctx.fillStyle = 'black';\n                ctx.textAlign = \"center\";\n                ctx.textBaseline = 'middle';\n                ctx.fillText('√ZZ†', x, y);\n            }\n        },\n    )\n}\n\nexport {iter_gates_sqrt_pauli_pairs};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_swaps.js",
    "content": "import {Gate} from \"./gate.js\"\nimport {\n    draw_connector,\n    draw_swap_control,\n    draw_iswap_control,\n    draw_zswap_control,\n    draw_xswap_control\n} from './gate_draw_util.js';\n\nfunction *iter_gates_swaps() {\n    yield new Gate(\n        'ISWAP',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'YZ'],\n            ['IZ', 'ZI'],\n            ['XI', 'ZY'],\n            ['ZI', 'IZ'],\n        ]),\n        (frame, targets) => frame.do_iswap(targets),\n        (frame, targets) => frame.do_iswap(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_iswap_control(ctx, x1, y1);\n            draw_iswap_control(ctx, x2, y2);\n        },\n    )\n    yield new Gate(\n        'ISWAP_DAG',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'YZ'],\n            ['IZ', 'ZI'],\n            ['XI', 'ZY'],\n            ['ZI', 'IZ'],\n        ]),\n        (frame, targets) => frame.do_iswap(targets),\n        (frame, targets) => frame.do_iswap(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_iswap_control(ctx, x1, y1);\n            draw_iswap_control(ctx, x2, y2);\n        },\n    )\n    yield new Gate(\n        'SWAP',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'XI'],\n            ['IZ', 'ZI'],\n            ['XI', 'IX'],\n            ['ZI', 'IZ'],\n        ]),\n        (frame, targets) => frame.do_swap(targets),\n        (frame, targets) => frame.do_swap(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_swap_control(ctx, x1, y1);\n            draw_swap_control(ctx, x2, y2);\n        },\n    );\n    yield new Gate(\n        'CXSWAP',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'XI'],\n            ['IZ', 'ZZ'],\n            ['XI', 'XX'],\n            ['ZI', 'IZ'],\n        ]),\n        (frame, targets) => frame.do_cx_swap(targets),\n        (frame, targets) => frame.do_swap_cx(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_zswap_control(ctx, x1, y1);\n            draw_xswap_control(ctx, x2, y2);\n        },\n    )\n    yield new Gate(\n        'CZSWAP',\n        2,\n        true,\n        false,\n        new Map([\n            ['IX', 'XZ'],\n            ['IZ', 'ZI'],\n            ['XI', 'ZX'],\n            ['ZI', 'IZ'],\n        ]),\n        (frame, targets) => frame.do_cz_swap(targets),\n        (frame, targets) => frame.do_cz_swap(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            let [x2, y2] = coordFunc(op.id_targets[1]);\n            draw_connector(ctx, x1, y1, x2, y2);\n            draw_zswap_control(ctx, x1, y1);\n            draw_zswap_control(ctx, x2, y2);\n        },\n    )\n}\n\nexport {iter_gates_swaps};\n"
  },
  {
    "path": "glue/crumble/gates/gateset_third_turns.js",
    "content": "import {rad} from \"../draw/config.js\"\nimport {Gate} from \"./gate.js\"\n\nfunction *iter_gates_third_turns() {\n    yield new Gate(\n        'C_XYZ',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Y'],\n            ['Z', 'X'],\n        ]),\n        (frame, targets) => frame.do_cycle_xyz(targets),\n        (frame, targets) => frame.do_cycle_zyx(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'teal';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('C', x1, y1 - rad / 3);\n            ctx.fillText(\"XYZ\", x1, y1 + rad / 3);\n        },\n    )\n    yield new Gate(\n        'C_NXYZ',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Y'],\n            ['Z', 'X'],\n        ]),\n        (frame, targets) => frame.do_cycle_xyz(targets),\n        (frame, targets) => frame.do_cycle_zyx(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'teal';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('C', x1, y1 - rad / 3);\n            ctx.fillText(\"NXYZ\", x1, y1 + rad / 3);\n        },\n    )\n    yield new Gate(\n        'C_XNYZ',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Y'],\n            ['Z', 'X'],\n        ]),\n        (frame, targets) => frame.do_cycle_xyz(targets),\n        (frame, targets) => frame.do_cycle_zyx(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'teal';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('C', x1, y1 - rad / 3);\n            ctx.fillText(\"XNYZ\", x1, y1 + rad / 3);\n        },\n    )\n    yield new Gate(\n        'C_XYNZ',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Y'],\n            ['Z', 'X'],\n        ]),\n        (frame, targets) => frame.do_cycle_xyz(targets),\n        (frame, targets) => frame.do_cycle_zyx(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'teal';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('C', x1, y1 - rad / 3);\n            ctx.fillText(\"XYNZ\", x1, y1 + rad / 3);\n        },\n    )\n    yield new Gate(\n        'C_ZYX',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Z'],\n            ['Z', 'Y'],\n        ]),\n        (frame, targets) => frame.do_cycle_zyx(targets),\n        (frame, targets) => frame.do_cycle_xyz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'teal';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('C', x1, y1 - rad / 3);\n            ctx.fillText(\"ZYX\", x1, y1 + rad / 3);\n        },\n    )\n    yield new Gate(\n        'C_ZYNX',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Z'],\n            ['Z', 'Y'],\n        ]),\n        (frame, targets) => frame.do_cycle_zyx(targets),\n        (frame, targets) => frame.do_cycle_xyz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'teal';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('C', x1, y1 - rad / 3);\n            ctx.fillText(\"ZYNX\", x1, y1 + rad / 3);\n        },\n    )\n    yield new Gate(\n        'C_ZNYX',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Z'],\n            ['Z', 'Y'],\n        ]),\n        (frame, targets) => frame.do_cycle_zyx(targets),\n        (frame, targets) => frame.do_cycle_xyz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'teal';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('C', x1, y1 - rad / 3);\n            ctx.fillText(\"ZNYX\", x1, y1 + rad / 3);\n        },\n    )\n    yield new Gate(\n        'C_NZYX',\n        1,\n        true,\n        false,\n        new Map([\n            ['X', 'Z'],\n            ['Z', 'Y'],\n        ]),\n        (frame, targets) => frame.do_cycle_zyx(targets),\n        (frame, targets) => frame.do_cycle_xyz(targets),\n        (op, coordFunc, ctx) => {\n            let [x1, y1] = coordFunc(op.id_targets[0]);\n            ctx.fillStyle = 'teal';\n            ctx.fillRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.fillStyle = 'black';\n            ctx.strokeStyle = 'black';\n            ctx.strokeRect(x1 - rad, y1 - rad, rad*2, rad*2);\n            ctx.textAlign = \"center\";\n            ctx.textBaseline = 'middle';\n            ctx.fillText('C', x1, y1 - rad / 3);\n            ctx.fillText(\"NZYX\", x1, y1 + rad / 3);\n        },\n    )\n}\n\nexport {iter_gates_third_turns};\n"
  },
  {
    "path": "glue/crumble/keyboard/chord.js",
    "content": "import {describe} from \"../base/describe.js\";\nimport {equate} from \"../base/equate.js\";\n\nclass ChordEvent {\n    /**\n     * @param {!boolean} inProgress\n     * @param {!Set<!string>} chord\n     * @param {!boolean} altKey\n     * @param {!boolean} ctrlKey\n     * @param {!boolean} metaKey\n     * @param {!boolean} shiftKey\n     */\n    constructor(inProgress, chord, altKey, ctrlKey, metaKey, shiftKey) {\n        this.inProgress = inProgress;\n        this.chord = chord;\n        this.altKey = altKey;\n        this.shiftKey = shiftKey;\n        this.ctrlKey = ctrlKey;\n        this.metaKey = metaKey;\n    }\n\n    /**\n     * @param {*} other\n     * @return {!boolean}\n     */\n    isEqualTo(other) {\n        return other instanceof ChordEvent &&\n            this.inProgress === other.inProgress &&\n            equate(this.chord, other.chord) &&\n            this.altKey === other.altKey &&\n            this.shiftKey === other.shiftKey &&\n            this.ctrlKey === other.ctrlKey &&\n            this.metaKey === other.metaKey;\n    }\n\n    /**\n     * @return {!string}\n     */\n    toString() {\n        return `ChordEvent(\n    inProgress=${this.inProgress},\n    chord=${describe(this.chord)},\n    altKey=${this.altKey},\n    shiftKey=${this.shiftKey},\n    ctrlKey=${this.ctrlKey},\n    metaKey=${this.metaKey},\n)`;\n    }\n}\n\nconst MODIFIER_KEYS = new Set([\"alt\", \"shift\", \"control\", \"meta\"]);\nconst ACTION_KEYS = new Set(['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\\\\', '`']);\n\nclass Chorder {\n    constructor() {\n        this.curModifiers = /** @type {!Set<!string>} */ new Set();\n        this.curPressed = /** @type {!Set<!string>} */ new Set();\n        this.curChord = /** @type {!Set<!string>} */ new Set();\n        this.queuedEvents = /** @type {!Array<!ChordEvent>} */ [];\n    }\n\n    /**\n     * @param {!boolean} inProgress\n     */\n    toEvent(inProgress) {\n        return new ChordEvent(\n            inProgress,\n            new Set(this.curChord),\n            this.curModifiers.has(\"alt\"),\n            this.curModifiers.has(\"control\"),\n            this.curModifiers.has(\"meta\"),\n            this.curModifiers.has(\"shift\")\n        );\n    }\n\n    /**\n     * @param {!boolean} inProgress\n     * @private\n     */\n    _queueEvent(inProgress) {\n        this.queuedEvents.push(this.toEvent(inProgress));\n    }\n\n    handleFocusChanged() {\n        this.curPressed.clear();\n        this.curChord.clear();\n        this.curModifiers.clear();\n    }\n\n    /**\n     * @param {!KeyboardEvent} ev\n     */\n    handleKeyEvent(ev) {\n        let key = ev.key.toLowerCase();\n        if (key === 'escape') {\n            this.handleFocusChanged();\n        }\n        if (ev.type === 'keydown') {\n            let flag_key_pairs = [\n                [ev.altKey, \"alt\"],\n                [ev.shiftKey, \"shift\"],\n                [ev.ctrlKey, \"control\"],\n                [ev.metaKey, \"meta\"],\n            ];\n            for (let [b, k] of flag_key_pairs) {\n                if (b) {\n                    this.curModifiers.add(k);\n                } else {\n                    this.curModifiers.delete(k);\n                }\n            }\n            if (!MODIFIER_KEYS.has(key)) {\n                this.curPressed.add(key);\n                this.curChord.add(key);\n            }\n            this._queueEvent(true);\n        } else if (ev.type === 'keyup') {\n            if (!MODIFIER_KEYS.has(key)) {\n                this.curPressed.delete(key);\n                this._queueEvent(this.curPressed.size > 0 && !ACTION_KEYS.has(key));\n                if (ACTION_KEYS.has(key)) {\n                    this.curChord.delete(key);\n                }\n                if (this.curPressed.size === 0) {\n                    this.curModifiers.clear();\n                    this.curChord.clear();\n                }\n            }\n        } else {\n            throw new Error(\"Not a recognized key event type: \" + ev.type);\n        }\n    }\n}\n\nexport {Chorder, ChordEvent};\n"
  },
  {
    "path": "glue/crumble/keyboard/chord.test.js",
    "content": "import {test, assertThat, skipRestOfTestIfHeadless} from \"../test/test_util.js\"\nimport {Chorder, ChordEvent} from \"./chord.js\"\n\ntest(\"chorder.usage\", () => {\n    let c = new Chorder();\n    assertThat(c.curChord).isEqualTo(new Set());\n    assertThat(c.curPressed).isEqualTo(new Set());\n    assertThat(c.queuedEvents).isEqualTo([]);\n    skipRestOfTestIfHeadless();\n\n    c.handleKeyEvent(new KeyboardEvent('keydown', {key: 'x', ctrlKey: true}));\n    assertThat(c.queuedEvents.shift()).isEqualTo(new ChordEvent(true, new Set([\"x\"]), false, true, false, false));\n    assertThat(c.curChord).isEqualTo(new Set([\"x\"]));\n    assertThat(c.curPressed).isEqualTo(new Set([\"x\"]));\n    assertThat(c.curModifiers).isEqualTo(new Set([\"control\"]));\n    assertThat(c.queuedEvents).isEqualTo([]);\n\n    c.handleKeyEvent(new KeyboardEvent('keydown', {key: 'r', altKey: true}));\n    assertThat(c.queuedEvents.shift()).isEqualTo(new ChordEvent(true, new Set([\"r\", \"x\"]), true, false, false, false));\n    assertThat(c.curChord).isEqualTo(new Set([\"r\", \"x\"]));\n    assertThat(c.curPressed).isEqualTo(new Set([\"r\", \"x\"]));\n    assertThat(c.curModifiers).isEqualTo(new Set([\"alt\"]));\n    assertThat(c.queuedEvents).isEqualTo([]);\n\n    c.handleKeyEvent(new KeyboardEvent('keyup', {key: 'x'}));\n    assertThat(c.queuedEvents.shift()).isEqualTo(new ChordEvent(true, new Set([\"r\", \"x\"]), true, false, false, false));\n    assertThat(c.curChord).isEqualTo(new Set([\"r\", \"x\"]));\n    assertThat(c.curPressed).isEqualTo(new Set([\"r\"]));\n    assertThat(c.curModifiers).isEqualTo(new Set([\"alt\"]));\n    assertThat(c.queuedEvents).isEqualTo([]);\n\n    c.handleKeyEvent(new KeyboardEvent('keyup', {key: 'r'}));\n    assertThat(c.queuedEvents.shift()).isEqualTo(new ChordEvent(false, new Set([\"r\", \"x\"]), true, false, false, false));\n    assertThat(c.curChord).isEqualTo(new Set([]));\n    assertThat(c.curPressed).isEqualTo(new Set([]));\n    assertThat(c.curModifiers).isEqualTo(new Set([]));\n    assertThat(c.queuedEvents).isEqualTo([]);\n});\n"
  },
  {
    "path": "glue/crumble/keyboard/toolbox.js",
    "content": "import {GATE_MAP} from \"../gates/gateset.js\"\n\nlet toolboxCanvas = /** @type {!HTMLCanvasElement} */ document.getElementById('toolbox');\n\nlet DIAM = 28;\nlet PITCH = DIAM + 4;\nlet PAD = 10.5;\n\nlet COLUMNS = ['H', 'S', 'R', 'M', 'MR', 'C', 'W', 'SC', 'MC', 'P', '1-9'];\nlet DEF_ROW = [1,    2,   2,   2,  2,     1,   2,   2,    2,    -1, -1, -1];\n\n/**\n * @param {!ChordEvent} ev\n * @returns {undefined|!{row: !int, strength: !number}}\n */\nfunction getFocusedRow(ev) {\n    if (ev.ctrlKey) {\n        return undefined;\n    }\n    let hasX = +ev.chord.has('x');\n    let hasY = +ev.chord.has('y');\n    let hasZ = +ev.chord.has('z');\n    if ((hasX && !hasY && !hasZ) || (!hasX && hasY && hasZ)) {\n        return {row: 0, strength: Math.max(hasX, Math.min(hasY, hasZ))};\n    }\n    if ((!hasX && hasY && !hasZ) || (hasX && !hasY && hasZ)) {\n        return {row: 1, strength: Math.max(hasY, Math.min(hasX, hasZ))};\n    }\n    if ((!hasX && !hasY && hasZ) || (hasX && hasY && !hasZ)) {\n        return {row: 2, strength: Math.max(hasZ, Math.min(hasX, hasY))};\n    }\n    return undefined;\n}\n/**\n * @param {!ChordEvent} ev\n * @returns {undefined|!{col: !int, strength: !number}}\n */\nfunction getFocusedCol(ev) {\n    if (ev.ctrlKey) {\n        return undefined;\n    }\n    let best = undefined;\n    for (let k = 0; k < COLUMNS.length; k++) {\n        let s = 0;\n        for (let c of COLUMNS[k].toLowerCase()) {\n            s += ev.chord.has(c.toLowerCase());\n        }\n        if (s === COLUMNS[k].length) {\n            if (best === undefined || s >= best.strength) {\n                best = {col: k, strength: s / COLUMNS[k].length};\n            }\n        }\n    }\n    return best;\n}\n\nfunction make_pos_to_gate_dict() {\n    let result = new Map([\n        ['0,0', GATE_MAP.get(\"H_YZ\")],\n        ['0,1', GATE_MAP.get(\"H\")],\n        ['0,2', GATE_MAP.get(\"H_XY\")],\n        ['1,0', GATE_MAP.get(\"SQRT_X\")],\n        ['1,1', GATE_MAP.get(\"SQRT_Y\")],\n        ['1,2', GATE_MAP.get(\"S\")],\n        ['2,0', GATE_MAP.get(\"RX\")],\n        ['2,1', GATE_MAP.get(\"RY\")],\n        ['2,2', GATE_MAP.get(\"R\")],\n        ['3,0', GATE_MAP.get(\"MX\")],\n        ['3,1', GATE_MAP.get(\"MY\")],\n        ['3,2', GATE_MAP.get(\"M\")],\n        ['4,0', GATE_MAP.get(\"MRX\")],\n        ['4,1', GATE_MAP.get(\"MRY\")],\n        ['4,2', GATE_MAP.get(\"MRZ\")],\n        ['5,0', GATE_MAP.get(\"CX\")],\n        ['5,1', GATE_MAP.get(\"CY\")],\n        ['5,2', GATE_MAP.get(\"CZ\")],\n        ['6,0', GATE_MAP.get(\"CXSWAP\")],\n        ['6,1', GATE_MAP.get(\"SWAP\")],\n        ['6,2', GATE_MAP.get(\"CZSWAP\")],\n        ['7,0', GATE_MAP.get(\"SQRT_XX\")],\n        ['7,1', GATE_MAP.get(\"SQRT_YY\")],\n        ['7,2', GATE_MAP.get(\"SQRT_ZZ\")],\n        ['8,0', GATE_MAP.get(\"MXX\")],\n        ['8,1', GATE_MAP.get(\"MYY\")],\n        ['8,2', GATE_MAP.get(\"MZZ\")],\n    ]);\n    let x = 9;\n    for (let k = 0; k < 4; k++) {\n        result.set(`${x},0`, GATE_MAP.get(\"MARKX\").withDefaultArgument(k));\n        result.set(`${x},1`, GATE_MAP.get(\"MARKY\").withDefaultArgument(k));\n        result.set(`${x},2`, GATE_MAP.get(\"MARKZ\").withDefaultArgument(k));\n        result.set(`${x},-1`, GATE_MAP.get(\"MARK\").withDefaultArgument(k));\n        x += 1;\n    }\n    return result;\n}\nlet POS_TO_GATE_DICT = make_pos_to_gate_dict();\n\n/**\n * @param {!ChordEvent} ev\n * @returns {{focusedRow: (!{row: !int, strength: !number}|undefined), partialFocusedRow: (!{row: !int, strength: !number}|undefined), focusedCol: (!{col: !int, strength: !number}|undefined), chosenGate: undefined|!Gate}}\n */\nfunction getToolboxFocusedData(ev) {\n    let partialFocusedRow = getFocusedRow(ev);\n    let focusedCol = getFocusedCol(ev);\n\n    let focusedRow = partialFocusedRow;\n    if (focusedCol !== undefined && partialFocusedRow === undefined) {\n        let row = DEF_ROW[focusedCol.col];\n        if (row === undefined) {\n            focusedRow = undefined;\n        } else {\n            focusedRow = {strength: 0, row: row};\n        }\n    }\n    let chosenGate = undefined;\n    if (focusedRow !== undefined && focusedCol !== undefined) {\n        let key = `${focusedCol.col},${focusedRow.row}`;\n        if (POS_TO_GATE_DICT.has(key)) {\n            chosenGate = POS_TO_GATE_DICT.get(key);\n        }\n    }\n\n    return {partialFocusedRow, focusedRow, focusedCol, chosenGate};\n}\n\n/**\n * @param {!ChordEvent} ev\n */\nfunction drawToolbox(ev) {\n    toolboxCanvas.width = toolboxCanvas.scrollWidth;\n    toolboxCanvas.height = toolboxCanvas.scrollHeight;\n    let ctx = toolboxCanvas.getContext('2d');\n    ctx.clearRect(0, 0, toolboxCanvas.width, toolboxCanvas.height);\n    ctx.textAlign = 'right';\n    ctx.textBaseline = 'middle';\n    ctx.fillText('X', PAD - 3, PAD + DIAM / 2);\n    ctx.fillText('Y', PAD - 3, PAD + DIAM / 2 + PITCH);\n    ctx.fillText('Z', PAD - 3, PAD + DIAM / 2 + PITCH * 2);\n    ctx.textAlign = 'center';\n    ctx.textBaseline = 'bottom';\n    for (let k = 0; k < COLUMNS.length; k++) {\n        ctx.fillText(COLUMNS[k], PAD + DIAM / 2 + PITCH * k, PAD);\n    }\n\n    ctx.fillStyle = 'white';\n    ctx.strokeStyle = 'black';\n    let xGates = ['H_YZ', 'S_X', 'R_X', 'M_X', 'MR_X', 'C_X', 'CXSWAP', '√XX', 'M_XX', 'PX', 'X1'];\n    let yGates = ['H',    'S_Y', 'R_Y', 'M_Y', 'MR_Y', 'C_Y', 'SWAP',   '√YY', 'M_YY',  'PY',  'Y1'];\n    let zGates = ['H_XY', 'S',   'R',   'M',   'MR',   'C_Z', 'CZSWAP', '√ZZ', 'M_ZZ', 'PZ', 'Z1'];\n    let gates = [xGates, yGates, zGates];\n    for (let k = 0; k < COLUMNS.length; k++) {\n        for (let p = 0; p < 3; p++) {\n            ctx.fillRect(PAD + PITCH * k, PAD + PITCH * p, DIAM, DIAM);\n        }\n    }\n    for (let k = 0; k < COLUMNS.length; k++) {\n        for (let p = 0; p < 3; p++) {\n            let text = gates[p][k];\n            let cx = PAD + PITCH * k + DIAM / 2;\n            let cy = PAD + PITCH * p + DIAM / 2;\n            if (text.startsWith('P')) {\n                ctx.beginPath();\n                let numPoints = 3;\n                if (text === 'PX') {\n                    numPoints = 4;\n                    ctx.fillStyle = 'red';\n                } else if (text === 'PY') {\n                    numPoints = 5;\n                    ctx.fillStyle = 'green';\n                    cy += 1;\n                } else if (text === 'PZ') {\n                    numPoints = 3;\n                    ctx.fillStyle = 'blue';\n                    cy += 2;\n                }\n                let pts = [];\n                for (let k = 0; k < numPoints; k++) {\n                    let t = 2 * Math.PI / numPoints * (k + 0.5);\n                    pts.push([\n                        Math.round(cx + 0.3 * DIAM * Math.sin(t)),\n                        Math.round(cy + 0.3 * DIAM * Math.cos(t)),\n                    ]);\n                }\n                ctx.moveTo(pts[pts.length - 1][0], pts[pts.length - 1][1]);\n                for (let pt of pts) {\n                    ctx.lineTo(pt[0], pt[1]);\n                }\n\n                ctx.closePath();\n                ctx.globalAlpha *= 0.25;\n                ctx.fill();\n                ctx.globalAlpha *= 4;\n                continue;\n            }\n            if (text.endsWith('1')) {\n                ctx.beginPath();\n                ctx.moveTo(cx + PITCH * 0.15, cy - PITCH * 0.25);\n                ctx.lineTo(cx, cy + PITCH * 0.1);\n                ctx.lineTo(cx - PITCH * 0.15, cy - PITCH * 0.25);\n                ctx.closePath();\n                let color = text === 'X1' ? 'red' : text === 'Y1' ? 'green' : 'blue';\n                ctx.fillStyle = color;\n                ctx.strokeStyle = color;\n                ctx.fill();\n                ctx.lineWidth = 2;\n                ctx.beginPath();\n                ctx.moveTo(cx, cy);\n                ctx.lineTo(cx + DIAM * 0.5, cy);\n                ctx.stroke();\n                ctx.lineWidth = 1;\n                continue;\n            }\n\n            ctx.fillStyle = 'black';\n            if (text.indexOf('_') !== -1) {\n                let [main, sub] = text.split('_');\n                let k = 16;\n                let w1 = 0;\n                let w2 = 0;\n                while (k > 4) {\n                    ctx.font = `${k}pt monospace`;\n                    w1 = ctx.measureText(main).width;\n                    ctx.font = `${k * 0.6}pt monospace`;\n                    w2 = ctx.measureText(sub).width;\n                    if (w1 + w2 <= 26) {\n                        break;\n                    }\n                    k -= 1;\n                }\n                cx -= (w1 + w2) / 2;\n                ctx.font = `${k}pt monospace`;\n                ctx.textAlign = 'left';\n                ctx.textBaseline = 'middle';\n                ctx.fillText(main, cx, cy);\n                ctx.font = `${k * 0.6}pt monospace`;\n                ctx.textAlign = 'left';\n                ctx.textBaseline = 'top';\n                ctx.fillText(sub, cx + w1, cy);\n            } else {\n                let k = 16;\n                while (k > 4) {\n                    ctx.font = `${k}pt monospace`;\n                    if (ctx.measureText(text).width <= 28) {\n                        break;\n                    }\n                    k -= 1;\n                }\n                ctx.textAlign = 'center';\n                ctx.textBaseline = 'middle';\n                ctx.fillText(text, cx, cy);\n            }\n        }\n    }\n    ctx.strokeStyle = 'black';\n    for (let k = 0; k < COLUMNS.length; k++) {\n        for (let p = 0; p < 3; p++) {\n            ctx.strokeRect(PAD + PITCH * k, PAD + PITCH * p, DIAM, DIAM);\n        }\n    }\n\n    let focus = getToolboxFocusedData(ev);\n\n    if (focus.partialFocusedRow !== undefined) {\n        ctx.fillStyle = 'rgba(255, 255, 0, ' + (0.5 * focus.partialFocusedRow.strength) + ')';\n        ctx.fillRect(0, PAD + PITCH * focus.partialFocusedRow.row - (PITCH - DIAM) / 2, PAD + PITCH * COLUMNS.length, PITCH);\n    }\n    if (focus.focusedCol !== undefined) {\n        ctx.fillStyle = 'rgba(255, 255, 0, ' + (0.5 * focus.focusedCol.strength) + ')';\n        ctx.fillRect( PAD + PITCH * focus.focusedCol.col - (PITCH - DIAM) / 2, 0, PITCH, PAD + PITCH * 3);\n    }\n    if (focus.focusedRow !== undefined && focus.focusedCol !== undefined) {\n        ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';\n        ctx.fillRect( PAD + PITCH * focus.focusedCol.col - (PITCH - DIAM) / 2, PAD + PITCH * focus.focusedRow.row - (PITCH - DIAM) / 2, PITCH, PITCH);\n    }\n\n    ctx.textAlign = 'left';\n    ctx.textBaseline = 'middle';\n    ctx.fillStyle = 'black';\n}\n\nexport {getToolboxFocusedData, drawToolbox};\n"
  },
  {
    "path": "glue/crumble/main.js",
    "content": "import {Circuit} from \"./circuit/circuit.js\"\nimport {minXY} from \"./circuit/layer.js\"\nimport {pitch} from \"./draw/config.js\"\nimport {GATE_MAP} from \"./gates/gateset.js\"\nimport {EditorState} from \"./editor/editor_state.js\";\nimport {initUrlCircuitSync} from \"./editor/sync_url_to_state.js\";\nimport {draw} from \"./draw/main_draw.js\";\nimport {drawToolbox} from \"./keyboard/toolbox.js\";\nimport {Operation} from \"./circuit/operation.js\";\nimport {make_mpp_gate} from './gates/gateset_mpp.js';\nimport {PropagatedPauliFrames} from './circuit/propagated_pauli_frames.js';\n\nconst OFFSET_X = -pitch + Math.floor(pitch / 4) + 0.5;\nconst OFFSET_Y = -pitch + Math.floor(pitch / 4) + 0.5;\n\nconst btnInsertLayer = /** @type{!HTMLButtonElement} */ document.getElementById('btnInsertLayer');\nconst btnDeleteLayer = /** @type{!HTMLButtonElement} */ document.getElementById('btnDeleteLayer');\nconst btnUndo = /** @type{!HTMLButtonElement} */ document.getElementById('btnUndo');\nconst btnRedo = /** @type{!HTMLButtonElement} */ document.getElementById('btnRedo');\nconst btnClearMarkers = /** @type{!HTMLButtonElement} */ document.getElementById('btnClearMarkers');\nconst btnImportExport = /** @type{!HTMLButtonElement} */ document.getElementById('btnShowHideImportExport');\nconst btnNextLayer = /** @type{!HTMLButtonElement} */ document.getElementById('btnNextLayer');\nconst btnPrevLayer = /** @type{!HTMLButtonElement} */ document.getElementById('btnPrevLayer');\nconst btnRotate45 = /** @type{!HTMLButtonElement} */ document.getElementById('btnRotate45');\nconst btnRotate45Counter = /** @type{!HTMLButtonElement} */ document.getElementById('btnRotate45Counter');\nconst btnExport = /** @type {!HTMLButtonElement} */ document.getElementById('btnExport');\nconst btnImport = /** @type {!HTMLButtonElement} */ document.getElementById('btnImport');\nconst btnClear = /** @type {!HTMLButtonElement} */ document.getElementById('clear');\nconst txtStimCircuit = /** @type {!HTMLTextAreaElement} */ document.getElementById('txtStimCircuit');\nconst btnTimelineFocus = /** @type{!HTMLButtonElement} */ document.getElementById('btnTimelineFocus');\nconst btnClearTimelineFocus = /** @type{!HTMLButtonElement} */ document.getElementById('btnClearTimelineFocus');\nconst btnClearSelectedMarkers = /** @type{!HTMLButtonElement} */ document.getElementById('btnClearSelectedMarkers');\nconst btnShowExamples = /** @type {!HTMLButtonElement} */ document.getElementById('btnShowExamples');\nconst divExamples = /** @type{!HTMLDivElement} */ document.getElementById('examples-div');\n\n// Prevent typing in the import/export text editor from causing changes in the main circuit editor.\ntxtStimCircuit.addEventListener('keyup', ev => ev.stopPropagation());\ntxtStimCircuit.addEventListener('keydown', ev => ev.stopPropagation());\n\nlet editorState = /** @type {!EditorState} */ new EditorState(document.getElementById('cvn'));\n\nbtnExport.addEventListener('click', _ev => {\n    exportCurrentState();\n});\nbtnImport.addEventListener('click', _ev => {\n    let text = txtStimCircuit.value;\n    let circuit = Circuit.fromStimCircuit(text);\n    editorState.commit(circuit);\n});\n\nbtnImportExport.addEventListener('click', _ev => {\n    let div = /** @type{!HTMLDivElement} */ document.getElementById('divImportExport');\n    if (div.style.display === 'none') {\n        div.style.display = 'block';\n        btnImportExport.textContent = \"Hide Import/Export\";\n        exportCurrentState();\n    } else {\n        div.style.display = 'none';\n        btnImportExport.textContent = \"Show Import/Export\";\n        txtStimCircuit.value = '';\n    }\n    setTimeout(() => {\n        window.scrollTo(0, 0);\n    }, 0);\n});\n\nbtnClear.addEventListener('click', _ev => {\n    editorState.clearCircuit();\n});\n\nbtnUndo.addEventListener('click', _ev => {\n    editorState.undo();\n});\n\nbtnTimelineFocus.addEventListener('click', _ev => {\n    editorState.timelineSet = new Map(editorState.focusedSet.entries());\n    editorState.force_redraw();\n});\n\nbtnClearSelectedMarkers.addEventListener('click', _ev => {\n    editorState.unmarkFocusInferBasis(false);\n    editorState.force_redraw();\n});\n\nbtnShowExamples.addEventListener('click', _ev => {\n    if (divExamples.style.display === 'none') {\n        divExamples.style.display = 'block';\n        btnShowExamples.textContent = \"Hide Example Circuits\";\n    } else {\n        divExamples.style.display = 'none';\n        btnShowExamples.textContent = \"Show Example Circuits\";\n    }\n});\n\nbtnClearTimelineFocus.addEventListener('click', _ev => {\n    editorState.timelineSet = new Map();\n    editorState.force_redraw();\n});\n\nbtnRedo.addEventListener('click', _ev => {\n    editorState.redo();\n});\n\nbtnClearMarkers.addEventListener('click', _ev => {\n    editorState.clearMarkers();\n});\n\nbtnRotate45.addEventListener('click', _ev => {\n    editorState.rotate45(+1, false);\n});\nbtnRotate45Counter.addEventListener('click', _ev => {\n    editorState.rotate45(-1, false);\n});\n\nbtnInsertLayer.addEventListener('click', _ev => {\n    editorState.insertLayer(false);\n});\nbtnDeleteLayer.addEventListener('click', _ev => {\n    editorState.deleteCurLayer(false);\n});\n\nbtnNextLayer.addEventListener('click', _ev => {\n    editorState.changeCurLayerTo(editorState.curLayer + 1);\n});\nbtnPrevLayer.addEventListener('click', _ev => {\n    editorState.changeCurLayerTo(editorState.curLayer - 1);\n});\n\nwindow.addEventListener('resize', _ev => {\n    editorState.canvas.width = editorState.canvas.scrollWidth;\n    editorState.canvas.height = editorState.canvas.scrollHeight;\n    editorState.force_redraw();\n});\n\nfunction exportCurrentState() {\n    let validStimCircuit = editorState.copyOfCurCircuit().toStimCircuit().\n        replaceAll('\\nPOLYGON', '\\n#!pragma POLYGON').\n        replaceAll('\\nERR', '\\n#!pragma ERR').\n        replaceAll('\\nMARK', '\\n#!pragma MARK');\n    let txt = txtStimCircuit;\n    txt.value = validStimCircuit + '\\n';\n    txt.focus();\n    txt.select();\n}\n\neditorState.canvas.addEventListener('mousemove', ev => {\n    editorState.curMouseX = ev.offsetX + OFFSET_X;\n    editorState.curMouseY = ev.offsetY + OFFSET_Y;\n\n    // Scrubber.\n    let w = editorState.canvas.width / 2;\n    if (isInScrubber && ev.buttons === 1) {\n        editorState.changeCurLayerTo(Math.floor((ev.offsetX - w) / 8));\n        return;\n    }\n\n    editorState.force_redraw();\n});\n\nlet isInScrubber = false;\neditorState.canvas.addEventListener('mousedown', ev => {\n    editorState.curMouseX = ev.offsetX + OFFSET_X;\n    editorState.curMouseY = ev.offsetY + OFFSET_Y;\n    editorState.mouseDownX = ev.offsetX + OFFSET_X;\n    editorState.mouseDownY = ev.offsetY + OFFSET_Y;\n\n    // Scrubber.\n    let w = editorState.canvas.width / 2;\n    isInScrubber = ev.offsetY < 20 && ev.offsetX > w && ev.buttons === 1;\n    if (isInScrubber) {\n        editorState.changeCurLayerTo(Math.floor((ev.offsetX - w) / 8));\n        return;\n    }\n\n    editorState.force_redraw();\n});\n\neditorState.canvas.addEventListener('mouseup', ev => {\n    let highlightedArea = editorState.currentPositionsBoxesByMouseDrag(ev.altKey);\n    editorState.mouseDownX = undefined;\n    editorState.mouseDownY = undefined;\n    editorState.curMouseX = ev.offsetX + OFFSET_X;\n    editorState.curMouseY = ev.offsetY + OFFSET_Y;\n    editorState.changeFocus(highlightedArea, ev.shiftKey, ev.ctrlKey);\n    if (ev.buttons === 1) {\n        isInScrubber = false;\n    }\n});\n\n/**\n * @return {!Map<!string, !function(preview: !boolean) : void>}\n */\nfunction makeChordHandlers() {\n    let res = /** @type {!Map<!string, !function(preview: !boolean) : void>} */ new Map();\n\n    res.set('shift+t', preview => editorState.rotate45(-1, preview));\n    res.set('t', preview => editorState.rotate45(+1, preview));\n    res.set('escape', () => editorState.clearFocus());\n    res.set('delete', preview => editorState.deleteAtFocus(preview));\n    res.set('backspace', preview => editorState.deleteAtFocus(preview));\n    res.set('ctrl+delete', preview => editorState.deleteCurLayer(preview));\n    res.set('ctrl+insert', preview => editorState.insertLayer(preview));\n    res.set('ctrl+backspace', preview => editorState.deleteCurLayer(preview));\n    res.set('ctrl+z', preview => { if (!preview) editorState.undo() });\n    res.set('ctrl+y', preview => { if (!preview) editorState.redo() });\n    res.set('ctrl+shift+z', preview => { if (!preview) editorState.redo() });\n    res.set('ctrl+c', async preview => { await copyToClipboard(); });\n    res.set('ctrl+v', pasteFromClipboard);\n    res.set('ctrl+x', async preview => {\n        await copyToClipboard();\n        if (editorState.focusedSet.size === 0) {\n            let c = editorState.copyOfCurCircuit();\n            c.layers[editorState.curLayer].id_ops.clear();\n            c.layers[editorState.curLayer].markers.length = 0;\n            editorState.commit_or_preview(c, preview);\n        } else {\n            editorState.deleteAtFocus(preview);\n        }\n    });\n    res.set('l', preview => {\n        if (!preview) {\n            editorState.timelineSet = new Map(editorState.focusedSet.entries());\n            editorState.force_redraw();\n        }\n    });\n    res.set(' ', preview => editorState.unmarkFocusInferBasis(preview));\n\n    for (let [key, val] of [\n        ['1', 0],\n        ['2', 1],\n        ['3', 2],\n        ['4', 3],\n        ['5', 4],\n        ['6', 5],\n        ['7', 6],\n        ['8', 7],\n        ['9', 8],\n        ['0', 9],\n        ['-', 10],\n        ['=', 11],\n        ['\\\\', 12],\n        ['`', 13],\n    ]) {\n        res.set(`${key}`, preview => editorState.markFocusInferBasis(preview, val));\n        res.set(`${key}+x`, preview => editorState.writeGateToFocus(preview, GATE_MAP.get('MARKX').withDefaultArgument(val)));\n        res.set(`${key}+y`, preview => editorState.writeGateToFocus(preview, GATE_MAP.get('MARKY').withDefaultArgument(val)));\n        res.set(`${key}+z`, preview => editorState.writeGateToFocus(preview, GATE_MAP.get('MARKZ').withDefaultArgument(val)));\n        res.set(`${key}+d`, preview => editorState.writeMarkerToDetector(preview, val));\n        res.set(`${key}+o`, preview => editorState.writeMarkerToObservable(preview, val));\n        res.set(`${key}+j`, preview => editorState.moveDetOrObsAtFocusIntoMarker(preview, val));\n        res.set(`${key}+k`, preview => editorState.addDissipativeOverlapToMarkers(preview, val));\n    }\n\n    let defaultPolygonAlpha = 0.25;\n    res.set('p', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [1, 0, 0, defaultPolygonAlpha]));\n    res.set('alt+p', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [0, 1, 0, defaultPolygonAlpha]));\n    res.set('shift+p', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [0, 0, 1, defaultPolygonAlpha]));\n    res.set('p+x', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [1, 0, 0, defaultPolygonAlpha]));\n    res.set('p+y', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [0, 1, 0, defaultPolygonAlpha]));\n    res.set('p+z', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [0, 0, 1, defaultPolygonAlpha]));\n    res.set('p+x+y', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [1, 1, 0, defaultPolygonAlpha]));\n    res.set('p+x+z', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [1, 0, 1, defaultPolygonAlpha]));\n    res.set('p+y+z', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [0, 1, 1, defaultPolygonAlpha]));\n    res.set('p+x+y+z', preview => editorState.writeGateToFocus(preview, GATE_MAP.get(\"POLYGON\"), [1, 1, 1, defaultPolygonAlpha]));\n    res.set('m+p+x', preview => editorState.writeGateToFocus(preview, make_mpp_gate(\"X\".repeat(editorState.focusedSet.size)), []));\n    res.set('m+p+y', preview => editorState.writeGateToFocus(preview, make_mpp_gate(\"Y\".repeat(editorState.focusedSet.size)), []));\n    res.set('m+p+z', preview => editorState.writeGateToFocus(preview, make_mpp_gate(\"Z\".repeat(editorState.focusedSet.size)), []));\n    res.set('f', preview => editorState.flipTwoQubitGateOrderAtFocus(preview));\n    res.set('g', preview => editorState.reverseLayerOrderFromFocusToEmptyLayer(preview));\n    res.set('shift+>', preview => editorState.applyCoordinateTransform((x, y) => [x + 1, y], preview, false));\n    res.set('shift+<', preview => editorState.applyCoordinateTransform((x, y) => [x - 1, y], preview, false));\n    res.set('shift+v', preview => editorState.applyCoordinateTransform((x, y) => [x, y + 1], preview, false));\n    res.set('shift+^', preview => editorState.applyCoordinateTransform((x, y) => [x, y - 1], preview, false));\n    res.set('>', preview => editorState.applyCoordinateTransform((x, y) => [x + 1, y], preview, false));\n    res.set('<', preview => editorState.applyCoordinateTransform((x, y) => [x - 1, y], preview, false));\n    res.set('v', preview => editorState.applyCoordinateTransform((x, y) => [x, y + 1], preview, false));\n    res.set('^', preview => editorState.applyCoordinateTransform((x, y) => [x, y - 1], preview, false));\n    res.set('.', preview => editorState.applyCoordinateTransform((x, y) => [x + 0.5, y + 0.5], preview, false));\n\n    /**\n     * @param {!Array<!string>} chords\n     * @param {!string} name\n     * @param {undefined|!string=}inverse_name\n     */\n    function addGateChords(chords, name, inverse_name=undefined) {\n        for (let chord of chords) {\n            if (res.has(chord)) {\n                throw new Error(\"Chord collision: \" + chord);\n            }\n            res.set(chord, preview => editorState.writeGateToFocus(preview, GATE_MAP.get(name)));\n        }\n        if (inverse_name !== undefined) {\n            addGateChords(chords.map(e => 'shift+' + e), inverse_name);\n        }\n    }\n\n    addGateChords(['h', 'h+y', 'h+x+z'], \"H\", \"H\");\n    addGateChords(['h+z', 'h+x+y'], \"H_XY\", \"H_XY\");\n    addGateChords(['h+x', 'h+y+z'], \"H_YZ\", \"H_YZ\");\n    addGateChords(['s+x', 's+y+z'], \"SQRT_X\", \"SQRT_X_DAG\");\n    addGateChords(['s+y', 's+x+z'], \"SQRT_Y\", \"SQRT_Y_DAG\");\n    addGateChords(['s', 's+z', 's+x+y'], \"S\", \"S_DAG\");\n    addGateChords(['r+x', 'r+y+z'], \"RX\");\n    addGateChords(['r+y', 'r+x+z'], \"RY\");\n    addGateChords(['r', 'r+z', 'r+x+y'], \"R\");\n    addGateChords(['m+x', 'm+y+z'], \"MX\");\n    addGateChords(['m+y', 'm+x+z'], \"MY\");\n    addGateChords(['m', 'm+z', 'm+x+y'], \"M\");\n    addGateChords(['m+r+x', 'm+r+y+z'], \"MRX\");\n    addGateChords(['m+r+y', 'm+r+x+z'], \"MRY\");\n    addGateChords(['m+r', 'm+r+z', 'm+r+x+y'], \"MR\");\n    addGateChords(['c'], \"CX\", \"CX\");\n    addGateChords(['c+x'], \"CX\", \"CX\");\n    addGateChords(['c+y'], \"CY\", \"CY\");\n    addGateChords(['c+z'], \"CZ\", \"CZ\");\n    addGateChords(['j+x'], \"X\", \"X\");\n    addGateChords(['j+y'], \"Y\", \"Y\");\n    addGateChords(['j+z'], \"Z\", \"Z\");\n    addGateChords(['c+x+y'], \"XCY\", \"XCY\");\n    addGateChords(['alt+c+x'], \"XCX\", \"XCX\");\n    addGateChords(['alt+c+y'], \"YCY\", \"YCY\");\n\n    addGateChords(['w'], \"SWAP\", \"SWAP\");\n    addGateChords(['w+x'], \"CXSWAP\", undefined);\n    addGateChords(['c+w+x'], \"CXSWAP\", undefined);\n    addGateChords(['i+w'], \"ISWAP\", \"ISWAP_DAG\");\n    addGateChords(['w+z'], \"CZSWAP\", undefined);\n    addGateChords(['c+w+z'], \"CZSWAP\", undefined);\n    addGateChords(['c+w'], \"CZSWAP\", undefined);\n\n    addGateChords(['c+t'], \"C_XYZ\", \"C_ZYX\");\n    addGateChords(['c+s+x'], \"SQRT_XX\", \"SQRT_XX_DAG\");\n    addGateChords(['c+s+y'], \"SQRT_YY\", \"SQRT_YY_DAG\");\n    addGateChords(['c+s+z'], \"SQRT_ZZ\", \"SQRT_ZZ_DAG\");\n    addGateChords(['c+s'], \"SQRT_ZZ\", \"SQRT_ZZ_DAG\");\n\n    addGateChords(['c+m+x'], \"MXX\", \"MXX\");\n    addGateChords(['c+m+y'], \"MYY\", \"MYY\");\n    addGateChords(['c+m+z'], \"MZZ\", \"MZZ\");\n    addGateChords(['c+m'], \"MZZ\", \"MZZ\");\n\n    return res;\n}\n\nlet fallbackEmulatedClipboard = undefined;\nasync function copyToClipboard() {\n    let c = editorState.copyOfCurCircuit();\n    c.layers = [c.layers[editorState.curLayer]]\n    if (editorState.focusedSet.size > 0) {\n        c.layers[0] = c.layers[0].id_filteredByQubit(q => {\n            let x = c.qubitCoordData[q * 2];\n            let y = c.qubitCoordData[q * 2 + 1];\n            return editorState.focusedSet.has(`${x},${y}`);\n        });\n        let [x, y] = minXY(editorState.focusedSet.values());\n        c = c.shifted(-x, -y);\n    }\n\n    let content = c.toStimCircuit()\n    fallbackEmulatedClipboard = content;\n    try {\n        await navigator.clipboard.writeText(content);\n    } catch (ex) {\n        console.warn(\"Failed to write to clipboard. Using fallback emulated clipboard.\", ex);\n    }\n}\n\n/**\n * @param {!boolean} preview\n */\nasync function pasteFromClipboard(preview) {\n    let text;\n    try {\n        text = await navigator.clipboard.readText();\n    } catch (ex) {\n        console.warn(\"Failed to read from clipboard. Using fallback emulated clipboard.\", ex);\n        text = fallbackEmulatedClipboard;\n    }\n    if (text === undefined) {\n        return;\n    }\n\n    let pastedCircuit = Circuit.fromStimCircuit(text);\n    if (pastedCircuit.layers.length !== 1) {\n        throw new Error(text);\n    }\n    let newCircuit = editorState.copyOfCurCircuit();\n    if (editorState.focusedSet.size > 0) {\n        let [x, y] = minXY(editorState.focusedSet.values());\n        pastedCircuit = pastedCircuit.shifted(x, y);\n    }\n\n    // Include new coordinates.\n    let usedCoords = [];\n    for (let q = 0; q < pastedCircuit.qubitCoordData.length; q += 2) {\n        usedCoords.push([pastedCircuit.qubitCoordData[q], pastedCircuit.qubitCoordData[q + 1]]);\n    }\n    newCircuit = newCircuit.withCoordsIncluded(usedCoords);\n    let c2q = newCircuit.coordToQubitMap();\n\n    // Remove existing content at paste location.\n    for (let key of editorState.focusedSet.keys()) {\n        let q = c2q.get(key);\n        if (q !== undefined) {\n            newCircuit.layers[editorState.curLayer].id_pop_at(q);\n        }\n    }\n\n    // Add content to paste location.\n    for (let op of pastedCircuit.layers[0].iter_gates_and_markers()) {\n        let newTargets = [];\n        for (let q of op.id_targets) {\n            let x = pastedCircuit.qubitCoordData[2*q];\n            let y = pastedCircuit.qubitCoordData[2*q+1];\n            newTargets.push(c2q.get(`${x},${y}`));\n        }\n        newCircuit.layers[editorState.curLayer].put(new Operation(\n            op.gate,\n            op.tag,\n            op.args,\n            new Uint32Array(newTargets),\n        ));\n    }\n\n    editorState.commit_or_preview(newCircuit, preview);\n}\n\nconst CHORD_HANDLERS = makeChordHandlers();\n/**\n * @param {!KeyboardEvent} ev\n */\nfunction handleKeyboardEvent(ev) {\n    editorState.chorder.handleKeyEvent(ev);\n    if (ev.type === 'keydown') {\n        if (ev.key.toLowerCase() === 'q') {\n            let d = ev.shiftKey ? 5 : 1;\n            editorState.changeCurLayerTo(editorState.curLayer - d);\n            return;\n        }\n        if (ev.key.toLowerCase() === 'e') {\n            let d = ev.shiftKey ? 5 : 1;\n            editorState.changeCurLayerTo(editorState.curLayer + d);\n            return;\n        }\n        if (ev.key === 'Home') {\n            editorState.changeCurLayerTo(0);\n            ev.preventDefault();\n            return;\n        }\n        if (ev.key === 'End') {\n            editorState.changeCurLayerTo(editorState.copyOfCurCircuit().layers.length - 1);\n            ev.preventDefault();\n            return;\n        }\n    }\n    let evs = editorState.chorder.queuedEvents;\n    if (evs.length === 0) {\n        return;\n    }\n    let chord_ev = evs[evs.length - 1];\n    while (evs.length > 0) {\n        evs.pop();\n    }\n\n    let pressed = [...chord_ev.chord];\n    if (pressed.length === 0) {\n        return;\n    }\n    pressed.sort();\n    let key = '';\n    if (chord_ev.altKey) {\n        key += 'alt+';\n    }\n    if (chord_ev.ctrlKey) {\n        key += 'ctrl+';\n    }\n    if (chord_ev.metaKey) {\n        key += 'meta+';\n    }\n    if (chord_ev.shiftKey) {\n        key += 'shift+';\n    }\n    for (let e of pressed) {\n        key += `${e}+`;\n    }\n    key = key.substring(0, key.length - 1);\n\n    let handler = CHORD_HANDLERS.get(key);\n    if (handler !== undefined) {\n        handler(chord_ev.inProgress);\n        ev.preventDefault();\n    } else {\n        editorState.preview(editorState.copyOfCurCircuit());\n    }\n}\n\ndocument.addEventListener('keydown', handleKeyboardEvent);\ndocument.addEventListener('keyup', handleKeyboardEvent);\n\neditorState.canvas.width = editorState.canvas.scrollWidth;\neditorState.canvas.height = editorState.canvas.scrollHeight;\neditorState.rev.changes().subscribe(() => {\n    editorState.obs_val_draw_state.set(editorState.toSnapshot(undefined));\n    drawToolbox(editorState.chorder.toEvent(false));\n});\ninitUrlCircuitSync(editorState.rev);\neditorState.obs_val_draw_state.observable().subscribe(ds => requestAnimationFrame(() => draw(editorState.canvas.getContext('2d'), ds)));\nwindow.addEventListener('focus', () => {\n    editorState.chorder.handleFocusChanged();\n});\nwindow.addEventListener('blur', () => {\n    editorState.chorder.handleFocusChanged();\n});\n\n// Intercept clicks on the example circuit links, and load them without actually reloading the page, to preserve undo history.\nfor (let anchor of document.getElementById('examples-div').querySelectorAll('a')) {\n    anchor.onclick = ev => {\n        // Don't stop the user from e.g. opening the example in a new tab using ctrl+click.\n        if (ev.shiftKey || ev.ctrlKey || ev.altKey || ev.button !== 0) {\n            return undefined;\n        }\n        let circuitText = anchor.href.split('#circuit=')[1];\n\n        editorState.rev.commit(circuitText);\n        return false;\n    };\n}\n"
  },
  {
    "path": "glue/crumble/package.json",
    "content": "{\n  \"type\": \"module\"\n}\n"
  },
  {
    "path": "glue/crumble/run_tests_headless.js",
    "content": "import {run_tests} from \"./test/test_util.js\"\nimport \"./test/test_import_all.js\"\n\nlet total = await run_tests(() => {}, _name => true);\nif (!total.passed) {\n    throw new Error(\"Some tests failed\");\n}\n"
  },
  {
    "path": "glue/crumble/test/generated_gate_name_list.test.js",
    "content": "const KNOWN_GATE_NAMES_FROM_STIM = `\nI\nX\nY\nZ\nC_NXYZ\nC_NZYX\nC_XNYZ\nC_XYNZ\nC_XYZ\nC_ZNYX\nC_ZYNX\nC_ZYX\nH\nH_NXY\nH_NXZ\nH_NYZ\nH_XY\nH_XZ\nH_YZ\nS\nSQRT_X\nSQRT_X_DAG\nSQRT_Y\nSQRT_Y_DAG\nSQRT_Z\nSQRT_Z_DAG\nS_DAG\nCNOT\nCX\nCXSWAP\nCY\nCZ\nCZSWAP\nII\nISWAP\nISWAP_DAG\nSQRT_XX\nSQRT_XX_DAG\nSQRT_YY\nSQRT_YY_DAG\nSQRT_ZZ\nSQRT_ZZ_DAG\nSWAP\nSWAPCX\nSWAPCZ\nXCX\nXCY\nXCZ\nYCX\nYCY\nYCZ\nZCX\nZCY\nZCZ\nCORRELATED_ERROR\nDEPOLARIZE1\nDEPOLARIZE2\nE\nELSE_CORRELATED_ERROR\nHERALDED_ERASE\nHERALDED_PAULI_CHANNEL_1\nII_ERROR\nI_ERROR\nPAULI_CHANNEL_1\nPAULI_CHANNEL_2\nX_ERROR\nY_ERROR\nZ_ERROR\nM\nMR\nMRX\nMRY\nMRZ\nMX\nMY\nMZ\nR\nRX\nRY\nRZ\nMXX\nMYY\nMZZ\nMPP\nSPP\nSPP_DAG\nREPEAT\nDETECTOR\nMPAD\nOBSERVABLE_INCLUDE\nQUBIT_COORDS\nSHIFT_COORDS\nTICK\n`\n\nexport {KNOWN_GATE_NAMES_FROM_STIM};\n"
  },
  {
    "path": "glue/crumble/test/test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Test Crumble</title>\n    <link rel=\"shortcut icon\" href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABgWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kTlIA0EUhj+j4kHEwhQiFluolQFREUuNgggRQlTwKtzdnJBdw27ExlKwDVh4NF6FjbW2FraCIHiAWFpZKdpIWN8kgQQxDgzz8c/8j/f+Ad9RxrTchgGw7JwTnQppC4tLWtMrrfiAAC266WbHI5EwNdfXPXXqvAuqWrXf/bnaYnHXhDpNeMzMOjnhVeGRjVxW8Z7qwkzpMeFz4X5HGhR+VLpR4jfFySKrpgk4c9EJ4YCwlqxio4rNlGMJDwv3xCxb6vsWShxTvKnYyqyb5T7VhP64PT+rdNndTDHNDBE0DNZJkyFHUE5bFJeo3Idq+LuK/oi4DHGlMcUxyRoWetGP+oPf2bqJocFSJX8IGl8876MXmnagkPe872PPK5xA/TNc2RX/2hGMfoqer2g9h9C+BRfXFc3Yhctt6HzK6o5elOpl+xIJeD+Tb1qEjltoXS7lVr7n9AHmJKvwDewfQF9Saq/UmLu5Ord/35Tz+wHVp3JoxsjWZAAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+YKAhYQLxXIct8AAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAx0lEQVRYw+2XwQ7EIAhEB+N/E76cnkgIa6OuWTFxvTWxdRgKDwmAYu+i+KDKPP62CJjHNYsQ7Psk8iGk7AxdmeGC1e0CvBBbKQK8ljQB5kK2AxcLsJLMdoBKZvQAULMOtk5IR7Dg294+yw4RymUBs3qQ5bHAO34vC8yFPwvSBFhJ3skC35Bq1sHHsKDGKfUX94J46HllGDjd5XnI5WjOXwXQSg5X95eXaaU3zXSjG3XJ79LW1ak1RsX9/qdsldqsPTppo66k6QGRuElWZ7d4CQAAAABJRU5ErkJggg==\">\n</head>\n<body style=\"margin: 0\">\n    <div id=\"status\">Loading tests...</div>\n    <div id=\"acc\"></div>\n</body>\n</html>\n<script type=\"module\" src=\"test_main.js\"></script>\n"
  },
  {
    "path": "glue/crumble/test/test_import_all.js",
    "content": "import \"../base/describe.test.js\"\nimport \"../base/equate.test.js\"\nimport \"../base/obs.test.js\"\nimport \"../base/revision.test.js\"\nimport \"../base/seq.test.js\"\nimport \"../circuit/circuit.test.js\"\nimport \"../circuit/layer.test.js\"\nimport \"../circuit/pauli_frame.test.js\"\nimport \"../circuit/propagated_pauli_frames.test.js\"\nimport \"../draw/main_draw.test.js\"\nimport \"../editor/editor_state.test.js\"\nimport \"../gates/gateset.test.js\"\nimport \"../keyboard/chord.test.js\"\nimport \"../test/generated_gate_name_list.test.js\"\nimport \"../test/test_util.test.js\"\n"
  },
  {
    "path": "glue/crumble/test/test_main.js",
    "content": "import {run_tests, test, assertThat} from \"./test_util.js\"\n\nlet imported = import(\"./test_import_all.js\");\ntest(\"init\", () => assertThat(imported).asyncResolvesToAValueThat().isNotEqualTo(undefined));\nawait imported.catch(() => {});\n\nlet status = /** @type {!HTMLDivElement} */ document.getElementById(\"status\");\nlet acc = /** @type {!HTMLDivElement} */ document.getElementById(\"acc\");\n\nlet testFilter = undefined;\nlet hash = document.location.hash;\nif (hash.startsWith('#')) {\n    hash = hash.substring(1);\n}\nif (hash.startsWith('test=')) {\n    hash = hash.substring(5);\n    testFilter = hash;\n    console.log(`Only running '${testFilter}'`)\n}\n\nstatus.textContent = \"Running tests...\";\n\nlet total = await run_tests(progress => {\n    status.textContent = `${progress.num_tests_left - progress.num_tests}/${progress.num_tests} ${progress.name} ${progress.passed ? 'passed' : 'failed'} (${progress.num_tests_failed} failed)`;\n    if (!progress.passed) {\n        let d = document.createElement(\"div\");\n        d.textContent = `Test '${progress.name}' failed:`;\n        acc.appendChild(d);\n        let a = document.createElement(\"a\");\n        a.textContent = `(click here to only run this test)`;\n        a.style.marginLeft = '5px';\n        a.href = `#test=${progress.name}`;\n        d.appendChild(a);\n        acc.appendChild(d);\n\n        let p = document.createElement(\"pre\");\n        p.style.marginLeft = '40px';\n        p.style.backgroundColor = 'lightgray';\n        p.textContent = `${progress.error}`;\n        acc.appendChild(p);\n    } else if (progress.skipped) {\n        let d = document.createElement(\"pre\");\n        d.textContent = `Test '${progress.name}' skipped`;\n        acc.appendChild(d);\n    }\n}, name => testFilter === undefined || name === testFilter);\nif (!total.passed) {\n    if (total.num_skipped > 0) {\n        status.textContent = `${total.num_tests_failed} tests failed out of ${total.num_tests - total.num_skipped} (${total.num_skipped} skipped).`;\n    } else {\n        status.textContent = `${total.num_tests_failed} tests failed out of ${total.num_tests}.`;\n    }\n} else if (total.num_skipped > 0) {\n    status.textContent = `All ${total.num_tests} tests passed (${total.num_skipped} skipped).`;\n} else {\n    status.textContent = `All ${total.num_tests} tests passed.`;\n}\n"
  },
  {
    "path": "glue/crumble/test/test_util.js",
    "content": "import {describe} from \"../base/describe.js\";\nimport {equate} from \"../base/equate.js\";\n\nlet _tests = /** @type {!Array<!{name: !string, body: !function}>} */ [];\nlet _usedAssertIndices = 0;\nlet _unawaitedAsserts = 0;\n\n/**\n * @param {!string} name\n * @param {!function} body\n */\nfunction test(name, body) {\n    _tests.push({name, body});\n}\n\n/**\n * @param {!string} text\n * @param {!int} indentation\n * @param {!boolean} indent_first\n * @returns {!string}\n */\nfunction indent(text, indentation, indent_first=true) {\n    let lines = text.split('\\n');\n    let prefix = ' '.repeat(indentation);\n    for (let k = 0; k < lines.length; k++) {\n        let p = k > 0 || indent_first ? prefix : '';\n        lines[k] = p + lines[k];\n    }\n    return lines.join('\\n');\n}\n\n/**\n * @param {*} obj\n * @returns {!boolean}\n */\nfunction isSequence(obj) {\n    return obj instanceof Array || obj instanceof Uint32Array;\n}\n\n/**\n * @param {*} actual\n * @param {*} expected\n * @returns {!string}\n */\nfunction diff(actual, expected) {\n    let differences = [];\n    if (isSequence(actual) && isSequence(expected)) {\n        for (let k = 0; k < Math.max(actual.length, expected.length); k++) {\n            if (!equate(actual[k], expected[k])) {\n                differences.push(`${describe(k)}: ${diff(actual[k], expected[k])}`);\n            }\n        }\n    }\n    if ((actual instanceof Set || actual instanceof Map) && ((expected instanceof Set || expected instanceof Map))) {\n        for (let k of actual.keys()) {\n            if (!expected.has(k)) {\n                differences.push(`${describe(k)} missing from expected`);\n            }\n        }\n        for (let k of expected.keys()) {\n            if (!actual.has(k)) {\n                differences.push(`${describe(k)} missing from actual`);\n            }\n        }\n    }\n    if (actual instanceof Map && expected instanceof Map) {\n        for (let k of actual.keys()) {\n            if (expected.has(k)) {\n                let v1 = actual.get(k);\n                let v2 = expected.get(k);\n                if (!equate(v1, v2)) {\n                    differences.push(`${describe(k)}: ${diff(actual.get(k), expected.get(k))}`);\n                }\n            }\n        }\n    }\n    if (typeof actual === 'number' && typeof expected === 'number') {\n        differences.push(`${actual} != ${expected}`);\n    }\n    if (differences.length === 0) {\n        let lines1 = describe(actual).split('\\n');\n        let lines2 = describe(expected).split('\\n');\n        for (let k = 0; k < Math.max(lines1.length, lines2.length); k++) {\n            let line1 = lines1[k];\n            let line2 = lines2[k];\n            if ((line1 === undefined && line2 === '') || (line2 === undefined && line1 === '')) {\n                differences.push('▯');\n            } else if (line1 === undefined) {\n                differences.push('█'.repeat(line2.length));\n            } else if (line2 === undefined) {\n                differences.push('█'.repeat(line1.length));\n            } else {\n                let t = '';\n                for (let x = 0; x < Math.max(line1.length, line2.length); x++) {\n                    let c1 = line1[x];\n                    let c2 = line2[x];\n                    t += c1 === c2 ? c1 : '█';\n                }\n                differences.push(t);\n            }\n        }\n    }\n\n    return differences.map(e => indent(e, 4, false)).join('\\n');\n}\n\nclass AsyncAssertSubject {\n    /**\n     * @param {!Promise<!AssertSubject>} asyncSubject\n     */\n    constructor(asyncSubject) {\n        this.asyncSubject = asyncSubject;\n    }\n\n    /**\n     * @param {!string} info\n     * @returns {!AsyncAssertSubject}\n     */\n    withInfo(info) {\n        return new AsyncAssertSubject(this.asyncSubject.then(subject => subject.withInfo(info)));\n    }\n\n    /**\n     * @returns {!AsyncAssertSubject}\n     */\n    runsWithoutThrowingAnException() {\n        return new AsyncAssertSubject(this.asyncSubject.then(subject => subject.runsWithoutThrowingAnException()));\n    }\n\n    /**\n     * @returns {!AsyncAssertSubject}\n     */\n    resolvesToAValueThat() {\n        return new AsyncAssertSubject(this.asyncSubject.then(async subject => await subject.asyncResolvesToAValueThat()));\n    }\n\n    /**\n     * @returns {!AsyncAssertSubject}\n     */\n    rejectsWithAnExceptionThat() {\n        return new AsyncAssertSubject(this.asyncSubject.then(async subject => await subject.asyncRejectsWithAnExceptionThat()));\n    }\n\n    /**\n     * @returns {!AsyncAssertSubject}\n     */\n    throwsAnExceptionThat() {\n        return new AsyncAssertSubject(this.asyncSubject.then(subject => subject.throwsAnExceptionThat()));\n    }\n\n    /**\n     * @param {!RegExp} pattern\n     * @returns {!AsyncAssertSubject}\n     */\n    matches(pattern) {\n        return new AsyncAssertSubject(this.asyncSubject.then(subject => subject.matches(pattern)));\n    }\n\n    /**\n     * @param {*} expected\n     * @returns {!AsyncAssertSubject}\n     */\n    isEqualTo(expected) {\n        return new AsyncAssertSubject(this.asyncSubject.then(subject => subject.isEqualTo(expected)));\n    }\n\n    /**\n     * @param {*} unexpected\n     * @returns {!AsyncAssertSubject}\n     */\n    isNotEqualTo(unexpected) {\n        return new AsyncAssertSubject(this.asyncSubject.then(subject => subject.isNotEqualTo(unexpected)));\n    }\n\n    then(resolve, reject) {\n        this.asyncSubject.then(e => {\n            _unawaitedAsserts -= 1;\n            resolve(e);\n        }, ex => {\n            _unawaitedAsserts -= 1;\n            reject(ex);\n        });\n    }\n}\n\nclass AssertSubject {\n    /**\n     * @param {*} value\n     * @param {!int} index\n     * @param {!*} info\n     */\n    constructor(value, index, info) {\n        this.value = value;\n        this.index = index;\n        this.info = info;\n    }\n\n    /**\n     * @param {!*} info\n     * @returns {!AssertSubject}\n     */\n    withInfo(info) {\n        return new AssertSubject(this.value, this.index, info);\n    }\n\n    /**\n     * @returns {!string}\n     * @private\n     */\n    _trace() {\n        try {\n            throw new Error('');\n        } catch (ex) {\n            let lines = `${ex.stack}`.split('\\n');\n            return 'Stack trace:\\n' + lines.slice(3).join('\\n')\n        }\n    }\n\n    /**\n     * @returns {!string}\n     * @private\n     */\n    _whichAssertion() {\n        if (this.info === undefined) {\n            return `Assertion #${this.index}`;\n        }\n        return `Assertion #${this.index} with info ${describe(this.info)}`;\n    }\n\n    runsWithoutThrowingAnException() {\n        try {\n            this.value();\n        } catch (ex) {\n            throw new Error(`${this._whichAssertion()} failed. Got an exception:\n\n${indent('' + ex, 4)}\n\nbut expected the following not to throw:\n\n${indent('' + this.value, 4)}\n\n`);\n        }\n    }\n\n    /**\n     * @returns {!AsyncAssertSubject}\n     */\n    asyncResolvesToAValueThat() {\n        _unawaitedAsserts += 1;\n        return new AsyncAssertSubject(\n            new Promise((resolve, reject) => {\n                this.value.then(v => resolve(new AssertSubject(v, this.index, this.info))).catch(\n                    ex => reject(new Error(`Promise should have resolved, but instead rejected with:\n\n${describe(ex)}\n`, {cause: ex})));\n            }));\n    }\n\n    /**\n     * @returns {!AsyncAssertSubject}\n     */\n    asyncRejectsWithAnExceptionThat() {\n        _unawaitedAsserts += 1;\n        return new AsyncAssertSubject(\n            new Promise((resolve, reject) => {\n                this.value.then(v => reject(new Error(`Promise should have rejected, but instead resolved to:\n\n${describe(v)}\n`))).catch(ex => resolve(new AssertSubject(ex, this.index, this.info)));\n            }));\n    }\n\n    /**\n     * @returns {!AssertSubject}\n     */\n    throwsAnExceptionThat() {\n        try {\n            this.value();\n        } catch (ex) {\n            return new AssertSubject(ex, this.index, this.info);\n        }\n        throw new Error(`${this._whichAssertion()} failed. Expected the following to throw an exception:\n\n${indent('' + this.value, 4)}\n`);\n    }\n\n    /**\n     * @param {!RegExp} pattern\n     * @returns void\n     */\n    matches(pattern) {\n        if (!pattern.test('' + this.value)) {\n        throw new Error(`${this._whichAssertion()} failed. Expected the following to match:\n\nActual value {\n${indent(describe(this.value), 4)}\n}\n\nExpected pattern {\n    ${pattern}\n}\n`);\n        }\n    }\n\n    /**\n     * @param {*} expected\n     * @returns void\n     */\n    isEqualTo(expected) {\n        if (!equate(this.value, expected)) {\n            let s1 = describe(this.value);\n            let s2 = describe(expected);\n            throw new Error(`${this._whichAssertion()} failed. Expected the following objects to be equal.\n${s1 === s2 ? 'WARNING! Objects not equal but strings equal!' : ''}\nActual value {\n${indent(s1, 4)}\n}\n\nExpected value {\n${indent(s2, 4)}\n}\n\nDifferences {\n${indent(diff(this.value, expected), 4)}\n}\n\n${this._trace()}\n`);\n        }\n    }\n\n    /**\n     * @param {*} unexpected\n     * @returns void\n     */\n    isNotEqualTo(unexpected) {\n        if (equate(this.value, unexpected)) {\n            let s1 = describe(this.value);\n            let s2 = describe(unexpected);\n            throw new Error(`${this._whichAssertion()} failed. Expected the following objects to NOT be equal.\n\nActual value {\n${indent(s1, 4)}\n}\n\nExpected different value {\n${indent(s2, 4)}\n}\n`);\n        }\n    }\n}\n\n/**\n * @param {*} value\n * @returns {!AssertSubject}\n */\nfunction assertThat(value) {\n    _usedAssertIndices++;\n    return new AssertSubject(value, _usedAssertIndices, undefined);\n}\n\nfunction skipRestOfTestIfHeadless() {\n    try {\n        // Actually, even attempting to read the variable will raise an error.\n        if (document === undefined) {\n            throw new Error();\n        }\n    } catch (_) {\n        throw new Error(\"skipRestOfTestIfHeadless:document === undefined\");\n    }\n}\n\nclass TestProgress {\n    /**\n     * @param {!string} name\n     * @param {!boolean} passed\n     * @param {*} error\n     * @param {!int} num_tests\n     * @param {!int} num_tests_failed\n     * @param {!int} num_tests_left\n     * @param {!int} num_skipped\n     */\n    constructor(name, passed, error, num_tests, num_tests_failed, num_tests_left, num_skipped) {\n        this.name = name;\n        this.passed = passed;\n        this.error = error;\n        this.num_tests = num_tests;\n        this.num_tests_failed = num_tests_failed;\n        this.num_tests_left = num_tests_left;\n        this.num_skipped = num_skipped;\n    }\n}\n\n/**\n * @param {!function(progress: !TestProgress)} callback\n * @param {!function(name: !string): !boolean} name_filter\n */\nasync function run_tests(callback, name_filter) {\n    let num_tests = _tests.length;\n    let num_tests_left = _tests.length;\n    let num_tests_failed = 0;\n    let all_passed = true;\n    let num_skipped = 0;\n    for (let test of _tests) {\n        if (!name_filter(test.name)) {\n            num_skipped += 1;\n            continue;\n        }\n        console.log(\"run test\", test.name);\n        _usedAssertIndices = 0;\n        let name = test.name;\n        let passed = false;\n        let error = undefined;\n        let skipped = false;\n        try {\n            await test.body();\n            if (_usedAssertIndices === 0) {\n                throw new Error(\"No assertions in test.\");\n            }\n            if (_unawaitedAsserts > 0) {\n                throw new Error(\"An async assertion wasn't awaited.\");\n            }\n            passed = true;\n        } catch (ex) {\n            if (ex instanceof Error && ex.message === \"skipRestOfTestIfHeadless:document === undefined\") {\n                console.warn(`skipped part of test '${test.name}' because tests are running headless`);\n                skipped = true;\n                num_skipped += 1;\n                passed = true;\n            } else {\n                error = ex;\n                all_passed = false;\n                num_tests_failed++;\n                console.error(\"failed test\", test.name, ex);\n            }\n        }\n        num_tests_left--;\n        callback(new TestProgress(name, passed, error, num_tests, num_tests_failed, num_tests_left, num_skipped));\n    }\n\n    let msg = `done running tests: ${num_tests_failed} failed, ${num_skipped} skipped`;\n    if (num_tests_failed > 0) {\n        console.error(msg);\n    } else if (num_skipped > 0) {\n        console.warn(msg);\n    } else {\n        console.log(msg);\n    }\n    return new TestProgress('', all_passed, undefined, num_tests, num_tests_failed, 0, num_skipped);\n}\n\nexport {test, run_tests, assertThat, skipRestOfTestIfHeadless}\n"
  },
  {
    "path": "glue/crumble/test/test_util.test.js",
    "content": "import {test, assertThat} from \"./test_util.js\";\n\nfunction expectFailure(func, match) {\n    try {\n        func();\n    } catch (ex) {\n        if (match.test('' + ex)) {\n            return;\n        }\n        throw new Error('message \"' + ex + '\" does not match ' + match, {cause: ex});\n    }\n    throw new Error('Expected an exception matching ' + match);\n}\n\n/**\n * @param {!function(): void} func\n * @param {!RegExp} match\n */\nasync function asyncExpectFailure(func, match) {\n    try {\n        await func();\n    } catch (ex) {\n        if (match.test('' + ex)) {\n            return;\n        }\n        throw new Error('message \"' + ex + '\" does not match ' + match, {cause: ex});\n    }\n    throw new Error('Expected an exception matching ' + match);\n}\n\ntest(\"test_util.throws\", () => {\n    assertThat(() => {\n        throw new Error('test');\n    }).throwsAnExceptionThat().matches(/test/);\n\n    let a = 1;\n    assertThat(() => {\n        a += 1;\n    }).runsWithoutThrowingAnException();\n    assertThat(a).isEqualTo(2);\n\n    expectFailure(() => {\n        assertThat(() => {\n            throw new Error('XYZ');\n        }).runsWithoutThrowingAnException();\n    }, /expected the following not to throw:/);\n\n    expectFailure(() => {\n        assertThat(() => {\n        }).throwsAnExceptionThat();\n    }, /Expected the following to throw/);\n\n    expectFailure(() => {\n        assertThat(() => {\n            throw new Error('xyz')\n        }).throwsAnExceptionThat().matches(/XYZ/);\n    }, /Expected the following to match/);\n});\n\ntest(\"test_util.isEqualTo\", () => {\n    assertThat(undefined).isEqualTo(undefined);\n    assertThat(null).isEqualTo(null);\n    assertThat(\"1\").isEqualTo(\"1\");\n    assertThat(1).isEqualTo(1);\n    assertThat(\"1\").isNotEqualTo(1);\n    assertThat([1, 2, 3]).isEqualTo([1, 2, 3]);\n    assertThat([1, 2, 3]).isNotEqualTo([1, 2, 4]);\n    assertThat(new Set([1, 2, 3])).isEqualTo(new Set([1, 2, 3]));\n    assertThat(new Set([1, 2, 3])).isNotEqualTo(new Set([1, 2, 4]));\n    assertThat(new Set([1, 2, 3])).isNotEqualTo(new Set([1, 2]));\n    assertThat(new Set([1, 2, 3])).isNotEqualTo(new Set([1, 2, 3, 4]));\n    assertThat(new Map([[1, 2], [3, 4]])).isEqualTo(new Map([[1, 2], [3, 4]]));\n    assertThat(new Map([[1, 2], [3, 4]])).isNotEqualTo(new Map([[1, 2], [3, 5]]));\n    assertThat(new Map([[1, 2], [3, 4]])).isNotEqualTo(new Map([[1, 2]]));\n    assertThat(new Map([[1, 2], [3, 4]])).isNotEqualTo(new Map([[1, 2], [3, 4], [5, 6]]));\n\n    expectFailure(() => {\n        assertThat(undefined).isNotEqualTo(undefined);\n    }, /Expected the following objects to NOT be equal/);\n    expectFailure(() => {\n        assertThat(\"1\").isEqualTo(1);\n    }, /Expected the following objects to be equal/);\n});\n\ntest(\"test_util.async\", async () => {\n    let e = (async () => 5)();\n    let ex = (async () => {\n        throw new Error(\"test\");\n    })();\n    await assertThat(e).asyncResolvesToAValueThat().isEqualTo(5);\n    await assertThat(ex).asyncRejectsWithAnExceptionThat().matches(/test/);\n\n    expectFailure(() => {\n        assertThat(e).isEqualTo(5);\n    }, /to be equal/);\n    await asyncExpectFailure(async () => {\n        await assertThat(e).asyncRejectsWithAnExceptionThat();\n    }, /should have rejected/);\n    await asyncExpectFailure(async () => {\n        await assertThat(e).asyncResolvesToAValueThat().isEqualTo(6);\n    }, /to be equal/);\n\n    expectFailure(() => {\n        assertThat(ex).isEqualTo(5);\n    }, /to be equal/);\n    await asyncExpectFailure(async () => {\n        await assertThat(ex).asyncResolvesToAValueThat();\n    }, /should have resolved/);\n    await asyncExpectFailure(async () => {\n        await assertThat(ex).asyncRejectsWithAnExceptionThat().matches(/bla/);\n    }, /test/);\n});\n"
  },
  {
    "path": "glue/javascript/README.md",
    "content": "# Stim in Javascript\n\nThis directory contains glue code for exposing stim to javascript.\n\nFor build instructions, see [the \"build javascript bindings\" sections of the dev documentation](/dev/README.md#build-javascript-bindings).\n\n## Exposed API\n\n```\nstim.Circuit\n    static stim.Circuit.<constructor>\n    stim.Circuit.append_operation\n    stim.Circuit.append_from_stim_program_text\n    stim.Circuit.copy\n    stim.Circuit.isEqualTo\n    stim.Circuit.repeated\n    stim.Circuit.toString\n\nstim.Tableau\n    static stim.Tableau.<constructor>\n    static stim.Tableau.random\n    static stim.Tableau.from_named_gate\n    static stim.Tableau.from_conjugated_generators_xs_zs\n    stim.Tableau.x_output\n    stim.Tableau.y_output\n    stim.Tableau.z_output\n    stim.Tableau.toString\n    stim.Tableau.isEqualTo\n    stim.Tableau.length\n\nstim.TableauSimulator\n    static stim.TableauSimulator.<constructor>\n    stim.TableauSimulator.CNOT\n    stim.TableauSimulator.CY\n    stim.TableauSimulator.CZ\n    stim.TableauSimulator.H\n    stim.TableauSimulator.X\n    stim.TableauSimulator.Y\n    stim.TableauSimulator.Z\n    stim.TableauSimulator.copy\n    stim.TableauSimulator.current_inverse_tableau\n    stim.TableauSimulator.do_circuit\n    stim.TableauSimulator.do_pauli_string\n    stim.TableauSimulator.do_tableau\n    stim.TableauSimulator.measure\n    stim.TableauSimulator.measure_kickback\n    stim.TableauSimulator.set_inverse_tableau\n\nstim.PauliString\n    static stim.PauliString.<constructor>\n    static stim.PauliString.random\n    stim.PauliString.commutes\n    stim.PauliString.isEqualTo\n    stim.PauliString.length\n    stim.PauliString.neg\n    stim.PauliString.pauli\n    stim.PauliString.sign\n    stim.PauliString.times\n    stim.PauliString.toString\n```\n"
  },
  {
    "path": "glue/javascript/build_wasm.sh",
    "content": "#!/bin/bash\nset -e\n\n# Get to this script's git repo root.\ncd \"$( dirname \"${BASH_SOURCE[0]}\" )\"\ncd \"$(git rev-parse --show-toplevel)\"\n\n# Find relevant source files using naming conventions.\nreadarray -t stim_src_files < <( \\\n    find src \\\n    | grep \"\\\\.cc\" \\\n    | grep -v \"\\\\.\\(test\\|perf\\|pybind\\)\\\\.cc\" \\\n    | grep -v \"main\\\\.cc\" \\\n)\nreadarray -t glue_src_files < <( \\\n    find glue/javascript \\\n    | grep \"\\\\.js\\\\.cc\" \\\n)\nreadarray -t js_test_files < <( \\\n    find glue/javascript \\\n    | grep \"\\\\.test\\\\.js\" \\\n)\n\nmkdir -p out\necho '<script src=\"stim.js\"></script>' > out/all_stim_tests.html\necho '<script type=\"text/javascript\">' >> out/all_stim_tests.html\ncat \"glue/javascript/stim.test_harness.js\" \"${js_test_files[@]}\" >> out/all_stim_tests.html\necho '</script>' >> out/all_stim_tests.html\n\n# Build web assembly module using emscripten.\nemcc \\\n    -std=c++20 \\\n    -s NO_DISABLE_EXCEPTION_CATCHING \\\n    -s EXPORT_NAME=\"load_stim_module\"  \\\n    -s MODULARIZE=1  \\\n    -s SINGLE_FILE=1  \\\n    -o out/stim.js \\\n    --no-entry \\\n    --bind \\\n    -I src \\\n    \"${glue_src_files[@]}\" \\\n    \"${stim_src_files[@]}\"\n"
  },
  {
    "path": "glue/javascript/circuit.js.cc",
    "content": "#include \"circuit.js.h\"\n\n#include <emscripten/bind.h>\n#include <emscripten/val.h>\n\nusing namespace stim;\n\nExposedCircuit::ExposedCircuit() : circuit() {\n}\n\nExposedCircuit::ExposedCircuit(Circuit circuit) : circuit(circuit) {\n}\n\nExposedCircuit::ExposedCircuit(const std::string &text) : circuit(Circuit(text)) {\n}\n\nvoid ExposedCircuit::append_operation(\n    const std::string &name, const emscripten::val &targets, const emscripten::val &args) {\n    circuit.safe_append_u(\n        name,\n        emscripten::convertJSArrayToNumberVector<uint32_t>(targets),\n        emscripten::convertJSArrayToNumberVector<double>(args));\n}\n\nvoid ExposedCircuit::append_from_stim_program_text(const std::string &text) {\n    circuit.append_from_text(text);\n}\n\nExposedCircuit ExposedCircuit::repeated(size_t repetitions) const {\n    return ExposedCircuit(circuit * repetitions);\n}\n\nExposedCircuit ExposedCircuit::copy() const {\n    return ExposedCircuit(circuit);\n}\n\nstd::string ExposedCircuit::toString() const {\n    return circuit.str();\n}\n\nbool ExposedCircuit::isEqualTo(const ExposedCircuit &other) const {\n    return circuit == other.circuit;\n}\n\nvoid emscripten_bind_circuit() {\n    auto c = emscripten::class_<ExposedCircuit>(\"Circuit\");\n    c.constructor();\n    c.constructor<const std::string &>();\n    c.function(\"toString\", &ExposedCircuit::toString);\n    c.function(\"repeated\", &ExposedCircuit::repeated);\n    c.function(\"copy\", &ExposedCircuit::copy);\n    c.function(\"append_operation\", &ExposedCircuit::append_operation);\n    c.function(\"append_from_stim_program_text\", &ExposedCircuit::append_from_stim_program_text);\n    c.function(\"isEqualTo\", &ExposedCircuit::isEqualTo);\n}\n"
  },
  {
    "path": "glue/javascript/circuit.js.h",
    "content": "#ifndef STIM_CIRCUIT_JS_H\n#define STIM_CIRCUIT_JS_H\n\n#include <cstddef>\n#include <cstdint>\n#include <emscripten/val.h>\n\n#include \"stim/circuit/circuit.h\"\n\nstruct ExposedCircuit {\n    stim::Circuit circuit;\n    ExposedCircuit();\n    explicit ExposedCircuit(stim::Circuit circuit);\n    explicit ExposedCircuit(const std::string &text);\n    void append_operation(const std::string &name, const emscripten::val &targets, const emscripten::val &args);\n    void append_from_stim_program_text(const std::string &text);\n    ExposedCircuit repeated(size_t repetitions) const;\n    ExposedCircuit copy() const;\n    bool isEqualTo(const ExposedCircuit &other) const;\n    std::string toString() const;\n};\n\nvoid emscripten_bind_circuit();\n\n#endif\n"
  },
  {
    "path": "glue/javascript/circuit.test.js",
    "content": "test(\"circuit.constructor\", ({stim, assert}) => {\n    let c = new stim.Circuit();\n    assert(c.toString() === '');\n\n    c = new stim.Circuit('H 0\\n   H 1  # comment');\n    assert(c.toString() === 'H 0 1');\n});\n\ntest(\"circuit.repeated\", ({stim, assert}) => {\n    let c = new stim.Circuit('H 0\\nCNOT 0 1');\n    assert(c.repeated(0).isEqualTo(new stim.Circuit()));\n    assert(c.repeated(1).isEqualTo(c));\n    assert(!c.repeated(5).isEqualTo(c));\n\n    assert(c.repeated(5).toString().trim() === `\nREPEAT 5 {\n    H 0\n    CX 0 1\n}\n    `.trim());\n});\n\ntest(\"circuit.copy\", ({stim, assert}) => {\n    let c = new stim.Circuit(`\n        REPEAT 2 {\n            H 0\n            CNOT 0 1\n        }\n    `);\n    let c2 = c.copy();\n    assert(c.isEqualTo(c2));\n    c.append_operation(\"X\", [0], []);\n    assert(!c.isEqualTo(c2));\n});\n\ntest(\"circuit.append_operation\", ({stim, assert}) => {\n    let c = new stim.Circuit();\n    c.append_operation(\"H\", [0, 1], []);\n    c.append_operation(\"X_ERROR\", [0, 1, 2], [0.25]);\n    assert(c.toString().trim() === `\nH 0 1\nX_ERROR(0.25) 0 1 2\n    `.trim());\n});\n\ntest(\"circuit.append_from_stim_program_text\", ({stim, assert}) => {\n    let c = new stim.Circuit();\n    let c2 = new stim.Circuit(\"H 0\\nCNOT 0 1\");\n    c.append_from_stim_program_text(\"H 0\\nCNOT 0 1\");\n    assert(c.isEqualTo(c2));\n});\n\ntest(\"circuit.isEqualTo\", ({stim, assert}) => {\n    assert(new stim.Circuit().isEqualTo(new stim.Circuit()));\n    assert(new stim.Circuit('').isEqualTo(new stim.Circuit()));\n    assert(!new stim.Circuit('H 0').isEqualTo(new stim.Circuit()));\n    assert(!new stim.Circuit('H 0').isEqualTo(new stim.Circuit('X 0')));\n    assert(!new stim.Circuit('H 0').isEqualTo(new stim.Circuit('H 1')));\n    assert(new stim.Circuit('H 1').isEqualTo(new stim.Circuit('H 1')));\n    assert(!new stim.Circuit('H 1').isEqualTo(new stim.Circuit(`\n        REPEAT 1 {\n            H 1\n        }\n    `)));\n});\n"
  },
  {
    "path": "glue/javascript/common.js.cc",
    "content": "#include \"common.js.h\"\n\nusing namespace stim;\n\nuint32_t js_val_to_uint32_t(const emscripten::val &val) {\n    double v = val.as<double>();\n    double f = floor(v);\n    if (v != f || v < 0 || v > UINT32_MAX) {\n        throw std::out_of_range(\"Number isn't a uint32_t: \" + std::to_string(v));\n    }\n    return (uint32_t)f;\n}\n"
  },
  {
    "path": "glue/javascript/common.js.h",
    "content": "#ifndef STIM_COMMON_JS_H\n#define STIM_COMMON_JS_H\n\n#include <emscripten/val.h>\n\n#include \"stim/util_bot/probability_util.h\"\n\ntemplate <typename T>\nemscripten::val vec_to_js_array(const std::vector<T> &items) {\n    emscripten::val result = emscripten::val::array();\n    for (size_t k = 0; k < items.size(); k++) {\n        result.set(k, items[k]);\n    }\n    return result;\n}\n\nuint32_t js_val_to_uint32_t(const emscripten::val &val);\n\n#endif\n"
  },
  {
    "path": "glue/javascript/pauli_string.js.cc",
    "content": "#include \"pauli_string.js.h\"\n\n#include <emscripten/bind.h>\n\n#include \"common.js.h\"\n\nusing namespace stim;\n\nExposedPauliString::ExposedPauliString(PauliString<stim::MAX_BITWORD_WIDTH> pauli_string) : pauli_string(pauli_string) {\n}\n\nExposedPauliString::ExposedPauliString(const emscripten::val &arg) : pauli_string(0) {\n    std::string t = arg.typeOf().as<std::string>();\n    if (arg.isNumber()) {\n        pauli_string = PauliString<stim::MAX_BITWORD_WIDTH>(js_val_to_uint32_t(arg));\n    } else if (arg.isString()) {\n        pauli_string = PauliString<stim::MAX_BITWORD_WIDTH>::from_str(arg.as<std::string>());\n    } else {\n        throw std::invalid_argument(\"Expected an int or a string. Got \" + t);\n    }\n}\n\nExposedPauliString ExposedPauliString::random(size_t n) {\n    auto rng = externally_seeded_rng();\n    return ExposedPauliString(PauliString<stim::MAX_BITWORD_WIDTH>::random(n, rng));\n}\n\nExposedPauliString ExposedPauliString::times(const ExposedPauliString &other) const {\n    PauliString<stim::MAX_BITWORD_WIDTH> result = pauli_string;\n    uint8_t r = result.ref().inplace_right_mul_returning_log_i_scalar(other.pauli_string);\n    if (r & 1) {\n        throw std::invalid_argument(\"Multiplied non-commuting.\");\n    }\n    if (r & 2) {\n        result.sign ^= 1;\n    }\n    return ExposedPauliString(result);\n}\n\nExposedPauliString ExposedPauliString::neg() const {\n    PauliString<stim::MAX_BITWORD_WIDTH> result = pauli_string;\n    result.sign ^= 1;\n    return ExposedPauliString(result);\n}\n\nbool ExposedPauliString::isEqualTo(const ExposedPauliString &other) const {\n    return pauli_string == other.pauli_string;\n}\n\nbool ExposedPauliString::commutes(const ExposedPauliString &other) const {\n    return pauli_string.ref().commutes(other.pauli_string);\n}\n\nstd::string ExposedPauliString::toString() const {\n    return pauli_string.str();\n}\n\nuint8_t ExposedPauliString::pauli(size_t index) const {\n    if (index >= pauli_string.num_qubits) {\n        return 0;\n    }\n    uint8_t x = pauli_string.xs[index];\n    uint8_t z = pauli_string.zs[index];\n    return pauli_xz_to_xyz(x, z);\n}\n\nsize_t ExposedPauliString::getLength() const {\n    return pauli_string.num_qubits;\n}\n\nint8_t ExposedPauliString::getSign() const {\n    return pauli_string.sign ? -1 : +1;\n}\n\nvoid emscripten_bind_pauli_string() {\n    auto c = emscripten::class_<ExposedPauliString>(\"PauliString\");\n    c.constructor<const emscripten::val &>();\n    c.class_function(\"random\", &ExposedPauliString::random);\n    c.function(\"neg\", &ExposedPauliString::neg);\n    c.function(\"times\", &ExposedPauliString::times);\n    c.function(\"commutes\", &ExposedPauliString::commutes);\n    c.function(\"isEqualTo\", &ExposedPauliString::isEqualTo);\n    c.function(\"toString\", &ExposedPauliString::toString);\n    c.function(\"pauli\", &ExposedPauliString::pauli);\n    c.property(\"length\", &ExposedPauliString::getLength);\n    c.property(\"sign\", &ExposedPauliString::getSign);\n}\n"
  },
  {
    "path": "glue/javascript/pauli_string.js.h",
    "content": "#ifndef STIM_PAULI_STRING_JS_H\n#define STIM_PAULI_STRING_JS_H\n\n#include <cstddef>\n#include <cstdint>\n#include <emscripten/val.h>\n\n#include \"stim/stabilizers/pauli_string.h\"\n\nstruct ExposedPauliString {\n    stim::PauliString<stim::MAX_BITWORD_WIDTH> pauli_string;\n    explicit ExposedPauliString(stim::PauliString<stim::MAX_BITWORD_WIDTH> pauli_string);\n    explicit ExposedPauliString(const emscripten::val &arg);\n    static ExposedPauliString random(size_t n);\n    ExposedPauliString times(const ExposedPauliString &other) const;\n    bool commutes(const ExposedPauliString &other) const;\n    size_t getLength() const;\n    int8_t getSign() const;\n    uint8_t pauli(size_t index) const;\n    ExposedPauliString neg() const;\n    bool isEqualTo(const ExposedPauliString &other) const;\n    std::string toString() const;\n};\n\nvoid emscripten_bind_pauli_string();\n\n#endif\n"
  },
  {
    "path": "glue/javascript/pauli_string.test.js",
    "content": "test(\"pauli_string.constructor<int>\", ({stim, assert}) => {\n    let p = new stim.PauliString(0);\n    assert(p.length === 0);\n    assert(p.sign === +1);\n    assert(p.toString() === \"+\");\n\n    p = new stim.PauliString(1);\n    assert(p.length === 1);\n    assert(p.sign === +1);\n    assert(p.pauli(0) === 0);\n    assert(p.toString() === \"+_\");\n\n    p = new stim.PauliString(2);\n    assert(p.length === 2);\n    assert(p.sign === +1);\n    assert(p.pauli(0) === 0);\n    assert(p.pauli(1) === 0);\n    assert(p.toString() === \"+__\");\n\n    p = new stim.PauliString(1000);\n    assert(p.length === 1000);\n    assert(p.sign === +1);\n    assert(p.pauli(0) === 0);\n    assert(p.pauli(1) === 0);\n    assert(p.pauli(999) === 0);\n    assert(p.toString() === \"+\" + \"_\".repeat(1000));\n});\n\ntest(\"pauli_string.constructor<str>\", ({stim, assert}) => {\n    let p = new stim.PauliString(\"\");\n    assert(p.length === 0);\n    assert(p.sign === +1);\n    assert(p.toString() === \"+\");\n\n    p = new stim.PauliString(\"-\");\n    assert(p.length === 0);\n    assert(p.sign === -1);\n    assert(p.toString() === \"-\");\n\n    p = new stim.PauliString(\"-IXYZ\");\n    assert(p.length === 4);\n    assert(p.sign === -1);\n    assert(p.pauli(0) === 0);\n    assert(p.pauli(1) === 1);\n    assert(p.pauli(2) === 2);\n    assert(p.pauli(3) === 3);\n    assert(p.toString() === \"-_XYZ\");\n\n    try {\n        new stim.PauliString([]);\n        assert(false);\n    } catch {\n    }\n});\n\ntest(\"pauli_string.equality\", ({stim, assert}) => {\n    let ps = k => new stim.PauliString(k);\n    assert(ps(\"+\").isEqualTo(ps(\"+\")));\n    assert(ps(\"XX\").isEqualTo(ps(\"XX\")));\n    assert(!ps(\"XX\").isEqualTo(ps(\"XY\")));\n    assert(!ps(\"XX\").isEqualTo(ps(\"XXX\")));\n    assert(!ps(\"__\").isEqualTo(ps(\"___\")));\n    assert(!ps(\"XX\").isEqualTo(ps(\"ZX\")));\n    assert(!ps(\"XX\").isEqualTo(ps(\"__\")));\n    assert(!ps(\"+\").isEqualTo(ps(\"-\")));\n});\n\ntest(\"pauli_string.random\", ({stim, assert}) => {\n    assert(!stim.PauliString.random(100).isEqualTo(stim.PauliString.random(100)));\n});\n\ntest(\"pauli_string.times\", ({stim, assert}) => {\n    let ps = k => new stim.PauliString(k);\n    assert(ps(\"XX\").times(ps(\"YY\")).isEqualTo(ps(\"-ZZ\")));\n    assert(ps(\"XY\").times(ps(\"YX\")).isEqualTo(ps(\"+ZZ\")));\n    assert(ps(\"ZZ\").times(ps(\"YY\")).isEqualTo(ps(\"-XX\")));\n});\n\ntest(\"pauli_string.commutes\", ({stim, assert}) => {\n    let ps = k => new stim.PauliString(k);\n    assert(ps('+').commutes(ps('+')));\n    assert(ps('+XX').commutes(ps('+YY')));\n    assert(ps('+XX').commutes(ps('-YY')));\n    assert(ps('+XX').commutes(ps('+ZZ')));\n    assert(!ps('+XX').commutes(ps('+XZ')));\n    assert(!ps('+XX').commutes(ps('+XZ')));\n});\n\ntest(\"pauli_string.neg\", ({stim, assert}) => {\n    let ps = k => new stim.PauliString(k);\n    assert(ps('+').neg().isEqualTo(ps('-')));\n    assert(ps('-').neg().isEqualTo(ps('+')));\n    assert(ps('+XYZ').neg().isEqualTo(ps('-XYZ')));\n});\n"
  },
  {
    "path": "glue/javascript/stim.js.cc",
    "content": "#include <emscripten/bind.h>\n#include <emscripten/val.h>\n\n#include \"circuit.js.h\"\n#include \"pauli_string.js.h\"\n#include \"tableau.js.h\"\n#include \"tableau_simulator.js.h\"\n\nEMSCRIPTEN_BINDINGS(stim) {\n    emscripten_bind_circuit();\n    emscripten_bind_pauli_string();\n    emscripten_bind_tableau();\n    emscripten_bind_tableau_simulator();\n}\n"
  },
  {
    "path": "glue/javascript/stim.test_harness.js",
    "content": "let tests = [];\nlet __any_failures = false;\n\nfunction test(name, handler) {\n    tests.push({name, handler});\n}\n\nfunction tryPromiseRun(method) {\n    try {\n        return Promise.resolve(method());\n    } catch (ex) {\n        return Promise.reject(ex);\n    }\n}\n\nasync function run_all_tests() {\n    let stim = await load_stim_module();\n    let results = [];\n    for (let {name, handler} of tests) {\n        let result = tryPromiseRun(() => {\n            let count = 0;\n            let assert = condition => {\n                count += 1;\n                if (!condition) {\n                    throw new Error(`Assert #${count} failed.`);\n                }\n            };\n            return handler({stim, assert});\n        });\n        results.push({name, result});\n    }\n    for (let {result, name} of results) {\n        try {\n            await result;\n            console.log(`pass ${name}`);\n        } catch (ex) {\n            __any_failures = true;\n            console.error(`FAIL ${name}: ${ex}`);\n        }\n    }\n    try {\n        if (__any_failures) {\n            console.error(\"THERE WERE TEST FAILURES\");\n            throw Error(\"THERE WERE TEST FAILURES\");\n        } else {\n            console.info(\"All tests passed.\");\n        }\n    } finally {\n        var doneDiv = document.createElement('div');\n        doneDiv.id = 'done';\n        doneDiv.innerText = 'Done';\n        document.body.appendChild(doneDiv);\n    }\n}\n\nsetTimeout(run_all_tests, 0);\n"
  },
  {
    "path": "glue/javascript/tableau.js.cc",
    "content": "#include \"tableau.js.h\"\n\n#include <emscripten/bind.h>\n\n#include \"common.js.h\"\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nExposedTableau::ExposedTableau(Tableau<MAX_BITWORD_WIDTH> tableau) : tableau(tableau) {\n}\n\nExposedTableau::ExposedTableau(int n) : tableau(n) {\n}\n\nExposedTableau ExposedTableau::random(int n) {\n    auto rng = externally_seeded_rng();\n    return ExposedTableau(Tableau<MAX_BITWORD_WIDTH>::random(n, rng));\n}\n\nExposedTableau ExposedTableau::from_named_gate(const std::string &name) {\n    const Gate &gate = GATE_DATA.at(name);\n    if (!(gate.flags & GATE_IS_UNITARY)) {\n        throw std::out_of_range(\"Recognized name, but not unitary: \" + name);\n    }\n    return ExposedTableau(gate.tableau<MAX_BITWORD_WIDTH>());\n}\n\nstd::string ExposedTableau::str() const {\n    return tableau.str();\n}\n\nExposedPauliString ExposedTableau::x_output(size_t index) const {\n    if (index >= tableau.num_qubits) {\n        throw std::invalid_argument(\"target >= tableau.length\");\n    }\n    return ExposedPauliString(tableau.xs[index]);\n}\nExposedPauliString ExposedTableau::y_output(size_t index) const {\n    if (index >= tableau.num_qubits) {\n        throw std::invalid_argument(\"target >= tableau.length\");\n    }\n\n    // Compute Y using Y = i*X*Z.\n    uint8_t log_i = 1;\n    PauliString copy = tableau.xs[index];\n    log_i += copy.ref().inplace_right_mul_returning_log_i_scalar(tableau.zs[index]);\n    if (log_i & 1) {\n        throw std::out_of_range(\"Malformed tableau. X_k commutes with Z_k.\");\n    }\n    copy.sign ^= (log_i & 2) != 0;\n    return ExposedPauliString(copy);\n}\nExposedPauliString ExposedTableau::z_output(size_t index) const {\n    if (index >= tableau.num_qubits) {\n        throw std::invalid_argument(\"target >= tableau.length\");\n    }\n    return ExposedPauliString(tableau.zs[index]);\n}\n\nExposedTableau ExposedTableau::from_conjugated_generators_xs_zs(\n    const emscripten::val &xs_val, const emscripten::val &zs_val) {\n    auto xs = emscripten::vecFromJSArray<ExposedPauliString>(xs_val);\n    auto zs = emscripten::vecFromJSArray<ExposedPauliString>(zs_val);\n    size_t n = xs.size();\n    if (zs.size() != n) {\n        throw std::invalid_argument(\"xs.length != zs.length\");\n    }\n    for (const auto &e : xs) {\n        if (e.pauli_string.num_qubits != n) {\n            throw std::invalid_argument(\"x.length != xs.length\");\n        }\n    }\n    for (const auto &e : zs) {\n        if (e.pauli_string.num_qubits != n) {\n            throw std::invalid_argument(\"z.length != zs.length\");\n        }\n    }\n    Tableau<MAX_BITWORD_WIDTH> result(n);\n    for (size_t q = 0; q < n; q++) {\n        result.xs[q] = xs[q].pauli_string;\n        result.zs[q] = zs[q].pauli_string;\n    }\n    if (!result.satisfies_invariants()) {\n        throw std::invalid_argument(\n            \"The given generator outputs don't describe a valid Clifford operation.\\n\"\n            \"They don't preserve commutativity.\\n\"\n            \"Everything must commute, except for X_k anticommuting with Z_k for each k.\");\n    }\n    return ExposedTableau(result);\n}\n\nsize_t ExposedTableau::getLength() const {\n    return tableau.num_qubits;\n}\n\nbool ExposedTableau::isEqualTo(const ExposedTableau &other) const {\n    return tableau == other.tableau;\n}\n\nvoid emscripten_bind_tableau() {\n    auto c = emscripten::class_<ExposedTableau>(\"Tableau\");\n    c.constructor<int>();\n    c.class_function(\"random\", &ExposedTableau::random);\n    c.class_function(\"from_named_gate\", &ExposedTableau::from_named_gate);\n    c.class_function(\"from_conjugated_generators_xs_zs\", &ExposedTableau::from_conjugated_generators_xs_zs);\n    c.function(\"x_output\", &ExposedTableau::x_output);\n    c.function(\"y_output\", &ExposedTableau::y_output);\n    c.function(\"z_output\", &ExposedTableau::z_output);\n    c.function(\"toString\", &ExposedTableau::str);\n    c.function(\"isEqualTo\", &ExposedTableau::isEqualTo);\n    c.property(\"length\", &ExposedTableau::getLength);\n}\n"
  },
  {
    "path": "glue/javascript/tableau.js.h",
    "content": "#ifndef STIM_TABLEAU_JS_H\n#define STIM_TABLEAU_JS_H\n\n#include <cstddef>\n#include <cstdint>\n\n#include \"pauli_string.js.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nstruct ExposedTableau {\n    stim::Tableau<stim::MAX_BITWORD_WIDTH> tableau;\n    explicit ExposedTableau(stim::Tableau<stim::MAX_BITWORD_WIDTH> tableau);\n    explicit ExposedTableau(int n);\n    static ExposedTableau random(int n);\n    static ExposedTableau from_named_gate(const std::string &name);\n    static ExposedTableau from_conjugated_generators_xs_zs(\n        const emscripten::val &xs_val, const emscripten::val &zs_val);\n    ExposedPauliString x_output(size_t index) const;\n    ExposedPauliString y_output(size_t index) const;\n    ExposedPauliString z_output(size_t index) const;\n    size_t getLength() const;\n    std::string str() const;\n    bool isEqualTo(const ExposedTableau &other) const;\n};\n\nvoid emscripten_bind_tableau();\n\n#endif\n"
  },
  {
    "path": "glue/javascript/tableau.test.js",
    "content": "test(\"tableau.constructor<int>\", ({stim, assert}) => {\n    let p = new stim.Tableau(0);\n    assert(p.length === 0);\n\n    p = new stim.Tableau(1);\n    assert(p.length === 1);\n    assert(p.x_output(0).toString() === \"+X\");\n    assert(p.y_output(0).toString() === \"+Y\");\n    assert(p.z_output(0).toString() === \"+Z\");\n\n    p = new stim.Tableau(8);\n    assert(p.length === 8);\n    assert(p.x_output(5).toString() === \"+_____X__\");\n    assert(p.y_output(5).toString() === \"+_____Y__\");\n    assert(p.z_output(5).toString() === \"+_____Z__\");\n});\n\ntest(\"tableau.from_conjugated_generators_xs_zs\", ({stim, assert}) => {\n    assert(new stim.Tableau(0).isEqualTo(stim.Tableau.from_conjugated_generators_xs_zs([], [])));\n    assert(new stim.Tableau(1).isEqualTo(stim.Tableau.from_conjugated_generators_xs_zs(\n        [new stim.PauliString(\"+X\")], [new stim.PauliString(\"+Z\")]\n    )));\n    let t = stim.Tableau.from_conjugated_generators_xs_zs(\n        [\n            new stim.PauliString(\"+XX\"),\n            new stim.PauliString(\"+_X\"),\n        ],\n        [\n            new stim.PauliString(\"+Z_\"),\n            new stim.PauliString(\"+ZZ\"),\n        ],\n    );\n    assert(t.toString().trim() === `\n+-xz-xz-\n| ++ ++\n| XZ _Z\n| X_ XZ\n`.trim());\n});\n\ntest(\"tableau.from_named_gate_vs_output\", ({stim, assert}) => {\n    assert(new stim.Tableau(3).toString().trim() === `\n+-xz-xz-xz-\n| ++ ++ ++\n| XZ __ __\n| __ XZ __\n| __ __ XZ\n`.trim());\n\n    assert(stim.Tableau.from_named_gate(\"H\").toString().trim() === `\n+-xz-\n| ++\n| ZX\n`.trim());\n\n    assert(stim.Tableau.from_named_gate(\"X\").toString().trim() === `\n+-xz-\n| +-\n| XZ\n`.trim());\n\n    let cnot = stim.Tableau.from_named_gate(\"CNOT\");\n    assert(cnot.toString().trim() === `\n+-xz-xz-\n| ++ ++\n| XZ _Z\n| X_ XZ\n`.trim());\n    assert(cnot.x_output(0).toString() === \"+XX\");\n    assert(cnot.x_output(1).toString() === \"+_X\");\n    assert(cnot.y_output(0).toString() === \"+YX\");\n    assert(cnot.y_output(1).toString() === \"+ZY\");\n    assert(cnot.z_output(0).toString() === \"+Z_\");\n    assert(cnot.z_output(1).toString() === \"+ZZ\");\n});\n\ntest(\"tableau.random\", ({stim, assert}) => {\n    assert(!stim.Tableau.random(10).isEqualTo(stim.Tableau.random(10)));\n});\n\ntest(\"tableau.equality\", ({stim, assert}) => {\n    let h = stim.Tableau.from_named_gate(\"H\");\n    let x = stim.Tableau.from_named_gate(\"X\");\n    let id = stim.Tableau.from_named_gate(\"I\");\n    let cnot = stim.Tableau.from_named_gate(\"CNOT\");\n    assert(h.isEqualTo(h));\n    assert(h.isEqualTo(stim.Tableau.from_named_gate(\"H\")));\n    assert(!h.isEqualTo(x));\n    assert(!id.isEqualTo(x));\n    assert(id.isEqualTo(id));\n    assert(x.isEqualTo(x));\n    assert(cnot.isEqualTo(cnot));\n    assert(!x.isEqualTo(cnot));\n    assert(new stim.Tableau(2).isEqualTo(new stim.Tableau(2)));\n    assert(!new stim.Tableau(3).isEqualTo(new stim.Tableau(2)));\n});\n"
  },
  {
    "path": "glue/javascript/tableau_simulator.js.cc",
    "content": "#include \"tableau_simulator.js.h\"\n\n#include <emscripten/bind.h>\n#include <emscripten/val.h>\n\n#include \"common.js.h\"\n\nusing namespace stim;\n\nstruct JsCircuitInstruction {\n    GateType gate_type;\n    std::vector<GateTarget> targets;\n    JsCircuitInstruction(GateType gate_type, std::vector<GateTarget> targets) : gate_type(gate_type), targets(std::move(targets)) {\n    }\n    JsCircuitInstruction(GateType gate_type, std::vector<uint32_t> init_targets) : gate_type(gate_type) {\n        for (auto e : init_targets) {\n            targets.push_back(GateTarget{e});\n        }\n    }\n    operator CircuitInstruction() const {\n        return {gate_type, {}, targets, \"\"};\n    }\n};\n\nstatic JsCircuitInstruction args_to_targets(TableauSimulator<MAX_BITWORD_WIDTH> &self, GateType gate_type, const emscripten::val &args) {\n    std::vector<uint32_t> result = emscripten::convertJSArrayToNumberVector<uint32_t>(args);\n    uint32_t max_q = 0;\n    for (uint32_t q : result) {\n        max_q = std::max(max_q, q & TARGET_VALUE_MASK);\n    }\n\n    // Note: quadratic behavior.\n    self.ensure_large_enough_for_qubits((size_t)max_q + 1);\n\n    return JsCircuitInstruction(gate_type, result);\n}\n\nstatic JsCircuitInstruction safe_targets(TableauSimulator<MAX_BITWORD_WIDTH> &self, GateType gate_type, uint32_t target) {\n    uint32_t max_q = target & TARGET_VALUE_MASK;\n    self.ensure_large_enough_for_qubits((size_t)max_q + 1);\n    return JsCircuitInstruction(gate_type, {GateTarget{target}});\n}\n\nstatic JsCircuitInstruction safe_targets(TableauSimulator<MAX_BITWORD_WIDTH> &self, GateType gate_type, uint32_t target1, uint32_t target2) {\n    uint32_t max_q = std::max(target1 & TARGET_VALUE_MASK, target2 & TARGET_VALUE_MASK);\n    self.ensure_large_enough_for_qubits((size_t)max_q + 1);\n    if (target1 == target2) {\n        throw std::invalid_argument(\"target1 == target2\");\n    }\n    return JsCircuitInstruction(gate_type, {GateTarget{target1}, GateTarget{target2}});\n}\n\nstatic JsCircuitInstruction args_to_target_pairs(TableauSimulator<MAX_BITWORD_WIDTH> &self, GateType gate_type, const emscripten::val &args) {\n    auto result = args_to_targets(self, gate_type, args);\n    if (result.targets.size() & 1) {\n        throw std::out_of_range(\"Two qubit operation requires an even number of targets.\");\n    }\n    return result;\n}\n\nExposedTableauSimulator::ExposedTableauSimulator() : sim(externally_seeded_rng(), 0) {\n}\n\nbool ExposedTableauSimulator::measure(size_t target) {\n    sim.ensure_large_enough_for_qubits(target + 1);\n    sim.do_MZ(JsCircuitInstruction(GateType::M, {GateTarget{target}}));\n    return (bool)sim.measurement_record.storage.back();\n}\n\nemscripten::val ExposedTableauSimulator::measure_kickback(size_t target) {\n    sim.ensure_large_enough_for_qubits(target + 1);\n    auto result = sim.measure_kickback_z(GateTarget{(uint32_t)target});\n    emscripten::val returned = emscripten::val::object();\n    returned.set(\"result\", result.first);\n    if (result.second.num_qubits) {\n        returned.set(\"kickback\", ExposedPauliString(result.second));\n    } else {\n        returned.set(\"kickback\", emscripten::val::undefined());\n    }\n    return returned;\n}\n\nvoid ExposedTableauSimulator::do_circuit(const ExposedCircuit &circuit) {\n    sim.ensure_large_enough_for_qubits(circuit.circuit.count_qubits());\n    circuit.circuit.for_each_operation([&](const CircuitInstruction &op) {\n        sim.do_gate(op);\n    });\n}\nvoid ExposedTableauSimulator::do_pauli_string(const ExposedPauliString &pauli_string) {\n    sim.ensure_large_enough_for_qubits(pauli_string.pauli_string.num_qubits);\n    sim.paulis(pauli_string.pauli_string);\n}\nvoid ExposedTableauSimulator::do_tableau(const ExposedTableau &tableau, const emscripten::val &targets) {\n    auto conv = emscripten::convertJSArrayToNumberVector<size_t>(targets);\n    uint32_t max_q = 0;\n    for (uint32_t q : conv) {\n        max_q = std::max(max_q, q & TARGET_VALUE_MASK);\n    }\n    sim.ensure_large_enough_for_qubits((size_t)max_q + 1);\n    sim.inv_state.inplace_scatter_prepend(tableau.tableau.inverse(), conv);\n}\n\nvoid ExposedTableauSimulator::X(uint32_t target) {\n    sim.do_X(safe_targets(sim, GateType::X, target));\n}\nvoid ExposedTableauSimulator::Y(uint32_t target) {\n    sim.do_Y(safe_targets(sim, GateType::Y, target));\n}\nvoid ExposedTableauSimulator::Z(uint32_t target) {\n    sim.do_Z(safe_targets(sim, GateType::Z, target));\n}\nvoid ExposedTableauSimulator::H(uint32_t target) {\n    sim.do_H_XZ(safe_targets(sim, GateType::H, target));\n}\nvoid ExposedTableauSimulator::CNOT(uint32_t control, uint32_t target) {\n    sim.do_ZCX(safe_targets(sim, GateType::CX, control, target));\n}\nvoid ExposedTableauSimulator::SWAP(uint32_t target1, uint32_t target2) {\n    sim.do_SWAP(safe_targets(sim, GateType::SWAP, target1, target2));\n}\nvoid ExposedTableauSimulator::CY(uint32_t control, uint32_t target) {\n    sim.do_ZCY(safe_targets(sim, GateType::CY, control, target));\n}\nvoid ExposedTableauSimulator::CZ(uint32_t control, uint32_t target) {\n    sim.do_ZCZ(safe_targets(sim, GateType::CZ, control, target));\n}\n\nExposedTableau ExposedTableauSimulator::current_inverse_tableau() const {\n    return ExposedTableau(sim.inv_state);\n}\nvoid ExposedTableauSimulator::set_inverse_tableau(const ExposedTableau &tableau) {\n    sim.inv_state = tableau.tableau;\n}\n\nExposedTableauSimulator ExposedTableauSimulator::copy() const {\n    return *this;\n}\n\nvoid emscripten_bind_tableau_simulator() {\n    auto c = emscripten::class_<ExposedTableauSimulator>(\"TableauSimulator\");\n    c.constructor();\n    c.function(\"current_inverse_tableau\", &ExposedTableauSimulator::current_inverse_tableau);\n    c.function(\"set_inverse_tableau\", &ExposedTableauSimulator::set_inverse_tableau);\n    c.function(\"measure\", &ExposedTableauSimulator::measure);\n    c.function(\"measure_kickback\", &ExposedTableauSimulator::measure_kickback);\n    c.function(\"do_circuit\", &ExposedTableauSimulator::do_circuit);\n    c.function(\"do_tableau\", &ExposedTableauSimulator::do_tableau);\n    c.function(\"do_pauli_string\", &ExposedTableauSimulator::do_pauli_string);\n    c.function(\"X\", &ExposedTableauSimulator::X);\n    c.function(\"Y\", &ExposedTableauSimulator::Y);\n    c.function(\"Z\", &ExposedTableauSimulator::Z);\n    c.function(\"H\", &ExposedTableauSimulator::H);\n    c.function(\"CNOT\", &ExposedTableauSimulator::CNOT);\n    c.function(\"CY\", &ExposedTableauSimulator::CY);\n    c.function(\"CZ\", &ExposedTableauSimulator::CZ);\n    c.function(\"SWAP\", &ExposedTableauSimulator::SWAP);\n    c.function(\"copy\", &ExposedTableauSimulator::copy);\n}\n"
  },
  {
    "path": "glue/javascript/tableau_simulator.js.h",
    "content": "#ifndef STIM_TABLEAU_SIMULATOR_JS_H\n#define STIM_TABLEAU_SIMULATOR_JS_H\n\n#include <cstddef>\n#include <cstdint>\n#include <emscripten/val.h>\n\n#include \"circuit.js.h\"\n#include \"pauli_string.js.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"tableau.js.h\"\n\nstruct ExposedTableauSimulator {\n    stim::TableauSimulator<stim::MAX_BITWORD_WIDTH> sim;\n    ExposedTableauSimulator();\n    ExposedTableauSimulator copy() const;\n    bool measure(size_t target);\n    emscripten::val measure_kickback(size_t target);\n    ExposedTableau current_inverse_tableau() const;\n    void set_inverse_tableau(const ExposedTableau &tableau);\n    void do_circuit(const ExposedCircuit &circuit);\n    void do_pauli_string(const ExposedPauliString &pauli_string);\n    void do_tableau(const ExposedTableau &tableau, const emscripten::val &targets);\n    void X(uint32_t target);\n    void Y(uint32_t target);\n    void Z(uint32_t target);\n    void H(uint32_t target);\n    void CNOT(uint32_t control, uint32_t target);\n    void CY(uint32_t control, uint32_t target);\n    void CZ(uint32_t control, uint32_t target);\n    void SWAP(uint32_t target1, uint32_t target12);\n};\n\nvoid emscripten_bind_tableau_simulator();\n\n#endif\n"
  },
  {
    "path": "glue/javascript/tableau_simulator.test.js",
    "content": "test(\"tableau_simulator.constructor\", ({stim, assert}) => {\n    let s = new stim.TableauSimulator();\n    assert(s.current_inverse_tableau().isEqualTo(new stim.Tableau(0)));\n});\n\ntest(\"tableau_simulator.set_inverse_tableau\", ({stim, assert}) => {\n    let s = new stim.TableauSimulator();\n    let t = new stim.Tableau(10);\n    s.set_inverse_tableau(t);\n    assert(s.current_inverse_tableau().isEqualTo(t));\n});\n\ntest(\"tableau_simulator.measure\", ({stim, assert}) => {\n    let s = new stim.TableauSimulator();\n    assert(s.measure(0) === false);\n    assert(s.measure(1) === false);\n    assert(s.measure(2) === false);\n    s.X(0);\n    s.X(2);\n    assert(s.measure(0) === true);\n    assert(s.measure(1) === false);\n    assert(s.measure(2) === true);\n\n    assert(s.measure(500) === false);\n});\n\ntest(\"tableau_simulator.gate_methods_vs_do_tableau\", ({stim, assert}) => {\n    for (let gate of [\"X\", \"Y\", \"Z\", \"H\", \"CNOT\", \"CY\", \"CZ\"]) {\n        let t = stim.Tableau.from_named_gate(gate);\n        let n = t.length;\n        let s = new stim.TableauSimulator();\n        for (let k = 0; k < n; k++) {\n            s.H(k);\n            s.CNOT(k, k + n);\n        }\n        let s2 = s.copy();\n        if (n === 1) {\n            s[gate](2);\n            s2.do_tableau(t, [2]);\n        } else {\n            s[gate](2, 3);\n            s2.do_tableau(t, [2, 3]);\n        }\n        assert(s.current_inverse_tableau().isEqualTo(s2.current_inverse_tableau()));\n    }\n});\n\ntest(\"tableau_simulator.do_tableau\", ({stim, assert}) => {\n    let a = new stim.TableauSimulator();\n    a.do_tableau(stim.Tableau.from_named_gate(\"X\"), [0]);\n    assert(a.measure(0) === true);\n    assert(a.measure(1) === false);\n    assert(a.measure(2) === false);\n    a.do_tableau(stim.Tableau.from_named_gate(\"CNOT\"), [0, 2]);\n    assert(a.measure(0) === true);\n    assert(a.measure(1) === false);\n    assert(a.measure(2) === true);\n});\n\ntest(\"tableau_simulator.copy\", ({stim, assert}) => {\n    let a = new stim.TableauSimulator();\n    a.X(2);\n    let b = a.copy();\n    assert(a.current_inverse_tableau().isEqualTo(b.current_inverse_tableau()));\n    a.Y(1);\n    assert(!a.current_inverse_tableau().isEqualTo(b.current_inverse_tableau()));\n});\n\ntest(\"tableau_simulator.do_circuit\", ({stim, assert}) => {\n    let a = new stim.TableauSimulator();\n    a.do_circuit(new stim.Circuit(`\n        X 0 2\n        SWAP 2 3\n    `));\n    assert(a.measure(0) === true);\n    assert(a.measure(1) === false);\n    assert(a.measure(2) === false);\n    assert(a.measure(3) === true);\n});\n\ntest(\"tableau_simulator.do_pauli_string\", ({stim, assert}) => {\n    let a = new stim.TableauSimulator();\n    a.do_circuit(new stim.Circuit(`\n        H_XZ 4 5 6 7\n        H_YZ 8 9 10 11\n    `));\n    a.do_pauli_string(new stim.PauliString(\"_XYZ_XYZ_XYZ\"));\n    a.do_circuit(new stim.Circuit(`\n        H_XZ 4 5 6 7\n        H_YZ 8 9 10 11\n    `));\n    assert(a.measure(0) === false);\n    assert(a.measure(1) === true);\n    assert(a.measure(2) === true);\n    assert(a.measure(3) === false);\n\n    assert(a.measure(4) === false);\n    assert(a.measure(5) === false);\n    assert(a.measure(6) === true);\n    assert(a.measure(7) === true);\n\n    assert(a.measure(8) === false);\n    assert(a.measure(9) === true);\n    assert(a.measure(10) === false);\n    assert(a.measure(11) === true);\n});\n\ntest(\"tableau_simulator.measure_kickback\", ({stim, assert}) => {\n    let a = new stim.TableauSimulator();\n    a.do_circuit(new stim.Circuit(`\n        H 0\n        CNOT 0 1 0 3\n    `));\n    let v1 = a.measure_kickback(1);\n    let v2 = a.measure_kickback(3);\n    assert(v1.kickback.isEqualTo(new stim.PauliString('+XX_X')));\n    assert(v2.kickback === undefined);\n    assert(v1.result === v2.result);\n});\n\ntest(\"tableau_simulator.collision\", ({stim, assert}) => {\n    let s = new stim.TableauSimulator();\n    try {\n        s.CNOT(0, 0);\n        assert(false);\n    } catch {\n    }\n    try {\n        s.SWAP(2, 2);\n        assert(false);\n    } catch {\n    }\n    s.SWAP(0, 1);\n});\n"
  },
  {
    "path": "glue/lattice_surgery/README.md",
    "content": "# Lattice Surgery Subroutine Synthesizer (LaSsynth)\nA lattice surgery subroutine (LaS) is a confined volume with a set of ports.\nWithin this volume, lattice surgery merges and splits are performed.\nThe function of a LaS is characterized by a set of stabilizers on these ports.\n\nThe lattice surgery subroutine synthesizer (LaSsynth) uses SAT/SMT solvers to synthesize LaS given the volume, the ports, and the stabilizers.\nLaSsynth outputs a textual representation of LaS (LaSRe) which is a JSON file with filename extension `.lasre`.\nLaSsynth can also generate 3D modelling files in the [GLTF](https://www.khronos.org/gltf/) format from LaSRe files.\n\nThe main ideas of this project is provided in the paper [A SAT Scalpel for Lattice Surgery](http://arxiv.org/abs/2404.18369) by Tan, Niu, and Gidney.\nFor files specific to the paper, please refer to [its Zenodo archive](https://zenodo.org/doi/10.5281/zenodo.11051465).\n\n## Installation\nIt is recommended to create a virtual Python environment. Once inside the environment, in this directory, `pip install .`\nApart from LaSsynth, this will install a few packages that we need: \n  - `z3-solver` version `4.12.1.0`, from pip\n  - `networkx` default version, from pip\n  - `stim` default version, from pip\n  - `stimzx` from files included in sirectory `./stimzx/`. We copied these files from [here](https://github.com/quantumlib/Stim/tree/0fdddef863cfe777f3f2086a092ba99785725c07/glue/zx).\n  - `ipykernel` default version, from pip, to view the demo Jupyter notebook.\n\nWe have a dependency [kissat](https://github.com/arminbiere/kissat) which is a SAT solver, not a Python package. \nIt is recommended to install it and find out the directory of the executable `kissat` because we will need it later.\nLaSsynth can be used without Kissat, in which case it just uses `z3-solver`, but on certain cases Kissat can offer big runtime improvements.\n\n## How to use\nSee the [demo notebook in the docs directory](docs/demo.ipynb)\n\n## Cite this work\n```bibtex\n@inproceedings{tan-niu-gidney_lattice_surgery,\n    author = {Tan, Daniel Bochen and Niu, Murphy Yuezhen and Gidney, Craig},\n\ttitle = {A {SAT} Scalpel for Lattice Surgery: Representation and Synthesis of Subroutines for Surface-Code Fault-Tolerant Quantum Computing},\n\tshorttitle = {A {SAT} Scalpel for Lattice Surgery},\n\tbooktitle = {2024 ACM/IEEE 51st Annual International Symposium on Computer Architecture ({ISCA})},\n\tyear = {2024},\n    url = {http://arxiv.org/abs/2404.18369},\n}\n```"
  },
  {
    "path": "glue/lattice_surgery/docs/demo.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Introduction to the LaSSynth, Lattice Surgery Subroutine Synthesizer\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Prerequisites\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"\\n\",\n    \"This Jupyter notebook aims at giving a minimal demo on how to use this software.\\n\",\n    \"The reader needs to know how lattice surgery works to fully understand this notebook.\\n\",\n    \"The most direct reference is [our paper](http://arxiv.org/abs/2404.18369) which, in itself, also provides more pointers to background knowledge references.\\n\",\n    \"There are two we would like to mention here.\\n\",\n    \"- [arXiv:1704.08670](https://arxiv.org/abs/1704.08670) links merging and spliting operations in lattice surgery to ZX calculus.\\n\",\n    \"We leverage this connection a lot in our software.\\n\",\n    \"- [arXiv:1808.02892](https://arxiv.org/abs/1808.02892) is helpful because it works through some examples of composing lattice surgery operations to perform quantum computation.\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Introduction\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"\\n\",\n    \"In what follows, we are assuming a surface code quantum memory with nearest-neighbor connectivity among the qubits (in both the physical and the logical sense).\\n\",\n    \"We perform fault-tolerant quantum computing with lattice surgery between patches of physical qubits.\\n\",\n    \"Some of these patches correspond to logical qubits whereas others can be temporary ancilla during computation.\\n\",\n    \"\\n\",\n    \"Since the logical qubits are in a 2D grid, and there is the time dimension, the compilation problem is laying out operations in a 3D grid to realize certain computation.\\n\",\n    \"We consider only a bounded spacetime and what *can* be realized within the bounds is called a *lattice surgery subroutine* (LaS), because it should be considered as a subroutine in the whole quantum algorithm.\\n\",\n    \"\\n\",\n    \"Because of the connection between lattice surgery and ZX calculus, a LaS can be seen as a ZX diagram with nodes at points in a 3D grid and edges only between nearest neighbors, as seen in the figure below.\\n\",\n    \"If you have worked with ZX calculus, you would know that this ZX diagram is a CNOT.\\n\",\n    \"However, it seems that there are two \\\"unnecessary\\\" identity nodes in the middle.\\n\",\n    \"This is because there are other constraints when it comes to realizing the CNOT in a surface code memory.\\n\",\n    \"Our representation of a LaS, the \\\"pipe diagram\\\" below, does account for these extra constraints.\"\n   ]\n  },\n  {\n   \"attachments\": {\n    \"e1d30228-b8e9-4608-942a-e09fe765c155.png\": {\n     \"image/png\": \"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\"\n    }\n   },\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"![Screenshot from 2023-09-14 05-14-00.png](attachment:e1d30228-b8e9-4608-942a-e09fe765c155.png)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Pipe diagrams\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"\\n\",\n    \"\\n\",\n    \"We use a 3D coordinate system with basis I, J, and K.\\n\",\n    \"We avoid using X, Y, and Z because these letters are also used in ZX calculus for different purposes.\\n\",\n    \"K is the time dimension while I and J are the space dimensions.\\n\",\n    \"\\n\",\n    \"If we want the pipe diagram to look like exactly what happens on chip, we need to draw them in scale, e.g, shown on the right below.\\n\",\n    \"There are four patches of surface codes, and only three are used in the computation.\\n\",\n    \"These three are identified by their coordinates in the I-J plane: (1,0), (1,1), and (0,1) from left to right in the picture.\\n\",\n    \"Between the patches, there are some \\\"gaps\\\" which are lines on physical qubits.\\n\",\n    \"We can perform merging and splitting of patches with these gaps.\\n\",\n    \"Since the gap is very narrow compared to the patches, but what happens there are really what decides the computation.\\n\",\n    \"Thus, to see these merging and splitting more clearly, we often stretch the gaps in the pipe diagram, resulting in something like the picture on the left below.\\n\",\n    \"\\n\",\n    \"The unit in all three dimension is the code distance.\\n\",\n    \"So, a patch going through a full QEC cycle will become a cube.\\n\",\n    \"These cubes are sitting at integer points in the I-J-K grid.\\n\",\n    \"Nontrivial logical operations are done by connecting these cubes with pipes.\\n\",\n    \"For example, two cubes connected in the I-J plane correspond to performing merging and splitting of two patches; a cube that has a vertical connection below but not above is a logical measurement; etc.\\n\",\n    \"At this point, we see that the problem of compiling LaS is laying out these cubes and pipes in a limited spacetime.\"\n   ]\n  },\n  {\n   \"attachments\": {\n    \"dac9ce3a-5960-445f-a5d9-f13e0ac44c80.png\": {\n     \"image/png\": \"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\"\n    }\n   },\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"![Screenshot from 2023-09-14 05-55-57.png](attachment:dac9ce3a-5960-445f-a5d9-f13e0ac44c80.png)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## LaS Specification\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"There are some constraints in the construction of these diagrams, e.g., matching colors at intersection of two pipes, but we are not going to introduce them here.\\n\",\n    \"After all, the purpose of a synthesizer is to let a computer consider those constraints instead of humans.\\n\",\n    \"The reader can refer to our paper, or even to the code in this repo for these constraints later on.\\n\",\n    \"What we are going to detail now is how to specify a problem to the compiler, so that the reader can start using the software.\"\n   ]\n  },\n  {\n   \"attachments\": {\n    \"4fef384b-1f6b-4712-8dcf-8e3f7b973a2f.png\": {\n     \"image/png\": \"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iaQX1tbOwr6srAwyM5PIyEggIyMRtToVqVSOQq4gTe6E1NAcmcwImdQAA6kcU5kBKtVN0P6vPACKKuW8yOVy6tZ1QqPRcP36nzRu3Ahra+uKNkskD7y9vfH29hbe//rrr/z2229MmTKFoUOHFrvftWvXCtWkO3XqREREBCtWrGDmzJlIpVKio6Pp3bs3o0aNokmTJkC2eNqRI0fYtm2bjuNy+PBhGjduLCivtmrVCltbWxYsWMCjR4+E2mSBgYHCMd9++22etp04cQKVSsWqVauEgoReXl6888473L17t8iOy/Lly0lOTuby5cvCzISvr69wY8+hXr16giMQGhrKmjVrCuxbKpVy5coVvQ8AZ86c4eeff2bjxo3Cjb1NmzbExsayYMECJk2ahEKhIC0tjVmzZjF06FChjpG3tzdWVlZ069aN06dP07lzZ2rXri0s+UilUurWrZvnElD79u1p3749kF0ZPC/HZfbs2WRlZXH48GFhrENDQ3FzcyMkJIQDBw4IbVUqFfv378fW1haAjh07sn//fg4cOKDXcbGysuL69esFjmF1QKPRMHjwYO7fv8+nn35aZo7aP8JxOXr0KC1atMDGxqaiTalwnI3gLU00W69uQ9usJ1lZCaSnx6HVajEyssLAwAIzMyeMjWsikRQUfJu9fp9TWTpNk4axtOD13sqCQqGgfn03FAo5f/75J02aNBGdlyrAzZs3CQoKolu3bsybN69Efb1ez6pv377s3buXe/fuUb9+fZycnFi6dClxcXEcOnSIJ0+eoFKpyMzMJCsrS+dYf39/goODmTRpEoGBgXh5eeHr61vsGSFfX18MDAx45513CA4Opl27dlhaWrJ3795i9XfhwgU8PT11llOUSmWp1NgJCgrKc9Zy3759SCQSzM3NdWT+a9SoQVxcHI8ePcLFxYXbt28TGxvLoEGDdI738/MjPDy8TIOY9+7dS48ePXQqVhsYGDBw4ECWL19ORkaGUKfO0NBQcFog23mqV68ekZGRZWZfVSEzM5MTJ07QunVrFi9ezLBhw0o1KDeHau+43L59m8ePH//jZ1tepb4SemalsOnyb3h4NMXevjMKhRJJCWdMjCRGaLSaKjXzAuDs7IxEIuXvv++jVquxsbEpk+lNkZITFxdHnz59sLW15aeffir1zLach5tXY5+++uorPv/8cxwdHXF1dcXE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\"\n    }\n   },\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"![Screenshot from 2023-09-14 06-26-00.png](attachment:4fef384b-1f6b-4712-8dcf-8e3f7b973a2f.png)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"The LaS specification is shown in part b) of the figure above.\\n\",\n    \"`max_i`, `max_j` and `max_k` are the bounds of spacetime.\\n\",\n    \"In our example, they are 2, 2, and 3, which means all the cubes and pipes are within 2x2x3 volume.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 10,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"input_dict = {\\n\",\n    \"  \\\"max_i\\\": 2, \\\"max_j\\\": 2, \\\"max_k\\\": 3\\n\",\n    \"}\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"There are certain *ports* that connects the LaS to the outside (which makes sense since a subroutine in classical computing always has some arguements and some returns).\\n\",\n    \"In this example, there are two ports on the bottom floor corresponding to the two qubits before the CNOT; then, there is some manipulation of these two qubits implmented with the pipes in the gray box; on the top floor, the two ports are the qubits after going through the CNOT.\\n\",\n    \"\\n\",\n    \"We need to provide three things to specify each port.\\n\",\n    \"Let us look at the port for the output of control qubit in the CNOT indicated in the callout in part a) of the figure above.\\n\",\n    \"In the code block below, it is the third port in `input_dict[\\\"ports\\\"]`.\\n\",\n    \"- Its `location` is `[1,0,3]` because that is where the information is going out of the LSS.\\n\",\n    \"- In general, the pipe connecting a port can also be in I, J or K direction.\\n\",\n    \"Additionally, we need another character (`-` or `+`) to indicate the direction from the port to the other parts of the LaS.\\n\",\n    \"In this example, the pipe is in the K direction, and we need to go downward from `[1, 0, 3]` to everything else, so the `direction` of the port is `-K`.\\n\",\n    \"- Finally, surface code patches have a space orientation of the X and Z boundaries indicated by red and blue above.\\n\",\n    \"We provide which one of I, J, and K is orthogonal to the face of Z boundary (blue).\\n\",\n    \"In this example, it is J that is orthogonal to the blue faces, so the `z_basis_direction` of this port is `J`.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 11,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"input_dict[\\\"ports\\\"] = [\\n\",\n    \"    {\\\"location\\\": [1, 0, 0], \\\"direction\\\": \\\"+K\\\", \\\"z_basis_direction\\\": \\\"J\\\"},\\n\",\n    \"    {\\\"location\\\": [0, 1, 0], \\\"direction\\\": \\\"+K\\\", \\\"z_basis_direction\\\": \\\"J\\\"},\\n\",\n    \"    {\\\"location\\\": [1, 0, 3], \\\"direction\\\": \\\"-K\\\", \\\"z_basis_direction\\\": \\\"J\\\"},\\n\",\n    \"    {\\\"location\\\": [0, 1, 3], \\\"direction\\\": \\\"-K\\\", \\\"z_basis_direction\\\": \\\"J\\\"},\\n\",\n    \"]\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Finally, we need to provide the stabilizer constraints on the ports to ensure that the LaS indeed realizes the logical operations we want to perform.\\n\",\n    \"Although intuitively there are input and output ports for the CNOT, in a LaS, there is no inherent distinction between inputs and outputs.\\n\",\n    \"What matters is that the given stabilizers have to match the ordering of the ports.\\n\",\n    \"Our ordering is (control qubit input, target qubit input, control qubit output, target qubit output), so the correct stabilizers are ZIZI, IZZZ, XIXX, and IXIX.\\n\",\n    \"If we change the ordering of the `\\\"ports\\\"` list above, we also need to change the stabilizers.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 12,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"input_dict[\\\"stabilizers\\\"] = [\\\"Z.Z.\\\", \\\".ZZZ\\\", \\\"X.XX\\\", \\\".X.X\\\"]\\n\",\n    \"# Note that we use a . for an identity in a stabilizer\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Solving LaS\"\n   ]\n  },\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"By now we have finished preparing the specification of the LaS.\\n\",\n    \"We can use our software package `lassynth`, specifically the class `LatticeSurgerySynthesizer` to solve the problem.\\n\",\n    \"When we invoke `solve` method, the synthesizer gives us a solution with respect to a `specification`.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 13,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"<lassynth.lattice_surgery_synthesis.LatticeSurgerySolution at 0x104d68760>\"\n      ]\n     },\n     \"execution_count\": 13,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"from lassynth import LatticeSurgerySynthesizer\\n\",\n    \"\\n\",\n    \"las_synth = LatticeSurgerySynthesizer()\\n\",\n    \"result = las_synth.solve(specification=input_dict)\\n\",\n    \"result\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"As you have noticed, the return value is of a class `LatticeSurgerySolution`.\\n\",\n    \"We implement a few methods for this class to help us further manipulate the solution.\\n\",\n    \"To see the \\\"raw\\\" solution, i.e., LaSRe (lattice surgery subroutine representation) in the paper, you can access the `lasre` of this result.\\n\",\n    \"Due to technical reasons, the `ports` here is another encoding compared to the `ports` in the specification.\\n\",\n    \"Intersted readers can refer to comments in the code to understand this encoding, but it is not too important in this notebook.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 14,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"{'n_i': 2,\\n\",\n       \" 'n_j': 2,\\n\",\n       \" 'n_k': 3,\\n\",\n       \" 'n_p': 4,\\n\",\n       \" 'n_s': 4,\\n\",\n       \" 'ports': [{'i': 1, 'j': 0, 'k': 0, 'd': 'K', 'e': '-', 'c': 1},\\n\",\n       \"  {'i': 0, 'j': 1, 'k': 0, 'd': 'K', 'e': '-', 'c': 1},\\n\",\n       \"  {'i': 1, 'j': 0, 'k': 2, 'd': 'K', 'e': '+', 'c': 1},\\n\",\n       \"  {'i': 0, 'j': 1, 'k': 2, 'd': 'K', 'e': '+', 'c': 1}],\\n\",\n       \" 'stabs': [[{'KI': 0, 'KJ': 1},\\n\",\n       \"   {'KI': 0, 'KJ': 0},\\n\",\n       \"   {'KI': 0, 'KJ': 1},\\n\",\n       \"   {'KI': 0, 'KJ': 0}],\\n\",\n       \"  [{'KI': 0, 'KJ': 0},\\n\",\n       \"   {'KI': 0, 'KJ': 1},\\n\",\n       \"   {'KI': 0, 'KJ': 1},\\n\",\n       \"   {'KI': 0, 'KJ': 1}],\\n\",\n       \"  [{'KI': 1, 'KJ': 0},\\n\",\n       \"   {'KI': 0, 'KJ': 0},\\n\",\n       \"   {'KI': 1, 'KJ': 0},\\n\",\n       \"   {'KI': 1, 'KJ': 0}],\\n\",\n       \"  [{'KI': 0, 'KJ': 0},\\n\",\n       \"   {'KI': 1, 'KJ': 0},\\n\",\n       \"   {'KI': 0, 'KJ': 0},\\n\",\n       \"   {'KI': 1, 'KJ': 0}]],\\n\",\n       \" 'port_cubes': [(1, 0, 0), (0, 1, 0), (1, 0, 3), (0, 1, 3)],\\n\",\n       \" 'optional': {},\\n\",\n       \" 'ExistI': [[[0, 1, 0], [0, 1, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \" 'ExistJ': [[[0, 0, 1], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \" 'ExistK': [[[0, 1, 0], [1, 1, 1]], [[1, 1, 1], [1, 1, 0]]],\\n\",\n       \" 'ColorI': [[[0, 1, 1], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \" 'ColorJ': [[[0, 0, 0], [0, 0, 0]], [[0, 0, 1], [0, 0, 0]]],\\n\",\n       \" 'NodeY': [[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [1, 0, 1]]],\\n\",\n       \" 'CorrIJ': [[[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 1, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]]],\\n\",\n       \" 'CorrIK': [[[[0, 0, 0], [0, 0, 1]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 1, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [0, 1, 0]], [[0, 0, 0], [0, 0, 0]]]],\\n\",\n       \" 'CorrJK': [[[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 1], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]]],\\n\",\n       \" 'CorrJI': [[[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 1], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]]],\\n\",\n       \" 'CorrKI': [[[[1, 0, 1], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[1, 0, 1], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[1, 1, 1], [0, 0, 1]], [[1, 1, 1], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [1, 1, 1]], [[0, 0, 0], [1, 1, 0]]]],\\n\",\n       \" 'CorrKJ': [[[[0, 0, 1], [0, 0, 0]], [[1, 1, 1], [0, 0, 0]]],\\n\",\n       \"  [[[1, 1, 1], [1, 1, 1]], [[0, 1, 1], [0, 0, 0]]],\\n\",\n       \"  [[[1, 0, 1], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]]],\\n\",\n       \"  [[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [1, 1, 0]]]]}\"\n      ]\n     },\n     \"execution_count\": 14,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"result.lasre\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Post-process and Output LaS\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"We provide a few rewrite passes to remove valid but unnecessary structures in the solution, and also color the K-pipes.\\n\",\n    \"These can be applied with the follow call. \"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 15,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"result = result.after_default_optimizations()\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"We can export the result to a few formats.\\n\",\n    \"The most direct one is to save the LaSRe, which is now just a dictionary\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 16,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"result.save_lasre(\\\"cnot.lasre.json\\\")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"We can also create a 3D modelling file in the [GLTF](https://www.khronos.org/gltf/) format.\\n\",\n    \"This can be opened in many software, a lot of them are also web-based.\\n\",\n    \"The `attach_axes` flag attaches I (red), J (green), and K (blue) axis to the GLTF.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 17,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"result.to_3d_model_gltf(\\\"cnot.gltf\\\", attach_axes=True)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Like mentioned previously, the generated LaS can be easily mapped to a ZX-diagram.\\n\",\n    \"We can use this connection to verify our result.\\n\",\n    \"Internally, we construct the ZX-diagram and let [Stim ZX](https://github.com/quantumlib/Stim/tree/main/glue/zx) to derive the stabilizers.\\n\",\n    \"Then, we check whether these stabilizers are commutable with the ones in the specification.\\n\",\n    \"If all are commutable, then our LaS is correct.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 18,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"specified:\\n\",\n      \"+Z_Z_\\n\",\n      \"+_ZZZ\\n\",\n      \"+X_XX\\n\",\n      \"+_X_X\\n\",\n      \"==============================================================\\n\",\n      \"resulting:\\n\",\n      \"+X_XX\\n\",\n      \"+Z_Z_\\n\",\n      \"+_X_X\\n\",\n      \"+_ZZZ\\n\",\n      \"==============================================================\\n\",\n      \"specified and resulting stabilizers are equivalent.\\n\"\n     ]\n    },\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"True\"\n      ]\n     },\n     \"execution_count\": 18,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"result.verify_stabilizers_stimzx(specification=input_dict, print_stabilizers=True)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Using Other SAT solver\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"So far, we are using the [Z3 SMT solver](https://github.com/Z3Prover/z3) to do everything.\\n\",\n    \"In our experience, it may be faster to generate an SAT problem with Z3 and solve it using other solvers, like Kissat.\\n\",\n    \"For the user, it is very easy to change: just initiate the `LatticeSurgerySynthesizer` with the directory where Kissat is installed in your system.\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 19,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"las_synth = LatticeSurgerySynthesizer(solver=\\\"kissat\\\", kissat_dir=\\\"\\\")\\n\",\n    \"# you need to add the kissat dir based on where kissat is on your computer\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 20,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Adding constraints time: 0.207474946975708\\n\",\n      \"CNF generation time: 0.004982948303222656\\n\",\n      \"c ---- [ banner ] ------------------------------------------------------------\\n\",\n      \"c\\n\",\n      \"c Kissat SAT Solver\\n\",\n      \"c \\n\",\n      \"c Copyright (c) 2021-2023 Armin Biere University of Freiburg\\n\",\n      \"c Copyright (c) 2019-2021 Armin Biere Johannes Kepler University Linz\\n\",\n      \"c \\n\",\n      \"c Version 3.1.1 71caafb4d182ced9f76cef45b00f37cc598f2a37\\n\",\n      \"c Apple clang version 15.0.0 (clang-1500.3.9.4) -W -Wall -O3 -DNDEBUG\\n\",\n      \"c Sun May 12 13:03:10 PDT 2024 Darwin MacBook-Pro-2 23.4.0 arm64\\n\",\n      \"c\\n\",\n      \"c ---- [ parsing ] -----------------------------------------------------------\\n\",\n      \"c\\n\",\n      \"c opened and reading DIMACS file:\\n\",\n      \"c\\n\",\n      \"c   cnot.dimacs\\n\",\n      \"c\\n\",\n      \"c parsed 'p cnf 462 2231' header\\n\",\n      \"c closing input after reading 40739 bytes (40 KB)\\n\",\n      \"c finished parsing after 0.00 seconds\\n\",\n      \"c\\n\",\n      \"c ---- [ options ] -----------------------------------------------------------\\n\",\n      \"c\\n\",\n      \"c --seed=916189                    (different from default '0')\\n\",\n      \"c\\n\",\n      \"c ---- [ solving ] -----------------------------------------------------------\\n\",\n      \"c\\n\",\n      \"c  seconds switched conflicts irredundant variables\\n\",\n      \"c         MB reductions redundant    trail   remaining\\n\",\n      \"c          level restarts   binary      glue\\n\",\n      \"c\\n\",\n      \"c *  0.00  2 0 0 0  0   0   0 614 1557 0% 0 402 87%\\n\",\n      \"c {  0.00  2 0 0 0  0   0   0 614 1557 0% 0 402 87%\\n\",\n      \"c i  0.00  2 22 0 0  0  38  23 623 1556 44% 2 398 86%\\n\",\n      \"c i  0.00  2 22 0 0  0  39  23 623 1556 44% 2 397 86%\\n\",\n      \"c }  0.00  2 22 0 0  0  39  23 623 1556 44% 2 397 86%\\n\",\n      \"c 1  0.00  2 22 0 0  0  39  23 623 1556 44% 2 397 86%\\n\",\n      \"c\\n\",\n      \"c ---- [ result ] ------------------------------------------------------------\\n\",\n      \"c\\n\",\n      \"s SATISFIABLE\\n\",\n      \"v 1 -2 -3 -4 5 -6 -7 -8 9 10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22\\n\",\n      \"v 23 -24 -25 -26 -27 28 -29 -30 -31 -32 33 -34 35 -36 37 38 39 40 41 42 43 44\\n\",\n      \"v 45 46 47 48 -49 50 -51 -52 -53 54 -55 -56 -57 -58 -59 60 -61 62 -63 64 65\\n\",\n      \"v -66 -67 -68 69 -70 71 -72 -73 -74 75 -76 -77 -78 79 -80 -81 -82 -83 -84 85\\n\",\n      \"v 86 -87 -88 -89 90 91 92 93 94 95 -96 -97 -98 99 100 101 -102 -103 -104 -105\\n\",\n      \"v -106 -107 -108 109 110 111 112 113 -114 115 116 117 118 119 120 121 122 -123\\n\",\n      \"v -124 -125 -126 127 128 129 130 131 132 133 134 135 -136 137 -138 139 -140\\n\",\n      \"v 141 142 143 -144 145 -146 147 148 -149 -150 -151 152 153 154 -155 -156 -157\\n\",\n      \"v 158 159 160 -161 -162 163 -164 165 166 -167 168 169 -170 171 172 173 174\\n\",\n      \"v -175 176 177 178 179 180 -181 182 183 184 185 -186 187 188 189 190 191 192\\n\",\n      \"v 193 -194 -195 196 197 198 -199 -200 201 202 -203 204 205 206 207 208 209\\n\",\n      \"v -210 -211 212 213 214 215 216 217 218 219 -220 221 -222 -223 -224 225 226\\n\",\n      \"v 227 228 -229 230 -231 232 -233 234 235 236 -237 -238 239 240 241 242 243\\n\",\n      \"v -244 245 246 247 -248 249 -250 251 -252 -253 254 255 256 257 258 -259 260\\n\",\n      \"v 261 262 263 -264 -265 266 267 268 -269 270 -271 272 273 -274 275 276 277 278\\n\",\n      \"v 279 280 281 282 283 284 -285 286 -287 288 289 290 -291 292 293 -294 -295 296\\n\",\n      \"v 297 -298 299 300 301 302 303 -304 305 -306 307 -308 309 -310 311 312 313\\n\",\n      \"v -314 315 -316 317 318 319 -320 321 322 323 -324 -325 326 327 328 -329 330\\n\",\n      \"v 331 332 333 334 335 336 -337 -338 339 340 341 -342 -343 344 345 346 347 348\\n\",\n      \"v 349 350 351 352 353 354 355 -356 357 -358 359 -360 361 362 363 -364 365 -366\\n\",\n      \"v 367 368 369 -370 371 -372 373 -374 -375 376 -377 378 -379 380 -381 382 -383\\n\",\n      \"v -384 385 386 -387 388 389 390 391 392 393 394 395 -396 -397 398 -399 400\\n\",\n      \"v -401 402 403 -404 405 406 407 408 -409 -410 411 412 413 414 415 -416 -417\\n\",\n      \"v 418 -419 420 421 422 423 424 425 426 427 428 429 430 -431 432 433 434 435\\n\",\n      \"v 436 437 438 439 -440 441 442 443 444 445 446 447 448 -449 450 451 452 453\\n\",\n      \"v 454 455 456 457 -458 459 -460 461 462 0\\n\",\n      \"c\\n\",\n      \"c ---- [ profiling ] ---------------------------------------------------------\\n\",\n      \"c\\n\",\n      \"c           0.00   39.95 %  parse\\n\",\n      \"c           0.00   36.66 %  search\\n\",\n      \"c           0.00   34.35 %  focused\\n\",\n      \"c           0.00    0.00 %  simplify\\n\",\n      \"c =============================================\\n\",\n      \"c           0.00  100.00 %  total\\n\",\n      \"c\\n\",\n      \"c ---- [ statistics ] --------------------------------------------------------\\n\",\n      \"c\\n\",\n      \"c conflicts:                               39            12268.01 per second\\n\",\n      \"c decisions:                              186                4.77 per conflict\\n\",\n      \"c jumped_reasons:                        1002               29 %  propagations\\n\",\n      \"c propagations:                          3417          1074866    per second\\n\",\n      \"c queue_decisions:                        186              100 %  decision\\n\",\n      \"c random_decisions:                         0                0 %  decision\\n\",\n      \"c random_sequences:                         0                0    interval\\n\",\n      \"c score_decisions:                          0                0 %  decision\\n\",\n      \"c switched:                                 0                0    interval\\n\",\n      \"c vivify_checks:                            0                0    per vivify\\n\",\n      \"c vivify_units:                             0                0 %  variables\\n\",\n      \"c\\n\",\n      \"c ---- [ resources ] ---------------------------------------------------------\\n\",\n      \"c\\n\",\n      \"c maximum-resident-set-size:       1828716544 bytes       1744 MB\\n\",\n      \"c process-time:                                              0.00 seconds\\n\",\n      \"c\\n\",\n      \"c ---- [ shutting down ] -----------------------------------------------------\\n\",\n      \"c\\n\",\n      \"c exit 10\\n\",\n      \"kissat runtime: 0.008579015731811523\\n\",\n      \"kissat SAT!\\n\",\n      \"Construct a Z3 SMT model and solve...\\n\",\n      \"elapsed time: 0.021113s\\n\",\n      \"Z3 SAT\\n\",\n      \"Total solving time: 0.04399609565734863\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"result = las_synth.solve(\\n\",\n    \"    specification=input_dict,\\n\",\n    \"    print_detail=True,\\n\",\n    \"    dimacs_file_name=\\\"cnot\\\",\\n\",\n    \"    sat_log_file_name=\\\"cnot\\\"\\n\",\n    \")\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"We used a few optional arguments above.\\n\",\n    \"`print_detail` will display the output of Kissat on the screen. \\n\",\n    \"`dimacs_file_name` specifies where to store the SAT problem instance in the DIMACS format.\\n\",\n    \"This instance is generated by Z3 and then solved by Kissat.\\n\",\n    \"`sat_log_file_name` saves the output of Kissat, which is basically what you have seen as the output (from `c ---- [ banner ]` to `c exit 10`).\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3 (ipykernel)\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.8.19\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 4\n}\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/__init__.py",
    "content": "from .lattice_surgery_synthesis import LatticeSurgerySynthesizer\nfrom .lattice_surgery_synthesis import LatticeSurgerySolution\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/lattice_surgery_synthesis.py",
    "content": "\"\"\"Two wrapper classes, rewrite passes, and translators.\"\"\"\n\nimport functools\nimport itertools\nimport json\nimport time\nimport multiprocessing\nimport random\nimport networkx\nfrom typing import Any, Literal, Mapping, Optional, Sequence\nfrom lassynth.rewrite_passes.attach_fixups import attach_fixups\nfrom lassynth.rewrite_passes.color_z import color_z\nfrom lassynth.rewrite_passes.remove_unconnected import remove_unconnected\nfrom lassynth.sat_synthesis.lattice_surgery_sat import LatticeSurgerySAT\nfrom lassynth.tools.verify_stabilizers import verify_stabilizers\nfrom lassynth.translators.gltf_generator import gltf_generator\nfrom lassynth.translators.textfig_generator import textfig_generator\nfrom lassynth.translators.zx_grid_graph import ZXGridGraph\nfrom lassynth.translators.networkx_generator import networkx_generator\n\n\ndef check_lasre(lasre: Mapping[str, Any]) -> None:\n    \"\"\"check aspects of LaSRe other than SMT constraints, i.e., data layout.\"\"\"\n    if \"n_i\" not in lasre:\n        raise ValueError(\n            f\"upper bound of I dimension, `n_i`, is missing in lasre.\")\n    if lasre[\"n_i\"] <= 0:\n        raise ValueError(\"n_i <= 0.\")\n    if \"n_j\" not in lasre:\n        raise ValueError(\n            f\"upper bound of J dimension, `n_j`, is missing in lasre.\")\n    if lasre[\"n_j\"] <= 0:\n        raise ValueError(\"n_j <= 0.\")\n    if \"n_k\" not in lasre:\n        raise ValueError(\n            f\"upper bound of K dimension, `n_k`, is missing in lasre.\")\n    if lasre[\"n_k\"] <= 0:\n        raise ValueError(\"n_k <= 0.\")\n    if \"n_p\" not in lasre:\n        raise ValueError(f\"number of ports, `n_p`, is missing in lasre.\")\n    if lasre[\"n_p\"] <= 0:\n        raise ValueError(\"n_p <= 0.\")\n    if \"n_s\" not in lasre:\n        raise ValueError(f\"number of stabilizers, `n_s`, is missing in lasre.\")\n    if lasre[\"n_s\"] < 0:\n        raise ValueError(\"n_s < 0.\")\n    if lasre[\"n_s\"] == 0:\n        print(\"no stabilizer!\")\n\n    if \"ports\" not in lasre:\n        raise ValueError(f\"`ports` is missing in lasre.\")\n    if len(lasre[\"ports\"]) != lasre[\"n_p\"]:\n        raise ValueError(\"number of ports in `ports` is different from `n_p`.\")\n    for port in lasre[\"ports\"]:\n        if \"i\" not in port:\n            raise ValueError(f\"location `i` missing from port {port}.\")\n        if port[\"i\"] not in range(lasre[\"n_i\"]):\n            raise ValueError(f\"i out of range in port {port}.\")\n        if \"j\" not in port:\n            raise ValueError(f\"location `j` missing from port {port}.\")\n        if port[\"j\"] not in range(lasre[\"n_j\"]):\n            raise ValueError(f\"j out of range in port {port}.\")\n        if \"k\" not in port:\n            raise ValueError(f\"location `k` missing from port {port}.\")\n        if port[\"k\"] not in range(lasre[\"n_k\"]):\n            raise ValueError(f\"k out of range in port {port}.\")\n        if \"d\" not in port:\n            raise ValueError(f\"direction `d` missing from port {port}.\")\n        if port[\"d\"] not in [\"I\", \"J\", \"K\"]:\n            raise ValueError(f\"direction not I, J, or K in port {port}.\")\n        if \"e\" not in port:\n            raise ValueError(f\"open end `e` missing from port {port}.\")\n        if port[\"e\"] not in [\"-\", \"+\"]:\n            raise ValueError(f\"open end not - or + in port {port}.\")\n        if \"c\" not in port:\n            raise ValueError(f\"color `c` missing from port {port}.\")\n        if port[\"c\"] not in [0, 1]:\n            raise ValueError(f\"color not 0 or 1 in port {port}.\")\n\n    if \"stabs\" not in lasre:\n        raise ValueError(f\"`stabs` is missing in lasre.\")\n    if len(lasre[\"stabs\"]) != lasre[\"n_s\"]:\n        raise ValueError(\"number of stabs in `stabs` is different from `n_s`.\")\n    for stab in lasre[\"stabs\"]:\n        if len(stab) != lasre[\"n_p\"]:\n            raise ValueError(\"number of boundary corrsurf is not `n_p`.\")\n        for i, corrsurf in enumerate(stab):\n            for (k, v) in corrsurf.items():\n                if lasre[\"ports\"][i][\"d\"] == \"I\" and k not in [\"IJ\", \"IK\"]:\n                    raise ValueError(f\"stabs[{i}] key invalid {stab}.\")\n                if lasre[\"ports\"][i][\"d\"] == \"J\" and k not in [\"JI\", \"JK\"]:\n                    raise ValueError(f\"stabs[{i}] key invalid {stab}.\")\n                if lasre[\"ports\"][i][\"d\"] == \"K\" and k not in [\"KI\", \"KJ\"]:\n                    raise ValueError(f\"stabs[{i}] key invalid {stab}.\")\n                if v not in [0, 1]:\n                    raise ValueError(f\"stabs[{i}] value not 0 or 1 {stab}.\")\n\n    port_cubes = []\n    for p in lasre[\"ports\"]:\n        # if e=-, (i,j,k); otherwise, +1 in the proper direction\n        if p[\"e\"] == \"-\":\n            port_cubes.append((p[\"i\"], p[\"j\"], p[\"k\"]))\n        elif p[\"d\"] == \"I\":\n            port_cubes.append((p[\"i\"] + 1, p[\"j\"], p[\"k\"]))\n        elif p[\"d\"] == \"J\":\n            port_cubes.append((p[\"i\"], p[\"j\"] + 1, p[\"k\"]))\n        elif p[\"d\"] == \"K\":\n            port_cubes.append((p[\"i\"], p[\"j\"], p[\"k\"] + 1))\n    lasre[\"port_cubes\"] = port_cubes\n\n    if \"optional\" not in lasre:\n        lasre[\"optional\"] = {}\n\n    for key in [\n            \"NodeY\",\n            \"ExistI\",\n            \"ExistJ\",\n            \"ExistK\",\n            \"ColorI\",\n            \"ColorJ\",\n    ]:\n        if key not in lasre:\n            raise ValueError(f\"`{key}` missing from lasre.\")\n        if len(lasre[key]) != lasre[\"n_i\"]:\n            raise ValueError(f\"dimension of {key} is wrong.\")\n        for tmp in lasre[key]:\n            if len(tmp) != lasre[\"n_j\"]:\n                raise ValueError(f\"dimension of {key} is wrong.\")\n            for tmptmp in tmp:\n                if len(tmptmp) != lasre[\"n_k\"]:\n                    raise ValueError(f\"dimension of {key} is wrong.\")\n\n    if lasre[\"n_s\"] > 0:\n        for key in [\n                \"CorrIJ\",\n                \"CorrIK\",\n                \"CorrJI\",\n                \"CorrJK\",\n                \"CorrKI\",\n                \"CorrKJ\",\n        ]:\n            if key not in lasre:\n                raise ValueError(f\"`{key}` missing from lasre.\")\n            if len(lasre[key]) != lasre[\"n_s\"]:\n                raise ValueError(f\"dimension of {key} is wrong.\")\n            for tmp in lasre[key]:\n                if len(tmp) != lasre[\"n_i\"]:\n                    raise ValueError(f\"dimension of {key} is wrong.\")\n                for tmptmp in tmp:\n                    if len(tmptmp) != lasre[\"n_j\"]:\n                        raise ValueError(f\"dimension of {key} is wrong.\")\n                    for tmptmptmp in tmptmp:\n                        if len(tmptmptmp) != lasre[\"n_k\"]:\n                            raise ValueError(f\"dimension of {key} is wrong.\")\n\n\nclass LatticeSurgerySolution:\n    \"\"\"A class for the result of synthesizer lattice surgery subroutine. \n\n    It internally saves an LaSRe (Lattice Surgery Subroutine Representation)\n    and we can apply rewrite passes to it, or use translators to derive\n    other formats of the LaS solution\n    \"\"\"\n\n    def __init__(\n        self,\n        lasre: Mapping[str, Any],\n    ) -> None:\n        \"\"\"initialization for LatticeSurgerySubroutine\n\n        Args:\n            lasre (Mapping[str, Any]): LaSRe\n        \"\"\"\n        check_lasre(lasre)\n        self.lasre = lasre\n\n    def get_depth(self) -> int:\n        \"\"\"get the depth/height of the LaS in LaSRe.\n\n        Returns:\n            int: depth/height of the LaS in LaSRe\n        \"\"\"\n        return self.lasre[\"n_k\"]\n\n    def after_removing_disconnected_pieces(self):\n        \"\"\"remove_unconnected.\"\"\"\n        return LatticeSurgerySolution(lasre=remove_unconnected(self.lasre))\n\n    def after_color_k_pipes(self):\n        \"\"\"coloring K pipes.\"\"\"\n        return LatticeSurgerySolution(lasre=color_z(self.lasre))\n\n    def after_default_optimizations(self):\n        \"\"\"default optimizations: remove unconnected, and then color K pipes.\"\"\"\n        solution = LatticeSurgerySolution(lasre=remove_unconnected(self.lasre))\n        solution = LatticeSurgerySolution(lasre=color_z(solution.lasre))\n        return solution\n\n    def after_t_factory_default_optimizations(self):\n        \"\"\"default optimization for T-factories.\"\"\"\n        solution = LatticeSurgerySolution(lasre=remove_unconnected(self.lasre))\n        solution = LatticeSurgerySolution(lasre=color_z(solution.lasre))\n        solution = LatticeSurgerySolution(lasre=attach_fixups(solution.lasre))\n        return solution\n\n    def save_lasre(self, file_name: str) -> None:\n        \"\"\"save the current LaSRe to a file.\n\n        Args:\n            file_name (str): file name including extension to save the LaSRe\n        \"\"\"\n        with open(file_name, \"w\") as f:\n            json.dump(self.lasre, f)\n\n    def to_3d_model_gltf(self,\n                         output_file_name: str,\n                         stabilizer: int = -1,\n                         tube_len: float = 2.0,\n                         no_color_z: bool = False,\n                         attach_axes: bool = False,\n                         rm_dir: Optional[str] = None) -> None:\n        \"\"\"generate gltf file (for 3D modelling).\n\n        Args:\n            output_file_name (str): file name including extension to save gltf\n            stabilizer (int, optional): Defaults to -1 meaning do not draw\n                correlation surfaces. If the value is in [0, n_s),\n                the correlation surfaces corresponding to that stabilizer\n                are drawn and faces in one of the directions are revealed\n                to unveil the correlation surfaces.\n            tube_len (float, optional): Length of the pipe comapred to\n                the cube. Defaults to 2.0.\n            no_color_z (bool, optional): Do not color the K pipes.\n                Defaults to False.\n            attach_axes (bool, optional): attach IJK axes. Defaults to False.\n                If attached, the color coding is I->red, J->green, K->blue.\n            rm_dir (str, optional): the (+|-)(I|J|K) faces to remove.\n                Intended to reveal correlation surfaces. Default to None.\n        \"\"\"\n        gltf = gltf_generator(\n            self.lasre,\n            stabilizer=stabilizer,\n            tube_len=tube_len,\n            no_color_z=no_color_z,\n            attach_axes=attach_axes,\n            rm_dir=rm_dir if rm_dir else (\":+J\" if stabilizer >= 0 else None),\n        )\n        with open(output_file_name, \"w\") as f:\n            json.dump(gltf, f)\n\n    def to_zigxag_url(\n        self,\n        io_spec: Optional[Sequence[str]] = None,\n    ) -> str:\n        \"\"\"generate a link that leads to a ZigXag figure.\n\n        Args:\n            io_spec (Optional[Sequence[str]], optional): Specify whether\n            each port is an input or an output. Length must be the same\n            with the number of ports. Defaults to None, which means\n            all ports are outputs.\n\n        Returns:\n            str: the ZigXag link\n        \"\"\"\n        zxgridgraph = ZXGridGraph(self.lasre)\n        return zxgridgraph.to_zigxag_url(io_spec=io_spec)\n\n    def to_text_diagram(self) -> str:\n        \"\"\"generate the text figure of LaS time slices.\n\n        Returns:\n            str: text figure of the LaS\n        \"\"\"\n        return textfig_generator(self.lasre)\n\n    def to_networkx_graph(self) -> networkx.Graph:\n        \"\"\"generate a annotated networkx.Graph correponding to the LaS.\n\n        Returns:\n            networkx.Graph:\n        \"\"\"\n        return networkx_generator(self.lasre)\n\n    def verify_stabilizers_stimzx(self,\n                                  specification: Mapping[str, Any],\n                                  print_stabilizers: bool = False) -> bool:\n        \"\"\"verify the stabilizer of the LaS.\n\n        Use StimZX to deduce the stabilizers from the annotated networkx graph.\n        Then use Stim to ensure that this set of stabilizers and the set of\n        stabilizers specified in the input are equivalent.\n\n        Args:\n            specification (Mapping[str, Any]): the LaS specification to verify\n                the current solution against.\n            print_stabilizers (bool, optional): If True, print the two sets of\n                stabilizers. Defaults to False.\n\n        Returns:\n            bool: True if the two sets are equivalent; otherwise False.\n        \"\"\"\n        paulistrings = [\n            paulistring.replace(\".\", \"_\")\n            for paulistring in specification[\"stabilizers\"]\n        ]\n        return verify_stabilizers(\n            paulistrings,\n            self.to_networkx_graph(),\n            print_stabilizers=print_stabilizers,\n        )\n\n\nclass LatticeSurgerySynthesizer:\n    \"\"\"A class to synthesize LaS.\"\"\"\n\n    def __init__(\n        self,\n        solver: Literal[\"kissat\", \"z3\"] = \"z3\",\n        kissat_dir: Optional[str] = None,\n    ) -> None:\n        \"\"\"initialize.\n\n        Args:\n            solver (Literal[\"kissat\", \"z3\"], optional): the solver to use.\n                Defaults to \"z3\". \"kissat\" is recommended.\n            kissat_dir (Optional[str], optional): directory of the kissat\n                executable. Defaults to None.\n        \"\"\"\n        self.solver = solver\n        self.kissat_dir = kissat_dir\n\n    def solve(\n        self,\n        specification: Mapping[str, Any],\n        given_arrs: Optional[Mapping[str, Any]] = None,\n        given_vals: Optional[Sequence[Mapping[str, Any]]] = None,\n        print_detail: bool = False,\n        dimacs_file_name: Optional[str] = None,\n        sat_log_file_name: Optional[str] = None,\n    ) -> Optional[LatticeSurgerySolution]:\n        \"\"\"solve an LaS synthesis problem.\n\n        Args:\n            specification (Mapping[str, Any]): the LaS specification to solve.\n            given_arrs (Optional[Mapping[str, Any]], optional): given array of\n                known values to plug in. Defaults to None.\n            given_vals (Optional[Sequence[Mapping[str, Any]]], optional): given\n                known values to plug in. Defaults to None. Format should be\n                a sequence of dicts. Each one contains three fields: \"array\",\n                the name of the array, e.g., \"ExistI\"; \"indices\", a sequence of\n                the indices, e.g., [0, 0, 0]; and \"value\", 0 or 1.\n            print_detail (bool, optional): whether to print details in\n                SAT solving. Defaults to False.\n            dimacs_file_name (Optional[str], optional): file to save the\n                DIMACS. Defaults to None.\n            sat_log_file_name (Optional[str], optional): file to save the\n                SAT solver log. Defaults to None.\n\n        Returns:\n            Optional[LatticeSurgerySubroutine]: if the problem is\n                unsatisfiable, this is None; otherwise, a\n                LatticeSurgerySolution initialized by the compiled result.\n        \"\"\"\n        start_time = time.time()\n        sat_synthesis = LatticeSurgerySAT(\n            input_dict=specification,\n            given_arrs=given_arrs,\n            given_vals=given_vals,\n        )\n        if print_detail:\n            print(f\"Adding constraints time: {time.time() - start_time}\")\n\n        start_time = time.time()\n        if self.solver == \"z3\":\n            if_sat = sat_synthesis.check_z3(print_progress=print_detail)\n        else:\n            if_sat = sat_synthesis.check_kissat(\n                dimacs_file_name=dimacs_file_name,\n                sat_log_file_name=sat_log_file_name,\n                print_progress=print_detail,\n                kissat_dir=self.kissat_dir,\n            )\n        if print_detail:\n            print(f\"Total solving time: {time.time() - start_time}\")\n\n        if if_sat:\n            solver_result = sat_synthesis.get_result()\n            return LatticeSurgerySolution(lasre=solver_result)\n        else:\n            return None\n\n    def optimize_depth(\n        self,\n        specification: Mapping[str, Any],\n        start_depth: Optional[int] = None,\n        print_detail: bool = False,\n        dimacs_file_name_prefix: Optional[str] = None,\n        sat_log_file_name_prefix: Optional[str] = None,\n    ) -> LatticeSurgerySolution:\n        \"\"\"find the optimal solution in terms of depth/height of the LaS.\n\n    Args:\n        specification (Mapping[str, Any]): the LaS specification to solve.\n        start_depth (int, optional): starting depth of the exploration. If not\n            provided, use the depth given in the specification\n        print_detail (bool, optional): whether to print details in SAT solving.\n            Defaults to False.\n        dimacs_file_name_prefix (Optional[str], optional): file prefix to save\n            the DIMACS. The full file name will contain the specific depth\n            after this prefix. Defaults to None.\n        sat_log_file_name_prefix (Optional[str], optional): file prefix to save\n            the SAT log. The full file name will contain the specific depth\n            after this prefix. Defaults to None.\n        result_file_name_prefix (Optional[str], optional): file prefix to save\n            the variable assignments. The full file name will contain the\n            specific depth after this prefix. Defaults to None.\n        post_optimization (str, optional): optimization to perform when\n            initializing the LatticeSurgerySubroutine object for the result.\n            Defaults to \"default\".\n\n    Raises:\n        ValueError: starting depth is too low.\n\n    Returns:\n        LatticeSurgerySolution: compiled result with the optimal depth.\n    \"\"\"\n        self.specification = dict(specification)\n        if start_depth is None:\n            depth = self.specification[\"max_k\"]\n        else:\n            depth = int(start_depth)\n        if depth < 2:\n            raise ValueError(\"depth too low.\")\n\n        checked_depth = {}\n        while True:\n            # the ports on the top floor will still be on the top floor when we\n            # increase the height. This is an assumption. Adapt to your case.\n            for port in self.specification[\"ports\"]:\n                if port[\"location\"][2] == self.specification[\"max_k\"]:\n                    port[\"location\"][2] = depth\n            self.specification[\"max_k\"] = depth\n\n            result = self.solve(\n                specification=self.specification,\n                print_detail=print_detail,\n                dimacs_file_name=dimacs_file_name_prefix +\n                f\"_d={depth}\" if dimacs_file_name_prefix else None,\n                sat_log_file_name=sat_log_file_name_prefix +\n                f\"_d={depth}\" if sat_log_file_name_prefix else None,\n            )\n            if result is None:\n                checked_depth[str(depth)] = \"UNSAT\"\n                if str(depth + 1) in checked_depth:\n                    # since this depth leads to UNSAT, we need to increase\n                    # the depth, but if depth+1 is already checked, we can stop\n                    break\n                else:\n                    depth += 1\n            else:\n                checked_depth[str(depth)] = \"SAT\"\n                self.sat_result = LatticeSurgerySolution(lasre=result.lasre)\n                if str(depth - 1) in checked_depth:\n                    # since this depth leads to SAT, we need to try decreasing\n                    # the depth, but if depth-1 is already checked, we can stop\n                    break\n                else:\n                    depth -= 1\n\n        return self.sat_result\n\n    def try_one_permutation(\n        self,\n        perm: Sequence[int],\n        specification: Mapping[str, Any],\n        print_detail: bool = False,\n        dimacs_file_name_prefix: Optional[str] = None,\n        sat_log_file_name_prefix: Optional[str] = None,\n    ) -> Optional[LatticeSurgerySolution]:\n        \"\"\"check if the problem is satisfiable given a port permutation.\n\n        Args:\n            specification (Mapping[str, Any]): the LaS specification to solve.\n            perm (Sequence[int]): the given permutation, which is an integer\n                tuple of length n (n being the number of ports permuted).\n            print_detail (bool, optional): whether to print details in\n                SAT solving. Defaults to False.\n            dimacs_file_name_prefix (Optional[str], optional): file prefix\n                to save the DIMACS. The full file name will contain the\n                specific permutation after this prefix. Defaults to None.\n            sat_log_file_name_prefix (Optional[str], optional): file prefix\n                to save the SAT log. The full file name will contain the\n                specific permutation after this prefix. Defaults to None.\n\n        Returns:\n            Optional[LatticeSurgerySubroutine]: if the problem is\n                unsatisfiable, this is None; otherwise, a\n                LatticeSurgerySolution initialized by the compiled result.\n        \"\"\"\n\n        # say `perm` is [0,3,2], then `original` is in order, i.e., [0,2,3]\n        # the full permutation is 0,1,2,3 -> 0,1,3,2\n        original = sorted(perm)\n        this_spec = dict(specification)\n        new_ports = []\n        for p, port in enumerate(specification[\"ports\"]):\n            if p not in perm:\n                # the p-th port is not involved in `perm`, e.g., 1 is unchanged\n                new_ports.append(port)\n\n            else:\n                # after the permutation, the index of the p-th port in\n                # specification is the k-th port in `perm` where k is the place\n                # of p in `original`. In this example, when p=0 and 1, nothing\n                # changed. When p=2, we find `place` to be 1, and perm[place]=3\n                # so we attach port_3. When p=3, we end up attach port_2\n                place = original.index(p)\n                new_ports.append(specification[\"ports\"][perm[place]])\n        this_spec[\"ports\"] = new_ports\n\n        result = self.solve(\n            specification=this_spec,\n            print_detail=print_detail,\n            dimacs_file_name=dimacs_file_name_prefix + \"_\" +\n            perm.__repr__().replace(\" \", \"\")\n            if dimacs_file_name_prefix else None,\n            sat_log_file_name=sat_log_file_name_prefix + \"_\" +\n            perm.__repr__().replace(\" \", \"\")\n            if sat_log_file_name_prefix else None,\n        )\n        print(f\"{perm}: {'SAT' if result else 'UNSAT'}\")\n        return result\n\n    def solve_all_port_permutations(\n        self,\n        permute_ports: Sequence[int],\n        parallelism: int = 1,\n        shuffle: bool = True,\n        **kwargs,\n    ) -> Mapping[str, Sequence[Sequence[int]]]:\n        \"\"\"try all the permutations of given ports, which ones are satisfiable.\n\n        Note that we do not check that the LaS after permuting the ports (we do\n        not permute the stabilizers accordingly) is functionally equivalent.\n        The user should use this method based on their judgement. Also, the\n        number of permutations scales exponentially with the number of ports\n        to permute, so this method can easily take an immense amount of time.\n\n        Args:\n            permute_ports (Sequence[int]): the indices of ports to permute\n            parallelism (int, optional): number of parallel process. Each one\n                try one permutation. A New proess starts when an old one\n                finishes. Defaults to 1.\n            shuffle (bool, optional): whether using a random order to start the\n                processes. Defaults to True.\n            **kwargs: other arguments to `try_one_permutation`.\n\n        Returns:\n            Mapping[str, Sequence[Sequence[int]]]: a dict with two keys.\n                \"SAT\": [.] a list containing all the satisfiable permutations;\n                \"UNSAT\": [.] all the unsatisfiable permutations.\n        \"\"\"\n        perms = list(itertools.permutations(permute_ports))\n        if shuffle:\n            random.shuffle(perms)\n\n        pool = multiprocessing.Pool(parallelism)\n        # issue the job one by one (chuck=1)\n        results = pool.map(\n            functools.partial(\n                self.try_one_permutation,\n                **kwargs,\n            ),\n            perms,\n            chunksize=1,\n        )\n\n        sat_perms = []\n        unsat_perms = []\n        for p, result in enumerate(results):\n            if result is None:\n                unsat_perms.append(perms[p])\n            else:\n                sat_perms.append(perms[p])\n\n        return {\n            \"SAT\": sat_perms,\n            \"UNSAT\": unsat_perms,\n        }\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/rewrite_passes/__init__.py",
    "content": ""
  },
  {
    "path": "glue/lattice_surgery/lassynth/rewrite_passes/attach_fixups.py",
    "content": "\"\"\"assuming all T injections requiring fixup are on the top floor.\nThe output is also on the top floor\"\"\"\n\nfrom typing import Mapping, Any\n\n\ndef attach_fixups(lasre: Mapping[str, Any]) -> Mapping[str, Any]:\n    n_s = lasre[\"n_s\"]\n    n_i = lasre[\"n_i\"]\n    n_j = lasre[\"n_j\"]\n    n_k = lasre[\"n_k\"]\n\n    fixup_locs = []\n    for p in lasre[\"optional\"][\"top_fixups\"]:\n        fixup_locs.append((lasre[\"ports\"][p][\"i\"], lasre[\"ports\"][p][\"j\"]))\n\n    lasre[\"n_k\"] += 2\n    # we add two layers on the top. The lower layer will contain fixups dressed\n    # as Y cubes that is connecting downwards. The upper layer will contain no\n    # new cubes. This corresponds to waiting the machine to apply the fixups\n    # because there is a finite interaction time from the machine knows whether\n    # the injection is T or T^dagger to apply the fixups.\n    for i in range(n_i):\n        for j in range(n_j):\n            if (i, j) in fixup_locs:\n                lasre[\"NodeY\"][i][j].append(1)  # fixup dressed as Y cubes\n                lasre[\"ExistK\"][i][j][n_k - 1] = 1  # connect fixup downwards\n            else:\n                lasre[\"NodeY\"][i][j].append(0)  # no fixup\n                lasre[\"ExistK\"][i][j][n_k - 1] = 0\n            lasre[\"NodeY\"][i][j].append(0)  # the upper layer is empty\n\n            # do not add any new pipes in the added layer\n            for arr in [\"ExistI\", \"ExistJ\", \"ExistK\"]:\n                lasre[arr][i][j].append(0)\n                lasre[arr][i][j].append(0)\n            for arr in [\"ColorI\", \"ColorJ\", \"ColorKM\", \"ColorKP\"]:\n                lasre[arr][i][j].append(-1)\n                lasre[arr][i][j].append(-1)\n            for s in range(n_s):\n                for arr in [\n                        \"CorrIJ\", \"CorrIK\", \"CorrJK\", \"CorrJI\", \"CorrKI\",\n                        \"CorrKJ\"\n                ]:\n                    lasre[arr][s][i][j].append(0)\n                    lasre[arr][s][i][j].append(0)\n\n    # the output ports need to be extended in the two added layers\n    for port in lasre[\"ports\"]:\n        if \"f\" in port and port[\"f\"] == \"output\":\n            ii, jj = port[\"i\"], port[\"j\"]\n            lasre[\"ExistK\"][ii][jj][n_k - 1] = 1\n            lasre[\"ExistK\"][ii][jj][n_k] = 1\n            lasre[\"ExistK\"][ii][jj][n_k + 1] = 1\n            lasre[\"ColorKM\"][ii][jj][n_k] = lasre[\"ColorKP\"][ii][jj][n_k - 1]\n            lasre[\"ColorKM\"][ii][jj][n_k + 1] = lasre[\"ColorKM\"][ii][jj][n_k]\n            lasre[\"ColorKP\"][ii][jj][n_k] = lasre[\"ColorKM\"][ii][jj][n_k]\n            lasre[\"ColorKP\"][ii][jj][n_k + 1] = lasre[\"ColorKP\"][ii][jj][n_k]\n            for s in range(n_s):\n                lasre[\"CorrKI\"][s][ii][jj][n_k] = lasre[\"CorrKI\"][s][ii][jj][\n                    n_k - 1]\n                lasre[\"CorrKI\"][s][ii][jj][n_k +\n                                           1] = lasre[\"CorrKI\"][s][ii][jj][n_k]\n                lasre[\"CorrKJ\"][s][ii][jj][n_k] = lasre[\"CorrKJ\"][s][ii][jj][\n                    n_k - 1]\n                lasre[\"CorrKJ\"][s][ii][jj][n_k +\n                                           1] = lasre[\"CorrKJ\"][s][ii][jj][n_k]\n            port[\"k\"] += 2\n            new_cubes = []\n            for c in lasre[\"port_cubes\"]:\n                if c[0] == port[\"i\"] and c[1] == port[\"j\"]:\n                    new_cubes.append((c[0], c[1], port[\"k\"] + 1))\n                else:\n                    new_cubes.append(c)\n            lasre[\"port_cubes\"] = new_cubes\n\n    t_injections = []\n    for port in lasre[\"ports\"]:\n        if port[\"f\"] == \"T\":\n            if port[\"e\"] == \"+\":\n                t_injections.append([port[\"i\"], port[\"j\"], port[\"k\"] + 1])\n            else:\n                t_injections.append([port[\"i\"], port[\"j\"], port[\"k\"]])\n    lasre[\"optional\"][\"t_injections\"] = t_injections\n\n    return lasre\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/rewrite_passes/color_z.py",
    "content": "\"\"\"We do not have ColorZ from the SAT/SMT. Now we color the Z-pipes.\"\"\"\n\nfrom typing import Sequence, Mapping, Any, Union, Tuple\n\n\ndef if_uncolorK(n_i: int, n_j: int, n_k: int,\n                ExistK: Sequence[Sequence[Sequence[int]]],\n                ColorKP: Sequence[Sequence[Sequence[int]]],\n                ColorKM: Sequence[Sequence[Sequence[int]]]) -> bool:\n    \"\"\"return whether there are uncolored K-pipes\"\"\"\n    for i in range(n_i):\n        for j in range(n_j):\n            for k in range(n_k):\n                if ExistK[i][j][k] and (ColorKP[i][j][k] == -1\n                                        or ColorKM[i][j][k] == -1):\n                    return True\n    return False\n\n\ndef in_bound(n_i: int, n_j: int, n_k: int, i: int, j: int, k: int) -> bool:\n    if i in range(n_i) and j in range(n_j) and k in range(n_k):\n        return True\n    return False\n\n\ndef propogate_IJcolor(n_i: int, n_j: int, n_k: int,\n                      ExistI: Sequence[Sequence[Sequence[int]]],\n                      ExistJ: Sequence[Sequence[Sequence[int]]],\n                      ExistK: Sequence[Sequence[Sequence[int]]],\n                      ColorI: Sequence[Sequence[Sequence[int]]],\n                      ColorJ: Sequence[Sequence[Sequence[int]]],\n                      ColorKP: Sequence[Sequence[Sequence[int]]],\n                      ColorKM: Sequence[Sequence[Sequence[int]]]) -> None:\n    \"\"\"propagate the color of I- and J-pipes to their neighbor K-pipes.\"\"\"\n\n    for i in range(n_i):\n        for j in range(n_j):\n            for k in range(n_k):\n                if ExistK[i][j][k]:\n                    # 4 possible neighbor I/J pipe for the minus end of K-pipe\n                    if in_bound(n_i, n_j, n_k, i - 1, j,\n                                k) and ExistI[i - 1][j][k]:\n                        ColorKM[i][j][k] = 1 - ColorI[i - 1][j][k]\n                    if ExistI[i][j][k]:\n                        ColorKM[i][j][k] = 1 - ColorI[i][j][k]\n                    if in_bound(n_i, n_j, n_k, i, j - 1,\n                                k) and ExistJ[i][j - 1][k]:\n                        ColorKM[i][j][k] = 1 - ColorJ[i][j - 1][k]\n                    if ExistJ[i][j][k]:\n                        ColorKM[i][j][k] = 1 - ColorJ[i][j][k]\n\n                    # 4 possible neighbor I/J pipe for the plus end of K-pipe\n                    if (in_bound(n_i, n_j, n_k, i - 1, j, k + 1)\n                            and ExistI[i - 1][j][k + 1]):\n                        ColorKP[i][j][k] = 1 - ColorI[i - 1][j][k + 1]\n                    if in_bound(n_i, n_j, n_k, i, j,\n                                k + 1) and ExistI[i][j][k + 1]:\n                        ColorKP[i][j][k] = 1 - ColorI[i][j][k + 1]\n                    if (in_bound(n_i, n_j, n_k, i, j - 1, k + 1)\n                            and ExistJ[i][j - 1][k + 1]):\n                        ColorKP[i][j][k] = 1 - ColorJ[i][j - 1][k + 1]\n                    if in_bound(n_i, n_j, n_k, i, j,\n                                k + 1) and ExistJ[i][j][k + 1]:\n                        ColorKP[i][j][k] = 1 - ColorJ[i][j][k + 1]\n\n\ndef propogate_Kcolor(n_i: int, n_j: int, n_k: int,\n                     ExistK: Sequence[Sequence[Sequence[int]]],\n                     ColorKP: Sequence[Sequence[Sequence[int]]],\n                     ColorKM: Sequence[Sequence[Sequence[int]]],\n                     NodeY: Sequence[Sequence[Sequence[int]]]) -> bool:\n    \"\"\"propagate color from colored K-pipes to uncolored K-pipes.\n    If no new color can be assigned, return False; otherwise, return True.\"\"\"\n\n    did_something = False\n    for i in range(n_i):\n        for j in range(n_j):\n            for k in range(n_k):\n                if ExistK[i][j][k]:\n                    # consider propagate color from below\n                    if in_bound(\n                            n_i, n_j, n_k, i, j, k -\n                            1) and ExistK[i][j][k - 1] and NodeY[i][j][k -\n                                                                       1] == 0:\n                        if ColorKP[i][j][k -\n                                         1] > -1 and ColorKM[i][j][k] == -1:\n                            ColorKM[i][j][k] = ColorKP[i][j][k - 1]\n                            did_something = True\n                    # consider propagate color from above\n                    if in_bound(\n                            n_i, n_j, n_k, i, j, k +\n                            1) and ExistK[i][j][k + 1] and NodeY[i][j][k +\n                                                                       1] == 0:\n                        if ColorKM[i][j][k +\n                                         1] > -1 and ColorKP[i][j][k] == -1:\n                            ColorKP[i][j][k] = ColorKM[i][j][k + 1]\n                            did_something = True\n\n                    # if K-pipe connects a Y Cube, two ends can be colored same\n                    if (NodeY[i][j][k] and ColorKM[i][j][k] == -1\n                            and ColorKP[i][j][k] > -1):\n                        ColorKM[i][j][k] = ColorKP[i][j][k]\n                        did_something = True\n                    if (in_bound(n_i, n_j, n_k, i, j, k + 1)\n                            and NodeY[i][j][k + 1] and ColorKM[i][j][k] > -1\n                            and ColorKP[i][j][k] == -1):\n                        ColorKP[i][j][k] = ColorKM[i][j][k]\n                        did_something = True\n    return did_something\n\n\ndef assign_Kcolor(n_i: int, n_j: int, n_k: int,\n                  ExistK: Sequence[Sequence[Sequence[int]]],\n                  ColorKP: Sequence[Sequence[Sequence[int]]],\n                  ColorKM: Sequence[Sequence[Sequence[int]]],\n                  NodeY: Sequence[Sequence[Sequence[int]]]) -> None:\n    \"\"\"when no color can be deducted by propagating from other K-pipes, we\n    assign some color variables at will. Then, we can continue to propagate.\"\"\"\n\n    # assign a color by letting the two ends of a K-pipe to be the same\n    for i in range(n_i):\n        for j in range(n_j):\n            for k in range(n_k):\n                if ExistK[i][j][k]:\n                    if ColorKM[i][j][k] > -1 and ColorKP[i][j][k] == -1:\n                        ColorKP[i][j][k] = ColorKM[i][j][k]\n                        break\n    # For K-pipes that have no color at both ends and connects a Y-cube\n    for i in range(n_i):\n        for j in range(n_j):\n            for k in range(n_k):\n                if ExistK[i][j][k]:\n                    if NodeY[i][j][k] and ColorKM[i][j][k] == -1:\n                        ColorKM[i][j][k] = 0\n                        break\n                    if (in_bound(n_i, n_j, n_k, i, j, k + 1)\n                            and NodeY[i][j][k + 1] and ColorKP[i][j][k] == -1):\n                        ColorKP[i][j][k] = 0\n                        break\n\n\ndef color_ports(ports: Sequence[Mapping[str, Union[str, int]]],\n                ColorKP: Sequence[Sequence[Sequence[int]]],\n                ColorKM: Sequence[Sequence[Sequence[int]]]) -> None:\n    for port in ports:\n        if port['d'] == 'K':\n            if port['e'] == '+':\n                ColorKP[port['i']][port['j']][port['k']] = port['c']\n            else:\n                ColorKM[port['i']][port['j']][port['k']] = port['c']\n\n\ndef color_kp_km(\n    n_i: int,\n    n_j: int,\n    n_k: int,\n    ExistI: Sequence[Sequence[Sequence[int]]],\n    ExistJ: Sequence[Sequence[Sequence[int]]],\n    ExistK: Sequence[Sequence[Sequence[int]]],\n    ColorI: Sequence[Sequence[Sequence[int]]],\n    ColorJ: Sequence[Sequence[Sequence[int]]],\n    ports: Sequence[Mapping[str, Union[str, int]]],\n    NodeY: Sequence[Sequence[Sequence[int]]],\n) -> Tuple[Sequence[Sequence[Sequence[int]]],\n           Sequence[Sequence[Sequence[int]]]]:\n    ColorKP = [[[-1 for _ in range(n_k)] for _ in range(n_j)]\n               for _ in range(n_i)]\n    ColorKM = [[[-1 for _ in range(n_k)] for _ in range(n_j)]\n               for _ in range(n_i)]\n\n    # at ports, the color follows from the port configuration\n    color_ports(ports, ColorKP, ColorKM)\n\n    # propogate the color of I-pipes and J-pipes to their neighboring K-pipes\n    propogate_IJcolor(n_i, n_j, n_k, ExistI, ExistJ, ExistK, ColorI, ColorJ,\n                      ColorKP, ColorKM)\n\n    # the rest of the K-pipes are only neighboring other K-pipes. Until all of\n    # them are colored, we propagate colors of the existing K-pipes. If at one\n    # point, nothing can be implied via propagation, we assign a color at will\n    # and continue. Because of the domain wall operation, we can do this.\n    while if_uncolorK(n_i, n_j, n_k, ExistK, ColorKP, ColorKM):\n        if not propogate_Kcolor(n_i, n_j, n_k, ExistK, ColorKP, ColorKM,\n                                NodeY):\n            assign_Kcolor(n_i, n_j, n_k, ExistK, ColorKP, ColorKM, NodeY)\n    return ColorKP, ColorKM\n\n\ndef color_z(lasre: Mapping[str, Any]) -> Mapping[str, Any]:\n    n_i, n_j, n_k = (\n        lasre['n_i'],\n        lasre['n_j'],\n        lasre['n_k'],\n    )\n    ExistI, ColorI, ExistJ, ColorJ, ExistK = (\n        lasre['ExistI'],\n        lasre['ColorI'],\n        lasre['ExistJ'],\n        lasre['ColorJ'],\n        lasre['ExistK'],\n    )\n    NodeY = lasre['NodeY']\n    ports = lasre['ports']\n\n    # for a K-pipe (i,j,k)-(i,j,k+1), ColorKP (plus) is its color at (i,j,k+1)\n    # and ColorKM (minus) is its color at (i,j,k)\n    lasre['ColorKP'], lasre['ColorKM'] = color_kp_km(n_i, n_j, n_k, ExistI,\n                                                     ExistJ, ExistK, ColorI,\n                                                     ColorJ, ports, NodeY)\n    return lasre\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/rewrite_passes/remove_unconnected.py",
    "content": "\"\"\"In the generated LaS, there can be some 'floating donuts' not connecting to\nany ports. These objects won't affect the function of the LaS. We remove them.\n\"\"\"\n\nfrom typing import Mapping, Any, Sequence, Union, Tuple\n\n\ndef check_cubes(\n    n_i: int, n_j: int, n_k: int, ExistI: Sequence[Sequence[Sequence[int]]],\n    ExistJ: Sequence[Sequence[Sequence[int]]],\n    ExistK: Sequence[Sequence[Sequence[int]]],\n    ports: Sequence[Mapping[str, Union[str, int]]],\n    NodeY: Sequence[Sequence[Sequence[int]]]\n) -> Sequence[Sequence[Sequence[int]]]:\n    # we linearize the cubes, cube at (i,j,k) -> index i*n_j*n_k + j*n_k + k\n    # construct adjancency list of the cubes from the pipes\n    adj = [[] for _ in range(n_i * n_j * n_k)]\n    for i in range(n_i):\n        for j in range(n_j):\n            for k in range(n_k):\n                if ExistI[i][j][k] and i + 1 < n_i:\n                    adj[i * n_j * n_k + j * n_k +\n                        k].append((i + 1) * n_j * n_k + j * n_k + k)\n                    adj[(i + 1) * n_j * n_k + j * n_k +\n                        k].append(i * n_j * n_k + j * n_k + k)\n                if ExistJ[i][j][k] and j + 1 < n_j:\n                    adj[i * n_j * n_k + j * n_k + k].append(i * n_j * n_k +\n                                                            (j + 1) * n_k + k)\n                    adj[i * n_j * n_k + (j + 1) * n_k +\n                        k].append(i * n_j * n_k + j * n_k + k)\n                if ExistK[i][j][k] and k + 1 < n_k:\n                    adj[i * n_j * n_k + j * n_k + k].append(i * n_j * n_k +\n                                                            j * n_k + k + 1)\n                    adj[i * n_j * n_k + j * n_k + k + 1].append(i * n_j * n_k +\n                                                                j * n_k + k)\n\n    # if a cube can reach any of the vips, i.e., open cube for a port\n    vips = [p[\"i\"] * n_j * n_k + p[\"j\"] * n_k + p[\"k\"] for p in ports]\n\n    # first assume all cubes are nonconnected\n    connected_cubes = [[[0 for _ in range(n_k)] for _ in range(n_j)]\n                       for _ in range(n_i)]\n\n    # a Y cube is only effective if it is connected to a cube (i,j,k) that is\n    # connected to ports. In this case, (i,j,k) will be in `connected_cubes`\n    # and all pipes from (i,j,k) will be selected in `check_pipes`, so we can\n    # assume all the Y cubes to be nonconnected for now.\n    y_cubes = [\n        i * n_j * n_k + j * n_k + k for i in range(n_i) for j in range(n_j)\n        for k in range(n_k) if NodeY[i][j][k]\n    ]\n\n    for i in range(n_i):\n        for j in range(n_j):\n            for k in range(n_k):\n                # breadth first search for each cube\n                queue = [\n                    i * n_j * n_k + j * n_k + k,\n                ]\n                if i * n_j * n_k + j * n_k + k in y_cubes:\n                    continue\n                visited = [0 for _ in range(n_i * n_j * n_k)]\n                while len(queue) > 0:\n                    if queue[0] in vips:\n                        connected_cubes[i][j][k] = 1\n                        break\n                    visited[queue[0]] = 1\n                    for v in adj[queue[0]]:\n                        if not visited[v] and v not in y_cubes:\n                            queue.append(v)\n                    queue.pop(0)\n\n    return connected_cubes\n\n\ndef check_pipes(\n    n_i: int, n_j: int, n_k: int, ExistI: Sequence[Sequence[Sequence[int]]],\n    ExistJ: Sequence[Sequence[Sequence[int]]],\n    ExistK: Sequence[Sequence[Sequence[int]]],\n    connected_cubes: Sequence[Sequence[Sequence[int]]]\n) -> Tuple[Sequence[Sequence[Sequence[int]]],\n           Sequence[Sequence[Sequence[int]]],\n           Sequence[Sequence[Sequence[int]]]]:\n    EffectI = [[[0 for _ in range(n_k)] for _ in range(n_j)]\n               for _ in range(n_i)]\n    EffectJ = [[[0 for _ in range(n_k)] for _ in range(n_j)]\n               for _ in range(n_i)]\n    EffectK = [[[0 for _ in range(n_k)] for _ in range(n_j)]\n               for _ in range(n_i)]\n    for i in range(n_i):\n        for j in range(n_j):\n            for k in range(n_k):\n                if ExistI[i][j][k] and (connected_cubes[i][j][k] or\n                                        (i + 1 < n_i\n                                         and connected_cubes[i + 1][j][k])):\n                    EffectI[i][j][k] = 1\n                if ExistJ[i][j][k] and (connected_cubes[i][j][k] or\n                                        (j + 1 < n_j\n                                         and connected_cubes[i][j + 1][k])):\n                    EffectJ[i][j][k] = 1\n                if ExistK[i][j][k] and (connected_cubes[i][j][k] or\n                                        (k + 1 < n_k\n                                         and connected_cubes[i][j][k + 1])):\n                    EffectK[i][j][k] = 1\n    return EffectI, EffectJ, EffectK\n\n\ndef array3DAnd(\n    arr0: Sequence[Sequence[Sequence[int]]],\n    arr1: Sequence[Sequence[Sequence[int]]]\n) -> Sequence[Sequence[Sequence[int]]]:\n    \"\"\"taking the AND of two arrays of bits\"\"\"\n    a = len(arr0)\n    b = len(arr0[0])\n    c = len(arr0[0][0])\n    arrAnd = [[[0 for _ in range(c)] for _ in range(b)] for _ in range(a)]\n    for i in range(a):\n        for j in range(b):\n            for k in range(c):\n                if arr0[i][j][k] == 1 and arr1[i][j][k] == 1:\n                    arrAnd[i][j][k] = 1\n    return arrAnd\n\n\ndef remove_unconnected(lasre: Mapping[str, Any]) -> Mapping[str, Any]:\n    n_i, n_j, n_k = (\n        lasre[\"n_i\"],\n        lasre[\"n_j\"],\n        lasre[\"n_k\"],\n    )\n    ExistI, ExistJ, ExistK, NodeY = (\n        lasre[\"ExistI\"],\n        lasre[\"ExistJ\"],\n        lasre[\"ExistK\"],\n        lasre[\"NodeY\"],\n    )\n    ports = lasre[\"ports\"]\n\n    connected_cubes = check_cubes(n_i, n_j, n_k, ExistI, ExistJ, ExistK, ports,\n                                  NodeY)\n    connectedI, connectedJ, connectedK = check_pipes(n_i, n_j, n_k, ExistI,\n                                                     ExistJ, ExistK,\n                                                     connected_cubes)\n    maskedI, maskedJ, maskedK = (\n        array3DAnd(ExistI, connectedI),\n        array3DAnd(ExistJ, connectedJ),\n        array3DAnd(ExistK, connectedK),\n    )\n    lasre[\"ExistI\"], lasre[\"ExistJ\"], lasre[\n        \"ExistK\"] = maskedI, maskedJ, maskedK\n\n    return lasre\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/sat_synthesis/__init__.py",
    "content": ""
  },
  {
    "path": "glue/lattice_surgery/lassynth/sat_synthesis/lattice_surgery_sat.py",
    "content": "\"\"\"LatticeSurgerySAT to encode the synthesis problem to SAT/SMT\"\"\"\n\nimport os\nimport subprocess\nimport sys\nimport tempfile\nimport time\nfrom typing import Any, Mapping, Sequence, Union, Tuple, Optional\nimport z3\n\n\ndef var_given(\n    data: Mapping[str, Any],\n    arr: str,\n    i: int,\n    j: int,\n    k: int,\n    l: Optional[int] = None,\n) -> bool:\n    \"\"\"Check whether data[arr][i][j][k]([l]) is given.\n\n    If the given indices are not found, return False; otherwise return True.\n\n    Args:\n        data (Mapping[str, Any]): contain arrays\n        arr (str): ExistI, etc.\n        i (int): first index\n        j (int): second index\n        k (int): third index\n        l (int, optional): optional fourth index. Defaults to None.\n\n    Returns:\n        bool: whether the variable value is given\n\n    Raises:\n        ValueError: found value, but not 0 nor 1 nor -1.\n    \"\"\"\n\n    if arr not in data:\n        return False\n    if l is None:\n        if data[arr][i][j][k] == -1:\n            return False\n        elif data[arr][i][j][k] != 0 and data[arr][i][j][k] != 1:\n            raise ValueError(f\"{arr}[{i}, {j}, {k}] is not 0 nor 1 nor -1.\")\n        return True\n    # l is not None, then\n    if data[arr][i][j][k][l] == -1:\n        return False\n    elif data[arr][i][j][k][l] != 0 and data[arr][i][j][k][l] != 1:\n        raise ValueError(f\"{arr}[{i}, {j}, {k}, {l}] is not 0 nor 1 nor -1.\")\n    return True\n\n\ndef port_incident_pipes(\n        port: Mapping[str, Union[str, int]], n_i: int, n_j: int,\n        n_k: int) -> Tuple[Sequence[str], Sequence[Tuple[int, int, int]]]:\n    \"\"\"Compute the pipes incident to a port.\n\n    A port is an pipe with a open end. The incident pipes of a port are the\n    five other pipes connecting to that end. However, some of these pipes\n    can be out of bound, we just want to compute those that are in bound.\n\n    Args:\n        port (Mapping[str, Union[str,  int]]): the port to consider\n        n_i (int): spatial bound on I direction\n        n_j (int): spatial bound on J direction\n        n_k (int): spatial bound on K direction\n\n    Returns:\n        Tuple[Sequence[str], Sequence[Tuple[int, int, int]]]:\n            Two lists of the same length [0,6): (dirs, coords)\n            dirs: the direction of the incident pipes, can be \"I\", \"J\", or \"K\"\n            coords: the coordinates of the incident pipes, each one is (i,j,k)\n    \"\"\"\n    coords = []\n    dirs = []\n\n    # first, just consider adjancency without caring about out-of-bound\n    if port[\"d\"] == \"I\":\n        adj_dirs = [\"I\", \"J\", \"J\", \"K\", \"K\"]\n        if port[\"e\"] == \"-\":  # empty cube is (i,j,k)\n            adj_coords = [\n                (port[\"i\"] - 1, port[\"j\"], port[\"k\"]),  # (i-1,j,k)---(i,j,k)\n                (port[\"i\"], port[\"j\"] - 1, port[\"k\"]),  # (i,j-1,k)---(i,j,k)\n                (port[\"i\"], port[\"j\"], port[\"k\"]),  # (i,j,k)---(i,j+1,k)\n                (port[\"i\"], port[\"j\"], port[\"k\"] - 1),  # (i,j,k-1)---(i,j,k)\n                (port[\"i\"], port[\"j\"], port[\"k\"]),  # (i,j,k)---(i,j,k+1)\n            ]\n        elif port[\"e\"] == \"+\":  # empty cube is (i+1,j,k)\n            adj_coords = [\n                (port[\"i\"] + 1, port[\"j\"], port[\"k\"]),  # (i+1,j,k)---(i+2,j,k)\n                (port[\"i\"] + 1, port[\"j\"] - 1,\n                 port[\"k\"]),  # (i+1,j-1,k)---(i+1,j,k)\n                (port[\"i\"] + 1, port[\"j\"],\n                 port[\"k\"]),  # (i+1,j,k)---(i+1,j+1,k)\n                (port[\"i\"] + 1, port[\"j\"],\n                 port[\"k\"] - 1),  # (i+1,j,k-1)---(i+1,j,k)\n                (port[\"i\"] + 1, port[\"j\"],\n                 port[\"k\"]),  # (i+1,j,k)---(i+1,j,k+1)\n            ]\n\n    if port[\"d\"] == \"J\":\n        adj_dirs = [\"J\", \"K\", \"K\", \"I\", \"I\"]\n        if port[\"e\"] == \"-\":\n            adj_coords = [\n                (port[\"i\"], port[\"j\"] - 1, port[\"k\"]),\n                (port[\"i\"], port[\"j\"], port[\"k\"] - 1),\n                (port[\"i\"], port[\"j\"], port[\"k\"]),\n                (port[\"i\"] - 1, port[\"j\"], port[\"k\"]),\n                (port[\"i\"], port[\"j\"], port[\"k\"]),\n            ]\n        elif port[\"e\"] == \"+\":\n            adj_coords = [\n                (port[\"i\"], port[\"j\"] + 1, port[\"k\"]),\n                (port[\"i\"], port[\"j\"] + 1, port[\"k\"] - 1),\n                (port[\"i\"], port[\"j\"] + 1, port[\"k\"]),\n                (port[\"i\"] - 1, port[\"j\"] + 1, port[\"k\"]),\n                (port[\"i\"], port[\"j\"] + 1, port[\"k\"]),\n            ]\n\n    if port[\"d\"] == \"K\":\n        adj_dirs = [\"K\", \"I\", \"I\", \"J\", \"J\"]\n        if port[\"e\"] == \"-\":\n            adj_coords = [\n                (port[\"i\"], port[\"j\"], port[\"k\"] - 1),\n                (port[\"i\"] - 1, port[\"j\"], port[\"k\"]),\n                (port[\"i\"], port[\"j\"], port[\"k\"]),\n                (port[\"i\"], port[\"j\"] - 1, port[\"k\"]),\n                (port[\"i\"], port[\"j\"], port[\"k\"]),\n            ]\n        elif port[\"e\"] == \"+\":\n            adj_coords = [\n                (port[\"i\"], port[\"j\"], port[\"k\"] + 1),\n                (port[\"i\"] - 1, port[\"j\"], port[\"k\"] + 1),\n                (port[\"i\"], port[\"j\"], port[\"k\"] + 1),\n                (port[\"i\"], port[\"j\"] - 1, port[\"k\"] + 1),\n                (port[\"i\"], port[\"j\"], port[\"k\"] + 1),\n            ]\n\n    # only keep the pipes in bound\n    for i, coord in enumerate(adj_coords):\n        if ((coord[0] in range(n_i)) and (coord[1] in range(n_j))\n                and (coord[2] in range(n_k))):\n            coords.append(adj_coords[i])\n            dirs.append(adj_dirs[i])\n\n    return dirs, coords\n\n\ndef cnf_even_parity_upto4(eles: Sequence[Any]) -> Any:\n    \"\"\"Compute the CNF format of parity of up to four Z3 binary variables.\n\n    Args:\n        eles (Sequence[Any]): the binary variables.\n\n    Returns:\n        (Any) the Z3 constraint meaning the parity of the inputs is even.\n\n    Raises:\n        ValueError: number of elements is not 1, 2, 3, or 4.\n    \"\"\"\n\n    if len(eles) == 1:\n        # 1 var even parity -> this var is false\n        return z3.Not(eles[0])\n\n    elif len(eles) == 2:\n        # 2 vars even pairty -> both True or both False\n        return z3.Or(z3.And(z3.Not(eles[0]), z3.Not(eles[1])),\n                     z3.And(eles[0], eles[1]))\n\n    elif len(eles) == 3:\n        # 3 vars even parity -> all False, or 2 True and 1 False\n        return z3.Or(\n            z3.And(z3.Not(eles[0]), z3.Not(eles[1]), z3.Not(eles[2])),\n            z3.And(eles[0], eles[1], z3.Not(eles[2])),\n            z3.And(eles[0], z3.Not(eles[1]), eles[2]),\n            z3.And(z3.Not(eles[0]), eles[1], eles[2]),\n        )\n\n    elif len(eles) == 4:\n        # 4 vars even parity -> 0, 2, or 4 vars are True\n        return z3.Or(\n            z3.And(z3.Not(eles[0]), z3.Not(eles[1]), z3.Not(eles[2]),\n                   z3.Not(eles[3])),\n            z3.And(z3.Not(eles[0]), z3.Not(eles[1]), eles[2], eles[3]),\n            z3.And(z3.Not(eles[0]), eles[1], z3.Not(eles[2]), eles[3]),\n            z3.And(z3.Not(eles[0]), eles[1], eles[2], z3.Not(eles[3])),\n            z3.And(eles[0], z3.Not(eles[1]), z3.Not(eles[2]), eles[3]),\n            z3.And(eles[0], z3.Not(eles[1]), eles[2], z3.Not(eles[3])),\n            z3.And(eles[0], eles[1], z3.Not(eles[2]), z3.Not(eles[3])),\n            z3.And(eles[0], eles[1], eles[2], eles[3]),\n        )\n\n    else:\n        raise ValueError(\"This function only supports 1, 2, 3, or 4 vars.\")\n\n\nclass LatticeSurgerySAT:\n    \"\"\"class of synthesizing LaSRe using Z3 SMT solver and Kissat SAT solver.\n\n    It encodes a lattice surgery synthesis problem to SAT/SMT and checks\n    whether there is a solution. We are given certain spacetime volume, certain\n    ports, and certain stabilizers. LatticeSurgerySAT encodes the constraints\n    on LaSRe variables such that the resulting variable assignments consist of\n    a valid lattice surgery subroutine with the correct functionality\n    (satisfies all the given stabilizers). LatticeSurgerySAT finds the solution\n    with a SAT/SMT solver.\n    \"\"\"\n\n    def __init__(\n        self,\n        input_dict: Mapping[str, Any],\n        color_ij: bool = True,\n        given_arrs: Optional[Mapping[str, Any]] = None,\n        given_vals: Optional[Sequence[Mapping[str, Any]]] = None,\n    ) -> None:\n        \"\"\"initialization of LatticeSurgerySAT.\n\n        Args:\n            input_dict (Mapping[str, Any]): specification of LaS.\n            color_ij (bool, optional): if the color matching constraints of\n                I and J pipes are imposed. Defaults to True. So far, we always\n                impose these constraints.\n            given_arrs (Mapping[str, Any], optional):\n                    Arrays of values to plug in. Defaults to None.\n            given_vals (Sequence[Mapping[str, Any]], optional):\n                Values to plug in. Defaults to None. These values will\n                replace existing values if already set by given_arrs.\n        \"\"\"\n        self.input_dict = input_dict\n        self.color_ij = color_ij\n        self.goal = z3.Goal()\n        self.process_input(input_dict)\n        self.build_smt_model(given_arrs=given_arrs, given_vals=given_vals)\n\n    def process_input(self, input_dict: Mapping[str, Any]) -> None:\n        \"\"\"read input specification, mainly translating the info at the ports.\n\n        Args:\n            input_dict (Mapping[str, Any]): LaS specification.\n\n        Raises:\n            ValueError: missing key in input specification.\n            ValueError: some spatial bound <= 0.\n            ValueError: more stabilizers than ports.\n            ValueError: stabilizer length is not the same as\n                the number of ports.\n            ValueError: stabilizer contains things other than I, X, Y, or Z.\n            ValueError: missing key in port.\n            ValueError: port location is not a 3-tuple.\n            ValueError: port direction is not 2-string.\n            ValueError: port sign (which end is dangling) is not - or +.\n            ValueError: port axis is not I, J, or K.\n            ValueError: port location+direction is out of bound.\n            ValueError: port Z basis direction is not I, J, or K, and\n                the same with the pipe.\n            ValueError: forbidden cube location is not a 3-tuple.\n            ValueError: forbiddent cube location is out of bounds.\n        \"\"\"\n        data = input_dict\n\n        for key in [\"max_i\", \"max_j\", \"max_k\", \"ports\", \"stabilizers\"]:\n            if key not in data:\n                raise ValueError(f\"missing key {key} in input specification.\")\n\n        # load spatial bound, check > 0\n        self.n_i = data[\"max_i\"]\n        self.n_j = data[\"max_j\"]\n        self.n_k = data[\"max_k\"]\n        if min([self.n_i, self.n_j, self.n_k]) <= 0:\n            raise ValueError(\"max_i or _j or _k <= 0.\")\n\n        self.n_p = len(data[\"ports\"])\n        self.n_s = len(data[\"stabilizers\"])\n        # there should be at most as many stabilizers as ports\n        if self.n_s > self.n_p:\n            raise ValueError(\n                f\"{self.n_s} stabilizers, too many for {self.n_p} ports.\")\n\n        # stabilizers should be paulistrings of length #ports\n        self.paulistrings = [s.replace(\".\", \"I\") for s in data[\"stabilizers\"]]\n        for s in self.paulistrings:\n            if len(s) != self.n_p:\n                raise ValueError(\n                    f\"len({s}) = {len(s)}, but there are {self.n_p} ports.\")\n            for i in range(len(s)):\n                if s[i] not in [\"I\", \"X\", \"Y\", \"Z\"]:\n                    raise ValueError(\n                        f\"{s} has invalid Pauli. I, X, Y, and Z are allowed.\")\n\n        # transform port data\n        self.ports = []\n        for port in data[\"ports\"]:\n            for key in [\"location\", \"direction\", \"z_basis_direction\"]:\n                if key not in port:\n                    raise ValueError(f\"missing key {key} in port {port}\")\n\n            if len(port[\"location\"]) != 3:\n                raise ValueError(f\"port location should be 3-tuple {port}.\")\n\n            if len(port[\"direction\"]) != 2:\n                raise ValueError(\n                    f\"port direction should have 2 characters {port}.\")\n            if port[\"direction\"][0] not in [\"+\", \"-\"]:\n                raise ValueError(f\"port direction with invalid sign {port}.\")\n            if port[\"direction\"][1] not in [\"I\", \"J\", \"K\"]:\n                raise ValueError(f\"port direction with invalid axis {port}.\")\n\n            if port[\"direction\"][0] == \"-\" and port[\"direction\"][\n                    1] == \"I\" and (port[\"location\"][0] not in range(\n                        1, self.n_i + 1)):\n                raise ValueError(\n                    f\"{port['location']} with direction {port['direction']}\"\n                    f\" should be in range [1, f{self.n_i+1}).\")\n            if port[\"direction\"][0] == \"+\" and port[\"direction\"][\n                    1] == \"I\" and (port[\"location\"][0] not in range(\n                        0, self.n_i)):\n                raise ValueError(\n                    f\"{port['location']} with direction {port['direction']}\"\n                    f\" should be in range [0, f{self.n_i}).\")\n            if port[\"direction\"][0] == \"-\" and port[\"direction\"][\n                    1] == \"J\" and (port[\"location\"][1] not in range(\n                        1, self.n_j + 1)):\n                raise ValueError(\n                    f\"{port['location']} with direction {port['direction']}\"\n                    f\" should be in range [1, {self.n_j+1}).\")\n            if port[\"direction\"][0] == \"+\" and port[\"direction\"][\n                    1] == \"J\" and (port[\"location\"][1] not in range(\n                        0, self.n_j)):\n                raise ValueError(\n                    f\"{port['location']} with direction {port['direction']}\"\n                    f\" should be in range [0, f{self.n_j}).\")\n            if port[\"direction\"][0] == \"-\" and port[\"direction\"][\n                    1] == \"K\" and (port[\"location\"][2] not in range(\n                        1, self.n_k + 1)):\n                raise ValueError(\n                    f\"{port['location']} with direction {port['direction']}\"\n                    f\" should be in range [1, f{self.n_k+1}).\")\n            if port[\"direction\"][0] == \"+\" and port[\"direction\"][\n                    1] == \"K\" and (port[\"location\"][2] not in range(\n                        0, self.n_k)):\n                raise ValueError(\n                    f\"{port['location']} with direction {port['direction']}\"\n                    f\" should be in range [0, f{self.n_k}).\")\n\n            # internally, a port is an pipe. This is different from what we\n            # expose to the user: in LaS specification, a port is a cube and\n            # associated with a direction, e.g., cube [i,j,k] and direction\n            # \"-K\". This means the port should be the pipe connecting (i,j,k)\n            # downwards to the volume of LaS. Thus, that pipe is (i,j,k-1) --\n            # (i,j,k) which by convention is the K-pipe (i,j,k-1).\n            # a port here has fields \"i\", \"j\", \"k\", \"d\", \"e\", \"f\", \"c\"\n            my_port = {}\n\n            # \"i\", \"j\", and \"k\" are the i,j,k of the pipe\n            my_port[\"i\"], my_port[\"j\"], my_port[\"k\"] = port[\"location\"]\n            if port[\"direction\"][0] == \"-\":\n                my_port[port[\"direction\"][1].lower()] -= 1\n\n            # \"d\" is one of I, J, and K, corresponding to the port being an\n            #     I-pipe, J-pipe, or a K-pipe\n            my_port[\"d\"] = port[\"direction\"][1]\n\n            # \"e\" is the end of the pipe that is open. For example, if the port\n            #     is a K-pipe (i,j,k), then \"e\"=\"+\" means the cube (i,j,k+1) is\n            #     open; otherwise, \"e\"=\"-\" means cube (i,j,k) is open.\n            my_port[\"e\"] = \"-\" if port[\"direction\"][0] == \"+\" else \"+\"\n\n            # \"c\" is the color variable of the pipe corresponding to the port\n            z_dir = port[\"z_basis_direction\"]\n            if z_dir not in [\"I\", \"J\", \"K\"] or z_dir == my_port[\"d\"]:\n                raise ValueError(\n                    f\"port with invalid Z basis direction {port}.\")\n            if my_port[\"d\"] == \"I\":\n                my_port[\"c\"] = 0 if z_dir == \"J\" else 1\n            if my_port[\"d\"] == \"J\":\n                my_port[\"c\"] = 0 if z_dir == \"K\" else 1\n            if my_port[\"d\"] == \"K\":\n                my_port[\"c\"] = 0 if z_dir == \"I\" else 1\n\n            # \"f\" is the function of the pipe, e.g., it can say this port is a\n            #     T injection. This field is not used in the SAT synthesis, but\n            #     we keep this info to use in later stages like gltf generation\n            if \"function\" in port:\n                my_port[\"f\"] = port[\"function\"]\n\n            self.ports.append(my_port)\n\n        # from paulistrings to correlation surfaces\n        self.stabs = self.derive_corr_boundary(self.paulistrings)\n\n        self.optional = {}\n        self.forbidden_cubes = []\n        if \"optional\" in data:\n            self.optional = data[\"optional\"]\n\n            if \"forbidden_cubes\" in data[\"optional\"]:\n                for cube in data[\"optional\"][\"forbidden_cubes\"]:\n                    if len(cube) != 3:\n                        raise ValueError(\n                            f\"forbid cube should be 3-tuple {cube}.\")\n                    if (cube[0] not in range(self.n_i)\n                            or cube[1] not in range(self.n_j)\n                            or cube[2] not in range(self.n_k)):\n                        raise ValueError(\n                            f\"forbidden {cube} out of range \"\n                            f\"(i,j,k) < ({self.n_i, self.n_j, self.n_k})\")\n                    self.forbidden_cubes.append(cube)\n\n        self.get_port_cubes()\n\n    def get_port_cubes(self) -> None:\n        \"\"\"calculate which cubes are the open cube for the ports.\n        Note that these are *** 3-tuples ***, not lists with 3 elements.\"\"\"\n        self.port_cubes = []\n        for p in self.ports:\n            # if e=-, (i,j,k); otherwise, +1 in the proper direction\n            if p[\"e\"] == \"-\":\n                self.port_cubes.append((p[\"i\"], p[\"j\"], p[\"k\"]))\n            elif p[\"d\"] == \"I\":\n                self.port_cubes.append((p[\"i\"] + 1, p[\"j\"], p[\"k\"]))\n            elif p[\"d\"] == \"J\":\n                self.port_cubes.append((p[\"i\"], p[\"j\"] + 1, p[\"k\"]))\n            elif p[\"d\"] == \"K\":\n                self.port_cubes.append((p[\"i\"], p[\"j\"], p[\"k\"] + 1))\n\n    def derive_corr_boundary(\n            self, paulistrings: Sequence[str]\n    ) -> Sequence[Sequence[Mapping[str, int]]]:\n        \"\"\"derive the boundary correlation surface variable values.\n\n        From the color orientation of the ports and the stabilizers, we can\n        derive which correlation surface variables evaluates to True and which\n        to False at the ports for each stabilizer.\n\n        Args:\n            paulistrings (Sequence[str]): stabilizers as a list of Paulistrings\n\n        Returns:\n            Sequence[Sequence[Mapping[str, int]]]: Outer layer list is the\n            list of stabilizers. Inner layer list is the situation at each port\n            for one specifeic stabilizer. Each port is specified with a\n            dictionary of 2 bits for the 2 correaltion surfaces.\n        \"\"\"\n        stabs = []\n        for paulistring in paulistrings:\n            corr = []\n            for p in range(self.n_p):\n                if paulistring[p] == \"I\":\n                    # I -> no corr surf should be present\n                    if self.ports[p][\"d\"] == \"I\":\n                        corr.append({\"IJ\": 0, \"IK\": 0})\n                    if self.ports[p][\"d\"] == \"J\":\n                        corr.append({\"JI\": 0, \"JK\": 0})\n                    if self.ports[p][\"d\"] == \"K\":\n                        corr.append({\"KI\": 0, \"KJ\": 0})\n\n                if paulistring[p] == \"Y\":\n                    # Y -> both corr surf should be present\n                    if self.ports[p][\"d\"] == \"I\":\n                        corr.append({\"IJ\": 1, \"IK\": 1})\n                    if self.ports[p][\"d\"] == \"J\":\n                        corr.append({\"JI\": 1, \"JK\": 1})\n                    if self.ports[p][\"d\"] == \"K\":\n                        corr.append({\"KI\": 1, \"KJ\": 1})\n\n                if paulistring[p] == \"X\":\n                    # X -> only corr surf touching red faces\n                    if self.ports[p][\"d\"] == \"I\":\n                        if self.ports[p][\"c\"]:\n                            corr.append({\"IJ\": 1, \"IK\": 0})\n                        else:\n                            corr.append({\"IJ\": 0, \"IK\": 1})\n                    if self.ports[p][\"d\"] == \"J\":\n                        if self.ports[p][\"c\"]:\n                            corr.append({\"JI\": 0, \"JK\": 1})\n                        else:\n                            corr.append({\"JI\": 1, \"JK\": 0})\n                    if self.ports[p][\"d\"] == \"K\":\n                        if self.ports[p][\"c\"]:\n                            corr.append({\"KI\": 1, \"KJ\": 0})\n                        else:\n                            corr.append({\"KI\": 0, \"KJ\": 1})\n\n                if paulistring[p] == \"Z\":\n                    # Z -> only corr surf touching blue faces\n                    if self.ports[p][\"d\"] == \"I\":\n                        if not self.ports[p][\"c\"]:\n                            corr.append({\"IJ\": 1, \"IK\": 0})\n                        else:\n                            corr.append({\"IJ\": 0, \"IK\": 1})\n                    if self.ports[p][\"d\"] == \"J\":\n                        if not self.ports[p][\"c\"]:\n                            corr.append({\"JI\": 0, \"JK\": 1})\n                        else:\n                            corr.append({\"JI\": 1, \"JK\": 0})\n                    if self.ports[p][\"d\"] == \"K\":\n                        if not self.ports[p][\"c\"]:\n                            corr.append({\"KI\": 1, \"KJ\": 0})\n                        else:\n                            corr.append({\"KI\": 0, \"KJ\": 1})\n            stabs.append(corr)\n        return stabs\n\n    def build_smt_model(\n        self,\n        given_arrs: Optional[Mapping[str, Any]] = None,\n        given_vals: Optional[Sequence[Mapping[str, Any]]] = None,\n    ) -> None:\n        \"\"\"build the SMT model with variables and constraints.\n\n            Args:\n                given_arrs (Mapping[str, Any], optional):\n                    Arrays of values to plug in. Defaults to None.\n                given_vals (Sequence[Mapping[str, Any]], optional):\n                    Values to plug in. Defaults to None. These values will\n                    replace existing values if already set by given_arrs.\n            \"\"\"\n        self.define_vars()\n        if given_arrs is not None:\n            self.plugin_arrs(given_arrs)\n        if given_vals is not None:\n            self.plugin_vals(given_vals)\n\n        # baseline order of constraint sets, '...' menas name in the paper\n\n        # validity constraints that directly set variables values\n        self.constraint_forbid_cube()\n        self.constraint_port()  # 'no fanouts'\n        self.constraint_connect_outside()  # 'no unexpected ports'\n\n        # more complex validity constraints involving boolean logic\n        self.constraint_timelike_y()  # 'time-like Y cubes'\n        self.constraint_no_deg1()  # 'no degree-1 non-Y cubes'\n        if self.color_ij:\n            # 'matching colors at passthroughs' and '... at turns'\n            self.constraint_ij_color()\n        self.constraint_3d_corner()  # 'no 3D corners'\n\n        # simpler functionality constraints\n        self.constraint_corr_ports()  # 'stabilizer as boundary conditions'\n        self.constraint_corr_y()  # 'both or non at Y cubes'\n\n        # more complex functionality constraints\n        # 'all or no orthogonal surfaces at non-Y cubes:\n        self.constraint_corr_perp()\n        # 'even parity of parallel surfaces at non-Y cubes':\n        self.constraint_corr_para()\n\n    def define_vars(self) -> None:\n        \"\"\"define the variables in Z3 into self.vars.\"\"\"\n        self.vars = {\n            \"ExistI\":\n            [[[z3.Bool(f\"ExistI({i},{j},{k})\") for k in range(self.n_k)]\n              for j in range(self.n_j)] for i in range(self.n_i)],\n            \"ExistJ\":\n            [[[z3.Bool(f\"ExistJ({i},{j},{k})\") for k in range(self.n_k)]\n              for j in range(self.n_j)] for i in range(self.n_i)],\n            \"ExistK\":\n            [[[z3.Bool(f\"ExistK({i},{j},{k})\") for k in range(self.n_k)]\n              for j in range(self.n_j)] for i in range(self.n_i)],\n            \"NodeY\":\n            [[[z3.Bool(f\"NodeY({i},{j},{k})\") for k in range(self.n_k)]\n              for j in range(self.n_j)] for i in range(self.n_i)],\n            \"CorrIJ\":\n            [[[[z3.Bool(f\"CorrIJ({s},{i},{j},{k})\") for k in range(self.n_k)]\n               for j in range(self.n_j)] for i in range(self.n_i)]\n             for s in range(self.n_s)],\n            \"CorrIK\":\n            [[[[z3.Bool(f\"CorrIK({s},{i},{j},{k})\") for k in range(self.n_k)]\n               for j in range(self.n_j)] for i in range(self.n_i)]\n             for s in range(self.n_s)],\n            \"CorrJK\":\n            [[[[z3.Bool(f\"CorrJK({s},{i},{j},{k})\") for k in range(self.n_k)]\n               for j in range(self.n_j)] for i in range(self.n_i)]\n             for s in range(self.n_s)],\n            \"CorrJI\":\n            [[[[z3.Bool(f\"CorrJI({s},{i},{j},{k})\") for k in range(self.n_k)]\n               for j in range(self.n_j)] for i in range(self.n_i)]\n             for s in range(self.n_s)],\n            \"CorrKI\":\n            [[[[z3.Bool(f\"CorrKI({s},{i},{j},{k})\") for k in range(self.n_k)]\n               for j in range(self.n_j)] for i in range(self.n_i)]\n             for s in range(self.n_s)],\n            \"CorrKJ\":\n            [[[[z3.Bool(f\"CorrKJ({s},{i},{j},{k})\") for k in range(self.n_k)]\n               for j in range(self.n_j)] for i in range(self.n_i)]\n             for s in range(self.n_s)],\n        }\n\n        if self.color_ij:\n            self.vars[\"ColorI\"] = [[[\n                z3.Bool(f\"ColorI({i},{j},{k})\") for k in range(self.n_k)\n            ] for j in range(self.n_j)] for i in range(self.n_i)]\n            self.vars[\"ColorJ\"] = [[[\n                z3.Bool(f\"ColorJ({i},{j},{k})\") for k in range(self.n_k)\n            ] for j in range(self.n_j)] for i in range(self.n_i)]\n\n    def plugin_arrs(self, data: Mapping[str, Any]) -> None:\n        \"\"\"plug in the given arrays of values.\n\n        Args:\n            data (Mapping[str, Any]): contains gieven values.\n\n        Raises:\n            ValueError: data contains an invalid array name.\n            ValueError: array given has wrong dimensions.\n        \"\"\"\n\n        for key in data:\n            if key in [\n                    \"NodeY\",\n                    \"ExistI\",\n                    \"ExistJ\",\n                    \"ExistK\",\n                    \"ColorI\",\n                    \"ColorJ\",\n            ]:\n                if len(data[key]) != self.n_i:\n                    raise ValueError(f\"dimension of {key} is wrong.\")\n                for tmp in data[key]:\n                    if len(tmp) != self.n_j:\n                        raise ValueError(f\"dimension of {key} is wrong.\")\n                    for tmptmp in tmp:\n                        if len(tmptmp) != self.n_k:\n                            raise ValueError(f\"dimension of {key} is wrong.\")\n            elif key in [\n                    \"CorrIJ\",\n                    \"CorrIK\",\n                    \"CorrJI\",\n                    \"CorrJK\",\n                    \"CorrKI\",\n                    \"CorrKJ\",\n            ]:\n                if len(data[key]) != self.n_s:\n                    raise ValueError(f\"dimension of {key} is wrong.\")\n                for tmp in data[key]:\n                    if len(tmp) != self.n_i:\n                        raise ValueError(f\"dimension of {key} is wrong.\")\n                    for tmptmp in tmp:\n                        if len(tmptmp) != self.n_j:\n                            raise ValueError(f\"dimension of {key} is wrong.\")\n                        for tmptmptmp in tmptmp:\n                            if len(tmptmptmp) != self.n_k:\n                                raise ValueError(\n                                    f\"dimension of {key} is wrong.\")\n            else:\n                raise ValueError(f\"{key} is not a valid array name\")\n\n        arrs = [\n            \"NodeY\",\n            \"ExistI\",\n            \"ExistJ\",\n            \"ExistK\",\n        ]\n        if self.color_ij:\n            arrs += [\"ColorI\", \"ColorJ\"]\n\n        for s in range(self.n_s):\n            for i in range(self.n_i):\n                for j in range(self.n_j):\n                    for k in range(self.n_k):\n                        if s == 0:  # Exist, Node, and Color vars\n                            for arr in arrs:\n                                if var_given(data, arr, i, j, k):\n                                    self.goal.add(\n                                        self.vars[arr][i][j][k]\n                                        if data[arr][i][j][k] ==\n                                        1 else z3.Not(self.vars[arr][i][j][k]))\n                        # Corr vars\n                        for arr in [\n                                \"CorrIJ\",\n                                \"CorrIK\",\n                                \"CorrJI\",\n                                \"CorrJK\",\n                                \"CorrKI\",\n                                \"CorrKJ\",\n                        ]:\n                            if var_given(data, arr, s, i, j, k):\n                                self.goal.add(\n                                    self.vars[arr][s][i][j][k]\n                                    if data[arr][s][i][j][k] ==\n                                    1 else z3.Not(self.vars[arr][s][i][j][k]))\n\n    def plugin_vals(self, data_set: Sequence[Mapping[str, Any]]):\n        \"\"\"plug in the given values\n\n        Args:\n            data (Sequence[Mapping[str, Any]]): given values as a sequence\n            of dicts. Each one contains three fields: \"array\", the name of\n            the array, e.g., \"ExistI\"; \"indices\", a sequence of the indices;\n            and \"value\".\n\n        Raises:\n            ValueError: given_vals missing a field.\n            ValueError: array name is not valid.\n            ValueError: indices dimension for certain array is wrong.\n            ValueError: index value out of bound.\n            ValueError: given value is neither 0 nor 1.\n        \"\"\"\n        for data in data_set:\n            for key in [\"array\", \"indices\", \"value\"]:\n                if key not in data:\n                    raise ValueError(f\"{key} is not in given val\")\n            if data[\"array\"] not in [\n                    \"NodeY\",\n                    \"ExistI\",\n                    \"ExistJ\",\n                    \"ExistK\",\n                    \"ColorI\",\n                    \"ColorJ\",\n                    \"CorrIJ\",\n                    \"CorrIK\",\n                    \"CorrJI\",\n                    \"CorrJK\",\n                    \"CorrKI\",\n                    \"CorrKJ\",\n            ]:\n                raise ValueError(f\"{data['array']} is not a valid array.\")\n            if data[\"array\"] in [\n                    \"NodeY\",\n                    \"ExistI\",\n                    \"ExistJ\",\n                    \"ExistK\",\n                    \"ColorI\",\n                    \"ColorJ\",\n            ]:\n                if len(data[\"indices\"] != 3):\n                    raise ValueError(f\"Need 3 indices for {data['array']}.\")\n                if data[\"indices\"][0] not in range(self.n_i):\n                    raise ValueError(f\"i index out of range\")\n                if data[\"indices\"][1] not in range(self.n_j):\n                    raise ValueError(f\"j index out of range\")\n                if data[\"indices\"][2] not in range(self.n_k):\n                    raise ValueError(f\"k index out of range\")\n\n            if data[\"array\"] in [\n                    \"CorrIJ\",\n                    \"CorrIK\",\n                    \"CorrJI\",\n                    \"CorrJK\",\n                    \"CorrKI\",\n                    \"CorrKJ\",\n            ]:\n                if len(data[\"indices\"] != 4):\n                    raise ValueError(f\"Need 4 indices for {data['array']}.\")\n                if data[\"indices\"][0] not in range(self.n_s):\n                    raise ValueError(f\"s index out of range\")\n                if data[\"indices\"][1] not in range(self.n_i):\n                    raise ValueError(f\"i index out of range\")\n                if data[\"indices\"][2] not in range(self.n_j):\n                    raise ValueError(f\"j index out of range\")\n                if data[\"indices\"][3] not in range(self.n_k):\n                    raise ValueError(f\"k index out of range\")\n\n            if data[\"value\"] not in [0, 1]:\n                raise ValueError(\"Given value can only be 0 or 1.\")\n\n            (arr, idx) = data[\"array\"], data[\"indices\"]\n            if arr.startswith(\"Corr\"):\n                s, i, j, k = idx\n                if data[\"value\"] == 1:\n                    self.goal.add(self.vars[arr][s][i][j][k])\n                else:\n                    self.goal.add(z3.Not(self.vars[arr][s][i][j][k]))\n            else:\n                i, j, k = idx\n                if data[\"value\"] == 1:\n                    self.goal.add(self.vars[arr][i][j][k])\n                else:\n                    self.goal.add(z3.Not(self.vars[arr][i][j][k]))\n\n    def constraint_forbid_cube(self) -> None:\n        \"\"\"forbid a list of cubes.\"\"\"\n        for cube in self.forbidden_cubes:\n            (i, j, k) = cube[0], cube[1], cube[2]\n            self.goal.add(z3.Not(self.vars[\"NodeY\"][i][j][k]))\n            if i > 0:\n                self.goal.add(z3.Not(self.vars[\"ExistI\"][i - 1][j][k]))\n            self.goal.add(z3.Not(self.vars[\"ExistI\"][i][j][k]))\n            if j > 0:\n                self.goal.add(z3.Not(self.vars[\"ExistJ\"][i][j - 1][k]))\n            self.goal.add(z3.Not(self.vars[\"ExistJ\"][i][j][k]))\n            if k > 0:\n                self.goal.add(z3.Not(self.vars[\"ExistK\"][i][j][k - 1]))\n            self.goal.add(z3.Not(self.vars[\"ExistK\"][i][j][k]))\n\n    def constraint_port(self) -> None:\n        \"\"\"some pipes must exist and some must not depending on the ports.\"\"\"\n        for port in self.ports:\n            # the pipe specified by the port exists\n            self.goal.add(self.vars[f\"Exist{port['d']}\"][port[\"i\"]][port[\"j\"]][\n                port[\"k\"]])\n            # if I- or J-pipe exist, set the color value too to the given one\n            if self.color_ij:\n                if port[\"d\"] != \"K\":\n                    if port[\"c\"] == 1:\n                        self.goal.add(self.vars[f\"Color{port['d']}\"][port[\"i\"]]\n                                      [port[\"j\"]][port[\"k\"]])\n                    else:\n                        self.goal.add(\n                            z3.Not(self.vars[f\"Color{port['d']}\"][port[\"i\"]][\n                                port[\"j\"]][port[\"k\"]]))\n\n            # collect the pipes touching the port to forbid them\n            dirs, coords = port_incident_pipes(port, self.n_i, self.n_j,\n                                               self.n_k)\n            for i, coord in enumerate(coords):\n                self.goal.add(\n                    z3.Not(self.vars[f\"Exist{dirs[i]}\"][coord[0]][coord[1]][\n                        coord[2]]))\n\n    def constraint_connect_outside(self) -> None:\n        \"\"\"no pipe should cross the spatial bound except for ports.\"\"\"\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                # consider K-pipes crossing K-bound and not a port\n                if (i, j, self.n_k) not in self.port_cubes:\n                    self.goal.add(\n                        z3.Not(self.vars[\"ExistK\"][i][j][self.n_k - 1]))\n        for i in range(self.n_i):\n            for k in range(self.n_k):\n                if (i, self.n_j, k) not in self.port_cubes:\n                    self.goal.add(\n                        z3.Not(self.vars[\"ExistJ\"][i][self.n_j - 1][k]))\n        for j in range(self.n_j):\n            for k in range(self.n_k):\n                if (self.n_i, j, k) not in self.port_cubes:\n                    self.goal.add(\n                        z3.Not(self.vars[\"ExistI\"][self.n_i - 1][j][k]))\n\n    def constraint_timelike_y(self) -> None:\n        \"\"\"forbid all I- and J- pipes to Y cubes.\"\"\"\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                for k in range(self.n_k):\n                    if (i, j, k) not in self.port_cubes:\n                        self.goal.add(\n                            z3.Implies(\n                                self.vars[\"NodeY\"][i][j][k],\n                                z3.Not(self.vars[\"ExistI\"][i][j][k]),\n                            ))\n                        self.goal.add(\n                            z3.Implies(\n                                self.vars[\"NodeY\"][i][j][k],\n                                z3.Not(self.vars[\"ExistJ\"][i][j][k]),\n                            ))\n                        if i - 1 >= 0:\n                            self.goal.add(\n                                z3.Implies(\n                                    self.vars[\"NodeY\"][i][j][k],\n                                    z3.Not(self.vars[\"ExistI\"][i - 1][j][k]),\n                                ))\n                        if j - 1 >= 0:\n                            self.goal.add(\n                                z3.Implies(\n                                    self.vars[\"NodeY\"][i][j][k],\n                                    z3.Not(self.vars[\"ExistJ\"][i][j - 1][k]),\n                                ))\n\n    def constraint_ij_color(self) -> None:\n        \"\"\"color matching for I- and J-pipes.\"\"\"\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                for k in range(self.n_k):\n                    if i >= 1 and j >= 1:\n                        # (i-1,j,k)-(i,j,k) and (i,j-1,k)-(i,j,k)\n                        self.goal.add(\n                            z3.Implies(\n                                z3.And(\n                                    self.vars[\"ExistI\"][i - 1][j][k],\n                                    self.vars[\"ExistJ\"][i][j - 1][k],\n                                ),\n                                z3.Or(\n                                    z3.And(\n                                        self.vars[\"ColorI\"][i - 1][j][k],\n                                        z3.Not(self.vars[\"ColorJ\"][i][j -\n                                                                      1][k]),\n                                    ),\n                                    z3.And(\n                                        z3.Not(self.vars[\"ColorI\"][i -\n                                                                   1][j][k]),\n                                        self.vars[\"ColorJ\"][i][j - 1][k],\n                                    ),\n                                ),\n                            ))\n\n                    if i >= 1:\n                        # (i-1,j,k)-(i,j,k) and (i,j,k)-(i,j+1,k)\n                        self.goal.add(\n                            z3.Implies(\n                                z3.And(\n                                    self.vars[\"ExistI\"][i - 1][j][k],\n                                    self.vars[\"ExistJ\"][i][j][k],\n                                ),\n                                z3.Or(\n                                    z3.And(\n                                        self.vars[\"ColorI\"][i - 1][j][k],\n                                        z3.Not(self.vars[\"ColorJ\"][i][j][k]),\n                                    ),\n                                    z3.And(\n                                        z3.Not(self.vars[\"ColorI\"][i -\n                                                                   1][j][k]),\n                                        self.vars[\"ColorJ\"][i][j][k],\n                                    ),\n                                ),\n                            ))\n                        # (i-1,j,k)-(i,j,k) and (i,j,k)-(i+1,j,k)\n                        self.goal.add(\n                            z3.Implies(\n                                z3.And(\n                                    self.vars[\"ExistI\"][i - 1][j][k],\n                                    self.vars[\"ExistI\"][i][j][k],\n                                ),\n                                z3.Or(\n                                    z3.And(\n                                        self.vars[\"ColorI\"][i - 1][j][k],\n                                        self.vars[\"ColorI\"][i][j][k],\n                                    ),\n                                    z3.And(\n                                        z3.Not(self.vars[\"ColorI\"][i -\n                                                                   1][j][k]),\n                                        z3.Not(self.vars[\"ColorI\"][i][j][k]),\n                                    ),\n                                ),\n                            ))\n\n                    if j >= 1:\n                        # (i,j,k)-(i+1,j,k) and (i,j-1,k)-(i,j,k)\n                        self.goal.add(\n                            z3.Implies(\n                                z3.And(\n                                    self.vars[\"ExistI\"][i][j][k],\n                                    self.vars[\"ExistJ\"][i][j - 1][k],\n                                ),\n                                z3.Or(\n                                    z3.And(\n                                        self.vars[\"ColorI\"][i][j][k],\n                                        z3.Not(self.vars[\"ColorJ\"][i][j -\n                                                                      1][k]),\n                                    ),\n                                    z3.And(\n                                        z3.Not(self.vars[\"ColorI\"][i][j][k]),\n                                        self.vars[\"ColorJ\"][i][j - 1][k],\n                                    ),\n                                ),\n                            ))\n                        # (i,j-1,k)-(i,j,k) and (i,j,k)-(i,j+1,k)\n                        self.goal.add(\n                            z3.Implies(\n                                z3.And(\n                                    self.vars[\"ExistJ\"][i][j - 1][k],\n                                    self.vars[\"ExistJ\"][i][j][k],\n                                ),\n                                z3.Or(\n                                    z3.And(\n                                        self.vars[\"ColorJ\"][i][j - 1][k],\n                                        self.vars[\"ColorJ\"][i][j][k],\n                                    ),\n                                    z3.And(\n                                        z3.Not(self.vars[\"ColorJ\"][i][j -\n                                                                      1][k]),\n                                        z3.Not(self.vars[\"ColorJ\"][i][j][k]),\n                                    ),\n                                ),\n                            ))\n\n                    # (i,j,k)-(i+1,j,k) and (i,j,k)-(i,j+1,k)\n                    self.goal.add(\n                        z3.Implies(\n                            z3.And(self.vars[\"ExistI\"][i][j][k],\n                                   self.vars[\"ExistJ\"][i][j][k]),\n                            z3.Or(\n                                z3.And(\n                                    self.vars[\"ColorI\"][i][j][k],\n                                    z3.Not(self.vars[\"ColorJ\"][i][j][k]),\n                                ),\n                                z3.And(\n                                    z3.Not(self.vars[\"ColorI\"][i][j][k]),\n                                    self.vars[\"ColorJ\"][i][j][k],\n                                ),\n                            ),\n                        ))\n\n    def constraint_3d_corner(self) -> None:\n        \"\"\"at least in one direction, both pipes nonexist.\"\"\"\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                for k in range(self.n_k):\n                    i_pipes = [\n                        self.vars[\"ExistI\"][i][j][k],\n                    ]\n                    if i - 1 >= 0:\n                        i_pipes.append(self.vars[\"ExistI\"][i - 1][j][k])\n                    j_pipes = [\n                        self.vars[\"ExistJ\"][i][j][k],\n                    ]\n                    if j - 1 >= 0:\n                        j_pipes.append(self.vars[\"ExistJ\"][i][j - 1][k])\n                    k_pipes = [\n                        self.vars[\"ExistK\"][i][j][k],\n                    ]\n                    if k - 1 >= 0:\n                        k_pipes.append(self.vars[\"ExistK\"][i][j][k - 1])\n\n                    # at least one of the three terms is true. The first term\n                    # is that both I-pipes connecting to (i,j,k) do not exist.\n                    self.goal.add(\n                        z3.Or(\n                            z3.Not(z3.Or(i_pipes)),\n                            z3.Not(z3.Or(j_pipes)),\n                            z3.Not(z3.Or(k_pipes)),\n                        ))\n\n    def constraint_no_deg1(self) -> None:\n        \"\"\"forbid degree-1 X or Z cubes by considering incident pipes.\"\"\"\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                for k in range(self.n_k):\n                    for d in [\"I\", \"J\", \"K\"]:\n                        for e in [\"-\", \"+\"]:\n                            cube = {\"I\": i, \"J\": j, \"K\": k}\n                            cube[d] += 1 if e == \"+\" else 0\n\n                            # construct fake ports to get incident pipes\n                            p0 = {\n                                \"i\": i,\n                                \"j\": j,\n                                \"k\": k,\n                                \"d\": d,\n                                \"e\": e,\n                                \"c\": 0\n                            }\n                            found_p0 = False\n                            for port in self.ports:\n                                if (i == port[\"i\"] and j == port[\"j\"]\n                                        and k == port[\"k\"] and d == port[\"d\"]):\n                                    found_p0 = True\n\n                            # only non-port pipes need to consider\n                            if (not found_p0 and cube[\"I\"] < self.n_i\n                                    and cube[\"J\"] < self.n_j\n                                    and cube[\"K\"] < self.n_k):\n                                # only cubes inside bound need to consider\n                                dirs, coords = port_incident_pipes(\n                                    p0, self.n_i, self.n_j, self.n_k)\n                                pipes = [\n                                    self.vars[f\"Exist{dirs[l]}\"][coord[0]][\n                                        coord[1]][coord[2]]\n                                    for l, coord in enumerate(coords)\n                                ]\n                                # if the cube is not Y and the pipe exist, then\n                                # at least one of its incident pipes exists.\n                                self.goal.add(\n                                    z3.Implies(\n                                        z3.And(\n                                            z3.Not(\n                                                self.vars[\"NodeY\"][cube[\"I\"]][\n                                                    cube[\"J\"]][cube[\"K\"]]),\n                                            self.vars[f\"Exist{d}\"][i][j][k],\n                                        ),\n                                        z3.Or(pipes),\n                                    ))\n\n    def constraint_corr_ports(self) -> None:\n        \"\"\"plug in the correlation surface values at the ports.\"\"\"\n        for s, stab in enumerate(self.stabs):\n            for p, corrs in enumerate(stab):\n                for k, v in corrs.items():\n                    if v == 1:\n                        self.goal.add(\n                            self.vars[f\"Corr{k}\"][s][self.ports[p][\"i\"]][\n                                self.ports[p][\"j\"]][self.ports[p][\"k\"]])\n                    else:\n                        self.goal.add(\n                            z3.Not(self.vars[f\"Corr{k}\"][s][self.ports[p][\"i\"]]\n                                   [self.ports[p][\"j\"]][self.ports[p][\"k\"]]))\n\n    def constraint_corr_y(self) -> None:\n        \"\"\"correlation surfaces at Y-cubes should both exist or nonexist.\"\"\"\n        for s in range(self.n_s):\n            for i in range(self.n_i):\n                for j in range(self.n_j):\n                    for k in range(self.n_k):\n                        self.goal.add(\n                            z3.Or(\n                                z3.Not(self.vars[\"NodeY\"][i][j][k]),\n                                z3.Or(\n                                    z3.And(\n                                        self.vars[\"CorrKI\"][s][i][j][k],\n                                        self.vars[\"CorrKJ\"][s][i][j][k],\n                                    ),\n                                    z3.And(\n                                        z3.Not(\n                                            self.vars[\"CorrKI\"][s][i][j][k]),\n                                        z3.Not(\n                                            self.vars[\"CorrKJ\"][s][i][j][k]),\n                                    ),\n                                ),\n                            ))\n                        if k - 1 >= 0:\n                            self.goal.add(\n                                z3.Or(\n                                    z3.Not(self.vars[\"NodeY\"][i][j][k]),\n                                    z3.Or(\n                                        z3.And(\n                                            self.vars[\"CorrKI\"][s][i][j][k -\n                                                                         1],\n                                            self.vars[\"CorrKJ\"][s][i][j][k -\n                                                                         1],\n                                        ),\n                                        z3.And(\n                                            z3.Not(self.vars[\"CorrKI\"][s][i][j]\n                                                   [k - 1]),\n                                            z3.Not(self.vars[\"CorrKJ\"][s][i][j]\n                                                   [k - 1]),\n                                        ),\n                                    ),\n                                ))\n\n    def constraint_corr_perp(self) -> None:\n        \"\"\"for corr surf perpendicular to normal vector, all or none exists.\"\"\"\n        for s in range(self.n_s):\n            for i in range(self.n_i):\n                for j in range(self.n_j):\n                    for k in range(self.n_k):\n                        if (i, j, k) not in self.port_cubes:\n                            # only consider X or Z spider\n                            # if normal is K meaning meaning both\n                            # (i,j,k)-(i,j,k+1) and (i,j,k)-(i,j,k-1) are\n                            # out of range, or in range but nonexistent\n                            normal = z3.And(\n                                z3.Not(self.vars[\"NodeY\"][i][j][k]),\n                                z3.Not(self.vars[\"ExistK\"][i][j][k]),\n                            )\n                            if k - 1 >= 0:\n                                normal = z3.And(\n                                    normal,\n                                    z3.Not(self.vars[\"ExistK\"][i][j][k - 1]))\n\n                            # for other pipes, we need to build an intermediate\n                            # expression for (i,j,k)-(i+1,j,k) and\n                            # (i,j,k)-(i,j+1,k), built expression meaning\n                            # the pipe is nonexistent or exist and has\n                            # the correlation surface perpendicular to\n                            # the normal vector in them.\n                            no_pipe_or_with_corr = [\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistI\"][i][j][k]),\n                                    self.vars[\"CorrIJ\"][s][i][j][k],\n                                ),\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistJ\"][i][j][k]),\n                                    self.vars[\"CorrJI\"][s][i][j][k],\n                                ),\n                            ]\n\n                            # for (i,j,k)-(i+1,j,k) and (i,j,k)-(i,j+1,k),\n                            # build expression meaning the pipe is nonexistent\n                            # or exist and does not have the correlation\n                            # surface perpendicular to the normal vector.\n                            no_pipe_or_no_corr = [\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistI\"][i][j][k]),\n                                    z3.Not(self.vars[\"CorrIJ\"][s][i][j][k]),\n                                ),\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistJ\"][i][j][k]),\n                                    z3.Not(self.vars[\"CorrJI\"][s][i][j][k]),\n                                ),\n                            ]\n\n                            if i - 1 >= 0:\n                                # add (i-1,j,k)-(i,j,k) to the expression\n                                no_pipe_or_with_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistI\"][i -\n                                                                   1][j][k]),\n                                        self.vars[\"CorrIJ\"][s][i - 1][j][k],\n                                    ))\n                                no_pipe_or_no_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistI\"][i -\n                                                                   1][j][k]),\n                                        z3.Not(\n                                            self.vars[\"CorrIJ\"][s][i -\n                                                                   1][j][k]),\n                                    ))\n\n                            if j - 1 >= 0:\n                                # add (i,j-1,k)-(i,j,k) to the expression\n                                no_pipe_or_with_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistJ\"][i][j -\n                                                                      1][k]),\n                                        self.vars[\"CorrJI\"][s][i][j - 1][k],\n                                    ))\n                                no_pipe_or_no_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistJ\"][i][j -\n                                                                      1][k]),\n                                        z3.Not(\n                                            self.vars[\"CorrJI\"][s][i][j -\n                                                                      1][k]),\n                                    ))\n\n                            # if normal vector is K, then in all its\n                            # incident pipes that exist all correlation surface\n                            # in I-J plane exist or nonexist\n                            self.goal.add(\n                                z3.Implies(\n                                    normal,\n                                    z3.Or(\n                                        z3.And(no_pipe_or_with_corr),\n                                        z3.And(no_pipe_or_no_corr),\n                                    ),\n                                ))\n\n                            # if normal is I\n                            normal = z3.And(\n                                z3.Not(self.vars[\"NodeY\"][i][j][k]),\n                                z3.Not(self.vars[\"ExistI\"][i][j][k]),\n                            )\n                            if i - 1 >= 0:\n                                normal = z3.And(\n                                    normal,\n                                    z3.Not(self.vars[\"ExistI\"][i - 1][j][k]))\n                            no_pipe_or_with_corr = [\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistJ\"][i][j][k]),\n                                    self.vars[\"CorrJK\"][s][i][j][k],\n                                ),\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistK\"][i][j][k]),\n                                    self.vars[\"CorrKJ\"][s][i][j][k],\n                                ),\n                            ]\n                            no_pipe_or_no_corr = [\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistJ\"][i][j][k]),\n                                    z3.Not(self.vars[\"CorrJK\"][s][i][j][k]),\n                                ),\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistK\"][i][j][k]),\n                                    z3.Not(self.vars[\"CorrKJ\"][s][i][j][k]),\n                                ),\n                            ]\n                            if j - 1 >= 0:\n                                no_pipe_or_with_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistJ\"][i][j -\n                                                                      1][k]),\n                                        self.vars[\"CorrJK\"][s][i][j - 1][k],\n                                    ))\n                                no_pipe_or_no_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistJ\"][i][j -\n                                                                      1][k]),\n                                        z3.Not(\n                                            self.vars[\"CorrJK\"][s][i][j -\n                                                                      1][k]),\n                                    ))\n                            if k - 1 >= 0:\n                                no_pipe_or_with_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistK\"][i][j][k -\n                                                                         1]),\n                                        self.vars[\"CorrKJ\"][s][i][j][k - 1],\n                                    ))\n                                no_pipe_or_no_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistK\"][i][j][k -\n                                                                         1]),\n                                        z3.Not(\n                                            self.vars[\"CorrKJ\"][s][i][j][k -\n                                                                         1]),\n                                    ))\n                            self.goal.add(\n                                z3.Implies(\n                                    normal,\n                                    z3.Or(\n                                        z3.And(no_pipe_or_with_corr),\n                                        z3.And(no_pipe_or_no_corr),\n                                    ),\n                                ))\n\n                            # if normal is J\n                            normal = z3.And(\n                                z3.Not(self.vars[\"NodeY\"][i][j][k]),\n                                z3.Not(self.vars[\"ExistJ\"][i][j][k]),\n                            )\n                            if j - 1 >= 0:\n                                normal = z3.And(\n                                    normal,\n                                    z3.Not(self.vars[\"ExistJ\"][i][j - 1][k]))\n                            no_pipe_or_with_corr = [\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistI\"][i][j][k]),\n                                    self.vars[\"CorrIK\"][s][i][j][k],\n                                ),\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistK\"][i][j][k]),\n                                    self.vars[\"CorrKI\"][s][i][j][k],\n                                ),\n                            ]\n                            no_pipe_or_no_corr = [\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistI\"][i][j][k]),\n                                    z3.Not(self.vars[\"CorrIK\"][s][i][j][k]),\n                                ),\n                                z3.Or(\n                                    z3.Not(self.vars[\"ExistK\"][i][j][k]),\n                                    z3.Not(self.vars[\"CorrKI\"][s][i][j][k]),\n                                ),\n                            ]\n                            if i - 1 >= 0:\n                                no_pipe_or_with_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistI\"][i -\n                                                                   1][j][k]),\n                                        self.vars[\"CorrIK\"][s][i - 1][j][k],\n                                    ))\n                                no_pipe_or_no_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistI\"][i -\n                                                                   1][j][k]),\n                                        z3.Not(\n                                            self.vars[\"CorrIK\"][s][i -\n                                                                   1][j][k]),\n                                    ))\n                            if k - 1 >= 0:\n                                no_pipe_or_with_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistK\"][i][j][k -\n                                                                         1]),\n                                        self.vars[\"CorrKI\"][s][i][j][k - 1],\n                                    ))\n                                no_pipe_or_no_corr.append(\n                                    z3.Or(\n                                        z3.Not(self.vars[\"ExistK\"][i][j][k -\n                                                                         1]),\n                                        z3.Not(\n                                            self.vars[\"CorrKI\"][s][i][j][k -\n                                                                         1]),\n                                    ))\n                            self.goal.add(\n                                z3.Implies(\n                                    normal,\n                                    z3.Or(\n                                        z3.And(no_pipe_or_with_corr),\n                                        z3.And(no_pipe_or_no_corr),\n                                    ),\n                                ))\n\n    def constraint_corr_para(self) -> None:\n        \"\"\"for corr surf parallel to the normal , even number of them exist.\"\"\"\n        for s in range(self.n_s):\n            for i in range(self.n_i):\n                for j in range(self.n_j):\n                    for k in range(self.n_k):\n                        if (i, j, k) not in self.port_cubes:\n                            # only X or Z spiders, if normal is K\n                            normal = z3.And(\n                                z3.Not(self.vars[\"NodeY\"][i][j][k]),\n                                z3.Not(self.vars[\"ExistK\"][i][j][k]),\n                            )\n                            if k - 1 >= 0:\n                                normal = z3.And(\n                                    normal,\n                                    z3.Not(self.vars[\"ExistK\"][i][j][k - 1]))\n\n                            # unlike in constraint_corr_perp, we only care\n                            # about the cases where the pipe exists and the\n                            # correlation surface parallel to K also is present\n                            # so we build intermediate expressions as below\n                            pipe_with_corr = [\n                                z3.And(\n                                    self.vars[\"ExistI\"][i][j][k],\n                                    self.vars[\"CorrIK\"][s][i][j][k],\n                                ),\n                                z3.And(\n                                    self.vars[\"ExistJ\"][i][j][k],\n                                    self.vars[\"CorrJK\"][s][i][j][k],\n                                ),\n                            ]\n\n                            # add (i-1,j,k)-(i,j,k) to the expression\n                            if i - 1 >= 0:\n                                pipe_with_corr.append(\n                                    z3.And(\n                                        self.vars[\"ExistI\"][i - 1][j][k],\n                                        self.vars[\"CorrIK\"][s][i - 1][j][k],\n                                    ))\n\n                            # add (i,j-1,k)-(i,j,k) to the expression\n                            if j - 1 >= 0:\n                                pipe_with_corr.append(\n                                    z3.And(\n                                        self.vars[\"ExistJ\"][i][j - 1][k],\n                                        self.vars[\"CorrJK\"][s][i][j - 1][k],\n                                    ))\n\n                            # parity of the expressions must be even\n                            self.goal.add(\n                                z3.Implies(\n                                    normal,\n                                    cnf_even_parity_upto4(pipe_with_corr)))\n\n                            # if normal is I\n                            normal = z3.And(\n                                z3.Not(self.vars[\"NodeY\"][i][j][k]),\n                                z3.Not(self.vars[\"ExistI\"][i][j][k]),\n                            )\n                            if i - 1 >= 0:\n                                normal = z3.And(\n                                    normal,\n                                    z3.Not(self.vars[\"ExistI\"][i - 1][j][k]))\n                            pipe_with_corr = [\n                                z3.And(\n                                    self.vars[\"ExistJ\"][i][j][k],\n                                    self.vars[\"CorrJI\"][s][i][j][k],\n                                ),\n                                z3.And(\n                                    self.vars[\"ExistK\"][i][j][k],\n                                    self.vars[\"CorrKI\"][s][i][j][k],\n                                ),\n                            ]\n                            if j - 1 >= 0:\n                                pipe_with_corr.append(\n                                    z3.And(\n                                        self.vars[\"ExistJ\"][i][j - 1][k],\n                                        self.vars[\"CorrJI\"][s][i][j - 1][k],\n                                    ))\n                            if k - 1 >= 0:\n                                pipe_with_corr.append(\n                                    z3.And(\n                                        self.vars[\"ExistK\"][i][j][k - 1],\n                                        self.vars[\"CorrKI\"][s][i][j][k - 1],\n                                    ))\n                            self.goal.add(\n                                z3.Implies(\n                                    normal,\n                                    cnf_even_parity_upto4(pipe_with_corr)))\n\n                            # if normal is J\n                            normal = z3.And(\n                                z3.Not(self.vars[\"NodeY\"][i][j][k]),\n                                z3.Not(self.vars[\"ExistJ\"][i][j][k]),\n                            )\n                            if j - 1 >= 0:\n                                normal = z3.And(\n                                    normal,\n                                    z3.Not(self.vars[\"ExistJ\"][i][j - 1][k]))\n                            pipe_with_corr = [\n                                z3.And(\n                                    self.vars[\"ExistI\"][i][j][k],\n                                    self.vars[\"CorrIJ\"][s][i][j][k],\n                                ),\n                                z3.And(\n                                    self.vars[\"ExistK\"][i][j][k],\n                                    self.vars[\"CorrKJ\"][s][i][j][k],\n                                ),\n                            ]\n                            if i - 1 >= 0:\n                                pipe_with_corr.append(\n                                    z3.And(\n                                        self.vars[\"ExistI\"][i - 1][j][k],\n                                        self.vars[\"CorrIJ\"][s][i - 1][j][k],\n                                    ))\n                            if k - 1 >= 0:\n                                pipe_with_corr.append(\n                                    z3.And(\n                                        self.vars[\"ExistK\"][i][j][k - 1],\n                                        self.vars[\"CorrKJ\"][s][i][j][k - 1],\n                                    ))\n                            self.goal.add(\n                                z3.Implies(\n                                    normal,\n                                    cnf_even_parity_upto4(pipe_with_corr)))\n\n    def check_z3(self, print_progress: bool = True) -> bool:\n        \"\"\"check whether the built goal in self.goal is satisfiable.\n\n        Args:\n            print_progress (bool, optional): if print out the progress made.\n\n        Returns:\n            bool: True if SAT, False if UNSAT\n        \"\"\"\n        if print_progress:\n            print(\"Construct a Z3 SMT model and solve...\")\n        start_time = time.time()\n        self.solver = z3.Solver()\n        self.solver.add(self.goal)\n        ifsat = self.solver.check()\n        elapsed = time.time() - start_time\n        if print_progress:\n            print(\"elapsed time: {:2f}s\".format(elapsed))\n        if ifsat == z3.sat:\n            if print_progress:\n                print(\"Z3 SAT\")\n            return True\n        else:\n            if print_progress:\n                print(\"Z3 UNSAT\")\n            return False\n\n    def check_kissat(\n        self,\n        kissat_dir: str,\n        dimacs_file_name: Optional[str] = None,\n        sat_log_file_name: Optional[str] = None,\n        print_progress: bool = True,\n    ) -> bool:\n        \"\"\"check whether there is a solution with Kissat\n\n        Args:\n            kissat_dir (str): directory containing an executable named kissat\n            dimacs_file_name (str, optional): Defaults to None. Then, the\n                dimacs file is in a tmp directory. If specified, the dimacs\n                will be saved to that path.\n            sat_log_file_name (str, optional): Defaults to None. Then, the\n                sat log file is in a tmp directory. If specified, the sat log\n                will be saved to that path.\n            print_progress (bool, optional): whether print the SAT solving\n                process on screen. Defaults to True.\n\n        Raises:\n            ValueError: kissat_dir is not a directory\n            ValueError: there is no executable kissat in kissat_dir\n            ValueError: the return code to kissat is neither SAT nor UNSAT\n\n        Returns:\n            bool: True if SAT, False if UNSAT\n        \"\"\"\n        if not os.path.isdir(kissat_dir):\n            raise ValueError(f\"{kissat_dir} is not a directory.\")\n        if kissat_dir.endswith(\"/\"):\n            solver_cmd = kissat_dir + \"kissat\"\n        else:\n            solver_cmd = kissat_dir + \"/kissat\"\n        if not os.path.isfile(solver_cmd):\n            raise ValueError(f\"There is no kissat in {kissat_dir}.\")\n\n        if_solved = False\n        with tempfile.TemporaryDirectory() as tmp_dir:\n            # open a tmp directory as workspace\n\n            # dimacs and sat log are either in the tmp dir, or as user specify\n            tmp_dimacs_file_name = (dimacs_file_name + \".dimacs\" if dimacs_file_name else\n                                    tmp_dir + \"/tmp.dimacs\")\n            tmp_sat_log_file_name = (sat_log_file_name + \".kissat\" if sat_log_file_name\n                                     else tmp_dir + \"/tmp.sat\")\n\n            if self.write_cnf(tmp_dimacs_file_name,\n                              print_progress=print_progress):\n                # continue if the CNF is non-trivial, i.e., write_cnf is True\n                kissat_start_time = time.time()\n\n                with open(tmp_sat_log_file_name, \"w\") as log:\n                    # use tmp_sat_log_file_name to record stdout of kissat\n\n                    kissat_return_code = -100\n                    # -100 if the return code is not updated later on.\n\n                    import random\n                    with subprocess.Popen(\n                        [\n                            solver_cmd, f'--seed={random.randrange(1000000)}',\n                            tmp_dimacs_file_name\n                        ],\n                            stdout=subprocess.PIPE,\n                            bufsize=1,\n                            universal_newlines=True,\n                    ) as run_kissat:\n                        for line in run_kissat.stdout:\n                            log.write(line)\n                            if print_progress:\n                                sys.stdout.write(line)\n                        get_return_code = run_kissat.communicate()[0]\n                        kissat_return_code = run_kissat.returncode\n\n                if kissat_return_code == 10:\n                    # 10 means SAT in Kissat\n                    if_solved = True\n                    if print_progress:\n                        print(\n                            f\"kissat runtime: {time.time()-kissat_start_time}\")\n                        print(\"kissat SAT!\")\n\n                    # we read the Kissat solution from the SAT log, then, plug\n                    # those into the Z3 model and solved inside Z3 again.\n                    # The reason is that Z3 did some simplification of the\n                    # problem so not every variable appear in the DIMACS given\n                    # to Kissat. We still need to know their value.\n                    result = self.read_kissat_result(\n                        tmp_dimacs_file_name,\n                        tmp_sat_log_file_name,\n                    )\n                    self.plugin_arrs(result)\n                    self.check_z3(print_progress)\n\n                elif kissat_return_code == 20:\n                    if print_progress:\n                        print(f\"{solver_cmd} UNSAT\")\n\n                elif kissat_return_code == -100:\n                    print(\"Did not get Kissat return code.\")\n\n                else:\n                    raise ValueError(\n                        f\"Kissat return code {kissat_return_code} is neither\"\n                        \" SAT nor UNSAT. Maybe you should add print_process=\"\n                        \"True to enable the Kissat printout message to see \"\n                        \"what is going on.\")\n        # closing the tmp directory, the files and itself are removed\n\n        return if_solved\n\n    def write_cnf(self,\n                  output_file_name: str,\n                  print_progress: bool = False) -> bool:\n        \"\"\"generate CNF for the problem.\n\n        Args:\n            output_file_name (str): file to write CNF.\n\n        Returns:\n            bool: False if the CNF is trivial, True otherwise\n        \"\"\"\n        cnf_start_time = time.time()\n        simplified = z3.Tactic(\"simplify\")(self.goal)[0]\n        simplified = z3.Tactic(\"propagate-values\")(simplified)[0]\n        cnf = z3.Tactic(\"tseitin-cnf\")(simplified)[0]\n        dimacs = cnf.dimacs()\n        if print_progress:\n            print(f\"CNF generation time: {time.time() - cnf_start_time}\")\n\n        with open(output_file_name, \"w\") as output_f:\n            output_f.write(cnf.dimacs())\n        if dimacs.startswith(\"p cnf 1 1\"):\n            print(\"Generated CNF is trivial meaning z3 concludes the instance\"\n                  \" UNSAT during simplification.\")\n            return False\n        else:\n            return True\n\n    def read_kissat_result(self, dimacs_file: str,\n                           result_file: str) -> Mapping[str, Any]:\n        \"\"\"read result from external SAT solver\n\n        Args:\n            dimacs_file (str):\n            result_file (str): log from Kissat containing SAT assignments\n\n        Raises:\n            ValueError: in the dimacs file, the last lines are comments that\n                records the mapping from SAT variable indices to the variable\n                names in Z3. If the coordinates in this name is incorrect.\n\n        Returns:\n            Mapping[str, Any]: variable assignment in arrays. All the one with\n                a corresponding SAT variable are read off from the SAT log.\n                The others are left with -1.\n        \"\"\"\n        results = {\n            \"ExistI\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"ExistJ\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"ExistK\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"ColorI\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"ColorJ\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"NodeY\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                      for _ in range(self.n_i)],\n            \"CorrIJ\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrIK\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrJK\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrJI\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrKI\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrKJ\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n        }\n\n        # in this file, the assigments are lines starting with \"v\" like\n        # v -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 ...\n        # the vars starts from 1 and - means it's False; otherwise, it's True\n        # we scan through all these lines, and save the assignments to `sat`\n        with open(result_file, \"r\") as f:\n            sat_output = f.readlines()\n        sat = {}\n        for line in sat_output:\n            if line.startswith(\"v\"):\n                assignments = line[1:].strip().split(\" \")\n                for assignment in assignments:\n                    tmp = int(assignment)\n                    if tmp < 0:\n                        sat[str(-tmp)] = 0\n                    elif tmp > 0:\n                        sat[str(tmp)] = 1\n\n        # in the dimacs generated by Z3, there are lines starting with \"c\" like\n        # c 8804 CorrIJ(1,0,3,4)    or    c 60053 k!44404\n        # which records the mapping from our variables to variables in dimacs\n        # the ones starting with k! are added in the translation, we don\"t care\n        with open(dimacs_file, \"r\") as f:\n            dimacs = f.readlines()\n        for line in dimacs:\n            if line.startswith(\"c\"):\n                _, index, name = line.strip().split(\" \")\n                if name.startswith((\n                        \"NodeY\",\n                        \"ExistI\",\n                        \"ExistJ\",\n                        \"ExistK\",\n                        \"ColorI\",\n                        \"ColorJ\",\n                        \"CorrIJ\",\n                        \"CorrIK\",\n                        \"CorrJI\",\n                        \"CorrJK\",\n                        \"CorrKI\",\n                        \"CorrKJ\",\n                )):\n                    arr, tmp = name[:-1].split(\"(\")\n                    coords = [int(num) for num in tmp.split(\",\")]\n                    if len(coords) == 3:\n                        results[arr][coords[0]][coords[1]][\n                            coords[2]] = sat[index]\n                    elif len(coords) == 4:\n                        results[arr][coords[0]][coords[1]][coords[2]][\n                            coords[3]] = sat[index]\n                    else:\n                        raise ValueError(\"number of coord should be 3 or 4!\")\n\n        return results\n\n    def get_result(self) -> Mapping[str, Any]:\n        \"\"\"get the variable values.\n\n            Returns:\n                Mapping[str, Any]: output in the LaSRe format\n        \"\"\"\n        model = self.solver.model()\n        data = {\n            \"n_i\":\n            self.n_i,\n            \"n_j\":\n            self.n_j,\n            \"n_k\":\n            self.n_k,\n            \"n_p\":\n            self.n_p,\n            \"n_s\":\n            self.n_s,\n            \"ports\":\n            self.ports,\n            \"stabs\":\n            self.stabs,\n            \"port_cubes\":\n            self.port_cubes,\n            \"optional\":\n            self.optional,\n            \"ExistI\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"ExistJ\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"ExistK\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"ColorI\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"ColorJ\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                       for _ in range(self.n_i)],\n            \"NodeY\": [[[-1 for _ in range(self.n_k)] for _ in range(self.n_j)]\n                      for _ in range(self.n_i)],\n            \"CorrIJ\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrIK\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrJK\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrJI\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrKI\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n            \"CorrKJ\": [[[[-1 for _ in range(self.n_k)]\n                         for _ in range(self.n_j)] for _ in range(self.n_i)]\n                       for _ in range(self.n_s)],\n        }\n        arrs = [\n            \"NodeY\",\n            \"ExistI\",\n            \"ExistJ\",\n            \"ExistK\",\n        ]\n        if self.color_ij:\n            arrs += [\n                \"ColorI\",\n                \"ColorJ\",\n            ]\n        for s in range(self.n_s):\n            for i in range(self.n_i):\n                for j in range(self.n_j):\n                    for k in range(self.n_k):\n                        if s == 0:  # Exist, Node, and Color vars\n                            for arr in arrs:\n                                data[arr][i][j][k] = (\n                                    1 if model[self.vars[arr][i][j][k]] else 0)\n\n                        # Corr vars\n                        for arr in [\n                                \"CorrIJ\",\n                                \"CorrIK\",\n                                \"CorrJI\",\n                                \"CorrJK\",\n                                \"CorrKI\",\n                                \"CorrKJ\",\n                        ]:\n                            data[arr][s][i][j][k] = (\n                                1 if model[self.vars[arr][s][i][j][k]] else 0)\n        return data\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/tools/__init__.py",
    "content": ""
  },
  {
    "path": "glue/lattice_surgery/lassynth/tools/verify_stabilizers.py",
    "content": "from typing import Sequence\nimport stim\nimport stimzx\n\n\ndef verify_stabilizers(\n    specified_paulistrings: Sequence[str],\n    result_networkx,\n    print_stabilizers: bool = False,\n) -> bool:\n    result_stabilizers = [\n        stab.output\n        for stab in stimzx.zx_graph_to_external_stabilizers(result_networkx)\n    ]\n    specified_stabilizers = [\n        stim.PauliString(paulistring) for paulistring in specified_paulistrings\n    ]\n    if print_stabilizers:\n        print(\"specified:\")\n        for s in specified_stabilizers:\n            print(s)\n        print(\"==============================================================\")\n        print(\"resulting:\")\n        for s in result_stabilizers:\n            print(s)\n        print(\"==============================================================\")\n\n    for s in result_stabilizers:\n        for ss in specified_stabilizers:\n            if not ss.commutes(s):\n                print(f\"result stabilizer {s} not commuting with \"\n                      f\"specified stabilizer {ss}\")\n                if print_stabilizers:\n                    print(\"specified and resulting stabilizers not equivalent\")\n                return False\n    if print_stabilizers:\n        print(\"specified and resulting stabilizers are equivalent.\")\n    return True\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/translators/__init__.py",
    "content": "from lassynth.translators.zx_grid_graph import ZXGridGraph\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/translators/gltf_generator.py",
    "content": "\"\"\"generating a 3D modelling file in gltf format from our LaSRe.\"\"\"\n\nimport json\nfrom typing import Any, Mapping, Optional, Sequence, Tuple\n\n# constants\nSQ2 = 0.707106769085  # square root of 2\nTHICKNESS = 0.01  # half separation of front and back sides of each face\nAXESTHICKNESS = 0.1\n\ndef float_to_little_endian_hex(f):\n    from struct import pack\n\n    # Pack the float into a binary string using the little-endian format\n    binary_data = pack(\"<f\", f)\n\n    # Convert the binary string to a hexadecimal string\n    hex_string = binary_data.hex()\n\n    return hex_string\n\n\ndef hex_to_bin(s):\n    from codecs import encode, decode\n\n    s = encode(decode(s, \"hex\"), \"base64\").decode()\n    s = str(s).replace(\"\\n\", \"\")\n    return \"data:application/octet-stream;base64,\" + s\n\n\ndef base_gen(\n    tubelen: float = 2.0,\n) -> Mapping[str, Any]:\n    \"\"\"generate basic gltf contents, i.e., independent from the LaS\n\n    Args:\n        tubelen (float, optional): ratio of the length of the pipe with respect\n            to the length of a cube. Defaults to 2.0.\n\n    Returns:\n        Mapping[str, Any]: gltf with everything here.\n    \"\"\"\n    # floats as hex, little endian\n    floats = {\n        \"0\": \"00000000\",\n        \"1\": \"0000803F\",\n        \"-1\": \"000080BF\",\n        \"0.5\": \"0000003F\",\n        \"0.45\": \"6666E63E\",\n    }\n    floats[\"tube\"] = float_to_little_endian_hex(tubelen)\n    floats[\"+SQ2\"] = float_to_little_endian_hex(SQ2)\n    floats[\"-SQ2\"] = float_to_little_endian_hex(-SQ2)\n    floats[\"+T\"] = float_to_little_endian_hex(THICKNESS)\n    floats[\"-T\"] = float_to_little_endian_hex(-THICKNESS)\n    floats[\"1-T\"] = float_to_little_endian_hex(1 - THICKNESS)\n    floats[\"T-1\"] = float_to_little_endian_hex(THICKNESS - 1)\n    floats[\"0.5+T\"] = float_to_little_endian_hex(0.5 + THICKNESS)\n    floats[\"0.5-T\"] = float_to_little_endian_hex(0.5 - THICKNESS)\n\n    # integers as hex\n    ints = [\"0000\", \"0100\", \"0200\", \"0300\", \"0400\", \"0500\", \"0600\", \"0700\"]\n\n    gltf = {\n        \"asset\": {\n            \"generator\": \"LaSRe CodeGen by Daniel Bochen Tan\",\n            \"version\": \"2.0\"\n        },\n        \"scene\": 0,\n        \"scenes\": [{\n            \"name\": \"Scene\",\n            \"nodes\": [0]\n        }],\n        \"nodes\": [{\n            \"name\": \"Lattice Surgery Subroutine\",\n            \"children\": []\n        }],\n    }\n    gltf[\"accessors\"] = []\n    gltf[\"buffers\"] = []\n    gltf[\"bufferViews\"] = []\n\n    # materials are the colors. baseColorFactor is (R, G, B, alpha)\n    gltf[\"materials\"] = [\n        {\n            \"name\": \"0-blue\",\n            \"pbrMetallicRoughness\": {\n                \"baseColorFactor\": [0, 0, 1, 1]\n            },\n            \"doubleSided\": False,\n        },\n        {\n            \"name\": \"1-red\",\n            \"pbrMetallicRoughness\": {\n                \"baseColorFactor\": [1, 0, 0, 1]\n            },\n            \"doubleSided\": False,\n        },\n        {\n            \"name\": \"2-green\",\n            \"pbrMetallicRoughness\": {\n                \"baseColorFactor\": [0, 1, 0, 1]\n            },\n            \"doubleSided\": False,\n        },\n        {\n            \"name\": \"3-gray\",\n            \"pbrMetallicRoughness\": {\n                \"baseColorFactor\": [0.5, 0.5, 0.5, 1]\n            },\n            \"doubleSided\": False,\n        },\n        {\n            \"name\": \"4-cyan.3\",\n            \"pbrMetallicRoughness\": {\n                \"baseColorFactor\": [0, 1, 1, 0.3]\n            },\n            \"doubleSided\": False,\n            \"alphaMode\": \"BLEND\",\n        },\n        {\n            \"name\": \"5-black\",\n            \"pbrMetallicRoughness\": {\n                \"baseColorFactor\": [0, 0, 0, 1]\n            },\n            \"doubleSided\": False,\n        },\n        {\n            \"name\": \"6-yellow\",\n            \"pbrMetallicRoughness\": {\n                \"baseColorFactor\": [1, 1, 0, 1]\n            },\n            \"doubleSided\": False,\n        },\n        {\n            \"name\": \"7-white\",\n            \"pbrMetallicRoughness\": {\n                \"baseColorFactor\": [1, 1, 1, 1]\n            },\n            \"doubleSided\": False,\n        },\n    ]\n\n    # for a 3D coordinate (X,Y,Z), the convention of VEC3 in GLTF is (X,Z,-Y)\n    # below are the data we store into the embedded binary in the GLTF.\n    # For each data, we create a buffer, there is one and only one bufferView\n    # for this buffer, and there is one and only one accessor for this\n    # bufferView. This is for simplicity. So in what follows, we always gather\n    # the string corresponding to the data, whether they're a list of floats or\n    # a list of integers. Then, we append a buffer, a bufferView, and an\n    # accessor to the GLTF. This part is quite machinary.\n\n    # GLTF itself support doubleside color in materials, but this can lead to\n    # problems when converting to other formats. So, for each face of a cube or\n    # a pipe, we will make it two sides, front and back. The POSITION of\n    # vertices of these two are shifted on the Z axis by 2*THICKNESS. Since we\n    # need their color to both facing outside, the back side require opposite\n    # NORMAL vectors, and the index order needs to be reversed. We begin with\n    # definition for the front sides.\n\n    # 0, positions of square: [(+T,+T,-T),(1-T,+T,-T),(+T,1-T,-T),(1-T,1-T,-T)]\n    s = (floats[\"+T\"] + floats[\"-T\"] + floats[\"-T\"] + floats[\"1-T\"] +\n         floats[\"-T\"] + floats[\"-T\"] + floats[\"+T\"] + floats[\"-T\"] +\n         floats[\"T-1\"] + floats[\"1-T\"] + floats[\"-T\"] + floats[\"T-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 0,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 0,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [1 - THICKNESS, -THICKNESS, -THICKNESS],\n        \"min\": [THICKNESS, -THICKNESS, THICKNESS - 1],\n    })\n\n    # 1, positions of rectangle: [(0,0,-T),(L,0,-T),(0,1,-T),(L,1,-T)]\n    s = (floats[\"0\"] + floats[\"-T\"] + floats[\"0\"] + floats[\"tube\"] +\n         floats[\"-T\"] + floats[\"0\"] + floats[\"0\"] + floats[\"-T\"] +\n         floats[\"-1\"] + floats[\"tube\"] + floats[\"-T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 1,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 1,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [tubelen, -THICKNESS, 0],\n        \"min\": [0, -THICKNESS, -1],\n    })\n\n    # 2, normals of rect/sqr: (0,0,-1)*4\n    s = (floats[\"0\"] + floats[\"-1\"] + floats[\"0\"] + floats[\"0\"] +\n         floats[\"-1\"] + floats[\"0\"] + floats[\"0\"] + floats[\"-1\"] +\n         floats[\"0\"] + floats[\"0\"] + floats[\"-1\"] + floats[\"0\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 2,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 2,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4\n    })\n\n    # 3, vertices of rect/sqr: [1,0,3, 3,0,2]\n    s = ints[1] + ints[0] + ints[3] + ints[3] + ints[0] + ints[2]\n    gltf[\"buffers\"].append({\"byteLength\": 12, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 3,\n        \"byteLength\": 12,\n        \"byteOffset\": 0,\n        \"target\": 34963\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 3,\n        \"componentType\": 5123,\n        \"type\": \"SCALAR\",\n        \"count\": 6\n    })\n\n    # 4, positions of tilted rect: [(0,0,1/2+T),(1/2,0,+T),(0,1,1/2+T),(1/2,1,+T)]\n    s = (floats[\"0\"] + floats[\"0.5+T\"] + floats[\"0\"] + floats[\"0.5\"] +\n         floats[\"+T\"] + floats[\"0\"] + floats[\"0\"] + floats[\"0.5+T\"] +\n         floats[\"-1\"] + floats[\"0.5\"] + floats[\"+T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 4,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 4,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [0.5, 0.5 + THICKNESS, 0],\n        \"min\": [0, THICKNESS, -1],\n    })\n\n    # 5, normals of tilted rect: (-sqrt(2)/2, 0, -sqrt(2)/2)*4\n    s = (floats[\"-SQ2\"] + floats[\"-SQ2\"] + floats[\"0\"] + floats[\"-SQ2\"] +\n         floats[\"-SQ2\"] + floats[\"0\"] + floats[\"-SQ2\"] + floats[\"-SQ2\"] +\n         floats[\"0\"] + floats[\"-SQ2\"] + floats[\"-SQ2\"] + floats[\"0\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 5,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 5,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4\n    })\n\n    # 6, positions of Hadamard rectangle: [(0,0,-T),(15/32L,0,-T),(15/32L,1,-T),\n    # (15/32L,1,-T),(17/32L,0,-T),(17/32L,1,-T),(L,0,-T),(L,1,-T)]\n    floats[\"left\"] = float_to_little_endian_hex(tubelen * 15 / 32)\n    floats[\"right\"] = float_to_little_endian_hex(tubelen * 17 / 32)\n    s = (floats[\"0\"] + floats[\"-T\"] + floats[\"0\"] + floats[\"left\"] +\n         floats[\"-T\"] + floats[\"0\"] + floats[\"0\"] + floats[\"-T\"] +\n         floats[\"-1\"] + floats[\"left\"] + floats[\"-T\"] + floats[\"-1\"] +\n         floats[\"right\"] + floats[\"-T\"] + floats[\"0\"] + floats[\"right\"] +\n         floats[\"-T\"] + floats[\"-1\"] + floats[\"tube\"] + floats[\"-T\"] +\n         floats[\"0\"] + floats[\"tube\"] + floats[\"-T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 96, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 6,\n        \"byteLength\": 96,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 6,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 8,\n        \"max\": [tubelen, -THICKNESS, 0],\n        \"min\": [0, -THICKNESS, -1],\n    })\n\n    # 7, normals of Hadamard rect (0,0,-1)*8\n    s = (floats[\"0\"] + floats[\"-1\"] + floats[\"0\"] + floats[\"0\"] +\n         floats[\"-1\"] + floats[\"0\"] + floats[\"0\"] + floats[\"-1\"] +\n         floats[\"0\"] + floats[\"0\"] + floats[\"-1\"] + floats[\"0\"] + floats[\"0\"] +\n         floats[\"-1\"] + floats[\"0\"] + floats[\"0\"] + floats[\"-1\"] +\n         floats[\"0\"] + floats[\"0\"] + floats[\"-1\"] + floats[\"0\"] + floats[\"0\"] +\n         floats[\"-1\"] + floats[\"0\"])\n    gltf[\"buffers\"].append({\"byteLength\": 96, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 7,\n        \"byteLength\": 96,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 7,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 8\n    })\n\n    # 8, vertices of middle rect in Hadamard rect: [4,1,5, 5,1,3]\n    s = ints[4] + ints[1] + ints[5] + ints[5] + ints[1] + ints[3]\n    gltf[\"buffers\"].append({\"byteLength\": 12, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 8,\n        \"byteLength\": 12,\n        \"byteOffset\": 0,\n        \"target\": 34963\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 8,\n        \"componentType\": 5123,\n        \"type\": \"SCALAR\",\n        \"count\": 6\n    })\n\n    # 9, vertices of upper rect in Hadamard rect: [6,4,7, 7,4,5]\n    s = ints[6] + ints[4] + ints[7] + ints[7] + ints[4] + ints[5]\n    gltf[\"buffers\"].append({\"byteLength\": 12, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 9,\n        \"byteLength\": 12,\n        \"byteOffset\": 0,\n        \"target\": 34963\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 9,\n        \"componentType\": 5123,\n        \"type\": \"SCALAR\",\n        \"count\": 6\n    })\n\n    # 10, vertices of lines around a face: [0,1, 0,2, 2,3, 3,1]\n    # GLTF supports drawing lines, but there may be a problem converting to\n    # other formats. We have thus not used these data.\n    s = (ints[0] + ints[1] + ints[0] + ints[2] + ints[2] + ints[3] + ints[3] +\n         ints[1])\n    gltf[\"buffers\"].append({\"byteLength\": 16, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 10,\n        \"byteLength\": 16,\n        \"byteOffset\": 0,\n        \"target\": 34963\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 10,\n        \"componentType\": 5123,\n        \"type\": \"SCALAR\",\n        \"count\": 8\n    })\n\n    # 11, positions of half-distance rectangle: [(0,0,-T),(0.45,0,-T),(0,1,-T),(0.45,1,-T)]\n    s = (floats[\"0\"] + floats[\"-T\"] + floats[\"0\"] + floats[\"0.45\"] +\n         floats[\"-T\"] + floats[\"0\"] + floats[\"0\"] + floats[\"-T\"] +\n         floats[\"-1\"] + floats[\"0.45\"] + floats[\"-T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 11,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 11,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [0.45, -THICKNESS, 0],\n        \"min\": [0, -THICKNESS, -1],\n    })\n\n    # 12, backside, positions of square: [(+T,+T,+T),(1-T,+T,+T),(+T,1-T,+T),(1-T,1-T,+T)]\n    s = (floats[\"+T\"] + floats[\"+T\"] + floats[\"-T\"] + floats[\"1-T\"] +\n         floats[\"+T\"] + floats[\"-T\"] + floats[\"+T\"] + floats[\"+T\"] +\n         floats[\"T-1\"] + floats[\"1-T\"] + floats[\"+T\"] + floats[\"T-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 12,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 12,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [1 - THICKNESS, THICKNESS, -THICKNESS],\n        \"min\": [THICKNESS, THICKNESS, THICKNESS - 1],\n    })\n\n    # 13, backside, normals of rect/sqr: (0,0,1)*4\n    s = (floats[\"0\"] + floats[\"1\"] + floats[\"0\"] + floats[\"0\"] + floats[\"1\"] +\n         floats[\"0\"] + floats[\"0\"] + floats[\"1\"] + floats[\"0\"] + floats[\"0\"] +\n         floats[\"1\"] + floats[\"0\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 13,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 13,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4\n    })\n\n    # For the cubes, we want to draw black lines around its boundaries to help\n    # people identify them visually. However, drawing lines in GLTF may become\n    # a problem when converting to other formats. Here, we define super thin\n    # rectangles at the boundaries of squares which will be seen as lines.\n\n    # 14, frontside, positions of edge 0: [(+T,0,-T),(1-T,0,-T),(+T,+T,-T),(1-T,+T,-T)]\n    s = (floats[\"+T\"] + floats[\"-T\"] + floats[\"0\"] + floats[\"1-T\"] +\n         floats[\"-T\"] + floats[\"0\"] + floats[\"+T\"] + floats[\"-T\"] +\n         floats[\"-T\"] + floats[\"1-T\"] + floats[\"-T\"] + floats[\"-T\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 14,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 14,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [1 - THICKNESS, -THICKNESS, 0],\n        \"min\": [THICKNESS, -THICKNESS, -THICKNESS],\n    })\n\n    # 15, frontside, positions of edge 1: [(1-T,+T,-T),(1,+T,-T),(1-T,1-T,-T),(1,1-T,-T)]\n    s = (floats[\"1-T\"] + floats[\"-T\"] + floats[\"-T\"] + floats[\"1\"] +\n         floats[\"-T\"] + floats[\"-T\"] + floats[\"1-T\"] + floats[\"-T\"] +\n         floats[\"T-1\"] + floats[\"1\"] + floats[\"-T\"] + floats[\"T-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 15,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 15,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [1, -THICKNESS, -THICKNESS],\n        \"min\": [1 - THICKNESS, -THICKNESS, THICKNESS - 1],\n    })\n\n    # 16, frontside, positions of edge 2: [(0,+T,-T),(+T,+T,-T),(0,1-T,-T),(+T,1-T,-T)]\n    s = (floats[\"0\"] + floats[\"-T\"] + floats[\"-T\"] + floats[\"+T\"] +\n         floats[\"-T\"] + floats[\"-T\"] + floats[\"0\"] + floats[\"-T\"] +\n         floats[\"T-1\"] + floats[\"+T\"] + floats[\"-T\"] + floats[\"T-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 16,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 16,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [THICKNESS, -THICKNESS, -THICKNESS],\n        \"min\": [0, -THICKNESS, THICKNESS - 1],\n    })\n\n    # 17, frontside, positions of edge 3: [(+T,1-T,-T),(1-T,1-T,-T),(+T,1,-T),(1-T,1,-T)]\n    s = (floats[\"+T\"] + floats[\"-T\"] + floats[\"T-1\"] + floats[\"1-T\"] +\n         floats[\"-T\"] + floats[\"T-1\"] + floats[\"+T\"] + floats[\"-T\"] +\n         floats[\"-1\"] + floats[\"1-T\"] + floats[\"-T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 17,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 17,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [1 - THICKNESS, -THICKNESS, THICKNESS - 1],\n        \"min\": [THICKNESS, -THICKNESS, -1],\n    })\n\n    # 18, backside, positions of edge 0: [(+T,0,+T),(1-T,0,+T),(+T,+T,+T),(1-T,+T,+T)]\n    s = (floats[\"+T\"] + floats[\"+T\"] + floats[\"0\"] + floats[\"1-T\"] +\n         floats[\"+T\"] + floats[\"0\"] + floats[\"+T\"] + floats[\"+T\"] +\n         floats[\"-T\"] + floats[\"1-T\"] + floats[\"+T\"] + floats[\"-T\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 18,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 18,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [1 - THICKNESS, THICKNESS, 0],\n        \"min\": [THICKNESS, THICKNESS, -THICKNESS],\n    })\n\n    # 19, backside, positions of edge 1: [(1-T,+T,+T),(1,+T,+T),(1-T,1-T,+T),(1,1-T,+T)]\n    s = (floats[\"1-T\"] + floats[\"+T\"] + floats[\"-T\"] + floats[\"1\"] +\n         floats[\"+T\"] + floats[\"-T\"] + floats[\"1-T\"] + floats[\"+T\"] +\n         floats[\"T-1\"] + floats[\"1\"] + floats[\"+T\"] + floats[\"T-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 19,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 19,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [1, THICKNESS, -THICKNESS],\n        \"min\": [1 - THICKNESS, THICKNESS, THICKNESS - 1],\n    })\n\n    # 20, backside, positions of edge 2: [(0,+T,+T),(+T,+T,+T),(0,1-T,+T),(+T,1-T,+T)]\n    s = (floats[\"0\"] + floats[\"+T\"] + floats[\"-T\"] + floats[\"+T\"] +\n         floats[\"+T\"] + floats[\"-T\"] + floats[\"0\"] + floats[\"+T\"] +\n         floats[\"T-1\"] + floats[\"+T\"] + floats[\"+T\"] + floats[\"T-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 20,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 20,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [THICKNESS, THICKNESS, -THICKNESS],\n        \"min\": [0, THICKNESS, THICKNESS - 1],\n    })\n\n    # 21, backside, positions of edge 3: [(+T,1-T,+T),(1-T,1-T,+T),(+T,1,+T),(1-T,1,+T)]\n    s = (floats[\"+T\"] + floats[\"+T\"] + floats[\"T-1\"] + floats[\"1-T\"] +\n         floats[\"+T\"] + floats[\"T-1\"] + floats[\"+T\"] + floats[\"+T\"] +\n         floats[\"-1\"] + floats[\"1-T\"] + floats[\"+T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 21,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 21,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [1 - THICKNESS, THICKNESS, THICKNESS - 1],\n        \"min\": [THICKNESS, THICKNESS, -1],\n    })\n\n    # 22, backside vertices of rect/sqr: [1,3,0, 3,2,0]\n    s = ints[1] + ints[3] + ints[0] + ints[3] + ints[2] + ints[0]\n    gltf[\"buffers\"].append({\"byteLength\": 12, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 22,\n        \"byteLength\": 12,\n        \"byteOffset\": 0,\n        \"target\": 34963\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 22,\n        \"componentType\": 5123,\n        \"type\": \"SCALAR\",\n        \"count\": 6\n    })\n\n    # 23, backside, positions of rectangle: [(0,0,+T),(L,0,+T),(0,1,+T),(L,1,+T)]\n    s = (floats[\"0\"] + floats[\"+T\"] + floats[\"0\"] + floats[\"tube\"] +\n         floats[\"+T\"] + floats[\"0\"] + floats[\"0\"] + floats[\"+T\"] +\n         floats[\"-1\"] + floats[\"tube\"] + floats[\"+T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 23,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 23,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [tubelen, THICKNESS, 0],\n        \"min\": [0, THICKNESS, -1],\n    })\n\n    # 24, backside, positions of half-distance rectangle: [(0,0,+T),(0.45,0,+T),(0,1,+T),(0.45,1,+T)]\n    s = (floats[\"0\"] + floats[\"+T\"] + floats[\"0\"] + floats[\"0.45\"] +\n         floats[\"+T\"] + floats[\"0\"] + floats[\"0\"] + floats[\"+T\"] +\n         floats[\"-1\"] + floats[\"0.45\"] + floats[\"+T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 24,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 24,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [0.45, THICKNESS, 0],\n        \"min\": [0, THICKNESS, -1],\n    })\n\n    # 25, backside, positions of Hadamard rectangle: [(0,0,+T),(15/32L,0,+T),(15/32L,1,+T),\n    # (15/32L,1,+T),(17/32L,0,+T),(17/32L,1,+T),(L,0,+T),(L,1,+T)]\n    floats[\"left\"] = float_to_little_endian_hex(tubelen * 15 / 32)\n    floats[\"right\"] = float_to_little_endian_hex(tubelen * 17 / 32)\n    s = (floats[\"0\"] + floats[\"+T\"] + floats[\"0\"] + floats[\"left\"] +\n         floats[\"+T\"] + floats[\"0\"] + floats[\"0\"] + floats[\"+T\"] +\n         floats[\"-1\"] + floats[\"left\"] + floats[\"+T\"] + floats[\"-1\"] +\n         floats[\"right\"] + floats[\"+T\"] + floats[\"0\"] + floats[\"right\"] +\n         floats[\"+T\"] + floats[\"-1\"] + floats[\"tube\"] + floats[\"+T\"] +\n         floats[\"0\"] + floats[\"tube\"] + floats[\"+T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 96, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 25,\n        \"byteLength\": 96,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 25,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 8,\n        \"max\": [tubelen, THICKNESS, 0],\n        \"min\": [0, THICKNESS, -1],\n    })\n\n    # 26, backside, normals of Hadamard rect (0,0,1)*8\n    s = (floats[\"0\"] + floats[\"1\"] + floats[\"0\"] + floats[\"0\"] + floats[\"1\"] +\n         floats[\"0\"] + floats[\"0\"] + floats[\"1\"] + floats[\"0\"] + floats[\"0\"] +\n         floats[\"1\"] + floats[\"0\"] + floats[\"0\"] + floats[\"1\"] + floats[\"0\"] +\n         floats[\"0\"] + floats[\"1\"] + floats[\"0\"] + floats[\"0\"] + floats[\"1\"] +\n         floats[\"0\"] + floats[\"0\"] + floats[\"1\"] + floats[\"0\"])\n    gltf[\"buffers\"].append({\"byteLength\": 96, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 26,\n        \"byteLength\": 96,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 26,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 8\n    })\n\n    # 27, backside, vertices of middle rect in Hadamard rect: [4,5,1, 5,3,1]\n    s = ints[4] + ints[5] + ints[1] + ints[5] + ints[3] + ints[1]\n    gltf[\"buffers\"].append({\"byteLength\": 12, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 27,\n        \"byteLength\": 12,\n        \"byteOffset\": 0,\n        \"target\": 34963\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 27,\n        \"componentType\": 5123,\n        \"type\": \"SCALAR\",\n        \"count\": 6\n    })\n\n    # 28, backside, vertices of upper rect in Hadamard rect: [6,7,4, 7,5,4]\n    s = ints[6] + ints[7] + ints[4] + ints[7] + ints[5] + ints[4]\n    gltf[\"buffers\"].append({\"byteLength\": 12, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 28,\n        \"byteLength\": 12,\n        \"byteOffset\": 0,\n        \"target\": 34963\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 28,\n        \"componentType\": 5123,\n        \"type\": \"SCALAR\",\n        \"count\": 6\n    })\n\n    # 29, backside, positions of tilted rect: [(0,0,1/2+T),(1/2,0,+T),(0,1,1/2+T),(1/2,1,+T)]\n    s = (floats[\"0\"] + floats[\"0.5-T\"] + floats[\"0\"] + floats[\"0.5\"] +\n         floats[\"-T\"] + floats[\"0\"] + floats[\"0\"] + floats[\"0.5-T\"] +\n         floats[\"-1\"] + floats[\"0.5\"] + floats[\"-T\"] + floats[\"-1\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 29,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 29,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4,\n        \"max\": [0.5, 0.5 - THICKNESS, 0],\n        \"min\": [0, -THICKNESS, -1],\n    })\n\n    # 30, backside, normals of tilted rect: (sqrt(2)/2, 0, sqrt(2)/2)*4\n    s = (floats[\"+SQ2\"] + floats[\"+SQ2\"] + floats[\"0\"] + floats[\"+SQ2\"] +\n         floats[\"+SQ2\"] + floats[\"0\"] + floats[\"+SQ2\"] + floats[\"+SQ2\"] +\n         floats[\"0\"] + floats[\"+SQ2\"] + floats[\"+SQ2\"] + floats[\"0\"])\n    gltf[\"buffers\"].append({\"byteLength\": 48, \"uri\": hex_to_bin(s)})\n    gltf[\"bufferViews\"].append({\n        \"buffer\": 30,\n        \"byteLength\": 48,\n        \"byteOffset\": 0,\n        \"target\": 34962\n    })\n    gltf[\"accessors\"].append({\n        \"bufferView\": 30,\n        \"componentType\": 5126,\n        \"type\": \"VEC3\",\n        \"count\": 4\n    })\n\n    # finished creating the binary\n\n    # Now we create meshes. These are the real constructors of the 3D diagram.\n    # a mesh can contain multiple primitives. A primitive can be defined by a\n    # set of vertices POSITION, their NORMAL vectors, the order of going around\n    # these vertices, and the color (material) for the triangles defined by\n    # going around the vertices. `mode:4` means color these triangles.\n    gltf[\"meshes\"] = [\n        {\n            \"name\":\n            \"0-square-blue\",\n            \"primitives\": [\n                # front side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 0\n                    },\n                    \"indices\": 3,\n                    \"material\": 0,\n                    \"mode\": 4,\n                },\n                # back side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 12\n                    },\n                    \"indices\": 22,\n                    \"material\": 0,\n                    \"mode\": 4,\n                },\n                # front side edge 0\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 14\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # front side edge 1\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 15\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # front side edge 2\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 16\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # front side edge 3\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 17\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # back side edge 0\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 18\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # back side edge 1\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 19\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # back side edge 2\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 20\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # back side edge 3\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 21\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"1-square-red\",\n            \"primitives\": [\n                # front side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 0\n                    },\n                    \"indices\": 3,\n                    \"material\": 1,\n                    \"mode\": 4,\n                },\n                # back side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 12\n                    },\n                    \"indices\": 22,\n                    \"material\": 1,\n                    \"mode\": 4,\n                },\n                # front side edge 0\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 14\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # front side edge 1\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 15\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # front side edge 2\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 16\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # front side edge 3\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 17\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # back side edge 0\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 18\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # back side edge 1\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 19\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # back side edge 2\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 20\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # back side edge 3\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 21\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"2-square-gray\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 0\n                    },\n                    \"indices\": 3,\n                    \"material\": 3,\n                    \"mode\": 4,\n                },\n                # back side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 12\n                    },\n                    \"indices\": 22,\n                    \"material\": 3,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"3-square-green\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 0\n                    },\n                    \"indices\": 3,\n                    \"material\": 2,\n                    \"mode\": 4,\n                },  # back side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 12\n                    },\n                    \"indices\": 22,\n                    \"material\": 2,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"4-rectangle-blue\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 1\n                    },\n                    \"indices\": 3,\n                    \"material\": 0,\n                    \"mode\": 4,\n                },\n                # backside\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 23\n                    },\n                    \"indices\": 22,\n                    \"material\": 0,\n                    \"mode\": 4,\n                }\n            ],\n        },\n        {\n            \"name\":\n            \"5-rectangle-red\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 1\n                    },\n                    \"indices\": 3,\n                    \"material\": 1,\n                    \"mode\": 4,\n                },\n                # backside\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 23\n                    },\n                    \"indices\": 22,\n                    \"material\": 1,\n                    \"mode\": 4,\n                }\n            ],\n        },\n        {\n            \"name\":\n            \"6-rectangle-gray\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 1\n                    },\n                    \"indices\": 3,\n                    \"material\": 3,\n                    \"mode\": 4,\n                },\n                # backside\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 23\n                    },\n                    \"indices\": 22,\n                    \"material\": 3,\n                    \"mode\": 4,\n                }\n            ],\n        },\n        {\n            \"name\":\n            \"7-rectangle-red/yellow/blue\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 7,\n                        \"POSITION\": 6\n                    },\n                    \"indices\": 3,\n                    \"material\": 1,\n                    \"mode\": 4,\n                },\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 7,\n                        \"POSITION\": 6\n                    },\n                    \"indices\": 8,\n                    \"material\": 6,\n                    \"mode\": 4,\n                },\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 7,\n                        \"POSITION\": 6\n                    },\n                    \"indices\": 9,\n                    \"material\": 0,\n                    \"mode\": 4,\n                },\n                # backside\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 26,\n                        \"POSITION\": 25\n                    },\n                    \"indices\": 22,\n                    \"material\": 1,\n                    \"mode\": 4,\n                },\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 26,\n                        \"POSITION\": 25\n                    },\n                    \"indices\": 27,\n                    \"material\": 6,\n                    \"mode\": 4,\n                },\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 26,\n                        \"POSITION\": 25\n                    },\n                    \"indices\": 28,\n                    \"material\": 0,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"8-rectangle-blue/yellow/red\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 7,\n                        \"POSITION\": 6\n                    },\n                    \"indices\": 3,\n                    \"material\": 0,\n                    \"mode\": 4,\n                },\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 7,\n                        \"POSITION\": 6\n                    },\n                    \"indices\": 8,\n                    \"material\": 6,\n                    \"mode\": 4,\n                },\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 7,\n                        \"POSITION\": 6\n                    },\n                    \"indices\": 9,\n                    \"material\": 1,\n                    \"mode\": 4,\n                },\n                # backside\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 26,\n                        \"POSITION\": 25\n                    },\n                    \"indices\": 22,\n                    \"material\": 0,\n                    \"mode\": 4,\n                },\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 26,\n                        \"POSITION\": 25\n                    },\n                    \"indices\": 27,\n                    \"material\": 6,\n                    \"mode\": 4,\n                },\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 26,\n                        \"POSITION\": 25\n                    },\n                    \"indices\": 28,\n                    \"material\": 1,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"9-square-cyan.3\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 0\n                    },\n                    \"indices\": 3,\n                    \"material\": 4,\n                    \"mode\": 4,\n                },  # back side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 12\n                    },\n                    \"indices\": 22,\n                    \"material\": 4,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"10-rectangle-cyan.3\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 1\n                    },\n                    \"indices\": 3,\n                    \"material\": 4,\n                    \"mode\": 4,\n                },\n                # backside\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 23\n                    },\n                    \"indices\": 22,\n                    \"material\": 4,\n                    \"mode\": 4,\n                }\n            ],\n        },\n        {\n            \"name\":\n            \"11-tilted-cyan.3\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 5,\n                        \"POSITION\": 4\n                    },\n                    \"indices\": 3,\n                    \"material\": 4,\n                    \"mode\": 4,\n                },\n                # backside\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 30,\n                        \"POSITION\": 29\n                    },\n                    \"indices\": 22,\n                    \"material\": 4,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"12-half-distance-rectangle-green\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 11\n                    },\n                    \"indices\": 3,\n                    \"material\": 2,\n                    \"mode\": 4,\n                },\n                # back side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 24\n                    },\n                    \"indices\": 22,\n                    \"material\": 2,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"13-square-black\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 0\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },  # back side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 12\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n            ],\n        },\n        {\n            \"name\":\n            \"14-half-distance-rectangle-black\",\n            \"primitives\": [\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 2,\n                        \"POSITION\": 11\n                    },\n                    \"indices\": 3,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n                # back side\n                {\n                    \"attributes\": {\n                        \"NORMAL\": 13,\n                        \"POSITION\": 24\n                    },\n                    \"indices\": 22,\n                    \"material\": 5,\n                    \"mode\": 4,\n                },\n            ],\n        },\n    ]\n\n    return gltf\n\n\ndef axes_gen(SEP: float, max_i: int, max_j: int,\n             max_k: int) -> Sequence[Mapping[str, Any]]:\n    rectangles = []\n\n    # I axis, red\n    rectangles += [\n        {\n            \"name\": f\"axisI:-K\",\n            \"mesh\": 5,\n            \"translation\": [-0.5, -0.5, 0.5],\n            \"scale\": [SEP * max_i / (SEP - 1), AXESTHICKNESS, AXESTHICKNESS],\n        },\n        {\n            \"name\": f\"axisI:+K\",\n            \"mesh\": 5,\n            \"translation\": [-0.5, -0.5 + AXESTHICKNESS, 0.5],\n            \"scale\": [SEP * max_i / (SEP - 1), AXESTHICKNESS, AXESTHICKNESS],\n        },\n        {\n            \"name\": f\"axisI:-J\",\n            \"mesh\": 5,\n            \"translation\": [-0.5, -0.5, 0.5],\n            \"rotation\": [SQ2, 0, 0, SQ2],\n            \"scale\": [SEP * max_i / (SEP - 1), AXESTHICKNESS, AXESTHICKNESS],\n        },\n        {\n            \"name\": f\"axisI:+J\",\n            \"mesh\": 5,\n            \"translation\": [-0.5, -0.5, 0.5 - AXESTHICKNESS],\n            \"rotation\": [SQ2, 0, 0, SQ2],\n            \"scale\": [SEP * max_i / (SEP - 1), AXESTHICKNESS, AXESTHICKNESS],\n        },\n    ]\n\n    # J axis, green\n    rectangles += [\n        {\n            \"name\": f\"axisJ:-K\",\n            \"rotation\": [0, SQ2, 0, SQ2],\n            \"translation\": [-0.5 + AXESTHICKNESS, -0.5, 0.5],\n            \"mesh\": 3,\n            \"scale\": [SEP * max_j, AXESTHICKNESS, AXESTHICKNESS],\n        },\n        {\n            \"name\": f\"axisJ:+K\",\n            \"rotation\": [0, SQ2, 0, SQ2],\n            \"translation\": [\n                -0.5 + AXESTHICKNESS,\n                -0.5 + AXESTHICKNESS,\n                0.5,\n            ],\n            \"mesh\": 3,\n            \"scale\": [SEP * max_j, AXESTHICKNESS, AXESTHICKNESS],\n        },\n        {\n            \"name\": f\"axisJ:-I\",\n            \"rotation\": [0.5, 0.5, -0.5, 0.5],\n            \"translation\": [-0.5, -0.5, 0.5],\n            \"mesh\": 3,\n            \"scale\": [SEP * max_j, AXESTHICKNESS, AXESTHICKNESS],\n        },\n        {\n            \"name\": f\"axisJ:+I\",\n            \"rotation\": [0.5, 0.5, -0.5, 0.5],\n            \"translation\": [-0.5 + AXESTHICKNESS, -0.5, 0.5],\n            \"mesh\": 3,\n            \"scale\": [SEP * max_j, AXESTHICKNESS, AXESTHICKNESS],\n        },\n    ]\n\n    # K axis, blue\n    rectangles += [\n        {\n            \"name\": f\"axisK:-I\",\n            \"mesh\": 4,\n            \"rotation\": [0, 0, SQ2, SQ2],\n            \"translation\": [-0.5, -0.5 + AXESTHICKNESS, 0.5],\n            \"scale\": [SEP * max_k / (SEP - 1), AXESTHICKNESS, AXESTHICKNESS],\n        },\n        {\n            \"name\": f\"axisK:+I\",\n            \"mesh\": 4,\n            \"rotation\": [0, 0, SQ2, SQ2],\n            \"translation\": [-0.5 + AXESTHICKNESS, -0.5 + AXESTHICKNESS, 0.5],\n            \"scale\": [SEP * max_k / (SEP - 1), AXESTHICKNESS, AXESTHICKNESS],\n        },\n        {\n            \"name\": f\"axisK:-J\",\n            \"mesh\": 4,\n            \"rotation\": [0.5, 0.5, 0.5, 0.5],\n            \"translation\": [-0.5 + AXESTHICKNESS, -0.5 + AXESTHICKNESS, 0.5],\n            \"scale\": [SEP * max_k / (SEP - 1), AXESTHICKNESS, AXESTHICKNESS],\n        },\n        {\n            \"name\":\n            f\"axisK:+J\",\n            \"mesh\":\n            4,\n            \"rotation\": [0.5, 0.5, 0.5, 0.5],\n            \"translation\": [\n                -0.5 + AXESTHICKNESS,\n                -0.5 + AXESTHICKNESS,\n                0.5 - AXESTHICKNESS,\n            ],\n            \"scale\": [SEP * max_k / (SEP - 1), AXESTHICKNESS, AXESTHICKNESS],\n        },\n    ]\n\n    return rectangles\n\n\ndef tube_gen(SEP: float, loc: Tuple[int, int, int], dir: str, color: int,\n             stabilizer: int, corr: Tuple[int, int], noColor: bool,\n             rm_dir: str) -> Sequence[Mapping[str, Any]]:\n    \"\"\"compute the GLTF nodes for a pipe. This can include its four faces and\n    correlation surface inside, minus the face to remove specified by rm_dir. \n\n    Args:\n        SEP (float): the distance, e.g., from I-pipe(i,j,k) to I-pipe(i+1,j,k).\n        loc (Tuple[int, int, int]): 3D coordinate of the pipe.\n        dir (str): direction of the pipe, \"I\", \"J\", or \"K\".\n        color (int): color variable of the pipe, can be -1(unknown), 0, or 1.\n        stabilizer (int): index of the stabilizer.\n        corr (Tuple[int, int]): two bits for two possible corr surface inside.\n        noColor (bool): K-pipe are not colored if this is True.\n        rm_dir (str): the direction of face to remove. if a stabilier is shown.\n\n    Returns:\n        Sequence[Mapping[str, Any]]: list of constructed GLTF nodes, typically\n            4 or 5 contiguous nodes in the list corredpond to one pipe.\n    \"\"\"\n    rectangles = []\n    if dir == \"I\":\n        rectangles = [\n            {\n                \"name\": f\"edgeI{loc}:-K\",\n                \"mesh\": 4 if color else 5,\n                \"translation\": [1 + SEP * loc[0], SEP * loc[2], -SEP * loc[1]],\n            },\n            {\n                \"name\": f\"edgeI{loc}:+K\",\n                \"mesh\": 4 if color else 5,\n                \"translation\":\n                [1 + SEP * loc[0], 1 + SEP * loc[2], -SEP * loc[1]],\n            },\n            {\n                \"name\": f\"edgeI{loc}:-J\",\n                \"mesh\": 5 if color else 4,\n                \"translation\": [1 + SEP * loc[0], SEP * loc[2], -SEP * loc[1]],\n                \"rotation\": [SQ2, 0, 0, SQ2],\n            },\n            {\n                \"name\": f\"edgeI{loc}:+J\",\n                \"mesh\": 5 if color else 4,\n                \"translation\":\n                [1 + SEP * loc[0], SEP * loc[2], -1 - SEP * loc[1]],\n                \"rotation\": [SQ2, 0, 0, SQ2],\n            },\n        ]\n        if corr[0]:\n            rectangles.append({\n                \"name\":\n                f\"edgeI{loc}:CorrIJ\",\n                \"mesh\":\n                10,\n                \"translation\": [\n                    1 + SEP * loc[0],\n                    0.5 + SEP * loc[2],\n                    -SEP * loc[1],\n                ],\n            })\n        if corr[1]:\n            rectangles.append({\n                \"name\":\n                f\"edgeI{loc}:CorrIK\",\n                \"mesh\":\n                10,\n                \"translation\": [\n                    1 + SEP * loc[0],\n                    SEP * loc[2],\n                    -0.5 - SEP * loc[1],\n                ],\n                \"rotation\": [SQ2, 0, 0, SQ2],\n            })\n    elif dir == \"J\":\n        rectangles = [\n            {\n                \"name\": f\"edgeJ{loc}:-K\",\n                \"rotation\": [0, SQ2, 0, SQ2],\n                \"translation\":\n                [1 + SEP * loc[0], SEP * loc[2], -1 - SEP * loc[1]],\n                \"mesh\": 5 if color else 4,\n            },\n            {\n                \"name\":\n                f\"edgeJ{loc}:+K\",\n                \"rotation\": [0, SQ2, 0, SQ2],\n                \"translation\": [\n                    1 + SEP * loc[0],\n                    1 + SEP * loc[2],\n                    -1 - SEP * loc[1],\n                ],\n                \"mesh\":\n                5 if color else 4,\n            },\n            {\n                \"name\": f\"edgeJ{loc}:-I\",\n                \"rotation\": [0.5, 0.5, -0.5, 0.5],\n                \"translation\": [SEP * loc[0], SEP * loc[2], -1 - SEP * loc[1]],\n                \"mesh\": 4 if color else 5,\n            },\n            {\n                \"name\": f\"edgeJ{loc}:+I\",\n                \"rotation\": [0.5, 0.5, -0.5, 0.5],\n                \"translation\":\n                [1 + SEP * loc[0], SEP * loc[2], -1 - SEP * loc[1]],\n                \"mesh\": 4 if color else 5,\n            },\n        ]\n        if corr[0]:\n            rectangles.append({\n                \"name\":\n                f\"edgeJ{loc}:CorrJK\",\n                \"mesh\":\n                10,\n                \"rotation\": [0.5, 0.5, -0.5, 0.5],\n                \"translation\": [\n                    0.5 + SEP * loc[0],\n                    SEP * loc[2],\n                    -1 - SEP * loc[1],\n                ],\n            })\n        if corr[1]:\n            rectangles.append({\n                \"name\":\n                f\"edgeJ{loc}:CorrJI\",\n                \"mesh\":\n                10,\n                \"rotation\": [0, SQ2, 0, SQ2],\n                \"translation\": [\n                    1 + SEP * loc[0],\n                    0.5 + SEP * loc[2],\n                    -1 - SEP * loc[1],\n                ],\n            })\n\n    elif dir == \"K\":\n        colorKM = color // 7\n        colorKP = color % 7\n        rectangles = [\n            {\n                \"name\": f\"edgeJ{loc}:-I\",\n                \"mesh\": 6,\n                \"rotation\": [0, 0, SQ2, SQ2],\n                \"translation\": [SEP * loc[0], 1 + SEP * loc[2], -SEP * loc[1]],\n            },\n            {\n                \"name\": f\"edgeJ{loc}:+I\",\n                \"mesh\": 6,\n                \"rotation\": [0, 0, SQ2, SQ2],\n                \"translation\":\n                [1 + SEP * loc[0], 1 + SEP * loc[2], -SEP * loc[1]],\n            },\n            {\n                \"name\": f\"edgeK{loc}:-J\",\n                \"mesh\": 6,\n                \"rotation\": [0.5, 0.5, 0.5, 0.5],\n                \"translation\":\n                [1 + SEP * loc[0], 1 + SEP * loc[2], -SEP * loc[1]],\n            },\n            {\n                \"name\":\n                f\"edgeJ{loc}:+J\",\n                \"mesh\":\n                6,\n                \"rotation\": [0.5, 0.5, 0.5, 0.5],\n                \"translation\": [\n                    1 + SEP * loc[0],\n                    1 + SEP * loc[2],\n                    -1 - SEP * loc[1],\n                ],\n            },\n        ]\n        if not noColor:\n            if colorKM == 0 and colorKP == 0:\n                rectangles[0][\"mesh\"] = 4\n                rectangles[1][\"mesh\"] = 4\n                rectangles[2][\"mesh\"] = 5\n                rectangles[3][\"mesh\"] = 5\n            if colorKM == 1 and colorKP == 1:\n                rectangles[0][\"mesh\"] = 5\n                rectangles[1][\"mesh\"] = 5\n                rectangles[2][\"mesh\"] = 4\n                rectangles[3][\"mesh\"] = 4\n            if colorKM == 1 and colorKP == 0:\n                rectangles[0][\"mesh\"] = 7\n                rectangles[1][\"mesh\"] = 7\n                rectangles[2][\"mesh\"] = 8\n                rectangles[3][\"mesh\"] = 8\n            if colorKM == 0 and colorKP == 1:\n                rectangles[0][\"mesh\"] = 8\n                rectangles[1][\"mesh\"] = 8\n                rectangles[2][\"mesh\"] = 7\n                rectangles[3][\"mesh\"] = 7\n\n        if corr[0]:\n            rectangles.append({\n                \"name\":\n                f\"edgeK{loc}:CorrKI\",\n                \"mesh\":\n                10,\n                \"rotation\": [0.5, 0.5, 0.5, 0.5],\n                \"translation\": [\n                    1 + SEP * loc[0],\n                    1 + SEP * loc[2],\n                    -0.5 - SEP * loc[1],\n                ],\n            })\n        if corr[1]:\n            rectangles.append({\n                \"name\":\n                f\"edgeK{loc}:CorrKJ\",\n                \"mesh\":\n                10,\n                \"rotation\": [0, 0, SQ2, SQ2],\n                \"translation\": [\n                    0.5 + SEP * loc[0],\n                    1 + SEP * loc[2],\n                    -SEP * loc[1],\n                ],\n            })\n\n    rectangles = [rect for rect in rectangles if rm_dir not in rect[\"name\"]]\n    if stabilizer == -1:\n        rectangles = [\n            rect for rect in rectangles if \"Corr\" not in rect[\"name\"]\n        ]\n    return rectangles\n\n\ndef cube_gen(\n    SEP: float,\n    loc: Tuple[int, int, int],\n    exists: Mapping[str, int],\n    colors: Mapping[str, int],\n    stabilizer: int,\n    corr: Mapping[str, Tuple[int, int]],\n    noColor: bool,\n    rm_dir: str,\n) -> Sequence[Mapping[str, Any]]:\n    \"\"\"compute the GLTF nodes for a cube. This can include its faces and\n    correlation surface inside, minus the face to remove specified by rm_dir. \n\n    Args:\n        SEP (float): the distance, e.g., from cube(i,j,k) to cube(i+1,j,k).\n        loc (Tuple[int, int, int]): 3D coordinate of the pipe.\n        exists (Mapping[str, int]): whether there is a pipe in the 6 directions\n            to this cube. (+|-)(I|J|K).\n        colors (Mapping[str, int]): color variable of the pipe, can be\n            -1(unknown), 0, or 1.\n        stabilizer (int): index of the stabilizer.\n        corr (Mapping[str, Tuple[int, int]]): two bits for two possible\n            correlation surface inside a pipe. These info for all 6 pipes.\n        noColor (bool): K-pipe are not colored if this is True.\n        rm_dir (str): the direction of face to remove. if a stabilier is shown.\n\n    Returns:\n        Sequence[Mapping[str, Any]]: list of constructed GLTF nodes.\n    \"\"\"\n    squares = []\n    for face in [\"-K\", \"+K\"]:\n        if exists[face] == 0:\n            squares.append({\n                \"name\":\n                f\"spider{loc}:{face}\",\n                \"mesh\":\n                2,\n                \"translation\": [\n                    SEP * loc[0],\n                    (1 if face == \"+K\" else 0) + SEP * loc[2],\n                    -SEP * loc[1],\n                ],\n            })\n            for dir in [\"+I\", \"-I\", \"+J\", \"-J\"]:\n                if exists[dir]:\n                    if dir == \"+I\" or dir == \"-I\":\n                        if colors[dir] == 1:\n                            squares[-1][\"mesh\"] = 0\n                        else:\n                            squares[-1][\"mesh\"] = 1\n                    else:\n                        if colors[dir] == 0:\n                            squares[-1][\"mesh\"] = 0\n                        else:\n                            squares[-1][\"mesh\"] = 1\n                    break\n    for face in [\"-I\", \"+I\"]:\n        if exists[face] == 0:\n            squares.append({\n                \"name\":\n                f\"spider{loc}:{face}\",\n                \"mesh\":\n                2,\n                \"translation\": [\n                    (1 if face == \"+I\" else 0) + SEP * loc[0],\n                    SEP * loc[2],\n                    -SEP * loc[1],\n                ],\n                \"rotation\": [0, 0, SQ2, SQ2],\n            })\n            for dir in [\"+J\", \"-J\", \"+K\", \"-K\"]:\n                if exists[dir]:\n                    if dir == \"+J\" or dir == \"-J\":\n                        if colors[dir] == 1:\n                            squares[-1][\"mesh\"] = 0\n                        else:\n                            squares[-1][\"mesh\"] = 1\n                    elif not noColor:\n                        if colors[dir] == 1:\n                            squares[-1][\"mesh\"] = 1\n                        elif colors[dir] == 0:\n                            squares[-1][\"mesh\"] = 0\n    for face in [\"-J\", \"+J\"]:\n        if exists[face] == 0:\n            squares.append({\n                \"name\":\n                f\"spider{loc}:{face}\",\n                \"mesh\":\n                2,\n                \"translation\": [\n                    1 + SEP * loc[0],\n                    SEP * loc[2],\n                    (-1 if face == \"+J\" else 0) - SEP * loc[1],\n                ],\n                \"rotation\": [0.5, 0.5, 0.5, 0.5],\n            })\n            for dir in [\"+I\", \"-I\", \"+K\", \"-K\"]:\n                if exists[dir]:\n                    if dir == \"+I\" or dir == \"-I\":\n                        if colors[dir] == 0:\n                            squares[-1][\"mesh\"] = 0\n                        else:\n                            squares[-1][\"mesh\"] = 1\n                    elif not noColor:\n                        if colors[dir] == 1:\n                            squares[-1][\"mesh\"] = 0\n                        elif colors[dir] == 0:\n                            squares[-1][\"mesh\"] = 1\n\n    degree = sum([v for (k, v) in exists.items()])\n    normal = {\"I\": 0, \"J\": 0, \"K\": 0}\n    if exists[\"-I\"] == 0 and exists[\"+I\"] == 0:\n        normal[\"I\"] = 1\n    if exists[\"-J\"] == 0 and exists[\"+J\"] == 0:\n        normal[\"J\"] = 1\n    if exists[\"-K\"] == 0 and exists[\"+K\"] == 0:\n        normal[\"K\"] = 1\n    if degree > 1:\n        if (exists[\"-I\"] and exists[\"+I\"] and exists[\"-J\"] == 0\n                and exists[\"+J\"] == 0 and exists[\"-K\"] == 0\n                and exists[\"+K\"] == 0):\n            if corr[\"-I\"][0]:\n                squares.append({\n                    \"name\":\n                    f\"spider{loc}:Corr\",\n                    \"mesh\":\n                    9,\n                    \"translation\": [\n                        SEP * loc[0],\n                        0.5 + SEP * loc[2],\n                        -SEP * loc[1],\n                    ],\n                })\n            if corr[\"-I\"][1]:\n                squares.append({\n                    \"name\":\n                    f\"spider{loc}:Corr\",\n                    \"mesh\":\n                    9,\n                    \"translation\": [\n                        1 + SEP * loc[0],\n                        SEP * loc[2],\n                        -0.5 - SEP * loc[1],\n                    ],\n                    \"rotation\": [0.5, 0.5, 0.5, 0.5],\n                })\n        elif (exists[\"-I\"] == 0 and exists[\"+I\"] == 0 and exists[\"-J\"]\n              and exists[\"+J\"] and exists[\"-K\"] == 0 and exists[\"+K\"] == 0):\n            if corr[\"-J\"][0]:\n                squares.append({\n                    \"name\":\n                    f\"spider{loc}:Corr\",\n                    \"mesh\":\n                    9,\n                    \"translation\": [\n                        0.5 + SEP * loc[0],\n                        SEP * loc[2],\n                        -SEP * loc[1],\n                    ],\n                    \"rotation\": [0, 0, SQ2, SQ2],\n                })\n            if corr[\"-J\"][1]:\n                squares.append({\n                    \"name\":\n                    f\"spider{loc}:Corr\",\n                    \"mesh\":\n                    9,\n                    \"translation\": [\n                        SEP * loc[0],\n                        0.5 + SEP * loc[2],\n                        -SEP * loc[1],\n                    ],\n                })\n        elif (exists[\"-I\"] == 0 and exists[\"+I\"] == 0 and exists[\"-J\"] == 0\n              and exists[\"+J\"] == 0 and exists[\"-K\"] and exists[\"+K\"]):\n            if corr[\"-K\"][0]:\n                squares.append({\n                    \"name\":\n                    f\"spider{loc}:Corr\",\n                    \"mesh\":\n                    9,\n                    \"translation\": [\n                        1 + SEP * loc[0],\n                        SEP * loc[2],\n                        -0.5 - SEP * loc[1],\n                    ],\n                    \"rotation\": [0.5, 0.5, 0.5, 0.5],\n                })\n            if corr[\"-K\"][1]:\n                squares.append({\n                    \"name\":\n                    f\"spider{loc}:Corr\",\n                    \"mesh\":\n                    9,\n                    \"translation\": [\n                        0.5 + SEP * loc[0],\n                        SEP * loc[2],\n                        -SEP * loc[1],\n                    ],\n                    \"rotation\": [0, 0, SQ2, SQ2],\n                })\n        else:\n            if normal[\"I\"]:\n                if corr[\"-J\"][0] or corr[\"+J\"][0] or corr[\"-K\"][1] or corr[\n                        \"+K\"][1]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        9,\n                        \"translation\": [\n                            0.5 + SEP * loc[0],\n                            SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                        \"rotation\": [0, 0, SQ2, SQ2],\n                    })\n\n                if corr[\"-J\"][1] and corr[\"+J\"][1] and corr[\"-K\"][0] and corr[\n                        \"+K\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            SEP * loc[0],\n                            SEP * loc[2],\n                            -1 - SEP * loc[1],\n                        ],\n                        \"rotation\": [0, -SQ2, 0, SQ2],\n                    })\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            SEP * loc[0],\n                            0.5 + SEP * loc[2],\n                            -0.5 - SEP * loc[1],\n                        ],\n                        \"rotation\": [0, -SQ2, 0, SQ2],\n                    })\n                elif corr[\"-J\"][1] and corr[\"+J\"][1]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        9,\n                        \"translation\": [\n                            SEP * loc[0],\n                            0.5 + SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                    })\n                elif corr[\"-K\"][0] and corr[\"+K\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        9,\n                        \"translation\": [\n                            1 + SEP * loc[0],\n                            SEP * loc[2],\n                            -0.5 - SEP * loc[1],\n                        ],\n                        \"rotation\": [0.5, 0.5, 0.5, 0.5],\n                    })\n                elif corr[\"-J\"][1] and corr[\"-K\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            1 + SEP * loc[0],\n                            SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                        \"rotation\": [0, SQ2, 0, SQ2],\n                    })\n                elif corr[\"+J\"][1] and corr[\"+K\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            1 + SEP * loc[0],\n                            0.5 + SEP * loc[2],\n                            -0.5 - SEP * loc[1],\n                        ],\n                        \"rotation\": [0, SQ2, 0, SQ2],\n                    })\n                elif corr[\"+J\"][1] and corr[\"-K\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            SEP * loc[0],\n                            SEP * loc[2],\n                            -1 - SEP * loc[1],\n                        ],\n                        \"rotation\": [0, -SQ2, 0, SQ2],\n                    })\n                elif corr[\"-J\"][1] and corr[\"+K\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            SEP * loc[0],\n                            0.5 + SEP * loc[2],\n                            -0.5 - SEP * loc[1],\n                        ],\n                        \"rotation\": [0, -SQ2, 0, SQ2],\n                    })\n            elif normal[\"J\"]:\n                if corr[\"-K\"][0] or corr[\"+K\"][0] or corr[\"-I\"][1] or corr[\n                        \"+I\"][1]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        9,\n                        \"translation\": [\n                            1 + SEP * loc[0],\n                            SEP * loc[2],\n                            -0.5 - SEP * loc[1],\n                        ],\n                        \"rotation\": [0.5, 0.5, 0.5, 0.5],\n                    })\n\n                if corr[\"-K\"][1] and corr[\"+K\"][1] and corr[\"-I\"][0] and corr[\n                        \"+I\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            0.5 + SEP * loc[0],\n                            0.5 + SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                        \"rotation\": [0, 0, SQ2, SQ2],\n                    })\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            1 + SEP * loc[0],\n                            SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                        \"rotation\": [0, 0, SQ2, SQ2],\n                    })\n                elif corr[\"-K\"][1] and corr[\"+K\"][1]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        9,\n                        \"translation\": [\n                            0.5 + SEP * loc[0],\n                            SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                        \"rotation\": [0, 0, SQ2, SQ2],\n                    })\n                elif corr[\"-I\"][0] and corr[\"+I\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        9,\n                        \"translation\": [\n                            SEP * loc[0],\n                            0.5 + SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                    })\n                elif corr[\"-K\"][1] and corr[\"-I\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\":\n                        [SEP * loc[0], SEP * loc[2], -SEP * loc[1]],\n                    })\n                elif corr[\"+K\"][1] and corr[\"+I\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            0.5 + SEP * loc[0],\n                            0.5 + SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                    })\n                elif corr[\"+K\"][1] and corr[\"-I\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            0.5 + SEP * loc[0],\n                            0.5 + SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                        \"rotation\": [0, 0, SQ2, SQ2],\n                    })\n                elif corr[\"-K\"][1] and corr[\"+I\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            1 + SEP * loc[0],\n                            SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                        \"rotation\": [0, 0, SQ2, SQ2],\n                    })\n            else:\n                if corr[\"-I\"][0] or corr[\"+I\"][0] or corr[\"-J\"][1] or corr[\n                        \"+J\"][1]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        9,\n                        \"translation\": [\n                            SEP * loc[0],\n                            0.5 + SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                    })\n\n                if corr[\"-I\"][1] and corr[\"+I\"][1] and corr[\"-J\"][0] and corr[\n                        \"+J\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            0.5 + SEP * loc[0],\n                            SEP * loc[2],\n                            -0.5 - SEP * loc[1],\n                        ],\n                        \"rotation\": [SQ2, 0, 0, SQ2],\n                    })\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            SEP * loc[0],\n                            SEP * loc[2],\n                            -1 - SEP * loc[1],\n                        ],\n                        \"rotation\": [SQ2, 0, 0, SQ2],\n                    })\n                elif corr[\"-I\"][1] and corr[\"+I\"][1]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        9,\n                        \"translation\": [\n                            1 + SEP * loc[0],\n                            SEP * loc[2],\n                            -0.5 - SEP * loc[1],\n                        ],\n                        \"rotation\": [0.5, 0.5, 0.5, 0.5],\n                    })\n                elif corr[\"-J\"][0] and corr[\"+J\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        9,\n                        \"translation\": [\n                            0.5 + SEP * loc[0],\n                            SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                        \"rotation\": [0, 0, SQ2, SQ2],\n                    })\n                elif corr[\"-I\"][1] and corr[\"-J\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            SEP * loc[0],\n                            1 + SEP * loc[2],\n                            -SEP * loc[1],\n                        ],\n                        \"rotation\": [-SQ2, 0, 0, SQ2],\n                    })\n                elif corr[\"+I\"][1] and corr[\"+J\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            0.5 + SEP * loc[0],\n                            1 + SEP * loc[2],\n                            -0.5 - SEP * loc[1],\n                        ],\n                        \"rotation\": [-SQ2, 0, 0, SQ2],\n                    })\n                elif corr[\"+I\"][1] and corr[\"-J\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            0.5 + SEP * loc[0],\n                            SEP * loc[2],\n                            -0.5 - SEP * loc[1],\n                        ],\n                        \"rotation\": [SQ2, 0, 0, SQ2],\n                    })\n                elif corr[\"-I\"][1] and corr[\"+J\"][0]:\n                    squares.append({\n                        \"name\":\n                        f\"spider{loc}:Corr\",\n                        \"mesh\":\n                        11,\n                        \"translation\": [\n                            SEP * loc[0],\n                            SEP * loc[2],\n                            -1 - SEP * loc[1],\n                        ],\n                        \"rotation\": [SQ2, 0, 0, SQ2],\n                    })\n\n    squares = [sqar for sqar in squares if rm_dir not in sqar[\"name\"]]\n    if stabilizer == -1:\n        squares = [sqar for sqar in squares if \"Corr\" not in sqar[\"name\"]]\n    return squares\n\n\ndef special_gen(\n    SEP: float,\n    loc: Tuple[int, int, int],\n    exists: Mapping[str, int],\n    type: str,\n    stabilizer: int,\n    rm_dir: str,\n) -> Sequence[Mapping[str, Any]]:\n    \"\"\"compute the GLTF nodes for special cubes. Currently Ycube and Tinjection \n\n    Args:\n        SEP (float): the distance, e.g., from cube(i,j,k) to cube(i+1,j,k).\n        loc (Tuple[int, int, int]): 3D coordinate of the pipe.\n        exists (Mapping[str, int]): whether there is a pipe in the 6 directions\n            to this cube. (+|-)(I|J|K).\n        stabilizer (int): index of the stabilizer.\n        noColor (bool): K-pipe are not colored if this is True.\n        rm_dir (str): the direction of face to remove. if a stabilier is shown.\n\n    Returns:\n        Sequence[Mapping[str, Any]]: list of constructed GLTF nodes.\n    \"\"\"\n    if type == \"Y\":\n        square_mesh = 3\n        half_dist_mesh = 12\n    elif type == \"T\":\n        square_mesh = 13\n        half_dist_mesh = 14\n    else:\n        square_mesh = -1\n        half_dist_mesh = -1\n\n    shapes = []\n    if exists[\"+K\"]:\n        # need connect to top\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:top:-K\",\n            \"mesh\":\n            square_mesh,\n            \"translation\": [\n                SEP * loc[0],\n                0.55 + SEP * loc[2],\n                -SEP * loc[1],\n            ],\n        })\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:top:-I\",\n            \"mesh\":\n            half_dist_mesh,\n            \"rotation\": [0, 0, SQ2, SQ2],\n            \"translation\": [SEP * loc[0], 0.55 + SEP * loc[2], -SEP * loc[1]],\n        })\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:top:+I\",\n            \"mesh\":\n            half_dist_mesh,\n            \"rotation\": [0, 0, SQ2, SQ2],\n            \"translation\":\n            [1 + SEP * loc[0], 0.55 + SEP * loc[2], -SEP * loc[1]],\n        })\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:top:-J\",\n            \"mesh\":\n            half_dist_mesh,\n            \"rotation\": [0.5, 0.5, 0.5, 0.5],\n            \"translation\":\n            [1 + SEP * loc[0], 0.55 + SEP * loc[2], -SEP * loc[1]],\n        })\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:top:+J\",\n            \"mesh\":\n            half_dist_mesh,\n            \"rotation\": [0.5, 0.5, 0.5, 0.5],\n            \"translation\": [\n                1 + SEP * loc[0],\n                0.55 + SEP * loc[2],\n                -SEP * loc[1] - 1,\n            ],\n        })\n\n    if exists[\"-K\"]:\n        # need connect to bottom\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:bottom:+K\",\n            \"mesh\":\n            square_mesh,\n            \"translation\": [\n                SEP * loc[0],\n                0.45 + SEP * loc[2],\n                -SEP * loc[1],\n            ],\n        })\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:bottom:-I\",\n            \"mesh\":\n            half_dist_mesh,\n            \"rotation\": [0, 0, SQ2, SQ2],\n            \"translation\": [SEP * loc[0], SEP * loc[2], -SEP * loc[1]],\n        })\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:bottom:+I\",\n            \"mesh\":\n            half_dist_mesh,\n            \"rotation\": [0, 0, SQ2, SQ2],\n            \"translation\": [1 + SEP * loc[0], SEP * loc[2], -SEP * loc[1]],\n        })\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:bottom:-J\",\n            \"mesh\":\n            half_dist_mesh,\n            \"rotation\": [0.5, 0.5, 0.5, 0.5],\n            \"translation\": [1 + SEP * loc[0], SEP * loc[2], -SEP * loc[1]],\n        })\n        shapes.append({\n            \"name\":\n            f\"spider{loc}:bottom:+J\",\n            \"mesh\":\n            half_dist_mesh,\n            \"rotation\": [0.5, 0.5, 0.5, 0.5],\n            \"translation\": [\n                1 + SEP * loc[0],\n                SEP * loc[2],\n                -SEP * loc[1] - 1,\n            ],\n        })\n\n    shapes = [shp for shp in shapes if rm_dir not in shp[\"name\"]]\n    return shapes\n\n\ndef gltf_generator(lasre: Mapping[str, Any],\n                   stabilizer: int = -1,\n                   tube_len: float = 2.0,\n                   no_color_z: bool = False,\n                   attach_axes: bool = False,\n                   rm_dir: Optional[str] = None) -> Mapping[str, Any]:\n    \"\"\"generate gltf in a dict and write to a json file with extension .gltf\n\n    Args:\n        lasre (Mapping[str, Any]): LaSRe of the LaS.\n        stabilizer (int, optional): index of the stabilizer. The correlation\n            surfaces corresponding to it will be drawn. Defaults to -1, which\n            means do not draw any correlation surfaces.\n        tube_len (float, optional): ratio of the length of the pipes compared\n            to the length of the cubes. Defaults to 2.0.\n        no_color_z (bool, optional): do not color the Z-pipes. Defaults to\n            False, which means by default Z-pipes are colored.\n        attach_axes (bool, optional): attach an IJK axes. Defaults to False.\n        rm_dir (str, optional): the direction of faces to remove to reveal\n            the correlation surfaces. Defaults to None.\n\n    Raises:\n        ValueError: rm_dir is not any one of :(+|-)(I|J|K)\n        ValueError: the index of stabilizer is not -1 nor in [0, n_stabilizer)\n\n    Returns:\n        Mapping[str, Any]: the constructed gltf in a dict.\n    \"\"\"\n    s, tubelen, noColor = (\n        stabilizer,\n        tube_len,\n        no_color_z,\n    )\n    if rm_dir is None:\n        rm_dir = \":II\"\n    elif rm_dir not in [\":+I\", \":-I\", \":+J\", \":-J\", \":+K\", \":-K\"]:\n        raise ValueError(\"rm_dir is not one of :+I, :-I, :+J, :-J, :+K, :-K\")\n\n    gltf = base_gen(tubelen)\n\n    i_bound = lasre[\"n_i\"]\n    j_bound = lasre[\"n_j\"]\n    k_bound = lasre[\"n_k\"]\n    NodeY = lasre[\"NodeY\"]\n    ExistI = lasre[\"ExistI\"]\n    ColorI = lasre[\"ColorI\"]\n    ExistJ = lasre[\"ExistJ\"]\n    ColorJ = lasre[\"ColorJ\"]\n    ExistK = lasre[\"ExistK\"]\n    s_bound = None\n    if \"CorrIJ\" in lasre:\n        CorrIJ = lasre[\"CorrIJ\"]\n        CorrIK = lasre[\"CorrIK\"]\n        CorrJI = lasre[\"CorrJI\"]\n        CorrJK = lasre[\"CorrJK\"]\n        CorrKI = lasre[\"CorrKI\"]\n        CorrKJ = lasre[\"CorrKJ\"]\n        s_bound = len(CorrIJ)\n    if \"ColorKP\" not in lasre:\n        ColorKP = [[[-1 for _ in range(k_bound)] for _ in range(j_bound)]\n                   for _ in range(i_bound)]\n    else:\n        ColorKP = lasre[\"ColorKP\"]\n    if \"ColorKM\" not in lasre:\n        ColorKM = [[[-1 for _ in range(k_bound)] for _ in range(j_bound)]\n                   for _ in range(i_bound)]\n    else:\n        ColorKM = lasre[\"ColorKM\"]\n    port_cubes = lasre[\"port_cubes\"]\n    t_injections = (lasre[\"optional\"][\"t_injections\"]\n                    if \"t_injections\" in lasre[\"optional\"] else [])\n\n    if s < -1 or (s_bound is not None and s_bound > 0 and s not in range(-1, s_bound)):\n        raise ValueError(f\"No such stabilizer index {s}.\")\n\n    for i in range(i_bound):\n        for j in range(j_bound):\n            for k in range(k_bound):\n                if ExistI[i][j][k]:\n                    gltf[\"nodes\"] += tube_gen(\n                        tubelen + 1.0,\n                        (i, j, k),\n                        \"I\",\n                        ColorI[i][j][k],\n                        s,\n                        (CorrIJ[s][i][j][k],\n                         CorrIK[s][i][j][k]) if s_bound else (0, 0),\n                        noColor,\n                        rm_dir,\n                    )\n                if ExistJ[i][j][k]:\n                    gltf[\"nodes\"] += tube_gen(\n                        tubelen + 1.0,\n                        (i, j, k),\n                        \"J\",\n                        ColorJ[i][j][k],\n                        s,\n                        (CorrJK[s][i][j][k],\n                         CorrJI[s][i][j][k]) if s_bound else (0, 0),\n                        noColor,\n                        rm_dir,\n                    )\n                if ExistK[i][j][k]:\n                    gltf[\"nodes\"] += tube_gen(\n                        tubelen + 1.0,\n                        (i, j, k),\n                        \"K\",\n                        7 * ColorKM[i][j][k] + ColorKP[i][j][k],\n                        s,\n                        (CorrKI[s][i][j][k],\n                         CorrKJ[s][i][j][k]) if s_bound else (0, 0),\n                        noColor,\n                        rm_dir,\n                    )\n\n    for i in range(i_bound):\n        for j in range(j_bound):\n            for k in range(k_bound):\n                exists = {\"-I\": 0, \"+I\": 0, \"-K\": 0, \"+K\": 0, \"-J\": 0, \"+J\": 0}\n                colors = {}\n                corr = {\n                    \"-I\": (0, 0),\n                    \"+I\": (0, 0),\n                    \"-J\": (0, 0),\n                    \"+J\": (0, 0),\n                    \"-K\": (0, 0),\n                    \"+K\": (0, 0),\n                }\n                if i > 0 and ExistI[i - 1][j][k]:\n                    exists[\"-I\"] = 1\n                    colors[\"-I\"] = ColorI[i - 1][j][k]\n                    corr[\"-I\"] = (CorrIJ[s][i - 1][j][k],\n                                  CorrIK[s][i - 1][j][k]) if s_bound else (0,\n                                                                           0)\n                if ExistI[i][j][k]:\n                    exists[\"+I\"] = 1\n                    colors[\"+I\"] = ColorI[i][j][k]\n                    corr[\"+I\"] = (CorrIJ[s][i][j][k],\n                                  CorrIK[s][i][j][k]) if s_bound else (0, 0)\n                if j > 0 and ExistJ[i][j - 1][k]:\n                    exists[\"-J\"] = 1\n                    colors[\"-J\"] = ColorJ[i][j - 1][k]\n                    corr[\"-J\"] = (CorrJK[s][i][j - 1][k],\n                                  CorrJI[s][i][j - 1][k]) if s_bound else (0,\n                                                                           0)\n                if ExistJ[i][j][k]:\n                    exists[\"+J\"] = 1\n                    colors[\"+J\"] = ColorJ[i][j][k]\n                    corr[\"+J\"] = (CorrJK[s][i][j][k],\n                                  CorrJI[s][i][j][k]) if s_bound else (0, 0)\n                if k > 0 and ExistK[i][j][k - 1]:\n                    exists[\"-K\"] = 1\n                    colors[\"-K\"] = ColorKP[i][j][k - 1]\n                    corr[\"-K\"] = (CorrKI[s][i][j][k - 1],\n                                  CorrKJ[s][i][j][k - 1]) if s_bound else (0,\n                                                                           0)\n                if ExistK[i][j][k]:\n                    exists[\"+K\"] = 1\n                    colors[\"+K\"] = ColorKM[i][j][k]\n                    corr[\"+K\"] = (CorrKI[s][i][j][k],\n                                  CorrKJ[s][i][j][k]) if s_bound else (0, 0)\n                if sum([v for (k, v) in exists.items()]) > 0:\n                    if (i, j, k) not in port_cubes:\n                        if NodeY[i][j][k]:\n                            gltf[\"nodes\"] += special_gen(\n                                tubelen + 1.0,\n                                (i, j, k),\n                                exists,\n                                \"Y\",\n                                s,\n                                rm_dir,\n                            )\n                        else:\n                            gltf[\"nodes\"] += cube_gen(\n                                tubelen + 1.0,\n                                (i, j, k),\n                                exists,\n                                colors,\n                                s,\n                                corr,\n                                noColor,\n                                rm_dir,\n                            )\n                    elif [i, j, k] in t_injections:\n                        gltf[\"nodes\"] += special_gen(\n                            tubelen + 1.0,\n                            (i, j, k),\n                            exists,\n                            \"T\",\n                            s,\n                            rm_dir,\n                        )\n\n    if attach_axes:\n        gltf[\"nodes\"] += axes_gen(tube_len + 1.0, i_bound, j_bound, k_bound)\n\n    gltf[\"nodes\"][0][\"children\"] = list(range(1, len(gltf[\"nodes\"])))\n\n    return gltf\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/translators/networkx_generator.py",
    "content": "\"\"\"generate a annotated networkx.Graph corresponding to the LaS.\"\"\"\n\nimport networkx\nfrom lassynth.translators import ZXGridGraph\nimport stimzx\nfrom typing import Mapping, Any\n\n\ndef networkx_generator(lasre: Mapping[str, Any]) -> networkx.Graph:\n    n_i, n_j, n_k = lasre[\"n_i\"], lasre[\"n_j\"], lasre[\"n_k\"]\n    port_cubes = lasre[\"port_cubes\"]\n    zxgridgraph = ZXGridGraph(lasre)\n    edges = zxgridgraph.edges\n    nodes = zxgridgraph.nodes\n\n    zx_nx_graph = networkx.Graph()\n    type_to_str = {\"X\": \"X\", \"Z\": \"Z\", \"Pi\": \"in\", \"Po\": \"out\", \"I\": \"X\"}\n    cnt = 0\n    for (i, j, k) in port_cubes:\n        node = nodes[i][j][k]\n        zx_nx_graph.add_node(cnt, value=stimzx.ZxType(type_to_str[node.type]))\n        node.node_id = cnt\n        cnt += 1\n\n    for i in range(n_i + 1):\n        for j in range(n_j + 1):\n            for k in range(n_k + 1):\n                node = nodes[i][j][k]\n                if node.type not in [\"N\", \"Po\", \"Pi\"]:\n                    zx_nx_graph.add_node(cnt,\n                                         value=stimzx.ZxType(\n                                             type_to_str[node.type]))\n                    node.node_id = cnt\n                    cnt += 1\n                if node.y_tail_minus:\n                    zx_nx_graph.add_node(cnt, value=stimzx.ZxType(\"Z\", 1))\n                    zx_nx_graph.add_edge(node.node_id, cnt)\n                    cnt += 1\n                if node.y_tail_plus:\n                    zx_nx_graph.add_node(cnt, value=stimzx.ZxType(\"Z\", 3))\n                    zx_nx_graph.add_edge(node.node_id, cnt)\n                    cnt += 1\n\n    for edge in edges:\n        if edge.type != \"h\":\n            zx_nx_graph.add_edge(edge.node0.node_id, edge.node1.node_id)\n        else:\n            zx_nx_graph.add_node(cnt, value=stimzx.ZxType(\"H\"))\n            zx_nx_graph.add_edge(cnt, edge.node0.node_id)\n            zx_nx_graph.add_edge(cnt, edge.node1.node_id)\n            cnt += 1\n\n    return zx_nx_graph\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/translators/textfig_generator.py",
    "content": "\"\"\"Generate text figures of 2D time slices of the LaS.\"\"\"\n\nfrom lassynth.translators import ZXGridGraph\n\n\nclass TextLayer:\n    pad_i = 1\n    pad_j = 1\n    sep_i = 4\n    sep_j = 4\n\n    def __init__(self, zx_graph: ZXGridGraph, k: int, if_middle: bool) -> None:\n        self.n_i, self.n_j, self.n_k = (\n            zx_graph.n_i,\n            zx_graph.n_j,\n            zx_graph.n_k,\n        )\n        self.chars = [[\n            \" \" for _ in range(2 * TextLayer.pad_i +\n                               (self.n_i - 1) * TextLayer.sep_i + 1)\n        ] + [\"\\n\"] for _ in range(2 * TextLayer.pad_j +\n                                  (self.n_j - 1) * TextLayer.sep_j + 1)]\n        if if_middle:\n            self.compute_middle(zx_graph, k)\n        else:\n            self.compute_normal(zx_graph, k)\n\n    def set_char(self, j: int, i: int, character):\n        self.chars[j][i] = character\n\n    def compute_normal(self, zx_graph: ZXGridGraph, k: int):\n        \"\"\"a normal layer corresponds to a layer of cubes in LaS, e.g., \n             /   /\n            X   X \n            |  /  \n            |     \n            |/    \n            Z   . \n           /      \n        There are 2x2 tiles of surface codes. The bottom right one is not being\n        used, represented by a `.`; the top right one is identity in because\n        it has degree 2, but our convention is that these spiders have type `X`\n        The top left one is like that, too. The bottom left is a Z-spider with\n        three edges, which is non trivial. `-` and `|` I-pipes and J-pipes.\n        `/` are K-pipes. The `/` on the bottom left corner of a spider connects\n        to the previous moment. The `/` on the top right corner of a spider\n        connects to the next moment.\n\n        Args:\n            zx_graph (ZXGridGraph):\n            k (int): the height of this layer.\n        \"\"\"\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                spider = zx_graph.nodes[i][j][k]\n\n                if spider.type in [\"N\", \"Pi\", \"Po\"]:\n                    self.set_char(\n                        TextLayer.pad_j + j * TextLayer.sep_j,\n                        TextLayer.pad_i + i * TextLayer.sep_i,\n                        \".\",\n                    )\n                    continue\n                elif spider.type == \"I\":\n                    self.set_char(\n                        TextLayer.pad_j + j * TextLayer.sep_j,\n                        TextLayer.pad_i + i * TextLayer.sep_i,\n                        \"X\",\n                    )\n                else:\n                    self.set_char(\n                        TextLayer.pad_j + j * TextLayer.sep_j,\n                        TextLayer.pad_i + i * TextLayer.sep_i,\n                        spider.type,\n                    )\n\n                # I pipes\n                if spider.exists[\"+I\"]:\n                    for offset in range(1, TextLayer.sep_i):\n                        self.set_char(\n                            TextLayer.pad_j + j * TextLayer.sep_j,\n                            TextLayer.pad_i + i * TextLayer.sep_i + offset,\n                            \"-\",\n                        )\n\n                # J pipes\n                if spider.exists[\"+J\"]:\n                    for offset in range(1, TextLayer.sep_i):\n                        self.set_char(\n                            TextLayer.pad_j + j * TextLayer.sep_j + offset,\n                            TextLayer.pad_i + i * TextLayer.sep_i,\n                            \"|\",\n                        )\n\n                # K pipes\n                if spider.exists[\"+K\"]:\n                    self.set_char(\n                        TextLayer.pad_j + j * TextLayer.sep_j - 1,\n                        TextLayer.pad_i + i * TextLayer.sep_i + 1,\n                        \"/\",\n                    )\n                if spider.exists[\"-K\"]:\n                    self.set_char(\n                        TextLayer.pad_j + j * TextLayer.sep_j + 1,\n                        TextLayer.pad_i + i * TextLayer.sep_i - 1,\n                        \"/\",\n                    )\n\n    def compute_middle(self, zx_graph: ZXGridGraph, k: int):\n        \"\"\"a middle layer is either a Hadmard edge or a normal edge, e.g.,\n                 /\n            .   X \n               /  \n                \n             /    \n            H   . \n           /      \n        These layers cannot have `-` or `|`. It only has `/` which are K-pipes.\n        The node is either `H` meaning the edge is a Hadamard edge, or `X`\n        meaning the edge is a normal edge. We use `X` for identity here.\n\n        Args:\n            zx_graph (ZXGridGraph): \n            k (int): the height of this layer. There is a middle layer after a \n                normal layer.\n        \"\"\"\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                self.set_char(\n                    TextLayer.pad_j + j * TextLayer.sep_j,\n                    TextLayer.pad_i + i * TextLayer.sep_i,\n                    \".\",\n                )\n                spider = zx_graph.nodes[i][j][k]\n                color_sum = -1\n                if k == self.n_k - 1:\n                    try:\n                        for port in zx_graph.lasre[\"ports\"]:\n                            if (port[\"i\"], port[\"j\"], port[\"k\"]) == (i, j, k):\n                                color_sum = port[\"c\"] + spider.colors[\"+K\"]\n                                break\n                    except ValueError:\n                        print(\n                            f\"KPipe({i},{j},{k}) connect outside but not port.\"\n                        )\n                else:\n                    upper_spider = zx_graph.nodes[i][j][k + 1]\n                    if spider.exists[\"+K\"] == 1 and upper_spider.exists[\n                            \"-K\"] == 1:\n                        color_sum = spider.colors[\"+K\"] + upper_spider.colors[\n                            \"-K\"]\n                    if spider.exists[\"+K\"] == 0 and upper_spider.exists[\n                            \"-K\"] == 1:\n                        try:\n                            for port in zx_graph.lasre[\"ports\"]:\n                                if (port[\"i\"], port[\"j\"], port[\"k\"]) == (i, j,\n                                                                         k):\n                                    color_sum = port[\n                                        \"c\"] + upper_spider.colors[\"-K\"]\n                                    break\n                        except ValueError:\n                            print(f\"KPipe({i},{j},{k})- should be a port.\")\n                    if spider.exists[\"+K\"] == 1 and upper_spider.exists[\n                            \"-K\"] == 0:\n                        try:\n                            for port in zx_graph.lasre[\"ports\"]:\n                                if (port[\"i\"], port[\"j\"],\n                                        port[\"k\"]) == (i, j, k + 1):\n                                    color_sum = port[\"c\"] + spider.colors[\"+K\"]\n                                    break\n                        except ValueError:\n                            print(f\"KPipe({i},{j},{k + 1})- should be a port\")\n\n                if color_sum != -1:\n                    self.set_char(\n                        TextLayer.pad_j + j * TextLayer.sep_j - 1,\n                        TextLayer.pad_i + i * TextLayer.sep_i + 1,\n                        \"/\",\n                    )\n                    self.set_char(\n                        TextLayer.pad_j + j * TextLayer.sep_j + 1,\n                        TextLayer.pad_i + i * TextLayer.sep_i - 1,\n                        \"/\",\n                    )\n                    if color_sum == 1:\n                        self.set_char(\n                            TextLayer.pad_j + j * TextLayer.sep_j,\n                            TextLayer.pad_i + i * TextLayer.sep_i,\n                            \"H\",\n                        )\n                    else:\n                        self.set_char(\n                            TextLayer.pad_j + j * TextLayer.sep_j,\n                            TextLayer.pad_i + i * TextLayer.sep_i,\n                            \"X\",\n                        )\n\n    def get_text(self):\n        text = \"\"\n        for j in range(2 * TextLayer.pad_j + (self.n_j - 1) * TextLayer.sep_j +\n                       1):\n            for i in range(2 * TextLayer.pad_i +\n                           (self.n_i - 1) * TextLayer.sep_i + 1):\n                text += self.chars[j][i]\n            text += \"\\n\"\n        return text\n\n\ndef textfig_generator(lasre: dict):\n    text = \"======================================\\n\"\n    zx_graph = ZXGridGraph(lasre)\n    for k in range(lasre[\"n_k\"] - 1, -1, -1):\n        text += TextLayer(zx_graph, k, True).get_text()\n        text += \"======================================\\n\"\n        text += TextLayer(zx_graph, k, False).get_text()\n        text += \"======================================\\n\"\n    return text\n"
  },
  {
    "path": "glue/lattice_surgery/lassynth/translators/zx_grid_graph.py",
    "content": "\"\"\"Classes ZXGridEdge, ZXGridSpider, and ZXGridGraph. ZXGridGraph is a graph\nwhere nodes are the cubes in LaS and edges are pipes in LaS.\n\"\"\"\n\nfrom typing import Any, Mapping, Sequence, Tuple, Optional\n\n\nclass ZXGridNode:\n\n    def __init__(self, coord3: Tuple[int, int, int],\n                 connectivity: Mapping[str, Mapping[str, int]]) -> None:\n        \"\"\"initialize ZXGridNode for a cube in the LaS.\n\n        self.type: type of ZX spider, 'N': no spider, 'X'/'Z': X/Z-spider,\n            'S': Y cube, 'I': identity, 'Pi': input port, 'Po': output port. \n        self.i/j/k: 3D corrdinates of the cube in the LaS.\n        self.exists is a dictionary with six keys corresponding to whether a\n            pipe exist in the six directions to a cube in the LaS.\n        self.colors are the colors of these possible pipes.\n        self.y_tail_plus: if this node connects a Y on the top.\n        self.y_tail_minus: if this node connects a Y on the bottom.\n        \n        Args:\n            coord3 (Tuple[int, int, int]): 3D coordinate of the cube.\n            connectivity (Mapping[str, Mapping[str, int]]): contains exists\n                and colors of the six possible pipes to a cube\n        \"\"\"\n        self.i, self.j, self.k = coord3\n        self.y_tail_plus = False\n        self.y_tail_minus = False\n        self.node_id = -1\n        self.exists = connectivity[\"exists\"]\n        self.colors = connectivity[\"colors\"]\n        self.compute_type()\n\n    def compute_type(self) -> None:\n        \"\"\"decide the type of a ZXGridNoe\n        \n        Raises:\n            ValueError: node has degree=1, which should be forbidden earlier.\n            ValueError: node has degree>4, which should be forbidden earlier.\n        \"\"\"\n        deg = sum([v for (k, v) in self.exists.items()])\n        if deg == 0:\n            self.type = \"N\"\n            return\n        elif deg == 1:\n            raise ValueError(\"There should not be deg-1 Z or X spiders.\")\n        elif deg == 2:\n            self.type = \"I\"\n        elif deg >= 5:\n            raise ValueError(\"deg > 4: 3D corner exists\")\n        else:  # degree = 3 or 4\n            if self.exists[\"-I\"] == 0 and self.exists[\"+I\"] == 0:\n                if self.exists[\"-J\"]:\n                    if self.colors[\"-J\"] == 0:\n                        self.type = \"X\"\n                    else:\n                        self.type = \"Z\"\n                else:  # must exist +J\n                    if self.colors[\"+J\"] == 0:\n                        self.type = \"X\"\n                    else:\n                        self.type = \"Z\"\n\n            if self.exists[\"-J\"] == 0 and self.exists[\"+J\"] == 0:\n                if self.exists[\"-I\"]:\n                    if self.colors[\"-I\"] == 0:\n                        self.type = \"Z\"\n                    else:\n                        self.type = \"X\"\n                else:  # must exist +I\n                    if self.colors[\"+I\"] == 0:\n                        self.type = \"Z\"\n                    else:\n                        self.type = \"X\"\n\n            if self.exists[\"-K\"] == 0 and self.exists[\"+K\"] == 0:\n                if self.exists[\"-I\"]:\n                    if self.colors[\"-I\"] == 0:\n                        self.type = \"X\"\n                    else:\n                        self.type = \"Z\"\n                else:  # must exist +I\n                    if self.colors[\"+I\"] == 0:\n                        self.type = \"X\"\n                    else:\n                        self.type = \"Z\"\n\n    def zigxag_xy(self, n_j: int) -> Tuple[int, int]:\n        return (self.k * (n_j + 2) + self.j, -(n_j + 1) * self.i + self.j)\n\n    def zigxag_str(self, n_j: int) -> str:\n        zigxag_type = {\n            'Z': '@',\n            'X': 'O',\n            'S': 's',\n            'W': 'w',\n            'I': 'O',\n            'Pi': 'in',\n            'Po': 'out',\n        }\n        (x, y) = self.zigxag_xy(n_j)\n        return str(-y) + ',' + str(-x) + ',' + str(zigxag_type[self.type])\n\n\nclass ZXGridEdge:\n\n    def __init__(self, if_h: bool, node0: ZXGridNode,\n                 node1: ZXGridNode) -> None:\n        \"\"\"initialize ZXGridEdge for a pipe in the LaS.\n        \n        Args:\n            if_h (bool): if this edge is a Hadamard edge.\n            node0 (ZXGridNode): one end of the edge.\n            node1 (ZXGridNode): the other end of the edge.\n\n        Raises:\n            ValueError: the two spiders are the same.\n            ValueError: the two spiders are not neighbors.\n        \"\"\"\n\n        dist = abs(node0.i - node1.i) + abs(node0.j - node1.j) + abs(node0.k -\n                                                                     node1.k)\n        if dist == 0:\n            raise ValueError(f\"{node0} and {node1} are the same.\")\n        if dist > 1:\n            raise ValueError(f\"{node0} and {node1} are not neighbors.\")\n        self.node0, self.node1 = node0, node1\n        self.type = \"h\" if if_h else \"-\"\n\n    def zigxag_str(self, n_j: int) -> str:\n        (xa, ya) = self.node0.zigxag_xy(n_j)\n        (xb, yb) = self.node1.zigxag_xy(n_j)\n        return (str(-ya) + ',' + str(-xa) + ',' + str(-yb) + ',' + str(-xb) +\n                ',' + self.type)\n\n\nclass ZXGridGraph:\n\n    def __init__(self, lasre: Mapping[str, Any]) -> None:\n        self.lasre = lasre\n        self.n_i, self.n_j, self.n_k = (\n            lasre[\"n_i\"],\n            lasre[\"n_j\"],\n            lasre[\"n_k\"],\n        )\n        self.nodes = [[[\n            ZXGridNode((i, j, k), self.gather_cube_connectivity(i, j, k))\n            for k in range(self.n_k + 1)\n        ] for j in range(self.n_j + 1)] for i in range(self.n_i + 1)]\n        for (i, j, k) in self.lasre[\"port_cubes\"]:\n            self.nodes[i][j][k].type = 'Po'\n        self.append_y_tails()\n        self.edges = []\n        self.derive_edges()\n\n    def gather_cube_connectivity(self, i: int, j: int,\n                                 k: int) -> Mapping[str, Mapping[str, int]]:\n        # exists and colors for no cube\n        exists = {\"-I\": 0, \"+I\": 0, \"-K\": 0, \"+K\": 0, \"-J\": 0, \"+J\": 0}\n        colors = {\n            \"-I\": -1,\n            \"+I\": -1,\n            \"-K\": -1,\n            \"+K\": -1,\n            \"-J\": -1,\n            \"+J\": -1,\n        }\n        if i in range(self.n_i) and j in range(self.n_j) and k in range(\n                self.n_k) and ((i, j, k) not in self.lasre[\"port_cubes\"]) and (\n                    self.lasre[\"NodeY\"][i][j][k] == 0):\n            if i > 0 and self.lasre[\"ExistI\"][i - 1][j][k]:\n                exists[\"-I\"] = 1\n                colors[\"-I\"] = self.lasre[\"ColorI\"][i - 1][j][k]\n            if self.lasre[\"ExistI\"][i][j][k]:\n                exists[\"+I\"] = 1\n                colors[\"+I\"] = self.lasre[\"ColorI\"][i][j][k]\n            if j > 0 and self.lasre[\"ExistJ\"][i][j - 1][k]:\n                exists[\"-J\"] = 1\n                colors[\"-J\"] = self.lasre[\"ColorJ\"][i][j - 1][k]\n            if self.lasre[\"ExistJ\"][i][j][k]:\n                exists[\"+J\"] = 1\n                colors[\"+J\"] = self.lasre[\"ColorJ\"][i][j][k]\n            if k > 0 and self.lasre[\"ExistK\"][i][j][k - 1]:\n                exists[\"-K\"] = 1\n                colors[\"-K\"] = self.lasre[\"ColorKP\"][i][j][k - 1]\n            if self.lasre[\"ExistK\"][i][j][k]:\n                exists[\"+K\"] = 1\n                colors[\"+K\"] = self.lasre[\"ColorKM\"][i][j][k]\n        return {\"exists\": exists, \"colors\": colors}\n\n    def append_y_tails(self) -> None:\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                for k in range(self.n_k):\n                    if self.lasre[\"NodeY\"][i][j][k]:\n                        if (k - 1 >= 0 and self.lasre[\"ExistK\"][i][j][k - 1]\n                                and (not self.lasre[\"NodeY\"][i][j][k - 1])):\n                            self.nodes[i][j][k - 1].y_tail_plus = True\n                        if (k + 1 < self.n_k and self.lasre[\"ExistK\"][i][j][k]\n                                and (not self.lasre[\"NodeY\"][i][j][k + 1])):\n                            self.nodes[i][j][k + 1].y_tail_minus = True\n\n    def derive_edges(self):\n        valid_types = [\"Z\", \"X\", \"S\", \"I\", \"Pi\", \"Po\"]\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                for k in range(self.n_k):\n                    if (self.lasre[\"ExistI\"][i][j][k] == 1\n                            and self.nodes[i][j][k].type in valid_types\n                            and self.nodes[i + 1][j][k].type in valid_types):\n                        self.edges.append(\n                            ZXGridEdge(0, self.nodes[i][j][k],\n                                       self.nodes[i + 1][j][k]))\n\n                    if (self.lasre[\"ExistJ\"][i][j][k] == 1\n                            and self.nodes[i][j][k].type in valid_types\n                            and self.nodes[i][j + 1][k].type in valid_types):\n                        self.edges.append(\n                            ZXGridEdge(0, self.nodes[i][j][k],\n                                       self.nodes[i][j + 1][k]))\n\n                    if (self.lasre[\"ExistK\"][i][j][k] == 1\n                            and self.nodes[i][j][k].type in valid_types\n                            and self.nodes[i][j][k + 1].type in valid_types):\n                        self.edges.append(\n                            ZXGridEdge(\n                                abs(self.lasre[\"ColorKM\"][i][j][k] -\n                                    self.lasre[\"ColorKP\"][i][j][k]),\n                                self.nodes[i][j][k],\n                                self.nodes[i][j][k + 1],\n                            ))\n\n    def to_zigxag_url(self, io_spec: Optional[Sequence[str]] = None) -> str:\n        \"\"\"generate a url for ZigXag\n\n        Args:\n            io_spec (Sequence[str], optional): specify whether each port is an\n                input port or an output port. \n\n        Raises:\n            ValueError: len(io_spec) is not the same with the number of ports.\n\n        Returns:\n            str: zigxag url\n        \"\"\"\n        if io_spec is not None:\n            if len(io_spec) != len(self.lasre[\"port_cubes\"]):\n                raise ValueError(\n                    f\"io_spec has length {len(io_spec)} but there are \"\n                    f\"{len(self.lasre['port_cubes'])} ports.\")\n            for w, (i, j, k) in enumerate(self.lasre[\"port_cubes\"]):\n                self.nodes[i][j][k].type = io_spec[w]\n\n        valid_types = [\"Z\", \"X\", \"S\", \"W\", \"I\", \"Pi\", \"Po\"]\n        nodes_str = \"\"\n        first = True\n        for i in range(self.n_i + 1):\n            for j in range(self.n_j + 1):\n                for k in range(self.n_k + 1):\n                    if self.nodes[i][j][k].type in valid_types:\n                        if not first:\n                            nodes_str += \";\"\n                        nodes_str += self.nodes[i][j][k].zigxag_str(self.n_j)\n                        first = False\n\n        edges_str = \"\"\n        for i, edge in enumerate(self.edges):\n            if i > 0:\n                edges_str += \";\"\n            edges_str += edge.zigxag_str(self.n_j)\n\n        # add nodes and edges for Y cubes\n        for i in range(self.n_i):\n            for j in range(self.n_j):\n                for k in range(self.n_k):\n                    (x, y) = self.nodes[i][j][k].zigxag_xy(self.n_j)\n                    if self.nodes[i][j][k].y_tail_plus:\n                        nodes_str += (\";\" + str(x + self.n_j - j) + \",\" +\n                                      str(y) + \",s\")\n                        edges_str += (\";\" + str(x + self.n_j - j) + \",\" +\n                                      str(y) + \",\" + str(x) + \",\" + str(y) +\n                                      \",-\")\n                    if self.nodes[i][j][k].y_tail_minus:\n                        nodes_str += (\";\" + str(x - j - 1) + \",\" + str(y) +\n                                      \",s\")\n                        edges_str += (\";\" + str(x - j - 1) + \",\" + str(y) +\n                                      \",\" + str(x) + \",\" + str(y) + \",-\")\n\n        zigxag_str = \"https://algassert.com/zigxag#\" + nodes_str + \":\" + edges_str\n        return zigxag_str\n"
  },
  {
    "path": "glue/lattice_surgery/setup.py",
    "content": "from setuptools import find_packages, setup\n\nwith open('README.md', encoding='UTF-8') as f:\n    long_description = f.read()\n\n__version__ = '0.1.0'\n\nsetup(\n    name='LaSsynth',\n    version=__version__,\n    author='',\n    author_email='',\n    url='',\n    license='Apache 2',\n    packages=find_packages(),\n    description='Lattice Surgery Subroutine Synthesizer',\n    long_description=long_description,\n    long_description_content_type='text/markdown',\n    python_requires='>=3.6.0',\n    data_files=['README.md'],\n    install_requires=[\n        'z3-solver==4.12.1.0',\n        'stim',\n        'networkx',\n        'ipykernel',\n    ],\n    tests_require=['pytest', 'python3-distutils'],\n)\n"
  },
  {
    "path": "glue/lattice_surgery/stimzx/__init__.py",
    "content": "__version__ = '1.12.dev0'\nfrom ._external_stabilizer import (\n    ExternalStabilizer,\n)\n\nfrom ._text_diagram_parsing import (\n    text_diagram_to_networkx_graph,\n)\n\nfrom ._zx_graph_solver import (\n    zx_graph_to_external_stabilizers,\n    text_diagram_to_zx_graph,\n    ZxType,\n)\n"
  },
  {
    "path": "glue/lattice_surgery/stimzx/_external_stabilizer.py",
    "content": "from typing import List, Any\n\nimport stim\n\n\nclass ExternalStabilizer:\n    \"\"\"An input-to-output relationship enforced by a stabilizer circuit.\"\"\"\n\n    def __init__(self, *, input: stim.PauliString, output: stim.PauliString):\n        self.input = input\n        self.output = output\n\n    @staticmethod\n    def from_dual(dual: stim.PauliString, num_inputs: int) -> 'ExternalStabilizer':\n        sign = dual.sign\n\n        # Transpose input. Ys get negated.\n        for k in range(num_inputs):\n            if dual[k] == 2:\n                sign *= -1\n\n        return ExternalStabilizer(\n            input=dual[:num_inputs],\n            output=dual[num_inputs:],\n        )\n\n    @staticmethod\n    def canonicals_from_duals(duals: List[stim.PauliString], num_inputs: int) -> List['ExternalStabilizer']:\n        if not duals:\n            return []\n        duals = [e.copy() for e in duals]\n        num_qubits = len(duals[0])\n        num_outputs = num_qubits - num_inputs\n        id_out = stim.PauliString(num_outputs)\n\n        # Pivot on output qubits, to potentially isolate input-only stabilizers.\n        _eliminate_stabilizers(duals, range(num_inputs, num_qubits))\n\n        # Separate input-only stabilizers from the rest.\n        input_only_stabilizers = []\n        output_using_stabilizers = []\n        for dual in duals:\n            if dual[num_inputs:] == id_out:\n                input_only_stabilizers.append(dual)\n            else:\n                output_using_stabilizers.append(dual)\n\n        # Separately canonicalize the output-using and input-only stabilizers.\n        _eliminate_stabilizers(output_using_stabilizers, range(num_qubits))\n        _eliminate_stabilizers(input_only_stabilizers, range(num_inputs))\n\n        duals = input_only_stabilizers + output_using_stabilizers\n        return [ExternalStabilizer.from_dual(e, num_inputs) for e in duals]\n\n    def __mul__(self, other: 'ExternalStabilizer') -> 'ExternalStabilizer':\n        return ExternalStabilizer(input=other.input * self.input, output=self.output * other.output)\n\n    def __str__(self) -> str:\n        return str(self.input) + ' -> ' + str(self.output)\n\n    def __eq__(self, other: Any) -> bool:\n        if not isinstance(other, ExternalStabilizer):\n            return NotImplemented\n        return self.output == other.output and self.input == other.input\n\n    def __ne__(self, other: Any) -> bool:\n        return not self == other\n\n    def __repr__(self):\n        return f'stimzx.ExternalStabilizer(input={self.input!r}, output={self.output!r})'\n\n\ndef _eliminate_stabilizers(stabilizers: List[stim.PauliString], elimination_indices: range):\n    \"\"\"Performs partial Gaussian elimination on the list of stabilizers.\"\"\"\n    min_pivot = 0\n    for q in elimination_indices:\n        for b in [1, 3]:\n            for pivot in range(min_pivot, len(stabilizers)):\n                p = stabilizers[pivot][q]\n                if p == 2 or p == b:\n                    break\n            else:\n                continue\n            for k, stabilizer in enumerate(stabilizers):\n                p = stabilizer[q]\n                if k != pivot and (p == 2 or p == b):\n                    stabilizer *= stabilizers[pivot]\n            if min_pivot != pivot:\n                stabilizers[min_pivot], stabilizers[pivot] = stabilizers[pivot], stabilizers[min_pivot]\n            min_pivot += 1\n"
  },
  {
    "path": "glue/lattice_surgery/stimzx/_external_stabilizer_test.py",
    "content": "import stim\nimport stimzx\n\n\ndef test_repr():\n    e = stimzx.ExternalStabilizer(input=stim.PauliString(\"XX\"), output=stim.PauliString(\"Y\"))\n    assert eval(repr(e), {'stimzx': stimzx, 'stim': stim}) == e\n"
  },
  {
    "path": "glue/lattice_surgery/stimzx/_text_diagram_parsing.py",
    "content": "import re\nfrom typing import Dict, Tuple, TypeVar, List, Set, Callable\n\nimport networkx as nx\n\nK = TypeVar(\"K\")\n\n\ndef text_diagram_to_networkx_graph(text_diagram: str, *, value_func: Callable[[str], K] = str) -> nx.MultiGraph:\n    r\"\"\"Converts a text diagram into a networkx multi graph.\n\n    Args:\n        text_diagram: An ascii text diagram of the graph, linking nodes together with edges. Edges can be horizontal\n            (-), vertical (|), diagonal (/\\), crossing (+), or changing direction (*). Nodes can be alphanumeric with\n            parentheses. It is assumed that all text is shown with a fixed-width font.\n        value_func: An optional transformation to apply to the node text in order to get the node's value. Otherwise\n            the node's value is just its text.\n\n    Example:\n\n        >>> import stimzx\n        >>> import networkx as nx\n        >>> actual = stimzx.text_diagram_to_networkx_graph(r'''\n        ...\n        ...           A\n        ...           |\n        ...    NODE1--+--NODE2----------*\n        ...           |     |          /\n        ...           B     |         /\n        ...                 *------NODE4\n        ...\n        ... ''')\n        >>> expected = nx.MultiGraph()\n        >>> expected.add_node(0, value='A')\n        >>> expected.add_node(1, value='NODE1')\n        >>> expected.add_node(2, value='NODE2')\n        >>> expected.add_node(3, value='B')\n        >>> expected.add_node(4, value='NODE4')\n        >>> _ = expected.add_edge(0, 3)\n        >>> _ = expected.add_edge(1, 2)\n        >>> _ = expected.add_edge(2, 4)\n        >>> _ = expected.add_edge(2, 4)\n        >>> nx.testing.assert_graphs_equal(actual, expected)\n\n    Returns:\n        A networkx multi graph containing the graph from the text diagram. Nodes in the graph are integers (the ordering\n        of nodes is in the natural string ordering from left to right then top to bottom in the diagram), and have a\n        \"value\" attribute containing either the node's string from the diagram or else a function of that string if\n        value_func was specified.\n    \"\"\"\n    char_map = _text_to_char_map(text_diagram)\n    node_ids, nodes = _find_nodes(char_map, value_func)\n    edges = _find_all_edges(char_map, node_ids)\n    result = nx.MultiGraph()\n    for k, v in enumerate(nodes):\n        result.add_node(k, value=v)\n    for a, b in edges:\n        result.add_edge(a, b)\n    return result\n\n\ndef _text_to_char_map(text: str) -> Dict[complex, str]:\n    char_map = {}\n    x = 0\n    y = 0\n    for c in text:\n        if c == '\\n':\n            x = 0\n            y += 1\n            continue\n        if c != ' ':\n            char_map[x + 1j*y] = c\n        x += 1\n    return char_map\n\n\nDIR_TO_CHARS = {\n    -1 - 1j: '\\\\',\n    0 - 1j: '|+',\n    1 - 1j: '/',\n    -1: '-+',\n    1: '-+',\n    -1 + 1j: '/',\n    1j: '|+',\n    1 + 1j: '\\\\',\n}\n\nCHAR_TO_DIR = {\n    '\\\\': 1 + 1j,\n    '-': 1,\n    '|': 1j,\n    '/': -1 + 1j,\n}\n\n\ndef _find_all_edges(char_map: Dict[complex, str], terminal_map: Dict[complex, K]) -> List[Tuple[K, K]]:\n    edges = []\n    already_travelled = set()\n    for xy, c in char_map.items():\n        x = int(xy.real)\n        y = int(xy.imag)\n        if xy in terminal_map or xy in already_travelled or c in '*+':\n            continue\n        already_travelled.add(xy)\n        dxy = CHAR_TO_DIR.get(c)\n        if dxy is None:\n            raise ValueError(f\"Character {x+1} ('{c}') in line {y+1} isn't part in a node or an edge\")\n        n1 = _find_end_of_edge(xy + dxy, dxy, char_map, terminal_map, already_travelled)\n        n2 = _find_end_of_edge(xy - dxy, -dxy, char_map, terminal_map, already_travelled)\n        edges.append((n2, n1))\n    return edges\n\n\ndef _find_end_of_edge(xy: complex, dxy: complex, char_map: Dict[complex, str], terminal_map: Dict[complex, K], already_travelled: Set[complex]):\n    while True:\n        c = char_map[xy]\n        if xy in terminal_map:\n            return terminal_map[xy]\n\n        if c != '+':\n            if xy in already_travelled:\n                raise ValueError(\"Edge used twice.\")\n            already_travelled.add(xy)\n\n        next_deltas: List[complex] = []\n        if c == '*':\n            for dx2 in [-1, 0, 1]:\n                for dy2 in [-1, 0, 1]:\n                    dxy2 = dx2 + dy2 * 1j\n                    c2 = char_map.get(xy + dxy2)\n                    if dxy2 != 0 and dxy2 != -dxy and c2 is not None and c2 in DIR_TO_CHARS[dxy2]:\n                        next_deltas.append(dxy2)\n            if len(next_deltas) != 1:\n                raise ValueError(f\"Edge junction ('*') at character {int(xy.real)+1}$ in line {int(xy.imag)+1} doesn't have exactly 2 legs.\")\n            dxy, = next_deltas\n        else:\n            expected = DIR_TO_CHARS[dxy]\n            if c not in expected:\n                raise ValueError(f\"Dangling edge at character {int(xy.real)+1} in line {int(xy.imag)+1} travelling dx=${int(dxy.real)},dy={int(dxy.imag)}.\")\n        xy += dxy\n\n\ndef _find_nodes(char_map: Dict[complex, str], value_func: Callable[[str], K]) -> Tuple[Dict[complex, int], List[K]]:\n    node_ids = {}\n    nodes = []\n\n    node_chars = re.compile(\"^[a-zA-Z0-9()]$\")\n    next_node_id = 0\n\n    for xy, lead_char in char_map.items():\n        if xy in node_ids:\n            continue\n        if not node_chars.match(lead_char):\n            continue\n\n        n = 0\n        nested = 0\n        full_name = ''\n        while True:\n            c = char_map.get(xy + n, ' ')\n            if c == ' ' and nested > 0:\n                raise ValueError(\"Label ended before ')' to go with '(' was found.\")\n            if nested == 0 and not node_chars.match(c):\n                break\n            full_name += c\n            if c == '(':\n                nested += 1\n            elif c == ')':\n                nested -= 1\n            n += 1\n\n        nodes.append(value_func(full_name))\n        node_id = next_node_id\n        next_node_id += 1\n        for k in range(n):\n            node_ids[xy + k] = node_id\n\n    return node_ids, nodes\n"
  },
  {
    "path": "glue/lattice_surgery/stimzx/_text_diagram_parsing_test.py",
    "content": "import networkx as nx\nimport pytest\nfrom ._text_diagram_parsing import _find_nodes, _text_to_char_map, _find_end_of_edge, _find_all_edges, text_diagram_to_networkx_graph\n\n\ndef test_text_to_char_map():\n    assert _text_to_char_map(\"\"\"\nABC DEF\nG    \n HI\n    \"\"\") == {\n        0 + 1j: 'A',\n        1 + 1j: 'B',\n        2 + 1j: 'C',\n        4 + 1j: 'D',\n        5 + 1j: 'E',\n        6 + 1j: 'F',\n        0 + 2j: 'G',\n        1 + 3j: 'H',\n        2 + 3j: 'I',\n    }\n\n\ndef test_find_nodes():\n    assert _find_nodes(_text_to_char_map(''), lambda e: e) == ({}, [])\n    with pytest.raises(ValueError, match=\"base 10\"):\n        _find_nodes(_text_to_char_map('NOTANINT'), int)\n    with pytest.raises(ValueError, match=r\"ended before '\\)'\"):\n        _find_nodes(_text_to_char_map('X(run_off'), str)\n    assert _find_nodes(_text_to_char_map('X'), str) == (\n        {\n            0j: 0,\n        },\n        ['X'],\n    )\n    assert _find_nodes(_text_to_char_map('\\n   X'), str) == (\n        {\n            3 + 1j: 0,\n        },\n        ['X'],\n    )\n    assert _find_nodes(_text_to_char_map('X(pi)'), str) == (\n        {\n            0: 0,\n            1: 0,\n            2: 0,\n            3: 0,\n            4: 0,\n        },\n        ['X(pi)'],\n    )\n    assert _find_nodes(_text_to_char_map('X--Z'), str) == (\n        {\n            0: 0,\n            3: 1,\n        },\n        ['X', 'Z'],\n    )\n    assert _find_nodes(_text_to_char_map(\"\"\"\nX--*\n  /\n Z\n\"\"\"), str) == (\n        {\n            1j: 0,\n            1 + 3j: 1,\n        },\n        ['X', 'Z'],\n    )\n    assert _find_nodes(_text_to_char_map(\"\"\"\nX(pi)--Z\n\"\"\"), str) == (\n        {\n            0 + 1j: 0,\n            1 + 1j: 0,\n            2 + 1j: 0,\n            3 + 1j: 0,\n            4 + 1j: 0,\n            7 + 1j: 1,\n        },\n        [\"X(pi)\", \"Z\"],\n    )\n\n\ndef test_find_end_of_edge():\n    c = _text_to_char_map(r\"\"\"\n1--------*\n          \\    2      |\n     5     \\      *--++-*\n            *-----+-* |/\n                  | | /\n                  2 |/\n                    *\n    \"\"\")\n    terminal = {1: 'ONE', 18 + 6j: 'TWO'}\n    seen = set()\n    assert _find_end_of_edge(1 + 1j, 1, c, terminal, seen) == 'TWO'\n    assert len(seen) == 31\n\n\ndef test_find_all_edges():\n    c = _text_to_char_map(r\"\"\"\nX---Z      H----X(pi/2)\n          /\n       Z(pi/2)\n    \"\"\")\n    node_ids, _ = _find_nodes(c, str)\n    assert _find_all_edges(c, node_ids) == [\n        (0, 1),\n        (2, 3),\n        (2, 4),\n    ]\n\n\ndef test_from_text_diagram():\n    actual = text_diagram_to_networkx_graph(\"\"\"\nin---Z---H---------out\n     |\nin---X---Z(-pi/2)---out\n    \"\"\")\n    expected = nx.MultiGraph()\n    expected.add_node(0, value='in'),\n    expected.add_node(1, value='Z'),\n    expected.add_node(2, value='H'),\n    expected.add_node(3, value='out'),\n    expected.add_node(4, value='in'),\n    expected.add_node(5, value='X'),\n    expected.add_node(6, value='Z(-pi/2)'),\n    expected.add_node(7, value='out'),\n    expected.add_edge(0, 1)\n    expected.add_edge(1, 2)\n    expected.add_edge(2, 3)\n    expected.add_edge(1, 5)\n    expected.add_edge(4, 5)\n    expected.add_edge(5, 6)\n    expected.add_edge(6, 7)\n    nx.testing.assert_graphs_equal(actual, expected)\n\n    actual = text_diagram_to_networkx_graph(\"\"\"\n        Z-*\n        | |\n        X-*\n    \"\"\")\n    expected = nx.MultiGraph()\n    expected.add_node(0, value='Z')\n    expected.add_node(1, value='X')\n    expected.add_edge(0, 1)\n    expected.add_edge(0, 1)\n    nx.testing.assert_graphs_equal(actual, expected)\n"
  },
  {
    "path": "glue/lattice_surgery/stimzx/_zx_graph_solver.py",
    "content": "from typing import Dict, Tuple, List, Any, Union\nimport stim\nimport networkx as nx\n\nfrom ._text_diagram_parsing import text_diagram_to_networkx_graph\nfrom ._external_stabilizer import ExternalStabilizer\n\n\nclass ZxType:\n    \"\"\"Data describing a ZX node.\"\"\"\n\n    def __init__(self, kind: str, quarter_turns: int = 0):\n        self.kind = kind\n        self.quarter_turns = quarter_turns\n\n    def __eq__(self, other):\n        if not isinstance(other, ZxType):\n            return NotImplemented\n        return self.kind == other.kind and self.quarter_turns == other.quarter_turns\n\n    def __ne__(self, other):\n        return not self == other\n\n    def __hash__(self):\n        return hash((ZxType, self.kind, self.quarter_turns))\n\n    def __repr__(self):\n        return f'ZxType(kind={self.kind!r}, quarter_turns={self.quarter_turns!r})'\n\n\nZX_TYPES = {\n    \"X\": ZxType(\"X\"),\n    \"X(pi/2)\": ZxType(\"X\", 1),\n    \"X(pi)\": ZxType(\"X\", 2),\n    \"X(-pi/2)\": ZxType(\"X\", 3),\n    \"Z\": ZxType(\"Z\"),\n    \"Z(pi/2)\": ZxType(\"Z\", 1),\n    \"Z(pi)\": ZxType(\"Z\", 2),\n    \"Z(-pi/2)\": ZxType(\"Z\", 3),\n    \"H\": ZxType(\"H\"),\n    \"in\": ZxType(\"in\"),\n    \"out\": ZxType(\"out\"),\n}\n\n\ndef text_diagram_to_zx_graph(text_diagram: str) -> nx.MultiGraph:\n    \"\"\"Converts an ASCII text diagram into a ZX graph (represented as a networkx MultiGraph).\n\n    Supported node types:\n        \"X\": X spider with angle set to 0.\n        \"Z\": Z spider with angle set to 0.\n        \"X(pi/2)\": X spider with angle set to pi/2.\n        \"X(pi)\": X spider with angle set to pi.\n        \"X(-pi/2)\": X spider with angle set to -pi/2.\n        \"Z(pi/2)\": X spider with angle set to pi/2.\n        \"Z(pi)\": X spider with angle set to pi.\n        \"Z(-pi/2)\": X spider with angle set to -pi/2.\n        \"H\": Hadamard node. Must have degree 2.\n        \"in\": Input node. Must have degree 1.\n        \"out\": Output node. Must have degree 1.\n\n    Args:\n        text_diagram: A text diagram containing ZX nodes (e.g. \"X(pi)\") and edges (e.g. \"------\") connecting them.\n\n    Example:\n        >>> import stimzx\n        >>> import networkx\n        >>> actual: networkx.MultiGraph = stimzx.text_diagram_to_zx_graph(r'''\n        ...     in----X------out\n        ...           |\n        ...     in---Z(pi)---out\n        ... ''')\n        >>> expected = networkx.MultiGraph()\n        >>> expected.add_node(0, value=stimzx.ZxType(\"in\"))\n        >>> expected.add_node(1, value=stimzx.ZxType(\"X\"))\n        >>> expected.add_node(2, value=stimzx.ZxType(\"out\"))\n        >>> expected.add_node(3, value=stimzx.ZxType(\"in\"))\n        >>> expected.add_node(4, value=stimzx.ZxType(\"Z\", quarter_turns=2))\n        >>> expected.add_node(5, value=stimzx.ZxType(\"out\"))\n        >>> _ = expected.add_edge(0, 1)\n        >>> _ = expected.add_edge(1, 2)\n        >>> _ = expected.add_edge(1, 4)\n        >>> _ = expected.add_edge(3, 4)\n        >>> _ = expected.add_edge(4, 5)\n        >>> networkx.testing.assert_graphs_equal(actual, expected)\n\n    Returns:\n        A networkx MultiGraph containing the nodes and edges from the diagram. Nodes are numbered 0, 1, 2, etc in\n            reading ordering from the diagram, and have a \"value\" attribute of type `stimzx.ZxType`.\n    \"\"\"\n    return text_diagram_to_networkx_graph(text_diagram, value_func=ZX_TYPES.__getitem__)\n\n\ndef _reduced_zx_graph(graph: Union[nx.Graph, nx.MultiGraph]) -> nx.Graph:\n    \"\"\"Return an equivalent graph without self edges or repeated edges.\"\"\"\n    reduced_graph = nx.Graph()\n    odd_parity_edges = set()\n    for n1, n2 in graph.edges():\n        if n1 == n2:\n            continue\n        odd_parity_edges ^= {frozenset([n1, n2])}\n    for n, value in graph.nodes('value'):\n        reduced_graph.add_node(n, value=value)\n    for n1, n2 in odd_parity_edges:\n        reduced_graph.add_edge(n1, n2)\n    return reduced_graph\n\n\ndef zx_graph_to_external_stabilizers(graph: Union[nx.Graph, nx.MultiGraph]) -> List[ExternalStabilizer]:\n    \"\"\"Computes the external stabilizers of a ZX graph; generators of Paulis that leave it unchanged including sign.\n\n    Args:\n        graph: A non-contradictory connected ZX graph with nodes annotated by 'type' and optionally by 'angle'.\n            Allowed types are 'x', 'z', 'h', and 'out'.\n            Allowed angles are multiples of `math.pi/2`. Only 'x' and 'z' node types can have angles.\n            'out' nodes must have degree 1.\n            'h' nodes must have degree 2.\n\n    Returns:\n        A list of canonicalized external stabilizer generators for the graph.\n    \"\"\"\n\n    graph = _reduced_zx_graph(graph)\n    sim = stim.TableauSimulator()\n\n    # Interpret each edge as a cup producing an EPR pair.\n    # - The qubits of the EPR pair fly away from the center of the edge, towards their respective nodes.\n    # - The qubit keyed by (a, b) is the qubit heading towards b from the edge between a and b.\n    qubit_ids: Dict[Tuple[Any, Any], int] = {}\n    for n1, n2 in graph.edges:\n        qubit_ids[(n1, n2)] = len(qubit_ids)\n        qubit_ids[(n2, n1)] = len(qubit_ids)\n        sim.h(qubit_ids[(n1, n2)])\n        sim.cnot(qubit_ids[(n1, n2)], qubit_ids[(n2, n1)])\n\n    # Interpret each internal node as a family of post-selected parity measurements.\n    for n, node_type in graph.nodes('value'):\n        if node_type.kind in 'XZ':\n            # Surround X type node with Hadamards so it can be handled as if it were Z type.\n            if node_type.kind == 'X':\n                for neighbor in graph.neighbors(n):\n                    sim.h(qubit_ids[(neighbor, n)])\n        elif node_type.kind == 'H':\n            # Hadamard one input so the H node can be handled as if it were Z type.\n            neighbor, _ = graph.neighbors(n)\n            sim.h(qubit_ids[(neighbor, n)])\n        elif node_type.kind in ['out', 'in']:\n            continue  # Don't measure qubits leaving the system.\n        else:\n            raise ValueError(f\"Unknown node type {node_type!r}\")\n\n        # Handle Z type node.\n        # - Postselects the ZZ observable over each pair of incoming qubits.\n        # - Postselects the (S**quarter_turns X S**-quarter_turns)XX..X observable over all incoming qubits.\n        neighbors = [n2 for n2 in graph.neighbors(n) if n2 != n]\n        center = qubit_ids[(neighbors[0], n)]  # Pick one incoming qubit to be the common control for the others.\n        # Handle node angle using a phasing operation.\n        [id, sim.s, sim.z, sim.s_dag][node_type.quarter_turns](center)\n        # Use multi-target CNOT and Hadamard to transform postselected observables into single-qubit Z observables.\n        for n2 in neighbors[1:]:\n            sim.cnot(center, qubit_ids[(n2, n)])\n        sim.h(center)\n        # Postselect the observables.\n        for n2 in neighbors:\n            _pseudo_postselect(sim, qubit_ids[(n2, n)])\n\n    # Find output qubits.\n    in_nodes = sorted(n for n, value in graph.nodes('value') if value.kind == 'in')\n    out_nodes = sorted(n for n, value in graph.nodes('value') if value.kind == 'out')\n    ext_nodes = in_nodes + out_nodes\n    out_qubits = []\n    for out in ext_nodes:\n        (neighbor,) = graph.neighbors(out)\n        out_qubits.append(qubit_ids[(neighbor, out)])\n\n    # Remove qubits corresponding to non-external edges.\n    for i, q in enumerate(out_qubits):\n        sim.swap(q, len(qubit_ids) + i)\n    for i, q in enumerate(out_qubits):\n        sim.swap(i, len(qubit_ids) + i)\n    sim.set_num_qubits(len(out_qubits))\n\n    # Stabilizers of the simulator state are the external stabilizers of the graph.\n    dual_stabilizers = sim.canonical_stabilizers()\n    return ExternalStabilizer.canonicals_from_duals(dual_stabilizers, len(in_nodes))\n\n\ndef _pseudo_postselect(sim: stim.TableauSimulator, target: int):\n    \"\"\"Pretend to postselect by using classical feedback to consistently get into the measurement-was-false state.\"\"\"\n    measurement_result, kickback = sim.measure_kickback(target)\n    if kickback is not None:\n        for qubit, pauli in enumerate(kickback):\n            feedback_op = [None, sim.cnot, sim.cy, sim.cz][pauli]\n            if feedback_op is not None:\n                feedback_op(stim.target_rec(-1), qubit)\n    assert kickback is not None or not measurement_result, \"Impossible postselection. Graph contained a contradiction.\"\n"
  },
  {
    "path": "glue/lattice_surgery/stimzx/_zx_graph_solver_test.py",
    "content": "from typing import List\n\nimport stim\n\nfrom ._zx_graph_solver import zx_graph_to_external_stabilizers, text_diagram_to_zx_graph, ExternalStabilizer\n\n\ndef test_disconnected():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X    X---out\n    \"\"\")) == [\n        ExternalStabilizer(input=stim.PauliString(\"Z\"), output=stim.PauliString(\"_\")),\n        ExternalStabilizer(input=stim.PauliString(\"_\"), output=stim.PauliString(\"Z\")),\n    ]\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z---out\n             |\n             X\n    \"\"\")) == [\n        ExternalStabilizer(input=stim.PauliString(\"Z\"), output=stim.PauliString(\"_\")),\n        ExternalStabilizer(input=stim.PauliString(\"_\"), output=stim.PauliString(\"Z\")),\n    ]\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z---X---out\n             |   |\n             *---*\n    \"\"\")) == [\n        ExternalStabilizer(input=stim.PauliString(\"X\"), output=stim.PauliString(\"_\")),\n        ExternalStabilizer(input=stim.PauliString(\"_\"), output=stim.PauliString(\"Z\")),\n    ]\n\n\ndef test_cnot():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X---out\n             |\n        in---Z---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"CNOT 1 0\"))\n\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z---out\n             |\n        in---X---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"CNOT 0 1\"))\n\n\ndef test_cz():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z---out\n             |\n             H\n             |\n        in---Z---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"CZ 0 1\"))\n\n\ndef test_s():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z(pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"S 0\"))\n\n\ndef test_s_dag():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z(-pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"S_DAG 0\"))\n\n\ndef test_sqrt_x():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X(pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"SQRT_X 0\"))\n\n\ndef test_sqrt_x_sqrt_x():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X(pi/2)---X(pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"X 0\"))\n\n\ndef test_sqrt_z_sqrt_z():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z(pi/2)---Z(pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"Z 0\"))\n\n\ndef test_sqrt_x_dag():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X(-pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"SQRT_X_DAG 0\"))\n\n\ndef test_x():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X(pi)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"X 0\"))\n\n\ndef test_z():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z(pi)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"Z 0\"))\n\n\ndef test_id():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X---Z---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"I 0\"))\n\n\ndef test_s_state_distill():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(r\"\"\"\n                        *                  *---------------Z--------------------Z-------Z(pi/2)\n                       / \\                 |               |                    |\n                *-----*   *------------Z---+---------------+---Z----------------+-------Z(pi/2)\n                |                      |   |               |   |                |\n                X---X---Z(pi/2)        X---X---Z(pi/2)     X---X---Z(pi/2)      X---X---Z(pi/2)\n                |   |                  |                   |                    |   |\n                *---+------------------Z-------------------+--------------------+---Z---Z(pi/2)\n                    |                                      |                    |\n           in-------Z--------------------------------------Z-------------------Z(pi)--------out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"S 0\"))\n\n\ndef external_stabilizers_of_circuit(circuit: stim.Circuit) -> List[ExternalStabilizer]:\n    n = circuit.num_qubits\n    s = stim.TableauSimulator()\n    s.do(circuit)\n    t = s.current_inverse_tableau()**-1\n    stabilizers = []\n    for k in range(n):\n        p = [0] * n\n        p[k] = 1\n        stabilizers.append(stim.PauliString(p) + t.x_output(k))\n        p[k] = 3\n        stabilizers.append(stim.PauliString(p) + t.z_output(k))\n    return [ExternalStabilizer.from_dual(e, circuit.num_qubits) for e in stabilizers]\n"
  },
  {
    "path": "glue/python/README.md",
    "content": "# Stim\n\nStim is a fast simulator for quantum stabilizer circuits.\n\nAPI references are available on the stim github wiki: https://github.com/quantumlib/stim/wiki\n\nStim can be installed into a python 3 environment using pip:\n\n```bash\npip install stim\n```\n\nOnce stim is installed, you can `import stim` and use it.\nThere are three supported use cases:\n\n1. Interactive simulation with `stim.TableauSimulator`.\n2. High speed sampling with samplers compiled from `stim.Circuit`.\n3. Independent exploration using `stim.Tableau` and `stim.PauliString`.\n\n## Interactive Simulation\n\nUse `stim.TableauSimulator` to simulate operations one by one while inspecting the results:\n\n```python\nimport stim\n\ns = stim.TableauSimulator()\n\n# Create a GHZ state.\ns.h(0)\ns.cnot(0, 1)\ns.cnot(0, 2)\n\n# Look at the simulator state re-inverted to be forwards:\nt = s.current_inverse_tableau()\nprint(t**-1)\n# prints:\n# +-xz-xz-xz-\n# | ++ ++ ++\n# | ZX _Z _Z\n# | _X XZ __\n# | _X __ XZ\n\n# Measure the GHZ state.\nprint(s.measure_many(0, 1, 2))\n# prints one of:\n# [True, True, True]\n# or:\n# [False, False, False]\n```\n\n## High Speed Sampling\n\nBy creating a `stim.Circuit` and compiling it into a sampler, samples can be generated very quickly:\n\n```python\nimport stim\n\n# Create a circuit that measures a large GHZ state.\nc = stim.Circuit()\nc.append(\"H\", [0])\nfor k in range(1, 30):\n    c.append(\"CNOT\", [0, k])\nc.append(\"M\", range(30))\n\n# Compile the circuit into a high performance sampler.\nsampler = c.compile_sampler()\n\n# Collect a batch of samples.\n# Note: the ideal batch size, in terms of speed per sample, is roughly 1024.\n# Smaller batches are slower because they are not sufficiently vectorized.\n# Bigger batches are slower because they use more memory.\nbatch = sampler.sample(1024)\nprint(type(batch))  # numpy.ndarray\nprint(batch.dtype)  # numpy.uint8\nprint(batch.shape)  # (1024, 30)\nprint(batch)\n# Prints something like:\n# [[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]\n#  [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n#  [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]\n#  ...\n#  [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]\n#  [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]\n#  [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n#  [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]]\n```\n\nThis also works on circuits that include noise:\n\n```python\nimport stim\nimport numpy as np\n\nc = stim.Circuit(\"\"\"\n    X_ERROR(0.1) 0\n    Y_ERROR(0.2) 1\n    Z_ERROR(0.3) 2\n    DEPOLARIZE1(0.4) 3\n    DEPOLARIZE2(0.5) 4 5\n    M 0 1 2 3 4 5\n\"\"\")\nbatch = c.compile_sampler().sample(2**20)\nprint(np.mean(batch, axis=0).round(3))\n# Prints something like:\n# [0.1   0.2   0.    0.267 0.267 0.266]\n```\n\nYou can also sample annotated detection events using `stim.Circuit.compile_detector_sampler`.\n\nFor a list of gates that can appear in a `stim.Circuit`, see the [latest readme on github](https://github.com/quantumlib/Stim#readme).\n\n## Independent Exploration\n\nStim provides data types `stim.PauliString` and `stim.Tableau`, which support a variety of fast operations.\n\n```python\nimport stim\n\nxx = stim.PauliString(\"XX\")\nyy = stim.PauliString(\"YY\")\nassert xx * yy == -stim.PauliString(\"ZZ\")\n\ns = stim.Tableau.from_named_gate(\"S\")\nprint(repr(s))\n# prints:\n# stim.Tableau.from_conjugated_generators(\n#     xs=[\n#         stim.PauliString(\"+Y\"),\n#     ],\n#     zs=[\n#         stim.PauliString(\"+Z\"),\n#     ],\n# )\n\ns_dag = stim.Tableau.from_named_gate(\"S_DAG\")\nassert s**-1 == s_dag\nassert s**1000000003 == s_dag\n\ncnot = stim.Tableau.from_named_gate(\"CNOT\")\ncz = stim.Tableau.from_named_gate(\"CZ\")\nh = stim.Tableau.from_named_gate(\"H\")\nt = stim.Tableau(5)\nt.append(cnot, [1, 4])\nt.append(h, [4])\nt.append(cz, [1, 4])\nt.prepend(h, [4])\nassert t == stim.Tableau(5)\n```\n"
  },
  {
    "path": "glue/python/src/stim/__init__.py",
    "content": "\"\"\"Stim: a fast quantum stabilizer circuit library.\"\"\"\n\n# This is the entrypoint when running `import stim`.\n#\n# It does runtime detection of CPU features, and based on that imports the fastest pre-built C++ extension that only uses\n# compatible instructions. Importing a different one can result in runtime segfaults that crash the python interpreter.\n\nimport stim._detect_machine_architecture as _tmp\n\n\n_tmp = _tmp._UNSTABLE_detect_march()\ntry:\n    # NOTE: avx2 disabled until https://github.com/quantumlib/Stim/issues/432 is fixed\n    # if _tmp == 'avx2':\n    #     from stim._stim_avx2 import _UNSTABLE_raw_format_data, __version__\n    #     from stim._stim_avx2 import *\n    if _tmp == 'avx2' or _tmp == 'sse2':\n        from stim._stim_sse2 import _UNSTABLE_raw_format_data, __version__\n        from stim._stim_sse2 import *\n    else:\n        from stim._stim_polyfill import _UNSTABLE_raw_format_data, __version__\n        from stim._stim_polyfill import *\nexcept ModuleNotFoundError:\n    from stim._stim_polyfill import _UNSTABLE_raw_format_data, __version__\n    from stim._stim_polyfill import *\n\ndel _tmp\n\n\ndef _pytest_pycharm_pybind_repr_bug_workaround(cls):\n    f = cls.__repr__\n    cls.__repr__ = lambda e: f(e)\n    cls.__repr__.__doc__ = f.__doc__\n_pytest_pycharm_pybind_repr_bug_workaround(Circuit)\n_pytest_pycharm_pybind_repr_bug_workaround(CircuitErrorLocation)\n_pytest_pycharm_pybind_repr_bug_workaround(CircuitErrorLocationStackFrame)\n_pytest_pycharm_pybind_repr_bug_workaround(CircuitInstruction)\n_pytest_pycharm_pybind_repr_bug_workaround(CircuitRepeatBlock)\n_pytest_pycharm_pybind_repr_bug_workaround(CircuitTargetsInsideInstruction)\n_pytest_pycharm_pybind_repr_bug_workaround(CompiledDemSampler)\n_pytest_pycharm_pybind_repr_bug_workaround(CompiledDetectorSampler)\n_pytest_pycharm_pybind_repr_bug_workaround(CompiledMeasurementSampler)\n_pytest_pycharm_pybind_repr_bug_workaround(CompiledMeasurementsToDetectionEventsConverter)\n_pytest_pycharm_pybind_repr_bug_workaround(DemInstruction)\n_pytest_pycharm_pybind_repr_bug_workaround(DemRepeatBlock)\n_pytest_pycharm_pybind_repr_bug_workaround(DemTarget)\n_pytest_pycharm_pybind_repr_bug_workaround(DemTargetWithCoords)\n_pytest_pycharm_pybind_repr_bug_workaround(DetectorErrorModel)\n_pytest_pycharm_pybind_repr_bug_workaround(ExplainedError)\n_pytest_pycharm_pybind_repr_bug_workaround(FlipSimulator)\n_pytest_pycharm_pybind_repr_bug_workaround(FlippedMeasurement)\n_pytest_pycharm_pybind_repr_bug_workaround(Flow)\n_pytest_pycharm_pybind_repr_bug_workaround(GateData)\n_pytest_pycharm_pybind_repr_bug_workaround(GateTarget)\n_pytest_pycharm_pybind_repr_bug_workaround(GateTargetWithCoords)\n_pytest_pycharm_pybind_repr_bug_workaround(PauliString)\n_pytest_pycharm_pybind_repr_bug_workaround(PauliStringIterator)\n_pytest_pycharm_pybind_repr_bug_workaround(Tableau)\n_pytest_pycharm_pybind_repr_bug_workaround(TableauIterator)\n_pytest_pycharm_pybind_repr_bug_workaround(TableauSimulator)\ndel _pytest_pycharm_pybind_repr_bug_workaround\n"
  },
  {
    "path": "glue/python/src/stim/__init__.pyi",
    "content": "\"\"\"Stim (Development Version): a fast quantum stabilizer circuit library.\"\"\"\n# (This is a stubs file describing the classes and methods in stim.)\nfrom __future__ import annotations\nfrom typing import overload, TYPE_CHECKING, List, Dict, Tuple, Any, Union, Iterable, Optional, Sequence, Literal\nif TYPE_CHECKING:\n    import io\n    import pathlib\n    import numpy as np\n    import stim\nclass Circuit:\n    \"\"\"A mutable stabilizer circuit.\n\n    The stim.Circuit class is arguably the most important object in the\n    entire library. It is the interface through which you explain a\n    noisy quantum computation to Stim, in order to do fast bulk sampling\n    or fast error analysis.\n\n    For example, suppose you want to use a matching-based decoder on a\n    new quantum error correction construction. Stim can help you do this\n    but the very first step is to create a circuit implementing the\n    construction. Once you have the circuit you can then use methods like\n    stim.Circuit.detector_error_model() to create an object that can be\n    used to configure the decoder, or like\n    stim.Circuit.compile_detector_sampler() to produce problems for the\n    decoder to solve, or like stim.Circuit.shortest_graphlike_error() to\n    check for mistakes in the implementation of the code.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit()\n        >>> c.append(\"X\", 0)\n        >>> c.append(\"M\", 0)\n        >>> c.compile_sampler().sample(shots=1)\n        array([[ True]])\n\n        >>> stim.Circuit('''\n        ...    H 0\n        ...    CNOT 0 1\n        ...    M 0 1\n        ...    DETECTOR rec[-1] rec[-2]\n        ... ''').compile_detector_sampler().sample(shots=1)\n        array([[False]])\n    \"\"\"\n    def __add__(\n        self,\n        second: stim.Circuit,\n    ) -> stim.Circuit:\n        \"\"\"Creates a circuit by appending two circuits.\n\n        Examples:\n            >>> import stim\n            >>> c1 = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c2 = stim.Circuit('''\n            ...    M 0 1 2\n            ... ''')\n            >>> c1 + c2\n            stim.Circuit('''\n                X 0\n                Y 1 2\n                M 0 1 2\n            ''')\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.Circuit,\n    ) -> bool:\n        \"\"\"Determines if two circuits have identical contents.\n        \"\"\"\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: int,\n    ) -> Union[stim.CircuitInstruction, stim.CircuitRepeatBlock]:\n        pass\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: slice,\n    ) -> stim.Circuit:\n        pass\n    def __getitem__(\n        self,\n        index_or_slice: object,\n    ) -> object:\n        \"\"\"Returns copies of instructions from the circuit.\n\n        Args:\n            index_or_slice: An integer index picking out an instruction to return, or a\n                slice picking out a range of instructions to return as a circuit.\n\n        Returns:\n            If the index was an integer, then an instruction from the circuit.\n            If the index was a slice, then a circuit made up of the instructions in that\n            slice.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...    X 0\n            ...    X_ERROR(0.5) 2\n            ...    REPEAT 100 {\n            ...        X 0\n            ...        Y 1 2\n            ...    }\n            ...    TICK\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... ''')\n            >>> circuit[1]\n            stim.CircuitInstruction('X_ERROR', [stim.GateTarget(2)], [0.5])\n            >>> circuit[2]\n            stim.CircuitRepeatBlock(100, stim.Circuit('''\n                X 0\n                Y 1 2\n            '''))\n            >>> circuit[1::2]\n            stim.Circuit('''\n                X_ERROR(0.5) 2\n                TICK\n                DETECTOR rec[-1]\n            ''')\n        \"\"\"\n    def __iadd__(\n        self,\n        second: stim.Circuit,\n    ) -> stim.Circuit:\n        \"\"\"Appends a circuit into the receiving circuit (mutating it).\n\n        Examples:\n            >>> import stim\n            >>> c1 = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c2 = stim.Circuit('''\n            ...    M 0 1 2\n            ... ''')\n            >>> c1 += c2\n            >>> print(repr(c1))\n            stim.Circuit('''\n                X 0\n                Y 1 2\n                M 0 1 2\n            ''')\n        \"\"\"\n    def __imul__(\n        self,\n        repetitions: int,\n    ) -> stim.Circuit:\n        \"\"\"Mutates the circuit by putting its contents into a REPEAT block.\n\n        Special case: if the repetition count is 0, the circuit is cleared.\n        Special case: if the repetition count is 1, nothing happens.\n\n        Args:\n            repetitions: The number of times the REPEAT block should repeat.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c *= 3\n            >>> print(repr(c))\n            stim.Circuit('''\n                REPEAT 3 {\n                    X 0\n                    Y 1 2\n                }\n            ''')\n        \"\"\"\n    def __init__(\n        self,\n        stim_program_text: str = '',\n    ) -> None:\n        \"\"\"Creates a stim.Circuit.\n\n        Args:\n            stim_program_text: Defaults to empty. Describes operations to append into\n                the circuit.\n\n        Examples:\n            >>> import stim\n            >>> empty = stim.Circuit()\n            >>> not_empty = stim.Circuit('''\n            ...    X 0\n            ...    CNOT 0 1\n            ...    M 1\n            ... ''')\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of top-level instructions and blocks in the circuit.\n\n        Instructions inside of blocks are not included in this count.\n\n        Examples:\n            >>> import stim\n            >>> len(stim.Circuit())\n            0\n            >>> len(stim.Circuit('''\n            ...    X 0\n            ...    X_ERROR(0.5) 1 2\n            ...    TICK\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... '''))\n            5\n            >>> len(stim.Circuit('''\n            ...    REPEAT 100 {\n            ...        X 0\n            ...        Y 1 2\n            ...    }\n            ... '''))\n            1\n        \"\"\"\n    def __mul__(\n        self,\n        repetitions: int,\n    ) -> stim.Circuit:\n        \"\"\"Repeats the circuit using a REPEAT block.\n\n        Has special cases for 0 repetitions and 1 repetitions.\n\n        Args:\n            repetitions: The number of times the REPEAT block should repeat.\n\n        Returns:\n            repetitions=0: An empty circuit.\n            repetitions=1: A copy of this circuit.\n            repetitions>=2: A circuit with a single REPEAT block, where the contents of\n                that repeat block are this circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c * 3\n            stim.Circuit('''\n                REPEAT 3 {\n                    X 0\n                    Y 1 2\n                }\n            ''')\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.Circuit,\n    ) -> bool:\n        \"\"\"Determines if two circuits have non-identical contents.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.Circuit`.\n        \"\"\"\n    def __rmul__(\n        self,\n        repetitions: int,\n    ) -> stim.Circuit:\n        \"\"\"Repeats the circuit using a REPEAT block.\n\n        Has special cases for 0 repetitions and 1 repetitions.\n\n        Args:\n            repetitions: The number of times the REPEAT block should repeat.\n\n        Returns:\n            repetitions=0: An empty circuit.\n            repetitions=1: A copy of this circuit.\n            repetitions>=2: A circuit with a single REPEAT block, where the contents of\n                that repeat block are this circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> 3 * c\n            stim.Circuit('''\n                REPEAT 3 {\n                    X 0\n                    Y 1 2\n                }\n            ''')\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns stim instructions (that can be saved to a file and parsed by stim) for the current circuit.\n        \"\"\"\n    @overload\n    def append(\n        self,\n        name: str,\n        targets: Union[int, stim.GateTarget, stim.PauliString, Iterable[Union[int, stim.GateTarget, stim.PauliString]]],\n        arg: Union[float, Iterable[float], None] = None,\n        *,\n        tag: str = \"\",\n    ) -> None:\n        pass\n    @overload\n    def append(\n        self,\n        name: Union[stim.CircuitInstruction, stim.CircuitRepeatBlock, stim.Circuit],\n    ) -> None:\n        pass\n    def append(\n        self,\n        name: object,\n        targets: object = (),\n        arg: object = None,\n        *,\n        tag: str = '',\n    ) -> None:\n        \"\"\"Appends an operation into the circuit.\n\n        Note: `stim.Circuit.append_operation` is an alias of `stim.Circuit.append`.\n\n        Args:\n            name: The name of the operation's gate (e.g. \"H\" or \"M\" or \"CNOT\").\n\n                This argument can also be set to a `stim.CircuitInstruction` or\n                `stim.CircuitInstructionBlock`, which results in the instruction or\n                block being appended to the circuit. The other arguments (targets\n                and arg) can't be specified when doing so.\n\n                (The argument being called `name` is no longer quite right, but\n                is being kept for backwards compatibility.)\n            targets: The objects operated on by the gate. This can be either a\n                single target or an iterable of multiple targets.\n\n                Each target can be:\n                    An int: The index of a targeted qubit.\n                    A `stim.GateTarget`: Could be a variety of things. Methods like\n                        `stim.target_rec`, `stim.target_sweet`, `stim.target_x`, and\n                        `stim.CircuitInstruction.__getitem__` all return this type.\n                    A `stim.PauliString`: This will automatically be expanded into\n                        a product of pauli targets like `X1*Y2*Z3`.\n            arg: The \"parens arguments\" for the gate, such as the probability for a\n                noise operation. A double or list of doubles parameterizing the\n                gate. Different gates take different parens arguments. For example,\n                X_ERROR takes a probability, OBSERVABLE_INCLUDE takes an observable\n                index, and PAULI_CHANNEL_1 takes three disjoint probabilities.\n\n                Note: Defaults to no parens arguments. Except, for backwards\n                compatibility reasons, `cirq.append_operation` (but not\n                `cirq.append`) will default to a single 0.0 argument for gates that\n                take exactly one argument.\n            tag: A customizable string attached to the instruction.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit()\n            >>> c.append(\"X\", 0)\n            >>> c.append(\"H\", [0, 1])\n            >>> c.append(\"M\", [0, stim.target_inv(1)])\n            >>> c.append(\"CNOT\", [stim.target_rec(-1), 0])\n            >>> c.append(\"X_ERROR\", [0], 0.125)\n            >>> c.append(\"CORRELATED_ERROR\", [stim.target_x(0), stim.target_y(2)], 0.25)\n            >>> c.append(\"MPP\", [stim.PauliString(\"X1*Y2\"), stim.GateTarget(\"Z3\")])\n            >>> print(repr(c))\n            stim.Circuit('''\n                X 0\n                H 0 1\n                M 0 !1\n                CX rec[-1] 0\n                X_ERROR(0.125) 0\n                E(0.25) X0 Y2\n                MPP X1*Y2 Z3\n            ''')\n        \"\"\"\n    def append_from_stim_program_text(\n        self,\n        stim_program_text: str,\n    ) -> None:\n        \"\"\"Appends operations described by a STIM format program into the circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit()\n            >>> c.append_from_stim_program_text('''\n            ...    H 0  # comment\n            ...    CNOT 0 2\n            ...\n            ...    M 2\n            ...    CNOT rec[-1] 1\n            ... ''')\n            >>> print(c)\n            H 0\n            CX 0 2\n            M 2\n            CX rec[-1] 1\n\n        Args:\n            stim_program_text: The STIM program text containing the circuit operations\n                to append.\n        \"\"\"\n    def append_operation(\n        self,\n        name: object,\n        targets: object = (),\n        arg: object = None,\n        *,\n        tag: str = '',\n    ) -> None:\n        \"\"\"[DEPRECATED] use stim.Circuit.append instead\n        \"\"\"\n    def approx_equals(\n        self,\n        other: object,\n        *,\n        atol: float,\n    ) -> bool:\n        \"\"\"Checks if a circuit is approximately equal to another circuit.\n\n        Two circuits are approximately equal if they are equal up to slight\n        perturbations of instruction arguments such as probabilities. For example,\n        `X_ERROR(0.100) 0` is approximately equal to `X_ERROR(0.099)` within an absolute\n        tolerance of 0.002. All other details of the circuits (such as the ordering of\n        instructions and targets) must be exactly the same.\n\n        Args:\n            other: The circuit, or other object, to compare to this one.\n            atol: The absolute error tolerance. The maximum amount each probability may\n                have been perturbed by.\n\n        Returns:\n            True if the given object is a circuit approximately equal up to the\n            receiving circuit up to the given tolerance, otherwise False.\n\n        Examples:\n            >>> import stim\n            >>> base = stim.Circuit('''\n            ...    X_ERROR(0.099) 0 1 2\n            ...    M 0 1 2\n            ... ''')\n\n            >>> base.approx_equals(base, atol=0)\n            True\n\n            >>> base.approx_equals(stim.Circuit('''\n            ...    X_ERROR(0.101) 0 1 2\n            ...    M 0 1 2\n            ... '''), atol=0)\n            False\n\n            >>> base.approx_equals(stim.Circuit('''\n            ...    X_ERROR(0.101) 0 1 2\n            ...    M 0 1 2\n            ... '''), atol=0.0001)\n            False\n\n            >>> base.approx_equals(stim.Circuit('''\n            ...    X_ERROR(0.101) 0 1 2\n            ...    M 0 1 2\n            ... '''), atol=0.01)\n            True\n\n            >>> base.approx_equals(stim.Circuit('''\n            ...    DEPOLARIZE1(0.099) 0 1 2\n            ...    MRX 0 1 2\n            ... '''), atol=9999)\n            False\n        \"\"\"\n    def clear(\n        self,\n    ) -> None:\n        \"\"\"Clears the contents of the circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0\n            ...    Y 1 2\n            ... ''')\n            >>> c.clear()\n            >>> c\n            stim.Circuit()\n        \"\"\"\n    def compile_detector_sampler(\n        self,\n        *,\n        seed: object = None,\n    ) -> stim.CompiledDetectorSampler:\n        \"\"\"Returns an object that can batch sample detection events from the circuit.\n\n        Args:\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    H 0\n            ...    CNOT 0 1\n            ...    M 0 1\n            ...    DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> s = c.compile_detector_sampler()\n            >>> s.sample(shots=1)\n            array([[False]])\n        \"\"\"\n    def compile_m2d_converter(\n        self,\n        *,\n        skip_reference_sample: bool = False,\n    ) -> stim.CompiledMeasurementsToDetectionEventsConverter:\n        \"\"\"Creates a measurement-to-detection-event converter for the given circuit.\n\n        The converter can efficiently compute detection events and observable flips\n        from raw measurement data.\n\n        The converter uses a noiseless reference sample, collected from the circuit\n        using stim's Tableau simulator during initialization of the converter, as a\n        baseline for determining what the expected value of a detector is.\n\n        Note that the expected behavior of gauge detectors (detectors that are not\n        actually deterministic under noiseless execution) can vary depending on the\n        reference sample. Stim mitigates this by always generating the same reference\n        sample for a given circuit.\n\n        Args:\n            skip_reference_sample: Defaults to False. When set to True, the reference\n                sample used by the converter is initialized to all-zeroes instead of\n                being collected from the circuit. This should only be used if it's known\n                that the all-zeroes sample is actually a possible result from the\n                circuit (under noiseless execution).\n\n        Returns:\n            An initialized stim.CompiledMeasurementsToDetectionEventsConverter.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> converter = stim.Circuit('''\n            ...    X 0\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... ''').compile_m2d_converter()\n            >>> converter.convert(\n            ...     measurements=np.array([[0], [1]], dtype=np.bool_),\n            ...     append_observables=False,\n            ... )\n            array([[ True],\n                   [False]])\n        \"\"\"\n    def compile_sampler(\n        self,\n        *,\n        skip_reference_sample: bool = False,\n        seed: Optional[int] = None,\n        reference_sample: Optional[np.ndarray] = None,\n    ) -> stim.CompiledMeasurementSampler:\n        \"\"\"Returns an object that can quickly batch sample measurements from the circuit.\n\n        Args:\n            skip_reference_sample: Defaults to False. When set to True, the reference\n                sample used by the sampler is initialized to all-zeroes instead of being\n                collected from the circuit. This means that the results returned by the\n                sampler are actually whether or not each measurement was *flipped*,\n                instead of true measurement results.\n\n                Forcing an all-zero reference sample is useful when you are only\n                interested in error propagation and don't want to have to deal with the\n                fact that some measurements want to be On when no errors occur. It is\n                also useful when you know for sure that the all-zero result is actually\n                a possible result from the circuit (under noiseless execution), meaning\n                it is a valid reference sample as good as any other. Computing the\n                reference sample is the most time consuming and memory intensive part of\n                simulating the circuit, so promising that the simulator can safely skip\n                that step is an effective optimization.\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n            reference_sample: The data to xor into the measurement flips produced by the\n                frame simulator, in order to produce proper measurement results.\n                This can either be specified as an `np.bool_` array or a bit packed\n                `np.uint8` array (little endian). Under normal conditions, the reference\n                sample should be a valid noiseless sample of the circuit, such as the\n                one returned by `circuit.reference_sample()`. If this argument is not\n                provided, the reference sample will be set to\n                `circuit.reference_sample()`, unless `skip_reference_sample=True`\n                is used, in which case it will be set to all-zeros.\n\n        Raises:\n            ValueError: skip_reference_sample is True and reference_sample is not None.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 2\n            ...    M 0 1 2\n            ... ''')\n            >>> s = c.compile_sampler()\n            >>> s.sample(shots=1)\n            array([[False, False,  True]])\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a copy of the circuit. An independent circuit with the same contents.\n\n        Examples:\n            >>> import stim\n\n            >>> c1 = stim.Circuit(\"H 0\")\n            >>> c2 = c1.copy()\n            >>> c2 is c1\n            False\n            >>> c2 == c1\n            True\n        \"\"\"\n    def count_determined_measurements(\n        self,\n        *,\n        unknown_input: bool = False,\n    ) -> int:\n        \"\"\"Counts the number of predictable measurements in the circuit.\n\n        This method ignores any noise in the circuit.\n\n        This method works by performing a tableau stabilizer simulation of the circuit\n        and, before each measurement is simulated, checking if its expectation is\n        non-zero.\n\n        A measurement is predictable if its result can be predicted by using other\n        measurements that have already been performed, assuming the circuit is executed\n        without any noise.\n\n        Note that, when multiple measurements occur at the same time, re-ordering the\n        order they are resolved can change which specific measurements are predictable\n        but won't change how many of them were predictable in total.\n\n        The number of predictable measurements is a useful quantity because it's\n        related to the number of detectors and observables that a circuit should\n        declare. If circuit.num_detectors + circuit.num_observables is less than\n        circuit.count_determined_measurements(), this is a warning sign that you've\n        missed some detector declarations.\n\n        The exact relationship between the number of determined measurements and the\n        number of detectors and observables can differ from code to code. For example,\n        the toric code has an extra redundant measurement compared to the surface code\n        because in the toric code the last X stabilizer to be measured is equal to the\n        product of all other X stabilizers even in the first round when initializing in\n        the Z basis. Typically this relationship is not declared as a detector, because\n        it's not local, or as an observable, because it doesn't store a qubit.\n\n        Args:\n            unknown_input: Defaults to False (inputs assumed to be in the |0> state).\n                When set to True, the inputs are instead treated as being in unknown\n                random states. For example, this means that Z-basis measurements at\n                the very beginning of the circuit will be considered random rather\n                than determined.\n\n        Returns:\n            The number of measurements that were predictable.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     R 0\n            ...     M 0\n            ... ''').count_determined_measurements()\n            1\n\n            >>> stim.Circuit('''\n            ...     R 0\n            ...     H 0\n            ...     M 0\n            ... ''').count_determined_measurements()\n            0\n\n            >>> stim.Circuit('''\n            ...     M 0\n            ... ''').count_determined_measurements()\n            1\n\n            >>> stim.Circuit('''\n            ...     M 0\n            ... ''').count_determined_measurements(unknown_input=True)\n            0\n\n            >>> stim.Circuit('''\n            ...     M 0\n            ...     M 0 1\n            ...     M 0 1 2\n            ...     M 0 1 2 3\n            ... ''').count_determined_measurements(unknown_input=True)\n            6\n\n            >>> stim.Circuit('''\n            ...     R 0 1\n            ...     MZZ 0 1\n            ...     MYY 0 1\n            ...     MXX 0 1\n            ... ''').count_determined_measurements()\n            2\n\n            >>> circuit = stim.Circuit.generated(\n            ...     \"surface_code:rotated_memory_x\",\n            ...     distance=5,\n            ...     rounds=9,\n            ... )\n            >>> circuit.count_determined_measurements()\n            217\n            >>> circuit.num_detectors + circuit.num_observables\n            217\n        \"\"\"\n    def decomposed(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Recreates the circuit using (mostly) the {H,S,CX,M,R} gate set.\n\n        The intent of this method is to simplify the circuit to use fewer gate types,\n        so it's easier for other tools to consume. Currently, this method performs the\n        following simplifications:\n\n        - Single qubit cliffords are decomposed into {H,S}.\n        - Multi-qubit cliffords are decomposed into {H,S,CX}.\n        - Single qubit dissipative gates are decomposed into {H,S,M,R}.\n        - Multi-qubit dissipative gates are decomposed into {H,S,CX,M,R}.\n\n        Currently, the following types of gate *aren't* simplified, but they may be\n        in the future:\n\n        - Noise instructions (like X_ERROR, DEPOLARIZE2, and E).\n        - Annotations (like TICK, DETECTOR, and SHIFT_COORDS).\n        - The MPAD instruction.\n        - Repeat blocks are not flattened.\n\n        Returns:\n            A `stim.Circuit` whose function is equivalent to the original circuit,\n            but with most gates decomposed into the {H,S,CX,M,R} gate set.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     SWAP 0 1\n            ... ''').decomposed()\n            stim.Circuit('''\n                CX 0 1 1 0 0 1\n            ''')\n\n            >>> stim.Circuit('''\n            ...     ISWAP 0 1 2 1\n            ...     TICK\n            ...     MPP !X1*Y2*Z3\n            ... ''').decomposed()\n            stim.Circuit('''\n                H 0\n                CX 0 1 1 0\n                H 1\n                S 1 0\n                H 2\n                CX 2 1 1 2\n                H 1\n                S 1 2\n                TICK\n                H 1 2\n                S 2\n                H 2\n                S 2 2\n                CX 2 1 3 1\n                M !1\n                CX 2 1 3 1\n                H 2\n                S 2\n                H 2\n                S 2 2\n                H 1\n            ''')\n        \"\"\"\n    def detecting_regions(\n        self,\n        *,\n        targets: Optional[Iterable[stim.DemTarget | str | Iterable[float]]] = None,\n        ticks: Optional[Iterable[int]] = None,\n    ) -> Dict[stim.DemTarget, Dict[int, stim.PauliString]]:\n        \"\"\"Records where detectors and observables are sensitive to errors over time.\n\n        The result of this method is a nested dictionary, mapping detectors/observables\n        and ticks to Pauli sensitivities for that detector/observable at that time.\n\n        For example, if observable 2 has Z-type sensitivity on qubits 5 and 6 during\n        tick 3, then `result[stim.target_logical_observable_id(2)][3]` will be equal to\n        `stim.PauliString(\"Z5*Z6\")`.\n\n        If you want sensitivities from more places in the circuit, besides just at the\n        TICK instructions, you can work around this by making a version of the circuit\n        with more TICKs.\n\n        Args:\n            targets: Defaults to everything (None).\n\n                When specified, this should be an iterable of filters where items\n                matching any one filter are included.\n\n                A variety of filters are supported:\n                    stim.DemTarget: Includes the targeted detector or observable.\n                    Iterable[float]: Coordinate prefix match. Includes detectors whose\n                        coordinate data begins with the same floats.\n                    \"D\": Includes all detectors.\n                    \"L\": Includes all observables.\n                    \"D#\" (e.g. \"D5\"): Includes the detector with the specified index.\n                    \"L#\" (e.g. \"L5\"): Includes the observable with the specified index.\n\n            ticks: Defaults to everything (None).\n                When specified, this should be a list of integers corresponding to\n                the tick indices to report sensitivities for.\n\n            ignore_anticommutation_errors: Defaults to False.\n                When set to False, invalid detecting regions that anticommute with a\n                reset will cause the method to raise an exception. When set to True,\n                the offending component will simply be silently dropped. This can\n                result in broken detectors having apparently enormous detecting\n                regions.\n\n        Returns:\n            Nested dictionaries keyed first by a `stim.DemTarget` identifying the\n            detector or observable, then by the index of the tick, leading to a\n            PauliString with that target's error sensitivity at that tick.\n\n            Note you can use `stim.PauliString.pauli_indices` to quickly get to the\n            non-identity terms in the sensitivity.\n\n        Examples:\n            >>> import stim\n\n            >>> detecting_regions = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     H 0\n            ...     TICK\n            ...     CX 0 1\n            ...     TICK\n            ...     MX 0 1\n            ...     DETECTOR rec[-1] rec[-2]\n            ... ''').detecting_regions()\n            >>> for target, tick_regions in detecting_regions.items():\n            ...     print(\"target\", target)\n            ...     for tick, sensitivity in tick_regions.items():\n            ...         print(\"    tick\", tick, \"=\", sensitivity)\n            target D0\n                tick 0 = +Z_\n                tick 1 = +X_\n                tick 2 = +XX\n\n            >>> circuit = stim.Circuit.generated(\n            ...     \"surface_code:rotated_memory_x\",\n            ...     rounds=5,\n            ...     distance=4,\n            ... )\n\n            >>> detecting_regions = circuit.detecting_regions(\n            ...     targets=[\"L0\", (2, 4), stim.DemTarget.relative_detector_id(5)],\n            ...     ticks=range(5, 15),\n            ... )\n            >>> for target, tick_regions in detecting_regions.items():\n            ...     print(\"target\", target)\n            ...     for tick, sensitivity in tick_regions.items():\n            ...         print(\"    tick\", tick, \"=\", sensitivity)\n            target D1\n                tick 5 = +____________________X______________________\n                tick 6 = +____________________Z______________________\n            target D5\n                tick 5 = +______X____________________________________\n                tick 6 = +______Z____________________________________\n            target D14\n                tick 5 = +__________X_X______XXX_____________________\n                tick 6 = +__________X_X______XZX_____________________\n                tick 7 = +__________X_X______XZX_____________________\n                tick 8 = +__________X_X______XXX_____________________\n                tick 9 = +__________XXX_____XXX______________________\n                tick 10 = +__________XXX_______X______________________\n                tick 11 = +__________X_________X______________________\n                tick 12 = +____________________X______________________\n                tick 13 = +____________________Z______________________\n            target D29\n                tick 7 = +____________________Z______________________\n                tick 8 = +____________________X______________________\n                tick 9 = +____________________XX_____________________\n                tick 10 = +___________________XXX_______X_____________\n                tick 11 = +____________X______XXXX______X_____________\n                tick 12 = +__________X_X______XXX_____________________\n                tick 13 = +__________X_X______XZX_____________________\n                tick 14 = +__________X_X______XZX_____________________\n            target D44\n                tick 14 = +____________________Z______________________\n            target L0\n                tick 5 = +_X________X________X________X______________\n                tick 6 = +_X________X________X________X______________\n                tick 7 = +_X________X________X________X______________\n                tick 8 = +_X________X________X________X______________\n                tick 9 = +_X________X_______XX________X______________\n                tick 10 = +_X________X________X________X______________\n                tick 11 = +_X________XX_______X________XX_____________\n                tick 12 = +_X________X________X________X______________\n                tick 13 = +_X________X________X________X______________\n                tick 14 = +_X________X________X________X______________\n        \"\"\"\n    def detector_error_model(\n        self,\n        *,\n        decompose_errors: bool = False,\n        flatten_loops: bool = False,\n        allow_gauge_detectors: bool = False,\n        approximate_disjoint_errors: float = False,\n        ignore_decomposition_failures: bool = False,\n        block_decomposition_from_introducing_remnant_edges: bool = False,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns a stim.DetectorErrorModel describing the error processes in the circuit.\n\n        Args:\n            decompose_errors: Defaults to false. When set to true, the error analysis\n                attempts to decompose the components of composite error mechanisms (such\n                as depolarization errors) into simpler errors, and suggest this\n                decomposition via `stim.target_separator()` between the components. For\n                example, in an XZ surface code, single qubit depolarization has a Y\n                error term which can be decomposed into simpler X and Z error terms.\n                Decomposition fails (causing this method to throw) if it's not possible\n                to decompose large errors into simple errors that affect at most two\n                detectors.\n            flatten_loops: Defaults to false. When set to True, the output will not\n                contain any `repeat` blocks. When set to False, the error analysis\n                watches for loops in the circuit reaching a periodic steady state with\n                respect to the detectors being introduced, the error mechanisms that\n                affect them, and the locations of the logical observables. When it\n                identifies such a steady state, it outputs a repeat block. This is\n                massively more efficient than flattening for circuits that contain\n                loops, but creates a more complex output.\n            allow_gauge_detectors: Defaults to false. When set to false, the error\n                analysis verifies that detectors in the circuit are actually\n                deterministic under noiseless execution of the circuit. When set to\n                True, these detectors are instead considered to be part of degrees\n                freedom that can be removed from the error model. For example, if\n                detectors D1 and D3 both anti-commute with a reset, then the error model\n                has a gauge `error(0.5) D1 D3`. When gauges are identified, one of the\n                involved detectors is removed from the system using Gaussian\n                elimination.\n\n                Note that logical observables are still verified to be deterministic,\n                even if this option is set.\n            approximate_disjoint_errors: Defaults to false. When set to false, composite\n                error mechanisms with disjoint components (such as\n                `PAULI_CHANNEL_1(0.1, 0.2, 0.0)`) can cause the error analysis to throw\n                exceptions (because detector error models can only contain independent\n                error mechanisms). When set to true, the probabilities of the disjoint\n                cases are instead assumed to be independent probabilities. For example,\n                a `PAULI_CHANNEL_1(0.1, 0.2, 0.0)` becomes equivalent to an\n                `X_ERROR(0.1)` followed by a `Y_ERROR(0.2)`. This assumption is an\n                approximation, but it is a good approximation for small probabilities.\n\n                This argument can also be set to a probability between 0 and 1, setting\n                a threshold below which the approximation is acceptable. Any error\n                mechanisms that have a component probability above the threshold will\n                cause an exception to be thrown.\n            ignore_decomposition_failures: Defaults to False.\n                When this is set to True, circuit errors that fail to decompose into\n                graphlike detector error model errors no longer cause the conversion\n                process to abort. Instead, the undecomposed error is inserted into the\n                output. Whatever tool the detector error model is then given to is\n                responsible for dealing with the undecomposed errors (e.g. a tool may\n                choose to simply ignore them).\n\n                Irrelevant unless decompose_errors=True.\n            block_decomposition_from_introducing_remnant_edges: Defaults to False.\n                Requires that both A B and C D be present elsewhere in the detector\n                error model in order to decompose A B C D into A B ^ C D. Normally, only\n                one of A B or C D needs to appear to allow this decomposition.\n\n                Remnant edges can be a useful feature for ensuring decomposition\n                succeeds, but they can also reduce the effective code distance by giving\n                the decoder single edges that actually represent multiple errors in the\n                circuit (resulting in the decoder making misinformed choices when\n                decoding).\n\n                Irrelevant unless decompose_errors=True.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     X_ERROR(0.125) 0\n            ...     X_ERROR(0.25) 1\n            ...     CORRELATED_ERROR(0.375) X0 X1\n            ...     M 0 1\n            ...     DETECTOR rec[-2]\n            ...     DETECTOR rec[-1]\n            ... ''').detector_error_model()\n            stim.DetectorErrorModel('''\n                error(0.125) D0\n                error(0.375) D0 D1\n                error(0.25) D1\n            ''')\n        \"\"\"\n    def diagram(\n        self,\n        type: Literal[\"timeline-text\", \"timeline-svg\", \"timeline-svg-html\", \"timeline-3d\", \"timeline-3d-html\", \"detslice-text\", \"detslice-svg\", \"detslice-svg-html\", \"matchgraph-svg\", \"matchgraph-svg-html\", \"matchgraph-3d\", \"matchgraph-3d-html\", \"timeslice-svg\", \"timeslice-svg-html\", \"detslice-with-ops-svg\", \"detslice-with-ops-svg-html\", \"interactive\", \"interactive-html\"] = 'timeline-text',\n        *,\n        tick: Union[None, int, range] = None,\n        filter_coords: Iterable[Union[Iterable[float], stim.DemTarget]] = ((),),\n        rows: int | None = None,\n    ) -> 'stim._DiagramHelper':\n        \"\"\"Returns a diagram of the circuit, from a variety of options.\n\n        Args:\n            type: The type of diagram. Available types are:\n                \"timeline-text\" (default): An ASCII diagram of the\n                    operations applied by the circuit over time. Includes\n                    annotations showing the measurement record index that\n                    each measurement writes to, and the measurements used\n                    by detectors.\n                \"timeline-svg\": An SVG image of the operations applied by\n                    the circuit over time. Includes annotations showing the\n                    measurement record index that each measurement writes\n                    to, and the measurements used by detectors.\n                \"timeline-svg-html\": A resizable SVG image viewer of the\n                    operations applied by the circuit over time. Includes\n                    annotations showing the measurement record index that\n                    each measurement writes to, and the measurements used\n                    by detectors.\n                \"timeline-3d\": A 3d model, in GLTF format, of the operations\n                    applied by the circuit over time.\n                \"timeline-3d-html\": Same 3d model as 'timeline-3d' but\n                    embedded into an HTML web page containing an interactive\n                    THREE.js viewer for the 3d model.\n                \"detslice-text\": An ASCII diagram of the stabilizers\n                    that detectors declared by the circuit correspond to\n                    during the TICK instruction identified by the `tick`\n                    argument.\n                \"detslice-svg\": An SVG image of the stabilizers\n                    that detectors declared by the circuit correspond to\n                    during the TICK instruction identified by the `tick`\n                    argument. For example, a detector slice diagram of a\n                    CSS surface code circuit during the TICK between a\n                    measurement layer and a reset layer will produce the\n                    usual diagram of a surface code.\n\n                    Uses the Pauli color convention XYZ=RGB.\n                \"detslice-svg-html\": Same as detslice-svg but the SVG image\n                    is inside a resizable HTML iframe.\n                \"matchgraph-svg\": An SVG image of the match graph extracted\n                    from the circuit by stim.Circuit.detector_error_model.\n                \"matchgraph-svg-html\": Same as matchgraph-svg but the SVG image\n                    is inside a resizable HTML iframe.\n                \"matchgraph-3d\": An 3D model of the match graph extracted\n                    from the circuit by stim.Circuit.detector_error_model.\n                \"matchgraph-3d-html\": Same 3d model as 'match-graph-3d' but\n                    embedded into an HTML web page containing an interactive\n                    THREE.js viewer for the 3d model.\n                \"timeslice-svg\": An SVG image of the operations applied\n                    between two TICK instructions in the circuit, with the\n                    operations laid out in 2d.\n                \"timeslice-svg-html\": Same as timeslice-svg but the SVG image\n                    is inside a resizable HTML iframe.\n                \"detslice-with-ops-svg\": A combination of timeslice-svg\n                    and detslice-svg, with the operations overlaid\n                    over the detector slices taken from the TICK after the\n                    operations were applied.\n                \"detslice-with-ops-svg-html\": Same as detslice-with-ops-svg\n                    but the SVG image is inside a resizable HTML iframe.\n                \"interactive\" or \"interactive-html\": An HTML web page\n                    containing Crumble (an interactive editor for 2D\n                    stabilizer circuits) initialized with the given circuit\n                    as its default contents.\n            tick: Required for detector and time slice diagrams. Specifies\n                which TICK instruction, or range of TICK instructions, to\n                slice at. Note that the first TICK instruction in the\n                circuit corresponds tick=1. The value tick=0 refers to the\n                very start of the circuit.\n\n                Passing `range(A, B)` for a detector slice will show the\n                slices for ticks A through B including A but excluding B.\n\n                Passing `range(A, B)` for a time slice will show the\n                operations between tick A and tick B.\n            rows: In diagrams that have multiple separate pieces, such as timeslice\n                diagrams and detslice diagrams, this controls how many rows of\n                pieces there will be. If not specified, a number of rows that creates\n                a roughly square layout will be chosen.\n            filter_coords: A list of things to include in the diagram. Different\n                effects depending on the diagram.\n\n                For detslice diagrams, the filter defaults to showing all detectors\n                and no observables. When specified, each list entry can be a collection\n                of floats (detectors whose coordinates start with the same numbers will\n                be included), a stim.DemTarget (specifying a detector or observable\n                to include), a string like \"D5\" or \"L0\" specifying a detector or\n                observable to include.\n\n        Returns:\n            An object whose `__str__` method returns the diagram, so that\n            writing the diagram to a file works correctly. The returned\n            object may also define methods such as `_repr_html_`, so that\n            ipython notebooks recognize it can be shown using a specialized\n            viewer instead of as raw text.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1 1 2\n            ... ''')\n\n            >>> print(circuit.diagram())\n            q0: -H-@---\n                   |\n            q1: ---X-@-\n                     |\n            q2: -----X-\n\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ...     TICK\n            ...     M 0 1\n            ...     DETECTOR rec[-1] rec[-2]\n            ... ''')\n\n            >>> print(circuit.diagram(\"detslice-text\", tick=1))\n            q0: -Z:D0-\n                 |\n            q1: -Z:D0-\n        \"\"\"\n    def explain_detector_error_model_errors(\n        self,\n        *,\n        dem_filter: object = None,\n        reduce_to_one_representative_error: bool = False,\n    ) -> List[stim.ExplainedError]:\n        \"\"\"Explains how detector error model errors are produced by circuit errors.\n\n        Args:\n            dem_filter: Defaults to None (unused). When used, the output will only\n                contain detector error model errors that appear in the given\n                `stim.DetectorErrorModel`. Any error mechanisms from the detector error\n                model that can't be reproduced using one error from the circuit will\n                also be included in the result, but with an empty list of associated\n                circuit error mechanisms.\n            reduce_to_one_representative_error: Defaults to False. When True, the items\n                in the result will contain at most one circuit error mechanism.\n\n        Returns:\n            A `List[stim.ExplainedError]` (see `stim.ExplainedError` for more\n            information). Each item in the list describes how a detector error model\n            error can be produced by individual circuit errors.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     # Create Bell pair.\n            ...     H 0\n            ...     CNOT 0 1\n            ...\n            ...     # Noise.\n            ...     DEPOLARIZE1(0.01) 0\n            ...\n            ...     # Bell basis measurement.\n            ...     CNOT 0 1\n            ...     H 0\n            ...     M 0 1\n            ...\n            ...     # Both measurements should be False under noiseless execution.\n            ...     DETECTOR rec[-1]\n            ...     DETECTOR rec[-2]\n            ... ''')\n            >>> explained_errors = circuit.explain_detector_error_model_errors(\n            ...     dem_filter=stim.DetectorErrorModel('error(1) D0 D1'),\n            ...     reduce_to_one_representative_error=True,\n            ... )\n            >>> print(explained_errors[0].circuit_error_locations[0])\n            CircuitErrorLocation {\n                flipped_pauli_product: Y0\n                Circuit location stack trace:\n                    (after 0 TICKs)\n                    at instruction #3 (DEPOLARIZE1) in the circuit\n                    at target #1 of the instruction\n                    resolving to DEPOLARIZE1(0.01) 0\n            }\n        \"\"\"\n    def flattened(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Creates an equivalent circuit without REPEAT or SHIFT_COORDS.\n\n        Returns:\n            A `stim.Circuit` with the same instructions in the same order,\n            but with loops flattened into repeated instructions and with\n            all coordinate shifts inlined.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     REPEAT 5 {\n            ...         MR 0 1\n            ...         DETECTOR(0, 0) rec[-2]\n            ...         DETECTOR(1, 0) rec[-1]\n            ...         SHIFT_COORDS(0, 1)\n            ...     }\n            ... ''').flattened()\n            stim.Circuit('''\n                MR 0 1\n                DETECTOR(0, 0) rec[-2]\n                DETECTOR(1, 0) rec[-1]\n                MR 0 1\n                DETECTOR(0, 1) rec[-2]\n                DETECTOR(1, 1) rec[-1]\n                MR 0 1\n                DETECTOR(0, 2) rec[-2]\n                DETECTOR(1, 2) rec[-1]\n                MR 0 1\n                DETECTOR(0, 3) rec[-2]\n                DETECTOR(1, 3) rec[-1]\n                MR 0 1\n                DETECTOR(0, 4) rec[-2]\n                DETECTOR(1, 4) rec[-1]\n            ''')\n        \"\"\"\n    def flattened_operations(\n        self,\n    ) -> list:\n        \"\"\"[DEPRECATED]\n\n        Returns a list of tuples encoding the contents of the circuit.\n        Instead of this method, use `for instruction in circuit` or, to\n        avoid REPEAT blocks, `for instruction in circuit.flattened()`.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...    H 0\n            ...    X_ERROR(0.125) 1\n            ...    M 0 !1\n            ... ''').flattened_operations()\n            [('H', [0], 0), ('X_ERROR', [1], 0.125), ('M', [0, ('inv', 1)], 0)]\n\n            >>> stim.Circuit('''\n            ...    REPEAT 2 {\n            ...        H 6\n            ...    }\n            ... ''').flattened_operations()\n            [('H', [6], 0), ('H', [6], 0)]\n        \"\"\"\n    def flow_generators(\n        self,\n    ) -> List[stim.Flow]:\n        \"\"\"Returns a list of flows that generate all of the circuit's flows.\n\n        Every stabilizer flow that the circuit implements is a product of some\n        subset of the returned generators. Every returned flow will be a flow\n        of the circuit.\n\n        Returns:\n            A list of flow generators for the circuit.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit(\"H 0\").flow_generators()\n            [stim.Flow(\"X -> Z\"), stim.Flow(\"Z -> X\")]\n\n            >>> stim.Circuit(\"M 0\").flow_generators()\n            [stim.Flow(\"1 -> Z xor rec[0]\"), stim.Flow(\"Z -> rec[0]\")]\n\n            >>> stim.Circuit(\"RX 0\").flow_generators()\n            [stim.Flow(\"1 -> X\")]\n\n            >>> for flow in stim.Circuit(\"MXX 0 1\").flow_generators():\n            ...     print(flow)\n            1 -> XX xor rec[0]\n            _X -> _X\n            X_ -> _X xor rec[0]\n            ZZ -> ZZ\n\n            >>> for flow in stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     rounds=2,\n            ...     distance=3,\n            ...     after_clifford_depolarization=1e-3,\n            ... ).flow_generators():\n            ...     print(flow)\n            1 -> rec[0]\n            1 -> rec[1]\n            1 -> rec[2]\n            1 -> rec[3]\n            1 -> rec[4]\n            1 -> rec[5]\n            1 -> rec[6]\n            1 -> ____Z\n            1 -> ___Z_\n            1 -> __Z__\n            1 -> _Z___\n            1 -> Z____\n        \"\"\"\n    @staticmethod\n    def from_file(\n        file: Union[io.TextIOBase, str, pathlib.Path],\n    ) -> stim.Circuit:\n        \"\"\"Reads a stim circuit from a file.\n\n        The file format is defined at\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n        Args:\n            file: A file path or open file object to read from.\n\n        Returns:\n            The circuit parsed from the file.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         print('H 5', file=f)\n            ...     circuit = stim.Circuit.from_file(path)\n            >>> circuit\n            stim.Circuit('''\n                H 5\n            ''')\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         print('CNOT 4 5', file=f)\n            ...     with open(path) as f:\n            ...         circuit = stim.Circuit.from_file(f)\n            >>> circuit\n            stim.Circuit('''\n                CX 4 5\n            ''')\n        \"\"\"\n    @staticmethod\n    def generated(\n        code_task: str,\n        *,\n        distance: int,\n        rounds: int,\n        after_clifford_depolarization: float = 0.0,\n        before_round_data_depolarization: float = 0.0,\n        before_measure_flip_probability: float = 0.0,\n        after_reset_flip_probability: float = 0.0,\n    ) -> stim.Circuit:\n        \"\"\"Generates common circuits.\n\n        The generated circuits can include configurable noise.\n\n        The generated circuits include DETECTOR and OBSERVABLE_INCLUDE annotations so\n        that their detection events and logical observables can be sampled.\n\n        The generated circuits include TICK annotations to mark the progression of time.\n        (E.g. so that converting them using `stimcirq.stim_circuit_to_cirq_circuit` will\n        produce a `cirq.Circuit` with the intended moment structure.)\n\n        Args:\n            code_task: A string identifying the type of circuit to generate. Available\n                code tasks are:\n                    - \"repetition_code:memory\"\n                    - \"surface_code:rotated_memory_x\"\n                    - \"surface_code:rotated_memory_z\"\n                    - \"surface_code:unrotated_memory_x\"\n                    - \"surface_code:unrotated_memory_z\"\n                    - \"color_code:memory_xyz\"\n            distance: The desired code distance of the generated circuit. The code\n                distance is the minimum number of physical errors needed to cause a\n                logical error. This parameter indirectly determines how many qubits the\n                generated circuit uses.\n            rounds: How many times the measurement qubits in the generated circuit will\n                be measured. Indirectly determines the duration of the generated\n                circuit.\n            after_clifford_depolarization: Defaults to 0. The probability (p) of\n                `DEPOLARIZE1(p)` operations to add after every single-qubit Clifford\n                operation and `DEPOLARIZE2(p)` operations to add after every two-qubit\n                Clifford operation. The after-Clifford depolarizing operations are only\n                included if this probability is not 0.\n            before_round_data_depolarization: Defaults to 0. The probability (p) of\n                `DEPOLARIZE1(p)` operations to apply to every data qubit at the start of\n                a round of stabilizer measurements. The start-of-round depolarizing\n                operations are only included if this probability is not 0.\n            before_measure_flip_probability: Defaults to 0. The probability (p) of\n                `X_ERROR(p)` operations applied to qubits before each measurement (X\n                basis measurements use `Z_ERROR(p)` instead). The before-measurement\n                flips are only included if this probability is not 0.\n            after_reset_flip_probability: Defaults to 0. The probability (p) of\n                `X_ERROR(p)` operations applied to qubits after each reset (X basis\n                resets use `Z_ERROR(p)` instead). The after-reset flips are only\n                included if this probability is not 0.\n\n        Returns:\n            The generated circuit.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     distance=4,\n            ...     rounds=10000,\n            ...     after_clifford_depolarization=0.0125)\n            >>> print(circuit)\n            R 0 1 2 3 4 5 6\n            TICK\n            CX 0 1 2 3 4 5\n            DEPOLARIZE2(0.0125) 0 1 2 3 4 5\n            TICK\n            CX 2 1 4 3 6 5\n            DEPOLARIZE2(0.0125) 2 1 4 3 6 5\n            TICK\n            MR 1 3 5\n            DETECTOR(1, 0) rec[-3]\n            DETECTOR(3, 0) rec[-2]\n            DETECTOR(5, 0) rec[-1]\n            REPEAT 9999 {\n                TICK\n                CX 0 1 2 3 4 5\n                DEPOLARIZE2(0.0125) 0 1 2 3 4 5\n                TICK\n                CX 2 1 4 3 6 5\n                DEPOLARIZE2(0.0125) 2 1 4 3 6 5\n                TICK\n                MR 1 3 5\n                SHIFT_COORDS(0, 1)\n                DETECTOR(1, 0) rec[-3] rec[-6]\n                DETECTOR(3, 0) rec[-2] rec[-5]\n                DETECTOR(5, 0) rec[-1] rec[-4]\n            }\n            M 0 2 4 6\n            DETECTOR(1, 1) rec[-3] rec[-4] rec[-7]\n            DETECTOR(3, 1) rec[-2] rec[-3] rec[-6]\n            DETECTOR(5, 1) rec[-1] rec[-2] rec[-5]\n            OBSERVABLE_INCLUDE(0) rec[-1]\n        \"\"\"\n    def get_detector_coordinates(\n        self,\n        only: object = None,\n    ) -> Dict[int, List[float]]:\n        \"\"\"Returns the coordinate metadata of detectors in the circuit.\n\n        Args:\n            only: Defaults to None (meaning include all detectors). A list of detector\n                indices to include in the result. Detector indices beyond the end of the\n                detector error model of the circuit cause an error.\n\n        Returns:\n            A dictionary mapping integers (detector indices) to lists of floats\n            (coordinates).\n\n            Detectors with no specified coordinate data are mapped to an empty tuple.\n            If `only` is specified, then `set(result.keys()) == set(only)`.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ...    DETECTOR(1, 2, 3) rec[-1]\n            ...    REPEAT 3 {\n            ...        DETECTOR(42) rec[-1]\n            ...        SHIFT_COORDS(100)\n            ...    }\n            ... ''')\n            >>> circuit.get_detector_coordinates()\n            {0: [], 1: [1.0, 2.0, 3.0], 2: [42.0], 3: [142.0], 4: [242.0]}\n            >>> circuit.get_detector_coordinates(only=[1])\n            {1: [1.0, 2.0, 3.0]}\n        \"\"\"\n    def get_final_qubit_coordinates(\n        self,\n    ) -> Dict[int, List[float]]:\n        \"\"\"Returns the coordinate metadata of qubits in the circuit.\n\n        If a qubit's coordinates are specified multiple times, only the last specified\n        coordinates are returned.\n\n        Returns:\n            A dictionary mapping qubit indices (integers) to coordinates (lists of\n            floats). Qubits that never had their coordinates specified are not included\n            in the result.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...    QUBIT_COORDS(1, 2, 3) 1\n            ... ''')\n            >>> circuit.get_final_qubit_coordinates()\n            {1: [1.0, 2.0, 3.0]}\n        \"\"\"\n    def has_all_flows(\n        self,\n        flows: Iterable[stim.Flow],\n        *,\n        unsigned: bool = False,\n    ) -> bool:\n        \"\"\"Determines if the circuit has all the given stabilizer flow or not.\n\n        This is a faster version of `all(c.has_flow(f) for f in flows)`. It's faster\n        because, behind the scenes, the circuit can be iterated once instead of once\n        per flow.\n\n        This method ignores any noise in the circuit.\n\n        Args:\n            flows: An iterable of `stim.Flow` instances representing the flows to check.\n            unsigned: Defaults to False. When False, the flows must be correct including\n                the sign of the Pauli strings. When True, only the Pauli terms need to\n                be correct; the signs are permitted to be inverted. In effect, this\n                requires the circuit to be correct up to Pauli gates.\n\n        Returns:\n            True if the circuit has the given flow; False otherwise.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('H 0').has_all_flows([\n            ...     stim.Flow('X -> Z'),\n            ...     stim.Flow('Y -> Y'),\n            ...     stim.Flow('Z -> X'),\n            ... ])\n            False\n\n            >>> stim.Circuit('H 0').has_all_flows([\n            ...     stim.Flow('X -> Z'),\n            ...     stim.Flow('Y -> -Y'),\n            ...     stim.Flow('Z -> X'),\n            ... ])\n            True\n\n            >>> stim.Circuit('H 0').has_all_flows([\n            ...     stim.Flow('X -> Z'),\n            ...     stim.Flow('Y -> Y'),\n            ...     stim.Flow('Z -> X'),\n            ... ], unsigned=True)\n            True\n\n        Caveats:\n            Currently, the unsigned=False version of this method is implemented by\n            performing 256 randomized tests. Each test has a 50% chance of a false\n            positive, and a 0% chance of a false negative. So, when the method returns\n            True, there is technically still a 2^-256 chance the circuit doesn't have\n            the flow. This is lower than the chance of a cosmic ray flipping the result.\n        \"\"\"\n    def has_flow(\n        self,\n        flow: stim.Flow,\n        *,\n        unsigned: bool = False,\n    ) -> bool:\n        \"\"\"Determines if the circuit has the given stabilizer flow or not.\n\n        A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer\n        P at the start of the circuit to the instantaneous stabilizer Q at the end of\n        the circuit. The flow may be mediated by certain measurements. For example,\n        a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and\n        the CNOT flows implemented by the circuit involve these measurements.\n\n        A flow like P -> Q means the circuit transforms P into Q.\n        A flow like 1 -> P means the circuit prepares P.\n        A flow like P -> 1 means the circuit measures P.\n        A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR).\n\n        This method ignores any noise in the circuit.\n\n        Args:\n            flow: The flow to check for.\n            unsigned: Defaults to False. When False, the flows must be correct including\n                the sign of the Pauli strings. When True, only the Pauli terms need to\n                be correct; the signs are permitted to be inverted. In effect, this\n                requires the circuit to be correct up to Pauli gates.\n\n        Returns:\n            True if the circuit has the given flow; False otherwise.\n\n        Examples:\n            >>> import stim\n\n            >>> m = stim.Circuit('M 0')\n            >>> m.has_flow(stim.Flow('Z -> Z'))\n            True\n            >>> m.has_flow(stim.Flow('X -> X'))\n            False\n            >>> m.has_flow(stim.Flow('Z -> I'))\n            False\n            >>> m.has_flow(stim.Flow('Z -> I xor rec[-1]'))\n            True\n            >>> m.has_flow(stim.Flow('Z -> rec[-1]'))\n            True\n\n            >>> cx58 = stim.Circuit('CX 5 8')\n            >>> cx58.has_flow(stim.Flow('X5 -> X5*X8'))\n            True\n            >>> cx58.has_flow(stim.Flow('X_ -> XX'))\n            False\n            >>> cx58.has_flow(stim.Flow('_____X___ -> _____X__X'))\n            True\n\n            >>> stim.Circuit('''\n            ...     RY 0\n            ... ''').has_flow(stim.Flow(\n            ...     output=stim.PauliString(\"Y\"),\n            ... ))\n            True\n\n            >>> stim.Circuit('''\n            ...     RY 0\n            ...     X_ERROR(0.1) 0\n            ... ''').has_flow(stim.Flow(\n            ...     output=stim.PauliString(\"Y\"),\n            ... ))\n            True\n\n            >>> stim.Circuit('''\n            ...     RY 0\n            ... ''').has_flow(stim.Flow(\n            ...     output=stim.PauliString(\"X\"),\n            ... ))\n            False\n\n            >>> stim.Circuit('''\n            ...     CX 0 1\n            ... ''').has_flow(stim.Flow(\n            ...     input=stim.PauliString(\"+X_\"),\n            ...     output=stim.PauliString(\"+XX\"),\n            ... ))\n            True\n\n            >>> stim.Circuit('''\n            ...     # Lattice surgery CNOT\n            ...     R 1\n            ...     MXX 0 1\n            ...     MZZ 1 2\n            ...     MX 1\n            ... ''').has_flow(stim.Flow(\n            ...     input=stim.PauliString(\"+X_X\"),\n            ...     output=stim.PauliString(\"+__X\"),\n            ...     measurements=[0, 2],\n            ... ))\n            True\n\n            >>> stim.Circuit('''\n            ...     H 0\n            ... ''').has_flow(\n            ...     stim.Flow(\"Y -> Y\"),\n            ...     unsigned=True,\n            ... )\n            True\n\n            >>> stim.Circuit('''\n            ...     H 0\n            ... ''').has_flow(\n            ...     stim.Flow(\"Y -> Y\"),\n            ...     unsigned=False,\n            ... )\n            False\n\n        Caveats:\n            Currently, the unsigned=False version of this method is implemented by\n            performing 256 randomized tests. Each test has a 50% chance of a false\n            positive, and a 0% chance of a false negative. So, when the method returns\n            True, there is technically still a 2^-256 chance the circuit doesn't have\n            the flow. This is lower than the chance of a cosmic ray flipping the result.\n        \"\"\"\n    def insert(\n        self,\n        index: int,\n        operation: Union[stim.CircuitInstruction, stim.Circuit],\n    ) -> None:\n        \"\"\"Inserts an operation at the given index, pushing existing operations forward.\n\n        Beware that inserted operations are automatically fused with the preceding\n        and following operations, if possible. This can make it complex to reason\n        about how the indices of operations change in response to insertions.\n\n        Args:\n            index: The index to insert at.\n\n                Must satisfy -len(circuit) <= index < len(circuit). Negative indices\n                are made non-negative by adding len(circuit) to them, so they refer to\n                indices relative to the end of the circuit instead of the start.\n\n                Instructions before the index are not shifted. Instructions that\n                were at or after the index are shifted forwards as needed.\n            operation: The object to insert. This can be a single\n                stim.CircuitInstruction or an entire stim.Circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...     H 0\n            ...     S 1\n            ...     X 2\n            ... ''')\n            >>> c.insert(1, stim.CircuitInstruction(\"Y\", [3, 4, 5]))\n            >>> c\n            stim.Circuit('''\n                H 0\n                Y 3 4 5\n                S 1\n                X 2\n            ''')\n            >>> c.insert(-1, stim.Circuit(\"S 999\\nCX 0 1\\nCZ 2 3\"))\n            >>> c\n            stim.Circuit('''\n                H 0\n                Y 3 4 5\n                S 1 999\n                CX 0 1\n                CZ 2 3\n                X 2\n            ''')\n        \"\"\"\n    def inverse(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a circuit that applies the same operations but inverted and in reverse.\n\n        If circuit starts with QUBIT_COORDS instructions, the returned circuit will\n        still have the same QUBIT_COORDS instructions in the same order at the start.\n\n        Returns:\n            A `stim.Circuit` that applies inverted operations in the reverse order.\n\n        Raises:\n            ValueError: The circuit contains operations that don't have an inverse,\n                such as measurements. There are also some unsupported operations\n                such as SHIFT_COORDS.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     S 0 1\n            ...     ISWAP 0 1 1 2\n            ... ''').inverse()\n            stim.Circuit('''\n                ISWAP_DAG 1 2 0 1\n                S_DAG 1 0\n            ''')\n\n            >>> stim.Circuit('''\n            ...     QUBIT_COORDS(1, 2) 0\n            ...     QUBIT_COORDS(4, 3) 1\n            ...     QUBIT_COORDS(9, 5) 2\n            ...     H 0 1\n            ...     REPEAT 100 {\n            ...         CX 0 1 1 2\n            ...         TICK\n            ...         S 1 2\n            ...     }\n            ... ''').inverse()\n            stim.Circuit('''\n                QUBIT_COORDS(1, 2) 0\n                QUBIT_COORDS(4, 3) 1\n                QUBIT_COORDS(9, 5) 2\n                REPEAT 100 {\n                    S_DAG 2 1\n                    TICK\n                    CX 1 2 0 1\n                }\n                H 1 0\n            ''')\n        \"\"\"\n    def likeliest_error_sat_problem(\n        self,\n        *,\n        quantization: int = 100,\n        format: str = 'WDIMACS',\n    ) -> str:\n        \"\"\"Makes a maxSAT problem for the circuit's likeliest undetectable logical error.\n\n        The output is a string describing the maxSAT problem in WDIMACS format\n        (see https://jix.github.io/varisat/manual/0.2.0/formats/dimacs.html). The\n        optimal solution to the problem is the highest likelihood set of error\n        mechanisms that combine to flip any logical observable while producing no\n        detection events).\n\n        If there are any errors with probability p > 0.5, they are inverted so\n        that the resulting weight ends up being positive. If there are errors\n        with weight close or equal to 0.5, they can end up with 0 weight meaning\n        that they can be included or not in the solution with no affect on the\n        likelihood.\n\n        There are many tools that can solve maxSAT problems in WDIMACS format.\n        One quick way to get started is to install pysat by running this BASH\n        terminal command:\n\n            pip install python-sat\n\n        Afterwards, you can run the included maxSAT solver \"RC2\" with this\n        Python code:\n\n            from pysat.examples.rc2 import RC2\n            from pysat.formula import WCNF\n\n            wcnf = WCNF(from_string=\"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\")\n\n            with RC2(wcnf) as rc2:\n            print(rc2.compute())\n            print(rc2.cost)\n\n        Much faster solvers are available online. For example, you can download\n        one of the entries in the 2023 maxSAT competition (see\n        https://maxsat-evaluations.github.io/2023) and run it on your problem by\n        running these BASH terminal commands:\n\n            wget https://maxsat-evaluations.github.io/2023/mse23-solver-src/exact/CASHWMaxSAT-CorePlus.zip\n            unzip CASHWMaxSAT-CorePlus.zip\n            ./CASHWMaxSAT-CorePlus/bin/cashwmaxsatcoreplus -bm -m your_problem.wcnf\n\n        Args:\n            format: Defaults to \"WDIMACS\", corresponding to WDIMACS format which is\n                described here: http://www.maxhs.org/docs/wdimacs.html\n            quantization: Defaults to 10. Error probabilities are converted to log-odds\n                and scaled/rounded to be positive integers at most this large. Setting\n                this argument to a larger number results in more accurate quantization\n                such that the returned error set should have a likelihood closer to the\n                true most likely solution. This comes at the cost of making some maxSAT\n                solvers slower.\n\n        Returns:\n            A string corresponding to the contents of a maxSAT problem file in the\n            requested format.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...   X_ERROR(0.1) 0\n            ...   M 0\n            ...   OBSERVABLE_INCLUDE(0) rec[-1]\n            ...   X_ERROR(0.4) 0\n            ...   M 0\n            ...   DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> print(circuit.likeliest_error_sat_problem(\n            ...   quantization=1000\n            ... ), end='')\n            p wcnf 2 4 4001\n            185 -1 0\n            1000 -2 0\n            4001 -1 0\n            4001 2 0\n        \"\"\"\n    def missing_detectors(\n        self,\n        *,\n        unknown_input: bool = False,\n    ) -> int:\n        \"\"\"Finds deterministic measurements independent of declared detectors/observables.\n\n        This method is useful for debugging missing detectors in a circuit, because it\n        identifies generators for uncovered degrees of freedom.\n\n        It's not recommended to use this method to solve for the detectors of a circuit.\n        The returned detectors are not guaranteed to be stable across versions, and\n        aren't optimized to be \"good\" (e.g. form a low weight basis or be matchable\n        if possible). It will also identify things that are technically determined\n        but that the user may not want to use as a detector, such as the fact that\n        in the first round after transversal Z basis initialization of a toric code\n        the product of all X stabilizer measurements is deterministic even though the\n        individual measurements are all random.\n\n        Args:\n            unknown_input: Defaults to False (inputs assumed to be in the |0> state).\n                When set to True, the inputs are instead treated as being in unknown\n                random states. For example, this means that Z-basis measurements at\n                the very beginning of the circuit will be considered random rather\n                than determined.\n\n        Returns:\n            A circuit containing DETECTOR instructions that specify the uncovered\n            degrees of freedom in the deterministic measurement sets of the input\n            circuit. The returned circuit can be appended to the input circuit to\n            get a circuit with no missing detectors.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     R 0\n            ...     M 0\n            ... ''').missing_detectors()\n            stim.Circuit('''\n                DETECTOR rec[-1]\n            ''')\n\n            >>> stim.Circuit('''\n            ...     MZZ 0 1\n            ...     MYY 0 1\n            ...     MXX 0 1\n            ...     DEPOLARIZE1(0.1) 0 1\n            ...     MZZ 0 1\n            ...     MYY 0 1\n            ...     MXX 0 1\n            ...     DETECTOR rec[-1] rec[-4]\n            ...     DETECTOR rec[-2] rec[-5]\n            ...     DETECTOR rec[-3] rec[-6]\n            ... ''').missing_detectors(unknown_input=True)\n            stim.Circuit('''\n                DETECTOR rec[-3] rec[-2] rec[-1]\n            ''')\n        \"\"\"\n    @property\n    def num_detectors(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of bits produced when sampling the circuit's detectors.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ...    REPEAT 100 {\n            ...        M 0 1 2\n            ...        DETECTOR rec[-1]\n            ...        DETECTOR rec[-2]\n            ...    }\n            ... ''')\n            >>> c.num_detectors\n            201\n        \"\"\"\n    @property\n    def num_measurements(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of bits produced when sampling the circuit's measurements.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    M 0\n            ...    REPEAT 100 {\n            ...        M 0 1\n            ...    }\n            ... ''')\n            >>> c.num_measurements\n            201\n        \"\"\"\n    @property\n    def num_observables(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of logical observables defined by the circuit.\n\n        This is one more than the largest index that appears as an argument to an\n        OBSERVABLE_INCLUDE instruction.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    M 0\n            ...    OBSERVABLE_INCLUDE(2) rec[-1]\n            ...    OBSERVABLE_INCLUDE(5) rec[-1]\n            ... ''')\n            >>> c.num_observables\n            6\n        \"\"\"\n    @property\n    def num_qubits(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of qubits used when simulating the circuit.\n\n        This is always one more than the largest qubit index used by the circuit.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...    X 0\n            ...    M 0 1\n            ... ''').num_qubits\n            2\n            >>> stim.Circuit('''\n            ...    X 0\n            ...    M 0 1\n            ...    H 100\n            ... ''').num_qubits\n            101\n        \"\"\"\n    @property\n    def num_sweep_bits(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of sweep bits needed to completely configure the circuit.\n\n        This is always one more than the largest sweep bit index used by the circuit.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...    CX sweep[2] 0\n            ... ''').num_sweep_bits\n            3\n            >>> stim.Circuit('''\n            ...    CZ sweep[5] 0\n            ...    CX sweep[2] 0\n            ... ''').num_sweep_bits\n            6\n        \"\"\"\n    @property\n    def num_ticks(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of TICK instructions executed when running the circuit.\n\n        TICKs in loops are counted once per iteration.\n\n        Returns:\n            The number of ticks executed by the circuit.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit().num_ticks\n            0\n\n            >>> stim.Circuit('''\n            ...    TICK\n            ... ''').num_ticks\n            1\n\n            >>> stim.Circuit('''\n            ...    H 0\n            ...    TICK\n            ...    CX 0 1\n            ...    TICK\n            ... ''').num_ticks\n            2\n\n            >>> stim.Circuit('''\n            ...    H 0\n            ...    TICK\n            ...    REPEAT 100 {\n            ...        CX 0 1\n            ...        TICK\n            ...    }\n            ... ''').num_ticks\n            101\n        \"\"\"\n    def pop(\n        self,\n        index: int = -1,\n    ) -> Union[stim.CircuitInstruction, stim.CircuitRepeatBlock]:\n        \"\"\"Pops an operation from the end of the circuit, or at the given index.\n\n        Args:\n            index: Defaults to -1 (end of circuit). The index to pop from.\n\n        Returns:\n            The popped instruction.\n\n        Raises:\n            IndexError: The given index is outside the bounds of the circuit.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...     H 0\n            ...     S 1\n            ...     X 2\n            ...     Y 3\n            ... ''')\n            >>> c.pop()\n            stim.CircuitInstruction('Y', [stim.GateTarget(3)], [])\n            >>> c.pop(1)\n            stim.CircuitInstruction('S', [stim.GateTarget(1)], [])\n            >>> c\n            stim.Circuit('''\n                H 0\n                X 2\n            ''')\n        \"\"\"\n    def reference_detector_and_observable_signs(\n        self,\n        *,\n        bit_packed: bool = False,\n    ) -> Tuple[np.ndarray, np.ndarray]:\n        \"\"\"Determines noiseless parities of the measurement sets of detectors/observables.\n\n        BEWARE: the returned values are NOT the \"expected value of the\n        detector/observable\". Stim consistently defines the value of a\n        detector/observable as whether or not it flipped, so the expected value of a\n        detector/observable is vacuously always 0 (not flipped). This method instead\n        returns the \"sign\"; the expected parity of the measurement set declared by the\n        detector/observable. The sign is the baseline used to determine if a flip\n        occurred. A detector/observable's value is whether its sign disagrees with the\n        measured parity of its measurement set.\n\n        Note that this method doesn't account for sweep bits. It will effectively ignore\n        instructions like `CX sweep[0] 0`.\n\n        Args:\n            bit_packed: Defaults to False. Determines whether the output numpy arrays\n                use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n        Returns:\n            A (det, obs) tuple with numpy arrays containing the reference parities.\n\n            if bit_packed:\n                det.shape == (math.ceil(num_detectors / 8),)\n                det.dtype == np.uint8\n                obs.shape == (math.ceil(num_observables / 8),)\n                obs.dtype == np.uint8\n            else:\n                det.shape == (num_detectors,)\n                det.dtype == np.bool_\n                obs.shape == (num_observables,)\n                obs.dtype == np.bool_\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     X 1\n            ...     M 0 1\n            ...     DETECTOR rec[-1]\n            ...     DETECTOR rec[-2]\n            ...     OBSERVABLE_INCLUDE(3) rec[-1] rec[-2]\n            ... ''').reference_detector_and_observable_signs()\n            (array([ True, False]), array([False, False, False,  True]))\n        \"\"\"\n    def reference_sample(\n        self,\n        *,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Samples the given circuit in a deterministic fashion.\n\n        Discards all noisy operations, and biases all collapse events\n        towards +Z instead of randomly +Z/-Z.\n\n        Args:\n            bit_packed: Defaults to False. Determines whether the output numpy arrays\n                use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n        Returns:\n            A numpy array containing the reference sample.\n\n            if bit_packed:\n                shape == (math.ceil(num_measurements / 8),)\n                dtype == np.uint8\n            else:\n                shape == (num_measurements,)\n                dtype == np.bool_\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     X 1\n            ...     M 0 1\n            ... ''').reference_sample()\n            array([False,  True])\n        \"\"\"\n    def search_for_undetectable_logical_errors(\n        self,\n        *,\n        dont_explore_detection_event_sets_with_size_above: int,\n        dont_explore_edges_with_degree_above: int,\n        dont_explore_edges_increasing_symptom_degree: bool,\n        canonicalize_circuit_errors: bool = False,\n    ) -> List[stim.ExplainedError]:\n        \"\"\"Searches for small sets of errors that form an undetectable logical error.\n\n        THIS IS A HEURISTIC METHOD. It does not guarantee that it will find errors of\n        particular sizes, or with particular properties. The errors it finds are a\n        tangled combination of the truncation parameters you specify, internal\n        optimizations which are correct when not truncating, and minutia of the circuit\n        being considered.\n\n        If you want a well behaved method that does provide guarantees of finding errors\n        of a particular type, use `stim.Circuit.shortest_graphlike_error`. This method\n        is more thorough than that (assuming you don't truncate so hard you omit\n        graphlike edges), but exactly how thorough is difficult to describe. It's also\n        not guaranteed that the behavior of this method will not be changed in the\n        future in a way that permutes which logical errors are found and which are\n        missed.\n\n        This search method considers hyper errors, so it has worst case exponential\n        runtime. It is important to carefully consider the arguments you are providing,\n        which truncate the search space and trade cost for quality.\n\n        The search progresses by starting from each error that crosses a logical\n        observable, noting which detection events each error produces, and then\n        iteratively adding in errors touching those detection events attempting to\n        cancel out the detection event with the lowest index.\n\n        Beware that the choice of logical observable can interact with the truncation\n        options. Using different observables can change whether or not the search\n        succeeds, even if those observables are equal modulo the stabilizers of the\n        code. This is because the edges crossing logical observables are used as\n        starting points for the search, and starting from different places along a path\n        will result in different numbers of symptoms in intermediate states as the\n        search progresses. For example, if the logical observable is next to a boundary,\n        then the starting edges are likely boundary edges (degree 1) with 'room to\n        grow', whereas if the observable was running through the bulk then the starting\n        edges will have degree at least 2.\n\n        Args:\n            dont_explore_detection_event_sets_with_size_above: Truncates the search\n                space by refusing to cross an edge (i.e. add an error) when doing so\n                would produce an intermediate state that has more detection events than\n                this limit.\n            dont_explore_edges_with_degree_above: Truncates the search space by refusing\n                to consider errors that cause a lot of detection events. For example,\n                you may only want to consider graphlike errors which have two or fewer\n                detection events.\n            dont_explore_edges_increasing_symptom_degree: Truncates the search space by\n                refusing to cross an edge (i.e. add an error) when doing so would\n                produce an intermediate state that has more detection events that the\n                previous intermediate state. This massively improves the efficiency of\n                the search because instead of, for example, exploring all n^4 possible\n                detection event sets with 4 symptoms, the search will attempt to cancel\n                out symptoms one by one.\n            canonicalize_circuit_errors: Whether or not to use one representative for\n                equal-symptom circuit errors.\n\n                False (default): Each DEM error lists every possible circuit error that\n                    single handedly produces those symptoms as a potential match. This\n                    is verbose but gives complete information.\n                True: Each DEM error is matched with one possible circuit error that\n                    single handedly produces those symptoms, with a preference towards\n                    errors that are simpler (e.g. apply Paulis to fewer qubits). This\n                    discards mostly-redundant information about different ways to\n                    produce the same symptoms in order to give a succinct result.\n\n        Returns:\n            A list of error mechanisms that cause an undetected logical error.\n\n            Each entry in the list is a `stim.ExplainedError` detailing the location\n            and effects of a single physical error. The effects of the entire list\n            combine to produce a logical frame change without any detection events.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit.generated(\n            ...     \"surface_code:rotated_memory_x\",\n            ...     rounds=5,\n            ...     distance=5,\n            ...     after_clifford_depolarization=0.001)\n            >>> print(len(circuit.search_for_undetectable_logical_errors(\n            ...     dont_explore_detection_event_sets_with_size_above=4,\n            ...     dont_explore_edges_with_degree_above=4,\n            ...     dont_explore_edges_increasing_symptom_degree=True,\n            ... )))\n            5\n        \"\"\"\n    def shortest_error_sat_problem(\n        self,\n        *,\n        format: str = 'WDIMACS',\n    ) -> str:\n        \"\"\"Makes a maxSAT problem of the circuit's distance, that other tools can solve.\n\n        The output is a string describing the maxSAT problem in WDIMACS format\n        (see https://jix.github.io/varisat/manual/0.2.0/formats/dimacs.html). The\n        optimal solution to the problem is the fault distance of the circuit (the\n        minimum number of error mechanisms that combine to flip any logical observable\n        while producing no detection events). This method ignores the probabilities of\n        the error mechanisms since it only cares about minimizing the number of errors\n        triggered.\n\n        There are many tools that can solve maxSAT problems in WDIMACS format.\n        One quick way to get started is to install pysat by running this BASH\n        terminal command:\n\n            pip install python-sat\n\n        Afterwards, you can run the included maxSAT solver \"RC2\" with this\n        Python code:\n\n            from pysat.examples.rc2 import RC2\n            from pysat.formula import WCNF\n\n            wcnf = WCNF(from_string=\"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\")\n\n            with RC2(wcnf) as rc2:\n            print(rc2.compute())\n            print(rc2.cost)\n\n        Much faster solvers are available online. For example, you can download\n        one of the entries in the 2023 maxSAT competition (see\n        https://maxsat-evaluations.github.io/2023) and run it on your problem by\n        running these BASH terminal commands:\n\n            wget https://maxsat-evaluations.github.io/2023/mse23-solver-src/exact/CASHWMaxSAT-CorePlus.zip\n            unzip CASHWMaxSAT-CorePlus.zip\n            ./CASHWMaxSAT-CorePlus/bin/cashwmaxsatcoreplus -bm -m your_problem.wcnf\n\n        Args:\n            format: Defaults to \"WDIMACS\", corresponding to WDIMACS format which is\n                described here: http://www.maxhs.org/docs/wdimacs.html\n\n        Returns:\n            A string corresponding to the contents of a maxSAT problem file in the\n            requested format.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...   X_ERROR(0.1) 0\n            ...   M 0\n            ...   OBSERVABLE_INCLUDE(0) rec[-1]\n            ...   X_ERROR(0.4) 0\n            ...   M 0\n            ...   DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> print(circuit.shortest_error_sat_problem(), end='')\n            p wcnf 2 4 5\n            1 -1 0\n            1 -2 0\n            5 -1 0\n            5 2 0\n        \"\"\"\n    def shortest_graphlike_error(\n        self,\n        *,\n        ignore_ungraphlike_errors: bool = True,\n        canonicalize_circuit_errors: bool = False,\n    ) -> List[stim.ExplainedError]:\n        \"\"\"Finds a minimum set of graphlike errors to produce an undetected logical error.\n\n        A \"graphlike error\" is an error that creates at most two detection events\n        (causes a change in the parity of the measurement sets of at most two DETECTOR\n        annotations).\n\n        Note that this method does not pay attention to error probabilities (other than\n        ignoring errors with probability 0). It searches for a logical error with the\n        minimum *number* of physical errors, not the maximum probability of those\n        physical errors all occurring.\n\n        This method works by converting the circuit into a `stim.DetectorErrorModel`\n        using `circuit.detector_error_model(...)`, computing the shortest graphlike\n        error of the error model, and then converting the physical errors making up that\n        logical error back into representative circuit errors.\n\n        Args:\n            ignore_ungraphlike_errors:\n                False: Attempt to decompose any ungraphlike errors in the circuit into\n                    graphlike parts. If this fails, raise an exception instead of\n                    continuing.\n\n                    Note: in some cases, graphlike errors only appear as parts of\n                    decomposed ungraphlike errors. This can produce a result that lists\n                    DEM errors with zero matching circuit errors, because the only way\n                    to achieve those errors is by combining a decomposed error with a\n                    graphlike error. As a result, when using this option it is NOT\n                    guaranteed that the length of the result is an upper bound on the\n                    true code distance. That is only the case if every item in the\n                    result lists at least one matching circuit error.\n                True (default): Ungraphlike errors are simply skipped as if they weren't\n                    present, even if they could become graphlike if decomposed. This\n                    guarantees the length of the result is an upper bound on the true\n                    code distance.\n            canonicalize_circuit_errors: Whether or not to use one representative for\n                equal-symptom circuit errors.\n\n                False (default): Each DEM error lists every possible circuit error that\n                    single handedly produces those symptoms as a potential match. This\n                    is verbose but gives complete information.\n                True: Each DEM error is matched with one possible circuit error that\n                    single handedly produces those symptoms, with a preference towards\n                    errors that are simpler (e.g. apply Paulis to fewer qubits). This\n                    discards mostly-redundant information about different ways to\n                    produce the same symptoms in order to give a succinct result.\n\n        Returns:\n            A list of error mechanisms that cause an undetected logical error.\n\n            Each entry in the list is a `stim.ExplainedError` detailing the location\n            and effects of a single physical error. The effects of the entire list\n            combine to produce a logical frame change without any detection events.\n\n        Examples:\n            >>> import stim\n\n            >>> circuit = stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     rounds=10,\n            ...     distance=7,\n            ...     before_round_data_depolarization=0.01)\n            >>> len(circuit.shortest_graphlike_error())\n            7\n        \"\"\"\n    def solve_flow_measurements(\n        self,\n        flows: List[stim.Flow],\n    ) -> List[Optional[List[int]]]:\n        \"\"\"Finds measurements to explain the starts/ends of the given flows, ignoring sign.\n\n        CAUTION: it's not guaranteed that the solutions returned by this method are\n        minimal. It may use 20 measurements when only 2 are needed. The method applies\n        some simple heuristics that attempt to reduce the size, but these heuristics\n        aren't perfect and don't make any strong guarantees.\n\n        The recommended way to use this method is on small parts of a circuit, such as a\n        single surface code round. The ideal use case is when there is exactly one\n        solution for each flow, because then the method behaves predictably and\n        consistently. When there are multiple solutions, the method has no real way to\n        pick out a \"good\" solution rather than a \"cataclysmic trash fire of a\" solution.\n        For example, if you have a multi-round surface code circuit with open time\n        boundaries and solve the flow 1 -> Z1*Z2*Z3*Z4, then there's a good solution\n        (the Z1*Z2*Z3*Z4 measurement from the last round), various mediocre solutions\n        (a Z1*Z2*Z3*Z4 measurement from a different round), and lots of terrible\n        solutions (a combination of multiple Z1*Z2*Z3*Z4 measurements from an odd number\n        of rounds, times a random combination of unrelated detectors). The method is\n        permitted to return any of those solutions.\n\n        Args:\n            flows: A list of flows, each of which to be solved. Measurements and signs\n                are entirely ignored.\n\n                An error is raised if one of the given flows has an identity pauli\n                string as its input and as its output, despite the fact that this case\n                has a vacuous solution (no measurements). This error is only present as\n                a safety check that catches some possible bugs in the calling code, such\n                as accidentally applying this method to detector flows. This error may\n                be removed in the future, so that the vacuous case succeeds vacuously.\n\n        Returns:\n            A list of solutions for each given flow.\n\n            If no solution exists for flows[k], then solutions[k] is None.\n            Otherwise, solutions[k] is a list of measurement indices for flows[k].\n\n            When solutions[k] is not None, it's guaranteed that\n\n                circuit.has_flow(stim.Flow(\n                    input=flows[k].input,\n                    output=flows[k].output,\n                    measurements=solutions[k],\n                ), unsigned=True)\n\n        Raises:\n            ValueError:\n                A flow had an empty input and output.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     M 2\n            ... ''').solve_flow_measurements([\n            ...     stim.Flow(\"Z2 -> 1\"),\n            ... ])\n            [[0]]\n\n            >>> stim.Circuit('''\n            ...     M 2\n            ... ''').solve_flow_measurements([\n            ...     stim.Flow(\"X2 -> X2\"),\n            ... ])\n            [None]\n\n            >>> stim.Circuit('''\n            ...     MXX 0 1\n            ... ''').solve_flow_measurements([\n            ...     stim.Flow(\"YY -> ZZ\"),\n            ... ])\n            [[0]]\n\n            >>> # Rep code cycle\n            >>> stim.Circuit('''\n            ...     R 1 3\n            ...     CX 0 1 2 3\n            ...     CX 4 3 2 1\n            ...     M 1 3\n            ... ''').solve_flow_measurements([\n            ...     stim.Flow(\"1 -> Z0*Z4\"),\n            ...     stim.Flow(\"Z0 -> Z2\"),\n            ...     stim.Flow(\"X0*X2*X4 -> X0*X2*X4\"),\n            ...     stim.Flow(\"Y0 -> Y0\"),\n            ... ])\n            [[0, 1], [0], [], None]\n        \"\"\"\n    def time_reversed_for_flows(\n        self,\n        flows: Iterable[stim.Flow],\n        *,\n        dont_turn_measurements_into_resets: bool = False,\n    ) -> Tuple[stim.Circuit, List[stim.Flow]]:\n        \"\"\"Time-reverses the circuit while preserving error correction structure.\n\n        This method returns a circuit that has the same internal detecting regions\n        as the given circuit, as well as the same internal-to-external flows given\n        in the `flows` argument, except they are all time-reversed. For example, if\n        you pass a fault tolerant preparation circuit into this method (1 -> Z), the\n        result will be a fault tolerant *measurement* circuit (Z -> 1). Or, if you\n        pass a fault tolerant C_XYZ circuit into this method (X->Y, Y->Z, and Z->X),\n        the result will be a fault tolerant C_ZYX circuit (X->Z, Y->X, and Z->Y).\n\n        Note that this method doesn't guarantee that it will preserve the *sign* of the\n        detecting regions or stabilizer flows. For example, inverting a memory circuit\n        that preserves a logical observable (X->X and Z->Z) may produce a\n        memory circuit that always bit flips the logical observable (X->X and Z->-Z) or\n        that dynamically adjusts the logical observable in response to measurements\n        (like \"X -> X xor rec[-1]\" and \"Z -> Z xor rec[-2]\").\n\n        This method will turn time-reversed resets into measurements, and attempts to\n        turn time-reversed measurements into resets. A measurement will time-reverse\n        into a reset if some annotated detectors, annotated observables, or given flows\n        have detecting regions with sensitivity just before the measurement but none\n        have detecting regions with sensitivity after the measurement.\n\n        In some cases this method will have to introduce new operations. In particular,\n        when a measurement-reset operation has a noisy result, time-reversing this\n        measurement noise produces reset noise. But the measure-reset operations don't\n        have built-in reset noise, so the reset noise is specified by adding an X_ERROR\n        or Z_ERROR noise instruction after the time-reversed measure-reset operation.\n\n        Args:\n            flows: Flows you care about, that reach past the start/end of the given\n                circuit. The result will contain an inverted flow for each of these\n                given flows. You need this information because it reveals the\n                measurements needed to produce the inverted flows that you care\n                about.\n\n                An exception will be raised if the circuit doesn't have all these\n                flows. The inverted circuit will have the inverses of these flows\n                (ignoring sign).\n            dont_turn_measurements_into_resets: Defaults to False. When set to\n                True, measurements will time-reverse into measurements even if\n                nothing is sensitive to the measured qubit after the measurement\n                completes. This guarantees the output circuit has *all* flows\n                that the input circuit has (up to sign and feedback), even ones\n                that aren't annotated.\n\n        Returns:\n            An (inverted_circuit, inverted_flows) tuple.\n\n            inverted_circuit is the qec inverse of the given circuit.\n\n            inverted_flows is a list of flows, matching up by index with the flows\n            given as arguments to the method. The input, output, and sign fields\n            of these flows are boring. The useful field is measurement_indices,\n            because it's difficult to predict which measurements are needed for\n            the inverted flow due to effects such as implicitly-included resets\n            inverting into explicitly-included measurements.\n\n        Caveats:\n            Currently, this method doesn't compute the sign of the inverted flows.\n            It unconditionally sets the sign to False.\n\n        Examples:\n            >>> import stim\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     R 0\n            ...     H 0\n            ...     S 0\n            ...     MY 0\n            ...     DETECTOR rec[-1]\n            ... ''').time_reversed_for_flows([])\n            >>> inv_circuit\n            stim.Circuit('''\n                RY 0\n                S_DAG 0\n                H 0\n                M 0\n                DETECTOR rec[-1]\n            ''')\n            >>> inv_flows\n            []\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     M 0\n            ... ''').time_reversed_for_flows([\n            ...     stim.Flow(\"Z -> rec[-1]\"),\n            ... ])\n            >>> inv_circuit\n            stim.Circuit('''\n                R 0\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"1 -> Z\")]\n            >>> inv_circuit.has_all_flows(inv_flows, unsigned=True)\n            True\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     R 0\n            ... ''').time_reversed_for_flows([\n            ...     stim.Flow(\"1 -> Z\"),\n            ... ])\n            >>> inv_circuit\n            stim.Circuit('''\n                M 0\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"Z -> rec[-1]\")]\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     M 0\n            ... ''').time_reversed_for_flows([\n            ...     stim.Flow(\"1 -> Z xor rec[-1]\"),\n            ... ])\n            >>> inv_circuit\n            stim.Circuit('''\n                M 0\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"Z -> rec[-1]\")]\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     M 0\n            ... ''').time_reversed_for_flows(\n            ...     flows=[stim.Flow(\"Z -> rec[-1]\")],\n            ...     dont_turn_measurements_into_resets=True,\n            ... )\n            >>> inv_circuit\n            stim.Circuit('''\n                M 0\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"1 -> Z xor rec[-1]\")]\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     MR(0.125) 0\n            ... ''').time_reversed_for_flows([])\n            >>> inv_circuit\n            stim.Circuit('''\n                MR 0\n                X_ERROR(0.125) 0\n            ''')\n            >>> inv_flows\n            []\n\n            >>> inv_circuit, inv_flows = stim.Circuit('''\n            ...     MXX 0 1\n            ...     H 0\n            ... ''').time_reversed_for_flows([\n            ...     stim.Flow(\"ZZ -> YY xor rec[-1]\"),\n            ...     stim.Flow(\"ZZ -> XZ\"),\n            ... ])\n            >>> inv_circuit\n            stim.Circuit('''\n                H 0\n                MXX 0 1\n            ''')\n            >>> inv_flows\n            [stim.Flow(\"YY -> ZZ xor rec[-1]\"), stim.Flow(\"XZ -> ZZ\")]\n\n            >>> stim.Circuit.generated(\n            ...     \"surface_code:rotated_memory_x\",\n            ...     distance=2,\n            ...     rounds=1,\n            ... ).time_reversed_for_flows([])[0]\n            stim.Circuit('''\n                QUBIT_COORDS(1, 1) 1\n                QUBIT_COORDS(2, 0) 2\n                QUBIT_COORDS(3, 1) 3\n                QUBIT_COORDS(1, 3) 6\n                QUBIT_COORDS(2, 2) 7\n                QUBIT_COORDS(3, 3) 8\n                QUBIT_COORDS(2, 4) 12\n                RX 8 6 3 1\n                MR 12 7 2\n                TICK\n                H 12 2\n                TICK\n                CX 1 7 12 6\n                TICK\n                CX 6 7 12 8\n                TICK\n                CX 3 7 2 1\n                TICK\n                CX 8 7 2 3\n                TICK\n                H 12 2\n                TICK\n                M 12 7 2\n                DETECTOR(2, 0, 1) rec[-1]\n                DETECTOR(2, 4, 1) rec[-3]\n                MX 8 6 3 1\n                DETECTOR(2, 0, 0) rec[-5] rec[-2] rec[-1]\n                DETECTOR(2, 4, 0) rec[-7] rec[-4] rec[-3]\n                OBSERVABLE_INCLUDE(0) rec[-3] rec[-1]\n            ''')\n        \"\"\"\n    def to_crumble_url(\n        self,\n        *,\n        skip_detectors: bool = False,\n        mark: Optional[Dict[int, List[stim.ExplainedError]]] = None,\n    ) -> str:\n        \"\"\"Returns a URL that opens up crumble and loads this circuit into it.\n\n        Crumble is a tool for editing stabilizer circuits, and visualizing their\n        stabilizer flows. Its source code is in the `glue/crumble` directory of\n        the stim code repository on github. A prebuilt version is made available\n        at https://algassert.com/crumble, which is what the URL returned by this\n        method will point to.\n\n        Args:\n            skip_detectors: Defaults to False. If set to True, detectors from the\n                circuit aren't included in the crumble URL. This can reduce visual\n                clutter in crumble, and improve its performance, since it doesn't\n                need to indicate or track the sensitivity regions of detectors.\n            mark: Defaults to None (no marks). If set to a dictionary from int to\n                errors, such as `mark={1: circuit.shortest_graphlike_error()}`,\n                then the errors will be highlighted and tracked forward by crumble.\n\n        Returns:\n            A URL that can be opened in a web browser.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ...     S 1\n            ... ''').to_crumble_url()\n            'https://algassert.com/crumble#circuit=H_0;CX_0_1;S_1_'\n\n            >>> circuit = stim.Circuit('''\n            ...     M(0.25) 0 1 2\n            ...     DETECTOR rec[-1] rec[-2]\n            ...     DETECTOR rec[-2] rec[-3]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''')\n            >>> err = circuit.shortest_graphlike_error(canonicalize_circuit_errors=True)\n            >>> circuit.to_crumble_url(skip_detectors=True, mark={1: err})\n            'https://algassert.com/crumble#circuit=;TICK;MARKX(1)1;MARKX(1)2;MARKX(1)0;TICK;M(0.25)0_1_2;OI(0)rec[-1]_'\n        \"\"\"\n    def to_file(\n        self,\n        file: Union[io.TextIOBase, str, pathlib.Path],\n    ) -> None:\n        \"\"\"Writes the stim circuit to a file.\n\n        The file format is defined at\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n        Args:\n            file: A file path or an open file to write to.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> c = stim.Circuit('H 5\\nX 0')\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         c.to_file(f)\n            ...     with open(path) as f:\n            ...         contents = f.read()\n            >>> contents\n            'H 5\\nX 0\\n'\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     c.to_file(path)\n            ...     with open(path) as f:\n            ...         contents = f.read()\n            >>> contents\n            'H 5\\nX 0\\n'\n        \"\"\"\n    def to_qasm(\n        self,\n        *,\n        open_qasm_version: int,\n        skip_dets_and_obs: bool = False,\n    ) -> str:\n        \"\"\"Creates an equivalent OpenQASM implementation of the circuit.\n\n        Args:\n            open_qasm_version: The version of OpenQASM to target.\n                This should be set to 2 or to 3.\n\n                Differences between the versions are:\n                    - Support for operations on classical bits (only version 3).\n                        This means DETECTOR and OBSERVABLE_INCLUDE only work with\n                        version 3.\n                    - Support for feedback operations (only version 3).\n                    - Support for subroutines (only version 3). Without subroutines,\n                        non-standard dissipative gates like MR and RX need to decompose\n                        inline every single time they're used.\n                    - Minor name changes (e.g. creg -> bit, qelib1.inc -> stdgates.inc).\n            skip_dets_and_obs: Defaults to False. When set to False, the output will\n                include a `dets` register and an `obs` register (assuming the circuit\n                has detectors and observables). These registers will be computed as part\n                of running the circuit. This requires performing a simulation of the\n                circuit, in order to correctly account for the expected value of\n                measurements.\n\n                When set to True, the `dets` and `obs` registers are not included in the\n                output, and no simulation of the circuit is performed.\n\n        Returns:\n            The OpenQASM code as a string.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     R 0 1\n            ...     X 1\n            ...     H 0\n            ...     CX 0 1\n            ...     M 0 1\n            ...     DETECTOR rec[-1] rec[-2]\n            ... ''');\n            >>> qasm = circuit.to_qasm(open_qasm_version=3);\n            >>> print(qasm.strip().replace('\\n\\n', '\\n'))\n            OPENQASM 3.0;\n            include \"stdgates.inc\";\n            qreg q[2];\n            creg rec[2];\n            creg dets[1];\n            reset q[0];\n            reset q[1];\n            x q[1];\n            h q[0];\n            cx q[0], q[1];\n            measure q[0] -> rec[0];\n            measure q[1] -> rec[1];\n            dets[0] = rec[1] ^ rec[0] ^ 1;\n        \"\"\"\n    def to_quirk_url(\n        self,\n    ) -> str:\n        \"\"\"Returns a URL that opens up quirk and loads this circuit into it.\n\n        Quirk is an open source drag and drop circuit editor with support for up to 16\n        qubits. Its source code is available at https://github.com/strilanc/quirk\n        and a prebuilt version is available at https://algassert.com/quirk, which is\n        what the URL returned by this method will point to.\n\n        Quirk doesn't support features like noise, feedback, or detectors. This method\n        will simply drop any unsupported operations from the circuit when producing\n        the URL.\n\n        Returns:\n            A URL that can be opened in a web browser.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ...     S 1\n            ... ''').to_quirk_url()\n            'https://algassert.com/quirk#circuit={\"cols\":[[\"H\"],[\"•\",\"X\"],[1,\"Z^½\"]]}'\n        \"\"\"\n    def to_tableau(\n        self,\n        *,\n        ignore_noise: bool = False,\n        ignore_measurement: bool = False,\n        ignore_reset: bool = False,\n    ) -> stim.Tableau:\n        \"\"\"Converts the circuit into an equivalent stabilizer tableau.\n\n        Args:\n            ignore_noise: Defaults to False. When False, any noise operations in the\n                circuit will cause the conversion to fail with an exception. When True,\n                noise operations are skipped over as if they weren't even present in the\n                circuit.\n            ignore_measurement: Defaults to False. When False, any measurement\n                operations in the circuit will cause the conversion to fail with an\n                exception. When True, measurement operations are skipped over as if they\n                weren't even present in the circuit.\n            ignore_reset: Defaults to False. When False, any reset operations in the\n                circuit will cause the conversion to fail with an exception. When True,\n                reset operations are skipped over as if they weren't even present in the\n                circuit.\n\n        Returns:\n            A tableau equivalent to the circuit (up to global phase).\n\n        Raises:\n            ValueError:\n                The circuit contains noise operations but ignore_noise=False.\n                OR\n                The circuit contains measurement operations but\n                ignore_measurement=False.\n                OR\n                The circuit contains reset operations but ignore_reset=False.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ... ''').to_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n        \"\"\"\n    def with_inlined_feedback(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a circuit without feedback with rewritten detectors/observables.\n\n        When a feedback operation affects the expected parity of a detector or\n        observable, the measurement controlling that feedback operation is implicitly\n        part of the measurement set that defines the detector or observable. This\n        method removes all feedback, but avoids changing the meaning of detectors or\n        observables by turning these implicit measurement dependencies into explicit\n        measurement dependencies added to the observable or detector.\n\n        This method guarantees that the detector error model derived from the original\n        circuit, and the transformed circuit, will be equivalent (modulo floating point\n        rounding errors and variations in where loops are placed). Specifically, the\n        following should be true for any circuit:\n\n            dem1 = circuit.flattened().detector_error_model()\n            dem2 = circuit.with_inlined_feedback().flattened().detector_error_model()\n            assert dem1.approx_equals(dem2, 1e-5)\n\n        Returns:\n            A `stim.Circuit` with feedback operations removed, with rewritten DETECTOR\n            instructions (as needed to avoid changing the meaning of each detector), and\n            with additional OBSERVABLE_INCLUDE instructions (as needed to avoid changing\n            the meaning of each observable).\n\n            The circuit's function is permitted to differ from the original in that\n            any feedback operation can be pushed to the end of the circuit and\n            discarded. All non-feedback operations must stay where they are, preserving\n            the structure of the circuit.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     CX 0 1        # copy to measure qubit\n            ...     M 1           # measure first time\n            ...     CX rec[-1] 1  # use feedback to reset measurement qubit\n            ...     CX 0 1        # copy to measure qubit\n            ...     M 1           # measure second time\n            ...     DETECTOR rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').with_inlined_feedback()\n            stim.Circuit('''\n                CX 0 1\n                M 1\n                OBSERVABLE_INCLUDE(0) rec[-1]\n                CX 0 1\n                M 1\n                DETECTOR rec[-1]\n                OBSERVABLE_INCLUDE(0) rec[-1]\n            ''')\n        \"\"\"\n    def without_noise(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a copy of the circuit with all noise processes removed.\n\n        Pure noise instructions, such as X_ERROR and DEPOLARIZE2, are not\n        included in the result.\n\n        Noisy measurement instructions, like `M(0.001)`, have their noise\n        parameter removed.\n\n        Returns:\n            A `stim.Circuit` with the same instructions except all noise\n            processes have been removed.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     X_ERROR(0.25) 0\n            ...     CNOT 0 1\n            ...     M(0.125) 0\n            ... ''').without_noise()\n            stim.Circuit('''\n                CX 0 1\n                M 0\n            ''')\n        \"\"\"\n    def without_tags(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a copy of the circuit with all tags removed.\n\n        Returns:\n            A `stim.Circuit` with the same instructions except all tags have been\n            removed.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit('''\n            ...     X[test-tag] 0\n            ...     M[test-tag-2](0.125) 0\n            ... ''').without_tags()\n            stim.Circuit('''\n                X 0\n                M(0.125) 0\n            ''')\n        \"\"\"\nclass CircuitErrorLocation:\n    \"\"\"Describes the location of an error mechanism from a stim circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit.generated(\n        ...     \"repetition_code:memory\",\n        ...     distance=5,\n        ...     rounds=5,\n        ...     before_round_data_depolarization=1e-3,\n        ... )\n        >>> logical_error = circuit.shortest_graphlike_error()\n        >>> error_location = logical_error[0].circuit_error_locations[0]\n        >>> print(error_location)\n        CircuitErrorLocation {\n            flipped_pauli_product: X0\n            Circuit location stack trace:\n                (after 1 TICKs)\n                at instruction #3 (DEPOLARIZE1) in the circuit\n                at target #1 of the instruction\n                resolving to DEPOLARIZE1(0.001) 0\n        }\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        tick_offset: int,\n        flipped_pauli_product: List[stim.GateTargetWithCoords],\n        flipped_measurement: object,\n        instruction_targets: stim.CircuitTargetsInsideInstruction,\n        stack_frames: List[stim.CircuitErrorLocationStackFrame],\n        noise_tag: str = '',\n    ) -> None:\n        \"\"\"Creates a stim.CircuitErrorLocation.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.CircuitErrorLocation(\n            ...     tick_offset=1,\n            ...     flipped_pauli_product=(\n            ...         stim.GateTargetWithCoords(\n            ...             gate_target=stim.target_x(0),\n            ...             coords=[],\n            ...         ),\n            ...     ),\n            ...     flipped_measurement=stim.FlippedMeasurement(\n            ...         record_index=None,\n            ...         observable=(),\n            ...     ),\n            ...     instruction_targets=stim.CircuitTargetsInsideInstruction(\n            ...         gate='DEPOLARIZE1',\n            ...         args=[0.001],\n            ...         target_range_start=0,\n            ...         target_range_end=1,\n            ...         targets_in_range=(stim.GateTargetWithCoords(\n            ...             gate_target=0,\n            ...             coords=[],\n            ...         ),)\n            ...     ),\n            ...     stack_frames=(\n            ...         stim.CircuitErrorLocationStackFrame(\n            ...             instruction_offset=2,\n            ...             iteration_index=0,\n            ...             instruction_repetitions_arg=0,\n            ...         ),\n            ...     ),\n            ...     noise_tag='test-tag',\n            ... )\n            >>> print(err)\n            CircuitErrorLocation {\n                noise_tag: test-tag\n                flipped_pauli_product: X0\n                Circuit location stack trace:\n                    (after 1 TICKs)\n                    at instruction #3 (DEPOLARIZE1) in the circuit\n                    at target #1 of the instruction\n                    resolving to DEPOLARIZE1(0.001) 0\n            }\n        \"\"\"\n    @property\n    def flipped_measurement(\n        self,\n    ) -> Optional[stim.FlippedMeasurement]:\n        \"\"\"The measurement that was flipped by the error mechanism.\n\n        If the error isn't a measurement error, this will be None.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     M(0.125) 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].flipped_measurement\n            stim.FlippedMeasurement(\n                record_index=0,\n                observable=(stim.GateTargetWithCoords(stim.target_z(0), []),),\n            )\n        \"\"\"\n    @property\n    def flipped_pauli_product(\n        self,\n    ) -> List[stim.GateTargetWithCoords]:\n        \"\"\"The Pauli errors that the error mechanism applied to qubits.\n\n        When the error is a measurement error, this will be an empty list.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].flipped_pauli_product\n            [stim.GateTargetWithCoords(stim.target_y(0), [])]\n        \"\"\"\n    @property\n    def instruction_targets(\n        self,\n    ) -> stim.CircuitTargetsInsideInstruction:\n        \"\"\"Within the error instruction, which may have hundreds of\n        targets, which specific targets were being executed to\n        produce the error.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> targets = err[0].circuit_error_locations[0].instruction_targets\n            >>> targets == stim.CircuitTargetsInsideInstruction(\n            ...     gate='Y_ERROR',\n            ...     args=[0.125],\n            ...     target_range_start=0,\n            ...     target_range_end=1,\n            ...     targets_in_range=(stim.GateTargetWithCoords(0, []),),\n            ... )\n            True\n        \"\"\"\n    @property\n    def noise_tag(\n        self,\n    ) -> str:\n        \"\"\"The tag on the noise instruction that caused the error.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     Y_ERROR[test-tag](0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].noise_tag\n            'test-tag'\n        \"\"\"\n    @property\n    def stack_frames(\n        self,\n    ) -> List[stim.CircuitErrorLocationStackFrame]:\n        \"\"\"Describes where in the circuit's execution the error happened.\n\n        Multiple frames are needed because the error may occur within a loop,\n        or a loop nested inside a loop, or etc.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].stack_frames\n            [stim.CircuitErrorLocationStackFrame(\n                instruction_offset=2,\n                iteration_index=0,\n                instruction_repetitions_arg=0,\n            )]\n        \"\"\"\n    @property\n    def tick_offset(\n        self,\n    ) -> int:\n        \"\"\"The number of TICKs that executed before the error happened.\n\n        This counts TICKs occurring multiple times during loops.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     TICK\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].tick_offset\n            3\n        \"\"\"\nclass CircuitErrorLocationStackFrame:\n    \"\"\"Describes the location of an instruction being executed within a\n    circuit or loop, distinguishing between separate loop iterations.\n\n    The full location of an instruction is a list of these frames,\n    drilling down from the top level circuit to the inner-most loop\n    that the instruction is within.\n\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     REPEAT 5 {\n        ...         R 0\n        ...         Y_ERROR(0.125) 0\n        ...         M 0\n        ...     }\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].stack_frames[0]\n        stim.CircuitErrorLocationStackFrame(\n            instruction_offset=0,\n            iteration_index=0,\n            instruction_repetitions_arg=5,\n        )\n        >>> err[0].circuit_error_locations[0].stack_frames[1]\n        stim.CircuitErrorLocationStackFrame(\n            instruction_offset=1,\n            iteration_index=4,\n            instruction_repetitions_arg=0,\n        )\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        instruction_offset: int,\n        iteration_index: int,\n        instruction_repetitions_arg: int,\n    ) -> None:\n        \"\"\"Creates a stim.CircuitErrorLocationStackFrame.\n\n        Examples:\n            >>> import stim\n            >>> frame = stim.CircuitErrorLocationStackFrame(\n            ...     instruction_offset=1,\n            ...     iteration_index=2,\n            ...     instruction_repetitions_arg=3,\n            ... )\n        \"\"\"\n    @property\n    def instruction_offset(\n        self,\n    ) -> int:\n        \"\"\"The index of the instruction within the circuit, or within the\n        instruction's parent REPEAT block. This is slightly different\n        from the line number, because blank lines and commented lines\n        don't count and also because the offset of the first instruction\n        is 0 instead of 1.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].stack_frames[0].instruction_offset\n            2\n        \"\"\"\n    @property\n    def instruction_repetitions_arg(\n        self,\n    ) -> int:\n        \"\"\"If the instruction being referred to is a REPEAT block,\n        this is the repetition count of that REPEAT block. Otherwise\n        this field defaults to 0.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     REPEAT 5 {\n            ...         R 0\n            ...         Y_ERROR(0.125) 0\n            ...         M 0\n            ...     }\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> full = err[0].circuit_error_locations[0].stack_frames[0]\n            >>> loop = err[0].circuit_error_locations[0].stack_frames[1]\n            >>> full.instruction_repetitions_arg\n            5\n            >>> loop.instruction_repetitions_arg\n            0\n        \"\"\"\n    @property\n    def iteration_index(\n        self,\n    ) -> int:\n        \"\"\"Disambiguates which iteration of the loop containing this instruction\n        is being referred to. If the instruction isn't in a REPEAT block, this\n        field defaults to 0.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     REPEAT 5 {\n            ...         R 0\n            ...         Y_ERROR(0.125) 0\n            ...         M 0\n            ...     }\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> full = err[0].circuit_error_locations[0].stack_frames[0]\n            >>> loop = err[0].circuit_error_locations[0].stack_frames[1]\n            >>> full.iteration_index\n            0\n            >>> loop.iteration_index\n            4\n        \"\"\"\nclass CircuitInstruction:\n    \"\"\"An instruction, like `H 0 1` or `CNOT rec[-1] 5`, from a circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     M 0 1\n        ...     X_ERROR(0.125) 5\n        ... ''')\n        >>> circuit[0]\n        stim.CircuitInstruction('H', [stim.GateTarget(0)], [])\n        >>> circuit[1]\n        stim.CircuitInstruction('M', [stim.GateTarget(0), stim.GateTarget(1)], [])\n        >>> circuit[2]\n        stim.CircuitInstruction('X_ERROR', [stim.GateTarget(5)], [0.125])\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.CircuitInstruction,\n    ) -> bool:\n        \"\"\"Determines if two `stim.CircuitInstruction`s are identical.\n        \"\"\"\n    def __init__(\n        self,\n        name: str,\n        targets: Optional[Iterable[Union[int, stim.GateTarget]]] = None,\n        gate_args: Optional[Iterable[float]] = None,\n        *,\n        tag: str = \"\",\n    ) -> None:\n        \"\"\"Creates or parses a `stim.CircuitInstruction`.\n\n        Args:\n            name: The name of the instruction being applied.\n                If `targets` and `gate_args` aren't specified, this can be a full\n                instruction line from a stim Circuit file, like \"CX 0 1\".\n            targets: The targets the instruction is being applied to. These can be raw\n                values like `0` and `stim.target_rec(-1)`, or instances of\n                `stim.GateTarget`.\n            gate_args: The sequence of numeric arguments parameterizing a gate. For\n                noise gates this is their probabilities. For `OBSERVABLE_INCLUDE`\n                instructions it's the index of the logical observable to affect.\n            tag: Defaults to \"\". A custom string attached to the instruction. For\n                example, for a TICK instruction, this could a string specifying an\n                amount of time which is used by custom code for adding noise to a\n                circuit. In general, stim will attempt to propagate tags across circuit\n                transformations but will otherwise completely ignore them.\n\n        Examples:\n            >>> import stim\n\n            >>> print(stim.CircuitInstruction('DEPOLARIZE1', [5], [0.25]))\n            DEPOLARIZE1(0.25) 5\n\n            >>> stim.CircuitInstruction('CX rec[-1] 5  # comment')\n            stim.CircuitInstruction('CX', [stim.target_rec(-1), stim.GateTarget(5)], [])\n\n            >>> print(stim.CircuitInstruction('I', [2], tag='100ns'))\n            I[100ns] 2\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.CircuitInstruction,\n    ) -> bool:\n        \"\"\"Determines if two `stim.CircuitInstruction`s are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CircuitInstruction`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a text description of the instruction as a stim circuit file line.\n        \"\"\"\n    def gate_args_copy(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns the gate's arguments (numbers parameterizing the instruction).\n\n        For noisy gates this typically a list of probabilities.\n        For OBSERVABLE_INCLUDE it's a singleton list containing the logical observable\n        index.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.CircuitInstruction('X_ERROR', [2, 3], [0.125])\n            >>> instruction.gate_args_copy()\n            [0.125]\n\n            >>> instruction.gate_args_copy() == instruction.gate_args_copy()\n            True\n            >>> instruction.gate_args_copy() is instruction.gate_args_copy()\n            False\n        \"\"\"\n    @property\n    def name(\n        self,\n    ) -> str:\n        \"\"\"The name of the instruction (e.g. `H` or `X_ERROR` or `DETECTOR`).\n        \"\"\"\n    @property\n    def num_measurements(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of bits produced when running this instruction.\n\n        Examples:\n            >>> import stim\n            >>> stim.CircuitInstruction('H', [0]).num_measurements\n            0\n            >>> stim.CircuitInstruction('M', [0]).num_measurements\n            1\n            >>> stim.CircuitInstruction('M', [2, 3, 5, 7, 11]).num_measurements\n            5\n            >>> stim.CircuitInstruction('MXX', [0, 1, 4, 5, 11, 13]).num_measurements\n            3\n            >>> stim.Circuit('MPP X0*X1 X0*Z1*Y2')[0].num_measurements\n            2\n            >>> stim.CircuitInstruction('HERALDED_ERASE', [0], [0.25]).num_measurements\n            1\n        \"\"\"\n    @property\n    def tag(\n        self,\n    ) -> str:\n        \"\"\"The custom tag attached to the instruction.\n\n        The tag is an arbitrary string.\n        The default tag, when none is specified, is the empty string.\n\n        Examples:\n            >>> import stim\n            >>> stim.Circuit(\"H[test] 0\")[0].tag\n            'test'\n            >>> stim.Circuit(\"H 0\")[0].tag\n            ''\n        \"\"\"\n    def target_groups(\n        self,\n    ) -> List[List[stim.GateTarget]]:\n        \"\"\"Splits the instruction's targets into groups depending on the type of gate.\n\n        Single qubit gates like H get one group per target.\n        Two qubit gates like CX get one group per pair of targets.\n        Pauli product gates like MPP get one group per combined product.\n\n        Returns:\n            A list of groups of targets.\n\n        Examples:\n            >>> import stim\n            >>> for g in stim.Circuit('H 0 1 2')[0].target_groups():\n            ...     print(repr(g))\n            [stim.GateTarget(0)]\n            [stim.GateTarget(1)]\n            [stim.GateTarget(2)]\n\n            >>> for g in stim.Circuit('CX 0 1 2 3')[0].target_groups():\n            ...     print(repr(g))\n            [stim.GateTarget(0), stim.GateTarget(1)]\n            [stim.GateTarget(2), stim.GateTarget(3)]\n\n            >>> for g in stim.Circuit('MPP X0*Y1*Z2 X5*X6')[0].target_groups():\n            ...     print(repr(g))\n            [stim.target_x(0), stim.target_y(1), stim.target_z(2)]\n            [stim.target_x(5), stim.target_x(6)]\n\n            >>> for g in stim.Circuit('DETECTOR rec[-1] rec[-2]')[0].target_groups():\n            ...     print(repr(g))\n            [stim.target_rec(-1)]\n            [stim.target_rec(-2)]\n\n            >>> for g in stim.Circuit('CORRELATED_ERROR(0.1) X0 Y1')[0].target_groups():\n            ...     print(repr(g))\n            [stim.target_x(0), stim.target_y(1)]\n        \"\"\"\n    def targets_copy(\n        self,\n    ) -> List[stim.GateTarget]:\n        \"\"\"Returns a copy of the targets of the instruction.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.CircuitInstruction('X_ERROR', [2, 3], [0.125])\n            >>> instruction.targets_copy()\n            [stim.GateTarget(2), stim.GateTarget(3)]\n\n            >>> instruction.targets_copy() == instruction.targets_copy()\n            True\n            >>> instruction.targets_copy() is instruction.targets_copy()\n            False\n        \"\"\"\nclass CircuitRepeatBlock:\n    \"\"\"A REPEAT block from a circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     H 0\n        ...     REPEAT 5 {\n        ...         CX 0 1\n        ...         CZ 1 2\n        ...     }\n        ... ''')\n        >>> repeat_block = circuit[1]\n        >>> repeat_block.repeat_count\n        5\n        >>> repeat_block.body_copy()\n        stim.Circuit('''\n            CX 0 1\n            CZ 1 2\n        ''')\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.CircuitRepeatBlock,\n    ) -> bool:\n        \"\"\"Determines if two `stim.CircuitRepeatBlock`s are identical.\n        \"\"\"\n    def __init__(\n        self,\n        repeat_count: int,\n        body: stim.Circuit,\n        *,\n        tag: str = '',\n    ) -> None:\n        \"\"\"Initializes a `stim.CircuitRepeatBlock`.\n\n        Args:\n            repeat_count: The number of times to repeat the block.\n            body: The body of the block, as a circuit.\n            tag: Defaults to empty. A custom string attached to the REPEAT instruction.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit()\n            >>> c.append(stim.CircuitRepeatBlock(100, stim.Circuit(\"M 0\")))\n            >>> c\n            stim.Circuit('''\n                REPEAT 100 {\n                    M 0\n                }\n            ''')\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.CircuitRepeatBlock,\n    ) -> bool:\n        \"\"\"Determines if two `stim.CircuitRepeatBlock`s are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.CircuitRepeatBlock`.\n        \"\"\"\n    def body_copy(\n        self,\n    ) -> stim.Circuit:\n        \"\"\"Returns a copy of the body of the repeat block.\n\n        (Making a copy is enforced to make it clear that editing the result won't change\n        the block's body.)\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     REPEAT 5 {\n            ...         CX 0 1\n            ...         CZ 1 2\n            ...     }\n            ... ''')\n            >>> repeat_block = circuit[1]\n            >>> repeat_block.body_copy()\n            stim.Circuit('''\n                CX 0 1\n                CZ 1 2\n            ''')\n        \"\"\"\n    @property\n    def name(\n        self,\n    ) -> str:\n        \"\"\"Returns the name \"REPEAT\".\n\n        This is a duck-typing convenience method. It exists so that code that doesn't\n        know whether it has a `stim.CircuitInstruction` or a `stim.CircuitRepeatBlock`\n        can check the object's name without having to do an `instanceof` check first.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     REPEAT 5 {\n            ...         CX 1 2\n            ...     }\n            ...     S 1\n            ... ''')\n            >>> [instruction.name for instruction in circuit]\n            ['H', 'REPEAT', 'S']\n        \"\"\"\n    @property\n    def num_measurements(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of bits produced when running this loop.\n\n        Examples:\n            >>> import stim\n            >>> stim.CircuitRepeatBlock(\n            ...     body=stim.Circuit(\"M 0 1\"),\n            ...     repeat_count=25,\n            ... ).num_measurements\n            50\n        \"\"\"\n    @property\n    def repeat_count(\n        self,\n    ) -> int:\n        \"\"\"The repetition count of the repeat block.\n\n        Examples:\n            >>> import stim\n            >>> circuit = stim.Circuit('''\n            ...     H 0\n            ...     REPEAT 5 {\n            ...         CX 0 1\n            ...         CZ 1 2\n            ...     }\n            ... ''')\n            >>> repeat_block = circuit[1]\n            >>> repeat_block.repeat_count\n            5\n        \"\"\"\n    @property\n    def tag(\n        self,\n    ) -> str:\n        \"\"\"The custom tag attached to the REPEAT instruction.\n\n        The tag is an arbitrary string.\n        The default tag, when none is specified, is the empty string.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     REPEAT[test] 5 {\n            ...         H 0\n            ...     }\n            ... ''')[0].tag\n            'test'\n\n            >>> stim.Circuit('''\n            ...     REPEAT 5 {\n            ...         H 0\n            ...     }\n            ... ''')[0].tag\n            ''\n        \"\"\"\nclass CircuitTargetsInsideInstruction:\n    \"\"\"Describes a range of targets within a circuit instruction.\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        gate: str,\n        tag: str = '',\n        args: List[float],\n        target_range_start: int,\n        target_range_end: int,\n        targets_in_range: List[stim.GateTargetWithCoords],\n    ) -> None:\n        \"\"\"Creates a stim.CircuitTargetsInsideInstruction.\n\n        Examples:\n            >>> import stim\n            >>> val = stim.CircuitTargetsInsideInstruction(\n            ...     gate='X_ERROR',\n            ...     tag='',\n            ...     args=[0.25],\n            ...     target_range_start=0,\n            ...     target_range_end=1,\n            ...     targets_in_range=[stim.GateTargetWithCoords(0, [])],\n            ... )\n        \"\"\"\n    @property\n    def args(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns parens arguments of the gate / instruction that was being executed.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.args\n            [0.25]\n        \"\"\"\n    @property\n    def gate(\n        self,\n    ) -> Optional[str]:\n        \"\"\"Returns the name of the gate / instruction that was being executed.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.gate\n            'X_ERROR'\n        \"\"\"\n    @property\n    def tag(\n        self,\n    ) -> str:\n        \"\"\"Returns the tag of the gate / instruction that was being executed.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR[look-at-me-imma-tag](0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.tag\n            'look-at-me-imma-tag'\n        \"\"\"\n    @property\n    def target_range_end(\n        self,\n    ) -> int:\n        \"\"\"Returns the exclusive end of the range of targets that were executing\n        within the gate / instruction.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.target_range_start\n            0\n            >>> loc.instruction_targets.target_range_end\n            1\n        \"\"\"\n    @property\n    def target_range_start(\n        self,\n    ) -> int:\n        \"\"\"Returns the inclusive start of the range of targets that were executing\n        within the gate / instruction.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.target_range_start\n            0\n            >>> loc.instruction_targets.target_range_end\n            1\n        \"\"\"\n    @property\n    def targets_in_range(\n        self,\n    ) -> List[stim.GateTargetWithCoords]:\n        \"\"\"Returns the subset of targets of the gate/instruction that were being executed.\n\n        Includes coordinate data with the targets.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n            >>> loc.instruction_targets.targets_in_range\n            [stim.GateTargetWithCoords(0, [])]\n        \"\"\"\nclass CliffordString:\n    \"\"\"A tensor product of single qubit Clifford gates (e.g. \"H \\u2297 X \\u2297 S\").\n\n    Represents a collection of Clifford operations applied pairwise to a\n    collection of qubits. Ignores global phase.\n\n    Examples:\n        >>> import stim\n        >>> stim.CliffordString(\"H,S,C_XYZ\") * stim.CliffordString(\"H,H,H\")\n        stim.CliffordString(\"I,C_ZYX,SQRT_X_DAG\")\n    \"\"\"\n    def __add__(\n        self,\n        rhs: stim.CliffordString,\n    ) -> stim.CliffordString:\n        \"\"\"Concatenates two CliffordStrings.\n\n        Args:\n            rhs: The suffix of the concatenation.\n\n        Returns:\n            The concatenated Clifford string.\n\n        Examples:\n            >>> import stim\n            >>> stim.CliffordString(\"I,X,H\") + stim.CliffordString(\"Y,S\")\n            stim.CliffordString(\"I,X,H,Y,S\")\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.CliffordString,\n    ) -> bool:\n        \"\"\"Determines if two Clifford strings have identical contents.\n        \"\"\"\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: int,\n    ) -> stim.GateData:\n        pass\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: slice,\n    ) -> stim.CliffordString:\n        pass\n    def __getitem__(\n        self,\n        index_or_slice: Union[int, slice],\n    ) -> Union[stim.GateData, stim.CliffordString]:\n        \"\"\"Returns a Clifford or substring from the CliffordString.\n\n        Args:\n            index_or_slice: The index of the Clifford to return, or the slice\n                corresponding to the sub CliffordString to return.\n\n        Returns:\n            The indexed Clifford (as a stim.GateData instance) or the sliced\n            CliffordString.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.CliffordString(\"I,X,Y,Z,H\")\n\n            >>> s[2]\n            stim.gate_data('Y')\n\n            >>> s[-1]\n            stim.gate_data('H')\n\n            >>> s[:-1]\n            stim.CliffordString(\"I,X,Y,Z\")\n\n            >>> s[::2]\n            stim.CliffordString(\"I,Y,H\")\n        \"\"\"\n    def __iadd__(\n        self,\n        rhs: stim.CliffordString,\n    ) -> stim.CliffordString:\n        \"\"\"Mutates the CliffordString by concatenating onto it.\n\n        Args:\n            rhs: The suffix to concatenate onto the target CliffordString.\n\n        Returns:\n            The mutated Clifford string.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.CliffordString(\"I,X,H\")\n            >>> alias = c\n            >>> alias += stim.CliffordString(\"Y,S\")\n            >>> c\n            stim.CliffordString(\"I,X,H,Y,S\")\n        \"\"\"\n    def __imul__(\n        self,\n        rhs: Union[stim.CliffordString, int],\n    ) -> stim.CliffordString:\n        \"\"\"Inplace CliffordString multiplication.\n\n        Mutates the CliffordString into itself multiplied by another CliffordString\n        (via pairwise Clifford multipliation) or by an integer (via repeating the\n        contents).\n\n        Args:\n            rhs: Either a stim.CliffordString or an int. If rhs is a\n                stim.CliffordString, then the Cliffords from each string are multiplied\n                pairwise. If rhs is an int, it is the number of times to repeat the\n                Clifford string's contents.\n\n        Returns:\n            The mutated Clifford string.\n\n        Examples:\n            >>> import stim\n\n            >>> c = stim.CliffordString(\"S,X,X\")\n            >>> alias = c\n            >>> alias *= stim.CliffordString(\"S,Z,H,Z\")\n            >>> c\n            stim.CliffordString(\"Z,Y,SQRT_Y,Z\")\n\n            >>> c = stim.CliffordString(\"I,X,H\")\n            >>> alias = c\n            >>> alias *= 2\n            >>> c\n            stim.CliffordString(\"I,X,H,I,X,H\")\n        \"\"\"\n    def __init__(\n        self,\n        arg: Union[int, str, stim.CliffordString, stim.PauliString, stim.Circuit],\n        /,\n    ) -> None:\n        \"\"\"Initializes a stim.CliffordString from the given argument.\n\n        Args:\n            arg [position-only]: This can be a variety of types, including:\n                int: initializes an identity Clifford string of the given length.\n                str: initializes by parsing a comma-separated list of gate names.\n                stim.CliffordString: initializes by copying the given Clifford string.\n                stim.PauliString: initializes by copying from the given Pauli string\n                    (ignores the sign of the Pauli string).\n                stim.Circuit: initializes a CliffordString equivalent to the action\n                    of the circuit (as long as the circuit only contains single qubit\n                    unitary operations and annotations).\n                Iterable: initializes by interpreting each item as a Clifford.\n                    Each item can be a single-qubit Clifford gate name (like \"SQRT_X\")\n                    or stim.GateData instance.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.CliffordString(5)\n            stim.CliffordString(\"I,I,I,I,I\")\n\n            >>> stim.CliffordString(\"X,Y,Z,SQRT_X\")\n            stim.CliffordString(\"X,Y,Z,SQRT_X\")\n\n            >>> stim.CliffordString([\"H\", stim.gate_data(\"S\")])\n            stim.CliffordString(\"H,S\")\n\n            >>> stim.CliffordString(stim.PauliString(\"XYZ\"))\n            stim.CliffordString(\"X,Y,Z\")\n\n            >>> stim.CliffordString(stim.CliffordString(\"X,Y,Z\"))\n            stim.CliffordString(\"X,Y,Z\")\n\n            >>> stim.CliffordString(stim.Circuit('''\n            ...     H 0 1 2\n            ...     S 2 3\n            ...     TICK\n            ...     S 3\n            ...     I 6\n            ... '''))\n            stim.CliffordString(\"H,H,C_ZYX,Z,I,I,I\")\n        \"\"\"\n    def __ipow__(\n        self,\n        num_qubits: int,\n    ) -> object:\n        \"\"\"Mutates the CliffordString into itself raised to a power.\n\n        Args:\n            power: The power to raise the CliffordString's Cliffords to.\n                This value can be negative (e.g. -1 inverts the string).\n\n        Returns:\n            The mutated Clifford string.\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.CliffordString(\"I,X,H,S,C_XYZ\")\n            >>> p **= 3\n            >>> p\n            stim.CliffordString(\"I,X,H,S_DAG,I\")\n\n            >>> p **= 2\n            >>> p\n            stim.CliffordString(\"I,I,I,Z,I\")\n\n            >>> alias = p\n            >>> alias **= 2\n            >>> p\n            stim.CliffordString(\"I,I,I,I,I\")\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of Clifford operations in the string.\n\n        Examples:\n            >>> import stim\n            >>> len(stim.CliffordString(\"I,X,Y,Z,H\"))\n            5\n        \"\"\"\n    def __mul__(\n        self,\n        rhs: Union[stim.CliffordString, int],\n    ) -> stim.CliffordString:\n        \"\"\"CliffordString multiplication.\n\n        Args:\n            rhs: Either a stim.CliffordString or an int. If rhs is a\n                stim.CliffordString, then the Cliffords from each string are multiplied\n                pairwise. If rhs is an int, it is the number of times to repeat the\n                Clifford string's contents.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.CliffordString(\"S,X,X\") * stim.CliffordString(\"S,Z,H,Z\")\n            stim.CliffordString(\"Z,Y,SQRT_Y,Z\")\n\n            >>> stim.CliffordString(\"I,X,H\") * 3\n            stim.CliffordString(\"I,X,H,I,X,H,I,X,H\")\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.CliffordString,\n    ) -> bool:\n        \"\"\"Determines if two Clifford strings have non-identical contents.\n        \"\"\"\n    def __pow__(\n        self,\n        power: int,\n    ) -> stim.CliffordString:\n        \"\"\"Returns the CliffordString raised to a power.\n\n        Args:\n            power: The power to raise the CliffordString's Cliffords to.\n                This value can be negative (e.g. -1 returns the inverse string).\n\n        Returns:\n            The Clifford string raised to the power.\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n            >>> p**0\n            stim.CliffordString(\"I,I,I,I,I\")\n\n            >>> p**1\n            stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n            >>> p**12000001\n            stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n            >>> p**2\n            stim.CliffordString(\"I,I,I,Z,C_ZYX\")\n\n            >>> p**3\n            stim.CliffordString(\"I,X,H,S_DAG,I\")\n\n            >>> p**-1\n            stim.CliffordString(\"I,X,H,S_DAG,C_ZYX\")\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CliffordString`.\n        \"\"\"\n    def __rmul__(\n        self,\n        lhs: int,\n    ) -> stim.CliffordString:\n        \"\"\"CliffordString left-multiplication.\n\n        Args:\n            lhs: The number of times to repeat the Clifford string's contents.\n\n        Returns:\n            The repeated Clifford string.\n\n        Examples:\n            >>> import stim\n\n            >>> 2 * stim.CliffordString(\"I,X,H\")\n            stim.CliffordString(\"I,X,H,I,X,H\")\n\n            >>> 0 * stim.CliffordString(\"I,X,H\")\n            stim.CliffordString(\"\")\n\n            >>> 5 * stim.CliffordString(\"I\")\n            stim.CliffordString(\"I,I,I,I,I\")\n        \"\"\"\n    def __setitem__(\n        self,\n        index_or_slice: Union[int, slice],\n        new_value: Union[str, stim.GateData, stim.CliffordString, stim.PauliString, stim.Tableau],\n    ) -> None:\n        \"\"\"Overwrites an indexed Clifford, or slice of Cliffords, with the given value.\n\n        Args:\n            index_or_slice: The index of the Clifford to overwrite, or the slice\n                of Cliffords to overwrite.\n            new_value: Specifies the value to write into the Clifford string. This can\n                be set to a few different types of values:\n                - str: Name of the single qubit Clifford gate to write to the index or\n                    broadcast over the slice.\n                - stim.GateData: The single qubit Clifford gate to write to the index\n                    or broadcast over the slice.\n                - stim.Tableau: Must be a single qubit tableau. Specifies the single\n                    qubit Clifford gate to write to the index or broadcast over the\n                    slice.\n                - stim.CliffordString: String of Cliffords to write into the slice.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.CliffordString(\"I,I,I,I,I\")\n\n            >>> s[1] = 'H'\n            >>> s\n            stim.CliffordString(\"I,H,I,I,I\")\n\n            >>> s[2:] = 'SQRT_X'\n            >>> s\n            stim.CliffordString(\"I,H,SQRT_X,SQRT_X,SQRT_X\")\n\n            >>> s[0] = stim.gate_data('S_DAG').inverse\n            >>> s\n            stim.CliffordString(\"S,H,SQRT_X,SQRT_X,SQRT_X\")\n\n            >>> s[:] = 'I'\n            >>> s\n            stim.CliffordString(\"I,I,I,I,I\")\n\n            >>> s[::2] = stim.CliffordString(\"X,Y,Z\")\n            >>> s\n            stim.CliffordString(\"X,I,Y,I,Z\")\n\n            >>> s[0] = stim.Tableau.from_named_gate(\"H\")\n            >>> s\n            stim.CliffordString(\"H,I,Y,I,Z\")\n\n            >>> s[:] = stim.Tableau.from_named_gate(\"S\")\n            >>> s\n            stim.CliffordString(\"S,S,S,S,S\")\n\n            >>> s[:4] = stim.PauliString(\"IXYZ\")\n            >>> s\n            stim.CliffordString(\"I,X,Y,Z,S\")\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a string representation of the CliffordString's operations.\n        \"\"\"\n    @staticmethod\n    def all_cliffords_string(\n    ) -> stim.CliffordString:\n        \"\"\"Returns a stim.CliffordString containing each single qubit Clifford once.\n\n        Useful for things like testing that a method works on every single Clifford.\n\n        Examples:\n            >>> import stim\n            >>> cliffords = stim.CliffordString.all_cliffords_string()\n            >>> len(cliffords)\n            24\n\n            >>> print(cliffords[:8])\n            I,X,Y,Z,H_XY,S,S_DAG,H_NXY\n\n            >>> print(cliffords[8:16])\n            H,SQRT_Y_DAG,H_NXZ,SQRT_Y,H_YZ,H_NYZ,SQRT_X,SQRT_X_DAG\n\n            >>> print(cliffords[16:])\n            C_XYZ,C_XYNZ,C_NXYZ,C_XNYZ,C_ZYX,C_ZNYX,C_NZYX,C_ZYNX\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.CliffordString:\n        \"\"\"Returns a copy of the CliffordString.\n\n        Returns:\n            The copy.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.CliffordString(\"H,X\")\n            >>> alias = c\n            >>> copy = c.copy()\n            >>> c *= 5\n            >>> alias\n            stim.CliffordString(\"H,X,H,X,H,X,H,X,H,X\")\n            >>> copy\n            stim.CliffordString(\"H,X\")\n        \"\"\"\n    @staticmethod\n    def random(\n        num_qubits: int,\n    ) -> stim.CliffordString:\n        \"\"\"Samples a uniformly random CliffordString.\n\n        Args:\n            num_qubits: The number of qubits the CliffordString should act upon.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.CliffordString.random(5)\n            >>> len(p)\n            5\n\n        Returns:\n            The sampled Clifford string.\n        \"\"\"\n    def x_outputs(\n        self,\n        *,\n        bit_packed_signs: bool = False,\n    ) -> Tuple[stim.PauliString, np.ndarray]:\n        \"\"\"Returns what each Clifford in the CliffordString conjugates an X input into.\n\n        For example, H conjugates X into +Z and S_DAG conjugates X into -Y.\n\n        Combined with `z_outputs`, the results of this method completely specify\n        the single qubit Clifford applied to each qubit.\n\n        Args:\n            bit_packed_signs: Defaults to False. When False, the sign data is returned\n                in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n                `np.uint8` and 8 bits are packed into each byte (in little endian\n                order).\n\n        Returns:\n            A (paulis, signs) tuple.\n\n            `paulis` has type stim.PauliString. Its sign is always positive.\n\n            `signs` has type np.ndarray and an argument-dependent shape:\n                bit_packed_signs=False:\n                    dtype=np.bool_\n                    shape=(num_qubits,)\n                bit_packed_signs=True:\n                    dtype=np.uint8\n                    shape=(math.ceil(num_qubits / 8),)\n\n        Examples:\n            >>> import stim\n            >>> x_paulis, x_signs = stim.CliffordString(\"I,Y,H,S\").x_outputs()\n            >>> x_paulis\n            stim.PauliString(\"+XXZY\")\n            >>> x_signs\n            array([False,  True, False, False])\n\n            >>> stim.CliffordString(\"I,Y,H,S\").x_outputs(bit_packed_signs=True)[1]\n            array([2], dtype=uint8)\n        \"\"\"\n    def y_outputs(\n        self,\n        *,\n        bit_packed_signs: bool = False,\n    ) -> Tuple[stim.PauliString, np.ndarray]:\n        \"\"\"Returns what each Clifford in the CliffordString conjugates a Y input into.\n\n        For example, H conjugates Y into -Y and S_DAG conjugates Y into +X.\n\n        Args:\n            bit_packed_signs: Defaults to False. When False, the sign data is returned\n                in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n                `np.uint8` and 8 bits are packed into each byte (in little endian\n                order).\n\n        Returns:\n            A (paulis, signs) tuple.\n\n            `paulis` has type stim.PauliString. Its sign is always positive.\n\n            `signs` has type np.ndarray and an argument-dependent shape:\n                bit_packed_signs=False:\n                    dtype=np.bool_\n                    shape=(num_qubits,)\n                bit_packed_signs=True:\n                    dtype=np.uint8\n                    shape=(math.ceil(num_qubits / 8),)\n\n        Examples:\n            >>> import stim\n            >>> y_paulis, y_signs = stim.CliffordString(\"I,X,H,S\").y_outputs()\n            >>> y_paulis\n            stim.PauliString(\"+YYYX\")\n            >>> y_signs\n            array([False,  True,  True,  True])\n\n            >>> stim.CliffordString(\"I,X,H,S\").y_outputs(bit_packed_signs=True)[1]\n            array([14], dtype=uint8)\n        \"\"\"\n    def z_outputs(\n        self,\n        *,\n        bit_packed_signs: bool = False,\n    ) -> Tuple[stim.PauliString, np.ndarray]:\n        \"\"\"Returns what each Clifford in the CliffordString conjugates a Z input into.\n\n        For example, H conjugates Z into +X and SQRT_X conjugates Z into -Y.\n\n        Combined with `x_outputs`, the results of this method completely specify\n        the single qubit Clifford applied to each qubit.\n\n        Args:\n            bit_packed_signs: Defaults to False. When False, the sign data is returned\n                in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n                `np.uint8` and 8 bits are packed into each byte (in little endian\n                order).\n\n        Returns:\n            A (paulis, signs) tuple.\n\n            `paulis` has type stim.PauliString. Its sign is always positive.\n\n            `signs` has type np.ndarray and an argument-dependent shape:\n                bit_packed_signs=False:\n                    dtype=np.bool_\n                    shape=(num_qubits,)\n                bit_packed_signs=True:\n                    dtype=np.uint8\n                    shape=(math.ceil(num_qubits / 8),)\n\n        Examples:\n            >>> import stim\n            >>> z_paulis, z_signs = stim.CliffordString(\"I,Y,H,S\").z_outputs()\n            >>> z_paulis\n            stim.PauliString(\"+ZZXZ\")\n            >>> z_signs\n            array([False,  True, False, False])\n\n            >>> stim.CliffordString(\"I,Y,H,S\").z_outputs(bit_packed_signs=True)[1]\n            array([2], dtype=uint8)\n        \"\"\"\nclass CompiledDemSampler:\n    \"\"\"A helper class for efficiently sampler from a detector error model.\n\n    Examples:\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...    error(0) D0\n        ...    error(1) D1 D2 L0\n        ... ''')\n        >>> sampler = dem.compile_sampler()\n        >>> det_data, obs_data, err_data = sampler.sample(\n        ...     shots=4,\n        ...     return_errors=True)\n        >>> det_data\n        array([[False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True],\n               [False,  True,  True]])\n        >>> obs_data\n        array([[ True],\n               [ True],\n               [ True],\n               [ True]])\n        >>> err_data\n        array([[False,  True],\n               [False,  True],\n               [False,  True],\n               [False,  True]])\n    \"\"\"\n    def sample(\n        self,\n        shots: int,\n        *,\n        bit_packed: bool = False,\n        return_errors: bool = False,\n        recorded_errors_to_replay: Optional[np.ndarray] = None,\n    ) -> Tuple[np.ndarray, np.ndarray, Optional[np.ndarray]]:\n        \"\"\"Samples the detector error model's error mechanisms to produce sample data.\n\n        Args:\n            shots: The number of times to sample from the model.\n            bit_packed: Defaults to false.\n                False: the returned numpy arrays have dtype=np.bool_.\n                True: the returned numpy arrays have dtype=np.uint8 and pack 8 bits into\n                    each byte.\n\n                Setting this to True is equivalent to running\n                `np.packbits(data, bitorder='little', axis=1)` on each output value, but\n                has the performance benefit of the data never being expanded into an\n                unpacked form.\n            return_errors: Defaults to False.\n                False: the third entry of the returned tuple is None.\n                True: the third entry of the returned tuple is a numpy array recording\n                which errors were sampled.\n            recorded_errors_to_replay: Defaults to None, meaning sample errors randomly.\n                If not None, this is expected to be a 2d numpy array specifying which\n                errors to apply (e.g. one returned from a previous call to the sample\n                method). The array must have dtype=np.bool_ and\n                shape=(num_shots, num_errors) or dtype=np.uint8 and\n                shape=(num_shots, math.ceil(num_errors / 8)).\n\n        Returns:\n            A tuple (detector_data, obs_data, error_data).\n\n            Assuming bit_packed is False and return_errors is True:\n                - If error_data[s, k] is True, then the error with index k fired in the\n                    shot with index s.\n                - If detector_data[s, k] is True, then the detector with index k ended\n                    up flipped in the shot with index s.\n                - If obs_data[s, k] is True, then the observable with index k ended up\n                    flipped in the shot with index s.\n\n            The dtype and shape of the data depends on the arguments:\n                if bit_packed:\n                    detector_data.shape == (num_shots, math.ceil(num_detectors / 8))\n                    detector_data.dtype == np.uint8\n                    obs_data.shape == (num_shots, math.ceil(num_observables / 8))\n                    obs_data.dtype == np.uint8\n                    if return_errors:\n                        error_data.shape = (num_shots, math.ceil(num_errors / 8))\n                        error_data.dtype = np.uint8\n                    else:\n                        error_data is None\n                else:\n                    detector_data.shape == (num_shots, num_detectors)\n                    detector_data.dtype == np.bool_\n                    obs_data.shape == (num_shots, num_observables)\n                    obs_data.dtype == np.bool_\n                    if return_errors:\n                        error_data.shape = (num_shots, num_errors)\n                        error_data.dtype = np.bool_\n                    else:\n                        error_data is None\n\n            Note that bit packing is done using little endian order on the last axis\n            (i.e. like `np.packbits(data, bitorder='little', axis=1)`).\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> dem = stim.DetectorErrorModel('''\n            ...    error(0) D0\n            ...    error(1) D1 D2 L0\n            ... ''')\n            >>> sampler = dem.compile_sampler()\n\n            >>> # Taking samples.\n            >>> det_data, obs_data, err_data_not_requested = sampler.sample(shots=4)\n            >>> det_data\n            array([[False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True]])\n            >>> obs_data\n            array([[ True],\n                   [ True],\n                   [ True],\n                   [ True]])\n            >>> err_data_not_requested is None\n            True\n\n            >>> # Recording errors.\n            >>> det_data, obs_data, err_data = sampler.sample(\n            ...     shots=4,\n            ...     return_errors=True)\n            >>> det_data\n            array([[False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True]])\n            >>> obs_data\n            array([[ True],\n                   [ True],\n                   [ True],\n                   [ True]])\n            >>> err_data\n            array([[False,  True],\n                   [False,  True],\n                   [False,  True],\n                   [False,  True]])\n\n            >>> # Bit packing.\n            >>> det_data, obs_data, err_data = sampler.sample(\n            ...     shots=4,\n            ...     return_errors=True,\n            ...     bit_packed=True)\n            >>> det_data\n            array([[6],\n                   [6],\n                   [6],\n                   [6]], dtype=uint8)\n            >>> obs_data\n            array([[1],\n                   [1],\n                   [1],\n                   [1]], dtype=uint8)\n            >>> err_data\n            array([[2],\n                   [2],\n                   [2],\n                   [2]], dtype=uint8)\n\n            >>> # Recording and replaying errors.\n            >>> noisy_dem = stim.DetectorErrorModel('''\n            ...    error(0.125) D0\n            ...    error(0.25) D1\n            ... ''')\n            >>> noisy_sampler = noisy_dem.compile_sampler()\n            >>> det_data, obs_data, err_data = noisy_sampler.sample(\n            ...     shots=100,\n            ...     return_errors=True)\n            >>> replay_det_data, replay_obs_data, _ = noisy_sampler.sample(\n            ...     shots=100,\n            ...     recorded_errors_to_replay=err_data)\n            >>> np.array_equal(det_data, replay_det_data)\n            True\n            >>> np.array_equal(obs_data, replay_obs_data)\n            True\n        \"\"\"\n    def sample_write(\n        self,\n        shots: int,\n        *,\n        det_out_file: Union[None, str, pathlib.Path],\n        det_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        obs_out_file: Union[None, str, pathlib.Path],\n        obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        err_out_file: Union[None, str, pathlib.Path] = None,\n        err_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        replay_err_in_file: Union[None, str, pathlib.Path] = None,\n        replay_err_in_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    ) -> None:\n        \"\"\"Samples the detector error model and writes the results to disk.\n\n        Args:\n            shots: The number of times to sample from the model.\n            det_out_file: Where to write detection event data.\n                If None: detection event data is not written.\n                If str or pathlib.Path: opens and overwrites the file at the given path.\n                NOT IMPLEMENTED: io.IOBase\n            det_out_format: The format to write the detection event data in\n                (e.g. \"01\" or \"b8\").\n            obs_out_file: Where to write observable flip data.\n                If None: observable flip data is not written.\n                If str or pathlib.Path: opens and overwrites the file at the given path.\n                NOT IMPLEMENTED: io.IOBase\n            obs_out_format: The format to write the observable flip data in\n                (e.g. \"01\" or \"b8\").\n            err_out_file: Where to write errors-that-occurred data.\n                If None: errors-that-occurred data is not written.\n                If str or pathlib.Path: opens and overwrites the file at the given path.\n                NOT IMPLEMENTED: io.IOBase\n            err_out_format: The format to write the errors-that-occurred data in\n                (e.g. \"01\" or \"b8\").\n            replay_err_in_file: If this is specified, errors are replayed from data\n                instead of generated randomly. The following types are supported:\n                - None: errors are generated randomly according to the probabilities\n                    in the detector error model.\n                - str or pathlib.Path: the file at the given path is opened and\n                    errors-to-apply data is read from there.\n                - io.IOBase: NOT IMPLEMENTED\n            replay_err_in_format: The format to write the errors-that-occurred data in\n                (e.g. \"01\" or \"b8\").\n\n        Returns:\n            Nothing. Results are written to disk.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> import pathlib\n            >>> dem = stim.DetectorErrorModel('''\n            ...    error(0) D0\n            ...    error(0) D1\n            ...    error(0) D0\n            ...    error(1) D1 D2 L0\n            ...    error(0) D0\n            ... ''')\n            >>> sampler = dem.compile_sampler()\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     d = pathlib.Path(d)\n            ...     sampler.sample_write(\n            ...         shots=1,\n            ...         det_out_file=d / 'dets.01',\n            ...         det_out_format='01',\n            ...         obs_out_file=d / 'obs.01',\n            ...         obs_out_format='01',\n            ...         err_out_file=d / 'err.hits',\n            ...         err_out_format='hits',\n            ...     )\n            ...     with open(d / 'dets.01') as f:\n            ...         assert f.read() == \"011\\n\"\n            ...     with open(d / 'obs.01') as f:\n            ...         assert f.read() == \"1\\n\"\n            ...     with open(d / 'err.hits') as f:\n            ...         assert f.read() == \"3\\n\"\n        \"\"\"\nclass CompiledDetectorSampler:\n    \"\"\"An analyzed stabilizer circuit whose detection events can be sampled quickly.\n    \"\"\"\n    def __init__(\n        self,\n        circuit: stim.Circuit,\n        *,\n        seed: object = None,\n    ) -> None:\n        \"\"\"Creates an object that can sample the detection events from a circuit.\n\n        Args:\n            circuit: The circuit to sample from.\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n\n        Returns:\n            An initialized stim.CompiledDetectorSampler.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    H 0\n            ...    CNOT 0 1\n            ...    X_ERROR(1.0) 0\n            ...    M 0 1\n            ...    DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> s = c.compile_detector_sampler()\n            >>> s.sample(shots=1)\n            array([[ True]])\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.CompiledDetectorSampler`.\n        \"\"\"\n    def sample(\n        self,\n        shots: int,\n        *,\n        prepend_observables: bool = False,\n        append_observables: bool = False,\n        separate_observables: bool = False,\n        bit_packed: bool = False,\n        dets_out: Optional[np.ndarray] = None,\n        obs_out: Optional[np.ndarray] = None,\n    ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:\n        \"\"\"Returns a numpy array containing a batch of detector samples from the circuit.\n\n        The circuit must define the detectors using DETECTOR instructions. Observables\n        defined by OBSERVABLE_INCLUDE instructions can also be included in the results\n        as honorary detectors.\n\n        Args:\n            shots: The number of times to sample every detector in the circuit.\n            separate_observables: Defaults to False. When set to True, the return value\n                is a (detection_events, observable_flips) tuple instead of a flat\n                detection_events array.\n            prepend_observables: Defaults to false. When set, observables are included\n                with the detectors and are placed at the start of the results.\n            append_observables: Defaults to false. When set, observables are included\n                with the detectors and are placed at the end of the results.\n            bit_packed: Returns a uint8 numpy array with 8 bits per byte, instead of\n                a bool_ numpy array with 1 bit per byte. Uses little endian packing.\n            dets_out: Defaults to None. Specifies a pre-allocated numpy array to write\n                the detection event data into. This array must have the correct shape\n                and dtype.\n            obs_out: Defaults to None. Specifies a pre-allocated numpy array to write\n                the observable flip data into. This array must have the correct shape\n                and dtype.\n\n        Returns:\n            A numpy array or tuple of numpy arrays containing the samples.\n\n            if separate_observables=False and bit_packed=False:\n                A single numpy array.\n                dtype=bool_\n                shape=(\n                    shots,\n                    num_detectors + num_observables * (\n                        append_observables + prepend_observables),\n                )\n                The bit for detection event `m` in shot `s` is at\n                    result[s, m]\n\n            if separate_observables=False and bit_packed=True:\n                A single numpy array.\n                dtype=uint8\n                shape=(\n                    shots,\n                    math.ceil((num_detectors + num_observables * (\n                        append_observables + prepend_observables)) / 8),\n                )\n                The bit for detection event `m` in shot `s` is at\n                    (result[s, m // 8] >> (m % 8)) & 1\n\n            if separate_observables=True and bit_packed=False:\n                A (dets, obs) tuple.\n                dets.dtype=bool_\n                dets.shape=(shots, num_detectors)\n                obs.dtype=bool_\n                obs.shape=(shots, num_observables)\n                The bit for detection event `m` in shot `s` is at\n                    dets[s, m]\n                The bit for observable `m` in shot `s` is at\n                    obs[s, m]\n\n            if separate_observables=True and bit_packed=True:\n                A (dets, obs) tuple.\n                dets.dtype=uint8\n                dets.shape=(shots, math.ceil(num_detectors / 8))\n                obs.dtype=uint8\n                obs.shape=(shots, math.ceil(num_observables / 8))\n                The bit for detection event `m` in shot `s` is at\n                    (dets[s, m // 8] >> (m % 8)) & 1\n                The bit for observable `m` in shot `s` is at\n                    (obs[s, m // 8] >> (m % 8)) & 1\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    H 0\n            ...    CNOT 0 1\n            ...    X_ERROR(1.0) 0\n            ...    M 0 1\n            ...    DETECTOR rec[-1] rec[-2]\n            ... ''')\n            >>> s = c.compile_detector_sampler()\n            >>> s.sample(shots=1)\n            array([[ True]])\n        \"\"\"\n    def sample_bit_packed(\n        self,\n        shots: int,\n        *,\n        prepend_observables: bool = False,\n        append_observables: bool = False,\n    ) -> object:\n        \"\"\"[DEPRECATED] Use sampler.sample(..., bit_packed=True) instead.\n\n        Returns a numpy array containing bit packed detector samples from the circuit.\n\n        The circuit must define the detectors using DETECTOR instructions. Observables\n        defined by OBSERVABLE_INCLUDE instructions can also be included in the results\n        as honorary detectors.\n\n        Args:\n            shots: The number of times to sample every detector in the circuit.\n            prepend_observables: Defaults to false. When set, observables are included\n                with the detectors and are placed at the start of the results.\n            append_observables: Defaults to false. When set, observables are included\n                with the detectors and are placed at the end of the results.\n\n        Returns:\n            A numpy array with `dtype=uint8` and `shape=(shots, n)` where `n` is\n            `num_detectors + num_observables*(append_observables+prepend_observables)`.\n            The bit for detection event `m` in shot `s` is at\n            `result[s, (m // 8)] & 2**(m % 8)`.\n        \"\"\"\n    def sample_write(\n        self,\n        shots: int,\n        *,\n        filepath: Union[str, pathlib.Path],\n        format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        obs_out_filepath: Optional[Union[str, pathlib.Path]] = None,\n        obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        prepend_observables: bool = False,\n        append_observables: bool = False,\n    ) -> None:\n        \"\"\"Samples detection events from the circuit and writes them to a file.\n\n        Args:\n            shots: The number of times to sample every measurement in the circuit.\n            filepath: The file to write the results to.\n            format: The output format to write the results with.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            obs_out_filepath: Sample observables as part of each shot, and write them to\n                this file. This keeps the observable data separate from the detector\n                data.\n            obs_out_format: If writing the observables to a file, this is the format to\n                write them in.\n\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            prepend_observables: Sample observables as part of each shot, and put them\n                at the start of the detector data.\n            append_observables: Sample observables as part of each shot, and put them at\n                the end of the detector data.\n\n        Returns:\n            None.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     path = f\"{d}/tmp.dat\"\n            ...     c = stim.Circuit('''\n            ...         X_ERROR(1) 0\n            ...         M 0 1\n            ...         DETECTOR rec[-2]\n            ...         DETECTOR rec[-1]\n            ...     ''')\n            ...     c.compile_detector_sampler().sample_write(\n            ...         shots=3,\n            ...         filepath=path,\n            ...         format=\"dets\")\n            ...     with open(path) as f:\n            ...         print(f.read(), end='')\n            shot D0\n            shot D0\n            shot D0\n        \"\"\"\nclass CompiledMeasurementSampler:\n    \"\"\"An analyzed stabilizer circuit whose measurements can be sampled quickly.\n    \"\"\"\n    def __init__(\n        self,\n        circuit: stim.Circuit,\n        *,\n        skip_reference_sample: bool = False,\n        seed: object = None,\n        reference_sample: object = None,\n    ) -> None:\n        \"\"\"Creates a measurement sampler for the given circuit.\n\n        The sampler uses a noiseless reference sample, collected from the circuit using\n        stim's Tableau simulator during initialization of the sampler, as a baseline for\n        deriving more samples using an error propagation simulator.\n\n        Args:\n            circuit: The stim circuit to sample from.\n            skip_reference_sample: Defaults to False. When set to True, the reference\n                sample used by the sampler is initialized to all-zeroes instead of being\n                collected from the circuit. This means that the results returned by the\n                sampler are actually whether or not each measurement was *flipped*,\n                instead of true measurement results.\n\n                Forcing an all-zero reference sample is useful when you are only\n                interested in error propagation and don't want to have to deal with the\n                fact that some measurements want to be On when no errors occur. It is\n                also useful when you know for sure that the all-zero result is actually\n                a possible result from the circuit (under noiseless execution), meaning\n                it is a valid reference sample as good as any other. Computing the\n                reference sample is the most time consuming and memory intensive part of\n                simulating the circuit, so promising that the simulator can safely skip\n                that step is an effective optimization.\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n            reference_sample: The data to xor into the measurement flips produced by the\n                frame simulator, in order to produce proper measurement results.\n                This can either be specified as an `np.bool_` array or a bit packed\n                `np.uint8` array (little endian). Under normal conditions, the reference\n                sample should be a valid noiseless sample of the circuit, such as the\n                one returned by `circuit.reference_sample()`. If this argument is not\n                provided, the reference sample will be set to\n                `circuit.reference_sample()`, unless `skip_reference_sample=True`\n                is used, in which case it will be set to all-zeros.\n\n        Returns:\n            An initialized stim.CompiledMeasurementSampler.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0   2 3\n            ...    M 0 1 2 3\n            ... ''')\n            >>> s = c.compile_sampler()\n            >>> s.sample(shots=1)\n            array([[ True, False,  True,  True]])\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CompiledMeasurementSampler`.\n        \"\"\"\n    def sample(\n        self,\n        shots: int,\n        *,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Samples a batch of measurement samples from the circuit.\n\n        Args:\n            shots: The number of times to sample every measurement in the circuit.\n            bit_packed: Returns a uint8 numpy array with 8 bits per byte, instead of\n                a bool_ numpy array with 1 bit per byte. Uses little endian packing.\n\n        Returns:\n            A numpy array containing the samples.\n\n            If bit_packed=False:\n                dtype=bool_\n                shape=(shots, circuit.num_measurements)\n                The bit for measurement `m` in shot `s` is at\n                    result[s, m]\n            If bit_packed=True:\n                dtype=uint8\n                shape=(shots, math.ceil(circuit.num_measurements / 8))\n                The bit for measurement `m` in shot `s` is at\n                    (result[s, m // 8] >> (m % 8)) & 1\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0   2 3\n            ...    M 0 1 2 3\n            ... ''')\n            >>> s = c.compile_sampler()\n            >>> s.sample(shots=1)\n            array([[ True, False,  True,  True]])\n        \"\"\"\n    def sample_bit_packed(\n        self,\n        shots: int,\n    ) -> np.ndarray:\n        \"\"\"[DEPRECATED] Use sampler.sample(..., bit_packed=True) instead.\n\n        Samples a bit packed batch of measurement samples from the circuit.\n\n        Args:\n            shots: The number of times to sample every measurement in the circuit.\n\n        Returns:\n            A numpy array with `dtype=uint8` and\n            `shape=(shots, (num_measurements + 7) // 8)`.\n\n            The bit for measurement `m` in shot `s` is at\n            `result[s, (m // 8)] & 2**(m % 8)`.\n\n        Examples:\n            >>> import stim\n            >>> c = stim.Circuit('''\n            ...    X 0 1 2 3 4 5 6 7     10\n            ...    M 0 1 2 3 4 5 6 7 8 9 10\n            ... ''')\n            >>> s = c.compile_sampler()\n            >>> s.sample_bit_packed(shots=1)\n            array([[255,   4]], dtype=uint8)\n        \"\"\"\n    def sample_write(\n        self,\n        shots: int,\n        *,\n        filepath: Union[str, pathlib.Path],\n        format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    ) -> None:\n        \"\"\"Samples measurements from the circuit and writes them to a file.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     path = f\"{d}/tmp.dat\"\n            ...     c = stim.Circuit('''\n            ...         X 0   2 3\n            ...         M 0 1 2 3\n            ...     ''')\n            ...     c.compile_sampler().sample_write(5, filepath=path, format=\"01\")\n            ...     with open(path) as f:\n            ...         print(f.read(), end='')\n            1011\n            1011\n            1011\n            1011\n            1011\n\n        Args:\n            shots: The number of times to sample every measurement in the circuit.\n            filepath: The file to write the results to.\n            format: The output format to write the results with.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n\n        Returns:\n            None.\n        \"\"\"\nclass CompiledMeasurementsToDetectionEventsConverter:\n    \"\"\"A tool for quickly converting measurements from an analyzed stabilizer circuit into detection events.\n    \"\"\"\n    def __init__(\n        self,\n        circuit: stim.Circuit,\n        *,\n        skip_reference_sample: bool = False,\n    ) -> None:\n        \"\"\"Creates a measurement-to-detection-events converter for the given circuit.\n\n        The converter uses a noiseless reference sample, collected from the circuit\n        using stim's Tableau simulator during initialization of the converter, as a\n        baseline for determining what the expected value of a detector is.\n\n        Note that the expected behavior of gauge detectors (detectors that are not\n        actually deterministic under noiseless execution) can vary depending on the\n        reference sample. Stim mitigates this by always generating the same reference\n        sample for a given circuit.\n\n        Args:\n            circuit: The stim circuit to use for conversions.\n            skip_reference_sample: Defaults to False. When set to True, the reference\n                sample used by the converter is initialized to all-zeroes instead of\n                being collected from the circuit. This should only be used if it's known\n                that the all-zeroes sample is actually a possible result from the\n                circuit (under noiseless execution).\n\n        Returns:\n            An initialized stim.CompiledMeasurementsToDetectionEventsConverter.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> converter = stim.Circuit('''\n            ...    X 0\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... ''').compile_m2d_converter()\n            >>> converter.convert(\n            ...     measurements=np.array([[0], [1]], dtype=np.bool_),\n            ...     append_observables=False,\n            ... )\n            array([[ True],\n                   [False]])\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.CompiledMeasurementsToDetectionEventsConverter`.\n        \"\"\"\n    @overload\n    def convert(\n        self,\n        *,\n        measurements: np.ndarray,\n        sweep_bits: Optional[np.ndarray] = None,\n        append_observables: bool = False,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        pass\n    @overload\n    def convert(\n        self,\n        *,\n        measurements: np.ndarray,\n        sweep_bits: Optional[np.ndarray] = None,\n        separate_observables: Literal[True],\n        append_observables: bool = False,\n        bit_packed: bool = False,\n    ) -> Tuple[np.ndarray, np.ndarray]:\n        pass\n    def convert(\n        self,\n        *,\n        measurements: np.ndarray,\n        sweep_bits: Optional[np.ndarray] = None,\n        separate_observables: bool = False,\n        append_observables: bool = False,\n        bit_packed: bool = False,\n    ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:\n        \"\"\"Converts measurement data into detection event data.\n\n        Args:\n            measurements: A numpy array containing measurement data.\n\n                The dtype of the array is used to determine if it is bit packed or not.\n                dtype=np.bool_ (unpacked data):\n                    shape=(num_shots, circuit.num_measurements)\n                dtype=np.uint8 (bit packed data):\n                    shape=(num_shots, math.ceil(circuit.num_measurements / 8))\n            sweep_bits: Optional. A numpy array containing sweep data for the `sweep[k]`\n                controls in the circuit.\n\n                The dtype of the array is used to determine if it is bit packed or not.\n                dtype=np.bool_ (unpacked data):\n                    shape=(num_shots, circuit.num_sweep_bits)\n                dtype=np.uint8 (bit packed data):\n                    shape=(num_shots, math.ceil(circuit.num_sweep_bits / 8))\n            separate_observables: Defaults to False. When set to True, two numpy arrays\n                are returned instead of one, with the second array containing the\n                observable flip data.\n            append_observables: Defaults to False. When set to True, the observables in\n                the circuit are treated as if they were additional detectors. Their\n                results are appended to the end of the detection event data.\n            bit_packed: Defaults to False. When set to True, the returned numpy\n                array contains bit packed data (dtype=np.uint8 with 8 bits per item)\n                instead of unpacked data (dtype=np.bool_).\n\n        Returns:\n            The detection event data and (optionally) observable data. The result is a\n            single numpy array if separate_observables is false, otherwise it's a tuple\n            of two numpy arrays.\n\n            When returning two numpy arrays, the first array is the detection event data\n            and the second is the observable flip data.\n\n            The dtype of the returned arrays is np.bool_ if bit_packed is false,\n            otherwise they're np.uint8 arrays.\n\n            shape[0] of the array(s) is the number of shots.\n            shape[1] of the array(s) is the number of bits per shot (divided by 8 if bit\n            packed) (e.g. for just detection event data it would be\n            circuit.num_detectors).\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> converter = stim.Circuit('''\n            ...    X 0\n            ...    M 0 1\n            ...    DETECTOR rec[-1]\n            ...    DETECTOR rec[-2]\n            ...    OBSERVABLE_INCLUDE(0) rec[-2]\n            ... ''').compile_m2d_converter()\n            >>> dets, obs = converter.convert(\n            ...     measurements=np.array([[1, 0],\n            ...                            [1, 0],\n            ...                            [1, 0],\n            ...                            [0, 0],\n            ...                            [1, 0]], dtype=np.bool_),\n            ...     separate_observables=True,\n            ... )\n            >>> dets\n            array([[False, False],\n                   [False, False],\n                   [False, False],\n                   [False,  True],\n                   [False, False]])\n            >>> obs\n            array([[False],\n                   [False],\n                   [False],\n                   [ True],\n                   [False]])\n        \"\"\"\n    def convert_file(\n        self,\n        *,\n        measurements_filepath: Union[str, pathlib.Path],\n        measurements_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        sweep_bits_filepath: Optional[Union[str, pathlib.Path]] = None,\n        sweep_bits_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        detection_events_filepath: Union[str, pathlib.Path],\n        detection_events_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n        append_observables: bool = False,\n        obs_out_filepath: Optional[Union[str, pathlib.Path]] = None,\n        obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01',\n    ) -> None:\n        \"\"\"Reads measurement data from a file and writes detection events to another file.\n\n        Args:\n            measurements_filepath: A file containing measurement data to be converted.\n            measurements_format: The format the measurement data is stored in.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            detection_events_filepath: Where to save detection event data to.\n            detection_events_format: The format to save the detection event data in.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            sweep_bits_filepath: Defaults to None. A file containing sweep data, or\n                None. When specified, sweep data (used for `sweep[k]` controls in the\n                circuit, which can vary from shot to shot) will be read from the given\n                file. When not specified, all sweep bits default to False and no\n                sweep-controlled operations occur.\n            sweep_bits_format: The format the sweep data is stored in.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            obs_out_filepath: Sample observables as part of each shot, and write them to\n                this file. This keeps the observable data separate from the detector\n                data.\n            obs_out_format: If writing the observables to a file, this is the format to\n                write them in.\n                Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                Defaults to \"01\".\n            append_observables: When True, the observables in the circuit are included\n                as part of the detection event data. Specifically, they are treated as\n                if they were additional detectors at the end of the circuit. When False,\n                observable data is not output.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> converter = stim.Circuit('''\n            ...    X 0\n            ...    M 0\n            ...    DETECTOR rec[-1]\n            ... ''').compile_m2d_converter()\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...    with open(f\"{d}/measurements.01\", \"w\") as f:\n            ...        print(\"0\", file=f)\n            ...        print(\"1\", file=f)\n            ...    converter.convert_file(\n            ...        measurements_filepath=f\"{d}/measurements.01\",\n            ...        detection_events_filepath=f\"{d}/detections.01\",\n            ...        append_observables=False,\n            ...    )\n            ...    with open(f\"{d}/detections.01\") as f:\n            ...        print(f.read(), end=\"\")\n            1\n            0\n        \"\"\"\nclass DemInstruction:\n    \"\"\"An instruction from a detector error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ...     error(0.125) D0 D1 L0\n        ...     error(0.125) D1 D2\n        ...     error(0.125) D2 D3\n        ...     error(0.125) D3\n        ... ''')\n        >>> instruction = model[0]\n        >>> instruction\n        stim.DemInstruction('error', [0.125], [stim.target_relative_detector_id(0)])\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.DemInstruction,\n    ) -> bool:\n        \"\"\"Determines if two instructions have identical contents.\n        \"\"\"\n    def __init__(\n        self,\n        type: str,\n        args: Optional[Iterable[float]] = None,\n        targets: Optional[Iterable[stim.DemTarget]] = None,\n        *,\n        tag: str = \"\",\n    ) -> None:\n        \"\"\"Creates or parses a stim.DemInstruction.\n\n        Args:\n            type: The name of the instruction type (e.g. \"error\" or \"shift_detectors\").\n                If `args` and `targets` aren't specified, this can also be set to a\n                full line of text from a dem file, like \"error(0.25) D0\".\n            args: Numeric values parameterizing the instruction (e.g. the 0.1 in\n                \"error(0.1)\").\n            targets: The objects the instruction involves (e.g. the \"D0\" and \"L1\" in\n                \"error(0.1) D0 L1\").\n            tag: An arbitrary piece of text attached to the instruction.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.DemInstruction(\n            ...     'error',\n            ...     [0.125],\n            ...     [stim.target_relative_detector_id(5)],\n            ...     tag='test-tag',\n            ... )\n            >>> print(instruction)\n            error[test-tag](0.125) D5\n\n            >>> print(stim.DemInstruction('error(0.125) D5 L6 ^ D4  # comment'))\n            error(0.125) D5 L6 ^ D4\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.DemInstruction,\n    ) -> bool:\n        \"\"\"Determines if two instructions have non-identical contents.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.DetectorErrorModel`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns detector error model (.dem) instructions (that can be parsed by stim) for the model.\n        \"\"\"\n    def args_copy(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns a copy of the list of numbers parameterizing the instruction.\n\n        For example, this would be coordinates of a detector instruction or the\n        probability of an error instruction. The result is a copy, meaning that\n        editing it won't change the instruction's targets or future copies.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.DetectorErrorModel('''\n            ...     error(0.125) D0\n            ... ''')[0]\n            >>> instruction.args_copy()\n            [0.125]\n\n            >>> instruction.args_copy() == instruction.args_copy()\n            True\n            >>> instruction.args_copy() is instruction.args_copy()\n            False\n        \"\"\"\n    @property\n    def tag(\n        self,\n    ) -> str:\n        \"\"\"Returns the arbitrary text tag attached to the instruction.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...     error[test-tag](0.125) D0\n            ...     error(0.125) D0\n            ... ''')\n            >>> dem[0].tag\n            'test-tag'\n            >>> dem[1].tag\n            ''\n        \"\"\"\n    def target_groups(\n        self,\n    ) -> List[List[stim.DemTarget]]:\n        \"\"\"Returns a copy of the instruction's targets, split by target separators.\n\n        When a detector error model instruction contains a suggested decomposition,\n        its targets contain separators (`stim.DemTarget(\"^\")`). This method splits the\n        targets into groups based the separators, similar to how `str.split` works.\n\n        Returns:\n            A list of groups of targets.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...     error(0.01) D0 D1 ^ D2\n            ...     error(0.01) D0 L0\n            ...     error(0.01)\n            ... ''')\n\n            >>> dem[0].target_groups()\n            [[stim.DemTarget('D0'), stim.DemTarget('D1')], [stim.DemTarget('D2')]]\n\n            >>> dem[1].target_groups()\n            [[stim.DemTarget('D0'), stim.DemTarget('L0')]]\n\n            >>> dem[2].target_groups()\n            [[]]\n        \"\"\"\n    def targets_copy(\n        self,\n    ) -> List[Union[int, stim.DemTarget]]:\n        \"\"\"Returns a copy of the instruction's targets.\n\n        The result is a copy, meaning that editing it won't change the instruction's\n        targets or future copies.\n\n        Examples:\n            >>> import stim\n            >>> instruction = stim.DetectorErrorModel('''\n            ...     error(0.125) D0 L2\n            ... ''')[0]\n            >>> instruction.targets_copy()\n            [stim.DemTarget('D0'), stim.DemTarget('L2')]\n\n            >>> instruction.targets_copy() == instruction.targets_copy()\n            True\n            >>> instruction.targets_copy() is instruction.targets_copy()\n            False\n        \"\"\"\n    @property\n    def type(\n        self,\n    ) -> str:\n        \"\"\"The name of the instruction type (e.g. \"error\" or \"shift_detectors\").\n        \"\"\"\nclass DemRepeatBlock:\n    \"\"\"A repeat block from a detector error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...     repeat 100 {\n        ...         error(0.125) D0 D1\n        ...         shift_detectors 1\n        ...     }\n        ... ''')\n        >>> model[0]\n        stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n            error(0.125) D0 D1\n            shift_detectors 1\n        '''))\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.DemRepeatBlock,\n    ) -> bool:\n        \"\"\"Determines if two repeat blocks are identical.\n        \"\"\"\n    def __init__(\n        self,\n        repeat_count: int,\n        block: stim.DetectorErrorModel,\n    ) -> None:\n        \"\"\"Creates a stim.DemRepeatBlock.\n\n        Args:\n            repeat_count: The number of times the repeat block's body is supposed to\n                execute.\n            block: The body of the repeat block as a DetectorErrorModel containing the\n                instructions to repeat.\n\n        Examples:\n            >>> import stim\n            >>> repeat_block = stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n            ...     error(0.125) D0 D1\n            ...     shift_detectors 1\n            ... '''))\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.DemRepeatBlock,\n    ) -> bool:\n        \"\"\"Determines if two repeat blocks are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.DemRepeatBlock`.\n        \"\"\"\n    def body_copy(\n        self,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns a copy of the block's body, as a stim.DetectorErrorModel.\n\n        Examples:\n            >>> import stim\n            >>> body = stim.DetectorErrorModel('''\n            ...     error(0.125) D0 D1\n            ...     shift_detectors 1\n            ... ''')\n            >>> repeat_block = stim.DemRepeatBlock(100, body)\n            >>> repeat_block.body_copy() == body\n            True\n            >>> repeat_block.body_copy() is repeat_block.body_copy()\n            False\n        \"\"\"\n    @property\n    def repeat_count(\n        self,\n    ) -> int:\n        \"\"\"The number of times the repeat block's body is supposed to execute.\n        \"\"\"\n    @property\n    def type(\n        self,\n    ) -> object:\n        \"\"\"Returns the type name \"repeat\".\n\n        This is a duck-typing convenience method. It exists so that code that doesn't\n        know whether it has a `stim.DemInstruction` or a `stim.DemRepeatBlock`\n        can check the type field without having to do an `instanceof` check first.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...     error(0.1) D0 L0\n            ...     repeat 5 {\n            ...         error(0.1) D0 D1\n            ...         shift_detectors 1\n            ...     }\n            ...     logical_observable L0\n            ... ''')\n            >>> [instruction.type for instruction in dem]\n            ['error', 'repeat', 'logical_observable']\n        \"\"\"\nclass DemTarget:\n    \"\"\"An instruction target from a detector error model (.dem) file.\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.DemTarget,\n    ) -> bool:\n        \"\"\"Determines if two `stim.DemTarget`s are identical.\n        \"\"\"\n    def __init__(\n        self,\n        arg: object,\n        /,\n    ) -> None:\n        \"\"\"Creates a stim.DemTarget from the given object.\n\n        Args:\n            arg: A string to parse as a stim.DemTarget, or some other object to\n                convert into a stim.DemTarget.\n\n        Examples:\n            >>> import stim\n            >>> stim.DemTarget(\"D5\") == stim.target_relative_detector_id(5)\n            True\n            >>> stim.DemTarget(\"L2\") == stim.target_logical_observable_id(2)\n            True\n            >>> stim.DemTarget(\"^\") == stim.target_separator()\n            True\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.DemTarget,\n    ) -> bool:\n        \"\"\"Determines if two `stim.DemTarget`s are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.DemTarget`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a text description of the detector error model target.\n        \"\"\"\n    def is_logical_observable_id(\n        self,\n    ) -> bool:\n        \"\"\"Determines if the detector error model target is a logical observable id target.\n\n        In a detector error model file, observable targets are prefixed by `L`. For\n        example, in `error(0.25) D0 L1` the `L1` is an observable target.\n\n        Examples:\n            >>> import stim\n            >>> stim.DemTarget(\"L2\").is_logical_observable_id()\n            True\n            >>> stim.DemTarget(\"D3\").is_logical_observable_id()\n            False\n            >>> stim.DemTarget(\"^\").is_logical_observable_id()\n            False\n        \"\"\"\n    def is_relative_detector_id(\n        self,\n    ) -> bool:\n        \"\"\"Determines if the detector error model target is a relative detector id target.\n\n        In a detector error model file, detectors are prefixed by `D`. For\n        example, in `error(0.25) D0 L1` the `D0` is a relative detector target.\n\n        Examples:\n            >>> import stim\n            >>> stim.DemTarget(\"L2\").is_relative_detector_id()\n            False\n            >>> stim.DemTarget(\"D3\").is_relative_detector_id()\n            True\n            >>> stim.DemTarget(\"^\").is_relative_detector_id()\n            False\n        \"\"\"\n    def is_separator(\n        self,\n    ) -> bool:\n        \"\"\"Determines if the detector error model target is a separator.\n\n        Separates separate the components of a suggested decompositions within an error.\n        For example, the `^` in `error(0.25) D1 D2 ^ D3 D4` is the separator.\n\n        Examples:\n            >>> import stim\n            >>> stim.DemTarget(\"L2\").is_separator()\n            False\n            >>> stim.DemTarget(\"D3\").is_separator()\n            False\n            >>> stim.DemTarget(\"^\").is_separator()\n            True\n        \"\"\"\n    @staticmethod\n    def logical_observable_id(\n        index: int,\n    ) -> stim.DemTarget:\n        \"\"\"Returns a logical observable id identifying a frame change.\n\n        Args:\n            index: The index of the observable.\n\n        Returns:\n            The logical observable target.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel()\n            >>> m.append(\"error\", 0.25, [\n            ...     stim.DemTarget.logical_observable_id(13)\n            ... ])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.25) L13\n            ''')\n        \"\"\"\n    @staticmethod\n    def relative_detector_id(\n        index: int,\n    ) -> stim.DemTarget:\n        \"\"\"Returns a relative detector id (e.g. \"D5\" in a .dem file).\n\n        Args:\n            index: The index of the detector, relative to the current detector offset.\n\n        Returns:\n            The relative detector target.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel()\n            >>> m.append(\"error\", 0.25, [\n            ...     stim.DemTarget.relative_detector_id(13)\n            ... ])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.25) D13\n            ''')\n        \"\"\"\n    @staticmethod\n    def separator(\n    ) -> stim.DemTarget:\n        \"\"\"Returns a target separator (e.g. \"^\" in a .dem file).\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel()\n            >>> m.append(\"error\", 0.25, [\n            ...     stim.DemTarget.relative_detector_id(1),\n            ...     stim.DemTarget.separator(),\n            ...     stim.DemTarget.relative_detector_id(2),\n            ... ])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.25) D1 ^ D2\n            ''')\n        \"\"\"\n    @property\n    def val(\n        self,\n    ) -> int:\n        \"\"\"Returns the target's integer value.\n\n        Example:\n            >>> import stim\n            >>> stim.DemTarget(\"D5\").val\n            5\n            >>> stim.DemTarget(\"L6\").val\n            6\n        \"\"\"\nclass DemTargetWithCoords:\n    \"\"\"A detector error model instruction target with associated coords.\n\n    It is also guaranteed that, if the type of the DEM target is a\n    relative detector id, it is actually absolute (i.e. relative to\n    0).\n\n    For example, if the DEM target is a detector from a circuit with\n    coordinate arguments given to detectors, the coords field will\n    contain the coordinate data for the detector.\n\n    This is helpful information to have available when debugging a\n    problem in a circuit, instead of having to constantly manually\n    look up the coordinates of a detector index in order to understand\n    what is happening.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.DemTargetWithCoords(stim.DemTarget(\"D1\"), [1.5, 2.0])\n        >>> t.dem_target\n        stim.DemTarget('D1')\n        >>> t.coords\n        [1.5, 2.0]\n    \"\"\"\n    def __init__(\n        self,\n        dem_target: stim.DemTarget,\n        coords: List[float],\n    ) -> None:\n        \"\"\"Creates a stim.DemTargetWithCoords.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].dem_error_terms[0]\n            stim.DemTargetWithCoords(dem_target=stim.DemTarget('D0'), coords=[2, 3])\n        \"\"\"\n    @property\n    def coords(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns the associated coordinate information as a list of floats.\n\n        If there is no coordinate information, returns an empty list.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].dem_error_terms[0].coords\n            [2.0, 3.0]\n        \"\"\"\n    @property\n    def dem_target(\n        self,\n    ) -> stim.DemTarget:\n        \"\"\"Returns the actual DEM target as a `stim.DemTarget`.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0 1\n            ...     X_ERROR(0.25) 0 1\n            ...     M 0 1\n            ...     DETECTOR(2, 3) rec[-1] rec[-2]\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].dem_error_terms[0].dem_target\n            stim.DemTarget('D0')\n        \"\"\"\nclass DetectorErrorModel:\n    \"\"\"An error model built out of independent error mechanics.\n\n    This class is one of the most important classes in Stim, because it is the\n    mechanism used to explain circuits to decoders. A typical workflow would\n    look something like:\n\n        1. Create a quantum error correction circuit annotated with detectors\n            and observables.\n        2. Fail at configuring your favorite decoder using the circuit, because\n            it's a pain to convert circuit error mechanisms into a format\n            understood by the decoder.\n        2a. Call circuit.detector_error_model(), with decompose_errors=True\n            if working with a matching-based code. This converts the circuit\n            errors into a straightforward list of independent \"with\n            probability p these detectors and observables get flipped\" terms.\n        3. Write tedious but straightforward glue code to create whatever\n            graph-like object the decoder needs from the detector error model.\n        3a. Actually, ideally, someone has already done that for you. For\n            example, pymatching can take detector error models directly and\n            sinter knows how to explain a detector error model to fusion_blossom.\n        4. Get samples using circuit.compile_detector_sampler(), feed them to\n            the decoder, and compare its observable flip predictions to the\n            actual flips recorded in the samples.\n        4a. Actually, sinter will basically handle steps 2 through 4 for you.\n            So you should probably have just generated your circuits, called\n            `sinter collect` on them, then `sinter plot` on the results.\n        5. Write the paper.\n\n    Error mechanisms are described in terms of the visible detection events and the\n    hidden observable frame changes that they causes. Error mechanisms can also\n    suggest decompositions of their effects into components, which can be helpful\n    for decoders that want to work with a simpler decomposed error model instead of\n    the full error model.\n\n    Examples:\n        >>> import stim\n        >>> model = stim.DetectorErrorModel('''\n        ...     error(0.125) D0\n        ...     error(0.125) D0 D1 L0\n        ...     error(0.125) D1 D2\n        ...     error(0.125) D2 D3\n        ...     error(0.125) D3\n        ... ''')\n        >>> len(model)\n        5\n\n        >>> stim.Circuit('''\n        ...     X_ERROR(0.125) 0\n        ...     X_ERROR(0.25) 1\n        ...     CORRELATED_ERROR(0.375) X0 X1\n        ...     M 0 1\n        ...     DETECTOR rec[-2]\n        ...     DETECTOR rec[-1]\n        ... ''').detector_error_model()\n        stim.DetectorErrorModel('''\n            error(0.125) D0\n            error(0.375) D0 D1\n            error(0.25) D1\n        ''')\n    \"\"\"\n    def __add__(\n        self,\n        second: stim.DetectorErrorModel,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Creates a detector error model by appending two models.\n\n        Examples:\n            >>> import stim\n            >>> m1 = stim.DetectorErrorModel('''\n            ...    error(0.125) D0\n            ... ''')\n            >>> m2 = stim.DetectorErrorModel('''\n            ...    error(0.25) D1\n            ... ''')\n            >>> m1 + m2\n            stim.DetectorErrorModel('''\n                error(0.125) D0\n                error(0.25) D1\n            ''')\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.DetectorErrorModel,\n    ) -> bool:\n        \"\"\"Determines if two detector error models have identical contents.\n        \"\"\"\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: int,\n    ) -> Union[stim.DemInstruction, stim.DemRepeatBlock]:\n        pass\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: slice,\n    ) -> stim.DetectorErrorModel:\n        pass\n    def __getitem__(\n        self,\n        index_or_slice: object,\n    ) -> object:\n        \"\"\"Returns copies of instructions from the detector error model.\n\n        Args:\n            index_or_slice: An integer index picking out an instruction to return, or a\n                slice picking out a range of instructions to return as a detector error\n                model.\n\n        Examples:\n            >>> import stim\n            >>> model = stim.DetectorErrorModel('''\n            ...    error(0.125) D0\n            ...    error(0.125) D1 L1\n            ...    repeat 100 {\n            ...        error(0.125) D1 D2\n            ...        shift_detectors 1\n            ...    }\n            ...    error(0.125) D2\n            ...    logical_observable L0\n            ...    detector D5\n            ... ''')\n            >>> model[0]\n            stim.DemInstruction('error', [0.125], [stim.target_relative_detector_id(0)])\n            >>> model[2]\n            stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n                error(0.125) D1 D2\n                shift_detectors 1\n            '''))\n            >>> model[1::2]\n            stim.DetectorErrorModel('''\n                error(0.125) D1 L1\n                error(0.125) D2\n                detector D5\n            ''')\n        \"\"\"\n    def __iadd__(\n        self,\n        second: stim.DetectorErrorModel,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Appends a detector error model into the receiving model (mutating it).\n\n        Examples:\n            >>> import stim\n            >>> m1 = stim.DetectorErrorModel('''\n            ...    error(0.125) D0\n            ... ''')\n            >>> m2 = stim.DetectorErrorModel('''\n            ...    error(0.25) D1\n            ... ''')\n            >>> m1 += m2\n            >>> print(repr(m1))\n            stim.DetectorErrorModel('''\n                error(0.125) D0\n                error(0.25) D1\n            ''')\n        \"\"\"\n    def __imul__(\n        self,\n        repetitions: int,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Mutates the detector error model by putting its contents into a repeat block.\n\n        Special case: if the repetition count is 0, the model is cleared.\n        Special case: if the repetition count is 1, nothing happens.\n\n        Args:\n            repetitions: The number of times the repeat block should repeat.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel('''\n            ...    error(0.25) D0\n            ...    shift_detectors 1\n            ... ''')\n            >>> m *= 3\n            >>> print(m)\n            repeat 3 {\n                error(0.25) D0\n                shift_detectors 1\n            }\n        \"\"\"\n    def __init__(\n        self,\n        detector_error_model_text: str = '',\n    ) -> None:\n        \"\"\"Creates a stim.DetectorErrorModel.\n\n        Args:\n            detector_error_model_text: Defaults to empty. Describes instructions to\n                append into the circuit in the detector error model (.dem) format.\n\n        Examples:\n            >>> import stim\n            >>> empty = stim.DetectorErrorModel()\n            >>> not_empty = stim.DetectorErrorModel('''\n            ...    error(0.125) D0 L0\n            ... ''')\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of top-level instructions/blocks in the detector error model.\n\n        Instructions inside of blocks are not included in this count.\n\n        Examples:\n            >>> import stim\n            >>> len(stim.DetectorErrorModel())\n            0\n            >>> len(stim.DetectorErrorModel('''\n            ...    error(0.1) D0 D1\n            ...    shift_detectors 100\n            ...    logical_observable L5\n            ... '''))\n            3\n            >>> len(stim.DetectorErrorModel('''\n            ...    repeat 100 {\n            ...        error(0.1) D0 D1\n            ...        error(0.1) D1 D2\n            ...    }\n            ... '''))\n            1\n        \"\"\"\n    def __mul__(\n        self,\n        repetitions: int,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Repeats the detector error model using a repeat block.\n\n        Has special cases for 0 repetitions and 1 repetitions.\n\n        Args:\n            repetitions: The number of times the repeat block should repeat.\n\n        Returns:\n            repetitions=0: An empty detector error model.\n            repetitions=1: A copy of this detector error model.\n            repetitions>=2: A detector error model with a single repeat block, where the\n            contents of that repeat block are this detector error model.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel('''\n            ...    error(0.25) D0\n            ...    shift_detectors 1\n            ... ''')\n            >>> m * 3\n            stim.DetectorErrorModel('''\n                repeat 3 {\n                    error(0.25) D0\n                    shift_detectors 1\n                }\n            ''')\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.DetectorErrorModel,\n    ) -> bool:\n        \"\"\"Determines if two detector error models have non-identical contents.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.DetectorErrorModel`.\n        \"\"\"\n    def __rmul__(\n        self,\n        repetitions: int,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Repeats the detector error model using a repeat block.\n\n        Has special cases for 0 repetitions and 1 repetitions.\n\n        Args:\n            repetitions: The number of times the repeat block should repeat.\n\n        Returns:\n            repetitions=0: An empty detector error model.\n            repetitions=1: A copy of this detector error model.\n            repetitions>=2: A detector error model with a single repeat block, where the\n            contents of that repeat block are this detector error model.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel('''\n            ...    error(0.25) D0\n            ...    shift_detectors 1\n            ... ''')\n            >>> 3 * m\n            stim.DetectorErrorModel('''\n                repeat 3 {\n                    error(0.25) D0\n                    shift_detectors 1\n                }\n            ''')\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns the contents of a detector error model file (.dem) encoding the model.\n        \"\"\"\n    def append(\n        self,\n        instruction: object,\n        parens_arguments: object = None,\n        targets: List[object] = (),\n        *,\n        tag: str = '',\n    ) -> None:\n        \"\"\"Appends an instruction to the detector error model.\n\n        Args:\n            instruction: Either the name of an instruction, a stim.DemInstruction, a\n                stim.DemRepeatBlock. or a stim.DetectorErrorModel. The\n                `parens_arguments`, `targets`, and 'tag' arguments should be given iff\n                the instruction is a name.\n            parens_arguments: Numeric values parameterizing the instruction. The numbers\n                inside parentheses in a detector error model file (eg. the `0.25` in\n                `error(0.25) D0`). This argument can be given either a list of doubles,\n                or a single double (which will be implicitly wrapped into a list).\n            targets: The instruction targets, such as the `D0` in `error(0.25) D0`.\n            tag: An arbitrary piece of text attached to the repeat instruction.\n\n        Examples:\n            >>> import stim\n            >>> m = stim.DetectorErrorModel()\n            >>> m.append(\"error\", 0.125, [\n            ...     stim.DemTarget.relative_detector_id(1),\n            ... ])\n            >>> m.append(\"error\", 0.25, [\n            ...     stim.DemTarget.relative_detector_id(1),\n            ...     stim.DemTarget.separator(),\n            ...     stim.DemTarget.relative_detector_id(2),\n            ...     stim.DemTarget.logical_observable_id(3),\n            ... ], tag='test-tag')\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.125) D1\n                error[test-tag](0.25) D1 ^ D2 L3\n            ''')\n\n            >>> m.append(\"shift_detectors\", (1, 2, 3), [5])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.125) D1\n                error[test-tag](0.25) D1 ^ D2 L3\n                shift_detectors(1, 2, 3) 5\n            ''')\n\n            >>> m += m * 3\n            >>> m.append(m[0])\n            >>> m.append(m[-2])\n            >>> print(repr(m))\n            stim.DetectorErrorModel('''\n                error(0.125) D1\n                error[test-tag](0.25) D1 ^ D2 L3\n                shift_detectors(1, 2, 3) 5\n                repeat 3 {\n                    error(0.125) D1\n                    error[test-tag](0.25) D1 ^ D2 L3\n                    shift_detectors(1, 2, 3) 5\n                }\n                error(0.125) D1\n                repeat 3 {\n                    error(0.125) D1\n                    error[test-tag](0.25) D1 ^ D2 L3\n                    shift_detectors(1, 2, 3) 5\n                }\n            ''')\n        \"\"\"\n    def approx_equals(\n        self,\n        other: object,\n        *,\n        atol: float,\n    ) -> bool:\n        \"\"\"Checks if detector error models are approximately equal.\n\n        Two detector error model are approximately equal if they are equal up to slight\n        perturbations of instruction arguments such as probabilities. For example\n        `error(0.100) D0` is approximately equal to `error(0.099) D0` within an absolute\n        tolerance of 0.002. All other details of the models (such as the ordering of\n        errors and their targets) must be exactly the same.\n\n        Args:\n            other: The detector error model, or other object, to compare to this one.\n            atol: The absolute error tolerance. The maximum amount each probability may\n                have been perturbed by.\n\n        Returns:\n            True if the given object is a detector error model approximately equal up to\n            the receiving circuit up to the given tolerance, otherwise False.\n\n        Examples:\n            >>> import stim\n            >>> base = stim.DetectorErrorModel('''\n            ...    error(0.099) D0 D1\n            ... ''')\n\n            >>> base.approx_equals(base, atol=0)\n            True\n\n            >>> base.approx_equals(stim.DetectorErrorModel('''\n            ...    error(0.101) D0 D1\n            ... '''), atol=0)\n            False\n\n            >>> base.approx_equals(stim.DetectorErrorModel('''\n            ...    error(0.101) D0 D1\n            ... '''), atol=0.0001)\n            False\n\n            >>> base.approx_equals(stim.DetectorErrorModel('''\n            ...    error(0.101) D0 D1\n            ... '''), atol=0.01)\n            True\n\n            >>> base.approx_equals(stim.DetectorErrorModel('''\n            ...    error(0.099) D0 D1 L0 L1 L2 L3 L4\n            ... '''), atol=9999)\n            False\n        \"\"\"\n    def clear(\n        self,\n    ) -> None:\n        \"\"\"Clears the contents of the detector error model.\n\n        Examples:\n            >>> import stim\n            >>> model = stim.DetectorErrorModel('''\n            ...    error(0.1) D0 D1\n            ... ''')\n            >>> model.clear()\n            >>> model\n            stim.DetectorErrorModel()\n        \"\"\"\n    def compile_sampler(\n        self,\n        *,\n        seed: object = None,\n    ) -> stim.CompiledDemSampler:\n        \"\"\"Returns a CompiledDemSampler that can batch sample from detector error models.\n\n        Args:\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                shots are taken. For example, taking 10 shots and then 90 shots will\n                give different results from taking 100 shots in one call.\n\n        Returns:\n            A seeded stim.CompiledDemSampler for the given detector error model.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...    error(0) D0\n            ...    error(1) D1 D2 L0\n            ... ''')\n            >>> sampler = dem.compile_sampler()\n            >>> det_data, obs_data, err_data = sampler.sample(\n            ...     shots=4,\n            ...     return_errors=True)\n            >>> det_data\n            array([[False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True],\n                   [False,  True,  True]])\n            >>> obs_data\n            array([[ True],\n                   [ True],\n                   [ True],\n                   [ True]])\n            >>> err_data\n            array([[False,  True],\n                   [False,  True],\n                   [False,  True],\n                   [False,  True]])\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns a copy of the detector error model.\n\n        The copy is an independent detector error model with the same contents.\n\n        Examples:\n            >>> import stim\n\n            >>> c1 = stim.DetectorErrorModel(\"error(0.1) D0 D1\")\n            >>> c2 = c1.copy()\n            >>> c2 is c1\n            False\n            >>> c2 == c1\n            True\n        \"\"\"\n    def diagram(\n        self,\n        type: Literal[\"matchgraph-svg\", \"matchgraph-svg-html\", \"matchgraph-3d\", \"matchgraph-3d-html\"] = 'matchgraph-svg',\n    ) -> Any:\n        \"\"\"Returns a diagram of the circuit, from a variety of options.\n\n        Args:\n            type: The type of diagram. Available types are:\n                \"matchgraph-svg\": An image of the decoding graph of the\n                    detector error model. Red lines are errors crossing a\n                    logical observable. Blue lines are undecomposed hyper\n                    errors.\n                \"matchgraph-svg-html\": Same as matchgraph-svg but with the\n                    SVG wrapped in a resizable HTML iframe.\n                \"matchgraph-3d\": A 3d model of the decoding graph of the\n                    detector error model. Red lines are errors crossing a\n                    logical observable. Blue lines are undecomposed hyper\n                    errors.\n\n                    GLTF files can be opened with a variety of programs, or\n                    opened online in viewers such as\n                    https://gltf-viewer.donmccurdy.com/ . Red lines are\n                    errors crossing a logical observable.\n                \"matchgraph-3d-html\": Same 3d model as 'match-graph-3d' but\n                    embedded into an HTML web page containing an interactive\n                    THREE.js viewer for the 3d model.\n\n        Returns:\n            An object whose `__str__` method returns the diagram, so that\n            writing the diagram to a file works correctly. The returned\n            object also defines a `_repr_html_` method, so that ipython\n            notebooks recognize it can be shown using a specialized\n            viewer instead of as raw text.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> circuit = stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     rounds=10,\n            ...     distance=7,\n            ...     after_clifford_depolarization=0.01)\n            >>> dem = circuit.detector_error_model(decompose_errors=True)\n\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     diagram = circuit.diagram(\"match-graph-svg\")\n            ...     with open(f\"{d}/dem_image.svg\", \"w\") as f:\n            ...         print(diagram, file=f)\n\n            >>> with tempfile.TemporaryDirectory() as d:\n            ...     diagram = circuit.diagram(\"match-graph-3d\")\n            ...     with open(f\"{d}/dem_3d_model.gltf\", \"w\") as f:\n            ...         print(diagram, file=f)\n        \"\"\"\n    def flattened(\n        self,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns the detector error model without repeat or detector_shift instructions.\n\n        Returns:\n            A `stim.DetectorErrorModel` with the same errors in the same order, but with\n            repeat loops flattened into actually repeated instructions and with all\n            coordinate/index shifts inlined.\n\n        Examples:\n            >>> import stim\n            >>> stim.DetectorErrorModel('''\n            ...     error(0.125) D0\n            ...     REPEAT 5 {\n            ...         error(0.25) D0 D1\n            ...         shift_detectors 1\n            ...     }\n            ...     error(0.125) D0 L0\n            ... ''').flattened()\n            stim.DetectorErrorModel('''\n                error(0.125) D0\n                error(0.25) D0 D1\n                error(0.25) D1 D2\n                error(0.25) D2 D3\n                error(0.25) D3 D4\n                error(0.25) D4 D5\n                error(0.125) D5 L0\n            ''')\n        \"\"\"\n    @staticmethod\n    def from_file(\n        file: Union[io.TextIOBase, str, pathlib.Path],\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Reads a detector error model from a file.\n\n        The file format is defined at\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n        Args:\n            file: A file path or open file object to read from.\n\n        Returns:\n            The circuit parsed from the file.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         print('error(0.25) D2 D3', file=f)\n            ...     circuit = stim.DetectorErrorModel.from_file(path)\n            >>> circuit\n            stim.DetectorErrorModel('''\n                error(0.25) D2 D3\n            ''')\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         print('error(0.25) D2 D3', file=f)\n            ...     with open(path) as f:\n            ...         circuit = stim.DetectorErrorModel.from_file(f)\n            >>> circuit\n            stim.DetectorErrorModel('''\n                error(0.25) D2 D3\n            ''')\n        \"\"\"\n    def get_detector_coordinates(\n        self,\n        only: object = None,\n    ) -> Dict[int, List[float]]:\n        \"\"\"Returns the coordinate metadata of detectors in the detector error model.\n\n        Args:\n            only: Defaults to None (meaning include all detectors). A list of detector\n                indices to include in the result. Detector indices beyond the end of the\n                detector error model cause an error.\n\n        Returns:\n            A dictionary mapping integers (detector indices) to lists of floats\n            (coordinates). Detectors with no specified coordinate data are mapped to an\n            empty tuple. If `only` is specified, then `set(result.keys()) == set(only)`.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...    error(0.25) D0 D1\n            ...    detector(1, 2, 3) D1\n            ...    shift_detectors(5) 1\n            ...    detector(1, 2) D2\n            ... ''')\n            >>> dem.get_detector_coordinates()\n            {0: [], 1: [1.0, 2.0, 3.0], 2: [], 3: [6.0, 2.0]}\n            >>> dem.get_detector_coordinates(only=[1])\n            {1: [1.0, 2.0, 3.0]}\n        \"\"\"\n    @property\n    def num_detectors(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of detectors (e.g. `D2`) in the error model.\n\n        Detector indices are assumed to be contiguous from 0 up to whatever the maximum\n        detector id is. If the largest detector's absolute id is n-1, then the number of\n        detectors is n.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     X_ERROR(0.125) 0\n            ...     X_ERROR(0.25) 1\n            ...     CORRELATED_ERROR(0.375) X0 X1\n            ...     M 0 1\n            ...     DETECTOR rec[-2]\n            ...     DETECTOR rec[-1]\n            ... ''').detector_error_model().num_detectors\n            2\n\n            >>> stim.DetectorErrorModel('''\n            ...    error(0.1) D0 D199\n            ... ''').num_detectors\n            200\n\n            >>> stim.DetectorErrorModel('''\n            ...    shift_detectors 1000\n            ...    error(0.1) D0 D199\n            ... ''').num_detectors\n            1200\n        \"\"\"\n    @property\n    def num_errors(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of errors (e.g. `error(0.1) D0`) in the error model.\n\n        Error instructions inside repeat blocks count once per repetition.\n        Redundant errors with the same targets count as separate errors.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.DetectorErrorModel('''\n            ...     error(0.125) D0\n            ...     repeat 100 {\n            ...         repeat 5 {\n            ...             error(0.25) D1\n            ...         }\n            ...     }\n            ... ''').num_errors\n            501\n        \"\"\"\n    @property\n    def num_observables(\n        self,\n    ) -> int:\n        \"\"\"Counts the number of frame changes (e.g. `L2`) in the error model.\n\n        Observable indices are assumed to be contiguous from 0 up to whatever the\n        maximum observable id is. If the largest observable's id is n-1, then the number\n        of observables is n.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Circuit('''\n            ...     X_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(99) rec[-1]\n            ... ''').detector_error_model().num_observables\n            100\n\n            >>> stim.DetectorErrorModel('''\n            ...    error(0.1) L399\n            ... ''').num_observables\n            400\n        \"\"\"\n    def rounded(\n        self,\n        arg0: int,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Creates an equivalent detector error model but with rounded error probabilities.\n\n        Args:\n            digits: The number of digits to round to.\n\n        Returns:\n            A `stim.DetectorErrorModel` with the same instructions in the same order,\n            but with the parens arguments of error instructions rounded to the given\n            precision.\n\n            Instructions whose error probability was rounded to zero are still\n            included in the output.\n\n        Examples:\n            >>> import stim\n            >>> dem = stim.DetectorErrorModel('''\n            ...     error(0.019499) D0\n            ...     error(0.000001) D0 D1\n            ... ''')\n\n            >>> dem.rounded(2)\n            stim.DetectorErrorModel('''\n                error(0.02) D0\n                error(0) D0 D1\n            ''')\n\n            >>> dem.rounded(3)\n            stim.DetectorErrorModel('''\n                error(0.019) D0\n                error(0) D0 D1\n            ''')\n        \"\"\"\n    def shortest_graphlike_error(\n        self,\n        ignore_ungraphlike_errors: bool = True,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Finds a minimum set of graphlike errors to produce an undetected logical error.\n\n        Note that this method does not pay attention to error probabilities (other than\n        ignoring errors with probability 0). It searches for a logical error with the\n        minimum *number* of physical errors, not the maximum probability of those\n        physical errors all occurring.\n\n        This method works by looking for errors that have frame changes (eg.\n        \"error(0.1) D0 D1 L5\" flips the frame of observable 5). These errors are\n        converted into one or two symptoms and a net frame change. The symptoms can then\n        be moved around by following errors touching that symptom. Each symptom is moved\n        until it disappears into a boundary or cancels against another remaining\n        symptom, while leaving the other symptoms alone (ensuring only one symptom is\n        allowed to move significantly reduces waste in the search space). Eventually a\n        path or cycle of errors is found that cancels out the symptoms, and if there is\n        still a frame change at that point then that path or cycle is a logical error\n        (otherwise all that was found was a stabilizer of the system; a dead end). The\n        search process advances like a breadth first search, seeded from all the\n        frame-change errors and branching them outward in tandem, until one of them wins\n        the race to find a solution.\n\n        Args:\n            ignore_ungraphlike_errors: Defaults to True. When False, an exception is\n                raised if there are any errors in the model that are not graphlike. When\n                True, those errors are skipped as if they weren't present.\n\n                A graphlike error is an error with less than two symptoms. For the\n                purposes of this method, errors are also considered graphlike if they\n                are decomposed into graphlike components:\n\n                graphlike:\n                    error(0.1) D0\n                    error(0.1) D0 D1\n                    error(0.1) D0 D1 L0\n                not graphlike but decomposed into graphlike components:\n                    error(0.1) D0 D1 ^ D2\n                not graphlike, not decomposed into graphlike components:\n                    error(0.1) D0 D1 D2\n                    error(0.1) D0 D1 D2 ^ D3\n\n        Returns:\n            A detector error model containing just the error instructions corresponding\n            to an undetectable logical error. There will be no other kinds of\n            instructions (no `repeat`s, no `shift_detectors`, etc). The error\n            probabilities will all be set to 1.\n\n            The `len` of the returned model is the graphlike code distance of the\n            circuit. But beware that in general the true code distance may be smaller.\n            For example, in the XZ surface code with twists, the true minimum sized\n            logical error is likely to use Y errors. But each Y error decomposes into\n            two graphlike components (the X part and the Z part). As a result, the\n            graphlike code distance in that context is likely to be nearly twice as\n            large as the true code distance.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.DetectorErrorModel('''\n            ...     error(0.125) D0\n            ...     error(0.125) D0 D1\n            ...     error(0.125) D1 L55\n            ...     error(0.125) D1\n            ... ''').shortest_graphlike_error()\n            stim.DetectorErrorModel('''\n                error(1) D1\n                error(1) D1 L55\n            ''')\n\n            >>> stim.DetectorErrorModel('''\n            ...     error(0.125) D0 D1 D2\n            ...     error(0.125) L0\n            ... ''').shortest_graphlike_error(ignore_ungraphlike_errors=True)\n            stim.DetectorErrorModel('''\n                error(1) L0\n            ''')\n\n            >>> circuit = stim.Circuit.generated(\n            ...     \"repetition_code:memory\",\n            ...     rounds=10,\n            ...     distance=7,\n            ...     before_round_data_depolarization=0.01)\n            >>> model = circuit.detector_error_model(decompose_errors=True)\n            >>> len(model.shortest_graphlike_error())\n            7\n        \"\"\"\n    def to_file(\n        self,\n        file: Union[io.TextIOBase, str, pathlib.Path],\n    ) -> None:\n        \"\"\"Writes the detector error model to a file.\n\n        The file format is defined at\n        https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n        Args:\n            file: A file path or an open file to write to.\n\n        Examples:\n            >>> import stim\n            >>> import tempfile\n            >>> c = stim.DetectorErrorModel('error(0.25) D2 D3')\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     with open(path, 'w') as f:\n            ...         c.to_file(f)\n            ...     with open(path) as f:\n            ...         contents = f.read()\n            >>> contents\n            'error(0.25) D2 D3\\n'\n\n            >>> with tempfile.TemporaryDirectory() as tmpdir:\n            ...     path = tmpdir + '/tmp.stim'\n            ...     c.to_file(path)\n            ...     with open(path) as f:\n            ...         contents = f.read()\n            >>> contents\n            'error(0.25) D2 D3\\n'\n        \"\"\"\n    def without_tags(\n        self,\n    ) -> stim.DetectorErrorModel:\n        \"\"\"Returns a copy of the detector error model with all tags removed.\n\n        Returns:\n            A `stim.DetectorErrorModel` with the same instructions except all tags have\n            been removed.\n\n        Examples:\n            >>> import stim\n            >>> stim.DetectorErrorModel('''\n            ...     error[test-tag](0.25) D0\n            ... ''').without_tags()\n            stim.DetectorErrorModel('''\n                error(0.25) D0\n            ''')\n        \"\"\"\nclass ExplainedError:\n    \"\"\"Describes the location of an error mechanism from a stim circuit.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     R 0\n        ...     TICK\n        ...     Y_ERROR(0.125) 0\n        ...     M 0\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> print(err[0])\n        ExplainedError {\n            dem_error_terms: L0\n            CircuitErrorLocation {\n                flipped_pauli_product: Y0\n                Circuit location stack trace:\n                    (after 1 TICKs)\n                    at instruction #3 (Y_ERROR) in the circuit\n                    at target #1 of the instruction\n                    resolving to Y_ERROR(0.125) 0\n            }\n        }\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        dem_error_terms: List[stim.DemTargetWithCoords],\n        circuit_error_locations: List[stim.CircuitErrorLocation],\n    ) -> None:\n        \"\"\"Creates a stim.ExplainedError.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> print(err[0])\n            ExplainedError {\n                dem_error_terms: L0\n                CircuitErrorLocation {\n                    flipped_pauli_product: Y0\n                    Circuit location stack trace:\n                        (after 1 TICKs)\n                        at instruction #3 (Y_ERROR) in the circuit\n                        at target #1 of the instruction\n                        resolving to Y_ERROR(0.125) 0\n                }\n            }\n        \"\"\"\n    @property\n    def circuit_error_locations(\n        self,\n    ) -> List[stim.CircuitErrorLocation]:\n        \"\"\"The locations of circuit errors that produce the symptoms in dem_error_terms.\n\n        Note: if this list contains a single entry, it may be because a result\n        with a single representative error was requested (as opposed to all possible\n        errors).\n\n        Note: if this list is empty, it may be because there was a DEM error decomposed\n        into parts where one of the parts is impossible to make on its own from a single\n        circuit error.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     R 0\n            ...     TICK\n            ...     Y_ERROR(0.125) 0\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> print(err[0].circuit_error_locations[0])\n            CircuitErrorLocation {\n                flipped_pauli_product: Y0\n                Circuit location stack trace:\n                    (after 1 TICKs)\n                    at instruction #3 (Y_ERROR) in the circuit\n                    at target #1 of the instruction\n                    resolving to Y_ERROR(0.125) 0\n            }\n        \"\"\"\n    @property\n    def dem_error_terms(\n        self,\n    ) -> List[stim.DemTargetWithCoords]:\n        \"\"\"The detectors and observables flipped by this error mechanism.\n        \"\"\"\nclass FlipSimulator:\n    \"\"\"A simulator that tracks whether things are flipped, instead of what they are.\n\n    Tracking flips is significantly cheaper than tracking actual values, requiring\n    O(1) work per gate (compared to O(n) for unitary operations and O(n^2) for\n    collapsing operations in the tableau simulator, where n is the qubit count).\n\n    Supports interactive usage, where gates and measurements are applied on demand.\n\n    Examples:\n        >>> import stim\n        >>> sim = stim.FlipSimulator(batch_size=256)\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        batch_size: int,\n        disable_stabilizer_randomization: bool = False,\n        num_qubits: int = 0,\n        seed: Optional[int] = None,\n    ) -> None:\n        \"\"\"Initializes a stim.FlipSimulator.\n\n        Args:\n            batch_size: For speed, the flip simulator simulates many instances in\n                parallel. This argument determines the number of parallel instances.\n\n                It's recommended to use a multiple of 256, because internally the state\n                of the instances is striped across SSE (128 bit) or AVX (256 bit)\n                words with one bit in the word belonging to each instance. The result is\n                that, even if you only ask for 1 instance, probably the same amount of\n                work is being done as if you'd asked for 256 instances. The extra\n                results just aren't being used, creating waste.\n\n            disable_stabilizer_randomization: Determines whether or not the flip\n                simulator uses stabilizer randomization. Defaults to False (stabilizer\n                randomization used). Set to True to disable stabilizer randomization.\n\n                Stabilizer randomization means that, when a qubit is initialized or\n                measured in the Z basis, a Z error is added to the qubit with 50%\n                probability. More generally, anytime a stabilizer is introduced into\n                the system by any means, an error equal to that stabilizer is applied\n                with 50% probability. This ensures that observables anticommuting with\n                stabilizers of the system must be maximally uncertain. In other words,\n                this feature enforces Heisenberg's uncertainty principle.\n\n                This is a safety feature that you should not turn off unless you have a\n                reason to do so. Stabilizer randomization is turned on by default\n                because it catches mistakes. For example, suppose you are trying to\n                create a stabilizer code but you accidentally have the code measure two\n                anticommuting stabilizers. With stabilizer randomization turned off, it\n                will look like this code works. With stabilizer randomization turned on,\n                the two measurements will correctly randomize each other revealing that\n                the code doesn't work.\n\n                In some use cases, stabilizer randomization is a hindrance instead of\n                helpful. For example, if you are using the flip simulator to understand\n                how an error propagates through the system, the stabilizer randomization\n                will be introducing error terms that you don't want.\n\n            num_qubits: Sets the initial number of qubits tracked by the simulation.\n                The simulator will still automatically resize as needed when qubits\n                beyond this limit are touched.\n\n                This parameter exists as a way to hint at the desired size of the\n                simulator's state for performance, and to ensure methods that\n                peek at the size have the expected size from the start instead of\n                only after the relevant qubits have been touched.\n\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                circuit is executed. For example, reordering whether a reset on one\n                qubit happens before or after a reset on another qubit can result in\n                different measurement results being observed starting from the same\n                seed.\n\n        Returns:\n            An initialized stim.FlipSimulator.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n        \"\"\"\n    def append_measurement_flips(\n        self,\n        measurement_flip_data: np.ndarray,\n    ) -> None:\n        \"\"\"Appends measurement flip data to the simulator's measurement record.\n\n        Args:\n            measurement_flip_data: The flip data to append. The following shape/dtype\n                combinations are supported.\n\n                Single measurement without bit packing:\n                    shape=(self.batch_size,)\n                    dtype=np.bool_\n\n                Single measurement with bit packing:\n                    shape=(math.ceil(self.batch_size / 8),)\n                    dtype=np.uint8\n\n                Multiple measurements without bit packing:\n                    shape=(num_measurements, self.batch_size)\n                    dtype=np.bool_\n\n                Multiple measurements with bit packing:\n                    shape=(num_measurements, math.ceil(self.batch_size / 8))\n                    dtype=np.uint8\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.append_measurement_flips(np.array(\n            ...     [0, 1, 0, 0, 1, 0, 0, 1, 1],\n            ...     dtype=np.bool_,\n            ... ))\n\n            >>> sim.get_measurement_flips()\n            array([[False,  True, False, False,  True, False, False,  True,  True]])\n\n            >>> sim.append_measurement_flips(np.array(\n            ...     [0b11001001, 0],\n            ...     dtype=np.uint8,\n            ... ))\n\n            >>> sim.get_measurement_flips()\n            array([[False,  True, False, False,  True, False, False,  True,  True],\n                   [ True, False, False,  True, False, False,  True,  True, False]])\n\n            >>> sim.append_measurement_flips(np.array(\n            ...     [[0b11111111, 0b1], [0b00000000, 0b0], [0b11111111, 0b1]],\n            ...     dtype=np.uint8,\n            ... ))\n\n            >>> sim.get_measurement_flips()\n            array([[False,  True, False, False,  True, False, False,  True,  True],\n                   [ True, False, False,  True, False, False,  True,  True, False],\n                   [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n                   [False, False, False, False, False, False, False, False, False],\n                   [ True,  True,  True,  True,  True,  True,  True,  True,  True]])\n\n            >>> sim.append_measurement_flips(np.array(\n            ...     [[1, 0, 1, 0, 1, 0, 1, 0, 1], [0, 1, 0, 1, 0, 1, 0, 1, 0]],\n            ...     dtype=np.bool_,\n            ... ))\n\n            >>> sim.get_measurement_flips()\n            array([[False,  True, False, False,  True, False, False,  True,  True],\n                   [ True, False, False,  True, False, False,  True,  True, False],\n                   [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n                   [False, False, False, False, False, False, False, False, False],\n                   [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n                   [ True, False,  True, False,  True, False,  True, False,  True],\n                   [False,  True, False,  True, False,  True, False,  True, False]])\n        \"\"\"\n    @property\n    def batch_size(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of instances being simulated by the simulator.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.batch_size\n            256\n            >>> sim = stim.FlipSimulator(batch_size=42)\n            >>> sim.batch_size\n            42\n        \"\"\"\n    def broadcast_pauli_errors(\n        self,\n        *,\n        pauli: Union[str, int],\n        mask: np.ndarray,\n        p: float = 1,\n    ) -> None:\n        \"\"\"Applies a pauli error to all qubits in all instances, filtered by a mask.\n\n        Args:\n            pauli: The pauli, specified as an integer or string.\n                Uses the convention 0=I, 1=X, 2=Y, 3=Z.\n                Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.\n            mask: A 2d numpy array specifying where to apply errors. The first axis\n                is qubits, the second axis is simulation instances. The first axis\n                can have a length less than the current number of qubits (or more,\n                which adds qubits to the simulation). The length of the second axis\n                must match the simulator's `batch_size`. The array must satisfy\n\n                    mask.dtype == np.bool_\n                    len(mask.shape) == 2\n                    mask.shape[1] == flip_sim.batch_size\n\n                The error is only applied to qubit q in instance k when\n\n                    mask[q, k] == True.\n            p: Defaults to 1 (no effect). When specified, the error is applied\n                probabilistically instead of deterministically to each (instance, qubit)\n                pair matching the mask. This argument specifies the probability.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=2,\n            ...     num_qubits=3,\n            ...     disable_stabilizer_randomization=True,\n            ... )\n            >>> sim.broadcast_pauli_errors(\n            ...     pauli='X',\n            ...     mask=np.asarray([[True, False],[False, False],[True, True]]),\n            ... )\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+X_X\"), stim.PauliString(\"+__X\")]\n\n            >>> sim.broadcast_pauli_errors(\n            ...     pauli='Z',\n            ...     mask=np.asarray([[False, True],[False, False],[True, True]]),\n            ... )\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+X_Y\"), stim.PauliString(\"+Z_Y\")]\n        \"\"\"\n    def clear(\n        self,\n    ) -> None:\n        \"\"\"Clears the simulator's state, so it can be reused for another simulation.\n\n        This clears the measurement flip history, clears the detector flip history,\n        and zeroes the observable flip state. It also resets all qubits to |0>. If\n        stabilizer randomization is disabled, this zeros all pauli flip data. Otherwise\n        it randomizes all pauli flips to be I or Z with equal probability.\n\n        Behind the scenes, this doesn't free memory or resize the simulator. So,\n        repeating the same simulation with calls to `clear` in between will be faster\n        than allocating a new simulator each time (by avoiding re-allocations).\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.do(stim.Circuit(\"M(0.1) 9\"))\n            >>> sim.num_qubits\n            10\n            >>> sim.get_measurement_flips().shape\n            (1, 256)\n\n            >>> sim.clear()\n            >>> sim.num_qubits\n            10\n            >>> sim.get_measurement_flips().shape\n            (0, 256)\n        \"\"\"\n    def copy(\n        self,\n        *,\n        copy_rng: bool = False,\n        seed: Optional[int] = None,\n    ) -> stim.FlipSimulator:\n        \"\"\"Returns a simulator with the same internal state, except perhaps its prng.\n\n        Args:\n            copy_rng: Defaults to False. When False, the copy's pseudo random number\n                generator is reinitialized with a random seed instead of being a copy\n                of the original simulator's pseudo random number generator. This\n                causes the copy and the original to sample independent randomness,\n                instead of identical randomness, for future random operations. When set\n                to true, the copy will have the exact same pseudo random number\n                generator state as the original, and so will produce identical results\n                if told to do the same noisy operations. This argument is incompatible\n                with the `seed` argument.\n\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng state is either copied from the\n                original simulator or reseeded from system entropy, depending on the\n                copy_rng argument.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                circuit is executed. For example, reordering whether a reset on one\n                qubit happens before or after a reset on another qubit can result in\n                different measurement results being observed starting from the same\n                seed.\n\n        Returns:\n            The copy of the simulator.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n\n            >>> s1 = stim.FlipSimulator(batch_size=256)\n            >>> s1.set_pauli_flip('X', qubit_index=2, instance_index=3)\n            >>> s2 = s1.copy()\n            >>> s2 is s1\n            False\n            >>> s2.peek_pauli_flips() == s1.peek_pauli_flips()\n            True\n\n            >>> s1 = stim.FlipSimulator(batch_size=256)\n            >>> s2 = s1.copy(copy_rng=True)\n            >>> s1.do(stim.Circuit(\"X_ERROR(0.25) 0 \\n M 0\"))\n            >>> s2.do(stim.Circuit(\"X_ERROR(0.25) 0 \\n M 0\"))\n            >>> np.array_equal(s1.get_measurement_flips(), s2.get_measurement_flips())\n            True\n        \"\"\"\n    def do(\n        self,\n        obj: Union[stim.Circuit, stim.CircuitInstruction, stim.CircuitRepeatBlock],\n    ) -> None:\n        \"\"\"Applies a circuit or circuit instruction to the simulator's state.\n\n        The results of any measurements performed can be retrieved using the\n        `get_measurement_flips` method.\n\n        Args:\n            obj: The circuit or instruction to apply to the simulator's state.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=1,\n            ...     disable_stabilizer_randomization=True,\n            ... )\n            >>> circuit = stim.Circuit('''\n            ...     X_ERROR(1) 0 1 3\n            ...     REPEAT 5 {\n            ...         H 0\n            ...         C_XYZ 1\n            ...     }\n            ... ''')\n            >>> sim.do(circuit)\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+ZZ_X\")]\n\n            >>> sim.do(circuit[0])\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+YY__\")]\n\n            >>> sim.do(circuit[1])\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+YX__\")]\n        \"\"\"\n    def generate_bernoulli_samples(\n        self,\n        num_samples: int,\n        *,\n        p: float,\n        bit_packed: bool = False,\n        out: Optional[np.ndarray] = None,\n    ) -> np.ndarray:\n        \"\"\"Uses the simulator's random number generator to produce biased coin flips.\n\n        This method has best performance when specifying `bit_packed=True` and\n        when specifying an `out=` parameter pointing to a numpy array that has\n        contiguous data aligned to a 64 bit boundary. (If `out` isn't specified,\n        the returned numpy array will have this property.)\n\n        Args:\n            num_samples: The number of samples to produce.\n            p: The probability of each sample being True instead of False.\n            bit_packed: Defaults to False (no bit packing). When True, the result\n                has type np.uint8 instead of np.bool_ and 8 samples are packed into\n                each byte as if by np.packbits(bitorder='little'). (The bit order\n                is relevant when producing a number of samples that isn't a multiple\n                of 8.)\n            out: Defaults to None (allocate new). A numpy array to write the samples\n                into. Must have the correct size and dtype.\n\n        Returns:\n            A numpy array containing the samples. The shape and dtype depends on\n            the bit_packed argument:\n\n                if not bit_packed:\n                    shape = (num_samples,)\n                    dtype = np.bool_\n                elif not transpose and bit_packed:\n                    shape = (math.ceil(num_samples / 8),)\n                    dtype = np.uint8\n\n        Raises:\n            ValueError:\n                The given `out` argument had a shape or dtype inconsistent with the\n                requested data.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> r = sim.generate_bernoulli_samples(1001, p=0.25)\n            >>> r.dtype\n            dtype('bool')\n            >>> r.shape\n            (1001,)\n\n            >>> r = sim.generate_bernoulli_samples(53, p=0.1, bit_packed=True)\n            >>> r.dtype\n            dtype('uint8')\n            >>> r.shape\n            (7,)\n            >>> r[6] & 0b1110_0000  # zero'd padding bits\n            np.uint8(0)\n\n            >>> r2 = sim.generate_bernoulli_samples(53, p=0.2, bit_packed=True, out=r)\n            >>> r is r2  # Check request to reuse r worked.\n            True\n        \"\"\"\n    def get_detector_flips(\n        self,\n        *,\n        detector_index: Optional[int] = None,\n        instance_index: Optional[int] = None,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Retrieves detector flip data from the simulator's detection event record.\n\n        Args:\n            record_index: Identifies a detector to read results from.\n                Setting this to None (default) returns results from all detectors.\n                Otherwise this should be an integer in range(0, self.num_detectors).\n            instance_index: Identifies a simulation instance to read results from.\n                Setting this to None (the default) returns results from all instances.\n                Otherwise this should be an integer in range(0, self.batch_size).\n            bit_packed: Defaults to False. Determines whether the result is bit packed.\n                If this is set to true, the returned numpy array will be bit packed as\n                if by applying\n\n                    out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n                Behind the scenes the data is always bit packed, so setting this\n                argument avoids ever unpacking in the first place. This substantially\n                improves performance when there is a lot of data.\n\n        Returns:\n            A numpy array containing the requested data. By default this is a 2d array\n            of shape (self.num_detectors, self.batch_size), where the first index is\n            the detector_index and the second index is the instance_index and the\n            dtype is np.bool_.\n\n            Specifying detector_index slices away the first index, leaving a 1d array\n            with only an instance_index.\n\n            Specifying instance_index slices away the last index, leaving a 1d array\n            with only a detector_index (or a 0d array, a boolean, if detector_index\n            was also specified).\n\n            Specifying bit_packed=True bit packs the last remaining index, changing\n            the dtype to np.uint8.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.do(stim.Circuit('''\n            ...     M 0 0 0\n            ...     DETECTOR rec[-2] rec[-3]\n            ...     DETECTOR rec[-1] rec[-2]\n            ... '''))\n\n            >>> sim.get_detector_flips()\n            array([[False, False, False, False, False, False, False, False, False],\n                   [False, False, False, False, False, False, False, False, False]])\n\n            >>> sim.get_detector_flips(bit_packed=True)\n            array([[0, 0],\n                   [0, 0]], dtype=uint8)\n\n            >>> sim.get_detector_flips(instance_index=2)\n            array([False, False])\n\n            >>> sim.get_detector_flips(detector_index=1)\n            array([False, False, False, False, False, False, False, False, False])\n\n            >>> sim.get_detector_flips(instance_index=2, detector_index=1)\n            array(False)\n        \"\"\"\n    def get_measurement_flips(\n        self,\n        *,\n        record_index: Optional[int] = None,\n        instance_index: Optional[int] = None,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Retrieves measurement flip data from the simulator's measurement record.\n\n        Args:\n            record_index: Identifies a measurement to read results from.\n                Setting this to None (default) returns results from all measurements.\n                Setting this to a non-negative integer indexes measurements by the order\n                    they occurred. For example, record index 0 is the first measurement.\n                Setting this to a negative integer indexes measurements by recency.\n                    For example, recording index -1 is the most recent measurement.\n            instance_index: Identifies a simulation instance to read results from.\n                Setting this to None (the default) returns results from all instances.\n                Otherwise this should be set to an integer in range(0, self.batch_size).\n            bit_packed: Defaults to False. Determines whether the result is bit packed.\n                If this is set to true, the returned numpy array will be bit packed as\n                if by applying\n\n                    out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n                Behind the scenes the data is always bit packed, so setting this\n                argument avoids ever unpacking in the first place. This substantially\n                improves performance when there is a lot of data.\n\n        Returns:\n            A numpy array containing the requested data. By default this is a 2d array\n            of shape (self.num_measurements, self.batch_size), where the first index is\n            the measurement_index and the second index is the instance_index and the\n            dtype is np.bool_.\n\n            Specifying record_index slices away the first index, leaving a 1d array\n            with only an instance_index.\n\n            Specifying instance_index slices away the last index, leaving a 1d array\n            with only a measurement_index (or a 0d array, a boolean, if record_index\n            was also specified).\n\n            Specifying bit_packed=True bit packs the last remaining index, changing\n            the dtype to np.uint8.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.do(stim.Circuit('M 0 1 2'))\n\n            >>> sim.get_measurement_flips()\n            array([[False, False, False, False, False, False, False, False, False],\n                   [False, False, False, False, False, False, False, False, False],\n                   [False, False, False, False, False, False, False, False, False]])\n\n            >>> sim.get_measurement_flips(bit_packed=True)\n            array([[0, 0],\n                   [0, 0],\n                   [0, 0]], dtype=uint8)\n\n            >>> sim.get_measurement_flips(instance_index=1)\n            array([False, False, False])\n\n            >>> sim.get_measurement_flips(record_index=2)\n            array([False, False, False, False, False, False, False, False, False])\n\n            >>> sim.get_measurement_flips(instance_index=1, record_index=2)\n            array(False)\n        \"\"\"\n    def get_observable_flips(\n        self,\n        *,\n        observable_index: Optional[int] = None,\n        instance_index: Optional[int] = None,\n        bit_packed: bool = False,\n    ) -> np.ndarray:\n        \"\"\"Retrieves observable flip data from the simulator's detection event record.\n\n        Args:\n            record_index: Identifies a observable to read results from.\n                Setting this to None (default) returns results from all observables.\n                Otherwise this should be an integer in range(0, self.num_observables).\n            instance_index: Identifies a simulation instance to read results from.\n                Setting this to None (the default) returns results from all instances.\n                Otherwise this should be an integer in range(0, self.batch_size).\n            bit_packed: Defaults to False. Determines whether the result is bit packed.\n                If this is set to true, the returned numpy array will be bit packed as\n                if by applying\n\n                    out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n                Behind the scenes the data is always bit packed, so setting this\n                argument avoids ever unpacking in the first place. This substantially\n                improves performance when there is a lot of data.\n\n        Returns:\n            A numpy array containing the requested data. By default this is a 2d array\n            of shape (self.num_observables, self.batch_size), where the first index is\n            the observable_index and the second index is the instance_index and the\n            dtype is np.bool_.\n\n            Specifying observable_index slices away the first index, leaving a 1d array\n            with only an instance_index.\n\n            Specifying instance_index slices away the last index, leaving a 1d array\n            with only a observable_index (or a 0d array, a boolean, if observable_index\n            was also specified).\n\n            Specifying bit_packed=True bit packs the last remaining index, changing\n            the dtype to np.uint8.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.do(stim.Circuit('''\n            ...     M 0 0 0\n            ...     OBSERVABLE_INCLUDE(0) rec[-2]\n            ...     OBSERVABLE_INCLUDE(1) rec[-1]\n            ... '''))\n\n            >>> sim.get_observable_flips()\n            array([[False, False, False, False, False, False, False, False, False],\n                   [False, False, False, False, False, False, False, False, False]])\n\n            >>> sim.get_observable_flips(bit_packed=True)\n            array([[0, 0],\n                   [0, 0]], dtype=uint8)\n\n            >>> sim.get_observable_flips(instance_index=2)\n            array([False, False])\n\n            >>> sim.get_observable_flips(observable_index=1)\n            array([False, False, False, False, False, False, False, False, False])\n\n            >>> sim.get_observable_flips(instance_index=2, observable_index=1)\n            array(False)\n        \"\"\"\n    @property\n    def num_detectors(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of detectors that have been simulated and stored.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.num_detectors\n            0\n            >>> sim.do(stim.Circuit('''\n            ...     M 0 0\n            ...     DETECTOR rec[-1] rec[-2]\n            ... '''))\n            >>> sim.num_detectors\n            1\n        \"\"\"\n    @property\n    def num_measurements(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of measurements that have been simulated and stored.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.num_measurements\n            0\n            >>> sim.do(stim.Circuit('M 3 5'))\n            >>> sim.num_measurements\n            2\n        \"\"\"\n    @property\n    def num_observables(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of observables currently tracked by the simulator.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.num_observables\n            0\n            >>> sim.do(stim.Circuit('''\n            ...     M 0\n            ...     OBSERVABLE_INCLUDE(4) rec[-1]\n            ... '''))\n            >>> sim.num_observables\n            5\n        \"\"\"\n    @property\n    def num_qubits(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of qubits currently tracked by the simulator.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(batch_size=256)\n            >>> sim.num_qubits\n            0\n            >>> sim = stim.FlipSimulator(batch_size=256, num_qubits=4)\n            >>> sim.num_qubits\n            4\n            >>> sim.do(stim.Circuit('H 5'))\n            >>> sim.num_qubits\n            6\n        \"\"\"\n    @overload\n    def peek_pauli_flips(\n        self,\n    ) -> List[stim.PauliString]:\n        pass\n    @overload\n    def peek_pauli_flips(\n        self,\n        *,\n        instance_index: int,\n    ) -> stim.PauliString:\n        pass\n    def peek_pauli_flips(\n        self,\n        *,\n        instance_index: Optional[int] = None,\n    ) -> Union[stim.PauliString, List[stim.PauliString]]:\n        \"\"\"Returns the current pauli errors packed into stim.PauliString instances.\n\n        Args:\n            instance_index: Defaults to None. When set to None, the pauli errors from\n                all instances are returned as a list of `stim.PauliString`. When set to\n                an integer, a single `stim.PauliString` is returned containing the\n                errors for the indexed instance.\n\n        Returns:\n            if instance_index is None:\n                A list of stim.PauliString, with the k'th entry being the errors from\n                the k'th simulation instance.\n            else:\n                A stim.PauliString with the errors from the k'th simulation instance.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=2,\n            ...     disable_stabilizer_randomization=True,\n            ...     num_qubits=10,\n            ... )\n\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+__________\"), stim.PauliString(\"+__________\")]\n\n            >>> sim.peek_pauli_flips(instance_index=0)\n            stim.PauliString(\"+__________\")\n\n            >>> sim.do(stim.Circuit('''\n            ...     X_ERROR(1) 0 3 5\n            ...     Z_ERROR(1) 3 6\n            ... '''))\n\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+X__Y_XZ___\"), stim.PauliString(\"+X__Y_XZ___\")]\n\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=1,\n            ...     num_qubits=100,\n            ... )\n            >>> flips: stim.PauliString = sim.peek_pauli_flips(instance_index=0)\n            >>> sorted(set(str(flips)))  # Should have Zs from stabilizer randomization\n            ['+', 'Z', '_']\n        \"\"\"\n    def set_pauli_flip(\n        self,\n        pauli: Union[str, int],\n        *,\n        qubit_index: int,\n        instance_index: int,\n    ) -> None:\n        \"\"\"Sets the pauli flip on a given qubit in a given simulation instance.\n\n        Args:\n            pauli: The pauli, specified as an integer or string.\n                Uses the convention 0=I, 1=X, 2=Y, 3=Z.\n                Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.\n            qubit_index: The qubit to put the error on. Must be non-negative. The state\n                will automatically expand as needed to store the error.\n            instance_index: The simulation index to put the error inside. Use negative\n                indices to index from the end of the list.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.FlipSimulator(\n            ...     batch_size=2,\n            ...     num_qubits=3,\n            ...     disable_stabilizer_randomization=True,\n            ... )\n            >>> sim.set_pauli_flip('X', qubit_index=2, instance_index=1)\n            >>> sim.peek_pauli_flips()\n            [stim.PauliString(\"+___\"), stim.PauliString(\"+__X\")]\n        \"\"\"\n    def to_numpy(\n        self,\n        *,\n        bit_packed: bool = False,\n        transpose: bool = False,\n        output_xs: Union[bool, np.ndarray] = False,\n        output_zs: Union[bool, np.ndarray] = False,\n        output_measure_flips: Union[bool, np.ndarray] = False,\n        output_detector_flips: Union[bool, np.ndarray] = False,\n        output_observable_flips: Union[bool, np.ndarray] = False,\n    ) -> Optional[Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]]:\n        \"\"\"Writes the simulator state into numpy arrays.\n\n        Args:\n            bit_packed: Whether or not the result is bit packed, storing 8 bits per\n                byte instead of 1 bit per byte. Bit packing always applies to\n                the second index of the result. Bits are packed in little endian\n                order (as if by `np.packbits(X, axis=1, order='little')`).\n            transpose: Defaults to False. When set to False, the second index of the\n                returned array (the index affected by bit packing) is the shot index\n                (meaning the first index is the qubit index or measurement index or\n                etc). When set to True, results are transposed so that the first\n                index is the shot index.\n            output_xs: Defaults to False. When set to False, the X flip data is not\n                generated and the corresponding array in the result tuple is set to\n                None. When set to True, a new array is allocated to hold the X flip\n                data and this array is returned via the result tuple. When set to\n                a numpy array, the results are written into that array (the shape and\n                dtype of the array must be exactly correct).\n            output_zs: Defaults to False. When set to False, the Z flip data is not\n                generated and the corresponding array in the result tuple is set to\n                None. When set to True, a new array is allocated to hold the Z flip\n                data and this array is returned via the result tuple. When set to\n                a numpy array, the results are written into that array (the shape and\n                dtype of the array must be exactly correct).\n            output_measure_flips: Defaults to False. When set to False, the measure\n                flip data is not generated and the corresponding array in the result\n                tuple is set to None. When set to True, a new array is allocated to\n                hold the measure flip data and this array is returned via the result\n                tuple. When set to a numpy array, the results are written into that\n                array (the shape and dtype of the array must be exactly correct).\n            output_detector_flips: Defaults to False. When set to False, the detector\n                flip data is not generated and the corresponding array in the result\n                tuple is set to None. When set to True, a new array is allocated to\n                hold the detector flip data and this array is returned via the result\n                tuple. When set to a numpy array, the results are written into that\n                array (the shape and dtype of the array must be exactly correct).\n            output_observable_flips: Defaults to False. When set to False, the obs\n                flip data is not generated and the corresponding array in the result\n                tuple is set to None. When set to True, a new array is allocated to\n                hold the obs flip data and this array is returned via the result\n                tuple. When set to a numpy array, the results are written into that\n                array (the shape and dtype of the array must be exactly correct).\n\n        Returns:\n            A tuple (xs, zs, ms, ds, os) of numpy arrays. The xs and zs arrays are\n            the pauli flip data specified using XZ encoding (00=I, 10=X, 11=Y, 01=Z).\n            The ms array is the measure flip data, the ds array is the detector flip\n            data, and the os array is the obs flip data. The arrays default to\n            `None` when the corresponding `output_*` argument was left False.\n\n            The shape and dtype of the data depends on arguments given to the function.\n            The following specifies each array's shape and dtype for each case:\n\n                if not transpose and not bit_packed:\n                    xs.shape = (sim.batch_size, sim.num_qubits)\n                    zs.shape = (sim.batch_size, sim.num_qubits)\n                    ms.shape = (sim.batch_size, sim.num_measurements)\n                    ds.shape = (sim.batch_size, sim.num_detectors)\n                    os.shape = (sim.batch_size, sim.num_observables)\n                    xs.dtype = np.bool_\n                    zs.dtype = np.bool_\n                    ms.dtype = np.bool_\n                    ds.dtype = np.bool_\n                    os.dtype = np.bool_\n                elif not transpose and bit_packed:\n                    xs.shape = (sim.batch_size, math.ceil(sim.num_qubits / 8))\n                    zs.shape = (sim.batch_size, math.ceil(sim.num_qubits / 8))\n                    ms.shape = (sim.batch_size, math.ceil(sim.num_measurements / 8))\n                    ds.shape = (sim.batch_size, math.ceil(sim.num_detectors / 8))\n                    os.shape = (sim.batch_size, math.ceil(sim.num_observables / 8))\n                    xs.dtype = np.uint8\n                    zs.dtype = np.uint8\n                    ms.dtype = np.uint8\n                    ds.dtype = np.uint8\n                    os.dtype = np.uint8\n                elif transpose and not bit_packed:\n                    xs.shape = (sim.num_qubits, sim.batch_size)\n                    zs.shape = (sim.num_qubits, sim.batch_size)\n                    ms.shape = (sim.num_measurements, sim.batch_size)\n                    ds.shape = (sim.num_detectors, sim.batch_size)\n                    os.shape = (sim.num_observables, sim.batch_size)\n                    xs.dtype = np.bool_\n                    zs.dtype = np.bool_\n                    ms.dtype = np.bool_\n                    ds.dtype = np.bool_\n                    os.dtype = np.bool_\n                elif transpose and bit_packed:\n                    xs.shape = (sim.num_qubits, math.ceil(sim.batch_size / 8))\n                    zs.shape = (sim.num_qubits, math.ceil(sim.batch_size / 8))\n                    ms.shape = (sim.num_measurements, math.ceil(sim.batch_size / 8))\n                    ds.shape = (sim.num_detectors, math.ceil(sim.batch_size / 8))\n                    os.shape = (sim.num_observables, math.ceil(sim.batch_size / 8))\n                    xs.dtype = np.uint8\n                    zs.dtype = np.uint8\n                    ms.dtype = np.uint8\n                    ds.dtype = np.uint8\n                    os.dtype = np.uint8\n\n        Raises:\n            ValueError:\n                All the `output_*` arguments were False, or an `output_*` argument\n                had a shape or dtype inconsistent with the requested data.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> sim = stim.FlipSimulator(batch_size=9)\n            >>> sim.do(stim.Circuit('M(1) 0 1 2'))\n\n            >>> ms_buf = np.empty(shape=(9, 1), dtype=np.uint8)\n            >>> xs, zs, ms, ds, os = sim.to_numpy(\n            ...     transpose=True,\n            ...     bit_packed=True,\n            ...     output_xs=True,\n            ...     output_measure_flips=ms_buf,\n            ... )\n            >>> assert ms is ms_buf\n            >>> xs\n            array([[0],\n                   [0],\n                   [0],\n                   [0],\n                   [0],\n                   [0],\n                   [0],\n                   [0],\n                   [0]], dtype=uint8)\n            >>> zs\n            >>> ms\n            array([[7],\n                   [7],\n                   [7],\n                   [7],\n                   [7],\n                   [7],\n                   [7],\n                   [7],\n                   [7]], dtype=uint8)\n            >>> ds\n            >>> os\n        \"\"\"\nclass FlippedMeasurement:\n    \"\"\"Describes a measurement that was flipped.\n\n    Gives the measurement's index in the measurement record, and also\n    the observable of the measurement.\n\n    Examples:\n        >>> import stim\n        >>> err = stim.Circuit('''\n        ...     M(0.25) 1 10\n        ...     OBSERVABLE_INCLUDE(0) rec[-1]\n        ... ''').shortest_graphlike_error()\n        >>> err[0].circuit_error_locations[0].flipped_measurement\n        stim.FlippedMeasurement(\n            record_index=1,\n            observable=(stim.GateTargetWithCoords(stim.target_z(10), []),),\n        )\n    \"\"\"\n    def __init__(\n        self,\n        measurement_record_index: Optional[int],\n        measured_observable: Iterable[stim.GateTargetWithCoords],\n    ):\n        \"\"\"Creates a stim.FlippedMeasurement.\n\n        Examples:\n            >>> import stim\n            >>> print(stim.FlippedMeasurement(\n            ...     record_index=5,\n            ...     observable=[],\n            ... ))\n            stim.FlippedMeasurement(\n                record_index=5,\n                observable=(),\n            )\n        \"\"\"\n    @property\n    def observable(\n        self,\n    ) -> List[stim.GateTargetWithCoords]:\n        \"\"\"Returns the observable of the flipped measurement.\n\n        For example, an `MX 5` measurement will have the observable X5.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     M(0.25) 1 10\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].flipped_measurement.observable\n            [stim.GateTargetWithCoords(stim.target_z(10), [])]\n        \"\"\"\n    @property\n    def record_index(\n        self,\n    ) -> int:\n        \"\"\"The measurement record index of the flipped measurement.\n        For example, the fifth measurement in a circuit has a measurement\n        record index of 4.\n\n        Examples:\n            >>> import stim\n            >>> err = stim.Circuit('''\n            ...     M(0.25) 1 10\n            ...     OBSERVABLE_INCLUDE(0) rec[-1]\n            ... ''').shortest_graphlike_error()\n            >>> err[0].circuit_error_locations[0].flipped_measurement.record_index\n            1\n        \"\"\"\nclass Flow:\n    \"\"\"A stabilizer flow (e.g. \"XI -> XX xor rec[-1]\").\n\n    Stabilizer circuits implement, and can be defined by, how they turn input\n    stabilizers into output stabilizers mediated by measurements. These\n    relationships are called stabilizer flows, and `stim.Flow` is a representation\n    of such a flow. For example, a `stim.Flow` can be given to\n    `stim.Circuit.has_flow` to verify that a circuit implements the flow.\n\n    A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer\n    P at the start of the circuit to the instantaneous stabilizer Q at the end of\n    the circuit. The flow may be mediated by certain measurements. For example,\n    a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and\n    the CNOT flows implemented by the circuit involve these measurements.\n\n    A flow like P -> Q means the circuit transforms P into Q.\n    A flow like 1 -> P means the circuit prepares P.\n    A flow like P -> 1 means the circuit measures P.\n    A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR).\n\n    References:\n        Stim's gate documentation includes the stabilizer flows of each gate.\n\n        Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are\n        defined and provides a circuit construction for experimentally verifying\n        their presence.\n\n    Examples:\n        >>> import stim\n        >>> c = stim.Circuit(\"CNOT 2 4\")\n\n        >>> c.has_flow(stim.Flow(\"__X__ -> __X_X\"))\n        True\n\n        >>> c.has_flow(stim.Flow(\"X2*X4 -> X2\"))\n        True\n\n        >>> c.has_flow(stim.Flow(\"Z4 -> Z4\"))\n        False\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.Flow,\n    ) -> bool:\n        \"\"\"Determines if two flows have identical contents.\n        \"\"\"\n    def __init__(\n        self,\n        arg: Union[None, str, stim.Flow] = None,\n        /,\n        *,\n        input: Optional[stim.PauliString] = None,\n        output: Optional[stim.PauliString] = None,\n        measurements: Optional[Iterable[Union[int, GateTarget]]] = None,\n        included_observables: Optional[Iterable[int]] = None,\n    ) -> None:\n        \"\"\"Initializes a stim.Flow.\n\n        When given a string, the string is parsed as flow shorthand. For example,\n        the string \"X_ -> ZZ xor rec[-1]\" will result in a flow with input pauli string\n        \"X_\", output pauli string \"ZZ\", and measurement indices [-1].\n\n        Args:\n            arg [position-only]: Defaults to None. Must be specified by itself if used.\n                str: Initializes a flow by parsing the given shorthand text.\n                stim.Flow: Initializes a copy of the given flow.\n                None (default): Initializes an empty flow.\n            input: Defaults to None. Can be set to a stim.PauliString to directly\n                specify the flow's input stabilizer.\n            output: Defaults to None. Can be set to a stim.PauliString to directly\n                specify the flow's output stabilizer.\n            measurements: Defaults to None. Can be set to a list of integers or gate\n                targets like `stim.target_rec(-1)`, to specify the measurements that\n                mediate the flow. Negative and positive measurement indices are allowed.\n                Indexes follow the python convention where -1 is the last measurement in\n                a circuit and 0 is the first measurement in a circuit.\n            included_observables: Defaults to None. `OBSERVABLE_INCLUDE` instructions\n                that target an observable index from this list will be implicitly\n                included in the flow. This allows flows to refer to observables. For\n                example, the flow \"X5 -> obs[3]\" says \"At the start of the circuit,\n                observable 3 should be an X term on qubit 5. By the end of the circuit\n                it will be measured. The `OBSERVABLE_INCLUDE(3)` instructions in the\n                circuit should explain how this happened.\".\n\n        Examples:\n            >>> import stim\n\n            >>> stim.Flow(\"X2 -> -Y2*Z4 xor rec[-1]\")\n            stim.Flow(\"__X -> -__Y_Z xor rec[-1]\")\n\n            >>> stim.Flow(\"Z -> 1 xor rec[-1]\")\n            stim.Flow(\"Z -> rec[-1]\")\n\n            >>> stim.Flow(\n            ...     input=stim.PauliString(\"XX\"),\n            ...     output=stim.PauliString(\"_X\"),\n            ...     measurements=[],\n            ... )\n            stim.Flow(\"XX -> _X\")\n\n            >>> # Identical terms cancel.\n            >>> stim.Flow(\"X2 -> Y2*Y2 xor rec[-2] xor rec[-2]\")\n            stim.Flow(\"__X -> ___\")\n\n            >>> stim.Flow(\"X -> Y xor obs[3] xor obs[3] xor obs[3]\")\n            stim.Flow(\"X -> Y xor obs[3]\")\n        \"\"\"\n    def __mul__(\n        self,\n        rhs: stim.Flow,\n    ) -> stim.Flow:\n        \"\"\"Computes the product of two flows.\n\n        Args:\n            rhs: The right hand side of the multiplication.\n\n        Returns:\n            The product of the two flows.\n\n        Raises:\n            ValueError: The inputs anti-commute (their product would be anti-Hermitian).\n                For example, 1 -> X times 1 -> Y fails because it would give 1 -> iZ.\n\n        Examples:\n            >>> import stim\n            >>> stim.Flow(\"X -> X\") * stim.Flow(\"Z -> Z\")\n            stim.Flow(\"Y -> Y\")\n\n            >>> stim.Flow(\"1 -> XX\") * stim.Flow(\"1 -> ZZ\")\n            stim.Flow(\"1 -> -YY\")\n\n            >>> stim.Flow(\"X -> rec[-1]\") * stim.Flow(\"X -> rec[-2]\")\n            stim.Flow(\"_ -> rec[-2] xor rec[-1]\")\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.Flow,\n    ) -> bool:\n        \"\"\"Determines if two flows have non-identical contents.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.Flow`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a shorthand description of the flow.\n        \"\"\"\n    def included_observables_copy(\n        self,\n    ) -> List[int]:\n        \"\"\"Returns a copy of the flow's included observable indices.\n\n        When an observable is included in a flow, the flow implicitly includes all\n        measurements and pauli terms from `OBSERVABLE_INCLUDE` instructions targeting\n        that observable index.\n\n        Examples:\n            >>> import stim\n            >>> f = stim.Flow(included_observables=[3, 2])\n            >>> f.included_observables_copy()\n            [2, 3]\n\n            >>> f.included_observables_copy() is f.included_observables_copy()\n            False\n\n            >>> f = stim.Flow(\"X2 -> obs[3]\")\n            >>> f.included_observables_copy()\n            [3]\n            >>> stim.Circuit(\"OBSERVABLE_INCLUDE(3) X2\").has_flow(f)\n            True\n        \"\"\"\n    def input_copy(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns a copy of the flow's input stabilizer.\n\n        Examples:\n            >>> import stim\n            >>> f = stim.Flow(input=stim.PauliString('XX'))\n            >>> f.input_copy()\n            stim.PauliString(\"+XX\")\n\n            >>> f.input_copy() is f.input_copy()\n            False\n        \"\"\"\n    def measurements_copy(\n        self,\n    ) -> List[int]:\n        \"\"\"Returns a copy of the flow's measurement indices.\n\n        Examples:\n            >>> import stim\n            >>> f = stim.Flow(measurements=[-1, 2])\n            >>> f.measurements_copy()\n            [-1, 2]\n\n            >>> f.measurements_copy() is f.measurements_copy()\n            False\n        \"\"\"\n    def output_copy(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns a copy of the flow's output stabilizer.\n\n        Examples:\n            >>> import stim\n            >>> f = stim.Flow(output=stim.PauliString('XX'))\n            >>> f.output_copy()\n            stim.PauliString(\"+XX\")\n\n            >>> f.output_copy() is f.output_copy()\n            False\n        \"\"\"\nclass GateData:\n    \"\"\"Details about a gate supported by stim.\n\n    Examples:\n        >>> import stim\n        >>> stim.gate_data('h').name\n        'H'\n        >>> stim.gate_data('h').is_unitary\n        True\n        >>> stim.gate_data('h').tableau\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X\"),\n            ],\n        )\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.GateData,\n    ) -> bool:\n        \"\"\"Determines if two GateData instances are identical.\n        \"\"\"\n    def __init__(\n        self,\n        name: str,\n    ) -> None:\n        \"\"\"Finds gate data for the named gate.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateData('H').is_unitary\n            True\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.GateData,\n    ) -> bool:\n        \"\"\"Determines if two GateData instances are not identical.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.GateData`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns text describing the gate data.\n        \"\"\"\n    @property\n    def aliases(\n        self,\n    ) -> List[str]:\n        \"\"\"Returns all aliases that can be used to name the gate.\n\n        Although gates can be referred to by lower case and mixed\n        case named, the result only includes upper cased aliases.\n\n        Examples:\n            >>> import stim\n            >>> stim.gate_data('H').aliases\n            ['H', 'H_XZ']\n            >>> stim.gate_data('cnot').aliases\n            ['CNOT', 'CX', 'ZCX']\n        \"\"\"\n    @property\n    def flows(\n        self,\n    ) -> Optional[List[stim.Flow]]:\n        \"\"\"Returns stabilizer flow generators for the gate, or else None.\n\n        A stabilizer flow describes an input-output relationship that the gate\n        satisfies, where an input pauli string is transformed into an output\n        pauli string mediated by certain measurement results.\n\n        Caution: this method returns None for variable-target-count gates like MPP.\n        Not because MPP has no stabilizer flows, but because its stabilizer flows\n        depend on how many qubits it targets and what basis it targets them in.\n\n        Returns:\n            A list of stim.Flow instances representing the generators.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').flows\n            [stim.Flow(\"X -> Z\"), stim.Flow(\"Z -> X\")]\n\n            >>> for e in stim.gate_data('ISWAP').flows:\n            ...     print(e)\n            X_ -> ZY\n            Z_ -> _Z\n            _X -> YZ\n            _Z -> Z_\n\n            >>> for e in stim.gate_data('MXX').flows:\n            ...     print(e)\n            X_ -> X_\n            _X -> _X\n            ZZ -> ZZ\n            XX -> rec[-1]\n        \"\"\"\n    @property\n    def generalized_inverse(\n        self,\n    ) -> stim.GateData:\n        \"\"\"The closest-thing-to-an-inverse for the gate, if forced to pick something.\n\n        The generalized inverse of a unitary gate U is its actual inverse U^-1.\n\n        The generalized inverse of a reset or measurement gate U is a gate V such that,\n        for every stabilizer flow that U has, V has the time reverse of that flow (up\n        to Pauli feedback, with potentially more flows). For example, the time-reverse\n        of R is MR because R has the single flow 1 -> Z and MR has the time reversed\n        flow Z -> rec[-1].\n\n        The generalized inverse of noise like X_ERROR is just the same noise.\n\n        The generalized inverse of an annotation like TICK is just the same annotation.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').generalized_inverse\n            stim.gate_data('H')\n\n            >>> stim.gate_data('CXSWAP').generalized_inverse\n            stim.gate_data('SWAPCX')\n\n            >>> stim.gate_data('X_ERROR').generalized_inverse\n            stim.gate_data('X_ERROR')\n\n            >>> stim.gate_data('MX').generalized_inverse\n            stim.gate_data('MX')\n\n            >>> stim.gate_data('MRY').generalized_inverse\n            stim.gate_data('MRY')\n\n            >>> stim.gate_data('R').generalized_inverse\n            stim.gate_data('M')\n\n            >>> stim.gate_data('DETECTOR').generalized_inverse\n            stim.gate_data('DETECTOR')\n\n            >>> stim.gate_data('TICK').generalized_inverse\n            stim.gate_data('TICK')\n        \"\"\"\n    def hadamard_conjugated(\n        self,\n        *,\n        unsigned: bool = False,\n    ) -> Optional[stim.GateData]:\n        \"\"\"Returns a stim gate equivalent to this gate conjugated by Hadamard gates.\n\n        The Hadamard conjugate can be thought of as the XZ dual of the gate; the gate\n        you get by exchanging the X and Z bases. For example, a SQRT_X will become a\n        SQRT_Z and a CX gate will switch directions into an XCZ.\n\n        If stim doesn't define a gate equivalent to conjugating this gate by Hadamards,\n        the value `None` is returned.\n\n        Args:\n            unsigned: Defaults to False. When False, the returned gate must be *exactly*\n                the Hadamard conjugation of this gate. When True, the returned gate must\n                have the same flows but the sign of the flows can be different (i.e.\n                the returned gate must be the Hadamard conjugate up to Pauli gate\n                differences).\n\n        Returns:\n            A stim.GateData instance of the Hadamard conjugate, if it exists in stim.\n\n            None, if stim doesn't define a gate equal to the Hadamard conjugate.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('X').hadamard_conjugated()\n            stim.gate_data('Z')\n            >>> stim.gate_data('CX').hadamard_conjugated()\n            stim.gate_data('XCZ')\n            >>> stim.gate_data('RY').hadamard_conjugated() is None\n            True\n            >>> stim.gate_data('RY').hadamard_conjugated(unsigned=True)\n            stim.gate_data('RY')\n            >>> stim.gate_data('ISWAP').hadamard_conjugated(unsigned=True) is None\n            True\n            >>> stim.gate_data('SWAP').hadamard_conjugated()\n            stim.gate_data('SWAP')\n            >>> stim.gate_data('CXSWAP').hadamard_conjugated()\n            stim.gate_data('SWAPCX')\n            >>> stim.gate_data('MXX').hadamard_conjugated()\n            stim.gate_data('MZZ')\n            >>> stim.gate_data('DEPOLARIZE1').hadamard_conjugated()\n            stim.gate_data('DEPOLARIZE1')\n            >>> stim.gate_data('X_ERROR').hadamard_conjugated()\n            stim.gate_data('Z_ERROR')\n            >>> stim.gate_data('H_XY').hadamard_conjugated()\n            stim.gate_data('H_NYZ')\n            >>> stim.gate_data('DETECTOR').hadamard_conjugated(unsigned=True)\n            stim.gate_data('DETECTOR')\n        \"\"\"\n    @property\n    def inverse(\n        self,\n    ) -> Optional[stim.GateData]:\n        \"\"\"The inverse of the gate, or None if it has no inverse.\n\n        The inverse V of a gate U must have the property that V undoes the effects of U\n        and that U undoes the effects of V. In particular, the circuit\n\n            U 0 1\n            V 0 1\n\n        should be equivalent to doing nothing at all.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').inverse\n            stim.gate_data('H')\n\n            >>> stim.gate_data('CX').inverse\n            stim.gate_data('CX')\n\n            >>> stim.gate_data('S').inverse\n            stim.gate_data('S_DAG')\n\n            >>> stim.gate_data('CXSWAP').inverse\n            stim.gate_data('SWAPCX')\n\n            >>> stim.gate_data('X_ERROR').inverse is None\n            True\n            >>> stim.gate_data('M').inverse is None\n            True\n            >>> stim.gate_data('R').inverse is None\n            True\n            >>> stim.gate_data('DETECTOR').inverse is None\n            True\n            >>> stim.gate_data('TICK').inverse is None\n            True\n        \"\"\"\n    @property\n    def is_noisy_gate(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate can produce noise.\n\n        Note that measurement operations are considered noisy,\n        because for example `M(0.001) 2 3 5` will include\n        noise that flips its result 0.1% of the time.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('M').is_noisy_gate\n            True\n            >>> stim.gate_data('MXX').is_noisy_gate\n            True\n            >>> stim.gate_data('X_ERROR').is_noisy_gate\n            True\n            >>> stim.gate_data('CORRELATED_ERROR').is_noisy_gate\n            True\n            >>> stim.gate_data('MPP').is_noisy_gate\n            True\n\n            >>> stim.gate_data('H').is_noisy_gate\n            False\n            >>> stim.gate_data('CX').is_noisy_gate\n            False\n            >>> stim.gate_data('R').is_noisy_gate\n            False\n            >>> stim.gate_data('DETECTOR').is_noisy_gate\n            False\n        \"\"\"\n    @property\n    def is_reset(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate resets qubits in any basis.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('R').is_reset\n            True\n            >>> stim.gate_data('RX').is_reset\n            True\n            >>> stim.gate_data('MR').is_reset\n            True\n\n            >>> stim.gate_data('M').is_reset\n            False\n            >>> stim.gate_data('MXX').is_reset\n            False\n            >>> stim.gate_data('MPP').is_reset\n            False\n            >>> stim.gate_data('H').is_reset\n            False\n            >>> stim.gate_data('CX').is_reset\n            False\n            >>> stim.gate_data('HERALDED_ERASE').is_reset\n            False\n            >>> stim.gate_data('DEPOLARIZE2').is_reset\n            False\n            >>> stim.gate_data('X_ERROR').is_reset\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').is_reset\n            False\n            >>> stim.gate_data('DETECTOR').is_reset\n            False\n        \"\"\"\n    @property\n    def is_single_qubit_gate(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate is a single qubit gate.\n\n        Single qubit gates apply separately to each of their targets.\n\n        Variable-qubit gates like CORRELATED_ERROR and MPP are not\n        considered single qubit gates.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').is_single_qubit_gate\n            True\n            >>> stim.gate_data('R').is_single_qubit_gate\n            True\n            >>> stim.gate_data('M').is_single_qubit_gate\n            True\n            >>> stim.gate_data('X_ERROR').is_single_qubit_gate\n            True\n\n            >>> stim.gate_data('CX').is_single_qubit_gate\n            False\n            >>> stim.gate_data('MXX').is_single_qubit_gate\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').is_single_qubit_gate\n            False\n            >>> stim.gate_data('MPP').is_single_qubit_gate\n            False\n            >>> stim.gate_data('DETECTOR').is_single_qubit_gate\n            False\n            >>> stim.gate_data('TICK').is_single_qubit_gate\n            False\n            >>> stim.gate_data('REPEAT').is_single_qubit_gate\n            False\n        \"\"\"\n    @property\n    def is_symmetric_gate(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate is the same when its targets are swapped.\n\n        A two qubit gate is symmetric if it doesn't matter if you swap its targets. It\n        is unaffected when conjugated by the SWAP gate.\n\n        Single qubit gates are vacuously symmetric. A multi-qubit gate is symmetric if\n        swapping any two of its targets has no effect.\n\n        Note that this method is for symmetry *without broadcasting*. For example, SWAP\n        is symmetric even though SWAP 1 2 3 4 isn't equal to SWAP 1 3 2 4.\n\n        Returns:\n            True if the gate is symmetric.\n            False if the gate isn't symmetric.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('CX').is_symmetric_gate\n            False\n            >>> stim.gate_data('CZ').is_symmetric_gate\n            True\n            >>> stim.gate_data('ISWAP').is_symmetric_gate\n            True\n            >>> stim.gate_data('CXSWAP').is_symmetric_gate\n            False\n            >>> stim.gate_data('MXX').is_symmetric_gate\n            True\n            >>> stim.gate_data('DEPOLARIZE2').is_symmetric_gate\n            True\n            >>> stim.gate_data('PAULI_CHANNEL_2').is_symmetric_gate\n            False\n            >>> stim.gate_data('H').is_symmetric_gate\n            True\n            >>> stim.gate_data('R').is_symmetric_gate\n            True\n            >>> stim.gate_data('X_ERROR').is_symmetric_gate\n            True\n            >>> stim.gate_data('CORRELATED_ERROR').is_symmetric_gate\n            False\n            >>> stim.gate_data('MPP').is_symmetric_gate\n            False\n            >>> stim.gate_data('DETECTOR').is_symmetric_gate\n            False\n        \"\"\"\n    @property\n    def is_two_qubit_gate(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate is a two qubit gate.\n\n        Two qubit gates must be given an even number of targets.\n\n        Variable-qubit gates like CORRELATED_ERROR and MPP are not\n        considered two qubit gates.\n\n        Returns:\n            True if the gate is a two qubit gate.\n            False if the gate isn't a two qubit gate.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('CX').is_two_qubit_gate\n            True\n            >>> stim.gate_data('MXX').is_two_qubit_gate\n            True\n\n            >>> stim.gate_data('H').is_two_qubit_gate\n            False\n            >>> stim.gate_data('R').is_two_qubit_gate\n            False\n            >>> stim.gate_data('M').is_two_qubit_gate\n            False\n            >>> stim.gate_data('X_ERROR').is_two_qubit_gate\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').is_two_qubit_gate\n            False\n            >>> stim.gate_data('MPP').is_two_qubit_gate\n            False\n            >>> stim.gate_data('DETECTOR').is_two_qubit_gate\n            False\n        \"\"\"\n    @property\n    def is_unitary(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate is a unitary gate.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('H').is_unitary\n            True\n            >>> stim.gate_data('CX').is_unitary\n            True\n\n            >>> stim.gate_data('R').is_unitary\n            False\n            >>> stim.gate_data('M').is_unitary\n            False\n            >>> stim.gate_data('MXX').is_unitary\n            False\n            >>> stim.gate_data('X_ERROR').is_unitary\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').is_unitary\n            False\n            >>> stim.gate_data('MPP').is_unitary\n            False\n            >>> stim.gate_data('DETECTOR').is_unitary\n            False\n        \"\"\"\n    @property\n    def name(\n        self,\n    ) -> str:\n        \"\"\"Returns the canonical name of the gate.\n\n        Examples:\n            >>> import stim\n            >>> stim.gate_data('H').name\n            'H'\n            >>> stim.gate_data('cnot').name\n            'CX'\n        \"\"\"\n    @property\n    def num_parens_arguments_range(\n        self,\n    ) -> range:\n        \"\"\"Returns the min/max parens arguments taken by the gate, as a python range.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('M').num_parens_arguments_range\n            range(0, 2)\n            >>> list(stim.gate_data('M').num_parens_arguments_range)\n            [0, 1]\n            >>> list(stim.gate_data('R').num_parens_arguments_range)\n            [0]\n            >>> list(stim.gate_data('H').num_parens_arguments_range)\n            [0]\n            >>> list(stim.gate_data('X_ERROR').num_parens_arguments_range)\n            [1]\n            >>> list(stim.gate_data('PAULI_CHANNEL_1').num_parens_arguments_range)\n            [3]\n            >>> list(stim.gate_data('PAULI_CHANNEL_2').num_parens_arguments_range)\n            [15]\n            >>> stim.gate_data('DETECTOR').num_parens_arguments_range\n            range(0, 256)\n            >>> list(stim.gate_data('OBSERVABLE_INCLUDE').num_parens_arguments_range)\n            [1]\n        \"\"\"\n    @property\n    def produces_measurements(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate produces measurement results.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('M').produces_measurements\n            True\n            >>> stim.gate_data('MRY').produces_measurements\n            True\n            >>> stim.gate_data('MXX').produces_measurements\n            True\n            >>> stim.gate_data('MPP').produces_measurements\n            True\n            >>> stim.gate_data('HERALDED_ERASE').produces_measurements\n            True\n\n            >>> stim.gate_data('H').produces_measurements\n            False\n            >>> stim.gate_data('CX').produces_measurements\n            False\n            >>> stim.gate_data('R').produces_measurements\n            False\n            >>> stim.gate_data('X_ERROR').produces_measurements\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').produces_measurements\n            False\n            >>> stim.gate_data('DETECTOR').produces_measurements\n            False\n        \"\"\"\n    @property\n    def tableau(\n        self,\n    ) -> Optional[stim.Tableau]:\n        \"\"\"Returns the gate's tableau, or None if the gate has no tableau.\n\n        Examples:\n            >>> import stim\n            >>> print(stim.gate_data('M').tableau)\n            None\n            >>> stim.gate_data('H').tableau\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+X\"),\n                ],\n            )\n            >>> stim.gate_data('ISWAP').tableau\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+ZY\"),\n                    stim.PauliString(\"+YZ\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+_Z\"),\n                    stim.PauliString(\"+Z_\"),\n                ],\n            )\n        \"\"\"\n    @property\n    def takes_measurement_record_targets(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate can accept rec targets.\n\n        For example, `CX` can take a measurement record target\n        like `CX rec[-1] 1`.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('CX').takes_measurement_record_targets\n            True\n            >>> stim.gate_data('DETECTOR').takes_measurement_record_targets\n            True\n\n            >>> stim.gate_data('H').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('SWAP').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('R').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('M').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('MRY').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('MXX').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('X_ERROR').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('CORRELATED_ERROR').takes_measurement_record_targets\n            False\n            >>> stim.gate_data('MPP').takes_measurement_record_targets\n            False\n        \"\"\"\n    @property\n    def takes_pauli_targets(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not the gate expects pauli targets.\n\n        For example, `CORRELATED_ERROR` takes targets like `X0` and `Y1`\n        instead of `0` or `1`.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.gate_data('CORRELATED_ERROR').takes_pauli_targets\n            True\n            >>> stim.gate_data('MPP').takes_pauli_targets\n            True\n\n            >>> stim.gate_data('H').takes_pauli_targets\n            False\n            >>> stim.gate_data('CX').takes_pauli_targets\n            False\n            >>> stim.gate_data('R').takes_pauli_targets\n            False\n            >>> stim.gate_data('M').takes_pauli_targets\n            False\n            >>> stim.gate_data('MRY').takes_pauli_targets\n            False\n            >>> stim.gate_data('MXX').takes_pauli_targets\n            False\n            >>> stim.gate_data('X_ERROR').takes_pauli_targets\n            False\n            >>> stim.gate_data('DETECTOR').takes_pauli_targets\n            False\n        \"\"\"\n    @property\n    def unitary_matrix(\n        self,\n    ) -> Optional[np.ndarray]:\n        \"\"\"Returns the gate's unitary matrix, or None if the gate isn't unitary.\n\n        Examples:\n            >>> import stim\n\n            >>> print(stim.gate_data('M').unitary_matrix)\n            None\n\n            >>> stim.gate_data('X').unitary_matrix\n            array([[0.+0.j, 1.+0.j],\n                   [1.+0.j, 0.+0.j]], dtype=complex64)\n\n            >>> stim.gate_data('ISWAP').unitary_matrix\n            array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j],\n                   [0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]], dtype=complex64)\n        \"\"\"\nclass GateTarget:\n    \"\"\"Represents a gate target, like `0` or `rec[-1]`, from a circuit.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit('''\n        ...     M 0 !1\n        ... ''')\n        >>> circuit[0].targets_copy()[0]\n        stim.GateTarget(0)\n        >>> circuit[0].targets_copy()[1]\n        stim.target_inv(1)\n    \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.GateTarget,\n    ) -> bool:\n        \"\"\"Determines if two `stim.GateTarget`s are identical.\n        \"\"\"\n    def __init__(\n        self,\n        value: object,\n    ) -> None:\n        \"\"\"Initializes a `stim.GateTarget`.\n\n        Args:\n            value: A value to convert into a gate target, like an integer\n                to interpret as a qubit target or a string to parse.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(stim.GateTarget(5))\n            stim.GateTarget(5)\n            >>> stim.GateTarget(\"X7\")\n            stim.target_x(7)\n            >>> stim.GateTarget(\"rec[-3]\")\n            stim.target_rec(-3)\n            >>> stim.GateTarget(\"!Z7\")\n            stim.target_z(7, invert=True)\n            >>> stim.GateTarget(\"*\")\n            stim.GateTarget.combiner()\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.GateTarget,\n    ) -> bool:\n        \"\"\"Determines if two `stim.GateTarget`s are different.\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns text that is a valid python expression evaluating to an equivalent `stim.GateTarget`.\n        \"\"\"\n    @property\n    def is_combiner(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a combiner target like `*`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_combiner\n            False\n            >>> stim.target_inv(7).is_combiner\n            False\n            >>> stim.target_x(8).is_combiner\n            False\n            >>> stim.target_y(2).is_combiner\n            False\n            >>> stim.target_z(3).is_combiner\n            False\n            >>> stim.target_sweep_bit(9).is_combiner\n            False\n            >>> stim.target_rec(-5).is_combiner\n            False\n            >>> stim.target_combiner().is_combiner\n            True\n        \"\"\"\n    @property\n    def is_inverted_result_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is an inverted target like `!5` or `!X4`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_inverted_result_target\n            False\n            >>> stim.target_inv(7).is_inverted_result_target\n            True\n            >>> stim.target_x(8).is_inverted_result_target\n            False\n            >>> stim.target_x(8, invert=True).is_inverted_result_target\n            True\n            >>> stim.target_y(2).is_inverted_result_target\n            False\n            >>> stim.target_z(3).is_inverted_result_target\n            False\n            >>> stim.target_sweep_bit(9).is_inverted_result_target\n            False\n            >>> stim.target_rec(-5).is_inverted_result_target\n            False\n        \"\"\"\n    @property\n    def is_measurement_record_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a measurement record target like `rec[-5]`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_measurement_record_target\n            False\n            >>> stim.target_inv(7).is_measurement_record_target\n            False\n            >>> stim.target_x(8).is_measurement_record_target\n            False\n            >>> stim.target_y(2).is_measurement_record_target\n            False\n            >>> stim.target_z(3).is_measurement_record_target\n            False\n            >>> stim.target_sweep_bit(9).is_measurement_record_target\n            False\n            >>> stim.target_rec(-5).is_measurement_record_target\n            True\n        \"\"\"\n    @property\n    def is_qubit_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a qubit target like `5` or `!6`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_qubit_target\n            True\n            >>> stim.target_inv(7).is_qubit_target\n            True\n            >>> stim.target_x(8).is_qubit_target\n            False\n            >>> stim.target_y(2).is_qubit_target\n            False\n            >>> stim.target_z(3).is_qubit_target\n            False\n            >>> stim.target_sweep_bit(9).is_qubit_target\n            False\n            >>> stim.target_rec(-5).is_qubit_target\n            False\n        \"\"\"\n    @property\n    def is_sweep_bit_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a sweep bit target like `sweep[4]`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_sweep_bit_target\n            False\n            >>> stim.target_inv(7).is_sweep_bit_target\n            False\n            >>> stim.target_x(8).is_sweep_bit_target\n            False\n            >>> stim.target_y(2).is_sweep_bit_target\n            False\n            >>> stim.target_z(3).is_sweep_bit_target\n            False\n            >>> stim.target_sweep_bit(9).is_sweep_bit_target\n            True\n            >>> stim.target_rec(-5).is_sweep_bit_target\n            False\n        \"\"\"\n    @property\n    def is_x_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is an X pauli target like `X2` or `!X7`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_x_target\n            False\n            >>> stim.target_inv(7).is_x_target\n            False\n            >>> stim.target_x(8).is_x_target\n            True\n            >>> stim.target_y(2).is_x_target\n            False\n            >>> stim.target_z(3).is_x_target\n            False\n            >>> stim.target_sweep_bit(9).is_x_target\n            False\n            >>> stim.target_rec(-5).is_x_target\n            False\n        \"\"\"\n    @property\n    def is_y_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a Y pauli target like `Y2` or `!Y7`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_y_target\n            False\n            >>> stim.target_inv(7).is_y_target\n            False\n            >>> stim.target_x(8).is_y_target\n            False\n            >>> stim.target_y(2).is_y_target\n            True\n            >>> stim.target_z(3).is_y_target\n            False\n            >>> stim.target_sweep_bit(9).is_y_target\n            False\n            >>> stim.target_rec(-5).is_y_target\n            False\n        \"\"\"\n    @property\n    def is_z_target(\n        self,\n    ) -> bool:\n        \"\"\"Returns whether or not this is a Z pauli target like `Z2` or `!Z7`.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).is_z_target\n            False\n            >>> stim.target_inv(7).is_z_target\n            False\n            >>> stim.target_x(8).is_z_target\n            False\n            >>> stim.target_y(2).is_z_target\n            False\n            >>> stim.target_z(3).is_z_target\n            True\n            >>> stim.target_sweep_bit(9).is_z_target\n            False\n            >>> stim.target_rec(-5).is_z_target\n            False\n        \"\"\"\n    @property\n    def pauli_type(\n        self,\n    ) -> str:\n        \"\"\"Returns whether this is an 'X', 'Y', or 'Z' target.\n\n        For non-pauli targets, this property evaluates to 'I'.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).pauli_type\n            'I'\n            >>> stim.target_inv(7).pauli_type\n            'I'\n            >>> stim.target_x(8).pauli_type\n            'X'\n            >>> stim.target_y(2).pauli_type\n            'Y'\n            >>> stim.target_z(3).pauli_type\n            'Z'\n            >>> stim.target_sweep_bit(9).pauli_type\n            'I'\n            >>> stim.target_rec(-5).pauli_type\n            'I'\n        \"\"\"\n    @property\n    def qubit_value(\n        self,\n    ) -> Optional[int]:\n        \"\"\"Returns the integer value of the targeted qubit, or else None.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).qubit_value\n            6\n            >>> stim.target_inv(7).qubit_value\n            7\n            >>> stim.target_x(8).qubit_value\n            8\n            >>> stim.target_y(2).qubit_value\n            2\n            >>> stim.target_z(3).qubit_value\n            3\n            >>> print(stim.target_sweep_bit(9).qubit_value)\n            None\n            >>> print(stim.target_rec(-5).qubit_value)\n            None\n        \"\"\"\n    @property\n    def value(\n        self,\n    ) -> int:\n        \"\"\"The numeric part of the target.\n\n        This is non-negative integer for qubit targets, and a negative integer for\n        measurement record targets.\n\n        Examples:\n            >>> import stim\n            >>> stim.GateTarget(6).value\n            6\n            >>> stim.target_inv(7).value\n            7\n            >>> stim.target_x(8).value\n            8\n            >>> stim.target_y(2).value\n            2\n            >>> stim.target_z(3).value\n            3\n            >>> stim.target_sweep_bit(9).value\n            9\n            >>> stim.target_rec(-5).value\n            -5\n        \"\"\"\nclass GateTargetWithCoords:\n    \"\"\"A gate target with associated coordinate information.\n\n    For example, if the gate target is a qubit from a circuit with\n    QUBIT_COORDS instructions, the coords field will contain the\n    coordinate data from the QUBIT_COORDS instruction for the qubit.\n\n    This is helpful information to have available when debugging a\n    problem in a circuit, instead of having to constantly manually\n    look up the coordinates of a qubit index in order to understand\n    what is happening.\n\n    Examples:\n        >>> import stim\n        >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n        >>> t.gate_target\n        stim.GateTarget(0)\n        >>> t.coords\n        [1.5, 2.0]\n    \"\"\"\n    def __init__(\n        self,\n        gate_target: object,\n        coords: List[float],\n    ) -> None:\n        \"\"\"Creates a stim.GateTargetWithCoords.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n            >>> t.gate_target\n            stim.GateTarget(0)\n            >>> t.coords\n            [1.5, 2.0]\n        \"\"\"\n    @property\n    def coords(\n        self,\n    ) -> List[float]:\n        \"\"\"Returns the associated coordinate information as a list of floats.\n\n        If there is no coordinate information, returns an empty list.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n            >>> t.coords\n            [1.5, 2.0]\n        \"\"\"\n    @property\n    def gate_target(\n        self,\n    ) -> stim.GateTarget:\n        \"\"\"Returns the actual gate target as a `stim.GateTarget`.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n            >>> t.gate_target\n            stim.GateTarget(0)\n        \"\"\"\nclass PauliString:\n    \"\"\"A signed Pauli tensor product (e.g. \"+X \\u2297 X \\u2297 X\" or \"-Y \\u2297 Z\".\n\n    Represents a collection of Pauli operations (I, X, Y, Z) applied pairwise to a\n    collection of qubits.\n\n    Examples:\n        >>> import stim\n        >>> stim.PauliString(\"XX\") * stim.PauliString(\"YY\")\n        stim.PauliString(\"-ZZ\")\n        >>> print(stim.PauliString(5))\n        +_____\n    \"\"\"\n    def __add__(\n        self,\n        rhs: stim.PauliString,\n    ) -> stim.PauliString:\n        \"\"\"Returns the tensor product of two Pauli strings.\n\n        Concatenates the Pauli strings and multiplies their signs.\n\n        Args:\n            rhs: A second stim.PauliString.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.PauliString(\"X\") + stim.PauliString(\"YZ\")\n            stim.PauliString(\"+XYZ\")\n\n            >>> stim.PauliString(\"iX\") + stim.PauliString(\"-X\")\n            stim.PauliString(\"-iXX\")\n\n        Returns:\n            The tensor product.\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.PauliString,\n    ) -> bool:\n        \"\"\"Determines if two Pauli strings have identical contents.\n        \"\"\"\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: int,\n    ) -> int:\n        pass\n    @overload\n    def __getitem__(\n        self,\n        index_or_slice: slice,\n    ) -> stim.PauliString:\n        pass\n    def __getitem__(\n        self,\n        index_or_slice: object,\n    ) -> object:\n        \"\"\"Returns an individual Pauli or Pauli string slice from the pauli string.\n\n        Individual Paulis are returned as an int using the encoding 0=I, 1=X, 2=Y, 3=Z.\n        Slices are returned as a stim.PauliString (always with positive sign).\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(\"_XYZ\")\n            >>> p[2]\n            2\n            >>> p[-1]\n            3\n            >>> p[:2]\n            stim.PauliString(\"+_X\")\n            >>> p[::-1]\n            stim.PauliString(\"+ZYX_\")\n\n        Args:\n            index_or_slice: The index of the pauli to return, or the slice of paulis to\n                return.\n\n        Returns:\n            0: Identity.\n            1: Pauli X.\n            2: Pauli Y.\n            3: Pauli Z.\n        \"\"\"\n    def __iadd__(\n        self,\n        rhs: stim.PauliString,\n    ) -> stim.PauliString:\n        \"\"\"Performs an inplace tensor product.\n\n        Concatenates the given Pauli string onto the receiving string and multiplies\n        their signs.\n\n        Args:\n            rhs: A second stim.PauliString.\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.PauliString(\"iX\")\n            >>> alias = p\n            >>> p += stim.PauliString(\"-YY\")\n            >>> p\n            stim.PauliString(\"-iXYY\")\n            >>> alias is p\n            True\n\n        Returns:\n            The mutated pauli string.\n        \"\"\"\n    def __imul__(\n        self,\n        rhs: object,\n    ) -> stim.PauliString:\n        \"\"\"Inplace right-multiplies the Pauli string.\n\n        Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n        Args:\n            rhs: The right hand side of the multiplication. This can be:\n                - A stim.PauliString to right-multiply term-by-term into the paulis of\n                    the pauli string.\n                - A complex unit (1, -1, 1j, -1j) to multiply into the sign of the pauli\n                    string.\n                - A non-negative integer indicating the tensor power to raise the pauli\n                    string to (how many times to repeat it).\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.PauliString(\"X\")\n            >>> p *= 1j\n            >>> p\n            stim.PauliString(\"+iX\")\n\n            >>> p = stim.PauliString(\"iXY_\")\n            >>> p *= 3\n            >>> p\n            stim.PauliString(\"-iXY_XY_XY_\")\n\n            >>> p = stim.PauliString(\"X\")\n            >>> alias = p\n            >>> p *= stim.PauliString(\"Y\")\n            >>> alias\n            stim.PauliString(\"+iZ\")\n\n            >>> p = stim.PauliString(\"X\")\n            >>> p *= stim.PauliString(\"_YY\")\n            >>> p\n            stim.PauliString(\"+XYY\")\n\n        Returns:\n            The mutated Pauli string.\n        \"\"\"\n    def __init__(\n        self,\n        arg: Union[None, int, str, stim.PauliString, Iterable[Union[int, Literal[\"_\", \"I\", \"X\", \"Y\", \"Z\"]]]] = None,\n        /,\n    ) -> None:\n        \"\"\"Initializes a stim.PauliString from the given argument.\n\n        When given a string, the string is parsed as a pauli string. The string can\n        optionally start with a sign ('+', '-', 'i', '+i', or '-i'). The rest of the\n        string should be either a dense pauli string or a sparse pauli string. A dense\n        pauli string is made up of characters from '_IXYZ' where '_' and 'I' mean\n        identity, 'X' means Pauli X, 'Y' means Pauli Y, and 'Z' means Pauli Z. A sparse\n        pauli string is a series of integers seperated by '*' and prefixed by 'I', 'X',\n        'Y', or 'Z'.\n\n        Args:\n            arg [position-only]: This can be a variety of types, including:\n                None (default): initializes an empty Pauli string.\n                int: initializes an identity Pauli string of the given length.\n                str: initializes by parsing the given text.\n                stim.PauliString: initializes a copy of the given Pauli string.\n                Iterable: initializes by interpreting each item as a Pauli.\n                    Each item can be a single-qubit Pauli string (like \"X\"),\n                    or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n                Dict[int, Union[int, str]]: initializes by interpreting keys as\n                    the qubit index and values as the Pauli for that index.\n                    Each value can be a single-qubit Pauli string (like \"X\"),\n                    or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n                Dict[Union[int, str], Iterable[int]]: initializes by interpreting keys\n                    as Pauli operators and values as the qubit indices for that Pauli.\n                    Each key can be a single-qubit Pauli string (like \"X\"),\n                    or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.PauliString(\"-XYZ\")\n            stim.PauliString(\"-XYZ\")\n\n            >>> stim.PauliString()\n            stim.PauliString(\"+\")\n\n            >>> stim.PauliString(5)\n            stim.PauliString(\"+_____\")\n\n            >>> stim.PauliString(stim.PauliString(\"XX\"))\n            stim.PauliString(\"+XX\")\n\n            >>> stim.PauliString([0, 1, 3, 2])\n            stim.PauliString(\"+_XZY\")\n\n            >>> stim.PauliString(\"X\" for _ in range(4))\n            stim.PauliString(\"+XXXX\")\n\n            >>> stim.PauliString(\"-X2*Y6\")\n            stim.PauliString(\"-__X___Y\")\n\n            >>> stim.PauliString(\"X6*Y6\")\n            stim.PauliString(\"+i______Z\")\n\n            >>> stim.PauliString({0: \"X\", 2: \"Y\", 3: \"X\"})\n            stim.PauliString(\"+X_YX\")\n\n            >>> stim.PauliString({0: \"X\", 2: 2, 3: 1})\n            stim.PauliString(\"+X_YX\")\n\n            >>> stim.PauliString({\"X\": [1], 2: [4], \"Z\": [0, 3]})\n            stim.PauliString(\"+ZX_ZY\")\n        \"\"\"\n    def __itruediv__(\n        self,\n        rhs: complex,\n    ) -> stim.PauliString:\n        \"\"\"Inplace divides the Pauli string by a complex unit.\n\n        Args:\n            rhs: The divisor. Can be 1, -1, 1j, or -1j.\n\n        Examples:\n            >>> import stim\n\n            >>> p = stim.PauliString(\"X\")\n            >>> p /= 1j\n            >>> p\n            stim.PauliString(\"-iX\")\n\n        Returns:\n            The mutated Pauli string.\n\n        Raises:\n            ValueError: The divisor isn't 1, -1, 1j, or -1j.\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the length the pauli string; the number of qubits it operates on.\n\n        Examples:\n            >>> import stim\n            >>> len(stim.PauliString(\"XY_ZZ\"))\n            5\n            >>> len(stim.PauliString(\"X0*Z99\"))\n            100\n        \"\"\"\n    def __mul__(\n        self,\n        rhs: object,\n    ) -> stim.PauliString:\n        \"\"\"Right-multiplies the Pauli string.\n\n        Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n        Args:\n            rhs: The right hand side of the multiplication. This can be:\n                - A stim.PauliString to right-multiply term-by-term with the paulis of\n                    the pauli string.\n                - A complex unit (1, -1, 1j, -1j) to multiply with the sign of the pauli\n                    string.\n                - A non-negative integer indicating the tensor power to raise the pauli\n                    string to (how many times to repeat it).\n\n        Examples:\n            >>> import stim\n\n            >>> stim.PauliString(\"X\") * 1\n            stim.PauliString(\"+X\")\n            >>> stim.PauliString(\"X\") * -1\n            stim.PauliString(\"-X\")\n            >>> stim.PauliString(\"X\") * 1j\n            stim.PauliString(\"+iX\")\n\n            >>> stim.PauliString(\"X\") * 2\n            stim.PauliString(\"+XX\")\n            >>> stim.PauliString(\"-X\") * 2\n            stim.PauliString(\"+XX\")\n            >>> stim.PauliString(\"iX\") * 2\n            stim.PauliString(\"-XX\")\n            >>> stim.PauliString(\"X\") * 3\n            stim.PauliString(\"+XXX\")\n            >>> stim.PauliString(\"iX\") * 3\n            stim.PauliString(\"-iXXX\")\n\n            >>> stim.PauliString(\"X\") * stim.PauliString(\"Y\")\n            stim.PauliString(\"+iZ\")\n            >>> stim.PauliString(\"X\") * stim.PauliString(\"XX_\")\n            stim.PauliString(\"+_X_\")\n            >>> stim.PauliString(\"XXXX\") * stim.PauliString(\"_XYZ\")\n            stim.PauliString(\"+X_ZY\")\n\n        Returns:\n            The product or tensor power.\n\n        Raises:\n            TypeError: The right hand side isn't a stim.PauliString, a non-negative\n                integer, or a complex unit (1, -1, 1j, or -1j).\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.PauliString,\n    ) -> bool:\n        \"\"\"Determines if two Pauli strings have non-identical contents.\n        \"\"\"\n    def __neg__(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns the negation of the pauli string.\n\n        Examples:\n            >>> import stim\n            >>> -stim.PauliString(\"X\")\n            stim.PauliString(\"-X\")\n            >>> -stim.PauliString(\"-Y\")\n            stim.PauliString(\"+Y\")\n            >>> -stim.PauliString(\"iZZZ\")\n            stim.PauliString(\"-iZZZ\")\n        \"\"\"\n    def __pos__(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns a pauli string with the same contents.\n\n        Examples:\n            >>> import stim\n            >>> +stim.PauliString(\"+X\")\n            stim.PauliString(\"+X\")\n            >>> +stim.PauliString(\"-YY\")\n            stim.PauliString(\"-YY\")\n            >>> +stim.PauliString(\"iZZZ\")\n            stim.PauliString(\"+iZZZ\")\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equivalent `stim.PauliString`.\n        \"\"\"\n    def __rmul__(\n        self,\n        lhs: object,\n    ) -> stim.PauliString:\n        \"\"\"Left-multiplies the Pauli string.\n\n        Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n        Args:\n            lhs: The left hand side of the multiplication. This can be:\n                - A stim.PauliString to right-multiply term-by-term with the paulis of\n                    the pauli string.\n                - A complex unit (1, -1, 1j, -1j) to multiply with the sign of the pauli\n                    string.\n                - A non-negative integer indicating the tensor power to raise the pauli\n                    string to (how many times to repeat it).\n\n        Examples:\n            >>> import stim\n\n            >>> 1 * stim.PauliString(\"X\")\n            stim.PauliString(\"+X\")\n            >>> -1 * stim.PauliString(\"X\")\n            stim.PauliString(\"-X\")\n            >>> 1j * stim.PauliString(\"X\")\n            stim.PauliString(\"+iX\")\n\n            >>> 2 * stim.PauliString(\"X\")\n            stim.PauliString(\"+XX\")\n            >>> 2 * stim.PauliString(\"-X\")\n            stim.PauliString(\"+XX\")\n            >>> 2 * stim.PauliString(\"iX\")\n            stim.PauliString(\"-XX\")\n            >>> 3 * stim.PauliString(\"X\")\n            stim.PauliString(\"+XXX\")\n            >>> 3 * stim.PauliString(\"iX\")\n            stim.PauliString(\"-iXXX\")\n\n            >>> stim.PauliString(\"X\") * stim.PauliString(\"Y\")\n            stim.PauliString(\"+iZ\")\n            >>> stim.PauliString(\"X\") * stim.PauliString(\"XX_\")\n            stim.PauliString(\"+_X_\")\n            >>> stim.PauliString(\"XXXX\") * stim.PauliString(\"_XYZ\")\n            stim.PauliString(\"+X_ZY\")\n\n        Returns:\n            The product.\n\n        Raises:\n            ValueError: The scalar phase factor isn't 1, -1, 1j, or -1j.\n        \"\"\"\n    def __setitem__(\n        self,\n        index: int,\n        new_pauli: object,\n    ) -> None:\n        \"\"\"Mutates an entry in the pauli string using the encoding 0=I, 1=X, 2=Y, 3=Z.\n\n        Args:\n            index: The index of the pauli to overwrite.\n            new_pauli: Either a character from '_IXYZ' or an integer from range(4).\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(4)\n            >>> p[2] = 1\n            >>> print(p)\n            +__X_\n            >>> p[0] = 3\n            >>> p[1] = 2\n            >>> p[3] = 0\n            >>> print(p)\n            +ZYX_\n            >>> p[0] = 'I'\n            >>> p[1] = 'X'\n            >>> p[2] = 'Y'\n            >>> p[3] = 'Z'\n            >>> print(p)\n            +_XYZ\n            >>> p[-1] = 'Y'\n            >>> print(p)\n            +_XYY\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a text description.\n        \"\"\"\n    def __truediv__(\n        self,\n        rhs: complex,\n    ) -> stim.PauliString:\n        \"\"\"Divides the Pauli string by a complex unit.\n\n        Args:\n            rhs: The divisor. Can be 1, -1, 1j, or -1j.\n\n        Examples:\n            >>> import stim\n\n            >>> stim.PauliString(\"X\") / 1j\n            stim.PauliString(\"-iX\")\n\n        Returns:\n            The quotient.\n\n        Raises:\n            ValueError: The divisor isn't 1, -1, 1j, or -1j.\n        \"\"\"\n    @overload\n    def after(\n        self,\n        operation: Union[stim.Circuit, stim.CircuitInstruction],\n    ) -> stim.PauliString:\n        pass\n    @overload\n    def after(\n        self,\n        operation: stim.Tableau,\n        targets: Iterable[int],\n    ) -> stim.PauliString:\n        pass\n    def after(\n        self,\n        operation: Union[stim.Circuit, stim.Tableau, stim.CircuitInstruction],\n        targets: Optional[Iterable[int]] = None,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating the Pauli string by an operation.\n\n        Args:\n            operation: A circuit, tableau, or circuit instruction to\n                conjugate the Pauli string by. Must be Clifford (e.g.\n                if it's a circuit, the circuit can't have noise or\n                measurements).\n            targets: Required if and only if the operation is a tableau.\n                Specifies which qubits to target.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(\"_XYZ\")\n\n            >>> p.after(stim.CircuitInstruction(\"H\", [1]))\n            stim.PauliString(\"+_ZYZ\")\n\n            >>> p.after(stim.Circuit('''\n            ...     C_XYZ 1 2 3\n            ... '''))\n            stim.PauliString(\"+_YZX\")\n\n            >>> p.after(stim.Tableau.from_named_gate('CZ'), targets=[0, 1])\n            stim.PauliString(\"+ZXYZ\")\n\n        Returns:\n            The conjugated Pauli string. The Pauli string after the\n            operation that is exactly equivalent to the given Pauli\n            string before the operation.\n        \"\"\"\n    @overload\n    def before(\n        self,\n        operation: Union[stim.Circuit, stim.CircuitInstruction],\n    ) -> stim.PauliString:\n        pass\n    @overload\n    def before(\n        self,\n        operation: stim.Tableau,\n        targets: Iterable[int],\n    ) -> stim.PauliString:\n        pass\n    def before(\n        self,\n        operation: Union[stim.Circuit, stim.Tableau, stim.CircuitInstruction],\n        targets: Optional[Iterable[int]] = None,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating the Pauli string by an operation.\n\n        Args:\n            operation: A circuit, tableau, or circuit instruction to\n                anti-conjugate the Pauli string by. Must be Clifford (e.g.\n                if it's a circuit, the circuit can't have noise or\n                measurements).\n            targets: Required if and only if the operation is a tableau.\n                Specifies which qubits to target.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(\"_XYZ\")\n\n            >>> p.before(stim.CircuitInstruction(\"H\", [1]))\n            stim.PauliString(\"+_ZYZ\")\n\n            >>> p.before(stim.Circuit('''\n            ...     C_XYZ 1 2 3\n            ... '''))\n            stim.PauliString(\"+_ZXY\")\n\n            >>> p.before(stim.Tableau.from_named_gate('CZ'), targets=[0, 1])\n            stim.PauliString(\"+ZXYZ\")\n\n        Returns:\n            The conjugated Pauli string. The Pauli string before the\n            operation that is exactly equivalent to the given Pauli\n            string after the operation.\n        \"\"\"\n    def commutes(\n        self,\n        other: stim.PauliString,\n    ) -> bool:\n        \"\"\"Determines if two Pauli strings commute or not.\n\n        Two Pauli strings commute if they have an even number of matched\n        non-equal non-identity Pauli terms. Otherwise they anticommute.\n\n        Args:\n            other: The other Pauli string.\n\n        Examples:\n            >>> import stim\n            >>> xx = stim.PauliString(\"XX\")\n            >>> xx.commutes(stim.PauliString(\"X_\"))\n            True\n            >>> xx.commutes(stim.PauliString(\"XX\"))\n            True\n            >>> xx.commutes(stim.PauliString(\"XY\"))\n            False\n            >>> xx.commutes(stim.PauliString(\"XZ\"))\n            False\n            >>> xx.commutes(stim.PauliString(\"ZZ\"))\n            True\n            >>> xx.commutes(stim.PauliString(\"X_Y__\"))\n            True\n            >>> xx.commutes(stim.PauliString(\"\"))\n            True\n\n        Returns:\n            True if the Pauli strings commute, False if they anti-commute.\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns a copy of the pauli string.\n\n        The copy is an independent pauli string with the same contents.\n\n        Examples:\n            >>> import stim\n            >>> p1 = stim.PauliString.random(2)\n            >>> p2 = p1.copy()\n            >>> p2 is p1\n            False\n            >>> p2 == p1\n            True\n        \"\"\"\n    def extended_product(\n        self,\n        other: stim.PauliString,\n    ) -> Tuple[complex, stim.PauliString]:\n        \"\"\"[DEPRECATED] Use multiplication (__mul__ or *) instead.\n        \"\"\"\n    @staticmethod\n    def from_numpy(\n        *,\n        xs: np.ndarray,\n        zs: np.ndarray,\n        sign: Union[int, float, complex] = +1,\n        num_qubits: Optional[int] = None,\n    ) -> stim.PauliString:\n        \"\"\"Creates a pauli string from X bit and Z bit numpy arrays, using the encoding:\n\n            x=0 and z=0 -> P=I\n            x=1 and z=0 -> P=X\n            x=1 and z=1 -> P=Y\n            x=0 and z=1 -> P=Z\n\n        Args:\n            xs: The X bits of the pauli string. This array can either be a 1-dimensional\n                numpy array with dtype=np.bool_, or a bit packed 1-dimensional numpy\n                array with dtype=np.uint8. If the dtype is np.uint8 then the array is\n                assumed to be bit packed in little endian order and the \"num_qubits\"\n                argument must be specified. When bit packed, the x bit with offset k is\n                stored at (xs[k // 8] >> (k % 8)) & 1.\n            zs: The Z bits of the pauli string. This array can either be a 1-dimensional\n                numpy array with dtype=np.bool_, or a bit packed 1-dimensional numpy\n                array with dtype=np.uint8. If the dtype is np.uint8 then the array is\n                assumed to be bit packed in little endian order and the \"num_qubits\"\n                argument must be specified. When bit packed, the x bit with offset k is\n                stored at (xs[k // 8] >> (k % 8)) & 1.\n            sign: Defaults to +1. Set to +1, -1, 1j, or -1j to control the sign of the\n                returned Pauli string.\n            num_qubits: Must be specified if xs or zs is a bit packed array. Specifies\n                the expected length of the Pauli string.\n\n        Returns:\n            The created pauli string.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n\n            >>> xs = np.array([1, 1, 1, 1, 1, 1, 1, 0, 0], dtype=np.bool_)\n            >>> zs = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1], dtype=np.bool_)\n            >>> stim.PauliString.from_numpy(xs=xs, zs=zs, sign=-1)\n            stim.PauliString(\"-XXXXYYYZZ\")\n\n            >>> xs = np.array([127, 0], dtype=np.uint8)\n            >>> zs = np.array([240, 1], dtype=np.uint8)\n            >>> stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=9)\n            stim.PauliString(\"+XXXXYYYZZ\")\n        \"\"\"\n    @staticmethod\n    def from_unitary_matrix(\n        matrix: Iterable[Iterable[Union[int, float, complex]]],\n        *,\n        endian: Literal[\"little\", \"big\"] = 'little',\n        unsigned: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Creates a stim.PauliString from the unitary matrix of a Pauli group member.\n\n        Args:\n            matrix: A unitary matrix specified as an iterable of rows, with each row is\n                an iterable of amplitudes. The unitary matrix must correspond to a\n                Pauli string, including global phase.\n            endian:\n                \"little\": matrix entries are in little endian order, where higher index\n                    qubits correspond to larger changes in row/col indices.\n                \"big\": matrix entries are in big endian order, where higher index\n                    qubits correspond to smaller changes in row/col indices.\n            unsigned: When False, the input must only contain the values\n                [0, 1, -1, 1j, -1j] and the output will have the correct global phase.\n                When True, the input is permitted to be scaled by an arbitrary unit\n                complex value and the output will always have positive sign.\n                False is stricter but provides more information, while True is more\n                flexible but provides less information.\n\n        Returns:\n            The pauli string equal to the given unitary matrix.\n\n        Raises:\n            ValueError: The given matrix isn't the unitary matrix of a Pauli string.\n\n        Examples:\n            >>> import stim\n            >>> stim.PauliString.from_unitary_matrix([\n            ...     [1j, 0],\n            ...     [0, -1j],\n            ... ], endian='little')\n            stim.PauliString(\"+iZ\")\n\n            >>> stim.PauliString.from_unitary_matrix([\n            ...     [1j**0.1, 0],\n            ...     [0, -(1j**0.1)],\n            ... ], endian='little', unsigned=True)\n            stim.PauliString(\"+Z\")\n\n            >>> stim.PauliString.from_unitary_matrix([\n            ...     [0, 1, 0, 0],\n            ...     [1, 0, 0, 0],\n            ...     [0, 0, 0, -1],\n            ...     [0, 0, -1, 0],\n            ... ], endian='little')\n            stim.PauliString(\"+XZ\")\n        \"\"\"\n    @staticmethod\n    def iter_all(\n        num_qubits: int,\n        *,\n        min_weight: int = 0,\n        max_weight: object = None,\n        allowed_paulis: str = 'XYZ',\n    ) -> stim.PauliStringIterator:\n        \"\"\"Returns an iterator that iterates over all matching pauli strings.\n\n        Args:\n            num_qubits: The desired number of qubits in the pauli strings.\n            min_weight: Defaults to 0. The minimum number of non-identity terms that\n                must be present in each yielded pauli string.\n            max_weight: Defaults to None (unused). The maximum number of non-identity\n                terms that must be present in each yielded pauli string.\n            allowed_paulis: Defaults to \"XYZ\". Set this to a string containing the\n                non-identity paulis that are allowed to appear in each yielded pauli\n                string. This argument must be a string made up of only \"X\", \"Y\", and\n                \"Z\" characters. A non-identity Pauli is allowed if it appears in the\n                string, and not allowed if it doesn't. Identity Paulis are always\n                allowed.\n\n        Returns:\n            An Iterable[stim.PauliString] that yields the requested pauli strings.\n\n        Examples:\n            >>> import stim\n            >>> pauli_string_iterator = stim.PauliString.iter_all(\n            ...     num_qubits=3,\n            ...     min_weight=1,\n            ...     max_weight=2,\n            ...     allowed_paulis=\"XZ\",\n            ... )\n            >>> for p in pauli_string_iterator:\n            ...     print(p)\n            +X__\n            +Z__\n            +_X_\n            +_Z_\n            +__X\n            +__Z\n            +XX_\n            +XZ_\n            +ZX_\n            +ZZ_\n            +X_X\n            +X_Z\n            +Z_X\n            +Z_Z\n            +_XX\n            +_XZ\n            +_ZX\n            +_ZZ\n        \"\"\"\n    def pauli_indices(\n        self,\n        included_paulis: str = \"XYZ\",\n    ) -> List[int]:\n        \"\"\"Returns the indices of non-identity Paulis, or of specified Paulis.\n\n        Args:\n            include: A string containing the Pauli types to include.\n                X type Pauli indices are included if \"X\" or \"x\" is in the string.\n                Y type Pauli indices are included if \"Y\" or \"y\" is in the string.\n                Z type Pauli indices are included if \"Z\" or \"z\" is in the string.\n                I type Pauli indices are included if \"I\" or \"_\" is in the string.\n                An exception is thrown if other characters are in the string.\n\n        Returns:\n            A list containing the ascending indices of matching Pauli terms.\n\n        Examples:\n            >>> import stim\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices()\n            [5, 9, 14]\n\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"XZ\")\n            [5, 14]\n\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"X\")\n            [5]\n\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"Y\")\n            [9]\n\n            >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"IY\")\n            [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17]\n\n            >>> stim.PauliString(\"-X103*Y100\").pauli_indices()\n            [100, 103]\n        \"\"\"\n    @staticmethod\n    def random(\n        num_qubits: int,\n        *,\n        allow_imaginary: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Samples a uniformly random Hermitian Pauli string.\n\n        Args:\n            num_qubits: The number of qubits the Pauli string should act on.\n            allow_imaginary: Defaults to False. If True, the sign of the result may be\n                1j or -1j in addition to +1 or -1. In other words, setting this to True\n                allows the result to be non-Hermitian.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString.random(5)\n            >>> len(p)\n            5\n            >>> p.sign in [-1, +1]\n            True\n\n            >>> p2 = stim.PauliString.random(3, allow_imaginary=True)\n            >>> len(p2)\n            3\n            >>> p2.sign in [-1, +1, 1j, -1j]\n            True\n\n        Returns:\n            The sampled Pauli string.\n        \"\"\"\n    @property\n    def sign(\n        self,\n    ) -> complex:\n        \"\"\"The sign of the Pauli string. Can be +1, -1, 1j, or -1j.\n\n        Examples:\n            >>> import stim\n            >>> stim.PauliString(\"X\").sign\n            (1+0j)\n            >>> stim.PauliString(\"-X\").sign\n            (-1+0j)\n            >>> stim.PauliString(\"iX\").sign\n            1j\n            >>> stim.PauliString(\"-iX\").sign\n            (-0-1j)\n        \"\"\"\n    @sign.setter\n    def sign(self, value: complex):\n        pass\n    def to_numpy(\n        self,\n        *,\n        bit_packed: bool = False,\n    ) -> Tuple[np.ndarray, np.ndarray]:\n        \"\"\"Decomposes the contents of the pauli string into X bit and Z bit numpy arrays.\n\n        Args:\n            bit_packed: Defaults to False. Determines whether the output numpy arrays\n                use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n        Returns:\n            An (xs, zs) tuple encoding the paulis from the string. The k'th Pauli from\n            the string is encoded into k'th bit of xs and the k'th bit of zs using\n            the \"xz\" encoding:\n\n                P=I -> x=0 and z=0\n                P=X -> x=1 and z=0\n                P=Y -> x=1 and z=1\n                P=Z -> x=0 and z=1\n\n            The dtype and shape of the result depends on the bit_packed argument.\n\n            If bit_packed=False:\n                Each bit gets its own byte.\n                xs.dtype = zs.dtype = np.bool_\n                xs.shape = zs.shape = len(self)\n                xs_k = xs[k]\n                zs_k = zs[k]\n\n            If bit_packed=True:\n                Equivalent to applying np.packbits(bitorder='little') to the result.\n                xs.dtype = zs.dtype = np.uint8\n                xs.shape = zs.shape = math.ceil(len(self) / 8)\n                xs_k = (xs[k // 8] >> (k % 8)) & 1\n                zs_k = (zs[k // 8] >> (k % 8)) & 1\n\n        Examples:\n            >>> import stim\n\n            >>> xs, zs = stim.PauliString(\"XXXXYYYZZ\").to_numpy()\n            >>> xs\n            array([ True,  True,  True,  True,  True,  True,  True, False, False])\n            >>> zs\n            array([False, False, False, False,  True,  True,  True,  True,  True])\n\n            >>> xs, zs = stim.PauliString(\"XXXXYYYZZ\").to_numpy(bit_packed=True)\n            >>> xs\n            array([127,   0], dtype=uint8)\n            >>> zs\n            array([240,   1], dtype=uint8)\n        \"\"\"\n    def to_tableau(\n        self,\n    ) -> stim.Tableau:\n        \"\"\"Creates a Tableau equivalent to this Pauli string.\n\n        The tableau represents a Clifford operation that multiplies qubits\n        by the corresponding Pauli operations from this Pauli string.\n        The global phase of the pauli operation is lost in the conversion.\n\n        Returns:\n            The created tableau.\n\n        Examples:\n            >>> import stim\n            >>> p = stim.PauliString(\"ZZ\")\n            >>> p.to_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"-X_\"),\n                    stim.PauliString(\"-_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_Z\"),\n                ],\n            )\n            >>> q = stim.PauliString(\"YX_Z\")\n            >>> q.to_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"-X___\"),\n                    stim.PauliString(\"+_X__\"),\n                    stim.PauliString(\"+__X_\"),\n                    stim.PauliString(\"-___X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"-Z___\"),\n                    stim.PauliString(\"-_Z__\"),\n                    stim.PauliString(\"+__Z_\"),\n                    stim.PauliString(\"+___Z\"),\n                ],\n            )\n        \"\"\"\n    def to_unitary_matrix(\n        self,\n        *,\n        endian: Literal[\"little\", \"big\"],\n    ) -> np.ndarray[np.complex64]:\n        \"\"\"Converts the pauli string into a unitary matrix.\n\n        Args:\n            endian:\n                \"little\": The first qubit is the least significant (corresponds\n                    to an offset of 1 in the matrix).\n                \"big\": The first qubit is the most significant (corresponds\n                    to an offset of 2**(n - 1) in the matrix).\n\n        Returns:\n            A numpy array with dtype=np.complex64 and\n            shape=(1 << len(pauli_string), 1 << len(pauli_string)).\n\n        Example:\n            >>> import stim\n            >>> stim.PauliString(\"-YZ\").to_unitary_matrix(endian=\"little\")\n            array([[0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j],\n                   [0.-1.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j],\n                   [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j]], dtype=complex64)\n        \"\"\"\n    @property\n    def weight(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of non-identity pauli terms in the pauli string.\n\n        Examples:\n            >>> import stim\n            >>> stim.PauliString(\"+___\").weight\n            0\n            >>> stim.PauliString(\"+__X\").weight\n            1\n            >>> stim.PauliString(\"+XYZ\").weight\n            3\n            >>> stim.PauliString(\"-XXX___XXYZ\").weight\n            7\n        \"\"\"\nclass PauliStringIterator:\n    \"\"\"Iterates over all pauli strings matching specified patterns.\n\n    Examples:\n        >>> import stim\n        >>> pauli_string_iterator = stim.PauliString.iter_all(\n        ...     2,\n        ...     min_weight=1,\n        ...     max_weight=1,\n        ...     allowed_paulis=\"XZ\",\n        ... )\n        >>> for p in pauli_string_iterator:\n        ...     print(p)\n        +X_\n        +Z_\n        +_X\n        +_Z\n    \"\"\"\n    def __iter__(\n        self,\n    ) -> stim.PauliStringIterator:\n        \"\"\"Returns an independent copy of the pauli string iterator.\n\n        Since for-loops and loop-comprehensions call `iter` on things they\n        iterate, this effectively allows the iterator to be iterated\n        multiple times.\n        \"\"\"\n    def __next__(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Returns the next iterated pauli string.\n        \"\"\"\nclass Tableau:\n    \"\"\"A stabilizer tableau.\n\n    Represents a Clifford operation by explicitly storing how that operation\n    conjugates a list of Pauli group generators into composite Pauli products.\n\n    Examples:\n        >>> import stim\n        >>> stim.Tableau.from_named_gate(\"H\")\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X\"),\n            ],\n        )\n\n        >>> t = stim.Tableau.random(5)\n        >>> t_inv = t**-1\n        >>> print(t * t_inv)\n        +-xz-xz-xz-xz-xz-\n        | ++ ++ ++ ++ ++\n        | XZ __ __ __ __\n        | __ XZ __ __ __\n        | __ __ XZ __ __\n        | __ __ __ XZ __\n        | __ __ __ __ XZ\n\n        >>> x2z3 = t.x_output(2) * t.z_output(3)\n        >>> t_inv(x2z3)\n        stim.PauliString(\"+__XZ_\")\n    \"\"\"\n    def __add__(\n        self,\n        rhs: stim.Tableau,\n    ) -> stim.Tableau:\n        \"\"\"Returns the direct sum (diagonal concatenation) of two Tableaus.\n\n        Args:\n            rhs: A second stim.Tableau.\n\n        Examples:\n            >>> import stim\n\n            >>> s = stim.Tableau.from_named_gate(\"S\")\n            >>> cz = stim.Tableau.from_named_gate(\"CZ\")\n            >>> print(s + cz)\n            +-xz-xz-xz-\n            | ++ ++ ++\n            | YZ __ __\n            | __ XZ Z_\n            | __ Z_ XZ\n\n        Returns:\n            The direct sum.\n        \"\"\"\n    def __call__(\n        self,\n        pauli_string: stim.PauliString,\n    ) -> stim.PauliString:\n        \"\"\"Returns the equivalent PauliString after the Tableau's Clifford operation.\n\n        If P is a Pauli product before a Clifford operation C, then this method returns\n        Q = C * P * C**-1 (the conjugation of P by C). Q is the equivalent Pauli product\n        after C. This works because:\n\n            C*P\n            = C*P * I\n            = C*P * (C**-1 * C)\n            = (C*P*C**-1) * C\n            = Q*C\n\n        (Keep in mind that A*B means first B is applied, then A is applied.)\n\n        Args:\n            pauli_string: The pauli string to conjugate.\n\n        Returns:\n            The new conjugated pauli string.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> p = stim.PauliString(\"XX\")\n            >>> result = t(p)\n            >>> print(result)\n            +X_\n        \"\"\"\n    def __eq__(\n        self,\n        arg0: stim.Tableau,\n    ) -> bool:\n        \"\"\"Determines if two tableaus have identical contents.\n        \"\"\"\n    def __iadd__(\n        self,\n        rhs: stim.Tableau,\n    ) -> stim.Tableau:\n        \"\"\"Performs an inplace direct sum (diagonal concatenation).\n\n        Args:\n            rhs: A second stim.Tableau.\n\n        Examples:\n            >>> import stim\n\n            >>> s = stim.Tableau.from_named_gate(\"S\")\n            >>> cz = stim.Tableau.from_named_gate(\"CZ\")\n            >>> alias = s\n            >>> s += cz\n            >>> alias is s\n            True\n            >>> print(s)\n            +-xz-xz-xz-\n            | ++ ++ ++\n            | YZ __ __\n            | __ XZ Z_\n            | __ Z_ XZ\n\n        Returns:\n            The mutated tableau.\n        \"\"\"\n    def __init__(\n        self,\n        num_qubits: int,\n    ) -> None:\n        \"\"\"Creates an identity tableau over the given number of qubits.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau(3)\n            >>> print(t)\n            +-xz-xz-xz-\n            | ++ ++ ++\n            | XZ __ __\n            | __ XZ __\n            | __ __ XZ\n\n        Args:\n            num_qubits: The number of qubits the tableau's operation acts on.\n        \"\"\"\n    def __len__(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of qubits operated on by the tableau.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> len(t)\n            2\n        \"\"\"\n    def __mul__(\n        self,\n        rhs: stim.Tableau,\n    ) -> stim.Tableau:\n        \"\"\"Returns the product of two tableaus.\n\n        If the tableau T1 represents the Clifford operation with unitary C1,\n        and the tableau T2 represents the Clifford operation with unitary C2,\n        then the tableau T1*T2 represents the Clifford operation with unitary C1*C2.\n\n        Args:\n            rhs: The tableau  on the right hand side of the multiplication.\n\n        Examples:\n            >>> import stim\n            >>> t1 = stim.Tableau.random(4)\n            >>> t2 = stim.Tableau.random(4)\n            >>> t3 = t2 * t1\n            >>> p = stim.PauliString.random(4)\n            >>> t3(p) == t2(t1(p))\n            True\n        \"\"\"\n    def __ne__(\n        self,\n        arg0: stim.Tableau,\n    ) -> bool:\n        \"\"\"Determines if two tableaus have non-identical contents.\n        \"\"\"\n    def __pow__(\n        self,\n        exponent: int,\n    ) -> stim.Tableau:\n        \"\"\"Raises the tableau to an integer power.\n\n        Large powers are reached efficiently using repeated squaring.\n        Negative powers are reached by inverting the tableau.\n\n        Args:\n            exponent: The power to raise to. Can be negative, zero, or positive.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.Tableau.from_named_gate(\"S\")\n            >>> s**0 == stim.Tableau(1)\n            True\n            >>> s**1 == s\n            True\n            >>> s**2 == stim.Tableau.from_named_gate(\"Z\")\n            True\n            >>> s**-1 == s**3 == stim.Tableau.from_named_gate(\"S_DAG\")\n            True\n            >>> s**5 == s\n            True\n            >>> s**(400000000 + 1) == s\n            True\n            >>> s**(-400000000 + 1) == s\n            True\n        \"\"\"\n    def __repr__(\n        self,\n    ) -> str:\n        \"\"\"Returns valid python code evaluating to an equal `stim.Tableau`.\n        \"\"\"\n    def __str__(\n        self,\n    ) -> str:\n        \"\"\"Returns a text description.\n        \"\"\"\n    def append(\n        self,\n        gate: stim.Tableau,\n        targets: Sequence[int],\n    ) -> None:\n        \"\"\"Appends an operation's effect into this tableau, mutating this tableau.\n\n        Time cost is O(n*m*m) where n=len(self) and m=len(gate).\n\n        Args:\n            gate: The tableau of the operation being appended into this tableau.\n            targets: The qubits being targeted by the gate.\n\n        Examples:\n            >>> import stim\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> t = stim.Tableau(2)\n            >>> t.append(cnot, [0, 1])\n            >>> t.append(cnot, [1, 0])\n            >>> t.append(cnot, [0, 1])\n            >>> t == stim.Tableau.from_named_gate(\"SWAP\")\n            True\n        \"\"\"\n    def copy(\n        self,\n    ) -> stim.Tableau:\n        \"\"\"Returns a copy of the tableau. An independent tableau with the same contents.\n\n        Examples:\n            >>> import stim\n            >>> t1 = stim.Tableau.random(2)\n            >>> t2 = t1.copy()\n            >>> t2 is t1\n            False\n            >>> t2 == t1\n            True\n        \"\"\"\n    @staticmethod\n    def from_circuit(\n        circuit: stim.Circuit,\n        *,\n        ignore_noise: bool = False,\n        ignore_measurement: bool = False,\n        ignore_reset: bool = False,\n    ) -> stim.Tableau:\n        \"\"\"Converts a circuit into an equivalent stabilizer tableau.\n\n        Args:\n            circuit: The circuit to compile into a tableau.\n            ignore_noise: Defaults to False. When False, any noise operations in the\n                circuit will cause the conversion to fail with an exception. When True,\n                noise operations are skipped over as if they weren't even present in the\n                circuit.\n            ignore_measurement: Defaults to False. When False, any measurement\n                operations in the circuit will cause the conversion to fail with an\n                exception. When True, measurement operations are skipped over as if they\n                weren't even present in the circuit.\n            ignore_reset: Defaults to False. When False, any reset operations in the\n                circuit will cause the conversion to fail with an exception. When True,\n                reset operations are skipped over as if they weren't even present in the\n                circuit.\n\n        Returns:\n            The tableau equivalent to the given circuit (up to global phase).\n\n        Raises:\n            ValueError:\n                The circuit contains noise operations but ignore_noise=False.\n                OR\n                The circuit contains measurement operations but\n                ignore_measurement=False.\n                OR\n                The circuit contains reset operations but ignore_reset=False.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_circuit(stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ... '''))\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n        \"\"\"\n    @staticmethod\n    def from_conjugated_generators(\n        *,\n        xs: List[stim.PauliString],\n        zs: List[stim.PauliString],\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau from the given outputs for each generator.\n\n        Verifies that the tableau is well formed.\n\n        Args:\n            xs: A List[stim.PauliString] with the results of conjugating X0, X1, etc.\n            zs: A List[stim.PauliString] with the results of conjugating Z0, Z1, etc.\n\n        Returns:\n            The created tableau.\n\n        Raises:\n            ValueError: The given outputs are malformed. Their lengths are inconsistent,\n                or they don't satisfy the required commutation relationships.\n\n        Examples:\n            >>> import stim\n            >>> identity3 = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"X__\"),\n            ...         stim.PauliString(\"_X_\"),\n            ...         stim.PauliString(\"__X\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"Z__\"),\n            ...         stim.PauliString(\"_Z_\"),\n            ...         stim.PauliString(\"__Z\"),\n            ...     ],\n            ... )\n            >>> identity3 == stim.Tableau(3)\n            True\n        \"\"\"\n    @staticmethod\n    def from_named_gate(\n        name: str,\n    ) -> stim.Tableau:\n        \"\"\"Returns the tableau of a named Clifford gate.\n\n        Args:\n            name: The name of the Clifford gate.\n\n        Returns:\n            The gate's tableau.\n\n        Examples:\n            >>> import stim\n            >>> print(stim.Tableau.from_named_gate(\"H\"))\n            +-xz-\n            | ++\n            | ZX\n            >>> print(stim.Tableau.from_named_gate(\"CNOT\"))\n            +-xz-xz-\n            | ++ ++\n            | XZ _Z\n            | X_ XZ\n            >>> print(stim.Tableau.from_named_gate(\"S\"))\n            +-xz-\n            | ++\n            | YZ\n        \"\"\"\n    def from_numpy(\n        self,\n        *,\n        x2x: np.ndarray,\n        x2z: np.ndarray,\n        z2x: np.ndarray,\n        z2z: np.ndarray,\n        x_signs: Optional[np.ndarray] = None,\n        z_signs: Optional[np.ndarray] = None,\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau from numpy arrays x2x, x2z, z2x, z2z, x_signs, and z_signs.\n\n        The x2x, x2z, z2x, z2z arrays are the four quadrants of the table defined in\n        Aaronson and Gottesman's \"Improved Simulation of Stabilizer Circuits\"\n        ( https://arxiv.org/abs/quant-ph/0406196 ).\n\n        Args:\n            x2x: A 2d numpy array containing the x-to-x coupling bits. The bits can be\n                bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                result will satisfy result.x_output_pauli(i, j) in [1, 2] == x2x[i, j].\n                Bit packing must be in little endian order and only applies to the\n                second axis.\n            x2z: A 2d numpy array containing the x-to-z coupling bits. The bits can be\n                bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                result will satisfy result.x_output_pauli(i, j) in [2, 3] == x2z[i, j].\n                Bit packing must be in little endian order and only applies to the\n                second axis.\n            z2x: A 2d numpy array containing the z-to-x coupling bits. The bits can be\n                bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                result will satisfy result.z_output_pauli(i, j) in [1, 2] == z2x[i, j].\n                Bit packing must be in little endian order and only applies to the\n                second axis.\n            z2z: A 2d numpy array containing the z-to-z coupling bits. The bits can be\n                bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                result will satisfy result.z_output_pauli(i, j) in [2, 3] == z2z[i, j].\n                Bit packing must be in little endian order and only applies to the\n                second axis.\n            x_signs: Defaults to all-positive if not specified. A 1d numpy array\n                containing the sign bits for the X generator outputs. False means\n                positive and True means negative. The bits can be bit packed\n                (dtype=uint8) or not (dtype=bool_). Bit packing must be in little endian\n                order.\n            z_signs: Defaults to all-positive if not specified. A 1d numpy array\n                containing the sign bits for the Z generator outputs. False means\n                positive and True means negative. The bits can be bit packed\n                (dtype=uint8) or not (dtype=bool_). Bit packing must be in little endian\n                order.\n\n        Returns:\n            The tableau created from the numpy data.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n\n            >>> tableau = stim.Tableau.from_numpy(\n            ...     x2x=np.array([[1, 1], [0, 1]], dtype=np.bool_),\n            ...     z2x=np.array([[0, 0], [0, 0]], dtype=np.bool_),\n            ...     x2z=np.array([[0, 0], [0, 0]], dtype=np.bool_),\n            ...     z2z=np.array([[1, 0], [1, 1]], dtype=np.bool_),\n            ... )\n            >>> tableau\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n            >>> tableau == stim.Tableau.from_named_gate(\"CNOT\")\n            True\n\n            >>> stim.Tableau.from_numpy(\n            ...     x2x=np.array([[9], [5], [7], [6]], dtype=np.uint8),\n            ...     x2z=np.array([[13], [13], [0], [3]], dtype=np.uint8),\n            ...     z2x=np.array([[8], [5], [9], [15]], dtype=np.uint8),\n            ...     z2z=np.array([[6], [11], [2], [3]], dtype=np.uint8),\n            ...     x_signs=np.array([7], dtype=np.uint8),\n            ...     z_signs=np.array([9], dtype=np.uint8),\n            ... )\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"-Y_ZY\"),\n                    stim.PauliString(\"-Y_YZ\"),\n                    stim.PauliString(\"-XXX_\"),\n                    stim.PauliString(\"+ZYX_\"),\n                ],\n                zs=[\n                    stim.PauliString(\"-_ZZX\"),\n                    stim.PauliString(\"+YZXZ\"),\n                    stim.PauliString(\"+XZ_X\"),\n                    stim.PauliString(\"-YYXX\"),\n                ],\n            )\n        \"\"\"\n    @staticmethod\n    def from_stabilizers(\n        stabilizers: Iterable[stim.PauliString],\n        *,\n        allow_redundant: bool = False,\n        allow_underconstrained: bool = False,\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau representing a state with the given stabilizers.\n\n        Args:\n            stabilizers: A list of `stim.PauliString`s specifying the stabilizers that\n                the state must have. It is permitted for stabilizers to have different\n                lengths. All stabilizers are padded up to the length of the longest\n                stabilizer by appending identity terms.\n            allow_redundant: Defaults to False. If set to False, then the given\n                stabilizers must all be independent. If any one of them is a product of\n                the others (including the empty product), an exception will be raised.\n                If set to True, then redundant stabilizers are simply ignored.\n            allow_underconstrained: Defaults to False. If set to False, then the given\n                stabilizers must form a complete set of generators. They must exactly\n                specify the desired stabilizer state, with no degrees of freedom left\n                over. For an n-qubit state there must be n independent stabilizers. If\n                set to True, then there can be leftover degrees of freedom which can be\n                set arbitrarily.\n\n        Returns:\n            A tableau which, when applied to the all-zeroes state, produces a state\n            with the given stabilizers.\n\n            Guarantees that result.z_output(k) will be equal to the k'th independent\n            stabilizer from the `stabilizers` argument.\n\n        Raises:\n            ValueError:\n                A stabilizer is redundant but allow_redundant=True wasn't set.\n                OR\n                The given stabilizers are contradictory (e.g. \"+Z\" and \"-Z\" both\n                specified).\n                OR\n                The given stabilizers anticommute (e.g. \"+Z\" and \"+X\" both specified).\n                OR\n                The stabilizers left behind a degree of freedom but\n                allow_underconstrained=True wasn't set.\n                OR\n                A stabilizer has an imaginary sign (i or -i).\n\n        Examples:\n\n            >>> import stim\n            >>> stim.Tableau.from_stabilizers([\n            ...     stim.PauliString(\"XX\"),\n            ...     stim.PauliString(\"ZZ\"),\n            ... ])\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n\n            >>> stim.Tableau.from_stabilizers([\n            ...     stim.PauliString(\"XX_\"),\n            ...     stim.PauliString(\"ZZ_\"),\n            ...     stim.PauliString(\"-YY_\"),\n            ...     stim.PauliString(\"\"),\n            ... ], allow_underconstrained=True, allow_redundant=True)\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z__\"),\n                    stim.PauliString(\"+_X_\"),\n                    stim.PauliString(\"+__X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX_\"),\n                    stim.PauliString(\"+ZZ_\"),\n                    stim.PauliString(\"+__Z\"),\n                ],\n            )\n        \"\"\"\n    @staticmethod\n    def from_state_vector(\n        state_vector: Iterable[float],\n        *,\n        endian: Literal[\"little\", \"big\"],\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau representing the stabilizer state of the given state vector.\n\n        Args:\n            state_vector: A list of complex amplitudes specifying a superposition. The\n                vector must correspond to a state that is reachable using Clifford\n                operations, and can be unnormalized.\n            endian:\n                \"little\": state vector is in little endian order, where higher index\n                    qubits correspond to larger changes in the state index.\n                \"big\": state vector is in big endian order, where higher index qubits\n                    correspond to smaller changes in the state index.\n\n        Returns:\n            A tableau which, when applied to the all-zeroes state, produces a state\n            with the given state vector.\n\n        Raises:\n            ValueError:\n                The given state vector isn't a list of complex values specifying a\n                stabilizer state.\n                OR\n                The given endian value isn't 'little' or 'big'.\n\n        Examples:\n\n            >>> import stim\n            >>> stim.Tableau.from_state_vector([\n            ...     0.5**0.5,\n            ...     0.5**0.5 * 1j,\n            ... ], endian='little')\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Y\"),\n                ],\n            )\n            >>> stim.Tableau.from_state_vector([\n            ...     0.5**0.5,\n            ...     0,\n            ...     0,\n            ...     0.5**0.5,\n            ... ], endian='little')\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n        \"\"\"\n    @staticmethod\n    def from_unitary_matrix(\n        matrix: Iterable[Iterable[float]],\n        *,\n        endian: Literal[\"little\", \"big\"] = 'little',\n    ) -> stim.Tableau:\n        \"\"\"Creates a tableau from the unitary matrix of a Clifford operation.\n\n        Args:\n            matrix: A unitary matrix specified as an iterable of rows, with each row is\n                an iterable of amplitudes. The unitary matrix must correspond to a\n                Clifford operation.\n            endian:\n                \"little\": matrix entries are in little endian order, where higher index\n                    qubits correspond to larger changes in row/col indices.\n                \"big\": matrix entries are in big endian order, where higher index\n                    qubits correspond to smaller changes in row/col indices.\n        Returns:\n            The tableau equivalent to the given unitary matrix (up to global phase).\n\n        Raises:\n            ValueError: The given matrix isn't the unitary matrix of a Clifford\n                operation.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_unitary_matrix([\n            ...     [1, 0],\n            ...     [0, 1j],\n            ... ], endian='little')\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Y\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n            )\n\n            >>> stim.Tableau.from_unitary_matrix([\n            ...     [1, 0, 0, 0],\n            ...     [0, 1, 0, 0],\n            ...     [0, 0, 0, -1j],\n            ...     [0, 0, 1j, 0],\n            ... ], endian='little')\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+XZ\"),\n                    stim.PauliString(\"+YX\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+ZZ\"),\n                    stim.PauliString(\"+_Z\"),\n                ],\n            )\n        \"\"\"\n    def inverse(\n        self,\n        *,\n        unsigned: bool = False,\n    ) -> stim.Tableau:\n        \"\"\"Computes the inverse of the tableau.\n\n        The inverse T^-1 of a tableau T is the unique tableau with the property that\n        T * T^-1 = T^-1 * T = I where I is the identity tableau.\n\n        Args:\n            unsigned: Defaults to false. When set to true, skips computing the signs of\n                the output observables and instead just set them all to be positive.\n                This is beneficial because computing the signs takes O(n^3) time and the\n                rest of the inverse computation is O(n^2) where n is the number of\n                qubits in the tableau. So, if you only need the Pauli terms (not the\n                signs), it is significantly cheaper.\n\n        Returns:\n            The inverse tableau.\n\n        Examples:\n            >>> import stim\n\n            >>> # Check that the inverse agrees with hard-coded tableaus.\n            >>> s = stim.Tableau.from_named_gate(\"S\")\n            >>> s_dag = stim.Tableau.from_named_gate(\"S_DAG\")\n            >>> s.inverse() == s_dag\n            True\n            >>> z = stim.Tableau.from_named_gate(\"Z\")\n            >>> z.inverse() == z\n            True\n\n            >>> # Check that multiplying by the inverse produces the identity.\n            >>> t = stim.Tableau.random(10)\n            >>> t_inv = t.inverse()\n            >>> identity = stim.Tableau(10)\n            >>> t * t_inv == t_inv * t == identity\n            True\n\n            >>> # Check a manual case.\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"-__Z\"),\n            ...         stim.PauliString(\"+XZ_\"),\n            ...         stim.PauliString(\"+_ZZ\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"-YYY\"),\n            ...         stim.PauliString(\"+Z_Z\"),\n            ...         stim.PauliString(\"-ZYZ\")\n            ...     ],\n            ... )\n            >>> print(t.inverse())\n            +-xz-xz-xz-\n            | -- +- --\n            | XX XX YX\n            | XZ Z_ X_\n            | X_ YX Y_\n            >>> print(t.inverse(unsigned=True))\n            +-xz-xz-xz-\n            | ++ ++ ++\n            | XX XX YX\n            | XZ Z_ X_\n            | X_ YX Y_\n        \"\"\"\n    def inverse_x_output(\n        self,\n        input_index: int,\n        *,\n        unsigned: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Conjugates a single-qubit X Pauli generator by the inverse of the tableau.\n\n        A faster version of `tableau.inverse(unsigned).x_output(input_index)`.\n\n        Args:\n            input_index: Identifies the column (the qubit of the X generator) to return\n                from the inverse tableau.\n            unsigned: Defaults to false. When set to true, skips computing the result's\n                sign and instead just sets it to positive. This is beneficial because\n                computing the sign takes O(n^2) time whereas all other parts of the\n                computation take O(n) time where n is the number of qubits in the\n                tableau.\n\n        Returns:\n            The result of conjugating an X generator by the inverse of the tableau.\n\n        Examples:\n            >>> import stim\n\n            # Check equivalence with the inverse's x_output.\n            >>> t = stim.Tableau.random(4)\n            >>> expected = t.inverse().x_output(0)\n            >>> t.inverse_x_output(0) == expected\n            True\n            >>> expected.sign = +1\n            >>> t.inverse_x_output(0, unsigned=True) == expected\n            True\n        \"\"\"\n    def inverse_x_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.inverse().x_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the column (the qubit of the input X generator) in\n                the inverse tableau.\n            output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n        Returns:\n            An integer identifying Pauli at the given location in the inverse tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t_inv = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... ).inverse()\n            >>> t_inv.inverse_x_output_pauli(0, 0)\n            2\n            >>> t_inv.inverse_x_output_pauli(0, 1)\n            0\n            >>> t_inv.inverse_x_output_pauli(1, 0)\n            2\n            >>> t_inv.inverse_x_output_pauli(1, 1)\n            3\n        \"\"\"\n    def inverse_y_output(\n        self,\n        input_index: int,\n        *,\n        unsigned: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Conjugates a single-qubit Y Pauli generator by the inverse of the tableau.\n\n        A faster version of `tableau.inverse(unsigned).y_output(input_index)`.\n\n        Args:\n            input_index: Identifies the column (the qubit of the Y generator) to return\n                from the inverse tableau.\n            unsigned: Defaults to false. When set to true, skips computing the result's\n                sign and instead just sets it to positive. This is beneficial because\n                computing the sign takes O(n^2) time whereas all other parts of the\n                computation take O(n) time where n is the number of qubits in the\n                tableau.\n\n        Returns:\n            The result of conjugating a Y generator by the inverse of the tableau.\n\n        Examples:\n            >>> import stim\n\n            # Check equivalence with the inverse's y_output.\n            >>> t = stim.Tableau.random(4)\n            >>> expected = t.inverse().y_output(0)\n            >>> t.inverse_y_output(0) == expected\n            True\n            >>> expected.sign = +1\n            >>> t.inverse_y_output(0, unsigned=True) == expected\n            True\n        \"\"\"\n    def inverse_y_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.inverse().y_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the column (the qubit of the input Y generator) in\n                the inverse tableau.\n            output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n        Returns:\n            An integer identifying Pauli at the given location in the inverse tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t_inv = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... ).inverse()\n            >>> t_inv.inverse_y_output_pauli(0, 0)\n            1\n            >>> t_inv.inverse_y_output_pauli(0, 1)\n            2\n            >>> t_inv.inverse_y_output_pauli(1, 0)\n            0\n            >>> t_inv.inverse_y_output_pauli(1, 1)\n            2\n        \"\"\"\n    def inverse_z_output(\n        self,\n        input_index: int,\n        *,\n        unsigned: bool = False,\n    ) -> stim.PauliString:\n        \"\"\"Conjugates a single-qubit Z Pauli generator by the inverse of the tableau.\n\n        A faster version of `tableau.inverse(unsigned).z_output(input_index)`.\n\n        Args:\n            input_index: Identifies the column (the qubit of the Z generator) to return\n                from the inverse tableau.\n            unsigned: Defaults to false. When set to true, skips computing the result's\n                sign and instead just sets it to positive. This is beneficial because\n                computing the sign takes O(n^2) time whereas all other parts of the\n                computation take O(n) time where n is the number of qubits in the\n                tableau.\n\n        Returns:\n            The result of conjugating a Z generator by the inverse of the tableau.\n\n        Examples:\n            >>> import stim\n\n            >>> import stim\n\n            # Check equivalence with the inverse's z_output.\n            >>> t = stim.Tableau.random(4)\n            >>> expected = t.inverse().z_output(0)\n            >>> t.inverse_z_output(0) == expected\n            True\n            >>> expected.sign = +1\n            >>> t.inverse_z_output(0, unsigned=True) == expected\n            True\n        \"\"\"\n    def inverse_z_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.inverse().z_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the column (the qubit of the input Z generator) in\n                the inverse tableau.\n            output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n        Returns:\n            An integer identifying Pauli at the given location in the inverse tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t_inv = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... ).inverse()\n            >>> t_inv.inverse_z_output_pauli(0, 0)\n            3\n            >>> t_inv.inverse_z_output_pauli(0, 1)\n            2\n            >>> t_inv.inverse_z_output_pauli(1, 0)\n            2\n            >>> t_inv.inverse_z_output_pauli(1, 1)\n            1\n        \"\"\"\n    @staticmethod\n    def iter_all(\n        num_qubits: int,\n        *,\n        unsigned: bool = False,\n    ) -> stim.TableauIterator:\n        \"\"\"Returns an iterator that iterates over all Tableaus of a given size.\n\n        Args:\n            num_qubits: The size of tableau to iterate over.\n            unsigned: Defaults to False. If set to True, only tableaus where\n                all columns have positive sign are yielded by the iterator.\n                This substantially reduces the total number of tableaus to\n                iterate over.\n\n        Returns:\n            An Iterable[stim.Tableau] that yields the requested tableaus.\n\n        Examples:\n            >>> import stim\n            >>> single_qubit_gate_reprs = set()\n            >>> for t in stim.Tableau.iter_all(1):\n            ...     single_qubit_gate_reprs.add(repr(t))\n            >>> len(single_qubit_gate_reprs)\n            24\n\n            >>> num_2q_gates_mod_paulis = 0\n            >>> for _ in stim.Tableau.iter_all(2, unsigned=True):\n            ...     num_2q_gates_mod_paulis += 1\n            >>> num_2q_gates_mod_paulis\n            720\n        \"\"\"\n    def prepend(\n        self,\n        gate: stim.Tableau,\n        targets: Sequence[int],\n    ) -> None:\n        \"\"\"Prepends an operation's effect into this tableau, mutating this tableau.\n\n        Time cost is O(n*m*m) where n=len(self) and m=len(gate).\n\n        Args:\n            gate: The tableau of the operation being prepended into this tableau.\n            targets: The qubits being targeted by the gate.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.from_named_gate(\"H\")\n            >>> t.prepend(stim.Tableau.from_named_gate(\"X\"), [0])\n            >>> t == stim.Tableau.from_named_gate(\"SQRT_Y_DAG\")\n            True\n        \"\"\"\n    @staticmethod\n    def random(\n        num_qubits: int,\n    ) -> stim.Tableau:\n        \"\"\"Samples a uniformly random Clifford operation and returns its tableau.\n\n        Args:\n            num_qubits: The number of qubits the tableau should act on.\n\n        Returns:\n            The sampled tableau.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.random(42)\n\n        References:\n            \"Hadamard-free circuits expose the structure of the Clifford group\"\n            Sergey Bravyi, Dmitri Maslov\n            https://arxiv.org/abs/2003.09412\n        \"\"\"\n    def then(\n        self,\n        second: stim.Tableau,\n    ) -> stim.Tableau:\n        \"\"\"Returns the result of composing two tableaus.\n\n        If the tableau T1 represents the Clifford operation with unitary C1,\n        and the tableau T2 represents the Clifford operation with unitary C2,\n        then the tableau T1.then(T2) represents the Clifford operation with unitary\n        C2*C1.\n\n        Args:\n            second: The result is equivalent to applying the second tableau after\n                the receiving tableau.\n\n        Examples:\n            >>> import stim\n            >>> t1 = stim.Tableau.random(4)\n            >>> t2 = stim.Tableau.random(4)\n            >>> t3 = t1.then(t2)\n            >>> p = stim.PauliString.random(4)\n            >>> t3(p) == t2(t1(p))\n            True\n        \"\"\"\n    def to_circuit(\n        self,\n        method: Literal[\"elimination\", \"graph_state\"] = 'elimination',\n    ) -> stim.Circuit:\n        \"\"\"Synthesizes a circuit that implements the tableau's Clifford operation.\n\n        The circuits returned by this method are not guaranteed to be stable\n        from version to version, and may be produced using randomization.\n\n        Args:\n            method: The method to use when synthesizing the circuit. Available values:\n                \"elimination\": Cancels off-diagonal terms using Gaussian elimination.\n                    Gate set: H, S, CX\n                    Circuit qubit count: n\n                    Circuit operation count: O(n^2)\n                    Circuit depth: O(n^2)\n                \"graph_state\": Prepares the tableau's state using a graph state circuit.\n                    Gate set: RX, CZ, H, S, X, Y, Z\n                    Circuit qubit count: n\n                    Circuit operation count: O(n^2)\n\n                    The circuit will be made up of three layers:\n                        1. An RX layer initializing all qubits.\n                        2. A CZ layer coupling the qubits.\n                            (Each CZ is an edge in the graph state.)\n                        3. A single qubit rotation layer.\n\n                    Note: \"graph_state\" treats the tableau as a state instead of as a\n                    Clifford operation. It will preserve the set of stabilizers, but\n                    not the exact choice of generators.\n                \"mpp_state\": Prepares the tableau's state using MPP and feedback.\n                    Gate set: MPP, CX rec, CY rec, CZ rec\n                    Circuit qubit count: n\n                    Circuit operation count: O(n^2)\n\n                    The circuit will be made up of two layers:\n                        1. An MPP layer measuring each of the tableau's stabilizers.\n                        2. A feedback layer using the measurement results to control\n                            whether or not to apply each of the tableau's destabilizers\n                            in order to get the correct sign for each stabilizer.\n\n                    Note: \"mpp_state\" treats the tableau as a state instead of as a\n                    Clifford operation. It will preserve the set of stabilizers, but\n                    not the exact choice of generators.\n                \"mpp_state_unsigned\": Prepares the tableau's state up to sign using MPP.\n                    Gate set: MPP\n                    Circuit qubit count: n\n                    Circuit operation count: O(n^2)\n\n                    The circuit will contain a series of MPP measurements measuring each\n                    of the tableau's stabilizers. The stabilizers are measured in the\n                    order used by the tableau (i.e. tableau.z_output(k) is the k'th\n                    stabilizer measured).\n\n                    Note: \"mpp_state_unsigned\" treats the tableau as a state instead of\n                    as a Clifford operation. It will preserve the set of stabilizers,\n                    but not the exact choice of generators.\n        Returns:\n            The synthesized circuit.\n\n        Example:\n            >>> import stim\n            >>> tableau = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"+YZ__\"),\n            ...         stim.PauliString(\"-Y_XY\"),\n            ...         stim.PauliString(\"+___Y\"),\n            ...         stim.PauliString(\"+YZX_\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"+XZYY\"),\n            ...         stim.PauliString(\"-XYX_\"),\n            ...         stim.PauliString(\"-ZXXZ\"),\n            ...         stim.PauliString(\"+XXZ_\"),\n            ...     ],\n            ... )\n\n            >>> tableau.to_circuit()\n            stim.Circuit('''\n                S 0\n                H 0 1 3\n                CX 0 1 0 2 0 3\n                S 1 3\n                H 1 3\n                CX 1 0 3 0 3 1 1 3 3 1\n                H 1\n                S 1\n                CX 1 3\n                H 2 3\n                CX 2 1 3 1 3 2 2 3 3 2\n                H 3\n                CX 2 3\n                S 3\n                H 3 0 1 2\n                S 0 0 1 1 2 2\n                H 0 1 2\n                S 3 3\n            ''')\n\n            >>> tableau.to_circuit(\"graph_state\")\n            stim.Circuit('''\n                RX 0 1 2 3\n                TICK\n                CZ 0 3 1 2 1 3\n                TICK\n                X 0 1\n                Z 2\n                S 2 3\n                H 3\n                S 3\n            ''')\n\n            >>> tableau.to_circuit(\"mpp_state_unsigned\")\n            stim.Circuit('''\n                MPP X0*Z1*Y2*Y3 !X0*Y1*X2 !Z0*X1*X2*Z3 X0*X1*Z2\n            ''')\n\n            >>> tableau.to_circuit(\"mpp_state\")\n            stim.Circuit('''\n                MPP X0*Z1*Y2*Y3 !X0*Y1*X2 !Z0*X1*X2*Z3 X0*X1*Z2\n                CX rec[-3] 2 rec[-1] 2\n                CY rec[-4] 0 rec[-3] 0 rec[-3] 3 rec[-2] 3 rec[-1] 0\n                CZ rec[-4] 1 rec[-1] 1\n            ''')\n        \"\"\"\n    def to_numpy(\n        self,\n        *,\n        bit_packed: bool = False,\n    ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:\n        \"\"\"Decomposes the contents of the tableau into six numpy arrays.\n\n        The first four numpy arrays correspond to the four quadrants of the table\n        defined in Aaronson and Gottesman's \"Improved Simulation of Stabilizer Circuits\"\n        ( https://arxiv.org/abs/quant-ph/0406196 ).\n\n        The last two numpy arrays are the X and Z sign bit vectors of the tableau.\n\n        Args:\n            bit_packed: Defaults to False. Determines whether the output numpy arrays\n                use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n        Returns:\n            An (x2x, x2z, z2x, z2z, x_signs, z_signs) tuple encoding the tableau.\n\n            x2x: A 2d table of whether tableau(X_i)_j is X or Y (instead of I or Z).\n            x2z: A 2d table of whether tableau(X_i)_j is Z or Y (instead of I or X).\n            z2x: A 2d table of whether tableau(Z_i)_j is X or Y (instead of I or Z).\n            z2z: A 2d table of whether tableau(Z_i)_j is Z or Y (instead of I or X).\n            x_signs: A vector of whether tableau(X_i) is negative.\n            z_signs: A vector of whether tableau(Z_i) is negative.\n\n            If bit_packed=False then:\n                x2x.dtype = np.bool_\n                x2z.dtype = np.bool_\n                z2x.dtype = np.bool_\n                z2z.dtype = np.bool_\n                x_signs.dtype = np.bool_\n                z_signs.dtype = np.bool_\n                x2x.shape = (len(tableau), len(tableau))\n                x2z.shape = (len(tableau), len(tableau))\n                z2x.shape = (len(tableau), len(tableau))\n                z2z.shape = (len(tableau), len(tableau))\n                x_signs.shape = len(tableau)\n                z_signs.shape = len(tableau)\n                x2x[i, j] = tableau.x_output_pauli(i, j) in [1, 2]\n                x2z[i, j] = tableau.x_output_pauli(i, j) in [2, 3]\n                z2x[i, j] = tableau.z_output_pauli(i, j) in [1, 2]\n                z2z[i, j] = tableau.z_output_pauli(i, j) in [2, 3]\n\n            If bit_packed=True then:\n                x2x.dtype = np.uint8\n                x2z.dtype = np.uint8\n                z2x.dtype = np.uint8\n                z2z.dtype = np.uint8\n                x_signs.dtype = np.uint8\n                z_signs.dtype = np.uint8\n                x2x.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                x2z.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                z2x.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                z2z.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                x_signs.shape = math.ceil(len(tableau) / 8)\n                z_signs.shape = math.ceil(len(tableau) / 8)\n                (x2x[i, j // 8] >> (j % 8)) & 1 = tableau.x_output_pauli(i, j) in [1, 2]\n                (x2z[i, j // 8] >> (j % 8)) & 1 = tableau.x_output_pauli(i, j) in [2, 3]\n                (z2x[i, j // 8] >> (j % 8)) & 1 = tableau.z_output_pauli(i, j) in [1, 2]\n                (z2z[i, j // 8] >> (j % 8)) & 1 = tableau.z_output_pauli(i, j) in [2, 3]\n\n        Examples:\n            >>> import stim\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> print(repr(cnot))\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n            >>> x2x, x2z, z2x, z2z, x_signs, z_signs = cnot.to_numpy()\n            >>> x2x\n            array([[ True,  True],\n                   [False,  True]])\n            >>> x2z\n            array([[False, False],\n                   [False, False]])\n            >>> z2x\n            array([[False, False],\n                   [False, False]])\n            >>> z2z\n            array([[ True, False],\n                   [ True,  True]])\n            >>> x_signs\n            array([False, False])\n            >>> z_signs\n            array([False, False])\n\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"-Y_ZY\"),\n            ...         stim.PauliString(\"-Y_YZ\"),\n            ...         stim.PauliString(\"-XXX_\"),\n            ...         stim.PauliString(\"+ZYX_\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"-_ZZX\"),\n            ...         stim.PauliString(\"+YZXZ\"),\n            ...         stim.PauliString(\"+XZ_X\"),\n            ...         stim.PauliString(\"-YYXX\"),\n            ...     ],\n            ... )\n\n            >>> x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy()\n            >>> x2x\n            array([[ True, False, False,  True],\n                   [ True, False,  True, False],\n                   [ True,  True,  True, False],\n                   [False,  True,  True, False]])\n            >>> x2z\n            array([[ True, False,  True,  True],\n                   [ True, False,  True,  True],\n                   [False, False, False, False],\n                   [ True,  True, False, False]])\n            >>> z2x\n            array([[False, False, False,  True],\n                   [ True, False,  True, False],\n                   [ True, False, False,  True],\n                   [ True,  True,  True,  True]])\n            >>> z2z\n            array([[False,  True,  True, False],\n                   [ True,  True, False,  True],\n                   [False,  True, False, False],\n                   [ True,  True, False, False]])\n            >>> x_signs\n            array([ True,  True,  True, False])\n            >>> z_signs\n            array([ True, False, False,  True])\n\n            >>> x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy(bit_packed=True)\n            >>> x2x\n            array([[9],\n                   [5],\n                   [7],\n                   [6]], dtype=uint8)\n            >>> x2z\n            array([[13],\n                   [13],\n                   [ 0],\n                   [ 3]], dtype=uint8)\n            >>> z2x\n            array([[ 8],\n                   [ 5],\n                   [ 9],\n                   [15]], dtype=uint8)\n            >>> z2z\n            array([[ 6],\n                   [11],\n                   [ 2],\n                   [ 3]], dtype=uint8)\n            >>> x_signs\n            array([7], dtype=uint8)\n            >>> z_signs\n            array([9], dtype=uint8)\n        \"\"\"\n    def to_pauli_string(\n        self,\n    ) -> stim.PauliString:\n        \"\"\"Return a Pauli string equivalent to the tableau.\n\n        If the tableau is equivalent to a pauli product, creates\n        an equivalent pauli string. If not, then an error is raised.\n\n        Returns:\n            The created pauli string\n\n        Raises:\n            ValueError: The Tableau isn't equivalent to a Pauli product.\n\n        Example:\n            >>> import stim\n            >>> t = (stim.Tableau.from_named_gate(\"Z\") +\n            ...      stim.Tableau.from_named_gate(\"Y\") +\n            ...      stim.Tableau.from_named_gate(\"I\") +\n            ...      stim.Tableau.from_named_gate(\"X\"))\n            >>> print(t)\n            +-xz-xz-xz-xz-\n            | -+ -- ++ +-\n            | XZ __ __ __\n            | __ XZ __ __\n            | __ __ XZ __\n            | __ __ __ XZ\n            >>> print(t.to_pauli_string())\n            +ZY_X\n        \"\"\"\n    def to_stabilizers(\n        self,\n        *,\n        canonicalize: bool = False,\n    ) -> List[stim.PauliString]:\n        \"\"\"Returns the stabilizer generators of the tableau, optionally canonicalized.\n\n        The stabilizer generators of the tableau are its Z outputs. Canonicalizing\n        standardizes the generators, so that states that are equal will produce the\n        same generators. For example, [ZI, IZ], [ZI, ZZ], amd [ZZ, ZI] describe equal\n        states and all canonicalize to [ZI, IZ].\n\n        The canonical form is computed as follows:\n\n            1. Get a list of stabilizers using `tableau.z_output(k)` for each k.\n            2. Perform Gaussian elimination. pivoting on standard generators.\n                2a) Pivot on g=X0 first, then Z0, X1, Z1, X2, Z2, etc.\n                2b) Find a stabilizer that uses the generator g. If there are none,\n                    go to the next g.\n                2c) Multiply that stabilizer into all other stabilizers that use the\n                    generator g.\n                2d) Swap that stabilizer with the stabilizer at position `r` then\n                    increment `r`. `r` starts at 0.\n\n        Args:\n            canonicalize: Defaults to False. When False, the tableau's Z outputs\n                are returned unchanged. When True, the Z outputs are rewritten\n                into a standard form. Two stabilizer states have the same standard\n                form if and only if they describe equivalent quantum states.\n\n        Returns:\n            A List[stim.PauliString] of the tableau's stabilizer generators.\n\n        Examples:\n            >>> import stim\n            >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n\n            >>> raw_stabilizers = t.to_stabilizers()\n            >>> for e in raw_stabilizers:\n            ...     print(repr(e))\n            stim.PauliString(\"+Z_\")\n            stim.PauliString(\"+ZZ\")\n\n            >>> canonical_stabilizers = t.to_stabilizers(canonicalize=True)\n            >>> for e in canonical_stabilizers:\n            ...     print(repr(e))\n            stim.PauliString(\"+Z_\")\n            stim.PauliString(\"+_Z\")\n        \"\"\"\n    def to_state_vector(\n        self,\n        *,\n        endian: Literal[\"little\", \"big\"] = 'little',\n    ) -> np.ndarray[np.complex64]:\n        \"\"\"Returns the state vector produced by applying the tableau to the |0..0> state.\n\n        This function takes O(n * 2**n) time and O(2**n) space, where n is the number of\n        qubits. The computation is done by initialization a random state vector and\n        iteratively projecting it into the +1 eigenspace of each stabilizer of the\n        state. The state is then canonicalized so that zero values are actually exactly\n        0, and so that the first non-zero entry is positive.\n\n        Args:\n            endian:\n                \"little\" (default): state vector is in little endian order, where higher\n                    index qubits correspond to larger changes in the state index.\n                \"big\": state vector is in big endian order, where higher index qubits\n                    correspond to smaller changes in the state index.\n\n        Returns:\n            A `numpy.ndarray[numpy.complex64]` of computational basis amplitudes.\n\n            If the result is in little endian order then the amplitude at offset\n            b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n            computational basis state where the qubit with index 0 is storing the bit\n            b_0, the qubit with index 1 is storing the bit b_1, etc.\n\n            If the result is in big endian order then the amplitude at offset\n            b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n            computational basis state where the qubit with index 0 is storing the bit\n            b_{n-1}, the qubit with index 1 is storing the bit b_{n-2}, etc.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> i2 = stim.Tableau.from_named_gate('I')\n            >>> x = stim.Tableau.from_named_gate('X')\n            >>> h = stim.Tableau.from_named_gate('H')\n\n            >>> (x + i2).to_state_vector(endian='little')\n            array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)\n\n            >>> (i2 + x).to_state_vector(endian='little')\n            array([0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], dtype=complex64)\n\n            >>> (i2 + x).to_state_vector(endian='big')\n            array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)\n\n            >>> (h + h).to_state_vector(endian='little')\n            array([0.5+0.j, 0.5+0.j, 0.5+0.j, 0.5+0.j], dtype=complex64)\n        \"\"\"\n    def to_unitary_matrix(\n        self,\n        *,\n        endian: Literal[\"little\", \"big\"],\n    ) -> np.ndarray[np.complex64]:\n        \"\"\"Converts the tableau into a unitary matrix.\n\n        For an n-qubit tableau, this method performs O(n 4^n) work. It uses the state\n        channel duality to transform the tableau into a list of stabilizers, then\n        generates a random state vector and projects it into the +1 eigenspace of each\n        stabilizer.\n\n        Note that tableaus don't have a defined global phase, so the result's global\n        phase may be different from what you expect. For example, the square of\n        SQRT_X's unitary might equal -X instead of +X.\n\n        Args:\n            endian:\n                \"little\": The first qubit is the least significant (corresponds\n                    to an offset of 1 in the state vector).\n                \"big\": The first qubit is the most significant (corresponds\n                    to an offset of 2**(n - 1) in the state vector).\n\n        Returns:\n            A numpy array with dtype=np.complex64 and\n            shape=(1 << len(tableau), 1 << len(tableau)).\n\n        Example:\n            >>> import stim\n            >>> cnot = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"XX\"),\n            ...         stim.PauliString(\"_X\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"Z_\"),\n            ...         stim.PauliString(\"ZZ\"),\n            ...     ],\n            ... )\n            >>> cnot.to_unitary_matrix(endian='big')\n            array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\n                   [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n                   [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]], dtype=complex64)\n        \"\"\"\n    def x_output(\n        self,\n        target: int,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating a Pauli X by the tableau's Clifford operation.\n\n        Args:\n            target: The qubit targeted by the Pauli X operation.\n\n        Examples:\n            >>> import stim\n            >>> h = stim.Tableau.from_named_gate(\"H\")\n            >>> h.x_output(0)\n            stim.PauliString(\"+Z\")\n\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> cnot.x_output(0)\n            stim.PauliString(\"+XX\")\n            >>> cnot.x_output(1)\n            stim.PauliString(\"+_X\")\n        \"\"\"\n    def x_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.x_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the tableau column (the qubit of the input X\n                generator).\n            output_index: Identifies the tableau row (the output qubit).\n\n        Returns:\n            An integer identifying Pauli at the given location in the tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... )\n            >>> t.x_output_pauli(0, 0)\n            2\n            >>> t.x_output_pauli(0, 1)\n            0\n            >>> t.x_output_pauli(1, 0)\n            2\n            >>> t.x_output_pauli(1, 1)\n            3\n        \"\"\"\n    def x_sign(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns just the sign of the result of conjugating an X generator.\n\n        This operation runs in constant time.\n\n        Args:\n            target: The qubit the X generator applies to.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_named_gate(\"S_DAG\").x_sign(0)\n            -1\n            >>> stim.Tableau.from_named_gate(\"S\").x_sign(0)\n            1\n        \"\"\"\n    def y_output(\n        self,\n        target: int,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating a Pauli Y by the tableau's Clifford operation.\n\n        Args:\n            target: The qubit targeted by the Pauli Y operation.\n\n        Examples:\n            >>> import stim\n            >>> h = stim.Tableau.from_named_gate(\"H\")\n            >>> h.y_output(0)\n            stim.PauliString(\"-Y\")\n\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> cnot.y_output(0)\n            stim.PauliString(\"+YX\")\n            >>> cnot.y_output(1)\n            stim.PauliString(\"+ZY\")\n        \"\"\"\n    def y_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.y_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the tableau column (the qubit of the input Y\n                generator).\n            output_index: Identifies the tableau row (the output qubit).\n\n        Returns:\n            An integer identifying Pauli at the given location in the tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... )\n            >>> t.y_output_pauli(0, 0)\n            1\n            >>> t.y_output_pauli(0, 1)\n            2\n            >>> t.y_output_pauli(1, 0)\n            0\n            >>> t.y_output_pauli(1, 1)\n            2\n        \"\"\"\n    def y_sign(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns just the sign of the result of conjugating a Y generator.\n\n        Unlike x_sign and z_sign, this operation runs in linear time.\n        The Y generator has to be computed by multiplying the X and Z\n        outputs and the sign depends on all terms.\n\n        Args:\n            target: The qubit the Y generator applies to.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_named_gate(\"S_DAG\").y_sign(0)\n            1\n            >>> stim.Tableau.from_named_gate(\"S\").y_sign(0)\n            -1\n        \"\"\"\n    def z_output(\n        self,\n        target: int,\n    ) -> stim.PauliString:\n        \"\"\"Returns the result of conjugating a Pauli Z by the tableau's Clifford operation.\n\n        Args:\n            target: The qubit targeted by the Pauli Z operation.\n\n        Examples:\n            >>> import stim\n            >>> h = stim.Tableau.from_named_gate(\"H\")\n            >>> h.z_output(0)\n            stim.PauliString(\"+X\")\n\n            >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n            >>> cnot.z_output(0)\n            stim.PauliString(\"+Z_\")\n            >>> cnot.z_output(1)\n            stim.PauliString(\"+ZZ\")\n        \"\"\"\n    def z_output_pauli(\n        self,\n        input_index: int,\n        output_index: int,\n    ) -> int:\n        \"\"\"Constant-time version of `tableau.z_output(input_index)[output_index]`\n\n        Args:\n            input_index: Identifies the tableau column (the qubit of the input Z\n                generator).\n            output_index: Identifies the tableau row (the output qubit).\n\n        Returns:\n            An integer identifying Pauli at the given location in the tableau:\n\n                0: I\n                1: X\n                2: Y\n                3: Z\n\n        Examples:\n            >>> import stim\n\n            >>> t = stim.Tableau.from_conjugated_generators(\n            ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n            ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n            ... )\n            >>> t.z_output_pauli(0, 0)\n            3\n            >>> t.z_output_pauli(0, 1)\n            2\n            >>> t.z_output_pauli(1, 0)\n            2\n            >>> t.z_output_pauli(1, 1)\n            1\n        \"\"\"\n    def z_sign(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns just the sign of the result of conjugating a Z generator.\n\n        This operation runs in constant time.\n\n        Args:\n            target: The qubit the Z generator applies to.\n\n        Examples:\n            >>> import stim\n            >>> stim.Tableau.from_named_gate(\"SQRT_X_DAG\").z_sign(0)\n            1\n            >>> stim.Tableau.from_named_gate(\"SQRT_X\").z_sign(0)\n            -1\n        \"\"\"\nclass TableauIterator:\n    \"\"\"Iterates over all stabilizer tableaus of a specified size.\n\n    Examples:\n        >>> import stim\n        >>> tableau_iterator = stim.Tableau.iter_all(1)\n        >>> n = 0\n        >>> for single_qubit_clifford in tableau_iterator:\n        ...     n += 1\n        >>> n\n        24\n    \"\"\"\n    def __iter__(\n        self,\n    ) -> stim.TableauIterator:\n        \"\"\"Returns an independent copy of the tableau iterator.\n\n        Since for-loops and loop-comprehensions call `iter` on things they\n        iterate, this effectively allows the iterator to be iterated\n        multiple times.\n        \"\"\"\n    def __next__(\n        self,\n    ) -> stim.Tableau:\n        \"\"\"Returns the next iterated tableau.\n        \"\"\"\nclass TableauSimulator:\n    \"\"\"A stabilizer circuit simulator that tracks an inverse stabilizer tableau.\n\n    Supports interactive usage, where gates and measurements are applied on demand.\n\n    Examples:\n        >>> import stim\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> if s.measure(0):\n        ...     s.h(1)\n        ...     s.cnot(1, 2)\n        >>> s.measure(1) == s.measure(2)\n        True\n\n        >>> s = stim.TableauSimulator()\n        >>> s.h(0)\n        >>> s.cnot(0, 1)\n        >>> s.current_inverse_tableau()\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"+ZX\"),\n                stim.PauliString(\"+_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"+X_\"),\n                stim.PauliString(\"+XZ\"),\n            ],\n        )\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        seed: Optional[int] = None,\n    ) -> None:\n        \"\"\"Initializes a stim.TableauSimulator.\n\n        Args:\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng is seeded from system entropy.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                circuit is executed. For example, reordering whether a reset on one\n                qubit happens before or after a reset on another qubit can result in\n                different measurement results being observed starting from the same\n                seed.\n\n        Returns:\n            An initialized stim.TableauSimulator.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator(seed=0)\n            >>> s2 = stim.TableauSimulator(seed=0)\n            >>> s.h(0)\n            >>> s2.h(0)\n            >>> s.measure(0) == s2.measure(0)\n            True\n        \"\"\"\n    def c_xyz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a C_XYZ gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.c_xyz(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Y +Z +X\n        \"\"\"\n    def c_zyx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a C_ZYX gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.c_zyx(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Z +X +Y\n        \"\"\"\n    def canonical_stabilizers(\n        self,\n    ) -> List[stim.PauliString]:\n        \"\"\"Returns a standardized list of the simulator's current stabilizer generators.\n\n        Two simulators have the same canonical stabilizers if and only if their current\n        quantum state is equal (and tracking the same number of qubits).\n\n        The canonical form is computed as follows:\n\n            1. Get a list of stabilizers using the `z_output`s of\n                `simulator.current_inverse_tableau()**-1`.\n            2. Perform Gaussian elimination on each generator g.\n                2a) The generators are considered in order X0, Z0, X1, Z1, X2, Z2, etc.\n                2b) Pick any stabilizer that uses the generator g. If there are none,\n                    go to the next g.\n                2c) Multiply that stabilizer into all other stabilizers that use the\n                    generator g.\n                2d) Swap that stabilizer with the stabilizer at position `next_output`\n                    then increment `next_output`.\n\n        Returns:\n            A List[stim.PauliString] of the simulator's state's stabilizers.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.cnot(0, 1)\n            >>> s.x(2)\n            >>> for e in s.canonical_stabilizers():\n            ...     print(repr(e))\n            stim.PauliString(\"+XX_\")\n            stim.PauliString(\"+ZZ_\")\n            stim.PauliString(\"-__Z\")\n\n            >>> # Scramble the stabilizers then check the canonical form is unchanged.\n            >>> s.set_inverse_tableau(s.current_inverse_tableau()**-1)\n            >>> s.cnot(0, 1)\n            >>> s.cz(0, 2)\n            >>> s.s(0, 2)\n            >>> s.cy(2, 1)\n            >>> s.set_inverse_tableau(s.current_inverse_tableau()**-1)\n            >>> for e in s.canonical_stabilizers():\n            ...     print(repr(e))\n            stim.PauliString(\"+XX_\")\n            stim.PauliString(\"+ZZ_\")\n            stim.PauliString(\"-__Z\")\n        \"\"\"\n    def cnot(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.cnot(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def copy(\n        self,\n        *,\n        copy_rng: bool = False,\n        seed: Optional[int] = None,\n    ) -> stim.TableauSimulator:\n        \"\"\"Returns a simulator with the same internal state, except perhaps its prng.\n\n        Args:\n            copy_rng: By default, new simulator's prng is reinitialized with a random\n                seed. However, one can set this argument to True in order to have the\n                prng state copied together with the rest of the original simulator's\n                state. Consequently, in this case the two simulators will produce the\n                same measurement outcomes for the same quantum circuits.  If both seed\n                and copy_rng are set, an exception is raised. Defaults to False.\n            seed: PARTIALLY determines simulation results by deterministically seeding\n                the random number generator.\n\n                Must be None or an integer in range(2**64).\n\n                Defaults to None. When None, the prng state is either copied from the\n                original simulator or reseeded from system entropy, depending on the\n                copy_rng argument.\n\n                When set to an integer, making the exact same series calls on the exact\n                same machine with the exact same version of Stim will produce the exact\n                same simulation results.\n\n                CAUTION: simulation results *WILL NOT* be consistent between versions of\n                Stim. This restriction is present to make it possible to have future\n                optimizations to the random sampling, and is enforced by introducing\n                intentional differences in the seeding strategy from version to version.\n\n                CAUTION: simulation results *MAY NOT* be consistent across machines that\n                differ in the width of supported SIMD instructions. For example, using\n                the same seed on a machine that supports AVX instructions and one that\n                only supports SSE instructions may produce different simulation results.\n\n                CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                circuit is executed. For example, reordering whether a reset on one\n                qubit happens before or after a reset on another qubit can result in\n                different measurement results being observed starting from the same\n                seed.\n\n        Examples:\n            >>> import stim\n\n            >>> s1 = stim.TableauSimulator()\n            >>> s1.set_inverse_tableau(stim.Tableau.random(1))\n            >>> s2 = s1.copy()\n            >>> s2 is s1\n            False\n            >>> s2.current_inverse_tableau() == s1.current_inverse_tableau()\n            True\n\n            >>> s1 = stim.TableauSimulator()\n            >>> s2 = s1.copy(copy_rng=True)\n            >>> s1.h(0)\n            >>> s2.h(0)\n            >>> assert s1.measure(0) == s2.measure(0)\n\n            >>> s = stim.TableauSimulator()\n            >>> def brute_force_post_select(qubit, desired_result):\n            ...     global s\n            ...     while True:\n            ...         s2 = s.copy()\n            ...         if s2.measure(qubit) == desired_result:\n            ...             s = s2\n            ...             break\n            >>> s.h(0)\n            >>> brute_force_post_select(qubit=0, desired_result=True)\n            >>> s.measure(0)\n            True\n        \"\"\"\n    def current_inverse_tableau(\n        self,\n    ) -> stim.Tableau:\n        \"\"\"Returns a copy of the internal state of the simulator as a stim.Tableau.\n\n        Returns:\n            A stim.Tableau copy of the simulator's state.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.current_inverse_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+X\"),\n                ],\n            )\n            >>> s.cnot(0, 1)\n            >>> s.current_inverse_tableau()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+ZX\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+X_\"),\n                    stim.PauliString(\"+XZ\"),\n                ],\n            )\n        \"\"\"\n    def current_measurement_record(\n        self,\n    ) -> List[bool]:\n        \"\"\"Returns a copy of the record of all measurements performed by the simulator.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.current_measurement_record()\n            []\n            >>> s.measure(0)\n            False\n            >>> s.x(0)\n            >>> s.measure(0)\n            True\n            >>> s.current_measurement_record()\n            [False, True]\n            >>> s.do(stim.Circuit(\"M 0\"))\n            >>> s.current_measurement_record()\n            [False, True, True]\n\n        Returns:\n            A list of booleans containing the result of every measurement performed by\n            the simulator so far.\n        \"\"\"\n    def cx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.cx(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def cy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.cy(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n        \"\"\"\n    def cz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.cz(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def depolarize1(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies single-qubit depolarization to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n            p: The chance of the error being applied,\n                independently, to each qubit.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.depolarize1(0, 1, 2, p=0.01)\n        \"\"\"\n    def depolarize2(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies two-qubit depolarization to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n                The pairs of qubits are formed by\n                zip(targets[::1], targets[1::2]).\n            p: The chance of the error being applied,\n                independently, to each qubit pair.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.depolarize1(0, 1, 4, 5, p=0.01)\n        \"\"\"\n    def do(\n        self,\n        circuit_or_pauli_string: Union[stim.Circuit, stim.PauliString, stim.CircuitInstruction, stim.CircuitRepeatBlock],\n    ) -> None:\n        \"\"\"Applies a circuit or pauli string to the simulator's state.\n\n        Args:\n            circuit_or_pauli_string: A stim.Circuit, stim.PauliString,\n                stim.CircuitInstruction, or stim.CircuitRepeatBlock\n                with operations to apply to the simulator's state.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.do(stim.Circuit('''\n            ...     X 0\n            ...     M 0\n            ... '''))\n            >>> s.current_measurement_record()\n            [True]\n\n            >>> s = stim.TableauSimulator()\n            >>> s.do(stim.PauliString(\"IXYZ\"))\n            >>> s.measure_many(0, 1, 2, 3)\n            [False, True, True, False]\n        \"\"\"\n    def do_circuit(\n        self,\n        circuit: stim.Circuit,\n    ) -> None:\n        \"\"\"Applies a circuit to the simulator's state.\n\n        Args:\n            circuit: A stim.Circuit containing operations to apply.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.do_circuit(stim.Circuit('''\n            ...     X 0\n            ...     M 0\n            ... '''))\n            >>> s.current_measurement_record()\n            [True]\n        \"\"\"\n    def do_pauli_string(\n        self,\n        pauli_string: stim.PauliString,\n    ) -> None:\n        \"\"\"Applies the paulis from a pauli string to the simulator's state.\n\n        Args:\n            pauli_string: A stim.PauliString containing Paulis to apply.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.do_pauli_string(stim.PauliString(\"IXYZ\"))\n            >>> s.measure_many(0, 1, 2, 3)\n            [False, True, True, False]\n        \"\"\"\n    def do_tableau(\n        self,\n        tableau: stim.Tableau,\n        targets: List[int],\n    ) -> None:\n        \"\"\"Applies a custom tableau operation to qubits in the simulator.\n\n        Note that this method has to compute the inverse of the tableau, because the\n        simulator's internal state is an inverse tableau.\n\n        Args:\n            tableau: A stim.Tableau representing the Clifford operation to apply.\n            targets: The indices of the qubits to operate on.\n\n        Examples:\n            >>> import stim\n            >>> sim = stim.TableauSimulator()\n            >>> sim.h(1)\n            >>> sim.h_yz(2)\n            >>> [str(sim.peek_bloch(k)) for k in range(4)]\n            ['+Z', '+X', '+Y', '+Z']\n            >>> rot3 = stim.Tableau.from_conjugated_generators(\n            ...     xs=[\n            ...         stim.PauliString(\"_X_\"),\n            ...         stim.PauliString(\"__X\"),\n            ...         stim.PauliString(\"X__\"),\n            ...     ],\n            ...     zs=[\n            ...         stim.PauliString(\"_Z_\"),\n            ...         stim.PauliString(\"__Z\"),\n            ...         stim.PauliString(\"Z__\"),\n            ...     ],\n            ... )\n\n            >>> sim.do_tableau(rot3, [1, 2, 3])\n            >>> [str(sim.peek_bloch(k)) for k in range(4)]\n            ['+Z', '+Z', '+X', '+Y']\n\n            >>> sim.do_tableau(rot3, [1, 2, 3])\n            >>> [str(sim.peek_bloch(k)) for k in range(4)]\n            ['+Z', '+Y', '+Z', '+X']\n        \"\"\"\n    def h(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Hadamard gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.h(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Z -Y +X\n        \"\"\"\n    def h_xy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an operation that swaps the X and Y axes to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.h_xy(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Y +X -Z\n        \"\"\"\n    def h_xz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Hadamard gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.h_xz(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Z -Y +X\n        \"\"\"\n    def h_yz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an operation that swaps the Y and Z axes to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.h_yz(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -X +Z +Y\n        \"\"\"\n    def iswap(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an ISWAP gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.iswap(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Y +Z\n        \"\"\"\n    def iswap_dag(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an ISWAP_DAG gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.iswap_dag(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ -Y +Z\n        \"\"\"\n    def measure(\n        self,\n        target: int,\n    ) -> bool:\n        \"\"\"Measures a single qubit.\n\n        Unlike the other methods on TableauSimulator, this one does not broadcast\n        over multiple targets. This is to avoid returning a list, which would\n        create a pitfall where typing `if sim.measure(qubit)` would be a bug.\n\n        To measure multiple qubits, use `TableauSimulator.measure_many`.\n\n        Args:\n            target: The index of the qubit to measure.\n\n        Returns:\n            The measurement result as a bool.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.x(1)\n            >>> s.measure(0)\n            False\n            >>> s.measure(1)\n            True\n        \"\"\"\n    def measure_kickback(\n        self,\n        target: int,\n    ) -> tuple:\n        \"\"\"Measures a qubit and returns the result as well as its Pauli kickback (if any).\n\n        The \"Pauli kickback\" of a stabilizer circuit measurement is a set of Pauli\n        operations that flip the post-measurement system state between the two possible\n        post-measurement states. For example, consider measuring one of the qubits in\n        the state |00>+|11> in the Z basis. If the measurement result is False, then the\n        system projects into the state |00>. If the measurement result is True, then the\n        system projects into the state |11>. Applying a Pauli X operation to both qubits\n        flips between |00> and |11>. Therefore the Pauli kickback of the measurement is\n        `stim.PauliString(\"XX\")`. Note that there are often many possible equivalent\n        Pauli kickbacks. For example, if in the previous example there was a third qubit\n        in the |0> state, then both `stim.PauliString(\"XX_\")` and\n        `stim.PauliString(\"XXZ\")` are valid kickbacks.\n\n        Measurements with deterministic results don't have a Pauli kickback.\n\n        Args:\n            target: The index of the qubit to measure.\n\n        Returns:\n            A (result, kickback) tuple.\n            The result is a bool containing the measurement's output.\n            The kickback is either None (meaning the measurement was deterministic) or a\n            stim.PauliString (meaning the measurement was random, and the operations in\n            the Pauli string flip between the two possible post-measurement states).\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n\n            >>> s.measure_kickback(0)\n            (False, None)\n\n            >>> s.h(0)\n            >>> s.measure_kickback(0)[1]\n            stim.PauliString(\"+X\")\n\n            >>> def pseudo_post_select(qubit, desired_result):\n            ...     m, kick = s.measure_kickback(qubit)\n            ...     if m != desired_result:\n            ...         if kick is None:\n            ...             raise ValueError(\"Post-selected the impossible!\")\n            ...         s.do(kick)\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.cnot(0, 1)\n            >>> s.cnot(0, 2)\n            >>> pseudo_post_select(qubit=2, desired_result=True)\n            >>> s.measure_many(0, 1, 2)\n            [True, True, True]\n        \"\"\"\n    def measure_many(\n        self,\n        *targets,\n    ) -> List[bool]:\n        \"\"\"Measures multiple qubits.\n\n        Args:\n            *targets: The indices of the qubits to measure.\n\n        Returns:\n            The measurement results as a list of bools.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.x(1)\n            >>> s.measure_many(0, 1)\n            [False, True]\n        \"\"\"\n    def measure_observable(\n        self,\n        observable: stim.PauliString,\n        *,\n        flip_probability: float = 0.0,\n    ) -> bool:\n        \"\"\"Measures an pauli string observable, as if by an MPP instruction.\n\n        Args:\n            observable: The observable to measure, specified as a stim.PauliString.\n            flip_probability: Probability of the recorded measurement result being\n                flipped.\n\n        Returns:\n            The result of the measurement.\n\n            The result is also recorded into the measurement record.\n\n        Raises:\n            ValueError: The given pauli string isn't Hermitian, or the given probability\n                isn't a valid probability.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.cnot(0, 1)\n\n            >>> s.measure_observable(stim.PauliString(\"XX\"))\n            False\n\n            >>> s.measure_observable(stim.PauliString(\"YY\"))\n            True\n\n            >>> s.measure_observable(stim.PauliString(\"-ZZ\"))\n            True\n        \"\"\"\n    @property\n    def num_qubits(\n        self,\n    ) -> int:\n        \"\"\"Returns the number of qubits currently being tracked by the simulator.\n\n        Note that the number of qubits being tracked will implicitly increase if qubits\n        beyond the current limit are touched. Untracked qubits are always assumed to be\n        in the |0> state.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.num_qubits\n            0\n            >>> s.h(2)\n            >>> s.num_qubits\n            3\n        \"\"\"\n    def peek_bloch(\n        self,\n        target: int,\n    ) -> stim.PauliString:\n        \"\"\"Returns the state of the qubit as a single-qubit stim.PauliString stabilizer.\n\n        This is a non-physical operation. It reports information about the qubit without\n        disturbing it.\n\n        Args:\n            target: The qubit to peek at.\n\n        Returns:\n            stim.PauliString(\"I\"):\n                The qubit is entangled. Its bloch vector is x=y=z=0.\n            stim.PauliString(\"+Z\"):\n                The qubit is in the |0> state. Its bloch vector is z=+1, x=y=0.\n            stim.PauliString(\"-Z\"):\n                The qubit is in the |1> state. Its bloch vector is z=-1, x=y=0.\n            stim.PauliString(\"+Y\"):\n                The qubit is in the |i> state. Its bloch vector is y=+1, x=z=0.\n            stim.PauliString(\"-Y\"):\n                The qubit is in the |-i> state. Its bloch vector is y=-1, x=z=0.\n            stim.PauliString(\"+X\"):\n                The qubit is in the |+> state. Its bloch vector is x=+1, y=z=0.\n            stim.PauliString(\"-X\"):\n                The qubit is in the |-> state. Its bloch vector is x=-1, y=z=0.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+Z\")\n            >>> s.x(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"-Z\")\n            >>> s.h(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"-X\")\n            >>> s.sqrt_x(1)\n            >>> s.peek_bloch(1)\n            stim.PauliString(\"-Y\")\n            >>> s.cz(0, 1)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+_\")\n        \"\"\"\n    def peek_observable_expectation(\n        self,\n        observable: stim.PauliString,\n    ) -> int:\n        \"\"\"Determines the expected value of an observable.\n\n        Because the simulator's state is always a stabilizer state, the expectation will\n        always be exactly -1, 0, or +1.\n\n        This is a non-physical operation.\n        It reports information about the quantum state without disturbing it.\n\n        Args:\n            observable: The observable to determine the expected value of.\n                This observable must have a real sign, not an imaginary sign.\n\n        Returns:\n            +1: Observable will be deterministically false when measured.\n            -1: Observable will be deterministically true when measured.\n            0: Observable will be random when measured.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.peek_observable_expectation(stim.PauliString(\"+Z\"))\n            1\n            >>> s.peek_observable_expectation(stim.PauliString(\"+X\"))\n            0\n            >>> s.peek_observable_expectation(stim.PauliString(\"-Z\"))\n            -1\n\n            >>> s.do(stim.Circuit('''\n            ...     H 0\n            ...     CNOT 0 1\n            ... '''))\n            >>> queries = ['XX', 'YY', 'ZZ', '-ZZ', 'ZI', 'II', 'IIZ']\n            >>> for q in queries:\n            ...     print(q, s.peek_observable_expectation(stim.PauliString(q)))\n            XX 1\n            YY -1\n            ZZ 1\n            -ZZ -1\n            ZI 0\n            II 1\n            IIZ 1\n        \"\"\"\n    def peek_x(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns the expected value of a qubit's X observable.\n\n        Because the simulator's state is always a stabilizer state, the expectation will\n        always be exactly -1, 0, or +1.\n\n        This is a non-physical operation.\n        It reports information about the quantum state without disturbing it.\n\n        Args:\n            target: The qubit to analyze.\n\n        Returns:\n            +1: Qubit is in the |+> state.\n            -1: Qubit is in the |-> state.\n            0: Qubit is in some other state.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_z(0)\n            >>> s.peek_x(0)\n            0\n            >>> s.reset_x(0)\n            >>> s.peek_x(0)\n            1\n            >>> s.z(0)\n            >>> s.peek_x(0)\n            -1\n        \"\"\"\n    def peek_y(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns the expected value of a qubit's Y observable.\n\n        Because the simulator's state is always a stabilizer state, the expectation will\n        always be exactly -1, 0, or +1.\n\n        This is a non-physical operation.\n        It reports information about the quantum state without disturbing it.\n\n        Args:\n            target: The qubit to analyze.\n\n        Returns:\n            +1: Qubit is in the |i> state.\n            -1: Qubit is in the |-i> state.\n            0: Qubit is in some other state.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_z(0)\n            >>> s.peek_y(0)\n            0\n            >>> s.reset_y(0)\n            >>> s.peek_y(0)\n            1\n            >>> s.z(0)\n            >>> s.peek_y(0)\n            -1\n        \"\"\"\n    def peek_z(\n        self,\n        target: int,\n    ) -> int:\n        \"\"\"Returns the expected value of a qubit's Z observable.\n\n        Because the simulator's state is always a stabilizer state, the expectation will\n        always be exactly -1, 0, or +1.\n\n        This is a non-physical operation.\n        It reports information about the quantum state without disturbing it.\n\n        Args:\n            target: The qubit to analyze.\n\n        Returns:\n            +1: Qubit is in the |0> state.\n            -1: Qubit is in the |1> state.\n            0: Qubit is in some other state.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.peek_z(0)\n            0\n            >>> s.reset_z(0)\n            >>> s.peek_z(0)\n            1\n            >>> s.x(0)\n            >>> s.peek_z(0)\n            -1\n        \"\"\"\n    def postselect_observable(\n        self,\n        observable: stim.PauliString,\n        *,\n        desired_value: bool = False,\n    ) -> None:\n        \"\"\"Projects into a desired observable, or raises an exception if it was impossible.\n\n        Postselecting an observable forces it to collapse to a specific eigenstate,\n        as if it was measured and that state was the result of the measurement.\n\n        Args:\n            observable: The observable to postselect, specified as a pauli string.\n                The pauli string's sign must be -1 or +1 (not -i or +i).\n            desired_value:\n                False (default): Postselect into the +1 eigenstate of the observable.\n                True: Postselect into the -1 eigenstate of the observable.\n\n        Raises:\n            ValueError:\n                The given observable had an imaginary sign.\n                OR\n                The postselection was impossible. The observable was in the opposite\n                eigenstate, so measuring it would never ever return the desired result.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.postselect_observable(stim.PauliString(\"+XX\"))\n            >>> s.postselect_observable(stim.PauliString(\"+ZZ\"))\n            >>> s.peek_observable_expectation(stim.PauliString(\"+YY\"))\n            -1\n        \"\"\"\n    def postselect_x(\n        self,\n        targets: Union[int, Iterable[int]],\n        *,\n        desired_value: bool,\n    ) -> None:\n        \"\"\"Postselects qubits in the X basis, or raises an exception.\n\n        Postselecting a qubit forces it to collapse to a specific state, as\n        if it was measured and that state was the result of the measurement.\n\n        Args:\n            targets: The qubit index or indices to postselect.\n            desired_value:\n                False: postselect targets into the |+> state.\n                True: postselect targets into the |-> state.\n\n        Raises:\n            ValueError:\n                The postselection failed. One of the qubits was in a state\n                orthogonal to the desired state, so it was literally\n                impossible for a measurement of the qubit to return the\n                desired result.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.peek_x(0)\n            0\n            >>> s.postselect_x(0, desired_value=False)\n            >>> s.peek_x(0)\n            1\n            >>> s.h(0)\n            >>> s.peek_x(0)\n            0\n            >>> s.postselect_x(0, desired_value=True)\n            >>> s.peek_x(0)\n            -1\n        \"\"\"\n    def postselect_y(\n        self,\n        targets: Union[int, Iterable[int]],\n        *,\n        desired_value: bool,\n    ) -> None:\n        \"\"\"Postselects qubits in the Y basis, or raises an exception.\n\n        Postselecting a qubit forces it to collapse to a specific state, as\n        if it was measured and that state was the result of the measurement.\n\n        Args:\n            targets: The qubit index or indices to postselect.\n            desired_value:\n                False: postselect targets into the |i> state.\n                True: postselect targets into the |-i> state.\n\n        Raises:\n            ValueError:\n                The postselection failed. One of the qubits was in a state\n                orthogonal to the desired state, so it was literally\n                impossible for a measurement of the qubit to return the\n                desired result.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.peek_y(0)\n            0\n            >>> s.postselect_y(0, desired_value=False)\n            >>> s.peek_y(0)\n            1\n            >>> s.reset_x(0)\n            >>> s.peek_y(0)\n            0\n            >>> s.postselect_y(0, desired_value=True)\n            >>> s.peek_y(0)\n            -1\n        \"\"\"\n    def postselect_z(\n        self,\n        targets: Union[int, Iterable[int]],\n        *,\n        desired_value: bool,\n    ) -> None:\n        \"\"\"Postselects qubits in the Z basis, or raises an exception.\n\n        Postselecting a qubit forces it to collapse to a specific state, as if it was\n        measured and that state was the result of the measurement.\n\n        Args:\n            targets: The qubit index or indices to postselect.\n            desired_value:\n                False: postselect targets into the |0> state.\n                True: postselect targets into the |1> state.\n\n        Raises:\n            ValueError:\n                The postselection failed. One of the qubits was in a state\n                orthogonal to the desired state, so it was literally\n                impossible for a measurement of the qubit to return the\n                desired result.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.peek_z(0)\n            0\n            >>> s.postselect_z(0, desired_value=False)\n            >>> s.peek_z(0)\n            1\n            >>> s.h(0)\n            >>> s.peek_z(0)\n            0\n            >>> s.postselect_z(0, desired_value=True)\n            >>> s.peek_z(0)\n            -1\n        \"\"\"\n    def reset(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Resets qubits to the |0> state.\n\n        Args:\n            *targets: The indices of the qubits to reset.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.x(0)\n            >>> s.reset(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+Z\")\n        \"\"\"\n    def reset_x(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Resets qubits to the |+> state.\n\n        Args:\n            *targets: The indices of the qubits to reset.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+X\")\n        \"\"\"\n    def reset_y(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Resets qubits to the |i> state.\n\n        Args:\n            *targets: The indices of the qubits to reset.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_y(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+Y\")\n        \"\"\"\n    def reset_z(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Resets qubits to the |0> state.\n\n        Args:\n            *targets: The indices of the qubits to reset.\n\n        Example:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.h(0)\n            >>> s.reset_z(0)\n            >>> s.peek_bloch(0)\n            stim.PauliString(\"+Z\")\n        \"\"\"\n    def s(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.s(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Y -X +Z\n        \"\"\"\n    def s_dag(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_Z_DAG gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.s_dag(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -Y +X +Z\n        \"\"\"\n    def set_inverse_tableau(\n        self,\n        new_inverse_tableau: stim.Tableau,\n    ) -> None:\n        \"\"\"Overwrites the simulator's internal state with the given inverse tableau.\n\n        The inverse tableau specifies how Pauli product observables of qubits at the\n        current time transform into equivalent Pauli product observables at the\n        beginning of time, when all qubits were in the |0> state. For example, if the Z\n        observable on qubit 5 maps to a product of Z observables at the start of time\n        then a Z basis measurement on qubit 5 will be deterministic and equal to the\n        sign of the product. Whereas if it mapped to a product of observables including\n        an X or a Y then the Z basis measurement would be random.\n\n        Any qubits not within the length of the tableau are implicitly in the |0> state.\n\n        Args:\n            new_inverse_tableau: The tableau to overwrite the internal state with.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> t = stim.Tableau.random(4)\n            >>> s.set_inverse_tableau(t)\n            >>> s.current_inverse_tableau() == t\n            True\n        \"\"\"\n    def set_num_qubits(\n        self,\n        new_num_qubits: int,\n    ) -> None:\n        \"\"\"Resizes the simulator's internal state.\n\n        This forces the simulator's internal state to track exactly the qubits whose\n        indices are in `range(new_num_qubits)`.\n\n        Note that untracked qubits are always assumed to be in the |0> state. Therefore,\n        calling this method will effectively force any qubit whose index is outside\n        `range(new_num_qubits)` to be reset to |0>.\n\n        Note that this method does not prevent future operations from implicitly\n        expanding the size of the tracked state (e.g. setting the number of qubits to 5\n        will not prevent a Hadamard from then being applied to qubit 100, increasing the\n        number of qubits back to 101).\n\n        Args:\n            new_num_qubits: The length of the range of qubits the internal simulator\n                should be tracking.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> len(s.current_inverse_tableau())\n            0\n\n            >>> s.set_num_qubits(5)\n            >>> len(s.current_inverse_tableau())\n            5\n\n            >>> s.x(0, 1, 2, 3)\n            >>> s.set_num_qubits(2)\n            >>> s.measure_many(0, 1, 2, 3)\n            [True, True, False, False]\n        \"\"\"\n    def set_state_from_stabilizers(\n        self,\n        stabilizers: Iterable[stim.PauliString],\n        *,\n        allow_redundant: bool = False,\n        allow_underconstrained: bool = False,\n    ) -> None:\n        \"\"\"Sets the tableau simulator's state to a state satisfying the given stabilizers.\n\n        The old quantum state is completely overwritten, even if the new state is\n        underconstrained by the given stabilizers. The number of qubits is changed to\n        exactly match the number of qubits in the longest given stabilizer.\n\n        Args:\n            stabilizers: A list of `stim.PauliString`s specifying the stabilizers that\n                the new state must have. It is permitted for stabilizers to have\n                different lengths. All stabilizers are padded up to the length of the\n                longest stabilizer by appending identity terms.\n            allow_redundant: Defaults to False. If set to False, then the given\n                stabilizers must all be independent. If any one of them is a product of\n                the others (including the empty product), an exception will be raised.\n                If set to True, then redundant stabilizers are simply ignored.\n            allow_underconstrained: Defaults to False. If set to False, then the given\n                stabilizers must form a complete set of generators. They must exactly\n                specify the desired stabilizer state, with no degrees of freedom left\n                over. For an n-qubit state there must be n independent stabilizers. If\n                set to True, then there can be leftover degrees of freedom which can be\n                set arbitrarily.\n\n        Returns:\n            Nothing. Mutates the states of the simulator to match the desired\n            stabilizers.\n\n            Guarantees that self.current_inverse_tableau().inverse_z_output(k) will be\n            equal to the k'th independent stabilizer from the `stabilizers` argument.\n\n        Raises:\n            ValueError:\n                A stabilizer is redundant but allow_redundant=True wasn't set.\n                OR\n                The given stabilizers are contradictory (e.g. \"+Z\" and \"-Z\" both\n                specified).\n                OR\n                The given stabilizers anticommute (e.g. \"+Z\" and \"+X\" both specified).\n                OR\n                The stabilizers left behind a degree of freedom but\n                allow_underconstrained=True wasn't set.\n                OR\n                A stabilizer has an imaginary sign (i or -i).\n\n        Examples:\n\n            >>> import stim\n            >>> tab_sim = stim.TableauSimulator()\n            >>> tab_sim.set_state_from_stabilizers([\n            ...     stim.PauliString(\"XX\"),\n            ...     stim.PauliString(\"ZZ\"),\n            ... ])\n            >>> tab_sim.current_inverse_tableau().inverse()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n\n            >>> tab_sim.set_state_from_stabilizers([\n            ...     stim.PauliString(\"XX_\"),\n            ...     stim.PauliString(\"ZZ_\"),\n            ...     stim.PauliString(\"-YY_\"),\n            ...     stim.PauliString(\"\"),\n            ... ], allow_underconstrained=True, allow_redundant=True)\n            >>> tab_sim.current_inverse_tableau().inverse()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z__\"),\n                    stim.PauliString(\"+_X_\"),\n                    stim.PauliString(\"+__X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX_\"),\n                    stim.PauliString(\"+ZZ_\"),\n                    stim.PauliString(\"+__Z\"),\n                ],\n            )\n        \"\"\"\n    def set_state_from_state_vector(\n        self,\n        state_vector: Iterable[float],\n        *,\n        endian: Literal[\"little\", \"big\"],\n    ) -> None:\n        \"\"\"Sets the simulator's state to a superposition specified by an amplitude vector.\n\n        Args:\n            state_vector: A list of complex amplitudes specifying a superposition. The\n                vector must correspond to a state that is reachable using Clifford\n                operations, and must be normalized (i.e. it must be a unit vector).\n            endian:\n                \"little\": state vector is in little endian order, where higher index\n                    qubits correspond to larger changes in the state index.\n                \"big\": state vector is in big endian order, where higher index qubits\n                    correspond to smaller changes in the state index.\n\n        Returns:\n            Nothing. Mutates the states of the simulator to match the desired state.\n\n        Raises:\n            ValueError:\n                The given state vector isn't a list of complex values specifying a\n                stabilizer state.\n                OR\n                The given endian value isn't 'little' or 'big'.\n\n        Examples:\n\n            >>> import stim\n            >>> tab_sim = stim.TableauSimulator()\n            >>> tab_sim.set_state_from_state_vector([\n            ...     0.5**0.5,\n            ...     0.5**0.5 * 1j,\n            ... ], endian='little')\n            >>> tab_sim.current_inverse_tableau().inverse()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+Y\"),\n                ],\n            )\n            >>> tab_sim.set_state_from_state_vector([\n            ...     0.5**0.5,\n            ...     0,\n            ...     0,\n            ...     0.5**0.5,\n            ... ], endian='little')\n            >>> tab_sim.current_inverse_tableau().inverse()\n            stim.Tableau.from_conjugated_generators(\n                xs=[\n                    stim.PauliString(\"+Z_\"),\n                    stim.PauliString(\"+_X\"),\n                ],\n                zs=[\n                    stim.PauliString(\"+XX\"),\n                    stim.PauliString(\"+ZZ\"),\n                ],\n            )\n        \"\"\"\n    def sqrt_x(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.sqrt_x(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Z -Y\n        \"\"\"\n    def sqrt_x_dag(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_X_DAG gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.sqrt_x_dag(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X -Z +Y\n        \"\"\"\n    def sqrt_y(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.sqrt_y(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -Z +Y +X\n        \"\"\"\n    def sqrt_y_dag(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a SQRT_Y_DAG gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.sqrt_y_dag(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +Z +Y -X\n        \"\"\"\n    def state_vector(\n        self,\n        *,\n        endian: Literal[\"little\", \"big\"] = 'little',\n    ) -> np.ndarray[np.complex64]:\n        \"\"\"Returns a wavefunction for the simulator's current state.\n\n        This function takes O(n * 2**n) time and O(2**n) space, where n is the number of\n        qubits. The computation is done by initialization a random state vector and\n        iteratively projecting it into the +1 eigenspace of each stabilizer of the\n        state. The state is then canonicalized so that zero values are actually exactly\n        0, and so that the first non-zero entry is positive.\n\n        Args:\n            endian:\n                \"little\" (default): state vector is in little endian order, where higher\n                    index qubits correspond to larger changes in the state index.\n                \"big\": state vector is in big endian order, where higher index qubits\n                    correspond to smaller changes in the state index.\n\n        Returns:\n            A `numpy.ndarray[numpy.complex64]` of computational basis amplitudes.\n\n            If the result is in little endian order then the amplitude at offset\n            b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n            computational basis state where the qubit with index 0 is storing the bit\n            b_0, the qubit with index 1 is storing the bit b_1, etc.\n\n            If the result is in big endian order then the amplitude at offset\n            b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n            computational basis state where the qubit with index 0 is storing the bit\n            b_{n-1}, the qubit with index 1 is storing the bit b_{n-2}, etc.\n\n        Examples:\n            >>> import stim\n            >>> import numpy as np\n            >>> s = stim.TableauSimulator()\n            >>> s.x(2)\n            >>> s.state_vector(endian='little')\n            array([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                  dtype=complex64)\n\n            >>> s.state_vector(endian='big')\n            array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                  dtype=complex64)\n\n            >>> s.sqrt_x(1, 2)\n            >>> s.state_vector()\n            array([0.5+0.j , 0. +0.j , 0. -0.5j, 0. +0.j , 0. +0.5j, 0. +0.j ,\n                   0.5+0.j , 0. +0.j ], dtype=complex64)\n        \"\"\"\n    def swap(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a swap gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.swap(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +Y +X +X +Z\n        \"\"\"\n    def x(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Pauli X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.x(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X -Y -Z\n        \"\"\"\n    def x_error(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies X errors to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n            p: The chance of the X error being applied,\n                independently, to each qubit.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.x_error(0, 1, 2, p=0.01)\n        \"\"\"\n    def xcx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an X-controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.xcx(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n        \"\"\"\n    def xcy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an X-controlled Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.xcy(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +_ +_\n        \"\"\"\n    def xcz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies an X-controlled Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.xcz(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +_ +_\n        \"\"\"\n    def y(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Pauli Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.y(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -X +Y -Z\n        \"\"\"\n    def y_error(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies Y errors to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n            p: The chance of the Y error being applied,\n                independently, to each qubit.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.y_error(0, 1, 2, p=0.01)\n        \"\"\"\n    def ycx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Y-controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.ycx(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def ycy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Y-controlled Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.ycy(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +_ +_\n        \"\"\"\n    def ycz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Y-controlled Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.ycz(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +_ +_\n        \"\"\"\n    def z(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a Pauli Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            +X +Y +Z\n            >>> s.z(0, 1, 2)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n            -X -Y +Z\n        \"\"\"\n    def z_error(\n        self,\n        *targets: int,\n        p: float,\n    ):\n        \"\"\"Probabilistically applies Z errors to targets.\n\n        Args:\n            *targets: The indices of the qubits to target with the noise.\n            p: The chance of the Z error being applied,\n                independently, to each qubit.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.z_error(0, 1, 2, p=0.01)\n        \"\"\"\n    def zcx(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled X gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.zcx(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n    def zcy(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled Y gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.zcy(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n        \"\"\"\n    def zcz(\n        self,\n        *targets,\n    ) -> None:\n        \"\"\"Applies a controlled Z gate to the simulator's state.\n\n        Args:\n            *targets: The indices of the qubits to target with the gate.\n                Applies the gate to the first two targets, then the next two targets,\n                and so forth. There must be an even number of targets.\n\n        Examples:\n            >>> import stim\n            >>> s = stim.TableauSimulator()\n            >>> s.reset_x(0, 3)\n            >>> s.reset_y(1)\n\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +X +Y +Z +X\n            >>> s.zcz(0, 1, 2, 3)\n            >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n            +_ +_ +Z +X\n        \"\"\"\n@overload\ndef gate_data(\n    name: str,\n) -> stim.GateData:\n    pass\n@overload\ndef gate_data(\n) -> Dict[str, stim.GateData]:\n    pass\ndef gate_data(\n    name: Optional[str] = None,\n) -> Union[str, Dict[str, stim.GateData]]:\n    \"\"\"Returns gate data for the given named gate, or all gates.\n\n    Examples:\n        >>> import stim\n        >>> stim.gate_data('cnot').aliases\n        ['CNOT', 'CX', 'ZCX']\n        >>> stim.gate_data('cnot').is_two_qubit_gate\n        True\n        >>> gate_dict = stim.gate_data()\n        >>> len(gate_dict) > 50\n        True\n        >>> gate_dict['MX'].produces_measurements\n        True\n    \"\"\"\ndef main(\n    *,\n    command_line_args: List[str],\n) -> int:\n    \"\"\"Runs the command line tool version of stim on the given arguments.\n\n    Note that by default any input will be read from stdin, any output\n    will print to stdout (as opposed to being intercepted). For most\n    commands, you can use arguments like `--out` to write to a file\n    instead of stdout and `--in` to read from a file instead of stdin.\n\n    Returns:\n        An exit code (0 means success, not zero means failure).\n\n    Raises:\n        A large variety of errors, depending on what you are doing and\n        how it failed! Beware that many errors are caught by the main\n        method itself and printed to stderr, with the only indication\n        that something went wrong being the return code.\n\n    Example:\n        >>> import stim\n        >>> import tempfile\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = f'{d}/tmp.out'\n        ...     return_code = stim.main(command_line_args=[\n        ...         \"gen\",\n        ...         \"--code=repetition_code\",\n        ...         \"--task=memory\",\n        ...         \"--rounds=1000\",\n        ...         \"--distance=2\",\n        ...         \"--out\",\n        ...         path,\n        ...     ])\n        ...     assert return_code == 0\n        ...     with open(path) as f:\n        ...         print(f.read(), end='')\n        # Generated repetition_code circuit.\n        # task: memory\n        # rounds: 1000\n        # distance: 2\n        # before_round_data_depolarization: 0\n        # before_measure_flip_probability: 0\n        # after_reset_flip_probability: 0\n        # after_clifford_depolarization: 0\n        # layout:\n        # L0 Z1 d2\n        # Legend:\n        #     d# = data qubit\n        #     L# = data qubit with logical observable crossing\n        #     Z# = measurement qubit\n        R 0 1 2\n        TICK\n        CX 0 1\n        TICK\n        CX 2 1\n        TICK\n        MR 1\n        DETECTOR(1, 0) rec[-1]\n        REPEAT 999 {\n            TICK\n            CX 0 1\n            TICK\n            CX 2 1\n            TICK\n            MR 1\n            SHIFT_COORDS(0, 1)\n            DETECTOR(1, 0) rec[-1] rec[-2]\n        }\n        M 0 2\n        DETECTOR(1, 1) rec[-1] rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\"\n@overload\ndef read_shot_data_file(\n    *,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    bit_packed: bool = False,\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n) -> np.ndarray:\n    pass\n@overload\ndef read_shot_data_file(\n    *,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    bit_packed: bool = False,\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n    separate_observables: Literal[True],\n) -> Tuple[np.ndarray, np.ndarray]:\n    pass\ndef read_shot_data_file(\n    *,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    bit_packed: bool = False,\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n    separate_observables: bool = False,\n) -> Union[Tuple[np.ndarray, np.ndarray], np.ndarray]:\n    \"\"\"Reads shot data, such as measurement samples, from a file.\n\n    Args:\n        path: The path to the file to read the data from.\n        format: The format that the data is stored in, such as 'b8'.\n            See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        bit_packed: Defaults to false. Determines whether the result is a bool_\n            numpy array with one bit per byte, or a uint8 numpy array with 8 bits\n            per byte.\n        num_measurements: How many measurements there are per shot.\n        num_detectors: How many detectors there are per shot.\n        num_observables: How many observables there are per shot.\n            Note that this only refers to observables *stored in the file*, not to\n            observables from the original circuit that was sampled.\n        separate_observables: When set to True, the result is a tuple of two arrays,\n            one containing the detection event data and the other containing the\n            observable data, instead of a single array.\n\n    Returns:\n        If separate_observables=True:\n            A tuple (dets, obs) of numpy arrays containing the loaded data.\n\n            If bit_packed=False:\n                dets.dtype = np.bool_\n                dets.shape = (num_shots, num_measurements + num_detectors)\n                det bit b from shot s is at dets[s, b]\n                obs.dtype = np.bool_\n                obs.shape = (num_shots, num_observables)\n                obs bit b from shot s is at dets[s, b]\n            If bit_packed=True:\n                dets.dtype = np.uint8\n                dets.shape = (num_shots, math.ceil(\n                    (num_measurements + num_detectors) / 8))\n                obs.dtype = np.uint8\n                obs.shape = (num_shots, math.ceil(num_observables / 8))\n                det bit b from shot s is at dets[s, b // 8] & (1 << (b % 8))\n                obs bit b from shot s is at obs[s, b // 8] & (1 << (b % 8))\n\n        If separate_observables=False:\n            A numpy array containing the loaded data.\n\n            If bit_packed=False:\n                dtype = np.bool_\n                shape = (num_shots,\n                         num_measurements + num_detectors + num_observables)\n                bit b from shot s is at result[s, b]\n            If bit_packed=True:\n                dtype = np.uint8\n                shape = (num_shots, math.ceil(\n                    (num_measurements + num_detectors + num_observables) / 8))\n                bit b from shot s is at result[s, b // 8] & (1 << (b % 8))\n\n    Examples:\n        >>> import stim\n        >>> import pathlib\n        >>> import tempfile\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = pathlib.Path(d) / 'shots'\n        ...     with open(path, 'w') as f:\n        ...         print(\"0000\", file=f)\n        ...         print(\"0101\", file=f)\n        ...\n        ...     read = stim.read_shot_data_file(\n        ...         path=str(path),\n        ...         format='01',\n        ...         num_measurements=4)\n        >>> read\n        array([[False, False, False, False],\n               [False,  True, False,  True]])\n    \"\"\"\ndef target_combined_paulis(\n    paulis: Union[stim.PauliString, List[stim.GateTarget]],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a list of targets encoding a pauli product for instructions like MPP.\n\n    Args:\n        paulis: The paulis to encode into the targets. This can be a\n            `stim.PauliString` or a list of pauli targets from `stim.target_x`,\n            `stim.target_pauli`, etc.\n        invert: Defaults to False. If True, the product is inverted (like \"!X2*Y3\").\n            Note that this is in addition to any inversions specified by the\n            `paulis` argument.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     *stim.target_combined_paulis(stim.PauliString(\"-XYZ\")),\n        ...     *stim.target_combined_paulis([stim.target_x(2), stim.target_y(5)]),\n        ...     *stim.target_combined_paulis([stim.target_z(9)], invert=True),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP !X0*Y1*Z2 X2*Y5 !Z9\n        ''')\n    \"\"\"\ndef target_combiner(\n) -> stim.GateTarget:\n    \"\"\"Returns a target combiner that can be used to build Pauli products.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*Y3*Z5\n        ''')\n    \"\"\"\ndef target_inv(\n    qubit_index: Union[int, stim.GateTarget],\n) -> stim.GateTarget:\n    \"\"\"Returns a target flagged as inverted.\n\n    Inverted targets are used to indicate measurement results should be flipped.\n\n    Args:\n        qubit_index: The underlying qubit index of the inverted target.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"M\", [2, stim.target_inv(3)])\n        >>> circuit\n        stim.Circuit('''\n            M 2 !3\n        ''')\n\n    For example, the '!1' in 'M 0 !1 2' is qubit 1 flagged as inverted,\n    meaning the measurement result from qubit 1 should be inverted when reported.\n    \"\"\"\ndef target_logical_observable_id(\n    index: int,\n) -> stim.DemTarget:\n    \"\"\"Returns a logical observable id identifying a frame change.\n\n    Args:\n        index: The index of the observable.\n\n    Returns:\n        The logical observable target.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.target_logical_observable_id(13)\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) L13\n        ''')\n    \"\"\"\ndef target_pauli(\n    qubit_index: int,\n    pauli: Union[str, int],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a pauli target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        pauli: The pauli gate to use. This can either be a string identifying the\n            pauli by name (\"x\", \"X\", \"y\", \"Y\", \"z\", or \"Z\") or an integer following\n            the convention (1=X, 2=Y, 3=Z). Setting this argument to \"I\" or to\n            0 will return a qubit target instead of a pauli target.\n        invert: Defaults to False. If True, the target is inverted (like \"!X10\"),\n            indicating that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_pauli(2, \"X\"),\n        ...     stim.target_combiner(),\n        ...     stim.target_pauli(3, \"y\", invert=True),\n        ...     stim.target_pauli(5, 3),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3 Z5\n        ''')\n\n        >>> circuit.append(\"M\", [\n        ...     stim.target_pauli(7, \"I\"),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3 Z5\n            M 7\n        ''')\n    \"\"\"\ndef target_rec(\n    lookback_index: int,\n) -> stim.GateTarget:\n    \"\"\"Returns a measurement record target with the given lookback.\n\n    Measurement record targets are used to refer back to the measurement record;\n    the list of measurements that have been performed so far. Measurement record\n    targets always specify an index relative to the *end* of the measurement record.\n    The latest measurement is `stim.target_rec(-1)`, the next most recent\n    measurement is `stim.target_rec(-2)`, and so forth. Indexing is done this way\n    in order to make it possible to write loops.\n\n    Args:\n        lookback_index: A negative integer indicating how far to look back, relative\n            to the end of the measurement record.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"M\", [5, 7, 11])\n        >>> circuit.append(\"CX\", [stim.target_rec(-2), 3])\n        >>> circuit\n        stim.Circuit('''\n            M 5 7 11\n            CX rec[-2] 3\n        ''')\n    \"\"\"\ndef target_relative_detector_id(\n    index: int,\n) -> stim.DemTarget:\n    \"\"\"Returns a relative detector id (e.g. \"D5\" in a .dem file).\n\n    Args:\n        index: The index of the detector, relative to the current detector offset.\n\n    Returns:\n        The relative detector target.\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.target_relative_detector_id(13)\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) D13\n        ''')\n    \"\"\"\ndef target_separator(\n) -> stim.DemTarget:\n    \"\"\"Returns a target separator (e.g. \"^\" in a .dem file).\n\n    Examples:\n        >>> import stim\n        >>> m = stim.DetectorErrorModel()\n        >>> m.append(\"error\", 0.25, [\n        ...     stim.target_relative_detector_id(1),\n        ...     stim.target_separator(),\n        ...     stim.target_relative_detector_id(2),\n        ... ])\n        >>> print(repr(m))\n        stim.DetectorErrorModel('''\n            error(0.25) D1 ^ D2\n        ''')\n    \"\"\"\ndef target_sweep_bit(\n    sweep_bit_index: int,\n) -> stim.GateTarget:\n    \"\"\"Returns a sweep bit target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        sweep_bit_index: The index of the sweep bit to target.\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"CX\", [stim.target_sweep_bit(2), 5])\n        >>> circuit\n        stim.Circuit('''\n            CX sweep[2] 5\n        ''')\n    \"\"\"\ndef target_x(\n    qubit_index: Union[int, stim.GateTarget],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a Pauli X target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        invert: Defaults to False. If True, the target is inverted (indicating\n            that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3, invert=True),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3*Z5\n        ''')\n    \"\"\"\ndef target_y(\n    qubit_index: Union[int, stim.GateTarget],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a Pauli Y target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        invert: Defaults to False. If True, the target is inverted (indicating\n            that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3, invert=True),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3*Z5\n        ''')\n    \"\"\"\ndef target_z(\n    qubit_index: Union[int, stim.GateTarget],\n    invert: bool = False,\n) -> stim.GateTarget:\n    \"\"\"Returns a Pauli Z target that can be passed into `stim.Circuit.append`.\n\n    Args:\n        qubit_index: The qubit that the Pauli applies to.\n        invert: Defaults to False. If True, the target is inverted (indicating\n            that, for example, measurement results should be inverted).\n\n    Examples:\n        >>> import stim\n        >>> circuit = stim.Circuit()\n        >>> circuit.append(\"MPP\", [\n        ...     stim.target_x(2),\n        ...     stim.target_combiner(),\n        ...     stim.target_y(3, invert=True),\n        ...     stim.target_combiner(),\n        ...     stim.target_z(5),\n        ... ])\n        >>> circuit\n        stim.Circuit('''\n            MPP X2*!Y3*Z5\n        ''')\n    \"\"\"\ndef write_shot_data_file(\n    *,\n    data: np.ndarray,\n    path: Union[str, pathlib.Path],\n    format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    num_measurements: int = 0,\n    num_detectors: int = 0,\n    num_observables: int = 0,\n) -> None:\n    \"\"\"Writes shot data, such as measurement samples, to a file.\n\n    Args:\n        data: The data to write to the file. This must be a numpy array. The dtype\n            of the array determines whether or not the data is bit packed, and the\n            shape must match the bits per shot.\n\n            dtype=np.bool_: Not bit packed. Shape must be\n                (num_shots, num_measurements + num_detectors + num_observables).\n            dtype=np.uint8: Yes bit packed. Shape must be\n                (num_shots, math.ceil(\n                    (num_measurements + num_detectors + num_observables) / 8)).\n        path: The path to the file to write the data to.\n        format: The format that the data is stored in, such as 'b8'.\n            See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        num_measurements: How many measurements there are per shot.\n        num_detectors: How many detectors there are per shot.\n        num_observables: How many observables there are per shot.\n            Note that this only refers to observables *in the given shot data*, not\n            to observables from the original circuit that was sampled.\n\n    Examples:\n        >>> import stim\n        >>> import pathlib\n        >>> import tempfile\n        >>> import numpy as np\n        >>> with tempfile.TemporaryDirectory() as d:\n        ...     path = pathlib.Path(d) / 'shots'\n        ...     shot_data = np.array([\n        ...         [0, 1, 0],\n        ...         [0, 1, 1],\n        ...     ], dtype=np.bool_)\n        ...\n        ...     stim.write_shot_data_file(\n        ...         path=str(path),\n        ...         data=shot_data,\n        ...         format='01',\n        ...         num_measurements=3)\n        ...\n        ...     with open(path) as f:\n        ...         written = f.read()\n        >>> written\n        '010\\n011\\n'\n    \"\"\"\n"
  },
  {
    "path": "glue/python/src/stim/_main_argv.py",
    "content": "import sys\n\nimport stim\n\n\ndef main_argv():\n    stim.main(command_line_args=sys.argv[1:])\n\n\nif __name__ == '__main__':\n    main_argv()\n"
  },
  {
    "path": "glue/sample/MANIFEST.in",
    "content": "recursive-include src *.py\n"
  },
  {
    "path": "glue/sample/README.md",
    "content": "# sinter: fast QEC sampling\n\nSinter is a software tool/library for doing fast monte carlo sampling of\nquantum error correction circuits.\n\n- [How it works](#how_it_works)\n- [How to install](#how_to_install)\n- [How to use: Python API](#how_to_use_python)\n    - [Sinter Python API Reference](doc/sinter_api.md)\n- [How to use: Linux Command Line](#how_to_use_linux)\n    - [Sinter Command Line Reference](doc/sinter_command_line.md)\n- [The csv format for sample statistics](#csv_format)\n\n<a name=\"how_to_works\"></a>\n# How it works\n\nSinter takes Stim circuits annotated with noise, detectors, and logical\nobservables.\nIt uses stim to sample the circuits and a decoder such as pymatching to predict\nwhether the logical observables were flipped or not, given the detector data.\nIt records how often this succeeds, and how often it fails (the error rate).\n\nSinter uses python multiprocessing to do parallel sampling across multiple CPU\ncores, dynamically decides which circuits need more samples based on parameters\nspecified by the user (such as a target number of errors), saves the results to\nas simple CSV format, and has some basic  plotting functionality for viewing the\nresults.\n\nSinter doesn't support cloud compute, but it does scale well on  a single\nmachine.\nI've tested it on 2 core machines, 4 core machines, and 96 core machines.\nAlthough there are potential pitfalls (e.g. setting batch sizes too large causes\nthrashing), sinter generally achieves good resource utilization of the processes\nyou assign to it.\n\n<a name=\"how_to_install\"></a>\n# How to install\n\nSinter is available as a pypi package. It can be installed using pip:\n\n```\npip install sinter\n```\n\nWhen you are in a python virtual environment with sinter installed, you have\naccess to a command line command `sinter` which can be used to perform tasks\nfrom the command line. You can also `import sinter` in a python program in order\nto use sinter's python API.\n\n<a name=\"how_to_use_python\"></a>\n# How to use: Python API\n\nThis example assumes you are in a python environment with `sinter` and\n`pymatching` installed.\n\n```python\nimport stim\nimport sinter\nimport matplotlib.pyplot as plt\n\n\n# Generates surface code circuit tasks using Stim's circuit generation.\ndef generate_example_tasks():\n    for p in [0.001, 0.005, 0.01]:\n        for d in [3, 5]:\n            yield sinter.Task(\n                circuit=stim.Circuit.generated(\n                    rounds=d,\n                    distance=d,\n                    after_clifford_depolarization=p,\n                    code_task=f'surface_code:rotated_memory_x',\n                ),\n                json_metadata={\n                    'p': p,\n                    'd': d,\n                },\n            )\n\n\ndef main():\n    # Collect the samples (takes a few minutes).\n    samples = sinter.collect(\n        num_workers=4,\n        max_shots=1_000_000,\n        max_errors=1000,\n        tasks=generate_example_tasks(),\n        decoders=['pymatching'],\n    )\n\n    # Print samples as CSV data.\n    print(sinter.CSV_HEADER)\n    for sample in samples:\n        print(sample.to_csv_line())\n\n    # Render a matplotlib plot of the data.\n    fig, ax = plt.subplots(1, 1)\n    sinter.plot_error_rate(\n        ax=ax,\n        stats=samples,\n        group_func=lambda stat: f\"Rotated Surface Code d={stat.json_metadata['d']}\",\n        x_func=lambda stat: stat.json_metadata['p'],\n    )\n    ax.loglog()\n    ax.set_ylim(1e-5, 1)\n    ax.grid()\n    ax.set_title('Logical Error Rate vs Physical Error Rate')\n    ax.set_ylabel('Logical Error Probability (per shot)')\n    ax.set_xlabel('Physical Error Rate')\n    ax.legend()\n\n    # Save to file and also open in a window.\n    fig.savefig('plot.png')\n    plt.show()\n\n\n# NOTE: This is actually necessary! If the code inside 'main()' was at the\n# module level, the multiprocessing children spawned by sinter.collect would\n# also attempt to run that code.\nif __name__ == '__main__':\n    main()\n```\n\nExample output to stdout:\n\n```\n     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata\n   1000000,       837,         0,    36.6,pymatching,9f7e20c54fec45b6aef7491b774dd5c0a3b9a005aa82faf5b9c051d6e40d60a9,\"{\"\"d\"\":3,\"\"p\"\":0.001}\"\n     53498,      1099,         0,    6.52,pymatching,3f40432443a99b933fb548b831fb54e7e245d9d73a35c03ea5a2fb2ce270f8c8,\"{\"\"d\"\":3,\"\"p\"\":0.005}\"\n     16269,      1023,         0,    3.23,pymatching,17b2e0c99560d20307204494ac50e31b33e50721b4ebae99d9e3577ae7248874,\"{\"\"d\"\":3,\"\"p\"\":0.01}\"\n   1000000,       151,         0,    77.3,pymatching,e179a18739201250371ffaae0197d8fa19d26b58dfc2942f9f1c85568645387a,\"{\"\"d\"\":5,\"\"p\"\":0.001}\"\n     11363,      1068,         0,    12.5,pymatching,a4dec28934a033215ff1389651a26114ecc22016a6e122008830cf7dd04ba5ad,\"{\"\"d\"\":5,\"\"p\"\":0.01}\"\n     61569,      1001,         0,    24.5,pymatching,2fefcc356752482fb4c6d912c228f6d18762f5752796c668b6abeb7775f5de92,\"{\"\"d\"\":5,\"\"p\"\":0.005}\"\n```\n\nand the corresponding image saved to `plot.png`:\n\n![Example plot](readme_example_plot.png)\n\n## python API utility methods\n\nSinter's python module exposes a variety of methods that are handy for plotting\nor analyzing QEC data.\nSee the [sinter API reference](https://github.com/quantumlib/Stim/blob/main/doc/sinter_api.md).\n\n<a name=\"how_to_use_linux\"></a>\n# How to use: Linux Command Line\n\nThis example assumes you are using a linux command line in a python virtualenv with `sinter` installed.\n\n## pick circuits\n\nFor this example, we will use Stim's circuit generation functionality to produce\ncircuits to benchmark.\nWe will make rotated surface code circuits with various physical error rates,\nwith filenames like `rotated_d5_p0.001_surface_code.stim`.\n\n```bash\nmkdir -p circuits\npython -c \"\n\nimport stim\n\nfor p in [0.001, 0.005, 0.01]:\n    for d in [3, 5]:\n        with open(f'circuits/d={d},p={p},b=X,type=rotated_surface_memory.stim', 'w') as f:\n            c = stim.Circuit.generated(\n                rounds=d,\n                distance=d,\n                after_clifford_depolarization=p,\n                after_reset_flip_probability=p,\n                before_measure_flip_probability=p,\n                before_round_data_depolarization=p,\n                code_task=f'surface_code:rotated_memory_x')\n            print(c, file=f)\n\"\n```\n\nNormally, making the circuit files is the hardest step, because they are what\nspecifies the problem you are sampling from.\nAlmost all of the work you do will generally involve creating the exact perfect\ncircuit file for your needs.\nBut this is just an example, so we'll use normal surface code circuits.\n\n# collect\n\nYou can use sinter to collect statistics on each circuit by using the `sinter collect` command.\nThis command takes options specifying how much data to collect, how to do decoding, etc.\n\nThe `processes` argument decides how many workers to use. Set it to `auto` to set\nit to the number of CPUs on your machine.\n\nThe `metadata_func` argument can be used to specify custom python expression that turns the `path`\ninto a dictionary or other JSON object associated with the circuit.\nIf you set `metadata_func` to `auto` then will use the method\n`sinter.comma_separated_key_values(path)` which parses\nstim circuit paths like `folder/a=2,b=test.stim` into a dictionary like `{'a': 2, 'b': 'test'}`.\n\nBy default, sinter writes the collected statistics to stdout as CSV data.\nOne particularly important option that changes this behavior is `--save_resume_filepath`,\nwhich allows the command to be interrupted and restarted without losing data.\nAny data already at the file specified by `--save_resume_filepath` will count towards the\namount of statistics asked to be collected, and sinter will append new statistics to this file\ninstead of overwriting it.\n\n```bash\nsinter collect \\\n    --processes auto \\\n    --circuits circuits/*.stim \\\n    --metadata_func auto \\\n    --decoders pymatching \\\n    --max_shots 1_000_000 \\\n    --max_errors 1000 \\\n    --save_resume_filepath stats.csv\n```\n\nBeware that if you SIGKILL or SIGTEM sinter, instead of just using SIGINT, it's possible\n(though unlikely) that you are killing it just as it writes a row of CSV data. This truncates\nthe data, which requires manual intervention on your part to fix (e.g. by deleting the partial row\nusing a text editor).\n\n# combine\n\nNote that the CSV data written by sinter will contain multiple rows for each case, because\nsinter starts by running small batches to see roughly what the error rate is before moving\nto larger batch sizes. \n\nYou can get a single-row-per-case CSV file by using `sinter combine`:\n\n```bash\nsinter combine stats.csv\n```\n\n```\n     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata\n     58591,      1067,         0,    5.50,pymatching,bb46c8fca4d9fd9d4d27a5039686332ac5e24011a7f2aea5a65f6040445567c0,\"{\"\"b\"\":\"\"X\"\",\"\"d\"\":3,\"\"p\"\":0.005,\"\"type\"\":\"\"rotated_surface_memory\"\"}\"\n   1000000,       901,         0,    73.4,pymatching,4c0780830fe1747ab22767b69d1178f803943c83dd4afa6d241acf02e6dfa71f,\"{\"\"b\"\":\"\"X\"\",\"\"d\"\":3,\"\"p\"\":0.001,\"\"type\"\":\"\"rotated_surface_memory\"\"}\"\n     16315,      1026,         0,    2.39,pymatching,64d81b177ef1a455644ac3e03f374394cd8ad385ba2ee0ac147b2405107564fc,\"{\"\"b\"\":\"\"X\"\",\"\"d\"\":3,\"\"p\"\":0.01,\"\"type\"\":\"\"rotated_surface_memory\"\"}\"\n   1000000,       157,         0,   116.5,pymatching,100855c078af0936d098cecbd8bfb7591c0951ae69527c002c9c5f4c79bde129,\"{\"\"b\"\":\"\"X\"\",\"\"d\"\":5,\"\"p\"\":0.001,\"\"type\"\":\"\"rotated_surface_memory\"\"}\"\n     61677,      1005,         0,    21.2,pymatching,6d7b8b312a5460c7fe08119d3c7a040daa25bd34d524611160e4aac6196293fe,\"{\"\"b\"\":\"\"X\"\",\"\"d\"\":5,\"\"p\"\":0.005,\"\"type\"\":\"\"rotated_surface_memory\"\"}\"\n     10891,      1021,         0,    7.43,pymatching,477252e968f0f22f64ccb058c0e1e9c77b765f60f74df8b6707de7ec65ed13b7,\"{\"\"b\"\":\"\"X\"\",\"\"d\"\":5,\"\"p\"\":0.01,\"\"type\"\":\"\"rotated_surface_memory\"\"}\"\n```\n\n# plot\n\nYou can use `sinter plot` to view the results you've collected.\nThis command takes a CSV file, an argument `--group_func` indicating how to\ngroup the statistics into curves, an argument `--x_func` indicating how to\npick the X coordinate of each point, and various other arguments. Each `*_func`\nargument takes a string that will be evaluated as a python expression, with\nvarious useful values in scope such as a `metadata` value containing the\njson metadata for the various points being evaluated. There is also a special\n`m` value where `m.key` is shorthand for `metadata.get('key', None)`.\n\nHere is an example of a `sinter plot` command:\n\n```bash\nsinter plot \\\n    --in stats.csv \\\n    --group_func \"f'''Rotated Surface Code d={m.d}'''\" \\\n    --x_func m.p \\\n    --xaxis \"[log]Physical Error Rate\" \\\n    --fig_size 1024 1024 \\\n    --out surface_code_figure.png \\\n    --show\n```\n\nWhich will save a png image of, and also open a window showing, a plot like this one:\n\n![Example plot](readme_example_plot.png)\n\n<a name=\"csv_format\"></a>\n# The csv format for sample statistics\n\nSinter saves samples as a table using a Comma Separated Value format.\nFor example:\n\n```\n  shots,errors,discards,seconds,decoder,strong_id,json_metadata\n1000000,   837,       0,   36.6,pymatching,9f7e20c54fec45b6aef7491b774dd5c0a3b9a005aa82faf5b9c051d6e40d60a9,\"{\"\"d\"\":3,\"\"p\"\":0.001}\"\n  53498,  1099,       0,   6.52,pymatching,3f40432443a99b933fb548b831fb54e7e245d9d73a35c03ea5a2fb2ce270f8c8,\"{\"\"d\"\":3,\"\"p\"\":0.005}\"\n  16269,  1023,       0,   3.23,pymatching,17b2e0c99560d20307204494ac50e31b33e50721b4ebae99d9e3577ae7248874,\"{\"\"d\"\":3,\"\"p\"\":0.01}\"\n1000000,   151,       0,   77.3,pymatching,e179a18739201250371ffaae0197d8fa19d26b58dfc2942f9f1c85568645387a,\"{\"\"d\"\":5,\"\"p\"\":0.001}\"\n  11363,  1068,       0,   12.5,pymatching,a4dec28934a033215ff1389651a26114ecc22016a6e122008830cf7dd04ba5ad,\"{\"\"d\"\":5,\"\"p\"\":0.01}\"\n  61569,  1001,       0,   24.5,pymatching,2fefcc356752482fb4c6d912c228f6d18762f5752796c668b6abeb7775f5de92,\"{\"\"d\"\":5,\"\"p\"\":0.005}\"\n```\n\nThe columns are:\n\n- `shots` (unsigned int): How many times the circuit was sampled.\n- `errors` (unsigned int): How many times the decoder failed to predict any logical observable.\n- `discards` (unsigned int): How many times a shot was discarded because a postselected detector fired or because the decoder incorrectly predicted the value of a postselected observable. Discarded shots never count as errors.\n- `seconds` (non-negative float): How many CPU core seconds it took to simulate and decode these shots.\n- `decoder` (str): Which decoder was used.\n- `strong_id` (str):\nHex representation of a cryptographic hash of the problem\nbeing sampled from.\nThe hashed data includes the exact circuit that was simulated,\nthe decoder that was used,\nthe exact detector error model that was given to the decoder,\nthe postselection rules that were applied,\nand the metadata associated with the circuit.\nThe purpose of the strong id is to make it impossible to accidentally combine\nshots that were from separate circuits or separate versions of a circuit.\n- `json_metadata` (json): A free form field that can store any value representable in\n[Java Script Object Notation](https://json.org). For example, this could be a\ndictionary with helpful keys like \"noise_level\" or \"circuit_name\". The json\nvalue is serialized into JSON and then escaped so that it can be put into the\nCSV data (e.g. quotes get doubled up).\n- `custom_counts` (json[Dict[str, int]]): An optional field that can store a\ndictionary from string keys to integer counts represented in\n[Java Script Object Notation](https://json.org).\nThe counts can be a huge variety of things, ranging from per-observable error\ncounts to detection event counts. In general, any value that should be added\nwhen merging rows could be in these counters.\n\nNote shots may be spread across multiple rows.\nFor example, this data:\n\n```\n  shots,errors,discards,seconds,decoder,strong_id,json_metadata\n 500000,   437,       0,   20.5,pymatching,9f7e20c54fec45b6aef7491b774dd5c0a3b9a005aa82faf5b9c051d6e40d60a9,\"{\"\"d\"\":3,\"\"p\"\":0.001}\"\n 500000,   400,       0,   16.1,pymatching,9f7e20c54fec45b6aef7491b774dd5c0a3b9a005aa82faf5b9c051d6e40d60a9,\"{\"\"d\"\":3,\"\"p\"\":0.001}\"\n```\n\nhas the same total statistics as this data:\n\n```\n  shots,errors,discards,seconds,decoder,strong_id,json_metadata\n1000000,   837,       0,   36.6,pymatching,9f7e20c54fec45b6aef7491b774dd5c0a3b9a005aa82faf5b9c051d6e40d60a9,\"{\"\"d\"\":3,\"\"p\"\":0.001}\"\n```\n\njust split over two rows instead of combined into one.\n"
  },
  {
    "path": "glue/sample/requirements.txt",
    "content": "matplotlib\nnumpy\nstim\nscipy\n"
  },
  {
    "path": "glue/sample/setup.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom setuptools import setup\n\nwith open('README.md', encoding='UTF-8') as f:\n    long_description = f.read()\nwith open('requirements.txt', encoding='UTF-8') as f:\n    requirements = f.read().splitlines()\n\n__version__ = '1.16.dev0'\n\nsetup(\n    name='sinter',\n    version=__version__,\n    author='Craig Gidney',\n    author_email='craig.gidney@gmail.com',\n    license='Apache 2',\n    packages=['sinter', 'sinter._data', 'sinter._collection', 'sinter._command', 'sinter._decoding'],\n    package_dir={'': 'src'},\n    description='Samples stim circuits and decodes them using pymatching.',\n    long_description=long_description,\n    long_description_content_type='text/markdown',\n    python_requires='>=3.7.0',\n    data_files=['README.md', 'requirements.txt', 'readme_example_plot.png'],\n    install_requires=requirements,\n    tests_require=['pytest', 'pymatching'],\n    entry_points={\n        'console_scripts': ['sinter=sinter._command._main:main'],\n    },\n)\n"
  },
  {
    "path": "glue/sample/src/sinter/__init__.py",
    "content": "__version__ = '1.16.dev0'\n\nfrom sinter._collection import (\n    collect,\n    iter_collect,\n    post_selection_mask_from_4th_coord,\n    Progress,\n)\nfrom sinter._data import (\n    AnonTaskStats,\n    CollectionOptions,\n    CSV_HEADER,\n    read_stats_from_csv_files,\n    stats_from_csv_files,\n    Task,\n    TaskStats,\n)\nfrom sinter._decoding import (\n    CompiledDecoder,\n    Decoder,\n    BUILT_IN_DECODERS,\n    BUILT_IN_SAMPLERS,\n    Sampler,\n    CompiledSampler,\n)\nfrom sinter._probability_util import (\n    comma_separated_key_values,\n    Fit,\n    fit_binomial,\n    fit_line_slope,\n    fit_line_y_at_x,\n    log_binomial,\n    log_factorial,\n    shot_error_rate_to_piece_error_rate,\n)\nfrom sinter._plotting import (\n    better_sorted_str_terms,\n    plot_discard_rate,\n    plot_error_rate,\n    plot_custom,\n    group_by,\n)\nfrom sinter._predict import (\n    predict_discards_bit_packed,\n    predict_observables_bit_packed,\n    predict_on_disk,\n    predict_observables,\n)\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/__init__.py",
    "content": "from sinter._collection._collection import (\n    collect,\n    iter_collect,\n    post_selection_mask_from_4th_coord,\n    post_selection_mask_from_predicate,\n    Progress,\n)\nfrom sinter._collection._printer import (\n    ThrottledProgressPrinter,\n)\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_collection.py",
    "content": "import contextlib\nimport dataclasses\nimport pathlib\nfrom typing import Any, Callable, Iterator, Optional, Union, Iterable, List, TYPE_CHECKING, Tuple, Dict\n\nimport math\nimport numpy as np\nimport stim\n\nfrom sinter._data import CSV_HEADER, ExistingData, TaskStats, CollectionOptions, Task\nfrom sinter._collection._collection_manager import CollectionManager\nfrom sinter._collection._printer import ThrottledProgressPrinter\n\nif TYPE_CHECKING:\n    import sinter\n\n\n@dataclasses.dataclass(frozen=True)\nclass Progress:\n    \"\"\"Describes statistics and status messages from ongoing sampling.\n\n    This is the type yielded by `sinter.iter_collect`, and given to the\n    `progress_callback` argument of `sinter.collect`.\n\n    Attributes:\n        new_stats: New sampled statistics collected since the last progress\n            update.\n        status_message: A free form human readable string describing the current\n            collection status, such as the number of tasks left and the\n            estimated time to completion for each task.\n    \"\"\"\n    new_stats: Tuple[TaskStats, ...]\n    status_message: str\n\n\ndef iter_collect(*,\n                 num_workers: int,\n                 tasks: Union[Iterator['sinter.Task'],\n                              Iterable['sinter.Task']],\n                 hint_num_tasks: Optional[int] = None,\n                 additional_existing_data: Union[None, dict[str, 'TaskStats'], Iterable['TaskStats']] = None,\n                 max_shots: Optional[int] = None,\n                 max_errors: Optional[int] = None,\n                 decoders: Optional[Iterable[str]] = None,\n                 max_batch_seconds: Optional[int] = None,\n                 max_batch_size: Optional[int] = None,\n                 start_batch_size: Optional[int] = None,\n                 count_observable_error_combos: bool = False,\n                 count_detection_events: bool = False,\n                 custom_decoders: Optional[Dict[str, Union['sinter.Decoder', 'sinter.Sampler']]] = None,\n                 custom_error_count_key: Optional[str] = None,\n                 allowed_cpu_affinity_ids: Optional[Iterable[int]] = None,\n                 ) -> Iterator['sinter.Progress']:\n    \"\"\"Iterates error correction statistics collected from worker processes.\n\n    It is important to iterate until the sequence ends, or worker processes will\n    be left alive. The values yielded during iteration are progress updates from\n    the workers.\n\n    Note: if max_batch_size and max_batch_seconds are both not used (or\n    explicitly set to None), a default batch-size-limiting mechanism will be\n    chosen.\n\n    Args:\n        num_workers: The number of worker processes to use.\n        tasks: Decoding problems to sample.\n        hint_num_tasks: If `tasks` is an iterator or a generator, its length\n            can be given here so that progress printouts can say how many cases\n            are left.\n        additional_existing_data: Defaults to None (no additional data).\n            Statistical data that has already been collected, in addition to\n            anything included in each task's `previous_stats` field.\n        decoders: Defaults to None (specified by each Task). The names of the\n            decoders to use on each Task. It must either be the case that each\n            Task specifies a decoder and this is set to None, or this is an\n            iterable and each Task has its decoder set to None.\n        max_shots: Defaults to None (unused). Stops the sampling process\n            after this many samples have been taken from the circuit.\n        max_errors: Defaults to None (unused). Stops the sampling process\n            after this many errors have been seen in samples taken from the\n            circuit. The actual number sampled errors may be larger due to\n            batching.\n        count_observable_error_combos: Defaults to False. When set to to True,\n            the returned stats will have a custom counts field with keys\n            like `obs_mistake_mask=E_E__` counting how many times specific\n            combinations of observables were mispredicted by the decoder.\n        count_detection_events: Defaults to False. When set to True, the\n            returned stats will have a custom counts field withs the\n            key `detection_events` counting the number of times a detector fired\n            and also `detectors_checked` counting the number of detectors that\n            were executed. The detection fraction is the ratio of these two\n            numbers.\n        start_batch_size: Defaults to None (collector's choice). The very\n            first shots taken from the circuit will use a batch of this\n            size, and no other batches will be taken in parallel. Once this\n            initial fact finding batch is done, batches can be taken in\n            parallel and the normal batch size limiting processes take over.\n        max_batch_size: Defaults to None (unused). Limits batches from\n            taking more than this many shots at once. For example, this can\n            be used to ensure memory usage stays below some limit.\n        max_batch_seconds: Defaults to None (unused). When set, the recorded\n            data from previous shots is used to estimate how much time is\n            taken per shot. This information is then used to predict the\n            biggest batch size that can finish in under the given number of\n            seconds. Limits each batch to be no larger than that.\n        custom_decoders: Custom decoders that can be used if requested by name.\n            If not specified, only decoders built into sinter, such as\n            'pymatching' and 'fusion_blossom', can be used.\n        custom_error_count_key: Makes `max_errors` apply to `stat.custom_counts[key]`\n            instead of `stat.errors`.\n        allowed_cpu_affinity_ids: Controls which CPUs the workers can be pinned to. The\n            set of allowed IDs should be at least as large as the number of workers, though\n            this is not strictly required. If not set, defaults to all CPUs being allowed.\n\n    Yields:\n        sinter.Progress instances recording incremental statistical data as it\n        is collected by workers.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> tasks = [\n        ...     sinter.Task(\n        ...         circuit=stim.Circuit.generated(\n        ...             'repetition_code:memory',\n        ...             distance=5,\n        ...             rounds=5,\n        ...             before_round_data_depolarization=1e-3,\n        ...         ),\n        ...         json_metadata={'d': 5},\n        ...     ),\n        ...     sinter.Task(\n        ...         circuit=stim.Circuit.generated(\n        ...             'repetition_code:memory',\n        ...             distance=7,\n        ...             rounds=5,\n        ...             before_round_data_depolarization=1e-3,\n        ...         ),\n        ...         json_metadata={'d': 7},\n        ...     ),\n        ... ]\n        >>> iterator = sinter.iter_collect(\n        ...     tasks=tasks,\n        ...     decoders=['vacuous'],\n        ...     num_workers=2,\n        ...     max_shots=100,\n        ... )\n        >>> total_shots = 0\n        >>> for progress in iterator:\n        ...     for stat in progress.new_stats:\n        ...         total_shots += stat.shots\n        >>> print(total_shots)\n        200\n    \"\"\"\n    existing_data: dict[str, TaskStats]\n    if isinstance(additional_existing_data, ExistingData):\n        existing_data = additional_existing_data.data\n    elif isinstance(additional_existing_data, dict):\n        existing_data = additional_existing_data\n    elif additional_existing_data is None:\n        existing_data = {}\n    else:\n        acc = ExistingData()\n        for stat in additional_existing_data:\n            acc.add_sample(stat)\n        existing_data = acc.data\n\n    if isinstance(decoders, str):\n        decoders = [decoders]\n\n    if hint_num_tasks is None:\n        try:\n            # noinspection PyTypeChecker\n            hint_num_tasks = len(tasks)\n        except TypeError:\n            pass\n\n    if decoders is not None:\n        old_tasks = tasks\n        tasks = (\n            Task(\n                circuit=task.circuit,\n                decoder=decoder,\n                detector_error_model=task.detector_error_model,\n                postselection_mask=task.postselection_mask,\n                postselected_observables_mask=task.postselected_observables_mask,\n                json_metadata=task.json_metadata,\n                collection_options=task.collection_options,\n                circuit_path=task.circuit_path,\n            )\n            for task in old_tasks\n            for decoder in (decoders if task.decoder is None else [task.decoder])\n        )\n\n    progress_log: list[Optional[TaskStats]] = []\n    def log_progress(e: Optional[TaskStats]):\n        progress_log.append(e)\n    with CollectionManager(\n        num_workers=num_workers,\n        tasks=tasks,\n        collection_options=CollectionOptions(\n            max_shots=max_shots,\n            max_errors=max_errors,\n            max_batch_seconds=max_batch_seconds,\n            start_batch_size=start_batch_size,\n            max_batch_size=max_batch_size,\n        ),\n        existing_data=existing_data,\n        count_observable_error_combos=count_observable_error_combos,\n        count_detection_events=count_detection_events,\n        custom_error_count_key=custom_error_count_key,\n        custom_decoders=custom_decoders or {},\n        allowed_cpu_affinity_ids=allowed_cpu_affinity_ids,\n        worker_flush_period=max_batch_seconds or 120,\n        progress_callback=log_progress,\n    ) as manager:\n        try:\n            yield Progress(\n                new_stats=(),\n                status_message=f\"Starting {num_workers} workers...\"\n            )\n            manager.start_workers()\n            manager.start_distributing_work()\n\n            while manager.task_states:\n                manager.process_message()\n                if progress_log:\n                    vals = list(progress_log)\n                    progress_log.clear()\n                    for e in vals:\n                        if e is not None:\n                            yield Progress(\n                                new_stats=(e,),\n                                status_message=manager.status_message(),\n                            )\n\n        except KeyboardInterrupt:\n            yield Progress(\n                new_stats=(),\n                status_message='KeyboardInterrupt',\n            )\n            raise\n\n\ndef collect(*,\n            num_workers: int,\n            tasks: Union[Iterator['sinter.Task'], Iterable['sinter.Task']],\n            existing_data_filepaths: Iterable[Union[str, pathlib.Path]] = (),\n            save_resume_filepath: Union[None, str, pathlib.Path] = None,\n            progress_callback: Optional[Callable[['sinter.Progress'], None]] = None,\n            max_shots: Optional[int] = None,\n            max_errors: Optional[int] = None,\n            count_observable_error_combos: bool = False,\n            count_detection_events: bool = False,\n            decoders: Optional[Iterable[str]] = None,\n            max_batch_seconds: Optional[int] = None,\n            max_batch_size: Optional[int] = None,\n            start_batch_size: Optional[int] = None,\n            print_progress: bool = False,\n            hint_num_tasks: Optional[int] = None,\n            custom_decoders: Optional[Dict[str, Union['sinter.Decoder', 'sinter.Sampler']]] = None,\n            custom_error_count_key: Optional[str] = None,\n            allowed_cpu_affinity_ids: Optional[Iterable[int]] = None,\n            ) -> List['sinter.TaskStats']:\n    \"\"\"Collects statistics from the given tasks, using multiprocessing.\n\n    Args:\n        num_workers: The number of worker processes to use.\n        tasks: Decoding problems to sample.\n        save_resume_filepath: Defaults to None (unused). If set to a filepath,\n            results will be saved to that file while they are collected. If the\n            python interpreter is stopped or killed, calling this method again\n            with the same save_resume_filepath will load the previous results\n            from the file so it can resume where it left off.\n\n            The stats in this file will be counted in addition to each task's\n            previous_stats field (as opposed to overriding the field).\n        existing_data_filepaths: CSV data saved to these files will be loaded,\n            included in the returned results, and count towards things like\n            max_shots and max_errors.\n        progress_callback: Defaults to None (unused). If specified, then each\n            time new sample statistics are acquired from a worker this method\n            will be invoked with the new `sinter.TaskStats`.\n        hint_num_tasks: If `tasks` is an iterator or a generator, its length\n            can be given here so that progress printouts can say how many cases\n            are left.\n        decoders: Defaults to None (specified by each Task). The names of the\n            decoders to use on each Task. It must either be the case that each\n            Task specifies a decoder and this is set to None, or this is an\n            iterable and each Task has its decoder set to None.\n        count_observable_error_combos: Defaults to False. When set to to True,\n            the returned stats will have a custom counts field with keys\n            like `obs_mistake_mask=E_E__` counting how many times specific\n            combinations of observables were mispredicted by the decoder.\n        count_detection_events: Defaults to False. When set to True, the\n            returned stats will have a custom counts field withs the\n            key `detection_events` counting the number of times a detector fired\n            and also `detectors_checked` counting the number of detectors that\n            were executed. The detection fraction is the ratio of these two\n            numbers.\n        max_shots: Defaults to None (unused). Stops the sampling process\n            after this many samples have been taken from the circuit.\n        max_errors: Defaults to None (unused). Stops the sampling process\n            after this many errors have been seen in samples taken from the\n            circuit. The actual number sampled errors may be larger due to\n            batching.\n        start_batch_size: Defaults to None (collector's choice). The very\n            first shots taken from the circuit will use a batch of this\n            size, and no other batches will be taken in parallel. Once this\n            initial fact finding batch is done, batches can be taken in\n            parallel and the normal batch size limiting processes take over.\n        max_batch_size: Defaults to None (unused). Limits batches from\n            taking more than this many shots at once. For example, this can\n            be used to ensure memory usage stays below some limit.\n        print_progress: When True, progress is printed to stderr while\n            collection runs.\n        max_batch_seconds: Defaults to None (unused). When set, the recorded\n            data from previous shots is used to estimate how much time is\n            taken per shot. This information is then used to predict the\n            biggest batch size that can finish in under the given number of\n            seconds. Limits each batch to be no larger than that.\n        custom_decoders: Named child classes of `sinter.decoder`, that can be\n            used if requested by name by a task or by the decoders list.\n            If not specified, only decoders with support built into sinter, such\n            as 'pymatching' and 'fusion_blossom', can be used.\n        custom_error_count_key: Makes `max_errors` apply to `stat.custom_counts[key]`\n            instead of `stat.errors`.\n        allowed_cpu_affinity_ids: Controls which CPUs the workers can be pinned to. The\n            set of allowed IDs should be at least as large as the number of workers, though\n            this is not strictly required. If not set, defaults to all CPUs being allowed.\n\n    Returns:\n        A list of sample statistics, one from each problem. The list is not in\n        any specific order. This is the same data that would have been written\n        to a CSV file, but aggregated so that each problem has exactly one\n        sample statistic instead of potentially multiple.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> tasks = [\n        ...     sinter.Task(\n        ...         circuit=stim.Circuit.generated(\n        ...             'repetition_code:memory',\n        ...             distance=5,\n        ...             rounds=5,\n        ...             before_round_data_depolarization=1e-3,\n        ...         ),\n        ...         json_metadata={'d': 5},\n        ...     ),\n        ...     sinter.Task(\n        ...         circuit=stim.Circuit.generated(\n        ...             'repetition_code:memory',\n        ...             distance=7,\n        ...             rounds=5,\n        ...             before_round_data_depolarization=1e-3,\n        ...         ),\n        ...         json_metadata={'d': 7},\n        ...     ),\n        ... ]\n        >>> stats = sinter.collect(\n        ...     tasks=tasks,\n        ...     decoders=['vacuous'],\n        ...     num_workers=2,\n        ...     max_shots=100,\n        ... )\n        >>> for stat in sorted(stats, key=lambda e: e.json_metadata['d']):\n        ...     print(stat.json_metadata, stat.shots)\n        {'d': 5} 100\n        {'d': 7} 100\n    \"\"\"\n    # Load existing data.\n    additional_existing_data = ExistingData()\n    for existing in existing_data_filepaths:\n        additional_existing_data += ExistingData.from_file(existing)\n\n    if save_resume_filepath in existing_data_filepaths:\n        raise ValueError(\"save_resume_filepath in existing_data_filepaths\")\n\n    progress_printer = ThrottledProgressPrinter(\n        outs=[],\n        print_progress=print_progress,\n        min_progress_delay=0.1,\n    )\n    with contextlib.ExitStack() as exit_stack:\n        # Open save/resume file.\n        if save_resume_filepath is not None:\n            save_resume_filepath = pathlib.Path(save_resume_filepath)\n            if save_resume_filepath.exists():\n                additional_existing_data += ExistingData.from_file(save_resume_filepath)\n                save_resume_file = exit_stack.enter_context(\n                        open(save_resume_filepath, 'a'))  # type: ignore\n            else:\n                save_resume_filepath.parent.mkdir(exist_ok=True)\n                save_resume_file = exit_stack.enter_context(\n                        open(save_resume_filepath, 'w'))  # type: ignore\n                print(CSV_HEADER, file=save_resume_file, flush=True)\n        else:\n            save_resume_file = None\n\n        # Collect data.\n        result = ExistingData()\n        result.data = dict(additional_existing_data.data)\n        for progress in iter_collect(\n            num_workers=num_workers,\n            max_shots=max_shots,\n            max_errors=max_errors,\n            max_batch_seconds=max_batch_seconds,\n            start_batch_size=start_batch_size,\n            max_batch_size=max_batch_size,\n            count_observable_error_combos=count_observable_error_combos,\n            count_detection_events=count_detection_events,\n            decoders=decoders,\n            tasks=tasks,\n            hint_num_tasks=hint_num_tasks,\n            additional_existing_data=additional_existing_data,\n            custom_decoders=custom_decoders,\n            custom_error_count_key=custom_error_count_key,\n            allowed_cpu_affinity_ids=allowed_cpu_affinity_ids,\n        ):\n            for stats in progress.new_stats:\n                result.add_sample(stats)\n                if save_resume_file is not None:\n                    print(stats.to_csv_line(), file=save_resume_file, flush=True)\n            if print_progress:\n                progress_printer.show_latest_progress(progress.status_message)\n            if progress_callback is not None:\n                progress_callback(progress)\n        if print_progress:\n            progress_printer.flush()\n        return list(result.data.values())\n\n\ndef post_selection_mask_from_predicate(\n    circuit_or_dem: Union[stim.Circuit, stim.DetectorErrorModel],\n    *,\n    postselected_detectors_predicate: Callable[[int, Any, Tuple[float, ...]], bool],\n    metadata: Any,\n) -> np.ndarray:\n    num_dets = circuit_or_dem.num_detectors\n    post_selection_mask = np.zeros(dtype=np.uint8, shape=math.ceil(num_dets / 8))\n    for k, coord in circuit_or_dem.get_detector_coordinates().items():\n        if postselected_detectors_predicate(k, metadata, coord):\n            post_selection_mask[k // 8] |= 1 << (k % 8)\n    return post_selection_mask\n\n\ndef post_selection_mask_from_4th_coord(dem: Union[stim.Circuit, stim.DetectorErrorModel]) -> np.ndarray:\n    \"\"\"Returns a mask that postselects detector's with non-zero 4th coordinate.\n\n    This method is a leftover from before the existence of the command line\n    argument `--postselected_detectors_predicate`, when\n    `--postselect_detectors_with_non_zero_4th_coord` was the only way to do\n    post selection of detectors.\n\n    Args:\n        dem: The detector error model to pull coordinate data from.\n\n    Returns:\n        A bit packed numpy array where detectors with non-zero 4th coordinate\n        data have a True bit at their corresponding index.\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     detector(1, 2, 3) D0\n        ...     detector(1, 1, 1, 1) D1\n        ...     detector(1, 1, 1, 0) D2\n        ...     detector(1, 1, 1, 999) D80\n        ... ''')\n        >>> sinter.post_selection_mask_from_4th_coord(dem)\n        array([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], dtype=uint8)\n    \"\"\"\n    num_dets = dem.num_detectors\n    post_selection_mask = np.zeros(dtype=np.uint8, shape=math.ceil(num_dets / 8))\n    for k, coord in dem.get_detector_coordinates().items():\n        if len(coord) >= 4 and coord[3]:\n            post_selection_mask[k // 8] |= 1 << (k % 8)\n    return post_selection_mask\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_collection_manager.py",
    "content": "import collections\nimport contextlib\nimport math\nimport multiprocessing\nimport os\nimport pathlib\nimport queue\nimport tempfile\nimport threading\nfrom typing import Any, Optional, List, Dict, Iterable, Callable, Tuple\nfrom typing import Union\nfrom typing import cast\n\nfrom sinter._collection._collection_worker_loop import collection_worker_loop\nfrom sinter._collection._mux_sampler import MuxSampler\nfrom sinter._collection._sampler_ramp_throttled import RampThrottledSampler\nfrom sinter._data import CollectionOptions, Task, AnonTaskStats, TaskStats\nfrom sinter._decoding import Sampler, Decoder\n\n\nclass _ManagedWorkerState:\n    def __init__(self, worker_id: int, *, cpu_pin: Optional[int] = None):\n        self.worker_id: int = worker_id\n        self.process: Union[multiprocessing.Process, threading.Thread, None] = None\n        self.input_queue: Optional[multiprocessing.Queue[Tuple[str, Any]]] = None\n        self.assigned_work_key: Any = None\n        self.asked_to_drop_shots: int = 0\n        self.cpu_pin = cpu_pin\n\n        # Shots transfer into this field when manager sends shot requests to workers.\n        # Shots transfer out of this field when clients flush results or respond to work return requests.\n        self.assigned_shots: int = 0\n\n    def send_message(self, message: Any):\n        self.input_queue.put(message)\n\n    def ask_to_return_all_shots(self):\n        if self.asked_to_drop_shots == 0 and self.assigned_shots > 0:\n            self.send_message((\n                'return_shots',\n                (\n                    self.assigned_work_key,\n                    self.assigned_shots,\n                ),\n            ))\n            self.asked_to_drop_shots = self.assigned_shots\n\n    def has_returned_all_shots(self) -> bool:\n        return self.assigned_shots == 0 and self.asked_to_drop_shots == 0\n\n    def is_available_to_reassign(self) -> bool:\n        return self.assigned_work_key is None\n\n\nclass _ManagedTaskState:\n    def __init__(self, *, partial_task: Task, strong_id: str, shots_left: int, errors_left: int):\n        self.partial_task = partial_task\n        self.strong_id = strong_id\n        self.shots_left = shots_left\n        self.errors_left = errors_left\n        self.shots_unassigned = shots_left\n        self.shot_return_requests = 0\n        self.assigned_soft_error_flush_threshold: int = errors_left\n        self.workers_assigned: list[int] = []\n\n    def is_completed(self) -> bool:\n        return self.shots_left <= 0 or self.errors_left <= 0\n\n\nclass CollectionManager:\n    def __init__(\n            self,\n            *,\n            existing_data: Dict[Any, TaskStats],\n            collection_options: CollectionOptions,\n            custom_decoders: dict[str, Union[Decoder, Sampler]],\n            num_workers: int,\n            worker_flush_period: float,\n            tasks: Iterable[Task],\n            progress_callback: Callable[[Optional[TaskStats]], None],\n            allowed_cpu_affinity_ids: Optional[Iterable[int]],\n            count_observable_error_combos: bool = False,\n            count_detection_events: bool = False,\n            custom_error_count_key: Optional[str] = None,\n            use_threads_for_debugging: bool = False,\n    ):\n        assert isinstance(custom_decoders, dict)\n        self.existing_data = existing_data\n        self.num_workers: int = num_workers\n        self.custom_decoders = custom_decoders\n        self.worker_flush_period: float = worker_flush_period\n        self.progress_callback = progress_callback\n        self.collection_options = collection_options\n        self.partial_tasks: list[Task] = list(tasks)\n        self.task_strong_ids: List[Optional[str]] = [None] * len(self.partial_tasks)\n        self.allowed_cpu_affinity_ids = None if allowed_cpu_affinity_ids is None else sorted(set(allowed_cpu_affinity_ids))\n        self.count_observable_error_combos = count_observable_error_combos\n        self.count_detection_events = count_detection_events\n        self.custom_error_count_key = custom_error_count_key\n        self.use_threads_for_debugging = use_threads_for_debugging\n\n        self.shared_worker_output_queue: Optional[multiprocessing.SimpleQueue[Tuple[str, int, Any]]] = None\n        self.task_states: Dict[Any, _ManagedTaskState] = {}\n        self.started: bool = False\n        self.total_collected = {k: v.to_anon_stats() for k, v in existing_data.items()}\n\n        if self.allowed_cpu_affinity_ids is None:\n            cpus = range(os.cpu_count())\n        else:\n            num_cpus = os.cpu_count()\n            cpus = [e for e in self.allowed_cpu_affinity_ids if e < num_cpus]\n        self.worker_states: List[_ManagedWorkerState] = []\n        for index in range(num_workers):\n            cpu_pin = None if len(cpus) == 0 else cpus[index % len(cpus)]\n            self.worker_states.append(_ManagedWorkerState(index, cpu_pin=cpu_pin))\n        self.tmp_dir: Optional[pathlib.Path] = None\n\n    def __enter__(self):\n        self.exit_stack = contextlib.ExitStack().__enter__()\n        self.tmp_dir = pathlib.Path(self.exit_stack.enter_context(tempfile.TemporaryDirectory()))\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb):\n        self.hard_stop()\n        self.exit_stack.__exit__(exc_type, exc_val, exc_tb)\n        self.exit_stack = None\n        self.tmp_dir = None\n\n    def start_workers(self, *, actually_start_worker_processes: bool = True):\n        assert not self.started\n\n        # Use max_batch_size from collection_options if provided, otherwise default to 1024 as large\n        # batch sizes can lead to thrashing\n        max_batch_shots = self.collection_options.max_batch_size or 1024\n\n        sampler = RampThrottledSampler(\n            sub_sampler=MuxSampler(\n                custom_decoders=self.custom_decoders,\n                count_observable_error_combos=self.count_observable_error_combos,\n                count_detection_events=self.count_detection_events,\n                tmp_dir=self.tmp_dir,\n            ),\n            target_batch_seconds=1,\n            max_batch_shots=max_batch_shots,\n        )\n\n        self.started = True\n        current_method = multiprocessing.get_start_method()\n        try:\n            # To ensure the child processes do not accidentally share ANY state\n            # related to random number generation, we use 'spawn' instead of 'fork'.\n            multiprocessing.set_start_method('spawn', force=True)\n            # Create queues after setting start method to work around a deadlock\n            # bug that occurs otherwise.\n            self.shared_worker_output_queue = multiprocessing.SimpleQueue()\n\n            for worker_id in range(self.num_workers):\n                worker_state = self.worker_states[worker_id]\n                worker_state.input_queue = multiprocessing.Queue()\n                worker_state.input_queue.cancel_join_thread()\n                worker_state.assigned_work_key = None\n                args = (\n                    self.worker_flush_period,\n                    worker_id,\n                    sampler,\n                    worker_state.input_queue,\n                    self.shared_worker_output_queue,\n                    worker_state.cpu_pin,\n                    self.custom_error_count_key,\n                )\n                if self.use_threads_for_debugging:\n                    worker_state.process = threading.Thread(\n                        target=collection_worker_loop,\n                        args=args,\n                    )\n                else:\n                    worker_state.process = multiprocessing.Process(\n                        target=collection_worker_loop,\n                        args=args,\n                    )\n\n                if actually_start_worker_processes:\n                    worker_state.process.start()\n        finally:\n            multiprocessing.set_start_method(current_method, force=True)\n\n    def start_distributing_work(self):\n        self._compute_task_ids()\n        self._distribute_work()\n\n    def _compute_task_ids(self):\n        idle_worker_ids = list(range(self.num_workers))\n        unknown_task_ids = list(range(len(self.partial_tasks)))\n        worker_to_task_map = {}\n        while worker_to_task_map or unknown_task_ids:\n            while idle_worker_ids and unknown_task_ids:\n                worker_id = idle_worker_ids.pop()\n                unknown_task_id = unknown_task_ids.pop()\n                worker_to_task_map[worker_id] = unknown_task_id\n                self.worker_states[worker_id].send_message(('compute_strong_id', self.partial_tasks[unknown_task_id]))\n\n            try:\n                message = self.shared_worker_output_queue.get()\n                message_type, worker_id, message_body = message\n                if message_type == 'computed_strong_id':\n                    assert worker_id in worker_to_task_map\n                    assert isinstance(message_body, str)\n                    self.task_strong_ids[worker_to_task_map.pop(worker_id)] = message_body\n                    idle_worker_ids.append(worker_id)\n                elif message_type == 'stopped_due_to_exception':\n                    cur_task, cur_shots_left, unflushed_work_done, traceback, ex = message_body\n                    raise ValueError(f'Worker failed: traceback={traceback}') from ex\n                else:\n                    raise NotImplementedError(f'{message_type=}')\n                self.progress_callback(None)\n            except queue.Empty:\n                pass\n\n        assert len(idle_worker_ids) == self.num_workers\n        seen = set()\n        for k in range(len(self.partial_tasks)):\n            options = self.partial_tasks[k].collection_options.combine(self.collection_options)\n            key: str = self.task_strong_ids[k]\n            if key in seen:\n                raise ValueError(f'Same task given twice: {self.partial_tasks[k]!r}')\n            seen.add(key)\n\n            shots_left = options.max_shots\n            errors_left = options.max_errors\n            if errors_left is None:\n                errors_left = shots_left\n            errors_left = min(errors_left, shots_left)\n            if key in self.existing_data:\n                val = self.existing_data[key]\n                shots_left -= val.shots\n                if self.custom_error_count_key is None:\n                    errors_left -= val.errors\n                else:\n                    errors_left -= val.custom_counts[self.custom_error_count_key]\n            if shots_left <= 0:\n                continue\n            self.task_states[key] = _ManagedTaskState(\n                partial_task=self.partial_tasks[k],\n                strong_id=key,\n                shots_left=shots_left,\n                errors_left=errors_left,\n            )\n            if self.task_states[key].is_completed():\n                del self.task_states[key]\n\n    def hard_stop(self):\n        if not self.started:\n            return\n\n        removed_workers = [state.process for state in self.worker_states]\n        for state in self.worker_states:\n            if isinstance(state.process, threading.Thread):\n                state.send_message('stop')\n            state.process = None\n            state.assigned_work_key = None\n            state.input_queue = None\n        self.shared_worker_output_queue = None\n        self.started = False\n        self.task_states.clear()\n\n        # SIGKILL everything.\n        for w in removed_workers:\n            if isinstance(w, multiprocessing.Process):\n                w.kill()\n        # Wait for them to be done.\n        for w in removed_workers:\n            w.join()\n\n    def _handle_task_progress(self, task_id: Any):\n        task_state = self.task_states[task_id]\n        if task_state.is_completed():\n            workers_ready = all(self.worker_states[worker_id].has_returned_all_shots() for worker_id in task_state.workers_assigned)\n            if workers_ready:\n                # Task is fully completed and can be forgotten entirely. Re-assign the workers.\n                del self.task_states[task_id]\n                for worker_id in task_state.workers_assigned:\n                    w = self.worker_states[worker_id]\n                    assert w.assigned_shots <= 0\n                    assert w.asked_to_drop_shots == 0\n                    w.assigned_work_key = None\n                self._distribute_work()\n            else:\n                # Task is sufficiently sampled, but some workers are still running.\n                for worker_id in task_state.workers_assigned:\n                    self.worker_states[worker_id].ask_to_return_all_shots()\n            self.progress_callback(None)\n        else:\n            self._distribute_unassigned_workers_to_jobs()\n            self._distribute_work_within_a_job(task_state)\n\n    def state_summary(self) -> str:\n        lines = []\n        for worker_id, worker in enumerate(self.worker_states):\n            lines.append(f'worker {worker_id}:'\n                         f' asked_to_drop_shots={worker.asked_to_drop_shots}'\n                         f' assigned_shots={worker.assigned_shots}'\n                         f' assigned_work_key={worker.assigned_work_key}')\n        for task in self.task_states.values():\n            lines.append(f'task {task.strong_id=}:\\n'\n                         f'    workers_assigned={task.workers_assigned}\\n'\n                         f'    shot_return_requests={task.shot_return_requests}\\n'\n                         f'    shots_left={task.shots_left}\\n'\n                         f'    errors_left={task.errors_left}\\n'\n                         f'    shots_unassigned={task.shots_unassigned}')\n        return '\\n' + '\\n'.join(lines) + '\\n'\n\n    def process_message(self) -> bool:\n        try:\n            message = self.shared_worker_output_queue.get()\n        except queue.Empty:\n            return False\n\n        message_type, worker_id, message_body = message\n        worker_state = self.worker_states[worker_id]\n\n        if message_type == 'flushed_results':\n            task_strong_id, anon_stat = message_body\n            assert isinstance(anon_stat, AnonTaskStats)\n            assert worker_state.assigned_work_key == task_strong_id\n            task_state = self.task_states[task_strong_id]\n\n            worker_state.assigned_shots -= anon_stat.shots\n            task_state.shots_left -= anon_stat.shots\n            if worker_state.assigned_shots < 0:\n                # Worker over-achieved. Correct the imbalance by giving them the shots.\n                extra_shots = abs(worker_state.assigned_shots)\n                worker_state.assigned_shots += extra_shots\n                task_state.shots_unassigned -= extra_shots\n                worker_state.send_message((\n                    'accept_shots',\n                    (task_state.strong_id, extra_shots),\n                ))\n\n            if self.custom_error_count_key is None:\n                task_state.errors_left -= anon_stat.errors\n            else:\n                task_state.errors_left -= anon_stat.custom_counts[self.custom_error_count_key]\n\n            stat = TaskStats(\n                strong_id=task_state.strong_id,\n                decoder=task_state.partial_task.decoder,\n                json_metadata=task_state.partial_task.json_metadata,\n                shots=anon_stat.shots,\n                discards=anon_stat.discards,\n                seconds=anon_stat.seconds,\n                errors=anon_stat.errors,\n                custom_counts=anon_stat.custom_counts,\n            )\n\n            self._handle_task_progress(task_strong_id)\n\n            if stat.strong_id not in self.total_collected:\n                self.total_collected[stat.strong_id] = AnonTaskStats()\n            self.total_collected[stat.strong_id] += stat.to_anon_stats()\n            self.progress_callback(stat)\n\n        elif message_type == 'changed_job':\n            pass\n\n        elif message_type == 'accepted_shots':\n            pass\n\n        elif message_type == 'returned_shots':\n            task_key, shots_returned = message_body\n            assert isinstance(shots_returned, int)\n            assert shots_returned >= 0\n            assert worker_state.assigned_work_key == task_key\n            assert worker_state.asked_to_drop_shots or worker_state.asked_to_drop_errors\n            task_state = self.task_states[task_key]\n            task_state.shot_return_requests -= 1\n            worker_state.asked_to_drop_shots = 0\n            worker_state.asked_to_drop_errors = 0\n            task_state.shots_unassigned += shots_returned\n            worker_state.assigned_shots -= shots_returned\n            assert worker_state.assigned_shots >= 0\n            self._handle_task_progress(task_key)\n\n        elif message_type == 'stopped_due_to_exception':\n            cur_task, cur_shots_left, unflushed_work_done, traceback, ex = message_body\n            raise RuntimeError(f'Worker failed: traceback={traceback}') from ex\n\n        else:\n            raise NotImplementedError(f'{message_type=}')\n\n        return True\n\n    def run_until_done(self) -> bool:\n        try:\n            while self.task_states:\n                self.process_message()\n            return True\n\n        except KeyboardInterrupt:\n            return False\n\n        finally:\n            self.hard_stop()\n\n    def _distribute_unassigned_workers_to_jobs(self):\n        idle_workers = [\n            w\n            for w in range(self.num_workers)[::-1]\n            if self.worker_states[w].is_available_to_reassign()\n        ]\n        if not idle_workers or not self.started:\n            return\n\n        groups = collections.defaultdict(list)\n        for work_state in self.task_states.values():\n            if not work_state.is_completed():\n                groups[len(work_state.workers_assigned)].append(work_state)\n        for k in groups.keys():\n            groups[k] = groups[k][::-1]\n        if not groups:\n            return\n        min_assigned = min(groups.keys(), default=0)\n\n        # Distribute workers to unfinished jobs with the fewest workers.\n        while idle_workers:\n            task_state: _ManagedTaskState = groups[min_assigned].pop()\n            groups[min_assigned + 1].append(task_state)\n            if not groups[min_assigned]:\n                min_assigned += 1\n\n            worker_id = idle_workers.pop()\n            task_state.workers_assigned.append(worker_id)\n            worker_state = self.worker_states[worker_id]\n            worker_state.assigned_work_key = task_state.strong_id\n            worker_state.send_message((\n                'change_job',\n                (task_state.partial_task, CollectionOptions(max_errors=task_state.errors_left), task_state.assigned_soft_error_flush_threshold),\n            ))\n\n    def _distribute_unassigned_work_to_workers_within_a_job(self, task_state: _ManagedTaskState):\n        if not self.started or not task_state.workers_assigned or task_state.shots_left <= 0:\n            return\n\n        num_task_workers = len(task_state.workers_assigned)\n        expected_shots_per_worker = (task_state.shots_left + num_task_workers - 1) // num_task_workers\n\n        # Give unassigned shots to idle workers.\n        for worker_id in sorted(task_state.workers_assigned, key=lambda wid: self.worker_states[wid].assigned_shots):\n            worker_state = self.worker_states[worker_id]\n            if worker_state.assigned_shots < expected_shots_per_worker:\n                shots_to_assign = min(expected_shots_per_worker - worker_state.assigned_shots,\n                                      task_state.shots_unassigned)\n                if shots_to_assign > 0:\n                    task_state.shots_unassigned -= shots_to_assign\n                    worker_state.assigned_shots += shots_to_assign\n                    worker_state.send_message((\n                        'accept_shots',\n                        (task_state.strong_id, shots_to_assign),\n                    ))\n\n    def status_message(self) -> str:\n        num_known_tasks_ids = sum(e is not None for e in self.task_strong_ids)\n        if num_known_tasks_ids < len(self.task_strong_ids):\n            return f\"Analyzed {num_known_tasks_ids}/{len(self.task_strong_ids)} tasks...\"\n        max_errors = self.collection_options.max_errors\n        max_shots = self.collection_options.max_shots\n\n        tasks_left = 0\n        lines = []\n        skipped_lines = []\n        for k, strong_id in enumerate(self.task_strong_ids):\n            if strong_id not in self.task_states:\n                continue\n            c = self.total_collected.get(strong_id, AnonTaskStats())\n            tasks_left += 1\n            w = len(self.task_states[strong_id].workers_assigned)\n            dt = None\n            if max_shots is not None and c.shots:\n                dt = (max_shots - c.shots) * c.seconds / c.shots\n            c_errors = c.custom_counts[self.custom_error_count_key] if self.custom_error_count_key is not None else c.errors\n            if max_errors is not None and c_errors and c.seconds:\n                dt2 = (max_errors - c_errors) * c.seconds / c_errors\n                if dt is None:\n                    dt = dt2\n                else:\n                    dt = min(dt, dt2)\n            if dt is not None:\n                dt /= 60\n            if dt is not None and w > 0:\n                dt /= w\n            line = [\n                f'{w}',\n                self.partial_tasks[k].decoder,\n                (\"?\" if dt is None or dt == 0 else \"[draining]\" if dt <= 0 else \"<1m\" if dt < 1 else str(round(dt)) + 'm') + ('·∞' if w == 0 else ''),\n                f'{max_shots - c.shots}' if max_shots is not None else f'{c.shots}',\n                f'{max_errors - c_errors}' if max_errors is not None else f'{c_errors}',\n                \",\".join(\n                    [f\"{k}={v}\" for k, v in self.partial_tasks[k].json_metadata.items()]\n                    if isinstance(self.partial_tasks[k].json_metadata, dict)\n                    else str(self.partial_tasks[k].json_metadata)\n                )\n            ]\n            if w == 0:\n                skipped_lines.append(line)\n            else:\n                lines.append(line)\n        if len(lines) < 50 and skipped_lines:\n            missing_lines = 50 - len(lines)\n            lines.extend(skipped_lines[:missing_lines])\n            skipped_lines = skipped_lines[missing_lines:]\n\n        if lines:\n            lines.insert(0, [\n                'workers',\n                'decoder',\n                'eta',\n                'shots_left' if max_shots is not None else 'shots_taken',\n                'errors_left' if max_errors is not None else 'errors_seen',\n                'json_metadata'])\n            justs = cast(list[Callable[[str, int], str]], [str.rjust, str.rjust, str.rjust, str.rjust, str.rjust, str.ljust])\n            cols = len(lines[0])\n            lengths = [\n                max(len(lines[row][col]) for row in range(len(lines)))\n                for col in range(cols)\n            ]\n            lines = [\n                \"  \" + \" \".join(justs[col](row[col], lengths[col]) for col in range(cols))\n                for row in lines\n            ]\n        if skipped_lines:\n            lines.append('        ... (' + str(len(skipped_lines)) + ' more tasks) ...')\n        return f'{tasks_left} tasks left:\\n' + '\\n'.join(lines)\n\n    def _update_soft_error_threshold_for_a_job(self, task_state: _ManagedTaskState):\n        if task_state.errors_left <= len(task_state.workers_assigned):\n            desired_threshold = 1\n        elif task_state.errors_left <= task_state.assigned_soft_error_flush_threshold * self.num_workers:\n            desired_threshold = max(1, math.ceil(task_state.errors_left * 0.5 / self.num_workers))\n        else:\n            return\n\n        if task_state.assigned_soft_error_flush_threshold != desired_threshold:\n            task_state.assigned_soft_error_flush_threshold = desired_threshold\n            for wid in task_state.workers_assigned:\n                self.worker_states[wid].send_message(('set_soft_error_flush_threshold', desired_threshold))\n\n    def _take_work_if_unsatisfied_workers_within_a_job(self, task_state: _ManagedTaskState):\n        if not self.started or not task_state.workers_assigned or task_state.shots_left <= 0:\n            return\n\n        if all(self.worker_states[w].assigned_shots > 0 for w in task_state.workers_assigned):\n            return\n\n        w = len(task_state.workers_assigned)\n        expected_shots_per_worker = (task_state.shots_left + w - 1) // w\n\n        # There are idle workers that couldn't be given any shots. Take shots from other workers.\n        for worker_id in sorted(task_state.workers_assigned, key=lambda w: self.worker_states[w].assigned_shots, reverse=True):\n            worker_state = self.worker_states[worker_id]\n            if worker_state.asked_to_drop_shots or worker_state.assigned_shots <= expected_shots_per_worker:\n                continue\n            shots_to_take = worker_state.assigned_shots - expected_shots_per_worker\n            assert shots_to_take > 0\n            worker_state.asked_to_drop_shots = shots_to_take\n            task_state.shot_return_requests += 1\n            worker_state.send_message((\n                'return_shots',\n                (\n                    task_state.strong_id,\n                    shots_to_take,\n                ),\n            ))\n\n    def _distribute_work_within_a_job(self, t: _ManagedTaskState):\n        self._distribute_unassigned_work_to_workers_within_a_job(t)\n        self._take_work_if_unsatisfied_workers_within_a_job(t)\n\n    def _distribute_work(self):\n        self._distribute_unassigned_workers_to_jobs()\n        for w in self.task_states.values():\n            if not w.is_completed():\n                self._distribute_work_within_a_job(w)\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_collection_manager_test.py",
    "content": "import multiprocessing\nimport time\nfrom typing import Any, List, Union\n\nimport sinter\nimport stim\n\nfrom sinter._collection._collection_manager import CollectionManager\n\n\ndef _assert_drain_queue(q: multiprocessing.Queue, expected_contents: List[Any]):\n    for v in expected_contents:\n        assert q.get(timeout=0.1) == v\n    if not q.empty():\n        assert False, f'queue had another item: {q.get()=}'\n\n\ndef _put_wait_not_empty(q: Union[multiprocessing.Queue, multiprocessing.SimpleQueue], item: Any):\n    q.put(item)\n    while q.empty():\n        time.sleep(0.0001)\n\n\ndef test_manager():\n    log = []\n    t0 = sinter.Task(\n        circuit=stim.Circuit('H 0'),\n        detector_error_model=stim.DetectorErrorModel(),\n        decoder='fusion_blossom',\n        collection_options=sinter.CollectionOptions(max_shots=100_000_000, max_errors=100),\n        json_metadata={'a': 3},\n    )\n    t1 = sinter.Task(\n        circuit=stim.Circuit('M 0'),\n        detector_error_model=stim.DetectorErrorModel(),\n        decoder='pymatching',\n        collection_options=sinter.CollectionOptions(max_shots=10_000_000),\n        json_metadata=None,\n    )\n    manager = CollectionManager(\n        num_workers=3,\n        worker_flush_period=30,\n        tasks=[t0, t1],\n        progress_callback=log.append,\n        existing_data={},\n        collection_options=sinter.CollectionOptions(),\n        custom_decoders={},\n        allowed_cpu_affinity_ids=None,\n    )\n\n    assert manager.state_summary() == \"\"\"\nworker 0: asked_to_drop_shots=0 assigned_shots=0 assigned_work_key=None\nworker 1: asked_to_drop_shots=0 assigned_shots=0 assigned_work_key=None\nworker 2: asked_to_drop_shots=0 assigned_shots=0 assigned_work_key=None\n\"\"\"\n\n    manager.start_workers(actually_start_worker_processes=False)\n    manager.shared_worker_output_queue.put(('computed_strong_id', 2, 'c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa'))\n    manager.shared_worker_output_queue.put(('computed_strong_id', 1, 'a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604'))\n    manager.start_distributing_work()\n\n    assert manager.state_summary() == \"\"\"\nworker 0: asked_to_drop_shots=0 assigned_shots=100000000 assigned_work_key=a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604\nworker 1: asked_to_drop_shots=0 assigned_shots=5000000 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\nworker 2: asked_to_drop_shots=0 assigned_shots=5000000 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\ntask task.strong_id='a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604':\n    workers_assigned=[0]\n    shot_return_requests=0\n    shots_left=100000000\n    errors_left=100\n    shots_unassigned=0\ntask task.strong_id='c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa':\n    workers_assigned=[1, 2]\n    shot_return_requests=0\n    shots_left=10000000\n    errors_left=10000000\n    shots_unassigned=0\n\"\"\"\n\n    _assert_drain_queue(manager.worker_states[0].input_queue, [\n        (\n            'change_job',\n            (t0, sinter.CollectionOptions(max_errors=100), 100),\n        ),\n        (\n            'accept_shots',\n            (t0.strong_id(), 100_000_000),\n        ),\n    ])\n    _assert_drain_queue(manager.worker_states[1].input_queue, [\n        ('compute_strong_id', t0),\n        (\n            'change_job',\n            (t1, sinter.CollectionOptions(max_errors=10000000), 10000000),\n        ),\n        (\n            'accept_shots',\n            (t1.strong_id(), 5_000_000),\n        ),\n    ])\n    _assert_drain_queue(manager.worker_states[2].input_queue, [\n        ('compute_strong_id', t1),\n        (\n            'change_job',\n            (t1, sinter.CollectionOptions(max_errors=10000000), 10000000),\n        ),\n        (\n            'accept_shots',\n            (t1.strong_id(), 5_000_000),\n        ),\n    ])\n\n    assert manager.shared_worker_output_queue.empty()\n    assert log.pop() is None\n    assert log.pop() is None\n    assert not log\n    _put_wait_not_empty(manager.shared_worker_output_queue, (\n        'flushed_results',\n        2,\n        (t1.strong_id(), sinter.AnonTaskStats(\n            shots=5_000_000,\n            errors=123,\n            discards=0,\n            seconds=1,\n        )),\n    ))\n\n    assert manager.process_message()\n    assert manager.state_summary() == \"\"\"\nworker 0: asked_to_drop_shots=0 assigned_shots=100000000 assigned_work_key=a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604\nworker 1: asked_to_drop_shots=2500000 assigned_shots=5000000 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\nworker 2: asked_to_drop_shots=0 assigned_shots=0 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\ntask task.strong_id='a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604':\n    workers_assigned=[0]\n    shot_return_requests=0\n    shots_left=100000000\n    errors_left=100\n    shots_unassigned=0\ntask task.strong_id='c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa':\n    workers_assigned=[1, 2]\n    shot_return_requests=1\n    shots_left=5000000\n    errors_left=9999877\n    shots_unassigned=0\n\"\"\"\n\n    assert log.pop() == sinter.TaskStats(\n        strong_id=t1.strong_id(),\n        decoder=t1.decoder,\n        json_metadata=t1.json_metadata,\n        shots=5_000_000,\n        errors=123,\n        discards=0,\n        seconds=1,\n    )\n    assert not log\n\n    _assert_drain_queue(manager.worker_states[0].input_queue, [])\n    _assert_drain_queue(manager.worker_states[1].input_queue, [\n        (\n            'return_shots',\n            (t1.strong_id(), 2_500_000),\n        ),\n    ])\n    _assert_drain_queue(manager.worker_states[2].input_queue, [])\n\n    _put_wait_not_empty(manager.shared_worker_output_queue, (\n        'returned_shots',\n        1,\n        (t1.strong_id(), 2_000_000),\n    ))\n    assert manager.process_message()\n    assert manager.state_summary() == \"\"\"\nworker 0: asked_to_drop_shots=0 assigned_shots=100000000 assigned_work_key=a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604\nworker 1: asked_to_drop_shots=0 assigned_shots=3000000 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\nworker 2: asked_to_drop_shots=0 assigned_shots=2000000 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\ntask task.strong_id='a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604':\n    workers_assigned=[0]\n    shot_return_requests=0\n    shots_left=100000000\n    errors_left=100\n    shots_unassigned=0\ntask task.strong_id='c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa':\n    workers_assigned=[1, 2]\n    shot_return_requests=0\n    shots_left=5000000\n    errors_left=9999877\n    shots_unassigned=0\n\"\"\"\n\n    _assert_drain_queue(manager.worker_states[0].input_queue, [])\n    _assert_drain_queue(manager.worker_states[1].input_queue, [])\n    _assert_drain_queue(manager.worker_states[2].input_queue, [\n        (\n            'accept_shots',\n            (t1.strong_id(), 2_000_000),\n        ),\n    ])\n\n    _put_wait_not_empty(manager.shared_worker_output_queue, (\n        'flushed_results',\n        1,\n        (t1.strong_id(), sinter.AnonTaskStats(\n            shots=3_000_000,\n            errors=444,\n            discards=1,\n            seconds=2,\n        ))\n    ))\n    assert manager.process_message()\n    assert manager.state_summary() == \"\"\"\nworker 0: asked_to_drop_shots=0 assigned_shots=100000000 assigned_work_key=a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604\nworker 1: asked_to_drop_shots=0 assigned_shots=0 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\nworker 2: asked_to_drop_shots=1000000 assigned_shots=2000000 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\ntask task.strong_id='a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604':\n    workers_assigned=[0]\n    shot_return_requests=0\n    shots_left=100000000\n    errors_left=100\n    shots_unassigned=0\ntask task.strong_id='c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa':\n    workers_assigned=[1, 2]\n    shot_return_requests=1\n    shots_left=2000000\n    errors_left=9999433\n    shots_unassigned=0\n\"\"\"\n\n    _put_wait_not_empty(manager.shared_worker_output_queue, (\n        'flushed_results',\n        2,\n        (t1.strong_id(), sinter.AnonTaskStats(\n            shots=2_000_000,\n            errors=555,\n            discards=2,\n            seconds=2.5,\n        ))\n    ))\n    assert manager.process_message()\n    assert manager.state_summary() == \"\"\"\nworker 0: asked_to_drop_shots=0 assigned_shots=100000000 assigned_work_key=a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604\nworker 1: asked_to_drop_shots=0 assigned_shots=0 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\nworker 2: asked_to_drop_shots=1000000 assigned_shots=0 assigned_work_key=c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa\ntask task.strong_id='a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604':\n    workers_assigned=[0]\n    shot_return_requests=0\n    shots_left=100000000\n    errors_left=100\n    shots_unassigned=0\ntask task.strong_id='c03f7852e4579e2a99cefac80eeb6b09556907540ab3d7787a3d07309c3333aa':\n    workers_assigned=[1, 2]\n    shot_return_requests=1\n    shots_left=0\n    errors_left=9998878\n    shots_unassigned=0\n\"\"\"\n\n    assert manager.shared_worker_output_queue.empty()\n    _put_wait_not_empty(manager.shared_worker_output_queue, (\n        'returned_shots',\n        2,\n        (t1.strong_id(), 0)\n    ))\n    assert manager.process_message()\n    assert manager.shared_worker_output_queue.empty()\n    assert manager.state_summary() == \"\"\"\nworker 0: asked_to_drop_shots=66666666 assigned_shots=100000000 assigned_work_key=a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604\nworker 1: asked_to_drop_shots=0 assigned_shots=0 assigned_work_key=a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604\nworker 2: asked_to_drop_shots=0 assigned_shots=0 assigned_work_key=a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604\ntask task.strong_id='a9165b6e4ab1053c04c017d0739a7bfff0910d62091fc9ee81716833eda7f604':\n    workers_assigned=[0, 1, 2]\n    shot_return_requests=1\n    shots_left=100000000\n    errors_left=100\n    shots_unassigned=0\n\"\"\"\n\n    _assert_drain_queue(manager.worker_states[0].input_queue, [\n        ('return_shots', (t0.strong_id(), 66666666)),\n    ])\n    _assert_drain_queue(manager.worker_states[1].input_queue, [\n        ('change_job', (t0, sinter.CollectionOptions(max_errors=100), 100)),\n    ])\n    _assert_drain_queue(manager.worker_states[2].input_queue, [\n        ('return_shots', (t1.strong_id(), 1000000)),\n        ('change_job', (t0, sinter.CollectionOptions(max_errors=100), 100)),\n    ])\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_collection_test.py",
    "content": "import collections\nimport multiprocessing\nimport pathlib\nimport tempfile\nimport time\n\nimport pytest\n\nimport sinter\nimport stim\n\n\ndef test_iter_collect():\n    result = collections.defaultdict(sinter.AnonTaskStats)\n    for sample in sinter.iter_collect(\n        num_workers=2,\n        tasks=[\n            sinter.Task(\n                circuit=stim.Circuit.generated(\n                    'repetition_code:memory',\n                    rounds=3,\n                    distance=3,\n                    after_clifford_depolarization=p),\n                decoder='pymatching',\n                json_metadata={'p': p},\n                collection_options=sinter.CollectionOptions(\n                    max_shots=1000,\n                    max_errors=100,\n                    start_batch_size=100,\n                    max_batch_size=1000,\n                ),\n            )\n            for p in [0.01, 0.02, 0.03, 0.04]\n        ],\n    ):\n        for stats in sample.new_stats:\n            result[stats.json_metadata['p']] += stats.to_anon_stats()\n    assert len(result) == 4\n    for k, v in result.items():\n        assert v.shots >= 1000 or v.errors >= 100\n        assert v.discards == 0\n    assert result[0.01].errors <= 10\n    assert result[0.02].errors <= 30\n    assert result[0.03].errors <= 70\n    assert 1 <= result[0.04].errors <= 100\n\n\ndef test_collect():\n    results = sinter.collect(\n        num_workers=2,\n        tasks=[\n            sinter.Task(\n                circuit=stim.Circuit.generated(\n                    'repetition_code:memory',\n                    rounds=3,\n                    distance=3,\n                    after_clifford_depolarization=p),\n                decoder='pymatching',\n                json_metadata={'p': p},\n                collection_options=sinter.CollectionOptions(\n                    max_shots=1000,\n                    max_errors=100,\n                    start_batch_size=100,\n                    max_batch_size=1000,\n                ),\n            )\n            for p in [0.01, 0.02, 0.03, 0.04]\n        ]\n    )\n    probabilities = [e.json_metadata['p'] for e in results]\n    assert len(probabilities) == len(set(probabilities))\n    d = {e.json_metadata['p']: e for e in results}\n    assert len(d) == 4\n    for k, v in d.items():\n        assert v.shots >= 1000 or v.errors >= 100\n        assert v.discards == 0\n    assert d[0.01].errors <= 10\n    assert d[0.02].errors <= 30\n    assert d[0.03].errors <= 70\n    assert 1 <= d[0.04].errors <= 100\n\n\ndef test_collect_from_paths():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        tasks = []\n        for p in [0.01, 0.02, 0.03, 0.04]:\n            path = d / f'tmp{p}.stim'\n            stim.Circuit.generated(\n                'repetition_code:memory',\n                rounds=3,\n                distance=3,\n                after_clifford_depolarization=p,\n            ).to_file(path)\n            tasks.append(sinter.Task(\n                circuit_path=path,\n                decoder='pymatching',\n                json_metadata={'p': p},\n                collection_options=sinter.CollectionOptions(\n                    max_shots=1000,\n                    max_errors=100,\n                    start_batch_size=100,\n                    max_batch_size=1000,\n                ),\n            ))\n\n        results = sinter.collect(\n            num_workers=2,\n            tasks=tasks\n        )\n    probabilities = [e.json_metadata['p'] for e in results]\n    assert len(probabilities) == len(set(probabilities))\n    d = {e.json_metadata['p']: e for e in results}\n    assert len(d) == 4\n    for k, v in d.items():\n        assert v.shots >= 1000 or v.errors >= 100\n        assert v.discards == 0\n    assert d[0.01].errors <= 10\n    assert d[0.02].errors <= 30\n    assert d[0.03].errors <= 70\n    assert 1 <= d[0.04].errors <= 100\n\n\nclass AlternatingPredictionsDecoder(sinter.Decoder):\n    def decode_via_files(self,\n                         *,\n                         num_shots: int,\n                         num_dets: int,\n                         num_obs: int,\n                         dem_path: pathlib.Path,\n                         dets_b8_in_path: pathlib.Path,\n                         obs_predictions_b8_out_path: pathlib.Path,\n                         tmp_dir: pathlib.Path,\n                       ) -> None:\n        bytes_per_shot = (num_obs + 7) // 8\n        with open(obs_predictions_b8_out_path, 'wb') as f:\n            for k in range(num_shots):\n                f.write((k % 3 == 0).to_bytes(length=bytes_per_shot, byteorder='little'))\n\n\ndef test_collect_custom_decoder():\n    results = sinter.collect(\n        num_workers=2,\n        tasks=[\n            sinter.Task(\n                circuit=stim.Circuit(\"\"\"\n                    M(0.1) 0\n                    DETECTOR rec[-1]\n                    OBSERVABLE_INCLUDE(0) rec[-1]\n                \"\"\"),\n                json_metadata=None,\n            )\n        ],\n        max_shots=10000,\n        decoders=['alternate'],\n        custom_decoders={'alternate': AlternatingPredictionsDecoder()},\n    )\n    assert len(results) == 1\n    assert results[0].shots == 10000\n    assert 2500 < results[0].errors < 4000\n\n\ndef test_iter_collect_list():\n    result = collections.defaultdict(sinter.AnonTaskStats)\n    for sample in sinter.iter_collect(\n        num_workers=2,\n        tasks=[\n            sinter.Task(\n                circuit=stim.Circuit.generated(\n                    'repetition_code:memory',\n                    rounds=3,\n                    distance=3,\n                    after_clifford_depolarization=p),\n                decoder='pymatching',\n                json_metadata={'p': p},\n                collection_options=sinter.CollectionOptions(\n                    max_errors=100,\n                    max_shots=1000,\n                    start_batch_size=100,\n                    max_batch_size=1000,\n                ),\n            )\n            for p in [0.01, 0.02, 0.03, 0.04]\n        ],\n    ):\n        for stats in sample.new_stats:\n            result[stats.json_metadata['p']] += stats.to_anon_stats()\n    assert len(result) == 4\n    for k, v in result.items():\n        assert v.shots >= 1000 or v.errors >= 100\n        assert v.discards == 0\n    assert result[0.01].errors <= 10\n    assert result[0.02].errors <= 30\n    assert result[0.03].errors <= 70\n    assert 1 <= result[0.04].errors <= 100\n\n\ndef test_iter_collect_worker_fails():\n    with pytest.raises(RuntimeError, match=\"Worker failed\"):\n        _ = list(sinter.iter_collect(\n            decoders=['NOT A VALID DECODER'],\n            num_workers=1,\n            tasks=iter([\n                sinter.Task(\n                    circuit=stim.Circuit.generated('repetition_code:memory', rounds=3, distance=3),\n                    collection_options=sinter.CollectionOptions(\n                        max_errors=1,\n                        max_shots=1,\n                    ),\n                ),\n            ]),\n        ))\n\n\nclass FixedSizeSampler(sinter.Sampler, sinter.CompiledSampler):\n    def compiled_sampler_for_task(self, task: sinter.Task) -> sinter.CompiledSampler:\n        return self\n\n    def sample(self, suggested_shots: int) -> 'sinter.AnonTaskStats':\n        return sinter.AnonTaskStats(\n            shots=1024,\n            errors=5,\n        )\n\n\ndef test_fixed_size_sampler():\n    results = sinter.collect(\n        num_workers=2,\n        tasks=[\n            sinter.Task(\n                circuit=stim.Circuit(),\n                decoder='fixed_size_sampler',\n                json_metadata={},\n                collection_options=sinter.CollectionOptions(\n                    max_shots=100_000,\n                    max_errors=1_000,\n                ),\n            )\n        ],\n        custom_decoders={'fixed_size_sampler': FixedSizeSampler()}\n    )\n    assert 100_000 <= results[0].shots <= 100_000 + 3000\n\n\nclass MockTimingSampler(sinter.Sampler, sinter.CompiledSampler):\n    def compiled_sampler_for_task(self, task: sinter.Task) -> sinter.CompiledSampler:\n        return self\n\n    def sample(self, suggested_shots: int) -> 'sinter.AnonTaskStats':\n        actual_shots = -(-suggested_shots // 1024) * 1024\n        time.sleep(actual_shots * 0.00001)\n        return sinter.AnonTaskStats(\n            shots=actual_shots,\n            errors=5,\n            seconds=actual_shots * 0.00001,\n        )\n\n\ndef test_mock_timing_sampler():\n    results = sinter.collect(\n        num_workers=12,\n        tasks=[\n            sinter.Task(\n                circuit=stim.Circuit(),\n                decoder='MockTimingSampler',\n                json_metadata={},\n            )\n        ],\n        max_shots=1_000_000,\n        max_errors=10_000,\n        custom_decoders={'MockTimingSampler': MockTimingSampler()},\n    )\n    assert 1_000_000 <= results[0].shots <= 1_000_000 + 12000\n\nclass BatchSizeTrackingSampler(sinter.Sampler, sinter.CompiledSampler):\n    \"\"\"A sampler that tracks the suggested batch size requests it receives.\"\"\"\n\n    def __init__(self, batch_sizes: list[int]):\n        self.batch_sizes = batch_sizes\n\n    def compiled_sampler_for_task(self, task: sinter.Task) -> sinter.CompiledSampler:\n        return self\n\n    def sample(self, suggested_shots: int) -> sinter.AnonTaskStats:\n        self.batch_sizes.append(suggested_shots)\n        return sinter.AnonTaskStats(\n            shots=suggested_shots,\n            errors=1,\n            seconds=0.001,\n        )\n\n\ndef test_ramp_throttled_sampler_respects_max_batch_size():\n    \"\"\"Test that the CollectionManager instantiated RampThrottledSampler respects the `max_batch_size`\n    parameter.\"\"\"\n\n    # since the RampThrottledSampler and batch sizing happens in the worker process, we need a\n    # shared list to track what goes on with the sampler\n    with multiprocessing.Manager() as manager:\n        tracking_sampler = BatchSizeTrackingSampler(manager.list())\n\n        sinter.collect(\n            num_workers=1,\n            tasks=[\n                sinter.Task(\n                    circuit=stim.Circuit(),\n                    decoder='tracking_sampler',\n                    json_metadata={'test': 'small_batch'},\n                )\n            ],\n            max_shots=10_000,\n            max_batch_size=128,  # Set a small max batch size\n            custom_decoders={'tracking_sampler': tracking_sampler},\n        )\n        # batch size should start at one and then maximum seen should be at most 128\n        assert tracking_sampler.batch_sizes[0] == 1\n        assert 1 < max(tracking_sampler.batch_sizes) <= 128\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_collection_worker_loop.py",
    "content": "import os\nfrom typing import Optional, TYPE_CHECKING\n\nfrom sinter._decoding import Sampler\nfrom sinter._collection._collection_worker_state import CollectionWorkerState\n\nif TYPE_CHECKING:\n    import multiprocessing\n\n\ndef collection_worker_loop(\n    flush_period: float,\n    worker_id: int,\n    sampler: Sampler,\n    inp: 'multiprocessing.Queue',\n    out: 'multiprocessing.Queue',\n    core_affinity: Optional[int],\n    custom_error_count_key: Optional[str],\n) -> None:\n    try:\n        if core_affinity is not None and hasattr(os, 'sched_setaffinity'):\n            os.sched_setaffinity(0, {core_affinity})\n    except:\n        # If setting the core affinity fails, we keep going regardless.\n        pass\n\n    worker = CollectionWorkerState(\n        flush_period=flush_period,\n        worker_id=worker_id,\n        sampler=sampler,\n        inp=inp,\n        out=out,\n        custom_error_count_key=custom_error_count_key,\n    )\n    worker.run_message_loop()\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_collection_worker_state.py",
    "content": "import queue\nimport time\nfrom typing import Any\nfrom typing import Optional\nfrom typing import TYPE_CHECKING\n\nimport stim\n\nfrom sinter._data import AnonTaskStats\nfrom sinter._data import CollectionOptions\nfrom sinter._data import Task\nfrom sinter._decoding import CompiledSampler\nfrom sinter._decoding import Sampler\n\nif TYPE_CHECKING:\n    import multiprocessing\n\n\ndef _fill_in_task(task: Task) -> Task:\n    changed = False\n    circuit = task.circuit\n    if circuit is None:\n        circuit = stim.Circuit.from_file(task.circuit_path)\n        changed = True\n    dem = task.detector_error_model\n    if dem is None:\n        try:\n            dem = circuit.detector_error_model(decompose_errors=True, approximate_disjoint_errors=True)\n        except ValueError:\n            try:\n                dem = circuit.detector_error_model(approximate_disjoint_errors=True)\n            except ValueError:\n                dem = circuit.detector_error_model(approximate_disjoint_errors=True, flatten_loops=True)\n        changed = True\n    if not changed:\n        return task\n    return Task(\n        circuit=circuit,\n        decoder=task.decoder,\n        detector_error_model=dem,\n        postselection_mask=task.postselection_mask,\n        postselected_observables_mask=task.postselected_observables_mask,\n        json_metadata=task.json_metadata,\n        collection_options=task.collection_options,\n    )\n\n\nclass CollectionWorkerState:\n    def __init__(\n            self,\n            *,\n            flush_period: float,\n            worker_id: int,\n            inp: 'multiprocessing.Queue',\n            out: 'multiprocessing.Queue',\n            sampler: Sampler,\n            custom_error_count_key: Optional[str],\n    ):\n        assert isinstance(flush_period, (int, float))\n        assert isinstance(sampler, Sampler)\n        self.max_flush_period = flush_period\n        self.cur_flush_period = 0.01\n        self.inp = inp\n        self.out = out\n        self.sampler = sampler\n        self.compiled_sampler: CompiledSampler | None = None\n        self.worker_id = worker_id\n\n        self.current_task: Task | None = None\n        self.current_error_cutoff: int | None = None\n        self.custom_error_count_key = custom_error_count_key\n        self.current_task_shots_left: int = 0\n        self.unflushed_results: AnonTaskStats = AnonTaskStats()\n        self.last_flush_message_time = time.monotonic()\n        self.soft_error_flush_threshold: int = 1\n\n    def _send_message_to_manager(self, message: Any):\n        self.out.put(message)\n\n    def state_summary(self) -> str:\n        lines = [\n            f'Worker(id={self.worker_id}) [',\n            f'    max_flush_period={self.max_flush_period}',\n            f'    cur_flush_period={self.cur_flush_period}',\n            f'    sampler={self.sampler}',\n            f'    compiled_sampler={self.compiled_sampler}',\n            f'    current_task={self.current_task}',\n            f'    current_error_cutoff={self.current_error_cutoff}',\n            f'    custom_error_count_key={self.custom_error_count_key}',\n            f'    current_task_shots_left={self.current_task_shots_left}',\n            f'    unflushed_results={self.unflushed_results}',\n            f'    last_flush_message_time={self.last_flush_message_time}',\n            f'    soft_error_flush_threshold={self.soft_error_flush_threshold}',\n            f']',\n        ]\n        return '\\n' + '\\n'.join(lines) + '\\n'\n\n    def flush_results(self):\n        if self.unflushed_results.shots > 0:\n            self.last_flush_message_time = time.monotonic()\n            self.cur_flush_period = min(self.cur_flush_period * 1.4, self.max_flush_period)\n            self._send_message_to_manager((\n                'flushed_results',\n                self.worker_id,\n                (self.current_task.strong_id(), self.unflushed_results),\n            ))\n            self.unflushed_results = AnonTaskStats()\n            return True\n        return False\n\n    def accept_shots(self, *, shots_delta: int):\n        assert shots_delta >= 0\n        self.current_task_shots_left += shots_delta\n        self._send_message_to_manager((\n            'accepted_shots',\n            self.worker_id,\n            (self.current_task.strong_id(), shots_delta),\n        ))\n\n    def return_shots(self, *, requested_shots: int):\n        assert requested_shots >= 0\n        returned_shots = max(0, min(requested_shots, self.current_task_shots_left))\n        self.current_task_shots_left -= returned_shots\n        if self.current_task_shots_left <= 0:\n            self.flush_results()\n        self._send_message_to_manager((\n            'returned_shots',\n            self.worker_id,\n            (self.current_task.strong_id(), returned_shots),\n        ))\n\n    def compute_strong_id(self, *, new_task: Task):\n        strong_id = _fill_in_task(new_task).strong_id()\n        self._send_message_to_manager((\n            'computed_strong_id',\n            self.worker_id,\n            strong_id,\n        ))\n\n    def change_job(self, *, new_task: Task, new_collection_options: CollectionOptions):\n        self.flush_results()\n\n        self.current_task = _fill_in_task(new_task)\n        self.current_error_cutoff = new_collection_options.max_errors\n        self.compiled_sampler = self.sampler.compiled_sampler_for_task(self.current_task)\n        assert self.current_task.strong_id() is not None\n        self.current_task_shots_left = 0\n        self.last_flush_message_time = time.monotonic()\n\n        self._send_message_to_manager((\n            'changed_job',\n            self.worker_id,\n            (self.current_task.strong_id(),),\n        ))\n\n    def process_messages(self) -> int:\n        num_processed = 0\n        while True:\n            try:\n                message = self.inp.get_nowait()\n            except queue.Empty:\n                return num_processed\n\n            num_processed += 1\n            message_type, message_body = message\n\n            if message_type == 'stop':\n                return -1\n\n            elif message_type == 'flush_results':\n                self.flush_results()\n\n            elif message_type == 'compute_strong_id':\n                assert isinstance(message_body, Task)\n                self.compute_strong_id(new_task=message_body)\n\n            elif message_type == 'change_job':\n                new_task, new_collection_options, soft_error_flush_threshold = message_body\n                self.cur_flush_period = 0.01\n                self.soft_error_flush_threshold = soft_error_flush_threshold\n                assert isinstance(new_task, Task)\n                self.change_job(new_task=new_task, new_collection_options=new_collection_options)\n\n            elif message_type == 'set_soft_error_flush_threshold':\n                soft_error_flush_threshold = message_body\n                self.soft_error_flush_threshold = soft_error_flush_threshold\n\n            elif message_type == 'accept_shots':\n                job_key, shots_delta = message_body\n                assert isinstance(shots_delta, int)\n                assert job_key == self.current_task.strong_id()\n                self.accept_shots(shots_delta=shots_delta)\n\n            elif message_type == 'return_shots':\n                job_key, requested_shots = message_body\n                assert isinstance(requested_shots, int)\n                assert job_key == self.current_task.strong_id()\n                self.return_shots(requested_shots=requested_shots)\n\n            else:\n                raise NotImplementedError(f'{message_type=}')\n\n    def num_unflushed_errors(self) -> int:\n        if self.custom_error_count_key is not None:\n            return self.unflushed_results.custom_counts[self.custom_error_count_key]\n        return self.unflushed_results.errors\n\n    def do_some_work(self) -> bool:\n        did_some_work = False\n\n        # Sample some stats.\n        if self.current_task_shots_left > 0:\n            # Don't keep sampling if we've exceeded the number of errors needed.\n            if self.current_error_cutoff is not None and self.current_error_cutoff <= 0:\n                return self.flush_results()\n\n            some_work_done = self.compiled_sampler.sample(self.current_task_shots_left)\n            if some_work_done.shots < 1:\n                raise ValueError(f\"Sampler didn't do any work. It returned statistics with shots == 0: {some_work_done}.\")\n            assert isinstance(some_work_done, AnonTaskStats)\n            self.current_task_shots_left -= some_work_done.shots\n            if self.current_error_cutoff is not None:\n                errors_done = some_work_done.custom_counts[self.custom_error_count_key] if self.custom_error_count_key is not None else some_work_done.errors\n                self.current_error_cutoff -= errors_done\n            self.unflushed_results += some_work_done\n            did_some_work = True\n\n        # Report them periodically.\n        should_flush = False\n        if self.num_unflushed_errors() >= self.soft_error_flush_threshold:\n            should_flush = True\n        if self.unflushed_results.shots > 0:\n            if self.current_task_shots_left <= 0 or self.last_flush_message_time + self.cur_flush_period < time.monotonic():\n                should_flush = True\n        if should_flush:\n            did_some_work |= self.flush_results()\n\n        return did_some_work\n\n    def run_message_loop(self):\n        try:\n            while True:\n                num_messages_processed = self.process_messages()\n                if num_messages_processed == -1:\n                    break\n                did_some_work = self.do_some_work()\n                if not did_some_work and num_messages_processed == 0:\n                    time.sleep(0.01)\n\n        except KeyboardInterrupt:\n            pass\n\n        except BaseException as ex:\n            import traceback\n            self._send_message_to_manager((\n                'stopped_due_to_exception',\n                self.worker_id,\n                (None if self.current_task is None else self.current_task.strong_id(), self.current_task_shots_left, self.unflushed_results, traceback.format_exc(), ex),\n            ))\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_collection_worker_test.py",
    "content": "import collections\nimport multiprocessing\nimport time\nfrom typing import Any, List\n\nimport sinter\nimport stim\n\nfrom sinter._collection._collection_worker_state import CollectionWorkerState\n\n\nclass MockWorkHandler(sinter.Sampler, sinter.CompiledSampler):\n    def __init__(self):\n        self.expected_task = None\n        self.expected = collections.deque()\n\n    def compiled_sampler_for_task(self, task: sinter.Task) -> sinter.CompiledSampler:\n        assert task == self.expected_task\n        return self\n\n    def handles_throttling(self) -> bool:\n        return True\n\n    def sample(self, shots: int) -> sinter.AnonTaskStats:\n        assert self.expected\n        expected_shots, response = self.expected.popleft()\n        assert shots == expected_shots\n        return response\n\n\ndef _assert_drain_queue(q: multiprocessing.Queue, expected_contents: List[Any]):\n    for v in expected_contents:\n        assert q.get(timeout=0.1) == v\n    assert q.empty()\n\n\ndef _put_wait_not_empty(q: multiprocessing.Queue, item: Any):\n    q.put(item)\n    while q.empty():\n        time.sleep(0.0001)\n\n\ndef test_worker_stop():\n    handler = MockWorkHandler()\n\n    inp = multiprocessing.Queue()\n    out = multiprocessing.Queue()\n    inp.cancel_join_thread()\n    out.cancel_join_thread()\n\n    worker = CollectionWorkerState(\n        flush_period=-1,\n        worker_id=5,\n        sampler=handler,\n        inp=inp,\n        out=out,\n        custom_error_count_key=None,\n    )\n\n    assert worker.process_messages() == 0\n    _assert_drain_queue(out, [])\n\n    t0 = sinter.Task(\n        circuit=stim.Circuit('H 0'),\n        detector_error_model=stim.DetectorErrorModel(),\n        decoder='mock',\n        collection_options=sinter.CollectionOptions(max_shots=100_000_000),\n        json_metadata={'a': 3},\n    )\n    handler.expected_task = t0\n\n    _put_wait_not_empty(inp, ('change_job', (t0, sinter.CollectionOptions(max_errors=100_000_000), 100_000_000)))\n    assert worker.process_messages() == 1\n    _assert_drain_queue(out, [('changed_job', 5, (t0.strong_id(),))])\n\n    _put_wait_not_empty(inp, ('stop', None))\n    assert worker.process_messages() == -1\n\n\ndef test_worker_skip_work():\n    handler = MockWorkHandler()\n\n    inp = multiprocessing.Queue()\n    out = multiprocessing.Queue()\n    inp.cancel_join_thread()\n    out.cancel_join_thread()\n\n    worker = CollectionWorkerState(\n        flush_period=-1,\n        worker_id=5,\n        sampler=handler,\n        inp=inp,\n        out=out,\n        custom_error_count_key=None,\n    )\n\n    assert worker.process_messages() == 0\n    _assert_drain_queue(out, [])\n\n    t0 = sinter.Task(\n        circuit=stim.Circuit('H 0'),\n        detector_error_model=stim.DetectorErrorModel(),\n        decoder='mock',\n        collection_options=sinter.CollectionOptions(max_shots=100_000_000),\n        json_metadata={'a': 3},\n    )\n    handler.expected_task = t0\n    _put_wait_not_empty(inp, ('change_job', (t0, sinter.CollectionOptions(max_errors=100_000_000), 100_000_000)))\n    assert worker.process_messages() == 1\n    _assert_drain_queue(out, [('changed_job', 5, (t0.strong_id(),))])\n\n    _put_wait_not_empty(inp, ('accept_shots', (t0.strong_id(), 10000)))\n    assert worker.process_messages() == 1\n    _assert_drain_queue(out, [('accepted_shots', 5, (t0.strong_id(), 10000))])\n\n    assert worker.current_task == t0\n    assert worker.current_task_shots_left == 10000\n    assert worker.process_messages() == 0\n    _assert_drain_queue(out, [])\n\n    _put_wait_not_empty(inp, ('return_shots', (t0.strong_id(), 2000)))\n    assert worker.process_messages() == 1\n    _assert_drain_queue(out, [\n        ('returned_shots', 5, (t0.strong_id(), 2000)),\n    ])\n\n    _put_wait_not_empty(inp, ('return_shots', (t0.strong_id(), 20000000)))\n    assert worker.process_messages() == 1\n    _assert_drain_queue(out, [\n        ('returned_shots', 5, (t0.strong_id(), 8000)),\n    ])\n\n    assert not worker.do_some_work()\n\n\ndef test_worker_finish_work():\n    handler = MockWorkHandler()\n\n    inp = multiprocessing.Queue()\n    out = multiprocessing.Queue()\n    inp.cancel_join_thread()\n    out.cancel_join_thread()\n\n    worker = CollectionWorkerState(\n        flush_period=-1,\n        worker_id=5,\n        sampler=handler,\n        inp=inp,\n        out=out,\n        custom_error_count_key=None,\n    )\n\n    assert worker.process_messages() == 0\n    _assert_drain_queue(out, [])\n\n    ta = sinter.Task(\n        circuit=stim.Circuit('H 0'),\n        detector_error_model=stim.DetectorErrorModel(),\n        decoder='mock',\n        collection_options=sinter.CollectionOptions(max_shots=100_000_000),\n        json_metadata={'a': 3},\n    )\n    handler.expected_task = ta\n    _put_wait_not_empty(inp, ('change_job', (ta, sinter.CollectionOptions(max_errors=100_000_000), 100_000_000)))\n    _put_wait_not_empty(inp, ('accept_shots', (ta.strong_id(), 10000)))\n    t0 = time.monotonic()\n    num_processed = 0\n    while True:\n        num_processed += worker.process_messages()\n        if num_processed >= 2:\n            break\n        if time.monotonic() - t0 > 1:\n            raise ValueError(\"Messages not processed\")\n    assert num_processed == 2\n    _assert_drain_queue(out, [\n        ('changed_job', 5, (ta.strong_id(),)),\n        ('accepted_shots', 5, (ta.strong_id(), 10000)),\n    ])\n\n    assert worker.current_task == ta\n    assert worker.current_task_shots_left == 10000\n    assert worker.process_messages() == 0\n    _assert_drain_queue(out, [])\n\n    handler.expected.append((\n        10000,\n        sinter.AnonTaskStats(\n            shots=1000,\n            errors=23,\n            discards=0,\n            seconds=1,\n        ),\n    ))\n\n    assert worker.do_some_work()\n    worker.flush_results()\n    _assert_drain_queue(out, [\n        ('flushed_results', 5, (ta.strong_id(), sinter.AnonTaskStats(shots=1000, errors=23, discards=0, seconds=1)))])\n\n    handler.expected.append((\n        9000,\n        sinter.AnonTaskStats(\n            shots=9000,\n            errors=13,\n            discards=0,\n            seconds=1,\n        ),\n    ))\n\n    assert worker.do_some_work()\n    worker.flush_results()\n    _assert_drain_queue(out, [\n        ('flushed_results', 5, (ta.strong_id(), sinter.AnonTaskStats(\n            shots=9000,\n            errors=13,\n            discards=0,\n            seconds=1,\n        ))),\n    ])\n    assert not worker.do_some_work()\n    worker.flush_results()\n    _assert_drain_queue(out, [])\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_mux_sampler.py",
    "content": "import pathlib\nfrom typing import Optional\nfrom typing import Union\n\nfrom sinter._data import Task\nfrom sinter._decoding._decoding_all_built_in_decoders import BUILT_IN_SAMPLERS\nfrom sinter._decoding._decoding_decoder_class import Decoder\nfrom sinter._decoding._sampler import CompiledSampler\nfrom sinter._decoding._sampler import Sampler\nfrom sinter._decoding._stim_then_decode_sampler import StimThenDecodeSampler\n\n\nclass MuxSampler(Sampler):\n    \"\"\"Looks up the sampler to use for a task, by the task's decoder name.\"\"\"\n\n    def __init__(\n        self,\n        *,\n        custom_decoders: Union[dict[str, Union[Decoder, Sampler]], None],\n        count_observable_error_combos: bool,\n        count_detection_events: bool,\n        tmp_dir: Optional[pathlib.Path],\n    ):\n        self.custom_decoders = custom_decoders\n        self.count_observable_error_combos = count_observable_error_combos\n        self.count_detection_events = count_detection_events\n        self.tmp_dir = tmp_dir\n\n    def compiled_sampler_for_task(self, task: Task) -> CompiledSampler:\n        return self._resolve_sampler(task.decoder).compiled_sampler_for_task(task)\n\n    def _resolve_sampler(self, name: str) -> Sampler:\n        sub_sampler: Union[Decoder, Sampler]\n\n        if name in self.custom_decoders:\n            sub_sampler = self.custom_decoders[name]\n        elif name in BUILT_IN_SAMPLERS:\n            sub_sampler = BUILT_IN_SAMPLERS[name]\n        else:\n            raise NotImplementedError(f'Not a recognized decoder or sampler: {name=}. Did you forget to specify custom_decoders?')\n\n        if isinstance(sub_sampler, Sampler):\n            if self.count_detection_events:\n                raise NotImplementedError(\"'count_detection_events' not supported when using a custom Sampler (instead of a custom Decoder).\")\n            if self.count_observable_error_combos:\n                raise NotImplementedError(\"'count_observable_error_combos' not supported when using a custom Sampler (instead of a custom Decoder).\")\n            return sub_sampler\n        elif isinstance(sub_sampler, Decoder) or hasattr(sub_sampler, 'compile_decoder_for_dem'):\n            return StimThenDecodeSampler(\n                decoder=sub_sampler,\n                count_detection_events=self.count_detection_events,\n                count_observable_error_combos=self.count_observable_error_combos,\n                tmp_dir=self.tmp_dir,\n            )\n        else:\n            raise NotImplementedError(f\"Don't know how to turn this into a Sampler: {sub_sampler!r}\")\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_printer.py",
    "content": "import threading\nfrom typing import List, Any\n\nimport sys\nimport time\n\n\nclass ThrottledProgressPrinter:\n    \"\"\"Handles printing progress updates interspersed amongst output.\n\n    Throttles the progress updates to not flood the screen when 100 show up\n    at the same time, and instead only show the latest one.\n    \"\"\"\n    def __init__(self, *, outs: List[Any], print_progress: bool, min_progress_delay: float):\n        self.outs = outs\n        self.print_progress = print_progress\n        self.next_can_print_time = time.monotonic()\n        self.latest_msg = ''\n        self.latest_printed_msg = ''\n        self.min_progress_delay = min_progress_delay\n        self.is_worker_running = False\n        self.lock = threading.Lock()\n\n    def print_out(self, msg: str) -> None:\n        with self.lock:\n            for out in self.outs:\n                print(msg, file=out, flush=True)\n\n    def show_latest_progress(self, msg: str) -> None:\n        if not self.print_progress:\n            return\n        with self.lock:\n            if msg == self.latest_msg:\n                return\n            self.latest_msg = msg\n            if not self.is_worker_running:\n                dt = self._try_print_else_delay()\n                if dt > 0:\n                    self.is_worker_running = True\n                    threading.Thread(target=self._print_worker).start()\n\n    def flush(self):\n        with self.lock:\n            if self.latest_msg != \"\" and self.latest_printed_msg != self.latest_msg:\n                print('\\033[31m' + self.latest_msg + '\\033[0m', file=sys.stderr, flush=True)\n                self.latest_printed_msg = self.latest_msg\n\n    def _try_print_else_delay(self) -> float:\n        t = time.monotonic()\n        dt = self.next_can_print_time - t\n        if dt <= 0:\n            self.next_can_print_time = t + self.min_progress_delay\n            self.is_worker_running = False\n            if self.latest_msg != \"\" and self.latest_msg != self.latest_printed_msg:\n                print('\\033[31m' + self.latest_msg + '\\033[0m', file=sys.stderr, flush=True)\n                self.latest_printed_msg = self.latest_msg\n        return max(dt, 0)\n\n    def _print_worker(self):\n        while True:\n            with self.lock:\n                dt = self._try_print_else_delay()\n            if dt == 0:\n                break\n            time.sleep(dt)\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_sampler_ramp_throttled.py",
    "content": "import time\n\nfrom sinter._decoding import Sampler, CompiledSampler\nfrom sinter._data import Task, AnonTaskStats\n\n\nclass RampThrottledSampler(Sampler):\n    \"\"\"Wraps a sampler to adjust requested shots to hit a target time.\n\n    This sampler will initially only take 1 shot per call. If the time taken\n    significantly undershoots the target time, the maximum number of shots per\n    call is increased by a constant factor. If it exceeds the target time, the\n    maximum is reduced by a constant factor. The result is that the sampler\n    \"ramps up\" how many shots it does per call until it takes roughly the target\n    time, and then dynamically adapts to stay near it.\n    \"\"\"\n\n    def __init__(self, sub_sampler: Sampler, target_batch_seconds: float, max_batch_shots: int):\n        self.sub_sampler = sub_sampler\n        self.target_batch_seconds = target_batch_seconds\n        self.max_batch_shots = max_batch_shots\n\n    def __str__(self) -> str:\n        return f'CompiledRampThrottledSampler({self.sub_sampler})'\n\n    def compiled_sampler_for_task(self, task: Task) -> CompiledSampler:\n        compiled_sub_sampler = self.sub_sampler.compiled_sampler_for_task(task)\n        if compiled_sub_sampler.handles_throttling():\n            return compiled_sub_sampler\n\n        return CompiledRampThrottledSampler(\n            sub_sampler=compiled_sub_sampler,\n            target_batch_seconds=self.target_batch_seconds,\n            max_batch_shots=self.max_batch_shots,\n        )\n\n\nclass CompiledRampThrottledSampler(CompiledSampler):\n    def __init__(self, sub_sampler: CompiledSampler, target_batch_seconds: float, max_batch_shots: int):\n        self.sub_sampler = sub_sampler\n        self.target_batch_seconds = target_batch_seconds\n        self.batch_shots = 1\n        self.max_batch_shots = max_batch_shots\n\n    def __str__(self) -> str:\n        return f'CompiledRampThrottledSampler({self.sub_sampler})'\n\n    def sample(self, max_shots: int) -> AnonTaskStats:\n        t0 = time.monotonic()\n        actual_shots = min(max_shots, self.batch_shots)\n        result = self.sub_sampler.sample(actual_shots)\n        dt = time.monotonic() - t0\n\n        # Rebalance number of shots.\n        if self.batch_shots > 1 and dt > self.target_batch_seconds * 1.3:\n            self.batch_shots //= 2\n        if result.shots * 2 >= actual_shots:\n            for _ in range(4):\n                if self.batch_shots * 2 > self.max_batch_shots:\n                    break\n                if dt > self.target_batch_seconds * 0.3:\n                    break\n                self.batch_shots *= 2\n                dt *= 2\n\n        return result\n"
  },
  {
    "path": "glue/sample/src/sinter/_collection/_sampler_ramp_throttled_test.py",
    "content": "from unittest import mock\n\nimport pytest\n\nimport sinter\nimport stim\nfrom sinter._collection._sampler_ramp_throttled import (\n    CompiledRampThrottledSampler,\n    RampThrottledSampler,\n)\nfrom sinter._data import AnonTaskStats, Task\n\n\nclass MockSampler(sinter.Sampler, sinter.CompiledSampler):\n    \"\"\"Mock sampler that tracks `suggested_shots` parameter in `sample` calls.\"\"\"\n\n    def __init__(self):\n        self.calls = []\n\n    def compiled_sampler_for_task(self, task: Task) -> sinter.CompiledSampler:\n        return self\n\n    def sample(self, suggested_shots: int) -> AnonTaskStats:\n        self.calls.append(suggested_shots)\n        return AnonTaskStats(\n            shots=suggested_shots,\n            errors=1,\n            seconds=0.001 * suggested_shots,  # Simulate time proportional to shots\n        )\n\n\n@pytest.fixture\ndef mock_sampler():\n    return MockSampler()\n\n\ndef test_initial_batch_size(mock_sampler):\n    \"\"\"Test that the sampler starts with a batch size of 1.\"\"\"\n    sampler = CompiledRampThrottledSampler(\n        sub_sampler=mock_sampler,\n        target_batch_seconds=1.0,\n        max_batch_shots=1024,\n    )\n\n    # First call should use batch_size=1\n    sampler.sample(100)\n    assert mock_sampler.calls[0] == 1\n\n\ndef test_batch_size_ramps_up(mock_sampler):\n    \"\"\"Test that the batch size increases when execution is fast.\"\"\"\n    sampler = CompiledRampThrottledSampler(\n        sub_sampler=mock_sampler,\n        target_batch_seconds=1.0,\n        max_batch_shots=1024,\n    )\n\n    # Mock time.monotonic to simulate fast execution\n    # two calls per sample for tic/toc\n    with mock.patch(\n        \"time.monotonic\", side_effect=[0.0, 0.001, 0.02, 0.021, 0.03, 0.031]\n    ):\n        sampler.sample(100)  # First call, batch_size=1\n        sampler.sample(100)  # Should double 4 times to 16\n        sampler.sample(100)  # Should double 4 times again but hit limit of 100\n\n    assert mock_sampler.calls == [1, 16, 100]\n\n\ndef test_batch_size_decreases(mock_sampler):\n    \"\"\"Test that the batch size decreases when execution is slow.\"\"\"\n    sampler = CompiledRampThrottledSampler(\n        sub_sampler=mock_sampler,\n        target_batch_seconds=0.1,\n        max_batch_shots=1024,\n    )\n\n    # Set initial batch size higher for this test\n    sampler.batch_shots = 64\n\n    # Mock time.monotonic to simulate slow execution (>1.3x target)\n    with mock.patch(\"time.monotonic\", side_effect=[0.0, 0.15, 0.5, 0.65]):\n        sampler.sample(100)  # First call, batch_size=64\n        sampler.sample(100)  # Should halve to 32\n\n    assert mock_sampler.calls == [64, 32]\n\n\ndef test_respects_max_batch_shots(mock_sampler):\n    \"\"\"Test that the batch size never exceeds max_batch_shots.\"\"\"\n    sampler = CompiledRampThrottledSampler(\n        sub_sampler=mock_sampler,\n        target_batch_seconds=1.0,\n        max_batch_shots=16,  # Small max for testing\n    )\n\n    # Set initial batch size close to max\n    sampler.batch_shots = 8\n\n    # Mock time.monotonic to simulate very fast execution\n    # two calls per sample for tic/toc\n    with mock.patch(\n        \"time.monotonic\", side_effect=[0.0, 0.001, 0.02, 0.021, 0.03, 0.031]\n    ):\n        sampler.sample(100)  # First call, batch_size=8\n        sampler.sample(100)  # Should double to 16\n        sampler.sample(100)  # Should stay at 16 (max)\n\n    assert mock_sampler.calls == [8, 16, 16]\n\n\ndef test_respects_max_shots_parameter(mock_sampler):\n    \"\"\"Test that the sampler respects the max_shots parameter.\"\"\"\n    sampler = CompiledRampThrottledSampler(\n        sub_sampler=mock_sampler,\n        target_batch_seconds=1.0,\n        max_batch_shots=1024,\n    )\n\n    # Set batch size higher than max_shots\n    sampler.batch_shots = 100\n\n    # Call with max_shots=10\n    sampler.sample(10)\n\n    # Should only request 10 shots, not 100\n    assert mock_sampler.calls[0] == 10\n\n\ndef test_sub_sampler_parameter_pass_through(mock_sampler):\n    \"\"\"Test that parameters are passed through to compiled sub sampler.\"\"\"\n    factory = RampThrottledSampler(\n        sub_sampler=mock_sampler,\n        target_batch_seconds=0.5,\n        max_batch_shots=512,\n    )\n\n    task = Task(circuit=stim.Circuit(), decoder=\"test\")\n    compiled = factory.compiled_sampler_for_task(task)\n\n    assert isinstance(compiled, CompiledRampThrottledSampler)\n    assert compiled.target_batch_seconds == 0.5\n    assert compiled.max_batch_shots == 512\n    assert compiled.batch_shots == 1  # Initial batch size\n"
  },
  {
    "path": "glue/sample/src/sinter/_command/__init__.py",
    "content": ""
  },
  {
    "path": "glue/sample/src/sinter/_command/_main.py",
    "content": "import sys\nfrom typing import Optional, List\n\n\ndef main(*, command_line_args: Optional[List[str]] = None):\n    if command_line_args is None:\n        command_line_args = sys.argv[1:]\n\n    mode = command_line_args[0] if command_line_args else None\n    if mode == 'combine':\n        from sinter._command._main_combine import main_combine\n        return main_combine(command_line_args=command_line_args[1:])\n    if mode == 'collect':\n        from sinter._command._main_collect import main_collect\n        return main_collect(command_line_args=command_line_args[1:])\n    if mode == 'plot':\n        from sinter._command._main_plot import main_plot\n        return main_plot(command_line_args=command_line_args[1:])\n    if mode == 'predict':\n        from sinter._command._main_predict import main_predict\n        return main_predict(command_line_args=command_line_args[1:])\n\n    want_help = mode in ['help', 'h', '--help', '-help', '-h', '--h']\n    if not want_help:\n        if command_line_args and not command_line_args[0].startswith('-'):\n            print(f\"\\033[31mUnrecognized command: sinter {command_line_args[0]}\\033[0m\\n\", file=sys.stderr)\n        else:\n            print(f\"\\033[31mDidn't specify a command.\\033[0m\\n\", file=sys.stderr)\n    print(f\"Available commands are:\\n\"\n          f\"    sinter collect\\n\"\n          f\"    sinter combine\\n\"\n          f\"    sinter plot\"\n          f\"\", file=sys.stderr)\n    if not want_help:\n        sys.exit(1)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "glue/sample/src/sinter/_command/_main_collect.py",
    "content": "import argparse\nimport math\nimport os\nimport sys\nfrom typing import Iterator, Any, Tuple, List, Callable, Optional\nfrom typing import cast\n\nimport numpy as np\nimport stim\n\nfrom sinter._collection import ThrottledProgressPrinter\nfrom sinter._data import Task\nfrom sinter._collection import collect, Progress, post_selection_mask_from_predicate\nfrom sinter._command._main_combine import ExistingData, CSV_HEADER\nfrom sinter._decoding._decoding_all_built_in_decoders import BUILT_IN_SAMPLERS\n\n\ndef iter_file_paths_into_goals(circuit_paths: Iterator[str],\n                               metadata_func: Callable,\n                               postselected_detectors_predicate: Optional[Callable[[int, Any, Tuple[float, ...]], bool]],\n                               postselected_observables_predicate: Callable[[int, Any], bool],\n                               ) -> Iterator[Task]:\n    for path in circuit_paths:\n        with open(path) as f:\n            circuit_text = f.read()\n        circuit = stim.Circuit(circuit_text)\n\n        metadata = metadata_func(path=path, circuit=circuit)\n        if postselected_detectors_predicate is not None:\n            post_mask = post_selection_mask_from_predicate(circuit, metadata=metadata, postselected_detectors_predicate=postselected_detectors_predicate)\n            if not np.any(post_mask):\n                post_mask = None\n        else:\n            post_mask = None\n        postselected_observables = [\n            k\n            for k in range(circuit.num_observables)\n            if postselected_observables_predicate(k, metadata)\n        ]\n        if any(postselected_observables):\n            postselected_observables_mask = np.zeros(shape=math.ceil(circuit.num_observables / 8), dtype=np.uint8)\n            for k in postselected_observables:\n                postselected_observables_mask[k // 8] |= 1 << (k % 8)\n        else:\n            postselected_observables_mask = None\n\n        yield Task(\n            circuit=circuit,\n            postselection_mask=post_mask,\n            postselected_observables_mask=postselected_observables_mask,\n            json_metadata=metadata,\n        )\n\n\ndef parse_args(args: List[str]) -> Any:\n    parser = argparse.ArgumentParser(description='Collect Monte Carlo samples.',\n                                     prog='sinter collect')\n    parser.add_argument('--circuits',\n                        nargs='+',\n                        required=True,\n                        help='Circuit files to sample from and decode.\\n'\n                             'This parameter can be given multiple arguments.')\n    parser.add_argument('--decoders',\n                        type=str,\n                        nargs='+',\n                        required=True,\n                        help='The decoder to use to predict observables from detection events.')\n    parser.add_argument('--custom_decoders_module_function',\n                        default=None,\n                        nargs='+',\n                        help='Use the syntax \"module:function\" to \"import function from module\" '\n                             'and use the result of \"function()\" as the custom_decoders '\n                             'dictionary. The dictionary must map strings to stim.Decoder '\n                             'instances.')\n    parser.add_argument('--max_shots',\n                        type=int,\n                        default=None,\n                        help='Sampling of a circuit will stop if this many shots have been taken.')\n    parser.add_argument('--max_errors',\n                        type=int,\n                        default=None,\n                        help='Sampling of a circuit will stop if this many errors have been seen.')\n    parser.add_argument('--processes',\n                        default='auto',\n                        type=str,\n                        help='Number of processes to use for simultaneous sampling and decoding. '\n                             'Must be either a number or \"auto\" which sets it to the number of '\n                             'CPUs on the machine.')\n    parser.add_argument('--save_resume_filepath',\n                        type=str,\n                        default=None,\n                        help='Activates MERGE mode.\\n'\n                             \"If save_resume_filepath doesn't exist, initializes it with a CSV header.\\n\"\n                             'CSV data already at save_resume_filepath counts towards max_shots and max_errors.\\n'\n                             'Collected data is appended to save_resume_filepath.\\n'\n                             'Note that MERGE mode is tolerant to failures: if the process is killed, it can simply be restarted and it will pick up where it left off.\\n'\n                             'Note that MERGE mode is idempotent: if sufficient data has been collected, no additional work is done when run again.')\n\n    parser.add_argument('--start_batch_size',\n                        type=int,\n                        default=100,\n                        help='Initial number of samples to batch together into one job.\\n'\n                             'Starting small prevents over-sampling of circuits above threshold.\\n'\n                             'The allowed batch size increases exponentially from this starting point.')\n    parser.add_argument('--max_batch_size',\n                        type=int,\n                        default=None,\n                        help='Maximum number of samples to batch together into one job.\\n'\n                             'Bigger values increase the delay between jobs finishing.\\n'\n                             'Smaller values decrease the amount of aggregation of results, increasing the amount of output information.')\n    parser.add_argument('--max_batch_seconds',\n                        type=int,\n                        default=None,\n                        help='Limits number of shots in a batch so that the estimated runtime of the batch is below this amount.')\n    parser.add_argument('--postselect_detectors_with_non_zero_4th_coord',\n                        help='Turns on detector postselection. '\n                             'If any detector with a non-zero 4th coordinate fires, the shot is discarded.',\n                        action='store_true')\n    parser.add_argument('--postselected_detectors_predicate',\n                        type=str,\n                        default='''False''',\n                        help='Specifies a predicate used to decide which detectors to postselect. '\n                             'When a postselected detector produces a detection event, the shot is discarded instead of being given to the decoder.'\n                             'The number of discarded shots is tracked as a statistic.'\n                             'Available values:\\n'\n                             '    index: The unique number identifying the detector, determined by the order of detectors in the circuit file.\\n'\n                             '    coords: The coordinate data associated with the detector. An empty tuple, if the circuit file did not specify detector coordinates.\\n'\n                             '    metadata: The metadata associated with the task being sampled.\\n'\n                             'Expected expression type:\\n'\n                             '    Something that can be given to `bool` to get False (do not postselect) or True (yes postselect).\\n'\n                             'Examples:\\n'\n                             '''    --postselected_detectors_predicate \"coords[2] == 0\"\\n'''\n                             '''    --postselected_detectors_predicate \"coords[3] < metadata['postselection_level']\"\\n''')\n    parser.add_argument('--postselected_observables_predicate',\n                        type=str,\n                        default='''False''',\n                        help='Specifies a predicate used to decide which observables to postselect. '\n                             'When a decoder mispredicts a postselected observable, the shot is discarded instead of counting as an error.'\n                             'Available values:\\n'\n                             '    index: The index of the observable to postselect or not.\\n'\n                             '    metadata: The metadata associated with the task.\\n'\n                             'Expected expression type:\\n'\n                             '    Something that can be given to `bool` to get False (do not postselect) or True (yes postselect).\\n'\n                             'Examples:\\n'\n                             '''    --postselected_observables_predicate \"False\"\\n'''\n                             '''    --postselected_observables_predicate \"metadata['d'] == 5 and index >= 2\"\\n''')\n    parser.add_argument('--count_observable_error_combos',\n                        help='When set, the returned stats will include custom '\n                             'counts like `obs_mistake_mask=E_E__` counting '\n                             'how many times the decoder made each pattern of '\n                             'observable mistakes.',\n                        action='store_true')\n    parser.add_argument('--count_detection_events',\n                        help='When set, the returned stats will include custom '\n                             'counts `detectors_checked` and '\n                             '`detection_events`. The detection fraction is '\n                             'the ratio of these two numbers.',\n                        action='store_true')\n    parser.add_argument('--quiet',\n                        help='Disables writing progress to stderr.',\n                        action='store_true')\n    parser.add_argument('--custom_error_count_key',\n                        type=str,\n                        help='Makes --max_errors apply to `stat.custom_counts[key]` '\n                             'instead of to `stat.errors`.',\n                        default=None)\n    parser.add_argument('--allowed_cpu_affinity_ids',\n                        type=str,\n                        nargs='+',\n                        help='Controls which CPUs workers can be pinned to. By default, all'\n                             ' CPUs are used. Specifying this argument makes it so that '\n                             'only the given CPU ids can be pinned. The given arguments '\n                             ' will be evaluated as python expressions. The expressions '\n                             'should be integers or iterables of integers. So values like'\n                             ' \"1\" and \"[1, 2, 4]\" and \"range(5, 30)\" all work.',\n                        default=None)\n    parser.add_argument('--also_print_results_to_stdout',\n                        help='Even if writing to a file, also write results to stdout.',\n                        action='store_true')\n    parser.add_argument('--existing_data_filepaths',\n                        nargs='*',\n                        type=str,\n                        default=(),\n                        help='CSV data from these files counts towards max_shots and max_errors.\\n'\n                             'This parameter can be given multiple arguments.')\n    parser.add_argument('--metadata_func',\n                        type=str,\n                        default=\"{'path': path}\",\n                        help='A python expression that associates json metadata with a circuit\\'s results.\\n'\n                             'Set to \"auto\" to use \"sinter.comma_separated_key_values(path)\"\\n'\n                             'Values available to the expression:\\n'\n                             '    path: Relative path to the circuit file, from the command line arguments.\\n'\n                             '    circuit: The circuit itself, parsed from the file, as a stim.Circuit.\\n'\n                             'Expected type:\\n'\n                             '    A value that can be serialized into JSON, like a Dict[str, int].\\n'\n                             '\\n'\n                             '    Note that the decoder field is already recorded separately, so storing\\n'\n                             '    it in the metadata as well would be redundant. But something like\\n'\n                             '    decoder version could be usefully added.\\n'\n                             'Examples:\\n'\n                             '''    --metadata_func \"{'path': path}\"\\n'''\n                             '''    --metadata_func \"auto\"\\n'''\n                             '''    --metadata_func \"{'n': circuit.num_qubits, 'p': float(path.split('/')[-1].split('.')[0])}\"\\n'''\n                        )\n    import sinter\n    a = parser.parse_args(args=args)\n    if a.metadata_func == 'auto':\n        a.metadata_func = \"sinter.comma_separated_key_values(path)\"\n    a.metadata_func = eval(compile(\n        'lambda *, path, circuit: ' + a.metadata_func,\n        filename='metadata_func:command_line_arg',\n        mode='eval'), {'sinter': sinter})\n    a.postselected_observables_predicate = eval(compile(\n        'lambda index, metadata: ' + a.postselected_observables_predicate,\n        filename='postselected_observables_predicate:command_line_arg',\n        mode='eval'))\n    if a.postselected_detectors_predicate == 'False':\n        if a.postselect_detectors_with_non_zero_4th_coord:\n            a.postselected_detectors_predicate = lambda index, metadata, coords: coords[3]\n        else:\n            a.postselected_detectors_predicate = None\n    else:\n        if a.postselect_detectors_with_non_zero_4th_coord:\n            raise ValueError(\"Can't specify both --postselect_detectors_with_non_zero_4th_coord and --postselected_detectors_predicate\")\n        a.postselected_detectors_predicate = eval(compile(\n            'lambda index, metadata, coords: ' + cast(str, a.postselected_detectors_predicate),\n            filename='postselected_detectors_predicate:command_line_arg',\n            mode='eval'))\n    if a.custom_decoders_module_function is not None:\n        all_custom_decoders = {}\n        for entry in a.custom_decoders_module_function:\n            terms = entry.split(':')\n            if len(terms) != 2:\n                raise ValueError(\"--custom_decoders_module_function didn't have exactly one colon \"\n                                 \"separating a module name from a function name. Expected an argument \"\n                                 \"of the form --custom_decoders_module_function 'module:function'\")\n            module, function = terms\n            vals = {'__name__': '[]'}\n            exec(f\"from {module} import {function} as _custom_decoders\", vals)\n            custom_decoders = vals['_custom_decoders']()\n            all_custom_decoders = {**all_custom_decoders, **custom_decoders}\n        a.custom_decoders = all_custom_decoders\n    else:\n        a.custom_decoders = None\n    for decoder in a.decoders:\n        if decoder not in BUILT_IN_SAMPLERS and (a.custom_decoders is None or decoder not in a.custom_decoders):\n            message = f\"Not a recognized decoder or sampler: {decoder=}.\\n\"\n            message += f\"Available built-in decoders and samplers: {sorted(e for e in BUILT_IN_SAMPLERS.keys() if 'internal' not in e)}.\\n\"\n            if a.custom_decoders is None:\n                message += f\"No custom decoders are available. --custom_decoders_module_function wasn't specified.\"\n            else:\n                message += f\"Available custom decoders: {sorted(a.custom_decoders.keys())}.\"\n            raise ValueError(message)\n    if a.allowed_cpu_affinity_ids is not None:\n        vals: List[int] = []\n        e: str\n        for e in a.allowed_cpu_affinity_ids:\n            try:\n                v = eval(e, {}, {})\n                if isinstance(v, int):\n                    vals.append(v)\n                elif all(isinstance(e, int) for e in v):\n                    vals.extend(v)\n                else:\n                    raise ValueError(\"Not an integer or iterable of integers.\")\n            except Exception as ex:\n                raise ValueError(\"Failed to eval {e!r} for --allowed_cpu_affinity_ids\") from ex\n        a.allowed_cpu_affinity_ids = vals\n    return a\n\n\ndef open_merge_file(path: str) -> Tuple[Any, ExistingData]:\n    try:\n        existing = ExistingData.from_file(path)\n        return open(path, 'a'), existing\n    except FileNotFoundError:\n        f = open(path, 'w')\n        print(CSV_HEADER, file=f)\n        return f, ExistingData()\n\n\ndef main_collect(*, command_line_args: List[str]):\n    args = parse_args(args=command_line_args)\n\n    iter_tasks = iter_file_paths_into_goals(\n        circuit_paths=args.circuits,\n        metadata_func=args.metadata_func,\n        postselected_detectors_predicate=args.postselected_detectors_predicate,\n        postselected_observables_predicate=args.postselected_observables_predicate,\n    )\n    num_tasks = len(args.circuits) * len(args.decoders)\n\n    print_to_stdout = args.also_print_results_to_stdout or args.save_resume_filepath is None\n\n    did_work = False\n    printer = ThrottledProgressPrinter(\n        outs=[],\n        print_progress=not args.quiet,\n        min_progress_delay=0.03 if args.also_print_results_to_stdout else 0.1,\n    )\n    if print_to_stdout:\n        printer.outs.append(sys.stdout)\n\n    def on_progress(sample: Progress) -> None:\n        nonlocal did_work\n        for stats in sample.new_stats:\n            if not did_work:\n                printer.print_out(CSV_HEADER)\n                did_work = True\n            printer.print_out(stats.to_csv_line())\n\n        msg = sample.status_message\n        if msg == 'KeyboardInterrupt':\n            printer.show_latest_progress('\\nInterrupted. Output is flushed. Cleaning up workers...')\n            printer.flush()\n        else:\n            printer.show_latest_progress(msg)\n\n    if args.processes == 'auto':\n        num_workers = os.cpu_count()\n    else:\n        try:\n            num_workers = int(args.processes)\n        except ValueError:\n            num_workers = 0\n        if num_workers < 1:\n            raise ValueError(f'--processes must be a non-negative integer, or \"auto\", but was: {args.processes}')\n    try:\n        collect(\n            num_workers=num_workers,\n            hint_num_tasks=num_tasks,\n            tasks=iter_tasks,\n            print_progress=False,\n            save_resume_filepath=args.save_resume_filepath,\n            existing_data_filepaths=args.existing_data_filepaths,\n            progress_callback=on_progress,\n            max_errors=args.max_errors,\n            max_shots=args.max_shots,\n            count_detection_events=args.count_detection_events,\n            count_observable_error_combos=args.count_observable_error_combos,\n            decoders=args.decoders,\n            max_batch_seconds=args.max_batch_seconds,\n            max_batch_size=args.max_batch_size,\n            start_batch_size=args.start_batch_size,\n            custom_decoders=args.custom_decoders,\n            custom_error_count_key=args.custom_error_count_key,\n            allowed_cpu_affinity_ids=args.allowed_cpu_affinity_ids,\n        )\n    except KeyboardInterrupt:\n        pass\n"
  },
  {
    "path": "glue/sample/src/sinter/_command/_main_collect_test.py",
    "content": "import collections\nimport pathlib\nimport tempfile\n\nimport stim\n\nimport pytest\nimport sinter\nfrom sinter._command._main import main\nfrom sinter._command._main_combine import ExistingData\nfrom sinter._plotting import split_by\n\n\ndef test_split_by():\n    assert split_by('abcdefcccghi', lambda e: e == 'c') == [list('ab'), list('c'), list('def'), list('ccc'), list('ghi')]\n\n\ndef test_main_collect():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        for distance in [3, 5, 7]:\n            c = stim.Circuit.generated(\n                'repetition_code:memory',\n                rounds=3,\n                distance=distance,\n                after_clifford_depolarization=0.02)\n            with open(d / f'{distance}.stim', 'w') as f:\n                print(c, file=f)\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / \"3.stim\"),\n            str(d / \"5.stim\"),\n            str(d / \"7.stim\"),\n            \"--max_shots\",\n            \"1000\",\n            \"--max_errors\",\n            \"10\",\n            \"--decoders\",\n            \"pymatching\",\n            \"--processes\",\n            \"4\",\n            \"--quiet\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n        ])\n        data = ExistingData.from_file(d / \"out.csv\").data\n        assert len(data) == 3\n        for k, v in data.items():\n            assert v.discards == 0\n            assert v.errors <= 50\n            assert v.shots >= 1000\n\n        # No more work when existing stats at merge location are sufficient.\n        with open(d / \"out.csv\") as f:\n            contents1 = f.read()\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / \"3.stim\"),\n            str(d / \"5.stim\"),\n            str(d / \"7.stim\"),\n            \"--max_shots\",\n            \"1000\",\n            \"--max_errors\",\n            \"10\",\n            \"--decoders\",\n            \"pymatching\",\n            \"--processes\",\n            \"4\",\n            \"--quiet\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n        ])\n        with open(d / \"out.csv\") as f:\n            contents2 = f.read()\n        assert contents1 == contents2\n\n        # No more work when existing work is sufficient.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / \"3.stim\"),\n            str(d / \"5.stim\"),\n            str(d / \"7.stim\"),\n            \"--max_shots\",\n            \"1000\",\n            \"--max_errors\",\n            \"10\",\n            \"--decoders\",\n            \"pymatching\",\n            \"--processes\",\n            \"4\",\n            \"--quiet\",\n            \"--existing_data_filepaths\",\n            str(d / \"out.csv\"),\n            \"--save_resume_filepath\",\n            str(d / \"out2.csv\"),\n        ])\n        data2 = ExistingData.from_file(d / \"out2.csv\").data\n        assert len(data2) == 0\n\n\nclass AlternatingPredictionsDecoder(sinter.Decoder):\n    def decode_via_files(self,\n                         *,\n                         num_shots: int,\n                         num_dets: int,\n                         num_obs: int,\n                         dem_path: pathlib.Path,\n                         dets_b8_in_path: pathlib.Path,\n                         obs_predictions_b8_out_path: pathlib.Path,\n                         tmp_dir: pathlib.Path,\n                       ) -> None:\n        bytes_per_shot = (num_obs + 7) // 8\n        with open(obs_predictions_b8_out_path, 'wb') as f:\n            for k in range(num_shots):\n                f.write((k % 3 == 0).to_bytes(length=bytes_per_shot, byteorder='little'))\n\n\ndef _make_custom_decoders():\n    return {'alternate': AlternatingPredictionsDecoder()}\n\n\ndef test_main_collect_with_custom_decoder():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'tmp.stim', 'w') as f:\n            print(\"\"\"\n                M(0.1) 0\n                DETECTOR rec[-1]\n                OBSERVABLE_INCLUDE(0) rec[-1]\n            \"\"\", file=f)\n\n        with pytest.raises(ValueError, match=\"Not a recognized decoder\"):\n            main(command_line_args=[\n                \"collect\",\n                \"--circuits\",\n                str(d / \"tmp.stim\"),\n                \"--max_shots\",\n                \"1000\",\n                \"--decoders\",\n                \"NOTEXIST\",\n                \"--custom_decoders_module_function\",\n                \"sinter._command._main_collect_test:_make_custom_decoders\",\n                \"--processes\",\n                \"2\",\n                \"--quiet\",\n                \"--save_resume_filepath\",\n                str(d / \"out.csv\"),\n            ])\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / \"tmp.stim\"),\n            \"--max_shots\",\n            \"1000\",\n            \"--decoders\",\n            \"alternate\",\n            \"--custom_decoders_module_function\",\n            \"sinter._command._main_collect_test:_make_custom_decoders\",\n            \"--processes\",\n            \"2\",\n            \"--quiet\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n        ])\n        data = ExistingData.from_file(d / \"out.csv\").data\n        assert len(data) == 1\n        v, = data.values()\n        assert v.shots == 1000\n        assert 50 < v.errors < 500\n        assert v.discards == 0\n\n\ndef test_main_collect_post_select_observables():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'circuit.stim', 'w') as f:\n            print(\"\"\"\n                M(0.125) 0 1\n                OBSERVABLE_INCLUDE(0) rec[-1]\n                OBSERVABLE_INCLUDE(11) rec[-1] rec[-2]\n            \"\"\", file=f)\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--postselected_observables_predicate\",\n            \"index == 11\",\n            \"--circuits\",\n            str(d / \"circuit.stim\"),\n            \"--max_shots\",\n            \"10000\",\n            \"--max_errors\",\n            \"10000\",\n            \"--decoders\",\n            \"pymatching\",\n            \"--processes\",\n            \"4\",\n            \"--quiet\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n        ])\n        data = sinter.stats_from_csv_files(d / \"out.csv\")\n        assert len(data) == 1\n        stats, = data\n        assert stats.shots == 10000\n        assert 0.21875 - 0.1 < stats.discards / stats.shots < 0.21875 + 0.1\n        assert 0.015625 - 0.01 <= stats.errors / (stats.shots - stats.discards) <= 0.015625 + 0.02\n\n\ndef test_main_collect_comma_separated_key_values():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        paths = []\n        for distance in [3, 5, 7]:\n            c = stim.Circuit.generated(\n                'repetition_code:memory',\n                rounds=3,\n                distance=distance,\n                after_clifford_depolarization=0.02)\n            path = d / f'd={distance},p=0.02,r=3.0,c=rep_code.stim'\n            paths.append(str(path))\n            with open(path, 'w') as f:\n                print(c, file=f)\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            *paths,\n            \"--max_shots\",\n            \"1000\",\n            \"--metadata_func\",\n            \"sinter.comma_separated_key_values(path)\",\n            \"--max_errors\",\n            \"10\",\n            \"--decoders\",\n            \"pymatching\",\n            \"--processes\",\n            \"4\",\n            \"--quiet\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n        ])\n        data = sinter.stats_from_csv_files(d / \"out.csv\")\n        seen_metadata = frozenset(repr(e.json_metadata) for e in data)\n        assert seen_metadata == frozenset([\n            \"{'c': 'rep_code', 'd': 3, 'p': 0.02, 'r': 3.0}\",\n            \"{'c': 'rep_code', 'd': 5, 'p': 0.02, 'r': 3.0}\",\n            \"{'c': 'rep_code', 'd': 7, 'p': 0.02, 'r': 3.0}\",\n        ])\n\n\ndef test_main_collect_count_observable_error_combos():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / 'a=3.stim', 'w') as f:\n            print(\"\"\"\n                X_ERROR(0.1) 0\n                X_ERROR(0.2) 1\n                M 0 1\n                OBSERVABLE_INCLUDE(0) rec[-1]\n                OBSERVABLE_INCLUDE(1) rec[-2]\n            \"\"\", file=f)\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / 'a=3.stim'),\n            \"--max_shots\",\n            \"100000\",\n            \"--metadata_func\",\n            \"sinter.comma_separated_key_values(path)\",\n            \"--max_errors\",\n            \"10000\",\n            \"--decoders\",\n            \"pymatching\",\n            \"--count_observable_error_combos\",\n            \"--processes\",\n            \"4\",\n            \"--quiet\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n        ])\n        data = sinter.stats_from_csv_files(d / \"out.csv\")\n        assert len(data) == 1\n        item, = data\n        assert set(item.custom_counts.keys()) == {\"obs_mistake_mask=E_\", \"obs_mistake_mask=_E\", \"obs_mistake_mask=EE\"}\n        assert 0.1*0.8 - 0.01 < item.custom_counts['obs_mistake_mask=_E'] / item.shots < 0.1*0.8 + 0.01\n        assert 0.9*0.2 - 0.01 < item.custom_counts['obs_mistake_mask=E_'] / item.shots < 0.9*0.2 + 0.01\n        assert 0.1*0.2 - 0.01 < item.custom_counts['obs_mistake_mask=EE'] / item.shots < 0.1*0.2 + 0.01\n\n\ndef test_main_collect_count_detection_events():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / 'a=3.stim', 'w') as f:\n            print(\"\"\"\n                X_ERROR(0.1) 0\n                X_ERROR(0.2) 1\n                M 0 1\n                OBSERVABLE_INCLUDE(0) rec[-1]\n                OBSERVABLE_INCLUDE(1) rec[-2]\n                DETECTOR rec[-2]\n            \"\"\", file=f)\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / 'a=3.stim'),\n            \"--max_shots\",\n            \"100000\",\n            \"--metadata_func\",\n            \"sinter.comma_separated_key_values(path)\",\n            \"--decoders\",\n            \"pymatching\",\n            \"--count_detection_events\",\n            \"--processes\",\n            \"4\",\n            \"--quiet\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n        ])\n        data = sinter.stats_from_csv_files(d / \"out.csv\")\n        assert len(data) == 1\n        item, = data\n        assert set(item.custom_counts.keys()) == {\"detection_events\", \"detectors_checked\"}\n        assert item.custom_counts['detectors_checked'] == 100000\n        assert 100000 * 0.1 * 0.5 < item.custom_counts['detection_events'] < 100000 * 0.1 * 1.5\n\n\ndef test_cpu_pin():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / 'a=3.stim', 'w') as f:\n            print(\"\"\"\n                X_ERROR(0.1) 0\n                X_ERROR(0.2) 1\n                M 0 1\n                OBSERVABLE_INCLUDE(0) rec[-1]\n                OBSERVABLE_INCLUDE(1) rec[-2]\n                DETECTOR rec[-2]\n            \"\"\", file=f)\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / 'a=3.stim'),\n            \"--max_shots\",\n            \"100000\",\n            \"--metadata_func\",\n            \"auto\",\n            \"--decoders\",\n            \"pymatching\",\n            \"--count_detection_events\",\n            \"--processes\",\n            \"4\",\n            \"--quiet\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n            \"--allowed_cpu_affinity_ids\",\n            \"0\",\n            \"range(1, 9, 2)\",\n            \"[4, 20]\"\n        ])\n        data = sinter.stats_from_csv_files(d / \"out.csv\")\n        assert len(data) == 1\n        item, = data\n        assert set(item.custom_counts.keys()) == {\"detection_events\", \"detectors_checked\"}\n        assert item.custom_counts['detectors_checked'] == 100000\n        assert 100000 * 0.1 * 0.5 < item.custom_counts['detection_events'] < 100000 * 0.1 * 1.5\n\n\ndef test_custom_error_stopping_count():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        stim.Circuit.generated(\n            'repetition_code:memory',\n            rounds=25,\n            distance=5,\n            after_clifford_depolarization=0.1,\n        ).to_file(d / 'a=3.stim')\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / 'a=3.stim'),\n            \"--max_shots\",\n            \"100_000_000_000_000\",\n            \"--quiet\",\n            \"--max_errors\",\n            \"1_000_000\",\n            \"--metadata_func\",\n            \"auto\",\n            \"--decoders\",\n            \"vacuous\",\n            \"--count_detection_events\",\n            \"--processes\",\n            \"4\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n            \"--custom_error_count_key\",\n            \"detection_events\",\n        ])\n        data = sinter.stats_from_csv_files(d / \"out.csv\")\n        assert len(data) == 1\n        item, = data\n        # Would normally need >1_000_000 shots to see 1_000_000 errors.\n        assert item.shots < 100_000\n        assert item.errors < 90_000\n        assert item.custom_counts['detection_events'] > 1_000_000\n\n\ndef test_auto_processes():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        stim.Circuit.generated(\n            'repetition_code:memory',\n            rounds=5,\n            distance=3,\n            after_clifford_depolarization=0.1,\n        ).to_file(d / 'a=3.stim')\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / 'a=3.stim'),\n            \"--max_shots\",\n            \"200\",\n            \"--quiet\",\n            \"--metadata_func\",\n            \"auto\",\n            \"--decoders\",\n            \"vacuous\",\n            \"--processes\",\n            \"auto\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n        ])\n        data = sinter.stats_from_csv_files(d / \"out.csv\")\n        assert len(data) == 1\n\n\ndef test_implicit_auto_processes():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        stim.Circuit.generated(\n            'repetition_code:memory',\n            rounds=5,\n            distance=3,\n            after_clifford_depolarization=0.1,\n        ).to_file(d / 'a=3.stim')\n\n        # Collects requested stats.\n        main(command_line_args=[\n            \"collect\",\n            \"--circuits\",\n            str(d / 'a=3.stim'),\n            \"--max_shots\",\n            \"200\",\n            \"--quiet\",\n            \"--metadata_func\",\n            \"auto\",\n            \"--decoders\",\n            \"perfectionist\",\n            \"--save_resume_filepath\",\n            str(d / \"out.csv\"),\n        ])\n        data = sinter.stats_from_csv_files(d / \"out.csv\")\n        assert len(data) == 1\n        assert data[0].discards > 0\n"
  },
  {
    "path": "glue/sample/src/sinter/_command/_main_combine.py",
    "content": "import argparse\nimport collections\nimport json\n\nimport sys\nfrom typing import List, Any\n\nimport sinter\nfrom sinter._data import CSV_HEADER, ExistingData\nfrom sinter._plotting import better_sorted_str_terms\n\n\ndef main_combine(*, command_line_args: List[str]):\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--order',\n                        choices=('preserve', 'metadata', 'error'),\n                        default='metadata',\n                        help='Determines the order of output rows.\\n'\n                             '    metadata (default): sort ascending by metadata.'\n                             '    preserve: match order of input rows.\\n'\n                             '    error: sort ascending by error rate')\n    parser.add_argument('--strip_custom_counts',\n                        help='Removes custom counts from the output.',\n                        action='store_true')\n    parser.add_argument('rest',\n                        nargs=argparse.REMAINDER,\n                        type=str,\n                        help='Paths to CSV files containing sample statistics.')\n    args = parser.parse_args(command_line_args)\n\n    if args.rest:\n        total = ExistingData()\n        for path in args.rest:\n            total += ExistingData.from_file(path)\n    else:\n        total = ExistingData.from_file(sys.stdin)\n\n    total = list(total.data.values())\n\n    if args.strip_custom_counts:\n        total = [\n            sinter.TaskStats(\n                strong_id=task.strong_id,\n                decoder=task.decoder,\n                json_metadata=task.json_metadata,\n                shots=task.shots,\n                errors=task.errors,\n                discards=task.discards,\n                seconds=task.seconds,\n            )\n            for task in total\n        ]\n    else:\n        total = [\n            sinter.TaskStats(\n                strong_id=task.strong_id,\n                decoder=task.decoder,\n                json_metadata=task.json_metadata,\n                shots=task.shots,\n                errors=task.errors,\n                discards=task.discards,\n                seconds=task.seconds,\n                custom_counts=collections.Counter(dict(sorted(task.custom_counts.items(), key=better_sorted_str_terms))),\n            )\n            for task in total\n        ]\n\n    if args.order == 'metadata':\n        output = sorted(total, key=lambda e: better_sorted_str_terms(json.dumps(e.json_metadata, separators=(',', ':'), sort_keys=True)))\n    elif args.order == 'preserve':\n        output = list(total)\n    elif args.order == 'error':\n        def err_rate_key(stats: sinter.TaskStats) -> Any:\n            num_kept = stats.shots - stats.discards\n            err_rate = 0 if num_kept == 0 else stats.errors / num_kept\n            discard_rate = 0 if stats.shots == 0 else stats.discards / stats.shots\n            return err_rate, discard_rate\n        output = sorted(total, key=err_rate_key)\n    else:\n        raise NotImplementedError(f'order={args.order}')\n\n    print(CSV_HEADER)\n    for value in output:\n        print(value.to_csv_line())\n"
  },
  {
    "path": "glue/sample/src/sinter/_command/_main_combine_test.py",
    "content": "import contextlib\nimport io\nimport pathlib\nimport tempfile\n\nfrom sinter._command._main import main\n\n\ndef test_main_combine():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata\n300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"path\"\":\"\"a.stim\"\"}\"\n300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"path\"\":\"\"a.stim\"\"}\"\n9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,\"{\"\"path\"\":\"\"b.stim\"\"}\"\n            \"\"\".strip(), file=f)\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"combine\",\n                str(d / \"input.csv\"),\n            ])\n        assert out.getvalue() == \"\"\"     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts\n       600,       101,       220,    3.00,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"path\"\":\"\"a.stim\"\"}\",\n         9,         5,         4,    6.00,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,\"{\"\"path\"\":\"\"b.stim\"\"}\",\n\"\"\"\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"combine\",\n                str(d / \"input.csv\"),\n                str(d / \"input.csv\"),\n            ])\n        assert out.getvalue() == \"\"\"     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts\n      1200,       202,       440,    6.00,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"path\"\":\"\"a.stim\"\"}\",\n        18,        10,         8,    12.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,\"{\"\"path\"\":\"\"b.stim\"\"}\",\n\"\"\"\n\n\ndef test_main_combine_legacy_custom_counts():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'old.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata\n100,1,20,1.0,pymatching,abc123,\"{\"\"path\"\":\"\"a.stim\"\"}\"\n            \"\"\".strip(), file=f)\n        with open(d / f'new.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata,custom_counts\n300,1,20,1.0,pymatching,abc123,\"{\"\"path\"\":\"\"a.stim\"\"}\",\"{\"\"x\"\":2}\"\n300,1,20,1.0,pymatching,abc123,\"{\"\"path\"\":\"\"a.stim\"\"}\",\"{\"\"y\"\":3}\"\n            \"\"\".strip(), file=f)\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"combine\",\n                str(d / \"old.csv\"),\n                str(d / \"new.csv\"),\n            ])\n        assert out.getvalue() == \"\"\"     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts\n       700,         3,        60,    3.00,pymatching,abc123,\"{\"\"path\"\":\"\"a.stim\"\"}\",\"{\"\"x\"\":2,\"\"y\"\":3}\"\n\"\"\"\n\n\ndef test_order_flag():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,   strong_id,json_metadata\n1000, 100,   4,       2.0,    pymatching,deadbeef0,\"{\"\"d\"\":19}\"\n2000, 300,   3,       3.0,    pymatching,deadbeef1,\"{\"\"d\"\":9}\"\n3000, 200,   2000,    5.0,    pymatching,deadbeef2,\"{\"\"d\"\":200}\"\n4000, 100,   1,       7.0,    pymatching,deadbeef3,\"{\"\"d\"\":3}\"\n5000, 100,   0,       11,     pymatching,deadbeef4,\"{\"\"d\"\":5}\"\n            \"\"\".strip(), file=f)\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"combine\",\n                \"--order\",\n                \"preserve\",\n                str(d / \"input.csv\"),\n                str(d / \"input.csv\"),\n            ])\n        assert out.getvalue() == \"\"\"     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts\n      2000,       200,         8,    4.00,pymatching,deadbeef0,\"{\"\"d\"\":19}\",\n      4000,       600,         6,    6.00,pymatching,deadbeef1,\"{\"\"d\"\":9}\",\n      6000,       400,      4000,    10.0,pymatching,deadbeef2,\"{\"\"d\"\":200}\",\n      8000,       200,         2,    14.0,pymatching,deadbeef3,\"{\"\"d\"\":3}\",\n     10000,       200,         0,    22.0,pymatching,deadbeef4,\"{\"\"d\"\":5}\",\n\"\"\"\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"combine\",\n                \"--order\",\n                \"metadata\",\n                str(d / \"input.csv\"),\n                str(d / \"input.csv\"),\n            ])\n        assert out.getvalue() == \"\"\"     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts\n      8000,       200,         2,    14.0,pymatching,deadbeef3,\"{\"\"d\"\":3}\",\n     10000,       200,         0,    22.0,pymatching,deadbeef4,\"{\"\"d\"\":5}\",\n      4000,       600,         6,    6.00,pymatching,deadbeef1,\"{\"\"d\"\":9}\",\n      2000,       200,         8,    4.00,pymatching,deadbeef0,\"{\"\"d\"\":19}\",\n      6000,       400,      4000,    10.0,pymatching,deadbeef2,\"{\"\"d\"\":200}\",\n\"\"\"\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"combine\",\n                \"--order\",\n                \"error\",\n                str(d / \"input.csv\"),\n                str(d / \"input.csv\"),\n            ])\n        assert out.getvalue() == \"\"\"     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts\n     10000,       200,         0,    22.0,pymatching,deadbeef4,\"{\"\"d\"\":5}\",\n      8000,       200,         2,    14.0,pymatching,deadbeef3,\"{\"\"d\"\":3}\",\n      2000,       200,         8,    4.00,pymatching,deadbeef0,\"{\"\"d\"\":19}\",\n      4000,       600,         6,    6.00,pymatching,deadbeef1,\"{\"\"d\"\":9}\",\n      6000,       400,      4000,    10.0,pymatching,deadbeef2,\"{\"\"d\"\":200}\",\n\"\"\"\n\n\ndef test_order_custom_counts():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,   strong_id,json_metadata,custom_counts\n1000, 100,   4,       2.0,    pymatching,deadbeef0,[],\"{\"\"d4\"\":3,\"\"d2\"\":30}\"\n            \"\"\".strip(), file=f)\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"combine\",\n                str(d / \"input.csv\"),\n            ])\n        assert out.getvalue() == \"\"\"     shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts\n      1000,       100,         4,    2.00,pymatching,deadbeef0,[],\"{\"\"d2\"\":30,\"\"d4\"\":3}\"\n\"\"\"\n"
  },
  {
    "path": "glue/sample/src/sinter/_command/_main_plot.py",
    "content": "import math\nimport sys\nfrom typing import Any, Callable, Iterable, List, Optional, TYPE_CHECKING, Tuple, Union, Dict, Sequence, cast\nimport argparse\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom sinter._command._main_combine import ExistingData\nfrom sinter._plotting import plot_discard_rate, plot_custom\nfrom sinter._plotting import plot_error_rate\nfrom sinter._probability_util import shot_error_rate_to_piece_error_rate, Fit\n\nif TYPE_CHECKING:\n    import sinter\n\n\ndef parse_args(args: List[str]) -> Any:\n    parser = argparse.ArgumentParser(description='Plot collected CSV data.',\n                                     prog='sinter plot')\n    parser.add_argument('--filter_func',\n                        type=str,\n                        default=\"True\",\n                        help='A python expression that determines whether a case is kept or not.\\n'\n                             'Values available to the python expression:\\n'\n                             '    metadata: The parsed value from the json_metadata for the data point.\\n'\n                             '    m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\\n'\n                             '    decoder: The decoder that decoded the data for the data point.\\n'\n                             '    strong_id: The cryptographic hash of the case that was sampled for the data point.\\n'\n                             '    stat: The sinter.TaskStats object for the data point.\\n'\n                             'Expected expression type:\\n'\n                             '    Something that can be given to `bool` to get True or False.\\n'\n                             'Examples:\\n'\n                             '''    --filter_func \"decoder=='pymatching'\"\\n'''\n                             '''    --filter_func \"0.001 < metadata['p'] < 0.005\"\\n''')\n    parser.add_argument('--preprocess_stats_func',\n                        type=str,\n                        default=None,\n                        help='An expression that operates on a `stats` value, returning a new list of stats to plot.\\n'\n                             'For example, this could double add a field to json_metadata or merge stats together.\\n'\n                             'Examples:\\n'\n                             '''    --preprocess_stats_func \"[stat for stat in stats if stat.errors > 0]\\n'''\n                             '''    --preprocess_stats_func \"[stat.with_edits(errors=stat.custom_counts['severe_errors']) for stat in stats]\\n'''\n                             '''    --preprocess_stats_func \"__import__('your_custom_module').your_custom_function(stats)\"\\n'''\n                             )\n    parser.add_argument('--x_func',\n                        type=str,\n                        default=\"1\",\n                        help='A python expression that determines where points go on the x axis.\\n'\n                             'Values available to the python expression:\\n'\n                             '    metadata: The parsed value from the json_metadata for the data point.\\n'\n                             '    m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\\n'\n                             '    decoder: The decoder that decoded the data for the data point.\\n'\n                             '    strong_id: The cryptographic hash of the case that was sampled for the data point.\\n'\n                             '    stat: The sinter.TaskStats object for the data point.\\n'\n                             'Expected expression type:\\n'\n                             '    Something that can be given to `float` to get a float.\\n'\n                             'Examples:\\n'\n                             '''    --x_func \"metadata['p']\"\\n'''\n                             '''    --x_func m.p\\n'''\n                             '''    --x_func \"metadata['path'].split('/')[-1].split('.')[0]\"\\n'''\n                        )\n    parser.add_argument('--point_label_func',\n                        type=str,\n                        default=\"None\",\n                        help='A python expression that determines text to put next to data points.\\n'\n                             'Values available to the python expression:\\n'\n                             '    metadata: The parsed value from the json_metadata for the data point.\\n'\n                             '    m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\\n'\n                             '    decoder: The decoder that decoded the data for the data point.\\n'\n                             '    strong_id: The cryptographic hash of the case that was sampled for the data point.\\n'\n                             '    stat: The sinter.TaskStats object for the data point.\\n'\n                             'Expected expression type:\\n'\n                             '    Something Falsy (no label), or something that can be given to `str` to get a string.\\n'\n                             'Examples:\\n'\n                             '''    --point_label_func \"f'p={m.p}'\"\\n'''\n                        )\n    parser.add_argument('--y_func',\n                        type=str,\n                        default=None,\n                        help='A python expression that determines where points go on the y axis.\\n'\n                             'This argument is not used by error rate or discard rate plots; only\\n'\n                             'by the \"custom_y\" type plot.'\n                             'Values available to the python expression:\\n'\n                             '    metadata: The parsed value from the json_metadata for the data point.\\n'\n                             '    m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\\n'\n                             '    decoder: The decoder that decoded the data for the data point.\\n'\n                             '    strong_id: The cryptographic hash of the case that was sampled for the data point.\\n'\n                             '    stat: The sinter.TaskStats object for the data point.\\n'\n                             'Expected expression type:\\n'\n                             '    A `sinter.Fit` specifying an uncertainty region,.\\n'\n                             '    or else something that can be given to `float` to get a float.\\n'\n                             'Examples:\\n'\n                             '''    --x_func \"metadata['p']\"\\n'''\n                             '''    --x_func \"metadata['path'].split('/')[-1].split('.')[0]\"\\n'''\n                        )\n    parser.add_argument('--fig_size',\n                        type=int,\n                        nargs=2,\n                        default=None,\n                        help='Desired figure width and height in pixels.')\n    parser.add_argument('--dpi',\n                        type=float,\n                        default=100,\n                        help='Dots per inch. Determines resolution of the figure.')\n    parser.add_argument('--group_func',\n                        type=str,\n                        default=\"'all data (use -group_func and -x_func to group into curves)'\",\n                        help='A python expression that determines how points are grouped into curves.\\n'\n                             'If this evaluates to a dict, different keys control different groupings (e.g. \"color\" and \"marker\")\\n'\n                             'Values available to the python expression:\\n'\n                             '    metadata: The parsed value from the json_metadata for the data point.\\n'\n                             '    m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\\n'\n                             '    decoder: The decoder that decoded the data for the data point.\\n'\n                             '    strong_id: The cryptographic hash of the case that was sampled for the data point.\\n'\n                             '    stat: The sinter.TaskStats object for the data point.\\n'\n                             'Expected expression type:\\n'\n                             '    A dict, or something that can be given to `str` to get a useful string.\\n'\n                             'Recognized dict keys:\\n'\n                             '    \"color\": controls color grouping\\n'\n                             '    \"marker\": controls marker grouping\\n'\n                             '    \"linestyle\": controls linestyle grouping\\n'\n                             '    \"order\": controls ordering in the legend\\n'\n                             '    \"label\": the text shown in the legend\\n'\n                             'Examples:\\n'\n                             '''    --group_func \"(decoder, m.d)\"\\n'''\n                             '''    --group_func \"{'color': decoder, 'marker': m.d, 'label': (decoder, m.d)}\"\\n'''\n                             '''    --group_func \"metadata['path'].split('/')[-2]\"\\n'''\n                        )\n    parser.add_argument('--failure_unit_name',\n                        type=str,\n                        default=None,\n                        help='The unit of failure, typically either \"shot\" (the default) or \"round\".\\n'\n                             'If this argument is specified, --failure_units_per_shot_func must also be specified.\\n'''\n                        )\n    parser.add_argument('--failure_units_per_shot_func',\n                        type=str,\n                        default=None,\n                        help='A python expression that evaluates to the number of failure units there are per shot.\\n'\n                             'For example, if the failure unit is rounds, this should be an expression that returns\\n'\n                             'the number of rounds in a shot. Sinter has no way of knowing what you consider a round\\n'\n                             'to be, otherwise.\\n'\n                             '\\n'\n                             'This value is used to rescale the logical error rate plots. For example, if there are 4\\n'\n                             'failure units per shot then a shot error rate of 10%% corresponds to a unit failure rate\\n'\n                             'of 2.7129%%. The conversion formula (assuming less than 50%% error rates) is:\\n'\n                             '\\n'\n                             '    P_unit = 0.5 - 0.5 * (1 - 2 * P_shot)**(1/units_per_shot)\\n'\n                             '\\n'\n                             'Values available to the python expression:\\n'\n                             '    metadata: The parsed value from the json_metadata for the data point.\\n'\n                             '    m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\\n'\n                             '    decoder: The decoder that decoded the data for the data point.\\n'\n                             '    strong_id: The cryptographic hash of the case that was sampled for the data point.\\n'\n                             '    stat: The sinter.TaskStats object for the data point.\\n'\n                             '\\n'\n                             'Expected expression type:\\n'\n                             '    float.\\n'\n                             '\\n'\n                             'Examples:\\n'\n                             '''    --failure_units_per_shot_func \"metadata['rounds']\"\\n'''\n                             '''    --failure_units_per_shot_func m.r\\n'''\n                             '''    --failure_units_per_shot_func \"m.distance * 3\"\\n'''\n                             '''    --failure_units_per_shot_func \"10\"\\n'''\n                        )\n    parser.add_argument('--failure_values_func',\n                        type=str,\n                        default=None,\n                        help='A python expression that evaluates to the number of independent ways a shot can fail.\\n'\n                             'For example, if a shot corresponds to a memory experiment preserving two observables,\\n'\n                             'then the failure unions is 2.\\n'\n                             '\\n'\n                             'This value is necessary to correctly rescale the logical error rate plots when using\\n'\n                             '--failure_values_func. By default it is assumed to be 1.\\n'\n                             '\\n'\n                             'Values available to the python expression:\\n'\n                             '    metadata: The parsed value from the json_metadata for the data point.\\n'\n                             '    m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\\n'\n                             '    decoder: The decoder that decoded the data for the data point.\\n'\n                             '    strong_id: The cryptographic hash of the case that was sampled for the data point.\\n'\n                             '    stat: The sinter.TaskStats object for the data point.\\n'\n                             '\\n'\n                             'Expected expression type:\\n'\n                             '    float.\\n'\n                             '\\n'\n                             'Examples:\\n'\n                             '''    --failure_values_func \"metadata['num_obs']\"\\n'''\n                             '''    --failure_values_func \"2\"\\n'''\n                        )\n    parser.add_argument('--plot_args_func',\n                        type=str,\n                        default='''{}''',\n                        help='A python expression used to customize the look of curves.\\n'\n                             'Values available to the python expression:\\n'\n                             '    index: A unique integer identifying the curve.\\n'\n                             '    key: The group key (returned from --group_func) identifying the curve.\\n'\n                             '    stats: The list of sinter.TaskStats object in the group.\\n'\n                             '    metadata: (From one arbitrary data point in the group.) The parsed value from the json_metadata for the data point.\\n'\n                             '    m: `m.key` is a shorthand for `metadata.get(\"key\", None)`.\\n'\n                             '    decoder: (From one arbitrary data point in the group.) The decoder that decoded the data for the data point.\\n'\n                             '    strong_id: (From one arbitrary data point in the group.) The cryptographic hash of the case that was sampled for the data point.\\n'\n                             '    stat: (From one arbitrary data point in the group.) The sinter.TaskStats object for the data point.\\n'\n                             'Expected expression type:\\n'\n                             '    A dictionary to give to matplotlib plotting functions as a **kwargs argument.\\n'\n                             'Examples:\\n'\n                             \"\"\"    --plot_args_func \"'''{'label': 'curve #' + str(index), 'linewidth': 5}'''\"\\n\"\"\"\n                             \"\"\"    --plot_args_func \"'''{'marker': 'ov*sp^<>8PhH+xXDd|'[index %% 18]}'''\"\\n\"\"\"\n                        )\n    parser.add_argument('--in',\n                        type=str,\n                        nargs='+',\n                        required=True,\n                        help='Input files to get data from.')\n    parser.add_argument('--type',\n                        choices=['error_rate', 'discard_rate', 'custom_y'],\n                        nargs='+',\n                        default=(),\n                        help='Picks the figures to include.')\n    parser.add_argument('--out',\n                        type=str,\n                        default=None,\n                        help='Write the plot to a file instead of showing it.\\n'\n                             '(Use --show to still show the plot.)')\n    parser.add_argument('--xaxis',\n                        type=str,\n                        default='[log]',\n                        help='Customize the X axis label. '\n                             'Prefix [log] for logarithmic scale. '\n                             'Prefix [sqrt] for square root scale.')\n    parser.add_argument('--yaxis',\n                        type=str,\n                        default=None,\n                        help='Customize the Y axis label. '\n                             'Prefix [log] for logarithmic scale. '\n                             'Prefix [sqrt] for square root scale.')\n    parser.add_argument('--custom_error_count_keys',\n                        type=str,\n                        nargs='+',\n                        default=None,\n                        help=\"Replaces the stat's error count with one of its custom counts. Stats \"\n                             \"without this count end up with an error count of 0. Adds the json \"\n                             \"metadata field 'custom_error_count_key' to identify the custom count \"\n                             \"used. Specifying multiple values turns each stat into multiple \"\n                             \"stats.\")\n    parser.add_argument('--show',\n                        action='store_true',\n                        help='Displays the plot in a window even when --out is specified.')\n    parser.add_argument('--xmin',\n                        default=None,\n                        type=float,\n                        help='Forces the minimum value of the x axis.')\n    parser.add_argument('--xmax',\n                        default=None,\n                        type=float,\n                        help='Forces the maximum value of the x axis.')\n    parser.add_argument('--ymin',\n                        default=None,\n                        type=float,\n                        help='Forces the minimum value of the y axis.')\n    parser.add_argument('--ymax',\n                        default=None,\n                        type=float,\n                        help='Forces the maximum value of the y axis.')\n    parser.add_argument('--title',\n                        default=None,\n                        type=str,\n                        help='Sets the title of the plot.')\n    parser.add_argument('--subtitle',\n                        default=None,\n                        type=str,\n                        help='Sets the subtitle of the plot.\\n'\n                             '\\n'\n                             'Note: The pattern \"{common}\" will expand to text including\\n'\n                             'all json metadata values that are the same across all stats.')\n    parser.add_argument('--highlight_max_likelihood_factor',\n                        type=float,\n                        default=1000,\n                        help='The relative likelihood ratio that determines the color highlights around curves.\\n'\n                             'Set this to 1 or larger. Set to 1 to disable highlighting.')\n    parser.add_argument('--line_fits',\n                        action='store_true',\n                        help='Adds dashed line fits to every curve.')\n\n    a = parser.parse_args(args=args)\n    if 'custom_y' in a.type and a.y_func is None:\n        raise ValueError(\"--type custom_y requires --y_func.\")\n    if a.y_func is not None and a.type and 'custom_y' not in a.type:\n        raise ValueError(\"--y_func only works with --type custom_y.\")\n    if (len(a.type) == 0 and a.y_func is not None) or list(a.type) == 'custom_y':\n        if a.failure_units_per_shot_func is not None:\n            raise ValueError(\"--failure_units_per_shot_func doesn't affect --type custom_y\")\n    if (a.failure_units_per_shot_func is not None) != (a.failure_unit_name is not None):\n        raise ValueError(\"--failure_units_per_shot_func and --failure_unit_name can only be specified together.\")\n    if a.failure_values_func is not None and a.failure_units_per_shot_func is None:\n            raise ValueError('Specified --failure_values_func without --failure_units_per_shot_func')\n    if a.failure_units_per_shot_func is None:\n        a.failure_units_per_shot_func = \"1\"\n    if a.failure_values_func is None:\n        a.failure_values_func = \"1\"\n    if a.failure_unit_name is None:\n        a.failure_unit_name = 'shot'\n\n    def _compile_argument_into_func(arg_name: str, arg_val: Any = ()):\n        if arg_val == ():\n            arg_val = getattr(a, arg_name)\n        raw_func = eval(compile(\n            f'lambda *, stat, decoder, metadata, m, strong_id, sinter, math, np: {arg_val}',\n            filename=f'{arg_name}:command_line_arg',\n            mode='eval',\n        ))\n        import sinter\n        return lambda stat: raw_func(\n            sinter=sinter,\n            math=math,\n            np=np,\n            stat=stat,\n            decoder=stat.decoder,\n            metadata=stat.json_metadata,\n            m=_FieldToMetadataWrapper(stat.json_metadata),\n            strong_id=stat.strong_id)\n\n    a.preprocess_stats_func = None if a.preprocess_stats_func is None else eval(compile(\n        f'lambda *, stats: {a.preprocess_stats_func}',\n        filename='preprocess_stats_func:command_line_arg',\n        mode='eval'))\n    a.x_func = _compile_argument_into_func('x_func', a.x_func)\n    if a.y_func is not None:\n        a.y_func = _compile_argument_into_func('y_func')\n    a.point_label_func = _compile_argument_into_func('point_label_func')\n    a.group_func = _compile_argument_into_func('group_func')\n    a.filter_func = _compile_argument_into_func('filter_func')\n    a.failure_units_per_shot_func = _compile_argument_into_func('failure_units_per_shot_func')\n    a.failure_values_func = _compile_argument_into_func('failure_values_func')\n    raw_plot_args_func = eval(compile(\n        f'lambda *, index, key, stats, stat, decoder, metadata, m, strong_id: {a.plot_args_func}',\n        filename='plot_args_func:command_line_arg',\n        mode='eval'))\n    a.plot_args_func = lambda index, group_key, stats: raw_plot_args_func(\n            index=index,\n            key=group_key,\n            stats=stats,\n            stat=stats[0],\n            decoder=stats[0].decoder,\n            metadata=stats[0].json_metadata,\n            m=_FieldToMetadataWrapper(stats[0].json_metadata),\n            strong_id=stats[0].strong_id)\n    return a\n\n\ndef _log_ticks(\n        min_v: float,\n        max_v: float,\n) -> Tuple[float, float, List[float], List[float]]:\n    d0 = math.floor(math.log10(min_v) + 0.0001)\n    d1 = math.ceil(math.log10(max_v) - 0.0001)\n    if d1 == d0:\n        d1 += 1\n        d0 -= 1\n    return (\n        10**d0,\n        10**d1,\n        [10**k for k in range(d0, d1 + 1)],\n        [d*10**k for k in range(d0, d1) for d in range(2, 10)],\n    )\n\n\ndef _sqrt_ticks(\n        min_v: float,\n        max_v: float,\n) -> Tuple[float, float, List[float], List[float]]:\n    if max_v == min_v:\n        max_v *= 2\n        min_v /= 2\n    if max_v == min_v:\n        max_v = 1\n        min_v = 0\n    d = max_v - min_v\n    step = 10**math.floor(math.log10(d))\n    small_step = step / 10\n\n    start_k = math.floor(min_v / step)\n    end_k = math.ceil(max_v / step) + 1\n    major_ticks = [step * k for k in range(start_k, end_k)]\n    if len(major_ticks) < 5:\n        step /= 2\n        start_k = math.floor(min_v / step)\n        end_k = math.ceil(max_v / step) + 1\n        major_ticks = [step * k for k in range(start_k, end_k)]\n\n    small_start_k = math.floor(major_ticks[0] / small_step)\n    small_end_k = math.ceil(major_ticks[-1] / small_step) + 1\n    minor_ticks = [small_step * k for k in range(small_start_k, small_end_k)]\n\n    return (\n        major_ticks[0],\n        major_ticks[-1],\n        major_ticks,\n        minor_ticks,\n    )\n\n\ndef _pick_min_max(\n        *,\n        plotted_stats: Sequence['sinter.TaskStats'],\n        v_func: Callable[['sinter.TaskStats'], Optional[float]],\n        default_min: float,\n        default_max: float,\n        forced_min: Optional[float],\n        forced_max: Optional[float],\n        want_positive: bool,\n        want_strictly_positive: bool,\n) -> Tuple[float, float]:\n    assert default_max >= default_min\n    vs = []\n    for stat in plotted_stats:\n        v = v_func(stat)\n        if isinstance(v, (int, float)):\n            vs.append(v)\n        elif isinstance(v, Fit):\n            for e in [v.low, v.best, v.high]:\n                if e is not None:\n                    vs.append(e)\n        elif v is None:\n            pass\n        else:\n            raise NotImplementedError(f'{v=}')\n    if want_positive:\n        vs = [v for v in vs if v > 0]\n\n    min_v = min(vs, default=default_min)\n    max_v = max(vs, default=default_max)\n    if forced_min is not None:\n        min_v = forced_min\n        max_v = max(min_v, max_v)\n    if forced_max is not None:\n        max_v = forced_max\n        min_v = min(min_v, max_v)\n    if want_positive:\n        assert min_v >= 0\n    if want_strictly_positive:\n        assert min_v > 0\n    assert max_v >= min_v\n\n    return min_v, max_v\n\n\ndef _set_axis_scale_label_ticks(\n        *,\n        ax: Optional[plt.Axes],\n        y_not_x: bool,\n        axis_label: str,\n        default_scale: str = 'linear',\n        default_min_v: float = 0,\n        default_max_v: float = 0,\n        v_func: Callable[['sinter.TaskStats'], Optional[float]],\n        forced_min_v: Optional[float] = None,\n        forced_max_v: Optional[float] = None,\n        plotted_stats: Sequence['sinter.TaskStats'],\n) -> Optional[str]:\n    if ax is None:\n        return None\n    set_scale = ax.set_yscale if y_not_x else ax.set_xscale\n    set_label = ax.set_ylabel if y_not_x else ax.set_xlabel\n    set_lim = cast(Callable[[Optional[float], Optional[float]], None], ax.set_ylim if y_not_x else ax.set_xlim)\n    set_ticks = ax.set_yticks if y_not_x else ax.set_xticks\n\n    if axis_label.startswith('[') and ']' in axis_label:\n        axis_split = axis_label.index(']')\n        scale_name = axis_label[1:axis_split]\n        axis_label = axis_label[axis_split + 1:]\n    else:\n        scale_name = default_scale\n    set_label(axis_label)\n\n    min_v, max_v = _pick_min_max(\n        plotted_stats=plotted_stats,\n        v_func=v_func,\n        default_min=default_min_v,\n        default_max=default_max_v,\n        forced_min=forced_min_v,\n        forced_max=forced_max_v,\n        want_positive=scale_name != 'linear',\n        want_strictly_positive=scale_name == 'log',\n    )\n\n    if scale_name == 'linear':\n        set_lim(min_v, max_v)\n    elif scale_name == 'log':\n        set_scale('log')\n        min_v, max_v, major_ticks, minor_ticks = _log_ticks(min_v, max_v)\n        if forced_min_v is not None:\n            min_v = forced_min_v\n        if forced_max_v is not None:\n            max_v = forced_max_v\n        set_ticks(major_ticks)\n        set_ticks(minor_ticks, minor=True)\n        set_lim(min_v, max_v)\n    elif scale_name == 'sqrt':\n        from matplotlib.scale import FuncScale\n        min_v, max_v, major_ticks, minor_ticks = _sqrt_ticks(min_v, max_v)\n        if forced_min_v is not None:\n            min_v = forced_min_v\n        if forced_max_v is not None:\n            max_v = forced_max_v\n        set_scale(FuncScale(ax, (lambda e: e**0.5, lambda e: e**2)))\n        set_ticks(major_ticks)\n        set_ticks(minor_ticks, minor=True)\n        set_lim(min_v, max_v)\n    else:\n        raise NotImplemented(f'{scale_name=}')\n    return scale_name\n\n\ndef _common_json_properties(stats: List['sinter.TaskStats']) -> Dict[str, Any]:\n    vals = {}\n    for stat in stats:\n        if isinstance(stat.json_metadata, dict):\n            for k in stat.json_metadata:\n                vals[k] = set()\n    for stat in stats:\n        if isinstance(stat.json_metadata, dict):\n            for k in vals:\n                v = stat.json_metadata.get(k)\n                if v is None or isinstance(v, (float, str, int)):\n                    vals[k].add(v)\n    if 'decoder' not in vals:\n        vals['decoder'] = set()\n        for stat in stats:\n            vals['decoder'].add(stat.decoder)\n    return {k: next(iter(v)) for k, v in vals.items() if len(v) == 1}\n\n\ndef _plot_helper(\n    *,\n    samples: Union[Iterable['sinter.TaskStats'], ExistingData],\n    group_func: Callable[['sinter.TaskStats'], Any],\n    filter_func: Callable[['sinter.TaskStats'], Any],\n    preprocess_stats_func: Optional[Callable],\n    failure_units_per_shot_func: Callable[['sinter.TaskStats'], Any],\n    failure_values_func: Callable[['sinter.TaskStats'], Any],\n    x_func: Callable[['sinter.TaskStats'], Any],\n    y_func: Optional[Callable[['sinter.TaskStats'], Any]],\n    failure_unit: str,\n    plot_types: Sequence[str],\n    highlight_max_likelihood_factor: Optional[float],\n    xaxis: str,\n    yaxis: Optional[str],\n    min_y: Optional[float],\n    max_y: Optional[float],\n    max_x: Optional[float],\n    min_x: Optional[float],\n    title: Optional[str],\n    subtitle: Optional[str],\n    fig_size: Optional[Tuple[int, int]],\n    plot_args_func: Callable[[int, Any, List['sinter.TaskStats']], Dict[str, Any]],\n    line_fits: bool,\n    point_label_func: Callable[['sinter.TaskStats'], Any] = lambda _: None,\n    dpi: float,\n) -> Tuple[plt.Figure, List[plt.Axes]]:\n    if isinstance(samples, ExistingData):\n        total = samples\n    else:\n        total = ExistingData()\n        for sample in samples:\n            total.add_sample(sample)\n    total.data = {k: v\n                  for k, v in total.data.items()\n                  if bool(filter_func(v))}\n\n    if preprocess_stats_func is not None:\n        processed_stats = preprocess_stats_func(stats=list(total.data.values()))\n        total.data = {}\n        for stat in processed_stats:\n            total.add_sample(stat)\n\n    if not plot_types:\n        if y_func is not None:\n            plot_types = ['custom_y']\n        else:\n            plot_types = ['error_rate']\n            if any(s.discards for s in total.data.values()):\n                plot_types.append('discard_rate')\n    include_error_rate_plot = 'error_rate' in plot_types\n    include_discard_rate_plot = 'discard_rate' in plot_types\n    include_custom_plot = 'custom_y' in plot_types\n    num_plots = include_error_rate_plot + include_discard_rate_plot + include_custom_plot\n\n    fig: plt.Figure\n    ax_err: Optional[plt.Axes] = None\n    ax_dis: Optional[plt.Axes] = None\n    ax_cus: Optional[plt.Axes] = None\n    fig, axes = plt.subplots(1, num_plots)\n    if num_plots == 1:\n        axes = [axes]\n    axes = list(axes)\n    pop_axes = list(axes)\n    if include_custom_plot:\n        ax_cus = pop_axes.pop()\n    if include_discard_rate_plot:\n        ax_dis = pop_axes.pop()\n    if include_error_rate_plot:\n        ax_err = pop_axes.pop()\n    assert not pop_axes\n\n    plotted_stats: List['sinter.TaskStats'] = [\n        stat\n        for stat in total.data.values()\n    ]\n\n    def stat_to_err_rate(stat: 'sinter.TaskStats') -> Optional[float]:\n        if stat.shots <= stat.discards:\n            return None\n        err_rate = stat.errors / (stat.shots - stat.discards)\n        pieces = failure_units_per_shot_func(stat)\n        return shot_error_rate_to_piece_error_rate(err_rate, pieces=pieces)\n\n    x_scale_name: Optional[str] = None\n    for ax in [ax_err, ax_dis, ax_cus]:\n        v = _set_axis_scale_label_ticks(\n            ax=ax,\n            y_not_x=False,\n            axis_label=xaxis,\n            default_scale='linear',\n            default_min_v=1,\n            default_max_v=10,\n            forced_max_v=max_x,\n            forced_min_v=min_x,\n            plotted_stats=plotted_stats,\n            v_func=x_func,\n        )\n        x_scale_name = x_scale_name or v\n\n    y_scale_name: Optional[str] = None\n    if ax_err is not None:\n        y_scale_name = y_scale_name or _set_axis_scale_label_ticks(\n            ax=ax_err,\n            y_not_x=True,\n            axis_label=f\"Logical Error Rate (per {failure_unit})\" if yaxis is None else yaxis,\n            default_scale='log',\n            forced_max_v=max_y if max_y is not None else 1 if min_y is None or 1 > min_y else None,\n            default_min_v=1e-4,\n            default_max_v=1,\n            forced_min_v=min_y,\n            plotted_stats=plotted_stats,\n            v_func=stat_to_err_rate,\n        )\n        assert x_scale_name is not None\n        assert y_scale_name is not None\n        plot_error_rate(\n            ax=ax_err,\n            stats=plotted_stats,\n            group_func=group_func,\n            x_func=x_func,\n            failure_units_per_shot_func=failure_units_per_shot_func,\n            failure_values_func=failure_values_func,\n            highlight_max_likelihood_factor=highlight_max_likelihood_factor,\n            plot_args_func=plot_args_func,\n            line_fits=None if not line_fits else (x_scale_name, y_scale_name),\n            point_label_func=point_label_func,\n        )\n        ax_err.grid(which='major', color='#000000')\n        ax_err.grid(which='minor', color='#DDDDDD')\n        ax_err.legend()\n\n    if ax_dis is not None:\n        plot_discard_rate(\n            ax=ax_dis,\n            stats=plotted_stats,\n            group_func=group_func,\n            failure_units_per_shot_func=failure_units_per_shot_func,\n            x_func=x_func,\n            highlight_max_likelihood_factor=highlight_max_likelihood_factor,\n            plot_args_func=plot_args_func,\n            point_label_func=point_label_func,\n        )\n        ax_dis.set_yticks([p / 10 for p in range(11)], labels=[f'{10*p}%' for p in range(11)])\n        ax_dis.set_ylim(0, 1)\n        ax_dis.grid(which='major', color='#000000')\n        ax_dis.grid(which='minor', color='#DDDDDD')\n        if yaxis is not None and not include_custom_plot and ax_err is None:\n            ax_dis.set_ylabel(yaxis)\n        else:\n            ax_dis.set_ylabel(f\"Discard Rate (per {failure_unit})\")\n        ax_dis.legend()\n\n    if ax_cus is not None:\n        assert y_func is not None\n        y_scale_name = y_scale_name or _set_axis_scale_label_ticks(\n            ax=ax_cus,\n            y_not_x=True,\n            axis_label='custom' if yaxis is None else yaxis,\n            default_scale='linear',\n            default_min_v=1e-4,\n            default_max_v=1,\n            plotted_stats=plotted_stats,\n            v_func=y_func,\n            forced_min_v=min_y,\n            forced_max_v=max_y,\n        )\n        plot_custom(\n            ax=ax_cus,\n            stats=plotted_stats,\n            x_func=x_func,\n            y_func=y_func,\n            group_func=group_func,\n            plot_args_func=plot_args_func,\n            line_fits=None if not line_fits else (x_scale_name, y_scale_name),\n            point_label_func=point_label_func,\n        )\n        ax_cus.grid(which='major', color='#000000')\n        ax_cus.grid(which='minor', color='#DDDDDD')\n        ax_cus.legend()\n\n    stripped_xaxis = xaxis\n    if stripped_xaxis is not None:\n        if stripped_xaxis.startswith('[') and ']' in stripped_xaxis:\n            stripped_xaxis = stripped_xaxis[stripped_xaxis.index(']') + 1:]\n\n    vs_suffix = ''\n    if stripped_xaxis is not None:\n        vs_suffix = f' vs {stripped_xaxis}'\n    if ax_err is not None:\n        ax_err.set_title(f'Logical Error Rate per {failure_unit}{vs_suffix}')\n        if title is not None:\n            ax_err.set_title(title)\n    if ax_dis is not None:\n        ax_dis.set_title(f'Discard Rate per {failure_unit}{vs_suffix}')\n    if ax_cus is not None:\n        if title is not None:\n            ax_cus.set_title(title)\n        else:\n            ax_cus.set_title(f'Custom Plot')\n    if subtitle is not None:\n        if '{common}' in subtitle:\n            auto_subtitle = ', '.join(f'{k}={v}' for k, v in sorted(_common_json_properties(plotted_stats).items()))\n            subtitle = subtitle.replace('{common}', auto_subtitle)\n        for ax in axes:\n            ax.set_title(ax.title.get_text() + '\\n' + subtitle)\n\n    if fig_size is None:\n        fig.set_dpi(dpi)\n        fig.set_size_inches(1000 * num_plots / dpi, 1000 / dpi)\n    else:\n        w, h = fig_size\n        fig.set_dpi(dpi)\n        fig.set_size_inches(w / dpi, h / dpi)\n    fig.tight_layout()\n    axs = [e for e in [ax_err, ax_dis] if e is not None]\n    return fig, axs\n\n\nclass _FieldToMetadataWrapper:\n    def __init__(self, d: Dict):\n        self.__private_d = d\n\n    def __getattr__(self, item):\n        if isinstance(self.__private_d, dict):\n            return self.__private_d.get(item, None)\n        return None\n\n\ndef main_plot(*, command_line_args: List[str]):\n    args = parse_args(command_line_args)\n    total = ExistingData()\n    for file in getattr(args, 'in'):\n        total += ExistingData.from_file(file)\n\n    if args.custom_error_count_keys:\n        seen_keys = {k for stat in total.data.values() for k in stat.custom_counts}\n        missing = []\n        for k in args.custom_error_count_keys:\n            if k not in seen_keys:\n                missing.append(k)\n        if missing:\n            print(\"Warning: the following custom error count keys didn't appear in any statistic:\", file=sys.stderr)\n            for k in sorted(missing):\n                print(f'    {k!r}', file=sys.stderr)\n            print(\"Here are the keys that do appear:\", file=sys.stderr)\n            for k in sorted(seen_keys):\n                print(f'    {k!r}', file=sys.stderr)\n\n        total.data = {\n            s.strong_id: s\n            for v in total.data.values()\n            for s in v._split_custom_counts(args.custom_error_count_keys)\n        }\n\n    fig, _ = _plot_helper(\n        samples=total,\n        group_func=args.group_func,\n        x_func=args.x_func,\n        point_label_func=args.point_label_func,\n        y_func=args.y_func,\n        filter_func=args.filter_func,\n        failure_units_per_shot_func=args.failure_units_per_shot_func,\n        failure_values_func=args.failure_values_func,\n        plot_args_func=args.plot_args_func,\n        failure_unit=args.failure_unit_name,\n        plot_types=args.type,\n        xaxis=args.xaxis,\n        yaxis=args.yaxis,\n        fig_size=args.fig_size,\n        min_y=args.ymin,\n        max_y=args.ymax,\n        max_x=args.xmax,\n        min_x=args.xmin,\n        highlight_max_likelihood_factor=args.highlight_max_likelihood_factor,\n        title=args.title,\n        subtitle=args.subtitle,\n        line_fits=args.line_fits,\n        preprocess_stats_func=args.preprocess_stats_func,\n        dpi=args.dpi,\n    )\n    if args.out is not None:\n        fig.savefig(args.out, dpi=args.dpi)\n    if args.show or args.out is None:\n        plt.show()\n"
  },
  {
    "path": "glue/sample/src/sinter/_command/_main_plot_test.py",
    "content": "import contextlib\nimport io\nimport pathlib\nimport tempfile\n\nimport pytest\nfrom sinter._command._main import main\nfrom sinter._command._main_plot import _log_ticks, _sqrt_ticks\n\n\ndef test_main_plot():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata\n300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"path\"\":\"\"a.stim\"\"}\"\n300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"path\"\":\"\"a.stim\"\"}\"\n9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,\"{\"\"path\"\":\"\"b.stim\"\"}\"\n            \"\"\".strip(), file=f)\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output.png\"),\n                \"--x_func\",\n                \"int('a' in metadata['path'])\",\n                \"--group_func\",\n                \"decoder\",\n                \"--ymin\",\n                \"1e-3\",\n                \"--title\",\n                \"test_plot\",\n            ])\n        assert (d / \"output.png\").exists()\n\n\ndef test_main_plot_2():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata\n300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"path\"\":\"\"a.stim\"\"}\"\n300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"path\"\":\"\"a.stim\"\"}\"\n9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,\"{\"\"path\"\":\"\"b.stim\"\"}\"\n            \"\"\".strip(), file=f)\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output.png\"),\n                \"--x_func\",\n                \"int('a' in metadata['path'])\",\n                \"--group_func\",\n                \"decoder\",\n                \"--plot_args_func\",\n                \"{'lw': 2, 'color': 'r' if decoder == 'never' else 'b'}\",\n            ])\n        assert (d / \"output.png\").exists()\n\n\ndef test_main_plot_failure_units():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata\n300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"r\"\":15,\"\"d\"\":5}\"\n300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf7,\"{\"\"r\"\":9,\"\"d\"\":3}\"\n9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,\"{\"\"r\"\":6,\"\"d\"\":2}\"\n            \"\"\".strip(), file=f)\n\n        out = io.StringIO()\n        with pytest.raises(ValueError,  match=\"specified together\"):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output.png\"),\n                \"--x_func\",\n                \"metadata['d']\",\n                \"--group_func\",\n                \"decoder\",\n                \"--failure_units_per_shot_func\",\n                \"metadata['r']\",\n            ])\n        with pytest.raises(ValueError,  match=\"specified together\"):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output.png\"),\n                \"--x_func\",\n                \"metadata['d']\",\n                \"--group_func\",\n                \"decoder\",\n                \"--failure_unit_name\",\n                \"Rounds\",\n            ])\n        assert not (d / \"output.png\").exists()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output.png\"),\n                \"--x_func\",\n                \"metadata['d']\",\n                \"--group_func\",\n                \"decoder\",\n                \"--failure_units_per_shot_func\",\n                \"metadata['r']\",\n                \"--failure_unit_name\",\n                \"Rounds\",\n            ])\n        assert (d / \"output.png\").exists()\n\n\ndef test_main_plot_xaxis():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata\n300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"r\"\":15,\"\"d\"\":5}\"\n300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf7,\"{\"\"r\"\":9,\"\"d\"\":3}\"\n9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,\"{\"\"r\"\":6,\"\"d\"\":2}\"\n            \"\"\".strip(), file=f)\n\n        out = io.StringIO()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output.png\"),\n                \"--x_func\",\n                \"metadata['d']\",\n                \"--xaxis\",\n                \"[sqrt]distance root\",\n            ])\n        assert (d / \"output.png\").exists()\n\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output2.png\"),\n                \"--x_func\",\n                \"metadata['d']\",\n                \"--xaxis\",\n                \"[log]distance log\",\n            ])\n        assert (d / \"output2.png\").exists()\n\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output3.png\"),\n                \"--x_func\",\n                \"metadata['d']\",\n                \"--xaxis\",\n                \"distance raw\",\n            ])\n        assert (d / \"output3.png\").exists()\n\n\ndef test_main_plot_custom_y_func():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata\n300,1,20,1.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf6,\"{\"\"r\"\":15,\"\"d\"\":5}\"\n300,100,200,2.0,pymatching,f256bab362f516ebe4d59a08ae67330ff7771ff738757cd738f4b30605ddccf7,\"{\"\"r\"\":9,\"\"d\"\":3}\"\n9,5,4,6.0,pymatching,5fe5a6cd4226b1a910d57e5479d1ba6572e0b3115983c9516360916d1670000f,\"{\"\"r\"\":6,\"\"d\"\":2}\"\n            \"\"\".strip(), file=f)\n\n        out = io.StringIO()\n        with pytest.raises(AttributeError,  match=\"secondsX\"):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output.png\"),\n                \"--x_func\",\n                \"metadata['d']\",\n                \"--group_func\",\n                \"decoder\",\n                \"--y_func\",\n                \"stat.secondsX\",\n                \"--yaxis\",\n                \"test axis\"\n            ])\n        assert not (d / \"output.png\").exists()\n        with contextlib.redirect_stdout(out):\n            main(command_line_args=[\n                \"plot\",\n                \"--in\",\n                str(d / \"input.csv\"),\n                \"--out\",\n                str(d / \"output.png\"),\n                \"--x_func\",\n                \"metadata['d']\",\n                \"--group_func\",\n                \"decoder\",\n                \"--y_func\",\n                \"stat.seconds\",\n                \"--yaxis\",\n                \"test axis\"\n            ])\n        assert (d / \"output.png\").exists()\n\n\ndef test_log_ticks():\n    assert _log_ticks(12, 499) == (\n        10,\n        1000,\n        [10, 100, 1000],\n        [20, 30, 40, 50, 60, 70, 80, 90, 200, 300, 400, 500, 600, 700, 800, 900],\n    )\n\n    assert _log_ticks(1.2, 4.9) == (\n        1,\n        10,\n        [1, 10],\n        [2, 3, 4, 5, 6, 7, 8, 9],\n    )\n\n\ndef test_sqrt_ticks():\n    assert _sqrt_ticks(12, 499) == (\n        0,\n        500,\n        [0, 100, 200, 300, 400, 500],\n        [10*k for k in range(51)],\n    )\n\n    assert _sqrt_ticks(105, 499) == (\n        100,\n        500,\n        [100, 200, 300, 400, 500],\n        [10*k for k in range(10, 51)],\n    )\n\n    assert _sqrt_ticks(305, 590) == (\n        300,\n        600,\n        [300, 350, 400, 450, 500, 550, 600],\n        [10*k for k in range(30, 61)],\n    )\n\n    assert _sqrt_ticks(305000, 590000) == (\n        300000,\n        600000,\n        [300000, 350000, 400000, 450000, 500000, 550000, 600000],\n        [10000*k for k in range(30, 61)],\n    )\n\n\ndef test_main_plot_degenerate_data():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\n                shots,errors,discards,seconds,decoder,strong_id,json_metadata\n                  100,     0,       0,   1.00,magical,000000000,\"{}\"\n            \"\"\".strip(), file=f)\n\n        main(command_line_args=[\n            \"plot\",\n            \"--in\",\n            str(d / \"input.csv\"),\n            \"--out\",\n            str(d / \"output.png\"),\n        ])\n        assert (d / \"output.png\").exists()\n\n\ndef test_main_plot_degenerate_data_sqrt_axis():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\n                shots,errors,discards,seconds,decoder,strong_id,json_metadata\n                  100,     0,       0,   1.00,magical,000000000,\"{}\"\n            \"\"\".strip(), file=f)\n\n        main(command_line_args=[\n            \"plot\",\n            \"--in\",\n            str(d / \"input.csv\"),\n            \"--out\",\n            str(d / \"output.png\"),\n            \"--xaxis\",\n            \"[sqrt]x\",\n        ])\n        assert (d / \"output.png\").exists()\n\n\ndef test_failure_values_func():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\n                shots,errors,discards,seconds,decoder,strong_id,json_metadata\n                 1000,   400,       0,   1.00,magical,000000001,\"{\"\"f\"\":1}\"\n                 1000,   400,       0,   1.00,magical,000000002,\"{\"\"f\"\":2}\"\n                 1000,   400,       0,   1.00,magical,000000003,\"{\"\"f\"\":3}\"\n                 1000,   400,       0,   1.00,magical,000000005,\"{\"\"f\"\":5}\"\n            \"\"\".strip(), file=f)\n\n        main(command_line_args=[\n            \"plot\",\n            \"--in\",\n            str(d / \"input.csv\"),\n            \"--out\",\n            str(d / \"output.png\"),\n            \"--xaxis\",\n            \"values\",\n            \"--x_func\",\n            \"metadata['f']\",\n            \"--subtitle\",\n            \"test\",\n            \"--failure_values_func\",\n            \"metadata['f']\",\n            \"--failure_units_per_shot_func\",\n            \"100\",\n            \"--failure_unit_name\",\n            \"rounds\",\n        ])\n        assert (d / \"output.png\").exists()\n\n\ndef test_m_fields():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\n                shots,errors,discards,seconds,decoder,strong_id,json_metadata\n                 1000,   400,       0,   1.00,magical,000000001,\"{\"\"f\"\":1}\"\n                 1000,   400,       0,   1.00,magical,000000002,\"{\"\"f\"\":2}\"\n                 1000,   400,       0,   1.00,magical,000000003,\"{\"\"f\"\":3}\"\n                 1000,   400,       0,   1.00,magical,000000005,\"{\"\"f\"\":5}\"\n            \"\"\".strip(), file=f)\n\n        main(command_line_args=[\n            \"plot\",\n            \"--in\",\n            str(d / \"input.csv\"),\n            \"--out\",\n            str(d / \"output.png\"),\n            \"--xaxis\",\n            \"values\",\n            \"--x_func\",\n            \"m.f\",\n            \"--group_func\",\n            \"m.g\",\n            \"--subtitle\",\n            \"test\",\n        ])\n        assert (d / \"output.png\").exists()\n\n\ndef test_split_custom_counts():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\n                shots,errors,discards,seconds,decoder,strong_id,json_metadata,custom_counts\n                 1000,   400,       0,   1.00,magical,000000001,\"{\"\"f\"\":1}\",\n                 1000,   400,       0,   1.00,magical,000000002,\"{\"\"f\"\":2}\",\"{\"\"a\"\":3}\"\n                 1000,   400,       0,   1.00,magical,000000003,\"{\"\"f\"\":3}\",\"{\"\"b\"\":3,\"\"c\"\":4}\"\n                 1000,   400,       0,   1.00,magical,000000005,\"{\"\"f\"\":5}\",\n            \"\"\".strip(), file=f)\n\n        main(command_line_args=[\n            \"plot\",\n            \"--in\",\n            str(d / \"input.csv\"),\n            \"--out\",\n            str(d / \"output.png\"),\n            \"--xaxis\",\n            \"values\",\n            \"--x_func\",\n            \"m.f\",\n            \"--group_func\",\n            \"m.g\",\n            \"--subtitle\",\n            \"test\",\n            \"--custom_error_count_keys\",\n            \"a\",\n            \"b\",\n        ])\n        assert (d / \"output.png\").exists()\n\n\ndef test_line_fits():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.csv', 'w') as f:\n            print(\"\"\"\n                shots,errors,discards,seconds,decoder,strong_id,json_metadata,custom_counts\n                 1000,   400,       0,   1.00,magical,000000001,\"{\"\"a\"\":1,\"\"b\"\":1}\",\n                 1000,   400,       0,   1.00,magical,000000002,\"{\"\"a\"\":2,\"\"b\"\":1}\"\n            \"\"\".strip(), file=f)\n\n        main(command_line_args=[\n            \"plot\",\n            \"--in\",\n            str(d / \"input.csv\"),\n            \"--out\",\n            str(d / \"output.png\"),\n            \"--xaxis\",\n            \"values\",\n            \"--x_func\",\n            \"m.a\",\n            \"--group_func\",\n            \"m.b\",\n            \"--xmin\",\n            \"0\",\n            \"--xmax\",\n            \"10\",\n            \"--line_fits\"\n        ])\n        assert (d / \"output.png\").exists()\n"
  },
  {
    "path": "glue/sample/src/sinter/_command/_main_predict.py",
    "content": "import argparse\nfrom typing import Any\nfrom typing import List\n\nfrom sinter._predict import predict_on_disk\n\n\ndef parse_args(args: List[str]) -> Any:\n    parser = argparse.ArgumentParser(\n        description='Predict observable flips from detector data.',\n        prog='sinter predict',\n    )\n    parser.add_argument('--dets',\n                        type=str,\n                        required=True,\n                        help='File to read detection event data from.')\n    parser.add_argument('--dets_format',\n                        type=str,\n                        required=True,\n                        help='Format detection event data is stored in.\\n'\n                             'For example: b8 or 01')\n    parser.add_argument('--dem',\n                        type=str,\n                        required=True,\n                        help='File to read detector error model from.')\n    parser.add_argument('--decoder',\n                        type=str,\n                        required=True,\n                        help='Decoder to use.')\n    parser.add_argument('--obs_out',\n                        type=str,\n                        required=True,\n                        help='Location to write predictions from decoder.')\n    parser.add_argument('--obs_out_format',\n                        type=str,\n                        required=True,\n                        help='Format to write predictions in.')\n\n    parser.add_argument('--postselect_detectors_with_non_zero_4th_coord',\n                        help='Turns on postselection. '\n                             'If any detector with a non-zero 4th coordinate fires, the shot is discarded.',\n                        action='store_true')\n    parser.add_argument('--discards_out',\n                        type=str,\n                        default=None,\n                        help='Location to write whether each shot should be discarded.'\n                             'Specified if and only if --postselect_detectors_with_non_zero_4th_coord.')\n    parser.add_argument('--discards_out_format',\n                        type=str,\n                        default=None,\n                        help='Format to write discard data in.'\n                             'Specified if and only if --postselect_detectors_with_non_zero_4th_coord.')\n    result = parser.parse_args(args)\n\n    if result.postselect_detectors_with_non_zero_4th_coord and result.discards_out is None:\n        raise ValueError(\"Must specify --discards_out to record results of --postselect_detectors_with_non_zero_4th_coord.\")\n    if result.discards_out is not None and result.discards_out_format is None:\n        raise ValueError(\"Must specify --discards_out_format to specify how to record results of --discards_out.\")\n\n    return result\n\n\ndef main_predict(*, command_line_args: List[str]):\n    parsed = parse_args(command_line_args)\n    predict_on_disk(\n        decoder=parsed.decoder,\n        dem_path=parsed.dem,\n        dets_path=parsed.dets,\n        dets_format=parsed.dets_format,\n        obs_out_path=parsed.obs_out,\n        obs_out_format=parsed.obs_out_format,\n        postselect_detectors_with_non_zero_4th_coord=parsed.postselect_detectors_with_non_zero_4th_coord,\n        discards_out_path=parsed.discards_out,\n        discards_out_format=parsed.discards_out_format,\n    )\n"
  },
  {
    "path": "glue/sample/src/sinter/_command/_main_predict_test.py",
    "content": "import pathlib\nimport tempfile\n\nfrom sinter._command._main import main\n\n\ndef test_main_predict():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        with open(d / f'input.dets', 'w') as f:\n            print(\"\"\"\nshot D0\nshot\n            \"\"\", file=f)\n        with open(d / f'input.dem', 'w') as f:\n            print(\"\"\"\nerror(0.1) D0 L0\n            \"\"\", file=f)\n\n        main(command_line_args=[\n            \"predict\",\n            \"--dets\",\n            str(d / \"input.dets\"),\n            \"--dem\",\n            str(d / \"input.dem\"),\n            \"--decoder\",\n            \"pymatching\",\n            \"--dets_format\",\n            \"dets\",\n            \"--obs_out\",\n            str(d / \"output.01\"),\n            \"--obs_out_format\",\n            \"01\",\n        ])\n        with open(d / 'output.01') as f:\n            assert f.read() == '1\\n0\\n'\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/__init__.py",
    "content": "from sinter._data._anon_task_stats import (\n    AnonTaskStats,\n)\nfrom sinter._data._collection_options import (\n    CollectionOptions,\n)\nfrom sinter._data._csv_out import (\n    CSV_HEADER,\n)\nfrom sinter._data._existing_data import (\n    read_stats_from_csv_files,\n    stats_from_csv_files,\n    ExistingData,\n)\nfrom sinter._data._task import (\n    Task,\n)\nfrom sinter._data._task_stats import (\n    TaskStats,\n)\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_anon_task_stats.py",
    "content": "import collections\nimport dataclasses\nfrom typing import Counter, Union, TYPE_CHECKING\nimport numpy as np\n\nif TYPE_CHECKING:\n    from sinter._data._task_stats import TaskStats\n\n\n@dataclasses.dataclass(frozen=True)\nclass AnonTaskStats:\n    \"\"\"Statistics sampled from an unspecified task.\n\n    Attributes:\n        shots: Number of times the task was sampled.\n        errors: Number of times a sample resulted in an error.\n        discards: Number of times a sample resulted in a discard. Note that\n            discarded a task is not an error.\n        seconds: The amount of CPU core time spent sampling the tasks, in\n            seconds.\n        custom_counts: A counter mapping string keys to integer values. Used for\n            tracking arbitrary values, such as per-observable error counts or\n            the number of times detectors fired. The meaning of the information\n            in the counts is not specified; the only requirement is that it\n            should be correct to add each key's counts when merging statistics.\n\n            Although this field is an editable object, it's invalid to edit the\n            counter after the stats object is initialized.\n    \"\"\"\n\n    shots: int = 0\n    errors: int = 0\n    discards: int = 0\n    seconds: float = 0\n    custom_counts: Counter[str] = dataclasses.field(default_factory=collections.Counter)\n\n    def __post_init__(self):\n        assert isinstance(self.errors, (int, np.integer))\n        assert isinstance(self.shots, (int, np.integer))\n        assert isinstance(self.discards, (int, np.integer))\n        assert isinstance(self.seconds, (int, float, np.integer, np.floating))\n        assert isinstance(self.custom_counts, collections.Counter)\n        assert self.errors >= 0\n        assert self.discards >= 0\n        assert self.seconds >= 0\n        assert self.shots >= self.errors + self.discards\n        assert all(isinstance(k, str) and isinstance(v, (int, np.integer)) for k, v in self.custom_counts.items())\n\n    def __repr__(self) -> str:\n        terms = []\n        if self.shots != 0:\n            terms.append(f'shots={self.shots!r}')\n        if self.errors != 0:\n            terms.append(f'errors={self.errors!r}')\n        if self.discards != 0:\n            terms.append(f'discards={self.discards!r}')\n        if self.seconds != 0:\n            terms.append(f'seconds={self.seconds!r}')\n        if self.custom_counts:\n            terms.append(f'custom_counts={self.custom_counts!r}')\n        return f'sinter.AnonTaskStats({\", \".join(terms)})'\n\n    def __add__(self, other: 'AnonTaskStats') -> 'AnonTaskStats':\n        \"\"\"Returns the sum of the statistics from both anonymous stats.\n\n        Adds the shots, the errors, the discards, and the seconds.\n\n        Examples:\n            >>> import sinter\n            >>> a = sinter.AnonTaskStats(\n            ...    shots=100,\n            ...    errors=20,\n            ... )\n            >>> b = sinter.AnonTaskStats(\n            ...    shots=1000,\n            ...    errors=200,\n            ... )\n            >>> a + b\n            sinter.AnonTaskStats(shots=1100, errors=220)\n        \"\"\"\n        if isinstance(other, AnonTaskStats):\n            return AnonTaskStats(\n                shots=self.shots + other.shots,\n                errors=self.errors + other.errors,\n                discards=self.discards + other.discards,\n                seconds=self.seconds + other.seconds,\n                custom_counts=self.custom_counts + other.custom_counts,\n            )\n\n        return NotImplemented\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_anon_task_stats_test.py",
    "content": "import collections\n\nimport sinter\n\n\ndef test_repr():\n    v = sinter.AnonTaskStats(shots=22, errors=3, discards=4, seconds=5)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.AnonTaskStats()\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.AnonTaskStats(shots=22)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.AnonTaskStats(shots=21, errors=4)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.AnonTaskStats(shots=21, discards=4)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.AnonTaskStats(seconds=4)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n\n\ndef test_add():\n    a0 = sinter.AnonTaskStats(shots=220, errors=30, discards=40, seconds=50)\n    b0 = sinter.AnonTaskStats(shots=50, errors=4, discards=3, seconds=2)\n    assert a0 + b0 == sinter.AnonTaskStats(shots=270, errors=34, discards=43, seconds=52)\n    assert a0 + sinter.AnonTaskStats() == a0\n\n    a = sinter.AnonTaskStats(shots=220, errors=30, discards=40, seconds=50, custom_counts=collections.Counter({'a': 10, 'b': 20}))\n    b = sinter.AnonTaskStats(shots=50, errors=4, discards=3, seconds=2, custom_counts=collections.Counter({'a': 1, 'c': 3}))\n    assert a + b == sinter.AnonTaskStats(shots=270, errors=34, discards=43, seconds=52, custom_counts=collections.Counter({'a': 11, 'b': 20, 'c': 3}))\n\n    assert a + sinter.AnonTaskStats() == a\n    assert sinter.AnonTaskStats() + b == b\n\n    assert a + b0 == sinter.AnonTaskStats(shots=270, errors=34, discards=43, seconds=52, custom_counts=collections.Counter({'a': 10, 'b': 20}))\n    assert a0 + b == sinter.AnonTaskStats(shots=270, errors=34, discards=43, seconds=52, custom_counts=collections.Counter({'a': 1, 'c': 3}))\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_collection_options.py",
    "content": "import dataclasses\nfrom typing import Optional, TYPE_CHECKING\n\nif TYPE_CHECKING:\n    import sinter\n\n\n@dataclasses.dataclass(frozen=True)\nclass CollectionOptions:\n    \"\"\"Describes options for how data is collected for a decoding problem.\n\n    Attributes:\n        max_shots: Defaults to None (unused). Stops the sampling process\n            after this many samples have been taken from the circuit.\n        max_errors: Defaults to None (unused). Stops the sampling process\n            after this many errors have been seen in samples taken from the\n            circuit. The actual number sampled errors may be larger due to\n            batching.\n        start_batch_size: Defaults to None (collector's choice). The very\n            first shots taken from the circuit will use a batch of this\n            size, and no other batches will be taken in parallel. Once this\n            initial fact finding batch is done, batches can be taken in\n            parallel and the normal batch size limiting processes take over.\n        max_batch_size: Defaults to None (unused). Limits batches from\n            taking more than this many shots at once. For example, this can\n            be used to ensure memory usage stays below some limit.\n        max_batch_seconds: Defaults to None (unused). When set, the recorded\n            data from previous shots is used to estimate how much time is\n            taken per shot. This information is then used to predict the\n            biggest batch size that can finish in under the given number of\n            seconds. Limits each batch to be no larger than that.\n    \"\"\"\n\n    max_shots: Optional[int] = None\n    max_errors: Optional[int] = None\n    start_batch_size: Optional[int] = None\n    max_batch_size: Optional[int] = None\n    max_batch_seconds: Optional[float] = None\n\n    def __post_init__(self):\n        if self.max_shots is not None and self.max_shots < 0:\n            raise ValueError(f'max_shots is not None and max_shots={self.max_shots} < 0')\n        if self.max_errors is not None and self.max_errors < 0:\n            raise ValueError(f'max_errors is not None and max_errors={self.max_errors} < 0')\n        if self.start_batch_size is not None and self.start_batch_size <= 0:\n            raise ValueError(f'start_batch_size is not None and start_batch_size={self.start_batch_size} <= 0')\n        if self.max_batch_size is not None and self.max_batch_size <= 0:\n            raise ValueError(\n                f'max_batch_size={self.max_batch_size} is not None and max_batch_size <= 0')\n        if self.max_batch_seconds is not None and self.max_batch_seconds <= 0:\n            raise ValueError(\n                f'max_batch_seconds={self.max_batch_seconds} is not None and max_batch_seconds <= 0')\n\n    def __repr__(self) -> str:\n        terms = []\n        if self.max_shots is not None:\n            terms.append(f'max_shots={self.max_shots!r}')\n        if self.max_errors is not None:\n            terms.append(f'max_errors={self.max_errors!r}')\n        if self.start_batch_size is not None:\n            terms.append(f'start_batch_size={self.start_batch_size!r}')\n        if self.max_batch_size is not None:\n            terms.append(f'max_batch_size={self.max_batch_size!r}')\n        if self.max_batch_seconds is not None:\n            terms.append(f'max_batch_seconds={self.max_batch_seconds!r}')\n        return f'sinter.CollectionOptions({\", \".join(terms)})'\n\n    def combine(self, other: 'sinter.CollectionOptions') -> 'sinter.CollectionOptions':\n        \"\"\"Returns a combination of multiple collection options.\n\n        All fields are combined by taking the minimum from both collection\n        options objects, with None treated as being infinitely large.\n\n        Args:\n            other: The collections options to combine with.\n\n        Returns:\n            The combined collection options.\n\n        Examples:\n            >>> import sinter\n            >>> a = sinter.CollectionOptions(\n            ...    max_shots=1_000_000,\n            ...    start_batch_size=100,\n            ... )\n            >>> b = sinter.CollectionOptions(\n            ...    max_shots=100_000,\n            ...    max_errors=100,\n            ... )\n            >>> a.combine(b)\n            sinter.CollectionOptions(max_shots=100000, max_errors=100, start_batch_size=100)\n        \"\"\"\n        return CollectionOptions(\n            max_shots=nullable_min(self.max_shots, other.max_shots),\n            max_errors=nullable_min(self.max_errors, other.max_errors),\n            start_batch_size=nullable_min(self.start_batch_size, other.start_batch_size),\n            max_batch_size=nullable_min(self.max_batch_size, other.max_batch_size),\n            max_batch_seconds=nullable_min(self.max_batch_seconds, other.max_batch_seconds))\n\n\ndef nullable_min(a: Optional[int], b: Optional[int]) -> Optional[int]:\n    if a is None:\n        return b\n    if b is None:\n        return a\n    return min(a, b)\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_collection_options_test.py",
    "content": "import sinter\n\n\ndef test_repr():\n    v = sinter.CollectionOptions()\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.CollectionOptions(max_shots=100)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.CollectionOptions(max_errors=100)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.CollectionOptions(start_batch_size=10)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.CollectionOptions(max_batch_size=100)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.CollectionOptions(max_batch_seconds=30)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n    v = sinter.CollectionOptions(max_shots=100, max_errors=90, start_batch_size=80, max_batch_size=200, max_batch_seconds=30)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n\n\ndef test_combine():\n    a = sinter.CollectionOptions(max_shots=200, max_batch_seconds=300)\n    b = sinter.CollectionOptions(max_errors=100, max_batch_seconds=400)\n    assert a.combine(b) == sinter.CollectionOptions(max_errors=100, max_shots=200, max_batch_seconds=300)\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_csv_out.py",
    "content": "import collections\nimport csv\nimport io\nimport json\nfrom typing import Any, Optional\n\n\ndef escape_csv(text: Any, width: Optional[int]) -> str:\n    output = io.StringIO()\n    csv.writer(output).writerow([text])\n    text = output.getvalue().strip()\n    if width is not None:\n        text = text.rjust(width)\n    return text\n\n\ndef csv_line(*,\n             shots: Any,\n             errors: Any,\n             discards: Any,\n             seconds: Any,\n             decoder: Any,\n             strong_id: Any,\n             json_metadata: Any,\n             custom_counts: Any,\n             is_header: bool = False) -> str:\n    if isinstance(seconds, float):\n        if seconds < 1:\n            seconds = f'{seconds:0.3f}'\n        elif seconds < 10:\n            seconds = f'{seconds:0.2f}'\n        else:\n            seconds = f'{seconds:0.1f}'\n    if not is_header:\n        json_metadata = json.dumps(json_metadata,\n                                   separators=(',', ':'),\n                                   sort_keys=True)\n        if custom_counts:\n            # Ensure all custom_counts values are integers before dumping to JSON\n            for k in custom_counts:\n                custom_counts[k] = int(custom_counts[k])\n            custom_counts = escape_csv(\n                json.dumps(custom_counts,\n                           separators=(',', ':'),\n                           sort_keys=True), None)\n        else:\n            custom_counts = ''\n\n\n    shots = escape_csv(shots, 10)\n    if isinstance(errors, (dict, collections.Counter)):\n        errors = json.dumps(errors, separators=(',', ':'), sort_keys=True)\n    errors = escape_csv(errors, 10)\n    discards = escape_csv(discards, 10)\n    seconds = escape_csv(seconds, 8)\n    decoder = escape_csv(decoder, None)\n    strong_id = escape_csv(strong_id, None)\n    json_metadata = escape_csv(json_metadata, None)\n    return (f'{shots},'\n            f'{errors},'\n            f'{discards},'\n            f'{seconds},'\n            f'{decoder},'\n            f'{strong_id},'\n            f'{json_metadata},'\n            f'{custom_counts}')\n\n\nCSV_HEADER = csv_line(shots='shots',\n                      errors='errors',\n                      discards='discards',\n                      seconds='seconds',\n                      strong_id='strong_id',\n                      decoder='decoder',\n                      json_metadata='json_metadata',\n                      custom_counts='custom_counts',\n                      is_header=True)\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_existing_data.py",
    "content": "import collections\nimport json\nimport pathlib\nfrom typing import Any, Dict, List, TYPE_CHECKING\n\nfrom sinter._data._task_stats import TaskStats\nfrom sinter._data._task import Task\nfrom sinter._data._anon_task_stats import AnonTaskStats\n\nif TYPE_CHECKING:\n    import sinter\n\n\nclass ExistingData:\n    def __init__(self):\n        self.data: Dict[str, TaskStats] = {}\n\n    def stats_for(self, case: Task) -> AnonTaskStats:\n        if isinstance(case, Task):\n            key = case.strong_id()\n        else:\n            raise NotImplementedError(f'{type(case)}')\n        if key not in self.data:\n            return AnonTaskStats()\n        return self.data[key].to_anon_stats()\n\n    def add_sample(self, sample: TaskStats) -> None:\n        k = sample.strong_id\n        current = self.data.get(k)\n        if current is not None:\n            self.data[k] = current + sample\n        else:\n            self.data[k] = sample\n\n    def __iadd__(self, other: 'ExistingData') -> 'ExistingData':\n        for sample in other.data.values():\n            self.add_sample(sample)\n        return self\n\n    @staticmethod\n    def from_file(path_or_file: Any) -> 'ExistingData':\n        expected_fields = {\n            \"shots\",\n            \"discards\",\n            \"errors\",\n            \"seconds\",\n            \"strong_id\",\n            \"decoder\",\n            \"json_metadata\",\n        }\n        # Import is done locally to reduce cost of importing sinter.\n        import csv\n        if isinstance(path_or_file, (str, pathlib.Path)):\n            with open(path_or_file) as csvfile:\n                return ExistingData.from_file(csvfile)\n        reader = csv.DictReader(path_or_file)\n        reader.fieldnames = [e.strip() for e in reader.fieldnames]\n        actual_fields = set(reader.fieldnames)\n        if not (expected_fields <= actual_fields):\n            raise ValueError(\n                f\"Bad CSV data. \"\n                f\"Got columns {sorted(actual_fields)!r} \"\n                f\"but expected columns {sorted(expected_fields)!r}\")\n        has_custom_counts = 'custom_counts' in actual_fields\n        result = ExistingData()\n        for row in reader:\n            if has_custom_counts:\n                custom_counts = row['custom_counts']\n                if custom_counts is None or custom_counts == '':\n                    custom_counts = collections.Counter()\n                else:\n                    custom_counts = json.loads(custom_counts)\n                    if not isinstance(custom_counts, dict) or not all(isinstance(k, str) or not isinstance(v, int) for k, v in custom_counts.items()):\n                        raise ValueError(f\"{row['custom_counts']=} isn't empty or a dictionary from string keys to integer values.\")\n                    custom_counts = collections.Counter(custom_counts)\n            else:\n                custom_counts = collections.Counter()\n            result.add_sample(TaskStats(\n                shots=int(row['shots']),\n                discards=int(row['discards']),\n                errors=int(row['errors']),\n                custom_counts=custom_counts,\n                seconds=float(row['seconds']),\n                strong_id=row['strong_id'],\n                decoder=row['decoder'],\n                json_metadata=json.loads(row['json_metadata']),\n            ))\n        return result\n\n\ndef stats_from_csv_files(*paths_or_files: Any) -> List['sinter.TaskStats']:\n    \"\"\"Reads and aggregates shot statistics from CSV files.\n\n    (An old alias of `read_stats_from_csv_files`, kept around for backwards\n    compatibility.)\n\n    Assumes the CSV file was written by printing `sinter.CSV_HEADER` and then\n    a list of `sinter.TaskStats`. When statistics from the same task appear\n    in multiple files (identified by the strong id being the same), the\n    statistics for that task are folded together (so only the total shots,\n    total errors, etc for each task are included in the results).\n\n    Args:\n        *paths_or_files: Each argument should be either a path (in the form of\n            a string or a pathlib.Path) or a TextIO object (e.g. as returned by\n            `open`). File data is read from each argument.\n\n    Returns:\n        A list of task stats, where each task appears only once in the list and\n        the stats associated with it are the totals aggregated from all files.\n\n    Examples:\n        >>> import sinter\n        >>> import io\n        >>> in_memory_file = io.StringIO()\n        >>> _ = in_memory_file.write('''\n        ...     shots,errors,discards,seconds,decoder,strong_id,json_metadata\n        ...     1000,42,0,0.125,pymatching,9c31908e2b,\"{\"\"d\"\":9}\"\n        ...     3000,24,0,0.125,pymatching,9c31908e2b,\"{\"\"d\"\":9}\"\n        ...     1000,250,0,0.125,pymatching,deadbeef08,\"{\"\"d\"\":7}\"\n        ... '''.strip())\n        >>> _ = in_memory_file.seek(0)\n        >>> stats = sinter.stats_from_csv_files(in_memory_file)\n        >>> for stat in stats:\n        ...     print(repr(stat))\n        sinter.TaskStats(strong_id='9c31908e2b', decoder='pymatching', json_metadata={'d': 9}, shots=4000, errors=66, seconds=0.25)\n        sinter.TaskStats(strong_id='deadbeef08', decoder='pymatching', json_metadata={'d': 7}, shots=1000, errors=250, seconds=0.125)\n    \"\"\"\n    result = ExistingData()\n    for p in paths_or_files:\n        result += ExistingData.from_file(p)\n    return list(result.data.values())\n\n\ndef read_stats_from_csv_files(*paths_or_files: Any) -> List['sinter.TaskStats']:\n    \"\"\"Reads and aggregates shot statistics from CSV files.\n\n    Assumes the CSV file was written by printing `sinter.CSV_HEADER` and then\n    a list of `sinter.TaskStats`. When statistics from the same task appear\n    in multiple files (identified by the strong id being the same), the\n    statistics for that task are folded together (so only the total shots,\n    total errors, etc for each task are included in the results).\n\n    Args:\n        *paths_or_files: Each argument should be either a path (in the form of\n            a string or a pathlib.Path) or a TextIO object (e.g. as returned by\n            `open`). File data is read from each argument.\n\n    Returns:\n        A list of task stats, where each task appears only once in the list and\n        the stats associated with it are the totals aggregated from all files.\n\n    Examples:\n        >>> import sinter\n        >>> import io\n        >>> in_memory_file = io.StringIO()\n        >>> _ = in_memory_file.write('''\n        ...     shots,errors,discards,seconds,decoder,strong_id,json_metadata\n        ...     1000,42,0,0.125,pymatching,9c31908e2b,\"{\"\"d\"\":9}\"\n        ...     3000,24,0,0.125,pymatching,9c31908e2b,\"{\"\"d\"\":9}\"\n        ...     1000,250,0,0.125,pymatching,deadbeef08,\"{\"\"d\"\":7}\"\n        ... '''.strip())\n        >>> _ = in_memory_file.seek(0)\n        >>> stats = sinter.read_stats_from_csv_files(in_memory_file)\n        >>> for stat in stats:\n        ...     print(repr(stat))\n        sinter.TaskStats(strong_id='9c31908e2b', decoder='pymatching', json_metadata={'d': 9}, shots=4000, errors=66, seconds=0.25)\n        sinter.TaskStats(strong_id='deadbeef08', decoder='pymatching', json_metadata={'d': 7}, shots=1000, errors=250, seconds=0.125)\n    \"\"\"\n    result = ExistingData()\n    for p in paths_or_files:\n        result += ExistingData.from_file(p)\n    return list(result.data.values())\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_existing_data_test.py",
    "content": "import collections\nimport pathlib\nimport tempfile\n\nimport sinter\n\n\ndef test_read_stats_from_csv_files():\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n\n        with open(d / 'tmp.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata\n  300,     1,      20,    1.0,pymatching,abc123,\"{\"\"d\"\":3}\"\n 1000,     3,      40,    3.0,pymatching,abc123,\"{\"\"d\"\":3}\"\n 2000,     0,      10,    2.0,pymatching,def456,\"{\"\"d\"\":5}\"\n    \"\"\".strip(), file=f)\n\n        assert sinter.read_stats_from_csv_files(d / 'tmp.csv') == [\n            sinter.TaskStats(strong_id='abc123', decoder='pymatching', json_metadata={'d': 3}, shots=1300, errors=4, discards=60, seconds=4.0),\n            sinter.TaskStats(strong_id='def456', decoder='pymatching', json_metadata={'d': 5}, shots=2000, errors=0, discards=10, seconds=2.0),\n        ]\n\n        with open(d / 'tmp2.csv', 'w') as f:\n            print(\"\"\"\nshots,errors,discards,seconds,decoder,strong_id,json_metadata,custom_counts\n  300,     1,      20,    1.0,pymatching,abc123,\"{\"\"d\"\":3}\",\"{\"\"dets\"\":1234}\"\n 1000,     3,      40,    3.0,pymatching,abc123,\"{\"\"d\"\":3}\",\n 2000,     0,      10,    2.0,pymatching,def456,\"{\"\"d\"\":5}\"\n    \"\"\".strip(), file=f)\n\n        assert sinter.read_stats_from_csv_files(d / 'tmp2.csv') == [\n            sinter.TaskStats(strong_id='abc123', decoder='pymatching', json_metadata={'d': 3}, shots=1300, errors=4, discards=60, seconds=4.0, custom_counts=collections.Counter({'dets': 1234})),\n            sinter.TaskStats(strong_id='def456', decoder='pymatching', json_metadata={'d': 5}, shots=2000, errors=0, discards=10, seconds=2.0),\n        ]\n\n        assert sinter.read_stats_from_csv_files(d / 'tmp.csv', d / 'tmp2.csv') == [\n            sinter.TaskStats(strong_id='abc123', decoder='pymatching', json_metadata={'d': 3}, shots=2600, errors=8, discards=120, seconds=8.0, custom_counts=collections.Counter({'dets': 1234})),\n            sinter.TaskStats(strong_id='def456', decoder='pymatching', json_metadata={'d': 5}, shots=4000, errors=0, discards=20, seconds=4.0),\n        ]\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_task.py",
    "content": "import pathlib\nfrom typing import Any, Dict, Optional, TYPE_CHECKING\n\nimport hashlib\nimport json\nimport math\nfrom typing import Union\n\nimport numpy as np\n\nfrom sinter._data._collection_options import CollectionOptions\n\nif TYPE_CHECKING:\n    import sinter\n    import stim\n\n\nclass Task:\n    \"\"\"A decoding problem that sinter can sample from.\n\n    Attributes:\n        circuit: The annotated noisy circuit to sample detection event data\n            and logical observable data form.\n        decoder: The decoder to use to predict the logical observable data\n            from the detection event data. This can be set to None if it\n            will be specified later (e.g. by the call to `collect`).\n        detector_error_model: Specifies the error model to give to the decoder.\n            Defaults to None, indicating that it should be automatically derived\n            using `stim.Circuit.detector_error_model`.\n        postselection_mask: Defaults to None (unused). A bit packed bitmask\n            identifying detectors that must not fire. Shots where the\n            indicated detectors fire are discarded.\n        postselected_observables_mask: Defaults to None (unused). A bit\n            packed bitmask identifying observable indices to postselect on.\n            Anytime the decoder's predicted flip for one of these\n            observables doesn't agree with the actual measured flip value of\n            the observable, the shot is discarded instead of counting as an\n            error.\n        json_metadata: Defaults to None. Custom additional data describing\n            the problem. Must be JSON serializable. For example, this could\n            be a dictionary with \"physical_error_rate\" and \"code_distance\"\n            keys.\n        collection_options: Specifies custom options for collecting this\n            single task. These options are merged with the global options\n            to determine what happens.\n\n            For example, if a task has `collection_options` set to\n            `sinter.CollectionOptions(max_shots=1000, max_errors=100)` and\n            `sinter.collect` was called with `max_shots=500` and\n            `max_errors=200`, then either 500 shots or 100 errors will be\n            collected for the task (whichever comes first).\n\n    Examples:\n        >>> import sinter\n        >>> import stim\n        >>> task = sinter.Task(\n        ...     circuit=stim.Circuit.generated(\n        ...         'repetition_code:memory',\n        ...         rounds=10,\n        ...         distance=10,\n        ...         before_round_data_depolarization=1e-3,\n        ...     ),\n        ... )\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        circuit: Optional['stim.Circuit'] = None,\n        decoder: Optional[str] = None,\n        detector_error_model: Optional['stim.DetectorErrorModel'] = None,\n        postselection_mask: Optional[np.ndarray] = None,\n        postselected_observables_mask: Optional[np.ndarray] = None,\n        json_metadata: Any = None,\n        collection_options: 'sinter.CollectionOptions' = CollectionOptions(),\n        skip_validation: bool = False,\n        circuit_path: Optional[Union[str, pathlib.Path]] = None,\n        _unvalidated_strong_id: Optional[str] = None,\n    ) -> None:\n        \"\"\"\n        Args:\n            circuit: The annotated noisy circuit to sample detection event data\n                and logical observable data form.\n            decoder: The decoder to use to predict the logical observable data\n                from the detection event data. This can be set to None if it\n                will be specified later (e.g. by the call to `collect`).\n            detector_error_model: Specifies the error model to give to the decoder.\n                Defaults to None, indicating that it should be automatically derived\n                using `stim.Circuit.detector_error_model`.\n            postselection_mask: Defaults to None (unused). A bit packed bitmask\n                identifying detectors that must not fire. Shots where the\n                indicated detectors fire are discarded.\n            postselected_observables_mask: Defaults to None (unused). A bit\n                packed bitmask identifying observable indices to postselect on.\n                Anytime the decoder's predicted flip for one of these\n                observables doesn't agree with the actual measured flip value of\n                the observable, the shot is discarded instead of counting as an\n                error.\n            json_metadata: Defaults to None. Custom additional data describing\n                the problem. Must be JSON serializable. For example, this could\n                be a dictionary with \"physical_error_rate\" and \"code_distance\"\n                keys.\n            collection_options: Specifies custom options for collecting this\n                single task. These options are merged with the global options\n                to determine what happens.\n\n                For example, if a task has `collection_options` set to\n                `sinter.CollectionOptions(max_shots=1000, max_errors=100)` and\n                `sinter.collect` was called with `max_shots=500` and\n                `max_errors=200`, then either 500 shots or 100 errors will be\n                collected for the task (whichever comes first).\n            skip_validation: Defaults to False. Normally the arguments given to\n                this method are checked for consistency (e.g. the detector error\n                model should have the same number of detectors as the circuit).\n                Setting this argument to True will skip doing the consistency\n                checks. Note that this can result in confusing errors later, if\n                the arguments are not actually consistent.\n            circuit_path: Typically set to None. If the circuit isn't specified,\n                this is the filepath to read it from. Not included in the strong\n                id.\n            _unvalidated_strong_id: Must be set to None unless `skip_validation`\n                is set to True. Otherwise, if this is specified then it should\n                be equal to the value returned by self.strong_id().\n        \"\"\"\n        if not skip_validation:\n            if circuit_path is None and circuit is None:\n                raise ValueError('circuit_path is None and circuit is None')\n            if _unvalidated_strong_id is not None:\n                raise ValueError(\"_unvalidated_strong_id is not None and not skip_validation\")\n            dem = detector_error_model\n            if circuit is not None:\n                num_dets = circuit.num_detectors\n                num_obs = circuit.num_observables\n                if dem is not None:\n                    if circuit.num_detectors != dem.num_detectors:\n                        raise ValueError(f\"circuit.num_detectors={num_dets!r} != detector_error_model.num_detectors={dem.num_detectors!r}\")\n                    if num_obs != dem.num_observables:\n                        raise ValueError(f\"circuit.num_observables={num_obs!r} != detector_error_model.num_observables={dem.num_observables!r}\")\n                if postselection_mask is not None:\n                    shape = (math.ceil(num_dets / 8),)\n                    if postselection_mask.shape != shape:\n                        raise ValueError(f\"postselection_mask.shape={postselection_mask.shape!r} != (math.ceil(circuit.num_detectors / 8),)={shape!r}\")\n                if postselected_observables_mask is not None:\n                    shape = (math.ceil(num_obs / 8),)\n                    if postselected_observables_mask.shape != shape:\n                        raise ValueError(f\"postselected_observables_mask.shape={postselected_observables_mask.shape!r} != (math.ceil(circuit.num_observables / 8),)={shape!r}\")\n            if postselection_mask is not None:\n                if not isinstance(postselection_mask, np.ndarray):\n                    raise ValueError(f\"not isinstance(postselection_mask={postselection_mask!r}, np.ndarray)\")\n                if postselection_mask.dtype != np.uint8:\n                    raise ValueError(f\"postselection_mask.dtype={postselection_mask.dtype!r} != np.uint8\")\n            if postselected_observables_mask is not None:\n                if not isinstance(postselected_observables_mask, np.ndarray):\n                    raise ValueError(f\"not isinstance(postselected_observables_mask={postselected_observables_mask!r}, np.ndarray)\")\n                if postselected_observables_mask.dtype != np.uint8:\n                    raise ValueError(f\"postselected_observables_mask.dtype={postselected_observables_mask.dtype!r} != np.uint8\")\n        self.circuit_path = None if circuit_path is None else pathlib.Path(circuit_path)\n        self.circuit = circuit\n        self.decoder = decoder\n        self.detector_error_model = detector_error_model\n        self.postselection_mask = postselection_mask\n        self.postselected_observables_mask = postselected_observables_mask\n        self.json_metadata = json_metadata\n        self.collection_options = collection_options\n        self._unvalidated_strong_id = _unvalidated_strong_id\n\n    def strong_id_value(self) -> Dict[str, Any]:\n        \"\"\"Contains all raw values that affect the strong id.\n\n        This value is converted into the actual strong id by:\n            - Serializing it into text using JSON.\n            - Serializing the JSON text into bytes using UTF8.\n            - Hashing the UTF8 bytes using SHA256.\n\n        Examples:\n            >>> import sinter\n            >>> import stim\n            >>> task = sinter.Task(\n            ...     circuit=stim.Circuit('H 0'),\n            ...     detector_error_model=stim.DetectorErrorModel(),\n            ...     decoder='pymatching',\n            ... )\n            >>> task.strong_id_value()\n            {'circuit': 'H 0', 'decoder': 'pymatching', 'decoder_error_model': '', 'postselection_mask': None, 'json_metadata': None}\n        \"\"\"\n        if self.circuit is None:\n            raise ValueError(\"Can't compute strong_id until `circuit` is set.\")\n        if self.decoder is None:\n            raise ValueError(\"Can't compute strong_id until `decoder` is set.\")\n        if self.detector_error_model is None:\n            raise ValueError(\"Can't compute strong_id until `detector_error_model` is set.\")\n        result = {\n            'circuit': str(self.circuit),\n            'decoder': self.decoder,\n            'decoder_error_model': str(self.detector_error_model),\n            'postselection_mask':\n                None\n                if self.postselection_mask is None\n                else [int(e) for e in self.postselection_mask],\n            'json_metadata': self.json_metadata,\n        }\n        if self.postselected_observables_mask is not None:\n            result['postselected_observables_mask'] = [int(e) for e in self.postselected_observables_mask]\n        return result\n\n    def strong_id_text(self) -> str:\n        \"\"\"The text that is serialized and hashed to get the strong id.\n\n        This value is converted into the actual strong id by:\n            - Serializing into bytes using UTF8.\n            - Hashing the UTF8 bytes using SHA256.\n\n        Examples:\n            >>> import sinter\n            >>> import stim\n            >>> task = sinter.Task(\n            ...     circuit=stim.Circuit('H 0'),\n            ...     detector_error_model=stim.DetectorErrorModel(),\n            ...     decoder='pymatching',\n            ... )\n            >>> task.strong_id_text()\n            '{\"circuit\": \"H 0\", \"decoder\": \"pymatching\", \"decoder_error_model\": \"\", \"postselection_mask\": null, \"json_metadata\": null}'\n        \"\"\"\n        return json.dumps(self.strong_id_value())\n\n    def strong_id_bytes(self) -> bytes:\n        \"\"\"The bytes that are hashed to get the strong id.\n\n        This value is converted into the actual strong id by:\n            - Hashing these bytes using SHA256.\n\n        Examples:\n            >>> import sinter\n            >>> import stim\n            >>> task = sinter.Task(\n            ...     circuit=stim.Circuit('H 0'),\n            ...     detector_error_model=stim.DetectorErrorModel(),\n            ...     decoder='pymatching',\n            ... )\n            >>> task.strong_id_bytes()\n            b'{\"circuit\": \"H 0\", \"decoder\": \"pymatching\", \"decoder_error_model\": \"\", \"postselection_mask\": null, \"json_metadata\": null}'\n        \"\"\"\n        return self.strong_id_text().encode('utf8')\n\n    def _recomputed_strong_id(self) -> str:\n        return hashlib.sha256(self.strong_id_bytes()).hexdigest()\n\n    def strong_id(self) -> str:\n        \"\"\"Computes a cryptographically unique identifier for this task.\n\n        This value is affected by:\n            - The exact circuit.\n            - The exact detector error model.\n            - The decoder.\n            - The json metadata.\n            - The postselection mask.\n\n        Examples:\n            >>> import sinter\n            >>> import stim\n            >>> task = sinter.Task(\n            ...     circuit=stim.Circuit(),\n            ...     detector_error_model=stim.DetectorErrorModel(),\n            ...     decoder='pymatching',\n            ... )\n            >>> task.strong_id()\n            '7424ea021693d4abc1c31c12e655a48779f61a7c2969e457ae4fe400c852bee5'\n        \"\"\"\n        if self._unvalidated_strong_id is None:\n            self._unvalidated_strong_id = self._recomputed_strong_id()\n        return self._unvalidated_strong_id\n\n    def __repr__(self) -> str:\n        terms = []\n        if self.circuit is not None:\n            terms.append(f'circuit={self.circuit!r}')\n        if self.decoder is not None:\n            terms.append(f'decoder={self.decoder!r}')\n        if self.detector_error_model is not None:\n            terms.append(f'detector_error_model={self.detector_error_model!r}')\n        if self.postselection_mask is not None:\n            nd = self.circuit.num_detectors\n            bits = list(np.unpackbits(self.postselection_mask, count=nd, bitorder='little'))\n            terms.append(f'''postselection_mask=np.packbits({bits!r}, bitorder='little')''')\n        if self.postselected_observables_mask is not None:\n            no = self.circuit.num_observables\n            bits = list(np.unpackbits(self.postselected_observables_mask, count=no, bitorder='little'))\n            terms.append(f'''postselected_observables_mask=np.packbits({bits!r}, bitorder='little')''')\n        if self.json_metadata is not None:\n            terms.append(f'json_metadata={self.json_metadata!r}')\n        if self.collection_options != CollectionOptions():\n            terms.append(f'collection_options={self.collection_options!r}')\n        if self.circuit_path is not None:\n            terms.append(f'circuit_path={self.circuit_path!r}')\n        return f'sinter.Task({\", \".join(terms)})'\n\n    def __eq__(self, other: Any) -> bool:\n        if not isinstance(other, Task):\n            return NotImplemented\n        if self._unvalidated_strong_id is not None and other._unvalidated_strong_id is not None:\n            return self._unvalidated_strong_id == other._unvalidated_strong_id\n        return (\n            self.circuit_path == other.circuit_path and\n            self.circuit == other.circuit and\n            self.decoder == other.decoder and\n            self.detector_error_model == other.detector_error_model and\n            np.array_equal(self.postselection_mask, other.postselection_mask) and\n            np.array_equal(self.postselected_observables_mask, other.postselected_observables_mask) and\n            self.json_metadata == other.json_metadata and\n            self.collection_options == other.collection_options\n        )\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_task_stats.py",
    "content": "import collections\nimport dataclasses\nfrom typing import Counter, List, Any\nfrom typing import Optional\nfrom typing import Union\nfrom typing import overload\nimport numpy as np\nfrom sinter._data._anon_task_stats import AnonTaskStats\nfrom sinter._data._csv_out import csv_line\n\n\ndef _is_equal_json_values(json1: Any, json2: Any):\n    if json1 == json2:\n        return True\n\n    if type(json1) == type(json2):\n        if isinstance(json1, dict):\n            return json1.keys() == json2.keys() and all(_is_equal_json_values(json1[k], json2[k]) for k in json1.keys())\n        elif isinstance(json1, (list, tuple)):\n            return len(json1) == len(json2) and all(_is_equal_json_values(a, b) for a, b in zip(json1, json2))\n    elif isinstance(json1, (list, tuple)) and isinstance(json2, (list, tuple)):\n        return _is_equal_json_values(tuple(json1), tuple(json2))\n\n    return False\n\n\n@dataclasses.dataclass(frozen=True)\nclass TaskStats:\n    \"\"\"Statistics sampled from a task.\n\n    The rows in the CSV files produced by sinter correspond to instances of\n    `sinter.TaskStats`. For example, a row can be produced by printing a\n    `sinter.TaskStats`.\n\n    Attributes:\n        strong_id: The cryptographically unique identifier of the task, from\n            `sinter.Task.strong_id()`.\n        decoder: The name of the decoder that was used to decode the task.\n            Errors are counted when this decoder made a wrong prediction.\n        json_metadata: A JSON-encodable value (such as a dictionary from strings\n            to integers) that were included with the task in order to describe\n            what the task was. This value can be a huge variety of things, but\n            typically it will be a dictionary with fields such as 'd' for the\n            code distance.\n        shots: Number of times the task was sampled.\n        errors: Number of times a sample resulted in an error.\n        discards: Number of times a sample resulted in a discard. Note that\n            discarded a task is not an error.\n        seconds: The amount of CPU core time spent sampling the tasks, in\n            seconds.\n        custom_counts: A counter mapping string keys to integer values. Used for\n            tracking arbitrary values, such as per-observable error counts or\n            the number of times detectors fired. The meaning of the information\n            in the counts is not specified; the only requirement is that it\n            should be correct to add each key's counts when merging statistics.\n\n            Although this field is an editable object, it's invalid to edit the\n            counter after the stats object is initialized.\n    \"\"\"\n\n    # Information describing the problem that was sampled.\n    strong_id: str\n    decoder: str\n    json_metadata: Any\n\n    # Information describing the results of sampling.\n    shots: int = 0\n    errors: int = 0\n    discards: int = 0\n    seconds: float = 0\n    custom_counts: Counter[str] = dataclasses.field(default_factory=collections.Counter)\n\n    def __post_init__(self):\n        assert isinstance(self.errors, (int, np.integer))\n        assert isinstance(self.shots, (int, np.integer))\n        assert isinstance(self.discards, (int, np.integer))\n        assert isinstance(self.seconds, (int, float, np.integer, np.floating))\n        assert isinstance(self.custom_counts, collections.Counter)\n        assert isinstance(self.decoder, str)\n        assert isinstance(self.strong_id, str)\n        assert self.json_metadata is None or isinstance(self.json_metadata, (int, float, str, dict, list, tuple))\n        assert self.errors >= 0\n        assert self.discards >= 0\n        assert self.seconds >= 0\n        assert self.shots >= self.errors + self.discards\n        assert all(isinstance(k, str) and isinstance(v, (int, np.integer)) for k, v in self.custom_counts.items())\n\n    def with_edits(\n        self,\n        *,\n        strong_id: Optional[str] = None,\n        decoder: Optional[str] = None,\n        json_metadata: Optional[Any] = None,\n        shots: Optional[int] = None,\n        errors: Optional[int] = None,\n        discards: Optional[int] = None,\n        seconds: Optional[float] = None,\n        custom_counts: Optional[Counter[str]] = None,\n    ) -> 'TaskStats':\n        return TaskStats(\n            strong_id=self.strong_id if strong_id is None else strong_id,\n            decoder=self.decoder if decoder is None else decoder,\n            json_metadata=self.json_metadata if json_metadata is None else json_metadata,\n            shots=self.shots if shots is None else shots,\n            errors=self.errors if errors is None else errors,\n            discards=self.discards if discards is None else discards,\n            seconds=self.seconds if seconds is None else seconds,\n            custom_counts=self.custom_counts if custom_counts is None else custom_counts,\n        )\n\n    @overload\n    def __add__(self, other: AnonTaskStats) -> AnonTaskStats:\n        pass\n    @overload\n    def __add__(self, other: 'TaskStats') -> 'TaskStats':\n        pass\n    def __add__(self, other: Union[AnonTaskStats, 'TaskStats']) -> Union[AnonTaskStats, 'TaskStats']:\n        if isinstance(other, AnonTaskStats):\n            return self.to_anon_stats() + other\n\n        if isinstance(other, TaskStats):\n            if self.strong_id != other.strong_id:\n                raise ValueError(f'{self.strong_id=} != {other.strong_id=}')\n            if not _is_equal_json_values(self.json_metadata, other.json_metadata) or self.decoder != other.decoder:\n                raise ValueError(\n                    \"A stat had the same strong id as another, but their other identifying information (json_metadata, decoder) differed.\\n\"\n                    \"The strong id is supposed to be a cryptographic hash that uniquely identifies what was sampled, so this is an error.\\n\"\n                    \"\\n\"\n                    \"This failure can occur when post-processing data (e.g. combining X basis stats and Z basis stats into synthetic both-basis stats).\\n\"\n                    \"To fix it, ensure any post-processing sets the strong id of the synthetic data in some cryptographically secure way.\\n\"\n                    \"\\n\"\n                    \"In some cases this can be caused by attempting to add a value that has gone through JSON serialization+parsing to one\\n\"\n                    \"that hasn't, which causes things like tuples transforming into lists.\\n\"\n                    \"\\n\"\n                    f\"The two stats:\\n1. {self!r}\\n2. {other!r}\")\n\n            total = self.to_anon_stats() + other.to_anon_stats()\n            return TaskStats(\n                decoder=self.decoder,\n                strong_id=self.strong_id,\n                json_metadata=self.json_metadata,\n                shots=total.shots,\n                errors=total.errors,\n                discards=total.discards,\n                seconds=total.seconds,\n                custom_counts=total.custom_counts,\n            )\n\n        return NotImplemented\n    __radd__ = __add__\n\n    def to_anon_stats(self) -> AnonTaskStats:\n        \"\"\"Returns a `sinter.AnonTaskStats` with the same statistics.\n\n        Examples:\n            >>> import sinter\n            >>> stat = sinter.TaskStats(\n            ...     strong_id='test',\n            ...     json_metadata={'a': [1, 2, 3]},\n            ...     decoder='pymatching',\n            ...     shots=22,\n            ...     errors=3,\n            ...     discards=4,\n            ...     seconds=5,\n            ... )\n            >>> stat.to_anon_stats()\n            sinter.AnonTaskStats(shots=22, errors=3, discards=4, seconds=5)\n        \"\"\"\n        return AnonTaskStats(\n            shots=self.shots,\n            errors=self.errors,\n            discards=self.discards,\n            seconds=self.seconds,\n            custom_counts=self.custom_counts.copy(),\n        )\n\n    def to_csv_line(self) -> str:\n        \"\"\"Converts into a line that can be printed into a CSV file.\n\n        Examples:\n            >>> import sinter\n            >>> stat = sinter.TaskStats(\n            ...     strong_id='test',\n            ...     json_metadata={'a': [1, 2, 3]},\n            ...     decoder='pymatching',\n            ...     shots=22,\n            ...     errors=3,\n            ...     seconds=5,\n            ... )\n            >>> print(sinter.CSV_HEADER)\n                 shots,    errors,  discards, seconds,decoder,strong_id,json_metadata,custom_counts\n            >>> print(stat.to_csv_line())\n                    22,         3,         0,    5.00,pymatching,test,\"{\"\"a\"\":[1,2,3]}\",\n        \"\"\"\n        return csv_line(\n            shots=int(self.shots),\n            errors=int(self.errors),\n            seconds=float(self.seconds),\n            discards=int(self.discards),\n            strong_id=self.strong_id,\n            decoder=self.decoder,\n            json_metadata=self.json_metadata,\n            custom_counts=self.custom_counts,\n        )\n\n    def _split_custom_counts(self, custom_keys: List[str]) -> List['TaskStats']:\n        result = []\n        for k in custom_keys:\n            m = self.json_metadata\n            if isinstance(m, dict):\n                m = dict(m)\n                m.setdefault('custom_error_count_key', k)\n                m.setdefault('original_error_count', self.errors)\n            result.append(TaskStats(\n                strong_id=f'{self.strong_id}:{k}',\n                decoder=self.decoder,\n                json_metadata=m,\n                shots=self.shots,\n                errors=self.custom_counts[k],\n                discards=self.discards,\n                seconds=self.seconds,\n                custom_counts=self.custom_counts,\n            ))\n        return result\n\n    def __str__(self) -> str:\n        return self.to_csv_line()\n\n    def __repr__(self) -> str:\n        terms = []\n        terms.append(f'strong_id={self.strong_id!r}')\n        terms.append(f'decoder={self.decoder!r}')\n        terms.append(f'json_metadata={self.json_metadata!r}')\n        if self.shots:\n            terms.append(f'shots={self.shots!r}')\n        if self.errors:\n            terms.append(f'errors={self.errors!r}')\n        if self.discards:\n            terms.append(f'discards={self.discards!r}')\n        if self.seconds:\n            terms.append(f'seconds={self.seconds!r}')\n        if self.custom_counts:\n            terms.append(f'custom_counts={self.custom_counts!r}')\n        return f'sinter.TaskStats({\", \".join(terms)})'\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_task_stats_test.py",
    "content": "import collections\n\nimport pytest\n\nimport sinter\nfrom sinter._data._task_stats import _is_equal_json_values\n\n\ndef test_repr():\n    v = sinter.TaskStats(\n        strong_id='test',\n        json_metadata={'a': [1, 2, 3]},\n        decoder='pymatching',\n        shots=22,\n        errors=3,\n        discards=4,\n        seconds=5,\n    )\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n\n\ndef test_to_csv_line():\n    v = sinter.TaskStats(\n        strong_id='test',\n        json_metadata={'a': [1, 2, 3]},\n        decoder='pymatching',\n        shots=22,\n        errors=3,\n        discards=4,\n        seconds=5,\n    )\n    assert v.to_csv_line() == str(v) == '        22,         3,         4,    5.00,pymatching,test,\"{\"\"a\"\":[1,2,3]}\",'\n\n\ndef test_to_anon_stats():\n    v = sinter.TaskStats(\n        strong_id='test',\n        json_metadata={'a': [1, 2, 3]},\n        decoder='pymatching',\n        shots=22,\n        errors=3,\n        discards=4,\n        seconds=5,\n    )\n    assert v.to_anon_stats() == sinter.AnonTaskStats(shots=22, errors=3, discards=4, seconds=5)\n\n\ndef test_add():\n    a = sinter.TaskStats(\n        decoder='pymatching',\n        json_metadata={'a': 2},\n        strong_id='abcdef',\n        shots=220,\n        errors=30,\n        discards=40,\n        seconds=50,\n        custom_counts=collections.Counter({'a': 10, 'b': 20}),\n    )\n    b = sinter.TaskStats(\n        decoder='pymatching',\n        json_metadata={'a': 2},\n        strong_id='abcdef',\n        shots=50,\n        errors=4,\n        discards=3,\n        seconds=2,\n        custom_counts=collections.Counter({'a': 1, 'c': 3}),\n    )\n    c = sinter.TaskStats(\n        decoder='pymatching',\n        json_metadata={'a': 2},\n        strong_id='abcdef',\n        shots=270,\n        errors=34,\n        discards=43,\n        seconds=52,\n        custom_counts=collections.Counter({'a': 11, 'b': 20, 'c': 3}),\n    )\n    assert a + b == c\n    with pytest.raises(ValueError):\n        a + sinter.TaskStats(\n            decoder='pymatching',\n            json_metadata={'a': 2},\n            strong_id='abcdefDIFFERENT',\n            shots=270,\n            errors=34,\n            discards=43,\n            seconds=52,\n            custom_counts=collections.Counter({'a': 11, 'b': 20, 'c': 3}),\n        )\n\n\ndef test_with_edits():\n    v = sinter.TaskStats(\n        decoder='pymatching',\n        json_metadata={'a': 2},\n        strong_id='abcdefDIFFERENT',\n        shots=270,\n        errors=34,\n        discards=43,\n        seconds=52,\n        custom_counts=collections.Counter({'a': 11, 'b': 20, 'c': 3}),\n    )\n    assert v.with_edits(json_metadata={'b': 3}) == sinter.TaskStats(\n        decoder='pymatching',\n        json_metadata={'b': 3},\n        strong_id='abcdefDIFFERENT',\n        shots=270,\n        errors=34,\n        discards=43,\n        seconds=52,\n        custom_counts=collections.Counter({'a': 11, 'b': 20, 'c': 3}),\n    )\n    assert v == sinter.TaskStats(strong_id='', json_metadata={}, decoder='').with_edits(\n        decoder='pymatching',\n        json_metadata={'a': 2},\n        strong_id='abcdefDIFFERENT',\n        shots=270,\n        errors=34,\n        discards=43,\n        seconds=52,\n        custom_counts=collections.Counter({'a': 11, 'b': 20, 'c': 3}),\n    )\n\n\ndef test_is_equal_json_values():\n    assert _is_equal_json_values([1, 2], (1, 2))\n    assert _is_equal_json_values([1, [3, (5, 6)]], (1, (3, [5, 6])))\n    assert not _is_equal_json_values([1, [3, (5, 6)]], (1, (3, [5, 7])))\n    assert not _is_equal_json_values([1, [3, (5, 6)]], (1, (3, [5])))\n    assert not _is_equal_json_values([1, 2], (1, 3))\n    assert not _is_equal_json_values([1, 2], {1, 2})\n    assert _is_equal_json_values({'x': [1, 2]}, {'x': (1, 2)})\n    assert _is_equal_json_values({'x': (1, 2)}, {'x': (1, 2)})\n    assert not _is_equal_json_values({'x': (1, 2)}, {'y': (1, 2)})\n    assert not _is_equal_json_values({'x': (1, 2)}, {'x': (1, 2), 'y': []})\n    assert not _is_equal_json_values({'x': (1, 2), 'y': []}, {'x': (1, 2)})\n    assert not _is_equal_json_values({'x': (1, 2)}, {'x': (1, 3)})\n    assert not _is_equal_json_values(1, 2)\n    assert _is_equal_json_values(1, 1)\n"
  },
  {
    "path": "glue/sample/src/sinter/_data/_task_test.py",
    "content": "import numpy as np\n\nimport stim\n\nimport sinter\n\n\ndef test_repr():\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0 1 2\n        M 0 1 2\n        DETECTOR rec[-1] rec[-2]\n        DETECTOR rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    v = sinter.Task(circuit=circuit)\n    assert eval(repr(v), {\"stim\": stim, \"sinter\": sinter, \"np\": np}) == v\n\n    v = sinter.Task(circuit=circuit, detector_error_model=circuit.detector_error_model())\n    assert eval(repr(v), {\"stim\": stim, \"sinter\": sinter, \"np\": np}) == v\n\n    v = sinter.Task(circuit=circuit, postselection_mask=np.array([1], dtype=np.uint8))\n    assert eval(repr(v), {\"stim\": stim, \"sinter\": sinter, \"np\": np}) == v\n\n    v = sinter.Task(circuit=circuit, postselection_mask=np.array([2], dtype=np.uint8))\n    assert eval(repr(v), {\"stim\": stim, \"sinter\": sinter, \"np\": np}) == v\n\n    v = sinter.Task(circuit=circuit, postselected_observables_mask=np.array([1], dtype=np.uint8))\n    assert eval(repr(v), {\"stim\": stim, \"sinter\": sinter, \"np\": np}) == v\n\n    v = sinter.Task(circuit=circuit, collection_options=sinter.CollectionOptions(max_shots=10))\n    assert eval(repr(v), {\"stim\": stim, \"sinter\": sinter, \"np\": np}) == v\n\n    v = sinter.Task(circuit=circuit, json_metadata={'a': 5})\n    assert eval(repr(v), {\"stim\": stim, \"sinter\": sinter, \"np\": np}) == v\n\n    v = sinter.Task(circuit=circuit, decoder='pymatching')\n    assert eval(repr(v), {\"stim\": stim, \"sinter\": sinter, \"np\": np}) == v\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/__init__.py",
    "content": "from sinter._decoding._decoding import (\n    streaming_post_select,\n    sample_decode,\n)\nfrom sinter._decoding._decoding_decoder_class import (\n    CompiledDecoder,\n    Decoder,\n)\nfrom sinter._decoding._decoding_all_built_in_decoders import (\n    BUILT_IN_DECODERS,\n    BUILT_IN_SAMPLERS,\n)\nfrom sinter._decoding._sampler import (\n    Sampler,\n    CompiledSampler,\n)\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_decoding.py",
    "content": "import collections\nfrom typing import Iterable\nfrom typing import Optional, Dict, Tuple, TYPE_CHECKING, Union\n\nimport contextlib\nimport pathlib\nimport tempfile\nimport math\nimport time\n\nimport numpy as np\nimport stim\n\nfrom sinter._data import AnonTaskStats\nfrom sinter._decoding._decoding_all_built_in_decoders import BUILT_IN_DECODERS\nfrom sinter._decoding._decoding_decoder_class import CompiledDecoder, Decoder\n\nif TYPE_CHECKING:\n    import sinter\n\n\ndef streaming_post_select(*,\n                          num_dets: int,\n                          num_obs: int,\n                          dets_in_b8: pathlib.Path,\n                          obs_in_b8: Optional[pathlib.Path],\n                          dets_out_b8: pathlib.Path,\n                          obs_out_b8: Optional[pathlib.Path],\n                          discards_out_b8: Optional[pathlib.Path],\n                          num_shots: int,\n                          post_mask: np.ndarray) -> int:\n    if post_mask.shape != ((num_dets + 7) // 8,):\n        raise ValueError(f\"post_mask.shape={post_mask.shape} != (math.ceil(num_detectors / 8),)\")\n    if post_mask.dtype != np.uint8:\n        raise ValueError(f\"post_mask.dtype={post_mask.dtype} != np.uint8\")\n    assert (obs_in_b8 is None) == (obs_out_b8 is None)\n\n    num_det_bytes = math.ceil(num_dets / 8)\n    num_obs_bytes = math.ceil(num_obs / 8)\n    num_shots_left = num_shots\n    num_discards = 0\n\n    with contextlib.ExitStack() as ctx:\n        dets_in_f = ctx.enter_context(open(dets_in_b8, 'rb'))\n        dets_out_f = ctx.enter_context(open(dets_out_b8, 'wb'))\n        if obs_in_b8 is not None and obs_out_b8 is not None:\n            obs_in_f = ctx.enter_context(open(obs_in_b8, 'rb'))\n            obs_out_f = ctx.enter_context(open(obs_out_b8, 'wb'))\n        else:\n            obs_in_f = None\n            obs_out_f = None\n        if discards_out_b8 is not None:\n            discards_out_f = ctx.enter_context(open(discards_out_b8, 'wb'))\n        else:\n            discards_out_f = None\n\n        while num_shots_left:\n            batch_size = min(num_shots_left, math.ceil(10 ** 6 / max(1, num_dets)))\n\n            det_batch = np.fromfile(dets_in_f, dtype=np.uint8, count=num_det_bytes * batch_size)\n            det_batch.shape = (batch_size, num_det_bytes)\n            discarded = np.any(det_batch & post_mask, axis=1)\n            det_left = det_batch[~discarded, :]\n            det_left.tofile(dets_out_f)\n\n            if obs_in_f is not None and obs_out_f is not None:\n                obs_batch = np.fromfile(obs_in_f, dtype=np.uint8, count=num_obs_bytes * batch_size)\n                obs_batch.shape = (batch_size, num_obs_bytes)\n                obs_left = obs_batch[~discarded, :]\n                obs_left.tofile(obs_out_f)\n            if discards_out_f is not None:\n                discarded.tofile(discards_out_f)\n\n            num_discards += np.count_nonzero(discarded)\n            num_shots_left -= batch_size\n\n    return num_discards\n\n\ndef _streaming_count_mistakes(\n        *,\n        num_shots: int,\n        num_obs: int,\n        num_det: int,\n        postselected_observable_mask: Optional[np.ndarray] = None,\n        dets_in: pathlib.Path,\n        obs_in: pathlib.Path,\n        predictions_in: pathlib.Path,\n        count_detection_events: bool,\n        count_observable_error_combos: bool,\n) -> Tuple[int, int, collections.Counter]:\n\n    num_det_bytes = math.ceil(num_det / 8)\n    num_obs_bytes = math.ceil(num_obs / 8)\n    num_errors = 0\n    num_discards = 0\n    custom_counts = collections.Counter()\n    if count_detection_events:\n        with open(dets_in, 'rb') as dets_in_f:\n            num_shots_left = num_shots\n            while num_shots_left:\n                batch_size = min(num_shots_left, math.ceil(10**6 / max(num_obs, 1)))\n                det_data = np.fromfile(dets_in_f, dtype=np.uint8, count=num_det_bytes * batch_size)\n                for b in range(8):\n                    custom_counts['detection_events'] += np.count_nonzero(det_data & (1 << b))\n                num_shots_left -= batch_size\n        custom_counts['detectors_checked'] += num_shots * num_det\n\n    with open(obs_in, 'rb') as obs_in_f:\n        with open(predictions_in, 'rb') as predictions_in_f:\n            num_shots_left = num_shots\n            while num_shots_left:\n                batch_size = min(num_shots_left, math.ceil(10**6 / max(num_obs, 1)))\n\n                obs_batch = np.fromfile(obs_in_f, dtype=np.uint8, count=num_obs_bytes * batch_size)\n                pred_batch = np.fromfile(predictions_in_f, dtype=np.uint8, count=num_obs_bytes * batch_size)\n                obs_batch.shape = (batch_size, num_obs_bytes)\n                pred_batch.shape = (batch_size, num_obs_bytes)\n\n                cmp_table = pred_batch ^ obs_batch\n                err_mask = np.any(cmp_table, axis=1)\n                if postselected_observable_mask is not None:\n                    discard_mask = np.any(cmp_table & postselected_observable_mask, axis=1)\n                    err_mask &= ~discard_mask\n                    num_discards += np.count_nonzero(discard_mask)\n\n                if count_observable_error_combos:\n                    for misprediction_arr in cmp_table[err_mask]:\n                        err_key = \"obs_mistake_mask=\" + ''.join('_E'[b] for b in np.unpackbits(misprediction_arr, count=num_obs, bitorder='little'))\n                        custom_counts[err_key] += 1\n\n                num_errors += np.count_nonzero(err_mask)\n                num_shots_left -= batch_size\n    return num_discards, num_errors, custom_counts\n\n\ndef sample_decode(*,\n                  circuit_obj: Optional[stim.Circuit],\n                  circuit_path: Union[None, str, pathlib.Path],\n                  dem_obj: Optional[stim.DetectorErrorModel],\n                  dem_path: Union[None, str, pathlib.Path],\n                  post_mask: Optional[np.ndarray] = None,\n                  postselected_observable_mask: Optional[np.ndarray] = None,\n                  count_observable_error_combos: bool = False,\n                  count_detection_events: bool = False,\n                  num_shots: int,\n                  decoder: str,\n                  tmp_dir: Union[str, pathlib.Path, None] = None,\n                  custom_decoders: Optional[Dict[str, 'sinter.Decoder']] = None,\n                  __private__unstable__force_decode_on_disk: Optional[bool] = None,\n                  ) -> AnonTaskStats:\n    \"\"\"Samples how many times a decoder correctly predicts the logical frame.\n\n    Args:\n        circuit_obj: The noisy circuit to sample from and decode results for.\n            Must specify circuit_obj XOR circuit_path.\n        circuit_path: The file storing the circuit to sample from.\n            Must specify circuit_obj XOR circuit_path.\n        dem_obj: The error model to give to the decoder.\n            Must specify dem_obj XOR dem_path.\n        dem_path: The file storing the error model to give to the decoder.\n            Must specify dem_obj XOR dem_path.\n        post_mask: Postselection mask. Any samples that have a non-zero result\n            at a location where the mask has a 1 bit are discarded. If set to\n            None, no postselection is performed.\n        postselected_observable_mask: Bit packed mask indicating which observables to\n            postselect on. If the decoder incorrectly predicts any of these observables, the\n            shot is discarded instead of counted as an error.\n        count_observable_error_combos: Defaults to False. When set to to True,\n            the returned AnonTaskStats will have a custom counts field with keys\n            like `obs_mistake_mask=E_E__` counting how many times specific\n            combinations of observables were mispredicted by the decoder.\n        count_detection_events: Defaults to False. When set to True, the\n            returned AnonTaskStats will have a custom counts field withs the\n            key `detection_events` counting the number of times a detector fired\n            and also `detectors_checked` counting the number of detectors that\n            were executed. The detection fraction is the ratio of these two\n            numbers.\n        num_shots: The number of sample shots to take from the circuit.\n        decoder: The name of the decoder to use. Allowed values are:\n            \"pymatching\":\n                Use pymatching min-weight-perfect-match decoder.\n            \"internal\":\n                Use internal decoder with uncorrelated decoding.\n            \"internal_correlated\":\n                Use internal decoder with correlated decoding.\n        tmp_dir: An existing directory that is currently empty where temporary\n            files can be written as part of performing decoding. If set to\n            None, one is created using the tempfile package.\n        custom_decoders: Custom decoders that can be used if requested by name.\n            If not specified, only decoders built into sinter, such as\n            'pymatching' and 'fusion_blossom', can be used.\n    \"\"\"\n    if (circuit_obj is None) == (circuit_path is None):\n        raise ValueError('(circuit_obj is None) == (circuit_path is None)')\n    if (dem_obj is None) == (dem_path is None):\n        raise ValueError('(dem_obj is None) == (dem_path is None)')\n    if num_shots == 0:\n        return AnonTaskStats()\n\n    decoder_obj: Optional[Decoder] = None\n    if custom_decoders is not None:\n        decoder_obj = custom_decoders.get(decoder)\n    if decoder_obj is None:\n        decoder_obj = BUILT_IN_DECODERS.get(decoder)\n    if decoder_obj is None:\n        raise NotImplementedError(f\"Unrecognized decoder: {decoder!r}\")\n\n    dem: stim.DetectorErrorModel\n    if dem_obj is None:\n        dem = stim.DetectorErrorModel.from_file(dem_path)\n    else:\n        dem = dem_obj\n\n    circuit: stim.Circuit\n    if circuit_path is not None:\n        circuit = stim.Circuit.from_file(circuit_path)\n    else:\n        circuit = circuit_obj\n\n    start_time = time.monotonic()\n    try:\n        if __private__unstable__force_decode_on_disk:\n            raise NotImplementedError()\n        compiled_decoder = decoder_obj.compile_decoder_for_dem(dem=dem)\n        return _sample_decode_helper_using_memory(\n            circuit=circuit,\n            post_mask=post_mask,\n            postselected_observable_mask=postselected_observable_mask,\n            compiled_decoder=compiled_decoder,\n            total_num_shots=num_shots,\n            num_det=circuit.num_detectors,\n            mini_batch_size=1024,\n            start_time_monotonic=start_time,\n            num_obs=circuit.num_observables,\n            count_observable_error_combos=count_observable_error_combos,\n            count_detection_events=count_detection_events,\n        )\n    except NotImplementedError:\n        assert __private__unstable__force_decode_on_disk or __private__unstable__force_decode_on_disk is None\n        pass\n    return _sample_decode_helper_using_disk(\n        circuit=circuit,\n        dem=dem,\n        dem_path=dem_path,\n        post_mask=post_mask,\n        postselected_observable_mask=postselected_observable_mask,\n        num_shots=num_shots,\n        decoder_obj=decoder_obj,\n        tmp_dir=tmp_dir,\n        start_time_monotonic=start_time,\n        count_observable_error_combos=count_observable_error_combos,\n        count_detection_events=count_detection_events,\n    )\n\n\ndef _sample_decode_helper_using_memory(\n    *,\n    circuit: stim.Circuit,\n    post_mask: Optional[np.ndarray],\n    postselected_observable_mask: Optional[np.ndarray],\n    num_obs: int,\n    num_det: int,\n    total_num_shots: int,\n    mini_batch_size: int,\n    compiled_decoder: CompiledDecoder,\n    start_time_monotonic: float,\n    count_observable_error_combos: bool,\n    count_detection_events: bool,\n) -> AnonTaskStats:\n    sampler: stim.CompiledDetectorSampler = circuit.compile_detector_sampler()\n\n    out_num_discards = 0\n    out_num_errors = 0\n    shots_left = total_num_shots\n    custom_counts = collections.Counter()\n    while shots_left > 0:\n        cur_num_shots = min(shots_left, mini_batch_size)\n        dets_data, obs_data = sampler.sample(shots=cur_num_shots, separate_observables=True, bit_packed=True)\n\n        # Discard any shots that contain a postselected detection events.\n        if post_mask is not None:\n            discarded_flags = np.any(dets_data & post_mask, axis=1)\n            cur_num_discarded_shots = np.count_nonzero(discarded_flags)\n            if cur_num_discarded_shots:\n                out_num_discards += cur_num_discarded_shots\n                dets_data = dets_data[~discarded_flags, :]\n                obs_data = obs_data[~discarded_flags, :]\n\n        # Have the decoder predict which observables are flipped.\n        predict_data = compiled_decoder.decode_shots_bit_packed(bit_packed_detection_event_data=dets_data)\n\n        # Discard any shots where the decoder predicts a flipped postselected observable.\n        if postselected_observable_mask is not None:\n            discarded_flags = np.any(postselected_observable_mask & (predict_data ^ obs_data), axis=1)\n            cur_num_discarded_shots = np.count_nonzero(discarded_flags)\n            if cur_num_discarded_shots:\n                out_num_discards += cur_num_discarded_shots\n                obs_data = obs_data[~discarded_flags, :]\n                predict_data = predict_data[~discarded_flags, :]\n\n        # Count how many mistakes the decoder made on non-discarded shots.\n        mispredictions = obs_data ^ predict_data\n        err_mask = np.any(mispredictions, axis=1)\n        if count_detection_events:\n            for b in range(8):\n                custom_counts['detection_events'] += np.count_nonzero(dets_data & (1 << b))\n        if count_observable_error_combos:\n            for misprediction_arr in mispredictions[err_mask]:\n                err_key = \"obs_mistake_mask=\" + ''.join('_E'[b] for b in np.unpackbits(misprediction_arr, count=num_obs, bitorder='little'))\n                custom_counts[err_key] += 1\n        out_num_errors += np.count_nonzero(err_mask)\n        shots_left -= cur_num_shots\n\n    if count_detection_events:\n        custom_counts['detectors_checked'] += num_det * total_num_shots\n    return AnonTaskStats(\n        shots=total_num_shots,\n        errors=out_num_errors,\n        discards=out_num_discards,\n        seconds=time.monotonic() - start_time_monotonic,\n        custom_counts=custom_counts,\n    )\n\n\ndef _sample_decode_helper_using_disk(\n    *,\n    circuit: stim.Circuit,\n    dem: stim.DetectorErrorModel,\n    dem_path: Union[str, pathlib.Path],\n    post_mask: Optional[np.ndarray],\n    postselected_observable_mask: Optional[np.ndarray],\n    num_shots: int,\n    decoder_obj: Decoder,\n    tmp_dir: Union[str, pathlib.Path, None],\n    start_time_monotonic: float,\n    count_observable_error_combos: bool,\n    count_detection_events: bool,\n) -> AnonTaskStats:\n    with contextlib.ExitStack() as exit_stack:\n        if tmp_dir is None:\n            tmp_dir = exit_stack.enter_context(tempfile.TemporaryDirectory())\n        tmp_dir = pathlib.Path(tmp_dir)\n        if dem_path is None:\n            dem_path = tmp_dir / 'tmp.dem'\n            dem.to_file(dem_path)\n        dem_path = pathlib.Path(dem_path)\n\n        dets_all_path = tmp_dir / 'sinter_dets.all.b8'\n        obs_all_path = tmp_dir / 'sinter_obs.all.b8'\n        dets_kept_path = tmp_dir / 'sinter_dets.kept.b8'\n        obs_kept_path = tmp_dir / 'sinter_obs.kept.b8'\n        predictions_path = tmp_dir / 'sinter_predictions.b8'\n\n        num_dets = circuit.num_detectors\n        num_obs = circuit.num_observables\n\n        # Sample data using Stim.\n        sampler: stim.CompiledDetectorSampler = circuit.compile_detector_sampler()\n        sampler.sample_write(\n            num_shots,\n            filepath=str(dets_all_path),\n            obs_out_filepath=str(obs_all_path),\n            format='b8',\n            obs_out_format='b8',\n        )\n\n        # Postselect, then split into detection event data and observable data.\n        if post_mask is None:\n            num_det_discards = 0\n            dets_used_path = dets_all_path\n            obs_used_path = obs_all_path\n        else:\n            num_det_discards = streaming_post_select(\n                num_shots=num_shots,\n                num_dets=num_dets,\n                num_obs=num_obs,\n                dets_in_b8=dets_all_path,\n                dets_out_b8=dets_kept_path,\n                obs_in_b8=obs_all_path,\n                obs_out_b8=obs_kept_path,\n                post_mask=post_mask,\n                discards_out_b8=None,\n            )\n            dets_used_path = dets_kept_path\n            obs_used_path = obs_kept_path\n        num_kept_shots = num_shots - num_det_discards\n\n        # Perform syndrome decoding to predict observables from detection events.\n        decoder_obj.decode_via_files(\n            num_shots=num_kept_shots,\n            num_dets=num_dets,\n            num_obs=num_obs,\n            dem_path=dem_path,\n            dets_b8_in_path=dets_used_path,\n            obs_predictions_b8_out_path=predictions_path,\n            tmp_dir=tmp_dir,\n        )\n\n        # Count how many predictions matched the actual observable data.\n        num_obs_discards, num_errors, custom_counts = _streaming_count_mistakes(\n            num_shots=num_kept_shots,\n            num_obs=num_obs,\n            num_det=num_dets,\n            dets_in=dets_all_path,\n            obs_in=obs_used_path,\n            predictions_in=predictions_path,\n            postselected_observable_mask=postselected_observable_mask,\n            count_detection_events=count_detection_events,\n            count_observable_error_combos=count_observable_error_combos,\n        )\n\n        return AnonTaskStats(\n            shots=num_shots,\n            errors=num_errors,\n            discards=num_obs_discards + num_det_discards,\n            seconds=time.monotonic() - start_time_monotonic,\n            custom_counts=custom_counts,\n        )\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_decoding_all_built_in_decoders.py",
    "content": "from typing import Dict\nfrom typing import Union\n\nfrom sinter._decoding._decoding_decoder_class import Decoder\nfrom sinter._decoding._decoding_fusion_blossom import FusionBlossomDecoder\nfrom sinter._decoding._decoding_pymatching import PyMatchingDecoder\nfrom sinter._decoding._decoding_vacuous import VacuousDecoder\nfrom sinter._decoding._perfectionist_sampler import PerfectionistSampler\nfrom sinter._decoding._sampler import Sampler\nfrom sinter._decoding._decoding_mwpf import HyperUFDecoder, MwpfDecoder\n\nBUILT_IN_DECODERS: Dict[str, Decoder] = {\n    'vacuous': VacuousDecoder(),\n    'pymatching': PyMatchingDecoder(),\n    'fusion_blossom': FusionBlossomDecoder(),\n    # an implementation of (weighted) hypergraph UF decoder (https://arxiv.org/abs/2103.08049)\n    'hypergraph_union_find': HyperUFDecoder(),\n    # Minimum-Weight Parity Factor using similar primal-dual method the blossom algorithm (https://pypi.org/project/mwpf/)\n    'mw_parity_factor': MwpfDecoder(),\n}\n\nBUILT_IN_SAMPLERS: Dict[str, Union[Decoder, Sampler]] = {\n    **BUILT_IN_DECODERS,\n    'perfectionist': PerfectionistSampler(),\n}\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_decoding_decoder_class.py",
    "content": "import abc\nimport pathlib\n\nimport numpy as np\nimport stim\n\n\nclass CompiledDecoder(metaclass=abc.ABCMeta):\n    \"\"\"Abstract class for decoders preconfigured to a specific decoding task.\n\n    This is the type returned by `sinter.Decoder.compile_decoder_for_dem`. The\n    idea is that, when many shots of the same decoding task are going to be\n    performed, it is valuable to pay the cost of configuring the decoder only\n    once instead of once per batch of shots. Custom decoders can optionally\n    implement that method, and return this type, to increase sampling\n    efficiency.\n    \"\"\"\n\n    @abc.abstractmethod\n    def decode_shots_bit_packed(\n            self,\n            *,\n            bit_packed_detection_event_data: np.ndarray,\n    ) -> np.ndarray:\n        \"\"\"Predicts observable flips from the given detection events.\n\n        All data taken and returned must be bit packed with bitorder='little'.\n\n        Args:\n            bit_packed_detection_event_data: Detection event data stored as a\n                bit packed numpy array. The numpy array will have the following\n                dtype/shape:\n\n                    dtype: uint8\n                    shape: (num_shots, ceil(dem.num_detectors / 8))\n\n                where `num_shots` is the number of shots to decoder and `dem` is\n                the detector error model this instance was compiled to decode.\n\n                It's guaranteed that the data will be laid out in memory so that\n                detection events within a shot are contiguous in memory (i.e.\n                that bit_packed_detection_event_data.strides[1] == 1).\n\n        Returns:\n            Bit packed observable flip data stored as a bit packed numpy array.\n            The numpy array must have the following dtype/shape:\n\n                dtype: uint8\n                shape: (num_shots, ceil(dem.num_observables / 8))\n\n            where `num_shots` is bit_packed_detection_event_data.shape[0] and\n            `dem` is the detector error model this instance was compiled to\n            decode.\n        \"\"\"\n        pass\n\n\nclass Decoder:\n    \"\"\"Abstract base class for custom decoders.\n\n    Custom decoders can be explained to sinter by inheriting from this class and\n    implementing its methods.\n\n    Decoder classes MUST be serializable (e.g. via pickling), so that they can\n    be given to worker processes when using python multiprocessing.\n\n    Child classes should implement `compile_decoder_for_dem`, but (for legacy\n    reasons) can alternatively implement `decode_via_files`. At least one of\n    the two methods must be implemented.\n    \"\"\"\n\n    def compile_decoder_for_dem(\n        self,\n        *,\n        dem: stim.DetectorErrorModel,\n    ) -> CompiledDecoder:\n        \"\"\"Creates a decoder preconfigured for the given detector error model.\n\n        This method is optional to implement. By default, it will raise a\n        NotImplementedError. When sampling, sinter will attempt to use this\n        method first and otherwise fallback to using `decode_via_files`.\n\n        The idea is that the preconfigured decoder amortizes the cost of\n        configuration over more calls. This makes smaller batch sizes efficient,\n        reducing the amount of memory used for storing each batch, improving\n        overall efficiency.\n\n        Args:\n            dem: A detector error model for the samples that will need to be\n                decoded. What to configure the decoder to decode.\n\n        Returns:\n            An instance of `sinter.CompiledDecoder` that can be used to invoke\n            the preconfigured decoder.\n\n        Raises:\n            NotImplementedError: This `sinter.Decoder` doesn't support compiling\n                for a dem.\n        \"\"\"\n        raise NotImplementedError('compile_decoder_for_dem')\n\n    def decode_via_files(self,\n                         *,\n                         num_shots: int,\n                         num_dets: int,\n                         num_obs: int,\n                         dem_path: pathlib.Path,\n                         dets_b8_in_path: pathlib.Path,\n                         obs_predictions_b8_out_path: pathlib.Path,\n                         tmp_dir: pathlib.Path,\n                       ) -> None:\n        \"\"\"Performs decoding by reading/writing problems and answers from disk.\n\n        Args:\n            num_shots: The number of times the circuit was sampled. The number\n                of problems to be solved.\n            num_dets: The number of detectors in the circuit. The number of\n                detection event bits in each shot.\n            num_obs: The number of observables in the circuit. The number of\n                predicted bits in each shot.\n            dem_path: The file path where the detector error model should be\n                read from, e.g. using `stim.DetectorErrorModel.from_file`. The\n                error mechanisms specified by the detector error model should be\n                used to configure the decoder.\n            dets_b8_in_path: The file path that detection event data should be\n                read from. Note that the file may be a named pipe instead of a\n                fixed size object. The detection events will be in b8 format\n                (see\n                https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n                ). The number of detection events per shot is available via the\n                `num_dets` argument or via the detector error model at\n                `dem_path`.\n            obs_predictions_b8_out_path: The file path that decoder predictions\n                must be written to. The predictions must be written in b8 format\n                (see\n                https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n                ). The number of observables per shot is available via the\n                `num_obs` argument or via the detector error model at\n                `dem_path`.\n            tmp_dir: Any temporary files generated by the decoder during its\n                operation MUST be put into this directory. The reason for this\n                requirement is because sinter is allowed to kill the decoding\n                process without warning, without giving it time to clean up any\n                temporary objects. All cleanup should be done via sinter\n                deleting this directory after killing the decoder.\n        \"\"\"\n        dem = stim.DetectorErrorModel.from_file(dem_path)\n\n        try:\n            compiled = self.compile_decoder_for_dem(dem=dem)\n        except NotImplementedError as ex:\n            raise NotImplementedError(f\"{type(self).__qualname__} didn't implement `compile_decoder_for_dem` or `decode_via_files`.\") from ex\n\n        num_det_bytes = -(-num_dets // 8)\n        num_obs_bytes = -(-num_obs // 8)\n        dets = np.fromfile(dets_b8_in_path, dtype=np.uint8, count=num_shots * num_det_bytes)\n        dets = dets.reshape(num_shots, num_det_bytes)\n        obs = compiled.decode_shots_bit_packed(bit_packed_detection_event_data=dets)\n        if obs.dtype != np.uint8 or obs.shape != (num_shots, num_obs_bytes):\n            raise ValueError(f\"Got a numpy array with dtype={obs.dtype},shape={obs.shape} instead of dtype={np.uint8},shape={(num_shots, num_obs_bytes)} from {type(self).__qualname__}(...).compile_decoder_for_dem(...).decode_shots_bit_packed(...).\")\n        obs.tofile(obs_predictions_b8_out_path)\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_decoding_fusion_blossom.py",
    "content": "import math\nimport pathlib\nfrom typing import Callable, List, TYPE_CHECKING, Tuple\n\nimport numpy as np\nimport stim\n\nfrom sinter._decoding._decoding_decoder_class import Decoder, CompiledDecoder\n\nif TYPE_CHECKING:\n    import fusion_blossom\n\n\nclass FusionBlossomCompiledDecoder(CompiledDecoder):\n    def __init__(self, solver: 'fusion_blossom.SolverSerial', fault_masks: 'np.ndarray', num_dets: int, num_obs: int):\n        self.solver = solver\n        self.fault_masks = fault_masks\n        self.num_dets = num_dets\n        self.num_obs = num_obs\n\n    def decode_shots_bit_packed(\n            self,\n            *,\n            bit_packed_detection_event_data: 'np.ndarray',\n    ) -> 'np.ndarray':\n        num_shots = bit_packed_detection_event_data.shape[0]\n        predictions = np.zeros(shape=(num_shots, (self.num_obs + 7) // 8), dtype=np.uint8)\n        import fusion_blossom\n        for shot in range(num_shots):\n            dets_sparse = np.flatnonzero(np.unpackbits(bit_packed_detection_event_data[shot], count=self.num_dets, bitorder='little'))\n            syndrome = fusion_blossom.SyndromePattern(syndrome_vertices=dets_sparse)\n            self.solver.solve(syndrome)\n            prediction = int(np.bitwise_xor.reduce(self.fault_masks[self.solver.subgraph()]))\n            predictions[shot] = np.packbits(\n                np.array(list(np.binary_repr(prediction, width=self.num_obs))[::-1],dtype=np.uint8),\n                bitorder=\"little\",\n            )\n            self.solver.clear()\n        return predictions\n\n\nclass FusionBlossomDecoder(Decoder):\n    \"\"\"Use fusion blossom to predict observables from detection events.\"\"\"\n\n    def compile_decoder_for_dem(self, *, dem: 'stim.DetectorErrorModel') -> CompiledDecoder:\n        try:\n            import fusion_blossom\n        except ImportError as ex:\n            raise ImportError(\n                \"The decoder 'fusion_blossom' isn't installed\\n\"\n                \"To fix this, install the python package 'fusion_blossom' into your environment.\\n\"\n                \"For example, if you are using pip, run `pip install fusion_blossom`.\\n\"\n            ) from ex\n\n        solver, fault_masks = detector_error_model_to_fusion_blossom_solver_and_fault_masks(dem)\n        return FusionBlossomCompiledDecoder(solver, fault_masks, dem.num_detectors, dem.num_observables)\n\n\n    def decode_via_files(self,\n                         *,\n                         num_shots: int,\n                         num_dets: int,\n                         num_obs: int,\n                         dem_path: pathlib.Path,\n                         dets_b8_in_path: pathlib.Path,\n                         obs_predictions_b8_out_path: pathlib.Path,\n                         tmp_dir: pathlib.Path,\n                       ) -> None:\n        try:\n            import fusion_blossom\n        except ImportError as ex:\n            raise ImportError(\n                \"The decoder 'fusion_blossom' isn't installed\\n\"\n                \"To fix this, install the python package 'fusion-blossom' into your environment.\\n\"\n                \"For example, if you are using pip, run `pip install fusion-blossom~=0.1.4`.\\n\"\n            ) from ex\n\n        error_model = stim.DetectorErrorModel.from_file(dem_path)\n        solver, fault_masks = detector_error_model_to_fusion_blossom_solver_and_fault_masks(error_model)\n        num_det_bytes = math.ceil(num_dets / 8)\n        with open(dets_b8_in_path, 'rb') as dets_in_f:\n            with open(obs_predictions_b8_out_path, 'wb') as obs_out_f:\n                for _ in range(num_shots):\n                    dets_bit_packed = np.fromfile(dets_in_f, dtype=np.uint8, count=num_det_bytes)\n                    if dets_bit_packed.shape != (num_det_bytes,):\n                        raise IOError('Missing dets data.')\n                    dets_sparse = np.flatnonzero(np.unpackbits(dets_bit_packed, count=num_dets, bitorder='little'))\n                    syndrome = fusion_blossom.SyndromePattern(syndrome_vertices=dets_sparse)\n                    solver.solve(syndrome)\n                    prediction = int(np.bitwise_xor.reduce(fault_masks[solver.subgraph()]))\n                    obs_out_f.write(prediction.to_bytes((num_obs + 7) // 8, byteorder='little'))\n                    solver.clear()\n\n\ndef iter_flatten_model(model: stim.DetectorErrorModel,\n                       handle_error: Callable[[float, List[int], List[int]], None],\n                       handle_detector_coords: Callable[[int, np.ndarray], None]):\n    det_offset = 0\n    coords_offset = np.zeros(100, dtype=np.float64)\n\n    def _helper(m: stim.DetectorErrorModel, reps: int):\n        nonlocal det_offset\n        nonlocal coords_offset\n        for _ in range(reps):\n            for instruction in m:\n                if isinstance(instruction, stim.DemRepeatBlock):\n                    _helper(instruction.body_copy(), instruction.repeat_count)\n                elif isinstance(instruction, stim.DemInstruction):\n                    if instruction.type == \"error\":\n                        dets: List[int] = []\n                        frames: List[int] = []\n                        t: stim.DemTarget\n                        p = instruction.args_copy()[0]\n                        for t in instruction.targets_copy():\n                            if t.is_relative_detector_id():\n                                dets.append(t.val + det_offset)\n                            elif t.is_logical_observable_id():\n                                frames.append(t.val)\n                            elif t.is_separator():\n                                # Treat each component of a decomposed error as an independent error.\n                                # (Ideally we could configure some sort of correlated analysis; oh well.)\n                                handle_error(p, dets, frames)\n                                frames = []\n                                dets = []\n                        # Handle last component.\n                        handle_error(p, dets, frames)\n                    elif instruction.type == \"shift_detectors\":\n                        det_offset += instruction.targets_copy()[0]\n                        a = np.array(instruction.args_copy())\n                        coords_offset[:len(a)] += a\n                    elif instruction.type == \"detector\":\n                        a = np.array(instruction.args_copy())\n                        for t in instruction.targets_copy():\n                            handle_detector_coords(t.val + det_offset, a + coords_offset[:len(a)])\n                    elif instruction.type == \"logical_observable\":\n                        pass\n                    else:\n                        raise NotImplementedError()\n                else:\n                    raise NotImplementedError()\n    _helper(model, 1)\n\n\ndef detector_error_model_to_fusion_blossom_solver_and_fault_masks(model: stim.DetectorErrorModel) -> Tuple['fusion_blossom.SolverSerial', np.ndarray]:\n    \"\"\"Convert a stim error model into a NetworkX graph.\"\"\"\n\n    import fusion_blossom\n\n    def handle_error(p: float, dets: List[int], frame_changes: List[int]):\n        if p == 0:\n            return\n        if len(dets) == 0:\n            # No symptoms for this error.\n            # Code probably has distance 1.\n            # Accept it and keep going, though of course decoding will probably perform terribly.\n            return\n        if len(dets) == 1:\n            dets = [dets[0], num_detectors]\n        if len(dets) > 2:\n            raise NotImplementedError(\n                f\"Error with more than 2 symptoms can't become an edge or boundary edge: {dets!r}.\")\n        if p > 0.5:\n            # fusion_blossom doesn't support negative edge weights.\n            # approximate them as weight 0.\n            p = 0.5\n        weight = math.log((1 - p) / p)\n        mask = sum(1 << k for k in frame_changes)\n        edges.append((dets[0], dets[1], weight, mask))\n\n    def handle_detector_coords(detector: int, coords: np.ndarray):\n        pass\n\n    num_detectors = model.num_detectors\n    edges: List[Tuple[int, int, float, int]] = []\n    iter_flatten_model(\n        model,\n        handle_error=handle_error,\n        handle_detector_coords=handle_detector_coords,\n    )\n    max_weight = max(1e-4, max((w for _, _, w, _ in edges), default=1))\n    rescaled_edges = [\n        (a, b, round(w * 2**10 / max_weight) * 2)\n        for a, b, w, _ in edges\n    ]\n    fault_masks = np.array([e[3] for e in edges], dtype=np.uint64)\n\n    initializer = fusion_blossom.SolverInitializer(\n        num_detectors + 1,  # Total number of nodes.\n        rescaled_edges,  # Weighted edges.\n        [num_detectors],  # Boundary node.\n    )\n\n    return fusion_blossom.SolverSerial(initializer), fault_masks\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_decoding_mwpf.py",
    "content": "import math\nimport pathlib\nfrom typing import Callable, List, TYPE_CHECKING, Tuple, Any, Optional\n\nimport numpy as np\nimport stim\n\nfrom sinter._decoding._decoding_decoder_class import Decoder, CompiledDecoder\n\nif TYPE_CHECKING:\n    import mwpf\n\n\ndef mwpf_import_error() -> ImportError:\n    return ImportError(\n        \"The decoder 'MWPF' isn't installed\\n\"\n        \"To fix this, install the python package 'MWPF' into your environment.\\n\"\n        \"For example, if you are using pip, run `pip install MWPF~=0.1.5`.\\n\"\n    )\n\n\nclass MwpfCompiledDecoder(CompiledDecoder):\n    def __init__(\n        self,\n        solver: \"mwpf.SolverSerialJointSingleHair\",\n        fault_masks: \"np.ndarray\",\n        num_dets: int,\n        num_obs: int,\n    ):\n        self.solver = solver\n        self.fault_masks = fault_masks\n        self.num_dets = num_dets\n        self.num_obs = num_obs\n\n    def decode_shots_bit_packed(\n        self,\n        *,\n        bit_packed_detection_event_data: \"np.ndarray\",\n    ) -> \"np.ndarray\":\n        num_shots = bit_packed_detection_event_data.shape[0]\n        predictions = np.zeros(\n            shape=(num_shots, (self.num_obs + 7) // 8), dtype=np.uint8\n        )\n        import mwpf\n\n        for shot in range(num_shots):\n            dets_sparse = np.flatnonzero(\n                np.unpackbits(\n                    bit_packed_detection_event_data[shot],\n                    count=self.num_dets,\n                    bitorder=\"little\",\n                )\n            )\n            syndrome = mwpf.SyndromePattern(defect_vertices=dets_sparse)\n            if self.solver is None:\n                prediction = 0\n            else:\n                self.solver.solve(syndrome)\n                prediction = int(\n                    np.bitwise_xor.reduce(self.fault_masks[self.solver.subgraph()])\n                )\n                self.solver.clear()\n            predictions[shot] = np.packbits(\n                np.array(\n                    list(np.binary_repr(prediction, width=self.num_obs))[::-1],\n                    dtype=np.uint8,\n                ),\n                bitorder=\"little\",\n            )\n        return predictions\n\n\nclass MwpfDecoder(Decoder):\n    \"\"\"Use MWPF to predict observables from detection events.\"\"\"\n\n    def __init__(\n        self,\n        decoder_cls: Any = None,  # decoder class used to construct the MWPF decoder.\n        # in the Rust implementation, all of them inherits from the class of `SolverSerialPlugins`\n        # but just provide different plugins for optimizing the primal and/or dual solutions.\n        # For example, `SolverSerialUnionFind` is the most basic solver without any plugin: it only\n        # grows the clusters until the first valid solution appears; some more optimized solvers uses\n        # one or more plugins to further optimize the solution, which requires longer decoding time.\n        cluster_node_limit: int = 50,  # The maximum number of nodes in a cluster,\n    ):\n        self.decoder_cls = decoder_cls\n        self.cluster_node_limit = cluster_node_limit\n        super().__init__()\n\n    def compile_decoder_for_dem(\n        self,\n        *,\n        dem: \"stim.DetectorErrorModel\",\n    ) -> CompiledDecoder:\n        solver, fault_masks = detector_error_model_to_mwpf_solver_and_fault_masks(\n            dem,\n            decoder_cls=self.decoder_cls,\n            cluster_node_limit=self.cluster_node_limit,\n        )\n        return MwpfCompiledDecoder(\n            solver,\n            fault_masks,\n            dem.num_detectors,\n            dem.num_observables,\n        )\n\n    def decode_via_files(\n        self,\n        *,\n        num_shots: int,\n        num_dets: int,\n        num_obs: int,\n        dem_path: pathlib.Path,\n        dets_b8_in_path: pathlib.Path,\n        obs_predictions_b8_out_path: pathlib.Path,\n        tmp_dir: pathlib.Path,\n    ) -> None:\n        import mwpf\n\n        error_model = stim.DetectorErrorModel.from_file(dem_path)\n        solver, fault_masks = detector_error_model_to_mwpf_solver_and_fault_masks(\n            error_model,\n            decoder_cls=self.decoder_cls,\n            cluster_node_limit=self.cluster_node_limit,\n        )\n        num_det_bytes = math.ceil(num_dets / 8)\n        with open(dets_b8_in_path, \"rb\") as dets_in_f:\n            with open(obs_predictions_b8_out_path, \"wb\") as obs_out_f:\n                for _ in range(num_shots):\n                    dets_bit_packed = np.fromfile(\n                        dets_in_f, dtype=np.uint8, count=num_det_bytes\n                    )\n                    if dets_bit_packed.shape != (num_det_bytes,):\n                        raise IOError(\"Missing dets data.\")\n                    dets_sparse = np.flatnonzero(\n                        np.unpackbits(\n                            dets_bit_packed, count=num_dets, bitorder=\"little\"\n                        )\n                    )\n                    syndrome = mwpf.SyndromePattern(defect_vertices=dets_sparse)\n                    if solver is None:\n                        prediction = 0\n                    else:\n                        solver.solve(syndrome)\n                        prediction = int(\n                            np.bitwise_xor.reduce(fault_masks[solver.subgraph()])\n                        )\n                        solver.clear()\n                    obs_out_f.write(\n                        prediction.to_bytes((num_obs + 7) // 8, byteorder=\"little\")\n                    )\n\n\nclass HyperUFDecoder(MwpfDecoder):\n    def __init__(self):\n        super().__init__(decoder_cls=\"SolverSerialUnionFind\", cluster_node_limit=0)\n\n\ndef iter_flatten_model(\n    model: stim.DetectorErrorModel,\n    handle_error: Callable[[float, List[int], List[int]], None],\n    handle_detector_coords: Callable[[int, np.ndarray], None],\n):\n    det_offset = 0\n    coords_offset = np.zeros(100, dtype=np.float64)\n\n    def _helper(m: stim.DetectorErrorModel, reps: int):\n        nonlocal det_offset\n        nonlocal coords_offset\n        for _ in range(reps):\n            for instruction in m:\n                if isinstance(instruction, stim.DemRepeatBlock):\n                    _helper(instruction.body_copy(), instruction.repeat_count)\n                elif isinstance(instruction, stim.DemInstruction):\n                    if instruction.type == \"error\":\n                        dets: set[int] = set()\n                        frames: set[int] = set()\n                        t: stim.DemTarget\n                        p = instruction.args_copy()[0]\n                        for t in instruction.targets_copy():\n                            if t.is_relative_detector_id():\n                                dets ^= {t.val + det_offset}\n                            elif t.is_logical_observable_id():\n                                frames ^= {t.val}\n                        handle_error(p, list(dets), list(frames))\n                    elif instruction.type == \"shift_detectors\":\n                        det_offset += instruction.targets_copy()[0]\n                        a = np.array(instruction.args_copy())\n                        coords_offset[: len(a)] += a\n                    elif instruction.type == \"detector\":\n                        a = np.array(instruction.args_copy())\n                        for t in instruction.targets_copy():\n                            handle_detector_coords(\n                                t.val + det_offset, a + coords_offset[: len(a)]\n                            )\n                    elif instruction.type == \"logical_observable\":\n                        pass\n                    else:\n                        raise NotImplementedError()\n                else:\n                    raise NotImplementedError()\n\n    _helper(model, 1)\n\n\ndef deduplicate_hyperedges(\n    hyperedges: List[Tuple[List[int], float, int]]\n) -> List[Tuple[List[int], float, int]]:\n    indices: dict[frozenset[int], Tuple[int, float]] = dict()\n    result: List[Tuple[List[int], float, int]] = []\n    for dets, weight, mask in hyperedges:\n        dets_set = frozenset(dets)\n        if dets_set in indices:\n            idx, min_weight = indices[dets_set]\n            p1 = 1 / (1 + math.exp(weight))\n            p2 = 1 / (1 + math.exp(result[idx][1]))\n            p = p1 * (1 - p2) + p2 * (1 - p1)\n            # choosing the mask from the most likely error\n            new_mask = result[idx][2]\n            if weight < min_weight:\n                indices[dets_set] = (idx, weight)\n                new_mask = mask\n            result[idx] = (dets, math.log((1 - p) / p), new_mask)\n        else:\n            indices[dets_set] = (len(result), weight)\n            result.append((dets, weight, mask))\n    return result\n\n\ndef detector_error_model_to_mwpf_solver_and_fault_masks(\n    model: stim.DetectorErrorModel,\n    decoder_cls: Any = None,\n    cluster_node_limit: int = 50,\n) -> Tuple[Optional[\"mwpf.SolverSerialJointSingleHair\"], np.ndarray]:\n    \"\"\"Convert a stim error model into a NetworkX graph.\"\"\"\n\n    try:\n        import mwpf\n    except ImportError as ex:\n        raise mwpf_import_error() from ex\n\n    num_detectors = model.num_detectors\n    is_detector_connected = np.full(num_detectors, False, dtype=bool)\n    hyperedges: List[Tuple[List[int], float, int]] = []\n\n    def handle_error(p: float, dets: List[int], frame_changes: List[int]):\n        if p == 0:\n            return\n        if len(dets) == 0:\n            # No symptoms for this error.\n            # Code probably has distance 1.\n            # Accept it and keep going, though of course decoding will probably perform terribly.\n            return\n        if p > 0.5:\n            # mwpf doesn't support negative edge weights (yet, will be supported in the next version).\n            # approximate them as weight 0.\n            p = 0.5\n        weight = math.log((1 - p) / p)\n        mask = sum(1 << k for k in frame_changes)\n        is_detector_connected[dets] = True\n        hyperedges.append((dets, weight, mask))\n\n    def handle_detector_coords(detector: int, coords: np.ndarray):\n        pass\n\n    iter_flatten_model(\n        model,\n        handle_error=handle_error,\n        handle_detector_coords=handle_detector_coords,\n    )\n    # mwpf package panic on duplicate edges, thus we need to handle them here\n    hyperedges = deduplicate_hyperedges(hyperedges)\n\n    # fix the input by connecting an edge to all isolated vertices; will be supported in the next version\n    for idx in range(num_detectors):\n        if not is_detector_connected[idx]:\n            hyperedges.append(([idx], 0, 0))\n\n    max_weight = max(1e-4, max((w for _, w, _ in hyperedges), default=1))\n    rescaled_edges = [\n        mwpf.HyperEdge(v, round(w * 2**10 / max_weight) * 2) for v, w, _ in hyperedges\n    ]\n    fault_masks = np.array([e[2] for e in hyperedges], dtype=np.uint64)\n\n    initializer = mwpf.SolverInitializer(\n        num_detectors,  # Total number of nodes.\n        rescaled_edges,  # Weighted edges.\n    )\n\n    if decoder_cls is None:\n        # default to the solver with highest accuracy\n        decoder_cls = mwpf.SolverSerialJointSingleHair\n    elif isinstance(decoder_cls, str):\n        decoder_cls = getattr(mwpf, decoder_cls)\n    return (\n        (\n            decoder_cls(initializer, config={\"cluster_node_limit\": cluster_node_limit})\n            if num_detectors > 0 and len(rescaled_edges) > 0\n            else None\n        ),\n        fault_masks,\n    )\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_decoding_pymatching.py",
    "content": "from sinter._decoding._decoding_decoder_class import Decoder, CompiledDecoder\n\n\nclass PyMatchingCompiledDecoder(CompiledDecoder):\n    def __init__(self, matcher: 'pymatching.Matching'):\n        self.matcher = matcher\n\n    def decode_shots_bit_packed(\n            self,\n            *,\n            bit_packed_detection_event_data: 'np.ndarray',\n    ) -> 'np.ndarray':\n        return self.matcher.decode_batch(\n            shots=bit_packed_detection_event_data,\n            bit_packed_shots=True,\n            bit_packed_predictions=True,\n            return_weights=False,\n        )\n\n\nclass PyMatchingDecoder(Decoder):\n    \"\"\"Use pymatching to predict observables from detection events.\"\"\"\n\n    def compile_decoder_for_dem(self, *, dem: 'stim.DetectorErrorModel') -> CompiledDecoder:\n        try:\n            import pymatching\n        except ImportError as ex:\n            raise ImportError(\n                \"The decoder 'pymatching' isn't installed\\n\"\n                \"To fix this, install the python package 'pymatching' into your environment.\\n\"\n                \"For example, if you are using pip, run `pip install pymatching`.\\n\"\n            ) from ex\n\n        return PyMatchingCompiledDecoder(pymatching.Matching.from_detector_error_model(dem))\n\n    def decode_via_files(self,\n                         *,\n                         num_shots: int,\n                         num_dets: int,\n                         num_obs: int,\n                         dem_path: 'pathlib.Path',\n                         dets_b8_in_path: 'pathlib.Path',\n                         obs_predictions_b8_out_path: 'pathlib.Path',\n                         tmp_dir: 'pathlib.Path',\n                       ) -> None:\n        try:\n            import pymatching\n        except ImportError as ex:\n            raise ImportError(\n                \"The decoder 'pymatching' isn't installed\\n\"\n                \"To fix this, install the python package 'pymatching' into your environment.\\n\"\n                \"For example, if you are using pip, run `pip install pymatching`.\\n\"\n            ) from ex\n\n        if num_dets == 0:\n            with open(obs_predictions_b8_out_path, 'wb') as f:\n                f.write(b'\\0' * (num_obs * num_shots))\n            return\n\n        if not hasattr(pymatching, 'cli'):\n            raise ValueError(\"\"\"\nThe installed version of pymatching has no `pymatching.cli` method.\nsinter requires pymatching 2.1.0 or later.\nIf you're using pip to install packages, this can be fixed by running\n\n```\npip install \"pymatching~=2.1\" --upgrade\n```\n\n\"\"\")\n\n        result = pymatching.cli(command_line_args=[\n            \"predict\",\n            \"--dem\", str(dem_path),\n            \"--in\", str(dets_b8_in_path),\n            \"--in_format\", \"b8\",\n            \"--out\", str(obs_predictions_b8_out_path),\n            \"--out_format\", \"b8\",\n        ])\n        if result:\n            raise ValueError(\"pymatching.cli returned a non-zero exit code\")\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_decoding_test.py",
    "content": "import os\n\nimport pathlib\nimport tempfile\nfrom typing import Dict, List, Optional, Tuple\n\nimport numpy as np\nimport pytest\n\nimport sinter\nimport stim\n\nfrom sinter import CompiledDecoder\nfrom sinter._collection import post_selection_mask_from_4th_coord\nfrom sinter._decoding._decoding_all_built_in_decoders import BUILT_IN_DECODERS\nfrom sinter._decoding._decoding import sample_decode\nfrom sinter._decoding._decoding_vacuous import VacuousDecoder\n\n\ndef get_test_decoders() -> Tuple[List[str], Dict[str, sinter.Decoder]]:\n    available_decoders = list(BUILT_IN_DECODERS.keys())\n    custom_decoders = {}\n    try:\n        import pymatching\n    except ImportError:\n        available_decoders.remove('pymatching')\n    try:\n        import fusion_blossom\n    except ImportError:\n        available_decoders.remove('fusion_blossom')\n    try:\n        import mwpf\n    except ImportError:\n        available_decoders.remove('hypergraph_union_find')\n        available_decoders.remove('mw_parity_factor')\n\n    e = os.environ.get('SINTER_PYTEST_CUSTOM_DECODERS')\n    if e is not None:\n        for term in e.split(';'):\n            module, method = term.split(':')\n            for name, obj in getattr(__import__(module), method)().items():\n                custom_decoders[name] = obj\n                available_decoders.append(name)\n\n    available_decoders.append(\"also_vacuous\")\n    custom_decoders[\"also_vacuous\"] = VacuousDecoder()\n    return available_decoders, custom_decoders\n\nTEST_DECODER_NAMES, TEST_CUSTOM_DECODERS = get_test_decoders()\n\nDECODER_CASES = [\n    (decoder, force_streaming)\n    for decoder in TEST_DECODER_NAMES\n    for force_streaming in [None, True]\n]\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_decode_repetition_code(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit.generated('repetition_code:memory',\n                                     rounds=3,\n                                     distance=3,\n                                     after_clifford_depolarization=0.05)\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        num_shots=1000,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    if 'vacuous' not in decoder:\n        assert 1 <= result.errors <= 100\n    assert result.shots == 1000\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_decode_surface_code(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit.generated(\n        \"surface_code:rotated_memory_x\",\n        distance=3,\n        rounds=15,\n        after_clifford_depolarization=0.001,\n    )\n    stats = sample_decode(\n        num_shots=1000,\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    if 'vacuous' not in decoder:\n        assert 0 <= stats.errors <= 50\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_empty(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit()\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        num_shots=1000,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    assert result.shots == 1000\n    assert result.errors == 0\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_no_observables(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n        DETECTOR rec[-1]\n    \"\"\")\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        num_shots=1000,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    assert result.shots == 1000\n    assert result.errors == 0\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_invincible_observables(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0 1\n        DETECTOR rec[-2]\n        OBSERVABLE_INCLUDE(1) rec[-1]\n    \"\"\")\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        num_shots=1000,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    assert result.shots == 1000\n    assert result.errors == 0\n\n\n@pytest.mark.parametrize('decoder,force_streaming,offset', [(a, b, c) for a, b in DECODER_CASES for c in range(8)])\ndef test_observable_offsets_mod8(decoder: str, force_streaming: bool, offset: int):\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        MR 0\n        DETECTOR rec[-1]\n    \"\"\") * (8 + offset) + stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        MR 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        num_shots=1000,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    assert result.shots == 1000\n    assert 50 <= result.errors <= 150\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_no_detectors(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        num_shots=1000,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    assert 50 <= result.errors <= 150\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_no_detectors_with_post_mask(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        post_mask=np.array([], dtype=np.uint8),\n        num_shots=1000,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    assert 50 <= result.errors <= 150\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_post_selection(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.6) 0\n        M 0\n        DETECTOR(2, 0, 0, 1) rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n\n        X_ERROR(0.5) 1\n        M 1\n        DETECTOR(1, 0, 0) rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        \n        X_ERROR(0.1) 2\n        M 2\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        post_mask=post_selection_mask_from_4th_coord(circuit),\n        num_shots=2000,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert 1050 <= result.discards <= 1350\n    if 'vacuous' not in decoder:\n        assert 40 <= result.errors <= 160\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_observable_post_selection(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        X_ERROR(0.2) 1\n        M 0 1\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        OBSERVABLE_INCLUDE(1) rec[-1] rec[-2]\n    \"\"\")\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        post_mask=None,\n        postselected_observable_mask=np.array([1], dtype=np.uint8),\n        num_shots=10000,\n        decoder=decoder,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    np.testing.assert_allclose(result.discards / result.shots, 0.2, atol=0.1)\n    if 'vacuous' not in decoder:\n        np.testing.assert_allclose(result.errors / (result.shots - result.discards), 0.1, atol=0.05)\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_error_splitting(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        X_ERROR(0.2) 1\n        M 0 1\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        OBSERVABLE_INCLUDE(1) rec[-1] rec[-2]\n    \"\"\")\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        post_mask=None,\n        num_shots=10000,\n        decoder=decoder,\n        count_observable_error_combos=True,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    assert set(result.custom_counts.keys()) == {'obs_mistake_mask=E_', 'obs_mistake_mask=_E', 'obs_mistake_mask=EE'}\n    if 'vacuous' not in decoder:\n        np.testing.assert_allclose(result.errors / result.shots, 1 - 0.8 * 0.9, atol=0.05)\n        np.testing.assert_allclose(result.custom_counts['obs_mistake_mask=E_'] / result.shots, 0.1 * 0.2, atol=0.05)\n        np.testing.assert_allclose(result.custom_counts['obs_mistake_mask=_E'] / result.shots, 0.1 * 0.8, atol=0.05)\n        np.testing.assert_allclose(result.custom_counts['obs_mistake_mask=EE'] / result.shots, 0.9 * 0.2, atol=0.05)\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_detector_counting(decoder: str, force_streaming: Optional[bool]):\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        X_ERROR(0.2) 1\n        M 0 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        OBSERVABLE_INCLUDE(1) rec[-1] rec[-2]\n    \"\"\")\n    result = sample_decode(\n        circuit_obj=circuit,\n        circuit_path=None,\n        dem_obj=circuit.detector_error_model(decompose_errors=True),\n        dem_path=None,\n        post_mask=None,\n        num_shots=10000,\n        decoder=decoder,\n        count_detection_events=True,\n        __private__unstable__force_decode_on_disk=force_streaming,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    assert result.custom_counts['detectors_checked'] == 20000\n    assert 0.3 * 10000 * 0.5 <= result.custom_counts['detection_events'] <= 0.3 * 10000 * 2.0\n    assert set(result.custom_counts.keys()) == {'detectors_checked', 'detection_events'}\n\n\n@pytest.mark.parametrize('decoder,force_streaming', DECODER_CASES)\ndef test_decode_fails_correctly(decoder: str, force_streaming: Optional[bool]):\n    decoder_obj = BUILT_IN_DECODERS.get(decoder)\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        circuit = stim.Circuit(\"\"\"\n            REPEAT 9 {\n                MR(0.001) 0\n                DETECTOR rec[-1]\n                OBSERVABLE_INCLUDE(0) rec[-1]\n            }\n        \"\"\")\n        dem = circuit.detector_error_model()\n        circuit.to_file(d / 'circuit.stim')\n        dem.to_file(d / 'dem.dem')\n        with open(d / 'bad_dets.b8', 'wb') as f:\n            f.write(b'!')\n\n        if 'vacuous' not in decoder:\n            with pytest.raises(Exception):\n                decoder_obj.decode_via_files(\n                    num_shots=1,\n                    num_dets=dem.num_detectors,\n                    num_obs=dem.num_observables,\n                    dem_path=d / 'dem.dem',\n                    dets_b8_in_path=d / 'bad_dets.b8',\n                    obs_predictions_b8_out_path=d / 'predict.b8',\n                    tmp_dir=d,\n                )\n\n\n@pytest.mark.parametrize('decoder', TEST_DECODER_NAMES)\ndef test_full_scale(decoder: str):\n    result, = sinter.collect(\n        num_workers=2,\n        tasks=[sinter.Task(circuit=stim.Circuit())],\n        decoders=[decoder],\n        max_shots=1000,\n        custom_decoders=TEST_CUSTOM_DECODERS,\n    )\n    assert result.discards == 0\n    assert result.shots == 1000\n    assert result.errors == 0\n\n\ndef test_infer_decode_via_files_from_decode_from_compile_decoder_for_dem():\n    class IncompleteDecoder(sinter.Decoder):\n        pass\n\n    class WrongDecoder(sinter.Decoder, sinter.CompiledDecoder):\n        def compile_decoder_for_dem(\n                self,\n                *,\n                dem: stim.DetectorErrorModel,\n        ) -> CompiledDecoder:\n            return self\n        def decode_shots_bit_packed(\n                self,\n                *,\n                bit_packed_detection_event_data: np.ndarray,\n        ) -> np.ndarray:\n            return np.zeros(shape=5, dtype=np.bool_)\n\n    class TrivialCompiledDecoder(sinter.CompiledDecoder):\n        def __init__(self, num_obs: int):\n            self.num_obs = -(-num_obs // 8)\n\n        def decode_shots_bit_packed(\n                self,\n                *,\n                bit_packed_detection_event_data: np.ndarray,\n        ) -> np.ndarray:\n            return np.zeros(dtype=np.uint8, shape=(bit_packed_detection_event_data.shape[0], self.num_obs))\n\n    class TrivialDecoder(sinter.Decoder):\n        def compile_decoder_for_dem(\n            self,\n            *,\n            dem: stim.DetectorErrorModel,\n        ) -> CompiledDecoder:\n                return TrivialCompiledDecoder(num_obs=dem.num_observables)\n\n    circuit = stim.Circuit.generated(\"repetition_code:memory\", distance=3, rounds=3)\n    dem = circuit.detector_error_model()\n\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n\n        circuit.compile_detector_sampler().sample_write(\n            shots=10,\n            filepath=d / 'dets.b8',\n            format='b8',\n        )\n\n        dem.to_file(d / 'dem.dem')\n\n        with pytest.raises(NotImplementedError, match='compile_decoder_for_dem'):\n            IncompleteDecoder().decode_via_files(\n                num_shots=10,\n                num_dets=dem.num_detectors,\n                num_obs=dem.num_observables,\n                dem_path=d / 'dem.dem',\n                dets_b8_in_path=d / 'dets.b8',\n                obs_predictions_b8_out_path=d / 'obs.b8',\n                tmp_dir=d,\n            )\n\n        with pytest.raises(ValueError, match='shape='):\n            WrongDecoder().decode_via_files(\n                num_shots=10,\n                num_dets=dem.num_detectors,\n                num_obs=dem.num_observables,\n                dem_path=d / 'dem.dem',\n                dets_b8_in_path=d / 'dets.b8',\n                obs_predictions_b8_out_path=d / 'obs.b8',\n                tmp_dir=d,\n            )\n\n        TrivialDecoder().decode_via_files(\n            num_shots=10,\n            num_dets=dem.num_detectors,\n            num_obs=dem.num_observables,\n            dem_path=d / 'dem.dem',\n            dets_b8_in_path=d / 'dets.b8',\n            obs_predictions_b8_out_path=d / 'obs.b8',\n            tmp_dir=d,\n        )\n        obs = np.fromfile(d / 'obs.b8', dtype=np.uint8, count=10)\n        np.testing.assert_array_equal(obs, [0] * 10)\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_decoding_vacuous.py",
    "content": "import numpy as np\n\nfrom sinter._decoding._decoding_decoder_class import Decoder, CompiledDecoder\n\n\nclass VacuousDecoder(Decoder):\n    \"\"\"An example decoder that always predicts the observables aren't flipped.\n    \"\"\"\n\n    def compile_decoder_for_dem(self, *, dem: 'stim.DetectorErrorModel') -> CompiledDecoder:\n        return VacuousCompiledDecoder(shape=(dem.num_observables + 7) // 8)\n\n    def decode_via_files(self,\n                         *,\n                         num_shots: int,\n                         num_dets: int,\n                         num_obs: int,\n                         dem_path: 'pathlib.Path',\n                         dets_b8_in_path: 'pathlib.Path',\n                         obs_predictions_b8_out_path: 'pathlib.Path',\n                         tmp_dir: 'pathlib.Path',\n                       ) -> None:\n        with open(obs_predictions_b8_out_path, 'wb') as f:\n            f.write(b'\\0' * (num_obs * num_shots))\n\n\nclass VacuousCompiledDecoder(CompiledDecoder):\n    \"\"\"An example decoder that always predicts the observables aren't flipped.\n    \"\"\"\n    def __init__(self, shape: int):\n        self.shape = shape\n\n    def decode_shots_bit_packed(\n            self,\n            *,\n            bit_packed_detection_event_data: 'np.ndarray',\n    ) -> 'np.ndarray':\n        return np.zeros(shape=(bit_packed_detection_event_data.shape[0], self.shape), dtype=np.uint8)\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_perfectionist_sampler.py",
    "content": "import time\n\nimport numpy as np\n\nfrom sinter._data import Task, AnonTaskStats\nfrom sinter._decoding._sampler import Sampler, CompiledSampler\n\n\nclass PerfectionistSampler(Sampler):\n    \"\"\"Predicts obs aren't flipped. Discards shots with any detection events.\"\"\"\n    def compiled_sampler_for_task(self, task: Task) -> CompiledSampler:\n        return CompiledPerfectionistSampler(task)\n\n\nclass CompiledPerfectionistSampler(CompiledSampler):\n    def __init__(self, task: Task):\n        self.stim_sampler = task.circuit.compile_detector_sampler()\n\n    def sample(self, max_shots: int) -> AnonTaskStats:\n        t0 = time.monotonic()\n        dets, obs = self.stim_sampler.sample(\n            shots=max_shots,\n            bit_packed=True,\n            separate_observables=True,\n        )\n        num_shots = dets.shape[0]\n        discards = np.any(dets, axis=1)\n        errors = np.any(obs, axis=1)\n        num_discards = np.count_nonzero(discards)\n        num_errors = np.count_nonzero(errors & ~discards)\n        t1 = time.monotonic()\n\n        return AnonTaskStats(\n            shots=num_shots,\n            errors=num_errors,\n            discards=num_discards,\n            seconds=t1 - t0,\n        )\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_sampler.py",
    "content": "import abc\nfrom typing import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    import sinter\n\n\nclass CompiledSampler(metaclass=abc.ABCMeta):\n    \"\"\"A sampler that has been configured for efficiently sampling some task.\"\"\"\n\n    @abc.abstractmethod\n    def sample(self, suggested_shots: int) -> 'sinter.AnonTaskStats':\n        \"\"\"Samples shots and returns statistics.\n\n        Args:\n            suggested_shots: The number of shots being requested. The sampler\n                may perform more shots or fewer shots than this, so technically\n                this argument can just be ignored. If a sampler is optimized for\n                a specific batch size, it can simply return one batch per call\n                regardless of this parameter.\n\n                However, this parameter is a useful hint about the amount of\n                work being done. The sampler can use this to optimize its\n                behavior. For example, it could adjust its batch size downward\n                if the suggested shots is very small. Whereas if the suggested\n                shots is very high, the sampler should focus entirely on\n                achieving the best possible throughput.\n\n                Note that, in typical workloads, the sampler will be called\n                repeatedly with the same value of suggested_shots. Therefore it\n                is reasonable to allocate buffers sized to accomodate the\n                current suggested_shots, expecting them to be useful again for\n                the next shot.\n\n        Returns:\n            A sinter.AnonTaskStats saying how many shots were actually taken,\n            how many errors were seen, etc.\n\n            The returned stats must have at least one shot.\n        \"\"\"\n        pass\n\n    def handles_throttling(self) -> bool:\n        \"\"\"Return True to disable sinter wrapping samplers with throttling.\n\n        By default, sinter will wrap samplers so that they initially only do\n        a small number of shots then slowly ramp up. Sometimes this behavior\n        is not desired (e.g. in unit tests). Override this method to return True\n        to disable it.\n        \"\"\"\n        return False\n\n\nclass Sampler(metaclass=abc.ABCMeta):\n    \"\"\"A strategy for producing stats from tasks.\n\n    Call `sampler.compiled_sampler_for_task(task)` to get a compiled sampler for\n    a task, then call `compiled_sampler.sample(shots)` to collect statistics.\n\n    A sampler differs from a `sinter.Decoder` because the sampler is responsible\n    for the full sampling process (e.g. simulating the circuit), whereas a\n    decoder can do nothing except predict observable flips from detection event\n    data. This prevents the decoders from cheating, but makes them less flexible\n    overall. A sampler can do things like use simulators other than stim, or\n    really anything at all as long as it ends with returning statistics about\n    shot counts, error counts, and etc.\n    \"\"\"\n\n    @abc.abstractmethod\n    def compiled_sampler_for_task(self, task: 'sinter.Task') -> 'sinter.CompiledSampler':\n        \"\"\"Creates, configures, and returns an object for sampling the task.\"\"\"\n        pass\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_stim_then_decode_sampler.py",
    "content": "import collections\nimport pathlib\nimport random\nimport time\nfrom typing import Optional\nfrom typing import Union\n\nimport numpy as np\n\nfrom sinter._data import Task, AnonTaskStats\nfrom sinter._decoding._sampler import Sampler, CompiledSampler\nfrom sinter._decoding._decoding_decoder_class import Decoder, CompiledDecoder\n\n\nclass StimThenDecodeSampler(Sampler):\n    \"\"\"Samples shots using stim, then decodes using the given decoder.\n\n    This is the default sampler; the one used to wrap decoders with no\n    specified sampler.\n\n    The decoder's goal is to predict the observable flips given the detection\n    event data. Errors are when the prediction is wrong. Discards are when the\n    decoder returns an extra byte of prediction data for each shot, and the\n    extra byte is not zero.\n    \"\"\"\n    def __init__(\n        self,\n        *,\n        decoder: Decoder,\n        count_observable_error_combos: bool,\n        count_detection_events: bool,\n        tmp_dir: Optional[pathlib.Path],\n    ):\n        self.decoder = decoder\n        self.count_observable_error_combos = count_observable_error_combos\n        self.count_detection_events = count_detection_events\n        self.tmp_dir = tmp_dir\n\n    def compiled_sampler_for_task(self, task: Task) -> CompiledSampler:\n        return _CompiledStimThenDecodeSampler(\n            decoder=self.decoder,\n            task=task,\n            count_detection_events=self.count_detection_events,\n            count_observable_error_combos=self.count_observable_error_combos,\n            tmp_dir=self.tmp_dir,\n        )\n\n\ndef classify_discards_and_errors(\n    *,\n    actual_obs: np.ndarray,\n    predictions: np.ndarray,\n    postselected_observables_mask: Union[np.ndarray, None],\n    out_count_observable_error_combos: Union[None, collections.Counter[str]],\n    num_obs: int,\n) -> tuple[int, int]:\n    num_discards = 0\n\n    # Added bytes are used for signalling discards.\n    if predictions.shape[1] == actual_obs.shape[1] + 1:\n        discard_mask = predictions[:, -1] != 0\n        predictions = predictions[:, :-1]\n        num_discards += np.count_nonzero(discard_mask)\n        discard_mask ^= True\n        actual_obs = actual_obs[discard_mask]\n        predictions = predictions[discard_mask]\n\n    # Mispredicted observables can be used for signalling discards.\n    if postselected_observables_mask is not None:\n        discard_mask = np.any((actual_obs ^ predictions) & postselected_observables_mask, axis=1)\n        num_discards += np.count_nonzero(discard_mask)\n        discard_mask ^= True\n        actual_obs = actual_obs[discard_mask]\n        predictions = predictions[discard_mask]\n\n    fail_mask = np.any(actual_obs != predictions, axis=1)\n    if out_count_observable_error_combos is not None:\n        for k in np.flatnonzero(fail_mask):\n            mistakes = np.unpackbits(actual_obs[k] ^ predictions[k], count=num_obs, bitorder='little')\n            err_key = \"obs_mistake_mask=\" + ''.join('_E'[b] for b in mistakes)\n            out_count_observable_error_combos[err_key] += 1\n\n    num_errors = np.count_nonzero(fail_mask)\n    return num_discards, num_errors\n\n\nclass DiskDecoder(CompiledDecoder):\n    def __init__(self, decoder: Decoder, task: Task, tmp_dir: pathlib.Path):\n        self.decoder = decoder\n        self.task = task\n        self.top_tmp_dir: pathlib.Path = tmp_dir\n\n        while True:\n            k = random.randint(0, 2**64)\n            self.top_tmp_dir = tmp_dir / f'disk_decoder_{k}'\n            try:\n                self.top_tmp_dir.mkdir()\n                break\n            except FileExistsError:\n                pass\n        self.decoder_tmp_dir: pathlib.Path = self.top_tmp_dir / 'dec'\n        self.decoder_tmp_dir.mkdir()\n        self.num_obs = task.detector_error_model.num_observables\n        self.num_dets = task.detector_error_model.num_detectors\n        self.dem_path = self.top_tmp_dir / 'dem.dem'\n        self.dets_b8_in_path = self.top_tmp_dir / 'dets.b8'\n        self.obs_predictions_b8_out_path = self.top_tmp_dir / 'obs.b8'\n        self.task.detector_error_model.to_file(self.dem_path)\n\n    def decode_shots_bit_packed(\n            self,\n            *,\n            bit_packed_detection_event_data: np.ndarray,\n    ) -> np.ndarray:\n        num_shots = bit_packed_detection_event_data.shape[0]\n        with open(self.dets_b8_in_path, 'wb') as f:\n            bit_packed_detection_event_data.tofile(f)\n        self.decoder.decode_via_files(\n            num_shots=num_shots,\n            num_obs=self.num_obs,\n            num_dets=self.num_dets,\n            dem_path=self.dem_path,\n            dets_b8_in_path=self.dets_b8_in_path,\n            obs_predictions_b8_out_path=self.obs_predictions_b8_out_path,\n            tmp_dir=self.decoder_tmp_dir,\n        )\n        num_obs_bytes = (self.num_obs + 7) // 8\n        with open(self.obs_predictions_b8_out_path, 'rb') as f:\n            prediction = np.fromfile(f, dtype=np.uint8, count=num_obs_bytes * num_shots)\n            assert prediction.shape == (num_obs_bytes * num_shots,)\n        self.obs_predictions_b8_out_path.unlink()\n        self.dets_b8_in_path.unlink()\n        return prediction.reshape((num_shots, num_obs_bytes))\n\n\ndef _compile_decoder_with_disk_fallback(\n    decoder: Decoder,\n    task: Task,\n    tmp_dir: Optional[pathlib.Path],\n) -> CompiledDecoder:\n    try:\n        return decoder.compile_decoder_for_dem(dem=task.detector_error_model)\n    except NotImplementedError:\n        pass\n    if tmp_dir is None:\n        raise ValueError(f\"Decoder {task.decoder=} didn't implement `compile_decoder_for_dem`, but no temporary directory was provided for falling back to `decode_via_files`.\")\n    return DiskDecoder(decoder, task, tmp_dir)\n\n\nclass _CompiledStimThenDecodeSampler(CompiledSampler):\n    def __init__(\n        self,\n        *,\n        decoder: Decoder,\n        task: Task,\n        count_observable_error_combos: bool,\n        count_detection_events: bool,\n        tmp_dir: Optional[pathlib.Path],\n    ):\n        self.task = task\n        self.compiled_decoder = _compile_decoder_with_disk_fallback(decoder, task, tmp_dir)\n        self.stim_sampler = task.circuit.compile_detector_sampler()\n        self.count_observable_error_combos = count_observable_error_combos\n        self.count_detection_events = count_detection_events\n        self.num_det = self.task.circuit.num_detectors\n        self.num_obs = self.task.circuit.num_observables\n\n    def sample(self, max_shots: int) -> AnonTaskStats:\n        t0 = time.monotonic()\n        dets, actual_obs = self.stim_sampler.sample(\n            shots=max_shots,\n            bit_packed=True,\n            separate_observables=True,\n        )\n        num_shots = dets.shape[0]\n\n        custom_counts = collections.Counter()\n        if self.count_detection_events:\n            custom_counts['detectors_checked'] += self.num_det * num_shots\n            for b in range(8):\n                custom_counts['detection_events'] += np.count_nonzero(dets & (1 << b))\n\n        # Discard any shots that contain a postselected detection events.\n        if self.task.postselection_mask is not None:\n            discarded_flags = np.any(dets & self.task.postselection_mask, axis=1)\n            num_discards_1 = np.count_nonzero(discarded_flags)\n            if num_discards_1:\n                dets = dets[~discarded_flags, :]\n                actual_obs = actual_obs[~discarded_flags, :]\n        else:\n            num_discards_1 = 0\n\n        predictions = self.compiled_decoder.decode_shots_bit_packed(bit_packed_detection_event_data=dets)\n        if not isinstance(predictions, np.ndarray):\n            raise ValueError(\"not isinstance(predictions, np.ndarray)\")\n        if predictions.dtype != np.uint8:\n            raise ValueError(\"predictions.dtype != np.uint8\")\n        if len(predictions.shape) != 2:\n            raise ValueError(\"len(predictions.shape) != 2\")\n        if predictions.shape[0] != num_shots:\n            raise ValueError(\"predictions.shape[0] != num_shots\")\n        if predictions.shape[1] < actual_obs.shape[1]:\n            raise ValueError(\"predictions.shape[1] < actual_obs.shape[1]\")\n        if predictions.shape[1] > actual_obs.shape[1] + 1:\n            raise ValueError(\"predictions.shape[1] > actual_obs.shape[1] + 1\")\n\n        num_discards_2, num_errors = classify_discards_and_errors(\n            actual_obs=actual_obs,\n            predictions=predictions,\n            postselected_observables_mask=self.task.postselected_observables_mask,\n            out_count_observable_error_combos=custom_counts if self.count_observable_error_combos else None,\n            num_obs=self.num_obs,\n        )\n        t1 = time.monotonic()\n\n        return AnonTaskStats(\n            shots=num_shots,\n            errors=num_errors,\n            discards=num_discards_1 + num_discards_2,\n            seconds=t1 - t0,\n            custom_counts=custom_counts,\n        )\n"
  },
  {
    "path": "glue/sample/src/sinter/_decoding/_stim_then_decode_sampler_test.py",
    "content": "import collections\n\nimport numpy as np\n\nfrom sinter._decoding._stim_then_decode_sampler import \\\n    classify_discards_and_errors\n\n\ndef test_classify_discards_and_errors():\n    assert classify_discards_and_errors(\n        actual_obs=np.array([\n            [1, 2],\n            [2, 2],\n            [3, 2],\n            [4, 3],\n            [1, 3],\n            [0, 3],\n            [0, 3],\n        ], dtype=np.uint8),\n        predictions=np.array([\n            [1, 2],\n            [2, 2],\n            [3, 2],\n            [4, 3],\n            [1, 3],\n            [0, 3],\n            [0, 3],\n        ], dtype=np.uint8),\n        postselected_observables_mask=None,\n        out_count_observable_error_combos=None,\n        num_obs=16,\n    ) == (0, 0)\n\n    assert classify_discards_and_errors(\n        actual_obs=np.array([\n            [1, 2],\n            [2, 2],\n            [3, 2],\n            [4, 3],\n            [1, 3],\n            [0, 3],\n            [0, 3],\n        ], dtype=np.uint8),\n        predictions=np.array([\n            [0, 0],\n            [2, 2],\n            [3, 2],\n            [4, 1],\n            [1, 3],\n            [0, 3],\n            [0, 3],\n        ], dtype=np.uint8),\n        postselected_observables_mask=None,\n        out_count_observable_error_combos=None,\n        num_obs=16,\n    ) == (0, 2)\n\n    assert classify_discards_and_errors(\n        actual_obs=np.array([\n            [1, 2],\n            [2, 2],\n            [3, 2],\n            [4, 3],\n            [1, 3],\n            [0, 3],\n            [0, 3],\n        ], dtype=np.uint8),\n        predictions=np.array([\n            [0, 0, 0],\n            [2, 2, 0],\n            [3, 2, 0],\n            [4, 1, 0],\n            [1, 3, 0],\n            [0, 3, 0],\n            [0, 3, 0],\n        ], dtype=np.uint8),\n        postselected_observables_mask=None,\n        out_count_observable_error_combos=None,\n        num_obs=16,\n    ) == (0, 2)\n\n    assert classify_discards_and_errors(\n        actual_obs=np.array([\n            [1, 2],\n            [2, 2],\n            [3, 2],\n            [4, 3],\n            [1, 3],\n            [0, 3],\n            [0, 3],\n        ], dtype=np.uint8),\n        predictions=np.array([\n            [0, 0, 0],\n            [2, 2, 1],\n            [3, 2, 0],\n            [4, 1, 0],\n            [1, 3, 0],\n            [0, 3, 0],\n            [0, 3, 0],\n        ], dtype=np.uint8),\n        postselected_observables_mask=None,\n        out_count_observable_error_combos=None,\n        num_obs=16,\n    ) == (1, 2)\n\n    assert classify_discards_and_errors(\n        actual_obs=np.array([\n            [1, 2],\n            [2, 2],\n            [3, 2],\n            [4, 3],\n            [1, 3],\n            [0, 3],\n            [0, 3],\n        ], dtype=np.uint8),\n        predictions=np.array([\n            [0, 0, 1],\n            [2, 2, 0],\n            [3, 2, 0],\n            [4, 1, 0],\n            [1, 3, 0],\n            [0, 3, 0],\n            [0, 3, 0],\n        ], dtype=np.uint8),\n        postselected_observables_mask=None,\n        out_count_observable_error_combos=None,\n        num_obs=16,\n    ) == (1, 1)\n\n    assert classify_discards_and_errors(\n        actual_obs=np.array([\n            [1, 2],\n            [2, 2],\n            [3, 2],\n            [4, 3],\n            [1, 3],\n            [0, 3],\n            [0, 3],\n        ], dtype=np.uint8),\n        predictions=np.array([\n            [0, 0, 1],\n            [2, 2, 1],\n            [3, 2, 0],\n            [4, 1, 0],\n            [1, 3, 0],\n            [0, 3, 0],\n            [0, 3, 0],\n        ], dtype=np.uint8),\n        postselected_observables_mask=None,\n        out_count_observable_error_combos=None,\n        num_obs=16,\n    ) == (2, 1)\n\n    assert classify_discards_and_errors(\n        actual_obs=np.array([\n            [1, 2],\n            [2, 2],\n            [3, 2],\n            [4, 3],\n            [1, 3],\n            [2, 3],\n            [1, 3],\n        ], dtype=np.uint8),\n        predictions=np.array([\n            [0, 0, 1],\n            [2, 2, 1],\n            [3, 2, 0],\n            [4, 1, 0],\n            [1, 3, 0],\n            [0, 3, 0],\n            [0, 3, 0],\n        ], dtype=np.uint8),\n        postselected_observables_mask=np.array([1, 0]),\n        out_count_observable_error_combos=None,\n        num_obs=16,\n    ) == (3, 2)\n\n    counter = collections.Counter()\n    assert classify_discards_and_errors(\n        actual_obs=np.array([\n            [1, 2],\n            [1, 2],\n        ], dtype=np.uint8),\n        predictions=np.array([\n            [1, 0],\n            [1, 2],\n        ], dtype=np.uint8),\n        postselected_observables_mask=np.array([1, 0]),\n        out_count_observable_error_combos=counter,\n        num_obs=13,\n    ) == (0, 1)\n    assert counter == collections.Counter([\"obs_mistake_mask=_________E___\"])\n"
  },
  {
    "path": "glue/sample/src/sinter/_plotting.py",
    "content": "import math\nfrom typing import Callable, TypeVar, List, Any, Iterable, Optional, TYPE_CHECKING, Dict, Union, Literal, Tuple\nfrom typing import Sequence\nfrom typing import cast\n\nimport numpy as np\n\nfrom sinter._probability_util import fit_binomial, shot_error_rate_to_piece_error_rate, Fit\n\nif TYPE_CHECKING:\n    import sinter\n    import matplotlib.pyplot as plt\n\n\nMARKERS: str = \"ov*sp^<>8PhH+xXDd|\" * 100\nLINESTYLES: tuple[str, ...] = (\n    'solid',\n    'dotted',\n    'dashed',\n    'dashdot',\n    'loosely dotted',\n    'dotted',\n    'densely dotted',\n    'long dash with offset',\n    'loosely dashed',\n    'dashed',\n    'densely dashed',\n    'loosely dashdotted',\n    'dashdotted',\n    'densely dashdotted',\n    'dashdotdotted',\n    'loosely dashdotdotted',\n    'densely dashdotdotted',\n)\nT = TypeVar('T')\nTVal = TypeVar('TVal')\nTKey = TypeVar('TKey')\n\n\ndef split_by(vs: Iterable[T], key_func: Callable[[T], Any]) -> List[List[T]]:\n    cur_key: Any = None\n    out: List[List[T]] = []\n    buf: List[T] = []\n    for item in vs:\n        key = key_func(item)\n        if key != cur_key:\n            cur_key = key\n            if buf:\n                out.append(buf)\n                buf = []\n        buf.append(item)\n    if buf:\n        out.append(buf)\n    return out\n\n\nclass LooseCompare:\n    def __init__(self, val: Any):\n        self.val: Any = None\n\n        self.val = val.val if isinstance(val, LooseCompare) else val\n\n    def __lt__(self, other: Any) -> bool:\n        other_val = other.val if isinstance(other, LooseCompare) else other\n        if isinstance(self.val, (int, float)) and isinstance(other_val, (int, float)):\n            return self.val < other_val\n        if isinstance(self.val, (tuple, list)) and isinstance(other_val, (tuple, list)):\n            return tuple(LooseCompare(e) for e in self.val) < tuple(LooseCompare(e) for e in other_val)\n        return str(self.val) < str(other_val)\n\n    def __gt__(self, other: Any) -> bool:\n        other_val = other.val if isinstance(other, LooseCompare) else other\n        if isinstance(self.val, (int, float)) and isinstance(other_val, (int, float)):\n            return self.val > other_val\n        if isinstance(self.val, (tuple, list)) and isinstance(other_val, (tuple, list)):\n            return tuple(LooseCompare(e) for e in self.val) > tuple(LooseCompare(e) for e in other_val)\n        return str(self.val) > str(other_val)\n\n    def __str__(self) -> str:\n        return str(self.val)\n\n    def __eq__(self, other: Any) -> bool:\n        if isinstance(other, LooseCompare):\n            other_val = other.val\n        else:\n            other_val = other\n        if isinstance(self.val, (int, float)) and isinstance(other_val, (int, float)):\n            return self.val == other_val\n        return str(self.val) == str(other_val)\n\n\ndef better_sorted_str_terms(val: Any) -> Any:\n    \"\"\"A function that orders \"a10000\" after \"a9\", instead of before.\n\n    Normally, sorting strings sorts them lexicographically, treating numbers so\n    that \"1999999\" ends up being less than \"2\". This method splits the string\n    into a tuple of text pairs and parsed number parts, so that sorting by this\n    key puts \"2\" before \"1999999\".\n\n    Because this method is intended for use in plotting, where it's more\n    important to see a bad result than to see nothing, it returns a type that\n    tries to be comparable to everything.\n\n    Args:\n        val: The value to convert into a value with a better sorting order.\n\n    Returns:\n        A custom type of object with a better sorting order.\n\n    Examples:\n        >>> import sinter\n        >>> items = [\n        ...    \"distance=199999, rounds=3\",\n        ...    \"distance=2, rounds=3\",\n        ...    \"distance=199999, rounds=199999\",\n        ...    \"distance=2, rounds=199999\",\n        ... ]\n        >>> for e in sorted(items, key=sinter.better_sorted_str_terms):\n        ...    print(e)\n        distance=2, rounds=3\n        distance=2, rounds=199999\n        distance=199999, rounds=3\n        distance=199999, rounds=199999\n    \"\"\"\n    if val is None:\n        return 'None'\n    if isinstance(val, tuple):\n        return tuple(better_sorted_str_terms(e) for e in val)\n    if not isinstance(val, str):\n        return LooseCompare(val)\n    terms = split_by(val, lambda c: c in '.0123456789')\n    result = []\n    for term in terms:\n        term = ''.join(term)\n        if '.' in term:\n            try:\n                term = float(term)\n            except ValueError:\n                try:\n                    term = tuple(int(e) for e in term.split('.'))\n                except ValueError:\n                    pass\n        else:\n            try:\n                term = int(term)\n            except ValueError:\n                pass\n        result.append(term)\n    if len(result) == 1 and isinstance(result[0], (int, float)):\n        return LooseCompare(result[0])\n    return tuple(LooseCompare(e) for e in result)\n\n\ndef group_by(items: Iterable[TVal],\n             *,\n             key: Callable[[TVal], TKey],\n             ) -> Dict[TKey, List[TVal]]:\n    \"\"\"Groups items based on whether they produce the same key from a function.\n\n    Args:\n        items: The items to group.\n        key: Items that produce the same value from this function get grouped together.\n\n    Returns:\n        A dictionary mapping outputs that were produced by the grouping function to\n        the list of items that produced that output.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.group_by([1, 2, 3], key=lambda i: i == 2)\n        {False: [1, 3], True: [2]}\n\n        >>> sinter.group_by(range(10), key=lambda i: i % 3)\n        {0: [0, 3, 6, 9], 1: [1, 4, 7], 2: [2, 5, 8]}\n    \"\"\"\n\n    result: Dict[TKey, List[TVal]] = {}\n\n    for item in items:\n        curve_id = key(item)\n        result.setdefault(curve_id, []).append(item)\n\n    return result\n\n\nTCurveId = TypeVar('TCurveId')\n\n\nclass _FrozenDict:\n    def __init__(self, v: dict):\n        self._v = dict(v)\n        self._eq = frozenset(v.items())\n        self._hash = hash(self._eq)\n\n        terms = []\n        for k in sorted(self._v.keys(), key=lambda e: (e != 'sort', e)):\n            terms.append(k)\n            terms.append(better_sorted_str_terms(self._v[k])\n        )\n        self._order = tuple(terms)\n\n    def __eq__(self, other):\n        if isinstance(other, _FrozenDict):\n            return self._eq == other._eq\n        return NotImplemented\n\n    def __lt__(self, other):\n        if isinstance(other, _FrozenDict):\n            return self._order < other._order\n        return NotImplemented\n\n    def __ne__(self, other):\n        return not (self == other)\n\n    def __hash__(self):\n        return self._hash\n\n    def __getitem__(self, item):\n        return self._v[item]\n\n    def get(self, item, alternate = None):\n        return self._v.get(item, alternate)\n\n    def __str__(self):\n        return \" \".join(str(v) for _, v in sorted(self._v.items()))\n\n\ndef plot_discard_rate(\n        *,\n        ax: 'plt.Axes',\n        stats: 'Iterable[sinter.TaskStats]',\n        x_func: Callable[['sinter.TaskStats'], Any],\n        failure_units_per_shot_func: Callable[['sinter.TaskStats'], Any] = lambda _: 1,\n        group_func: Callable[['sinter.TaskStats'], TCurveId] = lambda _: None,\n        filter_func: Callable[['sinter.TaskStats'], Any] = lambda _: True,\n        plot_args_func: Callable[[int, TCurveId, List['sinter.TaskStats']], Dict[str, Any]] = lambda index, group_key, group_stats: dict(),\n        highlight_max_likelihood_factor: Optional[float] = 1e3,\n        point_label_func: Callable[['sinter.TaskStats'], Any] = lambda _: None,\n) -> None:\n    \"\"\"Plots discard rates in curves with uncertainty highlights.\n\n    Args:\n        ax: The plt.Axes to plot onto. For example, the `ax` value from `fig, ax = plt.subplots(1, 1)`.\n        stats: The collected statistics to plot.\n        x_func: The X coordinate to use for each stat's data point. For example, this could be\n            `x_func=lambda stat: stat.json_metadata['physical_error_rate']`.\n        failure_units_per_shot_func: How many discard chances there are per shot. This rescales what the\n            discard rate means. By default, it is the discard rate per shot, but this allows\n            you to instead make it the discard rate per round. For example, if the metadata\n            associated with a shot has a field 'r' which is the number of rounds, then this can be\n            achieved with `failure_units_per_shot_func=lambda stats: stats.metadata['r']`.\n        group_func: Optional. When specified, multiple curves will be plotted instead of one curve.\n            The statistics are grouped into curves based on whether or not they get the same result\n            out of this function. For example, this could be `group_func=lambda stat: stat.decoder`.\n            If the result of the function is a dictionary, then optional keys in the dictionary will\n            also control the plotting of each curve. Available keys are:\n                'label': the label added to the legend for the curve\n                'color': the color used for plotting the curve\n                'marker': the marker used for the curve\n                'linestyle': the linestyle used for the curve\n                'sort': the order in which the curves will be plotted and added to the legend\n            e.g. if two curves (with different resulting dictionaries from group_func) share the same\n            value for key 'marker', they will be plotted with the same marker.\n            Colors, markers and linestyles are assigned in order, sorted by the values for those keys.\n        filter_func: Optional. When specified, some curves will not be plotted.\n            The statistics are filtered and only plotted if filter_func(stat) returns True.\n            For example, `filter_func=lambda s: s.json_metadata['basis'] == 'x'` would plot only stats\n            where the saved metadata indicates the basis was 'x'.\n        plot_args_func: Optional. Specifies additional arguments to give the underlying calls to\n            `plot` and `fill_between` used to do the actual plotting. For example, this can be used\n            to specify markers and colors. Takes the index of the curve in sorted order and also a\n            curve_id (these will be 0 and None respectively if group_func is not specified). For example,\n            this could be:\n\n                plot_args_func=lambda index, curve_id: {'color': 'red'\n                                                        if curve_id == 'pymatching'\n                                                        else 'blue'}\n\n        highlight_max_likelihood_factor: Controls how wide the uncertainty highlight region around curves is.\n            Must be 1 or larger. Hypothesis probabilities at most that many times as unlikely as the max likelihood\n            hypothesis will be highlighted.\n        point_label_func: Optional. Specifies text to draw next to data points.\n    \"\"\"\n    if highlight_max_likelihood_factor is None:\n        highlight_max_likelihood_factor = 1\n\n    def y_func(stat: 'sinter.TaskStats') -> Union[float, 'sinter.Fit']:\n        result = fit_binomial(\n            num_shots=stat.shots,\n            num_hits=stat.discards,\n            max_likelihood_factor=highlight_max_likelihood_factor,\n        )\n\n        pieces = failure_units_per_shot_func(stat)\n        result = Fit(\n            low=shot_error_rate_to_piece_error_rate(result.low, pieces=pieces),\n            best=shot_error_rate_to_piece_error_rate(result.best, pieces=pieces),\n            high=shot_error_rate_to_piece_error_rate(result.high, pieces=pieces),\n        )\n\n        if highlight_max_likelihood_factor == 1:\n            return result.best\n        return result\n\n    plot_custom(\n        ax=ax,\n        stats=stats,\n        x_func=x_func,\n        y_func=y_func,\n        group_func=group_func,\n        filter_func=filter_func,\n        plot_args_func=plot_args_func,\n        point_label_func=point_label_func,\n    )\n\n\ndef plot_error_rate(\n        *,\n        ax: 'plt.Axes',\n        stats: 'Iterable[sinter.TaskStats]',\n        x_func: Callable[['sinter.TaskStats'], Any],\n        failure_units_per_shot_func: Callable[['sinter.TaskStats'], Any] = lambda _: 1,\n        failure_values_func: Callable[['sinter.TaskStats'], Any] = lambda _: 1,\n        group_func: Callable[['sinter.TaskStats'], TCurveId] = lambda _: None,\n        filter_func: Callable[['sinter.TaskStats'], Any] = lambda _: True,\n        plot_args_func: Callable[[int, TCurveId, List['sinter.TaskStats']], Dict[str, Any]] = lambda index, group_key, group_stats: dict(),\n        highlight_max_likelihood_factor: Optional[float] = 1e3,\n        line_fits: Optional[Tuple[Literal['linear', 'log', 'sqrt'], Literal['linear', 'log', 'sqrt']]] = None,\n        point_label_func: Callable[['sinter.TaskStats'], Any] = lambda _: None,\n) -> None:\n    \"\"\"Plots error rates in curves with uncertainty highlights.\n\n    Args:\n        ax: The plt.Axes to plot onto. For example, the `ax` value from `fig, ax = plt.subplots(1, 1)`.\n        stats: The collected statistics to plot.\n        x_func: The X coordinate to use for each stat's data point. For example, this could be\n            `x_func=lambda stat: stat.json_metadata['physical_error_rate']`.\n        failure_units_per_shot_func: How many error chances there are per shot. This rescales what the\n            logical error rate means. By default, it is the logical error rate per shot, but this allows\n            you to instead make it the logical error rate per round. For example, if the metadata\n            associated with a shot has a field 'r' which is the number of rounds, then this can be\n            achieved with `failure_units_per_shot_func=lambda stats: stats.metadata['r']`.\n        failure_values_func: How many independent ways there are for a shot to fail, such as\n            the number of independent observables in a memory experiment. This affects how the failure\n            units rescaling plays out (e.g. with 1 independent failure the \"center\" of the conversion\n            is at 50% whereas for 2 independent failures the \"center\" is at 75%).\n        group_func: Optional. When specified, multiple curves will be plotted instead of one curve.\n            The statistics are grouped into curves based on whether or not they get the same result\n            out of this function. For example, this could be `group_func=lambda stat: stat.decoder`.\n            If the result of the function is a dictionary, then optional keys in the dictionary will\n            also control the plotting of each curve. Available keys are:\n                'label': the label added to the legend for the curve\n                'color': the color used for plotting the curve\n                'marker': the marker used for the curve\n                'linestyle': the linestyle used for the curve\n                'sort': the order in which the curves will be plotted and added to the legend\n            e.g. if two curves (with different resulting dictionaries from group_func) share the same\n            value for key 'marker', they will be plotted with the same marker.\n            Colors, markers and linestyles are assigned in order, sorted by the values for those keys.\n        filter_func: Optional. When specified, some curves will not be plotted.\n            The statistics are filtered and only plotted if filter_func(stat) returns True.\n            For example, `filter_func=lambda s: s.json_metadata['basis'] == 'x'` would plot only stats\n            where the saved metadata indicates the basis was 'x'.\n        plot_args_func: Optional. Specifies additional arguments to give the underlying calls to\n            `plot` and `fill_between` used to do the actual plotting. For example, this can be used\n            to specify markers and colors. Takes the index of the curve in sorted order and also a\n            curve_id (these will be 0 and None respectively if group_func is not specified). For example,\n            this could be:\n\n                plot_args_func=lambda index, curve_id: {'color': 'red'\n                                                        if curve_id == 'pymatching'\n                                                        else 'blue'}\n\n        highlight_max_likelihood_factor: Controls how wide the uncertainty highlight region around curves is.\n            Must be 1 or larger. Hypothesis probabilities at most that many times as unlikely as the max likelihood\n            hypothesis will be highlighted.\n        line_fits: Defaults to None. Set this to a tuple (x_scale, y_scale) to include a dashed line\n            fit to every curve. The scales determine how to transform the coordinates before\n            performing the fit, and can be set to 'linear', 'sqrt', or 'log'.\n        point_label_func: Optional. Specifies text to draw next to data points.\n    \"\"\"\n    if highlight_max_likelihood_factor is None:\n        highlight_max_likelihood_factor = 1\n    if not (highlight_max_likelihood_factor >= 1):\n        raise ValueError(f\"not (highlight_max_likelihood_factor={highlight_max_likelihood_factor} >= 1)\")\n\n    def y_func(stat: 'sinter.TaskStats') -> Union[float, 'sinter.Fit']:\n        result = fit_binomial(\n            num_shots=stat.shots - stat.discards,\n            num_hits=stat.errors,\n            max_likelihood_factor=highlight_max_likelihood_factor,\n        )\n\n        pieces = failure_units_per_shot_func(stat)\n        values = failure_values_func(stat)\n        result = Fit(\n            low=shot_error_rate_to_piece_error_rate(result.low, pieces=pieces, values=values),\n            best=shot_error_rate_to_piece_error_rate(result.best, pieces=pieces, values=values),\n            high=shot_error_rate_to_piece_error_rate(result.high, pieces=pieces, values=values),\n        )\n\n        if stat.errors == 0:\n            result = Fit(low=result.low, high=result.high, best=float('nan'))\n\n        if highlight_max_likelihood_factor == 1:\n            return result.best\n        return result\n\n    plot_custom(\n        ax=ax,\n        stats=stats,\n        x_func=x_func,\n        y_func=y_func,\n        group_func=group_func,\n        filter_func=filter_func,\n        plot_args_func=plot_args_func,\n        line_fits=line_fits,\n        point_label_func=point_label_func,\n    )\n\n\ndef _rescale(v: Sequence[float], scale: str, invert: bool) -> np.ndarray:\n    if scale == 'linear':\n        return np.array(v)\n    elif scale == 'log':\n        return np.exp(v) if invert else np.log(v)\n    elif scale == 'sqrt':\n        return np.array(v)**2 if invert else np.sqrt(v)\n    else:\n        raise NotImplementedError(f'{scale=}')\n\n\ndef plot_custom(\n        *,\n        ax: 'plt.Axes',\n        stats: 'Iterable[sinter.TaskStats]',\n        x_func: Callable[['sinter.TaskStats'], Any],\n        y_func: Callable[['sinter.TaskStats'], Union['sinter.Fit', float, int]],\n        group_func: Callable[['sinter.TaskStats'], TCurveId] = lambda _: None,\n        point_label_func: Callable[['sinter.TaskStats'], Any] = lambda _: None,\n        filter_func: Callable[['sinter.TaskStats'], Any] = lambda _: True,\n        plot_args_func: Callable[[int, TCurveId, List['sinter.TaskStats']], Dict[str, Any]] = lambda index, group_key, group_stats: dict(),\n        line_fits: Optional[Tuple[Literal['linear', 'log', 'sqrt'], Literal['linear', 'log', 'sqrt']]] = None,\n) -> None:\n    \"\"\"Plots error rates in curves with uncertainty highlights.\n\n    Args:\n        ax: The plt.Axes to plot onto. For example, the `ax` value from `fig, ax = plt.subplots(1, 1)`.\n        stats: The collected statistics to plot.\n        x_func: The X coordinate to use for each stat's data point. For example, this could be\n            `x_func=lambda stat: stat.json_metadata['physical_error_rate']`.\n        y_func: The Y value to use for each stat's data point. This can be a float or it can be a\n            sinter.Fit value, in which case the curve will follow the fit.best value and a\n            highlighted area will be shown from fit.low to fit.high.\n        group_func: Optional. When specified, multiple curves will be plotted instead of one curve.\n            The statistics are grouped into curves based on whether or not they get the same result\n            out of this function. For example, this could be `group_func=lambda stat: stat.decoder`.\n            If the result of the function is a dictionary, then optional keys in the dictionary will\n            also control the plotting of each curve. Available keys are:\n                'label': the label added to the legend for the curve\n                'color': the color used for plotting the curve\n                'marker': the marker used for the curve\n                'linestyle': the linestyle used for the curve\n                'sort': the order in which the curves will be plotted and added to the legend\n            e.g. if two curves (with different resulting dictionaries from group_func) share the same\n            value for key 'marker', they will be plotted with the same marker.\n            Colors, markers and linestyles are assigned in order, sorted by the values for those keys.\n        point_label_func: Optional. Specifies text to draw next to data points.\n        filter_func: Optional. When specified, some curves will not be plotted.\n            The statistics are filtered and only plotted if filter_func(stat) returns True.\n            For example, `filter_func=lambda s: s.json_metadata['basis'] == 'x'` would plot only stats\n            where the saved metadata indicates the basis was 'x'.\n        plot_args_func: Optional. Specifies additional arguments to give the underlying calls to\n            `plot` and `fill_between` used to do the actual plotting. For example, this can be used\n            to specify markers and colors. Takes the index of the curve in sorted order and also a\n            curve_id (these will be 0 and None respectively if group_func is not specified). For example,\n            this could be:\n\n                plot_args_func=lambda index, group_key, group_stats: {\n                    'color': (\n                        'red'\n                        if group_key == 'decoder=pymatching p=0.001'\n                        else 'blue'\n                    ),\n                }\n        line_fits: Defaults to None. Set this to a tuple (x_scale, y_scale) to include a dashed line\n            fit to every curve. The scales determine how to transform the coordinates before\n            performing the fit, and can be set to 'linear', 'sqrt', or 'log'.\n    \"\"\"\n\n    def group_dict_func(item: 'sinter.TaskStats') -> _FrozenDict:\n        e = group_func(item)\n        return _FrozenDict(e if isinstance(e, dict) else {'label': str(e)})\n\n    # Backwards compatibility to when the group stats argument wasn't present.\n    import inspect\n    if len(inspect.signature(plot_args_func).parameters) == 2:\n        old_plot_args_func = cast(Callable[[int, TCurveId], Any], plot_args_func)\n        plot_args_func = lambda a, b, _: old_plot_args_func(a, b)\n\n    filtered_stats: List['sinter.TaskStats'] = [\n        stat\n        for stat in stats\n        if filter_func(stat)\n    ]\n\n    curve_groups = group_by(filtered_stats, key=group_dict_func)\n    colors = {\n        k: f'C{i}'\n        for i, k in enumerate(sorted({g.get('color', g) for g in curve_groups.keys()}, key=better_sorted_str_terms))\n    }\n    markers = {\n        k: MARKERS[i % len(MARKERS)]\n        for i, k in enumerate(sorted({g.get('marker', g) for g in curve_groups.keys()}, key=better_sorted_str_terms))\n    }\n    linestyles = {\n        k: LINESTYLES[i % len(LINESTYLES)]\n        for i, k in enumerate(sorted({g.get('linestyle', None) for g in curve_groups.keys()}, key=better_sorted_str_terms))\n    }\n\n    def sort_key(a: Any) -> Any:\n        if isinstance(a, _FrozenDict):\n            return a.get('sort', better_sorted_str_terms(a))\n        return better_sorted_str_terms(a)\n\n    for k, group_key in enumerate(sorted(curve_groups.keys(), key=sort_key)):\n        group = curve_groups[group_key]\n        group = sorted(group, key=x_func)\n        color = colors[group_key.get('color', group_key)]\n        marker = markers[group_key.get('marker', group_key)]\n        linestyle = linestyles[group_key.get('linestyle', None)]\n        label = str(group_key.get('label', group_key))\n        xs_label: list[float] = []\n        ys_label: list[float] = []\n        vs_label: list[float] = []\n        xs_best: list[float] = []\n        ys_best: list[float] = []\n        xs_low_high: list[float] = []\n        ys_low: list[float] = []\n        ys_high: list[float] = []\n        for item in group:\n            x = x_func(item)\n            y = y_func(item)\n            point_label = point_label_func(item)\n            if isinstance(y, Fit):\n                if y.low is not None and y.high is not None and not math.isnan(y.low) and not math.isnan(y.high):\n                    xs_low_high.append(x)\n                    ys_low.append(y.low)\n                    ys_high.append(y.high)\n                if y.best is not None and not math.isnan(y.best):\n                    ys_best.append(y.best)\n                    xs_best.append(x)\n\n                if point_label:\n                    cy = None\n                    for e in [y.best, y.high, y.low]:\n                        if e is not None and not math.isnan(e):\n                            cy = e\n                            break\n                    if cy is not None:\n                        xs_label.append(x)\n                        ys_label.append(cy)\n                        vs_label.append(point_label)\n            elif not math.isnan(y):\n                xs_best.append(x)\n                ys_best.append(y)\n                if point_label:\n                    xs_label.append(x)\n                    ys_label.append(y)\n                    vs_label.append(point_label)\n        args = dict(plot_args_func(k, group_func(group[0]), group))\n        if 'linestyle' not in args:\n            args['linestyle'] = linestyle\n        if 'marker' not in args:\n            args['marker'] = marker\n        if 'color' not in args:\n            args['color'] = color\n        if 'label' not in args:\n            args['label'] = label\n        ax.plot(xs_best, ys_best, **args)\n        for x, y, lbl in zip(xs_label, ys_label, vs_label):\n            if lbl:\n                ax.annotate(lbl, (x, y))\n        if len(xs_low_high) > 1:\n            ax.fill_between(xs_low_high, ys_low, ys_high, color=args['color'], alpha=0.2, zorder=-100)\n        elif len(xs_low_high) == 1:\n            l, = ys_low\n            h, = ys_high\n            m = (l + h) / 2\n            ax.errorbar(xs_low_high, [m], yerr=([m - l], [h - m]), marker='', elinewidth=1, ecolor=color, capsize=5)\n\n        if line_fits is not None and len(set(xs_best)) >= 2:\n            x_scale, y_scale = line_fits\n            fit_xs = _rescale(xs_best, x_scale, False)\n            fit_ys = _rescale(ys_best, y_scale, False)\n\n            from scipy.stats import linregress\n            line_fit = linregress(fit_xs, fit_ys)\n\n            x0 = fit_xs[0]\n            x1 = fit_xs[-1]\n            dx = x1 - x0\n            x0 -= dx*10\n            x1 += dx*10\n            if x0 < 0 <= fit_xs[0] > x0 and x_scale == 'sqrt':\n                x0 = 0\n\n            out_xs = np.linspace(x0, x1, 1000)\n            out_ys = out_xs * line_fit.slope + line_fit.intercept\n            out_xs = _rescale(out_xs, x_scale, True)\n            out_ys = _rescale(out_ys, y_scale, True)\n\n            line_fit_kwargs = args.copy()\n            line_fit_kwargs.pop('marker', None)\n            line_fit_kwargs.pop('label', None)\n            line_fit_kwargs['linestyle'] = '--'\n            line_fit_kwargs.setdefault('linewidth', 1)\n            line_fit_kwargs['linewidth'] /= 2\n            ax.plot(out_xs, out_ys, **line_fit_kwargs)\n"
  },
  {
    "path": "glue/sample/src/sinter/_plotting_test.py",
    "content": "import io\n\nfrom matplotlib import pyplot as plt\n\nimport sinter\n\n\ndef test_better_sorted_str_terms():\n    f = sinter.better_sorted_str_terms\n    assert f('everyone et al. 2020') == ('everyone et al', '.', ' ', 2020)\n    assert f('a') == ('a',)\n    assert f('abc') == ('abc',)\n    assert f('a1b2') == ('a', 1, 'b', 2)\n    assert f('a1.5b2') == ('a', 1.5, 'b', 2)\n    assert f('a1.5.3b2') == ('a', (1, 5, 3), 'b', 2)\n    assert f(1) < f(None)\n    assert f(1) < f('2')\n    assert f('2') > f(1)\n    assert sorted([\n        \"planar d=10 r=30\",\n        \"planar d=16 r=36\",\n        \"planar d=4 r=12\",\n        \"toric d=10 r=30\",\n        \"toric d=18 r=54\",\n    ], key=f) == [\n        \"planar d=4 r=12\",\n        \"planar d=10 r=30\",\n        \"planar d=16 r=36\",\n        \"toric d=10 r=30\",\n        \"toric d=18 r=54\",\n    ]\n    assert sorted([\n        \"a1\",\n        \"1a\",\n    ], key=f) == [\n        \"1a\",\n        \"a1\",\n    ]\n\n\ndef test_plotting_does_not_crash():\n    data = io.StringIO()\n    data.write(\"\"\"  shots,errors,discards,seconds,decoder,strong_id,json_metadata\n1000000, 837,0,36.6,pymatching,9f7e20c54fec45b6aef7491b774dd5c0a3b9a005aa82faf5b9c051d6e40d60a9,\"{\"\"d\"\":3,\"\"p\"\":0.001}\"\n  53498,1099,0,6.52,pymatching,3f40432443a99b933fb548b831fb54e7e245d9d73a35c03ea5a2fb2ce270f8c8,\"{\"\"d\"\":3,\"\"p\"\":0.005}\"\n  16269,1023,0,3.23,pymatching,17b2e0c99560d20307204494ac50e31b33e50721b4ebae99d9e3577ae7248874,\"{\"\"d\"\":3,\"\"p\"\":0.01}\"\n1000000, 151,0,77.3,pymatching,e179a18739201250371ffaae0197d8fa19d26b58dfc2942f9f1c85568645387a,\"{\"\"d\"\":5,\"\"p\"\":0.001}\"\n  11363,1068,0,12.5,pymatching,a4dec28934a033215ff1389651a26114ecc22016a6e122008830cf7dd04ba5ad,\"{\"\"d\"\":5,\"\"p\"\":0.01}\"\n  61569,1001,0,24.5,pymatching,2fefcc356752482fb4c6d912c228f6d18762f5752796c668b6abeb7775f5de92,\"{\"\"d\"\":5,\"\"p\"\":0.005}\"\n\"\"\")\n    data.seek(0)\n    stats = sinter.stats_from_csv_files(data)\n\n    fig, ax = plt.subplots(1, 1)\n    sinter.plot_error_rate(\n        ax=ax,\n        stats=stats,\n        group_func=lambda e: f\"Rotated Surface Code d={e.json_metadata['d']}\",\n        x_func=lambda e: e.json_metadata['p'],\n        plot_args_func=lambda k, e: {'marker': \"ov*sp^<>8PhH+xXDd|\"[k]},\n    )\n    sinter.plot_error_rate(\n        ax=ax,\n        stats=stats,\n        group_func=lambda e: f\"Rotated Surface Code d={e.json_metadata['d']}\",\n        x_func=lambda e: e.json_metadata['p'],\n        plot_args_func=lambda k, e: {'marker': \"ov*sp^<>8PhH+xXDd|\"[k]},\n        failure_units_per_shot_func=lambda stats: stats.json_metadata['d'] * 3,\n    )\n    sinter.plot_error_rate(\n        ax=ax,\n        stats=stats,\n        group_func=lambda e: f\"Rotated Surface Code d={e.json_metadata['d']}\",\n        x_func=lambda e: e.json_metadata['p'],\n        plot_args_func=lambda k, e: {'marker': \"ov*sp^<>8PhH+xXDd|\"[k]},\n        failure_units_per_shot_func=lambda stats: stats.json_metadata['d'] * 3,\n        highlight_max_likelihood_factor=None,\n    )\n    sinter.plot_discard_rate(\n        ax=ax,\n        stats=stats,\n        group_func=lambda e: f\"Rotated Surface Code d={e.json_metadata['d']}\",\n        x_func=lambda e: e.json_metadata['p'],\n        plot_args_func=lambda k, e: {'marker': \"ov*sp^<>8PhH+xXDd|\"[k]},\n    )\n    sinter.plot_discard_rate(\n        ax=ax,\n        stats=stats,\n        group_func=lambda e: f\"Rotated Surface Code d={e.json_metadata['d']}\",\n        x_func=lambda e: e.json_metadata['p'],\n        plot_args_func=lambda k, e: {'marker': \"ov*sp^<>8PhH+xXDd|\"[k]},\n        highlight_max_likelihood_factor=None,\n    )\n    sinter.plot_discard_rate(\n        ax=ax,\n        stats=stats,\n        group_func=lambda e: f\"Rotated Surface Code d={e.json_metadata['d']}\",\n        x_func=lambda e: e.json_metadata['p'],\n        plot_args_func=lambda k, e: {'marker': \"ov*sp^<>8PhH+xXDd|\"[k]},\n        failure_units_per_shot_func=lambda stats: stats.json_metadata['d'] * 3,\n    )\n\n\ndef test_group_by():\n    assert sinter.group_by([1, 2, 3], key=lambda i: i == 2) == {False: [1, 3], True: [2]}\n    assert sinter.group_by(range(10), key=lambda i: i % 3) == {0: [0, 3, 6, 9], 1: [1, 4, 7], 2: [2, 5, 8]}\n    assert sinter.group_by([], key=lambda i: 0) == {}\n    assert sinter.group_by([1, 2, 3, 1], key=lambda i: 0) == {0: [1, 2, 3, 1]}\n"
  },
  {
    "path": "glue/sample/src/sinter/_predict.py",
    "content": "import os.path\nimport pathlib\n\nimport math\nimport numpy as np\nimport stim\nimport tempfile\nfrom typing import Optional, Union, Dict, TYPE_CHECKING\n\nfrom sinter._collection import post_selection_mask_from_4th_coord\nfrom sinter._decoding import Decoder, BUILT_IN_DECODERS, streaming_post_select\n\nif TYPE_CHECKING:\n    import sinter\n\n\ndef _converted_on_disk(\n        in_path: pathlib.Path,\n        out_path: pathlib.Path,\n        num_dets: int,\n        num_obs: int,\n        in_format: str,\n        out_format: str) -> pathlib.Path:\n    if in_format == out_format:\n        return in_path\n    raw = stim.read_shot_data_file(\n        path=str(in_path),\n        format=in_format,\n        bit_pack=True,\n        num_detectors=num_dets,\n        num_observables=num_obs,\n    )\n    stim.write_shot_data_file(\n        data=raw,\n        path=str(out_path),\n        format=out_format,\n        num_detectors=num_dets,\n        num_observables=num_obs,\n    )\n    return out_path\n\n\ndef predict_on_disk(\n    *,\n    decoder: str,\n    dem_path: Union[str, pathlib.Path],\n    dets_path: Union[str, pathlib.Path],\n    dets_format: str,\n    obs_out_path: Union[str, pathlib.Path],\n    obs_out_format: str,\n    postselect_detectors_with_non_zero_4th_coord: bool = False,\n    discards_out_path: Optional[Union[str, pathlib.Path]] = None,\n    discards_out_format: Optional[str] = None,\n    custom_decoders: Dict[str, 'sinter.Decoder'] = None,\n) -> None:\n    \"\"\"Performs decoding and postselection on disk.\n\n    Args:\n        decoder: The decoder to use for decoding.\n        dem_path: The detector error model to use to configure the decoder.\n        dets_path: Where the detection event data is stored on disk.\n        dets_format: The format the detection event data is stored in (e.g. '01' or 'b8').\n        obs_out_path: Where to write predicted observable flip data on disk.\n            Note that the predicted observable flip data will not included data from shots discarded by postselection.\n            Use the data in discards_out_path to determine which shots were discarded.\n        obs_out_format: The format to write the observable flip data in (e.g. '01' or 'b8').\n        postselect_detectors_with_non_zero_4th_coord: Activates postselection. Detectors that have a non-zero 4th\n            coordinate will be postselected. Any shot where a postselected detector fires will be discarded.\n            Requires specifying discards_out_path, for indicating which shots were discarded.\n        discards_out_path: Only used if postselection is being used. Where to write discard data on disk.\n        discards_out_format: The format to write discard data in (e.g. '01' or 'b8').\n        custom_decoders: Custom decoders that can be used if requested by name.\n    \"\"\"\n    if (discards_out_path is not None) != (discards_out_format is not None):\n        raise ValueError('(discards_out_path is not None) != (discards_out_format is not None)')\n    if (discards_out_path is not None) != postselect_detectors_with_non_zero_4th_coord:\n        raise ValueError('(discards_out_path is not None) != postselect_detectors_with_non_zero_4th_coord')\n\n    dem_path = pathlib.Path(dem_path)\n    dets_path = pathlib.Path(dets_path)\n    obs_out_path = pathlib.Path(obs_out_path)\n    if discards_out_path is not None:\n        discards_out_path = pathlib.Path(discards_out_path)\n\n    with tempfile.TemporaryDirectory() as tmp_dir:\n        tmp_dir = pathlib.Path(tmp_dir)\n        decode_obj: Optional[Decoder] = None\n        if custom_decoders is not None:\n            decode_obj = custom_decoders.get(decoder)\n        if decode_obj is None:\n            decode_obj = BUILT_IN_DECODERS.get(decoder)\n        if decode_obj is None:\n            raise NotImplementedError(f\"Unrecognized decoder: {decoder!r}\")\n\n        with open(dem_path) as f:\n            dem = stim.DetectorErrorModel(f.read())\n\n        num_dets = dem.num_detectors\n        num_det_bytes = math.ceil(num_dets / 8)\n        num_obs = dem.num_observables\n\n        dets_b8_path = _converted_on_disk(\n            in_path=dets_path,\n            out_path=tmp_dir / 'sinter_dets.b8',\n            in_format=dets_format,\n            out_format='b8',\n            num_dets=num_dets,\n            num_obs=0)\n        if num_det_bytes == 0:\n            raise NotImplementedError(\"Don't know how many shots there are, because num_det_bytes=0.\")\n        num_shots = os.path.getsize(dets_b8_path) // num_det_bytes\n\n        if discards_out_path is not None:\n            if discards_out_format == 'b8':\n                discards_b8_path = discards_out_path\n            else:\n                discards_b8_path = tmp_dir / 'sinter_discards.b8'\n            post_selection_mask = np.zeros(dtype=np.uint8, shape=math.ceil(num_dets / 8))\n            if postselect_detectors_with_non_zero_4th_coord:\n                post_selection_mask = post_selection_mask_from_4th_coord(dem)\n            kept_dets_b8_path = tmp_dir / 'sinter_dets.kept.b8'\n            num_discards = streaming_post_select(\n                num_shots=num_shots,\n                num_dets=num_dets,\n                num_obs=num_obs,\n                dets_in_b8=dets_b8_path,\n                obs_in_b8=None,\n                obs_out_b8=None,\n                discards_out_b8=discards_b8_path,\n                dets_out_b8=kept_dets_b8_path,\n                post_mask=post_selection_mask,\n            )\n            assert discards_out_format is not None\n            _converted_on_disk(\n                in_path=discards_b8_path,\n                out_path=discards_out_path,\n                out_format=discards_out_format,\n                in_format='b8',\n                num_dets=1,\n                num_obs=0,\n            )\n            num_kept_shots = num_shots - num_discards\n        else:\n            kept_dets_b8_path = dets_b8_path\n            num_kept_shots = num_shots\n            if postselect_detectors_with_non_zero_4th_coord:\n                raise ValueError('postselect_detectors_with_non_zero_4th_coord and discards_out_path is None')\n\n        if obs_out_format != 'b8':\n            obs_inter = tmp_dir / 'sinter_obs_inter.b8'\n        else:\n            obs_inter = obs_out_path\n        decode_obj.decode_via_files(\n            num_shots=num_kept_shots,\n            num_dets=num_dets,\n            num_obs=num_obs,\n            dem_path=dem_path,\n            dets_b8_in_path=kept_dets_b8_path,\n            obs_predictions_b8_out_path=obs_inter,\n            tmp_dir=tmp_dir,\n        )\n        _converted_on_disk(\n            in_path=obs_inter,\n            out_path=obs_out_path,\n            out_format=obs_out_format,\n            in_format='b8',\n            num_dets=0,\n            num_obs=num_obs,\n        )\n\n\ndef predict_discards_bit_packed(\n    *,\n    dem: stim.DetectorErrorModel,\n    dets_bit_packed: np.ndarray,\n    postselect_detectors_with_non_zero_4th_coord: bool,\n) -> np.ndarray:\n    \"\"\"Determines which shots to discard due to postselected detectors firing.\n\n    Args:\n        dem: The detector error model the detector data applies to.\n            This is also where coordinate data is read from, in order to\n            determine which detectors to postselect as not having fired.\n        dets_bit_packed: A uint8 numpy array with shape\n            (num_shots, math.ceil(num_dets / 8)). Contains bit packed detection\n            event data.\n        postselect_detectors_with_non_zero_4th_coord: Determines how\n            postselection is done. Currently, this is the only option so it has\n            to be set to True. Any detector from the detector error model that\n            specifies coordinate data with at least four coordinates where the\n            fourth coordinate (coord index 3) is non-zero will be postselected.\n\n    Returns:\n        A numpy bool_ array with shape (num_shots,) where False means not discarded and\n        True means yes discarded.\n    \"\"\"\n    if not postselect_detectors_with_non_zero_4th_coord:\n        raise ValueError(\"not postselect_detectors_with_non_zero_4th_coord\")\n    num_dets = dem.num_detectors\n    nb = math.ceil(num_dets / 8)\n    if len(dets_bit_packed.shape) != 2:\n        raise ValueError(f'len(dets_data_bit_packed.shape={dets_bit_packed.shape}) != 2')\n    if dets_bit_packed.shape[1] != nb:\n        raise ValueError(f'dets_data_bit_packed.shape[1]={dets_bit_packed.shape[1]} != math.ceil(dem.num_detectors={dem.num_detectors} / 8)')\n    if dets_bit_packed.dtype != np.uint8:\n        raise ValueError(f'dets_data_bit_packed.dtype={dets_bit_packed.dtype} != np.uint8')\n\n    post_selection_mask = np.zeros(dtype=np.uint8, shape=nb)\n    if postselect_detectors_with_non_zero_4th_coord:\n        for k, coord in dem.get_detector_coordinates().items():\n            if len(coord) >= 4 and coord[3]:\n                post_selection_mask[k // 8] |= 1 << (k % 8)\n    return np.any(dets_bit_packed & post_selection_mask, axis=1)\n\n\ndef predict_observables(\n    *,\n    dem: stim.DetectorErrorModel,\n    dets: np.ndarray,\n    decoder: str,\n    bit_pack_result: bool = False,\n    custom_decoders: Optional[Dict[str, 'sinter.Decoder']] = None,\n) -> np.ndarray:\n    \"\"\"Predicts which observables were flipped based on detection event data.\n\n    Args:\n        dem: The detector error model the detector data applies to.\n            This is also where coordinate data is read from, in order to\n            determine which detectors to postselect as not having fired.\n        dets: The detection event data. Can be bit packed or not bit packed.\n            If dtype=np.bool_ then shape=(num_shots, num_detectors)\n            If dtype=np.uint8 then shape=(num_shots, math.ceil(num_detectors/8))\n        decoder: The decoder to use for decoding, e.g. \"pymatching\".\n        bit_pack_result: Defaults to False. Determines if the result is bit packed\n            or not.\n        custom_decoders: Custom decoders that can be used if requested by name.\n            If not specified, only decoders built into sinter, such as\n            'pymatching' and 'fusion_blossom', can be used.\n\n    Returns:\n        If bit_packed_result=False (default):\n            dtype=np.bool_\n            shape=(num_shots, num_observables)\n        If bit_packed_result=True:\n            dtype=np.uint8\n            shape=(num_shots, math.ceil(num_observables / 8))\n\n    Examples:\n        >>> import numpy as np\n        >>> import sinter\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     error(0.1) D0 L0\n        ...     error(0.1) D0 D1\n        ...     error(0.1) D1\n        ... ''')\n        >>> sinter.predict_observables(\n        ...     dem=dem,\n        ...     dets=np.array([\n        ...         [False, False],\n        ...         [True, False],\n        ...         [False, True],\n        ...         [True, True],\n        ...     ], dtype=np.bool_),\n        ...     decoder='vacuous',  # try replacing with 'pymatching'\n        ...     bit_pack_result=False,\n        ... )\n        array([[False],\n               [False],\n               [False],\n               [False]])\n    \"\"\"\n\n    if dets.dtype == np.bool_:\n        dets = np.packbits(dets, axis=1, bitorder='little')\n    result = predict_observables_bit_packed(\n        dem=dem,\n        dets_bit_packed=dets,\n        decoder=decoder,\n        custom_decoders=custom_decoders,\n    )\n    if not bit_pack_result:\n        return np.unpackbits(result, axis=1, bitorder='little', count=dem.num_observables).astype(np.bool_)\n    return result\n\n\ndef predict_observables_bit_packed(\n    *,\n    dem: stim.DetectorErrorModel,\n    dets_bit_packed: np.ndarray,\n    decoder: str,\n    custom_decoders: Optional[Dict[str, 'sinter.Decoder']] = None,\n) -> np.ndarray:\n    \"\"\"Predicts which observables were flipped based on detection event data.\n\n    This method predates `sinter.predict_observables` gaining optional bit\n    packing arguments.\n\n    Args:\n        dem: The detector error model the detector data applies to.\n            This is also where coordinate data is read from, in order to\n            determine which detectors to postselect as not having fired.\n        dets_bit_packed: A uint8 numpy array with shape\n            (num_shots, math.ceil(num_dets / 8)). Contains bit packed detection\n            event data.\n        decoder: The decoder to use for decoding, e.g. \"pymatching\".\n        custom_decoders: Custom decoders that can be used if requested by name.\n            If not specified, only decoders built into sinter, such as\n            'pymatching' and 'fusion_blossom', can be used.\n\n    Returns:\n        A numpy uint8 array with shape (num_shots, math.ceil(num_obs / 8)).\n        Contains bit packed observable prediction data.\n\n    Examples:\n        >>> import numpy as np\n        >>> import sinter\n        >>> import stim\n        >>> dem = stim.DetectorErrorModel('''\n        ...     error(0.1) D0 L0\n        ...     error(0.1) D0 D1\n        ...     error(0.1) D1\n        ... ''')\n        >>> sinter.predict_observables_bit_packed(\n        ...     dem=dem,\n        ...     dets_bit_packed=np.array([\n        ...         [0b00],\n        ...         [0b01],\n        ...         [0b10],\n        ...         [0b11],\n        ...     ], dtype=np.uint8),\n        ...     decoder='vacuous',  # try replacing with 'pymatching'\n        ... )\n        array([[0],\n               [0],\n               [0],\n               [0]], dtype=uint8)\n    \"\"\"\n\n    decode_obj: Optional[Decoder] = None\n    if custom_decoders is not None:\n        decode_obj = custom_decoders.get(decoder)\n    if decode_obj is None:\n        decode_obj = BUILT_IN_DECODERS.get(decoder)\n    if decode_obj is None:\n        raise NotImplementedError(f\"Unrecognized decoder: {decoder!r}\")\n\n    with tempfile.TemporaryDirectory() as tmp_dir:\n        tmp_dir = pathlib.Path(tmp_dir)\n        dets_b8_path = tmp_dir / 'sinter_dets.b8'\n        pred_b8_path = tmp_dir / 'sinter_predictions.b8'\n        dem_path = tmp_dir / 'dem.dem'\n        dem.to_file(dem_path)\n        num_dets = dem.num_detectors\n        num_obs = dem.num_observables\n\n        stim.write_shot_data_file(\n            data=dets_bit_packed,\n            path=str(dets_b8_path),\n            format='b8',\n            num_detectors=num_dets,\n            num_observables=0,\n        )\n\n        decode_obj.decode_via_files(\n            num_shots=dets_bit_packed.shape[0],\n            num_dets=num_dets,\n            num_obs=num_obs,\n            dem_path=dem_path,\n            dets_b8_in_path=dets_b8_path,\n            obs_predictions_b8_out_path=pred_b8_path,\n            tmp_dir=tmp_dir,\n        )\n\n        return stim.read_shot_data_file(\n            path=str(pred_b8_path),\n            format='b8',\n            bit_pack=True,\n            num_detectors=0,\n            num_observables=num_obs,\n        )\n"
  },
  {
    "path": "glue/sample/src/sinter/_predict_test.py",
    "content": "import pathlib\n\nimport numpy as np\nimport stim\nimport tempfile\n\nimport sinter\n\n\ndef test_predict_on_disk_no_postselect():\n    with tempfile.TemporaryDirectory() as tmp_dir:\n        tmp_dir = pathlib.Path(tmp_dir)\n        dem_path = tmp_dir / 'dem'\n        dets_path = tmp_dir / 'dets'\n        obs_out_path = tmp_dir / 'obs'\n\n        with open(dem_path, 'w') as f:\n            print(\"\"\"\n                error(0.1) D0 L0\n                detector(0, 0, 0, 1) D0\n            \"\"\", file=f)\n        with open(dets_path, 'w') as f:\n            print(\"0\", file=f)\n            print(\"1\", file=f)\n\n        sinter.predict_on_disk(\n            decoder='pymatching',\n            dem_path=dem_path,\n            dets_path=dets_path,\n            dets_format='01',\n            obs_out_path=obs_out_path,\n            obs_out_format='01',\n            postselect_detectors_with_non_zero_4th_coord=False,\n            discards_out_path=None,\n            discards_out_format=None,\n        )\n\n        with open(obs_out_path) as f:\n            assert f.read() == '0\\n1\\n'\n\n\ndef test_predict_on_disk_yes_postselect():\n    with tempfile.TemporaryDirectory() as tmp_dir:\n        tmp_dir = pathlib.Path(tmp_dir)\n        dem_path = tmp_dir / 'dem'\n        dets_path = tmp_dir / 'dets'\n        obs_out_path = tmp_dir / 'obs'\n        discards_out_path = tmp_dir / 'discards'\n\n        with open(dem_path, 'w') as f:\n            print(\"\"\"\n                error(0.1) D0 L0\n                detector(0, 0, 0, 1) D0\n            \"\"\", file=f)\n        with open(dets_path, 'w') as f:\n            print(\"0\", file=f)\n            print(\"1\", file=f)\n\n        sinter.predict_on_disk(\n            decoder='pymatching',\n            dem_path=dem_path,\n            dets_path=dets_path,\n            dets_format='01',\n            obs_out_path=obs_out_path,\n            obs_out_format='01',\n            postselect_detectors_with_non_zero_4th_coord=True,\n            discards_out_path=discards_out_path,\n            discards_out_format='01',\n        )\n\n        with open(obs_out_path) as f:\n            assert f.read() == '0\\n'\n        with open(discards_out_path) as f:\n            assert f.read() == '0\\n1\\n'\n\n\ndef test_predict_discards_bit_packed_none_postselected():\n    dem = stim.DetectorErrorModel(\"\"\"\n        error(0.1) D0 L0\n    \"\"\")\n    actual = sinter.predict_discards_bit_packed(\n        dem=dem,\n        dets_bit_packed=np.packbits(np.array([\n            [False],\n            [True],\n        ], dtype=np.bool_), bitorder='little', axis=1),\n        postselect_detectors_with_non_zero_4th_coord=True,\n    )\n    np.testing.assert_array_equal(\n        actual,\n        [False, False],\n    )\n\n\ndef test_predict_discards_bit_packed_some_postselected():\n    dem = stim.DetectorErrorModel(\"\"\"\n        error(0.1) D0 L0\n        detector(0, 0, 0, 1) D0\n    \"\"\")\n    actual = sinter.predict_discards_bit_packed(\n        dem=dem,\n        dets_bit_packed=np.packbits(np.array([\n            [False],\n            [True],\n        ], dtype=np.bool_), bitorder='little', axis=1),\n        postselect_detectors_with_non_zero_4th_coord=True,\n    )\n    np.testing.assert_array_equal(\n        actual,\n        [False, True],\n    )\n\n\ndef test_predict_observables_bit_packed():\n    dem = stim.DetectorErrorModel(\"\"\"\n        error(0.1) D0 L0\n    \"\"\")\n\n    actual = sinter.predict_observables_bit_packed(\n        dem=dem,\n        dets_bit_packed=np.packbits(np.array([\n            [False],\n            [True],\n        ], dtype=np.bool_), bitorder='little', axis=1),\n        decoder='pymatching',\n    )\n    np.testing.assert_array_equal(\n        np.unpackbits(actual, bitorder='little', count=1, axis=1),\n        [\n            [False],\n            [True],\n        ],\n    )\n\n\ndef test_predict_observables():\n    dem = stim.DetectorErrorModel(\"\"\"\n        error(0.1) D0 L0\n    \"\"\")\n\n    actual = sinter.predict_observables(\n        dem=dem,\n        dets=np.packbits(np.array([\n            [False],\n            [True],\n        ], dtype=np.bool_), bitorder='little', axis=1),\n        decoder='pymatching',\n        bit_pack_result=True,\n    )\n    np.testing.assert_array_equal(\n        np.unpackbits(actual, bitorder='little', count=1, axis=1),\n        [\n            [False],\n            [True],\n        ],\n    )\n\n    actual = sinter.predict_observables(\n        dem=dem,\n        dets=np.array([\n            [False],\n            [True],\n        ], dtype=np.bool_),\n        decoder='pymatching',\n        bit_pack_result=True,\n    )\n    np.testing.assert_array_equal(\n        np.unpackbits(actual, bitorder='little', count=1, axis=1),\n        [\n            [False],\n            [True],\n        ],\n    )\n\n    actual = sinter.predict_observables(\n        dem=dem,\n        dets=np.packbits(np.array([\n            [False],\n            [True],\n        ], dtype=np.bool_), bitorder='little', axis=1),\n        decoder='pymatching',\n        bit_pack_result=False,\n    )\n    np.testing.assert_array_equal(\n        actual,\n        [[False], [True]],\n    )\n\n    actual = sinter.predict_observables(\n        dem=dem,\n        dets=np.array([\n            [False],\n            [True],\n        ], dtype=np.bool_),\n        decoder='pymatching',\n        bit_pack_result=False,\n    )\n    np.testing.assert_array_equal(\n        actual,\n        [[False], [True]],\n    )\n\n    actual = sinter.predict_observables(\n        dem=dem,\n        dets=np.packbits(np.array([\n            [False],\n            [True],\n        ], dtype=np.bool_), bitorder='little', axis=1),\n        decoder='pymatching',\n    )\n    np.testing.assert_array_equal(\n        actual,\n        [[False], [True]],\n    )\n\n    actual = sinter.predict_observables(\n        dem=dem,\n        dets=np.array([\n            [False],\n            [True],\n        ], dtype=np.bool_),\n        decoder='pymatching',\n    )\n    np.testing.assert_array_equal(\n        actual,\n        [[False], [True]],\n    )\n"
  },
  {
    "path": "glue/sample/src/sinter/_probability_util.py",
    "content": "import dataclasses\nimport math\nimport pathlib\nfrom typing import Any, Dict, Union, Callable, Sequence, TYPE_CHECKING, overload\nfrom typing import Optional\n\nimport numpy as np\n\nif TYPE_CHECKING:\n    import sinter\n\n    # Go on a magical journey looking for scipy's linear regression type.\n    try:\n        from scipy.stats._stats_py import LinregressResult\n    except ImportError:\n        try:\n            from scipy.stats._stats_mstats_common import LinregressResult\n        except ImportError:\n            from scipy.stats import linregress\n            LinregressResult = type(linregress([0, 1], [0, 1]))\n\n\ndef log_binomial(*, p: Union[float, np.ndarray], n: int, hits: int) -> np.ndarray:\n    r\"\"\"Approximates the natural log of a binomial distribution's probability.\n\n    When working with large binomials, it's often necessary to work in log space\n    to represent the result. For example, suppose that out of two million\n    samples 200_000 are hits. The maximum likelihood estimate is p=0.2. Even if\n    this is the true probability, the chance of seeing *exactly* 20% hits out of\n    a million shots is roughly 10^-217322. Whereas the smallest representable\n    double is roughly 10^-324. But ln(10^-217322) ~= -500402.4 is representable.\n\n    This method evaluates $\\ln(P(hits = B(n, p)))$, with all computations done\n    in log space to ensure intermediate values can be represented as floating\n    point numbers without underflowing to 0 or overflowing to infinity. This\n    method can be broadcast over multiple hypothesis probabilities by giving a\n    numpy array for `p` instead of a single float.\n\n    Args:\n        p: The hypotehsis probability. The independent probability of a hit\n            occurring for each sample. This can also be an array of\n            probabilities, in which case the function is broadcast over the\n            array.\n        n: The number of samples that were taken.\n        hits: The number of hits that were observed amongst the samples that\n            were taken.\n\n    Returns:\n        $\\ln(P(hits = B(n, p)))$\n\n    Examples:\n        >>> import sinter\n        >>> sinter.log_binomial(p=0.5, n=100, hits=50)\n        array(-2.5308762, dtype=float32)\n        >>> sinter.log_binomial(p=0.2, n=1_000_000, hits=1_000)\n        array(-216626.97, dtype=float32)\n        >>> sinter.log_binomial(p=0.1, n=1_000_000, hits=1_000)\n        array(-99654.86, dtype=float32)\n        >>> sinter.log_binomial(p=0.01, n=1_000_000, hits=1_000)\n        array(-6742.573, dtype=float32)\n        >>> sinter.log_binomial(p=[0.01, 0.1, 0.2], n=1_000_000, hits=1_000)\n        array([  -6742.573,  -99654.86 , -216626.97 ], dtype=float32)\n    \"\"\"\n    # Clamp probabilities into the valid [0, 1] range (in case float error put them outside it).\n    p_clipped = np.clip(p, 0, 1)\n\n    result = np.zeros(shape=p_clipped.shape, dtype=np.float32)\n    misses = n - hits\n\n    # Handle p=0 and p=1 cases separately, to avoid arithmetic warnings.\n    if hits:\n        result[p_clipped == 0] = -np.inf\n    if misses:\n        result[p_clipped == 1] = -np.inf\n\n    # Multiply p**hits and (1-p)**misses onto the total, in log space.\n    result[p_clipped != 0] += np.log(p_clipped[p_clipped != 0]) * float(hits)\n    result[p_clipped != 1] += np.log1p(-p_clipped[p_clipped != 1]) * float(misses)\n\n    # Multiply (n choose hits) onto the total, in log space.\n    log_n_choose_hits = log_factorial(n) - log_factorial(misses) - log_factorial(hits)\n    result += log_n_choose_hits\n\n    return result\n\n\ndef log_factorial(n: int) -> float:\n    r\"\"\"Approximates $\\ln(n!)$; the natural logarithm of a factorial.\n\n    Args:\n        n: The input to the factorial.\n\n    Returns:\n        Evaluates $ln(n!)$ using `math.lgamma(n+1)`.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.log_factorial(0)\n        0.0\n        >>> sinter.log_factorial(1)\n        0.0\n        >>> sinter.log_factorial(2)\n        0.693147180559945\n        >>> sinter.log_factorial(100)\n        363.73937555556347\n    \"\"\"\n    return math.lgamma(n + 1)\n\n\ndef binary_search(*, func: Callable[[int], float], min_x: int, max_x: int, target: float) -> int:\n    \"\"\"Performs an approximate granular binary search over a monotonically ascending function.\"\"\"\n    while max_x > min_x + 1:\n        med_x = (min_x + max_x) // 2\n        out = func(med_x)\n        if out < target:\n            min_x = med_x\n        elif out > target:\n            max_x = med_x\n        else:\n            return med_x\n    fmax = func(max_x)\n    fmin = func(min_x)\n    dmax = 0 if fmax == target else fmax - target\n    dmin = 0 if fmin == target else fmin - target\n    return max_x if abs(dmax) < abs(dmin) else min_x\n\n\ndef binary_intercept(*, func: Callable[[float], float], start_x: float, step: float, target_y: float, atol: float) -> float:\n    \"\"\"Performs an approximate granular binary search over a monotonically ascending function.\"\"\"\n    start_y = func(start_x)\n    if abs(start_y - target_y) <= atol:\n        return start_x\n    while (func(start_x + step) >= target_y) == (start_y >= target_y):\n        step *= 2\n        if np.isinf(step) or step == 0:\n            raise ValueError(\"Failed.\")\n    xs = [start_x, start_x + step]\n    min_x = min(xs)\n    max_x = max(xs)\n    increasing = func(min_x) < func(max_x)\n\n    while True:\n        med_x = (min_x + max_x) / 2\n        med_y = func(med_x)\n        if abs(med_y - target_y) <= atol:\n            return med_x\n        assert med_x not in [min_x, max_x]\n        if (med_y < target_y) == increasing:\n            min_x = med_x\n        else:\n            max_x = med_x\n\n\ndef least_squares_cost(*, xs: np.ndarray, ys: np.ndarray, intercept: float, slope: float) -> float:\n    assert len(xs.shape) == 1\n    assert xs.shape == ys.shape\n    return np.sum((intercept + slope*xs - ys)**2)\n\n\ndef least_squares_through_point(*, xs: np.ndarray, ys: np.ndarray, required_x: float, required_y: float) -> 'LinregressResult':\n    # Local import to reduce initial cost of importing sinter.\n    from scipy.optimize import leastsq\n    from scipy.stats import linregress\n\n    # HACK: get scipy's linear regression result type\n    LinregressResult = type(linregress([0, 1], [0, 1]))\n\n    xs2 = xs - required_x\n    ys2 = ys - required_y\n\n    def err(slope: float) -> float:\n        return least_squares_cost(xs=xs2, ys=ys2, intercept=0, slope=slope)\n\n    (best_slope,), _ = leastsq(func=err, x0=0.0)\n    intercept = required_y - required_x * best_slope\n    return LinregressResult(best_slope, intercept, None, None, None, intercept_stderr=False)\n\n\ndef least_squares_with_slope(*, xs: np.ndarray, ys: np.ndarray, required_slope: float) -> 'LinregressResult':\n    def err(intercept: float) -> float:\n        return least_squares_cost(xs=xs, ys=ys, intercept=intercept, slope=required_slope)\n\n    # Local import to reduce initial cost of importing sinter.\n    from scipy.optimize import leastsq\n\n    # HACK: get scipy's linear regression result type\n    from scipy.stats import linregress\n    LinregressResult = type(linregress([0, 1], [0, 1]))\n\n    (best_intercept,), _ = leastsq(func=err, x0=0.0)\n    return LinregressResult(required_slope, best_intercept, None, None, None, intercept_stderr=False)\n\n\n@dataclasses.dataclass(frozen=True)\nclass Fit:\n    \"\"\"The result of a fitting process.\n\n    Attributes:\n        low: The hypothesis with the smallest parameter whose cost or score was\n            still \"close to\" the cost of the best hypothesis. For example, this\n            could be a hypothesis whose squared error was within some tolerance\n            of the best fit's square error, or whose likelihood was within some\n            maximum Bayes factor of the max likelihood hypothesis.\n        best: The max likelihood hypothesis. The hypothesis that had the lowest\n            squared error, or the best fitting score.\n        high: The hypothesis with the larger parameter whose cost or score was\n            still \"close to\" the cost of the best hypothesis. For example, this\n            could be a hypothesis whose squared error was within some tolerance\n            of the best fit's square error, or whose likelihood was within some\n            maximum Bayes factor of the max likelihood hypothesis.\n    \"\"\"\n    low: Optional[float]\n    best: Optional[float]\n    high: Optional[float]\n\n    def __repr__(self) -> str:\n        return f'sinter.Fit(low={self.low!r}, best={self.best!r}, high={self.high!r})'\n\n\ndef fit_line_y_at_x(*,\n                    xs: Sequence[float],\n                    ys: Sequence[float],\n                    target_x: float,\n                    max_extra_squared_error: float) -> 'sinter.Fit':\n    \"\"\"Performs a line fit, focusing on the line's y coord at a given x coord.\n\n    Finds the y value at the given x of the best fit, but also the minimum and\n    maximum values for y at the given x amongst all possible line fits whose\n    squared error cost is within the given `max_extra_squared_error` cost of the\n    best fit.\n\n    Args:\n        xs: The x coordinates of points to fit.\n        ys: The y coordinates of points to fit.\n        target_x: The fit values are the value of y at this x coordinate.\n        max_extra_squared_error: When computing the low and high fits, this is\n            the maximum additional squared error that can be introduced by\n            varying the slope away from the best fit.\n\n    Returns:\n        A sinter.Fit containing the best fit for y at the given x, as well as\n        low and high fits that are as far as possible from the best fit while\n        respecting the given max_extra_squared_error.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.fit_line_y_at_x(\n        ...     xs=[1, 2, 3],\n        ...     ys=[10, 12, 14],\n        ...     target_x=4,\n        ...     max_extra_squared_error=1,\n        ... )\n        sinter.Fit(low=14.47247314453125, best=16.0, high=17.52752685546875)\n    \"\"\"\n\n    # Local import to reduce initial cost of importing sinter.\n    from scipy.stats import linregress\n\n    xs = np.array(xs, dtype=np.float64)\n    ys = np.array(ys, dtype=np.float64)\n    fit = linregress(xs, ys)\n    base_cost = least_squares_cost(xs=xs, ys=ys, intercept=fit.intercept, slope=fit.slope)\n    base_y = float(fit.intercept + target_x * fit.slope)\n\n    def cost_for_y(y2: float) -> float:\n        fit2 = least_squares_through_point(xs=xs, ys=ys, required_x=target_x, required_y=y2)\n        return least_squares_cost(xs=xs, ys=ys, intercept=fit2.intercept, slope=fit2.slope)\n\n    low_y = binary_intercept(start_x=base_y, step=-1, target_y=base_cost + max_extra_squared_error, func=cost_for_y, atol=1e-5)\n    high_y = binary_intercept(start_x=base_y, step=1, target_y=base_cost + max_extra_squared_error, func=cost_for_y, atol=1e-5)\n    return Fit(low=low_y, best=base_y, high=high_y)\n\n\ndef fit_line_slope(*,\n              xs: Sequence[float],\n              ys: Sequence[float],\n              max_extra_squared_error: float) -> 'sinter.Fit':\n    \"\"\"Performs a line fit of the given points, focusing on the line's slope.\n\n    Finds the slope of the best fit, but also the minimum and maximum slopes\n    for line fits whose squared error cost is within the given\n    `max_extra_squared_error` cost of the best fit.\n\n    Note that the extra squared error is computed while including a specific\n    offset of some specific line. So the low/high estimates are for specific\n    lines, not for the general class of lines with a given slope, adding\n    together the contributions of all lines in that class.\n\n    Args:\n        xs: The x coordinates of points to fit.\n        ys: The y coordinates of points to fit.\n        max_extra_squared_error: When computing the low and high fits, this is\n            the maximum additional squared error that can be introduced by\n            varying the slope away from the best fit.\n\n    Returns:\n        A sinter.Fit containing the best fit, as well as low and high fits that\n        are as far as possible from the best fit while respective the given\n        max_extra_squared_error.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.fit_line_slope(\n        ...     xs=[1, 2, 3],\n        ...     ys=[10, 12, 14],\n        ...     max_extra_squared_error=1,\n        ... )\n        sinter.Fit(low=1.2928924560546875, best=2.0, high=2.7071075439453125)\n    \"\"\"\n    # Local import to reduce initial cost of importing sinter.\n    from scipy.stats import linregress\n\n    xs = np.array(xs, dtype=np.float64)\n    ys = np.array(ys, dtype=np.float64)\n    fit = linregress(xs, ys)\n    base_cost = least_squares_cost(xs=xs, ys=ys, intercept=fit.intercept, slope=fit.slope)\n\n    def cost_for_slope(slope: float) -> float:\n        fit2 = least_squares_with_slope(xs=xs, ys=ys, required_slope=slope)\n        return least_squares_cost(xs=xs, ys=ys, intercept=fit2.intercept, slope=fit2.slope)\n\n    low_slope = binary_intercept(start_x=fit.slope, step=-1, target_y=base_cost + max_extra_squared_error, func=cost_for_slope, atol=1e-5)\n    high_slope = binary_intercept(start_x=fit.slope, step=1, target_y=base_cost + max_extra_squared_error, func=cost_for_slope, atol=1e-5)\n    return Fit(low=float(low_slope), best=float(fit.slope), high=float(high_slope))\n\n\ndef fit_binomial(\n        *,\n        num_shots: int,\n        num_hits: int,\n        max_likelihood_factor: float) -> 'sinter.Fit':\n    \"\"\"Determine hypothesis probabilities compatible with the given hit ratio.\n\n    The result includes the best fit (the max likelihood hypothis) as well as\n    the smallest and largest probabilities whose likelihood is within the given\n    factor of the maximum likelihood hypothesis.\n\n    Args:\n        num_shots: The number of samples that were taken.\n        num_hits: The number of hits that were seen in the samples.\n        max_likelihood_factor: The maximum Bayes factor between the low/high\n            hypotheses and the best hypothesis (the max likelihood hypothesis).\n            This value should be larger than 1 (as opposed to between 0 and 1).\n\n    Returns:\n        A `sinter.Fit` with the low, best, and high hypothesis probabilities.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.fit_binomial(\n        ...     num_shots=100_000_000,\n        ...     num_hits=2,\n        ...     max_likelihood_factor=1000,\n        ... )\n        sinter.Fit(low=2e-10, best=2e-08, high=1.259e-07)\n        >>> sinter.fit_binomial(\n        ...     num_shots=10,\n        ...     num_hits=5,\n        ...     max_likelihood_factor=9,\n        ... )\n        sinter.Fit(low=0.202, best=0.5, high=0.798)\n    \"\"\"\n    if max_likelihood_factor < 1:\n        raise ValueError(f'max_likelihood_factor={max_likelihood_factor} < 1')\n    if num_shots == 0:\n        return Fit(low=0, high=1, best=0.5)\n    log_max_likelihood = log_binomial(p=num_hits / num_shots, n=num_shots, hits=num_hits)\n    target_log_likelihood = log_max_likelihood - math.log(max_likelihood_factor)\n    acc = 100\n    low = binary_search(\n        func=lambda exp_err: log_binomial(p=exp_err / (acc * num_shots), n=num_shots, hits=num_hits),\n        target=target_log_likelihood,\n        min_x=0,\n        max_x=num_hits * acc) / acc\n    high = binary_search(\n        func=lambda exp_err: -log_binomial(p=exp_err / (acc * num_shots), n=num_shots, hits=num_hits),\n        target=-target_log_likelihood,\n        min_x=num_hits * acc,\n        max_x=num_shots * acc) / acc\n    return Fit(best=num_hits / num_shots, low=low / num_shots, high=high / num_shots)\n\n\n@overload\ndef shot_error_rate_to_piece_error_rate(shot_error_rate: float, *, pieces: float, values: float = 1) -> float:\n    pass\n@overload\ndef shot_error_rate_to_piece_error_rate(shot_error_rate: 'sinter.Fit', *, pieces: float, values: float = 1) -> 'sinter.Fit':\n    pass\ndef shot_error_rate_to_piece_error_rate(shot_error_rate: Union[float, 'sinter.Fit'], *, pieces: float, values: float = 1) -> Union[float, 'sinter.Fit']:\n    \"\"\"Convert from total error rate to per-piece error rate.\n\n    Args:\n        shot_error_rate: The rate at which shots fail. If this is set to a sinter.Fit,\n            the conversion broadcasts over the low,best,high of the fit.\n        pieces: The number of xor-pieces we want to subdivide each shot into,\n            as if each piece was an independent chance for the shot to fail and\n            the total chance of a shot failing was the xor of each piece\n            failing.\n        values: The number of or-pieces each shot's failure is being formed out\n            of.\n\n    Returns:\n        Let N = `pieces` (number of rounds)\n        Let V = `values` (number of observables)\n        Let S = `shot_error_rate`\n        Let R = the returned result\n\n        R satisfies the following property. Let X be the probability of each\n        observable flipping, each round. R will be the probability that any of\n        the observables is flipped after 1 round, given this X. X is chosen to\n        satisfy the following condition. If a Bernoulli distribution with\n        probability X is sampled V*N times, and the results grouped into V\n        groups of N, and each group is reduced to a single value using XOR, and\n        then the reduced group values are reduced to a single final value using\n        OR, then this final value will be True with probability S.\n\n        Or, in other words, if a shot consists of N rounds which V independent\n        observables must survive, then R is like the per-round failure for\n        any of the observables.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.shot_error_rate_to_piece_error_rate(\n        ...     shot_error_rate=0.1,\n        ...     pieces=2,\n        ... )\n        0.05278640450004207\n        >>> sinter.shot_error_rate_to_piece_error_rate(\n        ...     shot_error_rate=0.05278640450004207,\n        ...     pieces=1 / 2,\n        ... )\n        0.10000000000000003\n        >>> sinter.shot_error_rate_to_piece_error_rate(\n        ...     shot_error_rate=1e-9,\n        ...     pieces=100,\n        ... )\n        1.000000082740371e-11\n        >>> sinter.shot_error_rate_to_piece_error_rate(\n        ...     shot_error_rate=0.6,\n        ...     pieces=10,\n        ...     values=2,\n        ... )\n        0.12052311142021144\n    \"\"\"\n\n    if isinstance(shot_error_rate, Fit):\n        return Fit(\n            low=shot_error_rate_to_piece_error_rate(shot_error_rate=shot_error_rate.low, pieces=pieces, values=values),\n            best=shot_error_rate_to_piece_error_rate(shot_error_rate=shot_error_rate.best, pieces=pieces, values=values),\n            high=shot_error_rate_to_piece_error_rate(shot_error_rate=shot_error_rate.high, pieces=pieces, values=values),\n        )\n\n    if not (0 <= shot_error_rate <= 1):\n        raise ValueError(f'need (0 <= shot_error_rate={shot_error_rate} <= 1)')\n    if pieces <= 0:\n        raise ValueError('need pieces > 0')\n    if not isinstance(pieces, (int, float)):\n        raise ValueError('need isinstance(pieces, (int, float)')\n    if not isinstance(values, (int, float)):\n        raise ValueError('need isinstance(values, (int, float)')\n    if pieces == 1:\n        return shot_error_rate\n    if values != 1:\n        p = 1 - (1 - shot_error_rate)**(1 / values)\n        p = shot_error_rate_to_piece_error_rate(p, pieces=pieces)\n        return 1 - (1 - p)**values\n\n    if shot_error_rate > 0.5:\n        return 1 - shot_error_rate_to_piece_error_rate(1 - shot_error_rate, pieces=pieces)\n    assert 0 <= shot_error_rate <= 0.5\n    randomize_rate = 2*shot_error_rate\n    round_randomize_rate = 1 - (1 - randomize_rate)**(1 / pieces)\n    round_error_rate = round_randomize_rate / 2\n\n    if round_error_rate == 0:\n        # The intermediate numbers got too small. Fallback to division approximation.\n        return shot_error_rate / pieces\n\n    return round_error_rate\n\n\ndef comma_separated_key_values(path: str) -> Dict[str, Any]:\n    \"\"\"Converts paths like 'folder/d=5,r=3.stim' into dicts like {'d':5,'r':3}.\n\n    On the command line, specifying `--metadata_func auto` results in this\n    method being used to extra metadata from the circuit file paths. Integers\n    and floats will be parsed into their values, instead of being stored as\n    strings.\n\n    Args:\n        path: A file path where the name of the file has a series of terms like\n            'a=b' separated by commas and ending in '.stim'.\n\n    Returns:\n        A dictionary from named keys to parsed values.\n\n    Examples:\n        >>> import sinter\n        >>> sinter.comma_separated_key_values(\"folder/d=5,r=3.5,x=abc.stim\")\n        {'d': 5, 'r': 3.5, 'x': 'abc'}\n    \"\"\"\n    name = pathlib.Path(path).name\n    if '.' in name:\n        name = name[:name.rindex('.')]\n    result = {}\n    for term in name.split(','):\n        parts = term.split('=')\n        if len(parts) != 2:\n            raise ValueError(f\"Expected a path with a filename containing comma-separated key=value terms like 'a=2,b=3.stim', but got {path!r}.\")\n        k, v = parts\n        try:\n            v = int(v)\n        except ValueError:\n            try:\n                v = float(v)\n            except ValueError:\n                pass\n        result[k] = v\n    return result\n"
  },
  {
    "path": "glue/sample/src/sinter/_probability_util_test.py",
    "content": "import math\nfrom typing import Union\n\nimport numpy as np\nimport pytest\n\nimport sinter\nfrom sinter._probability_util import (\n    binary_search, log_binomial, log_factorial, fit_line_y_at_x, fit_line_slope,\n    binary_intercept, least_squares_through_point, fit_binomial, shot_error_rate_to_piece_error_rate,\n)\nfrom sinter._probability_util import comma_separated_key_values\n\n\n@pytest.mark.parametrize(\n    \"arg,result\",\n    {\n        0: 0,\n        1: 0,\n        2: math.log(2),\n        3: math.log(2) + math.log(3),\n        # These values were taken from wolfram alpha:\n        10: 15.1044125730755152952257093292510,\n        100: 363.73937555556349014407999336965,\n        1000: 5912.128178488163348878130886725,\n        10000: 82108.9278368143534553850300635,\n        100000: 1051299.2218991218651292781082,\n    }.items(),\n)\ndef test_log_factorial(arg, result):\n    np.testing.assert_allclose(log_factorial(arg), result, rtol=1e-11)\n\n\n@pytest.mark.parametrize(\n    \"n,p,hits,result\",\n    [\n        (1, 0.5, 0, np.log(0.5)),\n        (1, 0.5, 1, np.log(0.5)),\n        (1, 0.1, 0, np.log(0.9)),\n        (1, 0.1, 1, np.log(0.1)),\n        (2, [0, 1, 0.1, 0.5], 0, [0, -np.inf, np.log(0.9 ** 2), np.log(0.25)]),\n        (2, [0, 1, 0.1, 0.5], 1, [-np.inf, -np.inf, np.log(0.1 * 0.9 * 2), np.log(0.5)]),\n        (2, [0, 1, 0.1, 0.5], 2, [-np.inf, 0, np.log(0.1 ** 2), np.log(0.25)]),\n        # Magic number comes from PDF[BinomialDistribution[10^10, 10^-6], 10000] on wolfram alpha.\n        (10 ** 10, 10 ** -6, 10 ** 4, np.log(0.0039893915536591)),\n        # Corner cases.\n        (1, 0.0, 0, 0),\n        (1, 0.0, 1, -np.inf),\n        (1, 1.0, 0, -np.inf),\n        (1, 1.0, 1, 0),\n        # Array broadcast.\n        (2, np.array([0.0, 0.5, 1.0]), 0, np.array([0.0, np.log(0.25), -np.inf])),\n        (2, np.array([0.0, 0.5, 1.0]), 1, np.array([-np.inf, np.log(0.5), -np.inf])),\n        (2, np.array([0.0, 0.5, 1.0]), 2, np.array([-np.inf, np.log(0.25), 0.0])),\n    ],\n)\ndef test_log_binomial(\n    n: int, p: Union[float, np.ndarray], hits: int, result: Union[float, np.ndarray]\n) -> None:\n    np.testing.assert_allclose(log_binomial(n=n, p=p, hits=hits), result, rtol=1e-2)\n\n\ndef test_binary_search():\n    assert binary_search(func=lambda x: x**2, min_x=0, max_x=10**100, target=100.1) == 10\n    assert binary_search(func=lambda x: x**2, min_x=0, max_x=10**100, target=100) == 10\n    assert binary_search(func=lambda x: x**2, min_x=0, max_x=10**100, target=99.9) == 10\n    assert binary_search(func=lambda x: x**2, min_x=0, max_x=10**100, target=90) == 9\n    assert binary_search(func=lambda x: x**2, min_x=0, max_x=10**100, target=92) == 10\n    assert binary_search(func=lambda x: x**2, min_x=0, max_x=10**100, target=-100) == 0\n    assert binary_search(func=lambda x: x**2, min_x=0, max_x=10**100, target=10**300) == 10**100\n\n\ndef test_least_squares_through_point():\n    fit = least_squares_through_point(\n        xs=np.array([1, 2, 3]),\n        ys=np.array([2, 3, 4]),\n        required_x=1,\n        required_y=2)\n    np.testing.assert_allclose(fit.slope, 1)\n    np.testing.assert_allclose(fit.intercept, 1)\n\n    fit = least_squares_through_point(\n        xs=np.array([1, 2, 3]),\n        ys=np.array([2, 3, 4]),\n        required_x=1,\n        required_y=1)\n    np.testing.assert_allclose(fit.slope, 1.6, rtol=1e-5)\n    np.testing.assert_allclose(fit.intercept, -0.6, atol=1e-5)\n\n\ndef test_binary_intercept():\n    t = binary_intercept(func=lambda x: x**2, start_x=5, step=1, target_y=82.3, atol=0.01)\n    assert t > 0 and abs(t**2 - 82.3) <= 0.01\n    t = binary_intercept(func=lambda x: -x**2, start_x=5, step=1, target_y=-82.3, atol=0.01)\n    assert t > 0 and abs(t**2 - 82.3) <= 0.01\n    t = binary_intercept(func=lambda x: x**2, start_x=0, step=-1, target_y=82.3, atol=0.01)\n    assert t < 0 and abs(t**2 - 82.3) <= 0.01\n    t = binary_intercept(func=lambda x: -x**2, start_x=0, step=-1, target_y=-82.3, atol=0.2)\n    assert t < 0 and abs(t**2 - 82.3) <= 0.2\n\n\ndef test_fit_y_at_x():\n    fit = fit_line_y_at_x(\n        xs=[1, 2, 3],\n        ys=[1, 5, 9],\n        target_x=100,\n        max_extra_squared_error=1,\n    )\n    assert 300 < fit.low < 390 < fit.best < 410 < fit.high < 500\n\n\ndef test_fit_slope():\n    fit = fit_line_slope(\n        xs=[1, 2, 3],\n        ys=[1, 5, 9],\n        max_extra_squared_error=1,\n    )\n    np.testing.assert_allclose(fit.best, 4)\n    assert 3 < fit.low < 3.5 < fit.best < 4.5 < fit.high < 5\n\n\ndef test_fit_binomial_shrink_towards_half():\n    with pytest.raises(ValueError, match='max_likelihood_factor'):\n        fit_binomial(num_shots=10 ** 5, num_hits=10 ** 5 / 2, max_likelihood_factor=0.1)\n\n    fit = fit_binomial(num_shots=10 ** 5, num_hits=10 ** 5 / 2, max_likelihood_factor=1e3)\n    np.testing.assert_allclose(\n        (fit.low, fit.best, fit.high),\n        (0.494122, 0.5, 0.505878),\n        rtol=1e-4,\n    )\n    fit = fit_binomial(num_shots=10 ** 4, num_hits=10 ** 4 / 2, max_likelihood_factor=1e3)\n    np.testing.assert_allclose(\n        (fit.low, fit.best, fit.high),\n        (0.481422, 0.5, 0.518578),\n        rtol=1e-4,\n    )\n    fit = fit_binomial(num_shots=10 ** 4, num_hits=10 ** 4 / 2, max_likelihood_factor=1e2)\n    np.testing.assert_allclose(\n        (fit.low, fit.best, fit.high),\n        (0.48483, 0.5, 0.51517),\n        rtol=1e-4,\n    )\n    fit = fit_binomial(num_shots=1000, num_hits=500, max_likelihood_factor=1e3)\n    np.testing.assert_allclose(\n        (fit.low, fit.best, fit.high),\n        (0.44143, 0.5, 0.55857),\n        rtol=1e-4,\n    )\n    fit = fit_binomial(num_shots=100, num_hits=50, max_likelihood_factor=1e3)\n    np.testing.assert_allclose(\n        (fit.low, fit.best, fit.high),\n        (0.3204, 0.5, 0.6796),\n        rtol=1e-4,\n    )\n\n\n@pytest.mark.parametrize(\"n,c,factor\", [\n    (100, 50, 1e1),\n    (100, 50, 1e2),\n    (100, 50, 1e3),\n    (1000, 500, 1e3),\n    (10**6, 100, 1e3),\n    (10**6, 100, 1e2),\n])\ndef test_fit_binomial_vs_log_binomial(n: int, c: int, factor: float):\n    fit = fit_binomial(num_shots=n, num_hits=n - c, max_likelihood_factor=factor)\n    a = fit.low\n    b = fit.high\n\n    raw = log_binomial(p=(n - c) / n, n=n, hits=n - c)\n    low = log_binomial(p=a, n=n, hits=n - c)\n    high = log_binomial(p=b, n=n, hits=n - c)\n\n    np.testing.assert_allclose(\n        fit.best,\n        (n - c) / n,\n        rtol=1e-4,\n    )\n\n    np.testing.assert_allclose(\n        np.exp(raw - low),\n        factor,\n        rtol=1e-2,\n    )\n    np.testing.assert_allclose(\n        np.exp(raw - high),\n        factor,\n        rtol=1e-2,\n    )\n\n\ndef test_comma_separated_key_values():\n    d = comma_separated_key_values(\"folder/a=2,b=3.0,c=test.stim\")\n    assert d == {\n        'a': 2,\n        'b': 3.0,\n        'c': 'test',\n    }\n    assert type(d['a']) == int\n    assert type(d['b']) == float\n    with pytest.raises(ValueError, match='separated'):\n        comma_separated_key_values(\"folder/a,b=3.0,c=test.stim\")\n\n\ndef test_shot_error_rate_to_piece_error_rate():\n    np.testing.assert_allclose(\n        shot_error_rate_to_piece_error_rate(\n            shot_error_rate=0.2 * (1 - 0.2) * 2,\n            pieces=2,\n        ),\n        0.2,\n        rtol=1e-5)\n\n    np.testing.assert_allclose(\n        shot_error_rate_to_piece_error_rate(\n            shot_error_rate=0.001 * (1 - 0.001) * 2,\n            pieces=2,\n        ),\n        0.001,\n        rtol=1e-5)\n\n    np.testing.assert_allclose(\n        shot_error_rate_to_piece_error_rate(\n            shot_error_rate=0.001 * (1 - 0.001)**2 * 3 + 0.001**3,\n            pieces=3,\n        ),\n        0.001,\n        rtol=1e-5)\n\n    # Extremely low error rates.\n    np.testing.assert_allclose(\n        shot_error_rate_to_piece_error_rate(\n            shot_error_rate=1e-100,\n            pieces=100,\n        ),\n        1e-102,\n        rtol=1e-5)\n\n\ndef test_shot_error_rate_to_piece_error_rate_unions():\n    np.testing.assert_allclose(\n        shot_error_rate_to_piece_error_rate(\n            shot_error_rate=0.75,\n            pieces=1,\n            values=2,\n        ),\n        0.75,\n        rtol=1e-5)\n\n    np.testing.assert_allclose(\n        shot_error_rate_to_piece_error_rate(\n            shot_error_rate=0.2,\n            pieces=1,\n            values=2,\n        ),\n        0.2,\n        rtol=1e-5)\n\n    np.testing.assert_allclose(\n        shot_error_rate_to_piece_error_rate(\n            shot_error_rate=0.001,\n            pieces=1000000,\n            values=2,\n        ),\n        0.001 / 1000000,\n        rtol=1e-2)\n\n    np.testing.assert_allclose(\n        shot_error_rate_to_piece_error_rate(\n            shot_error_rate=0.0975,\n            pieces=10,\n            values=2,\n        ),\n        0.010453280306648605,\n        rtol=1e-5)\n\n\ndef test_fit_repr():\n    v = sinter.Fit(low=0.25, best=1, high=10)\n    assert eval(repr(v), {\"sinter\": sinter}) == v\n"
  },
  {
    "path": "glue/zx/README.md",
    "content": "# Stim ZX\n\nStim ZX is an example of using Stim as a library for implementing other tools.\nStim ZX implements utilities for analyzing stabilizer ZX calculus graphs.\n\n# How to Install\n\nstimzx is not a published pypi package.\nYou have to install it from source using `pip install -e`.\nFor example:\n\n```\ngit clone git@github.com:quantumlib/stim.git\ncd stim\npip install -e glue/zx\n```\n\n# How to Use\n\nStimZX implements one key method for getting the stabilizers of a stabilizer ZX graph:\n\n```\nstimzx.zx_graph_to_external_stabilizers(\n    graph: Union[nx.Graph, nx.MultiGraph]\n) -> List[stimzx.ExternalStabilizer]\n```\n\nand one fun helper method for creating the graphs from text diagrams:\n\n```\nstimzx.text_diagram_to_zx_graph(\n    text_diagram: str\n) -> nx.MultiGraph\n```\n\nFor example:\n\n```python\nimport stimzx\n\n\nprint(\"CNOT graph\")\ncnot_graph = stimzx.text_diagram_to_zx_graph(r\"\"\"\n    in---Z---out\n         |\n    in---X---out\n\"\"\")\nfor e in stimzx.zx_graph_to_external_stabilizers(cnot_graph):\n    print(e)\n# prints:\n# CNOT graph\n# +X_ -> +XX\n# +Z_ -> +Z_\n# +_X -> +_X\n# +_Z -> +ZZ\n\nprint(\"SQRT_X graph\")\nsqrt_x_graph = stimzx.text_diagram_to_zx_graph(r\"\"\"\n    in---X(pi/2)---out\n\"\"\")\nfor e in stimzx.zx_graph_to_external_stabilizers(sqrt_x_graph):\n    print(e)\n# prints:\n# SQRT_X graph\n# +X -> +X\n# +Z -> +Y\n\nprint(\"mystery graph\")\ngraph = stimzx.text_diagram_to_zx_graph(r\"\"\"\n    in---X\n         |\n         H *---Z(-pi/2)---out\n         |/\n    in---X\n\"\"\")\nfor e in stimzx.zx_graph_to_external_stabilizers(graph):\n    print(e)\n# prints:\n# mystery graph\n# +ZX -> +_\n# +XZ -> +Z\n# +Z_ -> +Y\n\n\nprint(\"S distillation graph\")\ns_distill_graph = stimzx.text_diagram_to_zx_graph(r\"\"\"\n                *                  *---------------Z--------------------Z-------Z(pi/2)\n               / \\                 |               |                    |\n        *-----*   *------------Z---+---------------+---Z----------------+-------Z(pi/2)\n        |                      |   |               |   |                |\n        X---X---Z(pi/2)        X---X---Z(pi/2)     X---X---Z(pi/2)      X---X---Z(pi/2)\n        |   |                  |                   |                    |   |\n        *---+------------------Z-------------------+--------------------+---Z---Z(pi/2)\n            |                                      |                    |\n   in-------Z--------------------------------------Z-------------------Z(pi)--------out\n\"\"\")\nfor e in stimzx.zx_graph_to_external_stabilizers(s_distill_graph):\n    print(e)\n# prints:\n# S distillation graph\n# +X -> +Y\n# +Z -> +Z\n```\n"
  },
  {
    "path": "glue/zx/setup.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom setuptools import setup\n\nwith open('README.md', encoding='UTF-8') as f:\n    long_description = f.read()\n\n__version__ = '1.16.dev0'\n\nsetup(\n    name='stimzx',\n    version=__version__,\n    author='Craig Gidney',\n    author_email='craig.gidney@gmail.com',\n    url='https://github.com/quantumlib/stim',\n    license='Apache 2',\n    packages=['stimzx'],\n    description='Implements utilities for analyzing ZX calculus graphs using Stim.',\n    long_description=long_description,\n    long_description_content_type='text/markdown',\n    python_requires='>=3.6.0',\n    data_files=['README.md'],\n    install_requires=['stim', 'networkx~=3.0'],\n    tests_require=['pytest', 'python3-distutils'],\n)\n"
  },
  {
    "path": "glue/zx/stimzx/__init__.py",
    "content": "__version__ = '1.16.dev0'\nfrom ._external_stabilizer import (\n    ExternalStabilizer,\n)\n\nfrom ._text_diagram_parsing import (\n    text_diagram_to_networkx_graph,\n)\n\nfrom ._zx_graph_solver import (\n    zx_graph_to_external_stabilizers,\n    text_diagram_to_zx_graph,\n    ZxType,\n)\n"
  },
  {
    "path": "glue/zx/stimzx/_external_stabilizer.py",
    "content": "from typing import List, Any\n\nimport stim\n\n\nclass ExternalStabilizer:\n    \"\"\"An input-to-output relationship enforced by a stabilizer circuit.\"\"\"\n\n    def __init__(self, *, input: stim.PauliString, output: stim.PauliString):\n        self.input = input\n        self.output = output\n\n    @staticmethod\n    def from_dual(dual: stim.PauliString, num_inputs: int) -> 'ExternalStabilizer':\n        sign = dual.sign\n\n        # Transpose input. Ys get negated.\n        for k in range(num_inputs):\n            if dual[k] == 2:\n                sign *= -1\n\n        return ExternalStabilizer(\n            input=dual[:num_inputs],\n            output=dual[num_inputs:] * sign,\n        )\n\n    @staticmethod\n    def canonicals_from_duals(duals: List[stim.PauliString], num_inputs: int) -> List['ExternalStabilizer']:\n        if not duals:\n            return []\n        duals = [e.copy() for e in duals]\n        num_qubits = len(duals[0])\n        num_outputs = num_qubits - num_inputs\n        id_out = stim.PauliString(num_outputs)\n\n        # Pivot on output qubits, to potentially isolate input-only stabilizers.\n        _eliminate_stabilizers(duals, range(num_inputs, num_qubits))\n\n        # Separate input-only stabilizers from the rest.\n        input_only_stabilizers = []\n        output_using_stabilizers = []\n        for dual in duals:\n            if dual[num_inputs:] == id_out:\n                input_only_stabilizers.append(dual)\n            else:\n                output_using_stabilizers.append(dual)\n\n        # Separately canonicalize the output-using and input-only stabilizers.\n        _eliminate_stabilizers(output_using_stabilizers, range(num_qubits))\n        _eliminate_stabilizers(input_only_stabilizers, range(num_inputs))\n\n        duals = input_only_stabilizers + output_using_stabilizers\n        return [ExternalStabilizer.from_dual(e, num_inputs) for e in duals]\n\n    def __mul__(self, other: 'ExternalStabilizer') -> 'ExternalStabilizer':\n        return ExternalStabilizer(input=other.input * self.input, output=self.output * other.output)\n\n    def __str__(self) -> str:\n        return str(self.input) + ' -> ' + str(self.output)\n\n    def __eq__(self, other: Any) -> bool:\n        if not isinstance(other, ExternalStabilizer):\n            return NotImplemented\n        return self.output == other.output and self.input == other.input\n\n    def __ne__(self, other: Any) -> bool:\n        return not self == other\n\n    def __repr__(self):\n        return f'stimzx.ExternalStabilizer(input={self.input!r}, output={self.output!r})'\n\n\ndef _eliminate_stabilizers(stabilizers: List[stim.PauliString], elimination_indices: range):\n    \"\"\"Performs partial Gaussian elimination on the list of stabilizers.\"\"\"\n    min_pivot = 0\n    for q in elimination_indices:\n        for b in [1, 3]:\n            for pivot in range(min_pivot, len(stabilizers)):\n                p = stabilizers[pivot][q]\n                if p == 2 or p == b:\n                    break\n            else:\n                continue\n            for k, stabilizer in enumerate(stabilizers):\n                p = stabilizer[q]\n                if k != pivot and (p == 2 or p == b):\n                    stabilizer *= stabilizers[pivot]\n            if min_pivot != pivot:\n                stabilizers[min_pivot], stabilizers[pivot] = stabilizers[pivot], stabilizers[min_pivot]\n            min_pivot += 1\n"
  },
  {
    "path": "glue/zx/stimzx/_external_stabilizer_test.py",
    "content": "import stim\nimport stimzx\n\n\ndef test_repr():\n    e = stimzx.ExternalStabilizer(input=stim.PauliString(\"XX\"), output=stim.PauliString(\"Y\"))\n    assert eval(repr(e), {'stimzx': stimzx, 'stim': stim}) == e\n"
  },
  {
    "path": "glue/zx/stimzx/_text_diagram_parsing.py",
    "content": "import re\nfrom typing import Dict, Tuple, TypeVar, List, Set, Callable\n\nimport networkx as nx\n\nK = TypeVar(\"K\")\n\n\ndef text_diagram_to_networkx_graph(text_diagram: str, *, value_func: Callable[[str], K] = str) -> nx.MultiGraph:\n    r\"\"\"Converts a text diagram into a networkx multi graph.\n\n    Args:\n        text_diagram: An ascii text diagram of the graph, linking nodes together with edges. Edges can be horizontal\n            (-), vertical (|), diagonal (/\\), crossing (+), or changing direction (*). Nodes can be alphanumeric with\n            parentheses. It is assumed that all text is shown with a fixed-width font.\n        value_func: An optional transformation to apply to the node text in order to get the node's value. Otherwise\n            the node's value is just its text.\n\n    Example:\n\n        >>> import stimzx\n        >>> import networkx as nx\n        >>> actual = stimzx.text_diagram_to_networkx_graph(r'''\n        ...\n        ...           A\n        ...           |\n        ...    NODE1--+--NODE2----------*\n        ...           |     |          /\n        ...           B     |         /\n        ...                 *------NODE4\n        ...\n        ... ''')\n        >>> expected = nx.MultiGraph()\n        >>> expected.add_node(0, value='A')\n        >>> expected.add_node(1, value='NODE1')\n        >>> expected.add_node(2, value='NODE2')\n        >>> expected.add_node(3, value='B')\n        >>> expected.add_node(4, value='NODE4')\n        >>> _ = expected.add_edge(0, 3)\n        >>> _ = expected.add_edge(1, 2)\n        >>> _ = expected.add_edge(2, 4)\n        >>> _ = expected.add_edge(2, 4)\n        >>> nx.utils.graphs_equal(actual, expected)\n        True\n\n    Returns:\n        A networkx multi graph containing the graph from the text diagram. Nodes in the graph are integers (the ordering\n        of nodes is in the natural string ordering from left to right then top to bottom in the diagram), and have a\n        \"value\" attribute containing either the node's string from the diagram or else a function of that string if\n        value_func was specified.\n    \"\"\"\n    char_map = _text_to_char_map(text_diagram)\n    node_ids, nodes = _find_nodes(char_map, value_func)\n    edges = _find_all_edges(char_map, node_ids)\n    result = nx.MultiGraph()\n    for k, v in enumerate(nodes):\n        result.add_node(k, value=v)\n    for a, b in edges:\n        result.add_edge(a, b)\n    return result\n\n\ndef _text_to_char_map(text: str) -> Dict[complex, str]:\n    char_map = {}\n    x = 0\n    y = 0\n    for c in text:\n        if c == '\\n':\n            x = 0\n            y += 1\n            continue\n        if c != ' ':\n            char_map[x + 1j*y] = c\n        x += 1\n    return char_map\n\n\nDIR_TO_CHARS = {\n    -1 - 1j: '\\\\',\n    0 - 1j: '|+',\n    1 - 1j: '/',\n    -1: '-+',\n    1: '-+',\n    -1 + 1j: '/',\n    1j: '|+',\n    1 + 1j: '\\\\',\n}\n\nCHAR_TO_DIR = {\n    '\\\\': 1 + 1j,\n    '-': 1,\n    '|': 1j,\n    '/': -1 + 1j,\n}\n\n\ndef _find_all_edges(char_map: Dict[complex, str], terminal_map: Dict[complex, K]) -> List[Tuple[K, K]]:\n    edges = []\n    already_travelled = set()\n    for xy, c in char_map.items():\n        x = int(xy.real)\n        y = int(xy.imag)\n        if xy in terminal_map or xy in already_travelled or c in '*+':\n            continue\n        already_travelled.add(xy)\n        dxy = CHAR_TO_DIR.get(c)\n        if dxy is None:\n            raise ValueError(f\"Character {x+1} ('{c}') in line {y+1} isn't part in a node or an edge\")\n        n1 = _find_end_of_edge(xy + dxy, dxy, char_map, terminal_map, already_travelled)\n        n2 = _find_end_of_edge(xy - dxy, -dxy, char_map, terminal_map, already_travelled)\n        edges.append((n2, n1))\n    return edges\n\n\ndef _find_end_of_edge(xy: complex, dxy: complex, char_map: Dict[complex, str], terminal_map: Dict[complex, K], already_travelled: Set[complex]):\n    while True:\n        c = char_map[xy]\n        if xy in terminal_map:\n            return terminal_map[xy]\n\n        if c != '+':\n            if xy in already_travelled:\n                raise ValueError(\"Edge used twice.\")\n            already_travelled.add(xy)\n\n        next_deltas: List[complex] = []\n        if c == '*':\n            for dx2 in [-1, 0, 1]:\n                for dy2 in [-1, 0, 1]:\n                    dxy2 = dx2 + dy2 * 1j\n                    c2 = char_map.get(xy + dxy2)\n                    if dxy2 != 0 and dxy2 != -dxy and c2 is not None and c2 in DIR_TO_CHARS[dxy2]:\n                        next_deltas.append(dxy2)\n            if len(next_deltas) != 1:\n                raise ValueError(f\"Edge junction ('*') at character {int(xy.real)+1}$ in line {int(xy.imag)+1} doesn't have exactly 2 legs.\")\n            dxy, = next_deltas\n        else:\n            expected = DIR_TO_CHARS[dxy]\n            if c not in expected:\n                raise ValueError(f\"Dangling edge at character {int(xy.real)+1} in line {int(xy.imag)+1} travelling dx=${int(dxy.real)},dy={int(dxy.imag)}.\")\n        xy += dxy\n\n\ndef _find_nodes(char_map: Dict[complex, str], value_func: Callable[[str], K]) -> Tuple[Dict[complex, int], List[K]]:\n    node_ids = {}\n    nodes = []\n\n    node_chars = re.compile(\"^[a-zA-Z0-9()]$\")\n    next_node_id = 0\n\n    for xy, lead_char in char_map.items():\n        if xy in node_ids:\n            continue\n        if not node_chars.match(lead_char):\n            continue\n\n        n = 0\n        nested = 0\n        full_name = ''\n        while True:\n            c = char_map.get(xy + n, ' ')\n            if c == ' ' and nested > 0:\n                raise ValueError(\"Label ended before ')' to go with '(' was found.\")\n            if nested == 0 and not node_chars.match(c):\n                break\n            full_name += c\n            if c == '(':\n                nested += 1\n            elif c == ')':\n                nested -= 1\n            n += 1\n\n        nodes.append(value_func(full_name))\n        node_id = next_node_id\n        next_node_id += 1\n        for k in range(n):\n            node_ids[xy + k] = node_id\n\n    return node_ids, nodes\n"
  },
  {
    "path": "glue/zx/stimzx/_text_diagram_parsing_test.py",
    "content": "import networkx as nx\nimport pytest\nfrom ._text_diagram_parsing import _find_nodes, _text_to_char_map, _find_end_of_edge, _find_all_edges, text_diagram_to_networkx_graph\n\n\ndef test_text_to_char_map():\n    assert _text_to_char_map(\"\"\"\nABC DEF\nG    \n HI\n    \"\"\") == {\n        0 + 1j: 'A',\n        1 + 1j: 'B',\n        2 + 1j: 'C',\n        4 + 1j: 'D',\n        5 + 1j: 'E',\n        6 + 1j: 'F',\n        0 + 2j: 'G',\n        1 + 3j: 'H',\n        2 + 3j: 'I',\n    }\n\n\ndef test_find_nodes():\n    assert _find_nodes(_text_to_char_map(''), lambda e: e) == ({}, [])\n    with pytest.raises(ValueError, match=\"base 10\"):\n        _find_nodes(_text_to_char_map('NOTANINT'), int)\n    with pytest.raises(ValueError, match=r\"ended before '\\)'\"):\n        _find_nodes(_text_to_char_map('X(run_off'), str)\n    assert _find_nodes(_text_to_char_map('X'), str) == (\n        {\n            0j: 0,\n        },\n        ['X'],\n    )\n    assert _find_nodes(_text_to_char_map('\\n   X'), str) == (\n        {\n            3 + 1j: 0,\n        },\n        ['X'],\n    )\n    assert _find_nodes(_text_to_char_map('X(pi)'), str) == (\n        {\n            0: 0,\n            1: 0,\n            2: 0,\n            3: 0,\n            4: 0,\n        },\n        ['X(pi)'],\n    )\n    assert _find_nodes(_text_to_char_map('X--Z'), str) == (\n        {\n            0: 0,\n            3: 1,\n        },\n        ['X', 'Z'],\n    )\n    assert _find_nodes(_text_to_char_map(\"\"\"\nX--*\n  /\n Z\n\"\"\"), str) == (\n        {\n            1j: 0,\n            1 + 3j: 1,\n        },\n        ['X', 'Z'],\n    )\n    assert _find_nodes(_text_to_char_map(\"\"\"\nX(pi)--Z\n\"\"\"), str) == (\n        {\n            0 + 1j: 0,\n            1 + 1j: 0,\n            2 + 1j: 0,\n            3 + 1j: 0,\n            4 + 1j: 0,\n            7 + 1j: 1,\n        },\n        [\"X(pi)\", \"Z\"],\n    )\n\n\ndef test_find_end_of_edge():\n    c = _text_to_char_map(r\"\"\"\n1--------*\n          \\    2      |\n     5     \\      *--++-*\n            *-----+-* |/\n                  | | /\n                  2 |/\n                    *\n    \"\"\")\n    terminal = {1: 'ONE', 18 + 6j: 'TWO'}\n    seen = set()\n    assert _find_end_of_edge(1 + 1j, 1, c, terminal, seen) == 'TWO'\n    assert len(seen) == 31\n\n\ndef test_find_all_edges():\n    c = _text_to_char_map(r\"\"\"\nX---Z      H----X(pi/2)\n          /\n       Z(pi/2)\n    \"\"\")\n    node_ids, _ = _find_nodes(c, str)\n    assert _find_all_edges(c, node_ids) == [\n        (0, 1),\n        (2, 3),\n        (2, 4),\n    ]\n\n\ndef test_from_text_diagram():\n    actual = text_diagram_to_networkx_graph(\"\"\"\nin---Z---H---------out\n     |\nin---X---Z(-pi/2)---out\n    \"\"\")\n    expected = nx.MultiGraph()\n    expected.add_node(0, value='in'),\n    expected.add_node(1, value='Z'),\n    expected.add_node(2, value='H'),\n    expected.add_node(3, value='out'),\n    expected.add_node(4, value='in'),\n    expected.add_node(5, value='X'),\n    expected.add_node(6, value='Z(-pi/2)'),\n    expected.add_node(7, value='out'),\n    expected.add_edge(0, 1)\n    expected.add_edge(1, 2)\n    expected.add_edge(2, 3)\n    expected.add_edge(1, 5)\n    expected.add_edge(4, 5)\n    expected.add_edge(5, 6)\n    expected.add_edge(6, 7)\n    assert nx.utils.graphs_equal(actual, expected)\n\n    actual = text_diagram_to_networkx_graph(\"\"\"\n        Z-*\n        | |\n        X-*\n    \"\"\")\n    expected = nx.MultiGraph()\n    expected.add_node(0, value='Z')\n    expected.add_node(1, value='X')\n    expected.add_edge(0, 1)\n    expected.add_edge(0, 1)\n    assert nx.utils.graphs_equal(actual, expected)\n"
  },
  {
    "path": "glue/zx/stimzx/_zx_graph_solver.py",
    "content": "from typing import Dict, Tuple, List, Any, Union\nimport stim\nimport networkx as nx\n\nfrom ._text_diagram_parsing import text_diagram_to_networkx_graph\nfrom ._external_stabilizer import ExternalStabilizer\n\n\nclass ZxType:\n    \"\"\"Data describing a ZX node.\"\"\"\n\n    def __init__(self, kind: str, quarter_turns: int = 0):\n        self.kind = kind\n        self.quarter_turns = quarter_turns\n\n    def __eq__(self, other):\n        if not isinstance(other, ZxType):\n            return NotImplemented\n        return self.kind == other.kind and self.quarter_turns == other.quarter_turns\n\n    def __ne__(self, other):\n        return not self == other\n\n    def __hash__(self):\n        return hash((ZxType, self.kind, self.quarter_turns))\n\n    def __repr__(self):\n        return f'ZxType(kind={self.kind!r}, quarter_turns={self.quarter_turns!r})'\n\n\nZX_TYPES = {\n    \"X\": ZxType(\"X\"),\n    \"X(pi/2)\": ZxType(\"X\", 1),\n    \"X(pi)\": ZxType(\"X\", 2),\n    \"X(-pi/2)\": ZxType(\"X\", 3),\n    \"Z\": ZxType(\"Z\"),\n    \"Z(pi/2)\": ZxType(\"Z\", 1),\n    \"Z(pi)\": ZxType(\"Z\", 2),\n    \"Z(-pi/2)\": ZxType(\"Z\", 3),\n    \"H\": ZxType(\"H\"),\n    \"in\": ZxType(\"in\"),\n    \"out\": ZxType(\"out\"),\n}\n\n\ndef text_diagram_to_zx_graph(text_diagram: str) -> nx.MultiGraph:\n    \"\"\"Converts an ASCII text diagram into a ZX graph (represented as a networkx MultiGraph).\n\n    Supported node types:\n        \"X\": X spider with angle set to 0.\n        \"Z\": Z spider with angle set to 0.\n        \"X(pi/2)\": X spider with angle set to pi/2.\n        \"X(pi)\": X spider with angle set to pi.\n        \"X(-pi/2)\": X spider with angle set to -pi/2.\n        \"Z(pi/2)\": X spider with angle set to pi/2.\n        \"Z(pi)\": X spider with angle set to pi.\n        \"Z(-pi/2)\": X spider with angle set to -pi/2.\n        \"H\": Hadamard node. Must have degree 2.\n        \"in\": Input node. Must have degree 1.\n        \"out\": Output node. Must have degree 1.\n\n    Args:\n        text_diagram: A text diagram containing ZX nodes (e.g. \"X(pi)\") and edges (e.g. \"------\") connecting them.\n\n    Example:\n        >>> import stimzx\n        >>> import networkx\n        >>> actual: networkx.MultiGraph = stimzx.text_diagram_to_zx_graph(r'''\n        ...     in----X------out\n        ...           |\n        ...     in---Z(pi)---out\n        ... ''')\n        >>> expected = networkx.MultiGraph()\n        >>> expected.add_node(0, value=stimzx.ZxType(\"in\"))\n        >>> expected.add_node(1, value=stimzx.ZxType(\"X\"))\n        >>> expected.add_node(2, value=stimzx.ZxType(\"out\"))\n        >>> expected.add_node(3, value=stimzx.ZxType(\"in\"))\n        >>> expected.add_node(4, value=stimzx.ZxType(\"Z\", quarter_turns=2))\n        >>> expected.add_node(5, value=stimzx.ZxType(\"out\"))\n        >>> _ = expected.add_edge(0, 1)\n        >>> _ = expected.add_edge(1, 2)\n        >>> _ = expected.add_edge(1, 4)\n        >>> _ = expected.add_edge(3, 4)\n        >>> _ = expected.add_edge(4, 5)\n        >>> networkx.utils.graphs_equal(actual, expected)\n        True\n\n    Returns:\n        A networkx MultiGraph containing the nodes and edges from the diagram. Nodes are numbered 0, 1, 2, etc in\n            reading ordering from the diagram, and have a \"value\" attribute of type `stimzx.ZxType`.\n    \"\"\"\n    return text_diagram_to_networkx_graph(text_diagram, value_func=ZX_TYPES.__getitem__)\n\n\ndef _reduced_zx_graph(graph: Union[nx.Graph, nx.MultiGraph]) -> nx.Graph:\n    \"\"\"Return an equivalent graph without self edges or repeated edges.\"\"\"\n    reduced_graph = nx.Graph()\n    odd_parity_edges = set()\n    for n1, n2 in graph.edges():\n        if n1 == n2:\n            continue\n        odd_parity_edges ^= {frozenset([n1, n2])}\n    for n, value in graph.nodes('value'):\n        reduced_graph.add_node(n, value=value)\n    for n1, n2 in odd_parity_edges:\n        reduced_graph.add_edge(n1, n2)\n    return reduced_graph\n\n\ndef zx_graph_to_external_stabilizers(graph: Union[nx.Graph, nx.MultiGraph]) -> List[ExternalStabilizer]:\n    \"\"\"Computes the external stabilizers of a ZX graph; generators of Paulis that leave it unchanged including sign.\n\n    Args:\n        graph: A non-contradictory connected ZX graph with nodes annotated by 'type' and optionally by 'angle'.\n            Allowed types are 'x', 'z', 'h', and 'out'.\n            Allowed angles are multiples of `math.pi/2`. Only 'x' and 'z' node types can have angles.\n            'out' nodes must have degree 1.\n            'h' nodes must have degree 2.\n\n    Returns:\n        A list of canonicalized external stabilizer generators for the graph.\n    \"\"\"\n\n    graph = _reduced_zx_graph(graph)\n    sim = stim.TableauSimulator()\n\n    # Interpret each edge as a cup producing an EPR pair.\n    # - The qubits of the EPR pair fly away from the center of the edge, towards their respective nodes.\n    # - The qubit keyed by (a, b) is the qubit heading towards b from the edge between a and b.\n    qubit_ids: Dict[Tuple[Any, Any], int] = {}\n    for n1, n2 in graph.edges:\n        qubit_ids[(n1, n2)] = len(qubit_ids)\n        qubit_ids[(n2, n1)] = len(qubit_ids)\n        sim.h(qubit_ids[(n1, n2)])\n        sim.cnot(qubit_ids[(n1, n2)], qubit_ids[(n2, n1)])\n\n    # Interpret each internal node as a family of post-selected parity measurements.\n    for n, node_type in graph.nodes('value'):\n        if node_type.kind in 'XZ':\n            # Surround X type node with Hadamards so it can be handled as if it were Z type.\n            if node_type.kind == 'X':\n                for neighbor in graph.neighbors(n):\n                    sim.h(qubit_ids[(neighbor, n)])\n        elif node_type.kind == 'H':\n            # Hadamard one input so the H node can be handled as if it were Z type.\n            neighbor, _ = graph.neighbors(n)\n            sim.h(qubit_ids[(neighbor, n)])\n        elif node_type.kind in ['out', 'in']:\n            continue  # Don't measure qubits leaving the system.\n        else:\n            raise ValueError(f\"Unknown node type {node_type!r}\")\n\n        # Handle Z type node.\n        # - Postselects the ZZ observable over each pair of incoming qubits.\n        # - Postselects the (S**quarter_turns X S**-quarter_turns)XX..X observable over all incoming qubits.\n        neighbors = [n2 for n2 in graph.neighbors(n) if n2 != n]\n        center = qubit_ids[(neighbors[0], n)]  # Pick one incoming qubit to be the common control for the others.\n        # Handle node angle using a phasing operation.\n        [id, sim.s, sim.z, sim.s_dag][node_type.quarter_turns](center)\n        # Use multi-target CNOT and Hadamard to transform postselected observables into single-qubit Z observables.\n        for n2 in neighbors[1:]:\n            sim.cnot(center, qubit_ids[(n2, n)])\n        sim.h(center)\n        # Postselect the observables.\n        for n2 in neighbors:\n            _pseudo_postselect(sim, qubit_ids[(n2, n)])\n\n    # Find output qubits.\n    in_nodes = sorted(n for n, value in graph.nodes('value') if value.kind == 'in')\n    out_nodes = sorted(n for n, value in graph.nodes('value') if value.kind == 'out')\n    ext_nodes = in_nodes + out_nodes\n    out_qubits = []\n    for out in ext_nodes:\n        (neighbor,) = graph.neighbors(out)\n        out_qubits.append(qubit_ids[(neighbor, out)])\n\n    # Remove qubits corresponding to non-external edges.\n    for i, q in enumerate(out_qubits):\n        sim.swap(q, len(qubit_ids) + i)\n    for i, q in enumerate(out_qubits):\n        sim.swap(i, len(qubit_ids) + i)\n    sim.set_num_qubits(len(out_qubits))\n\n    # Stabilizers of the simulator state are the external stabilizers of the graph.\n    dual_stabilizers = sim.canonical_stabilizers()\n    return ExternalStabilizer.canonicals_from_duals(dual_stabilizers, len(in_nodes))\n\n\ndef _pseudo_postselect(sim: stim.TableauSimulator, target: int):\n    \"\"\"Pretend to postselect by using classical feedback to consistently get into the measurement-was-false state.\"\"\"\n    measurement_result, kickback = sim.measure_kickback(target)\n    if kickback is not None:\n        for qubit, pauli in enumerate(kickback):\n            feedback_op = [None, sim.cnot, sim.cy, sim.cz][pauli]\n            if feedback_op is not None:\n                feedback_op(stim.target_rec(-1), qubit)\n    assert kickback is not None or not measurement_result, \"Impossible postselection. Graph contained a contradiction.\"\n"
  },
  {
    "path": "glue/zx/stimzx/_zx_graph_solver_test.py",
    "content": "from typing import List\n\nimport stim\n\nfrom ._zx_graph_solver import zx_graph_to_external_stabilizers, text_diagram_to_zx_graph, ExternalStabilizer\n\n\ndef test_disconnected():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X    X---out\n    \"\"\")) == [\n        ExternalStabilizer(input=stim.PauliString(\"Z\"), output=stim.PauliString(\"_\")),\n        ExternalStabilizer(input=stim.PauliString(\"_\"), output=stim.PauliString(\"Z\")),\n    ]\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z---out\n             |\n             X\n    \"\"\")) == [\n        ExternalStabilizer(input=stim.PauliString(\"Z\"), output=stim.PauliString(\"_\")),\n        ExternalStabilizer(input=stim.PauliString(\"_\"), output=stim.PauliString(\"Z\")),\n    ]\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z---X---out\n             |   |\n             *---*\n    \"\"\")) == [\n        ExternalStabilizer(input=stim.PauliString(\"X\"), output=stim.PauliString(\"_\")),\n        ExternalStabilizer(input=stim.PauliString(\"_\"), output=stim.PauliString(\"Z\")),\n    ]\n\n\ndef test_cnot():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X---out\n             |\n        in---Z---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"CNOT 1 0\"))\n\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z---out\n             |\n        in---X---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"CNOT 0 1\"))\n\n\ndef test_cz():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z---out\n             |\n             H\n             |\n        in---Z---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"CZ 0 1\"))\n\n\ndef test_s():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z(pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"S 0\"))\n\n\ndef test_s_dag():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z(-pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"S_DAG 0\"))\n\n\ndef test_sqrt_x():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X(pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"SQRT_X 0\"))\n\n\ndef test_sqrt_x_sqrt_x():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X(pi/2)---X(pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"X 0\"))\n\n\ndef test_sqrt_z_sqrt_z():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z(pi/2)---Z(pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"Z 0\"))\n\n\ndef test_sqrt_x_dag():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X(-pi/2)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"SQRT_X_DAG 0\"))\n\n\ndef test_x():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X(pi)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"X 0\"))\n\n\ndef test_z():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---Z(pi)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"Z 0\"))\n\n\ndef test_id():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(\"\"\"\n        in---X---Z---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"I 0\"))\n\n\ndef test_s_state_distill():\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(r\"\"\"\n                        *                  *---------------Z--------------------Z-------Z(pi/2)\n                       / \\                 |               |                    |\n                *-----*   *------------Z---+---------------+---Z----------------+-------Z(pi/2)\n                |                      |   |               |   |                |\n                X---X---Z(pi/2)        X---X---Z(pi/2)     X---X---Z(pi/2)      X---X---Z(pi/2)\n                |   |                  |                   |                    |   |\n                *---+------------------Z-------------------+--------------------+---Z---Z(pi/2)\n                    |                                      |                    |\n           in-------Z--------------------------------------Z-------------------Z(pi)--------out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"S 0\"))\n\n\ndef external_stabilizers_of_circuit(circuit: stim.Circuit) -> List[ExternalStabilizer]:\n    n = circuit.num_qubits\n    s = stim.TableauSimulator()\n    s.do(circuit)\n    t = s.current_inverse_tableau()**-1\n    stabilizers = []\n    for k in range(n):\n        p = [0] * n\n        p[k] = 1\n        stabilizers.append(stim.PauliString(p) + t.x_output(k))\n        p[k] = 3\n        stabilizers.append(stim.PauliString(p) + t.z_output(k))\n    return [ExternalStabilizer.from_dual(e, circuit.num_qubits) for e in stabilizers]\n\n\ndef test_sign():\n    x, z = external_stabilizers_of_circuit(stim.Circuit(\"X 0\"))\n    assert x.input == stim.PauliString(\"+X\")\n    assert x.output == stim.PauliString(\"+X\")\n    assert z.input == stim.PauliString(\"+Z\")\n    assert z.output == stim.PauliString(\"-Z\")\n\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(r\"\"\"\n        in---X---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"I 0\"))\n\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(r\"\"\"\n        in---X(pi)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"X 0\"))\n\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(r\"\"\"\n        in---Z(pi)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"Z 0\"))\n\n    assert zx_graph_to_external_stabilizers(text_diagram_to_zx_graph(r\"\"\"\n        in---X(pi)---Z(pi)---out\n    \"\"\")) == external_stabilizers_of_circuit(stim.Circuit(\"Y 0\"))\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"stim\",\n  \"title\": \"Stim\",\n  \"description\": \"A quantum stabilizer circuit simulator.\",\n  \"license\": \"Apache-2.0\",\n  \"version\": \"1.0.0\",\n  \"homepage\": \"https://github.com/quantumlib/stim\",\n  \"bugs\": {\n    \"url\": \"https://github.com/quantumlib/stim/issues\"\n  },\n  \"devDependencies\": {\n    \"puppeteer\": \"^5.3.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/quantumlib/stim.git\"\n  }\n}\n"
  },
  {
    "path": "puppeteer_run_tests.js",
    "content": "const puppeteer = require('puppeteer');\n\n(async () => {\n    try {\n        const browser = await puppeteer.launch();\n        const page = await browser.newPage();\n        let caughtPageError = false;\n        page.on('console', message => console.log(message.text()));\n        page.on('pageerror', ({message}) => {\n            caughtPageError = true;\n            console.error(\"Page error bubbled into PuppeteerRunTests.js: \" + message);\n        });\n\n        const outDirUrl = 'file:///' + __dirname.split('\\\\').join('/') + '/out/';\n        await page.goto(outDirUrl + 'all_stim_tests.html#blocking');\n        await page.waitForSelector('#done', {timeout: 5 * 60 * 1000});\n        let anyFailures = await page.evaluate('__any_failures');\n\n        await browser.close();\n        if (anyFailures || caughtPageError) {\n            process.exit(1);\n        }\n    } catch (ex) {\n        console.error(\"Error bubbled up into PuppeteerRunTests.js: \" + ex);\n        process.exit(1);\n    }\n})();\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools\", \"wheel\", \"pybind11~=2.11.1\"]\nbuild-backend = \"setuptools.build_meta\"\n"
  },
  {
    "path": "setup.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport platform\n\nfrom setuptools import setup, Extension\nimport glob\nimport pybind11\n\nALL_SOURCE_FILES = glob.glob(\"src/**/*.cc\", recursive=True)\nMUX_SOURCE_FILES = glob.glob(\"src/**/march.pybind.cc\", recursive=True)\nTEST_FILES = glob.glob(\"src/**/*.test.cc\", recursive=True)\nPERF_FILES = glob.glob(\"src/**/*.perf.cc\", recursive=True)\nMAIN_FILES = glob.glob(\"src/**/main.cc\", recursive=True)\nHEADER_FILES = glob.glob(\"src/**/*.h\", recursive=True) + glob.glob(\"src/**/*.inl\", recursive=True)\nRELEVANT_SOURCE_FILES = sorted(set(ALL_SOURCE_FILES) - set(TEST_FILES + PERF_FILES + MAIN_FILES + MUX_SOURCE_FILES))\n\n__version__ = '1.16.dev0'\n\nif platform.system().startswith('Win'):\n    common_compile_args = [\n        '/std:c++20',\n        '/O2',\n        f'/DVERSION_INFO={__version__}',\n    ]\n    arch_avx = ['/arch:AVX2']\n    arch_sse = ['/arch:SSE2']\n    arch_basic = []\nelse:\n    common_compile_args = [\n        '-std=c++20',\n        '-fno-strict-aliasing',\n        '-O3',\n        '-g0',\n        f'-DVERSION_INFO={__version__}',\n    ]\n    arch_avx = ['-mavx2']\n    arch_sse = ['-msse2', '-mno-avx2']\n    arch_basic = []\n\nstim_detect_machine_architecture = Extension(\n    'stim._detect_machine_architecture',\n    sources=MUX_SOURCE_FILES,\n    include_dirs=[pybind11.get_include(), \"src\"],\n    language='c++',\n    extra_compile_args=[\n        *common_compile_args,\n        *arch_basic,\n    ],\n)\nstim_polyfill = Extension(\n    'stim._stim_polyfill',\n    sources=RELEVANT_SOURCE_FILES,\n    include_dirs=[pybind11.get_include(), \"src\"],\n    language='c++',\n    extra_compile_args=[\n        *common_compile_args,\n        *arch_basic,\n        '-DSTIM_PYBIND11_MODULE_NAME=_stim_polyfill',\n    ],\n)\nstim_sse2 = Extension(\n    'stim._stim_sse2',\n    sources=RELEVANT_SOURCE_FILES,\n    include_dirs=[pybind11.get_include(), \"src\"],\n    language='c++',\n    extra_compile_args=[\n        *common_compile_args,\n        *arch_sse,\n        '-DSTIM_PYBIND11_MODULE_NAME=_stim_sse2',\n    ],\n)\n\n# NOTE: disabled until https://github.com/quantumlib/Stim/issues/432 is fixed\n# stim_avx2 = Extension(\n#     'stim._stim_avx2',\n#     sources=RELEVANT_SOURCE_FILES,\n#     include_dirs=[pybind11.get_include(), \"src\"],\n#     language='c++',\n#     extra_compile_args=[\n#         *common_compile_args,\n#         *arch_avx,\n#         '-DSTIM_PYBIND11_MODULE_NAME=_stim_avx2',\n#     ],\n# )\n\nwith open('glue/python/README.md', encoding='UTF-8') as f:\n    long_description = f.read()\n\ndef _get_extensions():\n    archs=[\"x86\", \"i686\", \"i386\", \"amd64\"]\n    if any(_ext in platform.processor().lower() for _ext in archs):\n        # NOTE: disabled until https://github.com/quantumlib/Stim/issues/432 is fixed\n        # stim_avx2,\n        return [stim_detect_machine_architecture, stim_polyfill,\n                # stim_avx2,\n                stim_sse2]\n    else:\n        return [stim_detect_machine_architecture, stim_polyfill]\n\nsetup(\n    name='stim',\n    version=__version__,\n    author='Craig Gidney',\n    author_email='craig.gidney@gmail.com',\n    url='https://github.com/quantumlib/stim',\n    license='Apache 2',\n    description='A fast library for analyzing with quantum stabilizer circuits.',\n    long_description=long_description,\n    long_description_content_type='text/markdown',\n    ext_modules=_get_extensions(),\n    python_requires='>=3.6.0',\n    packages=['stim'],\n    package_dir={'stim': 'glue/python/src/stim'},\n    package_data={'': [*HEADER_FILES, 'glue/python/src/stim/__init__.pyi', 'glue/python/README.md', 'pyproject.toml']},\n    include_package_data=True,\n    install_requires=['numpy'],\n    entry_points={\n        'console_scripts': ['stim=stim._main_argv:main_argv'],\n    },\n    # Needed on Windows to avoid the default `build` colliding with Bazel's `BUILD`.\n    options={'build': {'build_base': 'python_build_stim'}},\n)\n"
  },
  {
    "path": "src/main.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/main_namespaced.h\"\n\nint main(int argc, const char **argv) {\n    return stim::main(argc, argv);\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/circuit.h\"\n\n#include <algorithm>\n#include <string>\n#include <utility>\n\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\n\nenum class READ_CONDITION {\n    READ_AS_LITTLE_AS_POSSIBLE,\n    READ_UNTIL_END_OF_BLOCK,\n    READ_UNTIL_END_OF_FILE,\n};\n\n/// Concatenates the second pointer range's data into the first.\n/// Typically, the two ranges are contiguous and so this only requires advancing the end of the destination region.\n/// In cases where that doesn't occur, space is created in the given monotonic buffer to store the result and both\n/// the start and end of the destination range move.\nvoid fuse_data(SpanRef<const GateTarget> &dst, SpanRef<const GateTarget> src, MonotonicBuffer<GateTarget> &buf) {\n    if (dst.ptr_end != src.ptr_start) {\n        buf.ensure_available(src.size() + dst.size());\n        dst = buf.take_copy(dst);\n        src = buf.take_copy(src);\n    }\n    assert(dst.ptr_end == src.ptr_start);\n    dst.ptr_end = src.ptr_end;\n}\n\nCircuit::Circuit() : target_buf(), arg_buf(), tag_buf(), operations(), blocks() {\n}\n\nCircuit::Circuit(const Circuit &circuit)\n    : target_buf(circuit.target_buf.total_allocated()),\n      arg_buf(circuit.arg_buf.total_allocated()),\n      tag_buf(circuit.tag_buf.total_allocated()),\n      operations(circuit.operations),\n      blocks(circuit.blocks) {\n    // Keep local copy of operation data.\n    for (auto &op : operations) {\n        op.targets = target_buf.take_copy(op.targets);\n        op.args = arg_buf.take_copy(op.args);\n        op.tag = tag_buf.take_copy(op.tag);\n    }\n}\n\nCircuit::Circuit(Circuit &&circuit) noexcept\n    : target_buf(std::move(circuit.target_buf)),\n      arg_buf(std::move(circuit.arg_buf)),\n      tag_buf(std::move(circuit.tag_buf)),\n      operations(std::move(circuit.operations)),\n      blocks(std::move(circuit.blocks)) {\n}\n\nCircuit &Circuit::operator=(const Circuit &circuit) {\n    if (&circuit != this) {\n        blocks = circuit.blocks;\n        operations = circuit.operations;\n\n        // Keep local copy of operation data.\n        target_buf = MonotonicBuffer<GateTarget>(circuit.target_buf.total_allocated());\n        arg_buf = MonotonicBuffer<double>(circuit.arg_buf.total_allocated());\n        tag_buf = MonotonicBuffer<char>(circuit.tag_buf.total_allocated());\n        for (auto &op : operations) {\n            op.targets = target_buf.take_copy(op.targets);\n            op.args = arg_buf.take_copy(op.args);\n            op.tag = tag_buf.take_copy(op.tag);\n        }\n    }\n    return *this;\n}\n\nCircuit &Circuit::operator=(Circuit &&circuit) noexcept {\n    if (&circuit != this) {\n        operations = std::move(circuit.operations);\n        blocks = std::move(circuit.blocks);\n        target_buf = std::move(circuit.target_buf);\n        arg_buf = std::move(circuit.arg_buf);\n        tag_buf = std::move(circuit.tag_buf);\n    }\n    return *this;\n}\n\nbool Circuit::operator==(const Circuit &other) const {\n    if (operations.size() != other.operations.size() || blocks.size() != other.blocks.size()) {\n        return false;\n    }\n    for (size_t k = 0; k < operations.size(); k++) {\n        if (operations[k].gate_type == GateType::REPEAT && other.operations[k].gate_type == GateType::REPEAT) {\n            if (operations[k].repeat_block_rep_count() != other.operations[k].repeat_block_rep_count()) {\n                return false;\n            }\n            const auto &b1 = operations[k].repeat_block_body(*this);\n            const auto &b2 = other.operations[k].repeat_block_body(other);\n            if (b1 != b2) {\n                return false;\n            }\n        } else if (operations[k] != other.operations[k]) {\n            return false;\n        }\n    }\n    return true;\n}\nbool Circuit::operator!=(const Circuit &other) const {\n    return !(*this == other);\n}\nbool Circuit::approx_equals(const Circuit &other, double atol) const {\n    if (operations.size() != other.operations.size() || blocks.size() != other.blocks.size()) {\n        return false;\n    }\n    for (size_t k = 0; k < operations.size(); k++) {\n        if (operations[k].gate_type == GateType::REPEAT && other.operations[k].gate_type == GateType::REPEAT) {\n            if (operations[k].repeat_block_rep_count() != other.operations[k].repeat_block_rep_count()) {\n                return false;\n            }\n            const auto &b1 = operations[k].repeat_block_body(*this);\n            const auto &b2 = other.operations[k].repeat_block_body(other);\n            if (!b1.approx_equals(b2, atol)) {\n                return false;\n            }\n        } else if (!operations[k].approx_equals(other.operations[k], atol)) {\n            return false;\n        }\n    }\n    return true;\n}\n\ninline bool is_name_char(int c) {\n    return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_';\n}\n\ntemplate <typename SOURCE>\ninline const Gate &read_gate_name(int &c, SOURCE read_char) {\n    char name_buf[32];\n    size_t n = 0;\n    while (is_name_char(c) && n < sizeof(name_buf)) {\n        name_buf[n] = (char)c;\n        c = read_char();\n        n++;\n    }\n    // Note: in the name-too-long case, the full buffer name won't match any gate and an exception will fire.\n    try {\n        return GATE_DATA.at(std::string_view{&name_buf[0], n});\n    } catch (const std::out_of_range &ex) {\n        throw std::invalid_argument(ex.what());\n    }\n}\n\ntemplate <typename SOURCE>\nuint64_t read_uint63_t(int &c, SOURCE read_char) {\n    if (!(c >= '0' && c <= '9')) {\n        throw std::invalid_argument(\"Expected a digit but got '\" + std::string(1, c) + \"'\");\n    }\n    uint64_t result = 0;\n    do {\n        result *= 10;\n        result += c - '0';\n        if (result >= uint64_t{1} << 63) {\n            throw std::invalid_argument(\"Number too large.\");\n        }\n        c = read_char();\n    } while (c >= '0' && c <= '9');\n    return result;\n}\n\ntemplate <typename SOURCE>\ninline void read_arbitrary_targets_into(int &c, SOURCE read_char, Circuit &circuit) {\n    bool need_space = true;\n    while (read_until_next_line_arg(c, read_char, need_space)) {\n        GateTarget t = read_single_gate_target(c, read_char);\n        circuit.target_buf.append_tail(t);\n        need_space = !t.is_combiner();\n    }\n}\n\ntemplate <typename SOURCE>\ninline void read_result_targets64_into(int &c, SOURCE read_char, Circuit &circuit) {\n    while (read_until_next_line_arg(c, read_char)) {\n        uint64_t q = read_uint63_t(c, read_char);\n        circuit.target_buf.append_tail(GateTarget{(uint32_t)(q & 0xFFFFFFFFULL)});\n        circuit.target_buf.append_tail(GateTarget{(uint32_t)(q >> 32)});\n    }\n}\n\ntemplate <typename SOURCE>\nvoid circuit_read_single_operation(Circuit &circuit, char lead_char, SOURCE read_char) {\n    int c = (int)lead_char;\n    const auto &gate = read_gate_name(c, read_char);\n    std::string_view tail_tag;\n    try {\n        read_tag(c, gate.name, read_char, circuit.tag_buf);\n        if (!circuit.tag_buf.tail.empty()) {\n            tail_tag = std::string_view(circuit.tag_buf.tail.ptr_start, circuit.tag_buf.tail.size());\n        }\n\n        read_parens_arguments(c, gate.name, read_char, circuit.arg_buf);\n        if (gate.flags & GATE_IS_BLOCK) {\n            read_result_targets64_into(c, read_char, circuit);\n            if (c != '{') {\n                throw std::invalid_argument(\"Missing '{' at start of \" + std::string(gate.name) + \" block.\");\n            }\n        } else {\n            read_arbitrary_targets_into(c, read_char, circuit);\n            if (c == '{') {\n                throw std::invalid_argument(\"Unexpected '{'.\");\n            }\n            CircuitInstruction(gate.id, circuit.arg_buf.tail, circuit.target_buf.tail, tail_tag).validate();\n        }\n    } catch (const std::invalid_argument &ex) {\n        circuit.target_buf.discard_tail();\n        circuit.arg_buf.discard_tail();\n        throw ex;\n    }\n\n    circuit.tag_buf.commit_tail();\n    circuit.operations.push_back(\n        CircuitInstruction(gate.id, circuit.arg_buf.commit_tail(), circuit.target_buf.commit_tail(), tail_tag));\n}\n\nvoid Circuit::try_fuse_last_two_ops() {\n    if (operations.size() >= 2) {\n        try_fuse_after(operations.size() - 2);\n    }\n}\n\nvoid Circuit::try_fuse_after(size_t index) {\n    if (index + 1 >= operations.size()) {\n        return;\n    }\n    if (operations[index].can_fuse(operations[index + 1])) {\n        fuse_data(operations[index].targets, operations[index + 1].targets, target_buf);\n        operations.erase(operations.begin() + index + 1);\n    }\n}\n\ntemplate <typename SOURCE>\nvoid circuit_read_operations(Circuit &circuit, SOURCE read_char, READ_CONDITION read_condition) {\n    auto &ops = circuit.operations;\n    do {\n        int c = read_char();\n        read_past_dead_space_between_commands(c, read_char);\n        if (c == EOF) {\n            if (read_condition == READ_CONDITION::READ_UNTIL_END_OF_BLOCK) {\n                throw std::invalid_argument(\"Unterminated block. Got a '{' without an eventual '}'.\");\n            }\n            return;\n        }\n        if (c == '}') {\n            if (read_condition != READ_CONDITION::READ_UNTIL_END_OF_BLOCK) {\n                throw std::invalid_argument(\"Uninitiated block. Got a '}' without a '{'.\");\n            }\n            return;\n        }\n        circuit_read_single_operation(circuit, c, read_char);\n        CircuitInstruction &new_op = ops.back();\n\n        if (new_op.gate_type == GateType::REPEAT) {\n            if (new_op.targets.size() != 2) {\n                throw std::invalid_argument(\"Invalid instruction. Expected one repetition arg like `REPEAT 100 {`.\");\n            }\n            uint32_t rep_count_low = new_op.targets[0].data;\n            uint32_t rep_count_high = new_op.targets[1].data;\n            uint32_t block_id = (uint32_t)circuit.blocks.size();\n            if (rep_count_low == 0 && rep_count_high == 0) {\n                throw std::invalid_argument(\"Repeating 0 times is not supported.\");\n            }\n\n            // Read block.\n            circuit.blocks.emplace_back();\n            circuit_read_operations(circuit.blocks.back(), read_char, READ_CONDITION::READ_UNTIL_END_OF_BLOCK);\n\n            // Rewrite target data to reference the parsed block.\n            circuit.target_buf.ensure_available(3);\n            circuit.target_buf.append_tail(GateTarget{block_id});\n            circuit.target_buf.append_tail(GateTarget{rep_count_low});\n            circuit.target_buf.append_tail(GateTarget{rep_count_high});\n            new_op.targets = circuit.target_buf.commit_tail();\n        }\n\n        // Fuse operations.\n        circuit.try_fuse_last_two_ops();\n    } while (read_condition != READ_CONDITION::READ_AS_LITTLE_AS_POSSIBLE);\n}\n\nvoid Circuit::append_from_text(std::string_view text) {\n    size_t k = 0;\n    circuit_read_operations(\n        *this,\n        [&]() {\n            return k < text.size() ? text[k++] : EOF;\n        },\n        READ_CONDITION::READ_UNTIL_END_OF_FILE);\n}\n\nvoid Circuit::safe_append(CircuitInstruction operation, bool block_fusion) {\n    auto flags = GATE_DATA[operation.gate_type].flags;\n    if (flags & GATE_IS_BLOCK) {\n        throw std::invalid_argument(\"Can't append a block like a normal operation.\");\n    }\n\n    operation.validate();\n\n    // Ensure arg/target data is backed by coping it into this circuit's buffers.\n    operation.args = arg_buf.take_copy(operation.args);\n    operation.targets = target_buf.take_copy(operation.targets);\n    operation.tag = tag_buf.take_copy(operation.tag);\n\n    if (!block_fusion && !operations.empty() && operations.back().can_fuse(operation)) {\n        // Extend targets of last gate.\n        fuse_data(operations.back().targets, operation.targets, target_buf);\n    } else {\n        // Add a fresh new operation with its own target data.\n        operations.push_back(operation);\n    }\n}\n\nvoid Circuit::safe_append_ua(\n    std::string_view gate_name, const std::vector<uint32_t> &targets, double singleton_arg, std::string_view tag) {\n    const auto &gate = GATE_DATA.at(gate_name);\n\n    std::vector<GateTarget> converted;\n    converted.reserve(targets.size());\n    for (auto e : targets) {\n        converted.push_back({e});\n    }\n\n    safe_append(CircuitInstruction(gate.id, &singleton_arg, converted, tag));\n}\n\nvoid Circuit::safe_append_u(\n    std::string_view gate_name,\n    const std::vector<uint32_t> &targets,\n    const std::vector<double> &args,\n    std::string_view tag) {\n    const auto &gate = GATE_DATA.at(gate_name);\n\n    std::vector<GateTarget> converted;\n    converted.reserve(targets.size());\n    for (auto e : targets) {\n        converted.push_back({e});\n    }\n\n    safe_append(CircuitInstruction(gate.id, args, converted, tag));\n}\n\nvoid Circuit::safe_insert(size_t index, const CircuitInstruction &instruction) {\n    if (index > operations.size()) {\n        throw std::invalid_argument(\"index > operations.size()\");\n    }\n    auto flags = GATE_DATA[instruction.gate_type].flags;\n    if (flags & GATE_IS_BLOCK) {\n        throw std::invalid_argument(\"Can't insert a block like a normal operation.\");\n    }\n    instruction.validate();\n\n    // Copy arg/target data into this circuit's buffers.\n    CircuitInstruction copy = instruction;\n    copy.args = arg_buf.take_copy(copy.args);\n    copy.targets = target_buf.take_copy(copy.targets);\n    copy.tag = tag_buf.take_copy(copy.tag);\n    operations.insert(operations.begin() + index, copy);\n\n    // Fuse at boundaries.\n    try_fuse_after(index);\n    if (index > 0) {\n        try_fuse_after(index - 1);\n    }\n}\n\nvoid Circuit::safe_insert(size_t index, const Circuit &circuit) {\n    if (index > operations.size()) {\n        throw std::invalid_argument(\"index > operations.size()\");\n    }\n\n    operations.insert(operations.begin() + index, circuit.operations.begin(), circuit.operations.end());\n\n    // Copy backing data over into this circuit.\n    for (size_t k = index; k < index + circuit.operations.size(); k++) {\n        if (operations[k].gate_type == GateType::REPEAT) {\n            blocks.push_back(operations[k].repeat_block_body(circuit));\n            auto repeat_count = operations[k].repeat_block_rep_count();\n            target_buf.append_tail(GateTarget{(uint32_t)(blocks.size() - 1)});\n            target_buf.append_tail(GateTarget{(uint32_t)(repeat_count & 0xFFFFFFFFULL)});\n            target_buf.append_tail(GateTarget{(uint32_t)(repeat_count >> 32)});\n            operations[k].targets = target_buf.commit_tail();\n        } else {\n            operations[k].targets = target_buf.take_copy(operations[k].targets);\n            operations[k].args = arg_buf.take_copy(operations[k].args);\n            operations[k].tag = tag_buf.take_copy(operations[k].tag);\n        }\n    }\n\n    // Fuse at boundaries.\n    if (!circuit.operations.empty()) {\n        try_fuse_after(index + circuit.operations.size() - 1);\n        if (index > 0) {\n            try_fuse_after(index - 1);\n        }\n    }\n}\n\nvoid Circuit::safe_insert_repeat_block(\n    size_t index, uint64_t repeat_count, const Circuit &block, std::string_view tag) {\n    if (repeat_count == 0) {\n        throw std::invalid_argument(\"Can't repeat 0 times.\");\n    }\n    if (index > operations.size()) {\n        throw std::invalid_argument(\"index > operations.size()\");\n    }\n    target_buf.append_tail(GateTarget{(uint32_t)blocks.size()});\n    target_buf.append_tail(GateTarget{(uint32_t)(repeat_count & 0xFFFFFFFFULL)});\n    target_buf.append_tail(GateTarget{(uint32_t)(repeat_count >> 32)});\n    blocks.push_back(block);\n    auto targets = target_buf.commit_tail();\n    operations.insert(operations.begin() + index, CircuitInstruction(GateType::REPEAT, {}, targets, tag));\n}\n\nvoid Circuit::safe_append_reversed_targets(CircuitInstruction instruction, bool reverse_in_pairs) {\n    if (reverse_in_pairs) {\n        if (instruction.targets.size() % 2 != 0) {\n            throw std::invalid_argument(\"targets.size() % 2 != 0\");\n        }\n        for (size_t k = instruction.targets.size(); k;) {\n            k -= 2;\n            target_buf.append_tail(instruction.targets[k]);\n            target_buf.append_tail(instruction.targets[k + 1]);\n        }\n    } else {\n        for (size_t k = instruction.targets.size(); k-- > 0;) {\n            target_buf.append_tail(instruction.targets[k]);\n        }\n    }\n\n    CircuitInstruction to_add = instruction;\n    try {\n        to_add.validate();\n    } catch (const std::invalid_argument &ex) {\n        target_buf.discard_tail();\n        throw;\n    }\n\n    // Commit reversed tail data.\n    to_add.targets = target_buf.commit_tail();\n\n    // Ensure arg/tag data is backed by copying it into this circuit's buffers.\n    to_add.args = arg_buf.take_copy(to_add.args);\n    to_add.tag = tag_buf.take_copy(to_add.tag);\n\n    if (!operations.empty() && operations.back().can_fuse(to_add)) {\n        // Extend targets of last gate.\n        fuse_data(operations.back().targets, to_add.targets, target_buf);\n    } else {\n        // Add a fresh new operation with its own target data.\n        operations.push_back(to_add);\n    }\n}\n\nvoid Circuit::append_from_file(FILE *file, bool stop_asap) {\n    circuit_read_operations(\n        *this,\n        [&]() {\n            return getc(file);\n        },\n        stop_asap ? READ_CONDITION::READ_AS_LITTLE_AS_POSSIBLE : READ_CONDITION::READ_UNTIL_END_OF_FILE);\n}\n\nvoid stim::print_circuit(std::ostream &out, const Circuit &c, size_t indentation) {\n    bool first = true;\n    for (const auto &op : c.operations) {\n        if (first) {\n            first = false;\n        } else {\n            out << \"\\n\";\n        }\n\n        // Recurse on repeat blocks.\n        if (op.gate_type == GateType::REPEAT) {\n            if (op.targets.size() == 3 && op.targets[0].data < c.blocks.size()) {\n                for (size_t k = 0; k < indentation; k++) {\n                    out << ' ';\n                }\n                out << \"REPEAT\";\n                if (!op.tag.empty()) {\n                    out << '[';\n                    write_tag_escaped_string_to(op.tag, out);\n                    out << ']';\n                }\n                out << \" \" << op.repeat_block_rep_count() << \" {\\n\";\n                print_circuit(out, c.blocks[op.targets[0].data], indentation + 4);\n                out << '\\n';\n                for (size_t k = 0; k < indentation; k++) {\n                    out << ' ';\n                }\n                out << '}';\n                continue;\n            }\n        }\n\n        for (size_t k = 0; k < indentation; k++) {\n            out << ' ';\n        }\n        out << op;\n    }\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const Circuit &c) {\n    print_circuit(out, c, 0);\n    return out;\n}\n\nvoid Circuit::clear() {\n    target_buf.clear();\n    arg_buf.clear();\n    operations.clear();\n    blocks.clear();\n}\n\nCircuit Circuit::operator+(const Circuit &other) const {\n    Circuit result = *this;\n    result += other;\n    return result;\n}\nCircuit Circuit::operator*(uint64_t repetitions) const {\n    if (repetitions == 0) {\n        return Circuit();\n    }\n    if (repetitions == 1) {\n        return *this;\n    }\n    // If the entire circuit is a repeat block, just adjust its repeat count.\n    if (operations.size() == 1 && operations[0].gate_type == GateType::REPEAT) {\n        uint64_t old_reps = operations[0].repeat_block_rep_count();\n        uint64_t new_reps = old_reps * repetitions;\n        if (old_reps != new_reps / repetitions) {\n            throw std::invalid_argument(\"Fused repetition count is too large.\");\n        }\n        Circuit copy;\n        copy.append_repeat_block(new_reps, operations[0].repeat_block_body(*this), \"\");\n        return copy;\n    }\n\n    Circuit result;\n    result.append_repeat_block(repetitions, *this, \"\");\n    return result;\n}\n\n/// Helper method for fusing during concatenation. If the data being extended is at the end of\n/// the monotonic buffer and there's space for the additional data, put it there in place.\n/// Otherwise it needs to be copied to the new location.\n///\n/// CAUTION: This violates the usual guarantee that once data is committed to a monotonic\n/// buffer it cannot be moved. The old data is still readable in its original location, but\n/// the caller is responsible for guaranteeing that no dangling writeable pointers remain\n/// that point to the old location (since they will write data that is no longer read by\n/// other parts of the code).\ntemplate <typename T>\nSpanRef<const T> mono_extend(MonotonicBuffer<T> &cur, SpanRef<const T> original, SpanRef<const T> additional) {\n    if (original.ptr_end == cur.tail.ptr_start) {\n        // Try to append new data right after the original data.\n        cur.ensure_available(additional.size());\n        if (original.ptr_end == cur.tail.ptr_start) {\n            cur.append_tail(additional);\n            auto added = cur.commit_tail();\n            return {original.ptr_start, added.ptr_end};\n        }\n    }\n\n    // Ensure necessary space is available, plus some padding to avoid quadratic behavior when repeatedly extending.\n    cur.ensure_available((int)(1.1 * (original.size() + additional.size())) + 10);\n    cur.append_tail(original);\n    cur.append_tail(additional);\n    return cur.commit_tail();\n}\n\nCircuit &Circuit::operator+=(const Circuit &other) {\n    SpanRef<const CircuitInstruction> ops_to_add = other.operations;\n    if (!operations.empty() && !ops_to_add.empty() && operations.back().can_fuse(ops_to_add[0])) {\n        operations.back().targets = mono_extend(target_buf, operations.back().targets, ops_to_add[0].targets);\n        ops_to_add.ptr_start++;\n    }\n\n    if (&other == this) {\n        operations.insert(operations.end(), ops_to_add.begin(), ops_to_add.end());\n        return *this;\n    }\n\n    uint32_t block_offset = (uint32_t)blocks.size();\n    blocks.insert(blocks.end(), other.blocks.begin(), other.blocks.end());\n    for (const auto &op : ops_to_add) {\n        SpanRef<stim::GateTarget> target_data = target_buf.take_copy(op.targets);\n        if (op.gate_type == GateType::REPEAT) {\n            assert(op.targets.size() == 3);\n            target_data[0].data += block_offset;\n        }\n        SpanRef<double> arg_data = arg_buf.take_copy(op.args);\n        std::string_view tag_data = tag_buf.take_copy(op.tag);\n        operations.push_back(CircuitInstruction(op.gate_type, arg_data, target_data, tag_data));\n    }\n\n    return *this;\n}\nCircuit &Circuit::operator*=(uint64_t repetitions) {\n    if (repetitions == 0) {\n        clear();\n    } else {\n        *this = *this * repetitions;\n    }\n    return *this;\n}\n\nstd::string Circuit::str() const {\n    std::stringstream s;\n    s << *this;\n    return s.str();\n}\n\nCircuit Circuit::from_file(FILE *file) {\n    Circuit result;\n    result.append_from_file(file, false);\n    return result;\n}\n\nCircuit::Circuit(std::string_view text) {\n    append_from_text(text);\n}\n\nsize_t Circuit::count_qubits() const {\n    return (uint32_t)max_operation_property([](const CircuitInstruction &op) -> uint32_t {\n        uint32_t r = 0;\n        for (auto t : op.targets) {\n            if (!(t.data & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n                r = std::max(r, t.qubit_value() + uint32_t{1});\n            }\n        }\n        return r;\n    });\n}\n\nsize_t Circuit::max_lookback() const {\n    return max_operation_property([](const CircuitInstruction &op) -> uint32_t {\n        uint32_t r = 0;\n        for (auto t : op.targets) {\n            if (t.data & TARGET_RECORD_BIT) {\n                r = std::max(r, t.qubit_value());\n            }\n        }\n        return r;\n    });\n}\n\nuint64_t stim::add_saturate(uint64_t a, uint64_t b) {\n    uint64_t r = a + b;\n    if (r < a) {\n        return UINT64_MAX;\n    }\n    return r;\n}\n\nuint64_t stim::mul_saturate(uint64_t a, uint64_t b) {\n    if (b && a > UINT64_MAX / b) {\n        return UINT64_MAX;\n    }\n    return a * b;\n}\n\nuint64_t Circuit::count_measurements() const {\n    return flat_count_operations([=](const CircuitInstruction &op) -> uint64_t {\n        return op.count_measurement_results();\n    });\n}\n\nuint64_t Circuit::count_detectors() const {\n    return flat_count_operations([=](const CircuitInstruction &op) -> uint64_t {\n        return op.gate_type == GateType::DETECTOR;\n    });\n}\n\nuint64_t Circuit::count_ticks() const {\n    return flat_count_operations([=](const CircuitInstruction &op) -> uint64_t {\n        return op.gate_type == GateType::TICK;\n    });\n}\n\nuint64_t Circuit::count_observables() const {\n    return max_operation_property([=](const CircuitInstruction &op) -> uint64_t {\n        return op.gate_type == GateType::OBSERVABLE_INCLUDE ? (size_t)op.args[0] + 1 : 0;\n    });\n}\n\nsize_t Circuit::count_sweep_bits() const {\n    return max_operation_property([](const CircuitInstruction &op) -> uint32_t {\n        uint32_t r = 0;\n        for (auto t : op.targets) {\n            if (t.data & TARGET_SWEEP_BIT) {\n                r = std::max(r, t.qubit_value() + 1);\n            }\n        }\n        return r;\n    });\n}\n\nCircuitStats Circuit::compute_stats() const {\n    CircuitStats total;\n    for (const auto &op : operations) {\n        op.add_stats_to(total, this);\n    }\n    return total;\n}\n\nCircuit Circuit::py_get_slice(int64_t start, int64_t step, int64_t slice_length) const {\n    assert(slice_length >= 0);\n    assert(slice_length == 0 || start >= 0);\n    Circuit result;\n    for (size_t k = 0; k < (size_t)slice_length; k++) {\n        const auto &op = operations[start + step * k];\n        if (op.gate_type == GateType::REPEAT) {\n            result.target_buf.append_tail(GateTarget{(uint32_t)result.blocks.size()});\n            result.target_buf.append_tail(op.targets[1]);\n            result.target_buf.append_tail(op.targets[2]);\n            auto targets = result.target_buf.commit_tail();\n            auto tag = result.tag_buf.take_copy(op.tag);\n            result.blocks.push_back(op.repeat_block_body(*this));\n            result.operations.push_back(CircuitInstruction(op.gate_type, {}, targets, tag));\n        } else {\n            auto args = result.arg_buf.take_copy(op.args);\n            auto targets = result.target_buf.take_copy(op.targets);\n            auto tag = result.tag_buf.take_copy(op.tag);\n            result.operations.push_back({op.gate_type, args, targets, tag});\n        }\n    }\n    return result;\n}\n\nvoid Circuit::append_repeat_block(uint64_t repeat_count, Circuit &&body, std::string_view tag) {\n    if (repeat_count == 0) {\n        throw std::invalid_argument(\"Can't repeat 0 times.\");\n    }\n    target_buf.append_tail(GateTarget{(uint32_t)blocks.size()});\n    target_buf.append_tail(GateTarget{(uint32_t)(repeat_count & 0xFFFFFFFFULL)});\n    target_buf.append_tail(GateTarget{(uint32_t)(repeat_count >> 32)});\n    blocks.push_back(std::move(body));\n    auto targets = target_buf.commit_tail();\n    operations.push_back(CircuitInstruction(GateType::REPEAT, {}, targets, tag_buf.take_copy(tag)));\n}\n\nvoid Circuit::append_repeat_block(uint64_t repeat_count, const Circuit &body, std::string_view tag) {\n    if (repeat_count == 0) {\n        throw std::invalid_argument(\"Can't repeat 0 times.\");\n    }\n    target_buf.append_tail(GateTarget{(uint32_t)blocks.size()});\n    target_buf.append_tail(GateTarget{(uint32_t)(repeat_count & 0xFFFFFFFFULL)});\n    target_buf.append_tail(GateTarget{(uint32_t)(repeat_count >> 32)});\n    blocks.push_back(body);\n    auto targets = target_buf.commit_tail();\n    operations.push_back(CircuitInstruction(GateType::REPEAT, {}, targets, tag_buf.take_copy(tag)));\n}\n\nconst Circuit Circuit::aliased_noiseless_circuit() const {\n    // HACK: result has pointers into `circuit`!\n    Circuit result;\n    for (const auto &op : operations) {\n        auto flags = GATE_DATA[op.gate_type].flags;\n        if (flags & GATE_PRODUCES_RESULTS) {\n            if (op.gate_type == GateType::HERALDED_ERASE || op.gate_type == GateType::HERALDED_PAULI_CHANNEL_1) {\n                // Replace heralded errors with fixed MPAD.\n                result.target_buf.ensure_available(op.targets.size());\n                auto &tail = result.target_buf.tail;\n                tail.ptr_end = tail.ptr_start + op.targets.size();\n                memset(tail.ptr_start, 0, (tail.ptr_end - tail.ptr_start) * sizeof(GateTarget));\n                result.operations.push_back(\n                    CircuitInstruction(GateType::MPAD, {}, result.target_buf.commit_tail(), op.tag));\n                result.try_fuse_last_two_ops();\n            } else {\n                // Drop result flip probability.\n                result.operations.push_back(CircuitInstruction(op.gate_type, {}, op.targets, op.tag));\n            }\n        } else if (!(flags & GATE_IS_NOISY)) {\n            // Keep noiseless operations.\n            result.operations.push_back(op);\n        }\n\n        // Because some operations are rewritten into others, and some become fusable due to\n        // arguments getting removed, just keep trying to fuse things.\n        result.try_fuse_last_two_ops();\n    }\n    for (const auto &block : blocks) {\n        result.blocks.push_back(block.aliased_noiseless_circuit());\n    }\n    return result;\n}\n\nCircuit Circuit::without_tags() const {\n    Circuit result;\n    for (CircuitInstruction inst : operations) {\n        if (inst.gate_type == GateType::REPEAT) {\n            result.append_repeat_block(inst.repeat_block_rep_count(), inst.repeat_block_body(*this).without_tags(), \"\");\n        } else {\n            inst.tag = \"\";\n            result.safe_append(inst);\n        }\n    }\n    return result;\n}\n\nCircuit Circuit::without_noise() const {\n    Circuit result;\n    for (const auto &op : operations) {\n        auto flags = GATE_DATA[op.gate_type].flags;\n        if (flags & GATE_PRODUCES_RESULTS) {\n            if (op.gate_type == GateType::HERALDED_ERASE || op.gate_type == GateType::HERALDED_PAULI_CHANNEL_1) {\n                // Replace heralded errors with fixed MPAD.\n                result.target_buf.ensure_available(op.targets.size());\n                auto &tail = result.target_buf.tail;\n                tail.ptr_end = tail.ptr_start + op.targets.size();\n                memset(tail.ptr_start, 0, (tail.ptr_end - tail.ptr_start) * sizeof(GateTarget));\n                auto tag = result.tag_buf.take_copy(op.tag);\n                result.operations.push_back(\n                    CircuitInstruction(GateType::MPAD, {}, result.target_buf.commit_tail(), tag));\n            } else {\n                // Drop result flip probabilities.\n                auto targets = result.target_buf.take_copy(op.targets);\n                auto tag = result.tag_buf.take_copy(op.tag);\n                result.safe_append(CircuitInstruction(op.gate_type, {}, targets, tag));\n            }\n        } else if (op.gate_type == GateType::REPEAT) {\n            auto args = result.arg_buf.take_copy(op.args);\n            auto targets = result.target_buf.take_copy(op.targets);\n            auto tag = result.tag_buf.take_copy(op.tag);\n            result.operations.push_back({op.gate_type, args, targets, tag});\n        } else if (!(flags & GATE_IS_NOISY)) {\n            // Keep noiseless operations.\n            auto args = result.arg_buf.take_copy(op.args);\n            auto targets = result.target_buf.take_copy(op.targets);\n            auto tag = result.tag_buf.take_copy(op.tag);\n            result.safe_append(CircuitInstruction(op.gate_type, args, targets, tag));\n        }\n\n        // Because some operations are rewritten into others, and some become fusable due to\n        // arguments getting removed, just keep trying to fuse things.\n        result.try_fuse_last_two_ops();\n    }\n    for (const auto &block : blocks) {\n        result.blocks.push_back(block.without_noise());\n    }\n    return result;\n}\n\nvoid flattened_helper(\n    const Circuit &body, std::vector<double> &cur_coordinate_shift, std::vector<double> &coord_buffer, Circuit &out) {\n    for (const auto &op : body.operations) {\n        GateType id = op.gate_type;\n        if (id == GateType::SHIFT_COORDS) {\n            while (cur_coordinate_shift.size() < op.args.size()) {\n                cur_coordinate_shift.push_back(0);\n            }\n            for (size_t k = 0; k < op.args.size(); k++) {\n                cur_coordinate_shift[k] += op.args[k];\n            }\n        } else if (id == GateType::REPEAT) {\n            uint64_t reps = op.repeat_block_rep_count();\n            const auto &loop_body = op.repeat_block_body(body);\n            for (uint64_t k = 0; k < reps; k++) {\n                flattened_helper(loop_body, cur_coordinate_shift, coord_buffer, out);\n            }\n        } else {\n            coord_buffer.clear();\n            coord_buffer.insert(coord_buffer.end(), op.args.begin(), op.args.end());\n            if (id == GateType::QUBIT_COORDS || id == GateType::DETECTOR) {\n                for (size_t k = 0; k < coord_buffer.size() && k < cur_coordinate_shift.size(); k++) {\n                    coord_buffer[k] += cur_coordinate_shift[k];\n                }\n            }\n            out.safe_append(CircuitInstruction(op.gate_type, coord_buffer, op.targets, op.tag));\n        }\n    }\n}\n\nCircuit Circuit::flattened() const {\n    Circuit result;\n    std::vector<double> shift;\n    std::vector<double> coord_buffer;\n    flattened_helper(*this, shift, coord_buffer, result);\n    return result;\n}\n\nCircuit Circuit::inverse(bool allow_weak_inverse) const {\n    Circuit result;\n    result.operations.reserve(operations.size());\n    result.target_buf.ensure_available(target_buf.total_allocated());\n    result.arg_buf.ensure_available(arg_buf.total_allocated());\n    result.tag_buf.ensure_available(tag_buf.total_allocated());\n    size_t skip_reversing = 0;\n\n    std::vector<double> args_buf;\n    for (size_t k = 0; k < operations.size(); k++) {\n        const auto &op = operations[k];\n        if (op.gate_type == GateType::REPEAT) {\n            const auto &block = op.repeat_block_body(*this);\n            uint64_t reps = op.repeat_block_rep_count();\n            result.append_repeat_block(reps, block.inverse(allow_weak_inverse), op.tag);\n            continue;\n        }\n\n        SpanRef<const double> args = op.args;\n        const auto &gate_data = GATE_DATA[op.gate_type];\n        auto flags = gate_data.flags;\n        if (flags & GATE_IS_UNITARY) {\n            // Unitary gates always have an inverse.\n        } else if (op.gate_type == GateType::TICK) {\n            // Ticks are self-inverse.\n        } else if (flags & GATE_IS_NOISY) {\n            // Noise isn't invertible, but it is weakly invertible.\n            // ELSE_CORRELATED_ERROR isn't implemented due to complex order dependencies.\n            if (!allow_weak_inverse || op.gate_type == GateType::ELSE_CORRELATED_ERROR) {\n                throw std::invalid_argument(\n                    \"The circuit has no well-defined inverse because it contains noise.\\n\"\n                    \"For example it contains a '\" +\n                    op.str() + \"' instruction.\");\n            }\n        } else if (flags & (GATE_IS_RESET | GATE_PRODUCES_RESULTS)) {\n            // Dissipative operations aren't invertible, but they are weakly invertible.\n            if (!allow_weak_inverse) {\n                throw std::invalid_argument(\n                    \"The circuit has no well-defined inverse because it contains resets or measurements.\\n\"\n                    \"For example it contains a '\" +\n                    op.str() + \"' instruction.\");\n            }\n        } else if (op.gate_type == GateType::QUBIT_COORDS) {\n            // Qubit coordinate headers are kept at the beginning.\n            if (k > skip_reversing) {\n                throw std::invalid_argument(\n                    \"Inverting QUBIT_COORDS is not implemented except at the start of the circuit.\");\n            }\n            skip_reversing++;\n        } else if (op.gate_type == GateType::SHIFT_COORDS) {\n            // Coordinate shifts reverse.\n            args_buf.clear();\n            for (const auto &a : op.args) {\n                args_buf.push_back(-a);\n            }\n            args = args_buf;\n        } else if (op.gate_type == GateType::DETECTOR || op.gate_type == GateType::OBSERVABLE_INCLUDE) {\n            if (allow_weak_inverse) {\n                // If strong inverse for these gets implemented, they should be included in the weak inverse.\n                // But for now it's sufficient to just drop them for the weak inverse.\n                continue;\n            }\n            throw std::invalid_argument(\"Inverse not implemented: \" + op.str());\n        } else {\n            throw std::invalid_argument(\"Inverse not implemented: \" + op.str());\n        }\n\n        // Add inverse operation to inverse circuit.\n        result.safe_append_reversed_targets(\n            CircuitInstruction(gate_data.best_candidate_inverse_id, args, op.targets, op.tag),\n            gate_data.flags & GATE_TARGETS_PAIRS);\n    }\n\n    // Put the qubit coordinates in the original order.\n    std::reverse(result.operations.begin() + skip_reversing, result.operations.end());\n\n    return result;\n}\n\nvoid stim::vec_pad_add_mul(std::vector<double> &target, SpanRef<const double> offset, uint64_t mul) {\n    while (target.size() < offset.size()) {\n        target.push_back(0);\n    }\n    for (size_t k = 0; k < offset.size(); k++) {\n        target[k] += offset[k] * mul;\n    }\n}\n\nvoid get_final_qubit_coords_helper(\n    const Circuit &circuit,\n    uint64_t repetitions,\n    std::vector<double> &out_coord_shift,\n    std::map<uint64_t, std::vector<double>> &out_qubit_coords) {\n    auto initial_shift = out_coord_shift;\n    std::map<uint64_t, std::vector<double>> new_qubit_coords;\n\n    for (const auto &op : circuit.operations) {\n        if (op.gate_type == GateType::REPEAT) {\n            const auto &block = circuit.blocks[op.targets[0].data];\n            uint64_t block_repeats = op.repeat_block_rep_count();\n            get_final_qubit_coords_helper(block, block_repeats, out_coord_shift, new_qubit_coords);\n        } else if (op.gate_type == GateType::SHIFT_COORDS) {\n            vec_pad_add_mul(out_coord_shift, op.args);\n        } else if (op.gate_type == GateType::QUBIT_COORDS) {\n            while (out_coord_shift.size() < op.args.size()) {\n                out_coord_shift.push_back(0);\n            }\n            for (const auto &t : op.targets) {\n                if (t.is_qubit_target()) {\n                    auto &vec = new_qubit_coords[t.qubit_value()];\n                    for (size_t k = 0; k < op.args.size(); k++) {\n                        vec.push_back(op.args[k] + out_coord_shift[k]);\n                    }\n                }\n            }\n        }\n    }\n\n    // Handle additional iterations by computing the total coordinate shift instead of iterating instructions.\n    if (repetitions > 1 && out_coord_shift != initial_shift) {\n        // Determine how much each coordinate shifts in each iteration.\n        auto gain_per_iteration = out_coord_shift;\n        for (size_t k = 0; k < initial_shift.size(); k++) {\n            gain_per_iteration[k] -= initial_shift[k];\n        }\n\n        // Shift in-loop qubit coordinates forward to the last iteration's values.\n        for (auto &kv : new_qubit_coords) {\n            auto &qc = kv.second;\n            for (size_t k = 0; k < qc.size(); k++) {\n                qc[k] += gain_per_iteration[k] * (repetitions - 1);\n            }\n        }\n\n        // Advance the coordinate shifts to account for all iterations.\n        vec_pad_add_mul(out_coord_shift, gain_per_iteration, repetitions - 1);\n    }\n\n    // Output updated values.\n    for (const auto &kv : new_qubit_coords) {\n        out_qubit_coords[kv.first] = kv.second;\n    }\n}\n\nstd::map<uint64_t, std::vector<double>> Circuit::get_final_qubit_coords() const {\n    std::vector<double> coord_shift;\n    std::map<uint64_t, std::vector<double>> qubit_coords;\n    get_final_qubit_coords_helper(*this, 1, coord_shift, qubit_coords);\n    return qubit_coords;\n}\n\nstd::vector<double> Circuit::final_coord_shift() const {\n    std::vector<double> coord_shift;\n    for (const auto &op : operations) {\n        if (op.gate_type == GateType::SHIFT_COORDS) {\n            vec_pad_add_mul(coord_shift, op.args);\n        } else if (op.gate_type == GateType::REPEAT) {\n            const auto &block = op.repeat_block_body(*this);\n            uint64_t reps = op.repeat_block_rep_count();\n            vec_pad_add_mul(coord_shift, block.final_coord_shift(), reps);\n        }\n    }\n    return coord_shift;\n}\n\nvoid get_detector_coordinates_helper(\n    const Circuit &circuit,\n    const std::set<uint64_t> &included_detector_indices,\n    std::set<uint64_t>::const_iterator &iter_desired_detector_index,\n    const std::vector<double> &initial_coord_shift,\n    uint64_t &next_detector_index,\n    std::map<uint64_t, std::vector<double>> &out) {\n    if (iter_desired_detector_index == included_detector_indices.end()) {\n        return;\n    }\n\n    std::vector<double> coord_shift = initial_coord_shift;\n    for (const auto &op : circuit.operations) {\n        if (op.gate_type == GateType::SHIFT_COORDS) {\n            vec_pad_add_mul(coord_shift, op.args);\n        } else if (op.gate_type == GateType::REPEAT) {\n            const auto &block = op.repeat_block_body(circuit);\n            auto block_shift = block.final_coord_shift();\n            uint64_t per = block.count_detectors();\n            uint64_t reps = op.repeat_block_rep_count();\n            uint64_t used_reps = 0;\n            while (used_reps < reps) {\n                uint64_t skip =\n                    per == 0 ? reps : std::min(reps, (*iter_desired_detector_index - next_detector_index) / per);\n                used_reps += skip;\n                next_detector_index += per * skip;\n                vec_pad_add_mul(coord_shift, block_shift, skip);\n                if (used_reps < reps) {\n                    get_detector_coordinates_helper(\n                        block,\n                        included_detector_indices,\n                        iter_desired_detector_index,\n                        coord_shift,\n                        next_detector_index,\n                        out);\n                    used_reps += 1;\n                    vec_pad_add_mul(coord_shift, block_shift);\n                    if (iter_desired_detector_index == included_detector_indices.end()) {\n                        return;\n                    }\n                }\n            }\n        } else if (op.gate_type == GateType::DETECTOR) {\n            if (next_detector_index == *iter_desired_detector_index) {\n                std::vector<double> det_coords;\n                for (size_t k = 0; k < op.args.size(); k++) {\n                    det_coords.push_back(op.args[k]);\n                    if (k < coord_shift.size()) {\n                        det_coords[k] += coord_shift[k];\n                    }\n                }\n                out[next_detector_index] = det_coords;\n\n                iter_desired_detector_index++;\n                if (iter_desired_detector_index == included_detector_indices.end()) {\n                    return;\n                }\n            }\n            next_detector_index++;\n        }\n    }\n}\n\nstd::vector<double> Circuit::coords_of_detector(uint64_t detector_index) const {\n    return get_detector_coordinates({detector_index})[detector_index];\n}\n\nstd::map<uint64_t, std::vector<double>> Circuit::get_detector_coordinates(\n    const std::set<uint64_t> &included_detector_indices) const {\n    std::map<uint64_t, std::vector<double>> out;\n    uint64_t next_coordinate_index = 0;\n    std::set<uint64_t>::const_iterator iter = included_detector_indices.begin();\n    get_detector_coordinates_helper(*this, included_detector_indices, iter, {}, next_coordinate_index, out);\n\n    if (iter != included_detector_indices.end()) {\n        std::stringstream msg;\n        msg << \"Detector index \" << *iter << \" is too big. The circuit has \";\n        msg << count_detectors() << \" detectors)\";\n        throw std::invalid_argument(msg.str());\n    }\n\n    return out;\n}\n\nstd::string Circuit::describe_instruction_location(size_t instruction_offset) const {\n    std::stringstream out;\n    out << \"    at instruction #\" << (instruction_offset + 1);\n    const auto &op = operations[instruction_offset];\n    if (op.gate_type == GateType::REPEAT) {\n        out << \" [which is a REPEAT \" << op.repeat_block_rep_count() << \" block]\";\n    } else {\n        out << \" [which is \" << op << \"]\";\n    }\n    return out.str();\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CIRCUIT_CIRCUIT_H\n#define _STIM_CIRCUIT_CIRCUIT_H\n\n#include <cmath>\n#include <cstdint>\n#include <cstring>\n#include <iostream>\n#include <map>\n#include <memory>\n#include <set>\n#include <unordered_map>\n#include <vector>\n\n#include \"stim/circuit/circuit_instruction.h\"\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/mem/monotonic_buffer.h\"\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\nuint64_t add_saturate(uint64_t a, uint64_t b);\nuint64_t mul_saturate(uint64_t a, uint64_t b);\n\n/// A description of a quantum computation.\nstruct Circuit {\n    /// Backing data stores for variable-sized target data referenced by operations.\n    MonotonicBuffer<GateTarget> target_buf;\n    MonotonicBuffer<double> arg_buf;\n    MonotonicBuffer<char> tag_buf;\n    /// Operations in the circuit, from earliest to latest.\n    std::vector<CircuitInstruction> operations;\n    std::vector<Circuit> blocks;\n\n    // Returns one more than the largest `k` from any qubit target `k` or `!k` or `{X,Y,Z}k`.\n    size_t count_qubits() const;\n    // Returns the number of measurement bits produced by the circuit.\n    uint64_t count_measurements() const;\n    // Returns the number of detection event bits produced by the circuit.\n    uint64_t count_detectors() const;\n    // Returns one more than the largest `k` from any `OBSERVABLE_INCLUDE(k)` instruction.\n    uint64_t count_observables() const;\n    // Returns the number of ticks performed when running the circuit.\n    uint64_t count_ticks() const;\n    // Returns the largest `k` from any `rec[-k]` target.\n    size_t max_lookback() const;\n    // Returns one more than the largest `k` from any `sweep[k]` target.\n    size_t count_sweep_bits() const;\n\n    CircuitStats compute_stats() const;\n\n    /// Constructs an empty circuit.\n    Circuit();\n    /// Copy constructor.\n    Circuit(const Circuit &circuit);\n    /// Move constructor.\n    Circuit(Circuit &&circuit) noexcept;\n    /// Copy assignment.\n    Circuit &operator=(const Circuit &circuit);\n    /// Move assignment.\n    Circuit &operator=(Circuit &&circuit) noexcept;\n\n    /// Parse constructor. Creates a circuit from text with operations like \"H 0 \\n CNOT 0 1 \\n M 0 1\".\n    ///\n    /// Note: operations are automatically fused.\n    explicit Circuit(std::string_view text);\n    /// Parses a circuit from a file containing operations.\n    ///\n    /// Note: operations are automatically fused.\n    static Circuit from_file(FILE *file);\n    /// Grows the circuit using operations from a file.\n    ///\n    /// Note: operations are automatically fused.\n    ///\n    /// Args:\n    ///     file: The opened file to read from.\n    ///     stop_asap: When set to true, the reading process stops after the next operation is read. This is used for\n    ///         interactive (repl) mode, where measurements should produce results immediately instead of only after the\n    ///         circuit is entirely specified. *This has significantly worse performance. It prevents measurement\n    ///         batching.*\n    void append_from_file(FILE *file, bool stop_asap = false);\n    /// Grows the circuit using operations from a string.\n    ///\n    /// Note: operations are automatically fused.\n    void append_from_text(std::string_view text);\n\n    Circuit operator+(const Circuit &other) const;\n    Circuit operator*(uint64_t repetitions) const;\n    Circuit &operator+=(const Circuit &other);\n    Circuit &operator*=(uint64_t repetitions);\n\n    /// Safely adds an operation at the end of the circuit, copying its data into the circuit's jagged data as needed.\n    void safe_append(CircuitInstruction operation, bool block_fusion = false);\n    /// Safely adds an operation at the end of the circuit, copying its data into the circuit's jagged data as needed.\n    void safe_append_ua(\n        std::string_view gate_name,\n        const std::vector<uint32_t> &targets,\n        double singleton_arg,\n        std::string_view tag = \"\");\n    /// Safely adds an operation at the end of the circuit, copying its data into the circuit's jagged data as needed.\n    void safe_append_u(\n        std::string_view gate_name,\n        const std::vector<uint32_t> &targets,\n        const std::vector<double> &args = {},\n        std::string_view tag = \"\");\n    /// Safely copies a repeat block to the end of the circuit.\n    void append_repeat_block(uint64_t repeat_count, const Circuit &body, std::string_view tag);\n    /// Safely moves a repeat block to the end of the circuit.\n    void append_repeat_block(uint64_t repeat_count, Circuit &&body, std::string_view tag);\n\n    void safe_insert(size_t index, const CircuitInstruction &instruction);\n    void safe_insert_repeat_block(size_t index, uint64_t repeat_count, const Circuit &block, std::string_view tag);\n    void safe_insert(size_t index, const Circuit &circuit);\n\n    /// Appends the given gate, but with targets reversed.\n    void safe_append_reversed_targets(CircuitInstruction instruction, bool reverse_in_pairs);\n\n    /// Resets the circuit back to an empty circuit.\n    void clear();\n\n    /// Returns a text description of the circuit.\n    std::string str() const;\n    /// Equality.\n    bool operator==(const Circuit &other) const;\n    /// Inequality.\n    bool operator!=(const Circuit &other) const;\n    /// Approximate equality.\n    bool approx_equals(const Circuit &other, double atol) const;\n\n    /// Gets a python-style slice of the circuit's instructions.\n    Circuit py_get_slice(int64_t start, int64_t step, int64_t slice_length) const;\n\n    /// Returns a noiseless version of the given circuit. The result must live for less time than the given circuit.\n    ///\n    /// CAUTION: for performance, the returned circuit contains pointers into the given circuit!\n    /// The result's lifetime must be shorter than the given circuit's lifetime!\n    const Circuit aliased_noiseless_circuit() const;\n\n    /// Returns a copy of the circuit with all noise processes removed.\n    Circuit without_noise() const;\n    /// Returns a copy of the circuit with all tags removed.\n    Circuit without_tags() const;\n\n    /// Returns an equivalent circuit without REPEAT or SHIFT_COORDS instructions.\n    Circuit flattened() const;\n\n    /// Returns a circuit that implements the inverse Clifford operation.\n    ///\n    /// Args:\n    ///     allow_weak_inverse: When this is set to true, the inverse of the circuit doesn't need\n    ///         to be exact. In particular, noise and measurement becomes self-inverse. Examples:\n    ///             - The weak inverse of MX is MX.\n    ///             - The weak inverse of MRX is MRX.\n    ///             - The weak inverse of RX is MRX.\n    ///             - The weak inverse of X_ERROR(0.1) is X_ERROR(0.1).\n    ///             - The weak inverse of DETECTOR is [discard the operation].\n    ///             - The weak inverse of OBSERVABLE_INCLUDE is [discard the operation].\n    ///\n    /// Returns:\n    ///     The inverted circuit.\n    Circuit inverse(bool allow_weak_inverse = false) const;\n\n    /// Helper method for executing the circuit, e.g. repeating REPEAT blocks.\n    template <typename CALLBACK>\n    void for_each_operation(const CALLBACK &callback) const {\n        for (const auto &op : operations) {\n            if (op.gate_type == GateType::REPEAT) {\n                uint64_t repeats = op.repeat_block_rep_count();\n                const auto &block = op.repeat_block_body(*this);\n                for (uint64_t k = 0; k < repeats; k++) {\n                    block.for_each_operation(callback);\n                }\n            } else {\n                callback(op);\n            }\n        }\n    }\n\n    /// Helper method for reverse-executing the circuit, e.g. repeating REPEAT blocks.\n    template <typename CALLBACK>\n    void for_each_operation_reverse(const CALLBACK &callback) const {\n        for (size_t p = operations.size(); p-- > 0;) {\n            const auto &op = operations[p];\n            if (op.gate_type == GateType::REPEAT) {\n                uint64_t repeats = op.repeat_block_rep_count();\n                const auto &block = op.repeat_block_body(*this);\n                for (uint64_t k = 0; k < repeats; k++) {\n                    block.for_each_operation_reverse(callback);\n                }\n            } else {\n                callback(op);\n            }\n        }\n    }\n\n    /// Helper method for counting measurements, detectors, etc.\n    template <typename COUNT>\n    uint64_t flat_count_operations(const COUNT &count) const {\n        uint64_t n = 0;\n        for (const auto &op : operations) {\n            if (op.gate_type == GateType::REPEAT) {\n                assert(op.targets.size() == 3);\n                auto b = op.targets[0].data;\n                assert(b < blocks.size());\n                auto sub = blocks[b].flat_count_operations<COUNT>(count);\n                n = add_saturate(n, mul_saturate(sub, op.repeat_block_rep_count()));\n            } else {\n                n = add_saturate(n, count(op));\n            }\n        }\n        return n;\n    }\n\n    /// Helper method for finding the largest observable, etc.\n    template <typename MAP>\n    uint64_t max_operation_property(const MAP &map) const {\n        uint64_t n = 0;\n        for (const auto &block : blocks) {\n            n = std::max(n, block.max_operation_property<MAP>(map));\n        }\n        for (const auto &op : operations) {\n            if (op.gate_type == GateType::REPEAT) {\n                // Handled in block case.\n                continue;\n            }\n            n = std::max(n, (uint64_t)map(op));\n        }\n        return n;\n    }\n\n    /// Looks for QUBIT_COORDS instructions in the circuit, and returns a map from qubit index to qubit coordinate.\n    ///\n    /// This method efficiently handles REPEAT blocks. It finishes in time proportional to the size of the circuit\n    /// file, not time proportional to the amount of data produced by the circuit.\n    std::map<uint64_t, std::vector<double>> get_final_qubit_coords() const;\n\n    /// Looks up the coordinate data of a detector.\n    ///\n    /// Args:\n    ///     detector_index: The index of the detector to get coordinate data for.\n    ///         Detectors are indexed by the order they appear in the circuit (accounting for repeat blocks).\n    ///\n    /// Returns:\n    ///     The coordinate data for the detector.\n    ///     If the detector has no coordinate data, an empty vector is returned.\n    ///\n    /// Throws:\n    ///     std::invalid_argument: The detector index is greater than or equal to circuit.count_detectors().\n    std::vector<double> coords_of_detector(uint64_t detector_index) const;\n\n    /// Looks up the coordinate data of a given set of detectors.\n    ///\n    /// Args:\n    ///     included_detector_indices: An ordered set of the indices of detectors to get coordinate data for.\n    ///\n    /// Returns:\n    ///     A map from detector index to coordinate data.\n    ///     Every index from included_detector_indices will be in this map as a key.\n    ///     Detectors with no coordinate data are mapped to an empty vector.\n    ///\n    /// Throws:\n    ///     std::invalid_argument: A detector index is greater than or equal to circuit.count_detectors().\n    std::map<uint64_t, std::vector<double>> get_detector_coordinates(\n        const std::set<uint64_t> &included_detector_indices) const;\n\n    /// Returns the total coordinate shift accumulated over the entire circuit, accounting for REPEAT blocks.\n    std::vector<double> final_coord_shift() const;\n\n    /// Helper method for building up human readable descriptions of circuit locations.\n    std::string describe_instruction_location(size_t instruction_offset) const;\n\n    void try_fuse_last_two_ops();\n    void try_fuse_after(size_t index);\n};\n\nvoid vec_pad_add_mul(std::vector<double> &target, SpanRef<const double> offset, uint64_t mul = 1);\n\ntemplate <typename SOURCE>\ninline void read_past_within_line_whitespace(int &c, SOURCE read_char) {\n    while (c == ' ' || c == '\\t') {\n        c = read_char();\n    }\n}\n\ntemplate <typename SOURCE>\nbool read_until_next_line_arg(int &c, SOURCE read_char, bool space_required = true) {\n    if (c == '*') {\n        return true;\n    }\n    if (space_required) {\n        if (c != ' ' && c != '#' && c != '\\t' && c != '\\n' && c != '\\r' && c != '{' && c != EOF) {\n            throw std::invalid_argument(\"Targets must be separated by spacing.\");\n        }\n    }\n    while (c == ' ' || c == '\\t' || c == '\\r') {\n        c = read_char();\n    }\n    if (c == '#') {\n        do {\n            c = read_char();\n        } while (c != '\\n' && c != EOF);\n    }\n    return c != '\\n' && c != '{' && c != EOF;\n}\n\ntemplate <typename SOURCE>\nvoid read_past_dead_space_between_commands(int &c, SOURCE read_char) {\n    while (true) {\n        while (isspace(c)) {\n            c = read_char();\n        }\n        if (c == EOF) {\n            break;\n        }\n        if (c != '#') {\n            break;\n        }\n        while (c != '\\n' && c != EOF) {\n            c = read_char();\n        }\n    }\n}\n\ninline bool is_double_char(int c) {\n    return (c >= '0' && c <= '9') || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-';\n}\n\ntemplate <typename SOURCE>\ndouble read_normal_double(int &c, SOURCE read_char) {\n    char buf[64];\n    size_t n = 0;\n    while (n < sizeof(buf) - 1 && is_double_char(c)) {\n        buf[n] = (char)c;\n        c = read_char();\n        n++;\n    }\n    buf[n] = '\\0';\n\n    char *end;\n    double result = strtod(buf, &end);\n    if (end != buf + n || std::isinf(result) || std::isnan(result)) {\n        throw std::invalid_argument(\"Not a real number: \" + std::string(buf));\n    }\n    return result;\n}\n\ntemplate <typename SOURCE>\nvoid read_tag(int &c, std::string_view name, SOURCE read_char, MonotonicBuffer<char> &out) {\n    if (c != '[') {\n        return;\n    }\n    c = read_char();\n\n    while (c != ']') {\n        if (c == '\\r' || c == '\\n') {\n            std::stringstream ss;\n            ss << \"A tag wasn't closed with ']' before the end of the line.\\n\";\n            ss << \"Hit a \";\n            if (c == '\\r') {\n                ss << \"carriage return character (0x0D)\";\n            } else {\n                ss << \"line feed character (0x0A)\";\n            }\n            ss << \" while trying to parse the tag of \";\n            if (name.empty()) {\n                ss << \"an instruction.\\n\";\n            } else {\n                ss << \"a '\" << name << \"' instruction.\\n\";\n            }\n            ss << \"In tags, use the escape sequence '\\\\r' for carriage returns and '\\\\n' for line feeds.\";\n            throw std::invalid_argument(ss.str());\n        } else if (c == '\\\\') {\n            c = read_char();\n            switch (c) {\n                case 'n':\n                    out.append_tail('\\n');\n                    break;\n                case 'r':\n                    out.append_tail('\\r');\n                    break;\n                case 'B':\n                    out.append_tail('\\\\');\n                    break;\n                case 'C':\n                    out.append_tail(']');\n                    break;\n                default:\n                    std::stringstream ss;\n                    ss << \"Unrecognized escape sequence '\\\\\" << c << \"'.\";\n                    ss << \"\\nKnown escape sequences are:\";\n                    ss << \"\\n    \\\\n: 0x0A (line feed)\";\n                    ss << \"\\n    \\\\r: 0x0D (carriage return)\";\n                    ss << \"\\n    \\\\B: 0x5C (backslash '\\\\')\";\n                    ss << \"\\n    \\\\C: 0x5D (closing square bracket ']')\";\n                    throw std::invalid_argument(ss.str());\n            }\n        } else {\n            out.append_tail(c);\n        }\n        c = read_char();\n    }\n\n    c = read_char();\n}\n\ntemplate <typename SOURCE>\nvoid read_parens_arguments(int &c, std::string_view name, SOURCE read_char, MonotonicBuffer<double> &out) {\n    if (c != '(') {\n        return;\n    }\n    c = read_char();\n\n    read_past_within_line_whitespace(c, read_char);\n    while (true) {\n        out.append_tail(read_normal_double(c, read_char));\n        read_past_within_line_whitespace(c, read_char);\n        if (c != ',') {\n            break;\n        }\n        c = read_char();\n        read_past_within_line_whitespace(c, read_char);\n    }\n\n    read_past_within_line_whitespace(c, read_char);\n    if (c != ')') {\n        throw std::invalid_argument(\"Parens arguments for '\" + std::string(name) + \"' didn't end with a ')'.\");\n    }\n    c = read_char();\n}\n\nstd::ostream &operator<<(std::ostream &out, const Circuit &c);\nvoid print_circuit(std::ostream &out, const Circuit &c, size_t indentation);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/circuit/circuit.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/circuit.h\"\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(circuit_parse) {\n    Circuit c;\n    benchmark_go([&]() {\n        c = Circuit(R\"input(\nH 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\nCNOT 4 5 6 7\nM 1 2 3 4 5 6 7 8 9 10 11\n            )input\");\n    }).goal_nanos(950);\n    if (c.count_qubits() == 0) {\n        std::cerr << \"impossible\";\n    }\n}\n\nBENCHMARK(circuit_parse_sparse) {\n    Circuit c;\n    for (auto k = 0; k < 1000; k++) {\n        c.safe_append_u(\"H\", {0});\n        c.safe_append_u(\"CNOT\", {1, 2});\n        c.safe_append_u(\"M\", {0});\n    }\n    auto text = c.str();\n    benchmark_go([&]() {\n        c = Circuit(text.data());\n    }).goal_micros(150);\n    if (c.count_qubits() == 0) {\n        std::cerr << \"impossible\";\n    }\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/circuit.pybind.h\"\n\n#include <fstream>\n\n#include \"stim/circuit/circuit_instruction.pybind.h\"\n#include \"stim/circuit/circuit_repeat_block.pybind.h\"\n#include \"stim/circuit/gate_target.pybind.h\"\n#include \"stim/cmd/command_diagram.pybind.h\"\n#include \"stim/dem/detector_error_model_target.pybind.h\"\n#include \"stim/diagram/detector_slice/detector_slice_set.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_color_code.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/io/raii_file.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/compiled_detector_sampler.pybind.h\"\n#include \"stim/py/compiled_measurement_sampler.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n#include \"stim/search/search.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/simulators/error_matcher.h\"\n#include \"stim/simulators/measurements_to_detection_events.pybind.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/stabilizers/flow.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nstd::string circuit_repr(const Circuit &self) {\n    if (self.operations.empty()) {\n        return \"stim.Circuit()\";\n    }\n    std::stringstream ss;\n    ss << \"stim.Circuit('''\\n\";\n    print_circuit(ss, self, 4);\n    ss << \"\\n''')\";\n    return ss.str();\n}\n\nstd::vector<ExplainedError> circuit_shortest_graphlike_error(\n    const Circuit &self, bool ignore_ungraphlike_errors, bool reduce_to_representative) {\n    DetectorErrorModel dem =\n        ErrorAnalyzer::circuit_to_detector_error_model(self, !ignore_ungraphlike_errors, true, false, 1, false, false);\n    DetectorErrorModel filter = shortest_graphlike_undetectable_logical_error(dem, ignore_ungraphlike_errors);\n    return ErrorMatcher::explain_errors_from_circuit(self, &filter, reduce_to_representative);\n}\n\nstd::vector<ExplainedError> py_find_undetectable_logical_error(\n    const Circuit &self,\n    size_t dont_explore_detection_event_sets_with_size_above,\n    size_t dont_explore_edges_with_degree_above,\n    bool dont_explore_edges_increasing_symptom_degree,\n    bool reduce_to_representative) {\n    DetectorErrorModel dem = ErrorAnalyzer::circuit_to_detector_error_model(self, false, true, false, 1, false, false);\n    DetectorErrorModel filter = stim::find_undetectable_logical_error(\n        dem,\n        dont_explore_detection_event_sets_with_size_above,\n        dont_explore_edges_with_degree_above,\n        dont_explore_edges_increasing_symptom_degree);\n    return ErrorMatcher::explain_errors_from_circuit(self, &filter, reduce_to_representative);\n}\n\nstd::string py_shortest_error_sat_problem(const Circuit &self, std::string_view format) {\n    DetectorErrorModel dem = ErrorAnalyzer::circuit_to_detector_error_model(self, false, true, false, 1, false, false);\n    return stim::shortest_error_sat_problem(dem, format);\n}\n\nstd::string py_likeliest_error_sat_problem(const Circuit &self, int quantization, std::string_view format) {\n    DetectorErrorModel dem = ErrorAnalyzer::circuit_to_detector_error_model(self, false, true, false, 1, false, false);\n    return stim::likeliest_error_sat_problem(dem, quantization, format);\n}\n\npybind11::object circuit_get_item(const Circuit &self, const pybind11::object &index_or_slice) {\n    pybind11::ssize_t index, step, slice_length;\n    if (normalize_index_or_slice(index_or_slice, self.operations.size(), &index, &step, &slice_length)) {\n        return pybind11::cast(self.py_get_slice(index, step, slice_length));\n    }\n\n    auto &op = self.operations[index];\n    if (op.gate_type == GateType::REPEAT) {\n        return pybind11::cast(\n            CircuitRepeatBlock{op.repeat_block_rep_count(), op.repeat_block_body(self), pybind11::str(op.tag)});\n    }\n    std::vector<GateTarget> targets;\n    for (const auto &e : op.targets) {\n        targets.push_back(GateTarget(e));\n    }\n    std::vector<double> args;\n    for (const auto &e : op.args) {\n        args.push_back(e);\n    }\n    return pybind11::cast(PyCircuitInstruction(op.gate_type, targets, args, op.tag));\n}\n\npybind11::object circuit_pop(Circuit &self, pybind11::ssize_t index) {\n    if (index < -(pybind11::ssize_t)self.operations.size() || index >= (pybind11::ssize_t)self.operations.size()) {\n        std::stringstream ss;\n        ss << \"not -len(circuit) < index=\" << index << \" < len(circuit)=\" << self.operations.size();\n        throw std::out_of_range(ss.str());\n    }\n    if (index < 0) {\n        index += self.operations.size();\n    }\n\n    pybind11::object result = circuit_get_item(self, pybind11::cast(index));\n    self.operations.erase(self.operations.begin() + (size_t)index);\n    return result;\n}\nvoid circuit_insert(Circuit &self, pybind11::ssize_t &index, pybind11::object &operation) {\n    if (index < 0) {\n        index += self.operations.size();\n    }\n    if (index < 0 || (uint64_t)index > self.operations.size()) {\n        std::stringstream ss;\n        ss << \"Index is out of range. Need -len(circuit) <= index <= len(circuit).\";\n        ss << \"\\n    index=\" << index;\n        ss << \"\\n    len(circuit)=\" << self.operations.size();\n        throw std::invalid_argument(ss.str());\n    }\n    if (pybind11::isinstance<PyCircuitInstruction>(operation)) {\n        const PyCircuitInstruction &v = pybind11::cast<const PyCircuitInstruction &>(operation);\n        self.safe_insert(index, v.as_operation_ref());\n    } else if (pybind11::isinstance<CircuitRepeatBlock>(operation)) {\n        const CircuitRepeatBlock &v = pybind11::cast<const CircuitRepeatBlock &>(operation);\n        self.safe_insert_repeat_block(index, v.repeat_count, v.body, pybind11::cast<std::string_view>(v.tag));\n    } else if (pybind11::isinstance<Circuit>(operation)) {\n        const Circuit &v = pybind11::cast<const Circuit &>(operation);\n        self.safe_insert(index, v);\n    } else {\n        std::stringstream ss;\n        ss << \"Don't know how to insert an object of type \";\n        ss << pybind11::str(pybind11::module_::import(\"builtins\").attr(\"type\")(operation));\n        ss << \"\\nExpected a stim.CircuitInstruction, stim.CircuitRepeatBlock, or stim.Circuit.\";\n        throw std::invalid_argument(ss.str());\n    }\n}\n\nvoid handle_to_gate_targets(const pybind11::handle &obj, std::vector<uint32_t> &out, bool can_iterate) {\n    try {\n        FlexPauliString ps = pybind11::cast<FlexPauliString>(obj);\n        bool first = true;\n        ps.value.ref().for_each_active_pauli([&](size_t q) {\n            if (!first) {\n                out.push_back(GateTarget::combiner().data);\n            }\n            first = false;\n            out.push_back(GateTarget::pauli_xz(q, ps.value.xs[q], ps.value.zs[q]).data);\n        });\n        if (first) {\n            throw std::invalid_argument(\"Don't know how to target an empty stim.PauliString\");\n        }\n        return;\n    } catch (const pybind11::cast_error &ex) {\n    }\n\n    try {\n        std::string_view text = pybind11::cast<std::string_view>(obj);\n        out.push_back(GateTarget::from_target_str(text).data);\n        return;\n    } catch (const pybind11::cast_error &ex) {\n    }\n\n    try {\n        out.push_back(pybind11::cast<GateTarget>(obj).data);\n        return;\n    } catch (const pybind11::cast_error &ex) {\n    }\n\n    try {\n        out.push_back(GateTarget{pybind11::cast<uint32_t>(obj)}.data);\n        return;\n    } catch (const pybind11::cast_error &ex) {\n    }\n\n    if (can_iterate) {\n        pybind11::module collections = pybind11::module::import(\"collections.abc\");\n        pybind11::object iterable_type = collections.attr(\"Iterable\");\n        if (pybind11::isinstance(obj, iterable_type)) {\n            for (const auto &t : obj) {\n                handle_to_gate_targets(t, out, false);\n            }\n            return;\n        }\n    }\n\n    std::stringstream ss;\n    ss << \"Don't know how to target the object `\";\n    ss << pybind11::cast<std::string_view>(pybind11::repr(obj));\n    ss << \"`.\";\n    throw std::invalid_argument(ss.str());\n}\n\nvoid circuit_append(\n    Circuit &self,\n    const pybind11::object &obj,\n    const pybind11::object &targets,\n    const pybind11::object &arg,\n    std::string_view tag,\n    bool backwards_compat) {\n    // Extract single target or list of targets.\n    std::vector<uint32_t> raw_targets;\n    handle_to_gate_targets(targets, raw_targets, true);\n\n    if (pybind11::isinstance<pybind11::str>(obj)) {\n        std::string_view gate_name = pybind11::cast<std::string_view>(obj);\n\n        // Maintain backwards compatibility to when there was always exactly one argument.\n        pybind11::object used_arg;\n        if (!arg.is_none()) {\n            used_arg = arg;\n        } else if (backwards_compat && GATE_DATA.at(gate_name).arg_count == 1) {\n            used_arg = pybind11::make_tuple(0.0);\n        } else {\n            used_arg = pybind11::make_tuple();\n        }\n\n        // Extract single argument or list of arguments.\n        try {\n            auto d = pybind11::cast<double>(used_arg);\n            self.safe_append_ua(gate_name, raw_targets, d, tag);\n            return;\n        } catch (const pybind11::cast_error &) {\n        }\n        try {\n            auto args = pybind11::cast<std::vector<double>>(used_arg);\n            self.safe_append_u(gate_name, raw_targets, args, tag);\n            return;\n        } catch (const pybind11::cast_error &) {\n        }\n        throw std::invalid_argument(\"Arg must be a double or sequence of doubles.\");\n    } else if (pybind11::isinstance<PyCircuitInstruction>(obj)) {\n        if (!raw_targets.empty() || !arg.is_none() || !tag.empty()) {\n            throw std::invalid_argument(\n                \"Can't specify `targets` or `arg` or `tag` when appending a stim.CircuitInstruction.\");\n        }\n\n        const PyCircuitInstruction &instruction = pybind11::cast<PyCircuitInstruction>(obj);\n        self.safe_append(\n            CircuitInstruction{\n                instruction.gate_type,\n                instruction.gate_args,\n                instruction.targets,\n                pybind11::cast<std::string_view>(instruction.tag),\n            });\n    } else if (pybind11::isinstance<CircuitRepeatBlock>(obj)) {\n        if (!raw_targets.empty() || !arg.is_none() || !tag.empty()) {\n            throw std::invalid_argument(\n                \"Can't specify `targets` or `arg` or `tag` when appending a stim.CircuitRepeatBlock.\");\n        }\n\n        const CircuitRepeatBlock &block = pybind11::cast<CircuitRepeatBlock>(obj);\n        self.append_repeat_block(block.repeat_count, block.body, pybind11::cast<std::string_view>(block.tag));\n    } else if (pybind11::isinstance<Circuit>(obj)) {\n        self += pybind11::cast<Circuit>(obj);\n    } else {\n        throw std::invalid_argument(\n            \"First argument of append_operation must be a str (a gate name), \"\n            \"a stim.CircuitInstruction, \"\n            \"or a stim.CircuitRepeatBlock\");\n    }\n}\nvoid circuit_append_backwards_compat(\n    Circuit &self,\n    const pybind11::object &obj,\n    const pybind11::object &targets,\n    const pybind11::object &arg,\n    std::string_view tag) {\n    circuit_append(self, obj, targets, arg, tag, true);\n}\nvoid circuit_append_strict(\n    Circuit &self,\n    const pybind11::object &obj,\n    const pybind11::object &targets,\n    const pybind11::object &arg,\n    std::string_view tag) {\n    circuit_append(self, obj, targets, arg, tag, false);\n}\n\npybind11::class_<Circuit> stim_pybind::pybind_circuit(pybind11::module &m) {\n    auto c = pybind11::class_<Circuit>(\n        m,\n        \"Circuit\",\n        clean_doc_string(R\"DOC(\n            A mutable stabilizer circuit.\n\n            The stim.Circuit class is arguably the most important object in the\n            entire library. It is the interface through which you explain a\n            noisy quantum computation to Stim, in order to do fast bulk sampling\n            or fast error analysis.\n\n            For example, suppose you want to use a matching-based decoder on a\n            new quantum error correction construction. Stim can help you do this\n            but the very first step is to create a circuit implementing the\n            construction. Once you have the circuit you can then use methods like\n            stim.Circuit.detector_error_model() to create an object that can be\n            used to configure the decoder, or like\n            stim.Circuit.compile_detector_sampler() to produce problems for the\n            decoder to solve, or like stim.Circuit.shortest_graphlike_error() to\n            check for mistakes in the implementation of the code.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit()\n                >>> c.append(\"X\", 0)\n                >>> c.append(\"M\", 0)\n                >>> c.compile_sampler().sample(shots=1)\n                array([[ True]])\n\n                >>> stim.Circuit('''\n                ...    H 0\n                ...    CNOT 0 1\n                ...    M 0 1\n                ...    DETECTOR rec[-1] rec[-2]\n                ... ''').compile_detector_sampler().sample(shots=1)\n                array([[False]])\n\n        )DOC\")\n            .data());\n\n    return c;\n}\n\nuint64_t obj_to_abs_detector_id(const pybind11::handle &obj, bool fail) {\n    try {\n        return obj.cast<uint64_t>();\n    } catch (const pybind11::cast_error &) {\n    }\n    try {\n        ExposedDemTarget t = obj.cast<ExposedDemTarget>();\n        if (t.is_relative_detector_id()) {\n            return t.data;\n        }\n    } catch (const pybind11::cast_error &) {\n    }\n    if (!fail) {\n        return UINT64_MAX;\n    }\n\n    std::stringstream ss;\n    ss << \"Expected a detector id but didn't get a stim.DemTarget or a uint64_t.\";\n    ss << \" Got \" << pybind11::repr(obj);\n    throw std::invalid_argument(ss.str());\n}\n\nstd::set<uint64_t> obj_to_abs_detector_id_set(\n    const pybind11::object &obj, const std::function<size_t(void)> &get_num_detectors) {\n    std::set<uint64_t> filter;\n    if (obj.is_none()) {\n        size_t n = get_num_detectors();\n        for (size_t k = 0; k < n; k++) {\n            filter.insert(k);\n        }\n    } else {\n        uint64_t single = obj_to_abs_detector_id(obj, false);\n        if (single != UINT64_MAX) {\n            filter.insert(single);\n        } else {\n            for (const auto &e : obj) {\n                filter.insert(obj_to_abs_detector_id(e, true));\n            }\n        }\n    }\n    return filter;\n}\n\nvoid stim_pybind::pybind_circuit_methods(pybind11::module &, pybind11::class_<Circuit> &c) {\n    c.def(\n        pybind11::init([](std::string_view stim_program_text) {\n            Circuit self;\n            self.append_from_text(stim_program_text);\n            return self;\n        }),\n        pybind11::arg(\"stim_program_text\") = \"\",\n        clean_doc_string(R\"DOC(\n            Creates a stim.Circuit.\n\n            Args:\n                stim_program_text: Defaults to empty. Describes operations to append into\n                    the circuit.\n\n            Examples:\n                >>> import stim\n                >>> empty = stim.Circuit()\n                >>> not_empty = stim.Circuit('''\n                ...    X 0\n                ...    CNOT 0 1\n                ...    M 1\n                ... ''')\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_measurements\",\n        &Circuit::count_measurements,\n        clean_doc_string(R\"DOC(\n            Counts the number of bits produced when sampling the circuit's measurements.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    M 0\n                ...    REPEAT 100 {\n                ...        M 0 1\n                ...    }\n                ... ''')\n                >>> c.num_measurements\n                201\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_detectors\",\n        &Circuit::count_detectors,\n        clean_doc_string(R\"DOC(\n            Counts the number of bits produced when sampling the circuit's detectors.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    M 0\n                ...    DETECTOR rec[-1]\n                ...    REPEAT 100 {\n                ...        M 0 1 2\n                ...        DETECTOR rec[-1]\n                ...        DETECTOR rec[-2]\n                ...    }\n                ... ''')\n                >>> c.num_detectors\n                201\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_ticks\",\n        &Circuit::count_ticks,\n        clean_doc_string(R\"DOC(\n            Counts the number of TICK instructions executed when running the circuit.\n\n            TICKs in loops are counted once per iteration.\n\n            Returns:\n                The number of ticks executed by the circuit.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit().num_ticks\n                0\n\n                >>> stim.Circuit('''\n                ...    TICK\n                ... ''').num_ticks\n                1\n\n                >>> stim.Circuit('''\n                ...    H 0\n                ...    TICK\n                ...    CX 0 1\n                ...    TICK\n                ... ''').num_ticks\n                2\n\n                >>> stim.Circuit('''\n                ...    H 0\n                ...    TICK\n                ...    REPEAT 100 {\n                ...        CX 0 1\n                ...        TICK\n                ...    }\n                ... ''').num_ticks\n                101\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_observables\",\n        &Circuit::count_observables,\n        clean_doc_string(R\"DOC(\n            Counts the number of logical observables defined by the circuit.\n\n            This is one more than the largest index that appears as an argument to an\n            OBSERVABLE_INCLUDE instruction.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    M 0\n                ...    OBSERVABLE_INCLUDE(2) rec[-1]\n                ...    OBSERVABLE_INCLUDE(5) rec[-1]\n                ... ''')\n                >>> c.num_observables\n                6\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_qubits\",\n        &Circuit::count_qubits,\n        clean_doc_string(R\"DOC(\n            Counts the number of qubits used when simulating the circuit.\n\n            This is always one more than the largest qubit index used by the circuit.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...    X 0\n                ...    M 0 1\n                ... ''').num_qubits\n                2\n                >>> stim.Circuit('''\n                ...    X 0\n                ...    M 0 1\n                ...    H 100\n                ... ''').num_qubits\n                101\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_sweep_bits\",\n        &Circuit::count_sweep_bits,\n        clean_doc_string(R\"DOC(\n            Returns the number of sweep bits needed to completely configure the circuit.\n\n            This is always one more than the largest sweep bit index used by the circuit.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...    CX sweep[2] 0\n                ... ''').num_sweep_bits\n                3\n                >>> stim.Circuit('''\n                ...    CZ sweep[5] 0\n                ...    CX sweep[2] 0\n                ... ''').num_sweep_bits\n                6\n        )DOC\")\n            .data());\n\n    c.def(\n        \"compile_sampler\",\n        &py_init_compiled_sampler,\n        pybind11::kw_only(),\n        pybind11::arg(\"skip_reference_sample\") = false,\n        pybind11::arg(\"seed\") = pybind11::none(),\n        pybind11::arg(\"reference_sample\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def compile_sampler(self, *, skip_reference_sample: bool = False, seed: Optional[int] = None, reference_sample: Optional[np.ndarray] = None) -> stim.CompiledMeasurementSampler:\n            Returns an object that can quickly batch sample measurements from the circuit.\n\n            Args:\n                skip_reference_sample: Defaults to False. When set to True, the reference\n                    sample used by the sampler is initialized to all-zeroes instead of being\n                    collected from the circuit. This means that the results returned by the\n                    sampler are actually whether or not each measurement was *flipped*,\n                    instead of true measurement results.\n\n                    Forcing an all-zero reference sample is useful when you are only\n                    interested in error propagation and don't want to have to deal with the\n                    fact that some measurements want to be On when no errors occur. It is\n                    also useful when you know for sure that the all-zero result is actually\n                    a possible result from the circuit (under noiseless execution), meaning\n                    it is a valid reference sample as good as any other. Computing the\n                    reference sample is the most time consuming and memory intensive part of\n                    simulating the circuit, so promising that the simulator can safely skip\n                    that step is an effective optimization.\n                seed: PARTIALLY determines simulation results by deterministically seeding\n                    the random number generator.\n\n                    Must be None or an integer in range(2**64).\n\n                    Defaults to None. When None, the prng is seeded from system entropy.\n\n                    When set to an integer, making the exact same series calls on the exact\n                    same machine with the exact same version of Stim will produce the exact\n                    same simulation results.\n\n                    CAUTION: simulation results *WILL NOT* be consistent between versions of\n                    Stim. This restriction is present to make it possible to have future\n                    optimizations to the random sampling, and is enforced by introducing\n                    intentional differences in the seeding strategy from version to version.\n\n                    CAUTION: simulation results *MAY NOT* be consistent across machines that\n                    differ in the width of supported SIMD instructions. For example, using\n                    the same seed on a machine that supports AVX instructions and one that\n                    only supports SSE instructions may produce different simulation results.\n\n                    CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                    shots are taken. For example, taking 10 shots and then 90 shots will\n                    give different results from taking 100 shots in one call.\n                reference_sample: The data to xor into the measurement flips produced by the\n                    frame simulator, in order to produce proper measurement results.\n                    This can either be specified as an `np.bool_` array or a bit packed\n                    `np.uint8` array (little endian). Under normal conditions, the reference\n                    sample should be a valid noiseless sample of the circuit, such as the\n                    one returned by `circuit.reference_sample()`. If this argument is not\n                    provided, the reference sample will be set to\n                    `circuit.reference_sample()`, unless `skip_reference_sample=True`\n                    is used, in which case it will be set to all-zeros.\n\n            Raises:\n                ValueError: skip_reference_sample is True and reference_sample is not None.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    X 2\n                ...    M 0 1 2\n                ... ''')\n                >>> s = c.compile_sampler()\n                >>> s.sample(shots=1)\n                array([[False, False,  True]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"reference_sample\",\n        [](const Circuit &self, bool bit_packed) {\n            auto ref = TableauSimulator<MAX_BITWORD_WIDTH>::reference_sample_circuit(self);\n            simd_bits_range_ref<MAX_BITWORD_WIDTH> reference_sample(ref.ptr_simd, ref.num_simd_words);\n            size_t num_measure = self.count_measurements();\n            return simd_bits_to_numpy(reference_sample, num_measure, bit_packed);\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def reference_sample(self, *, bit_packed: bool = False) -> np.ndarray:\n            Samples the given circuit in a deterministic fashion.\n\n            Discards all noisy operations, and biases all collapse events\n            towards +Z instead of randomly +Z/-Z.\n\n            Args:\n                bit_packed: Defaults to False. Determines whether the output numpy arrays\n                    use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n            Returns:\n                A numpy array containing the reference sample.\n\n                if bit_packed:\n                    shape == (math.ceil(num_measurements / 8),)\n                    dtype == np.uint8\n                else:\n                    shape == (num_measurements,)\n                    dtype == np.bool_\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...     X 1\n                ...     M 0 1\n                ... ''').reference_sample()\n                array([False,  True])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"reference_detector_and_observable_signs\",\n        [](const Circuit &self, bool bit_packed) -> pybind11::object {\n            simd_bits<MAX_BITWORD_WIDTH> ref = TableauSimulator<MAX_BITWORD_WIDTH>::reference_sample_circuit(self);\n            size_t num_det = self.count_detectors();\n            size_t num_obs = self.count_observables();\n            simd_bits<MAX_BITWORD_WIDTH> dets(num_det);\n            simd_bits<MAX_BITWORD_WIDTH> obs(num_obs);\n            size_t offset = 0;\n            size_t k_det = 0;\n            self.for_each_operation([&](CircuitInstruction inst) {\n                if (inst.gate_type == GateType::DETECTOR || inst.gate_type == GateType::OBSERVABLE_INCLUDE) {\n                    bit_ref d = inst.gate_type == GateType::DETECTOR ? dets[k_det++] : obs[(int)inst.args[0]];\n                    for (const auto &t : inst.targets) {\n                        if (t.is_measurement_record_target()) {\n                            d ^= ref[offset + t.value()];\n                        }\n                    }\n                } else {\n                    offset += inst.count_measurement_results();\n                }\n            });\n            auto det_py = simd_bits_to_numpy(dets, num_det, bit_packed);\n            auto obs_py = simd_bits_to_numpy(obs, num_obs, bit_packed);\n            return pybind11::make_tuple(det_py, obs_py);\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def reference_detector_and_observable_signs(self, *, bit_packed: bool = False) -> tuple[np.ndarray, np.ndarray]:\n            Determines noiseless parities of the measurement sets of detectors/observables.\n\n            BEWARE: the returned values are NOT the \"expected value of the\n            detector/observable\". Stim consistently defines the value of a\n            detector/observable as whether or not it flipped, so the expected value of a\n            detector/observable is vacuously always 0 (not flipped). This method instead\n            returns the \"sign\"; the expected parity of the measurement set declared by the\n            detector/observable. The sign is the baseline used to determine if a flip\n            occurred. A detector/observable's value is whether its sign disagrees with the\n            measured parity of its measurement set.\n\n            Note that this method doesn't account for sweep bits. It will effectively ignore\n            instructions like `CX sweep[0] 0`.\n\n            Args:\n                bit_packed: Defaults to False. Determines whether the output numpy arrays\n                    use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n            Returns:\n                A (det, obs) tuple with numpy arrays containing the reference parities.\n\n                if bit_packed:\n                    det.shape == (math.ceil(num_detectors / 8),)\n                    det.dtype == np.uint8\n                    obs.shape == (math.ceil(num_observables / 8),)\n                    obs.dtype == np.uint8\n                else:\n                    det.shape == (num_detectors,)\n                    det.dtype == np.bool_\n                    obs.shape == (num_observables,)\n                    obs.dtype == np.bool_\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...     X 1\n                ...     M 0 1\n                ...     DETECTOR rec[-1]\n                ...     DETECTOR rec[-2]\n                ...     OBSERVABLE_INCLUDE(3) rec[-1] rec[-2]\n                ... ''').reference_detector_and_observable_signs()\n                (array([ True, False]), array([False, False, False,  True]))\n        )DOC\")\n            .data());\n\n    c.def(\n        \"compile_m2d_converter\",\n        &py_init_compiled_measurements_to_detection_events_converter,\n        pybind11::kw_only(),\n        pybind11::arg(\"skip_reference_sample\") = false,\n        clean_doc_string(R\"DOC(\n            Creates a measurement-to-detection-event converter for the given circuit.\n\n            The converter can efficiently compute detection events and observable flips\n            from raw measurement data.\n\n            The converter uses a noiseless reference sample, collected from the circuit\n            using stim's Tableau simulator during initialization of the converter, as a\n            baseline for determining what the expected value of a detector is.\n\n            Note that the expected behavior of gauge detectors (detectors that are not\n            actually deterministic under noiseless execution) can vary depending on the\n            reference sample. Stim mitigates this by always generating the same reference\n            sample for a given circuit.\n\n            Args:\n                skip_reference_sample: Defaults to False. When set to True, the reference\n                    sample used by the converter is initialized to all-zeroes instead of\n                    being collected from the circuit. This should only be used if it's known\n                    that the all-zeroes sample is actually a possible result from the\n                    circuit (under noiseless execution).\n\n            Returns:\n                An initialized stim.CompiledMeasurementsToDetectionEventsConverter.\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n                >>> converter = stim.Circuit('''\n                ...    X 0\n                ...    M 0\n                ...    DETECTOR rec[-1]\n                ... ''').compile_m2d_converter()\n                >>> converter.convert(\n                ...     measurements=np.array([[0], [1]], dtype=np.bool_),\n                ...     append_observables=False,\n                ... )\n                array([[ True],\n                       [False]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"compile_detector_sampler\",\n        &py_init_compiled_detector_sampler,\n        pybind11::kw_only(),\n        pybind11::arg(\"seed\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            Returns an object that can batch sample detection events from the circuit.\n\n            Args:\n                seed: PARTIALLY determines simulation results by deterministically seeding\n                    the random number generator.\n\n                    Must be None or an integer in range(2**64).\n\n                    Defaults to None. When None, the prng is seeded from system entropy.\n\n                    When set to an integer, making the exact same series calls on the exact\n                    same machine with the exact same version of Stim will produce the exact\n                    same simulation results.\n\n                    CAUTION: simulation results *WILL NOT* be consistent between versions of\n                    Stim. This restriction is present to make it possible to have future\n                    optimizations to the random sampling, and is enforced by introducing\n                    intentional differences in the seeding strategy from version to version.\n\n                    CAUTION: simulation results *MAY NOT* be consistent across machines that\n                    differ in the width of supported SIMD instructions. For example, using\n                    the same seed on a machine that supports AVX instructions and one that\n                    only supports SSE instructions may produce different simulation results.\n\n                    CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                    shots are taken. For example, taking 10 shots and then 90 shots will\n                    give different results from taking 100 shots in one call.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    H 0\n                ...    CNOT 0 1\n                ...    M 0 1\n                ...    DETECTOR rec[-1] rec[-2]\n                ... ''')\n                >>> s = c.compile_detector_sampler()\n                >>> s.sample(shots=1)\n                array([[False]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"clear\",\n        &Circuit::clear,\n        clean_doc_string(R\"DOC(\n            Clears the contents of the circuit.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    X 0\n                ...    Y 1 2\n                ... ''')\n                >>> c.clear()\n                >>> c\n                stim.Circuit()\n        )DOC\")\n            .data());\n\n    c.def(\n        \"flattened_operations\",\n        [](Circuit &self) {\n            pybind11::list result;\n            self.for_each_operation([&](const CircuitInstruction &op) {\n                pybind11::list args;\n                pybind11::list targets;\n                for (auto t : op.targets) {\n                    auto v = t.qubit_value();\n                    if (t.data & TARGET_INVERTED_BIT) {\n                        targets.append(pybind11::make_tuple(\"inv\", v));\n                    } else if (t.data & (TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT)) {\n                        if (!(t.data & TARGET_PAULI_Z_BIT)) {\n                            targets.append(pybind11::make_tuple(\"X\", v));\n                        } else if (!(t.data & TARGET_PAULI_X_BIT)) {\n                            targets.append(pybind11::make_tuple(\"Z\", v));\n                        } else {\n                            targets.append(pybind11::make_tuple(\"Y\", v));\n                        }\n                    } else if (t.data & TARGET_RECORD_BIT) {\n                        targets.append(pybind11::make_tuple(\"rec\", -(long long)v));\n                    } else if (t.data & TARGET_SWEEP_BIT) {\n                        targets.append(pybind11::make_tuple(\"sweep\", v));\n                    } else {\n                        targets.append(pybind11::int_(v));\n                    }\n                }\n                for (auto t : op.args) {\n                    args.append(t);\n                }\n                const auto &gate_data = GATE_DATA[op.gate_type];\n                if (op.args.empty()) {\n                    // Backwards compatibility.\n                    result.append(pybind11::make_tuple(gate_data.name, targets, 0));\n                } else if (op.args.size() == 1) {\n                    // Backwards compatibility.\n                    result.append(pybind11::make_tuple(gate_data.name, targets, op.args[0]));\n                } else {\n                    result.append(pybind11::make_tuple(gate_data.name, targets, args));\n                }\n            });\n            return result;\n        },\n        clean_doc_string(R\"DOC(\n            [DEPRECATED]\n\n            Returns a list of tuples encoding the contents of the circuit.\n            Instead of this method, use `for instruction in circuit` or, to\n            avoid REPEAT blocks, `for instruction in circuit.flattened()`.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...    H 0\n                ...    X_ERROR(0.125) 1\n                ...    M 0 !1\n                ... ''').flattened_operations()\n                [('H', [0], 0), ('X_ERROR', [1], 0.125), ('M', [0, ('inv', 1)], 0)]\n\n                >>> stim.Circuit('''\n                ...    REPEAT 2 {\n                ...        H 6\n                ...    }\n                ... ''').flattened_operations()\n                [('H', [6], 0), ('H', [6], 0)]\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two circuits have identical contents.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two circuits have non-identical contents.\");\n\n    c.def(\n        \"__add__\",\n        &Circuit::operator+,\n        pybind11::arg(\"second\"),\n        clean_doc_string(R\"DOC(\n            Creates a circuit by appending two circuits.\n\n            Examples:\n                >>> import stim\n                >>> c1 = stim.Circuit('''\n                ...    X 0\n                ...    Y 1 2\n                ... ''')\n                >>> c2 = stim.Circuit('''\n                ...    M 0 1 2\n                ... ''')\n                >>> c1 + c2\n                stim.Circuit('''\n                    X 0\n                    Y 1 2\n                    M 0 1 2\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__iadd__\",\n        &Circuit::operator+=,\n        pybind11::arg(\"second\"),\n        clean_doc_string(R\"DOC(\n            Appends a circuit into the receiving circuit (mutating it).\n\n            Examples:\n                >>> import stim\n                >>> c1 = stim.Circuit('''\n                ...    X 0\n                ...    Y 1 2\n                ... ''')\n                >>> c2 = stim.Circuit('''\n                ...    M 0 1 2\n                ... ''')\n                >>> c1 += c2\n                >>> print(repr(c1))\n                stim.Circuit('''\n                    X 0\n                    Y 1 2\n                    M 0 1 2\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__imul__\",\n        &Circuit::operator*=,\n        pybind11::arg(\"repetitions\"),\n        clean_doc_string(R\"DOC(\n            Mutates the circuit by putting its contents into a REPEAT block.\n\n            Special case: if the repetition count is 0, the circuit is cleared.\n            Special case: if the repetition count is 1, nothing happens.\n\n            Args:\n                repetitions: The number of times the REPEAT block should repeat.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    X 0\n                ...    Y 1 2\n                ... ''')\n                >>> c *= 3\n                >>> print(repr(c))\n                stim.Circuit('''\n                    REPEAT 3 {\n                        X 0\n                        Y 1 2\n                    }\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__mul__\",\n        &Circuit::operator*,\n        pybind11::arg(\"repetitions\"),\n        clean_doc_string(R\"DOC(\n            Repeats the circuit using a REPEAT block.\n\n            Has special cases for 0 repetitions and 1 repetitions.\n\n            Args:\n                repetitions: The number of times the REPEAT block should repeat.\n\n            Returns:\n                repetitions=0: An empty circuit.\n                repetitions=1: A copy of this circuit.\n                repetitions>=2: A circuit with a single REPEAT block, where the contents of\n                    that repeat block are this circuit.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    X 0\n                ...    Y 1 2\n                ... ''')\n                >>> c * 3\n                stim.Circuit('''\n                    REPEAT 3 {\n                        X 0\n                        Y 1 2\n                    }\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__rmul__\",\n        &Circuit::operator*,\n        pybind11::arg(\"repetitions\"),\n        clean_doc_string(R\"DOC(\n            Repeats the circuit using a REPEAT block.\n\n            Has special cases for 0 repetitions and 1 repetitions.\n\n            Args:\n                repetitions: The number of times the REPEAT block should repeat.\n\n            Returns:\n                repetitions=0: An empty circuit.\n                repetitions=1: A copy of this circuit.\n                repetitions>=2: A circuit with a single REPEAT block, where the contents of\n                    that repeat block are this circuit.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    X 0\n                ...    Y 1 2\n                ... ''')\n                >>> 3 * c\n                stim.Circuit('''\n                    REPEAT 3 {\n                        X 0\n                        Y 1 2\n                    }\n                ''')\n        )DOC\")\n            .data());\n\n    for (size_t k = 0; k < 2; k++) {\n        c.def(\n            k == 0 ? \"append_operation\" : \"append\",\n            k == 0 ? &circuit_append_backwards_compat : &circuit_append_strict,\n            pybind11::arg(\"name\"),\n            pybind11::arg(\"targets\") = pybind11::make_tuple(),\n            pybind11::arg(\"arg\") = pybind11::none(),\n            pybind11::kw_only(),\n            pybind11::arg(\"tag\") = \"\",\n            k == 0 ? \"[DEPRECATED] use stim.Circuit.append instead\"\n                   : clean_doc_string(R\"DOC(\n                @overload def append(self, name: str, targets: Union[int, stim.GateTarget, stim.PauliString, Iterable[Union[int, stim.GateTarget, stim.PauliString]]], arg: Union[float, Iterable[float], None] = None, *, tag: str = \"\") -> None:\n                @overload def append(self, name: Union[stim.CircuitInstruction, stim.CircuitRepeatBlock, stim.Circuit]) -> None:\n                Appends an operation into the circuit.\n\n                Note: `stim.Circuit.append_operation` is an alias of `stim.Circuit.append`.\n\n                Args:\n                    name: The name of the operation's gate (e.g. \"H\" or \"M\" or \"CNOT\").\n\n                        This argument can also be set to a `stim.CircuitInstruction` or\n                        `stim.CircuitInstructionBlock`, which results in the instruction or\n                        block being appended to the circuit. The other arguments (targets\n                        and arg) can't be specified when doing so.\n\n                        (The argument being called `name` is no longer quite right, but\n                        is being kept for backwards compatibility.)\n                    targets: The objects operated on by the gate. This can be either a\n                        single target or an iterable of multiple targets.\n\n                        Each target can be:\n                            An int: The index of a targeted qubit.\n                            A `stim.GateTarget`: Could be a variety of things. Methods like\n                                `stim.target_rec`, `stim.target_sweet`, `stim.target_x`, and\n                                `stim.CircuitInstruction.__getitem__` all return this type.\n                            A `stim.PauliString`: This will automatically be expanded into\n                                a product of pauli targets like `X1*Y2*Z3`.\n                    arg: The \"parens arguments\" for the gate, such as the probability for a\n                        noise operation. A double or list of doubles parameterizing the\n                        gate. Different gates take different parens arguments. For example,\n                        X_ERROR takes a probability, OBSERVABLE_INCLUDE takes an observable\n                        index, and PAULI_CHANNEL_1 takes three disjoint probabilities.\n\n                        Note: Defaults to no parens arguments. Except, for backwards\n                        compatibility reasons, `cirq.append_operation` (but not\n                        `cirq.append`) will default to a single 0.0 argument for gates that\n                        take exactly one argument.\n                    tag: A customizable string attached to the instruction.\n\n                Examples:\n                    >>> import stim\n                    >>> c = stim.Circuit()\n                    >>> c.append(\"X\", 0)\n                    >>> c.append(\"H\", [0, 1])\n                    >>> c.append(\"M\", [0, stim.target_inv(1)])\n                    >>> c.append(\"CNOT\", [stim.target_rec(-1), 0])\n                    >>> c.append(\"X_ERROR\", [0], 0.125)\n                    >>> c.append(\"CORRELATED_ERROR\", [stim.target_x(0), stim.target_y(2)], 0.25)\n                    >>> c.append(\"MPP\", [stim.PauliString(\"X1*Y2\"), stim.GateTarget(\"Z3\")])\n                    >>> print(repr(c))\n                    stim.Circuit('''\n                        X 0\n                        H 0 1\n                        M 0 !1\n                        CX rec[-1] 0\n                        X_ERROR(0.125) 0\n                        E(0.25) X0 Y2\n                        MPP X1*Y2 Z3\n                    ''')\n            )DOC\")\n                         .data());\n    }\n\n    c.def(\n        \"insert\",\n        &circuit_insert,\n        pybind11::arg(\"index\"),\n        pybind11::arg(\"operation\"),\n        clean_doc_string(R\"DOC(\n            Inserts an operation at the given index, pushing existing operations forward.\n            @signature def insert(self, index: int, operation: Union[stim.CircuitInstruction, stim.Circuit]) -> None:\n\n            Beware that inserted operations are automatically fused with the preceding\n            and following operations, if possible. This can make it complex to reason\n            about how the indices of operations change in response to insertions.\n\n            Args:\n                index: The index to insert at.\n\n                    Must satisfy -len(circuit) <= index < len(circuit). Negative indices\n                    are made non-negative by adding len(circuit) to them, so they refer to\n                    indices relative to the end of the circuit instead of the start.\n\n                    Instructions before the index are not shifted. Instructions that\n                    were at or after the index are shifted forwards as needed.\n                operation: The object to insert. This can be a single\n                    stim.CircuitInstruction or an entire stim.Circuit.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...     H 0\n                ...     S 1\n                ...     X 2\n                ... ''')\n                >>> c.insert(1, stim.CircuitInstruction(\"Y\", [3, 4, 5]))\n                >>> c\n                stim.Circuit('''\n                    H 0\n                    Y 3 4 5\n                    S 1\n                    X 2\n                ''')\n                >>> c.insert(-1, stim.Circuit(\"S 999\\nCX 0 1\\nCZ 2 3\"))\n                >>> c\n                stim.Circuit('''\n                    H 0\n                    Y 3 4 5\n                    S 1 999\n                    CX 0 1\n                    CZ 2 3\n                    X 2\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"pop\",\n        &circuit_pop,\n        pybind11::arg(\"index\") = -1,\n        clean_doc_string(R\"DOC(\n            @signature def pop(self, index: int = -1) -> Union[stim.CircuitInstruction, stim.CircuitRepeatBlock]:\n            Pops an operation from the end of the circuit, or at the given index.\n\n            Args:\n                index: Defaults to -1 (end of circuit). The index to pop from.\n\n            Returns:\n                The popped instruction.\n\n            Raises:\n                IndexError: The given index is outside the bounds of the circuit.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...     H 0\n                ...     S 1\n                ...     X 2\n                ...     Y 3\n                ... ''')\n                >>> c.pop()\n                stim.CircuitInstruction('Y', [stim.GateTarget(3)], [])\n                >>> c.pop(1)\n                stim.CircuitInstruction('S', [stim.GateTarget(1)], [])\n                >>> c\n                stim.Circuit('''\n                    H 0\n                    X 2\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"append_from_stim_program_text\",\n        [](Circuit &self, const char *text) {\n            self.append_from_text(text);\n        },\n        pybind11::arg(\"stim_program_text\"),\n        clean_doc_string(R\"DOC(\n            Appends operations described by a STIM format program into the circuit.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit()\n                >>> c.append_from_stim_program_text('''\n                ...    H 0  # comment\n                ...    CNOT 0 2\n                ...\n                ...    M 2\n                ...    CNOT rec[-1] 1\n                ... ''')\n                >>> print(c)\n                H 0\n                CX 0 2\n                M 2\n                CX rec[-1] 1\n\n            Args:\n                stim_program_text: The STIM program text containing the circuit operations\n                    to append.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__str__\",\n        &Circuit::str,\n        \"Returns stim instructions (that can be saved to a file and parsed by stim) for the current circuit.\");\n    c.def(\n        \"__repr__\",\n        &circuit_repr,\n        \"Returns text that is a valid python expression evaluating to an equivalent `stim.Circuit`.\");\n\n    c.def(\n        \"copy\",\n        [](Circuit &self) {\n            Circuit copy = self;\n            return copy;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the circuit. An independent circuit with the same contents.\n\n            Examples:\n                >>> import stim\n\n                >>> c1 = stim.Circuit(\"H 0\")\n                >>> c2 = c1.copy()\n                >>> c2 is c1\n                False\n                >>> c2 == c1\n                True\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"generated\",\n        [](std::string_view type,\n           size_t distance,\n           size_t rounds,\n           double after_clifford_depolarization,\n           double before_round_data_depolarization,\n           double before_measure_flip_probability,\n           double after_reset_flip_probability) {\n            auto r = type.find(':');\n            std::string_view code;\n            std::string_view task;\n            if (r == std::string::npos) {\n                code = \"\";\n                task = type;\n            } else {\n                code = type.substr(0, r);\n                task = type.substr(r + 1);\n            }\n\n            CircuitGenParameters params(rounds, distance, std::string(task));\n            params.after_clifford_depolarization = after_clifford_depolarization;\n            params.after_reset_flip_probability = after_reset_flip_probability;\n            params.before_measure_flip_probability = before_measure_flip_probability;\n            params.before_round_data_depolarization = before_round_data_depolarization;\n            params.validate_params();\n\n            if (code == \"surface_code\") {\n                return generate_surface_code_circuit(params).circuit;\n            } else if (code == \"repetition_code\") {\n                return generate_rep_code_circuit(params).circuit;\n            } else if (code == \"color_code\") {\n                return generate_color_code_circuit(params).circuit;\n            } else {\n                throw std::invalid_argument(\n                    \"Unrecognized circuit type. Expected type to start with \"\n                    \"'surface_code:', 'repetition_code:', or 'color_code:'.\");\n            }\n        },\n        pybind11::arg(\"code_task\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"distance\"),\n        pybind11::arg(\"rounds\"),\n        pybind11::arg(\"after_clifford_depolarization\") = 0.0,\n        pybind11::arg(\"before_round_data_depolarization\") = 0.0,\n        pybind11::arg(\"before_measure_flip_probability\") = 0.0,\n        pybind11::arg(\"after_reset_flip_probability\") = 0.0,\n        clean_doc_string(R\"DOC(\n            Generates common circuits.\n\n            The generated circuits can include configurable noise.\n\n            The generated circuits include DETECTOR and OBSERVABLE_INCLUDE annotations so\n            that their detection events and logical observables can be sampled.\n\n            The generated circuits include TICK annotations to mark the progression of time.\n            (E.g. so that converting them using `stimcirq.stim_circuit_to_cirq_circuit` will\n            produce a `cirq.Circuit` with the intended moment structure.)\n\n            Args:\n                code_task: A string identifying the type of circuit to generate. Available\n                    code tasks are:\n                        - \"repetition_code:memory\"\n                        - \"surface_code:rotated_memory_x\"\n                        - \"surface_code:rotated_memory_z\"\n                        - \"surface_code:unrotated_memory_x\"\n                        - \"surface_code:unrotated_memory_z\"\n                        - \"color_code:memory_xyz\"\n                distance: The desired code distance of the generated circuit. The code\n                    distance is the minimum number of physical errors needed to cause a\n                    logical error. This parameter indirectly determines how many qubits the\n                    generated circuit uses.\n                rounds: How many times the measurement qubits in the generated circuit will\n                    be measured. Indirectly determines the duration of the generated\n                    circuit.\n                after_clifford_depolarization: Defaults to 0. The probability (p) of\n                    `DEPOLARIZE1(p)` operations to add after every single-qubit Clifford\n                    operation and `DEPOLARIZE2(p)` operations to add after every two-qubit\n                    Clifford operation. The after-Clifford depolarizing operations are only\n                    included if this probability is not 0.\n                before_round_data_depolarization: Defaults to 0. The probability (p) of\n                    `DEPOLARIZE1(p)` operations to apply to every data qubit at the start of\n                    a round of stabilizer measurements. The start-of-round depolarizing\n                    operations are only included if this probability is not 0.\n                before_measure_flip_probability: Defaults to 0. The probability (p) of\n                    `X_ERROR(p)` operations applied to qubits before each measurement (X\n                    basis measurements use `Z_ERROR(p)` instead). The before-measurement\n                    flips are only included if this probability is not 0.\n                after_reset_flip_probability: Defaults to 0. The probability (p) of\n                    `X_ERROR(p)` operations applied to qubits after each reset (X basis\n                    resets use `Z_ERROR(p)` instead). The after-reset flips are only\n                    included if this probability is not 0.\n\n            Returns:\n                The generated circuit.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit.generated(\n                ...     \"repetition_code:memory\",\n                ...     distance=4,\n                ...     rounds=10000,\n                ...     after_clifford_depolarization=0.0125)\n                >>> print(circuit)\n                R 0 1 2 3 4 5 6\n                TICK\n                CX 0 1 2 3 4 5\n                DEPOLARIZE2(0.0125) 0 1 2 3 4 5\n                TICK\n                CX 2 1 4 3 6 5\n                DEPOLARIZE2(0.0125) 2 1 4 3 6 5\n                TICK\n                MR 1 3 5\n                DETECTOR(1, 0) rec[-3]\n                DETECTOR(3, 0) rec[-2]\n                DETECTOR(5, 0) rec[-1]\n                REPEAT 9999 {\n                    TICK\n                    CX 0 1 2 3 4 5\n                    DEPOLARIZE2(0.0125) 0 1 2 3 4 5\n                    TICK\n                    CX 2 1 4 3 6 5\n                    DEPOLARIZE2(0.0125) 2 1 4 3 6 5\n                    TICK\n                    MR 1 3 5\n                    SHIFT_COORDS(0, 1)\n                    DETECTOR(1, 0) rec[-3] rec[-6]\n                    DETECTOR(3, 0) rec[-2] rec[-5]\n                    DETECTOR(5, 0) rec[-1] rec[-4]\n                }\n                M 0 2 4 6\n                DETECTOR(1, 1) rec[-3] rec[-4] rec[-7]\n                DETECTOR(3, 1) rec[-2] rec[-3] rec[-6]\n                DETECTOR(5, 1) rec[-1] rec[-2] rec[-5]\n                OBSERVABLE_INCLUDE(0) rec[-1]\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_file\",\n        [](pybind11::object &obj) {\n            if (pybind11::isinstance<pybind11::str>(obj)) {\n                std::string_view path = pybind11::cast<std::string_view>(obj);\n                RaiiFile f(path, \"rb\");\n                return Circuit::from_file(f.f);\n            }\n\n            pybind11::object py_path = pybind11::module::import(\"pathlib\").attr(\"Path\");\n            if (pybind11::isinstance(obj, py_path)) {\n                pybind11::object obj_str = pybind11::str(obj);\n                std::string_view path = pybind11::cast<std::string_view>(obj_str);\n                RaiiFile f(path, \"rb\");\n                return Circuit::from_file(f.f);\n            }\n\n            pybind11::object py_text_io_base = pybind11::module::import(\"io\").attr(\"TextIOBase\");\n            if (pybind11::isinstance(obj, py_text_io_base)) {\n                pybind11::object contents = obj.attr(\"read\")();\n                return Circuit(pybind11::cast<std::string_view>(contents));\n            }\n\n            std::stringstream ss;\n            ss << \"Don't know how to read from \";\n            ss << pybind11::repr(obj);\n            throw std::invalid_argument(ss.str());\n        },\n        pybind11::arg(\"file\"),\n        clean_doc_string(R\"DOC(\n            @signature def from_file(file: Union[io.TextIOBase, str, pathlib.Path]) -> stim.Circuit:\n            Reads a stim circuit from a file.\n\n            The file format is defined at\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n            Args:\n                file: A file path or open file object to read from.\n\n            Returns:\n                The circuit parsed from the file.\n\n            Examples:\n                >>> import stim\n                >>> import tempfile\n\n                >>> with tempfile.TemporaryDirectory() as tmpdir:\n                ...     path = tmpdir + '/tmp.stim'\n                ...     with open(path, 'w') as f:\n                ...         print('H 5', file=f)\n                ...     circuit = stim.Circuit.from_file(path)\n                >>> circuit\n                stim.Circuit('''\n                    H 5\n                ''')\n\n                >>> with tempfile.TemporaryDirectory() as tmpdir:\n                ...     path = tmpdir + '/tmp.stim'\n                ...     with open(path, 'w') as f:\n                ...         print('CNOT 4 5', file=f)\n                ...     with open(path) as f:\n                ...         circuit = stim.Circuit.from_file(f)\n                >>> circuit\n                stim.Circuit('''\n                    CX 4 5\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_file\",\n        [](const Circuit &self, pybind11::object &obj) {\n            if (pybind11::isinstance<pybind11::str>(obj)) {\n                std::string path = pybind11::cast<std::string>(obj);\n                std::ofstream out(path, std::ofstream::out);\n                if (!out.is_open()) {\n                    throw std::invalid_argument(\"Failed to open \" + path);\n                }\n                out << self << '\\n';\n                return;\n            }\n\n            auto py_path = pybind11::module::import(\"pathlib\").attr(\"Path\");\n            if (pybind11::isinstance(obj, py_path)) {\n                auto path = pybind11::cast<std::string>(pybind11::str(obj));\n                std::ofstream out(path, std::ofstream::out);\n                if (!out.is_open()) {\n                    throw std::invalid_argument(\"Failed to open \" + path);\n                }\n                out << self << '\\n';\n                return;\n            }\n\n            auto py_text_io_base = pybind11::module::import(\"io\").attr(\"TextIOBase\");\n            if (pybind11::isinstance(obj, py_text_io_base)) {\n                obj.attr(\"write\")(pybind11::str(self.str()));\n                obj.attr(\"write\")(pybind11::str(\"\\n\"));\n                return;\n            }\n\n            std::stringstream ss;\n            ss << \"Don't know how to write to \";\n            ss << pybind11::repr(obj);\n            throw std::invalid_argument(ss.str());\n        },\n        pybind11::arg(\"file\"),\n        clean_doc_string(R\"DOC(\n            @signature def to_file(self, file: Union[io.TextIOBase, str, pathlib.Path]) -> None:\n            Writes the stim circuit to a file.\n\n            The file format is defined at\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n\n            Args:\n                file: A file path or an open file to write to.\n\n            Examples:\n                >>> import stim\n                >>> import tempfile\n                >>> c = stim.Circuit('H 5\\nX 0')\n\n                >>> with tempfile.TemporaryDirectory() as tmpdir:\n                ...     path = tmpdir + '/tmp.stim'\n                ...     with open(path, 'w') as f:\n                ...         c.to_file(f)\n                ...     with open(path) as f:\n                ...         contents = f.read()\n                >>> contents\n                'H 5\\nX 0\\n'\n\n                >>> with tempfile.TemporaryDirectory() as tmpdir:\n                ...     path = tmpdir + '/tmp.stim'\n                ...     c.to_file(path)\n                ...     with open(path) as f:\n                ...         contents = f.read()\n                >>> contents\n                'H 5\\nX 0\\n'\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__len__\",\n        [](const Circuit &self) {\n            return self.operations.size();\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of top-level instructions and blocks in the circuit.\n\n            Instructions inside of blocks are not included in this count.\n\n            Examples:\n                >>> import stim\n                >>> len(stim.Circuit())\n                0\n                >>> len(stim.Circuit('''\n                ...    X 0\n                ...    X_ERROR(0.5) 1 2\n                ...    TICK\n                ...    M 0\n                ...    DETECTOR rec[-1]\n                ... '''))\n                5\n                >>> len(stim.Circuit('''\n                ...    REPEAT 100 {\n                ...        X 0\n                ...        Y 1 2\n                ...    }\n                ... '''))\n                1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__getitem__\",\n        &circuit_get_item,\n        pybind11::arg(\"index_or_slice\"),\n        clean_doc_string(R\"DOC(\n            Returns copies of instructions from the circuit.\n            @overload def __getitem__(self, index_or_slice: int) -> Union[stim.CircuitInstruction, stim.CircuitRepeatBlock]:\n            @overload def __getitem__(self, index_or_slice: slice) -> stim.Circuit:\n\n            Args:\n                index_or_slice: An integer index picking out an instruction to return, or a\n                    slice picking out a range of instructions to return as a circuit.\n\n            Returns:\n                If the index was an integer, then an instruction from the circuit.\n                If the index was a slice, then a circuit made up of the instructions in that\n                slice.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...    X 0\n                ...    X_ERROR(0.5) 2\n                ...    REPEAT 100 {\n                ...        X 0\n                ...        Y 1 2\n                ...    }\n                ...    TICK\n                ...    M 0\n                ...    DETECTOR rec[-1]\n                ... ''')\n                >>> circuit[1]\n                stim.CircuitInstruction('X_ERROR', [stim.GateTarget(2)], [0.5])\n                >>> circuit[2]\n                stim.CircuitRepeatBlock(100, stim.Circuit('''\n                    X 0\n                    Y 1 2\n                '''))\n                >>> circuit[1::2]\n                stim.Circuit('''\n                    X_ERROR(0.5) 2\n                    TICK\n                    DETECTOR rec[-1]\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"detector_error_model\",\n        [](const Circuit &self,\n           bool decompose_errors,\n           bool flatten_loops,\n           bool allow_gauge_detectors,\n           double approximate_disjoint_errors,\n           bool ignore_decomposition_failures,\n           bool block_decomposition_from_introducing_remnant_edges) -> DetectorErrorModel {\n            return ErrorAnalyzer::circuit_to_detector_error_model(\n                self,\n                decompose_errors,\n                !flatten_loops,\n                allow_gauge_detectors,\n                approximate_disjoint_errors,\n                ignore_decomposition_failures,\n                block_decomposition_from_introducing_remnant_edges);\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"decompose_errors\") = false,\n        pybind11::arg(\"flatten_loops\") = false,\n        pybind11::arg(\"allow_gauge_detectors\") = false,\n        pybind11::arg(\"approximate_disjoint_errors\") = false,\n        pybind11::arg(\"ignore_decomposition_failures\") = false,\n        pybind11::arg(\"block_decomposition_from_introducing_remnant_edges\") = false,\n        clean_doc_string(R\"DOC(\n            Returns a stim.DetectorErrorModel describing the error processes in the circuit.\n\n            Args:\n                decompose_errors: Defaults to false. When set to true, the error analysis\n                    attempts to decompose the components of composite error mechanisms (such\n                    as depolarization errors) into simpler errors, and suggest this\n                    decomposition via `stim.target_separator()` between the components. For\n                    example, in an XZ surface code, single qubit depolarization has a Y\n                    error term which can be decomposed into simpler X and Z error terms.\n                    Decomposition fails (causing this method to throw) if it's not possible\n                    to decompose large errors into simple errors that affect at most two\n                    detectors.\n                flatten_loops: Defaults to false. When set to True, the output will not\n                    contain any `repeat` blocks. When set to False, the error analysis\n                    watches for loops in the circuit reaching a periodic steady state with\n                    respect to the detectors being introduced, the error mechanisms that\n                    affect them, and the locations of the logical observables. When it\n                    identifies such a steady state, it outputs a repeat block. This is\n                    massively more efficient than flattening for circuits that contain\n                    loops, but creates a more complex output.\n                allow_gauge_detectors: Defaults to false. When set to false, the error\n                    analysis verifies that detectors in the circuit are actually\n                    deterministic under noiseless execution of the circuit. When set to\n                    True, these detectors are instead considered to be part of degrees\n                    freedom that can be removed from the error model. For example, if\n                    detectors D1 and D3 both anti-commute with a reset, then the error model\n                    has a gauge `error(0.5) D1 D3`. When gauges are identified, one of the\n                    involved detectors is removed from the system using Gaussian\n                    elimination.\n\n                    Note that logical observables are still verified to be deterministic,\n                    even if this option is set.\n                approximate_disjoint_errors: Defaults to false. When set to false, composite\n                    error mechanisms with disjoint components (such as\n                    `PAULI_CHANNEL_1(0.1, 0.2, 0.0)`) can cause the error analysis to throw\n                    exceptions (because detector error models can only contain independent\n                    error mechanisms). When set to true, the probabilities of the disjoint\n                    cases are instead assumed to be independent probabilities. For example,\n                    a `PAULI_CHANNEL_1(0.1, 0.2, 0.0)` becomes equivalent to an\n                    `X_ERROR(0.1)` followed by a `Y_ERROR(0.2)`. This assumption is an\n                    approximation, but it is a good approximation for small probabilities.\n\n                    This argument can also be set to a probability between 0 and 1, setting\n                    a threshold below which the approximation is acceptable. Any error\n                    mechanisms that have a component probability above the threshold will\n                    cause an exception to be thrown.\n                ignore_decomposition_failures: Defaults to False.\n                    When this is set to True, circuit errors that fail to decompose into\n                    graphlike detector error model errors no longer cause the conversion\n                    process to abort. Instead, the undecomposed error is inserted into the\n                    output. Whatever tool the detector error model is then given to is\n                    responsible for dealing with the undecomposed errors (e.g. a tool may\n                    choose to simply ignore them).\n\n                    Irrelevant unless decompose_errors=True.\n                block_decomposition_from_introducing_remnant_edges: Defaults to False.\n                    Requires that both A B and C D be present elsewhere in the detector\n                    error model in order to decompose A B C D into A B ^ C D. Normally, only\n                    one of A B or C D needs to appear to allow this decomposition.\n\n                    Remnant edges can be a useful feature for ensuring decomposition\n                    succeeds, but they can also reduce the effective code distance by giving\n                    the decoder single edges that actually represent multiple errors in the\n                    circuit (resulting in the decoder making misinformed choices when\n                    decoding).\n\n                    Irrelevant unless decompose_errors=True.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     X_ERROR(0.125) 0\n                ...     X_ERROR(0.25) 1\n                ...     CORRELATED_ERROR(0.375) X0 X1\n                ...     M 0 1\n                ...     DETECTOR rec[-2]\n                ...     DETECTOR rec[-1]\n                ... ''').detector_error_model()\n                stim.DetectorErrorModel('''\n                    error(0.125) D0\n                    error(0.375) D0 D1\n                    error(0.25) D1\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"approx_equals\",\n        [](const Circuit &self, const pybind11::object &obj, double atol) -> bool {\n            try {\n                return self.approx_equals(pybind11::cast<Circuit>(obj), atol);\n            } catch (const pybind11::cast_error &) {\n                return false;\n            }\n        },\n        pybind11::arg(\"other\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"atol\"),\n        clean_doc_string(R\"DOC(\n            Checks if a circuit is approximately equal to another circuit.\n\n            Two circuits are approximately equal if they are equal up to slight\n            perturbations of instruction arguments such as probabilities. For example,\n            `X_ERROR(0.100) 0` is approximately equal to `X_ERROR(0.099)` within an absolute\n            tolerance of 0.002. All other details of the circuits (such as the ordering of\n            instructions and targets) must be exactly the same.\n\n            Args:\n                other: The circuit, or other object, to compare to this one.\n                atol: The absolute error tolerance. The maximum amount each probability may\n                    have been perturbed by.\n\n            Returns:\n                True if the given object is a circuit approximately equal up to the\n                receiving circuit up to the given tolerance, otherwise False.\n\n            Examples:\n                >>> import stim\n                >>> base = stim.Circuit('''\n                ...    X_ERROR(0.099) 0 1 2\n                ...    M 0 1 2\n                ... ''')\n\n                >>> base.approx_equals(base, atol=0)\n                True\n\n                >>> base.approx_equals(stim.Circuit('''\n                ...    X_ERROR(0.101) 0 1 2\n                ...    M 0 1 2\n                ... '''), atol=0)\n                False\n\n                >>> base.approx_equals(stim.Circuit('''\n                ...    X_ERROR(0.101) 0 1 2\n                ...    M 0 1 2\n                ... '''), atol=0.0001)\n                False\n\n                >>> base.approx_equals(stim.Circuit('''\n                ...    X_ERROR(0.101) 0 1 2\n                ...    M 0 1 2\n                ... '''), atol=0.01)\n                True\n\n                >>> base.approx_equals(stim.Circuit('''\n                ...    DEPOLARIZE1(0.099) 0 1 2\n                ...    MRX 0 1 2\n                ... '''), atol=9999)\n                False\n        )DOC\")\n            .data());\n\n    c.def(\n        \"get_detector_coordinates\",\n        [](const Circuit &self, const pybind11::object &obj) {\n            return self.get_detector_coordinates(obj_to_abs_detector_id_set(obj, [&]() {\n                return self.count_detectors();\n            }));\n        },\n        pybind11::arg(\"only\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            Returns the coordinate metadata of detectors in the circuit.\n\n            Args:\n                only: Defaults to None (meaning include all detectors). A list of detector\n                    indices to include in the result. Detector indices beyond the end of the\n                    detector error model of the circuit cause an error.\n\n            Returns:\n                A dictionary mapping integers (detector indices) to lists of floats\n                (coordinates).\n\n                Detectors with no specified coordinate data are mapped to an empty tuple.\n                If `only` is specified, then `set(result.keys()) == set(only)`.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...    M 0\n                ...    DETECTOR rec[-1]\n                ...    DETECTOR(1, 2, 3) rec[-1]\n                ...    REPEAT 3 {\n                ...        DETECTOR(42) rec[-1]\n                ...        SHIFT_COORDS(100)\n                ...    }\n                ... ''')\n                >>> circuit.get_detector_coordinates()\n                {0: [], 1: [1.0, 2.0, 3.0], 2: [42.0], 3: [142.0], 4: [242.0]}\n                >>> circuit.get_detector_coordinates(only=[1])\n                {1: [1.0, 2.0, 3.0]}\n        )DOC\")\n            .data());\n\n    c.def(\n        \"get_final_qubit_coordinates\",\n        &Circuit::get_final_qubit_coords,\n        clean_doc_string(R\"DOC(\n            Returns the coordinate metadata of qubits in the circuit.\n\n            If a qubit's coordinates are specified multiple times, only the last specified\n            coordinates are returned.\n\n            Returns:\n                A dictionary mapping qubit indices (integers) to coordinates (lists of\n                floats). Qubits that never had their coordinates specified are not included\n                in the result.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...    QUBIT_COORDS(1, 2, 3) 1\n                ... ''')\n                >>> circuit.get_final_qubit_coordinates()\n                {1: [1.0, 2.0, 3.0]}\n        )DOC\")\n            .data());\n\n    c.def(\n        pybind11::pickle(\n            [](const Circuit &self) -> pybind11::str {\n                return self.str();\n            },\n            [](const pybind11::str &text) {\n                return Circuit(pybind11::cast<std::string_view>(text));\n            }));\n\n    c.def(\n        \"shortest_graphlike_error\",\n        &circuit_shortest_graphlike_error,\n        pybind11::kw_only(),\n        pybind11::arg(\"ignore_ungraphlike_errors\") = true,\n        pybind11::arg(\"canonicalize_circuit_errors\") = false,\n        clean_doc_string(R\"DOC(\n            Finds a minimum set of graphlike errors to produce an undetected logical error.\n\n            A \"graphlike error\" is an error that creates at most two detection events\n            (causes a change in the parity of the measurement sets of at most two DETECTOR\n            annotations).\n\n            Note that this method does not pay attention to error probabilities (other than\n            ignoring errors with probability 0). It searches for a logical error with the\n            minimum *number* of physical errors, not the maximum probability of those\n            physical errors all occurring.\n\n            This method works by converting the circuit into a `stim.DetectorErrorModel`\n            using `circuit.detector_error_model(...)`, computing the shortest graphlike\n            error of the error model, and then converting the physical errors making up that\n            logical error back into representative circuit errors.\n\n            Args:\n                ignore_ungraphlike_errors:\n                    False: Attempt to decompose any ungraphlike errors in the circuit into\n                        graphlike parts. If this fails, raise an exception instead of\n                        continuing.\n\n                        Note: in some cases, graphlike errors only appear as parts of\n                        decomposed ungraphlike errors. This can produce a result that lists\n                        DEM errors with zero matching circuit errors, because the only way\n                        to achieve those errors is by combining a decomposed error with a\n                        graphlike error. As a result, when using this option it is NOT\n                        guaranteed that the length of the result is an upper bound on the\n                        true code distance. That is only the case if every item in the\n                        result lists at least one matching circuit error.\n                    True (default): Ungraphlike errors are simply skipped as if they weren't\n                        present, even if they could become graphlike if decomposed. This\n                        guarantees the length of the result is an upper bound on the true\n                        code distance.\n                canonicalize_circuit_errors: Whether or not to use one representative for\n                    equal-symptom circuit errors.\n\n                    False (default): Each DEM error lists every possible circuit error that\n                        single handedly produces those symptoms as a potential match. This\n                        is verbose but gives complete information.\n                    True: Each DEM error is matched with one possible circuit error that\n                        single handedly produces those symptoms, with a preference towards\n                        errors that are simpler (e.g. apply Paulis to fewer qubits). This\n                        discards mostly-redundant information about different ways to\n                        produce the same symptoms in order to give a succinct result.\n\n            Returns:\n                A list of error mechanisms that cause an undetected logical error.\n\n                Each entry in the list is a `stim.ExplainedError` detailing the location\n                and effects of a single physical error. The effects of the entire list\n                combine to produce a logical frame change without any detection events.\n\n            Examples:\n                >>> import stim\n\n                >>> circuit = stim.Circuit.generated(\n                ...     \"repetition_code:memory\",\n                ...     rounds=10,\n                ...     distance=7,\n                ...     before_round_data_depolarization=0.01)\n                >>> len(circuit.shortest_graphlike_error())\n                7\n        )DOC\")\n            .data());\n\n    c.def(\n        \"search_for_undetectable_logical_errors\",\n        &py_find_undetectable_logical_error,\n        pybind11::kw_only(),\n        pybind11::arg(\"dont_explore_detection_event_sets_with_size_above\"),\n        pybind11::arg(\"dont_explore_edges_with_degree_above\"),\n        pybind11::arg(\"dont_explore_edges_increasing_symptom_degree\"),\n        pybind11::arg(\"canonicalize_circuit_errors\") = false,\n        clean_doc_string(R\"DOC(\n            Searches for small sets of errors that form an undetectable logical error.\n\n            THIS IS A HEURISTIC METHOD. It does not guarantee that it will find errors of\n            particular sizes, or with particular properties. The errors it finds are a\n            tangled combination of the truncation parameters you specify, internal\n            optimizations which are correct when not truncating, and minutia of the circuit\n            being considered.\n\n            If you want a well behaved method that does provide guarantees of finding errors\n            of a particular type, use `stim.Circuit.shortest_graphlike_error`. This method\n            is more thorough than that (assuming you don't truncate so hard you omit\n            graphlike edges), but exactly how thorough is difficult to describe. It's also\n            not guaranteed that the behavior of this method will not be changed in the\n            future in a way that permutes which logical errors are found and which are\n            missed.\n\n            This search method considers hyper errors, so it has worst case exponential\n            runtime. It is important to carefully consider the arguments you are providing,\n            which truncate the search space and trade cost for quality.\n\n            The search progresses by starting from each error that crosses a logical\n            observable, noting which detection events each error produces, and then\n            iteratively adding in errors touching those detection events attempting to\n            cancel out the detection event with the lowest index.\n\n            Beware that the choice of logical observable can interact with the truncation\n            options. Using different observables can change whether or not the search\n            succeeds, even if those observables are equal modulo the stabilizers of the\n            code. This is because the edges crossing logical observables are used as\n            starting points for the search, and starting from different places along a path\n            will result in different numbers of symptoms in intermediate states as the\n            search progresses. For example, if the logical observable is next to a boundary,\n            then the starting edges are likely boundary edges (degree 1) with 'room to\n            grow', whereas if the observable was running through the bulk then the starting\n            edges will have degree at least 2.\n\n            Args:\n                dont_explore_detection_event_sets_with_size_above: Truncates the search\n                    space by refusing to cross an edge (i.e. add an error) when doing so\n                    would produce an intermediate state that has more detection events than\n                    this limit.\n                dont_explore_edges_with_degree_above: Truncates the search space by refusing\n                    to consider errors that cause a lot of detection events. For example,\n                    you may only want to consider graphlike errors which have two or fewer\n                    detection events.\n                dont_explore_edges_increasing_symptom_degree: Truncates the search space by\n                    refusing to cross an edge (i.e. add an error) when doing so would\n                    produce an intermediate state that has more detection events that the\n                    previous intermediate state. This massively improves the efficiency of\n                    the search because instead of, for example, exploring all n^4 possible\n                    detection event sets with 4 symptoms, the search will attempt to cancel\n                    out symptoms one by one.\n                canonicalize_circuit_errors: Whether or not to use one representative for\n                    equal-symptom circuit errors.\n\n                    False (default): Each DEM error lists every possible circuit error that\n                        single handedly produces those symptoms as a potential match. This\n                        is verbose but gives complete information.\n                    True: Each DEM error is matched with one possible circuit error that\n                        single handedly produces those symptoms, with a preference towards\n                        errors that are simpler (e.g. apply Paulis to fewer qubits). This\n                        discards mostly-redundant information about different ways to\n                        produce the same symptoms in order to give a succinct result.\n\n            Returns:\n                A list of error mechanisms that cause an undetected logical error.\n\n                Each entry in the list is a `stim.ExplainedError` detailing the location\n                and effects of a single physical error. The effects of the entire list\n                combine to produce a logical frame change without any detection events.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit.generated(\n                ...     \"surface_code:rotated_memory_x\",\n                ...     rounds=5,\n                ...     distance=5,\n                ...     after_clifford_depolarization=0.001)\n                >>> print(len(circuit.search_for_undetectable_logical_errors(\n                ...     dont_explore_detection_event_sets_with_size_above=4,\n                ...     dont_explore_edges_with_degree_above=4,\n                ...     dont_explore_edges_increasing_symptom_degree=True,\n                ... )))\n                5\n        )DOC\")\n            .data());\n\n    c.def(\n        \"shortest_error_sat_problem\",\n        &py_shortest_error_sat_problem,\n        pybind11::kw_only(),\n        pybind11::arg(\"format\") = \"WDIMACS\",\n        clean_doc_string(R\"DOC(\n            Makes a maxSAT problem of the circuit's distance, that other tools can solve.\n\n            The output is a string describing the maxSAT problem in WDIMACS format\n            (see https://jix.github.io/varisat/manual/0.2.0/formats/dimacs.html). The\n            optimal solution to the problem is the fault distance of the circuit (the\n            minimum number of error mechanisms that combine to flip any logical observable\n            while producing no detection events). This method ignores the probabilities of\n            the error mechanisms since it only cares about minimizing the number of errors\n            triggered.\n\n            There are many tools that can solve maxSAT problems in WDIMACS format.\n            One quick way to get started is to install pysat by running this BASH\n            terminal command:\n\n                pip install python-sat\n\n            Afterwards, you can run the included maxSAT solver \"RC2\" with this\n            Python code:\n\n                from pysat.examples.rc2 import RC2\n                from pysat.formula import WCNF\n\n                wcnf = WCNF(from_string=\"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\")\n\n                with RC2(wcnf) as rc2:\n                print(rc2.compute())\n                print(rc2.cost)\n\n            Much faster solvers are available online. For example, you can download\n            one of the entries in the 2023 maxSAT competition (see\n            https://maxsat-evaluations.github.io/2023) and run it on your problem by\n            running these BASH terminal commands:\n\n                wget https://maxsat-evaluations.github.io/2023/mse23-solver-src/exact/CASHWMaxSAT-CorePlus.zip\n                unzip CASHWMaxSAT-CorePlus.zip\n                ./CASHWMaxSAT-CorePlus/bin/cashwmaxsatcoreplus -bm -m your_problem.wcnf\n\n            Args:\n                format: Defaults to \"WDIMACS\", corresponding to WDIMACS format which is\n                    described here: http://www.maxhs.org/docs/wdimacs.html\n\n            Returns:\n                A string corresponding to the contents of a maxSAT problem file in the\n                requested format.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...   X_ERROR(0.1) 0\n                ...   M 0\n                ...   OBSERVABLE_INCLUDE(0) rec[-1]\n                ...   X_ERROR(0.4) 0\n                ...   M 0\n                ...   DETECTOR rec[-1] rec[-2]\n                ... ''')\n                >>> print(circuit.shortest_error_sat_problem(), end='')\n                p wcnf 2 4 5\n                1 -1 0\n                1 -2 0\n                5 -1 0\n                5 2 0\n        )DOC\")\n            .data());\n\n    c.def(\n        \"likeliest_error_sat_problem\",\n        &py_likeliest_error_sat_problem,\n        pybind11::kw_only(),\n        pybind11::arg(\"quantization\") = 100,\n        pybind11::arg(\"format\") = \"WDIMACS\",\n        clean_doc_string(R\"DOC(\n            Makes a maxSAT problem for the circuit's likeliest undetectable logical error.\n\n            The output is a string describing the maxSAT problem in WDIMACS format\n            (see https://jix.github.io/varisat/manual/0.2.0/formats/dimacs.html). The\n            optimal solution to the problem is the highest likelihood set of error\n            mechanisms that combine to flip any logical observable while producing no\n            detection events).\n\n            If there are any errors with probability p > 0.5, they are inverted so\n            that the resulting weight ends up being positive. If there are errors\n            with weight close or equal to 0.5, they can end up with 0 weight meaning\n            that they can be included or not in the solution with no affect on the\n            likelihood.\n\n            There are many tools that can solve maxSAT problems in WDIMACS format.\n            One quick way to get started is to install pysat by running this BASH\n            terminal command:\n\n                pip install python-sat\n\n            Afterwards, you can run the included maxSAT solver \"RC2\" with this\n            Python code:\n\n                from pysat.examples.rc2 import RC2\n                from pysat.formula import WCNF\n\n                wcnf = WCNF(from_string=\"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\")\n\n                with RC2(wcnf) as rc2:\n                print(rc2.compute())\n                print(rc2.cost)\n\n            Much faster solvers are available online. For example, you can download\n            one of the entries in the 2023 maxSAT competition (see\n            https://maxsat-evaluations.github.io/2023) and run it on your problem by\n            running these BASH terminal commands:\n\n                wget https://maxsat-evaluations.github.io/2023/mse23-solver-src/exact/CASHWMaxSAT-CorePlus.zip\n                unzip CASHWMaxSAT-CorePlus.zip\n                ./CASHWMaxSAT-CorePlus/bin/cashwmaxsatcoreplus -bm -m your_problem.wcnf\n\n            Args:\n                format: Defaults to \"WDIMACS\", corresponding to WDIMACS format which is\n                    described here: http://www.maxhs.org/docs/wdimacs.html\n                quantization: Defaults to 10. Error probabilities are converted to log-odds\n                    and scaled/rounded to be positive integers at most this large. Setting\n                    this argument to a larger number results in more accurate quantization\n                    such that the returned error set should have a likelihood closer to the\n                    true most likely solution. This comes at the cost of making some maxSAT\n                    solvers slower.\n\n            Returns:\n                A string corresponding to the contents of a maxSAT problem file in the\n                requested format.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...   X_ERROR(0.1) 0\n                ...   M 0\n                ...   OBSERVABLE_INCLUDE(0) rec[-1]\n                ...   X_ERROR(0.4) 0\n                ...   M 0\n                ...   DETECTOR rec[-1] rec[-2]\n                ... ''')\n                >>> print(circuit.likeliest_error_sat_problem(\n                ...   quantization=1000\n                ... ), end='')\n                p wcnf 2 4 4001\n                185 -1 0\n                1000 -2 0\n                4001 -1 0\n                4001 2 0\n        )DOC\")\n            .data());\n\n    c.def(\n        \"explain_detector_error_model_errors\",\n        [](const Circuit &self,\n           const pybind11::object &dem_filter,\n           bool reduce_to_one_representative_error) -> std::vector<ExplainedError> {\n            if (dem_filter.is_none()) {\n                return ErrorMatcher::explain_errors_from_circuit(self, nullptr, reduce_to_one_representative_error);\n            } else {\n                const DetectorErrorModel &model = dem_filter.cast<const DetectorErrorModel &>();\n                return ErrorMatcher::explain_errors_from_circuit(self, &model, reduce_to_one_representative_error);\n            }\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"dem_filter\") = pybind11::none(),\n        pybind11::arg(\"reduce_to_one_representative_error\") = false,\n        clean_doc_string(R\"DOC(\n            Explains how detector error model errors are produced by circuit errors.\n\n            Args:\n                dem_filter: Defaults to None (unused). When used, the output will only\n                    contain detector error model errors that appear in the given\n                    `stim.DetectorErrorModel`. Any error mechanisms from the detector error\n                    model that can't be reproduced using one error from the circuit will\n                    also be included in the result, but with an empty list of associated\n                    circuit error mechanisms.\n                reduce_to_one_representative_error: Defaults to False. When True, the items\n                    in the result will contain at most one circuit error mechanism.\n\n            Returns:\n                A `List[stim.ExplainedError]` (see `stim.ExplainedError` for more\n                information). Each item in the list describes how a detector error model\n                error can be produced by individual circuit errors.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     # Create Bell pair.\n                ...     H 0\n                ...     CNOT 0 1\n                ...\n                ...     # Noise.\n                ...     DEPOLARIZE1(0.01) 0\n                ...\n                ...     # Bell basis measurement.\n                ...     CNOT 0 1\n                ...     H 0\n                ...     M 0 1\n                ...\n                ...     # Both measurements should be False under noiseless execution.\n                ...     DETECTOR rec[-1]\n                ...     DETECTOR rec[-2]\n                ... ''')\n                >>> explained_errors = circuit.explain_detector_error_model_errors(\n                ...     dem_filter=stim.DetectorErrorModel('error(1) D0 D1'),\n                ...     reduce_to_one_representative_error=True,\n                ... )\n                >>> print(explained_errors[0].circuit_error_locations[0])\n                CircuitErrorLocation {\n                    flipped_pauli_product: Y0\n                    Circuit location stack trace:\n                        (after 0 TICKs)\n                        at instruction #3 (DEPOLARIZE1) in the circuit\n                        at target #1 of the instruction\n                        resolving to DEPOLARIZE1(0.01) 0\n                }\n        )DOC\")\n            .data());\n\n    c.def(\n        \"without_noise\",\n        &Circuit::without_noise,\n        clean_doc_string(R\"DOC(\n            Returns a copy of the circuit with all noise processes removed.\n\n            Pure noise instructions, such as X_ERROR and DEPOLARIZE2, are not\n            included in the result.\n\n            Noisy measurement instructions, like `M(0.001)`, have their noise\n            parameter removed.\n\n            Returns:\n                A `stim.Circuit` with the same instructions except all noise\n                processes have been removed.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...     X_ERROR(0.25) 0\n                ...     CNOT 0 1\n                ...     M(0.125) 0\n                ... ''').without_noise()\n                stim.Circuit('''\n                    CX 0 1\n                    M 0\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"without_tags\",\n        &Circuit::without_tags,\n        clean_doc_string(R\"DOC(\n            Returns a copy of the circuit with all tags removed.\n\n            Returns:\n                A `stim.Circuit` with the same instructions except all tags have been\n                removed.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...     X[test-tag] 0\n                ...     M[test-tag-2](0.125) 0\n                ... ''').without_tags()\n                stim.Circuit('''\n                    X 0\n                    M(0.125) 0\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"flattened\",\n        &Circuit::flattened,\n        clean_doc_string(R\"DOC(\n            Creates an equivalent circuit without REPEAT or SHIFT_COORDS.\n\n            Returns:\n                A `stim.Circuit` with the same instructions in the same order,\n                but with loops flattened into repeated instructions and with\n                all coordinate shifts inlined.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...     REPEAT 5 {\n                ...         MR 0 1\n                ...         DETECTOR(0, 0) rec[-2]\n                ...         DETECTOR(1, 0) rec[-1]\n                ...         SHIFT_COORDS(0, 1)\n                ...     }\n                ... ''').flattened()\n                stim.Circuit('''\n                    MR 0 1\n                    DETECTOR(0, 0) rec[-2]\n                    DETECTOR(1, 0) rec[-1]\n                    MR 0 1\n                    DETECTOR(0, 1) rec[-2]\n                    DETECTOR(1, 1) rec[-1]\n                    MR 0 1\n                    DETECTOR(0, 2) rec[-2]\n                    DETECTOR(1, 2) rec[-1]\n                    MR 0 1\n                    DETECTOR(0, 3) rec[-2]\n                    DETECTOR(1, 3) rec[-1]\n                    MR 0 1\n                    DETECTOR(0, 4) rec[-2]\n                    DETECTOR(1, 4) rec[-1]\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"inverse\",\n        [](const Circuit &self) -> Circuit {\n            return self.inverse();\n        },\n        clean_doc_string(R\"DOC(\n            Returns a circuit that applies the same operations but inverted and in reverse.\n\n            If circuit starts with QUBIT_COORDS instructions, the returned circuit will\n            still have the same QUBIT_COORDS instructions in the same order at the start.\n\n            Returns:\n                A `stim.Circuit` that applies inverted operations in the reverse order.\n\n            Raises:\n                ValueError: The circuit contains operations that don't have an inverse,\n                    such as measurements. There are also some unsupported operations\n                    such as SHIFT_COORDS.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     S 0 1\n                ...     ISWAP 0 1 1 2\n                ... ''').inverse()\n                stim.Circuit('''\n                    ISWAP_DAG 1 2 0 1\n                    S_DAG 1 0\n                ''')\n\n                >>> stim.Circuit('''\n                ...     QUBIT_COORDS(1, 2) 0\n                ...     QUBIT_COORDS(4, 3) 1\n                ...     QUBIT_COORDS(9, 5) 2\n                ...     H 0 1\n                ...     REPEAT 100 {\n                ...         CX 0 1 1 2\n                ...         TICK\n                ...         S 1 2\n                ...     }\n                ... ''').inverse()\n                stim.Circuit('''\n                    QUBIT_COORDS(1, 2) 0\n                    QUBIT_COORDS(4, 3) 1\n                    QUBIT_COORDS(9, 5) 2\n                    REPEAT 100 {\n                        S_DAG 2 1\n                        TICK\n                        CX 1 2 0 1\n                    }\n                    H 1 0\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"diagram\",\n        &circuit_diagram,\n        pybind11::arg(\"type\") = \"timeline-text\",\n        pybind11::kw_only(),\n        pybind11::arg(\"tick\") = pybind11::none(),\n        pybind11::arg(\"rows\") = pybind11::none(),\n        pybind11::arg(\"filter_coords\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def diagram(self, type: Literal[\"timeline-text\", \"timeline-svg\", \"timeline-svg-html\", \"timeline-3d\", \"timeline-3d-html\", \"detslice-text\", \"detslice-svg\", \"detslice-svg-html\", \"matchgraph-svg\", \"matchgraph-svg-html\", \"matchgraph-3d\", \"matchgraph-3d-html\", \"timeslice-svg\", \"timeslice-svg-html\", \"detslice-with-ops-svg\", \"detslice-with-ops-svg-html\", \"interactive\", \"interactive-html\"] = 'timeline-text', *, tick: Union[None, int, range] = None, filter_coords: Iterable[Union[Iterable[float], stim.DemTarget]] = ((),), rows: int | None = None) -> 'stim._DiagramHelper':\n            Returns a diagram of the circuit, from a variety of options.\n\n            Args:\n                type: The type of diagram. Available types are:\n                    \"timeline-text\" (default): An ASCII diagram of the\n                        operations applied by the circuit over time. Includes\n                        annotations showing the measurement record index that\n                        each measurement writes to, and the measurements used\n                        by detectors.\n                    \"timeline-svg\": An SVG image of the operations applied by\n                        the circuit over time. Includes annotations showing the\n                        measurement record index that each measurement writes\n                        to, and the measurements used by detectors.\n                    \"timeline-svg-html\": A resizable SVG image viewer of the\n                        operations applied by the circuit over time. Includes\n                        annotations showing the measurement record index that\n                        each measurement writes to, and the measurements used\n                        by detectors.\n                    \"timeline-3d\": A 3d model, in GLTF format, of the operations\n                        applied by the circuit over time.\n                    \"timeline-3d-html\": Same 3d model as 'timeline-3d' but\n                        embedded into an HTML web page containing an interactive\n                        THREE.js viewer for the 3d model.\n                    \"detslice-text\": An ASCII diagram of the stabilizers\n                        that detectors declared by the circuit correspond to\n                        during the TICK instruction identified by the `tick`\n                        argument.\n                    \"detslice-svg\": An SVG image of the stabilizers\n                        that detectors declared by the circuit correspond to\n                        during the TICK instruction identified by the `tick`\n                        argument. For example, a detector slice diagram of a\n                        CSS surface code circuit during the TICK between a\n                        measurement layer and a reset layer will produce the\n                        usual diagram of a surface code.\n\n                        Uses the Pauli color convention XYZ=RGB.\n                    \"detslice-svg-html\": Same as detslice-svg but the SVG image\n                        is inside a resizable HTML iframe.\n                    \"matchgraph-svg\": An SVG image of the match graph extracted\n                        from the circuit by stim.Circuit.detector_error_model.\n                    \"matchgraph-svg-html\": Same as matchgraph-svg but the SVG image\n                        is inside a resizable HTML iframe.\n                    \"matchgraph-3d\": An 3D model of the match graph extracted\n                        from the circuit by stim.Circuit.detector_error_model.\n                    \"matchgraph-3d-html\": Same 3d model as 'match-graph-3d' but\n                        embedded into an HTML web page containing an interactive\n                        THREE.js viewer for the 3d model.\n                    \"timeslice-svg\": An SVG image of the operations applied\n                        between two TICK instructions in the circuit, with the\n                        operations laid out in 2d.\n                    \"timeslice-svg-html\": Same as timeslice-svg but the SVG image\n                        is inside a resizable HTML iframe.\n                    \"detslice-with-ops-svg\": A combination of timeslice-svg\n                        and detslice-svg, with the operations overlaid\n                        over the detector slices taken from the TICK after the\n                        operations were applied.\n                    \"detslice-with-ops-svg-html\": Same as detslice-with-ops-svg\n                        but the SVG image is inside a resizable HTML iframe.\n                    \"interactive\" or \"interactive-html\": An HTML web page\n                        containing Crumble (an interactive editor for 2D\n                        stabilizer circuits) initialized with the given circuit\n                        as its default contents.\n                tick: Required for detector and time slice diagrams. Specifies\n                    which TICK instruction, or range of TICK instructions, to\n                    slice at. Note that the first TICK instruction in the\n                    circuit corresponds tick=1. The value tick=0 refers to the\n                    very start of the circuit.\n\n                    Passing `range(A, B)` for a detector slice will show the\n                    slices for ticks A through B including A but excluding B.\n\n                    Passing `range(A, B)` for a time slice will show the\n                    operations between tick A and tick B.\n                rows: In diagrams that have multiple separate pieces, such as timeslice\n                    diagrams and detslice diagrams, this controls how many rows of\n                    pieces there will be. If not specified, a number of rows that creates\n                    a roughly square layout will be chosen.\n                filter_coords: A list of things to include in the diagram. Different\n                    effects depending on the diagram.\n\n                    For detslice diagrams, the filter defaults to showing all detectors\n                    and no observables. When specified, each list entry can be a collection\n                    of floats (detectors whose coordinates start with the same numbers will\n                    be included), a stim.DemTarget (specifying a detector or observable\n                    to include), a string like \"D5\" or \"L0\" specifying a detector or\n                    observable to include.\n\n            Returns:\n                An object whose `__str__` method returns the diagram, so that\n                writing the diagram to a file works correctly. The returned\n                object may also define methods such as `_repr_html_`, so that\n                ipython notebooks recognize it can be shown using a specialized\n                viewer instead of as raw text.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     H 0\n                ...     CNOT 0 1 1 2\n                ... ''')\n\n                >>> print(circuit.diagram())\n                q0: -H-@---\n                       |\n                q1: ---X-@-\n                         |\n                q2: -----X-\n\n                >>> circuit = stim.Circuit('''\n                ...     H 0\n                ...     CNOT 0 1\n                ...     TICK\n                ...     M 0 1\n                ...     DETECTOR rec[-1] rec[-2]\n                ... ''')\n\n                >>> print(circuit.diagram(\"detslice-text\", tick=1))\n                q0: -Z:D0-\n                     |\n                q1: -Z:D0-\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_CIRCUIT_CIRCUIT_PYBIND_H\n#define _STIM_CIRCUIT_CIRCUIT_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::Circuit> pybind_circuit(pybind11::module &m);\nvoid pybind_circuit_methods(pybind11::module &m, pybind11::class_<stim::Circuit> &c);\nvoid pybind_circuit_methods_extra(pybind11::module &m, pybind11::class_<stim::Circuit> &c);\n\n}  // namespace stim_pybind\n\nstd::set<uint64_t> obj_to_abs_detector_id_set(\n    const pybind11::object &obj, const std::function<size_t(void)> &get_num_detectors);\nstd::string circuit_repr(const stim::Circuit &self);\n\n#endif\n"
  },
  {
    "path": "src/stim/circuit/circuit.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/circuit.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n\nusing namespace stim;\n\nTEST(circuit, from_text) {\n    Circuit expected;\n    const auto &f = [](const char *c) {\n        return Circuit(c);\n    };\n    ASSERT_EQ(f(\"# not an operation\"), expected);\n\n    expected.clear();\n    expected.safe_append_u(\"H\", {0});\n    ASSERT_EQ(f(\"H 0\"), expected);\n    ASSERT_EQ(f(\"h 0\"), expected);\n    ASSERT_EQ(f(\"H 0     \"), expected);\n    ASSERT_EQ(f(\"     H 0     \"), expected);\n    ASSERT_EQ(f(\"\\tH 0\\t\\t\"), expected);\n    ASSERT_EQ(f(\"H 0  # comment\"), expected);\n\n    expected.clear();\n    expected.safe_append_u(\"H\", {23});\n    ASSERT_EQ(f(\"H 23\"), expected);\n\n    expected.clear();\n    expected.safe_append_ua(\"DEPOLARIZE1\", {4, 5}, 0.125);\n    ASSERT_EQ(f(\"DEPOLARIZE1(0.125) 4 5  # comment\"), expected);\n\n    expected.clear();\n    expected.safe_append_u(\"ZCX\", {5, 6});\n    ASSERT_EQ(f(\"  \\t Cnot 5 6  # comment   \"), expected);\n\n    ASSERT_THROW({ f(\"H a\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"H(1)\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"X_ERROR 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"H 9999999999999999999999999999999999999999999\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"H -1\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CNOT 0 a\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CNOT 0 99999999999999999999999999999999\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CNOT 0 -1\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"DETECTOR 1 2\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CX 1 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"SWAP 1 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"DEPOLARIZE2(1) 1 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"DETEstdCTOR rec[-1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"DETECTOR rec[0]\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"DETECTOR rec[1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"DETECTOR rec[-999999999999]\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"OBSERVABLE_INCLUDE rec[-1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"OBSERVABLE_INCLUDE(-1) rec[-1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CORRELATED_ERROR(1) B1\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CORRELATED_ERROR(1) X 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CORRELATED_ERROR(1) X\\n\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CORRELATED_ERROR(1) 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"ELSE_CORRELATED_ERROR(1) 1 2\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CORRELATED_ERROR(1) 1 2\"); }, std::invalid_argument);\n    ASSERT_THROW({ f(\"CORRELATED_ERROR(1) A\"); }, std::invalid_argument);\n\n    ASSERT_THROW({ f(\"CNOT 0\\nCNOT 1\"); }, std::invalid_argument);\n\n    expected.clear();\n    ASSERT_EQ(f(\"\"), expected);\n    ASSERT_EQ(f(\"# Comment\\n\\n\\n# More\"), expected);\n\n    expected.clear();\n    expected.safe_append_u(\"H_XZ\", {0});\n    ASSERT_EQ(f(\"H 0\"), expected);\n\n    expected.clear();\n    expected.safe_append_u(\"H_XZ\", {0, 1});\n    ASSERT_EQ(f(\"H 0 \\n H 1\"), expected);\n\n    expected.clear();\n    expected.safe_append_u(\"H_XZ\", {1});\n    ASSERT_EQ(f(\"H 1\"), expected);\n\n    expected.clear();\n    expected.safe_append_u(\"H\", {0});\n    expected.safe_append_u(\"ZCX\", {0, 1});\n    ASSERT_EQ(\n        f(\"# EPR\\n\"\n          \"H 0\\n\"\n          \"CNOT 0 1\"),\n        expected);\n\n    expected.clear();\n    expected.safe_append_u(\"M\", {0, 0 | TARGET_INVERTED_BIT, 1, 1 | TARGET_INVERTED_BIT});\n    ASSERT_EQ(f(\"M 0 !0 1 !1\"), expected);\n\n    // Measurement fusion.\n    expected.clear();\n    expected.safe_append_u(\"H\", {0});\n    expected.safe_append_u(\"M\", {0, 1, 2});\n    expected.safe_append_u(\"SWAP\", {0, 1});\n    expected.safe_append_u(\"M\", {0, 10});\n    ASSERT_EQ(\n        f(R\"CIRCUIT(\n            H 0\n            M 0\n            M 1\n            M 2\n            SWAP 0 1\n            M 0\n            M 10\n        )CIRCUIT\"),\n        expected);\n\n    expected.clear();\n    expected.safe_append_u(\"X\", {0});\n    expected += Circuit(\"Y 1 2\") * 2;\n    ASSERT_EQ(\n        f(R\"CIRCUIT(\n            X 0\n            REPEAT 2 {\n              Y 1\n              Y 2 #####\"\n            } #####\"\n        )CIRCUIT\"),\n        expected);\n\n    expected.clear();\n    expected.safe_append_u(\"DETECTOR\", {5 | TARGET_RECORD_BIT});\n    ASSERT_EQ(f(\"DETECTOR rec[-5]\"), expected);\n    expected.clear();\n    expected.safe_append_u(\"DETECTOR\", {6 | TARGET_RECORD_BIT});\n    ASSERT_EQ(f(\"DETECTOR rec[-6]\"), expected);\n\n    Circuit parsed =\n        f(\"M 0\\n\"\n          \"REPEAT 5 {\\n\"\n          \"  M 1 2\\n\"\n          \"  M 3\\n\"\n          \"} #####\");\n    ASSERT_EQ(parsed.operations.size(), 2);\n    ASSERT_EQ(parsed.blocks.size(), 1);\n    ASSERT_EQ(parsed.blocks[0].operations.size(), 1);\n    ASSERT_EQ(parsed.blocks[0].operations[0].targets.size(), 3);\n\n    expected.clear();\n    expected.safe_append_ua(\n        \"CORRELATED_ERROR\",\n        {90 | TARGET_PAULI_X_BIT,\n         91 | TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT,\n         92 | TARGET_PAULI_Z_BIT,\n         93 | TARGET_PAULI_X_BIT},\n        0.125);\n    ASSERT_EQ(\n        f(R\"circuit(\n            CORRELATED_ERROR(0.125) X90 Y91 Z92 X93\n          )circuit\"),\n        expected);\n}\n\nTEST(circuit, parse_mpp) {\n    ASSERT_THROW({ Circuit(\"H *\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP 0\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP *\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP * X1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP * X1 *\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP X1 *\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP X1 * * Y2\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP X1**Y2\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP(1.1) X1**Y2\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP(-0.5) X1**Y2\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP X1*rec[-1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP rec[-1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP sweep[0]\"); }, std::invalid_argument);\n    auto c = Circuit(\"MPP X1*Y2 Z3 * Z4\\nMPP Z5\");\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.operations[0].args.size(), 0);\n    ASSERT_EQ(c.operations[0].targets.size(), 7);\n    std::vector<GateTarget> expected{\n        GateTarget::x(1),\n        GateTarget::combiner(),\n        GateTarget::y(2),\n        GateTarget::z(3),\n        GateTarget::combiner(),\n        GateTarget::z(4),\n        GateTarget::z(5),\n    };\n    ASSERT_EQ(c.operations[0].targets, (SpanRef<GateTarget>)expected);\n\n    c = Circuit(\"MPP(0.125) X1*Y2 Z3 * Z4\\nMPP Z5\");\n    ASSERT_EQ(c.operations[0].args.size(), 1);\n    ASSERT_EQ(c.operations[0].args[0], 0.125);\n\n    c = Circuit(\"MPP X1*X1\");\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.operations[0].targets.size(), 3);\n}\n\nTEST(circuit, parse_spp) {\n    ASSERT_THROW({ Circuit(\"SPP 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"SPP rec[-1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"SPP sweep[0]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"SPP rec[-1]*X0\"); }, std::invalid_argument);\n\n    Circuit c;\n\n    c = Circuit(\"SPP\");\n    ASSERT_EQ(c.operations.size(), 1);\n\n    c = Circuit(\"SPP X0 X1*Y2*Z3\");\n    ASSERT_EQ(c.operations.size(), 1);\n\n    c = Circuit(\"SPP X1 Z2\");\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.operations[0].targets.size(), 2);\n    ASSERT_EQ(\n        c.operations[0].targets,\n        ((SpanRef<const GateTarget>)std::vector<GateTarget>{GateTarget::x(1), GateTarget::z(2)}));\n}\n\nTEST(circuit, parse_spp_dag) {\n    ASSERT_THROW({ Circuit(\"SPP_DAG 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"SPP_DAG rec[-1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"SPP_DAG sweep[0]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"SPP_DAG rec[-1]*X0\"); }, std::invalid_argument);\n\n    Circuit c;\n\n    c = Circuit(\"SPP_DAG\");\n    ASSERT_EQ(c.operations.size(), 1);\n\n    c = Circuit(\"SPP_DAG X0 X1*Y2*Z3\");\n    ASSERT_EQ(c.operations.size(), 1);\n\n    c = Circuit(\"SPP_DAG X1 Z2\");\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.operations[0].targets.size(), 2);\n    ASSERT_EQ(\n        c.operations[0].targets,\n        ((SpanRef<const GateTarget>)std::vector<GateTarget>{GateTarget::x(1), GateTarget::z(2)}));\n}\n\nTEST(circuit, parse_tag) {\n    Circuit c;\n\n    c = Circuit(\"H[test] 3 5\");\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.operations[0].gate_type, GateType::H);\n    ASSERT_EQ(c.operations[0].tag, \"test\");\n    ASSERT_EQ(c.operations[0].targets.size(), 2);\n    ASSERT_EQ(c.operations[0].targets[0], GateTarget::qubit(3));\n    ASSERT_EQ(c.operations[0].targets[1], GateTarget::qubit(5));\n\n    c = Circuit(\"H[] 3 5\");\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.operations[0].gate_type, GateType::H);\n    ASSERT_EQ(c.operations[0].tag, \"\");\n    ASSERT_EQ(c.operations[0].targets.size(), 2);\n\n    c = Circuit(\"H 3 5\");\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.operations[0].gate_type, GateType::H);\n    ASSERT_EQ(c.operations[0].tag, \"\");\n    ASSERT_EQ(c.operations[0].targets.size(), 2);\n\n    c = Circuit(\"H[test \\\\B\\\\C\\\\r\\\\n] 3 5\");\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.operations[0].gate_type, GateType::H);\n    ASSERT_EQ(c.operations[0].tag, \"test \\\\]\\r\\n\");\n    ASSERT_EQ(c.operations[0].targets.size(), 2);\n    ASSERT_EQ(c.operations[0].str(), \"H[test \\\\B\\\\C\\\\r\\\\n] 3 5\");\n\n    c = Circuit(R\"CIRCUIT(\n        X_ERROR[test](0.125)\n        X_ERROR[no_fuse](0.125) 1\n        X_ERROR(0.125) 2\n        X_ERROR[](0.125) 3\n        REPEAT[looper] 5 {\n            CX[within] 0 1\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.operations.size(), 4);\n    ASSERT_EQ(c.operations[0].gate_type, GateType::X_ERROR);\n    ASSERT_EQ(c.operations[1].gate_type, GateType::X_ERROR);\n    ASSERT_EQ(c.operations[2].gate_type, GateType::X_ERROR);\n    ASSERT_EQ(c.operations[0].tag, \"test\");\n    ASSERT_EQ(c.operations[1].tag, \"no_fuse\");\n    ASSERT_EQ(c.operations[2].tag, \"\");\n    ASSERT_EQ(c.operations[0].targets.size(), 0);\n    ASSERT_EQ(c.operations[1].targets.size(), 1);\n    ASSERT_EQ(c.operations[2].targets.size(), 2);\n    ASSERT_EQ(c.operations[1].targets[0], GateTarget::qubit(1));\n    ASSERT_EQ(c.operations[2].targets[0], GateTarget::qubit(2));\n    ASSERT_EQ(c.operations[2].targets[1], GateTarget::qubit(3));\n    ASSERT_EQ(c.operations[3].gate_type, GateType::REPEAT);\n    ASSERT_EQ(c.operations[3].tag, \"looper\");\n    ASSERT_EQ(c.operations[3].repeat_block_rep_count(), 5);\n    ASSERT_EQ(c.str(), R\"CIRCUIT(X_ERROR[test](0.125)\nX_ERROR[no_fuse](0.125) 1\nX_ERROR(0.125) 2 3\nREPEAT[looper] 5 {\n    CX[within] 0 1\n})CIRCUIT\");\n}\n\nTEST(circuit, parse_sweep_bits) {\n    ASSERT_THROW({ Circuit(\"H sweep[0]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"X sweep[0]\"); }, std::invalid_argument);\n\n    std::vector<GateTarget> expected{\n        GateTarget::sweep_bit(2),\n        GateTarget::qubit(5),\n    };\n\n    Circuit c(\"CNOT sweep[2] 5\");\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.operations[0].targets, (SpanRef<GateTarget>)expected);\n    ASSERT_TRUE(c.operations[0].args.empty());\n}\n\nTEST(circuit, append_circuit) {\n    Circuit c1;\n    c1.safe_append_u(\"X\", {0, 1});\n    c1.safe_append_u(\"M\", {0, 1, 2, 4});\n\n    Circuit c2;\n    c2.safe_append_u(\"M\", {7});\n\n    Circuit actual = c1;\n    actual += c2;\n    ASSERT_EQ(actual.operations.size(), 2);\n    ASSERT_EQ(actual, Circuit(\"X 0 1\\nM 0 1 2 4 7\"));\n\n    actual *= 4;\n    ASSERT_EQ(actual.str(), R\"CIRCUIT(REPEAT 4 {\n    X 0 1\n    M 0 1 2 4 7\n})CIRCUIT\");\n}\n\nTEST(circuit, append_op_fuse) {\n    Circuit expected;\n    Circuit actual;\n\n    actual.clear();\n    expected.safe_append_u(\"H\", {1, 2, 3});\n    actual.safe_append_u(\"H\", {1});\n    actual.safe_append_u(\"H\", {2, 3});\n    ASSERT_EQ(actual, expected);\n    actual.safe_append_u(\"R\", {0});\n    actual.safe_append_u(\"R\", {});\n    expected.safe_append_u(\"R\", {0});\n    ASSERT_EQ(actual, expected);\n\n    actual.clear();\n    actual.safe_append_u(\"DETECTOR\", {2 | TARGET_RECORD_BIT, 2 | TARGET_RECORD_BIT});\n    actual.safe_append_u(\"DETECTOR\", {1 | TARGET_RECORD_BIT, 1 | TARGET_RECORD_BIT});\n    ASSERT_EQ(actual.operations.size(), 2);\n\n    actual.clear();\n    actual.safe_append_u(\"TICK\", {});\n    actual.safe_append_u(\"TICK\", {});\n    ASSERT_EQ(actual.operations.size(), 2);\n\n    actual.clear();\n    expected.clear();\n    actual.safe_append_u(\"M\", {0, 1});\n    actual.safe_append_u(\"M\", {2, 3});\n    expected.safe_append_u(\"M\", {0, 1, 2, 3});\n    ASSERT_EQ(actual, expected);\n\n    ASSERT_THROW({ actual.safe_append_u(\"CNOT\", {0}); }, std::invalid_argument);\n    ASSERT_THROW({ actual.safe_append_ua(\"X\", {0}, 0.5); }, std::invalid_argument);\n}\n\nTEST(circuit, str) {\n    Circuit c;\n    c.safe_append_u(\"tick\", {});\n    c.safe_append_u(\"CNOT\", {2, 3});\n    c.safe_append_u(\"CNOT\", {5 | TARGET_RECORD_BIT, 3});\n    c.safe_append_u(\"CY\", {6 | TARGET_SWEEP_BIT, 4});\n    c.safe_append_u(\"M\", {1, 3, 2});\n    c.safe_append_u(\"DETECTOR\", {7 | TARGET_RECORD_BIT});\n    c.safe_append_ua(\"OBSERVABLE_INCLUDE\", {11 | TARGET_RECORD_BIT, 1 | TARGET_RECORD_BIT}, 17);\n    c.safe_append_ua(\"X_ERROR\", {19}, 0.5);\n    c.safe_append_ua(\n        \"CORRELATED_ERROR\",\n        {\n            23 | TARGET_PAULI_X_BIT,\n            27 | TARGET_PAULI_Z_BIT,\n            29 | TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT,\n        },\n        0.25);\n    ASSERT_EQ(c.str(), R\"circuit(TICK\nCX 2 3 rec[-5] 3\nCY sweep[6] 4\nM 1 3 2\nDETECTOR rec[-7]\nOBSERVABLE_INCLUDE(17) rec[-11] rec[-1]\nX_ERROR(0.5) 19\nE(0.25) X23 Z27 Y29)circuit\");\n}\n\nTEST(circuit, append_op_validation) {\n    Circuit c;\n    ASSERT_THROW({ c.safe_append_u(\"CNOT\", {0}); }, std::invalid_argument);\n    c.safe_append_u(\"CNOT\", {0, 1});\n\n    ASSERT_THROW({ c.safe_append_u(\"REPEAT\", {100}); }, std::invalid_argument);\n    ASSERT_THROW({ c.safe_append_u(\"X\", {0 | TARGET_PAULI_X_BIT}); }, std::invalid_argument);\n    ASSERT_THROW({ c.safe_append_u(\"X\", {0 | TARGET_PAULI_Z_BIT}); }, std::invalid_argument);\n    ASSERT_THROW({ c.safe_append_u(\"X\", {0 | TARGET_INVERTED_BIT}); }, std::invalid_argument);\n    ASSERT_THROW({ c.safe_append_ua(\"X\", {0}, 0.5); }, std::invalid_argument);\n\n    ASSERT_THROW({ c.safe_append_u(\"M\", {0 | TARGET_PAULI_X_BIT}); }, std::invalid_argument);\n    ASSERT_THROW({ c.safe_append_u(\"M\", {0 | TARGET_PAULI_Z_BIT}); }, std::invalid_argument);\n    c.safe_append_u(\"M\", {0 | TARGET_INVERTED_BIT});\n    c.safe_append_ua(\"M\", {0 | TARGET_INVERTED_BIT}, 0.125);\n    ASSERT_THROW({ c.safe_append_ua(\"M\", {0}, 1.5); }, std::invalid_argument);\n    ASSERT_THROW({ c.safe_append_ua(\"M\", {0}, -1.5); }, std::invalid_argument);\n    ASSERT_THROW({ c.safe_append_u(\"M\", {0}, {0.125, 0.25}); }, std::invalid_argument);\n\n    c.safe_append_ua(\"CORRELATED_ERROR\", {0 | TARGET_PAULI_X_BIT}, 0.1);\n    c.safe_append_ua(\"CORRELATED_ERROR\", {0 | TARGET_PAULI_Z_BIT}, 0.1);\n    ASSERT_THROW({ c.safe_append_u(\"CORRELATED_ERROR\", {0 | TARGET_PAULI_X_BIT}); }, std::invalid_argument);\n    ASSERT_THROW({ c.safe_append_u(\"CORRELATED_ERROR\", {0 | TARGET_PAULI_X_BIT}, {0.1, 0.2}); }, std::invalid_argument);\n    ASSERT_THROW(\n        { c.safe_append_u(\"CORRELATED_ERROR\", {0 | TARGET_PAULI_X_BIT | TARGET_INVERTED_BIT}); },\n        std::invalid_argument);\n    c.safe_append_ua(\"X_ERROR\", {0}, 0.5);\n\n    ASSERT_THROW({ c.safe_append_u(\"CNOT\", {0, 0}); }, std::invalid_argument);\n}\n\nTEST(circuit, repeat_validation) {\n    ASSERT_THROW({ Circuit(\"REPEAT 100 {\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"REPEAT 100 {{\\n}\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"REPEAT {\\n}\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit().append_from_text(\"REPEAT 100 {\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit().append_from_text(\"REPEAT {\\n}\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"H {\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"H {\\n}\"); }, std::invalid_argument);\n}\n\nTEST(circuit, tick_validation) {\n    ASSERT_THROW({ Circuit(\"TICK 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit().safe_append_u(\"TICK\", {1}); }, std::invalid_argument);\n}\n\nTEST(circuit, detector_validation) {\n    ASSERT_THROW({ Circuit(\"DETECTOR 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit().safe_append_u(\"DETECTOR\", {1}); }, std::invalid_argument);\n}\n\nTEST(circuit, x_error_validation) {\n    Circuit(\"X_ERROR(0) 1\");\n    Circuit(\"X_ERROR(0.1) 1\");\n    Circuit(\"X_ERROR(1) 1\");\n    ASSERT_THROW({ Circuit(\"X_ERROR 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"X_ERROR(-0.1) 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"X_ERROR(1.1) 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"X_ERROR(0.1, 0.1) 1\"); }, std::invalid_argument);\n}\n\nTEST(circuit, pauli_err_1_validation) {\n    Circuit(\"PAULI_CHANNEL_1(0,0,0) 1\");\n    Circuit(\"PAULI_CHANNEL_1(0.1,0.2,0.6) 1\");\n    Circuit(\"PAULI_CHANNEL_1(1,0,0) 1\");\n    Circuit(\"PAULI_CHANNEL_1(0.33333333334,0.33333333334,0.33333333334) 1\");\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_1 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_1(0.1) 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_1(0.1,0.1) 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_1(0.1,0.1,0.1,0.1) 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_1(-1,0,0) 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_1(0.1,0.5,0.6) 1\"); }, std::invalid_argument);\n}\n\nTEST(circuit, pauli_err_2_validation) {\n    Circuit(\"PAULI_CHANNEL_2(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) 1 2\");\n    Circuit(\"PAULI_CHANNEL_2(0.1,0,0,0,0,0,0,0,0,0,0.1,0,0,0,0.1) 1 2\");\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_2(0.1,0,0,0,0,0,0,0,0,0,0.1,0,0,0,0.1) 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_2(0.4,0,0,0,0,0.4,0,0,0,0,0,0,0,0,0.4) 1 2\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_2(0,0,0,0,0,0,0,0,0,0,0,0,0,0) 1 2\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"PAULI_CHANNEL_2(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) 1 2\"); }, std::invalid_argument);\n}\n\nTEST(circuit, qubit_coords) {\n    ASSERT_THROW({ Circuit(\"TICK 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit().safe_append_u(\"TICK\", {1}); }, std::invalid_argument);\n}\n\nTEST(circuit, classical_controls) {\n    ASSERT_THROW(\n        {\n            Circuit(R\"circuit(\n                M 0\n                XCX rec[-1] 1\n             )circuit\");\n        },\n        std::invalid_argument);\n\n    Circuit expected;\n    expected.safe_append_u(\"CX\", {0, 1, 1 | TARGET_RECORD_BIT, 1});\n    expected.safe_append_u(\"CY\", {2 | TARGET_RECORD_BIT, 1});\n    expected.safe_append_u(\"CZ\", {4 | TARGET_RECORD_BIT, 1});\n    ASSERT_EQ(\n        Circuit(R\"circuit(ZCX 0 1\nZCX rec[-1] 1\nZCY rec[-2] 1\nZCZ rec[-4] 1)circuit\"),\n        expected);\n}\n\nTEST(circuit, for_each_operation) {\n    Circuit c;\n    c.append_from_text(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 2 {\n            X 1\n            REPEAT 3 {\n                Y 2\n            }\n        }\n    )CIRCUIT\");\n\n    Circuit flat;\n    flat.safe_append_u(\"H\", {0});\n    flat.safe_append_u(\"M\", {0, 1});\n    flat.safe_append_u(\"X\", {1});\n    flat.safe_append_u(\"Y\", {2});\n    flat.operations.push_back(flat.operations.back());\n    flat.operations.push_back(flat.operations.back());\n    flat.safe_append_u(\"X\", {1});\n    flat.safe_append_u(\"Y\", {2});\n    flat.operations.push_back(flat.operations.back());\n    flat.operations.push_back(flat.operations.back());\n\n    std::vector<CircuitInstruction> ops;\n    c.for_each_operation([&](const CircuitInstruction &op) {\n        ops.push_back(op);\n    });\n    ASSERT_EQ(ops, flat.operations);\n}\n\nTEST(circuit, for_each_operation_reverse) {\n    Circuit c;\n    c.append_from_text(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 2 {\n            X 1\n            REPEAT 3 {\n                Y 2\n            }\n        }\n    )CIRCUIT\");\n\n    Circuit flat;\n    flat.safe_append_u(\"Y\", {2});\n    flat.operations.push_back(flat.operations.back());\n    flat.operations.push_back(flat.operations.back());\n    flat.safe_append_u(\"X\", {1});\n    flat.safe_append_u(\"Y\", {2});\n    flat.operations.push_back(flat.operations.back());\n    flat.operations.push_back(flat.operations.back());\n    flat.safe_append_u(\"X\", {1});\n    flat.safe_append_u(\"M\", {0, 1});\n    flat.safe_append_u(\"H\", {0});\n\n    std::vector<CircuitInstruction> ops;\n    c.for_each_operation_reverse([&](const CircuitInstruction &op) {\n        ops.push_back(op);\n    });\n    ASSERT_EQ(ops, flat.operations);\n}\n\nTEST(circuit, count_qubits) {\n    ASSERT_EQ(Circuit().count_qubits(), 0);\n\n    auto c = Circuit(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 2 {\n            X 1\n            REPEAT 3 {\n                Y 2\n                M 2\n            }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.count_qubits(), 3);\n    ASSERT_EQ(c.compute_stats().num_qubits, 3);\n\n    // Ensure not unrolling to compute.\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 999999 {\n            REPEAT 999999 {\n                REPEAT 999999 {\n                    REPEAT 999999 {\n                        X 1\n                        REPEAT 999999 {\n                            Y 2\n                            M 2\n                        }\n                    }\n                }\n            }\n        }\n    )CIRCUIT\")\n            .count_qubits(),\n        3);\n}\n\nTEST(circuit, count_sweep_bits) {\n    ASSERT_EQ(Circuit().count_sweep_bits(), 0);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 2 {\n            X 1\n            REPEAT 3 {\n                CY 100 3\n                CY 80 3\n                M 2\n            }\n        }\n    )CIRCUIT\")\n            .count_sweep_bits(),\n        0);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 2 {\n            X 1\n            REPEAT 3 {\n                CY sweep[100] 3\n                CY sweep[80] 3\n                M 2\n            }\n        }\n    )CIRCUIT\")\n            .count_sweep_bits(),\n        101);\n\n    // Ensure not unrolling to compute.\n    auto c = Circuit(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 999999 {\n            REPEAT 999999 {\n                REPEAT 999999 {\n                    REPEAT 999999 {\n                        X 1\n                        REPEAT 999999 {\n                            CY sweep[77] 3\n                            M 2\n                        }\n                    }\n                }\n            }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.count_sweep_bits(), 78);\n    ASSERT_EQ(c.compute_stats().num_sweep_bits, 78);\n}\n\nTEST(circuit, count_detectors_num_observables) {\n    ASSERT_EQ(Circuit().count_detectors(), 0);\n    ASSERT_EQ(Circuit().count_observables(), 0);\n\n    auto c = Circuit(R\"CIRCUIT(\n        M 0 1 2\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(5) rec[-1]\n    )CIRCUIT\");\n    ASSERT_EQ(c.count_detectors(), 1);\n    ASSERT_EQ(c.count_observables(), 6);\n    ASSERT_EQ(c.compute_stats().num_detectors, 1);\n    ASSERT_EQ(c.compute_stats().num_observables, 6);\n\n    // Ensure not unrolling to compute.\n    c = Circuit(R\"CIRCUIT(\n        M 0 1\n        REPEAT 1000 {\n            REPEAT 1000 {\n                REPEAT 1000 {\n                    REPEAT 1000 {\n                        DETECTOR rec[-1]\n                        OBSERVABLE_INCLUDE(2) rec[-1]\n                    }\n                }\n            }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.count_detectors(), 1000000000000ULL);\n    ASSERT_EQ(c.count_observables(), 3);\n    ASSERT_EQ(c.compute_stats().num_detectors, 1000000000000ULL);\n    ASSERT_EQ(c.compute_stats().num_observables, 3);\n\n    c = Circuit(R\"CIRCUIT(\n        M 0 1\n        REPEAT 999999 {\n         REPEAT 999999 {\n          REPEAT 999999 {\n           REPEAT 999999 {\n            REPEAT 999999 {\n             REPEAT 999999 {\n              REPEAT 999999 {\n               REPEAT 999999 {\n                REPEAT 999999 {\n                 REPEAT 999999 {\n                  REPEAT 999999 {\n                   REPEAT 999999 {\n                    REPEAT 999999 {\n                        DETECTOR rec[-1]\n                    }\n                   }\n                  }\n                 }\n                }\n               }\n              }\n             }\n            }\n           }\n          }\n         }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.count_detectors(), UINT64_MAX);\n    ASSERT_EQ(c.count_observables(), 0);\n    ASSERT_EQ(c.compute_stats().num_detectors, UINT64_MAX);\n    ASSERT_EQ(c.compute_stats().num_observables, 0);\n}\n\nTEST(circuit, max_lookback) {\n    ASSERT_EQ(Circuit().max_lookback(), 0);\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n        M 0 1 2 3 4 5 6\n    )CIRCUIT\")\n            .max_lookback(),\n        0);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n        M 0 1 2 3 4 5 6\n        REPEAT 2 {\n            CNOT rec[-4] 0\n            REPEAT 3 {\n                CNOT rec[-1] 0\n            }\n        }\n    )CIRCUIT\")\n            .max_lookback(),\n        4);\n\n    // Ensure not unrolling to compute.\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n        M 0 1 2 3 4 5\n        REPEAT 999999 {\n            REPEAT 999999 {\n                REPEAT 999999 {\n                    REPEAT 999999 {\n                        REPEAT 999999 {\n                            CNOT rec[-5] 0\n                        }\n                    }\n                }\n            }\n        }\n    )CIRCUIT\")\n            .max_lookback(),\n        5);\n}\n\nTEST(circuit, count_measurements) {\n    ASSERT_EQ(Circuit().count_measurements(), 0);\n\n    auto c = Circuit(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 2 {\n            X 1\n            REPEAT 3 {\n                Y 2\n                M 2\n            }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.count_measurements(), 8);\n    ASSERT_EQ(c.compute_stats().num_measurements, 8);\n\n    // Ensure not unrolling to compute.\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n        REPEAT 999999 {\n            REPEAT 999999 {\n                REPEAT 999999 {\n                    M 0\n                }\n            }\n        }\n    )CIRCUIT\")\n            .count_measurements(),\n        999999ULL * 999999ULL * 999999ULL);\n\n    c = Circuit(R\"CIRCUIT(\n        REPEAT 999999 {\n         REPEAT 999999 {\n          REPEAT 999999 {\n           REPEAT 999999 {\n            REPEAT 999999 {\n             REPEAT 999999 {\n              REPEAT 999999 {\n               REPEAT 999999 {\n                REPEAT 999999 {\n                    M 0\n                }\n               }\n              }\n             }\n            }\n           }\n          }\n         }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.count_measurements(), UINT64_MAX);\n    ASSERT_EQ(c.compute_stats().num_measurements, UINT64_MAX);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            MPP X0 Z1 Y2\n        )CIRCUIT\")\n            .count_measurements(),\n        3);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            MPP X0 Z1*Y2\n        )CIRCUIT\")\n            .count_measurements(),\n        2);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            MPP X0*X1*X2*X3*X4 Z5 Z6\n        )CIRCUIT\")\n            .count_measurements(),\n        3);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            MPP X0*X1*X2*X3*X4 Z5 Z6\n        )CIRCUIT\")\n            .operations[0]\n            .count_measurement_results(),\n        3);\n\n    ASSERT_EQ(Circuit(\"MXX 0 1 2 3\").operations[0].count_measurement_results(), 2);\n    ASSERT_EQ(Circuit(\"MYY 0 1 2 3\").operations[0].count_measurement_results(), 2);\n    ASSERT_EQ(Circuit(\"MZZ 0 1 2 3\").operations[0].count_measurement_results(), 2);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            MPP X0*X1 Z0*Z1 Y0*Y1\n        )CIRCUIT\")\n            .count_measurements(),\n        3);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            HERALDED_ERASE(0.01) 0 1 2\n        )CIRCUIT\")\n            .count_measurements(),\n        3);\n}\n\nTEST(circuit, preserves_repetition_blocks) {\n    Circuit c = Circuit(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 2 {\n            X 1\n            REPEAT 3 {\n                Y 2\n                M 2\n                X 0\n            }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.operations.size(), 3);\n    ASSERT_EQ(c.blocks.size(), 1);\n    ASSERT_EQ(c.blocks[0].operations.size(), 2);\n    ASSERT_EQ(c.blocks[0].blocks.size(), 1);\n    ASSERT_EQ(c.blocks[0].blocks[0].operations.size(), 3);\n    ASSERT_EQ(c.blocks[0].blocks[0].blocks.size(), 0);\n}\n\nTEST(circuit, multiplication_repeats) {\n    Circuit c = Circuit(R\"CIRCUIT(\n        H 0\n        M 0 1\n    )CIRCUIT\");\n    ASSERT_EQ(c * 2, Circuit(R\"CIRCUIT(\n        REPEAT 2 {\n            H 0\n            M 0 1\n        }\n    )CIRCUIT\"));\n    ASSERT_EQ((c * 2) * 3, Circuit(R\"CIRCUIT(\n        REPEAT 6 {\n            H 0\n            M 0 1\n        }\n    )CIRCUIT\"));\n\n    ASSERT_EQ(c * 0, Circuit());\n    ASSERT_EQ(c * 1, c);\n    Circuit copy = c;\n    c *= 1;\n    ASSERT_EQ(c, copy);\n    c *= 0;\n    ASSERT_EQ(c, Circuit());\n}\n\nTEST(circuit, self_addition) {\n    Circuit c = Circuit(R\"CIRCUIT(\n        X 0\n    )CIRCUIT\");\n    c += c;\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c.blocks.size(), 0);\n    ASSERT_EQ(c, Circuit(\"X 0 0\"));\n\n    c = Circuit(R\"CIRCUIT(\n        X 0\n        Y 0\n    )CIRCUIT\");\n    c += c;\n    ASSERT_EQ(c.operations.size(), 4);\n    ASSERT_EQ(c.blocks.size(), 0);\n    ASSERT_EQ(c.operations[0], c.operations[2]);\n    ASSERT_EQ(c.operations[1], c.operations[3]);\n    ASSERT_EQ(c, Circuit(\"X 0\\nY 0\\nX 0\\nY 0\"));\n\n    c = Circuit(R\"CIRCUIT(\n        X 0\n        REPEAT 2 {\n            Y 0\n        }\n    )CIRCUIT\");\n    c += c;\n    ASSERT_EQ(c.operations.size(), 4);\n    ASSERT_EQ(c.blocks.size(), 1);\n    ASSERT_EQ(c.operations[0], c.operations[2]);\n    ASSERT_EQ(c.operations[1], c.operations[3]);\n}\n\nTEST(circuit, addition_shares_blocks) {\n    Circuit c1 = Circuit(R\"CIRCUIT(\n        X 0\n        REPEAT 2 {\n            X 1\n        }\n    )CIRCUIT\");\n    Circuit c2 = Circuit(R\"CIRCUIT(\n        X 2\n        REPEAT 2 {\n            X 3\n        }\n    )CIRCUIT\");\n    Circuit c3 = Circuit(R\"CIRCUIT(\n        X 0\n        REPEAT 2 {\n            X 1\n        }\n        X 2\n        REPEAT 2 {\n            X 3\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c1 + c2, c3);\n    c1 += c2;\n    ASSERT_EQ(c1, c3);\n}\n\nTEST(circuit, big_rep_count) {\n    Circuit c = Circuit(R\"CIRCUIT(\n        REPEAT 1234567890123456789 {\n            M 1\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.operations[0].targets.size(), 3);\n    ASSERT_EQ(c.operations[0].targets[0].data, 0);\n    ASSERT_EQ(c.operations[0].targets[1].data, 1234567890123456789ULL & 0xFFFFFFFFULL);\n    ASSERT_EQ(c.operations[0].targets[2].data, 1234567890123456789ULL >> 32);\n    ASSERT_EQ(c.str(), \"REPEAT 1234567890123456789 {\\n    M 1\\n}\");\n    ASSERT_EQ(c.count_measurements(), 1234567890123456789ULL);\n\n    ASSERT_THROW({ c * 12345ULL; }, std::invalid_argument);\n}\n\nTEST(circuit, zero_repetitions_not_allowed) {\n    ASSERT_ANY_THROW({\n        Circuit(R\"CIRCUIT(\n            REPEAT 0 {\n                M 0\n                OBSERVABLE_INCLUDE(0) rec[-1]\n            }\n        )CIRCUIT\");\n    });\n}\n\nTEST(circuit, negative_float_coordinates) {\n    auto c = Circuit(R\"CIRCUIT(\n        SHIFT_COORDS(-1, -2, -3)\n        QUBIT_COORDS(1, -2) 1\n        QUBIT_COORDS(-3.5) 1\n    )CIRCUIT\");\n    ASSERT_EQ(c.operations[0].args[2], -3);\n    ASSERT_EQ(c.operations[2].args[0], -3.5);\n    ASSERT_ANY_THROW({ Circuit(\"M(-0.1) 0\"); });\n    c = Circuit(\"QUBIT_COORDS(1e20) 0\");\n    ASSERT_EQ(c.operations[0].args[0], 1e20);\n    c = Circuit(\"QUBIT_COORDS(1E+20) 0\");\n    ASSERT_EQ(c.operations[0].args[0], 1E+20);\n    ASSERT_ANY_THROW({ Circuit(\"QUBIT_COORDS(1e10000) 0\"); });\n}\n\nTEST(circuit, py_get_slice) {\n    Circuit c(R\"CIRCUIT(\n        H 0\n        CNOT 0 1\n        M(0.125) 0 1\n        REPEAT 100 {\n            E(0.25) X0 Y5\n            REPEAT 20 {\n                H 0\n            }\n        }\n        H 1\n        REPEAT 999 {\n            H 2\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.py_get_slice(0, 1, 6), c);\n    ASSERT_EQ(c.py_get_slice(0, 1, 4), Circuit(R\"CIRCUIT(\n        H 0\n        CNOT 0 1\n        M(0.125) 0 1\n        REPEAT 100 {\n            E(0.25) X0 Y5\n            REPEAT 20 {\n                H 0\n            }\n        }\n    )CIRCUIT\"));\n    ASSERT_EQ(c.py_get_slice(2, 1, 3), Circuit(R\"CIRCUIT(\n        M(0.125) 0 1\n        REPEAT 100 {\n            E(0.25) X0 Y5\n            REPEAT 20 {\n                H 0\n            }\n        }\n        H 1\n    )CIRCUIT\"));\n\n    ASSERT_EQ(c.py_get_slice(4, -1, 3), Circuit(R\"CIRCUIT(\n        H 1\n        REPEAT 100 {\n            E(0.25) X0 Y5\n            REPEAT 20 {\n                H 0\n            }\n        }\n        M(0.125) 0 1\n    )CIRCUIT\"));\n\n    ASSERT_EQ(c.py_get_slice(5, -2, 3), Circuit(R\"CIRCUIT(\n        REPEAT 999 {\n            H 2\n        }\n        REPEAT 100 {\n            E(0.25) X0 Y5\n            REPEAT 20 {\n                H 0\n            }\n        }\n        CNOT 0 1\n    )CIRCUIT\"));\n\n    Circuit c2 = c;\n    Circuit c3 = c2.py_get_slice(0, 1, 6);\n    c2.clear();\n    ASSERT_EQ(c, c3);\n}\n\nTEST(circuit, append_repeat_block) {\n    Circuit c;\n    Circuit b(\"X 0\");\n    Circuit a(\"Y 0\");\n\n    c.append_repeat_block(100, b, \"\");\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        REPEAT 100 {\n            X 0\n        }\n    )CIRCUIT\"));\n\n    c.append_repeat_block(200, a, \"\");\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        REPEAT 100 {\n            X 0\n        }\n        REPEAT 200 {\n            Y 0\n        }\n    )CIRCUIT\"));\n\n    c.append_repeat_block(400, std::move(b), \"\");\n    ASSERT_TRUE(b.operations.empty());\n    ASSERT_FALSE(a.operations.empty());\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        REPEAT 100 {\n            X 0\n        }\n        REPEAT 200 {\n            Y 0\n        }\n        REPEAT 400 {\n            X 0\n        }\n    )CIRCUIT\"));\n\n    ASSERT_THROW({ c.append_repeat_block(0, a, \"\"); }, std::invalid_argument);\n    ASSERT_THROW({ c.append_repeat_block(0, std::move(a), \"\"); }, std::invalid_argument);\n}\n\nTEST(circuit, aliased_noiseless_circuit) {\n    Circuit initial(R\"CIRCUIT(\n        H 0\n        X_ERROR(0.1) 0\n        M(0.05) 0\n        M(0.15) 1\n        REPEAT 100 {\n            CNOT 0 1\n            DEPOLARIZE2(0.1) 0 1\n            MPP(0.1) X0*X1 Z0 Z1\n        }\n    )CIRCUIT\");\n    Circuit noiseless = initial.aliased_noiseless_circuit();\n    ASSERT_EQ(noiseless, Circuit(R\"CIRCUIT(\n        H 0\n        M 0 1\n        REPEAT 100 {\n            CNOT 0 1\n            MPP X0*X1 Z0 Z1\n        }\n    )CIRCUIT\"));\n\n    Circuit c1 = initial.without_noise();\n    Circuit c2 = c1;\n    ASSERT_EQ(c1, noiseless);\n    initial.clear();\n    ASSERT_EQ(c1, c2);\n\n    ASSERT_EQ(Circuit(\"H 0\\nX_ERROR(0.01) 0\\nH 0\").without_noise(), Circuit(\"H 0 0\"));\n}\n\nTEST(circuit, noiseless_heralded_erase) {\n    Circuit noisy(R\"CIRCUIT(\n        M 0 1\n        MPAD 1\n        HERALDED_ERASE(0.01) 2 3 0 1\n        MPAD 1\n        M 2 0\n        DETECTOR rec[-1] rec[-8]\n    )CIRCUIT\");\n    Circuit noiseless(R\"CIRCUIT(\n        M 0 1\n        MPAD 1 0 0 0 0 1\n        M 2 0\n        DETECTOR rec[-1] rec[-8]\n    )CIRCUIT\");\n\n    ASSERT_EQ(noisy.aliased_noiseless_circuit(), noiseless);\n    ASSERT_EQ(noisy.without_noise(), noiseless);\n}\n\nTEST(circuit, validate_nan_probability) {\n    Circuit c;\n    ASSERT_THROW({ c.safe_append_ua(\"X_ERROR\", {0}, NAN); }, std::invalid_argument);\n}\n\nTEST(circuit, validate_mpad) {\n    Circuit c;\n    c.append_from_text(\"MPAD 0 1\");\n    ASSERT_THROW({ c.append_from_text(\"MPAD 2\"); }, std::invalid_argument);\n    ASSERT_THROW({ c.append_from_text(\"MPAD sweep[-1]\"); }, std::invalid_argument);\n}\n\nTEST(circuit, get_final_qubit_coords) {\n    ASSERT_EQ(Circuit().get_final_qubit_coords(), (std::map<uint64_t, std::vector<double>>{}));\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n                  QUBIT_COORDS(1, 2) 3\n              )CIRCUIT\")\n            .get_final_qubit_coords(),\n        (std::map<uint64_t, std::vector<double>>{\n            {3, {1, 2}},\n        }));\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n                  SHIFT_COORDS(10, 20, 30)\n                  QUBIT_COORDS(4, 5) 3\n              )CIRCUIT\")\n            .get_final_qubit_coords(),\n        (std::map<uint64_t, std::vector<double>>{\n            {3, {14, 25}},\n        }));\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n                  QUBIT_COORDS(1, 2, 3, 4) 1\n                  REPEAT 100 {\n                      SHIFT_COORDS(10, 20, 30)\n                  }\n                  QUBIT_COORDS(4, 5) 3\n                  QUBIT_COORDS(6) 4\n              )CIRCUIT\")\n            .get_final_qubit_coords(),\n        (std::map<uint64_t, std::vector<double>>{\n            {1, {1, 2, 3, 4}},\n            {3, {1004, 2005}},\n            {4, {1006}},\n        }));\n}\n\nTEST(circuit, get_final_qubit_coords_huge_repetition_count_efficiency) {\n    auto actual = Circuit(R\"CIRCUIT(\n        QUBIT_COORDS(0) 0\n        REPEAT 1000 {\n            QUBIT_COORDS(1, 1) 1\n            REPEAT 2000 {\n                QUBIT_COORDS(2, 0.5) 2\n                REPEAT 4000 {\n                    QUBIT_COORDS(3) 3\n                    REPEAT 8000 {\n                        QUBIT_COORDS(4) 4\n                        SHIFT_COORDS(100)\n                        QUBIT_COORDS(5) 5\n                    }\n                    SHIFT_COORDS(10)\n                    QUBIT_COORDS(6) 6\n                }\n                QUBIT_COORDS(7) 7\n            }\n            QUBIT_COORDS(8) 8\n        }\n        QUBIT_COORDS(9) 9\n    )CIRCUIT\")\n                      .get_final_qubit_coords();\n\n    ASSERT_EQ(\n        actual,\n        (std::map<uint64_t, std::vector<double>>{\n            {0, {0}},\n            {1, {6400080000000001 - 6400080000000, 1}},\n            {2, {6400080000000002 - 3200040000, 0.5}},\n            {3, {6400080000000003 - 800010}},\n            {4, {6400080000000004 - 110}},\n            {5, {6400080000000005 - 10}},\n            {6, {6400080000000006}},\n            {7, {6400080000000007}},\n            {8, {6400080000000008}},\n            {9, {6400080000000009}},\n        }));\n    // Precision sanity check.\n    ASSERT_EQ(6400080000000009, (uint64_t)(double)6400080000000009);\n}\n\nTEST(circuit, count_ticks) {\n    ASSERT_EQ(Circuit().count_ticks(), 0);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            TICK\n        )CIRCUIT\")\n            .count_ticks(),\n        1);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            TICK\n            TICK\n        )CIRCUIT\")\n            .count_ticks(),\n        2);\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            TICK\n            H 0\n            TICK\n        )CIRCUIT\")\n            .count_ticks(),\n        2);\n\n    auto c = Circuit(R\"CIRCUIT(\n        TICK\n        REPEAT 1000 {\n            REPEAT 2000 {\n                REPEAT 1000 {\n                    TICK\n                }\n                TICK\n                TICK\n                TICK\n            }\n        }\n        TICK\n    )CIRCUIT\");\n    ASSERT_EQ(c.count_ticks(), 2006000002);\n    ASSERT_EQ(c.compute_stats().num_ticks, 2006000002);\n}\n\nTEST(circuit, coords_of_detector) {\n    Circuit c(R\"CIRCUIT(\n        TICK\n        REPEAT 1000 {\n            REPEAT 2000 {\n                REPEAT 1000 {\n                    DETECTOR(0, 0, 0, 4)\n                    SHIFT_COORDS(1, 0, 0)\n                }\n                DETECTOR(0, 0, 0, 3)\n                SHIFT_COORDS(0, 1, 0)\n            }\n            DETECTOR(0, 0, 0, 2)\n            SHIFT_COORDS(0, 0, 1)\n        }\n        DETECTOR(0, 0, 0, 1)\n    )CIRCUIT\");\n    ASSERT_EQ(c.coords_of_detector(0), (std::vector<double>{0, 0, 0, 4}));\n    ASSERT_EQ(c.coords_of_detector(1), (std::vector<double>{1, 0, 0, 4}));\n    ASSERT_EQ(c.coords_of_detector(999), (std::vector<double>{999, 0, 0, 4}));\n    ASSERT_EQ(c.coords_of_detector(1000), (std::vector<double>{1000, 0, 0, 3}));\n    ASSERT_EQ(c.coords_of_detector(1001), (std::vector<double>{1000, 1, 0, 4}));\n    ASSERT_EQ(c.coords_of_detector(1002), (std::vector<double>{1001, 1, 0, 4}));\n\n    ASSERT_THROW({ c.get_detector_coordinates({4000000000}); }, std::invalid_argument);\n\n    auto result = c.get_detector_coordinates({\n        0,\n        1,\n        999,\n        1000,\n        1001,\n        1002,\n    });\n    ASSERT_EQ(\n        result,\n        (std::map<uint64_t, std::vector<double>>{\n            {0, {0, 0, 0, 4}},\n            {1, {1, 0, 0, 4}},\n            {999, {999, 0, 0, 4}},\n            {1000, {1000, 0, 0, 3}},\n            {1001, {1000, 1, 0, 4}},\n            {1002, {1001, 1, 0, 4}},\n        }));\n}\n\nTEST(circuit, final_coord_shift) {\n    Circuit c(R\"CIRCUIT(\n        REPEAT 1000 {\n            REPEAT 2000 {\n                REPEAT 3000 {\n                    SHIFT_COORDS(0, 0, 1)\n                }\n                SHIFT_COORDS(1)\n            }\n            SHIFT_COORDS(0, 1)\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(c.final_coord_shift(), (std::vector<double>{2000000, 1000, 6000000000}));\n}\n\nTEST(circuit, concat_fuse) {\n    Circuit c1(\"H 0\");\n    Circuit c2(\"H 1\");\n    Circuit c3 = c1 + c2;\n    ASSERT_EQ(c3.operations.size(), 1);\n    ASSERT_EQ(c3, Circuit(\"H 0 1\"));\n}\n\nTEST(circuit, concat_self_fuse) {\n    Circuit c(\"H 0\");\n    c += c;\n    ASSERT_EQ(c.operations.size(), 1);\n    ASSERT_EQ(c, Circuit(\"H 0 0\"));\n}\n\nTEST(circuit, assignment_copies_operations) {\n    Circuit c1(\"H 0 1\\nS 0\");\n    Circuit c2(\"TICK\");\n    ASSERT_EQ(c1.operations.size(), 2);\n    ASSERT_EQ(c2.operations.size(), 1);\n    c2 = c1;\n    ASSERT_EQ(c2.operations.size(), 2);\n    ASSERT_EQ(c1, c2);\n}\n\nTEST(circuit, flattened) {\n    ASSERT_EQ(Circuit().flattened(), Circuit());\n    ASSERT_EQ(Circuit(\"SHIFT_COORDS(1, 2)\").flattened(), Circuit());\n    ASSERT_EQ(Circuit(\"H 1\").flattened(), Circuit(\"H 1\"));\n    ASSERT_EQ(Circuit(\"REPEAT 100 {\\n}\").flattened(), Circuit());\n    ASSERT_EQ(Circuit(\"REPEAT 3 {\\nH 0\\n}\").flattened(), Circuit(\"H 0 0 0\"));\n}\n\nTEST(circuit, approx_equals) {\n    Circuit ref(R\"CIRCUIT(\n        H 0\n        X_ERROR(0.02) 0\n        QUBIT_COORDS(0.08, 0.06) 0\n    )CIRCUIT\");\n\n    ASSERT_TRUE(ref.approx_equals(ref, 1e-4));\n    ASSERT_TRUE(ref.approx_equals(ref, 0));\n\n    ASSERT_FALSE(ref.approx_equals(\n        Circuit(R\"CIRCUIT(\n        H 0\n        X_ERROR(0.021) 0\n        QUBIT_COORDS(0.08, 0.06) 0\n    )CIRCUIT\"),\n        1e-4));\n    ASSERT_FALSE(ref.approx_equals(\n        Circuit(R\"CIRCUIT(\n        H 0\n        X_ERROR(0.02) 0\n        QUBIT_COORDS(0.081, 0.06) 0\n    )CIRCUIT\"),\n        1e-4));\n    ASSERT_FALSE(ref.approx_equals(\n        Circuit(R\"CIRCUIT(\n        H 0\n        X_ERROR(0.02) 0\n        QUBIT_COORDS(0.08, 0.06) 0\n        TICK\n    )CIRCUIT\"),\n        1e-4));\n    ASSERT_FALSE(ref.approx_equals(\n        Circuit(R\"CIRCUIT(\n        H 0\n        X_ERROR(0.02) 0\n        REPEAT 1 {\n            QUBIT_COORDS(0.08, 0.06) 0\n        }\n    )CIRCUIT\"),\n        1e-4));\n    ASSERT_TRUE(ref.approx_equals(\n        Circuit(R\"CIRCUIT(\n        H 0\n        X_ERROR(0.021) 0\n        QUBIT_COORDS(0.081, 0.06) 0\n    )CIRCUIT\"),\n        1e-2));\n    ASSERT_FALSE(ref.approx_equals(\n        Circuit(R\"CIRCUIT(\n        H 1\n        X_ERROR(0.02) 0\n        QUBIT_COORDS(0.08, 0.06) 0\n    )CIRCUIT\"),\n        100));\n    ASSERT_FALSE(ref.approx_equals(\n        Circuit(R\"CIRCUIT(\n        H 0\n        QUBIT_COORDS(0.08, 0.06) 0\n        X_ERROR(0.02) 0\n    )CIRCUIT\"),\n        100));\n    Circuit rep2(R\"CIRCUIT(\n        H 0\n        X_ERROR(0.02) 0\n        REPEAT 1 {\n            QUBIT_COORDS(0.08, 0.06) 0\n        }\n    )CIRCUIT\");\n    ASSERT_FALSE(ref.approx_equals(rep2, 100));\n    ASSERT_TRUE(rep2.approx_equals(rep2, 0));\n}\n\nTEST(circuit, equality) {\n    Circuit a(R\"CIRCUIT(\n        H 0\n        REPEAT 100 {\n            X_ERROR(0.25) 1\n        }\n    )CIRCUIT\");\n    Circuit b(R\"CIRCUIT(\n        H 1\n        REPEAT 100 {\n            X_ERROR(0.25) 1\n        }\n    )CIRCUIT\");\n    Circuit c(R\"CIRCUIT(\n        H 0\n        REPEAT 100 {\n            X_ERROR(0.125) 1\n        }\n    )CIRCUIT\");\n\n    ASSERT_FALSE(a == b);\n    ASSERT_FALSE(a == c);\n    ASSERT_FALSE(b == c);\n    ASSERT_TRUE(a == Circuit(a));\n    ASSERT_TRUE(b == Circuit(b));\n    ASSERT_TRUE(c == Circuit(c));\n\n    ASSERT_TRUE(a != b);\n    ASSERT_TRUE(a != c);\n    ASSERT_TRUE(b != c);\n    ASSERT_FALSE(a != Circuit(a));\n    ASSERT_FALSE(b != Circuit(b));\n    ASSERT_FALSE(c != Circuit(c));\n}\n\nTEST(circuit, parse_windows_newlines) {\n    ASSERT_EQ(Circuit(\"H 0\\r\\nCX 0 1\\r\\n\"), Circuit(\"H 0\\nCX 0 1\\n\"));\n}\n\nTEST(circuit, inverse) {\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            H 0\n            CX 0 1\n            S 1\n        )CIRCUIT\")\n            .inverse(),\n        Circuit(R\"CIRCUIT(\n            S_DAG 1\n            CX 0 1\n            H 0\n        )CIRCUIT\"));\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            TICK\n        )CIRCUIT\")\n            .inverse(),\n        Circuit(R\"CIRCUIT(\n            TICK\n        )CIRCUIT\"));\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            QUBIT_COORDS(1, 2) 0\n            QUBIT_COORDS(1, 3) 1\n            CY 0 1\n            SQRT_X_DAG 1\n        )CIRCUIT\")\n            .inverse(),\n        Circuit(R\"CIRCUIT(\n            QUBIT_COORDS(1, 2) 0\n            QUBIT_COORDS(1, 3) 1\n            SQRT_X 1\n            CY 0 1\n        )CIRCUIT\"));\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            CX 0 1 2 3 4 5\n            C_XYZ 6 7 8 9\n        )CIRCUIT\")\n            .inverse(),\n        Circuit(R\"CIRCUIT(\n            C_ZYX 9 8 7 6\n            CX 4 5 2 3 0 1\n        )CIRCUIT\"));\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            S_DAG 0\n            REPEAT 100 {\n                ISWAP 0 1 1 2\n                TICK\n                CZ\n                CX 0 1\n                REPEAT 50 {\n                }\n            }\n            H 1 2\n        )CIRCUIT\")\n            .inverse(),\n        Circuit(R\"CIRCUIT(\n            H 2 1\n            REPEAT 100 {\n                REPEAT 50 {\n                }\n                CX 0 1\n                CZ\n                TICK\n                ISWAP_DAG 1 2 0 1\n            }\n            S 0\n        )CIRCUIT\"));\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            SHIFT_COORDS(-2, 3)\n            TICK\n            TICK\n            SHIFT_COORDS(4)\n            TICK\n        )CIRCUIT\")\n            .inverse(),\n        Circuit(R\"CIRCUIT(\n            TICK\n            SHIFT_COORDS(-4)\n            TICK\n            TICK\n            SHIFT_COORDS(2, -3)\n        )CIRCUIT\"));\n\n    ASSERT_EQ(\n        Circuit(R\"CIRCUIT(\n            X_ERROR(0.125) 0 1\n            Y_ERROR(0.125) 1 2\n            Z_ERROR(0.125) 2 3\n            PAULI_CHANNEL_1(0.125, 0.25, 0) 0 1 0 0\n            PAULI_CHANNEL_2(0, 0.125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 5 7 2 3\n            DEPOLARIZE1(0.25) 4 5 6\n            DEPOLARIZE2(0.25) 1 2 3 4\n            REPEAT 2 {\n                MX(0.125) 3 4\n                MY(0.125) 5 6\n                M(0.125) 7 8\n            }\n            MRX(0.125) 9 10\n            MRY(0.125) 11 12\n            MR(0.125) 13 14\n            RX 15 16\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(0) rec[-1]\n            RY 17 18\n            R 19 20\n            MPP(0.125) X0*X1 Y2*Y3*Y4 Z5*Y6\n        )CIRCUIT\")\n            .inverse(true),\n        Circuit(R\"CIRCUIT(\n            MPP(0.125) Y6*Z5 Y4*Y3*Y2 X1*X0\n            M 20 19\n            MY 18 17\n            MX 16 15\n            MR(0.125) 14 13\n            MRY(0.125) 12 11\n            MRX(0.125) 10 9\n            REPEAT 2 {\n                M(0.125) 8 7\n                MY(0.125) 6 5\n                MX(0.125) 4 3\n            }\n            DEPOLARIZE2(0.25) 3 4 1 2\n            DEPOLARIZE1(0.25) 6 5 4\n            PAULI_CHANNEL_2(0, 0.125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 2 3 5 7\n            PAULI_CHANNEL_1(0.125, 0.25, 0) 0 0 1 0\n            Z_ERROR(0.125) 3 2\n            Y_ERROR(0.125) 2 1\n            X_ERROR(0.125) 1 0\n        )CIRCUIT\"));\n\n    ASSERT_THROW({ Circuit(\"X_ERROR(0.125) 0\").inverse(); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"M(0.125) 0\").inverse(); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"M 0\").inverse(); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"R 0\").inverse(); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MR 0\").inverse(); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"MPP X0*X1\").inverse(); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"DETECTOR\").inverse(); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"OBSERVABLE_INCLUDE\").inverse(); }, std::invalid_argument);\n    ASSERT_THROW({ Circuit(\"ELSE_CORRELATED_ERROR(0.125) X0\").inverse(true); }, std::invalid_argument);\n}\n\nCircuit stim::generate_test_circuit_with_all_operations() {\n    return Circuit(R\"CIRCUIT(\n        QUBIT_COORDS(1, 2, 3) 0\n\n        # Pauli gates\n        I 0\n        X 1\n        Y 2\n        Z 3\n        TICK\n\n        # Single Qubit Clifford Gates\n        C_XYZ 0\n        C_NXYZ 1\n        C_XNYZ 2\n        C_XYNZ 3\n        C_ZYX 4\n        C_NZYX 5\n        C_ZNYX 6\n        C_ZYNX 7\n        H_XY 0\n        H_XZ 1\n        H_YZ 2\n        H_NXY 3\n        H_NXZ 4\n        H_NYZ 5\n        SQRT_X 0\n        SQRT_X_DAG 1\n        SQRT_Y 2\n        SQRT_Y_DAG 3\n        SQRT_Z 4\n        SQRT_Z_DAG 5\n        TICK\n\n        # Two Qubit Clifford Gates\n        CXSWAP 0 1\n        ISWAP 2 3\n        ISWAP_DAG 4 5\n        SWAP 6 7\n        SWAPCX 8 9\n        CZSWAP 10 11\n        SQRT_XX 0 1\n        SQRT_XX_DAG 2 3\n        SQRT_YY 4 5\n        SQRT_YY_DAG 6 7\n        SQRT_ZZ 8 9\n        SQRT_ZZ_DAG 10 11\n        II 12 13\n        XCX 0 1\n        XCY 2 3\n        XCZ 4 5\n        YCX 6 7\n        YCY 8 9\n        YCZ 10 11\n        ZCX 12 13\n        ZCY 14 15\n        ZCZ 16 17\n        TICK\n\n        # Noise Channels\n        CORRELATED_ERROR(0.01) X1 Y2 Z3\n        ELSE_CORRELATED_ERROR(0.02) X4 Y7 Z6\n        DEPOLARIZE1(0.02) 0\n        DEPOLARIZE2(0.03) 1 2\n        PAULI_CHANNEL_1(0.01, 0.02, 0.03) 3\n        PAULI_CHANNEL_2(0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.010, 0.011, 0.012, 0.013, 0.014, 0.015) 4 5\n        X_ERROR(0.01) 0\n        Y_ERROR(0.02) 1\n        Z_ERROR(0.03) 2\n        HERALDED_ERASE(0.04) 3\n        HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.04) 6\n        I_ERROR(0.06) 7\n        II_ERROR(0.07) 8 9\n        TICK\n\n        # Pauli Product Gates\n        MPP X0*Y1*Z2 Z0*Z1\n        SPP X0*Y1*Z2 X3\n        SPP_DAG X0*Y1*Z2 X2\n        TICK\n\n        # Collapsing Gates\n        MRX 0\n        MRY 1\n        MRZ 2\n        MX 3\n        MY 4\n        MZ 5 6\n        RX 7\n        RY 8\n        RZ 9\n        TICK\n\n        # Pair Measurement Gates\n        MXX 0 1 2 3\n        MYY 4 5\n        MZZ 6 7\n        TICK\n\n        # Control Flow\n        REPEAT 3 {\n            H 0\n            CX 0 1\n            S 1\n            TICK\n        }\n        TICK\n\n        # Annotations\n        MR 0\n        X_ERROR(0.1) 0\n        MR(0.01) 0\n        SHIFT_COORDS(1, 2, 3)\n        DETECTOR(1, 2, 3) rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        MPAD 0 1 0\n        OBSERVABLE_INCLUDE(1) Z2 Z3\n        TICK\n\n        # Inverted measurements.\n        MRX !0\n        MY !1\n        MZZ !2 3\n        OBSERVABLE_INCLUDE(1) rec[-1]\n        MYY !4 !5\n        MPP X6*!Y7*Z8\n        TICK\n\n        # Feedback\n        CX rec[-1] 0\n        CY sweep[0] 1\n        CZ 2 rec[-1]\n    )CIRCUIT\");\n}\n\nTEST(circuit, generate_test_circuit_with_all_operations) {\n    auto c = generate_test_circuit_with_all_operations();\n    std::set<GateType> seen{GateType::NOT_A_GATE};\n    for (const auto &instruction : c.operations) {\n        seen.insert(instruction.gate_type);\n    }\n    ASSERT_EQ(seen.size(), NUM_DEFINED_GATES);\n}\n\nTEST(circuit, insert_circuit) {\n    Circuit c(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\");\n    c.safe_insert(2, Circuit(R\"CIRCUIT(\n        H 1\n        X 3\n        S 2\n    )CIRCUIT\"));\n    ASSERT_EQ(c.operations.size(), 5);\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0 1\n        X 3\n        S 2 0\n        CX 0 1\n    )CIRCUIT\"));\n\n    c = Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\");\n    c.safe_insert(0, Circuit(R\"CIRCUIT(\n        H 1\n        X 3\n        S 2\n    )CIRCUIT\"));\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        H 1\n        X 3\n        S 2\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\"));\n\n    c = Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\");\n    c.safe_insert(4, Circuit(R\"CIRCUIT(\n        H 1\n        X 3\n        S 2\n    )CIRCUIT\"));\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n        H 1\n        X 3\n        S 2\n    )CIRCUIT\"));\n}\n\nTEST(circuit, insert_instruction) {\n    Circuit c = Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\");\n    c.safe_insert(2, Circuit(\"H 1\").operations[0]);\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0 1\n        S 0\n        CX 0 1\n    )CIRCUIT\"));\n\n    c = Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\");\n    c.safe_insert(2, Circuit(\"S 1\").operations[0]);\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 1 0\n        CX 0 1\n    )CIRCUIT\"));\n\n    c = Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\");\n    c.safe_insert(2, Circuit(\"X 1\").operations[0]);\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        X 1\n        S 0\n        CX 0 1\n    )CIRCUIT\"));\n\n    c = Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\");\n    c.safe_insert(0, Circuit(\"X 1\").operations[0]);\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        X 1\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\"));\n\n    c = Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n    )CIRCUIT\");\n    c.safe_insert(4, Circuit(\"X 1\").operations[0]);\n    ASSERT_EQ(c, Circuit(R\"CIRCUIT(\n        CX 0 1\n        H 0\n        S 0\n        CX 0 1\n        X 1\n    )CIRCUIT\"));\n}\n\nTEST(circuit, without_tags) {\n    Circuit initial(R\"CIRCUIT(\n        H[test-1] 0\n        REPEAT[test-2] 100 {\n            REPEAT[test-3] 100 {\n                M[test-4](0.125) 0\n            }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(initial.without_tags(), Circuit(R\"CIRCUIT(\n        H 0\n        REPEAT 100 {\n            REPEAT 100 {\n                M(0.125) 0\n            }\n        }\n    )CIRCUIT\"));\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit.test.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CIRCUIT_TEST_H\n#define _STIM_CIRCUIT_TEST_H\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim {\n\nstim::Circuit generate_test_circuit_with_all_operations();\n\n}  // namespace stim\n\n#endif"
  },
  {
    "path": "src/stim/circuit/circuit2.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <pybind11/stl.h>\n\n#include \"stim/circuit/circuit.pybind.h\"\n#include \"stim/cmd/command_help.h\"\n#include \"stim/dem/detector_error_model_target.pybind.h\"\n#include \"stim/util_top/circuit_flow_generators.h\"\n#include \"stim/util_top/circuit_inverse_qec.h\"\n#include \"stim/util_top/circuit_to_detecting_regions.h\"\n#include \"stim/util_top/circuit_vs_tableau.h\"\n#include \"stim/util_top/count_determined_measurements.h\"\n#include \"stim/util_top/export_crumble_url.h\"\n#include \"stim/util_top/export_qasm.h\"\n#include \"stim/util_top/export_quirk_url.h\"\n#include \"stim/util_top/has_flow.h\"\n#include \"stim/util_top/missing_detectors.h\"\n#include \"stim/util_top/simplified_circuit.h\"\n#include \"stim/util_top/transform_without_feedback.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nstatic std::set<DemTarget> py_dem_filter_to_dem_target_set(\n    const Circuit &circuit, const CircuitStats &stats, const pybind11::object &included_targets_filter) {\n    std::set<DemTarget> result;\n    auto add_all_dets = [&]() {\n        for (uint64_t k = 0; k < stats.num_detectors; k++) {\n            result.insert(DemTarget::relative_detector_id(k));\n        }\n    };\n    auto add_all_obs = [&]() {\n        for (uint64_t k = 0; k < stats.num_observables; k++) {\n            result.insert(DemTarget::observable_id(k));\n        }\n    };\n\n    bool has_coords = false;\n    std::map<uint64_t, std::vector<double>> cached_coords;\n    auto get_coords_cached = [&]() -> const std::map<uint64_t, std::vector<double>> & {\n        std::set<uint64_t> all_dets;\n        for (uint64_t k = 0; k < stats.num_detectors; k++) {\n            all_dets.insert(k);\n        }\n        if (!has_coords) {\n            cached_coords = circuit.get_detector_coordinates(all_dets);\n            has_coords = true;\n        }\n        return cached_coords;\n    };\n\n    if (included_targets_filter.is_none()) {\n        add_all_dets();\n        add_all_obs();\n        return result;\n    }\n    for (const auto &filter : included_targets_filter) {\n        bool fail = false;\n        if (pybind11::isinstance<ExposedDemTarget>(filter)) {\n            result.insert(pybind11::cast<ExposedDemTarget>(filter));\n        } else if (pybind11::isinstance<pybind11::str>(filter)) {\n            std::string_view s = pybind11::cast<std::string_view>(filter);\n            if (s == \"D\") {\n                add_all_dets();\n            } else if (s == \"L\") {\n                add_all_obs();\n            } else if (s.starts_with(\"D\") || s.starts_with(\"L\")) {\n                result.insert(DemTarget::from_text(s));\n            } else {\n                fail = true;\n            }\n        } else {\n            std::vector<double> prefix;\n            for (auto e : filter) {\n                if (pybind11::isinstance<pybind11::int_>(e) || pybind11::isinstance<pybind11::float_>(e)) {\n                    prefix.push_back(pybind11::cast<double>(e));\n                } else {\n                    fail = true;\n                    break;\n                }\n            }\n            if (!fail) {\n                for (const auto &[target, coord] : get_coords_cached()) {\n                    if (coord.size() >= prefix.size()) {\n                        bool match = true;\n                        for (size_t k = 0; k < prefix.size(); k++) {\n                            match &= prefix[k] == coord[k];\n                        }\n                        if (match) {\n                            result.insert(DemTarget::relative_detector_id(target));\n                        }\n                    }\n                }\n            }\n        }\n        if (fail) {\n            std::stringstream ss;\n            ss << \"Don't know how to interpret '\";\n            ss << pybind11::cast<std::string_view>(pybind11::repr(filter));\n            ss << \"' as a dem target filter.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n    return result;\n}\n\nvoid stim_pybind::pybind_circuit_methods_extra(pybind11::module &, pybind11::class_<Circuit> &c) {\n    c.def(\n        \"detecting_regions\",\n        [](const Circuit &self,\n           const pybind11::object &included_targets,\n           const pybind11::object &included_ticks,\n           bool ignore_anticommutation_errors) -> std::map<ExposedDemTarget, std::map<uint64_t, FlexPauliString>> {\n            auto stats = self.compute_stats();\n            auto included_target_set = py_dem_filter_to_dem_target_set(self, stats, included_targets);\n            std::set<uint64_t> included_tick_set;\n\n            if (included_ticks.is_none()) {\n                for (uint64_t k = 0; k < stats.num_ticks; k++) {\n                    included_tick_set.insert(k);\n                }\n            } else {\n                for (const auto &t : included_ticks) {\n                    included_tick_set.insert(pybind11::cast<uint64_t>(t));\n                }\n            }\n            auto result = circuit_to_detecting_regions(\n                self, included_target_set, included_tick_set, ignore_anticommutation_errors);\n            std::map<ExposedDemTarget, std::map<uint64_t, FlexPauliString>> exposed_result;\n            for (const auto &[k, v] : result) {\n                exposed_result.insert({ExposedDemTarget(k), std::move(v)});\n            }\n            return exposed_result;\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"targets\") = pybind11::none(),\n        pybind11::arg(\"ticks\") = pybind11::none(),\n        pybind11::arg(\"ignore_anticommutation_errors\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def detecting_regions(self, *, targets: Optional[Iterable[stim.DemTarget | str | Iterable[float]]] = None, ticks: Optional[Iterable[int]] = None) -> Dict[stim.DemTarget, Dict[int, stim.PauliString]]:\n            Records where detectors and observables are sensitive to errors over time.\n\n            The result of this method is a nested dictionary, mapping detectors/observables\n            and ticks to Pauli sensitivities for that detector/observable at that time.\n\n            For example, if observable 2 has Z-type sensitivity on qubits 5 and 6 during\n            tick 3, then `result[stim.target_logical_observable_id(2)][3]` will be equal to\n            `stim.PauliString(\"Z5*Z6\")`.\n\n            If you want sensitivities from more places in the circuit, besides just at the\n            TICK instructions, you can work around this by making a version of the circuit\n            with more TICKs.\n\n            Args:\n                targets: Defaults to everything (None).\n\n                    When specified, this should be an iterable of filters where items\n                    matching any one filter are included.\n\n                    A variety of filters are supported:\n                        stim.DemTarget: Includes the targeted detector or observable.\n                        Iterable[float]: Coordinate prefix match. Includes detectors whose\n                            coordinate data begins with the same floats.\n                        \"D\": Includes all detectors.\n                        \"L\": Includes all observables.\n                        \"D#\" (e.g. \"D5\"): Includes the detector with the specified index.\n                        \"L#\" (e.g. \"L5\"): Includes the observable with the specified index.\n\n                ticks: Defaults to everything (None).\n                    When specified, this should be a list of integers corresponding to\n                    the tick indices to report sensitivities for.\n\n                ignore_anticommutation_errors: Defaults to False.\n                    When set to False, invalid detecting regions that anticommute with a\n                    reset will cause the method to raise an exception. When set to True,\n                    the offending component will simply be silently dropped. This can\n                    result in broken detectors having apparently enormous detecting\n                    regions.\n\n            Returns:\n                Nested dictionaries keyed first by a `stim.DemTarget` identifying the\n                detector or observable, then by the index of the tick, leading to a\n                PauliString with that target's error sensitivity at that tick.\n\n                Note you can use `stim.PauliString.pauli_indices` to quickly get to the\n                non-identity terms in the sensitivity.\n\n            Examples:\n                >>> import stim\n\n                >>> detecting_regions = stim.Circuit('''\n                ...     R 0\n                ...     TICK\n                ...     H 0\n                ...     TICK\n                ...     CX 0 1\n                ...     TICK\n                ...     MX 0 1\n                ...     DETECTOR rec[-1] rec[-2]\n                ... ''').detecting_regions()\n                >>> for target, tick_regions in detecting_regions.items():\n                ...     print(\"target\", target)\n                ...     for tick, sensitivity in tick_regions.items():\n                ...         print(\"    tick\", tick, \"=\", sensitivity)\n                target D0\n                    tick 0 = +Z_\n                    tick 1 = +X_\n                    tick 2 = +XX\n\n                >>> circuit = stim.Circuit.generated(\n                ...     \"surface_code:rotated_memory_x\",\n                ...     rounds=5,\n                ...     distance=4,\n                ... )\n\n                >>> detecting_regions = circuit.detecting_regions(\n                ...     targets=[\"L0\", (2, 4), stim.DemTarget.relative_detector_id(5)],\n                ...     ticks=range(5, 15),\n                ... )\n                >>> for target, tick_regions in detecting_regions.items():\n                ...     print(\"target\", target)\n                ...     for tick, sensitivity in tick_regions.items():\n                ...         print(\"    tick\", tick, \"=\", sensitivity)\n                target D1\n                    tick 5 = +____________________X______________________\n                    tick 6 = +____________________Z______________________\n                target D5\n                    tick 5 = +______X____________________________________\n                    tick 6 = +______Z____________________________________\n                target D14\n                    tick 5 = +__________X_X______XXX_____________________\n                    tick 6 = +__________X_X______XZX_____________________\n                    tick 7 = +__________X_X______XZX_____________________\n                    tick 8 = +__________X_X______XXX_____________________\n                    tick 9 = +__________XXX_____XXX______________________\n                    tick 10 = +__________XXX_______X______________________\n                    tick 11 = +__________X_________X______________________\n                    tick 12 = +____________________X______________________\n                    tick 13 = +____________________Z______________________\n                target D29\n                    tick 7 = +____________________Z______________________\n                    tick 8 = +____________________X______________________\n                    tick 9 = +____________________XX_____________________\n                    tick 10 = +___________________XXX_______X_____________\n                    tick 11 = +____________X______XXXX______X_____________\n                    tick 12 = +__________X_X______XXX_____________________\n                    tick 13 = +__________X_X______XZX_____________________\n                    tick 14 = +__________X_X______XZX_____________________\n                target D44\n                    tick 14 = +____________________Z______________________\n                target L0\n                    tick 5 = +_X________X________X________X______________\n                    tick 6 = +_X________X________X________X______________\n                    tick 7 = +_X________X________X________X______________\n                    tick 8 = +_X________X________X________X______________\n                    tick 9 = +_X________X_______XX________X______________\n                    tick 10 = +_X________X________X________X______________\n                    tick 11 = +_X________XX_______X________XX_____________\n                    tick 12 = +_X________X________X________X______________\n                    tick 13 = +_X________X________X________X______________\n                    tick 14 = +_X________X________X________X______________\n            )DOC\")\n            .data());\n\n    c.def(\n        \"count_determined_measurements\",\n        &count_determined_measurements<MAX_BITWORD_WIDTH>,\n        pybind11::kw_only(),\n        pybind11::arg(\"unknown_input\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def count_determined_measurements(self, *, unknown_input: bool = False) -> int:\n            Counts the number of predictable measurements in the circuit.\n\n            This method ignores any noise in the circuit.\n\n            This method works by performing a tableau stabilizer simulation of the circuit\n            and, before each measurement is simulated, checking if its expectation is\n            non-zero.\n\n            A measurement is predictable if its result can be predicted by using other\n            measurements that have already been performed, assuming the circuit is executed\n            without any noise.\n\n            Note that, when multiple measurements occur at the same time, re-ordering the\n            order they are resolved can change which specific measurements are predictable\n            but won't change how many of them were predictable in total.\n\n            The number of predictable measurements is a useful quantity because it's\n            related to the number of detectors and observables that a circuit should\n            declare. If circuit.num_detectors + circuit.num_observables is less than\n            circuit.count_determined_measurements(), this is a warning sign that you've\n            missed some detector declarations.\n\n            The exact relationship between the number of determined measurements and the\n            number of detectors and observables can differ from code to code. For example,\n            the toric code has an extra redundant measurement compared to the surface code\n            because in the toric code the last X stabilizer to be measured is equal to the\n            product of all other X stabilizers even in the first round when initializing in\n            the Z basis. Typically this relationship is not declared as a detector, because\n            it's not local, or as an observable, because it doesn't store a qubit.\n\n            Args:\n                unknown_input: Defaults to False (inputs assumed to be in the |0> state).\n                    When set to True, the inputs are instead treated as being in unknown\n                    random states. For example, this means that Z-basis measurements at\n                    the very beginning of the circuit will be considered random rather\n                    than determined.\n\n            Returns:\n                The number of measurements that were predictable.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     R 0\n                ...     M 0\n                ... ''').count_determined_measurements()\n                1\n\n                >>> stim.Circuit('''\n                ...     R 0\n                ...     H 0\n                ...     M 0\n                ... ''').count_determined_measurements()\n                0\n\n                >>> stim.Circuit('''\n                ...     M 0\n                ... ''').count_determined_measurements()\n                1\n\n                >>> stim.Circuit('''\n                ...     M 0\n                ... ''').count_determined_measurements(unknown_input=True)\n                0\n\n                >>> stim.Circuit('''\n                ...     M 0\n                ...     M 0 1\n                ...     M 0 1 2\n                ...     M 0 1 2 3\n                ... ''').count_determined_measurements(unknown_input=True)\n                6\n\n                >>> stim.Circuit('''\n                ...     R 0 1\n                ...     MZZ 0 1\n                ...     MYY 0 1\n                ...     MXX 0 1\n                ... ''').count_determined_measurements()\n                2\n\n                >>> circuit = stim.Circuit.generated(\n                ...     \"surface_code:rotated_memory_x\",\n                ...     distance=5,\n                ...     rounds=9,\n                ... )\n                >>> circuit.count_determined_measurements()\n                217\n                >>> circuit.num_detectors + circuit.num_observables\n                217\n        )DOC\")\n            .data());\n\n    c.def(\n        \"missing_detectors\",\n        &missing_detectors,\n        pybind11::kw_only(),\n        pybind11::arg(\"unknown_input\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def missing_detectors(self, *, unknown_input: bool = False) -> int:\n            Finds deterministic measurements independent of declared detectors/observables.\n\n            This method is useful for debugging missing detectors in a circuit, because it\n            identifies generators for uncovered degrees of freedom.\n\n            It's not recommended to use this method to solve for the detectors of a circuit.\n            The returned detectors are not guaranteed to be stable across versions, and\n            aren't optimized to be \"good\" (e.g. form a low weight basis or be matchable\n            if possible). It will also identify things that are technically determined\n            but that the user may not want to use as a detector, such as the fact that\n            in the first round after transversal Z basis initialization of a toric code\n            the product of all X stabilizer measurements is deterministic even though the\n            individual measurements are all random.\n\n            Args:\n                unknown_input: Defaults to False (inputs assumed to be in the |0> state).\n                    When set to True, the inputs are instead treated as being in unknown\n                    random states. For example, this means that Z-basis measurements at\n                    the very beginning of the circuit will be considered random rather\n                    than determined.\n\n            Returns:\n                A circuit containing DETECTOR instructions that specify the uncovered\n                degrees of freedom in the deterministic measurement sets of the input\n                circuit. The returned circuit can be appended to the input circuit to\n                get a circuit with no missing detectors.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     R 0\n                ...     M 0\n                ... ''').missing_detectors()\n                stim.Circuit('''\n                    DETECTOR rec[-1]\n                ''')\n\n                >>> stim.Circuit('''\n                ...     MZZ 0 1\n                ...     MYY 0 1\n                ...     MXX 0 1\n                ...     DEPOLARIZE1(0.1) 0 1\n                ...     MZZ 0 1\n                ...     MYY 0 1\n                ...     MXX 0 1\n                ...     DETECTOR rec[-1] rec[-4]\n                ...     DETECTOR rec[-2] rec[-5]\n                ...     DETECTOR rec[-3] rec[-6]\n                ... ''').missing_detectors(unknown_input=True)\n                stim.Circuit('''\n                    DETECTOR rec[-3] rec[-2] rec[-1]\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_tableau\",\n        [](const Circuit &circuit, bool ignore_noise, bool ignore_measurement, bool ignore_reset) {\n            return circuit_to_tableau<MAX_BITWORD_WIDTH>(circuit, ignore_noise, ignore_measurement, ignore_reset);\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"ignore_noise\") = false,\n        pybind11::arg(\"ignore_measurement\") = false,\n        pybind11::arg(\"ignore_reset\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def to_tableau(self, *, ignore_noise: bool = False, ignore_measurement: bool = False, ignore_reset: bool = False) -> stim.Tableau:\n            Converts the circuit into an equivalent stabilizer tableau.\n\n            Args:\n                ignore_noise: Defaults to False. When False, any noise operations in the\n                    circuit will cause the conversion to fail with an exception. When True,\n                    noise operations are skipped over as if they weren't even present in the\n                    circuit.\n                ignore_measurement: Defaults to False. When False, any measurement\n                    operations in the circuit will cause the conversion to fail with an\n                    exception. When True, measurement operations are skipped over as if they\n                    weren't even present in the circuit.\n                ignore_reset: Defaults to False. When False, any reset operations in the\n                    circuit will cause the conversion to fail with an exception. When True,\n                    reset operations are skipped over as if they weren't even present in the\n                    circuit.\n\n            Returns:\n                A tableau equivalent to the circuit (up to global phase).\n\n            Raises:\n                ValueError:\n                    The circuit contains noise operations but ignore_noise=False.\n                    OR\n                    The circuit contains measurement operations but\n                    ignore_measurement=False.\n                    OR\n                    The circuit contains reset operations but ignore_reset=False.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...     H 0\n                ...     CNOT 0 1\n                ... ''').to_tableau()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z_\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+XX\"),\n                        stim.PauliString(\"+ZZ\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_qasm\",\n        [](const Circuit &self, int open_qasm_version, bool skip_dets_and_obs) -> std::string {\n            std::stringstream out;\n            export_open_qasm(self, out, open_qasm_version, skip_dets_and_obs);\n            return out.str();\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"open_qasm_version\"),\n        pybind11::arg(\"skip_dets_and_obs\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def to_qasm(self, *, open_qasm_version: int, skip_dets_and_obs: bool = False) -> str:\n            Creates an equivalent OpenQASM implementation of the circuit.\n\n            Args:\n                open_qasm_version: The version of OpenQASM to target.\n                    This should be set to 2 or to 3.\n\n                    Differences between the versions are:\n                        - Support for operations on classical bits (only version 3).\n                            This means DETECTOR and OBSERVABLE_INCLUDE only work with\n                            version 3.\n                        - Support for feedback operations (only version 3).\n                        - Support for subroutines (only version 3). Without subroutines,\n                            non-standard dissipative gates like MR and RX need to decompose\n                            inline every single time they're used.\n                        - Minor name changes (e.g. creg -> bit, qelib1.inc -> stdgates.inc).\n                skip_dets_and_obs: Defaults to False. When set to False, the output will\n                    include a `dets` register and an `obs` register (assuming the circuit\n                    has detectors and observables). These registers will be computed as part\n                    of running the circuit. This requires performing a simulation of the\n                    circuit, in order to correctly account for the expected value of\n                    measurements.\n\n                    When set to True, the `dets` and `obs` registers are not included in the\n                    output, and no simulation of the circuit is performed.\n\n            Returns:\n                The OpenQASM code as a string.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     R 0 1\n                ...     X 1\n                ...     H 0\n                ...     CX 0 1\n                ...     M 0 1\n                ...     DETECTOR rec[-1] rec[-2]\n                ... ''');\n                >>> qasm = circuit.to_qasm(open_qasm_version=3);\n                >>> print(qasm.strip().replace('\\n\\n', '\\n'))\n                OPENQASM 3.0;\n                include \"stdgates.inc\";\n                qreg q[2];\n                creg rec[2];\n                creg dets[1];\n                reset q[0];\n                reset q[1];\n                x q[1];\n                h q[0];\n                cx q[0], q[1];\n                measure q[0] -> rec[0];\n                measure q[1] -> rec[1];\n                dets[0] = rec[1] ^ rec[0] ^ 1;\n        )DOC\")\n            .data());\n\n    c.def(\n        \"has_flow\",\n        [](const Circuit &self, const Flow<MAX_BITWORD_WIDTH> &flow, bool unsigned_only) -> bool {\n            std::span<const Flow<MAX_BITWORD_WIDTH>> flows = {&flow, &flow + 1};\n            if (unsigned_only) {\n                return check_if_circuit_has_unsigned_stabilizer_flows<MAX_BITWORD_WIDTH>(self, flows)[0];\n            } else {\n                auto rng = externally_seeded_rng();\n                return sample_if_circuit_has_stabilizer_flows<MAX_BITWORD_WIDTH>(256, rng, self, flows)[0];\n            }\n        },\n        pybind11::arg(\"flow\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"unsigned\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def has_flow(self, flow: stim.Flow, *, unsigned: bool = False) -> bool:\n            Determines if the circuit has the given stabilizer flow or not.\n\n            A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer\n            P at the start of the circuit to the instantaneous stabilizer Q at the end of\n            the circuit. The flow may be mediated by certain measurements. For example,\n            a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and\n            the CNOT flows implemented by the circuit involve these measurements.\n\n            A flow like P -> Q means the circuit transforms P into Q.\n            A flow like 1 -> P means the circuit prepares P.\n            A flow like P -> 1 means the circuit measures P.\n            A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR).\n\n            This method ignores any noise in the circuit.\n\n            Args:\n                flow: The flow to check for.\n                unsigned: Defaults to False. When False, the flows must be correct including\n                    the sign of the Pauli strings. When True, only the Pauli terms need to\n                    be correct; the signs are permitted to be inverted. In effect, this\n                    requires the circuit to be correct up to Pauli gates.\n\n            Returns:\n                True if the circuit has the given flow; False otherwise.\n\n            Examples:\n                >>> import stim\n\n                >>> m = stim.Circuit('M 0')\n                >>> m.has_flow(stim.Flow('Z -> Z'))\n                True\n                >>> m.has_flow(stim.Flow('X -> X'))\n                False\n                >>> m.has_flow(stim.Flow('Z -> I'))\n                False\n                >>> m.has_flow(stim.Flow('Z -> I xor rec[-1]'))\n                True\n                >>> m.has_flow(stim.Flow('Z -> rec[-1]'))\n                True\n\n                >>> cx58 = stim.Circuit('CX 5 8')\n                >>> cx58.has_flow(stim.Flow('X5 -> X5*X8'))\n                True\n                >>> cx58.has_flow(stim.Flow('X_ -> XX'))\n                False\n                >>> cx58.has_flow(stim.Flow('_____X___ -> _____X__X'))\n                True\n\n                >>> stim.Circuit('''\n                ...     RY 0\n                ... ''').has_flow(stim.Flow(\n                ...     output=stim.PauliString(\"Y\"),\n                ... ))\n                True\n\n                >>> stim.Circuit('''\n                ...     RY 0\n                ...     X_ERROR(0.1) 0\n                ... ''').has_flow(stim.Flow(\n                ...     output=stim.PauliString(\"Y\"),\n                ... ))\n                True\n\n                >>> stim.Circuit('''\n                ...     RY 0\n                ... ''').has_flow(stim.Flow(\n                ...     output=stim.PauliString(\"X\"),\n                ... ))\n                False\n\n                >>> stim.Circuit('''\n                ...     CX 0 1\n                ... ''').has_flow(stim.Flow(\n                ...     input=stim.PauliString(\"+X_\"),\n                ...     output=stim.PauliString(\"+XX\"),\n                ... ))\n                True\n\n                >>> stim.Circuit('''\n                ...     # Lattice surgery CNOT\n                ...     R 1\n                ...     MXX 0 1\n                ...     MZZ 1 2\n                ...     MX 1\n                ... ''').has_flow(stim.Flow(\n                ...     input=stim.PauliString(\"+X_X\"),\n                ...     output=stim.PauliString(\"+__X\"),\n                ...     measurements=[0, 2],\n                ... ))\n                True\n\n                >>> stim.Circuit('''\n                ...     H 0\n                ... ''').has_flow(\n                ...     stim.Flow(\"Y -> Y\"),\n                ...     unsigned=True,\n                ... )\n                True\n\n                >>> stim.Circuit('''\n                ...     H 0\n                ... ''').has_flow(\n                ...     stim.Flow(\"Y -> Y\"),\n                ...     unsigned=False,\n                ... )\n                False\n\n            Caveats:\n                Currently, the unsigned=False version of this method is implemented by\n                performing 256 randomized tests. Each test has a 50% chance of a false\n                positive, and a 0% chance of a false negative. So, when the method returns\n                True, there is technically still a 2^-256 chance the circuit doesn't have\n                the flow. This is lower than the chance of a cosmic ray flipping the result.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"has_all_flows\",\n        [](const Circuit &self, const std::vector<Flow<MAX_BITWORD_WIDTH>> &flows, bool unsigned_only) -> bool {\n            std::vector<bool> results;\n            if (unsigned_only) {\n                results = check_if_circuit_has_unsigned_stabilizer_flows<MAX_BITWORD_WIDTH>(self, flows);\n            } else {\n                auto rng = externally_seeded_rng();\n                results = sample_if_circuit_has_stabilizer_flows<MAX_BITWORD_WIDTH>(256, rng, self, flows);\n            }\n            for (bool b : results) {\n                if (!b) {\n                    return false;\n                }\n            }\n            return true;\n        },\n        pybind11::arg(\"flows\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"unsigned\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def has_all_flows(self, flows: Iterable[stim.Flow], *, unsigned: bool = False) -> bool:\n            Determines if the circuit has all the given stabilizer flow or not.\n\n            This is a faster version of `all(c.has_flow(f) for f in flows)`. It's faster\n            because, behind the scenes, the circuit can be iterated once instead of once\n            per flow.\n\n            This method ignores any noise in the circuit.\n\n            Args:\n                flows: An iterable of `stim.Flow` instances representing the flows to check.\n                unsigned: Defaults to False. When False, the flows must be correct including\n                    the sign of the Pauli strings. When True, only the Pauli terms need to\n                    be correct; the signs are permitted to be inverted. In effect, this\n                    requires the circuit to be correct up to Pauli gates.\n\n            Returns:\n                True if the circuit has the given flow; False otherwise.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('H 0').has_all_flows([\n                ...     stim.Flow('X -> Z'),\n                ...     stim.Flow('Y -> Y'),\n                ...     stim.Flow('Z -> X'),\n                ... ])\n                False\n\n                >>> stim.Circuit('H 0').has_all_flows([\n                ...     stim.Flow('X -> Z'),\n                ...     stim.Flow('Y -> -Y'),\n                ...     stim.Flow('Z -> X'),\n                ... ])\n                True\n\n                >>> stim.Circuit('H 0').has_all_flows([\n                ...     stim.Flow('X -> Z'),\n                ...     stim.Flow('Y -> Y'),\n                ...     stim.Flow('Z -> X'),\n                ... ], unsigned=True)\n                True\n\n            Caveats:\n                Currently, the unsigned=False version of this method is implemented by\n                performing 256 randomized tests. Each test has a 50% chance of a false\n                positive, and a 0% chance of a false negative. So, when the method returns\n                True, there is technically still a 2^-256 chance the circuit doesn't have\n                the flow. This is lower than the chance of a cosmic ray flipping the result.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"flow_generators\",\n        &circuit_flow_generators<MAX_BITWORD_WIDTH>,\n        clean_doc_string(R\"DOC(\n            @signature def flow_generators(self) -> List[stim.Flow]:\n            Returns a list of flows that generate all of the circuit's flows.\n\n            Every stabilizer flow that the circuit implements is a product of some\n            subset of the returned generators. Every returned flow will be a flow\n            of the circuit.\n\n            Returns:\n                A list of flow generators for the circuit.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit(\"H 0\").flow_generators()\n                [stim.Flow(\"X -> Z\"), stim.Flow(\"Z -> X\")]\n\n                >>> stim.Circuit(\"M 0\").flow_generators()\n                [stim.Flow(\"1 -> Z xor rec[0]\"), stim.Flow(\"Z -> rec[0]\")]\n\n                >>> stim.Circuit(\"RX 0\").flow_generators()\n                [stim.Flow(\"1 -> X\")]\n\n                >>> for flow in stim.Circuit(\"MXX 0 1\").flow_generators():\n                ...     print(flow)\n                1 -> XX xor rec[0]\n                _X -> _X\n                X_ -> _X xor rec[0]\n                ZZ -> ZZ\n\n                >>> for flow in stim.Circuit.generated(\n                ...     \"repetition_code:memory\",\n                ...     rounds=2,\n                ...     distance=3,\n                ...     after_clifford_depolarization=1e-3,\n                ... ).flow_generators():\n                ...     print(flow)\n                1 -> rec[0]\n                1 -> rec[1]\n                1 -> rec[2]\n                1 -> rec[3]\n                1 -> rec[4]\n                1 -> rec[5]\n                1 -> rec[6]\n                1 -> ____Z\n                1 -> ___Z_\n                1 -> __Z__\n                1 -> _Z___\n                1 -> Z____\n        )DOC\")\n            .data());\n\n    c.def(\n        \"solve_flow_measurements\",\n        [](const Circuit &self, const std::vector<Flow<MAX_BITWORD_WIDTH>> &flows) -> pybind11::object {\n            std::span<const Flow<MAX_BITWORD_WIDTH>> flows_span = flows;\n            auto solution = solve_for_flow_measurements(self, flows_span);\n            std::vector<pybind11::object> result;\n            for (const auto &e : solution) {\n                if (e.has_value()) {\n                    result.push_back(pybind11::cast(*e));\n                } else {\n                    result.push_back(pybind11::none());\n                }\n            }\n            return pybind11::cast(result);\n        },\n        clean_doc_string(R\"DOC(\n            @signature def solve_flow_measurements(self, flows: List[stim.Flow]) -> List[Optional[List[int]]]:\n            Finds measurements to explain the starts/ends of the given flows, ignoring sign.\n\n            CAUTION: it's not guaranteed that the solutions returned by this method are\n            minimal. It may use 20 measurements when only 2 are needed. The method applies\n            some simple heuristics that attempt to reduce the size, but these heuristics\n            aren't perfect and don't make any strong guarantees.\n\n            The recommended way to use this method is on small parts of a circuit, such as a\n            single surface code round. The ideal use case is when there is exactly one\n            solution for each flow, because then the method behaves predictably and\n            consistently. When there are multiple solutions, the method has no real way to\n            pick out a \"good\" solution rather than a \"cataclysmic trash fire of a\" solution.\n            For example, if you have a multi-round surface code circuit with open time\n            boundaries and solve the flow 1 -> Z1*Z2*Z3*Z4, then there's a good solution\n            (the Z1*Z2*Z3*Z4 measurement from the last round), various mediocre solutions\n            (a Z1*Z2*Z3*Z4 measurement from a different round), and lots of terrible\n            solutions (a combination of multiple Z1*Z2*Z3*Z4 measurements from an odd number\n            of rounds, times a random combination of unrelated detectors). The method is\n            permitted to return any of those solutions.\n\n            Args:\n                flows: A list of flows, each of which to be solved. Measurements and signs\n                    are entirely ignored.\n\n                    An error is raised if one of the given flows has an identity pauli\n                    string as its input and as its output, despite the fact that this case\n                    has a vacuous solution (no measurements). This error is only present as\n                    a safety check that catches some possible bugs in the calling code, such\n                    as accidentally applying this method to detector flows. This error may\n                    be removed in the future, so that the vacuous case succeeds vacuously.\n\n            Returns:\n                A list of solutions for each given flow.\n\n                If no solution exists for flows[k], then solutions[k] is None.\n                Otherwise, solutions[k] is a list of measurement indices for flows[k].\n\n                When solutions[k] is not None, it's guaranteed that\n\n                    circuit.has_flow(stim.Flow(\n                        input=flows[k].input,\n                        output=flows[k].output,\n                        measurements=solutions[k],\n                    ), unsigned=True)\n\n            Raises:\n                ValueError:\n                    A flow had an empty input and output.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     M 2\n                ... ''').solve_flow_measurements([\n                ...     stim.Flow(\"Z2 -> 1\"),\n                ... ])\n                [[0]]\n\n                >>> stim.Circuit('''\n                ...     M 2\n                ... ''').solve_flow_measurements([\n                ...     stim.Flow(\"X2 -> X2\"),\n                ... ])\n                [None]\n\n                >>> stim.Circuit('''\n                ...     MXX 0 1\n                ... ''').solve_flow_measurements([\n                ...     stim.Flow(\"YY -> ZZ\"),\n                ... ])\n                [[0]]\n\n                >>> # Rep code cycle\n                >>> stim.Circuit('''\n                ...     R 1 3\n                ...     CX 0 1 2 3\n                ...     CX 4 3 2 1\n                ...     M 1 3\n                ... ''').solve_flow_measurements([\n                ...     stim.Flow(\"1 -> Z0*Z4\"),\n                ...     stim.Flow(\"Z0 -> Z2\"),\n                ...     stim.Flow(\"X0*X2*X4 -> X0*X2*X4\"),\n                ...     stim.Flow(\"Y0 -> Y0\"),\n                ... ])\n                [[0, 1], [0], [], None]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"time_reversed_for_flows\",\n        [](const Circuit &self,\n           const std::vector<Flow<MAX_BITWORD_WIDTH>> &flows,\n           bool dont_turn_measurements_into_resets) -> pybind11::object {\n            auto [inv_circuit, inv_flows] =\n                circuit_inverse_qec<MAX_BITWORD_WIDTH>(self, flows, dont_turn_measurements_into_resets);\n            return pybind11::make_tuple(inv_circuit, inv_flows);\n        },\n        pybind11::arg(\"flows\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"dont_turn_measurements_into_resets\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def time_reversed_for_flows(self, flows: Iterable[stim.Flow], *, dont_turn_measurements_into_resets: bool = False) -> Tuple[stim.Circuit, List[stim.Flow]]:\n            Time-reverses the circuit while preserving error correction structure.\n\n            This method returns a circuit that has the same internal detecting regions\n            as the given circuit, as well as the same internal-to-external flows given\n            in the `flows` argument, except they are all time-reversed. For example, if\n            you pass a fault tolerant preparation circuit into this method (1 -> Z), the\n            result will be a fault tolerant *measurement* circuit (Z -> 1). Or, if you\n            pass a fault tolerant C_XYZ circuit into this method (X->Y, Y->Z, and Z->X),\n            the result will be a fault tolerant C_ZYX circuit (X->Z, Y->X, and Z->Y).\n\n            Note that this method doesn't guarantee that it will preserve the *sign* of the\n            detecting regions or stabilizer flows. For example, inverting a memory circuit\n            that preserves a logical observable (X->X and Z->Z) may produce a\n            memory circuit that always bit flips the logical observable (X->X and Z->-Z) or\n            that dynamically adjusts the logical observable in response to measurements\n            (like \"X -> X xor rec[-1]\" and \"Z -> Z xor rec[-2]\").\n\n            This method will turn time-reversed resets into measurements, and attempts to\n            turn time-reversed measurements into resets. A measurement will time-reverse\n            into a reset if some annotated detectors, annotated observables, or given flows\n            have detecting regions with sensitivity just before the measurement but none\n            have detecting regions with sensitivity after the measurement.\n\n            In some cases this method will have to introduce new operations. In particular,\n            when a measurement-reset operation has a noisy result, time-reversing this\n            measurement noise produces reset noise. But the measure-reset operations don't\n            have built-in reset noise, so the reset noise is specified by adding an X_ERROR\n            or Z_ERROR noise instruction after the time-reversed measure-reset operation.\n\n            Args:\n                flows: Flows you care about, that reach past the start/end of the given\n                    circuit. The result will contain an inverted flow for each of these\n                    given flows. You need this information because it reveals the\n                    measurements needed to produce the inverted flows that you care\n                    about.\n\n                    An exception will be raised if the circuit doesn't have all these\n                    flows. The inverted circuit will have the inverses of these flows\n                    (ignoring sign).\n                dont_turn_measurements_into_resets: Defaults to False. When set to\n                    True, measurements will time-reverse into measurements even if\n                    nothing is sensitive to the measured qubit after the measurement\n                    completes. This guarantees the output circuit has *all* flows\n                    that the input circuit has (up to sign and feedback), even ones\n                    that aren't annotated.\n\n            Returns:\n                An (inverted_circuit, inverted_flows) tuple.\n\n                inverted_circuit is the qec inverse of the given circuit.\n\n                inverted_flows is a list of flows, matching up by index with the flows\n                given as arguments to the method. The input, output, and sign fields\n                of these flows are boring. The useful field is measurement_indices,\n                because it's difficult to predict which measurements are needed for\n                the inverted flow due to effects such as implicitly-included resets\n                inverting into explicitly-included measurements.\n\n            Caveats:\n                Currently, this method doesn't compute the sign of the inverted flows.\n                It unconditionally sets the sign to False.\n\n            Examples:\n                >>> import stim\n\n                >>> inv_circuit, inv_flows = stim.Circuit('''\n                ...     R 0\n                ...     H 0\n                ...     S 0\n                ...     MY 0\n                ...     DETECTOR rec[-1]\n                ... ''').time_reversed_for_flows([])\n                >>> inv_circuit\n                stim.Circuit('''\n                    RY 0\n                    S_DAG 0\n                    H 0\n                    M 0\n                    DETECTOR rec[-1]\n                ''')\n                >>> inv_flows\n                []\n\n                >>> inv_circuit, inv_flows = stim.Circuit('''\n                ...     M 0\n                ... ''').time_reversed_for_flows([\n                ...     stim.Flow(\"Z -> rec[-1]\"),\n                ... ])\n                >>> inv_circuit\n                stim.Circuit('''\n                    R 0\n                ''')\n                >>> inv_flows\n                [stim.Flow(\"1 -> Z\")]\n                >>> inv_circuit.has_all_flows(inv_flows, unsigned=True)\n                True\n\n                >>> inv_circuit, inv_flows = stim.Circuit('''\n                ...     R 0\n                ... ''').time_reversed_for_flows([\n                ...     stim.Flow(\"1 -> Z\"),\n                ... ])\n                >>> inv_circuit\n                stim.Circuit('''\n                    M 0\n                ''')\n                >>> inv_flows\n                [stim.Flow(\"Z -> rec[-1]\")]\n\n                >>> inv_circuit, inv_flows = stim.Circuit('''\n                ...     M 0\n                ... ''').time_reversed_for_flows([\n                ...     stim.Flow(\"1 -> Z xor rec[-1]\"),\n                ... ])\n                >>> inv_circuit\n                stim.Circuit('''\n                    M 0\n                ''')\n                >>> inv_flows\n                [stim.Flow(\"Z -> rec[-1]\")]\n\n                >>> inv_circuit, inv_flows = stim.Circuit('''\n                ...     M 0\n                ... ''').time_reversed_for_flows(\n                ...     flows=[stim.Flow(\"Z -> rec[-1]\")],\n                ...     dont_turn_measurements_into_resets=True,\n                ... )\n                >>> inv_circuit\n                stim.Circuit('''\n                    M 0\n                ''')\n                >>> inv_flows\n                [stim.Flow(\"1 -> Z xor rec[-1]\")]\n\n                >>> inv_circuit, inv_flows = stim.Circuit('''\n                ...     MR(0.125) 0\n                ... ''').time_reversed_for_flows([])\n                >>> inv_circuit\n                stim.Circuit('''\n                    MR 0\n                    X_ERROR(0.125) 0\n                ''')\n                >>> inv_flows\n                []\n\n                >>> inv_circuit, inv_flows = stim.Circuit('''\n                ...     MXX 0 1\n                ...     H 0\n                ... ''').time_reversed_for_flows([\n                ...     stim.Flow(\"ZZ -> YY xor rec[-1]\"),\n                ...     stim.Flow(\"ZZ -> XZ\"),\n                ... ])\n                >>> inv_circuit\n                stim.Circuit('''\n                    H 0\n                    MXX 0 1\n                ''')\n                >>> inv_flows\n                [stim.Flow(\"YY -> ZZ xor rec[-1]\"), stim.Flow(\"XZ -> ZZ\")]\n\n                >>> stim.Circuit.generated(\n                ...     \"surface_code:rotated_memory_x\",\n                ...     distance=2,\n                ...     rounds=1,\n                ... ).time_reversed_for_flows([])[0]\n                stim.Circuit('''\n                    QUBIT_COORDS(1, 1) 1\n                    QUBIT_COORDS(2, 0) 2\n                    QUBIT_COORDS(3, 1) 3\n                    QUBIT_COORDS(1, 3) 6\n                    QUBIT_COORDS(2, 2) 7\n                    QUBIT_COORDS(3, 3) 8\n                    QUBIT_COORDS(2, 4) 12\n                    RX 8 6 3 1\n                    MR 12 7 2\n                    TICK\n                    H 12 2\n                    TICK\n                    CX 1 7 12 6\n                    TICK\n                    CX 6 7 12 8\n                    TICK\n                    CX 3 7 2 1\n                    TICK\n                    CX 8 7 2 3\n                    TICK\n                    H 12 2\n                    TICK\n                    M 12 7 2\n                    DETECTOR(2, 0, 1) rec[-1]\n                    DETECTOR(2, 4, 1) rec[-3]\n                    MX 8 6 3 1\n                    DETECTOR(2, 0, 0) rec[-5] rec[-2] rec[-1]\n                    DETECTOR(2, 4, 0) rec[-7] rec[-4] rec[-3]\n                    OBSERVABLE_INCLUDE(0) rec[-3] rec[-1]\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_crumble_url\",\n        [](const Circuit &self, bool skip_detectors, pybind11::object &obj_mark) {\n            std::map<int, std::vector<ExplainedError>> mark;\n            if (!obj_mark.is_none()) {\n                mark = pybind11::cast<std::map<int, std::vector<ExplainedError>>>(obj_mark);\n            }\n            return export_crumble_url(self, skip_detectors, mark);\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"skip_detectors\") = false,\n        pybind11::arg(\"mark\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def to_crumble_url(self, *, skip_detectors: bool = False, mark: Optional[dict[int, list[stim.ExplainedError]]] = None) -> str:\n            Returns a URL that opens up crumble and loads this circuit into it.\n\n            Crumble is a tool for editing stabilizer circuits, and visualizing their\n            stabilizer flows. Its source code is in the `glue/crumble` directory of\n            the stim code repository on github. A prebuilt version is made available\n            at https://algassert.com/crumble, which is what the URL returned by this\n            method will point to.\n\n            Args:\n                skip_detectors: Defaults to False. If set to True, detectors from the\n                    circuit aren't included in the crumble URL. This can reduce visual\n                    clutter in crumble, and improve its performance, since it doesn't\n                    need to indicate or track the sensitivity regions of detectors.\n                mark: Defaults to None (no marks). If set to a dictionary from int to\n                    errors, such as `mark={1: circuit.shortest_graphlike_error()}`,\n                    then the errors will be highlighted and tracked forward by crumble.\n\n            Returns:\n                A URL that can be opened in a web browser.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...     H 0\n                ...     CNOT 0 1\n                ...     S 1\n                ... ''').to_crumble_url()\n                'https://algassert.com/crumble#circuit=H_0;CX_0_1;S_1_'\n\n                >>> circuit = stim.Circuit('''\n                ...     M(0.25) 0 1 2\n                ...     DETECTOR rec[-1] rec[-2]\n                ...     DETECTOR rec[-2] rec[-3]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''')\n                >>> err = circuit.shortest_graphlike_error(canonicalize_circuit_errors=True)\n                >>> circuit.to_crumble_url(skip_detectors=True, mark={1: err})\n                'https://algassert.com/crumble#circuit=;TICK;MARKX(1)1;MARKX(1)2;MARKX(1)0;TICK;M(0.25)0_1_2;OI(0)rec[-1]_'\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_quirk_url\",\n        &export_quirk_url,\n        clean_doc_string(R\"DOC(\n            Returns a URL that opens up quirk and loads this circuit into it.\n\n            Quirk is an open source drag and drop circuit editor with support for up to 16\n            qubits. Its source code is available at https://github.com/strilanc/quirk\n            and a prebuilt version is available at https://algassert.com/quirk, which is\n            what the URL returned by this method will point to.\n\n            Quirk doesn't support features like noise, feedback, or detectors. This method\n            will simply drop any unsupported operations from the circuit when producing\n            the URL.\n\n            Returns:\n                A URL that can be opened in a web browser.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit('''\n                ...     H 0\n                ...     CNOT 0 1\n                ...     S 1\n                ... ''').to_quirk_url()\n                'https://algassert.com/quirk#circuit={\"cols\":[[\"H\"],[\"•\",\"X\"],[1,\"Z^½\"]]}'\n        )DOC\")\n            .data());\n\n    c.def(\n        \"decomposed\",\n        &simplified_circuit,\n        clean_doc_string(R\"DOC(\n            Recreates the circuit using (mostly) the {H,S,CX,M,R} gate set.\n\n            The intent of this method is to simplify the circuit to use fewer gate types,\n            so it's easier for other tools to consume. Currently, this method performs the\n            following simplifications:\n\n            - Single qubit cliffords are decomposed into {H,S}.\n            - Multi-qubit cliffords are decomposed into {H,S,CX}.\n            - Single qubit dissipative gates are decomposed into {H,S,M,R}.\n            - Multi-qubit dissipative gates are decomposed into {H,S,CX,M,R}.\n\n            Currently, the following types of gate *aren't* simplified, but they may be\n            in the future:\n\n            - Noise instructions (like X_ERROR, DEPOLARIZE2, and E).\n            - Annotations (like TICK, DETECTOR, and SHIFT_COORDS).\n            - The MPAD instruction.\n            - Repeat blocks are not flattened.\n\n            Returns:\n                A `stim.Circuit` whose function is equivalent to the original circuit,\n                but with most gates decomposed into the {H,S,CX,M,R} gate set.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     SWAP 0 1\n                ... ''').decomposed()\n                stim.Circuit('''\n                    CX 0 1 1 0 0 1\n                ''')\n\n                >>> stim.Circuit('''\n                ...     ISWAP 0 1 2 1\n                ...     TICK\n                ...     MPP !X1*Y2*Z3\n                ... ''').decomposed()\n                stim.Circuit('''\n                    H 0\n                    CX 0 1 1 0\n                    H 1\n                    S 1 0\n                    H 2\n                    CX 2 1 1 2\n                    H 1\n                    S 1 2\n                    TICK\n                    H 1 2\n                    S 2\n                    H 2\n                    S 2 2\n                    CX 2 1 3 1\n                    M !1\n                    CX 2 1 3 1\n                    H 2\n                    S 2\n                    H 2\n                    S 2 2\n                    H 1\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"with_inlined_feedback\",\n        &circuit_with_inlined_feedback,\n        clean_doc_string(R\"DOC(\n            Returns a circuit without feedback with rewritten detectors/observables.\n\n            When a feedback operation affects the expected parity of a detector or\n            observable, the measurement controlling that feedback operation is implicitly\n            part of the measurement set that defines the detector or observable. This\n            method removes all feedback, but avoids changing the meaning of detectors or\n            observables by turning these implicit measurement dependencies into explicit\n            measurement dependencies added to the observable or detector.\n\n            This method guarantees that the detector error model derived from the original\n            circuit, and the transformed circuit, will be equivalent (modulo floating point\n            rounding errors and variations in where loops are placed). Specifically, the\n            following should be true for any circuit:\n\n                dem1 = circuit.flattened().detector_error_model()\n                dem2 = circuit.with_inlined_feedback().flattened().detector_error_model()\n                assert dem1.approx_equals(dem2, 1e-5)\n\n            Returns:\n                A `stim.Circuit` with feedback operations removed, with rewritten DETECTOR\n                instructions (as needed to avoid changing the meaning of each detector), and\n                with additional OBSERVABLE_INCLUDE instructions (as needed to avoid changing\n                the meaning of each observable).\n\n                The circuit's function is permitted to differ from the original in that\n                any feedback operation can be pushed to the end of the circuit and\n                discarded. All non-feedback operations must stay where they are, preserving\n                the structure of the circuit.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     CX 0 1        # copy to measure qubit\n                ...     M 1           # measure first time\n                ...     CX rec[-1] 1  # use feedback to reset measurement qubit\n                ...     CX 0 1        # copy to measure qubit\n                ...     M 1           # measure second time\n                ...     DETECTOR rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').with_inlined_feedback()\n                stim.Circuit('''\n                    CX 0 1\n                    M 1\n                    OBSERVABLE_INCLUDE(0) rec[-1]\n                    CX 0 1\n                    M 1\n                    DETECTOR rec[-1]\n                    OBSERVABLE_INCLUDE(0) rec[-1]\n                ''')\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit_instruction.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/circuit_instruction.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\n\nuint64_t CircuitInstruction::repeat_block_rep_count() const {\n    assert(targets.size() == 3);\n    uint64_t low = targets[1].data;\n    uint64_t high = targets[2].data;\n    return low | (high << 32);\n}\n\nCircuit &CircuitInstruction::repeat_block_body(Circuit &host) const {\n    assert(targets.size() == 3);\n    auto b = targets[0].data;\n    assert(b < host.blocks.size());\n    return host.blocks[b];\n}\n\nCircuitStats CircuitInstruction::compute_stats(const Circuit *host) const {\n    CircuitStats out;\n    add_stats_to(out, host);\n    return out;\n}\n\nvoid CircuitInstruction::add_stats_to(CircuitStats &out, const Circuit *host) const {\n    if (gate_type == GateType::REPEAT) {\n        if (host == nullptr) {\n            throw std::invalid_argument(\"gate_type == REPEAT && host == nullptr\");\n        }\n        // Recurse into blocks.\n        auto sub = repeat_block_body(*host).compute_stats();\n        auto reps = repeat_block_rep_count();\n        out.num_observables = std::max(out.num_observables, sub.num_observables);\n        out.num_qubits = std::max(out.num_qubits, sub.num_qubits);\n        out.max_lookback = std::max(out.max_lookback, sub.max_lookback);\n        out.num_sweep_bits = std::max(out.num_sweep_bits, sub.num_sweep_bits);\n        out.num_detectors = add_saturate(out.num_detectors, mul_saturate(sub.num_detectors, reps));\n        out.num_measurements = add_saturate(out.num_measurements, mul_saturate(sub.num_measurements, reps));\n        out.num_ticks = add_saturate(out.num_ticks, mul_saturate(sub.num_ticks, reps));\n        return;\n    }\n\n    for (auto t : targets) {\n        auto v = t.data & TARGET_VALUE_MASK;\n        // Qubit counting.\n        if (gate_type != GateType::MPAD) {\n            if (!(t.data & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n                out.num_qubits = std::max(out.num_qubits, v + 1);\n            }\n        }\n        // Lookback counting.\n        if (t.data & TARGET_RECORD_BIT) {\n            out.max_lookback = std::max(out.max_lookback, v);\n        }\n        // Sweep bit counting.\n        if (t.data & TARGET_SWEEP_BIT) {\n            out.num_sweep_bits = std::max(out.num_sweep_bits, v + 1);\n        }\n    }\n\n    // Measurement counting.\n    out.num_measurements += count_measurement_results();\n\n    switch (gate_type) {\n        case GateType::DETECTOR:\n            // Detector counting.\n            out.num_detectors += out.num_detectors < UINT64_MAX;\n            break;\n        case GateType::OBSERVABLE_INCLUDE:\n            // Observable counting.\n            out.num_observables = std::max(out.num_observables, (uint64_t)args[0] + 1);\n            break;\n        case GateType::TICK:\n            // Tick counting.\n            out.num_ticks++;\n            break;\n        default:\n            break;\n    }\n}\n\nconst Circuit &CircuitInstruction::repeat_block_body(const Circuit &host) const {\n    assert(targets.size() == 3);\n    auto b = targets[0].data;\n    assert(b < host.blocks.size());\n    return host.blocks[b];\n}\n\nCircuitInstruction::CircuitInstruction(\n    GateType gate_type, SpanRef<const double> args, SpanRef<const GateTarget> targets, std::string_view tag)\n    : gate_type(gate_type), args(args), targets(targets), tag(tag) {\n}\n\nvoid CircuitInstruction::validate() const {\n    const Gate &gate = GATE_DATA[gate_type];\n\n    if (gate.flags == GateFlags::NO_GATE_FLAG) {\n        throw std::invalid_argument(\"Unrecognized gate_type. Associated flag is NO_GATE_FLAG.\");\n    }\n\n    if (gate.flags & GATE_TARGETS_PAIRS) {\n        if (gate.flags & GATE_TARGETS_PAULI_STRING) {\n            size_t term_count = targets.size();\n            for (auto t : targets) {\n                if (t.is_combiner()) {\n                    term_count -= 2;\n                }\n            }\n            if (term_count & 1) {\n                throw std::invalid_argument(\n                    \"The gate \" + std::string(gate.name) +\n                    \" requires an even number of products to target, but was given \"\n                    \"(\" +\n                    comma_sep(args).str() + \").\");\n            }\n        } else {\n            if (targets.size() & 1) {\n                throw std::invalid_argument(\n                    \"Two qubit gate \" + std::string(gate.name) +\n                    \" requires an even number of targets but was given \"\n                    \"(\" +\n                    comma_sep(targets).str() + \").\");\n            }\n            for (size_t k = 0; k < targets.size(); k += 2) {\n                if (targets[k] == targets[k + 1]) {\n                    throw std::invalid_argument(\n                        \"The two qubit gate \" + std::string(gate.name) +\n                        \" was applied to a target pair with the same target (\" + targets[k].target_str() +\n                        \") twice. Gates can't interact targets with themselves.\");\n                }\n            }\n        }\n    }\n\n    if (gate.arg_count == ARG_COUNT_SYGIL_ZERO_OR_ONE) {\n        if (args.size() > 1) {\n            throw std::invalid_argument(\n                \"Gate \" + std::string(gate.name) + \" was given \" + std::to_string(args.size()) + \" parens arguments (\" +\n                comma_sep(args).str() + \") but takes 0 or 1 parens arguments.\");\n        }\n    } else if (args.size() != gate.arg_count && gate.arg_count != ARG_COUNT_SYGIL_ANY) {\n        throw std::invalid_argument(\n            \"Gate \" + std::string(gate.name) + \" was given \" + std::to_string(args.size()) + \" parens arguments (\" +\n            comma_sep(args).str() + \") but takes \" + std::to_string(gate.arg_count) + \" parens arguments.\");\n    }\n\n    if ((gate.flags & GATE_TAKES_NO_TARGETS) && !targets.empty()) {\n        throw std::invalid_argument(\n            \"Gate \" + std::string(gate.name) + \" takes no targets but was given targets\" + targets_str(targets) + \".\");\n    }\n\n    if (gate.flags & GATE_ARGS_ARE_DISJOINT_PROBABILITIES) {\n        double total = 0;\n        for (const auto p : args) {\n            if (!(p >= 0 && p <= 1)) {\n                throw std::invalid_argument(\n                    \"Gate \" + std::string(gate.name) + \" only takes probability arguments, but one of its arguments (\" +\n                    comma_sep(args).str() + \") wasn't a probability.\");\n            }\n            total += p;\n        }\n        if (total > 1.0000001) {\n            throw std::invalid_argument(\n                \"The disjoint probability arguments (\" + comma_sep(args).str() + \") given to gate \" +\n                std::string(gate.name) + \" sum to more than 1.\");\n        }\n    } else if (gate.flags & GATE_ARGS_ARE_UNSIGNED_INTEGERS) {\n        for (const auto p : args) {\n            if (p < 0 || p != round(p)) {\n                throw std::invalid_argument(\n                    \"Gate \" + std::string(gate.name) +\n                    \" only takes non-negative integer arguments, but one of its arguments (\" + comma_sep(args).str() +\n                    \") wasn't a non-negative integer.\");\n            }\n        }\n    }\n\n    uint32_t valid_target_mask = TARGET_VALUE_MASK;\n\n    // Check combiners.\n    if (gate.flags & GATE_TARGETS_COMBINERS) {\n        bool combiner_allowed = false;\n        bool just_saw_combiner = false;\n        bool failed = false;\n        for (const auto p : targets) {\n            if (p.is_combiner()) {\n                failed |= !combiner_allowed;\n                combiner_allowed = false;\n                just_saw_combiner = true;\n            } else {\n                combiner_allowed = true;\n                just_saw_combiner = false;\n            }\n        }\n        failed |= just_saw_combiner;\n        if (failed) {\n            throw std::invalid_argument(\n                \"Gate \" + std::string(gate.name) +\n                \" given combiners ('*') that aren't between other targets: \" + targets_str(targets) + \".\");\n        }\n        valid_target_mask |= TARGET_COMBINER;\n    }\n\n    // Check that targets are in range.\n    if (gate.flags & GATE_PRODUCES_RESULTS) {\n        valid_target_mask |= TARGET_INVERTED_BIT;\n    }\n    if (gate.flags & GATE_CAN_TARGET_BITS) {\n        valid_target_mask |= TARGET_RECORD_BIT | TARGET_SWEEP_BIT;\n    }\n    if (gate.flags & GATE_ONLY_TARGETS_MEASUREMENT_RECORD) {\n        if (gate.flags & GATE_TARGETS_PAULI_STRING) {\n            for (GateTarget q : targets) {\n                if (!q.is_measurement_record_target() && !q.is_pauli_target()) {\n                    throw std::invalid_argument(\n                        \"Gate \" + std::string(gate.name) +\n                        \" only takes measurement record targets and Pauli targets (rec[-k], Xk, Yk, Zk).\");\n                }\n            }\n        } else {\n            for (GateTarget q : targets) {\n                if (!q.is_measurement_record_target()) {\n                    throw std::invalid_argument(\n                        \"Gate \" + std::string(gate.name) + \" only takes measurement record targets (rec[-k]).\");\n                }\n            }\n        }\n    } else if (gate.flags & GATE_TARGETS_PAULI_STRING) {\n        if (gate.flags & GATE_CAN_TARGET_BITS) {\n            for (GateTarget q : targets) {\n                if (!(q.data & (TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT | TARGET_COMBINER | TARGET_SWEEP_BIT |\n                                TARGET_RECORD_BIT))) {\n                    throw std::invalid_argument(\n                        \"Gate \" + std::string(gate.name) +\n                        \" only takes Pauli targets or bit targets ('X2', 'Y3', 'Z5', 'rec[-1]', 'sweep[0]', etc).\");\n                }\n            }\n        } else {\n            for (GateTarget q : targets) {\n                if (!(q.data & (TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT | TARGET_COMBINER))) {\n                    throw std::invalid_argument(\n                        \"Gate \" + std::string(gate.name) + \" only takes Pauli targets ('X2', 'Y3', 'Z5', etc).\");\n                }\n            }\n        }\n    } else {\n        for (GateTarget q : targets) {\n            if (q.data != (q.data & valid_target_mask)) {\n                std::stringstream ss;\n                ss << \"Target \";\n                q.write_succinct(ss);\n                ss << \" has invalid modifiers for gate type '\" << gate.name << \"'.\";\n                throw std::invalid_argument(ss.str());\n            }\n        }\n    }\n    if (gate_type == GateType::MPAD) {\n        for (const auto &t : targets) {\n            if (t.data > 1) {\n                std::stringstream ss;\n                ss << \"Target \";\n                t.write_succinct(ss);\n                ss << \" is not valid for gate type '\" << gate.name << \"'.\";\n                throw std::invalid_argument(ss.str());\n            }\n        }\n    }\n}\n\nuint64_t CircuitInstruction::count_measurement_results() const {\n    auto flags = GATE_DATA[gate_type].flags;\n    if (!(flags & GATE_PRODUCES_RESULTS)) {\n        return 0;\n    }\n    uint64_t n = (uint64_t)targets.size();\n    if (flags & GATE_TARGETS_PAIRS) {\n        return n >> 1;\n    } else if (flags & GATE_TARGETS_COMBINERS) {\n        for (auto e : targets) {\n            if (e.is_combiner()) {\n                n -= 2;\n            }\n        }\n    }\n    return n;\n}\n\nbool CircuitInstruction::can_fuse(const CircuitInstruction &other) const {\n    auto flags = GATE_DATA[gate_type].flags;\n    return gate_type == other.gate_type && args == other.args && !(flags & GATE_IS_NOT_FUSABLE) && tag == other.tag;\n}\n\nbool CircuitInstruction::operator==(const CircuitInstruction &other) const {\n    return gate_type == other.gate_type && args == other.args && targets == other.targets && tag == other.tag;\n}\nbool CircuitInstruction::approx_equals(const CircuitInstruction &other, double atol) const {\n    if (gate_type != other.gate_type || targets != other.targets || args.size() != other.args.size() ||\n        tag != other.tag) {\n        return false;\n    }\n    for (size_t k = 0; k < args.size(); k++) {\n        if (fabs(args[k] - other.args[k]) > atol) {\n            return false;\n        }\n    }\n    return true;\n}\n\nbool CircuitInstruction::operator!=(const CircuitInstruction &other) const {\n    return !(*this == other);\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const CircuitInstruction &instruction) {\n    out << GATE_DATA[instruction.gate_type].name;\n    if (!instruction.tag.empty()) {\n        out << '[';\n        write_tag_escaped_string_to(instruction.tag, out);\n        out << ']';\n    }\n    if (!instruction.args.empty()) {\n        out << '(';\n        bool first = true;\n        for (auto e : instruction.args) {\n            if (first) {\n                first = false;\n            } else {\n                out << \", \";\n            }\n            if (e > (double)INT64_MIN && e < (double)INT64_MAX && (int64_t)e == e) {\n                out << (int64_t)e;\n            } else {\n                out << e;\n            }\n        }\n        out << ')';\n    }\n    write_targets(out, instruction.targets);\n    return out;\n}\n\nvoid stim::write_tag_escaped_string_to(std::string_view tag, std::ostream &out) {\n    for (char c : tag) {\n        switch (c) {\n            case '\\n':\n                out << \"\\\\n\";\n                break;\n            case '\\r':\n                out << \"\\\\r\";\n                break;\n            case '\\\\':\n                out << \"\\\\B\";\n                break;\n            case ']':\n                out << \"\\\\C\";\n                break;\n            default:\n                out << c;\n        }\n    }\n}\n\nstd::string CircuitInstruction::str() const {\n    std::stringstream s;\n    s << *this;\n    return s.str();\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit_instruction.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CIRCUIT_INSTRUCTION_H\n#define _STIM_CIRCUIT_INSTRUCTION_H\n\n#include <cstdint>\n\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\nstruct Circuit;\n\n/// Stores a variety of circuit quantities relevant for sizing memory.\nstruct CircuitStats {\n    uint64_t num_detectors = 0;\n    uint64_t num_observables = 0;\n    uint64_t num_measurements = 0;\n    uint32_t num_qubits = 0;\n    uint64_t num_ticks = 0;\n    uint32_t max_lookback = 0;\n    uint32_t num_sweep_bits = 0;\n\n    inline CircuitStats repeated(uint64_t repetitions) const {\n        return CircuitStats{\n            num_detectors * repetitions,\n            num_observables,\n            num_measurements * repetitions,\n            num_qubits,\n            (uint32_t)(num_ticks * repetitions),\n            max_lookback,\n            num_sweep_bits,\n        };\n    }\n};\n\n/// The data that describes how a gate is being applied to qubits (or other targets).\n///\n/// A gate applied to targets.\n///\n/// This struct is not self-sufficient. It points into data stored elsewhere (e.g. in a Circuit's jagged_data).\nstruct CircuitInstruction {\n    /// The gate applied by the operation.\n    GateType gate_type;\n\n    /// Numeric arguments varying the functionality of the gate.\n    ///\n    /// The meaning of the numbers varies from gate to gate.\n    /// Examples:\n    ///     X_ERROR(p) has a single argument: probability of X.\n    ///     PAULI_CHANNEL_1(px,py,pz) has multiple probability arguments.\n    ///     DETECTOR(c1,c2) has variable arguments: coordinate data.\n    ///     OBSERVABLE_INCLUDE(k) has a single argument: the observable index.\n    SpanRef<const double> args;\n\n    /// Encoded data indicating the qubits and other targets acted on by the gate.\n    SpanRef<const GateTarget> targets;\n\n    /// Arbitrary string associated with the instruction.\n    /// No effect on simulations or analysis steps within stim, but user code may use it.\n    std::string_view tag;\n\n    CircuitInstruction() = delete;\n    CircuitInstruction(\n        GateType gate_type, SpanRef<const double> args, SpanRef<const GateTarget> targets, std::string_view tag);\n\n    /// Computes number of qubits, number of measurements, etc.\n    CircuitStats compute_stats(const Circuit *host) const;\n    /// Computes number of qubits, number of measurements, etc and adds them into a target.\n    void add_stats_to(CircuitStats &out, const Circuit *host) const;\n\n    /// Determines if two operations can be combined into one operation (with combined targeting data).\n    ///\n    /// For example, `H 1` then `H 2 1` is equivalent to `H 1 2 1` so those instructions are fusable.\n    bool can_fuse(const CircuitInstruction &other) const;\n    /// Equality.\n    bool operator==(const CircuitInstruction &other) const;\n    /// Inequality.\n    bool operator!=(const CircuitInstruction &other) const;\n    /// Approximate equality.\n    bool approx_equals(const CircuitInstruction &other, double atol) const;\n    /// Returns a text description of the instruction, as would appear in a STIM circuit file.\n    std::string str() const;\n\n    /// Determines the number of entries added to the measurement record by the operation.\n    ///\n    /// Note: invalid to use this on REPEAT blocks.\n    uint64_t count_measurement_results() const;\n\n    uint64_t repeat_block_rep_count() const;\n    Circuit &repeat_block_body(Circuit &host) const;\n    const Circuit &repeat_block_body(const Circuit &host) const;\n\n    /// Verifies complex invariants that circuit instructions are supposed to follow.\n    ///\n    /// For example: CNOT gates should have an even number of targets.\n    /// For example: X_ERROR should have a single float argument between 0 and 1 inclusive.\n    ///\n    /// Raises:\n    ///     std::invalid_argument: Validation failed.\n    void validate() const;\n\n    template <typename CALLBACK>\n    inline void for_combined_target_groups(CALLBACK callback) const {\n        auto flags = GATE_DATA[gate_type].flags;\n        size_t start = 0;\n        while (start < targets.size()) {\n            size_t end;\n            if (flags & stim::GateFlags::GATE_TARGETS_COMBINERS) {\n                end = start + 1;\n                while (end < targets.size() && targets[end].is_combiner()) {\n                    end += 2;\n                }\n            } else if (flags & stim::GateFlags::GATE_IS_SINGLE_QUBIT_GATE) {\n                end = start + 1;\n            } else if (flags & stim::GateFlags::GATE_TARGETS_PAIRS) {\n                end = start + 2;\n            } else if (\n                (flags & stim::GateFlags::GATE_TARGETS_PAULI_STRING) &&\n                !(flags & stim::GateFlags::GATE_TARGETS_COMBINERS)) {\n                // like CORRELATED_ERROR\n                end = targets.size();\n            } else if (flags & stim::GateFlags::GATE_ONLY_TARGETS_MEASUREMENT_RECORD) {\n                // like DETECTOR\n                end = start + 1;\n            } else if (gate_type == GateType::MPAD || gate_type == GateType::QUBIT_COORDS) {\n                end = start + 1;\n            } else {\n                throw std::invalid_argument(\"Not implemented: splitting \" + str());\n            }\n            std::span<const GateTarget> group = targets.sub(start, end);\n            callback(group);\n            start = end;\n        }\n    }\n};\n\nvoid write_tag_escaped_string_to(std::string_view tag, std::ostream &out);\n\nstd::ostream &operator<<(std::ostream &out, const CircuitInstruction &op);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/circuit/circuit_instruction.pybind.cc",
    "content": "#include \"stim/circuit/circuit_instruction.pybind.h\"\n\n#include \"stim/circuit/gate_target.pybind.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nPyCircuitInstruction::PyCircuitInstruction(\n    std::string_view name,\n    std::span<pybind11::object> init_targets,\n    std::span<double> init_gate_args,\n    pybind11::str tag)\n    : gate_type(GATE_DATA.at(name).id), tag(tag) {\n    for (const auto &obj : init_gate_args) {\n        gate_args.push_back(obj);\n    }\n    for (const auto &obj : init_targets) {\n        targets.push_back(obj_to_gate_target(obj));\n    }\n\n    as_operation_ref().validate();\n}\nPyCircuitInstruction::PyCircuitInstruction(\n    GateType gate_type, std::vector<GateTarget> targets, std::vector<double> gate_args, pybind11::str tag)\n    : gate_type(gate_type), targets(targets), gate_args(gate_args), tag(tag) {\n    as_operation_ref().validate();\n}\n\nPyCircuitInstruction PyCircuitInstruction::from_str(std::string_view text) {\n    Circuit host;\n    host.append_from_text(text);\n    if (host.operations.size() != 1 || host.operations[0].gate_type == GateType::REPEAT) {\n        throw std::invalid_argument(\"Given text didn't parse to a single CircuitInstruction.\");\n    }\n    return PyCircuitInstruction::from_instruction(host.operations[0]);\n}\n\nPyCircuitInstruction PyCircuitInstruction::from_instruction(CircuitInstruction instruction) {\n    std::vector<double> arguments;\n    std::vector<GateTarget> targets;\n    arguments.insert(arguments.begin(), instruction.args.begin(), instruction.args.end());\n    targets.insert(targets.begin(), instruction.targets.begin(), instruction.targets.end());\n    return PyCircuitInstruction{\n        instruction.gate_type,\n        targets,\n        arguments,\n        instruction.tag,\n    };\n}\n\nbool PyCircuitInstruction::operator==(const PyCircuitInstruction &other) const {\n    return gate_type == other.gate_type && targets == other.targets && gate_args == other.gate_args &&\n           pybind11::cast<std::string_view>(tag) == pybind11::cast<std::string_view>(other.tag);\n}\nbool PyCircuitInstruction::operator!=(const PyCircuitInstruction &other) const {\n    return !(*this == other);\n}\n\nstd::string PyCircuitInstruction::repr() const {\n    std::stringstream result;\n    result << \"stim.CircuitInstruction('\" << name() << \"', [\";\n    bool first = true;\n    for (const auto &t : targets) {\n        if (first) {\n            first = false;\n        } else {\n            result << \", \";\n        }\n        result << t.repr();\n    }\n    result << \"], [\" << comma_sep(gate_args) << \"]\";\n    if (pybind11::cast<bool>(pybind11::bool_(tag))) {\n        result << \", tag=\";\n        result << pybind11::repr(tag);\n    }\n    result << \")\";\n    return result.str();\n}\n\nstd::string PyCircuitInstruction::str() const {\n    std::stringstream result;\n    result << as_operation_ref();\n    return result.str();\n}\n\nCircuitInstruction PyCircuitInstruction::as_operation_ref() const {\n    return CircuitInstruction{gate_type, gate_args, targets, pybind11::cast<std::string_view>(tag)};\n}\nPyCircuitInstruction::operator CircuitInstruction() const {\n    return as_operation_ref();\n}\nstd::string PyCircuitInstruction::name() const {\n    return std::string(GATE_DATA[gate_type].name);\n}\nstd::vector<uint32_t> PyCircuitInstruction::raw_targets() const {\n    std::vector<uint32_t> result;\n    for (const auto &t : targets) {\n        result.push_back(t.data);\n    }\n    return result;\n}\n\nstd::vector<GateTarget> PyCircuitInstruction::targets_copy() const {\n    return targets;\n}\nstd::vector<double> PyCircuitInstruction::gate_args_copy() const {\n    return gate_args;\n}\nstd::vector<std::vector<stim::GateTarget>> PyCircuitInstruction::target_groups() const {\n    std::vector<std::vector<stim::GateTarget>> results;\n    as_operation_ref().for_combined_target_groups([&](std::span<const GateTarget> group) {\n        std::vector<stim::GateTarget> copy;\n        for (auto g : group) {\n            if (!g.is_combiner()) {\n                copy.push_back(g);\n            }\n        }\n        results.push_back(std::move(copy));\n    });\n    return results;\n}\n\npybind11::class_<PyCircuitInstruction> stim_pybind::pybind_circuit_instruction(pybind11::module &m) {\n    return pybind11::class_<PyCircuitInstruction>(\n        m,\n        \"CircuitInstruction\",\n        clean_doc_string(R\"DOC(\n            An instruction, like `H 0 1` or `CNOT rec[-1] 5`, from a circuit.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     H 0\n                ...     M 0 1\n                ...     X_ERROR(0.125) 5\n                ... ''')\n                >>> circuit[0]\n                stim.CircuitInstruction('H', [stim.GateTarget(0)], [])\n                >>> circuit[1]\n                stim.CircuitInstruction('M', [stim.GateTarget(0), stim.GateTarget(1)], [])\n                >>> circuit[2]\n                stim.CircuitInstruction('X_ERROR', [stim.GateTarget(5)], [0.125])\n        )DOC\")\n            .data());\n}\nvoid stim_pybind::pybind_circuit_instruction_methods(pybind11::module &m, pybind11::class_<PyCircuitInstruction> &c) {\n    c.def(\n        pybind11::init(\n            [](std::string_view name, pybind11::object targets, pybind11::object gate_args, pybind11::str tag)\n                -> PyCircuitInstruction {\n                if (targets.is_none() and gate_args.is_none() && !pybind11::cast<bool>(pybind11::bool_(tag))) {\n                    return PyCircuitInstruction::from_str(name);\n                }\n                std::vector<double> conv_args;\n                std::vector<pybind11::object> conv_targets;\n                if (!gate_args.is_none()) {\n                    conv_args = pybind11::cast<std::vector<double>>(gate_args);\n                }\n                if (!targets.is_none()) {\n                    conv_targets = pybind11::cast<std::vector<pybind11::object>>(targets);\n                }\n                return PyCircuitInstruction(name, conv_targets, conv_args, tag);\n            }),\n        pybind11::arg(\"name\"),\n        pybind11::arg(\"targets\") = pybind11::none(),\n        pybind11::arg(\"gate_args\") = pybind11::none(),\n        pybind11::kw_only(),\n        pybind11::arg(\"tag\") = \"\",\n        clean_doc_string(R\"DOC(\n            @signature def __init__(self, name: str, targets: Optional[Iterable[Union[int, stim.GateTarget]]] = None, gate_args: Optional[Iterable[float]] = None, *, tag: str = \"\") -> None:\n            Creates or parses a `stim.CircuitInstruction`.\n\n            Args:\n                name: The name of the instruction being applied.\n                    If `targets` and `gate_args` aren't specified, this can be a full\n                    instruction line from a stim Circuit file, like \"CX 0 1\".\n                targets: The targets the instruction is being applied to. These can be raw\n                    values like `0` and `stim.target_rec(-1)`, or instances of\n                    `stim.GateTarget`.\n                gate_args: The sequence of numeric arguments parameterizing a gate. For\n                    noise gates this is their probabilities. For `OBSERVABLE_INCLUDE`\n                    instructions it's the index of the logical observable to affect.\n                tag: Defaults to \"\". A custom string attached to the instruction. For\n                    example, for a TICK instruction, this could a string specifying an\n                    amount of time which is used by custom code for adding noise to a\n                    circuit. In general, stim will attempt to propagate tags across circuit\n                    transformations but will otherwise completely ignore them.\n\n            Examples:\n                >>> import stim\n\n                >>> print(stim.CircuitInstruction('DEPOLARIZE1', [5], [0.25]))\n                DEPOLARIZE1(0.25) 5\n\n                >>> stim.CircuitInstruction('CX rec[-1] 5  # comment')\n                stim.CircuitInstruction('CX', [stim.target_rec(-1), stim.GateTarget(5)], [])\n\n                >>> print(stim.CircuitInstruction('I', [2], tag='100ns'))\n                I[100ns] 2\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"name\",\n        &PyCircuitInstruction::name,\n        clean_doc_string(R\"DOC(\n            The name of the instruction (e.g. `H` or `X_ERROR` or `DETECTOR`).\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"tag\",\n        [](PyCircuitInstruction &self) -> pybind11::str {\n            return self.tag;\n        },\n        clean_doc_string(R\"DOC(\n            The custom tag attached to the instruction.\n\n            The tag is an arbitrary string.\n            The default tag, when none is specified, is the empty string.\n\n            Examples:\n                >>> import stim\n                >>> stim.Circuit(\"H[test] 0\")[0].tag\n                'test'\n                >>> stim.Circuit(\"H 0\")[0].tag\n                ''\n        )DOC\")\n            .data());\n\n    c.def(\n        \"target_groups\",\n        &PyCircuitInstruction::target_groups,\n        clean_doc_string(R\"DOC(\n            @signature def target_groups(self) -> List[List[stim.GateTarget]]:\n            Splits the instruction's targets into groups depending on the type of gate.\n\n            Single qubit gates like H get one group per target.\n            Two qubit gates like CX get one group per pair of targets.\n            Pauli product gates like MPP get one group per combined product.\n\n            Returns:\n                A list of groups of targets.\n\n            Examples:\n                >>> import stim\n                >>> for g in stim.Circuit('H 0 1 2')[0].target_groups():\n                ...     print(repr(g))\n                [stim.GateTarget(0)]\n                [stim.GateTarget(1)]\n                [stim.GateTarget(2)]\n\n                >>> for g in stim.Circuit('CX 0 1 2 3')[0].target_groups():\n                ...     print(repr(g))\n                [stim.GateTarget(0), stim.GateTarget(1)]\n                [stim.GateTarget(2), stim.GateTarget(3)]\n\n                >>> for g in stim.Circuit('MPP X0*Y1*Z2 X5*X6')[0].target_groups():\n                ...     print(repr(g))\n                [stim.target_x(0), stim.target_y(1), stim.target_z(2)]\n                [stim.target_x(5), stim.target_x(6)]\n\n                >>> for g in stim.Circuit('DETECTOR rec[-1] rec[-2]')[0].target_groups():\n                ...     print(repr(g))\n                [stim.target_rec(-1)]\n                [stim.target_rec(-2)]\n\n                >>> for g in stim.Circuit('CORRELATED_ERROR(0.1) X0 Y1')[0].target_groups():\n                ...     print(repr(g))\n                [stim.target_x(0), stim.target_y(1)]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"targets_copy\",\n        &PyCircuitInstruction::targets_copy,\n        clean_doc_string(R\"DOC(\n            Returns a copy of the targets of the instruction.\n\n            Examples:\n                >>> import stim\n                >>> instruction = stim.CircuitInstruction('X_ERROR', [2, 3], [0.125])\n                >>> instruction.targets_copy()\n                [stim.GateTarget(2), stim.GateTarget(3)]\n\n                >>> instruction.targets_copy() == instruction.targets_copy()\n                True\n                >>> instruction.targets_copy() is instruction.targets_copy()\n                False\n        )DOC\")\n            .data());\n\n    c.def(\n        \"gate_args_copy\",\n        &PyCircuitInstruction::gate_args_copy,\n        clean_doc_string(R\"DOC(\n            Returns the gate's arguments (numbers parameterizing the instruction).\n\n            For noisy gates this typically a list of probabilities.\n            For OBSERVABLE_INCLUDE it's a singleton list containing the logical observable\n            index.\n\n            Examples:\n                >>> import stim\n                >>> instruction = stim.CircuitInstruction('X_ERROR', [2, 3], [0.125])\n                >>> instruction.gate_args_copy()\n                [0.125]\n\n                >>> instruction.gate_args_copy() == instruction.gate_args_copy()\n                True\n                >>> instruction.gate_args_copy() is instruction.gate_args_copy()\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_measurements\",\n        [](const PyCircuitInstruction &self) -> uint64_t {\n            return self.as_operation_ref().count_measurement_results();\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of bits produced when running this instruction.\n\n            Examples:\n                >>> import stim\n                >>> stim.CircuitInstruction('H', [0]).num_measurements\n                0\n                >>> stim.CircuitInstruction('M', [0]).num_measurements\n                1\n                >>> stim.CircuitInstruction('M', [2, 3, 5, 7, 11]).num_measurements\n                5\n                >>> stim.CircuitInstruction('MXX', [0, 1, 4, 5, 11, 13]).num_measurements\n                3\n                >>> stim.Circuit('MPP X0*X1 X0*Z1*Y2')[0].num_measurements\n                2\n                >>> stim.CircuitInstruction('HERALDED_ERASE', [0], [0.25]).num_measurements\n                1\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two `stim.CircuitInstruction`s are identical.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two `stim.CircuitInstruction`s are different.\");\n    c.def(\n        \"__repr__\",\n        &PyCircuitInstruction::repr,\n        \"Returns text that is a valid python expression evaluating to an equivalent `stim.CircuitInstruction`.\");\n    c.def(\n        \"__str__\",\n        &PyCircuitInstruction::str,\n        \"Returns a text description of the instruction as a stim circuit file line.\");\n\n    c.def(\"__hash__\", [](const PyCircuitInstruction &self) {\n        return pybind11::hash(pybind11::str(self.str()));\n    });\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit_instruction.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_CIRCUIT_CIRCUIT_INSTRUCTION_PYBIND_H\n#define _STIM_CIRCUIT_CIRCUIT_INSTRUCTION_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/circuit/circuit_instruction.h\"\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/gates/gates.h\"\n\nnamespace stim_pybind {\n\nstruct PyCircuitInstruction {\n    stim::GateType gate_type;\n    std::vector<stim::GateTarget> targets;\n    std::vector<double> gate_args;\n    pybind11::str tag;\n\n    PyCircuitInstruction() = delete;\n    PyCircuitInstruction(\n        std::string_view name, std::span<pybind11::object> targets, std::span<double> gate_args, pybind11::str tag);\n    PyCircuitInstruction(\n        stim::GateType gate_type,\n        std::vector<stim::GateTarget> targets,\n        std::vector<double> gate_args,\n        pybind11::str tag);\n    static PyCircuitInstruction from_str(std::string_view text);\n    static PyCircuitInstruction from_instruction(stim::CircuitInstruction instruction);\n\n    stim::CircuitInstruction as_operation_ref() const;\n    operator stim::CircuitInstruction() const;\n    std::string name() const;\n    std::vector<stim::GateTarget> targets_copy() const;\n    std::vector<double> gate_args_copy() const;\n    std::vector<uint32_t> raw_targets() const;\n    std::vector<std::vector<stim::GateTarget>> target_groups() const;\n    bool operator==(const PyCircuitInstruction &other) const;\n    bool operator!=(const PyCircuitInstruction &other) const;\n\n    std::string repr() const;\n    std::string str() const;\n};\n\npybind11::class_<PyCircuitInstruction> pybind_circuit_instruction(pybind11::module &m);\nvoid pybind_circuit_instruction_methods(pybind11::module &m, pybind11::class_<PyCircuitInstruction> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/circuit/circuit_instruction.test.cc",
    "content": "#include \"stim/circuit/circuit_instruction.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/circuit/circuit.test.h\"\n\nusing namespace stim;\n\nTEST(circuit_instruction, for_combined_targets) {\n    Circuit circuit(R\"CIRCUIT(\n        X\n        CX\n        S 1\n        H 0 2\n        TICK\n        CX 0 1 2 3\n        CY 3 5\n        SPP\n        MPP X0*X1*Z2 Z7 X5*X9\n        SPP Z5\n    )CIRCUIT\");\n    auto get_k = [&](size_t k) {\n        std::vector<std::vector<GateTarget>> results;\n        circuit.operations[k].for_combined_target_groups([&](std::span<const GateTarget> group) {\n            std::vector<GateTarget> items;\n            for (auto g : group) {\n                items.push_back(g);\n            }\n            results.push_back(items);\n        });\n        return results;\n    };\n    ASSERT_EQ(get_k(0), (std::vector<std::vector<GateTarget>>{}));\n    ASSERT_EQ(get_k(1), (std::vector<std::vector<GateTarget>>{}));\n    ASSERT_EQ(\n        get_k(2),\n        (std::vector<std::vector<GateTarget>>{\n            {GateTarget::qubit(1)},\n        }));\n    ASSERT_EQ(\n        get_k(3),\n        (std::vector<std::vector<GateTarget>>{\n            {GateTarget::qubit(0)},\n            {GateTarget::qubit(2)},\n        }));\n    ASSERT_EQ(get_k(4), (std::vector<std::vector<GateTarget>>{}));\n    ASSERT_EQ(\n        get_k(5),\n        (std::vector<std::vector<GateTarget>>{\n            {GateTarget::qubit(0), GateTarget::qubit(1)},\n            {GateTarget::qubit(2), GateTarget::qubit(3)},\n        }));\n    ASSERT_EQ(\n        get_k(6),\n        (std::vector<std::vector<GateTarget>>{\n            {GateTarget::qubit(3), GateTarget::qubit(5)},\n        }));\n    ASSERT_EQ(get_k(7), (std::vector<std::vector<GateTarget>>{}));\n    ASSERT_EQ(\n        get_k(8),\n        (std::vector<std::vector<GateTarget>>{\n            {GateTarget::x(0), GateTarget::combiner(), GateTarget::x(1), GateTarget::combiner(), GateTarget::z(2)},\n            {GateTarget::z(7)},\n            {GateTarget::x(5), GateTarget::combiner(), GateTarget::x(9)},\n        }));\n    ASSERT_EQ(\n        get_k(9),\n        (std::vector<std::vector<GateTarget>>{\n            {GateTarget::z(5)},\n        }));\n}\n\nTEST(circuit_instruction, for_combined_targets_works_on_all) {\n    Circuit c = generate_test_circuit_with_all_operations();\n    size_t count = 0;\n    for (const auto &e : c.operations) {\n        if (e.gate_type == GateType::REPEAT) {\n            continue;\n        }\n        e.for_combined_target_groups([&](std::span<const GateTarget> group) {\n            count += group.size();\n        });\n    }\n    ASSERT_TRUE(count > 0);\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit_instruction_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport stim\nimport pytest\n\n\ndef test_init_and_equality():\n    i = stim.CircuitInstruction(\"X_ERROR\", [stim.GateTarget(5)], [0.5])\n    assert i.name == \"X_ERROR\"\n    assert i.targets_copy() == [stim.GateTarget(5)]\n    assert i.gate_args_copy() == [0.5]\n    i2 = stim.CircuitInstruction(name=\"X_ERROR\", targets=[stim.GateTarget(5)], gate_args=[0.5])\n    assert i == i2\n\n    assert i == stim.CircuitInstruction(\"X_ERROR\", [stim.GateTarget(5)], [0.5])\n    assert not (i == stim.CircuitInstruction(\"Z_ERROR\", [stim.GateTarget(5)], [0.5]))\n    assert i != stim.CircuitInstruction(\"Z_ERROR\", [stim.GateTarget(5)], [0.5])\n    assert i != stim.CircuitInstruction(\"X_ERROR\", [stim.GateTarget(5), stim.GateTarget(6)], [0.5])\n    assert i != stim.CircuitInstruction(\"X_ERROR\", [stim.GateTarget(5)], [0.25])\n\n\n@pytest.mark.parametrize(\"value\", [\n    stim.CircuitInstruction(\"X_ERROR\", [stim.GateTarget(5)], [0.5]),\n    stim.CircuitInstruction(\"M\", [stim.GateTarget(stim.target_inv(3))]),\n])\ndef test_repr(value):\n    assert eval(repr(value), {'stim': stim}) == value\n    assert repr(eval(repr(value), {'stim': stim})) == repr(value)\n\n\ndef test_str():\n    assert str(stim.CircuitInstruction(\"X_ERROR\", [stim.GateTarget(5)], [0.5])) == \"X_ERROR(0.5) 5\"\n\n\ndef test_hashable():\n    a = stim.CircuitInstruction(\"X_ERROR\", [stim.GateTarget(5)], [0.5])\n    b = stim.CircuitInstruction(\"DEPOLARIZE1\", [stim.GateTarget(5)], [0.5])\n    c = stim.CircuitInstruction(\"X_ERROR\", [stim.GateTarget(5)], [0.5])\n    assert hash(a) == hash(c)\n    assert len({a, b, c}) == 2\n\n\ndef test_num_measurements():\n    assert stim.CircuitInstruction(\"X\", [1, 2, 3]).num_measurements == 0\n    assert stim.CircuitInstruction(\"MXX\", [1, 2]).num_measurements == 1\n    assert stim.CircuitInstruction(\"M\", [1, 2]).num_measurements == 2\n    assert stim.CircuitInstruction(\"MPAD\", [0, 1, 0]).num_measurements == 3\n\n\ndef test_target_groups():\n    assert stim.CircuitInstruction(\"MPAD\", [0, 1, 0]).target_groups() == [\n        [stim.GateTarget(0)],\n        [stim.GateTarget(1)],\n        [stim.GateTarget(0)],\n    ]\n    assert stim.CircuitInstruction(\"H\", []).target_groups() == []\n    assert stim.CircuitInstruction(\"H\", [1]).target_groups() == [[stim.GateTarget(1)]]\n    assert stim.CircuitInstruction(\"H\", [2, 3]).target_groups() == [[stim.GateTarget(2)], [stim.GateTarget(3)]]\n    assert stim.CircuitInstruction(\"CX\", []).target_groups() == []\n    assert stim.CircuitInstruction(\"CX\", [0, 1]).target_groups() == [[stim.GateTarget(0), stim.GateTarget(1)]]\n    assert stim.CircuitInstruction(\"CX\", [2, 3, 5, 7]).target_groups() == [[stim.GateTarget(2), stim.GateTarget(3)], [stim.GateTarget(5), stim.GateTarget(7)]]\n    assert stim.CircuitInstruction(\"DETECTOR\", []).target_groups() == []\n    assert stim.CircuitInstruction(\"CORRELATED_ERROR\", [], [0.001]).target_groups() == []\n    assert stim.CircuitInstruction(\"MPP\", []).target_groups() == []\n    assert stim.CircuitInstruction(\"MPAD\", []).target_groups() == []\n    assert stim.CircuitInstruction(\"QUBIT_COORDS\", [1, 2]).target_groups() == [[stim.GateTarget(1)], [stim.GateTarget(2)]]\n\n\ndef test_eager_validate():\n    with pytest.raises(ValueError, match=\"0, 1, 2\"):\n        stim.CircuitInstruction(\"CX\", [0, 1, 2])\n\n\ndef test_init_from_str():\n    assert stim.CircuitInstruction(\"CX\", [0, 1]) == stim.CircuitInstruction(\"CX 0 1\")\n\n    with pytest.raises(ValueError, match=\"single CircuitInstruction\"):\n        stim.CircuitInstruction(\"\")\n\n    with pytest.raises(ValueError, match=\"single CircuitInstruction\"):\n        stim.CircuitInstruction(\"\"\"\n            REPEAT 5 {\n                H 0\n                X 1\n            }\n        \"\"\")\n\n    with pytest.raises(ValueError, match=\"single CircuitInstruction\"):\n        stim.CircuitInstruction(\"\"\"\n            H 0 \n            X 1\n        \"\"\")\n"
  },
  {
    "path": "src/stim/circuit/circuit_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport io\nimport pathlib\nimport tempfile\nfrom typing import cast\n\nimport stim\nimport pytest\nimport numpy as np\n\n\ndef test_circuit_init_num_measurements_num_qubits():\n    c = stim.Circuit()\n    assert c.num_qubits == c.num_measurements == 0\n    assert str(c).strip() == \"\"\n\n    c.append_operation(\"X\", [3])\n    assert c.num_qubits == 4\n    assert c.num_measurements == 0\n    assert str(c).strip() == \"\"\"\nX 3\n        \"\"\".strip()\n\n    c.append_operation(\"M\", [0])\n    assert c.num_qubits == 4\n    assert c.num_measurements == 1\n    assert str(c).strip() == \"\"\"\nX 3\nM 0\n        \"\"\".strip()\n\n\ndef test_circuit_append_operation():\n    c = stim.Circuit()\n\n    with pytest.raises(IndexError, match=\"Gate not found\"):\n        c.append_operation(\"NOT_A_GATE\", [0])\n    with pytest.raises(ValueError, match=\"even number of targets\"):\n        c.append_operation(\"CNOT\", [0])\n    with pytest.raises(ValueError, match=\"takes 0\"):\n        c.append_operation(\"X\", [0], 0.5)\n    with pytest.raises(ValueError, match=\"invalid modifiers\"):\n        c.append_operation(\"X\", [stim.target_inv(0)])\n    with pytest.raises(ValueError, match=\"invalid modifiers\"):\n        c.append_operation(\"X\", [stim.target_x(0)])\n    with pytest.raises(IndexError, match=\"lookback\"):\n        stim.target_rec(0)\n    with pytest.raises(IndexError, match=\"lookback\"):\n        stim.target_rec(1)\n    with pytest.raises(IndexError, match=\"lookback\"):\n        stim.target_rec(-2**30)\n    assert stim.target_rec(-1) is not None\n    assert stim.target_rec(-15) is not None\n\n    c.append_operation(\"X\", [0])\n    c.append_operation(\"X\", [1, 2])\n    c.append_operation(\"X\", [3])\n    c.append_operation(\"CNOT\", [0, 1])\n    c.append_operation(\"M\", [0, stim.target_inv(1)])\n    c.append_operation(\"X_ERROR\", [0], 0.25)\n    c.append_operation(\"CORRELATED_ERROR\", [stim.target_x(0), stim.target_y(1)], 0.5)\n    c.append_operation(\"DETECTOR\", [stim.target_rec(-1)])\n    c.append_operation(\"OBSERVABLE_INCLUDE\", [stim.target_rec(-1), stim.target_rec(-2)], 5)\n    assert str(c).strip() == \"\"\"\nX 0 1 2 3\nCX 0 1\nM 0 !1\nX_ERROR(0.25) 0\nE(0.5) X0 Y1\nDETECTOR rec[-1]\nOBSERVABLE_INCLUDE(5) rec[-1] rec[-2]\n    \"\"\".strip()\n\n\ndef test_circuit_iadd():\n    c = stim.Circuit()\n    alias = c\n    c.append_operation(\"X\", [1, 2])\n    c2 = stim.Circuit()\n    c2.append_operation(\"Y\", [3])\n    c2.append_operation(\"M\", [4])\n    c += c2\n    assert c is alias\n    assert str(c).strip() == \"\"\"\nX 1 2\nY 3\nM 4\n        \"\"\".strip()\n\n    c += c\n    assert str(c).strip() == \"\"\"\nX 1 2\nY 3\nM 4\nX 1 2\nY 3\nM 4\n    \"\"\".strip()\n    assert c is alias\n\n\ndef test_circuit_add():\n    c = stim.Circuit()\n    c.append_operation(\"X\", [1, 2])\n    c2 = stim.Circuit()\n    c2.append_operation(\"Y\", [3])\n    c2.append_operation(\"M\", [4])\n    assert str(c + c2).strip() == \"\"\"\nX 1 2\nY 3\nM 4\n            \"\"\".strip()\n\n    assert str(c2 + c2).strip() == \"\"\"\nY 3\nM 4\nY 3\nM 4\n        \"\"\".strip()\n\n\ndef test_circuit_mul():\n    c = stim.Circuit()\n    c.append_operation(\"Y\", [3])\n    c.append_operation(\"M\", [4])\n    assert str(c * 2) == str(2 * c) == \"\"\"\nREPEAT 2 {\n    Y 3\n    M 4\n}\n        \"\"\".strip()\n    assert str((c * 2) * 3) == \"\"\"\nREPEAT 6 {\n    Y 3\n    M 4\n}\n        \"\"\".strip()\n    expected = \"\"\"\nREPEAT 3 {\n    Y 3\n    M 4\n}\n    \"\"\".strip()\n    assert str(c * 3) == str(3 * c) == expected\n    alias = c\n    c *= 3\n    assert alias is c\n    assert str(c) == expected\n    c *= 1\n    assert str(c) == expected\n    assert alias is c\n    c *= 0\n    assert str(c) == \"\"\n    assert alias is c\n\n\ndef test_circuit_repr():\n    v = stim.Circuit(\"\"\"\n        X 0\n        M 0\n    \"\"\")\n    r = repr(v)\n    assert r == \"\"\"stim.Circuit('''\n    X 0\n    M 0\n''')\"\"\"\n    assert eval(r, {'stim': stim}) == v\n\n\ndef test_circuit_eq():\n    a = \"\"\"\n        X 0\n        M 0\n    \"\"\"\n    b = \"\"\"\n        Y 0\n        M 0\n    \"\"\"\n    assert stim.Circuit() == stim.Circuit()\n    assert stim.Circuit() != stim.Circuit(a)\n    assert not (stim.Circuit() != stim.Circuit())\n    assert not (stim.Circuit() == stim.Circuit(a))\n    assert stim.Circuit(a) == stim.Circuit(a)\n    assert stim.Circuit(b) == stim.Circuit(b)\n    assert stim.Circuit(a) != stim.Circuit(b)\n\n    assert stim.Circuit() != None\n    assert stim.Circuit != object()\n    assert stim.Circuit != \"another type\"\n    assert not (stim.Circuit == None)\n    assert not (stim.Circuit == object())\n    assert not (stim.Circuit == \"another type\")\n\n\ndef test_circuit_clear():\n    c = stim.Circuit(\"\"\"\n        X 0\n        M 0\n    \"\"\")\n    c.clear()\n    assert c == stim.Circuit()\n\n\ndef test_circuit_compile_sampler():\n    c = stim.Circuit()\n    s = c.compile_sampler()\n    c.append_operation(\"M\", [0])\n    assert repr(s) == \"stim.CompiledMeasurementSampler(stim.Circuit())\"\n    s = c.compile_sampler()\n    assert repr(s) == \"\"\"\nstim.CompiledMeasurementSampler(stim.Circuit('''\n    M 0\n'''))\n    \"\"\".strip()\n\n    c.append_operation(\"H\", [0, 1, 2, 3, 4])\n    c.append_operation(\"M\", [0, 1, 2, 3, 4])\n    s = c.compile_sampler()\n    r = repr(s)\n    assert r == \"\"\"\nstim.CompiledMeasurementSampler(stim.Circuit('''\n    M 0\n    H 0 1 2 3 4\n    M 0 1 2 3 4\n'''))\n    \"\"\".strip() == str(stim.CompiledMeasurementSampler(c))\n\n    # Check that expression can be evaluated.\n    _ = eval(r, {\"stim\": stim})\n\n\ndef test_circuit_compile_detector_sampler():\n    c = stim.Circuit()\n    s = c.compile_detector_sampler()\n    c.append_operation(\"M\", [0])\n    assert repr(s) == \"stim.CompiledDetectorSampler(stim.Circuit())\"\n    c.append_operation(\"DETECTOR\", [stim.target_rec(-1)])\n    s = c.compile_detector_sampler()\n    r = repr(s)\n    assert r == \"\"\"\nstim.CompiledDetectorSampler(stim.Circuit('''\n    M 0\n    DETECTOR rec[-1]\n'''))\n    \"\"\".strip()\n\n    # Check that expression can be evaluated.\n    _ = eval(r, {\"stim\": stim})\n\n\ndef test_circuit_flattened_operations():\n    assert stim.Circuit('''\n        H 0\n        REPEAT 3 {\n            X_ERROR(0.125) 1\n        }\n        CORRELATED_ERROR(0.25) X3 Y4 Z5\n        M 0 !1\n        DETECTOR rec[-1]\n    ''').flattened_operations() == [\n        (\"H\", [0], 0),\n        (\"X_ERROR\", [1], 0.125),\n        (\"X_ERROR\", [1], 0.125),\n        (\"X_ERROR\", [1], 0.125),\n        (\"E\", [(\"X\", 3), (\"Y\", 4), (\"Z\", 5)], 0.25),\n        (\"M\", [0, (\"inv\", 1)], 0),\n        (\"DETECTOR\", [(\"rec\", -1)], 0),\n    ]\n\n\ndef test_copy():\n    c = stim.Circuit(\"H 0\")\n    c2 = c.copy()\n    assert c == c2\n    assert c is not c2\n\n\ndef test_hash():\n    # stim.Circuit is mutable. It must not also be value-hashable.\n    # Defining __hash__ requires defining a FrozenCircuit variant instead.\n    with pytest.raises(TypeError, match=\"unhashable\"):\n        _ = hash(stim.Circuit())\n\n\ndef test_circuit_generation():\n    surface_code_circuit = stim.Circuit.generated(\n            \"surface_code:rotated_memory_z\",\n            distance=5,\n            rounds=10)\n    samples = surface_code_circuit.compile_detector_sampler().sample(5)\n    assert samples.shape == (5, 24 * 10)\n    assert np.count_nonzero(samples) == 0\n\n\ndef test_circuit_generation_errors():\n    with pytest.raises(ValueError, match=\"Known repetition_code tasks\"):\n        stim.Circuit.generated(\n            \"repetition_code:UNKNOWN\",\n            distance=3,\n            rounds=1000)\n    with pytest.raises(ValueError, match=\"Expected type to start with.\"):\n        stim.Circuit.generated(\n            \"UNKNOWN:memory\",\n            distance=0,\n            rounds=1000)\n    with pytest.raises(ValueError, match=\"distance >= 2\"):\n        stim.Circuit.generated(\n            \"repetition_code:memory\",\n            distance=1,\n            rounds=1000)\n\n    with pytest.raises(ValueError, match=\"0 <= after_clifford_depolarization <= 1\"):\n        stim.Circuit.generated(\n            \"repetition_code:memory\",\n            distance=3,\n            rounds=1000,\n            after_clifford_depolarization=-1)\n    with pytest.raises(ValueError, match=\"0 <= before_round_data_depolarization <= 1\"):\n        stim.Circuit.generated(\n            \"repetition_code:memory\",\n            distance=3,\n            rounds=1000,\n            before_round_data_depolarization=-1)\n    with pytest.raises(ValueError, match=\"0 <= after_reset_flip_probability <= 1\"):\n        stim.Circuit.generated(\n            \"repetition_code:memory\",\n            distance=3,\n            rounds=1000,\n            after_reset_flip_probability=-1)\n    with pytest.raises(ValueError, match=\"0 <= before_measure_flip_probability <= 1\"):\n        stim.Circuit.generated(\n            \"repetition_code:memory\",\n            distance=3,\n            rounds=1000,\n            before_measure_flip_probability=-1)\n\n\ndef test_num_detectors():\n    assert stim.Circuit().num_detectors == 0\n    assert stim.Circuit(\"DETECTOR\").num_detectors == 1\n    assert stim.Circuit(\"\"\"\n        REPEAT 1000 {\n            DETECTOR\n        }\n    \"\"\").num_detectors == 1000\n    assert stim.Circuit(\"\"\"\n        DETECTOR\n        REPEAT 1000000 {\n            REPEAT 1000000 {\n                M 0\n                DETECTOR rec[-1]\n            }\n        }\n    \"\"\").num_detectors == 1000000**2 + 1\n\n\ndef test_num_observables():\n    assert stim.Circuit().num_observables == 0\n    assert stim.Circuit(\"OBSERVABLE_INCLUDE(0)\").num_observables == 1\n    assert stim.Circuit(\"OBSERVABLE_INCLUDE(1)\").num_observables == 2\n    assert stim.Circuit(\"\"\"\n        M 0\n        OBSERVABLE_INCLUDE(2)\n        REPEAT 1000000 {\n            REPEAT 1000000 {\n                M 0\n                OBSERVABLE_INCLUDE(3) rec[-1]\n            }\n            OBSERVABLE_INCLUDE(4)\n        }\n    \"\"\").num_observables == 5\n\n\ndef test_indexing_operations():\n    c = stim.Circuit()\n    assert len(c) == 0\n    assert list(c) == []\n    with pytest.raises(IndexError):\n        _ = c[0]\n    with pytest.raises(IndexError):\n        _ = c[-1]\n\n    c = stim.Circuit('X 0')\n    assert len(c) == 1\n    assert list(c) == [stim.CircuitInstruction('X', [stim.GateTarget(0)])]\n    assert c[0] == c[-1] == stim.CircuitInstruction('X', [stim.GateTarget(0)])\n    with pytest.raises(IndexError):\n        _ = c[1]\n    with pytest.raises(IndexError):\n        _ = c[-2]\n\n    c = stim.Circuit('''\n        X 5 6\n        REPEAT 1000 {\n            H 5\n        }\n        M !0\n    ''')\n    assert len(c) == 3\n    with pytest.raises(IndexError):\n        _ = c[3]\n    with pytest.raises(IndexError):\n        _ = c[-4]\n    assert list(c) == [\n        stim.CircuitInstruction('X', [stim.GateTarget(5), stim.GateTarget(6)]),\n        stim.CircuitRepeatBlock(1000, stim.Circuit('H 5')),\n        stim.CircuitInstruction('M', [stim.GateTarget(stim.target_inv(0))]),\n    ]\n\n\ndef test_slicing():\n    c = stim.Circuit(\"\"\"\n        H 0\n        REPEAT 5 {\n            X 1\n        }\n        Y 2\n        Z 3\n    \"\"\")\n    assert c[:] is not c\n    assert c[:] == c\n    assert c[1:-1] == stim.Circuit(\"\"\"\n        REPEAT 5 {\n            X 1\n        }\n        Y 2\n    \"\"\")\n    assert c[::2] == stim.Circuit(\"\"\"\n        H 0\n        Y 2\n    \"\"\")\n    assert c[1::2] == stim.Circuit(\"\"\"\n        REPEAT 5 {\n            X 1\n        }\n        Z 3\n    \"\"\")\n\n\ndef test_reappend_gate_targets():\n    expected = stim.Circuit(\"\"\"\n        MPP !X0 * X1\n        CX rec[-1] 5\n    \"\"\")\n    c = stim.Circuit()\n    c.append_operation(\"MPP\", cast(stim.CircuitInstruction, expected[0]).targets_copy())\n    c.append_operation(\"CX\", cast(stim.CircuitInstruction, expected[1]).targets_copy())\n    assert c == expected\n\n\ndef test_append_instructions_and_blocks():\n    c = stim.Circuit()\n\n    c.append_operation(\"TICK\")\n    assert c == stim.Circuit(\"TICK\")\n\n    with pytest.raises(ValueError, match=\"no targets\"):\n        c.append_operation(\"TICK\", [1, 2, 3])\n\n    c.append_operation(stim.Circuit(\"H 1\")[0])\n    assert c == stim.Circuit(\"TICK\\nH 1\")\n\n    c.append_operation(stim.Circuit(\"CX 1 2 3 4\")[0])\n    assert c == stim.Circuit(\"\"\"\n        TICK\n        H 1\n        CX 1 2 3 4\n    \"\"\")\n\n    c.append_operation((stim.Circuit(\"X 5\") * 100)[0])\n    assert c == stim.Circuit(\"\"\"\n        TICK\n        H 1\n        CX 1 2 3 4\n        REPEAT 100 {\n            X 5\n        }\n    \"\"\")\n\n    c.append_operation(stim.Circuit(\"PAULI_CHANNEL_1(0.125, 0.25, 0.325) 4 5 6\")[0])\n    assert c == stim.Circuit(\"\"\"\n        TICK\n        H 1\n        CX 1 2 3 4\n        REPEAT 100 {\n            X 5\n        }\n        PAULI_CHANNEL_1(0.125, 0.25, 0.325) 4 5 6\n    \"\"\")\n\n    with pytest.raises(ValueError, match=\"must be a\"):\n        c.append_operation(object())\n\n    with pytest.raises(ValueError, match=\"targets\"):\n        c.append_operation(stim.Circuit(\"H 1\")[0], [2])\n\n    with pytest.raises(ValueError, match=\"arg\"):\n        c.append_operation(stim.Circuit(\"H 1\")[0], [], 0.1)\n\n    with pytest.raises(ValueError, match=\"targets\"):\n        c.append_operation((stim.Circuit(\"H 1\") * 5)[0], [2])\n\n    with pytest.raises(ValueError, match=\"arg\"):\n        c.append_operation((stim.Circuit(\"H 1\") * 5)[0], [], 0.1)\n\n    with pytest.raises(ValueError, match=\"repeat 0\"):\n        c.append_operation(stim.CircuitRepeatBlock(0, stim.Circuit(\"H 1\")))\n\n\ndef test_circuit_measurement_sampling_seeded():\n    c = stim.Circuit(\"\"\"\n        H 0\n        M 0\n    \"\"\")\n    with pytest.raises(ValueError, match=\"seed\"):\n        c.compile_sampler(seed=-1)\n    with pytest.raises(ValueError, match=\"seed\"):\n        c.compile_sampler(seed=object())\n\n    s1 = c.compile_sampler().sample(256)\n    s2 = c.compile_sampler().sample(256)\n    assert not np.array_equal(s1, s2)\n\n    s1 = c.compile_sampler(seed=None).sample(256)\n    s2 = c.compile_sampler(seed=None).sample(256)\n    assert not np.array_equal(s1, s2)\n\n    s1 = c.compile_sampler(seed=5).sample(256)\n    s2 = c.compile_sampler(seed=5).sample(256)\n    s3 = c.compile_sampler(seed=6).sample(256)\n    assert np.array_equal(s1, s2)\n    assert not np.array_equal(s1, s3)\n\n\ndef test_circuit_detector_sampling_seeded():\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.5) 0\n        M 0\n        DETECTOR rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=\"seed\"):\n        c.compile_detector_sampler(seed=-1)\n    with pytest.raises(ValueError, match=\"seed\"):\n        c.compile_detector_sampler(seed=object())\n\n    s1 = c.compile_detector_sampler().sample(256)\n    s2 = c.compile_detector_sampler().sample(256)\n    assert not np.array_equal(s1, s2)\n\n    s1 = c.compile_detector_sampler(seed=None).sample(256)\n    s2 = c.compile_detector_sampler(seed=None).sample(256)\n    assert not np.array_equal(s1, s2)\n\n    s1 = c.compile_detector_sampler(seed=5).sample(256)\n    s2 = c.compile_detector_sampler(seed=5).sample(256)\n    s3 = c.compile_detector_sampler(seed=6).sample(256)\n    assert np.array_equal(s1, s2)\n    assert not np.array_equal(s1, s3)\n\n\ndef test_approx_equals():\n    base = stim.Circuit(\"X_ERROR(0.099) 0\")\n    assert not base.approx_equals(stim.Circuit(\"X_ERROR(0.101) 0\"), atol=0)\n    assert not base.approx_equals(stim.Circuit(\"X_ERROR(0.101) 0\"), atol=0.00001)\n    assert base.approx_equals(stim.Circuit(\"X_ERROR(0.101) 0\"), atol=0.01)\n    assert base.approx_equals(stim.Circuit(\"X_ERROR(0.101) 0\"), atol=999)\n    assert not base.approx_equals(stim.Circuit(\"DEPOLARIZE1(0.101) 0\"), atol=999)\n\n    assert not base.approx_equals(object(), atol=999)\n    assert not base.approx_equals(stim.PauliString(\"XYZ\"), atol=999)\n\n\ndef test_append_extended_cases():\n    c = stim.Circuit()\n    c.append(\"H\", 5)\n    c.append(\"CNOT\", [0, 1])\n    c.append(\"H\", c[0].targets_copy()[0])\n    c.append(\"X\", (e + 1 for e in range(5)))\n    assert c == stim.Circuit(\"\"\"\n        H 5\n        CNOT 0 1\n        H 5\n        X 1 2 3 4 5\n    \"\"\")\n\n\ndef test_pickle():\n    import pickle\n\n    t = stim.Circuit(\"\"\"\n        H 0\n        REPEAT 100 {\n            M 0\n            CNOT rec[-1] 2\n        }\n    \"\"\")\n    a = pickle.dumps(t)\n    assert pickle.loads(a) == t\n\n\ndef test_backwards_compatibility_vs_safety_append_vs_append_operation():\n    c = stim.Circuit()\n    with pytest.raises(ValueError, match=\"takes 1 parens argument\"):\n        c.append(\"X_ERROR\", [5])\n    with pytest.raises(ValueError, match=\"takes 1 parens argument\"):\n        c.append(\"OBSERVABLE_INCLUDE\", [])\n    assert c == stim.Circuit()\n    c.append_operation(\"X_ERROR\", [5])\n    assert c == stim.Circuit(\"X_ERROR(0) 5\")\n    c.append_operation(\"Z_ERROR\", [5], 0.25)\n    assert c == stim.Circuit(\"X_ERROR(0) 5\\nZ_ERROR(0.25) 5\")\n\n\ndef test_anti_commuting_mpp_error_message():\n    with pytest.raises(ValueError, match=\"while analyzing a Pauli product measurement\"):\n        stim.Circuit(\"\"\"\n            MPP X0 Z0\n            DETECTOR rec[-1]\n        \"\"\").detector_error_model()\n\n\ndef test_blocked_remnant_edge_error():\n    circuit = stim.Circuit(\"\"\"\n        X_ERROR(0.125) 0\n        CORRELATED_ERROR(0.25) X0 X1\n        M 0 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-2]\n    \"\"\")\n\n    assert circuit.detector_error_model(decompose_errors=True) == stim.DetectorErrorModel(\"\"\"\n        error(0.125) D2 D3\n        error(0.25) D2 D3 ^ D0 D1\n    \"\"\")\n\n    with pytest.raises(ValueError, match=\"Failed to decompose\"):\n        circuit.detector_error_model(\n            decompose_errors=True,\n            block_decomposition_from_introducing_remnant_edges=True)\n\n    assert circuit.detector_error_model(\n        decompose_errors=True,\n        block_decomposition_from_introducing_remnant_edges=True,\n        ignore_decomposition_failures=True) == stim.DetectorErrorModel(\"\"\"\n            error(0.25) D0 D1 D2 D3\n            error(0.125) D2 D3\n        \"\"\")\n\n\ndef test_shortest_graphlike_error():\n    c = stim.Circuit(\"\"\"\n        TICK\n        X_ERROR(0.125) 0\n        Y_ERROR(0.125) 0\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n\n    actual = c.shortest_graphlike_error()\n    assert len(actual) == 1\n    assert isinstance(actual[0], stim.ExplainedError)\n    assert str(actual[0]) == \"\"\"ExplainedError {\n    dem_error_terms: L0\n    CircuitErrorLocation {\n        flipped_pauli_product: Y0\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (Y_ERROR) in the circuit\n            at target #1 of the instruction\n            resolving to Y_ERROR(0.125) 0\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: X0\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #2 (X_ERROR) in the circuit\n            at target #1 of the instruction\n            resolving to X_ERROR(0.125) 0\n    }\n}\"\"\"\n\n    actual = c.shortest_graphlike_error(canonicalize_circuit_errors=True)\n    assert len(actual) == 1\n    assert isinstance(actual[0], stim.ExplainedError)\n    assert str(actual[0]) == \"\"\"ExplainedError {\n    dem_error_terms: L0\n    CircuitErrorLocation {\n        flipped_pauli_product: X0\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #2 (X_ERROR) in the circuit\n            at target #1 of the instruction\n            resolving to X_ERROR(0.125) 0\n    }\n}\"\"\"\n\n\ndef test_shortest_graphlike_error_empty():\n    with pytest.raises(ValueError, match=\"Failed to find\"):\n        stim.Circuit().shortest_graphlike_error()\n\n\ndef test_shortest_graphlike_error_msgs():\n    with pytest.raises(\n            ValueError,\n            match=\"NO OBSERVABLES\"\n    ):\n        stim.Circuit().shortest_graphlike_error()\n\n    c = stim.Circuit(\"\"\"\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=\"NO DETECTORS\"):\n        c.shortest_graphlike_error()\n\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n    \"\"\")\n    with pytest.raises(ValueError, match=r\"NO OBSERVABLES(.|\\n)*NO DETECTORS\"):\n        c.shortest_graphlike_error()\n    with pytest.raises(ValueError, match=\"\"):\n        c.shortest_graphlike_error()\n\n    c = stim.Circuit(\"\"\"\n        M 0\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=\"NO ERRORS\"):\n        c.shortest_graphlike_error()\n\n    c = stim.Circuit(\"\"\"\n        M(0.1) 0\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=\"NO GRAPHLIKE ERRORS\"):\n        c.shortest_graphlike_error()\n\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n        DETECTOR rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=\"NO OBSERVABLES\"):\n        c.shortest_graphlike_error()\n\n\ndef test_search_for_undetectable_logical_errors_empty():\n    with pytest.raises(ValueError, match=\"Failed to find\"):\n        stim.Circuit().search_for_undetectable_logical_errors(\n            dont_explore_edges_increasing_symptom_degree=True,\n            dont_explore_edges_with_degree_above=4,\n            dont_explore_detection_event_sets_with_size_above=4,\n        )\n\n\ndef test_search_for_undetectable_logical_errors_msgs():\n    with pytest.raises(ValueError, match=r\"NO OBSERVABLES(.|\\n)*NO DETECTORS\"):\n        stim.Circuit().search_for_undetectable_logical_errors(\n            dont_explore_edges_increasing_symptom_degree=True,\n            dont_explore_edges_with_degree_above=4,\n            dont_explore_detection_event_sets_with_size_above=4,\n        )\n\n    c = stim.Circuit(\"\"\"\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=r\"NO DETECTORS(.|\\n)*NO ERRORS\"):\n        c.search_for_undetectable_logical_errors(\n            dont_explore_edges_increasing_symptom_degree=True,\n            dont_explore_edges_with_degree_above=4,\n            dont_explore_detection_event_sets_with_size_above=4,\n        )\n\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n    \"\"\")\n    with pytest.raises(ValueError, match=r\"NO OBSERVABLES(.|\\n)*NO DETECTORS(.|\\n)*NO ERRORS\"):\n        c.search_for_undetectable_logical_errors(\n            dont_explore_edges_increasing_symptom_degree=True,\n            dont_explore_edges_with_degree_above=4,\n            dont_explore_detection_event_sets_with_size_above=4,\n        )\n\n    c = stim.Circuit(\"\"\"\n        M 0\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=\"NO ERRORS\"):\n        c.search_for_undetectable_logical_errors(\n            dont_explore_edges_increasing_symptom_degree=True,\n            dont_explore_edges_with_degree_above=4,\n            dont_explore_detection_event_sets_with_size_above=4,\n        )\n\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n        DETECTOR rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=\"NO OBSERVABLES\"):\n        c.search_for_undetectable_logical_errors(\n            dont_explore_edges_increasing_symptom_degree=True,\n            dont_explore_edges_with_degree_above=4,\n            dont_explore_detection_event_sets_with_size_above=4,\n        )\n\n\ndef test_shortest_error_sat_problem_unrecognized_format():\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        X_ERROR(0.4) 0\n        M 0\n        DETECTOR rec[-1] rec[-2]\n    \"\"\")\n    with pytest.raises(ValueError, match='Unsupported format'):\n        _ = c.shortest_error_sat_problem(format='unsupported format name')\n\n\ndef test_shortest_error_sat_problem():\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        X_ERROR(0.4) 0\n        M 0\n        DETECTOR rec[-1] rec[-2]\n    \"\"\")\n    sat_str = c.shortest_error_sat_problem()\n    assert sat_str == 'p wcnf 2 4 5\\n1 -1 0\\n1 -2 0\\n5 -1 0\\n5 2 0\\n'\n\n\ndef test_likeliest_error_sat_problem():\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        X_ERROR(0.4) 0\n        M 0\n        DETECTOR rec[-1] rec[-2]\n    \"\"\")\n    sat_str = c.likeliest_error_sat_problem(quantization=100)\n    assert sat_str == 'p wcnf 2 4 401\\n18 -1 0\\n100 -2 0\\n401 -1 0\\n401 2 0\\n'\n\n\ndef test_shortest_graphlike_error_ignore():\n    c = stim.Circuit(\"\"\"\n        TICK\n        X_ERROR(0.125) 0\n        M 0\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=\"Failed to decompose errors\"):\n        c.shortest_graphlike_error(ignore_ungraphlike_errors=False)\n    with pytest.raises(ValueError, match=\"Failed to find any graphlike logical errors\"):\n        c.shortest_graphlike_error(ignore_ungraphlike_errors=True)\n\n\ndef test_coords():\n    circuit = stim.Circuit(\"\"\"\n        QUBIT_COORDS(1, 2, 3) 0\n        QUBIT_COORDS(2) 1\n        SHIFT_COORDS(5)\n        QUBIT_COORDS(3) 4\n    \"\"\")\n    assert circuit.get_final_qubit_coordinates() == {\n        0: [1, 2, 3],\n        1: [2],\n        4: [8],\n    }\n\n\ndef test_explain_errors():\n    circuit = stim.Circuit(\"\"\"\n        H 0\n        CNOT 0 1\n        DEPOLARIZE1(0.01) 0\n        CNOT 0 1\n        H 0\n        M 0 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n    \"\"\")\n    r = circuit.explain_detector_error_model_errors()\n    assert len(r) == 3\n    assert str(r[0]) == \"\"\"ExplainedError {\n    dem_error_terms: D0\n    CircuitErrorLocation {\n        flipped_pauli_product: X0\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.01) 0\n    }\n}\"\"\"\n    assert str(r[1]) == \"\"\"ExplainedError {\n    dem_error_terms: D0 D1\n    CircuitErrorLocation {\n        flipped_pauli_product: Y0\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.01) 0\n    }\n}\"\"\"\n    assert str(r[2]) == \"\"\"ExplainedError {\n    dem_error_terms: D1\n    CircuitErrorLocation {\n        flipped_pauli_product: Z0\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.01) 0\n    }\n}\"\"\"\n\n    r = circuit.explain_detector_error_model_errors(\n        dem_filter=stim.DetectorErrorModel('error(1) D0 D1'),\n        reduce_to_one_representative_error=True,\n    )\n    assert len(r) == 1\n    assert str(r[0]) == \"\"\"ExplainedError {\n    dem_error_terms: D0 D1\n    CircuitErrorLocation {\n        flipped_pauli_product: Y0\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.01) 0\n    }\n}\"\"\"\n\n\ndef test_without_noise():\n    assert stim.Circuit(\"\"\"\n        X_ERROR(0.25) 0\n        CNOT 0 1\n        M(0.125) 0\n        REPEAT 50 {\n            DEPOLARIZE1(0.25) 0 1 2\n            X 0 1 2\n        }\n    \"\"\").without_noise() == stim.Circuit(\"\"\"\n        CNOT 0 1\n        M 0\n        REPEAT 50 {\n            X 0 1 2\n        }\n    \"\"\")\n\n\ndef test_flattened():\n    assert stim.Circuit(\"\"\"\n        SHIFT_COORDS(5, 0)\n        QUBIT_COORDS(1, 2, 3) 0\n        REPEAT 5 {\n            MR 0 1\n            DETECTOR(0, 0) rec[-2]\n            DETECTOR(1, 0) rec[-1]\n            SHIFT_COORDS(0, 1)\n        }\n    \"\"\").flattened() == stim.Circuit(\"\"\"\n        QUBIT_COORDS(6, 2, 3) 0\n        MR 0 1\n        DETECTOR(5, 0) rec[-2]\n        DETECTOR(6, 0) rec[-1]\n        MR 0 1\n        DETECTOR(5, 1) rec[-2]\n        DETECTOR(6, 1) rec[-1]\n        MR 0 1\n        DETECTOR(5, 2) rec[-2]\n        DETECTOR(6, 2) rec[-1]\n        MR 0 1\n        DETECTOR(5, 3) rec[-2]\n        DETECTOR(6, 3) rec[-1]\n        MR 0 1\n        DETECTOR(5, 4) rec[-2]\n        DETECTOR(6, 4) rec[-1]\n    \"\"\")\n\n\ndef test_complex_slice_does_not_seg_fault():\n    with pytest.raises(TypeError):\n        _ = stim.Circuit()[1j]\n\n\ndef test_circuit_from_file():\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = tmpdir + '/tmp.stim'\n        with open(path, 'w') as f:\n            print('H 5', file=f)\n        assert stim.Circuit.from_file(path) == stim.Circuit('H 5')\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = pathlib.Path(tmpdir) / 'tmp.stim'\n        with open(path, 'w') as f:\n            print('H 5', file=f)\n        assert stim.Circuit.from_file(path) == stim.Circuit('H 5')\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = tmpdir + '/tmp.stim'\n        with open(path, 'w') as f:\n            print('CNOT 4 5', file=f)\n        with open(path) as f:\n            assert stim.Circuit.from_file(f) == stim.Circuit('CX 4 5')\n\n    with pytest.raises(ValueError, match=\"how to read\"):\n        stim.Circuit.from_file(object())\n    with pytest.raises(ValueError, match=\"how to read\"):\n        stim.Circuit.from_file(123)\n\n\ndef test_circuit_to_file():\n    c = stim.Circuit('H 5\\ncnot 0 1')\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = tmpdir + '/tmp.stim'\n        c.to_file(path)\n        with open(path) as f:\n            assert f.read() == 'H 5\\nCX 0 1\\n'\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = pathlib.Path(tmpdir) / 'tmp.stim'\n        c.to_file(path)\n        with open(path) as f:\n            assert f.read() == 'H 5\\nCX 0 1\\n'\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = tmpdir + '/tmp.stim'\n        with open(path, 'w') as f:\n            c.to_file(f)\n        with open(path) as f:\n            assert f.read() == 'H 5\\nCX 0 1\\n'\n\n    with pytest.raises(ValueError, match=\"how to write\"):\n        c.to_file(object())\n    with pytest.raises(ValueError, match=\"how to write\"):\n        c.to_file(123)\n\n\ndef test_diagram():\n    c = stim.Circuit(\"\"\"\n        H 0\n        CX 0 1\n    \"\"\")\n    assert str(c.diagram()).strip() == \"\"\"\nq0: -H-@-\n       |\nq1: ---X-\n    \"\"\".strip()\n    assert str(c.diagram(type='timeline-text')) == str(c.diagram())\n\n    c = stim.Circuit(\"\"\"\n        H 0\n        CNOT 0 1\n        TICK\n        M 0 1\n        DETECTOR rec[-1] rec[-2]\n    \"\"\")\n    assert str(c.diagram(type='detector-slice-text', tick=1)).strip() == \"\"\"\nq0: -Z:D0-\n     |\nq1: -Z:D0-\n    \"\"\".strip()\n\n    c = stim.Circuit(\"\"\"\n        H 0\n        CNOT 0 1 0 2\n        TICK\n        M 0 1 2\n        DETECTOR(4,5) rec[-1] rec[-2]\n        DETECTOR(6) rec[-2] rec[-3]\n    \"\"\")\n    assert str(c.diagram(type='detector-slice-text', tick=1, filter_coords=[(5, 6, 7), (6,), (7, 8)])).strip() == \"\"\"\nq0: -Z:D1-\n     |\nq1: -Z:D1-\n\nq2: ------\n    \"\"\".strip()\n\n    assert c.diagram() is not None\n    assert c.diagram(type=\"timeline-svg\") is not None\n    assert c.diagram(type=\"timeline-svg\", tick=5) is not None\n    assert c.diagram(\"timeline-svg\") is not None\n    assert c.diagram(\"timeline-3d\") is not None\n    assert c.diagram(\"timeline-3d-html\") is not None\n\n    assert c.diagram(\"matchgraph-svg\") is not None\n    assert c.diagram(\"matchgraph-3d\") is not None\n    assert c.diagram(\"matchgraph-3d-html\") is not None\n    assert c.diagram(\"match-graph-svg\") is not None\n    assert c.diagram(\"match-graph-3d\") is not None\n    assert c.diagram(\"match-graph-3d-html\") is not None\n\n    assert c.diagram(\"detslice-svg\", tick=1) is not None\n    assert c.diagram(\"detslice-text\", tick=1) is not None\n    assert c.diagram(\"detector-slice-svg\", tick=1) is not None\n    assert c.diagram(\"detector-slice-text\", tick=1) is not None\n\n    assert c.diagram(\"detslice-with-ops-svg\", tick=1) is not None\n    assert c.diagram(\"timeslice-svg\", tick=1) is not None\n    assert c.diagram(\"time-slice-svg\", tick=1) is not None\n    assert c.diagram(\"time+detector-slice-svg\", tick=1) is not None\n    assert c.diagram(\"time+detector-slice-svg\", tick=range(1, 3)) is not None\n    with pytest.raises(ValueError, match=\"step\"):\n        assert c.diagram(\"time+detector-slice-svg\", tick=range(1, 3, 2)) is not None\n    with pytest.raises(ValueError, match=\"stop\"):\n        assert c.diagram(\"time+detector-slice-svg\", tick=range(3, 3)) is not None\n    assert \"iframe\" in str(c.diagram(type=\"match-graph-svg-html\"))\n    assert \"iframe\" in str(c.diagram(type=\"detslice-svg-html\"))\n    assert \"iframe\" in str(c.diagram(type=\"timeslice-svg-html\"))\n    assert \"iframe\" in str(c.diagram(type=\"timeline-svg-html\"))\n\n\ndef test_circuit_inverse():\n    assert stim.Circuit(\"\"\"\n        S 0 1\n        CX 0 1 0 2\n    \"\"\").inverse() == stim.Circuit(\"\"\"\n        CX 0 2 0 1\n        S_DAG 1 0\n    \"\"\")\n\n\ndef test_circuit_slice_reverse():\n    c = stim.Circuit()\n    assert c[::-1] == stim.Circuit()\n    c = stim.Circuit(\"X 1\\nY 2\\nZ 3\")\n    assert c[::-1] == stim.Circuit(\"Z 3\\nY 2\\nX 1\")\n\n\ndef test_with_inlined_feedback_bad_end_eats_into_loop():\n    assert stim.Circuit(\"\"\"\n        CX 0 1\n        M 1\n        CX rec[-1] 1\n        CX 0 1\n        M 1\n        DETECTOR rec[-1] rec[-2]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\").with_inlined_feedback() == stim.Circuit(\"\"\"\n        CX 0 1\n        M 1\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        CX 0 1\n        M 1\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n\n    before = stim.Circuit(\"\"\"\n        R 0 1 2 3 4 5 6\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 1 3 5\n        CX rec[-1] 5 rec[-2] 3 rec[-3] 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        REPEAT 10 {\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            CX 0 1 2 3 4 5\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            CX 6 5 4 3 2 1\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            M(0.25) 1 3 5\n            CX rec[-1] 5 rec[-2] 3 rec[-3] 1\n            DETECTOR rec[-1] rec[-4]\n            DETECTOR rec[-2] rec[-5]\n            DETECTOR rec[-3] rec[-6]\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n        }\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 1 3 5\n        CX rec[-1] 5 rec[-2] 3 rec[-3] 1\n        DETECTOR rec[-1] rec[-2] rec[-3]\n        DETECTOR rec[-3] rec[-4] rec[-5]\n        DETECTOR rec[-5] rec[-6] rec[-7]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    after = before.with_inlined_feedback()\n    assert after == stim.Circuit(\"\"\"\n        R 0 1 2 3 4 5 6\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 1 3 5\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 1 3 5\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        REPEAT 8 {\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            CX 0 1 2 3 4 5\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            CX 6 5 4 3 2 1\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            M(0.25) 1 3 5\n            DETECTOR rec[-7] rec[-1]\n            DETECTOR rec[-8] rec[-2]\n            DETECTOR rec[-9] rec[-3]\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n        }\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 1 3 5\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        DETECTOR rec[-7] rec[-1]\n        DETECTOR rec[-8] rec[-2]\n        DETECTOR rec[-9] rec[-3]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 1 3 5\n        DETECTOR rec[-6] rec[-5] rec[-4] rec[-3] rec[-2] rec[-1]\n        DETECTOR rec[-8] rec[-7] rec[-6] rec[-5] rec[-4] rec[-3]\n        DETECTOR rec[-10] rec[-9] rec[-8] rec[-7] rec[-6] rec[-5]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n\n    dem1 = before.flattened().detector_error_model()\n    dem2 = after.flattened().detector_error_model()\n    assert dem1.approx_equals(dem2, atol=1e-5)\n\n\ndef test_with_inlined_feedback():\n    assert stim.Circuit(\"\"\"\n        CX 0 1\n        M 1\n        CX rec[-1] 1\n        CX 0 1\n        M 1\n        DETECTOR rec[-1] rec[-2]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\").with_inlined_feedback() == stim.Circuit(\"\"\"\n        CX 0 1\n        M 1\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        CX 0 1\n        M 1\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n\n    before = stim.Circuit(\"\"\"\n        R 0 1 2 3 4 5 6\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 1 3 5\n        CX rec[-1] 5 rec[-2] 3 rec[-3] 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        REPEAT 10 {\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            CX 0 1 2 3 4 5\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            CX 6 5 4 3 2 1\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            M(0.25) 1 3 5\n            CX rec[-1] 5 rec[-2] 3 rec[-3] 1\n            DETECTOR rec[-1] rec[-4]\n            DETECTOR rec[-2] rec[-5]\n            DETECTOR rec[-3] rec[-6]\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n        }\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 0 1 2 3 4 5 6\n        CX rec[-1] 5 rec[-2] 3 rec[-3] 1\n        DETECTOR rec[-1] rec[-2] rec[-3]\n        DETECTOR rec[-3] rec[-4] rec[-5]\n        DETECTOR rec[-5] rec[-6] rec[-7]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    after = before.with_inlined_feedback()\n    assert str(after) == str(stim.Circuit(\"\"\"\n        R 0 1 2 3 4 5 6\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 1 3 5\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 1 3 5\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        REPEAT 9 {\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            CX 0 1 2 3 4 5\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            CX 6 5 4 3 2 1\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n            M(0.25) 1 3 5\n            DETECTOR rec[-7] rec[-1]\n            DETECTOR rec[-8] rec[-2]\n            DETECTOR rec[-9] rec[-3]\n            X_ERROR(0.125) 0 1 2 3 4 5 6\n            TICK\n        }\n\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 0 1 2 3 4 5\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        CX 6 5 4 3 2 1\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n        M(0.25) 0 1 2 3 4 5 6\n        DETECTOR rec[-8] rec[-3] rec[-2] rec[-1]\n        DETECTOR rec[-9] rec[-5] rec[-4] rec[-3]\n        DETECTOR rec[-10] rec[-7] rec[-6] rec[-5]\n        X_ERROR(0.125) 0 1 2 3 4 5 6\n        TICK\n\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\"))\n\n    dem1 = before.flattened().detector_error_model()\n    dem2 = after.flattened().detector_error_model()\n    assert dem1.approx_equals(dem2, atol=1e-5)\n\n\ndef test_detslice_ops_diagram_no_ticks_does_not_hang():\n    assert stim.Circuit.generated(\"surface_code:rotated_memory_x\", rounds=5, distance=5).diagram(\"detslice-svg\") is not None\n\n\ndef test_num_ticks():\n    assert stim.Circuit().num_ticks == 0\n    assert stim.Circuit(\"TICK\").num_ticks == 1\n    assert stim.Circuit(\"\"\"\n        TICK\n        REPEAT 100 {\n            TICK\n            TICK\n            REPEAT 10 {\n                TICK\n            }\n        }\n    \"\"\").num_ticks == 1201\n    assert stim.Circuit(\"\"\"\n        H 0\n        TICK\n        CX 0 1\n        TICK\n    \"\"\").num_ticks == 2\n\n\ndef test_reference_sample():\n    circuit = stim.Circuit(\n        \"\"\"\n        H 0\n        CNOT 0 1\n    \"\"\"\n    )\n    ref = circuit.reference_sample()\n    assert len(ref) == 0\n    circuit = stim.Circuit(\n        \"\"\"\n        H 0 1\n        CX 0 2 1 3\n        MPP X0*X1 Y0*Y1 Z0*Z1\n        \"\"\"\n    )\n    np.testing.assert_array_equal(circuit.reference_sample(), circuit.reference_sample())\n    assert np.sum(circuit.reference_sample()) % 2 == 1\n    circuit.append(\"X\", (i for i in range(0, 100, 2)))\n    circuit.append(\"M\", (i for i in range(100)))\n    ref_sample = circuit.reference_sample(bit_packed=True)\n    unpacked = np.unpackbits(ref_sample, bitorder=\"little\")\n    expected = circuit.reference_sample(bit_packed=False)\n    expected_padded = np.zeros_like(unpacked)\n    expected_padded[:len(expected)] = expected\n    np.testing.assert_array_equal(unpacked, expected_padded)\n\n\ndef test_max_mix_depolarization_is_allowed_in_dem_conversion_without_args():\n    assert stim.Circuit(\"\"\"\n        H 0\n        CX 0 1\n        DEPOLARIZE1(0.75) 0\n        CX 0 1\n        H 0\n        M 0 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n    \"\"\").detector_error_model(approximate_disjoint_errors=True) == stim.DetectorErrorModel(\"\"\"\n        error(0.5) D0\n        error(0.5) D0 D1\n        error(0.5) D1\n    \"\"\")\n\n    assert stim.Circuit(\"\"\"\n        H 0 1\n        CX 0 2 1 3\n        DEPOLARIZE2(0.9375) 0 1\n        CX 0 2 1 3\n        H 0 1\n        M 0 1 2 3\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n        DETECTOR rec[-4]\n    \"\"\").detector_error_model() == stim.DetectorErrorModel(\"\"\"\n        error(0.5) D0\n        error(0.5) D0 D1\n        error(0.5) D0 D1 D2\n        error(0.5) D0 D1 D2 D3\n        error(0.5) D0 D1 D3\n        error(0.5) D0 D2\n        error(0.5) D0 D2 D3\n        error(0.5) D0 D3\n        error(0.5) D1\n        error(0.5) D1 D2\n        error(0.5) D1 D2 D3\n        error(0.5) D1 D3\n        error(0.5) D2\n        error(0.5) D2 D3\n        error(0.5) D3\n    \"\"\")\n\n\ndef test_shortest_graphlike_error_many_obs():\n    c = stim.Circuit(\"\"\"\n        MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4\n        X_ERROR(0.1) 0 1 2 3 4\n        MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4\n        DETECTOR rec[-1] rec[-5]\n        DETECTOR rec[-2] rec[-6]\n        DETECTOR rec[-3] rec[-7]\n        DETECTOR rec[-4] rec[-8]\n        M 4\n        OBSERVABLE_INCLUDE(1200) rec[-1]\n    \"\"\")\n    assert len(c.shortest_graphlike_error()) == 5\n\n\ndef test_detslice_filter_coords_flexibility():\n    c = stim.Circuit.generated(\"repetition_code:memory\", distance=3, rounds=3)\n    d1 = c.diagram(\"detslice\", filter_coords=[stim.DemTarget.relative_detector_id(1)])\n    d2 = c.diagram(\"detslice-svg\", filter_coords=stim.DemTarget.relative_detector_id(1))\n    d3 = c.diagram(\"detslice\", filter_coords=[\"D1\"])\n    d4 = c.diagram(\"detslice\", filter_coords=\"D1\")\n    d5 = c.diagram(\"detector-slice-svg\", filter_coords=[3, 0])\n    d6 = c.diagram(\"detslice-svg\", filter_coords=[[3, 0]])\n    assert str(d1) == str(d2)\n    assert str(d1) == str(d3)\n    assert str(d1) == str(d4)\n    assert str(d1) == str(d5)\n    assert str(d1) == str(d6)\n    assert str(d1) != str(c.diagram(\"detslice\", filter_coords=\"L0\"))\n\n    d1 = c.diagram(\"detslice\", filter_coords=[stim.DemTarget.relative_detector_id(1), stim.DemTarget.relative_detector_id(3), stim.DemTarget.relative_detector_id(5), \"D7\"])\n    d2 = c.diagram(\"detslice\", filter_coords=[\"D1\", \"D3\", \"D5\", \"D7\"])\n    d3 = c.diagram(\"detslice-svg\", filter_coords=[3,])\n    d4 = c.diagram(\"detslice-svg\", filter_coords=[[3,]])\n    d5 = c.diagram(\"detslice-svg\", filter_coords=[[3, 0], [3, 1], [3, 2], [3, 3]])\n    assert str(d1) == str(d2)\n    assert str(d1) == str(d3)\n    assert str(d1) == str(d4)\n    assert str(d1) == str(d5)\n\n\ndef test_has_flow_ry():\n    c = stim.Circuit(\"\"\"\n        RY 0\n    \"\"\")\n    assert c.has_flow(stim.Flow(\"1 -> Y\"))\n    assert not c.has_flow(stim.Flow(\"1 -> -Y\"))\n    assert not c.has_flow(stim.Flow(\"1 -> X\"))\n    assert c.has_flow(stim.Flow(\"1 -> Y\"), unsigned=True)\n    assert not c.has_flow(stim.Flow(\"1 -> X\"), unsigned=True)\n    assert c.has_flow(stim.Flow(\"1 -> -Y\"), unsigned=True)\n\n\ndef test_has_flow_cxs():\n    c = stim.Circuit(\"\"\"\n        CX 0 1\n        S 0\n    \"\"\")\n\n    assert c.has_flow(stim.Flow(\"X_ -> YX\"))\n    assert c.has_flow(stim.Flow(\"Y_ -> -XX\"))\n    assert not c.has_flow(stim.Flow(\"X_ -> XX\"))\n    assert not c.has_flow(stim.Flow(\"X_ -> -XX\"))\n\n    assert c.has_flow(stim.Flow(\"X_ -> YX\"), unsigned=True)\n    assert c.has_flow(stim.Flow(\"Y_ -> -XX\"), unsigned=True)\n    assert not c.has_flow(stim.Flow(\"X_ -> XX\"), unsigned=True)\n    assert not c.has_flow(stim.Flow(\"X_ -> -XX\"), unsigned=True)\n\n\ndef test_has_flow_cxm():\n    c = stim.Circuit(\"\"\"\n        CX 0 1\n        M 1\n    \"\"\")\n    assert c.has_flow(stim.Flow(\"1 -> _Z xor rec[0]\"))\n    assert c.has_flow(stim.Flow(\"ZZ -> rec[0]\"))\n    assert c.has_flow(stim.Flow(\"ZZ -> _Z\"))\n    assert c.has_flow(stim.Flow(\"XX -> X_\"))\n    assert c.has_flow(stim.Flow(\"1 -> _Z xor rec[0]\"), unsigned=True)\n    assert c.has_flow(stim.Flow(\"ZZ -> rec[0]\"), unsigned=True)\n    assert c.has_flow(stim.Flow(\"ZZ -> _Z\"), unsigned=True)\n    assert c.has_flow(stim.Flow(\"XX -> X_\"), unsigned=True)\n\n\ndef test_has_flow_lattice_surgery():\n    c = stim.Circuit(\"\"\"\n        # Lattice surgery CNOT with feedback.\n        RX 2\n        MZZ 2 0\n        MXX 2 1\n        MZ 2\n        CX rec[-1] 1 rec[-3] 1\n        CZ rec[-2] 0\n\n        S 0\n    \"\"\")\n    assert c.has_flow(stim.Flow(\"X_ -> YX\"))\n    assert c.has_flow(stim.Flow(\"Z_ -> Z_\"))\n    assert c.has_flow(stim.Flow(\"_X -> _X\"))\n    assert c.has_flow(stim.Flow(\"_Z -> ZZ\"))\n    assert not c.has_flow(stim.Flow(\"X_ -> XX\"))\n\n    assert not c.has_flow(stim.Flow(\"X_ -> XX\"))\n    assert not c.has_flow(stim.Flow(\"X_ -> -YX\"))\n    assert not c.has_flow(stim.Flow(\"X_ -> XX\"), unsigned=True)\n    assert c.has_flow(stim.Flow(\"X_ -> -YX\"), unsigned=True)\n\n\ndef test_has_flow_lattice_surgery_without_feedback():\n    c = stim.Circuit(\"\"\"\n        # Lattice surgery CNOT without feedback.\n        RX 2\n        MZZ 2 0\n        MXX 2 1\n        MZ 2\n\n        S 0\n    \"\"\")\n    assert c.has_flow(stim.Flow(\"X_ -> YX xor rec[1]\"))\n    assert c.has_flow(stim.Flow(\"Z_ -> Z_\"))\n    assert c.has_flow(stim.Flow(\"_X -> _X\"))\n    assert c.has_flow(stim.Flow(\"_Z -> ZZ xor rec[0] xor rec[2]\"))\n    assert not c.has_flow(stim.Flow(\"X_ -> XX\"))\n    assert c.has_all_flows([])\n    assert c.has_all_flows([\n        stim.Flow(\"X_ -> YX xor rec[1]\"),\n        stim.Flow(\"Z_ -> Z_\"),\n    ])\n    assert not c.has_all_flows([\n        stim.Flow(\"X_ -> YX xor rec[1]\"),\n        stim.Flow(\"Z_ -> Z_\"),\n        stim.Flow(\"X_ -> XX\"),\n    ])\n\n    assert not c.has_flow(stim.Flow(\"X_ -> XX\"))\n    assert not c.has_flow(stim.Flow(\"X_ -> -YX\"))\n    assert not c.has_flow(stim.Flow(\"X_ -> XX\"), unsigned=True)\n    assert c.has_flow(stim.Flow(\"X_ -> -YX xor rec[1]\"), unsigned=True)\n\n\ndef test_has_flow_shorthands():\n    c = stim.Circuit(\"\"\"\n        MZ 99\n        MXX 1 99\n        MZZ 0 99\n        MX 99\n    \"\"\")\n\n    assert c.has_flow(stim.Flow(\"X_ -> XX xor rec[1] xor rec[3]\"))\n    assert c.has_flow(stim.Flow(\"Z_ -> Z_\"))\n    assert c.has_flow(stim.Flow(\"_X -> _X\"))\n    assert c.has_flow(stim.Flow(\"_Z -> ZZ xor rec[0] xor rec[2]\"))\n\n    assert c.has_flow(stim.Flow(\"X_ -> XX xor rec[1] xor rec[3]\"))\n    assert not c.has_flow(stim.Flow(\"Z_ -> -Z_\"))\n    assert not c.has_flow(stim.Flow(\"-Z_ -> Z_\"))\n    assert not c.has_flow(stim.Flow(\"Z_ -> X_\"))\n    assert c.has_flow(stim.Flow(\"iX_ -> iXX xor rec[1] xor rec[3]\"))\n    assert not c.has_flow(stim.Flow(\"-iX_ -> iXX xor rec[1] xor rec[3]\"))\n    assert c.has_flow(stim.Flow(\"-iX_ -> -iXX xor rec[1] xor rec[3]\"))\n    with pytest.raises(ValueError, match=\"Anti-Hermitian\"):\n        stim.Flow(\"iX_ -> XX\")\n\n\ndef test_decomposed():\n    assert stim.Circuit(\"\"\"\n        ISWAP 0 1 2 1\n        TICK\n        MPP X1*Z2*Y3\n    \"\"\").decomposed() == stim.Circuit(\"\"\"\n        H 0\n        CX 0 1 1 0\n        H 1\n        S 1 0\n        H 2\n        CX 2 1 1 2\n        H 1\n        S 1 2\n        TICK\n        H 1 3\n        S 3\n        H 3\n        S 3 3\n        CX 2 1 3 1\n        M 1\n        CX 2 1 3 1\n        H 3\n        S 3\n        H 3\n        S 3 3\n        H 1\n    \"\"\")\n\n\ndef test_detecting_regions():\n    assert stim.Circuit('''\n        R 0\n        TICK\n        H 0\n        TICK\n        CX 0 1\n        TICK\n        MX 0 1\n        DETECTOR rec[-1] rec[-2]\n    ''').detecting_regions() == {stim.DemTarget.relative_detector_id(0): {\n        0: stim.PauliString(\"Z_\"),\n        1: stim.PauliString(\"X_\"),\n        2: stim.PauliString(\"XX\"),\n    }}\n\n\ndef test_detecting_region_filters():\n    c = stim.Circuit.generated(\"repetition_code:memory\", distance=3, rounds=3)\n    assert len(c.detecting_regions(targets=[\"D\"])) == c.num_detectors\n    assert len(c.detecting_regions(targets=[\"L\"])) == c.num_observables\n    assert len(c.detecting_regions()) == c.num_observables + c.num_detectors\n    assert len(c.detecting_regions(targets=[\"D0\"])) == 1\n    assert len(c.detecting_regions(targets=[\"D0\", \"L0\"])) == 2\n    assert len(c.detecting_regions(targets=[stim.target_relative_detector_id(0), \"D0\"])) == 1\n\n\ndef test_detecting_regions_mzz():\n    c = stim.Circuit(\"\"\"\n        TICK\n        MZZ 0 1 1 2\n        TICK\n        M 2\n        DETECTOR rec[-1]\n    \"\"\")\n    assert c.detecting_regions() == {\n        stim.target_relative_detector_id(0): {\n            0: stim.PauliString(\"__Z\"),\n            1: stim.PauliString(\"__Z\"),\n        },\n    }\n\n\ndef test_insert():\n    c = stim.Circuit()\n    with pytest.raises(ValueError, match='type'):\n        c.insert(0, object())\n    with pytest.raises(ValueError, match='index <'):\n        c.insert(1, stim.CircuitInstruction(\"H\", [1]))\n    with pytest.raises(ValueError, match='index <'):\n        c.insert(-1, stim.CircuitInstruction(\"H\", [1]))\n    c.insert(0, stim.CircuitInstruction(\"H\", [1]))\n    assert c == stim.Circuit(\"\"\"\n        H 1\n    \"\"\")\n\n    with pytest.raises(ValueError, match='index <'):\n        c.insert(2, stim.CircuitInstruction(\"S\", [2]))\n    with pytest.raises(ValueError, match='index <'):\n        c.insert(-2, stim.CircuitInstruction(\"S\", [2]))\n    c.insert(0, stim.CircuitInstruction(\"S\", [2, 3]))\n    assert c == stim.Circuit(\"\"\"\n        S 2 3\n        H 1\n    \"\"\")\n\n    c.insert(-1, stim.Circuit(\"H 5\\nM 2\"))\n    assert c == stim.Circuit(\"\"\"\n        S 2 3\n        H 5\n        M 2\n        H 1\n    \"\"\")\n\n    c.insert(2, stim.Circuit(\"\"\"\n        REPEAT 100 {\n            M 3\n        }\n    \"\"\"))\n    assert c == stim.Circuit(\"\"\"\n        S 2 3\n        H 5\n        REPEAT 100 {\n            M 3\n        }\n        M 2\n        H 1\n    \"\"\")\n\n    c.insert(2, stim.Circuit(\"\"\"\n        REPEAT 100 {\n            M 3\n        }\n    \"\"\")[0])\n    assert c == stim.Circuit(\"\"\"\n        S 2 3\n        H 5\n        REPEAT 100 {\n            M 3\n        }\n        REPEAT 100 {\n            M 3\n        }\n        M 2\n        H 1\n    \"\"\")\n\n\ndef test_pop():\n    with pytest.raises(IndexError, match='index'):\n        stim.Circuit().pop()\n    with pytest.raises(IndexError, match='index'):\n        stim.Circuit().pop(-1)\n    with pytest.raises(IndexError, match='index'):\n        stim.Circuit().pop(0)\n    c = stim.Circuit(\"H 0\")\n    with pytest.raises(IndexError, match='index'):\n        c.pop(1)\n    with pytest.raises(IndexError, match='index'):\n        c.pop(-2)\n    assert c.pop(0) == stim.CircuitInstruction(\"H\", [0])\n    c = stim.Circuit(\"H 0\\n X 1\")\n    assert c.pop() == stim.CircuitInstruction(\"X\", [1])\n    assert c.pop() == stim.CircuitInstruction(\"H\", [0])\n\n\ndef test_circuit_create_with_odd_cx():\n    with pytest.raises(ValueError, match=\"0, 1, 2\"):\n        stim.Circuit(\"CX 0 1 2\")\n\n\ndef test_to_tableau():\n    assert stim.Circuit().to_tableau() == stim.Tableau(0)\n    assert stim.Circuit(\"QUBIT_COORDS 0\").to_tableau() == stim.Tableau(1)\n    assert stim.Circuit(\"I 0\").to_tableau() == stim.Tableau(1)\n    assert stim.Circuit(\"H 0\").to_tableau() == stim.Tableau.from_named_gate(\"H\")\n    assert stim.Circuit(\"CX 0 1\").to_tableau() == stim.Tableau.from_named_gate(\"CX\")\n    assert stim.Circuit(\"SPP Z0\").to_tableau() == stim.Tableau.from_named_gate(\"S\")\n    assert stim.Circuit(\"SPP X0\").to_tableau() == stim.Tableau.from_named_gate(\"SQRT_X\")\n    assert stim.Circuit(\"SPP_DAG Y0*Y1\").to_tableau() == stim.Tableau.from_named_gate(\"SQRT_YY_DAG\")\n\n\ndef test_circuit_tags():\n    c = stim.Circuit(\"\"\"\n        H[test] 0\n    \"\"\")\n    assert str(c) == \"H[test] 0\"\n    assert c[0].tag == 'test'\n    c.append(stim.CircuitInstruction('CX', [0, 1], tag='test2'))\n    assert c[1].tag == 'test2'\n    assert c == stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 0 1\n    \"\"\")\n    assert c != stim.Circuit(\"\"\"\n        H 0\n        CX 0 1\n    \"\"\")\n\n\ndef test_circuit_add_tags():\n    assert stim.Circuit(\"\"\"\n        H[test] 0\n    \"\"\") + stim.Circuit(\"\"\"\n        CX[test2] 0 1\n    \"\"\") == stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 0 1\n    \"\"\")\n\n\ndef test_circuit_eq_tags():\n    assert stim.CircuitInstruction(\"TICK\", tag=\"a\") == stim.CircuitInstruction(\"TICK\", tag=\"a\")\n    assert stim.CircuitInstruction(\"TICK\", tag=\"a\") != stim.CircuitInstruction(\"TICK\", tag=\"b\")\n    assert stim.CircuitRepeatBlock(1, stim.Circuit(), tag=\"a\") == stim.CircuitRepeatBlock(1, stim.Circuit(), tag=\"a\")\n    assert stim.CircuitRepeatBlock(1, stim.Circuit(), tag=\"a\") != stim.CircuitRepeatBlock(1, stim.Circuit(), tag=\"b\")\n    assert stim.Circuit(\"\"\"\n        H[test] 0\n    \"\"\") == stim.Circuit(\"\"\"\n        H[test] 0\n    \"\"\")\n    assert stim.Circuit(\"\"\"\n        H[test] 0\n    \"\"\") != stim.Circuit(\"\"\"\n        H[test2] 0\n    \"\"\")\n    assert stim.Circuit(\"\"\"\n        H[test] 0\n    \"\"\") != stim.Circuit(\"\"\"\n        H 0\n    \"\"\")\n    assert stim.Circuit(\"\"\"\n        H[] 0\n    \"\"\") == stim.Circuit(\"\"\"\n        H 0\n    \"\"\")\n\n\ndef test_circuit_get_item_tags():\n    assert stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n        REPEAT[test3] 3 {\n            M[test4](0.25) 4\n        }\n    \"\"\")[1] == stim.CircuitInstruction(\"CX[test2] 1 2\")\n    assert stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n        REPEAT[test3] 3 {\n            M[test4](0.25) 4\n        }\n    \"\"\")[2] == stim.CircuitRepeatBlock(3, stim.Circuit(\"M[test4](0.25) 4\"), tag=\"test3\")\n    assert stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n        REPEAT[test3] 3 {\n            M[test4](0.25) 4\n        }\n    \"\"\")[1:3] == stim.Circuit(\"\"\"\n        CX[test2] 1 2\n        REPEAT[test3] 3 {\n            M[test4](0.25) 4\n        }\n    \"\"\")\n\n\ndef test_tags_iadd():\n    c = stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n    \"\"\")\n    c += stim.Circuit(\"\"\"\n        REPEAT[test3] 3 {\n            M[test4](0.25) 4\n        }\n    \"\"\")\n    assert c == stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n        REPEAT[test3] 3 {\n            M[test4](0.25) 4\n        }\n    \"\"\")\n\n\ndef test_tags_imul():\n    c = stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n    \"\"\")\n    c *= 2\n    assert c == stim.Circuit(\"\"\"\n        REPEAT 2 {\n            H[test] 0\n            CX[test2] 1 2\n        }\n    \"\"\")\n\n\ndef test_tags_mul():\n    c = stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n    \"\"\")\n    assert c * 2 == stim.Circuit(\"\"\"\n        REPEAT 2 {\n            H[test] 0\n            CX[test2] 1 2\n        }\n    \"\"\")\n\n\ndef test_tags_append():\n    c = stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n    \"\"\")\n    c.append(stim.CircuitRepeatBlock(3, stim.Circuit(\"\"\"\n        M[test4](0.25) 4\n    \"\"\"), tag=\"test3\"))\n    assert c == stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n        REPEAT[test3] 3 {\n            M[test4](0.25) 4\n        }\n    \"\"\")\n\n\ndef test_tags_append_from_stim_program_text():\n    c = stim.Circuit()\n    c.append_from_stim_program_text(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n    \"\"\")\n    assert c == stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n    \"\"\")\n\n\ndef test_tag_approx_equals():\n    assert not stim.Circuit(\"H[test] 0\").approx_equals(stim.Circuit(\"H[test2] 0\"), atol=3)\n    assert stim.Circuit(\"H[test] 0\").approx_equals(stim.Circuit(\"H[test] 0\"), atol=3)\n\n\ndef test_tag_clear():\n    c = stim.Circuit(\"H[test] 0\")\n    c.clear()\n    assert c == stim.Circuit()\n\n\ndef test_tag_compile_samplers():\n    c = stim.Circuit(\"\"\"\n        R[test1] 0\n        X_ERROR[test2](0.25) 0\n        M[test3](0.25) 0\n        DETECTOR[test4](1, 2) rec[-1]\n    \"\"\")\n    s = c.compile_detector_sampler()\n    assert 200 < np.sum(s.sample(shots=1000)) < 600\n    s = c.compile_sampler()\n    assert 200 < np.sum(s.sample(shots=1000)) < 600\n    _ = c.compile_m2d_converter()\n\n\ndef test_tag_detector_error_model():\n    dem = stim.Circuit(\"\"\"\n        R[test1] 0\n        X_ERROR[test2](0.25) 0\n        M[test3](0.25) 0\n        DETECTOR[test4](1, 2) rec[-1]\n    \"\"\").detector_error_model()\n    assert dem == stim.DetectorErrorModel(\"\"\"\n        error[test2](0.25) D0\n        error[test3](0.25) D0\n        detector[test4](1, 2) D0\n    \"\"\")\n\n\ndef test_tag_copy():\n    c = stim.Circuit(\"\"\"\n        H[test] 0\n        CX[test2] 1 2\n        REPEAT[test3] 3 {\n            M[test4](0.25) 4\n        }\n    \"\"\").detector_error_model()\n    cc = c.copy()\n    assert cc is not c\n    assert cc == c\n\n\ndef test_tag_count_determined_measurements():\n    assert stim.Circuit(\"\"\"\n        R[test1] 0\n        X_ERROR[test2](0.25) 0\n        M[test3](0.25) 0\n        DETECTOR[test4](1, 2) rec[-1]\n    \"\"\").count_determined_measurements() == 1\n\n\ndef test_tag_decomposed():\n    assert stim.Circuit(\"\"\"\n        RX[test1] 0\n        X_ERROR[test2](0.25) 0\n        MPP[test3](0.25) X0*Z1\n        DETECTOR[test4](1, 2) rec[-1]\n        SPP[test5] Y0\n    \"\"\").decomposed() == stim.Circuit(\"\"\"\n        R[test1] 0\n        H[test1] 0\n        X_ERROR[test2](0.25) 0\n        H[test3] 0\n        CX[test3] 1 0\n        M[test3] 0\n        CX[test3] 1 0\n        H[test3] 0\n        DETECTOR[test4](1, 2) rec[-1]\n        H[test5] 0\n        S[test5] 0\n        H[test5] 0\n        S[test5] 0 0 0\n        H[test5] 0\n        S[test5] 0\n        H[test5] 0\n        S[test5] 0 0\n    \"\"\")\n\n\ndef test_tag_detecting_regions():\n    assert stim.Circuit(\"\"\"\n        R[test1] 0\n        X_ERROR[test2](0.25) 0\n        TICK\n        M[test3](0.25) 0\n        DETECTOR[test4](1, 2) rec[-1]\n    \"\"\").detecting_regions() == {stim.DemTarget('D0'): {0: stim.PauliString(\"Z\")}}\n\n\ndef test_tag_diagram():\n    # TODO: include tags in diagrams\n    assert str(stim.Circuit(\"\"\"\n        R[test1] 0\n        X_ERROR[test2](0.25) 0\n        M[test3](0.25) 0\n        DETECTOR[test4](1, 2) rec[-1]\n    \"\"\").diagram()) == \"\"\"\n        q0: -R-X_ERROR(0.25)-M(0.25):rec[0]-DETECTOR(1,2):D0=rec[0]-\n    \"\"\".strip()\n\n\ndef test_tag_flattened():\n    assert stim.Circuit(\"\"\"\n        R[test1] 0\n        REPEAT[test1.5] 2 {\n            H[test2] 0\n        }\n    \"\"\").flattened() == stim.Circuit(\"\"\"\n        R[test1] 0\n        H[test2] 0\n        H[test2] 0\n    \"\"\")\n\n\ndef test_tag_from_file():\n    c = stim.Circuit.from_file(io.StringIO(\"\"\"\n        R[test1] 0\n        REPEAT[test1.5] 2 {\n            H[test2] 0\n        }\n    \"\"\"))\n    assert c == stim.Circuit(\"\"\"\n        R[test1] 0\n        REPEAT[test1.5] 2 {\n            H[test2] 0\n        }\n    \"\"\")\n    s = io.StringIO()\n    c.to_file(s)\n    s.seek(0)\n    assert s.read() == str(c) + '\\n'\n\n\ndef test_tag_insert():\n    c = stim.Circuit(\"\"\"\n        H[test1] 0\n        S[test2] 0\n    \"\"\")\n    c.insert(1, stim.CircuitInstruction(\"CX[test3] 0 1\"))\n    assert c == stim.Circuit(\"\"\"\n        H[test1] 0\n        CX[test3] 0 1\n        S[test2] 0\n    \"\"\")\n\n\ndef test_tag_fuse():\n    c = stim.Circuit(\"\"\"\n        H[test1] 0\n        H[test1] 0\n        H[test2] 0\n        H[test1] 0\n    \"\"\")\n    assert len(c) == 3\n    assert c[0].tag == \"test1\"\n    assert c[1].tag == \"test2\"\n    assert c[2].tag == \"test1\"\n\n\ndef test_tag_inverse():\n    assert stim.Circuit(\"\"\"\n        S[test1] 0\n        CX[test2] 0 1\n        SPP[test3] X0*Y1\n        REPEAT[test4] 2 {\n            H[test5] 0\n        }\n    \"\"\").inverse() == stim.Circuit(\"\"\"\n        REPEAT[test4] 2 {\n            H[test5] 0\n        }\n        SPP_DAG[test3] Y1*X0\n        CX[test2] 0 1\n        S_DAG[test1] 0\n    \"\"\")\n\n\ndef test_tag_time_reversed_for_flows():\n    c, _ = stim.Circuit(\"\"\"\n        R[test1] 0\n        X_ERROR[test2](0.25) 0\n        SQRT_X[test3] 0\n        MY[test4] 0\n        DETECTOR[test5] rec[-1]\n    \"\"\").time_reversed_for_flows([])\n    assert c == stim.Circuit(\"\"\"\n        RY[test4] 0\n        SQRT_X_DAG[test3] 0\n        X_ERROR[test2](0.25) 0\n        M[test1] 0\n        DETECTOR[test5] rec[-1]\n    \"\"\")\n\n\ndef test_tag_with_inlined_feedback():\n    assert stim.Circuit(\"\"\"\n        R[test1] 0\n        X_ERROR[test2](0.25) 0 1\n        MR[test3] 0\n        CX[test4] rec[-1] 1\n        M[test5] 1\n        DETECTOR[test6] rec[-1]\n    \"\"\").with_inlined_feedback() == stim.Circuit(\"\"\"\n        R[test1] 0\n        X_ERROR[test2](0.25) 0 1\n        MR[test3] 0\n        M[test5] 1\n        DETECTOR[test6] rec[-2] rec[-1]\n    \"\"\")\n\n\ndef test_tag_without_noise():\n    assert stim.Circuit(\"\"\"\n        R[test1] 0\n        X_ERROR[test2](0.25) 0 1\n        M[test3](0.25) 0\n        DETECTOR[test4] rec[-1]\n    \"\"\").without_noise() == stim.Circuit(\"\"\"\n        R[test1] 0\n        M[test3] 0\n        DETECTOR[test4] rec[-1]\n    \"\"\")\n\n\ndef test_append_tag():\n    c = stim.Circuit()\n    c.append(\"H\", [2, 3], tag=\"test\")\n    assert c == stim.Circuit(\"H[test] 2 3\")\n\n    with pytest.raises(ValueError, match=\"tag\"):\n        c.append(c[0], tag=\"newtag\")\n\n    with pytest.raises(ValueError, match=\"tag\"):\n        c.append(stim.CircuitRepeatBlock(10, stim.Circuit()), tag=\"newtag\")\n\n    assert c == stim.Circuit(\"H[test] 2 3\")\n\n\ndef test_append_pauli_string():\n    c = stim.Circuit()\n    c.append(\"MPP\", [\n        stim.PauliString(\"X1*Y2*Z3\"),\n        stim.target_y(4),\n        stim.PauliString(\"Z5\"),\n    ])\n    assert c == stim.Circuit(\"\"\"\n        MPP X1*Y2*Z3 Y4 Z5\n    \"\"\")\n    c.append(\"MPP\", stim.PauliString(\"X1*X2\"))\n    assert c == stim.Circuit(\"\"\"\n        MPP X1*Y2*Z3 Y4 Z5 X1*X2\n    \"\"\")\n\n    with pytest.raises(ValueError, match=\"empty stim.PauliString\"):\n        c.append(\"MPP\", stim.PauliString(\"\"))\n    with pytest.raises(ValueError, match=\"empty stim.PauliString\"):\n        c.append(\"MPP\", [stim.PauliString(\"\")])\n    with pytest.raises(ValueError, match=\"empty stim.PauliString\"):\n        c.append(\"MPP\", [stim.PauliString(\"X1\"), stim.PauliString(\"\")])\n    assert c == stim.Circuit(\"\"\"\n        MPP X1*Y2*Z3 Y4 Z5 X1*X2\n    \"\"\")\n\n    with pytest.raises(ValueError, match=\"Don't know how to target\"):\n        c.append(\"MPP\", object())\n    with pytest.raises(ValueError, match=\"Don't know how to target\"):\n        c.append(\"MPP\", object())\n\n\ndef test_without_tags():\n    circuit = stim.Circuit(\"\"\"\n        H[tag] 5\n    \"\"\")\n    assert circuit.without_tags() == stim.Circuit(\"\"\"\n        H 5\n    \"\"\")\n\n\ndef test_reference_detector_and_observable_signs():\n    det, obs = stim.Circuit(\"\"\"\n        X 1\n        M 0 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        OBSERVABLE_INCLUDE(3) rec[-1] rec[-2]\n    \"\"\").reference_detector_and_observable_signs()\n    assert det.dtype == np.bool_\n    assert obs.dtype == np.bool_\n    np.testing.assert_array_equal(det, [True, False])\n    np.testing.assert_array_equal(obs, [False, False, False, True])\n\n    det, obs = stim.Circuit(\"\"\"\n        X 1\n        M 0 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        OBSERVABLE_INCLUDE(3) rec[-1] rec[-2]\n    \"\"\").reference_detector_and_observable_signs(bit_packed=True)\n    assert det.dtype == np.uint8\n    assert obs.dtype == np.uint8\n    np.testing.assert_array_equal(det, [0b01])\n    np.testing.assert_array_equal(obs, [0b1000])\n\n    circuit = stim.Circuit.generated(\"surface_code:rotated_memory_x\", rounds=3, distance=3)\n    det, obs = circuit.reference_detector_and_observable_signs(bit_packed=True)\n    assert det.dtype == np.uint8\n    assert obs.dtype == np.uint8\n    assert not np.any(det)\n    assert not np.any(obs)\n    assert len(det) == (circuit.num_detectors + 7) // 8\n    assert len(obs) == 1\n\n\ndef test_without_noise_removes_id_errors():\n    assert stim.Circuit(\"\"\"\n        I_ERROR 0\n        I_ERROR(0.25) 1\n        II_ERROR 2 3\n        II_ERROR(0.125) 3 4\n        H 0\n    \"\"\").without_noise() == stim.Circuit(\"\"\"\n        H 0\n    \"\"\")\n\n\ndef test_append_circuit_to_circuit():\n    circuit = stim.Circuit(\"\"\"\n        H 0\n    \"\"\")\n    circuit.append(stim.Circuit(\"\"\"\n        X 1\n        Z 2\n    \"\"\"))\n    assert circuit == stim.Circuit(\"\"\"\n        H 0\n        X 1\n        Z 2\n    \"\"\")\n"
  },
  {
    "path": "src/stim/circuit/circuit_repeat_block.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/circuit_repeat_block.pybind.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/circuit/circuit.pybind.h\"\n#include \"stim/circuit/circuit_instruction.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nCircuitRepeatBlock::CircuitRepeatBlock(uint64_t repeat_count, stim::Circuit body, pybind11::str tag)\n    : repeat_count(repeat_count), body(body), tag(tag) {\n    if (repeat_count == 0) {\n        throw std::invalid_argument(\"Can't repeat 0 times.\");\n    }\n}\n\nCircuit CircuitRepeatBlock::body_copy() {\n    return body;\n}\nbool CircuitRepeatBlock::operator==(const CircuitRepeatBlock &other) const {\n    return repeat_count == other.repeat_count && body == other.body &&\n           pybind11::cast<std::string_view>(tag) == pybind11::cast<std::string_view>(other.tag);\n}\nbool CircuitRepeatBlock::operator!=(const CircuitRepeatBlock &other) const {\n    return !(*this == other);\n}\nstd::string CircuitRepeatBlock::repr() const {\n    return \"stim.CircuitRepeatBlock(\" + std::to_string(repeat_count) + \", \" + circuit_repr(body) + \")\";\n}\n\npybind11::class_<CircuitRepeatBlock> stim_pybind::pybind_circuit_repeat_block(pybind11::module &m) {\n    return pybind11::class_<CircuitRepeatBlock>(\n        m,\n        \"CircuitRepeatBlock\",\n        clean_doc_string(R\"DOC(\n            A REPEAT block from a circuit.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     H 0\n                ...     REPEAT 5 {\n                ...         CX 0 1\n                ...         CZ 1 2\n                ...     }\n                ... ''')\n                >>> repeat_block = circuit[1]\n                >>> repeat_block.repeat_count\n                5\n                >>> repeat_block.body_copy()\n                stim.Circuit('''\n                    CX 0 1\n                    CZ 1 2\n                ''')\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_circuit_repeat_block_methods(pybind11::module &m, pybind11::class_<CircuitRepeatBlock> &c) {\n    c.def(\n        pybind11::init<uint64_t, Circuit, pybind11::str>(),\n        pybind11::arg(\"repeat_count\"),\n        pybind11::arg(\"body\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"tag\") = \"\",\n        clean_doc_string(R\"DOC(\n            Initializes a `stim.CircuitRepeatBlock`.\n\n            Args:\n                repeat_count: The number of times to repeat the block.\n                body: The body of the block, as a circuit.\n                tag: Defaults to empty. A custom string attached to the REPEAT instruction.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit()\n                >>> c.append(stim.CircuitRepeatBlock(100, stim.Circuit(\"M 0\")))\n                >>> c\n                stim.Circuit('''\n                    REPEAT 100 {\n                        M 0\n                    }\n                ''')\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"repeat_count\",\n        &CircuitRepeatBlock::repeat_count,\n        clean_doc_string(R\"DOC(\n            The repetition count of the repeat block.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     H 0\n                ...     REPEAT 5 {\n                ...         CX 0 1\n                ...         CZ 1 2\n                ...     }\n                ... ''')\n                >>> repeat_block = circuit[1]\n                >>> repeat_block.repeat_count\n                5\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"name\",\n        [](const CircuitRepeatBlock &self) -> pybind11::str {\n            return pybind11::cast(\"REPEAT\");\n        },\n        clean_doc_string(R\"DOC(\n            Returns the name \"REPEAT\".\n\n            This is a duck-typing convenience method. It exists so that code that doesn't\n            know whether it has a `stim.CircuitInstruction` or a `stim.CircuitRepeatBlock`\n            can check the object's name without having to do an `instanceof` check first.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     H 0\n                ...     REPEAT 5 {\n                ...         CX 1 2\n                ...     }\n                ...     S 1\n                ... ''')\n                >>> [instruction.name for instruction in circuit]\n                ['H', 'REPEAT', 'S']\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_measurements\",\n        [](const CircuitRepeatBlock &self) -> uint64_t {\n            return self.body.count_measurements() * self.repeat_count;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of bits produced when running this loop.\n\n            Examples:\n                >>> import stim\n                >>> stim.CircuitRepeatBlock(\n                ...     body=stim.Circuit(\"M 0 1\"),\n                ...     repeat_count=25,\n                ... ).num_measurements\n                50\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"repeat_count\",\n        &CircuitRepeatBlock::repeat_count,\n        clean_doc_string(R\"DOC(\n            The repetition count of the repeat block.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     H 0\n                ...     REPEAT 5 {\n                ...         CX 0 1\n                ...         CZ 1 2\n                ...     }\n                ... ''')\n                >>> repeat_block = circuit[1]\n                >>> repeat_block.repeat_count\n                5\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"tag\",\n        [](CircuitRepeatBlock &self) -> pybind11::str {\n            return self.tag;\n        },\n        clean_doc_string(R\"DOC(\n            The custom tag attached to the REPEAT instruction.\n\n            The tag is an arbitrary string.\n            The default tag, when none is specified, is the empty string.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     REPEAT[test] 5 {\n                ...         H 0\n                ...     }\n                ... ''')[0].tag\n                'test'\n\n                >>> stim.Circuit('''\n                ...     REPEAT 5 {\n                ...         H 0\n                ...     }\n                ... ''')[0].tag\n                ''\n        )DOC\")\n            .data());\n\n    c.def(\n        \"body_copy\",\n        &CircuitRepeatBlock::body_copy,\n        clean_doc_string(R\"DOC(\n            Returns a copy of the body of the repeat block.\n\n            (Making a copy is enforced to make it clear that editing the result won't change\n            the block's body.)\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     H 0\n                ...     REPEAT 5 {\n                ...         CX 0 1\n                ...         CZ 1 2\n                ...     }\n                ... ''')\n                >>> repeat_block = circuit[1]\n                >>> repeat_block.body_copy()\n                stim.Circuit('''\n                    CX 0 1\n                    CZ 1 2\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two `stim.CircuitRepeatBlock`s are identical.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two `stim.CircuitRepeatBlock`s are different.\");\n    c.def(\n        \"__repr__\",\n        &CircuitRepeatBlock::repr,\n        \"Returns valid python code evaluating to an equivalent `stim.CircuitRepeatBlock`.\");\n}\n"
  },
  {
    "path": "src/stim/circuit/circuit_repeat_block.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_CIRCUIT_CIRCUIT_REPEAT_BLOCK_PYBIND_H\n#define _STIM_CIRCUIT_CIRCUIT_REPEAT_BLOCK_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim_pybind {\n\nstruct CircuitRepeatBlock {\n    uint64_t repeat_count;\n    stim::Circuit body;\n    pybind11::str tag;\n    CircuitRepeatBlock(uint64_t repeat_count, stim::Circuit body, pybind11::str tag);\n    stim::Circuit body_copy();\n    bool operator==(const CircuitRepeatBlock &other) const;\n    bool operator!=(const CircuitRepeatBlock &other) const;\n    std::string repr() const;\n};\n\npybind11::class_<CircuitRepeatBlock> pybind_circuit_repeat_block(pybind11::module &m);\nvoid pybind_circuit_repeat_block_methods(pybind11::module &m, pybind11::class_<CircuitRepeatBlock> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/circuit/circuit_repeat_block_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport stim\nimport pytest\n\n\ndef test_init_and_equality():\n    r = stim.CircuitRepeatBlock(500, stim.Circuit(\"X 0\"))\n    assert r.repeat_count == 500\n    assert r.body_copy() == stim.Circuit(\"X 0\")\n    assert stim.CircuitRepeatBlock(500, stim.Circuit(\"X 0\")) == stim.CircuitRepeatBlock(500, stim.Circuit(\"X 0\"))\n    assert stim.CircuitRepeatBlock(500, stim.Circuit(\"X 0\")) != stim.CircuitRepeatBlock(500, stim.Circuit())\n    assert stim.CircuitRepeatBlock(500, stim.Circuit(\"X 0\")) != stim.CircuitRepeatBlock(101, stim.Circuit(\"X 0\"))\n    assert not (stim.CircuitRepeatBlock(500, stim.Circuit(\"X 0\")) == stim.CircuitRepeatBlock(500, stim.Circuit()))\n    assert not (stim.CircuitRepeatBlock(500, stim.Circuit(\"X 0\")) != stim.CircuitRepeatBlock(500, stim.Circuit(\"X 0\")))\n    r2 = stim.CircuitRepeatBlock(repeat_count=500, body=stim.Circuit(\"X 0\"))\n    assert r == r2\n\n    with pytest.raises(ValueError, match=\"repeat 0\"):\n        stim.CircuitRepeatBlock(0, stim.Circuit())\n\n\n@pytest.mark.parametrize(\"value\", [\n    stim.CircuitRepeatBlock(500, stim.Circuit(\"X 0\")),\n    stim.CircuitRepeatBlock(1, stim.Circuit(\"X 0\\nREPEAT 100 {\\nH 1\\n}\\n\")),\n])\ndef test_repr(value):\n    assert eval(repr(value), {'stim': stim}) == value\n    assert repr(eval(repr(value), {'stim': stim})) == repr(value)\n\n\ndef test_name():\n    assert [e.name for e in stim.Circuit('''\n        H 0\n        REPEAT 5 {\n            CX 1 2\n        }\n        S 1\n    ''')] == ['H', 'REPEAT', 'S']\n"
  },
  {
    "path": "src/stim/circuit/gate_decomposition.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/circuit/gate_decomposition.h\"\n\n#include <span>\n\n#include \"stim/stabilizers/pauli_string.h\"\n\nusing namespace stim;\n\nstruct ConjugateBySelfInverse {\n    CircuitInstruction inst;\n    const std::function<void(const CircuitInstruction &inst)> &do_instruction_callback;\n    ConjugateBySelfInverse(\n        CircuitInstruction inst, const std::function<void(const CircuitInstruction &inst)> &do_instruction_callback)\n        : inst(inst), do_instruction_callback(do_instruction_callback) {\n        if (!inst.targets.empty()) {\n            do_instruction_callback(inst);\n        }\n    }\n    ~ConjugateBySelfInverse() {\n        if (!inst.targets.empty()) {\n            do_instruction_callback(inst);\n        }\n    }\n};\n\nbool stim::accumulate_next_obs_terms_to_pauli_string_helper(\n    CircuitInstruction instruction,\n    size_t *start,\n    PauliString<64> *obs,\n    std::vector<GateTarget> *bits,\n    bool allow_imaginary) {\n    if (*start >= instruction.targets.size()) {\n        return false;\n    }\n\n    if (bits != nullptr) {\n        bits->clear();\n    }\n    obs->xs.clear();\n    obs->zs.clear();\n    obs->sign = false;\n    bool imag = false;\n\n    // Find end of current product.\n    size_t end = *start + 1;\n    while (end < instruction.targets.size() && instruction.targets[end].is_combiner()) {\n        end += 2;\n    }\n\n    // Accumulate terms.\n    for (size_t k = *start; k < end; k += 2) {\n        GateTarget t = instruction.targets[k];\n\n        if (t.is_pauli_target()) {\n            obs->left_mul_pauli(t, &imag);\n        } else if (t.is_classical_bit_target() && bits != nullptr) {\n            bits->push_back(t);\n        } else {\n            throw std::invalid_argument(\"Found an unsupported target `\" + t.str() + \"` in \" + instruction.str());\n        }\n    }\n\n    if (imag && !allow_imaginary) {\n        throw std::invalid_argument(\n            \"Acted on an anti-Hermitian operator (e.g. X0*Z0 instead of Y0) in \" + instruction.str());\n    }\n\n    *start = end;\n    return true;\n}\n\nvoid stim::decompose_mpp_operation(\n    const CircuitInstruction &mpp_op,\n    size_t num_qubits,\n    const std::function<void(const CircuitInstruction &inst)> &do_instruction_callback) {\n    PauliString<64> current(num_qubits);\n    simd_bits<64> merged(num_qubits);\n    std::vector<GateTarget> h_xz;\n    std::vector<GateTarget> h_yz;\n    std::vector<GateTarget> cnot;\n    std::vector<GateTarget> meas;\n\n    auto flush = [&]() {\n        if (meas.empty()) {\n            return;\n        }\n        {\n            ConjugateBySelfInverse c1(CircuitInstruction(GateType::H, {}, h_xz, mpp_op.tag), do_instruction_callback);\n            ConjugateBySelfInverse c2(\n                CircuitInstruction(GateType::H_YZ, {}, h_yz, mpp_op.tag), do_instruction_callback);\n            ConjugateBySelfInverse c3(CircuitInstruction(GateType::CX, {}, cnot, mpp_op.tag), do_instruction_callback);\n            do_instruction_callback(CircuitInstruction(GateType::M, mpp_op.args, meas, mpp_op.tag));\n        }\n        h_xz.clear();\n        h_yz.clear();\n        cnot.clear();\n        meas.clear();\n        merged.clear();\n    };\n\n    size_t start = 0;\n    while (accumulate_next_obs_terms_to_pauli_string_helper(mpp_op, &start, &current, nullptr)) {\n        // Products equal to +-I become MPAD instructions.\n        if (current.ref().has_no_pauli_terms()) {\n            flush();\n            GateTarget t = GateTarget::qubit((uint32_t)current.sign);\n            do_instruction_callback(CircuitInstruction{GateType::MPAD, mpp_op.args, &t, mpp_op.tag});\n            continue;\n        }\n\n        // If there's overlap with previous groups, the previous groups need to be flushed.\n        if (current.xs.intersects(merged) || current.zs.intersects(merged)) {\n            flush();\n        }\n        merged |= current.xs;\n        merged |= current.zs;\n\n        // Buffer operations to perform the desired measurement.\n        bool first = true;\n        current.ref().for_each_active_pauli([&](uint32_t q) {\n            bool x = current.xs[q];\n            bool z = current.zs[q];\n            // Include single qubit gates transforming the Pauli into a Z.\n            if (x) {\n                if (z) {\n                    h_yz.push_back({q});\n                } else {\n                    h_xz.push_back({q});\n                }\n            }\n            // Include CNOT gates folding onto a single measured qubit.\n            if (first) {\n                meas.push_back(GateTarget::qubit(q, current.sign));\n                first = false;\n            } else {\n                cnot.push_back({q});\n                cnot.push_back({meas.back().qubit_value()});\n            }\n        });\n        assert(!first);\n    }\n\n    // Flush remaining groups.\n    flush();\n}\n\nstatic void decompose_spp_or_spp_dag_operation_helper(\n    PauliStringRef<64> observable,\n    std::span<const GateTarget> classical_bits,\n    bool invert_sign,\n    const std::function<void(const CircuitInstruction &inst)> &do_instruction_callback,\n    std::vector<GateTarget> *h_xz_buf,\n    std::vector<GateTarget> *h_yz_buf,\n    std::vector<GateTarget> *cnot_buf,\n    std::string_view tag) {\n    h_xz_buf->clear();\n    h_yz_buf->clear();\n    cnot_buf->clear();\n\n    // Assemble quantum terms from the observable.\n    uint64_t focus_qubit = UINT64_MAX;\n    observable.for_each_active_pauli([&](uint32_t q) {\n        bool x = observable.xs[q];\n        bool z = observable.zs[q];\n        // Include single qubit gates transforming the Pauli into a Z.\n        if (x) {\n            if (z) {\n                h_yz_buf->push_back({q});\n            } else {\n                h_xz_buf->push_back({q});\n            }\n        }\n        // Include CNOT gates folding onto a single measured qubit.\n        if (focus_qubit == UINT64_MAX) {\n            focus_qubit = q;\n        } else {\n            cnot_buf->push_back({q});\n            cnot_buf->push_back({(uint32_t)focus_qubit});\n        }\n    });\n\n    // Products need a quantum part to have an observable effect.\n    if (focus_qubit == UINT64_MAX) {\n        return;\n    }\n\n    for (const auto &t : classical_bits) {\n        cnot_buf->push_back({t});\n        cnot_buf->push_back({(uint32_t)focus_qubit});\n    }\n\n    GateTarget t = GateTarget::qubit(focus_qubit);\n    bool sign = invert_sign ^ observable.sign;\n    GateType g = sign ? GateType::S_DAG : GateType::S;\n    {\n        ConjugateBySelfInverse c1(CircuitInstruction(GateType::H, {}, *h_xz_buf, tag), do_instruction_callback);\n        ConjugateBySelfInverse c2(CircuitInstruction(GateType::H_YZ, {}, *h_yz_buf, tag), do_instruction_callback);\n        ConjugateBySelfInverse c3(CircuitInstruction(GateType::CX, {}, *cnot_buf, tag), do_instruction_callback);\n        do_instruction_callback(CircuitInstruction(g, {}, &t, tag));\n    }\n}\n\nvoid stim::decompose_spp_or_spp_dag_operation(\n    const CircuitInstruction &spp_op,\n    size_t num_qubits,\n    bool invert_sign,\n    const std::function<void(const CircuitInstruction &inst)> &do_instruction_callback) {\n    PauliString<64> obs(num_qubits);\n    std::vector<GateTarget> h_xz_buf;\n    std::vector<GateTarget> h_yz_buf;\n    std::vector<GateTarget> cnot_buf;\n    std::vector<GateTarget> bits;\n\n    if (spp_op.gate_type == GateType::SPP) {\n        // No sign inversion needed.\n    } else if (spp_op.gate_type == GateType::SPP_DAG) {\n        invert_sign ^= true;\n    } else {\n        throw std::invalid_argument(\"Not an SPP or SPP_DAG instruction: \" + spp_op.str());\n    }\n\n    size_t start = 0;\n    while (accumulate_next_obs_terms_to_pauli_string_helper(spp_op, &start, &obs, &bits)) {\n        decompose_spp_or_spp_dag_operation_helper(\n            obs, bits, invert_sign, do_instruction_callback, &h_xz_buf, &h_yz_buf, &cnot_buf, spp_op.tag);\n    }\n}\n\nvoid stim::decompose_pair_instruction_into_disjoint_segments(\n    const CircuitInstruction &inst, size_t num_qubits, const std::function<void(CircuitInstruction)> &callback) {\n    simd_bits<64> used_as_control(num_qubits);\n    size_t num_flushed = 0;\n    size_t cur_index = 0;\n    auto flush = [&]() {\n        callback(\n            CircuitInstruction{\n                inst.gate_type,\n                inst.args,\n                inst.targets.sub(num_flushed, cur_index),\n                inst.tag,\n            });\n        used_as_control.clear();\n        num_flushed = cur_index;\n    };\n    while (cur_index < inst.targets.size()) {\n        size_t q0 = inst.targets[cur_index].qubit_value();\n        size_t q1 = inst.targets[cur_index + 1].qubit_value();\n        if (used_as_control[q0] || used_as_control[q1]) {\n            flush();\n        }\n        used_as_control[q0] = true;\n        used_as_control[q1] = true;\n        cur_index += 2;\n    }\n    if (num_flushed < inst.targets.size()) {\n        flush();\n    }\n}\n\nvoid stim::for_each_disjoint_target_segment_in_instruction_reversed(\n    const CircuitInstruction &inst,\n    simd_bits_range_ref<64> workspace,\n    const std::function<void(CircuitInstruction)> &callback) {\n    workspace.clear();\n    size_t cur_end = inst.targets.size();\n    size_t cur_start = inst.targets.size();\n    auto flush = [&]() {\n        callback(CircuitInstruction(inst.gate_type, inst.args, inst.targets.sub(cur_start, cur_end), inst.tag));\n        workspace.clear();\n        cur_end = cur_start;\n    };\n    while (cur_start > 0) {\n        auto t = inst.targets[cur_start - 1];\n        if (t.has_qubit_value()) {\n            if (workspace[t.qubit_value()]) {\n                flush();\n            }\n            workspace[t.qubit_value()] = true;\n        }\n        cur_start--;\n    }\n    if (cur_end > 0) {\n        flush();\n    }\n}\n\nvoid stim::for_each_combined_targets_group(\n    const CircuitInstruction &inst, const std::function<void(CircuitInstruction)> &callback) {\n    if (inst.targets.empty()) {\n        return;\n    }\n    size_t start = 0;\n    size_t next_start = 1;\n    while (true) {\n        if (next_start >= inst.targets.size() || !inst.targets[next_start].is_combiner()) {\n            callback(CircuitInstruction(inst.gate_type, inst.args, inst.targets.sub(start, next_start), inst.tag));\n            start = next_start;\n            next_start = start + 1;\n            if (next_start > inst.targets.size()) {\n                return;\n            }\n        } else {\n            next_start += 2;\n        }\n    }\n}\n"
  },
  {
    "path": "src/stim/circuit/gate_decomposition.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_GATE_DECOMPOSITION_H\n#define _STIM_GATE_DECOMPOSITION_H\n\n#include <functional>\n\n#include \"stim/circuit/circuit_instruction.h\"\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/mem/simd_bits.h\"\n\nnamespace stim {\n\n/// Decomposes MPP operations into sequences of simpler operations with the same effect.\n///\n/// The idea is that an instruction like\n///\n///     MPP X0*Z1*Y2 X3*X4 Y0*Y1*Y2*Y3*Y4\n///\n/// can be decomposed into a sequence of instructions like\n///\n///     H_XZ 0 3 4\n///     H_YZ 2\n///     CX 1 0 2 0 4 3\n///     M 0 3\n///     CX 1 0 2 0 4 3\n///     H_YZ 2\n///     H_XZ 0 3 4\n///\n///     H_YZ 0 1 2 3 4\n///     CX 1 0 2 0 3 0 4 0\n///     M 0\n///     CX 1 0 2 0 3 0 4 0\n///     H_YZ 0 1 2 3 4\n///\n/// This is tedious to do, so this method does it for you.\n///\n/// Args:\n///     mpp_op: The operation to decompose.\n///     num_qubits: The number of qubits in the system. All targets must be less than this.\n///     callback: How to execute decomposed instructions.\nvoid decompose_mpp_operation(\n    const CircuitInstruction &mpp_op,\n    size_t num_qubits,\n    const std::function<void(const CircuitInstruction &inst)> &do_instruction_callback);\n\n/// Decomposes SPP operations into sequences of simpler operations with the same effect.\nvoid decompose_spp_or_spp_dag_operation(\n    const CircuitInstruction &spp_op,\n    size_t num_qubits,\n    bool invert_sign,\n    const std::function<void(const CircuitInstruction &inst)> &do_instruction_callback);\n\n/// Finds contiguous segments where the first target of each pair is used once.\n///\n/// This is used when decomposing operations like MXX into CX and MX. The CX\n/// gates can overlap on their targets, but the measurements can't overlap with\n/// each other and the measurements can't overlap with the controls of the CX\n/// gates.\n///\n/// The idea is that an instruction like\n///\n///     MXX 0 1 0 2 3 5 4 5 3 4\n///\n/// can be decomposed into a sequence of instructions like\n///\n///     CX 0 1\n///     MX 0\n///     CX 0 1\n///\n///     CX 0 2 3 5 4 5\n///     MX 0 3 4\n///     CX 0 2 3 5 4 5\n///\n///     CX 3 4\n///     MX 3\n///     CX 3 4\n///\n/// Args:\n///     num_qubits: The number of qubits in the system. All targets in the circuit\n///         instruction must be less than this.\n///     inst: The circuit instruction to decompose.\n///     callback: The method called with each decomposed segment.\nvoid decompose_pair_instruction_into_disjoint_segments(\n    const CircuitInstruction &inst, size_t num_qubits, const std::function<void(CircuitInstruction)> &callback);\n\nbool accumulate_next_obs_terms_to_pauli_string_helper(\n    CircuitInstruction instruction,\n    size_t *start,\n    PauliString<64> *obs,\n    std::vector<GateTarget> *bits,\n    bool allow_imaginary = false);\n\nvoid for_each_disjoint_target_segment_in_instruction_reversed(\n    const CircuitInstruction &inst,\n    simd_bits_range_ref<64> workspace,\n    const std::function<void(CircuitInstruction)> &callback);\n\nvoid for_each_combined_targets_group(\n    const CircuitInstruction &inst, const std::function<void(CircuitInstruction)> &callback);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/circuit/gate_decomposition.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/gate_decomposition.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/cmd/command_help.h\"\n\nusing namespace stim;\n\nTEST(gate_decomposition, decompose_mpp_operation) {\n    Circuit out;\n    auto append_into_circuit = [&](const CircuitInstruction &inst) {\n        out.safe_append(inst);\n        out.append_from_text(\"TICK\");\n    };\n    decompose_mpp_operation(\n        Circuit(\"MPP(0.125) X0*X1*X2 Z3*Z4*Z5 X2*Y4 Z3 Z3 Z4*Z5\").operations[0], 10, append_into_circuit);\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        H 0 1 2\n        TICK\n        CX 1 0 2 0 4 3 5 3\n        TICK\n        M(0.125) 0 3\n        TICK\n        CX 1 0 2 0 4 3 5 3\n        TICK\n        H 0 1 2\n        TICK\n\n        H 2\n        TICK\n        H_YZ 4\n        TICK\n        CX 4 2\n        TICK\n        M(0.125) 2 3\n        TICK\n        CX 4 2\n        TICK\n        H_YZ 4\n        TICK\n        H 2\n        TICK\n\n        CX 5 4\n        TICK\n        M(0.125) 3 4\n        TICK\n        CX 5 4\n        TICK\n    )CIRCUIT\"));\n\n    out.clear();\n    decompose_mpp_operation(Circuit(\"MPP X0*Z1*Y2 X3*X4 Y0*Y1*Y2*Y3*Y4\").operations[0], 10, append_into_circuit);\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        H 0 3 4\n        TICK\n        H_YZ 2\n        TICK\n        CX 1 0 2 0 4 3\n        TICK\n        M 0 3\n        TICK\n        CX 1 0 2 0 4 3\n        TICK\n        H_YZ 2\n        TICK\n        H 0 3 4\n        TICK\n\n        H_YZ 0 1 2 3 4\n        TICK\n        CX 1 0 2 0 3 0 4 0\n        TICK\n        M 0\n        TICK\n        CX 1 0 2 0 3 0 4 0\n        TICK\n        H_YZ 0 1 2 3 4\n        TICK\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_mpp_to_mpad) {\n    Circuit out;\n    auto append_into_circuit = [&](const CircuitInstruction &inst) {\n        out.safe_append(inst);\n        out.append_from_text(\"TICK\");\n    };\n    decompose_mpp_operation(\n        Circuit(R\"CIRCUIT(\n            MPP(0.125) X0*X0 X0*!X0 X0*Y0*Z0*X1*Y1*Z1\n        )CIRCUIT\")\n            .operations[0],\n        10,\n        append_into_circuit);\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        MPAD(0.125) 0\n        TICK\n        MPAD(0.125) 1\n        TICK\n        MPAD(0.125) 1\n        TICK\n    )CIRCUIT\"));\n\n    ASSERT_THROW(\n        { decompose_mpp_operation(Circuit(\"MPP(0.125) X0*Y0*Z0\").operations[0], 10, append_into_circuit); },\n        std::invalid_argument);\n}\n\nTEST(gate_decomposition, decompose_pair_instruction_into_disjoint_segments) {\n    Circuit out;\n    auto append_into_circuit = [&](const CircuitInstruction &segment) {\n        out.safe_append(segment);\n        out.append_from_text(\"TICK\");\n    };\n    decompose_pair_instruction_into_disjoint_segments(\n        Circuit(\"MXX(0.125) 0 1 0 2 3 5 4 5 3 4\").operations[0], 10, append_into_circuit);\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        MXX(0.125) 0 1\n        TICK\n\n        MXX(0.125) 0 2 3 5\n        TICK\n\n        MXX(0.125) 4 5\n        TICK\n\n        MXX(0.125) 3 4\n        TICK\n    )CIRCUIT\"));\n\n    out.clear();\n    decompose_pair_instruction_into_disjoint_segments(Circuit(\"MZZ 0 1 1 2\").operations[0], 10, append_into_circuit);\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        MZZ 0 1\n        TICK\n\n        MZZ 1 2\n        TICK\n    )CIRCUIT\"));\n\n    out.clear();\n    decompose_pair_instruction_into_disjoint_segments(Circuit(\"MZZ\").operations[0], 10, append_into_circuit);\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_simple) {\n    Circuit out;\n    decompose_spp_or_spp_dag_operation(Circuit(\"SPP Z0\").operations[0], 10, false, [&](const CircuitInstruction &inst) {\n        out.safe_append(inst);\n    });\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        S 0\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_inverted) {\n    Circuit out;\n    decompose_spp_or_spp_dag_operation(\n        Circuit(\"SPP !Z0\").operations[0], 10, false, [&](const CircuitInstruction &inst) {\n            out.safe_append(inst);\n        });\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        S_DAG 0\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_inverted2) {\n    Circuit out;\n    decompose_spp_or_spp_dag_operation(Circuit(\"SPP Z0\").operations[0], 10, true, [&](const CircuitInstruction &inst) {\n        out.safe_append(inst);\n    });\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        S_DAG 0\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_inverted3) {\n    Circuit out;\n    decompose_spp_or_spp_dag_operation(\n        Circuit(\"SPP_DAG Z0\").operations[0], 10, false, [&](const CircuitInstruction &inst) {\n            out.safe_append(inst);\n        });\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        S_DAG 0\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_double_inverted) {\n    Circuit out;\n    decompose_spp_or_spp_dag_operation(Circuit(\"SPP !Z0\").operations[0], 10, true, [&](const CircuitInstruction &inst) {\n        out.safe_append(inst);\n    });\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        S 0\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_triple_inverted) {\n    Circuit out;\n    decompose_spp_or_spp_dag_operation(\n        Circuit(\"SPP_DAG !Z0\").operations[0], 10, true, [&](const CircuitInstruction &inst) {\n            out.safe_append(inst);\n        });\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        S_DAG 0\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_complex) {\n    Circuit out;\n    decompose_spp_or_spp_dag_operation(\n        Circuit(\"SPP X0*Y1*Z2\").operations[0], 10, false, [&](const CircuitInstruction &inst) {\n            out.safe_append(inst);\n        });\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        H 0\n        H_YZ 1\n        CX 1 0 2 0\n        S 0\n        CX 1 0 2 0\n        H_YZ 1\n        H 0\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_multiple) {\n    Circuit out;\n    decompose_spp_or_spp_dag_operation(\n        Circuit(\"SPP X0 Y0*!Z2\").operations[0], 10, false, [&](const CircuitInstruction &inst) {\n            out.safe_append(inst);\n        });\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        H 0\n        S 0\n        H 0\n        H_YZ 0\n        CX 2 0\n        S_DAG 0\n        CX 2 0\n        H_YZ 0\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_empty) {\n    Circuit out;\n    decompose_spp_or_spp_dag_operation(Circuit(\"SPP\").operations[0], 10, false, [&](const CircuitInstruction &inst) {\n        out.safe_append(inst);\n    });\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, decompose_spp_or_spp_dag_operation_bad) {\n    ASSERT_THROW(\n        {\n            decompose_spp_or_spp_dag_operation(\n                Circuit(\"SPP X0*Z0\").operations[0], 10, false, [](const CircuitInstruction &inst) {\n                });\n        },\n        std::invalid_argument);\n\n    ASSERT_THROW(\n        {\n            decompose_spp_or_spp_dag_operation(\n                Circuit(\"MPP X0*Z0\").operations[0], 10, false, [](const CircuitInstruction &inst) {\n                });\n        },\n        std::invalid_argument);\n}\n\nTEST(gate_decomposition, for_each_disjoint_target_segment_in_instruction_reversed) {\n    simd_bits<64> buf(100);\n\n    Circuit out;\n    auto append_into_circuit = [&](const CircuitInstruction &segment) {\n        out.safe_append(segment);\n        out.append_from_text(\"TICK\");\n    };\n    for_each_disjoint_target_segment_in_instruction_reversed(\n        Circuit(\"M(0.25) 0 1 2 3 2 5 6 7 1 5 6 6\").operations[0], buf, append_into_circuit);\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        M(0.25) 6\n        TICK\n\n        M(0.25) 7 1 5 6\n        TICK\n\n        M(0.25) 3 2 5 6\n        TICK\n\n        M(0.25) 0 1 2\n        TICK\n\n    )CIRCUIT\"));\n}\n\nTEST(gate_decomposition, for_each_combined_targets_group) {\n    Circuit out;\n    auto append_into_circuit = [&](const CircuitInstruction &segment) {\n        out.safe_append(segment);\n        out.append_from_text(\"TICK\");\n    };\n    for_each_combined_targets_group(Circuit(\"MPP(0.25) X0 Z1 Y2*Z3 Y4*Z5*Z6 Z8\").operations[0], append_into_circuit);\n    for_each_combined_targets_group(Circuit(\"MPP(0.25) X0 Y1 Z2\").operations[0], append_into_circuit);\n    for_each_combined_targets_group(Circuit(\"MPP(0.25) X0*Y1 Z2*Z3\").operations[0], append_into_circuit);\n    ASSERT_EQ(out, Circuit(R\"CIRCUIT(\n        MPP(0.25) X0\n        TICK\n        MPP(0.25) Z1\n        TICK\n        MPP(0.25) Y2*Z3\n        TICK\n        MPP(0.25) Y4*Z5*Z6\n        TICK\n        MPP(0.25) Z8\n        TICK\n        MPP(0.25) X0\n        TICK\n        MPP(0.25) Y1\n        TICK\n        MPP(0.25) Z2\n        TICK\n        MPP(0.25) X0*Y1\n        TICK\n        MPP(0.25) Z2*Z3\n        TICK\n    )CIRCUIT\"));\n}\n"
  },
  {
    "path": "src/stim/circuit/gate_target.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/gate_target.h\"\n\nusing namespace stim;\n\nGateTarget GateTarget::pauli_xz(uint32_t qubit, bool x, bool z, bool inverted) {\n    if (qubit != (qubit & TARGET_VALUE_MASK)) {\n        throw std::invalid_argument(\"qubit target larger than \" + std::to_string(TARGET_VALUE_MASK));\n    }\n    return {qubit | (TARGET_INVERTED_BIT * inverted) | (TARGET_PAULI_X_BIT * x) | (TARGET_PAULI_Z_BIT * z)};\n}\n\nGateTarget GateTarget::from_target_str(std::string_view text) {\n    int c = text[0];\n    size_t k = 1;\n    auto t = read_single_gate_target(c, [&]() {\n        return k < text.size() ? text[k++] : EOF;\n    });\n    if (c != EOF) {\n        throw std::invalid_argument(\"Unparsed text at end of \" + std::string(text));\n    }\n    return t;\n}\n\nGateTarget GateTarget::x(uint32_t qubit, bool inverted) {\n    if (qubit != (qubit & TARGET_VALUE_MASK)) {\n        throw std::invalid_argument(\"qubit target larger than \" + std::to_string(TARGET_VALUE_MASK));\n    }\n    return {qubit | (TARGET_INVERTED_BIT * inverted) | TARGET_PAULI_X_BIT};\n}\nGateTarget GateTarget::y(uint32_t qubit, bool inverted) {\n    if (qubit != (qubit & TARGET_VALUE_MASK)) {\n        throw std::invalid_argument(\"qubit target larger than \" + std::to_string(TARGET_VALUE_MASK));\n    }\n    return {qubit | (TARGET_INVERTED_BIT * inverted) | TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT};\n}\nGateTarget GateTarget::z(uint32_t qubit, bool inverted) {\n    if (qubit != (qubit & TARGET_VALUE_MASK)) {\n        throw std::invalid_argument(\"qubit target larger than \" + std::to_string(TARGET_VALUE_MASK));\n    }\n    return {qubit | (TARGET_INVERTED_BIT * inverted) | TARGET_PAULI_Z_BIT};\n}\nGateTarget GateTarget::qubit(uint32_t qubit, bool inverted) {\n    if (qubit != (qubit & TARGET_VALUE_MASK)) {\n        throw std::invalid_argument(\"qubit target larger than \" + std::to_string(TARGET_VALUE_MASK));\n    }\n    return {qubit | (TARGET_INVERTED_BIT * inverted)};\n}\nGateTarget GateTarget::rec(int32_t lookback) {\n    if (lookback >= 0 || lookback <= -(1 << 24)) {\n        throw std::out_of_range(\"Need -16777215 <= lookback <= -1\");\n    }\n    return {((uint32_t)-lookback) | TARGET_RECORD_BIT};\n}\nGateTarget GateTarget::sweep_bit(uint32_t index) {\n    return {index | TARGET_SWEEP_BIT};\n}\nGateTarget GateTarget::combiner() {\n    return {TARGET_COMBINER};\n}\n\nuint32_t GateTarget::qubit_value() const {\n    return data & TARGET_VALUE_MASK;\n}\n\nint32_t GateTarget::value() const {\n    int32_t result = (int32_t)(data & TARGET_VALUE_MASK);\n    if (is_measurement_record_target()) {\n        return -result;\n    }\n    return result;\n}\nint32_t GateTarget::rec_offset() const {\n    assert(is_measurement_record_target());\n    return -(int32_t)(data & TARGET_VALUE_MASK);\n}\nbool GateTarget::is_x_target() const {\n    return (data & TARGET_PAULI_X_BIT) && !(data & TARGET_PAULI_Z_BIT);\n}\nbool GateTarget::is_y_target() const {\n    return (data & TARGET_PAULI_X_BIT) && (data & TARGET_PAULI_Z_BIT);\n}\nbool GateTarget::is_z_target() const {\n    return !(data & TARGET_PAULI_X_BIT) && (data & TARGET_PAULI_Z_BIT);\n}\nbool GateTarget::is_inverted_result_target() const {\n    return data & TARGET_INVERTED_BIT;\n}\nbool GateTarget::is_measurement_record_target() const {\n    return data & TARGET_RECORD_BIT;\n}\nbool GateTarget::is_pauli_target() const {\n    return data & (TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT);\n}\nbool GateTarget::has_qubit_value() const {\n    return !(data & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT | TARGET_COMBINER));\n}\nbool GateTarget::is_qubit_target() const {\n    return !(data & (TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT | TARGET_RECORD_BIT | TARGET_SWEEP_BIT | TARGET_COMBINER));\n}\nbool GateTarget::is_combiner() const {\n    return data == TARGET_COMBINER;\n}\nbool GateTarget::is_sweep_bit_target() const {\n    return data & TARGET_SWEEP_BIT;\n}\nbool GateTarget::is_classical_bit_target() const {\n    return data & (TARGET_SWEEP_BIT | TARGET_RECORD_BIT);\n}\nbool GateTarget::operator==(const GateTarget &other) const {\n    return data == other.data;\n}\nbool GateTarget::operator<(const GateTarget &other) const {\n    return data < other.data;\n}\nbool GateTarget::operator!=(const GateTarget &other) const {\n    return data != other.data;\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const GateTarget &t) {\n    if (t.is_combiner()) {\n        return out << \"stim.GateTarget.combiner()\";\n    }\n    if (t.is_qubit_target()) {\n        if (t.is_inverted_result_target()) {\n            return out << \"stim.target_inv(\" << t.value() << \")\";\n        }\n        return out << t.value();\n    }\n    if (t.is_measurement_record_target()) {\n        return out << \"stim.target_rec(\" << t.value() << \")\";\n    }\n    if (t.is_sweep_bit_target()) {\n        return out << \"stim.target_sweep_bit(\" << t.value() << \")\";\n    }\n    if (t.is_x_target()) {\n        out << \"stim.target_x(\" << t.value();\n        if (t.is_inverted_result_target()) {\n            out << \", invert=True\";\n        }\n        return out << \")\";\n    }\n    if (t.is_y_target()) {\n        out << \"stim.target_y(\" << t.value();\n        if (t.is_inverted_result_target()) {\n            out << \", invert=True\";\n        }\n        return out << \")\";\n    }\n    if (t.is_z_target()) {\n        out << \"stim.target_z(\" << t.value();\n        if (t.is_inverted_result_target()) {\n            out << \", invert=True\";\n        }\n        return out << \")\";\n    }\n    throw std::invalid_argument(\"Malformed target.\");\n}\n\nstd::string GateTarget::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\nstd::string GateTarget::repr() const {\n    std::stringstream ss;\n    bool need_wrap = is_qubit_target() && !is_inverted_result_target();\n    if (need_wrap) {\n        ss << \"stim.GateTarget(\";\n    }\n    ss << *this;\n    if (need_wrap) {\n        ss << \")\";\n    }\n    return ss.str();\n}\n\nvoid GateTarget::write_succinct(std::ostream &out) const {\n    if (data == TARGET_COMBINER) {\n        out << \"*\";\n        return;\n    }\n    if (data & TARGET_INVERTED_BIT) {\n        out << '!';\n    }\n    if (data & (TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT)) {\n        bool x = data & TARGET_PAULI_X_BIT;\n        bool z = data & TARGET_PAULI_Z_BIT;\n        out << \"IXZY\"[x + z * 2];\n    }\n    if (data & TARGET_RECORD_BIT) {\n        out << \"rec[-\" << (data & TARGET_VALUE_MASK) << \"]\";\n    } else if (data & TARGET_SWEEP_BIT) {\n        out << \"sweep[\" << (data & TARGET_VALUE_MASK) << \"]\";\n    } else {\n        out << (data & TARGET_VALUE_MASK);\n    }\n}\n\nvoid stim::write_targets(std::ostream &out, SpanRef<const GateTarget> targets) {\n    bool skip_space = false;\n    for (auto t : targets) {\n        if (t.is_combiner()) {\n            skip_space = true;\n        } else if (!skip_space) {\n            out << ' ';\n        } else {\n            skip_space = false;\n        }\n        t.write_succinct(out);\n    }\n}\n\nstd::string stim::targets_str(SpanRef<const GateTarget> targets) {\n    std::stringstream out;\n    stim::write_targets(out, targets);\n    return out.str();\n}\n\nstd::string GateTarget::target_str() const {\n    std::stringstream out;\n    write_succinct(out);\n    return out.str();\n}\n\nGateTarget GateTarget::operator!() const {\n    if (data & (TARGET_COMBINER | TARGET_RECORD_BIT | TARGET_SWEEP_BIT)) {\n        throw std::invalid_argument(\"Target '\" + str() + \"' doesn't have a defined inverse.\");\n    }\n    return GateTarget{data ^ TARGET_INVERTED_BIT};\n}\n\nchar GateTarget::pauli_type() const {\n    assert(TARGET_PAULI_X_BIT == (1 << 30));\n    assert(TARGET_PAULI_Z_BIT == (1 << 29));\n    return \"IZXY\"[(data >> 29) & 3];\n}\n"
  },
  {
    "path": "src/stim/circuit/gate_target.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CIRCUIT_GATE_TARGET_H\n#define _STIM_CIRCUIT_GATE_TARGET_H\n\n#include <iostream>\n\n#include \"stim/gates/gates.h\"\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\nconstexpr uint32_t TARGET_VALUE_MASK = (uint32_t{1} << 24) - uint32_t{1};\nconstexpr uint32_t TARGET_INVERTED_BIT = uint32_t{1} << 31;\nconstexpr uint32_t TARGET_PAULI_X_BIT = uint32_t{1} << 30;\nconstexpr uint32_t TARGET_PAULI_Z_BIT = uint32_t{1} << 29;\nconstexpr uint32_t TARGET_RECORD_BIT = uint32_t{1} << 28;\nconstexpr uint32_t TARGET_COMBINER = uint32_t{1} << 27;\nconstexpr uint32_t TARGET_SWEEP_BIT = uint32_t{1} << 26;\n\nstruct GateTarget {\n    uint32_t data;\n    int32_t value() const;\n\n    static GateTarget x(uint32_t qubit, bool inverted = false);\n    static GateTarget y(uint32_t qubit, bool inverted = false);\n    static GateTarget z(uint32_t qubit, bool inverted = false);\n    static GateTarget pauli_xz(uint32_t qubit, bool x, bool z, bool inverted = false);\n    static GateTarget qubit(uint32_t qubit, bool inverted = false);\n    static GateTarget rec(int32_t lookback);\n    static GateTarget sweep_bit(uint32_t index);\n    static GateTarget combiner();\n    static GateTarget from_target_str(std::string_view text);\n\n    GateTarget operator!() const;\n    int32_t rec_offset() const;\n    bool has_qubit_value() const;\n    bool is_combiner() const;\n    bool is_x_target() const;\n    bool is_y_target() const;\n    bool is_z_target() const;\n    bool is_inverted_result_target() const;\n    bool is_measurement_record_target() const;\n    bool is_qubit_target() const;\n    bool is_sweep_bit_target() const;\n    bool is_classical_bit_target() const;\n    bool is_pauli_target() const;\n    uint32_t qubit_value() const;\n    bool operator==(const GateTarget &other) const;\n    bool operator!=(const GateTarget &other) const;\n    bool operator<(const GateTarget &other) const;\n    std::string str() const;\n    std::string repr() const;\n    char pauli_type() const;\n    std::string target_str() const;\n\n    void write_succinct(std::ostream &out) const;\n};\n\ntemplate <typename SOURCE>\nuint32_t read_uint24_t(int &c, SOURCE read_char) {\n    if (!(c >= '0' && c <= '9')) {\n        throw std::invalid_argument(\"Expected a digit but got '\" + std::string(1, c) + \"'\");\n    }\n    uint32_t result = 0;\n    do {\n        result *= 10;\n        result += c - '0';\n        if (result >= uint32_t{1} << 24) {\n            throw std::invalid_argument(\"Number too large.\");\n        }\n        c = read_char();\n    } while (c >= '0' && c <= '9');\n    return result;\n}\n\ntemplate <typename SOURCE>\ninline GateTarget read_raw_qubit_target(int &c, SOURCE read_char) {\n    return GateTarget::qubit(read_uint24_t(c, read_char));\n}\n\ntemplate <typename SOURCE>\ninline GateTarget read_measurement_record_target(int &c, SOURCE read_char) {\n    if (c != 'r' || read_char() != 'e' || read_char() != 'c' || read_char() != '[' || read_char() != '-') {\n        throw std::invalid_argument(\"Target started with 'r' but wasn't a record argument like 'rec[-1]'.\");\n    }\n    c = read_char();\n    uint32_t lookback = read_uint24_t(c, read_char);\n    if (c != ']') {\n        throw std::invalid_argument(\"Target started with 'r' but wasn't a record argument like 'rec[-1]'.\");\n    }\n    c = read_char();\n    return GateTarget{lookback | TARGET_RECORD_BIT};\n}\n\ntemplate <typename SOURCE>\ninline GateTarget read_sweep_bit_target(int &c, SOURCE read_char) {\n    if (c != 's' || read_char() != 'w' || read_char() != 'e' || read_char() != 'e' || read_char() != 'p' ||\n        read_char() != '[') {\n        throw std::invalid_argument(\"Target started with 's' but wasn't a sweep bit argument like 'sweep[5]'.\");\n    }\n    c = read_char();\n    uint32_t lookback = read_uint24_t(c, read_char);\n    if (c != ']') {\n        throw std::invalid_argument(\"Target started with 's' but wasn't a sweep bit argument like 'sweep[5]'.\");\n    }\n    c = read_char();\n    return GateTarget{lookback | TARGET_SWEEP_BIT};\n}\n\ntemplate <typename SOURCE>\ninline GateTarget read_single_gate_target(int &c, SOURCE read_char) {\n    switch (c) {\n        case '0':\n        case '1':\n        case '2':\n        case '3':\n        case '4':\n        case '5':\n        case '6':\n        case '7':\n        case '8':\n        case '9':\n            return read_raw_qubit_target(c, read_char);\n        case 'r':\n            return read_measurement_record_target(c, read_char);\n        case '!':\n            return read_inverted_target(c, read_char);\n        case 'X':\n        case 'Y':\n        case 'Z':\n        case 'x':\n        case 'y':\n        case 'z':\n            return read_pauli_target(c, read_char);\n        case '*':\n            c = read_char();\n            return GateTarget::combiner();\n        case 's':\n            return read_sweep_bit_target(c, read_char);\n        default:\n            throw std::invalid_argument(\"Unrecognized target prefix '\" + std::string(1, c) + \"'.\");\n    }\n}\n\ntemplate <typename SOURCE>\ninline GateTarget read_pauli_target(int &c, SOURCE read_char) {\n    uint32_t m = 0;\n    if (c == 'x' || c == 'X') {\n        m = TARGET_PAULI_X_BIT;\n    } else if (c == 'y' || c == 'Y') {\n        m = TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT;\n    } else if (c == 'z' || c == 'Z') {\n        m = TARGET_PAULI_Z_BIT;\n    } else {\n        assert(false);\n    }\n    c = read_char();\n    if (c == ' ') {\n        throw std::invalid_argument(\n            \"Pauli target '\" + std::string(1, c) + \"' followed by a space instead of a qubit index.\");\n    }\n    uint32_t q = read_uint24_t(c, read_char);\n\n    return {q | m};\n}\n\ntemplate <typename SOURCE>\ninline GateTarget read_inverted_target(int &c, SOURCE read_char) {\n    assert(c == '!');\n    c = read_char();\n    GateTarget t;\n    if (c == 'X' || c == 'x' || c == 'Y' || c == 'y' || c == 'Z' || c == 'z') {\n        t = read_pauli_target(c, read_char);\n    } else {\n        t = read_raw_qubit_target(c, read_char);\n    }\n    t.data ^= TARGET_INVERTED_BIT;\n    return t;\n}\n\nvoid write_targets(std::ostream &out, SpanRef<const GateTarget> targets);\nstd::string targets_str(SpanRef<const GateTarget> targets);\n\nstd::ostream &operator<<(std::ostream &out, const GateTarget &t);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/circuit/gate_target.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/gate_target.pybind.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/py/base.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nGateTarget handle_to_gate_target(const pybind11::handle &obj) {\n    try {\n        std::string_view text = pybind11::cast<std::string_view>(obj);\n        return GateTarget::from_target_str(text);\n    } catch (const pybind11::cast_error &ex) {\n    }\n    try {\n        return pybind11::cast<GateTarget>(obj);\n    } catch (const pybind11::cast_error &ex) {\n    }\n    try {\n        return GateTarget{pybind11::cast<uint32_t>(obj)};\n    } catch (const pybind11::cast_error &ex) {\n    }\n    throw std::invalid_argument(\n        \"target argument wasn't a qubit index, a result from a `stim.target_*` method, or a `stim.GateTarget`.\");\n}\n\nGateTarget obj_to_gate_target(const pybind11::object &obj) {\n    return handle_to_gate_target(obj);\n}\n\npybind11::class_<stim::GateTarget> stim_pybind::pybind_circuit_gate_target(pybind11::module &m) {\n    return pybind11::class_<GateTarget>(\n        m,\n        \"GateTarget\",\n        clean_doc_string(R\"DOC(\n            Represents a gate target, like `0` or `rec[-1]`, from a circuit.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit('''\n                ...     M 0 !1\n                ... ''')\n                >>> circuit[0].targets_copy()[0]\n                stim.GateTarget(0)\n                >>> circuit[0].targets_copy()[1]\n                stim.target_inv(1)\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_circuit_gate_target_methods(pybind11::module &m, pybind11::class_<stim::GateTarget> &c) {\n    c.def(\n        pybind11::init(&obj_to_gate_target),\n        pybind11::arg(\"value\"),\n        clean_doc_string(R\"DOC(\n            Initializes a `stim.GateTarget`.\n\n            Args:\n                value: A value to convert into a gate target, like an integer\n                    to interpret as a qubit target or a string to parse.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(stim.GateTarget(5))\n                stim.GateTarget(5)\n                >>> stim.GateTarget(\"X7\")\n                stim.target_x(7)\n                >>> stim.GateTarget(\"rec[-3]\")\n                stim.target_rec(-3)\n                >>> stim.GateTarget(\"!Z7\")\n                stim.target_z(7, invert=True)\n                >>> stim.GateTarget(\"*\")\n                stim.GateTarget.combiner()\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"value\",\n        &GateTarget::value,\n        clean_doc_string(R\"DOC(\n            The numeric part of the target.\n\n            This is non-negative integer for qubit targets, and a negative integer for\n            measurement record targets.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).value\n                6\n                >>> stim.target_inv(7).value\n                7\n                >>> stim.target_x(8).value\n                8\n                >>> stim.target_y(2).value\n                2\n                >>> stim.target_z(3).value\n                3\n                >>> stim.target_sweep_bit(9).value\n                9\n                >>> stim.target_rec(-5).value\n                -5\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"qubit_value\",\n        [](const GateTarget &self) -> pybind11::object {\n            if (self.data & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT | TARGET_COMBINER)) {\n                return pybind11::none();\n            }\n            return pybind11::cast(self.qubit_value());\n        },\n        clean_doc_string(R\"DOC(\n            @signature def qubit_value(self) -> Optional[int]:\n            Returns the integer value of the targeted qubit, or else None.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).qubit_value\n                6\n                >>> stim.target_inv(7).qubit_value\n                7\n                >>> stim.target_x(8).qubit_value\n                8\n                >>> stim.target_y(2).qubit_value\n                2\n                >>> stim.target_z(3).qubit_value\n                3\n                >>> print(stim.target_sweep_bit(9).qubit_value)\n                None\n                >>> print(stim.target_rec(-5).qubit_value)\n                None\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_qubit_target\",\n        &GateTarget::is_qubit_target,\n        clean_doc_string(R\"DOC(\n            Returns whether or not this is a qubit target like `5` or `!6`.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).is_qubit_target\n                True\n                >>> stim.target_inv(7).is_qubit_target\n                True\n                >>> stim.target_x(8).is_qubit_target\n                False\n                >>> stim.target_y(2).is_qubit_target\n                False\n                >>> stim.target_z(3).is_qubit_target\n                False\n                >>> stim.target_sweep_bit(9).is_qubit_target\n                False\n                >>> stim.target_rec(-5).is_qubit_target\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_x_target\",\n        &GateTarget::is_x_target,\n        clean_doc_string(R\"DOC(\n            Returns whether or not this is an X pauli target like `X2` or `!X7`.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).is_x_target\n                False\n                >>> stim.target_inv(7).is_x_target\n                False\n                >>> stim.target_x(8).is_x_target\n                True\n                >>> stim.target_y(2).is_x_target\n                False\n                >>> stim.target_z(3).is_x_target\n                False\n                >>> stim.target_sweep_bit(9).is_x_target\n                False\n                >>> stim.target_rec(-5).is_x_target\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_y_target\",\n        &GateTarget::is_y_target,\n        clean_doc_string(R\"DOC(\n            Returns whether or not this is a Y pauli target like `Y2` or `!Y7`.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).is_y_target\n                False\n                >>> stim.target_inv(7).is_y_target\n                False\n                >>> stim.target_x(8).is_y_target\n                False\n                >>> stim.target_y(2).is_y_target\n                True\n                >>> stim.target_z(3).is_y_target\n                False\n                >>> stim.target_sweep_bit(9).is_y_target\n                False\n                >>> stim.target_rec(-5).is_y_target\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_z_target\",\n        &GateTarget::is_z_target,\n        clean_doc_string(R\"DOC(\n            Returns whether or not this is a Z pauli target like `Z2` or `!Z7`.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).is_z_target\n                False\n                >>> stim.target_inv(7).is_z_target\n                False\n                >>> stim.target_x(8).is_z_target\n                False\n                >>> stim.target_y(2).is_z_target\n                False\n                >>> stim.target_z(3).is_z_target\n                True\n                >>> stim.target_sweep_bit(9).is_z_target\n                False\n                >>> stim.target_rec(-5).is_z_target\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"pauli_type\",\n        &GateTarget::pauli_type,\n        clean_doc_string(R\"DOC(\n            Returns whether this is an 'X', 'Y', or 'Z' target.\n\n            For non-pauli targets, this property evaluates to 'I'.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).pauli_type\n                'I'\n                >>> stim.target_inv(7).pauli_type\n                'I'\n                >>> stim.target_x(8).pauli_type\n                'X'\n                >>> stim.target_y(2).pauli_type\n                'Y'\n                >>> stim.target_z(3).pauli_type\n                'Z'\n                >>> stim.target_sweep_bit(9).pauli_type\n                'I'\n                >>> stim.target_rec(-5).pauli_type\n                'I'\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_inverted_result_target\",\n        &GateTarget::is_inverted_result_target,\n        clean_doc_string(R\"DOC(\n            Returns whether or not this is an inverted target like `!5` or `!X4`.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).is_inverted_result_target\n                False\n                >>> stim.target_inv(7).is_inverted_result_target\n                True\n                >>> stim.target_x(8).is_inverted_result_target\n                False\n                >>> stim.target_x(8, invert=True).is_inverted_result_target\n                True\n                >>> stim.target_y(2).is_inverted_result_target\n                False\n                >>> stim.target_z(3).is_inverted_result_target\n                False\n                >>> stim.target_sweep_bit(9).is_inverted_result_target\n                False\n                >>> stim.target_rec(-5).is_inverted_result_target\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_measurement_record_target\",\n        &GateTarget::is_measurement_record_target,\n        clean_doc_string(R\"DOC(\n            Returns whether or not this is a measurement record target like `rec[-5]`.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).is_measurement_record_target\n                False\n                >>> stim.target_inv(7).is_measurement_record_target\n                False\n                >>> stim.target_x(8).is_measurement_record_target\n                False\n                >>> stim.target_y(2).is_measurement_record_target\n                False\n                >>> stim.target_z(3).is_measurement_record_target\n                False\n                >>> stim.target_sweep_bit(9).is_measurement_record_target\n                False\n                >>> stim.target_rec(-5).is_measurement_record_target\n                True\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_combiner\",\n        &GateTarget::is_combiner,\n        clean_doc_string(R\"DOC(\n            Returns whether or not this is a combiner target like `*`.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).is_combiner\n                False\n                >>> stim.target_inv(7).is_combiner\n                False\n                >>> stim.target_x(8).is_combiner\n                False\n                >>> stim.target_y(2).is_combiner\n                False\n                >>> stim.target_z(3).is_combiner\n                False\n                >>> stim.target_sweep_bit(9).is_combiner\n                False\n                >>> stim.target_rec(-5).is_combiner\n                False\n                >>> stim.target_combiner().is_combiner\n                True\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_sweep_bit_target\",\n        &GateTarget::is_sweep_bit_target,\n        clean_doc_string(R\"DOC(\n            Returns whether or not this is a sweep bit target like `sweep[4]`.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateTarget(6).is_sweep_bit_target\n                False\n                >>> stim.target_inv(7).is_sweep_bit_target\n                False\n                >>> stim.target_x(8).is_sweep_bit_target\n                False\n                >>> stim.target_y(2).is_sweep_bit_target\n                False\n                >>> stim.target_z(3).is_sweep_bit_target\n                False\n                >>> stim.target_sweep_bit(9).is_sweep_bit_target\n                True\n                >>> stim.target_rec(-5).is_sweep_bit_target\n                False\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two `stim.GateTarget`s are identical.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two `stim.GateTarget`s are different.\");\n    c.def(\"__hash__\", [](const GateTarget &self) {\n        return pybind11::hash(pybind11::make_tuple(\"GateTarget\", self.data));\n    });\n    c.def(\n        \"__repr__\",\n        &GateTarget::repr,\n        \"Returns text that is a valid python expression evaluating to an equivalent `stim.GateTarget`.\");\n}\n"
  },
  {
    "path": "src/stim/circuit/gate_target.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_CIRCUIT_CIRCUIT_GATE_TARGET_PYBIND_H\n#define _STIM_CIRCUIT_CIRCUIT_GATE_TARGET_PYBIND_H\n\n#include <cstdint>\n#include <pybind11/pybind11.h>\n#include <string>\n\n#include \"stim/circuit/gate_target.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::GateTarget> pybind_circuit_gate_target(pybind11::module &m);\nvoid pybind_circuit_gate_target_methods(pybind11::module &m, pybind11::class_<stim::GateTarget> &c);\n\n}  // namespace stim_pybind\n\nstim::GateTarget obj_to_gate_target(const pybind11::object &obj);\nstim::GateTarget handle_to_gate_target(const pybind11::handle &obj);\n\n#endif\n"
  },
  {
    "path": "src/stim/circuit/gate_target.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/circuit/gate_target.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(gate_target, xyz) {\n    ASSERT_THROW({ GateTarget::x(UINT32_MAX); }, std::invalid_argument);\n    ASSERT_THROW({ GateTarget::y(UINT32_MAX, true); }, std::invalid_argument);\n    ASSERT_THROW({ GateTarget::z(UINT32_MAX, false); }, std::invalid_argument);\n\n    auto t = GateTarget::x(5, false);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), false);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), false);\n    ASSERT_EQ(t.is_x_target(), true);\n    ASSERT_EQ(t.is_y_target(), false);\n    ASSERT_EQ(t.is_z_target(), false);\n    ASSERT_EQ(t.str(), \"stim.target_x(5)\");\n    ASSERT_EQ(t.value(), 5);\n    ASSERT_TRUE(t.has_qubit_value());\n    ASSERT_FALSE(t.is_sweep_bit_target());\n\n    t = GateTarget::x(7, true);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), true);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), false);\n    ASSERT_EQ(t.is_x_target(), true);\n    ASSERT_EQ(t.is_y_target(), false);\n    ASSERT_EQ(t.is_z_target(), false);\n    ASSERT_EQ(t.str(), \"stim.target_x(7, invert=True)\");\n    ASSERT_EQ(t.value(), 7);\n    ASSERT_TRUE(t.has_qubit_value());\n    ASSERT_FALSE(t.is_sweep_bit_target());\n\n    t = GateTarget::y(11, false);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), false);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), false);\n    ASSERT_EQ(t.is_x_target(), false);\n    ASSERT_EQ(t.is_y_target(), true);\n    ASSERT_EQ(t.is_z_target(), false);\n    ASSERT_EQ(t.str(), \"stim.target_y(11)\");\n    ASSERT_EQ(t.value(), 11);\n    ASSERT_TRUE(t.has_qubit_value());\n    ASSERT_FALSE(t.is_sweep_bit_target());\n\n    t = GateTarget::y(13, true);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), true);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), false);\n    ASSERT_EQ(t.is_x_target(), false);\n    ASSERT_EQ(t.is_y_target(), true);\n    ASSERT_EQ(t.is_z_target(), false);\n    ASSERT_EQ(t.str(), \"stim.target_y(13, invert=True)\");\n    ASSERT_EQ(t.value(), 13);\n    ASSERT_FALSE(t.is_sweep_bit_target());\n\n    t = GateTarget::z(17, false);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), false);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), false);\n    ASSERT_EQ(t.is_x_target(), false);\n    ASSERT_EQ(t.is_y_target(), false);\n    ASSERT_EQ(t.is_z_target(), true);\n    ASSERT_EQ(t.str(), \"stim.target_z(17)\");\n    ASSERT_EQ(t.value(), 17);\n    ASSERT_TRUE(t.has_qubit_value());\n    ASSERT_FALSE(t.is_sweep_bit_target());\n\n    t = GateTarget::z(19, true);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), true);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), false);\n    ASSERT_EQ(t.is_x_target(), false);\n    ASSERT_EQ(t.is_y_target(), false);\n    ASSERT_EQ(t.is_z_target(), true);\n    ASSERT_EQ(t.str(), \"stim.target_z(19, invert=True)\");\n    ASSERT_EQ(t.value(), 19);\n    ASSERT_EQ(t.qubit_value(), 19);\n    ASSERT_TRUE(t.has_qubit_value());\n    ASSERT_FALSE(t.is_sweep_bit_target());\n}\n\nTEST(gate_target, qubit) {\n    ASSERT_THROW({ GateTarget::qubit(UINT32_MAX); }, std::invalid_argument);\n\n    auto t = GateTarget::qubit(5, false);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), false);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), true);\n    ASSERT_EQ(t.is_x_target(), false);\n    ASSERT_EQ(t.is_y_target(), false);\n    ASSERT_EQ(t.is_z_target(), false);\n    ASSERT_EQ(t.str(), \"5\");\n    ASSERT_EQ(t.value(), 5);\n    ASSERT_EQ(t.qubit_value(), 5);\n    ASSERT_TRUE(t.has_qubit_value());\n    ASSERT_FALSE(t.is_sweep_bit_target());\n\n    t = GateTarget::qubit(7, true);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), true);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), true);\n    ASSERT_EQ(t.is_x_target(), false);\n    ASSERT_EQ(t.is_y_target(), false);\n    ASSERT_EQ(t.is_z_target(), false);\n    ASSERT_EQ(t.str(), \"stim.target_inv(7)\");\n    ASSERT_EQ(t.value(), 7);\n    ASSERT_TRUE(t.has_qubit_value());\n    ASSERT_FALSE(t.is_sweep_bit_target());\n}\n\nTEST(gate_target, record) {\n    ASSERT_THROW({ GateTarget::rec(1); }, std::out_of_range);\n    ASSERT_THROW({ GateTarget::rec(0); }, std::out_of_range);\n    ASSERT_THROW({ GateTarget::rec(-(int32_t{1} << 30)); }, std::out_of_range);\n\n    auto t = GateTarget::rec(-5);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), false);\n    ASSERT_EQ(t.is_measurement_record_target(), true);\n    ASSERT_EQ(t.is_qubit_target(), false);\n    ASSERT_EQ(t.is_x_target(), false);\n    ASSERT_EQ(t.is_y_target(), false);\n    ASSERT_EQ(t.is_z_target(), false);\n    ASSERT_EQ(t.str(), \"stim.target_rec(-5)\");\n    ASSERT_EQ(t.value(), -5);\n    ASSERT_EQ(t.qubit_value(), 5);\n    ASSERT_FALSE(t.has_qubit_value());\n    ASSERT_FALSE(t.is_sweep_bit_target());\n}\n\nTEST(gate_target, sweep) {\n    auto t = GateTarget::sweep_bit(5);\n    ASSERT_EQ(t.is_combiner(), false);\n    ASSERT_EQ(t.is_inverted_result_target(), false);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), false);\n    ASSERT_EQ(t.is_x_target(), false);\n    ASSERT_EQ(t.is_y_target(), false);\n    ASSERT_EQ(t.is_z_target(), false);\n    ASSERT_EQ(t.str(), \"stim.target_sweep_bit(5)\");\n    ASSERT_EQ(t.value(), 5);\n    ASSERT_FALSE(t.has_qubit_value());\n    ASSERT_TRUE(t.is_sweep_bit_target());\n}\n\nTEST(gate_target, combiner) {\n    auto t = GateTarget::combiner();\n    ASSERT_EQ(t.is_combiner(), true);\n    ASSERT_EQ(t.is_inverted_result_target(), false);\n    ASSERT_EQ(t.is_measurement_record_target(), false);\n    ASSERT_EQ(t.is_qubit_target(), false);\n    ASSERT_EQ(t.is_x_target(), false);\n    ASSERT_EQ(t.is_y_target(), false);\n    ASSERT_EQ(t.is_z_target(), false);\n    ASSERT_EQ(t.str(), \"stim.GateTarget.combiner()\");\n    ASSERT_EQ(t.qubit_value(), 0);\n    ASSERT_FALSE(t.has_qubit_value());\n    ASSERT_FALSE(t.is_sweep_bit_target());\n}\n\nTEST(gate_target, equality) {\n    ASSERT_TRUE(GateTarget{0} == GateTarget{0});\n    ASSERT_FALSE(GateTarget{0} == GateTarget{1});\n    ASSERT_TRUE(GateTarget{0} != GateTarget{1});\n    ASSERT_FALSE(GateTarget{0} != GateTarget{0});\n    ASSERT_TRUE(GateTarget{0} < GateTarget{1});\n    ASSERT_FALSE(GateTarget{1} < GateTarget{0});\n    ASSERT_FALSE(GateTarget{0} < GateTarget{0});\n}\n\nTEST(gate_target, inverse) {\n    ASSERT_EQ(!GateTarget::qubit(5), GateTarget::qubit(5, true));\n    ASSERT_EQ(GateTarget::qubit(5), !GateTarget::qubit(5, true));\n    ASSERT_EQ(!GateTarget::x(5), GateTarget::x(5, true));\n    ASSERT_EQ(GateTarget::x(5), !GateTarget::x(5, true));\n    ASSERT_EQ(!GateTarget::y(5), GateTarget::y(5, true));\n    ASSERT_EQ(GateTarget::y(5), !GateTarget::y(5, true));\n    ASSERT_EQ(!GateTarget::z(9), GateTarget::z(9, true));\n    ASSERT_EQ(GateTarget::z(7), !GateTarget::z(7, true));\n    ASSERT_EQ(!!GateTarget::z(9), GateTarget::z(9));\n    ASSERT_THROW({ !GateTarget::combiner(); }, std::invalid_argument);\n    ASSERT_THROW({ !GateTarget::rec(-3); }, std::invalid_argument);\n    ASSERT_THROW({ !GateTarget::sweep_bit(6); }, std::invalid_argument);\n}\n\nTEST(gate_target, pauli) {\n    ASSERT_EQ(GateTarget::combiner().pauli_type(), 'I');\n    ASSERT_EQ(GateTarget::sweep_bit(5).pauli_type(), 'I');\n    ASSERT_EQ(GateTarget::rec(-5).pauli_type(), 'I');\n    ASSERT_EQ(GateTarget::qubit(5).pauli_type(), 'I');\n    ASSERT_EQ(GateTarget::qubit(6, true).pauli_type(), 'I');\n\n    ASSERT_EQ(GateTarget::x(7).pauli_type(), 'X');\n    ASSERT_EQ(GateTarget::x(7, true).pauli_type(), 'X');\n    ASSERT_EQ(GateTarget::y(7).pauli_type(), 'Y');\n    ASSERT_EQ(GateTarget::y(7, true).pauli_type(), 'Y');\n    ASSERT_EQ(GateTarget::z(7).pauli_type(), 'Z');\n    ASSERT_EQ(GateTarget::z(7, true).pauli_type(), 'Z');\n}\n\nTEST(gate_target, from_target_str) {\n    ASSERT_EQ(GateTarget::from_target_str(\"5\"), GateTarget::qubit(5));\n    ASSERT_EQ(GateTarget::from_target_str(\"rec[-3]\"), GateTarget::rec(-3));\n}\n\nTEST(gate_target, target_str_round_trip) {\n    std::vector<GateTarget> targets{\n        GateTarget::qubit(2),\n        GateTarget::qubit(3, true),\n        GateTarget::sweep_bit(5),\n        GateTarget::rec(-7),\n        GateTarget::x(11),\n        GateTarget::x(13, true),\n        GateTarget::y(17),\n        GateTarget::y(19, true),\n        GateTarget::z(23),\n        GateTarget::z(29, true),\n        GateTarget::combiner(),\n    };\n    for (const auto &t : targets) {\n        ASSERT_EQ(GateTarget::from_target_str(t.target_str().c_str()), t) << t;\n    }\n}\n\nTEST(gate_target, is_pauli_target) {\n    ASSERT_FALSE(GateTarget::qubit(2).is_pauli_target());\n    ASSERT_FALSE(GateTarget::qubit(3, true).is_pauli_target());\n    ASSERT_FALSE(GateTarget::sweep_bit(5).is_pauli_target());\n    ASSERT_FALSE(GateTarget::rec(-7).is_pauli_target());\n    ASSERT_TRUE(GateTarget::x(11).is_pauli_target());\n    ASSERT_TRUE(GateTarget::x(13, true).is_pauli_target());\n    ASSERT_TRUE(GateTarget::y(17).is_pauli_target());\n    ASSERT_TRUE(GateTarget::y(19, true).is_pauli_target());\n    ASSERT_TRUE(GateTarget::z(23).is_pauli_target());\n    ASSERT_TRUE(GateTarget::z(29, true).is_pauli_target());\n    ASSERT_FALSE(GateTarget::combiner().is_pauli_target());\n}\n\nTEST(gate_target, is_classical_bit_target) {\n    ASSERT_TRUE(GateTarget::sweep_bit(5).is_classical_bit_target());\n    ASSERT_TRUE(GateTarget::rec(-7).is_classical_bit_target());\n    ASSERT_FALSE(GateTarget::qubit(2).is_classical_bit_target());\n    ASSERT_FALSE(GateTarget::qubit(3, true).is_classical_bit_target());\n    ASSERT_FALSE(GateTarget::x(11).is_classical_bit_target());\n    ASSERT_FALSE(GateTarget::x(13, true).is_classical_bit_target());\n    ASSERT_FALSE(GateTarget::y(17).is_classical_bit_target());\n    ASSERT_FALSE(GateTarget::y(19, true).is_classical_bit_target());\n    ASSERT_FALSE(GateTarget::z(23).is_classical_bit_target());\n    ASSERT_FALSE(GateTarget::z(29, true).is_classical_bit_target());\n    ASSERT_FALSE(GateTarget::combiner().is_classical_bit_target());\n}\n"
  },
  {
    "path": "src/stim/circuit/gate_target_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport stim\nimport pytest\n\n\ndef test_init_and_equality():\n    assert stim.GateTarget(5) == stim.GateTarget(5)\n    assert stim.GateTarget(5) == stim.GateTarget(value=5)\n    assert not (stim.GateTarget(4) == stim.GateTarget(5))\n    assert stim.GateTarget(4) != stim.GateTarget(5)\n    assert not (stim.GateTarget(5) != stim.GateTarget(5))\n    assert stim.GateTarget(stim.target_x(5)) != stim.GateTarget(5)\n    assert stim.GateTarget(5) == stim.GateTarget(stim.GateTarget(5))\n\n\ndef test_properties():\n    g = stim.GateTarget(5)\n    assert g.value == 5\n    assert not g.is_x_target\n    assert not g.is_y_target\n    assert not g.is_z_target\n    assert not g.is_inverted_result_target\n    assert not g.is_measurement_record_target\n    assert not g.is_combiner\n    assert g.is_qubit_target\n\n    g = stim.GateTarget(stim.target_rec(-4))\n    assert g.value == -4\n    assert not g.is_x_target\n    assert not g.is_y_target\n    assert not g.is_z_target\n    assert not g.is_inverted_result_target\n    assert g.is_measurement_record_target\n    assert not g.is_combiner\n    assert not g.is_qubit_target\n\n    g = stim.GateTarget(stim.target_x(3))\n    assert g.value == 3\n    assert g.is_x_target\n    assert not g.is_y_target\n    assert not g.is_z_target\n    assert not g.is_inverted_result_target\n    assert not g.is_measurement_record_target\n    assert not g.is_combiner\n    assert not g.is_qubit_target\n\n    g = stim.GateTarget(stim.target_y(3))\n    assert g.value == 3\n    assert not g.is_x_target\n    assert g.is_y_target\n    assert not g.is_z_target\n    assert not g.is_inverted_result_target\n    assert not g.is_measurement_record_target\n    assert not g.is_combiner\n    assert not g.is_qubit_target\n\n    g = stim.GateTarget(stim.target_z(3))\n    assert g.value == 3\n    assert not g.is_x_target\n    assert not g.is_y_target\n    assert g.is_z_target\n    assert not g.is_inverted_result_target\n    assert not g.is_measurement_record_target\n    assert not g.is_combiner\n    assert not g.is_qubit_target\n\n    g = stim.GateTarget(stim.target_z(3, invert=True))\n    assert g.value == 3\n    assert not g.is_x_target\n    assert not g.is_y_target\n    assert g.is_z_target\n    assert g.is_inverted_result_target\n    assert not g.is_measurement_record_target\n    assert not g.is_combiner\n    assert not g.is_qubit_target\n\n    g = stim.GateTarget(stim.target_inv(3))\n    assert g.value == 3\n    assert not g.is_x_target\n    assert not g.is_y_target\n    assert not g.is_z_target\n    assert g.is_inverted_result_target\n    assert not g.is_measurement_record_target\n    assert not g.is_combiner\n    assert g.is_qubit_target\n\n    g = stim.target_combiner()\n    assert not g.is_x_target\n    assert not g.is_y_target\n    assert not g.is_z_target\n    assert not g.is_inverted_result_target\n    assert not g.is_measurement_record_target\n    assert not g.is_qubit_target\n    assert g.is_combiner\n\n\n@pytest.mark.parametrize(\"value\", [\n    stim.GateTarget(5),\n    stim.GateTarget(stim.target_rec(-5)),\n    stim.GateTarget(stim.target_x(5)),\n    stim.GateTarget(stim.target_y(5)),\n    stim.GateTarget(stim.target_z(5)),\n    stim.GateTarget(stim.target_inv(5)),\n])\ndef test_repr(value):\n    assert eval(repr(value), {'stim': stim}) == value\n    assert repr(eval(repr(value), {'stim': stim})) == repr(value)\n\n\ndef test_hashable():\n    a = stim.GateTarget(5)\n    b = stim.GateTarget(6)\n    c = stim.GateTarget(5)\n    assert hash(a) == hash(c)\n    assert len({a, b, c}) == 2\n\n\ndef test_pauli_type():\n    assert stim.GateTarget(5).pauli_type == 'I'\n    assert stim.target_inv(5).pauli_type == 'I'\n    assert stim.target_rec(-5).pauli_type == 'I'\n    assert stim.target_sweep_bit(6).pauli_type == 'I'\n\n    assert stim.target_x(7).pauli_type == 'X'\n    assert stim.target_y(8).pauli_type == 'Y'\n    assert stim.target_y(8, invert=True).pauli_type == 'Y'\n    assert stim.target_z(9).pauli_type == 'Z'\n"
  },
  {
    "path": "src/stim/cmd/command_analyze_errors.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_analyze_errors.h\"\n\n#include \"stim/cmd/command_help.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\n\nint stim::command_analyze_errors(int argc, const char **argv) {\n    check_for_unknown_arguments(\n        {\n            \"--allow_gauge_detectors\",\n            \"--approximate_disjoint_errors\",\n            \"--block_decompose_from_introducing_remnant_edges\",\n            \"--decompose_errors\",\n            \"--fold_loops\",\n            \"--ignore_decomposition_failures\",\n            \"--in\",\n            \"--out\",\n        },\n        {\"--analyze_errors\", \"--detector_hypergraph\"},\n        \"analyze_errors\",\n        argc,\n        argv);\n    bool decompose_errors = find_bool_argument(\"--decompose_errors\", argc, argv);\n    bool fold_loops = find_bool_argument(\"--fold_loops\", argc, argv);\n    bool allow_gauge_detectors = find_bool_argument(\"--allow_gauge_detectors\", argc, argv);\n    bool ignore_decomposition_failures = find_bool_argument(\"--ignore_decomposition_failures\", argc, argv);\n    bool block_decompose_from_introducing_remnant_edges =\n        find_bool_argument(\"--block_decompose_from_introducing_remnant_edges\", argc, argv);\n\n    const char *approximate_disjoint_errors_arg = find_argument(\"--approximate_disjoint_errors\", argc, argv);\n    float approximate_disjoint_errors_threshold;\n    if (approximate_disjoint_errors_arg != nullptr && *approximate_disjoint_errors_arg == '\\0') {\n        approximate_disjoint_errors_threshold = 1;\n    } else {\n        approximate_disjoint_errors_threshold =\n            find_float_argument(\"--approximate_disjoint_errors\", 0, 0, 1, argc, argv);\n    }\n\n    FILE *in = find_open_file_argument(\"--in\", stdin, \"rb\", argc, argv);\n    auto out_stream = find_output_stream_argument(\"--out\", true, argc, argv);\n    std::ostream &out = out_stream.stream();\n    auto circuit = Circuit::from_file(in);\n    if (in != stdin) {\n        fclose(in);\n    }\n    out << ErrorAnalyzer::circuit_to_detector_error_model(\n               circuit,\n               decompose_errors,\n               fold_loops,\n               allow_gauge_detectors,\n               approximate_disjoint_errors_threshold,\n               ignore_decomposition_failures,\n               block_decompose_from_introducing_remnant_edges)\n        << \"\\n\";\n    return EXIT_SUCCESS;\n}\n\nSubCommandHelp stim::command_analyze_errors_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"analyze_errors\";\n    result.description = \"Converts a circuit into a detector error model.\";\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example_circuit.stim\n            R 0 1\n            X_ERROR(0.125) 0 1\n            CNOT 0 1\n            M 0 1\n            DETECTOR rec[-1]\n            DETECTOR rec[-2]\n\n            >>> stim analyze_errors --in example_circuit.stim\n            error(0.125) D0\n            error(0.125) D0 D1\n        )PARAGRAPH\"));\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> stim gen \\\n                    --code repetition_code \\\n                    --task memory \\\n                    --distance 3 \\\n                    --rounds 1000 \\\n                    --after_reset_flip_probability 0.125 \\\n                    > rep_code.stim\n            >>> stim analyze_errors --fold_loops --in rep_code.stim\n            error(0.125) D0\n            error(0.125) D0 D1\n            error(0.125) D0 D2\n            error(0.125) D1 D3\n            error(0.125) D1 L0\n            error(0.125) D2 D4\n            error(0.125) D3 D5\n            detector(1, 0) D0\n            detector(3, 0) D1\n            repeat 998 {\n                error(0.125) D4 D6\n                error(0.125) D5 D7\n                shift_detectors(0, 1) 0\n                detector(1, 0) D2\n                detector(3, 0) D3\n                shift_detectors 2\n            }\n            shift_detectors(0, 1) 0\n            detector(1, 0) D2\n            detector(3, 0) D3\n            detector(1, 1) D4\n            detector(3, 1) D5\n        )PARAGRAPH\"));\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--allow_gauge_detectors\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Allows non-deterministic detectors to appear in the circuit.\n\n            Normally (without `--allow_gauge_detectors`), when a detector's\n            detecting region anti-commutes with a reset or measurement, stim\n            will raise an exception when analyzing the circuit. When\n            `--allow_gauge_detectors` is set, stim will instead append an error\n            mechanism into the detector error model that has a probability of\n            50% and flips all the detectors that anticommute with the operation.\n\n            This is potentially useful in situations where the layout of\n            detectors is supposed to stay fixed despite variations in the\n            circuit structure. Decoders can interpret the existence of the 50%\n            error as a weight 0 edge saying that the detectors should be fused\n            together.\n\n            For example, in the following stim circuit, the two detectors each\n            anticommute with the reset operation:\n\n                R 0\n                H 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n\n            Without `--allow_gauge_detectors`, stim will raise an exception when\n            analyzing this circuit. With `--allow_gauge_detectors`, stim will\n            add `error(0.5) D1 D2` to the output detector error model.\n\n            BEWARE that gauge detectors are very tricky to work with, and not\n            necessarily supported by all tools (even within stim itself). For\n            example, when converting from measurements to detection events,\n            there isn't a single choice for whether or not each individual gauge\n            detector produced a detection event. This means that it is valid\n            behavior for one conversion from measurements to detection events\n            to give different results from another, as long as the gauge\n            detectors that anticommute with the same operations flip together in\n            a consistent fashion that respects the structure of the circuit.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--approximate_disjoint_errors\",\n            \"probability\",\n            \"0.0\",\n            {\"[none]\", \"[switch]\", \"probability\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Allows disjoint errors to be approximated during the conversion.\n\n            Detector error models require that all error mechanisms be\n            specified as independent mechanisms. But some of the circuit error\n            mechanisms that Stim allows can express errors that don't correspond\n            to independent mechanisms. For example, the custom error channel\n            `PAULI_CHANNEL_1(0.1, 0.2, 0.0)` can't be expressed exactly as a set\n            of independent error mechanisms. But it can be approximated as an\n            `X_ERROR(0.1)` followed by a `Y_ERROR(0.2)`.\n\n            This flag can be set to any probability between 0 (the default when\n            not specified) and 1 (the default when specified without a value).\n            When set to a value strictly between 0 and 1, this determines the\n            maximum disjoint probability that is allowed to be approximated as\n            an independent probability.\n\n            Without `--approximate_disjoint_errors`, attempting to convert a\n            circuit containing `PAULI_CHANNEL_1(0.1, 0.2, 0.0)` will fail with\n            an error stating an approximation is needed. With\n            `--approximate_disjoint_errors`, the conversion will succeed by\n            approximating the error into an `X_ERROR(0.1)` followed by an\n            independent `Y_ERROR(0.2)`.\n\n            Note that, although `DEPOLARIZE1` and `DEPOLARIZE2` are often\n            defined in terms of disjoint errors, they can be exactly converted\n            into a set of independent errors (unless the probability of the\n            depolarizing error occurring exceeds maximum mixing, which is 75%\n            for `DEPOLARIZE1` and 93.75% for `DEPOLARIZE2`). So the\n            `--approximate_disjoint_errors` flag isn't needed for depolarizing\n            errors that appear in practice.\n\n            The error mechanisms that require approximations are:\n            - PAULI_CHANNEL_1\n            - PAULI_CHANNEL_2\n            - ELSE_CORRELATED_ERROR\n\n            In principle some custom Pauli channels can be converted exactly,\n            but Stim does not currently contain logic that attempts to do this.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--block_decompose_from_introducing_remnant_edges\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Prevents A*B from being decomposed unless A,B BOTH appear elsewhere.\n\n            Irrelevant unless `--decompose_errors` is specified.\n\n            When `--decompose_errors` is specified, any circuit error that\n            causes more than two detection events must be decomposed into a\n            set of errors with at most two detection events. The main constraint\n            on this process is that it must not use errors that couldn't\n            otherwise occur, since introducing such errors could violate\n            important properties that are used for decoding. For example, in the\n            normal surface code, it is very important that the decoding graphs\n            for X errors and Z errors are disjoint in the bulk, and decomposing\n            an error into a set of errors that violated this property would be\n            disastrous.\n\n            However, a corner case in this logic occurs if an error E1 that\n            produces detection events A*B needs to be decomposed when an error\n            E2 that produces detection events A appears elsewhere but no error\n            producing detection events B appears elsewhere. The detection events\n            B can be produced by both E1 and E2 occurring, but this a\n            combination of two errors and so treating it as one error can cause\n            problems. For example, it can result in the code distance appearing\n            to be smaller than it actually is. Introducing B is referred to as\n            introducing a \"remnant edge\" because B *only* appears in the\n            detector error model as a remnant of removing A from A*B.\n\n            By default, Stim does allow remnant edges to be introduced. Stim\n            will only do this if it is absolutely necessary, but it *will* do\n            it. And there are in fact QEC circuits where the decomposition\n            requires these edges to succeed. But sometimes the presence of a\n            remnant edge is a hint that the DETECTOR declarations in the circuit\n            are subtly wrong. To cause the decomposition process to fail in\n            this case, the `--block_decompose_from_introducing_remnant_edges`\n            can be specified.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--decompose_errors\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Decomposes errors with many detection events into \"graphlike\" parts.\n\n            When `--decompose_errors` is specified, Stim will suggest how errors\n            that cause more than 2 detection events (non-graphlike errors) can\n            be decomposed into errors with at most 2 detection events (graphlike\n            errors). For example, an error like `error(0.1) D0 D1 D2 D3` may be\n            instead output as `error(0.1) D0 D1 ^ D2 D3` or as\n            `error(0.1) D0 D3 ^ D1 ^ D2`.\n\n            The purpose of this feature is to make matching apply to more cases.\n            A common decoding strategy is \"matching\", where detection events are\n            paired up in order to determine which errors occurred. Matching only\n            works when the Tanner graph of the problem is a graph, not a\n            hypergraph. In other words, it requires all errors to produce at\n            most two detection events. This is a problem, because in practice\n            there are essentially always circuit error mechanisms that produce\n            more than two detection events. For example, in a CSS surface code,\n            Y type errors on the data qubits will produce four detection events.\n            For matching to work in these cases, non-graphlike errors (errors\n            with more than two detection events) need to be approximated as a\n            combination of graphlike errors.\n\n            When Stim is decomposing errors, the main guarantee that it provides\n            is that it will not introduce error mechanisms with symptoms that\n            are otherwise impossible or that would require a combination of\n            non-local errors to actually achieve. Informally, Stim guarantees it\n            will preserve the \"structure\" of the detector error model when\n            suggesting decompositions.\n\n            It's also worth noting that the suggested decompositions are\n            information preserving: the undecomposed model can always be\n            recovered by simply filtering out all `^` characters splitting the\n            errors into suggested components.\n\n            Stim uses two strategies for decomposing errors: intra-channel and\n            inter-channel.\n\n            The *intra-channel* strategy is always applied first, and works by\n            looking at the various detector/observable sets produced by each\n            case of a single noise channel. If some cases are products of other\n            cases, that product is *always* decomposed. For example, suppose\n            that a single qubit depolarizing channel has a `Y5` case that\n            produces four detection events `D0 D1 D2 D3`, an `X5` case that\n            produces two detection events `D0 D1`, and a `Z5` case that produces\n            two detection events `D2 D3`. Because `D0 D1 D2 D3` is the\n            combination of `D0 D1` and `D2 D3`, the `Y5` case will be decomposed\n            into `D0 D1 ^ D2 D3`. An important corner case here is the corner of\n            the CSS surface code, where a Y error has two symptoms which is\n            graphlike but because the intra-channel strategy is aggressive the\n            Y error will still be decomposed into X and Z pieces. This can keep\n            the X and Z decoding graphs disjoint.\n\n            The *inter-channel* strategy is used when an error component is\n            still not graphlike after the intra-channel strategy was applied.\n            This strategy searches over all other error mechanisms looking for a\n            combination that explains the error. If\n            `--block_decompose_from_introducing_remnant_edges` is specified then\n            this must be an exact match, otherwise the match can omit up to two\n            of the symptoms in the error (resulting in the producing of a\n            \"remnant edge\").\n\n            Note that the code implementing these strategies does not special\n            case any Pauli basis. For example, it does not prefer to decompose\n            Y into X*Z as opposed to X into Y*Z. It also does not prefer to\n            decompose YY into IY*YI as opposed to IY into YY*YI. The code\n            operates purely in terms of the sets of symptoms produced by the\n            various cases, with little regard for how those sets were produced.\n\n            If these strategies fail to decompose error into graphlike pieces,\n            Stim will throw an error saying it failed to find a satisfying\n            decomposition.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--fold_loops\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Allows the output to contain `repeat` blocks.\n\n            This flag substantially improves performance on circuits with\n            `REPEAT` blocks with large repetition counts. The analysis will take\n            less time and the output will be more compact. This option is only\n            OFF by default to maintain strict backwards compatibility of the\n            output.\n\n            When a circuit contains a `REPEAT` block, the structure of the\n            detectors often settles into a form that is identical from iteration\n            to iteration. Specifying the `--fold_loops` option tells Stim to\n            watch for periodicity in the structure of detectors by using a\n            \"tortoise and hare\" algorithm (see\n            https://en.wikipedia.org/wiki/Cycle_detection ).\n            This improves the asymptotic complexity of analyzing the loop from\n            O(total_repetitions) to O(cycle_period).\n\n            Note that, although logical observables can \"cross\" from the end of\n            the loop to the start of the loop without preventing loop folding,\n            detectors CANNOT. If there is any detector introduced after the\n            loop, whose sensitivity region extends to before the loop, loop\n            folding will fail and the code will fall back to flattening the\n            loop. This is disastrous for loops with huge repetition counts (e.g.\n            in the billions) because in that case loop folding is the difference\n            between the error analysis finishing in seconds instead of in days.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--ignore_decomposition_failures\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Allows non-graphlike errors into the output when decomposing errors.\n\n            Irrelevant unless `--decompose_errors` is specified.\n\n            Without `--ignore_decomposition_failures`, circuit errors that fail\n            to decompose into graphlike detector error model errors will cause\n            an error and abort the conversion process.\n\n            When `--ignore_decomposition_failures` is specified, circuit errors\n            that fail to decompose into graphlike detector error model errors\n            produce non-graphlike detector error models. Whatever processes\n            the detector error model is then responsible for dealing with the\n            undecomposed errors (e.g. a tool may choose to simply ignore them).\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in\",\n            \"filepath\",\n            \"{stdin}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses the stim circuit file to read the circuit to convert from.\n\n            By default, the circuit is read from stdin. When `--in $FILEPATH` is\n            specified, the circuit is instead read from the file at $FILEPATH.\n\n            The input should be a stim circuit. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out\",\n            \"filepath\",\n            \"{stdout}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses where to write the output detector error model.\n\n            By default, the output is written to stdout. When `--out $FILEPATH`\n            is specified, the output is instead written to the file at $FILEPATH.\n\n            The output is a stim detector error model. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n        )PARAGRAPH\"),\n        });\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_analyze_errors.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_ANALYZE_ERRORS_H\n#define _STIM_CMD_COMMAND_ANALYZE_ERRORS_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_analyze_errors(int argc, const char **argv);\nSubCommandHelp command_analyze_errors_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_analyze_errors.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/main_namespaced.test.h\"\n\nusing namespace stim;\n\nTEST(command_analyze_errors, detector_hypergraph_deprecated) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detector_hypergraph\"}, R\"input(\n            )input\")),\n        trim(R\"output(\n[stderr=[DEPRECATION] Use `stim analyze_errors` instead of `--detector_hypergraph`\n]\n            )output\"));\n}\n\nTEST(command_analyze_errors, analyze_errors) {\n    ASSERT_EQ(run_captured_stim_main({\"--analyze_errors\"}, \"\"), \"\\n\");\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--analyze_errors\"}, R\"input(\nX_ERROR(0.25) 0\nM 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(R\"output(\nerror(0.25) D0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"analyze_errors\"}, R\"input(\nX_ERROR(0.25) 0\nM 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(R\"output(\nerror(0.25) D0\n            )output\"));\n}\n\nTEST(command_analyze_errors, analyze_errors_fold_loops) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--analyze_errors\", \"--fold_loops\"}, R\"input(\nREPEAT 1000 {\n    R 0\n    X_ERROR(0.25) 0\n    M 0\n    DETECTOR rec[-1]\n}\n            )input\")),\n        trim(R\"output(\nrepeat 1000 {\n    error(0.25) D0\n    shift_detectors 1\n}\n            )output\"));\n}\n\nTEST(command_analyze_errors, analyze_errors_allow_gauge_detectors) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--analyze_errors\", \"--allow_gauge_detectors\"}, R\"input(\nR 0\nH 0\nCNOT 0 1\nM 0 1\nDETECTOR rec[-1]\nDETECTOR rec[-2]\n            )input\")),\n        trim(R\"output(\nerror(0.5) D0 D1\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--analyze_errors\"}, R\"input(\nR 0\nH 0\nCNOT 0 1\nM 0 1\nDETECTOR rec[-1]\nDETECTOR rec[-2]\n            )input\")),\n        trim(\n            R\"OUTPUT(\n[stderr=)OUTPUT\"\n            \"\\x1B\"\n            R\"OUTPUT([31mThe circuit contains non-deterministic detectors.\n\nTo make an SVG picture of the problem, you can use the python API like this:\n    your_circuit.diagram('detslice-with-ops-svg', tick=range(0, 5), filter_coords=['D0', 'D1', ])\nor the command line API like this:\n    stim diagram --in your_circuit_file.stim --type detslice-with-ops-svg --tick 0:5 --filter_coords D0:D1 > output_image.svg\n\nThis was discovered while analyzing a Z-basis reset (R) on:\n    qubit 0\n\nThe collapse anti-commuted with these detectors/observables:\n    D0\n    D1\n\nThe backward-propagating error sensitivity for D0 was:\n    X0\n    Z1\n\nThe backward-propagating error sensitivity for D1 was:\n    X0\n\nCircuit stack trace:\n    at instruction #1 [which is R 0]\n)OUTPUT\"\n            \"\\x1B\"\n            R\"OUTPUT([0m]\n)OUTPUT\"));\n}\n\nTEST(command_analyze_errors, analyze_errors_all_approximate_disjoint_errors) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--analyze_errors\", \"--approximate_disjoint_errors\"}, R\"input(\nR 0\nPAULI_CHANNEL_1(0.125, 0.25, 0.375) 0\nM 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(R\"output(\nerror(0.375) D0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--analyze_errors\"}, R\"input(\nR 0\nPAULI_CHANNEL_1(0.125, 0.25, 0.375) 0\nM 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(\n            R\"OUTPUT(\n[stderr=)OUTPUT\"\n            \"\\x1B\"\n            R\"OUTPUT([31mEncountered the operation PAULI_CHANNEL_1 during error analysis, but this operation requires the `approximate_disjoint_errors` option to be enabled.\nIf you're calling from python, using stim.Circuit.detector_error_model, you need to add the argument approximate_disjoint_errors=True.\n\nIf you're calling from the command line, you need to specify --approximate_disjoint_errors.\n\nCircuit stack trace:\n    at instruction #2 [which is PAULI_CHANNEL_1(0.125, 0.25, 0.375) 0]\n)OUTPUT\"\n            \"\\x1B\"\n            R\"OUTPUT([0m]\n)OUTPUT\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--analyze_errors\", \"--approximate_disjoint_errors\", \"0.3\"}, R\"input(\nR 0\nPAULI_CHANNEL_1(0.0, 0.25, 0.375) 0\nM 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(\n            R\"OUTPUT(\n[stderr=)OUTPUT\"\n            \"\\x1B\"\n            R\"OUTPUT([31mPAULI_CHANNEL_1 has a probability argument (0.375) larger than the `approximate_disjoint_errors` threshold (0.3).\n\nCircuit stack trace:\n    at instruction #2 [which is PAULI_CHANNEL_1(0, 0.25, 0.375) 0]\n)OUTPUT\"\n            \"\\x1B\"\n            R\"OUTPUT([0m]\n)OUTPUT\"));\n}\n"
  },
  {
    "path": "src/stim/cmd/command_convert.cc",
    "content": "// Copyright 2023 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_convert.h\"\n\n#include <stdexcept>\n\n#include \"command_help.h\"\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/io/measure_record_batch_writer.h\"\n#include \"stim/io/measure_record_reader.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\n\nstruct DataDetails {\n    int num_measurements;\n    int num_detectors;\n    int num_observables;\n    int bits_per_shot;\n    bool include_measurements;\n    bool include_detectors;\n    bool include_observables;\n};\n\nvoid process_num_flags(int argc, const char **argv, DataDetails *details_out) {\n    details_out->num_measurements = find_int64_argument(\"--num_measurements\", 0, 0, INT64_MAX, argc, argv);\n    details_out->num_detectors = find_int64_argument(\"--num_detectors\", 0, 0, INT64_MAX, argc, argv);\n    details_out->num_observables = find_int64_argument(\"--num_observables\", 0, 0, INT64_MAX, argc, argv);\n\n    details_out->include_measurements = details_out->num_measurements > 0;\n    details_out->include_detectors = details_out->num_detectors > 0;\n    details_out->include_observables = details_out->num_observables > 0;\n}\n\nstatic void process_dem(const char *dem_path_c_str, DataDetails *details_out) {\n    if (dem_path_c_str == nullptr) {\n        return;\n    }\n\n    FILE *dem_file = fopen(dem_path_c_str, \"rb\");\n    if (dem_file == nullptr) {\n        std::stringstream msg;\n        msg << \"Failed to open '\" << dem_path_c_str << \"'\";\n        throw std::invalid_argument(msg.str());\n    }\n    auto dem = DetectorErrorModel::from_file(dem_file);\n    fclose(dem_file);\n    details_out->num_detectors = dem.count_detectors();\n    details_out->num_observables = dem.count_observables();\n    details_out->include_detectors = details_out->num_detectors > 0;\n    details_out->include_observables = details_out->num_observables > 0;\n}\n\nstatic void process_circuit(const char *circuit_path_c_str, const char *types, DataDetails *details_out) {\n    if (circuit_path_c_str == nullptr) {\n        return;\n    }\n    if (types == nullptr) {\n        throw std::invalid_argument(\"--types required when passing circuit\");\n    }\n    FILE *circuit_file = fopen(circuit_path_c_str, \"rb\");\n    if (circuit_file == nullptr) {\n        std::stringstream msg;\n        msg << \"Failed to open '\" << circuit_path_c_str << \"'\";\n        throw std::invalid_argument(msg.str());\n    }\n    auto circuit = Circuit::from_file(circuit_file);\n    fclose(circuit_file);\n    CircuitStats circuit_stats = circuit.compute_stats();\n    details_out->num_measurements = circuit_stats.num_measurements;\n    details_out->num_detectors = circuit_stats.num_detectors;\n    details_out->num_observables = circuit_stats.num_observables;\n\n    while (types != nullptr && *types) {\n        char c = *types;\n        bool found_duplicate = false;\n        if (c == 'M') {\n            found_duplicate = details_out->include_measurements;\n            details_out->include_measurements = true;\n        } else if (c == 'D') {\n            found_duplicate = details_out->include_detectors;\n            details_out->include_detectors = true;\n        } else if (c == 'L') {\n            found_duplicate = details_out->include_observables;\n            details_out->include_observables = true;\n        } else {\n            throw std::invalid_argument(\"Unknown type passed to --types\");\n        }\n\n        if (found_duplicate) {\n            throw std::invalid_argument(\"Each type in types should only be specified once\");\n        }\n        ++types;\n    }\n}\n\nint stim::command_convert(int argc, const char **argv) {\n    check_for_unknown_arguments(\n        {\n            \"--in_format\",\n            \"--out_format\",\n            \"--obs_out_format\",\n            \"--in\",\n            \"--out\",\n            \"--obs_out\",\n            \"--circuit\",\n            \"--dem\",\n            \"--types\",\n            \"--num_measurements\",\n            \"--num_detectors\",\n            \"--num_observables\",\n            \"--bits_per_shot\",\n        },\n        {},\n        \"convert\",\n        argc,\n        argv);\n\n    DataDetails details;\n\n    const auto &in_format = find_enum_argument(\"--in_format\", nullptr, format_name_to_enum_map(), argc, argv);\n    const auto &out_format = find_enum_argument(\"--out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    const auto &obs_out_format = find_enum_argument(\"--obs_out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    FILE *in = find_open_file_argument(\"--in\", stdin, \"rb\", argc, argv);\n    FILE *out = find_open_file_argument(\"--out\", stdout, \"wb\", argc, argv);\n    FILE *obs_out = find_open_file_argument(\"--obs_out\", stdout, \"wb\", argc, argv);\n\n    // Determine the necessary data needed to parse the input and\n    // write to the new output.\n\n    // First see if everything was just given directly.\n    process_num_flags(argc, argv, &details);\n\n    // Next see if we can infer from a given DEM file.\n    const char *dem_path = find_argument(\"--dem\", argc, argv);\n    process_dem(dem_path, &details);\n\n    // Finally see if we can infer from a given circuit file and\n    // list of value types.\n    const char *circuit_path_c_str = find_argument(\"--circuit\", argc, argv);\n    const char *types = find_argument(\"--types\", argc, argv);\n    try {\n        process_circuit(circuit_path_c_str, types, &details);\n    } catch (std::exception &e) {\n        std::cerr << \"\\033[31m\" << e.what() << std::endl;\n        return EXIT_FAILURE;\n    }\n\n    // Not enough information to infer types, at this point we can only\n    // convert arbitrary bits.\n    if (!details.include_measurements && !details.include_detectors && !details.include_observables) {\n        // dets outputs explicit value types, which we don't know if we get here.\n        if (out_format.id == SampleFormat::SAMPLE_FORMAT_DETS) {\n            std::cerr\n                << \"\\033[31mNot enough information given to parse input file to write to dets. Please given a circuit \"\n                   \"with --types, a DEM file, or explicit number of each desired type\\n\";\n            return EXIT_FAILURE;\n        }\n        details.bits_per_shot = find_int64_argument(\"--bits_per_shot\", 0, 0, INT64_MAX, argc, argv);\n        if (details.bits_per_shot == 0) {\n            std::cerr << \"\\033[31mNot enough information given to parse input file.\\n\";\n            return EXIT_FAILURE;\n        }\n        details.include_measurements = true;\n        details.num_measurements = details.bits_per_shot;\n    }\n\n    auto reader = MeasureRecordReader<MAX_BITWORD_WIDTH>::make(\n        in,\n        in_format.id,\n        details.include_measurements ? details.num_measurements : 0,\n        details.include_detectors ? details.num_detectors : 0,\n        details.include_observables ? details.num_observables : 0);\n    auto writer = MeasureRecordWriter::make(out, out_format.id);\n\n    std::unique_ptr<MeasureRecordWriter> obs_writer;\n    if (obs_out != stdout) {\n        obs_writer = MeasureRecordWriter::make(obs_out, obs_out_format.id);\n    } else {\n        obs_out = nullptr;\n    }\n\n    simd_bits<MAX_BITWORD_WIDTH> buf(reader->bits_per_record());\n\n    while (reader->start_and_read_entire_record(buf)) {\n        int64_t offset = 0;\n        if (details.include_measurements) {\n            writer->begin_result_type('M');\n            for (int64_t i = 0; i < details.num_measurements; ++i) {\n                writer->write_bit(buf[i]);\n            }\n        }\n        offset += reader->num_measurements;\n        if (details.include_detectors) {\n            writer->begin_result_type('D');\n            for (int64_t i = 0; i < details.num_detectors; ++i) {\n                writer->write_bit(buf[i + offset]);\n            }\n        }\n        offset += reader->num_detectors;\n        if (details.include_observables) {\n            if (obs_writer) {\n                obs_writer->begin_result_type('L');\n            } else {\n                writer->begin_result_type('L');\n            }\n            for (int64_t i = 0; i < details.num_observables; ++i) {\n                if (obs_writer) {\n                    obs_writer->write_bit(buf[i + offset]);\n                } else {\n                    writer->write_bit(buf[i + offset]);\n                }\n            }\n        }\n        if (obs_writer) {\n            obs_writer->write_end();\n        }\n        writer->write_end();\n    }\n\n    if (in != stdin) {\n        fclose(in);\n    }\n    if (out != stdout) {\n        fclose(out);\n    }\n    if (obs_out != nullptr) {\n        fclose(obs_out);\n    }\n    return EXIT_SUCCESS;\n}\n\nSubCommandHelp stim::command_convert_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"convert\";\n    result.description = clean_doc_string(R\"PARAGRAPH(\n        Convert data between result formats.\n\n        See the various formats here:\n        https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n\n        To read and write data, the size of the records must be known.\n        If writing to a dets file, then the number of measurements, detectors\n        and observables per record must also be known.\n\n        Both of these pieces of information can either be given directly, or\n        inferred from various data sources, such as circuit or dem files.\n        )PARAGRAPH\");\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example.01\n            10000\n            11001\n            00000\n            01001\n\n            >>> stim convert \\\n                --in example.01 \\\n                --in_format 01 \\\n                --out_format dets\n                --num_measurements 5\n            shot M0\n            shot M0 M1 M4\n            shot\n            shot M1 M4\n        )PARAGRAPH\"));\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example.dem\n            detector D0\n            detector D1\n            logical_observable L2\n\n            >>> cat example.dets\n            shot D0\n            shot D0 D1 L2\n            shot\n            shot D1 L2\n\n            >>> stim convert \\\n                --in example.dets \\\n                --in_format dets \\\n                --out_format 01\n                --dem example.dem\n            10000\n            11001\n            00000\n            01001\n        )PARAGRAPH\"));\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example_circuit.stim\n            X 0\n            M 0 1\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(2) rec[-1]\n\n            >>> cat example_measure_data.01\n            00\n            01\n            10\n            11\n\n            >>> stim convert \\\n                --in example_measure_data.01 \\\n                --in_format 01 \\\n                --out_format dets\n                --circuit example_circuit.stim \\\n                --types M\n            shot\n            shot M1\n            shot M0\n            shot M0 M1\n        )PARAGRAPH\"));\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example.01\n            0010\n            0111\n            1000\n            1110\n\n            >>> stim convert \\\n                --in example.01 \\\n                --in_format 01 \\\n                --out_format hits\n                --bits_per_shot 4\n            2\n            1,2,3\n            0\n            0,1,2\n        )PARAGRAPH\"));\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when reading data.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing output data.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--obs_out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing observable flip data.\n\n            Irrelevant unless `--obs_out` is specified.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in\",\n            \"filepath\",\n            \"{stdin}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses the file to read data from.\n\n            By default, the circuit is read from stdin. When `--in $FILEPATH` is\n            specified, the circuit is instead read from the file at $FILEPATH.\n\n            The input's format is specified by `--in_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out\",\n            \"filepath\",\n            \"{stdout}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses where to write the data to.\n\n            By default, the output is written to stdout. When `--out $FILEPATH`\n            is specified, the output is instead written to the file at $FILEPATH.\n\n            The output's format is specified by `--out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--obs_out\",\n            \"filepath\",\n            \"\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the file to write observable flip data to.\n\n            When producing detection event data, the goal is typically to\n            predict whether or not the logical observables were flipped by using\n            the detection events. This argument specifies where to write that\n            observable flip data.\n\n            If this argument isn't specified, the observable flip data isn't\n            written to a file.\n\n            The output is in a format specified by `--obs_out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--circuit\",\n            \"filepath\",\n            \"\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies where the circuit that generated the data is.\n\n            This argument is optional, but can be used to infer the number of\n            measurements, detectors and observables to use per record.\n\n            The circuit file should be a stim circuit. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--types\",\n            \"M|D|L\",\n            \"\",\n            {\"[none]\"\n             \"types\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the types of events in the files.\n\n            This argument is required if a circuit is given as the circuit can\n            give the number of each type of event, but not which events are\n            contained within an input file.\n\n            Note that in most cases, a file will have either measurements only,\n            detections only, or detections and observables.\n\n            The type values (M, D, L) correspond to the value prefix letters\n            in dets files. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md#dets\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--num_measurements\",\n            \"int\",\n            \"0\",\n            {\"[none], int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the number of measurements in the input/output files.\n\n            This argument is required if writing to a dets file and the circuit\n            is not given.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--num_detectors\",\n            \"int\",\n            \"0\",\n            {\"[none], int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the number of detectors in the input/output files.\n\n            This argument is required if writing to a dets file and the circuit\n            or dem is not given.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--num_observables\",\n            \"int\",\n            \"0\",\n            {\"[none], int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the number of observables in the input/output files.\n\n            This argument is required if writing to a dets file and the circuit\n            or dem is not given.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--bits_per_shot\",\n            \"int\",\n            \"0\",\n            {\"[none], int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the number of bits per shot in the input/output files.\n\n            This argument is required if the circuit, dem or num_* flags\n            are not given, and not supported when writing to a dets file.\n\n            In this case we just treat the bits aas arbitrary data. It is up\n            to the user to interpert it correctly.\n        )PARAGRAPH\"),\n        });\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_convert.h",
    "content": "/*\n * Copyright 2023 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_CONVERT_H\n#define _STIM_CMD_COMMAND_CONVERT_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_convert(int argc, const char **argv);\nSubCommandHelp command_convert_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_convert.test.cc",
    "content": "// Copyright 2023 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/main_namespaced.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(command_convert, convert_measurements_with_circuit_to_dets) {\n    RaiiTempNamedFile tmp(R\"CIRCUIT(\n        X 0\n        M 0 1\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(2) rec[-1]\n      )CIRCUIT\");\n\n    std::vector<std::tuple<std::string, std::string>> measurement_data{\n        std::make_tuple(\"01\", \"00\\n01\\n10\\n11\\n\"),\n        std::make_tuple(\"b8\", std::string({0x00, 0x02, 0x01, 0x03})),\n        std::make_tuple(\"hits\", \"\\n1\\n0\\n0,1\\n\"),\n        std::make_tuple(\"r8\", std::string({0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}))};\n\n    for (const auto &[in_format, in_data] : measurement_data) {\n        ASSERT_EQ(\n            run_captured_stim_main(\n                {\"convert\",\n                 \"--in_format\",\n                 in_format.c_str(),\n                 \"--out_format\",\n                 \"dets\",\n                 \"--circuit\",\n                 tmp.path.c_str(),\n                 \"--types=M\"},\n                in_data),\n            \"shot\\nshot M1\\nshot M0\\nshot M0 M1\\n\");\n    }\n}\n\nTEST(command_convert, convert_detections_observables_with_circuit_to_dets) {\n    RaiiTempNamedFile tmp(R\"CIRCUIT(\n        CX 0 2 1 2\n        M 2\n        CX rec[-1] 2\n        DETECTOR rec[-1]\n        TICK\n\n        CX 0 2 1 2\n        M 2\n        CX rec[-1] 2\n        DETECTOR rec[-1] rec[-2]\n        TICK\n\n        CX 0 2 1 2\n        M 2\n        CX rec[-1] 2\n        DETECTOR rec[-1] rec[-2]\n        TICK\n\n        M 0 1\n        DETECTOR rec[-1] rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\");\n\n    std::vector<std::tuple<std::string, std::string>> detection_data{\n        std::make_tuple(\"01\", \"00000\\n11000\\n01100\\n00110\\n00010\\n00011\\n\"),\n        std::make_tuple(\"b8\", std::string({0x00, 0x03, 0x06, 0x0c, 0x08, 0x18})),\n        std::make_tuple(\"hits\", \"\\n0,1\\n1,2\\n2,3\\n3\\n3,4\\n\"),\n        std::make_tuple(\n            \"r8\",\n            std::string({0x05, 0x00, 0x00, 0x03, 0x01, 0x00, 0x02, 0x02, 0x00, 0x01, 0x03, 0x01, 0x03, 0x00, 0x00}))};\n\n    for (const auto &[in_format, in_data] : detection_data) {\n        ASSERT_EQ(\n            run_captured_stim_main(\n                {\"convert\",\n                 \"--in_format\",\n                 in_format.c_str(),\n                 \"--out_format\",\n                 \"dets\",\n                 \"--circuit\",\n                 tmp.path.c_str(),\n                 \"--types=DL\"},\n                in_data),\n            \"shot\\nshot D0 D1\\nshot D1 D2\\nshot D2 D3\\nshot D3\\nshot D3 L0\\n\");\n    }\n}\n\nTEST(command_convert, convert_detections_observables_with_circuit_to_dets_with_obs_out) {\n    RaiiTempNamedFile tmp(R\"CIRCUIT(\n        CX 0 2 1 2\n        M 2\n        CX rec[-1] 2\n        DETECTOR rec[-1]\n        TICK\n\n        CX 0 2 1 2\n        M 2\n        CX rec[-1] 2\n        DETECTOR rec[-1] rec[-2]\n        TICK\n\n        CX 0 2 1 2\n        M 2\n        CX rec[-1] 2\n        DETECTOR rec[-1] rec[-2]\n        TICK\n\n        M 0 1\n        DETECTOR rec[-1] rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\");\n    RaiiTempNamedFile tmp_obs;\n\n    std::vector<std::tuple<std::string, std::string>> detection_data{\n        std::make_tuple(\"01\", \"00000\\n11000\\n01100\\n00110\\n00010\\n00011\\n\"),\n        std::make_tuple(\"b8\", std::string({0x00, 0x03, 0x06, 0x0c, 0x08, 0x18})),\n        std::make_tuple(\"hits\", \"\\n0,1\\n1,2\\n2,3\\n3\\n3,4\\n\"),\n        std::make_tuple(\n            \"r8\",\n            std::string({0x05, 0x00, 0x00, 0x03, 0x01, 0x00, 0x02, 0x02, 0x00, 0x01, 0x03, 0x01, 0x03, 0x00, 0x00}))};\n\n    for (const auto &[in_format, in_data] : detection_data) {\n        ASSERT_EQ(\n            run_captured_stim_main(\n                {\"convert\",\n                 \"--in_format\",\n                 in_format.c_str(),\n                 \"--out_format\",\n                 \"dets\",\n                 \"--obs_out_format\",\n                 \"dets\",\n                 \"--obs_out\",\n                 tmp_obs.path.c_str(),\n                 \"--circuit\",\n                 tmp.path.c_str(),\n                 \"--types=DL\"},\n                in_data),\n            \"shot\\nshot D0 D1\\nshot D1 D2\\nshot D2 D3\\nshot D3\\nshot D3\\n\");\n        ASSERT_EQ(tmp_obs.read_contents(), \"shot\\nshot\\nshot\\nshot\\nshot\\nshot L0\\n\");\n    }\n}\n\nTEST(command_convert, convert_detections_observables_with_circuit_no_dets) {\n    RaiiTempNamedFile tmp(R\"CIRCUIT(\n      R 0 1 2 3 4\n      TICK\n      CX 0 1 2 3\n      DEPOLARIZE2(0.3) 0 1 2 3\n      TICK\n      CX 2 1 4 3\n      DEPOLARIZE2(0.3) 2 1 4 3\n      TICK\n      MR 1 3\n      DETECTOR(1, 0) rec[-2]\n      DETECTOR(3, 0) rec[-1]\n      M 0 2 4\n      DETECTOR(1, 1) rec[-2] rec[-3] rec[-5]\n      DETECTOR(3, 1) rec[-1] rec[-2] rec[-4]\n      OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\");\n\n    std::vector<std::tuple<std::string, std::string>> detection_data{\n        std::make_tuple(\"01\", \"10100\\n00011\\n00000\\n00100\\n00000\\n10000\\n\"),\n        std::make_tuple(\"b8\", std::string({0x05, 0x18, 0x00, 0x04, 0x00, 0x01})),\n        std::make_tuple(\"hits\", \"0,2\\n3,4\\n\\n2\\n\\n0\\n\"),\n        std::make_tuple(\"r8\", std::string({0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x05, 0x02, 0x02, 0x05, 0x00, 0x04}))};\n\n    for (const auto &[in_format, in_data] : detection_data) {\n        for (const auto &[out_format, out_data] : detection_data) {\n            ASSERT_EQ(\n                run_captured_stim_main(\n                    {\"convert\",\n                     \"--in_format\",\n                     in_format.c_str(),\n                     \"--out_format\",\n                     out_format.c_str(),\n                     \"--circuit\",\n                     tmp.path.c_str(),\n                     \"--types=DL\"},\n                    in_data),\n                out_data);\n        }\n    }\n}\n\nTEST(command_convert, convert_detections_observables_with_dem) {\n    RaiiTempNamedFile tmp(R\"DEM(\n        detector D0\n        detector D1\n        logical_observable L2\n      )DEM\");\n\n    std::vector<std::tuple<std::string, std::string>> detection_data{\n        std::make_tuple(\"01\", \"10000\\n11001\\n00000\\n01001\\n\"),\n        std::make_tuple(\"b8\", std::string({0x01, 0x13, 0x00, 0x12})),\n        std::make_tuple(\"dets\", \"shot D0\\nshot D0 D1 L2\\nshot\\nshot D1 L2\\n\"),\n        std::make_tuple(\"hits\", \"0\\n0,1,4\\n\\n1,4\\n\"),\n        std::make_tuple(\"r8\", std::string({0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x05, 0x01, 0x02, 0x00}))};\n\n    for (const auto &[in_format, in_data] : detection_data) {\n        for (const auto &[out_format, out_data] : detection_data) {\n            ASSERT_EQ(\n                run_captured_stim_main(\n                    {\"convert\",\n                     \"--in_format\",\n                     in_format.c_str(),\n                     \"--out_format\",\n                     out_format.c_str(),\n                     \"--dem\",\n                     tmp.path.c_str()},\n                    in_data),\n                out_data);\n        }\n    }\n}\n\nTEST(command_convert, convert_measurements_no_circuit_or_dem) {\n    std::vector<std::tuple<std::string, std::string>> measurement_data{\n        std::make_tuple(\"01\", \"100\\n010\\n110\\n001\\n010\\n111\\n\"),\n        std::make_tuple(\"b8\", std::string({0x01, 0x02, 0x03, 0x04, 0x02, 0x07})),\n        std::make_tuple(\"hits\", \"0\\n1\\n0,1\\n2\\n1\\n0,1,2\\n\"),\n        std::make_tuple(\"dets\", \"shot M0\\nshot M1\\nshot M0 M1\\nshot M2\\nshot M1\\nshot M0 M1 M2\\n\"),\n        std::make_tuple(\n            \"r8\",\n            std::string({0x00, 0x02, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}))};\n\n    for (const auto &[in_format, in_data] : measurement_data) {\n        for (const auto &[out_format, out_data] : measurement_data) {\n            ASSERT_EQ(\n                run_captured_stim_main(\n                    {\"convert\",\n                     \"--in_format\",\n                     in_format.c_str(),\n                     \"--out_format\",\n                     out_format.c_str(),\n                     \"--num_measurements\",\n                     \"3\"},\n                    in_data),\n                out_data);\n        }\n    }\n}\n\nTEST(command_convert, convert_detections_observables_no_circuit_or_dem) {\n    std::vector<std::tuple<std::string, std::string>> detection_data{\n        std::make_tuple(\"01\", \"10000\\n11001\\n00000\\n01001\\n\"),\n        std::make_tuple(\"b8\", std::string({0x01, 0x13, 0x00, 0x12})),\n        std::make_tuple(\"dets\", \"shot D0\\nshot D0 D1 L2\\nshot\\nshot D1 L2\\n\"),\n        std::make_tuple(\"hits\", \"0\\n0,1,4\\n\\n1,4\\n\"),\n        std::make_tuple(\"r8\", std::string({0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x05, 0x01, 0x02, 0x00}))};\n\n    for (const auto &[in_format, in_data] : detection_data) {\n        for (const auto &[out_format, out_data] : detection_data) {\n            ASSERT_EQ(\n                run_captured_stim_main(\n                    {\"convert\",\n                     \"--in_format\",\n                     in_format.c_str(),\n                     \"--out_format\",\n                     out_format.c_str(),\n                     \"--num_detectors\",\n                     \"2\",\n                     \"--num_observables\",\n                     \"3\"},\n                    in_data),\n                out_data);\n        }\n    }\n}\n\nTEST(command_convert, convert_bits_per_shot_no_dets) {\n    std::vector<std::tuple<std::string, std::string>> measurement_data{\n        std::make_tuple(\"01\", \"00\\n01\\n10\\n11\\n\"),\n        std::make_tuple(\"b8\", std::string({0x00, 0x02, 0x01, 0x03})),\n        std::make_tuple(\"hits\", \"\\n1\\n0\\n0,1\\n\"),\n        std::make_tuple(\"r8\", std::string({0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}))};\n\n    for (const auto &[in_format, in_data] : measurement_data) {\n        for (const auto &[out_format, out_data] : measurement_data) {\n            ASSERT_EQ(\n                run_captured_stim_main(\n                    {\"convert\",\n                     \"--in_format\",\n                     in_format.c_str(),\n                     \"--out_format\",\n                     out_format.c_str(),\n                     \"--bits_per_shot=2\"},\n                    in_data),\n                out_data);\n        }\n    }\n}\n\nTEST(command_convert, convert_multiple_bitword_sized_records) {\n    ASSERT_EQ(\n        run_captured_stim_main(\n            {\"convert\", \"--in_format=b8\", \"--out_format=b8\", \"--bits_per_shot=2048\"}, std::string(256, 0x6b)),\n        std::string(256, 0x6b));\n}\n\nTEST(command_convert, convert_circuit_fail_without_types) {\n    RaiiTempNamedFile tmp(R\"CIRCUIT(\n        X 0\n        M 0 1\n      )CIRCUIT\");\n\n    ASSERT_TRUE(matches(\n        run_captured_stim_main(\n            {\"convert\",\n             \"--in_format=01\",\n             \"--out_format\",\n             \"dets\",\n             \"--circuit\",\n             tmp.path.c_str(),\n             \"--num_measurements=2\"},\n            \"\"),\n        \".*--types required when passing circuit.*\"));\n}\n\nTEST(command_convert, convert_fail_without_any_information) {\n    ASSERT_TRUE(matches(\n        run_captured_stim_main({\"convert\", \"--in_format=r8\", \"--out_format=b8\"}, \"\"),\n        \".*Not enough information given to parse input file.*\"));\n}\n\nTEST(command_convert, convert_fail_with_bits_per_shot_to_dets) {\n    ASSERT_TRUE(matches(\n        run_captured_stim_main({\"convert\", \"--in_format=01\", \"--out_format\", \"dets\", \"--bits_per_shot=2\"}, \"\"),\n        \".*Not enough information given to parse input file to write to dets.*\"));\n}\n\nTEST(command_convert, convert_invalid_types) {\n    RaiiTempNamedFile tmp(\"\");\n\n    ASSERT_TRUE(matches(\n        run_captured_stim_main(\n            {\"convert\", \"--in_format=dets\", \"--out_format=dets\", \"--circuit\", tmp.path.c_str(), \"--types=N\"}, \"\"),\n        \".*Unknown type passed to --types.*\"));\n\n    ASSERT_TRUE(matches(\n        run_captured_stim_main(\n            {\"convert\", \"--in_format=dets\", \"--out_format=dets\", \"--circuit\", tmp.path.c_str(), \"--types=MM\"}, \"\"),\n        \".*Each type in types should only be specified once.*\"));\n}\n"
  },
  {
    "path": "src/stim/cmd/command_detect.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_detect.h\"\n\n#include \"command_help.h\"\n#include \"stim/io/raii_file.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/util_bot/probability_util.h\"\n\nusing namespace stim;\n\nint stim::command_detect(int argc, const char **argv) {\n    check_for_unknown_arguments(\n        {\"--seed\", \"--shots\", \"--append_observables\", \"--out_format\", \"--out\", \"--in\", \"--obs_out\", \"--obs_out_format\"},\n        {\"--detect\", \"--prepend_observables\"},\n        \"detect\",\n        argc,\n        argv);\n    const auto &out_format = find_enum_argument(\"--out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    const auto &obs_out_format = find_enum_argument(\"--obs_out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    bool prepend_observables = find_bool_argument(\"--prepend_observables\", argc, argv);\n    if (prepend_observables) {\n        std::cerr << \"[DEPRECATION] Avoid using `--prepend_observables`. Data readers assume observables are appended, \"\n                     \"not prepended.\\n\";\n    }\n    bool append_observables = find_bool_argument(\"--append_observables\", argc, argv);\n    uint64_t num_shots =\n        find_argument(\"--shots\", argc, argv)    ? (uint64_t)find_int64_argument(\"--shots\", 1, 0, INT64_MAX, argc, argv)\n        : find_argument(\"--detect\", argc, argv) ? (uint64_t)find_int64_argument(\"--detect\", 1, 0, INT64_MAX, argc, argv)\n                                                : 1;\n    if (out_format.id == SampleFormat::SAMPLE_FORMAT_DETS && !append_observables) {\n        prepend_observables = true;\n    }\n\n    RaiiFile in(find_open_file_argument(\"--in\", stdin, \"rb\", argc, argv));\n    RaiiFile out(find_open_file_argument(\"--out\", stdout, \"wb\", argc, argv));\n    RaiiFile obs_out(find_open_file_argument(\"--obs_out\", stdout, \"wb\", argc, argv));\n    if (obs_out.f == stdout) {\n        obs_out.f = nullptr;\n    }\n    if (out.f == stdout) {\n        out.responsible_for_closing = false;\n    }\n    if (in.f == stdin) {\n        out.responsible_for_closing = false;\n    }\n    if (num_shots == 0) {\n        return EXIT_SUCCESS;\n    }\n\n    auto circuit = Circuit::from_file(in.f);\n    in.done();\n    auto rng = optionally_seeded_rng(argc, argv);\n    sample_batch_detection_events_writing_results_to_disk<MAX_BITWORD_WIDTH>(\n        circuit,\n        num_shots,\n        prepend_observables,\n        append_observables,\n        out.f,\n        out_format.id,\n        rng,\n        obs_out.f,\n        obs_out_format.id);\n    return EXIT_SUCCESS;\n}\n\nSubCommandHelp stim::command_detect_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"detect\";\n    result.description = \"Sample detection events and observable flips from a circuit.\";\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example.stim\n            H 0\n            CNOT 0 1\n            X_ERROR(0.1) 0 1\n            M 0 1\n            DETECTOR rec[-1] rec[-2]\n\n            >>> stim detect --shots 5 --in example.stim\n            0\n            1\n            0\n            0\n            0\n        )PARAGRAPH\"));\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example.stim\n            # Single-shot X-basis rep code circuit.\n            RX 0 1 2 3 4 5 6\n            MPP X0*X1 X1*X2 X2*X3 X3*X4 X4*X5 X5*X6\n            Z_ERROR(0.1) 0 1 2 3 4 5 6\n            MPP X0 X1 X2 X3 X4 X5 X6\n            DETECTOR rec[-1] rec[-2] rec[-8]   # X6 X5 now = X5*X6 before\n            DETECTOR rec[-2] rec[-3] rec[-9]   # X5 X4 now = X4*X5 before\n            DETECTOR rec[-3] rec[-4] rec[-10]  # X4 X3 now = X3*X4 before\n            DETECTOR rec[-4] rec[-5] rec[-11]  # X3 X2 now = X2*X3 before\n            DETECTOR rec[-5] rec[-6] rec[-12]  # X2 X1 now = X1*X2 before\n            DETECTOR rec[-6] rec[-7] rec[-13]  # X1 X0 now = X0*X1 before\n            OBSERVABLE_INCLUDE(0) rec[-1]\n\n            >>> stim detect \\\n                --in example.stim \\\n                --out_format dets \\\n                --shots 10\n            shot\n            shot\n            shot L0 D0 D5\n            shot D1 D2\n            shot\n            shot L0 D0\n            shot D5\n            shot\n            shot D3 D4\n            shot D0 D1\n        )PARAGRAPH\"));\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing output data.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--seed\",\n            \"int\",\n            \"system_entropy\",\n            {\"[none]\", \"int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Makes simulation results PARTIALLY deterministic.\n\n            The seed integer must be a non-negative 64 bit signed integer.\n\n            When `--seed` isn't specified, the random number generator is seeded\n            using fresh entropy requested from the operating system.\n\n            When `--seed #` is set, the exact same simulation results will be\n            produced every time ASSUMING:\n\n            - the exact same other flags are specified\n            - the exact same version of Stim is being used\n            - the exact same machine architecture is being used (for example,\n                you're not switching from a machine that has AVX2 instructions\n                to one that doesn't).\n\n            CAUTION: simulation results *WILL NOT* be consistent between\n            versions of Stim. This restriction is present to make it possible to\n            have future optimizations to the random sampling, and is enforced by\n            introducing intentional differences in the seeding strategy from\n            version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines.\n            For example, using the same seed on a machine that supports AVX\n            instructions and one that only supports SSE instructions may produce\n            different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary\n            other flags and modes. For example, `--skip_reference_sample` may\n            result in fewer calls the to the random number generator before\n            reported sampling begins. More generally, using the same seed for\n            `stim sample` and `stim detect` will not result in detection events\n            corresponding to the measurement results.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--shots\",\n            \"int\",\n            \"1\",\n            {\"[none]\", \"int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the number of samples to take from the circuit.\n\n            Defaults to 1.\n            Must be an integer between 0 and a quintillion (10^18).\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--append_observables\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Appends observable flips to the end of samples as extra detectors.\n\n            PREFER --obs_out OVER THIS FLAG. Mixing the observable flip data\n            into detection event data tends to require simply separating them\n            again immediately, creating unnecessary work. For example, when\n            testing a decoder, you do not want to give the observable flips to\n            the decoder because that is the information the decoder is supposed\n            to be predicting from the detection events.\n\n            This flag causes observable flip data to be appended to each sample,\n            as if the observables were extra detectors at the end of the\n            circuit. For example, if there are 100 detectors and 10 observables\n            in the circuit, then the output will contain 110 detectors and the\n            last 10 are the observables.\n\n            Note that, when using `--out_format dets`, this option is implicitly\n            activated but observables are not appended as if they were\n            detectors (because `dets` has type hinting information). For\n            example, in the example from the last paragraph, the observables\n            would be named `L0` through `L9` instead of `D100` through `D109`.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--obs_out\",\n            \"filepath\",\n            \"\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the file to write observable flip data to.\n\n            When sampling detection event data, the goal is typically to predict\n            whether or not the logical observables were flipped by using the\n            detection events. This argument specifies where to write that\n            observable flip data.\n\n            If this argument isn't specified, the observable flip data isn't\n            written to a file.\n\n            The output is in a format specified by `--obs_out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--obs_out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing observable flip data.\n\n            Irrelevant unless `--obs_out` is specified.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in\",\n            \"filepath\",\n            \"{stdin}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses the stim circuit file to read the circuit to sample from.\n\n            By default, the circuit is read from stdin. When `--in $FILEPATH` is\n            specified, the circuit is instead read from the file at $FILEPATH.\n\n            The input should be a stim circuit. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out\",\n            \"filepath\",\n            \"{stdout}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses where to write the sampled data to.\n\n            By default, the output is written to stdout. When `--out $FILEPATH`\n            is specified, the output is instead written to the file at $FILEPATH.\n\n            The output is in a format specified by `--out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_detect.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_DETECT_H\n#define _STIM_CMD_COMMAND_DETECT_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_detect(int argc, const char **argv);\nSubCommandHelp command_detect_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_detect.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/main_namespaced.test.h\"\n\nusing namespace stim;\n\nTEST(command_detect, detect_basic) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\"}, R\"input(\nM 0\n            )input\")),\n        trim(R\"output(\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\"}, R\"input(\nM 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(R\"output(\n0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\"}, R\"input(\nX_ERROR(1) 0\nM 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(R\"output(\n1\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\", \"2\"}, R\"input(\nX_ERROR(1) 0\nM 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(R\"output(\n1\n1\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"detect\", \"--shots\", \"2\"}, R\"input(\nX_ERROR(1) 0\nM 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(R\"output(\n1\n1\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\"}, R\"input(\nDETECTOR\n            )input\")),\n        trim(R\"output(\n0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\"}, R\"input(\nX_ERROR(1) 0\nMR 0\nDETECTOR rec[-1]\n            )input\")),\n        trim(R\"output(\n1\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\"}, R\"input(\nX_ERROR(1) 0\nM 0\nM 0\nDETECTOR rec[-1] rec[-2]\n            )input\")),\n        trim(R\"output(\n0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\"}, R\"input(\nX_ERROR(1) 0\nMR 0\nMR 0\nDETECTOR rec[-1] rec[-2]\n            )input\")),\n        trim(R\"output(\n1\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\"}, R\"input(\nM 2\nM 2\nREPEAT 3 {\n  R 2\n  CNOT 0 2 1 2\n  DETECTOR rec[-1] rec[-2]\n  M 2\n}\nM 0 1\nOBSERVABLE_INCLUDE(0) rec[-2] rec[-1]\n            )input\")),\n        trim(R\"output(\n000\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\", \"--prepend_observables\"}, R\"input(\nM 2\nM 2\nREPEAT 3 {\n  R 2\n  CNOT 0 2 1 2\n  DETECTOR rec[-1] rec[-2]\n  M 2\n}\nM 0 1\nOBSERVABLE_INCLUDE(0) rec[-2] rec[-1]\n            )input\")),\n        trim(R\"output(\n0000\n[stderr=[DEPRECATION] Avoid using `--prepend_observables`. Data readers assume observables are appended, not prepended.\n]\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\", \"--prepend_observables\"}, R\"input(\nM 2\nM 2\nX_ERROR(1) 0 1\nREPEAT 3 {\n  R 2\n  CNOT 0 2 1 2\n  DETECTOR rec[-1] rec[-2]\n  M 2\n}\nM 0 1\nOBSERVABLE_INCLUDE(0) rec[-2]\n            )input\")),\n        trim(R\"output(\n1000\n[stderr=[DEPRECATION] Avoid using `--prepend_observables`. Data readers assume observables are appended, not prepended.\n]\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--detect\", \"--append_observables\"}, R\"input(\nM 2\nM 2\nX_ERROR(1) 0 1\nREPEAT 3 {\n  R 2\n  CNOT 0 2 1 2\n  DETECTOR rec[-1] rec[-2]\n  M 2\n}\nM 0 1\nOBSERVABLE_INCLUDE(0) rec[-2]\n            )input\")),\n        trim(R\"output(\n0001\n            )output\"));\n}\n\nTEST(command_detect, detection_event_simulator_counts_measurements_correctly) {\n    auto s = run_captured_stim_main({\"--detect=1000\"}, \"MPP Z8*X9\\nDETECTOR rec[-1]\");\n    size_t zeroes = 0;\n    size_t ones = 0;\n    for (size_t k = 0; k < s.size(); k += 2) {\n        zeroes += s[k] == '0';\n        ones += s[k] == '1';\n        ASSERT_EQ(s[k + 1], '\\n');\n    }\n    ASSERT_EQ(zeroes + ones, 1000);\n    ASSERT_TRUE(400 < zeroes && zeroes < 600);\n}\n\nTEST(command_detect, seeded_detecting) {\n    ASSERT_EQ(\n        run_captured_stim_main({\"detect\", \"--shots=256\", \"--seed 5\"}, R\"input(\n                X_ERROR(0.5) 0\n                M 0\n                DETECTOR rec[-1]\n            )input\"),\n        run_captured_stim_main({\"detect\", \"--shots=256\", \"--seed 5\"}, R\"input(\n                X_ERROR(0.5) 0\n                M 0\n                DETECTOR rec[-1]\n            )input\"));\n\n    ASSERT_NE(\n        run_captured_stim_main({\"detect\", \"--shots=256\"}, R\"input(\n                X_ERROR(0.5) 0\n                M 0\n                DETECTOR rec[-1]\n            )input\"),\n        run_captured_stim_main({\"detect\", \"--shots=256\"}, R\"input(\n                X_ERROR(0.5) 0\n                M 0\n                DETECTOR rec[-1]\n            )input\"));\n\n    ASSERT_NE(\n        run_captured_stim_main({\"detect\", \"--shots=256\", \"--seed 5\"}, R\"input(\n                X_ERROR(0.5) 0\n                M 0\n                DETECTOR rec[-1]\n            )input\"),\n        run_captured_stim_main({\"detect\", \"--shots=256\", \"--seed 6\"}, R\"input(\n                X_ERROR(0.5) 0\n                M 0\n                DETECTOR rec[-1]\n            )input\"));\n}\n"
  },
  {
    "path": "src/stim/cmd/command_diagram.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_diagram.h\"\n\n#include <limits>\n\n#include \"command_help.h\"\n#include \"stim/diagram/crumble.h\"\n#include \"stim/diagram/detector_slice/detector_slice_set.h\"\n#include \"stim/diagram/graph/match_graph_3d_drawer.h\"\n#include \"stim/diagram/graph/match_graph_svg_drawer.h\"\n#include \"stim/diagram/timeline/timeline_3d_drawer.h\"\n#include \"stim/diagram/timeline/timeline_ascii_drawer.h\"\n#include \"stim/diagram/timeline/timeline_svg_drawer.h\"\n#include \"stim/io/raii_file.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nenum class DiagramTypes {\n    NOT_A_DIAGRAM,\n    INTERACTIVE_HTML,\n    TIMELINE_TEXT,\n    TIMELINE_SVG,\n    TIMELINE_3D,\n    TIMELINE_3D_HTML,\n    TIME_SLICE_SVG,\n    TIME_SLICE_PLUS_DETECTOR_SLICE_SVG,\n    MATCH_GRAPH_SVG,\n    MATCH_GRAPH_3D,\n    MATCH_GRAPH_3D_HTML,\n    DETECTOR_SLICE_TEXT,\n    DETECTOR_SLICE_SVG,\n};\n\nstim::Circuit _read_circuit(RaiiFile &in, int argc, const char **argv) {\n    auto circuit = Circuit::from_file(in.f);\n    in.done();\n    if (find_bool_argument(\"--remove_noise\", argc, argv)) {\n        circuit = circuit.without_noise();\n    }\n    return circuit;\n}\n\nstim::DetectorErrorModel _read_dem(RaiiFile &in, int argc, const char **argv) {\n    if (find_bool_argument(\"--remove_noise\", argc, argv)) {\n        throw std::invalid_argument(\n            \"--remove_noise is incompatible with match graph diagrams, because the noise is needed to produce the \"\n            \"match graph.\");\n    }\n\n    std::string content;\n    while (true) {\n        int c = getc(in.f);\n        if (c == EOF) {\n            break;\n        }\n        content.push_back(c);\n    }\n    in.done();\n\n    try {\n        return DetectorErrorModel(content);\n    } catch (const std::exception &_) {\n    }\n\n    Circuit circuit(content);\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 1, true, false);\n    if (dem.count_errors() == 0) {\n        std::cerr << \"Warning: the detector error model derived from the circuit had no errors.\\n\"\n                     \"Did you input a noiseless circuit instead of a noisy one?\\n\";\n    }\n    return dem;\n}\n\nstd::vector<CoordFilter> _read_coord_filter(int argc, const char **argv) {\n    const char *arg = find_argument(\"--filter_coords\", argc, argv);\n    if (arg == nullptr) {\n        return std::vector<CoordFilter>{CoordFilter{}};\n    }\n\n    std::vector<CoordFilter> result;\n    for (std::string_view term : split_view(':', arg)) {\n        result.push_back(CoordFilter::parse_from(term));\n    }\n    return result;\n}\n\nDiagramTypes _read_diagram_type(int argc, const char **argv) {\n    std::map<std::string_view, DiagramTypes> diagram_types{\n        {\"timeline-text\", DiagramTypes::TIMELINE_TEXT},\n        {\"timeline-svg\", DiagramTypes::TIMELINE_SVG},\n        {\"timeline-3d\", DiagramTypes::TIMELINE_3D},\n        {\"timeline-3d-html\", DiagramTypes::TIMELINE_3D_HTML},\n        {\"timeslice-svg\", DiagramTypes::TIME_SLICE_SVG},\n        {\"detslice-with-ops-svg\", DiagramTypes::TIME_SLICE_PLUS_DETECTOR_SLICE_SVG},\n        {\"matchgraph-svg\", DiagramTypes::MATCH_GRAPH_SVG},\n        {\"matchgraph-3d\", DiagramTypes::MATCH_GRAPH_3D},\n        {\"matchgraph-3d-html\", DiagramTypes::MATCH_GRAPH_3D_HTML},\n        {\"interactive-html\", DiagramTypes::INTERACTIVE_HTML},\n        {\"detslice-text\", DiagramTypes::DETECTOR_SLICE_TEXT},\n        {\"detslice-svg\", DiagramTypes::DETECTOR_SLICE_SVG},\n    };\n    std::map<std::string_view, DiagramTypes> quietly_allowed_diagram_types{\n        {\"time-slice-svg\", DiagramTypes::TIME_SLICE_SVG},\n        {\"time+detector-slice-svg\", DiagramTypes::TIME_SLICE_PLUS_DETECTOR_SLICE_SVG},\n        {\"interactive\", DiagramTypes::INTERACTIVE_HTML},\n        {\"detector-slice-text\", DiagramTypes::DETECTOR_SLICE_TEXT},\n        {\"detector-slice-svg\", DiagramTypes::DETECTOR_SLICE_SVG},\n        {\"match-graph-svg\", DiagramTypes::MATCH_GRAPH_SVG},\n        {\"match-graph-3d\", DiagramTypes::MATCH_GRAPH_3D},\n        {\"match-graph-3d-html\", DiagramTypes::MATCH_GRAPH_3D_HTML},\n    };\n    DiagramTypes type = DiagramTypes::NOT_A_DIAGRAM;\n    try {\n        type = find_enum_argument(\"--type\", nullptr, quietly_allowed_diagram_types, argc, argv);\n    } catch (const std::invalid_argument &_) {\n    }\n    if (type == DiagramTypes::NOT_A_DIAGRAM) {\n        type = find_enum_argument(\"--type\", nullptr, diagram_types, argc, argv);\n        assert(type != DiagramTypes::NOT_A_DIAGRAM);\n    }\n    return type;\n}\n\nbool _read_tick(int argc, const char **argv, uint64_t *tick, uint64_t *tick_start, uint64_t *tick_num) {\n    *tick = 0;\n    *tick_start = 0;\n    *tick_num = UINT64_MAX;\n    if (find_argument(\"--tick\", argc, argv) == nullptr) {\n        return false;\n    }\n\n    std::string tick_str = find_argument(\"--tick\", argc, argv);\n    auto t = tick_str.find(':');\n    if (t != 0 && t != std::string::npos) {\n        *tick_start = parse_exact_uint64_t_from_string(tick_str.substr(0, t));\n        uint64_t tick_end = parse_exact_uint64_t_from_string(tick_str.substr(t + 1));\n        if (tick_end <= *tick_start) {\n            throw std::invalid_argument(\"tick_end <= tick_start\");\n        }\n        *tick_num = tick_end - *tick_start;\n        *tick = *tick_start;\n    } else {\n        *tick = find_int64_argument(\"--tick\", 0, 0, INT64_MAX, argc, argv);\n        *tick_num = 1;\n        *tick_start = *tick;\n    }\n    return true;\n}\n\nint stim::command_diagram(int argc, const char **argv) {\n    check_for_unknown_arguments(\n        {\n            \"--remove_noise\",\n            \"--type\",\n            \"--tick\",\n            \"--filter_coords\",\n            \"--in\",\n            \"--out\",\n        },\n        {},\n        \"diagram\",\n        argc,\n        argv);\n    RaiiFile in(find_open_file_argument(\"--in\", stdin, \"rb\", argc, argv));\n    auto out_stream = find_output_stream_argument(\"--out\", true, argc, argv);\n    auto &out = out_stream.stream();\n\n    DiagramTypes type = _read_diagram_type(argc, argv);\n\n    uint64_t tick = 0;\n    uint64_t tick_start = 0;\n    uint64_t tick_num = UINT64_MAX;\n    bool has_tick_arg = _read_tick(argc, argv, &tick, &tick_start, &tick_num);\n\n    if (type == DiagramTypes::TIMELINE_TEXT) {\n        auto circuit = _read_circuit(in, argc, argv);\n        out << DiagramTimelineAsciiDrawer::make_diagram(circuit);\n    } else if (type == DiagramTypes::TIMELINE_SVG) {\n        auto circuit = _read_circuit(in, argc, argv);\n        auto coord_filter = _read_coord_filter(argc, argv);\n        DiagramTimelineSvgDrawer::make_diagram_write_to(\n            circuit, out, tick_start, tick_num, DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE, coord_filter);\n    } else if (type == DiagramTypes::TIME_SLICE_SVG) {\n        auto circuit = _read_circuit(in, argc, argv);\n        auto coord_filter = _read_coord_filter(argc, argv);\n        DiagramTimelineSvgDrawer::make_diagram_write_to(\n            circuit, out, tick_start, tick_num, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_SLICE, coord_filter);\n    } else if (type == DiagramTypes::TIME_SLICE_PLUS_DETECTOR_SLICE_SVG) {\n        auto circuit = _read_circuit(in, argc, argv);\n        auto coord_filter = _read_coord_filter(argc, argv);\n        DiagramTimelineSvgDrawer::make_diagram_write_to(\n            circuit,\n            out,\n            tick_start,\n            tick_num,\n            DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE,\n            coord_filter);\n    } else if (type == DiagramTypes::TIMELINE_3D) {\n        auto circuit = _read_circuit(in, argc, argv);\n        DiagramTimeline3DDrawer::circuit_to_basic_3d_diagram(circuit).to_gltf_scene().to_json().write(out);\n    } else if (type == DiagramTypes::TIMELINE_3D_HTML) {\n        auto circuit = _read_circuit(in, argc, argv);\n        std::stringstream tmp_out;\n        DiagramTimeline3DDrawer::circuit_to_basic_3d_diagram(circuit).to_gltf_scene().to_json().write(tmp_out);\n        write_html_viewer_for_gltf_data(tmp_out.str(), out);\n    } else if (type == DiagramTypes::INTERACTIVE_HTML) {\n        auto circuit = _read_circuit(in, argc, argv);\n        write_crumble_html_with_preloaded_circuit(circuit, out);\n    } else if (type == DiagramTypes::MATCH_GRAPH_3D) {\n        auto dem = _read_dem(in, argc, argv);\n        dem_match_graph_to_basic_3d_diagram(dem).to_gltf_scene().to_json().write(out);\n    } else if (type == DiagramTypes::MATCH_GRAPH_3D_HTML) {\n        auto dem = _read_dem(in, argc, argv);\n        std::stringstream tmp_out;\n        dem_match_graph_to_basic_3d_diagram(dem).to_gltf_scene().to_json().write(tmp_out);\n        write_html_viewer_for_gltf_data(tmp_out.str(), out);\n    } else if (type == DiagramTypes::MATCH_GRAPH_SVG) {\n        auto dem = _read_dem(in, argc, argv);\n        dem_match_graph_to_svg_diagram_write_to(dem, out);\n    } else if (type == DiagramTypes::DETECTOR_SLICE_TEXT) {\n        if (!has_tick_arg) {\n            throw std::invalid_argument(\"Must specify --tick=# with --type=detector-slice-text\");\n        }\n        auto coord_filter = _read_coord_filter(argc, argv);\n        auto circuit = _read_circuit(in, argc, argv);\n        out << DetectorSliceSet::from_circuit_ticks(circuit, (uint64_t)tick, 1, coord_filter);\n    } else if (type == DiagramTypes::DETECTOR_SLICE_SVG) {\n        auto coord_filter = _read_coord_filter(argc, argv);\n        auto circuit = _read_circuit(in, argc, argv);\n        DetectorSliceSet::from_circuit_ticks(circuit, tick_start, tick_num, coord_filter).write_svg_diagram_to(out);\n    } else {\n        throw std::invalid_argument(\"Unknown type\");\n    }\n    out << '\\n';\n\n    return EXIT_SUCCESS;\n}\n\nSubCommandHelp stim::command_diagram_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"diagram\";\n    result.description = clean_doc_string(R\"PARAGRAPH(\n        Produces various kinds of diagrams.\n    )PARAGRAPH\");\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example_circuit.stim\n            H 0\n            CNOT 0 1\n\n            >>> stim diagram \\\n                --in example_circuit.stim \\\n                --type timeline-text\n            q0: -H-@-\n                   |\n            q1: ---X-\n        )PARAGRAPH\"));\n\n    result.examples.push_back(clean_doc_string(\n        R\"PARAGRAPH(\n        >>> # Making a video of detector slices moving around\n\n        >>> # First, make a circuit to animate.\n        >>> stim gen \\\n                --code surface_code \\\n                --task rotated_memory_x \\\n                --distance 5 \\\n                --rounds 100 \\\n                > surface_code.stim\n\n        >>> # Second, use gnu-parallel and stim diagram to make video frames.\n        >>> parallel stim diagram \\\n            --filter_coords 2,2:4,2 \\\n            --type detector-slice-svg \\\n            --tick {} \\\n            --in surface_code.stim \\\n            --out video_frame_{}.svg \\\n            ::: {0050..0150}\n\n        >>> # Third, use ffmpeg to turn the frames into a GIF.\n        >>> # (note: the complex filter argument is optional; it turns the background white)\n        >>> ffmpeg output_animation.gif \\\n            -framerate 5 \\\n            -pattern_type glob -i 'video_frame_*.svg' \\\n            -pix_fmt rgb8 \\\n            -filter_complex \"[0]split=2[bg][fg];[bg]drawbox=c=white@1:t=fill[bg];[bg][fg]overlay=format=auto\"\n\n        >>> # Alternatively, make an MP4 video instead of a GIF.\n        >>> ffmpeg output_video.mp4 \\\n            -framerate 5 \\\n            -pattern_type glob -i 'video_frame_*.svg' \\\n            -vf scale=1024:-1 \\\n            -c:v libx264 \\\n            -vf format=yuv420p \\\n            -vf \"pad=ceil(iw/2)*2:ceil(ih/2)*2\"\n    )PARAGRAPH\",\n        true));\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--remove_noise\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Removes noise from the input before turning it into a diagram.\n\n            For example, if the input is a noisy circuit and you aren't\n            interested in the details of the noise but rather in the structure\n            of the circuit, you can specify this flag in order to filter out\n            the noise.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--tick\",\n            \"int | int:int\",\n            \"none\",\n            {\"[none]\", \"int\", \"int-int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies that the diagram should apply to a specific TICK or range\n            of TICKS from the input circuit.\n\n            To specify a single tick, pass an integer like `--tick=5`.\n            To specify a range, pass two integers separated by a colon like\n            `--tick=start:end`. Note that the range is half open.\n\n            In detector and time slice diagrams, `--tick` identifies which ticks\n            to include in the diagram. Note that `--tick=0` is the very\n            beginning of the circuit and `--tick=1` is the instant of the first\n            TICK instruction.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--filter_coords\",\n            \"(float.seperatedby(',') | L# | D#).seperatedby(':')\",\n            \"\",\n            {\"[none]\", \"(float.seperatedby(',') | L# | D#).seperatedby(':')\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies coordinate filters that determine what appears in the diagram.\n\n            A coordinate is a double precision floating point number.\n            A point is a tuple of coordinates.\n            The coordinates of a point are separate by commas (',').\n            A filter is a set of points.\n            Points are separated by colons (':').\n\n            Filters can also be set to specific detector or observable indices,\n            like D0 or L0.\n\n            Example:\n                --filter-coords 2,3:4,5,6\n                    In a detector slice diagram this means that only detectors whose\n                    first two coordinates are (2,3), or whose first three coordinate\n                    are (4,5,6), should be included in the diagram.\n                --filter-coords L0\n                    In a detector slice diagram this means that logical observable 0\n                    should be included. Logical observables are only included if\n                    explicitly filtered in.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--type\",\n            \"name\",\n            \"\",\n            {\"name\"},\n            clean_doc_string(R\"PARAGRAPH(\n            The type of diagram to make.\n\n            The available diagram types are:\n\n            \"timeline-text\": Produces an ASCII text diagram of the operations\n                performed by a circuit over time. The qubits are laid out into\n                a line top to bottom, and time advances left to right. The input\n                object should be a stim circuit.\n\n                INPUT MUST BE A CIRCUIT.\n\n            \"timeline-svg\": Produces an SVG image diagram of the operations\n                performed by a circuit over time. The qubits are laid out into\n                a line top to bottom, and time advances left to right. The input\n                object should be a stim circuit.\n\n                INPUT MUST BE A CIRCUIT.\n\n            \"timeline-3d\": Produces a 3d model, in GLTF format, of the\n                operations applied by a stim circuit over time.\n\n                GLTF files can be opened with a variety of programs, or\n                opened online in viewers such as\n                https://gltf-viewer.donmccurdy.com/ .\n\n                INPUT MUST BE A CIRCUIT.\n\n            \"timeline-3d-html\": A web page containing a 3d model\n                viewer of the operations applied by a stim circuit\n                over time.\n\n                INPUT MUST BE A CIRCUIT.\n\n            \"matchgraph-svg\": An image of the decoding graph of a detector\n                error model. Red lines are errors crossing a logical observable.\n\n                INPUT MUST BE A DETECTOR ERROR MODEL OR A CIRCUIT.\n\n            \"matchgraph-3d\": A 3d model, in GLTF format, of the\n                decoding graph of a detector error model. Red lines are\n                errors crossing a logical observable.\n\n                GLTF files can be opened with a variety of programs, or\n                opened online in viewers such as\n                https://gltf-viewer.donmccurdy.com/ .\n\n                INPUT MUST BE A DETECTOR ERROR MODEL OR A CIRCUIT.\n\n            \"matchgraph-3d-html\": A web page containing a 3d model\n                viewer of the decoding graph of a detector error\n                model or circuit.\n\n                INPUT MUST BE A DETECTOR ERROR MODEL OR A CIRCUIT.\n\n            \"detslice-text\": An ASCII diagram of the stabilizers\n                that detectors declared by the circuit correspond to\n                during the TICK instruction identified by the `tick`\n                argument.\n\n                INPUT MUST BE A CIRCUIT.\n\n            \"detslice-svg\": An SVG image of the stabilizers\n                that detectors declared by the circuit correspond to\n                during the TICK instruction identified by the `tick`\n                argument. For example, a detector slice diagram of a\n                CSS surface code circuit during the TICK between a\n                measurement layer and a reset layer will produce the\n                usual diagram of a surface code. Uses the Pauli color convention\n                XYZ=RGB.\n\n                INPUT MUST BE A CIRCUIT.\n\n            \"timeslice-svg\": An SVG image of the operations that a circuit\n                applies during the specified tick or range of ticks.\n\n                INPUT MUST BE A CIRCUIT.\n\n            \"detslice-with-ops-svg\": An SVG image of the operations that a\n                circuit applies during the specified tick or range of ticks,\n                combined with the detector slices after those operations are\n                applied.\n\n                INPUT MUST BE A CIRCUIT.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in\",\n            \"filepath\",\n            \"{stdin}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Where to read the object to diagram from.\n\n            By default, the object is read from stdin. When `--in $FILEPATH` is\n            specified, the object is instead read from the file at $FILEPATH.\n\n            The expected type of object depends on the type of diagram.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out\",\n            \"filepath\",\n            \"{stdout}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses where to write the diagram to.\n\n            By default, the output is written to stdout. When `--out $FILEPATH`\n            is specified, the output is instead written to the file at $FILEPATH.\n\n            The type of output produced depends on the type of diagram.\n        )PARAGRAPH\"),\n        });\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_diagram.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_DIAGRAM_H\n#define _STIM_CMD_COMMAND_DIAGRAM_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_diagram(int argc, const char **argv);\nSubCommandHelp command_diagram_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_diagram.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_diagram.pybind.h\"\n\n#include \"stim/cmd/command_help.h\"\n#include \"stim/dem/detector_error_model_target.pybind.h\"\n#include \"stim/diagram/base64.h\"\n#include \"stim/diagram/crumble.h\"\n#include \"stim/diagram/detector_slice/detector_slice_set.h\"\n#include \"stim/diagram/graph/match_graph_3d_drawer.h\"\n#include \"stim/diagram/graph/match_graph_svg_drawer.h\"\n#include \"stim/diagram/timeline/timeline_3d_drawer.h\"\n#include \"stim/diagram/timeline/timeline_ascii_drawer.h\"\n#include \"stim/diagram/timeline/timeline_svg_drawer.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\nusing namespace stim_draw_internal;\n\npybind11::class_<DiagramHelper> stim_pybind::pybind_diagram(pybind11::module &m) {\n    auto c = pybind11::class_<DiagramHelper>(\n        m,\n        \"_DiagramHelper\",\n        clean_doc_string(R\"DOC(\n            A helper class for displaying diagrams in IPython notebooks.\n\n            To write the diagram's contents to a file (for example, to write an\n            SVG image to an SVG file), use `print(diagram, file=file)`.\n        )DOC\")\n            .data());\n\n    return c;\n}\n\nstd::string escape_html_for_srcdoc(std::string_view src) {\n    // From https://stackoverflow.com/a/9907752\n    std::stringstream dst;\n    for (char ch : src) {\n        switch (ch) {\n            case '&':\n                dst << \"&amp;\";\n                break;\n            case '\\'':\n                dst << \"&apos;\";\n                break;\n            case '\"':\n                dst << \"&quot;\";\n                break;\n            case '<':\n                dst << \"&lt;\";\n                break;\n            case '>':\n                dst << \"&gt;\";\n                break;\n            default:\n                dst << ch;\n                break;\n        }\n    }\n    return dst.str();\n}\n\npybind11::object diagram_as_html(const DiagramHelper &self) {\n    std::string output = \"None\";\n    if (self.type == DiagramType::DIAGRAM_TYPE_TEXT) {\n        return pybind11::cast(\"<pre>\" + self.content + \"</pre>\");\n    }\n    if (self.type == DiagramType::DIAGRAM_TYPE_SVG_HTML) {\n        // Wrap the SVG image into an img tag.\n        std::stringstream out;\n        out << R\"HTML(<img style=\"max-width: 100%; max-height: 100%\" src=\"data:image/svg+xml;base64,)HTML\";\n        write_data_as_base64_to(self.content, out);\n        out << R\"HTML(\"/>)HTML\";\n        output = out.str();\n    } else if (self.type == DiagramType::DIAGRAM_TYPE_SVG) {\n        // Github's Jupyter notebook preview will fail to show SVG images if they are wrapped in HTML.\n        // So, for SVG diagrams, we refuse to return an html repr in this case.\n        return pybind11::none();\n    }\n    if (self.type == DiagramType::DIAGRAM_TYPE_GLTF) {\n        std::stringstream out;\n        write_html_viewer_for_gltf_data(self.content, out);\n        output = out.str();\n    }\n    if (self.type == DiagramType::DIAGRAM_TYPE_HTML) {\n        output = self.content;\n    }\n    if (output == \"None\") {\n        return pybind11::none();\n    }\n\n    // Wrap the output into an iframe.\n    // In a Jupyter notebook this is very important, because it prevents output\n    // cells from seeing each others' elements when finding elements by id.\n    // Because, for some insane reason, Jupyter notebooks don't isolate the cells\n    // from each other by default! Colab does the right thing at least...\n    std::string framed =\n        R\"HTML(<iframe style=\"width: 100%; height: 300px; overflow: hidden; resize: both; border: 1px dashed gray;\" frameBorder=\"0\" srcdoc=\")HTML\" +\n        escape_html_for_srcdoc(output) + R\"HTML(\"></iframe>)HTML\";\n    return pybind11::cast(framed);\n}\n\nvoid stim_pybind::pybind_diagram_methods(pybind11::module &m, pybind11::class_<DiagramHelper> &c) {\n    c.def(\"_repr_html_\", &diagram_as_html);\n    c.def(\"_repr_svg_\", [](const DiagramHelper &self) -> pybind11::object {\n        if (self.type != DiagramType::DIAGRAM_TYPE_SVG) {\n            return pybind11::none();\n        }\n        return pybind11::cast(self.content);\n    });\n    c.def(\"_repr_pretty_\", [](const DiagramHelper &self, pybind11::object p, pybind11::object cycle) -> void {\n        pybind11::getattr(p, \"text\")(self.content);\n    });\n    c.def(\"__repr__\", [](const DiagramHelper &self) -> std::string {\n        std::stringstream ss;\n        ss << \"<A stim._DiagramHelper containing \";\n        switch (self.type) {\n            case DiagramType::DIAGRAM_TYPE_GLTF:\n                ss << \"a GLTF 3d model\";\n                break;\n            case DiagramType::DIAGRAM_TYPE_SVG:\n                ss << \"an SVG image\";\n                break;\n            case DiagramType::DIAGRAM_TYPE_TEXT:\n                ss << \"text\";\n                break;\n            case DiagramType::DIAGRAM_TYPE_HTML:\n                ss << \"an HTML document\";\n                break;\n            case DiagramType::DIAGRAM_TYPE_SVG_HTML:\n                ss << \"an HTML SVG image viewer\";\n                break;\n            default:\n                ss << \"???\";\n        }\n        ss << \" that will display inline in Jupyter notebooks. Use 'str' or 'print' to access the contents as text.>\";\n        return ss.str();\n    });\n    c.def(\"__str__\", [](const DiagramHelper &self) -> pybind11::object {\n        if (self.type == DiagramType::DIAGRAM_TYPE_SVG_HTML) {\n            return diagram_as_html(self);\n        }\n        return pybind11::cast(self.content);\n    });\n}\n\nDiagramHelper stim_pybind::dem_diagram(const DetectorErrorModel &dem, std::string_view type) {\n    if (type == \"matchgraph-svg\" || type == \"match-graph-svg\" || type == \"match-graph-svg-html\" ||\n        type == \"matchgraph-svg-html\") {\n        std::stringstream out;\n        dem_match_graph_to_svg_diagram_write_to(dem, out);\n        DiagramType d_type =\n            type.find(\"html\") != std::string::npos ? DiagramType::DIAGRAM_TYPE_SVG_HTML : DiagramType::DIAGRAM_TYPE_SVG;\n        return DiagramHelper{d_type, out.str()};\n    } else if (type == \"matchgraph-3d\" || type == \"match-graph-3d\") {\n        std::stringstream out;\n        dem_match_graph_to_basic_3d_diagram(dem).to_gltf_scene().to_json().write(out);\n        return DiagramHelper{DiagramType::DIAGRAM_TYPE_GLTF, out.str()};\n    } else if (type == \"matchgraph-3d-html\" || type == \"match-graph-3d-html\") {\n        std::stringstream out;\n        dem_match_graph_to_basic_3d_diagram(dem).to_gltf_scene().to_json().write(out);\n        std::stringstream out_html;\n        write_html_viewer_for_gltf_data(out.str(), out_html);\n        return DiagramHelper{DiagramType::DIAGRAM_TYPE_GLTF, out_html.str()};\n    } else {\n        std::stringstream ss;\n        ss << \"Unrecognized diagram type: \" << type;\n        throw std::invalid_argument(ss.str());\n    }\n}\n\nCoordFilter item_to_filter_single(const pybind11::handle &obj) {\n    if (pybind11::isinstance<ExposedDemTarget>(obj)) {\n        CoordFilter filter;\n        filter.exact_target = pybind11::cast<ExposedDemTarget>(obj).internal();\n        filter.use_target = true;\n        return filter;\n    }\n\n    try {\n        std::string_view text = pybind11::cast<std::string_view>(obj);\n        if (text.size() > 1 && text[0] == 'D') {\n            CoordFilter filter;\n            filter.exact_target = DemTarget::relative_detector_id(parse_exact_uint64_t_from_string(text.substr(1)));\n            filter.use_target = true;\n            return filter;\n        }\n        if (text.size() > 1 && text[0] == 'L') {\n            CoordFilter filter;\n            filter.exact_target = DemTarget::observable_id(parse_exact_uint64_t_from_string(text.substr(1)));\n            filter.use_target = true;\n            return filter;\n        }\n    } catch (const pybind11::cast_error &) {\n    } catch (const std::invalid_argument &) {\n    }\n\n    CoordFilter filter;\n    for (const auto &c : obj) {\n        filter.coordinates.push_back(pybind11::cast<double>(c));\n    }\n    return filter;\n}\n\nstd::vector<CoordFilter> item_to_filter_multi(const pybind11::object &obj) {\n    if (obj.is_none()) {\n        return {CoordFilter{}};\n    }\n\n    try {\n        return {item_to_filter_single(obj)};\n    } catch (const pybind11::cast_error &) {\n    } catch (const std::invalid_argument &) {\n    }\n\n    std::vector<CoordFilter> filters;\n    for (const auto &filter_case : obj) {\n        filters.push_back(item_to_filter_single(filter_case));\n    }\n    return filters;\n}\n\nDiagramHelper stim_pybind::circuit_diagram(\n    const Circuit &circuit,\n    std::string_view type,\n    const pybind11::object &tick,\n    const pybind11::object &rows,\n    const pybind11::object &filter_coords_obj) {\n    std::vector<CoordFilter> filter_coords;\n    try {\n        filter_coords = item_to_filter_multi(filter_coords_obj);\n    } catch (const std::exception &_) {\n        throw std::invalid_argument(\"filter_coords wasn't an Iterable[stim.DemTarget | Iterable[float]].\");\n    }\n\n    size_t num_rows = 0;\n    if (!rows.is_none()) {\n        num_rows = pybind11::cast<size_t>(rows);\n    }\n\n    uint64_t tick_min;\n    uint64_t num_ticks;\n    if (tick.is_none()) {\n        tick_min = 0;\n        num_ticks = UINT64_MAX;\n    } else if (pybind11::isinstance(tick, pybind11::module::import(\"builtins\").attr(\"range\"))) {\n        tick_min = pybind11::cast<uint64_t>(tick.attr(\"start\"));\n        auto tick_stop = pybind11::cast<uint64_t>(tick.attr(\"stop\"));\n        auto tick_step = pybind11::cast<uint64_t>(tick.attr(\"step\"));\n        if (tick_step != 1) {\n            throw std::invalid_argument(\"tick.step != 1\");\n        }\n        if (tick_stop <= tick_min) {\n            throw std::invalid_argument(\"tick.stop <= tick.start\");\n        }\n        num_ticks = tick_stop - tick_min;\n    } else {\n        tick_min = pybind11::cast<uint64_t>(tick);\n        num_ticks = 1;\n    }\n\n    if (type == \"timeline-text\") {\n        if (!tick.is_none()) {\n            throw std::invalid_argument(\"`tick` isn't used with type='timeline-text'\");\n        }\n        std::stringstream out;\n        out << DiagramTimelineAsciiDrawer::make_diagram(circuit);\n        return DiagramHelper{DiagramType::DIAGRAM_TYPE_TEXT, out.str()};\n    } else if (type == \"timeline-svg\" || type == \"timeline\" || type == \"timeline-svg-html\" || type == \"timeline-html\") {\n        std::stringstream out;\n        DiagramTimelineSvgDrawer::make_diagram_write_to(\n            circuit, out, tick_min, num_ticks, DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE, filter_coords);\n        DiagramType d_type =\n            type.find(\"html\") != std::string::npos ? DiagramType::DIAGRAM_TYPE_SVG_HTML : DiagramType::DIAGRAM_TYPE_SVG;\n        return DiagramHelper{d_type, out.str()};\n    } else if (\n        type == \"time-slice-svg\" || type == \"timeslice-svg\" || type == \"timeslice-html\" ||\n        type == \"timeslice-svg-html\" || type == \"time-slice-html\" || type == \"time-slice-svg-html\" ||\n        type == \"timeslice\" || type == \"time-slice\") {\n        std::stringstream out;\n        DiagramTimelineSvgDrawer::make_diagram_write_to(\n            circuit,\n            out,\n            tick_min,\n            num_ticks,\n            DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_SLICE,\n            filter_coords,\n            num_rows);\n        DiagramType d_type =\n            type.find(\"html\") != std::string::npos ? DiagramType::DIAGRAM_TYPE_SVG_HTML : DiagramType::DIAGRAM_TYPE_SVG;\n        return DiagramHelper{d_type, out.str()};\n    } else if (\n        type == \"detslice-svg\" || type == \"detslice\" || type == \"detslice-html\" || type == \"detslice-svg-html\" ||\n        type == \"detector-slice-svg\" || type == \"detector-slice\") {\n        std::stringstream out;\n        DetectorSliceSet::from_circuit_ticks(circuit, tick_min, num_ticks, filter_coords)\n            .write_svg_diagram_to(out, num_rows);\n        DiagramType d_type =\n            type.find(\"html\") != std::string::npos ? DiagramType::DIAGRAM_TYPE_SVG_HTML : DiagramType::DIAGRAM_TYPE_SVG;\n        return DiagramHelper{d_type, out.str()};\n    } else if (\n        type == \"detslice-with-ops\" || type == \"detslice-with-ops-svg\" || type == \"detslice-with-ops-html\" ||\n        type == \"detslice-with-ops-svg-html\" || type == \"time+detector-slice-svg\") {\n        std::stringstream out;\n        DiagramTimelineSvgDrawer::make_diagram_write_to(\n            circuit,\n            out,\n            tick_min,\n            num_ticks,\n            DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE,\n            filter_coords,\n            num_rows);\n        DiagramType d_type =\n            type.find(\"html\") != std::string::npos ? DiagramType::DIAGRAM_TYPE_SVG_HTML : DiagramType::DIAGRAM_TYPE_SVG;\n        return DiagramHelper{d_type, out.str()};\n    } else if (type == \"timeline-3d\") {\n        std::stringstream out;\n        DiagramTimeline3DDrawer::circuit_to_basic_3d_diagram(circuit).to_gltf_scene().to_json().write(out);\n        return DiagramHelper{DiagramType::DIAGRAM_TYPE_GLTF, out.str()};\n    } else if (type == \"timeline-3d-html\") {\n        std::stringstream out;\n        DiagramTimeline3DDrawer::circuit_to_basic_3d_diagram(circuit).to_gltf_scene().to_json().write(out);\n        std::stringstream out_html;\n        write_html_viewer_for_gltf_data(out.str(), out_html);\n        return DiagramHelper{DiagramType::DIAGRAM_TYPE_GLTF, out_html.str()};\n    } else if (type == \"detslice-text\" || type == \"detector-slice-text\") {\n        std::stringstream out;\n        DetectorSliceSet::from_circuit_ticks(circuit, tick_min, num_ticks, filter_coords).write_text_diagram_to(out);\n        return DiagramHelper{DiagramType::DIAGRAM_TYPE_TEXT, out.str()};\n    } else if (type == \"interactive\" || type == \"interactive-html\") {\n        std::stringstream out;\n        write_crumble_html_with_preloaded_circuit(circuit, out);\n        return DiagramHelper{DiagramType::DIAGRAM_TYPE_HTML, out.str()};\n    } else if (\n        type == \"match-graph-svg\" || type == \"matchgraph-svg\" || type == \"matchgraph-svg-html\" ||\n        type == \"matchgraph-html\" || type == \"match-graph-svg-html\" || type == \"match-graph-html\" ||\n        type == \"match-graph-3d\" || type == \"matchgraph-3d\" || type == \"match-graph-3d-html\" ||\n        type == \"matchgraph-3d-html\") {\n        DetectorErrorModel dem;\n        try {\n            // By default, try to decompose the errors.\n            dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 1, false, false);\n        } catch (const std::invalid_argument &) {\n            // If any decomposition fails, don't decompose at all.\n            dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, false, true, false, 1, false, false);\n        }\n        return dem_diagram(dem, type);\n    } else {\n        std::stringstream ss;\n        ss << \"Unrecognized diagram type: '\";\n        ss << type << \"'\";\n        throw std::invalid_argument(ss.str());\n    }\n}\n"
  },
  {
    "path": "src/stim/cmd/command_diagram.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_CMD_COMMAND_DIAGRAM_PYBIND_H\n#define _STIM_CMD_COMMAND_DIAGRAM_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/dem/detector_error_model.h\"\n\nnamespace stim_pybind {\n\nenum class DiagramType {\n    DIAGRAM_TYPE_GLTF,\n    DIAGRAM_TYPE_SVG,\n    DIAGRAM_TYPE_TEXT,\n    DIAGRAM_TYPE_HTML,\n    DIAGRAM_TYPE_SVG_HTML,\n};\n\nstruct DiagramHelper {\n    DiagramType type;\n    std::string content;\n};\n\npybind11::class_<DiagramHelper> pybind_diagram(pybind11::module &m);\nvoid pybind_diagram_methods(pybind11::module &m, pybind11::class_<DiagramHelper> &c);\nDiagramHelper dem_diagram(const stim::DetectorErrorModel &dem, std::string_view type);\nDiagramHelper circuit_diagram(\n    const stim::Circuit &circuit,\n    std::string_view type,\n    const pybind11::object &tick,\n    const pybind11::object &rows,\n    const pybind11::object &filter_coords_obj);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_diagram.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/main_namespaced.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(command_diagram, run_captured_stim_main) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\n                \"diagram\",\n                \"--type\",\n                \"timeline-text\",\n            },\n            R\"input(\n                H 0\n                CNOT 0 1\n            )input\")),\n        trim(R\"output(\nq0: -H-@-\n       |\nq1: ---X-\n            )output\"));\n}\n\nTEST(command_diagram, run_captured_stim_main_detector_slice) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"diagram\", \"--type\", \"detector-slice-text\", \"--tick\", \"1\"},\n            R\"input(\n                H 0\n                CNOT 0 1 0 2\n                TICK\n                M 0 1 2\n                DETECTOR(4,5) rec[-1] rec[-2]\n                DETECTOR(6) rec[-2] rec[-3]\n            )input\")),\n        trim(R\"output(\nq0: -------Z:D1-\n           |\nq1: -Z:D0--Z:D1-\n     |\nq2: -Z:D0-------\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"diagram\", \"--type\", \"detector-slice-text\", \"--tick\", \"1\", \"--filter_coords\", \"4\"},\n            R\"input(\n                H 0\n                CNOT 0 1 0 2\n                TICK\n                M 0 1 2\n                DETECTOR(4,5) rec[-1] rec[-2]\n                DETECTOR(6) rec[-2] rec[-3]\n            )input\")),\n        trim(R\"output(\nq0: ------\n\nq1: -Z:D0-\n     |\nq2: -Z:D0-\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"diagram\", \"--type\", \"detector-slice-text\", \"--tick\", \"1\", \"--filter_coords\", \"5,6,7:6:7,8\"},\n            R\"input(\n                H 0\n                CNOT 0 1 0 2\n                TICK\n                M 0 1 2\n                DETECTOR(4,5) rec[-1] rec[-2]\n                DETECTOR(6) rec[-2] rec[-3]\n            )input\")),\n        trim(R\"output(\nq0: -Z:D1-\n     |\nq1: -Z:D1-\n\nq2: ------\n            )output\"));\n}\n\nTEST(command_diagram, run_captured_stim_main_timeline_ticking) {\n    auto circuit = R\"input(\n        R 0 1\n        TICK\n        H 0\n        CNOT 0 1\n        TICK\n        S 0\n        TICK\n        H 0\n        M 0 1\n    )input\";\n    auto result_txt = run_captured_stim_main({\"diagram\", \"--type\", \"timeline-text\"}, circuit);\n    ASSERT_EQ(\"\\n\" + result_txt, R\"DIAGRAM(\n       /-\\   /--------\\\nq0: -R-H-@-S-H-M:rec[0]-\n         |\nq1: -R---X-----M:rec[1]-\n       \\-/   \\--------/\n)DIAGRAM\");\n\n    auto result = run_captured_stim_main({\"diagram\", \"--type\", \"timeline-svg\"}, circuit);\n    expect_string_is_identical_to_saved_file(result, \"command_diagram_timeline.svg\");\n\n    result = run_captured_stim_main({\"diagram\", \"--type\", \"timeline-svg\", \"--tick\", \"0\"}, circuit);\n    expect_string_is_identical_to_saved_file(result, \"command_diagram_timeline_tick0.svg\");\n\n    result = run_captured_stim_main({\"diagram\", \"--type\", \"timeline-svg\", \"--tick\", \"1\"}, circuit);\n    expect_string_is_identical_to_saved_file(result, \"command_diagram_timeline_tick1.svg\");\n\n    result = run_captured_stim_main({\"diagram\", \"--type\", \"timeline-svg\", \"--tick\", \"2\"}, circuit);\n    expect_string_is_identical_to_saved_file(result, \"command_diagram_timeline_tick2.svg\");\n\n    result = run_captured_stim_main({\"diagram\", \"--type\", \"timeline-svg\", \"--tick\", \"1:3\"}, circuit);\n    expect_string_is_identical_to_saved_file(result, \"command_diagram_timeline_tick1_3.svg\");\n}\n\nTEST(command_diagram, run_captured_stim_main_works_various_arguments) {\n    std::vector<std::string> diagram_types{\n        \"timeline-text\",\n        \"timeline-svg\",\n        \"timeline-3d\",\n        \"timeline-3d-html\",\n        \"match-graph-svg\",\n        \"match-graph-3d\",\n        \"match-graph-3d-html\",\n        \"detector-slice-text\",\n        \"detector-slice-svg\",\n        \"time-slice-svg\",\n        \"time+detector-slice-svg\",\n    };\n    for (const auto &type : diagram_types) {\n        auto actual = run_captured_stim_main(\n            {\n                \"diagram\",\n                \"--type\",\n                type.c_str(),\n                \"--tick\",\n                \"1:2\",\n            },\n            R\"input(\n            H 0\n            CNOT 0 1\n            X_ERROR(0.125) 0\n            TICK\n            M 0 1\n            DETECTOR(1, 2, 3) rec[-1] rec[-2]\n        )input\");\n        if (actual.find(\"[stderr\") != std::string::npos) {\n            EXPECT_TRUE(false) << actual;\n        }\n        EXPECT_NE(actual, \"\") << type;\n    }\n}\n\nTEST(command_diagram, warn_about_noiseless_match_graphs) {\n    auto result = run_captured_stim_main({\"diagram\", \"--type\", \"matchgraph-3d\", \"--remove_noise\"}, \"H 0\");\n    ASSERT_NE(result.find(\"--remove_noise is incompatible\"), std::string::npos);\n\n    result = run_captured_stim_main({\"diagram\", \"--type\", \"matchgraph-3d\"}, \"H 0\");\n    ASSERT_NE(\n        result.find(\"[stderr=Warning: the detector error model derived from the circuit had no errors\"),\n        std::string::npos);\n}\n"
  },
  {
    "path": "src/stim/cmd/command_explain_errors.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_explain_errors.h\"\n\n#include \"command_help.h\"\n#include \"stim/simulators/error_matcher.h\"\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\n\nint stim::command_explain_errors(int argc, const char **argv) {\n    check_for_unknown_arguments({\"--dem_filter\", \"--single\", \"--out\", \"--in\"}, {}, \"explain_errors\", argc, argv);\n\n    FILE *in = find_open_file_argument(\"--in\", stdin, \"rb\", argc, argv);\n    auto out_stream = find_output_stream_argument(\"--out\", true, argc, argv);\n    std::unique_ptr<DetectorErrorModel> dem_filter;\n    bool single = find_bool_argument(\"--single\", argc, argv);\n    bool has_filter = find_argument(\"--dem_filter\", argc, argv) != nullptr;\n    if (has_filter) {\n        FILE *filter_file = find_open_file_argument(\"--dem_filter\", stdin, \"rb\", argc, argv);\n        dem_filter =\n            std::unique_ptr<DetectorErrorModel>(new DetectorErrorModel(DetectorErrorModel::from_file(filter_file)));\n        fclose(filter_file);\n    }\n    auto circuit = Circuit::from_file(in);\n    if (in != stdin) {\n        fclose(in);\n    }\n    for (const auto &e : ErrorMatcher::explain_errors_from_circuit(circuit, dem_filter.get(), single)) {\n        out_stream.stream() << e << \"\\n\";\n    }\n    return EXIT_SUCCESS;\n}\n\nSubCommandHelp stim::command_explain_errors_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"explain_errors\";\n    result.description = clean_doc_string(R\"PARAGRAPH(\n        Find circuit errors that produce certain detection events.\n\n        Note that this command does not attempt to explain detection events\n        by using multiple errors. This command can only tell you how to\n        produce a set of detection events if they correspond to a specific\n        single physical error annotated into the circuit.\n\n        If you need to explain a detection event set using multiple errors,\n        use a decoder such as pymatching to find the set of single detector\n        error model errors that are needed and then use this command to\n        convert those specific errors into circuit errors.\n    )PARAGRAPH\");\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> stim gen \\\n                --code surface_code \\\n                --task rotated_memory_z \\\n                --distance 5 \\\n                --rounds 10 \\\n                --after_clifford_depolarization 0.001 \\\n                > example.stim\n            >>> echo \"error(1) D97 D102\" > example.dem\n\n            >>> stim explain_errors \\\n                --single \\\n                --in example.stim \\\n                --dem_filter example.dem\n            ExplainedError {\n                dem_error_terms: D97[coords 4,6,4] D102[coords 2,8,4]\n                CircuitErrorLocation {\n                    flipped_pauli_product: Z36[coords 3,7]\n                    Circuit location stack trace:\n                        (after 25 TICKs)\n                        at instruction #83 (a REPEAT 9 block) in the circuit\n                        after 2 completed iterations\n                        at instruction #12 (DEPOLARIZE2) in the REPEAT block\n                        at targets #3 to #4 of the instruction\n                        resolving to DEPOLARIZE2(0.001) 46[coords 2,8] 36[coords 3,7]\n                }\n            }\n        )PARAGRAPH\"));\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--dem_filter\",\n            \"filepath\",\n            \"01\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies a detector error model to use as a filter.\n\n            If `--dem_filter` isn't specified, an explanation of every single\n            set of symptoms that can be produced by the circuit.\n\n            If `--dem_filter` is specified, only explanations of the error\n            mechanisms present in the filter will be output. This is useful when\n            you are interested in a specific set of detection events.\n\n            The filter is specified as a detector error model file. See\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--single\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Explain using a single simple error instead of all possible errors.\n\n            When `--single` isn't specified, every single circuit error that\n            produces a specific detector error model is output as a possible\n            explanation of that error.\n\n            When `--single` is specified, only the simplest circuit error is\n            output. The \"simplest\" error is chosen by using heuristics such as\n            \"has fewer Pauli terms\" and \"happens earlier\".\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in\",\n            \"filepath\",\n            \"{stdin}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses the stim circuit file to read the explanatory circuit from.\n\n            By default, the circuit is read from stdin. When `--in $FILEPATH` is\n            specified, the circuit is instead read from the file at $FILEPATH.\n\n            The input should be a stim circuit. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out\",\n            \"filepath\",\n            \"{stdout}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses where to write the explanations to.\n\n            By default, the output is written to stdout. When `--out $FILEPATH`\n            is specified, the output is instead written to the file at $FILEPATH.\n\n            The output is in an arbitrary semi-human-readable format.\n        )PARAGRAPH\"),\n        });\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_explain_errors.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_EXPLAIN_ERRORS_H\n#define _STIM_CMD_COMMAND_EXPLAIN_ERRORS_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_explain_errors(int argc, const char **argv);\nSubCommandHelp command_explain_errors_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_explain_errors.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/main_namespaced.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(command_explain_errors, explain_errors) {\n    ASSERT_EQ(run_captured_stim_main({\"explain_errors\"}, \"\"), \"\");\n\n    RaiiTempNamedFile tmp(\"error(1) D0\\n\");\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"explain_errors\", \"--dem_filter\", tmp.path.c_str()}, R\"input(\nX_ERROR(0.25) 0 1\nM 0 1\nDETECTOR rec[-1]\nDETECTOR rec[-2]\n            )input\")),\n        trim(R\"output(\nExplainedError {\n    dem_error_terms: D0\n    CircuitErrorLocation {\n        flipped_pauli_product: X1\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #1 (X_ERROR) in the circuit\n            at target #2 of the instruction\n            resolving to X_ERROR(0.25) 1\n    }\n}\n            )output\"));\n}\n"
  },
  {
    "path": "src/stim/cmd/command_gen.cc",
    "content": "#include \"stim/cmd/command_gen.h\"\n\n#include \"command_help.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_color_code.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\n\nint stim::command_gen(int argc, const char **argv) {\n    std::map<std::string_view, GeneratedCircuit (*)(const CircuitGenParameters &)> code_name_to_func_map{\n        {\"color_code\", &generate_color_code_circuit},\n        {\"repetition_code\", &generate_rep_code_circuit},\n        {\"surface_code\", &generate_surface_code_circuit}};\n    std::vector<const char *> known_flags{\n        \"--after_clifford_depolarization\",\n        \"--after_reset_flip_probability\",\n        \"--code\",\n        \"--task\",\n        \"--before_measure_flip_probability\",\n        \"--before_round_data_depolarization\",\n        \"--distance\",\n        \"--out\",\n        \"--in\",\n        \"--rounds\",\n    };\n    std::vector<const char *> known_flags_deprecated{\n        \"--gen\",\n    };\n\n    check_for_unknown_arguments(known_flags, known_flags_deprecated, \"gen\", argc, argv);\n    const char *code_flag_name = find_argument(\"--gen\", argc, argv) ? \"--gen\" : \"--code\";\n    auto func = find_enum_argument(code_flag_name, nullptr, code_name_to_func_map, argc, argv);\n    CircuitGenParameters params(\n        (uint64_t)find_int64_argument(\"--rounds\", -1, 1, INT64_MAX, argc, argv),\n        (uint32_t)find_int64_argument(\"--distance\", -1, 2, 2047, argc, argv),\n        require_find_argument(\"--task\", argc, argv));\n    params.before_round_data_depolarization =\n        find_float_argument(\"--before_round_data_depolarization\", 0, 0, 1, argc, argv);\n    params.before_measure_flip_probability =\n        find_float_argument(\"--before_measure_flip_probability\", 0, 0, 1, argc, argv);\n    params.after_reset_flip_probability = find_float_argument(\"--after_reset_flip_probability\", 0, 0, 1, argc, argv);\n    params.after_clifford_depolarization = find_float_argument(\"--after_clifford_depolarization\", 0, 0, 1, argc, argv);\n    auto out_stream = find_output_stream_argument(\"--out\", true, argc, argv);\n    std::ostream &out = out_stream.stream();\n    out << \"# Generated \" << find_argument(code_flag_name, argc, argv) << \" circuit.\\n\";\n    out << \"# task: \" << params.task << \"\\n\";\n    out << \"# rounds: \" << params.rounds << \"\\n\";\n    out << \"# distance: \" << params.distance << \"\\n\";\n    out << \"# before_round_data_depolarization: \" << params.before_round_data_depolarization << \"\\n\";\n    out << \"# before_measure_flip_probability: \" << params.before_measure_flip_probability << \"\\n\";\n    out << \"# after_reset_flip_probability: \" << params.after_reset_flip_probability << \"\\n\";\n    out << \"# after_clifford_depolarization: \" << params.after_clifford_depolarization << \"\\n\";\n    out << \"# layout:\\n\";\n    auto generated = func(params);\n    out << generated.layout_str();\n    out << generated.hint_str;\n    out << generated.circuit;\n    out << \"\\n\";\n    return 0;\n}\n\nSubCommandHelp stim::command_gen_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"gen\";\n    result.description = clean_doc_string(R\"PARAGRAPH(\n        Generates example circuits.\n\n        The generated circuits include annotations for noise, detectors, logical\n        observables, the spatial locations of qubits, the spacetime locations\n        of detectors, and the inexorable passage of TICKs.\n\n        Note that the generated circuits are not intended to be sufficient for\n        research. They are really just examples to make it easier to get started\n        using Stim, so you can try things without having to first go through\n        the entire effort of making a correctly annotated quantum error\n        correction circuit.\n    )PARAGRAPH\");\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> stim gen \\\n                --code repetition_code \\\n                --task memory \\\n                --distance 3 \\\n                --rounds 100 \\\n                --after_clifford_depolarization 0.001\n            # Generated repetition_code circuit.\n            # task: memory\n            # rounds: 100\n            # distance: 3\n            # before_round_data_depolarization: 0\n            # before_measure_flip_probability: 0\n            # after_reset_flip_probability: 0\n            # after_clifford_depolarization: 0.001\n            # layout:\n            # L0 Z1 d2 Z3 d4\n            # Legend:\n            #     d# = data qubit\n            #     L# = data qubit with logical observable crossing\n            #     Z# = measurement qubit\n            R 0 1 2 3 4\n            TICK\n            CX 0 1 2 3\n            DEPOLARIZE2(0.001) 0 1 2 3\n            TICK\n            CX 2 1 4 3\n            DEPOLARIZE2(0.001) 2 1 4 3\n            TICK\n            MR 1 3\n            DETECTOR(1, 0) rec[-2]\n            DETECTOR(3, 0) rec[-1]\n            REPEAT 99 {\n                TICK\n                CX 0 1 2 3\n                DEPOLARIZE2(0.001) 0 1 2 3\n                TICK\n                CX 2 1 4 3\n                DEPOLARIZE2(0.001) 2 1 4 3\n                TICK\n                MR 1 3\n                SHIFT_COORDS(0, 1)\n                DETECTOR(1, 0) rec[-2] rec[-4]\n                DETECTOR(3, 0) rec[-1] rec[-3]\n            }\n            M 0 2 4\n            DETECTOR(1, 1) rec[-2] rec[-3] rec[-5]\n            DETECTOR(3, 1) rec[-1] rec[-2] rec[-4]\n            OBSERVABLE_INCLUDE(0) rec[-1]\n        )PARAGRAPH\"));\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--code\",\n            \"surface_code|repetition_code|color_code\",\n            \"\",\n            {\"surface_code|repetition_code|color_code\"},\n            clean_doc_string(R\"PARAGRAPH(\n            The error correcting code to use.\n\n            The available error correcting codes are:\n\n            `surface_code`\n                The surface code. A quantum code with a checkerboard pattern of\n                alternating X and Z stabilizers.\n            `repetition_code`\n                The repetition code. The simplest classical code.\n            `color_code`\n                The color code. A quantum code with a hexagonal pattern of\n                overlapping X and Z stabilizers.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--task\",\n            \"name\",\n            \"\",\n            {\"name\"},\n            clean_doc_string(R\"PARAGRAPH(\n            What the generated circuit should do; the experiment it should run.\n\n            Different error correcting codes support different tasks. The\n            available tasks are:\n\n            `memory` (repetition_code):\n                Initialize a logical `|0>`,\n                preserve it against noise for the given number of rounds,\n                then measure.\n            `rotated_memory_x` (surface_code):\n                Initialize a logical `|+>` in a rotated surface code,\n                preserve it against noise for the given number of rounds,\n                then measure in the X basis.\n            `rotated_memory_z` (surface_code):\n                Initialize a logical `|0>` in a rotated surface code,\n                preserve it against noise for the given number of rounds,\n                then measure in the X basis.\n            `unrotated_memory_x` (surface_code):\n                Initialize a logical `|+>` in an unrotated surface code,\n                preserve it against noise for the given number of rounds,\n                then measure in the Z basis.\n            `unrotated_memory_z` (surface_code):\n                Initialize a logical `|0>` in an unrotated surface code,\n                preserve it against noise for the given number of rounds,\n                then measure in the Z basis.\n            `memory_xyz` (color_code):\n                Initialize a logical `|0>`,\n                preserve it against noise for the given number of rounds,\n                then measure. Use a color code that alternates between measuring\n                X, then Y, then Z stabilizers.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--distance\",\n            \"int\",\n            \"\",\n            {\"int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            The minimum number of physical errors that cause a logical error.\n\n            The code distance determines how spatially large the generated\n            circuit has to be. Conventionally, the code distance specifically\n            refers to single-qubit errors between rounds instead of circuit\n            errors during rounds.\n\n            The distance must always be a positive integer. Different\n            codes/tasks may place additional constraints on the distance (e.g.\n            must be larger than 2 or must be odd or etc).\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--rounds\",\n            \"int\",\n            \"\",\n            {\"int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            The number of times the circuit's measurement qubits are measured.\n\n            The number of rounds must be an integer between 1 and a quintillion\n            (10^18). Different codes/tasks may place additional constraints on\n            the number of rounds (e.g. enough rounds to have measured all the\n            stabilizers at least once).\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--after_clifford_depolarization\",\n            \"probability\",\n            \"0\",\n            {\"[none]\", \"probability\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies a depolarizing noise level for unitary gates.\n\n            Defaults to 0 when not specified.\n            Must be a probability (a number between 0 and 1).\n\n            Adds a `DEPOLARIZE1(p)` operation after every single-qubit Clifford\n            operation, and a `DEPOLARIZE2(p)` noise operation after every\n            two-qubit Clifford operation. When set to 0 or not set, these noise\n            operations are not inserted at all.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--after_reset_flip_probability\",\n            \"probability\",\n            \"0\",\n            {\"[none]\", \"probability\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies a reset noise level.\n\n            Defaults to 0 when not specified.\n            Must be a probability (a number between 0 and 1).\n\n            Adds an `X_ERROR(p)` after `R` and `RY` operations, and a\n            `Z_ERROR(p)` after `RX` operations. When set to 0 or not set,\n            these noise operations are not inserted at all.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--before_measure_flip_probability\",\n            \"probability\",\n            \"0\",\n            {\"[none]\", \"probability\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies a measurement noise level.\n\n            Defaults to 0 when not specified.\n            Must be a probability (a number between 0 and 1).\n\n            Adds an `X_ERROR(p)` before `M` and `MY` operations, and a\n            `Z_ERROR(p)` before `MX` operations. When set to 0 or not set,\n            these noise operations are not inserted at all.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--before_round_data_depolarization\",\n            \"probability\",\n            \"0\",\n            {\"[none]\", \"probability\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies a quantum phenomenological noise level.\n\n            Defaults to 0 when not specified.\n            Must be a probability (a number between 0 and 1).\n\n            Adds a `DEPOLARIZE1(p)` operation to each data qubit at the start of\n            each round of stabilizer measurements. When set to 0 or not set,\n            these noise operations are not inserted at all.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out\",\n            \"filepath\",\n            \"{stdout}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses where to write the generated circuit to.\n\n            By default, the output is written to stdout. When `--out $FILEPATH`\n            is specified, the output is instead written to the file at $FILEPATH.\n\n            The output is a stim circuit. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n        )PARAGRAPH\"),\n        });\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_gen.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_GEN_H\n#define _STIM_CMD_COMMAND_GEN_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_gen(int argc, const char **argv);\nSubCommandHelp command_gen_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_gen.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <regex>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gen/gen_color_code.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/main_namespaced.test.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(command_gen, no_noise_no_detections, {\n    std::vector<uint32_t> distances{2, 3, 4, 5, 6, 7, 15};\n    std::vector<uint32_t> rounds{1, 2, 3, 4, 5, 6, 20};\n    std::map<std::string, std::pair<std::string, GeneratedCircuit (*)(const CircuitGenParameters &)>> funcs{\n        {\"color\", {\"memory_xyz\", &generate_color_code_circuit}},\n        {\"surface\", {\"unrotated_memory_x\", &generate_surface_code_circuit}},\n        {\"surface\", {\"unrotated_memory_z\", &generate_surface_code_circuit}},\n        {\"surface\", {\"rotated_memory_x\", &generate_surface_code_circuit}},\n        {\"surface\", {\"rotated_memory_z\", &generate_surface_code_circuit}},\n        {\"rep\", {\"memory\", &generate_rep_code_circuit}},\n    };\n    for (const auto &func : funcs) {\n        for (auto d : distances) {\n            for (auto r : rounds) {\n                if (func.first == \"color\" && (r < 2 || d % 2 == 0 || d < 3)) {\n                    continue;\n                }\n                CircuitGenParameters params(r, d, func.second.first);\n                auto circuit = func.second.second(params).circuit;\n                auto rng = INDEPENDENT_TEST_RNG();\n                auto [det_samples, obs_samples] = sample_batch_detection_events<W>(circuit, 256, rng);\n                EXPECT_FALSE(det_samples.data.not_zero() || obs_samples.data.not_zero())\n                    << \"d=\" << d << \", r=\" << r << \", task=\" << func.second.first << \", func=\" << func.first;\n            }\n        }\n    }\n})\n\nTEST(command_gen, execute) {\n    ASSERT_TRUE(matches(\n        run_captured_stim_main({\"--gen=repetition_code\", \"--rounds=3\", \"--distance=4\", \"--task=memory\"}, \"\"),\n        \".+Generated repetition_code.+\"));\n    ASSERT_TRUE(matches(\n        run_captured_stim_main({\"--gen=surface_code\", \"--rounds=3\", \"--distance=2\", \"--task=unrotated_memory_z\"}, \"\"),\n        \".+Generated surface_code.+\"));\n    ASSERT_TRUE(matches(\n        run_captured_stim_main(\n            {\"gen\", \"--code=surface_code\", \"--rounds=3\", \"--distance=2\", \"--task=unrotated_memory_z\"}, \"\"),\n        \".+Generated surface_code.+\"));\n    ASSERT_TRUE(matches(\n        run_captured_stim_main({\"--gen=surface_code\", \"--rounds=3\", \"--distance=2\", \"--task=rotated_memory_x\"}, \"\"),\n        \".+Generated surface_code.+\"));\n    ASSERT_TRUE(matches(\n        run_captured_stim_main({\"--gen=color_code\", \"--rounds=3\", \"--distance=3\", \"--task=memory_xyz\"}, \"\"),\n        \".+Generated color_code.+\"));\n}\n"
  },
  {
    "path": "src/stim/cmd/command_help.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_help.h\"\n\n#include <algorithm>\n#include <cstring>\n#include <iostream>\n#include <map>\n#include <set>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/cmd/command_analyze_errors.h\"\n#include \"stim/cmd/command_convert.h\"\n#include \"stim/cmd/command_detect.h\"\n#include \"stim/cmd/command_diagram.h\"\n#include \"stim/cmd/command_explain_errors.h\"\n#include \"stim/cmd/command_gen.h\"\n#include \"stim/cmd/command_m2d.h\"\n#include \"stim/cmd/command_repl.h\"\n#include \"stim/cmd/command_sample.h\"\n#include \"stim/cmd/command_sample_dem.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/stabilizers/flow.h\"\n#include \"stim/stabilizers/tableau.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/util_top/mbqc_decomposition.h\"\n\nusing namespace stim;\n\nstd::string stim::clean_doc_string(const char *c, bool allow_too_long) {\n    // Skip leading empty lines.\n    while (*c == '\\n') {\n        c++;\n    }\n\n    // Determine indentation using first non-empty line.\n    size_t indent = 0;\n    while (*c == ' ') {\n        indent++;\n        c++;\n    }\n\n    std::string result;\n    while (*c != '\\0') {\n        // Skip indentation.\n        for (size_t j = 0; j < indent && *c == ' '; j++) {\n            c++;\n        }\n\n        // Copy rest of line.\n        size_t line_length = 0;\n        while (*c != '\\0') {\n            result.push_back(*c);\n            c++;\n            if (result.back() == '\\n') {\n                break;\n            }\n            line_length++;\n        }\n        const char *start_of_line = result.c_str() + result.size() - line_length - 1;\n        if (strstr(start_of_line, \"\\\"\\\"\\\"\") != nullptr) {\n            std::stringstream ss;\n            ss << \"Docstring line contains \\\"\\\"\\\" (please use ''' instead):\\n\" << start_of_line << \"\\n\";\n            throw std::invalid_argument(ss.str());\n        }\n        if (!allow_too_long && line_length > 80) {\n            if (memcmp(start_of_line, \"@signature\", strlen(\"@signature\")) != 0 &&\n                memcmp(start_of_line, \"@overload\", strlen(\"@overload\")) != 0 &&\n                strstr(start_of_line, \"https://\") == nullptr) {\n                std::stringstream ss;\n                ss << \"Docstring line has length \" << line_length << \" > 80:\\n\"\n                   << start_of_line << std::string(80, '^') << \"\\n\";\n                throw std::invalid_argument(ss.str());\n            }\n        }\n    }\n\n    return result;\n}\n\nstd::vector<SubCommandHelp> make_sub_command_help() {\n    SubCommandHelp help_help;\n    help_help.subcommand_name = \"help\";\n    help_help.description = \"Prints helpful information about using stim.\";\n    auto result = std::vector<SubCommandHelp>{\n        command_analyze_errors_help(),\n        command_convert_help(),\n        command_detect_help(),\n        command_diagram_help(),\n        command_explain_errors_help(),\n        command_gen_help(),\n        command_m2d_help(),\n        command_repl_help(),\n        command_sample_help(),\n        command_sample_dem_help(),\n        help_help,\n    };\n    std::sort(result.begin(), result.end(), [](const SubCommandHelp &a, const SubCommandHelp &b) {\n        return a.subcommand_name < b.subcommand_name;\n    });\n    return result;\n}\n\nstd::string to_upper_case(std::string_view val) {\n    std::string result;\n    result.reserve(val.size());\n    for (char c : val) {\n        result.push_back(toupper(c));\n    }\n    return result;\n}\n\nstruct Acc {\n    std::string settled;\n    std::stringstream working;\n    int indent{};\n\n    void flush() {\n        auto s = working.str();\n        for (char c : s) {\n            settled.push_back(c);\n            if (c == '\\n') {\n                for (int k = 0; k < indent; k++) {\n                    settled.push_back(' ');\n                }\n            }\n        }\n        working.str(\"\");\n    }\n\n    void change_indent(int t) {\n        flush();\n        if (indent + t < 0) {\n            throw std::out_of_range(\"negative indent\");\n        }\n        indent += t;\n        working << '\\n';\n    }\n\n    template <typename T>\n    Acc &operator<<(const T &other) {\n        working << other;\n        return *this;\n    }\n};\n\nvoid print_fixed_width_float(Acc &out, float f, char u) {\n    if (f == 0) {\n        out << \"  \";\n    } else if (fabs(f - 1) < 0.0001) {\n        out << \"+\" << u;\n    } else if (fabs(f + 1) < 0.0001) {\n        out << \"-\" << u;\n    } else {\n        if (f > 0) {\n            out << \"+\";\n        }\n        out << f;\n    }\n}\n\nvoid print_example(Acc &out, std::string_view name, const Gate &gate) {\n    out << \"\\nExample:\\n\";\n    out.change_indent(+4);\n    for (size_t k = 0; k < 3; k++) {\n        out << name;\n        if (gate.flags & GATE_IS_NOISY) {\n            if (k == 2 || !(gate.flags & GATE_PRODUCES_RESULTS)) {\n                out << \"(\" << 0.001 << \")\";\n            }\n        }\n        if (k != 1) {\n            out << \" \" << 5;\n            if (gate.flags & GATE_TARGETS_PAIRS) {\n                out << \" \" << 6;\n            }\n        }\n        if (k != 0) {\n            out << \" \";\n            if (gate.flags & GATE_PRODUCES_RESULTS) {\n                out << \"!\";\n            }\n            out << 42;\n            if (gate.flags & GATE_TARGETS_PAIRS) {\n                out << \" \" << 43;\n            }\n        }\n        out << \"\\n\";\n    }\n    if (gate.flags & GATE_CAN_TARGET_BITS) {\n        if (gate.name[0] == 'C' || gate.name[0] == 'Z') {\n            out << gate.name << \" rec[-1] 111\\n\";\n        }\n        if (gate.name.back() == 'Z') {\n            out << gate.name << \" 111 rec[-1]\\n\";\n        }\n    }\n    out.change_indent(-4);\n}\n\nstd::vector<GateTarget> stim::gate_decomposition_help_targets_for_gate_type(GateType g) {\n    if (g == GateType::MPP) {\n        return {\n            GateTarget::x(0),\n            GateTarget::combiner(),\n            GateTarget::y(1),\n            GateTarget::combiner(),\n            GateTarget::z(2),\n            GateTarget::x(3),\n            GateTarget::combiner(),\n            GateTarget::x(4),\n        };\n    } else if (g == GateType::SPP || g == GateType::SPP_DAG) {\n        return {\n            GateTarget::x(0),\n            GateTarget::combiner(),\n            GateTarget::y(1),\n            GateTarget::combiner(),\n            GateTarget::z(2),\n        };\n    } else if (g == GateType::DETECTOR || g == GateType::OBSERVABLE_INCLUDE) {\n        return {GateTarget::rec(-1)};\n    } else if (g == GateType::TICK || g == GateType::SHIFT_COORDS) {\n        return {};\n    } else if (g == GateType::E || g == GateType::ELSE_CORRELATED_ERROR) {\n        return {GateTarget::x(0)};\n    } else if (GATE_DATA[g].flags & GATE_TARGETS_PAIRS) {\n        return {GateTarget::qubit(0), GateTarget::qubit(1)};\n    } else {\n        return {GateTarget::qubit(0)};\n    }\n}\n\nvoid print_decomposition(Acc &out, const Gate &gate) {\n    const char *decomposition = gate.h_s_cx_m_r_decomposition;\n    if (decomposition != nullptr) {\n        std::stringstream undecomposed;\n        auto decomp_targets = gate_decomposition_help_targets_for_gate_type(gate.id);\n        undecomposed << CircuitInstruction{gate.id, {}, decomp_targets, \"\"};\n\n        out << \"Decomposition (into H, S, CX, M, R):\\n\";\n        out.change_indent(+4);\n        out << \"# The following circuit is equivalent (up to global phase) to `\";\n        out << undecomposed.str() << \"`\";\n        out << decomposition;\n        Circuit c(decomposition);\n        if (c == Circuit(undecomposed.str())) {\n            out << \"\\n# (The decomposition is trivial because this gate is in the target gate set.)\\n\";\n        } else if (c.operations.empty()) {\n            out << \"\\n# (The decomposition is empty because this gate has no effect.)\\n\";\n        }\n        out.change_indent(-4);\n    }\n}\n\nvoid print_mbqc_decomposition(Acc &out, const Gate &gate) {\n    const char *decomposition = mbqc_decomposition(gate.id);\n    if (decomposition != nullptr) {\n        std::stringstream undecomposed;\n        auto decomp_targets = gate_decomposition_help_targets_for_gate_type(gate.id);\n        undecomposed << CircuitInstruction{gate.id, {}, decomp_targets, \"\"};\n\n        out << \"MBQC Decomposition (into MX, MY, MZ, MXX, MZZ, and Pauli feedback):\\n\";\n        out.change_indent(+4);\n        out << \"# The following circuit performs `\";\n        out << undecomposed.str() << \"` (but affects the measurement record and an ancilla qubit)\";\n        out << decomposition;\n        Circuit c(decomposition);\n        if (c == Circuit(undecomposed.str())) {\n            out << \"\\n# (The decomposition is trivial because this gate is in the target gate set.)\\n\";\n        } else if (c.operations.empty()) {\n            out << \"\\n# (The decomposition is empty because this gate has no effect.)\\n\";\n        }\n\n        out.change_indent(-4);\n    }\n}\n\nvoid print_stabilizer_generators(Acc &out, const Gate &gate) {\n    auto flows = gate.flows<MAX_BITWORD_WIDTH>();\n    if (flows.empty()) {\n        return;\n    }\n    auto decomp_targets = gate_decomposition_help_targets_for_gate_type(gate.id);\n    if (decomp_targets.size() > 2) {\n        out << \"Stabilizer Generators (for `\";\n        out << CircuitInstruction{gate.id, {}, decomp_targets, \"\"};\n        out << \"`):\\n\";\n    } else {\n        out << \"Stabilizer Generators:\\n\";\n    }\n    out.change_indent(+4);\n    for (const auto &flow : gate.flows<MAX_BITWORD_WIDTH>()) {\n        auto s = flow.str();\n        std::string no_plus;\n        for (char c : s) {\n            if (c != '+') {\n                no_plus.push_back(c);\n            }\n        }\n        out << no_plus << \"\\n\";\n    }\n    out.change_indent(-4);\n}\n\nvoid print_bloch_vector(Acc &out, const Gate &gate) {\n    if (!(gate.flags & GATE_IS_UNITARY) || !(gate.flags & GATE_IS_SINGLE_QUBIT_GATE)) {\n        return;\n    }\n\n    out << \"Bloch Rotation (axis angle):\\n\";\n    out.change_indent(+4);\n    auto axis_angle = gate.to_axis_angle();\n    auto rx = axis_angle[0];\n    auto ry = axis_angle[1];\n    auto rz = axis_angle[2];\n    auto angle = (int)round(axis_angle[3] * 180 / 3.14159265359);\n    if (angle > 180) {\n        angle -= 360;\n    }\n    out << \"Axis: \";\n    if (rx != 0) {\n        out << \"+-\"[rx < 0] << 'X';\n    }\n    if (ry != 0) {\n        out << \"+-\"[ry < 0] << 'Y';\n    }\n    if (rz != 0) {\n        out << \"+-\"[rz < 0] << 'Z';\n    }\n    out << \"\\n\";\n    out << \"Angle: \" << angle << \"°\\n\";\n\n    out.change_indent(-4);\n    out << \"Bloch Rotation (Euler angles):\\n\";\n    out.change_indent(+4);\n    auto euler_angles = gate.to_euler_angles();\n    auto theta_deg = (int)round(euler_angles[0] * 180 / 3.14159265359) % 360;\n    auto phi_deg = (int)round(euler_angles[1] * 180 / 3.14159265359) % 360;\n    auto lambda_deg = (int)round(euler_angles[2] * 180 / 3.14159265359) % 360;\n    out << \"  theta = \" << theta_deg << \"°\\n\";\n    out << \"    phi = \" << phi_deg << \"°\\n\";\n    out << \" lambda = \" << lambda_deg << \"°\\n\";\n    out << \"unitary = RotZ(phi) * RotY(theta) * RotZ(lambda)\\n\";\n    out << \"unitary = RotZ(\" << phi_deg << \"°) * RotY(\" << theta_deg << \"°) * RotZ(\" << lambda_deg << \"°)\\n\";\n    out << \"unitary = \";\n    std::array<const char *, 4> y_rots{\"I\", \"SQRT_Y\", \"Y\", \"SQRT_Y_DAG\"};\n    std::array<const char *, 4> z_rots{\"I\", \"S\", \"Z\", \"S_DAG\"};\n    out << z_rots[(phi_deg / 90) & 3];\n    out << \" * \";\n    out << y_rots[(theta_deg / 90) & 3];\n    out << \" * \";\n    out << z_rots[(lambda_deg / 90) & 3];\n\n    out.change_indent(-4);\n    out << \"\\n\";\n}\n\nvoid print_unitary_matrix(Acc &out, const Gate &gate) {\n    if (!gate.has_known_unitary_matrix()) {\n        return;\n    }\n    auto matrix = gate.unitary();\n    out << \"Unitary Matrix\";\n    if (gate.flags & GATE_TARGETS_PAIRS) {\n        out << \" (little endian)\";\n    }\n    out << \":\\n\";\n    out.change_indent(+4);\n    bool all_halves = true;\n    bool all_sqrt_halves = true;\n    double s = sqrt(0.5);\n    for (const auto &row : matrix) {\n        for (const auto &cell : row) {\n            all_halves &= cell.real() == 0.5 || cell.real() == 0 || cell.real() == -0.5;\n            all_halves &= cell.imag() == 0.5 || cell.imag() == 0 || cell.imag() == -0.5;\n            all_sqrt_halves &= fabs(fabs(cell.real()) - s) < 0.001 || cell.real() == 0;\n            all_sqrt_halves &= fabs(fabs(cell.imag()) - s) < 0.001 || cell.imag() == 0;\n        }\n    }\n    double factor = all_halves ? 2 : all_sqrt_halves ? 1 / s : 1;\n    bool first_row = true;\n    for (const auto &row : matrix) {\n        if (first_row) {\n            first_row = false;\n        } else {\n            out << \"\\n\";\n        }\n        out << \"[\";\n        bool first = true;\n        for (const auto &cell : row) {\n            if (first) {\n                first = false;\n            } else {\n                out << \", \";\n            }\n            print_fixed_width_float(out, cell.real() * factor, '1');\n            print_fixed_width_float(out, cell.imag() * factor, 'i');\n        }\n        out << \"]\";\n    }\n    if (all_halves) {\n        out << \" / 2\";\n    }\n    if (all_sqrt_halves) {\n        out << \" / sqrt(2)\";\n    }\n    out << \"\\n\";\n    out.change_indent(-4);\n}\n\nstd::string generate_per_gate_help_markdown(const Gate &alt_gate, int indent, bool anchor) {\n    Acc out;\n    out.indent = indent;\n    const Gate &gate = GATE_DATA.at(alt_gate.name);\n    if (anchor) {\n        out << \"<a name=\\\"\" << alt_gate.name << \"\\\"></a>\\n\";\n    }\n    if (gate.flags & GATE_IS_UNITARY) {\n        out << \"### The '\" << alt_gate.name << \"' Gate\\n\";\n    } else {\n        out << \"### The '\" << alt_gate.name << \"' Instruction\\n\";\n    }\n    for (const auto &entry : GATE_DATA.hashed_name_to_gate_type_table) {\n        if (entry.expected_name.size() > 0 && entry.id == alt_gate.id && entry.expected_name != alt_gate.name) {\n            out << \"\\nAlternate name: \";\n            if (anchor) {\n                out << \"<a name=\\\"\" << entry.expected_name << \"\\\"></a>\";\n            }\n            out << \"`\" << entry.expected_name << \"`\\n\";\n        }\n    }\n    out << gate.help;\n    if (std::string(gate.help).find(\"xample:\\n\") == std::string::npos &&\n        std::string(gate.help).find(\"xamples:\\n\") == std::string::npos) {\n        print_example(out, alt_gate.name, gate);\n    }\n    print_stabilizer_generators(out, gate);\n    print_bloch_vector(out, gate);\n    print_unitary_matrix(out, gate);\n    print_decomposition(out, gate);\n    print_mbqc_decomposition(out, gate);\n    out.flush();\n    return out.settled;\n}\n\nstd::string generate_subcommand_markdown(const SubCommandHelp &data, int indent, bool anchor) {\n    Acc out;\n    out.indent = indent;\n    if (anchor) {\n        out << \"<a name=\\\"\" << data.subcommand_name << \"\\\"></a>\\n\";\n    }\n    out << \"### stim \" << data.subcommand_name << \"\\n\\n\";\n    out << \"```\\n\";\n    out << data.str_help();\n    out << \"```\\n\";\n\n    out.flush();\n    return out.settled;\n}\n\nstd::string generate_per_format_markdown(const FileFormatData &format_data, int indent, bool anchor) {\n    Acc out;\n    out.indent = indent;\n    if (anchor) {\n        out << \"<a name=\\\"\" << format_data.name << \"\\\"></a>\";\n    }\n    out << \"The `\" << format_data.name << \"` Format\\n\";\n    out << format_data.help;\n    out << \"\\n\";\n\n    out << \"*Example \" << format_data.name << \" parsing code (python)*:\\n\";\n    out << \"```python\";\n    out << format_data.help_python_parse;\n    out << \"```\\n\";\n\n    out << \"*Example \" << format_data.name << \" saving code (python):*\\n\";\n    out << \"```python\";\n    out << format_data.help_python_save;\n    out << \"```\\n\";\n\n    out.flush();\n    return out.settled;\n}\n\nstd::map<std::string, std::string> generate_format_help_markdown() {\n    std::map<std::string, std::string> result;\n\n    std::stringstream all;\n    all << \"Result data formats supported by Stim\\n\";\n\n    all << \"\\n# Index\\n\";\n    for (const auto &kv : format_name_to_enum_map()) {\n        all << kv.first << \"\\n\";\n    }\n    result[std::string(\"FORMATS\")] = all.str();\n\n    for (const auto &kv : format_name_to_enum_map()) {\n        result[to_upper_case(kv.first)] = generate_per_format_markdown(kv.second, 0, false);\n    }\n\n    all.str(\"\");\n    all << R\"MARKDOWN(# Introduction\n\nA *result format* is a way of representing bits from shots sampled from a circuit.\nIt is some way of converting between a list-of-list-of-bits (a list-of-shots) and\na flat string of bytes or characters.\n\nGenerally, the result data formats supported by Stim are extremely minimalist.\nThey do not contain metadata about which circuit was run,\nhow many shots were taken,\nhow many bits are in each shot,\nor even self-identifying information like a header with magic bytes.\nThey produce *raw* data.\nEven details about which bits are measurements, which are detection events,\nand which are observable frame changes must be determined from context.\n\nThe major driver for having multiple formats is context-dependent preferences for\nbinary-vs-human-readable and dense-vs-sparse.\nFor example, '`01`' is a dense text format and '`r8`' is a sparse binary format.\nSometimes you want to be able to eyeball your data, so you want a text format.\nOther times you want maximum efficiency, so you want a binary format.\nSometimes your data is high entropy, with as many 1s as 0s, so you use a dense format.\nOther times the data is highly biased, with 1s being much rarer and more interesting\nthan 0s, so you use a sparse format.\n\n# Index\n)MARKDOWN\";\n    for (const auto &kv : format_name_to_enum_map()) {\n        all << \"- [The **\" << kv.first << \"** Format](#\" << kv.first << \")\\n\";\n    }\n    all << \"\\n\\n\";\n    for (const auto &kv : format_name_to_enum_map()) {\n        all << \"# \" << generate_per_format_markdown(kv.second, 0, true) << \"\\n\";\n    }\n    result[std::string(\"FORMATS_MARKDOWN\")] = all.str();\n\n    return result;\n}\n\nstd::map<std::string, std::string> generate_command_help_topics() {\n    std::map<std::string, std::string> result;\n\n    auto sub_command_data = make_sub_command_help();\n\n    for (const auto &subcommand : sub_command_data) {\n        result[to_upper_case(subcommand.subcommand_name)] = subcommand.str_help();\n    }\n\n    {\n        std::stringstream markdown;\n        markdown << \"# Stim command line reference\\n\\n\";\n        markdown << \"## Index\\n\\n\";\n        for (const auto &subcommand : sub_command_data) {\n            markdown << \"- [stim \" << subcommand.subcommand_name << \"](#\" << subcommand.subcommand_name << \")\\n\";\n        }\n        markdown << \"## Commands\\n\\n\";\n        for (const auto &subcommand : sub_command_data) {\n            markdown << generate_subcommand_markdown(subcommand, 0, true) << \"\\n\";\n        }\n        result[\"COMMANDS_MARKDOWN\"] = markdown.str();\n    }\n\n    {\n        std::stringstream commands_help;\n        commands_help << \"Available stim commands:\\n\\n\";\n        for (const auto &subcommand : sub_command_data) {\n            commands_help << \"    stim \" << subcommand.subcommand_name\n                          << std::string(20 - subcommand.subcommand_name.size(), ' ');\n            auto summary = subcommand.description;\n            auto n = summary.find('\\n');\n            if (n != std::string::npos) {\n                summary = summary.substr(0, n);\n            }\n            commands_help << \"# \" << summary << \"\\n\";\n        }\n        result[\"COMMANDS\"] = commands_help.str();\n    }\n\n    result[\"\"] = result[\"COMMANDS\"] + R\"PARAGRAPH(\nUse `stim help [topic]` for help on specific topics. Available topics include:\n\n    stim help commands  # List all tasks performed by stim.\n    stim help gates     # List all circuit instructions supported by stim.\n    stim help formats   # List all result formats supported by stim.\n    stim help [command] # Print information about a command, e.g. \"sample\".\n    stim help [gate]    # Print information about a gate, e.g. \"CNOT\".\n    stim help [format]  # Print information about a result format, e.g. \"01\".\n)PARAGRAPH\";\n\n    return result;\n}\n\nstd::map<std::string, std::string> generate_gate_help_markdown() {\n    std::map<std::string, std::string> result;\n    for (const auto &e : GATE_DATA.hashed_name_to_gate_type_table) {\n        if (!e.expected_name.empty()) {\n            result[std::string(e.expected_name)] = generate_per_gate_help_markdown(GATE_DATA[e.id], 0, false);\n        }\n    }\n\n    std::map<std::string, std::set<std::string>> categories;\n    for (const auto &e : GATE_DATA.hashed_name_to_gate_type_table) {\n        if (!e.expected_name.empty()) {\n            const auto &rep = GATE_DATA.at(e.expected_name);\n            categories[std::string(rep.category)].insert(std::string(e.expected_name));\n        }\n    }\n\n    std::stringstream all;\n    all << \"Gates supported by Stim\\n\";\n    all << \"=======================\\n\";\n    for (auto &category : categories) {\n        all << category.first.substr(2) << \":\\n\";\n        for (const auto &name : category.second) {\n            all << \"    \" << name << \"\\n\";\n        }\n    }\n\n    result[\"GATES\"] = all.str();\n\n    all.str(\"\");\n    all << \"# Gates supported by Stim\\n\\n\";\n    for (auto &category : categories) {\n        all << \"- \" << category.first.substr(2) << \"\\n\";\n        for (const auto &name : category.second) {\n            all << \"    - [\" << name << \"](#\" << name << \")\\n\";\n        }\n    }\n    all << \"\\n\";\n    for (auto &category : categories) {\n        all << \"## \" << category.first.substr(2) << \"\\n\\n\";\n        for (const auto &name : category.second) {\n            if (name == GATE_DATA.at(name).name) {\n                all << generate_per_gate_help_markdown(GATE_DATA.at(name), 0, true) << \"\\n\";\n            }\n        }\n    }\n    result[std::string(\"GATES_MARKDOWN\")] = all.str();\n\n    return result;\n}\n\nstd::string stim::help_for(std::string help_key) {\n    auto m1 = generate_gate_help_markdown();\n    auto m2 = generate_format_help_markdown();\n    auto m3 = generate_command_help_topics();\n\n    auto key = to_upper_case(help_key);\n    auto p = m1.find(key);\n    if (p == m1.end()) {\n        p = m2.find(key);\n        if (p == m2.end()) {\n            p = m3.find(key);\n            if (p == m3.end()) {\n                return \"\";\n            }\n        }\n    }\n    return p->second;\n}\n\nint stim::command_help(int argc, const char **argv) {\n    const char *help = find_argument(\"--help\", argc, argv);\n    if (help == nullptr) {\n        help = \"\\0\";\n    }\n    if (help[0] == '\\0' && argc == 3) {\n        help = argv[2];\n        // Handle usage like \"stim sample --help\".\n        if (strcmp(help, \"help\") == 0 || strcmp(help, \"--help\") == 0) {\n            help = argv[1];\n        }\n    }\n\n    auto msg = help_for(help);\n    if (msg == \"\") {\n        std::cerr << \"Unrecognized help topic '\" << help << \"'.\\n\";\n        return EXIT_FAILURE;\n    }\n    std::cout << msg;\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_help.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_HELP_H\n#define _STIM_CMD_COMMAND_HELP_H\n\n#include <map>\n#include <string>\n#include <vector>\n\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/gates/gates.h\"\n\nnamespace stim {\n\nint command_help(int argc, const char **argv);\nstd::string help_for(std::string help_key);\nstd::string clean_doc_string(const char *c, bool allow_too_long = false);\n\nstd::vector<GateTarget> gate_decomposition_help_targets_for_gate_type(stim::GateType g);\n\n}  // namespace stim\n\n#endif"
  },
  {
    "path": "src/stim/cmd/command_m2d.cc",
    "content": "#include \"stim/cmd/command_m2d.h\"\n\n#include \"command_help.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/simulators/measurements_to_detection_events.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/util_top/transform_without_feedback.h\"\n\nusing namespace stim;\n\nint stim::command_m2d(int argc, const char **argv) {\n    check_for_unknown_arguments(\n        {\n            \"--circuit\",\n            \"--in_format\",\n            \"--append_observables\",\n            \"--out_format\",\n            \"--out\",\n            \"--in\",\n            \"--skip_reference_sample\",\n            \"--sweep\",\n            \"--sweep_format\",\n            \"--obs_out\",\n            \"--obs_out_format\",\n            \"--ran_without_feedback\",\n        },\n        {\n            \"--m2d\",\n        },\n        \"m2d\",\n        argc,\n        argv);\n    const auto &in_format = find_enum_argument(\"--in_format\", nullptr, format_name_to_enum_map(), argc, argv);\n    const auto &out_format = find_enum_argument(\"--out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    const auto &sweep_format = find_enum_argument(\"--sweep_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    const auto &obs_out_format = find_enum_argument(\"--obs_out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    bool append_observables = find_bool_argument(\"--append_observables\", argc, argv);\n    bool skip_reference_sample = find_bool_argument(\"--skip_reference_sample\", argc, argv);\n    bool ran_without_feedback = find_bool_argument(\"--ran_without_feedback\", argc, argv);\n    FILE *circuit_file = find_open_file_argument(\"--circuit\", nullptr, \"rb\", argc, argv);\n    auto circuit = Circuit::from_file(circuit_file);\n    fclose(circuit_file);\n    if (ran_without_feedback) {\n        circuit = circuit_with_inlined_feedback(circuit);\n    }\n\n    FILE *in = find_open_file_argument(\"--in\", stdin, \"rb\", argc, argv);\n    FILE *out = find_open_file_argument(\"--out\", stdout, \"wb\", argc, argv);\n    FILE *sweep_in = find_open_file_argument(\"--sweep\", stdin, \"rb\", argc, argv);\n    FILE *obs_out = find_open_file_argument(\"--obs_out\", stdout, \"wb\", argc, argv);\n    if (sweep_in == stdin) {\n        sweep_in = nullptr;\n    }\n    if (obs_out == stdout) {\n        obs_out = nullptr;\n    }\n\n    stream_measurements_to_detection_events<MAX_BITWORD_WIDTH>(\n        in,\n        in_format.id,\n        sweep_in,\n        sweep_format.id,\n        out,\n        out_format.id,\n        circuit,\n        append_observables,\n        skip_reference_sample,\n        obs_out,\n        obs_out_format.id);\n    if (in != stdin) {\n        fclose(in);\n    }\n    if (sweep_in != nullptr) {\n        fclose(sweep_in);\n    }\n    if (obs_out != nullptr) {\n        fclose(obs_out);\n    }\n    if (out != stdout) {\n        fclose(out);\n    }\n    return EXIT_SUCCESS;\n}\n\nSubCommandHelp stim::command_m2d_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"m2d\";\n    result.description = clean_doc_string(R\"PARAGRAPH(\n        Convert measurement data into detection event data.\n\n        When sampling data from hardware, instead of from simulators, it's\n        necessary to convert the measurement data into detection event data that\n        can be fed into a decoder. This is necessary both because of\n        complexities in the exact sets of measurements being compared by a\n        circuit to produce detection events and also because the expected parity\n        of a detector's measurement set can vary due to (for example) spin echo\n        operations in the circuit.\n\n        Stim performs this conversion by simulating taking a reference sample\n        from the circuit, in order to determine the expected parity of the\n        measurements sets defining detectors and observables, and then comparing\n        the sampled measurement data to these expectations.\n    )PARAGRAPH\");\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example_circuit.stim\n            X 0\n            M 0 1\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(2) rec[-1]\n\n            >>> cat example_measure_data.01\n            00\n            01\n            10\n            11\n\n            >>> stim m2d \\\n                --append_observables \\\n                --circuit example_circuit.stim \\\n                --in example_measure_data.01 \\\n                --in_format 01 \\\n                --out_format dets\n            shot D0\n            shot D0 D1 L2\n            shot\n            shot D1 L2\n        )PARAGRAPH\"));\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing output detection data.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--obs_out\",\n            \"filepath\",\n            \"\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the file to write observable flip data to.\n\n            When producing detection event data, the goal is typically to\n            predict whether or not the logical observables were flipped by using\n            the detection events. This argument specifies where to write that\n            observable flip data.\n\n            If this argument isn't specified, the observable flip data isn't\n            written to a file.\n\n            The output is in a format specified by `--obs_out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--obs_out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing observable flip data.\n\n            Irrelevant unless `--obs_out` is specified.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when reading measurement data.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--sweep\",\n            \"filepath\",\n            \"\",\n            {\"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies a file to read sweep configuration data from.\n\n            Sweep bits are used to vary whether certain Pauli gates are included\n            in a circuit, or not, from shot to shot. For example, if a circuit\n            contains the instruction \"CX sweep[5] 0\" then there is an X pauli\n            that is included only in shots where the corresponding sweep data\n            has the bit at index 5 set to True.\n\n            If `--sweep` is not specified, all sweep bits default to OFF. If\n            `--sweep` is specified, each shot's sweep configuratoin data is\n            read from the specified file.\n\n            The sweep data's format is specified by `--sweep_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--sweep_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when reading sweep config data.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in\",\n            \"filepath\",\n            \"{stdin}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses the file to read measurement data from.\n\n            By default, the circuit is read from stdin. When `--in $FILEPATH` is\n            specified, the circuit is instead read from the file at $FILEPATH.\n\n            The input's format is specified by `--in_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out\",\n            \"filepath\",\n            \"{stdout}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses where to write the sampled data to.\n\n            By default, the output is written to stdout. When `--out $FILEPATH`\n            is specified, the output is instead written to the file at $FILEPATH.\n\n            The output's format is specified by `--out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--circuit\",\n            \"filepath\",\n            \"\",\n            {\"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies where the circuit that generated the measurements is.\n\n            This argument is required, because the circuit is what specifies how\n            to derive detection event data from measurement data.\n\n            The circuit file should be a stim circuit. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--append_observables\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Appends observable flips to the end of samples as extra detectors.\n\n            PREFER --obs_out OVER THIS FLAG. Mixing the observable flip data\n            into detection event data tends to require simply separating them\n            again immediately, creating unnecessary work. For example, when\n            testing a decoder, you do not want to give the observable flips to\n            the decoder because that is the information the decoder is supposed\n            to be predicting from the detection events.\n\n            This flag causes observable flip data to be appended to each sample,\n            as if the observables were extra detectors at the end of the\n            circuit. For example, if there are 100 detectors and 10 observables\n            in the circuit, then the output will contain 110 detectors and the\n            last 10 are the observables.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--ran_without_feedback\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Converts the results assuming all feedback operations were skipped.\n\n            Pauli feedback operations don't need to be performed on the quantum\n            computer. They can be performed within the classical control system.\n            As such, it often makes sense to skip them when sampling from the\n            circuit on hardware, and then account for this later during data\n            analysis. Turning on this flag means that the quantum computer\n            didn't apply the feedback operations, and it's the job of the m2d\n            conversion to read the measurement data, rewrite it to account for\n            feedback effects, then convert to detection events.\n\n            In the python API, the same effect can be achieved by using\n            stim.Circuit.with_inlined_feedback().compile_m2d_converter().\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--skip_reference_sample\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Asserts the circuit can produce a noiseless sample that is just 0s.\n\n            When this argument is specified, the reference sample (that the\n            measurement data will be compared to) is generated by simply setting\n            all measurements to 0 instead of by simulating the circuit without\n            noise.\n\n            Skipping the reference sample can significantly improve performance,\n            because acquiring the reference sample requires using the tableau\n            simulator. If the vacuous reference sample is actually a result that\n            can be produced by the circuit, under noiseless execution, then\n            specifying this flag has no observable outcome other than improving\n            performance.\n\n            CAUTION. When the all-zero sample isn't a result that can be\n            produced by the circuit under noiseless execution, specifying this\n            flag will cause incorrect output to be produced.\n        )PARAGRAPH\"),\n        });\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_m2d.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_M2D_H\n#define _STIM_CMD_COMMAND_M2D_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_m2d(int argc, const char **argv);\nSubCommandHelp command_m2d_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_m2d.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/main_namespaced.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(command_m2d, m2d) {\n    RaiiTempNamedFile tmp(R\"CIRCUIT(\n        X 0\n        M 0 1\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(2) rec[-1]\n    )CIRCUIT\");\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"m2d\", \"--in_format=01\", \"--out_format=dets\", \"--circuit\", tmp.path.c_str(), \"--append_observables\"},\n            \"00\\n01\\n10\\n11\\n\")),\n        trim(R\"output(\nshot D0\nshot D0 D1 L2\nshot\nshot D1 L2\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"m2d\", \"--in_format=01\", \"--out_format=dets\", \"--circuit\", tmp.path.c_str()}, \"00\\n01\\n10\\n11\\n\")),\n        trim(R\"output(\nshot D0\nshot D0 D1\nshot\nshot D1\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"m2d\", \"--in_format=01\", \"--out_format=dets\", \"--circuit\", tmp.path.c_str(), \"--skip_reference_sample\"},\n            \"00\\n01\\n10\\n11\\n\")),\n        trim(R\"output(\nshot\nshot D1\nshot D0\nshot D0 D1\n            )output\"));\n}\n\nTEST(command_m2d, m2d_without_feedback) {\n    RaiiTempNamedFile tmp(R\"CIRCUIT(\n        CX 0 2 1 2\n        M 2\n        CX rec[-1] 2\n        DETECTOR rec[-1]\n        TICK\n\n        CX 0 2 1 2\n        M 2\n        CX rec[-1] 2\n        DETECTOR rec[-1] rec[-2]\n        TICK\n\n        CX 0 2 1 2\n        M 2\n        CX rec[-1] 2\n        DETECTOR rec[-1] rec[-2]\n        TICK\n\n        M 0 1\n        DETECTOR rec[-1] rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\");\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"m2d\", \"--in_format=01\", \"--append_observables\", \"--out_format=dets\", \"--circuit\", tmp.path.c_str()},\n            \"00000\\n10000\\n01000\\n00100\\n00010\\n00001\\n\")),\n        trim(R\"output(\nshot\nshot D0 D1\nshot D1 D2\nshot D2 D3\nshot D3\nshot D3 L0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"m2d\",\n             \"--in_format=01\",\n             \"--append_observables\",\n             \"--out_format=dets\",\n             \"--circuit\",\n             tmp.path.c_str(),\n             \"--ran_without_feedback\"},\n            \"00000\\n11100\\n01100\\n00100\\n00010\\n00001\\n\")),\n        trim(R\"output(\nshot\nshot D0 D1\nshot D1 D2\nshot D2 D3\nshot D3\nshot D3 L0\n            )output\"));\n}\n\nTEST(command_m2d, m2d_obs_size_misalign_1_obs) {\n    RaiiTempNamedFile tmp_circuit(R\"CIRCUIT(\n        M 0\n        REPEAT 1024 {\n            DETECTOR rec[-1]\n        }\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\");\n    RaiiTempNamedFile tmp_obs;\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"m2d\", \"--in_format=01\", \"--obs_out\", tmp_obs.path.c_str(), \"--circuit\", tmp_circuit.path.c_str()},\n            \"0\\n\")),\n        trim(std::string(1024, '0') + \"\\n\"));\n    ASSERT_EQ(tmp_obs.read_contents(), \"0\\n\");\n}\n\nTEST(command_m2d, m2d_obs_size_misalign_11_obs) {\n    RaiiTempNamedFile tmp_circuit(R\"CIRCUIT(\n        M 0\n        REPEAT 1024 {\n            DETECTOR rec[-1]\n        }\n        OBSERVABLE_INCLUDE(10) rec[-1]\n    )CIRCUIT\");\n    RaiiTempNamedFile tmp_obs;\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"m2d\", \"--in_format=01\", \"--obs_out\", tmp_obs.path.c_str(), \"--circuit\", tmp_circuit.path.c_str()},\n            \"0\\n\")),\n        trim(std::string(1024, '0') + \"\\n\"));\n    ASSERT_EQ(tmp_obs.read_contents(), \"00000000000\\n\");\n}\n\nTEST(command_m2d, unphysical_observable_annotations) {\n    RaiiTempNamedFile tmp_circuit(R\"CIRCUIT(\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(0, 1) 2\n        QUBIT_COORDS(1, 1) 3\n        OBSERVABLE_INCLUDE(0) X0 X1\n        OBSERVABLE_INCLUDE(1) Z0 Z2\n        MPP X0*X1*X2*X3 Z0*Z1 Z2*Z3\n        DEPOLARIZE1(0.001) 0 1 2 3\n        MPP X0*X1*X2*X3 Z0*Z1 Z2*Z3\n        DETECTOR rec[-1] rec[-4]\n        DETECTOR rec[-2] rec[-5]\n        DETECTOR rec[-3] rec[-6]\n        OBSERVABLE_INCLUDE(0) X0 X1\n        OBSERVABLE_INCLUDE(1) Z0 Z2\n    )CIRCUIT\");\n    RaiiTempNamedFile tmp_obs;\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\"m2d\", \"--in_format=01\", \"--obs_out\", tmp_obs.path.c_str(), \"--circuit\", tmp_circuit.path.c_str()},\n            \"000000\\n100100\\n000110\\n\")),\n        trim(\"000\\n000\\n011\\n\"));\n    ASSERT_EQ(tmp_obs.read_contents(), \"00\\n00\\n00\\n\");\n}\n"
  },
  {
    "path": "src/stim/cmd/command_repl.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_repl.h\"\n\n#include \"command_help.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/util_bot/probability_util.h\"\n\nusing namespace stim;\n\nint stim::command_repl(int argc, const char **argv) {\n    check_for_unknown_arguments({}, {\"--repl\"}, \"repl\", argc, argv);\n    auto rng = externally_seeded_rng();\n    TableauSimulator<MAX_BITWORD_WIDTH>::sample_stream(stdin, stdout, SampleFormat::SAMPLE_FORMAT_01, true, rng);\n    return EXIT_SUCCESS;\n}\n\nSubCommandHelp stim::command_repl_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"repl\";\n    result.description = clean_doc_string(R\"PARAGRAPH(\n        Runs stim in interactive read-evaluate-print (REPL) mode.\n\n        Reads operations from stdin while immediately writing measurement\n        results to stdout.\n    )PARAGRAPH\");\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> stim repl\n            ... M 0\n            0\n            ... X 0\n            ... M 0\n            1\n            ... X 2 3 9\n            ... M 0 1 2 3 4 5 6 7 8 9\n            1 0 1 1 0 0 0 0 0 1\n            ... REPEAT 5 {\n            ...     R 0 1\n            ...     H 0\n            ...     CNOT 0 1\n            ...     M 0 1\n            ... }\n            00\n            11\n            11\n            00\n            11\n        )PARAGRAPH\"));\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_repl.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_REPL_H\n#define _STIM_CMD_COMMAND_REPL_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_repl(int argc, const char **argv);\nSubCommandHelp command_repl_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_sample.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_sample.h\"\n\n#include \"command_help.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/util_bot/probability_util.h\"\n#include \"stim/util_top/reference_sample_tree.h\"\n\nusing namespace stim;\n\nint stim::command_sample(int argc, const char **argv) {\n    check_for_unknown_arguments(\n        {\"--seed\", \"--skip_reference_sample\", \"--skip_loop_folding\", \"--out_format\", \"--out\", \"--in\", \"--shots\"},\n        {\"--sample\", \"--frame0\"},\n        \"sample\",\n        argc,\n        argv);\n    const auto &out_format = find_enum_argument(\"--out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    bool skip_reference_sample = find_bool_argument(\"--skip_reference_sample\", argc, argv);\n    bool skip_loop_folding = find_bool_argument(\"--skip_loop_folding\", argc, argv);\n    uint64_t num_shots =\n        find_argument(\"--shots\", argc, argv)    ? (uint64_t)find_int64_argument(\"--shots\", 1, 0, INT64_MAX, argc, argv)\n        : find_argument(\"--sample\", argc, argv) ? (uint64_t)find_int64_argument(\"--sample\", 1, 0, INT64_MAX, argc, argv)\n                                                : 1;\n    if (num_shots == 0) {\n        return EXIT_SUCCESS;\n    }\n    FILE *in = find_open_file_argument(\"--in\", stdin, \"rb\", argc, argv);\n    FILE *out = find_open_file_argument(\"--out\", stdout, \"wb\", argc, argv);\n    auto rng = optionally_seeded_rng(argc, argv);\n    bool deprecated_frame0 = find_bool_argument(\"--frame0\", argc, argv);\n    if (deprecated_frame0) {\n        std::cerr << \"[DEPRECATION] Use `--skip_reference_sample` instead of `--frame0`\\n\";\n        skip_reference_sample = true;\n    }\n\n    if (num_shots == 1 && !skip_reference_sample) {\n        TableauSimulator<MAX_BITWORD_WIDTH>::sample_stream(in, out, out_format.id, false, rng);\n    } else {\n        assert(num_shots > 0);\n        auto circuit = Circuit::from_file(in);\n        simd_bits<MAX_BITWORD_WIDTH> ref(0);\n        if (!skip_reference_sample) {\n            if (skip_loop_folding) {\n                ref = TableauSimulator<MAX_BITWORD_WIDTH>::reference_sample_circuit(circuit);\n            } else {\n                ReferenceSampleTree reference_sample_measurement_bits =\n                    ReferenceSampleTree::from_circuit_reference_sample(circuit.aliased_noiseless_circuit());\n                reference_sample_measurement_bits.decompress_into(ref);\n            }\n        }\n        sample_batch_measurements_writing_results_to_disk(circuit, ref, num_shots, out, out_format.id, rng);\n    }\n\n    if (in != stdin) {\n        fclose(in);\n    }\n    if (out != stdout) {\n        fclose(out);\n    }\n    return EXIT_SUCCESS;\n}\n\nSubCommandHelp stim::command_sample_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"sample\";\n    result.description = \"Samples measurements from a circuit.\";\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example_circuit.stim\n            H 0\n            CNOT 0 1\n            M 0 1\n\n            >>> stim sample --shots 5 < example_circuit.stim\n            00\n            11\n            11\n            00\n            11\n\n        )PARAGRAPH\"));\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example_circuit.stim\n            X 2 3 5\n            M 0 1 2 3 4 5 6 7 8 9\n\n            >>> stim sample --in example_circuit.stim --out_format dets\n            shot M2 M3 M5\n        )PARAGRAPH\"));\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--skip_reference_sample\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Asserts the circuit can produce a noiseless sample that is just 0s.\n\n            When this argument is specified, the reference sample (that is used\n            to convert measurement flip data from frame simulations into actual\n            measurement data) is generated by simply setting all measurements to\n            0 instead of by performing a stabilizer tableau simulation of the\n            circuit without noise.\n\n            Skipping the reference sample can significantly improve performance,\n            because acquiring the reference sample requires using the tableau\n            simulator. If the vacuous reference sample is actually a result that\n            can be produced by the circuit, under noiseless execution, then\n            specifying this flag has no observable outcome other than improving\n            performance.\n\n            CAUTION. When the all-zero sample isn't a result that can be\n            produced by the circuit under noiseless execution, specifying this\n            flag will cause incorrect output to be produced. Specifically, the\n            output measurement bits will be whether each measurement was\n            *FLIPPED* instead of the actual absolute value of the measurement.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--skip_loop_folding\",\n            \"bool\",\n            \"false\",\n            {\"[none]\", \"[switch]\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Skips loop folding logic on the reference sample calculation.\n\n            When this argument is specified, the reference sample (that is used\n            to convert measurement flip data from frame simulations into actual\n            measurement data) is generated by iterating through the entire\n            flattened circuit with no loop detection.\n\n            Loop folding can enormously improve performance for circuits\n            containing REPEAT blocks with large repeat counts, by detecting\n            periodicity in loops and fast-forwarding across them when computing\n            the reference sample for the circuit. However, in some cases the\n            analysis is not able to detect the periodicity that is present. For\n            example, this has been observed in honeycomb code circuits. When\n            this happens, the folding-capable analysis is slower than simply\n            analyzing the flattened circuit without any specialized loop logic.\n            The `--skip_loop_folding` flag can be used to just analyze the\n            flattened circuit, bypassing this slowdown for circuits such as\n            honeycomb code circuits.\n\n            By default, loop detection is enabled. Pass this flag to disable\n            it (when appropriate by use case).\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing output data.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--seed\",\n            \"int\",\n            \"system_entropy\",\n            {\"[none]\", \"int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Makes simulation results PARTIALLY deterministic.\n\n            The seed integer must be a non-negative 64 bit signed integer.\n\n            When `--seed` isn't specified, the random number generator is seeded\n            using fresh entropy requested from the operating system.\n\n            When `--seed #` is set, the exact same simulation results will be\n            produced every time ASSUMING:\n\n            - the exact same other flags are specified\n            - the exact same version of Stim is being used\n            - the exact same machine architecture is being used (for example,\n                you're not switching from a machine that has AVX2 instructions\n                to one that doesn't).\n\n            CAUTION: simulation results *WILL NOT* be consistent between\n            versions of Stim. This restriction is present to make it possible to\n            have future optimizations to the random sampling, and is enforced by\n            introducing intentional differences in the seeding strategy from\n            version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines.\n            For example, using the same seed on a machine that supports AVX\n            instructions and one that only supports SSE instructions may produce\n            different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary\n            other flags and modes. For example, `--skip_reference_sample` may\n            result in fewer calls the to the random number generator before\n            reported sampling begins. More generally, using the same seed for\n            `stim sample` and `stim detect` will not result in detection events\n            corresponding to the measurement results.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--shots\",\n            \"int\",\n            \"1\",\n            {\"[none]\", \"int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the number of samples to take from the circuit.\n\n            Defaults to 1.\n            Must be an integer between 0 and a quintillion (10^18).\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in\",\n            \"filepath\",\n            \"{stdin}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses the stim circuit file to read the circuit to sample from.\n\n            By default, the circuit is read from stdin. When `--in $FILEPATH` is\n            specified, the circuit is instead read from the file at $FILEPATH.\n\n            The input should be a stim circuit. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_stim_circuit.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out\",\n            \"filepath\",\n            \"{stdout}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses where to write the sampled data to.\n\n            By default, the output is written to stdout. When `--out $FILEPATH`\n            is specified, the output is instead written to the file at $FILEPATH.\n\n            The output is in a format specified by `--out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_sample.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_SAMPLE_H\n#define _STIM_CMD_COMMAND_SAMPLE_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_sample(int argc, const char **argv);\nSubCommandHelp command_sample_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_sample.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <unordered_map>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/main_namespaced.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nstd::unordered_map<std::string_view, size_t> line_freq_with_lifetime_matching_arg(std::string_view data) {\n    data = trim(data);\n    std::unordered_map<std::string_view, size_t> result{};\n    size_t start = 0;\n    for (size_t k = 0; k <= data.size(); k++) {\n        if (data[k] == '\\n' || data[k] == '\\0') {\n            result[data.substr(start, k - start)]++;\n            start = k + 1;\n        }\n    }\n    return result;\n}\n\nstd::string deviation(std::string_view sample_content, const std::unordered_map<std::string_view, float> &expected) {\n    auto actual = line_freq_with_lifetime_matching_arg(sample_content);\n    size_t actual_total = 0;\n    for (const auto &kv : actual) {\n        if (expected.find(kv.first) == expected.end()) {\n            return \"Sampled \" + std::string(kv.first) + \" which was not expected.\";\n        }\n        actual_total += kv.second;\n    }\n    if (actual_total == 0) {\n        return \"No samples.\";\n    }\n    double expected_unity = 0;\n    for (const auto &kv : expected) {\n        expected_unity += kv.second;\n    }\n    if (fabs(expected_unity - 1) > 1e-5) {\n        return \"Expected distribution doesn't add up to 1.\";\n    }\n    for (const auto &kv : expected) {\n        float expected_rate = kv.second;\n        float allowed_variation = 5 * sqrtf(expected_rate * (1 - expected_rate) / actual_total);\n        if (expected_rate - allowed_variation < 0 || expected_rate + allowed_variation > 1) {\n            return \"Not enough samples to bound results away from extremes.\";\n        }\n\n        float actual_rate = actual[kv.first] / (float)actual_total;\n        if (fabs(expected_rate - actual_rate) > allowed_variation) {\n            return \"Actual rate \" + std::to_string(actual_rate) + \" of sample '\" + std::string(kv.first) +\n                   \"' is more than 5 standard deviations from expected rate \" + std::to_string(expected_rate);\n        }\n    }\n\n    return \"\";\n}\n\nTEST(command_sample, sample_flag) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--sample\"}, R\"input(\nM 0\n            )input\")),\n        trim(R\"output(\n0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--sample=1\"}, R\"input(\nM 0\n            )input\")),\n        trim(R\"output(\n0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"sample\", \"--shots\", \"1\"}, R\"input(\nM 0\n            )input\")),\n        trim(R\"output(\n0\n            )output\"));\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"sample\", \"--shots\", \"2\"}, R\"input(\nM 0\n            )input\")),\n        trim(R\"output(\n0\n0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--sample=0\"}, R\"input(\nM 0\n            )input\")),\n        trim(R\"output(\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--sample=2\"}, R\"input(\nM 0\n            )input\")),\n        trim(R\"output(\n0\n0\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--sample\"}, R\"input(\nX 0\nM 0\n            )input\")),\n        trim(R\"output(\n1\n            )output\"));\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--sample\"}, R\"input(\nM !0\n            )input\")),\n        trim(R\"output(\n1\n            )output\"));\n}\n\nTEST(command_sample, intentional_failures) {\n    ASSERT_EQ(\n        \"Sampled 10 which was not expected.\",\n        deviation(\n            run_captured_stim_main({\"--sample=1000\"}, R\"input(\nX 0\nM 0 1\n            )input\"),\n            {{\"00\", 0.5}, {\"11\", 0.5}}));\n\n    ASSERT_NE(\n        \"Sampled 10 which was not expected.\",\n        deviation(\n            run_captured_stim_main({\"--sample=1000\"}, R\"input(\nH 0\nM 0\n            )input\"),\n            {{\"0\", 0.1}, {\"1\", 0.9}}));\n}\n\nTEST(command_sample, basic_distributions) {\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=10000\"}, R\"input(\nH 0\nCNOT 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.5}, {\"11\", 0.5}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=10000\"}, R\"input(\nH 0\nCNOT 0 1\nSQRT_X 0 1\nM 0 1\n            )input\"),\n            {{\"10\", 0.5}, {\"01\", 0.5}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=10000\"}, R\"input(\nH 0\nCNOT 0 1\nSQRT_Y 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.5}, {\"11\", 0.5}}));\n}\n\nTEST(command_sample, sample_x_error) {\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=100000\"}, R\"input(\nX_ERROR(0.1) 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.9 * 0.9}, {\"01\", 0.9 * 0.1}, {\"10\", 0.9 * 0.1}, {\"11\", 0.1 * 0.1}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=10\"}, R\"input(\nH 0 1\nX_ERROR(0.1) 0 1\nH 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 1}}));\n}\n\nTEST(command_sample, sample_z_error) {\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=100000\"}, R\"input(\nH 0 1\nZ_ERROR(0.1) 0 1\nH 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.9 * 0.9}, {\"01\", 0.9 * 0.1}, {\"10\", 0.9 * 0.1}, {\"11\", 0.1 * 0.1}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=10\"}, R\"input(\nZ_ERROR(0.1) 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 1}}));\n}\n\nTEST(command_sample, sample_y_error) {\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=100000\"}, R\"input(\nY_ERROR(0.1) 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.9 * 0.9}, {\"01\", 0.9 * 0.1}, {\"10\", 0.9 * 0.1}, {\"11\", 0.1 * 0.1}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=10\"}, R\"input(\nH_YZ 0 1\nY_ERROR(0.1) 0 1\nH_YZ 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 1}}));\n}\n\nTEST(command_sample, sample_depolarize1_error) {\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=100000\"}, R\"input(\nDEPOLARIZE1(0.3) 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.8 * 0.8}, {\"01\", 0.8 * 0.2}, {\"10\", 0.8 * 0.2}, {\"11\", 0.2 * 0.2}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=100000\"}, R\"input(\nH 0 1\nDEPOLARIZE1(0.3) 0 1\nH 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.8 * 0.8}, {\"01\", 0.8 * 0.2}, {\"10\", 0.8 * 0.2}, {\"11\", 0.2 * 0.2}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=100000\"}, R\"input(\nH_YZ 0 1\nDEPOLARIZE1(0.3) 0 1\nH_YZ 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.8 * 0.8}, {\"01\", 0.8 * 0.2}, {\"10\", 0.8 * 0.2}, {\"11\", 0.2 * 0.2}}));\n}\n\nTEST(command_sample, sample_depolarize2_error) {\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=100000\"}, R\"input(\nDEPOLARIZE2(0.1) 0 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.1 * 3 / 15 + 0.9}, {\"01\", 0.1 * 4 / 15}, {\"10\", 0.1 * 4 / 15}, {\"11\", 0.1 * 4 / 15}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=100000\"}, R\"input(\nH 0\nH_YZ 1\nDEPOLARIZE2(0.3) 0 1\nH 0\nH_YZ 1\nM 0 1\n            )input\"),\n            {{\"00\", 0.3 * 3 / 15 + 0.7}, {\"01\", 0.3 * 4 / 15}, {\"10\", 0.3 * 4 / 15}, {\"11\", 0.3 * 4 / 15}}));\n}\n\nTEST(command_sample, sample_measure_reset) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--sample\"}, R\"input(\nX 0\nR 0\nM 0\n            )input\")),\n        trim(R\"output(\n0\n            )output\"));\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--sample\"}, R\"input(\nX 0\nMR 0\nMR 0\n            )input\")),\n        trim(R\"output(\n10\n            )output\"));\n}\n\nTEST(command_sample, skip_reference_sample_flag) {\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample\", \"--skip_reference_sample\"}, R\"input(\nH 0\nS 0\nS 0\nH 0\nM 0\n            )input\"),\n            {{\"0\", 1}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=10\", \"--skip_reference_sample\"}, R\"input(\nH 0\nS 0\nS 0\nH 0\nM 0\n            )input\"),\n            {{\"0\", 1}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample\"}, R\"input(\nH 0\nS 0\nS 0\nH 0\nM 0\n            )input\"),\n            {{\"1\", 1}}));\n\n    ASSERT_EQ(\n        \"\",\n        deviation(\n            run_captured_stim_main({\"--sample=10\"}, R\"input(\nH 0\nS 0\nS 0\nH 0\nM 0\n            )input\"),\n            {{\"1\", 1}}));\n}\n\nTEST(command_sample, seeded_sampling) {\n    ASSERT_EQ(\n        run_captured_stim_main({\"sample\", \"--shots=256\", \"--seed 5\"}, R\"input(\n                H 0\n                M 0\n            )input\"),\n        run_captured_stim_main({\"sample\", \"--shots=256\", \"--seed 5\"}, R\"input(\n                H 0\n                M 0\n            )input\"));\n\n    ASSERT_NE(\n        run_captured_stim_main({\"sample\", \"--shots=256\"}, R\"input(\n                H 0\n                M 0\n            )input\"),\n        run_captured_stim_main({\"sample\", \"--shots=256\"}, R\"input(\n                H 0\n                M 0\n            )input\"));\n\n    ASSERT_NE(\n        run_captured_stim_main({\"sample\", \"--shots=256\", \"--seed 5\"}, R\"input(\n                H 0\n                M 0\n            )input\"),\n        run_captured_stim_main({\"sample\", \"--shots=256\", \"--seed 6\"}, R\"input(\n                H 0\n                M 0\n            )input\"));\n}\n"
  },
  {
    "path": "src/stim/cmd/command_sample_dem.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/cmd/command_sample_dem.h\"\n\n#include \"command_help.h\"\n#include \"stim/io/raii_file.h\"\n#include \"stim/simulators/dem_sampler.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/util_bot/probability_util.h\"\n\nusing namespace stim;\n\nint stim::command_sample_dem(int argc, const char **argv) {\n    check_for_unknown_arguments(\n        {\n            \"--seed\",\n            \"--shots\",\n            \"--out_format\",\n            \"--out\",\n            \"--in\",\n            \"--obs_out\",\n            \"--obs_out_format\",\n            \"--err_out\",\n            \"--err_out_format\",\n            \"--replay_err_in\",\n            \"--replay_err_in_format\",\n        },\n        {},\n        \"sample_dem\",\n        argc,\n        argv);\n    const auto &out_format = find_enum_argument(\"--out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    const auto &obs_out_format = find_enum_argument(\"--obs_out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    const auto &err_out_format = find_enum_argument(\"--err_out_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    const auto &err_in_format =\n        find_enum_argument(\"--replay_err_in_format\", \"01\", format_name_to_enum_map(), argc, argv);\n    uint64_t num_shots = find_int64_argument(\"--shots\", 1, 0, INT64_MAX, argc, argv);\n\n    RaiiFile in(find_open_file_argument(\"--in\", stdin, \"rb\", argc, argv));\n    RaiiFile out(find_open_file_argument(\"--out\", stdout, \"wb\", argc, argv));\n    RaiiFile obs_out(find_open_file_argument(\"--obs_out\", stdout, \"wb\", argc, argv));\n    RaiiFile err_out(find_open_file_argument(\"--err_out\", stdout, \"wb\", argc, argv));\n    RaiiFile err_in(find_open_file_argument(\"--replay_err_in\", stdin, \"rb\", argc, argv));\n    if (obs_out.f == stdout) {\n        obs_out.f = nullptr;\n    }\n    if (err_out.f == stdout) {\n        err_out.f = nullptr;\n    }\n    if (err_in.f == stdin) {\n        err_in.f = nullptr;\n    }\n    if (out.f == stdout) {\n        out.responsible_for_closing = false;\n    }\n    if (in.f == stdin) {\n        out.responsible_for_closing = false;\n    }\n    if (num_shots == 0) {\n        return EXIT_SUCCESS;\n    }\n\n    auto dem = DetectorErrorModel::from_file(in.f);\n    in.done();\n\n    DemSampler<MAX_BITWORD_WIDTH> sampler(std::move(dem), optionally_seeded_rng(argc, argv), 1024);\n    sampler.sample_write(\n        num_shots,\n        out.f,\n        out_format.id,\n        obs_out.f,\n        obs_out_format.id,\n        err_out.f,\n        err_out_format.id,\n        err_in.f,\n        err_in_format.id);\n\n    return EXIT_SUCCESS;\n}\n\nSubCommandHelp stim::command_sample_dem_help() {\n    SubCommandHelp result;\n    result.subcommand_name = \"sample_dem\";\n    result.description = clean_doc_string(R\"PARAGRAPH(\n        Samples detection events from a detector error model.\n\n        Supports recording and replaying the errors that occurred.\n    )PARAGRAPH\");\n\n    result.examples.push_back(clean_doc_string(R\"PARAGRAPH(\n            >>> cat example.dem\n            error(0) D0\n            error(0.5) D1 L0\n            error(1) D2 D3\n\n            >>> stim sample_dem \\\n                --shots 5 \\\n                --in example.dem \\\n                --out dets.01 \\\n                --out_format 01 \\\n                --obs_out obs_flips.01 \\\n                --obs_out_format 01\n\n            >>> cat dets.01\n            0111\n            0011\n            0011\n            0111\n            0111\n\n            >>> cat obs_flips.01\n            1\n            0\n            0\n            1\n            1\n        )PARAGRAPH\"));\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--replay_err_in\",\n            \"filepath\",\n            \"\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies a file to read error data to replay from.\n\n            When replaying error information, errors are no longer sampled\n            randomly but are instead driven by the file data. For example, this\n            file data could come from a previous run that wrote error data using\n            `--err_out`.\n\n            The input is in a format specified by `--err_in_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--replay_err_in_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when reading error data to replay.\n\n            Irrelevant unless `--replay_err_in` is specified.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--err_out\",\n            \"filepath\",\n            \"\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies a file to write a record of which errors occurred.\n\n            For example, the errors that occurred can be analyzed, modified, and\n            then given to `--replay_err_in` to see the effects of changes.\n\n            The output is in a format specified by `--err_out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--err_out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing recorded error data.\n\n            Irrelevant unless `--err_out` is specified.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--obs_out\",\n            \"filepath\",\n            \"\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the file to write observable flip data to.\n\n            When sampling detection event data, the goal is typically to predict\n            whether or not the logical observables were flipped by using the\n            detection events. This argument specifies where to write that\n            observable flip data.\n\n            If this argument isn't specified, the observable flip data isn't\n            written to a file.\n\n            The output is in a format specified by `--obs_out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--obs_out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing observable flip data.\n\n            Irrelevant unless `--obs_out` is specified.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out_format\",\n            \"01|b8|r8|ptb64|hits|dets\",\n            \"01\",\n            {\"[none]\", \"format\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the data format to use when writing output data.\n\n            The available formats are:\n\n                01 (default): dense human readable\n                b8: bit packed binary\n                r8: run length binary\n                ptb64: partially transposed bit packed binary for SIMD\n                hits: sparse human readable\n                dets: sparse human readable with type hints\n\n            For a detailed description of each result format, see the result\n            format reference:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--seed\",\n            \"int\",\n            \"system_entropy\",\n            {\"[none]\", \"int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Makes simulation results PARTIALLY deterministic.\n\n            The seed integer must be a non-negative 64 bit signed integer.\n\n            When `--seed` isn't specified, the random number generator is seeded\n            using fresh entropy requested from the operating system.\n\n            When `--seed #` is set, the exact same simulation results will be\n            produced every time ASSUMING:\n\n            - the exact same other flags are specified\n            - the exact same version of Stim is being used\n            - the exact same machine architecture is being used (for example,\n                you're not switching from a machine that has AVX2 instructions\n                to one that doesn't).\n\n            CAUTION: simulation results *WILL NOT* be consistent between\n            versions of Stim. This restriction is present to make it possible to\n            have future optimizations to the random sampling, and is enforced by\n            introducing intentional differences in the seeding strategy from\n            version to version.\n\n            CAUTION: simulation results *MAY NOT* be consistent across machines.\n            For example, using the same seed on a machine that supports AVX\n            instructions and one that only supports SSE instructions may produce\n            different simulation results.\n\n            CAUTION: simulation results *MAY NOT* be consistent if you vary\n            other flags and modes. For example, `--skip_reference_sample` may\n            result in fewer calls the to the random number generator before\n            reported sampling begins. More generally, using the same seed for\n            `stim sample` and `stim detect` will not result in detection events\n            corresponding to the measurement results.\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--shots\",\n            \"int\",\n            \"1\",\n            {\"[none]\", \"int\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Specifies the number of samples to take from the detector error model.\n\n            Defaults to 1.\n            Must be an integer between 0 and a quintillion (10^18).\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--in\",\n            \"filepath\",\n            \"{stdin}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses the file to read the detector error model to sample from.\n\n            By default, the detector error model is read from stdin. When\n            `--in $FILEPATH` is specified, the detector error model is instead\n            read from the file at $FILEPATH.\n\n            The input should be a stim detector error model. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n        )PARAGRAPH\"),\n        });\n\n    result.flags.push_back(\n        SubCommandHelpFlag{\n            \"--out\",\n            \"filepath\",\n            \"{stdout}\",\n            {\"[none]\", \"filepath\"},\n            clean_doc_string(R\"PARAGRAPH(\n            Chooses where to write the sampled data to.\n\n            By default, the output is written to stdout. When `--out $FILEPATH`\n            is specified, the output is instead written to the file at $FILEPATH.\n\n            The output is in a format specified by `--out_format`. See:\n            https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n        )PARAGRAPH\"),\n        });\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/cmd/command_sample_dem.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CMD_COMMAND_SAMPLE_DEM_H\n#define _STIM_CMD_COMMAND_SAMPLE_DEM_H\n\n#include \"stim/util_bot/arg_parse.h\"\n\nnamespace stim {\n\nint command_sample_dem(int argc, const char **argv);\nSubCommandHelp command_sample_dem_help();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/cmd/command_sample_dem.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/main_namespaced.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(main, sample_dem) {\n    ASSERT_EQ(run_captured_stim_main({\"sample_dem\"}, \"\"), \"\\n\");\n\n    RaiiTempNamedFile obs_out;\n\n    ASSERT_EQ(\n        trim(run_captured_stim_main(\n            {\n                \"sample_dem\",\n                \"--obs_out\",\n                obs_out.path.c_str(),\n                \"--out_format\",\n                \"01\",\n                \"--obs_out_format\",\n                \"01\",\n                \"--shots\",\n                \"5\",\n                \"--seed\",\n                \"0\",\n            },\n            R\"input(\n                error(0) D0\n                error(1) D1 L2\n            )input\")),\n        trim(R\"output(\n01\n01\n01\n01\n01\n            )output\"));\n    ASSERT_EQ(obs_out.read_contents(), \"001\\n001\\n001\\n001\\n001\\n\");\n}\n"
  },
  {
    "path": "src/stim/dem/dem_instruction.cc",
    "content": "#include \"stim/dem/dem_instruction.h\"\n\n#include <cmath>\n\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\n\nconstexpr uint64_t OBSERVABLE_BIT = uint64_t{1} << 63;\nconstexpr uint64_t SEPARATOR_SYGIL = UINT64_MAX;\n\nDemTarget DemTarget::observable_id(uint64_t id) {\n    if (id > MAX_OBS) {\n        throw std::invalid_argument(\"id > 0xFFFFFFFF\");\n    }\n    return {OBSERVABLE_BIT | id};\n}\nDemTarget DemTarget::relative_detector_id(uint64_t id) {\n    if (id > MAX_DET) {\n        throw std::invalid_argument(\"Relative detector id too large.\");\n    }\n    return {id};\n}\nbool DemTarget::is_observable_id() const {\n    return data != SEPARATOR_SYGIL && (data & OBSERVABLE_BIT);\n}\nbool DemTarget::is_separator() const {\n    return data == SEPARATOR_SYGIL;\n}\nbool DemTarget::is_relative_detector_id() const {\n    return data != SEPARATOR_SYGIL && !(data & OBSERVABLE_BIT);\n}\nuint64_t DemTarget::raw_id() const {\n    return data & ~OBSERVABLE_BIT;\n}\n\nuint64_t DemTarget::val() const {\n    if (data == SEPARATOR_SYGIL) {\n        throw std::invalid_argument(\"Separator doesn't have an integer value.\");\n    }\n    return raw_id();\n}\n\nbool DemTarget::operator==(const DemTarget &other) const {\n    return data == other.data;\n}\nbool DemTarget::operator!=(const DemTarget &other) const {\n    return !(*this == other);\n}\nbool DemTarget::operator<(const DemTarget &other) const {\n    return data < other.data;\n}\nstd::ostream &stim::operator<<(std::ostream &out, const DemTarget &v) {\n    if (v.is_separator()) {\n        out << \"^\";\n        return out;\n    } else if (v.is_relative_detector_id()) {\n        out << \"D\" << v.raw_id();\n    } else {\n        out << \"L\" << v.raw_id();\n    }\n    return out;\n}\n\nstd::string DemTarget::str() const {\n    std::stringstream s;\n    s << *this;\n    return s.str();\n}\n\nvoid DemTarget::shift_if_detector_id(int64_t offset) {\n    if (is_relative_detector_id()) {\n        data = (uint64_t)((int64_t)data + offset);\n    }\n}\nDemTarget DemTarget::from_text(std::string_view text) {\n    if (text == \"^\") {\n        return DemTarget::separator();\n    }\n    if (!text.empty()) {\n        bool is_det = text[0] == 'D';\n        bool is_obs = text[0] == 'L';\n        if (is_det || is_obs) {\n            int64_t parsed = 0;\n            if (parse_int64(text.substr(1), &parsed)) {\n                if (parsed >= 0) {\n                    if (is_det && (uint64_t)parsed <= MAX_DET) {\n                        return DemTarget::relative_detector_id(parsed);\n                    } else if (is_obs && (uint64_t)parsed <= MAX_OBS) {\n                        return DemTarget::observable_id(parsed);\n                    }\n                }\n            }\n        }\n    }\n    throw std::invalid_argument(\"Failed to parse as a stim.DemTarget: '\" + std::string(text) + \"'\");\n}\n\nbool DemInstruction::operator<(const DemInstruction &other) const {\n    if (type != other.type) {\n        return type < other.type;\n    }\n    if (target_data != other.target_data) {\n        return target_data < other.target_data;\n    }\n    if (tag != other.tag) {\n        return tag < other.tag;\n    }\n    return arg_data < other.arg_data;\n}\n\nbool DemInstruction::operator==(const DemInstruction &other) const {\n    return approx_equals(other, 0);\n}\nbool DemInstruction::operator!=(const DemInstruction &other) const {\n    return !(*this == other);\n}\nbool DemInstruction::approx_equals(const DemInstruction &other, double atol) const {\n    if (target_data != other.target_data) {\n        return false;\n    }\n    if (type != other.type) {\n        return false;\n    }\n    if (tag != other.tag) {\n        return false;\n    }\n    if (arg_data.size() != other.arg_data.size()) {\n        return false;\n    }\n    for (size_t k = 0; k < arg_data.size(); k++) {\n        if (fabs(arg_data[k] - other.arg_data[k]) > atol) {\n            return false;\n        }\n    }\n    return true;\n}\nstd::string DemInstruction::str() const {\n    std::stringstream s;\n    s << *this;\n    return s.str();\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const DemInstructionType &type) {\n    switch (type) {\n        case DemInstructionType::DEM_ERROR:\n            out << \"error\";\n            break;\n        case DemInstructionType::DEM_DETECTOR:\n            out << \"detector\";\n            break;\n        case DemInstructionType::DEM_LOGICAL_OBSERVABLE:\n            out << \"logical_observable\";\n            break;\n        case DemInstructionType::DEM_SHIFT_DETECTORS:\n            out << \"shift_detectors\";\n            break;\n        case DemInstructionType::DEM_REPEAT_BLOCK:\n            out << \"repeat\";\n            break;\n        default:\n            out << \"???unknown_instruction_type???\";\n            break;\n    }\n    return out;\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const DemInstruction &op) {\n    out << op.type;\n    if (!op.tag.empty()) {\n        out << '[';\n        write_tag_escaped_string_to(op.tag, out);\n        out << ']';\n    }\n    if (!op.arg_data.empty()) {\n        out << \"(\" << comma_sep(op.arg_data) << \")\";\n    }\n    if (op.type == DemInstructionType::DEM_SHIFT_DETECTORS || op.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n        for (const auto &e : op.target_data) {\n            out << \" \" << e.data;\n        }\n    } else {\n        for (const auto &e : op.target_data) {\n            out << \" \" << e;\n        }\n    }\n    return out;\n}\n\nvoid DemInstruction::validate() const {\n    switch (type) {\n        case DemInstructionType::DEM_ERROR:\n            if (arg_data.size() != 1) {\n                throw std::invalid_argument(\n                    \"'error' instruction takes 1 argument (a probability), but got \" + std::to_string(arg_data.size()) +\n                    \" arguments.\");\n            }\n            if (arg_data[0] < 0 || arg_data[0] > 1) {\n                throw std::invalid_argument(\n                    \"'error' instruction argument must be a probability (0 to 1) but got \" +\n                    std::to_string(arg_data[0]));\n            }\n            if (!target_data.empty()) {\n                if (target_data.front() == DemTarget::separator() || target_data.back() == DemTarget::separator()) {\n                    throw std::invalid_argument(\n                        \"First/last targets of 'error' instruction shouldn't be separators (^).\");\n                }\n            }\n            for (size_t k = 1; k < target_data.size(); k++) {\n                if (target_data[k - 1] == DemTarget::separator() && target_data[k] == DemTarget::separator()) {\n                    throw std::invalid_argument(\"'error' instruction has adjacent separators (^ ^).\");\n                }\n            }\n            break;\n        case DemInstructionType::DEM_SHIFT_DETECTORS:\n            if (target_data.size() != 1) {\n                throw std::invalid_argument(\n                    \"'shift_detectors' instruction takes 1 target, but got \" + std::to_string(target_data.size()) +\n                    \" targets.\");\n            }\n            break;\n        case DemInstructionType::DEM_DETECTOR:\n            if (target_data.size() != 1) {\n                throw std::invalid_argument(\n                    \"'detector' instruction takes 1 target but got \" + std::to_string(target_data.size()) +\n                    \" arguments.\");\n            }\n            if (!target_data[0].is_relative_detector_id()) {\n                throw std::invalid_argument(\n                    \"'detector' instruction takes a relative detector target (D#) but got \" + target_data[0].str() +\n                    \" arguments.\");\n            }\n            break;\n        case DemInstructionType::DEM_LOGICAL_OBSERVABLE:\n            if (arg_data.size() != 0) {\n                throw std::invalid_argument(\n                    \"'logical_observable' instruction takes 0 arguments but got \" + std::to_string(arg_data.size()) +\n                    \" arguments.\");\n            }\n            if (target_data.size() != 1) {\n                throw std::invalid_argument(\n                    \"'logical_observable' instruction takes 1 target but got \" + std::to_string(target_data.size()) +\n                    \" arguments.\");\n            }\n            if (!target_data[0].is_observable_id()) {\n                throw std::invalid_argument(\n                    \"'logical_observable' instruction takes a logical observable target (L#) but got \" +\n                    target_data[0].str() + \" arguments.\");\n            }\n            break;\n        case DemInstructionType::DEM_REPEAT_BLOCK:\n            // Handled elsewhere.\n            break;\n        default:\n            throw std::invalid_argument(\"Unknown instruction type.\");\n    }\n}\n\nuint64_t DemInstruction::repeat_block_rep_count() const {\n    assert(target_data.size() > 0);\n    return target_data[0].data;\n}\n\nconst DetectorErrorModel &DemInstruction::repeat_block_body(const DetectorErrorModel &host) const {\n    assert(target_data.size() == 2);\n    auto b = target_data[1].data;\n    assert(b < host.blocks.size());\n    return host.blocks[b];\n}\n\nDetectorErrorModel &DemInstruction::repeat_block_body(DetectorErrorModel &host) const {\n    assert(target_data.size() == 2);\n    auto b = target_data[1].data;\n    assert(b < host.blocks.size());\n    return host.blocks[b];\n}\n"
  },
  {
    "path": "src/stim/dem/dem_instruction.h",
    "content": "#ifndef _STIM_DEM_DEM_INSTRUCTION_H\n#define _STIM_DEM_DEM_INSTRUCTION_H\n\n#include <memory>\n#include <set>\n#include <string>\n#include <vector>\n\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\nconstexpr uint64_t MAX_OBS = 0xFFFFFFFF;\nconstexpr uint64_t MAX_DET = (uint64_t{1} << 62) - 1;\n\nenum class DemInstructionType : uint8_t {\n    DEM_ERROR,\n    DEM_SHIFT_DETECTORS,\n    DEM_DETECTOR,\n    DEM_LOGICAL_OBSERVABLE,\n    DEM_REPEAT_BLOCK,\n};\n\nstruct DemTarget {\n    uint64_t data;\n\n    static DemTarget observable_id(uint64_t id);\n    static DemTarget relative_detector_id(uint64_t id);\n    static constexpr DemTarget separator() {\n        return {UINT64_MAX};\n    }\n    uint64_t raw_id() const;\n    uint64_t val() const;\n    bool is_observable_id() const;\n    bool is_separator() const;\n    bool is_relative_detector_id() const;\n    void shift_if_detector_id(int64_t offset);\n\n    bool operator==(const DemTarget &other) const;\n    bool operator!=(const DemTarget &other) const;\n    bool operator<(const DemTarget &other) const;\n    std::string str() const;\n\n    static DemTarget from_text(std::string_view text);\n};\n\nstruct DetectorErrorModel;\nstruct DemInstruction {\n    SpanRef<const double> arg_data;\n    SpanRef<const DemTarget> target_data;\n    std::string_view tag;\n    DemInstructionType type;\n\n    bool operator<(const DemInstruction &other) const;\n    bool operator==(const DemInstruction &other) const;\n    bool operator!=(const DemInstruction &other) const;\n    bool approx_equals(const DemInstruction &other, double atol) const;\n    std::string str() const;\n\n    void validate() const;\n\n    uint64_t repeat_block_rep_count() const;\n    const DetectorErrorModel &repeat_block_body(const DetectorErrorModel &host) const;\n    DetectorErrorModel &repeat_block_body(DetectorErrorModel &host) const;\n\n    template <typename CALLBACK>\n    inline void for_separated_targets(CALLBACK callback) const {\n        size_t start = 0;\n        do {\n            size_t end = start + 1;\n            while (end < target_data.size() && !target_data[end].is_separator()) {\n                end++;\n            }\n            std::span<const DemTarget> group = target_data.sub(start, std::min(end, target_data.size()));\n            callback(group);\n            start = end + 1;\n        } while (start < target_data.size());\n    }\n};\n\nstd::ostream &operator<<(std::ostream &out, const DemInstructionType &type);\nstd::ostream &operator<<(std::ostream &out, const DemTarget &v);\nstd::ostream &operator<<(std::ostream &out, const DemInstruction &v);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/dem/dem_instruction.pybind.cc",
    "content": "#include \"stim/dem/dem_instruction.pybind.h\"\n\n#include \"stim/dem/detector_error_model_target.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nstd::vector<std::vector<ExposedDemTarget>> ExposedDemInstruction::target_groups() const {\n    std::vector<std::vector<ExposedDemTarget>> result;\n    as_dem_instruction().for_separated_targets([&](std::span<const DemTarget> group) {\n        std::vector<ExposedDemTarget> copy;\n        for (auto e : group) {\n            copy.push_back(e);\n        }\n        result.push_back(copy);\n    });\n    return result;\n}\n\nDemInstruction ExposedDemInstruction::as_dem_instruction() const {\n    return DemInstruction{arguments, targets, tag, type};\n}\n\nExposedDemInstruction ExposedDemInstruction::from_dem_instruction(stim::DemInstruction instruction) {\n    std::vector<double> arguments;\n    std::vector<DemTarget> targets;\n    arguments.insert(arguments.begin(), instruction.arg_data.begin(), instruction.arg_data.end());\n    targets.insert(targets.begin(), instruction.target_data.begin(), instruction.target_data.end());\n    return ExposedDemInstruction{arguments, targets, std::string(instruction.tag), instruction.type};\n}\n\nExposedDemInstruction ExposedDemInstruction::from_str(std::string_view text) {\n    DetectorErrorModel host;\n    host.append_from_text(text);\n    if (host.instructions.size() != 1 || host.instructions[0].type == DemInstructionType::DEM_REPEAT_BLOCK) {\n        throw std::invalid_argument(\"Given text didn't parse to a single DemInstruction.\");\n    }\n    return from_dem_instruction(host.instructions[0]);\n}\n\nstd::string ExposedDemInstruction::type_name() const {\n    std::stringstream out;\n    out << type;\n    return out.str();\n}\n\nstd::string ExposedDemInstruction::str() const {\n    return as_dem_instruction().str();\n}\n\nstd::string ExposedDemInstruction::repr() const {\n    std::stringstream out;\n    out << \"stim.DemInstruction('\" << type << \"', [\";\n    out << comma_sep(arguments);\n    out << \"], [\";\n    bool first = true;\n    for (const auto &e : targets) {\n        if (first) {\n            first = false;\n        } else {\n            out << \", \";\n        }\n        if (type == DemInstructionType::DEM_SHIFT_DETECTORS) {\n            out << e.data;\n        } else if (e.is_relative_detector_id()) {\n            out << \"stim.target_relative_detector_id(\" << e.raw_id() << \")\";\n        } else if (e.is_separator()) {\n            out << \"stim.target_separator()\";\n        } else {\n            out << \"stim.target_logical_observable_id(\" << e.raw_id() << \")\";\n        }\n    }\n    out << \"]\";\n    if (!tag.empty()) {\n        out << \", tag=\" << pybind11::cast<std::string>(pybind11::repr(pybind11::cast(tag)));\n    }\n    out << \")\";\n    return out.str();\n}\n\nbool ExposedDemInstruction::operator==(const ExposedDemInstruction &other) const {\n    return type == other.type && arguments == other.arguments && targets == other.targets && tag == other.tag;\n}\nbool ExposedDemInstruction::operator!=(const ExposedDemInstruction &other) const {\n    return !(*this == other);\n}\nstd::vector<pybind11::object> ExposedDemInstruction::targets_copy() const {\n    std::vector<pybind11::object> result;\n    if (type == DemInstructionType::DEM_SHIFT_DETECTORS) {\n        for (const auto &e : targets) {\n            result.push_back(pybind11::cast(e.data));\n        }\n    } else {\n        for (const auto &e : targets) {\n            result.push_back(pybind11::cast(ExposedDemTarget{e}));\n        }\n    }\n    return result;\n}\nstd::vector<double> ExposedDemInstruction::args_copy() const {\n    return arguments;\n}\n\npybind11::class_<ExposedDemInstruction> stim_pybind::pybind_detector_error_model_instruction(pybind11::module &m) {\n    return pybind11::class_<ExposedDemInstruction>(\n        m,\n        \"DemInstruction\",\n        clean_doc_string(R\"DOC(\n            An instruction from a detector error model.\n\n            Examples:\n                >>> import stim\n                >>> model = stim.DetectorErrorModel('''\n                ...     error(0.125) D0\n                ...     error(0.125) D0 D1 L0\n                ...     error(0.125) D1 D2\n                ...     error(0.125) D2 D3\n                ...     error(0.125) D3\n                ... ''')\n                >>> instruction = model[0]\n                >>> instruction\n                stim.DemInstruction('error', [0.125], [stim.target_relative_detector_id(0)])\n        )DOC\")\n            .data());\n}\nvoid stim_pybind::pybind_detector_error_model_instruction_methods(\n    pybind11::module &m, pybind11::class_<ExposedDemInstruction> &c) {\n    c.def(\n        pybind11::init(\n            [](std::string_view type, pybind11::object &arguments, pybind11::object &targets, std::string_view tag)\n                -> ExposedDemInstruction {\n                if (arguments.is_none() && targets.is_none()) {\n                    return ExposedDemInstruction::from_str(type);\n                }\n\n                std::string lower;\n                for (char c : type) {\n                    lower.push_back(tolower(c));\n                }\n                DemInstructionType conv_type;\n                std::vector<DemTarget> conv_targets;\n                if (lower == \"error\") {\n                    conv_type = DemInstructionType::DEM_ERROR;\n                } else if (lower == \"shift_detectors\") {\n                    conv_type = DemInstructionType::DEM_SHIFT_DETECTORS;\n                } else if (lower == \"detector\") {\n                    conv_type = DemInstructionType::DEM_DETECTOR;\n                } else if (lower == \"logical_observable\") {\n                    conv_type = DemInstructionType::DEM_LOGICAL_OBSERVABLE;\n                } else {\n                    throw std::invalid_argument(\"Unrecognized instruction name '\" + lower + \"'.\");\n                }\n                if (!targets.is_none()) {\n                    if (conv_type == DemInstructionType::DEM_SHIFT_DETECTORS) {\n                        for (const auto &e : targets) {\n                            try {\n                                conv_targets.push_back(DemTarget{pybind11::cast<uint64_t>(e)});\n                            } catch (pybind11::cast_error &) {\n                                throw std::invalid_argument(\n                                    \"Instruction '\" + lower + \"' only takes unsigned integer targets.\");\n                            }\n                        }\n                    } else {\n                        for (const auto &e : targets) {\n                            try {\n                                conv_targets.push_back(pybind11::cast<ExposedDemTarget>(e).internal());\n                            } catch (pybind11::cast_error &) {\n                                throw std::invalid_argument(\n                                    \"Instruction '\" + lower +\n                                    \"' only takes stim.target_relative_detector_id(k), \"\n                                    \"stim.target_logical_observable_id(k), \"\n                                    \"stim.target_separator() targets.\");\n                            }\n                        }\n                    }\n                }\n\n                std::vector<double> conv_args;\n                if (!arguments.is_none()) {\n                    conv_args = pybind11::cast<std::vector<double>>(arguments);\n                }\n                ExposedDemInstruction result{\n                    std::move(conv_args), std::move(conv_targets), std::string(tag), conv_type};\n                result.as_dem_instruction().validate();\n                return result;\n            }),\n        pybind11::arg(\"type\"),\n        pybind11::arg(\"args\") = pybind11::none(),\n        pybind11::arg(\"targets\") = pybind11::none(),\n        pybind11::kw_only(),\n        pybind11::arg(\"tag\") = \"\",\n        clean_doc_string(R\"DOC(\n            @signature def __init__(self, type: str, args: Optional[Iterable[float]] = None, targets: Optional[Iterable[stim.DemTarget]] = None, *, tag: str = \"\") -> None:\n            Creates or parses a stim.DemInstruction.\n\n            Args:\n                type: The name of the instruction type (e.g. \"error\" or \"shift_detectors\").\n                    If `args` and `targets` aren't specified, this can also be set to a\n                    full line of text from a dem file, like \"error(0.25) D0\".\n                args: Numeric values parameterizing the instruction (e.g. the 0.1 in\n                    \"error(0.1)\").\n                targets: The objects the instruction involves (e.g. the \"D0\" and \"L1\" in\n                    \"error(0.1) D0 L1\").\n                tag: An arbitrary piece of text attached to the instruction.\n\n            Examples:\n                >>> import stim\n                >>> instruction = stim.DemInstruction(\n                ...     'error',\n                ...     [0.125],\n                ...     [stim.target_relative_detector_id(5)],\n                ...     tag='test-tag',\n                ... )\n                >>> print(instruction)\n                error[test-tag](0.125) D5\n\n                >>> print(stim.DemInstruction('error(0.125) D5 L6 ^ D4  # comment'))\n                error(0.125) D5 L6 ^ D4\n        )DOC\")\n            .data());\n\n    c.def(\n        \"args_copy\",\n        &ExposedDemInstruction::args_copy,\n        clean_doc_string(R\"DOC(\n            @signature def args_copy(self) -> List[float]:\n            Returns a copy of the list of numbers parameterizing the instruction.\n\n            For example, this would be coordinates of a detector instruction or the\n            probability of an error instruction. The result is a copy, meaning that\n            editing it won't change the instruction's targets or future copies.\n\n            Examples:\n                >>> import stim\n                >>> instruction = stim.DetectorErrorModel('''\n                ...     error(0.125) D0\n                ... ''')[0]\n                >>> instruction.args_copy()\n                [0.125]\n\n                >>> instruction.args_copy() == instruction.args_copy()\n                True\n                >>> instruction.args_copy() is instruction.args_copy()\n                False\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"tag\",\n        &ExposedDemInstruction::tag,\n        clean_doc_string(R\"DOC(\n            Returns the arbitrary text tag attached to the instruction.\n\n            Examples:\n                >>> import stim\n                >>> dem = stim.DetectorErrorModel('''\n                ...     error[test-tag](0.125) D0\n                ...     error(0.125) D0\n                ... ''')\n                >>> dem[0].tag\n                'test-tag'\n                >>> dem[1].tag\n                ''\n        )DOC\")\n            .data());\n\n    c.def(\n        \"target_groups\",\n        &ExposedDemInstruction::target_groups,\n        clean_doc_string(R\"DOC(\n            @signature def target_groups(self) -> List[List[stim.DemTarget]]:\n            Returns a copy of the instruction's targets, split by target separators.\n\n            When a detector error model instruction contains a suggested decomposition,\n            its targets contain separators (`stim.DemTarget(\"^\")`). This method splits the\n            targets into groups based the separators, similar to how `str.split` works.\n\n            Returns:\n                A list of groups of targets.\n\n            Examples:\n                >>> import stim\n                >>> dem = stim.DetectorErrorModel('''\n                ...     error(0.01) D0 D1 ^ D2\n                ...     error(0.01) D0 L0\n                ...     error(0.01)\n                ... ''')\n\n                >>> dem[0].target_groups()\n                [[stim.DemTarget('D0'), stim.DemTarget('D1')], [stim.DemTarget('D2')]]\n\n                >>> dem[1].target_groups()\n                [[stim.DemTarget('D0'), stim.DemTarget('L0')]]\n\n                >>> dem[2].target_groups()\n                [[]]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"targets_copy\",\n        &ExposedDemInstruction::targets_copy,\n        clean_doc_string(R\"DOC(\n            @signature def targets_copy(self) -> List[Union[int, stim.DemTarget]]:\n            Returns a copy of the instruction's targets.\n\n            The result is a copy, meaning that editing it won't change the instruction's\n            targets or future copies.\n\n            Examples:\n                >>> import stim\n                >>> instruction = stim.DetectorErrorModel('''\n                ...     error(0.125) D0 L2\n                ... ''')[0]\n                >>> instruction.targets_copy()\n                [stim.DemTarget('D0'), stim.DemTarget('L2')]\n\n                >>> instruction.targets_copy() == instruction.targets_copy()\n                True\n                >>> instruction.targets_copy() is instruction.targets_copy()\n                False\n        )DOC\")\n            .data());\n    c.def_property_readonly(\n        \"type\",\n        &ExposedDemInstruction::type_name,\n        clean_doc_string(R\"DOC(\n            The name of the instruction type (e.g. \"error\" or \"shift_detectors\").\n        )DOC\")\n            .data());\n    c.def(pybind11::self == pybind11::self, \"Determines if two instructions have identical contents.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two instructions have non-identical contents.\");\n\n    c.def(\n        \"__str__\",\n        &ExposedDemInstruction::str,\n        \"Returns detector error model (.dem) instructions (that can be parsed by stim) for the model.\");\n    c.def(\n        \"__repr__\",\n        &ExposedDemInstruction::repr,\n        \"Returns text that is a valid python expression evaluating to an equivalent `stim.DetectorErrorModel`.\");\n\n    c.def(\"__hash__\", [](const ExposedDemInstruction &self) {\n        return pybind11::hash(pybind11::str(self.str()));\n    });\n}\n"
  },
  {
    "path": "src/stim/dem/dem_instruction.pybind.h",
    "content": "#ifndef _STIM_DEM_DETECTOR_ERROR_MODEL_INSTRUCTION_PYBIND_H\n#define _STIM_DEM_DETECTOR_ERROR_MODEL_INSTRUCTION_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/dem/detector_error_model_target.pybind.h\"\n\nnamespace stim_pybind {\n\nstruct ExposedDemInstruction {\n    std::vector<double> arguments;\n    std::vector<stim::DemTarget> targets;\n    std::string tag;\n    stim::DemInstructionType type;\n\n    static ExposedDemInstruction from_str(std::string_view text);\n    static ExposedDemInstruction from_dem_instruction(stim::DemInstruction instruction);\n\n    std::vector<std::vector<stim_pybind::ExposedDemTarget>> target_groups() const;\n    std::vector<double> args_copy() const;\n    std::vector<pybind11::object> targets_copy() const;\n    stim::DemInstruction as_dem_instruction() const;\n    std::string type_name() const;\n    std::string str() const;\n    std::string repr() const;\n    bool operator==(const ExposedDemInstruction &other) const;\n    bool operator!=(const ExposedDemInstruction &other) const;\n};\n\npybind11::class_<ExposedDemInstruction> pybind_detector_error_model_instruction(pybind11::module &m);\nvoid pybind_detector_error_model_instruction_methods(pybind11::module &m, pybind11::class_<ExposedDemInstruction> &c);\n\n}  // namespace stim_pybind\n#endif\n"
  },
  {
    "path": "src/stim/dem/dem_instruction.test.cc",
    "content": "#include \"stim/dem/dem_instruction.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/dem/detector_error_model.h\"\n\nusing namespace stim;\n\nTEST(dem_instruction, from_str) {\n    ASSERT_EQ(DemTarget::from_text(\"D5\"), DemTarget::relative_detector_id(5));\n    ASSERT_EQ(DemTarget::from_text(\"D0\"), DemTarget::relative_detector_id(0));\n    ASSERT_EQ(DemTarget::from_text(\"D4611686018427387903\"), DemTarget::relative_detector_id(4611686018427387903));\n\n    ASSERT_EQ(DemTarget::from_text(\"L5\"), DemTarget::observable_id(5));\n    ASSERT_EQ(DemTarget::from_text(\"L0\"), DemTarget::observable_id(0));\n    ASSERT_EQ(DemTarget::from_text(\"L4294967295\"), DemTarget::observable_id(4294967295));\n\n    ASSERT_THROW({ DemTarget::from_text(\"D4611686018427387904\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"L4294967296\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"L-1\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"L-1\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"D-1\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"Da\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"Da \"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\" Da\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"X\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"1\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"-1\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"0\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\"'\"); }, std::invalid_argument);\n    ASSERT_THROW({ DemTarget::from_text(\" \"); }, std::invalid_argument);\n}\n\nTEST(dem_instruction, for_separated_targets) {\n    DetectorErrorModel dem(\"error(0.1) D0 ^ D2 L0 ^ D1 D2 D3\");\n    std::vector<std::vector<DemTarget>> results;\n    dem.instructions[0].for_separated_targets([&](std::span<const DemTarget> group) {\n        std::vector<DemTarget> items;\n        for (auto g : group) {\n            items.push_back(g);\n        }\n        results.push_back(items);\n    });\n    ASSERT_EQ(\n        results,\n        (std::vector<std::vector<DemTarget>>{\n            {DemTarget::relative_detector_id(0)},\n            {DemTarget::relative_detector_id(2), DemTarget::observable_id(0)},\n            {DemTarget::relative_detector_id(1),\n             DemTarget::relative_detector_id(2),\n             DemTarget::relative_detector_id(3)},\n        }));\n\n    dem = DetectorErrorModel(\"error(0.1) D0\");\n    results.clear();\n    dem.instructions[0].for_separated_targets([&](std::span<const DemTarget> group) {\n        std::vector<DemTarget> items;\n        for (auto g : group) {\n            items.push_back(g);\n        }\n        results.push_back(items);\n    });\n    ASSERT_EQ(\n        results,\n        (std::vector<std::vector<DemTarget>>{\n            {DemTarget::relative_detector_id(0)},\n        }));\n\n    dem = DetectorErrorModel(\"error(0.1)\");\n    results.clear();\n    dem.instructions[0].for_separated_targets([&](std::span<const DemTarget> group) {\n        std::vector<DemTarget> items;\n        for (auto g : group) {\n            items.push_back(g);\n        }\n        results.push_back(items);\n    });\n    ASSERT_EQ(\n        results,\n        (std::vector<std::vector<DemTarget>>{\n            {},\n        }));\n}\n"
  },
  {
    "path": "src/stim/dem/dem_instruction_pybind_test.py",
    "content": "import stim\nimport pytest\n\n\ndef test_args_copy():\n    assert stim.DemInstruction(\"error\", [0.25], [stim.target_relative_detector_id(3)]).args_copy() == [0.25]\n    assert stim.DemInstruction(\"error\", [0.125], [stim.target_relative_detector_id(3)]).args_copy() == [0.125]\n    assert stim.DemInstruction(\"shift_detectors\", [], [1]).args_copy() == []\n    assert stim.DemInstruction(\"shift_detectors\", [0.125, 0.25], [1]).args_copy() == [0.125, 0.25]\n\n\ndef test_targets_copy():\n    t1 = [stim.target_relative_detector_id(3), stim.target_separator(), stim.target_logical_observable_id(2)]\n    assert stim.DemInstruction(\"error\", [0.25], t1).targets_copy() == t1\n    assert stim.DemInstruction(\"shift_detectors\", [], [1]).targets_copy() == [1]\n    t2 = [stim.target_logical_observable_id(3)]\n    assert stim.DemInstruction(\"logical_observable\", [], t2).targets_copy() == t2\n\n\ndef test_type():\n    assert stim.DemInstruction(\"error\", [0.25], [stim.target_relative_detector_id(3)]).type == \"error\"\n    assert stim.DemInstruction(\"ERROR\", [0.25], [stim.target_relative_detector_id(3)]).type == \"error\"\n    assert stim.DemInstruction(\"shift_detectors\", [], [1]).type == \"shift_detectors\"\n    assert stim.DemInstruction(\"detector\", [], [stim.target_relative_detector_id(3)]).type == \"detector\"\n    assert stim.DemInstruction(\"logical_observable\", [], [stim.target_logical_observable_id(3)]).type == \"logical_observable\"\n\n\ndef test_equality():\n    e1 = stim.DemInstruction(\"error\", [0.25], [stim.target_relative_detector_id(3)])\n    assert e1 == stim.DemInstruction(\"error\", [0.25], [stim.target_relative_detector_id(3)])\n    assert not (e1 != stim.DemInstruction(\"error\", [0.25], [stim.target_relative_detector_id(3)]))\n    assert e1 != stim.DemInstruction(\"error\", [0.35], [stim.target_relative_detector_id(3)])\n    assert not (e1 == stim.DemInstruction(\"error\", [0.35], [stim.target_relative_detector_id(3)]))\n    assert e1 != stim.DemInstruction(\"error\", [0.35], [stim.target_relative_detector_id(4)])\n    assert e1 != stim.DemInstruction(\"shift_detectors\", [0.35], [3])\n\n\ndef test_validation():\n    with pytest.raises(ValueError, match=\"takes 1 arg\"):\n        stim.DemInstruction(\"error\", [], [stim.target_relative_detector_id(3)])\n    with pytest.raises(ValueError, match=\"takes 1 arg\"):\n        stim.DemInstruction(\"error\", [0.5, 0.5], [stim.target_relative_detector_id(3)])\n    with pytest.raises(ValueError, match=\"last target.+separator\"):\n        stim.DemInstruction(\"error\", [0.25], [stim.target_separator()])\n    with pytest.raises(ValueError, match=\"0 to 1\"):\n        stim.DemInstruction(\"error\", [-0.1], [stim.target_relative_detector_id(3)])\n    with pytest.raises(ValueError, match=\"0 to 1\"):\n        stim.DemInstruction(\"error\", [1.1], [stim.target_relative_detector_id(3)])\n    with pytest.raises(ValueError, match=\"detector.+targets\"):\n        stim.DemInstruction(\"error\", [0.25], [3])\n\n    with pytest.raises(ValueError, match=\"integer targets\"):\n        stim.DemInstruction(\"shift_detectors\", [1.1], [stim.target_relative_detector_id(3)])\n\n\ndef test_str():\n    v = stim.DemInstruction(\"ERROR\", [0.125], [stim.target_relative_detector_id(3), stim.target_logical_observable_id(6)])\n    assert str(v) == \"error(0.125) D3 L6\"\n    v = stim.DemInstruction(\"Shift_detectors\", [1.5, 2.5, 5.5], [6])\n    assert str(v) == \"shift_detectors(1.5, 2.5, 5.5) 6\"\n\n\ndef test_repr():\n    v = stim.DemInstruction(\"error\", [0.25], [stim.target_relative_detector_id(3), stim.target_logical_observable_id(6)])\n    assert eval(repr(v), {\"stim\": stim}) == v\n    v = stim.DemInstruction(\"shift_detectors\", [1.5, 2.5, 5.5], [6])\n    assert eval(repr(v), {\"stim\": stim}) == v\n\n\ndef test_hashable():\n    a = stim.DemInstruction(\"error\", [0.25], [stim.target_relative_detector_id(3)])\n    b = stim.DemInstruction(\"error\", [0.125], [stim.target_relative_detector_id(3)])\n    c = stim.DemInstruction(\"error\", [0.25], [stim.target_relative_detector_id(3)])\n    assert hash(a) == hash(c)\n    assert len({a, b, c}) == 2\n\n\ndef test_target_groups():\n    dem = stim.DetectorErrorModel(\"detector D0\")\n    assert dem[0].target_groups() == [[stim.DemTarget(\"D0\")]]\n\n\ndef test_init_from_str():\n    assert stim.DemInstruction(\"detector D0\") == stim.DemInstruction(\"detector\", [], [stim.target_relative_detector_id(0)])\n\n    with pytest.raises(ValueError, match=\"single DemInstruction\"):\n        stim.DemInstruction(\"\")\n\n    with pytest.raises(ValueError, match=\"single DemInstruction\"):\n        stim.DemInstruction(\"\"\"\n            repeat 5 {\n                error(0.25) D0\n                shift_detectors 1\n            }\n        \"\"\")\n\n    with pytest.raises(ValueError, match=\"single DemInstruction\"):\n        stim.DemInstruction(\"\"\"\n            detector D0\n            detector D1\n        \"\"\")\n\n\ndef test_tag():\n    assert stim.DemInstruction(\"error[test](0.25) D1\").tag == 'test'\n    assert stim.DemInstruction(\"error\", [0.25], [stim.DemTarget(\"D1\")], tag=\"test\").tag == 'test'\n    dem = stim.DetectorErrorModel('''\n        error[test-tag](0.125) D0\n        error(0.125) D0\n    ''')\n    assert dem[0].tag == 'test-tag'\n    assert dem[1].tag == ''\n"
  },
  {
    "path": "src/stim/dem/detector_error_model.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/dem/detector_error_model.h\"\n\n#include <cmath>\n#include <iomanip>\n#include <limits>\n\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\n\nvoid DetectorErrorModel::append_error_instruction(\n    double probability, SpanRef<const DemTarget> targets, std::string_view tag) {\n    append_dem_instruction(DemInstruction{&probability, targets, tag, DemInstructionType::DEM_ERROR});\n}\n\nvoid DetectorErrorModel::append_shift_detectors_instruction(\n    SpanRef<const double> coord_shift, uint64_t detector_shift, std::string_view tag) {\n    DemTarget shift{detector_shift};\n    append_dem_instruction(DemInstruction{coord_shift, &shift, tag, DemInstructionType::DEM_SHIFT_DETECTORS});\n}\n\nvoid DetectorErrorModel::append_detector_instruction(\n    SpanRef<const double> coords, DemTarget target, std::string_view tag) {\n    append_dem_instruction(DemInstruction{coords, &target, tag, DemInstructionType::DEM_DETECTOR});\n}\n\nvoid DetectorErrorModel::append_logical_observable_instruction(DemTarget target, std::string_view tag) {\n    append_dem_instruction(DemInstruction{{}, &target, tag, DemInstructionType::DEM_LOGICAL_OBSERVABLE});\n}\n\nvoid DetectorErrorModel::append_dem_instruction(const DemInstruction &instruction) {\n    assert(instruction.type != DemInstructionType::DEM_REPEAT_BLOCK);\n    instruction.validate();\n    auto stored_targets = target_buf.take_copy(instruction.target_data);\n    auto stored_args = arg_buf.take_copy(instruction.arg_data);\n    auto tag = tag_buf.take_copy(instruction.tag);\n    instructions.push_back(DemInstruction{stored_args, stored_targets, tag, instruction.type});\n}\n\nvoid DetectorErrorModel::append_repeat_block(uint64_t repeat_count, DetectorErrorModel &&body, std::string_view tag) {\n    std::array<DemTarget, 2> data;\n    data[0].data = repeat_count;\n    data[1].data = blocks.size();\n    auto stored_targets = target_buf.take_copy(data);\n    blocks.push_back(std::move(body));\n    tag = tag_buf.take_copy(tag);\n    instructions.push_back({{}, stored_targets, tag, DemInstructionType::DEM_REPEAT_BLOCK});\n}\n\nvoid DetectorErrorModel::append_repeat_block(\n    uint64_t repeat_count, const DetectorErrorModel &body, std::string_view tag) {\n    DemTarget data[2];\n    data[0].data = repeat_count;\n    data[1].data = blocks.size();\n    auto stored_targets = target_buf.take_copy({&data[0], &data[2]});\n    blocks.push_back(body);\n    tag = tag_buf.take_copy(tag);\n    instructions.push_back({{}, stored_targets, tag, DemInstructionType::DEM_REPEAT_BLOCK});\n}\n\nbool DetectorErrorModel::operator==(const DetectorErrorModel &other) const {\n    return instructions == other.instructions && blocks == other.blocks;\n}\nbool DetectorErrorModel::operator!=(const DetectorErrorModel &other) const {\n    return !(*this == other);\n}\nbool DetectorErrorModel::approx_equals(const DetectorErrorModel &other, double atol) const {\n    if (instructions.size() != other.instructions.size() || blocks.size() != other.blocks.size()) {\n        return false;\n    }\n    for (size_t k = 0; k < instructions.size(); k++) {\n        if (!instructions[k].approx_equals(other.instructions[k], atol)) {\n            return false;\n        }\n    }\n    for (size_t k = 0; k < blocks.size(); k++) {\n        if (!blocks[k].approx_equals(other.blocks[k], atol)) {\n            return false;\n        }\n    }\n    return true;\n}\nstd::string DetectorErrorModel::str() const {\n    std::stringstream s;\n    s << *this;\n    return s.str();\n}\n\nvoid stim::print_detector_error_model(std::ostream &out, const DetectorErrorModel &v, size_t indent) {\n    bool first = true;\n    for (const auto &e : v.instructions) {\n        if (first) {\n            first = false;\n        } else {\n            out << \"\\n\";\n        }\n        for (size_t k = 0; k < indent; k++) {\n            out << \" \";\n        }\n        if (e.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            out << \"repeat\";\n            if (!e.tag.empty()) {\n                out << '[';\n                write_tag_escaped_string_to(e.tag, out);\n                out << ']';\n            }\n            out << \" \" << e.repeat_block_rep_count() << \" {\\n\";\n            print_detector_error_model(out, e.repeat_block_body(v), indent + 4);\n            out << \"\\n\";\n            for (size_t k = 0; k < indent; k++) {\n                out << \" \";\n            }\n            out << \"}\";\n        } else {\n            out << e;\n        }\n    }\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const DetectorErrorModel &v) {\n    out << std::setprecision(std::numeric_limits<long double>::digits10 + 1);\n    print_detector_error_model(out, v, 0);\n    return out;\n}\n\nDetectorErrorModel::DetectorErrorModel() {\n}\n\nDetectorErrorModel::DetectorErrorModel(const DetectorErrorModel &other)\n    : arg_buf(other.arg_buf.total_allocated()),\n      target_buf(other.target_buf.total_allocated()),\n      tag_buf(other.tag_buf.total_allocated()),\n      instructions(other.instructions),\n      blocks(other.blocks) {\n    // Keep local copy of buffer data.\n    for (auto &e : instructions) {\n        e.arg_data = arg_buf.take_copy(e.arg_data);\n        e.target_data = target_buf.take_copy(e.target_data);\n        e.tag = tag_buf.take_copy(e.tag);\n    }\n}\n\nDetectorErrorModel::DetectorErrorModel(DetectorErrorModel &&other) noexcept\n    : arg_buf(std::move(other.arg_buf)),\n      target_buf(std::move(other.target_buf)),\n      tag_buf(std::move(other.tag_buf)),\n      instructions(std::move(other.instructions)),\n      blocks(std::move(other.blocks)) {\n}\n\nDetectorErrorModel &DetectorErrorModel::operator=(const DetectorErrorModel &other) {\n    if (&other != this) {\n        instructions = other.instructions;\n        blocks = other.blocks;\n\n        // Keep local copy of operation data.\n        arg_buf = MonotonicBuffer<double>(other.arg_buf.total_allocated());\n        target_buf = MonotonicBuffer<DemTarget>(other.target_buf.total_allocated());\n        tag_buf = MonotonicBuffer<char>(other.tag_buf.total_allocated());\n        for (auto &e : instructions) {\n            e.arg_data = arg_buf.take_copy(e.arg_data);\n            e.target_data = target_buf.take_copy(e.target_data);\n            e.tag = tag_buf.take_copy(e.tag);\n        }\n    }\n    return *this;\n}\n\nDetectorErrorModel &DetectorErrorModel::operator=(DetectorErrorModel &&other) noexcept {\n    if (&other != this) {\n        instructions = std::move(other.instructions);\n        blocks = std::move(other.blocks);\n        arg_buf = std::move(other.arg_buf);\n        target_buf = std::move(other.target_buf);\n        tag_buf = std::move(other.tag_buf);\n    }\n    return *this;\n}\n\nenum class DEM_READ_CONDITION {\n    DEM_READ_AS_LITTLE_AS_POSSIBLE,\n    DEM_READ_UNTIL_END_OF_BLOCK,\n    DEM_READ_UNTIL_END_OF_FILE,\n};\n\ninline bool is_name_char(int c) {\n    return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_';\n}\n\ntemplate <typename SOURCE>\ninline DemInstructionType read_instruction_name(int &c, SOURCE read_char) {\n    char name_buf[32];\n    size_t n = 0;\n    while (is_name_char(c) && n < sizeof(name_buf) - 1) {\n        name_buf[n] = tolower((char)c);\n        c = read_char();\n        n++;\n    }\n    name_buf[n] = 0;\n    if (!strcmp(name_buf, \"error\")) {\n        return DemInstructionType::DEM_ERROR;\n    }\n    if (!strcmp(name_buf, \"shift_detectors\")) {\n        return DemInstructionType::DEM_SHIFT_DETECTORS;\n    }\n    if (!strcmp(name_buf, \"detector\")) {\n        return DemInstructionType::DEM_DETECTOR;\n    }\n    if (!strcmp(name_buf, \"logical_observable\")) {\n        return DemInstructionType::DEM_LOGICAL_OBSERVABLE;\n    }\n    if (!strcmp(name_buf, \"repeat\")) {\n        return DemInstructionType::DEM_REPEAT_BLOCK;\n    }\n    throw std::out_of_range(\"Unrecognized instruction name: \" + std::string(name_buf));\n}\n\ntemplate <typename SOURCE>\nuint64_t read_uint60_t(int &c, SOURCE read_char) {\n    if (!(c >= '0' && c <= '9')) {\n        throw std::invalid_argument(\"Expected a digit but got '\" + std::string(1, c) + \"'\");\n    }\n    uint64_t result = 0;\n    do {\n        result *= 10;\n        result += c - '0';\n        if (result >= uint64_t{1} << 60) {\n            throw std::out_of_range(\"Number too large.\");\n        }\n        c = read_char();\n    } while (c >= '0' && c <= '9');\n    return result;\n}\n\ntemplate <typename SOURCE>\ninline void read_arbitrary_dem_targets_into(int &c, SOURCE read_char, DetectorErrorModel &model) {\n    while (read_until_next_line_arg(c, read_char)) {\n        switch (c) {\n            case 'd':\n            case 'D':\n                c = read_char();\n                model.target_buf.append_tail(DemTarget::relative_detector_id(read_uint60_t(c, read_char)));\n                break;\n            case 'l':\n            case 'L':\n                c = read_char();\n                model.target_buf.append_tail(DemTarget::observable_id(read_uint60_t(c, read_char)));\n                break;\n            case '^':\n                c = read_char();\n                model.target_buf.append_tail(DemTarget::separator());\n                break;\n            default:\n                throw std::invalid_argument(\"Unrecognized target prefix '\" + std::string(1, c) + \"'.\");\n        }\n    }\n}\n\ntemplate <typename SOURCE>\nvoid dem_read_instruction(DetectorErrorModel &model, char lead_char, SOURCE read_char) {\n    int c = lead_char;\n    DemInstructionType type = read_instruction_name(c, read_char);\n    std::string_view tail_tag;\n    try {\n        read_tag(c, \"\", read_char, model.tag_buf);\n        if (!model.tag_buf.tail.empty()) {\n            tail_tag = std::string_view(model.tag_buf.tail.ptr_start, model.tag_buf.tail.size());\n        }\n        if (type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            if (!read_until_next_line_arg(c, read_char)) {\n                throw std::invalid_argument(\"Missing repeat count of repeat block.\");\n            }\n            model.target_buf.append_tail(DemTarget{read_uint60_t(c, read_char)});\n            if (read_until_next_line_arg(c, read_char)) {\n                throw std::invalid_argument(\"Too many numeric values given to repeat block.\");\n            }\n            if (c != '{') {\n                throw std::invalid_argument(\"Missing '{' at start of repeat block.\");\n            }\n        } else {\n            read_parens_arguments(c, \"detector error model instruction\", read_char, model.arg_buf);\n            if (type == DemInstructionType::DEM_SHIFT_DETECTORS) {\n                if (read_until_next_line_arg(c, read_char)) {\n                    model.target_buf.append_tail(DemTarget{read_uint60_t(c, read_char)});\n                }\n            }\n            read_arbitrary_dem_targets_into(c, read_char, model);\n            if (c == '{') {\n                throw std::invalid_argument(\"Unexpected '{'.\");\n            }\n            DemInstruction{model.arg_buf.tail, model.target_buf.tail, tail_tag, type}.validate();\n        }\n    } catch (const std::invalid_argument &) {\n        model.tag_buf.discard_tail();\n        model.target_buf.discard_tail();\n        model.arg_buf.discard_tail();\n        throw;\n    }\n\n    model.tag_buf.commit_tail();\n    model.instructions.push_back(\n        DemInstruction{\n            .arg_data = model.arg_buf.commit_tail(),\n            .target_data = model.target_buf.commit_tail(),\n            .tag = tail_tag,\n            .type = type,\n        });\n}\n\ntemplate <typename SOURCE>\nvoid model_read_operations(DetectorErrorModel &model, SOURCE read_char, DEM_READ_CONDITION read_condition) {\n    auto &ops = model.instructions;\n    do {\n        int c = read_char();\n        read_past_dead_space_between_commands(c, read_char);\n        if (c == EOF) {\n            if (read_condition == DEM_READ_CONDITION::DEM_READ_UNTIL_END_OF_BLOCK) {\n                throw std::out_of_range(\"Unterminated block. Got a '{' without an eventual '}'.\");\n            }\n            return;\n        }\n        if (c == '}') {\n            if (read_condition != DEM_READ_CONDITION::DEM_READ_UNTIL_END_OF_BLOCK) {\n                throw std::out_of_range(\"Uninitiated block. Got a '}' without a '{'.\");\n            }\n            return;\n        }\n        dem_read_instruction(model, c, read_char);\n\n        if (ops.back().type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            // Temporarily remove instruction until block is parsed.\n            auto repeat_count = ops.back().repeat_block_rep_count();\n            auto tag = ops.back().tag;\n            ops.pop_back();\n\n            // Recursively read the block contents.\n            DetectorErrorModel block;\n            model_read_operations(block, read_char, DEM_READ_CONDITION::DEM_READ_UNTIL_END_OF_BLOCK);\n\n            // Restore repeat block instruction, including block reference.\n            model.append_repeat_block(repeat_count, std::move(block), tag);\n        }\n    } while (read_condition != DEM_READ_CONDITION::DEM_READ_AS_LITTLE_AS_POSSIBLE);\n}\n\nvoid DetectorErrorModel::append_from_file(FILE *file, bool stop_asap) {\n    model_read_operations(\n        *this,\n        [&]() {\n            return getc(file);\n        },\n        stop_asap ? DEM_READ_CONDITION::DEM_READ_AS_LITTLE_AS_POSSIBLE\n                  : DEM_READ_CONDITION::DEM_READ_UNTIL_END_OF_FILE);\n}\n\nvoid DetectorErrorModel::append_from_text(std::string_view text) {\n    size_t k = 0;\n    model_read_operations(\n        *this,\n        [&]() {\n            return k < text.size() ? text[k++] : EOF;\n        },\n        DEM_READ_CONDITION::DEM_READ_UNTIL_END_OF_FILE);\n}\n\nDetectorErrorModel DetectorErrorModel::from_file(FILE *file) {\n    DetectorErrorModel result;\n    result.append_from_file(file, false);\n    return result;\n}\n\nDetectorErrorModel::DetectorErrorModel(std::string_view text) {\n    append_from_text(text);\n}\nvoid DetectorErrorModel::clear() {\n    target_buf.clear();\n    arg_buf.clear();\n    instructions.clear();\n    blocks.clear();\n}\n\nDetectorErrorModel DetectorErrorModel::rounded(uint8_t digits) const {\n    double scale = 1;\n    for (size_t k = 0; k < digits; k++) {\n        scale *= 10;\n    }\n\n    DetectorErrorModel result;\n    for (const auto &e : instructions) {\n        if (e.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            auto reps = e.repeat_block_rep_count();\n            auto &block = e.repeat_block_body(*this);\n            result.append_repeat_block(reps, block.rounded(digits), e.tag);\n        } else if (e.type == DemInstructionType::DEM_ERROR) {\n            std::vector<double> rounded_args;\n            for (auto a : e.arg_data) {\n                rounded_args.push_back(round(a * scale) / scale);\n            }\n            result.append_dem_instruction({rounded_args, e.target_data, e.tag, DemInstructionType::DEM_ERROR});\n        } else {\n            result.append_dem_instruction(e);\n        }\n    }\n    return result;\n}\n\nuint64_t DetectorErrorModel::total_detector_shift() const {\n    uint64_t result = 0;\n    for (const auto &e : instructions) {\n        if (e.type == DemInstructionType::DEM_SHIFT_DETECTORS) {\n            result += e.target_data[0].data;\n        } else if (e.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            result += e.repeat_block_rep_count() * e.repeat_block_body(*this).total_detector_shift();\n        }\n    }\n    return result;\n}\n\nvoid flattened_helper(\n    const DetectorErrorModel &body,\n    std::vector<double> &cur_coordinate_shift,\n    uint64_t &cur_detector_shift,\n    DetectorErrorModel &out) {\n    for (const auto &op : body.instructions) {\n        if (op.type == DemInstructionType::DEM_SHIFT_DETECTORS) {\n            while (cur_coordinate_shift.size() < op.arg_data.size()) {\n                cur_coordinate_shift.push_back(0);\n            }\n            for (size_t k = 0; k < op.arg_data.size(); k++) {\n                cur_coordinate_shift[k] += op.arg_data[k];\n            }\n            if (!op.target_data.empty()) {\n                cur_detector_shift += op.target_data[0].data;\n            }\n        } else if (op.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            const auto &loop_body = op.repeat_block_body(body);\n            auto reps = op.repeat_block_rep_count();\n            for (uint64_t k = 0; k < reps; k++) {\n                flattened_helper(loop_body, cur_coordinate_shift, cur_detector_shift, out);\n            }\n        } else if (op.type == DemInstructionType::DEM_LOGICAL_OBSERVABLE) {\n            out.append_dem_instruction(\n                DemInstruction{{}, op.target_data, op.tag, DemInstructionType::DEM_LOGICAL_OBSERVABLE});\n        } else if (op.type == DemInstructionType::DEM_DETECTOR) {\n            while (cur_coordinate_shift.size() < op.arg_data.size()) {\n                cur_coordinate_shift.push_back(0);\n            }\n\n            std::vector<double> shifted_coords;\n            for (size_t k = 0; k < op.arg_data.size(); k++) {\n                shifted_coords.push_back(op.arg_data[k] + cur_coordinate_shift[k]);\n            }\n            std::vector<DemTarget> shifted_detectors;\n            for (DemTarget t : op.target_data) {\n                t.shift_if_detector_id(cur_detector_shift);\n                shifted_detectors.push_back(t);\n            }\n\n            out.append_dem_instruction(\n                DemInstruction{shifted_coords, shifted_detectors, op.tag, DemInstructionType::DEM_DETECTOR});\n        } else if (op.type == DemInstructionType::DEM_ERROR) {\n            std::vector<DemTarget> shifted_detectors;\n            for (DemTarget t : op.target_data) {\n                t.shift_if_detector_id(cur_detector_shift);\n                shifted_detectors.push_back(t);\n            }\n\n            out.append_dem_instruction(\n                DemInstruction{op.arg_data, shifted_detectors, op.tag, DemInstructionType::DEM_ERROR});\n        } else {\n            throw std::invalid_argument(\"Unrecognized instruction type: \" + op.str());\n        }\n    }\n}\n\nDetectorErrorModel DetectorErrorModel::flattened() const {\n    DetectorErrorModel result;\n    std::vector<double> shift;\n    uint64_t det_shift = 0;\n    flattened_helper(*this, shift, det_shift, result);\n    return result;\n}\n\nuint64_t DetectorErrorModel::count_detectors() const {\n    uint64_t offset = 1;\n    uint64_t max_num = 0;\n    for (const auto &e : instructions) {\n        switch (e.type) {\n            case DemInstructionType::DEM_LOGICAL_OBSERVABLE:\n                break;\n            case DemInstructionType::DEM_SHIFT_DETECTORS:\n                offset += e.target_data[0].data;\n                break;\n            case DemInstructionType::DEM_REPEAT_BLOCK: {\n                auto &block = e.repeat_block_body(*this);\n                auto n = block.count_detectors();\n                auto reps = e.repeat_block_rep_count();\n                auto block_shift = block.total_detector_shift();  // Note: quadratic overhead in nesting level.\n                offset += block_shift * reps;\n                if (reps > 0 && n > 0) {\n                    max_num = std::max(max_num, offset + n - 1 - block_shift);\n                }\n            } break;\n            case DemInstructionType::DEM_DETECTOR:\n            case DemInstructionType::DEM_ERROR:\n                for (const auto &t : e.target_data) {\n                    if (t.is_relative_detector_id()) {\n                        max_num = std::max(max_num, offset + t.raw_id());\n                    }\n                }\n                break;\n            default:\n                throw std::invalid_argument(\"Instruction type not implemented in count_detectors: \" + e.str());\n        }\n    }\n    return max_num;\n}\n\nuint64_t DetectorErrorModel::count_errors() const {\n    uint64_t total = 0;\n    for (const auto &e : instructions) {\n        switch (e.type) {\n            case DemInstructionType::DEM_LOGICAL_OBSERVABLE:\n                break;\n            case DemInstructionType::DEM_SHIFT_DETECTORS:\n                break;\n            case DemInstructionType::DEM_REPEAT_BLOCK: {\n                auto &block = e.repeat_block_body(*this);\n                auto n = block.count_errors();\n                auto reps = e.repeat_block_rep_count();\n                total += n * reps;\n                break;\n            }\n            case DemInstructionType::DEM_DETECTOR:\n                break;\n            case DemInstructionType::DEM_ERROR:\n                total++;\n                break;\n            default:\n                throw std::invalid_argument(\"Instruction type not implemented in count_errors: \" + e.str());\n        }\n    }\n    return total;\n}\n\nuint64_t DetectorErrorModel::count_observables() const {\n    uint64_t max_num = 0;\n    for (const auto &e : instructions) {\n        switch (e.type) {\n            case DemInstructionType::DEM_SHIFT_DETECTORS:\n            case DemInstructionType::DEM_DETECTOR:\n                break;\n            case DemInstructionType::DEM_REPEAT_BLOCK: {\n                auto &block = e.repeat_block_body(*this);\n                max_num = std::max(max_num, block.count_observables());\n            } break;\n            case DemInstructionType::DEM_LOGICAL_OBSERVABLE:\n            case DemInstructionType::DEM_ERROR:\n                for (const auto &t : e.target_data) {\n                    if (t.is_observable_id()) {\n                        max_num = std::max(max_num, t.raw_id() + 1);\n                    }\n                }\n                break;\n            default:\n                throw std::invalid_argument(\"Instruction type not implemented in count_observables: \" + e.str());\n        }\n    }\n    return max_num;\n}\n\nDetectorErrorModel DetectorErrorModel::py_get_slice(int64_t start, int64_t step, int64_t slice_length) const {\n    assert(slice_length >= 0);\n    assert(slice_length == 0 || start >= 0);\n    DetectorErrorModel result;\n    for (size_t k = 0; k < (size_t)slice_length; k++) {\n        const auto &op = instructions[start + step * k];\n        if (op.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            result.append_repeat_block(op.repeat_block_rep_count(), op.repeat_block_body(*this), op.tag);\n        } else {\n            auto args = result.arg_buf.take_copy(op.arg_data);\n            auto targets = result.target_buf.take_copy(op.target_data);\n            result.instructions.push_back(DemInstruction{args, targets, op.tag, op.type});\n        }\n    }\n    return result;\n}\n\nDetectorErrorModel DetectorErrorModel::operator*(size_t repetitions) const {\n    DetectorErrorModel copy = *this;\n    copy *= repetitions;\n    return copy;\n}\n\nDetectorErrorModel &DetectorErrorModel::operator*=(size_t repetitions) {\n    if (repetitions == 0) {\n        clear();\n    }\n    if (repetitions <= 1) {\n        return *this;\n    }\n    DetectorErrorModel other = std::move(*this);\n    clear();\n    append_repeat_block(repetitions, std::move(other), \"\");\n    return *this;\n}\n\nDetectorErrorModel DetectorErrorModel::operator+(const DetectorErrorModel &other) const {\n    DetectorErrorModel result = *this;\n    result += other;\n    return result;\n}\n\nDetectorErrorModel &DetectorErrorModel::operator+=(const DetectorErrorModel &other) {\n    if (&other == this) {\n        instructions.insert(instructions.end(), instructions.begin(), instructions.end());\n        return *this;\n    }\n\n    for (auto &e : other.instructions) {\n        if (e.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            uint64_t repeat_count = e.repeat_block_rep_count();\n            const DetectorErrorModel &block = e.repeat_block_body(other);\n            append_repeat_block(repeat_count, block, e.tag);\n        } else {\n            append_dem_instruction(e);\n        }\n    }\n    return *this;\n}\n\nstd::pair<uint64_t, std::vector<double>> DetectorErrorModel::final_detector_and_coord_shift() const {\n    uint64_t detector_offset = 0;\n    std::vector<double> coord_shift;\n    for (const auto &op : instructions) {\n        if (op.type == DemInstructionType::DEM_SHIFT_DETECTORS) {\n            vec_pad_add_mul(coord_shift, op.arg_data);\n            detector_offset += op.target_data[0].data;\n        } else if (op.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            const auto &block = op.repeat_block_body(*this);\n            uint64_t reps = op.repeat_block_rep_count();\n            auto rec = block.final_detector_and_coord_shift();\n            vec_pad_add_mul(coord_shift, rec.second, reps);\n            detector_offset += reps * rec.first;\n        }\n    }\n    return {detector_offset, coord_shift};\n}\n\nbool get_detector_coordinates_helper(\n    const DetectorErrorModel &dem,\n    const std::set<uint64_t> &included_detector_indices,\n    std::set<uint64_t>::const_iterator &iter_desired_detector_index,\n    std::vector<double> &coord_shift,\n    uint64_t &detector_offset,\n    std::map<uint64_t, std::vector<double>> &out,\n    bool top) {\n    if (iter_desired_detector_index == included_detector_indices.end()) {\n        return true;\n    }\n\n    // Fills in data for a detector that was found while iterating.\n    // Returns true if all data has been filled in.\n    auto fill_in_data = [&](uint64_t fill_index, SpanRef<const double> fill_data) {\n        if (!included_detector_indices.contains(fill_index)) {\n            // Not interested in the index for this data.\n            return false;\n        }\n        if (out.contains(fill_index)) {\n            // Already have this data. Detector may have been declared twice?\n            return false;\n        }\n\n        // Write data to result dictionary.\n        std::vector<double> det_coords;\n        det_coords.reserve(fill_data.size());\n        for (size_t k = 0; k < fill_data.size(); k++) {\n            det_coords.push_back(fill_data[k]);\n            if (k < coord_shift.size()) {\n                det_coords[k] += coord_shift[k];\n            }\n        }\n        out[fill_index] = std::move(det_coords);\n\n        // Advance the iterator past values that have been written in.\n        // If the end has been reached, we're done.\n        while (out.contains(*iter_desired_detector_index)) {\n            ++iter_desired_detector_index;\n            if (iter_desired_detector_index == included_detector_indices.end()) {\n                return true;\n            }\n        }\n\n        return false;\n    };\n\n    for (const auto &op : dem.instructions) {\n        if (op.type == DemInstructionType::DEM_SHIFT_DETECTORS) {\n            vec_pad_add_mul(coord_shift, op.arg_data);\n            detector_offset += op.target_data[0].data;\n            while (*iter_desired_detector_index < detector_offset) {\n                // Shifting past an index proves that it will never be given data.\n                // So set the coordinate data to the empty list.\n                if (fill_in_data(*iter_desired_detector_index, {})) {\n                    return true;\n                }\n            }\n\n        } else if (op.type == DemInstructionType::DEM_DETECTOR) {\n            for (const auto &t : op.target_data) {\n                if (fill_in_data(t.data + detector_offset, op.arg_data)) {\n                    return true;\n                }\n            }\n\n        } else if (op.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            const auto &block = op.repeat_block_body(dem);\n            uint64_t reps = op.repeat_block_rep_count();\n\n            // TODO: Finish in time proportional to len(instructions) + len(desired) instead of len(execution).\n            for (uint64_t k = 0; k < reps; k++) {\n                if (get_detector_coordinates_helper(\n                        block,\n                        included_detector_indices,\n                        iter_desired_detector_index,\n                        coord_shift,\n                        detector_offset,\n                        out,\n                        false)) {\n                    return true;\n                }\n            }\n        }\n    }\n\n    // If we've reached the end of the detector error model, then all remaining\n    // values should be given empty data.\n    if (top && out.size() < included_detector_indices.size()) {\n        uint64_t n = dem.count_detectors();\n        while (*iter_desired_detector_index < n) {\n            if (fill_in_data(*iter_desired_detector_index, {})) {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nstd::map<uint64_t, std::vector<double>> DetectorErrorModel::get_detector_coordinates(\n    const std::set<uint64_t> &included_detector_indices) const {\n    std::map<uint64_t, std::vector<double>> out;\n    uint64_t detector_offset = 0;\n    std::set<uint64_t>::const_iterator iter = included_detector_indices.begin();\n    std::vector<double> coord_shift;\n    get_detector_coordinates_helper(*this, included_detector_indices, iter, coord_shift, detector_offset, out, true);\n\n    if (iter != included_detector_indices.end()) {\n        std::stringstream msg;\n        msg << \"Detector index \" << *iter << \" is too big. The detector error model has \";\n        msg << count_detectors() << \" detectors)\";\n        throw std::invalid_argument(msg.str());\n    }\n\n    return out;\n}\n\nDetectorErrorModel DetectorErrorModel::without_tags() const {\n    DetectorErrorModel result;\n    for (DemInstruction inst : instructions) {\n        if (inst.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n            result.append_repeat_block(inst.repeat_block_rep_count(), inst.repeat_block_body(*this).without_tags(), \"\");\n        } else {\n            inst.tag = \"\";\n            result.append_dem_instruction(inst);\n        }\n    }\n    return result;\n}\n"
  },
  {
    "path": "src/stim/dem/detector_error_model.h",
    "content": "#ifndef _STIM_DEM_DETECTOR_ERROR_MODEL_H\n#define _STIM_DEM_DETECTOR_ERROR_MODEL_H\n\n#include <memory>\n#include <set>\n#include <string>\n#include <vector>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/dem/dem_instruction.h\"\n#include \"stim/mem/monotonic_buffer.h\"\n\nnamespace stim {\n\nstruct DetectorErrorModel {\n    MonotonicBuffer<double> arg_buf;\n    MonotonicBuffer<DemTarget> target_buf;\n    MonotonicBuffer<char> tag_buf;\n    std::vector<DemInstruction> instructions;\n    std::vector<DetectorErrorModel> blocks;\n\n    /// Constructs an empty detector error model.\n    DetectorErrorModel();\n    /// Parses a detector error model from the given text.\n    explicit DetectorErrorModel(std::string_view text);\n\n    /// Copy constructor.\n    DetectorErrorModel(const DetectorErrorModel &other);\n    /// Move constructor.\n    DetectorErrorModel(DetectorErrorModel &&other) noexcept;\n    /// Copy assignment.\n    DetectorErrorModel &operator=(const DetectorErrorModel &other);\n    /// Move assignment.\n    DetectorErrorModel &operator=(DetectorErrorModel &&other) noexcept;\n\n    DetectorErrorModel &operator*=(size_t repetitions);\n    DetectorErrorModel operator*(size_t repetitions) const;\n    DetectorErrorModel operator+(const DetectorErrorModel &other) const;\n    DetectorErrorModel &operator+=(const DetectorErrorModel &other);\n\n    void append_dem_instruction(const DemInstruction &instruction);\n    void append_error_instruction(double probability, SpanRef<const DemTarget> targets, std::string_view tag);\n    void append_shift_detectors_instruction(\n        SpanRef<const double> coord_shift, uint64_t detector_shift, std::string_view tag);\n    void append_detector_instruction(SpanRef<const double> coords, DemTarget target, std::string_view tag);\n    void append_logical_observable_instruction(DemTarget target, std::string_view tag);\n    void append_repeat_block(uint64_t repeat_count, DetectorErrorModel &&body, std::string_view tag);\n    void append_repeat_block(uint64_t repeat_count, const DetectorErrorModel &body, std::string_view tag);\n\n    /// Grows the detector error model using operations from a string.\n    void append_from_text(std::string_view text);\n    /// Grows the detector error model using operations from a file.\n    ///\n    /// Args:\n    ///     file: The opened file to read from.\n    ///     stop_asap: When set to true, the reading process stops after the next instruction or block is read. This is\n    ///         potentially useful for interactive/streaming usage, where errors are being processed on the fly.\n    void append_from_file(FILE *file, bool stop_asap = false);\n    /// Parses a detector error model from a file.\n    static DetectorErrorModel from_file(FILE *file);\n\n    bool operator==(const DetectorErrorModel &other) const;\n    bool operator!=(const DetectorErrorModel &other) const;\n    bool approx_equals(const DetectorErrorModel &other, double atol) const;\n    std::string str() const;\n\n    DetectorErrorModel without_tags() const;\n\n    uint64_t total_detector_shift() const;\n    uint64_t count_detectors() const;\n    uint64_t count_observables() const;\n    uint64_t count_errors() const;\n\n    std::pair<uint64_t, std::vector<double>> final_detector_and_coord_shift() const;\n    std::map<uint64_t, std::vector<double>> get_detector_coordinates(\n        const std::set<uint64_t> &included_detector_indices) const;\n\n    void clear();\n\n   private:\n    template <typename CALLBACK>\n    void iter_flatten_error_instructions_helper(const CALLBACK &callback, uint64_t &detector_shift) const {\n        std::vector<DemTarget> translate_buf;\n        for (const auto &op : instructions) {\n            switch (op.type) {\n                case DemInstructionType::DEM_ERROR:\n                    translate_buf.clear();\n                    translate_buf.insert(translate_buf.end(), op.target_data.begin(), op.target_data.end());\n                    for (auto &t : translate_buf) {\n                        t.shift_if_detector_id((int64_t)detector_shift);\n                    }\n                    callback(DemInstruction{op.arg_data, translate_buf, op.tag, op.type});\n                    break;\n                case DemInstructionType::DEM_REPEAT_BLOCK: {\n                    const auto &block = op.repeat_block_body(*this);\n                    auto reps = op.repeat_block_rep_count();\n                    for (uint64_t k = 0; k < reps; k++) {\n                        block.iter_flatten_error_instructions_helper(callback, detector_shift);\n                    }\n                    break;\n                }\n                case DemInstructionType::DEM_SHIFT_DETECTORS:\n                    detector_shift += op.target_data[0].data;\n                    break;\n                case DemInstructionType::DEM_DETECTOR:\n                case DemInstructionType::DEM_LOGICAL_OBSERVABLE:\n                    break;\n                default:\n                    throw std::invalid_argument(\"Unrecognized DEM instruction type: \" + op.str());\n            }\n        }\n    }\n\n   public:\n    /// Iterates through the error model, invoking the given callback on each found error mechanism.\n    ///\n    /// Automatically flattens `repeat` blocks into repeated instructions.\n    /// Automatically folds `shift_detectors` instructions into adjusted indices of later error instructions.\n    ///\n    /// Args:\n    ///     callback: A function that takes a DemInstruction and returns no value. This function will be invoked once\n    ///         for each error instruction. The DemInstruction's arg_data will contain a single value (the error's\n    ///         probability) and the absolute targets of the error.\n    template <typename CALLBACK>\n    void iter_flatten_error_instructions(const CALLBACK &callback) const {\n        uint64_t offset = 0;\n        iter_flatten_error_instructions_helper(callback, offset);\n    }\n\n    /// Gets a python-style slice of the error model's instructions.\n    DetectorErrorModel py_get_slice(int64_t start, int64_t step, int64_t slice_length) const;\n\n    /// Rounds error probabilities to a given number of digits.\n    DetectorErrorModel rounded(uint8_t digits) const;\n\n    /// Returns an equivalent detector error model with no repeat blocks or detector_shift instructions.\n    DetectorErrorModel flattened() const;\n};\n\nvoid print_detector_error_model(std::ostream &out, const DetectorErrorModel &v, size_t indent);\nstd::ostream &operator<<(std::ostream &out, const DemInstructionType &type);\nstd::ostream &operator<<(std::ostream &out, const DetectorErrorModel &v);\nstd::ostream &operator<<(std::ostream &out, const DemTarget &v);\nstd::ostream &operator<<(std::ostream &out, const DemInstruction &v);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/dem/detector_error_model.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/dem/detector_error_model.pybind.h\"\n\n#include <fstream>\n\n#include \"stim/circuit/circuit.pybind.h\"\n#include \"stim/cmd/command_diagram.pybind.h\"\n#include \"stim/dem/dem_instruction.pybind.h\"\n#include \"stim/dem/detector_error_model_repeat_block.pybind.h\"\n#include \"stim/dem/detector_error_model_target.pybind.h\"\n#include \"stim/io/raii_file.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/search/search.h\"\n#include \"stim/simulators/dem_sampler.h\"\n\nusing namespace stim;\n\nstd::string stim_pybind::detector_error_model_repr(const DetectorErrorModel &self) {\n    if (self.instructions.empty()) {\n        return \"stim.DetectorErrorModel()\";\n    }\n    std::stringstream ss;\n    ss << \"stim.DetectorErrorModel('''\\n\";\n    print_detector_error_model(ss, self, 4);\n    ss << \"\\n''')\";\n    return ss.str();\n}\n\nstd::vector<double> python_arg_to_instruction_arguments(const pybind11::object &arg) {\n    if (arg.is_none()) {\n        return {};\n    }\n    try {\n        return {pybind11::cast<double>(arg)};\n    } catch (const pybind11::cast_error &) {\n    }\n    try {\n        return pybind11::cast<std::vector<double>>(arg);\n    } catch (const pybind11::cast_error &) {\n    }\n    throw std::invalid_argument(\"parens_arguments must be None, a double, or a list of doubles.\");\n}\n\nstatic DemInstructionType non_block_instruction_name_to_enum(std::string_view name) {\n    std::string low;\n    for (char c : name) {\n        low.push_back(tolower(c));\n    }\n    if (low == \"error\") {\n        return DemInstructionType::DEM_ERROR;\n    } else if (low == \"shift_detectors\") {\n        return DemInstructionType::DEM_SHIFT_DETECTORS;\n    } else if (low == \"detector\") {\n        return DemInstructionType::DEM_DETECTOR;\n    } else if (low == \"logical_observable\") {\n        return DemInstructionType::DEM_LOGICAL_OBSERVABLE;\n    }\n    throw std::invalid_argument(\"Not a non-block detector error model instruction name: \" + std::string(name));\n}\n\npybind11::class_<stim::DetectorErrorModel> stim_pybind::pybind_detector_error_model(pybind11::module &m) {\n    auto c = pybind11::class_<DetectorErrorModel>(\n        m,\n        \"DetectorErrorModel\",\n        clean_doc_string(R\"DOC(\n            An error model built out of independent error mechanics.\n\n            This class is one of the most important classes in Stim, because it is the\n            mechanism used to explain circuits to decoders. A typical workflow would\n            look something like:\n\n                1. Create a quantum error correction circuit annotated with detectors\n                    and observables.\n                2. Fail at configuring your favorite decoder using the circuit, because\n                    it's a pain to convert circuit error mechanisms into a format\n                    understood by the decoder.\n                2a. Call circuit.detector_error_model(), with decompose_errors=True\n                    if working with a matching-based code. This converts the circuit\n                    errors into a straightforward list of independent \"with\n                    probability p these detectors and observables get flipped\" terms.\n                3. Write tedious but straightforward glue code to create whatever\n                    graph-like object the decoder needs from the detector error model.\n                3a. Actually, ideally, someone has already done that for you. For\n                    example, pymatching can take detector error models directly and\n                    sinter knows how to explain a detector error model to fusion_blossom.\n                4. Get samples using circuit.compile_detector_sampler(), feed them to\n                    the decoder, and compare its observable flip predictions to the\n                    actual flips recorded in the samples.\n                4a. Actually, sinter will basically handle steps 2 through 4 for you.\n                    So you should probably have just generated your circuits, called\n                    `sinter collect` on them, then `sinter plot` on the results.\n                5. Write the paper.\n\n            Error mechanisms are described in terms of the visible detection events and the\n            hidden observable frame changes that they causes. Error mechanisms can also\n            suggest decompositions of their effects into components, which can be helpful\n            for decoders that want to work with a simpler decomposed error model instead of\n            the full error model.\n\n            Examples:\n                >>> import stim\n                >>> model = stim.DetectorErrorModel('''\n                ...     error(0.125) D0\n                ...     error(0.125) D0 D1 L0\n                ...     error(0.125) D1 D2\n                ...     error(0.125) D2 D3\n                ...     error(0.125) D3\n                ... ''')\n                >>> len(model)\n                5\n\n                >>> stim.Circuit('''\n                ...     X_ERROR(0.125) 0\n                ...     X_ERROR(0.25) 1\n                ...     CORRELATED_ERROR(0.375) X0 X1\n                ...     M 0 1\n                ...     DETECTOR rec[-2]\n                ...     DETECTOR rec[-1]\n                ... ''').detector_error_model()\n                stim.DetectorErrorModel('''\n                    error(0.125) D0\n                    error(0.375) D0 D1\n                    error(0.25) D1\n                ''')\n        )DOC\")\n            .data());\n\n    return c;\n}\n\nvoid stim_pybind::pybind_detector_error_model_methods(\n    pybind11::module &m, pybind11::class_<stim::DetectorErrorModel> &c) {\n    c.def(\n        pybind11::init([](const char *detector_error_model_text) {\n            DetectorErrorModel self;\n            self.append_from_text(detector_error_model_text);\n            return self;\n        }),\n        pybind11::arg(\"detector_error_model_text\") = \"\",\n        clean_doc_string(R\"DOC(\n            Creates a stim.DetectorErrorModel.\n\n            Args:\n                detector_error_model_text: Defaults to empty. Describes instructions to\n                    append into the circuit in the detector error model (.dem) format.\n\n            Examples:\n                >>> import stim\n                >>> empty = stim.DetectorErrorModel()\n                >>> not_empty = stim.DetectorErrorModel('''\n                ...    error(0.125) D0 L0\n                ... ''')\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_detectors\",\n        &DetectorErrorModel::count_detectors,\n        clean_doc_string(R\"DOC(\n            Counts the number of detectors (e.g. `D2`) in the error model.\n\n            Detector indices are assumed to be contiguous from 0 up to whatever the maximum\n            detector id is. If the largest detector's absolute id is n-1, then the number of\n            detectors is n.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     X_ERROR(0.125) 0\n                ...     X_ERROR(0.25) 1\n                ...     CORRELATED_ERROR(0.375) X0 X1\n                ...     M 0 1\n                ...     DETECTOR rec[-2]\n                ...     DETECTOR rec[-1]\n                ... ''').detector_error_model().num_detectors\n                2\n\n                >>> stim.DetectorErrorModel('''\n                ...    error(0.1) D0 D199\n                ... ''').num_detectors\n                200\n\n                >>> stim.DetectorErrorModel('''\n                ...    shift_detectors 1000\n                ...    error(0.1) D0 D199\n                ... ''').num_detectors\n                1200\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_errors\",\n        &DetectorErrorModel::count_errors,\n        clean_doc_string(R\"DOC(\n            Counts the number of errors (e.g. `error(0.1) D0`) in the error model.\n\n            Error instructions inside repeat blocks count once per repetition.\n            Redundant errors with the same targets count as separate errors.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.DetectorErrorModel('''\n                ...     error(0.125) D0\n                ...     repeat 100 {\n                ...         repeat 5 {\n                ...             error(0.25) D1\n                ...         }\n                ...     }\n                ... ''').num_errors\n                501\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_observables\",\n        &DetectorErrorModel::count_observables,\n        clean_doc_string(R\"DOC(\n            Counts the number of frame changes (e.g. `L2`) in the error model.\n\n            Observable indices are assumed to be contiguous from 0 up to whatever the\n            maximum observable id is. If the largest observable's id is n-1, then the number\n            of observables is n.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Circuit('''\n                ...     X_ERROR(0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(99) rec[-1]\n                ... ''').detector_error_model().num_observables\n                100\n\n                >>> stim.DetectorErrorModel('''\n                ...    error(0.1) L399\n                ... ''').num_observables\n                400\n        )DOC\")\n            .data());\n\n    c.def(\n        \"clear\",\n        &DetectorErrorModel::clear,\n        clean_doc_string(R\"DOC(\n            Clears the contents of the detector error model.\n\n            Examples:\n                >>> import stim\n                >>> model = stim.DetectorErrorModel('''\n                ...    error(0.1) D0 D1\n                ... ''')\n                >>> model.clear()\n                >>> model\n                stim.DetectorErrorModel()\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two detector error models have identical contents.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two detector error models have non-identical contents.\");\n\n    c.def(\n        \"__str__\",\n        &DetectorErrorModel::str,\n        clean_doc_string(R\"DOC(\n            Returns the contents of a detector error model file (.dem) encoding the model.\n        )DOC\")\n            .data());\n    c.def(\n        \"__repr__\",\n        &detector_error_model_repr,\n        clean_doc_string(R\"DOC(\n            Returns valid python code evaluating to an equivalent `stim.DetectorErrorModel`.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"copy\",\n        [](DetectorErrorModel &self) -> DetectorErrorModel {\n            return self;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the detector error model.\n\n            The copy is an independent detector error model with the same contents.\n\n            Examples:\n                >>> import stim\n\n                >>> c1 = stim.DetectorErrorModel(\"error(0.1) D0 D1\")\n                >>> c2 = c1.copy()\n                >>> c2 is c1\n                False\n                >>> c2 == c1\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__len__\",\n        [](const DetectorErrorModel &self) -> size_t {\n            return self.instructions.size();\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of top-level instructions/blocks in the detector error model.\n\n            Instructions inside of blocks are not included in this count.\n\n            Examples:\n                >>> import stim\n                >>> len(stim.DetectorErrorModel())\n                0\n                >>> len(stim.DetectorErrorModel('''\n                ...    error(0.1) D0 D1\n                ...    shift_detectors 100\n                ...    logical_observable L5\n                ... '''))\n                3\n                >>> len(stim.DetectorErrorModel('''\n                ...    repeat 100 {\n                ...        error(0.1) D0 D1\n                ...        error(0.1) D1 D2\n                ...    }\n                ... '''))\n                1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__getitem__\",\n        [](const DetectorErrorModel &self, const pybind11::object &index_or_slice) -> pybind11::object {\n            pybind11::ssize_t index, step, slice_length;\n            if (normalize_index_or_slice(index_or_slice, self.instructions.size(), &index, &step, &slice_length)) {\n                return pybind11::cast(self.py_get_slice(index, step, slice_length));\n            }\n\n            auto &op = self.instructions[index];\n            if (op.type == DemInstructionType::DEM_REPEAT_BLOCK) {\n                return pybind11::cast(ExposedDemRepeatBlock{op.repeat_block_rep_count(), op.repeat_block_body(self)});\n            }\n            ExposedDemInstruction result;\n            result.targets.insert(result.targets.begin(), op.target_data.begin(), op.target_data.end());\n            result.arguments.insert(result.arguments.begin(), op.arg_data.begin(), op.arg_data.end());\n            result.type = op.type;\n            result.tag = op.tag;\n            return pybind11::cast(result);\n        },\n        pybind11::arg(\"index_or_slice\"),\n        clean_doc_string(R\"DOC(\n            Returns copies of instructions from the detector error model.\n            @overload def __getitem__(self, index_or_slice: int) -> Union[stim.DemInstruction, stim.DemRepeatBlock]:\n            @overload def __getitem__(self, index_or_slice: slice) -> stim.DetectorErrorModel:\n\n            Args:\n                index_or_slice: An integer index picking out an instruction to return, or a\n                    slice picking out a range of instructions to return as a detector error\n                    model.\n\n            Examples:\n                >>> import stim\n                >>> model = stim.DetectorErrorModel('''\n                ...    error(0.125) D0\n                ...    error(0.125) D1 L1\n                ...    repeat 100 {\n                ...        error(0.125) D1 D2\n                ...        shift_detectors 1\n                ...    }\n                ...    error(0.125) D2\n                ...    logical_observable L0\n                ...    detector D5\n                ... ''')\n                >>> model[0]\n                stim.DemInstruction('error', [0.125], [stim.target_relative_detector_id(0)])\n                >>> model[2]\n                stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n                    error(0.125) D1 D2\n                    shift_detectors 1\n                '''))\n                >>> model[1::2]\n                stim.DetectorErrorModel('''\n                    error(0.125) D1 L1\n                    error(0.125) D2\n                    detector D5\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"approx_equals\",\n        [](const DetectorErrorModel &self, const pybind11::object &obj, double atol) -> bool {\n            try {\n                return self.approx_equals(pybind11::cast<DetectorErrorModel>(obj), atol);\n            } catch (const pybind11::cast_error &) {\n                return false;\n            }\n        },\n        pybind11::arg(\"other\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"atol\"),\n        clean_doc_string(R\"DOC(\n            Checks if detector error models are approximately equal.\n\n            Two detector error model are approximately equal if they are equal up to slight\n            perturbations of instruction arguments such as probabilities. For example\n            `error(0.100) D0` is approximately equal to `error(0.099) D0` within an absolute\n            tolerance of 0.002. All other details of the models (such as the ordering of\n            errors and their targets) must be exactly the same.\n\n            Args:\n                other: The detector error model, or other object, to compare to this one.\n                atol: The absolute error tolerance. The maximum amount each probability may\n                    have been perturbed by.\n\n            Returns:\n                True if the given object is a detector error model approximately equal up to\n                the receiving circuit up to the given tolerance, otherwise False.\n\n            Examples:\n                >>> import stim\n                >>> base = stim.DetectorErrorModel('''\n                ...    error(0.099) D0 D1\n                ... ''')\n\n                >>> base.approx_equals(base, atol=0)\n                True\n\n                >>> base.approx_equals(stim.DetectorErrorModel('''\n                ...    error(0.101) D0 D1\n                ... '''), atol=0)\n                False\n\n                >>> base.approx_equals(stim.DetectorErrorModel('''\n                ...    error(0.101) D0 D1\n                ... '''), atol=0.0001)\n                False\n\n                >>> base.approx_equals(stim.DetectorErrorModel('''\n                ...    error(0.101) D0 D1\n                ... '''), atol=0.01)\n                True\n\n                >>> base.approx_equals(stim.DetectorErrorModel('''\n                ...    error(0.099) D0 D1 L0 L1 L2 L3 L4\n                ... '''), atol=9999)\n                False\n        )DOC\")\n            .data());\n\n    c.def(\n        \"append\",\n        [](DetectorErrorModel &self,\n           const pybind11::object &instruction,\n           const pybind11::object &parens_arguments,\n           const std::vector<pybind11::object> &targets,\n           std::string_view tag) {\n            bool is_name = pybind11::isinstance<pybind11::str>(instruction);\n            if (!is_name && (!targets.empty() || !parens_arguments.is_none())) {\n                throw std::invalid_argument(\n                    \"Can't specify `parens_arguments` or `targets` when instruction is a \"\n                    \"stim.DemInstruction (instead of an instruction name).\");\n            }\n            if (is_name && (targets.empty() || parens_arguments.is_none())) {\n                throw std::invalid_argument(\n                    \"Must specify `parens_arguments` and `targets` when instruction is an instruction name.\");\n            }\n\n            if (is_name) {\n                std::string_view name = pybind11::cast<std::string_view>(instruction);\n                DemInstructionType type = non_block_instruction_name_to_enum(name);\n                std::vector<double> conv_args = python_arg_to_instruction_arguments(parens_arguments);\n                std::vector<DemTarget> conv_targets;\n                for (const auto &e : targets) {\n                    try {\n                        if (type == DemInstructionType::DEM_SHIFT_DETECTORS) {\n                            conv_targets.push_back(DemTarget{pybind11::cast<uint64_t>(e)});\n                        } else {\n                            conv_targets.push_back(DemTarget{pybind11::cast<ExposedDemTarget>(e).data});\n                        }\n                    } catch (pybind11::cast_error &) {\n                        std::stringstream ss;\n                        ss << \"Bad target '\";\n                        ss << pybind11::repr(e);\n                        ss << \"' for instruction '\";\n                        ss << name;\n                        ss << \"'.\";\n                        throw std::invalid_argument(ss.str());\n                    }\n                }\n\n                self.append_dem_instruction(\n                    DemInstruction{\n                        conv_args,\n                        conv_targets,\n                        tag,\n                        type,\n                    });\n            } else if (pybind11::isinstance<ExposedDemInstruction>(instruction)) {\n                const ExposedDemInstruction &exp = pybind11::cast<ExposedDemInstruction>(instruction);\n                self.append_dem_instruction(DemInstruction{exp.arguments, exp.targets, exp.tag, exp.type});\n            } else if (pybind11::isinstance<ExposedDemRepeatBlock>(instruction)) {\n                const ExposedDemRepeatBlock &block = pybind11::cast<ExposedDemRepeatBlock>(instruction);\n                self.append_repeat_block(block.repeat_count, block.body, block.tag);\n            } else if (pybind11::isinstance<DetectorErrorModel>(instruction)) {\n                self += pybind11::cast<DetectorErrorModel>(instruction);\n            } else {\n                throw std::invalid_argument(\n                    \"First argument to stim.DetectorErrorModel.append must be a str (an instruction name), \"\n                    \"a stim.DemInstruction, \"\n                    \"or a stim.DemRepeatBlock\");\n            }\n        },\n        pybind11::arg(\"instruction\"),\n        pybind11::arg(\"parens_arguments\") = pybind11::none(),\n        pybind11::arg(\"targets\") = pybind11::make_tuple(),\n        pybind11::kw_only(),\n        pybind11::arg(\"tag\") = \"\",\n        clean_doc_string(R\"DOC(\n            Appends an instruction to the detector error model.\n\n            Args:\n                instruction: Either the name of an instruction, a stim.DemInstruction, a\n                    stim.DemRepeatBlock. or a stim.DetectorErrorModel. The\n                    `parens_arguments`, `targets`, and 'tag' arguments should be given iff\n                    the instruction is a name.\n                parens_arguments: Numeric values parameterizing the instruction. The numbers\n                    inside parentheses in a detector error model file (eg. the `0.25` in\n                    `error(0.25) D0`). This argument can be given either a list of doubles,\n                    or a single double (which will be implicitly wrapped into a list).\n                targets: The instruction targets, such as the `D0` in `error(0.25) D0`.\n                tag: An arbitrary piece of text attached to the repeat instruction.\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel()\n                >>> m.append(\"error\", 0.125, [\n                ...     stim.DemTarget.relative_detector_id(1),\n                ... ])\n                >>> m.append(\"error\", 0.25, [\n                ...     stim.DemTarget.relative_detector_id(1),\n                ...     stim.DemTarget.separator(),\n                ...     stim.DemTarget.relative_detector_id(2),\n                ...     stim.DemTarget.logical_observable_id(3),\n                ... ], tag='test-tag')\n                >>> print(repr(m))\n                stim.DetectorErrorModel('''\n                    error(0.125) D1\n                    error[test-tag](0.25) D1 ^ D2 L3\n                ''')\n\n                >>> m.append(\"shift_detectors\", (1, 2, 3), [5])\n                >>> print(repr(m))\n                stim.DetectorErrorModel('''\n                    error(0.125) D1\n                    error[test-tag](0.25) D1 ^ D2 L3\n                    shift_detectors(1, 2, 3) 5\n                ''')\n\n                >>> m += m * 3\n                >>> m.append(m[0])\n                >>> m.append(m[-2])\n                >>> print(repr(m))\n                stim.DetectorErrorModel('''\n                    error(0.125) D1\n                    error[test-tag](0.25) D1 ^ D2 L3\n                    shift_detectors(1, 2, 3) 5\n                    repeat 3 {\n                        error(0.125) D1\n                        error[test-tag](0.25) D1 ^ D2 L3\n                        shift_detectors(1, 2, 3) 5\n                    }\n                    error(0.125) D1\n                    repeat 3 {\n                        error(0.125) D1\n                        error[test-tag](0.25) D1 ^ D2 L3\n                        shift_detectors(1, 2, 3) 5\n                    }\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__imul__\",\n        &DetectorErrorModel::operator*=,\n        pybind11::arg(\"repetitions\"),\n        clean_doc_string(R\"DOC(\n            Mutates the detector error model by putting its contents into a repeat block.\n\n            Special case: if the repetition count is 0, the model is cleared.\n            Special case: if the repetition count is 1, nothing happens.\n\n            Args:\n                repetitions: The number of times the repeat block should repeat.\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel('''\n                ...    error(0.25) D0\n                ...    shift_detectors 1\n                ... ''')\n                >>> m *= 3\n                >>> print(m)\n                repeat 3 {\n                    error(0.25) D0\n                    shift_detectors 1\n                }\n        )DOC\")\n            .data());\n\n    c.def(\n        \"get_detector_coordinates\",\n        [](const DetectorErrorModel &self, const pybind11::object &obj) {\n            return self.get_detector_coordinates(obj_to_abs_detector_id_set(obj, [&]() {\n                return self.count_detectors();\n            }));\n        },\n        pybind11::arg(\"only\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            Returns the coordinate metadata of detectors in the detector error model.\n\n            Args:\n                only: Defaults to None (meaning include all detectors). A list of detector\n                    indices to include in the result. Detector indices beyond the end of the\n                    detector error model cause an error.\n\n            Returns:\n                A dictionary mapping integers (detector indices) to lists of floats\n                (coordinates). Detectors with no specified coordinate data are mapped to an\n                empty tuple. If `only` is specified, then `set(result.keys()) == set(only)`.\n\n            Examples:\n                >>> import stim\n                >>> dem = stim.DetectorErrorModel('''\n                ...    error(0.25) D0 D1\n                ...    detector(1, 2, 3) D1\n                ...    shift_detectors(5) 1\n                ...    detector(1, 2) D2\n                ... ''')\n                >>> dem.get_detector_coordinates()\n                {0: [], 1: [1.0, 2.0, 3.0], 2: [], 3: [6.0, 2.0]}\n                >>> dem.get_detector_coordinates(only=[1])\n                {1: [1.0, 2.0, 3.0]}\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__add__\",\n        &DetectorErrorModel::operator+,\n        pybind11::arg(\"second\"),\n        clean_doc_string(R\"DOC(\n            Creates a detector error model by appending two models.\n\n            Examples:\n                >>> import stim\n                >>> m1 = stim.DetectorErrorModel('''\n                ...    error(0.125) D0\n                ... ''')\n                >>> m2 = stim.DetectorErrorModel('''\n                ...    error(0.25) D1\n                ... ''')\n                >>> m1 + m2\n                stim.DetectorErrorModel('''\n                    error(0.125) D0\n                    error(0.25) D1\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__iadd__\",\n        &DetectorErrorModel::operator+=,\n        pybind11::arg(\"second\"),\n        clean_doc_string(R\"DOC(\n            Appends a detector error model into the receiving model (mutating it).\n\n            Examples:\n                >>> import stim\n                >>> m1 = stim.DetectorErrorModel('''\n                ...    error(0.125) D0\n                ... ''')\n                >>> m2 = stim.DetectorErrorModel('''\n                ...    error(0.25) D1\n                ... ''')\n                >>> m1 += m2\n                >>> print(repr(m1))\n                stim.DetectorErrorModel('''\n                    error(0.125) D0\n                    error(0.25) D1\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__mul__\",\n        &DetectorErrorModel::operator*,\n        pybind11::arg(\"repetitions\"),\n        clean_doc_string(R\"DOC(\n            Repeats the detector error model using a repeat block.\n\n            Has special cases for 0 repetitions and 1 repetitions.\n\n            Args:\n                repetitions: The number of times the repeat block should repeat.\n\n            Returns:\n                repetitions=0: An empty detector error model.\n                repetitions=1: A copy of this detector error model.\n                repetitions>=2: A detector error model with a single repeat block, where the\n                contents of that repeat block are this detector error model.\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel('''\n                ...    error(0.25) D0\n                ...    shift_detectors 1\n                ... ''')\n                >>> m * 3\n                stim.DetectorErrorModel('''\n                    repeat 3 {\n                        error(0.25) D0\n                        shift_detectors 1\n                    }\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__rmul__\",\n        &DetectorErrorModel::operator*,\n        pybind11::arg(\"repetitions\"),\n        clean_doc_string(R\"DOC(\n            Repeats the detector error model using a repeat block.\n\n            Has special cases for 0 repetitions and 1 repetitions.\n\n            Args:\n                repetitions: The number of times the repeat block should repeat.\n\n            Returns:\n                repetitions=0: An empty detector error model.\n                repetitions=1: A copy of this detector error model.\n                repetitions>=2: A detector error model with a single repeat block, where the\n                contents of that repeat block are this detector error model.\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel('''\n                ...    error(0.25) D0\n                ...    shift_detectors 1\n                ... ''')\n                >>> 3 * m\n                stim.DetectorErrorModel('''\n                    repeat 3 {\n                        error(0.25) D0\n                        shift_detectors 1\n                    }\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        pybind11::pickle(\n            [](const DetectorErrorModel &self) -> pybind11::str {\n                return self.str();\n            },\n            [](const pybind11::str &text) -> DetectorErrorModel {\n                return DetectorErrorModel(pybind11::cast<std::string_view>(text));\n            }));\n\n    c.def(\n        \"shortest_graphlike_error\",\n        &shortest_graphlike_undetectable_logical_error,\n        pybind11::arg(\"ignore_ungraphlike_errors\") = true,\n        clean_doc_string(R\"DOC(\n            Finds a minimum set of graphlike errors to produce an undetected logical error.\n\n            Note that this method does not pay attention to error probabilities (other than\n            ignoring errors with probability 0). It searches for a logical error with the\n            minimum *number* of physical errors, not the maximum probability of those\n            physical errors all occurring.\n\n            This method works by looking for errors that have frame changes (eg.\n            \"error(0.1) D0 D1 L5\" flips the frame of observable 5). These errors are\n            converted into one or two symptoms and a net frame change. The symptoms can then\n            be moved around by following errors touching that symptom. Each symptom is moved\n            until it disappears into a boundary or cancels against another remaining\n            symptom, while leaving the other symptoms alone (ensuring only one symptom is\n            allowed to move significantly reduces waste in the search space). Eventually a\n            path or cycle of errors is found that cancels out the symptoms, and if there is\n            still a frame change at that point then that path or cycle is a logical error\n            (otherwise all that was found was a stabilizer of the system; a dead end). The\n            search process advances like a breadth first search, seeded from all the\n            frame-change errors and branching them outward in tandem, until one of them wins\n            the race to find a solution.\n\n            Args:\n                ignore_ungraphlike_errors: Defaults to True. When False, an exception is\n                    raised if there are any errors in the model that are not graphlike. When\n                    True, those errors are skipped as if they weren't present.\n\n                    A graphlike error is an error with less than two symptoms. For the\n                    purposes of this method, errors are also considered graphlike if they\n                    are decomposed into graphlike components:\n\n                    graphlike:\n                        error(0.1) D0\n                        error(0.1) D0 D1\n                        error(0.1) D0 D1 L0\n                    not graphlike but decomposed into graphlike components:\n                        error(0.1) D0 D1 ^ D2\n                    not graphlike, not decomposed into graphlike components:\n                        error(0.1) D0 D1 D2\n                        error(0.1) D0 D1 D2 ^ D3\n\n            Returns:\n                A detector error model containing just the error instructions corresponding\n                to an undetectable logical error. There will be no other kinds of\n                instructions (no `repeat`s, no `shift_detectors`, etc). The error\n                probabilities will all be set to 1.\n\n                The `len` of the returned model is the graphlike code distance of the\n                circuit. But beware that in general the true code distance may be smaller.\n                For example, in the XZ surface code with twists, the true minimum sized\n                logical error is likely to use Y errors. But each Y error decomposes into\n                two graphlike components (the X part and the Z part). As a result, the\n                graphlike code distance in that context is likely to be nearly twice as\n                large as the true code distance.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.DetectorErrorModel('''\n                ...     error(0.125) D0\n                ...     error(0.125) D0 D1\n                ...     error(0.125) D1 L55\n                ...     error(0.125) D1\n                ... ''').shortest_graphlike_error()\n                stim.DetectorErrorModel('''\n                    error(1) D1\n                    error(1) D1 L55\n                ''')\n\n                >>> stim.DetectorErrorModel('''\n                ...     error(0.125) D0 D1 D2\n                ...     error(0.125) L0\n                ... ''').shortest_graphlike_error(ignore_ungraphlike_errors=True)\n                stim.DetectorErrorModel('''\n                    error(1) L0\n                ''')\n\n                >>> circuit = stim.Circuit.generated(\n                ...     \"repetition_code:memory\",\n                ...     rounds=10,\n                ...     distance=7,\n                ...     before_round_data_depolarization=0.01)\n                >>> model = circuit.detector_error_model(decompose_errors=True)\n                >>> len(model.shortest_graphlike_error())\n                7\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_file\",\n        [](pybind11::object &obj) {\n            if (pybind11::isinstance<pybind11::str>(obj)) {\n                std::string_view path = pybind11::cast<std::string_view>(obj);\n                RaiiFile f(path, \"rb\");\n                return DetectorErrorModel::from_file(f.f);\n            }\n\n            auto py_path = pybind11::module::import(\"pathlib\").attr(\"Path\");\n            if (pybind11::isinstance(obj, py_path)) {\n                auto obj_str = pybind11::str(obj);\n                std::string_view path = pybind11::cast<std::string_view>(obj_str);\n                RaiiFile f(path, \"rb\");\n                return DetectorErrorModel::from_file(f.f);\n            }\n\n            auto py_text_io_base = pybind11::module::import(\"io\").attr(\"TextIOBase\");\n            if (pybind11::isinstance(obj, py_text_io_base)) {\n                auto contents = obj.attr(\"read\")();\n                return DetectorErrorModel(pybind11::cast<std::string_view>(contents));\n            }\n\n            std::stringstream ss;\n            ss << \"Don't know how to read from \";\n            ss << pybind11::repr(obj);\n            throw std::invalid_argument(ss.str());\n        },\n        pybind11::arg(\"file\"),\n        clean_doc_string(R\"DOC(\n            @signature def from_file(file: Union[io.TextIOBase, str, pathlib.Path]) -> stim.DetectorErrorModel:\n            Reads a detector error model from a file.\n\n            The file format is defined at\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n            Args:\n                file: A file path or open file object to read from.\n\n            Returns:\n                The circuit parsed from the file.\n\n            Examples:\n                >>> import stim\n                >>> import tempfile\n\n                >>> with tempfile.TemporaryDirectory() as tmpdir:\n                ...     path = tmpdir + '/tmp.stim'\n                ...     with open(path, 'w') as f:\n                ...         print('error(0.25) D2 D3', file=f)\n                ...     circuit = stim.DetectorErrorModel.from_file(path)\n                >>> circuit\n                stim.DetectorErrorModel('''\n                    error(0.25) D2 D3\n                ''')\n\n                >>> with tempfile.TemporaryDirectory() as tmpdir:\n                ...     path = tmpdir + '/tmp.stim'\n                ...     with open(path, 'w') as f:\n                ...         print('error(0.25) D2 D3', file=f)\n                ...     with open(path) as f:\n                ...         circuit = stim.DetectorErrorModel.from_file(f)\n                >>> circuit\n                stim.DetectorErrorModel('''\n                    error(0.25) D2 D3\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_file\",\n        [](const DetectorErrorModel &self, pybind11::object &obj) {\n            if (pybind11::isinstance<pybind11::str>(obj)) {\n                std::string path = pybind11::cast<std::string>(obj);\n                std::ofstream out(path, std::ofstream::out);\n                if (!out.is_open()) {\n                    throw std::invalid_argument(\"Failed to open \" + path);\n                }\n                out << self << '\\n';\n                return;\n            }\n\n            auto py_path = pybind11::module::import(\"pathlib\").attr(\"Path\");\n            if (pybind11::isinstance(obj, py_path)) {\n                std::string path = pybind11::cast<std::string>(pybind11::str(obj));\n                std::ofstream out(path, std::ofstream::out);\n                if (!out.is_open()) {\n                    throw std::invalid_argument(\"Failed to open \" + path);\n                }\n                out << self << '\\n';\n                return;\n            }\n\n            auto py_text_io_base = pybind11::module::import(\"io\").attr(\"TextIOBase\");\n            if (pybind11::isinstance(obj, py_text_io_base)) {\n                obj.attr(\"write\")(pybind11::str(self.str()));\n                obj.attr(\"write\")(pybind11::str(\"\\n\"));\n                return;\n            }\n\n            std::stringstream ss;\n            ss << \"Don't know how to write to \";\n            ss << pybind11::repr(obj);\n            throw std::invalid_argument(ss.str());\n        },\n        pybind11::arg(\"file\"),\n        clean_doc_string(R\"DOC(\n            @signature def to_file(self, file: Union[io.TextIOBase, str, pathlib.Path]) -> None:\n            Writes the detector error model to a file.\n\n            The file format is defined at\n            https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md\n\n            Args:\n                file: A file path or an open file to write to.\n\n            Examples:\n                >>> import stim\n                >>> import tempfile\n                >>> c = stim.DetectorErrorModel('error(0.25) D2 D3')\n\n                >>> with tempfile.TemporaryDirectory() as tmpdir:\n                ...     path = tmpdir + '/tmp.stim'\n                ...     with open(path, 'w') as f:\n                ...         c.to_file(f)\n                ...     with open(path) as f:\n                ...         contents = f.read()\n                >>> contents\n                'error(0.25) D2 D3\\n'\n\n                >>> with tempfile.TemporaryDirectory() as tmpdir:\n                ...     path = tmpdir + '/tmp.stim'\n                ...     c.to_file(path)\n                ...     with open(path) as f:\n                ...         contents = f.read()\n                >>> contents\n                'error(0.25) D2 D3\\n'\n        )DOC\")\n            .data());\n\n    c.def(\n        \"compile_sampler\",\n        [](const DetectorErrorModel &self, const pybind11::object &seed) -> DemSampler<MAX_BITWORD_WIDTH> {\n            return DemSampler<MAX_BITWORD_WIDTH>(self, make_py_seeded_rng(seed), 1024);\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"seed\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            Returns a CompiledDemSampler that can batch sample from detector error models.\n\n            Args:\n                seed: PARTIALLY determines simulation results by deterministically seeding\n                    the random number generator.\n\n                    Must be None or an integer in range(2**64).\n\n                    Defaults to None. When None, the prng is seeded from system entropy.\n\n                    When set to an integer, making the exact same series calls on the exact\n                    same machine with the exact same version of Stim will produce the exact\n                    same simulation results.\n\n                    CAUTION: simulation results *WILL NOT* be consistent between versions of\n                    Stim. This restriction is present to make it possible to have future\n                    optimizations to the random sampling, and is enforced by introducing\n                    intentional differences in the seeding strategy from version to version.\n\n                    CAUTION: simulation results *MAY NOT* be consistent across machines that\n                    differ in the width of supported SIMD instructions. For example, using\n                    the same seed on a machine that supports AVX instructions and one that\n                    only supports SSE instructions may produce different simulation results.\n\n                    CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                    shots are taken. For example, taking 10 shots and then 90 shots will\n                    give different results from taking 100 shots in one call.\n\n            Returns:\n                A seeded stim.CompiledDemSampler for the given detector error model.\n\n            Examples:\n                >>> import stim\n                >>> dem = stim.DetectorErrorModel('''\n                ...    error(0) D0\n                ...    error(1) D1 D2 L0\n                ... ''')\n                >>> sampler = dem.compile_sampler()\n                >>> det_data, obs_data, err_data = sampler.sample(\n                ...     shots=4,\n                ...     return_errors=True)\n                >>> det_data\n                array([[False,  True,  True],\n                       [False,  True,  True],\n                       [False,  True,  True],\n                       [False,  True,  True]])\n                >>> obs_data\n                array([[ True],\n                       [ True],\n                       [ True],\n                       [ True]])\n                >>> err_data\n                array([[False,  True],\n                       [False,  True],\n                       [False,  True],\n                       [False,  True]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"flattened\",\n        &DetectorErrorModel::flattened,\n        clean_doc_string(R\"DOC(\n            Returns the detector error model without repeat or detector_shift instructions.\n\n            Returns:\n                A `stim.DetectorErrorModel` with the same errors in the same order, but with\n                repeat loops flattened into actually repeated instructions and with all\n                coordinate/index shifts inlined.\n\n            Examples:\n                >>> import stim\n                >>> stim.DetectorErrorModel('''\n                ...     error(0.125) D0\n                ...     REPEAT 5 {\n                ...         error(0.25) D0 D1\n                ...         shift_detectors 1\n                ...     }\n                ...     error(0.125) D0 L0\n                ... ''').flattened()\n                stim.DetectorErrorModel('''\n                    error(0.125) D0\n                    error(0.25) D0 D1\n                    error(0.25) D1 D2\n                    error(0.25) D2 D3\n                    error(0.25) D3 D4\n                    error(0.25) D4 D5\n                    error(0.125) D5 L0\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"rounded\",\n        &DetectorErrorModel::rounded,\n        clean_doc_string(R\"DOC(\n            Creates an equivalent detector error model but with rounded error probabilities.\n\n            Args:\n                digits: The number of digits to round to.\n\n            Returns:\n                A `stim.DetectorErrorModel` with the same instructions in the same order,\n                but with the parens arguments of error instructions rounded to the given\n                precision.\n\n                Instructions whose error probability was rounded to zero are still\n                included in the output.\n\n            Examples:\n                >>> import stim\n                >>> dem = stim.DetectorErrorModel('''\n                ...     error(0.019499) D0\n                ...     error(0.000001) D0 D1\n                ... ''')\n\n                >>> dem.rounded(2)\n                stim.DetectorErrorModel('''\n                    error(0.02) D0\n                    error(0) D0 D1\n                ''')\n\n                >>> dem.rounded(3)\n                stim.DetectorErrorModel('''\n                    error(0.019) D0\n                    error(0) D0 D1\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"diagram\",\n        &dem_diagram,\n        pybind11::arg(\"type\"),\n        clean_doc_string(R\"DOC(\n            @signature def diagram(self, type: Literal[\"matchgraph-svg\", \"matchgraph-svg-html\", \"matchgraph-3d\", \"matchgraph-3d-html\"] = 'matchgraph-svg') -> Any:\n            Returns a diagram of the circuit, from a variety of options.\n\n            Args:\n                type: The type of diagram. Available types are:\n                    \"matchgraph-svg\": An image of the decoding graph of the\n                        detector error model. Red lines are errors crossing a\n                        logical observable. Blue lines are undecomposed hyper\n                        errors.\n                    \"matchgraph-svg-html\": Same as matchgraph-svg but with the\n                        SVG wrapped in a resizable HTML iframe.\n                    \"matchgraph-3d\": A 3d model of the decoding graph of the\n                        detector error model. Red lines are errors crossing a\n                        logical observable. Blue lines are undecomposed hyper\n                        errors.\n\n                        GLTF files can be opened with a variety of programs, or\n                        opened online in viewers such as\n                        https://gltf-viewer.donmccurdy.com/ . Red lines are\n                        errors crossing a logical observable.\n                    \"matchgraph-3d-html\": Same 3d model as 'match-graph-3d' but\n                        embedded into an HTML web page containing an interactive\n                        THREE.js viewer for the 3d model.\n\n            Returns:\n                An object whose `__str__` method returns the diagram, so that\n                writing the diagram to a file works correctly. The returned\n                object also defines a `_repr_html_` method, so that ipython\n                notebooks recognize it can be shown using a specialized\n                viewer instead of as raw text.\n\n            Examples:\n                >>> import stim\n                >>> import tempfile\n                >>> circuit = stim.Circuit.generated(\n                ...     \"repetition_code:memory\",\n                ...     rounds=10,\n                ...     distance=7,\n                ...     after_clifford_depolarization=0.01)\n                >>> dem = circuit.detector_error_model(decompose_errors=True)\n\n                >>> with tempfile.TemporaryDirectory() as d:\n                ...     diagram = circuit.diagram(\"match-graph-svg\")\n                ...     with open(f\"{d}/dem_image.svg\", \"w\") as f:\n                ...         print(diagram, file=f)\n\n                >>> with tempfile.TemporaryDirectory() as d:\n                ...     diagram = circuit.diagram(\"match-graph-3d\")\n                ...     with open(f\"{d}/dem_3d_model.gltf\", \"w\") as f:\n                ...         print(diagram, file=f)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"without_tags\",\n        &DetectorErrorModel::without_tags,\n        clean_doc_string(R\"DOC(\n            Returns a copy of the detector error model with all tags removed.\n\n            Returns:\n                A `stim.DetectorErrorModel` with the same instructions except all tags have\n                been removed.\n\n            Examples:\n                >>> import stim\n                >>> stim.DetectorErrorModel('''\n                ...     error[test-tag](0.25) D0\n                ... ''').without_tags()\n                stim.DetectorErrorModel('''\n                    error(0.25) D0\n                ''')\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/dem/detector_error_model.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_DEM_DETECTOR_ERROR_MODEL_PYBIND_H\n#define _STIM_DEM_DETECTOR_ERROR_MODEL_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/dem/detector_error_model.h\"\n\nnamespace stim_pybind {\n\nstd::string detector_error_model_repr(const stim::DetectorErrorModel &self);\npybind11::class_<stim::DetectorErrorModel> pybind_detector_error_model(pybind11::module &m);\nvoid pybind_detector_error_model_methods(pybind11::module &m, pybind11::class_<stim::DetectorErrorModel> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/dem/detector_error_model.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/dem/detector_error_model.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(detector_error_model, init_equality) {\n    DetectorErrorModel model1;\n    DetectorErrorModel model2;\n    ASSERT_TRUE(model1 == model2);\n    ASSERT_TRUE(!(model1 != model2));\n    model1.append_shift_detectors_instruction({}, 5, \"\");\n    ASSERT_TRUE(model1 != model2);\n    ASSERT_TRUE(!(model1 == model2));\n    model2.append_shift_detectors_instruction({}, 4, \"\");\n    ASSERT_NE(model1, model2);\n    model1.clear();\n    model2.clear();\n    ASSERT_EQ(model1, model2);\n\n    model1.append_repeat_block(5, {}, \"\");\n    model2.append_repeat_block(4, {}, \"\");\n    ASSERT_NE(model1, model2);\n\n    model1.append_error_instruction(0.2, {}, \"\");\n    model2.append_repeat_block(4, {}, \"\");\n    ASSERT_NE(model1, model2);\n}\n\nTEST(detector_error_model, append_shift_detectors_instruction) {\n    DetectorErrorModel model;\n    ASSERT_EQ(model.instructions.size(), 0);\n    ASSERT_EQ(model.blocks.size(), 0);\n\n    std::vector<double> arg_data{1.5, 2.5};\n    SpanRef<const double> arg_data_ref = arg_data;\n    model.append_shift_detectors_instruction(arg_data_ref, 5, \"\");\n    ASSERT_EQ(model.instructions.size(), 1);\n    ASSERT_EQ(model.instructions[0].type, DemInstructionType::DEM_SHIFT_DETECTORS);\n    ASSERT_EQ(model.instructions[0].target_data.size(), 1);\n    ASSERT_EQ(model.instructions[0].target_data[0].data, 5);\n    ASSERT_EQ(model.instructions[0].arg_data, arg_data_ref);\n    ASSERT_EQ(model.blocks.size(), 0);\n}\n\nTEST(detector_error_model, append_detector_instruction) {\n    DetectorErrorModel model;\n    ASSERT_EQ(model.instructions.size(), 0);\n    ASSERT_EQ(model.blocks.size(), 0);\n\n    std::vector<double> arg_data{1.5, 2.5};\n    SpanRef<const double> arg_data_ref = arg_data;\n    model.append_detector_instruction(arg_data_ref, DemTarget::relative_detector_id(5), \"\");\n    ASSERT_EQ(model.instructions.size(), 1);\n    ASSERT_EQ(model.instructions[0].type, DemInstructionType::DEM_DETECTOR);\n    ASSERT_EQ(model.instructions[0].target_data.size(), 1);\n    ASSERT_EQ(model.instructions[0].target_data[0], DemTarget::relative_detector_id(5));\n    ASSERT_EQ(model.instructions[0].arg_data, arg_data_ref);\n    ASSERT_EQ(model.blocks.size(), 0);\n\n    ASSERT_THROW({ model.append_detector_instruction({}, DemTarget::separator(), \"\"); }, std::invalid_argument);\n    ASSERT_THROW({ model.append_detector_instruction({}, DemTarget::observable_id(4), \"\"); }, std::invalid_argument);\n    model.append_detector_instruction({}, DemTarget::relative_detector_id(4), \"\");\n}\n\nTEST(detector_error_model, append_logical_observable_instruction) {\n    DetectorErrorModel model;\n    ASSERT_EQ(model.instructions.size(), 0);\n    ASSERT_EQ(model.blocks.size(), 0);\n\n    model.append_logical_observable_instruction(DemTarget::observable_id(5), \"\");\n    ASSERT_EQ(model.instructions.size(), 1);\n    ASSERT_EQ(model.instructions[0].type, DemInstructionType::DEM_LOGICAL_OBSERVABLE);\n    ASSERT_EQ(model.instructions[0].target_data.size(), 1);\n    ASSERT_EQ(model.instructions[0].target_data[0], DemTarget::observable_id(5));\n    ASSERT_EQ(model.instructions[0].arg_data.size(), 0);\n    ASSERT_EQ(model.blocks.size(), 0);\n\n    ASSERT_THROW({ model.append_logical_observable_instruction(DemTarget::separator(), \"\"); }, std::invalid_argument);\n    ASSERT_THROW(\n        { model.append_logical_observable_instruction(DemTarget::relative_detector_id(4), \"\"); },\n        std::invalid_argument);\n    model.append_logical_observable_instruction(DemTarget::observable_id(4), \"\");\n}\n\nTEST(detector_error_model, append_error_instruction) {\n    DetectorErrorModel model;\n    std::vector<DemTarget> symptoms;\n    symptoms.push_back(DemTarget::observable_id(3));\n    symptoms.push_back(DemTarget::relative_detector_id(4));\n    model.append_error_instruction(0.25, symptoms, \"\");\n    ASSERT_EQ(model.instructions.size(), 1);\n    ASSERT_EQ(model.blocks.size(), 0);\n    ASSERT_EQ(model.instructions[0].type, DemInstructionType::DEM_ERROR);\n    ASSERT_EQ(model.instructions[0].target_data, (SpanRef<DemTarget>)symptoms);\n    ASSERT_EQ(model.instructions[0].arg_data.size(), 1);\n    ASSERT_EQ(model.instructions[0].arg_data[0], 0.25);\n\n    model.clear();\n    ASSERT_EQ(model.instructions.size(), 0);\n\n    symptoms.push_back(DemTarget::separator());\n    symptoms.push_back(DemTarget::observable_id(4));\n\n    model.append_error_instruction(0.125, symptoms, \"\");\n    ASSERT_EQ(model.instructions.size(), 1);\n    ASSERT_EQ(model.blocks.size(), 0);\n    ASSERT_EQ(model.instructions[0].type, DemInstructionType::DEM_ERROR);\n    ASSERT_EQ(model.instructions[0].target_data, (SpanRef<DemTarget>)symptoms);\n    ASSERT_EQ(model.instructions[0].arg_data.size(), 1);\n    ASSERT_EQ(model.instructions[0].arg_data[0], 0.125);\n\n    ASSERT_THROW({ model.append_error_instruction(1.5, symptoms, \"\"); }, std::invalid_argument);\n    ASSERT_THROW({ model.append_error_instruction(-0.5, symptoms, \"\"); }, std::invalid_argument);\n\n    symptoms = {DemTarget::separator()};\n    ASSERT_THROW({ model.append_error_instruction(0.25, symptoms, \"\"); }, std::invalid_argument);\n    symptoms = {DemTarget::separator(), DemTarget::observable_id(0)};\n    ASSERT_THROW({ model.append_error_instruction(0.25, symptoms, \"\"); }, std::invalid_argument);\n    symptoms = {DemTarget::observable_id(0), DemTarget::separator()};\n    ASSERT_THROW({ model.append_error_instruction(0.25, symptoms, \"\"); }, std::invalid_argument);\n    symptoms = {\n        DemTarget::observable_id(0),\n        DemTarget::separator(),\n        DemTarget::separator(),\n        DemTarget::relative_detector_id(4)};\n    ASSERT_THROW({ model.append_error_instruction(0.25, symptoms, \"\"); }, std::invalid_argument);\n    symptoms = {DemTarget::observable_id(0), DemTarget::separator(), DemTarget::relative_detector_id(4)};\n    model.append_error_instruction(0.25, symptoms, \"\");\n}\n\nTEST(detector_error_model, append_block) {\n    DetectorErrorModel model;\n    DetectorErrorModel block;\n    block.append_shift_detectors_instruction({}, 3, \"\");\n    DetectorErrorModel block2 = block;\n\n    model.append_repeat_block(5, block, \"\");\n    block.append_shift_detectors_instruction({}, 4, \"\");\n    model.append_repeat_block(6, std::move(block), \"\");\n    model.append_repeat_block(20, block2, \"\");\n    ASSERT_EQ(model.instructions.size(), 3);\n    ASSERT_EQ(model.blocks.size(), 3);\n    ASSERT_EQ(model.instructions[0].type, DemInstructionType::DEM_REPEAT_BLOCK);\n    ASSERT_EQ(model.instructions[0].target_data[0].data, 5);\n    ASSERT_EQ(model.instructions[0].target_data[1].data, 0);\n    ASSERT_EQ(model.instructions[1].type, DemInstructionType::DEM_REPEAT_BLOCK);\n    ASSERT_EQ(model.instructions[1].target_data[0].data, 6);\n    ASSERT_EQ(model.instructions[1].target_data[1].data, 1);\n    ASSERT_EQ(model.instructions[2].type, DemInstructionType::DEM_REPEAT_BLOCK);\n    ASSERT_EQ(model.instructions[2].target_data[0].data, 20);\n    ASSERT_EQ(model.instructions[2].target_data[1].data, 2);\n    ASSERT_EQ(model.blocks[0], block2);\n    ASSERT_EQ(model.blocks[2], block2);\n    block2.append_shift_detectors_instruction({}, 4, \"\");\n    ASSERT_EQ(model.blocks[1], block2);\n}\n\nTEST(detector_error_model, round_trip_str) {\n    const char *t = R\"MODEL(error(0.125) D0\nrepeat 100 {\n    repeat 200 {\n        error[test-tag](0.25) D0 D1 L0 ^ D2\n        shift_detectors(1.5, 3) 10\n        detector(0.5) D0\n        detector D1\n    }\n    error(0.375) D0 D1\n    shift_detectors 20\n    logical_observable L0\n})MODEL\";\n    ASSERT_EQ(DetectorErrorModel(t).str(), std::string(t));\n}\n\nTEST(detector_error_model, parse) {\n    DetectorErrorModel expected;\n    ASSERT_EQ(DetectorErrorModel(\"\"), expected);\n\n    expected.append_error_instruction(0.125, (std::vector<DemTarget>{DemTarget::relative_detector_id(0)}), \"\");\n    ASSERT_EQ(\n        DetectorErrorModel(R\"MODEL(\n        error(0.125) D0\n    )MODEL\"),\n        expected);\n\n    expected.append_error_instruction(0.125, (std::vector<DemTarget>{DemTarget::relative_detector_id(5)}), \"\");\n    ASSERT_EQ(\n        DetectorErrorModel(R\"MODEL(\n        error(0.125) D0\n        error(0.125) D5\n    )MODEL\"),\n        expected);\n\n    expected.append_error_instruction(\n        0.25,\n        (std::vector<DemTarget>{\n            DemTarget::relative_detector_id(5), DemTarget::separator(), DemTarget::observable_id(4)}),\n        \"\");\n    ASSERT_EQ(\n        DetectorErrorModel(R\"MODEL(\n        error(0.125) D0\n        error(0.125) D5\n        error(0.25) D5 ^ L4\n    )MODEL\"),\n        expected);\n\n    expected.append_shift_detectors_instruction(std::vector<double>{1.5, 2}, 60, \"\");\n    ASSERT_EQ(\n        DetectorErrorModel(R\"MODEL(\n        error(0.125) D0\n        error(0.125) D5\n        error(0.25) D5 ^ L4\n        shift_detectors(1.5, 2) 60\n    )MODEL\"),\n        expected);\n\n    expected.append_repeat_block(100, expected, \"\");\n    ASSERT_EQ(\n        DetectorErrorModel(R\"MODEL(\n        error(0.125) D0\n        error(0.125) D5\n        error(0.25) D5 ^ L4\n        shift_detectors(1.5, 2) 60\n        repeat 100 {\n            error(0.125) D0\n            error(0.125) D5\n            error(0.25) D5 ^ L4\n            shift_detectors(1.5, 2) 60\n        }\n    )MODEL\"),\n        expected);\n}\n\nTEST(detector_error_model, parse_tag) {\n    std::string_view t = R\"MODEL(error[test1](0.125) D0\nrepeat[test2] 10 {\n    shift_detectors[test3](1.5, 3) 10\n    detector[test4](0.5) D0\n}\nlogical_observable[test5] L0)MODEL\";\n    DetectorErrorModel dem(t);\n    ASSERT_EQ(dem.str(), t);\n}\n\nTEST(detector_error_model, movement) {\n    const char *t = R\"MODEL(\n        error(0.2) D0\n        REPEAT 100 {\n            REPEAT 200 {\n                error(0.1) D0 D1 L0 ^ D2\n                shift_detectors 10\n            }\n            error(0.1) D0 D2\n            shift_detectors 20\n        }\n    )MODEL\";\n    DetectorErrorModel d1(t);\n    DetectorErrorModel d2(d1);\n    ASSERT_EQ(d1, d2);\n    ASSERT_EQ(d1, DetectorErrorModel(t));\n    DetectorErrorModel d3(std::move(d1));\n    ASSERT_EQ(d1, DetectorErrorModel());\n    ASSERT_EQ(d2, d3);\n    ASSERT_EQ(d2, DetectorErrorModel(t));\n    d1 = d3;\n    ASSERT_EQ(d1, d2);\n    ASSERT_EQ(d2, d3);\n    ASSERT_EQ(d2, DetectorErrorModel(t));\n    d1 = std::move(d2);\n    ASSERT_EQ(d1, d3);\n    ASSERT_EQ(d2, DetectorErrorModel());\n    ASSERT_EQ(d1, DetectorErrorModel(t));\n}\n\nTEST(dem_target, general) {\n    DemTarget d = DemTarget::relative_detector_id(3);\n    ASSERT_TRUE(d == DemTarget::relative_detector_id(3));\n    ASSERT_TRUE(!(d != DemTarget::relative_detector_id(3)));\n    ASSERT_TRUE(!(d == DemTarget::relative_detector_id(4)));\n    ASSERT_TRUE(d != DemTarget::relative_detector_id(4));\n    ASSERT_EQ(d, DemTarget::relative_detector_id(3));\n    ASSERT_NE(d, DemTarget::observable_id(5));\n    ASSERT_NE(d, DemTarget::separator());\n\n    DemTarget d3 = DemTarget::relative_detector_id(72);\n    DemTarget s = DemTarget::separator();\n    DemTarget o = DemTarget::observable_id(3);\n    ASSERT_EQ(d.str(), \"D3\");\n    ASSERT_EQ(d3.str(), \"D72\");\n    ASSERT_EQ(o.str(), \"L3\");\n    ASSERT_EQ(s.str(), \"^\");\n\n    ASSERT_TRUE(!o.is_separator());\n    ASSERT_TRUE(!d3.is_separator());\n    ASSERT_TRUE(s.is_separator());\n\n    ASSERT_TRUE(o.is_observable_id());\n    ASSERT_TRUE(!d3.is_observable_id());\n    ASSERT_TRUE(!s.is_observable_id());\n\n    ASSERT_TRUE(!o.is_relative_detector_id());\n    ASSERT_TRUE(d3.is_relative_detector_id());\n    ASSERT_TRUE(!s.is_relative_detector_id());\n}\n\nTEST(dem_instruction, general) {\n    std::vector<DemTarget> d1;\n    d1.push_back(DemTarget::observable_id(4));\n    d1.push_back(DemTarget::relative_detector_id(3));\n    std::vector<DemTarget> d2;\n    d2.push_back(DemTarget::observable_id(4));\n    std::vector<double> p125{0.125};\n    std::vector<double> p25{0.25};\n    std::vector<double> p126{0.126};\n    DemInstruction i1{p125, d1, \"\", DemInstructionType::DEM_ERROR};\n    DemInstruction i1a{p125, d1, \"\", DemInstructionType::DEM_ERROR};\n    DemInstruction i2{p125, d2, \"\", DemInstructionType::DEM_ERROR};\n    ASSERT_TRUE(i1 == i1a);\n    ASSERT_TRUE(!(i1 != i1a));\n    ASSERT_TRUE(!(i2 == i1a));\n    ASSERT_TRUE(i2 != i1a);\n\n    ASSERT_EQ(i1, (DemInstruction{p125, d1, \"\", DemInstructionType::DEM_ERROR}));\n    ASSERT_NE(i1, (DemInstruction{p125, d2, \"\", DemInstructionType::DEM_ERROR}));\n    ASSERT_NE(i1, (DemInstruction{p25, d1, \"\", DemInstructionType::DEM_ERROR}));\n    ASSERT_NE(\n        ((DemInstruction{{}, {}, \"\", DemInstructionType::DEM_DETECTOR})),\n        (DemInstruction{{}, {}, \"\", DemInstructionType::DEM_LOGICAL_OBSERVABLE}));\n\n    ASSERT_TRUE(i1.approx_equals(DemInstruction{p125, d1, \"\", DemInstructionType::DEM_ERROR}, 0));\n    ASSERT_TRUE(!i1.approx_equals(DemInstruction{p126, d1, \"\", DemInstructionType::DEM_ERROR}, 0));\n    ASSERT_TRUE(i1.approx_equals(DemInstruction{p126, d1, \"\", DemInstructionType::DEM_ERROR}, 0.01));\n    ASSERT_TRUE(!i1.approx_equals(DemInstruction{p125, d2, \"\", DemInstructionType::DEM_ERROR}, 9999));\n\n    ASSERT_EQ(i1.str(), \"error(0.125) L4 D3\");\n    ASSERT_EQ(i2.str(), \"error(0.125) L4\");\n\n    d1.push_back(DemTarget::separator());\n    d1.push_back(DemTarget::observable_id(11));\n    ASSERT_EQ((DemInstruction{p25, d1, \"\", DemInstructionType::DEM_ERROR}).str(), \"error(0.25) L4 D3 ^ L11\");\n}\n\nTEST(detector_error_model, total_detector_shift) {\n    ASSERT_EQ(DetectorErrorModel(\"\").total_detector_shift(), 0);\n    ASSERT_EQ(DetectorErrorModel(\"error(0.3) D2\").total_detector_shift(), 0);\n    ASSERT_EQ(DetectorErrorModel(\"shift_detectors 5\").total_detector_shift(), 5);\n    ASSERT_EQ(DetectorErrorModel(\"shift_detectors 5\\nshift_detectors 4\").total_detector_shift(), 9);\n    ASSERT_EQ(\n        DetectorErrorModel(R\"MODEL(\n        shift_detectors 5\n        repeat 1000 {\n            shift_detectors 4\n        }\n    )MODEL\")\n            .total_detector_shift(),\n        4005);\n}\n\nTEST(detector_error_model, count_detectors) {\n    ASSERT_EQ(DetectorErrorModel(\"\").count_detectors(), 0);\n    ASSERT_EQ(DetectorErrorModel(\"error(0.3) D2 L1000\").count_detectors(), 3);\n    ASSERT_EQ(DetectorErrorModel(\"shift_detectors 5\").count_detectors(), 0);\n    ASSERT_EQ(DetectorErrorModel(\"shift_detectors 5\\ndetector D3\").count_detectors(), 9);\n    ASSERT_EQ(\n        DetectorErrorModel(R\"MODEL(\n        shift_detectors 50\n        repeat 1000 {\n            detector D0\n            error(0.1) D0 D1\n            shift_detectors 4\n        }\n    )MODEL\")\n            .count_detectors(),\n        4048);\n}\n\nTEST(detector_error_model, count_observables) {\n    ASSERT_EQ(DetectorErrorModel(\"\").count_observables(), 0);\n    ASSERT_EQ(DetectorErrorModel(\"error(0.3) L2 D9999\").count_observables(), 3);\n    ASSERT_EQ(DetectorErrorModel(\"shift_detectors 5\\nlogical_observable L3\").count_observables(), 4);\n    ASSERT_EQ(\n        DetectorErrorModel(R\"MODEL(\n        shift_detectors 50\n        repeat 1000 {\n            logical_observable L5\n            error(0.1) D0 D1 L6\n            shift_detectors 4\n        }\n    )MODEL\")\n            .count_observables(),\n        7);\n}\n\nTEST(detector_error_model, from_file) {\n    FILE *f = tmpfile();\n    const char *program = R\"MODEL(\n        error(0.125) D1\n        REPEAT 99 {\n            error(0.25) D3 D4\n            shift_detectors 1\n        }\n    )MODEL\";\n    fprintf(f, \"%s\", program);\n    rewind(f);\n    auto d = DetectorErrorModel::from_file(f);\n    ASSERT_EQ(d, DetectorErrorModel(program));\n    d.clear();\n    rewind(f);\n    d.append_from_file(f);\n    ASSERT_EQ(d, DetectorErrorModel(program));\n    d.clear();\n    rewind(f);\n    d.append_from_file(f, false);\n    ASSERT_EQ(d, DetectorErrorModel(program));\n    d.clear();\n    rewind(f);\n    d.append_from_file(f, true);\n    ASSERT_EQ(d, DetectorErrorModel(\"error(0.125) D1\"));\n    d.append_from_file(f, true);\n    ASSERT_EQ(d, DetectorErrorModel(program));\n}\n\nTEST(detector_error_model, py_get_slice) {\n    DetectorErrorModel d(R\"MODEL(\n        detector D2\n        logical_observable L1\n        error(0.125) D0 L1\n        REPEAT 100 {\n            shift_detectors(0.25) 5\n            REPEAT 20 {\n            }\n        }\n        error(0.125) D1 D2\n        REPEAT 999 {\n        }\n    )MODEL\");\n    ASSERT_EQ(d.py_get_slice(0, 1, 6), d);\n    ASSERT_EQ(d.py_get_slice(0, 1, 4), DetectorErrorModel(R\"MODEL(\n        detector D2\n        logical_observable L1\n        error(0.125) D0 L1\n        REPEAT 100 {\n            shift_detectors(0.25) 5\n            REPEAT 20 {\n            }\n        }\n    )MODEL\"));\n    ASSERT_EQ(d.py_get_slice(2, 1, 3), DetectorErrorModel(R\"MODEL(\n        error(0.125) D0 L1\n        REPEAT 100 {\n            shift_detectors(0.25) 5\n            REPEAT 20 {\n            }\n        }\n        error(0.125) D1 D2\n    )MODEL\"));\n\n    ASSERT_EQ(d.py_get_slice(4, -1, 3), DetectorErrorModel(R\"MODEL(\n        error(0.125) D1 D2\n        REPEAT 100 {\n            shift_detectors(0.25) 5\n            REPEAT 20 {\n            }\n        }\n        error(0.125) D0 L1\n    )MODEL\"));\n\n    ASSERT_EQ(d.py_get_slice(5, -2, 3), DetectorErrorModel(R\"MODEL(\n        REPEAT 999 {\n        }\n        REPEAT 100 {\n            shift_detectors(0.25) 5\n            REPEAT 20 {\n            }\n        }\n        logical_observable L1\n    )MODEL\"));\n\n    DetectorErrorModel d2 = d;\n    DetectorErrorModel d3 = d2.py_get_slice(0, 1, 6);\n    d2.clear();\n    ASSERT_EQ(d, d3);\n}\n\nTEST(detector_error_model, mul) {\n    DetectorErrorModel original(R\"MODEL(\n        error(0.25) D0\n        REPEAT 999 {\n            error(0.25) D1\n        }\n    )MODEL\");\n    DetectorErrorModel d = original;\n    ASSERT_EQ(d * 3, DetectorErrorModel(R\"MODEL(\n        REPEAT 3 {\n            error(0.25) D0\n            REPEAT 999 {\n                error(0.25) D1\n            }\n        }\n    )MODEL\"));\n    ASSERT_EQ(d * 1, d);\n    ASSERT_EQ(d * 0, DetectorErrorModel());\n    ASSERT_EQ(d, original);\n}\n\nTEST(detector_error_model, imul) {\n    DetectorErrorModel original(R\"MODEL(\n        error(0.25) D0\n        REPEAT 999 {\n            error(0.25) D1\n        }\n    )MODEL\");\n    DetectorErrorModel d = original;\n    d *= 3;\n    ASSERT_EQ(d, DetectorErrorModel(R\"MODEL(\n        REPEAT 3 {\n            error(0.25) D0\n            REPEAT 999 {\n                error(0.25) D1\n            }\n        }\n    )MODEL\"));\n    d = original;\n    d *= 1;\n    ASSERT_EQ(d, original);\n    d = original;\n    d *= 0;\n    ASSERT_EQ(d, DetectorErrorModel());\n}\n\nTEST(detector_error_model, add) {\n    DetectorErrorModel a(R\"MODEL(\n        error(0.25) D0\n        REPEAT 999 {\n            error(0.25) D1\n        }\n    )MODEL\");\n    DetectorErrorModel b(R\"MODEL(\n        error(0.125) D1\n        REPEAT 2 {\n            REPEAT 3 {\n                error(0.125) D1\n            }\n        }\n    )MODEL\");\n\n    ASSERT_EQ(a + b, DetectorErrorModel(R\"MODEL(\n        error(0.25) D0\n        REPEAT 999 {\n            error(0.25) D1\n        }\n        error(0.125) D1\n        REPEAT 2 {\n            REPEAT 3 {\n                error(0.125) D1\n            }\n        }\n    )MODEL\"));\n\n    ASSERT_EQ(a + DetectorErrorModel(), a);\n    ASSERT_EQ(DetectorErrorModel() + a, a);\n    ASSERT_EQ(b + DetectorErrorModel(), b);\n    ASSERT_EQ(DetectorErrorModel() + b, b);\n    ASSERT_EQ(DetectorErrorModel() + DetectorErrorModel(), DetectorErrorModel());\n}\n\nTEST(detector_error_model, iadd) {\n    DetectorErrorModel a(R\"MODEL(\n        error(0.25) D0\n        REPEAT 999 {\n            error(0.25) D1\n        }\n    )MODEL\");\n    DetectorErrorModel b(R\"MODEL(\n        error(0.125) D1\n        REPEAT 2 {\n            REPEAT 3 {\n                error(0.125) D1\n            }\n        }\n    )MODEL\");\n\n    a += b;\n    ASSERT_EQ(a, DetectorErrorModel(R\"MODEL(\n        error(0.25) D0\n        REPEAT 999 {\n            error(0.25) D1\n        }\n        error(0.125) D1\n        REPEAT 2 {\n            REPEAT 3 {\n                error(0.125) D1\n            }\n        }\n    )MODEL\"));\n\n    DetectorErrorModel original = b;\n    b += DetectorErrorModel();\n    ASSERT_EQ(b, original);\n    b += a;\n    ASSERT_NE(b, original);\n\n    // Aliased.\n    a = original;\n    a += a;\n    a = DetectorErrorModel(a.str());  // Remove memory deduplication, because it affects equality.\n    ASSERT_EQ(a, original + original);\n}\n\nTEST(detector_error_model, iter_flatten_error_instructions) {\n    DetectorErrorModel d(R\"MODEL(\n        error(0.25) D0\n        shift_detectors 1\n        error(0.375) D0 D1\n        repeat 5 {\n            error(0.125) D0 D1 D2 L0\n            shift_detectors 2\n        }\n        detector D5000\n        logical_observable L5000\n    )MODEL\");\n\n    DetectorErrorModel dem;\n    d.iter_flatten_error_instructions([&](const DemInstruction &e) {\n        EXPECT_EQ(e.type, DemInstructionType::DEM_ERROR);\n        dem.append_error_instruction(e.arg_data[0], e.target_data, \"\");\n    });\n    ASSERT_EQ(dem, DetectorErrorModel(R\"MODEL(\n        error(0.25) D0\n        error(0.375) D1 D2\n        error(0.125) D1 D2 D3 L0\n        error(0.125) D3 D4 D5 L0\n        error(0.125) D5 D6 D7 L0\n        error(0.125) D7 D8 D9 L0\n        error(0.125) D9 D10 D11 L0\n    )MODEL\"));\n}\n\nTEST(detector_error_model, get_detector_coordinates_nested_loops) {\n    DetectorErrorModel dem(R\"MODEL(\n        repeat 200 {\n            repeat 100 {\n                detector(0, 0, 0, 4) D1\n                shift_detectors(1, 0, 0) 10\n            }\n            detector(0, 0, 0, 3) D2\n            shift_detectors(0, 1, 0) 0\n        }\n        detector(0, 0, 0, 2) D3\n    )MODEL\");\n    ASSERT_THROW({ dem.get_detector_coordinates({4000000000}); }, std::invalid_argument);\n    ASSERT_THROW({ dem.get_detector_coordinates({dem.count_detectors()}); }, std::invalid_argument);\n    auto result = dem.get_detector_coordinates({\n        0,\n        1,\n        11,\n        991,\n        1001,\n        1002,\n        1011,\n        1021,\n    });\n    ASSERT_EQ(\n        result,\n        (std::map<uint64_t, std::vector<double>>{\n            {0, {}},\n            {1, {0, 0, 0, 4}},\n            {11, {1, 0, 0, 4}},\n            {991, {99, 0, 0, 4}},\n            {1001, {100, 1, 0, 4}},\n            {1002, {100, 0, 0, 3}},\n            {1011, {101, 1, 0, 4}},\n            {1021, {102, 1, 0, 4}},\n        }));\n}\n\nTEST(detector_error_model, get_detector_coordinates_trivial) {\n    DetectorErrorModel dem;\n\n    dem = DetectorErrorModel(R\"MODEL(\n        detector(1, 2) D1\n    )MODEL\");\n    ASSERT_EQ(\n        dem.get_detector_coordinates({0, 1}),\n        (std::map<uint64_t, std::vector<double>>{\n            {0, {}},\n            {1, {1, 2}},\n        }));\n    ASSERT_THROW({ dem.get_detector_coordinates({2}); }, std::invalid_argument);\n\n    dem = DetectorErrorModel(R\"MODEL(\n        error(0.25) D0 D1\n    )MODEL\");\n    ASSERT_EQ(\n        dem.get_detector_coordinates({0, 1}),\n        (std::map<uint64_t, std::vector<double>>{\n            {0, {}},\n            {1, {}},\n        }));\n    ASSERT_THROW({ dem.get_detector_coordinates({2}); }, std::invalid_argument);\n\n    dem = DetectorErrorModel(R\"MODEL(\n        error(0.25) D0 D1\n        detector(1, 2, 3) D1\n        shift_detectors(5) 1\n        detector(1, 2) D2\n    )MODEL\");\n    ASSERT_EQ(\n        dem.get_detector_coordinates({0, 1, 2, 3}),\n        (std::map<uint64_t, std::vector<double>>{\n            {0, {}},\n            {1, {1, 2, 3}},\n            {2, {}},\n            {3, {6, 2}},\n        }));\n    ASSERT_THROW({ dem.get_detector_coordinates({4}); }, std::invalid_argument);\n}\n\nTEST(detector_error_model, final_detector_and_coord_shift) {\n    DetectorErrorModel dem(R\"MODEL(\n        repeat 1000 {\n            repeat 2000 {\n                repeat 3000 {\n                    shift_detectors(0, 0, 1) 0\n                }\n                shift_detectors(1) 2\n            }\n            shift_detectors(0, 1) 0\n        }\n    )MODEL\");\n    ASSERT_EQ(\n        dem.final_detector_and_coord_shift(),\n        (std::pair<uint64_t, std::vector<double>>{4000000, {2000000, 1000, 6000000000}}));\n}\n\nTEST(detector_error_model, rounded) {\n    DetectorErrorModel dem(R\"DEM(\n        error(0.01000002) D0 D1\n        repeat 2 {\n            error(0.123456789) D1 D2 L3\n        }\n        detector(0.0200000334,0.12345) D0\n        shift_detectors(5.0300004,0.12345) 3\n    )DEM\");\n\n    ASSERT_EQ(dem.rounded(0), DetectorErrorModel(R\"DEM(\n        error(0) D0 D1\n        repeat 2 {\n            error(0) D1 D2 L3\n        }\n        detector(0.0200000334,0.12345) D0\n        shift_detectors(5.0300004,0.12345) 3\n    )DEM\"));\n\n    ASSERT_EQ(dem.rounded(1), DetectorErrorModel(R\"DEM(\n        error(0) D0 D1\n        repeat 2 {\n            error(0.1) D1 D2 L3\n        }\n        detector(0.0200000334,0.12345) D0\n        shift_detectors(5.0300004,0.12345) 3\n    )DEM\"));\n\n    ASSERT_EQ(dem.rounded(2), DetectorErrorModel(R\"DEM(\n        error(0.01) D0 D1\n        repeat 2 {\n            error(0.12) D1 D2 L3\n        }\n        detector(0.0200000334,0.12345) D0\n        shift_detectors(5.0300004,0.12345) 3\n    )DEM\"));\n\n    ASSERT_EQ(dem.rounded(3), DetectorErrorModel(R\"DEM(\n        error(0.010) D0 D1\n        repeat 2 {\n            error(0.123) D1 D2 L3\n        }\n        detector(0.0200000334,0.12345) D0\n        shift_detectors(5.0300004,0.12345) 3\n    )DEM\"));\n}\n\nTEST(detector_error_model, surface_code_coords_dont_infinite_loop) {\n    CircuitGenParameters params(7, 5, \"rotated_memory_x\");\n    params.after_clifford_depolarization = 0.01;\n    params.before_measure_flip_probability = 0;\n    params.after_reset_flip_probability = 0;\n    params.before_round_data_depolarization = 0;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);\n    std::set<uint64_t> filter;\n    size_t n = dem.count_detectors();\n    for (size_t k = 0; k < n; k++) {\n        filter.insert(k);\n    }\n    auto coords1 = dem.get_detector_coordinates(filter);\n    auto coords2 = circuit.get_detector_coordinates(filter);\n    ASSERT_EQ(coords1.size(), coords2.size());\n    ASSERT_EQ(coords1.size(), n);\n    ASSERT_EQ(n, 168);\n}\n\nTEST(detector_error_model, flattened) {\n    ASSERT_EQ(DetectorErrorModel().flattened(), DetectorErrorModel());\n\n    ASSERT_EQ(\n        DetectorErrorModel(R\"DEM(\n        error(0.125) D0 D1 L0\n    )DEM\")\n            .flattened(),\n        DetectorErrorModel(R\"DEM(\n        error(0.125) D0 D1 L0\n    )DEM\"));\n\n    ASSERT_EQ(\n        DetectorErrorModel(R\"DEM(\n        error(0.125) D0 D1 L0\n        shift_detectors 5\n    )DEM\")\n            .flattened(),\n        DetectorErrorModel(R\"DEM(\n        error(0.125) D0 D1 L0\n    )DEM\"));\n\n    ASSERT_EQ(\n        DetectorErrorModel(R\"DEM(\n        shift_detectors 5\n        error(0.125) D0 D1 L0\n    )DEM\")\n            .flattened(),\n        DetectorErrorModel(R\"DEM(\n        error(0.125) D5 D6 L0\n    )DEM\"));\n\n    ASSERT_EQ(\n        DetectorErrorModel(R\"DEM(\n        detector(10, 20) D0\n        detector(10, 20, 30, 40) D1\n        logical_observable L0\n        shift_detectors(1, 2, 3) 5\n        detector(10, 20) D0\n        detector(10, 20, 30, 40) D1\n        logical_observable L1\n    )DEM\")\n            .flattened(),\n        DetectorErrorModel(R\"DEM(\n        detector(10, 20) D0\n        detector(10, 20, 30, 40) D1\n        logical_observable L0\n        detector(11, 22) D5\n        detector(11, 22, 33, 40) D6\n        logical_observable L1\n    )DEM\"));\n\n    ASSERT_EQ(\n        DetectorErrorModel(R\"DEM(\n        repeat 5 {\n            error(0.125) D0\n            shift_detectors(3) 2\n        }\n        detector(10, 20, 30, 40) D0\n    )DEM\")\n            .flattened(),\n        DetectorErrorModel(R\"DEM(\n        error(0.125) D0\n        error(0.125) D2\n        error(0.125) D4\n        error(0.125) D6\n        error(0.125) D8\n        detector(25, 20, 30, 40) D10\n    )DEM\"));\n}\n\nTEST(detector_error_model, parse_windows_newlines) {\n    ASSERT_EQ(\n        DetectorErrorModel(\"error(0.125) D0\\r\\ndetector(5) D10\\r\\n\"),\n        DetectorErrorModel(\"error(0.125) D0\\r\\ndetector(5) D10\\r\\n\"));\n}\n"
  },
  {
    "path": "src/stim/dem/detector_error_model_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport pathlib\nimport tempfile\n\nimport pytest\n\nimport stim\n\n\ndef test_init_get():\n    model = stim.DetectorErrorModel(\"\"\"\n        error(0.125) D0 L0\n        ERROR(0.25) D0 ^ D1\n        repeat 100 {\n            shift_detectors 1\n            error(0.125) D0 D1\n        }\n        shift_detectors(1, 1.5, 2, 2.5) 1\n        shift_detectors 5\n    \"\"\")\n    assert len(model) == 5\n    assert model[0] == stim.DemInstruction(\n        \"error\",\n        [0.125],\n        [stim.target_relative_detector_id(0), stim.target_logical_observable_id(0)])\n    assert model[1] == stim.DemInstruction(\n        \"error\",\n        [0.25],\n        [stim.target_relative_detector_id(0), stim.target_separator(), stim.target_relative_detector_id(1)])\n    assert model[2] == stim.DemRepeatBlock(\n        100,\n        stim.DetectorErrorModel(\"\"\"\n            shift_detectors 1\n            error(0.125) D0 D1\n        \"\"\"))\n    assert model[3] == stim.DemInstruction(\n        \"shift_detectors\",\n        [1, 1.5, 2, 2.5],\n        [1])\n    assert model[4] == stim.DemInstruction(\n        \"shift_detectors\",\n        [],\n        [5])\n\n\ndef test_equality():\n    assert stim.DetectorErrorModel() == stim.DetectorErrorModel()\n    assert not (stim.DetectorErrorModel() != stim.DetectorErrorModel())\n    assert not (stim.DetectorErrorModel() == stim.DetectorErrorModel(\"error(0.125) D0\"))\n    assert stim.DetectorErrorModel() != stim.DetectorErrorModel(\"error(0.125) D0\")\n\n    assert stim.DetectorErrorModel(\"error(0.125) D0\") == stim.DetectorErrorModel(\"error(0.125) D0\")\n    assert stim.DetectorErrorModel(\"error(0.125) D0\") != stim.DetectorErrorModel(\"error(0.126) D0\")\n    assert stim.DetectorErrorModel(\"error(0.125) D0\") != stim.DetectorErrorModel(\"detector(0.125) D0\")\n    assert stim.DetectorErrorModel(\"error(0.125) D0\") != stim.DetectorErrorModel(\"error(0.125) D1\")\n    assert stim.DetectorErrorModel(\"error(0.125) D0\") != stim.DetectorErrorModel(\"error(0.125) L0\")\n    assert stim.DetectorErrorModel(\"error(0.125) D0\") != stim.DetectorErrorModel(\"error(0.125) D0 D1\")\n    assert stim.DetectorErrorModel(\"\"\"\n        REPEAT 3 {\n            shift_detectors 4\n        }\n    \"\"\") == stim.DetectorErrorModel(\"\"\"\n        REPEAT 3 {\n            shift_detectors 4\n        }\n    \"\"\")\n    assert stim.DetectorErrorModel(\"\"\"\n        REPEAT 3 {\n            shift_detectors 4\n        }\n    \"\"\") != stim.DetectorErrorModel(\"\"\"\n        REPEAT 4 {\n            shift_detectors 4\n        }\n    \"\"\")\n    assert stim.DetectorErrorModel(\"\"\"\n        REPEAT 3 {\n            shift_detectors 4\n        }\n    \"\"\") != stim.DetectorErrorModel(\"\"\"\n        REPEAT 3 {\n            shift_detectors 5\n        }\n    \"\"\")\n\n\ndef test_repr():\n    v = stim.DetectorErrorModel()\n    assert eval(repr(v), {\"stim\": stim}) == v\n    v = stim.DetectorErrorModel(\"error(0.125) D0 D1\")\n    assert eval(repr(v), {\"stim\": stim}) == v\n\n\ndef test_approx_equals():\n    base = stim.DetectorErrorModel(\"error(0.099) D0\")\n    assert not base.approx_equals(stim.DetectorErrorModel(\"error(0.101) D0\"), atol=0)\n    assert not base.approx_equals(stim.DetectorErrorModel(\"error(0.101) D0\"), atol=0.00001)\n    assert base.approx_equals(stim.DetectorErrorModel(\"error(0.101) D0\"), atol=0.01)\n    assert base.approx_equals(stim.DetectorErrorModel(\"error(0.101) D0\"), atol=999)\n    assert not base.approx_equals(stim.DetectorErrorModel(\"error(0.101) D0 D1\"), atol=999)\n\n    assert not base.approx_equals(object(), atol=999)\n    assert not base.approx_equals(stim.PauliString(\"XYZ\"), atol=999)\n\n\ndef test_append():\n    m = stim.DetectorErrorModel()\n    m.append(\"error\", 0.125, [\n        stim.DemTarget.relative_detector_id(1),\n    ])\n    m.append(\"error\", 0.25, [\n        stim.DemTarget.relative_detector_id(1),\n        stim.DemTarget.separator(),\n        stim.DemTarget.relative_detector_id(2),\n        stim.DemTarget.logical_observable_id(3),\n    ])\n    m.append(\"shift_detectors\", (1, 2, 3), [5])\n    m += m * 3\n    m.append(m[0])\n    m.append(m[-2])\n    assert m == stim.DetectorErrorModel(\"\"\"\n        error(0.125) D1\n        error(0.25) D1 ^ D2 L3\n        shift_detectors(1, 2, 3) 5\n        repeat 3 {\n            error(0.125) D1\n            error(0.25) D1 ^ D2 L3\n            shift_detectors(1, 2, 3) 5\n        }\n        error(0.125) D1\n        repeat 3 {\n            error(0.125) D1\n            error(0.25) D1 ^ D2 L3\n            shift_detectors(1, 2, 3) 5\n        }\n    \"\"\")\n\n\ndef test_append_bad():\n    m = stim.DetectorErrorModel()\n    m.append(\"error\", 0.125, [stim.target_relative_detector_id(0)])\n    m.append(\"error\", [0.125], [stim.target_relative_detector_id(0)])\n    m.append(\"shift_detectors\", [], [5])\n    m += m * 3\n\n    with pytest.raises(ValueError, match=r\"Bad target 'stim.DemTarget\\('D0'\\)' for instruction 'shift_detectors'\"):\n        m.append(\"shift_detectors\", [0.125, 0.25], [stim.target_relative_detector_id(0)])\n    with pytest.raises(ValueError, match=\"takes 1 argument\"):\n        m.append(\"error\", [0.125, 0.25], [stim.target_relative_detector_id(0)])\n\n    with pytest.raises(ValueError, match=\"Bad target '0' for instruction 'error'\"):\n        m.append(\"error\", [0.125], [0])\n\n    with pytest.raises(ValueError, match=\"First argument\"):\n        m.append(None)\n    with pytest.raises(ValueError, match=\"First argument\"):\n        m.append(object())\n    with pytest.raises(ValueError, match=\"Must specify.*instruction name\"):\n        m.append(\"error\")\n    with pytest.raises(ValueError, match=\"Can't specify.*instruction is a\"):\n        m.append(m[0], 0.125, [])\n    with pytest.raises(ValueError, match=\"Can't specify.*instruction is a\"):\n        m.append(m[-1], 0.125, [])\n\n\ndef test_pickle():\n    import pickle\n\n    t = stim.DetectorErrorModel(\"\"\"\n        repeat 100 {\n            error(0.25) D0 L1\n            shift_detectors(1, 2) 3\n        }\n    \"\"\")\n    a = pickle.dumps(t)\n    assert pickle.loads(a) == t\n\n\ndef test_count_errors():\n    assert stim.DetectorErrorModel().num_errors == 0\n\n    assert stim.DetectorErrorModel(\"\"\"\n        logical_observable L100\n        detector D100\n        shift_detectors(100, 100, 100) 100\n        error(0.125) D100\n    \"\"\").num_errors == 1\n\n    assert stim.DetectorErrorModel(\"\"\"\n        error(0.125) D0\n        REPEAT 100 {\n            REPEAT 5 {\n                error(0.25) D1\n            }\n        }\n    \"\"\").num_errors == 501\n\n\ndef test_shortest_graphlike_error_trivial():\n    with pytest.raises(ValueError, match=\"any graphlike logical errors\"):\n        _ = stim.DetectorErrorModel().shortest_graphlike_error()\n    with pytest.raises(ValueError, match=\"any graphlike logical errors\"):\n        _ = stim.DetectorErrorModel(\"\"\"\n            error(0.1) D0\n        \"\"\").shortest_graphlike_error()\n    with pytest.raises(ValueError, match=\"any graphlike logical errors\"):\n        _ = stim.DetectorErrorModel(\"\"\"\n            error(0.1) D0 L0\n        \"\"\").shortest_graphlike_error()\n    assert stim.DetectorErrorModel(\"\"\"\n        error(0.1) L0\n    \"\"\").shortest_graphlike_error() == stim.DetectorErrorModel(\"\"\"\n        error(1) L0\n    \"\"\")\n    assert stim.DetectorErrorModel(\"\"\"\n        error(0.1) D0 D1 L0\n        error(0.1) D0 D1\n    \"\"\").shortest_graphlike_error() == stim.DetectorErrorModel(\"\"\"\n        error(1) D0 D1\n        error(1) D0 D1 L0\n    \"\"\")\n\n\ndef test_shortest_graphlike_error_line():\n    assert stim.DetectorErrorModel(\"\"\"\n        error(0.125) D0\n        error(0.125) D0 D1\n        error(0.125) D1 L55\n        error(0.125) D1\n    \"\"\").shortest_graphlike_error() == stim.DetectorErrorModel(\"\"\"\n        error(1) D1\n        error(1) D1 L55\n    \"\"\")\n\n    assert len(stim.DetectorErrorModel(\"\"\"\n        error(0.1) D0 D1 L5\n        REPEAT 1000 {\n            error(0.1) D0 D2\n            error(0.1) D1 D3\n            shift_detectors 2\n        }\n        error(0.1) D0\n        error(0.1) D1\n    \"\"\").shortest_graphlike_error()) == 2003\n\n\ndef test_shortest_graphlike_error_ignore():\n    assert stim.DetectorErrorModel(\"\"\"\n        error(0.125) D0 D1 D2\n        error(0.125) L0\n    \"\"\").shortest_graphlike_error(ignore_ungraphlike_errors=True) == stim.DetectorErrorModel(\"\"\"\n        error(1) L0\n    \"\"\")\n\n\ndef test_shortest_graphlike_error_rep_code():\n    circuit = stim.Circuit.generated(\"repetition_code:memory\",\n                                     rounds=10,\n                                     distance=7,\n                                     before_round_data_depolarization=0.01)\n    model = circuit.detector_error_model(decompose_errors=True)\n    assert len(model.shortest_graphlike_error()) == 7\n\n\ndef test_shortest_graphlike_error_msgs():\n    with pytest.raises(ValueError, match=r\"NO OBSERVABLES(.|\\n)*NO DETECTORS(.|\\n)*NO ERRORS\"):\n        stim.Circuit().detector_error_model(decompose_errors=True).shortest_graphlike_error()\n\n    c = stim.Circuit(\"\"\"\n        M 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=r\"NO DETECTORS(.|\\n)*NO ERRORS\"):\n        c.detector_error_model(decompose_errors=True).shortest_graphlike_error()\n\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n    \"\"\")\n    with pytest.raises(ValueError, match=r\"NO OBSERVABLES(.|\\n)*NO DETECTORS(.|\\n)*NO ERRORS\"):\n        c.detector_error_model(decompose_errors=True).shortest_graphlike_error()\n\n    c = stim.Circuit(\"\"\"\n        M 0\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=r\"NO ERRORS\"):\n        c.detector_error_model(decompose_errors=True).shortest_graphlike_error()\n\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.1) 0\n        M 0\n        DETECTOR rec[-1]\n    \"\"\")\n    with pytest.raises(ValueError, match=r\"NO OBSERVABLES\"):\n        c.detector_error_model(decompose_errors=True).shortest_graphlike_error()\n\n\ndef test_coords():\n    circuit = stim.Circuit(\"\"\"\n        M 0\n        DETECTOR(1, 2, 3) rec[-1]\n        REPEAT 3 {\n            DETECTOR(2) rec[-1]\n            SHIFT_COORDS(5)\n        }\n    \"\"\")\n    dem = circuit.detector_error_model()\n\n    assert dem.get_detector_coordinates() == {\n        0: [1, 2, 3],\n        1: [2],\n        2: [7],\n        3: [12],\n    }\n    assert circuit.get_detector_coordinates() == {\n        0: [1, 2, 3],\n        1: [2],\n        2: [7],\n        3: [12],\n    }\n\n    assert dem.get_detector_coordinates([1]) == {\n        1: [2],\n    }\n    assert circuit.get_detector_coordinates([1]) == {\n        1: [2],\n    }\n    assert dem.get_detector_coordinates(1) == {\n        1: [2],\n    }\n    assert circuit.get_detector_coordinates(1) == {\n        1: [2],\n    }\n    assert dem.get_detector_coordinates({1}) == {\n        1: [2],\n    }\n    assert circuit.get_detector_coordinates({1}) == {\n        1: [2],\n    }\n    assert dem.get_detector_coordinates(stim.DemTarget.relative_detector_id(1)) == {\n        1: [2],\n    }\n    assert circuit.get_detector_coordinates(stim.DemTarget.relative_detector_id(1)) == {\n        1: [2],\n    }\n    assert dem.get_detector_coordinates((stim.DemTarget.relative_detector_id(1),)) == {\n        1: [2],\n    }\n    assert circuit.get_detector_coordinates((stim.DemTarget.relative_detector_id(1),)) == {\n        1: [2],\n    }\n\n    assert dem.get_detector_coordinates(only=[2, 3]) == {\n        2: [7],\n        3: [12],\n    }\n    assert circuit.get_detector_coordinates(only=[2, 3]) == {\n        2: [7],\n        3: [12],\n    }\n\n    with pytest.raises(ValueError, match=\"Expected a detector id\"):\n        dem.get_detector_coordinates([-1])\n    with pytest.raises(ValueError, match=\"too big\"):\n        dem.get_detector_coordinates([500])\n    with pytest.raises(ValueError, match=\"Expected a detector id\"):\n        circuit.get_detector_coordinates([-1])\n    with pytest.raises(ValueError, match=\"too big\"):\n        circuit.get_detector_coordinates([500])\n\n\ndef test_dem_from_file():\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = tmpdir + '/tmp.stim'\n        with open(path, 'w') as f:\n            print('error(0.125) D0 L5', file=f)\n        assert stim.DetectorErrorModel.from_file(path) == stim.DetectorErrorModel('error(0.125) D0 L5')\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = pathlib.Path(tmpdir) / 'tmp.stim'\n        with open(path, 'w') as f:\n            print('error(0.125) D0 L5', file=f)\n        assert stim.DetectorErrorModel.from_file(path) == stim.DetectorErrorModel('error(0.125) D0 L5')\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = tmpdir + '/tmp.stim'\n        with open(path, 'w') as f:\n            print('error(0.125) D0 L5', file=f)\n        with open(path) as f:\n            assert stim.DetectorErrorModel.from_file(f) == stim.DetectorErrorModel('error(0.125) D0 L5')\n\n    with pytest.raises(ValueError, match=\"how to read\"):\n        stim.DetectorErrorModel.from_file(object())\n    with pytest.raises(ValueError, match=\"how to read\"):\n        stim.DetectorErrorModel.from_file(123)\n\n\ndef test_dem_to_file():\n    c = stim.DetectorErrorModel('error(0.125) D0 L5\\n')\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = tmpdir + '/tmp.stim'\n        c.to_file(path)\n        with open(path) as f:\n            assert f.read() == 'error(0.125) D0 L5\\n'\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = pathlib.Path(tmpdir) / 'tmp.stim'\n        c.to_file(path)\n        with open(path) as f:\n            assert f.read() == 'error(0.125) D0 L5\\n'\n\n    with tempfile.TemporaryDirectory() as tmpdir:\n        path = tmpdir + '/tmp.stim'\n        with open(path, 'w') as f:\n            c.to_file(f)\n        with open(path) as f:\n            assert f.read() == 'error(0.125) D0 L5\\n'\n\n    with pytest.raises(ValueError, match=\"how to write\"):\n        c.to_file(object())\n    with pytest.raises(ValueError, match=\"how to write\"):\n        c.to_file(123)\n\n\ndef test_flattened():\n    dem = stim.DetectorErrorModel(\"\"\"\n        shift_detectors 5\n        repeat 2 {\n            error(0.125) D0 D1\n        }\n    \"\"\")\n    assert dem.flattened() == stim.DetectorErrorModel(\"\"\"\n        error(0.125) D5 D6\n        error(0.125) D5 D6\n    \"\"\")\n\n\ndef test_rounded():\n    dem = stim.DetectorErrorModel(\"\"\"\n        error(0.1248) D0 D1\n    \"\"\")\n    assert dem.rounded(1) == stim.DetectorErrorModel(\"\"\"\n        error(0.1) D0 D1\n    \"\"\")\n    assert dem.rounded(2) == stim.DetectorErrorModel(\"\"\"\n        error(0.12) D0 D1\n    \"\"\")\n    assert dem.rounded(3) == stim.DetectorErrorModel(\"\"\"\n        error(0.125) D0 D1\n    \"\"\")\n    assert dem.rounded(4) == stim.DetectorErrorModel(\"\"\"\n        error(0.1248) D0 D1\n    \"\"\")\n    assert dem.rounded(5) == stim.DetectorErrorModel(\"\"\"\n        error(0.1248) D0 D1\n    \"\"\")\n\n    dem = stim.DetectorErrorModel(\"\"\"\n        error(0.01248) D0 D1\n    \"\"\")\n    assert dem.rounded(1) == stim.DetectorErrorModel(\"\"\"\n        error(0) D0 D1\n    \"\"\")\n    assert dem.rounded(2) == stim.DetectorErrorModel(\"\"\"\n        error(0.01) D0 D1\n    \"\"\")\n    assert dem.rounded(3) == stim.DetectorErrorModel(\"\"\"\n        error(0.012) D0 D1\n    \"\"\")\n    assert dem.rounded(4) == stim.DetectorErrorModel(\"\"\"\n        error(0.0125) D0 D1\n    \"\"\")\n\n\ndef test_diagram():\n    circuit = stim.Circuit.generated(\"repetition_code:memory\",\n                                     rounds=10,\n                                     distance=7,\n                                     before_round_data_depolarization=0.01)\n    dem = circuit.detector_error_model(decompose_errors=True)\n    assert dem.diagram(\"matchgraph-svg\") is not None\n    assert dem.diagram(\"matchgraph-3d\") is not None\n    assert dem.diagram(\"matchgraph-3d-html\") is not None\n    assert dem.diagram(\"match-graph-svg\") is not None\n    assert dem.diagram(type=\"match-graph-svg\") is not None\n    assert dem.diagram(type=\"match-graph-3d\") is not None\n    assert dem.diagram(type=\"match-graph-3d-html\") is not None\n    assert \"iframe\" in str(dem.diagram(type=\"match-graph-svg-html\"))\n\n\ndef test_shortest_graphlike_error_remnant():\n    c = stim.Circuit(\"\"\"\n        X_ERROR(0.125) 0 1 2 3 4 5 6 7 10\n        E(0.125) X2 X3 X10\n        M 0 1 2 3 4 5 6 7 10\n        OBSERVABLE_INCLUDE(0) rec[-2]\n        DETECTOR rec[-1]\n        DETECTOR rec[-2] rec[-3]\n        DETECTOR rec[-3] rec[-4]\n        DETECTOR rec[-4] rec[-5]\n        DETECTOR rec[-5] rec[-6]\n        DETECTOR rec[-6] rec[-7]\n        DETECTOR rec[-7] rec[-8]\n        DETECTOR rec[-8] rec[-9]\n    \"\"\")\n    d = stim.DetectorErrorModel(\"\"\"\n        error(0.125) D0\n        error(0.125) D0 ^ D4 D6\n        error(0.125) D1 D2\n        error(0.125) D1 L0\n        error(0.125) D2 D3\n        error(0.125) D3 D4\n        error(0.125) D4 D5\n        error(0.125) D5 D6\n        error(0.125) D6 D7\n        error(0.125) D7\n    \"\"\")\n    assert c.detector_error_model(decompose_errors=True) == d\n    assert len(c.shortest_graphlike_error(ignore_ungraphlike_errors=False)) == 7\n    assert len(d.shortest_graphlike_error(ignore_ungraphlike_errors=False)) == 7\n    assert len(c.shortest_graphlike_error(ignore_ungraphlike_errors=True)) == 8\n    assert len(d.shortest_graphlike_error(ignore_ungraphlike_errors=True)) == 8\n    assert len(c.shortest_graphlike_error()) == 8\n    assert len(d.shortest_graphlike_error()) == 8\n\n\ndef test_init_parse():\n    assert stim.DemInstruction(\"error(0.125) D0 D1\") == stim.DemInstruction(\"error\", [0.125], [stim.DemTarget(\"D0\"), stim.DemTarget(\"D1\")])\n\n\ndef test_without_tags():\n    dem = stim.DetectorErrorModel(\"\"\"\n        error[tag](0.25) D5\n    \"\"\")\n    assert dem.without_tags() == stim.DetectorErrorModel(\"\"\"\n        error(0.25) D5\n    \"\"\")\n\n\ndef test_append_dem_to_dem():\n    dem = stim.DetectorErrorModel(\"\"\"\n        error(0.25) D0\n    \"\"\")\n    dem.append(stim.DetectorErrorModel(\"\"\"\n        error(0.125) D1\n        error(0.25) D2\n    \"\"\"))\n    assert dem == stim.DetectorErrorModel(\"\"\"\n        error(0.25) D0\n        error(0.125) D1\n        error(0.25) D2\n    \"\"\")"
  },
  {
    "path": "src/stim/dem/detector_error_model_repeat_block.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/dem/detector_error_model_repeat_block.pybind.h\"\n\n#include \"stim/dem/dem_instruction.pybind.h\"\n#include \"stim/dem/detector_error_model.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\npybind11::class_<ExposedDemRepeatBlock> stim_pybind::pybind_detector_error_model_repeat_block(pybind11::module &m) {\n    return pybind11::class_<ExposedDemRepeatBlock>(\n        m,\n        \"DemRepeatBlock\",\n        clean_doc_string(R\"DOC(\n            A repeat block from a detector error model.\n\n            Examples:\n                >>> import stim\n                >>> model = stim.DetectorErrorModel('''\n                ...     repeat 100 {\n                ...         error(0.125) D0 D1\n                ...         shift_detectors 1\n                ...     }\n                ... ''')\n                >>> model[0]\n                stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n                    error(0.125) D0 D1\n                    shift_detectors 1\n                '''))\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_detector_error_model_repeat_block_methods(\n    pybind11::module &m, pybind11::class_<ExposedDemRepeatBlock> &c) {\n    c.def(\n        pybind11::init<uint64_t, DetectorErrorModel>(),\n        pybind11::arg(\"repeat_count\"),\n        pybind11::arg(\"block\"),\n        clean_doc_string(R\"DOC(\n            Creates a stim.DemRepeatBlock.\n\n            Args:\n                repeat_count: The number of times the repeat block's body is supposed to\n                    execute.\n                block: The body of the repeat block as a DetectorErrorModel containing the\n                    instructions to repeat.\n\n            Examples:\n                >>> import stim\n                >>> repeat_block = stim.DemRepeatBlock(100, stim.DetectorErrorModel('''\n                ...     error(0.125) D0 D1\n                ...     shift_detectors 1\n                ... '''))\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"repeat_count\",\n        &ExposedDemRepeatBlock::repeat_count,\n        \"The number of times the repeat block's body is supposed to execute.\");\n    c.def(\n        \"body_copy\",\n        &ExposedDemRepeatBlock::body_copy,\n        clean_doc_string(R\"DOC(\n            Returns a copy of the block's body, as a stim.DetectorErrorModel.\n\n            Examples:\n                >>> import stim\n                >>> body = stim.DetectorErrorModel('''\n                ...     error(0.125) D0 D1\n                ...     shift_detectors 1\n                ... ''')\n                >>> repeat_block = stim.DemRepeatBlock(100, body)\n                >>> repeat_block.body_copy() == body\n                True\n                >>> repeat_block.body_copy() is repeat_block.body_copy()\n                False\n        )DOC\")\n            .data());\n    c.def_property_readonly(\n        \"type\",\n        [](const ExposedDemRepeatBlock &self) -> pybind11::object {\n            return pybind11::cast(\"repeat\");\n        },\n        clean_doc_string(R\"DOC(\n            Returns the type name \"repeat\".\n\n            This is a duck-typing convenience method. It exists so that code that doesn't\n            know whether it has a `stim.DemInstruction` or a `stim.DemRepeatBlock`\n            can check the type field without having to do an `instanceof` check first.\n\n            Examples:\n                >>> import stim\n                >>> dem = stim.DetectorErrorModel('''\n                ...     error(0.1) D0 L0\n                ...     repeat 5 {\n                ...         error(0.1) D0 D1\n                ...         shift_detectors 1\n                ...     }\n                ...     logical_observable L0\n                ... ''')\n                >>> [instruction.type for instruction in dem]\n                ['error', 'repeat', 'logical_observable']\n        )DOC\")\n            .data());\n    c.def(pybind11::self == pybind11::self, \"Determines if two repeat blocks are identical.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two repeat blocks are different.\");\n\n    c.def(\n        \"__repr__\",\n        &ExposedDemRepeatBlock::repr,\n        \"Returns text that is a valid python expression evaluating to an equivalent `stim.DemRepeatBlock`.\");\n}\n\nstim::DetectorErrorModel ExposedDemRepeatBlock::body_copy() {\n    return body;\n}\nstd::string ExposedDemRepeatBlock::repr() const {\n    std::stringstream out;\n    out << \"stim.DemRepeatBlock(\" << repeat_count << \", \" << detector_error_model_repr(body);\n    if (!tag.empty()) {\n        out << \", tag=\" << pybind11::cast<std::string>(pybind11::repr(pybind11::cast(tag)));\n    }\n    out << \")\";\n    return out.str();\n}\nbool ExposedDemRepeatBlock::operator==(const ExposedDemRepeatBlock &other) const {\n    return repeat_count == other.repeat_count && body == other.body && tag == other.tag;\n}\nbool ExposedDemRepeatBlock::operator!=(const ExposedDemRepeatBlock &other) const {\n    return !(*this == other);\n}\n"
  },
  {
    "path": "src/stim/dem/detector_error_model_repeat_block.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_DEM_DETECTOR_ERROR_MODEL_REPEAT_BLOCK_PYBIND_H\n#define _STIM_DEM_DETECTOR_ERROR_MODEL_REPEAT_BLOCK_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/dem/detector_error_model.h\"\n\nnamespace stim_pybind {\n\nstruct ExposedDemRepeatBlock {\n    uint64_t repeat_count;\n    stim::DetectorErrorModel body;\n    std::string tag;\n\n    stim::DetectorErrorModel body_copy();\n    std::string repr() const;\n    bool operator==(const ExposedDemRepeatBlock &other) const;\n    bool operator!=(const ExposedDemRepeatBlock &other) const;\n};\n\npybind11::class_<ExposedDemRepeatBlock> pybind_detector_error_model_repeat_block(pybind11::module &m);\nvoid pybind_detector_error_model_repeat_block_methods(pybind11::module &m, pybind11::class_<ExposedDemRepeatBlock> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/dem/detector_error_model_repeat_block_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport stim\n\n\ndef test_init_vs_properties():\n    v = stim.DemRepeatBlock(5, stim.DetectorErrorModel('error(0.125) D1 L2'))\n    assert v.repeat_count == 5\n    assert v.body_copy() == stim.DetectorErrorModel('error(0.125) D1 L2')\n    assert v.body_copy() is not v.body_copy()\n\n\ndef test_equality():\n    m0 = stim.DetectorErrorModel()\n    m1 = stim.DetectorErrorModel('error(0.125) D1 L2')\n    assert stim.DemRepeatBlock(5, m0) == stim.DemRepeatBlock(5, m0)\n    assert not (stim.DemRepeatBlock(5, m0) != stim.DemRepeatBlock(5, m0))\n    assert stim.DemRepeatBlock(5, m0) != stim.DemRepeatBlock(5, m1)\n    assert not (stim.DemRepeatBlock(5, m0) == stim.DemRepeatBlock(5, m1))\n    assert stim.DemRepeatBlock(5, m0) != stim.DemRepeatBlock(6, m0)\n\n\ndef test_repr():\n    v = stim.DemRepeatBlock(5, stim.DetectorErrorModel('error(0.125) D1 L2'))\n    assert eval(repr(v), {\"stim\": stim}) == v\n\n\ndef test_type():\n    assert [e.type for e in stim.DetectorErrorModel('''\n        detector D0\n        REPEAT 5 {\n            error(0.1) D0\n        }\n        logical_observable L0\n    ''')] == ['detector', 'repeat', 'logical_observable']\n"
  },
  {
    "path": "src/stim/dem/detector_error_model_target.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/dem/detector_error_model_target.pybind.h\"\n\n#include \"stim/dem/detector_error_model.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\npybind11::class_<ExposedDemTarget> stim_pybind::pybind_detector_error_model_target(pybind11::module &m) {\n    return pybind11::class_<ExposedDemTarget>(\n        m, \"DemTarget\", \"An instruction target from a detector error model (.dem) file.\");\n}\n\nvoid stim_pybind::pybind_detector_error_model_target_methods(\n    pybind11::module &m, pybind11::class_<ExposedDemTarget> &c) {\n    c.def(\n        pybind11::init([](const pybind11::object &arg) -> ExposedDemTarget {\n            if (pybind11::isinstance<ExposedDemTarget>(arg)) {\n                return pybind11::cast<ExposedDemTarget>(arg);\n            }\n            if (pybind11::isinstance<pybind11::str>(arg)) {\n                std::string_view contents = pybind11::cast<std::string_view>(arg);\n                return DemTarget::from_text(contents);\n            }\n\n            std::stringstream ss;\n            ss << \"Don't know how to convert this into a stim.DemTarget: \";\n            ss << pybind11::repr(arg);\n            throw pybind11::type_error(ss.str());\n        }),\n        pybind11::arg(\"arg\"),\n        pybind11::pos_only(),\n        clean_doc_string(R\"DOC(\n            Creates a stim.DemTarget from the given object.\n\n            Args:\n                arg: A string to parse as a stim.DemTarget, or some other object to\n                    convert into a stim.DemTarget.\n\n            Examples:\n                >>> import stim\n                >>> stim.DemTarget(\"D5\") == stim.target_relative_detector_id(5)\n                True\n                >>> stim.DemTarget(\"L2\") == stim.target_logical_observable_id(2)\n                True\n                >>> stim.DemTarget(\"^\") == stim.target_separator()\n                True\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_relative_detector_id\",\n        &ExposedDemTarget::relative_detector_id,\n        pybind11::arg(\"index\"),\n        clean_doc_string(R\"DOC(\n            Returns a relative detector id (e.g. \"D5\" in a .dem file).\n\n            Args:\n                index: The index of the detector, relative to the current detector offset.\n\n            Returns:\n                The relative detector target.\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel()\n                >>> m.append(\"error\", 0.25, [\n                ...     stim.target_relative_detector_id(13)\n                ... ])\n                >>> print(repr(m))\n                stim.DetectorErrorModel('''\n                    error(0.25) D13\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_logical_observable_id\",\n        &ExposedDemTarget::observable_id,\n        pybind11::arg(\"index\"),\n        clean_doc_string(R\"DOC(\n            Returns a logical observable id identifying a frame change.\n\n            Args:\n                index: The index of the observable.\n\n            Returns:\n                The logical observable target.\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel()\n                >>> m.append(\"error\", 0.25, [\n                ...     stim.target_logical_observable_id(13)\n                ... ])\n                >>> print(repr(m))\n                stim.DetectorErrorModel('''\n                    error(0.25) L13\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_separator\",\n        &ExposedDemTarget::separator,\n        clean_doc_string(R\"DOC(\n            Returns a target separator (e.g. \"^\" in a .dem file).\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel()\n                >>> m.append(\"error\", 0.25, [\n                ...     stim.target_relative_detector_id(1),\n                ...     stim.target_separator(),\n                ...     stim.target_relative_detector_id(2),\n                ... ])\n                >>> print(repr(m))\n                stim.DetectorErrorModel('''\n                    error(0.25) D1 ^ D2\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two `stim.DemTarget`s are identical.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two `stim.DemTarget`s are different.\");\n\n    c.def_static(\n        \"relative_detector_id\",\n        &ExposedDemTarget::relative_detector_id,\n        pybind11::arg(\"index\"),\n        clean_doc_string(R\"DOC(\n            Returns a relative detector id (e.g. \"D5\" in a .dem file).\n\n            Args:\n                index: The index of the detector, relative to the current detector offset.\n\n            Returns:\n                The relative detector target.\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel()\n                >>> m.append(\"error\", 0.25, [\n                ...     stim.DemTarget.relative_detector_id(13)\n                ... ])\n                >>> print(repr(m))\n                stim.DetectorErrorModel('''\n                    error(0.25) D13\n                ''')\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"logical_observable_id\",\n        &ExposedDemTarget::observable_id,\n        pybind11::arg(\"index\"),\n        clean_doc_string(R\"DOC(\n            Returns a logical observable id identifying a frame change.\n\n            Args:\n                index: The index of the observable.\n\n            Returns:\n                The logical observable target.\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel()\n                >>> m.append(\"error\", 0.25, [\n                ...     stim.DemTarget.logical_observable_id(13)\n                ... ])\n                >>> print(repr(m))\n                stim.DetectorErrorModel('''\n                    error(0.25) L13\n                ''')\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"separator\",\n        &ExposedDemTarget::separator,\n        clean_doc_string(R\"DOC(\n            Returns a target separator (e.g. \"^\" in a .dem file).\n\n            Examples:\n                >>> import stim\n                >>> m = stim.DetectorErrorModel()\n                >>> m.append(\"error\", 0.25, [\n                ...     stim.DemTarget.relative_detector_id(1),\n                ...     stim.DemTarget.separator(),\n                ...     stim.DemTarget.relative_detector_id(2),\n                ... ])\n                >>> print(repr(m))\n                stim.DetectorErrorModel('''\n                    error(0.25) D1 ^ D2\n                ''')\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__repr__\", &ExposedDemTarget::repr, \"Returns valid python code evaluating to an equivalent `stim.DemTarget`.\");\n\n    c.def(\"__str__\", &ExposedDemTarget::str, \"Returns a text description of the detector error model target.\");\n\n    c.def(\n        \"is_relative_detector_id\",\n        &ExposedDemTarget::is_relative_detector_id,\n        clean_doc_string(R\"DOC(\n            Determines if the detector error model target is a relative detector id target.\n\n            In a detector error model file, detectors are prefixed by `D`. For\n            example, in `error(0.25) D0 L1` the `D0` is a relative detector target.\n\n            Examples:\n                >>> import stim\n                >>> stim.DemTarget(\"L2\").is_relative_detector_id()\n                False\n                >>> stim.DemTarget(\"D3\").is_relative_detector_id()\n                True\n                >>> stim.DemTarget(\"^\").is_relative_detector_id()\n                False\n        )DOC\")\n            .data());\n\n    c.def(\n        \"is_logical_observable_id\",\n        &ExposedDemTarget::is_observable_id,\n        clean_doc_string(R\"DOC(\n            Determines if the detector error model target is a logical observable id target.\n\n            In a detector error model file, observable targets are prefixed by `L`. For\n            example, in `error(0.25) D0 L1` the `L1` is an observable target.\n\n            Examples:\n                >>> import stim\n                >>> stim.DemTarget(\"L2\").is_logical_observable_id()\n                True\n                >>> stim.DemTarget(\"D3\").is_logical_observable_id()\n                False\n                >>> stim.DemTarget(\"^\").is_logical_observable_id()\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"val\",\n        &ExposedDemTarget::val,\n        clean_doc_string(R\"DOC(\n            Returns the target's integer value.\n\n            Example:\n                >>> import stim\n                >>> stim.DemTarget(\"D5\").val\n                5\n                >>> stim.DemTarget(\"L6\").val\n                6\n        )DOC\")\n            .data());\n\n    c.def(\n        \"is_separator\",\n        &ExposedDemTarget::is_separator,\n        clean_doc_string(R\"DOC(\n            Determines if the detector error model target is a separator.\n\n            Separates separate the components of a suggested decompositions within an error.\n            For example, the `^` in `error(0.25) D1 D2 ^ D3 D4` is the separator.\n\n            Examples:\n                >>> import stim\n                >>> stim.DemTarget(\"L2\").is_separator()\n                False\n                >>> stim.DemTarget(\"D3\").is_separator()\n                False\n                >>> stim.DemTarget(\"^\").is_separator()\n                True\n        )DOC\")\n            .data());\n\n    c.def(\"__hash__\", [](const ExposedDemTarget &self) {\n        return pybind11::hash(pybind11::make_tuple(\"DemInstruction\", self.data));\n    });\n}\n\nstd::string ExposedDemTarget::repr() const {\n    std::stringstream out;\n    if (is_relative_detector_id()) {\n        out << \"stim.DemTarget('D\" << raw_id() << \"')\";\n    } else if (is_separator()) {\n        out << \"stim.target_separator()\";\n    } else {\n        out << \"stim.DemTarget('L\" << raw_id() << \"')\";\n    }\n    return out.str();\n}\nExposedDemTarget::ExposedDemTarget(DemTarget target) : DemTarget(target) {\n}\nExposedDemTarget ExposedDemTarget::observable_id(uint32_t id) {\n    return {DemTarget::observable_id(id)};\n}\nExposedDemTarget ExposedDemTarget::relative_detector_id(uint64_t id) {\n    return {DemTarget::relative_detector_id(id)};\n}\nExposedDemTarget ExposedDemTarget::separator() {\n    return ExposedDemTarget(DemTarget::separator());\n}\nstim::DemTarget ExposedDemTarget::internal() const {\n    return {data};\n}\n"
  },
  {
    "path": "src/stim/dem/detector_error_model_target.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_DEM_DETECTOR_ERROR_MODEL_TARGET_PYBIND_H\n#define _STIM_DEM_DETECTOR_ERROR_MODEL_TARGET_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/dem/detector_error_model.h\"\n\nnamespace stim_pybind {\n\nstruct ExposedDemTarget : stim::DemTarget {\n    std::string repr() const;\n    ExposedDemTarget(stim::DemTarget target);\n    stim::DemTarget internal() const;\n    static ExposedDemTarget observable_id(uint32_t id);\n    static ExposedDemTarget relative_detector_id(uint64_t id);\n    static ExposedDemTarget separator();\n};\n\npybind11::class_<ExposedDemTarget> pybind_detector_error_model_target(pybind11::module &m);\nvoid pybind_detector_error_model_target_methods(pybind11::module &m, pybind11::class_<ExposedDemTarget> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/dem/detector_error_model_target_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport pytest\nimport stim\n\n\ndef test_equality():\n    assert stim.target_relative_detector_id(5) == stim.target_relative_detector_id(5)\n    assert not (stim.target_relative_detector_id(5) != stim.target_relative_detector_id(5))\n    assert stim.target_relative_detector_id(4) != stim.target_relative_detector_id(5)\n    assert not (stim.target_relative_detector_id(4) == stim.target_relative_detector_id(5))\n\n    assert stim.target_relative_detector_id(5) != stim.target_logical_observable_id(5)\n    assert stim.target_logical_observable_id(5) == stim.target_logical_observable_id(5)\n    assert stim.target_relative_detector_id(5) != stim.target_separator()\n    assert stim.target_separator() == stim.target_separator()\n\n\ndef test_str():\n    assert str(stim.target_relative_detector_id(5)) == \"D5\"\n    assert str(stim.target_logical_observable_id(6)) == \"L6\"\n    assert str(stim.target_separator()) == \"^\"\n\n\ndef test_properties():\n    assert stim.target_relative_detector_id(6).val == 6\n    assert stim.target_relative_detector_id(5).val == 5\n    assert stim.target_relative_detector_id(5).is_relative_detector_id()\n    assert not stim.target_relative_detector_id(5).is_logical_observable_id()\n    assert not stim.target_relative_detector_id(5).is_separator()\n\n    assert stim.target_logical_observable_id(6).val == 6\n    assert stim.target_logical_observable_id(5).val == 5\n    assert not stim.target_logical_observable_id(5).is_relative_detector_id()\n    assert stim.target_logical_observable_id(5).is_logical_observable_id()\n    assert not stim.target_logical_observable_id(5).is_separator()\n\n    assert not stim.target_separator().is_relative_detector_id()\n    assert not stim.target_separator().is_logical_observable_id()\n    assert stim.target_separator().is_separator()\n    with pytest.raises(ValueError, match=\"Separator\"):\n        _ = stim.target_separator().val\n\n\ndef test_repr():\n    v = stim.target_relative_detector_id(5)\n    assert eval(repr(v), {\"stim\": stim}) == v\n    v = stim.target_logical_observable_id(6)\n    assert eval(repr(v), {\"stim\": stim}) == v\n    v = stim.target_separator()\n    assert eval(repr(v), {\"stim\": stim}) == v\n\n\ndef test_static_constructors():\n    assert stim.DemTarget.relative_detector_id(5) == stim.target_relative_detector_id(5)\n    assert stim.DemTarget.logical_observable_id(5) == stim.target_logical_observable_id(5)\n    assert stim.DemTarget.separator() == stim.target_separator()\n\n\ndef test_hashable():\n    a = stim.DemTarget.relative_detector_id(3)\n    b = stim.DemTarget.logical_observable_id(5)\n    c = stim.DemTarget.relative_detector_id(3)\n    assert hash(a) == hash(c)\n    assert len({a, b, c}) == 2\n\n\ndef test_init():\n    assert stim.DemTarget(\"D0\") == stim.target_relative_detector_id(0)\n    assert stim.DemTarget(\"D5\") == stim.target_relative_detector_id(5)\n    assert stim.DemTarget(\"L0\") == stim.target_logical_observable_id(0)\n    assert stim.DemTarget(\"L5\") == stim.target_logical_observable_id(5)\n    assert stim.DemTarget(\"^\") == stim.target_separator()\n    assert stim.DemTarget(f\"D{2**62 - 1}\") == stim.target_relative_detector_id(2**62 - 1)\n    assert stim.DemTarget(f\"L{0xFFFFFFFF}\") == stim.target_logical_observable_id(0xFFFFFFFF)\n    with pytest.raises(ValueError, match=\"Failed to parse\"):\n        _ = stim.DemTarget(f\"D{2**62}\")\n    with pytest.raises(ValueError, match=\"Failed to parse\"):\n        _ = stim.DemTarget(f\"L{0x100000000}\")\n    with pytest.raises(ValueError, match=\"Failed to parse\"):\n        _ = stim.DemTarget(f\"L-1\")\n    with pytest.raises(ValueError, match=\"Failed to parse\"):\n        _ = stim.DemTarget(f\"X5\")\n    with pytest.raises(ValueError, match=\"Failed to parse\"):\n        _ = stim.DemTarget(f\"5\")\n"
  },
  {
    "path": "src/stim/diagram/ascii_diagram.cc",
    "content": "#include \"stim/diagram/ascii_diagram.h\"\n\n#include <cmath>\n\n#include \"stim/mem/span_ref.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\n/// Describes sizes and offsets within a diagram with variable-sized columns and rows.\nstruct AsciiLayout {\n    size_t num_x;\n    size_t num_y;\n    std::vector<size_t> x_spans;\n    std::vector<size_t> y_spans;\n    std::vector<size_t> x_offsets;\n    std::vector<size_t> y_offsets;\n};\n\nAsciiDiagramPos::AsciiDiagramPos(size_t x, size_t y, float align_x, float align_y)\n    : x(x), y(y), align_x(align_x), align_y(align_y) {\n}\n\nbool AsciiDiagramPos::operator==(const AsciiDiagramPos &other) const {\n    return x == other.x && y == other.y;\n}\n\nbool AsciiDiagramPos::operator<(const AsciiDiagramPos &other) const {\n    if (x != other.x) {\n        return x < other.x;\n    }\n    return y < other.y;\n}\n\nAsciiDiagramEntry::AsciiDiagramEntry(AsciiDiagramPos center, std::string label) : center(center), label(label) {\n}\n\nvoid AsciiDiagram::add_entry(AsciiDiagramEntry entry) {\n    cells.insert({entry.center, entry});\n}\n\nvoid AsciiDiagram::for_each_pos(const std::function<void(AsciiDiagramPos pos)> &callback) const {\n    for (const auto &item : cells) {\n        callback(item.first);\n    }\n    for (const auto &item : lines) {\n        callback(item.first);\n        callback(item.second);\n    }\n}\n\nAsciiLayout compute_sizing(const AsciiDiagram &diagram) {\n    AsciiLayout layout{0, 0, {}, {}, {}, {}};\n    diagram.for_each_pos([&](AsciiDiagramPos pos) {\n        layout.num_x = std::max(layout.num_x, pos.x + 1);\n        layout.num_y = std::max(layout.num_y, pos.y + 1);\n    });\n    layout.x_spans.resize(layout.num_x, 1);\n    layout.y_spans.resize(layout.num_y, 1);\n\n    for (const auto &item : diagram.cells) {\n        const auto &box = item.second;\n        auto &dx = layout.x_spans[box.center.x];\n        auto &dy = layout.y_spans[box.center.y];\n        dx = std::max(dx, box.label.size());\n        dy = std::max(dy, (size_t)1);\n    }\n\n    layout.x_offsets.push_back(0);\n    layout.y_offsets.push_back(0);\n    for (const auto &e : layout.x_spans) {\n        layout.x_offsets.push_back(layout.x_offsets.back() + e);\n    }\n    for (const auto &e : layout.y_spans) {\n        layout.y_offsets.push_back(layout.y_offsets.back() + e);\n    }\n\n    return layout;\n}\n\nAsciiDiagramPos AsciiDiagramPos::transposed() const {\n    return {y, x, align_y, align_x};\n}\nAsciiDiagramEntry AsciiDiagramEntry::transposed() const {\n    return {center.transposed(), label};\n}\n\nAsciiDiagram AsciiDiagram::transposed() const {\n    AsciiDiagram result;\n    for (const auto &e : cells) {\n        result.cells.insert({e.first.transposed(), e.second.transposed()});\n    }\n    result.lines.reserve(lines.size());\n    for (const auto &e : lines) {\n        result.lines.push_back({e.first.transposed(), e.second.transposed()});\n    }\n    return result;\n}\n\nvoid strip_padding_from_lines_and_write_to(SpanRef<std::string> out_lines, std::ostream &out) {\n    // Strip spacing at end of lines and end of diagram.\n    for (auto &line : out_lines) {\n        while (!line.empty() && line.back() == ' ') {\n            line.pop_back();\n        }\n    }\n\n    // Strip empty lines at start and end.\n    while (!out_lines.empty() && out_lines.back().empty()) {\n        out_lines.ptr_end--;\n    }\n    while (!out_lines.empty() && out_lines.front().empty()) {\n        out_lines.ptr_start++;\n    }\n\n    // Find indentation.\n    size_t indentation = SIZE_MAX;\n    for (const auto &line : out_lines) {\n        size_t k = 0;\n        while (k < line.length() && line[k] == ' ') {\n            k++;\n        }\n        indentation = std::min(indentation, k);\n    }\n\n    // Output while stripping empty lines at start of diagram.\n    for (size_t k = 0; k < out_lines.size(); k++) {\n        if (k) {\n            out.put('\\n');\n        }\n        out.write(out_lines[k].data() + indentation, out_lines[k].size() - indentation);\n    }\n}\n\nvoid AsciiDiagram::render(std::ostream &out) const {\n    AsciiLayout layout = compute_sizing(*this);\n\n    std::vector<std::string> out_lines;\n    out_lines.resize(layout.y_offsets.back());\n    for (auto &line : out_lines) {\n        line.resize(layout.x_offsets.back(), ' ');\n    }\n\n    auto p_align = [&](size_t c0, size_t cn, float align) {\n        if (align == 0.5f) {\n            cn--;\n        }\n        return c0 + (int)floor(align * cn);\n    };\n    auto x_align = [&](AsciiDiagramPos pos) {\n        return p_align(layout.x_offsets[pos.x], layout.x_spans[pos.x], pos.align_x);\n    };\n    auto y_align = [&](AsciiDiagramPos pos) {\n        return p_align(layout.y_offsets[pos.y], layout.y_spans[pos.y], pos.align_y);\n    };\n\n    for (const auto &line : lines) {\n        auto &p1 = line.first;\n        auto &p2 = line.second;\n\n        auto x1 = x_align(p1);\n        auto x2 = x_align(p2);\n        auto y1 = y_align(p1);\n        auto y2 = y_align(p2);\n        if (x1 > x2) {\n            std::swap(x1, x2);\n        }\n        if (y1 > y2) {\n            std::swap(y1, y2);\n        }\n        bool bx = x1 != x2;\n        while (x1 < x2) {\n            out_lines[y1][x1] = '-';\n            x1++;\n        }\n\n        char next_char = bx ? '.' : '|';\n        while (y1 < y2) {\n            out_lines[y1][x1] = next_char;\n            next_char = '|';\n            y1++;\n        }\n    }\n\n    for (const auto &item : cells) {\n        const auto &box = item.second;\n        auto x = layout.x_offsets[box.center.x];\n        auto y = layout.y_offsets[box.center.y];\n        x += (int)floor(box.center.align_x * (layout.x_spans[box.center.x] - box.label.size()));\n        y += (int)floor(box.center.align_y * (layout.y_spans[box.center.y] - 1));\n        for (size_t k = 0; k < box.label.size(); k++) {\n            out_lines[y][x + k] = box.label[k];\n        }\n    }\n\n    strip_padding_from_lines_and_write_to(out_lines, out);\n}\n\nstd::string AsciiDiagram::str() const {\n    std::stringstream ss;\n    render(ss);\n    return ss.str();\n}\n\nstd::ostream &stim_draw_internal::operator<<(std::ostream &out, const AsciiDiagram &drawer) {\n    drawer.render(out);\n    return out;\n}\n"
  },
  {
    "path": "src/stim/diagram/ascii_diagram.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_TIMELINE_ASCII_DIAGRAM_ASCII_DIAGRAM_H\n#define _STIM_DIAGRAM_TIMELINE_ASCII_DIAGRAM_ASCII_DIAGRAM_H\n\n#include <cstdint>\n#include <functional>\n#include <iostream>\n#include <map>\n#include <vector>\n\nnamespace stim_draw_internal {\n\n/// Identifies a location within a cell in a diagram with variable-sized columns and rows.\nstruct AsciiDiagramPos {\n    size_t x;       /// The column that the cell is in.\n    size_t y;       /// The row that the cell is in.\n    float align_x;  /// Identifies a pixel column within the cell, proportionally from left to right.\n    float align_y;  /// Identifies a pixel row within the cell, proportionally from top to bottom.\n\n    AsciiDiagramPos(size_t x, size_t y, float align_x, float align_y);\n    bool operator==(const AsciiDiagramPos &other) const;\n    bool operator<(const AsciiDiagramPos &other) const;\n    AsciiDiagramPos transposed() const;\n};\n\n/// Describes what to draw within a cell of a diagram with variable-sized columns and rows.\nstruct AsciiDiagramEntry {\n    /// The location of the cell, and the alignment to use for the text.\n    AsciiDiagramPos center;\n    /// The text to write.\n    std::string label;\n\n    AsciiDiagramEntry(AsciiDiagramPos center, std::string label);\n    AsciiDiagramEntry transposed() const;\n};\n\nstruct AsciiDiagram {\n    /// What to draw in various cells.\n    std::map<AsciiDiagramPos, AsciiDiagramEntry> cells;\n    /// Lines to draw in between cells.\n    std::vector<std::pair<AsciiDiagramPos, AsciiDiagramPos>> lines;\n\n    void add_entry(AsciiDiagramEntry cell);\n    void for_each_pos(const std::function<void(AsciiDiagramPos pos)> &callback) const;\n    AsciiDiagram transposed() const;\n    void render(std::ostream &out) const;\n    std::string str() const;\n};\nstd::ostream &operator<<(std::ostream &out, const AsciiDiagram &drawer);\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/ascii_diagram.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/diagram/ascii_diagram.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim_draw_internal;\n\nTEST(ascii_diagram, basic) {\n    AsciiDiagram diagram;\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            AsciiDiagramPos{0, 0, 0.5, 0.5},\n            {\"ABC\"},\n        });\n    ASSERT_EQ(\"\\n\" + diagram.str() + \"\\n\", R\"DIAGRAM(\nABC\n)DIAGRAM\");\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            AsciiDiagramPos{2, 0, 0.5, 0.5},\n            {\"DE\"},\n        });\n    ASSERT_EQ(\"\\n\" + diagram.str() + \"\\n\", R\"DIAGRAM(\nABC DE\n)DIAGRAM\");\n    diagram.lines.push_back({\n        AsciiDiagramPos{0, 1, 1, 0.5},\n        AsciiDiagramPos{2, 1, 0, 0.5},\n    });\n    diagram.lines.push_back({\n        AsciiDiagramPos{0, 2, 0, 0.5},\n        AsciiDiagramPos{2, 2, 1, 0.5},\n    });\n    diagram.lines.push_back({\n        AsciiDiagramPos{1, 3, 0, 0.5},\n        AsciiDiagramPos{1, 3, 1, 0.5},\n    });\n    diagram.lines.push_back({\n        AsciiDiagramPos{1, 4, 1, 0.5},\n        AsciiDiagramPos{1, 4, 0, 0.5},\n    });\n    ASSERT_EQ(\"\\n\" + diagram.str() + \"\\n\", R\"DIAGRAM(\nABC DE\n   -\n------\n   -\n   -\n)DIAGRAM\");\n}\n"
  },
  {
    "path": "src/stim/diagram/base64.cc",
    "content": "#include \"stim/diagram/base64.h\"\n\nusing namespace stim_draw_internal;\n\nchar u6_to_base64_char(uint8_t v) {\n    if (v < 26) {\n        return 'A' + v;\n    } else if (v < 52) {\n        return 'a' + v - 26;\n    } else if (v < 62) {\n        return '0' + v - 52;\n    } else if (v == 62) {\n        return '+';\n    } else {\n        return '/';\n    }\n}\n\nvoid stim_draw_internal::write_data_as_base64_to(std::string_view data, std::ostream &out) {\n    uint32_t buf = 0;\n    size_t bits_in_buf = 0;\n    for (char c : data) {\n        buf <<= 8;\n        buf |= (uint8_t)c;\n        bits_in_buf += 8;\n        if (bits_in_buf == 24) {\n            out << u6_to_base64_char((buf >> 18) & 0x3F);\n            out << u6_to_base64_char((buf >> 12) & 0x3F);\n            out << u6_to_base64_char((buf >> 6) & 0x3F);\n            out << u6_to_base64_char((buf >> 0) & 0x3F);\n            bits_in_buf = 0;\n            buf = 0;\n        }\n    }\n    if (bits_in_buf) {\n        buf <<= (24 - bits_in_buf);\n        out << u6_to_base64_char((buf >> 18) & 0x3F);\n        out << u6_to_base64_char((buf >> 12) & 0x3F);\n        out << (bits_in_buf == 8 ? '=' : u6_to_base64_char((buf >> 6) & 0x3F));\n        out << '=';\n    }\n}\n"
  },
  {
    "path": "src/stim/diagram/base64.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_BASE64_H\n#define _STIM_DIAGRAM_BASE64_H\n\n#include <cstdint>\n#include <iostream>\n\nnamespace stim_draw_internal {\n\nvoid write_data_as_base64_to(std::string_view data, std::ostream &out);\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/base64.test.cc",
    "content": "#include \"stim/diagram/base64.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim_draw_internal;\n\nTEST(base64, write_base64) {\n    auto f = [](std::string_view c) {\n        std::stringstream ss;\n        write_data_as_base64_to(c, ss);\n        return ss.str();\n    };\n\n    EXPECT_EQ(f(\"light work.\"), \"bGlnaHQgd29yay4=\");\n    EXPECT_EQ(f(\"light work\"), \"bGlnaHQgd29yaw==\");\n    EXPECT_EQ(f(\"light wor\"), \"bGlnaHQgd29y\");\n    EXPECT_EQ(f(\"light wo\"), \"bGlnaHQgd28=\");\n    EXPECT_EQ(f(\"light w\"), \"bGlnaHQgdw==\");\n    EXPECT_EQ(f(\"\"), \"\");\n    EXPECT_EQ(f(\"f\"), \"Zg==\");\n    EXPECT_EQ(f(\"fo\"), \"Zm8=\");\n    EXPECT_EQ(f(\"foo\"), \"Zm9v\");\n    EXPECT_EQ(f(\"foob\"), \"Zm9vYg==\");\n    EXPECT_EQ(f(\"fooba\"), \"Zm9vYmE=\");\n    EXPECT_EQ(f(\"foobar\"), \"Zm9vYmFy\");\n}\n"
  },
  {
    "path": "src/stim/diagram/basic_3d_diagram.cc",
    "content": "#include \"stim/diagram/basic_3d_diagram.h\"\n\n#include \"gate_data_3d.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nGltfScene Basic3dDiagram::to_gltf_scene() const {\n    GltfScene scene{{\"everything\"}, {}};\n\n    auto black_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"black\"},\n        {0, 0, 0, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n\n    auto red_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"red\"},\n        {1, 0, 0, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n\n    auto blue_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"blue\"},\n        {0, 0, 1, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n\n    auto purple_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"purple\"},\n        {1, 0, 1, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n\n    auto buf_scattered_lines = std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n        {\"buf_scattered_lines\"},\n        line_data,\n    });\n\n    auto buf_red_scattered_lines = std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n        {\"buf_red_scattered_lines\"},\n        red_line_data,\n    });\n\n    auto buf_blue_scattered_lines = std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n        {\"buf_blue_scattered_lines\"},\n        blue_line_data,\n    });\n\n    auto buf_purple_scattered_lines = std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n        {\"buf_purple_scattered_lines\"},\n        purple_line_data,\n    });\n\n    auto gate_data = make_gate_primitives();\n    for (const auto &g : elements) {\n        auto p = gate_data.find(g.gate_piece);\n        if (p == gate_data.end()) {\n            throw std::invalid_argument(\"Basic3dDiagram unknown gate piece: \" + std::string(g.gate_piece));\n        }\n        scene.nodes.push_back(\n            std::shared_ptr<GltfNode>(new GltfNode{\n                {\"\"},\n                p->second,\n                g.center,\n            }));\n    }\n\n    if (!buf_scattered_lines->vertices.empty()) {\n        scene.nodes.push_back(\n            std::shared_ptr<GltfNode>(new GltfNode{\n                {\"node_scattered_lines\"},\n                std::shared_ptr<GltfMesh>(new GltfMesh{\n                    {\"mesh_scattered_lines\"},\n                    {\n                        std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                            {\"primitive_scattered_lines\"},\n                            GL_LINES,\n                            buf_scattered_lines,\n                            nullptr,\n                            black_material,\n                        }),\n                    },\n                }),\n                {0, 0, 0},\n            }));\n    }\n\n    if (!buf_red_scattered_lines->vertices.empty()) {\n        scene.nodes.push_back(\n            std::shared_ptr<GltfNode>(new GltfNode{\n                {\"node_red_scattered_lines\"},\n                std::shared_ptr<GltfMesh>(new GltfMesh{\n                    {\"mesh_scattered_lines\"},\n                    {\n                        std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                            {\"primitive_red_scattered_lines\"},\n                            GL_LINES,\n                            buf_red_scattered_lines,\n                            nullptr,\n                            red_material,\n                        }),\n                    },\n                }),\n                {0, 0, 0},\n            }));\n    }\n\n    if (!buf_blue_scattered_lines->vertices.empty()) {\n        scene.nodes.push_back(\n            std::shared_ptr<GltfNode>(new GltfNode{\n                {\"node_blue_scattered_lines\"},\n                std::shared_ptr<GltfMesh>(new GltfMesh{\n                    {\"mesh_scattered_lines\"},\n                    {\n                        std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                            {\"primitive_blue_scattered_lines\"},\n                            GL_LINES,\n                            buf_blue_scattered_lines,\n                            nullptr,\n                            blue_material,\n                        }),\n                    },\n                }),\n                {0, 0, 0},\n            }));\n    }\n\n    if (!buf_purple_scattered_lines->vertices.empty()) {\n        scene.nodes.push_back(\n            std::shared_ptr<GltfNode>(new GltfNode{\n                {\"node_purple_scattered_lines\"},\n                std::shared_ptr<GltfMesh>(new GltfMesh{\n                    {\"mesh_scattered_lines\"},\n                    {\n                        std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                            {\"primitive_purple_scattered_lines\"},\n                            GL_LINES,\n                            buf_purple_scattered_lines,\n                            nullptr,\n                            purple_material,\n                        }),\n                    },\n                }),\n                {0, 0, 0},\n            }));\n    }\n\n    if (scene.nodes.empty()) {\n        auto buf_message_lines = std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n            {\"buf_blue_scattered_lines\"},\n            std::vector<Coord<3>>{\n                // E\n                {0, 0, 0},\n                {0, 2, 0},\n                {0, 2, 0},\n                {1, 2, 0},\n                {0, 1, 0},\n                {1, 1, 0},\n                {0, 0, 0},\n                {1, 0, 0},\n                // m\n                {2, 1, 0},\n                {3, 1, 0},\n                {2, 0, 0},\n                {2, 1, 0},\n                {2.5, 0, 0},\n                {2.5, 1, 0},\n                {3, 0, 0},\n                {3, 1, 0},\n                // p\n                {4, 1, 0},\n                {4, -1, 0},\n                {4, 1, 0},\n                {5, 1, 0},\n                {5, 1, 0},\n                {5, 0, 0},\n                {4, 0, 0},\n                {5, 0, 0},\n                // t\n                {6, 0, 0},\n                {6, 2, 0},\n                {5.5, 1.5, 0},\n                {6.5, 1.5, 0},\n                // y\n                {7, -1, 0},\n                {8, 1, 0},\n                {7, 1, 0},\n                {7.5, 0, 0},\n            }});\n        scene.nodes.push_back(\n            std::shared_ptr<GltfNode>(new GltfNode{\n                {\"empty_message\"},\n                std::shared_ptr<GltfMesh>(new GltfMesh{\n                    {\"mesh_scattered_lines\"},\n                    {\n                        std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                            {\"primitive_blue_scattered_lines\"},\n                            GL_LINES,\n                            buf_message_lines,\n                            nullptr,\n                            red_material,\n                        }),\n                    },\n                }),\n                {0, 0, 0},\n            }));\n    }\n\n    return scene;\n}\n"
  },
  {
    "path": "src/stim/diagram/basic_3d_diagram.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DRAW_3D_DIAGRAM_3D_H\n#define _STIM_DRAW_3D_DIAGRAM_3D_H\n\n#include <iostream>\n\n#include \"stim/diagram/gltf.h\"\n\nnamespace stim_draw_internal {\n\nstruct Basic3DElement {\n    std::string gate_piece;\n    Coord<3> center;\n};\n\nstruct Basic3dDiagram {\n    std::vector<Basic3DElement> elements;\n    std::vector<Coord<3>> line_data;\n    std::vector<Coord<3>> red_line_data;\n    std::vector<Coord<3>> blue_line_data;\n    std::vector<Coord<3>> purple_line_data;\n\n    GltfScene to_gltf_scene() const;\n};\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/circuit_timeline_helper.cc",
    "content": "#include \"stim/diagram/circuit_timeline_helper.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nvoid CircuitTimelineHelper::skip_loop_iterations(const CircuitTimelineLoopData &loop_data, uint64_t skipped_reps) {\n    if (loop_data.num_repetitions > 0) {\n        vec_pad_add_mul(cur_coord_shift, loop_data.shift_per_iteration, skipped_reps);\n        measure_offset += loop_data.measurements_per_iteration * skipped_reps;\n        detector_offset += loop_data.detectors_per_iteration * skipped_reps;\n        num_ticks_seen += loop_data.ticks_per_iteration * skipped_reps;\n    }\n}\n\nvoid CircuitTimelineHelper::do_repeat_block(const Circuit &circuit, const CircuitInstruction &op) {\n    const auto &body = op.repeat_block_body(circuit);\n    CircuitTimelineLoopData loop_data{\n        op.repeat_block_rep_count(),\n        body.count_measurements(),\n        body.count_detectors(),\n        body.count_ticks(),\n        body.final_coord_shift(),\n    };\n    cur_loop_nesting.push_back(loop_data);\n\n    if (unroll_loops) {\n        for (size_t k = 0; k < loop_data.num_repetitions; k++) {\n            do_circuit(body);\n        }\n    } else {\n        start_repeat_callback(loop_data);\n        do_circuit(body);\n        end_repeat_callback(loop_data);\n        skip_loop_iterations(loop_data, loop_data.num_repetitions - 1);\n    }\n\n    cur_loop_nesting.pop_back();\n}\n\nvoid CircuitTimelineHelper::do_atomic_operation(\n    GateType gate_type, SpanRef<const double> args, SpanRef<const GateTarget> targets) {\n    resolved_op_callback({gate_type, args, targets});\n}\n\nvoid CircuitTimelineHelper::do_operation_with_target_combiners(const CircuitInstruction &op) {\n    bool paired = GATE_DATA[op.gate_type].flags & GATE_TARGETS_PAIRS;\n    size_t start = 0;\n    while (start < op.targets.size()) {\n        size_t end = start + 1;\n        while (end < op.targets.size() && op.targets[end].is_combiner()) {\n            end += 2;\n        }\n        if (paired) {\n            end++;\n            while (end < op.targets.size() && op.targets[end].is_combiner()) {\n                end += 2;\n            }\n        }\n\n        if (GATE_DATA[op.gate_type].flags & GATE_PRODUCES_RESULTS) {\n            do_record_measure_result(op.targets[start].qubit_value());\n        }\n        do_atomic_operation(op.gate_type, op.args, {&op.targets[start], &op.targets[end]});\n        start = end;\n    }\n}\n\nvoid CircuitTimelineHelper::do_multi_qubit_atomic_operation(const CircuitInstruction &op) {\n    do_atomic_operation(op.gate_type, op.args, op.targets);\n}\n\nvoid CircuitTimelineHelper::do_two_qubit_gate(const CircuitInstruction &op) {\n    for (size_t k = 0; k < op.targets.size(); k += 2) {\n        const GateTarget *p = &op.targets[k];\n        if (GATE_DATA[op.gate_type].flags & GATE_PRODUCES_RESULTS) {\n            do_record_measure_result(p[0].qubit_value());\n        }\n        do_atomic_operation(op.gate_type, op.args, {p, p + 2});\n    }\n}\n\nvoid CircuitTimelineHelper::do_single_qubit_gate(const CircuitInstruction &op) {\n    for (const auto &t : op.targets) {\n        if (GATE_DATA[op.gate_type].flags & GATE_PRODUCES_RESULTS) {\n            do_record_measure_result(t.qubit_value());\n        }\n        do_atomic_operation(op.gate_type, op.args, {&t});\n    }\n}\n\nGateTarget CircuitTimelineHelper::rec_to_qubit(const GateTarget &target) {\n    return GateTarget::qubit(measure_index_to_qubit.get(measure_offset + (decltype(measure_offset))target.value()));\n}\n\nGateTarget CircuitTimelineHelper::pick_pseudo_target_representing_measurements(const CircuitInstruction &op) {\n    for (const auto &t : op.targets) {\n        if (t.is_qubit_target() || t.is_pauli_target()) {\n            return t;\n        }\n    }\n    // First check if coordinates prefix-match a qubit's coordinates.\n    if (!op.args.empty()) {\n        auto coords = shifted_coordinates_in_workspace(op.args);\n\n        for (size_t q = 0; q < latest_qubit_coords.size(); q++) {\n            SpanRef<const double> v = latest_qubit_coords[q];\n            if (!v.empty() && v.size() <= coords.size()) {\n                SpanRef<const double> prefix = {coords.ptr_start, coords.ptr_start + v.size()};\n                if (prefix == v) {\n                    return GateTarget::qubit((uint32_t)q);\n                }\n            }\n        }\n    }\n\n    // Otherwise fall back to picking the qubit of one of the targeted measurements.\n    if (op.targets.empty()) {\n        return GateTarget::qubit(0);\n    }\n    GateTarget pseudo_target = rec_to_qubit(op.targets[0]);\n    for (const auto &t : op.targets) {\n        GateTarget q = rec_to_qubit(t);\n        if (q.value() < pseudo_target.value()) {\n            pseudo_target = q;\n        }\n    }\n\n    return pseudo_target;\n}\n\nSpanRef<const double> CircuitTimelineHelper::shifted_coordinates_in_workspace(SpanRef<const double> coords) {\n    while (coord_workspace.size() < coords.size()) {\n        coord_workspace.push_back(0);\n    }\n    for (size_t k = 0; k < coords.size(); k++) {\n        coord_workspace[k] = coords[k];\n        if (k < cur_coord_shift.size()) {\n            coord_workspace[k] += cur_coord_shift[k];\n        }\n    }\n    return {coord_workspace.data(), coord_workspace.data() + coords.size()};\n}\n\nvoid CircuitTimelineHelper::do_detector(const CircuitInstruction &op) {\n    GateTarget pseudo_target = pick_pseudo_target_representing_measurements(op);\n    targets_workspace.clear();\n    targets_workspace.push_back(pseudo_target);\n    targets_workspace.insert(targets_workspace.end(), op.targets.begin(), op.targets.end());\n    do_atomic_operation(op.gate_type, shifted_coordinates_in_workspace(op.args), targets_workspace);\n    detector_offset++;\n}\n\nvoid CircuitTimelineHelper::do_observable_include(const CircuitInstruction &op) {\n    GateTarget pseudo_target = pick_pseudo_target_representing_measurements(op);\n    targets_workspace.clear();\n    targets_workspace.push_back(pseudo_target);\n    targets_workspace.insert(targets_workspace.end(), op.targets.begin(), op.targets.end());\n    do_atomic_operation(op.gate_type, op.args, targets_workspace);\n}\n\nvoid CircuitTimelineHelper::do_qubit_coords(const CircuitInstruction &op) {\n    for (const auto &target : op.targets) {\n        auto shifted = shifted_coordinates_in_workspace(op.args);\n\n        while (target.qubit_value() >= latest_qubit_coords.size()) {\n            latest_qubit_coords.push_back({});\n        }\n        auto &store = latest_qubit_coords[target.qubit_value()];\n        store.clear();\n        store.insert(store.begin(), shifted.begin(), shifted.end());\n\n        do_atomic_operation(op.gate_type, shifted, {&target});\n    }\n}\n\nvoid CircuitTimelineHelper::do_shift_coords(const CircuitInstruction &op) {\n    vec_pad_add_mul(cur_coord_shift, op.args);\n}\n\nvoid CircuitTimelineHelper::do_record_measure_result(uint32_t target_qubit) {\n    u64_workspace.clear();\n    for (const auto &e : cur_loop_nesting) {\n        u64_workspace.push_back(e.measurements_per_iteration);\n    }\n    for (const auto &e : cur_loop_nesting) {\n        u64_workspace.push_back(e.num_repetitions);\n    }\n    const uint64_t *p = u64_workspace.data();\n    auto n = cur_loop_nesting.size();\n    measure_index_to_qubit.set(measure_offset, {p, p + n}, {p + n, p + 2 * n}, target_qubit);\n    measure_offset++;\n}\n\nvoid CircuitTimelineHelper::do_next_operation(const Circuit &circuit, const CircuitInstruction &op) {\n    if (op.gate_type == GateType::REPEAT) {\n        do_repeat_block(circuit, op);\n    } else if (op.gate_type == GateType::DETECTOR) {\n        do_detector(op);\n    } else if (op.gate_type == GateType::OBSERVABLE_INCLUDE) {\n        do_observable_include(op);\n    } else if (op.gate_type == GateType::SHIFT_COORDS) {\n        do_shift_coords(op);\n    } else if (op.gate_type == GateType::E || op.gate_type == GateType::ELSE_CORRELATED_ERROR) {\n        do_multi_qubit_atomic_operation(op);\n    } else if (op.gate_type == GateType::QUBIT_COORDS) {\n        do_qubit_coords(op);\n    } else if (op.gate_type == GateType::TICK) {\n        do_atomic_operation(op.gate_type, {}, {});\n        num_ticks_seen += 1;\n    } else if (GATE_DATA[op.gate_type].flags & GATE_TARGETS_COMBINERS) {\n        do_operation_with_target_combiners(op);\n    } else if (GATE_DATA[op.gate_type].flags & GATE_TARGETS_PAIRS) {\n        do_two_qubit_gate(op);\n    } else {\n        do_single_qubit_gate(op);\n    }\n}\n\nvoid CircuitTimelineHelper::do_circuit(const Circuit &circuit) {\n    for (const auto &op : circuit.operations) {\n        do_next_operation(circuit, op);\n    }\n}\n"
  },
  {
    "path": "src/stim/diagram/circuit_timeline_helper.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_TIMELINE_ASCII_DIAGRAM_CIRCUIT_WITH_RESOLVED_TIMELINE_INFO_H\n#define _STIM_DIAGRAM_TIMELINE_ASCII_DIAGRAM_CIRCUIT_WITH_RESOLVED_TIMELINE_INFO_H\n\n#include <functional>\n#include <iostream>\n\n#include \"lattice_map.h\"\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim_draw_internal {\n\nstruct CircuitTimelineLoopData {\n    uint64_t num_repetitions;\n    uint64_t measurements_per_iteration;\n    uint64_t detectors_per_iteration;\n    uint64_t ticks_per_iteration;\n    std::vector<double> shift_per_iteration;\n};\n\nstruct CircuitTimelineHelper;\n\n/// Changes w.r.t. normal circuit operations:\n///     There is no broadcasting. Single-qubit gates have a single target, etc.\n///     DETECTOR and OBSERVABLE_INCLUDE instructions start with a qubit pseudo-target as a location hint.\n///     All coordinates have the effects SHIFT_COORDS folded in.\n///     QUBIT_COORDS is treated as a single-qubit gate. Will only have one target.\nstruct ResolvedTimelineOperation {\n    stim::GateType gate_type;\n    stim::SpanRef<const double> args;\n    stim::SpanRef<const stim::GateTarget> targets;\n};\n\nstruct CircuitTimelineHelper {\n    std::function<void(ResolvedTimelineOperation)> resolved_op_callback;\n    std::function<void(CircuitTimelineLoopData)> start_repeat_callback;\n    std::function<void(CircuitTimelineLoopData)> end_repeat_callback;\n    std::vector<double> cur_coord_shift;\n    uint64_t measure_offset = 0;\n    uint64_t detector_offset = 0;\n    uint64_t num_ticks_seen = 0;\n    bool unroll_loops = false;\n    std::vector<double> coord_workspace;\n    std::vector<uint64_t> u64_workspace;\n    std::vector<stim::GateTarget> targets_workspace;\n    std::vector<std::vector<double>> latest_qubit_coords;\n    std::vector<CircuitTimelineLoopData> cur_loop_nesting;\n    LatticeMap measure_index_to_qubit;\n\n    void do_atomic_operation(\n        const stim::GateType gate_type,\n        stim::SpanRef<const double> args,\n        stim::SpanRef<const stim::GateTarget> targets);\n\n    stim::GateTarget rec_to_qubit(const stim::GateTarget &target);\n    stim::GateTarget pick_pseudo_target_representing_measurements(const stim::CircuitInstruction &op);\n    void skip_loop_iterations(const CircuitTimelineLoopData &loop_data, uint64_t skipped_reps);\n    void do_record_measure_result(uint32_t target_qubit);\n    void do_repeat_block(const stim::Circuit &circuit, const stim::CircuitInstruction &op);\n    void do_next_operation(const stim::Circuit &circuit, const stim::CircuitInstruction &op);\n    void do_circuit(const stim::Circuit &circuit);\n    void do_operation_with_target_combiners(const stim::CircuitInstruction &op);\n    void do_multi_qubit_atomic_operation(const stim::CircuitInstruction &op);\n    void do_two_qubit_gate(const stim::CircuitInstruction &op);\n    void do_single_qubit_gate(const stim::CircuitInstruction &op);\n    void do_detector(const stim::CircuitInstruction &op);\n    void do_observable_include(const stim::CircuitInstruction &op);\n    void do_shift_coords(const stim::CircuitInstruction &op);\n    void do_qubit_coords(const stim::CircuitInstruction &op);\n    stim::SpanRef<const double> shifted_coordinates_in_workspace(stim::SpanRef<const double> coords);\n};\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/coord.h",
    "content": "#ifndef _STIM_DIAGRAM_COORD_H\n#define _STIM_DIAGRAM_COORD_H\n\n#include <array>\n#include <cmath>\n#include <iostream>\n\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim_draw_internal {\n\n/// Coordinate data. Used for individual vertex positions and also UV texture coordinates.\ntemplate <size_t DIM>\nstruct Coord {\n    std::array<float, DIM> xyz;\n\n    Coord<DIM> &operator+=(const Coord<DIM> &other) {\n        for (size_t k = 0; k < DIM; k++) {\n            xyz[k] += other.xyz[k];\n        }\n        return *this;\n    }\n    Coord<DIM> &operator-=(const Coord<DIM> &other) {\n        for (size_t k = 0; k < DIM; k++) {\n            xyz[k] -= other.xyz[k];\n        }\n        return *this;\n    }\n    Coord<DIM> &operator/=(float f) {\n        for (size_t k = 0; k < DIM; k++) {\n            xyz[k] /= f;\n        }\n        return *this;\n    }\n    Coord<DIM> &operator*=(float f) {\n        for (size_t k = 0; k < DIM; k++) {\n            xyz[k] *= f;\n        }\n        return *this;\n    }\n    Coord<DIM> operator+(const Coord<DIM> &other) const {\n        Coord<DIM> result = *this;\n        result += other;\n        return result;\n    }\n    Coord<DIM> operator-(const Coord<DIM> &other) const {\n        Coord<DIM> result = *this;\n        result -= other;\n        return result;\n    }\n    Coord<DIM> operator/(float other) const {\n        Coord<DIM> result = *this;\n        result /= other;\n        return result;\n    }\n    Coord<DIM> operator*(float other) const {\n        Coord<DIM> result = *this;\n        result *= other;\n        return result;\n    }\n    float dot(const Coord<DIM> &other) const {\n        float t = 0;\n        for (size_t k = 0; k < DIM; k++) {\n            t += xyz[k] * other.xyz[k];\n        }\n        return t;\n    }\n    float norm2() const {\n        return dot(*this);\n    }\n    float norm() const {\n        return sqrtf(norm2());\n    }\n\n    bool operator<(Coord<DIM> other) const {\n        for (size_t k = 0; k < DIM; k++) {\n            if (xyz[k] != other.xyz[k]) {\n                return xyz[k] < other.xyz[k];\n            }\n        }\n        return false;\n    }\n\n    bool operator==(Coord<DIM> other) const {\n        return xyz == other.xyz;\n    }\n\n    static std::pair<Coord<DIM>, Coord<DIM>> min_max(stim::SpanRef<const Coord<DIM>> coords) {\n        if (coords.empty()) {\n            return {{}, {}};\n        }\n        Coord<DIM> v_min;\n        Coord<DIM> v_max;\n        for (size_t k = 0; k < DIM; k++) {\n            v_min.xyz[k] = INFINITY;\n            v_max.xyz[k] = -INFINITY;\n        }\n        for (const auto &v : coords) {\n            for (size_t k = 0; k < DIM; k++) {\n                v_min.xyz[k] = std::min(v_min.xyz[k], v.xyz[k]);\n                v_max.xyz[k] = std::max(v_max.xyz[k], v.xyz[k]);\n            }\n        }\n        return {v_min, v_max};\n    }\n};\n\ntemplate <size_t DIM>\nstd::ostream &operator<<(std::ostream &out, const Coord<DIM> &coord) {\n    for (size_t k = 0; k < DIM; k++) {\n        if (k) {\n            out << ',';\n        }\n        out << coord.xyz[k];\n    }\n    return out;\n}\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/coord.test.cc",
    "content": "#include \"stim/diagram/coord.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/diagram/ascii_diagram.h\"\n\nusing namespace stim_draw_internal;\n\nTEST(coord, arithmetic) {\n    ASSERT_EQ((Coord<2>{2, 3} + Coord<2>{5, 7}), (Coord<2>{7, 10}));\n    ASSERT_EQ((Coord<2>{2, 3} - Coord<2>{5, 7}), (Coord<2>{-3, -4}));\n    ASSERT_EQ((Coord<2>{2, 3} * 5), (Coord<2>{10, 15}));\n    ASSERT_EQ((Coord<2>{2, 3} / 8), (Coord<2>{0.25, 0.375}));\n    ASSERT_EQ((Coord<2>{2, 3}.dot(Coord<2>{5, 7})), 2 * 5 + 3 * 7);\n    ASSERT_EQ((Coord<2>{2, 3}.norm2()), 13);\n    ASSERT_EQ((Coord<2>{3, 4}.norm()), 5);\n    ASSERT_TRUE((Coord<2>{3, 4} == Coord<2>{3, 4}));\n    ASSERT_FALSE((Coord<2>{3, 4} == Coord<2>{2, 4}));\n    ASSERT_FALSE((Coord<2>{3, 4} == Coord<2>{3, 2}));\n\n    ASSERT_FALSE((Coord<2>{3, 4} < Coord<2>{3, 4}));\n    ASSERT_FALSE((Coord<2>{3, 4} < Coord<2>{2, 4}));\n    ASSERT_TRUE((Coord<2>{3, 4} < Coord<2>{4, 4}));\n\n    ASSERT_TRUE((Coord<2>{3, 4} < Coord<2>{3, 6}));\n    ASSERT_FALSE((Coord<2>{3, 4} < Coord<2>{3, 2}));\n\n    ASSERT_TRUE((Coord<2>{3, 4} < Coord<2>{10, 0}));\n    ASSERT_FALSE((Coord<2>{3, 4} < Coord<2>{0, 10}));\n}\n\nTEST(coord, min_max) {\n    std::vector<Coord<2>> a{\n        {1, 10},\n        {10, 30},\n        {50, 5},\n    };\n    ASSERT_EQ((Coord<2>::min_max(a)), (std::pair<Coord<2>, Coord<2>>{{1, 5}, {50, 30}}));\n}\n"
  },
  {
    "path": "src/stim/diagram/crumble.cc",
    "content": "#include \"stim/diagram/crumble.h\"\n\n#include \"stim/diagram/crumble_data.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nvoid stim_draw_internal::write_crumble_html_with_preloaded_circuit(const Circuit &circuit, std::ostream &out) {\n    auto html = make_crumble_html();\n    const char *indicator = \"[[[DEFAULT_CIRCUIT_CONTENT_LITERAL]]]\";\n    size_t start = html.find(indicator);\n    out << html.substr(0, start);\n    out << circuit;\n    out << html.substr(start + strlen(indicator));\n}\n"
  },
  {
    "path": "src/stim/diagram/crumble.h",
    "content": "#ifndef _STIM_DIAGRAM_CRUMBLE_H\n#define _STIM_DIAGRAM_CRUMBLE_H\n\n#include <iostream>\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim_draw_internal {\n\nvoid write_crumble_html_with_preloaded_circuit(const stim::Circuit &circuit, std::ostream &out);\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/crumble_data.cc",
    "content": "#include \"stim/diagram/crumble_data.h\"\n\nstd::string stim_draw_internal::make_crumble_html() {\n    std::string result;\n    result.append(R\"CRUMBLE_PART(<!DOCTYPE html>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(<html lang=\"en\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(<head>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    <meta charset=\"UTF-8\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    <title>Crumble</title>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    <link rel=\"shortcut icon\" href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABgWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kTlIA0EUhj+j4kHEwhQiFluolQFREUuNgggRQlTwKtzdnJBdw27ExlKwDVh4NF6FjbW2FraCIHiAWFpZKdpIWN8kgQQxDgzz8c/8j/f+Ad9RxrTchgGw7JwTnQppC4tLWtMrrfiAAC266WbHI5EwNdfXPXXqvAuqWrXf/bnaYnHXhDpNeMzMOjnhVeGRjVxW8Z7qwkzpMeFz4X5HGhR+VLpR4jfFySKrpgk4c9EJ4YCwlqxio4rNlGMJDwv3xCxb6vsWShxTvKnYyqyb5T7VhP64PT+rdNndTDHNDBE0DNZJkyFHUE5bFJeo3Idq+LuK/oi4DHGlMcUxyRoWetGP+oPf2bqJocFSJX8IGl8876MXmnagkPe872PPK5xA/TNc2RX/2hGMfoqer2g9h9C+BRfXFc3Yhctt6HzK6o5elOpl+xIJeD+Tb1qEjltoXS7lVr7n9AHmJKvwDewfQF9Saq/UmLu5Ord/35Tz+wHVp3JoxsjWZAAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+YKAhYQLxXIct8AAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAx0lEQVRYw+2XwQ7EIAhEB+N/E76cnkgIa6OuWTFxvTWxdRgKDwmAYu+i+KDKPP62CJjHNYsQ7Psk8iGk7AxdmeGC1e0CvBBbKQK8ljQB5kK2AxcLsJLMdoBKZvQAULMOtk5IR7Dg294+yw4RymUBs3qQ5bHAO34vC8yFPwvSBFhJ3skC35Bq1sHHsKDGKfUX94J46HllGDjd5XnI5WjOXwXQSg5X95eXaaU3zXSjG3XJ79LW1ak1RsX9/qdsldqsPTppo66k6QGRuElWZ7d4CQAAAABJRU)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(5ErkJggg==\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(</head>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(<style>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    table tr {\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        border: 1px solid black;\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    }\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    table td {\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        border: 1px solid black;\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        padding-left: 5px;\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        padding-right: 5px;\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    }\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    table th {\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        border: 1px solid black;\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        padding-left: 5px;\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        padding-right: 5px;\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    }\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(</style>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(<body style=\"margin: 0\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                Crumble is a prototype stabilizer circuit editor.<br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <a href=\"https://github.com/quantumlib/Stim/blob/main/glue/crumble/README.md\">Read the manual</a>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnShowExamples\">Show Example Circuits</button><br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <canvas id=\"toolbox\" style=\"width: 370px; height: 110px; border: 1px solid black; margin: 0; padding: 0;\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                </canvas>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div id='examples-div' style=\"border: 1px solid black; margin: 10px; display: none; width: fit-content\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <strong>Example Circuits</strong>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <table style=\"border: 1px solid black; margin: 10px; text-align: left; border-collapse: collapse;\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                    <thead>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <th scope=\"col\">Code</th>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <th scope=\"col\">Style</th>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <th scope=\"col\">Task</th>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <th scope=\"col\">Size</th>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <th scope=\"col\">Link</th>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                    </thead>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                    <tbody>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Bacon-Shor Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Interleaved (XZXZ)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Memory (H)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>5x5x3</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,2)2;Q(0,3)3;Q(0,4)4;Q(1,0)5;Q(1,1)6;Q(1,2)7;Q(1,3)8;Q(1,4)9;Q(2,0)10;Q(2,1)11;Q(2,2)12;Q(2,3)13;Q(2,4)14;Q(3,0)15;Q(3,1)16;Q(3,2)17;Q(3,3)18;Q(3,4)19;Q(4,0)20;Q(4,1)21;Q(4,2)22;Q(4,3)23;Q(4,4)24;POLYGON(0,0,1,0.25)23_24;POLYGON(0,0,1,0.25)18_19;POLYGON(0,0,1,0.25)13_14;POLYGON(0,0,1,0.25)8_9;POLYGON(0,0,1,0.25)3_4;POLYGON(0,0,1,0.25)22_23;POLYGON(0,0,1,0.25)17_18;POLYGON(0,0,1,0.25)12_13;POLYGON(0,0,1,0.25)7_8;POLYGON(0,0,1,0.25)2_3;POLYGON(0,0,1,0.25)21_22;POLYGON(0,0,1,0.25)16_17;POLYGON(0,0,1,0.25)11_12;POLYGON(0,0,1,0.25)6_7;POLYGON(0,0,1,0.25)1_2;POLYGON(0,0,1,0.25)20_21;POLYGON(0,0,1,0.25)15_16;POLYGON(0,0,1,0.25)10_11;POLYGON(0,0,1,0.25)5_6;POLYGON(0,0,1,0.25)0_1;POLYGON(1,0,0,0.25)24_19;POLYGON(1,0,0,0.25)19_14;POLYGON(1,0,0,0.25)14_9;POLYGON(1,0,0,0.25)9_4;POLYGON(1,0,0,0.25)23_18;POLYGON(1,0,0,0.25)18_13;POLYGON(1,0,0,0.25)13_8;POLYGON(1,0,0,0.25)8_3;POLYGON(1,0,0,0.25)22_17;POLYGON(1,0,0,0.25)17_12;POLYGON(1,0,0,0.25)12_7;POLYGON(1,0,0,0.)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(25)7_2;POLYGON(1,0,0,0.25)21_16;POLYGON(1,0,0,0.25)16_11;POLYGON(1,0,0,0.25)11_6;POLYGON(1,0,0,0.25)6_1;POLYGON(1,0,0,0.25)20_15;POLYGON(1,0,0,0.25)15_10;POLYGON(1,0,0,0.25)10_5;POLYGON(1,0,0,0.25)5_0;TICK;R_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24;MARKZ(0)1_2_6_7_11_12_16_17_21_22;TICK;TICK;MZZ_0_1_5_6_10_11_15_16_20_21_2_3_7_8_12_13_17_18_22_23;DT(0,0,0)rec[-10];DT(1,0,0)rec[-9];DT(2,0,0)rec[-8];DT(3,0,0)rec[-7];DT(4,0,0)rec[-6];DT(0,2,0)rec[-5];DT(1,2,0)rec[-4];DT(2,2,0)rec[-3];DT(3,2,0)rec[-2];DT(4,2,0)rec[-1];TICK;MXX_0_5_1_6_2_7_3_8_4_9_10_15_11_16_12_17_13_18_14_19;MARKX(1)10_11_12_13_14_15_16_17_18_19;TICK;MZZ_1_2_6_7_11_12_16_17_21_22_3_4_8_9_13_14_18_19_23_24;MARKZ(0)1_2_6_7_11_12_16_17_21_22;DT(4,1,1)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10];DT(4,3,1)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5];TICK;MXX_5_10_6_11_7_12_8_13_9_14_15_20_16_21_17_22_18_23_19_24;TICK;TICK;MZZ_0_1_5_6_10_11_15_16_20_21_2_3_7_8_12_13_17_18_22_23;DT(4,0,2)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(4,2,2)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MXX_0_5_1_6_2_7_3_8_4_9_10_15_11_16_12_17_13_18_14_19;MARKX(1)10_11_12_13_14_15_16_17_18_19;DT(0,4,3)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(2,4,3)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MZZ_1_2_6_7_11_12_16_17_21_22_3_4_8_9_13_14_18_19_23_24;DT(4,1,4)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(4,3,4)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MXX_5_10_6_11_7_12_8_13_9_14_15_20_16_21_17_22_18_23_19_24;DT(1,4,5)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(3,4,5)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;TICK;MZZ_0_1_5_6_10_11_15_16_20_21_2_3_7_8_12_13_17_18_22_23;DT(4,0,6)rec[-6]_rec[-7]_rec[-8]_rec[-9)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(4,2,6)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MXX_0_5_1_6_2_7_3_8_4_9_10_15_11_16_12_17_13_18_14_19;DT(0,4,7)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(2,4,7)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MZZ_1_2_6_7_11_12_16_17_21_22_3_4_8_9_13_14_18_19_23_24;DT(4,1,8)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(4,3,8)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;MXX_5_10_6_11_7_12_8_13_9_14_15_20_16_21_17_22_18_23_19_24;DT(1,4,9)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-46]_rec[-47]_rec[-48]_rec[-49]_rec[-50];DT(3,4,9)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];TICK;TICK;M_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24;DT(4,0,10)rec[-4]_rec[-5]_rec[-9]_rec[-10]_rec)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART([-14]_rec[-15]_rec[-19]_rec[-20]_rec[-24]_rec[-25]_rec[-61]_rec[-62]_rec[-63]_rec[-64]_rec[-65];DT(4,1,10)rec[-3]_rec[-4]_rec[-8]_rec[-9]_rec[-13]_rec[-14]_rec[-18]_rec[-19]_rec[-23]_rec[-24]_rec[-41]_rec[-42]_rec[-43]_rec[-44]_rec[-45];DT(4,2,10)rec[-2]_rec[-3]_rec[-7]_rec[-8]_rec[-12]_rec[-13]_rec[-17]_rec[-18]_rec[-22]_rec[-23]_rec[-56]_rec[-57]_rec[-58]_rec[-59]_rec[-60];DT(4,3,10)rec[-1]_rec[-2]_rec[-6]_rec[-7]_rec[-11]_rec[-12]_rec[-16]_rec[-17]_rec[-21]_rec[-22]_rec[-36]_rec[-37]_rec[-38]_rec[-39]_rec[-40];OI(0)rec[-5]_rec[-10]_rec[-15]_rec[-20]_rec[-25]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Color Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Superdense</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Memory (Z)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>5x7x3</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,0)0;Q(1,0)1;Q(1,1)2;Q(1,2)3;Q(2,0)4;Q(2,1)5;Q(2,2)6;Q(2,3)7;Q(3,0)8;Q(3,1)9;Q(3,2)10;Q(3,3)11;Q(3,4)12;Q(3,5)13;Q(4,0)14;Q(4,1)15;Q(4,2)16;Q(4,3)17;Q(4,4)18;Q(4,5)19;Q(4,6)20;Q(5,0)21;Q(5,1)22;Q(5,2)23;Q(5,3)24;Q(5,4)25;Q(5,5)26;Q(6,0)27;Q(6,1)28;Q(6,2)29;Q(6,3)30;Q(6,4)31;Q(7,0)32;Q(7,1)33;Q(7,2)34;Q(8,0)35;Q(8,1)36;POLYGON(0,1,1,0.25)18_26_30_24;POLYGON(0,1,1,0.25)28_34_35_32;POLYGON(0,1,1,0.25)10_16_22_14_8_5;POLYGON(1,0,1,0.25)12_18_24_16_10_7;POLYGON(1,0,1,0.25)22_28_32_14;POLYGON(1,0,1,0.25)2_5_8_0;POLYGON(1,1,0,0.25)20_26_18_12;POLYGON(1,1,0,0.25)24_30_34_28_22_16;POLYGON(1,1,0,0.25)7_10_5_2;TICK;R_0_2_5_8_14_22_28_32_35_34_24_30_10_16_7_12_18_26_20;MARKZ(0)24_30_34_28_22_16;TICK;R_4_27_36_29_6_15_17_31_19;RX_1_21_33_23_3_9_11_25_13;MARKX(1)11;MARKZ(0)31_27;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;CX_1_2_21_22_33_34_23_24_9_10_11_12_25_26_4_5_27_28_29_30_6_7_15_16_17_18_19_20;TICK;CX_1_0_21_14_33_28_23_16_9_5_11_7_25_18_4_8_27_32_29_34_6)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_10_15_22_17_24_19_26;TICK;CX_33_32_23_22_3_2_9_8_11_10_25_24_13_12_36_35_29_28_6_5_15_14_17_16_31_30_19_18;TICK;CX_32_33_22_23_2_3_8_9_10_11_24_25_12_13_35_36_28_29_5_6_14_15_16_17_30_31_18_19;TICK;CX_0_1_14_21_28_33_16_23_5_9_7_11_18_25_8_4_32_27_34_29_10_6_22_15_24_17_26_19;TICK;CX_2_1_22_21_34_33_24_23_10_9_12_11_26_25_5_4_28_27_30_29_7_6_16_15_18_17_20_19;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;M_4_27_36_29_6_15_17_31_19;MX_1_21_33_23_3_9_11_25_13;MARKX(1)13_9;MARKZ(0)29;DT(2,0,0)rec[-18];DT(6,0,0)rec[-17];DT(8,1,0)rec[-16];DT(6,2,0)rec[-15];DT(2,2,0)rec[-14];DT(4,1,0)rec[-13];DT(4,3,0)rec[-12];DT(6,4,0)rec[-11];DT(4,5,0)rec[-10];TICK;R_4_27_36_29_6_15_17_31_19;RX_1_21_33_23_3_9_11_25_13;MARKX(1)11;MARKZ(3)15;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;CX_1_2_21_22_33_34_23_24_9_10_11_12_25_26_4_5_27_28_29_30_6_7_15_16_17_18_19_20;TICK;CX_1_0_21_14_33_28_23_16_9_5_11_7_25_18_4_8_27_32_29_34_6_10_15_22_17_24_19_26;TICK;CX_33_32_23_22_3_2_9_8_11_10_25_24_13_12_36_35_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(29_28_6_5_15_14_17_16_31_30_19_18;TICK;CX_32_33_22_23_2_3_8_9_10_11_24_25_12_13_35_36_28_29_5_6_14_15_16_17_30_31_18_19;TICK;CX_0_1_14_21_28_33_16_23_5_9_7_11_18_25_8_4_32_27_34_29_10_6_22_15_24_17_26_19;TICK;CX_2_1_22_21_34_33_24_23_10_9_12_11_26_25_5_4_28_27_30_29_7_6_16_15_18_17_20_19;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;M_4_27_36_29_6_15_17_31_19;MX_1_21_33_23_3_9_11_25_13;MARKX(1)11;MARKZ(3)15;DT(2,0,1)rec[-18]_rec[-36];DT(6,0,1)rec[-17]_rec[-35];DT(8,1,1)rec[-16]_rec[-34];DT(6,2,1)rec[-15]_rec[-33];DT(2,2,1)rec[-14]_rec[-32];DT(4,1,1)rec[-13]_rec[-31];DT(4,3,1)rec[-12]_rec[-30];DT(6,4,1)rec[-11]_rec[-29];DT(4,5,1)rec[-10]_rec[-28];DT(1,2,1)rec[-9]_rec[-23]_rec[-27];DT(5,2,1)rec[-8]_rec[-24]_rec[-26];DT(7,1,1)rec[-7];DT(5,4,1)rec[-6]_rec[-20]_rec[-26];DT(1,0,1)rec[-5]_rec[-27];DT(3,3,1)rec[-4]_rec[-21];DT(3,5,1)rec[-3]_rec[-19]_rec[-22];DT(5,3,1)rec[-2]_rec[-24];DT(3,4,1)rec[-1]_rec[-21];TICK;R_4_27_36_29_6_15_17_31_19;RX_1_21_33_23_3_9_11_25_13;MARKZ(2)27;MARKZ(3)17;TICK;CX_1_4_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;CX_1_2_21_22_33_34_23_24_9_10_11_12_25_26_4_5_27_28_29_30_6_7_15_16_17_18_19_20;TICK;CX_1_0_21_14_33_28_23_16_9_5_11_7_25_18_4_8_27_32_29_34_6_10_15_22_17_24_19_26;TICK;CX_33_32_23_22_3_2_9_8_11_10_25_24_13_12_36_35_29_28_6_5_15_14_17_16_31_30_19_18;TICK;CX_32_33_22_23_2_3_8_9_10_11_24_25_12_13_35_36_28_29_5_6_14_15_16_17_30_31_18_19;TICK;CX_0_1_14_21_28_33_16_23_5_9_7_11_18_25_8_4_32_27_34_29_10_6_22_15_24_17_26_19;TICK;CX_2_1_22_21_34_33_24_23_10_9_12_11_26_25_5_4_28_27_30_29_7_6_16_15_18_17_20_19;TICK;CX_1_4_21_27_33_36_23_29_3_6_9_15_11_17_25_31_13_19;TICK;M_4_27_36_29_6_15_17_31_19;MX_1_21_33_23_3_9_11_25_13;MARKZ(3)15;DT(2,0,2)rec[-18]_rec[-36];DT(6,0,2)rec[-17]_rec[-35];DT(8,1,2)rec[-16]_rec[-34];DT(6,2,2)rec[-15]_rec[-33];DT(2,2,2)rec[-14]_rec[-32];DT(4,1,2)rec[-13]_rec[-31];DT(4,3,2)rec[-12]_rec[-30];DT(6,4,2)rec[-11]_rec[-29];DT(4,5,2)rec[-10]_rec[-28];DT(1,2,2)rec[-9]_rec[-23]_rec[-27];DT(5,2,2)rec[-8]_rec[-24]_rec[-26];DT(7,1,2)rec[-7];DT(5,4,2)rec)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART([-6]_rec[-20]_rec[-26];DT(1,0,2)rec[-5]_rec[-27];DT(3,3,2)rec[-4]_rec[-21];DT(3,5,2)rec[-3]_rec[-19]_rec[-22];DT(5,3,2)rec[-2]_rec[-24];DT(3,4,2)rec[-1]_rec[-21];TICK;M_0_2_5_8_14_22_28_32_35_34_24_30_10_16_7_12_18_26_20;MARKZ(2)28_22_14_32;DT(2,0,3)rec[-16]_rec[-17]_rec[-18]_rec[-19]_rec[-37];DT(6,0,3)rec[-12]_rec[-13]_rec[-14]_rec[-15]_rec[-36];DT(8,1,3)rec[-10]_rec[-11]_rec[-12]_rec[-13]_rec[-35];DT(6,2,3)rec[-6]_rec[-8]_rec[-9]_rec[-10]_rec[-13]_rec[-14]_rec[-34];DT(4,1,3)rec[-6]_rec[-7]_rec[-14]_rec[-15]_rec[-16]_rec[-17]_rec[-32];DT(2,2,3)rec[-5]_rec[-7]_rec[-17]_rec[-18]_rec[-33];DT(4,3,3)rec[-3]_rec[-4]_rec[-5]_rec[-6]_rec[-7]_rec[-9]_rec[-31];DT(6,4,3)rec[-2]_rec[-3]_rec[-8]_rec[-9]_rec[-30];DT(4,5,3)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-29];OI(0)rec[-1]_rec[-2]_rec[-3]_rec[-4]_rec[-5]_rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-11]_rec[-12]_rec[-13]_rec[-14]_rec[-15]_rec[-16]_rec[-17]_rec[-18]_rec[-19]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Honeycomb Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>YXZ-YZX</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Memory (H)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>7x9x3</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,5)2;Q(0,6)3;Q(0,7)4;Q(1,0)5;Q(1,1)6;Q(1,2)7;Q(1,3)8;Q(1,4)9;Q(1,5)10;Q(1,6)11;Q(1,7)12;Q(1,8)13;Q(2,0)14;Q(2,1)15;Q(2,2)16;Q(2,3)17;Q(2,4)18;Q(2,5)19;Q(2,6)20;Q(2,7)21;Q(2,8)22;Q(3,0)23;Q(3,1)24;Q(3,2)25;Q(3,3)26;Q(3,4)27;Q(3,5)28;Q(3,6)29;Q(3,7)30;Q(3,8)31;Q(4,0)32;Q(4,1)33;Q(4,2)34;Q(4,3)35;Q(4,4)36;Q(4,5)37;Q(4,6)38;Q(4,7)39;Q(4,8)40;Q(5,0)41;Q(5,1)42;Q(5,2)43;Q(5,3)44;Q(5,4)45;Q(5,5)46;Q(5,6)47;Q(5,7)48;Q(5,8)49;Q(6,2)50;Q(6,3)51;Q(6,4)52;Q(6,8)53;POLYGON(0,0,1,0.25)11_20_21_22_13_12;POLYGON(0,0,1,0.25)17_26_27_28_19_18;POLYGON(0,0,1,0.25)5_14_15_16_7_6;POLYGON(0,0,1,0.25)29_38_39_40_31_30;POLYGON(0,0,1,0.25)35_44_45_46_37_36;POLYGON(0,0,1,0.25)48_47_53_49;POLYGON(0,0,1,0.25)8_9_10_2;POLYGON(0,0,1,0.25)23_32_33_34_25_24;POLYGON(0,0,1,0.25)42_41_50_43;POLYGON(0,1,0,0.25)9_18_19_20_11_10;POLYGON(0,1,0,0.25)15_24_25_26_17_16;POLYGON(0,1,0,0.25)27_36_37_38_29_28;POLYGON(0,1,0,0.25)21_30_31_22;POLYGON(0,1,0,0.25)39_48_49_40;POLYGON(0,1,0,0.25)45_52_4)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(7_46;POLYGON(0,1,0,0.25)4_12_13;POLYGON(0,1,0,0.25)1_6_7_8;POLYGON(0,1,0,0.25)33_42_43_44_35_34;POLYGON(0,1,0,0.25)14_5;POLYGON(0,1,0,0.25)32_23;POLYGON(1,0,0,0.25)2_10_11_12_4_3;POLYGON(1,0,0,0.25)19_28_29_30_21_20;POLYGON(1,0,0,0.25)7_16_17_18_9_8;POLYGON(1,0,0,0.25)25_34_35_36_27_26;POLYGON(1,0,0,0.25)43_50_51_52_45_44;POLYGON(1,0,0,0.25)37_46_47_48_39_38;POLYGON(1,0,0,0.25)22_13;POLYGON(1,0,0,0.25)40_31;POLYGON(1,0,0,0.25)53_49;POLYGON(1,0,0,0.25)0_5_6_1;POLYGON(1,0,0,0.25)14_23_24_15;POLYGON(1,0,0,0.25)32_41_42_33;TICK;R_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40_41_42_43_44_45_46_47_48_49_50_51_52_53;MARKZ(0)8_9_17_18_26_27_35_36_44_45_51_52;TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;MARKY(0)8_9_17_18_26_27_35_36_44_45_51_52;TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,0,0)rec[-32]_rec[-33]_rec[-49];DT(0,6,0)rec[-29]_rec[-30]_rec[-40];DT(6,3,0)rec[-25]_rec[-27]_rec[-55];DT(5,8,0)rec[-21]_rec[-22]_rec[-23]_rec[-34]_rec[-41];DT(0,5,0)rec[-20]_rec[-28]_rec[-31]_rec[-37]_rec[-60];DT(5,2,0)rec[-9]_rec[-24]_rec[-26]_rec[-46]_rec[-50];DT(1,8,0)rec[-7]_rec[-8]_rec[-15]_rec[-39]_rec[-44]_rec[-45];DT(3,8,0)rec[-5]_rec[-6]_rec[-14]_rec[-38]_rec[-42]_rec[-43];DT(1,2,0)rec[-4]_rec[-12]_rec[-13]_rec[-48]_rec[-53]_rec[-54];DT(3,2,0)rec[-3]_rec[-10]_rec[-11]_rec[-47]_rec[-51]_rec[-52];DT(2,5,0)rec[-2]_rec[-18]_rec[-19]_rec[-36]_rec[-58]_rec[-59];DT(4,5,0)rec[-1]_rec[-16]_rec[-17]_rec[-35]_rec[-56]_rec[-57];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,1)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-108]_rec[-119]_rec[-120];DT(3,2,1)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-107]_rec[-117]_rec[-118];DT(5,2,1)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-106]_rec[-115]_rec[-116];DT(0,5,1)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-97]_rec[-100]_rec[-105];DT(2,5,1)rec[-3]_rec[-10]_rec[-11]_rec[-43]_rec[-47]_rec[-48]_rec[-96]_rec[-103]_rec[-104];DT(4,5,1)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-95]_rec[-101]_rec[-102];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,8,2)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,2)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,2)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,2)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,2)rec[-14]_rec[-15])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,2)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,2)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,2)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,2)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,2)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,2)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,2)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,6,3)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,3)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,3)rec[-16]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,3)rec[-15]_rec[-19]_rec[-20]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,3))CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(rec[-14]_rec[-17]_rec[-18]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,3)rec[-13]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,3)rec[-2]_rec[-11]_rec[-12]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,3)rec[-1]_rec[-9]_rec[-10]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,4)rec[-15]_rec[-20]_rec[-21]_rec[-31]_rec[-39]_rec[-40]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,4)rec[-14]_rec[-18]_rec[-19]_rec[-30]_rec[-37]_rec[-38]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,4)rec[-6]_rec[-11]_rec[-12]_rec[-34]_rec[-35]_rec[-42]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,4)rec[-5]_rec[-9]_rec[-10])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_rec[-32]_rec[-33]_rec[-41]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,4)rec[-3]_rec[-25]_rec[-26]_rec[-29]_rec[-45]_rec[-46]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,4)rec[-2]_rec[-23]_rec[-24]_rec[-28]_rec[-43]_rec[-44]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,1,5)rec[-32]_rec[-33]_rec[-92]_rec[-93];DT(0,7,5)rec[-29]_rec[-30]_rec[-89]_rec[-90];DT(6,4,5)rec[-25]_rec[-27]_rec[-85]_rec[-87];DT(5,7,5)rec[-21]_rec[-22]_rec[-23]_rec[-81]_rec[-82]_rec[-83];DT(1,4,5)rec[-20]_rec[-28]_rec[-31]_rec[-80]_rec[-88]_rec[-91];DT(5,1,5)rec[-9]_rec[-24]_rec[-26]_rec[-69]_rec[-84]_rec[-86];DT(2,7,5)rec[-7]_rec[-8]_rec[-15]_rec[-67]_rec[-68]_rec[-75];DT(4,7,5)rec[-5]_rec[-6]_rec[-14]_rec[-65]_rec[-66]_rec[-74];DT(1,0,5)rec[-4]_rec[-12]_rec[-13]_rec[-64]_rec[-72]_rec[-)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(73];DT(3,0,5)rec[-3]_rec[-10]_rec[-11]_rec[-63]_rec[-70]_rec[-71];DT(2,3,5)rec[-2]_rec[-18]_rec[-19]_rec[-62]_rec[-78]_rec[-79];DT(4,3,5)rec[-1]_rec[-16]_rec[-17]_rec[-61]_rec[-76]_rec[-77];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,0,6)rec[-31]_rec[-32]_rec[-37]_rec[-97]_rec[-157]_rec[-158];DT(4,0,6)rec[-29]_rec[-30]_rec[-36]_rec[-96]_rec[-155]_rec[-156];DT(2,7,6)rec[-16]_rec[-25]_rec[-26]_rec[-39]_rec[-40]_rec[-99]_rec[-100]_rec[-142]_rec[-151]_rec[-152];DT(4,7,6)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54]_rec[-98]_rec[-114]_rec[-139]_rec[-149]_rec[-150];DT(2,1,6)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45]_rec[-95]_rec[-104]_rec[-105]_rec[-132]_rec[-137]_rec[-138];DT(4,1,6)rec[-4]_rec[-9]_rec[-10]_rec[-34]_rec[-42]_rec[-43]_rec[-94]_rec[-102]_rec[-103]_rec[-130]_rec[-135]_rec[-136];DT(1,4,6)rec[-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53]_rec[-10)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(8]_rec[-112]_rec[-113]_rec[-129]_rec[-143]_rec[-147];DT(3,4,6)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51]_rec[-107]_rec[-110]_rec[-111]_rec[-128]_rec[-145]_rec[-146];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,7)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-156]_rec[-160]_rec[-165]_rec[-201]_rec[-212]_rec[-213];DT(3,2,7)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-155]_rec[-163]_rec[-164]_rec[-200]_rec[-210]_rec[-211];DT(5,2,7)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-154]_rec[-161]_rec[-162]_rec[-199]_rec[-208]_rec[-209];DT(0,5,7)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-167]_rec[-168]_rec[-170]_rec[-190]_rec[-193]_rec[-198];DT(2,5,7)rec[-3]_rec[-10]_rec[-11]_rec[-43]_rec[-47]_rec[-48]_rec[-169]_rec[-173]_rec[-174]_rec[-189]_rec[-196]_rec[-197];DT(4,5,7)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-166]_rec[-1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(71]_rec[-172]_rec[-188]_rec[-194]_rec[-195];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,8,8)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,8)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,8)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,8)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,8)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,8)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,8)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,8)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,8)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,8)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,8)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,8)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,6,9)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,9)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,9)rec[-16]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,9)rec[-15]_rec[-19]_rec[-20]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,9)rec[-14]_rec[-17]_rec[-18]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,9)rec[-13]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,9)rec[-2]_rec[-11]_rec[-12]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,9)rec[-1]_rec[-9]_rec[-10]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,10)rec[-15]_rec[-20]_rec[-21]_rec[-31]_rec[-39]_rec[-40]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,10)rec[-14]_rec[-18]_rec[-19]_rec[-30]_rec[-37]_rec[-38]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,10)rec[-6]_rec[-11]_rec[-12]_rec[-34]_rec[-35]_rec[-42]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,10)rec[-5]_rec[-9]_rec[-10]_rec[-32]_rec[-33]_rec[-41]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,10)rec[-3]_rec[-25]_rec[-26]_rec[-29]_rec[-45]_rec[-46]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,10)rec[-2]_rec[-23]_rec[-24]_rec[-28]_rec[-43]_rec[-44]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)8_17_26_35_44_51;DT(0,1,11)rec[-32]_rec[-33]_rec[-92]_rec[)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(-93];DT(0,7,11)rec[-29]_rec[-30]_rec[-89]_rec[-90];DT(6,4,11)rec[-25]_rec[-27]_rec[-85]_rec[-87];DT(5,7,11)rec[-21]_rec[-22]_rec[-23]_rec[-81]_rec[-82]_rec[-83];DT(1,4,11)rec[-20]_rec[-28]_rec[-31]_rec[-80]_rec[-88]_rec[-91];DT(5,1,11)rec[-9]_rec[-24]_rec[-26]_rec[-69]_rec[-84]_rec[-86];DT(2,7,11)rec[-7]_rec[-8]_rec[-15]_rec[-67]_rec[-68]_rec[-75];DT(4,7,11)rec[-5]_rec[-6]_rec[-14]_rec[-65]_rec[-66]_rec[-74];DT(1,0,11)rec[-4]_rec[-12]_rec[-13]_rec[-64]_rec[-72]_rec[-73];DT(3,0,11)rec[-3]_rec[-10]_rec[-11]_rec[-63]_rec[-70]_rec[-71];DT(2,3,11)rec[-2]_rec[-18]_rec[-19]_rec[-62]_rec[-78]_rec[-79];DT(4,3,11)rec[-1]_rec[-16]_rec[-17]_rec[-61]_rec[-76]_rec[-77];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,0,12)rec[-31]_rec[-32]_rec[-37]_rec[-97]_rec[-157]_rec[-158];DT(4,0,12)rec[-29]_rec[-30]_rec[-36]_rec[-96]_rec[-155]_rec[-156];DT(2,7,12)rec[-16]_rec[-25]_rec[-26]_rec)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART([-39]_rec[-40]_rec[-99]_rec[-100]_rec[-142]_rec[-151]_rec[-152];DT(4,7,12)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54]_rec[-98]_rec[-114]_rec[-139]_rec[-149]_rec[-150];DT(2,1,12)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45]_rec[-95]_rec[-104]_rec[-105]_rec[-132]_rec[-137]_rec[-138];DT(4,1,12)rec[-4]_rec[-9]_rec[-10]_rec[-34]_rec[-42]_rec[-43]_rec[-94]_rec[-102]_rec[-103]_rec[-130]_rec[-135]_rec[-136];DT(1,4,12)rec[-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53]_rec[-108]_rec[-112]_rec[-113]_rec[-129]_rec[-143]_rec[-147];DT(3,4,12)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51]_rec[-107]_rec[-110]_rec[-111]_rec[-128]_rec[-145]_rec[-146];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,13)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-156]_rec[-160]_rec[-165]_rec[-201]_rec[-212]_rec[-213];DT(3,2,13)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-155]_rec[-163)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(]_rec[-164]_rec[-200]_rec[-210]_rec[-211];DT(5,2,13)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-154]_rec[-161]_rec[-162]_rec[-199]_rec[-208]_rec[-209];DT(0,5,13)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-167]_rec[-168]_rec[-170]_rec[-190]_rec[-193]_rec[-198];DT(2,5,13)rec[-3]_rec[-10]_rec[-11]_rec[-43]_rec[-47]_rec[-48]_rec[-169]_rec[-173]_rec[-174]_rec[-189]_rec[-196]_rec[-197];DT(4,5,13)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-166]_rec[-171]_rec[-172]_rec[-188]_rec[-194]_rec[-195];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)9_18_27_36_45_52;DT(2,8,14)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,14)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,14)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,14)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,14)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,14)rec[-13]_rec[-18]_rec[-19]_r)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ec[-73]_rec[-78]_rec[-79];DT(2,1,14)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,14)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,14)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,14)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,14)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,14)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44_48_49;MARKX(0)8_17_26_35_44_51;DT(0,6,15)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,15)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,15)rec[-17]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,15)rec[-16]_rec[-20]_rec[-21]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,15)rec[-15]_rec[-18]_rec[-19]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,15)rec[-14]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,15)rec[-3]_rec[-12]_rec[-13]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,15)rec[-2]_rec[-10]_rec[-11]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;MARKY(0)9_18_27_36_45_52_8_17_26_35_44_51;DT(1,2,16)rec[-15]_rec[-20]_rec[-21]_rec[-32]_rec[-40]_rec[-41]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,16)rec[-14]_rec[-18]_rec[-19]_rec[-31]_rec[-38]_rec[-39]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,16)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-36]_rec[-43]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,16)rec[-5]_rec[-9]_rec[-10]_rec[-33]_rec)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART([-34]_rec[-42]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,16)rec[-3]_rec[-25]_rec[-26]_rec[-30]_rec[-46]_rec[-47]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,16)rec[-2]_rec[-23]_rec[-24]_rec[-29]_rec[-44]_rec[-45]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;M_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40_41_42_43_44_45_46_47_48_49_50_51_52_53;MARKZ(0)8_9_17_18_26_27_35_36_44_45_51_52;DT(0,1,17)rec[-53]_rec[-54]_rec[-70]_rec[-113]_rec[-114];DT(0,7,17)rec[-50]_rec[-51]_rec[-61]_rec[-110]_rec[-111];DT(1,4,17)rec[-44]_rec[-45]_rec[-46]_rec[-52]_rec[-58]_rec[-81]_rec[-102]_rec[-109]_rec[-112];DT(0,5,17)rec[-42]_rec[-43]_rec[-44]_rec[-50]_rec[-51]_rec[-52]_rec[-58]_rec[-61]_rec[-66]_rec[-128]_rec[-129]_rec[-131]_rec[-151]_rec[-154]_rec[-159];DT(1,0,17)rec[-38]_rec[-39]_rec[-40]_rec[-47]_rec[-48]_rec[-49]_rec[-69]_rec[-74]_rec[-75]_rec[-86]_rec[-94]_rec[-95];DT(1,2,17)rec[-36]_rec[-3)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(7]_rec[-38]_rec[-45]_rec[-46]_rec[-47]_rec[-69]_rec[-80]_rec[-81]_rec[-117]_rec[-121]_rec[-126]_rec[-162]_rec[-173]_rec[-174];DT(2,7,17)rec[-32]_rec[-33]_rec[-34]_rec[-41]_rec[-42]_rec[-43]_rec[-60]_rec[-65]_rec[-66]_rec[-89]_rec[-90]_rec[-97];DT(2,3,17)rec[-26]_rec[-27]_rec[-28]_rec[-35]_rec[-36]_rec[-37]_rec[-57]_rec[-79]_rec[-80]_rec[-84]_rec[-100]_rec[-101];DT(2,5,17)rec[-24]_rec[-25]_rec[-26]_rec[-33]_rec[-34]_rec[-35]_rec[-57]_rec[-64]_rec[-65]_rec[-130]_rec[-134]_rec[-135]_rec[-150]_rec[-157]_rec[-158];DT(3,0,17)rec[-20]_rec[-21]_rec[-22]_rec[-29]_rec[-30]_rec[-31]_rec[-68]_rec[-72]_rec[-73]_rec[-85]_rec[-92]_rec[-93];DT(3,2,17)rec[-18]_rec[-19]_rec[-20]_rec[-27]_rec[-28]_rec[-29]_rec[-68]_rec[-78]_rec[-79]_rec[-116]_rec[-124]_rec[-125]_rec[-161]_rec[-171]_rec[-172];DT(4,7,17)rec[-14]_rec[-15]_rec[-16]_rec[-23]_rec[-24]_rec[-25]_rec[-59]_rec[-63]_rec[-64]_rec[-87]_rec[-88]_rec[-96];DT(4,3,17)rec[-8]_rec[-9]_rec[-10]_rec[-17]_rec[-18]_rec[-19]_rec[-56]_rec[-77]_rec[-78]_rec[-83]_rec[-98]_rec[-99];DT(4,5)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(,17)rec[-6]_rec[-7]_rec[-8]_rec[-15]_rec[-16]_rec[-17]_rec[-56]_rec[-62]_rec[-63]_rec[-127]_rec[-132]_rec[-133]_rec[-149]_rec[-155]_rec[-156];DT(5,1,17)rec[-4]_rec[-11]_rec[-12]_rec[-13]_rec[-67]_rec[-71]_rec[-91]_rec[-105]_rec[-107];DT(6,4,17)rec[-2]_rec[-3]_rec[-76]_rec[-106]_rec[-108];DT(5,2,17)rec[-2]_rec[-3]_rec[-4]_rec[-9]_rec[-10]_rec[-11]_rec[-67]_rec[-76]_rec[-77]_rec[-115]_rec[-122]_rec[-123]_rec[-160]_rec[-169]_rec[-170];DT(5,7,17)rec[-1]_rec[-5]_rec[-6]_rec[-7]_rec[-55]_rec[-62]_rec[-82]_rec[-103]_rec[-104];OI(0)rec[-2]_rec[-3]_rec[-9]_rec[-10]_rec[-18]_rec[-19]_rec[-27]_rec[-28]_rec[-36]_rec[-37]_rec[-45]_rec[-46]_rec[-76]_rec[-77]_rec[-78]_rec[-79]_rec[-80]_rec[-81]_rec[-83]_rec[-84]_rec[-108]_rec[-109]_rec[-115]_rec[-116]_rec[-117]_rec[-175]_rec[-176]_rec[-177]_rec[-208]_rec[-209]_rec[-234]_rec[-235]_rec[-268]_rec[-269]_rec[-294]_rec[-295]_rec[-301]_rec[-302]_rec[-303]_rec[-361]_rec[-362]_rec[-363]_rec[-394]_rec[-395]_rec[-420]_rec[-421]_rec[-454]_rec[-455]_rec[-480]_rec[-481]_rec[-487]_rec[-48)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(8]_rec[-489]_rec[-547]_rec[-548]_rec[-549]_rec[-580]_rec[-581]_rec[-606]_rec[-607]_rec[-634]_rec[-635]_rec[-636]_rec[-637]_rec[-638]_rec[-639]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Honeycomb Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>YXZ-YZX</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Memory (V)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>7x9x3</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,5)2;Q(0,6)3;Q(0,7)4;Q(1,0)5;Q(1,1)6;Q(1,2)7;Q(1,3)8;Q(1,4)9;Q(1,5)10;Q(1,6)11;Q(1,7)12;Q(1,8)13;Q(2,0)14;Q(2,1)15;Q(2,2)16;Q(2,3)17;Q(2,4)18;Q(2,5)19;Q(2,6)20;Q(2,7)21;Q(2,8)22;Q(3,0)23;Q(3,1)24;Q(3,2)25;Q(3,3)26;Q(3,4)27;Q(3,5)28;Q(3,6)29;Q(3,7)30;Q(3,8)31;Q(4,0)32;Q(4,1)33;Q(4,2)34;Q(4,3)35;Q(4,4)36;Q(4,5)37;Q(4,6)38;Q(4,7)39;Q(4,8)40;Q(5,0)41;Q(5,1)42;Q(5,2)43;Q(5,3)44;Q(5,4)45;Q(5,5)46;Q(5,6)47;Q(5,7)48;Q(5,8)49;Q(6,2)50;Q(6,3)51;Q(6,4)52;Q(6,8)53;POLYGON(0,0,1,0.25)11_20_21_22_13_12;POLYGON(0,0,1,0.25)17_26_27_28_19_18;POLYGON(0,0,1,0.25)5_14_15_16_7_6;POLYGON(0,0,1,0.25)29_38_39_40_31_30;POLYGON(0,0,1,0.25)35_44_45_46_37_36;POLYGON(0,0,1,0.25)48_47_53_49;POLYGON(0,0,1,0.25)8_9_10_2;POLYGON(0,0,1,0.25)23_32_33_34_25_24;POLYGON(0,0,1,0.25)42_41_50_43;POLYGON(0,1,0,0.25)9_18_19_20_11_10;POLYGON(0,1,0,0.25)15_24_25_26_17_16;POLYGON(0,1,0,0.25)27_36_37_38_29_28;POLYGON(0,1,0,0.25)21_30_31_22;POLYGON(0,1,0,0.25)39_48_49_40;POLYGON(0,1,0,0.25)45_52_4)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(7_46;POLYGON(0,1,0,0.25)4_12_13;POLYGON(0,1,0,0.25)1_6_7_8;POLYGON(0,1,0,0.25)33_42_43_44_35_34;POLYGON(0,1,0,0.25)14_5;POLYGON(0,1,0,0.25)32_23;POLYGON(1,0,0,0.25)2_10_11_12_4_3;POLYGON(1,0,0,0.25)19_28_29_30_21_20;POLYGON(1,0,0,0.25)7_16_17_18_9_8;POLYGON(1,0,0,0.25)25_34_35_36_27_26;POLYGON(1,0,0,0.25)43_50_51_52_45_44;POLYGON(1,0,0,0.25)37_46_47_48_39_38;POLYGON(1,0,0,0.25)22_13;POLYGON(1,0,0,0.25)40_31;POLYGON(1,0,0,0.25)53_49;POLYGON(1,0,0,0.25)0_5_6_1;POLYGON(1,0,0,0.25)14_23_24_15;POLYGON(1,0,0,0.25)32_41_42_33;TICK;RY_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40_41_42_43_44_45_46_47_48_49_50_51_52_53;MARKY(0)24_25_27_28_30_31;TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,3,0)rec[-27];DT(2,3,0)rec[-26];DT(3,3,0)rec[-25];DT(4,3,0)rec[-24];DT(5,3,0)rec[-23];DT(6,3,0)rec[-22];DT(1,0,0)rec[-21];DT(2,0,0)rec[-20];DT()CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(3,0,0)rec[-19];DT(4,0,0)rec[-18];DT(5,0,0)rec[-17];DT(0,0,0)rec[-16];DT(1,2,0)rec[-15];DT(3,2,0)rec[-14];DT(5,2,0)rec[-13];DT(1,6,0)rec[-12];DT(2,6,0)rec[-11];DT(3,6,0)rec[-10];DT(4,6,0)rec[-9];DT(5,6,0)rec[-8];DT(0,6,0)rec[-7];DT(1,8,0)rec[-6];DT(3,8,0)rec[-5];DT(0,5,0)rec[-4];DT(2,5,0)rec[-3];DT(4,5,0)rec[-2];DT(5,8,0)rec[-1];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(1,0,1)rec[-31]_rec[-32]_rec[-37];DT(3,0,1)rec[-29]_rec[-30]_rec[-36];DT(3,7,1)rec[-16]_rec[-25]_rec[-26]_rec[-39]_rec[-40];DT(4,7,1)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54];DT(2,3,1)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45];DT(4,3,1)rec[-4]_rec[-9]_rec[-10]_rec[-34]_rec[-42]_rec[-43];DT(1,6,1)rec)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART([-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53];DT(3,6,1)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,8,2)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,2)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,2)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,2)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,2)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,2)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,2)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,2)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,2)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,2)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(rec[-72];DT(3,4,2)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,2)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;DT(0,6,3)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,3)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,3)rec[-16]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,3)rec[-15]_rec[-19]_rec[-20]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,3)rec[-14]_rec[-17]_rec[-18]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,3)rec[-13]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,3)rec[-2]_rec[-11]_rec[-12]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(DT(4,3,3)rec[-1]_rec[-9]_rec[-10]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,4)rec[-15]_rec[-20]_rec[-21]_rec[-31]_rec[-39]_rec[-40]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,4)rec[-14]_rec[-18]_rec[-19]_rec[-30]_rec[-37]_rec[-38]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,4)rec[-6]_rec[-11]_rec[-12]_rec[-34]_rec[-35]_rec[-42]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,4)rec[-5]_rec[-9]_rec[-10]_rec[-32]_rec[-33]_rec[-41]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,4)rec[-3]_rec[-25]_rec[-26]_rec[-29]_rec[-45]_rec[-46]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,4)rec[-2]_rec[-23]_rec[-24]_rec[-28]_rec[-43]_rec[-44]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;DT(0,1,5)rec[-32]_rec[-33]_rec[-92]_rec[-93];DT(0,7,5)rec[-29]_rec[-30]_rec[-89]_rec[-90];DT(6,4,5)rec[-25]_rec[-27]_rec[-85]_rec[-87];DT(5,7,5)rec[-21]_rec[-22]_rec[-23]_rec[-81]_rec[-82]_rec[-83];DT(1,4,5)rec[-20]_rec[-28]_rec[-31]_rec[-80]_rec[-88]_rec[-91];DT(5,1,5)rec[-9]_rec[-24]_rec[-26]_rec[-69]_rec[-84]_rec[-86];DT(2,7,5)rec[-7]_rec[-8]_rec[-15]_rec[-67]_rec[-68]_rec[-75];DT(4,7,5)rec[-5]_rec[-6]_rec[-14]_rec[-65]_rec[-66]_rec[-74];DT(1,0,5)rec[-4]_rec[-12]_rec[-13]_rec[-64]_rec[-72]_rec[-73];DT(3,0,5)rec[-3]_rec[-10]_rec[-11]_rec[-63]_rec[-70]_rec[-71];DT(2,3,5)rec[-2]_rec[-18]_rec[-19]_rec[-62]_rec[-78]_rec[-79];DT(4,3,5)rec[-1]_rec[-16]_rec[-17]_rec[-61]_rec[-76]_rec[-77];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,0,6)rec[-31]_rec[-32]_rec[-37]_rec[-97]_rec[-157]_rec[-158];DT(4,0,6)rec[-29]_rec[-30]_rec[-36]_rec[-96]_rec[-155]_rec[-156];DT(2,7,6)rec[-16]_rec[-25]_rec[-26]_rec[-39]_rec[-40]_rec[-99]_rec[-100]_rec[-142]_rec[-151]_rec[-152];DT(4,7,6)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54]_rec[-98]_rec[-114]_rec[-139]_rec[-149]_rec[-150];DT(2,1,6)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45]_rec[-95]_rec[-104]_rec[-105]_rec[-132]_rec[-137]_rec[-138];DT(4,1,6)rec[-4]_rec[-9]_rec[-10]_rec[-34]_rec[-42]_rec[-43]_rec[-94]_rec[-102]_rec[-103]_rec[-130]_rec[-135]_rec[-136];DT(1,4,6)rec[-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53]_rec[-108]_rec[-112]_rec[-113]_rec[-129]_rec[-143]_rec[-147];DT(3,4,6)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51]_rec[-107]_rec[-110]_rec[-111]_rec[-128]_rec[-145]_rec[-146];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;DT(1,2,7)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-156]_rec[-160]_rec[-165]_rec[-201]_rec[-212]_rec[-213];DT(3,2,7)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-155]_rec[-163]_rec[-164]_rec[-200]_rec[-210]_rec[-211];DT(5,2,7)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-154]_rec[-161]_rec[-162]_rec[-199]_rec[-208]_rec[-209];DT(0,5,7)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-167]_rec[-168]_rec[-170]_rec[-190]_rec[-193]_rec[-198];DT(2,5,7)rec[-3]_rec[-10]_rec[-11]_rec[-43]_rec[-47]_rec[-48]_rec[-169]_rec[-173]_rec[-174]_rec[-189]_rec[-196]_rec[-197];DT(4,5,7)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-166]_rec[-171]_rec[-172]_rec[-188]_rec[-194]_rec[-195];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,8,8)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,8)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,8)rec)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART([-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,8)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,8)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,8)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,8)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,8)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,8)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,8)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,8)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70]_rec[-71];DT(5,4,8)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;DT(0,6,9)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,9)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,9)rec[-16]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,9)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART()rec[-15]_rec[-19]_rec[-20]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,9)rec[-14]_rec[-17]_rec[-18]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,9)rec[-13]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,9)rec[-2]_rec[-11]_rec[-12]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,9)rec[-1]_rec[-9]_rec[-10]_rec[-37]_rec[-42]_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,10)rec[-15]_rec[-20]_rec[-21]_rec[-31]_rec[-39]_rec[-40]_rec[-157]_rec[-165]_rec[-166]_rec[-201]_rec[-206]_rec[-207];DT(3,2,10)rec[-14]_rec[-18]_rec[-19]_rec[-30]_rec[-37]_rec[-38]_rec[-156]_rec[-163]_rec[-164]_rec[-200]_rec[-204]_rec[-205];DT(1,8,10)rec[-6]_rec[-11]_rec)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART([-12]_rec[-34]_rec[-35]_rec[-42]_rec[-160]_rec[-161]_rec[-168]_rec[-192]_rec[-197]_rec[-198];DT(3,8,10)rec[-5]_rec[-9]_rec[-10]_rec[-32]_rec[-33]_rec[-41]_rec[-158]_rec[-159]_rec[-167]_rec[-191]_rec[-195]_rec[-196];DT(2,5,10)rec[-3]_rec[-25]_rec[-26]_rec[-29]_rec[-45]_rec[-46]_rec[-155]_rec[-171]_rec[-172]_rec[-189]_rec[-211]_rec[-212];DT(4,5,10)rec[-2]_rec[-23]_rec[-24]_rec[-28]_rec[-43]_rec[-44]_rec[-154]_rec[-169]_rec[-170]_rec[-188]_rec[-209]_rec[-210];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_48_49_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44;MARKX(0)24_25_27_28_30_31;DT(0,1,11)rec[-32]_rec[-33]_rec[-92]_rec[-93];DT(0,7,11)rec[-29]_rec[-30]_rec[-89]_rec[-90];DT(6,4,11)rec[-25]_rec[-27]_rec[-85]_rec[-87];DT(5,7,11)rec[-21]_rec[-22]_rec[-23]_rec[-81]_rec[-82]_rec[-83];DT(1,4,11)rec[-20]_rec[-28]_rec[-31]_rec[-80]_rec[-88]_rec[-91];DT(5,1,11)rec[-9]_rec[-24]_rec[-26]_rec[-69]_rec[-84]_rec[-86];DT(2,7,11)rec[-7]_rec[-8]_rec[-15]_rec[-67]_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(rec[-68]_rec[-75];DT(4,7,11)rec[-5]_rec[-6]_rec[-14]_rec[-65]_rec[-66]_rec[-74];DT(1,0,11)rec[-4]_rec[-12]_rec[-13]_rec[-64]_rec[-72]_rec[-73];DT(3,0,11)rec[-3]_rec[-10]_rec[-11]_rec[-63]_rec[-70]_rec[-71];DT(2,3,11)rec[-2]_rec[-18]_rec[-19]_rec[-62]_rec[-78]_rec[-79];DT(4,3,11)rec[-1]_rec[-16]_rec[-17]_rec[-61]_rec[-76]_rec[-77];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,0,12)rec[-31]_rec[-32]_rec[-37]_rec[-97]_rec[-157]_rec[-158];DT(4,0,12)rec[-29]_rec[-30]_rec[-36]_rec[-96]_rec[-155]_rec[-156];DT(2,7,12)rec[-16]_rec[-25]_rec[-26]_rec[-39]_rec[-40]_rec[-99]_rec[-100]_rec[-142]_rec[-151]_rec[-152];DT(4,7,12)rec[-13]_rec[-23]_rec[-24]_rec[-38]_rec[-54]_rec[-98]_rec[-114]_rec[-139]_rec[-149]_rec[-150];DT(2,1,12)rec[-6]_rec[-11]_rec[-12]_rec[-35]_rec[-44]_rec[-45]_rec[-95]_rec[-104]_rec[-105]_rec[-132]_rec[-137]_rec[-138];DT(4,1,12)rec[-4]_rec[-9]_rec[-10]_rec[-3)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(4]_rec[-42]_rec[-43]_rec[-94]_rec[-102]_rec[-103]_rec[-130]_rec[-135]_rec[-136];DT(1,4,12)rec[-3]_rec[-17]_rec[-21]_rec[-48]_rec[-52]_rec[-53]_rec[-108]_rec[-112]_rec[-113]_rec[-129]_rec[-143]_rec[-147];DT(3,4,12)rec[-2]_rec[-19]_rec[-20]_rec[-47]_rec[-50]_rec[-51]_rec[-107]_rec[-110]_rec[-111]_rec[-128]_rec[-145]_rec[-146];TICK;MYY_8_9_17_18_26_27_35_36_44_45_51_52_5_6_14_15_23_24_32_33_41_42_0_1_7_16_25_34_43_50_11_12_20_21_29_30_38_39_47_48_3_4_13_22_31_40_2_10_19_28_37_46_49_53;DT(1,2,13)rec[-15]_rec[-26]_rec[-27]_rec[-30]_rec[-34]_rec[-39]_rec[-156]_rec[-160]_rec[-165]_rec[-201]_rec[-212]_rec[-213];DT(3,2,13)rec[-14]_rec[-24]_rec[-25]_rec[-29]_rec[-37]_rec[-38]_rec[-155]_rec[-163]_rec[-164]_rec[-200]_rec[-210]_rec[-211];DT(5,2,13)rec[-13]_rec[-22]_rec[-23]_rec[-28]_rec[-35]_rec[-36]_rec[-154]_rec[-161]_rec[-162]_rec[-199]_rec[-208]_rec[-209];DT(0,5,13)rec[-4]_rec[-7]_rec[-12]_rec[-41]_rec[-42]_rec[-44]_rec[-167]_rec[-168]_rec[-170]_rec[-190]_rec[-193]_rec[-198];DT(2,5,13)rec[-3]_rec[-10]_rec[-11]_rec[-43)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(]_rec[-47]_rec[-48]_rec[-169]_rec[-173]_rec[-174]_rec[-189]_rec[-196]_rec[-197];DT(4,5,13)rec[-2]_rec[-8]_rec[-9]_rec[-40]_rec[-45]_rec[-46]_rec[-166]_rec[-171]_rec[-172]_rec[-188]_rec[-194]_rec[-195];TICK;M_0_5_14_23_32_41_13_22_31_40_49_53;MZZ_19_20_28_29_37_38_46_47_10_11_21_30_4_12_2_3_39_48_16_17_25_26_34_35_43_44_50_51_7_8_15_24_1_6_33_42_9_18_27_36_45_52;MARKZ(0)31_29_28_25_26_23;DT(2,8,14)rec[-26]_rec[-27]_rec[-86]_rec[-87];DT(4,8,14)rec[-24]_rec[-25]_rec[-84]_rec[-85];DT(6,8,14)rec[-22]_rec[-23]_rec[-82]_rec[-83];DT(2,7,14)rec[-16]_rec[-20]_rec[-21]_rec[-76]_rec[-80]_rec[-81];DT(0,5,14)rec[-14]_rec[-15]_rec[-17]_rec[-74]_rec[-75]_rec[-77];DT(4,7,14)rec[-13]_rec[-18]_rec[-19]_rec[-73]_rec[-78]_rec[-79];DT(2,1,14)rec[-6]_rec[-30]_rec[-31]_rec[-66]_rec[-90]_rec[-91];DT(0,1,14)rec[-5]_rec[-32]_rec[-33]_rec[-65]_rec[-92]_rec[-93];DT(4,1,14)rec[-4]_rec[-28]_rec[-29]_rec[-64]_rec[-88]_rec[-89];DT(1,4,14)rec[-3]_rec[-7]_rec[-12]_rec[-63]_rec[-67]_rec[-72];DT(3,4,14)rec[-2]_rec[-10]_rec[-11]_rec[-62]_rec[-70])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_rec[-71];DT(5,4,14)rec[-1]_rec[-8]_rec[-9]_rec[-61]_rec[-68]_rec[-69];TICK;MX_0_1_2_3_4_8_51_50_52_41_47_53;MXX_9_10_18_19_27_28_36_37_45_46_11_20_29_38_6_7_15_16_24_25_33_34_42_43_12_13_21_22_30_31_39_40_5_14_23_32_17_26_35_44_48_49;MARKX(0)24_25_27_28_30_31;DT(0,6,15)rec[-30]_rec[-31]_rec[-47]_rec[-107]_rec[-156]_rec[-157];DT(6,2,15)rec[-26]_rec[-27]_rec[-41]_rec[-101]_rec[-152]_rec[-153];DT(5,4,15)rec[-17]_rec[-23]_rec[-25]_rec[-34]_rec[-51]_rec[-94]_rec[-111]_rec[-142]_rec[-149]_rec[-151];DT(1,6,15)rec[-16]_rec[-20]_rec[-21]_rec[-36]_rec[-50]_rec[-54]_rec[-96]_rec[-110]_rec[-114]_rec[-141]_rec[-145]_rec[-146];DT(3,6,15)rec[-15]_rec[-18]_rec[-19]_rec[-35]_rec[-52]_rec[-53]_rec[-95]_rec[-112]_rec[-113]_rec[-140]_rec[-143]_rec[-144];DT(1,1,15)rec[-14]_rec[-28]_rec[-32]_rec[-38]_rec[-40]_rec[-98]_rec[-100]_rec[-139]_rec[-154]_rec[-158];DT(2,3,15)rec[-3]_rec[-12]_rec[-13]_rec[-39]_rec[-44]_rec[-45]_rec[-99]_rec[-104]_rec[-105]_rec[-128]_rec[-137]_rec[-138];DT(4,3,15)rec[-2]_rec[-10]_rec[-11]_rec[-37]_rec[-42])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_rec[-43]_rec[-97]_rec[-102]_rec[-103]_rec[-127]_rec[-135]_rec[-136];TICK;TICK;MY_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40_41_42_43_44_45_46_47_48_49_50_51_52_53;MARKY(0)24_25_27_28_30_31;DT(2,0,16)rec[-40]_rec[-49]_rec[-59]_rec[-118]_rec[-119];DT(1,2,16)rec[-38]_rec[-39]_rec[-40]_rec[-47]_rec[-48]_rec[-49]_rec[-59]_rec[-67]_rec[-68]_rec[-184]_rec[-192]_rec[-193]_rec[-228]_rec[-233]_rec[-234];DT(1,4,16)rec[-34]_rec[-35]_rec[-36]_rec[-43]_rec[-44]_rec[-45]_rec[-70]_rec[-74]_rec[-75]_rec[-90]_rec[-104]_rec[-108];DT(1,8,16)rec[-32]_rec[-33]_rec[-34]_rec[-41]_rec[-42]_rec[-43]_rec[-62]_rec[-63]_rec[-70]_rec[-187]_rec[-188]_rec[-195]_rec[-219]_rec[-224]_rec[-225];DT(2,1,16)rec[-28]_rec[-29]_rec[-30]_rec[-37]_rec[-38]_rec[-39]_rec[-57]_rec[-66]_rec[-67]_rec[-93]_rec[-98]_rec[-99];DT(2,5,16)rec[-26]_rec[-27]_rec[-28]_rec[-35]_rec[-36]_rec[-37]_rec[-57]_rec[-73]_rec[-74]_rec[-182]_rec[-198]_rec[-199]_rec[-216]_rec[-238]_rec[-239];DT(2,7,16)rec[-2)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(3]_rec[-24]_rec[-32]_rec[-33]_rec[-61]_rec[-62]_rec[-103]_rec[-112]_rec[-113];DT(4,0,16)rec[-22]_rec[-31]_rec[-58]_rec[-116]_rec[-117];DT(3,2,16)rec[-20]_rec[-21]_rec[-22]_rec[-29]_rec[-30]_rec[-31]_rec[-58]_rec[-65]_rec[-66]_rec[-183]_rec[-190]_rec[-191]_rec[-227]_rec[-231]_rec[-232];DT(3,4,16)rec[-16]_rec[-17]_rec[-18]_rec[-25]_rec[-26]_rec[-27]_rec[-69]_rec[-72]_rec[-73]_rec[-89]_rec[-106]_rec[-107];DT(3,8,16)rec[-14]_rec[-15]_rec[-16]_rec[-23]_rec[-24]_rec[-25]_rec[-60]_rec[-61]_rec[-69]_rec[-185]_rec[-186]_rec[-194]_rec[-218]_rec[-222]_rec[-223];DT(4,1,16)rec[-10]_rec[-11]_rec[-12]_rec[-19]_rec[-20]_rec[-21]_rec[-56]_rec[-64]_rec[-65]_rec[-91]_rec[-96]_rec[-97];DT(4,5,16)rec[-8]_rec[-9]_rec[-10]_rec[-17]_rec[-18]_rec[-19]_rec[-56]_rec[-71]_rec[-72]_rec[-181]_rec[-196]_rec[-197]_rec[-215]_rec[-236]_rec[-237];DT(4,7,16)rec[-5]_rec[-6]_rec[-14]_rec[-15]_rec[-55]_rec[-60]_rec[-100]_rec[-110]_rec[-111];OI(0)rec[-23]_rec[-24]_rec[-26]_rec[-27]_rec[-29]_rec[-30]_rec[-61]_rec[-66]_rec[-73]_rec[-98]_rec[-107]_rec)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART([-112]_rec[-117]_rec[-158]_rec[-167]_rec[-172]_rec[-177]_rec[-186]_rec[-191]_rec[-198]_rec[-246]_rec[-251]_rec[-258]_rec[-284]_rec[-293]_rec[-298]_rec[-303]_rec[-344]_rec[-353]_rec[-358]_rec[-363]_rec[-372]_rec[-377]_rec[-384]_rec[-432]_rec[-437]_rec[-444]_rec[-470]_rec[-479]_rec[-484]_rec[-489]_rec[-530]_rec[-539]_rec[-544]_rec[-549]_rec[-558]_rec[-563]_rec[-570]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Surface Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Standard (ИZ)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Memory (V)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>5x5x3</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,2)0;Q(0,4)1;Q(0.5,0.5)2;Q(0.5,1.5)3;Q(0.5,2.5)4;Q(0.5,3.5)5;Q(0.5,4.5)6;Q(1,0)7;Q(1,1)8;Q(1,2)9;Q(1,3)10;Q(1,4)11;Q(1.5,0.5)12;Q(1.5,1.5)13;Q(1.5,2.5)14;Q(1.5,3.5)15;Q(1.5,4.5)16;Q(2,1)17;Q(2,2)18;Q(2,3)19;Q(2,4)20;Q(2,5)21;Q(2.5,0.5)22;Q(2.5,1.5)23;Q(2.5,2.5)24;Q(2.5,3.5)25;Q(2.5,4.5)26;Q(3,0)27;Q(3,1)28;Q(3,2)29;Q(3,3)30;Q(3,4)31;Q(3.5,0.5)32;Q(3.5,1.5)33;Q(3.5,2.5)34;Q(3.5,3.5)35;Q(3.5,4.5)36;Q(4,1)37;Q(4,2)38;Q(4,3)39;Q(4,4)40;Q(4,5)41;Q(4.5,0.5)42;Q(4.5,1.5)43;Q(4.5,2.5)44;Q(4.5,3.5)45;Q(4.5,4.5)46;Q(5,1)47;Q(5,3)48;POLYGON(0,0,1,0.25)12_22_23_13;POLYGON(0,0,1,0.25)3_13_14_4;POLYGON(0,0,1,0.25)14_24_25_15;POLYGON(0,0,1,0.25)5_15_16_6;POLYGON(0,0,1,0.25)34_44_45_35;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)32_42_43_33;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)12_2;POLYGON(0,0,1,0.25)32_22;POLYGON(0,0,1,0.25)46_36;POLYGON(0,0,1,0.25)26_16;POLYGON(1,0,0,0.25)2_12_13_3;POLYGON(1,0,0,0.25)13_23_24_14;POLYGON(1,0,0,0.25)4_14_15_5;POLYGON(1,0,0,0.25)1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(5_25_26_16;POLYGON(1,0,0,0.25)24_34_35_25;POLYGON(1,0,0,0.25)35_45_46_36;POLYGON(1,0,0,0.25)22_32_33_23;POLYGON(1,0,0,0.25)33_43_44_34;POLYGON(1,0,0,0.25)42_43;POLYGON(1,0,0,0.25)44_45;POLYGON(1,0,0,0.25)5_6;POLYGON(1,0,0,0.25)3_4;TICK;R_2_3_4_5_6_12_13_14_15_16_22_23_24_25_26_32_33_34_35_36_42_43_44_45_46;MARKZ(0)2_3_4_5_6;TICK;R_9_11_17_19_21_29_31_37_39_41_27_7;RX_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(1)28;TICK;CX_8_2_3_9_10_4_5_11_12_17_18_13_14_19_20_15_16_21_28_22_23_29_30_24_25_31_32_37_38_33_34_39_40_35_36_41_47_42_48_44;TICK;CX_13_9_15_11_22_17_24_19_26_21_33_29_35_31_42_37_44_39_46_41_8_3_10_5_18_14_20_16_28_23_30_25_38_34_40_36_47_43_48_45;TICK;CX_4_9_6_11_13_17_15_19_24_29_26_31_33_37_35_39_2_7_22_27_8_12_10_14_1_5_0_3_18_23_20_25_28_32_30_34_38_43_40_45;TICK;CX_8_13_14_9_10_15_16_11_23_17_18_24_25_19_20_26_28_33_34_29_30_35_36_31_43_37_38_44_45_39_40_46_0_4_1_6_12_7_32_27;TICK;M_9_11_17_19_21_29_31_37_39_41_27_7;MX_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(1)28;DT(1,2,0)rec[-24];DT(1,4,0)rec[-23];D)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(T(2,1,0)rec[-22];DT(2,3,0)rec[-21];DT(2,5,0)rec[-20];DT(3,2,0)rec[-19];DT(3,4,0)rec[-18];DT(4,1,0)rec[-17];DT(4,3,0)rec[-16];DT(4,5,0)rec[-15];DT(3,0,0)rec[-14];DT(1,0,0)rec[-13];TICK;R_9_11_17_19_21_29_31_37_39_41_7_27;RX_8_10_18_20_28_30_38_40_47_48_1_0;MARKX(1)28;MARKZ(2)29;TICK;CX_8_2_3_9_10_4_5_11_12_17_18_13_14_19_20_15_16_21_28_22_23_29_30_24_25_31_32_37_38_33_34_39_40_35_36_41_47_42_48_44;TICK;CX_13_9_15_11_22_17_24_19_26_21_33_29_35_31_42_37_44_39_46_41_8_3_10_5_18_14_20_16_28_23_30_25_38_34_40_36_47_43_48_45;TICK;CX_4_9_6_11_13_17_15_19_24_29_26_31_33_37_35_39_2_7_22_27_8_12_10_14_1_5_0_3_18_23_20_25_28_32_30_34_38_43_40_45;TICK;CX_8_13_14_9_10_15_16_11_23_17_18_24_25_19_20_26_28_33_34_29_30_35_36_31_43_37_38_44_45_39_40_46_0_4_1_6_12_7_32_27;TICK;M_9_11_17_19_21_29_31_37_39_41_7_27;MX_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(1)28;MARKZ(2)29;DT(1,2,1)rec[-24]_rec[-48];DT(1,4,1)rec[-23]_rec[-47];DT(2,1,1)rec[-22]_rec[-46];DT(2,3,1)rec[-21]_rec[-45];DT(2,5,1)rec[-20]_rec[-44];DT(3,2,1)rec[-19]_rec[-43];)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(DT(3,4,1)rec[-18]_rec[-42];DT(4,1,1)rec[-17]_rec[-41];DT(4,3,1)rec[-16]_rec[-40];DT(4,5,1)rec[-15]_rec[-39];DT(1,0,1)rec[-14]_rec[-37];DT(3,0,1)rec[-13]_rec[-38];DT(1,1,1)rec[-12]_rec[-36];DT(1,3,1)rec[-11]_rec[-35];DT(2,2,1)rec[-10]_rec[-34];DT(2,4,1)rec[-9]_rec[-33];DT(3,1,1)rec[-8]_rec[-32];DT(3,3,1)rec[-7]_rec[-31];DT(4,2,1)rec[-6]_rec[-30];DT(4,4,1)rec[-5]_rec[-29];DT(5,1,1)rec[-4]_rec[-28];DT(5,3,1)rec[-3]_rec[-27];DT(0,2,1)rec[-2]_rec[-26];DT(0,4,1)rec[-1]_rec[-25];TICK;R_9_11_17_19_21_29_31_37_39_41_7_27;RX_8_10_18_20_28_30_38_40_47_48_0_1;MARKZ(2)29;TICK;CX_8_2_3_9_10_4_5_11_12_17_18_13_14_19_20_15_16_21_28_22_23_29_30_24_25_31_32_37_38_33_34_39_40_35_36_41_47_42_48_44;TICK;CX_13_9_15_11_22_17_24_19_26_21_33_29_35_31_42_37_44_39_46_41_8_3_10_5_18_14_20_16_28_23_30_25_38_34_40_36_47_43_48_45;TICK;CX_4_9_6_11_13_17_15_19_24_29_26_31_33_37_35_39_2_7_22_27_8_12_10_14_1_5_0_3_18_23_20_25_28_32_30_34_38_43_40_45;TICK;CX_8_13_14_9_10_15_16_11_23_17_18_24_25_19_20_26_28_33_34_29_30_35_36_31_43_37_38_44_45_39)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_40_46_0_4_1_6_12_7_32_27;TICK;M_9_11_17_19_21_29_31_37_39_41_7_27;MX_8_10_18_20_28_30_38_40_47_48_0_1;MARKZ(2)29;DT(1,2,2)rec[-24]_rec[-48];DT(1,4,2)rec[-23]_rec[-47];DT(2,1,2)rec[-22]_rec[-46];DT(2,3,2)rec[-21]_rec[-45];DT(2,5,2)rec[-20]_rec[-44];DT(3,2,2)rec[-19]_rec[-43];DT(3,4,2)rec[-18]_rec[-42];DT(4,1,2)rec[-17]_rec[-41];DT(4,3,2)rec[-16]_rec[-40];DT(4,5,2)rec[-15]_rec[-39];DT(1,0,2)rec[-14]_rec[-38];DT(3,0,2)rec[-13]_rec[-37];DT(1,1,2)rec[-12]_rec[-36];DT(1,3,2)rec[-11]_rec[-35];DT(2,2,2)rec[-10]_rec[-34];DT(2,4,2)rec[-9]_rec[-33];DT(3,1,2)rec[-8]_rec[-32];DT(3,3,2)rec[-7]_rec[-31];DT(4,2,2)rec[-6]_rec[-30];DT(4,4,2)rec[-5]_rec[-29];DT(5,1,2)rec[-4]_rec[-28];DT(5,3,2)rec[-3]_rec[-27];DT(0,2,2)rec[-2]_rec[-26];DT(0,4,2)rec[-1]_rec[-25];TICK;M_2_3_4_5_6_12_13_14_15_16_22_23_24_25_26_32_33_34_35_36_42_43_44_45_46;MARKZ(0)2_3_4_5_6;DT(1,0,3)rec[-20]_rec[-25]_rec[-39];DT(1,2,3)rec[-18]_rec[-19]_rec[-23]_rec[-24]_rec[-49];DT(1,4,3)rec[-16]_rec[-17]_rec[-21]_rec[-22]_rec[-48];DT(2,1,3)rec[-14]_rec[-15]_rec[-)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(19]_rec[-20]_rec[-47];DT(2,3,3)rec[-12]_rec[-13]_rec[-17]_rec[-18]_rec[-46];DT(2,5,3)rec[-11]_rec[-16]_rec[-45];DT(3,0,3)rec[-10]_rec[-15]_rec[-38];DT(3,2,3)rec[-8]_rec[-9]_rec[-13]_rec[-14]_rec[-44];DT(3,4,3)rec[-6]_rec[-7]_rec[-11]_rec[-12]_rec[-43];DT(4,1,3)rec[-4]_rec[-5]_rec[-9]_rec[-10]_rec[-42];DT(4,3,3)rec[-2]_rec[-3]_rec[-7]_rec[-8]_rec[-41];DT(4,5,3)rec[-1]_rec[-6]_rec[-40];OI(0)rec[-21]_rec[-22]_rec[-23]_rec[-24]_rec[-25]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Surface Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>3-Coupler</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Memory (V)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>5x5x4</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,2)2;Q(0,3)3;Q(0,4)4;Q(0.5,0.5)5;Q(0.5,1.5)6;Q(0.5,2.5)7;Q(0.5,3.5)8;Q(0.5,4.5)9;Q(1,0)10;Q(1,1)11;Q(1,2)12;Q(1,3)13;Q(1,4)14;Q(1.5,0.5)15;Q(1.5,1.5)16;Q(1.5,2.5)17;Q(1.5,3.5)18;Q(1.5,4.5)19;Q(2,0)20;Q(2,1)21;Q(2,2)22;Q(2,3)23;Q(2,4)24;Q(2.5,0.5)25;Q(2.5,1.5)26;Q(2.5,2.5)27;Q(2.5,3.5)28;Q(2.5,4.5)29;Q(3,0)30;Q(3,1)31;Q(3,2)32;Q(3,3)33;Q(3,4)34;Q(3.5,0.5)35;Q(3.5,1.5)36;Q(3.5,2.5)37;Q(3.5,3.5)38;Q(3.5,4.5)39;Q(4,0)40;Q(4,1)41;Q(4,2)42;Q(4,3)43;Q(4,4)44;Q(4.5,0.5)45;Q(4.5,1.5)46;Q(4.5,2.5)47;Q(4.5,3.5)48;POLYGON(0,0,1,0.25)27_22_26_32;POLYGON(0,0,1,0.25)17_12_16_22;POLYGON(0,0,1,0.25)16_11_15_21;POLYGON(0,0,1,0.25)7_2_6_12;POLYGON(0,0,1,0.25)6_1_5_11;POLYGON(0,0,1,0.25)35_30_40;POLYGON(0,0,1,0.25)25_20_30;POLYGON(0,0,1,0.25)15_10_20;POLYGON(0,0,1,0.25)5_0_10;POLYGON(0,0,1,0.25)26_21_25_31;POLYGON(0,0,1,0.25)37_32_36_42;POLYGON(0,0,1,0.25)36_31_35_41;POLYGON(0,0,1,0.25)28_23_27_33;POLYGON(0,0,1,0.25)18_13_17_23;POLYGON(0,0,1,0.25)9_4_8_14;POLYGON(0,0,1,)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(0.25)8_3_7_13;POLYGON(0,0,1,0.25)38_33_37_43;POLYGON(0,0,1,0.25)9;POLYGON(0,0,1,0.25)19_14_18_24;POLYGON(0,0,1,0.25)19;POLYGON(0,0,1,0.25)29_24_28_34;POLYGON(0,0,1,0.25)29;POLYGON(0,0,1,0.25)39_34_38_44;POLYGON(0,0,1,0.25)39;POLYGON(1,0,0,0.25)12_6_11_16;POLYGON(1,0,0,0.25)22_16_21_26;POLYGON(1,0,0,0.25)13_7_12_17;POLYGON(1,0,0,0.25)23_17_22_27;POLYGON(1,0,0,0.25)33_27_32_37;POLYGON(1,0,0,0.25)3_2_7;POLYGON(1,0,0,0.25)2_1_6;POLYGON(1,0,0,0.25)1_0_5;POLYGON(1,0,0,0.25)21_15_20_25;POLYGON(1,0,0,0.25)11_5_10_15;POLYGON(1,0,0,0.25)32_26_31_36;POLYGON(1,0,0,0.25)31_25_30_35;POLYGON(1,0,0,0.25)48;POLYGON(1,0,0,0.25)43_37_42_47;POLYGON(1,0,0,0.25)47;POLYGON(1,0,0,0.25)42_36_41_46;POLYGON(1,0,0,0.25)46;POLYGON(1,0,0,0.25)41_35_40_45;POLYGON(1,0,0,0.25)45;POLYGON(1,0,0,0.25)14_8_13_18;POLYGON(1,0,0,0.25)24_18_23_28;POLYGON(1,0,0,0.25)34_28_33_38;POLYGON(1,0,0,0.25)4_3_8;POLYGON(1,0,0,0.25)44_38_43_48;TICK;R_0_1_2_3_4_10_11_12_13_14_20_21_22_23_24_30_31_32_33_34_40_41_42_43_44;TICK;R_37_35_28_26_17_15_8_6_9_19_29_39;RX)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_38_36_27_25_18_16_7_5_45_46_47_48;MARKX(1)27;MARKZ(0)17;TICK;CX_38_33_32_37_36_31_30_35_23_28_27_22_21_26_25_20_18_13_12_17_16_11_10_15_3_8_7_2_1_6_5_0_45_40_47_42_43_48_41_46_9_4_14_19_29_24_34_39;TICK;CX_42_37_40_35_33_28_31_26_22_17_20_15_13_8_11_6_38_34_36_32_27_23_25_21_18_14_16_12_7_3_5_1_47_43_45_41_24_19_44_39;TICK;CX_21_16_26_22_32_27_37_33_43_38_10_5_15_11_23_18_28_24_17_13_6_2_12_7_8_4_41_36_35_31_30_25_46_42_48_44_14_9_34_29;TICK;CX_26_21_17_12_2_7_22_27_33_38_37_32_15_10_0_5_6_1_28_23_13_18_8_3_31_36_11_16_20_25_35_30_46_41_48_43_42_47_40_45_19_14_39_34_24_29_4_9;TICK;M_38_36_27_25_18_16_7_5_9_19_29_39;MX_37_35_28_26_17_15_8_6_45_46_47_48;MARKX(1)17;MARKZ(0)16;DT(3.5,3.5,0)rec[-24];DT(3.5,1.5,0)rec[-23];DT(2.5,2.5,0)rec[-22];DT(2.5,0.5,0)rec[-21];DT(1.5,3.5,0)rec[-20];DT(1.5,1.5,0)rec[-19];DT(0.5,2.5,0)rec[-18];DT(0.5,0.5,0)rec[-17];DT(0.5,4.5,0)rec[-16];DT(1.5,4.5,0)rec[-15];DT(2.5,4.5,0)rec[-14];DT(3.5,4.5,0)rec[-13];TICK;R_38_36_27_25_18_16_7_5_9_19_29_39;RX_37_35_28_26_17_15_8_6_45_46_47_48;)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(MARKX(1)17;MARKX(3)26;MARKZ(0)16;MARKZ(2)27;TICK;CX_26_21_17_12_2_7_22_27_33_38_37_32_15_10_0_5_6_1_28_23_13_18_8_3_31_36_11_16_20_25_35_30_46_41_48_43_42_47_40_45_39_34_24_29_19_14_4_9;TICK;CX_21_16_26_22_32_27_37_33_43_38_10_5_15_11_23_18_28_24_17_13_6_2_12_7_8_4_41_36_35_31_30_25_46_42_48_44_14_9_34_29;TICK;CX_42_37_40_35_33_28_31_26_22_17_20_15_13_8_11_6_38_34_36_32_27_23_25_21_18_14_16_12_7_3_5_1_47_43_45_41_24_19_44_39;TICK;CX_38_33_32_37_36_31_30_35_23_28_27_22_21_26_25_20_18_13_12_17_16_11_10_15_3_8_7_2_1_6_5_0_45_40_47_42_43_48_41_46_14_19_34_39_29_24_9_4;TICK;M_37_35_28_26_17_15_8_6_9_19_29_39;MX_38_36_27_25_18_16_7_5_45_46_47_48;MARKX(1)27;MARKX(3)16;MARKZ(0)17;MARKZ(2)26;DT(3.5,1.5,1)rec[-24]_rec[-47];DT(3.5,0.5,1)rec[-23];DT(2.5,2.5,1)rec[-22]_rec[-46];DT(2.5,0.5,1)rec[-21]_rec[-45];DT(1.5,1.5,1)rec[-20]_rec[-43];DT(1.5,0.5,1)rec[-19];DT(0.5,2.5,1)rec[-18]_rec[-42];DT(0.5,0.5,1)rec[-17]_rec[-41];DT(1.5,4.5,1)rec[-16]_rec[-39]_rec[-40];DT(1.5,3.5,1)rec[-15]_rec[-44];DT(3.5,4.5,1)rec[-14]_rec[-37]_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(rec[-38];DT(3.5,3.5,1)rec[-13]_rec[-48];DT(2.5,3.5,1)rec[-12]_rec[-34];DT(2.5,1.5,1)rec[-11]_rec[-33];DT(1.5,2.5,1)rec[-10]_rec[-32];DT(2,0.5,1)rec[-9]_rec[-31];DT(0.5,3.5,1)rec[-8]_rec[-30];DT(0.5,1.5,1)rec[-7]_rec[-29];DT(0.5,2.5,2)rec[-6];DT(0.5,0.5,2)rec[-5];DT(4.5,0.5,1)rec[-4]_rec[-35];DT(4.5,2.5,1)rec[-3]_rec[-26]_rec[-27];DT(3.5,2.5,1)rec[-2]_rec[-36];DT(4.5,3.5,1)rec[-1]_rec[-25];TICK;R_37_35_28_26_17_15_8_6_9_19_29_39;RX_38_36_27_25_18_16_7_5_45_46_47_48;MARKX(3)16;MARKZ(2)26;TICK;CX_38_33_32_37_36_31_30_35_23_28_27_22_21_26_25_20_18_13_12_17_16_11_10_15_3_8_7_2_1_6_5_0_45_40_47_42_43_48_41_46_9_4_14_19_29_24_34_39;TICK;CX_42_37_40_35_33_28_31_26_22_17_20_15_13_8_11_6_38_34_36_32_27_23_25_21_18_14_16_12_7_3_5_1_47_43_45_41_24_19_44_39;TICK;CX_21_16_26_22_32_27_37_33_43_38_10_5_15_11_23_18_28_24_17_13_6_2_12_7_8_4_41_36_35_31_30_25_46_42_48_44_14_9_34_29;TICK;CX_26_21_17_12_2_7_22_27_33_38_37_32_15_10_0_5_6_1_28_23_13_18_8_3_31_36_11_16_20_25_35_30_46_41_48_43_42_47_40_45_19_14_39_34_24_29_4_9;TICK;M)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_38_36_27_25_18_16_7_5_9_19_29_39;MX_37_35_28_26_17_15_8_6_45_46_47_48;MARKX(3)26;MARKZ(2)27;DT(3.5,2.5,3)rec[-24]_rec[-48];DT(3.5,0.5,3)rec[-23]_rec[-47];DT(2.5,1.5,3)rec[-22]_rec[-45];DT(2.5,0.5,3)rec[-21];DT(1.5,2.5,3)rec[-20]_rec[-44];DT(1.5,0.5,3)rec[-19]_rec[-43];DT(0.5,1.5,3)rec[-18]_rec[-41];DT(0.5,0.5,3)rec[-17];DT(0.5,3.5,3)rec[-16]_rec[-42];DT(2.5,4.5,3)rec[-15]_rec[-38]_rec[-39];DT(2.5,3.5,3)rec[-14]_rec[-46];DT(3.5,4.5,3)rec[-13]_rec[-37];DT(2.5,2.5,3)rec[-12]_rec[-34];DT(3,0.5,3)rec[-11]_rec[-33];DT(1.5,3.5,3)rec[-10]_rec[-32];DT(1.5,1.5,3)rec[-9]_rec[-31];DT(0.5,2.5,3)rec[-8]_rec[-30];DT(1,0.5,3)rec[-7]_rec[-29];DT(0.5,3.5,4)rec[-6];DT(0.5,1.5,4)rec[-5];DT(4.5,1.5,3)rec[-4]_rec[-27]_rec[-28];DT(3.5,1.5,3)rec[-3]_rec[-35];DT(4.5,3.5,3)rec[-2]_rec[-25]_rec[-26];DT(3.5,3.5,3)rec[-1]_rec[-36];TICK;R_38_36_27_25_18_16_7_5_9_19_29_39;RX_37_35_28_26_17_15_8_6_45_46_47_48;TICK;CX_26_21_17_12_2_7_22_27_33_38_37_32_15_10_0_5_6_1_28_23_13_18_8_3_31_36_11_16_20_25_35_30_46_41_48_43_42_47_40_45_39_34_24_29_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(19_14_4_9;TICK;CX_21_16_26_22_32_27_37_33_43_38_10_5_15_11_23_18_28_24_17_13_6_2_12_7_8_4_41_36_35_31_30_25_46_42_48_44_14_9_34_29;TICK;CX_42_37_40_35_33_28_31_26_22_17_20_15_13_8_11_6_38_34_36_32_27_23_25_21_18_14_16_12_7_3_5_1_47_43_45_41_24_19_44_39;TICK;CX_38_33_32_37_36_31_30_35_23_28_27_22_21_26_25_20_18_13_12_17_16_11_10_15_3_8_7_2_1_6_5_0_45_40_47_42_43_48_41_46_14_19_34_39_29_24_9_4;TICK;M_37_35_28_26_17_15_8_6_9_19_29_39;MX_38_36_27_25_18_16_7_5_45_46_47_48;DT(3.5,1.5,5)rec[-24]_rec[-47];DT(3.5,0.5,5)rec[-23];DT(2.5,2.5,5)rec[-22]_rec[-46];DT(2.5,0.5,5)rec[-21]_rec[-45];DT(1.5,1.5,5)rec[-20]_rec[-43];DT(1.5,0.5,5)rec[-19];DT(0.5,2.5,5)rec[-18]_rec[-42];DT(0.5,0.5,5)rec[-17]_rec[-41];DT(1.5,4.5,5)rec[-16]_rec[-39]_rec[-40];DT(1.5,3.5,5)rec[-15]_rec[-44];DT(3.5,4.5,5)rec[-14]_rec[-37]_rec[-38];DT(3.5,3.5,5)rec[-13]_rec[-48];DT(2.5,3.5,5)rec[-12]_rec[-34];DT(2.5,1.5,5)rec[-11]_rec[-33];DT(1.5,2.5,5)rec[-10]_rec[-32];DT(2,0.5,5)rec[-9]_rec[-31];DT(0.5,3.5,5)rec[-8]_rec[-30];DT(0.5,1.5,5)rec[-7]_rec[-29])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;DT(0.5,2.5,6)rec[-6];DT(0.5,0.5,6)rec[-5];DT(4.5,0.5,5)rec[-4]_rec[-35];DT(4.5,2.5,5)rec[-3]_rec[-26]_rec[-27];DT(3.5,2.5,5)rec[-2]_rec[-36];DT(4.5,3.5,5)rec[-1]_rec[-25];TICK;M_0_1_2_3_4_10_11_12_13_14_20_21_22_23_24_30_31_32_33_34_40_41_42_43_44;DT(1,0,7)rec[-20]_rec[-25];DT(0.5,1.5,7)rec[-18]_rec[-19]_rec[-23]_rec[-24]_rec[-42];DT(0.5,3.5,7)rec[-16]_rec[-17]_rec[-21]_rec[-22]_rec[-43];DT(1.5,0.5,7)rec[-14]_rec[-15]_rec[-19]_rec[-20]_rec[-44];DT(1.5,2.5,7)rec[-12]_rec[-13]_rec[-17]_rec[-18]_rec[-45];DT(2.5,4.5,7)rec[-11]_rec[-16]_rec[-39]_rec[-40];DT(3,0,7)rec[-10]_rec[-15];DT(2.5,1.5,7)rec[-8]_rec[-9]_rec[-13]_rec[-14]_rec[-46];DT(2.5,3.5,7)rec[-6]_rec[-7]_rec[-11]_rec[-12]_rec[-47];DT(3.5,0.5,7)rec[-4]_rec[-5]_rec[-9]_rec[-10]_rec[-48];DT(3.5,2.5,7)rec[-2]_rec[-3]_rec[-7]_rec[-8]_rec[-49];DT(3.5,4.5,7)rec[-1]_rec[-6]_rec[-38];OI(0)rec[-21]_rec[-22]_rec[-23]_rec[-24]_rec[-25]_rec[-41]_rec[-89]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Surface Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Biased (XZZX)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Memory (V)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>5x5x3</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,2)0;Q(0,4)1;Q(0.5,0.5)2;Q(0.5,1.5)3;Q(0.5,2.5)4;Q(0.5,3.5)5;Q(0.5,4.5)6;Q(1,0)7;Q(1,1)8;Q(1,2)9;Q(1,3)10;Q(1,4)11;Q(1.5,0.5)12;Q(1.5,1.5)13;Q(1.5,2.5)14;Q(1.5,3.5)15;Q(1.5,4.5)16;Q(2,1)17;Q(2,2)18;Q(2,3)19;Q(2,4)20;Q(2,5)21;Q(2.5,0.5)22;Q(2.5,1.5)23;Q(2.5,2.5)24;Q(2.5,3.5)25;Q(2.5,4.5)26;Q(3,0)27;Q(3,1)28;Q(3,2)29;Q(3,3)30;Q(3,4)31;Q(3.5,0.5)32;Q(3.5,1.5)33;Q(3.5,2.5)34;Q(3.5,3.5)35;Q(3.5,4.5)36;Q(4,1)37;Q(4,2)38;Q(4,3)39;Q(4,4)40;Q(4,5)41;Q(4.5,0.5)42;Q(4.5,1.5)43;Q(4.5,2.5)44;Q(4.5,3.5)45;Q(4.5,4.5)46;Q(5,1)47;Q(5,3)48;POLYGON(0,0,1,0.25)12_22_23_13;POLYGON(0,0,1,0.25)3_13_14_4;POLYGON(0,0,1,0.25)14_24_25_15;POLYGON(0,0,1,0.25)5_15_16_6;POLYGON(0,0,1,0.25)34_44_45_35;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)32_42_43_33;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)12_2;POLYGON(0,0,1,0.25)32_22;POLYGON(0,0,1,0.25)46_36;POLYGON(0,0,1,0.25)26_16;POLYGON(1,0,0,0.25)2_12_13_3;POLYGON(1,0,0,0.25)13_23_24_14;POLYGON(1,0,0,0.25)4_14_15_5;POLYGON(1,0,0,0.25)1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(5_25_26_16;POLYGON(1,0,0,0.25)24_34_35_25;POLYGON(1,0,0,0.25)35_45_46_36;POLYGON(1,0,0,0.25)22_32_33_23;POLYGON(1,0,0,0.25)33_43_44_34;POLYGON(1,0,0,0.25)42_43;POLYGON(1,0,0,0.25)44_45;POLYGON(1,0,0,0.25)5_6;POLYGON(1,0,0,0.25)3_4;TICK;R_2_4_6_13_15_22_24_26_33_35_42_44_46;RX_12_3_14_5_16_25_36_45_34_23_43_32;MARKX(1)14_25;MARKZ(1)15_24;TICK;RX_9_11_17_19_21_29_31_37_39_41_27_7_10_18_8_28_38_48_47_30_40_20_0_1;MARKX(0)8;MARKX(1)19;TICK;CX_9_3_17_12_19_14_21_16_29_23_31_25_37_32_39_34_41_36_48_44_47_42_40_35_38_33_28_22_30_24_20_15_18_13_8_2_11_5_10_4;TICK;CZ_19_24_29_33_9_13_11_15_21_26_17_22_31_35_41_46_39_44_37_42_43_47_45_48_36_40_34_38_25_30_23_28_16_20_14_18_5_10_3_8;TICK;CZ_24_29_33_37_2_7_4_9_6_11_15_19_13_17_26_31_22_27_35_39_40_45_38_43_30_34_28_32_20_25_18_23_10_14_8_12_0_3_1_5;TICK;CX_9_14_11_16_17_23_19_25_29_34_31_36_37_43_39_45_7_12_27_32_40_46_38_44_30_35_28_33_20_26_18_24_8_13_10_15_1_6_0_4;TICK;MX_9_11_17_19_21_29_31_37_39_41_27_7_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(0)8;MARKX(1)19;DT(1,2,0)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART()rec[-24];DT(1,4,0)rec[-23];DT(2,1,0)rec[-22];DT(2,3,0)rec[-21];DT(2,5,0)rec[-20];DT(3,2,0)rec[-19];DT(3,4,0)rec[-18];DT(4,1,0)rec[-17];DT(4,3,0)rec[-16];DT(4,5,0)rec[-15];DT(3,0,0)rec[-14];DT(1,0,0)rec[-13];TICK;RX_9_11_17_19_21_29_31_37_39_41_27_7_10_18_8_28_38_48_47_30_40_20_0_1;MARKX(0)8;TICK;CX_9_3_17_12_19_14_21_16_29_23_31_25_37_32_39_34_41_36_48_44_47_42_40_35_38_33_28_22_30_24_20_15_18_13_8_2_11_5_10_4;TICK;CZ_19_24_29_33_9_13_11_15_21_26_17_22_31_35_41_46_39_44_37_42_43_47_45_48_36_40_34_38_25_30_23_28_16_20_14_18_5_10_3_8;TICK;CZ_24_29_33_37_2_7_4_9_6_11_15_19_13_17_26_31_22_27_35_39_40_45_38_43_30_34_28_32_20_25_18_23_10_14_8_12_0_3_1_5;TICK;CX_9_14_11_16_17_23_19_25_29_34_31_36_37_43_39_45_7_12_27_32_40_46_38_44_30_35_28_33_20_26_18_24_8_13_10_15_1_6_0_4;TICK;MX_9_11_17_19_21_29_31_37_39_41_7_27_8_10_18_20_28_30_38_40_47_48_0_1;MARKX(0)8;DT(1,2,1)rec[-24]_rec[-48];DT(1,4,1)rec[-23]_rec[-47];DT(2,1,1)rec[-22]_rec[-46];DT(2,3,1)rec[-21]_rec[-45];DT(2,5,1)rec[-20]_rec[-44];DT(3,2,1)rec[-19]_rec[-43])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;DT(3,4,1)rec[-18]_rec[-42];DT(4,1,1)rec[-17]_rec[-41];DT(4,3,1)rec[-16]_rec[-40];DT(4,5,1)rec[-15]_rec[-39];DT(1,0,1)rec[-14]_rec[-37];DT(3,0,1)rec[-13]_rec[-38];DT(1,1,1)rec[-12]_rec[-36];DT(1,3,1)rec[-11]_rec[-35];DT(2,2,1)rec[-10]_rec[-34];DT(2,4,1)rec[-9]_rec[-33];DT(3,1,1)rec[-8]_rec[-32];DT(3,3,1)rec[-7]_rec[-31];DT(4,2,1)rec[-6]_rec[-30];DT(4,4,1)rec[-5]_rec[-29];DT(5,1,1)rec[-4]_rec[-28];DT(5,3,1)rec[-3]_rec[-27];DT(0,2,1)rec[-2]_rec[-26];DT(0,4,1)rec[-1]_rec[-25];TICK;RX_9_11_17_19_21_29_31_37_39_41_27_7_10_18_8_28_38_48_47_30_40_20_0_1;TICK;CX_9_3_17_12_19_14_21_16_29_23_31_25_37_32_39_34_41_36_48_44_47_42_40_35_38_33_28_22_30_24_20_15_18_13_8_2_11_5_10_4;TICK;CZ_19_24_29_33_9_13_11_15_21_26_17_22_31_35_41_46_39_44_37_42_43_47_45_48_36_40_34_38_25_30_23_28_16_20_14_18_5_10_3_8;TICK;CZ_24_29_33_37_2_7_4_9_6_11_15_19_13_17_26_31_22_27_35_39_40_45_38_43_30_34_28_32_20_25_18_23_10_14_8_12_0_3_1_5;TICK;CX_9_14_11_16_17_23_19_25_29_34_31_36_37_43_39_45_7_12_27_32_40_46_38_44_30_35_28_33_20_26_18_24_8_13_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(10_15_1_6_0_4;TICK;MX_9_11_17_19_21_29_31_37_39_41_7_27_8_10_18_20_28_30_38_40_47_48_0_1;DT(1,2,2)rec[-24]_rec[-48];DT(1,4,2)rec[-23]_rec[-47];DT(2,1,2)rec[-22]_rec[-46];DT(2,3,2)rec[-21]_rec[-45];DT(2,5,2)rec[-20]_rec[-44];DT(3,2,2)rec[-19]_rec[-43];DT(3,4,2)rec[-18]_rec[-42];DT(4,1,2)rec[-17]_rec[-41];DT(4,3,2)rec[-16]_rec[-40];DT(4,5,2)rec[-15]_rec[-39];DT(3,0,2)rec[-14]_rec[-37];DT(1,0,2)rec[-13]_rec[-38];DT(1,1,2)rec[-12]_rec[-36];DT(1,3,2)rec[-11]_rec[-35];DT(2,2,2)rec[-10]_rec[-34];DT(2,4,2)rec[-9]_rec[-33];DT(3,1,2)rec[-8]_rec[-32];DT(3,3,2)rec[-7]_rec[-31];DT(4,2,2)rec[-6]_rec[-30];DT(4,4,2)rec[-5]_rec[-29];DT(5,1,2)rec[-4]_rec[-28];DT(5,3,2)rec[-3]_rec[-27];DT(0,2,2)rec[-2]_rec[-26];DT(0,4,2)rec[-1]_rec[-25];TICK;M_2_4_6_13_15_22_24_26_33_35_42_44_46;MX_3_5_12_14_16_23_25_32_34_36_43_45;DT(1,0,3)rec[-10]_rec[-25]_rec[-39];DT(1,2,3)rec[-9]_rec[-12]_rec[-22]_rec[-24]_rec[-49];DT(1,4,3)rec[-8]_rec[-11]_rec[-21]_rec[-23]_rec[-48];DT(2,5,3)rec[-8]_rec[-18]_rec[-45];DT(2,1,3)rec[-7]_rec[-10]_rec[-20]_rec[)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(-22]_rec[-47];DT(2,3,3)rec[-6]_rec[-9]_rec[-19]_rec[-21]_rec[-46];DT(3,0,3)rec[-5]_rec[-20]_rec[-38];DT(3,2,3)rec[-4]_rec[-7]_rec[-17]_rec[-19]_rec[-44];DT(3,4,3)rec[-3]_rec[-6]_rec[-16]_rec[-18]_rec[-43];DT(4,5,3)rec[-3]_rec[-13]_rec[-40];DT(4,1,3)rec[-2]_rec[-5]_rec[-15]_rec[-17]_rec[-42];DT(4,3,3)rec[-1]_rec[-4]_rec[-14]_rec[-16]_rec[-41];OI(0)rec[-11]_rec[-12]_rec[-23]_rec[-24]_rec[-25]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Toric Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Standard (ZZ)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Memory (ZH+ZV)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>6x6x3</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,0)0;Q(0,1)1;Q(0,2)2;Q(0,3)3;Q(0,4)4;Q(0,5)5;Q(0,6)6;Q(0.5,0.5)7;Q(0.5,1.5)8;Q(0.5,2.5)9;Q(0.5,3.5)10;Q(0.5,4.5)11;Q(0.5,5.5)12;Q(1,0)13;Q(1,1)14;Q(1,2)15;Q(1,3)16;Q(1,4)17;Q(1,5)18;Q(1,6)19;Q(1.5,0.5)20;Q(1.5,1.5)21;Q(1.5,2.5)22;Q(1.5,3.5)23;Q(1.5,4.5)24;Q(1.5,5.5)25;Q(2,0)26;Q(2,1)27;Q(2,2)28;Q(2,3)29;Q(2,4)30;Q(2,5)31;Q(2,6)32;Q(2.5,0.5)33;Q(2.5,1.5)34;Q(2.5,2.5)35;Q(2.5,3.5)36;Q(2.5,4.5)37;Q(2.5,5.5)38;Q(3,0)39;Q(3,1)40;Q(3,2)41;Q(3,3)42;Q(3,4)43;Q(3,5)44;Q(3,6)45;Q(3.5,0.5)46;Q(3.5,1.5)47;Q(3.5,2.5)48;Q(3.5,3.5)49;Q(3.5,4.5)50;Q(3.5,5.5)51;Q(4,0)52;Q(4,1)53;Q(4,2)54;Q(4,3)55;Q(4,4)56;Q(4,5)57;Q(4,6)58;Q(4.5,0.5)59;Q(4.5,1.5)60;Q(4.5,2.5)61;Q(4.5,3.5)62;Q(4.5,4.5)63;Q(4.5,5.5)64;Q(5,0)65;Q(5,1)66;Q(5,2)67;Q(5,3)68;Q(5,4)69;Q(5,5)70;Q(5,6)71;Q(5.5,0.5)72;Q(5.5,1.5)73;Q(5.5,2.5)74;Q(5.5,3.5)75;Q(5.5,4.5)76;Q(5.5,5.5)77;Q(6,0)78;Q(6,1)79;Q(6,2)80;Q(6,3)81;Q(6,4)82;Q(6,5)83;Q(6,6)84;POLYGON(0,0,1,0.25)13_26_27_14;POLYGON(0,0,1,0.25)1_14_15_2;POLYGON(0,0,1,0.25)15_28)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_29_16;POLYGON(0,0,1,0.25)3_16_17_4;POLYGON(0,0,1,0.25)41_54_55_42;POLYGON(0,0,1,0.25)29_42_43_30;POLYGON(0,0,1,0.25)39_52_53_40;POLYGON(0,0,1,0.25)27_40_41_28;POLYGON(0,0,1,0.25)65_78_79_66;POLYGON(0,0,1,0.25)53_66_67_54;POLYGON(0,0,1,0.25)67_80_81_68;POLYGON(0,0,1,0.25)55_68_69_56;POLYGON(0,0,1,0.25)69_82_83_70;POLYGON(0,0,1,0.25)57_70_71_58;POLYGON(0,0,1,0.25)43_56_57_44;POLYGON(0,0,1,0.25)31_44_45_32;POLYGON(0,0,1,0.25)17_30_31_18;POLYGON(0,0,1,0.25)5_18_19_6;POLYGON(1,0,0,0.25)0_13_14_1;POLYGON(1,0,0,0.25)14_27_28_15;POLYGON(1,0,0,0.25)2_15_16_3;POLYGON(1,0,0,0.25)16_29_30_17;POLYGON(1,0,0,0.25)28_41_42_29;POLYGON(1,0,0,0.25)42_55_56_43;POLYGON(1,0,0,0.25)26_39_40_27;POLYGON(1,0,0,0.25)40_53_54_41;POLYGON(1,0,0,0.25)52_65_66_53;POLYGON(1,0,0,0.25)66_79_80_67;POLYGON(1,0,0,0.25)54_67_68_55;POLYGON(1,0,0,0.25)68_81_82_69;POLYGON(1,0,0,0.25)56_69_70_57;POLYGON(1,0,0,0.25)70_83_84_71;POLYGON(1,0,0,0.25)30_43_44_31;POLYGON(1,0,0,0.25)44_57_58_45;POLYGON(1,0,0,0.25)4_17_18_5;POLYGON(1,0,0,0.25)18_31_32_19;TICK)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;R_0_1_2_3_4_5_13_14_15_16_17_18_26_27_28_29_30_31_39_40_41_42_43_44_52_53_54_55_56_57_65_66_67_68_69_70;MARKZ(0)39_40_41_42_43_44;TICK;R_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;RX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKZ(1)60;TICK;CX_7_0_1_8_9_2_3_10_11_4_5_12_13_20_21_14_15_22_23_16_17_24_25_18_33_26_27_34_35_28_29_36_37_30_31_38_39_46_47_40_41_48_49_42_43_50_51_44_59_52_53_60_61_54_55_62_63_56_57_64_65_72_73_66_67_74_75_68_69_76_77_70;TICK;CX_7_13_14_8_9_15_16_10_11_17_18_12_26_20_21_27_28_22_23_29_30_24_25_31_33_39_40_34_35_41_42_36_37_43_44_38_52_46_47_53_54_48_49_55_56_50_51_57_59_65_66_60_61_67_68_62_63_69_70_64_0_72_2_74_4_76_73_1_75_3_77_5;TICK;CX_7_1_2_8_9_3_4_10_11_5_14_20_21_15_16_22_23_17_18_24_33_27_28_34_35_29_30_36_37_31_40_46_47_41_42_48_49_43_44_50_59_53_54_60_61_55_56_62_63_57_66_72_73_67_68_74_75_69_70_76_0_12_26_38_52_64_25_13_51_39_77_65;TICK;CX_7_14_15_8_9_16_17_10_11_18_27_20_21_28_29_22_23_30_31_24_33_40_41_34_35_42_43_36_37_44_53_46_47_54_55_48_49_56_57_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(50_59_66_67_60_61_68_69_62_63_70_13_12_39_38_65_64_25_26_51_52_1_72_3_74_5_76_73_2_75_4_77_0;TICK;M_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;MX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKZ(1)60;DT(0.5,1.5,0)rec[-36];DT(0.5,3.5,0)rec[-35];DT(0.5,5.5,0)rec[-34];DT(1.5,0.5,0)rec[-33];DT(1.5,2.5,0)rec[-32];DT(1.5,4.5,0)rec[-31];DT(2.5,1.5,0)rec[-30];DT(2.5,3.5,0)rec[-29];DT(2.5,5.5,0)rec[-28];DT(3.5,0.5,0)rec[-27];DT(3.5,2.5,0)rec[-26];DT(3.5,4.5,0)rec[-25];DT(4.5,1.5,0)rec[-24];DT(4.5,3.5,0)rec[-23];DT(4.5,5.5,0)rec[-22];DT(5.5,0.5,0)rec[-21];DT(5.5,2.5,0)rec[-20];DT(5.5,4.5,0)rec[-19];TICK;R_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;RX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKX(2)25;MARKZ(1)60;TICK;CX_7_0_1_8_9_2_3_10_11_4_5_12_13_20_21_14_15_22_23_16_17_24_25_18_33_26_27_34_35_28_29_36_37_30_31_38_39_46_47_40_41_48_49_42_43_50_51_44_59_52_53_60_61_54_55_62_63_56_57_64_65_72_73_66_67_74_75_68_69_76_77_70;TICK;CX_7_13_14_8_9_15_16_10_11_17_18_12_26_20_21_27_28_2)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(2_23_29_30_24_25_31_33_39_40_34_35_41_42_36_37_43_44_38_52_46_47_53_54_48_49_55_56_50_51_57_59_65_66_60_61_67_68_62_63_69_70_64_0_72_2_74_4_76_73_1_75_3_77_5;TICK;CX_7_1_2_8_9_3_4_10_11_5_14_20_21_15_16_22_23_17_18_24_33_27_28_34_35_29_30_36_37_31_40_46_47_41_42_48_49_43_44_50_59_53_54_60_61_55_56_62_63_57_66_72_73_67_68_74_75_69_70_76_0_12_26_38_52_64_25_13_51_39_77_65;TICK;CX_7_14_15_8_9_16_17_10_11_18_27_20_21_28_29_22_23_30_31_24_33_40_41_34_35_42_43_36_37_44_53_46_47_54_55_48_49_56_57_50_59_66_67_60_61_68_69_62_63_70_13_12_39_38_65_64_25_26_51_52_1_72_3_74_5_76_73_2_75_4_77_0;TICK;M_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;MX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKX(2)25;MARKZ(1)60;DT(0.5,1.5,1)rec[-36]_rec[-72];DT(0.5,3.5,1)rec[-35]_rec[-71];DT(0.5,5.5,1)rec[-34]_rec[-70];DT(1.5,0.5,1)rec[-33]_rec[-69];DT(1.5,2.5,1)rec[-32]_rec[-68];DT(1.5,4.5,1)rec[-31]_rec[-67];DT(2.5,1.5,1)rec[-30]_rec[-66];DT(2.5,3.5,1)rec[-29]_rec[-65];DT(2.5,5.5,1)rec[-28]_rec[-64];DT(3.5,0.5,1)rec[-27)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(]_rec[-63];DT(3.5,2.5,1)rec[-26]_rec[-62];DT(3.5,4.5,1)rec[-25]_rec[-61];DT(4.5,1.5,1)rec[-24]_rec[-60];DT(4.5,3.5,1)rec[-23]_rec[-59];DT(4.5,5.5,1)rec[-22]_rec[-58];DT(5.5,0.5,1)rec[-21]_rec[-57];DT(5.5,2.5,1)rec[-20]_rec[-56];DT(5.5,4.5,1)rec[-19]_rec[-55];DT(0.5,0.5,1)rec[-18]_rec[-54];DT(0.5,2.5,1)rec[-17]_rec[-53];DT(0.5,4.5,1)rec[-16]_rec[-52];DT(1.5,1.5,1)rec[-15]_rec[-51];DT(1.5,3.5,1)rec[-14]_rec[-50];DT(1.5,5.5,1)rec[-13]_rec[-49];DT(2.5,0.5,1)rec[-12]_rec[-48];DT(2.5,2.5,1)rec[-11]_rec[-47];DT(2.5,4.5,1)rec[-10]_rec[-46];DT(3.5,1.5,1)rec[-9]_rec[-45];DT(3.5,3.5,1)rec[-8]_rec[-44];DT(3.5,5.5,1)rec[-7]_rec[-43];DT(4.5,0.5,1)rec[-6]_rec[-42];DT(4.5,2.5,1)rec[-5]_rec[-41];DT(4.5,4.5,1)rec[-4]_rec[-40];DT(5.5,1.5,1)rec[-3]_rec[-39];DT(5.5,3.5,1)rec[-2]_rec[-38];DT(5.5,5.5,1)rec[-1]_rec[-37];TICK;R_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;RX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKX(2)25;TICK;CX_7_0_1_8_9_2_3_10_11_4_5_12_13_20_21_14_15_22_23_16_17_24_25_18_33_26_27_34_35_28_2)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(9_36_37_30_31_38_39_46_47_40_41_48_49_42_43_50_51_44_59_52_53_60_61_54_55_62_63_56_57_64_65_72_73_66_67_74_75_68_69_76_77_70;TICK;CX_7_13_14_8_9_15_16_10_11_17_18_12_26_20_21_27_28_22_23_29_30_24_25_31_33_39_40_34_35_41_42_36_37_43_44_38_52_46_47_53_54_48_49_55_56_50_51_57_59_65_66_60_61_67_68_62_63_69_70_64_0_72_2_74_4_76_73_1_75_3_77_5;TICK;CX_7_1_2_8_9_3_4_10_11_5_14_20_21_15_16_22_23_17_18_24_33_27_28_34_35_29_30_36_37_31_40_46_47_41_42_48_49_43_44_50_59_53_54_60_61_55_56_62_63_57_66_72_73_67_68_74_75_69_70_76_0_12_26_38_52_64_25_13_51_39_77_65;TICK;CX_7_14_15_8_9_16_17_10_11_18_27_20_21_28_29_22_23_30_31_24_33_40_41_34_35_42_43_36_37_44_53_46_47_54_55_48_49_56_57_50_59_66_67_60_61_68_69_62_63_70_13_12_39_38_65_64_25_26_51_52_1_72_3_74_5_76_73_2_75_4_77_0;TICK;M_8_10_12_20_22_24_34_36_38_46_48_50_60_62_64_72_74_76;MX_7_9_11_21_23_25_33_35_37_47_49_51_59_61_63_73_75_77;MARKX(2)25;DT(0.5,1.5,2)rec[-36]_rec[-72];DT(0.5,3.5,2)rec[-35]_rec[-71];DT(0.5,5.5,2)rec[-34]_rec[-70];DT(1.5,0.5,2)rec[-33]_rec[-69];DT(1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(.5,2.5,2)rec[-32]_rec[-68];DT(1.5,4.5,2)rec[-31]_rec[-67];DT(2.5,1.5,2)rec[-30]_rec[-66];DT(2.5,3.5,2)rec[-29]_rec[-65];DT(2.5,5.5,2)rec[-28]_rec[-64];DT(3.5,0.5,2)rec[-27]_rec[-63];DT(3.5,2.5,2)rec[-26]_rec[-62];DT(3.5,4.5,2)rec[-25]_rec[-61];DT(4.5,1.5,2)rec[-24]_rec[-60];DT(4.5,3.5,2)rec[-23]_rec[-59];DT(4.5,5.5,2)rec[-22]_rec[-58];DT(5.5,0.5,2)rec[-21]_rec[-57];DT(5.5,2.5,2)rec[-20]_rec[-56];DT(5.5,4.5,2)rec[-19]_rec[-55];DT(0.5,0.5,2)rec[-18]_rec[-54];DT(0.5,2.5,2)rec[-17]_rec[-53];DT(0.5,4.5,2)rec[-16]_rec[-52];DT(1.5,1.5,2)rec[-15]_rec[-51];DT(1.5,3.5,2)rec[-14]_rec[-50];DT(1.5,5.5,2)rec[-13]_rec[-49];DT(2.5,0.5,2)rec[-12]_rec[-48];DT(2.5,2.5,2)rec[-11]_rec[-47];DT(2.5,4.5,2)rec[-10]_rec[-46];DT(3.5,1.5,2)rec[-9]_rec[-45];DT(3.5,3.5,2)rec[-8]_rec[-44];DT(3.5,5.5,2)rec[-7]_rec[-43];DT(4.5,0.5,2)rec[-6]_rec[-42];DT(4.5,2.5,2)rec[-5]_rec[-41];DT(4.5,4.5,2)rec[-4]_rec[-40];DT(5.5,1.5,2)rec[-3]_rec[-39];DT(5.5,3.5,2)rec[-2]_rec[-38];DT(5.5,5.5,2)rec[-1]_rec[-37];TICK;M_0_1_2_3_4_5_13_14_15_16_17_18_26_27_28)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_29_30_31_39_40_41_42_43_44_52_53_54_55_56_57_65_66_67_68_69_70;MARKZ(0)39_40_41_42_43_44;DT(0.5,1.5,3)rec[-28]_rec[-29]_rec[-34]_rec[-35]_rec[-72];DT(0.5,3.5,3)rec[-26]_rec[-27]_rec[-32]_rec[-33]_rec[-71];DT(0.5,5.5,3)rec[-25]_rec[-30]_rec[-31]_rec[-36]_rec[-70];DT(1.5,0.5,3)rec[-23]_rec[-24]_rec[-29]_rec[-30]_rec[-69];DT(1.5,2.5,3)rec[-21]_rec[-22]_rec[-27]_rec[-28]_rec[-68];DT(1.5,4.5,3)rec[-19]_rec[-20]_rec[-25]_rec[-26]_rec[-67];DT(2.5,1.5,3)rec[-16]_rec[-17]_rec[-22]_rec[-23]_rec[-66];DT(2.5,3.5,3)rec[-14]_rec[-15]_rec[-20]_rec[-21]_rec[-65];DT(2.5,5.5,3)rec[-13]_rec[-18]_rec[-19]_rec[-24]_rec[-64];DT(3.5,0.5,3)rec[-11]_rec[-12]_rec[-17]_rec[-18]_rec[-63];DT(3.5,2.5,3)rec[-9]_rec[-10]_rec[-15]_rec[-16]_rec[-62];DT(3.5,4.5,3)rec[-7]_rec[-8]_rec[-13]_rec[-14]_rec[-61];DT(5.5,0.5,3)rec[-5]_rec[-6]_rec[-35]_rec[-36]_rec[-57];DT(4.5,1.5,3)rec[-4]_rec[-5]_rec[-10]_rec[-11]_rec[-60];DT(5.5,2.5,3)rec[-3]_rec[-4]_rec[-33]_rec[-34]_rec[-56];DT(4.5,3.5,3)rec[-2]_rec[-3]_rec[-8]_rec[-9]_rec[-59];DT(5.5,4.5,3)rec[-1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(]_rec[-2]_rec[-31]_rec[-32]_rec[-55];DT(4.5,5.5,3)rec[-1]_rec[-6]_rec[-7]_rec[-12]_rec[-58];OI(0)rec[-3]_rec[-9]_rec[-15]_rec[-21]_rec[-27]_rec[-33];OI(1)rec[-13]_rec[-14]_rec[-15]_rec[-16]_rec[-17]_rec[-18]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr style=\"border-top: 3px solid black;\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Color Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Superdense</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Stability (X+Z)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>6x4x4</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,1)0;Q(0,2)1;Q(0,3)2;Q(1,0)3;Q(1,1)4;Q(1,2)5;Q(1,3)6;Q(1,4)7;Q(2,0)8;Q(2,1)9;Q(2,2)10;Q(2,3)11;Q(2,4)12;Q(3,0)13;Q(3,1)14;Q(3,2)15;Q(3,3)16;Q(3,4)17;Q(4,0)18;Q(4,1)19;Q(4,2)20;Q(4,3)21;Q(4,4)22;Q(5,1)23;Q(5,2)24;Q(5,3)25;POLYGON(0,1,1,0.25)14_18_24_20;POLYGON(0,1,1,0.25)11_16_22_7;POLYGON(0,1,1,0.25)3_9_5_1;POLYGON(1,0,1,0.25)9_14_20_16_11_5;POLYGON(1,1,0,0.25)3_18_14_9;POLYGON(1,1,0,0.25)20_24_22_16;POLYGON(1,1,0,0.25)1_5_11_7;TICK;R_13_6_17_15_23_25_4;RX_21_2_12_10_19_8_0;MARKZ(0)15;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;CX_21_20_12_11_10_9_19_18_25_24_17_16_15_14_2_1_6_5_4_3;TICK;CX_21_16_12_7_10_5_19_14_6_11_17_22_15_20_13_18_8_3_4_9;TICK;CX_6_7_10_11_15_16_21_22_19_20_23_24_8_9_13_14_0_1_4_5;TICK;CX_20_21_11_12_9_10_18_19_24_25_16_17_14_15_1_2_5_6_3_4;TICK;CX_16_21_7_12_5_10_14_19_11_6_22_17_20_15_18_13_3_8_9_4;TICK;CX_7_6_11_10_16_15_22_21_20_19_24_23_9_8_14_13_1_0_5_4;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;M_25_6_17_15_23_13_4;MX_21_2_12)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_10_19_8_0;MARKZ(0)15;OI(0)rec[-1]_rec[-2]_rec[-3]_rec[-5]_rec[-6]_rec[-7];OI(1)rec[-8]_rec[-9]_rec[-10]_rec[-12]_rec[-13]_rec[-14];TICK;R_13_6_17_15_23_25_4;RX_21_2_12_10_19_8_0;MARKX(1)0_2_12_21_19_8;MARKZ(0)17_13;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;CX_21_20_12_11_10_9_19_18_25_24_17_16_15_14_2_1_6_5_4_3;TICK;CX_21_16_12_7_10_5_19_14_6_11_17_22_15_20_13_18_8_3_4_9;TICK;CX_6_7_10_11_15_16_21_22_19_20_23_24_8_9_13_14_0_1_4_5;TICK;CX_20_21_11_12_9_10_18_19_24_25_16_17_14_15_1_2_5_6_3_4;TICK;CX_16_21_7_12_5_10_14_19_11_6_22_17_20_15_18_13_3_8_9_4;TICK;CX_7_6_11_10_16_15_22_21_20_19_24_23_9_8_14_13_1_0_5_4;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;M_25_6_17_15_23_13_4;MX_21_2_12_10_19_8_0;MARKX(1)8_0_2_12_21_19;MARKZ(0)15;DT(5,3,0)rec[-14]_rec[-28];DT(1,3,0)rec[-13]_rec[-27];DT(3,4,0)rec[-12]_rec[-26];DT(3,2,0)rec[-11]_rec[-25];DT(5,1,0)rec[-10]_rec[-24];DT(3,0,0)rec[-9]_rec[-23];DT(1,1,0)rec[-8]_rec[-22];DT(4,1,0)rec[-7]_rec[-17];DT(0,1,0)rec[-6]_rec[-15];DT(2,2,0)rec[-5]_rec[-18]_rec[-19])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;DT(2,0,0)rec[-4]_rec[-16]_rec[-19];DT(4,3,0)rec[-3]_rec[-21];DT(2,0.5,0)rec[-2]_rec[-16]_rec[-18];DT(0,3,0)rec[-1]_rec[-20];TICK;R_13_6_17_15_23_25_4;RX_21_2_12_10_19_8_0;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;CX_21_20_12_11_10_9_19_18_25_24_17_16_15_14_2_1_6_5_4_3;TICK;CX_21_16_12_7_10_5_19_14_6_11_17_22_15_20_13_18_8_3_4_9;TICK;CX_6_7_10_11_15_16_21_22_19_20_23_24_8_9_13_14_0_1_4_5;TICK;CX_20_21_11_12_9_10_18_19_24_25_16_17_14_15_1_2_5_6_3_4;TICK;CX_16_21_7_12_5_10_14_19_11_6_22_17_20_15_18_13_3_8_9_4;TICK;CX_7_6_11_10_16_15_22_21_20_19_24_23_9_8_14_13_1_0_5_4;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;M_25_6_17_15_23_13_4;MX_21_2_12_10_19_8_0;DT(5,3,1)rec[-14]_rec[-28];DT(1,3,1)rec[-13]_rec[-27];DT(3,4,1)rec[-12]_rec[-26];DT(3,2,1)rec[-11]_rec[-25];DT(5,1,1)rec[-10]_rec[-24];DT(3,0,1)rec[-9]_rec[-23];DT(1,1,1)rec[-8]_rec[-22];DT(4,1,1)rec[-7]_rec[-17];DT(0,1,1)rec[-6]_rec[-15];DT(2,2,1)rec[-5]_rec[-18]_rec[-19];DT(2,0,1)rec[-4]_rec[-16]_rec[-19];DT(4,3,1)rec[-3]_rec[-21];DT(2,0.5,1)rec[-)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(2]_rec[-16]_rec[-18];DT(0,3,1)rec[-1]_rec[-20];TICK;R_13_6_17_15_23_25_4;RX_21_2_12_10_19_8_0;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;CX_21_20_12_11_10_9_19_18_25_24_17_16_15_14_2_1_6_5_4_3;TICK;CX_21_16_12_7_10_5_19_14_6_11_17_22_15_20_13_18_8_3_4_9;TICK;CX_6_7_10_11_15_16_21_22_19_20_23_24_8_9_13_14_0_1_4_5;TICK;CX_20_21_11_12_9_10_18_19_24_25_16_17_14_15_1_2_5_6_3_4;TICK;CX_16_21_7_12_5_10_14_19_11_6_22_17_20_15_18_13_3_8_9_4;TICK;CX_7_6_11_10_16_15_22_21_20_19_24_23_9_8_14_13_1_0_5_4;TICK;CX_21_25_2_6_12_17_10_15_19_23_8_13_0_4;TICK;M_25_6_17_15_23_13_4;MX_21_2_12_10_19_8_0;DT(5,3,2)rec[-14]_rec[-28];DT(1,3,2)rec[-13]_rec[-27];DT(3,4,2)rec[-12]_rec[-26];DT(3,2,2)rec[-11]_rec[-25];DT(5,1,2)rec[-10]_rec[-24];DT(3,0,2)rec[-9]_rec[-23];DT(1,1,2)rec[-8]_rec[-22];DT(4,1,2)rec[-7]_rec[-17];DT(0,1,2)rec[-6]_rec[-15];DT(2,2,2)rec[-5]_rec[-18]_rec[-19];DT(2,0,2)rec[-4]_rec[-16]_rec[-19];DT(4,3,2)rec[-3]_rec[-21];DT(2,0.5,2)rec[-2]_rec[-16]_rec[-18];DT(0,3,2)rec[-1]_rec[-20]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Surface Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Standard (ИZ)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Stability (Z)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>4x4x5</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,1)0;Q(0,3)1;Q(0.5,0.5)2;Q(0.5,1.5)3;Q(0.5,2.5)4;Q(0.5,3.5)5;Q(1,0)6;Q(1,1)7;Q(1,2)8;Q(1,3)9;Q(1,4)10;Q(1.5,0.5)11;Q(1.5,1.5)12;Q(1.5,2.5)13;Q(1.5,3.5)14;Q(2,1)15;Q(2,2)16;Q(2,3)17;Q(2.5,0.5)18;Q(2.5,1.5)19;Q(2.5,2.5)20;Q(2.5,3.5)21;Q(3,0)22;Q(3,1)23;Q(3,2)24;Q(3,3)25;Q(3,4)26;Q(3.5,0.5)27;Q(3.5,1.5)28;Q(3.5,2.5)29;Q(3.5,3.5)30;Q(4,1)31;Q(4,3)32;POLYGON(0,0,1,0.25)11_2;POLYGON(0,0,1,0.25)3_12_13_4;POLYGON(0,0,1,0.25)2_3;POLYGON(0,0,1,0.25)13_20_21_14;POLYGON(0,0,1,0.25)19_28_29_20;POLYGON(0,0,1,0.25)11_18_19_12;POLYGON(0,0,1,0.25)27_18;POLYGON(0,0,1,0.25)27_28;POLYGON(0,0,1,0.25)4_5;POLYGON(0,0,1,0.25)14_5;POLYGON(0,0,1,0.25)30_21;POLYGON(0,0,1,0.25)29_30;POLYGON(1,0,0,0.25)2_11_12_3;POLYGON(1,0,0,0.25)12_19_20_13;POLYGON(1,0,0,0.25)18_27_28_19;POLYGON(1,0,0,0.25)20_29_30_21;POLYGON(1,0,0,0.25)4_13_14_5;TICK;RY_2_3_4_5_11_12_13_14_18_19_20_21_27_28_29_30;TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;OI(0)rec[-6]_rec[-7]_rec[-8]_rec[-9]_rec[-10]_rec[-11]_rec[-12]_rec[-13]_rec[-14]_rec[-15]_rec[-16]_rec[-17];TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;MARKZ(0)6_8_10_15_17_22_24_26_31_32_0_1;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;MARKZ(0)6_8_10_15_17_22_24_26_31_32_0_1;DT(0,1,0)rec[-17]_rec[-34];DT(0,3,0)rec[-16]_rec[-33];DT(1,0,0)rec[-15]_rec[-32];DT(1,2,0)rec[-14]_r)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ec[-31];DT(1,4,0)rec[-13]_rec[-30];DT(2,1,0)rec[-12]_rec[-29];DT(2,3,0)rec[-11]_rec[-28];DT(3,0,0)rec[-10]_rec[-27];DT(3,2,0)rec[-9]_rec[-26];DT(3,4,0)rec[-8]_rec[-25];DT(4,1,0)rec[-7]_rec[-24];DT(4,3,0)rec[-6]_rec[-23];DT(1,1,0)rec[-5]_rec[-22];DT(1,3,0)rec[-4]_rec[-21];DT(3,3,0)rec[-3]_rec[-20];DT(3,1,0)rec[-2]_rec[-19];DT(2,2,0)rec[-1]_rec[-18];TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;DT(0,1,1)rec[-17]_rec[-34];DT(0,3,1)rec[-16]_rec[-33];DT(1,0,1)rec[-15]_rec[-32];DT(1,2,1)rec[-14]_rec[-31];DT(1,4,1)rec[-13]_rec[-30];DT(2,1,1)rec[-12]_rec[-29];DT(2,3,1)rec[-11]_rec[-28];DT(3,0,1)rec[-10]_rec[-27];DT(3,2,1)rec[-9]_rec[-26];DT(3,4,1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART()rec[-8]_rec[-25];DT(4,1,1)rec[-7]_rec[-24];DT(4,3,1)rec[-6]_rec[-23];DT(1,1,1)rec[-5]_rec[-22];DT(1,3,1)rec[-4]_rec[-21];DT(3,3,1)rec[-3]_rec[-20];DT(3,1,1)rec[-2]_rec[-19];DT(2,2,1)rec[-1]_rec[-18];TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;DT(0,1,2)rec[-17]_rec[-34];DT(0,3,2)rec[-16]_rec[-33];DT(1,0,2)rec[-15]_rec[-32];DT(1,2,2)rec[-14]_rec[-31];DT(1,4,2)rec[-13]_rec[-30];DT(2,1,2)rec[-12]_rec[-29];DT(2,3,2)rec[-11]_rec[-28];DT(3,0,2)rec[-10]_rec[-27];DT(3,2,2)rec[-9]_rec[-26];DT(3,4,2)rec[-8]_rec[-25];DT(4,1,2)rec[-7]_rec[-24];DT(4,3,2)rec[-6]_rec[-23];DT(1,1,2)rec[-5]_rec[-22];DT(1,3,2)rec[-4]_rec[-21];DT(3,3,2)rec[-3]_rec[-20];DT)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART((3,1,2)rec[-2]_rec[-19];DT(2,2,2)rec[-1]_rec[-18];TICK;R_0_1_6_8_10_15_17_22_24_26_31_32;RX_7_9_25_23_16;TICK;CX_7_2_3_8_9_4_5_10_11_15_16_12_13_17_23_18_19_24_25_20_21_26_27_31_29_32;TICK;CX_2_0_4_1_12_8_14_10_18_15_20_17_28_24_30_26_7_3_16_13_9_5_23_19_25_21;TICK;CX_2_6_4_8_12_15_14_17_18_22_20_24_28_31_30_32_7_11_16_19_9_13_23_27_25_29;TICK;CX_3_0_5_1_11_6_7_12_13_8_9_14_19_15_16_20_21_17_27_22_23_28_29_24_25_30;TICK;M_0_1_6_8_10_15_17_22_24_26_31_32;MX_7_9_25_23_16;DT(0,1,3)rec[-17]_rec[-34];DT(0,3,3)rec[-16]_rec[-33];DT(1,0,3)rec[-15]_rec[-32];DT(1,2,3)rec[-14]_rec[-31];DT(1,4,3)rec[-13]_rec[-30];DT(2,1,3)rec[-12]_rec[-29];DT(2,3,3)rec[-11]_rec[-28];DT(3,0,3)rec[-10]_rec[-27];DT(3,2,3)rec[-9]_rec[-26];DT(3,4,3)rec[-8]_rec[-25];DT(4,1,3)rec[-7]_rec[-24];DT(4,3,3)rec[-6]_rec[-23];DT(1,1,3)rec[-5]_rec[-22];DT(1,3,3)rec[-4]_rec[-21];DT(3,3,3)rec[-3]_rec[-20];DT(3,1,3)rec[-2]_rec[-19];DT(2,2,3)rec[-1]_rec[-18];TICK;MY_2_3_4_5_11_12_13_14_18_19_20_21_27_28_29_30\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr style=\"border-top: 3px solid black;\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Surface Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Standard (ИZ)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Prepare (RY)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>5x5x4</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,2)0;Q(0,4)1;Q(0.5,0.5)2;Q(0.5,1.5)3;Q(0.5,2.5)4;Q(0.5,3.5)5;Q(0.5,4.5)6;Q(1,0)7;Q(1,1)8;Q(1,2)9;Q(1,3)10;Q(1,4)11;Q(1.5,0.5)12;Q(1.5,1.5)13;Q(1.5,2.5)14;Q(1.5,3.5)15;Q(1.5,4.5)16;Q(2,0)17;Q(2,1)18;Q(2,2)19;Q(2,3)20;Q(2,4)21;Q(2,5)22;Q(2.5,0.5)23;Q(2.5,1.5)24;Q(2.5,2.5)25;Q(2.5,3.5)26;Q(2.5,4.5)27;Q(3,0)28;Q(3,1)29;Q(3,2)30;Q(3,3)31;Q(3,4)32;Q(3.5,0.5)33;Q(3.5,1.5)34;Q(3.5,2.5)35;Q(3.5,3.5)36;Q(3.5,4.5)37;Q(4,0)38;Q(4,1)39;Q(4,2)40;Q(4,3)41;Q(4,4)42;Q(4,5)43;Q(4.5,0.5)44;Q(4.5,1.5)45;Q(4.5,2.5)46;Q(4.5,3.5)47;Q(4.5,4.5)48;Q(5,1)49;Q(5,2)50;Q(5,3)51;Q(5,4)52;POLYGON(0,0,1,0.25)12_13_3;POLYGON(0,0,1,0.25)4_14_15_5;POLYGON(0,0,1,0.25)13_24_25_14;POLYGON(0,0,1,0.25)15_26_27_16;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)34_45_46_35;POLYGON(0,0,1,0.25)36_47_48_37;POLYGON(0,0,1,0.25)3_4;POLYGON(0,0,1,0.25)5_6;POLYGON(0,0,1,0.25)23_12;POLYGON(0,0,1,0.25)44_33;POLYGON(1,0,0,0.25)3_13_14_4;POLYGON(1,0,0,0.25)5_15_16_6;POLYGON(1,0,0,0.25)1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(2_23_24_13;POLYGON(1,0,0,0.25)14_25_26_15;POLYGON(1,0,0,0.25)24_34_35_25;POLYGON(1,0,0,0.25)26_36_37_27;POLYGON(1,0,0,0.25)33_44_45_34;POLYGON(1,0,0,0.25)35_46_47_36;POLYGON(1,0,0,0.25)27_16;POLYGON(1,0,0,0.25)48_37;POLYGON(1,0,0,0.25)47_48;POLYGON(1,0,0,0.25)45_46;TICK;R_25_15_14_13_24_34_44_33_23_12_3_4_5_6;RX_45_46_35_47_36_26_48_37_27_16;TICK;R_0_1_42_40_38_31_29_21_19_17_10_8;RX_52_50_43_41_39_32_30_22_20_18_11_9;TICK;CX_37_42_35_40_33_38_26_31_24_29_16_21_14_19_12_17_5_10_3_8_52_48_50_46_41_36_39_34_32_27_30_25_20_15_18_13_11_6_9_4;TICK;CX_41_47_39_45_32_37_30_35_20_26_18_24_11_16_9_14_36_42_34_40_25_31_23_29_15_21_13_19_4_10;TICK;CX_52_47_50_45_43_37_41_35_39_33_32_26_30_24_22_16_20_14_18_12_11_5_9_3_4_0_6_1_48_42_46_40_44_38_36_31_34_29_27_21_25_19_23_17_15_10_13_8;TICK;CX_43_48_41_46_39_44_32_36_30_34_22_27_20_25_18_23_11_15_9_13_3_0_5_1_47_42_45_40_35_31_33_29_26_21_24_19_14_10_12_8;TICK;M_1_0_42_40_38_31_29_21_19_17_10_8;MX_52_50_43_41_39_32_30_22_20_18_11_9;DT(0,4,0)rec[-24];DT(0,2,0)rec[-23];DT(4)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(,0,0)rec[-20];DT(3,1,0)rec[-18];DT(2,2,0)rec[-16];DT(2,0,0)rec[-15];DT(1,3,0)rec[-14];DT(1,1,0)rec[-13];DT(5,4,0)rec[-12];DT(5,2,0)rec[-11];DT(4,5,0)rec[-10];DT(4,3,0)rec[-9];DT(3,4,0)rec[-7];DT(2,5,0)rec[-5];TICK;R_0_1_42_40_38_31_29_21_19_17_10_8;RX_52_50_43_41_39_32_30_22_20_18_11_9;TICK;CX_37_42_35_40_33_38_26_31_24_29_16_21_14_19_12_17_5_10_3_8_52_48_50_46_41_36_39_34_32_27_30_25_20_15_18_13_11_6_9_4;TICK;CX_41_47_39_45_32_37_30_35_20_26_18_24_11_16_9_14_36_42_34_40_25_31_23_29_15_21_13_19_4_10;TICK;CX_52_47_50_45_43_37_41_35_39_33_32_26_30_24_22_16_20_14_18_12_11_5_9_3_4_0_6_1_48_42_46_40_44_38_36_31_34_29_27_21_25_19_23_17_15_10_13_8;TICK;CX_43_48_41_46_39_44_32_36_30_34_22_27_20_25_18_23_11_15_9_13_3_0_5_1_47_42_45_40_35_31_33_29_26_21_24_19_14_10_12_8;TICK;M_1_0_42_40_38_31_29_21_19_17_10_8;MX_52_50_43_41_39_32_30_22_20_18_11_9;DT(0,4,1)rec[-24]_rec[-48];DT(0,2,1)rec[-23]_rec[-47];DT(4,4,1)rec[-22]_rec[-46];DT(4,2,1)rec[-21]_rec[-45];DT(4,0,1)rec[-20]_rec[-44];DT(3,3,1)rec[-19]_rec[-43];DT(3,1,1)rec[)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(-18]_rec[-42];DT(2,4,1)rec[-17]_rec[-41];DT(2,2,1)rec[-16]_rec[-40];DT(2,0,1)rec[-15]_rec[-39];DT(1,3,1)rec[-14]_rec[-38];DT(1,1,1)rec[-13]_rec[-37];DT(5,4,1)rec[-12]_rec[-36];DT(5,2,1)rec[-11]_rec[-35];DT(4,5,1)rec[-10]_rec[-34];DT(4,3,1)rec[-9]_rec[-33];DT(4,1,1)rec[-8]_rec[-32];DT(3,4,1)rec[-7]_rec[-31];DT(3,2,1)rec[-6]_rec[-30];DT(2,5,1)rec[-5]_rec[-29];DT(2,3,1)rec[-4]_rec[-28];DT(2,1,1)rec[-3]_rec[-27];DT(1,4,1)rec[-2]_rec[-26];DT(1,2,1)rec[-1]_rec[-25];TICK;POLYGON(0,0,1,0.25)13_24_25_14;POLYGON(0,0,1,0.25)4_14_15_5;POLYGON(0,0,1,0.25)15_26_27_16;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)3_4;POLYGON(0,0,1,0.25)5_6;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)2_12_13_3;POLYGON(0,0,1,0.25)34_45_46_35;POLYGON(0,0,1,0.25)36_47_48_37;POLYGON(0,0,1,0.25)38;POLYGON(0,0,1,0.25)28;POLYGON(0,0,1,0.25)17;POLYGON(0,0,1,0.25)7;POLYGON(0,0.5,0,1)2_48;POLYGON(1,0,0,0.25)3_13_14_4;POLYGON(1,0,0,0.25)14_25_26_15;POLYGON(1,0,0,0.25)5_15_16_6;POLYGON(1,0,0,0.25)26_36_37_27;POLYGON(1,0,0,0.25)24_34_35_25;POLY)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(GON(1,0,0,0.25)27_16;POLYGON(1,0,0,0.25)48_37;POLYGON(1,0,0,0.25)12_23_24_13;POLYGON(1,0,0,0.25)33_44_45_34;POLYGON(1,0,0,0.25)35_46_47_36;POLYGON(1,0,0,0.25)52;POLYGON(1,0,0,0.25)51;POLYGON(1,0,0,0.25)50;POLYGON(1,0,0,0.25)49;TICK;R_42_40_38_31_29_28_21_19_17_10_8_7_1_0;RX_52_51_50_49_43_41_39_32_30_22_20_18_11_9;RY_2;TICK;H_52_51_50_49_41_40_39_38_30_29_28_18_17_7_47_46_45_44_35_34_33_24_23_12;SQRT_X_DAG_42_31_19_8;TICK;XCY_48_52_36_41_25_30_13_18;TICK;CX_26_21_14_10_5_1_3_0_43_48_32_36_22_27_20_25_11_15_9_13_51_47_49_45_40_35_38_33_29_24_17_12_46_50_34_39_23_28;TICK;CX_27_21_15_10_6_1_4_0_43_37_32_26_22_16_20_14_11_5_9_3_40_46_38_44_29_34_17_23_47_52_45_50_35_41_33_39_24_30_12_18;XCY_42_48_31_36_19_25_8_13;TICK;CX_46_51_44_49_36_42_34_40_25_31_23_29_15_21_13_19_4_10_2_8_41_47_39_45_32_37_30_35_28_33_20_26_18_24_11_16_9_14_7_12;TICK;CX_47_51_45_49_37_42_35_40_26_31_24_29_16_21_14_19_5_10_3_8_41_36_39_34_32_27_30_25_28_23_20_15_18_13_11_6_9_4_7_2;TICK;M_52_51_50_49_42_40_31_29_21_19_10_8_1_0;MX_43_41_39_38_3)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(2_30_28_22_20_18_17_11_9_7;DT(5,4,2)rec[-28]_rec[-40];DT(4,3,2)rec[-27]_rec[-37];DT(5,2,2)rec[-26]_rec[-39];DT(4,1,2)rec[-25]_rec[-36];DT(3,2,2)rec[-23]_rec[-34];DT(2,1,2)rec[-21]_rec[-31];DT(2,4,2)rec[-20]_rec[-45];DT(1,3,2)rec[-18]_rec[-42];DT(0,4,2)rec[-16]_rec[-52];DT(0,2,2)rec[-15]_rec[-51];DT(4,5,2)rec[-14]_rec[-38];DT(4,4,2)rec[-13]_rec[-24]_rec[-50];DT(4,2,2)rec[-12]_rec[-49];DT(4,0,2)rec[-11]_rec[-48];DT(3,4,2)rec[-10]_rec[-35];DT(3,3,2)rec[-9]_rec[-22]_rec[-47];DT(3,1,2)rec[-8]_rec[-46];DT(2,5,2)rec[-7]_rec[-33];DT(2,3,2)rec[-6]_rec[-32];DT(2,2,2)rec[-5]_rec[-19]_rec[-44];DT(2,0,2)rec[-4]_rec[-43];DT(1,4,2)rec[-3]_rec[-30];DT(1,2,2)rec[-2]_rec[-29];DT(1,1,2)rec[-1]_rec[-17]_rec[-41];TICK;POLYGON(0,0,1,0.25)2_12_13_3;POLYGON(0,0,1,0.25)13_24_25_14;POLYGON(0,0,1,0.25)4_14_15_5;POLYGON(0,0,1,0.25)15_26_27_16;POLYGON(0,0,1,0.25)25_35_36_26;POLYGON(0,0,1,0.25)36_47_48_37;POLYGON(0,0,1,0.25)23_33_34_24;POLYGON(0,0,1,0.25)34_45_46_35;POLYGON(0,0,1,0.25)44_45;POLYGON(0,0,1,0.25)3_4;POLYGON(0,0,1,0.25)5_6;PO)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(LYGON(0,0,1,0.25)46_47;POLYGON(1,0,0,0.25)12_23_24_13;POLYGON(1,0,0,0.25)3_13_14_4;POLYGON(1,0,0,0.25)14_25_26_15;POLYGON(1,0,0,0.25)5_15_16_6;POLYGON(1,0,0,0.25)35_46_47_36;POLYGON(1,0,0,0.25)26_36_37_27;POLYGON(1,0,0,0.25)33_44_45_34;POLYGON(1,0,0,0.25)24_34_35_25;POLYGON(1,0,0,0.25)12_2;POLYGON(1,0,0,0.25)33_23;POLYGON(1,0,0,0.25)27_16;POLYGON(1,0,0,0.25)48_37;TICK;MPP_X33*X23_X12*X2_X27*X37*X36*X26_X25*X35*X34*X24_X4*X14*X13*X3_X6*X16*X15*X5;DT(3,0,3)rec[-6]_rec[-14];DT(1,0,3)rec[-5]_rec[-7];DT(3,4,3)rec[-4]_rec[-16];DT(3,2,3)rec[-3]_rec[-15];DT(1,2,3)rec[-2]_rec[-8];DT(1,4,3)rec[-1]_rec[-9];TICK;MPP_X48*X37_X27*X16_X36*X47*X46*X35_X34*X45*X44*X33_X13*X24*X23*X12_X15*X26*X25*X14;DT(4,5,4)rec[-6]_rec[-26];DT(2,5,4)rec[-5]_rec[-19];DT(4,3,4)rec[-4]_rec[-25];DT(4,0,4)rec[-3]_rec[-23]_rec[-24];DT(2,0,4)rec[-2]_rec[-16]_rec[-17];DT(2,3,4)rec[-1]_rec[-18];TICK;MPP_Z6*Z5_Z4*Z3_Z35*Z46*Z45*Z34_Z37*Z48*Z47*Z36_Z16*Z27*Z26*Z15_Z14*Z25*Z24*Z13;DT(0,4,5)rec[-6]_rec[-34];DT(0,2,5)rec[-5]_rec[-33];DT(4,2,5)rec[-4]_rec[)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(-41]_rec[-44];DT(4,4,5)rec[-3]_rec[-42]_rec[-46];DT(2,4,5)rec[-2]_rec[-38];DT(2,2,5)rec[-1]_rec[-37];TICK;MPP_Z47*Z46_Z45*Z44_Z24*Z34*Z33*Z23_Z26*Z36*Z35*Z25_Z5*Z15*Z14*Z4_Z3*Z13*Z12*Z2;DT(5,3,6)rec[-6]_rec[-51];DT(5,1,6)rec[-5]_rec[-49];DT(3,1,6)rec[-4]_rec[-45];DT(3,3,6)rec[-3]_rec[-46];DT(1,3,6)rec[-2]_rec[-42];DT(1,1,6)rec[-1]_rec[-41];TICK;MPP_X6*X5*X4*X3*Y2*Z23*Z12*Z44*Z33;OI(0)rec[-1]_rec[-54]_rec[-55]_rec[-56]_rec[-57]_rec[-58]_rec[-59]_rec[-60]_rec[-61]_rec[-62]_rec[-63]_rec[-64]_rec[-65]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        <tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Surface Code</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Standard (ИZ)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>Surgery (MZZ)</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td>7x3x5</td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            <td><a href=\"\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                #circuit=Q(0,2)0;Q(0.5,0.5)1;Q(0.5,1.5)2;Q(0.5,2.5)3;Q(1,0)4;Q(1,1)5;Q(1,2)6;Q(1.5,0.5)7;Q(1.5,1.5)8;Q(1.5,2.5)9;Q(2,1)10;Q(2,2)11;Q(2,3)12;Q(2.5,0.5)13;Q(2.5,1.5)14;Q(2.5,2.5)15;Q(3,0)16;Q(3,1)17;Q(3,2)18;Q(3.5,0.5)19;Q(3.5,1.5)20;Q(3.5,2.5)21;Q(4,1)22;Q(4,2)23;Q(4,3)24;Q(4.5,0.5)25;Q(4.5,1.5)26;Q(4.5,2.5)27;Q(5,0)28;Q(5,1)29;Q(5,2)30;Q(5.5,0.5)31;Q(5.5,1.5)32;Q(5.5,2.5)33;Q(6,1)34;Q(6,2)35;Q(6,3)36;Q(6.5,0.5)37;Q(6.5,1.5)38;Q(6.5,2.5)39;Q(7,1)40;POLYGON(0,0,1,0.25)7_13_14_8;POLYGON(0,0,1,0.25)2_8_9_3;POLYGON(0,0,1,0.25)7_1;POLYGON(0,0,1,0.25)15_9;POLYGON(0,0,1,0.25)31_37_38_32;POLYGON(0,0,1,0.25)26_32_33_27;POLYGON(0,0,1,0.25)31_25;POLYGON(0,0,1,0.25)39_33;POLYGON(1,0,0,0.25)1_7_8_2;POLYGON(1,0,0,0.25)8_14_15_9;POLYGON(1,0,0,0.25)2_3;POLYGON(1,0,0,0.25)13_14;POLYGON(1,0,0,0.25)25_31_32_26;POLYGON(1,0,0,0.25)32_38_39_33;POLYGON(1,0,0,0.25)26_27;POLYGON(1,0,0,0.25)37_38;TICK;R_1_2_3_7_8_9_13_14_15_25_26_27_31_32_33_37_38_39;MARKZ(1)25_26_27_13_14_15;TICK;R_6_10_4_12_30_34_28_36)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;RX_5_11_0_17_29_35_23_40;MARKX(0)1_7_13_25_31_37;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38;TICK;CX_5_8_9_6_14_10_11_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28;TICK;M_6_10_4_12_30_34_28_36;MX_5_11_0_17_29_35_23_40;DT(1,2,0)rec[-16];DT(2,1,0)rec[-15];DT(1,0,0)rec[-14];DT(2,3,0)rec[-13];DT(5,2,0)rec[-12];DT(6,1,0)rec[-11];DT(5,0,0)rec[-10];DT(6,3,0)rec[-9];TICK;POLYGON(0,0,1,0.25)2_8_9_3;POLYGON(0,0,1,0.25)7_1;POLYGON(0,0,1,0.25)15_9;POLYGON(0,0,1,0.25)31_37_38_32;POLYGON(0,0,1,0.25)31_25;POLYGON(0,0,1,0.25)39_33;POLYGON(0,0,1,0.25)7_13_14_8;POLYGON(0,0,1,0.25)26_32_33_27;POLYGON(1,0,0,0.25)1_7_8_2;POLYGON(1,0,0,0.25)8_14_15_9;POLYGON(1,0,0,0.25)2_3;POLYGON(1,0,0,0.25)25_31_32_26;POLYGON(1,0,0,0.25)32_38_39_33;POLYGON(1,0,0,0.25)37_38;POLYGON(1,0,0,0.25)20;POLYGON(1,0,0,0.25)19;POLYGON(1,0,0,0.25)21;POLYGON(1,0,0,0.25)13_19_20_14;POL)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(YGON(1,0,0,0.25)20_26_27_21;TICK;R_6_10_4_12_30_34_28_36_18_22_24_16;RX_5_11_0_17_29_35_23_40_19_20_21;MARKX(0)19;MARKZ(1)18_16_24_22;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37_14_18_19_22_23_20_21_24;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38_20_18_23_21_27_24_25_22;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38_15_18_20_22_17_19_13_16;TICK;CX_5_8_9_6_14_10_11_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28_17_20_26_22_19_16_21_18;TICK;M_6_10_4_12_30_34_28_36_24_16_22_18;MX_5_11_0_17_29_35_23_40;MARKZ(1)24_16_22_18;DT(1,2,1)rec[-20]_rec[-36];DT(2,1,1)rec[-19]_rec[-35];DT(1,0,1)rec[-18]_rec[-34];DT(2,3,1)rec[-17]_rec[-33];DT(5,2,1)rec[-16]_rec[-32];DT(6,1,1)rec[-15]_rec[-31];DT(5,0,1)rec[-14]_rec[-30];DT(6,3,1)rec[-13]_rec[-29];DT(1,1,1)rec[-8]_rec[-28];DT(2,2,1)rec[-7]_rec[-27];DT(0,2,1)rec[-6]_rec[-26];DT(3,1,1)rec[-5]_rec[-25];DT(5,1,1)rec[-4]_rec[-24];DT(6,2,1)rec[-3]_rec[-23];DT(4,2,1)rec[-2]_rec[-22];DT(7,1,1)rec[-1]_re)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(c[-21];OI(0)rec[-9]_rec[-10]_rec[-11]_rec[-12]_rec[-17]_rec[-18]_rec[-19]_rec[-20];TICK;POLYGON(0,0,1,0.25)2_8_9_3;POLYGON(0,0,1,0.25)7_1;POLYGON(0,0,1,0.25)15_9;POLYGON(0,0,1,0.25)31_37_38_32;POLYGON(0,0,1,0.25)31_25;POLYGON(0,0,1,0.25)39_33;POLYGON(0,0,1,0.25)7_13_14_8;POLYGON(0,0,1,0.25)26_32_33_27;POLYGON(0,0,1,0.25)19_25_26_20;POLYGON(0,0,1,0.25)19_13;POLYGON(0,0,1,0.25)27_21;POLYGON(0,0,1,0.25)14_20_21_15;POLYGON(1,0,0,0.25)1_7_8_2;POLYGON(1,0,0,0.25)8_14_15_9;POLYGON(1,0,0,0.25)2_3;POLYGON(1,0,0,0.25)25_31_32_26;POLYGON(1,0,0,0.25)32_38_39_33;POLYGON(1,0,0,0.25)37_38;POLYGON(1,0,0,0.25)13_19_20_14;POLYGON(1,0,0,0.25)20_26_27_21;TICK;R_6_10_4_12_30_34_28_36_18_22_24_16;RX_5_11_0_17_29_35_23_40;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37_14_18_19_22_23_20_21_24;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38_20_18_23_21_27_24_25_22;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38_15_18_20_22_17_19_13_16;TICK;CX_5_8_9_6_14_10_11)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28_17_20_26_22_19_16_21_18;TICK;M_6_10_4_12_30_34_28_36_24_16_22_18;MX_5_11_0_17_29_35_23_40;DT(1,2,2)rec[-20]_rec[-40];DT(2,1,2)rec[-19]_rec[-39];DT(1,0,2)rec[-18]_rec[-38];DT(2,3,2)rec[-17]_rec[-37];DT(5,2,2)rec[-16]_rec[-36];DT(6,1,2)rec[-15]_rec[-35];DT(5,0,2)rec[-14]_rec[-34];DT(6,3,2)rec[-13]_rec[-33];DT(4,3,2)rec[-12]_rec[-32];DT(3,0,2)rec[-11]_rec[-31];DT(4,1,2)rec[-10]_rec[-30];DT(3,2,2)rec[-9]_rec[-29];DT(1,1,2)rec[-8]_rec[-28];DT(2,2,2)rec[-7]_rec[-27];DT(0,2,2)rec[-6]_rec[-26];DT(3,1,2)rec[-5]_rec[-25];DT(5,1,2)rec[-4]_rec[-24];DT(6,2,2)rec[-3]_rec[-23];DT(4,2,2)rec[-2]_rec[-22];DT(7,1,2)rec[-1]_rec[-21];TICK;R_6_10_4_12_30_34_28_36_18_22_24_16;RX_5_11_0_17_29_35_23_40;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37_14_18_19_22_23_20_21_24;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38_20_18_23_21_27_24_25_22;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38_15_18_20_22_17_19_13_1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(6;TICK;CX_5_8_9_6_14_10_11_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28_17_20_26_22_19_16_21_18;TICK;M_6_10_4_12_30_34_28_36_24_16_22_18;MX_5_11_0_17_29_35_23_40_19_20_21;MARKX(0)19;DT(1,2,3)rec[-23]_rec[-43];DT(2,1,3)rec[-22]_rec[-42];DT(1,0,3)rec[-21]_rec[-41];DT(2,3,3)rec[-20]_rec[-40];DT(5,2,3)rec[-19]_rec[-39];DT(6,1,3)rec[-18]_rec[-38];DT(5,0,3)rec[-17]_rec[-37];DT(6,3,3)rec[-16]_rec[-36];DT(4,3,3)rec[-15]_rec[-35];DT(3,0,3)rec[-14]_rec[-34];DT(4,1,3)rec[-13]_rec[-33];DT(3,2,3)rec[-12]_rec[-32];DT(1,1,3)rec[-11]_rec[-31];DT(2,2,3)rec[-10]_rec[-30];DT(0,2,3)rec[-9]_rec[-29];DT(3,1,3)rec[-8]_rec[-28];DT(5,1,3)rec[-7]_rec[-27];DT(6,2,3)rec[-6]_rec[-26];DT(4,2,3)rec[-5]_rec[-25];DT(7,1,3)rec[-4]_rec[-24];TICK;POLYGON(0,0,1,0.25)7_13_14_8;POLYGON(0,0,1,0.25)2_8_9_3;POLYGON(0,0,1,0.25)7_1;POLYGON(0,0,1,0.25)15_9;POLYGON(0,0,1,0.25)31_37_38_32;POLYGON(0,0,1,0.25)26_32_33_27;POLYGON(0,0,1,0.25)31_25;POLYGON(0,0,1,0.25)39_33;POLYGON(1,0,0,0.25)1_7_8_2;POLYGON(1,0,0,0.25)8_14_15_9;POLYGON(1,0,0,0.25)2_3;POLYGON)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART((1,0,0,0.25)13_14;POLYGON(1,0,0,0.25)25_31_32_26;POLYGON(1,0,0,0.25)32_38_39_33;POLYGON(1,0,0,0.25)26_27;POLYGON(1,0,0,0.25)37_38;TICK;R_6_10_4_12_30_34_28_36;RX_5_11_0_17_29_35_23_40;TICK;CX_5_1_2_6_7_10_11_8_9_12_17_13_29_25_26_30_31_34_35_32_33_36_40_37;TICK;CX_8_6_13_10_5_2_11_9_15_12_17_14_32_30_37_34_29_26_35_33_39_36_40_38;TICK;CX_3_6_8_10_1_4_5_7_0_2_11_14_27_30_32_34_25_28_29_31_23_26_35_38;TICK;CX_5_8_9_6_14_10_11_15_0_3_7_4_29_32_33_30_38_34_35_39_23_27_31_28;TICK;M_6_10_4_12_30_34_28_36;MX_5_11_0_17_29_35_23_40;MARKX(0)1_7_13_25_31_37;DT(1,2,4)rec[-16]_rec[-39];DT(2,1,4)rec[-15]_rec[-38];DT(1,0,4)rec[-14]_rec[-37];DT(2,3,4)rec[-13]_rec[-36];DT(5,2,4)rec[-12]_rec[-35];DT(6,1,4)rec[-11]_rec[-34];DT(5,0,4)rec[-10]_rec[-33];DT(6,3,4)rec[-9]_rec[-32];DT(1,1,4)rec[-8]_rec[-27];DT(2,2,4)rec[-7]_rec[-26];DT(0,2,4)rec[-6]_rec[-25];DT(3.5,1.5,4)rec[-5]_rec[-18]_rec[-19]_rec[-24];DT(5,1,4)rec[-4]_rec[-23];DT(6,2,4)rec[-3]_rec[-22];DT(3.5,2.5,4)rec[-2]_rec[-17]_rec[-18]_rec[-21];DT(7,1,4)rec[-1]_rec[-20];TICK)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;M_1_2_3_7_8_9_13_14_15_25_26_27_31_32_33_37_38_39;DT(1,0,5)rec[-15]_rec[-18]_rec[-32];DT(1,2,5)rec[-13]_rec[-14]_rec[-16]_rec[-17]_rec[-34];DT(2,1,5)rec[-11]_rec[-12]_rec[-14]_rec[-15]_rec[-33];DT(2,3,5)rec[-10]_rec[-13]_rec[-31];DT(5,0,5)rec[-6]_rec[-9]_rec[-28];DT(5,2,5)rec[-4]_rec[-5]_rec[-7]_rec[-8]_rec[-30];DT(6,1,5)rec[-2]_rec[-3]_rec[-5]_rec[-6]_rec[-29];DT(6,3,5)rec[-1]_rec[-4]_rec[-27];OI(1)rec[-16]_rec[-17]_rec[-18];OI(2)rec[-7]_rec[-8]_rec[-9]\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            \">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                                Open Circuit\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                            </a></td>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                        </tr>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                    </tbody>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                </table>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnShowHideImportExport\">Show Import/Export</button><br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"clear\">Clear All</button><br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnClearMarkers\">Clear All Pauli Marks</button><br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnClearSelectedMarkers\">Clear Selected Marks (space)</button>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnRedo\">Redo (ctrl+Y)</button><br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnUndo\">Undo (ctrl+Z)</button>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnNextLayer\">Next Layer (e)</button><br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnPrevLayer\">Prev Layer (q)</button>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnRotate45\">Rotate 45 Clockwise ↻ (t)</button><br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnRotate45Counter\">Rotate 45 Mathwise ↺ (shift+t)</button>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnTimelineFocus\">Set Timeline Focus (L)</button><br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnClearTimelineFocus\">Clear Timeline Focus</button>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <div style=\"display: inline-block\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnInsertLayer\">Insert Layer (ctrl+insert)</button><br>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(                <button id=\"btnDeleteLayer\">Delete Layer (ctrl+delete)</button>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <textarea id=\"txtDefaultCircuit\" style=\"display: none\">[[[DEFAULT_CIRCUIT_CONTENT_LITERAL]]]</textarea>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    <div id=\"divImportExport\" style=\"display: none\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            <textarea id=\"txtStimCircuit\" style=\"width: 95vw; height: 300px; background-color: #FFFFB0\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(            </textarea>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <button id=\"btnExport\" style=\"background-color: red\">↑ Export to Stim Circuit ↑</button>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(        <button id=\"btnImport\" style=\"background-color: red\">↓ Import from Stim Circuit ↓</button>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    </div>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    <canvas id=\"cvn\" style=\"width: calc(100vw - 32px); height: calc(100vh - 150px); border: 1px solid black; margin: 0; padding: 0;\" tabindex=\"0\">\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    </canvas>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(</body>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(</html>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(<script>\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(class l{constructor(t,r,e,i,o,a,n,s,h=void 0){this.name=t,this.t=r,this.i=i,this.o=e,this.h=o,this.l=a,this.v=n,this.u=s,this.X=h}M(t){return new l(this.name,this.t,this.o,this.i,this.h,this.l,this.v,this.u,t)}}function I(r){var e=[];for(let t=0;t<r.length;t++){var i=\"I\".repeat(t),o=\"I\".repeat(r.length-t-1);\"X\"!==r[t]&&\"Y\"!==r[t]||e.push(i+\"X\"+o),\"Z\"!==r[t]&&\"Y\"!==r[t]||e.push(i+\"Z\"+o)}return e}class F{constructor(t,r,e,i){if(!(t instanceof l))throw new Error(\"!(gate instanceof Gate) gate=\"+t);if(!(e instanceof Float32Array))throw new Error(\"!(args instanceof Float32Array)\");if(!(i instanceof Uint32Array))throw new Error(\"!(targets instanceof Uint32Array)\");this.Z=t,this.tag=r,this.Y=e,this.R=i}toString(){return`${this.Z.name}[${this.tag}](${[...this.Y].join(\", \")}) `+[...this.R].join(\" \")}m(){return\"M\"===this.Z.name||\"MX\"===this.Z.name||\"MY\"===this.Z.name||\"MR\"===this.Z.name||\"MRX\"===this.Z.name||\"MRY\"===this.Z.name?this.R.length:\"MXX\"===this.Z.name||\"MYY\"===this.Z.name||\"MZZ\"===this.Z.name?this.R.length/2:t)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(his.Z.name.startsWith(\"MPP:\")?1:0}p(i){let r=this.Z.h;if(void 0===r){if(this.Z.name.startsWith(\"M\")){let r,e=(r=this.Z.name.startsWith(\"MPP:\")?this.Z.name.substring(4):this.Z.name.substring(1),0);for(let t=0;t<i.length;t++){var o=\"XYZ\".indexOf(i[t]),a=\"XYZ\".indexOf(r[t]);0<=o&&0<=a&&o!==a&&e++}return e%2!=0?\"ERR:\"+i:i}if(this.Z.name.startsWith(\"SPP:\")||this.Z.name.startsWith(\"SPP_DAG:\")){var t=this.Z.name.startsWith(\"SPP_DAG:\"),n=this.Z.name.substring(t?8:4);let r=0,e=\"\";for(let t=0;t<i.length;t++){var s=\"IXYZ\".indexOf(i[t]),h=\"IXYZ\".indexOf(n[t]);0<s&&0<h&&s!==h&&r++,e+=\"IXYZ\"[s^h]}return r%2!=0?e:i}if(\"POLYGON\"===this.Z.name)return i;throw new Error(this.Z.name)}if(i.length!==this.Z.t)throw new Error(\"before.length !== this.gate.num_qubits\");if(r.has(i))return r.get(i);let e=I(i);var l,f=[0,0];for(l of e=e.map(t=>r.get(t)))for(let t=0;t<i.length;t++)\"X\"===l[t]&&(f[t]^=1),\"Y\"===l[t]&&(f[t]^=3),\"Z\"===l[t]&&(f[t]^=2);let v=\"\";for(let t=0;t<i.length;t++)v+=\"IXZY\"[f[t]];return v}I(t,r){r.save();try{var e,i;this.)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(Z.u(this,t,r),\"\"!==this.tag&&0<this.R.length&&([e,i]=t(this.R[0]),r.fillText(this.tag,e,i+16))}finally{r.restore()}}}const P=50,Rt=10,N=-P+Math.floor(P/4)+.5,yt=-P+Math.floor(P/4)+.5;function a(t,r,e){void 0!==r&&void 0!==e&&(t.strokeStyle=\"black\",t.fillStyle=\"white\",t.beginPath(),t.arc(r,e,Rt,0,2*Math.PI),t.fill(),t.stroke(),t.beginPath(),t.moveTo(r,e-Rt),t.lineTo(r,e+Rt),t.stroke(),t.beginPath(),t.moveTo(r-Rt,e),t.lineTo(r+Rt,e),t.stroke())}function n(t,r,e){void 0!==r&&void 0!==e&&(t.strokeStyle=\"black\",t.fillStyle=\"#AAA\",t.beginPath(),t.moveTo(r,e+Rt),t.lineTo(r+Rt,e-Rt),t.lineTo(r-Rt,e-Rt),t.lineTo(r,e+Rt),t.stroke(),t.fill())}function s(t,r,e){void 0!==r&&void 0!==e&&(t.fillStyle=\"black\",t.beginPath(),t.arc(r,e,Rt,0,2*Math.PI),t.fill())}function b(t,r,e){var i;void 0!==r&&void 0!==e&&(t.fillStyle=\"black\",t.strokeStyle=\"black\",t.beginPath(),t.arc(r,e,Rt,0,2*Math.PI),t.fill(),t.stroke(),i=.4*Rt,t.strokeStyle=\"white\",t.lineWidth=3,t.beginPath(),t.moveTo(r-i,e-i),t.lineTo(r+i,e+i),t.stroke(),t.moveTo(r-i,e+)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(i),t.lineTo(r+i,e-i),t.stroke(),t.lineWidth=1)}function h(t,r,e){var i;void 0!==r&&void 0!==e&&(t.fillStyle=\"#888\",t.strokeStyle=\"#222\",t.beginPath(),t.arc(r,e,Rt,0,2*Math.PI),t.fill(),t.stroke(),i=.4*Rt,t.lineWidth=3,t.strokeStyle=\"black\",t.beginPath(),t.moveTo(r-i,e-i),t.lineTo(r+i,e+i),t.stroke(),t.moveTo(r-i,e+i),t.lineTo(r+i,e-i),t.stroke(),t.lineWidth=1)}function _(t,r,e){var i;void 0!==r&&void 0!==e&&(i=Rt/3,t.strokeStyle=\"black\",t.beginPath(),t.moveTo(r-i,e-i),t.lineTo(r+i,e+i),t.stroke(),t.moveTo(r-i,e+i),t.lineTo(r+i,e-i),t.stroke())}function E(t,r,e){var i;void 0!==r&&void 0!==e&&(i=1.1*Rt,t.strokeRect(r-i,e-i,2*i,2*i))}function mt(t,r,e,i,o){var a,n,s,h,l;void 0===r||void 0===e||void 0===i||void 0===o?(E(t,r,e),E(t,i,o)):i<r||i===r&&o<e?mt(t,i,o,r,e):(n=i-r,h=s=(a=o-e)/(a=Math.sqrt(n*n+a*a))*14,l=-(n=n/a*14),t.beginPath(),t.moveTo(r,e),a<1.1*P?t.lineTo(i,o):t.bezierCurveTo(r+n+h,e+s+l,i-n+h,o-s+l,i,o),t.stroke())}function c(t,r,e,i,o){t.lineWidth=2,t.strokeStyle=\"black\",mt(t,r,e,i,o),t.lineWidth=1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(}function S(e,i){if(e.beginPath(),0!==i.length){var r=i.length;if(1===r){var[[o,a]]=i;e.arc(o,a,1.7*Rt,0,2*Math.PI)}else if(2===r){var[[o,a],[n,s]]=i,h=n-o,l=s-a,f=(n+o)/2,v=(s+a)/2;let t=-l,r=h;var c=t*t+r*r,c=(2500<c&&(c=50/Math.sqrt(c),t*=c,r*=c),f+.2*t-.2*h),d=v+.2*r-.2*l,w=f+.2*t+.2*h,u=v+.2*r+.2*l,X=f-.2*t-.2*h,M=v-.2*r-.2*l,f=f-.2*t+.2*h,h=v-.2*r+.2*l;e.moveTo(o,a),e.bezierCurveTo(c,d,w,u,n,s),e.bezierCurveTo(f,h,X,M,o,a)}else{var[v,l]=i[r-1];e.moveTo(v,l);for(let t=0;t<r;t++){var[Z,Y]=i[t];e.lineTo(Z,Y)}}}}function pt(r,e,i){let o,a,n,s;if(r<0&&void 0!==i){let t=i.get(e);void 0===t&&(t=0),i.set(e,t+1),o=9.5-Math.round(t%3.9*5),a=9.5-Math.round(Math.floor(t/4)%3.8*5),n=3,s=3,r<-1<<28&&(o+=2,n+=4,a+=2,s+=4)}else 0===r?(o=Rt,a=Rt+5,n=2*Rt,s=5):1===r?(o=-Rt,a=Rt,n=5,s=2*Rt):2===r?(o=Rt,a=-Rt,n=2*Rt,s=5):3===r?(o=Rt+5,a=Rt,n=5,s=2*Rt):(o=Math.cos(.6*r)*Rt*1.7,a=Math.sin(.6*r)*Rt*1.7,n=5,s=5,o+=n/2,a+=s/2);return{dx:o,dy:a,_:n,A:s}}function A(s){return(t,r,e)=>{var i,o,a,[r,n]=r(t.R[0]);void 0!==r&&void 0!=)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(=n&&({dx:t,dy:i,_:o,A:a}=pt(t.Y[0]),e.fillStyle=s,o===a?e.fillRect(r-t-2,n-i-2,o+4,a+4):(t=r+(t<0?1:-1)*Rt,i=n+(i<0?1:-1)*Rt,o=t+(o>Rt?1:0)*Rt*2,a=i+(a>Rt?1:0)*Rt*2,e.beginPath(),e.moveTo(r,n),e.lineTo(t,i),e.lineTo(o,a),e.lineTo(r,n),e.fill()))}}function*k(){yield new l(\"ISWAP\",2,!0,!1,new Map([[\"IX\",\"YZ\"],[\"IZ\",\"ZI\"],[\"XI\",\"ZY\"],[\"ZI\",\"IZ\"]]),(t,r)=>t.k(r),(t,r)=>t.k(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),h(e,i,o),h(e,r,t)}),yield new l(\"ISWAP_DAG\",2,!0,!1,new Map([[\"IX\",\"YZ\"],[\"IZ\",\"ZI\"],[\"XI\",\"ZY\"],[\"ZI\",\"IZ\"]]),(t,r)=>t.k(r),(t,r)=>t.k(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),h(e,i,o),h(e,r,t)}),yield new l(\"SWAP\",2,!0,!1,new Map([[\"IX\",\"XI\"],[\"IZ\",\"ZI\"],[\"XI\",\"IX\"],[\"ZI\",\"IZ\"]]),(t,r)=>t.g(r),(t,r)=>t.g(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),_(e,i,o),_(e,r,t)}),yield new l(\"CXSWAP\",2,!0,!1,new Map([[\"IX\",\"XI\"],[\"IZ\",\"ZZ\"],[\"XI\",\"XX\"],[\"ZI\",\"IZ\"]]),(t,r)=>t.C(r),(t,r)=>t.S(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),b(e,i,o))CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(,i=e,o=t,void 0!==(e=r)&&void 0!==o&&(i.fillStyle=\"white\",i.strokeStyle=\"black\",i.beginPath(),i.arc(e,o,Rt,0,2*Math.PI),i.fill(),i.stroke(),t=.4*Rt,i.strokeStyle=\"black\",i.lineWidth=3,i.beginPath(),i.moveTo(e-t,o-t),i.lineTo(e+t,o+t),i.stroke(),i.moveTo(e-t,o+t),i.lineTo(e+t,o-t),i.stroke(),i.lineWidth=1)}),yield new l(\"CZSWAP\",2,!0,!1,new Map([[\"IX\",\"XZ\"],[\"IZ\",\"ZI\"],[\"XI\",\"ZX\"],[\"ZI\",\"IZ\"]]),(t,r)=>t.P(r),(t,r)=>t.P(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),b(e,i,o),b(e,r,t)})}function*g(){yield new l(\"CX\",2,!0,!1,new Map([[\"IX\",\"IX\"],[\"IZ\",\"ZZ\"],[\"XI\",\"XX\"],[\"ZI\",\"ZI\"]]),(t,r)=>t.O(r),(t,r)=>t.O(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),s(e,i,o),a(e,r,t)}),yield new l(\"CY\",2,!0,!1,new Map([[\"IX\",\"ZX\"],[\"IZ\",\"ZZ\"],[\"XI\",\"XY\"],[\"ZI\",\"ZI\"]]),(t,r)=>t.T(r),(t,r)=>t.T(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),s(e,i,o),n(e,r,t)}),yield new l(\"XCX\",2,!0,!1,new Map([[\"IX\",\"IX\"],[\"IZ\",\"XZ\"],[\"XI\",\"XI\"],[\"ZI\",\"ZX\"]]),(t,r)=>t.N(r),(t,r)=>t.N(r),(t,r,e)=>{var[i)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),a(e,i,o),a(e,r,t)}),yield new l(\"XCY\",2,!0,!1,new Map([[\"IX\",\"XX\"],[\"IZ\",\"XZ\"],[\"XI\",\"XI\"],[\"ZI\",\"ZY\"]]),(t,r)=>t.D(r),(t,r)=>t.D(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),a(e,i,o),n(e,r,t)}),yield new l(\"YCY\",2,!0,!1,new Map([[\"IX\",\"YX\"],[\"IZ\",\"YZ\"],[\"XI\",\"XY\"],[\"ZI\",\"ZY\"]]),(t,r)=>t.L(r),(t,r)=>t.L(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),n(e,i,o),n(e,r,t)}),yield new l(\"CZ\",2,!0,!1,new Map([[\"IX\",\"ZX\"],[\"IZ\",\"IZ\"],[\"XI\",\"XZ\"],[\"ZI\",\"ZI\"]]),(t,r)=>t.F(r),(t,r)=>t.F(r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),s(e,i,o),s(e,r,t)}),yield new l(\"MR\",1,!0,!1,new Map([[\"X\",\"ERR:I\"],[\"Y\",\"ERR:I\"],[\"Z\",\"I\"]]),(t,r)=>t.U(\"Z\",r),(t,r)=>t.U(\"Z\",r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"gray\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"MR\",r,t)}),yield new l(\"MRY\",1,!0,!1,new Map([[\"X\",\"ERR:I\"],[\"Y\",\")CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(I\"],[\"Z\",\"ERR:I\"]]),(t,r)=>t.U(\"Y\",r),(t,r)=>t.U(\"Y\",r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"gray\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"MRY\",r,t)}),yield new l(\"MRX\",1,!0,!1,new Map([[\"X\",\"I\"],[\"Y\",\"ERR:I\"],[\"Z\",\"ERR:I\"]]),(t,r)=>t.U(\"X\",r),(t,r)=>t.U(\"X\",r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"gray\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"MRX\",r,t)}),yield new l(\"H\",1,!0,!1,new Map([[\"X\",\"Z\"],[\"Z\",\"X\"]]),(t,r)=>t.G(r),(t,r)=>t.G(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"H\",r,t)}),yield new l(\"H_NXZ\",1,!0,!1,new Map([[\"X\",\"Z\"],[\"Z\",\"X\"]]),(t,r)=>t.G(r),(t,r)=>t.G(r),(t,r,e)=>{va)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(r[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"H\",r,t-Rt/3),e.fillText(\"NXZ\",r,t+Rt/3)}),yield new l(\"H_XY\",1,!0,!1,new Map([[\"X\",\"Y\"],[\"Z\",\"Z\"]]),(t,r)=>t.H(r),(t,r)=>t.H(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"H\",r,t-Rt/3),e.fillText(\"XY\",r,t+Rt/3)}),yield new l(\"H_NXY\",1,!0,!1,new Map([[\"X\",\"Y\"],[\"Z\",\"Z\"]]),(t,r)=>t.H(r),(t,r)=>t.H(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"H\",r,t-Rt/3),e.fillText(\"NXY\",r,t+Rt/3)}),yield new l(\"H_YZ\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Z\",\"Y\"]]),(t,r)=>t.K(r),(t,r)=>t.K(r),(t,r,e))CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"H\",r,t-Rt/3),e.fillText(\"YZ\",r,t+Rt/3)}),yield new l(\"H_NYZ\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Z\",\"Y\"]]),(t,r)=>t.K(r),(t,r)=>t.K(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"H\",r,t-Rt/3),e.fillText(\"NYZ\",r,t+Rt/3)}),yield new l(\"POLYGON\",void 0,!1,!0,void 0,()=>{},()=>{},(t,r,e)=>{var i,o=[];for(i of t.R){var[a,n]=r(i);o.push([a-=.5,n-=.5])}S(e,o),e.globalAlpha*=t.Y[3],e.fillStyle=`rgb(${255*t.Y[0]},${255*t.Y[1]},${255*t.Y[2]})`,e.fill()}),yield new l(\"DETECTOR\",void 0,!1,!0,void 0,()=>{},()=>{},(t,r,e)=>{}),yield new l(\"OBSERVABLE_INCLUDE\",void 0,!1,!0,void 0,()=>{},()=>{},(t,r,e)=>{}),yield new l(\"MARKX\",1,!0,!0,void 0,()=>{},()=>{},A(\"r)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ed\")),yield new l(\"MARKY\",1,!0,!0,void 0,()=>{},()=>{},A(\"green\")),yield new l(\"MARKZ\",1,!0,!0,void 0,()=>{},()=>{},A(\"blue\")),yield new l(\"MARK\",1,!1,!0,void 0,()=>{},()=>{},(t,r,e)=>{var[r,t]=r(t.R[0]);void 0!==r&&void 0!==t&&(e.fillStyle=\"magenta\",e.fillRect(r-Rt,t-Rt,Rt,Rt))}),yield new l(\"MXX\",2,!0,!1,new Map([[\"II\",\"II\"],[\"IX\",\"IX\"],[\"IY\",\"ERR:IY\"],[\"IZ\",\"ERR:IZ\"],[\"XI\",\"XI\"],[\"XX\",\"XX\"],[\"XY\",\"ERR:XY\"],[\"XZ\",\"ERR:XZ\"],[\"YI\",\"ERR:YI\"],[\"YX\",\"ERR:YX\"],[\"YY\",\"YY\"],[\"YZ\",\"YZ\"],[\"ZI\",\"ERR:ZI\"],[\"ZX\",\"ERR:ZX\"],[\"ZY\",\"ZY\"],[\"ZZ\",\"ZZ\"]]),(t,r)=>t.$(\"XX\",r),(t,r)=>t.$(\"XX\",r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),e.fillStyle=\"gray\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt,2*Rt,2*Rt),e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"MXX\",i,o),e.fillText(\"MXX\",r,t)}),yield new l(\"MYY\",2,!0,!1,new Map([[\"II\",\"II\"],[\"IX\",\"ERR:IX\"],[\"IY\",\"IY\"],[\"IZ\",\"ERR:IZ\"],[\"XI\",\"ERR)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(:XI\"],[\"XX\",\"XX\"],[\"XY\",\"ERR:XY\"],[\"XZ\",\"XZ\"],[\"YI\",\"YI\"],[\"YX\",\"ERR:YX\"],[\"YY\",\"YY\"],[\"YZ\",\"ERR:YZ\"],[\"ZI\",\"ERR:ZI\"],[\"ZX\",\"ZX\"],[\"ZY\",\"ERR:ZY\"],[\"ZZ\",\"ZZ\"]]),(t,r)=>t.$(\"YY\",r),(t,r)=>t.$(\"YY\",r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),e.fillStyle=\"gray\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt,2*Rt,2*Rt),e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"MYY\",i,o),e.fillText(\"MYY\",r,t)}),yield new l(\"MZZ\",2,!0,!1,new Map([[\"II\",\"II\"],[\"IX\",\"ERR:IX\"],[\"IY\",\"ERR:IY\"],[\"IZ\",\"IZ\"],[\"XI\",\"ERR:XI\"],[\"XX\",\"XX\"],[\"XY\",\"XY\"],[\"XZ\",\"ERR:XZ\"],[\"YI\",\"ERR:YI\"],[\"YX\",\"YX\"],[\"YY\",\"YY\"],[\"YZ\",\"ERR:YZ\"],[\"ZI\",\"ZI\"],[\"ZX\",\"ERR:ZX\"],[\"ZY\",\"ERR:ZY\"],[\"ZZ\",\"ZZ\"]]),(t,r)=>t.$(\"ZZ\",r),(t,r)=>t.$(\"ZZ\",r),(t,r,e)=>{var[i,o]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,i,o,r,t),e.fillStyle=\"gray\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(,2*Rt,2*Rt),e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"MZZ\",i,o),e.fillText(\"MZZ\",r,t)}),yield new l(\"ERR\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Z\",\"Z\"]]),()=>{},()=>{},(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"red\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"ERR\",r,t)}),yield new l(\"I\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Z\",\"Z\"]]),()=>{},()=>{},(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"white\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"I\",r,t)}),yield new l(\"X\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Z\",\"Z\"]]),()=>{},()=>{},(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"white\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillTe)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(xt(\"X\",r,t)}),yield new l(\"Y\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Z\",\"Z\"]]),()=>{},()=>{},(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"white\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"Y\",r,t)}),yield new l(\"Z\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Z\",\"Z\"]]),()=>{},()=>{},(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"white\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"Z\",r,t)}),yield new l(\"S\",1,!0,!1,new Map([[\"X\",\"Y\"],[\"Z\",\"Z\"]]),(t,r)=>t.H(r),(t,r)=>t.H(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"S\",r,t)}),yield new l(\"S_DAG\",1,!0,!1,new Map([[\"X\",\"Y\"],[\"Z\",\"Z\"]]),(t,r)=>t.H(r),(t,r)=>t.H(r),(t,r,e)=>{var[r,t]=r(t.R[0]);)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"S†\",r,t)}),yield new l(\"SQRT_X\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Z\",\"Y\"]]),(t,r)=>t.K(r),(t,r)=>t.K(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√X\",r,t)}),yield new l(\"SQRT_X_DAG\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Z\",\"Y\"]]),(t,r)=>t.K(r),(t,r)=>t.K(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√X†\",r,t)}),yield new l(\"SQRT_Y\",1,!0,!1,new Map([[\"X\",\"Z\"],[\"Z\",\"X\"]]),(t,r)=>t.G(r),(t,r)=>t.G(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√Y\",r,t)}),yield new l(\"SQRT_Y_DAG\",1,!0,!1,new Map([[\"X\",\"Z\"],[\"Z\",\"X\"]]),(t,r)=>t.G(r),(t,r)=>t.G(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"yellow\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√Y†\",r,t)}),yield new l(\"R\",1,!0,!1,new Map([[\"X\",\"ERR:I\"],[\"Y\",\"ERR:I\"],[\"Z\",\"ERR:I\"]]),(t,r)=>t.B(r),(t,r)=>t.U(\"Z\",r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"gray\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"R\",r,t)}),yield new l(\"RX\",1,!0,!1,new Map([[\"X\",\"ERR:I\"],[\"Y\",\"ERR:I\"],[\"Z\",\"ERR:I\"]]),(t,r)=>t.B(r),(t,r)=>t.U(\"X\",r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"gray\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillS)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(tyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"RX\",r,t)}),yield new l(\"RY\",1,!0,!1,new Map([[\"X\",\"ERR:I\"],[\"Y\",\"ERR:I\"],[\"Z\",\"ERR:I\"]]),(t,r)=>t.B(r),(t,r)=>t.U(\"Y\",r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"gray\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"RY\",r,t)}),yield new l(\"M\",1,!0,!1,new Map([[\"X\",\"ERR:X\"],[\"Y\",\"ERR:Y\"],[\"Z\",\"Z\"]]),(t,r)=>t.$(\"Z\",r),(t,r)=>t.$(\"Z\",r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"gray\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"M\",r,t),e.textAlign=\"left\"}),yield new l(\"MX\",1,!0,!1,new Map([[\"X\",\"X\"],[\"Y\",\"ERR:Y\"],[\"Z\",\"ERR:Z\"]]),(t,r)=>t.$(\"X\",r),(t,r)=>t.$(\"X\",r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"gray\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"MX\",r,t),e.textAlign=\"left\"}),yield new l(\"MY\",1,!0,!1,new Map([[\"X\",\"ERR:X\"],[\"Y\",\"Y\"],[\"Z\",\"ERR:Z\"]]),(t,r)=>t.$(\"Y\",r),(t,r)=>t.$(\"Y\",r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"gray\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"MY\",r,t),e.textAlign=\"left\"}),yield new l(\"II\",2,!0,!1,new Map([[\"IX\",\"IX\"],[\"IZ\",\"IZ\"],[\"XI\",\"XI\"],[\"ZI\",\"ZI\"]]),(t,r)=>{},(t,r)=>{},(t,r,e)=>{var i,o,[a,n]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,a,n,r,t);for([i,o]of[[a,n],[r,t]])e.fillStyle=\"white\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"II\",i,o)}),yield new l(\"SQRT_XX\",2,!0,!1,new Map([[\"IX\",\"IX\"],[\"IZ\",\"XY\"],[\"XI\",\"XI\"],[\"ZI\",\"YX\"]]),(t,r)=>t.q(r),(t,r)=>t.q(r),(t,r,e)=>{var i,o,[a,n]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,a,n,r,t);for([i,o)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(]of[[a,n],[r,t]])e.fillStyle=\"yellow\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√XX\",i,o)}),yield new l(\"SQRT_XX_DAG\",2,!0,!1,new Map([[\"IX\",\"IX\"],[\"IZ\",\"XY\"],[\"XI\",\"XI\"],[\"ZI\",\"YX\"]]),(t,r)=>t.q(r),(t,r)=>t.q(r),(t,r,e)=>{var i,o,[a,n]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,a,n,r,t);for([i,o]of[[a,n],[r,t]])e.fillStyle=\"yellow\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√XX†\",i,o)}),yield new l(\"SQRT_YY\",2,!0,!1,new Map([[\"IX\",\"YZ\"],[\"IZ\",\"YX\"],[\"XI\",\"ZY\"],[\"ZI\",\"XY\"]]),(t,r)=>t.W(r),(t,r)=>t.W(r),(t,r,e)=>{var i,o,[a,n]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,a,n,r,t);for([i,o]of[[a,n],[r,t]])e.fillStyle=\"yellow\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√YY\",i,o)})CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(),yield new l(\"SQRT_YY_DAG\",2,!0,!1,new Map([[\"IX\",\"YZ\"],[\"IZ\",\"YX\"],[\"XI\",\"ZY\"],[\"ZI\",\"XY\"]]),(t,r)=>t.W(r),(t,r)=>t.W(r),(t,r,e)=>{var i,o,[a,n]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,a,n,r,t);for([i,o]of[[a,n],[r,t]])e.fillStyle=\"yellow\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√YY†\",i,o)}),yield new l(\"SQRT_ZZ\",2,!0,!1,new Map([[\"IX\",\"ZY\"],[\"IZ\",\"IZ\"],[\"XI\",\"YZ\"],[\"ZI\",\"ZI\"]]),(t,r)=>t.V(r),(t,r)=>t.V(r),(t,r,e)=>{var i,o,[a,n]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,a,n,r,t);for([i,o]of[[a,n],[r,t]])e.fillStyle=\"yellow\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√ZZ\",i,o)}),yield new l(\"SQRT_ZZ_DAG\",2,!0,!1,new Map([[\"IX\",\"ZY\"],[\"IZ\",\"IZ\"],[\"XI\",\"YZ\"],[\"ZI\",\"ZI\"]]),(t,r)=>t.V(r),(t,r)=>t.V(r),(t,r,e)=>{var i,o,[a,n]=r(t.R[0]),[r,t]=r(t.R[1]);c(e,a,n,r,t);for([i,o]of[[a,n],[r,t]])e.)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(fillStyle=\"yellow\",e.fillRect(i-Rt,o-Rt,2*Rt,2*Rt),e.strokeStyle=\"black\",e.strokeRect(i-Rt,o-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"√ZZ†\",i,o)}),yield*k(),yield new l(\"C_XYZ\",1,!0,!1,new Map([[\"X\",\"Y\"],[\"Z\",\"X\"]]),(t,r)=>t.j(r),(t,r)=>t.J(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"teal\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"C\",r,t-Rt/3),e.fillText(\"XYZ\",r,t+Rt/3)}),yield new l(\"C_NXYZ\",1,!0,!1,new Map([[\"X\",\"Y\"],[\"Z\",\"X\"]]),(t,r)=>t.j(r),(t,r)=>t.J(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"teal\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"C\",r,t-Rt/3),e.fillText(\"NXYZ\",r,t+Rt/3)}),yield new l(\"C_XNYZ\",1,!0,!1,new Map([[\"X\",\"Y\"],[\"Z\",\"X\"]]),(t,r)=>t.j(r),(t,r)=>t.J(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"t)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(eal\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"C\",r,t-Rt/3),e.fillText(\"XNYZ\",r,t+Rt/3)}),yield new l(\"C_XYNZ\",1,!0,!1,new Map([[\"X\",\"Y\"],[\"Z\",\"X\"]]),(t,r)=>t.j(r),(t,r)=>t.J(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"teal\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"C\",r,t-Rt/3),e.fillText(\"XYNZ\",r,t+Rt/3)}),yield new l(\"C_ZYX\",1,!0,!1,new Map([[\"X\",\"Z\"],[\"Z\",\"Y\"]]),(t,r)=>t.J(r),(t,r)=>t.j(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"teal\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"C\",r,t-Rt/3),e.fillText(\"ZYX\",r,t+Rt/3)}),yield new l(\"C_ZYNX\",1,!0,!1,new Map([[\"X\",\"Z\"],[\"Z\",\"Y\"]]),(t,r)=>t.J(r),(t,r)=>t.j(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillSt)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(yle=\"teal\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"C\",r,t-Rt/3),e.fillText(\"ZYNX\",r,t+Rt/3)}),yield new l(\"C_ZNYX\",1,!0,!1,new Map([[\"X\",\"Z\"],[\"Z\",\"Y\"]]),(t,r)=>t.J(r),(t,r)=>t.j(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"teal\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"C\",r,t-Rt/3),e.fillText(\"ZNYX\",r,t+Rt/3)}),yield new l(\"C_NZYX\",1,!0,!1,new Map([[\"X\",\"Z\"],[\"Z\",\"Y\"]]),(t,r)=>t.J(r),(t,r)=>t.j(r),(t,r,e)=>{var[r,t]=r(t.R[0]);e.fillStyle=\"teal\",e.fillRect(r-Rt,t-Rt,2*Rt,2*Rt),e.fillStyle=\"black\",e.strokeStyle=\"black\",e.strokeRect(r-Rt,t-Rt,2*Rt,2*Rt),e.textAlign=\"center\",e.textBaseline=\"middle\",e.fillText(\"C\",r,t-Rt/3),e.fillText(\"NZYX\",r,t+Rt/3)})}const B=function(){var t,r=new Map;for(t of g())r.set(t.name,t);return r.set(\"MZ\",r.get(\"M\")),r.set(\"RZ\",r.get(\"R\")),)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(r.set(\"MRZ\",r.get(\"MR\")),r}(),H=((t=new Map).set(\"CNOT\",{name:\"CX\"}),t.set(\"MZ\",{name:\"M\"}),t.set(\"MRZ\",{name:\"MR\"}),t.set(\"RZ\",{name:\"R\"}),t.set(\"H_XZ\",{name:\"H\"}),t.set(\"SQRT_Z\",{name:\"S\"}),t.set(\"SQRT_Z_DAG\",{name:\"S_DAG\"}),t.set(\"ZCX\",{name:\"CX\"}),t.set(\"ZCY\",{name:\"CY\"}),t.set(\"ZCZ\",{name:\"CZ\"}),t.set(\"SWAPCZ\",{name:\"CZSWAP\"}),t.set(\"XCZ\",{name:\"CX\",tt:!0}),t.set(\"YCX\",{name:\"XCY\",tt:!0}),t.set(\"YCZ\",{name:\"CY\",tt:!0}),t.set(\"SWAPCX\",{name:\"CXSWAP\",tt:!0}),t.set(\"CORRELATED_ERROR\",{rt:!0}),t.set(\"DEPOLARIZE1\",{rt:!0}),t.set(\"DEPOLARIZE2\",{rt:!0}),t.set(\"E\",{rt:!0}),t.set(\"ELSE_CORRELATED_ERROR\",{rt:!0}),t.set(\"PAULI_CHANNEL_1\",{rt:!0}),t.set(\"PAULI_CHANNEL_2\",{rt:!0}),t.set(\"X_ERROR\",{rt:!0}),t.set(\"I_ERROR\",{rt:!0}),t.set(\"II_ERROR\",{rt:!0}),t.set(\"Y_ERROR\",{rt:!0}),t.set(\"Z_ERROR\",{rt:!0}),t.set(\"HERALDED_ERASE\",{rt:!0}),t.set(\"HERALDED_PAULI_CHANNEL_1\",{rt:!0}),t.set(\"MPAD\",{rt:!0}),t.set(\"SHIFT_COORDS\",{rt:!0}),t);function C(t,r){var e,i=new Map;for(e of t){var o=r(e),a=i.get(o);void 0===a?i.set(o,[e)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(]):a.push(e)}return i}class U{constructor(){this.et=new Map,this.it=[]}toString(){let t=\"Layer {\\n\";t+=\"    id_ops {\\n\";for(var[r,e]of this.et.entries())t+=`        ${r}: ${e}\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(`;t+=\"    }\\n    markers {\\n\";for(var i of this.it)t+=`        ${i}\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(`;return t=t+\"    }\\n\"+\"}\"}ot(){let r=C(this.nt(),t=>{let r=t.Z.name;return(r=(r=r.startsWith(\"MPP:\")&&!B.has(r)?\"MPP\":r).startsWith(\"SPP:\")&&!B.has(r)?\"SPP\":r).startsWith(\"SPP_DAG:\")&&!B.has(r)&&(r=\"SPP_DAG\"),\"\"!==t.tag&&(r+=\"[\"+t.tag.replace(\"\\\\\",\"\\\\B\").replace(\"\\r\",\"\\\\r\").replace(\"\\n\",\"\\\\n\").replace(\"]\",\"\\\\C\")+\"]\"),0<t.Y.length&&(r+=\"(\"+[...t.Y].join(\",\")+\")\"),r});var t=[...r.keys()];return t.sort((t,r)=>{var e=t.startsWith(\"MARK\")||t.startsWith(\"POLY\"),i=r.startsWith(\"MARK\")||r.startsWith(\"POLY\");return e!==i?e<i?-1:1:t<r?-1:r<t?1:0}),new Map(t.map(t=>[t,r.get(t)]))}st(){var t=new U;return t.et=new Map(this.et),t.it=[...this.it],t}m(){let t=0;for(var[r,e]of this.et.entries())e.R[0]===r&&(t+=e.m());return t}ht(){var t,r=[\"M\",\"MX\",\"MY\",\"MR\",\"MRX\",\"MRY\",\"MXX\",\"MYY\",\"MZZ\",\"RX\",\"RY\",\"R\"];for(t of this.et.values())if(t.Z.name.startsWith(\"MPP:\")||-1!==r.indexOf(t.Z.name))return!0;return!1}lt(){var t,r=[\"M\",\"MX\",\"MY\",\"MR\",\"MRX\",\"MRY\",\"MXX\",\"MYY\",\"MZZ\",\"RX\",\"RY\",\"R\"];for(t of this.et.values())if(1===t.R.length&&-1)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(===r.indexOf(t.Z.name)&&0===t.m())return!0;return!1}ft(){var t,r=[\"MR\",\"MRX\",\"MRY\",\"RX\",\"RY\",\"R\"];for(t of this.et.values())if(-1!==r.indexOf(t.Z.name))return!0;return!1}vt(){var t,r=[\"M\",\"MX\",\"MY\",\"MR\",\"MRX\",\"MRY\",\"MXX\",\"MYY\",\"MZZ\"];for(t of this.et.values())if(t.Z.name.startsWith(\"MPP:\")||-1!==r.indexOf(t.Z.name))return!0;return!1}empty(){return 0===this.et.size&&0===this.it.length}ct(t){var r,e,i=new U;for(r of this.et.values())t(r)&&i.put(r);for(e of this.it)t(e)&&i.it.push(e);return i}dt(r){return this.ct(t=>!t.R.every(t=>!r(t)))}wt(e,t){var r,i,o=new Map,a=new Set;for(r of e.keys()){var n=e.get(r),s=this.et.get(r);if(void 0!==s){let r=\"\";for(var h of s.R){a.has(h),a.add(h);let t=e.get(h);void 0===t&&(t=\"I\"),r+=t}var l=s.p(r),f=l.startsWith(\"ERR:\");for(let t=0;t<s.R.length;t++){var v=s.R[t];f?o.set(v,\"ERR:\"+l[4+t]):o.set(v,l[t])}}else o.set(r,n)}for(i of this.it)if(\"MARKX\"===i.Z.name&&i.Y[0]===t){var c=i.R[0];let t=o.get(c);void 0===t||\"I\"===t?t=\"X\":\"X\"===t?t=\"I\":\"Y\"===t?t=\"Z\":\"Z\"===t&&(t=\"Y\"),o.set(c,t))CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(}else if(\"MARKY\"===i.Z.name&&i.Y[0]===t){c=i.R[0];let t=o.get(c);void 0===t||\"I\"===t?t=\"Y\":\"X\"===t?t=\"Z\":\"Y\"===t?t=\"I\":\"Z\"===t&&(t=\"X\"),o.set(c,t)}else if(\"MARKZ\"===i.Z.name&&i.Y[0]===t){var d=i.R[0];let t=o.get(d);void 0===t||\"I\"===t?t=\"Z\":\"X\"===t?t=\"Y\":\"Y\"===t?t=\"X\":\"Z\"===t&&(t=\"I\"),o.set(d,t)}return o}ut(){return 0===this.et.size&&0===this.it.length}Xt(r){if(this.it=this.it.filter(t=>-1===t.R.indexOf(r)),this.et.has(r)){var t,e=this.et.get(r);for(t of e.R)this.et.delete(t);return e}}Mt(r,e=void 0){this.it=this.it.filter(t=>void 0!==e&&t.Y[0]!==e||\"MARKX\"!==t.Z.name&&\"MARKY\"!==t.Z.name&&\"MARKZ\"!==t.Z.name||t.R[0]!==r)}put(t,r=!0){if(t.Z.i)\"MARKX\"!==t.Z.name&&\"MARKY\"!==t.Z.name&&\"MARKZ\"!==t.Z.name||this.Mt(t.R[0],t.Y[0]),this.it.push(t);else{for(var e of t.R)if(this.et.has(e)){if(!r)throw new Error(\"Collision\");this.Xt(e)}for(var i of t.R)this.et.set(i,t)}}*nt(){for(var t of this.et.keys()){var r=this.et.get(t);r.R[0]===t&&(yield r)}yield*this.it}}function D(t){let r=void 0,e=void 0;for(var[i,o]of t)(void 0=)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(==r||i<r||i===r&&o<e)&&(r=i,e=o);return[r,e]}function f(f){return new l(\"MPP:\"+f,f.length,!0,!1,void 0,(t,r)=>t.Zt(f,r),(t,r)=>t.Zt(f,r),(r,e,i)=>{let o=void 0,a=void 0;for(let t=0;t<r.R.length;t++){var[n,s]=e(r.R[t]);void 0!==o&&c(i,n,s,o,a),o=n,a=s}for(let t=0;t<r.R.length;t++){var[h,l]=e(r.R[t]);i.fillStyle=\"gray\",i.fillRect(h-Rt,l-Rt,2*Rt,2*Rt),i.strokeStyle=\"black\",i.strokeRect(h-Rt,l-Rt,2*Rt,2*Rt),i.fillStyle=\"black\",i.textAlign=\"center\",i.textBaseline=\"middle\",i.font=\"bold 12pt monospace\",i.fillText(f[t],h,l-1),i.font=\"5pt monospace\",i.fillText(\"MPP\",h,l+8)}})}const d=1e3,x=(new function(){}).toString(),L=\"!recursion-limit!\",z=10;function K(t,r){if(0===r)return L;if(t instanceof Map){var e,i,o=r,a=[];for([e,i]of t.entries()){if(a.length>d){a.push(\"[...]\");break}e=G(e,o-1),i=G(i,o-1);a.push(e+\": \"+i)}return`Map{${a.join(\", \")}}`}if(t instanceof Set){var n,s=r,h=[];for(n of t){if(h.length>d){h.push(\"[...]\");break}h.push(G(n,s-1))}return`Set{${h.join(\", \")}}`}if(void 0!==t[Symbol.iterator]){var l,f=r,v=[])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;for(l of t){if(v.length>d){v.push(\"[...]\");break}v.push(G(l,f-1))}return`${t=Array.isArray(t)?\"\":t.constructor.name}[${v.join(\", \")}]`}}function Q(t,r){try{var e=String(t);if(e!==x)return e}catch{}var i=t,o=r,a=[];for(s in i)if(i.hasOwnProperty(s)){if(a.length>d){a.push(\"[...]\");break}var n=i[s],s=G(s,o-1),n=G(n,o-1);a.push(s+\": \"+n)}return void 0===i.constructor?\"[an unknown non-primitive value with no constructor]\":(e=(e=i.constructor.name)==={}.constructor.name?\"\":`(Type: ${e})`)+`{${a.join(\", \")}}`}function G(t,r=z){return(null===(e=t)?\"null\":void 0===e?\"undefined\":\"string\"==typeof e?`\"${e}\"`:\"number\"==typeof e?\"\"+e:void 0)||K(t,r)||Q(t,r);var e}function $(t){let r=[];var e,i=()=>{\"\"!==o&&(r.push(o),o=\"\")};let o=\"\";for(e of t)\" \"===e?i():\"*\"===e?(i(),r.push(\"*\")):o+=e;return i(),r}function q(e){var t=[];let i=0;for(;i<e.length;){let r=i+1;for(;r<e.length&&\"*\"===e[r];)r+=2;if(r>e.length)throw Error(`Dangling combiner in ${e}.`);var o=[];for(let t=i;t<r;t+=2){if(\"*\"===e[t]){if(0===t)throw Error(`Leading co)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(mbiner in ${e}.`);throw Error(`Adjacent combiners in ${e}.`)}o.push(e[t])}t.push(o),i=r}return t}function W(t,r,e,i){let o=\"\";var a,n=[];for(a of e){if(\"X\"!==(a=\"!\"===a[0]?a.substring(1):a)[0]&&\"Y\"!==a[0]&&\"Z\"!==a[0])throw Error(\"Non-Pauli target given to MPP: \"+e);o+=a[0];var s=parseInt(a.substring(1));if(s!=s)throw Error(\"Non-Pauli target given to MPP: \"+e);n.push(s)}let h=void 0;return void 0===(h=void 0===(h=i?B.get(\"M\"+o):h)?B.get(\"MPP:\"+o):h)&&(h=f(o)),new F(h,t,r,new Uint32Array(n))}function V(t,r,e,i){let o=\"\";var a,f,v,n=[];for(a of i){if(\"X\"!==(a=\"!\"===a[0]?a.substring(1):a)[0]&&\"Y\"!==a[0]&&\"Z\"!==a[0])throw Error(\"Non-Pauli target given to SPP: \"+i);o+=a[0];var s=parseInt(a.substring(1));if(s!=s)throw Error(\"Non-Pauli target given to SPP: \"+i);n.push(s)}let h=B.get((e?\"SPP_DAG:\":\"SPP:\")+o);return void 0===h&&(h=(f=o,v=e,new l((v?\"SPP_DAG:\":\"SPP:\")+f,f.length,!0,!1,void 0,(t,r)=>t.Yt(f,r),(t,r)=>t.Yt(f,r),(r,e,i)=>{let o=void 0,a=void 0;for(let t=0;t<r.R.length;t++){var[n,s]=e(r.R[t]);void 0!==o&&c(i)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(,n,s,o,a),o=n,a=s}for(let t=0;t<r.R.length;t++){var[h,l]=e(r.R[t]);i.fillStyle=\"gray\",i.fillRect(h-Rt,l-Rt,2*Rt,2*Rt),i.strokeStyle=\"black\",i.strokeRect(h-Rt,l-Rt,2*Rt,2*Rt),i.fillStyle=\"black\",i.textAlign=\"center\",i.textBaseline=\"middle\",i.font=\"bold 12pt monospace\",i.fillText(f[t],h,l-1),i.font=\"5pt monospace\",i.fillText(v?\"SPP†\":\"SPP\",h,l+8)}}))),new F(h,t,r,new Uint32Array(n))}class u{constructor(t,r=[]){if(!(t instanceof Float64Array))throw new Error(\"!(qubitCoords instanceof Float64Array)\");if(!Array.isArray(r))throw new Error(\"!Array.isArray(layers)\");if(!r.every(t=>t instanceof U))throw new Error(\"!layers.every(e => e instanceof Layer)\");this.Rt=t,this.yt=r}static It(t){t=t.replaceAll(\";\",\"\\n\").replaceAll(\"#!pragma ERR\",\"ERR\").replaceAll(\"#!pragma MARK\",\"MARK\").replaceAll(\"#!pragma POLYGON\",\"POLYGON\").replaceAll(\"_\",\" \").replaceAll(\"Q(\",\"QUBIT_COORDS(\").replaceAll(\"DT\",\"DETECTOR\").replaceAll(\"OI\",\"OBSERVABLE_INCLUDE\").replaceAll(\" COORDS\",\"_COORDS\").replaceAll(\" ERROR\",\"_ERROR\").replaceAll(\"C XYZ\",\"C_)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(XYZ\").replaceAll(\"C NXYZ\",\"C_NXYZ\").replaceAll(\"C XNYZ\",\"C_XNYZ\").replaceAll(\"C XYNZ\",\"C_XYNZ\").replaceAll(\"H XY\",\"H_XY\").replaceAll(\"H XZ\",\"H_XZ\").replaceAll(\"H YZ\",\"H_YZ\").replaceAll(\"H NXY\",\"H_NXY\").replaceAll(\"H NXZ\",\"H_NXZ\").replaceAll(\"H NYZ\",\"H_NYZ\").replaceAll(\" INCLUDE\",\"_INCLUDE\").replaceAll(\"SQRT \",\"SQRT_\").replaceAll(\" DAG \",\"_DAG \").replaceAll(\"C ZYX\",\"C_ZYX\").replaceAll(\"C NZYX\",\"C_NZYX\").replaceAll(\"C ZNYX\",\"C_ZNYX\").replaceAll(\"C ZYNX\",\"C_ZYNX\").split(\"\\n\");let T=[new U],N=0,D=new Map,x=new Set,s=(e,i,o,r)=>{T[T.length-1].empty()||T.push(new U);for(let t=0;t<r;t++){for(let r=i;r<o;r++){let t=e[r];var a,n;(t=t.split(\"#\")[0].trim()).toLowerCase().startsWith(\"repeat \")?(a=parseInt(t.split(\" \")[1]),n=((e,t,i)=>{let o=0;for(let r=t;r<i;r++){let t=e[r];if((t=t.split(\"#\")[0].trim()).toLowerCase().startsWith(\"repeat \"))o++;else if(\"}\"===t&&0===--o)return r}throw Error(\"Repeat block didn't end\")})(e,r,o),s(e,r+1,n,a),r=n):(o=>{let a=[],n=[],e=\"\",s=\"\",t=o.indexOf(\" \"),r=o.indexOf(\"(\"),i=o.indexOf(\"[\"),h)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(=o.indexOf(\"]\");if(i!==-1&&t!==-1&&t<i)i=-1;if(i!==-1&&r!==-1&&r<i)i=-1;if(i!==-1&&h>i){e=o.substring(i+1,h).replaceAll(\"\\\\C\",\"]\").replaceAll(\"\\\\r\",\"\\r\").replaceAll(\"\\\\n\",\"\\n\").replaceAll(\"\\\\B\",\"\\\\\");o=o.substring(0,i)+\" \"+o.substring(h+1)}if(o.indexOf(\")\")!==-1){let[t,r]=o.split(\")\");let[e,i]=t.split(\"(\");s=e.trim();a=i.split(\",\").map(t=>t.trim()).map(parseFloat);n=$(r)}else{let t=o.split(\" \").map(t=>t.trim()).filter(t=>t!==\"\");if(t.length===0)return;let[r,...e]=t;s=r.trim();a=[];n=e.flatMap($)}let l=false;if(\"\"!==s){0<a.length&&-1!==[\"M\",\"MX\",\"MY\",\"MZ\",\"MR\",\"MRX\",\"MRY\",\"MRZ\",\"MPP\",\"MPAD\"].indexOf(s)&&(a=[]);var f=H.get(s),v;if(void 0!==f){if(f.rt)return;if(void 0===f.name)throw new Error(`Unimplemented alias ${s}: ${G(f)}.`);l=void 0!==f.tt&&f.tt,s=f.name}else{if(\"TICK\"===s)return T.push(new U);if(\"MPP\"===s){var c=q(n),d;let r=T[T.length-1];for(d of c){var w=W(e,new Float32Array(a),d,!1);try{r.put(w,!1)}catch(t){T.push(new U),(r=T[T.length-1]).put(w,!1)}L.push({bt:T.length-1,_t:w.R})}return}if(\"DETECTOR\"===)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(s||\"OBSERVABLE_INCLUDE\"===s){var u=\"DETECTOR\"===s,X=u?N:0<a.length?Math.round(a[0]):0,M;for(M of n){if(!M.startsWith(\"rec[-\")||!M.endsWith(\"]\"))return console.warn(\"Ignoring instruction due to non-record target: \"+o);var Z=L.length+Number.parseInt(M.substring(4,M.length-1));if(Z<0||Z>=L.length)return console.warn(\"Ignoring instruction due to out of range record target: \"+o);var Y=L[Z];T[Y.bt].it.push(new F(B.get(s),e,new Float32Array([X]),new Uint32Array([Y._t[0]])))}return N+=u}if(\"SPP\"===s||\"SPP_DAG\"===s){var R=\"SPP_DAG\"===s,y=q(n),m;let r=T[T.length-1];for(m of y)try{r.put(V(e,new Float32Array(a),R,m),!1)}catch(t){T.push(new U),(r=T[T.length-1]).put(V(e,new Float32Array(a),R,m),!1)}return}if(s.startsWith(\"QUBIT_COORDS\")){var p=a.length<1?0:a[0],I=a.length<2?0:a[1],b;for(b of n){var _=parseInt(b);D.has(_)?console.warn(`Ignoring \"${o}\" because there's already coordinate data for qubit ${_}.`):x.has(p+\",\"+I)?console.warn(`Ignoring \"${o}\" because there's already a qubit placed at ${p},${I}.`):(D.set(_,[p,I]),x)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(.add(p+\",\"+I))}return}}let t=!1;for(v of n)if(v.startsWith(\"rec[\"))\"CX\"!==s&&\"CY\"!==s&&\"CZ\"!==s&&\"ZCX\"!==s&&\"ZCY\"!==s||(t=!0);else if(\"number\"!=typeof parseInt(v))throw new Error(o);if(t){var E=[];for(let t=0;t<n.length;t+=2){var A=n[t].startsWith(\"rec[\"),k=n[t+1].startsWith(\"rec[\");A||k?(A||T[T.length-1].put(new F(B.get(\"ERR\"),e,new Float32Array([]),new Uint32Array([n[t]]))),k||T[T.length-1].put(new F(B.get(\"ERR\"),e,new Float32Array([]),new Uint32Array([n[t+1]]))),console.warn(\"Feedback isn't supported yet. Ignoring\",s,n[t],n[t+1])):(E.push(n[t]),E.push(n[t+1]))}if(0===(n=E).length)return}var g=B.get(s);if(void 0===g)console.warn(\"Ignoring unrecognized instruction: \"+o);else{var C=new Float32Array(a);let r=T[T.length-1];if(void 0===g.t)r.put(new F(g,e,C,new Uint32Array(n)));else{if(n.length%g.t!=0)throw new Error(\"Incorrect number of targets in line \"+o);for(let t=0;t<n.length;t+=g.t){var S=n.slice(t,t+g.t),P=(l&&S.reverse(),new Uint32Array(S)),O=new F(g,e,C,P);try{r.put(O,!1)}catch(t){T.push(new U),(r=T[T.l)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ength-1]).put(O,!1)}0<O.m()&&L.push({bt:T.length-1,_t:O.R})}}}}})(t)}T[T.length-1].empty()||T.push(new U)}},L=[],o=(s(t,0,t.length,1),0<T.length&&T[T.length-1].ut()&&T.pop(),0);var r,e=t=>{let r=!0;for(;!D.has(t);){var e=r?t:o,i=e+\",0\";x.has(i)||(x.add(i),D.set(t,[e,0])),o+=!r,r=!1}};for(r of T)for(var i of r.nt())for(var a of i.R)e(a);var n=Math.max(...D.keys(),0)+1,h=new Float64Array(2*n);for(let t=0;t<n;t++){e(t);var[l,f]=D.get(t);h[2*t]=l,h[2*t+1]=f}return new u(h,T)}Et(){var t,r=new Set;for(t of this.yt)for(var e of t.nt())for(var i of e.R)r.add(i);return r}At(){return this.kt((t,r)=>[t-r,t+r])}gt(){var t,r,e=new Map;for(let t=0;t<this.Rt.length;t+=2){var i=this.Rt[t],o=this.Rt[t+1];e.set(i+\",\"+o,[i,o])}let a=1/0,n=1/0,s=256;for([t,r]of e.values())for(a=Math.min(t,a),n=Math.min(r,n);(t%s!=0||r%s!=0)&&s>1/256;)s/=2;let h;if(s<=1/256)h=1;else{h=1/s;let t=0;for(var[l,f]of e.values()){var v=(l-a+f-n)%(2*s),l=(l-a-f+n)%(2*s);t=t|(0==v?1:2)|(0==l?4:8)}5===t?h/=2:10===t&&(a-=s,h/=2)}let c=-a,d=-n;return(t,r)=>[)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART((t+c)*h,(r+d)*h]}Ct(){return this.kt(this.gt())}St(e,i){return this.kt((t,r)=>[t+e,r+i])}st(){return this.St(0,0)}kt(r){var e=new Float64Array(this.Rt.length);for(let t=0;t<this.Rt.length;t+=2){var[i,o]=r(this.Rt[t],this.Rt[t+1]);e[t]=i,e[t+1]=o}var t=this.yt.map(t=>t.st());return new u(e,t)}Pt(r){var e=new Map;for(let t=0;t<this.yt.length;t++){var i,o=this.yt[t];if(r)for(var a of o.ot().values())for(var n of a)0<n.m()&&(i=n.R[0],e.set(t+\":\"+i,{mid:e.size,Ot:n.R}));else for(var[s,h]of o.et.entries())h.R[0]===s&&0<h.m()&&e.set(t+\":\"+s,{mid:e.size,Ot:h.R})}var l,t=[],f=new Map;for(let r=0;r<this.yt.length;r++)for(l of this.yt[r].it)if(\"DETECTOR\"===l.Z.name){for(var v=Math.round(l.Y[0]);t.length<=v;)t.push({Tt:[],Ot:[]});var c=t[v],d=r+\":\"+l.R[0],d=e.get(d);void 0!==d&&(c.Tt.push(d.mid-e.size),c.Ot.push(...d.Ot))}else if(\"OBSERVABLE_INCLUDE\"===l.Z.name){c=Math.round(l.Y[0]);let t=f.get(c);void 0===t&&(t=[],f.set(c,t));d=r+\":\"+l.R[0];e.has(d)&&t.push(e.get(d).mid-e.size)}var w,u,X,M,Z=new Set,Y=[];for(w of t)0<w.)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(Tt.length&&(w.Tt=[...new Set(w.Tt)],w.Tt.sort((t,r)=>r-t),u=w.Tt.join(\":\"),Z.has(u)||(Z.add(u),Y.push(w)));for([X,M]of f.entries())(M=[...new Set(M)]).sort((t,r)=>r-t),f.set(X,M);return Y.sort((t,r)=>t.Tt[0]-r.Tt[0]),{Nt:Y,Dt:f}}xt(){var t,r=new Set;for(t of this.yt)for(var N of t.nt())for(var D of N.R)r.add(D);var{Nt:a,Dt:e}=this.Pt(!0);a.reverse();let n=0;var i,s=this.m(),o=[];for(i of r){var x=this.Rt[2*i],L=this.Rt[2*i+1];o.push({Lt:i,x:x,y:L})}o.sort((t,r)=>t.x!==r.x?t.x-r.x:t.y!==r.y?t.y-r.y:t.Lt-r.Lt);var h=new Map,l=[];for(let t=0;t<o.length;t++){var{Lt:F,x:U,y:G}=o[t];h.set(F,t),l.push(`QUBIT_COORDS(${U}, ${G}) `+t)}let f=0;var v,c,d,w,u,X=new Set;for(v of this.yt){for([c,d]of v.ot().entries()){var M=[],Z=c.split(\"(\")[0].split(\"[\")[0];if(\"DETECTOR\"!==Z&&\"OBSERVABLE_INCLUDE\"!==Z){var Y=B.get(Z);if(void 0!==Y||\"MPP\"!==Z&&\"SPP\"!==Z&&\"SPP_DAG\"!==Z){if(void 0!==Y&&Y.o){var R,y=[];for(R of d)n+=R.m(),y.push(...R.R);M.push(y)}else for(var m of d)n+=m.m(),M.push([...m.R]);for(var H of M){var p,I=[c];for(p of)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART( H)I.push(h.get(p));l.push(I.join(\" \"))}}else{var b,_=[Z+\" \"];for(b of d){n+=b.m();var z=b.Z.name.substring(Z.length+1);for(let t=0;t<b.R.length;t++)_.push(z[t]+h.get(b.R[t])),_.push(\"*\");_.pop(),_.push(\" \")}l.push(_.join(\"\").trim())}}}let o=f;for(;0<a.length;){var E=a[a.length-1],A=s-n;if(0<=E.Tt[0]+A)break;a.pop();var k,g=[],C=[];let t=0,r=0;for(k of E.Ot){var S=this.Rt[2*k],P=this.Rt[2*k+1];t+=S,r+=P,g.push(S),C.push(P)}0<E.Ot.length&&(t/=E.Ot.length,r/=E.Ot.length,t=Math.round(2*t)/2,r=Math.round(2*r)/2),g.push(t),C.push(r);let e,i=f;for(let t=0;t>=g.length&&(t=0,i+=1),e=`DETECTOR(${g[t]}, ${C[t]}, ${i})`,X.has(e);t++);X.add(e);var O,T=[e];for(O of E.Tt)T.push(`rec[${O+A}]`);l.push(T.join(\" \")),o=Math.max(o,i+1)}f=o;for([w,u]of[...e.entries()]){var K=s-n;if(!(0<=u[0]+K)){e.delete(w);var Q,$=[`OBSERVABLE_INCLUDE(${w})`];for(Q of u)$.push(`rec[${Q+K}]`);l.push($.join(\" \"))}}l.push(\"TICK\")}for(;0<l.length&&\"TICK\"===l[l.length-1];)l.pop();return l.join(\"\\n\")}m(){let t=0;for(var r of this.yt)t+=r.m();return t})CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(Ft(t){var r,e,i=this.Ut(),o=[];for([r,e]of t){var a=r+\",\"+e;i.has(a)||(i.set(a,i.size),o.push(r,e))}return new u(new Float64Array([...this.Rt,...o]),this.yt.map(t=>t.st()))}Ut(){var r=new Map;for(let t=0;t<this.Rt.length;t+=2){var e=this.Rt[t],i=this.Rt[t+1];r.set(e+\",\"+i,t/2)}return r}toString(){return this.xt()}Gt(t){return t instanceof u&&this.xt()===t.xt()}}function w(t,r){if(t===r||J(t)&&J(r))return!0;var e,i=function(t,r){if(!X(t)&&void 0!==t.constructor&&t.constructor.prototype.hasOwnProperty(\"Gt\"))return t.Gt(r);if(!X(r)&&void 0!==r.constructor&&r.constructor.prototype.hasOwnProperty(\"Gt\"))return r.Gt(t)}(t,r);if(void 0!==i)return i;if(X(t)||X(r)||t.constructor.name!==r.constructor.name)return!1;if(t instanceof Map){var o,a,i=t,n=r;if(i.size!==n.size)return!1;for([o,a]of i){if(!n.has(o))return!1;o=n.get(o);if(!w(a,o))return!1}return!0}if(t instanceof Set)return tt(t,r);if(e=t,Array.isArray(e)||!j.every(t=>!(e instanceof t))){var s=t,h=r;if(s.length!==h.length)return!1;for(let t=0;t<s.length;t++)if(!w()CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(s[t],h[t]))return!1;return!0}var l,f=t,v=r;if(!tt(i=rt(f),rt(v)))return!1;for(l of i)if(l!==Symbol.iterator&&!w(f[l],v[l]))return!1;i=void 0!==f[Symbol.iterator],t=void 0!==v[Symbol.iterator];return i==t&&!(i&&t&&!function(t,r){var e=r[Symbol.iterator]();for(var i of t){var o=e.next();if(o.done||!w(i,o.value))return}return e.next().done}(f,v))}const j=[Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint16Array,Uint32Array,Uint8ClampedArray];function J(t){return\"number\"==typeof t&&isNaN(t)}function X(t){return null==t||\"string\"==typeof t||\"number\"==typeof t||\"boolean\"==typeof t}function tt(t,r){if(t.size!==r.size)return!1;for(var e of t)if(!r.has(e))return!1;return!0}function rt(t){var r,e=new Set;for(r in t)t.hasOwnProperty(r)&&e.add(r);return e}class et{constructor(t,r,e,i,o,a){this.Ht=t,this.zt=r,this.altKey=e,this.shiftKey=a,this.ctrlKey=i,this.metaKey=o}Gt(t){return t instanceof et&&this.Ht===t.Ht&&w(this.zt,t.zt)&&this.altKey===t.altKey&&this.shiftKey===t.shiftKey&&this.ctrlKey===t.)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ctrlKey&&this.metaKey===t.metaKey}toString(){return`ChordEvent(\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    inProgress=${this.Ht},\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    chord=${G(this.zt)},\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    altKey=${this.altKey},\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    shiftKey=${this.shiftKey},\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    ctrlKey=${this.ctrlKey},\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(    metaKey=${this.metaKey},\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART()`}}const it=new Set([\"alt\",\"shift\",\"control\",\"meta\"]),ot=new Set([\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"0\",\"-\",\"=\",\"\\\\\",\"`\"]);class at{constructor(){this.Kt=new Set,this.Qt=new Set,this.$t=new Set,this.Bt=[]}qt(t){return new et(t,new Set(this.$t),this.Kt.has(\"alt\"),this.Kt.has(\"control\"),this.Kt.has(\"meta\"),this.Kt.has(\"shift\"))}Wt(t){this.Bt.push(this.qt(t))}Vt(){this.Qt.clear(),this.$t.clear(),this.Kt.clear()}jt(t){var r,e,i=t.key.toLowerCase();if(\"escape\"===i&&this.Vt(),\"keydown\"===t.type){for([r,e]of[[t.altKey,\"alt\"],[t.shiftKey,\"shift\"],[t.ctrlKey,\"control\"],[t.metaKey,\"meta\"]])r?this.Kt.add(e):this.Kt.delete(e);it.has(i)||(this.Qt.add(i),this.$t.add(i)),this.Wt(!0)}else{if(\"keyup\"!==t.type)throw new Error(\"Not a recognized key event type: \"+t.type);it.has(i)||(this.Qt.delete(i),this.Wt(0<this.Qt.size&&!ot.has(i)),ot.has(i)&&this.$t.delete(i),0===this.Qt.size&&(this.Kt.clear(),this.$t.clear()))}}}class nt{constructor(t,r,e=0,i=!1){this.action=t,this.Jt=r,this.tr=e,this.rr=i,this.er=\"idle\",this.ir=-1/0}ar)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART((){var t=this.Jt-(performance.now()-this.ir);if(0<t)this.nr(t);else{this.er=\"running\";t=performance.now();try{this.action()}finally{t=performance.now()-t;this.ir=performance.now()+t*this.tr,\"running-and-triggered\"===this.er?this.nr(this.Jt):this.er=\"idle\"}}}sr(){switch(this.er){case\"idle\":this.ar();break;case\"waiting\":break;case\"running\":this.er=\"running-and-triggered\";break;case\"running-and-triggered\":break;default:throw new Error(\"Unrecognized throttle state: \"+this.er)}}nr(e){if(this.er=\"waiting\",this.rr){let t,r=performance.now();(t=()=>{performance.now()<r+e?requestAnimationFrame(t):(this.er=\"idle\",this.ir=-1/0,this.sr())})()}else setTimeout(()=>{this.er=\"idle\",this.ir=-1/0,this.sr()},e)}}class i{constructor(t){this.hr=t}subscribe(t){return this.hr(t)}static of(...e){return new i(t=>{for(var r of e)t(r);return()=>{}})}lr(){let r=[];return this.subscribe(t=>r.push(t))(),r}map(e){return new i(r=>this.subscribe(t=>r(e(t))))}filter(e){return new i(r=>this.subscribe(t=>{e(t)&&r(t)}))}vr(s,h){return new i(r=>{)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(let e=!1,i=!1,o,a,t=this.subscribe(t=>{o=t,e=!0,i&&r(h(o,a))}),n=s.subscribe(t=>{a=t,i=!0,e&&r(h(o,a))});return()=>{t(),n()}})}static cr(){return new i(t=>{let r,e=!1;return(r=()=>{e||(t(void 0),window.requestAnimationFrame(r))})(),()=>{e=!0}})}dr(){return new i(e=>{let i=()=>{},o=!1,t=this.subscribe(t=>{var r;o||(r=i,i=t.subscribe(e),r())});return()=>{o=!0,i(),t()}})}wr(r){return this.map(t=>(r(t),t))}ur(){return new i(r=>{let e=[];return e.push(this.subscribe(t=>e.push(t.subscribe(r)))),()=>{for(var t of e)t()}})}Xr(a){return new i(t=>{let r=void 0,e=!1,i=new nt(()=>{e||t(r)},a),o=this.subscribe(t=>{r=t,i.sr()});return()=>{e=!0,o()}})}static Mr(r,e){return new i(t=>(r.addEventListener(e,t),()=>r.removeEventListener(e,t)))}Zr(t){return new i(r=>{let e=t;return this.subscribe(t=>{0<e?--e:r(t)})})}Yr(t=void 0){let o=t||((t,r)=>t===r);return new i(r=>{let e=!1,i=void 0;return this.subscribe(t=>{e&&o(i,t)||(i=t,e=!0,r(t))})})}}class st{constructor(){this.Rr=[],this.yr=new i(t=>{this.Rr.push(t);let r=!1;return()=)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(>{r||(r=!0,this.Rr.splice(this.Rr.indexOf(t),1))}})}mr(){return this.yr}send(t){for(var r of this.Rr)r(t)}}class ht{constructor(t=void 0){this.pr=t,this.Ir=new st,this.yr=new i(t=>(t(this.pr),this.Ir.mr().subscribe(t)))}mr(){return this.yr}set(t){this.pr=t,this.Ir.send(t)}get(){return this.pr}}class lt{constructor(t,r,e){if(r<0||r>=t.length)throw new Error(\"Bad index: \"+{history:t,index:r,br:e});if(!Array.isArray(t))throw new Error(\"Bad history: \"+{history:t,index:r,br:e});this.history=t,this.index=r,this.br=e,this._r=new st,this.Er=new ht(this.history[this.index])}Ar(){return this._r.mr()}kr(){return this.Er.mr()}gr(){return this.Er.get()}static Cr(t){return new lt([t],0,!1)}Sr(){return 0===this.index&&!this.br}Pr(){return this.index===this.history.length-1}clear(t){this.history=[t],this.index=0,this.br=!1,this.Er.set(t),this._r.send(t)}Or(t){this.br=t!==this.history[this.index],this._r.send(void 0)}Tr(){this.br=!1;var t=this.history[this.index];return this.Er.set(t),this._r.send(t),t}commit(t){t===this.hist)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ory[this.index]?this.Tr():(this.br=!1,this.index+=1,this.history.splice(this.index,this.history.length-this.index),this.history.push(t),this.Er.set(t),this._r.send(t))}Nr(){if(!this.br){if(0===this.index)return;--this.index}this.br=!1;var t=this.history[this.index];return this.Er.set(t),this._r.send(t),t}Dr(){var t;if(this.index+1!==this.history.length)return this.index+=1,this.br=!1,t=this.history[this.index],this.Er.set(t),this._r.send(t),t}toString(){return\"Revision(\"+G({index:this.index,count:this.history.length,Lr:this.br,head:this.history[this.index]})+\")\"}Gt(t){return t instanceof lt&&this.index===t.index&&this.br===t.br&&w(this.history,t.history)}}let It=32;function ft(t,e,N,o,D){var x,r=Math.floor(t.canvas.width/2),i=e.Fr();i.sort((t,r)=>{var[t,e]=o(t),[r,i]=o(r);return e!==i?e-i:t-r});let a=new Map,L=void 0,n=0,s=0,h=0,l=0;for(x of i){var[F,f]=o(x);s+=It,L!==f?(L=f,n=1.5*r,h=Math.max(h,l),l=0,s+=.25*It):(n+=.25*Rt,l++),a.set(F+\",\"+f,[Math.round(n)+.5,Math.round(s)+.5])}let v=It+Math.ceil(Rt*h*.25);v)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ar c=Math.floor(t.canvas.width/4/v);let U=e.Ur-c+1,d=Math.max(0,Math.min(U,D-2*c+1));var w=Math.min(d+2*c+2,D);let G=t=>{t-=e.Ur;return(t-=d-U)*v},u=(t,r)=>{var[t,e]=o(t);return[t,e,r]=[[t,e,r]][0],t=t+\",\"+e,a.has(t)?([e,t]=a.get(t),[e+G(r),t]):[void 0,void 0]};t.save();try{t.clearRect(r,0,r,t.canvas.height);var H,z,K=new Map;for([H,z]of N.entries()){E=_=b=et=rt=tt=J=I=P=S=j=V=W=C=p=m=q=g=k=B=A=y=R=$=Q=Y=Z=M=X=void 0;var X=t,M=u,Z=z,Y=H,Q=d,$=w,R=v,y=K;for(let o=Q-1;o<=$;o++){y.has(o)||y.set(o,new Map);var m,p,I,b,_,E,A=y.get(o),B=Z.Gr(o+.5),k=Z.Gr(o);for([m,p]of B.Hr.entries()){let{dx:t,dy:r,_:e,A:i}=pt(Y,m,A);0<=Y&&Y<4?(t=0,e=R,i=5,0===Y?r=10:1===Y?r=5:2===Y?r=0:3===Y&&(r=-5)):t-=R/2;var[g,q]=M(m,o);if(void 0!==g&&void 0!==q){if(\"X\"===p)X.fillStyle=\"red\";else if(\"Y\"===p)X.fillStyle=\"green\";else{if(\"Z\"!==p)throw new Error(\"Not a pauli: \"+p);X.fillStyle=\"blue\"}X.fillRect(g-t,q-r,e,i)}}for(I of k.zr){var{dx:C,dy:W,_:V,A:j}=pt(Y,I,A),[S,P]=(C-=R/2,M(I,o-.5));void 0!==S&&void 0!==P&&(X.strokeStyle=\"magenta\",X.li)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(neWidth=8,X.strokeRect(S-C,P-W,V,j),X.lineWidth=1,X.fillStyle=\"black\",X.fillRect(S-C,P-W,V,j))}for({Kr:b,Qr:_,color:E}of k.$r){var[J,tt]=M(b,o),[rt,et]=M(_,o);\"X\"===E?X.strokeStyle=\"red\":\"Y\"===E?X.strokeStyle=\"green\":\"Z\"===E?X.strokeStyle=\"blue\":X.strokeStyle=\"purple\",X.lineWidth=8,mt(X,J,tt,rt,et),X.lineWidth=1}}}t.globalAlpha*=.5,t.fillStyle=\"black\";var it,O,ot,at=G(e.Ur)+1.5*r-v/2;t.fillRect(at,0,v,t.canvas.height),t.globalAlpha*=2,t.strokeStyle=\"black\",t.fillStyle=\"black\";for(it of i){var[nt,st]=u(it,d-1),[ht,lt]=u(it,w+1);t.beginPath(),t.moveTo(nt,st),t.lineTo(ht,lt),t.stroke()}t.textAlign=\"right\",t.textBaseline=\"middle\";for(O of i){var[ft,vt]=u(O,d-1),ct=e.Br.Rt[2*O],dt=e.Br.Rt[2*O+1];t.fillText(ct+`,${dt}:`,ft,vt)}for(let r=d;r<=w;r++){var wt=t=>u(t,r),ut=e.Br.yt[r];if(void 0!==ut)for(var Xt of ut.nt())Xt.I(wt,t)}t.globalAlpha=.5;for(ot of i){var[Mt,T]=u(ot,d-1),[Zt,Yt]=o(ot);e.qr>t.canvas.width/2&&e.Wr>=T+yt-.55*It&&e.Wr<=T+.55*It+yt&&(t.beginPath(),t.moveTo(Mt,T),t.lineTo(Zt,Yt),t.stroke(),t.fillStyl)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(e=\"black\",t.fillRect(Zt-20,Yt-20,40,40),t.fillRect(t.canvas.width/2,T-It/3,t.canvas.width/2,2*It/3))}}finally{t.restore()}}class Z{constructor(t,r){if(32<t)throw new Error(\"num_frames > 32\");this.t=r,this.Vr=t,this.jr=new Uint32Array(r),this.Jr=new Uint32Array(r),this.flags=new Uint32Array(r)}st(){var r=new Z(this.Vr,this.t);for(let t=0;t<this.t;t++)r.jr[t]=this.jr[t],r.Jr[t]=this.Jr[t],r.flags[t]=this.flags[t];return r}te(n){if(n.length!==this.t)throw new Error(\"qubit_keys.length !== this.num_qubits\");var s=[];for(let t=0;t<this.Vr;t++)s.push(new Map);for(let a=0;a<this.t;a++){var h=n[a];let t=this.jr[a],r=this.Jr[a],e=this.flags[a],i=t|r|e,o=0;for(;i;)1&i&&(1&e?s[o].set(h,\"ERR:flag\"):t&r&1?s[o].set(h,\"Y\"):1&t?s[o].set(h,\"X\"):s[o].set(h,\"Z\")),o++,t>>=1,r>>=1,e>>=1,i>>=1}return s}static re(e){var t=e.length;if(0===t)throw new Error(\"strings.length === 0\");var r,i=e[0].length;for(r of e)if(r.length!==i)throw new Error(\"Inconsistent string length.\");var o=new Z(t,i);for(let r=0;r<t;r++)for(let t=0;t<i;t++){var )CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(a=e[r][t];if(\"X\"===a)o.jr[t]|=1<<r;else if(\"Y\"===a)o.jr[t]|=1<<r,o.Jr[t]|=1<<r;else if(\"Z\"===a)o.Jr[t]|=1<<r;else if(\"I\"!==a&&\"_\"!==a)if(\"!\"===a)o.flags[t]|=1<<r;else if(\"%\"===a)o.flags[t]|=1<<r,o.jr[t]|=1<<r;else{if(\"&\"===a)o.flags[t]|=1<<r,o.jr[t]|=1<<r;else{if(\"$\"!==a)throw new Error(\"Unrecognized pauli string character: '\"+a+\"'\");o.flags[t]|=1<<r}o.Jr[t]|=1<<r}}return o}ee(){var t=[];for(let e=0;e<this.Vr;e++){let r=\"\";for(let t=0;t<this.t;t++){var i=this.flags[t]>>e&1,o=this.jr[t]>>e&1,a=this.Jr[t]>>e&1;r+=\"_XZY!%$&\"[o+2*a+4*i]}t.push(r)}return t}static ie(e,i){var o=new Z(e.length,i.length);for(let r=0;r<e.length;r++)for(let t=0;t<i.length;t++){var a=e[r].get(i[t]);\"X\"===a?o.jr[t]|=1<<r:\"Z\"===a?o.Jr[t]|=1<<r:\"Y\"===a?(o.jr[t]|=1<<r,o.Jr[t]|=1<<r):\"I\"!==a&&void 0!==a&&(o.flags[t]|=1<<r)}return o}G(t){for(var r of t){var e=this.jr[r],i=this.Jr[r];this.Jr[r]=e,this.jr[r]=i}}H(t){for(var r of t)this.Jr[r]^=this.jr[r]}K(t){for(var r of t)this.jr[r]^=this.Jr[r]}B(t){for(var r of t)this.flags[r]|=this.jr[r],thi)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(s.flags[r]|=this.Jr[r],this.jr[r]=0,this.Jr[r]=0}$(i,o){for(let e=0;e<o.length;e+=i.length){let r=0;for(let t=0;t<i.length;t++){var a=o[e+t],n=i[t];if(\"X\"===n)r^=this.Jr[a];else if(\"Z\"===n)r^=this.jr[a];else{if(\"Y\"!==n)throw new Error(`Unrecognized measure obs: '${n}'`);r^=this.jr[a]^this.Jr[a]}}for(let t=0;t<i.length;t++){var s=o[e+t];this.flags[s]|=r}}}Zt(r,e){if(r.length!==e.length)throw new Error(\"bases.length !== targets.length\");let i=0;for(let t=0;t<r.length;t++){var o=e[t],a=r[t];if(\"X\"===a)i^=this.Jr[o];else if(\"Z\"===a)i^=this.jr[o];else{if(\"Y\"!==a)throw new Error(`Unrecognized measure obs: '${a}'`);i^=this.jr[o]^this.Jr[o]}}for(let t=0;t<r.length;t++){var n=e[t];this.flags[n]|=i}}Yt(i,o){if(i.length!==o.length)throw new Error(\"bases.length !== targets.length\");let a=0;for(let t=0;t<i.length;t++){var r=o[t],e=i[t];if(\"X\"===e)a^=this.Jr[r];else if(\"Z\"===e)a^=this.jr[r];else{if(\"Y\"!==e)throw new Error(`Unrecognized spp obs: '${e}'`);a^=this.jr[r]^this.Jr[r]}}for(let e=0;e<i.length;e++){var n=o[e],s=i[e)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(];let t=0,r=0;if(\"X\"===s)t=1;else{if(\"Z\"!==s){if(\"Y\"!==s)throw new Error(`Unrecognized spp obs: '${s}'`);t=1}r=1}t&&(this.jr[n]^=a),r&&(this.Jr[n]^=a)}}U(t,r){if(\"X\"===t)for(var e of r)this.flags[e]|=this.Jr[e],this.jr[e]=0,this.Jr[e]=0;else if(\"Z\"===t)for(var i of r)this.flags[i]|=this.jr[i],this.jr[i]=0,this.Jr[i]=0;else{if(\"Y\"!==t)throw new Error(\"Unrecognized demolition obs\");for(var o of r)this.flags[o]|=this.jr[o]^this.Jr[o],this.jr[o]=0,this.Jr[o]=0}}j(t){for(var r of t)this.jr[r]^=this.Jr[r],this.Jr[r]^=this.jr[r]}J(t){for(var r of t)this.Jr[r]^=this.jr[r],this.jr[r]^=this.Jr[r]}g(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1],o=this.jr[e],a=this.Jr[e],n=this.jr[i],s=this.Jr[i];this.jr[e]=n,this.Jr[e]=s,this.jr[i]=o,this.Jr[i]=a}}k(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1],o=this.jr[e],a=this.Jr[e],n=this.jr[i],s=this.Jr[i],h=o^n;this.jr[e]=n,this.Jr[e]=s^h,this.jr[i]=o,this.Jr[i]=a^h}}q(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1],o=this.Jr[e]^this.Jr[i];this.jr[e]^=o,this.jr[i])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(^=o}}W(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1],o=this.jr[e],a=this.Jr[e],n=this.jr[i],s=this.Jr[i];a^=o,o^=s^=n,s^=n^=a,a^=o,this.jr[e]=a,this.Jr[e]=o,this.jr[i]=s,this.Jr[i]=n}}V(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1],o=this.jr[e]^this.jr[i];this.Jr[e]^=o,this.Jr[i]^=o}}N(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1];this.jr[i]^=this.Jr[e],this.jr[e]^=this.Jr[i]}}D(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1];this.jr[i]^=this.Jr[e],this.Jr[i]^=this.Jr[e],this.jr[e]^=this.jr[i],this.jr[e]^=this.Jr[i]}}L(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1],o=this.jr[e]^this.Jr[e];this.jr[i]^=o,this.Jr[i]^=o,o=this.jr[i]^this.Jr[i],this.jr[e]^=o,this.Jr[e]^=o}}O(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1];this.jr[i]^=this.jr[e],this.Jr[e]^=this.Jr[i]}}C(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1],o=this.jr[e],a=this.Jr[e],n=this.jr[i],s=this.Jr[i];this.jr[e]=n^o,this.Jr[e]=s,this.jr[i]=o,this.Jr[i]=a^s}}S(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1],o=)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(this.jr[e],a=this.Jr[e],n=this.jr[i],s=this.Jr[i];this.jr[e]=n,this.Jr[e]=a^s,this.jr[i]=n^o,this.Jr[i]=a}}P(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1],o=this.jr[e],a=this.Jr[e],n=this.jr[i],s=this.Jr[i];this.jr[e]=n,this.Jr[e]=s^o,this.jr[i]=o,this.Jr[i]=a^n}}T(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1];this.jr[i]^=this.jr[e],this.Jr[i]^=this.jr[e],this.Jr[e]^=this.Jr[i],this.Jr[e]^=this.jr[i]}}F(r){for(let t=0;t<r.length;t+=2){var e=r[t],i=r[t+1];this.Jr[i]^=this.jr[e],this.Jr[e]^=this.jr[i]}}oe(t,r){t.l(this,r)}ae(t,r){t.v(this,r)}Gt(r){if(!(r instanceof Z)||r.Vr!==this.Vr||r.t!==this.t)return!1;for(let t=0;t<this.t;t++)if(this.jr[t]!==r.jr[t]||this.Jr[t]!==r.Jr[t]||this.flags[t]!==r.flags[t])return!1;return!0}toString(){return this.ee().join(\"\\n\")}}class Y{constructor(t,r,e){this.Hr=t,this.zr=r,this.$r=e}ne(t){for(var r of this.Hr.keys())if(t.has(r))return!0;for(var e of this.zr.keys())if(t.has(e))return!0;return!1}se(t){return new Y(new Map([...this.Hr.entries(),...t.Hr.entries()]),new )CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(Set([...this.zr,...t.zr]),[...this.$r,...t.$r])}toString(){let t=0;for(var r of this.Hr.keys())t=Math.max(t,r+1);for(var e of this.zr)t=Math.max(t,e+1);for(var[i,o]of this.$r)t=Math.max(t,i+1),t=Math.max(t,o+1);let a='\"';for(let r=0;r<t;r++){let t=this.Hr.get(r);void 0===t&&(t=\"_\"),this.zr.has(r)&&(t=\"E\"),a+=t}return a+='\"'}}class O{constructor(t){this.he=t}Gt(t){return t instanceof O&&w(this.he,t.he)}toString(){var t,r=[...this.he.keys()],e=(r.sort((t,r)=>t-r),[\"PropagatedPauliFrames {\"]);for(t of r)e.push(`    ${t}: `+this.he.get(t));return e.push(\"}\"),e.join(\"\\n\")}Gr(t){let r=this.he.get(t);return r=void 0===r?new Y(new Map,new Set,[]):r}static le(r,e){var i=new O(new Map);let o=new Map;for(let t=0;t<r.yt.length;t++){var a,n=r.yt[t],s=o,h=(o=n.wt(o,e),new Set);for(a of[...o.keys()]){var l=o.get(a);l.startsWith(\"ERR:\")&&(h.add(a),o.set(a,l.substring(4))),\"I\"===o.get(a)&&o.delete(a)}var f,v=[];for(f of n.nt())if(2===f.Z.t&&!f.Z.i){var c,[d,w]=f.R,u=new Set;for(c of f.R){var X=o.get(c),M=s.get(c);X!==M&&(void)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART( 0!==X&&u.add(X),void 0!==M)&&u.add(M)}if(0<u.size){let t=\"I\";1===u.size&&(t=[...u][0]),v.push({Kr:d,Qr:w,color:t})}}0<o.size&&i.he.set(t+.5,new Y(o,new Set,[])),(0<h.size||0<v.length)&&i.he.set(t,new Y(new Map,h,v))}return i}static fe(t,r){return O.ve(t,[r])[0]}static ve(t,e){var i=[];for(let r=0;r<e.length;r+=32){var o=[];for(let t=r;t<r+32&&t<e.length;t++)o.push(e[t]);i.push(...O.ce(t,o))}return i}static ce(t,e){var i=[];for(let t=0;t<e.length;t++)i.push(new O(new Map));var o=new Z(e.length,t.Et().size);let a=0;var n=[];for(let r=0;r<e.length;r++)for(let t=0;t<e[r].length;t++)n.push([r,e[r][t]]);n.sort((t,r)=>t[1]-r[1]);for(let r=t.yt.length-1;-1<=r;r--){var s,h=0<=r?t.yt[r]:new U,l=[...h.et.keys()];l.reverse();for(s of l){var f=h.et.get(s);if(f.R[0]===s){o.ae(f.Z,[...f.R]);for(let t=f.m();0<t;--t){--a;let e=0;for(;0<n.length&&n[n.length-1][1]===a;){var v=n[n.length-1];n.pop(),e^=1<<v[0]}if(0!==e)for(let r=0;r<f.R.length;r++){var c=f.R[r];let t;if(\"MX\"===f.Z.name||\"MRX\"===f.Z.name||\"MXX\"===f.Z.name)t=\"X\";e)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(lse if(\"MY\"===f.Z.name||\"MRY\"===f.Z.name||\"MYY\"===f.Z.name)t=\"Y\";else if(\"M\"===f.Z.name||\"MR\"===f.Z.name||\"MZZ\"===f.Z.name)t=\"Z\";else{if(\"MPAD\"===f.Z.name)continue;if(!f.Z.name.startsWith(\"MPP:\"))throw new Error(\"Unhandled measurement gate: \"+f.Z.name);t=f.Z.name[r+4]}if(\"X\"===t)o.jr[c]^=e;else{if(\"Y\"===t)o.jr[c]^=e;else if(\"Z\"!==t)throw new Error(\"Unhandled measurement gate: \"+f.Z.name);o.Jr[c]^=e}}}}}for(let t=0;t<e.length;t++){var d=1<<t,w=new Map,u=new Set;for(let t=0;t<o.jr.length;t++){var X=0!=(o.jr[t]&d),M=0!=(o.Jr[t]&d);X|M&&w.set(t,\"_XZY\"[X+2*M]),o.flags[t]&d&&u.add(t)}0<w.size&&i[t].he.set(r-.5,new Y(w,new Set,[])),0<u.size&&i[t].he.set(r,new Y(new Map,u,[]))}for(let t=0;t<o.jr.length;t++)o.flags[t]=0}return i}}function vt(t,r){var e,i,o,a;return void 0!==t&&void 0!==r&&(e=t/P,i=r/P,e=Math.floor(2*e+.5)/2,i=Math.floor(2*i+.5)/2,o=e*P,a=i*P,Math.abs(o-t)<=Rt)&&Math.abs(a-r)<=Rt&&e%1==i%1?[e,i]:[void 0,void 0]}function ct(t,r,e,i){var o,a,n=new Map;new Map;for([o,a]of i.entries()){_=C=g=k=A=E=v=f=l=b=)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(I=p=m=y=R=h=s=Y=Z=M=X=u=w=d=c=void 0;var s,h,l,f,v,c=t,d=r,w=e,u=a,X=o,M=n,Z=u.Gr(d.Ur+.5).Hr,Y=[];for([s,h]of Z.entries())Y.push([h,w(s)]);if(0<=X&&0<Y.length){Y.every(t=>\"X\"===t[0])?c.fillStyle=\"red\":Y.every(t=>\"Y\"===t[0])?c.fillStyle=\"green\":Y.every(t=>\"Z\"===t[0])?c.fillStyle=\"blue\":c.fillStyle=\"black\",c.strokeStyle=c.fillStyle;var R,y,Z=Y.map(t=>t[1]);let n=0,s=0;for([R,y]of Z)n+=R,s+=y;n/=Z.length,s/=Z.length,Z.sort((t,r)=>{var[t,e]=t,[r,i]=r;let o=Math.atan2(e-s,t-n),a=Math.atan2(i-s,r-n);return t===n&&e===s&&(o=-100),r===n&&i===s&&(a=-100),o-a}),S(c,Z),c.globalAlpha*=.25,c.fill(),c.globalAlpha*=4,c.lineWidth=2,c.stroke(),c.lineWidth=1}for([l,[f,v]]of Y){var{dx:m,dy:p,_:I,A:b}=pt(X,f+\":\"+v,M);if(\"X\"===l)c.fillStyle=\"red\";else if(\"Y\"===l)c.fillStyle=\"green\";else{if(\"Z\"!==l)throw new Error(\"Not a pauli: \"+l);c.fillStyle=\"blue\"}c.fillRect(f-m,v-p,I,b)}for(_ of Z=u.Gr(d.Ur).zr){var[_,E]=w(_),{dx:A,dy:k,_:g,A:C}=pt(X,_+\":\"+E,M);c.lineWidth=X<0?2:8,c.strokeStyle=\"magenta\",c.strokeRect(_-A,E-k,g,C),c.lineWidth)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(=1,c.fillStyle=\"black\",c.fillRect(_-A,E-k,g,C)}}}let dt=!0;function T(t,r){t.save();try{dt&&r()}finally{t.restore()}}function wt(Z,Y){let R=Y.Br,r=0;for(var t of R.yt)for(var e of t.it){var i=e.Z;\"MARKX\"!==i.name&&\"MARKY\"!==i.name&&\"MARKZ\"!==i.name||(r=Math.max(r,e.Y[0]+1))}let y=(t,r)=>[t*P-N,r*P-yt],m=t=>{var r=R.Rt[2*t],t=R.Rt[2*t+1];return y(r,t)},p=new Map;for(let t=0;t<r;t++)p.set(t,O.le(R,t));var o,{Nt:a,Dt:n}=R.Pt(!1),s=[];for(let t=0;t<a.length;t++)s.push(a[t].Tt);for(o of n.keys())s.push(n.get(o));var h,l=O.ve(R,s);let f=0;for(let t=0;t<a.length;t++)p.set(~t,l[f++]);for(h of n.keys())p.set(~h^1<<30,l[f++]);var v,c,d=new Set;for(v of R.yt)for(var w of v.et.keys())d.add(w);let I=new Set,b=new Set;for(c of R.Et()){var u=R.Rt[2*c],X=R.Rt[2*c+1];I.add(u+\",\"+X),d.has(c)&&b.add(u+\",\"+X)}T(Z,()=>{Z.fillStyle=\"white\",Z.clearRect(0,0,Z.canvas.width,Z.canvas.height);var[t,r]=vt(Y.qr,Y.Wr);let e=Y.Ur;for(let t=0;t<=Y.Ur;t++)for(var i of R.yt[t].it)if(\"POLYGON\"===i.Z.name){e=t;break}var o,a,n,s,h=[...R.yt[e].it])CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;h.sort((t,r)=>r.R.length-t.R.length);for(o of h)\"POLYGON\"===o.Z.name&&o.I(m,Z);T(Z,()=>{for(let t=0;t<100;t+=.5){var[r,,]=y(t,0),e=\"\"+t;Z.fillStyle=\"black\",Z.fillText(e,r-Z.measureText(e).width/2,15)}for(let t=0;t<100;t+=.5){var[,i]=y(0,t),o=\"\"+t;Z.fillStyle=\"black\",Z.fillText(o,18-Z.measureText(o).width,i)}Z.strokeStyle=\"black\";for(let r=0;r<100;r+=.5){var[t,,]=y(r,0),a=\"\"+r;Z.fillStyle=\"black\",Z.fillText(a,t-Z.measureText(a).width/2,15);for(let t=r%1;t<100;t+=1){var[n,s]=y(r,t),h=(Z.fillStyle=\"white\",!I.has(r+\",\"+t)),l=!b.has(r+\",\"+t);h&&(Z.globalAlpha*=.25),l&&(Z.globalAlpha*=.25),Z.fillRect(n-Rt,s-Rt,2*Rt,2*Rt),Z.strokeRect(n-Rt,s-Rt,2*Rt,2*Rt),h&&(Z.globalAlpha*=4),l&&(Z.globalAlpha*=4)}}});for([a,n]of p.entries()){u=w=d=M=X=c=v=f=l=void 0;var l=Z,f=Y,v=m,c=n;if(a,void 0!==(c=c.Gr(f.Ur).$r))for(var{Kr:d,Qr:w,color:u}of c){var[d,X]=v(d),[w,M]=v(w);\"X\"===u?l.strokeStyle=\"red\":\"Y\"===u?l.strokeStyle=\"green\":\"Z\"===u?l.strokeStyle=\"blue\":l.strokeStyle=\"purple\",l.lineWidth=8,mt(l,d,X,w,M),l.lineWidth=1}}for(s )CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(of R.yt[Y.Ur].nt())\"POLYGON\"!==s.Z.name&&s.I(m,Z);T(Z,()=>{Z.globalAlpha*=.25;for(var[t,r]of Y.de.values()){var[t,r]=y(t,r);Z.fillStyle=\"yellow\",Z.fillRect(t-1.25*Rt,r-1.25*Rt,2.5*Rt,2.5*Rt)}}),T(Z,()=>{Z.globalAlpha*=.5;for(var[t,r]of Y.we.values()){var[t,r]=y(t,r);Z.fillStyle=\"blue\",Z.fillRect(t-1.25*Rt,r-1.25*Rt,2.5*Rt,2.5*Rt)}}),ct(Z,Y,m,p),void 0!==t&&(Z.save(),Z.globalAlpha*=.5,[h,t]=y(t,r),Z.fillStyle=\"red\",Z.fillRect(h-Rt,t-Rt,2*Rt,2*Rt),Z.restore()),T(Z,()=>{var t,r,e,i,o,a;Z.globalAlpha*=.25,Z.fillStyle=\"blue\",void 0!==Y.ue&&void 0!==Y.qr&&(t=Math.min(Y.qr,Y.ue),r=Math.max(Y.qr,Y.ue),e=Math.min(Y.Wr,Y.Xe),i=Math.max(Y.Wr,Y.Xe),--t,r+=1,--e,i+=1,t-=N,r-=N,e-=yt,i-=yt,Z.fillRect(t,e,r-t,i-e));for([o,a]of Y.Me){var[n,s]=y(o,a);Z.fillRect(n-Rt,s-Rt,2*Rt,2*Rt)}})}),ft(Z,Y,p,m,R.yt.length),Z.save();try{Z.strokeStyle=\"black\",Z.translate(Math.floor(Z.canvas.width/2),0);for(let n=0;n<R.yt.length;n++){let t=!1,r=!1,e=!1,i=!1;var M=R.yt[n].ft(),_=R.yt[n].vt();let o=!1,a=!1;var E,A,k=R.yt[n].lt();for(E of R.yt[)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(n].it)t|=\"POLYGON\"===E.Z.name,r|=\"MARKX\"===E.Z.name,e|=\"MARKY\"===E.Z.name,i|=\"MARKZ\"===E.Z.name;for(A of R.yt[n].et.values())o|=2===A.R.length,a|=2<A.R.length;if(Z.fillStyle=\"white\",Z.fillRect(8*n,0,8,20),k?(Z.fillStyle=\"#FF0\",Z.fillRect(8*n,0,8,20)):t&&(Z.fillStyle=\"#FBB\",Z.fillRect(8*n,0,8,7),Z.fillStyle=\"#BFB\",Z.fillRect(8*n,7,8,7),Z.fillStyle=\"#BBF\",Z.fillRect(8*n,14,8,6)),_?(Z.fillStyle=\"#DDD\",Z.fillRect(8*n,0,8,20)):M&&(Z.fillStyle=\"#DDD\",Z.fillRect(8*n,0,4,20)),r&&(Z.fillStyle=\"red\",Z.fillRect(8*n+3,14,3,3)),e&&(Z.fillStyle=\"green\",Z.fillRect(8*n+3,9,3,3)),i&&(Z.fillStyle=\"blue\",Z.fillRect(8*n+3,3,3,3)),a){Z.strokeStyle=\"black\",Z.beginPath();var g,C=8*n+.5;for(g of[3,5])Z.moveTo(C+g,6),Z.lineTo(C+g,15);Z.stroke()}o&&(Z.strokeStyle=\"black\",Z.beginPath(),Z.moveTo(8*n+.5+4,6),Z.lineTo(8*n+.5+4,15),Z.stroke())}Z.fillStyle=\"black\",Z.beginPath(),Z.moveTo(8*Y.Ur+.5+4,16),Z.lineTo(8*Y.Ur+.5-2,28),Z.lineTo(8*Y.Ur+.5+10,28),Z.closePath(),Z.fill();for(let r=0;r<R.yt.length;r++){var S=![...p.values()].every(t=>0==)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(=t.Gr(r).zr.size);0<R.yt[r].et.size||R.yt[r].it.length;S?(Z.strokeStyle=\"magenta\",Z.lineWidth=4,Z.strokeRect(8*r+.5-1,-.5,9,22),Z.lineWidth=1):(Z.strokeStyle=\"#000\",Z.strokeRect(8*r+.5,.5,8,20))}}finally{Z.restore()}}class ut{constructor(t,r,e,i,o,a,n,s,h){for(this.Br=t.st(),this.Ur=r,this.we=new Map(e.entries()),this.de=new Map(i.entries()),this.qr=o,this.Wr=a,this.ue=n,this.Xe=s,this.Me=[...h];this.Br.yt.length<=this.Ur;)this.Br.yt.push(new U)}Ze(){return this.Br.Et()}Fr(){let r=this.Ze();var t=[];if(0<this.de.size){var e,i=this.Br.Ut();for(e of this.de.keys()){var o=i.get(e);void 0!==o&&t.push(o)}}else t.push(...r.values());return t.filter(t=>r.has(t))}}function Xt(r){let e=[1,0],i=[0,1];var o=(t,r)=>[t-r,t+r];r=(r%8+8)%8;for(let t=0;t<r;t++)e=o(e[0],e[1]),i=o(i[0],i[1]);return(t,r)=>[e[0]*t+i[0]*r,e[1]*t+i[1]*r]}function Mt(){try{return window.self===window.top}catch(t){}}class Zt{constructor(){this.Ye=!1,this.Re=void 0}ye(){this.Re={me:!0}}pe(t){this.Re=t}Ie(){this.Re=void 0}be(t,r){if(!r.startsWith(\"#\"))CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART()throw new Error('\"Expected a hash URL: '+{_e:t,Ee:r});if(Mt()&&this.Re!==t)if(this.Ye)document.location.hash=r;else try{void 0===this.Re?history.replaceState(t,\"\",r):(history.pushState(t,\"\",r),this.Re=void 0)}catch(t){console.warn(\"Calling 'history.replaceState/pushState' failed. Falling back to setting location.hash.\",t),this.Ye=!0,document.location.hash=r}}}function Yt(t){return\"#circuit=\"+(t=-1===(t=t.replaceAll(\"QUBIT_COORDS\",\"Q\").replaceAll(\"DETECTOR\",\"DT\").replaceAll(\"OBSERVABLE_INCLUDE\",\"OI\").replaceAll(\", \",\",\").replaceAll(\") \",\")\").replaceAll(\" \",\"_\").replaceAll(\"\\n\",\";\")).indexOf(\"%\")&&-1===t.indexOf(\"&\")?t:encodeURIComponent(t))}let r=document.getElementById(\"toolbox\"),M=10.5,R=[\"H\",\"S\",\"R\",\"M\",\"MR\",\"C\",\"W\",\"SC\",\"MC\",\"P\",\"1-9\"],bt=[1,2,2,2,2,1,2,2,2,-1,-1,-1];let _t=function(){var r=new Map([[\"0,0\",B.get(\"H_YZ\")],[\"0,1\",B.get(\"H\")],[\"0,2\",B.get(\"H_XY\")],[\"1,0\",B.get(\"SQRT_X\")],[\"1,1\",B.get(\"SQRT_Y\")],[\"1,2\",B.get(\"S\")],[\"2,0\",B.get(\"RX\")],[\"2,1\",B.get(\"RY\")],[\"2,2\",B.get(\"R\")],[\"3,0\",B.get(\"MX\")],)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART([\"3,1\",B.get(\"MY\")],[\"3,2\",B.get(\"M\")],[\"4,0\",B.get(\"MRX\")],[\"4,1\",B.get(\"MRY\")],[\"4,2\",B.get(\"MRZ\")],[\"5,0\",B.get(\"CX\")],[\"5,1\",B.get(\"CY\")],[\"5,2\",B.get(\"CZ\")],[\"6,0\",B.get(\"CXSWAP\")],[\"6,1\",B.get(\"SWAP\")],[\"6,2\",B.get(\"CZSWAP\")],[\"7,0\",B.get(\"SQRT_XX\")],[\"7,1\",B.get(\"SQRT_YY\")],[\"7,2\",B.get(\"SQRT_ZZ\")],[\"8,0\",B.get(\"MXX\")],[\"8,1\",B.get(\"MYY\")],[\"8,2\",B.get(\"MZZ\")]]);let e=9;for(let t=0;t<4;t++)r.set(e+\",0\",B.get(\"MARKX\").M(t)),r.set(e+\",1\",B.get(\"MARKY\").M(t)),r.set(e+\",2\",B.get(\"MARKZ\").M(t)),r.set(e+\",-1\",B.get(\"MARK\").M(t)),e+=1;return r}();function Et(t){var r,e=function(t){var r,e;if(!t.ctrlKey)return r=+t.zt.has(\"x\"),e=+t.zt.has(\"y\"),t=+t.zt.has(\"z\"),r&&!e&&!t||!r&&e&&t?{Ae:0,strength:Math.max(r,Math.min(e,t))}:!r&&e&&!t||r&&!e&&t?{Ae:1,strength:Math.max(e,Math.min(r,t))}:!r&&!e&&t||r&&e&&!t?{Ae:2,strength:Math.max(t,Math.min(r,e))}:void 0}(t),t=function(i){if(!i.ctrlKey){let e=void 0;for(let r=0;r<R.length;r++){let t=0;for(var o of R[r].toLowerCase())t+=i.zt.has(o.toLowerCase());t===R[r].length&&(vo)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(id 0===e||t>=e.strength)&&(e={ke:r,strength:t/R[r].length})}return e}}(t);let i=e,o=(void 0!==t&&void 0===e&&(r=bt[t.ke],i=void 0===r?void 0:{strength:0,Ae:r}),void 0);return void 0!==i&&void 0!==t&&(r=t.ke+\",\"+i.Ae,_t.has(r))&&(o=_t.get(r)),{ge:e,Ce:i,Se:t,Pe:o}}const e=-P+Math.floor(P/4)+.5,o=-P+Math.floor(P/4)+.5;var t=document.getElementById(\"btnInsertLayer\"),At=document.getElementById(\"btnDeleteLayer\"),kt=document.getElementById(\"btnUndo\"),gt=document.getElementById(\"btnRedo\"),Ct=document.getElementById(\"btnClearMarkers\");const St=document.getElementById(\"btnShowHideImportExport\");var Pt=document.getElementById(\"btnNextLayer\"),Ot=document.getElementById(\"btnPrevLayer\"),Tt=document.getElementById(\"btnRotate45\"),Nt=document.getElementById(\"btnRotate45Counter\"),v=document.getElementById(\"btnExport\"),Dt=document.getElementById(\"btnImport\"),xt=document.getElementById(\"clear\");const y=document.getElementById(\"txtStimCircuit\");var Lt=document.getElementById(\"btnTimelineFocus\"),Ft=document.getElementById(\"btnCle)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(arTimelineFocus\"),Ut=document.getElementById(\"btnClearSelectedMarkers\");const Gt=document.getElementById(\"btnShowExamples\"),Ht=document.getElementById(\"examples-div\");y.addEventListener(\"keyup\",t=>t.stopPropagation()),y.addEventListener(\"keydown\",t=>t.stopPropagation());let m=new class{constructor(t){this.rev=lt.Cr(\"\"),this.canvas=t,this.Wr=void 0,this.qr=void 0,this.Oe=new at,this.Ur=0,this.we=new Map,this.de=new Map,this.ue=void 0,this.Xe=void 0,this.Te=new ht(this.Ne(void 0))}De(t){var r,e,i,o=this.xe(),a=o.yt[this.Ur],n=new Set,s=new Map;for(r of[[\"CX\",\"reverse\"],[\"CY\",\"reverse\"],[\"XCY\",\"reverse\"],[\"CXSWAP\",\"reverse\"],[\"XCZ\",\"reverse\"],[\"XCY\",\"reverse\"],[\"YCX\",\"reverse\"],[\"SWAPCX\",\"reverse\"],[\"RX\",\"MX\"],[\"R\",\"M\"],[\"RY\",\"MY\"]])s.set(r[0],r[1]),s.set(r[1],r[0]);for(e of this.we.keys()){var h=a.et.get(o.Ut().get(e));void 0!==h&&s.has(h.Z.name)&&n.add(h.R[0])}for(i of n){var l=a.et.get(i),f=s.get(l.Z.name);\"reverse\"===f?a.et.get(i).R.reverse():l.Z=B.get(f)}this.Le(o,t)}Fe(t){var r=this.xe();let e=this.Ur;for()CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(;e<r.yt.length&&!r.yt[e].empty();)e+=1;var i=[];for(let t=this.Ur;t<e;t++)i.push(r.yt[t]);i.reverse();for(let t=this.Ur;t<e;t++)r.yt[t]=i[t-this.Ur];this.Le(r,t)}xe(){for(var t=u.It(this.rev.gr());t.yt.length<=this.Ur;)t.yt.push(new U);return t}Ue(){this.we.clear(),this.Ge()}He(t){var r,e=this.xe(),i=e.Ut();for(r of this.we.keys()){var o=i.get(r);void 0!==o&&e.yt[this.Ur].Xt(o)}this.Le(e,t)}ze(t){var r=this.xe();r.yt.splice(this.Ur,1),this.Le(r,t)}Ke(t){var r=this.xe();r.yt.splice(this.Ur,0,new U),this.Le(r,t)}Nr(){this.rev.Nr()}Dr(){this.rev.Dr()}Le(t,r){r?this.Qe(t):this.commit(t)}commit(t){for(;0<t.yt.length&&t.yt[t.yt.length-1].ut();)t.yt.pop();this.rev.commit(t.xt())}Qe(t){this.rev.Or(t.xt()),this.Te.set(this.Ne(t))}Ne(t){return void 0===t&&(t=this.xe()),new ut(t,this.Ur,this.we,this.de,this.qr,this.Wr,this.ue,this.Xe,this.$e(this.Oe.Kt.has(\"alt\")))}Ge(){var t=this.Te.get().Br;this.Te.set(this.Ne(t))}Be(){this.commit(new u(new Float64Array([]),[]))}qe(){var t,r=this.xe();for(t of r.yt)t.it=t.it.filter(t=)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(>\"MARKX\"!==t.Z.name&&\"MARKY\"!==t.Z.name&&\"MARKZ\"!==t.Z.name);this.commit(r)}$e(i){var t=this.qr,r=this.Wr,o=this.ue,a=this.Xe,n=[];if(void 0!==t&&void 0!==o){var[s,h]=vt(o,a),l=Math.min(t,o),f=Math.max(t,o),v=Math.min(r,a),c=Math.max(r,a),t=P/4-Rt;l+=t,f-=t,v+=t,c-=t,l=Math.floor(2*l/P+.5)/2,f=Math.floor(2*f/P+.5)/2,v=Math.floor(2*v/P+.5)/2,c=Math.floor(2*c/P+.5)/2;let e=1;l!=f&&v!=c||(e=2);for(let r=l;r<=f;r+=.5)for(let t=v;t<=c;t+=.5)r%1!=t%1||i&&(s%e!=r%e||h%e!=t%e)||n.push([r,t])}return n}We(o,t,r){let e=this.xe();e=e.kt(o),!t&&r&&(this.de=(r=t=>{var r,e,i=new Map;for([r,e]of t.values())[r,e]=o(r,e),i.set(r+\",\"+e,[r,e]);return i})(this.de),this.we=r(this.we)),this.Le(e,t)}Ve(t,r){let e=Xt(t),i=this.xe().kt(e).gt();this.We((t,r)=>([t,r]=e(t,r),i(t,r)),r,!0)}je(t){this.Ur=Math.max(t,0),this.Ge()}Je(t,r,e){r||e||this.we.clear();for(var[i,o]of t){var a=i+\",\"+o;e&&this.we.has(a)?this.we.delete(a):this.we.set(a,[i,o])}this.Ge()}ti(t){var r,e=new Map,i=this.xe().yt[this.Ur];for(r of[...t]){var o=i.et.get(r);if(v)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(oid 0!==o)if(\"RX\"===o.Z.name||\"MX\"===o.Z.name||\"MRX\"===o.Z.name)e.set(r,\"X\");else if(\"RY\"===o.Z.name||\"MY\"===o.Z.name||\"MRY\"===o.Z.name)e.set(r,\"Y\");else if(\"R\"===o.Z.name||\"M\"===o.Z.name||\"MR\"===o.Z.name)e.set(r,\"Z\");else if(\"MXX\"===o.Z.name||\"MYY\"===o.Z.name||\"MZZ\"===o.Z.name){var a,n=o.Z.name[1];for(a of o.R)e.set(a,n)}else if(o.Z.name.startsWith(\"MPP:\")&&void 0===o.Z.h&&o.R.length===o.Z.name.length-4){var s=o.Z.name.substring(4);for(let t=0;t<o.R.length;t++){var h=o.R[t];e.set(h,s[t])}}}return e}ri(t,r){var e,i=this.xe().Ft(this.we.values()),o=i.Ut(),a=new Set;for(e of this.we.keys())a.add(o.get(e));var n,s=this.ti(a);for(n of s.keys())a.add(n);var h=new Set(s.values());h.delete(void 0);let l;l=1===h.size?[...h][0]:\"Z\";var f,v=i.yt[this.Ur];for(f of a){let t=s.get(f);void 0===t&&(t=l);var c=B.get(\"MARK\"+t).M(r);v.put(new F(c,\"\",new Float32Array([r]),new Uint32Array([f])))}this.Le(i,t)}ei(t){var r,e,i,o=this.xe().Ft(this.we.values()),a=o.Ut(),n=new Set;for(r of this.we.keys())n.add(a.get(r));for(e of this.)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ti(n).keys())n.add(e);for(i of n)void 0!==i&&o.yt[this.Ur].Mt(i);this.Le(o,t)}ii(t,r,e){var i,o=this.xe().Ft(this.we.values()),a=o.Ut();for(i of this.we.keys())o.yt[this.Ur].put(new F(r,\"\",new Float32Array(e),new Uint32Array([a.get(i)])));this.Le(o,t)}oi(t,r,e){let i=this.xe();var[o,a]=vt(this.qr,this.Wr),[n,s]=D(this.we.values()),h=[];if(void 0===o||void 0===n||this.we.has(o+\",\"+a)){if(2===this.we.size)for(var[l,f]of this.we.values())h.push([l,f])}else{var v,c,d=o-n,w=a-s;for([v,c]of this.we.values())h.push([v,c]),h.push([v+d,c+w])}if(0<h.length){var u=(i=i.Ft(h)).Ut();for(let t=0;t<h.length;t+=2){var[X,M]=h[t],[Z,Y]=h[t+1],X=u.get(X+\",\"+M),M=u.get(Z+\",\"+Y);i.yt[this.Ur].put(new F(r,\"\",new Float32Array(e),new Uint32Array([X,M])))}}this.Le(i,t)}ai(t,r,e){if(0!==this.we.size){var i,n=[];let o=0,a=0;for(i of this.we.values())n.push(i),o+=i[0],a+=i[1];o/=n.length,a/=n.length,n.sort((t,r)=>{var[t,e]=t,[r,i]=r;return Math.atan2(e-a,t-o)-Math.atan2(i-a,r-o)});var s=this.xe().Ft(this.we.values()),h=s.Ut(),l=new Uint)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(32Array(this.we.size);for(let t=0;t<n.length;t++){var[f,v]=n[t];l[t]=h.get(f+\",\"+v)}s.yt[this.Ur].put(new F(r,\"\",new Float32Array(e),l)),this.Le(s,t)}}ni(t,r,e=void 0){void 0===e&&(e=void 0===r.X?[]:[r.X]),1===r.t?this.ii(t,r,e):2===r.t?this.oi(t,r,e):this.ai(t,r,e)}si(t,r){this.hi(t,r,!1)}li(t,r){this.hi(t,r,!0)}hi(t,r,e){var i=this.xe(),o=e?i.Pt(!1).Nt.length:r,a=O.le(i,r);for(let t=0;t<i.yt.length;t++){var n,s=0===t?new Y(new Map,new Set,[]):a.Gr(t-.5),h=a.Gr(t+.5),l=i.yt[t];for(n of new Set([...s.Hr.keys(),...h.Hr.keys()])){var f=s.Hr.get(n),v=h.Hr.get(n),c=l.et.get(n),d=void 0!==c?c.Z.name:void 0;let t=void 0;\"MR\"===d||\"MRX\"===d||\"MRY\"===d?t=f:void 0!==c&&0<c.m()&&(void 0===f?t=v:void 0===v?t=f:f!==v&&((d=new Set([\"X\",\"Y\",\"Z\"])).delete(f),d.delete(v),t=[...d][0])),void 0!==t&&l.it.push(new F(B.get(e?\"DETECTOR\":\"OBSERVABLE_INCLUDE\"),\"\",new Float32Array([o]),c.R))}l.it=l.it.filter(t=>!t.Z.name.startsWith(\"MARK\")||t.Y[0]!==r)}this.Le(i,t)}fi(t,i){var r,e=this.xe(),o=O.le(e,i),a=this.Ur,n=0===a?new Y(new Map)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(,new Set,[]):o.Gr(a-.5),s=o.Gr(a+.5),h=e.yt[a],l=new Set;for(r of new Set([...n.Hr.keys(),...s.Hr.keys()]))if(!l.has(r)){var f=n.Hr.get(r),v=s.Hr.get(r),c=h.et.get(r);if(void 0!==c){var d=c.Z.name;let e=void 0;if(\"R\"===d||\"M\"===d||\"MR\"===d)e=\"Z\";else if(\"RX\"===d||\"MX\"===d||\"MRX\"===d)e=\"X\";else{if(\"RY\"!==d&&\"MY\"!==d&&\"MRY\"!==d){if(\"MXX\"===d||\"MYY\"===d||\"MZZ\"===d){e=d[1];let t=0;for(var w of c.R){if(l.has(w)){t=-1;break}t+=n.Hr.get(w)===e}if(2===t)for(var u of c.R)l.add(u),h.it.push(new F(B.get(\"MARK\"+e),\"\",new Float32Array([i]),new Uint32Array([u])));continue}if(d.startsWith(\"MPP:\")){let r=0;for(let t=0;t<c.R.length;t++){var X=c.R[t];if(e=d[t+4],l.has(X)){r=-1;break}r+=n.Hr.get(X)===e}if(r>c.R.length/2)for(let t=0;t<c.R.length;t++){var M=c.R[t];e=d[t+4],l.add(M),h.it.push(new F(B.get(\"MARK\"+e),\"\",new Float32Array([i]),new Uint32Array([M])))}continue}continue}e=\"Y\"}void 0===f&&void 0===v||(h.it.push(new F(B.get(\"MARK\"+e),\"\",new Float32Array([i]),new Uint32Array([r]))),l.add(r))}}this.Le(e,t)}vi(t,i){let n=this.)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(xe(),s=new Set;var r,e=n.Ut();for(r of this.we.keys())s.add(e.get(r));var o=(()=>{var t,r,{Nt:e,Dt:i}=n.Pt(!1);for(let t=0;t<e.length;t++){var o=O.fe(n,e[t].Tt);if(o.Gr(this.Ur+.5).ne(s))return[o,new F(B.get(\"DETECTOR\"),\"\",new Float32Array([t]),new Uint32Array([]))]}for([t,r]of i.entries()){var a=O.fe(n,r);if(a.Gr(this.Ur+.5).ne(s))return[a,new F(B.get(\"OBSERVABLE_INCLUDE\"),\"\",new Float32Array([t]),new Uint32Array([]))]}})();if(void 0!==o){let[r,e]=o;var a=this.xe();for(let t=0;t<a.yt.length;t++){var h,l=0===t?new Y(new Map,new Set,[]):r.Gr(t-.5),f=r.Gr(t+.5),v=a.yt[t];for(h of new Set([...l.Hr.keys(),...f.Hr.keys()])){var c=l.Hr.get(h),d=f.Hr.get(h),w=v.et.get(h),u=void 0!==w?w.Z.name:void 0;let t=void 0;\"MR\"===u||\"MRX\"===u||\"MRY\"===u||\"R\"===u||\"RX\"===u||\"RY\"===u?t=d:void 0!==w&&0<w.m()&&(void 0===c?t=d:void 0===d?t=c:c!==d&&((u=new Set([\"X\",\"Y\",\"Z\"])).delete(c),u.delete(d),t=[...u][0])),void 0!==t&&v.it.push(new F(B.get(\"MARK\"+t),\"\",new Float32Array([i]),new Uint32Array([h])))}v.it=v.it.filter(t=>t.Z.name!=)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(=e.Z.name||t.Y[0]!==e.Y[0])}this.Le(a,t)}}}(document.getElementById(\"cvn\"));function zt(){var t=m.xe().xt().replaceAll(\"\\nPOLYGON\",\"\\n#!pragma POLYGON\").replaceAll(\"\\nERR\",\"\\n#!pragma ERR\").replaceAll(\"\\nMARK\",\"\\n#!pragma MARK\"),r=y;r.value=t+\"\\n\",r.focus(),r.select()}v.addEventListener(\"click\",t=>{zt()}),Dt.addEventListener(\"click\",t=>{var r=y.value,r=u.It(r);m.commit(r)}),St.addEventListener(\"click\",t=>{var r=document.getElementById(\"divImportExport\");\"none\"===r.style.display?(r.style.display=\"block\",St.textContent=\"Hide Import/Export\",zt()):(r.style.display=\"none\",St.textContent=\"Show Import/Export\",y.value=\"\"),setTimeout(()=>{window.scrollTo(0,0)},0)}),xt.addEventListener(\"click\",t=>{m.Be()}),kt.addEventListener(\"click\",t=>{m.Nr()}),Lt.addEventListener(\"click\",t=>{m.de=new Map(m.we.entries()),m.Ge()}),Ut.addEventListener(\"click\",t=>{m.ei(!1),m.Ge()}),Gt.addEventListener(\"click\",t=>{\"none\"===Ht.style.display?(Ht.style.display=\"block\",Gt.textContent=\"Hide Example Circuits\"):(Ht.style.display=\"none\",Gt.textC)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ontent=\"Show Example Circuits\")}),Ft.addEventListener(\"click\",t=>{m.de=new Map,m.Ge()}),gt.addEventListener(\"click\",t=>{m.Dr()}),Ct.addEventListener(\"click\",t=>{m.qe()}),Tt.addEventListener(\"click\",t=>{m.Ve(1,!1)}),Nt.addEventListener(\"click\",t=>{m.Ve(-1,!1)}),t.addEventListener(\"click\",t=>{m.Ke(!1)}),At.addEventListener(\"click\",t=>{m.ze(!1)}),Pt.addEventListener(\"click\",t=>{m.je(m.Ur+1)}),Ot.addEventListener(\"click\",t=>{m.je(m.Ur-1)}),window.addEventListener(\"resize\",t=>{m.canvas.width=m.canvas.scrollWidth,m.canvas.height=m.canvas.scrollHeight,m.Ge()}),m.canvas.addEventListener(\"mousemove\",t=>{m.qr=t.offsetX+e,m.Wr=t.offsetY+o;var r=m.canvas.width/2;Kt&&1===t.buttons?m.je(Math.floor((t.offsetX-r)/8)):m.Ge()});let Kt=!1;m.canvas.addEventListener(\"mousedown\",t=>{m.qr=t.offsetX+e,m.Wr=t.offsetY+o,m.ue=t.offsetX+e,m.Xe=t.offsetY+o;var r=m.canvas.width/2;(Kt=t.offsetY<20&&t.offsetX>r&&1===t.buttons)?m.je(Math.floor((t.offsetX-r)/8)):m.Ge()}),m.canvas.addEventListener(\"mouseup\",t=>{var r=m.$e(t.altKey);m.ue=void 0)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(,m.Xe=void 0,m.qr=t.offsetX+e,m.Wr=t.offsetY+o,m.Je(r,t.shiftKey,t.ctrlKey),1===t.buttons&&(Kt=!1)});let Qt=void 0;async function $t(){let e=m.xe();e.yt=[e.yt[m.Ur]],0<m.we.size&&(e.yt[0]=e.yt[0].dt(t=>{var r=e.Rt[2*t],t=e.Rt[2*t+1];return m.we.has(r+\",\"+t)}),[r,t]=D(m.we.values()),e=e.St(-r,-t));var t,r=e.xt();Qt=r;try{await navigator.clipboard.writeText(r)}catch(t){console.warn(\"Failed to write to clipboard. Using fallback emulated clipboard.\",t)}}async function Bt(e){let i;try{i=await navigator.clipboard.readText()}catch(t){console.warn(\"Failed to read from clipboard. Using fallback emulated clipboard.\",t),i=Qt}if(void 0!==i){let r=u.It(i);if(1!==r.yt.length)throw new Error(i);let t=m.xe();0<m.we.size&&([o,a]=D(m.we.values()),r=r.St(o,a));var o,a,n=[];for(let t=0;t<r.Rt.length;t+=2)n.push([r.Rt[t],r.Rt[t+1]]);var s,h,l=(t=t.Ft(n)).Ut();for(s of m.we.keys()){var f=l.get(s);void 0!==f&&t.yt[m.Ur].Xt(f)}for(h of r.yt[0].nt()){var v,c=[];for(v of h.R){var d=r.Rt[2*v],w=r.Rt[2*v+1];c.push(l.get(d+\",\"+w))}t.yt[m)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(.Ur].put(new F(h.Z,h.tag,h.Y,new Uint32Array(c)))}m.Le(t,e)}}const qt=function(){let o=new Map;o.set(\"shift+t\",t=>m.Ve(-1,t)),o.set(\"t\",t=>m.Ve(1,t)),o.set(\"escape\",()=>m.Ue()),o.set(\"delete\",t=>m.He(t)),o.set(\"backspace\",t=>m.He(t)),o.set(\"ctrl+delete\",t=>m.ze(t)),o.set(\"ctrl+insert\",t=>m.Ke(t)),o.set(\"ctrl+backspace\",t=>m.ze(t)),o.set(\"ctrl+z\",t=>{t||m.Nr()}),o.set(\"ctrl+y\",t=>{t||m.Dr()}),o.set(\"ctrl+shift+z\",t=>{t||m.Dr()}),o.set(\"ctrl+c\",async t=>{await $t()}),o.set(\"ctrl+v\",Bt),o.set(\"ctrl+x\",async t=>{var r;await $t(),0===m.we.size?((r=m.xe()).yt[m.Ur].et.clear(),r.yt[m.Ur].it.length=0,m.Le(r,t)):m.He(t)}),o.set(\"l\",t=>{t||(m.de=new Map(m.we.entries()),m.Ge())}),o.set(\" \",t=>m.ei(t));for(let[t,r]of[[\"1\",0],[\"2\",1],[\"3\",2],[\"4\",3],[\"5\",4],[\"6\",5],[\"7\",6],[\"8\",7],[\"9\",8],[\"0\",9],[\"-\",10],[\"=\",11],[\"\\\\\",12],[\"`\",13]])o.set(\"\"+t,t=>m.ri(t,r)),o.set(t+\"+x\",t=>m.ni(t,B.get(\"MARKX\").M(r))),o.set(t+\"+y\",t=>m.ni(t,B.get(\"MARKY\").M(r))),o.set(t+\"+z\",t=>m.ni(t,B.get(\"MARKZ\").M(r))),o.set(t+\"+d\",t=>m.li(t,r)),o.se)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(t(t+\"+o\",t=>m.si(t,r)),o.set(t+\"+j\",t=>m.vi(t,r)),o.set(t+\"+k\",t=>m.fi(t,r));let r=.25;function a(t,r,e=void 0){for(var i of t){if(o.has(i))throw new Error(\"Chord collision: \"+i);o.set(i,t=>m.ni(t,B.get(r)))}void 0!==e&&a(t.map(t=>\"shift+\"+t),e)}return o.set(\"p\",t=>m.ni(t,B.get(\"POLYGON\"),[1,0,0,r])),o.set(\"alt+p\",t=>m.ni(t,B.get(\"POLYGON\"),[0,1,0,r])),o.set(\"shift+p\",t=>m.ni(t,B.get(\"POLYGON\"),[0,0,1,r])),o.set(\"p+x\",t=>m.ni(t,B.get(\"POLYGON\"),[1,0,0,r])),o.set(\"p+y\",t=>m.ni(t,B.get(\"POLYGON\"),[0,1,0,r])),o.set(\"p+z\",t=>m.ni(t,B.get(\"POLYGON\"),[0,0,1,r])),o.set(\"p+x+y\",t=>m.ni(t,B.get(\"POLYGON\"),[1,1,0,r])),o.set(\"p+x+z\",t=>m.ni(t,B.get(\"POLYGON\"),[1,0,1,r])),o.set(\"p+y+z\",t=>m.ni(t,B.get(\"POLYGON\"),[0,1,1,r])),o.set(\"p+x+y+z\",t=>m.ni(t,B.get(\"POLYGON\"),[1,1,1,r])),o.set(\"m+p+x\",t=>m.ni(t,f(\"X\".repeat(m.we.size)),[])),o.set(\"m+p+y\",t=>m.ni(t,f(\"Y\".repeat(m.we.size)),[])),o.set(\"m+p+z\",t=>m.ni(t,f(\"Z\".repeat(m.we.size)),[])),o.set(\"f\",t=>m.De(t)),o.set(\"g\",t=>m.Fe(t)),o.set(\"shift+>\",t=>m.We((t,r)=>[t+1,r],t,)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(!1)),o.set(\"shift+<\",t=>m.We((t,r)=>[t-1,r],t,!1)),o.set(\"shift+v\",t=>m.We((t,r)=>[t,r+1],t,!1)),o.set(\"shift+^\",t=>m.We((t,r)=>[t,r-1],t,!1)),o.set(\">\",t=>m.We((t,r)=>[t+1,r],t,!1)),o.set(\"<\",t=>m.We((t,r)=>[t-1,r],t,!1)),o.set(\"v\",t=>m.We((t,r)=>[t,r+1],t,!1)),o.set(\"^\",t=>m.We((t,r)=>[t,r-1],t,!1)),o.set(\".\",t=>m.We((t,r)=>[t+.5,r+.5],t,!1)),a([\"h\",\"h+y\",\"h+x+z\"],\"H\",\"H\"),a([\"h+z\",\"h+x+y\"],\"H_XY\",\"H_XY\"),a([\"h+x\",\"h+y+z\"],\"H_YZ\",\"H_YZ\"),a([\"s+x\",\"s+y+z\"],\"SQRT_X\",\"SQRT_X_DAG\"),a([\"s+y\",\"s+x+z\"],\"SQRT_Y\",\"SQRT_Y_DAG\"),a([\"s\",\"s+z\",\"s+x+y\"],\"S\",\"S_DAG\"),a([\"r+x\",\"r+y+z\"],\"RX\"),a([\"r+y\",\"r+x+z\"],\"RY\"),a([\"r\",\"r+z\",\"r+x+y\"],\"R\"),a([\"m+x\",\"m+y+z\"],\"MX\"),a([\"m+y\",\"m+x+z\"],\"MY\"),a([\"m\",\"m+z\",\"m+x+y\"],\"M\"),a([\"m+r+x\",\"m+r+y+z\"],\"MRX\"),a([\"m+r+y\",\"m+r+x+z\"],\"MRY\"),a([\"m+r\",\"m+r+z\",\"m+r+x+y\"],\"MR\"),a([\"c\"],\"CX\",\"CX\"),a([\"c+x\"],\"CX\",\"CX\"),a([\"c+y\"],\"CY\",\"CY\"),a([\"c+z\"],\"CZ\",\"CZ\"),a([\"j+x\"],\"X\",\"X\"),a([\"j+y\"],\"Y\",\"Y\"),a([\"j+z\"],\"Z\",\"Z\"),a([\"c+x+y\"],\"XCY\",\"XCY\"),a([\"alt+c+x\"],\"XCX\",\"XCX\"),a([\"alt+c+y\"],\"YCY\",\"YCY\"),a([)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(\"w\"],\"SWAP\",\"SWAP\"),a([\"w+x\"],\"CXSWAP\",void 0),a([\"c+w+x\"],\"CXSWAP\",void 0),a([\"i+w\"],\"ISWAP\",\"ISWAP_DAG\"),a([\"w+z\"],\"CZSWAP\",void 0),a([\"c+w+z\"],\"CZSWAP\",void 0),a([\"c+w\"],\"CZSWAP\",void 0),a([\"c+t\"],\"C_XYZ\",\"C_ZYX\"),a([\"c+s+x\"],\"SQRT_XX\",\"SQRT_XX_DAG\"),a([\"c+s+y\"],\"SQRT_YY\",\"SQRT_YY_DAG\"),a([\"c+s+z\"],\"SQRT_ZZ\",\"SQRT_ZZ_DAG\"),a([\"c+s\"],\"SQRT_ZZ\",\"SQRT_ZZ_DAG\"),a([\"c+m+x\"],\"MXX\",\"MXX\"),a([\"c+m+y\"],\"MYY\",\"MYY\"),a([\"c+m+z\"],\"MZZ\",\"MZZ\"),a([\"c+m\"],\"MZZ\",\"MZZ\"),o}();function Wt(r){if(m.Oe.jt(r),\"keydown\"===r.type){if(\"q\"===r.key.toLowerCase())return e=r.shiftKey?5:1,void m.je(m.Ur-e);if(\"e\"===r.key.toLowerCase())return e=r.shiftKey?5:1,void m.je(m.Ur+e);if(\"Home\"===r.key)return m.je(0),void r.preventDefault();if(\"End\"===r.key)return m.je(m.xe().yt.length-1),void r.preventDefault()}var t=m.Oe.Bt;if(0!==t.length){for(var e=t[t.length-1];0<t.length;)t.pop();var i=[...e.zt];if(0!==i.length){i.sort();let t=\"\";e.altKey&&(t+=\"alt+\"),e.ctrlKey&&(t+=\"ctrl+\"),e.metaKey&&(t+=\"meta+\"),e.shiftKey&&(t+=\"shift+\");for(var o of i))CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(t+=o+\"+\";t=t.substring(0,t.length-1);i=qt.get(t);void 0!==i?(i(e.Ht),r.preventDefault()):m.Qe(m.xe())}}}document.addEventListener(\"keydown\",Wt),document.addEventListener(\"keyup\",Wt),m.canvas.width=m.canvas.scrollWidth,m.canvas.height=m.canvas.scrollHeight,m.rev.Ar().subscribe(()=>{m.Te.set(m.Ne(void 0));var t=m.Oe.qt(!1),a=(r.width=r.scrollWidth,r.height=r.scrollHeight,r.getContext(\"2d\"));a.clearRect(0,0,r.width,r.height),a.textAlign=\"right\",a.textBaseline=\"middle\",a.fillText(\"X\",7.5,24.5),a.fillText(\"Y\",7.5,56.5),a.fillText(\"Z\",7.5,88.5),a.textAlign=\"center\",a.textBaseline=\"bottom\";for(let t=0;t<R.length;t++)a.fillText(R[t],24.5+32*t,M);a.fillStyle=\"white\",a.strokeStyle=\"black\";var e=[[\"H_YZ\",\"S_X\",\"R_X\",\"M_X\",\"MR_X\",\"C_X\",\"CXSWAP\",\"√XX\",\"M_XX\",\"PX\",\"X1\"],[\"H\",\"S_Y\",\"R_Y\",\"M_Y\",\"MR_Y\",\"C_Y\",\"SWAP\",\"√YY\",\"M_YY\",\"PY\",\"Y1\"],[\"H_XY\",\"S\",\"R\",\"M\",\"MR\",\"C_Z\",\"CZSWAP\",\"√ZZ\",\"M_ZZ\",\"PZ\",\"Z1\"]];for(let r=0;r<R.length;r++)for(let t=0;t<3;t++)a.fillRect(M+32*r,M+32*t,28,28);for(let r=0;r<R.length;r++)for(let t=0;t<3;t++)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(){var n=e[t][r];let i=M+32*r+14,o=M+32*t+14;if(n.startsWith(\"P\")){a.beginPath();let r=3;\"PX\"===n?(r=4,a.fillStyle=\"red\"):\"PY\"===n?(r=5,a.fillStyle=\"green\",o+=1):\"PZ\"===n&&(r=3,a.fillStyle=\"blue\",o+=2);var s,h=[];for(let t=0;t<r;t++){var l=2*Math.PI/r*(t+.5);h.push([Math.round(i+8.4*Math.sin(l)),Math.round(o+8.4*Math.cos(l))])}a.moveTo(h[h.length-1][0],h[h.length-1][1]);for(s of h)a.lineTo(s[0],s[1]);a.closePath(),a.globalAlpha*=.25,a.fill(),a.globalAlpha*=4}else if(n.endsWith(\"1\")){a.beginPath(),a.moveTo(i+4.8,o-8),a.lineTo(i,o+3.2),a.lineTo(i-4.8,o-8),a.closePath();var f=\"X1\"===n?\"red\":\"Y1\"===n?\"green\":\"blue\";a.fillStyle=f,a.strokeStyle=f,a.fill(),a.lineWidth=2,a.beginPath(),a.moveTo(i,o),a.lineTo(i+14,o),a.stroke(),a.lineWidth=1}else if(a.fillStyle=\"black\",-1!==n.indexOf(\"_\")){var[v,c]=n.split(\"_\");let t=16,r=0,e=0;for(;4<t&&(a.font=t+\"pt monospace\",r=a.measureText(v).width,a.font=.6*t+\"pt monospace\",e=a.measureText(c).width,!(r+e<=26));)--t;i-=(r+e)/2,a.font=t+\"pt monospace\",a.textAlign=\"left\",a.textBaseli)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(ne=\"middle\",a.fillText(v,i,o),a.font=.6*t+\"pt monospace\",a.textAlign=\"left\",a.textBaseline=\"top\",a.fillText(c,i+r,o)}else{let t=16;for(;4<t&&(a.font=t+\"pt monospace\",!(a.measureText(n).width<=28));)--t;a.textAlign=\"center\",a.textBaseline=\"middle\",a.fillText(n,i,o)}}a.strokeStyle=\"black\";for(let r=0;r<R.length;r++)for(let t=0;t<3;t++)a.strokeRect(M+32*r,M+32*t,28,28);void 0!==(t=Et(t)).ge&&(a.fillStyle=\"rgba(255, 255, 0, \"+.5*t.ge.strength+\")\",a.fillRect(0,M+32*t.ge.Ae-2,M+32*R.length,32)),void 0!==t.Se&&(a.fillStyle=\"rgba(255, 255, 0, \"+.5*t.Se.strength+\")\",a.fillRect(M+32*t.Se.ke-2,0,32,106.5)),void 0!==t.Ce&&void 0!==t.Se&&(a.fillStyle=\"rgba(255, 0, 0, 0.5)\",a.fillRect(M+32*t.Se.ke-2,M+32*t.Ce.Ae-2,32,32)),a.textAlign=\"left\",a.textBaseline=\"middle\",a.fillStyle=\"black\"});{var Vt=m.rev;const p=new Zt;v=()=>{try{var t,r=(()=>{var t=document.location.hash.substring(1),r=new Map;if(\"\"!==t)for(var e of t.split(\"&\")){var i,o=e.indexOf(\"=\");-1!==o&&(i=e.substring(0,o),e=decodeURIComponent(e.substring(o+1)),r.set(i,)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(e))}return r})(),e=(r.has(\"circuit\")||(\"[[[DEFAULT-CIRCUIT-CONTENT-LITERAL]]]\"===(t=document.getElementById(\"txtDefaultCircuit\")).value.replaceAll(\"_\",\"-\")?r.set(\"circuit\",\"\"):r.set(\"circuit\",t.value)),u.It(r.get(\"circuit\"))),i=e.xt();Vt.clear(i),e.yt.every(t=>t.ut())&&1===r.size&&i===r.get(\"circuit\")?p.Ie():p.be(i,Yt(i))}catch(t){throw new Error(t)}},window.addEventListener(\"popstate\",v),v(),Vt.kr().Yr().Zr(1).subscribe(t=>{p.be(t,Yt(t))})}m.Te.mr().subscribe(t=>requestAnimationFrame(()=>wt(m.canvas.getContext(\"2d\"),t))),window.addEventListener(\"focus\",()=>{m.Oe.Vt()}),window.addEventListener(\"blur\",()=>{m.Oe.Vt()});for(let r of document.getElementById(\"examples-div\").querySelectorAll(\"a\"))r.onclick=t=>{if(!(t.shiftKey||t.ctrlKey||t.altKey||0!==t.button))return t=r.href.split(\"#circuit=\")[1],m.rev.commit(t),!1};\n)CRUMBLE_PART\");\n    result.append(R\"CRUMBLE_PART(</script>\n)CRUMBLE_PART\");\n    return result;\n}\n"
  },
  {
    "path": "src/stim/diagram/crumble_data.h",
    "content": "#ifndef _STIM_DIAGRAM_CRUMBLE_DATA_H\n#define _STIM_DIAGRAM_CRUMBLE_DATA_H\n\n#include <string>\n\nnamespace stim_draw_internal {\n\nstd::string make_crumble_html();\n\n}\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/detector_slice/detector_slice_set.cc",
    "content": "#include \"stim/diagram/detector_slice/detector_slice_set.h\"\n\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/diagram/coord.h\"\n#include \"stim/diagram/diagram_util.h\"\n#include \"stim/diagram/timeline/timeline_ascii_drawer.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/util_bot/str_util.h\"\n\nconstexpr float SLICE_WINDOW_GAP = 1.1f;\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\ntemplate <typename T>\ninline void write_key_val(std::ostream &out, const char *key, const T &val) {\n    out << ' ' << key << \"=\\\"\" << val << \"\\\"\";\n}\n\nstruct DetectorSliceSetComputer {\n    SparseUnsignedRevFrameTracker tracker;\n    uint64_t tick_cur;\n    uint64_t first_yield_tick;\n    uint64_t num_yield_ticks;\n    std::set<uint32_t> used_qubits;\n    std::function<void(void)> on_tick_callback;\n    DetectorSliceSetComputer(const Circuit &circuit, uint64_t first_yield_tick, uint64_t num_yield_ticks);\n    bool process_block_rev(const Circuit &block);\n    bool process_op_rev(const Circuit &parent, const CircuitInstruction &op);\n    bool process_tick();\n    void process_undo_start_of_circuit();\n};\n\nbool DetectorSliceSetComputer::process_block_rev(const Circuit &block) {\n    for (size_t k = block.operations.size(); k--;) {\n        if (process_op_rev(block, block.operations[k])) {\n            return true;\n        }\n    }\n    return false;\n}\n\nbool DetectorSliceSetComputer::process_tick() {\n    if (tick_cur >= first_yield_tick && tick_cur < first_yield_tick + num_yield_ticks) {\n        on_tick_callback();\n    }\n    tick_cur--;\n\n    // Offset by 1 to go one tick further, and catch any anticommutation issues.\n    return tick_cur + 1 < first_yield_tick;\n}\n\nvoid DetectorSliceSetComputer::process_undo_start_of_circuit() {\n    tracker.undo_implicit_RZs_at_start_of_circuit();\n}\n\nbool DetectorSliceSetComputer::process_op_rev(const Circuit &parent, const CircuitInstruction &op) {\n    if (op.gate_type == GateType::TICK) {\n        return process_tick();\n    } else if (op.gate_type == GateType::REPEAT) {\n        const auto &loop_body = op.repeat_block_body(parent);\n        uint64_t stop_iter = first_yield_tick + num_yield_ticks;\n        uint64_t max_skip = std::max(tick_cur, stop_iter) - stop_iter;\n        uint64_t reps = op.repeat_block_rep_count();\n        uint64_t ticks_per_iteration = loop_body.count_ticks();\n        uint64_t skipped_iterations = max_skip == 0              ? 0\n                                      : ticks_per_iteration == 0 ? reps\n                                                                 : std::min(reps, max_skip / ticks_per_iteration);\n        if (skipped_iterations) {\n            // We can allow the analyzer to fold parts of the loop we aren't yielding.\n            tracker.undo_loop(loop_body, skipped_iterations);\n            reps -= skipped_iterations;\n            tick_cur -= ticks_per_iteration * skipped_iterations;\n        }\n        while (reps > 0) {\n            if (process_block_rev(loop_body)) {\n                return true;\n            }\n            reps--;\n        }\n        return false;\n    } else {\n        for (auto t : op.targets) {\n            if (t.has_qubit_value()) {\n                used_qubits.insert(t.qubit_value());\n            }\n        }\n        tracker.undo_gate(op);\n        return false;\n    }\n}\nDetectorSliceSetComputer::DetectorSliceSetComputer(\n    const Circuit &circuit, uint64_t first_yield_tick, uint64_t num_yield_ticks)\n    : tracker(circuit.count_qubits(), circuit.count_measurements(), circuit.count_detectors(), false),\n      first_yield_tick(first_yield_tick),\n      num_yield_ticks(num_yield_ticks) {\n    tick_cur = circuit.count_ticks() + 1;  // +1 because of artificial TICKs at start and end.\n}\n\nstd::string DetectorSliceSet::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\nstd::ostream &stim_draw_internal::operator<<(std::ostream &out, const DetectorSliceSet &slice) {\n    slice.write_text_diagram_to(out);\n    return out;\n}\nstd::ostream &stim_draw_internal::operator<<(std::ostream &out, const CoordFilter &filter) {\n    if (filter.use_target) {\n        out << filter.exact_target;\n    } else {\n        out << comma_sep(filter.coordinates);\n    }\n    return out;\n}\n\nvoid DetectorSliceSet::write_text_diagram_to(std::ostream &out) const {\n    DiagramTimelineAsciiDrawer drawer(num_qubits, false);\n    drawer.moment_spacing = 2;\n\n    for (const auto &s : anticommutations) {\n        drawer.reserve_drawing_room_for_targets(s.second);\n        for (const auto &t : s.second) {\n            std::stringstream ss;\n            ss << \"ANTICOMMUTED\";\n            ss << \":\";\n            ss << s.first.second;\n            drawer.diagram.add_entry(\n                AsciiDiagramEntry{\n                    AsciiDiagramPos{\n                        drawer.m2x(drawer.cur_moment + 1),\n                        drawer.q2y(t.qubit_value()),\n                        0,\n                        0.5,\n                    },\n                    ss.str(),\n                });\n        }\n    }\n\n    for (const auto &s : slices) {\n        drawer.reserve_drawing_room_for_targets(s.second);\n        for (const auto &t : s.second) {\n            std::stringstream ss;\n            if (t.is_x_target()) {\n                ss << \"X\";\n            } else if (t.is_y_target()) {\n                ss << \"Y\";\n            } else if (t.is_z_target()) {\n                ss << \"Z\";\n            } else {\n                ss << \"?\";\n            }\n            ss << \":\";\n            ss << s.first.second;\n            drawer.diagram.add_entry(\n                AsciiDiagramEntry{\n                    AsciiDiagramPos{\n                        drawer.m2x(drawer.cur_moment),\n                        drawer.q2y(t.qubit_value()),\n                        0,\n                        0.5,\n                    },\n                    ss.str(),\n                });\n        }\n    }\n\n    // Make sure qubit lines are drawn first, so they are in the background.\n    drawer.diagram.lines.insert(drawer.diagram.lines.begin(), drawer.num_qubits, {{0, 0, 0.0, 0.5}, {0, 0, 1.0, 0.5}});\n    for (size_t q = 0; q < drawer.num_qubits; q++) {\n        drawer.diagram.lines[q] = {\n            {0, drawer.q2y(q), 1.0, 0.5},\n            {drawer.m2x(drawer.cur_moment) + 1, drawer.q2y(q), 1.0, 0.5},\n        };\n        std::stringstream ss;\n        ss << \"q\";\n        ss << q;\n        ss << \":\";\n        auto p = coordinates.find(q);\n        if (p != coordinates.end() && !p->second.empty()) {\n            ss << \"(\" << comma_sep(p->second) << \")\";\n        }\n        ss << \" \";\n        drawer.diagram.add_entry(\n            AsciiDiagramEntry{\n                {0, drawer.q2y(q), 1.0, 0.5},\n                ss.str(),\n            });\n    }\n\n    drawer.diagram.render(out);\n}\n\nstd::set<uint64_t> DetectorSliceSet::used_qubits() const {\n    std::set<uint64_t> result;\n    for (const auto &e : coordinates) {\n        result.insert(e.first);\n    }\n    for (const auto &e : slices) {\n        for (const auto &t : e.second) {\n            result.insert(t.qubit_value());\n        }\n    }\n    return result;\n}\n\nbool CoordFilter::matches(stim::SpanRef<const double> coords, stim::DemTarget target) const {\n    if (use_target) {\n        return target == exact_target;\n    }\n    if (!target.is_relative_detector_id()) {\n        return false;\n    }\n    for (size_t k = 0; k < coordinates.size(); k++) {\n        if (!std::isnan(coordinates[k])) {\n            if (coords.size() <= k || coords[k] != coordinates[k]) {\n                return false;\n            }\n        }\n    }\n    return true;\n}\nCoordFilter CoordFilter::parse_from(std::string_view data) {\n    CoordFilter filter;\n    if (data.empty()) {\n        // no filter\n    } else if (data[0] == 'D') {\n        filter.use_target = true;\n        filter.exact_target = DemTarget::relative_detector_id(parse_exact_uint64_t_from_string(data.substr(1)));\n    } else if (data[0] == 'L') {\n        filter.use_target = true;\n        filter.exact_target = DemTarget::observable_id(parse_exact_uint64_t_from_string(data.substr(1)));\n    } else {\n        for (const auto &v : split_view(',', data)) {\n            if (v == \"*\") {\n                filter.coordinates.push_back(std::numeric_limits<double>::quiet_NaN());\n            } else {\n                filter.coordinates.push_back(parse_exact_double_from_string(v));\n            }\n        }\n    }\n    return filter;\n}\n\nDetectorSliceSet DetectorSliceSet::from_circuit_ticks(\n    const stim::Circuit &circuit, uint64_t start_tick, uint64_t num_ticks, SpanRef<const CoordFilter> coord_filter) {\n    num_ticks = std::max(uint64_t{1}, std::min(num_ticks, circuit.count_ticks() - start_tick + 1));\n\n    DetectorSliceSetComputer helper(circuit, start_tick, num_ticks);\n    size_t num_qubits = helper.tracker.xs.size();\n\n    std::set<DemTarget> xs;\n    std::set<DemTarget> ys;\n    std::set<DemTarget> zs;\n    DetectorSliceSet result;\n    result.num_qubits = num_qubits;\n    result.min_tick = start_tick;\n    result.num_ticks = num_ticks;\n\n    auto process_anticommutations = [&](size_t out_tick) {\n        for (const auto &[d, g] : helper.tracker.anticommutations) {\n            result.anticommutations[{out_tick, d}].push_back(g);\n\n            // Stop propagating it backwards if it broke.\n            for (size_t q = 0; q < num_qubits; q++) {\n                if (helper.tracker.xs[q].contains(d)) {\n                    helper.tracker.xs[q].xor_item(d);\n                }\n                if (helper.tracker.zs[q].contains(d)) {\n                    helper.tracker.zs[q].xor_item(d);\n                }\n            }\n        }\n        helper.tracker.anticommutations.clear();\n    };\n\n    helper.on_tick_callback = [&]() {\n        process_anticommutations(helper.tick_cur + 1);\n\n        // Record locations of detectors and observables.\n        for (size_t q = 0; q < num_qubits; q++) {\n            xs.clear();\n            ys.clear();\n            zs.clear();\n            for (auto t : helper.tracker.xs[q]) {\n                xs.insert(t);\n            }\n            for (auto t : helper.tracker.zs[q]) {\n                if (xs.find(t) == xs.end()) {\n                    zs.insert(t);\n                } else {\n                    xs.erase(t);\n                    ys.insert(t);\n                }\n            }\n\n            for (const auto &t : xs) {\n                result.slices[{helper.tick_cur, t}].push_back(GateTarget::x(q));\n            }\n            for (const auto &t : ys) {\n                result.slices[{helper.tick_cur, t}].push_back(GateTarget::y(q));\n            }\n            for (const auto &t : zs) {\n                result.slices[{helper.tick_cur, t}].push_back(GateTarget::z(q));\n            }\n        }\n    };\n\n    if (!helper.process_tick()) {\n        bool early_exit = helper.process_block_rev(circuit);\n        if (!early_exit) {\n            helper.process_undo_start_of_circuit();\n            process_anticommutations(1);\n        }\n    }\n\n    std::set<uint64_t> included_detectors;\n    for (const auto &t : result.slices) {\n        if (t.first.second.is_relative_detector_id()) {\n            included_detectors.insert(t.first.second.data);\n        }\n    }\n    result.detector_coordinates = circuit.get_detector_coordinates(included_detectors);\n\n    result.coordinates = circuit.get_final_qubit_coords();\n    for (const auto &q : helper.used_qubits) {\n        result.coordinates[q];  // Default construct if doesn't exist.\n    }\n\n    auto keep = [&](DemTarget t) {\n        SpanRef<const double> coords{};\n        if (t.is_relative_detector_id()) {\n            auto coords_ptr = result.detector_coordinates.find(t.data);\n            if (coords_ptr != result.detector_coordinates.end()) {\n                coords = coords_ptr->second;\n            }\n        }\n        for (const auto &filter : coord_filter) {\n            if (filter.matches(coords, t)) {\n                return true;\n            }\n        }\n        return false;\n    };\n    std::vector<std::pair<uint64_t, DemTarget>> removed;\n    for (const auto &t : result.slices) {\n        if (!keep(t.first.second)) {\n            removed.push_back(t.first);\n        }\n    }\n    for (auto t : removed) {\n        result.slices.erase(t);\n        if (t.second.is_relative_detector_id()) {\n            result.detector_coordinates.erase(t.second.raw_id());\n        }\n    }\n\n    return result;\n}\n\nCoord<2> flattened_2d(SpanRef<const double> c) {\n    float x = 0;\n    float y = 0;\n    if (c.size() >= 1) {\n        x = (float)c[0];\n    }\n    if (c.size() >= 2) {\n        y = (float)c[1];\n    }\n\n    // Arbitrary orthographic projection.\n    for (size_t k = 2; k < c.size(); k++) {\n        x += (float)c[k] / k;\n        y += (float)c[k] / (k * k);\n    }\n\n    return {x, y};\n}\n\nfloat pick_characteristic_distance(const std::set<uint64_t> &used, const std::vector<Coord<2>> &coords_2d) {\n    if (used.size() == 0) {\n        return 1;\n    }\n\n    Coord<2> biggest{-INFINITY, -INFINITY};\n    for (auto q : used) {\n        biggest = std::max(biggest, coords_2d[q]);\n    }\n\n    float closest_squared_distance = INFINITY;\n    for (auto pt : coords_2d) {\n        if (biggest == pt) {\n            continue;\n        }\n        auto delta = biggest - pt;\n        auto d = delta.xyz[0] * delta.xyz[0] + delta.xyz[1] * delta.xyz[1];\n        if (d < closest_squared_distance) {\n            closest_squared_distance = d;\n        }\n    }\n\n    float result = sqrtf(closest_squared_distance);\n    if (result == INFINITY) {\n        result = 1;\n    }\n    return result;\n}\n\nFlattenedCoords FlattenedCoords::from(const DetectorSliceSet &set, float desired_unit_distance) {\n    auto used = set.used_qubits();\n    FlattenedCoords result;\n\n    for (uint64_t q = 0; q < set.num_qubits; q++) {\n        Coord<2> c{(float)q, 0};\n        auto p = set.coordinates.find(q);\n        if (p != set.coordinates.end() && !p->second.empty()) {\n            c = flattened_2d(p->second);\n        }\n        result.qubit_coords.push_back(c);\n    }\n    result.unscaled_qubit_coords = result.qubit_coords;\n\n    for (const auto &e : set.detector_coordinates) {\n        result.det_coords.insert({e.first, flattened_2d(e.second)});\n    }\n\n    float characteristic_distance = pick_characteristic_distance(used, result.qubit_coords);\n    result.unit_distance = desired_unit_distance;\n    float scale = desired_unit_distance / characteristic_distance;\n    for (auto &c : result.qubit_coords) {\n        c *= scale;\n    }\n    for (auto &e : result.det_coords) {\n        e.second *= scale;\n    }\n    if (!used.empty()) {\n        std::vector<Coord<2>> used_coords;\n        for (const auto &u : used) {\n            used_coords.push_back(result.qubit_coords[u]);\n        }\n        auto minmax = Coord<2>::min_max(used_coords);\n        auto offset = minmax.first;\n        offset *= -1;\n        offset.xyz[0] += 16;\n        offset.xyz[1] += 16;\n        for (auto &c : result.qubit_coords) {\n            c += offset;\n        }\n        for (auto &c : used_coords) {\n            c += offset;\n        }\n        for (auto &e : result.det_coords) {\n            e.second += offset;\n        }\n        result.size = minmax.second - minmax.first;\n        result.size.xyz[0] += 32;\n        result.size.xyz[1] += 32;\n    } else {\n        result.size.xyz[0] = 1;\n        result.size.xyz[1] = 1;\n    }\n\n    return result;\n}\n\nconst char *pick_color(SpanRef<const GateTarget> terms) {\n    bool has_x = false;\n    bool has_y = false;\n    bool has_z = false;\n    for (const auto &term : terms) {\n        has_x |= term.is_x_target();\n        has_y |= term.is_y_target();\n        has_z |= term.is_z_target();\n    }\n    if (has_x + has_y + has_z != 1) {\n        return nullptr;\n    } else if (has_x) {\n        return X_RED;\n    } else if (has_y) {\n        return Y_GREEN;\n    } else {\n        assert(has_z);\n        return Z_BLUE;\n    }\n}\n\nfloat offset_angle_from_to(Coord<2> origin, Coord<2> dst) {\n    auto d = dst - origin;\n    if (d.xyz[0] * d.xyz[0] + d.xyz[1] * d.xyz[1] < 1e-6) {\n        return 0.0f;\n    }\n    float offset_angle = atan2f(d.xyz[1], d.xyz[0]);\n    offset_angle += 2.0f * 3.14159265359f;\n    offset_angle = fmodf(offset_angle, 2.0f * 3.14159265359f);\n    // The -0.01f is to move the wraparound float error away from the common angle PI.\n    if (offset_angle > 3.14159265359f - 0.01f) {\n        offset_angle -= 2.0f * 3.14159265359f;\n    }\n    return offset_angle;\n}\n\nfloat _mirror_score(SpanRef<const Coord<2>> coords, size_t i, size_t j) {\n    auto para = coords[j] - coords[i];\n    float f = para.norm2();\n    if (f < 1e-4) {\n        return INFINITY;\n    }\n    para /= sqrtf(f);\n\n    Coord<2> perp = {-para.xyz[0], para.xyz[1]};\n    std::vector<Coord<2>> left;\n    std::vector<Coord<2>> right;\n    for (size_t k = 0; k < coords.size(); k++) {\n        if (k == i || k == j) {\n            continue;\n        }\n        auto d = coords[k] - coords[i];\n        float x = d.dot(para);\n        float y = d.dot(perp);\n        if (y < 0) {\n            right.push_back({x, -y});\n        } else {\n            left.push_back({x, y});\n        }\n    }\n    if (left.size() != right.size()) {\n        return INFINITY;\n    }\n    std::stable_sort(left.begin(), left.end());\n    std::stable_sort(right.begin(), right.end());\n    for (size_t k = 0; k < left.size(); k++) {\n        if ((left[k] - right[k]).norm2() > 1e-2) {\n            return INFINITY;\n        }\n    }\n\n    float max_distance = 0;\n    for (size_t k = 0; k < left.size(); k++) {\n        max_distance = std::max(max_distance, left[k].xyz[1]);\n    }\n\n    return max_distance;\n}\n\nbool _pick_center_using_mirror_symmetry(SpanRef<const Coord<2>> coords, Coord<2> &out) {\n    float best_score = INFINITY;\n    for (size_t i = 0; i < coords.size(); i++) {\n        for (size_t j = i + 1; j < coords.size(); j++) {\n            float f = _mirror_score(coords, i, j);\n            if (f < best_score) {\n                out = (coords[i] + coords[j]) / 2;\n                best_score = f;\n            }\n        }\n    }\n    return best_score < INFINITY;\n}\n\nCoord<2> stim_draw_internal::pick_polygon_center(SpanRef<const Coord<2>> coords) {\n    Coord<2> center{0, 0};\n    if (_pick_center_using_mirror_symmetry(coords, center)) {\n        return center;\n    }\n\n    for (const auto &coord : coords) {\n        center += coord;\n    }\n    center /= coords.size();\n    return center;\n}\n\nbool stim_draw_internal::is_colinear(Coord<2> a, Coord<2> b, Coord<2> c, float atol) {\n    for (size_t k = 0; k < 3; k++) {\n        auto d1 = a - b;\n        auto d2 = b - c;\n        if (d1.norm() < atol || d2.norm() < atol) {\n            return true;\n        }\n        d1 /= d1.norm();\n        d2 /= d2.norm();\n        if (fabs(d1.dot({d2.xyz[1], -d2.xyz[0]})) < atol) {\n            return true;\n        }\n        std::swap(a, b);\n        std::swap(b, c);\n    }\n    return false;\n}\n\ndouble stim_draw_internal::inv_space_fill_transform(Coord<2> a) {\n    double dx = ldexp((double)a.xyz[0], 4);\n    double dy = ldexp((double)a.xyz[1], 4);\n    uint64_t x = (uint64_t)std::min((double)(1ULL << 31), std::max(dx, 0.0));\n    uint64_t y = (uint64_t)std::min((double)(1ULL << 31), std::max(dy, 0.0));\n\n    for (size_t k = 64; k-- > 0;) {\n        uint64_t b = 1ULL << k;\n        uint64_t m = b - 1;\n        if ((x ^ y) & b) {\n            x ^= m;\n        }\n        if (!(y & b)) {\n            x ^= y & m;\n            y ^= x & m;\n            x ^= y & m;\n        }\n    }\n    y ^= x;\n\n    uint64_t gray = 0;\n    for (size_t k = 64; k--;) {\n        uint64_t b = 1ULL << k;\n        if (y & b) {\n            gray ^= b - 1;\n        }\n    }\n    x ^= gray;\n    y ^= gray;\n\n    uint64_t interleave = 0;\n    for (size_t k = 32; k--;) {\n        interleave |= ((x >> k) & 1ULL) << (2 * k + 1);\n        interleave |= ((y >> k) & 1ULL) << (2 * k);\n    }\n\n    return interleave;\n}\n\nvoid _draw_observable(\n    std::ostream &out,\n    uint64_t index,\n    const std::function<Coord<2>(uint32_t qubit)> &unscaled_coords,\n    const std::function<Coord<2>(uint64_t tick, uint32_t qubit)> &coords,\n    uint64_t tick,\n    SpanRef<const GateTarget> terms,\n    std::vector<Coord<2>> &pts_workspace,\n    bool next_tick_exists,\n    size_t scale) {\n    std::vector<GateTarget> terms_copy;\n    terms_copy.insert(terms_copy.end(), terms.begin(), terms.end());\n    std::stable_sort(terms_copy.begin(), terms_copy.end(), [&](GateTarget a, GateTarget b) {\n        auto a2 = inv_space_fill_transform(unscaled_coords(a.qubit_value()));\n        auto b2 = inv_space_fill_transform(unscaled_coords(b.qubit_value()));\n        if (a2 != b2) {\n            return a2 < b2;\n        }\n        a2 = inv_space_fill_transform(coords(tick, a.qubit_value()));\n        b2 = inv_space_fill_transform(coords(tick, b.qubit_value()));\n        return a2 < b2;\n    });\n\n    pts_workspace.clear();\n    for (const auto &term : terms_copy) {\n        pts_workspace.push_back(coords(tick, term.qubit_value()));\n    }\n\n    // TODO: CURRENTLY DISABLED BECAUSE IT'S UNCLEAR IF IT HELPS OR HURTS.\n    //    // Draw a semi-janky path connecting the observable together.\n    //    out << \"<path d=\\\"\";\n    //    out << \"M\" << pts_workspace[0].xyz[0] << \",\" << pts_workspace[0].xyz[1];\n    //    size_t n = pts_workspace.size();\n    //    for (size_t k = 1; k < n; k++) {\n    //        const auto &p = pts_workspace[(k - 1) % n];\n    //        const auto &a = pts_workspace[k];\n    //\n    //        auto dif = a - p;\n    //        auto average = (a + p) * 0.5;\n    //        if (dif.norm() > 50 * scale) {\n    //            dif /= dif.norm() / 50 / scale;\n    //        }\n    //        Coord<2> perp{-dif.xyz[1], dif.xyz[0]};\n    //        auto c1 = average + perp * 0.1 - dif * 0.1;\n    //        auto c2 = average + perp * 0.1 + dif * 0.1;\n    //\n    //        out << \"C\";\n    //        out << c1.xyz[0] << \" \" << c1.xyz[1] << \", \";\n    //        out << c2.xyz[0] << \" \" << c2.xyz[1] << \", \";\n    //        out << a.xyz[0] << \" \" << a.xyz[1];\n    //    }\n    //    out << \"\\\" id=\\\"obs-path:\" << index << \":\" << tick << \"\\\"\";\n    //    write_key_val(out, \"stroke\", BG_GREY);\n    //    write_key_val(out, \"fill\", \"none\");\n    //    write_key_val(out, \"stroke-width\", scale);\n    //    out << \"/>\\n\";\n\n    for (size_t k = 0; k < terms_copy.size(); k++) {\n        const auto &t = terms_copy[k];\n        out << \"<circle\";\n        out << \" id=\\\"obs-term:\" << index << \":\" << tick << \":\" << k << \"\\\"\";\n        auto c = coords(tick, t.qubit_value());\n        write_key_val(out, \"cx\", c.xyz[0]);\n        write_key_val(out, \"cy\", c.xyz[1]);\n        write_key_val(out, \"r\", scale * 1.1f);\n        write_key_val(out, \"stroke\", \"none\");\n        write_key_val(out, \"fill\", t.is_x_target() ? X_RED : t.is_y_target() ? Y_GREEN : Z_BLUE);\n        out << \"/>\\n\";\n    }\n    if (next_tick_exists) {\n        for (size_t k = 0; k < terms_copy.size(); k++) {\n            const auto &t = terms_copy[k];\n            out << \"<circle\";\n            out << \" id=\\\"obs-term-shadow:\" << index << \":\" << tick << \":\" << k << \"\\\"\";\n            auto c = coords(tick + 1, t.qubit_value());\n            write_key_val(out, \"cx\", c.xyz[0]);\n            write_key_val(out, \"cy\", c.xyz[1]);\n            write_key_val(out, \"r\", scale * 1.1f);\n            write_key_val(out, \"stroke\", t.is_x_target() ? X_RED : t.is_y_target() ? Y_GREEN : Z_BLUE);\n            write_key_val(out, \"stroke-width\", 3);\n            write_key_val(out, \"fill\", \"none\");\n            out << \"/>\\n\";\n        }\n    }\n}\n\nvoid _start_many_body_svg_path(\n    std::ostream &out,\n    const std::function<Coord<2>(uint64_t tick, uint32_t qubit)> &coords,\n    uint64_t tick,\n    SpanRef<const GateTarget> terms,\n    std::vector<Coord<2>> &pts_workspace) {\n    pts_workspace.clear();\n    for (const auto &term : terms) {\n        pts_workspace.push_back(coords(tick, term.qubit_value()));\n    }\n    auto center = pick_polygon_center(pts_workspace);\n    std::stable_sort(pts_workspace.begin(), pts_workspace.end(), [&](Coord<2> a, Coord<2> b) {\n        return offset_angle_from_to(center, a) < offset_angle_from_to(center, b);\n    });\n\n    out << \"<path d=\\\"\";\n    out << \"M\" << pts_workspace[0].xyz[0] << \",\" << pts_workspace[0].xyz[1];\n    size_t n = pts_workspace.size();\n    for (size_t k = 0; k < n; k++) {\n        const auto &p = pts_workspace[(k + n - 1) % n];\n        const auto &a = pts_workspace[k];\n        const auto &b = pts_workspace[(k + 1) % n];\n        const auto &c = pts_workspace[(k + 2) % n];\n        if (is_colinear(p, a, b, 3e-2f) || is_colinear(a, b, c, 3e-2f)) {\n            out << \" C\";\n            auto d = b - a;\n            d = {d.xyz[1], -d.xyz[0]};\n            d *= -0.1;\n            d += (a + b) / 2;\n            out << d.xyz[0] << \" \" << d.xyz[1] << \",\";\n            out << d.xyz[0] << \" \" << d.xyz[1] << \",\";\n            out << b.xyz[0] << \" \" << b.xyz[1];\n        } else {\n            out << \" L\" << b.xyz[0] << \",\" << b.xyz[1];\n        }\n    }\n    out << '\"';\n}\n\nvoid _start_two_body_svg_path(\n    std::ostream &out,\n    const std::function<Coord<2>(uint64_t tick, uint32_t qubit)> &coords,\n    uint64_t tick,\n    SpanRef<const GateTarget> terms) {\n    auto a = coords(tick, terms[0].qubit_value());\n    auto b = coords(tick, terms[1].qubit_value());\n    auto dif = b - a;\n    auto average = (a + b) * 0.5;\n    if (dif.norm() > 64) {\n        dif /= dif.norm() / 64;\n    }\n    Coord<2> perp{-dif.xyz[1], dif.xyz[0]};\n    auto ac1 = average + perp * 0.2f - dif * 0.2f;\n    auto ac2 = average + perp * 0.2f + dif * 0.2f;\n    auto bc1 = average + perp * -0.2f + dif * 0.2f;\n    auto bc2 = average + perp * -0.2f - dif * 0.2f;\n\n    out << \"<path d=\\\"\";\n    out << \"M\" << a.xyz[0] << \",\" << a.xyz[1] << \" \";\n    out << \"C\";\n    out << ac1.xyz[0] << \" \" << ac1.xyz[1] << \", \";\n    out << ac2.xyz[0] << \" \" << ac2.xyz[1] << \", \";\n    out << b.xyz[0] << \" \" << b.xyz[1] << \" \";\n    out << \"C\";\n    out << bc1.xyz[0] << \" \" << bc1.xyz[1] << \", \";\n    out << bc2.xyz[0] << \" \" << bc2.xyz[1] << \", \";\n    out << a.xyz[0] << \" \" << a.xyz[1];\n    out << '\"';\n}\n\nvoid _start_one_body_svg_path(\n    std::ostream &out,\n    const std::function<Coord<2>(uint64_t tick, uint32_t qubit)> &coords,\n    uint64_t tick,\n    SpanRef<const GateTarget> terms,\n    size_t scale) {\n    auto c = coords(tick, terms[0].qubit_value());\n    out << \"<circle\";\n    write_key_val(out, \"cx\", c.xyz[0]);\n    write_key_val(out, \"cy\", c.xyz[1]);\n    write_key_val(out, \"r\", scale);\n}\n\nvoid _start_slice_shape_command(\n    std::ostream &out,\n    const std::function<Coord<2>(uint64_t tick, uint32_t qubit)> &coords,\n    uint64_t tick,\n    SpanRef<const GateTarget> terms,\n    std::vector<Coord<2>> &pts_workspace,\n    size_t scale) {\n    if (terms.size() > 2) {\n        _start_many_body_svg_path(out, coords, tick, terms, pts_workspace);\n    } else if (terms.size() == 2) {\n        _start_two_body_svg_path(out, coords, tick, terms);\n    } else if (terms.size() == 1) {\n        _start_one_body_svg_path(out, coords, tick, terms, scale);\n    }\n}\n\nvoid DetectorSliceSet::write_svg_diagram_to(std::ostream &out, size_t num_rows) const {\n    size_t num_cols;\n    if (num_rows == 0) {\n        num_cols = (uint64_t)ceil(sqrt((double)num_ticks));\n        num_rows = num_ticks / num_cols;\n        while (num_cols * num_rows < num_ticks) {\n            num_rows++;\n        }\n        while (num_cols * num_rows >= num_ticks + num_rows) {\n            num_cols--;\n        }\n    } else {\n        num_cols = (num_ticks + num_rows - 1) / num_rows;\n    }\n\n    auto coordsys = FlattenedCoords::from(*this, 32);\n    out << R\"SVG(<svg viewBox=\"0 0 )SVG\";\n    out << coordsys.size.xyz[0] * ((num_cols - 1) * SLICE_WINDOW_GAP + 1);\n    out << \" \";\n    out << coordsys.size.xyz[1] * ((num_rows - 1) * SLICE_WINDOW_GAP + 1);\n    out << R\"SVG(\" xmlns=\"http://www.w3.org/2000/svg\">)SVG\";\n    out << \"\\n\";\n\n    auto coords = [&](uint64_t tick, uint32_t qubit) {\n        auto result = coordsys.qubit_coords[qubit];\n        uint64_t s = tick - min_tick;\n        uint64_t sx = s % num_cols;\n        uint64_t sy = s / num_cols;\n        result.xyz[0] += coordsys.size.xyz[0] * sx * SLICE_WINDOW_GAP;\n        result.xyz[1] += coordsys.size.xyz[1] * sy * SLICE_WINDOW_GAP;\n        return result;\n    };\n    auto unscaled_coords = [&](uint32_t qubit) {\n        return coordsys.unscaled_qubit_coords[qubit];\n    };\n    write_svg_contents_to(out, unscaled_coords, coords, min_tick + num_ticks, 6);\n\n    out << \"<g id=\\\"qubit_dots\\\">\\n\";\n    for (size_t k = 0; k < num_ticks; k++) {\n        for (auto q : used_qubits()) {\n            auto t = min_tick + k;\n\n            std::stringstream id_ss;\n            id_ss << \"qubit_dot\";\n            id_ss << \":\" << q;\n            add_coord_summary_to_ss(id_ss, coordinates.at(q));  // the raw qubit coordinates, not projected to 2D\n            id_ss << \":\" << t;                                  // the absolute tick\n\n            auto sc = coords(t, q);  // the svg coordinates, offset to the correct slice plot\n\n            out << \"<circle\";\n            write_key_val(out, \"id\", id_ss.str());\n            write_key_val(out, \"cx\", sc.xyz[0]);\n            write_key_val(out, \"cy\", sc.xyz[1]);\n            write_key_val(out, \"r\", 2);\n            write_key_val(out, \"stroke\", \"none\");\n            write_key_val(out, \"fill\", \"black\");\n            out << \"/>\\n\";\n        }\n    }\n    out << \"</g>\\n\";\n\n    // Border around different slices.\n    if (num_ticks > 1) {\n        size_t k = 0;\n        out << \"<g id=\\\"tick_borders\\\">\\n\";\n        for (uint64_t col = 0; col < num_cols; col++) {\n            for (uint64_t row = 0; row < num_rows && row * num_cols + col < num_ticks; row++) {\n                auto sw = coordsys.size.xyz[0];\n                auto sh = coordsys.size.xyz[1];\n\n                std::stringstream id_ss;\n                id_ss << \"tick_border:\" << k;\n                id_ss << \":\" << row << \"_\" << col;\n                id_ss << \":\" << k + min_tick;\n\n                out << \"<rect\";\n                write_key_val(out, \"id\", id_ss.str());\n                write_key_val(out, \"x\", sw * col * SLICE_WINDOW_GAP);\n                write_key_val(out, \"y\", sh * row * SLICE_WINDOW_GAP);\n                write_key_val(out, \"width\", sw);\n                write_key_val(out, \"height\", sh);\n                write_key_val(out, \"stroke\", \"black\");\n                write_key_val(out, \"fill\", \"none\");\n                out << \"/>\\n\";\n                k++;\n            }\n        }\n        out << \"</g>\\n\";\n    }\n\n    out << R\"SVG(</svg>)SVG\";\n}\n\nvoid DetectorSliceSet::write_svg_contents_to(\n    std::ostream &out,\n    const std::function<Coord<2>(uint32_t qubit)> &unscaled_coords,\n    const std::function<Coord<2>(uint64_t tick, uint32_t qubit)> &coords,\n    uint64_t end_tick,\n    size_t scale) const {\n    size_t clip_id = 0;\n\n    std::vector<Coord<2>> pts_workspace;\n\n    bool haveDrawnCorners = false;\n\n    using tup = std::tuple<uint64_t, stim::DemTarget, SpanRef<const GateTarget>, bool>;\n    std::vector<tup> sorted_terms;\n    for (const auto &e : slices) {\n        sorted_terms.push_back({e.first.first, e.first.second, e.second, false});\n    }\n    for (const auto &e : anticommutations) {\n        sorted_terms.push_back({e.first.first, e.first.second, e.second, true});\n    }\n    std::stable_sort(sorted_terms.begin(), sorted_terms.end(), [](const tup &e1, const tup &e2) -> int {\n        int a = (int)std::get<2>(e1).size();\n        int b = (int)std::get<2>(e2).size();\n        return a > b;\n    });\n\n    // Draw detector slices.\n    for (const auto &e : sorted_terms) {\n        uint64_t tick = std::get<0>(e);\n        DemTarget target = std::get<1>(e);\n        SpanRef<const GateTarget> terms = std::get<2>(e);\n        bool is_anticommutation = std::get<3>(e);\n        if (is_anticommutation) {\n            for (const auto &anti_target : terms) {\n                auto c = coords(tick, anti_target.qubit_value());\n                out << R\"SVG(<circle)SVG\";\n                write_key_val(out, \"cx\", c.xyz[0]);\n                write_key_val(out, \"cy\", c.xyz[1]);\n                write_key_val(out, \"r\", scale);\n                write_key_val(out, \"fill\", \"none\");\n                write_key_val(out, \"stroke\", \"magenta\");\n                write_key_val(out, \"stroke-width\", scale / 2);\n                out << \"/>\\n\";\n            }\n            continue;\n        }\n\n        if (target.is_observable_id()) {\n            _draw_observable(\n                out, target.val(), unscaled_coords, coords, tick, terms, pts_workspace, tick < end_tick - 1, scale);\n            continue;\n        }\n\n        const char *color = pick_color(terms);\n        bool drawCorners = false;\n        if (color == nullptr) {\n            drawCorners = true;\n            color = BG_GREY;\n        }\n\n        // Open the group element for this slice\n        out << \"<g id=\\\"slice:\" << target.val();\n        if (target.is_relative_detector_id()) {\n            add_coord_summary_to_ss(out, detector_coordinates.at(target.val()));\n        }\n        out << \":\" << tick << \"\\\">\\n\";\n\n        _start_slice_shape_command(out, coords, tick, terms, pts_workspace, scale);\n        write_key_val(out, \"stroke\", \"none\");\n        if (terms.size() > 2) {\n            write_key_val(out, \"fill-opacity\", 0.75);\n        }\n        write_key_val(out, \"fill\", color);\n        out << \"/>\\n\";\n\n        if (drawCorners) {\n            haveDrawnCorners = true;  // controls later writing out the universal gradients we'll reference here\n            out << R\"SVG(<clipPath id=\"clip)SVG\";\n            out << clip_id;\n            out << \"\\\">\";\n            _start_slice_shape_command(out, coords, tick, terms, pts_workspace, scale);\n            out << \"/></clipPath>\\n\";\n\n            size_t blur_radius = scale == 6 ? 20 : scale * 1.8f;\n            for (const auto &t : terms) {\n                auto c = coords(tick, t.qubit_value());\n                out << R\"SVG(<circle clip-path=\"url(#clip)SVG\";\n                out << clip_id;\n                out << \")\\\"\";\n                write_key_val(out, \"cx\", c.xyz[0]);\n                write_key_val(out, \"cy\", c.xyz[1]);\n                write_key_val(out, \"r\", blur_radius);\n                write_key_val(out, \"stroke\", \"none\");\n                if (t.is_x_target()) {\n                    write_key_val(out, \"fill\", \"url('#xgrad')\");\n                } else if (t.is_y_target()) {\n                    write_key_val(out, \"fill\", \"url('#ygrad')\");\n                } else {\n                    write_key_val(out, \"fill\", \"url('#zgrad')\");\n                }\n                out << \"/>\\n\";\n            }\n\n            clip_id++;\n        }\n\n        // Draw outline\n        _start_slice_shape_command(out, coords, tick, terms, pts_workspace, scale);\n        write_key_val(out, \"stroke\", \"black\");\n        write_key_val(out, \"fill\", \"none\");\n        out << \"/>\\n\";\n\n        // Close the group element for this slice\n        out << \"</g>\\n\";\n    }\n    if (haveDrawnCorners) {\n        // write out the universal radialGradients that all corners reference\n        out << \"<defs>\\n\";\n        static const char *const names[] = {\"xgrad\", \"ygrad\", \"zgrad\"};\n        static const char *const colors[] = {X_RED, Y_GREEN, Z_BLUE};\n        for (int i = 0; i < 3; ++i) {\n            out << \"<radialGradient\";\n            write_key_val(out, \"id\", names[i]);\n            out << \"><stop\";\n            write_key_val(out, \"offset\", \"50%\");\n            write_key_val(out, \"stop-color\", colors[i]);\n            write_key_val(out, \"stop-opacity\", \"1\");\n            out << \"/><stop\";\n            write_key_val(out, \"offset\", \"100%\");\n            write_key_val(out, \"stop-color\", \"#AAAAAA\");\n            write_key_val(out, \"stop-opacity\", \"0\");\n            out << \"/></radialGradient>\\n\";\n        }\n        out << \"</defs>\\n\";\n    }\n}\n"
  },
  {
    "path": "src/stim/diagram/detector_slice/detector_slice_set.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_DETECTOR_SLICE_DETECTOR_SLICE_SET_H\n#define _STIM_DIAGRAM_DETECTOR_SLICE_DETECTOR_SLICE_SET_H\n\n#include <functional>\n#include <iostream>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/diagram/coord.h\"\n\nnamespace stim_draw_internal {\n\nstruct CoordFilter {\n    std::vector<double> coordinates{};\n    bool use_target = false;\n    stim::DemTarget exact_target{};\n\n    bool matches(stim::SpanRef<const double> coords, stim::DemTarget target) const;\n    static CoordFilter parse_from(std::string_view data);\n};\n\nstruct DetectorSliceSet {\n    uint64_t num_qubits;\n    uint64_t min_tick;\n    uint64_t num_ticks;\n    /// Qubit ID -> qubit coordinates\n    std::map<uint64_t, std::vector<double>> coordinates;\n    /// DemTarget value -> detector coordinates\n    std::map<uint64_t, std::vector<double>> detector_coordinates;\n    /// (tick, DemTarget) -> terms in the slice\n    std::map<std::pair<uint64_t, stim::DemTarget>, std::vector<stim::GateTarget>> slices;\n    /// (tick, DemTarget) -> anticommutations in the slice\n    std::map<std::pair<uint64_t, stim::DemTarget>, std::vector<stim::GateTarget>> anticommutations;\n\n    /// Args:\n    ///     circuit: The circuit to make a detector slice diagram from.\n    ///     tick_index: The tick to target. tick_index=0 is the start of the\n    ///         circuit. tick_index=1 is the first TICK instruction, and so\n    ///         forth.\n    ///     coord_filter: Detectors that fail to match these coordinates\n    ///         are excluded.\n    static DetectorSliceSet from_circuit_ticks(\n        const stim::Circuit &circuit,\n        uint64_t start_tick,\n        uint64_t num_ticks,\n        stim::SpanRef<const CoordFilter> coord_filter);\n\n    std::set<uint64_t> used_qubits() const;\n    std::string str() const;\n\n    void write_text_diagram_to(std::ostream &out) const;\n    void write_svg_diagram_to(std::ostream &out, size_t num_rows = 0) const;\n    void write_svg_contents_to(\n        std::ostream &out,\n        const std::function<Coord<2>(uint32_t qubit)> &unscaled_coords,\n        const std::function<Coord<2>(uint64_t tick, uint32_t qubit)> &coords,\n        uint64_t end_tick,\n        size_t scale) const;\n};\n\ndouble inv_space_fill_transform(Coord<2> a);\n\nstruct FlattenedCoords {\n    std::vector<Coord<2>> unscaled_qubit_coords;\n    std::vector<Coord<2>> qubit_coords;\n    std::map<uint64_t, Coord<2>> det_coords;\n    Coord<2> size;\n    float unit_distance;\n\n    static FlattenedCoords from(const DetectorSliceSet &set, float desired_unit_distance);\n};\nCoord<2> pick_polygon_center(stim::SpanRef<const Coord<2>> coords);\nbool is_colinear(Coord<2> a, Coord<2> b, Coord<2> c, float atol);\n\nstd::ostream &operator<<(std::ostream &out, const DetectorSliceSet &slice);\nstd::ostream &operator<<(std::ostream &out, const CoordFilter &filter);\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/detector_slice/detector_slice_set.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/diagram/detector_slice/detector_slice_set.h\"\n\n#include <fstream>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/diagram/timeline/timeline_svg_drawer.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nTEST(detector_slice_set, from_circuit) {\n    CoordFilter empty_filter;\n    auto slice_set = DetectorSliceSet::from_circuit_ticks(\n        stim::Circuit(R\"CIRCUIT(\n        QUBIT_COORDS(3, 5) 1\n        R 0\n        M 0\n        DETECTOR rec[-1]\n        TICK\n        CX 2 1\n\n        TICK  # Here\n        H 0\n        CX 1 0\n        M 0\n        DETECTOR rec[-1]\n        M 1\n        DETECTOR rec[-1]\n\n        REPEAT 100 {\n            TICK\n            R 0\n            M 0\n            DETECTOR rec[-1]\n        }\n)CIRCUIT\"),\n        2,\n        1,\n        {&empty_filter});\n    ASSERT_EQ(slice_set.coordinates, (std::map<uint64_t, std::vector<double>>{{0, {}}, {1, {3, 5}}, {2, {}}}));\n    ASSERT_EQ(\n        slice_set.slices,\n        (std::map<std::pair<uint64_t, stim::DemTarget>, std::vector<stim::GateTarget>>{\n            {{2, DemTarget::relative_detector_id(1)}, {GateTarget::x(0), GateTarget::z(1)}},\n            {{2, DemTarget::relative_detector_id(2)}, {GateTarget::z(1)}},\n        }));\n}\n\nTEST(detector_slice_set, big_loop_seeking) {\n    stim::Circuit circuit(R\"CIRCUIT(\n        REPEAT 100000 {\n            REPEAT 10000 {\n                REPEAT 1000 {\n                    REPEAT 100 {\n                        REPEAT 10 {\n                            RY 0\n                            TICK\n                            MY 0\n                            DETECTOR rec[-1]\n                        }\n                    }\n                }\n                RX 1\n                TICK\n                MX 1\n                OBSERVABLE_INCLUDE(5) rec[-1]\n                DETECTOR rec[-1]\n            }\n        }\n    )CIRCUIT\");\n\n    uint64_t inner = 10 * 100 * 1000 + 1;\n    CoordFilter empty_filter;\n    CoordFilter obs5_filter;\n    obs5_filter.use_target = true;\n    obs5_filter.exact_target = DemTarget::observable_id(5);\n    auto slice_set = DetectorSliceSet::from_circuit_ticks(circuit, inner * 10000ULL * 50ULL + 2ULL, 1, {&empty_filter});\n    ASSERT_EQ(slice_set.coordinates, (std::map<uint64_t, std::vector<double>>{{0, {}}, {1, {}}}));\n    ASSERT_EQ(\n        slice_set.slices,\n        (std::map<std::pair<uint64_t, stim::DemTarget>, std::vector<stim::GateTarget>>{\n            {{inner * 10000ULL * 50ULL + 2ULL, DemTarget::relative_detector_id(inner * 10000ULL * 50ULL + 1ULL)},\n             {GateTarget::y(0)}},\n        }));\n\n    slice_set = DetectorSliceSet::from_circuit_ticks(\n        circuit,\n        inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL + 1ULL,\n        1,\n        std::vector<CoordFilter>{empty_filter, obs5_filter});\n    ASSERT_EQ(slice_set.coordinates, (std::map<uint64_t, std::vector<double>>{{0, {}}, {1, {}}}));\n    ASSERT_EQ(\n        slice_set.slices,\n        (std::map<std::pair<uint64_t, stim::DemTarget>, std::vector<stim::GateTarget>>{\n            {{inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL + 1ULL,\n              DemTarget::relative_detector_id(inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL)},\n             {GateTarget::x(1)}},\n            {{inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL + 1ULL, DemTarget::observable_id(5)},\n             {GateTarget::x(1)}},\n        }));\n\n    slice_set = DetectorSliceSet::from_circuit_ticks(\n        circuit,\n        inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL + 1ULL,\n        2,\n        std::vector<CoordFilter>{empty_filter, obs5_filter});\n    ASSERT_EQ(slice_set.coordinates, (std::map<uint64_t, std::vector<double>>{{0, {}}, {1, {}}}));\n    ASSERT_EQ(\n        slice_set.slices,\n        (std::map<std::pair<uint64_t, stim::DemTarget>, std::vector<stim::GateTarget>>{\n            {{inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL + 1ULL,\n              DemTarget::relative_detector_id(inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL)},\n             {GateTarget::x(1)}},\n            {{inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL + 1ULL, DemTarget::observable_id(5)},\n             {GateTarget::x(1)}},\n            {{inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL + 2ULL,\n              DemTarget::relative_detector_id(inner * 10000ULL * 25ULL + 1000ULL * 100ULL * 10ULL + 1ULL)},\n             {GateTarget::y(0)}},\n        }));\n}\n\nTEST(detector_slice_set_text_diagram, repetition_code) {\n    CoordFilter empty_filter;\n    CoordFilter obs_filter;\n    obs_filter.use_target = true;\n    obs_filter.exact_target = DemTarget::observable_id(0);\n    CircuitGenParameters params(10, 5, \"memory\");\n    auto circuit = generate_rep_code_circuit(params).circuit;\n    auto slice_set =\n        DetectorSliceSet::from_circuit_ticks(circuit, 9, 1, std::vector<CoordFilter>{empty_filter, obs_filter});\n    ASSERT_EQ(slice_set.slices.size(), circuit.count_qubits());\n    ASSERT_EQ(\"\\n\" + slice_set.str() + \"\\n\", R\"DIAGRAM(\nq0: --------Z:D12----------------------------\n            |\nq1: -Z:D8---Z:D12----------------------------\n            |\nq2: --------Z:D12--Z:D13---------------------\n                   |\nq3: -Z:D9----------Z:D13---------------------\n                   |\nq4: ---------------Z:D13--Z:D14--------------\n                          |\nq5: -Z:D10----------------Z:D14--------------\n                          |\nq6: ----------------------Z:D14--Z:D15-------\n                                 |\nq7: -Z:D11-----------------------Z:D15-------\n                                 |\nq8: -----------------------------Z:D15--Z:L0-\n)DIAGRAM\");\n\n    ASSERT_EQ(\n        \"\\n\" +\n            DetectorSliceSet::from_circuit_ticks(circuit, 11, 1, std::vector<CoordFilter>{empty_filter, obs_filter})\n                .str() +\n            \"\\n\",\n        R\"DIAGRAM(\nq0: --------Z:D16-\n            |\nq1: -Z:D12--Z:D16-\n     |\nq2: -Z:D12--Z:D17-\n            |\nq3: -Z:D13--Z:D17-\n     |\nq4: -Z:D13--Z:D18-\n            |\nq5: -Z:D14--Z:D18-\n     |\nq6: -Z:D14--Z:D19-\n            |\nq7: -Z:D15--Z:D19-\n     |\nq8: -Z:D15--Z:L0--\n)DIAGRAM\");\n}\n\nTEST(detector_slice_set_text_diagram, surface_code) {\n    CoordFilter empty_filter;\n    CoordFilter obs_filter;\n    obs_filter.use_target = true;\n    obs_filter.exact_target = DemTarget::observable_id(0);\n    CircuitGenParameters params(10, 2, \"unrotated_memory_z\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto slice_set =\n        DetectorSliceSet::from_circuit_ticks(circuit, 11, 1, std::vector<CoordFilter>{empty_filter, obs_filter});\n    ASSERT_EQ(slice_set.slices.size(), circuit.count_qubits());\n    ASSERT_EQ(\"\\n\" + slice_set.str() + \"\\n\", R\"DIAGRAM(\nq0:(0, 0) -X:D2--Z:D3--------------------------------Z:L0-\n           |     |                                   |\nq1:(1, 0) -X:D2--|-----------------X:D6--Z:D7--------Z:L0-\n           |     |                 |     |           |\nq2:(2, 0) -|-----|-----Z:D4--------X:D6--|-----------Z:L0-\n           |     |     |           |     |\nq3:(0, 1) -X:D2--Z:D3--|-----------|-----Z:D7-------------\n                       |           |     |\nq4:(1, 1) -------------Z:D4--X:D5--X:D6--Z:D7-------------\n                       |     |           |\nq5:(2, 1) -------------Z:D4--|-----------|-----Z:D8--X:D9-\n                       |     |           |     |     |\nq6:(0, 2) -------------|-----X:D5--------Z:D7--|-----|----\n                       |     |                 |     |\nq7:(1, 2) -------------Z:D4--X:D5--------------|-----X:D9-\n                                               |     |\nq8:(2, 2) -------------------------------------Z:D8--X:D9-\n)DIAGRAM\");\n}\n\nTEST(detector_slice_set_svg_diagram, surface_code) {\n    CoordFilter empty_filter;\n    CircuitGenParameters params(10, 2, \"rotated_memory_z\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto slice_set = DetectorSliceSet::from_circuit_ticks(circuit, 8, 1, {&empty_filter});\n    std::stringstream ss;\n    slice_set.write_svg_diagram_to(ss);\n    expect_string_is_identical_to_saved_file(ss.str(), \"rotated_memory_z_detector_slice.svg\");\n}\n\nTEST(detector_slice_set_svg_diagram, long_range_detector) {\n    Circuit circuit(R\"CIRCUIT(\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 1) 1\n        QUBIT_COORDS(2, 2) 2\n        QUBIT_COORDS(3, 3) 3\n        QUBIT_COORDS(4, 4) 4\n        QUBIT_COORDS(5, 5) 5\n        QUBIT_COORDS(6, 6) 6\n        QUBIT_COORDS(7, 7) 7\n        QUBIT_COORDS(8, 8) 8\n        QUBIT_COORDS(9, 9) 9\n        H 0 1 2 3 4 5 6 7 8 9\n        TICK\n        MX 0 9\n        DETECTOR(0) rec[-1] rec[-2]\n    )CIRCUIT\");\n    CoordFilter empty_filter;\n    auto slice_set = DetectorSliceSet::from_circuit_ticks(circuit, 1, 1, {&empty_filter});\n    std::stringstream ss;\n    slice_set.write_svg_diagram_to(ss);\n    expect_string_is_identical_to_saved_file(ss.str(), \"long_range_detector.svg\");\n}\n\nTEST(detector_slice_set, pick_polygon_center) {\n    std::vector<Coord<2>> coords;\n    coords.push_back({2, 1});\n    coords.push_back({4.5, 3.5});\n    coords.push_back({6, 0});\n    coords.push_back({1, 5});\n    ASSERT_EQ(pick_polygon_center(coords), (Coord<2>{3.25, 2.25}));\n\n    coords.pop_back();\n    coords.push_back({1, 6});\n    ASSERT_EQ(pick_polygon_center(coords), (Coord<2>{(2 + 4.5 + 6 + 1) / 4, (1 + 3.5 + 0 + 6) / 4}));\n\n    coords.push_back({7, 0});\n    coords.push_back({1, 5});\n    ASSERT_EQ(pick_polygon_center(coords), (Coord<2>{3.25, 2.25}));\n}\n\nTEST(detector_slice_set_svg_diagram, is_colinear) {\n    ASSERT_TRUE(is_colinear({0, 0}, {0, 0}, {1, 2}, 1e-4f));\n    ASSERT_TRUE(is_colinear({3, 6}, {1, 2}, {2, 4}, 1e-4f));\n\n    ASSERT_FALSE(is_colinear({3, 7}, {1, 2}, {2, 4}, 1e-4f));\n    ASSERT_FALSE(is_colinear({4, 6}, {1, 2}, {2, 4}, 1e-4f));\n    ASSERT_FALSE(is_colinear({3, 6}, {1, 3}, {2, 4}, 1e-4f));\n    ASSERT_FALSE(is_colinear({3, 6}, {2, 2}, {2, 4}, 1e-4f));\n    ASSERT_FALSE(is_colinear({3, 6}, {1, 2}, {1, 4}, 1e-4f));\n    ASSERT_FALSE(is_colinear({3, 6}, {1, 2}, {2, -4}, 1e-4f));\n\n    ASSERT_FALSE(is_colinear({0, 1e-3f}, {0, 0}, {1, 2}, 1e-4f));\n    ASSERT_TRUE(is_colinear({0, 1e-3f}, {0, 0}, {1, 2}, 1e-2f));\n}\n\nTEST(detector_slice_set_svg_diagram, colinear_polygon) {\n    Circuit circuit(R\"CIRCUIT(\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 1) 1\n        QUBIT_COORDS(2, 2) 2\n        QUBIT_COORDS(0, 3) 3\n        QUBIT_COORDS(4, 0) 4\n        QUBIT_COORDS(5, 1) 5\n        QUBIT_COORDS(6, 2) 6\n        R 0 1 2 3 4 5 6\n        H 3\n        TICK\n        H 3\n        M 0 1 2 3 4 5 6\n        DETECTOR rec[-1] rec[-2] rec[-3]\n        DETECTOR rec[-4] rec[-5] rec[-6] rec[-7]\n    )CIRCUIT\");\n    CoordFilter empty_filter;\n    auto slice_set = DetectorSliceSet::from_circuit_ticks(circuit, 1, 1, {&empty_filter});\n    std::stringstream ss;\n    slice_set.write_svg_diagram_to(ss);\n    expect_string_is_identical_to_saved_file(ss.str(), \"colinear_detector_slice.svg\");\n}\n\nTEST(detector_slice_set_svg_diagram, observable) {\n    Circuit circuit(R\"CIRCUIT(\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(2, 0) 1\n        QUBIT_COORDS(1, 1) 2\n        REPEAT 3 {\n            C_XYZ 0 1\n            TICK\n            CX 0 2\n            TICK\n            CX 1 2\n            TICK\n            M 2\n            TICK\n            R 2\n        }\n        DETECTOR rec[-1] rec[-2] rec[-3]\n        M 0 1\n        OBSERVABLE_INCLUDE(0) rec[-1] rec[-2]\n    )CIRCUIT\");\n    CoordFilter obs_filter;\n    obs_filter.use_target = true;\n    obs_filter.exact_target = DemTarget::observable_id(0);\n    std::stringstream ss;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit,\n        ss,\n        0,\n        circuit.count_ticks() + 1,\n        DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE,\n        {&obs_filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"observable_slices.svg\");\n}\n\nTEST(detector_slice_set_svg_diagram, svg_ids) {\n    Circuit circuit(R\"CIRCUIT(\n        QUBIT_COORDS 0\n        QUBIT_COORDS(1) 1\n        QUBIT_COORDS(2, 2) 2\n        QUBIT_COORDS(3, 3, 3) 3\n        R 0 1 2 3\n        TICK\n        M 0 1 2 3\n        DETECTOR rec[-1]\n        DETECTOR(1) rec[-1] rec[-2]\n        DETECTOR(2, 2) rec[-1] rec[-2] rec[-3]\n        DETECTOR(3, 3, 3) rec[-1] rec[-2] rec[-3] rec[-4]\n    )CIRCUIT\");\n    CoordFilter empty_filter;\n    auto slice_set = DetectorSliceSet::from_circuit_ticks(circuit, 1, 1, {&empty_filter});\n    std::stringstream ss;\n    slice_set.write_svg_diagram_to(ss);\n    expect_string_is_identical_to_saved_file(ss.str(), \"svg_ids.svg\");\n}\n\nTEST(coord_filter, parse_from) {\n    auto c = CoordFilter::parse_from(\"\");\n    ASSERT_TRUE(c.coordinates.empty());\n    ASSERT_FALSE(c.use_target);\n\n    c = CoordFilter::parse_from(\"D5\");\n    ASSERT_TRUE(c.coordinates.empty());\n    ASSERT_TRUE(c.use_target);\n    ASSERT_EQ(c.exact_target, DemTarget::relative_detector_id(5));\n\n    c = CoordFilter::parse_from(\"L7\");\n    ASSERT_TRUE(c.coordinates.empty());\n    ASSERT_TRUE(c.use_target);\n    ASSERT_EQ(c.exact_target, DemTarget::observable_id(7));\n\n    c = CoordFilter::parse_from(\"2,3,*,5\");\n    ASSERT_TRUE(c.coordinates.size() == 4);\n    ASSERT_TRUE(c.coordinates[0] == 2);\n    ASSERT_TRUE(c.coordinates[1] == 3);\n    ASSERT_TRUE(std::isnan(c.coordinates[2]));\n    ASSERT_TRUE(c.coordinates[3] == 5);\n    ASSERT_FALSE(c.use_target);\n}\n\nTEST(inv_space_fill_transform, inv_space_fill_transform) {\n    ASSERT_EQ(inv_space_fill_transform({0, 0}), 0);\n    ASSERT_EQ(inv_space_fill_transform({4, 55.5}), 339946);\n}\n\nTEST(detector_slice_set, from_circuit_with_errors) {\n    CoordFilter empty_filter;\n    auto slice_set = DetectorSliceSet::from_circuit_ticks(\n        stim::Circuit(R\"CIRCUIT(\n            TICK\n            R 0\n            TICK\n            R 0\n            TICK\n            MXX 0 1\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        0,\n        5,\n        {&empty_filter});\n    ASSERT_EQ(\n        slice_set.anticommutations,\n        (std::map<std::pair<uint64_t, stim::DemTarget>, std::vector<stim::GateTarget>>{\n            {{3, DemTarget::relative_detector_id(0)}, {GateTarget::x(0)}},\n        }));\n    ASSERT_EQ(\n        slice_set.slices,\n        (std::map<std::pair<uint64_t, stim::DemTarget>, std::vector<stim::GateTarget>>{\n            {{3, DemTarget::relative_detector_id(0)}, {GateTarget::x(0), GateTarget::x(1)}},\n        }));\n}\n\nTEST(circuit_diagram_timeline_text, anticommuting_detector_circuit) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        TICK\n        R 0\n        TICK\n        R 0\n        TICK\n        MXX 0 1\n        M 2\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n    )CIRCUIT\");\n    CoordFilter empty_filter;\n    std::stringstream ss;\n    ss << DetectorSliceSet::from_circuit_ticks(circuit, 0, 10, &empty_filter);\n    ASSERT_EQ(\"\\n\" + ss.str() + \"\\n\", R\"DIAGRAM(\nq0: -------ANTICOMMUTED:D1--X:D1-\n                            |\nq1: ------------------------X:D1-\n\nq2: -Z:D0--Z:D0-------------Z:D0-\n)DIAGRAM\");\n}\n"
  },
  {
    "path": "src/stim/diagram/diagram_util.cc",
    "content": "#include \"stim/diagram/diagram_util.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nstd::pair<std::string_view, std::string_view> stim_draw_internal::two_qubit_gate_pieces(GateType gate_type) {\n    if (gate_type == GateType::CX) {\n        return {\"Z\", \"X\"};\n    } else if (gate_type == GateType::CY) {\n        return {\"Z\", \"Y\"};\n    } else if (gate_type == GateType::CZ) {\n        return {\"Z\", \"Z\"};\n    } else if (gate_type == GateType::XCX) {\n        return {\"X\", \"X\"};\n    } else if (gate_type == GateType::XCY) {\n        return {\"X\", \"Y\"};\n    } else if (gate_type == GateType::XCZ) {\n        return {\"X\", \"Z\"};\n    } else if (gate_type == GateType::YCX) {\n        return {\"Y\", \"X\"};\n    } else if (gate_type == GateType::YCY) {\n        return {\"Y\", \"Y\"};\n    } else if (gate_type == GateType::YCZ) {\n        return {\"Y\", \"Z\"};\n    } else if (gate_type == GateType::CXSWAP) {\n        return {\"ZSWAP\", \"XSWAP\"};\n    } else if (gate_type == GateType::CZSWAP) {\n        return {\"ZSWAP\", \"ZSWAP\"};\n    } else if (gate_type == GateType::SWAPCX) {\n        return {\"XSWAP\", \"ZSWAP\"};\n    } else {\n        auto name = GATE_DATA[gate_type].name;\n        return {name, name};\n    }\n}\n\nsize_t stim_draw_internal::utf8_char_count(std::string_view s) {\n    size_t t = 0;\n    for (uint8_t c : s) {\n        // Continuation bytes start with \"10\" in binary.\n        if ((c & 0xC0) != 0x80) {\n            t++;\n        }\n    }\n    return t;\n}\n\nvoid stim_draw_internal::add_coord_summary_to_ss(std::ostream &ss, std::vector<double> vec) {\n    bool first = true;\n    for (const auto &c : vec) {\n        if (first) {\n            ss << \":\";\n        } else {\n            ss << \"_\";\n        }\n        ss << c;\n        first = false;\n    }\n}"
  },
  {
    "path": "src/stim/diagram/diagram_util.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_DIAGRAM_UTIL_H\n#define _STIM_DIAGRAM_DIAGRAM_UTIL_H\n\n#include <iostream>\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim_draw_internal {\n\nconstexpr const char *X_RED = \"#FF4040\";\nconstexpr const char *Y_GREEN = \"#59FF7A\";\nconstexpr const char *Z_BLUE = \"#4DA6FF\";\nconstexpr const char *EX_PURPLE = \"#FF4DDB\";\nconstexpr const char *EY_YELLOW = \"#F1FF59\";\nconstexpr const char *EZ_ORANGE = \"#FF9500\";\nconstexpr const char *BG_GREY = \"#AAAAAA\";\n\nsize_t utf8_char_count(std::string_view s);\n\n/// Splits a two qubit gate into two end pieces, which can be drawn independently.\nstd::pair<std::string_view, std::string_view> two_qubit_gate_pieces(stim::GateType gate_type);\n\n/// Adds each element of a vector to the string stream starting with ':', separated by '_'\n/// adds nothing if the vector is empty\nvoid add_coord_summary_to_ss(std::ostream &ss, std::vector<double> vec);\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/gate_data_3d.cc",
    "content": "#include \"stim/diagram/gate_data_3d.h\"\n\n#include \"stim/diagram/gate_data_3d_texture_data.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nconstexpr float CONTROL_RADIUS = 0.4f;\n\nstd::shared_ptr<GltfBuffer<2>> texture_coords_for_showing_on_spacelike_faces_of_cube(\n    std::string_view name, size_t tex_tile_x, size_t tex_tile_y, bool actually_just_square) {\n    constexpr size_t diam = 16;\n    float d = (float)1.0 / diam;\n    float dx = d * tex_tile_x;\n    float dy = d * tex_tile_y;\n    Coord<2> v00{dx + 0, dy + 0};\n    Coord<2> v01{dx + 0, dy + d};\n    Coord<2> v10{dx + d, dy + 0};\n    Coord<2> v11{dx + d, dy + d};\n    if (actually_just_square) {\n        return std::shared_ptr<GltfBuffer<2>>(new GltfBuffer<2>(\n            {{std::string(name)},\n             {\n                 v10,\n                 v00,\n                 v11,\n                 v00,\n                 v01,\n                 v11,\n                 v11,\n                 v10,\n                 v01,\n                 v01,\n                 v10,\n                 v00,\n             }}));\n    }\n\n    return std::shared_ptr<GltfBuffer<2>>(new GltfBuffer<2>(\n        {{std::string(name)},\n         {\n             v00, v01, v10, v01, v11, v10, v00, v00, v00, v00, v00, v00, v10, v00, v11, v00, v01, v11,\n             v01, v11, v00, v00, v11, v10, v00, v00, v00, v00, v00, v00, v11, v10, v01, v01, v10, v00,\n         }}));\n}\n\nstd::shared_ptr<GltfPrimitive> cube_gate(\n    std::string_view gate_canonical_name,\n    size_t tex_tile_x,\n    size_t tex_tile_y,\n    std::shared_ptr<GltfBuffer<3>> cube_position_buffer,\n    std::shared_ptr<GltfMaterial> material,\n    bool actually_just_square) {\n    return std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n        {\"primitive_gate_\" + std::string(gate_canonical_name)},\n        GL_TRIANGLES,\n        cube_position_buffer,\n        texture_coords_for_showing_on_spacelike_faces_of_cube(\n            \"tex_coords_gate_\" + std::string(gate_canonical_name), tex_tile_x, tex_tile_y, actually_just_square),\n        material,\n    });\n}\n\nstd::shared_ptr<GltfBuffer<3>> make_cube_triangle_list(bool actually_just_square) {\n    Coord<3> v000{-0.5f, +0.5f, +0.5f};\n    Coord<3> v001{-0.5f, +0.5f, -0.5f};\n    Coord<3> v010{-0.5f, -0.5f, +0.5f};\n    Coord<3> v011{-0.5f, -0.5f, -0.5f};\n    Coord<3> v100{+0.5f, +0.5f, +0.5f};\n    Coord<3> v101{+0.5f, +0.5f, -0.5f};\n    Coord<3> v110{+0.5f, -0.5f, +0.5f};\n    Coord<3> v111{+0.5f, -0.5f, -0.5f};\n    if (actually_just_square) {\n        v000.xyz[0] = 0;\n        v001.xyz[0] = 0;\n        v010.xyz[0] = 0;\n        v011.xyz[0] = 0;\n        return std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n            {\"cube\"},\n            {\n                v000,\n                v001,\n                v010,\n                v001,\n                v011,\n                v010,\n\n                v011,\n                v001,\n                v010,\n                v010,\n                v001,\n                v000,\n            }});\n    }\n    return std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n        {\"cube\"},\n        {\n            v000, v010, v100, v010, v110, v100,\n\n            v000, v100, v001, v001, v100, v101,\n\n            v000, v001, v010, v001, v011, v010,\n\n            v111, v011, v101, v101, v011, v001,\n\n            v111, v110, v011, v110, v010, v011,\n\n            v111, v101, v110, v110, v101, v100,\n        }});\n}\n\nstd::shared_ptr<GltfBuffer<3>> make_circle_loop(size_t n, float r, bool repeat_boundary) {\n    std::vector<Coord<3>> vertices;\n    vertices.push_back({0, r, 0});\n    for (size_t k = 1; k < n; k++) {\n        float t = k * 3.14159265359f * 2 / n;\n        vertices.push_back({0, cosf(t) * r, sinf(t) * r});\n    }\n    if (repeat_boundary) {\n        vertices.push_back({0, r, 0});\n    }\n    return std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n        {\"circle_loop\"},\n        std::move(vertices),\n    });\n}\n\nstd::pair<std::string_view, std::shared_ptr<GltfMesh>> make_x_control_mesh() {\n    auto line_cross = std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n        {\"control_x_line_cross\"},\n        {{0, -CONTROL_RADIUS, 0}, {0, +CONTROL_RADIUS, 0}, {0, 0, -CONTROL_RADIUS}, {0, 0, +CONTROL_RADIUS}},\n    });\n    auto circle = make_circle_loop(16, CONTROL_RADIUS, true);\n    auto black_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"black\"},\n        {0, 0, 0, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n    auto white_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"white\"},\n        {1, 1, 1, 1},\n        0.4,\n        0.5,\n        true,\n        nullptr,\n    });\n    auto mesh = std::shared_ptr<GltfMesh>(new GltfMesh{\n        {\"mesh_X_CONTROL\"},\n        {\n            std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                {\"primitive_circle_interior\"},\n                GL_TRIANGLE_FAN,\n                circle,\n                nullptr,\n                white_material,\n            }),\n            std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                {\"primitive_circle_perimeter\"},\n                GL_LINE_STRIP,\n                circle,\n                nullptr,\n                black_material,\n            }),\n            std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                {\"primitive_line_cross\"},\n                GL_LINES,\n                line_cross,\n                nullptr,\n                black_material,\n            }),\n        },\n    });\n    return {\"X_CONTROL\", mesh};\n}\n\nstd::pair<std::string_view, std::shared_ptr<GltfMesh>> make_xswap_control_mesh() {\n    float h = CONTROL_RADIUS * sqrtf(2) * 0.8f;\n    auto line_cross = std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n        {\"control_xswap_line_cross\"},\n        {{0, -h, -h}, {0, +h, +h}, {0, -h, +h}, {0, +h, -h}},\n    });\n    auto circle = make_circle_loop(16, CONTROL_RADIUS, true);\n    auto black_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"black\"},\n        {0, 0, 0, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n    auto white_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"white\"},\n        {1, 1, 1, 1},\n        0.4,\n        0.5,\n        true,\n        nullptr,\n    });\n    auto mesh = std::shared_ptr<GltfMesh>(new GltfMesh{\n        {\"mesh_XSWAP_CONTROL\"},\n        {\n            std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                {\"primitive_circle_interior\"},\n                GL_TRIANGLE_FAN,\n                circle,\n                nullptr,\n                white_material,\n            }),\n            std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                {\"primitive_circle_perimeter\"},\n                GL_LINE_STRIP,\n                circle,\n                nullptr,\n                black_material,\n            }),\n            std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                {\"primitive_line_cross\"},\n                GL_LINES,\n                line_cross,\n                nullptr,\n                black_material,\n            }),\n        },\n    });\n    return {\"XSWAP\", mesh};\n}\n\nstd::pair<std::string_view, std::shared_ptr<GltfMesh>> make_zswap_control_mesh() {\n    float h = CONTROL_RADIUS * sqrtf(2) * 0.8f;\n    auto line_cross = std::shared_ptr<GltfBuffer<3>>(new GltfBuffer<3>{\n        {\"control_zswap_line_cross\"},\n        {{0, -h, -h}, {0, +h, +h}, {0, -h, +h}, {0, +h, -h}},\n    });\n    auto circle = make_circle_loop(16, CONTROL_RADIUS, true);\n    auto black_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"black\"},\n        {0, 0, 0, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n    auto white_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"white\"},\n        {1, 1, 1, 1},\n        0.4,\n        0.5,\n        true,\n        nullptr,\n    });\n    auto mesh = std::shared_ptr<GltfMesh>(new GltfMesh{\n        {\"mesh_XSWAP_CONTROL\"},\n        {\n            std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                {\"primitive_circle_interior\"},\n                GL_TRIANGLE_FAN,\n                circle,\n                nullptr,\n                black_material,\n            }),\n            std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n                {\"primitive_line_cross\"},\n                GL_LINES,\n                line_cross,\n                nullptr,\n                white_material,\n            }),\n        },\n    });\n    return {\"ZSWAP\", mesh};\n}\n\nstd::pair<std::string_view, std::shared_ptr<GltfMesh>> make_y_control_mesh() {\n    auto gray_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"gray\"},\n        {0.5, 0.5, 0.5, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n    auto black_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"black\"},\n        {0, 0, 0, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n    auto tri_buf = make_circle_loop(3, CONTROL_RADIUS, false);\n    auto triangle_perimeter = std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n        {\"primitive_triangle_perimeter\"},\n        GL_LINE_LOOP,\n        tri_buf,\n        nullptr,\n        black_material,\n    });\n    auto triangle_interior = std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n        {\"primitive_triangle_interior\"},\n        GL_TRIANGLES,\n        tri_buf,\n        nullptr,\n        gray_material,\n    });\n    auto mesh = std::shared_ptr<GltfMesh>(new GltfMesh{\n        {\"mesh_control_Y\"},\n        {\n            triangle_perimeter,\n            triangle_interior,\n        },\n    });\n    return {\"Y_CONTROL\", mesh};\n}\n\nstd::pair<std::string_view, std::shared_ptr<GltfMesh>> make_z_control_mesh() {\n    auto circle = make_circle_loop(16, CONTROL_RADIUS, true);\n    auto black_material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"black\"},\n        {0, 0, 0, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n    auto disc_interior = std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n        {\"primitive_circle_interior\"},\n        GL_TRIANGLE_FAN,\n        circle,\n        nullptr,\n        black_material,\n    });\n    auto mesh = std::shared_ptr<GltfMesh>(new GltfMesh{\n        {\"mesh_Z_CONTROL\"},\n        {\n            disc_interior,\n        },\n    });\n    return {\"Z_CONTROL\", mesh};\n}\n\nstd::pair<std::string_view, std::shared_ptr<GltfMesh>> make_detector_mesh(bool excited) {\n    auto circle = make_circle_loop(8, CONTROL_RADIUS, true);\n    auto circle2 = make_circle_loop(8, CONTROL_RADIUS, true);\n    auto circle3 = make_circle_loop(8, CONTROL_RADIUS, true);\n    for (auto &e : circle2->vertices) {\n        std::swap(e.xyz[1], e.xyz[2]);\n        std::swap(e.xyz[0], e.xyz[1]);\n    }\n    for (auto &e : circle3->vertices) {\n        std::swap(e.xyz[0], e.xyz[1]);\n        std::swap(e.xyz[1], e.xyz[2]);\n    }\n    auto material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {excited ? \"det_red\" : \"det_black\"},\n        {excited ? 1.0f : 0.0f, excited ? 0.5f : 0.0f, excited ? 0.5f : 0.0f, 1},\n        1,\n        1,\n        true,\n        nullptr,\n    });\n    auto disc_interior = std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n        {excited ? \"excited_detector_primitive_circle_interior\" : \"detector_primitive_circle_interior\"},\n        GL_TRIANGLE_FAN,\n        circle,\n        nullptr,\n        material,\n    });\n    auto disc_interior2 = std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n        {excited ? \"excited_detector_primitive_circle_interior_2\" : \"detector_primitive_circle_interior_2\"},\n        GL_TRIANGLE_FAN,\n        circle2,\n        nullptr,\n        material,\n    });\n    auto disc_interior3 = std::shared_ptr<GltfPrimitive>(new GltfPrimitive{\n        {excited ? \"excited_detector_primitive_circle_interior_3\" : \"detector_primitive_circle_interior_3\"},\n        GL_TRIANGLE_FAN,\n        circle3,\n        nullptr,\n        material,\n    });\n    auto mesh = std::shared_ptr<GltfMesh>(new GltfMesh{\n        {excited ? \"mesh_EXCITED_DETECTOR\" : \"mesh_DETECTOR\"},\n        {\n            disc_interior,\n            disc_interior2,\n            disc_interior3,\n        },\n    });\n    return {excited ? \"EXCITED_DETECTOR\" : \"DETECTOR\", mesh};\n}\n\nstd::map<std::string_view, std::shared_ptr<GltfMesh>> stim_draw_internal::make_gate_primitives() {\n    bool actually_square = true;\n    auto cube = make_cube_triangle_list(actually_square);\n    auto image = std::shared_ptr<GltfImage>(new GltfImage{\n        {\"gates_image\"},\n        make_gate_3d_texture_data_uri(),\n    });\n    auto sampler = std::shared_ptr<GltfSampler>(new GltfSampler{\n        {\"gates_sampler\"},\n        GL_NEAREST,\n        GL_NEAREST,\n        GL_CLAMP_TO_EDGE,\n        GL_CLAMP_TO_EDGE,\n    });\n    auto texture = std::shared_ptr<GltfTexture>(new GltfTexture{\n        {\"gates_texture\"},\n        sampler,\n        image,\n    });\n    auto material = std::shared_ptr<GltfMaterial>(new GltfMaterial{\n        {\"gates_material\"},\n        {1, 1, 1, 1},\n        0.4,\n        0.5,\n        false,\n        texture,\n    });\n\n    auto f = [&](std::string_view s, size_t x, size_t y) -> std::pair<std::string_view, std::shared_ptr<GltfMesh>> {\n        return {s, GltfMesh::from_singleton_primitive(cube_gate(s, x, y, cube, material, actually_square))};\n    };\n\n    return std::map<std::string_view, std::shared_ptr<GltfMesh>>{\n        f(\"X\", 0, 6),\n        f(\"Y\", 0, 7),\n        f(\"Z\", 0, 8),\n\n        f(\"H_YZ\", 1, 6),\n        f(\"H\", 1, 7),\n        f(\"H_XY\", 1, 8),\n\n        f(\"SQRT_X\", 2, 6),\n        f(\"SQRT_Y\", 2, 7),\n        f(\"S\", 2, 8),\n\n        f(\"SQRT_X_DAG\", 3, 6),\n        f(\"SQRT_Y_DAG\", 3, 7),\n        f(\"S_DAG\", 3, 8),\n\n        f(\"MX\", 4, 6),\n        f(\"MY\", 4, 7),\n        f(\"M\", 4, 8),\n\n        f(\"RX\", 5, 6),\n        f(\"RY\", 5, 7),\n        f(\"R\", 5, 8),\n\n        f(\"MRX\", 6, 6),\n        f(\"MRY\", 6, 7),\n        f(\"MR\", 6, 8),\n\n        f(\"X_ERROR\", 7, 6),\n        f(\"Y_ERROR\", 7, 7),\n        f(\"Z_ERROR\", 7, 8),\n\n        f(\"E:X\", 8, 6),\n        f(\"E:Y\", 8, 7),\n        f(\"E:Z\", 8, 8),\n\n        f(\"ELSE_CORRELATED_ERROR:X\", 9, 6),\n        f(\"ELSE_CORRELATED_ERROR:Y\", 9, 7),\n        f(\"ELSE_CORRELATED_ERROR:Z\", 9, 8),\n\n        f(\"MPP:X\", 10, 6),\n        f(\"MPP:Y\", 10, 7),\n        f(\"MPP:Z\", 10, 8),\n\n        f(\"SQRT_XX\", 11, 6),\n        f(\"SQRT_YY\", 11, 7),\n        f(\"SQRT_ZZ\", 11, 8),\n\n        f(\"SQRT_XX_DAG\", 12, 6),\n        f(\"SQRT_YY_DAG\", 12, 7),\n        f(\"SQRT_ZZ_DAG\", 12, 8),\n\n        f(\"X:REC\", 13, 6),\n        f(\"Y:REC\", 13, 7),\n        f(\"Z:REC\", 13, 8),\n\n        f(\"X:SWEEP\", 14, 6),\n        f(\"Y:SWEEP\", 14, 7),\n        f(\"Z:SWEEP\", 14, 8),\n\n        f(\"I\", 0, 6),\n        f(\"C_XYZ\", 1, 9),\n        f(\"C_NXYZ\", 6, 10),\n        f(\"C_XNYZ\", 7, 10),\n        f(\"C_XYNZ\", 8, 10),\n        f(\"C_ZYX\", 2, 9),\n        f(\"C_NZYX\", 9, 10),\n        f(\"C_ZNYX\", 10, 10),\n        f(\"C_ZYNX\", 11, 10),\n        f(\"H_NXY\", 12, 10),\n        f(\"H_NXZ\", 13, 10),\n        f(\"H_NYZ\", 14, 10),\n        f(\"II\", 15, 10),\n        f(\"II_ERROR\", 15, 11),\n        f(\"I_ERROR\", 15, 8),\n        f(\"DEPOLARIZE1\", 3, 9),\n        f(\"DEPOLARIZE2\", 4, 9),\n        f(\"ISWAP\", 5, 9),\n        f(\"ISWAP_DAG\", 6, 9),\n        f(\"SWAP\", 7, 9),\n        f(\"PAULI_CHANNEL_1\", 8, 9),\n        f(\"PAULI_CHANNEL_2\", 9, 9),\n        f(\"MXX\", 10, 9),\n        f(\"MYY\", 11, 9),\n        f(\"MZZ\", 12, 9),\n        f(\"MPAD\", 13, 9),\n        f(\"HERALDED_ERASE\", 14, 9),\n        f(\"HERALDED_PAULI_CHANNEL_1\", 15, 9),\n\n        f(\"SPP:X\", 0, 10),\n        f(\"SPP:Y\", 1, 10),\n        f(\"SPP:Z\", 2, 10),\n        f(\"SPP_DAG:X\", 3, 10),\n        f(\"SPP_DAG:Y\", 4, 10),\n        f(\"SPP_DAG:Z\", 5, 10),\n\n        make_x_control_mesh(),\n        make_y_control_mesh(),\n        make_z_control_mesh(),\n        make_xswap_control_mesh(),\n        make_zswap_control_mesh(),\n        make_detector_mesh(false),\n        make_detector_mesh(true),\n    };\n}\n"
  },
  {
    "path": "src/stim/diagram/gate_data_3d.h",
    "content": "#ifndef _STIM_DIAGRAM_GATE_DATA_3d_H\n#define _STIM_DIAGRAM_GATE_DATA_3d_H\n\n#include \"stim/diagram/gltf.h\"\n\nnamespace stim_draw_internal {\n\nstd::map<std::string_view, std::shared_ptr<GltfMesh>> make_gate_primitives();\n\n}\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/gate_data_3d_texture_data.cc",
    "content": "#include \"stim/diagram/gate_data_3d_texture_data.h\"\n\nstd::string stim_draw_internal::make_gate_3d_texture_data_uri() {\n    std::string result;\n    result.append(\"data:image/png;base64,\");\n    result.append(\"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAdnJLH8AAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAIABJREFUeNrsnXdUVLnbx79DlSaCIlWKAiIIorgWsPxsrGLDgg2xYFkL9l5AwYqKvWJbC1bWrruKiuDq6iq6KDZQUSyAgiIIAjPwvH/sO/c4SxF17h2EfM6ZI95k5klyk5vvTZ4kIiIiMBgMBoPBqFQosSJgMBgMBoMJAAaDwWAwGEwAMBgMBoPBYAKAwWAwGAwGEwAMBoPBYDCYAGBUMs6cOYM3b96wgmAwGAwmABiVidOnTzMBwAAAvHr1Cjdv3uTdTkxMDFJTU8tFnj09PeHu7s5uPkPhDBkyBMeOHas8AuDDhw9wcnKCo6MjMjMzBbN7+/Zt6OvrY8yYMQCA/Px8NGzYEPb29vj48aNg6di2bRtGjx4tcy00NBTjxo3j1W5ubi4CAwPRrFkzhIeHw8vLC1ZWVhg5ciSuXLkid3vr1q2Dq6sr3N3d0a5dOyQkJJQaPyEhAQ4ODnj//j0v+c/Pz0dISAjq16+P2rVrw87ODmvXrhW8/icnJ8PU1LRcdEDbt2/HmjVrUL9+fd5t1atXDwEBAdizZ4/C83379m3cunWL9T4MhZKfn4/IyEh06tTp679MPygnT54kAASATp8+LZjdjRs3EgCysLAgIqKEhAQuHXFxcYKlY8SIEbRz506Za4MHD6awsDDebGZmZpKTkxN5eHhQZmYmjR07lu7evUupqanUrVs3AkCfPn2Sm71Vq1aRmpoaJSYmEhGRp6cn2djYkFgsLjZ+fn4+NWnShKKjo3nJf2FhIXXu3JmqVKlCV69eJSKiuLg4qlq1KoWGhgpa/8+dO8fVO3mW+dcyd+5cmjhxoqA2CwoKqHfv3rRw4UJB7T548IBq1KhBPj4+9OnTJxoyZAh16dKF8vLyyMfH\");\n    result.append(\"h/T19QV9BkgkEpJIJMSo3Jw4cYJ8fHy+6bs/7AiAjo4O97eamppgdg0NDQEAVlZW3P9FIhEAwMjISLB0/P3332jatKnMtatXr6J58+a82Vy7di3u3LmDhQsXypR/zZo1sW/fPpiamsrNVmFhIYKDg+Hk5ARLS0tuyDUhIQFHjhwp9juzZ89Gp06d0LJlS17yHxkZidOnT6Nv375cOTs4OKBbt24lpokvjI2NuX+rVKmikDa4bds2hIeHY8WKFYLaVVJSwo4dO7B161YcPnxYMLv6+vrQ19fHnj174OnpicaNG8PFxQV9+vTBnj17ULVqVejp6QmWniVLlmDVqlXsFbiSc/DgQfTt2/fb2tKPmulatWpxf5uZmQlm197eHgDg5OTECZHatWtDW1sb1atXFyQNOTk5ePHiBezs7Lhrb9++RWZmJidM+ODGjRsAgIKCgiJhWlpa3zYEVQKvX79GSkoKatSowV0zMTHhhl7/y7lz53D9+nX4+/vzlv87d+5wHdDnpKenw8DAQND6b2trC1VVVTg6Oiqk/T19+hQTJ06Ev78/lJWVFfICMHfuXAwdOhQvX74UxGbNmjXx8OFD3Lp1C61bt8b69etx8OBBNGnSBH/99ReePHnC1VEGQwhyc3Nx+fJldOjQoXIJADMzM+7N29zcXNAHr6amJicAAKBBgwZo0KCBYGmIiYlBo0aNuPxL3/6bNWvGq11pJ7d8+fJiw8eNGwdVVVW52FJRUQEASCQS7pr02Ir/jvi8efMGEyZMwN69e3ntjKRi5Pr16zL3IioqClOnThW0/qupqcHOzk6mHgrJ3LlzIZFI0L17d4U9A/r27QuJRIKFCxcKZjMqKgpr165FaGgo7O3tYWFhgbCwMOzatQuXL19mPRJDUM6cOYN27dp98yi4yo+acTU1NdSsWRMSiQSampqC2VVSUoKjo6NMh9+gQQOkp6fzanfWrFnYtGkTAODTp09QVlZGtWrVuPDPr40ePRpLliyRexoGDRqEbdu24dChQ9DQ\");\n    result.append(\"0CjyJizPzsjIyAh16tTBq1evuGvPnj0DADRs2FBGFAwdOhRBQUG8C0HplMv9+/dx+/ZtvHnzBtOnT8fp06fh5ORUxAteVVWVV2EotPCU8uLFCxw8eBBt27aFlpaWwp4BOjo6cHFxwY4dOzBv3jxuWoQv4uLi0LZtWygpKeHAgQOIj49HVlYWhgwZAm9vb2zZsgWxsbEKG5VhVD4OHTqEoUOHfvsP/MjOD40bNyZnZ2fB7QYGBlJOTg73//Pnz9ORI0cEs9+zZ0/67bffZK517dpVEGfI4OBgzvkMAK/5Dg8PJ2VlZYqJiaH8/HxydXWlFi1aUGFhoYyj4PDhwwUrezc3NwJAxsbGNHfuXMrKyuLCli5dypVLv3796Ny5c7ymZceOHXT//n3B6//y5csJAE2ePFnhz4AxY8YQAEGcMDMzM2nKlCl04cIF7vnTuHFjIiK6cOECzZw5kzIzMwXL+4IFC2j58uXMC66Skp2dTRYWFiU6RZeFH1oA9OjRg7p161bpbrylpSU9f/5c5pqxsTGlpqYKYv/w4cNUrVo1AkDKyso0d+5c3ryR//jjD+rfvz8NGjSI5s+fL+Pxfvv2bWrQoAFlZ2dzXtErVqyg3r17k7e3N928eVOuKwB27dpFlpaWXCdf3IoLHR0d6tq1a4Wufx4eHgSAtmzZovC0hISEEADq3r274LYNDAyoRo0aCss7EwCVm4MHD9LIkSO/6zd+aAEwfvx48vPzq1Q3PT09nQwMDGSuvXz5kszMzARNx+vXr6lJkyZcZ9i6dWt6+/atoOq3QYMGdPv2be6ar68vOTk5UW5uLkVERJCGhgZdv379u22lpKRQu3btqHnz5vTkyRNydXUlAGRoaEjv3r3j4iUlJZGOjg69fPmyQtdBMzMzAlBkFEpRD0EAZGtrK7jtiIgI+v3333m3c/LkSdLS0iryUVNTIzU1tWLDTp48yXrICk7Pnj250ahv5YfeCbBWrVqCOgCWB2JiYuDi4iJz7caNG2jcuLGg6TA2NsZP\");\n    result.append(\"P/2EgIAA6OrqIioqCi1bthRsM6Tx48dj6NChcHZ2BgDcvXsXO3bswIABA6Curo727dvDwMAAs2bN+i47r169QtOmTZGeno6IiAjUrl0bK1euhEgkQmpqKiZOnMjFDQkJwcqVK+W6HLI88vbtW24OXtFI/X9SUlIEt92+fXt07NiRdztdunTBx48fi3z8/f2xaNGiYsO6dOnCJsgrMB8/fuRWo3wPKj9yIXy+FLCiI3UCzMvLAxHJOADm5uZCJBJx1/hyAiwOLy8veHt7o3379nj48CFWrFiB+fPn82rz8OHDSE5OxtatW7lrf/zxBwCgTp063DVra2tERUUhOzv7m53VhgwZgufPn2Pjxo3cbzRt2hSjR4/Gxo0bsXv3bnTq1Am1atVCUlISVq9eXeHr4ucrMxSNhoYG90BkVHzy8/PRtm3bYsMuXrwo6J4wiuT48ePw8PD47lVPP7QA+O+bcEVmyZIlWLJkCXr27AkfHx/06NGDC+vcuTOmTJlSYsOQp+rU1tYuct3W1hYbN25E165dedkO+HOeP3+OefPmISoqSmYZpPQN8PMVIVpaWigoKMDbt2+/SQDcvXsX58+fBwBupEHKihUrEBUVhXv37mHUqFGwsLBAREREpaiLBgYGSElJQU5OjsLT8unTJwBA1apVWe9YCSgsLCzxGVNYWFhpyuHQoUOYMmXKd//ODz0FYG1tDWtr60rVAK5fv15kvX9MTIwgUwC//PLLF8WYdP0+HxQUFMDHxwdr1qwpsvGOrq4uAEAsFnPX8vLyAPy7gcu3EBcXx/39+PHjIm+ehw4dgpaWFj58+ICsrCwZ21Lu3btX4eqgdIojIyND4WnJysoCANSuXZv1jpWAKlWq4P9914p8FLUjptB8+PABd+/eRYsWLSqvACAirFu3Dhs3bqw0lf/FixdQVVWVWe+cmJiIGjVqCPIGlJqaisjIyGLDrl27BuDfKQG+CAoKQrNmzYrd9apVq1YAgKSkJJmykW7c9C1ItyAGgICAAOTm5sqE\");\n    result.append(\"P336FAYGBlBVVUViYiLc3Nxkyufo0aO4dOlShauH0q2WExMTFZ6W58+fA4DgPjCVnZcvX2Ls2LFYu3ZtpXrz/pw1a9Yo5CCwY8eOoVu3bkX2YfnWjvSH5NKlS5wHujw8vX8EDh06RH379pW5duDAAfL19RXEfrt27cjMzIzOnj1LRMQdBnT37l0yMzOjQYMGUUFBAS+2o6OjqWnTppSfn1/iMr3//e9/1KZNGyosLKSYmJgSl+p9DZ6enlw9s7e3p4CAAFq+fDm1b9+e6tevTw8fPqQ//viDdHR0uHhmZmZUp04dsrW1FXRduFBIDyLq37+/wtMyePBgAkBnzpypdF7gS5YsoVWrVinE9qBBg7j6HhISUunK/s8//+Tyf+XKFUFtd+rUiTuM7Hv5YQXAmzdvyNbWlurVqyezFKsiM2XKlCINfvLkybR582ZB7N++fZsmTZpEjRo1IkdHRzI1NaVmzZqRh4cHr0vC3r17R/b29hQfH19qvIyMDBo4cCC5u7uTs7MzrVmz5rtti8ViWrduHTk7O5O2tjbp6upSixYtaNOmTTIbcCQmJtLAgQOpevXqpKenR15eXkX2aqgoiMVisra2JisrK4WnxdbWlszNzb9rMxTG17NhwwbS1tYmZ2dn6tChQ6XLf1paGtnZ2VHdunUpLS1NMLvp6elUp04dmc3QvgcR0f9vsM5gfCV+fn4YNWqUIOfAM8oXYWFhGDhwIO7du8cdkCU0CQkJsLW1xdatWzF8+HB2UxRAdHQ0Nm/ejH379rHC+AFRYkXA+FY8PDy+2cGO8WPTv39/tG/fHuvWrVNYGtatW4dWrVrB19eX3RAFsWfPnlKdgxnlGzYCwGAwvol3797B1dUVu3bt4g5KEooHDx6gW7duiIyMFPQ4cMa/5OTkIDg4GCYmJkwAMAHAYDAqI0lJSRg5ciTWrl0LW1tbQWy+fv0avr6+gtpkyBIeHg4XFxdYWVmxwmACgMFgVFays7Oxdu1adOjQgffleDdv3sSJEycwZcoU\");\n    result.append(\"bu8HBoPBBACDwVAghYWF8lmbrGAbDAYTAAwGg8FgMCosTEozGAwGg8EEAIPBYDAYDCYAGAwGg8FgMAHAYDAYDAaDCQAGg8FgMBhMADAYDAaDwWACgMFgMBgMBhMADAaDwWAwmABgMBgMBoPxowmA9+/fY9y4cWjYsCEaNWqEAQMG4NWrV4ImPDc3F+vXr4e5uTkyMjIEs5uTk4MZM2bA0tISampqMDc3x/jx4/Hu3TtB7EskEoSEhKBevXrQ0NCAhYUF5syZA7FYrLBKNGzYMIhEIuTm5gpmc+bMmRCJREU+//zzj6B5T05Oxty5c9GpUyeMHTsWu3bt4tVe06ZNi8239GNhYcF7nnfv3o2WLVuiQ4cOcHd3R8uWLbF7927ByvzkyZNo06YNmjVrBktLS3h5eeHRo0fsac6oFJw4cQK+vr7w9fWFvb09HB0dERwcDIlE8vU/Rl9JamoqOTo6kre3N4nFYiIimjNnDpmYmNDTp0+Jb3Jzc2n16tVUp04dAkAA6P379yQEBQUF1KpVK1JWViZra2uqUaMGl4Y6depQcnIyr/YLCwvJ29ub6tWrRz4+PuTq6srZ9/X1JUVw8OBBLg2fPn0SxGZ6ejpVrVqVlJWVZT4dO3YUNO/Lli0jHR0dWrx4MeXl5fFu79atWwSAlJWVqXr16mRoaCjzEYlENG7cOF7TMG3aNDIxMaFHjx5x1+7fv096eno0c+ZM3stg+fLlZGJiQnfv3iUiog8fPlCHDh2oatWqdO3aNWIwKjKBgYHk7e1NBQUFREQkFotp5MiRBIAGDBjw1b/31QKgW7dupKOjQxkZGdy1vLw8MjQ0JDc3NyosLOS1AMRiMb17945SU1NJVVVVUAGwZs0aat++PSUmJnLXDhw4QJqamgSAvL29ebW/f/9+Cg4OlrkWGhrKdcB8C5D/kpiYSHXq1KGqVasKKgDmzJlDS5cuVVgjlEgk1KdPH1JTU6M//vhDMLujRo2iJUuWUHZ2drH3AgD9+eefvNmPj48nkUhE\");\n    result.append(\"q1evLhI2Y8YMEolElJSUxJv9v/76i5SUlGj79u0y19PS0khTU5MsLCyKLRuGsG0jPDycYmNjK0yebt++TUeOHOE6XUWRkZFBqqqqtGzZMpnrOTk5pKenRwDo77//5k8AREVFEQDy8vIqEubr60sA6Pjx44IViJmZmaACYNCgQZSTk1Pk+qpVqwgAaWlp8Wq/pJtra2tLAOjBgweClb1YLCZXV1c6efIkmZqaCiYA3r17R1ZWVpSVlaWwhiit6//tiPgu740bN5YYHhwcTGZmZrwK8P379xOAYtOxbt06AsDrW7inpycBoMePHxcJ8/HxIQC0du1a1gsrgPT0dFq6dClZWlpS9+7d6dmzZxUmbwkJCfS///2PrKysKCQkROblV0iePn1KAKh27dpF2rl0NDg0NPSrfvOrfAAOHjwIAHBxcSl2bhIA73Ogn6Ompibo3Iufnx80NDSKXO/Xrx8AQCwWg3g8XPGnn34q9nrNmjXh4OCAunXrClYW8+bNQ5MmTdClSxdB78Hq1auRkpKCHj16YNmyZUhOThbU/u7du7Fjxw60bdsWvr6+gtlVUVHB6NGjSww/dOgQ+vTpA5FIxFsaTE1NAQCbN29Gfn6+TFhsbCyMjY3RoEED3uxfvHgRAGBoaFgkrHXr1gCA48ePs0liAYmLi8PIkSNRv359vHnzBhcvXsSxY8cE8UURCmtra0RGRuLo0aOIi4uDtbU1xo0bh/j4eEHTYWlpic6dO0NFRQWFhYVF/PI+b6O8+ADUrl2bANC+ffuKhEVERBAAMjQ0FEwRSf0AhBoBKG3YSyQSUcOGDRUyLFSzZk2KiYkRzGZkZCQ1btyYm/cWagQgIyODqlWrxk15AKAqVarQ/PnzBRme+/jxIxkbGxMAOn/+fLl5Q3ny5AkBoOvXr/Nqp7CwkBwdHQkAdevWjRtuv337NlWrVo1+//133mzn5uZy9/zFixdFws+ePUsAyNjYWLARmVatWpGZmZmMP4RQfPjwgZycnKh27dr08uVLQW0X\");\n    result.append(\"FBTQsWPHqG3btmRnZ0cbNmygjx8/8mbv5MmTpKWl9VWfo0eP8paeN2/eUFBQEJmYmJCHhwedO3dOoe0/OTmZVFRUyMLCgnJzc/mZAigsLCRlZWUCQJcuXSp2eFraQDMzMyuVAIiLiyMAtGrVKkHtZmVlUZcuXWjbtm2C2UxLS6O6detSfHw8d00oAZCZmUlXrlyh48eP04wZM8jS0pKrc7169eJdBOzZs4frZKKjo8nb25tsbGzI2tqaRo0aRampqQqpf4sXLyZLS0tBbMXHx3MiyNnZmc6cOUMtW7akGzdu8G5bS0uLABT7cD99+jQBIG1tbcEeuiKRiADQrl27BL/nsbGxXN0/ffq0YC8bISEhVKdOHerUqRP98ccfvPt8lWfy8vJo9+7d5OLiQvb29rR582aF+KBMmzaNlJWVv+mlpMwCIC0tjatwxTX2e/fuceF8OgKVRwEwZ84csrCwKNY/gA9evHhBCxcu5HwglJWVafbs2YLY7tatG+3evVvmmpA+AP99KwwKCuIexCtXruTVXo8ePTgBEBQURLGxsXT79m1ubtrS0lIhIsDZ2ZlmzJghmL3ExERycHDg2rtQwrd79+4EgH7++eciYVJn2Fq1aglWDnv27KGgoCBBVoAUR2hoKIWEhPAufJOTk2nMmDFkbGxMfn5+MuKf8S+XL1+m3r17U82aNWnGjBmUlpYmiN2UlBTS1NQs1T9ILgLg5cuXXIO/c+dOqYpUqIdgeRAAqamppK+vTxEREYJ2fImJibR3715ycXHhyn3Lli282l27di0NGjSoyHVFCQApK1euJABkZmbGq526desSANqwYYPM9fz8fLK3tycANHjwYEHzHh8fTwDo1q1bgtm8fv069e7dmwIDA0lJSYkA0OjRo3nviO7cucOtuJkyZQp9+PCBMjMz6cCBA9yzoHPnzqw3kjPPnj0jT09PMjIyooCAAEpJSWGF8h+ysrJo3bp1ZG5uTj///LMgS+KJiCZNmkTTpk375u+XWQB8/Pix1BGA\");\n    result.append(\"q1evEgASiUQkkUgqjQDo1asXLVy4UGH2JRIJDRo0iACQvb09b3ZiY2PJycmpWO97RQuAwsJCatiwIQGg169f82ZHV1e3xCHo9evXEwCqWrWqoMOiCxYsIFtbW8HsRUREkImJCbfk9LfffqMqVapwIoBvrl27xoleJSUlqlevHq1bt46srKwIAG3atIn1Rjzx9OlTmjx5MtWsWZN8fHwE8zs6deoU6erqftVHqNVojx8/pokTJ5KpqSmNGTOGHj58KOiLoIeHx3f1t1/lBCh90Bfn7HPq1CnBh+AULQBWrFhBI0aMUHjDTEtLIzU1NVJVVeXNhnTpW1k+0k1ahCQwMJAA8OoQJZ37Lq7+379/n8v/hw8fBMu3o6Mj+fv7C2Lr3bt3pKenR9OnT5e5/vvvv3N7cgi1GU96ejo3zHrjxg0CQHp6eoKWfWV/27W1taWWLVtSeHi4YC995YXz589T165dydraWmFLA69evUqHDh36rt9Q+ZoVA61atcL+/fvx5MmTImHPnj0DALi7u1eK5S+HDx/GzZs3ERYWpvC0VK9eHS4uLrxuh9q4cWNkZ2eXuDXlp0+f4OXlBSUlJVSrVk3wMjAxMUH16tVhZGTEmw07OzskJyfjzZs3RcLMzMwAAOrq6tDW1hYkz48ePcLdu3exf/9+Qezt378f79+/h6urq8z1jh07IjAwELNnz8aJEye4JcF8oq+vz/3t7+8PAFi4cCGqVq3K1ubxjLa2Nvz8/DB27FicOXMGa9aswdSpU+Hn54dhw4YppP0LQU5ODvbu3Yu1a9fC0NAQ48ePR9euXaGkpJgjdZ4+ffr9be1r1ILU07a4eeDhw4cTADp16lSFHwE4deoU9ezZk/Lz84sdklcE9evXp379+inEtqKnAIiIfvnlF5oyZQqvNtauXUsAaNSoUUXCXrx4UaKDGp+jHg4ODoLZ8/f3L3EKJDk5mQCQn5+foPdduhV17969K7VHuqK5d+8ejRw5kgwMDGjs2LEKWxHDB2/fvqXp06eT\");\n    result.append(\"qakpjRgxguLi4spFuuRR3796K2BXV1eqXr26zMM+Ly+PDAwMqGnTpoI2Qum+BEIKgJMnT1LXrl2LXW/56tUr8vHx4c12fn5+sQLj2rVrpK2tTffu3avQAuDp06d04cKFYvPv4ODAez3Iyckhc3Nz0tPTK+ILcejQIRKJRMUukeULe3t7CgoKEsxeZGQkAaCpU6cWCXv48CEBoBMnTgiWnuvXr5OmpiZ5enoqRHxu376d5s+fr5BVAO/fv6fJkydTUFDQV6/95ntqZunSpfTXX39VGAHw559/0tKlSyk9Pb3cpCk/P58WL1783UvAv1oAPHnyhAwNDbmDPwoKCsjPz49MTEzoyZMnghaC9DCe58+fC2IvLCyMVFVVycXFhdzc3LiPq6srOTk5kYqKCq9LoszNzUlXV5dmz55NCQkJ9O7dOzp06BDZ2NjQ2bNnFVYZhRIA0u0uW7ZsSYcPH6bo6GiaP38+NWvWTOZ8Bj6JiYkhHR0dGjBgACfGXr58STY2NrRo0SJB37gACL4JzYgRI6hKlSoUHR3NXcvOzqauXbt+02Ek38qvv/5KNWrUoEWLFilkj/Znz55xPh979+4V3H5AQABnn+8DoBjlj/DwcO7+f88zAN/ypcTEROrduze5urqSm5ub4EM+GzZsoN69e3MF4OrqSkuXLuW1Azpy5Ai33rykj4qKCq/lEBgYSKampqSqqkpVq1YlZ2dnmjlzpsKX5QglAKKjo8nFxYU0NDRIT0+PWrduTaGhocVOxfDJ3bt3qXPnzuTs7ExeXl7UpUsXQc/AkHYAzs7Ogt/rwsJC2rJlCzVp0oQ6duxIAwYMoC5dutDmzZt5H/3bt28fTZ06lbp160bTpk1T6H7zubm51LRpUzIzM6OEhATB7R8/fpx0dHTIxcWFbGxsWI9YyXj69CmZm5tT48aNv2vzIRERj5vXMxgMBoM3kpKS0K9fP1y9epUVBuOrUWJFwGAwGD8me/bswahRo1hBML4JFVYEDAaD8WMhkUiwceNGiMVi\");\n    result.append(\"+Pj4sAJhfBNsCoDBYDB+MP744w+YmprC0dGRFQaDCQAGg8FgMBhlh/kAMBgMBoPBBACDwWAwGAwmABgMBoPBYDABwGAwGAwGgwkABoPBYDAYTAAwGAwGg8FgAoDBYDAYDAYTAAwGg8FgMJgAYDAYDAaDwQQAg8FgMBgMIfnqw4DEYjFOnjyJM2fOQCwWQ11dHUSEnJwcqKio4KeffsLgwYOho6PDSpfBYDAYjPIKfQW7d+8mNzc32rBhA2VkZBQJLygooN9//508PT3pjz/+IL4ZO3YsXbx4kVcbFy5coJkzZ5Kuri4BIACkoaFBtra25OLiQpaWlmRra0sDBgygs2fPkhBERUXR4MGDqU6dOmRsbEwNGzak5s2b04IFC+j58+d05coVWrhw4XfbefToES1cuJDq1avH5R0AqampkbGxMenr65OlpSW1adOGZs2aRf/88w8v+T18+DBNmDCBNDQ0CACpq6uThYWFzMfU1JTU1dUJAPn7+8vV/oMHD2jBggVkZWXFlYGJiYmMfX19fS5swYIFvN37t2/fUkhICLVo0YIcHBzIycmJmjRpQm3atKFVq1ZRUlISjRkzhvLy8uR2/+vWrcvlzdjYmGbMmEE3btzg4h07dowmTJhAampqXLz//e9/tHz5csrOzpZr/u/cuUOBgYFkaWnJ2TI3N6f58+fTnTt3BGl/0vpQu3Ztmfowb948iomJkZsdafnXqVNHpvznzZvHtbWMjAxauHAhaWtrEwASiUTUpUsXOnDggNzScfDgQRozZgypqqpy6XBxcaGAgAC6ffu23Mv34cOHNHPmTDIyMuLsbd++vczfHzhrtvZMAAAgAElEQVRwoEw9DA4O/up6mJubS4sWLSI3Nzfut/r3719i/GfPntGiRYvIycmJAJCTkxMtWrSIXrx4IdeyiYmJoV9++YXs7e3J1taWLCwsyN7eniZOnEhPnjz56t8rkwDIzs6mHj160LBhw8pUkBKJhGbMmEGhoaG8NcKMjAzS1tamHj16CNLo\");\n    result.append(\"V69eTQBIS0urSNjly5fJ0dGRAJCPjw+JxWJe0pCZmUl9+vQhZWVlmj59OiUlJXFhOTk5tGvXLjI1NSVlZWWaNGmSXB+60kYQHh5OEomEC4uNjaXx48dzDwcfHx/6+PEjL/kfPXo0ASA3N7cSG+3gwYNp4sSJvNj/+++/uXJ48OBBsQ/shg0b0syZM3mxf+jQIdLR0aEWLVpQdHQ0FRYWcmGpqak0Z84cUlFRIQByffDExsZy+T5x4kSJ8aZNm0YAqEaNGpSfn8+7CJamKTIykhTBP//8w6Xh9OnTvNmJiYnh7Jw8ebLYOI6OjmRoaEhRUVG8pcPX15cAkKGhoVwE5pc4e/Ysl+969erJ1PeSePnyJfcs0tbWlks9nD9/PpeO4ODgL4oXAJSYmCjXssjOziZfX19SU1OjJUuW0Lt377iwhIQE8vb25sLkKgByc3OpRYsW3/RWNWTIELp37x4vlSMkJIQAkLKyMj1//pz3ynjs2LESBQARUXp6OqdYQ0JCeBE89erVIyUlJTp27FiJ8ZKSksjMzIwGDx4sV9vSBvD5m9/n/Pnnn6Snp8epbj46gMDAwFIFgPQNecSIEbzUgZcvX5YqAKRiacKECXK3vWDBAu4tpKCgoFSRAIBu3bolN9tpaWlcvkt7w5W2SUdHR97b4+PHj7k0fcubjzxISUnh0hAbG6swO8uWLSNLS0t6+vQpr/mVdoRNmzYVpHyTkpJITU2NG1k6fvz4F78zdepUbjSkTp06ckuLdARYSUmJfv/991I7agAyL0nfS25uLrVu3ZoA0KFDh0qM5+fnRwBo/PjxZf7tLzoBjhkzBqampggKCvrq6YXVq1fD399f7tMWhYWFWL9+PbS1tVFQUIBNmzbxPlWirKxcari+vj769u0LANi9e7fc7Q8fPhwPHjzA8OHD0b179xLj1apVC1u2bMH79+8FyzsAuLm5ISwsDABw6dIlLF26VO5loKT0ZZ/VGjVqoGvXrgqpAwDg6OhY6v35FiIiIhAQEAArKyvs\");\n    result.append(\"3Lmz1HLw8vLCoEGD8ObNG17yXZptaVhZ7pNQaaoIaSjNzq+//ooNGzYgMjISVlZWguRXRUVFkPJVVVWFhoYGBgwYAABYtmxZqfGzsrKwbds2DBs2jJd01qtXD4WFhejfvz8SEhJKbQNleVaUlQkTJiAqKgo9evSAl5dXifGCg4NhaGiItWvXYu/evWV7ppYWGBkZiWPHjmHjxo3flHBdXV3UqFEDz549k+uNOH78ODQ0NBAYGAgA2LZtG3JzcxXuTyG96ampqXL93d9//x3h4eEAgGnTpn0xvoeHB8zNzQXPf6dOndCxY0cAwIoVK5CVlaWQ+8CXACgrbdq0kdtv5eTkYPDgwSAiTJ8+Herq6l/8zvTp0yGRSJiDUwVn586d8Pf3x/nz52FpaVlh8zl16lSIRCJcuXIFV69eLTFeaGgoWrVqBTs7O17SsX//fpibmyMjIwPdu3cX5PkWFxeHrVu3AgBGjx5dalxNTU0MHDgQADBr1izk5eV9nwAICAjA9OnToa+vX+xb+NatW9G3b19MmjQJgYGBOHXqFFq0aIFjx47JdEbnz5+Xa6GsWbMG48aNg6+vLzQ1NZGWloYDBw4otJLm5OTgyJEjAIAmTZrI9bdDQ0MBADY2NrC2ti7Td+bNm6eQchg0aBAAIDMzE6dPnxbU9v79+/HPP/8oJN9isRizZs2S+++GhYUhOTkZANCrV68yfcfBwQGdO3dmPWQFZt26dfD398eFCxfK/Ez4UXFwcOBeLEoaBZBIJFi7di2mTp3KWzoMDQ1x/PhxaGlp4cGDBxg4cCCIiNe8h4WFobCwECoqKmjRosUX47du3RoA8PLlS0RGRn67ALh//z5u3LiBkSNHFgnLy8tDr169EB0djb1792LVqlVwcHDAhAkTcPXqVTRv3pyLa2FhUeJwybcQGxuL2NhY+Pj4oFq1avD29uYahFAUFBTI/H39+nV06tQJz549g76+PhYvXixXe9Ib6eDgUObv1KhRQyGNtVmzZtzfN27cEMzu27dv\");\n    result.append(\"sWHDBoWJv8WLF+PTp09y/+2TJ08CAExNTWFgYMB6PgYWLFiApUuX4uLFi7C1ta0UeZaOfJ44cQKPHj0qEn7w4EEYGxujZcuWvKbD2dkZe/bsgUgkwokTJxAQEMCrvcuXLwMAzM3NoaGh8cX49vb2Rb5bGiVOkhw/fhxt2rSBnp5ekc6vc+fOeP/+Pa5evQpVVVUAgK2tLZ4+fYqffvoJhoaGXHwtLS25Ds+vWbMGw4YNg5aWFgDAz88PW7duxa1bt/DXX3/JiA8+yM7OhpGREQwNDZGdnY2XL19yw61dunTBqlWr5KrI09LS8OHDB4V26l+rkqWkpKTwYuPWrVsyw3zZ2dl49eoV72r8cxo0aACRSAQAyM/PBxFhwoQJcrfz4MEDAED16tVLjbdhwwZcuXIF7969k0njuHHjYGZmJrf09OjRo8RpCHn6nTCKZ8aMGThz5gzc3Nzkel/LO23atIGLiwtiYmKwfPlybNu2TSY8JCQEc+bMESQtPXr0wIIFCzB37lwsWrQIzs7OZR6d+1qko3/VqlUrU/zP40m/+00jADdv3ixWTQUHB+PixYvYsWOHzINAOs//36HH169fw9jYWG5veQcPHoSfnx93zcnJiUunEKMAWlpaePv2LeLi4pCYmIh3794hPDwc9evXx7lz5zBz5kwkJSXJzV5+fj73d1kUoKL53ElJTU2NFxuNGjXCw4cPuc+LFy/w5MkT1K9fX7B8xsbGIjc3F7m5ucjJycHcuXN5sSO9/5mZmaXGGzt2LJYvX46oqCicPXsWGhoaCA4OlnsncfToUZmy//zDxxQIo6jwVFZWxpUrV9ClSxfk5ORUmrxLh/f37t0r07lduHABmZmZ6NGjh2BpmTNnDvr37w8iwuDBg3H37l1e7X0+6lwanz9zy+KIWKIAeP78OerVqydz7cmTJwgMDISnpycaNGggE3bx4sViBUB8fLzcHFQ2b94Md3f3Ir83duxYAEB4eDhvb50loaOjg169euHmzZtwdnbGb7/9hmbN\");\n    result.append(\"msnNC1tfX5/rVN++fVvuG+nn+TYxMRHMrpWVFUaNGqWQPFepUgWBgYG87H4pHVF5/fo1CgsLS41ramrKOX82bNiQ9ZYVkAEDBmDPnj1QVlZGZGQkunbtysvUU3nEy8sLlpaWyMvLw5o1a7jrK1aswOTJkwVfDbJjxw40adIE2dnZ6N69O9LT0+Vuw8jICEDZR9c+d0w0NTX9dgHw8ePHIsMOK1euRH5+PiZNmlREnRw7dgwGBgZwcXGRCTtz5gw6dOjw3QUhFouxadMmxMTEwM7OTubj7+8PFRUViMVibNmyRSGVU11dnZv7T05Oxvr16+XWuUjfbO/fv1/uG+nff//N/e3m5iaobXd3d67BKGLkQ7pcSZ5IR7fy8/Px559/fjG+dEqOr9EXRvHIc9nXl+jfvz/27dsHFRUVXLx4Ed26dasUIkBZWZnrezZv3oysrCzcu3cPMTExGDp0qEKE/7Fjx2BqaorExET07du3zG/qZUX6DH3x4sUXRwGlL+lSpA6B3yQANDU1ZZYSEREOHToEY2PjIt6IYWFheP78OX7++WduXhT4d/5aIpF8cf6yLBw6dAg1a9ZEUlJSkaHH+Ph4zJgxAwCwZcsWiMVihVTQz73/5dlZ9+vXDwBw584dJCYmluk72dnZgs6Jf14XpG//7du3F9S2jY2NwgQAgCIjZvJg2LBhXJuSli2j/KGrqyuovT59+nAi4Pz58+jevXu5WAot5eHDh7z87rBhw6Cvr48PHz5gy5YtWLFiBcaMGaOw6VFjY2OcOHECmpqauHDhAqZMmSL3ER9p/1sWr37pMsk6deqUySGyRAFgYWEhM5yemJiItLQ0Gecn4N/lBtL5T3d3d5nfWLx4MTc8/72sWbOm1MIdO3YsVFVVkZycjN9++00hleHzIXoLCwu5/a50MyYAmD17dplGS2bMmCHjPyAEly9fxokTJwAACxcuVNhbaF5eHqZPn14hOhZ7e3uMGTMGwL9DjrGxsay3LWfo6OjIOL8KhZeXFw4cOAAV\");\n    result.append(\"FRVERETA09OzXIiA/Pz8Mm9E87VoaWlxU30hISE4evSo3PqYb6VRo0b49ddfIRKJ5D4C7ezszL0AfmnDO4lEgp07dwIAli9fXqaNkEoUAD/99BNu3bol81AFgIyMDO5aSkoKgoKC0LZtWwCAq6srF3bu3Dm8fv2aW7/5PURHRyMpKYkriJKUmKenJwBg1apVcr/JZRlVCAkJ+bdQlZS43ajk9XZx4MABaGpq4sCBAwgKCirx7T4vLw8jR47EiBEjyrRpjLzyHhcXh759+6KwsBAjRozgZUhOOrz2pZGN+fPn8zIH/vkcvLyH+kpjxYoV8PDwgEQiQf/+/fHixQtBH3Blzbc0TIiyUcS9SE9PR926ddG1a1cUFhZydjt37szrFMB/lx1/Tq9evXDw4EGoqKjg7Nmz6Ny5M28b1EifA196HgQEBKBx48bfbU8ikRTr9zJ+/Hioq6sjJSUF/fv3L7I8Vjpy/SWfGXmk5XMxxteSwNDQUDg6OuLs2bOljgLOnTsXjx49wuzZs8vuEFnSHsFxcXFkbW0tsx9xjRo1CAD98ssvNHfuXOrWrRu9f/+eO33p3r17lJeXRytWrCAPDw/uUJjr16/T5cuXv2kfZLFYTE2bNiUvL68vxt2yZQu3Z7Y8T8MiIlqxYgUBIE1NTfrw4UORPeKlB9UoKyvzdghSVFQUWVhYcPvh7927l+Lj4ykjI4MeP35MW7dupQ4dOtBff/0lV7u3bt3iyvW/py+mpKTQ4sWLSUdHh7S1tb94WMb3MGzYMAJAlpaWxZ418OnTJ1q0aBFpaWnxciDRtWvXBDn8pTjy8/Np6tSppKamRkZGRhQaGko5OTkyed+1axfp6emRurq6XOv/54feHD16tMR448aN4w4D4utALCmXLl3i0hQdHS3IPbh79y5nc+/evXT+/HmqWbMm73vw37hxg7N76tSpYuOMHDmSi+Po6MjL2QRDhgwhAKSrq0sJCQkyZ1Lk5OTQ/fv3afTo0aSpqSmXUyCvXLlCIpGoyPOW\");\n    result.append(\"iGj48OGkpKRE8fHxJR5KpaOjI5c9+d+/f1/qOShSCgsLycvLi/B1h+yWOQ1dunQhVVVVCg4OpszMTC7s6dOn5OPjQxoaGrRmzRr5HQbUtm1bmQfdmTNnyNTUlMzMzGj+/PmUm5tLRESRkZFkampKJiYm5O7uTmFhYVzlKCgoIHd392Jv4pf4/fffqVmzZtwRvKNHjy7xJixZskTm2FJ1dXUaMWJEsRXka7hw4QJNnz6dO2ACnx3LaWdnR+bm5qSrq0sODg40bNgwunv3Lq8Pg+zsbFq/fj21bduWjI2NuaN5W7RoQRs2bJCpGN/Lo0ePaMGCBWRjYyOTdwMDA3JwcCB7e3uysrKizp07U0hICKWlpfGS58OHD9PYsWNJSUmJS0P16tWpTp063MfMzIw7Baxv375ytf/gwQMKCgoia2trzr6hoSEFBATI9fjXspCYmEiLFi2iVq1aUe3atcnJyYnq1atHlpaW5O7uTitXrqTk5GS53v/P25WRkRH5+/sXOQ7Yz89P5rhYIY8DtrKyosDAQEGOA16wYAEZGBiQoaEheXt7f/fzpTTu379Pc+bMkTmG2sjIiGbMmCFT77Zs2UK1atWSaaPKysrk4eFBmzdv/u50HDx4kEaNGkXKysoyNkr6dO/e/bvrXVBQEHcMspubGy1dupTevHkj0yZ79eol870zZ87QpEmTqEqVKlxaOnToQMuWLfumevjmzRtasmQJNWnShDuRcOHChfTo0aMSv5OTk0MuLi681YmIiAjy9vYmGxsbcnBwoHr16lGDBg1o5syZ33QCqIhKGU+9desWBg8ejJs3b37zcPKCBQtgbGyM4cOHs8lCBoPBYDDKCUpfcm7w9fXFkCFDvmk+JTQ0FMnJyazzZzAYDAbjRxIAADBp0iQ4OzvD09OzzJvbfPz4EX5+fkhMTJTbengGg8FgMBjyo9QpgM+Jjo6Gv78/WrZsiUGDBhV7CMXjx4+xf/9+REdHY/bs2XI9FpXBYDAYDIYCBADw7/Krc+fOITw8\");\n    result.append(\"HM+fP4eqqiqUlJQgEolQUFAAKysreHl5oVWrVjJ7BTAYDAaDwfiBBQCDwWAwGIyKgRIrAgaDwWAwmABgMBgMBoPBBACDwWAwGAwmABgMBoPBYDABwGAwGAwGgwkABoPBYDAYTAAwGAwGg8FgAoDBYDAYDAYTAAwGg8FgMJgAYDAYDEY55927d7C2tgbbQBa4ceMGkpKSKr4AiI+Px8KFC2FnZweRSMR9NDQ0oKenBzs7O/j6+iImJob3BN+/fx/jx4+Hvb09zMzMUL16dTg5OWHmzJl49eqV3O1dvHgRs2bNgp6eHpdvZWVlGBoaomrVqrCwsICHhwcOHz4sSKO4f/8++vfvD0NDQ+jq6sLGxgbjxo3DlStXsHLlSly6dEnuNsPCwmTue1k+ffv2/W67586dw6xZs1CtWjXudxs2bIglS5bg5cuXMnETExOxePFiODk5QSQSoVatWpg/fz4eP378zfajo6PRs2dPmXzVq1cPixcvLjb+6dOn0aJFCy5ut27d8OTJk6+2u2zZMpibm3O/U7t2baxcuRIAEBcXB19fX+4MDpFIhI4dOyIsLEzmNy5fvoyRI0dCSUkJqqqqGDFiBJKTk78qHUlJSZg0aRJq1aolUwaGhoaYM2cOsrOzubi//fYbevfuzcWpX78+goKCvuv+R0ZGol27djK2DQwM4O/vjxcvXsjEffLkCUaNGsWVS9WqVTFt2jS8fv1aLm0gKipKpv1ra2sX+SgrK0MkEkFFRQVXr17l7RmQm5sLkUgENTU11KhRg/v8t0z4QF9fH7a2trh27ZpCOqwXL17I5FlNTQ0ikQi5ubmCpkMsFmPQoEGYNGnSj61i6Cu4efMmASAAdOnSJSIiSk9PpwULFpCysjKJRCJatWoV8UFBQQFNnz6dVFVVacqUKZSUlERERBKJhKKiosjNzY20tLRo69atvNhfu3YtAaCqVatSdnY2ERF9+vSJtm/fTtra2gSABg8eTIWFhcQXly5dIg0NDRowYAC9fPmSiIiSkpJo\");\n    result.append(\"1qxZpKKiQgAoMjJS7nY3b95M9vb2dPPmTcrLy+PyLq0Lf/31F3cvHj16RJ6enuTh4SE3+8HBwZytlJSUUuMmJCQQALp+/brc7M+cOZOzf/HixVLjisViUldXp7Fjx36XzUePHpGSkhIBKLZNTZkyhUvTo0ePSvyd+vXr08KFC78rLbm5udSvXz/O3tSpU4uNl5aWRgBo7NixlJ+fL7fynzZtGmc7ICCg1LjNmzcnCwsLio+Pl2sbOHz4MNWtW5f+/vvvYtv4vXv3qEqVKgSAZs+eTXwibXvt2rUjRbBz506aMGEClQd+/vlnAkCfPn0S1O6yZcvIx8eH6tevT+fPn6cfla8SAKmpqVxDvHv3rkzYnDlzCACJRCK5PnyJiAoLC6lPnz4EgDZs2FBsnLy8POrYsSMBoODgYLkX1LFjxwgA6erqFgnbtm0bVy779+/n5UZJJBIyNzen+vXrk0QiKRJ+5MgREolEvAiA5cuXc538fx9CnwuAz8O8vLzkZj88PJwAkKam5hfj5uXlEQB69+6d3Oy/e/eOtLS0CACtWLGi1LgPHz4kXV1dysjI+G677u7uBID69OlTJOzt27ekqqpKAOjIkSPFfj8nJ4eqVasml7IQi8XUqlUrAkA1a9ak9+/fF4nj5+dHffv2lXv9E4vF1LBhQwJAdnZ2JBaLi42Xnp5Oenp6dO3aNbmnYePGjXTq1Kliw/Lz87n0NWrUSK7ipzwKgPfv35OVlRWvLzvlWQC8fv2azMzMKCUlhS5evEgODg4l1skKJQDevn1bogB49eoVFzZy5Ei5JnLRokUEgP73v/+VGi8pKYk0NDRISUmJzp07J9c0nDx5skQBIJFISF1dnQCQp6cnLzfq9u3bBIB69+5dYpxOnTrxIgD27t1bpLGXJgCIiHbt2iU3+0ePHi2x7IvrLABQVlaWXMtgzJgxBIDs7e1LjTdnzhyaOHGi3ModAGlpadHHjx+LhHft2pUA0MCBA4v9/pEjR6hr165yK4OXL1+Snp4eAaAh\");\n    result.append(\"Q4bIhO3fv58cHR250TE+6r90lGvp0qXFxhk7dixNnjyZF/tLliwpMW/SEaIqVarQvXv3eH9oK1oAEBF16dKFoqOjK6UAGDBggMyonJeXF61Zs6ZyCwAi4t6Sfv75Z7klMCUlhTQ1NQkAhYeHfzF+z549CQA5OTnJVaGWJgCIiOrUqUMAqEWLFrzcqFu3bnGdQUkPmR07dvAiAEp7CJUkAORJeRAA8fHxJBKJCACdPXu2xDdBY2PjUofkv4bs7GxueiksLKxI+Pr16wkAaWtrF9s59e7dm/bt2yd3MSi972fOnCEiort375KxsbHch92LE1cASENDgxISEmTCrl27RlZWVsUKJT65fPkyN1WzevVqQdueIgXAnj17yM/Pr9IJgOjoaKpfv77MG//z58/JxMSE3r59W3kFwIcPH7iwoUOHyi2By5Yt4363LEOZ27dv5+JfvXpVEAHw6dMnTqSMGjWKlxslFovJ1NSUS8Ovv/5aJM6rV6/o+fPnTADwIACkbz0AqGPHjsWG79+/n9q3by9Xm4MGDSIAxfpU9O7dm7sH/+3oMzMzqUaNGry8kffo0YMAkJmZGT1//pxsbGxKnIaQJ7m5uVSvXj1uNFAq8PPz88nR0bHEIXq+yMzMJCsrK64zFmpIvDwIgMzMTLK0tKSCgoJKIwAkEgk1aNCALly4UCQsKChI7iPfP5QA2LRpExdW0hvS99xgU1PTr3pTBvDdzk9lFQALFiwgAKSmpsbrW9D58+c5RyMA1Lx5c4qKilJIxamMAuDChQucn8v9+/eLhLds2VLuHWFERAQBIBUVFXrz5o2M4K5WrRonAv4rEH799Vfy9vbm5X6kpqZSjRo1OKfYadOmCVbvrl69yr1xSx1+Fy1aVKyfBN8MHTqUAFC1atXoxYsXgrc9RQoAIiJPT88vOsVWJAGwdu3aEn2bPn36RNbW1nTr1q3KIQBu3LhBRP965x8+fJh0dHQIgNzmP6XY2dkRAHJ0dCxT/BcvXvDii1CcAEhKSqIpU6aQ\");\n    result.append(\"SCSi6tWr04kTJ3i/YdevX6e6detyeQRAnTt3LrZDYgJA/jRo0KDYuhUXF0e1atUq1kHzeygoKOBGftatW8dd37lzJ/Xs2ZOioqKKFQju7u50+vRp3u7J4cOHuft/8uRJQevexIkTuY43OjqajIyMKDk5WdA0SOtkSdMzlUEA7N+/n7cRz/ImAN6+fUumpqaljrAeO3aM3NzcKocA6NGjB3l6elKjRo3IwcGBvLy8eBmCMzc3JwDk4uJSpvg5OTlcGvv37y93AaCiokLu7u7k4OBAAEhJSYk2b97MW4dTHHl5eRQcHEy6urpcXlVVVWnRokVMAPAsAHbu3MnNQ6elpXHXR48eTQsWLODFpnQZXLNmzbhrHTp0oKNHj1JhYSFZWloSAFq7di0R/es3Y2hoyKtn8tWrV0lZWZmbCvjw4YNgdS87O5sbeldRUaHNmzcL+tBMSUnhRkD4WPXwowiAjx8/koWFhdxFb3kdAaiIyNUJkA9cXFwIANna2pYp/rt377g0jhkzhrcRgIyMDKpduzYBoBEjRijk5qWlpdGkSZO45WBlWSf9IwqAEydOlFkA5ObmEgDKycnhTXwZGhoSAE5wZWVlUfXq1b+4R8G3cufOHa6sHz9+TCkpKWRgYMDtyTB79mwCQE2aNCEiojVr1tDo0aN57QAtLS0pPDycE6HDhg0TtO7v2bOHE2JCL0fz8PDgpiXludz0RxMARP/6oURERDAB8INS7rcCtrKyAgC8fv0ahYWFX4z/9u1b7u8GDRrwli5dXV0cPnwY6urq2Lp1K/bv389rOeTk5OD+/fsy16pXr46VK1ciNjYWdevWBQAsWbIEaWlpFWrLTQ0NDa4M6Au7LWZnZ0NZWRlVqlThJS1qamoYM2YMAGDDhg0Qi8XYvXs32rdvD0NDQ15sOjo6cnV53759OHDgAHr16gU1NTUAgI+PDwDg77//xuPHj7Fv3z4MGDCAl7RIJBL07dsXkydPRq9evRASEgIA2L59O86dOydYnahWrdq/W5n+\");\n    result.append(\"/85/QrFp0yacOXMGIpEIO3fuhJ6eXqXeDrdv3744ePAg2yO5Im8FrEi6dOkCAPj48SMePXr0xfixsbEAAGVlZXh4ePCatkaNGnFbtP7yyy9ISEjgzVZmZia2bt1abFi9evVw8uRJqKioQCwW4/bt2xWqktasWZPbfjM1NfWLW4WamJjw2imMHj0aVapUwevXr3Hw4EFs2rQJY8eO5bUMpJ18WFgYwsLCMHDgQC7Mzs4OLi4uAICgoCCkpqbCzc2Nl3RMnz4dxsbGGDduHABg2LBh6NChAwBgxIgRyMrKqrAPy4SEBEydOhUA4Ofnx+W7pHpYGejcuTPOnTsHiUTCelMmAORPjx49uA4gPDz8i/GPHTsGAOjXrx/MzMx4T9+YMWPQt29fZGVloU+fPrzuSX3s2LESR0FsbGxgZ2fHjU5UJGxtbaGlpQUAX9yDPCIiAs2aNeM1PQYGBvD29gYATJkyBQDQsmVLXm0OGDAAysrKePToEdLS0op08FJBsPe5hhUAACAASURBVGfPHvTr148XAXTo0CGcPXu2iBDdunUrtLW1kZSUxJVHRUMikWDgwIHIycmBnZ0dgoODS4wrFouxadOmStGBaGhowNXVFefPn2e96Y/I18wXJCcnc3ORsbGxgnqbAiAjI6NSt1hNSEggdXV1MjQ0lLtXsNQRTUdHp0hYZmYm2djYEADy9fXlpQykZV+So9+bN29IQ0ODbGxsBFmbm5WVxdWFK1eu8G4vICCA22ipJOe227dvk66uLsXExPCenri4OC7/GzduFKQdSLcG9vf3L3ZeXuqUd+fOHbnbvnHjBhkYGJS42kS6KREAQVbDSNujhoaGIGU/b948zulQugKqJLZs2UIrV66sFD4ARP/uOPnfnSGZD0AFdAL8+++/uUYu9KYb0g2BevbsWWwH8P79e3JxcaHq1at/sYF+C6tXr+bWgBfn8fzPP/9wa/QnT54sdw/sz8XXwIEDOQFWWFhIt27doiZNmpC+vr4gnR8R0YMHD7j0HDx4\");\n    result.append(\"kHd7ubm51KtXLwJArVu3psjISMrMzKSsrCy6desWTZs2jbS1tWnHjh2C1ckOHTqQjo6OYCtApI5vJe002LFjR6pfv77c7Z48eZL09PRKdfTLy8vj1ufr6enxviXuunXruPqXnp7Oq63r169z2xAHBQWVGC8jI4NCQ0NJS0uL1wNiypsA+PTpE5mbm3NOqUwAVDAB8OjRIwoKCiJra2uu0dWqVYsCAwMF63CI/l1nWatWLWrUqBHt3buX7ty5Qzdv3qQ1a9aQmZkZtWvXjp48eSJXmxcuXKAZM2Zw+xwAIFdXVwoODi4yyhAaGsrFMTc3Jz8/P3r9+rXcBMD48ePpxo0btGDBAnJ1dSVjY2OqWrUqWVhY0KhRowTZjOTZs2e0cOFCql+/PpdXExMTmjdvHi/C63MKCgpo586d1KFDBzI0NCQVFRXS1dUle3t7GjNmjOB7IZw5c0auK02+xMePH6lt27YlhoeFhdHixYvlZu/06dPUrl077j7XrFmT5s6dS7m5uTLxoqOjZXYlxP9vWT1q1KgiW/Z+L9HR0TRr1izuTAIA1LRpU1qyZAmlpqbyUu6f13VNTU3S0tIq8tHQ0JDJP19pKY8CgIho4MCBgu8HwQTA9yMiEuAQezkiFouxZ88eTJw4kXM4UldXx4ULF3hzfGIwGIzyQm5uLjQ0NNCuXbtKP/fesWNHnD17Fp8+feJt5Q9zAixHqKqqwtfXF5cuXYKpqSkAIC8vDxcvXmR3k8FgMBiMiioApDRq1Ah37txBnz59AACBgYE4deoUu6MMBoPBYFRkAQAA+vr6OHjwIKKjo+Hm5oZevXph1apVyM/PZ3eWwWAwGIxS+OF8AErj/v37OHToEJ4+fQpbW1u0b9+e9zXhDAaDISRSHwA1NTWZnQhv3LiBWrVqVei8v3jxAg0bNuT+n5mZCbFYXKF9AGJiYtC0adOv+s6VK1fK9J0KJQAYDAaDwWCUDSVWBAwGg8FgMAHAYDAYDAaDCQAGg8FgMBhMADAYDAaDwWAC\");\n    result.append(\"gMFgMBgMBhMADAaDwWAwmABgMBgMBoPBBACDwWAwGAwmABgMBoPBYDAB8EMQERGBLl26oGfPnqwwPiMjIwMrVqyAhYVFpTueVCwWY+nSpejQoQO0tbXRqFEj/PbbbxUyr7GxsRg6dCgsLS3LRXr69+8PQ0NDxMXFKcT+wIEDYWRkhHv37gli78aNGxgyZEi52O735cuX8Pf3h7GxMf755x/2EPxRoW/g2rVrpKGhQQDo4cOHVNEpLCykCRMmkLm5OQGg7t27E+Nfbt68SV5eXqSkpEQAKCIiotLkXSKRUPv27Sk0NJSIiK5evUpVqlQhAHT+/PkKldf169eTs7MzASBDQ8NykSZLS0sCQEeOHFGIfenzIDw8nHdbO3fupPbt2xMAql69ukLL/cqVK+Tj40MikYgA0O3bt9mD8AcF3/rFw4cPk0gkomXLllWawgoPD2cCoATc3NwqnQDYsGEDAaCsrCzu2u7du8nIyIj++uuvCpffx48flysB8OTJEzp9+rTC7MfHx9OJEyeosLBQEHvJycnlQgBIcXBwYALgB+ebpwB69+6NJUuW4Pjx45VmtKR69epsyKgEatSoUenyvH//fqiqqkJbW5u75uPjg+Tk5Ap5CmV5q/+1a9eGh4eHwuzb2Niga9euEIlEgtj7/OS/8kB5Sw9DYB+AGTNmwNHREW/evKkUhaWiosJqDCsbjocPH0JVVZXdY4YgKCsrs/Qw5Numv/cHNm3axEqRUSnJyMiAuro6KwgGg1H5RgAUQWFhIbZu3YrWrVujR48eqFu3Ln766SeEhYUJmo68vDzMnDkTRkZG0NHRgZeXF5KSkgSxnZubi8WLF8PV1RVNmjRB7dq18csvvyAlJUUQ++fPn4e7uzvatGkDNzc3+Pr64v3794KV/YcPHzBz5ky0aNECZmZmMDY2xvDhw5GamipIp29nZwc7OztIJBLk5ORw/x8xYoQg+d+5cyfc3d0xatQoODs7QyQSyXwCAgIEScfZs2fx008/QVNTEy1atMDj\");\n    result.append(\"x48FqwOJiYmYM2cOjI2NcfPmTcGfQ0lJSQgICICpqSn+/PNPhT0P8/LyMGDAAIhEIhgbG2PmzJmIioqqEJ2TRCLBkSNH8PPPP3Mrr44ePQoXFxdoa2ujTZs2XJ17+vQpPD09oaOjA1NTU2zcuFHu6bl8+TK8vb1hZ2cHALh48SKaN28OTU1NNG/eHAkJCYKUy6lTp9C5c2d07NgRNjY2cHNzw969e7/tx340p4Xx48cTALp37x4REWVnZ5O9vT0BoD///JNX25cvXyb8H3vnHRbV0TXw39JZmiAiRUFEVBCwK/auscbEGqxR7L2baDQx9tiiSey9RI1GjRpfe+81iqIIilIVkN5h5/vDZT9Q7OwicH/P4/PmnTvsmTt37p0zZ845A6JNmzaiZcuWon79+qJ169Yqz29bW1sREhKi1jbExsaKmjVrCm9vb5GWliaEEGL37t0CEI6OjiIuLk6t8lesWCFMTEzEqVOnVGVTpkwRgEacACMjI0W1atXEgQMHhBBCZGZmimXLlqnu/8WLFxobi9ra2sLIyEij43/ChAlCV1dX+Pn5CSGESEtLEw0aNBCA6NWrl0hISBAZGRlqkR0fH69yAly5cqXo0KGDWLRokWjTpo0AhKenp0b64MyZM6Jv376qMXf16lWNPoNLly6JgQMHqrzgz549qxG56enpuToBjhkzRjRt2lSjY18IIRo1aqRWJ8Dvv/9euLi4qByvp0+fLvr16ycWL14sPD09BSAqV64srl27JurVqyfmzp0rpk6dqopQO3PmTJ61ZdOmTaJbt24CEA4ODmLlypWiVatWYubMmaJFixYCENWqVVN7n0+bNk04OTmJwMBA1ZgYNmyYAIS3t7fmogDyCxMTE6Grq5ujbOrUqQIQc+bM0YgCULJkSXH+/Pkc3sC2trYCEF5eXmptQ8+ePUWpUqVEUlKSqiwlJUUj4Wc3btwQOjo6YsGCBTnKMzIyROnSpTWiAHh5eYmpU6e+Vu7m5iYA8fPPPxdaBeDevXtCJpOJ\");\n    result.append(\"pk2b5ig/ePCgAIS5ubla5WcpAHp6emL9+vU5nr+dnZ0ARHBwsMb6w93dPV8UgCxq1aqV7wrAhAkTRIcOHURKSorG71/dCoAQ/x955eDgIG7cuKEqT0xMFKampgIQI0eOVC2GhBBi/vz5AhDDhw/P07YEBQUJQBgaGuYY/+np6cLKykoA4vHjx2rri6NHjwpA/Pnnn6+Ni6zv39q1azUTBZBfjBkzhokTJ+YoMzExASApKUkjbfD09KRu3bqq/+/s7MzcuXMB2Lt3L+np6WqRGxISwrZt22jZsiWGhoaqcn19fU6ePMm6deto3Lix2u572rRpZGRk0L179xzl2traVK9eXe39/uLFC3bs2MHhw4fp2LFjjn96enpUqFBBI9sA+cWFCxcQQmBlZZWjvEqVKgBER0eTkpKi9naYm5vTt2/fHM/f1dVVNUY1RX5HJVhYWOTrVuigQYMIDg5m9+7dhdYXpVixYqoxXrVqVVW5XC5XjbnevXvncMZ1d3cHIDQ0NE/bkjXPWFlZ5Rj/Ojo6VK5cGYCwsDC19cXs2bMBaNasWY5yHR0dhg4dCsCcOXM+6DcLnFvvTz/9BEBaWho7d+5kz549BAUFqV6K/KJLly706dOHpKQkgoODcXR0VMsEoFAocs0E5unpqdbQs8TERA4fPoy+vj52dnavXdeER/D169fJzMxkzJgxfPPNNxQ1sia8V309siYiMzMzDAwM8qVtWQqpJhQQTY65z1G+EIIePXqwZ88e/P39C3V0xtv62MjISNUf2cl6B1JTUzXWFlNTU9W8pA4SEhI4derUGxXfhg0bAuDv7094eDjW1tbv9bsFMhXwunXrqF27NsnJyWzbto3evXvne5sMDAzeu9M/ZQWsbi3zTQQGBpKeno6WVv4Nmaz7f/ToEUWRVq1aYWdnx61bt4iPj1eVP3nyBICuXbvmW9uyYuHzUwkvKshkMkxMTFQOgBkZGVKnfCa8qozkFcHBwarfzvoOZqdUqVKq//4QS3iBUwD69+/P5MmT\");\n    result.append(\"+eeffxgwYMBnZfpSKBTo6elhY2Ojlt83MzNTWQLehLrykmdpv8nJyURERORL/2Yl3Nm/f/8b61y9erXQflwMDQ05dOgQJUuWZOrUqaoxN2vWLFxdXZk3b570BS4iLF26lCpVqnD27FkmT54sdUghJ+vbn13hz07WPKijo5OrhbZQKABnzpxh3bp1tG3b9rM4ECM7UVFRPHv2jFatWqnNDFujRg0AfHx8OHjw4GvXT58+rbaDURwdHVVm3rdNwOpcAWbtAV6+fJnt27e/dt3Hx4cTJ04U6g+BXC7H2NiYpKQkvv32W7y9vXF1deXSpUtSZrYihIGBAbt27cLMzIyFCxeyZ88eqVMKMTY2Njg7OwPk+qyzFmWtW7f+oEVxgVIAspw67ty5ozKHZGZmcvv2beD/93wiIyM13ra1a9eir6/PzJkz1SajXLlyNGnSRGUJOX/+vOra0aNHGTVqFO3bt1eLbH19fby8vICXzoCvbkMkJCQAL2P01YWtrS3t2rUDoG/fvvz222+qPefLly/To0cPjfkGCCFQKBRkZmZqbIwlJyfTokULvLy8WL16NevXr2fdunVMnjxZ5aCk7nvOizqabE9h4tX7dXJyYt26dar34cGDB/nansL+jN9ncaPO9k6aNAl4mQckMTHxtcWflpbWh1uDClIIYEBAgNDV1RWAaN68uZg4caKoVauW6Nq1qwCEk5OT6NmzpypHQF7j4+MjDAwMhFwuF6tWrVKFnuzatUtYWFiIffv2aaQPbGxsVDHQpUuXFpaWlkJXV1ecPn1arbKjoqJE+fLlBSDs7OzE0qVLxe7du0WvXr2Eg4ODAISbm5uYPn262g5ICQ4OVskChK6urjA2NhaAWL16tUbHYlYbnj9/rhGZd+/eFYDQ1tYWjo6OokKFCsLFxUW4ubkJT09PMWjQIFV+AHXw5MkTAQgjI6PXnm/Tpk01djJeFh4eHgIQR44cyZfvUdu2bTUaBph1GJC+vn6OXA8DBw4UgHB2dhbh4eEau/+sw4DU\");\n    result.append(\"GXqcFQbYqFGjN4ZhnjhxIkf5P//8IwBRr169PG3LgwcPBCCKFSv22vjPOqlRneNfoVCIXr16qfIixMTECCGEuH37trC3txfz5s0r/HkAtm7dKhwcHIRcLhcdOnQQgYGB4tGjR8LGxkZUqlRJXLhwQa3yAwMDxahRo4STk5OwsLAQlStXFr179xYPHjzQWB88ffpU9OzZU5ibmwtDQ0PRvHlzcenSJY3IjoyMFIMGDRKWlpbC0NBQNGvWTFy5ckV07txZNGnSROzcuVOkp6ertQ3Pnj0TgwcPFtbW1kJPT09UqVJF7Ny5U2P9P3/+fFUMOiDq1KkjFi9eLHx8fNQue+rUqcLW1lbY2NgIuVyuOoY565+5ubkICwvLc7l79+4VDRs2VMnp3LmzOHTokLh9+7YYP368KimOi4uLWLdundrzIYwYMULVFnd3d7Fhw4Z8UwCy5wRRF5s3bxZNmjRR3XO3bt3Ev//+K5KTk0WnTp1yLAhmz56tmhzUwcOHD8Xw4cNVMitVqiR+++23PJezcuVK4ezsLAChpaUlxo4dK27evCmuXr0qhgwZkuP5L1myRAghxIIFC1SLFC0tLTFq1CgREBDwyW3Zt2+faNy4sUpm9+7dxeHDh8WdO3fEhAkTVOO/YsWKYsWKFWpVAlatWiWqVasmihcvLqpVqya++OKLj1aCZaKo2dEkJAooERERfPPNN+zatUsVH51FSkoKgYGBDBo0CG9vb3r16iV1mJpp164dBw8e5L///sPDw0PqEIkCh5bUBRISBQMvLy+aNWv22uQPL53CKlasSJMmTYrk0cz5tSespaWllpwfEhKSAiAhIQHAtWvXOHbsGGfPnn1jsp3//vuPS5cu0bJlS6nD1EBMTEyO5DIJCQk0aNBAIw6YEhLqQDrgW0KiAODi4oKHhweHDh3C0dGRdu3aUaFCBeRyObGxsVy7do3IyEh27NghndOuBlJSUihbtiy6urr8+eefVKpUCT8/v7eGxEpIfO5IPgASEgVoElq5ciV/\");\n    result.append(\"/fUXPj4+JCYmYm5uTrVq1VQhkIU5LWx+M2DAAHbs2IFCoaBRo0b89NNPqtwcEhKSAiAhISEhISFRIJB8ACQkJCQkJCQFQEJCQkJCQqIoIG0YSkhISEhI5AOyrGM0JQuAhISEhISEhKQASEhISEhISEgKgISEhISEhISkAEhISEhISEhICoCEhISEhISEpABISEhISEhISAqAhISERGEmICCAX3/9lcTERI3J9Pb2ZsuWLRq9z/3797N//34yMzOlhy4pABISEhJFFyEE06ZNY9myZfTp0wcjI6NCfb/t2rVDW1ub1q1bExgYKA2AT0RKBCTxSZw9e5YGDRpIHSEhkQ/MnTuX8+fPc/z48SJxvzKZjDZt2pCamkqLFi24efMmxsbG0kCQLAASmubmzZusW7dO6ggJiXwgLi6On3/+mSZNmhS5e2/cuDH+/v6sWLFCGgiSAiChaVJSUhg0aBDSYZISEvnD9evXSU5OJioqqsjde9Y9nz17VhoIkgIgoUlSU1Pp1asXV69elTpDQiKfyEojf+vWrSJ371n3rKUlTWEaUQAUCgUHDx6kY8eOtG7dGiEEc+fOpXTp0sjlcr744gvu3bunkUbfuHGDLl26UKtWLcqXL0+dOnVYs2YNtWvX5tSpU2qXf+HCBfr06YOzszNCCCZMmICZmRnt27dHoVCoXf7Zs2dp06YNHTt2pHz58shkMooVK6aRvhdC0LdvX65duwbAP//8Q5UqVahSpQqhoaFqk7tgwQLc3NyQyWR4enqqys+fP0///v2RyWTIZDLu37+vFvl//PEHVlZWKjn9+/cnODhYdX337t24u7tjbm7OqlWr8kTmvn37cHBwUMmcOXMmAIcOHaJRo0aq8g4dOqhWQpmZmUycOBEtLS08PDy4c+dOnrRl165d1KhRQyXTw8ODu3fvkpqaSufOnZHJZFSrVo0jR46opf9nzJiBoaEhMpkMHR0dJk+eTGxsrOr6oUOHcHFxQV9fX9VPavlgamlhbm6Ou7u7atxXqVIF\");\n    result.append(\"U1NTZDIZ9vb2GrOKVahQAQAfH58iN3HdvXsXAFdXV2kW/8QP+nsxa9YsUblyZQGIZs2aiZEjR4oOHTqIAQMGCCsrKwEICwsL8eTJE6FO1qxZI6ytrcWpU6dUZVu2bBFaWloCECdPnlSr/GXLlok6deoIQNjZ2Ykff/xRfPnll0JbW1toa2uLyMhItcp/8OCBsLa2FiEhIUIIIRQKhZg1a5YwMzMTmmTPnj0CEH369NGYzAsXLghA1K5d+7Vrrq6uAhC+vr5qk3/z5k0hk8kEIF68ePHadW9vb7F+/fo8lXn37l2hpaUlDA0NRXp6uqo8ISFBWFpaCkD4+fnl+JukpCRRvHhx8fz58zxtS3JysqhVq5YAxNdff60q//XXX4Wnp6dITExU6/P/448/BCCsra1zvd6jRw8xZcoUtclPT08XlSpVEsnJyTnK79y5IwwMDIS2trY4c+aMRt9DGxsbYWFhIfKD/v37i82bN+eL7B9++EEAYvfu3aIgU2AUACGEOHr0qABEiRIlxNatW1XlISEhwt7eXgCie/fuauuss2fPCm1t7Vwfer169TSiAAghxJMnTwQgDAwMxO+//676UJ87d07tsmfOnCmsra1FRkaGqkyhUIi6desWegXA19f3jQpA1vNXpwIghBCtW7cWgNiyZctrk66rq6tIS0tTm8yjR4/mKB8zZowAxIIFC3KU7969WwwePFgt9x8QECCMjY0FII4cOSKCg4OFs7OzSiFVJwqFQnh4eAhAnD17Nse1lJQUYWVlJZ4+fao2+UlJSWL69Om5PndAzJgxQ+MTSLVq1XIoY0VFAThx4oQAxMWLFyUFQFM+AFnhFu7u7nh5eanKbW1t+emnn1Rmy7S0NLU0dtq0aRgbG9OxY8fXrllbW2us07LM7cbGxgwePFhliqpXr57aZaelpREeHk7//v2JiYlR7QVOmDBBMmdpgBEjRgDw+++/5yjfsWMHX3/9Nbq6unkus1+/fgBs2LAh1zG/evXqHOXr1q3D29tbLfdf\");\n    result.append(\"tmxZfvnlFwCGDRtG3759WbRoEba2thrZ8548eTLwMvzt1S2K2rVrU7p0abXJNzQ0ZMqUKTnKRo0axb1792jSpMlr19RNeHg4ERERr/VFUaBJkyZ069aNkydPakTe06dP6dixI3Z2dtSpU4cZM2bw4MGDXOuuW7eOR48eFa4tACGEuHjxomoL4FUiIyMFIADh7++f55pSXFyc0NbWFtWrV8/1eqdOnTRmAYiPj1dtAWgaf39/YWJiIgBhbm4upk6dmuemXskC8PZVqLOzswDEtWvXVOV169YVQUFBapGZmpoqLC0thVwuF7GxsUIIIdLS0kTlypVFjRo1BCBOnz4thBAiLCzsje9IXtKiRQsBiJYtW2p03GVkZAgnJycBiFu3bqnKGzRoIA4ePKjRtuzcuVMAwtLSUiMWkOx9cPbsWTFkyBBx7969fFu95qcFIGtLZuLEiWLZsmUiKipKre98o0aNxObNm4Wvr6/4+++/Ra9evYSxsbGoVauWWLp0qWrr+9atW6Jp06YiMzOz8FkA3kbx4sUxMTEBICMjI88bGhQURGZmplp+uyDh5OTElStXaNKkCdHR0cycOZNy5cqxZs0aaXmuAWQyGcOGDQNg2bJlwEunVGtra0qVKqUWmXp6evTo0YOkpCR27twJwNatW/nyyy8ZPnw4gMrxcOPGjfTt21ft/TB69GgATpw4oXII1QTa2toqa9fs2bMB8PX1JSgoiC+++EJj7Xjy5AkDBw5EJpOxYcMGjVhAsjh37hyLFy+mU6dOuLi4FNl3McsZNCgoSK1WEH9/f1q1akXPnj2pWLEiX331FZs2bSIsLIyhQ4eyb98+nJycMDQ0pHv37ixcuLDgRCfklQVACCGMjIyElpaWapWSl/j4+AhAmJqaFmkLQHaOHz+ucsrStENMflgA7t+/n+8WACGEiI2NFcbGxsLAwEBEREQIb29vcezYMbXKvH37tgBE/fr1hUKhEDVq1BDPnz8XiYmJwszMTBgYGIioqChRpUqVXB0U83r8\");\n    result.append(\"V61aVUyePFkAolKlSiIlJUVj4yAlJUXY2NgILS0t8eDBAzFy5Egxa9Ysja48sxyBx4wZk2/v/7x588TYsWOFQqEokhaAa9euiVatWomIiAi1yklOTn7N8fNV0tLSPqodBdICkFuoW0REBImJidSsWRNTU9M8b6ijoyM6OjrExcWxf//+Iqv1rly5ktTUVACaNm3KxYsXGTVqFACbNm0q1Peup6cH8NYDTzQRhmlqakrv3r1JSUlhwYIF3Lx5k2bNmqlVpru7O9WrV+fcuXMsWbKEmjVrUqJECeRyOT169CAlJYWhQ4dSqVIlzM3N1dqWYcOGMXLkSObMmcMXX3zB3bt3mT59usbGgb6+PqNHj0ahUDB9+nS2b99O//79NSZ/+vTpXLx4kerVq7+28nz48KHG2jFx4kT+/vtv1q9fX+S+g3FxcbRp04bhw4djaWmpVlkGBgYYGBi8tY6urq7a2/HZWABcXV1fu7Zq1SoBiF27dqlNE+vYsaMAhJOTk3j8+LGq3M/PT5QuXVrjFgAbGxuNa72TJk16TevOao86IzBe5eDBgwIQX375pRDipTe0ukNAExMThZaWlpDL5TnCLbdu3SrMzc1z9Q5XF/fu3ROAkMlk4tdff9WIzN9//10AQldXVzx8+FBVfvPmTZUV6MSJE2ptw+bNm4WXl5fq/wcFBQkTExOhra0tLly4oLHxFxcXJ4oVKyYA0aVLF41a3bS0tISJiUmOZ5DFTz/9pNHvgYeHh3BzcytyFoDly5dr9H1XFwVSAQDEmjVrVOUPHz4UdnZ2YsCAAWrtrEePHqlinw0NDUWbNm1E27ZthZeXl/jyyy81pgCEhoYKQOjp6Yn4+HiNKwBmZmY54o2PHDkidHV1NfoyZJnj5XK5+PXXX0Xnzp1FeHi42uVmOZ9VqFBBjBw5UtSvX1/MnDlTtQVQs2ZNMXfuXI30QfPmzYWRkZGIiYnRiLzo6GhhYGAgOnfu/Nq1GjVqCCcnJ7Wag2/duiVsbGxEdHR0jvKZM2cK\");\n    result.append(\"QJQtW/a1a+pkypQpAhDHjx/XiLyIiAhha2srgBxh0Fn4+/uLNm3aaHQrQl9fXxgZGRU5BWDixIkCEMuXL5cUAE0rAJ6enmLo0KGibdu2olmzZqJWrVrijz/+0MhelJ+fn2jXrp2Qy+WiVKlSYtasWSIjI0NjPgA7d+4UDRo0UClCnp6eYtu2bRpVobhQ7AAAIABJREFUALJkV6lSRXTs2FG0bdtWXL58WeODd9q0acLY2Fi4u7trJAeCEC9zTrRo0UIYGBgIFxcXVd83atRIdOjQQfzvf//T2J7ovn37xMCBAzXa515eXrk+65UrV4rZs2erTe6uXbuEpaWl0NbWzhHvfufOnRx+KG5ubmL79u0a6YurV6+K8uXLa7TvsywwtWvXzvHP3d1d6OnpiVatWmmsPVl+Ic7OzkVOAViyZIkAhLe3t6QAfC5OgPmJJp0AJSQk8p9x48aJhQsXFtn7P3z4sMa3QD4XBeD06dMC0KjFpTAqADpSYJeEhERBIyEhge3bt3P79u0i2wclS5YEimY+/KzwR00mgCuMfJACkKWwiM/wCFghHUsrIVGoOXjwIHp6ejRs2JBJkybRrVs3LCwsimx/eHh44OHhQVJSUpG79+TkZAB69eolvRiaUgCyTt/KfgrX50J0dPRn2zYJCYlP4+zZs7Rr1w54eSJfxYoVOXfuXJHuE5lMxubNm+nSpQujRo3Czs6uyNz7rFmzmDRpEo0bN5Zejk/gvfIApKSkMH36dFW8+fXr1xkwYACnT5/O9xu4c+cO48ePV7Vl0qRJRTI3toREYcbNzY2aNWtiZmaGl5cXJ0+eVHu+g4JiBTh48CA///wzv/zyiypHSGHl1KlTDB06lDp16kjf+bxQIoVkO5eQkJAo8CQmJqKvr4+OTuF17YqLi1NLorl8m4BlMpmkAEhISEhISBS1FXg+KwBa0iOQkJCQkJAoeuigdJ7LN44dk55CfqI8RU4in1YA0vjPV0Tz5vnbgIEDP+v+2XbuHF7166tPQH73f5FX\");\n    result.append(\"ACQKHQkpKbiPG8f+yZNxK11a6pACir2BAWPs7elcsiSl9PVV5c/T0lgTEsLswEASMzMB6GRlxTfW1nSysgLgbmIiO589Y8ajR5J8iY9CIQSXHz5UrwIgka9IWwCFUavT1iYyPh4dLenxFmSepqQwxs+PcufPs/3ZM1X5prAwpgQEqCY/gN3PnzPI1xeA34OCqHrp0idPfkVdflEn8PlzyigVKglJAZAoAAgh0NfRYXLHjlS0s0Mh+XgWeFIVCnr5+HBGuV3X28aGYrl4ev9Ytiw7nj1j+IMHpOfhcy/q8osqviEhuHzmuQWCQ0P5dvhwho4fT8uvv6bX4MFkZGQwf+lSflm2jAZt2nD91i0A/vPxYdbChXw3YwZf9epFkjKZkKQASBQKMhUKrLy9qTJxIn5hYXSYNw8DLy+uSyuhAk+GEHj5+BCdno6Vnh6Ly5fPcb17yZI0Mjen3717knyJPFUANp0+Tc3vvkPWtSu633zD8iNHVHX+vnwZK29vKo4ezZazZ4lNSmLB/v3YDhqErGtXHIcN46gyXXNSaiqLDhxA1rUrrWfP5qzSYvMplLK1pUzp0jzw92fPli38MGECKzdsoLyTExNGjKB39+4MGD2a5JQUhk+cyKRRo5gzbRrp6en4PnggKQDSMC88aGtpcX3ePG7On09iSgo7x47l4dKlVHV0lDqnEBCSmsoI5Uerr60trYsXB8DN2JhF5cvT6fZtkrKZxSX574dfUhLf3ruH7NgxfnnyJNc6cRkZmJ48ieP58+yLiMA/KYnRfn7Ijh2j4bVr9Lt3jxpXrjAnMBABvEhPZ01ICNrHj1PhwgW8792j7tWrDPT1JTo9vUCMt6eRkdhbWtK7USPOzphBHaXS1bpqVVWdxpUq4VqqFJdnz6ZngwaYyeWMb9+e8z//jIWxMfq6ujR1cwNArq9PDScnejZowKHvv6eBMp//p2JkZIS7qytGcjnlnZz43/HjPHz0iA3bthETG4ujgwPXb93CSC5X5Ug4sH071atUkRQA\");\n    result.append(\"6bNauLC3tORJRAS7L1/m1N27OJQogVb+hppK5CFbw8PZ8/w5AKtcXbE3MOBvDw+GPXjAQw3khC+M8svL5XxfpgyGWlosffo01+2DNaGhZAhBcwsLvixRgnJyOcNLlQJghpMT61xdWV6xIlP8/Zn9+DEWurp429lho6fHN9bWrHF15VDVqvwbGUnXO3c+u3EVFBVF6iuKiUKhICtM3UBXlz9HjUKup8ewNWuAl9uNw9auZcWAAZjJ5Tn+1tHKirVDhvAgNJRFBw4AEBUfz/x9+1g1aJB6rWUZGVTz8KCvlxcTRoxg26pVKBQK/AICcpwZ8ywiQlIApE9q4aNMiRIYGxjgbm8vdUYhZPD9+0Smp1NKX587np7sjYhQTYqS/I9DVybjG2trwtPS2B4enuNaphCciY7Gw8QE7WzlOq8o1jVNTXEzNubPbH+fvY6Zjg5fW1lx7MULIt/TCrBNzecdRMXHM3bjRtrPncvaEydyXHs1R41DiRL80qsX/968ybZz55i7dy/tq1en4hv8BDrWrMk39eoxfedOHoaFMXj1ahb27o2hnl6e34dCoVD9d7NGjRj13Xdcv3WLp8HBLFmxgqoeHsTFxzN70SKSkpPZsWcPzyUF4O0KwNPgYMZMmUJpNzdkFhaqfyUrVGDKzJkkZtO4d+/fT+c+fVR13OrWZcb8+QW6c6ITExm7cSNlhw/HpHdv7AYNovuSJey9epVz9+/z8+7dn6V8mUxGQxcX7N7jpLSkzExmPn5MtcuXkR07huzYMXrfvfvebVwbGqr6O+cLF5jx6BF+H7kSO/HiBd/5+2N+6pTqN7WPH6fkmTOYnjyJw7lztLl5k7+ePaMou3g9T0tjiHL/1FRHR+UcJ8n/NEobGNDZyoqFT5/mKN8TEcFXH+ANb/KOVLxaMhlG2trvntSUYXjqRFdHh/EdOrB34kQWHjhAWkYGAOExMdjkctbCwObNaebuzrC1awmKinpniOCyfv0wMTSkztSpfFWrFhVsbXO+82fO0GPgQPRK\");\n    result.append(\"lswxx/QbMYKb2Y56PnHmDL0GD1Zd92zRgrVbthD+/DlnLlzg1Llz+Pr5ATBy4EDq1a5Ns44d+bJHD9q0aIGJsTHb165l/bZtlKlcmZjYWNyVxyhHx8Tw3YwZ/LJsGTWbNSMhMZEvOnemWceOxMTG0mvwYKo0bEhwaChBISE0bNuWsGfPOHXuHIv++IPWXbqw8c8/AUhNTWXukiX8NG8eX3TuTHRMDMvXraN+69YsXbkSBw8PegwcmENh+WwVAPtSpVg8axb+16/T/euvVeW9u3Vj1tSpGGUz+3Rq356VixcDMMzbm5unTzNt4sQC+5ENj4mhxuTJnPH1Zde4ccRt3IjvkiU0d3fHe8UKGkybRqYaH+Knyq9Wtux7yZFrazPV0ZHTNWqgrwwb3B4eTlBKyjv/VgCLsu2Zbq5UiWlly1L+FXPg+9LUwoI55coxw8lJ9XGPb9yYZw0b8rxRI6aXLcvZmBi63rnDt3fvFmklICQ1lUylOXO5iwumGs7/Xljlj3Nw4L/4eI69eKEq2x4ezjclS77zb4+/eIFPQgKD3rAiDktNZeezZ/SytsbwPUJ0NRGGZ2poiK25OWVKlKChiwsbTp0C3h4BML9nT2ISE4lOTHzn7xc3MWHSl18SFR9PfC5e900bNmTrqlVcOXaM4soFi4W5OeuWLaOqh0eOeisWLQLguzFjuHD4MP179sTayop/tm3j9rlzuCh9FPT09Fi5eDExgYHcPH1aNdE3b9QI/+vXee7nx6C+fVW/fejYMUqWKMGEESMYM2QIxkZGzJk2jeiYGIqZmfHjpEm8iI7G1toaPT09Bvbpg5mpKWu3bGHs0KGsXLyYYRMmEBcfz9JVq2hUrx7TJ03C1saGxcuX06ppU/wCAmjbsiV3zp/n7MWL7Prnn89fAchCX1+fzStW0LBuXQA27dhBTC7H7v44bx7dvvqK3+bPR1dX970acD8khGk7dmDl7Y2sa1e0u3VjxLp1HPnvP1WdP8+fp/uSJci6dkXWtSsVRo1i7t69\");\n    result.append(\"PFfj0b/jN2/mSUQE+ydNopqjIzKZDFNDQ7ybNePK7NlYGBur9cF8qvzSSgep9161aGtjp6+PsbY26UKw+JVVUG78GxnJ02yKQikDgzy5d3vl78iUCgqAgZYW/WxtWVKhAgAbw8LYkS02vChRUk+PbW5udLtzh9iMDErp67PoFa94Sf7HUcPUlAbFirFAqdheiYujmokJem+ZsPdGRDDz8WO2hoezt3Jl+r6yyr0aF8eip0+ZGhDAd2XKsEY5Ib0LTYfhff/VV8zft4+MzEx8g4NzlS2EYNGBA4xs3Zrt58+z//r1t/5mVHw85x88oHXVqkzcsoXgqKhc61Vxd2fH2rXIZDJeREezc+/e1+rMXbKEbl99xewffkArD3OceNaowc8LFtB/xAgaKy0aVT08SE1N5YG/P9f/+w8Lc3NOnz/PP4cO8WWbNty+e5eIyEg2bNvGiTNnaNGkCVEvXnD89Gn+8/Fhw7ZtlCxRAkMDA/T09DA1McHJ0RFTExM6d+jA1Rs3Co4CAKCjo8O21asxL1aM5xERjJkyJcf17X//zenz51n3228f1ICKdnbM6NaNKUoLQ5tq1VjWrx8tK1dW1fmmXj22jx6No1IbXj5gAJM7dsTKzExtHXPg+nUsjI1zNYOVLVmSSV9+qdYH86nyLU1MPtwcKJPhrXzpV4eEEKM0B76JBU+eMCDbR0Inj5wNtd/yO31tbFSWih2v7NV+DPcTExl2/z6yY8do/paXMjQ1Fb3jx7E8fZr1oaGEpKayJiQEk5MnMT55ko7//cdX//2Hy8WLjPbzU5s3vI5Mxg53dxY9fcru588ZpzR79re1peUHKn2S/NwZ6+DA4agofBISWBEczCCls9+b6FiiBFMdHVnn6kqHEiVeu17T1JSx9vasdXVllL39e78nmg7Dc7axoWa5cmw6cwb/8HCcrK1fn4T37qVT7dos6tOHao6ODFm9mtg3bPkJIRi+bh0LevVi5cCBKIRgiNKBMDeaNWrESKWD4NgpU4hPSFBdO3n2\");\n    result.append(\"LDv37GH1r7/m+ZhyKF2aO+fPk5ScTLVGjVSLW6/Ondm+ezchYWGMGjSIzTt3Ep+QgImxMRkZGRgZGdHXy4u+Xl7s2bwZW2trMjIzqVe7Nn29vJgzbRpjhw59TZ6FuTmmH/F9zlcFAMDOxoZl8+YBsGHbNg4p85j7+PoydsoUdm/ciNzQ8KMakrWiNXuL+dhU+dvmRkZq7xghBBFxcWw8fTrX613q1Pms5Zt85HPwsrbGTl+fhMxM/ggKemO9G/Hx3EtMpLeNjUYHrLZMpkoLG5kH4VQVjYxYUqECOjIZx1+84L/4+Fzr/R4cjIKX2xTf2tpip6+Pt50dnmZmVDQyYm/lyuypXJnVLi78FhREXzXFo893diYsLY1lymezNjSUo0pz9WoXF0zeY29Zkv92OlhaUk4uZ/zDhxhpa1P8Pa2ZeU1+hOFN+fpr5uzZQ3JaGrqv9OXJu3eJjI/nq1q10NbSYs3gwTyLjWXC5s25tn/m33/TtU4dHK2sKF28OHO8vDhw/fpbHRtnTZ1KGXt7QsLCmDJzJgDPIyL4dvhwtq5ahYkaLK+7/vkHYyMj/lyzhspubjxWWn+8Onfm97VrqV65Mp06dGDfv/9SXrk96VGpEqfPn2f91q08i4jgj7VrSUpOplHdugwdP56HAQH4+Pry1759ACQkJKgiEHz9/GjbsmXBUwAAenTpwlft2gEwcPRongYH83Xv3vz+yy84KzvnY/iQUxE1cYJi1kvW748/mLx1K8lpaTmuO1pZ8YUa40g/VX6LbPtnH2oFGKmMHlgaFETqG/wMfgkMZHjp0hhoON1wikJBmLIv3PLoY6Ark9HE3BwLXd3XHMAAkhUKrsTGUsbAAL1Xxp7+K/dfv1gxqpmYsOf5c9UedV7RtWRJWhUvzoBXlIsB9+6RkJmJvYEBC9Voii/M8jOEIEP5vLRkMkaVLs2RqCiGZztLIzNbnay/yf6/7/rdt/G5hOG5lS6Nu709EXFxOcofhIYyY9cu5nh5qcqqOjoyuEULVh8/\");\n    result.append(\"zr83b+acVC9dIuTFC76qVUtVNrRVKzwcHBixbt0btwKM5HLVXv/va9Zw5cYNeg0ezPABA6iRTfHJS+ITEmjbrRu/r1lDtcqVqeLu/rIPHRzo1L49DevWxdTEhG5ffUWrpk1fLkZNTNi0fDk/zZ9PlQYNKGllhXmxYowbPhw7GxuqN2nCdzNm0LFtWwBS09JY8Ntv/L5mDXVr1aJaNgt3gVIAAFYsXIhl8eIEh4biXq8eHdu0USkFhYVFffrgUKIECiGYt28fFUePZsOpUzlS63o6OxdK+YPs7DDV0eFZWhobw8JeX5mkpPBvVBRD32EaVQcLnjwhKTMTPS0txuZhmKNcW5tBdnZsDw8nNDU1x7XNYWH0+gBLR0xGBiX09N66lfGh1DA15bcKFeh8+zYJr2wvPElJYbK//8vJ0M6O9paWed7vhVm+f1ISvwYFcTAyUuX8962tLT1tbKggl5OUmcmWsDDuJSZyPDpalQhoqdIKsS40lFuvWI5epKezMiSEsLQ0DkZGcuQNE97nGIY3tVMnXJTvdlJqKjN27aLmd9/xLCaGG48fq+r5hYXxWBl++c2SJczft497wcEMXLmSbosX8zw2lsBsoXZn7t0jOS2NFwkJNP/55zdaAlo1bUrPrl1RKBQ079gRgHHDhqntm+Ldqxdn//2XYd7ezJk2LUe/L1+4UPXffyxYkMO3rU2LFgT+9x9h9+/TqX37l98RQ0O2r11L3NOn7P/zT4yV1uriFhZMGDGCYd7eDPP2/mzmuY9SAKxKlFB1TFx8vMo5sDBha27OpVmzVCvxp5GRfPvHH3iMH8+hV7TdwibfTEdHtbe/8MmT184TWPz0Kb1tbDRqGg1KSWH8w4dMCwiguK4uu9zdcf7IaIM3kbXaW5Zt60MAO549o/t7eIGnC8H0R494kpLyWqraT6GdpSVHqlbln8hIfN/geb06JET1nDZWqoRrHm6TFXb55eRyllWowM3atWmu9EQ30tZmU6VKKuWwp40NiU2a8LhePVUioKUV\");\n    result.append(\"KiCaN2ebmxtVXtnTtdDVZZCdHZnNmnGzdu03+ifkdxheblRzdGRAs2Yv711fn2mdOxO3cSP3Fi/Osegob2PDgcmTETt3ErtxIxO//BLXUqVYNWgQmTt28Pf48ZTJ5hPRuFIl/H79FbFzJ/eXLHlr25fMnk0JS0viExJoWLeuRqy+RZGPtt/a2digrdwjGjJuHHFv2Dv9UA7fuoXnlCm5/nuYB05fH4J1sWL8+913/D1+PM7KFeDdoCDazJlDt8WLSXiPULmCKn+0vT26Mhl+SUnszabFx2ZksCE0lDEaSDKUmJlJq5s3cbt4Eftz51j89CnLXVwIrF+f9rk4W32y0qWvTzdra1aGhKhOmjscFUUTc/O3eoGHpKQw8sEDSp45w6noaO56etLtPRSGd9HG0pJj1aqxv0oVzHV1aW9pyc9OTq9tOzQoVoytbm6qjI/murpcqVWL5RUrUu4TlKSiLl8T5HcY3puwV4MV50MwNDSkuFIBmr1okWpfvqChUCjY/c8/hD97xvnLlz+79n1U8OyziAi8Bgxgx7p19B8xguDQUMZOmcKapUs/uUGtqlRhy4gRuV6rMmEC/+XDQPiqVi3aVa/OqmPH+HHnTiLj49l58SLP4+I4Pm2a2lPt5of8UsrJcEtYGPOfPOFrZQTGiuBgWhQvTtmPdDL8EIy0tTlctSqxGRlUu3yZR8nJXI+Le2OcdV4wxt6eLWFhrA8NZXjp0qwMDmb1O8K27AwMWFqhAulCsDksLM9WK/9GRvJvZOQ7652NieFsTEye90VRl69pvv/qK1rPnk2/Jk3wDQ5WOe9lJ3sY3tJDh/CqX5/21au/8TdfDcNrW60apfIwWiM+ORn38eOZ8vXXKqtBnljjJk6kS8eOHDt1iotXrzJk3Dj+t2tXwVtha2kxavBgRg0eXDgsABkZGXTr14+xQ4fSqX17Fio9Nddu2cKRkycLjWnkWkBATlOdtjbDWrXCb+lSvqxZE4BTd++y/9q1QikfYIKDAwCXY2M5Ex1NuhAs\");\n    result.append(\"CwpivLJcU5jp6PCXhwf6WlqsDgnJkWo1r6lmYkJDc3N+DQrCJyEBKz09LN9zq2OBszPWenr0vXtXOoZZ4oPJ7zC8j0FXR4fYpKQ8XYRs27WLhwEBTJ84kZWLF6Ojo8PhEyf4U82ZV4siH6wATJw+HZuSJRkxcCAA/Xv2pEXjxgAMGDUqR+xmQWah0nP2VcyNjNgxejTllSb5K0rno8ImH8DD2Fi1dzn/yRO2hYdTTi6nlqmpxp9HNRMTVbKXQb6+aj14Zqy9Pf5JSXS5c4dRH7DVYaStzYZKlbgQG8ui90ikJFEwOR8TQ6fbt5EdO4bF6dMcVzoOvkhPZ7K/PyYnTzIvMJC4d+TRyI38DsP7UAx0dRncogXd69XLk997GBDAdzNmsG31arS1tXF3dVXF0o/5/nuiC4Glp8AqADv37uXwiROvJWNY/euvGBsZ8TQ4mHFTp2qs8clpaUzYvBlZ1670/f13YpR7Yg9CQ3EYOpSJW7YQl5zMF7NmMWr9eqZu387U7dtxGzcOt3HjSH9Lspb/AgPxf8NKU19XV5WoKCv8ZtelS7iNG4esa1cmbtlCUmoqCiFYc/w4Zn368Pvhw6+F8r2ND5WvLrJW+/9GRvJDQMB7r/53PX+O28WLyI4dY+LDhyRlZr7sj5AQzE6d4vegIJI/MJXy0FKl6FayJPGZmXS9c4eUV/7+UXIykx4+ROvYMUqfPavyzA5ITqbhtWu0vXWLm7n4qmQKkSNxT3tLS5wMDXEwMMjhTJYmxGthkakKBSnZ/rZ+sWKMs7fne39/LqgxU6VE/lGvWDF2e3jQw9qalMxMVeprC11dZMDeypWZVKbMR6Unzu8wvPflf7duoe/lRbG+fbn+6BHt585Fq1s3Gk6f/tG/mZqaSrf+/Vkyezals23zTZ80iTL29jyLiGDiJ/x+XhEdE8PcJUvQtbKiVrNmBIWEAPDH2rU4eHhw4PDhwqcAXLt5k+ETJ7Jr40ZVaEMWDqVLM1f5YFZv2sT+//3vgxuSlSRBvMV0\");\n    result.append(\"+qpZ1VBPj1969aK5uzs62toUU7arTIkStK9enfk9e6rS5/767bfM7N6db5s04dGzZ6wYMOA1DftVWSPXr881375QHtKhp6NDJ09PADp7enL6xx+xt7QkJjERub4+WjIZkfHxHJg8mWGtWn3QKVgfKj8vyBCCV6W1sLCgiokJAjDW1qbtK85B2WOcsz+fzlZWnK5RA3sDA2IyMpBra7/sj/R0DlSpwrDSpd+YDz3rN3Mzo692dcVZLudWfDzD7t/Pca2soSHznJ2Z7+xMZHq66gNsoq1NebmcfypXpuor3toPkpL43t+fS7GxrA0NJSYj42UcuL09o5Wr/+DUVBY8eUJQSgono6PZoMwEuCokhEuxsdxPSuK3oCDClOGDPzs5UV4up9WNG3zv70/IK2GFEoWDFS4ulNTXZ4hyHB6MjMRCV5dm73EI19vI7zC896GctTWj2rTh3uLF1K1QgWPTprF+6FA6f8L3aMj48dSsWvW1kHK5oaEqAd2azZs5qnSUzC/MixVj8ujRzP7hB8KfP6eE8puYkJjIvzt30q5VqwIzhmXixYt3blYeOHyY3kOG8HW7dm909EtLS8PQ1haFQoF5sWKcO3QIV2Xe9reizCa46MABxm3aROuqVfn3u+9yrWo9YADPYmM5Pm1aDgeZe8HBVJs0iatz5uBub8+Sgwf5smZNVerg+ORkVWa8VrNmYWdhwbohQ97arIqjR/MgNJRa5coxs3t3mlSqhI62NqHR0Xy/bRtbzp5l5cCB9FcmhlC9ZL6+NPnxR47+8AOZCgUPw8IY+hED4kPl77p0iR//+ou7QUFM6NCBH7t0wUBPj3UnTjBu0yZme3nRr0mT15WQVauAlyFs5qdOsd3dnXavTPJbw8Pp6ePDWldX+r0SRvRvZCRtb90C4HKtWq9tD5yJjqbJjRscrVqVTOBhUtI78wf8+vQpo/38kAExjRu/tpL6Lz4ez6tXSVEoGGtvzzxn5xzpVQXQ8sYNMoTgSLVqDPH1ZUH58hTT8IE17/UC\");\n    result.append(\"Ksc/QDMLC9a5uhKSmso/yg+3oZYWPW1scDp/nmomJiytUAFnuZw1ISEU19OjkpERPwQEcEp5It771HkXnmZm9Le1JSg1lVSFArmWFpZ6eiwLCkJPJmOeszNVTUxYotzm0JbJ6GJlxbf37uVqYXkXJtratCtRgm1ubmwND8dHuY1op6+Pnb4+X9++zRfFizPP2ZlRDx5wPS7unfXfe+HRvPknPb/jL17Q/MYN5pQrh29iIhsqVeKDdsOVW6mvkpUF8HMnPjmZiqNHs6B3b775mG2A5s1JTklh7JQprFi/niAfH0q9IVSxhLMzkVFRWFtZceX48RxWgvwgMzOTGk2b0rFNG9p/8QUXrlxh+IABH/b+W1jka3yj9o+TJv34pov/Hj3KkPHjmbVwISkpKYSEhREXH0+9WrXQyfYxPXvxIpN+/JG7Sk04JSWFjX/+SVBICBWdnbHIJZ5VtQI7d471J0+y6MABElJSePTsGRFxcejr6lJWGUr118WLzN27l4vKvN9X/P1JSU/H2cYGI319Spia8jwujq1nz9K6alUu+PmpHOWyTOYA28+fZ+2JE+ybOBG5Mp3sm7j5+DGbRozAwtiYzWfOMHnbNmb9/Tcrjx7Fulgx1g4ZQocaNV77O4cSJXiRkMD8f/5BIQQ/dunyUQ/mQ+W7lipFt7p12X7hAqUsLPi6dm1kMhlHbt9mcseOdPb0zNXikXTlCouDgpgeEMDDpCQuxMQQl5GBqY4ONso+cjUy4nBUFIvLl1dNtHeUedJ/fvxYtdd5LiaG2IwMrPX1VTkCHAwNeZGeznxlPoEf33JK4YkXL1gZEsL8wEDSlKv/M9HRRGVk4CSXY6xsv7W+PiX19NgfGcnF2Fg2hoXxKDmZqiZD1imsAAAgAElEQVQmmOjoIAMam5vzQ0AAh6OimF62LI4aiFr4GH569Ej134+Tk2lqbs79xES+DwjgXEwMp6KjScjM5GZ8PGFpaZQ2MMBSVxcvHx8OREbiLJezuHx5fg8OJlWZJfFddd5G\");\n    result.append(\"JysrFleoQC8fHw5FRXE+JobT0dF4WVvjk5DAtfh4SurpUcHICC8fH84pPfBPREdjrqub43Co9yVNCHwSEhhnb8+8wEBWhYRwLiaGQ1FRGGlrczM+Hv/kZL4vU4Y9ERH4JSW9s/778uN7npr5JsoaGhKamsr8J0/Y7u5OiQ896/4NHvxmn3n4YnZFZfaePTjb2NBcmUHvQ1h8+DB9hg7lmHJV/yQoiNJ2djkm9/sPHzL5p59UYXQJiYls3rmTZ8+fU9/TE718StWspaWFR6VKDB47lpSUFGZ8//0HRwD9NG/eT5+9BUCtZFsBfdK+TGIi5UeOpKqjIzvHjFFtB2QRp9RUf+7W7bVVe14Tm5SE9YAB9GvalN/799dod36wBUJpAVBrf2RkYH3mDP1sbfm9YkWN9cX3/v4sDQrCx9OTMvmoADxKTmbiw4dEpqfzv6pVCUhO5oeAAJZVqECps2dz1N1buTLBKSkMf/BAVWaopaXyl5jq6Eg7S0s8r14FXqbH3eHuToULF/BTOka+T53cMNXR4Wn9+gz29WX7KyctltTTw9XIiJPR0Yy2t8fbzg63ixdz1Mnezo8hpnFjvO/dY5fSrP3qb96vW5fBvr4qS8a76mvCAgAwJSCANSEhNDY3Z8eHToJvsAAUFBRCYNyrF6sHDaJHgwYfZQEo6DTr2BEzU1P+3rTpwyfgfLYAaFFIMDcyom/jxpQqXvy1yR/g+23bKGtlRb8mTdTell/++YfFffuy4sgRzrxy4pa6aejiwvAvvqDf8uXsvXr1o7Yf8rw/njxhcfnyrAgJ4cx7mqHzYtLNEIKapqZ4a/gZ5LZK3OLmRlxGBgHJyRx/8YJtbm7YvcMKBS8jMSq8IaudXFsbbzs7TkZHvzEq4n3qZNHe0hIzHR2O5/KMnqWlcfINz05HJuMba2uSFQqqm5pypFo1Zjk5cb5GDba5ufF9mTL41a1Lf1tbIhs1wuM9z3DobWPzQZN5Vn0DLa3XZI53cOBenToMLlWKwPr1c5xi+Sns\");\n    result.append(\"i4iglL4+K11c2PnsGfuy7bkXBbRkMlzs7HDXQGKwz5Hzly/Tunlzjp48WSDD4HUK08PQ19XNNR71WkAAa06c4OqcOSoTTaZCwYuEBErkcUjbn+fPU9nBgS516nDz8WP6L1/O7QULPsgB8FOZ0a0bq/LIsvLJ/REeTmVjY7qULMnN+Hj6+/py29PzjQ6AeUGyQsHMx4/5o2JFQlJT8bh0idUhIXn20f8YDLS0WO3iwhc3bnCyevW3HqJUzdSUyWXKqCbWHj4+Oa6X0NPjuzJlGOvgwKzHj/kjOJhXzXjvU+dVsqwkUe8RrWKpq8vkMmVeKp3FinFEGQp3PS6OVIWC0gYGtLh5k1L6+pjo6DCtbFkuxMbS4No1Hr0lI11HKyvKyeUYaWvT09qaTbmcRfGu+ikKBYdfvMgh83FyMj84OpKmUFD36tX3OqDnfZTM/0VFsVxp1epkZcXQ+/dpZG7+WfqbqIty1taUUfpbFSXiExLYe/Agv8yYQUZGBiMnTeLO+fM5zgv47BW4wvRAFEK85jmeqVAwePVqRrZunUNLPXTz5munb30q1x894vaTJ6qjen/p1YuU9HTGbtyo2RV3PlogcvRHXBy3ExLoovTl+MXZmZTMTMYqfTnUgQDGPHjAD46OGGhp4WRoyEwnJ8b5+eGvxtwB77taqmFqyu5sJuvcuBEXx9zAQGY+fkzPVyZ/gIi0NOYEBnI1NpZ6xYqRlssq+X3qvEq4MlrB7D0mr8j0dOYGBjI3MJCOt2/zPJvSkJiZyY34eJIyM/FLSiIxM5MUhQLfxER8ExPf6oew9/lz5gYG8kNAADOyebx/aP1XZaYoFCQrFNyIjyc0NTVHez+GmIwMxvj58Uu23Pi/VaxIXEbGa9EphR0rMzNMDAyKnAIwfc4cJo4cCcDYoUPJyMzkl2XLCpYFp7A8DN+QEE7dvcsVf39uBQaqylcdO8b1R49Iz8xU5QEYtX49w9ety7OUmEmpqSzcv5+mP/2EhbGxKpTxeWwsNsWKseLoUSZv\");\n    result.append(\"3Uq4BpJYZFkgBrdogXezZvRfvvyD8g/kSX9kZrLwyROa3riBha6uauX5PC0NG319VgQHM9nfn/A8btfVuDha3bjBhdjYHEfxagHxmZm0u3WLw58Y//yxRKWnczM+nu3u7mx/9uyNh9q8ys34eG7Fx2OUiwNnv3v3aGxu/taTCt+nThZHX7wgVaGgxRveC+s3WLHSFAq2hYfn2sZPYX1oKMB7/+6H1v9YtoSFqVJTP85mzbibkIC+lhbbwsMZ5Oub41phxsbcvEgd1vM0OBivAQM4feECqcpvWERUFFaWlvw4bx4r1q9H8Qm+MJqk0NipXOzsuKBMS5ydIS1bMqRly9fKf/322zyTLdfXZ1z79oxTHgmZ3TR2Zc4cza24lRaIrGQhv/TqRaWxYxm7cSPLPzA85ZP6Q1ubcQ4OjHslaVA5uZwr2RKT5DU1lfvPrzLK3v6DMvrlNbcTEhj14AFb3NzQ19KivaUl3e7cYVsuud5z+4yW1NOjZfHibA4LQ0smU21zhaelMdDXlw2urlyOjVU5+L1PnVw/bCkpzHz8mPnOzlyNi8sxgX1jbc0JpZk/tzZqy2QMtLNjsTI0UOsjVhq5/W5TCwti0tO5kYtn/9vqJykUucrMixVPTxsbeuaiUDWzsCCyUaMitxIu/p4+HYUF+1Kl2LZ6dY4yOxsbLhSgBECFTgEoyiSlprL8yBFm7NrF1E6dEEIgk8lyWCDM5HJGt22LdbFiUodpGA9jY05mC/ea4eTEDCen1+q1Kl6c6qamlJPL+a5MGYRSmeppbU2Da9eoZmJCKwsLysvltLW05H9RUex5/pz2lpacqF6daQEB3EtMfGedreHhbzTDz3z8mKCUFDZXqsTTlBQeJScTnZHBX8+e8SwtjSomJrSxtMTBwIAfHB1JFwJdmYxWxYvze3AwbsbGuBsbU0JXl30RETxNSaGzlRUmOjr0tbVlg3KVnh0TbW2+trLCVFkn6wS/knp6NDQ3p/rly9QxM8NOX5/WxYvzIDGRlsWLv7G+\");\n    result.append(\"55UrTCpTJofM1sWLY66jQ28bGx4lJxPzEWl6JXKnoIQsSuSidBeWMECJj0QDYYASb3kBpfGfr4j8DkMr4GGAAPuvX3/riYRvpRCEAX7S+5/PYYA60eb52wHHuiCRn/O/1P/5/AWQuiA/aXE0n+f/z7x/zm07R32v+m+v1KU6f33k7zeXhmC+Im0BFEJSElIY5z6OyfsnU9qttNQhBRTzJuY4TnXEoun/55ZPj0wneEUwIatCSAn6/6x7hk6GlJlQBruBdiCDjPgMQlaG8HTxU1JDUyX5Eh+MUAgeXn74bgVAQlIAJD4ftHW0iY+MR0tHS+qMAkz0yWiiT0bjPN8ZhwkvHSqD/gji0fRHr9VNDkjGd7Avxh7G6Nvqc6PFDZIeJknyJT6a54HPsSpjJXVEIUaaIQqb1i4EOvo6dJzcEbuKdgiFkDqlgOP/vT/xN196wZfsWhKZTu77BroWusgryrnT7U6eTn5FXX5RJcQ3BDsXu8+6jaHBoQz/djjjh47n65ZfM7jXYDIyMlg6fynLfllGmwZtuHX95WFlPv/5sHDWQmZ8N4NeX/UiOSm5yD9jSQEoRCgyFXhbeTOxykTC/MKY12EeXgZePLr+SOqcgqzUZQju9buHyBAYVTTCYZxDrvXKzihL2PowYi/HSvIl8kQBKOlUkr9++gsvfS+6yrqyvN9ywv3DVXX8LvoxxnUMfcz6sH/hfsIDwvmt9290lXWlq6wr+xfsJyn2/5Wxc9vO0cuoF6Mrjuby35c/uY22pWwpXaY0/g/82bJnCxN+mMCGlRtwKu/EiAkj6N67O6MHjCYlOYWJwycyatIops2ZRnp6Og98H0gKgDTMC9HD1NZi3vV5zL85n5TEFMbuHMvSh0txrOoodU4BJ/5WPIHzAl9OdNPLIi+XM/TKrLYZlm0sCZgWIMn/QJL8krj37T2OyY7x5JcnudbJiMvgpOlJzjueJ2JfBEn+SfiN9uOY7BjXGl7jXr97XKlxhcA5gSAg/UU6IWtCOK59nAsVLnDP\");\n    result.append(\"+x5X617Fd6Av6dHpBWLMRT6NxLqcNV2md6HHvB4AlK9THuty1qo65euUp3Sl0nx/6Hvaj2uPtZM1wzcNp+aXL09jrdGhBnKz/39WdbrUwbaiLTMvzKT217XzpJ1GRka4ursiN5LjVN6J4/87zqOHj9i2YRuxMbE4ODpw6/ot5EZy1Sm22w9sp0r1KtKcIX1aCxeW9pZEPIng8u7L3D11lxIOJZBpSa7mhYHHPz8m0TcRLUMtXFa7qCIIZLoyXFa78GDEAzITMyX5H4i8/P+xd97xNV9vHH/fmXmz9yaSEIkQO2oXra01SqlRFS1FjRq1tUUptUfNKqrjZ7SlI7ZQe2YIkb1k73nv/f1x4xIZkkiCyOf1yovX/T7f85zv+Z7veZ7znGdo4zDHAaGWkPC14Sjzix+bRW+LRlmgxOhNI0z7maLdQBubiTYAOC52xHWHKw03NeT+F/cJ+ToEiZEE67HWSC2lWAy1wHWbK82ONSPhaAK3B99+6eZWYkQi+blFFROFQqHO8NdzUk8atGrAzwt/Jjvtsen8wdUHGNsY4+LlUuTesRvHoqWnxQ/TilbI+2vDX7w79110jaoveVBBQQFNPJswbNQwPp3xKVv3bUWhUBAcFKzO0goQHxf/2q8pdQpALYSpgymauprYudvVDUYtgiJXgf+H/igVSgw7GWL9oep81n6GPZkBmST8mVDHv5IQSARYDLUgLzaP2J9ii1xTypUkn0lG1kQGT2QZftoXQa+lHrpuusTujy2RRqwvxuwdM5J8kshPKJ8V4Ny+c9VrWUpMZ/fU3Szrs4wT208UHZMn0vsKhAK8v/cm7WEa++bsU42LQslvS35j8KLBxdo1tDJk2NJhXP3jKv/9+h8AydHJ3L94n1YDqj4b6JOpdzt27cjsybO5cfUGkeGRbP5uM02aNSE9LZ1VX68iOyubgwcOEv+wTgEoUwE4e/Is/bv2x0hgpP5zMnXi63lfExURVVQ7Dw5h6vipGAuNMRIYYadnx/wZ84mNjq1052KC\");\n    result.append(\"YvjfV/9jSsMp6jMlbytv9s7aS/CVx6a+y4cvs2vKLvU51WDBYBZ1XsTvK38nN6vyIUCZyZnsnrqbifUn8oHsA7ytvfnuve+4fOgygecC+W3Jb9X6cirLXyAQ0KhDI4ysjZ7JQ54lJ+TLEC56XsRH4IOPwAe/D/zK3cfo7dHq+847nefB4gdkBVXOASvpRBL3Z9/nlOEpdZvHRcc5Y36Gk3onOWd/jus9rxP3Sxy8pr6NqRdSiVgbAYDTCicM2htg96kddyffreP/nNC01cRsoBnh34YX+T3+YDxmA8rvDS+WlR1cJRAKEOk8u17BozC86oRYIqbv9L58fuhz/vj2DwryVBkSU2JTMLQsmiTGvok9vaf25p9N/3Dv4j3+2fwP7Ya2Q0tPq8S2u4/vjnNbZ3ZO2kl2Wjb75uxj6NdDi9Ds2rKLJvZNisiYUYNGceLvospIfFw8c6bMwURkgpHACBcLF5YtWEZMVAznz5zn3KlzBAWoioyNmzSO1u1a079rf97v9z7denZDV6bL9p+2s2/nPjwcPEhNScXV3VX1rMkpLJ69mHUr1tG1ZVcyMzIZ+NZA+nftT2pKKuNHjKdD0w5ER0YTFRFFrw69iIuJ49ypc2xctZFBbw9i/+79AOTm5vLdsu9Yvmg5A98aSEpyCjs27eDtN95my9otNLFvwrj3x700tQIEScpnZwJc8PkC1q1QVTn6fP7nzFo0q1TaHl49iI2O5X///g9HJ8dndsCHZ2dCC7sVxgyPGQDMPDKT5n1Kzjr14+c/cmTFEWQmMrZGb0UkqXxRkJTYFOa1m4eOoQ7eW71xaOZATnoO538+z75Z+0hPTGfQgkEMWlg9mXSel/+BeQcYsmTIM/lsRZUJUJ4u57TpaRS5CgQSAe2C26Fp+4wKX0q44HaBTH9VYZuWF1qi30b/uZ89Yl0EdyfdRawnpn1Me0TaIhQ5CmL3xXJ38l3kGXIsR1rSeGfjVz6Rjo+g4pkARdoi2txpg1Y9LZQFSgInBhK1JarG+lyb\");\n    result.append(\"+L+pVKWiyQ7NJmZXDCa9TbjU8hKe/3pi9KZKgb418BZu+9y42uEquk11abS5kfoe33q+ND/ZHMNOhiQdT+Jat2u47nDFapSVagfvcA6rUVbUX1if3JhcLja7iPFbxjTe1VglrMpIBRT3II4rh6/Q67NeNTKuG0dvxLmtM2+OexO/k35kpmQW263nZecxzW0aEk0Jtm62fHbgs7K/5TsRfO75OQ1aNcCzlycDZg8oOv68SWpKKl1bduXB/QdoaGoQnRVdanGh3h17kxCfwCGfQ1hYWVTJc/+671fiH8bz8ZSP+XXfrwwcNpBb128x6cNJnLp2ipDgEPp27svN0Jskxidy8t+T9HmnD595f8bmPZuJDI+kjWsbAqID2LVlF23eaEPLti35dMynWNlYMXTUULq36c7fF/7GxNQELzcvlqxcQv/B/TESvNhMgOU6Apj39TyaNGsCwMGfD1JQSh7t5KRk7gXeY8eBHeUS/uXFkzvZsna1BhaqPPeGlobPJfwB9kzfQ3xYPDN/n0k9z3oIBAK09LToOrYrX1/6ulrPsKqCv7FtxSodimQiNKw1EOmKUOYrCV8d/sx7Eo4mkBP+OBmLpk3VlATVtCtsR6Ba7AGEmkKsxljh8p3qrDFmdwxxB+JeSyuAPEvOg/mqyA5lvpKorVF1/KsIei30MGhvQNhKlTNg2qU0ZJ4yhNLSl8r4Q/GEfBlC7N5YPA55qIX/I6RdTiN8VTjBc4NxmO2A6zbXcvWlpsPwBswZwOFvDiMvkBMZEFkib6mWlMGLBxPpH0n3j7s/s01bN1s6jezE/Uv36Tu9b4k0+gb6rN+5HoFAQG5OLseOHCvZIpqRSVBAEN/v+77KhD9AizYtWLlkJZ9++ClvdFIlPWrSrAm5ubncv3ufm1dvYmhkiO9pX44dOUbPfj3xu+VHQnwC+3bt48yJM3Tu1pmkxCROHz/NnZt32LdrH6bmpmhqaSKVSpHpyajnWA+Znoy+A/ty7fK1l2ItKZcCIBaLWbdjHWKxmHuB\");\n    result.append(\"99jw7YYS6ZbOX8qw0cNo3rp51XZSJCxiPivLtPYsmvLi6h9X0TXSLWYGAzCvb06/mf2q9cU8L3+Ziazi5iCJAOuxqo8+6vsoClLKLpgStjIM648eLxKlxWdXuB+i0tuxHGWJUEM1H2IPxD43r8zATAInBOIj8OHam6V/lLnRuRyXHue0yWmid0aTG5VL1LYoTspOclL3JDf73+TmgJtcaHSBoClByLPk1To/8lPy1WbiF3EcUpv520+1J/HvRDLuZBC5ORIbb5sy6U37m1Jvbj1cd7hi2te0uFLRUg+7qXa4bnfFbrJdub+Tmg7Ds3SypEHLBpz54Qyx92OxcCxZyMqMVWuLVFNarufQNdZFKBSWuSlr80Yb3h/zvtrinFdCqfB1K9YxcNhA3Ju6V+n7trW3xfe2L9lZ2XT07EhqiiqMdOCwgfz202/ERMXgPdmbn/f8TEZ6BroyXQoKCtDR0WHYqGEMGzWMPQf3YGFlgbxATut2rRk2ahjzl87nk6mfFONnaGSITE/Gy4ByOwG6N3Vn8szJACxftJwH94vGll+9eJV/j/7LnMVzasUuS6lUkhafxundp0u83nZQ25eav5ZMq1J8LYZZoGGtgTxDTsTGiFLp0q+lk+mfieUHljX6XgQiARo2GiohkPD84VQ6DXVw+c4FgVhA0vEk0m+ml0gXuSESFGDUxQir0VZoWGtgPdYa/Tb66DTUweOQBx4HPWj0fSMi1kfgP8qfOryaMOlrgnYDbe5Nv4dIR4TEWPJC+vEiwvDe+eIdDi49SF523nNbUSuKhcsXYmRsRHBQsPrI+RFCH4Syf/f+Mo+fK4sjvx5BR1eHbfu34ebhRlhImFoB2L5hOx7NPej7bl+OHj6Ko7PKst24SWN8T/uyd+de4uPi2b5xO9lZ2Xh19GL6J9MJvhdMwJ0ADv9yGICMjAx1BEJQQBDde3V/KeZ6haIAps+bjnMjZ3Kyc5jy0RT1A+Xn5zP5o8ksX7ccbZ3aURqy2dvNANg4ZiN7Z+0lL7uo\");\n    result.append(\"RmpWz4ymbzV9afk36dakcgJWIsBukip6IGJtBIrckp1VQleEYjvRFqFmzQaSKHIU5MWoxkLXrWqOYQQSAYadDZEYSYo5gAEoshWkXkpF00ETgbTo7u2RNeIRDN4wQOYp4+HBhyjldVkYXxmFv0CJskCptiDaTrYl8Z9EbCc+rqWhlD+meXTPk/8+q92y8LKE4dm62WLnbkdafFqpfX3kKPh0f8uiL8gvKBKCVxKMjI1Y9M0iAL796lvCQx9/i7Mnz2bWolno6etV+bvPSM9gSK8hbNuwDQ9PD7WFwb6ePX3e7YNXBy9kejIGDBlAlx5dVFYQPRmbftjEN4u+oX3T9piZm2FgaMDEaROxtLakc/POLJ69mF79Vf4bebl5rF+5nm0bttHKqxUenh6vngKgoaHBuu3rEAqFnDt1jh+3/6g2zTg3cn5ptJqqwMhVIzG1N0WpUHJ4+WGmNJzCqV2niqTWdWrjVCv5W3tbI9YTkxeXR8zumGLXc8JzSDyaiM0nNjX+XsJWhiHPkiOUCrGbWnVhjiJtEdbe1sT+FFuseEzMnhgsR5Tf0lGQUoDUVFrmUcZzKy3iqjvuet35Z93PImJNBAl/JpDkkwSA1WgrLIdbou2ijTxLTsyPMWT6Z5J8PFmdCOhRNEL0jmjSbxS1HOUn5RO1JYq8mDwS/kwg8Z/Eki1pL2EY3rtz38WmUcnf9p0Td/hr/V8A/PndnwSeCyxd+VEoObfvHJcOXkKpUPLT3J+IuRdTJu9ho4fRul1rcrJzmD15NgB///E3yUnJvPfBe9Uyl0aMHcHRs0cZO2Es85fOLzLu3276Vv3/lRtXIpE8tgZ169mNm6E3CYwJpM+7fVSWV20ttv+0nfC0cPb/vh8dXR21cvPpjE8ZO2EsYyeMfWnkXIWLAbVs2xLvSd5s+m4T82fMp4FLA7au28qZ62dqpMMrBqxAolGySS4zObPK+BhaGfLVf1+xacwmrh+7TkJ4AhtHb+T3lb8zfMVw9Q69uvAi+Yv1xVh/ZE3Y\");\n    result.append(\"t2GEfRuG1VirIgtt+OpwLD+wRGIsIS8+r0bee05EDhFrIghbFYbEWILrTle0narW2mQ70ZawlWFErIugwdIGhasYxB2Io+mxpjxYXHZKZWW+kpAvQ8gJy6HxD42rdTweOVwKtYRIjCTkJ9VsdrnaxF+7gTYu64ruoEU6IvU7FGmLsBxuieXwokqgy1oXXNa6lNimxEiCtbc11t5lO/E9CsPrOakni7supuvYroil4jLD8I6sPEKHER14cPXBM8Pwzv54lp2TduLR3aPEMLySUM+zXqk+RG5d3HDr4lY+JU0o4I1hb1SomqBAIODbTd/SybMTx44c4/fffmfx7MVsP7C91MiAOtSQBeAR5n41F/t69qSmpNKvSz9mLZyFmUXNVI2acXAG3wV+V+Jf/9n9q5SXgYUBs4/OZvr/pmPppPr4I/wiWNpzKauHrCYnI6dan/VF8rebYodAIiArKIv4Q48TZhSkFhC9Kxq7z6o/yZA8U871Hte54HaBc3bnCF8dTqNNjXgj9A1M+5hWOT8NKw0shlgQtSVKnVEu8e9EDDsblukFnhOVw91JdzljfobkU8m08WuD+RDz6pkT7Q1o8HUD6i+ur/6t6dGmOMxyQGomrfZ38rrzr2po6WlhaGWIqYMpjTo04tSuU0DpEQCDFg7CzMGMTWM24X/aH68hXmUKYO+t3qQlpPF1z6+xcrHCrF751mkTO5MXNiau7q6MnzIegA/f+5BO3Tqpo9BeNSgUCo78doS42Dgu+l586fpXKQVAS1uL2YtnqzXYkeNG1motqdWAVqzyW8WH6z9Ua8YXfr7A8j7La6Ta3ovgr2GjEoYAYd88zo8euTkS427GaNXXqvbnFumIaPZ3M1r6tkSrvhZKhZK0q2mIdKvPOcnuMzvyk/OJ3hmtet4tkdiML/uoQ9NaE5e1LpgPMSftalq17lRSzqZwf859ThudVidLutzmMqHLQsl7WP3WmNedf3XiRYXhPQ+y07OZ4DCB498fr9J2Zy2chVgspqCggA8/\");\n    result.append(\"+fDV3WELhYyfPJ7IjEhat2v98vWvsjfqG+irH7A2mmaezDQIIJKI6DGhB2uD1qo9bP1O+XHl9yu1kj+grsGeejGV5DPJKPOVRKyLwH66fY2+C7G+mCa/NEGoISTq+6giqVarGjJPGYYdDIlYE0HGnQykZlIkJuXzAnda6YTUQorfKL+6Msx1qDBeZBhepb9NiZis1Kwq9wXR1tFGJFL199G/dXiJFIDajj++/aPE33UMdZhyYAqWziqT/P1L92slfwDdJroYdzdWWwFi98Wi3UAbvVZ6Nf4+ZJ4ynFc5AxDgHVCt9d7tptqRdT+L24NuYze5/EcdIh0RjXc1JvV8KuGrwus+olqKuANxnLE4g4/Ah3sz7j0OR1WqnFR9BD4EfhJIbmTF05C/yDC8ykCiKaHb+G60e69d3cSoUwBqD0JvhhZJuFFk0mtI8OiuCuPQ1tcmPzefIyuOMEQ0hElOkwi5FqKmve1zm/c13+fAvANkJGVUC//qxKPdfsLRBILnBZdr96/IVRC2IkxVCtXpPOnXHntIJ/kkcULzBMHzgivsuEiXZ9kAACAASURBVGXziQ3mQ8yRp8u5Pfg2ipyiIYrpN9K51PoSPgIfgucHI89QnePnJ+Rze/Bt/nP/j+RTycXaVcqVRRL3mPQxQctRC017TXRcdR7T5SmLhUUqchXIcx7fa/CGAXbT7Lg/5z6p5+vq0tdGmA8xx/0ndxCAlqPWYwuRAAw7GGI7yZaGGxuq81VUBC8yDK8iuPHXDYZpDGOUwSgeXH3Asj7LGCIcwoIOC2r9+4+OjGbgWwMxEhixec1m9e8+x3yw0bVRR8fVagXgUTrgmihq8KQ5VSEvnd+ja2XRVITnzkk7S2xLqVQV6RBLxbR5tw0SDQl9Z/Sl92e9yUrNwtzxsQOYkY0Rvaf2ZsiSIRVKH1wR/lU2zgVKeIqdUTcjZE1loASRrgiTXibF73nqPQk1hNjPsMfuMzsKUgvQcnzsL6Bho4HdVDsclzgiMZKU3o+n3vsjuH6v\");\n    result.append(\"8v5Pv5FO4ISiIUiypjI8/ueBWF+MSEuk9hWQmEiQmklp9k8zDDsV9azOupulEtb/pRK9PZqClAIEQgF2k+2wm6La/edG5hK2MoyciBySTyYTvaswE+DWKFL/SyUrMIuI9RHkxqh2fI5LHNF21uZaj2vcn3Of3Khc6lC78KgaYfC8YPITH1sAwteE0+DrBs/V9osMwysvLBpY0HNyT1b7r8bFy4X5PvP5ZOcntBlYdeuRXC6vMRlTEVjZWLFt/zZMTE0wMn6cmt7c0pwFyxYw/MPhr8w8Flf2xuhIlZNUTnYOyUnJGBoZVlsnEyMSi/y/fvP6JdIlhKnKgabEpiAvkCMSP58J7fqx68z1mst7X75H486NEYlFJEcns2/OPkKuhTBuy7giwn7IkiFcPnyZvTP38tHmj1Qf6eo/Gb1mdLXyz8/N59jaY+ydtRfz+uZ8duAz6nnWU1sglvVeRt8Zfen1Wa9SlRBlvpK82Dxyo3ORecqKWQHuDL+j2v0/ddT3ZC2A3MhcNKwe73oclzgSfzieezPvqQuohK8Ox2WNS5nPnR2mSnQiz5BTkFaAWO/xNBXJRLj/4s7lNpeJ3hGN2ECM03IndVy4hrUGTiucuDv5LuZDzNGqr0Xy6WRknjI0LIvvyLRdtHFa7oTT8qI5FWw/tS2itNhPty9m/bAeZ431uOKOWkINIW3vVDxTpFFXI1x3uJIblUv8EVXkhVBLiOVwS3wdfZF5ynBZ64K2kzZR26KQGkvRaaxD8LxgtWWjPDTPgn4bfaw+tCI3IhdFrgKhthCpiZSIdREIpAKcljshayYj/DvVMYdAJMBskBn+o/1Jv55e4ecWyUSY9jbFbZ8bsXtjybiToX6XGtYa3HrnFsZvGeO0XPVe066mPZO+JuC0won4P+K5N/0erjtdid4Rjfkg83JV+isLLzIMryIKwPBvhpOdno3P9z5YuVjRcWTHKms//mG8epMZGx2Li6vLSyU4DQwN+OLLL/jyiy/pN7AfGpoaHNhzgIXLF75S\");\n    result.append(\"iqxo5sKZFerxhbMX2LVlF+tWrCMnR7X4+572JSkhCUdnR3R0dCrUgQeUHlsdExTDP5v+4cD8A6QnqhYW/9P+ZKVloSXTwshKpX1dPnyZvzf8zb9b/kWpUJKXlUfg2UDSE9JxaOqAWFJxPSfkegif/vApuka6nNlzhn2z9vG/r/7Hv1v+xcDCgI+3f0yLvi2KDqZEhL2HPTsn78Stixv+p/xxbuusPq+vLv4isQiXdi7kpOdw/9J9Bi0YhERTojb/aWhr8N5X7yHVKu40dCnrEhGrIwheEEzWvSxSzqeohe4jganjqkPi34k4r3ZWC9qM26o86SFLQihIKywhei6FgtQCNCw0kBhLEEgE6HroEjQ5CKMuRiSfSka/rT7aziUfWySdSCJqSxSh34SizFPt/pPPJFOQWIC2o7Z6R69hoYHUXErC7wmkXkglZncM2Q+ykTWTIZaJ0WuuR/KJZBL+TMB8iDlhy8OoP6/+S1k58MGix/M/OyQbwy6GZAZmEjwnmJRzKSSfSkaeISf9ejp5MXlo2moiMZFwZ9gdEv5IQNtJG+fVzkRuiESRqygXTVkwe9cMl9Uu3Blxh8RjiaT4ppB8OhmLYRZk3Mkg/Uo6UnMpOi463Bl2h5RzKaScTSH5RDISQ0kRhbDclqc8JRl3MrCbZkfo8lCitkaRci6FxGOJiHREpF9PJ/t+Ng5zHIg/GE9WUNYz6cuL+gvrV958qilE006T4LnB6DbRJcknCYdZDhVqozkl102p7qO9qkJCeAIHvz6IpZMl7m9WPEd/fYqOf3ZWNhtXbWTpgqXERKmsFZfOXyI9LR1be1u18/nLgCbNmnBgzwFSUlLIzcnF1t4Wp4YVS862fNHyRS/yGcpVDrg6UZ5ywK8avh//PXdO3MGztycjV9VciGRedh7Tm0zHvau72gKx1Xsro9eMVisET+NROeDqRMD4AJJPJGPS20TtyFfdyH6QzX/u/6HXUo+Gmxui01Dnhc2HjNsZXO95nXpf1MNmvA15D/O4/d5t\");\n    result.append(\"Gm1pxHnn80VoPQ55kBOZw92Jj+vbC7WEKLJVgrve3HqY9DbhcpvLKrPjYHPcD7hz3uU8WUFZ5aYp0RyoJ+aN8DcIGB9A3E9FKy1KzaXouOqQfDIZuyl2WI+15oLbhaIC8Yl+VgadUjrhP9afh78+LLFNr0Av1VwqtGQ8i748eFQO+Hlwo/cNknySaBvYFi2HioXHllUO+FWAUqFkhO4IvL/3pv377St8/5u8+Uo//4WzFxjcczBDRgxh5caVFbf6vQrlgOtQMQxaOIiYezE17hkr1ZIyftt4fL73IeBsAKd3n6bt4LalCv+aguNCR7LuZWHxnkWN8dSqr4XFCAuE2sIXKvwBdN11abSlEQl/qI6o0q+l02hTo3JlMtRtoouOS8n9F2mLsB5rTfLJ5FKjIspD8wgmfUwQ64tJPl78qCAvLo/kkyUfIQjEAiyGWqDIVqDXXA/Pfzxx/MqRFr4tcNvnhsMcB7yCvLD60IqOCR3RbVI+XxjLDywrJMwf0Qs1hcV42k+3p61/W2zG2/BG6BtFqlg+Lww7GSLSFVVY+NcGCIQCrBtZY+dux+uItu3b4tzQmRZtWryS/RdThyrHI4H7IvKku3Z05c2P3mTzh5vx7O1ZpedyldYyHxUMqmF1U6QpemG56osJ154mxO2PI2pbFAKRAOO3jEul1fPUw2GWg1qw3nn/TlFFz1SKw2wH7KfaE/JVCJEbI4uVxC0PTTGlqVCA5SU+O6GOxESiNncbdDAg6R9VDv20q2kochVo2mpyvdt1NGw0EMvE1J9fn9TzqVxpf4XsB9mltmvW3wztBtqIdERYDLcg5oeyndZKolfkKEj6O6koz5Bs6s2rhyJPwWWvy+Uq0FOH8sGigQVmDmav7fNLNaQIha/mXrpOAagGPPJef1HJYAYtHMS/W/59aWJz1eOgqHm+L1NCHufvnLngdoE3wsp2ykq7lkboslAAEv5MKL4bj88jdGkoBu0NMGhnoHbGqyjN08iNVUUriPXFFCQXlEmbn5Cv7qNw\");\n    result.append(\"lRCzgY8FgDxTTvq1dORZcrKCstBpqIMiR0FmwLNrdTw89FBt0i9LUXgWvTxTXoynIltB+rX0YsWennuelbPiX22Fvpk+mjLN1/b5FQrFSxepUO7NWZ24rlqkJ6ZzcudJAHz3+5IYmfhaWSCKCYrEx2l1Y/fHVio5SmWQejGVlDMpZNzIKLUSW42/F2MJYn1xmXUFis2n6+mk30gv0bPcf4w/hp0My6xUWB6aR0j6NwlFrgLjbiVbJ6QWJWeeU+QpiN0X+9ze70/j0bwpb7sVpa8KJJ9K5uHBhxSkFhCxLqLGimO9TDC0NHxtC/WcOXGGe4H38DnmQ2R4ZJ0F4HWHzFhGn2l96DOtz2trgXha6NlPs8d+Ws2mD9ZvrU/rGy9X7u20K2nkxeaR6Z9ZJMFQEZSwjkrNpRh3NyZmTwwCoUCt2OXF5hEwLgDXXa6kXkxVO/iVh6Yk5ITnEPJlCE7fOJF2OY3skMc7aouhFiSdSCq1jwKRAOtx1oSvDi95a1EenaeEdo26GJGfkl8kmVR56BVZipJ5VvGWx7CTIa0utnqt1zxdY93X9tk7dOnAg6QHr2z/6xSAWmiBeFRRzHe/L4ZWhhjbGNcNzEsAvRZ6dErpVOp14x7G6DXXQ7uBNg6zHVTJl7RVZ9tX2l9B5inDqIcR2s7amPQyIfGvRB4efIhJHxOan2hO8PxgMv0zn0kTuze21HDAkC9DyInIofGexuSE55D9IJuC5ALifokjLy4PWVMZJj1N0LTXpN68eijzlQgkAox7GBO5IRJdN1103XWRmEqIPxxPTngOZgPNEMvEWI2yInpXdDGeIpkIs3fMEOupaLQbaKsVH8MOhlxsfhH9tvpoWGtg/LYxmXczMe5uXCr9pTaXcJjpUISn8dvGiA3FWH5gqXqmlIK6CVlFeFVCFutQgg5dFwb4eqMmwgDrUMb8F9TN/xeJqggDfB686mGAAFd/v0rzPs0rN/6veBjg8+JFhwGKSTZ8sSPgM6huFXqhGkDd+L9gHbxuCF4k\");\n    result.append(\"uv37Yvm/AvL/7Nm9NGjQEkvLknN4NGcQ/FJZDez1nn7KqizQUCkFoA61Djk5GUyb5s6sWb9ja+tWNyC1AIaGHWne/FThoqFAoSjuIS8UaiEQCFEq5Vy50oHU1PN1/Ovw3AgKOk+rVv3rBuIlwO3btzl48CA7d+4kNDQUADs7O8aMGcM777yDu3vFsjHWKQC1ECKRmPT0BITCutdbWyCRmJKVdZc7d0aQlnaFp4P6dXRcad36KgKBJqGhy6tc+L3u/F/vDUUmGho6dQPxEsDd3R13d3c6depEx46qHC+7d++mU6dOlWqvLgywlkGpVCIWa9C//yysrRuiVCrqBqUWQCo1JShoGmlpl4sJP4FAgpvbjwiFmqSnX+PBg4V1/OtQh1oMa+vHmSzt7CqfhbFui1iLoFDI+egjC4yMrHBwaMry5X25ceMvvvrqAvXrN68boFcYYrE+ycknS7zm6LgYmawZCkUOd+6MQKnMr+NfhypBZmYyurqFRdcuH2b16sG4uHihrf24KE9q6kOCgi5gaenMihU3kEq1+PzzZmRnp2Fj44pQ+Dgvg7//GTIzk/n44+107jzmufp26NDPLFu2EG/vSXz33TKmTfuCfv0GsXXrOsRiMX/99Ttff72a5s1bk5mZwebNazA0NOLIkV/58MNP6NPn3Vf2vYhEj8f0ebIQ1ikAtQhCoYjly69ibGzDqlWDmTr1Z1JS4jAxsa0bnFccoaHLSvzdwOAN7O0/B+D+/VlkZvrX8a8gsrKCCA1dSnT0LpycvsHefkYxmoKCNM6etUEqNcbZ+Tt0dBoTGbme8PA1GBi0R1u7ARkZtzAzexcHh1nk5yfz8OH/CAz0RkurAQYG7cnM9EdX140GDZYjkRi+EvMuMjIAGxtVKe/09ASmTfuN5s17F6FZurQnAoGQTz7ZiVSqSidtZeXCxIk/IBY/Th4VFHSBK1d+p2nTt55b+AP06zeIyZM/QiqV8vff5xGJxMydO41PP52Os3Mj9PT08fYezpUr95g1azJD\");\n    result.append(\"h47Ey6sDVlY2/Pzzj6+0AlBlMqNuaa1dMDGxIz4+jIsXf8PP7xSmpvYIBHWvuTZCJJLRuPEPCARCkpKOEx6+to5/JaCt7YyDwxyEQi3Cw9eWaEGIjt6GUlmAkdGbmJr2Q1u7ATY2E9UWCFfXHTRsuIn7978gJORrJBIjrK3HIpVaYmExFFfXbTRrdoyEhKPcvj34lZljUVEBWFs3KhxvcTHhf+LEdq5fP0bv3p/h4uKl/r1Zs7eLCP+8vGw2bBiFlpYMb+/vq6RvAoEATU0tmjTxxMLCClNTM06c+JsrVy6yb98uMjMzaNiwMTk52Rw58iuNGzcB4K23+rBjx4G6BaROAaidMDV1QFNTFzs797rBqMVwcVmDllY9CgpS8PMbxTOr/dTxL0OYSLCwGEpeXiyxsT8VuaZUyklOPoNM1gQQPXFPUQOqnl5LdHXdiI3dXyKNWKyPmdk7JCX5kJ+fUO6+nT27l5iYoGody5s3/+GLL9py586JUhWAjh2LljZPTIxk9+6pWFo6M2TIkiLXnqbdv/8LYmKCGDlyNcbGNtX2HNnZWXTq9CbDho1i0qTP2bnzF6RSDeRyOYGBfmq6hw9j6xaQiigAvr6nMTISYGQkwMREhI2NbrE/ExMRRkYCTE3FXLpUO71wIyP9WbNmKB99ZM7IkfpMmuTEjh2fcveuL3/8sQo/v1NVzvP69aMsWtSFkSP1GT3aiJkzPfnttyVERNxh9eohJWrGjRp1wMiociVPs7Lucv/+bM6cscTHR4CPj4Do6B3lvt/Pb4T6vqtXOxMW9g1yeVal+pKUdIL792dz6pShus3jx0WcOWPOyZN6nDtnz/XrPYmL+6XGBdCLVfL6Y2U1GoDAwAnk5kbW8X9OaGraYmY2kPDwb4v8Hh9/EDOzAeVuRyyWPUPZECISld+rPijofKW/5fIJ/7+JiLhDly4f8uuvi4tcS0tLQCYrOZPo5s1jycnJYMKEXWrTf0m4e9eXo0fXFJr+R5dIs3z5IrV8MTeXlihfHl13\");\n    result.append(\"dbUmJeVxaeonC/F07tydcePeJzDQj4iIMNau/QaALl2688UXU4mKiiAuLoYDB/ao70lJSWbx4tmsW7eCrl1bkpmZwcCBb9G/f1dSU1MYP34EHTo0JTo6kqioCHr16kBcXAznzp1i48ZVDBr0Nvv37wYgNzeX775bxvLlixg48C1SUpLZsWMTb7/9Blu2rKVJE3vGjXv/pSkeVG4FIDExngYNXDh+/BLx8QVERmYU+Tt+/BISicrkM3nyTFq18qp1i66//2lmzWqBQCBk+fJr7N6dyoIFJ9DSkrFwYSd++GFalfM8fPgbli3rQ7Nmb7NlSxQ7diTw8cc7CA29ybRp7ly48HOJ99Wv71lpntraLjRosJTGjXerfwsLW1kuAZubG0Vs7IFCk6Eunp7/YG//OSJR5dKFGhl1oUGDpTg6Li5cXPXo1CmdDh3i6NjxIfXrLyAl5Sy3bw/Gz2/0a6EESKXmuLqqzKhxcQeIjd1Xx7+KYG8/jfT0myQlPc7QGBv7E+bmQ8uhrB4nI+MO1tbepXwbMcTF/YyFxQiEQq1y96m6w/A8PHrQu/dUunQZQ3JyDAEBZ555z/Hj27h582969/4MZ+e2pdLl5WWzcePoZ5r+ExPj6dWrP7duhREXl1dMvixfvla9udmwYScGBob4+BwjNTWZAwd+IDU1pVCRWIehoRHdurXhgw/eoUeP3giFQlas2ICRkTFt2rjy8ccjGTx4uJq3j88xTE3N+fTTGXz88Wfo6Ogyf/5SUlKS0dc3YObMhSQnJ2FhYYVUKmXkyHHo6enz44/b+eSTqaxevYUZMyaQnp7G1q1radeuIzNnLsDS0opNm1bTpUsPgoOD6N69F76+t7lw4SxHjvz6Uqwl5XYCTEiI58svv6VZs5bFruXn5+PtPZzc3Bw8PDyZOXNhhTrh67ufc+f2c/Xq72rzkZfXEJo1exuACxd+4dy5fVy+fAiADh1G4OU1BE/PXjU2UAqFnPXrP8Dc3JGJE39Qe7YaG9sydOjXODq25Ntv\");\n    result.append(\"q9apJDr6Lvv3z6FbN2/69n3smOTg0JRp035l164pHD26psR7jY2f3/FPR6cRQqFKqcvMDCA+/ndMTfuWeU94+HcIhRrI5flIpeYIBJIqGQtNzUehLgK1MiEUamJlNQZQ4u8/lpiY3ZiYvIW5+XvlbregIIWYmB8IC1tJTk4EMllTWre+/gwz4wPOn3dGqZRjbj4Ic/P30NV1JyHhD0JCviQ/Pwmp1BxtbWfk8gzy8xORyTxxcJiJvn6b5x4LV9cdSCQm5OZGERDwcY0vGrWZv55eCwwM2hMWthIjozdJS7uETOap/g5KQnz8IVJSzpGd/QAPj0PFvpG0tMuEh68iI8MPB4fZ2NpOeCkVS4FAyIABs/n11yXMm/cveXnZaGholyALwvnhh2lYWbnw3ntfltnmvn2ziYm5x8cf7yjT9J+ensa6dTswMCjuHBkWFsLs2VMAGDt2Ap07dwfgzTffJja2aHVRExNT9uw5WKwNc3NLfv75aIm8W7RoQ9euLfH3v80XX6iOMpo0aUZubi7379/lzp2bGBoa4et7mpCQ+7zzznv4+d0iISGefft2FVoeupGUlMjp08fR1ZVx795dTE3N0dTUQiqVIpPpUa+eIwB9+w7k2rXL9O//4n1Byq0ApKWl0r595xKvLV06n1u3rqOhocnmzXuQSCq26LdrN5SmTd9i9Ggj9PXNmTBhV5HrbdsOonnz3gwfro2OjgETJ/5Q4wMVHn6bhIRw2rQZWCSs5RFatRpA06ZvVSnP69ePoVDIsbVtXOL1YcOWcubMnhKvyWQmz28eEkoQCrUwMxtAdPQuwsK+KVMBkMvTiYrahrX1h4SHryl2Rvp8i1PpJV4tLUcRGDgBhSKX2NgDFVIAxGIDbG0nIRbr4+c3ivT0GyQmHsPY+O1S7wkLW4lSKVcLI5FIVQ3Nzu4zsrNDiIhYh5PTSiwthxd+O5e4fv0trlz5k2bNjmJkVPn8pzY2H2Ni0hNQ4uc3moKC5Br9Dl4H/vb2U7l5cwAZGXeIjNyM\");\n    result.append(\"k9OKMulNTftjaNipDKWiJXZ2UyvVl5oOw2vffji//LKIoKALSKVaWFm5lGr6/+STnUgkmqX2PTDwHMeOraNZs7dLNf0/gp2dQ4nCX6FQ8PHHH5CRkY6TU0MWLfqmyt+3ra09vr63mTt3Gh07enLpUiD6+gYMHDiM3377CT09Pby9J/Pzz3to1MgNXV0ZBQUF6OjoMGzYqMK1eBS5ubnI5QW0bt0OV1f3QqtPLomJ8UX4GRoa8YIzAD9e48tLOGXKLLS0imuD//13Tn3OsmDBMlxcXCu5w5MV/qtbitlPC6FQ9MIyUj16YdevHyMysuRQozZtqjqvvornv/9uITs7vcQxedor9xG0tGRVuCBOBwSkpPiWmWEtMnIrhoYd0NZuWMM7FxEaGjaF1qiESrUhkRijp9cCgJCQpWWYNB+SlHQcqdQMgUCkFv6P2zEqQQC0wsFhNkplPsHBCyr9nNraTjg5rQQgImI9SUn/lvE9VX3o5+vC38SkL9raDbh3bzoikQ4SyYurpllSGN6CBSeZMeOQ+k9Hx6DEMLzVqwOYOfN3NV2/fjPJykotMwxPJBLTv/9Mfv11cREHwMfm8q3cuvUvvXtPLdH0n52dVij4sso0/T+ie4TZsxeX2J81a5bz33/nEIvFbN68B01NrSof4yNHfkVHR5dt2/bj5uZBWFgIAAMHDmP79g14eDSnb993OXr0MI6OqnoIjRs3wdf3NHv37iQ+Po7t2zeSnZ2Fl1dHpk//hODgewQE3OHwYVWRhIyMDLUMCQoKoHv3XrwMeK4ogIyMdD7++AMUCgUdO3bF23sStRV2du4YGVmTm5vJ3LlenD69uxhN06Y9MDevX2U8PTx6IBAICQ+/zZw5rbh3779iNN27l2wCbdKkW5X1Q0enMcbGKutGaOg3pShIBURErC1UFmoWCkUOeXkxAOjqVr72gYFBOwwM2pGScpaUFN8SaSIi1mJj80mFjza0tBoUKhCV8z4WCMS4uf2ISKRNZmYg9+7NLINWgo1N1ZrG\");\n    result.append(\"azt/pbIApbKg8H4htraTSUz8B1vbiU/QyNU0j+558t9ntVsZvIgwvE6dRhMefpvTp39QKx+gMv3v2TO90PS/pIRv4w6hoTcAlek/NvY+I0euLtGB8cyZH5/57LduXWfZMpXCPGPGfJo1a1Et60dGRjpDhvRi27YNeHh44u7etHDjU48+fd7Fy6sDMpkeAwYMoUuXHoUWVj02bfqBb75ZRPv2TTEzM8fAwJCJE6dhaWlN587NWbx4Nr169S8c/1zWr1/Jtm0baNXKCw8PT14GPJcCMHv2ZMLCQtDXN2DDhl0IBLW3splIJGbChN1IJJpkZaWyYcMo5s71KuIwY2hohYmJXZXxtLFxVX9oUVGBzJ3rxbp1w4mLe6CmcXJqUyPP7+Cg8kGIjz9CVtbdYtfj4g6goWGJgUH7Gn83YWErkcuzEAqllTa1Pn7OWYWKTnErgFyeQVzcAaytx1a43UdZ7AwNO1eqX/XqzUVPrxVKZQF+fiNKLIbzCFZWo8nLi6/SMa7N/LOy7hMRsYaEhD/Vzn9WVqOxtByOtrYLcnkWMTE/kpnpT3LyceLjDxfeo3JMi47eQXr6jSJt5ucnERW1hby8GBIS/iQx8Z8y+/AyheFJJBr06TOdwMBzGBnZqC2gmzZ9SE5OZomm/4KCPPbtm42trRsBAWf466/STf8BAWeJjb1fZh9yc3Pw9h5Ofn4+zZu3ZurUOdW2fowYMZajR88yduwE5s9fWkSOffvtJvX/V67cWOR4u1u3nty8GUpgYIw6qZCWljbbt/9EeHga+/f/jo6OykJoZGTMp5/OYOzYCYwd+/w+IE9GEcjl8kq3U+lD2j//PMTevTsBWLFiA1ZWNtR2uLt3ZdGi06xf/wHR0XcJCrrAggUd8fTsxYgRK4qZy6oCAwbMwcjIml27ppCZmcLZs3u5cOEXunUbz6BBC9Tng9UNQ8PO6Ok1Jy3tKqGhK3B13faUEP6WevW+qNH3kZMTQUTEGsLCViGRGOPquhNtbafnatPEpFehQ9+f\");\n    result.append(\"ZGTcQle3yROL8fdYWLxfoRAuuTyLiIh1RESsx9CwA05OyyvcJz29VuqxffBgcWExnBI+ZrE+5uaDcXZexc2b/apsnGs7f23tBri4rHtK4dehceMfCv+vjaXlcLVPxyO4uKzFxWVtKULUCGtr71IjAooK/7+JiPBTh+G5uXVRX6upMLyn8eab47h920ctDM+c+YHbt33Q0THk8OHlxYR/aOhNQImOjgEbN45BqVSSzNBwjAAAIABJREFUmZnCihVFqwimpcUTFPQfH320qUz+CxfO5O5df7S1ddi8eU+R1Ld1gIiICPX/o6OjcXR0rDkFID4+jilTPioUUEMYOHBYlT1YSkpssUnz2Jz24mMnGzRoxcqVt/jzz+84ePBrsrJSuXbtT27e/IfBgxcyYEDVa6odO46kadO3+emnuZw8uYOCgjyOHVuLr+9+PvlkZ41FQ9jbT+f27aHExv6Io+MSNDQsAVX4U0FBGqamA6q9D3J5Jtev9yAnJ4rMTD8EAiGNGm0qFMy6VWFsxt7+c/z8RhAaugw3t32Fcy+fyMgttGzpW65WYmJ28fDhzyQm/o1EYoKnpw+Ghp0qlZXR1XW72qHSwWEWDg7Fzd8CgbBIaFlGxu0qG/PXnX91w8OjBx4ePVAqFRw5soKAgDM0atShzHseheH16TOtSsLwnoaGhjajR68psgY9bVVQ7dQzmTbNne7dP+bdd+cCsG7d/ecaj9Onfdi6VaWQLVmyEkdHJ15VKBQKjhz5jbi4WC5e9KV163bP1d6T5YAfYeTIkYwaNYoBAwbUTDngiRPHkJiYgKWldRETSVXAwMCCGTMOlXjtvfdejtIFYrGUfv0+p0uXD/nf/77ir7/WI5fns3//F+Tn5zJ48KIq56mvb4a391Z69/6MH3+cydWrv5OWFs833/RjzpxjVXrmXxrMzAahpTWb7OxQIiLW0KDBssLd/0rs7afWSMphkUiHZs3+pqAglYsXPcnOfkBa2tVy7bTKCwuL93jwYB5xcT/j6LgELS1H\");\n    result.append(\"YmP3YWzco9wOYZaWo7C0fJ9r17qRlHSc/Pz4So/Pf/+92IyOrzv/msKLDMMrCebmz95V5uZm8fBhCJGRflW0AUzmk09GoVQq6datJ6NHj3+l36lQKGT8+MmMHz+5Stp7VA54/vz5VdO/it6wY8cm/v33aJGEDK8DcnOzinn/y2TGjBy5ipUrb6rDZQ4eXEp6ekKV8IyJuUdWVmqR36ytGzFz5hE+//wwmpq6KBRyfvzx8xpaoETY2X0GQGTkZuTydDIz/UhPv6rOylZzSpg+TZr8glCoQVTU90XSrz7/c4qxs5uGUikvdHpUEh7+Hfb2FU30JKBx4z1IJCYEBHiTkxNGHepQFtq3H05s7H2Cgi4QHX23xsLwKgs9PVOcnNrQokXVHPlMm/YxMTFRGBubsG7d9roJUd0KSkWIg4PvMW+eysv7o48m0qlT6bvOqKiIWjVQ2dlpHD9esglNJZR/RyQSI5fnExJyvUp4PnhwtdTUwi1a9GXMmHWFO/Cb5Ofn1sg4WFl9iERiREFBKpGRWwgLW4mNzScVymxWVZDJPHF2XgVAQIA3WVn3qqxta+sPkUpNiYnZTVTU9+jquj+RjKj80NCwpHHjnRQUpHLnzvvq/AF1eLWRkPAnZ8/a4O8/hoCA8QQEjOfmzf74+AgICKj8rvVFheE9D9q2HUSLFn2eu51fftnLwYOqLKKrVm3BzMzitZEvL70CUFBQgLf3cLKzs3ByasjChaU7M+Xn57Njx6ZaN1iXLh0q1Q/B0tIJKytV/PuTSTqeFxcv/lbqtebNVR+dVKpVJOSnOiES6WBjM75Q8fiWhw8PYmPz4jKb2dh8grn5EOTydG7fHoxCkVM1H4ZQC1vbSSgUuQQGTijx3LlsPE70YWLSG1vbiaSk+PLgwYK6VacWID8/mZYtz+PquoNGjTbTqNFmlMp8tLTq4ey88rnaflnC8MrCsWNrGTJExMiR+ly+fIi1a4czZIiI0aMNiYoKrHB7UVERzJihWkeGDh1Jnz7vlErr73+b\");\n    result.append(\"s2dPvtD3L5fL8fR0ZOHCmXz11Vy++moutrYypk59tY4syq0AfPvtl1y7dqlcCRn27duJiYlphTqSmZlcqLlmlrIDT0ehkJOTk/HCBis+PpRDh0quS56WFk9cXDCWlk44OlZdvKqv70/4+58u8VpQ0AUAvLzeq5YQTFUMc3GFx9Z2EkKhBnl5sVhYDEUqNS12nwqKKu2L6t/ibbq6fo+2thPp6TcIDKycMlJQkEpBQepTysUERCIZxsZvoaPTuIhwl8vTUSrlyOUZT7WTUiggkor87uS0Al1dd0JCviYmZk+dBH3Foa/fsohFKCrqexIT/8LVdddzO6O+DGF4z4KDQzN6957K2rVBNG7cmU8/3cOcOcfo0GEEBgYWFfy2lUyYMIq0tFRsbe1Ztqzsss6rVy9VZ9p7UUhKSmT9+p0sXLicL774EienhmhpaTF//tJXah6Xy6vu2rVLfPvtV0DZCRnS0lI5dOhnvvhiKnv3Hi53J86fP8D58yrTT0pKLJs3j6VNm4Hq1LoXL/6Gr6+qROejGHwvr8Ho6Zmxf/8c/PxOsXz5Vezs3Ll924c9e2YwevQadHWNWb9+BHl52cyZ8xempvakpj7km2/64eU1hG7dvMsMnykJ+/d/QWRkAH37zsDevglKpZLQ0Bt8//14pFItpkz5qUqd4eTyfL76qgf9+8/mzTc/wtDQCrk8n+vXj7FlyzgcHJrywQcrq2Vy5OSEI5dnUFCQhlisp/5dKjXH0nIE0dE7Soy7z8kJL1TmYlEq5WWm8S0vsrPDCsejeH9EIhnu7r9w+XIboqN3IBYb4OS0vFypiAsKUomLO0BExHpyciLQ1XXH2LgnOjoNkUgMsbEZVyS6ITHxLx4+PERBQVrhYjoOM7OBhaGDv6uFe0SEqiaCmVl/pFILhEJN3N1/4uLFFvj5jeThw/9hafl+kb4YGXXF1XUHublRxMcfUVsiLC2H4+vriEzmiYvLWrS1nYiK2oZUaoyOTmOCg+eRnHwKoFw0zxZubbCy+pDc\");\n    result.append(\"3AgUilyEQm2kUhMiItYhEEhxclqOTNaM8PDvAJVviJnZIPz9R5OeXvHjL5FIhqlpb9zc9hEbu5eMjDsAaGhYo6Fhza1b72Bs/BZOTsu5e3cyaWlXn0lf3dDWdnliboYSFDQNW9vJGBp2qJL2X3QY3rPQqFF7GjVqT25uFr6++9HQ0KZfv5l4eHSvcFsbN67izJkTCIVCNm7cjUymVyJdTEwUGzeu5vDhX1i/fucLFZx6evq0bKk6gklNTWHevOksXrzyuXzijh8/zpgxY7C2tqZv376FcyubH3/8keDgYK5du8akSZO4d+8eY8eOJTExET8/P5YsWUKnTp0KZfWzaZ6EICnp2UmJ27VzJyBA9ZFpaWmXuNtUKBTk5DxOznH3bhympmbPfGgfn+c1xeUwd247unQZQ48eE/jtty/p3v1jdezsw4chzJ7dkoULT2Fr60Zycgy+vvvp3btiCWNSUmI5eHApHTqM4MaNv7hx4xgPH4aQk5OJrq4hTZu+zTvvfFGlta5VSo8SPT0zrl37g1u3/iUjI4ns7HRMTR3w8hpCnz7TKqzEPImtW4v/lpUVRFzcAaKjd5OdHYyBQTtMTPpgZTVGvdvPzAwkOHguTZr8+oRwPEZi4r9ERm5Sm+KNjLphbNytcDdd8YqASUknSEr6h4iIjcjl6YUCygszs35YWn6AVGpRZBcWEDAOUBUPMjXti4PDHHW44ssIH5+i35KHxxFycsK5e/dxBjorqzHqcsz16y/A2PhtLl9WJYBq0OBrbGwmcu6cjVopKQ9NaTAzexdHx0VcudLpibTKAtzcfiQiYgOpqeexs5uKtfUYLlxwe0IgOiOVmpGScu45TN9p+PuP4eHDX0t89jfeCMfP7wO1IvMs+vIJ2ufNya7k6tUu5OXF0rr1dYRCzQrdPW5c6dfi4oLL5Yn/IhEXF8ynnzagVasBTJ/+vwrf37hxFJ6ejuTm5iIQCEpMN69ScvLJy8sDwNm5Ef/95//SjMHUqeO5dy+Q338/VeF7DZ/S\");\n    result.append(\"F/r27YudnR3r169X/7Zjxw7GjFGlbl60aBHHjh3jv/9UWWHnzJnD+vXriYyMRE9Pr9w0FbIA+Pq+vDG1EokmU6b8xLx57YiPD6Njx5FFEmeYmdVj+PBvWLt2OEuXXuKffzYycGDFQygMDCzUcbGOji3UMa/ViXbtHhe1cXfvWmNjqq3tTL1686hXb16pNDo6DYsIfwBj47cxNn5b7ZhXFTAy6lJYEnjZM2mtrT/C2vqjV9y4XPyI48kIh6edCNPTbyAWy5BKLdTCvTw0JZoDxXq4um4nIGD8UzUVlAQFTUVHx7XUPmZlBZGTE1Gtz65QZFWIviYQHr6GlJRztGx5vsLC/1l42YW/an2tj6amLvXqNavU/ZaW1sTE5LyyX+vVqxfZv383p09fq5L2hMLi1uOhQ4c+YS0rak1t2rQp6enpxMbGqoV7eWjU/KgFsLR04s03x3Ht2p9YWDQodr1z5zGYmdVjyZJueHkNQSSSUIc6vArQ1W2Cjo5LiddEIm2srceSnHyy1AiI8tA8golJH8RifZKTjxe7lpcXp05nXMyMKBBjYTEUhSIbPb3meHr+g6PjV7Ro4Yub2z4cHObg5RWEldWHdOyYUCS7Ytnf9QdlpvwtjV4o1CzG095+Om3b+mNjM5433gitEkUxK+su9+/PwcFhFnp6LV/L+SkQCLCzc8fBoelr9+xyuZypU8czYcJUnJ0bVQuPW7ducffu3VLmXxbbtm2jc+fOODk5VYqmVigAERF+mJs7Ym3diH37ZpVI07PnJHJzM7G1daMOdXiZoafniYPDLOrVm4u7e/EdrVRqioPDbN54I4yEhKNcv/4WT0YdlJfmaWhpORQK+8Rn9lEiMSnMyjcLD48jSKXmAKSlXUWhyEVT05br17vx4MFCkpL+RlPTjtTU81y50r7EWhKPd5T9cXCYhaPjEurXf3ZCrZLoFYqcYjwjItajoWGNQpHH5ctexMcffq53pFTKuXPnA3R0XKhfv6hFMS3t8jPHujbBysrllbBWVDW2\");\n    result.append(\"bFlDWloq06c/tgY/fBj73O1eu3aNZcuW8eWXXxbZ/T9CfHw8S5cuxd7enp49e/LXX38VO5YvDw08Ry2AlwWpqXFcuXKYAQPm0LJlP6ZPb0KTJt1o1qzn07pqnWSpwyuBtLRrhIaqjjwSEv4sYTceT2joUgwM2mNg0E7tjFdRmqeRm6tavMRifQoKksukzc9PUPdRKFyFmdnAJ3ZGmaSnX0MuzyIrKwgdnYYoFDlkZgY8sw8PHx5Sn+lnZz+oNL1cnlmMp0KRTXr6NXJzo5/7HYWGLiUj4watWl0pVhkyJmbPa2UR0NMzrbGaJC8LoqMjWbp0ATt2HCgSEffnn4eeO3uhp6cns2apNrK9ehVP825qasrs2bM5e/Ysvr6+TJkypVI0r7wF4OrVP5g/v4M6IYZEokHDhm+wdu1wzp3bp6bLzEzh1q1/SUgIJzDwHHWow6uC9PTrpKffKLEAkb//GAwNO2FpOaLU+8tD8whJSf+iUORibFxygq8nHS6fhEKRR2zsvgoVSSrfIqvy9C5vuxWlrywyMwN58GAxGhpWhIevwd9/bOHfaC5ebEZubtRrNUd1dAzQ1NR9rZ557txpaGpqcunSeXUegAkTRnHixN9VyqdZs2Y0bdqUzMzi4fE7duzg1KlT7NlTeljxs2heaQtA8+a9i9TH1tDQYcqUn0qcoEOHfsXQoV/VSZQ6vOQQlCB4zTE27k5MzB4EAqE6zDQvL5aAgHG4uu4iNfUiWVlBqhbKQVMScnLCCQn5Eienb0hLu0x2doj6moXFUJKSTpTaR4FAhLX1OMLDV5eytxBW6tmNjLqQn59Cevq1CtGrHAaF1bLn0dFpSNeueXVT9Yl1t6SaBbUZO3YcqJZ2lSUE5cXFxfHPP/8wYsQIFAqFuhSwhYUFW7duZdSoUbRu3RpnZ+dChfzZNLVCAahDHWoTjI17oKfXHG3tBjg4zAaUiETaWFgM58qV9shknhgZ9UBb2xkTk16FOQkOYmLSh+bNTxAcPJ/MTP9n0sTG7kWh\");\n    result.append(\"KDl1dEjIl+TkRNC48R5ycsLJzn5AQUEycXG/kJcXh0zWFBOTnmhq2lOv3jyUynwEAgnGxj2IjNyAru7/2TvvuCrL94+/z4HDlD0EGYIg4iAHguLelpor98AytCxLzVXOMtNSy4a/0kzN1CL3yPymGTkKQVFQUZbsLRvZHM7vjwcOHDYKgnk+r5cvD89zP8/nnPsZ93Vf93V9ri60auWERGLCw4enyM+PxtR0EqqqOrRp8yrx8T9W4VRR0cHUdCKqqrq0afMqWlr2csPHwGAAPj7O6Om5oa5ugZHRS+TkBGNkNKLG9r6+vbGxWanAaWT0EqqqBpibu5f+pgzlDddI0NLSeyqFwP7r+OOPP/Dz8yMsLIzNmzcjEonIzc3l4MGDXLlyhZs3b/LHH38QEhLC2bNnefHFF5kwYQJnzpxhyJAhbNiwgU6dOtXZZubMmairqwsmdH10AJoST6oDoMSToTodACWe5v2vjE1pTjy5DsCToTYdgGcF3t5HcHOb/Jj9/3zffwbNXEtPJJPJmjlc9Ugzs09uVv4poud7AGj22+85h+h5v/+aeQQafqGZO6CZv8CwYZ81K39ZsN3zimdyCeDy5fvs3fsXV68GkZtbiJmZPhoaEkaN6o67+0BiY1Px8gpk9eqmkQS9f/kyf+3dS9DVqxTm5qJvZoZEQ4Puo0Yx0N2d1NhYAr28mLh6tXKEUUIJJZRoAB4+fIifnx9+fn5kZwvqn5MmTaJnz/rVWPn111+5dUuQpG7Xrh0dOnSgT58+SCRK/ZfKeKYWbrKz85g6dTtDhnxE69b6eHl9SHz8Lm7e/IyLF9dhbW1Mnz5rGDBgPamp2Y3On5edzfapU/loyBD0W7fmQy8vdsXH89nNm6y7eBFja2vW9OnD+gEDyE5NVd5dDcCePXvQ19fH19f3ueRXQgklBJiYmPDiiy8yZcqUCpO+y/XyFmZlZXH79m0A1NTUeP311xk4cKBy8H/WDYDMzFx69VrF0aPXOHZsKZ99NhMrq3LJX01NNdzd\");\n    result.append(\"B+Lt/Qnm5gakpTVu1cDczExW9erFtaNHWXrsGDM/+wwjKyv5fjVNTQa6u/OJtzcG5uY8SktT3l0NgKamJvr6+vLglDKEhoYyefJk+vTpQ7du3VBTU0MkEiESibh79+5/hl8JJZRQhKmpKSoqKqioqJCcnMz9+3XrSFy9elUuhaujo1NFFrclQVUVPv0Uvv0W1NRgxgz46y+wtIT//Q/efRcmToS1a0FPT9i3bBns3l01dmLjRihbzdPVhQsXYMECKFMWLjt+9Woh7uSHH8DY+BkyADw8dnL/fhweHkMZN65mkQ0rKyN27ZpPenpOo/Lv9PAg7v59hnp44DJuXI3tjKysmL9rFznp6fU+d9++fTl27FhpZcFITp8+zeHDh7l+/TqHDx+mf//+8rY6Ojq4u7uTnJxMZmYmP/74o/zfiRMnKCoqQk1NDQcHBzZu3IhMJiMuLo5Tp07h5+fH+fPn6du3b4viB5gxYwaRkZF07dpVvi0wMBBnZ2eGDx/Ov//+i7+/PzExMUyYMKHR76/m5v8vws7Ojl27dnHixAn5tiVLlnD48OHngl+JJ5ydisVIJBK6dRNkhi9dulRr+4KCAq5fv46Li4v8+JaM4mK4exdu3oTCQvD1hfBwiI2FsDBhwD5+HLZvh8xMCAmBkyeFv5cuLT+Pvj688AIMHFjmBYHgYLhyBUqzAeXHHzsmBH4fPSqc55kwAM6du8XRo0Jlo+XLx9bZftSo7lhbGzca/61z57h2VFAbG7t8eZ3tu48ahbG1db3P/88//7B9u5A/vXDhQsaOHcuUKVPo378/0dHRXLp0iSVLlgCQnZ3NTz/9xNWrV0lISODVV1+V/5swYQJLliyhVatWhISEsHbtWkpKSjhw4ADjxo2jd+/eFBUVcfHiRbp06dJi+GvCtm3bMDU1ZX6FUOnWrVvz66+/KgzUTYXm5n9acHNz48KFC8hkMjw9PfH09MTb25txtRi69UFCQgJSqRRNTc0Kz/I5du/e3aL4lWjZGDBgACKRiKio\");\n    result.append(\"KKKiomps5+vri62tLaampv+J3923L7z2WvnAXoa2bSE6usJ40x08PKAa1eAaceECDBnyjBgA338v5Aq2b2+Ovb1ZvY5Zv77xovv/LM2VM2/fHjN7+3odM3n9+gZx5OfnV7tt2bJl/PLLL2zdupUePXrI95WVxqyMvXv3kpVVVhVORlFRkXxfUVERX375Jerq6sycObNF8VeHpKQk4uLiCAlRFK+RSCS8+eabTX7fNTf/04K3tze//ioIm0ybNo1p06Zx7Ngxjh8/ruD9aShyc3OJjY1V2BYUFMSFCxdaFL8SLRutW7eWC9jU5AUoKSnhn3/+eaL7pbnQrRuMH1/Vrf/PP7BvHyQllW8bOxbeeUfRA9ChA/TpIxgGreopyCiTQX7+M2IAeHkFAtC5s2W9jzE21mk0/kAvoQqaZefO9T5Gx7jxPBAbNmxARUWFd955p9Z2r7zyCqamphQXF9dy4WXymXxL4Y+NjeXjjz/GxsZGXsMa4MUXXyQ/P5++ffvi6amo8Dh69GhatxYK0Hz++eeoq6sjEon48ktB837//v2YmZkhEomYNWsWoaGh8sHG0dERNzc3+eDQ3Pwtwx1ZXMWQE4vFTJ069YnOW6ZI1tL5lWj5XgCA+/fv8/Dhwyr7AwIC0NHRwdbW9pn7bf7+gmu/Jk2cu3eFdX2A06chMVFw+QM4OQnHnjwprOtXiJuUQ0sLjIwUtw0ZIngBGmwA3Llzhw0bNmBraysPhmrbti0fffQRd+7cafTOSUnJJjMzt3RQ133qFyc7JYXczEwAdBtxUG8IgoODSUlJoXfv3grbzc3N5evvp06dqjJIVYaGhgbLly8nMzOTgwcPthj+wMBArly5UsW9t3DhQmbMmEFKSgrTp0+nd+/eXLwolKq1srLCxMQEgKVLl8qLXQwfLujYz5kzh48//hiAqVOnykthurm5YWZmxunTp7G0tGwR/C0ZZYbaqlWr2Lp1K99//z0nT55EU1OTdu3acerUKfz9/QFwdHTk77//5rfffqv2\");\n    result.append(\"XB07dmTv3r0Ka/ItnV+JlgE7OzssLCyQyWRcvny5yv4rV64wsLKvvIVDVVWY/XfqJAQBdu8OtrZgYQF2djBqlBAEuHkzqKiAoyP06CF4AD76CMaMEYICy4L/MjNh8WKhXYcOwpKAuzt8+aUQC+DoCC+/DJMnw4gRsGLFYxgATk5OrFu3jv3798u37d+/n/Xr1+Pk5NTonVRYWD4z0NRUe/ozowqubrUKa4lPG6mpqVXWtiquwY8bN45PP/202mNdXV1ZvXo1P/zwAyEhIfTo0YPoiotIzcw/cuRIRo0aVeU4sVjMoUOHOHToEJaWlvj4+DBs2DBGjhxZxS3/5ptvIhKJOHTokHzbpEmTEIlE7Nu3T74tKCiI9u3bywfvlsDfErF48WLy8/PZv38/jo6OrF27luXLl/PGG2/g5ubGsGHDCA8PVxhMg4KC+OOPmouhhIWFkZWVpbAm31L5lWi5XoBbt24peBDDwsIoKCigcwM8tC3D6yYM4O+9JwQBHjkCQ4dCXBy89BJs2SIEAS5ZAunpMGgQHD4MOTkwfDj89hvMmQMJCcL5LlwQPANBQcL+1avhp5+EqP+y47duFXhWrBCCBR97CcDCwkL+2boBAW8NhaFhK8RiwcR5+DDrqV+kVoaGiEqjSbOqcT09LRgYGJCSklJrm7Nnz1a73dfXl08++YRZs2bxzjvvEB4e3uL4K6ffVcSMGTMICQnh008/RV9fn/Pnz9OzZ08Fd72trS1Dhgzhp59+QiqVAnDy5Ens7e05c+YMCaVPyZ49exSC+loKf0vBwoUL2bx5M6ampri6uhIUFERYWBgjR45ELBbz0ksvIZPJ0NWt3htXW652UVERSRUXNFsA/8W0NCYEBCD680+0vbxIqxCzUh3WPHiA6M8/sbpyhe9iY+tsXxfSLqYRMCGAP0V/4qXtRVFa7ed7sOYBf4r+5IrVFWK/i62zfV0QKht+yF9/afDnnyJCQhbXeUx8/I/8+aeIixdVCAv7gMzMa0/l3nRycsLAwIDi\");\n    result.append(\"4mKuXi2v6nr58mX69ev33KtaPg4e2wComF/ZlOkWGhoSunQRDIx7957+mqlEQwPr0oj12Hv3muUi2dvbY2pqWq3rqyKuXbtGZGTkM8lf3cNbJugheH80WblyJWFhYYwbN47s7GwWLFig0H7evHnExcVx/vx5ZDIZR44c4ddff6W4uJg9e/ZQVFTEnTt35GlCLYm/pWDHjh188MEHvPnmm/IlveLiYgwMDPj000+JjIwkJSXlsV+2dYm5PG3+oYaGeDo5oSISkSuV8n1czaV8C0pK5PvnWliwwNISwycUmDEcaoiTpxMiFRHSXClx39fMX1JQIt9vMdcCywWWSAyfjF9b25F27T7EzEwIIY+L201RUW2GvoyoqG0A6Oj0wN5+M3p6vZ/OYCUW069fPwB8fHwoKCiQB+rWVyVQ8XwlzZ6Hr/h9BPe8VCrM0vfuFb5HPePOFTBlipBKWD45g+peO89EEOC0aX1KX8hRREQk19OyLWg0nfk+06YBEHX7NskREfU6piAnp9H4V61aRWFhoTxVry7Mnj27Ufu/ufh3796tkEUAYGRkxOHDh7GxscHf318heGzChAkYGRnJ13lHjx5N9+7d6d27N7t37+bUqVMNSi1rbv6Wgr59+/LZZ5+xcuVK7lUygqVSaZOLrTQ1v7pYjKOWFsYSCTtiYiiq4bn9OTERy1JPkU4j/maxuhgtRy0kxhJidsQgK6qeP/HnRNQtBX4Vncbtc4nECF3dnkiluURHf11ju4cPf0NFRVhCUVXVe+r3oouLC1paWuTn5+Pj48Ply5dxc3N7LKW/khJxs+fhK34fYeBPTYXPP4e5cyEmBn7+ueH9dOaMYMiU4d13hWDDZ9IAeOutkVhYGJYORr/U2b6oSMrKlQcV4geeBCPfegvD0iWPX1atqrO9tKiIgytXKsQP1PlJX/OeAAAgAElEQVQSqsYFraqqyvr165k1axYeHh4KLz+JRFLtTT98+HDMzMzks1qJRFKvNc/m5q8O2dnZCmvqZVBTU8PK\");\n    result.append(\"ygobGxtUVVUVts+ePZvTp0/zf//3f8ydOxeA+fPnEx0dzQcffFCv9MOWwv80UfY7Kv6eMvTs2RMtLS10dHTo0aMHxsbGaGlpYWtrS2JiIra2tlhYWNCxY0cGDhyIiYmJ/N4oCxSu6Gmpbvbe3PwaKiq8YWlJXEEBR2pYptgZG8uCJgrcVNFQwfINSwriCkg6Uj1/7M5YLBc0XeCopeVbqKjoEBu7A6m0+iyhqKgt2NisbLb7VE1NjV69egFC4F9gYCBubm5NZHg2fR5+9YZJ+eerV4UgwYYiL0/x7wcPoLrVqmfCANDT08LTczFaWup4ev7Dhg1Ha5xdFxQUMX/+LubNG4a6euPoP2vp6bHY0xN1LS3+8fTk6IYNNfIXFRSwa/58hs2bh6SWdeWK6NevHytWrABg06ZN7N+/nx9++IELFy5gZWVFjx49OHDgQKnbTYd58+YxZMgQbG1tOXLkiDwS/8yZM/z222+cOXMGBwcHNm3ahFgsZvz48cyYMaNGK7m5+aFch6CyvsDChQsV1tUBfvnlF65du8YXX3xR5TweHh4UFhYyZMgQueExdepU9PT0GDBgQI1rx0+b/+7duxhX8AE+fPiQRYsWsXXrVlxdXZk1axZFRUWsWbMGMzMzYmJiuHbtGnp6enz++efyY0aPHo23t3fpzCNLno1QhsjISPr378+YMWPYsGEDQ4cOJTAwUKGNm5sb00vfXsuXL8eqgsQ1wLFjx3j06BF3796lZ8+e/PXXX8ydO5ecnBwuXrzIxYsXuX37Nq+++iqXLl0iMzOTgQMH0rZtW0aOHEnXrl3p378/tra2DB8+HCcnJ4WMkubmL8PblpZIRCK2VxMgeyk9HQdtbczr+Uw/1gD8tiUiiYjo7VX50y+lo+2gjbp50/FLJAZYWs6nqCid2NhdVfZnZv6Lioo2rVp1eyrv/ZKSkmrfs3379kVVVZXs7Gy6du2KtrZ2Fa8Q1L/SaHPm4deFIUPK0wM3bxai/M+cgX79hKWGXbugLKFq6VIh\");\n    result.append(\"ZbAynJ3Bx0c4porh/ay4Ifv1c+TcuVW4u+9g/frDnD8fwIIFI3B1tcfUVI+UlGy8vO5y+LA3GzZMpWvXto3K79ivH6vOnWOHuzuH168n4Px5RixYgL2rK3qmpmSnpHDXywvvw4eZumEDbRugFHf16lWFoJa6ZqW7d++ul5rZBx98wAcffNDi+X///Xd++OEHALZu3Yq2tjbOzs4A5OTkMGfOHN577z3s7e3Jzc3F1NSU8+fPM2jQoCrn6ty5MyNGjODtt98uN+C0tJg9ezazZs1qMfxRUVGkVigYtWPHDvr168fkyZNZuHAh27ZtQyKRsHr1ar777jvU1NTo3bs3s2fPlr/gTExMGDRokHwGdOjQIX7++WfWrFkjNy5sbGxwdnbGxsaGxYsXs379epYtW8a5c+fk3N7e3gwdOrTG6xMbG0unCtOQ70uFscpQeVmjYjZI5T4aUs20p7n5y2Curs6U1q05lJjI1YwM+unry/d9FRPDKhsbEhvg1WvwUoS5Oq2ntCbxUCIZVzPQ71fOH/NVDDarbChMLGzS96y19XvExHxDdPQXWFm9g1isXsGY/Awbm6dXPjcjI4PCwkIKCgoUPJStWrWie/fu3Lhxo1rhn4yMDPm7qqSkpM4YtbI8fHt7qC6UoHIefpcugsv/33/L8/ATE4W0vilThLV7hQmkFlR2gpbl4deEF1+EwYMFT8O2baCtLWQIuLpCWprgmXj9deEc48cLx5w6JWyvDD+/Wjx/PEMYMKAj9+59wb59f3P8uA/Llx8kNTUbIyMd7OxaM316X44dW4qOTtOk+XQcMIAv7t3j73378Dl+nIPLl5OdmoqOkRGt7ezoO306S48dQ1NHByXqj1GjRlWbhlfmWWgoqksF++abb1oU/9ChQzE0NKwwC+nGokWL0NLSYvTo0bi7uwNC8OGECRPw9PSU7z948CArVqzA39+f7t27y2dL6enpzJgxg127drG6hlLUjx49ok2bNsqbrgYssbbmUGIi26Oj5QZAZF4eqUVF\");\n    result.append(\"9NTV5bc6MmGeeABeYk3ioUSit0fLDYC8yDyKUovQ7alLym9Ny6+u3gYzs9nEx+8hIWE/FhbzSw3h+xQWJmNgMIjc3LAm/Q4pKSkEBARw8+ZNZDIZe/fupVOnTvTs2VM+2x8wYAB5eXkKXrTg4GBCQ0Pl2TkFBQXs27eP9u3bVxsnIBaX0K2bEHxXUx6+gwP07w8bNijm4Z88CV99JQTtvf9+mYcE1q0TDIOyPPzgYGHmvXJleR6+k5MQkFfqdK0W//sfXKuUXNG/P0ydKhgBDXVEVV4SeCYNAMGaUuftt0fy9tsjm4VfXUuLkW+/zcgKM7zmRIcOHVi3bh3+/v5s3br1qXL379+fr776ivbt23P79m0WL17M9evXlaNIDUhOTmb8+PHY29uzaNEi+SAPQgChVCrlrbfeol27duzaVe6CdXd3Z+nSpSxYsAAzMzOkUin+/v54eXmxaNGi0pnJacaOHYuWlhaDBw9m5cqVCuvpgYGB7N27F11dXdY3UKb6eYKzri599fU5+fAhEXl52GpqsiM2loVPSbRJ11kX/b76PDz5kLyIPDRtNYndEYvlwqcnGmVjs4KEhH1ERm6hTZvXEYlUiIraQtu2K54Kv7GxMUOHDq3VK2RiYlLFo9ehQwc6dOjAmDFj6sVTUiJWGISPHBH+gZCHX4bjx8u8SeXbSvW+qKg5VZaHX3E/CLn4lY8v46kvtLXhl1+EWb9UWj7rf9I4c7HykX92YW5ujouLCxMnTnzqZS8tLCzYunUr3377LcuWLaNt27b88ccf8gDApkJAQAATJ05k8eLFvPjii7i6uvLXX38BwtrfqVOnGD16NG+88QaBgYH07duXVq1a0a9fP7liXEORmprKvHnzeOONN5g5cyaOjo4KM/rr168zb948unfvTmZmJtOnT0dHR4eOHTsqqCNmZ2cTERHB9evXOXjwoFwbACAmJoZJkyYRHBxMv379GD58uFzGtn///qSmpvLll18yevRoZs+eLRfiKnNvXrhwgRs3bnD5\");\n    result.append(\"8mUMDQ05duyYwm/o3Lkzc+fOZf369TXGQSghYLG1NSUyGd/ExJAjlXIhNZWJT7HAjPVia2QlMmK+iUGaIyX1QiqmE58ev5aWAyYmE8jLe0BS0mEKCuLIyvLD1HT8f/J6W1gIbvKlS4WBdelScHMTZumZmTBrFuzZA6++WvXYb78VVPrKYGgoqPTNmQPe3oIrv1s3yMgQzj1+POzcWcegLFY8JwgBiSYm8PAhtGkjtGnVCrKzy6P9u3atutRQF1SVj/uzi4SEBA4ePMjatWufOveQIUMYPXq0fB3bx8eHW7duMWLECH4qM3kbGbm5uQwdOpR33nlHPovt1asXM2fOJCEhgdDQUKKjo/n9998ZNWoUn332GYsWLSIgIIDPPvuMgQMHcufOnQYLV82ePZu8vDy8SmtCrFy5knfffZdhw4bRunVroqKiOHbsGPr6+ixfvpwRI0YwcOBA1qxZw/Tp09HQ0GD8+PHY2dkpDPojRoyQfz569CivvfYa+vr6fPzxxxw4cID8/Hy0tLTk9QTOnDnDihUrmDVrFu3bt+fff/8FBGW00aNHy5cxzMzM2LBhwxPr6Jdh9OjRbNu2DSMjI/m1FYlEdOvWDX9/f5ZWjIiqzyxXV5eFCxcyePBguXTy0+JXU1Pj66+/ZsqUKTx69EjItaqECSYmtNXQYE98PKZqasw0N0flKYrMmEwwQaOtBvF74lEzVcN8pjkilacrcmNj8z7JyceIjPyUrKwbWFsvBv6bQjtxcRARAZcuwY0bwjYdHWFwTU8Xguz+/hsCAqDiimDHjmBuDhMmCGl9ICwbFBbC/v1CsF63bkKMQUaGsGwAUKomXu3A/8orgm7/pElC2mCZ9tzNm8L2P/4QvA5du4KVFVy+LAQHXrsGO3YIrv6+fYXURHV1GDlS+G329sLnf/9VzDJQGgD/ARQ9oRrZ4+DXX39ViJj39/cnPT2dgoKCJuPMy8tDKpXK170BevToga+vL7m5uTg6OtKuXTveffddcnJyOH36NCoqKkyZ\");\n    result.append(\"MoW8vDy2b9/Ojh072LJlS4N4MzIy6Nu3rwInQEREBB07dmTSpEl88cUXBAcHs3HjRrlkcps2bRg3bhybNm1i/HjF2dOJEycUqtKlpqbSu3dvZsyYQUFBARs2bEBLS0u+393dXe5dsbS0ZP78+XTv3p2EhAQWL17Mxo0bFVyo3t7ebN26lYkTJ3Lr1i1iYmKYNm3aY3lozp49y0svvUS/fv1YtmyZfLtIJKqzQFR1sLOzw9LSst5yyI3Jv2TJEm7dusWOHTuYNm0aZZESFSPGVUQiFlpZsTw0lM2RkURWuPZNhYr8IhURVgutCF0eSuTmSPpG9n3qz7eubk8MDYeSlnaR4uIM7O03/+ffo25ugjfAza18Xb8M9vZQWs9LYdvrrwt5+mUGwLlzgn5Ax45CPECpcxIVFcEbYGwszNyr8wKU6QBUtzyQkiLEI5ShYkhRabwyUJ4RIDwf5Z9rWsF6bAOgYpWtiilSSjwfqJwu16pVK6RSaa1a7E8KIyMj0tLSEIlEhIWFceDAAfksuLCwEC0tLblL3N7eXmFZ5J133mH79u34+Pg0mPeff/5BJBKRnp7OgQMH+N///lelD8RiMQYGBgr1EsaOHYu1tTV+fn5VBGtaVcoX2rhxo8IgXhn29vbYV5AE++qrrwBhGahyidSePXsqDCg1lVBtCKqr8CiTydizZ0+Dz3Xr1i2uXbtGnz59njr/rVu3OH/+PABr1qxh9bBhSGWyKtH9HhYWfBQezgwzMwwqBI9lln6PzOLiRruvZVJZleh+Cw8Lwj8Kx2yGGRKDcv7izGKF/xsLxcWZFBdnVvECpKVdxMrqXcRiNYW2wv8Z/6l3mre34AFITy/fJpEIyn1TpgjFd8pgaiqk/amoCDN+V1dBSCg1VcgkWLBAEALy8BCMAqlUCOwDKC1pUCPatoVPPxVSC8uSrUxMBDXB6pYhqjeyhXP88IPgNagJjx0DEBMTI/8cHx//xJ0fHp7EypWHEIunYmW1AH//SAAePEhiwID1jB69mVu3\");\n    result.append(\"Ijh58jqtW89DVXUax4+Xv8yDg+Pp2HEJr7zyOSEhCTx4kISDwyJWrDjImjWerFnjSf/+61BTmy4/d2XscHdnh7s7nmvW4LlmDQdXrGC6RMIXkycT6e/Pql69mCIS8eu6deQ/egQI1QK3T5nCUicnAv/+m1AfH7aMG8cUkYhPXnyR1NKSr6HXrvG6sTEHli+Xb/svYcaMGXzyySfyFJymQkxMDNOnT+fAgQNyN3J90LZtWyQSyWN5KPLz81mxYgVLly5l2LBhDdLyt7e3p6SkpIqXxtXV9Zm/5m+++SY5OTmYm5uzbds2bt68yZw5c0hJScHd3b3KtorBWY1Rpvdx+MsG/zL8nZ7O/Pv3iS8oYGlICNdKK3/qq6ryWps2LCrVJCiWyfghLo4tpVLX+xMSGqUWQPrf6dyff5+C+AJCloaQeU3gV9VXpc1rbbBaJPDLimXE/RBH5BaBP2F/QqPUAsjNDSEq6nOSko4SFbWtVApYGAENDYdhaDgcS8s3ykwV4uP3EhYmRM5lZ9/iwYN1ZGZeo6gohVu3RhIT8zUxMTsIClqAl5cuubmhte6riLi4OL777js2btzIb7/9xo8//sjBgwfJzFQ0TAoKCqrEuACkp6dz8uRJ3n//fY4ePcpff/3F6dOn+fHHH7lbXYJ8Dbh8WfAECN5VYRB++FAxiK9vX8HlfvKkIBW8ZImwfWRpbPrXXwtZANWV5614/uoQFSUYDTExgsTwxo2waBH8/ntDDDqwtlb0AjSKB+DOnTucOHFCocLZnDlzePXVV5kwYcJjVwRs1641n302ExMTXdau9URXV4hm0NHRwMHBnF275qOiIqZ7d1tUVcW8/PJnmJmV58na2pri7NyO/fvfRkVFzLVrofz22/s4OJiXGinpfPfdeT76aArdutlU+x2chg5l4Jw58r8Pvf8+uiYmzNu5Ex0jI5YdP857nTujpqmJRukMTsfYGF1TU9Z89RUG5gLX8pMn2TJ2LMkREeiX1owvzM9n3MqVjF2+/D83+JuY\");\n    result.append(\"mNCzZ0/eeOONJuUJDw+nV69efP755woR9PWFSCRqcL3woqIiBg8eTKdOndhbmuBbuRJgXZxmZmZoaGgobNfT06tSXbGlw9zcXJ5j3759e3R1ddm5cycpKSk8ePCAefPmER8fz9tvv82NGzfQ1tZW2Pak5cIbm18kEjHIwIBBBgbsqUZu7esOHcpflCIRHhYWeFR6c8uAgwkJLAsNpb++Pvs7dyZbKmXy7du8bmFBb11dNkdGsj8hAR9XV1x1dfk+Lo6zKSl84eCAwSADDAYZ0GlPVf4OX5fzi1RFWHhYYOGhyF+SX8KDtQ+I2BhB99+7Y/SSEcVZxdyZdgf9fvoYDjEkcHYgmvaadDnUBYmhhLQLaYQsC6Hz/s7oaDnQtu1S2ratPo6iR4+KBpOINm3m0qbN3GqM5Bi6dDmERGKMVJqDr29POnbchZZW+1r3KXg9LCzkXq4xY8ZQUlLC999/Lzf2y+Dn54efnx/Dhw9XCGg1MDDghRde4Nq1a4wfP16eBRMXF8f3339PWlqavKKg4n0FNjaCi97SUhg4k5OFtXNjYyFt79VXhTV9U1O4c0dYoz9/XqjMl5MjBPe9/LIwS//9dzh0SFij//prITPAyEhIGSwuFtICv/22Lg971W2nT9f/WYmKErQJ6kKDDQAnJyd5SeCmwNKlY/jjD39ef30n58+vYdWqX9i2bTYqKuXOijFjnJkxox9vvPE9N29uQSJR4fPPz7B69UR5u44dLdDTK19DnTv3WxwdLVixomYtdpcK67RBV69yZts2Vp45g46RkWARW1gwe+tW9i1aRJ+pU2ndrh33Ll2iXY8e8sG/7MXy1r59vNe5M8c2bmT4G29w7cgRXv+///vPDf4SiYSVK1eydOnSRqt9UBN+/vlnUlJSqi38UXlGWXmJIjQ0lMLCQiZNmtQgTh8fH3x8fKo1OOriLCkpISgoqEZOGxubZ+paJyQk8H7p4qhIJJK/A4qKikhMTCQjI0MhrqG6bS2Jf8aMGYoyb48BETDL3Bxb\");\n    result.append(\"TU1m3r1LsUxGcE4O79vYMKo0R31f584kFRZyNSODnjo6JBQUcMTJCbVGKKIm1hBj97EdjwIekROUg9FLRoglYgz6G2DzgXB/dTnUhdtTbiOWCHwFCQW8cOwFtOy1Gu3e0NAoV28MCnoTff3+8gJDte2rzmCW/zaxmHbt2nHp0iVkMhkikQiZTEZ6ejpWVlb4+PhUCSKtTvTHwsKCESNGcO7cOZydnasoByYkVC8ABIrKfhVidrlypfxzWJhi9H3FdfgyVJSGqVDBut545RWhjoCmplBQqEMHIQVQJhNiE8r+Li4WihpB/VIEW1waoEgkYs+eBfj5hTNkyEe8/fZI9PW1q7T76qvXSErK5LPPThIcHE9JiYyOHS0qzLDKb+4dO/7H1atB/PTTQgVDojK09ITiFnnZ2exwd2fovHl0r5gQCgydNw8HNze+f+MNigoKuHLoEIOqkV/SMTZm3s6dnNi8mb3vvsuMzf+9IBoVFRXWrl3Lli1b5PW5NTU1m6w6pHmpkbVixQrOnz/P6tWr5S/348ePc7QsEgdBJ7xizfCPP/6YUaNGMXHixAZxlgXNbd++nbNnz/LNN9/IiyJdvXqV/6tg1MXFxSmkGu7ZswexWFxj3n3rUu/QswiZTMYvv/yi8HdlA7C6bS2Fv127dtjZ2TXa9+mrr880MzNeu3ePgEeP5IN/mZGwp1MnPo+K4oOwMDwsLBpl8K8Ix+8cidoWRV5kHrG7FGsG6Lrq0npya0LfD6UwsZCSvJJGHfwV3fg/kJ0dQIcOXzVoX3WQSqWEhYXh6OgoNwyCgoLo3LkzAwYMwMfHp97xZ506daK4uJjg4OBn5hlr00aQ/l2+XIj0ByHK39dXUCP08BCWHyr+/eGHDeNokVkA1tbGLFz4Il9//TsGBtWLKxsb6/D116/x6qvfcvduDPv3Vy/MExKSwMqVh/jyy1exs6vfC/fHxYtRUVXFfdu2ave/sXs3y5yc+GTkSObt3FljaVLXCROw69mTxLAw1LS0mqy/VFRU\");\n    result.append(\"mrQkc02c33//PT4+PvKoeF1dXcaNG9dkBW9mz57NH3/8wblz50hJSeHTTz+lV69ezJgxA29vb7777jt5WysrK9566y0MDAyIjo7Gzs6OH374ocFlZO3t7dm0aRNbt25l8eLFLFmyhIMHD9KzZ0+uX7/Oe++9pzCgf/vtt2hqapKamkpRURFXr15VUCurCP0KUrPPIkJCQtDS0mpy7YfG5jcxMcHd3Z2PPvqIj2oRm2ko1traYn75MnOrUVpso67Om5aWnE1JYfPj1HetA+oW6rT7qB23X7mN7RpbVPUVX+12G+y41u0aJQUldNzZsUmux6NHdwkL+4CePa8gFmvWe19l5OTk4OfnR3JyMp07d1Yo9hMbG8vw4cORyWScO3eO27dvK2QF1YSyoNtHpbFbzwLi4+HLL4XP4eHl23NzheI+WVnCP2trxb+feQMgPDyJ4mIpLi72eHjs5M8/q89znzatLx9+eIQePWyrLfxTXCxl1qyvGTy4M/Pm1e9Bv37qFJf27+fjq1dR19aufubWrh0DZs8mJToaC0fHGs/le+IEfadN4+jHH3Ny82ZeaeR8fT09PaZPn46trS1jx47Fz8+vSaPwK+LQoUNMnTpVXvGuDJ988kmTcaqpqXH48OFqXjyPKlxzITrawcFBru//pKiupkFSNa5jLS2tKjr1tcHAwOCZeRmJxeJqjad169bJr3l1YlQ1CVTVVJWvqflNTEzYtGkTW7ZsoW3bxq0Xsic+noNduvBWUBC3e/dGr4ISY1R+Phbq6hioqvJFdDTLGpkbhMyBoDeDMJ1QNbZErCnGfJY5MqkMkWrj5/NLpTncuTMZB4dtaGuXvxPT0i6ip9e7xn3VoWItjopITk4mLS2Nv//+W34tvb2962UA5OTkAEIxs2cRZTGPjT2PbHEGQF5eIRs3Hufbbz2Ii0vjhReWsXv3xRoHcA0NSY2z348/PkZERDKnT6+s5IpKk5cXrojM5GR2zZvHhA8+oH2FamGP0tJQ19JCUiGQS6KhgaiW\");\n    result.append(\"WXd8cDBhvr7M2LwZXRMT/u/VV3GdOBGrzp0bra8yMzPZuXMnO+uSlmoCTJs2jWnTpqHE48OoNLakpWPcuHGMHDmStm3bsmPHDvLz8xGLxXTt2pWcnBy0tLSYNGkSFhYWLFiwgJ07d2JqalplW5k73snJibFjx9Y7ILOx+PX19bly5QodOnTAw8NDOHk9hIjqg+PJyfTW08NVV5e/0tN5JziYn0qf9VyplJ8SElhra8swQ0N6+voyytiYTjVMMJoMTajjExy8EKk0l6KidKKjvwRkZGZ6Y27uXuu+huD27dtMnjxZ/r7Py8vjk08+ITY2Fss6pJrv37+PRCLBoWIyfQtGdbbxmDFw61aZQVzZQK7fOVq0ASCTyViyZD9r176ChoYEO7vWbNw4jaVLf2Lw4M7Y21d19ZWUyKpNKfL1DWPTphP8+utihWyB9PQczp27hYdHVYNip4cHRlZWTKoU4Oi1dy9jKrh6AWQlJchqSGXKSU/n2MaNLCjNUe47fTr/eHryzaxZfHLtWr3LBCvRcJSl+RUWFj513oZyPiuSvKdOneLUqVO1tpk1a5aCNntSUlKVbWW4c+cOkydPfur86enpOFby2Mkq14Bt6ISlpITvYmM5kZzM6dIKoIMNDBgfEIC1hgajjI1ZHhLCW6XphHqqqnTR1uaV27fZ26kToNdo1ynltxRkUhnJR5MxnaToBShIKCDLN4uSohIK4gpQt2jcd1CnTvuq2Srkxhkbj6lxHwRWGQOqi9t49OgRMplMYbKnqamJo6Mj//zzj1z1srpjk5OT+fPPPxk3blyVAMCWiLZthbLDjo6wapWQEWBkJBQrGjVKkCru1k34OzBQ2Fb2d5mB8MILwvHDhwulgCtqG7RIA+D69QesXv0LiYkZSKUlFSwbEdnZeYwZ8ylfffUaI0cKD1lxsZTff79FeHgSf/wRwIsvduOFFwS3WlGRlNmzv8HIqBU3b0Zw82ZE6Uu6iLNnb7JtW1XL89L+/fidOYPb5Mkc+egj+faHkZEk\");\n    result.append(\"hYfzcgUFslAfH+5dvkxWcjIB58/TtUJ46LWjR/ll1SrsXV0pyMlBVU2NnPR0dIyMuHH6NF9MmsSMzZux6tJFOVo3Mnx9feVBeWfPnmXHjh289tprTfrQx8bGsnv3bm7fvk1RURFr167l1VdfrVeA2bPwMlKidmiKxbxnbc17FeSlx5mYKBgW/7i4yD/rqaryVzXu7caA8RhjhsmqN2jUzdXperpri+7LuLg4QkNDSUpK4v79+/Lgv6ysLE6cOIGqqiqZmZnolQZrZ2Zmkp+fT2BgIFZWVnTo0IGAgABAqMipq6tLTk4OqampzJgxo1GDPpsSUVFCymBNeO894V9NfwveEiEzoE5Pg6ypc7fqxJFmZp/crPxTRP9Nfe2GeH2UaD6Invf77wk9AE+K4ReauQOa+QsMG/ZZs/K/X1nz93l7/mXDhsmUD0Dz4QLDUfZ/M/b/hSMo8fwa4M87Jh9p5glYc1/+Zv4Ck5v59yuLASmhRANx+fJ99u79i6tXg8jNLcTMTB8NDQmjRnXH3X0gsbGpeHkFsnr1RCV/E+D+5cv8tXcvQVevUpibi76ZGRINDbqPGsVAd3dSY2MJ9PJi4urVSv4nQMe0I3YAACAASURBVEhCAke8vTlw+TLBpXLv5gYGuA8YwKTevelZ6lI/df06XoGBfHf+PIWlWTiDOndmdI8evDViBFqPGfOUEJKA9xFvLh+4THywwG9gbsAA9wH0ntQbu54C//VT1wn0CuT8d+cpLhT4Ow/qTI/RPRjx1gjUtR6TPyEEb+8jXL58gPh4QT/AwMCcAQPc6d17EnZ2gnrQ9eunCAz04vz57yguFuKAOnceRI8eoxkx4i3U1bVa7LtMaQAooUQ9kZ2dh4fHTo4d82Hp0pfx8voQKyshkj8vr5AjR7zp02cNiYkZvPvuS0r+RkZedjY7PTzwOXaMl5cu5UMvL4xKg+sK8/LwPnKENX36kJGYyEvvvqvkf0I4mJuzeuJEXnZ2pmuphPmu+fN5uVIMwzgXF8a5uKCm\");\n    result.append(\"qsrW06cx1tHh/Jo1SGpIAa0vzB3Mmbh6Is4vO7O8q8A/f9d8nF9W5HcZ54LLOBdU1VQ5vfU0OsY6rDm/BhXJE/KbOzBx4mqcnV9m+XIhfmL+/F04O7+syO8yDheXcaiqqnH69FZ0dIxZs+Y8KiqSFv9OkxsAuVIpH4WHcykjg6KSEu7l5JBfGuWePXgwrVRUOJSYyO64OC6lp6MpFuOorU1eSQnqYjETTUxYbmODplhMUE4Ox5OT2RARQUFJCW01NDBVUyOpsJDuOjq8b2NDbz3F6FdprpTwj8LJuJRBSVEJOfdyKMkX+AdnD0allQqJhxKJ2x1H+qV0xJpitB21KckrQawuxmSiCTbLbRBriskJyiH5eDIRGyIoKShBo60GaqZqFCYVotNdB5v3bdDrXYlfmkt4+EdkZFyipKSInJx7lJTkC/yDs1FRaUVi4iHi4naTnn4JsVgTbW1HSkryEIvVMTGZiI3NcsRiTXJygkhOPk5ExAZKSgrQ0GiLmpophYVJ6Oh0x8bmffT0eivwK/u/efu/LmRm5uLmtprg4HiOH1/GuHEuCvs1NdVwdx/I4MFd6NNnDWlpjSs48rzz52ZmstrNjfjgYJYdP47LOEVJbzVNTQa6u9Nl8GDW9OnDo7Q0JX8jwcLQsNrPlWFWKmxlbmDwxIN/RRhWSNk2tKiZX78028vA3OCJB38FfkOLaj9X4dc3k3sJnoXBHypIAY8NCCCmoIBLzs749epFbP/+vFKpWMlMMzM2lrp95lpYcLNXL+65uTHH3Jz14eGMvnULGeCorc0qW1v6ld4QN3r1wtfVlX9cXAjJzWXAjRtcqHSDBowNoCCmAOdLzvTy60X/2P6YvqLIbzbTDLuNAr/FXAt63eyF2z03zOeYE74+nFujb4EMtB21sV1li34/gb/XjV64+rri8o8LuSG53Bhwg7QLlfgDxlJQEIOz8yV69fKjf/9YTE1fUeQ3m4mdnVCy1cJiLr163cTN7R7m5nMID1/PrVujARna2o7Y2q5C\");\n    result.append(\"X7+fwN/rBq6uvri4/ENubgg3bgwgLU1x7VvZ/83b/3XBw2Mn9+/H4eExtMrgVxFWVkbs2jWf9PScRn1Qn3f+nR4exN2/z1APjyqDX0UYWVkxf9cucmrKe1LyNxgqFVLvxLUEjZbtEzdyYKm4gny7SFzzucv21dbmsfjF5caESFSz9kvZvtratEgD4HpWFhfT0lhta4t66cU2kkj4uUsXHCpJD+mrKq4aiIAl1tZ01dHBKz2d31NSamxrqa7OJnt7imQyVoWFybdnXc8i7WIatqttEasL/BIjCV1+7oKWgyJ/ZYlLRGC9xBqdrjqke6WT8ntKjW3VLdWx32SPrEhG2KoK/FnXSUu7iK3tasRiYb1IIjGiS5ef0dJSFI5QVa0s3yrC2noJOjpdSU/3IiXl9xrbqqtbYm+/CZmsiLCwVfLtyv5v3v6vC+fO3eLo0WsALF8+ts72o0Z1x9rauNEe0ued/9a5c1wrrfNQn2qa3UeNwrhCWp6SXwklajEAkksFTK5UshrVxGJmVahyVxu6lOY0R+TlNbhdYbLAn35FkV+sJshX1gfaXYTz5kXkNbhdYWGywJ9+pZLlp4a5+az68WsLef15eRENbqfs/+bt/7rw/fd/AtC+vXm1YlTVYf36xgvvfd75/yyVVzZv3x6zeuroT66hAJOSXwklKhkAvfX00FJR4Z3gYDZFRFBcITd7sqmpfFZaG0JzcwHo3KpV7e1KB56K7fR666GipULwO8FEbIpAVlzObzrZVD4rrQ25oQJ/q8618+eF5lVpp6fXGxUVLYKD3yEiYhMyWXE5v+lk+ay0Vv7cUOG8rWqX+s3Lq9pO2f/N2/91wctLUCvr3Nmy3scYGzee5vjzzh/o5SV4sBogo61jbKzkV0KJOqAKgrt5X6dOzLp7l9UPHnAwMZEt7dszxtgYx3qole2MjcU3K4vRxsYMrqXASWJhIR+EhSERiRQqYkmMJHTa14m7s+7yYPUDEg8m0n5Le4zHGKPtWDd/7M5YsnyzMB5tjMHg\");\n    result.append(\"mvkLEwsJ+yAMkUSE/eYK/BIjOnXax927s3jwYDWJiQdp334LxsZjFIpX1Mgfu5OsLF+MjUdjYDC4Zv7CRMLCPkAkkmBvX14eWNn/zdv/tSElJZvMzNzSQe3pS/c+7/zZKSnkZmYCoNsMg9rzzl8ZE7ZuRV1SfYBbek5Ok/NvnbAViXr1/DnpT4F/6wQkkuonJDk56Y3Od+fOHU6cOMG+ffuIjIwEwNramrlz58pLm9e238nJqW4DAGBK69Y4aGkx7/59bmRl8bK/P8MNDdnVsSO2mlXLN3pnZLA8NJTo/HyKZTK+dXRkvkX1EZIbwsMpAcJzc3HT0+NXJyc6VFrbbj2lNVoOWtyfd5+sG1n4v+yP4XBDOu7qiKZtVf4M7wxCl4eSH52PrFiG47eOWMyvnj98QziUQG54Lnpuejj96oRWh0r8raegpeXA/fvzyMq6gb//yxgaDqdjx11oalYtWpKR4U1o6HLy86ORyYpxdPwWC4v51fOHbwBKyM0NR0/PDSenX9HSUtRpVPZ/8/Z/zUZDuTdCU1Ptqb9wn3f+4gr1FdQ0NZX8zYwTy5fTzcam2n1fnj3Lkv37m5R/+Ynl2HSrnv/sl2fZv6SJ+ZefwMamW/X8Z79k//4ljcrn5OSEk5MTgwYNYuDAgQDs37+fQYMGKbSpbX+9DACAbjo6+Li4sDc+njUPHnAhLQ1XX1+8XVywrzRguOnrs7V9+3qRrGvXDmNJ3WkROt10cPFxIX5vPA/WPCDtQhq+rr64eLugZV8pGM5Nn/Zb68ffbl07JMb14NfphouLD/Hxe3nwYA1paRfw9XXFxcUbLS3FtTd9fTfat99aP/5265BI6rbelf3fvP1fHQwNWyEWiygpkfHwYdZTf+E+7/ytDA0RicXISkrIevhQya/EcwmLCpM762oCPOvaXxPEILiGU4uKhA0iER4WFgT16cM4ExNSiopY8+BB084yEgspShX4RWIRFh4W9Anqg8k4E4pSiniwpon5CxMpKkoV+EViLCw86NMn\");\n    result.append(\"CBOTcRQVpfDgwZom5Vf2f/P2f23Q0JDQpYvwQN27F6vkf8qQaGhgXVo4K/bePSW/Es8lVCroKoiriQmra3+tBkBkXh4XK+WF66uq4unkhL6qKv7Z2U364/Ii80i7qMivqq+Kk6cTqvqqZPs3MX9eJGlpFxX5VfVxcvJEVVWf7Gz/JuVX9n/z9n9dmDatDwC3b0cREZFcr2NycgoardDR887fZ9o0AKJu3yY5on7ZGwU5OUp+ZaEtJepjAADsT0ioav2LxVhpaNCumrWnhtxc9WmbsL8qv1hDjIaVBprtngJ/QtW1I7FYAw0NKzQ12zU5v7L/m7f/a8Nbb43EolSBbNWqX+psX1QkZeXKgwrr50r+x8fIt97CsNTF+cuquvUbpEVFHFy5UmH9XMmvhBK1GAC/p6SwOCSER1KpfOfPiYmE5ubyYYU6ypmlxR7Si+t+uBvSNuX3FEIWhyB9VM6f+HMiuaG52H1Yzl+cKZyrOL3uczakbUrK74SELEYqLZcwTUz8mdzcUOzsPiw/Z3Fm6f91R3w2pK2y/5u3/2uDnp4Wnp6L0dJSx9PzHzZsOFqjUVFQUMT8+buYN28Y6uqNIwf6vPNr6emx2NMTdS0t/vH05OiGDTXyFxUUsGv+fIbNm4fkMYvQKPkVUVKBS1oqT16t4VG6r7Y2jwNZSTl/ibTmc5ftq63NY/HLys9XUiKtmb90X21tWhoUggC/io7mh7g4OmlrUyiTYSKR8LezM666QvrPocREvoqOBsAzMZFfEhMBmG9hwUobG9ppapJZXMzGiAi2R0cjLb1xFgYF8aalJRMrSdtWRvRX0cT9EId2J21khTIkJhKc/3ZG11XgTzyUSNTWKOHzL4kk/pKIXm892n3YDqORRvLzRG6OJGJjBNJc4ULcn38fq3etMJ1YB3/0V8TF/YC2didkskIkEhOcnf9GV9e1dEA6RFycIMqRlHSEpKQjaGk5oKpanvMslebx6NFtRCIVuSRkSMhS2rR5DVPT2quj1dT/nbS12RQR\");\n    result.append(\"wZcxMTwsteoPJyVhKJGw1NoaW01NfkpIYN2DB0Tl5zPG2BhrDQ0uZ2QAsDQkhEEGBnwSGcl2Bwfm1CAuVFP/S0wlBLoHknCg3EuQfCKZ6C+iMZlggqatJul/pxO6LJQsvyx0uunQ6oVWZFwW+EOWhmAwyIDITyJx2O6A+Rzzx+r/iIhP5PEASUmHycj4B4nEELFYndzcUIqK0jAzm46t7TqSk4+RkXEZAD+/IYhEYvr0CUMsfrxI9n79HDl3bhXu7jtYv/4w588HsGDBCFxd7TE11SMlJRsvr7scPuzNhg1T6dq1baM+qM87v2O/fqw6d44d7u4cXr+egPPnGbFgAfauruiZmpKdksJdLy+8Dx9m6oYNtO3aVcnfSIhJTVX47NyuXbXtokpVSBMzMiiWSlFtpHoAqTGpCp/bOVfPnxIl8GckZiAtlqKi2kj8qTEKn9u1c65hEiOMTRkZiUilxaiotPxaeyLZsGGP5R+9++gR/W7cILO4mGsuLvSqUFzmkVRKJ29vTnftSjed2gVBHqccfElhCdd7XSfbP5uOuzti4VE1/SxgfAB6vfSw+cCGRv8CQEDAOBwcvkBT005he3DwO8TE7MDO7mNsbesOXrvA8HpzZhUXM8jPj1vZ2Xxqb8/KSuk4Q2/eZKaZGXPbtKly7MmHD5kQEMCytm0Vsgca8vOD3g4i9ttYzGaa0eVgl6oD+JfRpF1Io+uprohUFfW4H558SMCEANoua6uYPdCAL5Caep7U1P/h4PCFwvb8/Ci8vbugoqKNm1sgEomRwn4fn248enSXgQPTUFVVzGW/cKFh9dBzcwvYt+9vjh/34f79OFJTszEy0sHOrjXTp/dl9uwB6Og0XbrWf43/CA1TDCzIzeXvffvwOX6cuPv3yU5NRcfIiNZ2dvSdPp0Bs2ejqaPTZL//v8Y/+UjN939IQgKH//2Xg1euyMsBm+nrM2/oUMb27KlQDvjPO3fYdeECRaUezPqWAz5Sy+VPCEng38P/cuXgFXk5YH0zfYbO\");\n    result.append(\"G0rPsT0VygHf+fMOF3ZdQFok8Ne7HHAtXyAhIYR//z3MlSsH5eWA9fXNGDp0Hj17jlUoB3znzp9cuLALqVQIpq5vOeDJ9bz9IyMjsbW1LZ0IRWBT6d1f1/5GNwAAfk1KYtqdOwwyMMCrQonIVwMDGWtiUueM/wnGX7JvZePr4otmO0163+2NWK088jE/Kp+7s+/i/Ldz3YUhHvMLREd/gbX1ewrb0tMv4ec3GB2d7ri6+iAS1W0BNsQAAHiQl0fXa9fQEIsJ6tNHnt73Y3w8t7Kz+apD9fntj6RSzC9fxsvZmZ66uo/186WPpHh39qYgoQC3u24KdQJkUhk3+t3ghWMvoN5GvdpjL5tfxtnLGd2euo/V/4mJv2BoOBg1tYpytDJu3hxGWtpfvPDCsWq9LOHhH5GVdZ1u3X6r2v8NNACUaFw01ABQonFRmwHwVK5/c1/+Zv4CzW0APFHZoqmtWzPR1JS/09PZW2oh7ouPR1dVtV6D/5NAp7sOVu9akRuaS9SWKEXLdWkIDtsdGr0qVEWYmc1UHOCkOdy7NxeRSJXOnffVa/B/HNhparLJ3p7UoiLeCwkBIDAnh30JCVV0AUpkMsYGBDDtzh2Cc3J4y9ISiUjE0pAQXHx9ufuoYSVbVVqp0OGbDsiKZAS9FaToJtwRQ+sprRUGf1mJjICxAdyZdoec4Bws37JEJBERsjQEXxdfHt1tGL+h4ZBKg7+gApiW9hetW09VGPxTUn7D19eVmJgdGBu/hJHRCJKSPLl5cyghIUtQQgkllHje8cR1C//P0REDiYRloaFcTEtjb3w82+opUPPEg+EGOzSsNIj4JIK8B4LGfOq5VNRM1dB1blrZUjW11gp/h4WtJC8vnHbt1tKq1QtNyr3Q0pI+enocSEjg5MOHvH7vHns7dUKtUv6nDHiQm4tfdja/JCXxsKiIC2lpeGdmEpSTQ1qp9kBDYDLWBJPxJqRdTCPxZyEGpDCxkOQjyVi9Y0XlL5D7IJdsv2ySfkmi6GERaRfSyPTO\");\n    result.append(\"JCcoh6K0oifq87y8SEJDV6CmZoqj4w6FfUVFqeTmhpCWdp6UlP+RlxdBWtpFHj26S05OsPLJV0IJJZ57PPE01UxNjc/bt2fuvXu87O/P7d69qwxETYWyGWnA+ACCFgbR9URXwjeE0+33bk+1E9PT/yYm5lt0dLpjY/NB01ttIhF7OnWim48Pr9y+zY+dOmFXTaqgikhEoJub/O+hN2/ydYcOLGv7ZAFajt84knYxjZD3QjAebUzo8lDsNtlVWfcXqYhwCyznvzn0Jh2+7kDbZY0RICbj/v3XkUof0bnzj1WU/szN52BuPqfUG3CWrCw/HBy207HjbuVTr4QSSijRGB4AgNfatKGTtjZ5JSUEl1ale1owGSfMSFP/l8qtF29h4WGBxEDy1Pgruv47dWo613+VQVhbm9fbtKFEJuN2PVz5R5KS+CstjfWNoCqobqmO3cd2FCYVEjAuAERgMMCg1mOSjiSR9lcaD9Y3jqpgbOx3pa7/KZiavlJr29DQFURGbpaXHVZCCSWUeJZQUiG1UiqVNnh/kxoAR5OTcdTWRkMsZkFQkEIu+1MZDL9xRKQqIj82nzZz2zxV7tDQFeTlRWBruxodna5PjfdBXh6BOTl01NZme3Q0N+tQC1QRCbNzQ0njGEdWC63Q7qRN+qV07D6xq7O9SEXglxg+OX9eXgShoStRUzPB0fH/6uYWqQAiJBJD5ZtECSUqISAqCvcdO9CePZtbFZQGS2QyfvPzw3rBAs74+RGamMjKQ4cQT52K1YIF+JdWn3uQlMSA9esZvXkzPqGhbD19GpWpU2n/7rvcrHC+P+/cQWPmTNb++itplSYt/v/zZ3Xv1Sx2XExuZvkkMic9h3Nfn2Ol80rCfMMI9Qlly7gtTBFN4ZMXPyE1VkgRDL0WyuvGr3Ng+QFSY1NJepDEIodFHFxxEM81nniu8WRd/3VMV5tOpH9klT7w9/8fq1f3ZvFiR3JzM8v5c9I5d+5rVq50JizMl+vXTzJvXmumTVPFx+e4vF18fDBL\");\n    result.append(\"lnTk889fISEhhKSkByxa5MDBgyvw9FyDp+ca1q3rz/TpakRGNlzZNCYmpgJXfIP314Qnnq6G5ebyTUwM57t3Z0tUFOsePGB1WFiN0ehNAXVLdcTqYiT6EhA9vQcnPd2L2Njv0NHphq3tqqfGW1BSwtx79/ihY0cSCwsZeOMG8+7dw9fVVT7QV0aXVq0A6N5IKUoiFRGatprk3Mupl8elVReBX6f7k/LLuHdPcP136rS3XkV+WrXqglis8dS8M0oo8Syha9u2/LRwIWdv3mT81q3c+PRTTHR1EYtEjHF25rebN3m5NMvrs5kzMdHVZa2nJ7qly446Gho4mJuza/58VMRierVvT1JmJj9duoRd6/K4HUtDQ94bM4aPp06t8h26vdgNA3MDVnRfwf+3d+dxUVf748dfwzDMMCqbwgjIpoC7ueUSeutqy7eyxBQt03LLn6V1Na9paZq5Ua6ZaZnltTIrr2ZZ1yVNb6mZmIoLBsq+oyIg2zDb7w8QQYYBXJq6vp+Ph49H8Vne8znnfM7n8znn8zln5dMrmf7tdBQOChq5N6LfuH5cSL5AcI/yCcGmbZvG24+/TU5iDm46NwDKSssYOH0gj097vPKGYMZ3M/AOLR9z5HLGZXav2c3QuUOtzibYufP/4e7uzSuvdGHlyqeZPv1bFAoHGjVyp1+/cVy4kExwcPl4JA4Ojrz11mO4uV17IdnLK4iWLbsxceIGHByUnDt3mBkzvsPbO7TiWpHB7t1rGDp0bq2zCVpTdTrgq5599llGjRrFoEGDAGwur2s64JtqASitciFSOzgwPSCAto0asSotjV/z8/+nTxqTqZCYmLEVTf//QqGoeREsKro9k3f8IzaWCb6+hGi19HVzY7SPD8euXGF5xSBN1gQ7O6NxcKCVVmuX9HIOdsZB44C21c3FT01dzeXL+9DpItDpan5DU1qajMlUvRuqUaMONcZruNaCk8nIke8SFvY6paXlLyWWlRlZt24vzz77HufOZbFmzW602hGMGbOGkpIy\");\n    result.append(\"8vKKCA9fzPz5W8jMvMzSpdtRKIayZMl2zBWjlq1fv49evWZy8mQyW7b8ygsvrGPVqp2sWrWT+++fR+fO0ygtNZCfX2xz/1FR523+vtTUS7c1flxcBiNGvItSOYzDh8+V34DqDfy//7eWsWPXcOZMKosXf4tO9xzx8dmV6XrwYCz33juH2NgMm/Ezz53j3ZEjeT0sDENpKVA+Be7edet479lnyc/O5vNXX2XLvHnsXLWKnatW8UJAAB9OmEDqmTNM79qVKW3bciG5/Eug/JwcZvbuzfcrVpCXnc3uNWsYodWyZswYykpKKMrLY3F4OFvmz+dKxQA3te3/9wMHePXuu9nw8rXPfQtzc/nw+efZsXIlCb/9dlvj13V8p/butfn7Lmdl1Sv+VeF3342niwtDli6t/J4fwPG6d7qmDhhAnzZtGPv++xhMJl7btIklI0eirLLevGHDcNVqmb5xY+Xfln//PbOHDKn9YqR04JF/PELswVi+mPXFtb87OKCo8mCjUCh4Yf0LFFwoYMv8LVzOuMzhzYcrL/4Avm19Ky/+AKvHrMa3jS8DXxlYe3wHJY888g9iYw/yxRezao3frdsA+vQZztq1/6/yu//t25fyxBMzcXAoH3zI17dt5cUfYPXqMfj6tmHgwFcaVN917NiR2bNnk5iYiMViwWKxkJCQwOzZsyunCra1/La2ALwYG8uEFi0IqbioODk48EHbttx79Cjjzp7ltx49/rAXAv9oV5v+W7acY7Xp32DIJTd3D40atbulcTdmZWEGnmp+7e5zcUgI3128yOz4eMI9PWtMHQzlLw62dHamxS0aHrTBLQYOCpxbOqNucePxS0oSOX++vOm/dWvrTf8ZGRtqDMCk1YbUOhxwSIg3U6c+xqBBixk58l2++moKTk6OhIf3wGg0ExLSnJCQ5jRr1oQZMz7HaDSRmnqJxx/vzpgxfy+vEKc+RmJiDseOJeBQ8enpxYtX+OabV9DpXDGZzAwePA6A06dTmTdvCz///CYajQqNRsXz\");\n    result.append(\"zz9Y5/5r+31+fk1ve/z161/gzJlUTp5MplevEFQqRzw8GrNgwVM4OCho396PjRt/5pFHFnLo0HyaNm1CWFhrHnigE61b+1BcrK81vndICI9NncriQYN4d+RIpnz1FY5OTvQID8dsNOKq09F76FCCunQBYO+6dTRyc2PUihWoNBqmbtnCq3ffTWlFF5jZZKJ3RASPTp4MwIPPP0+TZs34fMYMTEYjl1JT6f744/x9zJjKMmBr/32efpr/vPMOXkFBPPziizT28KBj//74deiAb5s2tz1+Xfu39fvcmzevV/zKm3QnJ7555RXufvVVJv/rX7w3dmwtXWoKPnr+eTpMnUq/uXNZOXo0bo0a1djXugkT6Dd3Lk/36UNCTg5De/dGU0cXpE9rHyZ/OZnIRyMJ7BxI76G9ra7XpFkTnnv/OZYPW07qmVRe+PiF6ue867U6cOeqnfx+4HeWRC/BQWn7euTj05rJk78kMvJRAgM707v3UKvrjR79DlOmtGPbtrfo3TsCi8WMr2/bKnXOtYHxdu5cxe+/H2DJkujKG4Q/ixu+Oi9MTCSltJThzat/l93XzY3HPT05XVjItHPn/pCDsBgsmEvMlWPP3265uT+SlvY+TZrcRVDQzBrLzeYSYmNfsjqJzc3Yk5vL9HPnWB4aWu3vHioVrwYGUmI28/Tp0+hrGYu7hUZDI+WtK4CVY/3XM901LTQoG91ofAsxMWMwmYpo3XoVTk6eNdbIz/+Fy5f3Vg7BfJWTk2ed/f9LljxDTk4+r7zymdXlERG9uf/+jowatZqtW3+tvDhW3oQtHsmxY4l89dUv/PrrOUJCvNHpyiuBLl2CKlqE9ERELGPZsmcIDfVu0P7r+n23M75KpWTjxpeYOXMTCQnZfPjhHsaPv7/yZgNgyJBehIf3IDx8MXp99c876xP/mSVLyM/J4bNXaj4hXb04pp4+zabXXmPKV1+h0mjKm16Dghjx9tusHDECY1kZu1ev5uEXX6y2fe+ICDrefz+rR43i161ba1z8\");\n    result.append(\"bO0fYPq337ItMpKj335b47fd7vj12b+t31ef+FX5eniwbdo0Pv7xRz7cu7fW9fybNWPS//0fxxMTca/oXrzeve3a8dz99zP2/feJTkqifz2eSAHuevAunln2DKtHryY5OrnW9XoM6kGr7q3IOp+Fk9b6EN+ZcZlsnL6RUctHoWulq1/8ux7kmWeWsXr1aJKTo63fgDRpxujRK9m6dT5ffTWHxx77p/X4mXFs3DidUaOWo9O14s+mwTcAe3Nz+ftvvzEzPp7YoiK+zqn+ZvW/c3KIJVFxMgAAIABJREFUrnjBY2VqKsNPn+ZoQcHtuxj/mMvZ8WexmC0Uny8mflY8V47dzulryz8/AwsGQx5Hj/YlKqpX5b9ff+3GTz95k5W1kUaN2t+SiOeLixkdE8ODx46RXVbG6rQ0qg7feKSggO0V43AfKSjg3t9+Y2tOzTfeb9XTf9HZIhLnJZL/a3k3T9yUOC5+d7HO7W7m6T8j419cvrwfhUJJSsqyamkeFdWLQ4dCiYoKQ6Op2b/n6OiKUmn73QO12pFvvnmFHTtOsGbNbqvrvP32CHbuPEHLljUrEmdnJz777EVeeuljdu48QXj43TXWmTBhLX36tOHpp/s2eP91/b7bHb9duxbMnPkETzyxhEaNNAQF1RzoKzJyOAEBnjz77HtWJ6uxFd9RreaVb77hxI4d7F6zpsZyfVERyyIieHbZMnyue7/o72PG4BUUxLwHHuCeYcNQWnnKHPH225zYuRNdLePY29q/V1AQM7Zv54Px44k/erTGtrc7fl37r+v31Sd+tQtrcDAfv/ACkz76iEOx1sfMSMjOxmgycXdwMOPef7/Wfb0REcG5zEyeDAtr0Pn+8IsP03dEX94e+DYFF61fP458fYSwJ8PITc9l26JtNbtpjSZWjlhJ+7+3p/9z/RsW/+EX6dt3BG+/PZCCAut1W1jYk3h6BhIU1BWVysropyYjK1eOoH37v9O//3N/ypbsBncB9PfwoL9H7U9TQ7y8GHKbRwGs9vTb\");\n    result.append(\"zwOPfh60W9/uD4qoICws8Q/NpGCtlvXt2rG+nfVj7OHiwt6uXevcT/NbdAPQqG0jgl4PIuj1oAZtp25+4/F9fEbj4zP6hrZVKpugVDaqcz03t0bs2PEaffq8jtbK+OGrV+9i27ZpPP30Sv72t7YEBFRvhejevRWtW/vQzcpkJevW7eXEiSSOHFlUa/y69l/X77vd8f/xj0eYMmWD1ZuLq03D69e/wCOPLOTVVz+ncWNNg+I3cnPjtR07eL1PH9TXdWOtnTCB0Hvuoe+IEVa3feSll/h02jT8OnSwunzX6tVM27aNlU8/Tdu//Q3P68bCqGv/QV27MmnDBpYMGsQj//hHjTi3O35d+6/r99UV/3pPhYVxJjWVwUuX8re2bat3xZWVMX/rVlaPG0d6bi6d/vlPPty7l+f617zIXm3yd1A0/O3ssavGMv/B+awYtoLQ3tVbPTNiMzh/5DzDFw3HxdOF90a9R48neuDX/tpgZFvmbSEnMYfp306v/tCYnouHb91fBI0du4r58x9kxYphhIZa74pQqTQ41NLNvWXLPHJyEpk+/dvrWpDT8fDw/Wt3AYi/Hg9H+74F7+hhn/hKpQalsn4vH/r5NeW772Ywbdqn1f7+wQc/EB7egwce6MTUqY/x9NMrMRpNVi+C1zt9OpVXX/2cr756GWfn8qbKixevEF2lebO++6/t9/0R8RX1qMRVKiVbtvyTXbuiOXcuq97xr2rq58eM777j02nTrrU6rltH0vHjjHn33cq/ndm3D0vVri4bv+2HDz6gR3g4nR54gMemTmXl009jqjJFdr32D9z10EM8OX8+X8yaZS3hb2/8eqR9bb+vrvhXGa77fHvesGHc07o18dnXXu60WCxM2bCB1wcPRqNS0UqnY/6TTzL1k084XzE7bFVXpxI2W+qecsZsNlf7nl2pUjJ1y1TysvOqt0BeLmLL/C0MnVvePx/2VBid/68z7454F0NF99P5I+f5euHXjP9gPG7N3apte3zH8frFV6qYOnULeXnZ\");\n    result.append(\"tbcHW6pvU9lqe/4IX3+9kPHjP6j2tUBR0WWOH9/x1+0CEH9dLva+AXCxT3yFwgkHB43VZYWFpezeHc2uXdFculTeddSxoz9ffjkFtdqRzMzLTJ36Cd99dww/v/JZBvv378DBg7E888yqam++HzuWSHx8Njt3nqjcl15vICJiGZ06BbBr1wlWrPiexYu/5dFHFxEU5FXn/k+dSrH5+6q6HfGvHp/JZGbr1l8B2Lz5FwyGaxeL3buj+fHH05w/X34BcHFx5j//eRVvb7c645cWFhK9ezfRu3ZVvpXu37EjU778Eke1mvTff2f9Sy/ROiyMPWvX8v2KFWyZN4/vli1DUfHkVZSXx8kffuBiSgq/HzhQ+bsuZ2byydSpHPvuO5r6lT8Zdujfn9iDB1n1zDNkx8fb3H9eVhbnDh/ml82bMVUMm33vs88yZPbs6hek2xS/zuPLyLD5++oTH6BIr+fzAwfYc+oU+8+cqXbD98mkSXSpmGQmKj6ehxYs4FBsLKYqFz0HhYIrJSUMiIxkV/S1PvNLV66wft8+ADYdPEjadV8dVHU54zIHNh7g+H+OkxaTVvn3xh6NmbF9RuVLfYf/fZjXer4GFtAX6Ssv6k2aNiHpRBLLhiwj6UQS7458l8ZNG5N4LLFyHIBPp33KrLBZePjUfPq/fDmDAwc2cvz4f0hLu/b1VuPGHsyYsb3aS31Xm/ePHv2W7OwEoqN3kZx8ssoyA+++O5LGjZuSmHischyATz+dxqxZYXh4+Pxprgk3NRvgrXCjswH+r/yAhs4GeDM2ZWVV+3rgjz78rE1ZNH+q+R+e/gZDLgUFUTRt+lDN9JfZAO1KZgO0L5kN8K8xG6DcAMgNwP+mOzz/H/jhgTs7+e/0AviAnH53dPrb+filC0AIIYT4Ezp16hRvvvkmQUFBKBQKFAoFAQEBzJ07l1OnTtW5vC4yNqoQQgjxJ3R1tL/77ruPe++9F4ANGzZw3333VVvH1nJpARBCCCH+onx9r3026O/v3+DlcgMghBBC\");\n    result.append(\"/AUpq4zgam3cgbqW16ZGF0ChycSKlBQO5eXRXK1GqVDgolTSzcWFAqORoTodW3NymBIXh4XyoX9LzGYKTSYmtmjBaB8f4oqL+SQzkwWJifio1XR3cSGttJSmKhVzWrYkzM2t1h9kKjSRsiKFvEN5qJurUSgVKF2UuHRzwVhgRDdUR87WHOKmxIEF3Pq6YS4xYyo00WJiC3xG+1AcV0zmJ5kkLkhE7aPGpbsLpWmlqJqqaDmnJW5hNuKbCklJWUFe3iHU6uYoFEqUShdcXLphNBag0w0lJ2crcXFTAAtubn0xm0swmQpp0WIiPj6jKS6OIzPzExITF6BW++Di0p3S0jRUqqa0bDkHN7faR8Wyd/rbPX6hiRUrUjh0KI/mzdUolQpcXJR06+ZCQYGRoUN1bN2aw5QpcVgs0LevGyUlZgoLTUyc2ILRo32Iiyvmk08yWbAgER8fNd27u5CWVkrTpirmzGlJWJit4y9kRcoKDuUdorm6OUqFEhelC91culFgLGCobihbc7YyJW4KFiz0detLibmEQlMhE1tMZLTPaOKK4/gk8xMWJC7AR+1Dd5fupJWm0VTVlDkt5xBmI//tXf7tnf52P/8LC0lZsYK8Q4dQN2+OQqlE6eKCS7duGAsK0A0dSs7WrcRNmQIWC259+2IuKcFUWEiLiRPxGT2a4rg4Mj/5hMQFC1D7+ODSvTulaWmomjal5Zw5uNkYFc/+9Y+9y/+dnf5/tGo3AKmlpTx4/DiPNWvG9s6dK6eWzS4rY8CJEwz09MRDpWKcry8bs7IoMZvZUTGO9cLERMbExGC0WHjO15d5rVqxKCmJkd7eRAYHY7BYCI+Opv+xYxzt0aNyetqqSlNLOf7gcZo91ozO2ztXziFfll3GiQEn8BzoicpDhe84X7I2ZmEuMdNlR3n8xIWJxIyJwWK04PucL63mtSJpURLeI70JjgzGYrAQHR7Nsf7H6HG0R+X0tNXil6Zy/PiDNGv2GJ07b6+YRx7KyrI5cWIAnp4DUak88PUd\");\n    result.append(\"R1bWRszmErp0KR/UITFxITExY7BYjPj6PkerVvNISlqEt/dIgoMjsVgMREeHc+xYf3r0OErjxjVH9LJ3+ts9fmopDz54nMcea8b27Z1RVuR/dnYZAwacYOBATzw8VIwb58vGjVmUlJjZUZH/CxcmMmZMDEajheee82XevFYsWpTEyJHeREYGYzBYCA+Ppn//Yxw92oMOHawdfyoPHn+Qx5o9xvbO21FW5H92WTYDTgxgoOdAPFQejPMdx8asjZSYS9hRkf8LExcyJmYMRouR53yfY16reSxKWsRI75FEBkdisBgIjw6n/7H+HO1xlA5W8t/e5d/e6W/38z81leMPPkizxx6j8/btKCqeqsqyszkxYACeAwei8vDAd9w4sjZuxFxSQpcdFef/woXEjBmDxWjE97nnaDVvHkmLFuE9ciTBkZFYDAaiw8M51r8/PY4epbGVEf3sX//Yu/zf2elvD5VtBRZg+OnTuDk68lZISLV55XVOTmzt1InCKiNFqa9rZng5IAClQsHHGRkAKABVlX2oFAom+/ujN5vZaGXEKCxwevhpHN0cCXkrpPLkB3DSOdFpaydMhdfiO6irxw94OQCFUkHGx+XxUYBCVWUKSZUC/8n+mPVmsjZaiY+F06eH4+joRkjIW5WZD+DkpKNTp62YTIVVmlmqD8UaEPAyCoWSjIyPr0asNkWwQqHC338yZrOerKyN1g7frulv9/gWGD78NG5ujrz1VkjlxQdAp3Ni69ZOFFbJf/V1+f/yywEolQo+rsh/hQJUVfJfpVIwebI/er2ZjRutHb+F4aeH4+boxlshb1VWfuXHr2Nrp60UVsl/9XX5/3LAyygVSj6uyH8FClRV8l+lUDHZfzJ6s56NVvLf3uXf3ulv9/PfYuH08OE4urkR8tZblRef8vg6Om3diqmwyvl/3bDaAS+/jEKpJOPjj6+e8CiqjNmvUKnwnzwZs15P1saNf8L6x97l/85Of7vfAPx0+TIH8vIY7eODtUEn/TQam2P8X92miY3Z\");\n    result.append(\"5mytc/mny+QdyMNntA/WfoDGT4PXEBtzDFRso2yivKF1Ll/+iby8AxXjzdf8ARqNH15eQ6hr57Ynnal9HXunv93j/3SZAwfyGD3ax+qop35+GobYyP+r2zSxkf+21vnp8k8cyDvAaJ/RKKykgJ/GjyE28v/qNk1s5L+tdexd/u2d/nY//3/6ibwDB/AZPdrqsLsaPz+8bMxlf3UbZZMmN7SO/esfe5f/Ozv97X4DsKNimMZuNhKwu4tLrcsWJiVhsliY6OdndXmp2czi5GRcHR0Z4e1dY/mlHeXxm3SrPb5L99rjJy1MwmKy4DfRenxzqZnkxck4ujriPcJK/Es7KiqnbrXHd+lee/ykhVgsJvz8JlqPby4lOXkxjo6ueHvXnPDD3ulv9/gV+d/NRv53t5H/CxcmYTJZmFhL/peWmlm8OBlXV0dGjLB2/Dsqjr+bjePvbuP4F2KymJhYS/6XmktZnLwYV0dXRljJf3uXf3unv93P/4qm5CbdbJz/3W2c/wsXYjGZ8JtYy/lfWkry4sU4urribWXCH/vXP/Yu/3d2+ttL5TsAaaWlQPnc8vWVqdcTmZREQkkJerOZfd26cZ+7e7V1juTnsyAxkbNFRYRqtaxp0wZ/Tc1x2UvTyuOrPOofX5+pJykyiZKEEsx6M932dcP9vurx84/kk7ggkaKzRWhDtbRZ0waNv5X4pWkVTZUe9Y+vzyQpKZKSkgTMZj3duu3D3f2+6vHzj5CYuICiorNotaG0abMGjabmZxr2Tn+7x6/If48G5H9mpp7IyCQSEkrQ683s29eN+67L/yNH8lmwIJGzZ4sIDdWyZk0b/P2tHX9axfF7NOD4M4lMiiShJAG9Wc++bvu477r8P5J/hAWJCzhbdJZQbShr2qzB30r+27v82zv97X7+p1Wc/x4NOP8zM0mKjKQkIQGzXk+3fftwv+776/wjR0hcsICis2fRhobSZs0aNFY+07J//WPv8n9np7/dbwC0Fc2yV0ymem/srVYzIzDQ5jo9XF2Z\");\n    result.append(\"GVT3tLFKbXl805X6x1d7qwmcYTu+aw9XgmbWI37FbHEm05X6x1d7Exg4w3Z81x4EBc2sc1/2Tn+7x6/I/ysNyH9vbzUz6sj/Hj1cmTmzPsevrTj+Kw04fm9m1JH/PVx7MLMe+W/v8m/v9Lf7+V8x/bDpSgPOf29vAmfUcf736EHQzJl/gfrH3uX/zk5/e6nsArjHtXy2o2MFBXb5Ia73lMcvOGan+K73lMcvOGaX+PZOf7vHr8j/Y8fsdfz3VBz/sTuy/Ns7/e1+/t9Tcf4fs1P+273+sXf5v7PT3+43AEN1Olqo1axKS8NkZe5ms8XCJmtv798iuqE61C3UpK1Kw2KqGd9itpC16TbG1w1FrW5BWtoqLJaaTyEWi5msrE23Lb6909/u8YfqaNFCzapVaZis5L/ZbGHTptt5/ENpoW7BqrRVmKzkv9liZtNtzH97l397p7/dz/+hQ1G3aEHaqlVYrLSCWcxmsjZt+h+uf+xd/u/s9Lf7DYBWqWRzp07EFhUx7NQpssvKKlfKMxp5IyGB/lX6Z/RmMyU2mostgMFisblO9SYgJZ02d6IotohTw05Rln0tvjHPSMIbCXj0vxbfrDdjKrGxbwtYDBbb61zXBNSp02aKimI5dWoYZWXX5nk3GvNISHgDD4/+VSpEPSZTCbZ+gMViqGOda+yd/naPr1WyeXMnYmOLGDbsFNlV8j8vz8gbbyTQv0r+6/VmSmzkrcUCBoPF5jrVj1/L5k6biS2KZdipYWRXyf88Yx5vJLxB/yr5rzfrKbGRtxYsGCwGm+v8mcq/vdPf7ue/VkunzZspio3l1LBhlGVXOf/z8kh44w08+lc5//V6TCU28tZiwWIw2F7nT1X/2Lv839npXxez2Vz53yYrdWpdy2tTbSCgXq6uRPfqxZsJCfQ8cgQvJycCNBqCtVqmBQTgoVKRazCwOSeHqIIC9GYzq1JTGezlhXeV7zLjiotZn5GB2WJh24UL9HR1JUKnq/ZduNVmmF6u9IruRcKbCRzpeQQn\");\n    result.append(\"Lyc0ARq0wVoCpgWg8lBhyDWQszmHgqgCzHozqatS8Rrshdr7WvziuGIy1mdgMVu4sO0Crj1d0UXoqn0XbL0ZqBe9ekWTkPAmR470xMnJC40mAK02mICAaahUHhgMueTkbKagIAqzWU9q6iq8vAajVl97s7i4OI6MjPVYLGYuXNiGq2tPdLqIat+FWmPv9Ld7/F6uREf34s03E+jZ8wheXk4EBGgIDtYybVoAHh4qcnMNbN6cQ1RUAXq9mVWrUhk82AvvKvkfF1fM+vUZmM0Wtm27QM+erkRE6Kp9l279+HsR3SuaNxPepOeRnng5eRGgCSBYG8y0gGl4qDzINeSyOWczUQVR6M16VqWuYrDXYLyr5H9ccRzrM9ZjtpjZdmEbPV17EqGLqPZd9J+x/Ns7/e1+/vfqRa/oaBLefJMjPXvi5OWFJiAAbXAwAdOmofLwwJCbS87mzRRERWHW60ldtQqvwYNRV/mypTgujoz167GYzVzYtg3Xnj3RRURU+y79z1n/2Lv839npb0tqamrlf2dkZNCqVasGLa+NwnL//RZ7NkE8cIdPSP3Dn2BGdDsnwB2d/w/88MCdnfx3egF8QE6/Ozr96zj+U6dO8fXXX7N+/XqSkpIACAoKYtSoUQwaNAjA5vKOHTvWvwVACCGEEH8OV6cDnj17ts11bC23xeq0Qel6PW8nJ+O4dy/u+/fzUUYG+UZjjfX2X77Mk6dOodizB8WePUyOi+OiwQDAr/n5hEVF4b5/P4uSkihuQL+EPl1P8tvJ7HXcy373/WR8lIExv2b8rM+z+Nn3Z/Yo9hAVFkXez3mVy0qSSogeFM1e5V5iX4pFn6FvUMLo9ekkJ7/N3r2O7N/vTkbGRxiN+VbXPXkygoMHg4mOHsTJk0M4eXIIJ048yp49Cn75pT1mc8NixxUXM/3cOdQ//ohizx4eOn6cM0VFACSVlDAuJgbHvXuZFBtLgpU+rvrm362MedPbxxUzffo51OofUSj28NBDxzlzpmL7pBLGjYvB0XEv\");\n    result.append(\"kybFkpBQc/vDh/Pp1SsKhWIPzZv/xOefX3thrLjYxMyZ8SgUe3jkkeMcPWr9TfP9l/fz5KknUexRoNijYHLcZC4aLlaU518JiwrDfb87i5IWUWwqtrqPiJMRBB8MZlD0IIacHMKQk0N49MSjKPYoaP9Le/T1LAs3WrbNejMZ6zMqt014M4GS+Pr1Q37+eRa+vj+jUOwhLCyKn6vETEoqYdCgaJTKvbz0UiwZVWLm5xtZsiQZH5/ybYOCDvLDD7mVab9sWQoKxR4efvh4tX3eqmMuTSnlzDNn2KPYwx7FHpKXJFerL7I+z2Jfo30canOInK05tcY36/UkzJ3Lj2o1exQKYsaMofj8+WvH+csv/NKuHftdXUleuhRzlfdkAIrOnOFHtZpjDzzAySFDKv8dDApij0JB5qefNqgeSE19j//+tyknTjxWWa+cPDmEffsa8+OPWoqL42oeg1lPRsZ6fv7Zlz17FCQkvElJSXy9Y95I+Y0rjmP6uemof1Sj2KPgoeMPcaboTMW5n8S4mHE47nVkUuwkEkoSbMY/GRHBweBgogcNqky/E48+yh6Fgl/at8esrxk///Bhonr1Yo9CwU/Nm5P1+eeVy0zFxcTPnMkehYLjjzxCwdGjdabBjdbnN5Jf9ma1BcBXreaVgADWpafTWqtlrI+P1Y3vc3fnPnd3fNRqlqek0L1JE5pV9LP0dHWlmZMT+9u04a4mDRv6UO2rJuCVANLXpaNtrcVnrPX4zYc3RxuiJap3FM6Bzrj1vTbLl3OgMx79PHDt5Urg9MAGJ4xa7UtAwCukp69Dq22Nj8/YWtfVaPzo0OFTHBw0VS5ok1EoHGnffkONcaPrEqrV8lZICL3d3HgiOho/tZr2jRoBEOjsjL9Gw/tt2jCuyhzQN5J/tzLmTW8fquWtt0Lo3duNJ56Ixs9PTfv2FdsHOuPvr+H999swbpz17Xv1cmX37i506HAYB4fyt9qv0mqVPPmkjuPHC/j++y7U9irCfe73cZ/7ffiofViespzu\");\n    result.append(\"TbrTTNWsojz3pJlTM/a32c9dTe6qNR39NH582uFTNFXKwuS4yTgqHNnQfkONMdRrc6Nl20HtgM9oH/J/ySdrUxYtZ7esd7kbPrw5ISFaeveOIjDQmb5VYgYGOtOvnwe9erky/bqYrq6O/POfAQwe7EX37kdQqxX06+demfbduzdhxAhvPv20/W05Zo2/hvaftMdYYOTCNxfwfNwTR9drVZsuQkfy0mS6/tDV5kBDDmo1LefMwdHVlbgpU3Dt3RttcPC14+zdm0bt29Nu3brKz9aqKrt4kfaffIJu2LAqNycpHO7YEc+BA/EeObJB9YDZXESPHr/h7HzteC9c+IacnC2Ehi5Hqw2teQwOanx8RpOf/wtZWZto2bJhT4Y3Un5DtaG8FfIWvd1680T0E/ip/WjfqH3FuR+Iv8af99u8zzjfcXXG1/j50eHTT3GoMlhY3OTJKBwdab9hQ405AKD83YEuu3dzuEMHcHBAN3Ro5TKlVovuyScpOH6cLt9/D3W8h3Qz9fmN5Je92Zw42EmhqDHpizVvhYTQ3cWF6efPVz5pLk5OZqhO1+CLf1UKJ0WNST+u53K3C/5T/Mn+IpuCI9ee7EyFJnJ/yCXgnwE3lUAKhVOdF/BmzQZUKyyXL/+XlJSVBAZOtzl8ZF3CPT15yd+f9ZmZHM4vb304lJ9PVllZrRfSG8m/WxnzprcP9+Sll/xZvz6Tw4crtj+UT1ZWWa0X/8qy4OLImjVtSE4u5Z13Uqoti4xM4oMP2tbn/OetkLfo7tKd6eenk1/R6rM4eTFDdUNtXvwBBjQbUK3y/O/l/7IyZSXTA6fbHEr1VpdtByeHOs8da+6+24UpU/z54otsjlSJWVho4ocfcvmnjZhBQc589FE7YmOLWbasPP0vXTLw9tvJrF3b9rYfc5vVbXB0cSRuavUnrdT3UgmaFVTvUQb9XnoJlx49SHjjDYxVxsUo+O03NC1aWL34AygcHfEMD7/2B4uFmDFjUKhUtP3ggwbnRZMm3atdTAyGi5w9\");\n    result.append(\"Ox43t774+b1ku2J3cGrwg8fNlt9wz3Be8n+J9ZnrOZx/uOLcP0RWWVa9Lv4AzQYMqHbxv/zf/5KyciWB06fbHArY0cWFNmvWUJqcTMo771RblhQZWZ7+9Tn5b6I+v5n8+lPeAFgz4vRphp06Ve1vKoWC9e3acdFgYNq5c/ycl0dSSQlPN29+y3/w6RGnOTWsevyWc1ui8ddwdvxZLMbydxoT5iYQNCuo2qxit4LFYuDgwVakpa2u/JuHR79rFZWpkJiY0TRu3JGgoNk3HW9hq1YEaTSMi4khXa9nQWIiS0Nr3kmuTU8n8MAB9FU+B7ndMa2VhYZsX2v8ha0ICtIwblwM6el6FixIZOlSK/FHnGbYdWXh0UebERGhY86cBJKTy4eX3b79Al26NMHPT1Ov+CqFivXt1nPRcJFp56bxc97PJJUk8XTzp62kwQiGnbr2xNevSlkoNBUyOmY0HRt3ZPYNloX6lO3Ck4X81+O/XDl+5ZaU8blzW+Lvr2H8+LMYK2LOnZvArFlBlbMErl2bTmDgAfR6c40buKeeas6cOfGcO1fMhAlnWbo0FGdnh1t6zOlr0zkQeABzlfhqHzXBi4K5+N1Fcv5d3tSvz9CT/2s+XoO86n/T7+BAuw8/pCwnh/jXXis/781mEufNo+Xcude62tau5UBgYGWztFtYWLUn1NT33iN3717avPceTjpdg/Ohar0CcPbs85hMRbRvvx6F4lp6pqev5cCBwAZ3NVpT3/K7Nn0tgQcCa3QJLGy1kCBNEONixpGuT2dB4gKWhi6t/zH3q1KXFhYSM3o0jTt2JOi6Pu7r0x6g2aOPoouIIGHOHEqTk8ufwLdvp0mXLmhqmaOkrnS3VZ+fPj2CU1XO/frm11/6BsBbrcbHSjNMh8aNmRUUxLr0dGbHxzeowm9Q07y3GrVP9fhKrZI2q9twJfoKKctTKDxZiFlvxqWHy234BUo0Gv9ax4yOi5vZXodwAAAP5UlEQVRKaWlaRVOR001H0yqVfNSuHTFFRYRF\");\n    result.append(\"RbE8NBRnK0/17o6OBDg746hQ/GExaysL9d2+1vhaJR991I6YmCLCwqJYvtz6BcTbW42PT834K1e2RqVS8MILv1NcbOLDDzOYPLlh4293aNyBWUGzWJe+jtnxs2utxLzV3viorXexTI2bSlppGhvab8DpBstCfcq2g9YBTYAGZSPlLSnhWq2S1avbEB19heXLUzh5shC93kyPKjHd3R0JCHDG0bFmeXv33dY0aeJI795RDBrkRevW2lt+zI7ujjgHOKO4Lr7vBF9ce7sS+1IsxgIj5187T/DC4AanQeNOnfB/+WXS1qwh/9dfSX//fZo/9RSOLlV/gzvOAQEoHGv2pJbEx3N++nS8hgyp1iVwo7KyNpGT829CQt7G2bn6J16Oju44OwegUNzad7ptlV93R3cCnANwvC6mVqnlo3YfEVMUQ1hUGMtDl+Ps4HxD8eOmTqU0La286d+pevza0r71ypUoVCp+f+EFTMXFZHz4If6TJ99wGtiqz9Vqb9S1nPu28qs2e/fuJSAggHvuuYfIyEgiIyOZM2dO5Sd9x44do0+fPuh0OmbOnMmECRPo27cv+/fvr9xHfdaplo4NTZDFISG1LpsRGMg7KSmklJZittyerwtDFluP3/Thpuie1JHwRgK5e3Pp+EXH2xJfoXCgW7d9VpddurSL9PS1tGw5lyZNOt+ymPe6uzPA05OdFy/W+oQfodMRcQNPGTcT01ZZqM/2NuPf686AAZ7s3HmxxlNmZfxaykLz5k5ERoYwYcJZHnroOJGRwVYvVHWZETiDd1LeIaU0BbOltjRYbPXvuy7tYm36Wua2nEvnmywLdZVtbbCWnsd73tJy/vDDTXnySR1vvJHA3r25fHFdzIgIHRER1stb06Yqpk8PZOrUuAbNLdCQY9ZF6NBZia9wUNB2bVt+7forJx45QbNHm+EcdGMXoFZvvEHOv/9NzJgxNO7QgY5ffnndb4hAFxFRs5XQbObMs8+ibNyYtmvW3HRe6PWZxMZOwsOjHy1aPF9juU4X\");\n    result.append(\"gU4XcUvzv67yG6GLIKKWmPe638sAzwHsvLiz3i+91qhLd+0ife1aWs6dS5PONePXlvZOzZsTEhnJ2QkTOP7QQwRHRlq9QavXb6ijPg+p5dyvK79q079/f+666y78/f2ZUWWOg4CA8m6vrl278sADD2A0GlmwYAEAr732Go8//jhpaWm4uLjUa52bagGwZUVKChNatCCptJRZ8fH80UKXhGIqNuHayxVHtz/2C0ejMY+YmLE0adKVoKDXbum+D+Xn46tW4+nkxNiYGKtD9d5qNxvzprc/lI+vrxpPTyfGjo2xOjytLePH+xIaqkWpVBAW5naD5XkFE1pMIKk0iVnxs+q9XZ4xj7ExY+napCuv3aKyYI+yvWRJKMXFJnr1csWtATEvXTJw8GAeDz/clFdeOUdamv4PPebGHRrj86wP+Ufyb+odIAdnZ1q9+SZFMTG0eL7+FXnK0qXkHTxImzVrUDVrdtP5cPbsc5jNBtq1+xhrc9Xfajdbfg/lH8JX7YunkydjY8ZaHVrYZl2al0fM2LE06dqVoNcaHt93/Hi0oaEolErcwsL+8Pr8ZvLLwUpL6VNPPXWtdUxZvZWvc+fOXLlyhawqw7TXZ51bfgPwc14e2WVlzG/VikktWvBOaipH/uCJZVRNy1/ycdD88f0tsbEvYjBcoH37Dbe0Ke5CWRmLk5J4JzSU99q0IaqggOUpKbf1WG425k1vf6GMxYuTeOedUN57rw1RUQUsX96wY1YowN1dheYGy8LPeT+TXZbN/FbzmdRiEu+kvsORgiP12vbF2Be5YLjAhvYbajSR/pXKdtOKmA1JQ4sFJk36nSVLQvjgg7aYzRaef/7sH37MqqYqFA6KOkf/q3s/TSt+Q/3eHymKiSH+9ddpPnw4Xk88cdN5kJHxERcvfk9o6FI0moA/JN9vpvxeKLvA4qTFvBP6Du+1eY+ogiiWpyxvWF364osYLlyg/YYNN/b0rlCgcnevd57dyvr8VufXyZMniY2NtbqsuLiYdevW8fe//52Q\");\n    result.append(\"Wlpj61rnltQm2WVlLElOZmFFX8WC4GD81GrGnDlD2S14Ke3P7sKFb8jM/IyWLefSuHGHastKS1PIzz90Q/s1WyxMjI1lWWgoTg4OhHt6MtjLi9nx8ZwvLr4tx3KzMW96e7OFiRNjWbYsFCcnB8LDPRk82IvZs+M5f774D8nP7LJsliQvYWGrhRXleQF+aj/GnBlDmbnM5rbfXPiGzzI/Y27LuXS4riyklKZw6AbLwl/F/PmJDB2qIyjIGT8/DYsWBfPddxerjcvwv8piNHLm2WdReXjQ+t13ayxv6GQ2paUpxMW9TNOmD+Hr+1zNcpr95S0/hpspv2aLmYmxE1kWugwnByfCPcMZ7DWY2fGzOV98vn516TffkPnZZ7ScO5fGHa6rS1NSyD90+8+fG63Pb1V+HTt2jMjISObPn1/t6f/a77vAokWLCAgI4JFHHmHnzp0ornv3qz7r1HkDoLdYMFzXdDs5Lo5JVe5ICk0mnjp1iuUVFT5AY6WSpaGhnCkq4vWb6Aqw6C1YDNXjx02OI3aS9Tsic1n5zYZZf+tuOiwWPRaLocr/mzh6tC+ZmeWDelz91MPVtScBAdOu35qEhDk4O4fcUOwpcXGEe3oS5HytD3Nl69aYgFExMRir5M2mrCz6HD1arb/dWv7dypjXl4WGbm81/pQ4wsM9CarSb7tyZWtMJhg1KqbyrXSAyZPjmFRLWQAoKzPX+v5AbQpNhTx16imWhy6vfPGpsbIxS0OXcqboDK/Hv37d+TCZSbGTALhouMj4s+Pp6dqTadeVBQsW5iTMIeQGy4Ktsl0cV8zhTocpqhg46ep61587DVVWEdNaGm7alEWfPkerLfv3v3NITy9lUJU37l94oQWdOjXmxRdjG9wVYOuYszZlcbTP0VrPdXNZxfHfZG/Z1cF+rA1Ak7VpE0f79KlclrhwIQVHj9J27VpUHh41WgauHD/ekJqHmJgxgIJ27dZZedL8V2X1nZW1iaNH+1T7CsBsrl5v1UdDyu+mrE30OdqnWh//\");\n    result.append(\"lLgphHuGE+QcVOXcX4kJE6NiRmG02B6MzHDxImfHj8e1Z08Cpk2r0bSUMGcOzhVPsdenvbV8q22Zzd/QgPo8Lm4ysRXnfkPyqy5du3ZlxowZzJo1i88++6zGck9PT1599VXuvvtuDh48iJOT0w2tA7W8BJiu1/NldjYJJSVcMhhYm57OMJ0OV0dHMvR6DBUXmU8yM5mbkECGXk9UQQEtKyr9AqOx8hvwxcnJlJrNTPb3r3ZRsHnjka4n+8tsShJKMFwykL42Hd0wHY6ujugz9JgNNU/6ojNFpK1NK7/T+jKbRu0aWX1JqL70+nSys7+kpCQBg+ES6elr0emG4eCgobQ0BYPhUkUhmEJZWQ4ajR8nTw6uWgQpKvodozGfdu3WN7D5OY858fHsu3yZmY6OFJtMaCv6dXZeuoQCOJiXx+MnTjAzKIgwNzdyDQZSSksxWixctJF/tzJm1bJwI9tXi/9zHnPmxLNv32VmznSkuNiEVlux/c5LKBRw8GAejz9+gpkzgwgLcyMjQ4/BSlnIySnjq6+yOXOmCJVKwYcfpjNkiBfu7ra/A/8k8xPmJswlQ59BVEEULZ1bVpTngsrvmhcnL6bUXMpk/8kEOQeRoc/AYDZUVoA5ZTn4afwYXKUsmDHze9Hv5BvzWd/AslCfsm0qNFGaWoqx0IhZbyb7q2wufn8RY4GRhDkJeD/jjXOrhr0Id+ZMEWsrYn75ZTbt2jWq9tJfbq6BlJRSjEYLGRklLFqUxEcfZTBwoCdJSSUEBpbH++mnPEpKzOTmGrj//t+YPbslw4c3v+ljNuQaKE0pLf9MsMqHIBazhewvsrnw9QUsZgvxs+LxHuWNNkTb4HTP/fFHUletKn/6XbGivE+5T58qvyGX0pQULEYjRYmJJM6fj7JRI9LXrSN93bWLgOnKFfIOHSJ02bIGNCV/TG7uXjSaAH7/fdJ1dVMmBQVH6N07puKilUtpaQoWixGzGbKzv+Lixe8xGgtISJiDt/cz9XoTvSHlN9eQS0ppCkaL\");\n    result.append(\"kSN5R5gTP4d9l/cx03EmxaZitEptxbm/EwUKDuYd5PETjzMzaCZhbtb75eOmTKEsJweNnx8nBw+u2ixI0e+/Y8zPp9369TXSnipfIpXl5JD91VcUnTmDQqUi/cMP8RoyBJW7e73SvSH1uV6fgbni3G9IfjVEly5dys+HoiIaVQysdtXHH39Mx44d+fTTTxlZyyBTda0jkwHJZEDYOQHu6PyXyYDu8AIokwHd2el/3fEPHDgQPz8/VlXceJZ3HWSze/duRo4cyZtvvsl3333HkSPl7yN9/fXXjBo1iqioKEIrPr2vzzr16gIQQgghxO23a9cufvvtN/bt28eiRYuIjIxk9uzZ9O7dm379+nHs2DF27dpFXFwc33//PSaTiUGDBjF48GD69evHxx9/zOHDh+tcR1+la0RaAKQFQB5BpAVAWgCkBUBaAP4ELQBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBC\");\n    result.append(\"CCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEHe6/w9fw3EBXkQ95QAAAABJRU5ErkJggg==\");\n    return result;\n}\n"
  },
  {
    "path": "src/stim/diagram/gate_data_3d_texture_data.h",
    "content": "#ifndef _STIM_DIAGRAM_GATE_DATA_3d_TEXTURE_DATA_H\n#define _STIM_DIAGRAM_GATE_DATA_3d_TEXTURE_DATA_H\n\n#include <string>\n\nnamespace stim_draw_internal {\n\nstd::string make_gate_3d_texture_data_uri();\n\n}\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/gate_data_svg.cc",
    "content": "#include \"stim/diagram/gate_data_svg.h\"\n\nusing namespace stim_draw_internal;\n\nstd::map<std::string_view, SvgGateData> SvgGateData::make_gate_data_map() {\n    std::map<std::string_view, SvgGateData> result;\n\n    result.insert({\"X\", {1, \"X\", \"\", \"\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"Y\", {1, \"Y\", \"\", \"\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"Z\", {1, \"Z\", \"\", \"\", \"white\", \"black\", 0, 10, 0}});\n\n    result.insert({\"H_YZ\", {1, \"H\", \"YZ\", \"\", \"white\", \"black\", 22, 12, 0}});\n    result.insert({\"H\", {1, \"H\", \"\", \"\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"H_XY\", {1, \"H\", \"XY\", \"\", \"white\", \"black\", 22, 12, 0}});\n    result.insert({\"H_NXY\", {1, \"H\", \"NXY\", \"\", \"white\", \"black\", 22, 10, 0}});\n    result.insert({\"H_NXZ\", {1, \"H\", \"NXZ\", \"\", \"white\", \"black\", 22, 10, 0}});\n    result.insert({\"H_NYZ\", {1, \"H\", \"NYZ\", \"\", \"white\", \"black\", 22, 10, 0}});\n\n    result.insert({\"SQRT_X\", {1, \"√X\", \"\", \"\", \"white\", \"black\", 24, 0}});\n    result.insert({\"SQRT_Y\", {1, \"√Y\", \"\", \"\", \"white\", \"black\", 24, 0}});\n    result.insert({\"S\", {1, \"S\", \"\", \"\", \"white\", \"black\", 0, 10, 0}});\n\n    result.insert({\"SQRT_X_DAG\", {1, \"√X\", \"\", \"†\", \"white\", \"black\", 18, 14, 0}});\n    result.insert({\"SQRT_Y_DAG\", {1, \"√Y\", \"\", \"†\", \"white\", \"black\", 18, 14, 0}});\n    result.insert({\"S_DAG\", {1, \"S\", \"\", \"†\", \"white\", \"black\", 26, 14, 0}});\n\n    result.insert({\"MX\", {1, \"M\", \"X\", \"\", \"black\", \"white\", 26, 16, 0}});\n    result.insert({\"MY\", {1, \"M\", \"Y\", \"\", \"black\", \"white\", 26, 16, 0}});\n    result.insert({\"M\", {1, \"M\", \"\", \"\", \"black\", \"white\", 0, 10, 0}});\n\n    result.insert({\"RX\", {1, \"R\", \"X\", \"\", \"black\", \"white\", 26, 16, 0}});\n    result.insert({\"RY\", {1, \"R\", \"Y\", \"\", \"black\", \"white\", 26, 16, 0}});\n    result.insert({\"R\", {1, \"R\", \"\", \"\", \"black\", \"white\", 0, 10, 0}});\n\n    result.insert({\"MRX\", {1, \"MR\", \"X\", \"\", \"black\", \"white\", 0, 14, 0}});\n    result.insert({\"MRY\", {1, \"MR\", \"Y\", \"\", \"black\", \"white\", 0, 14, 0}});\n    result.insert({\"MR\", {1, \"MR\", \"\", \"\", \"black\", \"white\", 24, 16, 0}});\n\n    result.insert({\"I_ERROR\", {1, \"ERR\", \"I\", \"\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"II_ERROR\", {1, \"ERR\", \"II\", \"\", \"white\", \"black\", 10, 10, 0}});\n    result.insert({\"X_ERROR\", {1, \"ERR\", \"X\", \"\", \"pink\", \"black\", 0, 10, 0}});\n    result.insert({\"Y_ERROR\", {1, \"ERR\", \"Y\", \"\", \"pink\", \"black\", 0, 10, 0}});\n    result.insert({\"Z_ERROR\", {1, \"ERR\", \"Z\", \"\", \"pink\", \"black\", 0, 10, 0}});\n\n    result.insert({\"E[X]\", {1, \"E\", \"X\", \"\", \"pink\", \"black\", 0, 10, 0}});\n    result.insert({\"E[Y]\", {1, \"E\", \"Y\", \"\", \"pink\", \"black\", 0, 10, 0}});\n    result.insert({\"E[Z]\", {1, \"E\", \"Z\", \"\", \"pink\", \"black\", 0, 10, 0}});\n\n    result.insert({\"ELSE_CORRELATED_ERROR[X]\", {1, \"EE\", \"X\", \"\", \"pink\", \"black\", 0, 10, 0}});\n    result.insert({\"ELSE_CORRELATED_ERROR[Y]\", {1, \"EE\", \"Y\", \"\", \"pink\", \"black\", 0, 10, 0}});\n    result.insert({\"ELSE_CORRELATED_ERROR[Z]\", {1, \"EE\", \"Z\", \"\", \"pink\", \"black\", 0, 10, 0}});\n\n    result.insert({\"MPP[X]\", {1, \"MPP\", \"X\", \"\", \"black\", \"white\", 0, 10, 0}});\n    result.insert({\"MPP[Y]\", {1, \"MPP\", \"Y\", \"\", \"black\", \"white\", 0, 10, 0}});\n    result.insert({\"MPP[Z]\", {1, \"MPP\", \"Z\", \"\", \"black\", \"white\", 0, 10, 0}});\n\n    result.insert({\"SPP[X]\", {1, \"SPP\", \"X\", \"\", \"black\", \"white\", 0, 10, 0}});\n    result.insert({\"SPP[Y]\", {1, \"SPP\", \"Y\", \"\", \"black\", \"white\", 0, 10, 0}});\n    result.insert({\"SPP[Z]\", {1, \"SPP\", \"Z\", \"\", \"black\", \"white\", 0, 10, 0}});\n\n    result.insert({\"SPP_DAG[X]\", {1, \"SPP†\", \"X\", \"\", \"black\", \"white\", 0, 10, 0}});\n    result.insert({\"SPP_DAG[Y]\", {1, \"SPP†\", \"Y\", \"\", \"black\", \"white\", 0, 10, 0}});\n    result.insert({\"SPP_DAG[Z]\", {1, \"SPP†\", \"Z\", \"\", \"black\", \"white\", 0, 10, 0}});\n\n    result.insert({\"SQRT_XX\", {1, \"√XX\", \"\", \"\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"SQRT_YY\", {1, \"√YY\", \"\", \"\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"SQRT_ZZ\", {1, \"√ZZ\", \"\", \"\", \"white\", \"black\", 0, 10, 0}});\n\n    result.insert({\"SQRT_XX_DAG\", {1, \"√XX\", \"\", \"†\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"SQRT_YY_DAG\", {1, \"√YY\", \"\", \"†\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"SQRT_ZZ_DAG\", {1, \"√ZZ\", \"\", \"†\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"II\", {1, \"II\", \"\", \"\", \"white\", \"gray\", 0, 10, 0}});\n\n    result.insert({\"I\", {1, \"I\", \"\", \"\", \"white\", \"black\", 0, 10, 0}});\n    result.insert({\"C_XYZ\", {1, \"C\", \"XYZ\", \"\", \"white\", \"black\", 18, 10, 0}});\n    result.insert({\"C_NXYZ\", {1, \"C\", \"NXYZ\", \"\", \"white\", \"black\", 18, 8, 0}});\n    result.insert({\"C_XNYZ\", {1, \"C\", \"XNYZ\", \"\", \"white\", \"black\", 18, 8, 0}});\n    result.insert({\"C_XYNZ\", {1, \"C\", \"XYNZ\", \"\", \"white\", \"black\", 18, 8, 0}});\n    result.insert({\"C_ZYX\", {1, \"C\", \"ZYX\", \"\", \"white\", \"black\", 18, 10, 0}});\n    result.insert({\"C_NZYX\", {1, \"C\", \"NZYX\", \"\", \"white\", \"black\", 18, 8, 0}});\n    result.insert({\"C_ZNYX\", {1, \"C\", \"ZNYX\", \"\", \"white\", \"black\", 18, 8, 0}});\n    result.insert({\"C_ZYNX\", {1, \"C\", \"ZYNX\", \"\", \"white\", \"black\", 18, 8, 0}});\n\n    result.insert({\"DEPOLARIZE1\", {1, \"DEP\", \"1\", \"\", \"pink\", \"black\", 0, 10, 0}});\n    result.insert({\"DEPOLARIZE2\", {1, \"DEP\", \"2\", \"\", \"pink\", \"black\", 0, 10, 0}});\n\n    result.insert({\"PAULI_CHANNEL_1\", {4, \"PAULI_CHANNEL_1\", \"\", \"\", \"pink\", \"black\", 0, 10, 0}});\n    result.insert({\"PAULI_CHANNEL_2[0]\", {16, \"PAULI_CHANNEL_2\", \"0\", \"\", \"pink\", \"black\", 0, 10, 0}});\n    result.insert({\"PAULI_CHANNEL_2[1]\", {16, \"PAULI_CHANNEL_2\", \"1\", \"\", \"pink\", \"black\", 0, 10, 0}});\n\n    result.insert({\"MXX\", {1, \"M\", \"XX\", \"\", \"black\", \"white\", 18, 18, -6}});\n    result.insert({\"MYY\", {1, \"M\", \"YY\", \"\", \"black\", \"white\", 18, 18, -6}});\n    result.insert({\"MZZ\", {1, \"M\", \"ZZ\", \"\", \"black\", \"white\", 18, 18, -6}});\n    result.insert({\"MPAD\", {1, \"M\", \"PAD\", \"\", \"gray\", \"white\", 18, 12, -6}});\n    result.insert({\"HERALDED_ERASE\", {1, \"HErase\", \"\", \"\", \"#800000\", \"white\", 8, 10}});\n    result.insert({\"HERALDED_PAULI_CHANNEL_1\", {4, \"HERALDED_PAULI_CHANNEL_1\", \"\", \"\", \"#800000\", \"white\", 14, 10}});\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/diagram/gate_data_svg.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_GATE_DATA_SVG_H\n#define _STIM_DIAGRAM_GATE_DATA_SVG_H\n\n#include <cstdint>\n#include <map>\n#include <string>\n\nnamespace stim_draw_internal {\n\nstruct SvgGateData {\n    uint16_t span;\n    std::string body;\n    std::string subscript;\n    std::string superscript;\n    std::string fill;\n    std::string text_color;\n    size_t font_size;\n    size_t sub_font_size;\n    int32_t y_shift;\n\n    static std::map<std::string_view, SvgGateData> make_gate_data_map();\n};\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/gltf.cc",
    "content": "#include \"stim/diagram/gltf.h\"\n\n#include <iostream>\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nvoid GltfScene::visit(const gltf_visit_callback &callback) {\n    callback(\n        id,\n        \"scenes\",\n        [&]() {\n            return _to_json_local();\n        },\n        (uintptr_t)this);\n    for (auto &node : nodes) {\n        node->visit(callback);\n    }\n}\n\nJsonObj GltfScene::_to_json_local() const {\n    std::vector<JsonObj> scene_nodes_json;\n    for (const auto &n : nodes) {\n        scene_nodes_json.push_back(n->id.index);\n    }\n    return std::map<std::string, JsonObj>{\n        {\"nodes\", std::move(scene_nodes_json)},\n    };\n}\n\nJsonObj GltfScene::to_json() {\n    // Clear indices.\n    visit([&](GltfId &item_id, const char *type, const std::function<JsonObj(void)> &to_json, uintptr_t abs_id) {\n        item_id.index = UINT64_MAX;\n    });\n\n    // Re-index.\n    std::map<std::string, size_t> counts;\n    visit([&](GltfId &item_id, const char *type, const std::function<JsonObj(void)> &to_json, uintptr_t abs_id) {\n        auto &c = counts[type];\n        if (item_id.index == UINT64_MAX || item_id.index == c) {\n            item_id.index = c;\n            c++;\n        } else if (item_id.index > c) {\n            throw std::invalid_argument(\"out of order\");\n        }\n    });\n\n    std::map<std::string, JsonObj> result{\n        {\"scene\", 0},\n        {\"asset\",\n         std::map<std::string, JsonObj>{\n             {\"version\", \"2.0\"},\n         }},\n    };\n    for (const auto &r : counts) {\n        result.insert({r.first, std::vector<JsonObj>{}});\n    }\n    visit([&](GltfId &item_id, const char *type, const std::function<JsonObj(void)> &to_json, uintptr_t abs_id) {\n        auto &list = result.at(type).arr;\n        if (item_id.index == list.size()) {\n            list.push_back(to_json());\n        }\n    });\n\n    return result;\n}\n\nvoid GltfSampler::visit(const gltf_visit_callback &callback) {\n    callback(\n        id,\n        \"samplers\",\n        [&]() {\n            return to_json();\n        },\n        (uintptr_t)this);\n}\n\nJsonObj GltfSampler::to_json() const {\n    return std::map<std::string, JsonObj>{\n        {\"magFilter\", magFilter},\n        {\"minFilter\", minFilter},\n        {\"wrapS\", wrapS},\n        {\"wrapT\", wrapT},\n    };\n}\n\nvoid GltfImage::visit(const gltf_visit_callback &callback) {\n    callback(\n        id,\n        \"images\",\n        [&]() {\n            return to_json();\n        },\n        (uintptr_t)this);\n}\n\nJsonObj GltfImage::to_json() const {\n    return std::map<std::string, JsonObj>{\n        // Note: saving space by not including names.\n        //{\"name\", id.name},\n        {\"uri\", uri},\n    };\n}\n\nvoid GltfTexture::visit(const gltf_visit_callback &callback) {\n    callback(\n        id,\n        \"textures\",\n        [&]() {\n            return to_json();\n        },\n        (uintptr_t)this);\n    sampler->visit(callback);\n    source->visit(callback);\n}\n\nJsonObj GltfTexture::to_json() const {\n    return std::map<std::string, JsonObj>{\n        // Note: saving space by not including names.\n        //        {\"name\", id.name},\n        {\"sampler\", 0},\n        {\"source\", 0},\n    };\n}\n\nvoid GltfMaterial::visit(const gltf_visit_callback &callback) {\n    callback(\n        id,\n        \"materials\",\n        [&]() {\n            return to_json();\n        },\n        (uintptr_t)this);\n    if (texture) {\n        texture->visit(callback);\n    }\n}\n\nJsonObj GltfMaterial::to_json() const {\n    JsonObj result = std::map<std::string, JsonObj>{\n        //        {\"name\", id.name},\n        {\"pbrMetallicRoughness\",\n         std::map<std::string, JsonObj>{\n             {\"baseColorFactor\",\n              std::vector<JsonObj>{\n                  base_color_factor_rgba[0],\n                  base_color_factor_rgba[1],\n                  base_color_factor_rgba[2],\n                  base_color_factor_rgba[3],\n              }},\n             {\"metallicFactor\", metallic_factor},\n             {\"roughnessFactor\", roughness_factor}}},\n        {\"doubleSided\", double_sided},\n    };\n    if (texture) {\n        result.map.at(\"pbrMetallicRoughness\")\n            .map.insert(\n                {\"baseColorTexture\",\n                 std::map<std::string, JsonObj>{\n                     {\"index\", texture->id.index},\n                     {\"texCoord\", 0},\n                 }});\n    }\n    return result;\n}\n\nvoid GltfPrimitive::visit(const gltf_visit_callback &callback) {\n    position_buffer->visit(callback);\n    if (tex_coords_buffer) {\n        tex_coords_buffer->visit(callback);\n    }\n    material->visit(callback);\n}\n\nJsonObj GltfPrimitive::to_json() const {\n    std::map<std::string, JsonObj> attributes;\n    attributes.insert({\"POSITION\", position_buffer->id.index});\n    if (tex_coords_buffer) {\n        attributes.insert({\"TEXCOORD_0\", tex_coords_buffer->id.index});\n    }\n    return std::map<std::string, JsonObj>{\n        // Note: validator says \"name\" not expected for primitives.\n        // {\"name\", id.name},\n        {\"attributes\", std::move(attributes)},\n        {\"material\", material->id.index},\n        {\"mode\", element_type},\n    };\n}\n\nstd::shared_ptr<GltfMesh> GltfMesh::from_singleton_primitive(std::shared_ptr<GltfPrimitive> primitive) {\n    return std::shared_ptr<GltfMesh>(new GltfMesh{\n        {\"mesh_\" + primitive->id.name},\n        {primitive},\n    });\n}\n\nvoid GltfMesh::visit(const gltf_visit_callback &callback) {\n    callback(\n        id,\n        \"meshes\",\n        [&]() {\n            return to_json();\n        },\n        (uintptr_t)this);\n    for (auto &p : primitives) {\n        p->visit(callback);\n    }\n}\n\nJsonObj GltfMesh::to_json() const {\n    std::vector<JsonObj> json_primitives;\n    for (const auto &p : primitives) {\n        json_primitives.push_back(p->to_json());\n    }\n    return std::map<std::string, JsonObj>{\n        {\"primitives\", std::move(json_primitives)},\n    };\n}\n\nvoid GltfNode::visit(const gltf_visit_callback &callback) {\n    callback(\n        id,\n        \"nodes\",\n        [&]() {\n            return to_json();\n        },\n        (uintptr_t)this);\n    if (mesh) {\n        mesh->visit(callback);\n    }\n}\n\nJsonObj GltfNode::to_json() const {\n    return std::map<std::string, JsonObj>{\n        {\"mesh\", mesh->id.index},\n        {\"translation\", (std::vector<JsonObj>{translation.xyz[0], translation.xyz[1], translation.xyz[2]})},\n    };\n}\n\nvoid stim_draw_internal::write_html_viewer_for_gltf_data(std::string_view gltf_data, std::ostream &out) {\n    out << R\"HTML(\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"UTF-8\" />\n  <script type=\"importmap\">\n    {\n      \"imports\": {\n        \"three\": \"https://unpkg.com/three@0.138.0/build/three.module.js\",\n        \"three-orbitcontrols\": \"https://unpkg.com/three@0.138.0/examples/jsm/controls/OrbitControls.js\",\n        \"three-gltf-loader\": \"https://unpkg.com/three@0.138.0/examples/jsm/loaders/GLTFLoader.js\"\n      }\n    }\n  </script>\n</head>\n<body>\n  <a download=\"model.gltf\" id=\"stim-3d-viewer-download-link\" href=\"data:text/plain;base64,)HTML\";\n    write_data_as_base64_to(gltf_data, out);\n    out << R\"HTML(\">Download 3D Model as .GLTF File</a>\n  <br>Mouse Wheel = Zoom. Left Drag = Orbit. Right Drag = Strafe.\n  <div id=\"stim-3d-viewer-scene-container\" style=\"width: calc(100vw - 32px); height: calc(100vh - 64px);\">JavaScript Blocked?</div>\n\n  <script type=\"module\">\n    let container = document.getElementById(\"stim-3d-viewer-scene-container\");\n    let downloadLink = document.getElementById(\"stim-3d-viewer-download-link\");\n    container.textContent = \"Loading viewer...\";\n\n    /// BEGIN TERRIBLE HACK.\n    /// Change the ID to avoid cross-cell interactions.\n    /// This is a workaround for https://github.com/jupyter/notebook/issues/6598\n    container.id = undefined;\n    downloadLink.id = undefined;\n\n    import {Box3, Scene, Color, PerspectiveCamera, WebGLRenderer, DirectionalLight, Vector3} from \"three\";\n    import {OrbitControls} from \"three-orbitcontrols\";\n    import {GLTFLoader} from \"three-gltf-loader\";\n\n    try {\n      container.textContent = \"Loading model...\";\n      let modelDataUri = downloadLink.href;\n      let gltf = await new GLTFLoader().loadAsync(modelDataUri);\n      container.textContent = \"Loading scene...\";\n\n      // Create the scene, adding lighting for the loaded objects.\n      let scene = new Scene();\n      scene.background = new Color(\"white\");\n      let mainLight = new DirectionalLight(0xffffff, 5);\n      mainLight.position.set(1, 1, 0);\n      let backLight = new DirectionalLight(0xffffff, 4);\n      backLight.position.set(-1, -1, 0);\n      scene.add(mainLight, backLight);\n      scene.add(gltf.scene);\n\n      // Point the camera at the center, far enough back to see everything.\n      let camera = new PerspectiveCamera(35, container.clientWidth / container.clientHeight, 0.1, 100000);\n      let controls = new OrbitControls(camera, container);\n      let bounds = new Box3().setFromObject(scene);\n      let mid = new Vector3(\n          (bounds.min.x + bounds.max.x) * 0.5,\n          (bounds.min.y + bounds.max.y) * 0.5,\n          (bounds.min.z + bounds.max.z) * 0.5,\n      );\n      let boxPoints = [];\n      for (let dx of [0, 0.5, 1]) {\n          for (let dy of [0, 0.5, 1]) {\n              for (let dz of [0, 0.5, 1]) {\n                  boxPoints.push(new Vector3(\n                      bounds.min.x + (bounds.max.x - bounds.min.x) * dx,\n                      bounds.min.y + (bounds.max.y - bounds.min.y) * dy,\n                      bounds.min.z + (bounds.max.z - bounds.min.z) * dz,\n                  ));\n              }\n          }\n      }\n      let isInView = p => {\n          p = new Vector3(p.x, p.y, p.z);\n          p.project(camera);\n          return Math.abs(p.x) < 1 && Math.abs(p.y) < 1 && p.z >= 0 && p.z < 1;\n      };\n      let unit = new Vector3(0.3, 0.4, -1.8);\n      unit.normalize();\n      let setCameraDistance = d => {\n          controls.target.copy(mid);\n          camera.position.copy(mid);\n          camera.position.addScaledVector(unit, d);\n          controls.update();\n          return boxPoints.every(isInView);\n      };\n\n      let maxDistance = 1;\n      for (let k = 0; k < 20; k++) {\n          if (setCameraDistance(maxDistance)) {\n              break;\n          }\n          maxDistance *= 2;\n      }\n      let minDistance = maxDistance;\n      for (let k = 0; k < 20; k++) {\n          minDistance /= 2;\n          if (!setCameraDistance(minDistance)) {\n              break;\n          }\n      }\n      for (let k = 0; k < 20; k++) {\n          let mid = (minDistance + maxDistance) / 2;\n          if (setCameraDistance(mid)) {\n              maxDistance = mid;\n          } else {\n              minDistance = mid;\n          }\n      }\n      setCameraDistance(maxDistance);\n\n      // Set up rendering.\n      let renderer = new WebGLRenderer({ antialias: true });\n      container.textContent = \"\";\n      renderer.setSize(container.clientWidth, container.clientHeight);\n      renderer.setPixelRatio(window.devicePixelRatio);\n      renderer.physicallyCorrectLights = true;\n      container.appendChild(renderer.domElement);\n\n      // Render whenever any important changes have occurred.\n      requestAnimationFrame(() => renderer.render(scene, camera));\n      new ResizeObserver(() => {\n        let w = container.clientWidth;\n        let h = container.clientHeight;\n        camera.aspect = w / h;\n        camera.updateProjectionMatrix();\n        renderer.setSize(w, h);\n        renderer.render(scene, camera);\n      }).observe(container);\n      controls.addEventListener(\"change\", () => {\n          renderer.render(scene, camera);\n      })\n    } catch (ex) {\n      container.textContent = \"Failed to show model. \" + ex;\n      console.error(ex);\n    }\n  </script>\n</body>\n)HTML\";\n}\n"
  },
  {
    "path": "src/stim/diagram/gltf.h",
    "content": "#ifndef _STIM_DRAW_3D_GLTF_H\n#define _STIM_DRAW_3D_GLTF_H\n\n#include <functional>\n#include <iostream>\n\n#include \"base64.h\"\n#include \"stim/diagram/coord.h\"\n#include \"stim/diagram/json_obj.h\"\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim_draw_internal {\n\nconstexpr uint64_t GL_FLOAT = 5126;\nconstexpr uint64_t GL_ARRAY_BUFFER = 34962;\nconstexpr uint64_t GL_TRIANGLES = 4;\nconstexpr uint64_t GL_TRIANGLE_FAN = 6;\n\nconstexpr uint64_t GL_LINES = 1;\nconstexpr uint64_t GL_LINE_STRIP = 3;\nconstexpr uint64_t GL_LINE_LOOP = 2;\n\nconstexpr uint64_t GL_CLAMP_TO_EDGE = 33071;\nconstexpr uint64_t GL_NEAREST = 9728;\n\nstruct GltfId {\n    std::string name;\n    uint64_t index;\n\n    GltfId(std::string name) : name(name), index(UINT64_MAX) {\n    }\n    GltfId() = delete;\n};\n\ntypedef std::function<void(GltfId &id, const char *type, const std::function<JsonObj(void)> &to_json, uintptr_t abs_id)>\n    gltf_visit_callback;\n\n/// A named data buffer. Contains packed coordinate data.\ntemplate <size_t DIM>\nstruct GltfBuffer {\n    GltfId id;\n    std::vector<Coord<DIM>> vertices;\n\n    void visit(const gltf_visit_callback &callback) {\n        callback(\n            id,\n            \"buffers\",\n            [&]() {\n                return to_json_buffer();\n            },\n            (uintptr_t)this);\n        callback(\n            id,\n            \"bufferViews\",\n            [&]() {\n                return to_json_buffer_view();\n            },\n            (uintptr_t)this);\n        callback(\n            id,\n            \"accessors\",\n            [&]() {\n                return to_json_accessor();\n            },\n            (uintptr_t)this);\n    }\n\n    JsonObj to_json_buffer() const {\n        std::stringstream ss;\n        ss << \"data:application/octet-stream;base64,\";\n        size_t vertex_data_size = vertices.size() * sizeof(Coord<DIM>);\n        std::string_view vertex_data{(const char *)(const void *)vertices.data(), vertex_data_size};\n        write_data_as_base64_to(vertex_data, ss);\n        return std::map<std::string, JsonObj>{\n            {\"name\", id.name},\n            {\"uri\", ss.str()},\n            {\"byteLength\", (uint64_t)vertex_data_size},\n        };\n    }\n\n    JsonObj to_json_buffer_view() const {\n        return std::map<std::string, JsonObj>{\n            {\"name\", id.name},\n            {\"buffer\", id.index},\n            {\"byteOffset\", 0},\n            {\"byteLength\", (uint64_t)(vertices.size() * sizeof(Coord<DIM>))},\n            {\"target\", GL_ARRAY_BUFFER},\n        };\n    }\n\n    JsonObj to_json_accessor() const {\n        auto mima = Coord<DIM>::min_max(vertices);\n        std::vector<JsonObj> min_v;\n        std::vector<JsonObj> max_v;\n        for (size_t k = 0; k < DIM; k++) {\n            // Double precision is needed here because serializing a float to\n            // decimal then parsing it as a double can produce a slightly\n            // different value (because when you use the shortest decimal\n            // pattern that is uniquely closest to one float and serialize to\n            // that, there may be a closer double that is then picked when\n            // parsing). We need these values going through JSON land to end up\n            // exactly the same as the buffer floats going through binary land.\n            min_v.push_back((double)mima.first.xyz[k]);\n            max_v.push_back((double)mima.second.xyz[k]);\n        }\n        return std::map<std::string, JsonObj>{\n            {\"name\", id.name},\n            {\"bufferView\", id.index},\n            {\"byteOffset\", 0},\n            {\"componentType\", GL_FLOAT},\n            {\"count\", (uint64_t)vertices.size()},\n            {\"type\", \"VEC\" + std::to_string(DIM)},\n            {\"min\", std::move(min_v)},\n            {\"max\", std::move(max_v)},\n        };\n    }\n};\n\nstruct GltfSampler {\n    GltfId id;\n    uint64_t magFilter;\n    uint64_t minFilter;\n    uint64_t wrapS;\n    uint64_t wrapT;\n\n    void visit(const gltf_visit_callback &callback);\n    JsonObj to_json() const;\n};\n\nstruct GltfImage {\n    GltfId id;\n    std::string uri;\n\n    void visit(const gltf_visit_callback &callback);\n    JsonObj to_json() const;\n};\n\nstruct GltfTexture {\n    GltfId id;\n    std::shared_ptr<GltfSampler> sampler;\n    std::shared_ptr<GltfImage> source;\n\n    void visit(const gltf_visit_callback &callback);\n    JsonObj to_json() const;\n};\n\nstruct GltfMaterial {\n    GltfId id;\n    std::array<float, 4> base_color_factor_rgba;\n    float metallic_factor;\n    float roughness_factor;\n    bool double_sided;\n    std::shared_ptr<GltfTexture> texture;\n\n    void visit(const gltf_visit_callback &callback);\n    JsonObj to_json() const;\n};\n\nstruct GltfPrimitive {\n    GltfId id;\n    uint64_t element_type;\n    std::shared_ptr<GltfBuffer<3>> position_buffer;\n    std::shared_ptr<GltfBuffer<2>> tex_coords_buffer;\n    std::shared_ptr<GltfMaterial> material;\n\n    void visit(const gltf_visit_callback &callback);\n    JsonObj to_json() const;\n};\n\nstruct GltfMesh {\n    GltfId id;\n    std::vector<std::shared_ptr<GltfPrimitive>> primitives;\n\n    static std::shared_ptr<GltfMesh> from_singleton_primitive(std::shared_ptr<GltfPrimitive> primitive);\n    void visit(const gltf_visit_callback &callback);\n    JsonObj to_json() const;\n};\n\nstruct GltfNode {\n    GltfId id;\n    std::shared_ptr<GltfMesh> mesh;\n    Coord<3> translation;\n\n    void visit(const gltf_visit_callback &callback);\n    JsonObj to_json() const;\n};\n\nstruct GltfScene {\n    GltfId id;\n    std::vector<std::shared_ptr<GltfNode>> nodes;\n\n    void visit(const gltf_visit_callback &callback);\n    JsonObj _to_json_local() const;\n    JsonObj to_json();\n};\n\nvoid write_html_viewer_for_gltf_data(std::string_view gltf_data, std::ostream &out);\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/graph/match_graph_3d_drawer.cc",
    "content": "#include \"stim/diagram/graph/match_graph_3d_drawer.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nCoord<3> flattened_3d(SpanRef<const double> c) {\n    float x = 0;\n    float y = 0;\n    float z = 0;\n    if (c.size() >= 1) {\n        x = c[0];\n    }\n    if (c.size() >= 2) {\n        y = c[1];\n    }\n    if (c.size() >= 3) {\n        z = c[2];\n    }\n\n    // Arbitrary orthographic projection.\n    for (size_t k = 3; k < c.size(); k++) {\n        x += c[k] / k;\n        y += c[k] / (k * k);\n        x += c[k] / (k * k * k);\n    }\n\n    return {x * 3, y * 3, z * 3};\n}\n\nstd::vector<Coord<3>> pick_coordinates(const DetectorErrorModel &dem) {\n    std::set<uint64_t> det_set;\n    uint64_t n = dem.count_detectors();\n    std::set<Coord<3>> used_coords;\n    std::vector<Coord<3>> coords;\n    coords.resize(n);\n    float min_z = 0;\n    for (uint64_t k = 0; k < n; k++) {\n        det_set.insert(k);\n    }\n    auto dem_coords = dem.get_detector_coordinates(det_set);\n    for (auto &kv : dem_coords) {\n        if (kv.second.size() == 0) {\n            continue;\n        }\n        coords[kv.first] = flattened_3d(kv.second);\n        used_coords.insert(coords[kv.first]);\n        min_z = std::min(min_z, coords[kv.first].xyz[2]);\n    }\n\n    float next_x = 0;\n    float next_y = 0;\n    float dx = 1;\n    float dy = -1;\n    for (size_t d = 0; d < n; d++) {\n        auto p = dem_coords.find(d);\n        if (p == dem_coords.end() || p->second.size() == 0) {\n            coords[d] = {next_x * 3, next_y * 3, min_z - 1};\n            next_x += dx;\n            next_y += dy;\n            if (next_y < 0 || next_x < 0) {\n                next_x = std::max(next_x, 0.0f);\n                next_y = std::max(next_y, 0.0f);\n                dx *= -1;\n                dy *= -1;\n            }\n        }\n    }\n    if (next_x || next_y) {\n        std::cerr << \"Warning: not all detectors had coordinates. Placed them arbitrarily.\\n\";\n    }\n    return coords;\n}\n\nBasic3dDiagram stim_draw_internal::dem_match_graph_to_basic_3d_diagram(const stim::DetectorErrorModel &dem) {\n    Basic3dDiagram out;\n\n    auto coords = pick_coordinates(dem);\n    auto minmax = Coord<3>::min_max(coords);\n    auto center = (minmax.first + minmax.second) * 0.5;\n\n    std::set<uint64_t> boundary_observable_detectors;\n    std::vector<Coord<3>> det_coords;\n    auto handle_contiguous_targets = [&](SpanRef<const DemTarget> targets) {\n        bool has_observables = false;\n        det_coords.clear();\n        for (const auto &t : targets) {\n            has_observables |= t.is_observable_id();\n            if (t.is_relative_detector_id()) {\n                det_coords.push_back(coords[t.raw_id()]);\n            }\n        }\n        if (det_coords.empty()) {\n            return;\n        }\n        if (det_coords.size() == 1) {\n            auto d = det_coords[0] - center;\n            auto r = d.norm();\n            if (r < 1e-4) {\n                d = {1, 0, 0};\n            } else {\n                d /= r;\n            }\n            auto a = det_coords[0];\n            det_coords.push_back(a + d * 10);\n            if (has_observables) {\n                for (auto t : targets) {\n                    if (t.is_relative_detector_id()) {\n                        boundary_observable_detectors.insert(t.val());\n                    }\n                }\n            }\n        }\n        if (det_coords.size() == 2) {\n            if (has_observables) {\n                out.red_line_data.push_back(det_coords[0]);\n                out.red_line_data.push_back(det_coords[1]);\n            } else {\n                out.line_data.push_back(det_coords[0]);\n                out.line_data.push_back(det_coords[1]);\n            }\n        } else {\n            Coord<3> c{0, 0, 0};\n            for (const auto &e : det_coords) {\n                c += e;\n            }\n            c /= det_coords.size();\n            for (const auto &e : det_coords) {\n                if (has_observables) {\n                    out.purple_line_data.push_back(c);\n                    out.purple_line_data.push_back(e);\n                } else {\n                    out.blue_line_data.push_back(c);\n                    out.blue_line_data.push_back(e);\n                }\n            }\n        }\n    };\n\n    dem.iter_flatten_error_instructions([&](const DemInstruction &op) {\n        if (op.type != DemInstructionType::DEM_ERROR) {\n            return;\n        }\n        auto *p = op.target_data.ptr_start;\n        size_t start = 0;\n        for (size_t k = 0; k < op.target_data.size(); k++) {\n            if (op.target_data[k].is_separator()) {\n                handle_contiguous_targets({p + start, p + k});\n                start = k + 1;\n            }\n        }\n        handle_contiguous_targets({p + start, op.target_data.ptr_end});\n    });\n\n    for (size_t k = 0; k < coords.size(); k++) {\n        bool excited = boundary_observable_detectors.find(k) != boundary_observable_detectors.end();\n        out.elements.push_back({excited ? \"EXCITED_DETECTOR\" : \"DETECTOR\", coords[k]});\n    }\n\n    return out;\n}\n"
  },
  {
    "path": "src/stim/diagram/graph/match_graph_3d_drawer.h",
    "content": "#ifndef _STIM_DIAGRAM_GRAPH_MATCH_GRAPH_DRAWER_H\n#define _STIM_DIAGRAM_GRAPH_MATCH_GRAPH_DRAWER_H\n\n#include <iostream>\n\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/diagram/basic_3d_diagram.h\"\n#include \"stim/diagram/circuit_timeline_helper.h\"\n\nnamespace stim_draw_internal {\n\nBasic3dDiagram dem_match_graph_to_basic_3d_diagram(const stim::DetectorErrorModel &dem);\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/graph/match_graph_3d_drawer.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/diagram/graph/match_graph_3d_drawer.h\"\n\n#include <fstream>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nvoid expect_graph_diagram_is_identical_to_saved_file(const DetectorErrorModel &dem, std::string_view key) {\n    auto diagram = dem_match_graph_to_basic_3d_diagram(dem);\n    std::stringstream actual_ss;\n    diagram.to_gltf_scene().to_json().write(actual_ss);\n    auto actual = actual_ss.str();\n    expect_string_is_identical_to_saved_file(actual_ss.str(), key);\n}\n\nTEST(match_graph_drawer_3d, repetition_code) {\n    CircuitGenParameters params(10, 7, \"memory\");\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_rep_code_circuit(params).circuit;\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, false, false, false);\n    expect_graph_diagram_is_identical_to_saved_file(dem, \"match_graph_repetition_code.gltf\");\n}\n\nTEST(match_graph_drawer_3d, surface_code) {\n    CircuitGenParameters params(10, 3, \"unrotated_memory_z\");\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, false, false, false);\n    expect_graph_diagram_is_identical_to_saved_file(dem, \"match_graph_surface_code.gltf\");\n}\n\nTEST(match_graph_drawer_3d, missing_coordinates) {\n    Circuit circuit(R\"CIRCUIT(\n        R 0 1 2 3 4 5 6 7 8 9 10\n        X_ERROR(0.125) 0 1 2 3 4 5 6 7 8 9 10\n        M 0 1 2 3 4 5 6 7 8 9 10\n        DETECTOR rec[-1] rec[-2]\n        DETECTOR rec[-2] rec[-3]\n        DETECTOR rec[-3] rec[-4]\n        DETECTOR rec[-4] rec[-5]\n        DETECTOR rec[-5] rec[-6]\n        DETECTOR rec[-6] rec[-7]\n        DETECTOR rec[-7] rec[-8]\n        DETECTOR rec[-8] rec[-9]\n        DETECTOR rec[-9] rec[-10]\n        OBSERVABLE_INCLUDE(1) rec[-1]\n    )CIRCUIT\");\n\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, false, false, false);\n\n    testing::internal::CaptureStderr();\n    auto diagram = dem_match_graph_to_basic_3d_diagram(dem);\n    std::string err = testing::internal::GetCapturedStderr();\n    ASSERT_NE(err, \"\");\n\n    std::stringstream ss;\n    diagram.to_gltf_scene().to_json().write(ss);\n    expect_string_is_identical_to_saved_file(ss.str(), \"match_graph_no_coords.gltf\");\n}\n\nTEST(match_graph_drawer_3d, works_on_empty) {\n    auto diagram = dem_match_graph_to_basic_3d_diagram(DetectorErrorModel());\n    std::stringstream ss;\n    diagram.to_gltf_scene().to_json().write(ss);\n    expect_string_is_identical_to_saved_file(ss.str(), \"empty_match_graph.gltf\");\n}\n"
  },
  {
    "path": "src/stim/diagram/graph/match_graph_svg_drawer.cc",
    "content": "#include \"stim/diagram/graph/match_graph_svg_drawer.h\"\n\n#include \"stim/diagram/graph/match_graph_3d_drawer.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nCoord<2> project(Coord<3> coord) {\n    return {coord.xyz[0] * 5.0f + coord.xyz[2] * 0.2f, coord.xyz[1] * 5.0f + coord.xyz[2] * 0.1f};\n}\n\ntemplate <typename T>\ninline void write_key_val(std::ostream &out, const char *key, const T &val) {\n    out << ' ' << key << \"=\\\"\" << val << \"\\\"\";\n}\n\nvoid stim_draw_internal::dem_match_graph_to_svg_diagram_write_to(\n    const stim::DetectorErrorModel &dem, std::ostream &svg_out) {\n    auto diagram = dem_match_graph_to_basic_3d_diagram(dem);\n    std::vector<Coord<2>> used_coords;\n    for (const auto &e : diagram.line_data) {\n        used_coords.push_back(project(e));\n    }\n    for (const auto &e : diagram.red_line_data) {\n        used_coords.push_back(project(e));\n    }\n    for (const auto &e : diagram.blue_line_data) {\n        used_coords.push_back(project(e));\n    }\n    for (const auto &e : diagram.purple_line_data) {\n        used_coords.push_back(project(e));\n    }\n    for (const auto &e : diagram.elements) {\n        used_coords.push_back(project(e.center));\n    }\n    auto minmax = Coord<2>::min_max(used_coords);\n    minmax.first.xyz[0] -= 5;\n    minmax.first.xyz[1] -= 5;\n    minmax.second.xyz[0] += 5;\n    minmax.second.xyz[1] += 5;\n    auto off = minmax.first * -1.0f;\n\n    svg_out << R\"SVG(<svg viewBox=\"0 0 )SVG\";\n    svg_out << (minmax.second.xyz[0] - minmax.first.xyz[0]);\n    svg_out << \" \";\n    svg_out << (minmax.second.xyz[1] - minmax.first.xyz[1]);\n    svg_out << '\"' << ' ';\n    write_key_val(svg_out, \"version\", \"1.1\");\n    write_key_val(svg_out, \"xmlns\", \"http://www.w3.org/2000/svg\");\n    svg_out << \">\\n\";\n\n    auto write_lines = [&](const std::vector<Coord<3>> &line_data, const char *color) {\n        if (line_data.empty()) {\n            return;\n        }\n        svg_out << \"<path d=\\\"\";\n        for (size_t k = 0; k < line_data.size(); k++) {\n            if (k) {\n                svg_out << ' ';\n            }\n            svg_out << (k % 2 == 0 ? 'M' : 'L');\n            auto c = project(line_data[k]);\n            c += off;\n            svg_out << c.xyz[0];\n            svg_out << ',';\n            svg_out << c.xyz[1];\n        }\n        svg_out << '\"';\n        write_key_val(svg_out, \"stroke\", color);\n        write_key_val(svg_out, \"fill\", \"none\");\n        write_key_val(svg_out, \"stroke-width\", \"0.2\");\n        svg_out << \"/>\\n\";\n    };\n    write_lines(diagram.line_data, \"black\");\n    write_lines(diagram.red_line_data, \"red\");\n    write_lines(diagram.blue_line_data, \"blue\");\n    write_lines(diagram.purple_line_data, \"purple\");\n    for (const auto &e : diagram.elements) {\n        auto c = project(e.center);\n        c += off;\n        svg_out << \"<circle\";\n        write_key_val(svg_out, \"cx\", c.xyz[0]);\n        write_key_val(svg_out, \"cy\", c.xyz[1]);\n        write_key_val(svg_out, \"r\", 0.5);\n        write_key_val(svg_out, \"stroke\", \"none\");\n        write_key_val(svg_out, \"fill\", \"black\");\n        svg_out << \"/>\\n\";\n    }\n\n    svg_out << \"</svg>\";\n}\n"
  },
  {
    "path": "src/stim/diagram/graph/match_graph_svg_drawer.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_GRAPH_MATCH_GRAPH_SVG_DRAWER_H\n#define _STIM_DIAGRAM_GRAPH_MATCH_GRAPH_SVG_DRAWER_H\n\n#include <iostream>\n\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/diagram/basic_3d_diagram.h\"\n#include \"stim/diagram/circuit_timeline_helper.h\"\n\nnamespace stim_draw_internal {\n\nvoid dem_match_graph_to_svg_diagram_write_to(const stim::DetectorErrorModel &dem, std::ostream &svg_out);\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/graph/match_graph_svg_drawer.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/diagram/graph/match_graph_svg_drawer.h\"\n\n#include <fstream>\n\n#include \"gtest/gtest.h\"\n\n#include \"match_graph_3d_drawer.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nvoid expect_graph_svg_diagram_is_identical_to_saved_file(const DetectorErrorModel &dem, std::string_view key) {\n    std::stringstream actual_ss;\n    dem_match_graph_to_svg_diagram_write_to(dem, actual_ss);\n    auto actual = actual_ss.str();\n    expect_string_is_identical_to_saved_file(actual_ss.str(), key);\n}\n\nTEST(match_graph_drawer_svg, repetition_code) {\n    CircuitGenParameters params(10, 7, \"memory\");\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_rep_code_circuit(params).circuit;\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, false, false, false);\n    expect_graph_svg_diagram_is_identical_to_saved_file(dem, \"match_graph_repetition_code.svg\");\n}\n\nTEST(match_graph_drawer_svg, surface_code) {\n    CircuitGenParameters params(10, 3, \"unrotated_memory_z\");\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, false, false, false);\n    expect_graph_svg_diagram_is_identical_to_saved_file(dem, \"match_graph_surface_code.svg\");\n}\n\nTEST(match_graph_drawer_svg, missing_coordinates) {\n    Circuit circuit(R\"CIRCUIT(\n        R 0 1 2 3 4 5 6 7 8 9 10\n        X_ERROR(0.125) 0 1 2 3 4 5 6 7 8 9 10\n        M 0 1 2 3 4 5 6 7 8 9 10\n        DETECTOR rec[-1] rec[-2]\n        DETECTOR rec[-2] rec[-3]\n        DETECTOR rec[-3] rec[-4]\n        DETECTOR rec[-4] rec[-5]\n        DETECTOR rec[-5] rec[-6]\n        DETECTOR rec[-6] rec[-7]\n        DETECTOR rec[-7] rec[-8]\n        DETECTOR rec[-8] rec[-9]\n        DETECTOR rec[-9] rec[-10]\n        OBSERVABLE_INCLUDE(1) rec[-1]\n    )CIRCUIT\");\n\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, false, false, false);\n    std::stringstream ss;\n\n    testing::internal::CaptureStderr();\n    dem_match_graph_to_svg_diagram_write_to(dem, ss);\n    std::string err = testing::internal::GetCapturedStderr();\n    ASSERT_NE(err, \"\");\n\n    expect_string_is_identical_to_saved_file(ss.str(), \"match_graph_no_coords.svg\");\n}\n"
  },
  {
    "path": "src/stim/diagram/json_obj.cc",
    "content": "#include \"stim/diagram/json_obj.h\"\n\n#include <limits>\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nenum JsonType : uint8_t {\n    JsonTypeEmpty = 0,\n    JsonTypeMap = 1,\n    JsonTypeArray = 2,\n    JsonTypeBool = 3,\n    JsonTypeSingle = 4,\n    JsonTypeDouble = 5,\n    JsonTypeInt64 = 6,\n    JsonTypeUInt64 = 7,\n    JsonTypeString = 8,\n};\n\nJsonObj::JsonObj(float num) : val_float(num), type(JsonTypeSingle) {\n}\nJsonObj::JsonObj(double num) : val_double(num), type(JsonTypeDouble) {\n}\nJsonObj::JsonObj(uint64_t num) : val_uint64_t(num), type(JsonTypeUInt64) {\n}\nJsonObj::JsonObj(uint32_t num) : val_uint64_t(num), type(JsonTypeUInt64) {\n}\nJsonObj::JsonObj(uint16_t num) : val_uint64_t(num), type(JsonTypeUInt64) {\n}\nJsonObj::JsonObj(uint8_t num) : val_uint64_t(num), type(JsonTypeUInt64) {\n}\nJsonObj::JsonObj(int8_t num) : val_int64_t(num), type(JsonTypeInt64) {\n}\nJsonObj::JsonObj(int16_t num) : val_int64_t(num), type(JsonTypeInt64) {\n}\nJsonObj::JsonObj(int32_t num) : val_int64_t(num), type(JsonTypeInt64) {\n}\nJsonObj::JsonObj(int64_t num) : val_int64_t(num), type(JsonTypeInt64) {\n}\n\nJsonObj::JsonObj(std::string text) : text(text), type(JsonTypeString) {\n}\n\nJsonObj::JsonObj(const char *text) : text(text), type(JsonTypeString) {\n}\n\nJsonObj::JsonObj(std::map<std::string, JsonObj> map) : map(map), type(JsonTypeMap) {\n}\n\nJsonObj::JsonObj(std::vector<JsonObj> arr) : arr(arr), type(JsonTypeArray) {\n}\n\nJsonObj::JsonObj(bool boolean) : val_boolean(boolean), type(JsonTypeBool) {\n}\n\nvoid JsonObj::clear() {\n    text.clear();\n    map.clear();\n    arr.clear();\n    type = JsonTypeEmpty;\n    val_uint64_t = 0;\n}\n\nvoid JsonObj::write_str(std::string_view s, std::ostream &out) {\n    out << '\"';\n    for (char c : s) {\n        if (c == '\\0') {\n            out << \"\\\\0\";\n        } else if (c == '\\n') {\n            out << \"\\\\n\";\n        } else if (c == '\"') {\n            out << \"\\\\\\\"\";\n        } else if (c == '\\\\') {\n            out << \"\\\\\\\\\";\n        } else {\n            out << c;\n        }\n    }\n    out << '\"';\n}\n\nvoid indented_new_line(std::ostream &out, int64_t indent) {\n    if (indent >= 0) {\n        out << '\\n';\n        for (int64_t k = 0; k < indent; k++) {\n            out << ' ';\n        }\n    }\n}\n\nvoid JsonObj::write(std::ostream &out, int64_t indent) const {\n    switch (type) {\n        case JsonTypeMap: {\n            out << \"{\";\n            indented_new_line(out, indent + 2);\n            bool first = true;\n            for (const auto &e : map) {\n                if (first) {\n                    first = false;\n                } else {\n                    out << ',';\n                    indented_new_line(out, indent + 2);\n                }\n                write_str(e.first, out);\n                out << ':';\n                e.second.write(out, indent + 2);\n            }\n            if (!first) {\n                indented_new_line(out, indent);\n            }\n            out << \"}\";\n            break;\n        }\n        case JsonTypeArray: {\n            out << \"[\";\n            indented_new_line(out, indent + 2);\n            bool first = true;\n            for (const auto &e : arr) {\n                if (first) {\n                    first = false;\n                } else {\n                    out << ',';\n                    indented_new_line(out, indent + 2);\n                }\n                e.write(out, indent + 2);\n            }\n            if (!first) {\n                indented_new_line(out, indent);\n            }\n            out << \"]\";\n            break;\n        }\n        case JsonTypeString: {\n            write_str(text, out);\n            break;\n        }\n        case JsonTypeBool: {\n            out << (val_boolean ? \"true\" : \"false\");\n            break;\n        }\n        case JsonTypeSingle: {\n            out << val_float;\n            break;\n        }\n        case JsonTypeDouble: {\n            auto p = out.precision();\n            out.precision(std::numeric_limits<double>::digits10);\n            out << val_double;\n            out.precision(p);\n            break;\n        }\n        case JsonTypeInt64: {\n            out << val_int64_t;\n            break;\n        }\n        case JsonTypeUInt64: {\n            out << val_uint64_t;\n            break;\n        }\n        default:\n            throw std::invalid_argument(\"unknown type\");\n    }\n}\n\nstd::string JsonObj::str(bool indent) const {\n    std::stringstream ss;\n    ss.precision(std::numeric_limits<float>::max_digits10);\n    write(ss, indent ? 0 : INT64_MIN);\n    return ss.str();\n}\n\nstd::ostream &stim_draw_internal::operator<<(std::ostream &out, const JsonObj &obj) {\n    auto precision = out.precision();\n    out.precision(std::numeric_limits<float>::max_digits10);\n    obj.write(out);\n    out.precision(precision);\n    return out;\n}\n"
  },
  {
    "path": "src/stim/diagram/json_obj.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DRAW_JSON_OBJ_H\n#define _STIM_DRAW_JSON_OBJ_H\n\n#include <iostream>\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim_draw_internal {\n\nstruct JsonObj {\n    union {\n        float val_float;\n        double val_double;\n        int64_t val_int64_t;\n        uint64_t val_uint64_t;\n        bool val_boolean;\n    };\n    std::string text;\n    std::map<std::string, JsonObj> map;\n    std::vector<JsonObj> arr;\n    uint8_t type;\n\n    JsonObj(bool boolean);\n    JsonObj(float num);\n    JsonObj(double double_num);\n    JsonObj(uint8_t int_num);\n    JsonObj(uint16_t int_num);\n    JsonObj(uint32_t int_num);\n    JsonObj(uint64_t uint_num);\n    JsonObj(int8_t int_num);\n    JsonObj(int16_t int_num);\n    JsonObj(int32_t int_num);\n    JsonObj(int64_t int_num);\n    JsonObj(std::string text);\n    JsonObj(const char *text);\n    JsonObj(std::map<std::string, JsonObj> map);\n    JsonObj(std::vector<JsonObj> arr);\n\n    void clear();\n    static void write_str(std::string_view s, std::ostream &out);\n    void write(std::ostream &out, int64_t indent = INT64_MIN) const;\n    std::string str(bool indent = false) const;\n};\n\nstd::ostream &operator<<(std::ostream &out, const JsonObj &obj);\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/json_obj.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/diagram/json_obj.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nTEST(json_obj, str) {\n    EXPECT_EQ(JsonObj(1).str(), \"1\");\n    EXPECT_EQ(JsonObj(2.5f).str(), \"2.5\");\n    EXPECT_EQ(JsonObj(\"test\").str(), \"\\\"test\\\"\");\n\n    EXPECT_EQ(JsonObj(std::vector<JsonObj>{}).str(), \"[]\");\n    EXPECT_EQ(JsonObj(std::vector<JsonObj>{1}).str(), \"[1]\");\n    EXPECT_EQ(JsonObj(std::vector<JsonObj>{1, 2.5f, \"5\"}).str(), \"[1,2.5,\\\"5\\\"]\");\n\n    EXPECT_EQ(JsonObj(std::map<std::string, JsonObj>{}).str(), \"{}\");\n    EXPECT_EQ(JsonObj(std::map<std::string, JsonObj>{{\"a\", 1}}).str(), \"{\\\"a\\\":1}\");\n    EXPECT_EQ(JsonObj(std::map<std::string, JsonObj>{{\"a\", 1}, {\"b\", 2}}).str(), \"{\\\"a\\\":1,\\\"b\\\":2}\");\n}\n"
  },
  {
    "path": "src/stim/diagram/lattice_map.cc",
    "content": "#include \"stim/diagram/lattice_map.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nvoid LatticeMap::set(\n    uint64_t index,\n    stim::SpanRef<const uint64_t> offsets_per_iteration,\n    stim::SpanRef<const uint64_t> iteration_counts,\n    uint32_t value) {\n    if (offsets_per_iteration.empty()) {\n        if (index >= brute_force_data.size()) {\n            brute_force_data.resize(2 * index + 10);\n        }\n        brute_force_data[index] = value;\n        return;\n    }\n\n    for (uint64_t k = 0; k < iteration_counts[0]; k++) {\n        set(index + k * offsets_per_iteration[0],\n            {offsets_per_iteration.ptr_start + 1, offsets_per_iteration.ptr_end},\n            {iteration_counts.ptr_start + 1, iteration_counts.ptr_end},\n            value);\n    }\n}\nuint32_t LatticeMap::get(uint64_t index) {\n    if (index >= brute_force_data.size()) {\n        return 0;\n    }\n    return brute_force_data[index];\n}\n"
  },
  {
    "path": "src/stim/diagram/lattice_map.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_TIMELINE_ASCII_LATTICE_MAP_H\n#define _STIM_DIAGRAM_TIMELINE_ASCII_LATTICE_MAP_H\n\n#include <iostream>\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim_draw_internal {\n\n/// A map that supports writing to sets of indices that form bounded lattices.\nstruct LatticeMap {\n    std::vector<uint32_t> brute_force_data;\n\n    /// Write to a lattice of indices.\n    void set(\n        uint64_t index,\n        stim::SpanRef<const uint64_t> offsets_per_iteration,\n        stim::SpanRef<const uint64_t> iteration_counts,\n        uint32_t value);\n    /// Read the latest value written to an index, defaulting to 0 if no writes yet.\n    uint32_t get(uint64_t index);\n};\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/timeline/timeline_3d_drawer.cc",
    "content": "#include \"stim/diagram/timeline/timeline_3d_drawer.h\"\n\n#include \"stim/circuit/gate_decomposition.h\"\n#include \"stim/diagram/circuit_timeline_helper.h\"\n#include \"stim/diagram/detector_slice/detector_slice_set.h\"\n#include \"stim/diagram/diagram_util.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nCoord<3> trans(size_t m, Coord<2> xy) {\n    return {-(float)m, xy.xyz[0] * -2.0f, xy.xyz[1] * -2.0f};\n}\n\nCoord<3> DiagramTimeline3DDrawer::mq2xyz(size_t m, size_t q) const {\n    auto xy = qubit_coords[q];\n    return trans(m, xy);\n}\n\nvoid DiagramTimeline3DDrawer::do_feedback(\n    std::string_view gate, const GateTarget &qubit_target, const GateTarget &feedback_target) {\n    std::string key = std::string(gate);\n    if (feedback_target.is_sweep_bit_target()) {\n        key.append(\":SWEEP\");\n    } else if (feedback_target.is_measurement_record_target()) {\n        key.append(\":REC\");\n    }\n    auto center = mq2xyz(cur_moment, qubit_target.qubit_value());\n    diagram_out.elements.push_back({key, center});\n}\n\nvoid DiagramTimeline3DDrawer::draw_two_qubit_gate_end_point(Coord<3> center, std::string_view type) {\n    if (type == \"X\") {\n        diagram_out.elements.push_back({\"X_CONTROL\", center});\n    } else if (type == \"Y\") {\n        diagram_out.elements.push_back({\"Y_CONTROL\", center});\n    } else if (type == \"Z\") {\n        diagram_out.elements.push_back({\"Z_CONTROL\", center});\n    } else {\n        diagram_out.elements.push_back({std::string(type), center});\n    }\n}\n\nvoid DiagramTimeline3DDrawer::draw_gate_connecting_line(Coord<3> a, Coord<3> b) {\n    diagram_out.line_data.push_back(a);\n    auto d = b - a;\n    if (d.norm() > 2.2) {\n        auto c = (a + b) * 0.5;\n        c.xyz[0] -= 0.25;\n        diagram_out.line_data.push_back(c);\n        diagram_out.line_data.push_back(c);\n    }\n    diagram_out.line_data.push_back(b);\n}\n\nvoid DiagramTimeline3DDrawer::do_two_qubit_gate_instance(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n\n    const GateTarget &target1 = op.targets[0];\n    const GateTarget &target2 = op.targets[1];\n    auto ends = two_qubit_gate_pieces(op.gate_type);\n    if (target1.is_measurement_record_target() || target1.is_sweep_bit_target()) {\n        do_feedback(ends.second, target2, target1);\n        return;\n    }\n    if (target2.is_measurement_record_target() || target2.is_sweep_bit_target()) {\n        do_feedback(ends.first, target1, target2);\n        return;\n    }\n\n    auto pieces = two_qubit_gate_pieces(op.gate_type);\n    auto c1 = mq2xyz(cur_moment, target1.qubit_value());\n    auto c2 = mq2xyz(cur_moment, target2.qubit_value());\n    draw_two_qubit_gate_end_point(c1, pieces.first);\n    draw_two_qubit_gate_end_point(c2, pieces.second);\n    draw_gate_connecting_line(c1, c2);\n}\n\nvoid DiagramTimeline3DDrawer::start_next_moment() {\n    cur_moment += 1;\n    cur_moment_is_used = false;\n    cur_moment_used_flags.clear();\n    cur_moment_used_flags.resize(num_qubits, false);\n}\n\nvoid DiagramTimeline3DDrawer::do_tick() {\n    if (has_ticks && cur_moment > tick_start_moment) {\n        auto x1 = coord_bounds.first.xyz[0] - 0.2f;\n        auto x2 = coord_bounds.first.xyz[0] - 0.4f;\n        auto y1 = coord_bounds.first.xyz[1];\n        auto y2 = coord_bounds.second.xyz[1];\n        y1 -= 0.25f;\n        y2 += 0.25f;\n        Coord<3> p0 = trans(tick_start_moment, {x1, y1});\n        Coord<3> p1 = trans(tick_start_moment, {x1, y2});\n        Coord<3> p2 = trans(tick_start_moment, {x2, y1});\n        Coord<3> p3 = trans(tick_start_moment, {x2, y2});\n        Coord<3> p4 = trans(cur_moment, {x1, y1});\n        Coord<3> p5 = trans(cur_moment, {x1, y2});\n        Coord<3> p6 = trans(cur_moment, {x2, y1});\n        Coord<3> p7 = trans(cur_moment, {x2, y2});\n        p0.xyz[0] += 0.25;\n        p1.xyz[0] += 0.25;\n        p2.xyz[0] += 0.25;\n        p3.xyz[0] += 0.25;\n        p4.xyz[0] -= 0.25;\n        p5.xyz[0] -= 0.25;\n        p6.xyz[0] -= 0.25;\n        p7.xyz[0] -= 0.25;\n\n        diagram_out.blue_line_data.push_back(p0);\n        diagram_out.blue_line_data.push_back(p2);\n\n        diagram_out.blue_line_data.push_back(p1);\n        diagram_out.blue_line_data.push_back(p3);\n\n        diagram_out.blue_line_data.push_back(p2);\n        diagram_out.blue_line_data.push_back(p3);\n        diagram_out.blue_line_data.push_back(p2);\n        diagram_out.blue_line_data.push_back(p6);\n\n        diagram_out.blue_line_data.push_back(p3);\n        diagram_out.blue_line_data.push_back(p7);\n\n        diagram_out.blue_line_data.push_back(p4);\n        diagram_out.blue_line_data.push_back(p6);\n\n        diagram_out.blue_line_data.push_back(p5);\n        diagram_out.blue_line_data.push_back(p7);\n\n        diagram_out.blue_line_data.push_back(p6);\n        diagram_out.blue_line_data.push_back(p7);\n    }\n\n    start_next_moment();\n    tick_start_moment = cur_moment;\n}\n\nvoid DiagramTimeline3DDrawer::do_single_qubit_gate_instance(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n    const auto &target = op.targets[0];\n\n    auto center = mq2xyz(cur_moment, target.qubit_value());\n    const auto &gate_data = GATE_DATA[op.gate_type];\n    diagram_out.elements.push_back({std::string(gate_data.name), center});\n}\n\nvoid DiagramTimeline3DDrawer::reserve_drawing_room_for_targets(SpanRef<const GateTarget> targets) {\n    bool already_used = false;\n    for (auto t : targets) {\n        if (t.is_x_target() || t.is_y_target() || t.is_z_target() || t.is_qubit_target()) {\n            already_used |= cur_moment_used_flags[t.qubit_value()];\n        }\n    }\n    if (already_used) {\n        start_next_moment();\n    }\n    for (auto t : targets) {\n        if (t.is_x_target() || t.is_y_target() || t.is_z_target() || t.is_qubit_target()) {\n            cur_moment_used_flags[t.qubit_value()] = true;\n        }\n    }\n}\n\nvoid DiagramTimeline3DDrawer::do_multi_qubit_gate_with_pauli_targets(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n\n    Coord<3> prev{};\n    bool has_prev = false;\n    for (const auto &t : op.targets) {\n        if (t.is_combiner()) {\n            continue;\n        }\n        std::stringstream ss;\n        const auto &gate_data = GATE_DATA[op.gate_type];\n        ss << gate_data.name;\n        if (t.is_x_target()) {\n            ss << \":X\";\n        } else if (t.is_y_target()) {\n            ss << \":Y\";\n        } else if (t.is_z_target()) {\n            ss << \":Z\";\n        }\n        auto center = mq2xyz(cur_moment, t.qubit_value());\n        diagram_out.elements.push_back({ss.str(), center});\n        if (has_prev) {\n            draw_gate_connecting_line(center, prev);\n        }\n        prev = center;\n        has_prev = true;\n    }\n}\n\nvoid DiagramTimeline3DDrawer::do_start_repeat(const CircuitTimelineLoopData &loop_data) {\n    if (cur_moment_is_used) {\n        do_tick();\n    }\n    start_next_moment();\n    loop_start_moment_stack.push_back(cur_moment);\n    tick_start_moment = cur_moment;\n}\n\nvoid DiagramTimeline3DDrawer::do_end_repeat(const CircuitTimelineLoopData &loop_data) {\n    if (cur_moment_is_used) {\n        do_tick();\n    }\n\n    auto start = loop_start_moment_stack.back();\n    loop_start_moment_stack.pop_back();\n\n    auto x1 = coord_bounds.first.xyz[0];\n    auto x2 = coord_bounds.second.xyz[0];\n    auto y1 = coord_bounds.first.xyz[1];\n    auto y2 = coord_bounds.second.xyz[1];\n    x1 -= 0.5f * 3.0f / (2 + resolver.cur_loop_nesting.size());\n    x2 += 0.5f * 3.0f / (2 + resolver.cur_loop_nesting.size());\n    y1 -= 0.5f * 3.0f / (2 + resolver.cur_loop_nesting.size());\n    y2 += 0.5f * 3.0f / (2 + resolver.cur_loop_nesting.size());\n    Coord<3> p0 = trans(start, {x1, y1});\n    Coord<3> p1 = trans(start, {x1, y2});\n    Coord<3> p2 = trans(start, {x2, y1});\n    Coord<3> p3 = trans(start, {x2, y2});\n    Coord<3> p4 = trans(cur_moment, {x1, y1});\n    Coord<3> p5 = trans(cur_moment, {x1, y2});\n    Coord<3> p6 = trans(cur_moment, {x2, y1});\n    Coord<3> p7 = trans(cur_moment, {x2, y2});\n    p0.xyz[0] += 0.25;\n    p1.xyz[0] += 0.25;\n    p2.xyz[0] += 0.25;\n    p3.xyz[0] += 0.25;\n    p4.xyz[0] -= 0.25;\n    p5.xyz[0] -= 0.25;\n    p6.xyz[0] -= 0.25;\n    p7.xyz[0] -= 0.25;\n\n    diagram_out.red_line_data.push_back(p0);\n    diagram_out.red_line_data.push_back(p1);\n    diagram_out.red_line_data.push_back(p0);\n    diagram_out.red_line_data.push_back(p2);\n    diagram_out.red_line_data.push_back(p0);\n    diagram_out.red_line_data.push_back(p4);\n\n    diagram_out.red_line_data.push_back(p1);\n    diagram_out.red_line_data.push_back(p3);\n    diagram_out.red_line_data.push_back(p1);\n    diagram_out.red_line_data.push_back(p5);\n\n    diagram_out.red_line_data.push_back(p2);\n    diagram_out.red_line_data.push_back(p3);\n    diagram_out.red_line_data.push_back(p2);\n    diagram_out.red_line_data.push_back(p6);\n\n    diagram_out.red_line_data.push_back(p3);\n    diagram_out.red_line_data.push_back(p7);\n\n    diagram_out.red_line_data.push_back(p4);\n    diagram_out.red_line_data.push_back(p5);\n    diagram_out.red_line_data.push_back(p4);\n    diagram_out.red_line_data.push_back(p6);\n\n    diagram_out.red_line_data.push_back(p5);\n    diagram_out.red_line_data.push_back(p7);\n\n    diagram_out.red_line_data.push_back(p6);\n    diagram_out.red_line_data.push_back(p7);\n\n    start_next_moment();\n    tick_start_moment = cur_moment;\n}\n\nvoid DiagramTimeline3DDrawer::do_mpp(const ResolvedTimelineOperation &op) {\n    do_multi_qubit_gate_with_pauli_targets(op);\n}\n\nvoid DiagramTimeline3DDrawer::do_spp(const ResolvedTimelineOperation &op) {\n    do_multi_qubit_gate_with_pauli_targets(op);\n}\n\nvoid DiagramTimeline3DDrawer::do_correlated_error(const ResolvedTimelineOperation &op) {\n    if (cur_moment_is_used) {\n        start_next_moment();\n    }\n    do_multi_qubit_gate_with_pauli_targets(op);\n}\n\nvoid DiagramTimeline3DDrawer::do_else_correlated_error(const ResolvedTimelineOperation &op) {\n    do_correlated_error(op);\n}\n\nvoid DiagramTimeline3DDrawer::do_qubit_coords(const ResolvedTimelineOperation &op) {\n    // Not drawn.\n}\n\nvoid DiagramTimeline3DDrawer::do_detector(const ResolvedTimelineOperation &op) {\n    // Not drawn.\n}\n\nvoid DiagramTimeline3DDrawer::do_observable_include(const ResolvedTimelineOperation &op) {\n    // Not drawn.\n}\n\nvoid DiagramTimeline3DDrawer::do_resolved_operation(const ResolvedTimelineOperation &op) {\n    if (op.gate_type == GateType::MPP) {\n        do_mpp(op);\n    } else if (op.gate_type == GateType::SPP || op.gate_type == GateType::SPP_DAG) {\n        do_spp(op);\n    } else if (op.gate_type == GateType::DETECTOR) {\n        do_detector(op);\n    } else if (op.gate_type == GateType::OBSERVABLE_INCLUDE) {\n        do_observable_include(op);\n    } else if (op.gate_type == GateType::QUBIT_COORDS) {\n        do_qubit_coords(op);\n    } else if (op.gate_type == GateType::E) {\n        do_correlated_error(op);\n    } else if (op.gate_type == GateType::ELSE_CORRELATED_ERROR) {\n        do_else_correlated_error(op);\n    } else if (op.gate_type == GateType::TICK) {\n        do_tick();\n    } else if (GATE_DATA[op.gate_type].flags & GATE_TARGETS_PAIRS) {\n        do_two_qubit_gate_instance(op);\n    } else {\n        do_single_qubit_gate_instance(op);\n    }\n}\n\nDiagramTimeline3DDrawer::DiagramTimeline3DDrawer(size_t num_qubits, bool has_ticks)\n    : num_qubits(num_qubits), has_ticks(has_ticks) {\n    cur_moment_used_flags.resize(num_qubits, false);\n}\n\nvoid add_used_qubits(const Circuit &circuit, std::set<uint64_t> &out) {\n    for (const auto &op : circuit.operations) {\n        if (op.gate_type == GateType::REPEAT) {\n            add_used_qubits(op.repeat_block_body(circuit), out);\n        } else {\n            for (const auto &t : op.targets) {\n                if (t.is_x_target() || t.is_y_target() || t.is_z_target() || t.is_qubit_target()) {\n                    out.insert(t.qubit_value());\n                }\n            }\n        }\n    }\n}\n\nstd::pair<std::vector<Coord<2>>, std::pair<Coord<2>, Coord<2>>> pick_coords_for_circuit(const Circuit &circuit) {\n    DetectorSliceSet set;\n    set.num_qubits = circuit.count_qubits();\n    set.coordinates = circuit.get_final_qubit_coords();\n    auto coords = FlattenedCoords::from(set, 1).qubit_coords;\n    float default_y = 0;\n    for (auto e : set.coordinates) {\n        default_y = std::min(default_y, coords[e.first].xyz[1] - 1);\n    }\n    for (uint64_t q = 0; q < set.num_qubits; q++) {\n        if (set.coordinates.find(q) == set.coordinates.end()) {\n            coords[q].xyz = {(float)q, default_y};\n        }\n    }\n\n    std::set<uint64_t> used;\n    add_used_qubits(circuit, used);\n    std::vector<Coord<2>> used_coords;\n    for (const auto &q : used) {\n        used_coords.push_back(coords[q]);\n    }\n    if (used_coords.empty()) {\n        used_coords.push_back({0, 0});\n    }\n    auto bounds = Coord<2>::min_max(used_coords);\n    //    auto center = (bounds.first + bounds.second) * 0.5;\n    //    for (auto &c : coords) {\n    //        c -= center;\n    //    }\n    //    bounds.first -= center;\n    //    bounds.second -= center;\n    return {coords, bounds};\n}\n\nBasic3dDiagram DiagramTimeline3DDrawer::circuit_to_basic_3d_diagram(const Circuit &circuit) {\n    auto num_qubits = circuit.count_qubits();\n    auto has_ticks = circuit.count_ticks() > 0;\n    DiagramTimeline3DDrawer obj(num_qubits, has_ticks);\n    auto all_used = pick_coords_for_circuit(circuit);\n    obj.qubit_coords = all_used.first;\n    obj.coord_bounds = all_used.second;\n    auto minmax = obj.coord_bounds;\n\n    // Draw an arrow indicating the time direction.\n    auto y = -2 * (minmax.first.xyz[0] - 1);\n    auto z = -2 * (minmax.first.xyz[1] * 0.5f + minmax.second.xyz[1] * 0.5f);\n    obj.diagram_out.red_line_data.push_back({0, y, z});\n    obj.diagram_out.red_line_data.push_back({-3, y, z});\n    obj.diagram_out.red_line_data.push_back({-2.5f, y - 0.5f, z});\n    obj.diagram_out.red_line_data.push_back({-3, y, z});\n    obj.diagram_out.red_line_data.push_back({-2.5f, y + 0.5f, z});\n    obj.diagram_out.red_line_data.push_back({-3, y, z});\n\n    obj.resolver.resolved_op_callback = [&](const ResolvedTimelineOperation &op) {\n        obj.do_resolved_operation(op);\n    };\n    obj.resolver.start_repeat_callback = [&](const CircuitTimelineLoopData &loop_data) {\n        obj.do_start_repeat(loop_data);\n    };\n    obj.resolver.end_repeat_callback = [&](const CircuitTimelineLoopData &loop_data) {\n        obj.do_end_repeat(loop_data);\n    };\n    obj.resolver.do_circuit(circuit);\n    if (obj.cur_moment_is_used) {\n        obj.start_next_moment();\n    }\n\n    std::set<uint64_t> used;\n    add_used_qubits(circuit, used);\n    for (auto q : used) {\n        auto p1 = obj.mq2xyz(0, q);\n        p1.xyz[0] += 1;\n        auto p2 = obj.mq2xyz(obj.cur_moment + 1, q);\n        obj.diagram_out.line_data.push_back(p1);\n        obj.diagram_out.line_data.push_back(p2);\n    }\n\n    return obj.diagram_out;\n}\n"
  },
  {
    "path": "src/stim/diagram/timeline/timeline_3d_drawer.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_TIMELINE_TIMELINE_3D_DRAWER_H\n#define _STIM_DIAGRAM_TIMELINE_TIMELINE_3D_DRAWER_H\n\n#include <iostream>\n\n#include \"stim/diagram/basic_3d_diagram.h\"\n#include \"stim/diagram/circuit_timeline_helper.h\"\n\nnamespace stim_draw_internal {\n\nstruct DiagramTimeline3DDrawer {\n    CircuitTimelineHelper resolver;\n\n    std::vector<size_t> loop_start_moment_stack;\n    Basic3dDiagram diagram_out;\n    size_t cur_moment = 0;\n    size_t cur_moment_is_used = false;\n    size_t tick_start_moment = 0;\n    std::vector<bool> cur_moment_used_flags;\n    size_t num_qubits = 0;\n    bool has_ticks = false;\n    std::vector<Coord<2>> qubit_coords;\n    std::pair<Coord<2>, Coord<2>> coord_bounds;\n\n    DiagramTimeline3DDrawer(size_t num_qubits, bool has_ticks);\n\n    static Basic3dDiagram circuit_to_basic_3d_diagram(const stim::Circuit &circuit);\n\n    void do_start_repeat(const CircuitTimelineLoopData &loop_data);\n    void do_end_repeat(const CircuitTimelineLoopData &loop_data);\n    void start_next_moment();\n    void reserve_drawing_room_for_targets(stim::SpanRef<const stim::GateTarget> targets);\n    Coord<3> mq2xyz(size_t m, size_t q) const;\n    void draw_two_qubit_gate_end_point(Coord<3> center, std::string_view type);\n    void draw_gate_connecting_line(Coord<3> a, Coord<3> b);\n\n    void do_resolved_operation(const ResolvedTimelineOperation &op);\n    void do_tick();\n    void do_two_qubit_gate_instance(const ResolvedTimelineOperation &op);\n    void do_feedback(\n        std::string_view gate, const stim::GateTarget &qubit_target, const stim::GateTarget &feedback_target);\n    void do_single_qubit_gate_instance(const ResolvedTimelineOperation &op);\n    void do_multi_qubit_gate_with_pauli_targets(const ResolvedTimelineOperation &op);\n    void do_multi_qubit_gate_with_paired_pauli_targets(const ResolvedTimelineOperation &op);\n    void do_mpp(const ResolvedTimelineOperation &op);\n    void do_spp(const ResolvedTimelineOperation &op);\n    void do_correlated_error(const ResolvedTimelineOperation &op);\n    void do_qubit_coords(const ResolvedTimelineOperation &op);\n    void do_else_correlated_error(const ResolvedTimelineOperation &op);\n    void do_detector(const ResolvedTimelineOperation &op);\n    void do_observable_include(const ResolvedTimelineOperation &op);\n};\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/timeline/timeline_3d_drawer.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/diagram/timeline/timeline_3d_drawer.h\"\n\n#include <fstream>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nvoid expect_diagram_is_identical_to_saved_file(const Circuit &circuit, std::string_view key) {\n    auto diagram = DiagramTimeline3DDrawer::circuit_to_basic_3d_diagram(circuit);\n    std::stringstream actual_ss;\n    diagram.to_gltf_scene().to_json().write(actual_ss);\n    auto actual = actual_ss.str();\n\n    auto path = resolve_test_file(key);\n    FILE *f = fopen(path.c_str(), \"rb\");\n    auto expected = rewind_read_close(f);\n\n    if (expected != actual) {\n        auto dot = key.rfind('.');\n        std::string new_path;\n        if (dot == std::string::npos) {\n            new_path = path + \".new\";\n        } else {\n            dot += path.size() - key.size();\n            new_path = path.substr(0, dot) + \".new\" + path.substr(dot);\n        }\n        std::ofstream out;\n        out.open(new_path);\n        out << actual;\n        out.close();\n        EXPECT_TRUE(false) << \"Diagram didn't agree. key=\" << key;\n    }\n}\n\nTEST(circuit_diagram_timeline_3d, single_qubit_gates) {\n    Circuit circuit(R\"CIRCUIT(\n        I 0\n        X 1\n        Y 2\n        Z 3\n        C_XYZ 0\n        C_ZYX 1\n        H 2\n        H_XY 3\n        H_XZ 0\n        H_YZ 1\n        S 2\n        SQRT_X 3\n        SQRT_X_DAG 0\n        SQRT_Y 1\n        SQRT_Y_DAG 2\n        SQRT_Z 3\n        SQRT_Z_DAG 0\n        S_DAG 1\n        H 2 0 3\n    )CIRCUIT\");\n\n    expect_diagram_is_identical_to_saved_file(circuit, \"single_qubits_gates.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, two_qubits_gates) {\n    Circuit circuit(R\"CIRCUIT(\n        CNOT 0 1\n        CX 2 3\n        CY 4 5 5 4\n        CZ 0 2\n        ISWAP 1 3\n        ISWAP_DAG 2 4\n        SQRT_XX 3 5\n        SQRT_XX_DAG 0 5\n        SQRT_YY 3 4 4 3\n        SQRT_YY_DAG 0 1\n        SQRT_ZZ 2 3\n        SQRT_ZZ_DAG 4 5\n        SWAP 0 1\n        XCX 2 3\n        XCY 3 4\n        XCZ 0 1\n        YCX 2 3\n        YCY 4 5\n        YCZ 0 1\n        ZCX 2 3\n        ZCY 4 5\n        ZCZ 0 5 2 3 1 4\n        CXSWAP 0 1\n        SWAPCX 2 3\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"two_qubits_gates.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, noise_gates) {\n    Circuit circuit(R\"CIRCUIT(\n        DEPOLARIZE1(0.125) 0 1\n        DEPOLARIZE2(0.125) 0 2 4 5\n        X_ERROR(0.125) 0 1 2\n        Y_ERROR(0.125) 0 1 4\n        Z_ERROR(0.125) 2 3 5\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"noise_gates_1.gltf\");\n\n    circuit = Circuit(R\"CIRCUIT(\n        E(0.25) X1 X2\n        CORRELATED_ERROR(0.125) X1 Y2 Z3\n        ELSE_CORRELATED_ERROR(0.25) X2 Y4 Z3\n        ELSE_CORRELATED_ERROR(0.25) X5\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"noise_gates_2.gltf\");\n\n    circuit = Circuit(R\"CIRCUIT(\n        PAULI_CHANNEL_1(0.125,0.25,0.125) 0 1 2 3\n        PAULI_CHANNEL_2(0.01,0.01,0.01,0.02,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01) 0 1 2 4\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"noise_gates_3.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, collapsing) {\n    Circuit circuit(R\"CIRCUIT(\n        R 0\n        RX 1\n        RY 2\n        RZ 3\n        M(0.001) 0 1\n        MR 1 0\n        MRX 1 2\n        MRY 0 3 1\n        MRZ 0\n        MX 1\n        MY 2\n        MZ 3\n        MPP X0*Y2 Z3 X1 Z2*Y3\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"collapsing.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, measurement_looping) {\n    Circuit circuit(R\"CIRCUIT(\n        M 0\n        REPEAT 100 {\n            M 1\n            REPEAT 5 {\n                M 2\n            }\n            REPEAT 7 {\n                MPP X3*Y4\n            }\n        }\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"measurement_looping.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, repeat) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        H 0 1 2\n        REPEAT 5 {\n            RX 2\n            REPEAT 100 {\n                H 0 1 3 3\n            }\n        }\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"repeat.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, classical_feedback) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        M 0\n        CX rec[-1] 1\n        YCZ 2 sweep[5]\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"classical_feedback.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, lattice_surgery_cnot) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        R 2\n        MPP X1*X2\n        MPP Z0*Z2\n        MX 2\n        CZ rec[-3] 0\n        CX rec[-2] 1\n        CZ rec[-1] 0\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"lattice_surgery_cnot.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, tick) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        H 0 0\n        TICK\n        H 0 1\n        TICK\n        H 0\n        REPEAT 1 {\n            H 0 1\n            TICK\n            H 0\n            S 0\n        }\n        H 0 0\n        SQRT_X 0\n        TICK\n        H 0 0\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"tick.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, detector_pseudo_targets) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        M 0 1 2 3 4 5\n        REPEAT 100 {\n            M 1 2\n        }\n        DETECTOR(1) rec[-1]\n        DETECTOR(2) rec[-2]\n        DETECTOR(3) rec[-3]\n        DETECTOR(4) rec[-4]\n        DETECTOR(5) rec[-1] rec[-2]\n        OBSERVABLE_INCLUDE(100) rec[-201] rec[-203]\n    )CIRCUIT\");\n    expect_diagram_is_identical_to_saved_file(circuit, \"detector_pseudo_targets.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, repetition_code) {\n    CircuitGenParameters params(10, 3, \"memory\");\n    auto circuit = generate_rep_code_circuit(params).circuit;\n    expect_diagram_is_identical_to_saved_file(circuit, \"repetition_code.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, surface_code) {\n    CircuitGenParameters params(10, 3, \"unrotated_memory_z\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    expect_diagram_is_identical_to_saved_file(circuit, \"surface_code.gltf\");\n}\n\nTEST(circuit_diagram_timeline_3d, test_circuit_all_ops) {\n    expect_diagram_is_identical_to_saved_file(generate_test_circuit_with_all_operations(), \"circuit_all_ops_3d.gltf\");\n}\n"
  },
  {
    "path": "src/stim/diagram/timeline/timeline_ascii_drawer.cc",
    "content": "#include \"stim/diagram/timeline/timeline_ascii_drawer.h\"\n\n#include \"stim/diagram/circuit_timeline_helper.h\"\n#include \"stim/diagram/diagram_util.h\"\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nconstexpr double GATE_ALIGNMENT_X = 0;    // Left-justify gates when time moves right.\nconstexpr double GATE_ALIGNMENT_Y = 0.5;  // Center-justify gates when time moves down.\n\nsize_t DiagramTimelineAsciiDrawer::m2x(size_t m) const {\n    return m * (1 + moment_spacing) + 2;\n}\n\nsize_t DiagramTimelineAsciiDrawer::q2y(size_t q) const {\n    return q * 2 + 1;\n}\n\nvoid DiagramTimelineAsciiDrawer::do_feedback(\n    std::string_view gate, const GateTarget &qubit_target, const GateTarget &feedback_target) {\n    std::stringstream ss;\n    ss << gate;\n    ss << \"^\";\n    if (feedback_target.is_sweep_bit_target()) {\n        ss << \"sweep[\" << feedback_target.value() << \"]\";\n    } else if (feedback_target.is_measurement_record_target()) {\n        ss << \"rec[\" << (feedback_target.value() + resolver.measure_offset) << \"]\";\n    }\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            {\n                m2x(cur_moment),\n                q2y(qubit_target.qubit_value()),\n                GATE_ALIGNMENT_X,\n                GATE_ALIGNMENT_Y,\n            },\n            ss.str(),\n        });\n}\n\nvoid DiagramTimelineAsciiDrawer::do_two_qubit_gate_instance(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n\n    const GateTarget &target1 = op.targets[0];\n    const GateTarget &target2 = op.targets[1];\n    const auto &gate_data = GATE_DATA[op.gate_type];\n    auto ends = two_qubit_gate_pieces(op.gate_type);\n    if (target1.is_measurement_record_target() || target1.is_sweep_bit_target()) {\n        do_feedback(ends.second, target2, target1);\n        return;\n    }\n    if (target2.is_measurement_record_target() || target2.is_sweep_bit_target()) {\n        do_feedback(ends.first, target1, target2);\n        return;\n    }\n\n    std::stringstream first;\n    std::stringstream second;\n    first << (ends.first == \"Z\" ? \"@\" : ends.first);\n    second << (ends.second == \"Z\" ? \"@\" : ends.second);\n    if (!op.args.empty()) {\n        if (op.gate_type == GateType::PAULI_CHANNEL_2) {\n            first << \"[0]\";\n            second << \"[1]\";\n        }\n        first << \"(\" << comma_sep(op.args, \",\") << \")\";\n        second << \"(\" << comma_sep(op.args, \",\") << \")\";\n    }\n    if (gate_data.flags & GATE_PRODUCES_RESULTS) {\n        first << ':';\n        write_rec_index(first);\n    }\n\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            {\n                m2x(cur_moment),\n                q2y(target1.qubit_value()),\n                GATE_ALIGNMENT_X,\n                GATE_ALIGNMENT_Y,\n            },\n            first.str(),\n        });\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            {\n                m2x(cur_moment),\n                q2y(target2.qubit_value()),\n                GATE_ALIGNMENT_X,\n                GATE_ALIGNMENT_Y,\n            },\n            second.str(),\n        });\n}\n\nvoid DiagramTimelineAsciiDrawer::start_next_moment() {\n    cur_moment++;\n    cur_moment_is_used = false;\n    cur_moment_used_flags.clear();\n    cur_moment_used_flags.resize(num_qubits);\n}\n\nvoid DiagramTimelineAsciiDrawer::do_tick() {\n    if (has_ticks && cur_moment > tick_start_moment) {\n        size_t x1 = m2x(tick_start_moment);\n        size_t x2 = m2x(cur_moment);\n        size_t y1 = 0;\n        size_t y2 = q2y(num_qubits - 1) + 1;\n\n        diagram.add_entry(\n            AsciiDiagramEntry{\n                {x1, y1, 0, 0},\n                \"/\",\n            });\n        diagram.add_entry(\n            AsciiDiagramEntry{\n                {x2, y1, 1, 0},\n                \"\\\\\",\n            });\n        diagram.add_entry(\n            AsciiDiagramEntry{\n                {x1, y2, 0, 1},\n                \"\\\\\",\n            });\n        diagram.add_entry(\n            AsciiDiagramEntry{\n                {x2, y2, 1, 0},\n                \"/\",\n            });\n\n        diagram.lines.push_back({{x1, y1, 0.0, 0.0}, {x2, y1, 1.0, 0.0}});\n        diagram.lines.push_back({{x1, y2, 0.0, 0.0}, {x2, y2, 1.0, 0.0}});\n    }\n\n    start_next_moment();\n    tick_start_moment = cur_moment;\n}\n\nvoid DiagramTimelineAsciiDrawer::do_single_qubit_gate_instance(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n    const auto &target = op.targets[0];\n    const auto &gate_data = GATE_DATA[op.gate_type];\n\n    std::stringstream ss;\n    ss << gate_data.name;\n    if (!op.args.empty()) {\n        ss << \"(\" << comma_sep(op.args, \",\") << \")\";\n    }\n    if (gate_data.flags & GATE_PRODUCES_RESULTS) {\n        ss << ':';\n        write_rec_index(ss);\n    }\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            {\n                m2x(cur_moment),\n                q2y(target.qubit_value()),\n                GATE_ALIGNMENT_X,\n                GATE_ALIGNMENT_Y,\n            },\n            ss.str(),\n        });\n}\n\nvoid DiagramTimelineAsciiDrawer::write_det_index(std::ostream &out) {\n    out.put('D');\n    if (!resolver.cur_loop_nesting.empty()) {\n        out.put('[');\n    }\n    out << resolver.detector_offset;\n    for (size_t k = 0; k < resolver.cur_loop_nesting.size(); k++) {\n        out << \"+iter\";\n        if (k > 0) {\n            out << (k + 1);\n        }\n        auto p = resolver.cur_loop_nesting[k].detectors_per_iteration;\n        if (p != 1) {\n            out << '*' << p;\n        }\n    }\n    if (!resolver.cur_loop_nesting.empty()) {\n        out.put(']');\n    }\n}\nvoid DiagramTimelineAsciiDrawer::write_rec_index(std::ostream &out, int64_t lookback_shift) {\n    out << \"rec[\";\n    out << resolver.measure_offset + (decltype(resolver.measure_offset))lookback_shift;\n    for (size_t k = 0; k < resolver.cur_loop_nesting.size(); k++) {\n        auto n = resolver.cur_loop_nesting[k].measurements_per_iteration;\n        if (n != 0) {\n            out << \"+iter\";\n            if (k > 0) {\n                out << (k + 1);\n            }\n            if (n != 1) {\n                out << '*' << n;\n            }\n        }\n    }\n    out << ']';\n}\n\nvoid DiagramTimelineAsciiDrawer::write_coords(std::ostream &out, SpanRef<const double> relative_coordinates) {\n    out.put('(');\n    for (size_t k = 0; k < relative_coordinates.size(); k++) {\n        if (k) {\n            out.put(',');\n        }\n        write_coord(out, k, relative_coordinates[k]);\n    }\n    out.put(')');\n}\n\nvoid DiagramTimelineAsciiDrawer::write_coord(std::ostream &out, size_t coord_index, double absolute_coordinate) {\n    out << absolute_coordinate;\n    for (size_t k = 0; k < resolver.cur_loop_nesting.size(); k++) {\n        const auto &p = resolver.cur_loop_nesting[k].shift_per_iteration;\n        if (coord_index < p.size() && p[coord_index] != 0) {\n            out << \"+iter\";\n            if (k > 0) {\n                out << (k + 1);\n            }\n            if (p[coord_index] != 1) {\n                out << '*' << p[coord_index];\n            }\n        }\n    }\n}\n\nvoid DiagramTimelineAsciiDrawer::reserve_drawing_room_for_targets(SpanRef<const GateTarget> targets) {\n    size_t min_q = SIZE_MAX;\n    size_t max_q = 0;\n    for (const auto &t : targets) {\n        if (t.is_combiner() || t.is_measurement_record_target() || t.is_sweep_bit_target()) {\n            continue;\n        }\n        size_t q = t.qubit_value();\n        min_q = std::min(min_q, q);\n        max_q = std::max(max_q, q);\n    }\n    if (min_q == SIZE_MAX) {\n        return;\n    }\n\n    for (size_t q = min_q; q <= max_q; q++) {\n        if (cur_moment_used_flags[q]) {\n            start_next_moment();\n            break;\n        }\n    }\n    for (size_t q = min_q; q <= max_q; q++) {\n        cur_moment_used_flags[q] = true;\n    }\n    cur_moment_is_used = true;\n    if (min_q < max_q) {\n        diagram.lines.push_back(\n            {{\n                 m2x(cur_moment),\n                 q2y(min_q),\n                 GATE_ALIGNMENT_X,\n                 GATE_ALIGNMENT_Y,\n             },\n             {\n                 m2x(cur_moment),\n                 q2y(max_q),\n                 GATE_ALIGNMENT_X,\n                 GATE_ALIGNMENT_Y,\n             }});\n    }\n}\nvoid DiagramTimelineAsciiDrawer::do_multi_qubit_gate_with_pauli_targets(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n\n    for (const auto &t : op.targets) {\n        if (t.is_combiner()) {\n            continue;\n        }\n        std::stringstream ss;\n        const auto &gate_data = GATE_DATA[op.gate_type];\n        ss << gate_data.name;\n        if (t.is_x_target()) {\n            ss << \"[X]\";\n        } else if (t.is_y_target()) {\n            ss << \"[Y]\";\n        } else if (t.is_z_target()) {\n            ss << \"[Z]\";\n        }\n        if (!op.args.empty()) {\n            ss << \"(\" << comma_sep(op.args, \",\") << \")\";\n        }\n        if (gate_data.flags & GATE_PRODUCES_RESULTS) {\n            ss << ':';\n            write_rec_index(ss);\n        }\n        diagram.add_entry(\n            AsciiDiagramEntry{\n                {\n                    m2x(cur_moment),\n                    q2y(t.qubit_value()),\n                    GATE_ALIGNMENT_X,\n                    GATE_ALIGNMENT_Y,\n                },\n                ss.str(),\n            });\n    }\n}\n\nvoid DiagramTimelineAsciiDrawer::do_start_repeat(const CircuitTimelineLoopData &loop_data) {\n    if (cur_moment_is_used) {\n        do_tick();\n    }\n\n    AsciiDiagramPos top{m2x(cur_moment), 0, 0.0, 0.0};\n    AsciiDiagramPos bot{m2x(cur_moment), q2y(num_qubits - 1) + 1, 0.0, 1.0};\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            top,\n            \"/REP \" + std::to_string(loop_data.num_repetitions),\n        });\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            bot,\n            \"\\\\\",\n        });\n    diagram.lines.push_back({bot, top});\n\n    start_next_moment();\n    tick_start_moment = cur_moment;\n}\n\nvoid DiagramTimelineAsciiDrawer::do_end_repeat(const CircuitTimelineLoopData &loop_data) {\n    if (cur_moment_is_used) {\n        do_tick();\n    }\n\n    AsciiDiagramPos top{m2x(cur_moment), 0, 0.5, 0.0};\n    AsciiDiagramPos bot{m2x(cur_moment), q2y(num_qubits - 1) + 1, 0.5, 1.0};\n\n    diagram.lines.push_back({top, bot});\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            top,\n            \"\\\\\",\n        });\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            bot,\n            \"/\",\n        });\n\n    start_next_moment();\n    tick_start_moment = cur_moment;\n}\n\nvoid DiagramTimelineAsciiDrawer::do_correlated_error(const ResolvedTimelineOperation &op) {\n    if (cur_moment_is_used) {\n        start_next_moment();\n    }\n    do_multi_qubit_gate_with_pauli_targets(op);\n}\n\nvoid DiagramTimelineAsciiDrawer::do_else_correlated_error(const ResolvedTimelineOperation &op) {\n    do_correlated_error(op);\n}\n\nvoid DiagramTimelineAsciiDrawer::do_qubit_coords(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n    assert(op.targets.size() == 1);\n    const auto &target = op.targets[0];\n\n    std::stringstream ss;\n    const auto &gate_data = GATE_DATA[op.gate_type];\n    ss << gate_data.name;\n    write_coords(ss, op.args);\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            {\n                m2x(cur_moment),\n                q2y(target.qubit_value()),\n                GATE_ALIGNMENT_X,\n                GATE_ALIGNMENT_Y,\n            },\n            ss.str(),\n        });\n}\n\nvoid DiagramTimelineAsciiDrawer::do_detector(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n    auto pseudo_target = op.targets[0];\n    SpanRef<const GateTarget> rec_targets = op.targets;\n    rec_targets.ptr_start++;\n\n    std::stringstream ss;\n    ss << \"DETECTOR\";\n    if (!op.args.empty()) {\n        write_coords(ss, op.args);\n    }\n    ss.put(':');\n    write_det_index(ss);\n    ss.put('=');\n    for (size_t k = 0; k < rec_targets.size(); k++) {\n        if (k) {\n            ss << \"*\";\n        }\n        write_rec_index(ss, rec_targets[k].value());\n    }\n    if (rec_targets.empty()) {\n        ss.put('1');\n    }\n    diagram.add_entry(\n        AsciiDiagramEntry{\n            {\n                m2x(cur_moment),\n                q2y(pseudo_target.qubit_value()),\n                GATE_ALIGNMENT_X,\n                GATE_ALIGNMENT_Y,\n            },\n            ss.str(),\n        });\n}\n\nvoid DiagramTimelineAsciiDrawer::do_observable_include(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n    auto pseudo_target = op.targets[0];\n    SpanRef<const GateTarget> rec_targets = op.targets;\n    rec_targets.ptr_start++;\n\n    bool had_paulis = false;\n    for (const auto &t : rec_targets) {\n        if (t.is_pauli_target()) {\n            had_paulis = true;\n            std::stringstream ss;\n            ss << \"L\" << (op.args.empty() ? 0 : op.args[0]) << \"*=\";\n            ss << t.pauli_type();\n            diagram.add_entry(\n                AsciiDiagramEntry{\n                    {\n                        m2x(cur_moment),\n                        q2y(t.qubit_value()),\n                        GATE_ALIGNMENT_X,\n                        GATE_ALIGNMENT_Y,\n                    },\n                    ss.str(),\n                });\n        }\n    }\n\n    bool had_rec = false;\n    std::stringstream ss;\n    ss << \"OBSERVABLE_INCLUDE:L\" << (op.args.empty() ? 0 : op.args[0]);\n    ss << \"*=\";\n    for (const auto &t : rec_targets) {\n        if (t.is_measurement_record_target()) {\n            if (had_rec) {\n                ss << \"*\";\n            }\n            had_rec = true;\n            write_rec_index(ss, t.value());\n        }\n    }\n    if (had_rec || !had_paulis) {\n        if (rec_targets.empty()) {\n            ss.put('1');\n        }\n        diagram.add_entry(\n            AsciiDiagramEntry{\n                {\n                    m2x(cur_moment),\n                    q2y(pseudo_target.qubit_value()),\n                    GATE_ALIGNMENT_X,\n                    GATE_ALIGNMENT_Y,\n                },\n                ss.str(),\n            });\n    }\n}\n\nvoid DiagramTimelineAsciiDrawer::do_resolved_operation(const ResolvedTimelineOperation &op) {\n    if (op.gate_type == GateType::MPP || op.gate_type == GateType::SPP || op.gate_type == GateType::SPP_DAG) {\n        do_multi_qubit_gate_with_pauli_targets(op);\n    } else if (op.gate_type == GateType::DETECTOR) {\n        do_detector(op);\n    } else if (op.gate_type == GateType::OBSERVABLE_INCLUDE) {\n        do_observable_include(op);\n    } else if (op.gate_type == GateType::QUBIT_COORDS) {\n        do_qubit_coords(op);\n    } else if (op.gate_type == GateType::E) {\n        do_correlated_error(op);\n    } else if (op.gate_type == GateType::ELSE_CORRELATED_ERROR) {\n        do_else_correlated_error(op);\n    } else if (op.gate_type == GateType::TICK) {\n        do_tick();\n    } else if (GATE_DATA[op.gate_type].flags & GATE_TARGETS_PAIRS) {\n        do_two_qubit_gate_instance(op);\n    } else {\n        do_single_qubit_gate_instance(op);\n    }\n}\n\nDiagramTimelineAsciiDrawer::DiagramTimelineAsciiDrawer(size_t num_qubits, bool has_ticks)\n    : num_qubits(num_qubits), has_ticks(has_ticks) {\n    cur_moment_used_flags.resize(num_qubits);\n}\n\nAsciiDiagram DiagramTimelineAsciiDrawer::make_diagram(const Circuit &circuit) {\n    auto num_qubits = circuit.count_qubits();\n    auto has_ticks = circuit.count_ticks() > 0;\n    DiagramTimelineAsciiDrawer obj(num_qubits, has_ticks);\n    obj.resolver.resolved_op_callback = [&](const ResolvedTimelineOperation &op) {\n        obj.do_resolved_operation(op);\n    };\n    obj.resolver.start_repeat_callback = [&](const CircuitTimelineLoopData &loop_data) {\n        obj.do_start_repeat(loop_data);\n    };\n    obj.resolver.end_repeat_callback = [&](const CircuitTimelineLoopData &loop_data) {\n        obj.do_end_repeat(loop_data);\n    };\n    obj.resolver.do_circuit(circuit);\n    if (obj.cur_moment_is_used) {\n        obj.do_tick();\n    }\n\n    // Make space for the qubit lines to be drawn before other things.\n    obj.diagram.lines.insert(obj.diagram.lines.begin(), obj.num_qubits, {{0, 0, 0.0, 0.5}, {0, 0, 1.0, 0.5}});\n    // Overwrite the reserved space with the actual qubit lines.\n    for (size_t q = 0; q < obj.num_qubits; q++) {\n        obj.diagram.lines[q] = {\n            {0, obj.q2y(q), 1.0, 0.5},\n            {obj.m2x(obj.cur_moment), obj.q2y(q), 0.0, 0.5},\n        };\n        std::stringstream qubit;\n        qubit << 'q' << q << \": \";\n        obj.diagram.add_entry(\n            AsciiDiagramEntry{\n                {0, obj.q2y(q), 1.0, 0.5},\n                qubit.str(),\n            });\n    }\n\n    return obj.diagram;\n}\n"
  },
  {
    "path": "src/stim/diagram/timeline/timeline_ascii_drawer.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_TIMELINE_TIMELINE_ASCII_DRAWER_H\n#define _STIM_DIAGRAM_TIMELINE_TIMELINE_ASCII_DRAWER_H\n\n#include <iostream>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/diagram/ascii_diagram.h\"\n#include \"stim/diagram/circuit_timeline_helper.h\"\n#include \"stim/diagram/lattice_map.h\"\n\nnamespace stim_draw_internal {\n\nstruct DiagramTimelineAsciiDrawer {\n    AsciiDiagram diagram;\n    CircuitTimelineHelper resolver;\n\n    size_t cur_moment = 0;\n    size_t cur_moment_is_used = false;\n    size_t tick_start_moment = 0;\n    std::vector<bool> cur_moment_used_flags;\n    size_t num_qubits = 0;\n    bool has_ticks = false;\n    size_t moment_spacing = 1;\n\n    DiagramTimelineAsciiDrawer(size_t num_qubits, bool has_ticks);\n\n    /// Converts a circuit into a cell diagram.\n    static AsciiDiagram make_diagram(const stim::Circuit &circuit);\n\n    void do_start_repeat(const CircuitTimelineLoopData &loop_data);\n    void do_end_repeat(const CircuitTimelineLoopData &loop_data);\n    void start_next_moment();\n    void reserve_drawing_room_for_targets(stim::SpanRef<const stim::GateTarget> targets);\n    void write_rec_index(std::ostream &out, int64_t lookback_shift = -1);\n    void write_det_index(std::ostream &out);\n    void write_coord(std::ostream &out, size_t coord_index, double relative_coordinate);\n    void write_coords(std::ostream &out, stim::SpanRef<const double> relative_coordinates);\n    size_t m2x(size_t m) const;\n    size_t q2y(size_t q) const;\n\n    void do_resolved_operation(const ResolvedTimelineOperation &op);\n    void do_tick();\n    void do_two_qubit_gate_instance(const ResolvedTimelineOperation &op);\n    void do_feedback(\n        std::string_view gate, const stim::GateTarget &qubit_target, const stim::GateTarget &feedback_target);\n    void do_single_qubit_gate_instance(const ResolvedTimelineOperation &op);\n    void do_multi_qubit_gate_with_pauli_targets(const ResolvedTimelineOperation &op);\n    void do_multi_qubit_gate_with_paired_pauli_targets(const ResolvedTimelineOperation &op);\n    void do_correlated_error(const ResolvedTimelineOperation &op);\n    void do_qubit_coords(const ResolvedTimelineOperation &op);\n    void do_else_correlated_error(const ResolvedTimelineOperation &op);\n    void do_detector(const ResolvedTimelineOperation &op);\n    void do_observable_include(const ResolvedTimelineOperation &op);\n};\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/timeline/timeline_ascii_drawer.test.cc",
    "content": "#include \"stim/diagram/timeline/timeline_ascii_drawer.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nTEST(circuit_diagram_timeline_text, single_qubit_gates) {\n    Circuit circuit(R\"CIRCUIT(\n        I 0\n        X 1\n        Y 2\n        Z 3\n        C_XYZ 0\n        C_ZYX 1\n        H 2\n        H_XY 3\n        H_XZ 0\n        H_YZ 1\n        S 2\n        SQRT_X 3\n        SQRT_X_DAG 0\n        SQRT_Y 1\n        SQRT_Y_DAG 2\n        SQRT_Z 3\n        SQRT_Z_DAG 0\n        S_DAG 1\n        H 2 0 3\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\nq0: -I-C_XYZ-H------SQRT_X_DAG-S_DAG-H-\n\nq1: -X-C_ZYX-H_YZ---SQRT_Y-----S_DAG---\n\nq2: -Y-H-----S------SQRT_Y_DAG-H-------\n\nq3: -Z-H_XY--SQRT_X-S----------------H-\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, two_qubits_gates) {\n    Circuit circuit(R\"CIRCUIT(\n        CNOT 0 1\n        CX 2 3\n        CY 4 5 5 4\n        CZ 0 2\n        ISWAP 1 3\n        ISWAP_DAG 2 4\n        SQRT_XX 3 5\n        SQRT_XX_DAG 0 5\n        SQRT_YY 3 4 4 3\n        SQRT_YY_DAG 0 1\n        SQRT_ZZ 2 3\n        SQRT_ZZ_DAG 4 5\n        SWAP 0 1\n        XCX 2 3\n        XCY 3 4\n        XCZ 0 1\n        YCX 2 3\n        YCY 4 5\n        YCZ 0 1\n        ZCX 2 3\n        ZCY 4 5\n        ZCZ 0 5 2 3 1 4\n        CXSWAP 0 1\n        SWAPCX 0 1\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\nq0: -@-@-------------------------SQRT_XX_DAG---------SQRT_YY_DAG-SWAP----------X-Y---@-----ZSWAP-XSWAP-\n     | |                         |                   |           |             | |   |     |     |\nq1: -X-|-ISWAP-------------------|-------------------SQRT_YY_DAG-SWAP----------@-@---|---@-XSWAP-ZSWAP-\n       | |                       |                                                   |   |\nq2: -@-@-|-----ISWAP_DAG---------|-------------------------------SQRT_ZZ-----X---Y-@-|-@-|-------------\n     |   |     |                 |                               |           |   | | | | |\nq3: -X---ISWAP-|---------SQRT_XX-|-----------SQRT_YY-SQRT_YY-----SQRT_ZZ-----X-X-X-X-|-@-|-------------\n               |         |       |           |       |                         |     |   |\nq4: -@-Y-------ISWAP_DAG-|-------|-----------SQRT_YY-SQRT_YY-----SQRT_ZZ_DAG---Y-Y-@-|---@-------------\n     | |                 |       |                               |               | | |\nq5: -Y-@-----------------SQRT_XX-SQRT_XX_DAG---------------------SQRT_ZZ_DAG-----Y-Y-@-----------------\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, noise_gates) {\n    Circuit circuit(R\"CIRCUIT(\n        DEPOLARIZE1(0.125) 0 1\n        DEPOLARIZE2(0.125) 0 2 4 5\n        X_ERROR(0.125) 0 1 2\n        Y_ERROR(0.125) 0 1 4\n        Z_ERROR(0.125) 2 3 5\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\nq0: -DEPOLARIZE1(0.125)-DEPOLARIZE2(0.125)-X_ERROR(0.125)-Y_ERROR(0.125)-\n                        |\nq1: -DEPOLARIZE1(0.125)-|------------------X_ERROR(0.125)-Y_ERROR(0.125)-\n                        |\nq2: --------------------DEPOLARIZE2(0.125)-X_ERROR(0.125)-Z_ERROR(0.125)-\n\nq3: ------------------------------------------------------Z_ERROR(0.125)-\n\nq4: --------------------DEPOLARIZE2(0.125)----------------Y_ERROR(0.125)-\n                        |\nq5: --------------------DEPOLARIZE2(0.125)----------------Z_ERROR(0.125)-\n)DIAGRAM\");\n\n    circuit = Circuit(R\"CIRCUIT(\n        E(0.25) X1 X2\n        CORRELATED_ERROR(0.125) X1 Y2 Z3\n        ELSE_CORRELATED_ERROR(0.25) X2 Y4 Z3\n        ELSE_CORRELATED_ERROR(0.25) X5\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\nq0: --------------------------------------------------------------------------------------\n\nq1: -E[X](0.25)-E[X](0.125)---------------------------------------------------------------\n     |          |\nq2: -E[X](0.25)-E[Y](0.125)-ELSE_CORRELATED_ERROR[X](0.25)--------------------------------\n                |           |\nq3: ------------E[Z](0.125)-ELSE_CORRELATED_ERROR[Z](0.25)--------------------------------\n                            |\nq4: ------------------------ELSE_CORRELATED_ERROR[Y](0.25)--------------------------------\n\nq5: -------------------------------------------------------ELSE_CORRELATED_ERROR[X](0.25)-\n)DIAGRAM\");\n\n    circuit = Circuit(R\"CIRCUIT(\n        PAULI_CHANNEL_1(0.125,0.25,0.125) 0 1 2 3\n        PAULI_CHANNEL_2(0.01,0.01,0.01,0.02,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01) 0 1 2 4\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\nq0: -PAULI_CHANNEL_1(0.125,0.25,0.125)-PAULI_CHANNEL_2[0](0.01,0.01,0.01,0.02,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01)-\n                                       |\nq1: -PAULI_CHANNEL_1(0.125,0.25,0.125)-PAULI_CHANNEL_2[1](0.01,0.01,0.01,0.02,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01)-\n\nq2: -PAULI_CHANNEL_1(0.125,0.25,0.125)-PAULI_CHANNEL_2[0](0.01,0.01,0.01,0.02,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01)-\n                                       |\nq3: -PAULI_CHANNEL_1(0.125,0.25,0.125)-|----------------------------------------------------------------------------------------------\n                                       |\nq4: -----------------------------------PAULI_CHANNEL_2[1](0.01,0.01,0.01,0.02,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01)-\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, collapsing) {\n    Circuit circuit(R\"CIRCUIT(\n        R 0\n        RX 1\n        RY 2\n        RZ 3\n        M(0.001) 0 1\n        MR 1 0\n        MRX 1 2\n        MRY 0 3 1\n        MRZ 0\n        MX 1\n        MY 2\n        MZ 3\n        MPP X0*Y2 Z3 X1 Z2*Y3\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\nq0: -R--M(0.001):rec[0]-MR:rec[3]-MRY:rec[6]-MR:rec[9]-------------MPP[X]:rec[13]----------------\n                                                                   |\nq1: -RX-M(0.001):rec[1]-MR:rec[2]-MRX:rec[4]-MRY:rec[8]-MX:rec[10]-|--------------MPP[X]:rec[15]-\n                                                                   |\nq2: -RY---------------------------MRX:rec[5]------------MY:rec[11]-MPP[Y]:rec[13]-MPP[Z]:rec[16]-\n                                                                                  |\nq3: -R----------------------------MRY:rec[7]------------M:rec[12]--MPP[Z]:rec[14]-MPP[Y]:rec[16]-\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, unphysical_observable_include) {\n    Circuit circuit(R\"CIRCUIT(\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(0, 1) 2\n        QUBIT_COORDS(1, 1) 3\n        OBSERVABLE_INCLUDE(0) X0 X1\n        OBSERVABLE_INCLUDE(1) Z0 Z2\n        OBSERVABLE_INCLUDE(2) X2 X3\n        MPP X0*X1*X2*X3 Z0*Z1 Z2*Z3\n        DEPOLARIZE1(0.001) 0 1 2 3\n        MPP X0*X1*X2*X3 Z0*Z1 Z2*Z3\n        DETECTOR rec[-1] rec[-4]\n        DETECTOR rec[-2] rec[-5]\n        DETECTOR rec[-3] rec[-6]\n        OBSERVABLE_INCLUDE(0) X0 X1\n        OBSERVABLE_INCLUDE(1) Z0 Z2\n        OBSERVABLE_INCLUDE(2) X2 X3\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\nq0: -QUBIT_COORDS(0,0)-L0*=X-L1*=Z-------MPP[X]:rec[0]-MPP[Z]:rec[1]-DEPOLARIZE1(0.001)-MPP[X]:rec[3]-MPP[Z]:rec[4]-DETECTOR:D1=rec[4]*rec[1]-DETECTOR:D2=rec[3]*rec[0]-L0*=X-L1*=Z-------\n                       |     |           |             |                                |             |                                                                 |     |\nq1: -QUBIT_COORDS(1,0)-L0*=X-|-----------MPP[X]:rec[0]-MPP[Z]:rec[1]-DEPOLARIZE1(0.001)-MPP[X]:rec[3]-MPP[Z]:rec[4]-----------------------------------------------------L0*=X-|-----------\n                             |           |                                              |                                                                                     |\nq2: -QUBIT_COORDS(0,1)-------L1*=Z-L2*=X-MPP[X]:rec[0]-MPP[Z]:rec[2]-DEPOLARIZE1(0.001)-MPP[X]:rec[3]-MPP[Z]:rec[5]-DETECTOR:D0=rec[5]*rec[2]---------------------------------L1*=Z-L2*=X-\n                                   |     |             |                                |             |                                                                             |\nq3: -QUBIT_COORDS(1,1)-------------L2*=X-MPP[X]:rec[0]-MPP[Z]:rec[2]-DEPOLARIZE1(0.001)-MPP[X]:rec[3]-MPP[Z]:rec[5]-----------------------------------------------------------------L2*=X-\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, measurement_looping) {\n    Circuit circuit(R\"CIRCUIT(\n        M 0\n        REPEAT 100 {\n            M 1\n            REPEAT 5 {\n                M 2\n            }\n            REPEAT 7 {\n                MPP X3*Y4\n            }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\n              /REP 100                  /REP 5                        \\ /REP 7                             \\ \\\nq0: -M:rec[0]-|-------------------------|-----------------------------|-|----------------------------------|-|-\n              |                         |                             | |                                  | |\nq1: ----------|--------M:rec[1+iter*13]-|-----------------------------|-|----------------------------------|-|-\n              |                         |                             | |                                  | |\nq2: ----------|-------------------------|------M:rec[2+iter*13+iter2]-|-|----------------------------------|-|-\n              |                         |                             | |                                  | |\nq3: ----------|-------------------------|-----------------------------|-|------MPP[X]:rec[7+iter*13+iter2]-|-|-\n              |                         |                             | |      |                           | |\nq4: ----------|-------------------------|-----------------------------|-|------MPP[Y]:rec[7+iter*13+iter2]-|-|-\n              \\                         \\                             / \\                                  / /\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, repeat) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        H 0 1 2\n        REPEAT 5 {\n            RX 2\n            REPEAT 100 {\n                H 0 1 3 3\n            }\n        }\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\n       /REP 5    /REP 100     \\ \\\nq0: -H-|---------|--------H---|-|-\n       |         |            | |\nq1: -H-|---------|--------H---|-|-\n       |         |            | |\nq2: -H-|------RX-|------------|-|-\n       |         |            | |\nq3: ---|---------|--------H-H-|-|-\n       \\         \\            / /\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, classical_feedback) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        M 0\n        CX rec[-1] 1\n        YCZ 2 sweep[5]\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\nq0: -M:rec[0]---\n\nq1: -X^rec[0]---\n\nq2: -Y^sweep[5]-\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, lattice_surgery_cnot) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        R 2\n        MPP X1*X2\n        MPP Z0*Z2\n        MX 2\n        CZ rec[-3] 0\n        CX rec[-2] 1\n        CZ rec[-1] 0\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\nq0: -----------------MPP[Z]:rec[1]-Z^rec[0]--Z^rec[2]-\n                     |\nq1: ---MPP[X]:rec[0]-|-------------X^rec[1]-----------\n       |             |\nq2: -R-MPP[X]:rec[0]-MPP[Z]:rec[1]-MX:rec[2]----------\n)DIAGRAM\");\n\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).transposed().str() + \"\\n\", R\"DIAGRAM(\n    q0:           q1:           q2:\n      |             |             |\n      |             |             R\n      |             |             |\n      |       MPP[X]:rec[0]-MPP[X]:rec[0]\n      |             |             |\nMPP[Z]:rec[1]---------------MPP[Z]:rec[1]\n      |             |             |\n  Z^rec[0]      X^rec[1]      MX:rec[2]\n      |             |             |\n  Z^rec[2]          |             |\n      |             |             |\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, tick) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        H 0 0\n        TICK\n        H 0 1\n        TICK\n        H 0\n        REPEAT 1 {\n            H 0 1\n            TICK\n            H 0\n            S 0\n        }\n        H 0 0\n        SQRT_X 0\n        TICK\n        H 0 0\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\n     /-\\     /REP 1   /-\\ \\ /--------\\ /-\\\nq0: -H-H-H-H-|------H-H-S-|-H-H-SQRT_X-H-H-\n             |            |\nq1: -----H---|------H-----|----------------\n     \\-/     \\        \\-/ / \\--------/ \\-/\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, shifted_coords) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        QUBIT_COORDS(1, 2) 1\n        DETECTOR(4, 5, 6)\n        SHIFT_COORDS(10, 20, 30, 40)\n        QUBIT_COORDS(1, 2) 2\n        DETECTOR(4, 5, 6)\n        REPEAT 100 {\n            QUBIT_COORDS(7, 8) 3 4\n            DETECTOR(9, 10, 11)\n            SHIFT_COORDS(0, 200, 300, 400)\n        }\n        QUBIT_COORDS(1, 2) 5\n        DETECTOR(4, 5, 6)\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\n                                                  /REP 100                                                  \\\nq0: -DETECTOR(4,5,6):D0=1-DETECTOR(14,25,36):D1=1-|--------DETECTOR(19,30+iter*200,41+iter*300):D[2+iter]=1-|-DETECTOR(14,20025,30036):D102=1-\n                                                  |                                                         |\nq1: -QUBIT_COORDS(1,2)----------------------------|---------------------------------------------------------|---------------------------------\n                                                  |                                                         |\nq2: -QUBIT_COORDS(11,22)--------------------------|---------------------------------------------------------|---------------------------------\n                                                  |                                                         |\nq3: ----------------------------------------------|--------QUBIT_COORDS(17,28+iter*200)---------------------|---------------------------------\n                                                  |                                                         |\nq4: ----------------------------------------------|--------QUBIT_COORDS(17,28+iter*200)---------------------|---------------------------------\n                                                  |                                                         |\nq5: ----------------------------------------------|---------------------------------------------------------|-QUBIT_COORDS(11,20022)----------\n                                                  \\                                                         /\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, detector_pseudo_targets) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        M 0 1 2 3 4 5\n        REPEAT 100 {\n            M 1 2\n        }\n        DETECTOR(1) rec[-1]\n        DETECTOR(2) rec[-2]\n        DETECTOR(3) rec[-3]\n        DETECTOR(4) rec[-4]\n        DETECTOR(5) rec[-1] rec[-2]\n        OBSERVABLE_INCLUDE(100) rec[-201] rec[-203]\n    )CIRCUIT\");\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\n              /REP 100                 \\\nq0: -M:rec[0]-|------------------------|----------------------------------------------------------------------------------------\n              |                        |\nq1: -M:rec[1]-|--------M:rec[6+iter*2]-|-DETECTOR(2):D1=rec[204]-DETECTOR(4):D3=rec[202]-DETECTOR(5):D4=rec[205]*rec[204]-------\n              |                        |\nq2: -M:rec[2]-|--------M:rec[7+iter*2]-|-DETECTOR(1):D0=rec[205]-DETECTOR(3):D2=rec[203]----------------------------------------\n              |                        |\nq3: -M:rec[3]-|------------------------|-------------------------------------------------OBSERVABLE_INCLUDE:L100*=rec[5]*rec[3]-\n              |                        |\nq4: -M:rec[4]-|------------------------|----------------------------------------------------------------------------------------\n              |                        |\nq5: -M:rec[5]-|------------------------|----------------------------------------------------------------------------------------\n              \\                        /\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, surface_code) {\n    CircuitGenParameters params(10, 3, \"unrotated_memory_z\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\n      /-----------------\\     /-------\\ /-------\\     /----------------------------------\\ /REP 9       /-------\\ /-------\\     /-----------------------------------------------------------------------------------\\ \\ /------------------------------------------------------------------------------------------------------------------\\\n q0: -QUBIT_COORDS(0,0)-R-----------------@-------X----------------------------------------|------------------------@-------X-----------------------------------------------------------------------------------------|-M:rec[120]---------------------------------------------------------OBSERVABLE_INCLUDE:L0*=rec[122]*rec[121]*rec[120]-\n                                          |       |                                        |                        |       |                                                                                         |\n q1: -QUBIT_COORDS(1,0)-R-H-@-@-----------|-------@-H-MR:rec[0]----------------------------|--------H-@-@-----------|-------@-H-MR:rec[12+iter*12]-DETECTOR(1,0,1+iter):D[6+iter*12]=rec[12+iter*12]*rec[0+iter*12]---|----------------------------------------------------------------------------------------------------------------------\n                            | |           |                                                |          | |           |                                                                                                 |\n q2: -QUBIT_COORDS(2,0)-R---X-|-----------|-@-----X----------------------------------------|----------X-|-----------|-@-----X-----------------------------------------------------------------------------------------|-M:rec[121]-----------------------------------------------------------------------------------------------------------\n                              |           | |     |                                        |            |           | |     |                                                                                         |\n q3: -QUBIT_COORDS(3,0)-R-H-@-|-@---------|-|-----@-H-MR:rec[1]----------------------------|--------H-@-|-@---------|-|-----@-H-MR:rec[13+iter*12]-DETECTOR(3,0,1+iter):D[7+iter*12]=rec[13+iter*12]*rec[1+iter*12]---|----------------------------------------------------------------------------------------------------------------------\n                            | | |         | |                                              |          | | |         | |                                                                                               |\n q4: -QUBIT_COORDS(4,0)-R---X-|-|---------|-|-@--------------------------------------------|----------X-|-|---------|-|-@---------------------------------------------------------------------------------------------|-M:rec[122]-----------------------------------------------------------------------------------------------------------\n                              | |         | | |                                            |            | |         | | |                                                                                             |\n q5: -QUBIT_COORDS(0,1)-R---X-|-|-X-------X-|-|-------MR:rec[2]--DETECTOR(0,1,0):D0=rec[2]-|----------X-|-|-X-------X-|-|-------MR:rec[14+iter*12]-DETECTOR(0,1,1+iter):D[8+iter*12]=rec[14+iter*12]*rec[2+iter*12]---|-DETECTOR(0,1,10):D114=rec[125]*rec[123]*rec[120]*rec[110]------------------------------------------------------------\n                            | | | |         | |                                            |          | | | |         | |                                                                                             |\n q6: -QUBIT_COORDS(1,1)-R---@-X-|-|-----X---|-|---@----------------------------------------|----------@-X-|-|-----X---|-|---@-----------------------------------------------------------------------------------------|-M:rec[123]-----------------------------------------------------------------------------------------------------------\n                                | |     |   | |   |                                        |              | |     |   | |   |                                                                                         |\n q7: -QUBIT_COORDS(2,1)-R---X---|-|-X---|---X-|---X---MR:rec[3]--DETECTOR(2,1,0):D2=rec[3]-|----------X---|-|-X---|---X-|---X---MR:rec[15+iter*12]-DETECTOR(2,1,1+iter):D[9+iter*12]=rec[15+iter*12]*rec[3+iter*12]---|-DETECTOR(2,1,10):D116=rec[126]*rec[124]*rec[123]*rec[121]*rec[111]---------------------------------------------------\n                            |   | | |   |     |                                            |          |   | | |   |     |                                                                                             |\n q8: -QUBIT_COORDS(3,1)-R---@---X-|-|---|-X---|---@----------------------------------------|----------@---X-|-|---|-X---|---@-----------------------------------------------------------------------------------------|-M:rec[124]-----------------------------------------------------------------------------------------------------------\n                                  | |   | |   |   |                                        |                | |   | |   |   |                                                                                         |\n q9: -QUBIT_COORDS(4,1)-R---------|-|-X-|-|---X---X---MR:rec[4]--DETECTOR(4,1,0):D4=rec[4]-|----------------|-|-X-|-|---X---X---MR:rec[16+iter*12]-DETECTOR(4,1,1+iter):D[10+iter*12]=rec[16+iter*12]*rec[4+iter*12]--|-DETECTOR(4,1,10):D118=rec[127]*rec[124]*rec[122]*rec[112]------------------------------------------------------------\n                                  | | | | |                                                |                | | | | |                                                                                                 |\nq10: -QUBIT_COORDS(0,2)-R---------@-|-|-|-|-@-----X----------------------------------------|----------------@-|-|-|-|-@-----X-----------------------------------------------------------------------------------------|-M:rec[125]-----------------------------------------------------------------------------------------------------------\n                                    | | | | |     |                                        |                  | | | | |     |                                                                                         |\nq11: -QUBIT_COORDS(1,2)-R-H-@-@-----|-|-@-|-|-----@-H-MR:rec[5]----------------------------|--------H-@-@-----|-|-@-|-|-----@-H-MR:rec[17+iter*12]-DETECTOR(1,2,1+iter):D[11+iter*12]=rec[17+iter*12]*rec[5+iter*12]--|----------------------------------------------------------------------------------------------------------------------\n                            | |     | |   | |                                              |          | |     | |   | |                                                                                               |\nq12: -QUBIT_COORDS(2,2)-R---X-|-----@-|---|-|-@---X----------------------------------------|----------X-|-----@-|---|-|-@---X-----------------------------------------------------------------------------------------|-M:rec[126]-----------------------------------------------------------------------------------------------------------\n                              |       |   | | |   |                                        |            |       |   | | |   |                                                                                         |\nq13: -QUBIT_COORDS(3,2)-R-H-@-|-@-----|---@-|-|---@-H-MR:rec[6]----------------------------|--------H-@-|-@-----|---@-|-|---@-H-MR:rec[18+iter*12]-DETECTOR(3,2,1+iter):D[12+iter*12]=rec[18+iter*12]*rec[6+iter*12]--|----------------------------------------------------------------------------------------------------------------------\n                            | | |     |     | |                                            |          | | |     |     | |                                                                                             |\nq14: -QUBIT_COORDS(4,2)-R---X-|-|-----@-----|-|-@------------------------------------------|----------X-|-|-----@-----|-|-@-------------------------------------------------------------------------------------------|-M:rec[127]-----------------------------------------------------------------------------------------------------------\n                              | |           | | |                                          |            | |           | | |                                                                                           |\nq15: -QUBIT_COORDS(0,3)-R---X-|-|-X---------X-|-|-----MR:rec[7]--DETECTOR(0,3,0):D1=rec[7]-|----------X-|-|-X---------X-|-|-----MR:rec[19+iter*12]-DETECTOR(0,3,1+iter):D[13+iter*12]=rec[19+iter*12]*rec[7+iter*12]--|-DETECTOR(0,3,10):D115=rec[130]*rec[128]*rec[125]*rec[115]------------------------------------------------------------\n                            | | | |           | |                                          |          | | | |           | |                                                                                           |\nq16: -QUBIT_COORDS(1,3)-R---@-X-|-|-----X-----|-|-@----------------------------------------|----------@-X-|-|-----X-----|-|-@-----------------------------------------------------------------------------------------|-M:rec[128]-----------------------------------------------------------------------------------------------------------\n                                | |     |     | | |                                        |              | |     |     | | |                                                                                         |\nq17: -QUBIT_COORDS(2,3)-R---X---|-|-X---|-----X-|-X---MR:rec[8]--DETECTOR(2,3,0):D3=rec[8]-|----------X---|-|-X---|-----X-|-X---MR:rec[20+iter*12]-DETECTOR(2,3,1+iter):D[14+iter*12]=rec[20+iter*12]*rec[8+iter*12]--|-DETECTOR(2,3,10):D117=rec[131]*rec[129]*rec[128]*rec[126]*rec[116]---------------------------------------------------\n                            |   | | |   |       |                                          |          |   | | |   |       |                                                                                           |\nq18: -QUBIT_COORDS(3,3)-R---@---X-|-|---|-X-----|-@----------------------------------------|----------@---X-|-|---|-X-----|-@-----------------------------------------------------------------------------------------|-M:rec[129]-----------------------------------------------------------------------------------------------------------\n                                  | |   | |     | |                                        |                | |   | |     | |                                                                                         |\nq19: -QUBIT_COORDS(4,3)-R---------|-|-X-|-|-----X-X---MR:rec[9]--DETECTOR(4,3,0):D5=rec[9]-|----------------|-|-X-|-|-----X-X---MR:rec[21+iter*12]-DETECTOR(4,3,1+iter):D[15+iter*12]=rec[21+iter*12]*rec[9+iter*12]--|-DETECTOR(4,3,10):D119=rec[132]*rec[129]*rec[127]*rec[117]------------------------------------------------------------\n                                  | | | | |                                                |                | | | | |                                                                                                 |\nq20: -QUBIT_COORDS(0,4)-R---------@-|-|-|-|-------X----------------------------------------|----------------@-|-|-|-|-------X-----------------------------------------------------------------------------------------|-M:rec[130]-----------------------------------------------------------------------------------------------------------\n                                    | | | |       |                                        |                  | | | |       |                                                                                         |\nq21: -QUBIT_COORDS(1,4)-R-H-@-------|-|-@-|-------@-H-MR:rec[10]---------------------------|--------H-@-------|-|-@-|-------@-H-MR:rec[22+iter*12]-DETECTOR(1,4,1+iter):D[16+iter*12]=rec[22+iter*12]*rec[10+iter*12]-|----------------------------------------------------------------------------------------------------------------------\n                            |       | |   |                                                |          |       | |   |                                                                                                 |\nq22: -QUBIT_COORDS(2,4)-R---X-------@-|---|-------X----------------------------------------|----------X-------@-|---|-------X-----------------------------------------------------------------------------------------|-M:rec[131]-----------------------------------------------------------------------------------------------------------\n                                      |   |       |                                        |                    |   |       |                                                                                         |\nq23: -QUBIT_COORDS(3,4)-R-H-@---------|---@-------@-H-MR:rec[11]---------------------------|--------H-@---------|---@-------@-H-MR:rec[23+iter*12]-DETECTOR(3,4,1+iter):D[17+iter*12]=rec[23+iter*12]*rec[11+iter*12]-|----------------------------------------------------------------------------------------------------------------------\n                            |         |                                                    |          |         |                                                                                                     |\nq24: -QUBIT_COORDS(4,4)-R---X---------@----------------------------------------------------|----------X---------@-----------------------------------------------------------------------------------------------------|-M:rec[132]-----------------------------------------------------------------------------------------------------------\n      \\-----------------/     \\-------/ \\-------/     \\----------------------------------/ \\            \\-------/ \\-------/     \\-----------------------------------------------------------------------------------/ / \\------------------------------------------------------------------------------------------------------------------/\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, repetition_code) {\n    CircuitGenParameters params(10, 9, \"memory\");\n    auto circuit = generate_rep_code_circuit(params).circuit;\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\n            /--------------------------------\\ /REP 9       /-----------------------------------------------------------------------------\\ \\ /---------------------------------------------------\\\n q0: -R-@--------------------------------------|--------@-----------------------------------------------------------------------------------|-M:rec[80]-DETECTOR(1,10):D80=rec[81]*rec[80]*rec[72]--\n        |                                      |        |                                                                                   |\n q1: -R-X-X-MR:rec[0]-DETECTOR(1,0):D0=rec[0]--|--------X-X-MR:rec[8+iter*8]--DETECTOR(1,1+iter):D[8+iter*8]=rec[8+iter*8]*rec[0+iter*8]----|-------------------------------------------------------\n          |                                    |          |                                                                                 |\n q2: -R-@-@------------------------------------|--------@-@---------------------------------------------------------------------------------|-M:rec[81]-DETECTOR(3,10):D81=rec[82]*rec[81]*rec[73]--\n        |                                      |        |                                                                                   |\n q3: -R-X-X-MR:rec[1]-DETECTOR(3,0):D1=rec[1]--|--------X-X-MR:rec[9+iter*8]--DETECTOR(3,1+iter):D[9+iter*8]=rec[9+iter*8]*rec[1+iter*8]----|-------------------------------------------------------\n          |                                    |          |                                                                                 |\n q4: -R-@-@------------------------------------|--------@-@---------------------------------------------------------------------------------|-M:rec[82]-DETECTOR(5,10):D82=rec[83]*rec[82]*rec[74]--\n        |                                      |        |                                                                                   |\n q5: -R-X-X-MR:rec[2]-DETECTOR(5,0):D2=rec[2]--|--------X-X-MR:rec[10+iter*8]-DETECTOR(5,1+iter):D[10+iter*8]=rec[10+iter*8]*rec[2+iter*8]--|-------------------------------------------------------\n          |                                    |          |                                                                                 |\n q6: -R-@-@------------------------------------|--------@-@---------------------------------------------------------------------------------|-M:rec[83]-DETECTOR(7,10):D83=rec[84]*rec[83]*rec[75]--\n        |                                      |        |                                                                                   |\n q7: -R-X-X-MR:rec[3]-DETECTOR(7,0):D3=rec[3]--|--------X-X-MR:rec[11+iter*8]-DETECTOR(7,1+iter):D[11+iter*8]=rec[11+iter*8]*rec[3+iter*8]--|-------------------------------------------------------\n          |                                    |          |                                                                                 |\n q8: -R-@-@------------------------------------|--------@-@---------------------------------------------------------------------------------|-M:rec[84]-DETECTOR(9,10):D84=rec[85]*rec[84]*rec[76]--\n        |                                      |        |                                                                                   |\n q9: -R-X-X-MR:rec[4]-DETECTOR(9,0):D4=rec[4]--|--------X-X-MR:rec[12+iter*8]-DETECTOR(9,1+iter):D[12+iter*8]=rec[12+iter*8]*rec[4+iter*8]--|-------------------------------------------------------\n          |                                    |          |                                                                                 |\nq10: -R-@-@------------------------------------|--------@-@---------------------------------------------------------------------------------|-M:rec[85]-DETECTOR(11,10):D85=rec[86]*rec[85]*rec[77]-\n        |                                      |        |                                                                                   |\nq11: -R-X-X-MR:rec[5]-DETECTOR(11,0):D5=rec[5]-|--------X-X-MR:rec[13+iter*8]-DETECTOR(11,1+iter):D[13+iter*8]=rec[13+iter*8]*rec[5+iter*8]-|-------------------------------------------------------\n          |                                    |          |                                                                                 |\nq12: -R-@-@------------------------------------|--------@-@---------------------------------------------------------------------------------|-M:rec[86]-DETECTOR(13,10):D86=rec[87]*rec[86]*rec[78]-\n        |                                      |        |                                                                                   |\nq13: -R-X-X-MR:rec[6]-DETECTOR(13,0):D6=rec[6]-|--------X-X-MR:rec[14+iter*8]-DETECTOR(13,1+iter):D[14+iter*8]=rec[14+iter*8]*rec[6+iter*8]-|-------------------------------------------------------\n          |                                    |          |                                                                                 |\nq14: -R-@-@------------------------------------|--------@-@---------------------------------------------------------------------------------|-M:rec[87]-DETECTOR(15,10):D87=rec[88]*rec[87]*rec[79]-\n        |                                      |        |                                                                                   |\nq15: -R-X-X-MR:rec[7]-DETECTOR(15,0):D7=rec[7]-|--------X-X-MR:rec[15+iter*8]-DETECTOR(15,1+iter):D[15+iter*8]=rec[15+iter*8]*rec[7+iter*8]-|-------------------------------------------------------\n          |                                    |          |                                                                                 |\nq16: -R---@------------------------------------|----------@---------------------------------------------------------------------------------|-M:rec[88]-OBSERVABLE_INCLUDE:L0*=rec[88]--------------\n            \\--------------------------------/ \\            \\-----------------------------------------------------------------------------/ / \\---------------------------------------------------/\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, repetition_code_transposed) {\n    CircuitGenParameters params(10, 3, \"memory\");\n    auto circuit = generate_rep_code_circuit(params).circuit;\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).transposed().str() + \"\\n\", R\"DIAGRAM(\n                         q0:                                                q1:                                                q2:                                                q3:                                          q4:\n                          |                                                  |                                                  |                                                  |                                            |\n                          R                                                  R                                                  R                                                  R                                            R\n                          |                                                  |                                                  |                                                  |                                            |\n                          @--------------------------------------------------X                                                  @--------------------------------------------------X                                            |\n                          |                                                  |                                                  |                                                  |                                            |\n                          |                                                  X--------------------------------------------------@                                                  X--------------------------------------------@\n                          |                                                  |                                                  |                                                  |                                            |\n/                         |                                              MR:rec[0]                                              |                                              MR:rec[1]                                        |               \\\n|                         |                                                  |                                                  |                                                  |                                            |               |\n\\                         |                                       DETECTOR(1,0):D0=rec[0]                                       |                                       DETECTOR(3,0):D1=rec[1]                                 |               /\n                          |                                                  |                                                  |                                                  |                                            |\n/REP 9------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\\\n                          |                                                  |                                                  |                                                  |                                            |\n                          |                                                  |                                                  |                                                  |                                            |\n                          |                                                  |                                                  |                                                  |                                            |\n                          @--------------------------------------------------X                                                  @--------------------------------------------------X                                            |\n                          |                                                  |                                                  |                                                  |                                            |\n                          |                                                  X--------------------------------------------------@                                                  X--------------------------------------------@\n                          |                                                  |                                                  |                                                  |                                            |\n/                         |                                           MR:rec[2+iter*2]                                          |                                           MR:rec[3+iter*2]                                    |               \\\n|                         |                                                  |                                                  |                                                  |                                            |               |\n\\                         |                      DETECTOR(1,1+iter):D[2+iter*2]=rec[2+iter*2]*rec[0+iter*2]                     |                      DETECTOR(3,1+iter):D[3+iter*2]=rec[3+iter*2]*rec[1+iter*2]               |               /\n                          |                                                  |                                                  |                                                  |                                            |\n\\-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------/\n                          |                                                  |                                                  |                                                  |                                            |\n/                     M:rec[20]                                              |                                              M:rec[21]                                              |                                        M:rec[22]           \\\n|                         |                                                  |                                                  |                                                  |                                            |               |\n\\     DETECTOR(1,10):D20=rec[21]*rec[20]*rec[18]                             |                              DETECTOR(3,10):D21=rec[22]*rec[21]*rec[19]                             |                              OBSERVABLE_INCLUDE:L0*=rec[22]/\n                          |                                                  |                                                  |                                                  |                                            |\n)DIAGRAM\");\n}\n\nTEST(circuit_diagram_timeline_text, test_circuit_all_ops) {\n    auto circuit = generate_test_circuit_with_all_operations();\n    ASSERT_EQ(\"\\n\" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + \"\\n\", R\"DIAGRAM(\n      /-------------------\\ /---------------------\\ /---------------------\\ /-----------------------------------------------------------------------------------------------------------------------------------------------------\\ /------------------------------------------------------\\                        /REP 3 /---\\ \\   /--------------------------------------------------------------------------------------------------------------------------\\ /----------------------------------------\\\n q0: -QUBIT_COORDS(1,2,3)-I-C_XYZ--H_XY--SQRT_X-----ZSWAP-----SQRT_XX-----X------------DEPOLARIZE1(0.02)---------------X_ERROR(0.01)------------------------------------------------------------------------------------------------MPP[X]:rec[2]-MPP[Z]:rec[3]-SPP[X]-SPP_DAG[X]------------MRX:rec[4]-MXX:rec[11]-|------H-@---|---MR:rec[15]-X_ERROR(0.1)-MR(0.01):rec[16]-DETECTOR(2,4,6):D0=rec[16]-OBSERVABLE_INCLUDE:L0*=rec[16]-MPAD:rec[17]-MPAD:rec[19]-MRX:rec[20]--------------------------------X^rec[24]--\n                                                    |         |           |                                                                                                                                                         |             |             |      |                                |           |        |   |\n q1: ---------------------X-C_NXYZ-H-----SQRT_X_DAG-XSWAP-----SQRT_XX-----X-E[X](0.01)-DEPOLARIZE2(0.03)---------------Y_ERROR(0.02)------------------------------------------------------------------------------------------------MPP[Y]:rec[2]-MPP[Z]:rec[3]-SPP[Y]-SPP_DAG[Y]------------MRY:rec[5]-MXX---------|--------X-S-|------------------------------------------------------------------------------------------------------MPAD:rec[18]--------------MY:rec[21]---------------------------------Y^sweep[0]-\n                                                                            |          |                                                                                                                                            |                           |      |                                            |            |\n q2: ---------------------Y-C_XNYZ-H_YZ--SQRT_Y-----ISWAP-----SQRT_XX_DAG-X-E[Y](0.01)-DEPOLARIZE2(0.03)---------------Z_ERROR(0.03)------------------------------------------------------------------------------------------------MPP[Z]:rec[2]---------------SPP[Z]-SPP_DAG[Z]-SPP_DAG[X]-MR:rec[6]--MXX:rec[12]-|------------|-------------------------------------------------------------------------------------------------------------------L1*=Z--------MZZ:rec[22]-OBSERVABLE_INCLUDE:L1*=rec[22]-Z^rec[24]--\n                                                    |         |           | |                                                                                                                                                                                                                           |           |            |                                                                                                                   |            |\n q3: ---------------------Z-C_XYNZ-H_NXY-SQRT_Y_DAG-ISWAP-----SQRT_XX_DAG-Y-E[Z](0.01)-PAULI_CHANNEL_1(0.01,0.02,0.03)-HERALDED_ERASE(0.04):rec[0]--------------------------------------------------------------------------------------------------------------SPP[X]-----------------------MX:rec[7]--MXX---------|------------|-------------------------------------------------------------------------------------------------------------------L1*=Z--------MZZ---------------------------------------------------\n                                                                                                                                                                                                                                                                                                                    |            |\n q4: -----------------------C_ZYX--H_NXZ-S----------ISWAP_DAG-SQRT_YY-----X------------ELSE_CORRELATED_ERROR[X](0.02)--PAULI_CHANNEL_2[0](0.001,0.002,0.003,0.004,0.005,0.006,0.007,0.008,0.009,0.01,0.011,0.012,0.013,0.014,0.015)----------------------------------------------------------MY:rec[8]--MYY:rec[13]-|------------|--------------------------------------------------------------------------------------------------------------------------------------------MYY:rec[23]-------------------------------\n                                                    |         |           |            |                               |                                                                                                                                                                                |           |            |                                                                                                                                            |\n q5: -----------------------C_NZYX-H_NYZ-S_DAG------ISWAP_DAG-SQRT_YY-----@------------|-------------------------------PAULI_CHANNEL_2[1](0.001,0.002,0.003,0.004,0.005,0.006,0.007,0.008,0.009,0.01,0.011,0.012,0.013,0.014,0.015)----------------------------------------------------------M:rec[9]---MYY---------|------------|--------------------------------------------------------------------------------------------------------------------------------------------MYY---------------------------------------\n                                                                                       |                                                                                                                                                                                                                            |            |\n q6: -----------------------C_ZNYX------------------SWAP------SQRT_YY_DAG-Y------------ELSE_CORRELATED_ERROR[Z](0.02)--HERALDED_PAULI_CHANNEL_1(0.01,0.02,0.03,0.04):rec[1]------------------------------------------------------------------------------------------------------------------M:rec[10]--MZZ:rec[14]-|------------|--------------------------------------------------------------------------------------------------------------------------------------------MPP[X]:rec[24]----------------------------\n                                                    |         |           |            |                                                                                                                                                                                                                |           |            |                                                                                                                                            |\n q7: -----------------------C_ZYNX------------------SWAP------SQRT_YY_DAG-X------------ELSE_CORRELATED_ERROR[Y](0.02)--I_ERROR(0.06)---------------------------------------------------------------------------------------------------------------------------------------------------------RX---------MZZ---------|------------|--------------------------------------------------------------------------------------------------------------------------------------------MPP[Y]:rec[24]----------------------------\n                                                                                                                                                                                                                                                                                                                    |            |                                                                                                                                            |\n q8: -----------------------------------------------XSWAP-----SQRT_ZZ-----Y--------------------------------------------II_ERROR(0.07)--------------------------------------------------------------------------------------------------------------------------------------------------------RY---------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------MPP[Z]:rec[24]----------------------------\n                                                    |         |           |                                            |                                                                                                                                                                                            |            |\n q9: -----------------------------------------------ZSWAP-----SQRT_ZZ-----Y--------------------------------------------II_ERROR(0.07)--------------------------------------------------------------------------------------------------------------------------------------------------------R----------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                                                                                                                                                                                                                                                                                                                    |            |\nq10: -----------------------------------------------ZSWAP-----SQRT_ZZ_DAG-Y-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                                                    |         |           |                                                                                                                                                                                                                                         |            |\nq11: -----------------------------------------------ZSWAP-----SQRT_ZZ_DAG-@-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                                                                                                                                                                                                                                                                                                                    |            |\nq12: ---------------------------------------------------------II----------@-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                                                              |           |                                                                                                                                                                                                                                         |            |\nq13: ---------------------------------------------------------II----------X-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                                                                                                                                                                                                                                                                                                                    |            |\nq14: ---------------------------------------------------------------------@-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                                                                          |                                                                                                                                                                                                                                         |            |\nq15: ---------------------------------------------------------------------Y-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                                                                                                                                                                                                                                                                                                                    |            |\nq16: ---------------------------------------------------------------------@-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                                                                          |                                                                                                                                                                                                                                         |            |\nq17: ---------------------------------------------------------------------@-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n      \\-------------------/ \\---------------------/ \\---------------------/ \\-----------------------------------------------------------------------------------------------------------------------------------------------------/ \\------------------------------------------------------/                        \\      \\---/ /   \\--------------------------------------------------------------------------------------------------------------------------/ \\----------------------------------------/\n)DIAGRAM\");\n}\n"
  },
  {
    "path": "src/stim/diagram/timeline/timeline_svg_drawer.cc",
    "content": "#include \"stim/diagram/timeline/timeline_svg_drawer.h\"\n\n#include \"stim/circuit/gate_decomposition.h\"\n#include \"stim/diagram/circuit_timeline_helper.h\"\n#include \"stim/diagram/coord.h\"\n#include \"stim/diagram/detector_slice/detector_slice_set.h\"\n#include \"stim/diagram/diagram_util.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nconstexpr uint16_t TIME_SLICE_PADDING = 64;\nconstexpr uint16_t PADDING = 32;\nconstexpr uint16_t CIRCUIT_START_X = 32;\nconstexpr uint16_t CIRCUIT_START_Y = 32;\nconstexpr uint16_t GATE_PITCH = 64;\nconstexpr uint16_t GATE_RADIUS = 16;\nconstexpr uint16_t CONTROL_RADIUS = 12;\nconstexpr float SLICE_WINDOW_GAP = 1.1f;\n\ntemplate <typename T>\ninline void write_key_val(std::ostream &out, const char *key, const T &val) {\n    out << ' ' << key << \"=\\\"\" << val << \"\\\"\";\n}\n\nsize_t DiagramTimelineSvgDrawer::m2x(size_t m) const {\n    return GATE_PITCH * m + GATE_RADIUS + GATE_RADIUS + CIRCUIT_START_X + PADDING;\n}\n\nCoord<2> DiagramTimelineSvgDrawer::qt2xy(uint64_t tick, uint64_t moment_delta, size_t q) const {\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        Coord<2> result = coord_sys.qubit_coords[q];\n        result.xyz[0] += moment_delta * 14;\n        result.xyz[1] += moment_delta * 16;\n        result.xyz[0] += TIME_SLICE_PADDING;\n        result.xyz[1] += TIME_SLICE_PADDING;\n        uint64_t s = tick - min_tick;\n        uint64_t sx = s % num_cols;\n        uint64_t sy = s / num_cols;\n        result.xyz[0] += coord_sys.size.xyz[0] * sx * SLICE_WINDOW_GAP;\n        result.xyz[1] += coord_sys.size.xyz[1] * sy * SLICE_WINDOW_GAP;\n        return result;\n    }\n    return {(float)m2x(cur_moment), (float)q2y(q)};\n}\n\nCoord<2> DiagramTimelineSvgDrawer::q2xy(size_t q) const {\n    return qt2xy(resolver.num_ticks_seen, cur_moment - tick_start_moment, q);\n}\n\nsize_t DiagramTimelineSvgDrawer::q2y(size_t q) const {\n    return GATE_PITCH * q + CIRCUIT_START_Y + PADDING;\n}\n\nvoid DiagramTimelineSvgDrawer::do_feedback(\n    std::string_view gate, const GateTarget &qubit_target, const GateTarget &feedback_target) {\n    std::stringstream exponent;\n    if (feedback_target.is_sweep_bit_target()) {\n        exponent << \"sweep\";\n        if (mode == DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n            exponent << \"[\" << feedback_target.value() << \"]\";\n        }\n    } else if (feedback_target.is_measurement_record_target()) {\n        exponent << \"rec\";\n        if (mode == DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n            exponent << \"[\" << (feedback_target.value() + resolver.measure_offset) << \"]\";\n        }\n    }\n\n    auto c = q2xy(qubit_target.qubit_value());\n    draw_annotated_gate(\n        c.xyz[0],\n        c.xyz[1],\n        SvgGateData{\n            (uint16_t)(mode == DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE ? 2 : 1),\n            std::string(gate),\n            \"\",\n            exponent.str(),\n            \"lightgray\",\n            \"black\",\n            0,\n            10},\n        {});\n}\n\nvoid DiagramTimelineSvgDrawer::draw_x_control(float cx, float cy) {\n    svg_out << \"<circle\";\n    write_key_val(svg_out, \"cx\", cx);\n    write_key_val(svg_out, \"cy\", cy);\n    write_key_val(svg_out, \"r\", CONTROL_RADIUS);\n    write_key_val(svg_out, \"stroke\", \"black\");\n    write_key_val(svg_out, \"fill\", \"white\");\n    svg_out << \"/>\\n\";\n\n    svg_out << \"<path d=\\\"\";\n    svg_out << \"M\" << cx - CONTROL_RADIUS << \",\" << cy << \" \";\n    svg_out << \"L\" << cx + CONTROL_RADIUS << \",\" << cy << \" \";\n    svg_out << \"M\" << cx << \",\" << cy - CONTROL_RADIUS << \" \";\n    svg_out << \"L\" << cx << \",\" << cy + CONTROL_RADIUS << \" \";\n    svg_out << \"\\\"\";\n    write_key_val(svg_out, \"stroke\", \"black\");\n    svg_out << \"/>\\n\";\n}\n\nvoid DiagramTimelineSvgDrawer::draw_y_control(float cx, float cy) {\n    float r = CONTROL_RADIUS * 1.4;\n    float r_sin = r * sqrtf(3) * 0.5;\n    float r_cos = r * 0.5;\n    svg_out << \"<path d=\\\"\";\n    svg_out << \"M\" << cx << \",\" << cy + r << \" \";\n    svg_out << \"L\" << cx - r_sin << \",\" << cy - r_cos << \" \";\n    svg_out << \"L\" << cx + r_sin << \",\" << cy - r_cos << \" \";\n    svg_out << \"Z\";\n    svg_out << \"\\\"\";\n    write_key_val(svg_out, \"stroke\", \"black\");\n    write_key_val(svg_out, \"fill\", \"gray\");\n    svg_out << \"/>\\n\";\n}\n\nvoid DiagramTimelineSvgDrawer::draw_z_control(float cx, float cy) {\n    svg_out << \"<circle\";\n    write_key_val(svg_out, \"cx\", cx);\n    write_key_val(svg_out, \"cy\", cy);\n    write_key_val(svg_out, \"r\", CONTROL_RADIUS);\n    write_key_val(svg_out, \"stroke\", \"none\");\n    write_key_val(svg_out, \"fill\", \"black\");\n    svg_out << \"/>\\n\";\n}\n\nvoid DiagramTimelineSvgDrawer::draw_xswap_control(float cx, float cy) {\n    svg_out << \"<circle\";\n    write_key_val(svg_out, \"cx\", cx);\n    write_key_val(svg_out, \"cy\", cy);\n    write_key_val(svg_out, \"r\", CONTROL_RADIUS);\n    write_key_val(svg_out, \"stroke\", \"black\");\n    write_key_val(svg_out, \"fill\", \"white\");\n    svg_out << \"/>\\n\";\n\n    float r = CONTROL_RADIUS / 2.2f;\n    svg_out << \"<path d=\\\"\";\n    svg_out << \"M\" << cx - r << \",\" << cy - r << \" \";\n    svg_out << \"L\" << cx + r << \",\" << cy + r << \" \";\n    svg_out << \"M\" << cx + r << \",\" << cy - r << \" \";\n    svg_out << \"L\" << cx - r << \",\" << cy + r << \" \";\n    svg_out << \"\\\"\";\n    write_key_val(svg_out, \"stroke\", \"black\");\n    write_key_val(svg_out, \"stroke-width\", 4);\n    svg_out << \"/>\\n\";\n}\n\nvoid DiagramTimelineSvgDrawer::draw_zswap_control(float cx, float cy) {\n    svg_out << \"<circle\";\n    write_key_val(svg_out, \"cx\", cx);\n    write_key_val(svg_out, \"cy\", cy);\n    write_key_val(svg_out, \"r\", CONTROL_RADIUS);\n    write_key_val(svg_out, \"stroke\", \"none\");\n    write_key_val(svg_out, \"fill\", \"black\");\n    svg_out << \"/>\\n\";\n\n    float r = CONTROL_RADIUS / 2.2f;\n    svg_out << \"<path d=\\\"\";\n    svg_out << \"M\" << cx - r << \",\" << cy - r << \" \";\n    svg_out << \"L\" << cx + r << \",\" << cy + r << \" \";\n    svg_out << \"M\" << cx + r << \",\" << cy - r << \" \";\n    svg_out << \"L\" << cx - r << \",\" << cy + r << \" \";\n    svg_out << \"\\\"\";\n    write_key_val(svg_out, \"stroke\", \"white\");\n    write_key_val(svg_out, \"stroke-width\", 4);\n    svg_out << \"/>\\n\";\n}\n\nvoid DiagramTimelineSvgDrawer::draw_swap_control(float cx, float cy) {\n    float r = CONTROL_RADIUS / 2.0f;\n    svg_out << \"<path d=\\\"\";\n    svg_out << \"M\" << cx - r << \",\" << cy - r << \" \";\n    svg_out << \"L\" << cx + r << \",\" << cy + r << \" \";\n    svg_out << \"M\" << cx + r << \",\" << cy - r << \" \";\n    svg_out << \"L\" << cx - r << \",\" << cy + r << \" \";\n    svg_out << \"\\\"\";\n    write_key_val(svg_out, \"stroke\", \"black\");\n    write_key_val(svg_out, \"stroke-width\", 3);\n    svg_out << \"/>\\n\";\n}\n\nvoid DiagramTimelineSvgDrawer::draw_iswap_control(float cx, float cy, bool inverse) {\n    svg_out << \"<circle\";\n    write_key_val(svg_out, \"cx\", cx);\n    write_key_val(svg_out, \"cy\", cy);\n    write_key_val(svg_out, \"r\", CONTROL_RADIUS);\n    write_key_val(svg_out, \"stroke\", \"none\");\n    write_key_val(svg_out, \"fill\", \"gray\");\n    svg_out << \"/>\\n\";\n\n    draw_swap_control(cx, cy);\n\n    if (inverse) {\n        svg_out << \"<path d=\\\"\";\n        svg_out << \"M\" << cx + CONTROL_RADIUS - 4 << \",\" << cy - CONTROL_RADIUS - 2 << \" \";\n        svg_out << \"L\" << cx + CONTROL_RADIUS + 4 << \",\" << cy - CONTROL_RADIUS - 2 << \" \";\n        svg_out << \"M\" << cx + CONTROL_RADIUS << \",\" << cy - CONTROL_RADIUS - 6 << \" \";\n        svg_out << \"L\" << cx + CONTROL_RADIUS << \",\" << cy - 2 << \" \";\n        svg_out << \"\\\"\";\n        write_key_val(svg_out, \"stroke\", \"black\");\n        svg_out << \"/>\\n\";\n    }\n}\n\nvoid DiagramTimelineSvgDrawer::draw_generic_box(\n    float cx, float cy, std::string_view text, SpanRef<const double> end_args) {\n    auto f = gate_data_map.find(text);\n    if (f == gate_data_map.end()) {\n        throw std::invalid_argument(\n            \"DiagramTimelineSvgDrawer::draw_generic_box unhandled gate case: \" + std::string(text));\n    }\n    SvgGateData data = f->second;\n    draw_annotated_gate(cx, cy, data, end_args);\n}\n\nvoid DiagramTimelineSvgDrawer::draw_annotated_gate(\n    float cx, float cy, const SvgGateData &data, SpanRef<const double> end_args) {\n    cx += (data.span - 1) * GATE_PITCH * 0.5f;\n    float w = GATE_PITCH * (data.span - 1) + GATE_RADIUS * 2.0f;\n    float h = GATE_RADIUS * 2.0f;\n    size_t n = utf8_char_count(data.body) + utf8_char_count(data.subscript) + +utf8_char_count(data.superscript);\n    auto font_size = data.font_size != 0 ? data.font_size : n == 1 ? 30 : n >= 4 && data.span == 1 ? 12 : 16;\n    svg_out << \"<rect\";\n    write_key_val(svg_out, \"x\", cx - w * 0.5);\n    write_key_val(svg_out, \"y\", cy - h * 0.5);\n    write_key_val(svg_out, \"width\", w);\n    write_key_val(svg_out, \"height\", h);\n    write_key_val(svg_out, \"stroke\", \"black\");\n    write_key_val(svg_out, \"fill\", data.fill);\n    svg_out << \"/>\\n\";\n\n    moment_width = std::max(moment_width, data.span);\n    svg_out << \"<text\";\n    write_key_val(svg_out, \"dominant-baseline\", \"central\");\n    write_key_val(svg_out, \"text-anchor\", \"middle\");\n    write_key_val(svg_out, \"font-family\", \"monospace\");\n    write_key_val(svg_out, \"font-size\", font_size);\n    write_key_val(svg_out, \"x\", cx);\n    write_key_val(svg_out, \"y\", cy + data.y_shift);\n    if (data.text_color != \"black\") {\n        write_key_val(svg_out, \"fill\", data.text_color);\n    }\n    svg_out << \">\";\n    svg_out << data.body;\n    if (data.superscript[0] != '\\0') {\n        svg_out << \"<tspan\";\n        write_key_val(svg_out, \"baseline-shift\", \"super\");\n        write_key_val(svg_out, \"font-size\", data.sub_font_size);\n        svg_out << \">\";\n        svg_out << data.superscript;\n        svg_out << \"</tspan>\";\n    }\n    if (data.subscript[0] != '\\0') {\n        svg_out << \"<tspan\";\n        write_key_val(svg_out, \"baseline-shift\", \"sub\");\n        write_key_val(svg_out, \"font-size\", data.sub_font_size);\n        svg_out << \">\";\n        svg_out << data.subscript;\n        svg_out << \"</tspan>\";\n    }\n    svg_out << \"</text>\\n\";\n\n    if (!end_args.empty()) {\n        svg_out << \"<text\";\n        write_key_val(svg_out, \"dominant-baseline\", \"hanging\");\n        write_key_val(svg_out, \"text-anchor\", \"middle\");\n        write_key_val(svg_out, \"font-family\", \"monospace\");\n        write_key_val(svg_out, \"font-size\", data.sub_font_size);\n        write_key_val(svg_out, \"stroke\", \"red\");\n        write_key_val(svg_out, \"x\", cx);\n        write_key_val(svg_out, \"y\", cy + GATE_RADIUS + 4);\n        svg_out << \">\";\n        svg_out << comma_sep(end_args, \",\");\n        svg_out << \"</text>\\n\";\n    }\n}\n\nvoid DiagramTimelineSvgDrawer::draw_two_qubit_gate_end_point(\n    float cx, float cy, std::string_view type, SpanRef<const double> args) {\n    if (type == \"X\") {\n        draw_x_control(cx, cy);\n    } else if (type == \"Y\") {\n        draw_y_control(cx, cy);\n    } else if (type == \"Z\") {\n        draw_z_control(cx, cy);\n    } else if (type == \"SWAP\") {\n        draw_swap_control(cx, cy);\n    } else if (type == \"ISWAP\") {\n        draw_iswap_control(cx, cy, false);\n    } else if (type == \"ISWAP_DAG\") {\n        draw_iswap_control(cx, cy, true);\n    } else if (type == \"XSWAP\") {\n        draw_xswap_control(cx, cy);\n    } else if (type == \"ZSWAP\") {\n        draw_zswap_control(cx, cy);\n    } else {\n        draw_generic_box(cx, cy, type, args);\n    }\n}\n\nvoid DiagramTimelineSvgDrawer::do_two_qubit_gate_instance(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n\n    const GateTarget &target1 = op.targets[0];\n    const GateTarget &target2 = op.targets[1];\n    auto ends = two_qubit_gate_pieces(op.gate_type);\n    if (target1.is_measurement_record_target() || target1.is_sweep_bit_target()) {\n        do_feedback(ends.second, target2, target1);\n        return;\n    }\n    if (target2.is_measurement_record_target() || target2.is_sweep_bit_target()) {\n        do_feedback(ends.first, target1, target2);\n        return;\n    }\n\n    auto pieces = two_qubit_gate_pieces(op.gate_type);\n    std::string piece1 = std::string(pieces.first);\n    std::string piece2 = std::string(pieces.second);\n    if (op.gate_type == GateType::PAULI_CHANNEL_2) {\n        piece1.append(\"[0]\");\n        piece2.append(\"[1]\");\n    }\n\n    auto c1 = q2xy(target1.qubit_value());\n    auto c2 = q2xy(target2.qubit_value());\n    bool b = c1.xyz[1] > c2.xyz[1];\n    draw_two_qubit_gate_end_point(c1.xyz[0], c1.xyz[1], piece1, b ? op.args : SpanRef<const double>{});\n    draw_two_qubit_gate_end_point(c2.xyz[0], c2.xyz[1], piece2, !b ? op.args : SpanRef<const double>{});\n}\n\nvoid DiagramTimelineSvgDrawer::start_next_moment() {\n    cur_moment += moment_width;\n    moment_width = 1;\n    cur_moment_is_used = false;\n    cur_moment_used_flags.clear();\n    cur_moment_used_flags.resize(num_qubits);\n}\n\nvoid DiagramTimelineSvgDrawer::do_tick() {\n    if (has_ticks && cur_moment > tick_start_moment && mode == DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        float x1 = (float)m2x(tick_start_moment);\n        float x2 = (float)m2x(cur_moment + moment_width - 1);\n        float y1 = PADDING;\n        float y2 = (float)q2y(num_qubits);\n        x1 -= GATE_PITCH * 0.4375;\n        x2 += GATE_PITCH * 0.4375;\n\n        svg_out << \"<path d=\\\"\";\n        svg_out << \"M\" << x1 << \",\" << y1 + GATE_RADIUS * 0.5f << \" \";\n        svg_out << \"L\" << x1 << \",\" << y1 << \" \";\n        svg_out << \"L\" << x2 << \",\" << y1 << \" \";\n        svg_out << \"L\" << x2 << \",\" << y1 + GATE_RADIUS * 0.5f << \" \";\n        svg_out << \"\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\";\n\n        svg_out << \"<path d=\\\"\";\n        svg_out << \"M\" << x1 << \",\" << y2 - GATE_RADIUS * 0.5f << \" \";\n        svg_out << \"L\" << x1 << \",\" << y2 << \" \";\n        svg_out << \"L\" << x2 << \",\" << y2 << \" \";\n        svg_out << \"L\" << x2 << \",\" << y2 - GATE_RADIUS * 0.5f << \" \";\n        svg_out << \"\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\";\n    }\n\n    start_next_moment();\n    tick_start_moment = cur_moment;\n}\n\nvoid DiagramTimelineSvgDrawer::do_single_qubit_gate_instance(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n    const auto &target = op.targets[0];\n\n    std::stringstream ss;\n    const auto &gate_data = GATE_DATA[op.gate_type];\n    ss << gate_data.name;\n\n    auto c = q2xy(target.qubit_value());\n    draw_generic_box(c.xyz[0], c.xyz[1], ss.str(), op.args);\n    if (gate_data.flags & GATE_PRODUCES_RESULTS) {\n        draw_rec(c.xyz[0], c.xyz[1]);\n    }\n}\n\nvoid DiagramTimelineSvgDrawer::write_det_index(std::ostream &out) {\n    out.put('D');\n    if (!resolver.cur_loop_nesting.empty()) {\n        out.put('[');\n    }\n    out << resolver.detector_offset;\n    for (size_t k = 0; k < resolver.cur_loop_nesting.size(); k++) {\n        out << \"+iter\";\n        if (k > 0) {\n            out << (k + 1);\n        }\n        auto p = resolver.cur_loop_nesting[k].detectors_per_iteration;\n        if (p != 1) {\n            out << '*' << p;\n        }\n    }\n    if (!resolver.cur_loop_nesting.empty()) {\n        out.put(']');\n    }\n}\nvoid DiagramTimelineSvgDrawer::write_rec_index(std::ostream &out, int64_t lookback_shift) {\n    out << \"rec[\";\n    out << resolver.measure_offset + (decltype(resolver.measure_offset))lookback_shift;\n    for (size_t k = 0; k < resolver.cur_loop_nesting.size(); k++) {\n        auto n = resolver.cur_loop_nesting[k].measurements_per_iteration;\n        if (n != 0) {\n            out << \"+iter\";\n            if (k > 0) {\n                out << (k + 1);\n            }\n            if (n != 1) {\n                out << '*' << n;\n            }\n        }\n    }\n    out << ']';\n}\n\nvoid DiagramTimelineSvgDrawer::write_coords(std::ostream &out, SpanRef<const double> relative_coordinates) {\n    out.put('(');\n    for (size_t k = 0; k < relative_coordinates.size(); k++) {\n        if (k) {\n            out.put(',');\n        }\n        write_coord(out, k, relative_coordinates[k]);\n    }\n    out.put(')');\n}\n\nvoid DiagramTimelineSvgDrawer::write_coord(std::ostream &out, size_t coord_index, double absolute_coordinate) {\n    out << absolute_coordinate;\n    for (size_t k = 0; k < resolver.cur_loop_nesting.size(); k++) {\n        const auto &p = resolver.cur_loop_nesting[k].shift_per_iteration;\n        if (coord_index < p.size() && p[coord_index] != 0) {\n            out << \"+iter\";\n            if (k > 0) {\n                out << (k + 1);\n            }\n            if (p[coord_index] != 1) {\n                out << '*' << p[coord_index];\n            }\n        }\n    }\n}\n\nstd::pair<size_t, size_t> compute_minmax_q(SpanRef<const GateTarget> targets) {\n    size_t min_q = SIZE_MAX;\n    size_t max_q = 0;\n    for (const auto &t : targets) {\n        if (t.is_combiner() || t.is_measurement_record_target() || t.is_sweep_bit_target()) {\n            continue;\n        }\n        size_t q = t.qubit_value();\n        min_q = std::min(min_q, q);\n        max_q = std::max(max_q, q);\n    }\n    return {min_q, max_q};\n}\n\nvoid DiagramTimelineSvgDrawer::reserve_drawing_room_for_targets(SpanRef<const GateTarget> targets) {\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        for (const auto &t : targets) {\n            if (t.has_qubit_value() && cur_moment_used_flags[t.qubit_value()]) {\n                start_next_moment();\n                break;\n            }\n        }\n        std::vector<Coord<2>> coords;\n        for (const auto &t : targets) {\n            if (t.has_qubit_value()) {\n                cur_moment_used_flags[t.qubit_value()] = true;\n                coords.push_back(q2xy(t.qubit_value()));\n            }\n        }\n        cur_moment_is_used = true;\n\n        if (coords.size() > 1) {\n            svg_out << \"<path d=\\\"\";\n            svg_out << \"M\" << coords[0].xyz[0] << \",\" << coords[0].xyz[1] << \" \";\n            for (size_t k = 1; k < coords.size(); k++) {\n                auto p1 = coords[k - 1];\n                auto p2 = coords[k];\n                auto dp = p2 - p1;\n                if (dp.norm() < coord_sys.unit_distance * 1.1) {\n                    svg_out << \"L\";\n                    svg_out << p2.xyz[0] << \",\" << p2.xyz[1] << \" \";\n                } else {\n                    auto dp2 = Coord<2>{-dp.xyz[1], dp.xyz[0]};\n                    if (2 * dp2.xyz[0] + 3 * dp2.xyz[1] < 0) {\n                        dp2 *= -1;\n                    }\n                    auto p3 = p1 + dp * 0.2 + dp2 * 0.2;\n                    auto p4 = p2 + dp * -0.2 + dp2 * 0.2;\n                    svg_out << \"C\";\n                    svg_out << p3.xyz[0] << \" \" << p3.xyz[1] << \",\";\n                    svg_out << p4.xyz[0] << \" \" << p4.xyz[1] << \",\";\n                    svg_out << p2.xyz[0] << \" \" << p2.xyz[1] << \" \";\n                }\n            }\n            svg_out << \"\\\"\";\n            write_key_val(svg_out, \"fill\", \"none\");\n            write_key_val(svg_out, \"stroke\", \"black\");\n            write_key_val(svg_out, \"stroke-width\", \"5\");\n            svg_out << \"/>\\n\";\n        }\n\n        return;\n    }\n\n    auto minmax_q = compute_minmax_q(targets);\n    auto min_q = minmax_q.first;\n    auto max_q = minmax_q.second;\n    if (min_q == SIZE_MAX) {\n        return;\n    }\n\n    for (size_t q = min_q; q <= max_q; q++) {\n        if (cur_moment_used_flags[q]) {\n            start_next_moment();\n            break;\n        }\n    }\n    for (size_t q = min_q; q <= max_q; q++) {\n        cur_moment_used_flags[q] = true;\n    }\n    cur_moment_is_used = true;\n    if (min_q < max_q) {\n        auto x = m2x(cur_moment);\n        auto y1 = q2y(min_q);\n        auto y2 = q2y(max_q);\n        svg_out << \"<path d=\\\"\";\n        svg_out << \"M\" << x << \",\" << y1 << \" \";\n        svg_out << \"L\" << x << \",\" << y2 << \" \";\n        svg_out << \"\\\"\";\n        write_key_val(svg_out, \"stroke\", \"black\");\n        svg_out << \"/>\\n\";\n    }\n}\n\nvoid DiagramTimelineSvgDrawer::draw_rec(float cx, float cy) {\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        return;\n    }\n    svg_out << \"<text\";\n    write_key_val(svg_out, \"text-anchor\", \"middle\");\n    write_key_val(svg_out, \"font-family\", \"monospace\");\n    write_key_val(svg_out, \"font-size\", 8);\n    write_key_val(svg_out, \"x\", cx);\n    write_key_val(svg_out, \"y\", cy - GATE_RADIUS - 4);\n    svg_out << \">\";\n    write_rec_index(svg_out);\n    svg_out << \"</text>\\n\";\n}\n\nvoid DiagramTimelineSvgDrawer::do_multi_qubit_gate_with_pauli_targets(const ResolvedTimelineOperation &op) {\n    reserve_drawing_room_for_targets(op.targets);\n    auto minmax_q = compute_minmax_q(op.targets);\n\n    for (const auto &t : op.targets) {\n        if (t.is_combiner()) {\n            continue;\n        }\n        std::stringstream ss;\n        const auto &gate_data = GATE_DATA[op.gate_type];\n        ss << gate_data.name;\n        if (t.is_x_target()) {\n            ss << \"[X]\";\n        } else if (t.is_y_target()) {\n            ss << \"[Y]\";\n        } else if (t.is_z_target()) {\n            ss << \"[Z]\";\n        }\n        auto c = q2xy(t.qubit_value());\n        draw_generic_box(\n            c.xyz[0], c.xyz[1], ss.str(), t.qubit_value() == minmax_q.second ? op.args : SpanRef<const double>{});\n        if (gate_data.flags & GATE_PRODUCES_RESULTS && t.qubit_value() == minmax_q.first) {\n            draw_rec(c.xyz[0], c.xyz[1]);\n        }\n    }\n}\n\nvoid DiagramTimelineSvgDrawer::do_start_repeat(const CircuitTimelineLoopData &loop_data) {\n    if (resolver.num_ticks_seen < min_tick || resolver.num_ticks_seen > max_tick) {\n        return;\n    }\n    if (cur_moment_is_used) {\n        do_tick();\n    }\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        return;\n    }\n\n    auto x = m2x(cur_moment);\n    auto y1 = PADDING;\n    auto y2 = q2y(num_qubits);\n    y1 += (resolver.cur_loop_nesting.size() - 1) * 4;\n    y2 -= (resolver.cur_loop_nesting.size() - 1) * 4;\n\n    svg_out << \"<path d=\\\"\";\n    svg_out << \"M\" << x + GATE_RADIUS * 0.5 << \",\" << y1 << \" \";\n    svg_out << \"L\" << x << \",\" << y1 << \" \";\n    svg_out << \"L\" << x << \",\" << y2 << \" \";\n    svg_out << \"L\" << x + GATE_RADIUS * 0.5 << \",\" << y2 << \" \";\n    svg_out << \"\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\";\n\n    svg_out << \"<text\";\n    write_key_val(svg_out, \"dominant-baseline\", \"auto\");\n    write_key_val(svg_out, \"text-anchor\", \"start\");\n    write_key_val(svg_out, \"font-family\", \"monospace\");\n    write_key_val(svg_out, \"font-size\", 12);\n    write_key_val(svg_out, \"x\", x + 4);\n    write_key_val(svg_out, \"y\", y2 - 4);\n    svg_out << \">\";\n    svg_out << \"REP\" << loop_data.num_repetitions;\n    svg_out << \"</text>\\n\";\n\n    start_next_moment();\n    tick_start_moment = cur_moment;\n}\n\nvoid DiagramTimelineSvgDrawer::do_end_repeat(const CircuitTimelineLoopData &loop_data) {\n    if (resolver.num_ticks_seen < min_tick || resolver.num_ticks_seen > max_tick) {\n        return;\n    }\n    if (cur_moment_is_used) {\n        do_tick();\n    }\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        return;\n    }\n\n    auto x = m2x(cur_moment);\n    auto y1 = PADDING;\n    auto y2 = q2y(num_qubits);\n    y1 += (resolver.cur_loop_nesting.size() - 1) * 4;\n    y2 -= (resolver.cur_loop_nesting.size() - 1) * 4;\n\n    svg_out << \"<path d=\\\"\";\n    svg_out << \"M\" << x - GATE_RADIUS * 0.5 << \",\" << y1 << \" \";\n    svg_out << \"L\" << x << \",\" << y1 << \" \";\n    svg_out << \"L\" << x << \",\" << y2 << \" \";\n    svg_out << \"L\" << x - GATE_RADIUS * 0.5 << \",\" << y2 << \" \";\n    svg_out << \"\\\" stroke=\\\"black\\\" fill=\\\"none\\\"/>\\n\";\n\n    start_next_moment();\n    tick_start_moment = cur_moment;\n}\n\nvoid DiagramTimelineSvgDrawer::do_mpp(const ResolvedTimelineOperation &op) {\n    do_multi_qubit_gate_with_pauli_targets(op);\n}\n\nvoid DiagramTimelineSvgDrawer::do_spp(const ResolvedTimelineOperation &op) {\n    do_multi_qubit_gate_with_pauli_targets(op);\n}\n\nvoid DiagramTimelineSvgDrawer::do_correlated_error(const ResolvedTimelineOperation &op) {\n    if (cur_moment_is_used) {\n        start_next_moment();\n    }\n    do_multi_qubit_gate_with_pauli_targets(op);\n}\n\nvoid DiagramTimelineSvgDrawer::do_else_correlated_error(const ResolvedTimelineOperation &op) {\n    do_correlated_error(op);\n}\n\nvoid DiagramTimelineSvgDrawer::do_qubit_coords(const ResolvedTimelineOperation &op) {\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        return;\n    }\n    reserve_drawing_room_for_targets(op.targets);\n    assert(op.targets.size() == 1);\n    const auto &target = op.targets[0];\n\n    std::stringstream ss;\n    ss << \"COORDS\";\n    write_coords(ss, op.args);\n    auto c = q2xy(target.qubit_value());\n    draw_annotated_gate(\n        c.xyz[0], c.xyz[1], SvgGateData{(uint16_t)(2 + op.args.size()), ss.str(), \"\", \"\", \"white\", \"black\", 0, 10}, {});\n}\n\nvoid DiagramTimelineSvgDrawer::do_detector(const ResolvedTimelineOperation &op) {\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        return;\n    }\n    reserve_drawing_room_for_targets(op.targets);\n    auto pseudo_target = op.targets[0];\n    SpanRef<const GateTarget> rec_targets = op.targets;\n    rec_targets.ptr_start++;\n\n    auto c = q2xy(pseudo_target.qubit_value());\n    auto span = (uint16_t)(1 + std::max(std::max(op.targets.size(), op.args.size()), (size_t)2));\n    draw_annotated_gate(c.xyz[0], c.xyz[1], SvgGateData{span, \"DETECTOR\", \"\", \"\", \"lightgray\", \"black\", 0, 10}, {});\n    c.xyz[0] += (span - 1) * GATE_PITCH * 0.5f;\n\n    if (!op.args.empty()) {\n        svg_out << \"<text\";\n        write_key_val(svg_out, \"dominant-baseline\", \"hanging\");\n        write_key_val(svg_out, \"text-anchor\", \"middle\");\n        write_key_val(svg_out, \"font-family\", \"monospace\");\n        write_key_val(svg_out, \"font-size\", 8);\n        write_key_val(svg_out, \"x\", c.xyz[0]);\n        write_key_val(svg_out, \"y\", c.xyz[1] + GATE_RADIUS + 4);\n        svg_out << \">coords=\";\n        write_coords(svg_out, op.args);\n        svg_out << \"</text>\\n\";\n    }\n\n    svg_out << \"<text\";\n    write_key_val(svg_out, \"text-anchor\", \"middle\");\n    write_key_val(svg_out, \"font-family\", \"monospace\");\n    write_key_val(svg_out, \"font-size\", 8);\n    write_key_val(svg_out, \"x\", c.xyz[0]);\n    write_key_val(svg_out, \"y\", c.xyz[1] - GATE_RADIUS - 4);\n    svg_out << \">\";\n    write_det_index(svg_out);\n    svg_out << \" = \";\n    for (size_t k = 0; k < rec_targets.size(); k++) {\n        if (k) {\n            svg_out << \"*\";\n        }\n        write_rec_index(svg_out, rec_targets[k].value());\n    }\n    if (rec_targets.empty()) {\n        svg_out << \"1 (vacuous)\";\n    }\n    svg_out << \"</text>\\n\";\n}\n\nvoid DiagramTimelineSvgDrawer::do_observable_include(const ResolvedTimelineOperation &op) {\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        return;\n    }\n    reserve_drawing_room_for_targets(op.targets);\n    auto pseudo_target = op.targets[0];\n    SpanRef<const GateTarget> rec_targets = op.targets;\n    rec_targets.ptr_start++;\n\n    // Draw per-quit L#*=P boxes.\n    bool had_paulis = false;\n    bool had_rec = false;\n    for (const auto &t : rec_targets) {\n        if (t.is_measurement_record_target()) {\n            had_rec = true;\n        }\n        if (t.is_pauli_target()) {\n            had_paulis = true;\n            std::stringstream ss;\n            ss << \"L\" << (op.args.empty() ? 0 : op.args[0]) << \"*=\";\n            ss << t.pauli_type();\n            auto c = q2xy(t.qubit_value());\n            draw_annotated_gate(\n                c.xyz[0],\n                c.xyz[1],\n                SvgGateData{\n                    .span = 2,\n                    .body = ss.str(),\n                    .subscript = \"\",\n                    .superscript = \"\",\n                    .fill = \"lightgray\",\n                    .text_color = \"black\",\n                    .font_size = 0,\n                    .sub_font_size = 10},\n                {});\n        }\n    }\n\n    // Draw OBS_INCLUDE(#) box with rec annotations above it, if there are measurement records.\n    if (had_rec) {\n        had_rec = false;\n        auto span = (uint16_t)(1 + std::max(std::max(op.targets.size(), op.args.size()), (size_t)2));\n        auto c = q2xy(pseudo_target.qubit_value());\n        std::stringstream ss;\n        ss << \"OBS_INCLUDE(\" << (op.args.empty() ? 0 : op.args[0]) << \")\";\n        if (!had_paulis) {\n            draw_annotated_gate(\n                c.xyz[0], c.xyz[1], SvgGateData{span, ss.str(), \"\", \"\", \"lightgray\", \"black\", 0, 10}, {});\n        }\n        c.xyz[0] += (span - 1) * GATE_PITCH * 0.5f;\n\n        svg_out << \"<text\";\n        write_key_val(svg_out, \"text-anchor\", \"middle\");\n        write_key_val(svg_out, \"font-family\", \"monospace\");\n        write_key_val(svg_out, \"font-size\", 8);\n        write_key_val(svg_out, \"x\", c.xyz[0]);\n        write_key_val(svg_out, \"y\", c.xyz[1] - GATE_RADIUS - 4);\n        svg_out << \">\";\n        svg_out << \"L\" << op.args[0] << \" *= \";\n        ss << \"*=\";\n        for (const auto &t : rec_targets) {\n            if (t.is_measurement_record_target()) {\n                if (had_rec) {\n                    svg_out << \"*\";\n                }\n                had_rec = true;\n                write_rec_index(svg_out, t.value());\n            }\n        }\n        if (!had_rec && !had_paulis) {\n            svg_out << \"1 (vacuous)\";\n        }\n        svg_out << \"</text>\\n\";\n    }\n}\n\nvoid DiagramTimelineSvgDrawer::do_resolved_operation(const ResolvedTimelineOperation &op) {\n    if (resolver.num_ticks_seen < min_tick || resolver.num_ticks_seen > max_tick) {\n        return;\n    }\n    if (op.gate_type == GateType::MPP) {\n        do_mpp(op);\n    } else if (op.gate_type == GateType::SPP || op.gate_type == GateType::SPP_DAG) {\n        do_spp(op);\n    } else if (op.gate_type == GateType::DETECTOR) {\n        do_detector(op);\n    } else if (op.gate_type == GateType::OBSERVABLE_INCLUDE) {\n        do_observable_include(op);\n    } else if (op.gate_type == GateType::QUBIT_COORDS) {\n        do_qubit_coords(op);\n    } else if (op.gate_type == GateType::E) {\n        do_correlated_error(op);\n    } else if (op.gate_type == GateType::ELSE_CORRELATED_ERROR) {\n        do_else_correlated_error(op);\n    } else if (op.gate_type == GateType::TICK) {\n        do_tick();\n    } else if (GATE_DATA[op.gate_type].flags & GATE_TARGETS_PAIRS) {\n        do_two_qubit_gate_instance(op);\n    } else {\n        do_single_qubit_gate_instance(op);\n    }\n}\n\nDiagramTimelineSvgDrawer::DiagramTimelineSvgDrawer(std::ostream &svg_out, size_t num_qubits, bool has_ticks)\n    : svg_out(svg_out), num_qubits(num_qubits), has_ticks(has_ticks), gate_data_map(SvgGateData::make_gate_data_map()) {\n    cur_moment_used_flags.resize(num_qubits);\n}\n\nvoid DiagramTimelineSvgDrawer::make_diagram_write_to(\n    const Circuit &circuit,\n    std::ostream &svg_out,\n    uint64_t tick_slice_start,\n    uint64_t tick_slice_num,\n    DiagramTimelineSvgDrawerMode mode,\n    SpanRef<const CoordFilter> filter,\n    size_t num_rows) {\n    uint64_t circuit_num_ticks = circuit.count_ticks();\n    auto circuit_has_ticks = circuit_num_ticks > 0;\n    auto num_qubits = circuit.count_qubits();\n    std::stringstream buffer;\n    DiagramTimelineSvgDrawer obj(buffer, num_qubits, circuit_has_ticks);\n    tick_slice_num = std::min(tick_slice_num, circuit_num_ticks - tick_slice_start + 1);\n    if (!circuit.operations.empty() && circuit.operations.back().gate_type == GateType::TICK) {\n        tick_slice_num = std::min(tick_slice_num, circuit_num_ticks - tick_slice_start);\n    }\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        // The +1 is because we're showing the detector slice at the end of each tick region.\n        obj.detector_slice_set =\n            DetectorSliceSet::from_circuit_ticks(circuit, tick_slice_start + 1, tick_slice_num, filter);\n        obj.coord_sys = FlattenedCoords::from(obj.detector_slice_set, GATE_PITCH);\n        obj.coord_sys.size.xyz[0] += TIME_SLICE_PADDING * 2;\n        obj.coord_sys.size.xyz[1] += TIME_SLICE_PADDING * 2;\n        if (num_rows == 0) {\n            obj.num_cols = (uint64_t)ceil(sqrt((double)tick_slice_num));\n            obj.num_rows = tick_slice_num / obj.num_cols;\n        } else {\n            obj.num_rows = num_rows;\n            obj.num_cols = (tick_slice_num + num_rows - 1) / num_rows;\n        }\n        while (obj.num_cols * obj.num_rows < tick_slice_num) {\n            obj.num_rows++;\n        }\n        while (obj.num_cols * obj.num_rows >= tick_slice_num + obj.num_rows) {\n            obj.num_cols--;\n        }\n    }\n    obj.min_tick = tick_slice_start;\n    obj.max_tick = tick_slice_start + tick_slice_num - 1;\n    obj.mode = mode;\n    obj.resolver.unroll_loops = mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE;\n    obj.resolver.resolved_op_callback = [&](const ResolvedTimelineOperation &op) {\n        obj.do_resolved_operation(op);\n    };\n    obj.resolver.start_repeat_callback = [&](const CircuitTimelineLoopData &loop_data) {\n        obj.do_start_repeat(loop_data);\n    };\n    obj.resolver.end_repeat_callback = [&](const CircuitTimelineLoopData &loop_data) {\n        obj.do_end_repeat(loop_data);\n    };\n    obj.resolver.do_circuit(circuit);\n    if (obj.cur_moment_is_used) {\n        obj.do_tick();\n    }\n\n    auto w = obj.m2x(obj.cur_moment) - GATE_PITCH * 0.5f;\n    svg_out << R\"SVG(<svg viewBox=\"0 0 )SVG\";\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        auto sw = obj.coord_sys.size.xyz[0] * ((obj.num_cols - 1) * SLICE_WINDOW_GAP + 1);\n        auto sh = obj.coord_sys.size.xyz[1] * ((obj.num_rows - 1) * SLICE_WINDOW_GAP + 1);\n        svg_out << sw << \" \" << sh;\n    } else {\n        svg_out << w + PADDING;\n        svg_out << \" \";\n        svg_out << obj.q2y(obj.num_qubits) + PADDING;\n    }\n    svg_out << '\"' << ' ';\n    write_key_val(svg_out, \"version\", \"1.1\");\n    write_key_val(svg_out, \"xmlns\", \"http://www.w3.org/2000/svg\");\n    svg_out << \">\\n\";\n\n    if (mode == DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE) {\n        obj.detector_slice_set.write_svg_contents_to(\n            svg_out,\n            [&](uint32_t qubit) {\n                return obj.coord_sys.unscaled_qubit_coords[qubit];\n            },\n            [&](uint64_t tick, uint32_t qubit) {\n                return obj.qt2xy(tick - 1, 0, qubit);\n            },\n            obj.max_tick + 2,\n            24);\n    }\n\n    // Make sure qubit lines/points are drawn first, so they are in the background.\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE) {\n        // Draw qubit points.\n        auto tick = tick_slice_start;\n        svg_out << \"<g id=\\\"qubit_dots\\\">\\n\";\n        for (uint64_t col = 0; col < obj.num_cols; col++) {\n            for (uint64_t row = 0; row < obj.num_rows && row * obj.num_cols + col < tick_slice_num; row++) {\n                for (auto q : obj.detector_slice_set.used_qubits()) {\n                    std::stringstream id_ss;\n                    id_ss << \"qubit_dot\";\n                    id_ss << \":\" << q;\n                    add_coord_summary_to_ss(\n                        id_ss,\n                        obj.detector_slice_set.coordinates.at(q));  // the raw qubit coordinates, not projected to 2D\n                    id_ss << \":\" << tick;                           // the absolute tick\n\n                    auto c = obj.coord_sys.qubit_coords[q];  // the flattened coordinates in 2D\n\n                    svg_out << \"<circle\";\n                    write_key_val(svg_out, \"id\", id_ss.str());\n                    write_key_val(\n                        svg_out,\n                        \"cx\",\n                        TIME_SLICE_PADDING + c.xyz[0] + obj.coord_sys.size.xyz[0] * SLICE_WINDOW_GAP * col);\n                    write_key_val(\n                        svg_out,\n                        \"cy\",\n                        TIME_SLICE_PADDING + c.xyz[1] + obj.coord_sys.size.xyz[1] * SLICE_WINDOW_GAP * row);\n                    write_key_val(svg_out, \"r\", 2);\n                    write_key_val(svg_out, \"stroke\", \"none\");\n                    write_key_val(svg_out, \"fill\", \"black\");\n                    svg_out << \"/>\\n\";\n                }\n            }\n            tick++;\n        }\n        svg_out << \"</g>\\n\";\n    } else {\n        svg_out << \"<g id=\\\"qubit_lines\\\">\\n\";\n        // Draw qubit lines.\n        for (size_t q = 0; q < obj.num_qubits; q++) {\n            std::stringstream id_ss;\n            id_ss << \"qubit_line\";\n            id_ss << \":\" << q;\n\n            auto x1 = PADDING + CIRCUIT_START_X;\n            auto x2 = w;\n            auto y = obj.q2y(q);\n\n            svg_out << \"<path\";\n            write_key_val(svg_out, \"id\", id_ss.str());\n            svg_out << \" d=\\\"\";\n            svg_out << \"M\" << x1 << \",\" << y << \" \";\n            svg_out << \"L\" << x2 << \",\" << y << \" \";\n            svg_out << \"\\\"\";\n            write_key_val(svg_out, \"stroke\", \"black\");\n            svg_out << \"/>\\n\";\n\n            svg_out << \"<text\";\n            write_key_val(svg_out, \"dominant-baseline\", \"central\");\n            write_key_val(svg_out, \"text-anchor\", \"end\");\n            write_key_val(svg_out, \"font-family\", \"monospace\");\n            write_key_val(svg_out, \"font-size\", 12);\n            write_key_val(svg_out, \"x\", x1);\n            write_key_val(svg_out, \"y\", y);\n            svg_out << \">\";\n            svg_out << \"q\" << q;\n            svg_out << \"</text>\\n\";\n        }\n        svg_out << \"</g>\\n\";\n    }\n\n    svg_out << buffer.str();\n\n    // Border around different slices.\n    if (mode != DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE && tick_slice_num > 1) {\n        auto k = 0;\n        svg_out << \"<g id=\\\"tick_borders\\\">\\n\";\n        for (uint64_t row = 0; row < obj.num_rows; row++) {\n            for (uint64_t col = 0; col < obj.num_cols && row * obj.num_cols + col < tick_slice_num; col++) {\n                auto sw = obj.coord_sys.size.xyz[0];\n                auto sh = obj.coord_sys.size.xyz[1];\n\n                std::stringstream id_ss;\n                auto tick = k + tick_slice_start;  // the absolute tick\n                id_ss << \"tick_border:\" << k;\n                id_ss << \":\" << row << \"_\" << col;\n                id_ss << \":\" << tick;\n\n                svg_out << \"<text\";\n                write_key_val(svg_out, \"dominant-baseline\", \"hanging\");\n                write_key_val(svg_out, \"text-anchor\", \"middle\");\n                write_key_val(svg_out, \"font-family\", \"serif\");\n                write_key_val(svg_out, \"font-size\", 18);\n                write_key_val(svg_out, \"transform\", \"rotate(90)\");\n                write_key_val(svg_out, \"x\", sh * row * SLICE_WINDOW_GAP + sh / 2);\n                write_key_val(svg_out, \"y\", -(sw * col * SLICE_WINDOW_GAP + sw - 6));\n                svg_out << \">\";\n                svg_out << \"Tick \" << tick;\n                svg_out << \"</text>\\n\";\n\n                svg_out << \"<rect\";\n                write_key_val(svg_out, \"id\", id_ss.str());\n                write_key_val(svg_out, \"x\", sw * col * SLICE_WINDOW_GAP);\n                write_key_val(svg_out, \"y\", sh * row * SLICE_WINDOW_GAP);\n                write_key_val(svg_out, \"width\", sw);\n                write_key_val(svg_out, \"height\", sh);\n                write_key_val(svg_out, \"stroke\", \"black\");\n                write_key_val(svg_out, \"fill\", \"none\");\n                svg_out << \"/>\\n\";\n\n                k++;\n            }\n        }\n        svg_out << \"</g>\\n\";\n    }\n    svg_out << \"</svg>\";\n}\n"
  },
  {
    "path": "src/stim/diagram/timeline/timeline_svg_drawer.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_DIAGRAM_TIMELINE_TIMELINE_SVG_DRAWER_H\n#define _STIM_DIAGRAM_TIMELINE_TIMELINE_SVG_DRAWER_H\n\n#include <iostream>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/diagram/ascii_diagram.h\"\n#include \"stim/diagram/circuit_timeline_helper.h\"\n#include \"stim/diagram/detector_slice/detector_slice_set.h\"\n#include \"stim/diagram/gate_data_svg.h\"\n#include \"stim/diagram/lattice_map.h\"\n#include \"stim/util_bot/str_util.h\"\n\nnamespace stim_draw_internal {\n\nenum class DiagramTimelineSvgDrawerMode {\n    SVG_MODE_TIMELINE = 0,\n    SVG_MODE_TIME_SLICE = 1,\n    SVG_MODE_TIME_DETECTOR_SLICE = 2,\n};\n\nstruct DiagramTimelineSvgDrawer {\n    std::ostream &svg_out;\n    CircuitTimelineHelper resolver;\n\n    size_t cur_moment = 0;\n    uint16_t moment_width = 1;\n    size_t cur_moment_is_used = false;\n    size_t tick_start_moment = 0;\n    std::vector<bool> cur_moment_used_flags;\n    size_t num_qubits = 0;\n    bool has_ticks = false;\n    uint64_t min_tick = 0;\n    uint64_t max_tick = UINT64_MAX;\n    uint64_t num_cols = UINT64_MAX;\n    uint64_t num_rows = 1;\n    DiagramTimelineSvgDrawerMode mode;\n    DetectorSliceSet detector_slice_set;\n    FlattenedCoords coord_sys;\n    std::map<std::string_view, SvgGateData> gate_data_map;\n\n    DiagramTimelineSvgDrawer(std::ostream &out, size_t num_qubits, bool has_ticks);\n\n    /// Converts a circuit into a cell diagram.\n    static void make_diagram_write_to(\n        const stim::Circuit &circuit,\n        std::ostream &svg_out,\n        uint64_t tick_slice_start,\n        uint64_t tick_slice_num,\n        DiagramTimelineSvgDrawerMode mode,\n        stim::SpanRef<const CoordFilter> det_coord_filter,\n        size_t num_rows = 0);\n\n    void do_start_repeat(const CircuitTimelineLoopData &loop_data);\n    void do_end_repeat(const CircuitTimelineLoopData &loop_data);\n    void start_next_moment();\n    void reserve_drawing_room_for_targets(stim::SpanRef<const stim::GateTarget> targets);\n    void write_rec_index(std::ostream &out, int64_t lookback_shift = -1);\n    void write_det_index(std::ostream &out);\n    void write_coord(std::ostream &out, size_t coord_index, double relative_coordinate);\n    void write_coords(std::ostream &out, stim::SpanRef<const double> relative_coordinates);\n    size_t m2x(size_t m) const;\n    size_t q2y(size_t q) const;\n    Coord<2> q2xy(size_t q) const;\n    Coord<2> qt2xy(uint64_t tick, uint64_t moment_delta, size_t q) const;\n    void draw_annotated_gate(float cx, float cy, const SvgGateData &data, stim::SpanRef<const double> end_args);\n\n    void draw_xswap_control(float cx, float cy);\n    void draw_zswap_control(float cx, float cy);\n    void draw_x_control(float cx, float cy);\n    void draw_y_control(float cx, float cy);\n    void draw_z_control(float cx, float cy);\n    void draw_swap_control(float cx, float cy);\n    void draw_iswap_control(float cx, float cy, bool inverse);\n    void draw_generic_box(float cx, float cy, std::string_view text, stim::SpanRef<const double> end_args);\n    void draw_two_qubit_gate_end_point(float cx, float cy, std::string_view type, stim::SpanRef<const double> args);\n    void draw_rec(float cx, float cy);\n\n    void do_resolved_operation(const ResolvedTimelineOperation &op);\n    void do_tick();\n    void do_two_qubit_gate_instance(const ResolvedTimelineOperation &op);\n    void do_feedback(\n        std::string_view gate, const stim::GateTarget &qubit_target, const stim::GateTarget &feedback_target);\n    void do_single_qubit_gate_instance(const ResolvedTimelineOperation &op);\n    void do_multi_qubit_gate_with_pauli_targets(const ResolvedTimelineOperation &op);\n    void do_multi_qubit_gate_with_paired_pauli_targets(const ResolvedTimelineOperation &op);\n    void do_mpp(const ResolvedTimelineOperation &op);\n    void do_spp(const ResolvedTimelineOperation &op);\n    void do_correlated_error(const ResolvedTimelineOperation &op);\n    void do_qubit_coords(const ResolvedTimelineOperation &op);\n    void do_else_correlated_error(const ResolvedTimelineOperation &op);\n    void do_detector(const ResolvedTimelineOperation &op);\n    void do_observable_include(const ResolvedTimelineOperation &op);\n};\n\n}  // namespace stim_draw_internal\n\n#endif\n"
  },
  {
    "path": "src/stim/diagram/timeline/timeline_svg_drawer.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/diagram/timeline/timeline_svg_drawer.h\"\n\n#include <fstream>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\nusing namespace stim_draw_internal;\n\nvoid expect_svg_diagram_is_identical_to_saved_file(const Circuit &circuit, std::string_view key) {\n    std::stringstream ss;\n    CoordFilter filter;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 0, UINT64_MAX, DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE, {&filter});\n    expect_string_is_identical_to_saved_file(ss.str(), key);\n}\n\nTEST(circuit_diagram_timeline_svg, single_qubit_gates) {\n    Circuit circuit(R\"CIRCUIT(\n        I 0\n        X 1\n        Y 2\n        Z 3\n        C_XYZ 0\n        C_ZYX 1\n        H 2\n        H_XY 3\n        H_XZ 0\n        H_YZ 1\n        S 2\n        SQRT_X 3\n        SQRT_X_DAG 0\n        SQRT_Y 1\n        SQRT_Y_DAG 2\n        SQRT_Z 3\n        SQRT_Z_DAG 0\n        S_DAG 1\n        H 2 0 3\n    )CIRCUIT\");\n\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"single_qubits_gates.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, two_qubits_gates) {\n    Circuit circuit(R\"CIRCUIT(\n        CNOT 0 1\n        CX 2 3\n        CY 4 5 5 4\n        CZ 0 2\n        ISWAP 1 3\n        ISWAP_DAG 2 4\n        SQRT_XX 3 5\n        SQRT_XX_DAG 0 5\n        SQRT_YY 3 4 4 3\n        SQRT_YY_DAG 0 1\n        SQRT_ZZ 2 3\n        SQRT_ZZ_DAG 4 5\n        SWAP 0 1\n        XCX 2 3\n        XCY 3 4\n        XCZ 0 1\n        YCX 2 3\n        YCY 4 5\n        YCZ 0 1\n        ZCX 2 3\n        ZCY 4 5\n        ZCZ 0 5 2 3 1 4\n        CXSWAP 0 1\n        SWAPCX 2 3\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"two_qubits_gates.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, noise_gates) {\n    Circuit circuit(R\"CIRCUIT(\n        DEPOLARIZE1(0.125) 0 1\n        DEPOLARIZE2(0.125) 0 2 4 5\n        X_ERROR(0.125) 0 1 2\n        Y_ERROR(0.125) 0 1 4\n        Z_ERROR(0.125) 2 3 5\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"noise_gates_1.svg\");\n\n    circuit = Circuit(R\"CIRCUIT(\n        E(0.25) X1 X2\n        CORRELATED_ERROR(0.125) X1 Y2 Z3\n        ELSE_CORRELATED_ERROR(0.25) X2 Y4 Z3\n        ELSE_CORRELATED_ERROR(0.25) X5\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"noise_gates_2.svg\");\n\n    circuit = Circuit(R\"CIRCUIT(\n        PAULI_CHANNEL_1(0.125,0.25,0.125) 0 1 2 3\n        PAULI_CHANNEL_2(0.01,0.01,0.01,0.02,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01) 0 1 2 4\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"noise_gates_3.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, collapsing) {\n    Circuit circuit(R\"CIRCUIT(\n        R 0\n        RX 1\n        RY 2\n        RZ 3\n        M(0.001) 0 1\n        MR 1 0\n        MRX 1 2\n        MRY 0 3 1\n        MRZ 0\n        MX 1\n        MY 2\n        MZ 3\n        MPP X0*Y2 Z3 X1 Z2*Y3\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"collapsing.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, measurement_looping) {\n    Circuit circuit(R\"CIRCUIT(\n        M 0\n        REPEAT 100 {\n            M 1\n            REPEAT 5 {\n                M 2\n            }\n            REPEAT 7 {\n                MPP X3*Y4\n            }\n        }\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"measurement_looping.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, repeat) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        H 0 1 2\n        REPEAT 5 {\n            RX 2\n            REPEAT 100 {\n                H 0 1 3 3\n            }\n        }\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"repeat.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, classical_feedback) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        M 0\n        CX rec[-1] 1\n        YCZ 2 sweep[5]\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"classical_feedback.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, lattice_surgery_cnot) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        R 2\n        MPP X1*X2\n        MPP Z0*Z2\n        MX 2\n        CZ rec[-3] 0\n        CX rec[-2] 1\n        CZ rec[-1] 0\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"lattice_surgery_cnot.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, tick) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        H 0 0\n        TICK\n        H 0 1\n        TICK\n        H 0\n        REPEAT 1 {\n            H 0 1\n            TICK\n            H 0\n            S 0\n        }\n        H 0 0\n        SQRT_X 0\n        TICK\n        H 0 0\n    )CIRCUIT\");\n\n    std::stringstream ss;\n    CoordFilter filter;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 0, UINT64_MAX, DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE, {&filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"tick.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, shifted_coords) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        QUBIT_COORDS(1, 2) 1\n        DETECTOR(4, 5, 6)\n        SHIFT_COORDS(10, 20, 30, 40)\n        QUBIT_COORDS(1, 2) 2\n        DETECTOR(4, 5, 6)\n        REPEAT 100 {\n            QUBIT_COORDS(7, 8) 3 4\n            DETECTOR(9, 10, 11)\n            SHIFT_COORDS(0, 200, 300, 400)\n        }\n        QUBIT_COORDS(1, 2) 5\n        DETECTOR(4, 5, 6)\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"shifted_coords.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, detector_pseudo_targets) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        M 0 1 2 3 4 5\n        REPEAT 100 {\n            M 1 2\n        }\n        DETECTOR(1) rec[-1]\n        DETECTOR(2) rec[-2]\n        DETECTOR(3) rec[-3]\n        DETECTOR(4) rec[-4]\n        DETECTOR(5) rec[-1] rec[-2]\n        OBSERVABLE_INCLUDE(100) rec[-201] rec[-203]\n    )CIRCUIT\");\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"detector_pseudo_targets.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, repetition_code) {\n    CircuitGenParameters params(10, 3, \"memory\");\n    auto circuit = generate_rep_code_circuit(params).circuit;\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"repetition_code.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, surface_code) {\n    CircuitGenParameters params(10, 3, \"unrotated_memory_z\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    expect_svg_diagram_is_identical_to_saved_file(circuit, \"surface_code.svg\");\n}\n\nTEST(circuit_diagram_time_detector_slice_svg, surface_code_partial) {\n    CircuitGenParameters params(10, 3, \"unrotated_memory_z\");\n    auto circuit = generate_surface_code_circuit(params).circuit.flattened();\n    CoordFilter filter;\n    filter.coordinates.push_back(2);\n    std::stringstream ss;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 5, 11, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE, {&filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"surface_code_time_detector_slice.svg\");\n}\n\nTEST(circuit_diagram_time_detector_slice_svg, surface_code_full) {\n    CircuitGenParameters params(5, 3, \"unrotated_memory_z\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    CoordFilter filter;\n    filter.coordinates.push_back(1);\n    std::stringstream ss;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 0, UINT64_MAX, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE, {&filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"surface_code_full_time_detector_slice.svg\");\n}\n\nTEST(circuit_diagram_time_slice_svg, surface_code) {\n    CircuitGenParameters params(10, 3, \"rotated_memory_z\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    CoordFilter filter;\n    std::stringstream ss;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 5, 11, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_SLICE, {&filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"surface_code_time_slice.svg\");\n}\n\nTEST(circuit_diagram_timeline_svg, chained_loops) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        REPEAT 2 {\n            H 0\n            TICK\n        }\n        X 0\n        TICK\n        Y 0\n        TICK\n        Z 0\n        TICK\n        REPEAT 3 {\n            C_XYZ 0\n            TICK\n        }\n        X 1\n        TICK\n        Y 1\n        TICK\n        Z 1\n        TICK\n    )CIRCUIT\");\n\n    CoordFilter empty_filter;\n    std::stringstream ss;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 0, UINT64_MAX, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE, {&empty_filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"circuit_diagram_timeline_svg_chained_loops.svg\");\n}\n\nTEST(diagram_timeline_svg_drawer, make_diagram_write_to) {\n    CircuitGenParameters params(2, 3, \"rotated_memory_x\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    std::vector<CoordFilter> coord_filter{CoordFilter{}};\n    std::stringstream ss;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit,\n        ss,\n        0,\n        circuit.count_ticks(),\n        DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE,\n        coord_filter);\n    expect_string_is_identical_to_saved_file(ss.str(), \"detslice-with-ops_surface_code.svg\");\n}\n\nTEST(diagram_timeline_svg_drawer, test_circuit_all_ops_time_slice) {\n    auto circuit = generate_test_circuit_with_all_operations();\n    CoordFilter filter;\n    std::stringstream ss;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 0, UINT64_MAX, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_SLICE, {&filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"circuit_all_ops_timeslice.svg\");\n}\n\nTEST(diagram_timeline_svg_drawer, test_circuit_all_ops_time_line) {\n    auto circuit = generate_test_circuit_with_all_operations();\n    CoordFilter filter;\n    std::stringstream ss;\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 0, UINT64_MAX, DiagramTimelineSvgDrawerMode::SVG_MODE_TIMELINE, {&filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"circuit_all_ops_timeline.svg\");\n}\n\nTEST(diagram_timeline_svg_drawer, test_circuit_all_ops_detslice) {\n    CoordFilter empty_filter;\n    std::stringstream ss;\n    auto circuit = generate_test_circuit_with_all_operations();\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 0, UINT64_MAX, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE, {&empty_filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"circuit_all_ops_detslice.svg\");\n}\n\nTEST(diagram_timeline_svg_drawer, anticommuting_detector_circuit) {\n    CoordFilter empty_filter;\n    std::stringstream ss;\n    auto circuit = Circuit(R\"CIRCUIT(\n        TICK\n        R 0\n        TICK\n        R 0\n        TICK\n        MXX 0 1\n        M 2\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n    )CIRCUIT\");\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 0, UINT64_MAX, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_DETECTOR_SLICE, {&empty_filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"anticommuting_detslice.svg\");\n}\n\nTEST(diagram_timeline_svg_drawer, bezier_curves) {\n    CoordFilter empty_filter;\n    std::stringstream ss;\n    auto circuit = Circuit(R\"CIRCUIT(\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(2, 0) 2\n        QUBIT_COORDS(3, 0) 3\n        CX 0 1\n        CX 2 3\n        TICK\n        CX 0 2\n        CX 1 3\n    )CIRCUIT\");\n    DiagramTimelineSvgDrawer::make_diagram_write_to(\n        circuit, ss, 0, UINT64_MAX, DiagramTimelineSvgDrawerMode::SVG_MODE_TIME_SLICE, {&empty_filter});\n    expect_string_is_identical_to_saved_file(ss.str(), \"bezier_time_slice.svg\");\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_annotations.cc",
    "content": "#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nvoid GateDataMap::add_gate_data_annotations(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"DETECTOR\",\n            .id = GateType::DETECTOR,\n            .best_candidate_inverse_id = GateType::DETECTOR,\n            .arg_count = ARG_COUNT_SYGIL_ANY,\n            .flags =\n                (GateFlags)(GATE_ONLY_TARGETS_MEASUREMENT_RECORD | GATE_IS_NOT_FUSABLE | GATE_HAS_NO_EFFECT_ON_QUBITS),\n            .category = \"Z_Annotations\",\n            .help = R\"MARKDOWN(\nAnnotates that a set of measurements can be used to detect errors, because the set's parity should be deterministic.\n\nNote that it is not necessary to say whether the measurement set's parity is even or odd; all that matters is that the\nparity should be *consistent* when running the circuit and omitting all noisy operations. Note that, for example, this\nmeans that even though `X` and `X_ERROR(1)` have equivalent effects on the measurements making up a detector, they have\ndiffering effects on the detector (because `X` is intended, determining the expected value, and `X_ERROR` is noise,\ncausing deviations from the expected value).\n\nDetectors are ignored when sampling measurements, but produce results when sampling detection events. In detector\nsampling mode, each detector produces a result bit (where 0 means \"measurement set had expected parity\" and 1 means\n\"measurement set had incorrect parity\"). When converting a circuit into a detector error model, errors are grouped based\non the detectors they flip (the \"symptoms\" of the error) and the observables they flip (the \"frame changes\" of the\nerror).\n\nIt is permitted, though not recommended, for the measurement set given to a `DETECTOR` instruction to have inconsistent\nparity. When a detector's measurement set is inconsistent, the detector is called a \"gauge detector\" and the expected\nparity of the measurement set is chosen arbitrarily (in an implementation-defined way). Some circuit analysis tools\n(such as the circuit-to-detector-error-model conversion) will by default refuse to process circuits containing gauge\ndetectors. Gauge detectors produce random results when sampling detection events, though these results will be\nappropriately correlated with other gauge detectors. For example, if `DETECTOR rec[-1]` and `DETECTOR rec[-2]` are gauge\ndetectors but `DETECTOR rec[-1] rec[-2]` is not, then under noiseless execution the two gauge detectors would either\nalways produce the same result or always produce opposite results.\n\nDetectors can specify coordinates using their parens arguments. Coordinates have no effect on simulations, but can be\nuseful to tools consuming the circuit. For example, a tool drawing how the detectors in a circuit relate to each other\ncan use the coordinates as hints for where to place the detectors in the drawing.\n\nParens Arguments:\n\n    Optional.\n    Coordinate metadata, relative to the current coordinate offset accumulated from `SHIFT_COORDS` instructions.\n    Can be any number of coordinates from 1 to 16.\n    There is no required convention for which coordinate is which.\n\nTargets:\n\n    The measurement records to XOR together to get the deterministic-under-noiseless-execution parity.\n\nExample:\n\n    R 0\n    X_ERROR(0.1) 0\n    M 0  # This measurement is always False under noiseless execution.\n    # Annotate that most recent measurement should be deterministic.\n    DETECTOR rec[-1]\n\n    R 0\n    X 0\n    X_ERROR(0.1) 0\n    M 0  # This measurement is always True under noiseless execution.\n    # Annotate that most recent measurement should be deterministic.\n    DETECTOR rec[-1]\n\n    R 0 1\n    H 0\n    CNOT 0 1\n    DEPOLARIZE2(0.001) 0 1\n    M 0 1  # These two measurements are always equal under noiseless execution.\n    # Annotate that the parity of the previous two measurements should be consistent.\n    DETECTOR rec[-1] rec[-2]\n\n    # A series of trivial detectors with hinted coordinates along the diagonal line Y = 2X + 3.\n    REPEAT 100 {\n        R 0\n        M 0\n        SHIFT_COORDS(1, 2)\n        DETECTOR(0, 3) rec[-1]\n    }\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"OBSERVABLE_INCLUDE\",\n            .id = GateType::OBSERVABLE_INCLUDE,\n            .best_candidate_inverse_id = GateType::OBSERVABLE_INCLUDE,\n            .arg_count = 1,\n            .flags = (GateFlags)(GATE_ONLY_TARGETS_MEASUREMENT_RECORD | GATE_TARGETS_PAULI_STRING |\n                                 GATE_IS_NOT_FUSABLE | GATE_ARGS_ARE_UNSIGNED_INTEGERS | GATE_HAS_NO_EFFECT_ON_QUBITS),\n            .category = \"Z_Annotations\",\n            .help = R\"MARKDOWN(\nAdds measurement records to a specified logical observable.\n\nA potential point of confusion here is that Stim's notion of a logical observable is nothing more than a set of\nmeasurements, potentially spanning across the entire circuit, that together produce a deterministic result. It's more\nakin to the \"boundary of a parity sheet\" in a topological spacetime diagram than it is to the notion of a qubit\nobservable. For example, consider a surface code memory experiment that initializes a logical |0>, preserves the state\nnoise, and eventually performs a logical Z basis measurement. The circuit representing this experiment would use\n`OBSERVABLE_INCLUDE` instructions to specifying which physical measurements within the logical Z basis measurement\nshould be XOR'd together to get the logical measurement result. This effectively identifies the logical Z observable.\nBut the circuit would *not* declare an X observable, because the X observable is not deterministic in a Z basis memory\nexperiment; it has no corresponding deterministic measurement set.\n\nLogical observables are ignored when sampling measurements, but can produce results (if requested) when sampling\ndetection events. In detector sampling mode, each observable can produce a result bit (where 0 means \"measurement set\nhad expected parity\" and 1 means \"measurement set had incorrect parity\"). When converting a circuit into a detector\nerror model, errors are grouped based on the detectors they flip (the \"symptoms\" of the error) and the observables they\nflip (the \"frame changes\" of the error).\n\nAnother potential point of confusion is that when sampling logical measurement results, as part of sampling detection\nevents in the circuit, the reported results are not measurements of the logical observable but rather whether those\nmeasurement results *were flipped*. This has significant simulation speed benefits, and also makes it so that it is not\nnecessary to say whether the logical measurement result is supposed to be False or True. Note that, for example, this\nmeans that even though `X` and `X_ERROR(1)` have equivalent effects on the measurements making up an observable, they\nhave differing effects on the reported value of an observable when sampling detection events (because `X` is intended,\ndetermining the expected value, and `X_ERROR` is noise, causing deviations from the expected value).\n\nIt is not recommended for the measurement set of an observable to have inconsistent parity. For example, the\ncircuit-to-detector-error-model conversion will refuse to operate on circuits containing such observables.\n\nIn addition to targeting measurements, observables can target Pauli operators. This has no effect when running the\nquantum computation, but is used when configuring the decoder. For example, when performing a logical Z initialization,\nit allows a logical X operator to be introduced (by marking its Pauli terms) despite the fact that it anticommutes\nwith the initialization. In practice, when physically sampling a circuit or simulating sampling its measurements and\nthen computing the observables from the measurements, these Pauli terms are effectively ignored. However, they affect\ndetection event simulations and affect whether the observable is included in errors in the detector error model. This\nmakes it easier to benchmark all observables of a code, without having to introduce noiseless qubits entangled with the\nlogical qubit to avoid the testing of the X observable anticommuting with the testing of the Z observable.\n\nUnlike a `DETECTOR` instruction which provides a complete description of a detector by listing all its constituent\nmeasurement records, an individual `OBSERVABLE_INCLUDE` instruction is not required to (and generally does not) fully\ndescribe a logical observable. Instead, measurement records or Pauli targets are added to it incrementally. A logical\nobservable can be given both types of description: as a collection of Pauli targets and as a collection of measurement\nrecord targets.\n\nParens Arguments:\n\n    A non-negative integer specifying the index of the logical observable to add the measurement records to.\n\nTargets:\n\n    The measurement records or Pauli terms to add to the specified observable.\n\nExample:\n\n    R 0 1\n    H 0\n    CNOT 0 1\n    M 0 1\n    # Observable 0 is the parity of the previous two measurements.\n    OBSERVABLE_INCLUDE(0) rec[-1] rec[-2]\n\n    R 0 1\n    H 0\n    CNOT 0 1\n    M 0 1\n    # Observable 1 is the parity of the previous measurement...\n    OBSERVABLE_INCLUDE(1) rec[-1]\n    # ...and the one before that.\n    OBSERVABLE_INCLUDE(1) rec[-2]\n\n    # Unphysically tracking two anticommuting observables of a 2x2 surface code.\n    QUBIT_COORDS(0, 0) 0\n    QUBIT_COORDS(1, 0) 1\n    QUBIT_COORDS(0, 1) 2\n    QUBIT_COORDS(1, 1) 3\n    OBSERVABLE_INCLUDE(0) X0 X1\n    OBSERVABLE_INCLUDE(1) Z0 Z2\n    MPP X0*X1*X2*X3 Z0*Z1 Z2*Z3\n    DEPOLARIZE1(0.001) 0 1 2 3\n    MPP X0*X1*X2*X3 Z0*Z1 Z2*Z3\n    DETECTOR rec[-1] rec[-4]\n    DETECTOR rec[-2] rec[-5]\n    DETECTOR rec[-3] rec[-6]\n    OBSERVABLE_INCLUDE(0) X0 X1\n    OBSERVABLE_INCLUDE(1) Z0 Z2\n\n    # Stim circuit may include a description of an observable in terms of Pauli targets\n    # alongside a description in terms of measurement records.\n    OBSERVABLE_INCLUDE(0) Z0 Z1\n    M 0 1\n    OBSERVABLE_INCLUDE(0) rec[-2] rec[-1]\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"TICK\",\n            .id = GateType::TICK,\n            .best_candidate_inverse_id = GateType::TICK,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_NOT_FUSABLE | GATE_TAKES_NO_TARGETS | GATE_HAS_NO_EFFECT_ON_QUBITS),\n            .category = \"Z_Annotations\",\n            .help = R\"MARKDOWN(\nAnnotates the end of a layer of gates, or that time is advancing.\n\nThis instruction is not necessary, it has no effect on simulations, but it can be used by tools that are transforming or\nvisualizing the circuit. For example, a tool that adds noise to a circuit may include cross-talk terms that require\nknowing whether or not operations are happening in the same time step or not.\n\nTICK instructions are added, and checked for, by `stimcirq` in order to preserve the moment structure of cirq circuits\nconverted between stim circuits and cirq circuits.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    This instruction takes no targets.\n\nExample:\n\n    # First time step.\n    H 0\n    CZ 1 2\n    TICK\n\n    # Second time step.\n    H 1\n    TICK\n\n    # Empty time step.\n    TICK\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"QUBIT_COORDS\",\n            .id = GateType::QUBIT_COORDS,\n            .best_candidate_inverse_id = GateType::QUBIT_COORDS,\n            .arg_count = ARG_COUNT_SYGIL_ANY,\n            .flags = (GateFlags)(GATE_IS_NOT_FUSABLE | GATE_HAS_NO_EFFECT_ON_QUBITS),\n            .category = \"Z_Annotations\",\n            .help = R\"MARKDOWN(\nAnnotates the location of a qubit.\n\nCoordinates are not required and have no effect on simulations, but can be useful to tools consuming the circuit. For\nexample, a tool drawing the circuit  can use the coordinates as hints for where to place the qubits in the drawing.\n`stimcirq` uses `QUBIT_COORDS` instructions to preserve `cirq.LineQubit` and `cirq.GridQubit` coordinates when\nconverting between stim circuits and cirq circuits\n\nA qubit's coordinates can be specified multiple times, with the intended interpretation being that the qubit is at the\nlocation of the most recent assignment. For example, this could be used to indicate a simulated qubit is iteratively\nplaying the role of many physical qubits.\n\nParens Arguments:\n\n    Optional.\n    The latest coordinates of the qubit, relative to accumulated offsets from `SHIFT_COORDS` instructions.\n    Can be any number of coordinates from 1 to 16.\n    There is no required convention for which coordinate is which.\n\nTargets:\n\n    The qubit or qubits the coordinates apply to.\n\nExample:\n\n    # Annotate that qubits 0 to 3 are at the corners of a square.\n    QUBIT_COORDS(0, 0) 0\n    QUBIT_COORDS(0, 1) 1\n    QUBIT_COORDS(1, 0) 2\n    QUBIT_COORDS(1, 1) 3\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SHIFT_COORDS\",\n            .id = GateType::SHIFT_COORDS,\n            .best_candidate_inverse_id = GateType::SHIFT_COORDS,\n            .arg_count = ARG_COUNT_SYGIL_ANY,\n            .flags = (GateFlags)(GATE_IS_NOT_FUSABLE | GATE_TAKES_NO_TARGETS | GATE_HAS_NO_EFFECT_ON_QUBITS),\n            .category = \"Z_Annotations\",\n            .help = R\"MARKDOWN(\nAccumulates offsets that affect qubit coordinates and detector coordinates.\n\nNote: when qubit/detector coordinates use fewer dimensions than SHIFT_COORDS, the offsets from the additional dimensions\nare ignored (i.e. not specifying a dimension is different from specifying it to be 0).\n\nSee also: `QUBIT_COORDS`, `DETECTOR`.\n\nParens Arguments:\n\n    Offsets to add into the current coordinate offset.\n    Can be any number of coordinate offsets from 1 to 16.\n    There is no required convention for which coordinate is which.\n\nTargets:\n\n    This instruction takes no targets.\n\nExample:\n\n    SHIFT_COORDS(500.5)\n    QUBIT_COORDS(1510) 0  # Actually at 2010.5\n    SHIFT_COORDS(1500)\n    QUBIT_COORDS(11) 1    # Actually at 2011.5\n    QUBIT_COORDS(10.5) 2  # Actually at 2011.0\n\n    # Declare some detectors with coordinates along a diagonal line.\n    REPEAT 1000 {\n        CNOT 0 2\n        CNOT 1 2\n        MR 2\n        DETECTOR(10.5, 0) rec[-1] rec[-2]  # Actually at (2011.0, iteration_count).\n        SHIFT_COORDS(0, 1)  # Advance 2nd coordinate to track loop iterations.\n    }\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MPAD\",\n            .id = GateType::MPAD,\n            .best_candidate_inverse_id = GateType::MPAD,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_PRODUCES_RESULTS | GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"Z_Annotations\",\n            .help = R\"MARKDOWN(\nPads the measurement record with the listed measurement results.\n\nThis can be useful for ensuring measurements are aligned to word boundaries, or that the\nnumber of measurement bits produced per circuit layer is always the same even if the number\nof measured qubits varies.\n\nParens Arguments:\n\n    If no parens argument is given, the padding bits are recorded perfectly.\n    If one parens argument is given, the padding bits are recorded noisily.\n    The argument is the probability of recording the wrong result.\n\nTargets:\n\n    Each target is a measurement result to add.\n    Targets should be the value 0 or the value 1.\n\nExamples:\n\n    # Append a False result to the measurement record.\n    MPAD 0\n\n    # Append a True result to the measurement record.\n    MPAD 1\n\n    # Append a series of results to the measurement record.\n    MPAD 0 0 1 0 1\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_blocks.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nvoid GateDataMap::add_gate_data_blocks(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"REPEAT\",\n            .id = GateType::REPEAT,\n            .best_candidate_inverse_id = GateType::REPEAT,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_BLOCK | GATE_IS_NOT_FUSABLE),\n            .category = \"Y_Control Flow\",\n            .help = R\"MARKDOWN(\nRepeats the instructions in its body N times.\n\nCurrently, repetition counts of 0 are not allowed because they create corner cases with ambiguous resolutions.\nFor example, if a logical observable is only given measurements inside a repeat block with a repetition count of 0, it's\nambiguous whether the output of sampling the logical observables includes a bit for that logical observable.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    A positive integer in [1, 10^18] specifying the number of repetitions.\n\nExample:\n\n    REPEAT 2 {\n        CNOT 0 1\n        CNOT 2 1\n        M 1\n    }\n    REPEAT 10000000 {\n        CNOT 0 1\n        CNOT 2 1\n        M 1\n        DETECTOR rec[-1] rec[-3]\n    }\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_collapsing.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nvoid GateDataMap::add_gate_data_collapsing(bool &failed) {\n    // ===================== Measure Gates. ============================\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MX\",\n            .id = GateType::MX,\n            .best_candidate_inverse_id = GateType::MX,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_PRODUCES_RESULTS | GATE_IS_NOISY |\n                                 GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"L_Collapsing Gates\",\n            .help = R\"MARKDOWN(\nX-basis measurement.\nProjects each target qubit into `|+>` or `|->` and reports its value (false=`|+>`, true=`|->`).\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The qubits to measure in the X basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the X basis, and append the result into the measurement record.\n    MX 5\n\n    # Measure qubit 5 in the X basis, and append the INVERSE of its result into the measurement record.\n    MX !5\n\n    # Do a noisy measurement where the result put into the measurement record is wrong 1% of the time.\n    MX(0.01) 5\n\n    # Measure multiple qubits in the X basis, putting 3 bits into the measurement record.\n    MX 2 3 5\n\n    # Perform multiple noisy measurements. Each measurement fails independently with 2% probability.\n    MX(0.02) 2 3 5\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {\"X -> rec[-1]\", \"X -> +X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nM 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MY\",\n            .id = GateType::MY,\n            .best_candidate_inverse_id = GateType::MY,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_PRODUCES_RESULTS | GATE_IS_NOISY |\n                                 GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"L_Collapsing Gates\",\n            .help = R\"MARKDOWN(\nY-basis measurement.\nProjects each target qubit into `|i>` or `|-i>` and reports its value (false=`|i>`, true=`|-i>`).\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The qubits to measure in the Y basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the Y basis, and append the result into the measurement record.\n    MY 5\n\n    # Measure qubit 5 in the Y basis, and append the INVERSE of its result into the measurement record.\n    MY !5\n\n    # Do a noisy measurement where the result put into the measurement record is wrong 1% of the time.\n    MY(0.01) 5\n\n    # Measure multiple qubits in the X basis, putting 3 bits into the measurement record.\n    MY 2 3 5\n\n    # Perform multiple noisy measurements. Each measurement fails independently with 2% probability.\n    MY(0.02) 2 3 5\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {\"Y -> rec[-1]\", \"Y -> +Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nH 0\nM 0\nH 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"M\",\n            .id = GateType::M,\n            .best_candidate_inverse_id = GateType::M,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_PRODUCES_RESULTS | GATE_IS_NOISY |\n                                 GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"L_Collapsing Gates\",\n            .help = R\"MARKDOWN(\nZ-basis measurement.\nProjects each target qubit into `|0>` or `|1>` and reports its value (false=`|0>`, true=`|1>`).\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The qubits to measure in the Z basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the Z basis, and append the result into the measurement record.\n    M 5\n\n    # 'MZ' is the same as 'M'. This also measures qubit 5 in the Z basis.\n    MZ 5\n\n    # Measure qubit 5 in the Z basis, and append the INVERSE of its result into the measurement record.\n    MZ !5\n\n    # Do a noisy measurement where the result put into the measurement record is wrong 1% of the time.\n    MZ(0.01) 5\n\n    # Measure multiple qubits in the Z basis, putting 3 bits into the measurement record.\n    MZ 2 3 5\n\n    # Perform multiple noisy measurements. Each measurement fails independently with 2% probability.\n    MZ(0.02) 2 3 5\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {\"Z -> rec[-1]\", \"Z -> +Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nM 0\n)CIRCUIT\",\n        });\n\n    add_gate_alias(failed, \"MZ\", \"M\");\n\n    // ===================== Measure+Reset Gates. ============================\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MRX\",\n            .id = GateType::MRX,\n            .best_candidate_inverse_id = GateType::MRX,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_PRODUCES_RESULTS | GATE_IS_NOISY |\n                                 GATE_ARGS_ARE_DISJOINT_PROBABILITIES | GATE_IS_RESET),\n            .category = \"L_Collapsing Gates\",\n            .help = R\"MARKDOWN(\nX-basis demolition measurement (optionally noisy).\nProjects each target qubit into `|+>` or `|->`, reports its value (false=`|+>`, true=`|->`), then resets to `|+>`.\n\nParens Arguments:\n\n    If no parens argument is given, the demolition measurement is perfect.\n    If one parens argument is given, the demolition measurement's result is noisy.\n    The argument is the probability of returning the wrong result.\n    The argument does not affect the fidelity of the reset.\n\nTargets:\n\n    The qubits to measure and reset in the X basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the X basis, reset it to the |+> state, append the measurement result into the measurement record.\n    MRX 5\n\n    # Demolition measure qubit 5 in the X basis, but append the INVERSE of its result into the measurement record.\n    MRX !5\n\n    # Do a noisy demolition measurement where the result put into the measurement record is wrong 1% of the time.\n    MRX(0.01) 5\n\n    # Demolition measure multiple qubits in the X basis, putting 3 bits into the measurement record.\n    MRX 2 3 5\n\n    # Perform multiple noisy demolition measurements. Each measurement result is flipped independently with 2% probability.\n    MRX(0.02) 2 3 5\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {\"X -> rec[-1]\", \"1 -> +X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nM 0\nR 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MRY\",\n            .id = GateType::MRY,\n            .best_candidate_inverse_id = GateType::MRY,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_PRODUCES_RESULTS | GATE_IS_NOISY |\n                                 GATE_ARGS_ARE_DISJOINT_PROBABILITIES | GATE_IS_RESET),\n            .category = \"L_Collapsing Gates\",\n            .help = R\"MARKDOWN(\nY-basis demolition measurement (optionally noisy).\nProjects each target qubit into `|i>` or `|-i>`, reports its value (false=`|i>`, true=`|-i>`), then resets to `|i>`.\n\nParens Arguments:\n\n    If no parens argument is given, the demolition measurement is perfect.\n    If one parens argument is given, the demolition measurement's result is noisy.\n    The argument is the probability of returning the wrong result.\n    The argument does not affect the fidelity of the reset.\n\nTargets:\n\n    The qubits to measure and reset in the Y basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the Y basis, reset it to the |i> state, append the measurement result into the measurement record.\n    MRY 5\n\n    # Demolition measure qubit 5 in the Y basis, but append the INVERSE of its result into the measurement record.\n    MRY !5\n\n    # Do a noisy demolition measurement where the result put into the measurement record is wrong 1% of the time.\n    MRY(0.01) 5\n\n    # Demolition measure multiple qubits in the Y basis, putting 3 bits into the measurement record.\n    MRY 2 3 5\n\n    # Perform multiple noisy demolition measurements. Each measurement result is flipped independently with 2% probability.\n    MRY(0.02) 2 3 5\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {\"Y -> rec[-1]\", \"1 -> +Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nH 0\nM 0\nR 0\nH 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MR\",\n            .id = GateType::MR,\n            .best_candidate_inverse_id = GateType::MR,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_PRODUCES_RESULTS | GATE_IS_NOISY |\n                                 GATE_ARGS_ARE_DISJOINT_PROBABILITIES | GATE_IS_RESET),\n            .category = \"L_Collapsing Gates\",\n            .help = R\"MARKDOWN(\nZ-basis demolition measurement (optionally noisy).\nProjects each target qubit into `|0>` or `|1>`, reports its value (false=`|0>`, true=`|1>`), then resets to `|0>`.\n\nParens Arguments:\n\n    If no parens argument is given, the demolition measurement is perfect.\n    If one parens argument is given, the demolition measurement's result is noisy.\n    The argument is the probability of returning the wrong result.\n    The argument does not affect the fidelity of the reset.\n\nTargets:\n\n    The qubits to measure and reset in the Z basis.\n    Prefixing a qubit target with `!` flips its reported measurement result.\n\nExamples:\n\n    # Measure qubit 5 in the Z basis, reset it to the |0> state, append the measurement result into the measurement record.\n    MRZ 5\n\n    # MR is also a Z-basis demolition measurement.\n    MR 5\n\n    # Demolition measure qubit 5 in the Z basis, but append the INVERSE of its result into the measurement record.\n    MRZ !5\n\n    # Do a noisy demolition measurement where the result put into the measurement record is wrong 1% of the time.\n    MRZ(0.01) 5\n\n    # Demolition measure multiple qubits in the Z basis, putting 3 bits into the measurement record.\n    MRZ 2 3 5\n\n    # Perform multiple noisy demolition measurements. Each measurement result is flipped independently with 2% probability.\n    MRZ(0.02) 2 3 5\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {\"Z -> rec[-1]\", \"1 -> +Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nM 0\nR 0\n)CIRCUIT\",\n        });\n\n    add_gate_alias(failed, \"MRZ\", \"MR\");\n\n    // ===================== Reset Gates. ============================\n    add_gate(\n        failed,\n        Gate{\n            .name = \"RX\",\n            .id = GateType::RX,\n            .best_candidate_inverse_id = GateType::MX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_RESET),\n            .category = \"L_Collapsing Gates\",\n            .help = R\"MARKDOWN(\nX-basis reset.\nForces each target qubit into the `|+>` state by silently measuring it in the X basis and applying a `Z` gate if it ended up in the `|->` state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    The qubits to reset in the X basis.\n\nExamples:\n\n    # Reset qubit 5 into the |+> state.\n    RX 5\n\n    # Reset multiple qubits into the |+> state.\n    RX 2 3 5\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {\"1 -> +X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nR 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"RY\",\n            .id = GateType::RY,\n            .best_candidate_inverse_id = GateType::MY,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_RESET),\n            .category = \"L_Collapsing Gates\",\n            .help = R\"MARKDOWN(\nY-basis reset.\nForces each target qubit into the `|i>` state by silently measuring it in the Y basis and applying an `X` gate if it ended up in the `|-i>` state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    The qubits to reset in the Y basis.\n\nExamples:\n\n    # Reset qubit 5 into the |i> state.\n    RY 5\n\n    # Reset multiple qubits into the |i> state.\n    RY 2 3 5\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {\"1 -> +Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nR 0\nH 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"R\",\n            .id = GateType::R,\n            .best_candidate_inverse_id = GateType::M,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_RESET),\n            .category = \"L_Collapsing Gates\",\n            .help = R\"MARKDOWN(\nZ-basis reset.\nForces each target qubit into the `|0>` state by silently measuring it in the Z basis and applying an `X` gate if it ended up in the `|1>` state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    The qubits to reset in the Z basis.\n\nExamples:\n\n    # Reset qubit 5 into the |0> state.\n    RZ 5\n\n    # R means the same thing as RZ.\n    R 5\n\n    # Reset multiple qubits into the |0> state.\n    RZ 2 3 5\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {\"1 -> +Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nR 0\n)CIRCUIT\",\n        });\n\n    add_gate_alias(failed, \"RZ\", \"R\");\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_controlled.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nstatic constexpr std::complex<float> i = std::complex<float>(0, 1);\n\nvoid GateDataMap::add_gate_data_controlled(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"XCX\",\n            .id = GateType::XCX,\n            .best_candidate_inverse_id = GateType::XCX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe X-controlled X gate.\nFirst qubit is the control, second qubit is the target.\n\nApplies an X gate to the target if the control is in the |-> state.\n\nNegates the amplitude of the |->|-> state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data =\n                {{0.5f, 0.5f, 0.5f, -0.5f},\n                 {0.5f, 0.5f, -0.5f, 0.5f},\n                 {0.5f, -0.5f, 0.5f, 0.5f},\n                 {-0.5f, 0.5f, 0.5f, 0.5f}},\n            .flow_data = {\"+XI\", \"+ZX\", \"+IX\", \"+XZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nCNOT 0 1\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"XCY\",\n            .id = GateType::XCY,\n            .best_candidate_inverse_id = GateType::XCY,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe X-controlled Y gate.\nFirst qubit is the control, second qubit is the target.\n\nApplies a Y gate to the target if the control is in the |-> state.\n\nNegates the amplitude of the |->|-i> state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data =\n                {{0.5f, 0.5f, -0.5f * i, 0.5f * i},\n                 {0.5f, 0.5f, 0.5f * i, -0.5f * i},\n                 {0.5f * i, -0.5f * i, 0.5f, 0.5f},\n                 {-0.5f * i, 0.5f * i, 0.5f, 0.5f}},\n            .flow_data = {\"+XI\", \"+ZY\", \"+XX\", \"+XZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nS 1\nS 1\nS 1\nCNOT 0 1\nH 0\nS 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"XCZ\",\n            .id = GateType::XCZ,\n            .best_candidate_inverse_id = GateType::XCZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS | GATE_CAN_TARGET_BITS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe X-controlled Z gate.\nApplies a Z gate to the target if the control is in the |-> state.\nEquivalently: negates the amplitude of the |->|1> state.\nSame as a CX gate, but with reversed qubit order.\nThe first qubit is the control, and the second qubit is the target.\n\nTo perform a classically controlled X, replace the Z target with a `rec`\ntarget like rec[-2].\n\nTo perform an I or X gate as configured by sweep data, replace the\nZ target with a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Bit flip qubit 5 controlled by qubit 2.\n    XCZ 5 2\n\n    # Perform CX 2 5 then CX 4 2.\n    XCZ 5 2 2 4\n\n    # Bit flip qubit 6 if the most recent measurement result was TRUE.\n    XCZ 6 rec[-1]\n\n    # Bit flip qubits 7 and 8 conditioned on sweep configuration data.\n    XCZ 7 sweep[5] 8 sweep[5]\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}},\n            .flow_data = {\"+XI\", \"+ZZ\", \"+XX\", \"+IZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nCNOT 1 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"YCX\",\n            .id = GateType::YCX,\n            .best_candidate_inverse_id = GateType::YCX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe Y-controlled X gate.\nFirst qubit is the control, second qubit is the target.\n\nApplies an X gate to the target if the control is in the |-i> state.\n\nNegates the amplitude of the |-i>|-> state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data =\n                {{0.5f, -i * 0.5f, 0.5f, i * 0.5f},\n                 {i * 0.5f, 0.5f, -i * 0.5f, 0.5f},\n                 {0.5f, i * 0.5f, 0.5f, -i * 0.5f},\n                 {-i * 0.5f, 0.5f, i * 0.5f, 0.5f}},\n            .flow_data = {\"+XX\", \"+ZX\", \"+IX\", \"+YZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nH 1\nCNOT 1 0\nS 0\nH 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"YCY\",\n            .id = GateType::YCY,\n            .best_candidate_inverse_id = GateType::YCY,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe Y-controlled Y gate.\nFirst qubit is the control, second qubit is the target.\n\nApplies a Y gate to the target if the control is in the |-i> state.\n\nNegates the amplitude of the |-i>|-i> state.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data =\n                {{0.5f, -i * 0.5f, -i * 0.5f, 0.5f},\n                 {i * 0.5f, 0.5f, -0.5f, -i * 0.5f},\n                 {i * 0.5f, -0.5f, 0.5f, -i * 0.5f},\n                 {0.5f, i * 0.5f, i * 0.5f, 0.5f}},\n            .flow_data = {\"+XY\", \"+ZY\", \"+YX\", \"+YZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nS 1\nS 1\nS 1\nH 0\nCNOT 0 1\nH 0\nS 0\nS 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"YCZ\",\n            .id = GateType::YCZ,\n            .best_candidate_inverse_id = GateType::YCZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS | GATE_CAN_TARGET_BITS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe Y-controlled Z gate.\nApplies a Z gate to the target if the control is in the |-i> state.\nEquivalently: negates the amplitude of the |-i>|1> state.\nSame as a CY gate, but with reversed qubit order.\nThe first qubit is called the control, and the second qubit is the target.\n\nTo perform a classically controlled Y, replace the Z target with a `rec`\ntarget like rec[-2].\n\nTo perform an I or Y gate as configured by sweep data, replace the\nZ target with a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Apply Y to qubit 5 controlled by qubit 2.\n    YCZ 5 2\n\n    # Perform CY 2 5 then CY 4 2.\n    YCZ 5 2 2 4\n\n    # Apply Y to qubit 6 if the most recent measurement result was TRUE.\n    YCZ 6 rec[-1]\n\n    # Apply Y to qubits 7 and 8 conditioned on sweep configuration data.\n    YCZ 7 sweep[5] 8 sweep[5]\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 0, -i}, {0, 0, i, 0}},\n            .flow_data = {\"+XZ\", \"+ZZ\", \"+YX\", \"+IZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nCNOT 1 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"CX\",\n            .id = GateType::CX,\n            .best_candidate_inverse_id = GateType::CX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS | GATE_CAN_TARGET_BITS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe Z-controlled X gate.\nApplies an X gate to the target if the control is in the |1> state.\nEquivalently: negates the amplitude of the |1>|-> state.\nThe first qubit is called the control, and the second qubit is the target.\n\nTo perform a classically controlled X, replace the control with a `rec`\ntarget like rec[-2].\n\nTo perform an I or X gate as configured by sweep data, replace the\ncontrol with a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Bit flip qubit 5 controlled by qubit 2.\n    CX 2 5\n\n    # Perform CX 2 5 then CX 4 2.\n    CX 2 5 4 2\n\n    # Bit flip qubit 6 if the most recent measurement result was TRUE.\n    CX rec[-1] 6\n\n    # Bit flip qubits 7 and 8 conditioned on sweep configuration data.\n    CX sweep[5] 7 sweep[5] 8\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 1, 0, 0}},\n            .flow_data = {\"+XX\", \"+ZI\", \"+IX\", \"+ZZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nCNOT 0 1\n)CIRCUIT\",\n        });\n\n    add_gate_alias(failed, \"ZCX\", \"CX\");\n    add_gate_alias(failed, \"CNOT\", \"CX\");\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"CY\",\n            .id = GateType::CY,\n            .best_candidate_inverse_id = GateType::CY,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS | GATE_CAN_TARGET_BITS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe Z-controlled Y gate.\nApplies a Y gate to the target if the control is in the |1> state.\nEquivalently: negates the amplitude of the |1>|-i> state.\nThe first qubit is the control, and the second qubit is the target.\n\nTo perform a classically controlled Y, replace the control with a `rec`\ntarget like rec[-2].\n\nTo perform an I or Y gate as configured by sweep data, replace the\ncontrol with a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Apply Y to qubit 5 controlled by qubit 2.\n    CY 2 5\n\n    # Perform CY 2 5 then CY 4 2.\n    CY 2 5 4 2\n\n    # Apply Y to qubit 6 if the most recent measurement result was TRUE.\n    CY rec[-1] 6\n\n    # Apply Y to qubits 7 and 8 conditioned on sweep configuration data.\n    CY sweep[5] 7 sweep[5] 8\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 0, 0, -i}, {0, 0, 1, 0}, {0, i, 0, 0}},\n            .flow_data = {\"+XY\", \"+ZI\", \"+ZX\", \"+ZZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 1\nS 1\nS 1\nCNOT 0 1\nS 1\n)CIRCUIT\",\n        });\n\n    add_gate_alias(failed, \"ZCY\", \"CY\");\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"CZ\",\n            .id = GateType::CZ,\n            .best_candidate_inverse_id = GateType::CZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS | GATE_CAN_TARGET_BITS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe Z-controlled Z gate.\nApplies a Z gate to the target if the control is in the |1> state.\nEquivalently: negates the amplitude of the |1>|1> state.\nThe first qubit is called the control, and the second qubit is the target.\n\nTo perform a classically controlled Z, replace either qubit with a `rec`\ntarget like rec[-2].\n\nTo perform an I or Z gate as configured by sweep data, replace either qubit\nwith a `sweep` target like sweep[3].\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExample:\n\n    # Apply Z to qubit 5 controlled by qubit 2.\n    CZ 2 5\n\n    # Perform CZ 2 5 then CZ 4 2.\n    CZ 2 5 4 2\n\n    # Apply Z to qubit 6 if the most recent measurement result was TRUE.\n    CZ rec[-1] 6\n\n    # Apply Z to qubit 7 if the 3rd most recent measurement result was TRUE.\n    CZ 7 rec[-3]\n\n    # Apply Z to qubits 7 and 8 conditioned on sweep configuration data.\n    CZ sweep[5] 7 8 sweep[5]\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, -1}},\n            .flow_data = {\"+XZ\", \"+ZI\", \"+ZX\", \"+IZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 1\nCNOT 0 1\nH 1\n)CIRCUIT\",\n        });\n\n    add_gate_alias(failed, \"ZCZ\", \"CZ\");\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_hada.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nstatic constexpr std::complex<float> i = std::complex<float>(0, 1);\nstatic constexpr std::complex<float> s = 0.7071067811865475244f;\n\nvoid GateDataMap::add_gate_data_hada(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"H\",\n            .id = GateType::H,\n            .best_candidate_inverse_id = GateType::H,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nThe Hadamard gate.\nSwaps the X and Z axes.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{s, s}, {s, -s}},\n            .flow_data = {\"+Z\", \"+X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate_alias(failed, \"H_XZ\", \"H\");\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"H_XY\",\n            .id = GateType::H_XY,\n            .best_candidate_inverse_id = GateType::H_XY,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nA variant of the Hadamard gate that swaps the X and Y axes (instead of X and Z).\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0, s - i * s}, {s + i * s, 0}},\n            .flow_data = {\"+Y\", \"-Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nS 0\nS 0\nH 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"H_YZ\",\n            .id = GateType::H_YZ,\n            .best_candidate_inverse_id = GateType::H_YZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nA variant of the Hadamard gate that swaps the Y and Z axes (instead of X and Z).\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{s, -i * s}, {i * s, -s}},\n            .flow_data = {\"-X\", \"+Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nS 0\nH 0\nS 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"H_NXY\",\n            .id = GateType::H_NXY,\n            .best_candidate_inverse_id = GateType::H_NXY,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nA variant of the Hadamard gate that swaps the -X and +Y axes.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0, s + s * i}, {s - s * i, 0}},\n            .flow_data = {\"-Y\", \"-Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nH 0\nS 0\nS 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"H_NXZ\",\n            .id = GateType::H_NXZ,\n            .best_candidate_inverse_id = GateType::H_NXZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nA variant of the Hadamard gate that swaps the -X and +Z axes.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{-s, s}, {s, s}},\n            .flow_data = {\"-Z\", \"-X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nH 0\nS 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"H_NYZ\",\n            .id = GateType::H_NYZ,\n            .best_candidate_inverse_id = GateType::H_NYZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nA variant of the Hadamard gate that swaps the -Y and +Z axes.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{-s, -i * s}, {i * s, s}},\n            .flow_data = {\"-X\", \"-Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nH 0\nS 0\nH 0\n)CIRCUIT\",\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_heralded.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nvoid GateDataMap::add_gate_data_heralded(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"HERALDED_ERASE\",\n            .id = GateType::HERALDED_ERASE,\n            .best_candidate_inverse_id = GateType::HERALDED_ERASE,\n            .arg_count = 1,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES |\n                                 GATE_PRODUCES_RESULTS),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nThe heralded erasure noise channel.\n\nWhether or not this noise channel fires is recorded into the measurement\nrecord. When it doesn't fire, nothing happens to the target qubit and a\n0 is recorded. When it does fire, a 1 is recorded and the target qubit\nis erased to the maximally mixed state by applying X_ERROR(0.5) and\nZ_ERROR(0.5).\n\nCAUTION: when converting a circuit with this error into a detector\nerror model, this channel is split into multiple potential effects.\nIn the context of a DEM, these effects are considered independent.\nThis is an approximation, because independent effects can be combined.\nThe effect of this approximation, assuming a detector is declared\non the herald, is that it appears this detector can be cancelled out\nby two of the (originally disjoint) heralded effects firing together.\nSampling from the DEM instead of the circuit can thus produce unheralded\nerrors, even if the circuit noise model only contains heralded errors.\nThese issues occur with probability p^2, where p is the probability of a\nheralded error, since two effects that came from the same heralded error\nmust occur together to cancel out the herald detector. This also means\na decoder configured using the DEM will think there's a chance of unheralded\nerrors even if the circuit the DEM came from only uses heralded errors.\n\nParens Arguments:\n\n    A single float (p) specifying the chance of the noise firing.\n\nTargets:\n\n    Qubits to apply single-qubit depolarizing noise to. Each target\n    is operated on independently.\n\nPauli Mixture:\n\n    1-p: record 0, apply I\n    p/4: record 1, apply I\n    p/4: record 1, apply X\n    p/4: record 1, apply Y\n    p/4: record 1, apply Z\n\nExamples:\n\n    # Erase qubit 0 with probability 1%\n    HERALDED_ERASE(0.01) 0\n    # Declare a flag detector based on the erasure\n    DETECTOR rec[-1]\n\n    # Erase qubit 2 with 2% probability\n    # Separately, erase qubit 3 with 2% probability\n    HERALDED_ERASE(0.02) 2 3\n\n    # Do an XXXX measurement\n    MPP X2*X3*X5*X7\n    # Apply partially-heralded noise to the two qubits\n    HERALDED_ERASE(0.01) 2 3 5 7\n    DEPOLARIZE1(0.0001) 2 3 5 7\n    # Repeat the XXXX measurement\n    MPP X2*X3*X5*X7\n    # Declare a detector comparing the two XXXX measurements\n    DETECTOR rec[-1] rec[-6]\n    # Declare flag detectors based on the erasures\n    DETECTOR rec[-2]\n    DETECTOR rec[-3]\n    DETECTOR rec[-4]\n    DETECTOR rec[-5]\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"HERALDED_PAULI_CHANNEL_1\",\n            .id = GateType::HERALDED_PAULI_CHANNEL_1,\n            .best_candidate_inverse_id = GateType::HERALDED_PAULI_CHANNEL_1,\n            .arg_count = 4,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES |\n                                 GATE_PRODUCES_RESULTS),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nA heralded error channel that applies biased noise.\n\nThis error records a bit into the measurement record, indicating whether\nor not the herald fired. How likely it is that the herald fires, and the\ncorresponding chance of each possible error effect (I, X, Y, or Z) are\nconfigured by the parens arguments of the instruction.\n\nCAUTION: when converting a circuit with this error into a detector\nerror model, this channel is split into multiple potential effects.\nIn the context of a DEM, these effects are considered independent.\nThis is an approximation, because independent effects can be combined.\nThe effect of this approximation, assuming a detector is declared\non the herald, is that it appears this detector can be cancelled out\nby two of the (originally disjoint) heralded effects firing together.\nSampling from the DEM instead of the circuit can thus produce unheralded\nerrors, even if the circuit noise model only contains heralded errors.\nThese issues occur with probability p^2, where p is the probability of a\nheralded error, since two effects that came from the same heralded error\nmust occur together to cancel out the herald detector. This also means\na decoder configured using the DEM will think there's a chance of unheralded\nerrors even if the circuit the DEM came from only uses heralded errors.\n\nParens Arguments:\n\n    This instruction takes four arguments (pi, px, py, pz). The\n    arguments are disjoint probabilities, specifying the chances\n    of heralding with various effects.\n\n    pi is the chance of heralding with no effect (a false positive).\n    px is the chance of heralding with an X error.\n    py is the chance of heralding with a Y error.\n    pz is the chance of heralding with a Z error.\n\nTargets:\n\n    Qubits to apply heralded biased noise to.\n\nPauli Mixture:\n\n    1-pi-px-py-pz: record 0, apply I\n               pi: record 1, apply I\n               px: record 1, apply X\n               py: record 1, apply Y\n               pz: record 1, apply Z\n\nExamples:\n\n    # With 10% probability perform a phase flip of qubit 0.\n    HERALDED_PAULI_CHANNEL_1(0, 0, 0, 0.1) 0\n    DETECTOR rec[-1]  # Include the herald in detectors available to the decoder\n\n    # With 20% probability perform a heralded dephasing of qubit 0.\n    HERALDED_PAULI_CHANNEL_1(0.1, 0, 0, 0.1) 0\n    DETECTOR rec[-1]\n\n    # Subject a Bell Pair to heralded noise.\n    MXX 0 1\n    MZZ 0 1\n    HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.04) 0 1\n    MXX 0 1\n    MZZ 0 1\n    DETECTOR rec[-1] rec[-5]  # Did ZZ stabilizer change?\n    DETECTOR rec[-2] rec[-6]  # Did XX stabilizer change?\n    DETECTOR rec[-3]    # Did the herald on qubit 1 fire?\n    DETECTOR rec[-4]    # Did the herald on qubit 0 fire?\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_noisy.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nvoid GateDataMap::add_gate_data_noisy(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"DEPOLARIZE1\",\n            .id = GateType::DEPOLARIZE1,\n            .best_candidate_inverse_id = GateType::DEPOLARIZE1,\n            .arg_count = 1,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nThe single qubit depolarizing channel.\n\nApplies a single-qubit depolarizing error with the given probability.\nWhen a single-qubit depolarizing error is applied, a random Pauli\nerror (except for I) is chosen and applied. Note that this means\nmaximal mixing occurs when the probability parameter is set to 75%,\nrather than at 100%.\n\nApplies a randomly chosen Pauli with a given probability.\n\nParens Arguments:\n\n    A single float (p) specifying the depolarization strength.\n\nTargets:\n\n    Qubits to apply single-qubit depolarizing noise to.\n\nPauli Mixture:\n\n    1-p: I\n    p/3: X\n    p/3: Y\n    p/3: Z\n\nExamples:\n\n    # Apply 1-qubit depolarization to qubit 0 using p=1%\n    DEPOLARIZE1(0.01) 0\n\n    # Apply 1-qubit depolarization to qubit 2\n    # Separately apply 1-qubit depolarization to qubits 3 and 5\n    DEPOLARIZE1(0.01) 2 3 5\n\n    # Maximally mix qubits 0 through 2\n    DEPOLARIZE1(0.75) 0 1 2\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"DEPOLARIZE2\",\n            .id = GateType::DEPOLARIZE2,\n            .best_candidate_inverse_id = GateType::DEPOLARIZE2,\n            .arg_count = 1,\n            .flags = (GateFlags)(GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES | GATE_TARGETS_PAIRS),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nThe two qubit depolarizing channel.\n\nApplies a two-qubit depolarizing error with the given probability.\nWhen a two-qubit depolarizing error is applied, a random pair of Pauli\nerrors (except for II) is chosen and applied. Note that this means\nmaximal mixing occurs when the probability parameter is set to 93.75%,\nrather than at 100%.\n\nParens Arguments:\n\n    A single float (p) specifying the depolarization strength.\n\nTargets:\n\n    Qubit pairs to apply two-qubit depolarizing noise to.\n\nPauli Mixture:\n\n     1-p: II\n    p/15: IX\n    p/15: IY\n    p/15: IZ\n    p/15: XI\n    p/15: XX\n    p/15: XY\n    p/15: XZ\n    p/15: YI\n    p/15: YX\n    p/15: YY\n    p/15: YZ\n    p/15: ZI\n    p/15: ZX\n    p/15: ZY\n    p/15: ZZ\n\nExamples:\n\n    # Apply 2-qubit depolarization to qubit 0 and qubit 1 using p=1%\n    DEPOLARIZE2(0.01) 0 1\n\n    # Apply 2-qubit depolarization to qubit 2 and qubit 3\n    # Separately apply 2-qubit depolarization to qubit 5 and qubit 7\n    DEPOLARIZE2(0.01) 2 3 5 7\n\n    # Maximally mix qubits 0 through 3\n    DEPOLARIZE2(0.9375) 0 1 2 3\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"I_ERROR\",\n            .id = GateType::I_ERROR,\n            .best_candidate_inverse_id = GateType::I_ERROR,\n            .arg_count = ARG_COUNT_SYGIL_ANY,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nApplies an identity with a given probability.\n\nThis gate has no effect. It only exists because it can be useful as a\ncommunication mechanism for systems built on top of stim.\n\nParens Arguments:\n\n    A list of disjoint probabilities summing to at most 1.\n\n    The probabilities have no effect on stim simulations or error analysis, but may be\n    interpreted in arbitrary ways by external tools.\n\nTargets:\n\n    Qubits to apply identity noise to.\n\nPauli Mixture:\n\n     *: I\n\nExamples:\n\n    # does nothing\n    I_ERROR 0\n\n    # does nothing with probability 0.1, else does nothing\n    I_ERROR(0.1) 0\n\n    # doesn't require a probability argument\n    I_ERROR[LEAKAGE_NOISE_FOR_AN_ADVANCED_SIMULATOR:0.1] 0 2 4\n\n    # checks for you that the disjoint probabilities in the arguments are legal\n    I_ERROR[MULTIPLE_NOISE_MECHANISMS](0.1, 0.2) 0 2 4\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"II_ERROR\",\n            .id = GateType::II_ERROR,\n            .best_candidate_inverse_id = GateType::II_ERROR,\n            .arg_count = ARG_COUNT_SYGIL_ANY,\n            .flags = (GateFlags)(GATE_TARGETS_PAIRS | GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nApplies a two-qubit identity with a given probability.\n\nThis gate has no effect. It only exists because it can be useful as a\ncommunication mechanism for systems built on top of stim.\n\nParens Arguments:\n\n    A list of disjoint probabilities summing to at most 1.\n\n    The probabilities have no effect on stim simulations or error analysis, but may be\n    interpreted in arbitrary ways by external tools.\n\nTargets:\n\n    Qubits to apply identity noise to.\n\nPauli Mixture:\n\n    *: II\n\nExamples:\n\n    # does nothing\n    II_ERROR 0 1\n\n    # does nothing with probability 0.1, else does nothing\n    II_ERROR(0.1) 0 1\n\n    # checks for you that the targets are two-qubit pairs\n    II_ERROR[TWO_QUBIT_LEAKAGE_NOISE_FOR_AN_ADVANCED_SIMULATOR:0.1] 0 2 4 6\n\n    # checks for you that the disjoint probabilities in the arguments are legal\n    II_ERROR[MULTIPLE_TWO_QUBIT_NOISE_MECHANISMS](0.1, 0.2) 0 2 4 6\n\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"X_ERROR\",\n            .id = GateType::X_ERROR,\n            .best_candidate_inverse_id = GateType::X_ERROR,\n            .arg_count = 1,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nApplies a Pauli X with a given probability.\n\nParens Arguments:\n\n    A single float specifying the probability of applying an X operation.\n\nTargets:\n\n    Qubits to apply bit flip noise to.\n\nPauli Mixture:\n\n    1-p: I\n     p : X\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"Y_ERROR\",\n            .id = GateType::Y_ERROR,\n            .best_candidate_inverse_id = GateType::Y_ERROR,\n            .arg_count = 1,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nApplies a Pauli Y with a given probability.\n\nParens Arguments:\n\n    A single float specifying the probability of applying a Y operation.\n\nTargets:\n\n    Qubits to apply Y flip noise to.\n\nPauli Mixture:\n\n    1-p: I\n     p : Y\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"Z_ERROR\",\n            .id = GateType::Z_ERROR,\n            .best_candidate_inverse_id = GateType::Z_ERROR,\n            .arg_count = 1,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nApplies a Pauli Z with a given probability.\n\nParens Arguments:\n\n    A single float specifying the probability of applying a Z operation.\n\nTargets:\n\n    Qubits to apply phase flip noise to.\n\nPauli Mixture:\n\n    1-p: I\n     p : Z\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"PAULI_CHANNEL_1\",\n            .id = GateType::PAULI_CHANNEL_1,\n            .best_candidate_inverse_id = GateType::PAULI_CHANNEL_1,\n            .arg_count = 3,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nA single qubit Pauli error channel with explicitly specified probabilities for each case.\n\nParens Arguments:\n\n    Three floats specifying disjoint Pauli case probabilities.\n    px: Disjoint probability of applying an X error.\n    py: Disjoint probability of applying a Y error.\n    pz: Disjoint probability of applying a Z error.\n\nTargets:\n\n    Qubits to apply the custom noise channel to.\n\nExample:\n\n    # Sample errors from the distribution 10% X, 15% Y, 20% Z, 55% I.\n    # Apply independently to qubits 1, 2, 4.\n    PAULI_CHANNEL_1(0.1, 0.15, 0.2) 1 2 4\n\nPauli Mixture:\n\n    1-px-py-pz: I\n    px: X\n    py: Y\n    pz: Z\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"PAULI_CHANNEL_2\",\n            .id = GateType::PAULI_CHANNEL_2,\n            .best_candidate_inverse_id = GateType::PAULI_CHANNEL_2,\n            .arg_count = 15,\n            .flags = (GateFlags)(GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES | GATE_TARGETS_PAIRS),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nA two qubit Pauli error channel with explicitly specified probabilities for each case.\n\nParens Arguments:\n\n    Fifteen floats specifying the disjoint probabilities of each possible Pauli pair\n    that can occur (except for the non-error double identity case).\n    The disjoint probability arguments are (in order):\n\n    1. pix: Probability of applying an IX operation.\n    2. piy: Probability of applying an IY operation.\n    3. piz: Probability of applying an IZ operation.\n    4. pxi: Probability of applying an XI operation.\n    5. pxx: Probability of applying an XX operation.\n    6. pxy: Probability of applying an XY operation.\n    7. pxz: Probability of applying an XZ operation.\n    8. pyi: Probability of applying a YI operation.\n    9. pyx: Probability of applying a YX operation.\n    10. pyy: Probability of applying a YY operation.\n    11. pyz: Probability of applying a YZ operation.\n    12. pzi: Probability of applying a ZI operation.\n    13. pzx: Probability of applying a ZX operation.\n    14. pzy: Probability of applying a ZY operation.\n    15. pzz: Probability of applying a ZZ operation.\n\nTargets:\n\n    Pairs of qubits to apply the custom noise channel to.\n    There must be an even number of targets.\n\nExample:\n\n    # Sample errors from the distribution 10% XX, 20% YZ, 70% II.\n    # Apply independently to qubit pairs (1,2), (5,6), and (8,3)\n    PAULI_CHANNEL_2(0,0,0, 0,0.1,0,0, 0,0,0,0.2, 0,0,0,0) 1 2 5 6 8 3\n\nPauli Mixture:\n\n    1-pix-piy-piz-pxi-pxx-pxy-pxz-pyi-pyx-pyy-pyz-pzi-pzx-pzy-pzz: II\n    pix: IX\n    piy: IY\n    piz: IZ\n    pxi: XI\n    pxx: XX\n    pxy: XY\n    pxz: XZ\n    pyi: YI\n    pyx: YX\n    pyy: YY\n    pyz: YZ\n    pzi: ZI\n    pzx: ZX\n    pzy: ZY\n    pzz: ZZ\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"E\",\n            .id = GateType::E,\n            .best_candidate_inverse_id = GateType::E,\n            .arg_count = 1,\n            .flags = (GateFlags)(GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES | GATE_TARGETS_PAULI_STRING |\n                                 GATE_IS_NOT_FUSABLE),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nProbabilistically applies a Pauli product error with a given probability.\nSets the \"correlated error occurred flag\" to true if the error occurred.\nOtherwise sets the flag to false.\n\nSee also: `ELSE_CORRELATED_ERROR`.\n\nParens Arguments:\n\n    A single float specifying the probability of applying the Paulis making up the error.\n\nTargets:\n\n    Pauli targets specifying the Paulis to apply when the error occurs.\n    Note that, for backwards compatibility reasons, the targets are not combined using combiners (`*`).\n    They are implicitly all combined.\n\nExample:\n\n    # With 60% probability, uniformly pick X1*Y2 or Z2*Z3 or X1*Y2*Z3.\n    CORRELATED_ERROR(0.2) X1 Y2\n    ELSE_CORRELATED_ERROR(0.25) Z2 Z3\n    ELSE_CORRELATED_ERROR(0.33333333333) X1 Y2 Z3\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n    add_gate_alias(failed, \"CORRELATED_ERROR\", \"E\");\n    add_gate(\n        failed,\n        Gate{\n            .name = \"ELSE_CORRELATED_ERROR\",\n            .id = GateType::ELSE_CORRELATED_ERROR,\n            .best_candidate_inverse_id = GateType::ELSE_CORRELATED_ERROR,\n            .arg_count = 1,\n            .flags = (GateFlags)(GATE_IS_NOISY | GATE_ARGS_ARE_DISJOINT_PROBABILITIES | GATE_TARGETS_PAULI_STRING |\n                                 GATE_IS_NOT_FUSABLE),\n            .category = \"F_Noise Channels\",\n            .help = R\"MARKDOWN(\nProbabilistically applies a Pauli product error with a given probability, unless the \"correlated error occurred flag\" is set.\nIf the error occurs, sets the \"correlated error occurred flag\" to true.\nOtherwise leaves the flag alone.\n\nNote: when converting a circuit into a detector error model, every `ELSE_CORRELATED_ERROR` instruction must be preceded by\nan ELSE_CORRELATED_ERROR instruction or an E instruction. In other words, ELSE_CORRELATED_ERROR instructions should appear\nin contiguous chunks started by a CORRELATED_ERROR.\n\nSee also: `CORRELATED_ERROR`.\n\nParens Arguments:\n\n    A single float specifying the probability of applying the Paulis making up the error, conditioned on the \"correlated\n    error occurred flag\" being False.\n\nTargets:\n\n    Pauli targets specifying the Paulis to apply when the error occurs.\n    Note that, for backwards compatibility reasons, the targets are not combined using combiners (`*`).\n    They are implicitly all combined.\n\nExample:\n\n    # With 60% probability, uniformly pick X1*Y2 or Z2*Z3 or X1*Y2*Z3.\n    CORRELATED_ERROR(0.2) X1 Y2\n    ELSE_CORRELATED_ERROR(0.25) Z2 Z3\n    ELSE_CORRELATED_ERROR(0.33333333333) X1 Y2 Z3\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data = {},\n            .h_s_cx_m_r_decomposition = nullptr,\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_pair_measure.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nvoid GateDataMap::add_gate_data_pair_measure(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MXX\",\n            .id = GateType::MXX,\n            .best_candidate_inverse_id = GateType::MXX,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_TARGETS_PAIRS | GATE_PRODUCES_RESULTS | GATE_IS_NOISY |\n                                 GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"L_Pair Measurement Gates\",\n            .help = R\"MARKDOWN(\nTwo-qubit X basis parity measurement.\n\nThis operation measures whether pairs of qubits are in the {|++>,|-->} subspace or in the\n{|+->,|-+>} subspace of the two qubit state space. |+> and |-> are the +1 and -1\neigenvectors of the X operator.\n\nIf the qubits were in the {|++>,|-->} subspace, False is appended to the measurement record.\nIf the qubits were in the {|+->,|-+>} subspace, True is appended to the measurement record.\nInverting one of the qubit targets inverts the result.\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The pairs of qubits to measure in the X basis.\n\n    This operation accepts inverted qubit targets (like `!5` instead of `5`). Inverted\n    targets flip the measurement result.\n\nExamples:\n\n    # Measure the +XX observable of qubit 1 vs qubit 2.\n    MXX 1 2\n\n    # Measure the -XX observable of qubit 1 vs qubit 2.\n    MXX !1 2\n\n    # Do a noisy measurement of the +XX observable of qubit 2 vs qubit 3.\n    # The result recorded to the measurement record will be flipped 1% of the time.\n    MXX(0.01) 2 3\n\n    # Measure the +XX observable qubit 1 vs qubit 2, and also qubit 8 vs qubit 9\n    MXX 1 2 8 9\n\n    # Perform multiple noisy measurements.\n    # Each measurement has an independent 2% chance of being recorded wrong.\n    MXX(0.02) 2 3 5 7 11 19 17 4\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data =\n                {\n                    \"X_ -> +X_\",\n                    \"_X -> +_X\",\n                    \"ZZ -> +ZZ\",\n                    \"XX -> rec[-1]\",\n                },\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nCX 0 1\nH 0\nM 0\nH 0\nCX 0 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MYY\",\n            .id = GateType::MYY,\n            .best_candidate_inverse_id = GateType::MYY,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_TARGETS_PAIRS | GATE_PRODUCES_RESULTS | GATE_IS_NOISY |\n                                 GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"L_Pair Measurement Gates\",\n            .help = R\"MARKDOWN(\nTwo-qubit Y basis parity measurement.\n\nThis operation measures whether pairs of qubits are in the {|ii>,|jj>} subspace or in the\n{|ij>,|ji>} subspace of the two qubit state space. |i> and |j> are the +1 and -1\neigenvectors of the Y operator.\n\nIf the qubits were in the {|ii>,|jj>} subspace, False is appended to the measurement record.\nIf the qubits were in the {|ij>,|ji>} subspace, True is appended to the measurement record.\nInverting one of the qubit targets inverts the result.\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The pairs of qubits to measure in the Y basis.\n\n    This operation accepts inverted qubit targets (like `!5` instead of `5`). Inverted\n    targets flip the measurement result.\n\nExamples:\n\n    # Measure the +YY observable of qubit 1 vs qubit 2.\n    MYY 1 2\n\n    # Measure the -YY observable of qubit 1 vs qubit 2.\n    MYY !1 2\n\n    # Do a noisy measurement of the +YY observable of qubit 2 vs qubit 3.\n    # The result recorded to the measurement record will be flipped 1% of the time.\n    MYY(0.01) 2 3\n\n    # Measure the +YY observable qubit 1 vs qubit 2, and also qubit 8 vs qubit 9\n    MYY 1 2 8 9\n\n    # Perform multiple noisy measurements.\n    # Each measurement has an independent 2% chance of being recorded wrong.\n    MYY(0.02) 2 3 5 7 11 19 17 4\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data =\n                {\n                    \"XX -> +XX\",\n                    \"Y_ -> +Y_\",\n                    \"_Y -> +_Y\",\n                    \"YY -> rec[-1]\",\n                },\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0 1\nCX 0 1\nH 0\nM 0\nS 1 1\nH 0\nCX 0 1\nS 0 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MZZ\",\n            .id = GateType::MZZ,\n            .best_candidate_inverse_id = GateType::MZZ,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_TARGETS_PAIRS | GATE_PRODUCES_RESULTS | GATE_IS_NOISY |\n                                 GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"L_Pair Measurement Gates\",\n            .help = R\"MARKDOWN(\nTwo-qubit Z basis parity measurement.\n\nThis operation measures whether pairs of qubits are in the {|00>,|11>} subspace or in the\n{|01>,|10>} subspace of the two qubit state space. |0> and |1> are the +1 and -1\neigenvectors of the Z operator.\n\nIf the qubits were in the {|00>,|11>} subspace, False is appended to the measurement record.\nIf the qubits were in the {|01>,|10>} subspace, True is appended to the measurement record.\nInverting one of the qubit targets inverts the result.\n\nParens Arguments:\n\n    If no parens argument is given, the measurement is perfect.\n    If one parens argument is given, the measurement result is noisy.\n    The argument is the probability of returning the wrong result.\n\nTargets:\n\n    The pairs of qubits to measure in the Z basis.\n\n    This operation accepts inverted qubit targets (like `!5` instead of `5`). Inverted\n    targets flip the measurement result.\n\nExamples:\n\n    # Measure the +ZZ observable of qubit 1 vs qubit 2.\n    MZZ 1 2\n\n    # Measure the -ZZ observable of qubit 1 vs qubit 2.\n    MZZ !1 2\n\n    # Do a noisy measurement of the +ZZ observable of qubit 2 vs qubit 3.\n    # The result recorded to the measurement record will be flipped 1% of the time.\n    MZZ(0.01) 2 3\n\n    # Measure the +ZZ observable qubit 1 vs qubit 2, and also qubit 8 vs qubit 9\n    MZZ 1 2 8 9\n\n    # Perform multiple noisy measurements.\n    # Each measurement has an independent 2% chance of being recorded wrong.\n    MZZ(0.02) 2 3 5 7 11 19 17 4\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data =\n                {\n                    \"XX -> XX\",\n                    \"Z_ -> +Z_\",\n                    \"_Z -> +_Z\",\n                    \"ZZ -> rec[-1]\",\n                },\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nCX 0 1\nM 1\nCX 0 1\n)CIRCUIT\",\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_pauli.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nstatic constexpr std::complex<float> i = std::complex<float>(0, 1);\n\nvoid GateDataMap::add_gate_data_pauli(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"I\",\n            .id = GateType::I,\n            .best_candidate_inverse_id = GateType::I,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"A_Pauli Gates\",\n            .help = R\"MARKDOWN(\nThe identity gate.\nDoes nothing to the target qubits.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to do nothing to.\n)MARKDOWN\",\n            .unitary_data = {{1, 0}, {0, 1}},\n            .flow_data = {\"+X\", \"+Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\n# (no operations)\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"X\",\n            .id = GateType::X,\n            .best_candidate_inverse_id = GateType::X,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"A_Pauli Gates\",\n            .help = R\"MARKDOWN(\nThe Pauli X gate.\nThe bit flip gate.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0, 1}, {1, 0}},\n            .flow_data = {\"+X\", \"-Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nS 0\nS 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"Y\",\n            .id = GateType::Y,\n            .best_candidate_inverse_id = GateType::Y,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"A_Pauli Gates\",\n            .help = R\"MARKDOWN(\nThe Pauli Y gate.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0, -i}, {i, 0}},\n            .flow_data = {\"-X\", \"-Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nH 0\nS 0\nS 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"Z\",\n            .id = GateType::Z,\n            .best_candidate_inverse_id = GateType::Z,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"A_Pauli Gates\",\n            .help = R\"MARKDOWN(\nThe Pauli Z gate.\nThe phase flip gate.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0}, {0, -1}},\n            .flow_data = {\"-X\", \"+Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\n)CIRCUIT\",\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_pauli_product.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nvoid GateDataMap::add_gate_data_pauli_product(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"MPP\",\n            .id = GateType::MPP,\n            .best_candidate_inverse_id = GateType::MPP,\n            .arg_count = ARG_COUNT_SYGIL_ZERO_OR_ONE,\n            .flags = (GateFlags)(GATE_PRODUCES_RESULTS | GATE_IS_NOISY | GATE_TARGETS_PAULI_STRING |\n                                 GATE_TARGETS_COMBINERS | GATE_ARGS_ARE_DISJOINT_PROBABILITIES),\n            .category = \"P_Generalized Pauli Product Gates\",\n            .help = R\"MARKDOWN(\nMeasures general pauli product operators, like X1*Y2*Z3.\n\nParens Arguments:\n\n    An optional failure probability.\n    If no argument is given, all measurements are perfect.\n    If one argument is given, it's the chance of reporting measurement results incorrectly.\n\nTargets:\n\n    A series of Pauli products to measure.\n\n    Each Pauli product is a series of Pauli targets (like `X1`, `Y2`, or `Z3`) separated by\n    combiners (`*`). Each Pauli term can be inverted (like `!Y2` instead of `Y2`). A negated\n    product will record the opposite measurement result.\n\n    Note that, although you can write down instructions that measure anti-Hermitian products,\n    like `MPP X1*Z1`, doing this will cause exceptions when you simulate or analyze the\n    circuit since measuring an anti-Hermitian operator doesn't have well defined semantics.\n\n    Using overly-complicated Hermitian products, like saying `MPP X1*Y1*Y2*Z2` instead of\n    `MPP !Z1*X2`, is technically allowed. But probably not a great idea since tools consuming\n    the circuit may have assumed that each qubit would appear at most once in each product.\n\nExamples:\n\n    # Measure the two-body +X1*Y2 observable.\n    MPP X1*Y2\n\n    # Measure the one-body -Z5 observable.\n    MPP !Z5\n\n    # Measure the two-body +X1*Y2 observable and also the three-body -Z3*Z4*Z5 observable.\n    MPP X1*Y2 !Z3*Z4*Z5\n\n    # Noisily measure +Z1+Z2 and +X1*X2 (independently flip each reported result 0.1% of the time).\n    MPP(0.001) Z1*Z2 X1*X2\n\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data =\n                {\n                    \"XYZ__ -> rec[-2]\",\n                    \"___XX -> rec[-1]\",\n                    \"X____ -> X____\",\n                    \"_Y___ -> _Y___\",\n                    \"__Z__ -> __Z__\",\n                    \"___X_ -> ___X_\",\n                    \"____X -> ____X\",\n                    \"ZZ___ -> ZZ___\",\n                    \"_XX__ -> _XX__\",\n                    \"___ZZ -> ___ZZ\",\n                },\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 1 1 1\nH 0 1 3 4\nCX 2 0 1 0 4 3\nM 0 3\nCX 2 0 1 0 4 3\nH 0 1 3 4\nS 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SPP\",\n            .id = GateType::SPP,\n            .best_candidate_inverse_id = GateType::SPP_DAG,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_TARGETS_PAULI_STRING | GATE_TARGETS_COMBINERS | GATE_IS_UNITARY),\n            .category = \"P_Generalized Pauli Product Gates\",\n            .help = R\"MARKDOWN(\nThe generalized S gate. Phases the -1 eigenspace of Pauli product observables by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    A series of Pauli products to phase.\n\n    Each Pauli product is a series of Pauli targets (like `X1`, `Y2`, or `Z3`) separated by\n    combiners (`*`). Each Pauli term can be inverted (like `!Y2` instead of `Y2`), to negate\n    the product.\n\n    Note that, although you can write down instructions that phase anti-Hermitian products,\n    like `SPP X1*Z1`, doing this will cause exceptions when you simulate or analyze the\n    circuit since phasing an anti-Hermitian operator doesn't have well defined semantics.\n\n    Using overly-complicated Hermitian products, like saying `SPP X1*Y1*Y2*Z2` instead of\n    `SPP !Z1*X2`, is technically allowed. But probably not a great idea since tools consuming\n    the circuit may have assumed that each qubit would appear at most once in each product.\n\nExamples:\n\n    # Perform an S gate on qubit 1.\n    SPP Z1\n\n    # Perform a SQRT_X gate on qubit 1.\n    SPP X1\n\n    # Perform a SQRT_X_DAG gate on qubit 1.\n    SPP !X1\n\n    # Perform a SQRT_XX gate between qubit 1 and qubit 2.\n    SPP X1*X2\n\n    # Perform a SQRT_YY gate between qubit 1 and 2, and a SQRT_ZZ_DAG between qubit 3 and 4.\n    SPP Y1*Y2 !Z1*Z2\n\n    # Phase the -1 eigenspace of -X1*Y2*Z3 by i.\n    SPP !X1*Y2*Z3\n\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data =\n                {\n                    // For \"SPP X0*Y1*Z2\"\n                    \"X__ -> X__\",\n                    \"Z__ -> -YYZ\",\n                    \"_X_ -> -XZZ\",\n                    \"_Z_ -> XXZ\",\n                    \"__X -> XYY\",\n                    \"__Z -> __Z\",\n                },\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nCX 2 1\nCX 1 0\nS 1\nS 1\nH 1\nCX 1 0\nCX 2 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SPP_DAG\",\n            .id = GateType::SPP_DAG,\n            .best_candidate_inverse_id = GateType::SPP,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_TARGETS_PAULI_STRING | GATE_TARGETS_COMBINERS | GATE_IS_UNITARY),\n            .category = \"P_Generalized Pauli Product Gates\",\n            .help = R\"MARKDOWN(\nThe generalized S_DAG gate. Phases the -1 eigenspace of Pauli product observables by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    A series of Pauli products to phase.\n\n    Each Pauli product is a series of Pauli targets (like `X1`, `Y2`, or `Z3`) separated by\n    combiners (`*`). Each Pauli term can be inverted (like `!Y2` instead of `Y2`), to negate\n    the product.\n\n    Note that, although you can write down instructions that phase anti-Hermitian products,\n    like `SPP X1*Z1`, doing this will cause exceptions when you simulate or analyze the\n    circuit since phasing an anti-Hermitian operator doesn't have well defined semantics.\n\n    Using overly-complicated Hermitian products, like saying `SPP X1*Y1*Y2*Z2` instead of\n    `SPP !Z1*X2`, is technically allowed. But probably not a great idea since tools consuming\n    the circuit may have assumed that each qubit would appear at most once in each product.\n\nExamples:\n\n    # Perform an S_DAG gate on qubit 1.\n    SPP_DAG Z1\n\n    # Perform a SQRT_X_DAG gate on qubit 1.\n    SPP_DAG X1\n\n    # Perform a SQRT_X gate on qubit 1.\n    SPP_DAG !X1\n\n    # Perform a SQRT_XX_DAG gate between qubit 1 and qubit 2.\n    SPP_DAG X1*X2\n\n    # Perform a SQRT_YY_DAG gate between qubit 1 and 2, and a SQRT_ZZ between qubit 3 and 4.\n    SPP_DAG Y1*Y2 !Z1*Z2\n\n    # Phase the -1 eigenspace of -X1*Y2*Z3 by -i.\n    SPP_DAG !X1*Y2*Z3\n\n)MARKDOWN\",\n            .unitary_data = {},\n            .flow_data =\n                {\n                    // For \"SPP_DAG X0*Y1*Z2\"\n                    \"X__ -> X__\",\n                    \"Z__ -> YYZ\",\n                    \"_X_ -> XZZ\",\n                    \"_Z_ -> -XXZ\",\n                    \"__X -> -XYY\",\n                    \"__Z -> __Z\",\n                },\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nCX 2 1\nCX 1 0\nH 1\nS 1\nS 1\nCX 1 0\nCX 2 1\n)CIRCUIT\",\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_period_3.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nstatic constexpr std::complex<float> i = std::complex<float>(0, 1);\n\nvoid GateDataMap::add_gate_data_period_3(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"C_XYZ\",\n            .id = GateType::C_XYZ,\n            .best_candidate_inverse_id = GateType::C_ZYX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nRight handed period 3 axis cycling gate, sending X -> Y -> Z -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f - i * 0.5f, -0.5f - 0.5f * i}, {0.5f - 0.5f * i, 0.5f + 0.5f * i}},\n            .flow_data = {\"+Y\", \"+X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"C_NXYZ\",\n            .id = GateType::C_NXYZ,\n            .best_candidate_inverse_id = GateType::C_ZYNX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPerforms the period-3 cycle -X -> Y -> Z -> -X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f + i * 0.5f, 0.5f - 0.5f * i}, {-0.5f - 0.5f * i, 0.5f - 0.5f * i}},\n            .flow_data = {\"-Y\", \"-X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nH 0\nS 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"C_XNYZ\",\n            .id = GateType::C_XNYZ,\n            .best_candidate_inverse_id = GateType::C_ZNYX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPerforms the period-3 cycle X -> -Y -> Z -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f + i * 0.5f, -0.5f + 0.5f * i}, {0.5f + 0.5f * i, 0.5f - 0.5f * i}},\n            .flow_data = {\"-Y\", \"+X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"C_XYNZ\",\n            .id = GateType::C_XYNZ,\n            .best_candidate_inverse_id = GateType::C_NZYX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPerforms the period-3 cycle X -> Y -> -Z -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f - i * 0.5f, 0.5f + 0.5f * i}, {-0.5f + 0.5f * i, 0.5f + 0.5f * i}},\n            .flow_data = {\"+Y\", \"-X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nH 0\nS 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"C_ZYX\",\n            .id = GateType::C_ZYX,\n            .best_candidate_inverse_id = GateType::C_XYZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nLeft handed period 3 axis cycling gate, sending Z -> Y -> X -> Z.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f + i * 0.5f, 0.5f + 0.5f * i}, {-0.5f + 0.5f * i, 0.5f - 0.5f * i}},\n            .flow_data = {\"+Z\", \"+Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"C_ZYNX\",\n            .id = GateType::C_ZYNX,\n            .best_candidate_inverse_id = GateType::C_NXYZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPerforms the period-3 cycle -X -> Z -> Y -> -X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f - i * 0.5f, -0.5f + 0.5f * i}, {0.5f + 0.5f * i, 0.5f + 0.5f * i}},\n            .flow_data = {\"-Z\", \"+Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nH 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"C_ZNYX\",\n            .id = GateType::C_ZNYX,\n            .best_candidate_inverse_id = GateType::C_XNYZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPerforms the period-3 cycle X -> Z -> -Y -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f - i * 0.5f, 0.5f - 0.5f * i}, {-0.5f - 0.5f * i, 0.5f + 0.5f * i}},\n            .flow_data = {\"+Z\", \"-Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nS 0\nS 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"C_NZYX\",\n            .id = GateType::C_NZYX,\n            .best_candidate_inverse_id = GateType::C_XYNZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPerforms the period-3 cycle X -> -Z -> Y -> X.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f + i * 0.5f, -0.5f + -0.5f * i}, {0.5f - 0.5f * i, 0.5f - 0.5f * i}},\n            .flow_data = {\"-Z\", \"-Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nH 0\nS 0\nS 0\nS 0\n)CIRCUIT\",\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_period_4.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nstatic constexpr std::complex<float> i = std::complex<float>(0, 1);\n\nvoid GateDataMap::add_gate_data_period_4(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_X\",\n            .id = GateType::SQRT_X,\n            .best_candidate_inverse_id = GateType::SQRT_X_DAG,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPrincipal square root of X gate.\nPhases the amplitude of |-> by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f + 0.5f * i, 0.5f - 0.5f * i}, {0.5f - 0.5f * i, 0.5f + 0.5f * i}},\n            .flow_data = {\"+X\", \"-Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nS 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_X_DAG\",\n            .id = GateType::SQRT_X_DAG,\n            .best_candidate_inverse_id = GateType::SQRT_X,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nAdjoint of the principal square root of X gate.\nPhases the amplitude of |-> by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f - 0.5f * i, 0.5f + 0.5f * i}, {0.5f + 0.5f * i, 0.5f - 0.5f * i}},\n            .flow_data = {\"+X\", \"+Y\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nH 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_Y\",\n            .id = GateType::SQRT_Y,\n            .best_candidate_inverse_id = GateType::SQRT_Y_DAG,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPrincipal square root of Y gate.\nPhases the amplitude of |-i> by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f + 0.5f * i, -0.5f - 0.5f * i}, {0.5f + 0.5f * i, 0.5f + 0.5f * i}},\n            .flow_data = {\"-Z\", \"+X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_Y_DAG\",\n            .id = GateType::SQRT_Y_DAG,\n            .best_candidate_inverse_id = GateType::SQRT_Y,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nAdjoint of the principal square root of Y gate.\nPhases the amplitude of |-i> by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{0.5f - 0.5f * i, 0.5f - 0.5f * i}, {-0.5f + 0.5f * i, 0.5f - 0.5f * i}},\n            .flow_data = {\"+Z\", \"-X\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nS 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"S\",\n            .id = GateType::S,\n            .best_candidate_inverse_id = GateType::S_DAG,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPrincipal square root of Z gate.\nPhases the amplitude of |1> by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0}, {0, i}},\n            .flow_data = {\"+Y\", \"+Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate_alias(failed, \"SQRT_Z\", \"S\");\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"S_DAG\",\n            .id = GateType::S_DAG,\n            .best_candidate_inverse_id = GateType::S,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_SINGLE_QUBIT_GATE | GATE_IS_UNITARY),\n            .category = \"B_Single Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nAdjoint of the principal square root of Z gate.\nPhases the amplitude of |1> by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubits to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0}, {0, -i}},\n            .flow_data = {\"-Y\", \"+Z\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate_alias(failed, \"SQRT_Z_DAG\", \"S_DAG\");\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_pp.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nstatic constexpr std::complex<float> i = std::complex<float>(0, 1);\n\nvoid GateDataMap::add_gate_data_pp(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"II\",\n            .id = GateType::II,\n            .best_candidate_inverse_id = GateType::II,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nA two-qubit identity gate.\n\nTwice as much doing-nothing as the I gate! This gate only exists because it\ncan be useful as a communication mechanism for systems built on top of stim.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n\nExamples:\n\n    II 0 1\n\n    R 0\n    II[ACTUALLY_A_LEAKAGE_ISWAP] 0 1\n    R 0\n    CX 1 0\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}},\n            .flow_data = {\"+XI\", \"+ZI\", \"+IX\", \"+IZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_XX\",\n            .id = GateType::SQRT_XX,\n            .best_candidate_inverse_id = GateType::SQRT_XX_DAG,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPhases the -1 eigenspace of the XX observable by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data =\n                {{0.5f + 0.5f * i, 0, 0, 0.5f - 0.5f * i},\n                 {0, 0.5f + 0.5f * i, 0.5f - 0.5f * i, 0},\n                 {0, 0.5f - 0.5f * i, 0.5f + 0.5f * i, 0},\n                 {0.5f - 0.5f * i, 0, 0, 0.5f + 0.5f * i}},\n            .flow_data = {\"+XI\", \"-YX\", \"+IX\", \"-XY\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nCNOT 0 1\nH 1\nS 0\nS 1\nH 0\nH 1\n)CIRCUIT\",\n        });\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_XX_DAG\",\n            .id = GateType::SQRT_XX_DAG,\n            .best_candidate_inverse_id = GateType::SQRT_XX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPhases the -1 eigenspace of the XX observable by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data =\n                {{0.5f - 0.5f * i, 0, 0, 0.5f + 0.5f * i},\n                 {0, 0.5f - 0.5f * i, 0.5f + 0.5f * i, 0},\n                 {0, 0.5f + 0.5f * i, 0.5f - 0.5f * i, 0},\n                 {0.5f + 0.5f * i, 0, 0, 0.5f - 0.5f * i}},\n            .flow_data = {\"+XI\", \"+YX\", \"+IX\", \"+XY\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nCNOT 0 1\nH 1\nS 0\nS 0\nS 0\nS 1\nS 1\nS 1\nH 0\nH 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_YY\",\n            .id = GateType::SQRT_YY,\n            .best_candidate_inverse_id = GateType::SQRT_YY_DAG,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPhases the -1 eigenspace of the YY observable by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data =\n                {{0.5f + 0.5f * i, 0, 0, -0.5f + 0.5f * i},\n                 {0, 0.5f + 0.5f * i, 0.5f - 0.5f * i, 0},\n                 {0, 0.5f - 0.5f * i, 0.5f + 0.5f * i, 0},\n                 {-0.5f + 0.5f * i, 0, 0, 0.5f + 0.5f * i}},\n            .flow_data = {\"-ZY\", \"+XY\", \"-YZ\", \"+YX\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nS 1\nS 1\nS 1\nH 0\nCNOT 0 1\nH 1\nS 0\nS 1\nH 0\nH 1\nS 0\nS 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_YY_DAG\",\n            .id = GateType::SQRT_YY_DAG,\n            .best_candidate_inverse_id = GateType::SQRT_YY,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPhases the -1 eigenspace of the YY observable by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data =\n                {{0.5f - 0.5f * i, 0, 0, -0.5f - 0.5f * i},\n                 {0, 0.5f - 0.5f * i, 0.5f + 0.5f * i, 0},\n                 {0, 0.5f + 0.5f * i, 0.5f - 0.5f * i, 0},\n                 {-0.5f - 0.5f * i, 0, 0, 0.5f - 0.5f * i}},\n            .flow_data = {\"+ZY\", \"-XY\", \"+YZ\", \"-YX\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nS 1\nH 0\nCNOT 0 1\nH 1\nS 0\nS 1\nH 0\nH 1\nS 0\nS 1\nS 1\nS 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_ZZ\",\n            .id = GateType::SQRT_ZZ,\n            .best_candidate_inverse_id = GateType::SQRT_ZZ_DAG,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPhases the -1 eigenspace of the ZZ observable by i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, i, 0, 0}, {0, 0, i, 0}, {0, 0, 0, 1}},\n            .flow_data = {\"+YZ\", \"+ZI\", \"+ZY\", \"+IZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 1\nCNOT 0 1\nH 1\nS 0\nS 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SQRT_ZZ_DAG\",\n            .id = GateType::SQRT_ZZ_DAG,\n            .best_candidate_inverse_id = GateType::SQRT_ZZ,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nPhases the -1 eigenspace of the ZZ observable by -i.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, -i, 0, 0}, {0, 0, -i, 0}, {0, 0, 0, 1}},\n            .flow_data = {\"-YZ\", \"+ZI\", \"-ZY\", \"+IZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 1\nCNOT 0 1\nH 1\nS 0\nS 0\nS 0\nS 1\nS 1\nS 1\n)CIRCUIT\",\n        });\n}\n"
  },
  {
    "path": "src/stim/gates/gate_data_swaps.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nstatic constexpr std::complex<float> i = std::complex<float>(0, 1);\n\nvoid GateDataMap::add_gate_data_swaps(bool &failed) {\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SWAP\",\n            .id = GateType::SWAP,\n            .best_candidate_inverse_id = GateType::SWAP,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nSwaps two qubits.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 0, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 1}},\n            .flow_data = {\"+IX\", \"+IZ\", \"+XI\", \"+ZI\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nCNOT 0 1\nCNOT 1 0\nCNOT 0 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"ISWAP\",\n            .id = GateType::ISWAP,\n            .best_candidate_inverse_id = GateType::ISWAP_DAG,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nSwaps two qubits and phases the -1 eigenspace of the ZZ observable by i.\nEquivalent to `SWAP` then `CZ` then `S` on both targets.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 0, i, 0}, {0, i, 0, 0}, {0, 0, 0, 1}},\n            .flow_data = {\"+ZY\", \"+IZ\", \"+YZ\", \"+ZI\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nCNOT 0 1\nCNOT 1 0\nH 1\nS 1\nS 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"ISWAP_DAG\",\n            .id = GateType::ISWAP_DAG,\n            .best_candidate_inverse_id = GateType::ISWAP,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nSwaps two qubits and phases the -1 eigenspace of the ZZ observable by -i.\nEquivalent to `SWAP` then `CZ` then `S_DAG` on both targets.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 0, -i, 0}, {0, -i, 0, 0}, {0, 0, 0, 1}},\n            .flow_data = {\"-ZY\", \"+IZ\", \"-YZ\", \"+ZI\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nS 0\nS 0\nS 0\nS 1\nS 1\nS 1\nH 1\nCNOT 1 0\nCNOT 0 1\nH 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"CXSWAP\",\n            .id = GateType::CXSWAP,\n            .best_candidate_inverse_id = GateType::SWAPCX,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nA combination CX-then-SWAP gate.\nThis gate is kak-equivalent to the iswap gate, but preserves X/Z noise bias.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}, {0, 1, 0, 0}},\n            .flow_data = {\"+XX\", \"+IZ\", \"+XI\", \"+ZZ\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nCNOT 1 0\nCNOT 0 1\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"SWAPCX\",\n            .id = GateType::SWAPCX,\n            .best_candidate_inverse_id = GateType::CXSWAP,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nA combination SWAP-then-CX gate.\nThis gate is kak-equivalent to the iswap gate, but preserves X/Z noise bias.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 0, 0, 1}, {0, 1, 0, 0}, {0, 0, 1, 0}},\n            .flow_data = {\"+IX\", \"+ZZ\", \"+XX\", \"+ZI\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nCNOT 0 1\nCNOT 1 0\n)CIRCUIT\",\n        });\n\n    add_gate(\n        failed,\n        Gate{\n            .name = \"CZSWAP\",\n            .id = GateType::CZSWAP,\n            .best_candidate_inverse_id = GateType::CZSWAP,\n            .arg_count = 0,\n            .flags = (GateFlags)(GATE_IS_UNITARY | GATE_TARGETS_PAIRS),\n            .category = \"C_Two Qubit Clifford Gates\",\n            .help = R\"MARKDOWN(\nA combination CZ-and-SWAP gate.\nThis gate is kak-equivalent to the iswap gate.\n\nParens Arguments:\n\n    This instruction takes no parens arguments.\n\nTargets:\n\n    Qubit pairs to operate on.\n)MARKDOWN\",\n            .unitary_data = {{1, 0, 0, 0}, {0, 0, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, -1}},\n            .flow_data = {\"+ZX\", \"+IZ\", \"+XZ\", \"+ZI\"},\n            .h_s_cx_m_r_decomposition = R\"CIRCUIT(\nH 0\nCX 0 1\nCX 1 0\nH 1\n)CIRCUIT\",\n        });\n    add_gate_alias(failed, \"SWAPCZ\", \"CZSWAP\");\n}\n"
  },
  {
    "path": "src/stim/gates/gates.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\nusing namespace stim;\n\nGateDataMap::GateDataMap() {\n    bool failed = false;\n    items[0].name = \"NOT_A_GATE\";\n\n    add_gate_data_annotations(failed);\n    add_gate_data_blocks(failed);\n    add_gate_data_collapsing(failed);\n    add_gate_data_controlled(failed);\n    add_gate_data_hada(failed);\n    add_gate_data_heralded(failed);\n    add_gate_data_noisy(failed);\n    add_gate_data_pauli(failed);\n    add_gate_data_period_3(failed);\n    add_gate_data_period_4(failed);\n    add_gate_data_pp(failed);\n    add_gate_data_swaps(failed);\n    add_gate_data_pair_measure(failed);\n    add_gate_data_pauli_product(failed);\n    for (size_t k = 1; k < NUM_DEFINED_GATES; k++) {\n        if (items[k].name.empty()) {\n            std::cerr << \"Uninitialized gate id: \" << k << \".\\n\";\n            failed = true;\n        }\n    }\n    if (failed) {\n        throw std::out_of_range(\"Failed to initialize gate data.\");\n    }\n}\n\nGateType Gate::hadamard_conjugated(bool ignoring_sign) const {\n    switch (id) {\n        case GateType::DETECTOR:\n        case GateType::OBSERVABLE_INCLUDE:\n        case GateType::TICK:\n        case GateType::QUBIT_COORDS:\n        case GateType::SHIFT_COORDS:\n        case GateType::MPAD:\n        case GateType::H:\n        case GateType::H_NXZ:\n        case GateType::DEPOLARIZE1:\n        case GateType::DEPOLARIZE2:\n        case GateType::Y_ERROR:\n        case GateType::I:\n        case GateType::II:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n        case GateType::Y:\n        case GateType::SQRT_YY:\n        case GateType::SQRT_YY_DAG:\n        case GateType::MYY:\n        case GateType::SWAP:\n            return id;\n\n        case GateType::MY:\n        case GateType::MRY:\n        case GateType::RY:\n        case GateType::YCY:\n            return ignoring_sign ? id : GateType::NOT_A_GATE;\n\n        case GateType::ISWAP:\n        case GateType::CZSWAP:\n        case GateType::ISWAP_DAG:\n            return GateType::NOT_A_GATE;\n\n        case GateType::XCY:\n            return ignoring_sign ? GateType::CY : GateType::NOT_A_GATE;\n        case GateType::CY:\n            return ignoring_sign ? GateType::XCY : GateType::NOT_A_GATE;\n        case GateType::YCX:\n            return ignoring_sign ? GateType::YCZ : GateType::NOT_A_GATE;\n        case GateType::YCZ:\n            return ignoring_sign ? GateType::YCX : GateType::NOT_A_GATE;\n\n        case GateType::H_XY:\n            return GateType::H_NYZ;\n        case GateType::H_NYZ:\n            return GateType::H_XY;\n\n        case GateType::H_YZ:\n            return GateType::H_NXY;\n        case GateType::H_NXY:\n            return GateType::H_YZ;\n\n        case GateType::C_XYZ:\n            return GateType::C_ZNYX;\n        case GateType::C_ZNYX:\n            return GateType::C_XYZ;\n\n        case GateType::C_XNYZ:\n            return GateType::C_ZYX;\n        case GateType::C_ZYX:\n            return GateType::C_XNYZ;\n\n        case GateType::C_NXYZ:\n            return GateType::C_ZYNX;\n        case GateType::C_ZYNX:\n            return GateType::C_NXYZ;\n\n        case GateType::C_XYNZ:\n            return GateType::C_NZYX;\n        case GateType::C_NZYX:\n            return GateType::C_XYNZ;\n\n        case GateType::X:\n            return GateType::Z;\n        case GateType::Z:\n            return GateType::X;\n        case GateType::SQRT_Y:\n            return GateType::SQRT_Y_DAG;\n        case GateType::SQRT_Y_DAG:\n            return GateType::SQRT_Y;\n        case GateType::MX:\n            return GateType::M;\n        case GateType::M:\n            return GateType::MX;\n        case GateType::MRX:\n            return GateType::MR;\n        case GateType::MR:\n            return GateType::MRX;\n        case GateType::RX:\n            return GateType::R;\n        case GateType::R:\n            return GateType::RX;\n        case GateType::XCX:\n            return GateType::CZ;\n        case GateType::XCZ:\n            return GateType::CX;\n        case GateType::CX:\n            return GateType::XCZ;\n        case GateType::CZ:\n            return GateType::XCX;\n        case GateType::X_ERROR:\n            return GateType::Z_ERROR;\n        case GateType::Z_ERROR:\n            return GateType::X_ERROR;\n        case GateType::SQRT_X:\n            return GateType::S;\n        case GateType::SQRT_X_DAG:\n            return GateType::S_DAG;\n        case GateType::S:\n            return GateType::SQRT_X;\n        case GateType::S_DAG:\n            return GateType::SQRT_X_DAG;\n        case GateType::SQRT_XX:\n            return GateType::SQRT_ZZ;\n        case GateType::SQRT_XX_DAG:\n            return GateType::SQRT_ZZ_DAG;\n        case GateType::SQRT_ZZ:\n            return GateType::SQRT_XX;\n        case GateType::SQRT_ZZ_DAG:\n            return GateType::SQRT_XX_DAG;\n        case GateType::CXSWAP:\n            return GateType::SWAPCX;\n        case GateType::SWAPCX:\n            return GateType::CXSWAP;\n        case GateType::MXX:\n            return GateType::MZZ;\n        case GateType::MZZ:\n            return GateType::MXX;\n        default:\n            return GateType::NOT_A_GATE;\n    }\n}\n\nbool Gate::is_symmetric() const {\n    if (flags & GATE_IS_SINGLE_QUBIT_GATE) {\n        return true;\n    }\n\n    if (flags & GATE_TARGETS_PAIRS) {\n        switch (id) {\n            case GateType::II:\n            case GateType::II_ERROR:\n            case GateType::XCX:\n            case GateType::YCY:\n            case GateType::CZ:\n            case GateType::DEPOLARIZE2:\n            case GateType::SWAP:\n            case GateType::ISWAP:\n            case GateType::CZSWAP:\n            case GateType::ISWAP_DAG:\n            case GateType::MXX:\n            case GateType::MYY:\n            case GateType::MZZ:\n            case GateType::SQRT_XX:\n            case GateType::SQRT_YY:\n            case GateType::SQRT_ZZ:\n            case GateType::SQRT_XX_DAG:\n            case GateType::SQRT_YY_DAG:\n            case GateType::SQRT_ZZ_DAG:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    return false;\n}\n\nstd::array<float, 3> Gate::to_euler_angles() const {\n    if (unitary_data.size() != 2) {\n        throw std::out_of_range(std::string(name) + \" doesn't have 1q unitary data.\");\n    }\n    auto a = unitary_data[0][0];\n    auto b = unitary_data[0][1];\n    auto c = unitary_data[1][0];\n    auto d = unitary_data[1][1];\n    std::array<float, 3> xyz;\n    if (a == std::complex<float>{0}) {\n        xyz[0] = 3.14159265359f;\n        xyz[1] = 0;\n        xyz[2] = arg(-b / c);\n    } else if (b == std::complex<float>{0}) {\n        xyz[0] = 0;\n        xyz[1] = 0;\n        xyz[2] = arg(d / a);\n    } else {\n        xyz[0] = 3.14159265359f / 2;\n        xyz[1] = arg(c / a);\n        xyz[2] = arg(-b / a);\n    }\n    return xyz;\n}\n\nstd::array<float, 4> Gate::to_axis_angle() const {\n    if (unitary_data.size() != 2) {\n        throw std::out_of_range(std::string(name) + \" doesn't have 1q unitary data.\");\n    }\n    auto a = unitary_data[0][0];\n    auto b = unitary_data[0][1];\n    auto c = unitary_data[1][0];\n    auto d = unitary_data[1][1];\n    auto i = std::complex<float>{0, 1};\n    auto x = b + c;\n    auto y = b * i + c * -i;\n    auto z = a - d;\n    auto s = a + d;\n    s *= -i;\n    std::complex<double> p = 1;\n    if (s.imag() != 0) {\n        p = s;\n    }\n    if (x.imag() != 0) {\n        p = x;\n    }\n    if (y.imag() != 0) {\n        p = y;\n    }\n    if (z.imag() != 0) {\n        p = z;\n    }\n    p /= sqrt(p.imag() * p.imag() + p.real() * p.real());\n    p *= 2;\n    x /= p;\n    y /= p;\n    z /= p;\n    s /= p;\n    assert(x.imag() == 0);\n    assert(y.imag() == 0);\n    assert(z.imag() == 0);\n    assert(s.imag() == 0);\n    auto rx = x.real();\n    auto ry = y.real();\n    auto rz = z.real();\n    auto rs = s.real();\n\n    // At this point it's more of a quaternion. Normalize the axis.\n    auto r = sqrt(rx * rx + ry * ry + rz * rz);\n    if (r == 0) {\n        rx = 1;\n    } else {\n        rx /= r;\n        ry /= r;\n        rz /= r;\n    }\n    if ((rx < 0) + (ry < 0) + (rz < 0) > 1) {\n        rx = -rx;\n        ry = -ry;\n        rz = -rz;\n        rs = -rs;\n    }\n\n    return {rx, ry, rz, acosf(rs) * 2};\n}\n\nbool Gate::has_known_unitary_matrix() const {\n    return (flags & GateFlags::GATE_IS_UNITARY) &&\n           (flags & (GateFlags::GATE_IS_SINGLE_QUBIT_GATE | GateFlags::GATE_TARGETS_PAIRS));\n}\n\nstd::vector<std::vector<std::complex<float>>> Gate::unitary() const {\n    if (unitary_data.size() != 2 && unitary_data.size() != 4) {\n        throw std::out_of_range(std::string(name) + \" doesn't have 1q or 2q unitary data.\");\n    }\n    std::vector<std::vector<std::complex<float>>> result;\n    for (size_t k = 0; k < unitary_data.size(); k++) {\n        const auto &d = unitary_data[k];\n        result.emplace_back();\n        for (size_t j = 0; j < d.size(); j++) {\n            result.back().push_back(d[j]);\n        }\n    }\n    return result;\n}\n\nconst Gate &Gate::inverse() const {\n    if ((flags & GATE_IS_UNITARY) || id == GateType::TICK) {\n        return GATE_DATA[best_candidate_inverse_id];\n    }\n    throw std::out_of_range(std::string(name) + \" has no inverse.\");\n}\n\nvoid GateDataMap::add_gate(bool &failed, const Gate &gate) {\n    assert((size_t)gate.id < NUM_DEFINED_GATES);\n    auto h = gate_name_to_hash(gate.name);\n    auto &hash_loc = hashed_name_to_gate_type_table[h];\n    if (!hash_loc.expected_name.empty()) {\n        std::cerr << \"GATE COLLISION \" << gate.name << \" vs \" << items[(size_t)hash_loc.id].name << \"\\n\";\n        failed = true;\n        return;\n    }\n    items[(size_t)gate.id] = gate;\n    hash_loc.id = gate.id;\n    hash_loc.expected_name = gate.name;\n}\n\nvoid GateDataMap::add_gate_alias(bool &failed, const char *alt_name, const char *canon_name) {\n    auto h_alt = gate_name_to_hash(alt_name);\n    auto &hash_loc = hashed_name_to_gate_type_table[h_alt];\n    if (!hash_loc.expected_name.empty()) {\n        std::cerr << \"GATE COLLISION \" << alt_name << \" vs \" << items[(size_t)hash_loc.id].name << \"\\n\";\n        failed = true;\n        return;\n    }\n\n    auto h_canon = gate_name_to_hash(canon_name);\n    if (hashed_name_to_gate_type_table[h_canon].expected_name.empty()) {\n        std::cerr << \"MISSING CANONICAL GATE \" << canon_name << \"\\n\";\n        failed = true;\n        return;\n    }\n\n    hash_loc.id = hashed_name_to_gate_type_table[h_canon].id;\n    hash_loc.expected_name = alt_name;\n}\n\nextern const GateDataMap stim::GATE_DATA = GateDataMap();\n"
  },
  {
    "path": "src/stim/gates/gates.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_GATES_GATE_DATA_H\n#define _STIM_GATES_GATE_DATA_H\n\n#include <array>\n#include <cassert>\n#include <complex>\n#include <cstdint>\n#include <cstring>\n#include <iostream>\n#include <vector>\n\n#include \"stim/mem/fixed_cap_vector.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nstruct Tableau;\n\ntemplate <size_t W>\nstruct Flow;\n\ntemplate <size_t W>\nstruct PauliString;\n\n/// Used for gates' argument count to indicate that a gate takes a variable number of\n/// arguments. This is relevant to coordinate data on detectors and qubits, where there may\n/// be any number of coordinates.\nconstexpr uint8_t ARG_COUNT_SYGIL_ANY = uint8_t{0xFF};\n\n/// Used for gates' argument count to indicate that a gate takes 0 parens arguments or 1\n/// parens argument. This is relevant to measurement gates, where 0 parens arguments means\n/// a noiseless result whereas 1 parens argument is a noisy result.\nconstexpr uint8_t ARG_COUNT_SYGIL_ZERO_OR_ONE = uint8_t{0xFE};\n\nconstexpr inline uint16_t gate_name_to_hash(std::string_view text) {\n    // HACK: A collision is considered to be an error.\n    // Just do *anything* that makes all the defined gates have different values.\n\n    constexpr uint16_t const1 = 2126;\n    constexpr uint16_t const2 = 9883;\n    constexpr uint16_t const3 = 8039;\n    constexpr uint16_t const4 = 9042;\n    constexpr uint16_t const5 = 4916;\n    constexpr uint16_t const6 = 4048;\n    constexpr uint16_t const7 = 7081;\n\n    size_t n = text.size();\n    const char *v = text.data();\n    size_t result = n;\n    if (n > 0) {\n        auto c_first = v[0] | 0x20;\n        auto c_last = v[n - 1] | 0x20;\n        result ^= c_first * const1;\n        result += c_last * const2;\n    }\n    if (n > 2) {\n        auto c1 = v[1] | 0x20;\n        auto c2 = v[2] | 0x20;\n        result ^= c1 * const3;\n        result += c2 * const4;\n    }\n    if (n > 4) {\n        auto c3 = v[3] | 0x20;\n        auto c4 = v[4] | 0x20;\n        result ^= c3 * const5;\n        result += c4 * const6;\n    }\n    if (n > 5) {\n        auto c5 = v[5] | 0x20;\n        result ^= c5 * const7;\n    }\n    return result & 0x1FF;\n}\n\nconstexpr size_t NUM_DEFINED_GATES = 82;\n\nenum class GateType : uint8_t {\n    NOT_A_GATE = 0,\n    // Annotations\n    DETECTOR,\n    OBSERVABLE_INCLUDE,\n    TICK,\n    QUBIT_COORDS,\n    SHIFT_COORDS,\n    // Control flow\n    REPEAT,\n    // Collapsing gates\n    MPAD,\n    MX,\n    MY,\n    M,  // alias when parsing: MZ\n    MRX,\n    MRY,\n    MR,  // alias when parsing: MRZ\n    RX,\n    RY,\n    R,  // alias when parsing: RZ\n    // Controlled gates\n    XCX,\n    XCY,\n    XCZ,\n    YCX,\n    YCY,\n    YCZ,\n    CX,  // alias when parsing: CNOT, ZCX\n    CY,  // alias when parsing: ZCY\n    CZ,  // alias when parsing: ZCZ\n    // Hadamard-like gates\n    H,  // alias when parsing: H_XZ\n    H_XY,\n    H_YZ,\n    H_NXY,\n    H_NXZ,\n    H_NYZ,\n    // Noise channels\n    DEPOLARIZE1,\n    DEPOLARIZE2,\n    X_ERROR,\n    Y_ERROR,\n    Z_ERROR,\n    I_ERROR,\n    II_ERROR,\n    PAULI_CHANNEL_1,\n    PAULI_CHANNEL_2,\n    E,  // alias when parsing: CORRELATED_ERROR\n    ELSE_CORRELATED_ERROR,\n    // Heralded noise channels\n    HERALDED_ERASE,\n    HERALDED_PAULI_CHANNEL_1,\n    // Pauli gates\n    I,\n    X,\n    Y,\n    Z,\n    // Period 3 gates\n    C_XYZ,\n    C_ZYX,\n    C_NXYZ,\n    C_XNYZ,\n    C_XYNZ,\n    C_NZYX,\n    C_ZNYX,\n    C_ZYNX,\n    // Period 4 gates\n    SQRT_X,\n    SQRT_X_DAG,\n    SQRT_Y,\n    SQRT_Y_DAG,\n    S,      // alias when parsing: SQRT_Z\n    S_DAG,  // alias when parsing: SQRT_Z_DAG\n    // Parity phasing gates.\n    II,\n    SQRT_XX,\n    SQRT_XX_DAG,\n    SQRT_YY,\n    SQRT_YY_DAG,\n    SQRT_ZZ,\n    SQRT_ZZ_DAG,\n    // Pauli product gates\n    MPP,\n    SPP,\n    SPP_DAG,\n    // Swap gates\n    SWAP,\n    ISWAP,\n    CXSWAP,\n    SWAPCX,\n    CZSWAP,\n    ISWAP_DAG,\n    // Pair measurement gates\n    MXX,\n    MYY,\n    MZZ,\n};\n\nenum GateFlags : uint16_t {\n    // All gates must have at least one flag set.\n    NO_GATE_FLAG = 0,\n\n    // Indicates whether unitary and tableau data is available for the gate, so it can be tested more easily.\n    GATE_IS_UNITARY = 1 << 0,\n    // Determines whether or not the gate is omitted when computing a reference sample.\n    GATE_IS_NOISY = 1 << 1,\n    // Controls validation of probability arguments like X_ERROR(0.01).\n    GATE_ARGS_ARE_DISJOINT_PROBABILITIES = 1 << 2,\n    // Indicates whether the gate puts data into the measurement record or not.\n    // Also determines whether or not inverted targets (like \"!3\") are permitted.\n    GATE_PRODUCES_RESULTS = 1 << 3,\n    // Prevents the same gate on adjacent lines from being combined into one longer invocation.\n    GATE_IS_NOT_FUSABLE = 1 << 4,\n    // Controls block functionality for instructions like REPEAT.\n    GATE_IS_BLOCK = 1 << 5,\n    // Controls validation code checking for arguments coming in pairs.\n    GATE_TARGETS_PAIRS = 1 << 6,\n    // Controls instructions like CORRELATED_ERROR taking Pauli product targets (\"X1 Y2 Z3\").\n    // Note that this enables the Pauli terms but not the combine terms like X1*Y2.\n    GATE_TARGETS_PAULI_STRING = 1 << 7,\n    // Controls instructions like DETECTOR taking measurement record targets (\"rec[-1]\").\n    // The \"ONLY\" refers to the fact that this flag switches the default behavior to not allowing qubit targets.\n    // Further flags can then override that default.\n    GATE_ONLY_TARGETS_MEASUREMENT_RECORD = 1 << 8,\n    // Controls instructions like CX operating allowing measurement record targets and sweep bit targets.\n    GATE_CAN_TARGET_BITS = 1 << 9,\n    // Controls whether the gate takes qubit/record targets.\n    GATE_TAKES_NO_TARGETS = 1 << 10,\n    // Controls validation of index arguments like OBSERVABLE_INCLUDE(1).\n    GATE_ARGS_ARE_UNSIGNED_INTEGERS = 1 << 11,\n    // Controls instructions like MPP taking Pauli product combiners (\"X1*Y2 Z3\").\n    GATE_TARGETS_COMBINERS = 1 << 12,\n    // Measurements and resets are dissipative operations.\n    GATE_IS_RESET = 1 << 13,\n    // Annotations like DETECTOR aren't strictly speaking identity operations, but they can be ignored by code that only\n    // cares about effects that happen to qubits (as opposed to in the classical control system).\n    GATE_HAS_NO_EFFECT_ON_QUBITS = 1 << 14,\n    // Whether or not the gate trivially broadcasts over targets.\n    GATE_IS_SINGLE_QUBIT_GATE = 1 << 15,\n};\n\nstruct Gate {\n    /// The canonical name of the gate, used when printing it to a circuit file.\n    std::string_view name;\n    /// The gate's type, such as stim::GateType::X or stim::GateType::MRZ.\n    GateType id;\n    /// The id of the gate inverse to this one, or at least the closest thing to an inverse.\n    /// Set to GateType::NOT_A_GATE for gates with no inverse.\n    GateType best_candidate_inverse_id;\n    /// The number of parens arguments the gate expects (e.g. X_ERROR takes 1, PAULI_CHANNEL_1 takes 3).\n    /// Set to stim::ARG_COUNT_SYGIL_ANY to indicate any number is allowed (e.g. DETECTOR coordinate data).\n    uint8_t arg_count;\n    /// Bit-packed data describing details of the gate.\n    GateFlags flags;\n\n    /// A word describing what sort of gate this is.\n    std::string_view category;\n    /// Prose summary of what the gate is, how it fits into Stim, and how to use it.\n    std::string_view help;\n    /// A unitary matrix describing the gate. (Size 0 if the gate is not unitary.)\n    FixedCapVector<FixedCapVector<std::complex<float>, 4>, 4> unitary_data;\n    /// A shorthand description of the stabilizer flows of the gate.\n    /// For single qubit Cliffords, this should be the output stabilizers for X then Z.\n    /// For 2 qubit Cliffords, this should be the output stabilizers for X_, Z_, _X, _Z.\n    /// For 2 qubit dissipative gates, this should be flows like \"X_ -> XX xor rec[-1]\".\n    FixedCapVector<const char *, 10> flow_data;\n    /// Stim circuit file contents of a decomposition into H+S+CX+M+R operations. (nullptr if not decomposable.)\n    const char *h_s_cx_m_r_decomposition;\n\n    inline bool operator==(const Gate &other) const {\n        return id == other.id;\n    }\n    inline bool operator!=(const Gate &other) const {\n        return id != other.id;\n    }\n\n    const Gate &inverse() const;\n\n    template <size_t W>\n    Tableau<W> tableau() const {\n        if (!(flags & GateFlags::GATE_IS_UNITARY)) {\n            throw std::invalid_argument(std::string(name) + \" isn't unitary so it doesn't have a tableau.\");\n        }\n        const auto &d = flow_data;\n        if (flow_data.size() == 2) {\n            return Tableau<W>::gate1(d[0], d[1]);\n        }\n        if (flow_data.size() == 4) {\n            return Tableau<W>::gate2(d[0], d[1], d[2], d[3]);\n        }\n        throw std::out_of_range(std::string(name) + \" doesn't have 1q or 2q tableau data.\");\n    }\n\n    template <size_t W>\n    std::vector<Flow<W>> flows() const {\n        if (has_known_unitary_matrix()) {\n            auto t = tableau<W>();\n            if (flags & GateFlags::GATE_TARGETS_PAIRS) {\n                return {\n                    Flow<W>{stim::PauliString<W>::from_str(\"X_\"), t.xs[0], {}},\n                    Flow<W>{stim::PauliString<W>::from_str(\"Z_\"), t.zs[0], {}},\n                    Flow<W>{stim::PauliString<W>::from_str(\"_X\"), t.xs[1], {}},\n                    Flow<W>{stim::PauliString<W>::from_str(\"_Z\"), t.zs[1], {}},\n                };\n            }\n            return {\n                Flow<W>{stim::PauliString<W>::from_str(\"X\"), t.xs[0], {}},\n                Flow<W>{stim::PauliString<W>::from_str(\"Z\"), t.zs[0], {}},\n            };\n        }\n        std::vector<Flow<W>> out;\n        for (const auto &c : flow_data) {\n            out.push_back(Flow<W>::from_str(c));\n        }\n        return out;\n    }\n\n    std::vector<std::vector<std::complex<float>>> unitary() const;\n\n    bool is_symmetric() const;\n    GateType hadamard_conjugated(bool ignoring_sign) const;\n\n    /// Determines if the gate has a specified unitary matrix.\n    ///\n    /// Some unitary gates, such as SPP, don't have a specified matrix because the\n    /// matrix depends crucially on the targets.\n    bool has_known_unitary_matrix() const;\n\n    /// Converts a single qubit unitary gate into an euler-angles rotation.\n    ///\n    /// Returns:\n    ///     {theta, phi, lambda} using the same convention as qiskit.\n    ///     Each angle is in radians.\n    ///     For stabilizer operations, every angle will be a multiple of pi/2.\n    ///\n    ///     The unitary matrix U of the operation can be recovered (up to global phase)\n    ///     by computing U = RotZ(phi) * RotY(theta) * RotZ(lambda).\n    std::array<float, 3> to_euler_angles() const;\n\n    /// Converts a single qubit unitary gate into an axis-angle rotation.\n    ///\n    /// Returns:\n    ///     An array {x, y, z, a}.\n    ///     <x, y, z> is a unit vector indicating the axis of rotation.\n    ///     <a> is the angle of rotation in radians.\n    std::array<float, 4> to_axis_angle() const;\n};\n\ninline bool _case_insensitive_mismatch(std::string_view text1, std::string_view text2) {\n    if (text1.size() != text2.size()) {\n        return true;\n    }\n    bool failed = false;\n    for (size_t k = 0; k < text1.size(); k++) {\n        failed |= toupper(text1[k]) != text2[k];\n    }\n    return failed;\n}\n\nstruct GateDataMapHashEntry {\n    GateType id = GateType::NOT_A_GATE;\n    std::string_view expected_name;\n};\n\nstruct GateDataMap {\n   private:\n    void add_gate(bool &failed, const Gate &data);\n    void add_gate_alias(bool &failed, const char *alt_name, const char *canon_name);\n    void add_gate_data_annotations(bool &failed);\n    void add_gate_data_blocks(bool &failed);\n    void add_gate_data_heralded(bool &failed);\n    void add_gate_data_collapsing(bool &failed);\n    void add_gate_data_controlled(bool &failed);\n    void add_gate_data_hada(bool &failed);\n    void add_gate_data_noisy(bool &failed);\n    void add_gate_data_pauli(bool &failed);\n    void add_gate_data_period_3(bool &failed);\n    void add_gate_data_period_4(bool &failed);\n    void add_gate_data_pp(bool &failed);\n    void add_gate_data_swaps(bool &failed);\n    void add_gate_data_pair_measure(bool &failed);\n    void add_gate_data_pauli_product(bool &failed);\n\n   public:\n    std::array<GateDataMapHashEntry, 512> hashed_name_to_gate_type_table;\n    std::array<Gate, NUM_DEFINED_GATES> items;\n    GateDataMap();\n\n    inline const Gate &operator[](GateType g) const {\n        return items[(uint64_t)g];\n    }\n\n    inline const Gate &at(GateType g) const {\n        if ((uint8_t)g >= items.size()) {\n            throw std::out_of_range(\"Gate index out of range\");\n        }\n        return items[(uint8_t)g];\n    }\n\n    inline const Gate &at(std::string_view text) const {\n        auto h = gate_name_to_hash(text);\n        const auto &entry = hashed_name_to_gate_type_table[h];\n        if (_case_insensitive_mismatch(text, entry.expected_name)) {\n            throw std::out_of_range(\"Gate not found: '\" + std::string(text) + \"'\");\n        }\n        // Canonicalize.\n        return (*this)[entry.id];\n    }\n\n    inline bool has(std::string_view text) const {\n        auto h = gate_name_to_hash(text);\n        const auto &entry = hashed_name_to_gate_type_table[h];\n        return !_case_insensitive_mismatch(text, entry.expected_name);\n    }\n};\n\nextern const GateDataMap GATE_DATA;\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/gates/gates.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\n#include <iostream>\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(gate_data_hash_all_gate_names) {\n    std::vector<std::string> names;\n    for (const auto &gate : GATE_DATA.items) {\n        names.emplace_back(gate.name);\n    }\n    size_t result = 0;\n    benchmark_go([&]() {\n        for (const auto &s : names) {\n            result += gate_name_to_hash(s);\n        }\n    })\n        .goal_nanos(2.7 * names.size())\n        .show_rate(\"GateHashes\", names.size());\n    if (result == 0) {\n        std::cerr << \"impossible\";\n    }\n}\n"
  },
  {
    "path": "src/stim/gates/gates.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\n#include \"stim/gates/gates.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/stabilizers/flow.h\"\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\npybind11::object gate_num_parens_argument_range(const GateTypeWrapper &self_id) {\n    const auto &self = GATE_DATA.at(self_id.type);\n    auto r = pybind11::module::import(\"builtins\").attr(\"range\");\n    if (self.arg_count == ARG_COUNT_SYGIL_ZERO_OR_ONE) {\n        return r(2);\n    }\n    if (self.arg_count == ARG_COUNT_SYGIL_ANY) {\n        return r(256);\n    }\n    return r(self.arg_count, self.arg_count + 1);\n}\nstd::vector<std::string_view> gate_aliases(const GateTypeWrapper &self_id) {\n    std::vector<std::string_view> aliases;\n    for (const auto &h : GATE_DATA.hashed_name_to_gate_type_table) {\n        if (h.id == self_id.type) {\n            aliases.push_back(h.expected_name);\n        }\n    }\n    std::sort(aliases.begin(), aliases.end());\n    return aliases;\n}\n\npybind11::object gate_tableau(const GateTypeWrapper &self_id) {\n    const auto &self = GATE_DATA.at(self_id.type);\n    if (self.flags & GATE_IS_UNITARY) {\n        return pybind11::cast(self.tableau<MAX_BITWORD_WIDTH>());\n    }\n    return pybind11::none();\n}\npybind11::object gate_unitary_matrix(const GateTypeWrapper &self_id) {\n    const Gate &self = GATE_DATA.at(self_id.type);\n    if (self.has_known_unitary_matrix()) {\n        auto r = self.unitary();\n        auto n = r.size();\n        std::complex<float> *buffer = new std::complex<float>[n * n];\n        for (size_t a = 0; a < n; a++) {\n            for (size_t b = 0; b < n; b++) {\n                buffer[b + a * n] = r[a][b];\n            }\n        }\n\n        pybind11::capsule free_when_done(buffer, [](void *f) {\n            delete[] reinterpret_cast<std::complex<float> *>(f);\n        });\n\n        return pybind11::array_t<std::complex<float>>(\n            {(pybind11::ssize_t)n, (pybind11::ssize_t)n},\n            {(pybind11::ssize_t)(n * sizeof(std::complex<float>)), (pybind11::ssize_t)sizeof(std::complex<float>)},\n            buffer,\n            free_when_done);\n    }\n    return pybind11::none();\n}\n\npybind11::class_<GateTypeWrapper> stim_pybind::pybind_gate_data(pybind11::module &m) {\n    return pybind11::class_<GateTypeWrapper>(\n        m,\n        \"GateData\",\n        clean_doc_string(R\"DOC(\n            Details about a gate supported by stim.\n\n            Examples:\n                >>> import stim\n                >>> stim.gate_data('h').name\n                'H'\n                >>> stim.gate_data('h').is_unitary\n                True\n                >>> stim.gate_data('h').tableau\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+X\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_gate_data_methods(pybind11::module &m, pybind11::class_<GateTypeWrapper> &c) {\n    c.def(\n        pybind11::init([](const char *name) -> GateTypeWrapper {\n            return {GATE_DATA.at(name).id};\n        }),\n        pybind11::arg(\"name\"),\n        clean_doc_string(R\"DOC(\n            Finds gate data for the named gate.\n\n            Examples:\n                >>> import stim\n                >>> stim.GateData('H').is_unitary\n                True\n        )DOC\")\n            .data());\n\n    m.def(\n        \"gate_data\",\n        [](const pybind11::object &name) -> pybind11::object {\n            if (!name.is_none()) {\n                return pybind11::cast(GateTypeWrapper{GATE_DATA.at(pybind11::cast<std::string_view>(name)).id});\n            }\n\n            std::map<std::string_view, GateTypeWrapper> result;\n            for (const auto &g : GATE_DATA.items) {\n                if (g.id != GateType::NOT_A_GATE) {\n                    result.insert({g.name, GateTypeWrapper{g.id}});\n                }\n            }\n            return pybind11::cast(result);\n        },\n        pybind11::arg(\"name\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @overload def gate_data(name: str) -> stim.GateData:\n            @overload def gate_data() -> Dict[str, stim.GateData]:\n            @signature def gate_data(name: Optional[str] = None) -> Union[str, Dict[str, stim.GateData]]:\n            Returns gate data for the given named gate, or all gates.\n\n            Examples:\n                >>> import stim\n                >>> stim.gate_data('cnot').aliases\n                ['CNOT', 'CX', 'ZCX']\n                >>> stim.gate_data('cnot').is_two_qubit_gate\n                True\n                >>> gate_dict = stim.gate_data()\n                >>> len(gate_dict) > 50\n                True\n                >>> gate_dict['MX'].produces_measurements\n                True\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"name\",\n        [](const GateTypeWrapper &self_id) -> std::string_view {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.name;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the canonical name of the gate.\n\n            Examples:\n                >>> import stim\n                >>> stim.gate_data('H').name\n                'H'\n                >>> stim.gate_data('cnot').name\n                'CX'\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"aliases\",\n        &gate_aliases,\n        clean_doc_string(R\"DOC(\n            Returns all aliases that can be used to name the gate.\n\n            Although gates can be referred to by lower case and mixed\n            case named, the result only includes upper cased aliases.\n\n            Examples:\n                >>> import stim\n                >>> stim.gate_data('H').aliases\n                ['H', 'H_XZ']\n                >>> stim.gate_data('cnot').aliases\n                ['CNOT', 'CX', 'ZCX']\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__repr__\",\n        [](const GateTypeWrapper &self_id) -> std::string {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            std::stringstream ss;\n            ss << \"stim.gate_data('\" << self.name << \"')\";\n            return ss.str();\n        },\n        \"Returns text that is a valid python expression evaluating to an equivalent `stim.GateData`.\");\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two GateData instances are identical.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two GateData instances are not identical.\");\n\n    c.def(\n        \"__str__\",\n        [](const GateTypeWrapper &self_id) -> std::string {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            std::stringstream ss;\n            auto b = [](bool x) -> const char * {\n                return x ? \"True\" : \"False\";\n            };\n            auto v = [](const pybind11::object &obj) {\n                pybind11::object obj_repr = pybind11::repr(obj);\n                std::string result;\n                for (char c : pybind11::cast<std::string_view>(obj_repr)) {\n                    result.push_back(c);\n                    if (c == '\\n') {\n                        result.append(\"    \");\n                    }\n                }\n                return result;\n            };\n            ss << \"stim.GateData {\\n\";\n            ss << \"    .name = '\" << self.name << \"'\\n\";\n            ss << \"    .aliases = \" << v(pybind11::cast(gate_aliases(self_id))) << \"\\n\";\n            ss << \"    .is_noisy_gate = \" << b(self.flags & GATE_IS_NOISY) << \"\\n\";\n            ss << \"    .is_reset = \" << b(self.flags & GATE_IS_RESET) << \"\\n\";\n            ss << \"    .is_single_qubit_gate = \" << b(self.flags & GATE_IS_SINGLE_QUBIT_GATE) << \"\\n\";\n            ss << \"    .is_two_qubit_gate = \" << b(self.flags & GATE_TARGETS_PAIRS) << \"\\n\";\n            ss << \"    .is_unitary = \" << b(self.flags & GATE_IS_UNITARY) << \"\\n\";\n            ss << \"    .num_parens_arguments_range = \" << v(gate_num_parens_argument_range(self_id)) << \"\\n\";\n            ss << \"    .produces_measurements = \" << b(self.flags & GATE_PRODUCES_RESULTS) << \"\\n\";\n            ss << \"    .takes_measurement_record_targets = \"\n               << b(self.flags & (GATE_CAN_TARGET_BITS | GATE_ONLY_TARGETS_MEASUREMENT_RECORD)) << \"\\n\";\n            ss << \"    .takes_pauli_targets = \" << b(self.flags & GATE_TARGETS_PAULI_STRING) << \"\\n\";\n            if (self.flags & GATE_IS_UNITARY) {\n                ss << \"    .tableau = \" << v(gate_tableau(self_id)) << \"\\n\";\n                ss << \"    .unitary_matrix = np.array(\" << v(pybind11::cast(self.unitary()))\n                   << \", dtype=np.complex64)\\n\";\n            }\n            ss << \"}\";\n            return ss.str();\n        },\n        \"Returns text describing the gate data.\");\n\n    c.def_property_readonly(\n        \"tableau\",\n        &gate_tableau,\n        clean_doc_string(R\"DOC(\n            @signature def tableau(self) -> Optional[stim.Tableau]:\n            Returns the gate's tableau, or None if the gate has no tableau.\n\n            Examples:\n                >>> import stim\n                >>> print(stim.gate_data('M').tableau)\n                None\n                >>> stim.gate_data('H').tableau\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+X\"),\n                    ],\n                )\n                >>> stim.gate_data('ISWAP').tableau\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+ZY\"),\n                        stim.PauliString(\"+YZ\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+_Z\"),\n                        stim.PauliString(\"+Z_\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"unitary_matrix\",\n        &gate_unitary_matrix,\n        clean_doc_string(R\"DOC(\n            @signature def unitary_matrix(self) -> Optional[np.ndarray]:\n            Returns the gate's unitary matrix, or None if the gate isn't unitary.\n\n            Examples:\n                >>> import stim\n\n                >>> print(stim.gate_data('M').unitary_matrix)\n                None\n\n                >>> stim.gate_data('X').unitary_matrix\n                array([[0.+0.j, 1.+0.j],\n                       [1.+0.j, 0.+0.j]], dtype=complex64)\n\n                >>> stim.gate_data('ISWAP').unitary_matrix\n                array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                       [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j],\n                       [0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j],\n                       [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]], dtype=complex64)\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_unitary\",\n        [](const GateTypeWrapper &self_id) -> bool {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.flags & GATE_IS_UNITARY;\n        },\n        clean_doc_string(R\"DOC(\n            Returns whether or not the gate is a unitary gate.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('H').is_unitary\n                True\n                >>> stim.gate_data('CX').is_unitary\n                True\n\n                >>> stim.gate_data('R').is_unitary\n                False\n                >>> stim.gate_data('M').is_unitary\n                False\n                >>> stim.gate_data('MXX').is_unitary\n                False\n                >>> stim.gate_data('X_ERROR').is_unitary\n                False\n                >>> stim.gate_data('CORRELATED_ERROR').is_unitary\n                False\n                >>> stim.gate_data('MPP').is_unitary\n                False\n                >>> stim.gate_data('DETECTOR').is_unitary\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_parens_arguments_range\",\n        &gate_num_parens_argument_range,\n        clean_doc_string(R\"DOC(\n            @signature def num_parens_arguments_range(self) -> range:\n            Returns the min/max parens arguments taken by the gate, as a python range.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('M').num_parens_arguments_range\n                range(0, 2)\n                >>> list(stim.gate_data('M').num_parens_arguments_range)\n                [0, 1]\n                >>> list(stim.gate_data('R').num_parens_arguments_range)\n                [0]\n                >>> list(stim.gate_data('H').num_parens_arguments_range)\n                [0]\n                >>> list(stim.gate_data('X_ERROR').num_parens_arguments_range)\n                [1]\n                >>> list(stim.gate_data('PAULI_CHANNEL_1').num_parens_arguments_range)\n                [3]\n                >>> list(stim.gate_data('PAULI_CHANNEL_2').num_parens_arguments_range)\n                [15]\n                >>> stim.gate_data('DETECTOR').num_parens_arguments_range\n                range(0, 256)\n                >>> list(stim.gate_data('OBSERVABLE_INCLUDE').num_parens_arguments_range)\n                [1]\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_reset\",\n        [](const GateTypeWrapper &self_id) -> bool {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.flags & GATE_IS_RESET;\n        },\n        clean_doc_string(R\"DOC(\n            Returns whether or not the gate resets qubits in any basis.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('R').is_reset\n                True\n                >>> stim.gate_data('RX').is_reset\n                True\n                >>> stim.gate_data('MR').is_reset\n                True\n\n                >>> stim.gate_data('M').is_reset\n                False\n                >>> stim.gate_data('MXX').is_reset\n                False\n                >>> stim.gate_data('MPP').is_reset\n                False\n                >>> stim.gate_data('H').is_reset\n                False\n                >>> stim.gate_data('CX').is_reset\n                False\n                >>> stim.gate_data('HERALDED_ERASE').is_reset\n                False\n                >>> stim.gate_data('DEPOLARIZE2').is_reset\n                False\n                >>> stim.gate_data('X_ERROR').is_reset\n                False\n                >>> stim.gate_data('CORRELATED_ERROR').is_reset\n                False\n                >>> stim.gate_data('DETECTOR').is_reset\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_single_qubit_gate\",\n        [](const GateTypeWrapper &self_id) -> bool {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.flags & GATE_IS_SINGLE_QUBIT_GATE;\n        },\n        clean_doc_string(R\"DOC(\n            Returns whether or not the gate is a single qubit gate.\n\n            Single qubit gates apply separately to each of their targets.\n\n            Variable-qubit gates like CORRELATED_ERROR and MPP are not\n            considered single qubit gates.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('H').is_single_qubit_gate\n                True\n                >>> stim.gate_data('R').is_single_qubit_gate\n                True\n                >>> stim.gate_data('M').is_single_qubit_gate\n                True\n                >>> stim.gate_data('X_ERROR').is_single_qubit_gate\n                True\n\n                >>> stim.gate_data('CX').is_single_qubit_gate\n                False\n                >>> stim.gate_data('MXX').is_single_qubit_gate\n                False\n                >>> stim.gate_data('CORRELATED_ERROR').is_single_qubit_gate\n                False\n                >>> stim.gate_data('MPP').is_single_qubit_gate\n                False\n                >>> stim.gate_data('DETECTOR').is_single_qubit_gate\n                False\n                >>> stim.gate_data('TICK').is_single_qubit_gate\n                False\n                >>> stim.gate_data('REPEAT').is_single_qubit_gate\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"flows\",\n        [](const GateTypeWrapper &self_id) -> pybind11::object {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            auto f = self.flows<MAX_BITWORD_WIDTH>();\n            if (f.empty()) {\n                return pybind11::none();\n            }\n            std::vector<Flow<MAX_BITWORD_WIDTH>> results;\n            for (const auto &e : f) {\n                results.push_back(e);\n            }\n            return pybind11::cast(results);\n        },\n        clean_doc_string(R\"DOC(\n            @signature def flows(self) -> Optional[List[stim.Flow]]:\n            Returns stabilizer flow generators for the gate, or else None.\n\n            A stabilizer flow describes an input-output relationship that the gate\n            satisfies, where an input pauli string is transformed into an output\n            pauli string mediated by certain measurement results.\n\n            Caution: this method returns None for variable-target-count gates like MPP.\n            Not because MPP has no stabilizer flows, but because its stabilizer flows\n            depend on how many qubits it targets and what basis it targets them in.\n\n            Returns:\n                A list of stim.Flow instances representing the generators.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('H').flows\n                [stim.Flow(\"X -> Z\"), stim.Flow(\"Z -> X\")]\n\n                >>> for e in stim.gate_data('ISWAP').flows:\n                ...     print(e)\n                X_ -> ZY\n                Z_ -> _Z\n                _X -> YZ\n                _Z -> Z_\n\n                >>> for e in stim.gate_data('MXX').flows:\n                ...     print(e)\n                X_ -> X_\n                _X -> _X\n                ZZ -> ZZ\n                XX -> rec[-1]\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_symmetric_gate\",\n        [](const GateTypeWrapper &self_id) -> bool {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.is_symmetric();\n        },\n        clean_doc_string(R\"DOC(\n            Returns whether or not the gate is the same when its targets are swapped.\n\n            A two qubit gate is symmetric if it doesn't matter if you swap its targets. It\n            is unaffected when conjugated by the SWAP gate.\n\n            Single qubit gates are vacuously symmetric. A multi-qubit gate is symmetric if\n            swapping any two of its targets has no effect.\n\n            Note that this method is for symmetry *without broadcasting*. For example, SWAP\n            is symmetric even though SWAP 1 2 3 4 isn't equal to SWAP 1 3 2 4.\n\n            Returns:\n                True if the gate is symmetric.\n                False if the gate isn't symmetric.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('CX').is_symmetric_gate\n                False\n                >>> stim.gate_data('CZ').is_symmetric_gate\n                True\n                >>> stim.gate_data('ISWAP').is_symmetric_gate\n                True\n                >>> stim.gate_data('CXSWAP').is_symmetric_gate\n                False\n                >>> stim.gate_data('MXX').is_symmetric_gate\n                True\n                >>> stim.gate_data('DEPOLARIZE2').is_symmetric_gate\n                True\n                >>> stim.gate_data('PAULI_CHANNEL_2').is_symmetric_gate\n                False\n                >>> stim.gate_data('H').is_symmetric_gate\n                True\n                >>> stim.gate_data('R').is_symmetric_gate\n                True\n                >>> stim.gate_data('X_ERROR').is_symmetric_gate\n                True\n                >>> stim.gate_data('CORRELATED_ERROR').is_symmetric_gate\n                False\n                >>> stim.gate_data('MPP').is_symmetric_gate\n                False\n                >>> stim.gate_data('DETECTOR').is_symmetric_gate\n                False\n        )DOC\")\n            .data());\n\n    c.def(\n        \"hadamard_conjugated\",\n        [](const GateTypeWrapper &self_id, bool ignoring_sign) -> pybind11::object {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            GateType g = self.hadamard_conjugated(ignoring_sign);\n            if (g == GateType::NOT_A_GATE) {\n                return pybind11::none();\n            }\n            return pybind11::cast(GateTypeWrapper{g});\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"unsigned\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def hadamard_conjugated(self, *, unsigned: bool = False) -> Optional[stim.GateData]:\n            Returns a stim gate equivalent to this gate conjugated by Hadamard gates.\n\n            The Hadamard conjugate can be thought of as the XZ dual of the gate; the gate\n            you get by exchanging the X and Z bases. For example, a SQRT_X will become a\n            SQRT_Z and a CX gate will switch directions into an XCZ.\n\n            If stim doesn't define a gate equivalent to conjugating this gate by Hadamards,\n            the value `None` is returned.\n\n            Args:\n                unsigned: Defaults to False. When False, the returned gate must be *exactly*\n                    the Hadamard conjugation of this gate. When True, the returned gate must\n                    have the same flows but the sign of the flows can be different (i.e.\n                    the returned gate must be the Hadamard conjugate up to Pauli gate\n                    differences).\n\n            Returns:\n                A stim.GateData instance of the Hadamard conjugate, if it exists in stim.\n\n                None, if stim doesn't define a gate equal to the Hadamard conjugate.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('X').hadamard_conjugated()\n                stim.gate_data('Z')\n                >>> stim.gate_data('CX').hadamard_conjugated()\n                stim.gate_data('XCZ')\n                >>> stim.gate_data('RY').hadamard_conjugated() is None\n                True\n                >>> stim.gate_data('RY').hadamard_conjugated(unsigned=True)\n                stim.gate_data('RY')\n                >>> stim.gate_data('ISWAP').hadamard_conjugated(unsigned=True) is None\n                True\n                >>> stim.gate_data('SWAP').hadamard_conjugated()\n                stim.gate_data('SWAP')\n                >>> stim.gate_data('CXSWAP').hadamard_conjugated()\n                stim.gate_data('SWAPCX')\n                >>> stim.gate_data('MXX').hadamard_conjugated()\n                stim.gate_data('MZZ')\n                >>> stim.gate_data('DEPOLARIZE1').hadamard_conjugated()\n                stim.gate_data('DEPOLARIZE1')\n                >>> stim.gate_data('X_ERROR').hadamard_conjugated()\n                stim.gate_data('Z_ERROR')\n                >>> stim.gate_data('H_XY').hadamard_conjugated()\n                stim.gate_data('H_NYZ')\n                >>> stim.gate_data('DETECTOR').hadamard_conjugated(unsigned=True)\n                stim.gate_data('DETECTOR')\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_two_qubit_gate\",\n        [](const GateTypeWrapper &self_id) -> bool {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.flags & GATE_TARGETS_PAIRS;\n        },\n        clean_doc_string(R\"DOC(\n            Returns whether or not the gate is a two qubit gate.\n\n            Two qubit gates must be given an even number of targets.\n\n            Variable-qubit gates like CORRELATED_ERROR and MPP are not\n            considered two qubit gates.\n\n            Returns:\n                True if the gate is a two qubit gate.\n                False if the gate isn't a two qubit gate.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('CX').is_two_qubit_gate\n                True\n                >>> stim.gate_data('MXX').is_two_qubit_gate\n                True\n\n                >>> stim.gate_data('H').is_two_qubit_gate\n                False\n                >>> stim.gate_data('R').is_two_qubit_gate\n                False\n                >>> stim.gate_data('M').is_two_qubit_gate\n                False\n                >>> stim.gate_data('X_ERROR').is_two_qubit_gate\n                False\n                >>> stim.gate_data('CORRELATED_ERROR').is_two_qubit_gate\n                False\n                >>> stim.gate_data('MPP').is_two_qubit_gate\n                False\n                >>> stim.gate_data('DETECTOR').is_two_qubit_gate\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"is_noisy_gate\",\n        [](const GateTypeWrapper &self_id) -> bool {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.flags & GATE_IS_NOISY;\n        },\n        clean_doc_string(R\"DOC(\n            Returns whether or not the gate can produce noise.\n\n            Note that measurement operations are considered noisy,\n            because for example `M(0.001) 2 3 5` will include\n            noise that flips its result 0.1% of the time.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('M').is_noisy_gate\n                True\n                >>> stim.gate_data('MXX').is_noisy_gate\n                True\n                >>> stim.gate_data('X_ERROR').is_noisy_gate\n                True\n                >>> stim.gate_data('CORRELATED_ERROR').is_noisy_gate\n                True\n                >>> stim.gate_data('MPP').is_noisy_gate\n                True\n\n                >>> stim.gate_data('H').is_noisy_gate\n                False\n                >>> stim.gate_data('CX').is_noisy_gate\n                False\n                >>> stim.gate_data('R').is_noisy_gate\n                False\n                >>> stim.gate_data('DETECTOR').is_noisy_gate\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"produces_measurements\",\n        [](const GateTypeWrapper &self_id) -> bool {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.flags & GATE_PRODUCES_RESULTS;\n        },\n        clean_doc_string(R\"DOC(\n            Returns whether or not the gate produces measurement results.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('M').produces_measurements\n                True\n                >>> stim.gate_data('MRY').produces_measurements\n                True\n                >>> stim.gate_data('MXX').produces_measurements\n                True\n                >>> stim.gate_data('MPP').produces_measurements\n                True\n                >>> stim.gate_data('HERALDED_ERASE').produces_measurements\n                True\n\n                >>> stim.gate_data('H').produces_measurements\n                False\n                >>> stim.gate_data('CX').produces_measurements\n                False\n                >>> stim.gate_data('R').produces_measurements\n                False\n                >>> stim.gate_data('X_ERROR').produces_measurements\n                False\n                >>> stim.gate_data('CORRELATED_ERROR').produces_measurements\n                False\n                >>> stim.gate_data('DETECTOR').produces_measurements\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"takes_pauli_targets\",\n        [](const GateTypeWrapper &self_id) -> bool {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.flags & GATE_TARGETS_PAULI_STRING;\n        },\n        clean_doc_string(R\"DOC(\n            Returns whether or not the gate expects pauli targets.\n\n            For example, `CORRELATED_ERROR` takes targets like `X0` and `Y1`\n            instead of `0` or `1`.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('CORRELATED_ERROR').takes_pauli_targets\n                True\n                >>> stim.gate_data('MPP').takes_pauli_targets\n                True\n\n                >>> stim.gate_data('H').takes_pauli_targets\n                False\n                >>> stim.gate_data('CX').takes_pauli_targets\n                False\n                >>> stim.gate_data('R').takes_pauli_targets\n                False\n                >>> stim.gate_data('M').takes_pauli_targets\n                False\n                >>> stim.gate_data('MRY').takes_pauli_targets\n                False\n                >>> stim.gate_data('MXX').takes_pauli_targets\n                False\n                >>> stim.gate_data('X_ERROR').takes_pauli_targets\n                False\n                >>> stim.gate_data('DETECTOR').takes_pauli_targets\n                False\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"inverse\",\n        [](const GateTypeWrapper &self_id) -> pybind11::object {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            if (self.flags & GATE_IS_UNITARY) {\n                return pybind11::cast(GateTypeWrapper{self.best_candidate_inverse_id});\n            }\n            return pybind11::none();\n        },\n        clean_doc_string(R\"DOC(\n            @signature def inverse(self) -> Optional[stim.GateData]:\n            The inverse of the gate, or None if it has no inverse.\n\n            The inverse V of a gate U must have the property that V undoes the effects of U\n            and that U undoes the effects of V. In particular, the circuit\n\n                U 0 1\n                V 0 1\n\n            should be equivalent to doing nothing at all.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('H').inverse\n                stim.gate_data('H')\n\n                >>> stim.gate_data('CX').inverse\n                stim.gate_data('CX')\n\n                >>> stim.gate_data('S').inverse\n                stim.gate_data('S_DAG')\n\n                >>> stim.gate_data('CXSWAP').inverse\n                stim.gate_data('SWAPCX')\n\n                >>> stim.gate_data('X_ERROR').inverse is None\n                True\n                >>> stim.gate_data('M').inverse is None\n                True\n                >>> stim.gate_data('R').inverse is None\n                True\n                >>> stim.gate_data('DETECTOR').inverse is None\n                True\n                >>> stim.gate_data('TICK').inverse is None\n                True\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"generalized_inverse\",\n        [](const GateTypeWrapper &self_id) -> GateTypeWrapper {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return GateTypeWrapper{self.best_candidate_inverse_id};\n        },\n        clean_doc_string(R\"DOC(\n            The closest-thing-to-an-inverse for the gate, if forced to pick something.\n\n            The generalized inverse of a unitary gate U is its actual inverse U^-1.\n\n            The generalized inverse of a reset or measurement gate U is a gate V such that,\n            for every stabilizer flow that U has, V has the time reverse of that flow (up\n            to Pauli feedback, with potentially more flows). For example, the time-reverse\n            of R is MR because R has the single flow 1 -> Z and MR has the time reversed\n            flow Z -> rec[-1].\n\n            The generalized inverse of noise like X_ERROR is just the same noise.\n\n            The generalized inverse of an annotation like TICK is just the same annotation.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('H').generalized_inverse\n                stim.gate_data('H')\n\n                >>> stim.gate_data('CXSWAP').generalized_inverse\n                stim.gate_data('SWAPCX')\n\n                >>> stim.gate_data('X_ERROR').generalized_inverse\n                stim.gate_data('X_ERROR')\n\n                >>> stim.gate_data('MX').generalized_inverse\n                stim.gate_data('MX')\n\n                >>> stim.gate_data('MRY').generalized_inverse\n                stim.gate_data('MRY')\n\n                >>> stim.gate_data('R').generalized_inverse\n                stim.gate_data('M')\n\n                >>> stim.gate_data('DETECTOR').generalized_inverse\n                stim.gate_data('DETECTOR')\n\n                >>> stim.gate_data('TICK').generalized_inverse\n                stim.gate_data('TICK')\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"takes_measurement_record_targets\",\n        [](const GateTypeWrapper &self_id) -> bool {\n            const Gate &self = GATE_DATA.at(self_id.type);\n            return self.flags & (GATE_CAN_TARGET_BITS | GATE_ONLY_TARGETS_MEASUREMENT_RECORD);\n        },\n        clean_doc_string(R\"DOC(\n            Returns whether or not the gate can accept rec targets.\n\n            For example, `CX` can take a measurement record target\n            like `CX rec[-1] 1`.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.gate_data('CX').takes_measurement_record_targets\n                True\n                >>> stim.gate_data('DETECTOR').takes_measurement_record_targets\n                True\n\n                >>> stim.gate_data('H').takes_measurement_record_targets\n                False\n                >>> stim.gate_data('SWAP').takes_measurement_record_targets\n                False\n                >>> stim.gate_data('R').takes_measurement_record_targets\n                False\n                >>> stim.gate_data('M').takes_measurement_record_targets\n                False\n                >>> stim.gate_data('MRY').takes_measurement_record_targets\n                False\n                >>> stim.gate_data('MXX').takes_measurement_record_targets\n                False\n                >>> stim.gate_data('X_ERROR').takes_measurement_record_targets\n                False\n                >>> stim.gate_data('CORRELATED_ERROR').takes_measurement_record_targets\n                False\n                >>> stim.gate_data('MPP').takes_measurement_record_targets\n                False\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/gates/gates.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_GATES_GATE_DATA_PYBIND_H\n#define _STIM_GATES_GATE_DATA_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/gates/gates.h\"\n\nnamespace stim_pybind {\n\nstruct GateTypeWrapper {\n    stim::GateType type;\n    inline bool operator==(const GateTypeWrapper &other) const {\n        return type == other.type;\n    }\n};\n\npybind11::class_<GateTypeWrapper> pybind_gate_data(pybind11::module &m);\nvoid pybind_gate_data_methods(pybind11::module &m, pybind11::class_<GateTypeWrapper> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/gates/gates.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gates/gates.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/cmd/command_help.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/str_util.h\"\n#include \"stim/util_bot/test_util.test.h\"\n#include \"stim/util_top/circuit_flow_generators.h\"\n#include \"stim/util_top/has_flow.h\"\n\nusing namespace stim;\n\nTEST(gate_data, lookup) {\n    ASSERT_TRUE(GATE_DATA.has(\"H\"));\n    ASSERT_FALSE(GATE_DATA.has(\"H2345\"));\n    ASSERT_EQ(GATE_DATA.at(\"H\").id, GATE_DATA.at(\"H_XZ\").id);\n    ASSERT_NE(GATE_DATA.at(\"H\").id, GATE_DATA.at(\"H_XY\").id);\n    ASSERT_THROW(GATE_DATA.at(\"MISSING\"), std::out_of_range);\n\n    ASSERT_TRUE(GATE_DATA.has(\"h\"));\n    ASSERT_TRUE(GATE_DATA.has(\"Cnot\"));\n\n    ASSERT_TRUE(GATE_DATA.at(\"h\").id == GATE_DATA.at(\"H\").id);\n    ASSERT_TRUE(GATE_DATA.at(\"H_xz\").id == GATE_DATA.at(\"H\").id);\n}\n\nTEST(gate_data, zero_flag_means_not_a_gate) {\n    ASSERT_EQ((GateType)0, GateType::NOT_A_GATE);\n    ASSERT_EQ(GATE_DATA[(GateType)0].id, (GateType)0);\n    ASSERT_EQ(GATE_DATA[(GateType)0].flags, GateFlags::NO_GATE_FLAG);\n    for (size_t k = 0; k < GATE_DATA.items.size(); k++) {\n        const auto &g = GATE_DATA[(GateType)k];\n        if (g.id != GateType::NOT_A_GATE) {\n            EXPECT_NE(g.flags, GateFlags::NO_GATE_FLAG) << g.name;\n        }\n    }\n}\n\nTEST(gate_data, one_step_to_canonical_gate) {\n    for (size_t k = 0; k < GATE_DATA.items.size(); k++) {\n        const auto &g = GATE_DATA[(GateType)k];\n        if (g.id != GateType::NOT_A_GATE) {\n            EXPECT_TRUE(g.id == (GateType)k || GATE_DATA[g.id].id == g.id) << g.name;\n        }\n    }\n}\n\nTEST(gate_data, hash_matches_storage_location) {\n    ASSERT_EQ((GateType)0, GateType::NOT_A_GATE);\n    ASSERT_EQ(GATE_DATA[(GateType)0].id, (GateType)0);\n    ASSERT_EQ(GATE_DATA[(GateType)0].flags, GateFlags::NO_GATE_FLAG);\n    for (size_t k = 0; k < GATE_DATA.items.size(); k++) {\n        const auto &g = GATE_DATA[(GateType)k];\n        EXPECT_EQ(g.id, (GateType)k) << g.name;\n        if (g.id != GateType::NOT_A_GATE) {\n            EXPECT_EQ(GATE_DATA.hashed_name_to_gate_type_table[gate_name_to_hash(g.name)].id, g.id) << g.name;\n        }\n    }\n}\n\ntemplate <size_t W>\nstatic std::pair<std::vector<PauliString<W>>, std::vector<PauliString<W>>> circuit_output_eq_val(\n    const Circuit &circuit) {\n    // CAUTION: this is not 100% reliable when measurement count is larger than 1.\n    TableauSimulator<W> sim1(INDEPENDENT_TEST_RNG(), circuit.count_qubits(), -1);\n    TableauSimulator<W> sim2(INDEPENDENT_TEST_RNG(), circuit.count_qubits(), +1);\n    sim1.safe_do_circuit(circuit);\n    sim2.safe_do_circuit(circuit);\n    return {sim1.canonical_stabilizers(), sim2.canonical_stabilizers()};\n}\n\ntemplate <size_t W>\nbool is_decomposition_correct(const Gate &gate) {\n    const char *decomposition = gate.h_s_cx_m_r_decomposition;\n    if (decomposition == nullptr) {\n        return false;\n    }\n\n    Circuit original;\n    original.safe_append(CircuitInstruction(gate.id, {}, gate_decomposition_help_targets_for_gate_type(gate.id), \"\"));\n    uint32_t n = original.count_qubits();\n\n    Circuit epr;\n    for (uint32_t q = 0; q < n; q++) {\n        epr.safe_append_u(\"H\", {q});\n    }\n    for (uint32_t q = 0; q < n; q++) {\n        epr.safe_append_u(\"CNOT\", {q, q + n});\n    }\n\n    Circuit circuit1 = epr + original;\n    Circuit circuit2 = epr + Circuit(decomposition);\n\n    // Reset gates make the ancillary qubits irrelevant because the final value is unrelated to the initial value.\n    // So, for reset gates, discard the ancillary qubits.\n    // CAUTION: this could give false positives if \"partial reset\" gates are added in the future.\n    //          (E.g. a two qubit gate that resets only one of the qubits.)\n    if ((gate.flags & GATE_IS_RESET) && !(gate.flags & GATE_PRODUCES_RESULTS)) {\n        for (uint32_t q = 0; q < n; q++) {\n            circuit1.safe_append_u(\"R\", {q + n});\n            circuit2.safe_append_u(\"R\", {q + n});\n        }\n    }\n\n    for (const auto &op : circuit2.operations) {\n        if (op.gate_type != GateType::CX && op.gate_type != GateType::H && op.gate_type != GateType::S &&\n            op.gate_type != GateType::M && op.gate_type != GateType::R) {\n            return false;\n        }\n    }\n\n    auto v1 = circuit_output_eq_val<W>(circuit1);\n    auto v2 = circuit_output_eq_val<W>(circuit2);\n    return v1 == v2;\n}\n\nTEST_EACH_WORD_SIZE_W(gate_data, decompositions_are_correct, {\n    for (const auto &g : GATE_DATA.items) {\n        if (g.flags & GATE_IS_UNITARY) {\n            EXPECT_TRUE(g.h_s_cx_m_r_decomposition != nullptr) << g.name;\n        }\n        if (g.h_s_cx_m_r_decomposition != nullptr) {\n            EXPECT_TRUE(is_decomposition_correct<W>(g)) << g.name;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(gate_data, unitary_inverses_are_correct, {\n    for (const auto &g : GATE_DATA.items) {\n        if (g.has_known_unitary_matrix()) {\n            auto g_t_inv = g.tableau<W>().inverse(false);\n            auto g_inv_t = GATE_DATA[g.best_candidate_inverse_id].tableau<W>();\n            EXPECT_EQ(g_t_inv, g_inv_t) << g.name;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(gate_data, stabilizer_flows_are_correct, {\n    for (const auto &g : GATE_DATA.items) {\n        auto flows = g.flows<W>();\n        if (flows.empty()) {\n            continue;\n        }\n        std::vector<GateTarget> targets = gate_decomposition_help_targets_for_gate_type(g.id);\n\n        Circuit c;\n        c.safe_append(CircuitInstruction(g.id, {}, targets, \"\"));\n        auto rng = INDEPENDENT_TEST_RNG();\n        auto r = sample_if_circuit_has_stabilizer_flows<W>(256, rng, c, flows);\n        for (uint32_t fk = 0; fk < (uint32_t)flows.size(); fk++) {\n            EXPECT_TRUE(r[fk]) << \"gate \" << g.name << \" has an unsatisfied flow: \" << flows[fk];\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(gate_data, stabilizer_flows_are_also_correct_for_decomposed_circuit, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (const auto &g : GATE_DATA.items) {\n        auto flows = g.flows<W>();\n        if (flows.empty()) {\n            continue;\n        }\n        std::vector<GateTarget> targets = gate_decomposition_help_targets_for_gate_type(g.id);\n\n        Circuit c(g.h_s_cx_m_r_decomposition);\n        auto r = sample_if_circuit_has_stabilizer_flows<W>(256, rng, c, flows);\n        for (uint32_t fk = 0; fk < (uint32_t)flows.size(); fk++) {\n            EXPECT_TRUE(r[fk]) << \"gate \" << g.name << \" has a decomposition with an unsatisfied flow: \" << flows[fk];\n        }\n    }\n})\n\nstd::array<std::complex<float>, 4> canonicalize_global_phase(std::array<std::complex<float>, 4> v) {\n    for (std::complex<float> pivot : v) {\n        if (std::abs(pivot) > 1e-5) {\n            for (auto &t : v) {\n                t /= pivot;\n            }\n            return v;\n        }\n    }\n    return v;\n}\n\nvoid expect_unitaries_close_up_global_phase(\n    const Gate &g, std::array<std::complex<float>, 4> u1, std::array<std::complex<float>, 4> u2) {\n    u1 = canonicalize_global_phase(u1);\n    u2 = canonicalize_global_phase(u2);\n    for (size_t k = 0; k < 4; k++) {\n        if (std::abs(u1[k] - u2[k]) > 1e-5) {\n            std::stringstream out;\n            out << g.name << \":\\n\";\n            for (size_t k2 = 0; k2 < 4; k2++) {\n                out << \"    \" << u1[k2] << \" vs \" << u2[k2] << \"\\n\";\n            }\n            EXPECT_EQ(u1, u2) << out.str() << \"\\n\" << comma_sep(g.to_euler_angles(), \",\");\n            return;\n        }\n    }\n    EXPECT_TRUE(true);\n}\n\nstd::array<std::complex<float>, 4> reconstruct_unitary_from_euler_angles(const Gate &g) {\n    auto xyz = g.to_euler_angles();\n    auto c = cosf(xyz[0] / 2);\n    auto s = sinf(xyz[0] / 2);\n    return {\n        c,\n        -s * std::exp(std::complex<float>{0, xyz[2]}),\n        s * std::exp(std::complex<float>{0, xyz[1]}),\n        c * std::exp(std::complex<float>{0, xyz[1] + xyz[2]}),\n    };\n}\n\nstd::array<std::complex<float>, 4> reconstruct_unitary_from_data(Gate g) {\n    return {\n        g.unitary_data[0][0],\n        g.unitary_data[0][1],\n        g.unitary_data[1][0],\n        g.unitary_data[1][1],\n    };\n}\n\nstd::array<std::complex<float>, 4> reconstruct_unitary_from_axis_angle(const Gate &g) {\n    auto xyz_a = g.to_axis_angle();\n    auto x = xyz_a[0];\n    auto y = xyz_a[1];\n    auto z = xyz_a[2];\n    auto a = xyz_a[3];\n    auto c = cosf(a / 2);\n    auto s = -sinf(a / 2);\n    return {\n        std::complex<float>{c, s * z},\n        std::complex<float>{s * y, s * x},\n        std::complex<float>{-s * y, s * x},\n        std::complex<float>{c, -s * z},\n    };\n}\n\nstd::array<std::complex<float>, 4> reconstruct_unitary_from_euler_angles_via_vector_sim_for_axis_reference(\n    const Gate &g) {\n    auto xyz = g.to_euler_angles();\n    std::array<int, 3> half_turns;\n\n    for (size_t k = 0; k < 3; k++) {\n        half_turns[k] = (int)(roundf(xyz[k] / 3.14159265359f * 2)) & 3;\n    }\n    std::array<const char *, 4> y_rots{\"I\", \"SQRT_Y\", \"Y\", \"SQRT_Y_DAG\"};\n    std::array<const char *, 4> z_rots{\"I\", \"S\", \"Z\", \"S_DAG\"};\n\n    // Recover the unitary matrix via the state channel duality.\n    Circuit c;\n    c.safe_append_u(\"H\", {0});\n    c.safe_append_u(\"CX\", {0, 1});\n    c.safe_append_u(z_rots[half_turns[2]], {1});\n    c.safe_append_u(y_rots[half_turns[0]], {1});\n    c.safe_append_u(z_rots[half_turns[1]], {1});\n    VectorSimulator v(2);\n    v.do_unitary_circuit(c);\n\n    return {v.state[0], v.state[1], v.state[2], v.state[3]};\n}\n\nTEST(gate_data, to_euler_angles) {\n    for (const auto &g : GATE_DATA.items) {\n        if ((g.flags & GATE_IS_UNITARY) && (g.flags & GATE_IS_SINGLE_QUBIT_GATE)) {\n            auto u1 = reconstruct_unitary_from_data(g);\n            auto u2 = reconstruct_unitary_from_euler_angles(g);\n            expect_unitaries_close_up_global_phase(g, u1, u2);\n        }\n    }\n}\n\nTEST(gate_data, to_axis_angle) {\n    for (const auto &g : GATE_DATA.items) {\n        if ((g.flags & GATE_IS_UNITARY) && (g.flags & GATE_IS_SINGLE_QUBIT_GATE)) {\n            auto u1 = reconstruct_unitary_from_data(g);\n            auto u2 = reconstruct_unitary_from_axis_angle(g);\n            expect_unitaries_close_up_global_phase(g, u1, u2);\n        }\n    }\n}\n\nTEST(gate_data, to_euler_angles_axis_reference) {\n    for (const auto &g : GATE_DATA.items) {\n        if ((g.flags & GATE_IS_UNITARY) && (g.flags & GATE_IS_SINGLE_QUBIT_GATE)) {\n            auto u1 = reconstruct_unitary_from_data(g);\n            auto u2 = reconstruct_unitary_from_euler_angles_via_vector_sim_for_axis_reference(g);\n            expect_unitaries_close_up_global_phase(g, u1, u2);\n        }\n    }\n}\n\nTEST(gate_data, is_symmetric_vs_flow_generators_of_two_qubit_gates) {\n    for (const auto &g : GATE_DATA.items) {\n        if ((g.flags & stim::GATE_IS_NOISY) && !(g.flags & stim::GATE_PRODUCES_RESULTS)) {\n            continue;\n        }\n        if (g.flags & GATE_TARGETS_PAIRS) {\n            Circuit c1;\n            Circuit c2;\n            c1.safe_append_u(g.name, {0, 1}, {});\n            c2.safe_append_u(g.name, {1, 0}, {});\n            auto f1 = circuit_flow_generators<64>(c1);\n            auto f2 = circuit_flow_generators<64>(c2);\n            EXPECT_EQ(g.is_symmetric(), f1 == f2) << g.name;\n        }\n    }\n}\n\nTEST(gate_data, hadamard_conjugated_vs_flow_generators_of_two_qubit_gates) {\n    auto flow_key = [](const Circuit &circuit, bool ignore_sign) {\n        auto f = circuit_flow_generators<64>(circuit);\n        if (ignore_sign) {\n            for (auto &e : f) {\n                e.input.sign = false;\n                e.output.sign = false;\n            }\n        }\n        std::stringstream ss;\n        ss << comma_sep(f);\n        return ss.str();\n    };\n    std::map<std::string, GateType> known_flows_s;\n    std::map<std::string, std::vector<GateType>> known_flows_u;\n\n    for (const auto &g : GATE_DATA.items) {\n        if (g.id == GateType::II || g.id == GateType::II_ERROR || g.id == GateType::I_ERROR) {\n            ASSERT_EQ(g.hadamard_conjugated(false), g.id);\n            ASSERT_EQ(g.hadamard_conjugated(true), g.id);\n            continue;\n        }\n        if (g.arg_count != 0 && g.arg_count != ARG_COUNT_SYGIL_ZERO_OR_ONE && g.arg_count != ARG_COUNT_SYGIL_ANY) {\n            continue;\n        }\n        if ((g.flags & GATE_TARGETS_PAIRS) || (g.flags & GATE_IS_SINGLE_QUBIT_GATE)) {\n            Circuit c;\n            c.safe_append_u(g.name, {0, 1}, {});\n            auto key_s = flow_key(c, false);\n            auto key_u = flow_key(c, true);\n            ASSERT_EQ(known_flows_s.find(key_s), known_flows_s.end())\n                << \"collision between \" << g.name << \" and \" << GATE_DATA[known_flows_s[key_s]].name;\n            known_flows_s[key_s] = g.id;\n            known_flows_u[key_u].push_back(g.id);\n        }\n    }\n    for (const auto &g : GATE_DATA.items) {\n        if (g.id == GateType::II || g.id == GateType::II_ERROR || g.id == GateType::I_ERROR) {\n            continue;\n        }\n        if (g.arg_count != 0 && g.arg_count != ARG_COUNT_SYGIL_ZERO_OR_ONE && g.arg_count != ARG_COUNT_SYGIL_ANY) {\n            continue;\n        }\n        if ((g.flags & GATE_TARGETS_PAIRS) || (g.flags & GATE_IS_SINGLE_QUBIT_GATE)) {\n            Circuit c;\n            c.safe_append_u(\"H\", {0, 1}, {});\n            c.safe_append_u(g.name, {0, 1}, {});\n            c.safe_append_u(\"H\", {0, 1}, {});\n            auto key_s = flow_key(c, false);\n            auto key_u = flow_key(c, true);\n            auto other_s = known_flows_s.find(key_s);\n            auto &other_us = known_flows_u[key_u];\n            if (other_us.empty()) {\n                other_us.push_back(GateType::NOT_A_GATE);\n            }\n\n            GateType expected_s = other_s == known_flows_s.end() ? GateType::NOT_A_GATE : other_s->second;\n            GateType actual_s = g.hadamard_conjugated(false);\n            GateType actual_u = g.hadamard_conjugated(true);\n            bool found = std::find(other_us.begin(), other_us.end(), actual_u) != other_us.end();\n            EXPECT_EQ(actual_s, expected_s)\n                << \"signed \" << g.name << \" -> \" << GATE_DATA[actual_s].name << \" != \" << GATE_DATA[expected_s].name;\n            EXPECT_TRUE(found) << \"unsigned \" << g.name << \" -> \" << GATE_DATA[actual_u].name << \" not in \"\n                               << GATE_DATA[other_us[0]].name;\n        }\n    }\n}\n"
  },
  {
    "path": "src/stim/gates/gates_test.py",
    "content": "import numpy as np\nimport stim\n\n\ndef test_gate_data_eq():\n    assert stim.gate_data('H') == stim.GateData('H')\n    assert stim.gate_data('H') == stim.gate_data('H_XZ')\n    assert not (stim.gate_data('H') == stim.GateData('X_ERROR'))\n    assert stim.gate_data('X') != stim.GateData('H')\n\n\ndef test_gate_data_str():\n    assert str(stim.GateData('MXX')) == '''\nstim.GateData {\n    .name = 'MXX'\n    .aliases = ['MXX']\n    .is_noisy_gate = True\n    .is_reset = False\n    .is_single_qubit_gate = False\n    .is_two_qubit_gate = True\n    .is_unitary = False\n    .num_parens_arguments_range = range(0, 2)\n    .produces_measurements = True\n    .takes_measurement_record_targets = False\n    .takes_pauli_targets = False\n}\n    '''.strip()\n    assert str(stim.GateData('H')) == '''\nstim.GateData {\n    .name = 'H'\n    .aliases = ['H', 'H_XZ']\n    .is_noisy_gate = False\n    .is_reset = False\n    .is_single_qubit_gate = True\n    .is_two_qubit_gate = False\n    .is_unitary = True\n    .num_parens_arguments_range = range(0, 1)\n    .produces_measurements = False\n    .takes_measurement_record_targets = False\n    .takes_pauli_targets = False\n    .tableau = stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"+Z\"),\n        ],\n        zs=[\n            stim.PauliString(\"+X\"),\n        ],\n    )\n    .unitary_matrix = np.array([[(0.7071067690849304+0j), (0.7071067690849304+0j)], [(0.7071067690849304+0j), (-0.7071067690849304-0j)]], dtype=np.complex64)\n}\n    '''.strip()\n\n\ndef test_num_parens_arguments_range():\n    assert stim.gate_data('H').num_parens_arguments_range == range(0, 1)\n    assert stim.gate_data('M').num_parens_arguments_range == range(0, 2)\n\n\ndef test_is_reset():\n    assert not stim.gate_data('H').is_reset\n    assert stim.gate_data('R').is_reset\n    assert stim.gate_data('MR').is_reset\n\n\ndef test_is_two_qubit_gate():\n    assert not stim.gate_data('H').is_two_qubit_gate\n    assert stim.gate_data('CX').is_two_qubit_gate\n\n\ndef test_is_single_qubit_gate():\n    assert stim.gate_data('H').is_single_qubit_gate\n    assert not stim.gate_data('CX').is_single_qubit_gate\n\n\ndef test_is_noisy_gate():\n    assert stim.gate_data('X_ERROR').is_noisy_gate\n    assert not stim.gate_data('X').is_noisy_gate\n\n\ndef test_produces_measurements():\n    assert stim.gate_data('MR').produces_measurements\n    assert not stim.gate_data('R').produces_measurements\n\n\ndef test_takes_pauli_targets():\n    assert stim.gate_data('MPP').takes_pauli_targets\n    assert not stim.gate_data('MXX').takes_pauli_targets\n\n\ndef test_aliases():\n    assert stim.gate_data('H').aliases == ['H', 'H_XZ']\n    assert stim.gate_data('CX').aliases == ['CNOT', 'CX', 'ZCX']\n\n\ndef test_tableau():\n    assert stim.gate_data('H').tableau == stim.Tableau.from_named_gate('H')\n\n\ndef test_name():\n    assert stim.gate_data('H').name == 'H'\n\n\ndef test_gate_data_repr():\n    val = stim.GateData('MPP')\n    assert eval(repr(val), {\"stim\": stim}) == val\n\n\ndef test_takes_measurement_record_targets():\n    assert not stim.gate_data('H').takes_measurement_record_targets\n    assert stim.gate_data('DETECTOR').takes_measurement_record_targets\n\n\ndef test_gate_data_inverse():\n    for v in stim.gate_data().values():\n        assert v.is_unitary == (v.inverse is not None)\n        matrix = v.unitary_matrix\n        if matrix is not None:\n            assert v.is_unitary\n            assert np.allclose(matrix.conj().T, v.inverse.unitary_matrix, atol=1e-6), (v.name, v.inverse.name)\n            assert v.inverse == v.generalized_inverse\n\n    assert stim.gate_data('H').inverse == stim.gate_data('H')\n    assert stim.gate_data('S').inverse == stim.gate_data('S_DAG')\n    assert stim.gate_data('M').inverse is None\n    assert stim.gate_data('CXSWAP').inverse == stim.gate_data('SWAPCX')\n    assert stim.gate_data('SPP').inverse == stim.gate_data('SPP_DAG')\n\n    assert stim.gate_data('S').generalized_inverse == stim.gate_data('S_DAG')\n    assert stim.gate_data('M').generalized_inverse == stim.gate_data('M')\n    assert stim.gate_data('R').generalized_inverse == stim.gate_data('M')\n    assert stim.gate_data('MR').generalized_inverse == stim.gate_data('MR')\n    assert stim.gate_data('MPP').generalized_inverse == stim.gate_data('MPP')\n    assert stim.gate_data('ELSE_CORRELATED_ERROR').generalized_inverse == stim.gate_data('ELSE_CORRELATED_ERROR')\n\n\ndef test_gate_data_flows():\n    assert stim.GateData('H').flows == [\n        stim.Flow(\"X -> Z\"),\n        stim.Flow(\"Z -> X\"),\n    ]\n\n\ndef test_gate_is_symmetric():\n    assert stim.GateData('SWAP').is_symmetric_gate\n    assert stim.GateData('H').is_symmetric_gate\n    assert stim.GateData('MYY').is_symmetric_gate\n    assert stim.GateData('DEPOLARIZE2').is_symmetric_gate\n    assert not stim.GateData('PAULI_CHANNEL_2').is_symmetric_gate\n    assert not stim.GateData('DETECTOR').is_symmetric_gate\n    assert not stim.GateData('TICK').is_symmetric_gate\n\n\ndef test_gate_hadamard_conjugated():\n    assert stim.GateData('CZSWAP').hadamard_conjugated(unsigned=True) is None\n    assert stim.GateData('TICK').hadamard_conjugated() == stim.GateData('TICK')\n    assert stim.GateData('MYY').hadamard_conjugated() == stim.GateData('MYY')\n    assert stim.GateData('XCZ').hadamard_conjugated() == stim.GateData('CX')\n    assert stim.GateData('X_ERROR').hadamard_conjugated() == stim.GateData('Z_ERROR')\n    assert stim.GateData('Y_ERROR').hadamard_conjugated() == stim.GateData('Y_ERROR')\n    assert stim.GateData('Z_ERROR').hadamard_conjugated() == stim.GateData('X_ERROR')\n    assert stim.GateData('I_ERROR').hadamard_conjugated() == stim.GateData('I_ERROR')\n    assert stim.GateData('II_ERROR').hadamard_conjugated() == stim.GateData('II_ERROR')\n"
  },
  {
    "path": "src/stim/gen/circuit_gen_params.cc",
    "content": "#include \"stim/gen/circuit_gen_params.h\"\n\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\n\nvoid append_anti_basis_error(Circuit &circuit, const std::vector<uint32_t> &targets, double p, char basis) {\n    if (p > 0) {\n        if (basis == 'X') {\n            circuit.safe_append_ua(\"Z_ERROR\", targets, p);\n        } else {\n            circuit.safe_append_ua(\"X_ERROR\", targets, p);\n        }\n    }\n}\n\nvoid CircuitGenParameters::validate_params() const {\n    if (before_measure_flip_probability < 0 || before_measure_flip_probability > 1) {\n        throw std::invalid_argument(\"not 0 <= before_measure_flip_probability <= 1\");\n    }\n    if (before_round_data_depolarization < 0 || before_round_data_depolarization > 1) {\n        throw std::invalid_argument(\"not 0 <= before_round_data_depolarization <= 1\");\n    }\n    if (after_clifford_depolarization < 0 || after_clifford_depolarization > 1) {\n        throw std::invalid_argument(\"not 0 <= after_clifford_depolarization <= 1\");\n    }\n    if (after_reset_flip_probability < 0 || after_reset_flip_probability > 1) {\n        throw std::invalid_argument(\"not 0 <= after_reset_flip_probability <= 1\");\n    }\n}\n\nCircuitGenParameters::CircuitGenParameters(uint64_t rounds, uint32_t distance, std::string task)\n    : rounds(rounds), distance(distance), task(task) {\n}\n\nvoid CircuitGenParameters::append_begin_round_tick(Circuit &circuit, const std::vector<uint32_t> &data_qubits) const {\n    circuit.safe_append_u(\"TICK\", {});\n    if (before_round_data_depolarization > 0) {\n        circuit.safe_append_ua(\"DEPOLARIZE1\", data_qubits, before_round_data_depolarization);\n    }\n}\n\nvoid CircuitGenParameters::append_unitary_1(\n    Circuit &circuit, std::string_view name, const std::vector<uint32_t> targets) const {\n    circuit.safe_append_u(name, targets);\n    if (after_clifford_depolarization > 0) {\n        circuit.safe_append_ua(\"DEPOLARIZE1\", targets, after_clifford_depolarization);\n    }\n}\n\nvoid CircuitGenParameters::append_unitary_2(\n    Circuit &circuit, std::string_view name, const std::vector<uint32_t> targets) const {\n    circuit.safe_append_u(name, targets);\n    if (after_clifford_depolarization > 0) {\n        circuit.safe_append_ua(\"DEPOLARIZE2\", targets, after_clifford_depolarization);\n    }\n}\n\nvoid CircuitGenParameters::append_reset(Circuit &circuit, const std::vector<uint32_t> targets, char basis) const {\n    std::string gate(\"R\");\n    gate.push_back(basis);\n    circuit.safe_append_u(gate, targets);\n    append_anti_basis_error(circuit, targets, after_reset_flip_probability, basis);\n}\n\nvoid CircuitGenParameters::append_measure(Circuit &circuit, const std::vector<uint32_t> targets, char basis) const {\n    std::string gate(\"M\");\n    gate.push_back(basis);\n    append_anti_basis_error(circuit, targets, before_measure_flip_probability, basis);\n    circuit.safe_append_u(gate, targets);\n}\n\nvoid CircuitGenParameters::append_measure_reset(\n    Circuit &circuit, const std::vector<uint32_t> targets, char basis) const {\n    std::string gate(\"MR\");\n    gate.push_back(basis);\n    append_anti_basis_error(circuit, targets, before_measure_flip_probability, basis);\n    circuit.safe_append_u(gate, targets);\n    append_anti_basis_error(circuit, targets, after_reset_flip_probability, basis);\n}\n\nstd::string GeneratedCircuit::layout_str() const {\n    std::stringstream ss;\n    std::vector<std::vector<std::string>> lines;\n    for (const auto &kv : layout) {\n        auto x = kv.first.first;\n        auto y = kv.first.second;\n        while (lines.size() <= y) {\n            lines.push_back({});\n        }\n        while (lines[y].size() <= x) {\n            lines[y].push_back(\"\");\n        }\n        lines[y][x] = kv.second.first + std::to_string(kv.second.second);\n    }\n    size_t max_len = 0;\n    for (const auto &line : lines) {\n        for (const auto &entry : line) {\n            max_len = std::max(max_len, entry.size());\n        }\n    }\n    for (auto p = lines.crbegin(); p != lines.crend(); p++) {\n        const auto &line = *p;\n        ss << \"#\";\n        for (const auto &entry : line) {\n            ss << ' ' << entry;\n            ss << std::string(max_len - entry.size(), ' ');\n        }\n        ss << \"\\n\";\n    }\n    return ss.str();\n}\n"
  },
  {
    "path": "src/stim/gen/circuit_gen_params.h",
    "content": "#ifndef _STIM_GEN_CIRCUIT_GEN_PARAMS_H\n#define _STIM_GEN_CIRCUIT_GEN_PARAMS_H\n\n#include <map>\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim {\nstruct CircuitGenParameters {\n    uint64_t rounds;\n    uint32_t distance;\n    std::string task;\n    double after_clifford_depolarization = 0;\n    double before_round_data_depolarization = 0;\n    double before_measure_flip_probability = 0;\n    double after_reset_flip_probability = 0;\n\n    void validate_params() const;\n\n    CircuitGenParameters(uint64_t rounds, uint32_t distance, std::string task);\n    void append_begin_round_tick(Circuit &circuit, const std::vector<uint32_t> &data_qubits) const;\n    void append_unitary_1(Circuit &circuit, std::string_view name, const std::vector<uint32_t> targets) const;\n    void append_unitary_2(Circuit &circuit, std::string_view name, const std::vector<uint32_t> targets) const;\n    void append_reset(Circuit &circuit, const std::vector<uint32_t> targets, char basis = 'Z') const;\n    void append_measure(Circuit &circuit, const std::vector<uint32_t> targets, char basis = 'Z') const;\n    void append_measure_reset(Circuit &circuit, const std::vector<uint32_t> targets, char basis = 'Z') const;\n};\n\nstruct GeneratedCircuit {\n    Circuit circuit;\n    std::map<std::pair<uint32_t, uint32_t>, std::pair<char, uint32_t>> layout;\n    std::string hint_str;\n    std::string layout_str() const;\n};\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/gen/circuit_gen_params.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gen/circuit_gen_params.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(circuit_gen_params, append_begin_round_tick) {\n    CircuitGenParameters params(3, 5, \"test\");\n    Circuit circuit;\n\n    circuit.clear();\n    params.append_begin_round_tick(circuit, {1, 2, 3});\n    ASSERT_EQ(circuit, Circuit(\"TICK\"));\n\n    params.before_round_data_depolarization = 0.125;\n    circuit.clear();\n    params.append_begin_round_tick(circuit, {1, 2, 3});\n    ASSERT_EQ(circuit, Circuit(\"TICK\\nDEPOLARIZE1(0.125) 1 2 3\"));\n}\n\nTEST(circuit_gen_params, append_unitary_1) {\n    CircuitGenParameters params(3, 5, \"test\");\n    Circuit circuit;\n\n    circuit.clear();\n    params.append_unitary_1(circuit, \"H\", {2, 3, 5});\n    ASSERT_EQ(circuit, Circuit(\"H 2 3 5\"));\n\n    params.after_clifford_depolarization = 0.125;\n    circuit.clear();\n    params.append_unitary_1(circuit, \"H\", {2, 3, 5});\n    ASSERT_EQ(circuit, Circuit(\"H 2 3 5\\nDEPOLARIZE1(0.125) 2 3 5\"));\n}\n\nTEST(circuit_gen_params, append_unitary_2) {\n    CircuitGenParameters params(3, 5, \"test\");\n    Circuit circuit;\n\n    circuit.clear();\n    params.append_unitary_2(circuit, \"CNOT\", {2, 3, 5, 7});\n    ASSERT_EQ(circuit, Circuit(\"CX 2 3 5 7\"));\n\n    params.after_clifford_depolarization = 0.125;\n    circuit.clear();\n    params.append_unitary_2(circuit, \"CNOT\", {2, 3, 5, 7});\n    ASSERT_EQ(circuit, Circuit(\"CX 2 3 5 7\\nDEPOLARIZE2(0.125) 2 3 5 7\"));\n}\n\nTEST(circuit_gen_params, append_reset) {\n    CircuitGenParameters params(3, 5, \"test\");\n    Circuit circuit;\n\n    circuit.clear();\n    params.append_reset(circuit, {2, 3, 5});\n    params.append_reset(circuit, {2, 3, 5}, 'Z');\n    ASSERT_EQ(circuit, Circuit(\"R 2 3 5\\nR 2 3 5\"));\n    params.append_reset(circuit, {1}, 'X');\n    params.append_reset(circuit, {4}, 'Y');\n    ASSERT_EQ(circuit, Circuit(\"R 2 3 5\\nR 2 3 5\\nRX 1\\nRY 4\"));\n\n    params.after_reset_flip_probability = 0.125;\n    circuit.clear();\n    params.append_reset(circuit, {2, 3, 5});\n    ASSERT_EQ(circuit, Circuit(\"R 2 3 5\\nX_ERROR(0.125) 2 3 5\"));\n    params.append_reset(circuit, {1}, 'X');\n    params.append_reset(circuit, {4}, 'Y');\n    ASSERT_EQ(circuit, Circuit(\"R 2 3 5\\nX_ERROR(0.125) 2 3 5\\nRX 1\\nZ_ERROR(0.125) 1\\nRY 4\\nX_ERROR(0.125) 4\"));\n}\n\nTEST(circuit_gen_params, append_measure) {\n    CircuitGenParameters params(3, 5, \"test\");\n    Circuit circuit;\n\n    circuit.clear();\n    params.append_measure(circuit, {2, 3, 5});\n    params.append_measure(circuit, {2, 3, 5}, 'Z');\n    ASSERT_EQ(circuit, Circuit(\"M 2 3 5\\nM 2 3 5\"));\n    params.append_measure(circuit, {1}, 'X');\n    params.append_measure(circuit, {4}, 'Y');\n    ASSERT_EQ(circuit, Circuit(\"M 2 3 5\\nM 2 3 5\\nMX 1\\nMY 4\"));\n\n    params.before_measure_flip_probability = 0.125;\n    circuit.clear();\n    params.append_measure(circuit, {2, 3, 5});\n    ASSERT_EQ(circuit, Circuit(\"X_ERROR(0.125) 2 3 5\\nM 2 3 5\"));\n    params.append_measure(circuit, {1}, 'X');\n    params.append_measure(circuit, {4}, 'Y');\n    ASSERT_EQ(circuit, Circuit(\"X_ERROR(0.125) 2 3 5\\nM 2 3 5\\nZ_ERROR(0.125) 1\\nMX 1\\nX_ERROR(0.125) 4\\nMY 4\"));\n}\n\nTEST(circuit_gen_params, append_measure_reset) {\n    CircuitGenParameters params(3, 5, \"test\");\n    Circuit circuit;\n\n    circuit.clear();\n    params.append_measure_reset(circuit, {2, 3, 5});\n    params.append_measure_reset(circuit, {2, 3, 5}, 'Z');\n    ASSERT_EQ(circuit, Circuit(\"MR 2 3 5\\nMR 2 3 5\"));\n    params.append_measure_reset(circuit, {1}, 'X');\n    params.append_measure_reset(circuit, {4}, 'Y');\n    ASSERT_EQ(circuit, Circuit(\"MR 2 3 5\\nMR 2 3 5\\nMRX 1\\nMRY 4\"));\n\n    params.before_measure_flip_probability = 0.125;\n    params.after_reset_flip_probability = 0.25;\n    circuit.clear();\n    params.append_measure_reset(circuit, {2, 3, 5});\n    params.append_measure_reset(circuit, {1}, 'X');\n    params.append_measure_reset(circuit, {4}, 'Y');\n    ASSERT_EQ(circuit, Circuit(R\"CIRCUIT(\n        X_ERROR(0.125) 2 3 5\n        MR 2 3 5\n        X_ERROR(0.25) 2 3 5\n        Z_ERROR(0.125) 1\n        MRX 1\n        Z_ERROR(0.25) 1\n        X_ERROR(0.125) 4\n        MRY 4\n        X_ERROR(0.25) 4\n    )CIRCUIT\"));\n}\n"
  },
  {
    "path": "src/stim/gen/gen_color_code.cc",
    "content": "#include \"stim/gen/gen_color_code.h\"\n\n#include <algorithm>\n#include <array>\n#include <map>\n#include <set>\n#include <vector>\n\nusing namespace stim;\n\nstruct color_coord {\n    float x;\n    float y;\n    color_coord operator+(color_coord other) const {\n        return {x + other.x, y + other.y};\n    }\n    color_coord operator-(color_coord other) const {\n        return {x - other.x, y - other.y};\n    }\n    bool operator==(color_coord other) const {\n        return x == other.x && y == other.y;\n    }\n    bool operator<(color_coord other) const {\n        if (x != other.x) {\n            return x < other.x;\n        }\n        return y < other.y;\n    }\n};\n\nGeneratedCircuit stim::generate_color_code_circuit(const CircuitGenParameters &params) {\n    if (params.task != \"memory_xyz\") {\n        throw std::invalid_argument(\n            \"Unrecognized task '\" + params.task +\n            \"'. Known color_code tasks:\\n\"\n            \"    'memory_xyz': Initialize logical |0>, protect by cycling X then Y then Z stabilizer measurements, \"\n            \"measure logical Z.\\n\");\n    }\n    if (params.rounds < 2) {\n        throw std::invalid_argument(\"Need rounds >= 2.\");\n    }\n    if (params.distance < 2 || params.distance % 2 == 0) {\n        throw std::invalid_argument(\"Need an odd distance >= 3.\");\n    }\n\n    uint32_t d = params.distance;\n    uint32_t w = d + (d - 1) / 2;\n\n    // Lay out and index qubits.\n    std::set<color_coord> data_coords;\n    std::set<color_coord> measure_coords;\n    std::map<color_coord, uint32_t> p2q;\n    std::vector<uint32_t> data_qubits;\n    std::vector<uint32_t> measurement_qubits;\n    for (size_t y = 0; y < w; y++) {\n        for (size_t x = 0; x < w - y; x++) {\n            color_coord q{x + y / 2.0f, (float)y};\n            auto i = (uint32_t)p2q.size();\n            p2q[q] = i;\n            if ((x + 2 * y) % 3 == 2) {\n                measure_coords.insert(q);\n                measurement_qubits.push_back(p2q[q]);\n            } else {\n                data_coords.insert(q);\n                data_qubits.push_back(p2q[q]);\n            }\n        }\n    }\n\n    // Keep targets sorted to make the output look a bit cleaner.\n    std::vector<uint32_t> all_qubits;\n    all_qubits.insert(all_qubits.end(), data_qubits.begin(), data_qubits.end());\n    all_qubits.insert(all_qubits.end(), measurement_qubits.begin(), measurement_qubits.end());\n    std::sort(all_qubits.begin(), all_qubits.end());\n    std::sort(data_qubits.begin(), data_qubits.end());\n    std::sort(measurement_qubits.begin(), measurement_qubits.end());\n\n    // Reverse indices.\n    std::map<color_coord, uint32_t> data_coord_to_order;\n    std::map<color_coord, uint32_t> measure_coord_to_order;\n    std::map<uint32_t, color_coord> q2p;\n    for (const auto &kv : p2q) {\n        q2p[kv.second] = kv.first;\n    }\n    for (auto q : data_qubits) {\n        auto i = (uint32_t)data_coord_to_order.size();\n        data_coord_to_order[q2p[q]] = i;\n    }\n    for (auto q : measurement_qubits) {\n        auto i = (uint32_t)measure_coord_to_order.size();\n        measure_coord_to_order[q2p[q]] = i;\n    }\n\n    // Precompute targets for each tick of CNOT gates.\n    std::array<std::vector<uint32_t>, 6> cnot_targets;\n    std::vector<color_coord> deltas{\n        {1, 0},\n        {0.5, 1},\n        {0.5, -1},\n        {-1, 0},\n        {-0.5, 1},\n        {-0.5, -1},\n    };\n    for (size_t k = 0; k < deltas.size(); k++) {\n        for (auto measure : measure_coords) {\n            auto data = measure + deltas[k];\n            if (p2q.find(data) != p2q.end()) {\n                cnot_targets[k].push_back(p2q[data]);\n                cnot_targets[k].push_back(p2q[measure]);\n            }\n        }\n    }\n\n    // Build the repeated actions that make up the color code cycle.\n    Circuit cycle_actions;\n    params.append_begin_round_tick(cycle_actions, data_qubits);\n    params.append_unitary_1(cycle_actions, \"C_XYZ\", data_qubits);\n    for (const auto &targets : cnot_targets) {\n        cycle_actions.safe_append_u(\"TICK\", {});\n        params.append_unitary_2(cycle_actions, \"CNOT\", targets);\n    }\n    cycle_actions.safe_append_u(\"TICK\", {});\n    params.append_measure_reset(cycle_actions, measurement_qubits);\n\n    // Build the start of the circuit, getting a state that's ready to cycle.\n    // In particular, the first cycle has different detectors and so has to be handled special.\n    auto m = (uint32_t)measurement_qubits.size();\n    Circuit head;\n    for (auto q : all_qubits) {\n        color_coord c = q2p[q];\n        head.safe_append_u(\"QUBIT_COORDS\", {q}, {c.x, c.y});\n    }\n    params.append_reset(head, all_qubits);\n    head += cycle_actions * 2;\n    for (uint32_t k = m; k-- > 0;) {\n        color_coord c = q2p[measurement_qubits[m - k - 1]];\n        head.safe_append_u(\"DETECTOR\", {(k + 1) | TARGET_RECORD_BIT, (k + 1 + m) | TARGET_RECORD_BIT}, {c.x, c.y, 0});\n    }\n\n    // Build the repeated body of the circuit, including the detectors comparing to previous cycles.\n    Circuit body = cycle_actions;\n    body.safe_append_u(\"SHIFT_COORDS\", {}, {0, 0, 1});\n    for (uint32_t k = m; k-- > 0;) {\n        color_coord c = q2p[measurement_qubits[m - k - 1]];\n        body.safe_append_u(\n            \"DETECTOR\",\n            {(k + 1) | TARGET_RECORD_BIT, (k + 1 + m) | TARGET_RECORD_BIT, (k + 1 + 2 * m) | TARGET_RECORD_BIT},\n            {c.x, c.y, 0});\n    }\n\n    // Build the end of the circuit, getting out of the cycle state and terminating.\n    // In particular, the data measurements create detectors that have to be handled special.\n    // Also, the tail is responsible for identifying the logical observable.\n    Circuit tail;\n    params.append_measure(tail, data_qubits, \"ZXY\"[params.rounds % 3]);\n    for (auto m_q : measurement_qubits) {\n        auto measure = q2p[m_q];\n        std::vector<uint32_t> detectors;\n        for (auto delta : deltas) {\n            auto data = measure + delta;\n            if (p2q.find(data) != p2q.end()) {\n                detectors.push_back((uint32_t)(data_qubits.size() - data_coord_to_order[data]) | TARGET_RECORD_BIT);\n            }\n        }\n        uint32_t p =\n            (data_qubits.size() + measurement_qubits.size() - measure_coord_to_order[measure]) | TARGET_RECORD_BIT;\n        // Depending on if the last two rounds were XY, YZ, or ZX, different combinations are equal the data\n        // measurements.\n        if (params.rounds % 3 == 0) {\n            detectors.push_back(p);\n        } else if (params.rounds % 3 == 1) {\n            detectors.push_back(p + m);\n        } else {\n            detectors.push_back(p);\n            detectors.push_back(p + m);\n        }\n        std::sort(detectors.begin(), detectors.end());\n        tail.safe_append_u(\"DETECTOR\", detectors, {measure.x, measure.y, 1});\n    }\n    // Logical observable.\n    std::vector<uint32_t> obs_inc;\n    for (auto q : data_coords) {\n        if (q.y == 0) {\n            obs_inc.push_back((data_qubits.size() - data_coord_to_order[q]) | TARGET_RECORD_BIT);\n        }\n    }\n    std::sort(obs_inc.begin(), obs_inc.end());\n    tail.safe_append_ua(\"OBSERVABLE_INCLUDE\", obs_inc, 0);\n\n    // Put it all together.\n    auto full_circuit = head + body * (params.rounds - 2) + tail;\n\n    // Make 2d layout.\n    std::map<std::pair<uint32_t, uint32_t>, std::pair<char, uint32_t>> layout;\n    for (auto q : data_coords) {\n        layout[{(uint32_t)(q.x * 2), (uint32_t)q.y}] = {q.y == 0 ? 'L' : 'd', p2q[q]};\n    }\n    std::array<char, 3> rgb{'R', 'G', 'B'};\n    for (auto q : measure_coords) {\n        auto x = (uint32_t)(q.x * 2);\n        auto y = (uint32_t)q.y;\n        layout[{x, y}] = {rgb[(x + y) % 3], p2q[q]};\n    }\n\n    return {\n        full_circuit,\n        layout,\n        \"# Legend:\\n\"\n        \"#     d# = data qubit\\n\"\n        \"#     L# = data qubit with logical observable crossing\\n\"\n        \"#     R# = measurement qubit (red hex)\\n\"\n        \"#     G# = measurement qubit (green hex)\\n\"\n        \"#     B# = measurement qubit (blue hex)\\n\"};\n}\n"
  },
  {
    "path": "src/stim/gen/gen_color_code.h",
    "content": "#ifndef _STIM_GEN_GEN_COLOR_CODE_H\n#define _STIM_GEN_GEN_COLOR_CODE_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n\nnamespace stim {\nGeneratedCircuit generate_color_code_circuit(const CircuitGenParameters &params);\n}\n\n#endif\n"
  },
  {
    "path": "src/stim/gen/gen_color_code.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gen/gen_color_code.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(gen_color_code, color_code_hard_coded_comparison) {\n    CircuitGenParameters params(100, 5, \"memory_xyz\");\n    params.after_clifford_depolarization = 0.125;\n    params.after_reset_flip_probability = 0.25;\n    params.before_measure_flip_probability = 0.375;\n    params.before_round_data_depolarization = 0.0625;\n    auto out = generate_color_code_circuit(params);\n    ASSERT_EQ(\n        out.layout_str(),\n        \"\"\n        \"#                         d27\\n\"\n        \"#                     d25     R26\\n\"\n        \"#                 B22     d23     d24\\n\"\n        \"#             d18     d19     G20     d21\\n\"\n        \"#         d13     R14     d15     d16     R17\\n\"\n        \"#     B7      d8      d9      B10     d11     d12\\n\"\n        \"# L0      L1      G2      L3      L4      G5      L6 \\n\");\n    params.distance = 3;\n    out = generate_color_code_circuit(params);\n    ASSERT_EQ(\n        out.layout_str(),\n        \"\"\n        \"#          d9\\n\"\n        \"#       d7    R8\\n\"\n        \"#    B4    d5    d6\\n\"\n        \"# L0    L1    G2    L3\\n\");\n    ASSERT_EQ(\n        out.circuit.str(),\n        Circuit(R\"CIRCUIT(\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(2, 0) 2\n        QUBIT_COORDS(3, 0) 3\n        QUBIT_COORDS(0.5, 1) 4\n        QUBIT_COORDS(1.5, 1) 5\n        QUBIT_COORDS(2.5, 1) 6\n        QUBIT_COORDS(1, 2) 7\n        QUBIT_COORDS(2, 2) 8\n        QUBIT_COORDS(1.5, 3) 9\n        R 0 1 2 3 4 5 6 7 8 9\n        X_ERROR(0.25) 0 1 2 3 4 5 6 7 8 9\n        REPEAT 2 {\n            TICK\n            DEPOLARIZE1(0.0625) 0 1 3 5 6 7 9\n            C_XYZ 0 1 3 5 6 7 9\n            DEPOLARIZE1(0.125) 0 1 3 5 6 7 9\n            TICK\n            CX 5 4 3 2\n            DEPOLARIZE2(0.125) 5 4 3 2\n            TICK\n            CX 7 4 6 2\n            DEPOLARIZE2(0.125) 7 4 6 2\n            TICK\n            CX 1 4 6 8\n            DEPOLARIZE2(0.125) 1 4 6 8\n            TICK\n            CX 1 2 7 8\n            DEPOLARIZE2(0.125) 1 2 7 8\n            TICK\n            CX 5 2 9 8\n            DEPOLARIZE2(0.125) 5 2 9 8\n            TICK\n            CX 0 4 5 8\n            DEPOLARIZE2(0.125) 0 4 5 8\n            TICK\n            X_ERROR(0.375) 2 4 8\n            MR 2 4 8\n            X_ERROR(0.25) 2 4 8\n        }\n        DETECTOR(2, 0, 0) rec[-3] rec[-6]\n        DETECTOR(0.5, 1, 0) rec[-2] rec[-5]\n        DETECTOR(2, 2, 0) rec[-1] rec[-4]\n        REPEAT 98 {\n            TICK\n            DEPOLARIZE1(0.0625) 0 1 3 5 6 7 9\n            C_XYZ 0 1 3 5 6 7 9\n            DEPOLARIZE1(0.125) 0 1 3 5 6 7 9\n            TICK\n            CX 5 4 3 2\n            DEPOLARIZE2(0.125) 5 4 3 2\n            TICK\n            CX 7 4 6 2\n            DEPOLARIZE2(0.125) 7 4 6 2\n            TICK\n            CX 1 4 6 8\n            DEPOLARIZE2(0.125) 1 4 6 8\n            TICK\n            CX 1 2 7 8\n            DEPOLARIZE2(0.125) 1 2 7 8\n            TICK\n            CX 5 2 9 8\n            DEPOLARIZE2(0.125) 5 2 9 8\n            TICK\n            CX 0 4 5 8\n            DEPOLARIZE2(0.125) 0 4 5 8\n            TICK\n            X_ERROR(0.375) 2 4 8\n            MR 2 4 8\n            X_ERROR(0.25) 2 4 8\n            SHIFT_COORDS(0, 0, 1)\n            DETECTOR(2, 0, 0) rec[-3] rec[-6] rec[-9]\n            DETECTOR(0.5, 1, 0) rec[-2] rec[-5] rec[-8]\n            DETECTOR(2, 2, 0) rec[-1] rec[-4] rec[-7]\n        }\n        Z_ERROR(0.375) 0 1 3 5 6 7 9\n        MX 0 1 3 5 6 7 9\n        DETECTOR(2, 0, 1) rec[-3] rec[-4] rec[-5] rec[-6] rec[-13]\n        DETECTOR(0.5, 1, 1) rec[-2] rec[-4] rec[-6] rec[-7] rec[-12]\n        DETECTOR(2, 2, 1) rec[-1] rec[-2] rec[-3] rec[-4] rec[-11]\n        OBSERVABLE_INCLUDE(0) rec[-5] rec[-6] rec[-7]\n    )CIRCUIT\")\n            .str());\n}\n"
  },
  {
    "path": "src/stim/gen/gen_rep_code.cc",
    "content": "#include \"stim/gen/gen_rep_code.h\"\n\nusing namespace stim;\n\nGeneratedCircuit stim::generate_rep_code_circuit(const CircuitGenParameters &params) {\n    if (params.task != \"memory\") {\n        throw std::invalid_argument(\n            \"Unrecognized task '\" + params.task +\n            \"'. Known repetition_code tasks:\\n\"\n            \"    'memory': Initialize |0>, protect with parity measurements, measure.\\n\");\n    }\n    if (params.rounds < 1) {\n        throw std::invalid_argument(\"Need rounds >= 1.\");\n    }\n    if (params.distance < 2) {\n        throw std::invalid_argument(\"Need a distance >= 2.\");\n    }\n\n    uint32_t m = params.distance - 1;\n    uint32_t n = m * 2 + 1;\n\n    // Lay out qubits and determine interaction targets.\n    std::vector<uint32_t> all_qubits;\n    std::vector<uint32_t> data_qubits;\n    std::vector<uint32_t> cnot_targets_1;\n    std::vector<uint32_t> cnot_targets_2;\n    std::vector<uint32_t> measurement_qubits;\n    for (uint32_t q = 0; q < n; q++) {\n        all_qubits.push_back(q);\n        if (q % 2 == 0) {\n            data_qubits.push_back(q);\n        } else {\n            measurement_qubits.push_back(q);\n            cnot_targets_1.push_back(q - 1);\n            cnot_targets_1.push_back(q);\n            cnot_targets_2.push_back(q + 1);\n            cnot_targets_2.push_back(q);\n        }\n    }\n\n    // Build the repeated actions that make up the repetition code cycle.\n    Circuit cycle_actions;\n    params.append_begin_round_tick(cycle_actions, data_qubits);\n    params.append_unitary_2(cycle_actions, \"CNOT\", cnot_targets_1);\n    cycle_actions.safe_append_u(\"TICK\", {});\n    params.append_unitary_2(cycle_actions, \"CNOT\", cnot_targets_2);\n    cycle_actions.safe_append_u(\"TICK\", {});\n    params.append_measure_reset(cycle_actions, measurement_qubits);\n\n    // Build the start of the circuit, getting a state that's ready to cycle.\n    // In particular, the first cycle has different detectors and so has to be handled special.\n    Circuit head;\n    params.append_reset(head, all_qubits);\n    head += cycle_actions;\n    for (uint32_t k = 0; k < m; k++) {\n        head.safe_append_u(\"DETECTOR\", {(m - k) | TARGET_RECORD_BIT}, {(double)2 * k + 1, 0});\n    }\n\n    // Build the repeated body of the circuit, including the detectors comparing to previous cycles.\n    Circuit body = cycle_actions;\n    body.safe_append_u(\"SHIFT_COORDS\", {}, {0, 1});\n    for (uint32_t k = 0; k < m; k++) {\n        body.safe_append_u(\n            \"DETECTOR\", {(m - k) | TARGET_RECORD_BIT, (2 * m - k) | TARGET_RECORD_BIT}, {(double)2 * k + 1, 0});\n    }\n\n    // Build the end of the circuit, getting out of the cycle state and terminating.\n    // In particular, the data measurements create detectors that have to be handled special.\n    // Also, the tail is responsible for identifying the logical observable.\n    Circuit tail;\n    params.append_measure(tail, data_qubits);\n    for (uint32_t k = 0; k < m; k++) {\n        tail.safe_append_u(\n            \"DETECTOR\",\n            {(m - k) | TARGET_RECORD_BIT, (m - k + 1) | TARGET_RECORD_BIT, (2 * m - k + 1) | TARGET_RECORD_BIT},\n            {(double)2 * k + 1, 1});\n    }\n    tail.safe_append_ua(\"OBSERVABLE_INCLUDE\", {1 | TARGET_RECORD_BIT}, 0);\n\n    // Combine to form final circuit.\n    Circuit full_circuit = head + body * (params.rounds - 1) + tail;\n\n    // Produce a 2d layout.\n    std::map<std::pair<uint32_t, uint32_t>, std::pair<char, uint32_t>> layout;\n    for (uint32_t k = 0; k < n; k++) {\n        layout[{k, 0}] = {\"dZ\"[k & 1], k};\n    }\n    layout[{0, 0}].first = 'L';\n\n    return {\n        full_circuit,\n        layout,\n        \"# Legend:\\n\"\n        \"#     d# = data qubit\\n\"\n        \"#     L# = data qubit with logical observable crossing\\n\"\n        \"#     Z# = measurement qubit\\n\"};\n}\n"
  },
  {
    "path": "src/stim/gen/gen_rep_code.h",
    "content": "#ifndef _STIM_GEN_GEN_REP_CODE_H\n#define _STIM_GEN_GEN_REP_CODE_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n\nnamespace stim {\nGeneratedCircuit generate_rep_code_circuit(const CircuitGenParameters &params);\n}\n\n#endif\n"
  },
  {
    "path": "src/stim/gen/gen_rep_code.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gen/gen_rep_code.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(gen_rep_code, rep_code) {\n    CircuitGenParameters params(5000, 4, \"memory\");\n    params.after_clifford_depolarization = 0.125;\n    params.after_reset_flip_probability = 0.25;\n    params.before_measure_flip_probability = 0.375;\n    params.before_round_data_depolarization = 0.0625;\n    auto out = generate_rep_code_circuit(params);\n    ASSERT_EQ(out.layout_str(), R\"LAYOUT(# L0 Z1 d2 Z3 d4 Z5 d6\n)LAYOUT\");\n    ASSERT_EQ(\n        out.circuit.str(),\n        Circuit(R\"CIRCUIT(\n        R 0 1 2 3 4 5 6\n        X_ERROR(0.25) 0 1 2 3 4 5 6\n        TICK\n        DEPOLARIZE1(0.0625) 0 2 4 6\n        CX 0 1 2 3 4 5\n        DEPOLARIZE2(0.125) 0 1 2 3 4 5\n        TICK\n        CX 2 1 4 3 6 5\n        DEPOLARIZE2(0.125) 2 1 4 3 6 5\n        TICK\n        X_ERROR(0.375) 1 3 5\n        MR 1 3 5\n        X_ERROR(0.25) 1 3 5\n        DETECTOR(1, 0) rec[-3]\n        DETECTOR(3, 0) rec[-2]\n        DETECTOR(5, 0) rec[-1]\n        REPEAT 4999 {\n            TICK\n            DEPOLARIZE1(0.0625) 0 2 4 6\n            CX 0 1 2 3 4 5\n            DEPOLARIZE2(0.125) 0 1 2 3 4 5\n            TICK\n            CX 2 1 4 3 6 5\n            DEPOLARIZE2(0.125) 2 1 4 3 6 5\n            TICK\n            X_ERROR(0.375) 1 3 5\n            MR 1 3 5\n            X_ERROR(0.25) 1 3 5\n            SHIFT_COORDS(0, 1)\n            DETECTOR(1, 0) rec[-3] rec[-6]\n            DETECTOR(3, 0) rec[-2] rec[-5]\n            DETECTOR(5, 0) rec[-1] rec[-4]\n        }\n        X_ERROR(0.375) 0 2 4 6\n        M 0 2 4 6\n        DETECTOR(1, 1) rec[-3] rec[-4] rec[-7]\n        DETECTOR(3, 1) rec[-2] rec[-3] rec[-6]\n        DETECTOR(5, 1) rec[-1] rec[-2] rec[-5]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\")\n            .str());\n}\n"
  },
  {
    "path": "src/stim/gen/gen_surface_code.cc",
    "content": "#include \"stim/gen/gen_surface_code.h\"\n\n#include <algorithm>\n#include <array>\n#include <functional>\n#include <map>\n#include <set>\n#include <vector>\n\nusing namespace stim;\n\nstruct surface_coord {\n    float x;\n    float y;\n    surface_coord operator+(surface_coord other) const {\n        return {x + other.x, y + other.y};\n    }\n    surface_coord operator-(surface_coord other) const {\n        return {x - other.x, y - other.y};\n    }\n    bool operator==(surface_coord other) const {\n        return x == other.x && y == other.y;\n    }\n    bool operator<(surface_coord other) const {\n        if (x != other.x) {\n            return x < other.x;\n        }\n        return y < other.y;\n    }\n};\n\nGeneratedCircuit _finish_surface_code_circuit(\n    std::function<uint32_t(surface_coord)> coord_to_index,\n    const std::set<surface_coord> &data_coords,\n    const std::set<surface_coord> &x_measure_coords,\n    const std::set<surface_coord> &z_measure_coords,\n    const CircuitGenParameters &params,\n    const std::vector<surface_coord> &x_order,\n    const std::vector<surface_coord> &z_order,\n    const std::vector<surface_coord> x_observable,\n    const std::vector<surface_coord> z_observable,\n    bool is_memory_x) {\n    if (params.rounds < 1) {\n        throw std::invalid_argument(\"Need rounds >= 1.\");\n    }\n    if (params.distance < 2) {\n        throw std::invalid_argument(\"Need a distance >= 2.\");\n    }\n\n    const auto &chosen_basis_observable = is_memory_x ? x_observable : z_observable;\n    const auto &chosen_basis_measure_coords = is_memory_x ? x_measure_coords : z_measure_coords;\n\n    // Index the measurement qubits and data qubits.\n    std::map<surface_coord, uint32_t> p2q;\n    for (auto q : data_coords) {\n        p2q[q] = coord_to_index(q);\n    }\n    for (auto q : x_measure_coords) {\n        p2q[q] = coord_to_index(q);\n    }\n    for (auto q : z_measure_coords) {\n        p2q[q] = coord_to_index(q);\n    }\n\n    // Reverse index.\n    std::map<uint32_t, surface_coord> q2p;\n    for (const auto &kv : p2q) {\n        q2p[kv.second] = kv.first;\n    }\n\n    // Make target lists for various types of qubits.\n    std::vector<uint32_t> data_qubits;\n    std::vector<uint32_t> measurement_qubits;\n    std::vector<uint32_t> x_measurement_qubits;\n    std::vector<uint32_t> all_qubits;\n    for (auto q : data_coords) {\n        data_qubits.push_back(p2q[q]);\n    }\n    for (auto q : x_measure_coords) {\n        measurement_qubits.push_back(p2q[q]);\n        x_measurement_qubits.push_back(p2q[q]);\n    }\n    for (auto q : z_measure_coords) {\n        measurement_qubits.push_back(p2q[q]);\n    }\n    all_qubits.insert(all_qubits.end(), data_qubits.begin(), data_qubits.end());\n    all_qubits.insert(all_qubits.end(), measurement_qubits.begin(), measurement_qubits.end());\n    std::sort(all_qubits.begin(), all_qubits.end());\n    std::sort(data_qubits.begin(), data_qubits.end());\n    std::sort(measurement_qubits.begin(), measurement_qubits.end());\n    std::sort(x_measurement_qubits.begin(), x_measurement_qubits.end());\n\n    // Reverse index the measurement order used for defining detectors.\n    std::map<surface_coord, uint32_t> data_coord_to_order;\n    std::map<surface_coord, uint32_t> measure_coord_to_order;\n    for (auto q : data_qubits) {\n        auto i = data_coord_to_order.size();\n        data_coord_to_order[q2p[q]] = i;\n    }\n    for (auto q : measurement_qubits) {\n        auto i = measure_coord_to_order.size();\n        measure_coord_to_order[q2p[q]] = i;\n    }\n\n    // List out CNOT gate targets using given interaction orders.\n    std::array<std::vector<uint32_t>, 4> cnot_targets;\n    for (size_t k = 0; k < 4; k++) {\n        for (auto measure : x_measure_coords) {\n            auto data = measure + x_order[k];\n            if (p2q.find(data) != p2q.end()) {\n                cnot_targets[k].push_back(p2q[measure]);\n                cnot_targets[k].push_back(p2q[data]);\n            }\n        }\n        for (auto measure : z_measure_coords) {\n            auto data = measure + z_order[k];\n            if (p2q.find(data) != p2q.end()) {\n                cnot_targets[k].push_back(p2q[data]);\n                cnot_targets[k].push_back(p2q[measure]);\n            }\n        }\n    }\n\n    // Build the repeated actions that make up the surface code cycle.\n    Circuit cycle_actions;\n    params.append_begin_round_tick(cycle_actions, data_qubits);\n    params.append_unitary_1(cycle_actions, \"H\", x_measurement_qubits);\n    for (const auto &targets : cnot_targets) {\n        cycle_actions.safe_append_u(\"TICK\", {});\n        params.append_unitary_2(cycle_actions, \"CNOT\", targets);\n    }\n    cycle_actions.safe_append_u(\"TICK\", {});\n    params.append_unitary_1(cycle_actions, \"H\", x_measurement_qubits);\n    cycle_actions.safe_append_u(\"TICK\", {});\n    params.append_measure_reset(cycle_actions, measurement_qubits);\n\n    // Build the start of the circuit, getting a state that's ready to cycle.\n    // In particular, the first cycle has different detectors and so has to be handled special.\n    Circuit head;\n    for (const auto &kv : q2p) {\n        head.safe_append_u(\"QUBIT_COORDS\", {kv.first}, {kv.second.x, kv.second.y});\n    }\n    params.append_reset(head, data_qubits, \"ZX\"[is_memory_x]);\n    params.append_reset(head, measurement_qubits);\n    head += cycle_actions;\n    for (auto measure : chosen_basis_measure_coords) {\n        head.safe_append_u(\n            \"DETECTOR\",\n            {(uint32_t)(measurement_qubits.size() - measure_coord_to_order[measure]) | TARGET_RECORD_BIT},\n            {measure.x, measure.y, 0});\n    }\n\n    // Build the repeated body of the circuit, including the detectors comparing to previous cycles.\n    Circuit body = cycle_actions;\n    uint32_t m = measurement_qubits.size();\n    body.safe_append_u(\"SHIFT_COORDS\", {}, {0, 0, 1});\n    for (auto m_index : measurement_qubits) {\n        auto m_coord = q2p[m_index];\n        auto k = (uint32_t)measurement_qubits.size() - measure_coord_to_order[m_coord] - 1;\n        body.safe_append_u(\n            \"DETECTOR\", {(k + 1) | TARGET_RECORD_BIT, (k + 1 + m) | TARGET_RECORD_BIT}, {m_coord.x, m_coord.y, 0});\n    }\n\n    // Build the end of the circuit, getting out of the cycle state and terminating.\n    // In particular, the data measurements create detectors that have to be handled special.\n    // Also, the tail is responsible for identifying the logical observable.\n    Circuit tail;\n    params.append_measure(tail, data_qubits, \"ZX\"[is_memory_x]);\n    // Detectors.\n    for (auto measure : chosen_basis_measure_coords) {\n        std::vector<uint32_t> detectors;\n        for (auto delta : z_order) {\n            auto data = measure + delta;\n            if (p2q.find(data) != p2q.end()) {\n                detectors.push_back((data_qubits.size() - data_coord_to_order[data]) | TARGET_RECORD_BIT);\n            }\n        }\n        detectors.push_back(\n            (data_qubits.size() + measurement_qubits.size() - measure_coord_to_order[measure]) | TARGET_RECORD_BIT);\n        std::sort(detectors.begin(), detectors.end());\n        tail.safe_append_u(\"DETECTOR\", detectors, {measure.x, measure.y, 1});\n    }\n    // Logical observable.\n    std::vector<uint32_t> obs_inc;\n    for (auto q : chosen_basis_observable) {\n        obs_inc.push_back((data_qubits.size() - data_coord_to_order[q]) | TARGET_RECORD_BIT);\n    }\n    std::sort(obs_inc.begin(), obs_inc.end());\n    tail.safe_append_ua(\"OBSERVABLE_INCLUDE\", obs_inc, 0);\n\n    // Combine to form final circuit.\n    Circuit full_circuit = head + body * (params.rounds - 1) + tail;\n\n    // Produce a 2d layout.\n    std::map<std::pair<uint32_t, uint32_t>, std::pair<char, uint32_t>> layout;\n    float scale = x_order[0].x == 0.5 ? 2 : 1;\n    for (auto q : data_coords) {\n        layout[{(uint32_t)(q.x * scale), (uint32_t)(q.y * scale)}] = {'d', p2q[q]};\n    }\n    for (auto q : x_measure_coords) {\n        layout[{(uint32_t)(q.x * scale), (uint32_t)(q.y * scale)}] = {'X', p2q[q]};\n    }\n    for (auto q : z_measure_coords) {\n        layout[{(uint32_t)(q.x * scale), (uint32_t)(q.y * scale)}] = {'Z', p2q[q]};\n    }\n    for (auto q : chosen_basis_observable) {\n        layout[{(uint32_t)(q.x * scale), (uint32_t)(q.y * scale)}].first = 'L';\n    }\n\n    return {\n        full_circuit,\n        layout,\n        \"# Legend:\\n\"\n        \"#     d# = data qubit\\n\"\n        \"#     L# = data qubit with logical observable crossing\\n\"\n        \"#     X# = measurement qubit (X stabilizer)\\n\"\n        \"#     Z# = measurement qubit (Z stabilizer)\\n\"};\n}\n\nGeneratedCircuit _generate_rotated_surface_code_circuit(const CircuitGenParameters &params, bool is_memory_x) {\n    uint32_t d = params.distance;\n\n    // Place data qubits.\n    std::set<surface_coord> data_coords;\n    std::vector<surface_coord> x_observable;\n    std::vector<surface_coord> z_observable;\n    for (float x = 0.5; x <= d; x++) {\n        for (float y = 0.5; y <= d; y++) {\n            surface_coord q{x * 2, y * 2};\n            data_coords.insert(q);\n            if (y == 0.5) {\n                z_observable.push_back(q);\n            }\n            if (x == 0.5) {\n                x_observable.push_back(q);\n            }\n        }\n    }\n\n    // Place measurement qubits.\n    std::set<surface_coord> x_measure_coords;\n    std::set<surface_coord> z_measure_coords;\n    for (size_t x = 0; x <= d; x++) {\n        for (size_t y = 0; y <= d; y++) {\n            surface_coord q{(float)x * 2, (float)y * 2};\n            bool on_boundary_1 = x == 0 || x == d;\n            bool on_boundary_2 = y == 0 || y == d;\n            bool parity = x % 2 != y % 2;\n            if (on_boundary_1 && parity) {\n                continue;\n            }\n            if (on_boundary_2 && !parity) {\n                continue;\n            }\n            if (parity) {\n                x_measure_coords.insert(q);\n            } else {\n                z_measure_coords.insert(q);\n            }\n        }\n    }\n\n    // Define interaction orders so that hook errors run against the error grain instead of with it.\n    std::vector<surface_coord> z_order{\n        {1, 1},\n        {1, -1},\n        {-1, 1},\n        {-1, -1},\n    };\n    std::vector<surface_coord> x_order{\n        {1, 1},\n        {-1, 1},\n        {1, -1},\n        {-1, -1},\n    };\n\n    // Delegate.\n    return _finish_surface_code_circuit(\n        [&](surface_coord q) {\n            q = q - surface_coord{0, fmodf(q.x, 2)};\n            return (uint32_t)(q.x + q.y * (d + 0.5));\n        },\n        data_coords,\n        x_measure_coords,\n        z_measure_coords,\n        params,\n        x_order,\n        z_order,\n        x_observable,\n        z_observable,\n        is_memory_x);\n}\n\nGeneratedCircuit _generate_unrotated_surface_code_circuit(const CircuitGenParameters &params, bool is_memory_x) {\n    uint32_t d = params.distance;\n    assert(params.rounds > 0);\n\n    // Place qubits.\n    std::set<surface_coord> data_coords;\n    std::set<surface_coord> x_measure_coords;\n    std::set<surface_coord> z_measure_coords;\n    std::vector<surface_coord> x_observable;\n    std::vector<surface_coord> z_observable;\n    for (size_t x = 0; x < 2 * d - 1; x++) {\n        for (size_t y = 0; y < 2 * d - 1; y++) {\n            surface_coord q{(float)x, (float)y};\n            bool parity = x % 2 != y % 2;\n            if (parity) {\n                if (x % 2 == 0) {\n                    z_measure_coords.insert(q);\n                } else {\n                    x_measure_coords.insert(q);\n                }\n            } else {\n                data_coords.insert(q);\n                if (x == 0) {\n                    x_observable.push_back(q);\n                }\n                if (y == 0) {\n                    z_observable.push_back(q);\n                }\n            }\n        }\n    }\n\n    // Define interaction order. Doesn't matter so much for unrotated.\n    std::vector<surface_coord> order{\n        {1, 0},\n        {0, 1},\n        {0, -1},\n        {-1, 0},\n    };\n\n    // Delegate.\n    return _finish_surface_code_circuit(\n        [&](surface_coord q) {\n            return (uint32_t)(q.x + q.y * (2 * d - 1));\n        },\n        data_coords,\n        x_measure_coords,\n        z_measure_coords,\n        params,\n        order,\n        order,\n        x_observable,\n        z_observable,\n        is_memory_x);\n}\n\nGeneratedCircuit stim::generate_surface_code_circuit(const CircuitGenParameters &params) {\n    if (params.task == \"rotated_memory_x\") {\n        return _generate_rotated_surface_code_circuit(params, true);\n    } else if (params.task == \"rotated_memory_z\") {\n        return _generate_rotated_surface_code_circuit(params, false);\n    } else if (params.task == \"unrotated_memory_x\") {\n        return _generate_unrotated_surface_code_circuit(params, true);\n    } else if (params.task == \"unrotated_memory_z\") {\n        return _generate_unrotated_surface_code_circuit(params, false);\n    } else {\n        throw std::invalid_argument(\n            \"Unrecognized task '\" + params.task +\n            \"'. Known surface_code tasks:\\n\"\n            \"    'rotated_memory_x': Initialize logical |+> in rotated code, protect with parity measurements, measure \"\n            \"logical X.\\n\"\n            \"    'rotated_memory_z': Initialize logical |0> in rotated code, protect with parity measurements, measure \"\n            \"logical Z.\\n\"\n            \"    'unrotated_memory_x': Initialize logical |+> in unrotated code, protect with parity measurements, \"\n            \"measure logical X.\\n\"\n            \"    'unrotated_memory_z': Initialize logical |0> in unrotated code, protect with parity measurements, \"\n            \"measure logical Z.\\n\"\n            \"\");\n    }\n}\n"
  },
  {
    "path": "src/stim/gen/gen_surface_code.h",
    "content": "#ifndef _STIM_GEN_GEN_SURFACE_CODE_H\n#define _STIM_GEN_GEN_SURFACE_CODE_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n\nnamespace stim {\nGeneratedCircuit generate_surface_code_circuit(const CircuitGenParameters &params);\n}\n\n#endif\n"
  },
  {
    "path": "src/stim/gen/gen_surface_code.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gen/gen_surface_code.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(gen_surface_code, unrotated_surface_code_hard_coded_comparison) {\n    CircuitGenParameters params(5, 2, \"unrotated_memory_z\");\n    params.after_clifford_depolarization = 0.125;\n    params.after_reset_flip_probability = 0.25;\n    params.before_measure_flip_probability = 0.375;\n    params.before_round_data_depolarization = 0.0625;\n    auto out = generate_surface_code_circuit(params);\n    ASSERT_EQ(\n        out.layout_str(),\n        \"\"\n        \"# d6 X7 d8\\n\"\n        \"# Z3 d4 Z5\\n\"\n        \"# L0 X1 L2\\n\");\n    ASSERT_EQ(\n        out.circuit.str(),\n        Circuit(R\"CIRCUIT(\n            QUBIT_COORDS(0, 0) 0\n            QUBIT_COORDS(1, 0) 1\n            QUBIT_COORDS(2, 0) 2\n            QUBIT_COORDS(0, 1) 3\n            QUBIT_COORDS(1, 1) 4\n            QUBIT_COORDS(2, 1) 5\n            QUBIT_COORDS(0, 2) 6\n            QUBIT_COORDS(1, 2) 7\n            QUBIT_COORDS(2, 2) 8\n            R 0 2 4 6 8\n            X_ERROR(0.25) 0 2 4 6 8\n            R 1 3 5 7\n            X_ERROR(0.25) 1 3 5 7\n            TICK\n            DEPOLARIZE1(0.0625) 0 2 4 6 8\n            H 1 7\n            DEPOLARIZE1(0.125) 1 7\n            TICK\n            CX 1 2 7 8 4 3\n            DEPOLARIZE2(0.125) 1 2 7 8 4 3\n            TICK\n            CX 1 4 6 3 8 5\n            DEPOLARIZE2(0.125) 1 4 6 3 8 5\n            TICK\n            CX 7 4 0 3 2 5\n            DEPOLARIZE2(0.125) 7 4 0 3 2 5\n            TICK\n            CX 1 0 7 6 4 5\n            DEPOLARIZE2(0.125) 1 0 7 6 4 5\n            TICK\n            H 1 7\n            DEPOLARIZE1(0.125) 1 7\n            TICK\n            X_ERROR(0.375) 1 3 5 7\n            MR 1 3 5 7\n            X_ERROR(0.25) 1 3 5 7\n            DETECTOR(0, 1, 0) rec[-3]\n            DETECTOR(2, 1, 0) rec[-2]\n            REPEAT 4 {\n                TICK\n                DEPOLARIZE1(0.0625) 0 2 4 6 8\n                H 1 7\n                DEPOLARIZE1(0.125) 1 7\n                TICK\n                CX 1 2 7 8 4 3\n                DEPOLARIZE2(0.125) 1 2 7 8 4 3\n                TICK\n                CX 1 4 6 3 8 5\n                DEPOLARIZE2(0.125) 1 4 6 3 8 5\n                TICK\n                CX 7 4 0 3 2 5\n                DEPOLARIZE2(0.125) 7 4 0 3 2 5\n                TICK\n                CX 1 0 7 6 4 5\n                DEPOLARIZE2(0.125) 1 0 7 6 4 5\n                TICK\n                H 1 7\n                DEPOLARIZE1(0.125) 1 7\n                TICK\n                X_ERROR(0.375) 1 3 5 7\n                MR 1 3 5 7\n                X_ERROR(0.25) 1 3 5 7\n                SHIFT_COORDS(0, 0, 1)\n                DETECTOR(1, 0, 0) rec[-4] rec[-8]\n                DETECTOR(0, 1, 0) rec[-3] rec[-7]\n                DETECTOR(2, 1, 0) rec[-2] rec[-6]\n                DETECTOR(1, 2, 0) rec[-1] rec[-5]\n            }\n            X_ERROR(0.375) 0 2 4 6 8\n            M 0 2 4 6 8\n            DETECTOR(0, 1, 1) rec[-2] rec[-3] rec[-5] rec[-8]\n            DETECTOR(2, 1, 1) rec[-1] rec[-3] rec[-4] rec[-7]\n            OBSERVABLE_INCLUDE(0) rec[-4] rec[-5]\n        )CIRCUIT\")\n            .str());\n\n    params.rounds = 1;\n    params.task = \"unrotated_memory_x\";\n    auto out2 = generate_surface_code_circuit(params);\n    ASSERT_EQ(\n        out2.layout_str(),\n        \"\"\n        \"# L6 X7 d8\\n\"\n        \"# Z3 d4 Z5\\n\"\n        \"# L0 X1 d2\\n\");\n    ASSERT_EQ(\n        out2.circuit.str(),\n        Circuit(R\"CIRCUIT(\n        QUBIT_COORDS(0, 0) 0\n        QUBIT_COORDS(1, 0) 1\n        QUBIT_COORDS(2, 0) 2\n        QUBIT_COORDS(0, 1) 3\n        QUBIT_COORDS(1, 1) 4\n        QUBIT_COORDS(2, 1) 5\n        QUBIT_COORDS(0, 2) 6\n        QUBIT_COORDS(1, 2) 7\n        QUBIT_COORDS(2, 2) 8\n        RX 0 2 4 6 8\n        Z_ERROR(0.25) 0 2 4 6 8\n        R 1 3 5 7\n        X_ERROR(0.25) 1 3 5 7\n        TICK\n        DEPOLARIZE1(0.0625) 0 2 4 6 8\n        H 1 7\n        DEPOLARIZE1(0.125) 1 7\n        TICK\n        CX 1 2 7 8 4 3\n        DEPOLARIZE2(0.125) 1 2 7 8 4 3\n        TICK\n        CX 1 4 6 3 8 5\n        DEPOLARIZE2(0.125) 1 4 6 3 8 5\n        TICK\n        CX 7 4 0 3 2 5\n        DEPOLARIZE2(0.125) 7 4 0 3 2 5\n        TICK\n        CX 1 0 7 6 4 5\n        DEPOLARIZE2(0.125) 1 0 7 6 4 5\n        TICK\n        H 1 7\n        DEPOLARIZE1(0.125) 1 7\n        TICK\n        X_ERROR(0.375) 1 3 5 7\n        MR 1 3 5 7\n        X_ERROR(0.25) 1 3 5 7\n        DETECTOR(1, 0, 0) rec[-4]\n        DETECTOR(1, 2, 0) rec[-1]\n        Z_ERROR(0.375) 0 2 4 6 8\n        MX 0 2 4 6 8\n        DETECTOR(1, 0, 1) rec[-3] rec[-4] rec[-5] rec[-9]\n        DETECTOR(1, 2, 1) rec[-1] rec[-2] rec[-3] rec[-6]\n        OBSERVABLE_INCLUDE(0) rec[-2] rec[-5]\n    )CIRCUIT\")\n            .str());\n}\n\nTEST(gen_surface_code, rotated_surface_code_hard_coded_comparison) {\n    CircuitGenParameters params(5, 2, \"rotated_memory_z\");\n    params.after_clifford_depolarization = 0.125;\n    params.after_reset_flip_probability = 0.25;\n    params.before_measure_flip_probability = 0.375;\n    params.before_round_data_depolarization = 0.0625;\n    auto out = generate_surface_code_circuit(params);\n    ASSERT_EQ(\n        out.layout_str(),\n        \"\"\n        \"#         X12\\n\"\n        \"#     d6      d8 \\n\"\n        \"#         Z7 \\n\"\n        \"#     L1      L3 \\n\"\n        \"#         X2 \\n\");\n    ASSERT_EQ(\n        out.circuit.str(),\n        Circuit(R\"CIRCUIT(\n            QUBIT_COORDS(1, 1) 1\n            QUBIT_COORDS(2, 0) 2\n            QUBIT_COORDS(3, 1) 3\n            QUBIT_COORDS(1, 3) 6\n            QUBIT_COORDS(2, 2) 7\n            QUBIT_COORDS(3, 3) 8\n            QUBIT_COORDS(2, 4) 12\n            R 1 3 6 8\n            X_ERROR(0.25) 1 3 6 8\n            R 2 7 12\n            X_ERROR(0.25) 2 7 12\n            TICK\n            DEPOLARIZE1(0.0625) 1 3 6 8\n            H 2 12\n            DEPOLARIZE1(0.125) 2 12\n            TICK\n            CX 2 3 8 7\n            DEPOLARIZE2(0.125) 2 3 8 7\n            TICK\n            CX 2 1 3 7\n            DEPOLARIZE2(0.125) 2 1 3 7\n            TICK\n            CX 12 8 6 7\n            DEPOLARIZE2(0.125) 12 8 6 7\n            TICK\n            CX 12 6 1 7\n            DEPOLARIZE2(0.125) 12 6 1 7\n            TICK\n            H 2 12\n            DEPOLARIZE1(0.125) 2 12\n            TICK\n            X_ERROR(0.375) 2 7 12\n            MR 2 7 12\n            X_ERROR(0.25) 2 7 12\n            DETECTOR(2, 2, 0) rec[-2]\n            REPEAT 4 {\n                TICK\n                DEPOLARIZE1(0.0625) 1 3 6 8\n                H 2 12\n                DEPOLARIZE1(0.125) 2 12\n                TICK\n                CX 2 3 8 7\n                DEPOLARIZE2(0.125) 2 3 8 7\n                TICK\n                CX 2 1 3 7\n                DEPOLARIZE2(0.125) 2 1 3 7\n                TICK\n                CX 12 8 6 7\n                DEPOLARIZE2(0.125) 12 8 6 7\n                TICK\n                CX 12 6 1 7\n                DEPOLARIZE2(0.125) 12 6 1 7\n                TICK\n                H 2 12\n                DEPOLARIZE1(0.125) 2 12\n                TICK\n                X_ERROR(0.375) 2 7 12\n                MR 2 7 12\n                X_ERROR(0.25) 2 7 12\n                SHIFT_COORDS(0, 0, 1)\n                DETECTOR(2, 0, 0) rec[-3] rec[-6]\n                DETECTOR(2, 2, 0) rec[-2] rec[-5]\n                DETECTOR(2, 4, 0) rec[-1] rec[-4]\n            }\n            X_ERROR(0.375) 1 3 6 8\n            M 1 3 6 8\n            DETECTOR(2, 2, 1) rec[-1] rec[-2] rec[-3] rec[-4] rec[-6]\n            OBSERVABLE_INCLUDE(0) rec[-3] rec[-4]\n        )CIRCUIT\")\n            .str());\n\n    params.distance = 4;\n    out = generate_surface_code_circuit(params);\n    ASSERT_EQ(\n        out.layout_str(),\n        \"\"\n        \"#         X38             X42\\n\"\n        \"#     d28     d30     d32     d34\\n\"\n        \"#         Z29     X31     Z33\\n\"\n        \"#     d19     d21     d23     d25\\n\"\n        \"# Z18     X20     Z22     X24     Z26\\n\"\n        \"#     d10     d12     d14     d16\\n\"\n        \"#         Z11     X13     Z15\\n\"\n        \"#     L1      L3      L5      L7 \\n\"\n        \"#         X2              X6 \\n\");\n\n    params.distance = 5;\n    out = generate_surface_code_circuit(params);\n    ASSERT_EQ(\n        out.layout_str(),\n        \"\"\n        \"#                 X59             X63\\n\"\n        \"#     d45     d47     d49     d51     d53\\n\"\n        \"# Z44     X46     Z48     X50     Z52\\n\"\n        \"#     d34     d36     d38     d40     d42\\n\"\n        \"#         Z35     X37     Z39     X41     Z43\\n\"\n        \"#     d23     d25     d27     d29     d31\\n\"\n        \"# Z22     X24     Z26     X28     Z30\\n\"\n        \"#     d12     d14     d16     d18     d20\\n\"\n        \"#         Z13     X15     Z17     X19     Z21\\n\"\n        \"#     L1      L3      L5      L7      L9 \\n\"\n        \"#         X2              X6 \\n\");\n}\n"
  },
  {
    "path": "src/stim/io/README.md",
    "content": "# `io` directory\n\nThis directory contains types and functions responsible for reading and writing data in a variety\nof file formats supported by stim.\n"
  },
  {
    "path": "src/stim/io/measure_record.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/measure_record.h\"\n\n#include <algorithm>\n\n#include \"stim/io/measure_record_writer.h\"\n\nusing namespace stim;\n\nMeasureRecord::MeasureRecord(size_t max_lookback) : max_lookback(max_lookback), unwritten(0) {\n}\n\nvoid MeasureRecord::write_unwritten_results_to(MeasureRecordWriter &writer) {\n    size_t n = storage.size();\n    for (size_t k = n - unwritten; k < n; k++) {\n        writer.write_bit(storage[k]);\n    }\n    unwritten = 0;\n    if ((storage.size() >> 1) > max_lookback) {\n        storage.erase(storage.begin(), storage.end() - max_lookback);\n    }\n}\n\nbool MeasureRecord::lookback(size_t lookback) const {\n    if (lookback > storage.size()) {\n        throw std::out_of_range(\"Referred to a measurement record before the beginning of time.\");\n    }\n    if (lookback == 0) {\n        throw std::out_of_range(\"Lookback must be non-zero.\");\n    }\n    if (lookback > max_lookback) {\n        throw std::out_of_range(\"Referred to a measurement record past the lookback limit.\");\n    }\n    return *(storage.end() - lookback);\n}\n\nvoid MeasureRecord::record_result(bool result) {\n    storage.push_back(result);\n    unwritten++;\n}\n\nvoid MeasureRecord::record_results(const std::vector<bool> &results) {\n    storage.insert(storage.end(), results.begin(), results.end());\n    unwritten += results.size();\n}\n\nvoid MeasureRecord::clear() {\n    unwritten = 0;\n    storage.clear();\n}\n\nvoid MeasureRecord::discard_results_past_max_lookback() {\n    if (storage.size() > max_lookback) {\n        storage.erase(storage.begin(), storage.end() - max_lookback);\n    }\n    if (unwritten > max_lookback) {\n        unwritten = max_lookback;\n    }\n}\n"
  },
  {
    "path": "src/stim/io/measure_record.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_IO_MEASURE_RECORD_H\n#define _STIM_IO_MEASURE_RECORD_H\n\n#include <cstddef>\n#include <cstdint>\n\n#include \"stim/io/measure_record_writer.h\"\n\nnamespace stim {\n\n/// Stores a historical record of measurement results that can be looked up and written to the external world.\n///\n/// Results that have been written and are further back than `max_lookback` may be discarded from memory.\nstruct MeasureRecord {\n    /// How far back into the measurement record a circuit being simulated may look.\n    /// Results younger than this cannot be discarded.\n    size_t max_lookback;\n    /// How many results have been recorded but not yet written to the external world.\n    /// Results younger than this cannot be discarded.\n    size_t unwritten;\n    /// The actual recorded results.\n    std::vector<bool> storage;\n    /// Creates an empty measurement record.\n    MeasureRecord(size_t max_lookback = SIZE_MAX);\n    /// Forces all unwritten results to be written via the given writer.\n    ///\n    /// After the results are written, older measurements now eligible to be discarded may be removed from memory.\n    void write_unwritten_results_to(MeasureRecordWriter &writer);\n    /// Returns a measurement result from the record.\n    ///\n    /// Args:\n    ///     lookback: How far back the measurement is. lookback=1 is the latest measurement, 2 the second latest, etc.\n    bool lookback(size_t lookback) const;\n    /// Batch record.\n    void record_results(const std::vector<bool> &results);\n    /// Appends a measurement to the record.\n    void record_result(bool result);\n    /// Clear the record.\n    void clear();\n    /// Truncates the record to only include bits within the lookback limit.\n    void discard_results_past_max_lookback();\n};\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/io/measure_record.test.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/measure_record.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(MeasureRecord, basic_usage) {\n    MeasureRecord r(20);\n    r.record_result(true);\n    ASSERT_EQ(r.lookback(1), true);\n    r.record_result(false);\n    ASSERT_EQ(r.lookback(1), false);\n    ASSERT_EQ(r.lookback(2), true);\n    for (size_t k = 0; k < 50; k++) {\n        r.record_result(true);\n        r.record_result(false);\n    }\n    ASSERT_EQ(r.storage.size(), 102);\n\n    FILE *tmp = tmpfile();\n    r.write_unwritten_results_to(*MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_01));\n    rewind(tmp);\n    for (size_t k = 0; k < 102; k++) {\n        ASSERT_EQ(getc(tmp), '0' + (~k & 1));\n    }\n    ASSERT_EQ(getc(tmp), EOF);\n\n    ASSERT_LE(r.storage.size(), 40);\n}\n"
  },
  {
    "path": "src/stim/io/measure_record_batch.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_IO_MEASURE_RECORD_BATCH_H\n#define _STIM_IO_MEASURE_RECORD_BATCH_H\n\n#include \"stim/circuit/circuit_instruction.h\"\n#include \"stim/io/measure_record_batch_writer.h\"\n\nnamespace stim {\n\n/// Stores a record of multiple measurement streams that can be looked up and written to the external world.\n///\n/// Results that have been written and are further back than `max_lookback` may be discarded from memory.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstruct MeasureRecordBatch {\n    size_t num_shots;\n    /// How far back into the measurement record a circuit being simulated may look.\n    /// Results younger than this cannot be discarded.\n    size_t max_lookback;\n    /// How many results have been recorded but not yet written to the external world.\n    /// Results younger than this cannot be discarded.\n    size_t unwritten;\n    /// How many results are currently stored (from each separate stream).\n    size_t stored;\n    /// How many results have been written to the external world.\n    size_t written;\n    /// For performance reasons, measurement data given to store may include non-zero values past the data corresponding\n    /// to the number of expected shots. AND-ing the data with this mask fixes the problem.\n    simd_bits<W> shot_mask;\n    /// The 2-dimensional block of bits storing the measurement results from each separate measurement stream.\n    /// Major index is measurement index, minor index is shot index.\n    simd_bit_table<W> storage;\n\n    /// Constructs an empty MeasureRecordBatch configured for the given max_lookback and number of shots.\n    MeasureRecordBatch(size_t num_shots, size_t max_lookback);\n\n    /// Allows measurements older than max_lookback to be discarded, even though they weren't written out.\n    ///\n    /// E.g. this is used during detection event sampling, when what is written is derived detection events.\n    void mark_all_as_written();\n    /// Hints that measurements can be written to the given writer.\n    ///\n    /// For performance reasons, they may not be written until a large enough block has been accumulated.\n    void intermediate_write_unwritten_results_to(MeasureRecordBatchWriter &writer, simd_bits_range_ref<W> ref_sample);\n    /// Forces measurements to be written to the given writer, and to tell the writer the measurements are ending.\n    void final_write_unwritten_results_to(MeasureRecordBatchWriter &writer, simd_bits_range_ref<W> ref_sample);\n    /// Looks up a historical batch measurement.\n    ///\n    /// Returns:\n    ///     A reference into the storage table, with the bit at offset k corresponding to the measurement from stream k.\n    simd_bits_range_ref<W> lookback(size_t lookback) const;\n    /// Writes a zero'd result into the record and returns a reference to it to edit.\n    simd_bits_range_ref<W> record_zero_result_to_edit();\n    /// Xors a batch measurement result into pre-reserved noisy storage.\n    void xor_record_reserved_result(simd_bits_range_ref<W> result);\n    /// Appends a batch measurement result into storage.\n    void record_result(simd_bits_range_ref<W> result);\n    /// Reserves space for storing measurement results. Initializes bits to be noisy with the given probability.\n    void reserve_noisy_space_for_results(const CircuitInstruction &inst, std::mt19937_64 &rng);\n    /// Ensures there is enough space for storing a number of measurement results, without moving memory.\n    void reserve_space_for_results(size_t count);\n    /// Resets the record to an empty state.\n    void clear();\n\n    void destructive_resize(size_t new_num_shots, size_t new_max_lookback);\n};\n\n}  // namespace stim\n\n#include \"stim/io/measure_record_batch.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/io/measure_record_batch.inl",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <algorithm>\n\n#include \"stim/io/measure_record_batch.h\"\n#include \"stim/io/measure_record_batch_writer.h\"\n#include \"stim/util_bot/probability_util.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nMeasureRecordBatch<W>::MeasureRecordBatch(size_t num_shots, size_t max_lookback)\n    : num_shots(num_shots),\n      max_lookback(max_lookback),\n      unwritten(0),\n      stored(0),\n      written(0),\n      shot_mask(num_shots),\n      storage(1, num_shots) {\n    for (size_t k = 0; k < num_shots; k++) {\n        shot_mask[k] = true;\n    }\n}\n\ntemplate <size_t W>\nvoid MeasureRecordBatch<W>::reserve_space_for_results(size_t count) {\n    if (stored + count > storage.num_major_bits_padded()) {\n        simd_bit_table<W> new_storage((stored + count) * 2, storage.num_minor_bits_padded());\n        new_storage.data.word_range_ref(0, storage.data.num_simd_words) = storage.data;\n        storage = std::move(new_storage);\n    }\n}\n\ntemplate <size_t W>\nvoid MeasureRecordBatch<W>::reserve_noisy_space_for_results(const CircuitInstruction &inst, std::mt19937_64 &rng) {\n    size_t count = inst.targets.size();\n    reserve_space_for_results(count);\n    float p = inst.args.empty() ? 0 : inst.args[0];\n    biased_randomize_bits(p, storage[stored].u64, storage[stored + count].u64, rng);\n}\n\ntemplate <size_t W>\nvoid MeasureRecordBatch<W>::xor_record_reserved_result(simd_bits_range_ref<W> result) {\n    storage[stored] ^= result;\n    storage[stored] &= shot_mask;\n    stored++;\n    unwritten++;\n}\n\ntemplate <size_t W>\nvoid MeasureRecordBatch<W>::record_result(simd_bits_range_ref<W> result) {\n    reserve_space_for_results(1);\n    storage[stored] = result;\n    storage[stored] &= shot_mask;\n    stored++;\n    unwritten++;\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> MeasureRecordBatch<W>::record_zero_result_to_edit() {\n    reserve_space_for_results(1);\n    storage[stored].clear();\n    stored++;\n    unwritten++;\n    return storage[stored - 1];\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> MeasureRecordBatch<W>::lookback(size_t lookback) const {\n    if (lookback > stored) {\n        throw std::out_of_range(\"Referred to a measurement record before the beginning of time.\");\n    }\n    if (lookback == 0) {\n        throw std::out_of_range(\"Lookback must be non-zero.\");\n    }\n    if (lookback > max_lookback) {\n        throw std::out_of_range(\"Referred to a measurement record past the lookback limit.\");\n    }\n    return storage[stored - lookback];\n}\n\ntemplate <size_t W>\nvoid MeasureRecordBatch<W>::mark_all_as_written() {\n    unwritten = 0;\n    size_t m = max_lookback;\n    if ((stored >> 1) > m) {\n        memcpy(storage.data.u8, storage[stored - m].u8, m * storage.num_minor_u8_padded());\n        stored = m;\n    }\n}\n\ntemplate <size_t W>\nvoid MeasureRecordBatch<W>::intermediate_write_unwritten_results_to(\n    MeasureRecordBatchWriter &writer, simd_bits_range_ref<W> ref_sample) {\n    constexpr size_t WRITE_SIZE = 256;\n    while (unwritten >= WRITE_SIZE) {\n        auto slice = storage.slice_maj(stored - unwritten, stored - unwritten + WRITE_SIZE);\n        for (size_t k = 0; k < WRITE_SIZE; k++) {\n            size_t j = written + k;\n            if (j < ref_sample.num_bits_padded() && ref_sample[j]) {\n                slice[k] ^= shot_mask;\n            }\n        }\n        writer.batch_write_bytes<W>(slice, WRITE_SIZE >> 6);\n        unwritten -= WRITE_SIZE;\n        written += WRITE_SIZE;\n    }\n\n    size_t m = std::max(max_lookback, unwritten);\n    if ((stored >> 1) > m) {\n        memcpy(storage.data.u8, storage[stored - m].u8, m * storage.num_minor_u8_padded());\n        stored = m;\n    }\n}\n\ntemplate <size_t W>\nvoid MeasureRecordBatch<W>::final_write_unwritten_results_to(\n    MeasureRecordBatchWriter &writer, simd_bits_range_ref<W> ref_sample) {\n    size_t n = stored;\n    for (size_t k = n - unwritten; k < n; k++) {\n        bool invert = written < ref_sample.num_bits_padded() && ref_sample[written];\n        if (invert) {\n            storage[k] ^= shot_mask;\n        }\n        writer.batch_write_bit<W>(storage[k]);\n        if (invert) {\n            storage[k] ^= shot_mask;\n        }\n        written++;\n    }\n    unwritten = 0;\n    writer.write_end();\n}\n\ntemplate <size_t W>\nvoid MeasureRecordBatch<W>::clear() {\n    stored = 0;\n    unwritten = 0;\n}\n\ntemplate <size_t W>\nvoid MeasureRecordBatch<W>::destructive_resize(size_t new_num_shots, size_t new_max_lookback) {\n    unwritten = 0;\n    stored = 0;\n    written = 0;\n    max_lookback = new_max_lookback;\n    if (new_num_shots != num_shots) {\n        num_shots = new_num_shots;\n        shot_mask = simd_bits<W>(num_shots);\n        for (size_t k = 0; k < num_shots; k++) {\n            shot_mask[k] = true;\n        }\n        storage.destructive_resize(1, num_shots);\n    }\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/io/measure_record_batch.test.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/measure_record_batch.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordBatch, basic_usage, {\n    simd_bits<W> s0(5);\n    simd_bits<W> s1(5);\n    s0[0] = true;\n    s1[1] = true;\n    s0[2] = true;\n    s1[3] = true;\n    s0[4] = true;\n    MeasureRecordBatch<W> r(5, 20);\n    ASSERT_EQ(r.stored, 0);\n    r.record_result(s0);\n    ASSERT_EQ(r.stored, 1);\n    ASSERT_EQ(r.lookback(1), s0);\n    r.record_result(s1);\n    ASSERT_EQ(r.stored, 2);\n    ASSERT_EQ(r.lookback(1), s1);\n    ASSERT_EQ(r.lookback(2), s0);\n\n    for (size_t k = 0; k < 50; k++) {\n        r.record_result(s0);\n        r.record_result(s1);\n    }\n    ASSERT_EQ(r.unwritten, 102);\n    ASSERT_EQ(r.stored, 102);\n    FILE *tmp = tmpfile();\n    MeasureRecordBatchWriter w(tmp, 5, SampleFormat::SAMPLE_FORMAT_01);\n    r.intermediate_write_unwritten_results_to(w, simd_bits<W>(0));\n    ASSERT_EQ(r.unwritten, 102);\n\n    for (size_t k = 0; k < 500; k++) {\n        r.record_result(s0);\n        r.record_result(s1);\n    }\n    ASSERT_EQ(r.unwritten, 1102);\n    ASSERT_EQ(r.stored, 1102);\n    r.intermediate_write_unwritten_results_to(w, simd_bits<W>(0));\n    ASSERT_LT(r.unwritten, 100);\n    ASSERT_LT(r.stored, 100);\n    r.final_write_unwritten_results_to(w, simd_bits<W>(0));\n    ASSERT_EQ(r.unwritten, 0);\n    ASSERT_LT(r.stored, 100);\n\n    rewind(tmp);\n    for (size_t s = 0; s < 5; s++) {\n        simd_bits<W> sk = (s & 1) ? s1 : s0;\n        for (size_t k = 0; k < 1102; k++) {\n            ASSERT_EQ(getc(tmp), '0' + ((s + k + 1) & 1));\n        }\n        ASSERT_EQ(getc(tmp), '\\n');\n    }\n    ASSERT_EQ(getc(tmp), EOF);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordBatch, record_zero_result, {\n    MeasureRecordBatch<W> r(5, 2);\n    ASSERT_EQ(r.stored, 0);\n    auto v = r.record_zero_result_to_edit();\n    v[2] = 1;\n    ASSERT_EQ(r.stored, 1);\n    ASSERT_EQ(r.storage[0][1], 0);\n    ASSERT_EQ(r.storage[0][2], 1);\n    ASSERT_EQ(r.storage[0][3], 0);\n    ASSERT_EQ(r.lookback(1)[1], 0);\n    ASSERT_EQ(r.lookback(1)[2], 1);\n\n    r.record_zero_result_to_edit()[3] = 4;\n    ASSERT_EQ(r.storage[0][1], 0);\n    ASSERT_EQ(r.storage[0][2], 1);\n    ASSERT_EQ(r.storage[0][3], 0);\n    ASSERT_EQ(r.storage[1][1], 0);\n    ASSERT_EQ(r.storage[1][2], 0);\n    ASSERT_EQ(r.storage[1][3], 1);\n})\n"
  },
  {
    "path": "src/stim/io/measure_record_batch_writer.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/measure_record_batch_writer.h\"\n\n#include <algorithm>\n\nusing namespace stim;\n\nMeasureRecordBatchWriter::MeasureRecordBatchWriter(FILE *out, size_t num_shots, SampleFormat output_format)\n    : output_format(output_format), out(out) {\n    if (num_shots > 768) {\n        throw std::out_of_range(\"num_shots > 768 (safety check to ensure staying away from linux file handle limit)\");\n    }\n    if (output_format == SampleFormat::SAMPLE_FORMAT_PTB64 && num_shots % 64 != 0) {\n        throw std::out_of_range(\"Number of shots must be a multiple of 64 to use output format ptb64.\");\n    }\n    auto f = output_format;\n    auto s = num_shots;\n    if (output_format == SampleFormat::SAMPLE_FORMAT_PTB64) {\n        f = SampleFormat::SAMPLE_FORMAT_B8;\n        s += 63;\n        s /= 64;\n    }\n    if (s) {\n        writers.push_back(MeasureRecordWriter::make(out, f));\n    }\n    for (size_t k = 1; k < s; k++) {\n        FILE *file = tmpfile();\n        if (file == nullptr) {\n            throw std::out_of_range(\"Failed to open a temp file.\");\n        }\n        writers.push_back(MeasureRecordWriter::make(file, f));\n        temporary_files.push_back(file);\n    }\n}\n\nMeasureRecordBatchWriter::~MeasureRecordBatchWriter() {\n    for (auto &e : temporary_files) {\n        fclose(e);\n    }\n    temporary_files.clear();\n}\n\nvoid MeasureRecordBatchWriter::begin_result_type(char result_type) {\n    for (auto &e : writers) {\n        e->begin_result_type(result_type);\n    }\n}\n\nvoid MeasureRecordBatchWriter::write_end() {\n    for (auto &writer : writers) {\n        writer->write_end();\n    }\n\n    for (FILE *file : temporary_files) {\n        rewind(file);\n        while (true) {\n            int c = getc(file);\n            if (c == EOF) {\n                break;\n            }\n            putc(c, out);\n        }\n        fclose(file);\n    }\n    temporary_files.clear();\n}\n"
  },
  {
    "path": "src/stim/io/measure_record_batch_writer.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_IO_MEASURE_RECORD_BATCH_WRITER_H\n#define _STIM_IO_MEASURE_RECORD_BATCH_WRITER_H\n\n#include \"stim/io/measure_record_writer.h\"\n#include \"stim/mem/simd_bit_table.h\"\n\nnamespace stim {\n\n/// Handles buffering and writing multiple measurement data streams that ultimately need to be concatenated.\nstruct MeasureRecordBatchWriter {\n    SampleFormat output_format;\n    FILE *out;\n    /// Temporary files used to hold data that will eventually be concatenated onto the main stream.\n    std::vector<FILE *> temporary_files;\n    /// The individual writers for each incoming stream of measurement results.\n    /// The first writer will go directly to `out`, whereas the others go into temporary files.\n    std::vector<std::unique_ptr<MeasureRecordWriter>> writers;\n\n    MeasureRecordBatchWriter(FILE *out, size_t num_shots, SampleFormat output_format);\n    /// Cleans up temporary files.\n    ~MeasureRecordBatchWriter();\n    /// See MeasureRecordWriter::begin_result_type.\n    void begin_result_type(char result_type);\n\n    /// Writes a separate measurement result to each MeasureRecordWriter.\n    ///\n    /// Args:\n    ///     bits: The measurement results. The bit at offset k is the bit for the writer at offset k.\n    template <size_t W>\n    void batch_write_bit(simd_bits_range_ref<W> bits) {\n        if (output_format == SampleFormat::SAMPLE_FORMAT_PTB64) {\n            uint8_t *p = bits.u8;\n            for (auto &writer : writers) {\n                uint8_t *n = p + 8;\n                writer->write_bytes({p, n});\n                p = n;\n            }\n        } else {\n            for (size_t k = 0; k < writers.size(); k++) {\n                writers[k]->write_bit(bits[k]);\n            }\n        }\n    }\n\n    /// Writes multiple separate measurement results to each MeasureRecordWriter.\n    ///\n    /// This method can be called after calling `batch_write_bit<W>`, but for performance reasons it is recommended to\n    /// not do this since it can result in the individual writers doing extra work due to not being on byte boundaries.\n    ///\n    /// Args:\n    ///     table: The measurement results.\n    ///         The bits at minor offset k, from major offset 0 to major offset 64*num_major_u64, are the bits for the\n    ///         writer at offset k.\n    ///     num_major_u64: The number of measurement results (divided by 64) for each writer. The actual number of\n    ///         results is required to be a multiple of 64 for performance reasons.\n    template <size_t W>\n    void batch_write_bytes(const simd_bit_table<W> &table, size_t num_major_u64) {\n        if (output_format == SampleFormat::SAMPLE_FORMAT_PTB64) {\n            for (size_t k = 0; k < writers.size(); k++) {\n                for (size_t w = 0; w < num_major_u64; w++) {\n                    uint8_t *p = table.data.u8 + (k * 8) + table.num_minor_u8_padded() * w;\n                    writers[k]->write_bytes({p, p + 8});\n                }\n            }\n        } else {\n            auto transposed = table.transposed();\n            for (size_t k = 0; k < writers.size(); k++) {\n                uint8_t *p = transposed[k].u8;\n                writers[k]->write_bytes({p, p + num_major_u64 * 8});\n            }\n        }\n    }\n\n    /// Tells each writer to finish up, then concatenates all of their data into the `out` stream and cleans up.\n    void write_end();\n};\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/io/measure_record_batch_writer.test.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/measure_record_batch_writer.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordBatchWriter, basic_usage, {\n    FILE *tmp = tmpfile();\n    MeasureRecordBatchWriter w(tmp, 5, SampleFormat::SAMPLE_FORMAT_01);\n    simd_bits<W> v(5);\n    v[1] = true;\n    w.batch_write_bit<W>(v);\n    w.write_end();\n    rewind(tmp);\n    ASSERT_EQ(getc(tmp), '0');\n    ASSERT_EQ(getc(tmp), '\\n');\n    ASSERT_EQ(getc(tmp), '1');\n    ASSERT_EQ(getc(tmp), '\\n');\n    ASSERT_EQ(getc(tmp), '0');\n    ASSERT_EQ(getc(tmp), '\\n');\n    ASSERT_EQ(getc(tmp), '0');\n    ASSERT_EQ(getc(tmp), '\\n');\n    ASSERT_EQ(getc(tmp), '0');\n    ASSERT_EQ(getc(tmp), '\\n');\n})\n"
  },
  {
    "path": "src/stim/io/measure_record_reader.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_IO_MEASURE_RECORD_READER_H\n#define _STIM_IO_MEASURE_RECORD_READER_H\n\n#include <memory>\n\n#include \"stim/io/sparse_shot.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/mem/simd_bit_table.h\"\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\n// Returns true if an integer value is found at current position. Returns false otherwise.\n// Uses two output variables: value to return the integer value read and next for the next\n// character or EOF.\ninline bool read_uint64(FILE *in, uint64_t &value, int &next, bool include_next = false) {\n    if (!include_next) {\n        next = getc(in);\n    }\n    if (!isdigit(next)) {\n        return false;\n    }\n\n    value = 0;\n    while (isdigit(next)) {\n        uint64_t prev_value = value;\n        value *= 10;\n        value += next - '0';\n        if (value < prev_value) {\n            throw std::runtime_error(\"Integer value read from file was too big\");\n        }\n        next = getc(in);\n    }\n    return true;\n}\n\n/// Handles reading measurement data from the outside world.\n///\n/// Child classes implement the various input formats. Each file format encodes a certain number of records.\n/// Each record is a sequence of 0s and 1s. File formats B8 and R8 encode a single record. File formats 01,\n/// HITS and DETS encode any number of records. Record size in bits is fixed for each file and the client\n/// must specify it upfront.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstruct MeasureRecordReader {\n    size_t num_measurements;\n    size_t num_detectors;\n    size_t num_observables;\n    size_t bits_per_record() const;\n    MeasureRecordReader(size_t num_measurements, size_t num_detectors, size_t num_observables);\n\n    /// Creates a MeasureRecordReader that reads measurement records in the given format from the given FILE*.\n    /// Record size must be specified upfront. The DETS format supports three different types of records\n    /// and size of each is specified independently. All other formats support one type of record. It is\n    /// an error to specify non-zero size of detection event records or logical observable records unless\n    /// the input format is DETS.\n    static std::unique_ptr<MeasureRecordReader<W>> make(\n        FILE *in,\n        SampleFormat input_format,\n        size_t num_measurements,\n        size_t num_detectors = 0,\n        size_t num_observables = 0);\n\n    virtual ~MeasureRecordReader() = default;\n\n    /// Determines whether or not there is no actual data written for each shot.\n    ///\n    /// For example, sampling a circuit with no measurements produces no bytes of data\n    /// when using the 'b8' format.\n    ///\n    /// This is important to check for sometimes. For example, instead of getting stuck\n    /// in an infinite loop repeatedly reading zero bytes of data and not reaching the\n    /// end of the file, code can check for this degenerate code.\n    virtual bool expects_empty_serialized_data_for_each_shot() const = 0;\n\n    /// Reads entire records into the given bit table.\n    ///\n    /// This method must only be called when the reader is at the start of a record.\n    ///\n    /// Args:\n    ///     out: The bit table to write the records into.\n    ///         The major axis indexes shots.\n    ///         The minor axis indexes results within a shot.\n    ///     major_index_is_shot_index: Whether or not the data should be transposed.\n    ///     max_shots: Maximum number of shots to read. Automatically clamped down based on the size of `out`.\n    ///\n    /// Returns:\n    ///     The number of records that were read.\n    ///     Cannot be larger than the capacity of the output table.\n    ///     If this value is 0, there are no more records to read.\n    ///\n    /// Throws:\n    ///     std::invalid_argument:\n    ///         The minor axis of the table has a length that's too short to hold an entire record.\n    ///         The major axis of the table has length zero.\n    ///         The reader is not at the start of a record.\n    size_t read_records_into(simd_bit_table<W> &out, bool major_index_is_shot_index, size_t max_shots = UINT32_MAX);\n\n    /// Reads an entire record from start to finish, returning False if there are no more records.\n    /// The data from the record is bit packed into a simd_bits.\n    ///\n    /// Args:\n    ///     dirty_out_buffer: The simd-compatible buffer to write the data to. The buffer is not required to be zero'd.\n    ///\n    /// Returns:\n    ///     True: The record was read successfully.\n    ///     False: End of file. There were no more records. No record was read.\n    ///\n    /// Throws:\n    ///     std::invalid_argument: A record was only partially read.\n    virtual bool start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) = 0;\n\n    /// Reads an entire record from start to finish, returning False if there are no more records.\n    /// The data from the record is stored as sparse indices-of-ones data.\n    ///\n    /// When reading detection event data with observables appended, the observable data goes into the `mask` field\n    /// of the output. Note that this method requires that there be at most 32 observables.\n    ///\n    /// Args:\n    ///     cleared_out: A cleared SparseShot struct to write data into.\n    ///\n    /// Returns:\n    ///     True: The record was read successfully.\n    ///     False: End of file. There were no more records. No record was read.\n    ///\n    /// Throws:\n    ///     std::invalid_argument: A record was only partially read.\n    virtual bool start_and_read_entire_record(SparseShot &cleared_out) = 0;\n\n    /// Reads many records into a shot table.\n    ///\n    /// Args:\n    ///     out_table: The table to write shots into.\n    ///         Must have num_minor_bits >= bits_per_shot.\n    ///         num_major_bits is max read shots.\n    ///     max_shots: Don't read more than this many shots.\n    ///         Must be at most the number of shots that can be stored in the table.\n    ///\n    /// Returns:\n    ///     The number of shots that were read.\n    virtual size_t read_into_table_with_major_shot_index(simd_bit_table<W> &out_table, size_t max_shots);\n\n    /// Reads many records into a shot table.\n    ///\n    /// Args:\n    ///     out_table: The table to write shots into.\n    ///         Must have num_major_bits >= bits_per_shot.\n    ///         num_minor_bits is max read shots.\n    ///     max_shots: Don't read more than this many shots.\n    ///         Must be at most the number of shots that can be stored in the table.\n    ///\n    /// Returns:\n    ///     The number of shots that were read.\n    virtual size_t read_into_table_with_minor_shot_index(simd_bit_table<W> &out_table, size_t max_shots) = 0;\n\n   protected:\n    void move_obs_in_shots_to_mask_assuming_sorted(SparseShot &shot);\n};\n\ntemplate <size_t W>\nstruct MeasureRecordReaderFormatPTB64 : MeasureRecordReader<W> {\n    FILE *in;\n    // This buffer stores partially transposed shots.\n    // The uint64_t for index k of shot s is stored in the buffer at offset k*64 + s.\n    simd_bits<W> buf;\n    size_t num_unread_shots_in_buf;\n\n    MeasureRecordReaderFormatPTB64(FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables);\n\n    bool start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) override;\n    bool start_and_read_entire_record(SparseShot &cleared_out) override;\n    bool expects_empty_serialized_data_for_each_shot() const override;\n    size_t read_into_table_with_major_shot_index(simd_bit_table<W> &out_table, size_t max_shots) override;\n    size_t read_into_table_with_minor_shot_index(simd_bit_table<W> &out_table, size_t max_shots) override;\n\n   private:\n    bool load_cache();\n};\n\ntemplate <size_t W>\nstruct MeasureRecordReaderFormat01 : MeasureRecordReader<W> {\n    FILE *in;\n\n    MeasureRecordReaderFormat01(FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables);\n\n    bool start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) override;\n    bool start_and_read_entire_record(SparseShot &cleared_out) override;\n    bool expects_empty_serialized_data_for_each_shot() const override;\n    size_t read_into_table_with_minor_shot_index(simd_bit_table<W> &out_table, size_t max_shots) override;\n\n   private:\n    template <typename SAW0, typename SAW1>\n    bool start_and_read_entire_record_helper(SAW0 saw0, SAW1 saw1);\n};\n\ntemplate <size_t W>\nstruct MeasureRecordReaderFormatB8 : MeasureRecordReader<W> {\n    FILE *in;\n\n    MeasureRecordReaderFormatB8(FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables);\n\n    bool start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) override;\n    bool start_and_read_entire_record(SparseShot &cleared_out) override;\n    bool expects_empty_serialized_data_for_each_shot() const override;\n    size_t read_into_table_with_minor_shot_index(simd_bit_table<W> &out_table, size_t max_shots) override;\n};\n\ntemplate <size_t W>\nstruct MeasureRecordReaderFormatHits : MeasureRecordReader<W> {\n    FILE *in;\n\n    MeasureRecordReaderFormatHits(FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables);\n\n    bool start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) override;\n    bool start_and_read_entire_record(SparseShot &cleared_out) override;\n    bool expects_empty_serialized_data_for_each_shot() const override;\n    size_t read_into_table_with_minor_shot_index(simd_bit_table<W> &out_table, size_t max_shots) override;\n\n   private:\n    template <typename HANDLE_HIT>\n    bool start_and_read_entire_record_helper(HANDLE_HIT handle_hit);\n};\n\ntemplate <size_t W>\nstruct MeasureRecordReaderFormatR8 : MeasureRecordReader<W> {\n    FILE *in;\n\n    MeasureRecordReaderFormatR8(FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables);\n\n    bool start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) override;\n    bool start_and_read_entire_record(SparseShot &cleared_out) override;\n    bool expects_empty_serialized_data_for_each_shot() const override;\n    size_t read_into_table_with_minor_shot_index(simd_bit_table<W> &out_table, size_t max_shots) override;\n\n   private:\n    template <typename HANDLE_HIT>\n    bool start_and_read_entire_record_helper(HANDLE_HIT handle_hit);\n};\n\ntemplate <size_t W>\nstruct MeasureRecordReaderFormatDets : MeasureRecordReader<W> {\n    FILE *in;\n\n    MeasureRecordReaderFormatDets(\n        FILE *in, size_t num_measurements, size_t num_detectors = 0, size_t num_observables = 0);\n\n    bool start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) override;\n    bool start_and_read_entire_record(SparseShot &cleared_out) override;\n    bool expects_empty_serialized_data_for_each_shot() const override;\n    size_t read_into_table_with_minor_shot_index(simd_bit_table<W> &out_table, size_t max_shots) override;\n\n   private:\n    template <typename HANDLE_HIT>\n    bool start_and_read_entire_record_helper(HANDLE_HIT handle_hit);\n};\n\ntemplate <size_t W>\nsize_t read_file_data_into_shot_table(\n    FILE *in,\n    size_t max_shots,\n    size_t num_bits_per_shot,\n    SampleFormat format,\n    char dets_char,\n    simd_bit_table<W> &out_table,\n    bool shots_is_major_index_of_out_table);\n\n}  // namespace stim\n\n#include \"stim/io/measure_record_reader.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/io/measure_record_reader.inl",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <algorithm>\n\n#include \"stim/io/measure_record_reader.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nMeasureRecordReader<W>::MeasureRecordReader(size_t num_measurements, size_t num_detectors, size_t num_observables)\n    : num_measurements(num_measurements), num_detectors(num_detectors), num_observables(num_observables) {\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReader<W>::read_records_into(\n    simd_bit_table<W> &out, bool major_index_is_shot_index, size_t max_shots) {\n    if (!major_index_is_shot_index) {\n        simd_bit_table<W> buf(out.num_minor_bits_padded(), out.num_major_bits_padded());\n        size_t r = read_records_into(buf, true, max_shots);\n        buf.transpose_into(out);\n        return r;\n    }\n\n    size_t num_read = 0;\n    max_shots = std::min(max_shots, out.num_major_bits_padded());\n    while (num_read < max_shots && start_and_read_entire_record(out[num_read])) {\n        num_read++;\n    }\n    return num_read;\n}\n\ntemplate <size_t W>\nstd::unique_ptr<MeasureRecordReader<W>> MeasureRecordReader<W>::make(\n    FILE *in, SampleFormat input_format, size_t num_measurements, size_t num_detectors, size_t num_observables) {\n    switch (input_format) {\n        case SampleFormat::SAMPLE_FORMAT_01:\n            return std::make_unique<MeasureRecordReaderFormat01<W>>(\n                in, num_measurements, num_detectors, num_observables);\n        case SampleFormat::SAMPLE_FORMAT_B8:\n            return std::make_unique<MeasureRecordReaderFormatB8<W>>(\n                in, num_measurements, num_detectors, num_observables);\n        case SampleFormat::SAMPLE_FORMAT_DETS:\n            return std::make_unique<MeasureRecordReaderFormatDets<W>>(\n                in, num_measurements, num_detectors, num_observables);\n        case SampleFormat::SAMPLE_FORMAT_HITS:\n            return std::make_unique<MeasureRecordReaderFormatHits<W>>(\n                in, num_measurements, num_detectors, num_observables);\n        case SampleFormat::SAMPLE_FORMAT_PTB64:\n            return std::make_unique<MeasureRecordReaderFormatPTB64<W>>(\n                in, num_measurements, num_detectors, num_observables);\n        case SampleFormat::SAMPLE_FORMAT_R8:\n            return std::make_unique<MeasureRecordReaderFormatR8<W>>(\n                in, num_measurements, num_detectors, num_observables);\n        default:\n            throw std::invalid_argument(\"Sample format not recognized by MeasurementRecordReader\");\n    }\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReader<W>::bits_per_record() const {\n    return num_measurements + num_detectors + num_observables;\n}\n\ntemplate <size_t W>\nvoid MeasureRecordReader<W>::move_obs_in_shots_to_mask_assuming_sorted(SparseShot &shot) {\n    if (num_observables > 32) {\n        throw std::invalid_argument(\"More than 32 observables. Can't read into SparseShot struct.\");\n    }\n\n    size_t nd = num_measurements + num_detectors;\n    size_t n = nd + num_observables;\n    shot.obs_mask.clear();\n    while (!shot.hits.empty()) {\n        auto top = shot.hits.back();\n        if (top < nd) {\n            break;\n        }\n        if (top >= n) {\n            throw std::invalid_argument(\"Hit index from data is too large.\");\n        }\n        shot.hits.pop_back();\n        shot.obs_mask[top - nd] ^= true;\n    }\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReader<W>::read_into_table_with_major_shot_index(simd_bit_table<W> &out_table, size_t max_shots) {\n    size_t read_shots = 0;\n    while (read_shots < max_shots && start_and_read_entire_record(out_table[read_shots])) {\n        read_shots++;\n    }\n    return read_shots;\n}\n\n/// 01 format\n\ntemplate <size_t W>\nMeasureRecordReaderFormat01<W>::MeasureRecordReaderFormat01(\n    FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables)\n    : MeasureRecordReader<W>(num_measurements, num_detectors, num_observables), in(in) {\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormat01<W>::start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) {\n    return start_and_read_entire_record_helper(\n        [&](size_t k) {\n            dirty_out_buffer[k] = false;\n        },\n        [&](size_t k) {\n            dirty_out_buffer[k] = true;\n        });\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormat01<W>::start_and_read_entire_record(SparseShot &cleared_out) {\n    if (cleared_out.obs_mask.num_bits_padded() < this->num_observables) {\n        cleared_out.obs_mask = simd_bits<64>(this->num_observables);\n    }\n    bool result = start_and_read_entire_record_helper(\n        [&](size_t k) {\n        },\n        [&](size_t k) {\n            cleared_out.hits.push_back((uint64_t)k);\n        });\n    this->move_obs_in_shots_to_mask_assuming_sorted(cleared_out);\n    return result;\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormat01<W>::expects_empty_serialized_data_for_each_shot() const {\n    return false;\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReaderFormat01<W>::read_into_table_with_minor_shot_index(\n    simd_bit_table<W> &out_table, size_t max_shots) {\n    size_t read_shots = 0;\n    while (read_shots < max_shots) {\n        bool more = start_and_read_entire_record_helper(\n            [&](size_t k) {\n                out_table[k][read_shots] &= 0;\n            },\n            [&](size_t k) {\n                out_table[k][read_shots] |= 1;\n            });\n        if (!more) {\n            break;\n        }\n        read_shots++;\n    }\n    return read_shots;\n}\n\ntemplate <size_t W>\ntemplate <typename SAW0, typename SAW1>\nbool MeasureRecordReaderFormat01<W>::start_and_read_entire_record_helper(SAW0 saw0, SAW1 saw1) {\n    size_t n = this->bits_per_record();\n    for (size_t k = 0; k < n; k++) {\n        int b = getc(in);\n        switch (b) {\n            case '0':\n                saw0(k);\n                break;\n            case '1':\n                saw1(k);\n                break;\n            case EOF:\n                if (k == 0) {\n                    return false;\n                }\n                [[fallthrough]];\n            case '\\r':\n                [[fallthrough]];\n            case '\\n':\n                throw std::invalid_argument(\n                    \"01 data ended in middle of record at byte position \" + std::to_string(k) +\n                    \".\\nExpected bits per record was \" + std::to_string(n) + \".\");\n            default:\n                throw std::invalid_argument(\"Unexpected character in 01 format data: '\" + std::to_string(b) + \"'.\");\n        }\n    }\n    int last = getc(in);\n    if (n == 0 && last == EOF) {\n        return false;\n    }\n    if (last == '\\r') {\n        last = getc(in);\n    }\n    if (last != '\\n') {\n        throw std::invalid_argument(\n            \"01 data didn't end with a newline after the expected data length of '\" + std::to_string(n) + \"'.\");\n    }\n    return true;\n}\n\n/// B8 format\n\ntemplate <size_t W>\nMeasureRecordReaderFormatB8<W>::MeasureRecordReaderFormatB8(\n    FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables)\n    : MeasureRecordReader<W>(num_measurements, num_detectors, num_observables), in(in) {\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatB8<W>::start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) {\n    size_t n = this->bits_per_record();\n    size_t nb = (n + 7) >> 3;\n    size_t nr = fread(dirty_out_buffer.u8, 1, nb, in);\n    if (nr == 0) {\n        return false;\n    }\n    if (nr != nb) {\n        throw std::invalid_argument(\n            \"b8 data ended in middle of record at byte position \" + std::to_string(nr) +\n            \".\\n\"\n            \"Expected bytes per record was \" +\n            std::to_string(nb) + \" (\" + std::to_string(n) + \" bits padded).\");\n    }\n    return true;\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReaderFormatB8<W>::read_into_table_with_minor_shot_index(\n    simd_bit_table<W> &out_table, size_t max_shots) {\n    size_t n = this->bits_per_record();\n    if (n == 0) {\n        return 0;  // Ambiguous when the data ends. Stop as early as possible.\n    }\n    for (size_t read_shots = 0; read_shots < max_shots; read_shots++) {\n        for (size_t bit = 0; bit < n; bit += 8) {\n            int c = getc(in);\n            if (c == EOF) {\n                if (bit == 0) {\n                    return read_shots;\n                }\n                throw std::invalid_argument(\"b8 data ended in middle of record.\");\n            }\n            for (size_t b = 0; b < 8 && bit + b < n; b++) {\n                out_table[bit + b][read_shots] = ((c >> b) & 1) != 0;\n            }\n        }\n    }\n    return max_shots;\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatB8<W>::start_and_read_entire_record(SparseShot &cleared_out) {\n    if (cleared_out.obs_mask.num_bits_padded() < this->num_observables) {\n        cleared_out.obs_mask = simd_bits<64>(this->num_observables);\n    }\n    size_t n = this->bits_per_record();\n    size_t nb = (n + 7) >> 3;\n    if (n == 0) {\n        return 0;  // Ambiguous when the data ends. Stop as early as possible.\n    }\n    for (size_t k = 0; k < nb; k++) {\n        int b = getc(in);\n        if (b == EOF) {\n            if (k == 0) {\n                return false;\n            }\n            throw std::invalid_argument(\n                \"b8 data ended in middle of record at byte position \" + std::to_string(k) +\n                \".\\n\"\n                \"Expected bytes per record was \" +\n                std::to_string(nb) + \" (\" + std::to_string(n) + \" bits padded).\");\n        }\n\n        size_t bit_offset = k << 3;\n        for (size_t r = 0; r < 8; r++) {\n            if (b & (1 << r)) {\n                cleared_out.hits.push_back(bit_offset + r);\n            }\n        }\n    }\n    this->move_obs_in_shots_to_mask_assuming_sorted(cleared_out);\n    return true;\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatB8<W>::expects_empty_serialized_data_for_each_shot() const {\n    return this->bits_per_record() == 0;\n}\n\n/// Hits format\n\ntemplate <size_t W>\nMeasureRecordReaderFormatHits<W>::MeasureRecordReaderFormatHits(\n    FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables)\n    : MeasureRecordReader<W>(num_measurements, num_detectors, num_observables), in(in) {\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatHits<W>::start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) {\n    size_t m = this->bits_per_record();\n    dirty_out_buffer.prefix_ref(m).clear();\n    return start_and_read_entire_record_helper([&](size_t bit_index) {\n        if (bit_index >= m) {\n            throw std::invalid_argument(\"hit index is too large.\");\n        }\n        dirty_out_buffer[bit_index] ^= true;\n    });\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatHits<W>::start_and_read_entire_record(SparseShot &cleared_out) {\n    if (cleared_out.obs_mask.num_bits_padded() < this->num_observables) {\n        cleared_out.obs_mask = simd_bits<64>(this->num_observables);\n    }\n    size_t m = this->bits_per_record();\n    size_t nmd = this->num_measurements + this->num_detectors;\n    return start_and_read_entire_record_helper([&](size_t bit_index) {\n        if (bit_index >= m) {\n            throw std::invalid_argument(\"hit index is too large.\");\n        }\n        if (bit_index < nmd) {\n            cleared_out.hits.push_back(bit_index);\n        } else {\n            cleared_out.obs_mask[bit_index - nmd] ^= true;\n        }\n    });\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatHits<W>::expects_empty_serialized_data_for_each_shot() const {\n    return false;\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReaderFormatHits<W>::read_into_table_with_minor_shot_index(\n    simd_bit_table<W> &out_table, size_t max_shots) {\n    size_t read_shots = 0;\n    out_table.clear();\n    while (read_shots < max_shots) {\n        bool more = start_and_read_entire_record_helper([&](size_t bit_index) {\n            out_table[bit_index][read_shots] |= 1;\n        });\n        if (!more) {\n            break;\n        }\n        read_shots++;\n    }\n    return read_shots;\n}\n\ntemplate <size_t W>\ntemplate <typename HANDLE_HIT>\nbool MeasureRecordReaderFormatHits<W>::start_and_read_entire_record_helper(HANDLE_HIT handle_hit) {\n    bool first = true;\n    while (true) {\n        int next_char;\n        uint64_t value;\n        if (!read_uint64(in, value, next_char, false)) {\n            if (first && next_char == EOF) {\n                return false;\n            }\n            if (first && next_char == '\\r') {\n                next_char = getc(in);\n            }\n            if (first && next_char == '\\n') {\n                return true;\n            }\n            throw std::invalid_argument(\"HITS data wasn't comma-separated integers terminated by a newline.\");\n        }\n        handle_hit((size_t)value);\n        first = false;\n        if (next_char == '\\r') {\n            next_char = getc(in);\n            if (next_char == '\\n') {\n                return true;\n            }\n        } else if (next_char == '\\n') {\n            return true;\n        }\n        if (next_char != ',') {\n            throw std::invalid_argument(\"HITS data wasn't comma-separated integers terminated by a newline.\");\n        }\n    }\n}\n\n/// R8 format\n\ntemplate <size_t W>\nMeasureRecordReaderFormatR8<W>::MeasureRecordReaderFormatR8(\n    FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables)\n    : MeasureRecordReader<W>(num_measurements, num_detectors, num_observables), in(in) {\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatR8<W>::start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) {\n    dirty_out_buffer.prefix_ref(this->bits_per_record()).clear();\n    return start_and_read_entire_record_helper([&](size_t bit_index) {\n        dirty_out_buffer[bit_index] = 1;\n    });\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatR8<W>::start_and_read_entire_record(SparseShot &cleared_out) {\n    if (cleared_out.obs_mask.num_bits_padded() < this->num_observables) {\n        cleared_out.obs_mask = simd_bits<64>(this->num_observables);\n    }\n    bool result = start_and_read_entire_record_helper([&](size_t bit_index) {\n        cleared_out.hits.push_back(bit_index);\n    });\n    this->move_obs_in_shots_to_mask_assuming_sorted(cleared_out);\n    return result;\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatR8<W>::expects_empty_serialized_data_for_each_shot() const {\n    return false;\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReaderFormatR8<W>::read_into_table_with_minor_shot_index(\n    simd_bit_table<W> &out_table, size_t max_shots) {\n    size_t read_shots = 0;\n    out_table.clear();\n    while (read_shots < max_shots) {\n        bool more = start_and_read_entire_record_helper([&](size_t bit_index) {\n            out_table[bit_index][read_shots] |= 1;\n        });\n        if (!more) {\n            break;\n        }\n        read_shots++;\n    }\n    return read_shots;\n}\n\ntemplate <size_t W>\ntemplate <typename HANDLE_HIT>\nbool MeasureRecordReaderFormatR8<W>::start_and_read_entire_record_helper(HANDLE_HIT handle_hit) {\n    int next_char = getc(in);\n    if (next_char == EOF) {\n        return false;\n    }\n\n    size_t n = this->bits_per_record();\n    size_t pos = 0;\n    while (true) {\n        pos += next_char;\n        if (next_char != 255) {\n            if (pos < n) {\n                handle_hit(pos);\n                pos++;\n            } else if (pos == n) {\n                return true;\n            } else {\n                throw std::invalid_argument(\n                    \"r8 data jumped past expected end of encoded data. Expected to decode \" +\n                    std::to_string(this->bits_per_record()) + \" bits.\");\n            }\n        }\n        next_char = getc(in);\n        if (next_char == EOF) {\n            throw std::invalid_argument(\n                \"End of file before end of r8 data. Expected to decode \" + std::to_string(this->bits_per_record()) +\n                \" bits.\");\n        }\n    }\n}\n\n/// DETS format\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatDets<W>::start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) {\n    dirty_out_buffer.prefix_ref(this->bits_per_record()).clear();\n    return start_and_read_entire_record_helper([&](size_t bit_index) {\n        dirty_out_buffer[bit_index] = true;\n    });\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatDets<W>::start_and_read_entire_record(SparseShot &cleared_out) {\n    if (cleared_out.obs_mask.num_bits_padded() < this->num_observables) {\n        cleared_out.obs_mask = simd_bits<64>(this->num_observables);\n    }\n    size_t obs_start = this->num_measurements + this->num_detectors;\n    return start_and_read_entire_record_helper([&](size_t bit_index) {\n        if (bit_index < obs_start) {\n            cleared_out.hits.push_back(bit_index);\n        } else {\n            cleared_out.obs_mask[bit_index - obs_start] ^= true;\n        }\n    });\n}\n\ntemplate <size_t W>\nMeasureRecordReaderFormatDets<W>::MeasureRecordReaderFormatDets(\n    FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables)\n    : MeasureRecordReader<W>(num_measurements, num_detectors, num_observables), in(in) {\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatDets<W>::expects_empty_serialized_data_for_each_shot() const {\n    return false;\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReaderFormatDets<W>::read_into_table_with_minor_shot_index(\n    simd_bit_table<W> &out_table, size_t max_shots) {\n    size_t read_shots = 0;\n    out_table.clear();\n    while (read_shots < max_shots) {\n        bool more = start_and_read_entire_record_helper([&](size_t bit_index) {\n            out_table[bit_index][read_shots] |= 1;\n        });\n        if (!more) {\n            break;\n        }\n        read_shots++;\n    }\n    return read_shots;\n}\n\ntemplate <size_t W>\ntemplate <typename HANDLE_HIT>\nbool MeasureRecordReaderFormatDets<W>::start_and_read_entire_record_helper(HANDLE_HIT handle_hit) {\n    // Read \"shot\" prefix, or notice end of data. Ignore indentation and spacing.\n    while (true) {\n        int next_char = getc(in);\n        if (next_char == ' ' || next_char == '\\n' || next_char == '\\r' || next_char == '\\t') {\n            continue;\n        }\n        if (next_char == EOF) {\n            return false;\n        }\n        if (next_char != 's' || getc(in) != 'h' || getc(in) != 'o' || getc(in) != 't') {\n            throw std::invalid_argument(\"DETS data didn't start with 'shot'\");\n        }\n        break;\n    }\n\n    // Read prefixed integers until end of line.\n    int next_char = getc(in);\n    while (true) {\n        if (next_char == '\\r') {\n            next_char = getc(in);\n        }\n        if (next_char == '\\n' || next_char == EOF) {\n            return true;\n        }\n        if (next_char != ' ') {\n            throw std::invalid_argument(\"DETS data wasn't single-space-separated with no trailing spaces.\");\n        }\n        next_char = getc(in);\n        uint64_t offset;\n        uint64_t length;\n        if (next_char == 'M') {\n            offset = 0;\n            length = this->num_measurements;\n        } else if (next_char == 'D') {\n            offset = this->num_measurements;\n            length = this->num_detectors;\n        } else if (next_char == 'L') {\n            offset = this->num_measurements + this->num_detectors;\n            length = this->num_observables;\n        } else {\n            throw std::invalid_argument(\n                \"Unrecognized DETS prefix. Expected M or D or L not '\" + std::to_string(next_char) + \"'\");\n        }\n        char prefix = next_char;\n\n        uint64_t value;\n        if (!read_uint64(in, value, next_char, false)) {\n            throw std::invalid_argument(\"DETS data had a value prefix (M or D or L) not followed by an integer.\");\n        }\n        if (value >= length) {\n            std::stringstream msg;\n            msg << \"DETS data had a value larger than expected. \";\n            msg << \"Got \" << prefix << value << \" but expected length of \" << prefix << \" space to be \" << length\n                << \".\";\n            throw std::invalid_argument(msg.str());\n        }\n        handle_hit((size_t)(offset + value));\n    }\n}\n\n/// PTB64 format\n\ntemplate <size_t W>\nMeasureRecordReaderFormatPTB64<W>::MeasureRecordReaderFormatPTB64(\n    FILE *in, size_t num_measurements, size_t num_detectors, size_t num_observables)\n    : MeasureRecordReader<W>(num_measurements, num_detectors, num_observables),\n      in(in),\n      buf(0),\n      num_unread_shots_in_buf(0) {\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatPTB64<W>::load_cache() {\n    size_t n = this->bits_per_record();\n    size_t expected_buf_bits = (n + 63) / 64 * 64 * 64;\n    if (buf.num_bits_padded() < expected_buf_bits) {\n        buf = simd_bits<W>(expected_buf_bits);\n    }\n\n    size_t nb = this->bits_per_record() * (64 / 8);\n    size_t nr = fread(buf.u8, 1, nb, in);\n    if (nr == 0) {\n        num_unread_shots_in_buf = 0;\n        return false;\n    }\n    if (nr != nb) {\n        throw std::invalid_argument(\n            \"ptb64 data ended in middle of 64 record group at byte position \" + std::to_string(nr) +\n            \".\\n\"\n            \"Expected bytes per 64 records was \" +\n            std::to_string(nb) + \" (\" + std::to_string(n) + \" bits padded).\");\n    }\n\n    // Convert from bit interleaving to uint64_t interleaving.\n    for (size_t k = 0; k + 63 < n; k += 64) {\n        inplace_transpose_64x64(buf.u64 + k, 1);\n    }\n\n    num_unread_shots_in_buf = 64;\n    return true;\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatPTB64<W>::start_and_read_entire_record(simd_bits_range_ref<W> dirty_out_buffer) {\n    if (num_unread_shots_in_buf == 0) {\n        load_cache();\n    }\n    if (num_unread_shots_in_buf == 0) {\n        return false;\n    }\n\n    size_t offset = 64 - num_unread_shots_in_buf;\n    size_t n = this->bits_per_record();\n    size_t n64 = n / 64;\n    for (size_t k = 0; k < n64; k++) {\n        dirty_out_buffer.u64[k] = buf.u64[k * 64 + offset];\n    }\n    for (size_t k = n64 * 64; k < n; k++) {\n        dirty_out_buffer[k] = buf[k * 64 + offset];\n    }\n    num_unread_shots_in_buf -= 1;\n    return true;\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatPTB64<W>::start_and_read_entire_record(SparseShot &cleared_out) {\n    if (cleared_out.obs_mask.num_bits_padded() < this->num_observables) {\n        cleared_out.obs_mask = simd_bits<64>(this->num_observables);\n    }\n    if (num_unread_shots_in_buf == 0) {\n        load_cache();\n    }\n    if (num_unread_shots_in_buf == 0) {\n        return false;\n    }\n\n    size_t offset = 64 - num_unread_shots_in_buf;\n    size_t n = this->bits_per_record();\n    size_t n64 = n / 64;\n    for (size_t k = 0; k < n64; k++) {\n        uint64_t v = buf.u64[k * 64 + offset];\n        if (v) {\n            for (size_t k2 = 0; k2 < 64; k2++) {\n                if ((v >> k2) & 1) {\n                    cleared_out.hits.push_back(k * 64 + k2);\n                }\n            }\n        }\n    }\n    for (size_t k = n64 * 64; k < n; k++) {\n        if (buf[k * 64 + offset]) {\n            cleared_out.hits.push_back(k);\n        }\n    }\n    num_unread_shots_in_buf -= 1;\n    this->move_obs_in_shots_to_mask_assuming_sorted(cleared_out);\n    return true;\n}\n\ntemplate <size_t W>\nbool MeasureRecordReaderFormatPTB64<W>::expects_empty_serialized_data_for_each_shot() const {\n    return this->bits_per_record() == 0;\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReaderFormatPTB64<W>::read_into_table_with_minor_shot_index(\n    simd_bit_table<W> &out_table, size_t max_shots) {\n    size_t n = this->bits_per_record();\n    if (n == 0) {\n        return 0;  // Ambiguous when the data ends. Stop as early as possible.\n    }\n    if (max_shots % 64 != 0) {\n        throw std::invalid_argument(\"max_shots must be a multiple of 64 when using PTB64 format\");\n    }\n    for (size_t shots_read = 0; shots_read < max_shots; shots_read += 64) {\n        for (size_t bit = 0; bit < n; bit++) {\n            size_t read = fread(&out_table[bit].u64[shots_read >> 6], 1, sizeof(uint64_t), in);\n            if (read != sizeof(uint64_t)) {\n                if (read == 0 && bit == 0) {\n                    // End of file at a shot boundary.\n                    return shots_read;\n                } else {\n                    // Fragmented file.\n                    throw std::invalid_argument(\"File ended in the middle of a ptb64 record.\");\n                }\n            }\n        }\n    }\n    return max_shots;\n}\n\ntemplate <size_t W>\nsize_t MeasureRecordReaderFormatPTB64<W>::read_into_table_with_major_shot_index(\n    simd_bit_table<W> &out_table, size_t max_shots) {\n    size_t n = this->bits_per_record();\n    if (n == 0) {\n        return 0;  // Ambiguous when the data ends. Stop as early as possible.\n    }\n    uint64_t buffer[64];\n    assert(max_shots % 64 == 0);\n    for (size_t shot = 0; shot < max_shots; shot += 64) {\n        for (size_t bit = 0; bit < n; bit += 64) {\n            for (size_t b = 0; b < 64; b++) {\n                if (bit + b >= n) {\n                    buffer[b] = 0;\n                } else {\n                    size_t read = fread(&buffer[b], 1, sizeof(uint64_t), in);\n                    if (read != sizeof(uint64_t)) {\n                        if (read == 0 && bit == 0 && b == 0) {\n                            // End of file at a shot boundary.\n                            return shot;\n                        } else {\n                            // Fragmented file.\n                            throw std::invalid_argument(\"File ended in the middle of a ptb64 record.\");\n                        }\n                    }\n                }\n            }\n            inplace_transpose_64x64(buffer, 1);\n            for (size_t s = 0; s < 64; s++) {\n                out_table[shot + s].u64[bit >> 6] = buffer[s];\n            }\n        }\n    }\n    return max_shots;\n}\n\ntemplate <size_t W>\nsize_t read_file_data_into_shot_table(\n    FILE *in,\n    size_t max_shots,\n    size_t num_bits_per_shot,\n    SampleFormat format,\n    char dets_char,\n    simd_bit_table<W> &out_table,\n    bool shots_is_major_index_of_out_table) {\n    auto reader = MeasureRecordReader<W>::make(\n        in,\n        format,\n        dets_char == 'M' ? num_bits_per_shot : 0,\n        dets_char == 'D' ? num_bits_per_shot : 0,\n        dets_char == 'L' ? num_bits_per_shot : 0);\n    if (shots_is_major_index_of_out_table) {\n        return reader->read_into_table_with_major_shot_index(out_table, max_shots);\n    } else {\n        return reader->read_into_table_with_minor_shot_index(out_table, max_shots);\n    }\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/io/measure_record_reader.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/io/measure_record_reader.h\"\n\n#include \"stim/io/measure_record_writer.h\"\n#include \"stim/perf.perf.h\"\n#include \"stim/util_bot/probability_util.h\"\n\nusing namespace stim;\n\ntemplate <size_t n, size_t denom, SampleFormat format>\nvoid dense_reader_benchmark(double goal_micros) {\n    double p = 1 / (double)denom;\n    FILE *f = tmpfile();\n    {\n        auto writer = MeasureRecordWriter::make(f, format);\n        simd_bits<MAX_BITWORD_WIDTH> data(n);\n        std::mt19937_64 rng(0);\n        biased_randomize_bits(p, data.u64, data.u64 + (n >> 6), rng);\n        writer->write_bytes({data.u8, data.u8 + (n >> 3)});\n        writer->write_end();\n    }\n\n    auto reader = MeasureRecordReader<MAX_BITWORD_WIDTH>::make(f, format, n, 0, 0);\n    simd_bits<MAX_BITWORD_WIDTH> buffer(n);\n    benchmark_go([&]() {\n        rewind(f);\n        reader->start_and_read_entire_record(buffer);\n    })\n        .goal_micros(goal_micros)\n        .show_rate(\"Bits\", n);\n    if (!buffer.not_zero()) {\n        std::cerr << \"data dependence!\\n\";\n    }\n    fclose(f);\n}\n\ntemplate <size_t n, size_t denom, SampleFormat format>\nvoid sparse_reader_benchmark(double goal_micros) {\n    double p = 1 / (double)denom;\n    FILE *f = tmpfile();\n    {\n        auto writer = MeasureRecordWriter::make(f, format);\n        simd_bits<MAX_BITWORD_WIDTH> data(n);\n        std::mt19937_64 rng(0);\n        biased_randomize_bits(p, data.u64, data.u64 + (n >> 6), rng);\n        writer->write_bytes({data.u8, data.u8 + (n >> 3)});\n        writer->write_end();\n    }\n\n    auto reader = MeasureRecordReader<MAX_BITWORD_WIDTH>::make(f, format, n, 0, 0);\n    SparseShot buffer;\n    buffer.hits.reserve((size_t)ceil(n * p * 1.1));\n    benchmark_go([&]() {\n        rewind(f);\n        buffer.clear();\n        reader->start_and_read_entire_record(buffer);\n    })\n        .goal_micros(goal_micros)\n        .show_rate(\"Pops\", n * p);\n    if (buffer.hits.empty()) {\n        std::cerr << \"data dependence!\\n\";\n    }\n    fclose(f);\n}\n\nBENCHMARK(read_01_dense_per10) {\n    dense_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_01>(60);\n}\nBENCHMARK(read_01_sparse_per10) {\n    sparse_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_01>(45);\n}\n\nBENCHMARK(read_b8_dense_per10) {\n    dense_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_B8>(0.65);\n}\nBENCHMARK(read_b8_sparse_per10) {\n    sparse_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_B8>(6);\n}\n\nBENCHMARK(read_hits_dense_per10) {\n    dense_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_HITS>(16);\n}\nBENCHMARK(read_hits_dense_per100) {\n    dense_reader_benchmark<10000, 100, SampleFormat::SAMPLE_FORMAT_HITS>(2.1);\n}\nBENCHMARK(read_hits_sparse_per10) {\n    sparse_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_HITS>(15);\n}\nBENCHMARK(read_hits_sparse_per100) {\n    sparse_reader_benchmark<10000, 100, SampleFormat::SAMPLE_FORMAT_HITS>(2.2);\n}\n\nBENCHMARK(read_dets_dense_per10) {\n    dense_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_DETS>(23);\n}\nBENCHMARK(read_dets_dense_per100) {\n    dense_reader_benchmark<10000, 100, SampleFormat::SAMPLE_FORMAT_DETS>(3.0);\n}\nBENCHMARK(read_dets_sparse_per10) {\n    sparse_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_DETS>(23);\n}\nBENCHMARK(read_dets_sparse_per100) {\n    sparse_reader_benchmark<10000, 100, SampleFormat::SAMPLE_FORMAT_DETS>(3.0);\n}\n\nBENCHMARK(read_r8_dense_per10) {\n    dense_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_R8>(5);\n}\nBENCHMARK(read_r8_dense_per100) {\n    dense_reader_benchmark<10000, 100, SampleFormat::SAMPLE_FORMAT_R8>(1.3);\n}\nBENCHMARK(read_r8_sparse_per10) {\n    sparse_reader_benchmark<10000, 10, SampleFormat::SAMPLE_FORMAT_R8>(3.5);\n}\nBENCHMARK(read_r8_sparse_per100) {\n    sparse_reader_benchmark<10000, 100, SampleFormat::SAMPLE_FORMAT_R8>(1.0);\n}\n"
  },
  {
    "path": "src/stim/io/measure_record_reader.test.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/measure_record_reader.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/io/measure_record_batch_writer.h\"\n#include \"stim/io/measure_record_writer.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/probability_util.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nFILE *tmpfile_with_contents(std::string_view contents) {\n    FILE *tmp = tmpfile();\n    size_t written = fwrite(contents.data(), 1, contents.size(), tmp);\n    if (written != contents.size()) {\n        int en = errno;\n        std::cerr << \"Failed to write to tmpfile: \" << strerror(en) << std::endl;\n        throw std::invalid_argument(\"Failed to write to tmpfile\");\n    }\n    rewind(tmp);\n    return tmp;\n}\n\nTEST(read_unsigned_int, BasicUsage) {\n    int next = 0;\n    uint64_t value = 0;\n    FILE *tmp = tmpfile_with_contents(\"105\\n\");\n    ASSERT_NE(tmp, nullptr);\n    ASSERT_TRUE(read_uint64(tmp, value, next));\n    ASSERT_EQ(next, '\\n');\n    ASSERT_EQ(value, 105);\n}\n\nTEST(read_unsigned_int, ValueTooBig) {\n    int next = 0;\n    uint64_t value = 0;\n    FILE *tmp = tmpfile_with_contents(\"18446744073709551616\\n\");\n    ASSERT_NE(tmp, nullptr);\n    ASSERT_THROW({ read_uint64(tmp, value, next); }, std::runtime_error);\n}\n\ntemplate <size_t W>\nvoid assert_contents_load_correctly(SampleFormat format, std::string_view contents) {\n    FILE *tmp = tmpfile_with_contents(contents);\n    auto reader = MeasureRecordReader<W>::make(tmp, format, 18);\n    simd_bits<W> buf(18);\n    reader->start_and_read_entire_record(buf);\n    ASSERT_EQ(buf[0], 0);\n    ASSERT_EQ(buf[1], 0);\n    ASSERT_EQ(buf[2], 0);\n    ASSERT_EQ(buf[3], 1);\n    ASSERT_EQ(buf[4], 1);\n    ASSERT_EQ(buf[5], 1);\n    ASSERT_EQ(buf[6], 1);\n    ASSERT_EQ(buf[7], 1);\n    ASSERT_EQ(buf[8], 0);\n    ASSERT_EQ(buf[9], 0);\n    ASSERT_EQ(buf[10], 0);\n    ASSERT_EQ(buf[11], 0);\n    ASSERT_EQ(buf[12], 1);\n    ASSERT_EQ(buf[13], 1);\n    ASSERT_EQ(buf[14], 1);\n    ASSERT_EQ(buf[15], 1);\n    ASSERT_EQ(buf[16], 1);\n    ASSERT_EQ(buf[17], 1);\n\n    rewind(tmp);\n    SparseShot sparse;\n    reader->start_and_read_entire_record(sparse);\n    ASSERT_EQ(sparse.hits, (std::vector<uint64_t>{3, 4, 5, 6, 7, 12, 13, 14, 15, 16, 17}));\n}\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, Format01, {\n    assert_contents_load_correctly<W>(SampleFormat::SAMPLE_FORMAT_01, \"000111110000111111\\n\");\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatB8, {\n    assert_contents_load_correctly<W>(SampleFormat::SAMPLE_FORMAT_B8, \"\\xF8\\xF0\\x03\");\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatHits, {\n    assert_contents_load_correctly<W>(SampleFormat::SAMPLE_FORMAT_HITS, \"3,4,5,6,7,12,13,14,15,16,17\\n\");\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatR8, {\n    char tmp_data[]{3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0};\n    assert_contents_load_correctly<W>(\n        SampleFormat::SAMPLE_FORMAT_R8, std::string(std::begin(tmp_data), std::end(tmp_data)));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatR8_LongGap, {\n    FILE *tmp = tmpfile_with_contents(\"\\xFF\\xFF\\x02\\x20\");\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_R8, 8 * 64 + 32 + 1);\n    SparseShot sparse;\n    ASSERT_TRUE(reader->start_and_read_entire_record(sparse));\n    ASSERT_EQ(sparse.hits, (std::vector<uint64_t>{255 + 255 + 2}));\n    ASSERT_FALSE(reader->start_and_read_entire_record(sparse));\n})\n\nFILE *write_records(SpanRef<const uint8_t> data, SampleFormat format) {\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, format);\n    writer->write_bytes(data);\n    writer->write_end();\n    return tmp;\n}\n\ntemplate <size_t W>\nsize_t read_records_as_bytes(FILE *in, SpanRef<uint8_t> buf, SampleFormat format, size_t bits_per_record) {\n    auto reader = MeasureRecordReader<W>::make(in, format, bits_per_record);\n    if (buf.size() * 8 < reader->bits_per_record()) {\n        throw std::invalid_argument(\"buf too small\");\n    }\n    simd_bits<W> buf2(reader->bits_per_record());\n    bool success = reader->start_and_read_entire_record(buf2);\n    EXPECT_TRUE(success);\n    memcpy(buf.ptr_start, buf2.u8, (reader->bits_per_record() + 7) / 8);\n    return reader->bits_per_record();\n}\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, Format01_WriteRead, {\n    uint8_t src[]{0, 1, 2, 3, 4, 0xFF, 0xBF, 0xFE, 80, 0, 0, 1, 20};\n    constexpr size_t num_bytes = sizeof(src) / sizeof(uint8_t);\n    uint8_t dst[num_bytes];\n    memset(dst, 0, num_bytes);\n    FILE *tmp = write_records({src, src + num_bytes}, SampleFormat::SAMPLE_FORMAT_01);\n    rewind(tmp);\n    ASSERT_EQ(\n        num_bytes * 8,\n        read_records_as_bytes<W>(tmp, {dst, dst + num_bytes}, SampleFormat::SAMPLE_FORMAT_01, 8 * num_bytes));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(src[i], dst[i]);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatB8_WriteRead, {\n    uint8_t src[]{0, 1, 2, 3, 4, 0xFF, 0xBF, 0xFE, 80, 0, 0, 1, 20};\n    constexpr size_t num_bytes = sizeof(src) / sizeof(uint8_t);\n    uint8_t dst[num_bytes];\n    memset(dst, 0, num_bytes);\n    FILE *tmp = write_records({src, src + num_bytes}, SampleFormat::SAMPLE_FORMAT_B8);\n    rewind(tmp);\n    ASSERT_EQ(\n        num_bytes * 8,\n        read_records_as_bytes<W>(tmp, {dst, dst + num_bytes}, SampleFormat::SAMPLE_FORMAT_B8, 8 * num_bytes));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(src[i], dst[i]);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatR8_WriteRead, {\n    uint8_t src[]{0, 1, 2, 3, 4, 0xFF, 0xBF, 0xFE, 80, 0, 0, 1, 20};\n    constexpr size_t num_bytes = sizeof(src) / sizeof(uint8_t);\n    uint8_t dst[num_bytes]{};\n    FILE *tmp = write_records({src, src + num_bytes}, SampleFormat::SAMPLE_FORMAT_R8);\n    rewind(tmp);\n    ASSERT_EQ(\n        num_bytes * 8,\n        read_records_as_bytes<W>(tmp, {dst, dst + num_bytes}, SampleFormat::SAMPLE_FORMAT_R8, 8 * num_bytes));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(src[i], dst[i]);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatHits_WriteRead, {\n    uint8_t src[]{0, 1, 2, 3, 4, 0xFF, 0xBF, 0xFE, 80, 0, 0, 1, 20};\n    constexpr size_t num_bytes = sizeof(src) / sizeof(uint8_t);\n    uint8_t dst[num_bytes];\n    memset(dst, 0, num_bytes);\n    FILE *tmp = write_records({src, src + num_bytes}, SampleFormat::SAMPLE_FORMAT_HITS);\n    rewind(tmp);\n    ASSERT_EQ(\n        num_bytes * 8 - 1,\n        read_records_as_bytes<W>(tmp, {dst, dst + num_bytes}, SampleFormat::SAMPLE_FORMAT_HITS, 8 * num_bytes - 1));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(src[i], dst[i]);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatDets_WriteRead, {\n    uint8_t src[]{0, 1, 2, 3, 4, 0xFF, 0xBF, 0xFE, 80, 0, 0, 1, 20};\n    constexpr size_t num_bytes = sizeof(src) / sizeof(uint8_t);\n    uint8_t dst[num_bytes];\n    memset(dst, 0, num_bytes);\n    FILE *tmp = write_records({src, src + num_bytes}, SampleFormat::SAMPLE_FORMAT_DETS);\n    rewind(tmp);\n    ASSERT_EQ(\n        num_bytes * 8 - 1,\n        read_records_as_bytes<W>(tmp, {dst, dst + num_bytes}, SampleFormat::SAMPLE_FORMAT_DETS, 8 * num_bytes - 1));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(src[i], dst[i]);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, Format01_WriteRead_MultipleRecords, {\n    uint8_t record1[]{0x12, 0xAB, 0x00, 0xFF, 0x75};\n    uint8_t record2[]{0x80, 0xFF, 0x01, 0x56, 0x57};\n    uint8_t record3[]{0x2F, 0x08, 0xF0, 0x1C, 0x60};\n    constexpr size_t num_bytes = sizeof(record1) / sizeof(uint8_t);\n    constexpr size_t bits_per_record = 8 * num_bytes;\n\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_01);\n    writer->write_bytes({record1, record1 + num_bytes});\n    writer->write_end();\n    writer->write_bytes({record2, record2 + num_bytes});\n    writer->write_end();\n    writer->write_bytes({record3, record3 + num_bytes});\n    writer->write_end();\n\n    rewind(tmp);\n\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_01, bits_per_record);\n\n    simd_bits<W> buf(num_bytes * 8);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(buf.u8[i], record1[i]);\n    }\n\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(buf.u8[i], record2[i]);\n    }\n\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(buf.u8[i], record3[i]);\n    }\n\n    ASSERT_FALSE(reader->start_and_read_entire_record(buf));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatHits_WriteRead_MultipleRecords, {\n    uint8_t record1[]{0x12, 0xAB, 0x00, 0xFF, 0x75};\n    uint8_t record2[]{0x80, 0xFF, 0x01, 0x56, 0x57};\n    uint8_t record3[]{0x2F, 0x08, 0xF0, 0x1C, 0x60};\n    constexpr size_t num_bytes = sizeof(record1) / sizeof(uint8_t);\n    constexpr size_t bits_per_record = 8 * num_bytes - 1;\n\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_HITS);\n    writer->write_bytes({record1, record1 + num_bytes});\n    writer->write_end();\n    writer->write_bytes({record2, record2 + num_bytes});\n    writer->write_end();\n    writer->write_bytes({record3, record3 + num_bytes});\n    writer->write_end();\n\n    rewind(tmp);\n\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_HITS, bits_per_record);\n    simd_bits<W> buf(num_bytes * 8);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(buf.u8[i], record1[i]);\n    }\n\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(buf.u8[i], record2[i]);\n    }\n\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(buf.u8[i], record3[i]);\n    }\n\n    ASSERT_FALSE(reader->start_and_read_entire_record(buf));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatDets_WriteRead_MultipleRecords, {\n    uint8_t record1[]{0x12, 0xAB, 0x00, 0xFF, 0x75};\n    uint8_t record2[]{0x80, 0xFF, 0x01, 0x56, 0x57};\n    uint8_t record3[]{0x2F, 0x08, 0xF0, 0x1C, 0x60};\n    constexpr size_t num_bytes = sizeof(record1) / sizeof(uint8_t);\n    constexpr size_t bits_per_record = 8 * num_bytes - 1;\n\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS);\n    writer->write_bytes({record1, record1 + num_bytes});\n    writer->write_end();\n    writer->write_bytes({record2, record2 + num_bytes});\n    writer->write_end();\n    writer->write_bytes({record3, record3 + num_bytes});\n    writer->write_end();\n\n    rewind(tmp);\n\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS, bits_per_record);\n    simd_bits<W> buf(num_bytes * 8);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(buf.u8[i], record1[i]);\n    }\n\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(buf.u8[i], record2[i]);\n    }\n\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    for (size_t i = 0; i < num_bytes; ++i) {\n        ASSERT_EQ(buf.u8[i], record3[i]);\n    }\n\n    ASSERT_FALSE(reader->start_and_read_entire_record(buf));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, Format01_MultipleRecords, {\n    FILE *tmp = tmpfile_with_contents(\"111011001\\n010000000\\n101100011\\n\");\n    ASSERT_NE(tmp, nullptr);\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_01, 9);\n    simd_bits<W> buf(9);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    ASSERT_FALSE(reader->start_and_read_entire_record(buf));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatDets_MultipleShortRecords, {\n    FILE *tmp = tmpfile_with_contents(\"shot M0\\nshot M1\\nshot M0\\nshot\\n\");\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS, 2);\n\n    simd_bits<W> buf(2);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    ASSERT_EQ(buf[0], 1);\n    ASSERT_EQ(buf[1], 0);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    ASSERT_EQ(buf[0], 0);\n    ASSERT_EQ(buf[1], 1);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    ASSERT_EQ(buf[0], 1);\n    ASSERT_EQ(buf[1], 0);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    ASSERT_EQ(buf[0], 0);\n    ASSERT_EQ(buf[1], 0);\n    ASSERT_FALSE(reader->start_and_read_entire_record(buf));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatDets_HugeObservables, {\n    FILE *tmp = tmpfile_with_contents(\"shot L1000\\nshot D2 L999\\n\");\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS, 0, 10, 1500);\n\n    simd_bits<64> expected(1500);\n    simd_bits<W> buf(2);\n    SparseShot s;\n    bool b = reader->start_and_read_entire_record(s);\n    ASSERT_TRUE(b);\n    ASSERT_EQ(s.hits, (std::vector<uint64_t>{}));\n    expected[1000] = true;\n    ASSERT_EQ(s.obs_mask, expected);\n\n    s.clear();\n    b = reader->start_and_read_entire_record(s);\n    ASSERT_TRUE(b);\n    ASSERT_EQ(s.hits, (std::vector<uint64_t>{2}));\n    expected.clear();\n    expected[999] = true;\n    ASSERT_EQ(s.obs_mask, expected);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatDets_MultipleResultTypes_D0L0, {\n    FILE *tmp = tmpfile_with_contents(\"shot D0 D3 D5 L1 L2\\n\");\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS, 0, 7, 4);\n    simd_bits<W> buf(11);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    ASSERT_EQ(buf[0], 1);\n    ASSERT_EQ(buf[1], 0);\n    ASSERT_EQ(buf[2], 0);\n    ASSERT_EQ(buf[3], 1);\n    ASSERT_EQ(buf[4], 0);\n    ASSERT_EQ(buf[5], 1);\n    ASSERT_EQ(buf[6], 0);\n    ASSERT_EQ(buf[7], 0);\n    ASSERT_EQ(buf[8], 1);\n    ASSERT_EQ(buf[9], 1);\n    ASSERT_EQ(buf[10], 0);\n\n    rewind(tmp);\n    reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS, 0, 7, 4);\n    SparseShot sparse;\n    reader->start_and_read_entire_record(sparse);\n    ASSERT_EQ(sparse.hits, (std::vector<uint64_t>{0, 3, 5}));\n    ASSERT_EQ(sparse.obs_mask.ptr_simd[0], 6);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, Format01_InvalidInput, {\n    FILE *tmp = tmpfile_with_contents(\"012\\n\");\n    ASSERT_NE(tmp, nullptr);\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_01, 3);\n    simd_bits<W> buf(3);\n    ASSERT_THROW({ reader->start_and_read_entire_record(buf); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatHits_InvalidInput, {\n    FILE *tmp = tmpfile_with_contents(\"100,1\\n\");\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_HITS, 3);\n    simd_bits<W> buf(3);\n    ASSERT_THROW({ reader->start_and_read_entire_record(buf); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatHits_InvalidInput_sparse, {\n    FILE *tmp = tmpfile_with_contents(\"100,1\\n\");\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_HITS, 3);\n    SparseShot sparse;\n    ASSERT_THROW({ reader->start_and_read_entire_record(sparse); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatHits_Repeated_Dense, {\n    FILE *tmp = tmpfile_with_contents(\"1,1\\n\");\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_HITS, 3);\n    simd_bits<W> buf(3);\n    ASSERT_TRUE(reader->start_and_read_entire_record(buf));\n    ASSERT_EQ(buf[0], 0);\n    ASSERT_EQ(buf[1], 0);\n    ASSERT_EQ(buf[2], 0);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatHits_Repeated_Sparse, {\n    FILE *tmp = tmpfile_with_contents(\"1,1\\n\");\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_HITS, 3);\n    SparseShot sparse;\n    ASSERT_TRUE(reader->start_and_read_entire_record(sparse));\n    ASSERT_EQ(sparse.hits, (std::vector<uint64_t>{1, 1}));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatDets_InvalidInput_Sparse, {\n    FILE *tmp = tmpfile_with_contents(\"D2\\n\");\n    auto r = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS, 3);\n    SparseShot sparse;\n    ASSERT_THROW({ r->start_and_read_entire_record(sparse); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, FormatDets_InvalidInput_Dense, {\n    FILE *tmp = tmpfile_with_contents(\"D2\\n\");\n    auto r = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS, 3);\n    simd_bits<W> buf(3);\n    ASSERT_THROW({ r->start_and_read_entire_record(buf); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_records_into_RoundTrip, {\n    size_t n_shots = 100;\n    size_t n_results = 512 - 8;\n\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto shot_maj_data = simd_bit_table<W>::random(n_shots, n_results, rng);\n    auto shot_min_data = shot_maj_data.transposed();\n    for (const auto &kv : format_name_to_enum_map()) {\n        SampleFormat format = kv.second.id;\n        if (format == SampleFormat::SAMPLE_FORMAT_PTB64) {\n            // TODO: support this format.\n            continue;\n        }\n\n        // Write data to file.\n        FILE *f = tmpfile();\n        {\n            auto writer = MeasureRecordWriter::make(f, format);\n            for (size_t k = 0; k < n_shots; k++) {\n                writer->write_bytes({shot_maj_data[k].u8, shot_maj_data[k].u8 + n_results / 8});\n                writer->write_end();\n            }\n        }\n\n        // Check that read shot-min data matches written data.\n        rewind(f);\n        {\n            auto reader = MeasureRecordReader<W>::make(f, format, n_results, 0, 0);\n            simd_bit_table<W> read_shot_min_data(n_results, n_shots);\n            size_t n = reader->read_records_into(read_shot_min_data, false);\n            EXPECT_EQ(n, n_shots) << kv.second.name << \" (not striped)\";\n            EXPECT_EQ(read_shot_min_data, shot_min_data) << kv.second.name << \" (not striped)\";\n        }\n\n        // Check that read shot-maj data matches written data when transposing.\n        rewind(f);\n        {\n            auto reader = MeasureRecordReader<W>::make(f, format, n_results, 0, 0);\n            simd_bit_table<W> read_shot_maj_data(n_shots, n_results);\n            size_t n = reader->read_records_into(read_shot_maj_data, true);\n            EXPECT_EQ(n, n_shots) << kv.second.name << \" (striped)\";\n            EXPECT_EQ(read_shot_maj_data, shot_maj_data) << kv.second.name << \" (striped)\";\n        }\n\n        fclose(f);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_bits_into_bytes_entire_record_across_result_type, {\n    FILE *f = tmpfile_with_contents(\"shot D1 L1\");\n    auto reader = MeasureRecordReader<W>::make(f, SampleFormat::SAMPLE_FORMAT_DETS, 0, 3, 3);\n    simd_bit_table<W> read(6, 1);\n    size_t n = reader->read_records_into(read, false);\n    fclose(f);\n    ASSERT_EQ(n, 1);\n    ASSERT_EQ(read[0][0], false);\n    ASSERT_EQ(read[1][0], true);\n    ASSERT_EQ(read[2][0], false);\n    ASSERT_EQ(read[3][0], false);\n    ASSERT_EQ(read[4][0], true);\n    ASSERT_EQ(read[5][0], false);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_r8_detection_event_data, {\n    FILE *f = tmpfile();\n    putc(6, f);\n    putc(1, f);\n    putc(4, f);\n    rewind(f);\n    auto reader = MeasureRecordReader<W>::make(f, SampleFormat::SAMPLE_FORMAT_R8, 0, 3, 3);\n    simd_bit_table<W> read(6, 2);\n    size_t n = reader->read_records_into(read, false);\n    fclose(f);\n    ASSERT_EQ(n, 2);\n    ASSERT_EQ(read[0][0], false);\n    ASSERT_EQ(read[1][0], false);\n    ASSERT_EQ(read[2][0], false);\n    ASSERT_EQ(read[3][0], false);\n    ASSERT_EQ(read[4][0], false);\n    ASSERT_EQ(read[5][0], false);\n    ASSERT_EQ(read[0][1], false);\n    ASSERT_EQ(read[1][1], true);\n    ASSERT_EQ(read[2][1], false);\n    ASSERT_EQ(read[3][1], false);\n    ASSERT_EQ(read[4][1], false);\n    ASSERT_EQ(read[5][1], false);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_b8_detection_event_data_full_run_together, {\n    FILE *f = tmpfile();\n    putc(0, f);\n    putc(1, f);\n    putc(2, f);\n    putc(3, f);\n    rewind(f);\n    auto reader = MeasureRecordReader<W>::make(f, SampleFormat::SAMPLE_FORMAT_B8, 0, 27, 0);\n    simd_bit_table<W> read(27, 1);\n    size_t n = reader->read_records_into(read, false);\n    fclose(f);\n    ASSERT_EQ(n, 1);\n    auto t = read.transposed();\n    ASSERT_EQ(t[0].u8[0], 0);\n    ASSERT_EQ(t[0].u8[1], 1);\n    ASSERT_EQ(t[0].u8[2], 2);\n    ASSERT_EQ(t[0].u8[3], 3);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    size_t n = 512 - 8;\n    size_t no = 5;\n    size_t nd = n - no;\n\n    // Compute expected data.\n    simd_bits<W> test_data(n);\n    biased_randomize_bits(0.1, test_data.u64, test_data.u64 + test_data.num_u64_padded(), rng);\n    SparseShot sparse_test_data;\n    sparse_test_data.obs_mask = simd_bits<64>(no);\n    for (size_t k = 0; k < nd; k++) {\n        if (test_data[k]) {\n            sparse_test_data.hits.push_back(k);\n        }\n    }\n    for (size_t k = 0; k < no; k++) {\n        if (test_data[k + nd]) {\n            sparse_test_data.obs_mask[k] = true;\n        }\n    }\n\n    for (const auto &kv : format_name_to_enum_map()) {\n        SampleFormat format = kv.second.id;\n        if (format == SampleFormat::SAMPLE_FORMAT_PTB64) {\n            continue;\n        }\n\n        // Write data to file.\n        FILE *f = tmpfile();\n        {\n            auto writer = MeasureRecordWriter::make(f, format);\n            writer->begin_result_type('D');\n            for (size_t k = 0; k < nd; k++) {\n                writer->write_bit(test_data[k]);\n            }\n            writer->begin_result_type('L');\n            for (size_t k = 0; k < no; k++) {\n                writer->write_bit(test_data[k + nd]);\n            }\n            writer->write_end();\n        }\n\n        {\n            auto reader = MeasureRecordReader<W>::make(f, format, 0, nd, no);\n\n            // Check sparse record read.\n            SparseShot sparse_out;\n            rewind(f);\n            ASSERT_TRUE(reader->start_and_read_entire_record(sparse_out));\n            ASSERT_EQ(sparse_out, sparse_test_data);\n            ASSERT_FALSE(reader->start_and_read_entire_record(sparse_out));\n\n            rewind(f);\n            simd_bits<W> dense_out(n);\n            ASSERT_TRUE(reader->start_and_read_entire_record(dense_out));\n            for (size_t k = 0; k < n; k++) {\n                ASSERT_EQ(dense_out[k], test_data[k]);\n            }\n            ASSERT_FALSE(reader->start_and_read_entire_record(dense_out));\n        }\n\n        fclose(f);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record_all_zero, {\n    simd_bits<W> test_data(256);\n    SparseShot sparse_test_data;\n\n    for (const auto &kv : format_name_to_enum_map()) {\n        SampleFormat format = kv.second.id;\n        if (format == SampleFormat::SAMPLE_FORMAT_PTB64) {\n            continue;\n        }\n\n        // Write data to file.\n        FILE *f = tmpfile();\n        {\n            auto writer = MeasureRecordWriter::make(f, format);\n            writer->write_bytes({test_data.u8, test_data.u8 + 32});\n            writer->write_end();\n        }\n\n        {\n            auto reader = MeasureRecordReader<W>::make(f, format, 256, 0, 0);\n\n            // Check sparse record read.\n            SparseShot sparse_out;\n            rewind(f);\n            ASSERT_TRUE(reader->start_and_read_entire_record(sparse_out));\n            ASSERT_EQ(sparse_out, sparse_test_data);\n            ASSERT_FALSE(reader->start_and_read_entire_record(sparse_out));\n\n            rewind(f);\n            simd_bits<W> dense_out(256);\n            ASSERT_TRUE(reader->start_and_read_entire_record(dense_out));\n            ASSERT_EQ(dense_out, test_data);\n            ASSERT_FALSE(reader->start_and_read_entire_record(dense_out));\n        }\n\n        fclose(f);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record_ptb64_dense, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    FILE *f = tmpfile();\n    auto saved1 = simd_bits<W>::random(64 * 71, rng);\n    auto saved2 = simd_bits<W>::random(64 * 71, rng);\n    for (size_t k = 0; k < 64 * 71 / 8; k++) {\n        putc(saved1.u8[k], f);\n    }\n    for (size_t k = 0; k < 64 * 71 / 8; k++) {\n        putc(saved2.u8[k], f);\n    }\n    rewind(f);\n\n    simd_bits<W> loaded(71);\n    auto reader = MeasureRecordReader<W>::make(f, SampleFormat::SAMPLE_FORMAT_PTB64, 71, 0, 0);\n    for (size_t shot = 0; shot < 64; shot++) {\n        ASSERT_TRUE(reader->start_and_read_entire_record(loaded));\n        for (size_t m = 0; m < 71; m++) {\n            ASSERT_EQ(saved1[m * 64 + shot], loaded[m]);\n        }\n    }\n    for (size_t shot = 0; shot < 64; shot++) {\n        ASSERT_TRUE(reader->start_and_read_entire_record(loaded));\n        for (size_t m = 0; m < 71; m++) {\n            ASSERT_EQ(saved2[m * 64 + shot], loaded[m]);\n        }\n    }\n    ASSERT_FALSE(reader->start_and_read_entire_record(loaded));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, start_and_read_entire_record_ptb64_sparse, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    FILE *tmp = tmpfile();\n    simd_bit_table<W> ground_truth(71, 64 * 5);\n    {\n        MeasureRecordBatchWriter writer(tmp, 64 * 5, SampleFormat::SAMPLE_FORMAT_PTB64);\n        for (size_t k = 0; k < 71; k++) {\n            ground_truth[k].randomize(64 * 5, rng);\n            writer.batch_write_bit<W>(ground_truth[k]);\n        }\n        writer.write_end();\n    }\n    rewind(tmp);\n\n    auto reader = MeasureRecordReader<W>::make(tmp, SampleFormat::SAMPLE_FORMAT_PTB64, 71, 0, 0);\n    for (size_t shot = 0; shot < 64 * 5; shot++) {\n        SparseShot loaded;\n        ASSERT_TRUE(reader->start_and_read_entire_record(loaded));\n        std::vector<uint64_t> expected;\n        for (size_t m = 0; m < 71; m++) {\n            if (ground_truth[m][shot]) {\n                expected.push_back(m);\n            }\n        }\n        ASSERT_EQ(loaded.hits, expected);\n    }\n\n    SparseShot discard;\n    ASSERT_FALSE(reader->start_and_read_entire_record(discard));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_file_data_into_shot_table_vs_write_table, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (const auto &format_data : format_name_to_enum_map()) {\n        SampleFormat format = format_data.second.id;\n        size_t num_shots = 500;\n        if (format == SampleFormat::SAMPLE_FORMAT_PTB64) {\n            num_shots = 512 + 64;\n        }\n        size_t bits_per_shot = 1000;\n\n        simd_bit_table<W> expected(num_shots, bits_per_shot);\n        for (size_t shot = 0; shot < num_shots; shot++) {\n            expected[shot].randomize(bits_per_shot, rng);\n        }\n        simd_bit_table<W> expected_transposed = expected.transposed();\n\n        RaiiTempNamedFile tmp;\n        FILE *f = fopen(tmp.path.c_str(), \"wb\");\n        write_table_data<W>(f, num_shots, bits_per_shot, simd_bits<W>(0), expected_transposed, format, 'M', 'M', 0);\n        fclose(f);\n\n        f = fopen(tmp.path.c_str(), \"rb\");\n        simd_bit_table<W> output(num_shots, bits_per_shot);\n        read_file_data_into_shot_table(f, num_shots, bits_per_shot, format, 'M', output, true);\n        ASSERT_EQ(getc(f), EOF) << format_data.second.name << \", not transposed\";\n        fclose(f);\n        ASSERT_EQ(output, expected) << format_data.second.name << \", not transposed\";\n\n        f = fopen(tmp.path.c_str(), \"rb\");\n        simd_bit_table<W> output_transposed(bits_per_shot, num_shots);\n        read_file_data_into_shot_table(f, num_shots, bits_per_shot, format, 'M', output_transposed, false);\n        ASSERT_EQ(getc(f), EOF) << format_data.second.name << \", yes transposed\";\n        fclose(f);\n        ASSERT_EQ(output_transposed, expected_transposed) << format_data.second.name << \", yes transposed\";\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_windows_newlines_01, {\n    FILE *f = tmpfile();\n    fprintf(f, \"01\\r\\n01\\r\\n\");\n    rewind(f);\n    auto reader = MeasureRecordReader<W>::make(f, SampleFormat::SAMPLE_FORMAT_01, 2, 0, 0);\n    simd_bit_table<W> read(2, 2);\n    size_t n = reader->read_records_into(read, false);\n    ASSERT_EQ(n, 2);\n    ASSERT_EQ(read[0][0], false);\n    ASSERT_EQ(read[1][0], true);\n    ASSERT_EQ(read[0][1], false);\n    ASSERT_EQ(read[1][1], true);\n    fclose(f);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_windows_newlines_hits, {\n    FILE *f = tmpfile();\n    fprintf(f, \"3\\r\\n1\\r\\n\");\n    rewind(f);\n    auto reader = MeasureRecordReader<W>::make(f, SampleFormat::SAMPLE_FORMAT_HITS, 4, 0, 0);\n    simd_bit_table<W> read(4, 2);\n    size_t n = reader->read_records_into(read, false);\n    ASSERT_EQ(n, 2);\n    ASSERT_EQ(read[0][0], false);\n    ASSERT_EQ(read[1][0], false);\n    ASSERT_EQ(read[2][0], false);\n    ASSERT_EQ(read[3][0], true);\n    ASSERT_EQ(read[0][1], false);\n    ASSERT_EQ(read[1][1], true);\n    ASSERT_EQ(read[2][1], false);\n    ASSERT_EQ(read[3][1], false);\n    fclose(f);\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordReader, read_windows_newlines_dets, {\n    FILE *f = tmpfile();\n    fprintf(f, \"shot M3\\r\\n\\r\\n\\n   shot M1\\r\\n\\n\");\n    rewind(f);\n    auto reader = MeasureRecordReader<W>::make(f, SampleFormat::SAMPLE_FORMAT_DETS, 4, 0, 0);\n    simd_bit_table<W> read(4, 2);\n    size_t n = reader->read_records_into(read, false);\n    ASSERT_EQ(n, 2);\n    ASSERT_EQ(read[0][0], false);\n    ASSERT_EQ(read[1][0], false);\n    ASSERT_EQ(read[2][0], false);\n    ASSERT_EQ(read[3][0], true);\n    ASSERT_EQ(read[0][1], false);\n    ASSERT_EQ(read[1][1], true);\n    ASSERT_EQ(read[2][1], false);\n    ASSERT_EQ(read[3][1], false);\n    fclose(f);\n})\n"
  },
  {
    "path": "src/stim/io/measure_record_writer.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/measure_record_writer.h\"\n\n#include <algorithm>\n\nusing namespace stim;\n\nstd::unique_ptr<MeasureRecordWriter> MeasureRecordWriter::make(FILE *out, SampleFormat output_format) {\n    switch (output_format) {\n        case SampleFormat::SAMPLE_FORMAT_01:\n            return std::make_unique<MeasureRecordWriterFormat01>(out);\n        case SampleFormat::SAMPLE_FORMAT_B8:\n            return std::make_unique<MeasureRecordWriterFormatB8>(out);\n        case SampleFormat::SAMPLE_FORMAT_DETS:\n            return std::make_unique<MeasureRecordWriterFormatDets>(out);\n        case SampleFormat::SAMPLE_FORMAT_HITS:\n            return std::make_unique<MeasureRecordWriterFormatHits>(out);\n        case SampleFormat::SAMPLE_FORMAT_PTB64:\n            throw std::invalid_argument(\"SAMPLE_FORMAT_PTB64 incompatible with SingleMeasurementRecord\");\n        case SampleFormat::SAMPLE_FORMAT_R8:\n            return std::make_unique<MeasureRecordWriterFormatR8>(out);\n        default:\n            throw std::invalid_argument(\"Sample format not recognized by SingleMeasurementRecord\");\n    }\n}\n\nvoid MeasureRecordWriter::begin_result_type(char result_type) {\n}\n\nvoid MeasureRecordWriter::write_bits(uint8_t *data, size_t num_bits) {\n    size_t num_bytes = num_bits >> 3;\n    write_bytes({data, data + num_bytes});\n    for (size_t b = 0; b < (num_bits & 7); b++) {\n        write_bit((data[num_bytes] >> b) & 1);\n    }\n}\n\nvoid MeasureRecordWriter::write_bytes(SpanRef<const uint8_t> data) {\n    for (uint8_t b : data) {\n        for (size_t k = 0; k < 8; k++) {\n            write_bit((b >> k) & 1);\n        }\n    }\n}\n\nMeasureRecordWriterFormat01::MeasureRecordWriterFormat01(FILE *out) : out(out) {\n}\n\nvoid MeasureRecordWriterFormat01::write_bit(bool b) {\n    putc('0' + b, out);\n}\n\nvoid MeasureRecordWriterFormat01::write_end() {\n    putc('\\n', out);\n}\n\nMeasureRecordWriterFormatB8::MeasureRecordWriterFormatB8(FILE *out) : out(out) {\n}\n\nvoid MeasureRecordWriterFormatB8::write_bytes(SpanRef<const uint8_t> data) {\n    if (count == 0) {\n        fwrite(data.ptr_start, sizeof(uint8_t), data.ptr_end - data.ptr_start, out);\n    } else {\n        MeasureRecordWriter::write_bytes(data);\n    }\n}\n\nvoid MeasureRecordWriterFormatB8::write_bit(bool b) {\n    payload |= uint8_t{b} << count;\n    count++;\n    if (count == 8) {\n        putc(payload, out);\n        count = 0;\n        payload = 0;\n    }\n}\n\nvoid MeasureRecordWriterFormatB8::write_end() {\n    if (count > 0) {\n        putc(payload, out);\n        count = 0;\n        payload = 0;\n    }\n}\n\nMeasureRecordWriterFormatHits::MeasureRecordWriterFormatHits(FILE *out) : out(out) {\n}\n\nvoid MeasureRecordWriterFormatHits::write_bytes(SpanRef<const uint8_t> data) {\n    for (uint8_t b : data) {\n        if (!b) {\n            position += 8;\n        } else {\n            for (size_t k = 0; k < 8; k++) {\n                write_bit((b >> k) & 1);\n            }\n        }\n    }\n}\n\nvoid MeasureRecordWriterFormatHits::write_bit(bool b) {\n    if (b) {\n        if (first) {\n            first = false;\n        } else {\n            putc(',', out);\n        }\n        fprintf(out, \"%lld\", (unsigned long long)(position));\n    }\n    position++;\n}\n\nvoid MeasureRecordWriterFormatHits::write_end() {\n    putc('\\n', out);\n    position = 0;\n    first = true;\n}\n\nMeasureRecordWriterFormatR8::MeasureRecordWriterFormatR8(FILE *out) : out(out) {\n}\n\nvoid MeasureRecordWriterFormatR8::write_bytes(SpanRef<const uint8_t> data) {\n    for (uint8_t b : data) {\n        if (!b) {\n            run_length += 8;\n            if (run_length >= 0xFF) {\n                putc(0xFF, out);\n                run_length -= 0xFF;\n            }\n        } else {\n            for (size_t k = 0; k < 8; k++) {\n                write_bit((b >> k) & 1);\n            }\n        }\n    }\n}\n\nvoid MeasureRecordWriterFormatR8::write_bit(bool b) {\n    if (b) {\n        putc(run_length, out);\n        run_length = 0;\n    } else {\n        run_length++;\n        if (run_length == 255) {\n            putc(run_length, out);\n            run_length = 0;\n        }\n    }\n}\n\nvoid MeasureRecordWriterFormatR8::write_end() {\n    putc(run_length, out);\n    run_length = 0;\n}\n\nMeasureRecordWriterFormatDets::MeasureRecordWriterFormatDets(FILE *out) : out(out) {\n}\n\nvoid MeasureRecordWriterFormatDets::begin_result_type(char new_result_type) {\n    result_type = new_result_type;\n    position = 0;\n}\n\nvoid MeasureRecordWriterFormatDets::write_bytes(SpanRef<const uint8_t> data) {\n    for (uint8_t b : data) {\n        if (!b) {\n            position += 8;\n        } else {\n            for (size_t k = 0; k < 8; k++) {\n                write_bit((b >> k) & 1);\n            }\n        }\n    }\n}\n\nvoid MeasureRecordWriterFormatDets::write_bit(bool b) {\n    if (b) {\n        if (first) {\n            fprintf(out, \"shot\");\n            first = false;\n        }\n        putc(' ', out);\n        putc(result_type, out);\n        fprintf(out, \"%lld\", (unsigned long long)(position));\n    }\n    position++;\n}\n\nvoid MeasureRecordWriterFormatDets::write_end() {\n    if (first) {\n        fprintf(out, \"shot\");\n    }\n    putc('\\n', out);\n    position = 0;\n    first = true;\n}\n"
  },
  {
    "path": "src/stim/io/measure_record_writer.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_IO_MEASURE_RECORD_WRITER_H\n#define _STIM_IO_MEASURE_RECORD_WRITER_H\n\n#include <memory>\n\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/mem/simd_bit_table.h\"\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\n/// Handles writing measurement data to the outside world.\n///\n/// Child classes implement the various output formats.\nstruct MeasureRecordWriter {\n    /// Creates a MeasureRecordWriter that writes the given format into the given FILE*.\n    static std::unique_ptr<MeasureRecordWriter> make(FILE *out, SampleFormat output_format);\n    virtual ~MeasureRecordWriter() = default;\n    /// Writes (or buffers) one measurement result.\n    virtual void write_bit(bool b) = 0;\n    /// Writes (or buffers) multiple measurement results.\n    virtual void write_bytes(SpanRef<const uint8_t> data);\n    /// Flushes all buffered measurement results and writes any end-of-record markers that are needed (e.g. a newline).\n    virtual void write_end() = 0;\n    /// Writes (or buffers) multiple measurement results.\n    virtual void write_bits(uint8_t *data, size_t num_bits);\n    /// Used to control the DETS format prefix character (M for measurement, D for detector, L for logical observable).\n    ///\n    /// Setting this is understood to reset the \"result index\" back to 0 so that e.g. listing logical observables after\n    /// detectors results in the first logical observable being L0 instead of L[number-of-detectors].\n    virtual void begin_result_type(char result_type);\n};\n\nstruct MeasureRecordWriterFormat01 : MeasureRecordWriter {\n    FILE *out;\n    MeasureRecordWriterFormat01(FILE *out);\n    void write_bit(bool b) override;\n    void write_end() override;\n};\n\nstruct MeasureRecordWriterFormatB8 : MeasureRecordWriter {\n    FILE *out;\n    uint8_t payload = 0;\n    uint8_t count = 0;\n    MeasureRecordWriterFormatB8(FILE *out);\n    void write_bytes(SpanRef<const uint8_t> data) override;\n    void write_bit(bool b) override;\n    void write_end() override;\n};\n\nstruct MeasureRecordWriterFormatHits : MeasureRecordWriter {\n    FILE *out;\n    uint64_t position = 0;\n    bool first = true;\n\n    MeasureRecordWriterFormatHits(FILE *out);\n    void write_bytes(SpanRef<const uint8_t> data) override;\n    void write_bit(bool b) override;\n    void write_end() override;\n};\n\nstruct MeasureRecordWriterFormatR8 : MeasureRecordWriter {\n    FILE *out;\n    uint16_t run_length = 0;\n\n    MeasureRecordWriterFormatR8(FILE *out);\n    void write_bytes(SpanRef<const uint8_t> data) override;\n    void write_bit(bool b) override;\n    void write_end() override;\n};\n\nstruct MeasureRecordWriterFormatDets : MeasureRecordWriter {\n    FILE *out;\n    uint64_t position = 0;\n    char result_type = 'M';\n    bool first = true;\n\n    MeasureRecordWriterFormatDets(FILE *out);\n    void begin_result_type(char result_type) override;\n    void write_bytes(SpanRef<const uint8_t> data) override;\n    void write_bit(bool b) override;\n    void write_end() override;\n};\n\ntemplate <size_t W>\nsimd_bit_table<W> transposed_vs_ref(\n    size_t num_samples_raw, const simd_bit_table<W> &table, const simd_bits<W> &reference_sample) {\n    auto result = table.transposed();\n    for (size_t s = 0; s < num_samples_raw; s++) {\n        result[s].word_range_ref(0, reference_sample.num_simd_words) ^= reference_sample;\n    }\n    return result;\n}\n\ntemplate <size_t W>\nvoid write_table_data(\n    FILE *out,\n    size_t num_shots,\n    size_t num_measurements,\n    const simd_bits<W> &reference_sample,\n    const simd_bit_table<W> &table,\n    SampleFormat format,\n    char dets_prefix_1,\n    char dets_prefix_2,\n    size_t dets_prefix_transition) {\n    if (format == SampleFormat::SAMPLE_FORMAT_PTB64) {\n        if (num_shots % 64 != 0) {\n            throw std::invalid_argument(\"shots must be a multiple of 64 to use ptb64 format.\");\n        }\n        auto f64 = num_shots >> 6;\n        for (size_t s = 0; s < f64; s++) {\n            for (size_t m = 0; m < num_measurements; m++) {\n                uint64_t v = table[m].u64[s];\n                if (m < reference_sample.num_bits_padded() && reference_sample[m]) {\n                    v = ~v;\n                }\n                fwrite(&v, 1, 64 >> 3, out);\n            }\n        }\n    } else {\n        auto result = transposed_vs_ref(num_shots, table, reference_sample);\n        if (dets_prefix_transition == 0) {\n            dets_prefix_transition = num_measurements;\n            dets_prefix_1 = dets_prefix_2;\n        } else if (dets_prefix_1 == dets_prefix_2 || dets_prefix_transition >= num_measurements) {\n            dets_prefix_transition = num_measurements;\n        }\n        for (size_t shot = 0; shot < num_shots; shot++) {\n            auto w = MeasureRecordWriter::make(out, format);\n\n            w->begin_result_type(dets_prefix_1);\n            size_t n8 = dets_prefix_transition >> 3;\n            uint8_t *p = result[shot].u8;\n            w->write_bytes({p, p + n8});\n            size_t m = n8 << 3;\n            while (m < dets_prefix_transition) {\n                w->write_bit(result[shot][m]);\n                m++;\n            }\n\n            w->begin_result_type(dets_prefix_2);\n            while (m < num_measurements) {\n                w->write_bit(result[shot][m]);\n                m++;\n            }\n\n            w->write_end();\n        }\n    }\n}\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/io/measure_record_writer.test.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/measure_record_writer.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(MeasureRecordWriter, Format01) {\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_01);\n    uint8_t bytes[]{0xF8};\n    writer->write_bytes({bytes});\n    writer->write_bit(false);\n    writer->write_bytes({bytes});\n    writer->write_bit(true);\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(tmp), \"000111110000111111\\n\");\n}\n\nTEST(MeasureRecordWriter, FormatB8) {\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_B8);\n    uint8_t bytes[]{0xF8};\n    writer->write_bytes({bytes});\n    writer->write_bit(false);\n    writer->write_bytes({bytes});\n    writer->write_bit(true);\n    writer->write_end();\n    auto s = rewind_read_close(tmp);\n    ASSERT_EQ(s.size(), 3);\n    ASSERT_EQ(s[0], (char)0xF8);\n    ASSERT_EQ(s[1], (char)0xF0);\n    ASSERT_EQ(s[2], (char)0x03);\n}\n\nTEST(MeasureRecordWriter, FormatHits) {\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_HITS);\n    uint8_t bytes[]{0xF8};\n    writer->write_bytes({bytes});\n    writer->write_bit(false);\n    writer->write_bytes({bytes});\n    writer->write_bit(true);\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(tmp), \"3,4,5,6,7,12,13,14,15,16,17\\n\");\n}\n\nTEST(MeasureRecordWriter, FormatDets) {\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS);\n    uint8_t bytes[]{0xF8};\n    writer->begin_result_type('D');\n    writer->write_bytes({bytes});\n    writer->write_bit(false);\n    writer->write_bytes({bytes});\n    writer->begin_result_type('L');\n    writer->write_bit(false);\n    writer->write_bit(true);\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(tmp), \"shot D3 D4 D5 D6 D7 D12 D13 D14 D15 D16 L1\\n\");\n}\n\nTEST(MeasureRecordWriter, FormatDets_EmptyRecords) {\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS);\n    writer->write_end();\n    writer->write_end();\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(tmp), \"shot\\nshot\\nshot\\n\");\n}\n\nTEST(MeasureRecordWriter, FormatDets_MultipleRecords) {\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_DETS);\n\n    // First record\n    writer->begin_result_type('D');\n    writer->write_bit(false);\n    writer->write_bit(false);\n    writer->write_bit(true);\n    writer->begin_result_type('L');\n    writer->write_bit(false);\n    writer->write_bit(true);\n    writer->write_end();\n\n    // Second record\n    writer->begin_result_type('D');\n    writer->write_bit(true);\n    writer->write_bit(false);\n    writer->write_bit(false);\n    writer->write_bit(true);\n    writer->begin_result_type('L');\n    writer->write_bit(true);\n    writer->write_bit(false);\n    writer->write_bit(true);\n    writer->write_end();\n\n    ASSERT_EQ(rewind_read_close(tmp), \"shot D2 L1\\nshot D0 D3 L0 L2\\n\");\n}\n\nTEST(MeasureRecordWriter, FormatR8) {\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_R8);\n    uint8_t bytes[]{0xF8};\n    writer->write_bytes({bytes});\n    writer->write_bit(false);\n    writer->write_bytes({bytes});\n    writer->write_bit(true);\n    writer->write_end();\n    auto s = rewind_read_close(tmp);\n    ASSERT_EQ(s.size(), 12);\n    ASSERT_EQ(s[0], (char)3);\n    ASSERT_EQ(s[1], (char)0);\n    ASSERT_EQ(s[2], (char)0);\n    ASSERT_EQ(s[3], (char)0);\n    ASSERT_EQ(s[4], (char)0);\n    ASSERT_EQ(s[5], (char)4);\n    ASSERT_EQ(s[6], (char)0);\n    ASSERT_EQ(s[7], (char)0);\n    ASSERT_EQ(s[8], (char)0);\n    ASSERT_EQ(s[9], (char)0);\n    ASSERT_EQ(s[10], (char)0);\n    ASSERT_EQ(s[11], (char)0);\n}\n\nTEST(MeasureRecordWriter, FormatR8_LongGap) {\n    FILE *tmp = tmpfile();\n    auto writer = MeasureRecordWriter::make(tmp, SampleFormat::SAMPLE_FORMAT_R8);\n    uint8_t bytes[]{0, 0, 0, 0, 0, 0, 0, 0};\n    writer->write_bytes({bytes, bytes + 8});\n    writer->write_bytes({bytes, bytes + 8});\n    writer->write_bytes({bytes, bytes + 8});\n    writer->write_bytes({bytes, bytes + 8});\n    writer->write_bytes({bytes, bytes + 8});\n    writer->write_bytes({bytes, bytes + 8});\n    writer->write_bytes({bytes, bytes + 8});\n    writer->write_bytes({bytes, bytes + 8});\n    writer->write_bit(true);\n    writer->write_bytes({bytes, bytes + 4});\n    writer->write_end();\n    auto s = rewind_read_close(tmp);\n    ASSERT_EQ(s.size(), 4);\n    ASSERT_EQ(s[0], (char)255);\n    ASSERT_EQ(s[1], (char)255);\n    ASSERT_EQ(s[2], (char)2);\n    ASSERT_EQ(s[3], (char)32);\n}\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordWriter, write_table_data_small, {\n    simd_bit_table<W> results(4, 5);\n    simd_bits<W> ref_sample(0);\n    results[1][0] ^= 1;\n    results[1][1] ^= 1;\n    results[1][2] ^= 1;\n    results[1][3] ^= 1;\n    results[1][4] ^= 1;\n\n    FILE *tmp;\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 5, 4, ref_sample, results, SampleFormat::SAMPLE_FORMAT_01, 'M', 'M', 0);\n    ASSERT_EQ(rewind_read_close(tmp), \"0100\\n0100\\n0100\\n0100\\n0100\\n\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 5, 4, ref_sample, results, SampleFormat::SAMPLE_FORMAT_HITS, 'M', 'M', 0);\n    ASSERT_EQ(rewind_read_close(tmp), \"1\\n1\\n1\\n1\\n1\\n\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 5, 4, ref_sample, results, SampleFormat::SAMPLE_FORMAT_DETS, 'M', 'M', 0);\n    ASSERT_EQ(rewind_read_close(tmp), \"shot M1\\nshot M1\\nshot M1\\nshot M1\\nshot M1\\n\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 5, 4, ref_sample, results, SampleFormat::SAMPLE_FORMAT_DETS, 'D', 'L', 1);\n    ASSERT_EQ(rewind_read_close(tmp), \"shot L0\\nshot L0\\nshot L0\\nshot L0\\nshot L0\\n\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 5, 4, ref_sample, results, SampleFormat::SAMPLE_FORMAT_R8, 'M', 'M', 0);\n    ASSERT_EQ(rewind_read_close(tmp), \"\\x01\\x02\\x01\\x02\\x01\\x02\\x01\\x02\\x01\\x02\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 5, 4, ref_sample, results, SampleFormat::SAMPLE_FORMAT_B8, 'M', 'M', 0);\n    ASSERT_EQ(rewind_read_close(tmp), \"\\x02\\x02\\x02\\x02\\x02\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 64, 4, ref_sample, results, SampleFormat::SAMPLE_FORMAT_PTB64, 'M', 'M', 0);\n    ASSERT_EQ(\n        rewind_read_close(tmp),\n        std::string(\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\x1F\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\",\n            8 * 4));\n})\n\nTEST_EACH_WORD_SIZE_W(MeasureRecordWriter, write_table_data_large, {\n    simd_bit_table<W> results(100, 2);\n    simd_bits<W> ref_sample(100);\n    ref_sample[2] ^= true;\n    ref_sample[3] ^= true;\n    ref_sample[5] ^= true;\n    ref_sample[7] ^= true;\n    ref_sample[11] ^= true;\n    results[7][1] ^= true;\n\n    FILE *tmp;\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 2, 100, ref_sample, results, SampleFormat::SAMPLE_FORMAT_01, 'M', 'M', 0);\n    ASSERT_EQ(\n        rewind_read_close(tmp),\n        \"0011010100\"\n        \"0100000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\\n\"\n        \"0011010000\"\n        \"0100000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\"\n        \"0000000000\\n\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 2, 100, ref_sample, results, SampleFormat::SAMPLE_FORMAT_HITS, 'M', 'M', 0);\n    ASSERT_EQ(rewind_read_close(tmp), \"2,3,5,7,11\\n2,3,5,11\\n\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 2, 100, ref_sample, results, SampleFormat::SAMPLE_FORMAT_DETS, 'D', 'L', 5);\n    ASSERT_EQ(rewind_read_close(tmp), \"shot D2 D3 L0 L2 L6\\nshot D2 D3 L0 L6\\n\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 2, 100, ref_sample, results, SampleFormat::SAMPLE_FORMAT_DETS, 'D', 'L', 90);\n    ASSERT_EQ(rewind_read_close(tmp), \"shot D2 D3 D5 D7 D11\\nshot D2 D3 D5 D11\\n\");\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 2, 100, ref_sample, results, SampleFormat::SAMPLE_FORMAT_R8, 'M', 'M', 0);\n    ASSERT_EQ(\n        rewind_read_close(tmp),\n        std::string(\n            \"\\x02\\x00\\x01\\x01\\x03\\x58\"\n            \"\\x02\\x00\\x01\\x05\\x58\",\n            11));\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 2, 100, ref_sample, results, SampleFormat::SAMPLE_FORMAT_B8, 'M', 'M', 0);\n    ASSERT_EQ(\n        rewind_read_close(tmp),\n        std::string(\n            \"\\xAC\\x08\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\x2C\\x08\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\",\n            26));\n\n    tmp = tmpfile();\n    write_table_data<W>(tmp, 64, 100, ref_sample, results, SampleFormat::SAMPLE_FORMAT_PTB64, 'M', 'M', 0);\n    auto actual = rewind_read_close(tmp);\n    ASSERT_EQ(\n        actual,\n        std::string(\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\"\n            \"\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\xFD\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\"\n            \"\\0\\0\\0\\0\\0\\0\\0\\0\",\n            8 * 100));\n})\n\nTEST(MeasureRecordWriter, write_bits_01_a) {\n    FILE *f = tmpfile();\n    uint8_t data[]{0x0, 0xFF};\n    auto writer = MeasureRecordWriter::make(f, SampleFormat::SAMPLE_FORMAT_01);\n    writer->write_bits(&data[0], 11);\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(f), \"00000000111\\n\");\n}\n\nTEST(MeasureRecordWriter, write_bits_01_b) {\n    FILE *f = tmpfile();\n    uint8_t data[]{0xFF, 0x0};\n    auto writer = MeasureRecordWriter::make(f, SampleFormat::SAMPLE_FORMAT_01);\n    writer->write_bits(&data[0], 11);\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(f), \"11111111000\\n\");\n}\n\nTEST(MeasureRecordWriter, write_bits_b8_a) {\n    FILE *f = tmpfile();\n    uint8_t data[]{0x0, 0xFF};\n    auto writer = MeasureRecordWriter::make(f, SampleFormat::SAMPLE_FORMAT_B8);\n    writer->write_bits(&data[0], 11);\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(f), std::string(\"\\x00\\x07\", 2));\n}\n\nTEST(MeasureRecordWriter, write_bits_b8_b) {\n    FILE *f = tmpfile();\n    uint8_t data[]{0xFF, 0x0};\n    auto writer = MeasureRecordWriter::make(f, SampleFormat::SAMPLE_FORMAT_B8);\n    writer->write_bits(&data[0], 11);\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(f), std::string(\"\\xFF\\x00\", 2));\n}\n\nTEST(MeasureRecordWriter, write_bits_r8_a) {\n    FILE *f = tmpfile();\n    uint8_t data[]{0x0, 0xFF};\n    auto writer = MeasureRecordWriter::make(f, SampleFormat::SAMPLE_FORMAT_R8);\n    writer->write_bits(&data[0], 11);\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(f), std::string(\"\\x08\\x00\\x00\\x00\", 4));\n}\n\nTEST(MeasureRecordWriter, write_bits_r8_b) {\n    FILE *f = tmpfile();\n    uint8_t data[]{0xFF, 0x0};\n    auto writer = MeasureRecordWriter::make(f, SampleFormat::SAMPLE_FORMAT_R8);\n    writer->write_bits(&data[0], 11);\n    writer->write_end();\n    ASSERT_EQ(rewind_read_close(f), std::string(\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\", 9));\n}\n"
  },
  {
    "path": "src/stim/io/raii_file.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/io/raii_file.h\"\n\n#include <sstream>\n\nusing namespace stim;\n\nRaiiFile::RaiiFile(FILE *claim_ownership) : f(claim_ownership), responsible_for_closing(true) {\n}\n\nRaiiFile::RaiiFile(RaiiFile &&other) noexcept : f(other.f), responsible_for_closing(other.responsible_for_closing) {\n    other.responsible_for_closing = false;\n    other.f = nullptr;\n}\n\nRaiiFile::RaiiFile(const char *optional_path, const char *mode) : f(nullptr), responsible_for_closing(true) {\n    open(optional_path, mode);\n}\n\nRaiiFile::RaiiFile(std::string_view optional_path, const char *mode) : f(nullptr), responsible_for_closing(true) {\n    open(optional_path, mode);\n}\n\nvoid RaiiFile::open(const char *optional_path, const char *mode) {\n    done();\n    if (optional_path == nullptr) {\n        return;\n    }\n    open(std::string_view(optional_path), mode);\n}\n\nvoid RaiiFile::open(std::string_view optional_path, const char *mode) {\n    done();\n    if (optional_path.empty()) {\n        return;\n    }\n\n    // TODO: avoid needing the string copy (for null termination) to safely open the file.\n    f = fopen(std::string(optional_path).c_str(), mode);\n\n    if (f == nullptr) {\n        std::stringstream ss;\n        ss << \"Failed to open '\";\n        ss << optional_path;\n        ss << \"' for \";\n        if (*mode == 'r') {\n            ss << \"reading.\";\n        } else {\n            ss << \"writing.\";\n        }\n        throw std::invalid_argument(ss.str());\n    }\n}\n\nRaiiFile::~RaiiFile() {\n    done();\n}\n\nvoid RaiiFile::done() {\n    if (f != nullptr && responsible_for_closing) {\n        fclose(f);\n        f = nullptr;\n        responsible_for_closing = false;\n    }\n}\n"
  },
  {
    "path": "src/stim/io/raii_file.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_IO_RAII_FILE\n#define _STIM_IO_RAII_FILE\n\n#include <cstdio>\n#include <string_view>\n\nnamespace stim {\n\nstruct RaiiFile {\n    FILE *f;\n    bool responsible_for_closing;\n    RaiiFile(const char *optional_path, const char *mode);\n    RaiiFile(std::string_view optional_path, const char *mode);\n    RaiiFile(FILE *claim_ownership);\n    RaiiFile(const RaiiFile &other) = delete;\n    RaiiFile(RaiiFile &&other) noexcept;\n    ~RaiiFile();\n    void open(std::string_view optional_path, const char *mode);\n    void open(const char *optional_path, const char *mode);\n    void done();\n};\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/io/read_write.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/io/read_write.pybind.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/io/measure_record_reader.h\"\n#include \"stim/io/measure_record_writer.h\"\n#include \"stim/io/raii_file.h\"\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nstd::string path_to_string(const pybind11::object &path_obj) {\n    try {\n        return pybind11::cast<std::string>(path_obj);\n    } catch (pybind11::cast_error &ex) {\n    }\n\n    auto py_path = pybind11::module::import(\"pathlib\").attr(\"Path\");\n    if (pybind11::isinstance(path_obj, py_path)) {\n        return pybind11::cast<std::string>(pybind11::str(path_obj));\n    }\n\n    throw std::invalid_argument(\"Not a str or pathlib.Path: \" + pybind11::cast<std::string>(pybind11::str(path_obj)));\n}\n\npybind11::object buffer_slice_to_numpy(\n    size_t num_shots,\n    size_t shot_num_stride_bytes,\n    size_t shot_bit_copy_offset,\n    size_t shot_bit_copy_length,\n    bool bit_packed,\n    SpanRef<const uint8_t> immovable_buffer) {\n    size_t num_bytes_copied_per_shot = (shot_bit_copy_length + 7) / 8;\n    if (bit_packed) {\n        uint8_t *buffer = new uint8_t[num_bytes_copied_per_shot * num_shots];\n        memset(buffer, 0, num_bytes_copied_per_shot * num_shots);\n        for (size_t s = 0; s < num_shots; s++) {\n            size_t t = s * num_bytes_copied_per_shot * 8;\n            for (size_t k = 0; k < shot_bit_copy_length; k++) {\n                auto k2 = k + shot_bit_copy_offset;\n                auto bi = s * shot_num_stride_bytes + k2 / 8;\n                bool bit = (immovable_buffer[bi] >> (k2 % 8)) & 1;\n                buffer[t / 8] |= bit << (t & 7);\n                t++;\n            }\n        }\n\n        pybind11::capsule free_when_done(buffer, [](void *f) {\n            delete[] reinterpret_cast<uint8_t *>(f);\n        });\n\n        return pybind11::array_t<uint8_t>(\n            {(pybind11::ssize_t)num_shots, (pybind11::ssize_t)num_bytes_copied_per_shot},\n            {(pybind11::ssize_t)num_bytes_copied_per_shot, (pybind11::ssize_t)1},\n            buffer,\n            free_when_done);\n    } else {\n        bool *buffer = new bool[shot_bit_copy_length * num_shots];\n        size_t t = 0;\n        for (size_t s = 0; s < num_shots; s++) {\n            for (size_t k = 0; k < shot_bit_copy_length; k++) {\n                auto k2 = k + shot_bit_copy_offset;\n                auto bi = s * shot_num_stride_bytes + k2 / 8;\n                bool bit = (immovable_buffer[bi] >> (k2 % 8)) & 1;\n                buffer[t++] = bit;\n            }\n        }\n\n        pybind11::capsule free_when_done(buffer, [](void *f) {\n            delete[] reinterpret_cast<bool *>(f);\n        });\n\n        return pybind11::array_t<bool>(\n            {(pybind11::ssize_t)num_shots, (pybind11::ssize_t)shot_bit_copy_length},\n            {(pybind11::ssize_t)shot_bit_copy_length, (pybind11::ssize_t)1},\n            buffer,\n            free_when_done);\n    }\n}\n\npybind11::object read_shot_data_file(\n    const pybind11::object &path_obj,\n    const char *format,\n    const pybind11::handle &num_measurements,\n    const pybind11::handle &num_detectors,\n    const pybind11::handle &num_observables,\n    bool separate_observables,\n    bool bit_packed,\n    bool _legacy_bit_pack) {\n    auto path = path_to_string(path_obj);\n    auto parsed_format = format_to_enum(format);\n    bit_packed |= _legacy_bit_pack;\n\n    if (num_measurements.is_none() && num_detectors.is_none() && num_observables.is_none()) {\n        throw std::invalid_argument(\"Must specify num_measurements, num_detectors, num_observables.\");\n    }\n    size_t nm = num_measurements.is_none() ? 0 : pybind11::cast<size_t>(num_measurements);\n    size_t nd = num_detectors.is_none() ? 0 : pybind11::cast<size_t>(num_detectors);\n    size_t no = num_observables.is_none() ? 0 : pybind11::cast<size_t>(num_observables);\n\n    std::vector<uint8_t> full_buffer;\n    size_t num_bits_per_shot = nm + nd + no;\n    size_t num_bytes_per_shot = (num_bits_per_shot + 7) / 8;\n    size_t num_shots = 0;\n    {\n        RaiiFile f(path.c_str(), \"rb\");\n        auto reader = MeasureRecordReader<MAX_BITWORD_WIDTH>::make(f.f, parsed_format, nm, nd, no);\n\n        simd_bits<MAX_BITWORD_WIDTH> buffer(num_bits_per_shot);\n        while (true) {\n            if (!reader->start_and_read_entire_record(buffer)) {\n                break;\n            }\n            full_buffer.insert(full_buffer.end(), buffer.u8, buffer.u8 + num_bytes_per_shot);\n            num_shots += 1;\n        }\n    }\n\n    if (separate_observables) {\n        pybind11::object dets =\n            buffer_slice_to_numpy(num_shots, num_bytes_per_shot, 0, num_bits_per_shot - no, bit_packed, full_buffer);\n        pybind11::object obs =\n            buffer_slice_to_numpy(num_shots, num_bytes_per_shot, num_bits_per_shot - no, no, bit_packed, full_buffer);\n        return pybind11::make_tuple(dets, obs);\n    }\n\n    return buffer_slice_to_numpy(num_shots, num_bytes_per_shot, 0, num_bits_per_shot, bit_packed, full_buffer);\n}\n\nvoid write_shot_data_file(\n    const pybind11::object &data,\n    const pybind11::object &path_obj,\n    const char *format,\n    const pybind11::handle &num_measurements,\n    const pybind11::handle &num_detectors,\n    const pybind11::handle &num_observables) {\n    auto parsed_format = format_to_enum(format);\n    auto path = path_to_string(path_obj);\n\n    if (num_measurements.is_none() && num_detectors.is_none() && num_observables.is_none()) {\n        throw std::invalid_argument(\"Must specify num_measurements, num_detectors, num_observables.\");\n    }\n    size_t nm = num_measurements.is_none() ? 0 : pybind11::cast<size_t>(num_measurements);\n    size_t nd = num_detectors.is_none() ? 0 : pybind11::cast<size_t>(num_detectors);\n    size_t no = num_observables.is_none() ? 0 : pybind11::cast<size_t>(num_observables);\n    if (nm != 0 && (nd != 0 || no != 0)) {\n        throw std::invalid_argument(\"num_measurements and (num_detectors or num_observables)\");\n    }\n    size_t num_bits_per_shot = nm + nd + no;\n    size_t num_shots;\n    simd_bit_table<MAX_BITWORD_WIDTH> buffer =\n        numpy_array_to_transposed_simd_table(data, num_bits_per_shot, &num_shots);\n\n    RaiiFile f(path.c_str(), \"wb\");\n    simd_bits<MAX_BITWORD_WIDTH> unused(0);\n    write_table_data(\n        f.f,\n        num_shots,\n        num_bits_per_shot,\n        unused,\n        buffer,\n        parsed_format,\n        nm == 0 ? 'D' : 'M',\n        nm == 0 ? 'L' : 'M',\n        nm + nd);\n}\n\nvoid stim_pybind::pybind_read_write(pybind11::module &m) {\n    m.def(\n        \"read_shot_data_file\",\n        &read_shot_data_file,\n        pybind11::kw_only(),\n        pybind11::arg(\"path\"),\n        pybind11::arg(\"format\"),\n        pybind11::arg(\"num_measurements\") = pybind11::none(),\n        pybind11::arg(\"num_detectors\") = pybind11::none(),\n        pybind11::arg(\"num_observables\") = pybind11::none(),\n        pybind11::arg(\"separate_observables\") = false,\n        pybind11::arg(\"bit_packed\") = false,\n        pybind11::arg(\"bit_pack\") = false,  // Legacy argument for backwards compat.\n        clean_doc_string(R\"DOC(\n            Reads shot data, such as measurement samples, from a file.\n            @overload def read_shot_data_file(*, path: Union[str, pathlib.Path], format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"], bit_packed: bool = False, num_measurements: int = 0, num_detectors: int = 0, num_observables: int = 0) -> np.ndarray:\n            @overload def read_shot_data_file(*, path: Union[str, pathlib.Path], format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"], bit_packed: bool = False, num_measurements: int = 0, num_detectors: int = 0, num_observables: int = 0, separate_observables: Literal[True]) -> Tuple[np.ndarray, np.ndarray]:\n            @signature def read_shot_data_file(*, path: Union[str, pathlib.Path], format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"], bit_packed: bool = False, num_measurements: int = 0, num_detectors: int = 0, num_observables: int = 0, separate_observables: bool = False) -> Union[Tuple[np.ndarray, np.ndarray], np.ndarray]:\n\n            Args:\n                path: The path to the file to read the data from.\n                format: The format that the data is stored in, such as 'b8'.\n                    See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n                bit_packed: Defaults to false. Determines whether the result is a bool_\n                    numpy array with one bit per byte, or a uint8 numpy array with 8 bits\n                    per byte.\n                num_measurements: How many measurements there are per shot.\n                num_detectors: How many detectors there are per shot.\n                num_observables: How many observables there are per shot.\n                    Note that this only refers to observables *stored in the file*, not to\n                    observables from the original circuit that was sampled.\n                separate_observables: When set to True, the result is a tuple of two arrays,\n                    one containing the detection event data and the other containing the\n                    observable data, instead of a single array.\n\n            Returns:\n                If separate_observables=True:\n                    A tuple (dets, obs) of numpy arrays containing the loaded data.\n\n                    If bit_packed=False:\n                        dets.dtype = np.bool_\n                        dets.shape = (num_shots, num_measurements + num_detectors)\n                        det bit b from shot s is at dets[s, b]\n                        obs.dtype = np.bool_\n                        obs.shape = (num_shots, num_observables)\n                        obs bit b from shot s is at dets[s, b]\n                    If bit_packed=True:\n                        dets.dtype = np.uint8\n                        dets.shape = (num_shots, math.ceil(\n                            (num_measurements + num_detectors) / 8))\n                        obs.dtype = np.uint8\n                        obs.shape = (num_shots, math.ceil(num_observables / 8))\n                        det bit b from shot s is at dets[s, b // 8] & (1 << (b % 8))\n                        obs bit b from shot s is at obs[s, b // 8] & (1 << (b % 8))\n\n                If separate_observables=False:\n                    A numpy array containing the loaded data.\n\n                    If bit_packed=False:\n                        dtype = np.bool_\n                        shape = (num_shots,\n                                 num_measurements + num_detectors + num_observables)\n                        bit b from shot s is at result[s, b]\n                    If bit_packed=True:\n                        dtype = np.uint8\n                        shape = (num_shots, math.ceil(\n                            (num_measurements + num_detectors + num_observables) / 8))\n                        bit b from shot s is at result[s, b // 8] & (1 << (b % 8))\n\n            Examples:\n                >>> import stim\n                >>> import pathlib\n                >>> import tempfile\n                >>> with tempfile.TemporaryDirectory() as d:\n                ...     path = pathlib.Path(d) / 'shots'\n                ...     with open(path, 'w') as f:\n                ...         print(\"0000\", file=f)\n                ...         print(\"0101\", file=f)\n                ...\n                ...     read = stim.read_shot_data_file(\n                ...         path=str(path),\n                ...         format='01',\n                ...         num_measurements=4)\n                >>> read\n                array([[False, False, False, False],\n                       [False,  True, False,  True]])\n        )DOC\")\n            .data());\n\n    m.def(\n        \"write_shot_data_file\",\n        &write_shot_data_file,\n        pybind11::kw_only(),\n        pybind11::arg(\"data\"),\n        pybind11::arg(\"path\"),\n        pybind11::arg(\"format\"),\n        pybind11::arg(\"num_measurements\") = pybind11::none(),\n        pybind11::arg(\"num_detectors\") = pybind11::none(),\n        pybind11::arg(\"num_observables\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            Writes shot data, such as measurement samples, to a file.\n            @signature def write_shot_data_file(*, data: np.ndarray, path: Union[str, pathlib.Path], format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"], num_measurements: int = 0, num_detectors: int = 0, num_observables: int = 0) -> None:\n\n            Args:\n                data: The data to write to the file. This must be a numpy array. The dtype\n                    of the array determines whether or not the data is bit packed, and the\n                    shape must match the bits per shot.\n\n                    dtype=np.bool_: Not bit packed. Shape must be\n                        (num_shots, num_measurements + num_detectors + num_observables).\n                    dtype=np.uint8: Yes bit packed. Shape must be\n                        (num_shots, math.ceil(\n                            (num_measurements + num_detectors + num_observables) / 8)).\n                path: The path to the file to write the data to.\n                format: The format that the data is stored in, such as 'b8'.\n                    See https://github.com/quantumlib/Stim/blob/main/doc/result_formats.md\n                num_measurements: How many measurements there are per shot.\n                num_detectors: How many detectors there are per shot.\n                num_observables: How many observables there are per shot.\n                    Note that this only refers to observables *in the given shot data*, not\n                    to observables from the original circuit that was sampled.\n\n            Examples:\n                >>> import stim\n                >>> import pathlib\n                >>> import tempfile\n                >>> import numpy as np\n                >>> with tempfile.TemporaryDirectory() as d:\n                ...     path = pathlib.Path(d) / 'shots'\n                ...     shot_data = np.array([\n                ...         [0, 1, 0],\n                ...         [0, 1, 1],\n                ...     ], dtype=np.bool_)\n                ...\n                ...     stim.write_shot_data_file(\n                ...         path=str(path),\n                ...         data=shot_data,\n                ...         format='01',\n                ...         num_measurements=3)\n                ...\n                ...     with open(path) as f:\n                ...         written = f.read()\n                >>> written\n                '010\\n011\\n'\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/io/read_write.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_IO_READ_WRITE_PYBIND_H\n#define _STIM_IO_READ_WRITE_PYBIND_H\n\n#include <cstddef>\n#include <pybind11/pybind11.h>\n\n#include \"stim/mem/simd_bit_table.h\"\n\nnamespace stim_pybind {\n\nvoid pybind_read_write(pybind11::module &m);\n\n}  // namespace stim_pybind\n\n#endif"
  },
  {
    "path": "src/stim/io/read_write_pytest.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport itertools\n\nimport pathlib\nimport pytest\nimport tempfile\n\nimport numpy as np\nimport stim\n\n\ndef test_read_shot_data_file_01():\n    with tempfile.TemporaryDirectory() as d:\n        path = str(pathlib.Path(d) / 'file.01')\n        with open(path, 'w') as f:\n            print('0001110011', file=f)\n            print('0000000000', file=f)\n\n        with pytest.raises(ValueError, match='expected data length'):\n            stim.read_shot_data_file(\n                path=path,\n                format='01',\n                num_measurements=9,\n            )\n\n        with pytest.raises(ValueError, match='ended in middle'):\n            stim.read_shot_data_file(\n                path=path,\n                format='01',\n                num_measurements=11,\n            )\n\n        result = stim.read_shot_data_file(\n            path=path,\n            format='01',\n            num_measurements=10,\n        )\n        assert result.dtype == np.bool_\n        assert result.shape == (2, 10)\n        np.testing.assert_array_equal(\n            result,\n            [\n                [0, 0, 0, 1, 1, 1, 0, 0, 1, 1],\n                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n            ])\n\n        result = stim.read_shot_data_file(\n            path=path,\n            format='01',\n            num_measurements=10,\n            bit_pack=True,\n        )\n        assert result.dtype == np.uint8\n        assert result.shape == (2, 2)\n        np.testing.assert_array_equal(\n            result,\n            [\n                [0x38, 0x03],\n                [0x00, 0x00],\n            ])\n\n\ndef test_read_shot_data_file_dets():\n    with tempfile.TemporaryDirectory() as d:\n        path = str(pathlib.Path(d) / 'file.01')\n        with open(path, 'w') as f:\n            print('shot', file=f)\n            print('shot D0 D5 L0', file=f)\n\n        with pytest.raises(ValueError, match='D0'):\n            stim.read_shot_data_file(\n                path=path,\n                format='dets',\n                num_measurements=9,\n            )\n\n        with pytest.raises(ValueError, match='D5'):\n            stim.read_shot_data_file(\n                path=path,\n                format='dets',\n                num_measurements=0,\n                num_detectors=5,\n                num_observables=2,\n            )\n\n        result = stim.read_shot_data_file(\n            path=path,\n            format='dets',\n            num_measurements=0,\n            num_detectors=10,\n            num_observables=2,\n        )\n        assert result.dtype == np.bool_\n        assert result.shape == (2, 12)\n        np.testing.assert_array_equal(\n            result,\n            [\n                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n                [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],\n            ])\n\n        # Separate observables\n        result_dets, result_obs = stim.read_shot_data_file(\n            path=path,\n            format='dets',\n            num_measurements=0,\n            num_detectors=10,\n            num_observables=2,\n            separate_observables=True,\n        )\n        assert result_dets.dtype == np.bool_\n        assert result_dets.shape == (2, 10)\n        np.testing.assert_array_equal(\n            result_dets,\n            [\n                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n                [1, 0, 0, 0, 0, 1, 0, 0, 0, 0],\n            ])\n        assert result_obs.dtype == np.bool_\n        assert result_obs.shape == (2, 2)\n        np.testing.assert_array_equal(\n            result_obs,\n            [\n                [0, 0],\n                [1, 0],\n            ])\n\n        # Separate observables bit packed.\n        result_dets, result_obs = stim.read_shot_data_file(\n            path=path,\n            format='dets',\n            num_measurements=0,\n            num_detectors=10,\n            num_observables=2,\n            separate_observables=True,\n            bit_packed=True,\n        )\n        assert result_dets.dtype == np.uint8\n        assert result_dets.shape == (2, 2)\n        np.testing.assert_array_equal(\n            result_dets,\n            [\n                [0, 0],\n                [0b00100001, 0],\n            ])\n        assert result_obs.dtype == np.uint8\n        assert result_obs.shape == (2, 1)\n        np.testing.assert_array_equal(\n            result_obs,\n            [\n                [0],\n                [1],\n            ])\n\n\ndef test_write_shot_data_file_01():\n    with tempfile.TemporaryDirectory() as d:\n        path = str(pathlib.Path(d) / 'file.01')\n\n        with pytest.raises(ValueError, match='4 bits per shot.+bool_'):\n            stim.write_shot_data_file(\n                data=np.array([\n                    [0, 1, 0],\n                    [0, 1, 1],\n                ], dtype=np.bool_),\n                path=path,\n                format='01',\n                num_measurements=4,\n            )\n\n        with pytest.raises(ValueError, match='4 bits per shot.+uint8'):\n            stim.write_shot_data_file(\n                data=np.array([\n                    [0, 1, 0],\n                    [0, 1, 1],\n                ], dtype=np.uint8),\n                path=path,\n                format='01',\n                num_measurements=4,\n            )\n\n        with pytest.raises(ValueError, match='num_measurements and'):\n            stim.write_shot_data_file(\n                data=np.array([\n                    [0, 1, 0],\n                    [0, 1, 1],\n                ], dtype=np.bool_),\n                path=path,\n                format='01',\n                num_measurements=1,\n                num_detectors=2,\n            )\n\n        stim.write_shot_data_file(\n            data=np.array([\n                [0, 1, 0],\n                [0, 1, 1],\n            ], dtype=np.bool_),\n            path=path,\n            format='01',\n            num_measurements=3,\n        )\n        with open(path) as f:\n            assert f.read() == '010\\n011\\n'\n\n        stim.write_shot_data_file(\n            data=np.array([\n                [0x38, 0x03],\n                [0x00, 0x00],\n            ], dtype=np.uint8),\n            path=path,\n            format='01',\n            num_measurements=13,\n        )\n        with open(path) as f:\n            assert f.read() == '0001110011000\\n0000000000000\\n'\n\n\ndef test_read_data_file_partial_b8():\n    with tempfile.TemporaryDirectory() as d:\n        path = pathlib.Path(d) / 'tmp.b8'\n        with open(path, 'wb') as f:\n            f.write(b'\\0' * 273)\n        with pytest.raises(ValueError, match=\"middle of record\"):\n            stim.read_shot_data_file(\n                path=str(path),\n                format=\"b8\",\n                num_detectors=2185,\n                num_observables=0,\n            )\n\n\ndef test_read_data_file_big_b8():\n    with tempfile.TemporaryDirectory() as d:\n        path = pathlib.Path(d) / 'tmp.b8'\n        with open(path, 'wb') as f:\n            f.write(b'\\0' * 274000)\n        stim.read_shot_data_file(\n            path=str(path),\n            format=\"b8\",\n            num_detectors=2185,\n            num_observables=0,\n        )\n\n\ndef test_read_01_shots():\n    with tempfile.TemporaryDirectory() as d:\n        path = pathlib.Path(d) / 'shots'\n        with open(path, 'w') as f:\n            print(\"0000\", file=f)\n            print(\"0101\", file=f)\n\n        read = stim.read_shot_data_file(\n            path=str(path),\n            format='01',\n            num_measurements=4)\n        np.testing.assert_array_equal(\n            read,\n            [[0, 0, 0, 0], [0, 1, 0, 1]]\n        )\n\n\n@pytest.mark.parametrize(\"data_format,bit_packed,path_type\", itertools.product(\n    [\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    [False, True],\n    [\"str\", \"path\"]))\ndef test_read_write_shots_fuzzing(data_format: str, bit_packed: bool, path_type: str):\n    with tempfile.TemporaryDirectory() as d:\n        file_path = pathlib.Path(d) / 'shots'\n        num_shots = 320\n        num_measurements = 500\n        data = np.random.randint(2, size=(num_shots, num_measurements), dtype=np.bool_)\n        if bit_packed:\n            packed_data = np.packbits(data, axis=1, bitorder='little')\n        else:\n            packed_data = data\n        if path_type == \"path\":\n            path_arg = file_path\n        elif path_type == \"str\":\n            path_arg = str(file_path)\n        else:\n            raise NotImplementedError(f'{path_type=}')\n        stim.write_shot_data_file(\n            data=packed_data,\n            path=path_arg,\n            format=data_format,\n            num_measurements=num_measurements,\n        )\n        round_trip_data = stim.read_shot_data_file(\n            path=path_arg,\n            format=data_format,\n            num_measurements=num_measurements,\n            bit_pack=bit_packed,\n        )\n\n        np.testing.assert_array_equal(packed_data, round_trip_data)\n\n\n@pytest.mark.parametrize(\"data_format,num_bits_per_shot\", itertools.product(\n    [\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"],\n    [11, 511, 512, 513],\n))\ndef test_read_write_shots_fuzzing_vs_python_references(data_format: str, num_bits_per_shot: int):\n    with tempfile.TemporaryDirectory() as d:\n        path = pathlib.Path(d) / 'shots'\n        num_shots = 320\n        data = np.random.randint(2, size=(num_shots, num_bits_per_shot), dtype=np.bool_)\n        stim.write_shot_data_file(\n            data=data,\n            path=path,\n            format=data_format,\n            num_detectors=num_bits_per_shot,\n        )\n\n        g = {}\n        exec(stim._UNSTABLE_raw_format_data()[data_format]['save_example'], g)\n        save_method = g[f'save_{data_format}']\n        if data_format == 'dets':\n            reference_written_data = save_method(data, num_detectors=num_bits_per_shot, num_observables=0)\n        else:\n            reference_written_data = save_method(data)\n\n        with open(path, 'rb' if isinstance(reference_written_data, bytes) else 'r') as f:\n            actual_written_data = f.read()\n        assert actual_written_data == reference_written_data\n\n        g = {}\n        exec(stim._UNSTABLE_raw_format_data()[data_format]['parse_example'], g)\n        read_method = g[f'parse_{data_format}']\n        if data_format == \"01\":\n            reference_read_data = read_method(actual_written_data)\n        elif data_format == \"dets\":\n            reference_read_data = read_method(actual_written_data, num_detectors=num_bits_per_shot, num_observables=0)\n        else:\n            reference_read_data = read_method(actual_written_data, bits_per_shot=num_bits_per_shot)\n        actual_read_data = stim.read_shot_data_file(\n            path=path,\n            format=data_format,\n            num_detectors=num_bits_per_shot,\n        )\n\n        np.testing.assert_array_equal(actual_read_data, reference_read_data)\n"
  },
  {
    "path": "src/stim/io/sparse_shot.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/sparse_shot.h\"\n\n#include <sstream>\n\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\n\nSparseShot::SparseShot() : hits(), obs_mask(0) {\n}\nSparseShot::SparseShot(std::vector<uint64_t> hits, simd_bits<64> obs_mask)\n    : hits(std::move(hits)), obs_mask(std::move(obs_mask)) {\n}\n\nvoid SparseShot::clear() {\n    hits.clear();\n    obs_mask.clear();\n}\n\nbool SparseShot::operator==(const SparseShot &other) const {\n    return hits == other.hits && obs_mask == other.obs_mask;\n}\n\nbool SparseShot::operator!=(const SparseShot &other) const {\n    return !(*this == other);\n}\n\nuint64_t SparseShot::obs_mask_as_u64() const {\n    if (obs_mask.num_u64_padded() == 0) {\n        return 0;\n    }\n    return obs_mask.u64[0];\n}\n\nstd::string SparseShot::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const SparseShot &v) {\n    return out << \"SparseShot{{\" << comma_sep(v.hits) << \"}, \" << v.obs_mask << \"}\";\n}\n"
  },
  {
    "path": "src/stim/io/sparse_shot.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_IO_SPARSE_SHOT_H\n#define _STIM_IO_SPARSE_SHOT_H\n\n#include <string>\n#include <vector>\n\n#include \"stim/mem/simd_bits.h\"\n\nnamespace stim {\n\n/// Stores shot data sparsely, as a list of locations of 1 bits in the shot.\n///\n/// For contrast, dense storage would involve storing one bit for each bit in the shot.\n///\n/// If this shot is detection event data, the observable data is still stored densely in\n/// the obs_mask field.\nstruct SparseShot {\n    /// Indices of non-zero bits.\n    std::vector<uint64_t> hits;\n\n    /// When reading detection event data with observables appended, the observables go into this mask.\n    /// The observable with index k goes into the 1<<k bit.\n    simd_bits<64> obs_mask;\n\n    SparseShot();\n    SparseShot(std::vector<uint64_t> hits, simd_bits<64> obs_mask);\n\n    /// Returns a uint64_t containing the first 64 observable bit flips.\n    /// Defaults to 0 if there are no observables.\n    uint64_t obs_mask_as_u64() const;\n\n    void clear();\n    bool operator==(const SparseShot &other) const;\n    bool operator!=(const SparseShot &other) const;\n    std::string str() const;\n};\nstd::ostream &operator<<(std::ostream &out, const SparseShot &v);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/io/sparse_shot.test.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/io/sparse_shot.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nstatic simd_bits<64> obs_mask(uint64_t v) {\n    simd_bits<64> result(64);\n    result.ptr_simd[0] = v;\n    return result;\n}\n\nTEST(sparse_shot, equality) {\n    ASSERT_TRUE((SparseShot{}) == (SparseShot{}));\n    ASSERT_FALSE((SparseShot{}) != (SparseShot{}));\n    ASSERT_TRUE((SparseShot{}) != (SparseShot{{2}, obs_mask(0)}));\n    ASSERT_FALSE((SparseShot{}) == (SparseShot{{2}, obs_mask(0)}));\n\n    ASSERT_EQ((SparseShot{{1, 2, 3}, obs_mask(4)}), (SparseShot{{1, 2, 3}, obs_mask(4)}));\n    ASSERT_NE((SparseShot{{1, 2, 3}, obs_mask(4)}), (SparseShot{{1, 2, 3}, obs_mask(5)}));\n    ASSERT_NE((SparseShot{{1, 2, 3}, obs_mask(4)}), (SparseShot{{1, 2, 4}, obs_mask(4)}));\n    ASSERT_NE((SparseShot{{1, 2, 3}, obs_mask(4)}), (SparseShot{{1, 2}, obs_mask(4)}));\n}\n\nTEST(sparse_shot, str) {\n    ASSERT_EQ(\n        (SparseShot{{1, 2, 3}, obs_mask(4)}.str()),\n        \"SparseShot{{1, 2, 3}, __1_____________________________________________________________}\");\n}\n\nTEST(spares_shot, obs_mask_as_u64) {\n    SparseShot s{};\n    ASSERT_EQ(s.obs_mask_as_u64(), 0);\n\n    s.obs_mask = simd_bits<64>(5);\n    ASSERT_EQ(s.obs_mask_as_u64(), 0);\n    s.obs_mask[1] = true;\n    ASSERT_EQ(s.obs_mask_as_u64(), 2);\n\n    s.obs_mask = simd_bits<64>(125);\n    ASSERT_EQ(s.obs_mask_as_u64(), 0);\n    s.obs_mask[1] = true;\n    ASSERT_EQ(s.obs_mask_as_u64(), 2);\n    s.obs_mask[64] = true;\n    ASSERT_EQ(s.obs_mask_as_u64(), 2);\n}\n"
  },
  {
    "path": "src/stim/io/stim_data_formats.cc",
    "content": "#include \"stim/io/stim_data_formats.h\"\n\nusing namespace stim;\n\nconst std::map<std::string_view, FileFormatData> &stim::format_name_to_enum_map() {\n    static const std::map<std::string_view, stim::FileFormatData> mapping{\n        {\n            \"01\",\n            FileFormatData{\n                \"01\",\n                SampleFormat::SAMPLE_FORMAT_01,\n                R\"HELP(\nThe 01 format is a dense human readable format that stores shots as lines of '0' and '1' characters.\n\nThe data from each shot is terminated by a newline character '\\n'. Each character in the line is a '0' (indicating\nFalse) or a '1' (indicating True) corresponding to a measurement result (or a detector result) from a circuit.\n\nThis is the default format used by Stim, because it's the easiest to understand.\n\n*Example of producing 01 format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"01\")\n    ...     with open(path) as f:\n    ...         print(f.read().strip())\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n    00001111001101\n)HELP\",\n                R\"PYTHON(\nfrom typing import List\n\ndef save_01(shots: List[List[bool]]) -> str:\n    output = \"\"\n    for shot in shots:\n        for sample in shot:\n            output += '1' if sample else '0'\n        output += \"\\n\"\n    return output\n)PYTHON\",\n                R\"PYTHON(\nfrom typing import List\n\ndef parse_01(data: str) -> List[List[bool]]:\n    shots = []\n    for line in data.split('\\n'):\n        if not line:\n            continue\n        shot = []\n        for c in line:\n            assert c in '01'\n            shot.append(c == '1')\n        shots.append(shot)\n    return shots\n)PYTHON\",\n            },\n        },\n\n        {\n            \"b8\",\n            FileFormatData{\n                \"b8\",\n                SampleFormat::SAMPLE_FORMAT_B8,\n                R\"HELP(\nThe b8 format is a dense binary format that stores shots as bit-packed bytes.\n\nEach shot is stored into ceil(n / 8) bytes, where n is the number of bits in the shot. Effectively, each shot is padded\nup to a multiple of 8 by appending False bits, so that shots always start on a byte boundary. Bits are packed into bytes\nin significance order (the 1s bit is the first bit, the 2s bit is the second, the 4s bit is the third, and so forth\nuntil the 128s bit which is the eighth bit).\n\nThis format requires the reader to know the number of bits in each shot.\n\n*Example of producing b8 format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"b8\")\n    ...     with open(path, 'rb') as f:\n    ...         print(' '.join(hex(e)[2:] for e in f.read()))\n    f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c f0 2c\n)HELP\",\n                R\"PYTHON(\nfrom typing import List\n\ndef save_b8(shots: List[List[bool]]) -> bytes:\n    output = b\"\"\n    for shot in shots:\n        bytes_per_shot = (len(shot) + 7) // 8\n        v = 0\n        for b in reversed(shot):\n            v <<= 1\n            v += int(b)\n        output += v.to_bytes(bytes_per_shot, 'little')\n    return output\n)PYTHON\",\n                R\"PYTHON(\nfrom typing import List\n\ndef parse_b8(data: bytes, bits_per_shot: int) -> List[List[bool]]:\n    shots = []\n    bytes_per_shot = (bits_per_shot + 7) // 8\n    for offset in range(0, len(data), bytes_per_shot):\n        shot = []\n        for k in range(bits_per_shot):\n            byte = data[offset + k // 8]\n            bit = (byte >> (k % 8)) % 2 == 1\n            shot.append(bit)\n        shots.append(shot)\n    return shots\n)PYTHON\",\n            },\n        },\n\n        {\n            \"ptb64\",\n            FileFormatData{\n                \"ptb64\",\n                SampleFormat::SAMPLE_FORMAT_PTB64,\n                R\"HELP(\nThe ptb64 format is a dense SIMD-focused binary format that stores shots as partially transposed bit-packed data.\n\nEach 64 bit word (8 bytes) of the data contains bits from the same measurement result across 64 separate shots. The next\n8 bytes contain bits for the next measurement result from the 64 separate shots. This continues until the 8 bytes\ncontaining the bits from the last measurement result, and then starts over again with data from the next 64 shots (if\nthere are more).\n\nThe shots are stored by byte order then significance order. The first shot's data goes into the least significant bit of\nthe first byte of each 8 byte group.\n\nThis format requires the number of shots to be a multiple of 64.\nThis format requires the reader to know the number of shots that were taken.\n\nThis format is generally more tedious to work with, but useful for achieving good performance on data processing tasks\nwhere it is possible to parallelize across shots using SIMD instructions.\n\n*Example of producing ptb64 format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=64, filepath=path, format=\"ptb64\")\n    ...     with open(path, 'rb') as f:\n    ...         print(' '.join(hex(e)[2:] for e in f.read()))\n    0 0 0 0 0 0 0 0 ff ff ff ff ff ff ff ff\n)HELP\",\n                R\"PYTHON(\nfrom typing import List\n\ndef save_ptb64(shots: List[List[bool]]):\n    if len(shots) % 64 != 0:\n        raise ValueError(\"Number of shots must be a multiple of 64.\")\n\n    output = []\n    for shot_offset in range(0, len(shots), 64):\n        bits_per_shot = len(shots[0])\n        for measure_index in range(bits_per_shot):\n            v = 0\n            for k in range(64)[::-1]:\n                v <<= 1\n                v += int(shots[shot_offset + k][measure_index])\n            output.append(v.to_bytes(8, 'little'))\n    return b''.join(output)\n)PYTHON\",\n                R\"PYTHON(\nfrom typing import List\n\ndef parse_ptb64(data: bytes, bits_per_shot: int) -> List[List[bool]]:\n    num_shot_groups = int(len(data) * 8 / bits_per_shot / 64)\n    if len(data) * 8 != num_shot_groups * 64 * bits_per_shot:\n        raise ValueError(\"Number of shots must be a multiple of 64.\")\n\n    result = [[False] * bits_per_shot for _ in range(num_shot_groups * 64)]\n    for group_index in range(num_shot_groups):\n        group_bit_offset = 64 * bits_per_shot * group_index\n        for m in range(bits_per_shot):\n            m_bit_offset = m * 64\n            for shot in range(64):\n                bit_offset = group_bit_offset + m_bit_offset + shot\n                bit = data[bit_offset // 8] & (1 << (bit_offset % 8)) != 0\n                s = group_index * 64 + shot\n                result[s][m] = bit\n    return result\n)PYTHON\",\n            },\n        },\n\n        {\n            \"hits\",\n            FileFormatData{\n                \"hits\",\n                SampleFormat::SAMPLE_FORMAT_HITS,\n                R\"HELP(\nThe hits format is a dense human readable format that stores shots as a comma-separated list of integers.\nEach integer indicates the position of a bit that was True.\nPositions that aren't mentioned had bits that were False.\n\nThe data from each shot is terminated by a newline character '\\n'. The line is a series of non-negative integers\nseparated by commas, with each integer indicating a bit from the shot that was true.\n\nThis format requires the reader to know the number of bits in each shot (if they want to get a list instead of a set).\nThis format requires the reader to know how many trailing newlines, that don't correspond to shots with no hit, are in\nthe text data.\n\nThis format is useful in contexts where the number of set bits is expected to be low, e.g. when sampling detection\nevents.\n\n*Example of producing hits format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"hits\")\n    ...     with open(path) as f:\n    ...         print(f.read().strip())\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n    4,5,6,7,10,11,13\n)HELP\",\n                R\"PYTHON(\nfrom typing import List\n\ndef save_hits(shots: List[List[bool]]) -> str:\n    output = \"\"\n    for shot in shots:\n        output += \",\".join(str(index) for index, bit in enumerate(shot) if bit) + \"\\n\"\n    return output\n)PYTHON\",\n                R\"PYTHON(\nfrom typing import List\n\ndef parse_hits(data: str, bits_per_shot: int) -> List[List[bool]]:\n    shots = []\n    if data.endswith('\\n'):\n        data = data[:-1]\n    for line in data.split('\\n'):\n        shot = [False] * bits_per_shot\n        if line:\n            for term in line.split(','):\n                shot[int(term)] = True\n        shots.append(shot)\n    return shots\n)PYTHON\",\n            },\n        },\n\n        {\n            \"r8\",\n            FileFormatData{\n                \"r8\",\n                SampleFormat::SAMPLE_FORMAT_R8,\n                R\"HELP(\nThe r8 format is a sparse binary format that stores shots as a series of lengths of runs between 1s.\n\nEach byte in the data indicates how many False bits there are before the next True bit. The maximum byte value (255) is\nspecial; it indicates to include 255 False bits but not follow them by a True bit. A shot always has a terminating True\nbit appended to it before encoding. Decoding of the shot ends (and the next shot begin) when this True bit just past the\nend of the shot data is reached.\n\nThis format requires the reader to know the number of bits in each shot.\n\nThis format is useful in contexts where the number of set bits is expected to be low, e.g. when sampling detection\nevents.\n\n*Example of producing r8 format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"r8\")\n    ...     with open(path, 'rb') as f:\n    ...         print(' '.join(hex(e)[2:] for e in f.read()))\n    4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0 4 0 0 0 2 0 1 0\n\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n    ...     \"\"\").compile_sampler().sample_write(shots=10, filepath=path, format=\"r8\")\n    ...     with open(path, 'rb') as f:\n    ...         print(' '.join(hex(e)[2:] for e in f.read()))\n    9 1f 9 1f 9 1f 9 1f 9 1f 9 1f 9 1f 9 1f 9 1f 9 1f\n)HELP\",\n                R\"PYTHON(\nfrom typing import List\n\ndef save_r8(shots: List[List[bool]]) -> bytes:\n    output = []\n    for shot in shots:\n        gap = 0\n        for b in list(shot) + [True]:\n            if b:\n                while gap >= 255:\n                    gap -= 255\n                    output.append((255).to_bytes(1, 'big'))\n                output.append(gap.to_bytes(1, 'big'))\n                gap = 0\n            else:\n                gap += 1\n    return b''.join(output)\n)PYTHON\",\n                R\"PYTHON(\nfrom typing import List\n\ndef parse_r8(data: bytes, bits_per_shot: int) -> List[List[bool]]:\n    shots = []\n    shot = []\n    for byte in data:\n        shot += [False] * byte\n        if byte != 255:\n            shot.append(True)\n        if len(shot) > bits_per_shot:\n            assert len(shot) == bits_per_shot + 1 and shot[-1]\n            shot.pop()\n            shots.append(shot)\n            shot = []\n    assert len(shot) == 0\n    return shots\n)PYTHON\",\n            },\n        },\n\n        {\n            \"dets\",\n            FileFormatData{\n                \"dets\",\n                SampleFormat::SAMPLE_FORMAT_DETS,\n                R\"HELP(\nThe dets format is a sparse human readable format that stores shots as lines starting with the word 'shot'\nand then containing space-separated prefixed values like 'D5' and 'L2'. Each value's prefix indicates whether\nit is a measurement (M), a detector (D), or observable frame change (L) and its integer indicates that\nthe corresponding measurement/detection-event/frame-change was True instead of False.\n\nThe data from each shot is started with the text 'shot' and terminated by a newline character '\\n'. The rest of the\nline is a series of integers, separated by spaces and prefixed by a single letter. The prefix letter indicates the type\nof value ('M' for measurement, 'D' for detector, and 'L' for logical observable). The integer indicates the index of the\nvalue. For example, \"D1 D3 L0\" indicates detectors 1 and 3 fired, and logical observable 0 was flipped.\n\nThis format requires the reader to know the number of measurements/detectors/observables in each shot, if the reader\nwants to produce vectors of bits instead of sets.\n\n*Example of producing dets format data using stim's python API:*\n\n    >>> import pathlib\n    >>> import stim\n    >>> import tempfile\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X 1\n    ...         M 0 0 0 0 1 1 1 1 0 0 1 1 0 1 0 1\n    ...     \"\"\").compile_sampler().sample_write(shots=3, filepath=path, format=\"dets\")\n    ...     with open(path) as f:\n    ...         print(f.read().strip())\n    shot M4 M5 M6 M7 M10 M11 M13 M15\n    shot M4 M5 M6 M7 M10 M11 M13 M15\n    shot M4 M5 M6 M7 M10 M11 M13 M15\n\n    >>> with tempfile.TemporaryDirectory() as d:\n    ...     path = str(pathlib.Path(d) / \"tmp.dat\")\n    ...     stim.Circuit(\"\"\"\n    ...         X_ERROR(1) 1\n    ...         M 0 1 2\n    ...         DETECTOR rec[-1]\n    ...         DETECTOR rec[-2]\n    ...         DETECTOR rec[-3]\n    ...         OBSERVABLE_INCLUDE(5) rec[-2]\n    ...     \"\"\").compile_detector_sampler().sample_write(shots=2, filepath=path, format=\"dets\", append_observables=True)\n    ...     with open(path) as f:\n    ...         print(f.read().strip())\n    shot D1 L5\n    shot D1 L5\n)HELP\",\n                R\"PYTHON(\nfrom typing import List\n\ndef save_dets(shots: List[List[bool]], num_detectors: int, num_observables: int):\n    output = \"\"\n    for shot in shots:\n        assert len(shot) == num_detectors + num_observables\n        detectors = shot[:num_detectors]\n        observables = shot[num_detectors:]\n        output += \"shot\"\n        for k in range(num_detectors):\n            if shot[k]:\n                output += \" D\" + str(k)\n        for k in range(num_observables):\n            if shot[num_detectors + k]:\n                output += \" L\" + str(k)\n        output += \"\\n\"\n    return output\n)PYTHON\",\n                R\"PYTHON(\nfrom typing import List\n\ndef parse_dets(data: str, num_detectors: int, num_observables: int) -> List[List[bool]]:\n    shots = []\n    for line in data.split('\\n'):\n        if not line.strip():\n            continue\n        assert line.startswith('shot')\n        line = line[4:].strip()\n\n        shot = [False] * (num_detectors + num_observables)\n        if line:\n            for term in line.split(' '):\n                c = term[0]\n                v = int(term[1:])\n                if c == 'D':\n                    assert 0 <= v < num_detectors\n                    shot[v] = True\n                elif c == 'L':\n                    assert 0 <= v < num_observables\n                    shot[num_detectors + v] = True\n                else:\n                    raise NotImplementedError(c)\n        shots.append(shot)\n    return shots\n)PYTHON\",\n            },\n        },\n    };\n    return mapping;\n}\n"
  },
  {
    "path": "src/stim/io/stim_data_formats.h",
    "content": "#ifndef _STIM_IO_STIM_DATA_FORMATS_H\n#define _STIM_IO_STIM_DATA_FORMATS_H\n\n#include <map>\n#include <string>\n\nnamespace stim {\n\nenum class SampleFormat {\n    SAMPLE_FORMAT_01,\n    SAMPLE_FORMAT_B8,\n    SAMPLE_FORMAT_PTB64,\n    SAMPLE_FORMAT_HITS,\n    SAMPLE_FORMAT_R8,\n    SAMPLE_FORMAT_DETS,\n};\n\nstruct FileFormatData {\n    const char *name;\n    SampleFormat id;\n    const char *help;\n    const char *help_python_save;\n    const char *help_python_parse;\n};\n\nconst std::map<std::string_view, FileFormatData> &format_name_to_enum_map();\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/main.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <cmath>\n#include <iostream>\n#include <sstream>\n\n#include \"stim/perf.perf.h\"\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\n\nRegisteredBenchmark *running_benchmark = nullptr;\nstd::vector<RegisteredBenchmark> *all_registered_benchmarks_data = nullptr;\nuint64_t registry_initialized = 0;\n\n/// Describe quantity as an SI-prefixed value with two significant figures.\nstd::string si2(double val) {\n    char unit = ' ';\n    if (val < 1) {\n        if (val < 1) {\n            val *= 1000;\n            unit = 'm';\n        }\n        if (val < 1) {\n            val *= 1000;\n            unit = 'u';\n        }\n        if (val < 1) {\n            val *= 1000;\n            unit = 'n';\n        }\n        if (val < 1) {\n            val *= 1000;\n            unit = 'p';\n        }\n    } else {\n        if (val > 1000) {\n            val /= 1000;\n            unit = 'k';\n        }\n        if (val > 1000) {\n            val /= 1000;\n            unit = 'M';\n        }\n        if (val > 1000) {\n            val /= 1000;\n            unit = 'G';\n        }\n        if (val > 1000) {\n            val /= 1000;\n            unit = 'T';\n        }\n    }\n    std::stringstream ss;\n    if (1 <= val && val < 10) {\n        ss << (size_t)val << '.' << ((size_t)(val * 10) % 10);\n    } else if (10 <= val && val < 100) {\n        ss << ' ' << (size_t)val;\n    } else if (100 <= val && val < 1000) {\n        ss << (size_t)(val / 10) * 10;\n    } else {\n        ss << val;\n    }\n    ss << ' ' << unit;\n    return ss.str();\n}\n\nstatic std::vector<const char *> known_arguments{\"--only\", \"--target_seconds\"};\n\nvoid find_benchmarks(std::string_view filter, std::vector<RegisteredBenchmark> &out) {\n    bool found = false;\n\n    if (!filter.empty() && filter[filter.size() - 1] == '*') {\n        std::string_view start = filter.substr(0, filter.size() - 1);\n        for (const auto &benchmark : *all_registered_benchmarks_data) {\n            if (benchmark.name.substr(0, start.size()) == start) {\n                out.push_back(benchmark);\n                found = true;\n            }\n        }\n    } else {\n        for (const auto &benchmark : *all_registered_benchmarks_data) {\n            if (benchmark.name == filter) {\n                out.push_back(benchmark);\n                found = true;\n            }\n        }\n    }\n\n    if (!found) {\n        std::cerr << \"No benchmark matching filter '\" << filter << \"'. Available benchmarks are:\\n\";\n        for (auto &benchmark : *all_registered_benchmarks_data) {\n            std::cerr << \"    \" << benchmark.name << \"\\n\";\n        }\n        exit(EXIT_FAILURE);\n    }\n}\n\ndouble BENCHMARK_CONFIG_TARGET_SECONDS = 0.5;\n\nint main(int argc, const char **argv) {\n    check_for_unknown_arguments(known_arguments, {}, nullptr, argc, argv);\n    const char *only = find_argument(\"--only\", argc, argv);\n    BENCHMARK_CONFIG_TARGET_SECONDS = find_float_argument(\"--target_seconds\", 0.5, 0, 10000, argc, argv);\n\n    std::vector<RegisteredBenchmark> chosen_benchmarks;\n    if (only == nullptr) {\n        chosen_benchmarks = *all_registered_benchmarks_data;\n    } else {\n        std::string filter_text = only;\n        std::vector<std::string> filters{};\n        size_t s = 0;\n        for (size_t k = 0;; k++) {\n            if (only[k] == ',' || only[k] == '\\0') {\n                filters.push_back(filter_text.substr(s, k - s));\n                s = k + 1;\n            }\n            if (only[k] == '\\0') {\n                break;\n            }\n        }\n\n        if (filters.empty()) {\n            std::cerr << \"No filters specified.\\n\";\n            exit(EXIT_FAILURE);\n        }\n\n        for (const auto &filter : filters) {\n            find_benchmarks(filter, chosen_benchmarks);\n        }\n    }\n\n    for (auto &benchmark : chosen_benchmarks) {\n        running_benchmark = &benchmark;\n        benchmark.func();\n        for (const auto &result : benchmark.results) {\n            double actual_seconds_per_rep = result.total_seconds / result.total_reps;\n            if (result.goal_seconds != -1) {\n                int deviation = (int)round((log(result.goal_seconds) - log(actual_seconds_per_rep)) / (log(10) / 10.0));\n                std::cout << \"[\";\n                for (int k = -20; k <= 20; k++) {\n                    if ((k < deviation && k < 0) || (k > deviation && k > 0)) {\n                        std::cout << '.';\n                    } else if (k == deviation) {\n                        std::cout << '*';\n                    } else if (k == 0) {\n                        std::cout << '|';\n                    } else if (deviation < 0) {\n                        std::cout << '<';\n                    } else {\n                        std::cout << '>';\n                    }\n                }\n                std::cout << \"] \";\n                std::cout << si2(actual_seconds_per_rep) << \"s\";\n                std::cout << \" (vs \" << si2(result.goal_seconds) << \"s) \";\n            } else {\n                std::cout << si2(actual_seconds_per_rep) << \"s \";\n            }\n            for (const auto &e : result.marginal_rates) {\n                const auto &multiplier = e.second;\n                const auto &unit = e.first;\n                std::cout << \"(\" << si2(result.total_reps / result.total_seconds * multiplier) << unit << \"/s) \";\n            }\n            std::cout << benchmark.name << \"\\n\";\n            if (benchmark.results.empty()) {\n                std::cerr << \"`benchmark_go` was not called from BENCH(\" << benchmark.name << \")\";\n                exit(EXIT_FAILURE);\n            }\n        }\n    }\n\n    if (all_registered_benchmarks_data != nullptr) {\n        delete all_registered_benchmarks_data;\n        all_registered_benchmarks_data = nullptr;\n    }\n    return 0;\n}\n"
  },
  {
    "path": "src/stim/main_namespaced.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/main_namespaced.h\"\n\n#include <cstring>\n\n#include \"stim/cmd/command_analyze_errors.h\"\n#include \"stim/cmd/command_convert.h\"\n#include \"stim/cmd/command_detect.h\"\n#include \"stim/cmd/command_diagram.h\"\n#include \"stim/cmd/command_explain_errors.h\"\n#include \"stim/cmd/command_gen.h\"\n#include \"stim/cmd/command_help.h\"\n#include \"stim/cmd/command_m2d.h\"\n#include \"stim/cmd/command_repl.h\"\n#include \"stim/cmd/command_sample.h\"\n#include \"stim/cmd/command_sample_dem.h\"\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\n\nint stim::main(int argc, const char **argv) {\n    try {\n        const char *mode = argc > 1 ? argv[1] : \"\";\n        if (mode[0] == '-') {\n            mode = \"\";\n        }\n        auto is_mode = [&](const char *name) {\n            if (name[0] == '-') {\n                return find_argument(name, argc, argv) != nullptr || strcmp(mode, name + 2) == 0;\n            }\n            return strcmp(mode, name) == 0;\n        };\n\n        if (is_mode(\"--help\")) {\n            return command_help(argc, argv);\n        }\n\n        bool mode_repl = is_mode(\"--repl\");\n        bool mode_sample = is_mode(\"--sample\");\n        bool mode_sample_dem = is_mode(\"sample_dem\");\n        bool mode_diagram = is_mode(\"diagram\");\n        bool mode_detect = is_mode(\"--detect\");\n        bool mode_analyze_errors = is_mode(\"--analyze_errors\");\n        bool mode_gen = is_mode(\"--gen\");\n        bool mode_m2d = is_mode(\"--m2d\");\n        bool mode_explain_errors = is_mode(\"--explain_errors\");\n        bool old_mode_detector_hypergraph = find_bool_argument(\"--detector_hypergraph\", argc, argv);\n        if (old_mode_detector_hypergraph) {\n            std::cerr << \"[DEPRECATION] Use `stim analyze_errors` instead of `--detector_hypergraph`\\n\";\n            mode_analyze_errors = true;\n        }\n        bool mode_convert = is_mode(\"--convert\");\n        int modes_picked =\n            (mode_repl + mode_sample + mode_sample_dem + mode_detect + mode_analyze_errors + mode_gen + mode_m2d +\n             mode_explain_errors + mode_diagram + mode_convert);\n        if (modes_picked != 1) {\n            std::cerr << \"\\033[31m\";\n            if (modes_picked > 1) {\n                std::cerr << \"More than one mode was specified.\\n\\n\";\n            } else {\n                std::cerr << \"No mode was given.\\n\\n\";\n            }\n            std::cerr << help_for(\"\");\n            std::cerr << \"\\033[0m\";\n            return EXIT_FAILURE;\n        }\n\n        if (mode_gen) {\n            return command_gen(argc, argv);\n        }\n        if (mode_repl) {\n            return command_repl(argc, argv);\n        }\n        if (mode_sample) {\n            return command_sample(argc, argv);\n        }\n        if (mode_detect) {\n            return command_detect(argc, argv);\n        }\n        if (mode_analyze_errors) {\n            return command_analyze_errors(argc, argv);\n        }\n        if (mode_m2d) {\n            return command_m2d(argc, argv);\n        }\n        if (mode_explain_errors) {\n            return command_explain_errors(argc, argv);\n        }\n        if (mode_sample_dem) {\n            return command_sample_dem(argc, argv);\n        }\n        if (mode_diagram) {\n            return command_diagram(argc, argv);\n        }\n        if (mode_convert) {\n            return command_convert(argc, argv);\n        }\n\n        throw std::out_of_range(\"Mode not handled.\");\n    } catch (const std::invalid_argument &ex) {\n        std::string_view s = ex.what();\n        std::cerr << \"\\033[31m\";\n        std::cerr << s;\n        if (s.empty() || s.back() != '\\n') {\n            std::cerr << '\\n';\n        }\n        std::cerr << \"\\033[0m\";\n        return EXIT_FAILURE;\n    }\n}\n"
  },
  {
    "path": "src/stim/main_namespaced.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MAIN_NAMESPACED_H\n#define _STIM_MAIN_NAMESPACED_H\n\nnamespace stim {\n\n/// Stim's main method (in a namespace; not the global entrypoint main!).\nint main(int argc, const char **argv);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/main_namespaced.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/main_namespaced.h\"\n\n#include \"stim/perf.perf.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n\nusing namespace stim;\n\nCircuit make_rep_code(uint32_t distance, uint32_t rounds) {\n    Circuit round_ops;\n    for (uint32_t k = 0; k < distance - 1; k++) {\n        round_ops.safe_append_u(\"CNOT\", {2 * k, 2 * k + 1});\n    }\n    for (uint32_t k = 0; k < distance - 1; k++) {\n        round_ops.safe_append_ua(\"DEPOLARIZE2\", {2 * k, 2 * k + 1}, 0.001);\n    }\n    for (uint32_t k = 1; k < distance; k++) {\n        round_ops.safe_append_u(\"CNOT\", {2 * k, 2 * k - 1});\n    }\n    for (uint32_t k = 1; k < distance; k++) {\n        round_ops.safe_append_ua(\"DEPOLARIZE2\", {2 * k, 2 * k - 1}, 0.001);\n    }\n    for (uint32_t k = 0; k < distance - 1; k++) {\n        round_ops.safe_append_ua(\"X_ERROR\", {2 * k + 1}, 0.001);\n    }\n    for (uint32_t k = 0; k < distance - 1; k++) {\n        round_ops.safe_append_u(\"MR\", {2 * k + 1});\n    }\n    Circuit detectors;\n    for (uint32_t k = 1; k < distance; k++) {\n        detectors.safe_append_u(\"DETECTOR\", {k | TARGET_RECORD_BIT, (k + distance - 1) | TARGET_RECORD_BIT});\n    }\n\n    Circuit result = round_ops + (round_ops + detectors) * (rounds - 1);\n    for (uint32_t k = 0; k < distance; k++) {\n        result.safe_append_ua(\"X_ERROR\", {2 * k}, 0.001);\n    }\n    for (uint32_t k = 0; k < distance; k++) {\n        result.safe_append_u(\"M\", {2 * k});\n    }\n    for (uint32_t k = 1; k < distance; k++) {\n        result.safe_append_u(\n            \"DETECTOR\", {k | TARGET_RECORD_BIT, (k + 1) | TARGET_RECORD_BIT, (k + distance) | TARGET_RECORD_BIT});\n    }\n    result.safe_append_ua(\"OBSERVABLE_INCLUDE\", {1 | TARGET_RECORD_BIT}, 0);\n    return result;\n}\n\nBENCHMARK(main_sample1_tableau_rep_d1000_r100) {\n    size_t distance = 1000;\n    size_t rounds = 100;\n    auto circuit = make_rep_code(distance, rounds);\n    FILE *in = tmpfile();\n    FILE *out = tmpfile();\n    fprintf(in, \"%s\", circuit.str().data());\n    std::mt19937_64 rng(0);  // NOLINT(cert-msc51-cpp)\n    benchmark_go([&]() {\n        rewind(in);\n        rewind(out);\n        TableauSimulator<MAX_BITWORD_WIDTH>::sample_stream(in, out, SampleFormat::SAMPLE_FORMAT_B8, false, rng);\n    })\n        .goal_millis(22)\n        .show_rate(\"Samples\", circuit.count_measurements());\n}\n\nBENCHMARK(main_sample1_pauliframe_b8_rep_d1000_r100) {\n    size_t distance = 1000;\n    size_t rounds = 100;\n    auto circuit = make_rep_code(distance, rounds);\n    FILE *out = tmpfile();\n    std::mt19937_64 rng(0);  // NOLINT(cert-msc51-cpp)\n    simd_bits<MAX_BITWORD_WIDTH> ref(0);\n    benchmark_go([&]() {\n        rewind(out);\n        sample_batch_measurements_writing_results_to_disk(circuit, ref, 1, out, SampleFormat::SAMPLE_FORMAT_B8, rng);\n    })\n        .goal_millis(9)\n        .show_rate(\"Samples\", circuit.count_measurements());\n}\n\nBENCHMARK(main_sample1_detectors_b8_rep_d1000_r100) {\n    size_t distance = 1000;\n    size_t rounds = 100;\n    auto circuit = make_rep_code(distance, rounds);\n    FILE *out = tmpfile();\n    FILE *obs_out = tmpfile();\n    std::mt19937_64 rng(0);  // NOLINT(cert-msc51-cpp)\n    simd_bits<MAX_BITWORD_WIDTH> ref(circuit.count_measurements());\n    benchmark_go([&]() {\n        rewind(out);\n        sample_batch_detection_events_writing_results_to_disk<MAX_BITWORD_WIDTH>(\n            circuit,\n            1,\n            false,\n            false,\n            out,\n            SampleFormat::SAMPLE_FORMAT_B8,\n            rng,\n            obs_out,\n            SampleFormat::SAMPLE_FORMAT_B8);\n    })\n        .goal_millis(11)\n        .show_rate(\"Samples\", circuit.count_measurements());\n}\n\nBENCHMARK(main_sample256_pauliframe_b8_rep_d1000_r100) {\n    size_t distance = 1000;\n    size_t rounds = 100;\n    auto circuit = make_rep_code(distance, rounds);\n    FILE *out = tmpfile();\n    std::mt19937_64 rng(0);  // NOLINT(cert-msc51-cpp)\n    simd_bits<MAX_BITWORD_WIDTH> ref(0);\n    benchmark_go([&]() {\n        rewind(out);\n        sample_batch_measurements_writing_results_to_disk(circuit, ref, 256, out, SampleFormat::SAMPLE_FORMAT_B8, rng);\n    })\n        .goal_millis(13)\n        .show_rate(\"Samples\", circuit.count_measurements());\n}\n\nBENCHMARK(main_sample256_pauliframe_b8_rep_d1000_r1000_stream) {\n    DebugForceResultStreamingRaii stream;\n    size_t distance = 1000;\n    size_t rounds = 1000;\n    auto circuit = make_rep_code(distance, rounds);\n    FILE *out = tmpfile();\n    std::mt19937_64 rng(0);  // NOLINT(cert-msc51-cpp)\n    simd_bits<MAX_BITWORD_WIDTH> ref(0);\n    benchmark_go([&]() {\n        rewind(out);\n        sample_batch_measurements_writing_results_to_disk(circuit, ref, 256, out, SampleFormat::SAMPLE_FORMAT_B8, rng);\n    })\n        .goal_millis(360)\n        .show_rate(\"Samples\", circuit.count_measurements());\n}\n\nBENCHMARK(main_sample256_detectors_b8_rep_d1000_r100) {\n    size_t distance = 1000;\n    size_t rounds = 100;\n    auto circuit = make_rep_code(distance, rounds);\n    FILE *out = tmpfile();\n    FILE *obs_out = tmpfile();\n    std::mt19937_64 rng(0);  // NOLINT(cert-msc51-cpp)\n    simd_bits<MAX_BITWORD_WIDTH> ref(0);\n    benchmark_go([&]() {\n        rewind(out);\n        sample_batch_detection_events_writing_results_to_disk<MAX_BITWORD_WIDTH>(\n            circuit,\n            256,\n            false,\n            false,\n            out,\n            SampleFormat::SAMPLE_FORMAT_B8,\n            rng,\n            obs_out,\n            SampleFormat::SAMPLE_FORMAT_B8);\n    })\n        .goal_millis(15)\n        .show_rate(\"Samples\", circuit.count_measurements());\n}\n\nBENCHMARK(main_sample256_detectors_b8_rep_d1000_r1000_stream) {\n    DebugForceResultStreamingRaii stream;\n    size_t distance = 1000;\n    size_t rounds = 1000;\n    auto circuit = make_rep_code(distance, rounds);\n    FILE *out = tmpfile();\n    FILE *obs_out = tmpfile();\n    std::mt19937_64 rng(0);  // NOLINT(cert-msc51-cpp)\n    simd_bits<MAX_BITWORD_WIDTH> ref(0);\n    benchmark_go([&]() {\n        rewind(out);\n        sample_batch_detection_events_writing_results_to_disk<MAX_BITWORD_WIDTH>(\n            circuit,\n            256,\n            false,\n            false,\n            out,\n            SampleFormat::SAMPLE_FORMAT_B8,\n            rng,\n            obs_out,\n            SampleFormat::SAMPLE_FORMAT_B8);\n    })\n        .goal_millis(360)\n        .show_rate(\"Samples\", circuit.count_measurements());\n}\n"
  },
  {
    "path": "src/stim/main_namespaced.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/main_namespaced.h\"\n\n#include <regex>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/main_namespaced.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nstd::string stim::run_captured_stim_main(std::vector<const char *> flags, std::string_view std_in_content) {\n    // Setup input.\n    RaiiTempNamedFile raii_temp_file(std_in_content);\n    flags.push_back(\"--in\");\n    flags.push_back(raii_temp_file.path.data());\n\n    return run_captured_stim_main(flags);\n}\n\nstd::string stim::run_captured_stim_main(std::vector<const char *> flags) {\n    flags.insert(flags.begin(), \"[PROGRAM_LOCATION_IGNORE]\");\n\n    // Setup output.\n    testing::internal::CaptureStdout();\n    testing::internal::CaptureStderr();\n    int result;\n    try {\n        result = stim::main(flags.size(), flags.data());\n    } catch (const std::exception &e) {\n        return \"[exception=\" + std::string(e.what()) + \"]\" + testing::internal::GetCapturedStdout() +\n               testing::internal::GetCapturedStderr();\n    }\n    std::string out = testing::internal::GetCapturedStdout();\n    std::string err = testing::internal::GetCapturedStderr();\n    if (!err.empty()) {\n        return out + \"[stderr=\" + err + \"]\";\n    }\n    if (result != EXIT_SUCCESS) {\n        return \"[exit code != EXIT_SUCCESS]\";\n    }\n\n    return out;\n}\n\nstd::string_view stim::trim(std::string_view text) {\n    size_t s = 0;\n    size_t e = text.size();\n    while (s < e && std::isspace(text[s])) {\n        s++;\n    }\n    while (s < e && std::isspace(text[e - 1])) {\n        e--;\n    }\n    return text.substr(s, e - s);\n}\n\nbool stim::matches(std::string actual, std::string pattern) {\n    // Hackily work around C++ regex not supporting multiline matching.\n    std::replace(actual.begin(), actual.end(), '\\n', 'X');\n    std::replace(pattern.begin(), pattern.end(), '\\n', 'X');\n    return std::regex_match(actual, std::regex(\"^\" + pattern + \"$\"));\n}\n\nTEST(main, help_modes) {\n    ASSERT_TRUE(matches(run_captured_stim_main({\"--help\"}), \".*Available stim commands.+\"));\n    ASSERT_TRUE(matches(run_captured_stim_main({\"help\"}), \".*Available stim commands.+\"));\n    ASSERT_TRUE(matches(run_captured_stim_main({}), \".+stderr.+No mode.+\"));\n    ASSERT_TRUE(matches(run_captured_stim_main({\"--sample\", \"--repl\"}), \".+stderr.+More than one mode.+\"));\n    ASSERT_TRUE(matches(run_captured_stim_main({\"--sample\", \"--repl\", \"--detect\"}), \".+stderr.+More than one mode.+\"));\n    ASSERT_TRUE(matches(run_captured_stim_main({\"--help\", \"dhnsahddjoidsa\"}), \".*Unrecognized.*\"));\n    ASSERT_TRUE(matches(run_captured_stim_main({\"--help\", \"H\"}), \".+Hadamard.+\"));\n    ASSERT_TRUE(matches(run_captured_stim_main({\"--help\", \"sample\"}), \".*Samples measurements from a circuit.+\"));\n}\n\nTEST(main, bad_flag) {\n    ASSERT_EQ(\n        trim(run_captured_stim_main({\"--gen\", \"--unknown\"})),\n        trim(\n            \"[stderr=\\033[31mUnrecognized command line argument --unknown for `stim gen`.\\n\"\n            \"Recognized command line arguments for `stim gen`:\\n\"\n            \"    --after_clifford_depolarization\\n\"\n            \"    --after_reset_flip_probability\\n\"\n            \"    --before_measure_flip_probability\\n\"\n            \"    --before_round_data_depolarization\\n\"\n            \"    --code\\n\"\n            \"    --distance\\n\"\n            \"    --in\\n\"\n            \"    --out\\n\"\n            \"    --rounds\\n\"\n            \"    --task\\n\"\n            \"\\033[0m]\\n\"));\n}\n"
  },
  {
    "path": "src/stim/main_namespaced.test.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_MAIN_NAMESPACED_TEST_H\n#define _STIM_MAIN_NAMESPACED_TEST_H\n\n#include <string>\n#include <vector>\n\nnamespace stim {\n\nstd::string run_captured_stim_main(std::vector<const char *> flags);\nstd::string run_captured_stim_main(std::vector<const char *> flags, std::string_view std_in_content);\nstd::string_view trim(std::string_view text);\nbool matches(std::string actual, std::string pattern);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/README.md",
    "content": "# `mem` directory\n\nThis directory contains code related to efficiently packing data into memory.\n\nFor example, it exposes `simd_bits` which manages an array of booleans that are bit-packed, padded,\nand aligned so that same-instruction-multiple-data constructs can be safely used on the bits.\n\nA key behind-the-scenes type is `simd_word`, which has different implementations depending on the\ninstructions supported by the machine architecture. In particular, includes graceful degradation from\nAVX to SSE to raw 64 bit integers.\n"
  },
  {
    "path": "src/stim/mem/bit_ref.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/bit_ref.h\"\n\nusing namespace stim;\n\nbit_ref::bit_ref(void *base, size_t init_offset)\n    : byte((uint8_t *)base + (init_offset / 8)), bit_index(init_offset & 7) {\n}\n"
  },
  {
    "path": "src/stim/mem/bit_ref.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_BIT_REF_H\n#define _STIM_MEM_BIT_REF_H\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace stim {\n\n/// A reference to a bit within a byte.\n///\n/// Conceptually behaves the same as a `bool &`, as opposed to a `bool *`. For example, the `=` operator overwrites the\n/// contents of the bit being referenced instead of changing which bit is pointed to.\n///\n/// This should behave essentially identically to the weird bit references that come out of a `std::vector<bool>`.\nstruct bit_ref {\n    uint8_t *byte;\n    uint8_t bit_index;\n\n    /// Construct a bit_ref from a pointer and a bit offset.\n    /// The offset can be larger than a word.\n    /// Automatically canonicalized so that the offset is less than 8.\n    bit_ref(void *base, size_t offset);\n\n    /// Copy assignment.\n    inline bit_ref &operator=(bool value) {\n        *byte &= ~((uint8_t)1 << bit_index);\n        *byte |= (uint8_t)value << bit_index;\n        return *this;\n    }\n    /// Copy assignment.\n    inline bit_ref &operator=(const bit_ref &value) {\n        *this = (bool)value;\n        return *this;\n    }\n    /// Xor assignment.\n    inline bit_ref &operator^=(bool value) {\n        *byte ^= (uint8_t)value << bit_index;\n        return *this;\n    }\n    /// Bitwise-and assignment.\n    inline bit_ref &operator&=(bool value) {\n        *byte &= ((uint8_t)value << bit_index) | ~(1 << bit_index);\n        return *this;\n    }\n    /// Bitwise-or assignment.\n    inline bit_ref &operator|=(bool value) {\n        *byte |= (uint8_t)value << bit_index;\n        return *this;\n    }\n    /// Swap assignment.\n    inline void swap_with(bit_ref other) {\n        bool b = (bool)other;\n        other = (bool)*this;\n        *this = b;\n    }\n\n    /// Implicit conversion to bool.\n    inline operator bool() const {  // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)\n        return (*byte >> bit_index) & 1;\n    }\n};\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/bit_ref.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/bit_ref.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(bit_ref, get) {\n    uint64_t word = 0;\n    bit_ref b(&word, 5);\n    ASSERT_EQ(b, false);\n    word = 1;\n    ASSERT_EQ(b, false);\n    word = 32;\n    ASSERT_EQ(b, true);\n}\n\nTEST(bit_ref, set) {\n    uint64_t word = 0;\n    bit_ref b(&word, 5);\n    word = UINT64_MAX;\n    b = false;\n    ASSERT_EQ(word, UINT64_MAX - 32);\n}\n\nTEST(bit_ref, bit_xor) {\n    uint64_t word = 0;\n    bit_ref b2(&word, 2);\n    bit_ref b5(&word, 5);\n    b5 ^= 1;\n    ASSERT_EQ(word, 32);\n    b5 ^= 1;\n    ASSERT_EQ(word, 0);\n    b5 ^= 1;\n    ASSERT_EQ(word, 32);\n    b5 ^= 0;\n    ASSERT_EQ(word, 32);\n    b2 ^= 1;\n    ASSERT_EQ(word, 36);\n    b5 ^= 0;\n    ASSERT_EQ(word, 36);\n    b2 ^= 1;\n    ASSERT_EQ(word, 32);\n    b5 ^= 1;\n    ASSERT_EQ(word, 0);\n}\n\nTEST(bit_ref, bit_or) {\n    uint64_t word = 0;\n    bit_ref b2(&word, 2);\n    bit_ref b3(&word, 3);\n    b2 |= 0;\n    ASSERT_EQ(word, 0);\n    b2 |= 1;\n    ASSERT_EQ(word, 4);\n    b3 |= 1;\n    ASSERT_EQ(word, 12);\n    word = 0;\n    b3 |= 0;\n    ASSERT_EQ(word, 0);\n    b3 |= 1;\n    ASSERT_EQ(word, 8);\n    b3 |= 1;\n    ASSERT_EQ(word, 8);\n    b3 |= 0;\n    ASSERT_EQ(word, 8);\n}\n\nTEST(bit_ref, bit_andr) {\n    uint64_t word = 8;\n    bit_ref b2(&word, 2);\n    b2 &= 0;\n    ASSERT_EQ(word, 8);\n    b2 &= 1;\n    ASSERT_EQ(word, 8);\n    bit_ref b3(&word, 3);\n    b3 &= 1;\n    ASSERT_EQ(word, 8);\n    b3 &= 0;\n    ASSERT_EQ(word, 0);\n    b3 &= 0;\n    ASSERT_EQ(word, 0);\n    b3 &= 1;\n    ASSERT_EQ(word, 0);\n}\n\nTEST(bit_ref, swap_with) {\n    uint64_t word = 8;\n    bit_ref b3(&word, 3);\n    bit_ref b5(&word, 5);\n    b3.swap_with(b5);\n    ASSERT_EQ(word, 32);\n    b3.swap_with(b5);\n    ASSERT_EQ(word, 8);\n    word = 0;\n    b3.swap_with(b5);\n    ASSERT_EQ(word, 0);\n    word = UINT64_MAX;\n    b3.swap_with(b5);\n    ASSERT_EQ(word, UINT64_MAX);\n}\n"
  },
  {
    "path": "src/stim/mem/bitword.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_BIT_WORD_H\n#define _STIM_MEM_BIT_WORD_H\n\n#include <cstddef>\n\nnamespace stim {\n\n/// A `bitword` is a bag of bits that can be operated on in a SIMD-esque fashion\n/// by individual CPU instructions.\n///\n/// This template would not have to exist, except that different architectures and\n/// operating systems expose different interfaces between native types like\n/// uint64_t and intrinsics like __m256i. For example, in some contexts, __m256i\n/// values can be operated on by operators (e.g. you can do `a ^= b`) while in\n/// other contexts this does not work. The bitword template implementations define\n/// a common set of methods required by stim to function, so that the same code\n/// can be compiled to use 256 bit registers or 64 bit registers as appropriate.\ntemplate <size_t bit_size>\nstruct bitword;\n\ntemplate <size_t W>\ninline bool operator==(const bitword<W> &self, const bitword<W> &other) {\n    return self.to_u64_array() == other.to_u64_array();\n}\n\ntemplate <size_t W>\ninline bool operator<(const bitword<W> &self, const bitword<W> &other) {\n    auto v1 = self.to_u64_array();\n    auto v2 = other.to_u64_array();\n    for (size_t k = 0; k < v1.size(); k++) {\n        if (v1[k] != v2[k]) {\n            return v1[k] < v2[k];\n        }\n    }\n    return false;\n}\n\ntemplate <size_t W>\ninline bool operator!=(const bitword<W> &self, const bitword<W> &other) {\n    return !(self == other);\n}\n\ntemplate <size_t W>\ninline bool operator==(const bitword<W> &self, int other) {\n    return self == (bitword<W>)other;\n}\ntemplate <size_t W>\ninline bool operator!=(const bitword<W> &self, int other) {\n    return self != (bitword<W>)other;\n}\ntemplate <size_t W>\ninline bool operator==(const bitword<W> &self, uint64_t other) {\n    return self == (bitword<W>)other;\n}\ntemplate <size_t W>\ninline bool operator!=(const bitword<W> &self, uint64_t other) {\n    return self != (bitword<W>)other;\n}\ntemplate <size_t W>\ninline bool operator==(const bitword<W> &self, int64_t other) {\n    return self == (bitword<W>)other;\n}\ntemplate <size_t W>\ninline bool operator!=(const bitword<W> &self, int64_t other) {\n    return self != (bitword<W>)other;\n}\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const bitword<W> &v) {\n    out << \"bitword<\" << W << \">{\";\n    auto u = v.to_u64_array();\n    for (size_t k = 0; k < u.size(); k++) {\n        for (size_t b = 0; b < 64; b++) {\n            if ((b | k) && (b & 7) == 0) {\n                out << ' ';\n            }\n            out << \".1\"[(u[k] >> b) & 1];\n        }\n    }\n    out << '}';\n    return out;\n}\n\ntemplate <size_t W>\ninline bitword<W> operator<<(const bitword<W> &self, uint64_t offset) {\n    return self.shifted((int)offset);\n}\n\ntemplate <size_t W>\ninline bitword<W> operator>>(const bitword<W> &self, uint64_t offset) {\n    return self.shifted(-(int)offset);\n}\n\ntemplate <size_t W>\ninline bitword<W> &operator<<=(bitword<W> &self, uint64_t offset) {\n    self = (self << offset);\n    return self;\n}\n\ntemplate <size_t W>\ninline bitword<W> &operator>>=(bitword<W> &self, uint64_t offset) {\n    self = (self >> offset);\n    return self;\n}\n\ntemplate <size_t W>\ninline bitword<W> operator<<(const bitword<W> &self, int offset) {\n    return self.shifted((int)offset);\n}\n\ntemplate <size_t W>\ninline bitword<W> operator>>(const bitword<W> &self, int offset) {\n    return self.shifted(-(int)offset);\n}\n\ntemplate <size_t W>\ninline bitword<W> &operator<<=(bitword<W> &self, int offset) {\n    self = (self << offset);\n    return self;\n}\n\ntemplate <size_t W>\ninline bitword<W> &operator>>=(bitword<W> &self, int offset) {\n    self = (self >> offset);\n    return self;\n}\n\ntemplate <size_t W>\ninline bitword<W> operator&(const bitword<W> &self, int mask) {\n    return self & bitword<W>(mask);\n}\ntemplate <size_t W>\ninline bitword<W> operator&(const bitword<W> &self, uint64_t mask) {\n    return self & bitword<W>(mask);\n}\ntemplate <size_t W>\ninline bitword<W> operator&(const bitword<W> &self, int64_t mask) {\n    return self & bitword<W>(mask);\n}\ntemplate <size_t W>\ninline bitword<W> operator|(const bitword<W> &self, int mask) {\n    return self | bitword<W>(mask);\n}\ntemplate <size_t W>\ninline bitword<W> operator|(const bitword<W> &self, uint64_t mask) {\n    return self | bitword<W>(mask);\n}\ntemplate <size_t W>\ninline bitword<W> operator|(const bitword<W> &self, int64_t mask) {\n    return self | bitword<W>(mask);\n}\ntemplate <size_t W>\ninline bitword<W> operator^(const bitword<W> &self, int mask) {\n    return self ^ bitword<W>(mask);\n}\ntemplate <size_t W>\ninline bitword<W> operator^(const bitword<W> &self, uint64_t mask) {\n    return self ^ bitword<W>(mask);\n}\ntemplate <size_t W>\ninline bitword<W> operator^(const bitword<W> &self, int64_t mask) {\n    return self ^ bitword<W>(mask);\n}\n\ntemplate <size_t W>\ninline bitword<W> andnot(const bitword<W> &inv, const bitword<W> &val) {\n    return inv.andnot(val);\n}\ninline uint64_t andnot(uint64_t inv, uint64_t val) {\n    return ~inv & val;\n}\ninline uint32_t andnot(uint32_t inv, uint32_t val) {\n    return ~inv & val;\n}\ninline uint16_t andnot(uint16_t inv, uint16_t val) {\n    return ~inv & val;\n}\ninline uint8_t andnot(uint8_t inv, uint8_t val) {\n    return ~inv & val;\n}\ninline bool andnot(bool inv, bool val) {\n    return !inv && val;\n}\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/bitword_128_sse.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_SIMD_WORD_128_SSE_H\n#define _STIM_MEM_SIMD_WORD_128_SSE_H\n#ifdef __SSE2__\n\n#include <algorithm>\n#include <array>\n#include <bit>\n#include <immintrin.h>\n#include <sstream>\n#include <stdexcept>\n\n#include \"stim/mem/bitword.h\"\n\nnamespace stim {\n\n/// Implements a 128 bit bitword using SSE instructions.\ntemplate <>\nstruct bitword<128> {\n    constexpr static size_t BIT_SIZE = 128;\n    constexpr static size_t BIT_POW = 7;\n\n    union {\n        __m128i val;\n        uint8_t u8[16];\n        uint64_t u64[2];\n    };\n\n    static void *aligned_malloc(size_t bytes) {\n        return _mm_malloc(bytes, sizeof(__m128i));\n    }\n    static void aligned_free(void *ptr) {\n        _mm_free(ptr);\n    }\n\n    inline bitword() : val(__m128i{}) {\n    }\n    inline bitword(__m128i val) : val(val) {\n    }\n    inline bitword(std::array<uint64_t, 2> val) : val{_mm_set_epi64x(val[1], val[0])} {\n    }\n    inline bitword(uint64_t val) : val{_mm_set_epi64x(0, val)} {\n    }\n    inline bitword(int64_t val) : val{_mm_set_epi64x(-(val < 0), val)} {\n    }\n    inline bitword(int val) : val{_mm_set_epi64x(-(val < 0), val)} {\n    }\n\n    inline static bitword<128> tile8(uint8_t pattern) {\n        return {_mm_set1_epi8(pattern)};\n    }\n\n    inline static bitword<128> tile16(uint16_t pattern) {\n        return {_mm_set1_epi16(pattern)};\n    }\n\n    inline static bitword<128> tile32(uint32_t pattern) {\n        return {_mm_set1_epi32(pattern)};\n    }\n\n    inline static bitword<128> tile64(uint64_t pattern) {\n        return {_mm_set1_epi64x(pattern)};\n    }\n\n    inline std::array<uint64_t, 2> to_u64_array() const {\n        // I would use std::bit_cast here, but it failed to build in CI.\n\n        // I would use '_mm_extract_epi64' here, but it failed to build in CI when using `-O3`.\n        // Failures were on linux systems with gcc 12.2.0\n\n        uint64_t w0 = u64[0];\n        uint64_t w1 = u64[1];\n        return std::array<uint64_t, 2>{(uint64_t)w0, (uint64_t)w1};\n    }\n    inline operator bool() const {  // NOLINT(hicpp-explicit-conversions)\n        auto words = to_u64_array();\n        return (bool)(words[0] | words[1]);\n    }\n    inline operator int() const {  // NOLINT(hicpp-explicit-conversions)\n        return (int64_t)*this;\n    }\n    inline operator uint64_t() const {  // NOLINT(hicpp-explicit-conversions)\n        auto words = to_u64_array();\n        if (words[1]) {\n            throw std::invalid_argument(\"Too large for uint64_t\");\n        }\n        return words[0];\n    }\n    inline operator int64_t() const {  // NOLINT(hicpp-explicit-conversions)\n        auto words = to_u64_array();\n        int64_t result = (int64_t)words[0];\n        uint64_t expected = result < 0 ? (uint64_t)-1 : (uint64_t)0;\n        if (words[1] != expected) {\n            throw std::invalid_argument(\"Out of bounds of int64_t\");\n        }\n        return result;\n    }\n\n    inline bitword<128> &operator^=(const bitword<128> &other) {\n        val = _mm_xor_si128(val, other.val);\n        return *this;\n    }\n\n    inline bitword<128> &operator&=(const bitword<128> &other) {\n        val = _mm_and_si128(val, other.val);\n        return *this;\n    }\n\n    inline bitword<128> &operator|=(const bitword<128> &other) {\n        val = _mm_or_si128(val, other.val);\n        return *this;\n    }\n\n    inline bitword<128> operator^(const bitword<128> &other) const {\n        return {_mm_xor_si128(val, other.val)};\n    }\n\n    inline bitword<128> operator&(const bitword<128> &other) const {\n        return {_mm_and_si128(val, other.val)};\n    }\n\n    inline bitword<128> operator|(const bitword<128> &other) const {\n        return {_mm_or_si128(val, other.val)};\n    }\n\n    inline bitword<128> andnot(const bitword<128> &other) const {\n        return {_mm_andnot_si128(val, other.val)};\n    }\n\n    inline bitword<128> operator~() const {\n        return {_mm_xor_si128(val, _mm_set1_epi8(-1))};\n    }\n\n    inline uint16_t popcount() const {\n        auto words = to_u64_array();\n        return std::popcount(words[0]) + std::popcount(words[1]);\n    }\n\n    inline bitword<128> shifted(int offset) const {\n        auto w = to_u64_array();\n        while (offset <= -64) {\n            w[0] = w[1];\n            w[1] = 0;\n            offset += 64;\n        }\n        while (offset >= 64) {\n            w[1] = w[0];\n            w[0] = 0;\n            offset -= 64;\n        }\n        __m128i low2high;\n        __m128i high2low;\n        if (offset < 0) {\n            low2high = _mm_set_epi64x(0, w[1]);\n            high2low = _mm_set_epi64x(w[1], w[0]);\n            offset += 64;\n        } else {\n            low2high = _mm_set_epi64x(w[1], w[0]);\n            high2low = _mm_set_epi64x(w[0], 0);\n        }\n        uint64_t m = (uint64_t{1} << offset) - uint64_t{1};\n        low2high = _mm_slli_epi64(low2high, offset);\n        high2low = _mm_srli_epi64(high2low, 64 - offset);\n        low2high = _mm_and_si128(low2high, _mm_set1_epi64x(~m));\n        high2low = _mm_and_si128(high2low, _mm_set1_epi64x(m));\n        return _mm_or_si128(low2high, high2low);\n    }\n\n    inline std::string str() const {\n        std::stringstream out;\n        out << *this;\n        return out.str();\n    }\n\n    template <uint64_t shift>\n    static void inplace_transpose_block_pass(bitword<128> *data, size_t stride, __m128i mask) {\n        for (size_t k = 0; k < 128; k++) {\n            if (k & shift) {\n                continue;\n            }\n            bitword<128> &x = data[stride * k];\n            bitword<128> &y = data[stride * (k + shift)];\n            bitword<128> a = x & mask;\n            bitword<128> b = _mm_andnot_si128(mask, x.val);\n            bitword<128> c = y & mask;\n            bitword<128> d = _mm_andnot_si128(mask, y.val);\n            x = a | bitword<128>(_mm_slli_epi64(c.val, shift));\n            y = bitword<128>(_mm_srli_epi64(b.val, shift)) | d;\n        }\n    }\n\n    static void inplace_transpose_block_pass64(bitword<128> *data, size_t stride) {\n        uint64_t *ptr = (uint64_t *)data;\n        stride <<= 1;\n        for (size_t k = 0; k < 64; k++) {\n            std::swap(ptr[stride * k + 1], ptr[stride * (k + 64)]);\n        }\n    }\n\n    static void inplace_transpose_square(bitword<128> *data, size_t stride) {\n        inplace_transpose_block_pass<1>(data, stride, _mm_set1_epi8(0x55));\n        inplace_transpose_block_pass<2>(data, stride, _mm_set1_epi8(0x33));\n        inplace_transpose_block_pass<4>(data, stride, _mm_set1_epi8(0xF));\n        inplace_transpose_block_pass<8>(data, stride, _mm_set1_epi16(0xFF));\n        inplace_transpose_block_pass<16>(data, stride, _mm_set1_epi32(0xFFFF));\n        inplace_transpose_block_pass<32>(data, stride, _mm_set1_epi64x(0xFFFFFFFF));\n        inplace_transpose_block_pass64(data, stride);\n    }\n};\n\n}  // namespace stim\n\n#endif\n#endif\n"
  },
  {
    "path": "src/stim/mem/bitword_256_avx.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_SIMD_WORD_256_AVX_H\n#define _STIM_MEM_SIMD_WORD_256_AVX_H\n#if __AVX2__\n\n#include <array>\n#include <bit>\n#include <immintrin.h>\n#include <sstream>\n#include <stdexcept>\n\n#include \"stim/mem/bitword.h\"\n\nnamespace stim {\n\n/// Implements a 256 bit bitword using AVX instructions.\ntemplate <>\nstruct bitword<256> {\n    constexpr static size_t BIT_SIZE = 256;\n    constexpr static size_t BIT_POW = 8;\n\n    union {\n        __m256i val;\n        uint8_t u8[32];\n    };\n\n    static void *aligned_malloc(size_t bytes) {\n        return _mm_malloc(bytes, sizeof(__m256i));\n    }\n    static void aligned_free(void *ptr) {\n        _mm_free(ptr);\n    }\n\n    inline bitword() : val(__m256i{}) {\n    }\n    inline bitword(__m256i val) : val(val) {\n    }\n    inline bitword(std::array<uint64_t, 4> val) : val{_mm256_set_epi64x(val[3], val[2], val[1], val[0])} {\n    }\n    inline bitword(uint64_t val) : val{_mm256_set_epi64x(0, 0, 0, val)} {\n    }\n    inline bitword(int64_t val) : val{_mm256_set_epi64x(-(val < 0), -(val < 0), -(val < 0), val)} {\n    }\n    inline bitword(int val) : val{_mm256_set_epi64x(-(val < 0), -(val < 0), -(val < 0), val)} {\n    }\n\n    inline static bitword<256> tile8(uint8_t pattern) {\n        return {_mm256_set1_epi8(pattern)};\n    }\n\n    inline static bitword<256> tile16(uint16_t pattern) {\n        return {_mm256_set1_epi16(pattern)};\n    }\n\n    inline static bitword<256> tile32(uint32_t pattern) {\n        return {_mm256_set1_epi32(pattern)};\n    }\n\n    inline static bitword<256> tile64(uint64_t pattern) {\n        return {_mm256_set1_epi64x(pattern)};\n    }\n\n    inline std::array<uint64_t, 4> to_u64_array() const {\n        return std::array<uint64_t, 4>{\n            (uint64_t)_mm256_extract_epi64(val, 0),\n            (uint64_t)_mm256_extract_epi64(val, 1),\n            (uint64_t)_mm256_extract_epi64(val, 2),\n            (uint64_t)_mm256_extract_epi64(val, 3),\n        };\n    }\n\n    inline operator bool() const {  // NOLINT(hicpp-explicit-conversions)\n        auto words = to_u64_array();\n        return (bool)(words[0] | words[1] | words[2] | words[3]);\n    }\n    inline operator int() const {  // NOLINT(hicpp-explicit-conversions)\n        return (int64_t)*this;\n    }\n    inline operator uint64_t() const {  // NOLINT(hicpp-explicit-conversions)\n        auto words = to_u64_array();\n        if (words[1] || words[2] || words[3]) {\n            throw std::invalid_argument(\"Too large for uint64_t\");\n        }\n        return words[0];\n    }\n    inline operator int64_t() const {  // NOLINT(hicpp-explicit-conversions)\n        auto words = to_u64_array();\n        int64_t result = (int64_t)words[0];\n        uint64_t expected = result < 0 ? (uint64_t)-1 : (uint64_t)0;\n        if (words[1] != expected || words[2] != expected || words[3] != expected) {\n            throw std::invalid_argument(\"Out of bounds of int64_t\");\n        }\n        return result;\n    }\n\n    inline bitword<256> &operator^=(const bitword<256> &other) {\n        val = _mm256_xor_si256(val, other.val);\n        return *this;\n    }\n\n    inline bitword<256> &operator&=(const bitword<256> &other) {\n        val = _mm256_and_si256(val, other.val);\n        return *this;\n    }\n\n    inline bitword<256> &operator|=(const bitword<256> &other) {\n        val = _mm256_or_si256(val, other.val);\n        return *this;\n    }\n\n    inline bitword<256> operator^(const bitword<256> &other) const {\n        return {_mm256_xor_si256(val, other.val)};\n    }\n\n    inline bitword<256> operator&(const bitword<256> &other) const {\n        return {_mm256_and_si256(val, other.val)};\n    }\n\n    inline bitword<256> operator|(const bitword<256> &other) const {\n        return {_mm256_or_si256(val, other.val)};\n    }\n\n    inline bitword<256> andnot(const bitword<256> &other) const {\n        return {_mm256_andnot_si256(val, other.val)};\n    }\n\n    inline bitword<256> operator~() const {\n        return {_mm256_xor_si256(val, _mm256_set1_epi8(-1))};\n    }\n\n    inline uint16_t popcount() const {\n        auto v = to_u64_array();\n        return std::popcount(v[0]) + std::popcount(v[1]) + std::popcount(v[2]) + (uint16_t)std::popcount(v[3]);\n    }\n\n    inline bitword<256> shifted(int offset) const {\n        auto w = to_u64_array();\n        while (offset <= -64) {\n            w[0] = w[1];\n            w[1] = w[2];\n            w[2] = w[3];\n            w[3] = 0;\n            offset += 64;\n        }\n        while (offset >= 64) {\n            w[3] = w[2];\n            w[2] = w[1];\n            w[1] = w[0];\n            w[0] = 0;\n            offset -= 64;\n        }\n        __m256i low2high;\n        __m256i high2low;\n        if (offset < 0) {\n            low2high = _mm256_set_epi64x(0, w[3], w[2], w[1]);\n            high2low = _mm256_set_epi64x(w[3], w[2], w[1], w[0]);\n            offset += 64;\n        } else {\n            low2high = _mm256_set_epi64x(w[3], w[2], w[1], w[0]);\n            high2low = _mm256_set_epi64x(w[2], w[1], w[0], 0);\n        }\n        uint64_t m = (uint64_t{1} << offset) - uint64_t{1};\n        low2high = _mm256_slli_epi64(low2high, offset);\n        high2low = _mm256_srli_epi64(high2low, 64 - offset);\n        low2high = _mm256_and_si256(low2high, _mm256_set1_epi64x(~m));\n        high2low = _mm256_and_si256(high2low, _mm256_set1_epi64x(m));\n        return _mm256_or_si256(low2high, high2low);\n    }\n\n    inline std::string str() const {\n        std::stringstream out;\n        out << *this;\n        return out.str();\n    }\n\n    inline bool operator==(const bitword<256> &other) const {\n        return to_u64_array() == other.to_u64_array();\n    }\n    inline bool operator!=(const bitword<256> &other) const {\n        return !(*this == other);\n    }\n    inline bool operator==(int other) const {\n        return *this == (bitword<256>)other;\n    }\n    inline bool operator!=(int other) const {\n        return *this != (bitword<256>)other;\n    }\n    inline bool operator==(uint64_t other) const {\n        return *this == (bitword<256>)other;\n    }\n    inline bool operator!=(uint64_t other) const {\n        return *this != (bitword<256>)other;\n    }\n    inline bool operator==(int64_t other) const {\n        return *this == (bitword<256>)other;\n    }\n    inline bool operator!=(int64_t other) const {\n        return *this != (bitword<256>)other;\n    }\n\n    template <uint64_t shift>\n    static void inplace_transpose_block_pass(bitword<256> *data, size_t stride, __m256i mask) {\n        for (size_t k = 0; k < 256; k++) {\n            if (k & shift) {\n                continue;\n            }\n            bitword<256> &x = data[stride * k];\n            bitword<256> &y = data[stride * (k + shift)];\n            bitword<256> a = x & mask;\n            bitword<256> b = _mm256_andnot_si256(mask, x.val);\n            bitword<256> c = y & mask;\n            bitword<256> d = _mm256_andnot_si256(mask, y.val);\n            x = a | bitword<256>(_mm256_slli_epi64(c.val, shift));\n            y = bitword<256>(_mm256_srli_epi64(b.val, shift)) | d;\n        }\n    }\n\n    static void inplace_transpose_block_pass_64_and_128(bitword<256> *data, size_t stride) {\n        uint64_t *ptr = (uint64_t *)data;\n        stride <<= 2;\n\n        for (size_t k = 0; k < 64; k++) {\n            std::swap(ptr[stride * (k + 64 * 0) + 1], ptr[stride * (k + 64 * 1) + 0]);\n            std::swap(ptr[stride * (k + 64 * 0) + 2], ptr[stride * (k + 64 * 2) + 0]);\n            std::swap(ptr[stride * (k + 64 * 0) + 3], ptr[stride * (k + 64 * 3) + 0]);\n            std::swap(ptr[stride * (k + 64 * 1) + 2], ptr[stride * (k + 64 * 2) + 1]);\n            std::swap(ptr[stride * (k + 64 * 1) + 3], ptr[stride * (k + 64 * 3) + 1]);\n            std::swap(ptr[stride * (k + 64 * 2) + 3], ptr[stride * (k + 64 * 3) + 2]);\n        }\n    }\n\n    static void inplace_transpose_square(bitword<256> *data, size_t stride) {\n        inplace_transpose_block_pass<1>(data, stride, _mm256_set1_epi8(0x55));\n        inplace_transpose_block_pass<2>(data, stride, _mm256_set1_epi8(0x33));\n        inplace_transpose_block_pass<4>(data, stride, _mm256_set1_epi8(0xF));\n        inplace_transpose_block_pass<8>(data, stride, _mm256_set1_epi16(0xFF));\n        inplace_transpose_block_pass<16>(data, stride, _mm256_set1_epi32(0xFFFF));\n        inplace_transpose_block_pass<32>(data, stride, _mm256_set1_epi64x(0xFFFFFFFF));\n        inplace_transpose_block_pass_64_and_128(data, stride);\n    }\n};\n\n}  // namespace stim\n\n#endif\n#endif\n"
  },
  {
    "path": "src/stim/mem/bitword_64.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_SIMD_WORD_64_STD_H\n#define _STIM_MEM_SIMD_WORD_64_STD_H\n\n#include <array>\n#include <bit>\n#include <sstream>\n#include <stdlib.h>\n\n#include \"stim/mem/bitword.h\"\n#include \"stim/mem/simd_util.h\"\n\nnamespace stim {\n\n/// Implements a 64 bit bitword using no architecture-specific instructions, just standard C++.\ntemplate <>\nstruct bitword<64> {\n    constexpr static size_t BIT_SIZE = 64;\n    constexpr static size_t BIT_POW = 6;\n\n    union {\n        uint64_t val;\n        uint8_t u8[8];\n    };\n\n    static void *aligned_malloc(size_t bytes) {\n        return malloc(bytes);\n    }\n    static void aligned_free(void *ptr) {\n        free(ptr);\n    }\n\n    inline constexpr bitword() : val{} {\n    }\n    inline bitword(std::array<uint64_t, 1> val) : val{val[0]} {\n    }\n    inline constexpr bitword(uint64_t v) : val{v} {\n    }\n    inline constexpr bitword(int64_t v) : val{(uint64_t)v} {\n    }\n    inline constexpr bitword(int v) : val{(uint64_t)v} {\n    }\n\n    constexpr inline static bitword<64> tile64(uint64_t pattern) {\n        return bitword<64>(pattern);\n    }\n\n    constexpr inline static bitword<64> tile8(uint8_t pattern) {\n        return bitword<64>(tile64_helper(pattern, 8));\n    }\n\n    inline std::array<uint64_t, 1> to_u64_array() const {\n        return std::array<uint64_t, 1>{val};\n    }\n    inline operator bool() const {  // NOLINT(hicpp-explicit-conversions)\n        return (bool)(val);\n    }\n    inline operator int() const {  // NOLINT(hicpp-explicit-conversions)\n        return (int)val;\n    }\n    inline operator uint64_t() const {  // NOLINT(hicpp-explicit-conversions)\n        return val;\n    }\n    inline operator int64_t() const {  // NOLINT(hicpp-explicit-conversions)\n        return (int64_t)val;\n    }\n\n    inline bitword<64> &operator^=(const bitword<64> &other) {\n        val ^= other.val;\n        return *this;\n    }\n\n    inline bitword<64> &operator&=(const bitword<64> &other) {\n        val &= other.val;\n        return *this;\n    }\n\n    inline bitword<64> &operator|=(const bitword<64> &other) {\n        val |= other.val;\n        return *this;\n    }\n\n    inline bitword<64> operator^(const bitword<64> &other) const {\n        return bitword<64>(val ^ other.val);\n    }\n\n    inline bitword<64> operator&(const bitword<64> &other) const {\n        return bitword<64>(val & other.val);\n    }\n\n    inline bitword<64> operator|(const bitword<64> &other) const {\n        return bitword<64>(val | other.val);\n    }\n\n    inline bitword<64> andnot(const bitword<64> &other) const {\n        return bitword<64>(~val & other.val);\n    }\n\n    inline bitword<64> operator~() const {\n        return {~val};\n    }\n\n    inline uint16_t popcount() const {\n        return std::popcount(val);\n    }\n\n    inline std::string str() const {\n        std::stringstream out;\n        out << *this;\n        return out.str();\n    }\n\n    inline bitword<64> shifted(int offset) const {\n        uint64_t v = val;\n        if (offset >= 64 || offset <= -64) {\n            v = 0;\n        } else if (offset > 0) {\n            v <<= offset;\n        } else {\n            v >>= -offset;\n        }\n        return bitword<64>{v};\n    }\n\n    static void inplace_transpose_square(bitword<64> *data_block, size_t stride) {\n        inplace_transpose_64x64((uint64_t *)data_block, stride);\n    }\n};\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/fixed_cap_vector.h",
    "content": "#ifndef _STIM_MEM_FIXED_CAP_VECTOR_H\n#define _STIM_MEM_FIXED_CAP_VECTOR_H\n\n#include <array>\n#include <cstddef>\n#include <sstream>\n#include <stdexcept>\n\nnamespace stim {\n\n/// A vector with a variable number of items but a fixed size backing array.\ntemplate <typename T, size_t max_size>\nclass FixedCapVector {\n    std::array<T, max_size> data;\n    size_t num_used;\n\n   public:\n    FixedCapVector() : num_used(0) {};\n    FixedCapVector(std::initializer_list<T> list) : num_used(0) {\n        if (list.size() > max_size) {\n            throw std::out_of_range(\"list.size() > max_size\");\n        }\n        for (auto &e : list) {\n            push_back(std::move(e));\n        }\n    }\n\n    T &operator[](size_t index) {\n        return data[index];\n    }\n\n    const T &operator[](size_t index) const {\n        return data[index];\n    }\n\n    const T &front() const {\n        if (num_used == 0) {\n            throw std::out_of_range(\"Empty.\");\n        }\n        return data[0];\n    }\n    const T &back() const {\n        if (num_used == 0) {\n            throw std::out_of_range(\"Empty.\");\n        }\n        return data[num_used - 1];\n    }\n    T &front() {\n        if (num_used == 0) {\n            throw std::out_of_range(\"Empty.\");\n        }\n        return data[0];\n    }\n    T &back() {\n        if (num_used == 0) {\n            throw std::out_of_range(\"Empty.\");\n        }\n        return data[num_used - 1];\n    }\n    T *begin() {\n        return &data[0];\n    }\n    T *end() {\n        return &data[0] + num_used;\n    }\n    const T *end() const {\n        return &data[0] + num_used;\n    }\n    const T *begin() const {\n        return &data[0];\n    }\n    size_t size() const {\n        return num_used;\n    }\n    bool empty() const {\n        return num_used == 0;\n    }\n    T *find(const T &item) {\n        auto p = begin();\n        while (p != end()) {\n            if (*p == item) {\n                break;\n            }\n            p++;\n        }\n        return p;\n    }\n    const T *find(const T &item) const {\n        auto p = begin();\n        while (p != end()) {\n            if (*p == item) {\n                break;\n            }\n            p++;\n        }\n        return p;\n    }\n\n    void clear() {\n        num_used = 0;\n    }\n\n    void push_back(const T &item) {\n        if (num_used == data.size()) {\n            throw std::out_of_range(\"CappedVector capacity exceeded.\");\n        }\n        data[num_used] = item;\n        num_used++;\n    }\n    void push_back(T &&item) {\n        if (num_used == data.size()) {\n            throw std::out_of_range(\"CappedVector capacity exceeded.\");\n        }\n        data[num_used] = std::move(item);\n        num_used++;\n    }\n    void pop_back() {\n        if (num_used == 0) {\n            throw std::out_of_range(\"Popped empty CappedVector.\");\n        }\n        num_used -= 1;\n    }\n    bool operator==(const FixedCapVector<T, max_size> &other) const {\n        if (num_used != other.num_used) {\n            return false;\n        }\n        for (size_t k = 0; k < num_used; k++) {\n            if (data[k] != other.data[k]) {\n                return false;\n            }\n        }\n        return true;\n    }\n    bool operator!=(const FixedCapVector<T, max_size> &other) const {\n        return !(*this == other);\n    }\n    bool operator<(const FixedCapVector<T, max_size> &other) const {\n        if (num_used != other.num_used) {\n            return num_used < other.num_used;\n        }\n        for (size_t k = 0; k < num_used; k++) {\n            if (data[k] != other.data[k]) {\n                return data[k] < other.data[k];\n            }\n        }\n        return false;\n    }\n\n    std::string str() const {\n        std::stringstream ss;\n        ss << *this;\n        return ss.str();\n    }\n};\n\ntemplate <typename T, size_t max_size>\nstd::ostream &operator<<(std::ostream &out, const FixedCapVector<T, max_size> &v) {\n    out << \"FixedCapVector{\";\n    bool first = true;\n    for (const auto &t : v) {\n        if (first) {\n            first = false;\n        } else {\n            out << \", \";\n        }\n        out << t;\n    }\n    out << \"}\";\n    return out;\n}\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/fixed_cap_vector.test.cc",
    "content": "#include \"stim/mem/fixed_cap_vector.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(FixedCapVector, basic_usage) {\n    auto v = FixedCapVector<std::string, 5>();\n    const auto &c = v;\n\n    ASSERT_EQ(v.empty(), true);\n    ASSERT_EQ(v.size(), 0);\n    ASSERT_EQ(v.begin(), v.end());\n    ASSERT_EQ(v.find(\"x\"), v.end());\n    ASSERT_THROW({ v.front(); }, std::out_of_range);\n    ASSERT_THROW({ v.back(); }, std::out_of_range);\n    ASSERT_THROW({ c.front(); }, std::out_of_range);\n    ASSERT_THROW({ c.back(); }, std::out_of_range);\n\n    v.push_back(\"test\");\n    ASSERT_EQ(v.empty(), false);\n    ASSERT_EQ(v.size(), 1);\n    ASSERT_EQ(*v.begin(), \"test\");\n    ASSERT_EQ(v.front(), \"test\");\n    ASSERT_EQ(v.back(), \"test\");\n    ASSERT_EQ(v.begin() + 1, v.end());\n    ASSERT_EQ(v.find(\"test\"), v.begin());\n    ASSERT_EQ(v.find(\"other\"), v.end());\n    ASSERT_EQ(v[0], \"test\");\n\n    ASSERT_EQ(c.empty(), false);\n    ASSERT_EQ(c.size(), 1);\n    ASSERT_EQ(*c.begin(), \"test\");\n    ASSERT_EQ(c.front(), \"test\");\n    ASSERT_EQ(c.back(), \"test\");\n    ASSERT_EQ(c.begin() + 1, c.end());\n    ASSERT_EQ(c.find(\"test\"), c.begin());\n    ASSERT_EQ(c.find(\"other\"), c.end());\n    ASSERT_EQ(c[0], \"test\");\n\n    v.push_back(\"1\");\n    v.push_back(\"2\");\n    v.push_back(\"3\");\n    v.push_back(\"4\");\n    ASSERT_THROW({ v.push_back(\"5\"); }, std::out_of_range);\n\n    ASSERT_EQ(v.find(\"2\"), v.begin() + 2);\n\n    v[0] = \"new\";\n    ASSERT_EQ(c[0], \"new\");\n}\n\nTEST(FixedCapVector, push_pop) {\n    auto v = FixedCapVector<std::string, 5>();\n    std::string v2 = \"123\";\n\n    v.push_back(v2);\n    ASSERT_EQ(v2, \"123\");\n    ASSERT_EQ(v, (FixedCapVector<std::string, 5>{\"123\"}));\n\n    v2.push_back('4');\n    v.push_back(std::move(v2));\n    ASSERT_EQ(v2, \"\");\n    ASSERT_EQ(\n        v,\n        (FixedCapVector<std::string, 5>{\n            \"123\",\n            \"1234\",\n        }));\n\n    v.pop_back();\n    ASSERT_EQ(\n        v,\n        (FixedCapVector<std::string, 5>{\n            \"123\",\n        }));\n\n    v.pop_back();\n    ASSERT_EQ(v, (FixedCapVector<std::string, 5>{}));\n\n    ASSERT_THROW({ v.pop_back(); }, std::out_of_range);\n}\n\nTEST(FixedCapVector, ordering) {\n    auto v123 = FixedCapVector<int, 3>{1, 2, 3};\n    auto v12 = FixedCapVector<int, 3>{1, 2};\n    auto w12 = FixedCapVector<int, 3>{1, 2};\n    auto v423 = FixedCapVector<int, 3>{4, 2, 3};\n    ASSERT_LT(v123, v423);\n    ASSERT_LT(v12, v123);\n    ASSERT_TRUE((FixedCapVector<int, 3>{4, 2} < FixedCapVector<int, 3>{4, 2, 1}));\n    ASSERT_TRUE((FixedCapVector<int, 3>{4, 2, 0} < FixedCapVector<int, 3>{4, 2, 1}));\n    ASSERT_FALSE((FixedCapVector<int, 3>{4, 2, 2} < FixedCapVector<int, 3>{4, 2, 1}));\n    ASSERT_TRUE((FixedCapVector<int, 3>{4, 1, 2} < FixedCapVector<int, 3>{4, 2, 1}));\n    ASSERT_FALSE((FixedCapVector<int, 3>{4, 3, 2} < FixedCapVector<int, 3>{4, 2, 1}));\n    ASSERT_FALSE((FixedCapVector<int, 3>{4, 3, 1} < FixedCapVector<int, 3>{4, 2, 2}));\n    ASSERT_TRUE(v123 < v423);\n    ASSERT_FALSE(v423 < v123);\n    ASSERT_TRUE(v12 == w12);\n    ASSERT_TRUE(!(v12 != w12));\n    ASSERT_TRUE(v12 != v123);\n    ASSERT_TRUE(!(v12 == v123));\n    ASSERT_TRUE(v423 != v123);\n    ASSERT_TRUE(!(v423 == v123));\n}\n\nTEST(FixedCapVector, str) {\n    ASSERT_EQ((FixedCapVector<int, 3>{1, 2, 3}.str()), \"FixedCapVector{1, 2, 3}\");\n}\n"
  },
  {
    "path": "src/stim/mem/monotonic_buffer.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_MONOTONIC_BUFFER_H\n#define _STIM_MEM_MONOTONIC_BUFFER_H\n\n#include <cassert>\n#include <cstdlib>\n#include <iostream>\n#include <vector>\n\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\n/// A memory resource that can efficiently incrementally accumulate data.\n///\n/// There are three important types of \"region\" in play: the tail region, the current region, and old regions.\n///\n/// The tail is for contiguous data being added incrementally into the buffer.\n/// When the tail grows beyond the currently available storage, more memory is allocated and the tail is is copied into\n/// the new memory so that it can stay contiguous. At any time, the tail can be discarded or committed. Discarding the\n/// tail allows the memory it was covering to be re-used when writing the next tail. Committing the tail permanently\n/// preserves that data (until the monotonic buffer is cleared or deconstructed) and also guarantees it will no longer\n/// move so pointers to it can be stored.\n///\n/// The current region is a contiguous chunk of memory that the tail is being written into.\n/// When the tail grows beyond this region and triggers an allocation, the current region is relabelled as an old region\n/// and the newly allocated memory is now the current region. Each subsequent current region will be at least double the\n/// size of the previous one.\n///\n/// The old regions are memory that has been finalized, and will be stored until the buffer is cleared or deconstructed.\ntemplate <typename T>\nstruct MonotonicBuffer {\n    /// Contiguous memory that is being appended to, but has not yet been committed.\n    SpanRef<T> tail;\n    /// The current contiguous memory region with a mix of committed, staged, and unused memory.\n    SpanRef<T> cur;\n    /// Old contiguous memory regions that have been committed and now need to be kept.\n    std::vector<SpanRef<T>> old_areas;\n\n    /// Constructs an empty monotonic buffer.\n    MonotonicBuffer() : tail(), cur(), old_areas() {\n    }\n    /// Constructs an empty monotonic buffer with initial capacity for its current region.\n    MonotonicBuffer(size_t reserve) {\n        ensure_available(reserve);\n    }\n    void _soft_clear() {\n        cur.ptr_start = nullptr;\n        cur.ptr_end = nullptr;\n        tail.ptr_start = nullptr;\n        tail.ptr_end = nullptr;\n        old_areas.clear();\n    }\n    void _hard_clear() {\n        for (auto old : old_areas) {\n            free(old.ptr_start);\n        }\n        if (cur.ptr_start != nullptr) {\n            free(cur.ptr_start);\n        }\n    }\n    ~MonotonicBuffer() {\n        _hard_clear();\n    }\n    MonotonicBuffer(MonotonicBuffer &&other) noexcept\n        : tail(other.tail), cur(other.cur), old_areas(std::move(other.old_areas)) {\n        other._soft_clear();\n    }\n    MonotonicBuffer(const MonotonicBuffer &other) = delete;\n    MonotonicBuffer &operator=(MonotonicBuffer &&other) noexcept {\n        _hard_clear();\n        cur = other.cur;\n        tail = other.tail;\n        old_areas = std::move(other.old_areas);\n        other._soft_clear();\n        return *this;\n    }\n\n    /// Invalidates all previous data and resets the class into a clean state.\n    ///\n    /// Happens to keep the current contiguous memory region and free old regions.\n    void clear() {\n        for (auto old : old_areas) {\n            free(old.ptr_start);\n        }\n        old_areas.clear();\n        tail.ptr_end = tail.ptr_start = cur.ptr_start;\n    }\n\n    /// Returns the size of memory allocated and held by this monotonic buffer (in units of sizeof(T)).\n    size_t total_allocated() const {\n        size_t result = cur.size();\n        for (auto old : old_areas) {\n            result += old.size();\n        }\n        return result;\n    }\n\n    /// Appends and commits data.\n    /// Requires the tail to be empty, to avoid bugs where previously staged data is committed.\n    std::span<T> take_copy(std::span<const T> data) {\n        assert(tail.size() == 0);\n        append_tail(data);\n        return commit_tail();\n    }\n    std::string_view take_copy(std::string_view data) {\n        if (data.empty()) {\n            return std::string_view();\n        }\n        assert(tail.size() == 0);\n        append_tail(SpanRef<const char>(&data[0], &data[0] + data.size()));\n        SpanRef<char> v = commit_tail();\n        return {v.ptr_start, v.size()};\n    }\n\n    /// Adds a staged data item.\n    void append_tail(T item) {\n        ensure_available(1);\n        *tail.ptr_end = item;\n        tail.ptr_end++;\n    }\n\n    /// Adds staged data.\n    void append_tail(SpanRef<const T> data) {\n        ensure_available(data.size());\n        std::copy(data.begin(), data.end(), tail.ptr_end);\n        tail.ptr_end += data.size();\n    }\n\n    /// Throws away staged data, so its memory can be re-used.\n    void discard_tail() {\n        tail.ptr_end = tail.ptr_start;\n    }\n\n    /// Changes staged data into committed data that will be kept until the buffer is cleared or deconstructed.\n    SpanRef<T> commit_tail() {\n        SpanRef<T> result(tail);\n        tail.ptr_start = tail.ptr_end;\n        return result;\n    }\n\n    /// Ensures it is possible to stage at least `min_required` more items without more reallocations.\n    void ensure_available(size_t min_required) {\n        size_t available = cur.ptr_end - tail.ptr_end;\n        if (available >= min_required) {\n            return;\n        }\n\n        size_t alloc_count = std::max(min_required + tail.size(), cur.size() << 1);\n        if (cur.ptr_start != nullptr) {\n            old_areas.push_back(cur);\n        }\n        cur.ptr_start = (T *)malloc(alloc_count * sizeof(T));\n        cur.ptr_end = cur.ptr_start + alloc_count;\n\n        // Staged data is not complete yet; keep it contiguous by copying it to the new larger memory region.\n        size_t tail_size = tail.size();\n        if (tail_size) {\n            std::move(tail.ptr_start, tail.ptr_end, cur.ptr_start);\n        }\n\n        tail = {cur.ptr_start, cur.ptr_start + tail_size};\n    }\n};\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/monotonic_buffer.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/monotonic_buffer.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(pointer_range, equality) {\n    int data[100]{};\n    SpanRef<int> r1{&data[0], &data[10]};\n    SpanRef<int> r2{&data[10], &data[20]};\n    SpanRef<int> r4{&data[30], &data[50]};\n    ASSERT_TRUE(r1 == r2);\n    ASSERT_FALSE(r1 != r2);\n    ASSERT_EQ(r1, r2);\n    ASSERT_NE(r1, r4);\n    r2[0] = 1;\n    ASSERT_EQ(data[10], 1);\n    ASSERT_NE(r1, r2);\n    ASSERT_TRUE(r1 != r2);\n    ASSERT_FALSE(r1 == r2);\n    ASSERT_NE(r1, r4);\n    r2[0] = 0;\n    ASSERT_EQ(r1, r2);\n    r2[6] = 1;\n    ASSERT_NE(r1, r2);\n}\n\nTEST(monotonic_buffer, append_tail) {\n    MonotonicBuffer<int> buf;\n    for (size_t k = 0; k < 100; k++) {\n        buf.append_tail(k);\n    }\n\n    SpanRef<int> rng = buf.commit_tail();\n    ASSERT_EQ(rng.size(), 100);\n    for (size_t k = 0; k < 100; k++) {\n        ASSERT_EQ(rng[k], k);\n    }\n}\n\nTEST(monotonic_buffer, ensure_available) {\n    MonotonicBuffer<int> buf;\n    buf.append_tail(std::vector<int>{1, 2, 3, 4});\n    buf.append_tail(std::vector<int>{5, 6});\n    buf.append_tail(std::vector<int>{7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9});\n\n    SpanRef<const int> rng = buf.commit_tail();\n    std::vector<int> expected{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    SpanRef<const int> v = expected;\n    ASSERT_EQ(rng, v);\n}\n"
  },
  {
    "path": "src/stim/mem/simd_bit_table.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_SIMD_BIT_TABLE_H\n#define _STIM_MEM_SIMD_BIT_TABLE_H\n\n#include \"stim/mem/simd_bits.h\"\n\nnamespace stim {\n\n/// A 2d array of bit-packed booleans, padded and aligned to make simd operations more efficient.\n///\n/// The table contents are indexed by a major axis (not contiguous in memory) then a minor axis (contiguous in memory).\n///\n/// Note that, due to the padding, the smallest table you can have is 256x256 bits (8 KiB).\n/// Technically the padding of the major axis is not necessary, but it's included so that transposing preserves size.\n///\n/// Similar to simd_bits, simd_bit_table has no notion of the \"intended\" size of data, only the padded size. The\n/// intended size has to be stored separately.\ntemplate <size_t W>\nstruct simd_bit_table {\n    size_t num_simd_words_major;\n    size_t num_simd_words_minor;\n    simd_bits<W> data;\n\n    /// Creates zero initialized table.\n    simd_bit_table(size_t min_bits_major, size_t min_bits_minor);\n    /// Creates a randomly initialized table.\n    static simd_bit_table random(\n        size_t num_randomized_major_bits, size_t num_randomized_minor_bits, std::mt19937_64 &rng);\n    /// Creates a square table with 1s down the diagonal.\n    static simd_bit_table identity(size_t n);\n    /// Concatenates tables together to form a larger table.\n    static simd_bit_table from_quadrants(\n        size_t n,\n        const simd_bit_table &upper_left,\n        const simd_bit_table &upper_right,\n        const simd_bit_table &lower_left,\n        const simd_bit_table &lower_right);\n    /// Parses a bit table from some text.\n    ///\n    /// Args:\n    ///     text: A paragraph of characters specifying the contents of a bit table.\n    ///         Each line is a row (a major index) of the table.\n    ///         Each position within a line is a column (a minor index) of the table.\n    ///         A '1' at character C of line L (counting from 0) indicates out[L][C] will be set.\n    ///         A '0', '.', or '_' indicates out[L][C] will not be set.\n    ///         Leading newlines and spaces at the beginning of the text are ignored.\n    ///         Leading spaces at the beginning of a line are ignored.\n    ///         Other characters result in errors.\n    ///\n    /// Returns:\n    ///     A simd_bit_table with cell contents corresponding to the text.\n    static simd_bit_table from_text(const char *text, size_t min_rows = 0, size_t min_cols = 0);\n\n    /// Resizes the table. Doesn't clear to zero. Does nothing if already the target size.\n    void destructive_resize(size_t new_min_bits_major, size_t new_min_bits_minor);\n\n    /// Copies the table into another table.\n    ///\n    /// It's safe for the other table to have a different size.\n    /// When the other table has a different size, only the data at locations common to both\n    /// tables are copied over.\n    void copy_into_different_size_table(simd_bit_table<W> &other) const;\n\n    /// Resizes the table, keeping any data common to the old and new size and otherwise zeroing data.\n    void resize(size_t new_min_bits_major, size_t new_min_bits_minor);\n\n    /// Equality.\n    bool operator==(const simd_bit_table &other) const;\n    /// Inequality.\n    bool operator!=(const simd_bit_table &other) const;\n\n    /// Returns a reference to a row (column) of the table, when using row (column) major indexing.\n    inline simd_bits_range_ref<W> operator[](size_t major_index) {\n        return data.word_range_ref(major_index * num_simd_words_minor, num_simd_words_minor);\n    }\n    /// Returns a const reference to a row (column) of the table, when using row (column) major indexing.\n    inline const simd_bits_range_ref<W> operator[](size_t major_index) const {\n        return data.word_range_ref(major_index * num_simd_words_minor, num_simd_words_minor);\n    }\n    /// operator[] lets us extract a specified bit as (*this)[major_index][minor_index].\n    /// We can decompose these indicies as\n    /// major_index = (major_index_high << bitword<W>::BIT_POW) + major_index_low\n    /// minor_index = (minor_index_high << bitword<W>::BIT_POW) + minor_index_low\n    /// As minor_index_low ranges from 0 to W-1, (*this)[major_index][minor_index] ranges over the\n    /// bits of an aligned SIMD word. get_index_of_bitword returns the index in data.ptr_simd of\n    /// the corresponding simd word.\n    inline size_t get_index_of_bitword(size_t major_index_high, size_t major_index_low, size_t minor_index_high) const {\n        size_t major_index = (major_index_high << bitword<W>::BIT_POW) + major_index_low;\n        return major_index * num_simd_words_minor + minor_index_high;\n    }\n\n    /// Square matrix multiplication (assumes row major indexing). n is the diameter of the matrix.\n    simd_bit_table square_mat_mul(const simd_bit_table &rhs, size_t n) const;\n    /// Square matrix inverse, assuming input is lower triangular. n is the diameter of the matrix.\n    simd_bit_table inverse_assuming_lower_triangular(size_t n) const;\n    /// Transposes the table inplace.\n    void do_square_transpose();\n    /// Transposes the table out of place into a target location.\n    void transpose_into(simd_bit_table &out) const;\n    /// Transposes the table out of place.\n    simd_bit_table transposed() const;\n    /// Returns a subset of the table.\n    simd_bit_table slice_maj(size_t maj_start_bit, size_t maj_stop_bit) const;\n\n    /// Returns a copy of a column of the table.\n    simd_bits<W> read_across_majors_at_minor_index(size_t major_start, size_t major_stop, size_t minor_index) const;\n\n    /// Concatenates the contents of the two tables, along the major axis.\n    simd_bit_table<W> concat_major(const simd_bit_table<W> &second, size_t n_first, size_t n_second) const;\n    /// Overwrites a range of the table with a range from another table with the same minor size.\n    void overwrite_major_range_with(\n        size_t dst_major_start, const simd_bit_table<W> &src, size_t src_major_start, size_t num_major_indices) const;\n\n    /// Sets all bits in the table to zero.\n    void clear();\n\n    /// Number of 64 bit words in a column (row) assuming row (column) major indexing.\n    inline size_t num_major_u64_padded() const {\n        return num_simd_words_major * (sizeof(bitword<W>) / sizeof(uint64_t));\n    }\n    /// Number of 32 bit words in a column (row) assuming row (column) major indexing.\n    inline size_t num_major_u32_padded() const {\n        return num_simd_words_major * (sizeof(bitword<W>) / sizeof(uint32_t));\n    }\n    /// Number of 16 bit words in a column (row) assuming row (column) major indexing.\n    inline size_t num_major_u16_padded() const {\n        return num_simd_words_major * (sizeof(bitword<W>) / sizeof(uint16_t));\n    }\n    /// Number of 8 bit words in a column (row) assuming row (column) major indexing.\n    inline size_t num_major_u8_padded() const {\n        return num_simd_words_major * (sizeof(bitword<W>) / sizeof(uint8_t));\n    }\n    /// Number of bits in a column (row) assuming row (column) major indexing.\n    inline size_t num_major_bits_padded() const {\n        return num_simd_words_major * W;\n    }\n\n    /// Number of 64 bit words in a row (column) assuming row (column) major indexing.\n    inline size_t num_minor_u64_padded() const {\n        return num_simd_words_minor * (sizeof(bitword<W>) / sizeof(uint64_t));\n    }\n    /// Number of 32 bit words in a row (column) assuming row (column) major indexing.\n    inline size_t num_minor_u32_padded() const {\n        return num_simd_words_minor * (sizeof(bitword<W>) / sizeof(uint32_t));\n    }\n    /// Number of 16 bit words in a row (column) assuming row (column) major indexing.\n    inline size_t num_minor_u16_padded() const {\n        return num_simd_words_minor * (sizeof(bitword<W>) / sizeof(uint16_t));\n    }\n    /// Number of 8 bit words in a row (column) assuming row (column) major indexing.\n    inline size_t num_minor_u8_padded() const {\n        return num_simd_words_minor * (sizeof(bitword<W>) / sizeof(uint8_t));\n    }\n    /// Number of bits in a row (column) assuming row (column) major indexing.\n    inline size_t num_minor_bits_padded() const {\n        return num_simd_words_minor * W;\n    }\n\n    /// Returns a padded description of the table's contents.\n    std::string str() const;\n    /// Returns a truncated square description of the table's contents.\n    std::string str(size_t n) const;\n    /// Returns a truncated rectangle description of the table's contents.\n    std::string str(size_t rows, size_t cols) const;\n};\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const simd_bit_table<W> &v);\n\nconstexpr uint8_t lg(size_t k) {\n    return k <= 1 ? 0 : lg(k >> 1) + 1;\n}\n\n}  // namespace stim\n\n#include \"stim/mem/simd_bit_table.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/simd_bit_table.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <algorithm>\n#include <cassert>\n#include <cstring>\n#include <sstream>\n\nnamespace stim {\n\ntemplate <size_t W>\nsimd_bit_table<W>::simd_bit_table(size_t min_bits_major, size_t min_bits_minor)\n    : num_simd_words_major(min_bits_to_num_simd_words<W>(min_bits_major)),\n      num_simd_words_minor(min_bits_to_num_simd_words<W>(min_bits_minor)),\n      data(min_bits_to_num_bits_padded<W>(min_bits_minor) * min_bits_to_num_bits_padded<W>(min_bits_major)) {\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> simd_bit_table<W>::identity(size_t n) {\n    simd_bit_table<W> result(n, n);\n    for (size_t k = 0; k < n; k++) {\n        result[k][k] = true;\n    }\n    return result;\n}\n\ntemplate <size_t W>\nvoid simd_bit_table<W>::clear() {\n    data.clear();\n}\n\ntemplate <size_t W>\nbool simd_bit_table<W>::operator==(const simd_bit_table<W> &other) const {\n    return num_simd_words_minor == other.num_simd_words_minor && num_simd_words_major == other.num_simd_words_major &&\n           data == other.data;\n}\n\ntemplate <size_t W>\nbool simd_bit_table<W>::operator!=(const simd_bit_table<W> &other) const {\n    return !(*this == other);\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> simd_bit_table<W>::square_mat_mul(const simd_bit_table<W> &rhs, size_t n) const {\n    assert(num_major_bits_padded() >= n && num_minor_bits_padded() >= n);\n    assert(rhs.num_major_bits_padded() >= n && rhs.num_minor_bits_padded() >= n);\n\n    auto tmp = rhs.transposed();\n\n    simd_bit_table<W> result(n, n);\n    for (size_t row = 0; row < n; row++) {\n        for (size_t col = 0; col < n; col++) {\n            bitword<W> acc{};\n            (*this)[row].for_each_word(tmp[col], [&](bitword<W> &w1, bitword<W> &w2) {\n                acc ^= w1 & w2;\n            });\n            result[row][col] = acc.popcount() & 1;\n        }\n    }\n\n    return result;\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> simd_bit_table<W>::inverse_assuming_lower_triangular(size_t n) const {\n    assert(num_major_bits_padded() >= n && num_minor_bits_padded() >= n);\n\n    simd_bit_table<W> result = simd_bit_table<W>::identity(n);\n    simd_bits<W> copy_row(num_minor_bits_padded());\n    for (size_t target = 0; target < n; target++) {\n        copy_row = (*this)[target];\n        for (size_t pivot = 0; pivot < target; pivot++) {\n            if (copy_row[pivot]) {\n                copy_row ^= (*this)[pivot];\n                result[target] ^= result[pivot];\n            }\n        }\n    }\n    return result;\n}\n\ntemplate <size_t W>\nvoid exchange_low_indices(simd_bit_table<W> &table) {\n    for (size_t maj_high = 0; maj_high < table.num_simd_words_major; maj_high++) {\n        for (size_t min_high = 0; min_high < table.num_simd_words_minor; min_high++) {\n            size_t block_start = table.get_index_of_bitword(maj_high, 0, min_high);\n            bitword<W>::inplace_transpose_square(table.data.ptr_simd + block_start, table.num_simd_words_minor);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid simd_bit_table<W>::destructive_resize(size_t new_min_bits_major, size_t new_min_bits_minor) {\n    num_simd_words_minor = min_bits_to_num_simd_words<W>(new_min_bits_minor);\n    num_simd_words_major = min_bits_to_num_simd_words<W>(new_min_bits_major);\n    data.destructive_resize(num_simd_words_minor * num_simd_words_major * W * W);\n}\n\ntemplate <size_t W>\nvoid simd_bit_table<W>::copy_into_different_size_table(simd_bit_table<W> &other) const {\n    size_t ni = num_simd_words_minor;\n    size_t na = num_simd_words_major;\n    size_t mi = other.num_simd_words_minor;\n    size_t ma = other.num_simd_words_major;\n    size_t num_min_bytes = std::min(ni, mi) * (W / 8);\n    size_t num_maj = std::min(na, ma) * W;\n\n    if (ni == mi) {\n        memcpy(other.data.ptr_simd, data.ptr_simd, num_min_bytes * num_maj);\n    } else {\n        for (size_t maj = 0; maj < num_maj; maj++) {\n            memcpy(other[maj].ptr_simd, (*this)[maj].ptr_simd, num_min_bytes);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid simd_bit_table<W>::resize(size_t new_min_bits_major, size_t new_min_bits_minor) {\n    auto new_num_simd_words_minor = min_bits_to_num_simd_words<W>(new_min_bits_minor);\n    auto new_num_simd_words_major = min_bits_to_num_simd_words<W>(new_min_bits_major);\n    if (new_num_simd_words_major == num_simd_words_major && new_num_simd_words_minor == num_simd_words_minor) {\n        return;\n    }\n    auto new_table = simd_bit_table<W>(new_min_bits_major, new_min_bits_minor);\n    copy_into_different_size_table(new_table);\n    *this = std::move(new_table);\n}\n\ntemplate <size_t W>\nvoid simd_bit_table<W>::do_square_transpose() {\n    assert(num_simd_words_minor == num_simd_words_major);\n\n    // Current address tensor indices: [...min_low ...min_high ...maj_low ...maj_high]\n\n    exchange_low_indices(*this);\n\n    // Current address tensor indices: [...maj_low ...min_high ...min_low ...maj_high]\n\n    // Permute data such that high address bits of majors and minors are exchanged.\n    for (size_t maj_high = 0; maj_high < num_simd_words_major; maj_high++) {\n        for (size_t min_high = maj_high + 1; min_high < num_simd_words_minor; min_high++) {\n            for (size_t maj_low = 0; maj_low < W; maj_low++) {\n                std::swap(\n                    data.ptr_simd[get_index_of_bitword(maj_high, maj_low, min_high)],\n                    data.ptr_simd[get_index_of_bitword(min_high, maj_low, maj_high)]);\n            }\n        }\n    }\n    // Current address tensor indices: [...maj_low ...maj_high ...min_low ...min_high]\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> simd_bit_table<W>::transposed() const {\n    simd_bit_table<W> result(num_minor_bits_padded(), num_major_bits_padded());\n    transpose_into(result);\n    return result;\n}\n\ntemplate <size_t W>\nsimd_bits<W> simd_bit_table<W>::read_across_majors_at_minor_index(\n    size_t major_start, size_t major_stop, size_t minor_index) const {\n    assert(major_stop >= major_start);\n    assert(major_stop <= num_major_bits_padded());\n    assert(minor_index < num_minor_bits_padded());\n    simd_bits<W> result(major_stop - major_start);\n    for (size_t maj = major_start; maj < major_stop; maj++) {\n        result[maj - major_start] = (*this)[maj][minor_index];\n    }\n    return result;\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> simd_bit_table<W>::slice_maj(size_t maj_start_bit, size_t maj_stop_bit) const {\n    simd_bit_table<W> result(maj_stop_bit - maj_start_bit, num_minor_bits_padded());\n    for (size_t k = maj_start_bit; k < maj_stop_bit; k++) {\n        result[k - maj_start_bit] = (*this)[k];\n    }\n    return result;\n}\n\ntemplate <size_t W>\nvoid simd_bit_table<W>::transpose_into(simd_bit_table<W> &out) const {\n    assert(out.num_simd_words_minor == num_simd_words_major);\n    assert(out.num_simd_words_major == num_simd_words_minor);\n\n    for (size_t maj_high = 0; maj_high < num_simd_words_major; maj_high++) {\n        for (size_t min_high = 0; min_high < num_simd_words_minor; min_high++) {\n            for (size_t maj_low = 0; maj_low < W; maj_low++) {\n                size_t src_index = get_index_of_bitword(maj_high, maj_low, min_high);\n                size_t dst_index = out.get_index_of_bitword(min_high, maj_low, maj_high);\n                out.data.ptr_simd[dst_index] = data.ptr_simd[src_index];\n            }\n        }\n    }\n\n    exchange_low_indices(out);\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> simd_bit_table<W>::from_quadrants(\n    size_t n,\n    const simd_bit_table<W> &upper_left,\n    const simd_bit_table<W> &upper_right,\n    const simd_bit_table<W> &lower_left,\n    const simd_bit_table<W> &lower_right) {\n    assert(upper_left.num_minor_bits_padded() >= n && upper_left.num_major_bits_padded() >= n);\n    assert(upper_right.num_minor_bits_padded() >= n && upper_right.num_major_bits_padded() >= n);\n    assert(lower_left.num_minor_bits_padded() >= n && lower_left.num_major_bits_padded() >= n);\n    assert(lower_right.num_minor_bits_padded() >= n && lower_right.num_major_bits_padded() >= n);\n\n    simd_bit_table<W> result(n << 1, n << 1);\n    for (size_t row = 0; row < n; row++) {\n        for (size_t col = 0; col < n; col++) {\n            result[row][col] = upper_left[row][col];\n            result[row][col + n] = upper_right[row][col];\n            result[row + n][col] = lower_left[row][col];\n            result[row + n][col + n] = lower_right[row][col];\n        }\n    }\n    return result;\n}\n\ntemplate <size_t W>\nstd::string simd_bit_table<W>::str(size_t rows, size_t cols) const {\n    std::stringstream out;\n    for (size_t row = 0; row < rows; row++) {\n        if (row) {\n            out << \"\\n\";\n        }\n        for (size_t col = 0; col < cols; col++) {\n            out << \".1\"[(*this)[row][col]];\n        }\n    }\n    return out.str();\n}\n\ntemplate <size_t W>\nstd::string simd_bit_table<W>::str(size_t n) const {\n    return str(n, n);\n}\n\ntemplate <size_t W>\nstd::string simd_bit_table<W>::str() const {\n    return str(num_major_bits_padded(), num_minor_bits_padded());\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> simd_bit_table<W>::concat_major(\n    const simd_bit_table<W> &second, size_t n_first, size_t n_second) const {\n    if (num_major_bits_padded() < n_first || second.num_major_bits_padded() < n_second ||\n        num_minor_bits_padded() != second.num_minor_bits_padded()) {\n        throw std::invalid_argument(\"Size mismatch\");\n    }\n    simd_bit_table<W> result(n_first + n_second, num_minor_bits_padded());\n    auto n1 = n_first * num_minor_u8_padded();\n    auto n2 = n_second * num_minor_u8_padded();\n    memcpy(result.data.u8, data.u8, n1);\n    memcpy(result.data.u8 + n1, second.data.u8, n2);\n    return result;\n}\n\ntemplate <size_t W>\nvoid simd_bit_table<W>::overwrite_major_range_with(\n    size_t dst_major_start, const simd_bit_table<W> &src, size_t src_major_start, size_t num_major_indices) const {\n    assert(src.num_minor_bits_padded() == num_minor_bits_padded());\n    memcpy(\n        data.u8 + dst_major_start * num_minor_u8_padded(),\n        src.data.u8 + src_major_start * src.num_minor_u8_padded(),\n        num_major_indices * num_minor_u8_padded());\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> simd_bit_table<W>::from_text(const char *text, size_t min_rows, size_t min_cols) {\n    std::vector<std::vector<bool>> lines;\n    lines.push_back({});\n\n    // Skip indentation.\n    while (*text == '\\n' || *text == ' ') {\n        text++;\n    }\n\n    for (const char *c = text; *c;) {\n        if (*c == '\\n') {\n            lines.push_back({});\n            c++;\n            // Skip indentation.\n            while (*c == ' ') {\n                c++;\n            }\n        } else if (*c == '0' || *c == '.' || *c == '_') {\n            lines.back().push_back(false);\n            c++;\n        } else if (*c == '1') {\n            lines.back().push_back(true);\n            c++;\n        } else {\n            throw std::invalid_argument(\n                \"Expected indented characters from \\\"10._\\\\n\\\". Got '\" + std::string(1, *c) + \"'.\");\n        }\n    }\n\n    // Remove trailing newline.\n    if (!lines.empty() && lines.back().empty()) {\n        lines.pop_back();\n    }\n\n    size_t num_cols = min_cols;\n    for (const auto &v : lines) {\n        num_cols = std::max(v.size(), num_cols);\n    }\n    size_t num_rows = std::max(min_rows, lines.size());\n    simd_bit_table<W> out(num_rows, num_cols);\n    for (size_t row = 0; row < lines.size(); row++) {\n        for (size_t col = 0; col < lines[row].size(); col++) {\n            out[row][col] = lines[row][col];\n        }\n    }\n\n    return out;\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> simd_bit_table<W>::random(\n    size_t num_randomized_major_bits, size_t num_randomized_minor_bits, std::mt19937_64 &rng) {\n    simd_bit_table<W> result(num_randomized_major_bits, num_randomized_minor_bits);\n    for (size_t maj = 0; maj < num_randomized_major_bits; maj++) {\n        result[maj].randomize(num_randomized_minor_bits, rng);\n    }\n    return result;\n}\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const stim::simd_bit_table<W> &v) {\n    for (size_t k = 0; k < v.num_major_bits_padded(); k++) {\n        if (k) {\n            out << '\\n';\n        }\n        out << v[k];\n    }\n    return out;\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/mem/simd_bit_table.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_bit_table.h\"\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(simd_bit_table_inplace_square_transpose_diam10K) {\n    size_t n = 10 * 1000;\n    simd_bit_table<MAX_BITWORD_WIDTH> table(n, n);\n    benchmark_go([&]() {\n        table.do_square_transpose();\n    })\n        .goal_millis(6)\n        .show_rate(\"Bits\", n * n);\n}\n\nBENCHMARK(simd_bit_table_out_of_place_transpose_diam10K) {\n    size_t n = 10 * 1000;\n    simd_bit_table<MAX_BITWORD_WIDTH> table(n, n);\n    simd_bit_table<MAX_BITWORD_WIDTH> out(n, n);\n    benchmark_go([&]() {\n        table.transpose_into(out);\n    })\n        .goal_millis(12)\n        .show_rate(\"Bits\", n * n);\n}\n"
  },
  {
    "path": "src/stim/mem/simd_bit_table.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_bit_table.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, creation, {\n    simd_bit_table<W> a(3, 3);\n    ASSERT_EQ(\n        a.str(3),\n        \"...\\n\"\n        \"...\\n\"\n        \"...\");\n    a[1][2] = 1;\n    ASSERT_EQ(\n        a.str(3),\n        \"...\\n\"\n        \"..1\\n\"\n        \"...\");\n\n    ASSERT_EQ(\n        simd_bit_table<W>::identity(3).str(3),\n        \"1..\\n\"\n        \".1.\\n\"\n        \"..1\");\n\n    ASSERT_EQ(\n        simd_bit_table<W>::identity(2).str(2),\n        \"1.\\n\"\n        \".1\");\n\n    ASSERT_EQ(\n        simd_bit_table<W>::identity(2).str(3, 4),\n        \"1...\\n\"\n        \".1..\\n\"\n        \"....\");\n\n    ASSERT_EQ(simd_bit_table<W>::identity(2).str().substr(0, 5), \"1....\");\n    ASSERT_EQ(simd_bit_table<W>(0, 5).str(), \"\");\n    ASSERT_EQ(simd_bit_table<W>(5, 0).str().substr(0, 3), \"\\n\\n\\n\");\n\n    ASSERT_EQ(\n        simd_bit_table<W>::from_text(R\"TABLE(\n            1.\n            0._1\n            .1..\n        )TABLE\")\n            .str(5),\n        \"1....\\n\"\n        \"...1.\\n\"\n        \".1...\\n\"\n        \".....\\n\"\n        \".....\");\n\n    simd_bit_table<W> t = simd_bit_table<W>::from_text(\"\", 512, 256);\n    ASSERT_EQ(t.num_minor_bits_padded(), 256);\n    ASSERT_EQ(t.num_major_bits_padded(), 512);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, equality, {\n    simd_bit_table<W> a(3, 3);\n    simd_bit_table<W> b(3, 3);\n    simd_bit_table<W> c(511, 1000);\n    simd_bit_table<W> d(511, 1000);\n    ASSERT_EQ(a, b);\n    ASSERT_EQ(c, d);\n    ASSERT_NE(a, c);\n    a[0][1] = 1;\n    ASSERT_NE(a, b);\n    d[500][900] = 1;\n    ASSERT_NE(c, d);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, multiplication, {\n    simd_bit_table<W> m1(3, 3);\n    simd_bit_table<W> m2(3, 3);\n    m1[0][2] = true;\n    m2[2][1] = true;\n    auto m3 = m1.square_mat_mul(m2, 3);\n    ASSERT_TRUE(m3[0][1]);\n    ASSERT_EQ(\n        m1.str(3),\n        \"..1\\n\"\n        \"...\\n\"\n        \"...\");\n    ASSERT_EQ(\n        m2.str(3),\n        \"...\\n\"\n        \"...\\n\"\n        \".1.\");\n    ASSERT_EQ(\n        m3.str(3),\n        \".1.\\n\"\n        \"...\\n\"\n        \"...\");\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, xor_row_into, {\n    simd_bit_table<W> m(500, 500);\n    m[0][10] = true;\n    m[0][490] = true;\n    m[5][490] = true;\n    m[1] ^= m[0];\n    m[1] ^= m[5];\n    ASSERT_EQ(m[1][10], true);\n    ASSERT_EQ(m[1][490], false);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, inverse_assuming_lower_triangular, {\n    auto m = simd_bit_table<W>::identity(4);\n    m[3][1] = true;\n    ASSERT_EQ(\n        m.str(4),\n        \"1...\\n\"\n        \".1..\\n\"\n        \"..1.\\n\"\n        \".1.1\");\n    auto inv = m.inverse_assuming_lower_triangular(4);\n    ASSERT_EQ(m.square_mat_mul(inv, 4), simd_bit_table<W>::identity(4));\n    ASSERT_EQ(inv.square_mat_mul(m, 4), simd_bit_table<W>::identity(4));\n    ASSERT_EQ(\n        inv.str(4),\n        \"1...\\n\"\n        \".1..\\n\"\n        \"..1.\\n\"\n        \".1.1\");\n\n    m[3][0] = true;\n    ASSERT_EQ(\n        m.str(4),\n        \"1...\\n\"\n        \".1..\\n\"\n        \"..1.\\n\"\n        \"11.1\");\n    inv = m.inverse_assuming_lower_triangular(4);\n    ASSERT_EQ(m.square_mat_mul(inv, 4), simd_bit_table<W>::identity(4));\n    ASSERT_EQ(inv.square_mat_mul(m, 4), simd_bit_table<W>::identity(4));\n    ASSERT_EQ(\n        inv.str(4),\n        \"1...\\n\"\n        \".1..\\n\"\n        \"..1.\\n\"\n        \"11.1\");\n\n    m[1][0] = true;\n    ASSERT_EQ(\n        m.str(4),\n        \"1...\\n\"\n        \"11..\\n\"\n        \"..1.\\n\"\n        \"11.1\");\n    inv = m.inverse_assuming_lower_triangular(4);\n    ASSERT_EQ(m.square_mat_mul(inv, 4), simd_bit_table<W>::identity(4));\n    ASSERT_EQ(inv.square_mat_mul(m, 4), simd_bit_table<W>::identity(4));\n    ASSERT_EQ(\n        inv.str(4),\n        \"1...\\n\"\n        \"11..\\n\"\n        \"..1.\\n\"\n        \".1.1\");\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, transposed, {\n    auto m = simd_bit_table<W>::identity(4);\n    m[3][1] = true;\n    ASSERT_EQ(\n        m.str(4),\n        \"1...\\n\"\n        \".1..\\n\"\n        \"..1.\\n\"\n        \".1.1\");\n    auto trans = m;\n    trans.do_square_transpose();\n    ASSERT_EQ(\n        trans.str(4),\n        \"1...\\n\"\n        \".1.1\\n\"\n        \"..1.\\n\"\n        \"...1\");\n    auto trans2 = trans;\n    trans2.do_square_transpose();\n    ASSERT_EQ(trans2, m);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, random, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t = simd_bit_table<W>::random(100, 90, rng);\n    ASSERT_NE(t[99], simd_bits<W>(90));\n    ASSERT_EQ(t[100], simd_bits<W>(90));\n    t = t.transposed();\n    ASSERT_NE(t[89], simd_bits<W>(100));\n    ASSERT_EQ(t[90], simd_bits<W>(100));\n    ASSERT_NE(simd_bit_table<W>::random(10, 10, rng), simd_bit_table<W>::random(10, 10, rng));\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, slice_maj, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto m = simd_bit_table<W>::random(100, 64, rng);\n    auto s = m.slice_maj(5, 15);\n    ASSERT_EQ(s[0], m[5]);\n    ASSERT_EQ(s[9], m[14]);\n    ASSERT_FALSE(s[10].not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, from_concat_major, {\n    auto a = simd_bit_table<W>::from_text(R\"TABLE(\n        000111\n        101011\n        111111\n        000000\n    )TABLE\");\n    auto b = simd_bit_table<W>::from_text(R\"TABLE(\n        100000\n        000001\n        000100\n    )TABLE\");\n    ASSERT_EQ(a.concat_major(b, 4, 3), simd_bit_table<W>::from_text(R\"TABLE(\n            000111\n            101011\n            111111\n            000000\n            100000\n            000001\n            000100\n        )TABLE\"));\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, from_quadrants, {\n    simd_bit_table<W> t(2, 2);\n    simd_bit_table<W> z(2, 2);\n    t[1][0] = true;\n    ASSERT_EQ(\n        simd_bit_table<W>::from_quadrants(2, t, z, z, z).str(4),\n        \"....\\n\"\n        \"1...\\n\"\n        \"....\\n\"\n        \"....\");\n    ASSERT_EQ(\n        simd_bit_table<W>::from_quadrants(2, z, t, z, z).str(4),\n        \"....\\n\"\n        \"..1.\\n\"\n        \"....\\n\"\n        \"....\");\n    ASSERT_EQ(\n        simd_bit_table<W>::from_quadrants(2, z, z, t, z).str(4),\n        \"....\\n\"\n        \"....\\n\"\n        \"....\\n\"\n        \"1...\");\n    ASSERT_EQ(\n        simd_bit_table<W>::from_quadrants(2, z, z, z, t).str(4),\n        \"....\\n\"\n        \"....\\n\"\n        \"....\\n\"\n        \"..1.\");\n    ASSERT_EQ(\n        simd_bit_table<W>::from_quadrants(2, t, t, t, t).str(4),\n        \"....\\n\"\n        \"1.1.\\n\"\n        \"....\\n\"\n        \"1.1.\");\n})\n\nTEST(simd_bit_table, lg) {\n    ASSERT_EQ(lg(0), 0);\n    ASSERT_EQ(lg(1), 0);\n    ASSERT_EQ(lg(2), 1);\n    ASSERT_EQ(lg(3), 1);\n    ASSERT_EQ(lg(4), 2);\n    ASSERT_EQ(lg(5), 2);\n    ASSERT_EQ(lg(6), 2);\n    ASSERT_EQ(lg(7), 2);\n    ASSERT_EQ(lg(8), 3);\n    ASSERT_EQ(lg(9), 3);\n}\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, destructive_resize, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bit_table<W> table = simd_bit_table<W>::random(5, 7, rng);\n    const uint8_t *prev_pointer = table.data.u8;\n    table.destructive_resize(5, 7);\n    ASSERT_EQ(table.data.u8, prev_pointer);\n    table.destructive_resize(1025, 7);\n    ASSERT_NE(table.data.u8, prev_pointer);\n    ASSERT_GE(table.num_major_bits_padded(), 1025);\n    ASSERT_GE(table.num_minor_bits_padded(), 7);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, read_across_majors_at_minor_index, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bit_table<W> table = simd_bit_table<W>::random(5, 7, rng);\n    simd_bits<W> slice = table.read_across_majors_at_minor_index(2, 5, 1);\n    ASSERT_GE(slice.num_bits_padded(), 4);\n    ASSERT_EQ(slice[0], table[2][1]);\n    ASSERT_EQ(slice[1], table[3][1]);\n    ASSERT_EQ(slice[2], table[4][1]);\n    ASSERT_EQ(slice[3], false);\n})\n\ntemplate <size_t W>\nbool is_table_overlap_identical(const simd_bit_table<W> &a, const simd_bit_table<W> &b) {\n    size_t w_min = std::min(a.num_simd_words_minor, b.num_simd_words_minor);\n    size_t n_maj = std::min(a.num_major_bits_padded(), b.num_major_bits_padded());\n    for (size_t k_maj = 0; k_maj < n_maj; k_maj++) {\n        if (a[k_maj].word_range_ref(0, w_min) != b[k_maj].word_range_ref(0, w_min)) {\n            return false;\n        }\n    }\n    return true;\n}\n\ntemplate <size_t W>\nbool is_table_zero_outside(const simd_bit_table<W> &a, size_t num_major_bits, size_t num_minor_bits) {\n    size_t num_major_words = min_bits_to_num_simd_words<W>(num_major_bits);\n    size_t num_minor_words = min_bits_to_num_simd_words<W>(num_minor_bits);\n    if (a.num_simd_words_minor > num_minor_words) {\n        for (size_t k = 0; k < a.num_simd_words_major; k++) {\n            if (a[k].word_range_ref(num_minor_words, a.num_simd_words_minor - num_minor_words).not_zero()) {\n                return false;\n            }\n        }\n    }\n    for (size_t k = a.num_simd_words_major; k < num_major_words; k++) {\n        if (a[k].not_zero()) {\n            return false;\n        }\n    }\n    return true;\n}\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, copy_into_different_size_table, {\n    auto rng = INDEPENDENT_TEST_RNG();\n\n    auto check_size = [&](size_t w1, size_t h1, size_t w2, size_t h2) {\n        simd_bit_table<W> src = simd_bit_table<W>::random(w1, h1, rng);\n        simd_bit_table<W> dst = simd_bit_table<W>::random(w1, h1, rng);\n        src.copy_into_different_size_table(dst);\n        return is_table_overlap_identical(src, dst);\n    };\n\n    EXPECT_TRUE(check_size(0, 0, 0, 0));\n\n    EXPECT_TRUE(check_size(64, 0, 0, 0));\n    EXPECT_TRUE(check_size(0, 64, 0, 0));\n    EXPECT_TRUE(check_size(0, 0, 64, 0));\n    EXPECT_TRUE(check_size(0, 0, 0, 64));\n\n    EXPECT_TRUE(check_size(64, 64, 64, 64));\n    EXPECT_TRUE(check_size(512, 64, 64, 64));\n    EXPECT_TRUE(check_size(64, 512, 64, 64));\n    EXPECT_TRUE(check_size(64, 64, 512, 64));\n    EXPECT_TRUE(check_size(64, 64, 64, 512));\n\n    EXPECT_TRUE(check_size(512, 512, 64, 64));\n    EXPECT_TRUE(check_size(512, 64, 512, 64));\n    EXPECT_TRUE(check_size(512, 64, 64, 512));\n    EXPECT_TRUE(check_size(64, 512, 512, 64));\n    EXPECT_TRUE(check_size(64, 512, 64, 512));\n    EXPECT_TRUE(check_size(64, 64, 512, 512));\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bit_table, resize, {\n    auto rng = INDEPENDENT_TEST_RNG();\n\n    auto check_size = [&](size_t w1, size_t h1, size_t w2, size_t h2) {\n        simd_bit_table<W> src = simd_bit_table<W>::random(w1, h1, rng);\n        simd_bit_table<W> dst = src;\n        dst.resize(w2, h2);\n        return is_table_overlap_identical(src, dst) && is_table_zero_outside(dst, std::min(w1, w2), std::min(h1, h2));\n    };\n\n    EXPECT_TRUE(check_size(0, 0, 0, 0));\n\n    EXPECT_TRUE(check_size(64, 0, 0, 0));\n    EXPECT_TRUE(check_size(0, 64, 0, 0));\n    EXPECT_TRUE(check_size(0, 0, 64, 0));\n    EXPECT_TRUE(check_size(0, 0, 0, 64));\n\n    EXPECT_TRUE(check_size(64, 64, 64, 64));\n    EXPECT_TRUE(check_size(512, 64, 64, 64));\n    EXPECT_TRUE(check_size(64, 512, 64, 64));\n    EXPECT_TRUE(check_size(64, 64, 512, 64));\n    EXPECT_TRUE(check_size(64, 64, 64, 512));\n\n    EXPECT_TRUE(check_size(512, 512, 64, 64));\n    EXPECT_TRUE(check_size(512, 64, 512, 64));\n    EXPECT_TRUE(check_size(512, 64, 64, 512));\n    EXPECT_TRUE(check_size(64, 512, 512, 64));\n    EXPECT_TRUE(check_size(64, 512, 64, 512));\n    EXPECT_TRUE(check_size(64, 64, 512, 512));\n})\n"
  },
  {
    "path": "src/stim/mem/simd_bits.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_SIMD_BITS_H\n#define _STIM_MEM_SIMD_BITS_H\n\n#include <cstdint>\n#include <random>\n\n#include \"stim/mem/bit_ref.h\"\n#include \"stim/mem/simd_bits_range_ref.h\"\n\nnamespace stim {\n\n/// Densely packed bits, allocated with alignment and padding enabling SIMD operations.\n///\n/// Note that, due to the padding, the smallest simd_bits you can have is 256 bits (32 bytes) long.\n///\n/// For performance, simd_bits does not store the \"intended\" size of the data, only the padded size. Any intended size\n/// has to be tracked separately.\ntemplate <size_t W>\nstruct simd_bits {\n    size_t num_simd_words;\n    union {\n        // It is fair to say that this is the most dangerous block, or danger-enabling block, in the entire codebase.\n        // C++ is very particular when it comes to touching the same memory as if it had multiple different types.\n        // If you know how to make something *for sure work as a flexibly-accessible bag of bits*, please fix this.\n        // In the meantime, always build with `-fno-strict-aliasing` and a short ritual prayer to the compiler gods.\n        uint8_t *u8;\n        uint64_t *u64;\n        bitword<W> *ptr_simd;\n    };\n\n    /// Constructs a zero-initialized simd_bits with at least the given number of bits.\n    explicit simd_bits(size_t min_bits);\n    /// Frees allocated bits.\n    ~simd_bits();\n    /// Copy constructor.\n    simd_bits(const simd_bits &other);\n    /// Copy constructor from range reference.\n    simd_bits(const simd_bits_range_ref<W> other);\n    /// Move constructor.\n    simd_bits(simd_bits &&other) noexcept;\n\n    /// Copy assignment.\n    simd_bits &operator=(const simd_bits &other);\n    /// Copy assignment from range reference.\n    simd_bits &operator=(const simd_bits_range_ref<W> other);\n    /// Move assignment.\n    simd_bits &operator=(simd_bits &&other) noexcept;\n    // Xor assignment.\n    simd_bits &operator^=(const simd_bits_range_ref<W> other);\n    // Mask assignment.\n    simd_bits &operator&=(const simd_bits_range_ref<W> other);\n    simd_bits &operator|=(const simd_bits_range_ref<W> other);\n    // Addition assigment\n    simd_bits &operator+=(const simd_bits_range_ref<W> other);\n    simd_bits &operator-=(const simd_bits_range_ref<W> other);\n    // right shift assignment\n    simd_bits &operator>>=(int offset);\n    // left shift assignment\n    simd_bits &operator<<=(int offset);\n    // Swap assignment.\n    simd_bits &swap_with(simd_bits_range_ref<W> other);\n\n    // Equality.\n    bool operator==(const simd_bits_range_ref<W> &other) const;\n    bool operator==(const simd_bits<W> &other) const;\n    // Inequality.\n    bool operator!=(const simd_bits_range_ref<W> &other) const;\n    bool operator!=(const simd_bits<W> &other) const;\n    /// Determines whether or not any of the bits in the simd_bits are non-zero.\n    bool not_zero() const;\n\n    // Arbitrary ordering.\n    bool operator<(const simd_bits_range_ref<W> other) const;\n\n    void destructive_resize(size_t new_min_bits);\n    void preserving_resize(size_t new_min_bits);\n\n    /// Returns a reference to the bit at offset k.\n    bit_ref operator[](size_t k);\n    /// Returns a const reference to the bit at offset k.\n    const bit_ref operator[](size_t k) const;\n    /// Returns a reference to the bits in this simd_bits.\n    operator simd_bits_range_ref<W>();\n    /// Returns a const reference to the bits in this simd_bits.\n    operator const simd_bits_range_ref<W>() const;\n    /// Returns a reference to a sub-range of the bits in this simd_bits.\n    inline simd_bits_range_ref<W> word_range_ref(size_t word_offset, size_t sub_num_simd_words) {\n        return simd_bits_range_ref<W>(ptr_simd + word_offset, sub_num_simd_words);\n    }\n    /// Returns a reference to a sub-range of the bits at the start of this simd_bits.\n    inline simd_bits_range_ref<W> prefix_ref(size_t unpadded_bit_length) {\n        return simd_bits_range_ref<W>(ptr_simd, min_bits_to_num_simd_words<W>(unpadded_bit_length));\n    }\n    /// Returns a const reference to a sub-range of the bits in this simd_bits.\n    inline const simd_bits_range_ref<W> word_range_ref(size_t word_offset, size_t sub_num_simd_words) const {\n        return simd_bits_range_ref<W>(ptr_simd + word_offset, sub_num_simd_words);\n    }\n\n    /// Returns the number of bits that are 1 in the bit range.\n    size_t popcnt() const;\n    /// Returns the power-of-two-ness of the number, or SIZE_MAX if the number has no 1s.\n    size_t countr_zero() const;\n\n    /// Inverts all bits in the range.\n    void invert_bits();\n    /// Sets all bits in the range to zero.\n    void clear();\n    /// Randomizes the contents of this simd_bits using the given random number generator, up to the given bit position.\n    void randomize(size_t num_bits, std::mt19937_64 &rng);\n    /// Returns a simd_bits with at least the given number of bits, with bits up to the given number of bits randomized.\n    /// Padding bits beyond the minimum number of bits are not randomized.\n    static simd_bits<W> random(size_t min_bits, std::mt19937_64 &rng);\n\n    /// Returns whether or not the two ranges have set bits in common.\n    bool intersects(const simd_bits_range_ref<W> other) const;\n    /// Returns whether or not all bits that are set in `other` are also set in this range.\n    bool is_subset_of_or_equal_to(const simd_bits_range_ref<W> other) const;\n\n    /// Writes bits from another location.\n    /// Bits not part of the write are unchanged.\n    void truncated_overwrite_from(simd_bits_range_ref<W> other, size_t num_bits);\n    /// Sets all bits at the given position and beyond it to 0.\n    void clear_bits_past(size_t num_kept_bits);\n\n    /// Returns a description of the contents of the simd_bits.\n    std::string str() const;\n\n    /// Number of 64 bit words in the range.\n    inline size_t num_u64_padded() const {\n        return num_simd_words * (sizeof(bitword<W>) / sizeof(uint64_t));\n    }\n    /// Number of 32 bit words in the range.\n    inline size_t num_u32_padded() const {\n        return num_simd_words * (sizeof(bitword<W>) / sizeof(uint32_t));\n    }\n    /// Number of 16 bit words in the range.\n    inline size_t num_u16_padded() const {\n        return num_simd_words * (sizeof(bitword<W>) / sizeof(uint16_t));\n    }\n    /// Number of 8 bit words in the range.\n    inline size_t num_u8_padded() const {\n        return num_simd_words * (sizeof(bitword<W>) / sizeof(uint8_t));\n    }\n    /// Number of bits in the range.\n    inline size_t num_bits_padded() const {\n        return num_simd_words * W;\n    }\n\n    uint64_t as_u64() const;\n\n    template <typename CALLBACK>\n    void for_each_set_bit(CALLBACK callback) const {\n        size_t n = num_u64_padded();\n        for (size_t w = 0; w < n; w++) {\n            uint64_t v = u64[w];\n            while (v) {\n                size_t q = w * 64 + std::countr_zero(v);\n                v &= v - 1;\n                callback(q);\n            }\n        }\n    }\n};\n\ntemplate <size_t W>\nsimd_bits<W> operator^(const simd_bits_range_ref<W> a, const simd_bits_range_ref<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator|(const simd_bits_range_ref<W> a, const simd_bits_range_ref<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator&(const simd_bits_range_ref<W> a, const simd_bits_range_ref<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator^(const simd_bits<W> a, const simd_bits_range_ref<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator|(const simd_bits<W> a, const simd_bits_range_ref<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator&(const simd_bits<W> a, const simd_bits_range_ref<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator^(const simd_bits_range_ref<W> a, const simd_bits<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator|(const simd_bits_range_ref<W> a, const simd_bits<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator&(const simd_bits_range_ref<W> a, const simd_bits<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator^(const simd_bits<W> a, const simd_bits<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator|(const simd_bits<W> a, const simd_bits<W> b);\ntemplate <size_t W>\nsimd_bits<W> operator&(const simd_bits<W> a, const simd_bits<W> b);\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const simd_bits<W> m);\n\n}  // namespace stim\n\n#include \"stim/mem/simd_bits.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/simd_bits.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <algorithm>\n#include <cassert>\n#include <cstring>\n#include <random>\n#include <sstream>\n\n#include \"stim/mem/simd_util.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nuint64_t *malloc_aligned_padded_zeroed(size_t min_bits) {\n    size_t num_u8 = min_bits_to_num_bits_padded<W>(min_bits) >> 3;\n    void *result = bitword<W>::aligned_malloc(num_u8);\n    memset(result, 0, num_u8);\n    return (uint64_t *)result;\n}\n\ntemplate <size_t W>\nsimd_bits<W>::simd_bits(size_t min_bits)\n    : num_simd_words(min_bits_to_num_simd_words<W>(min_bits)), u64(malloc_aligned_padded_zeroed<W>(min_bits)) {\n}\n\ntemplate <size_t W>\nsimd_bits<W>::simd_bits(const simd_bits<W> &other)\n    : num_simd_words(other.num_simd_words), u64(malloc_aligned_padded_zeroed<W>(other.num_bits_padded())) {\n    memcpy(u8, other.u8, num_u8_padded());\n}\n\ntemplate <size_t W>\nsimd_bits<W>::simd_bits(const simd_bits_range_ref<W> other)\n    : num_simd_words(other.num_simd_words), u64(malloc_aligned_padded_zeroed<W>(other.num_bits_padded())) {\n    memcpy(u8, other.u8, num_u8_padded());\n}\n\ntemplate <size_t W>\nsimd_bits<W>::simd_bits(simd_bits<W> &&other) noexcept : num_simd_words(other.num_simd_words), u64(other.u64) {\n    other.u64 = nullptr;\n    other.num_simd_words = 0;\n}\n\ntemplate <size_t W>\nsimd_bits<W>::~simd_bits() {\n    if (u64 != nullptr) {\n        bitword<W>::aligned_free(u64);\n        u64 = nullptr;\n        num_simd_words = 0;\n    }\n}\n\ntemplate <size_t W>\nvoid simd_bits<W>::clear() {\n    simd_bits_range_ref<W>(*this).clear();\n}\n\ntemplate <size_t W>\nvoid simd_bits<W>::invert_bits() {\n    simd_bits_range_ref<W>(*this).invert_bits();\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator=(simd_bits<W> &&other) noexcept {\n    (*this).~simd_bits();\n    new (this) simd_bits(std::move(other));\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator=(const simd_bits<W> &other) {\n    *this = simd_bits_range_ref<W>(other);\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator=(const simd_bits_range_ref<W> other) {\n    // Avoid re-allocating if already the same size.\n    if (num_simd_words == other.num_simd_words) {\n        simd_bits_range_ref<W>(*this) = other;\n        return *this;\n    }\n\n    (*this).~simd_bits();\n    new (this) simd_bits(other);\n    return *this;\n}\n\ntemplate <size_t W>\nbool simd_bits<W>::operator==(const simd_bits_range_ref<W> &other) const {\n    return simd_bits_range_ref<W>(*this) == other;\n}\n\ntemplate <size_t W>\nbool simd_bits<W>::operator==(const simd_bits<W> &other) const {\n    return simd_bits_range_ref<W>(*this) == simd_bits_range_ref<W>(other);\n}\n\ntemplate <size_t W>\nbool simd_bits<W>::operator!=(const simd_bits_range_ref<W> &other) const {\n    return !(*this == other);\n}\n\ntemplate <size_t W>\nbool simd_bits<W>::operator!=(const simd_bits<W> &other) const {\n    return !(*this == other);\n}\n\ntemplate <size_t W>\nsimd_bits<W> simd_bits<W>::random(size_t min_bits, std::mt19937_64 &rng) {\n    simd_bits<W> result(min_bits);\n    result.randomize(min_bits, rng);\n    return result;\n}\n\ntemplate <size_t W>\nvoid simd_bits<W>::randomize(size_t num_bits, std::mt19937_64 &rng) {\n    simd_bits_range_ref<W>(*this).randomize(num_bits, rng);\n}\n\ntemplate <size_t W>\nvoid simd_bits<W>::truncated_overwrite_from(simd_bits_range_ref<W> other, size_t num_bits) {\n    simd_bits_range_ref<W>(*this).truncated_overwrite_from(other, num_bits);\n}\n\ntemplate <size_t W>\nvoid simd_bits<W>::clear_bits_past(size_t num_kept_bits) {\n    simd_bits_range_ref<W>(*this).clear_bits_past(num_kept_bits);\n}\n\ntemplate <size_t W>\nbit_ref simd_bits<W>::operator[](size_t k) {\n    return bit_ref(u64, k);\n}\n\ntemplate <size_t W>\nconst bit_ref simd_bits<W>::operator[](size_t k) const {\n    return bit_ref(u64, k);\n}\n\ntemplate <size_t W>\nsimd_bits<W>::operator simd_bits_range_ref<W>() {\n    return simd_bits_range_ref<W>(ptr_simd, num_simd_words);\n}\n\ntemplate <size_t W>\nsimd_bits<W>::operator const simd_bits_range_ref<W>() const {\n    return simd_bits_range_ref<W>(ptr_simd, num_simd_words);\n}\n\ntemplate <size_t W>\nsimd_bits<W> operator^(const simd_bits_range_ref<W> a, const simd_bits_range_ref<W> b) {\n    assert(a.num_simd_words == b.num_simd_words);\n    simd_bits<W> result(a.num_bits_padded());\n    ((simd_bits_range_ref<W>)result).for_each_word(a, b, [](bitword<W> &w0, bitword<W> &w1, bitword<W> &w2) {\n        w0 = w1 ^ w2;\n    });\n    return result;\n}\ntemplate <size_t W>\nsimd_bits<W> operator|(const simd_bits_range_ref<W> a, const simd_bits_range_ref<W> b) {\n    assert(a.num_simd_words == b.num_simd_words);\n    simd_bits<W> result(a.num_bits_padded());\n    ((simd_bits_range_ref<W>)result).for_each_word(a, b, [](bitword<W> &w0, bitword<W> &w1, bitword<W> &w2) {\n        w0 = w1 | w2;\n    });\n    return result;\n}\ntemplate <size_t W>\nsimd_bits<W> operator&(const simd_bits_range_ref<W> a, const simd_bits_range_ref<W> b) {\n    assert(a.num_simd_words == b.num_simd_words);\n    simd_bits<W> result(a.num_bits_padded());\n    ((simd_bits_range_ref<W>)result).for_each_word(a, b, [](bitword<W> &w0, bitword<W> &w1, bitword<W> &w2) {\n        w0 = w1 & w2;\n    });\n    return result;\n}\ntemplate <size_t W>\nsimd_bits<W> operator^(const simd_bits<W> a, const simd_bits_range_ref<W> b) {\n    return (const simd_bits_range_ref<W>)a ^ (const simd_bits_range_ref<W>)b;\n}\ntemplate <size_t W>\nsimd_bits<W> operator^(const simd_bits_range_ref<W> a, const simd_bits<W> b) {\n    return (const simd_bits_range_ref<W>)a ^ (const simd_bits_range_ref<W>)b;\n}\ntemplate <size_t W>\nsimd_bits<W> operator^(const simd_bits<W> a, const simd_bits<W> b) {\n    return (const simd_bits_range_ref<W>)a ^ (const simd_bits_range_ref<W>)b;\n}\ntemplate <size_t W>\nsimd_bits<W> operator|(const simd_bits<W> a, const simd_bits_range_ref<W> b) {\n    return (const simd_bits_range_ref<W>)a | (const simd_bits_range_ref<W>)b;\n}\ntemplate <size_t W>\nsimd_bits<W> operator|(const simd_bits_range_ref<W> a, const simd_bits<W> b) {\n    return (const simd_bits_range_ref<W>)a | (const simd_bits_range_ref<W>)b;\n}\ntemplate <size_t W>\nsimd_bits<W> operator|(const simd_bits<W> a, const simd_bits<W> b) {\n    return (const simd_bits_range_ref<W>)a | (const simd_bits_range_ref<W>)b;\n}\ntemplate <size_t W>\nsimd_bits<W> operator&(const simd_bits<W> a, const simd_bits_range_ref<W> b) {\n    return (const simd_bits_range_ref<W>)a & (const simd_bits_range_ref<W>)b;\n}\ntemplate <size_t W>\nsimd_bits<W> operator&(const simd_bits_range_ref<W> a, const simd_bits<W> b) {\n    return (const simd_bits_range_ref<W>)a & (const simd_bits_range_ref<W>)b;\n}\ntemplate <size_t W>\nsimd_bits<W> operator&(const simd_bits<W> a, const simd_bits<W> b) {\n    return (const simd_bits_range_ref<W>)a & (const simd_bits_range_ref<W>)b;\n}\n\ntemplate <size_t W>\nbool simd_bits<W>::operator<(const simd_bits_range_ref<W> other) const {\n    if (num_simd_words != other.num_simd_words) {\n        return num_simd_words < other.num_simd_words;\n    }\n    for (size_t k = 0; k < num_simd_words; k++) {\n        if (ptr_simd[k] != other.ptr_simd[k]) {\n            return ptr_simd[k] < other.ptr_simd[k];\n        }\n    }\n    return false;\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator^=(const simd_bits_range_ref<W> other) {\n    simd_bits_range_ref<W>(*this) ^= other;\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator&=(const simd_bits_range_ref<W> other) {\n    simd_bits_range_ref<W>(*this) &= other;\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator|=(const simd_bits_range_ref<W> other) {\n    simd_bits_range_ref<W>(*this) |= other;\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator+=(const simd_bits_range_ref<W> other) {\n    simd_bits_range_ref<W>(*this) += other;\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator-=(const simd_bits_range_ref<W> other) {\n    simd_bits_range_ref<W>(*this) -= other;\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator>>=(int offset) {\n    simd_bits_range_ref<W>(*this) >>= offset;\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::operator<<=(int offset) {\n    simd_bits_range_ref<W>(*this) <<= offset;\n    return *this;\n}\n\ntemplate <size_t W>\nbool simd_bits<W>::not_zero() const {\n    return simd_bits_range_ref<W>(*this).not_zero();\n}\n\ntemplate <size_t W>\nbool simd_bits<W>::intersects(const simd_bits_range_ref<W> other) const {\n    return simd_bits_range_ref<W>(*this).intersects(other);\n}\n\ntemplate <size_t W>\nbool simd_bits<W>::is_subset_of_or_equal_to(const simd_bits_range_ref<W> other) const {\n    return simd_bits_range_ref<W>(*this).is_subset_of_or_equal_to(other);\n}\n\ntemplate <size_t W>\nstd::string simd_bits<W>::str() const {\n    return simd_bits_range_ref<W>(*this).str();\n}\n\ntemplate <size_t W>\nsimd_bits<W> &simd_bits<W>::swap_with(simd_bits_range_ref<W> other) {\n    simd_bits_range_ref<W>(*this).swap_with(other);\n    return *this;\n}\n\ntemplate <size_t W>\nvoid simd_bits<W>::destructive_resize(size_t new_min_bits) {\n    if (min_bits_to_num_bits_padded<W>(new_min_bits) == num_bits_padded()) {\n        return;\n    }\n    *this = std::move(simd_bits<W>(new_min_bits));\n}\n\ntemplate <size_t W>\nvoid simd_bits<W>::preserving_resize(size_t new_min_bits) {\n    if (min_bits_to_num_bits_padded<W>(new_min_bits) == num_bits_padded()) {\n        return;\n    }\n    simd_bits<W> new_storage(new_min_bits);\n    memcpy(new_storage.ptr_simd, ptr_simd, sizeof(bitword<W>) * std::min(num_simd_words, new_storage.num_simd_words));\n    *this = std::move(new_storage);\n}\n\ntemplate <size_t W>\nsize_t simd_bits<W>::popcnt() const {\n    return simd_bits_range_ref<W>(*this).popcnt();\n}\n\ntemplate <size_t W>\nuint64_t simd_bits<W>::as_u64() const {\n    return simd_bits_range_ref<W>(*this).as_u64();\n}\n\ntemplate <size_t W>\nsize_t simd_bits<W>::countr_zero() const {\n    return simd_bits_range_ref<W>(*this).countr_zero();\n}\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const simd_bits<W> m) {\n    return out << simd_bits_range_ref<W>(m);\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/mem/simd_bits.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_bits.h\"\n\n#include <cstring>\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(simd_bits_randomize_10K) {\n    size_t n = 10 * 1000;\n    simd_bits<MAX_BITWORD_WIDTH> data(n);\n    std::mt19937_64 rng(0);\n    benchmark_go([&]() {\n        data.randomize(n, rng);\n    })\n        .goal_nanos(450)\n        .show_rate(\"Bits\", n);\n}\n\nBENCHMARK(simd_bits_xor_10K) {\n    size_t n = 10 * 1000;\n    simd_bits<MAX_BITWORD_WIDTH> d1(n);\n    simd_bits<MAX_BITWORD_WIDTH> d2(n);\n    benchmark_go([&]() {\n        d2 ^= d1;\n    })\n        .goal_nanos(20)\n        .show_rate(\"Bits\", n);\n}\n\nBENCHMARK(simd_bits_not_zero_100K) {\n    size_t n = 10 * 1000;\n    simd_bits<MAX_BITWORD_WIDTH> d(n);\n    d[600] = true;\n    size_t total = 0;\n    benchmark_go([&]() {\n        total += d.not_zero();\n    })\n        .goal_nanos(32)\n        .show_rate(\"Bits\", n);\n    if (total == 0) {\n        std::cerr << \"data dependency\";\n    }\n}\n"
  },
  {
    "path": "src/stim/mem/simd_bits.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_bits.h\"\n\n#include <random>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_util.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(simd_bits, move, {\n    simd_bits<W> a(512);\n    auto ptr = a.u64;\n\n    simd_bits<W> b(std::move(a));\n    ASSERT_EQ(b.u64, ptr);\n\n    simd_bits<W> c(1);\n    c = std::move(b);\n    ASSERT_EQ(c.u64, ptr);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, construct, {\n    simd_bits<W> d(1024);\n    ASSERT_NE(d.ptr_simd, nullptr);\n    ASSERT_EQ(d.num_simd_words, 1024 / W);\n    ASSERT_EQ(d.num_bits_padded(), 1024);\n    ASSERT_EQ(d.num_u8_padded(), 128);\n    ASSERT_EQ(d.num_u16_padded(), 64);\n    ASSERT_EQ(d.num_u32_padded(), 32);\n    ASSERT_EQ(d.num_u64_padded(), 16);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, aliased_editing_and_bit_refs, {\n    simd_bits<W> d(1024);\n    auto c = (char *)d.u8;\n    const simd_bits<W> &cref = d;\n\n    ASSERT_EQ(c[0], 0);\n    ASSERT_EQ(c[13], 0);\n    d[5] = true;\n    ASSERT_EQ(c[0], 32);\n    d[0] = true;\n    ASSERT_EQ(c[0], 33);\n    d[100] = true;\n    ASSERT_EQ(d[100], true);\n    ASSERT_EQ(c[12], 16);\n    c[12] = 0;\n    ASSERT_EQ(d[100], false);\n    ASSERT_EQ(cref[100], d[100]);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, min_bits_to_num_bits_padded, {\n    const auto &f = &min_bits_to_num_bits_padded<W>;\n    if (W == 256) {\n        ASSERT_EQ(f(0), 0);\n        ASSERT_EQ(f(1), 256);\n        ASSERT_EQ(f(100), 256);\n        ASSERT_EQ(f(255), 256);\n        ASSERT_EQ(f(256), 256);\n        ASSERT_EQ(f(257), 512);\n        ASSERT_EQ(f((1 << 30) - 1), 1 << 30);\n        ASSERT_EQ(f(1 << 30), 1 << 30);\n        ASSERT_EQ(f((1 << 30) + 1), (1 << 30) + 256);\n    } else if (W == 128) {\n        ASSERT_EQ(f(0), 0);\n        ASSERT_EQ(f(1), 128);\n        ASSERT_EQ(f(100), 128);\n        ASSERT_EQ(f(255), 256);\n        ASSERT_EQ(f(256), 256);\n        ASSERT_EQ(f(257), 256 + 128);\n        ASSERT_EQ(f((1 << 30) - 1), 1 << 30);\n        ASSERT_EQ(f(1 << 30), 1 << 30);\n        ASSERT_EQ(f((1 << 30) + 1), (1 << 30) + 128);\n    } else if (W == 64) {\n        ASSERT_EQ(f(0), 0);\n        ASSERT_EQ(f(1), 64);\n        ASSERT_EQ(f(100), 128);\n        ASSERT_EQ(f(255), 256);\n        ASSERT_EQ(f(256), 256);\n        ASSERT_EQ(f(257), 256 + 64);\n        ASSERT_EQ(f((1 << 30) - 1), 1 << 30);\n        ASSERT_EQ(f(1 << 30), 1 << 30);\n        ASSERT_EQ(f((1 << 30) + 1), (1 << 30) + 64);\n    } else {\n        ASSERT_TRUE(false) << \"Unrecognized size.\";\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, str, {\n    simd_bits<W> d(256);\n    ASSERT_EQ(\n        d.str(),\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\");\n    d[5] = true;\n    ASSERT_EQ(\n        d.str(),\n        \"_____1__________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\");\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, randomize, {\n    simd_bits<W> d(1024);\n\n    auto rng = INDEPENDENT_TEST_RNG();\n    d.randomize(64 + 57, rng);\n    uint64_t mask = (1ULL << 57) - 1;\n    // Randomized.\n    ASSERT_NE(d.u64[0], 0);\n    ASSERT_NE(d.u64[0], SIZE_MAX);\n    ASSERT_NE(d.u64[1] & mask, 0);\n    ASSERT_NE(d.u64[1] & mask, 0);\n    // Not touched.\n    ASSERT_EQ(d.u64[1] & ~mask, 0);\n    ASSERT_EQ(d.u64[2], 0);\n    ASSERT_EQ(d.u64[3], 0);\n\n    for (size_t k = 0; k < d.num_u64_padded(); k++) {\n        d.u64[k] = UINT64_MAX;\n    }\n    d.randomize(64 + 57, rng);\n    // Randomized.\n    ASSERT_NE(d.u64[0], 0);\n    ASSERT_NE(d.u64[0], SIZE_MAX);\n    ASSERT_NE(d.u64[1] & mask, 0);\n    ASSERT_NE(d.u64[1] & mask, 0);\n    // Not touched.\n    ASSERT_EQ(d.u64[1] & ~mask, UINT64_MAX & ~mask);\n    ASSERT_EQ(d.u64[2], UINT64_MAX);\n    ASSERT_EQ(d.u64[3], UINT64_MAX);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, xor_assignment, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> m0 = simd_bits<W>::random(512, rng);\n    simd_bits<W> m1 = simd_bits<W>::random(512, rng);\n    simd_bits<W> m2(512);\n    m2 ^= m0;\n    ASSERT_EQ(m0, m2);\n    m2 ^= m1;\n    for (size_t k = 0; k < m0.num_u64_padded(); k++) {\n        ASSERT_EQ(m2.u64[k], m0.u64[k] ^ m1.u64[k]);\n    }\n})\n\ntemplate <size_t W>\nvoid set_bits_from_u64_vector(simd_bits<W> &bits, std::vector<uint64_t> &vec) {\n    for (size_t w = 0; w < bits.num_u64_padded(); w++) {\n        for (size_t b = 0; b < 64; b++) {\n            bits[w * 64 + b] |= (vec[w] & (1ULL << b));\n        }\n    }\n}\n\nTEST_EACH_WORD_SIZE_W(simd_bits, add_assignment, {\n    simd_bits<W> m0(512);\n    simd_bits<W> m1(512);\n    uint64_t all_set = 0xFFFFFFFFFFFFFFFFULL;\n    uint64_t on_off = 0x0F0F0F0F0F0F0F0FULL;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        for (size_t k = 0; k < 64; k++) {\n            if (word % 2 == 0) {\n                m0[word * 64 + k] = all_set & (1ULL << k);\n                m1[word * 64 + k] = all_set & (1ULL << k);\n            } else {\n                m0[word * 64 + k] = (bool)(on_off & (1ULL << k));\n                m1[word * 64 + k] = (bool)(on_off & (1ULL << k));\n            }\n        }\n    }\n    m0 += m1;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        uint64_t pattern = 0ULL;\n        for (size_t k = 0; k < 64; k++) {\n            pattern |= (uint64_t{m0[word * 64 + k]} << k);\n        }\n        if (word % 2 == 0) {\n            ASSERT_EQ(pattern, 0xFFFFFFFFFFFFFFFEULL);\n        } else {\n            ASSERT_EQ(pattern, 0x1E1E1E1E1E1E1E1FULL);\n        }\n    }\n    for (size_t k = 0; k < m0.num_u64_padded() / 2; k++) {\n        m1.u64[2 * k] = 0ULL;\n        m1.u64[2 * k + 1] = 0ULL;\n    }\n    m0 += m1;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        uint64_t pattern = 0ULL;\n        for (size_t k = 0; k < 64; k++) {\n            pattern |= (uint64_t{m0[word * 64 + k]} << k);\n        }\n        if (word % 2 == 0) {\n            ASSERT_EQ(pattern, 0xFFFFFFFFFFFFFFFEULL);\n        } else {\n            ASSERT_EQ(pattern, 0x1E1E1E1E1E1E1E1FULL);\n        }\n    }\n    m0.clear();\n    m1.clear();\n    m1[0] = 1;\n    for (int i = 0; i < 512; i++) {\n        m0 += m1;\n    }\n    for (size_t k = 0; k < 64; k++) {\n        if (k == 9) {\n            ASSERT_EQ(m0[k], 1);\n        } else {\n            ASSERT_EQ(m0[k], 0);\n        }\n    }\n    m0.clear();\n    for (size_t k = 0; k < 64; k++) {\n        m0[k] = all_set & (1ULL << k);\n    }\n    m0 += m1;\n    ASSERT_EQ(m0[0], 0);\n    ASSERT_EQ(m0[64], 1);\n    // Test carrying across multiple (>=2) words.\n    size_t num_bits = 193;\n    simd_bits<W> add(num_bits);\n    simd_bits<W> one(num_bits);\n    for (size_t word = 0; word < add.num_u64_padded() - 1; word++) {\n        for (size_t k = 0; k < 64; k++) {\n            add[word * 64 + k] = 1;\n        }\n    }\n    one[0] = 1;\n    add += one;\n    // These should all overflow and carries should propagate to the last word.\n    for (size_t k = 0; k < num_bits - 1; k++) {\n        ASSERT_EQ(add[k], 0);\n    }\n    ASSERT_EQ(add[num_bits - 1], 1);\n    // From python\n    std::vector<uint64_t> x{\n        0ULL,\n        14988672980522980357ULL,\n        18446744073709551615ULL,\n        18446744073709551615ULL,\n        6866573900576593249ULL,\n        0ULL,\n        18446744073709551615ULL,\n        0ULL};\n    std::vector<uint64_t> y{\n        4413476325400229597ULL,\n        0ULL,\n        9428810821357656676ULL,\n        7863636477302268070ULL,\n        0ULL,\n        18446744073709551615ULL,\n        0ULL,\n        15077824728923429555ULL};\n    std::vector<uint64_t> z{\n        4413476325400229597ULL,\n        14988672980522980357ULL,\n        9428810821357656675ULL,\n        7863636477302268070ULL,\n        6866573900576593250ULL,\n        18446744073709551615ULL,\n        18446744073709551615ULL,\n        15077824728923429555ULL};\n    simd_bits<W> a(512), b(512), ref(512);\n    set_bits_from_u64_vector(a, x);\n    set_bits_from_u64_vector(b, y);\n    set_bits_from_u64_vector(ref, z);\n    a += b;\n    ASSERT_EQ(a, ref);\n})\n\ntemplate <size_t W>\nvoid set_random_words_to_all_set(\n    simd_bits<W> &bits, size_t num_bits, std::mt19937_64 &rng, std::uniform_real_distribution<double> &dist_real) {\n    bits.randomize(num_bits, rng);\n    size_t max_bit = W;\n    for (size_t iword = 0; iword < bits.num_simd_words; iword++) {\n        double r = dist_real(rng);\n        if (iword == bits.num_simd_words - 1) {\n            max_bit = num_bits - W * iword;\n        }\n        if (r < 1.0 / 3.0) {\n            double rall = dist_real(rng);\n            if (rall > 0.5) {\n                for (size_t k = 0; k < max_bit; k++) {\n                    bits[iword * W + k] = 1;\n                }\n            } else {\n                for (size_t k = 0; k < max_bit; k++) {\n                    bits[iword * W + k] = 0;\n                }\n            }\n        }\n    }\n}\n\nTEST_EACH_WORD_SIZE_W(simd_bits, fuzz_add_assignment, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    // a + b == b + a\n    std::uniform_real_distribution<double> dist_real(0, 1);\n    for (int i = 0; i < 10; i++) {\n        std::uniform_int_distribution<int> dist_bits(1, 1200);\n        int num_bits = dist_bits(rng);\n        simd_bits<W> m1(num_bits), m2(num_bits);\n        set_random_words_to_all_set(m1, num_bits, rng, dist_real);\n        set_random_words_to_all_set(m2, num_bits, rng, dist_real);\n        simd_bits<W> ref1(m1), ref2(m2);\n        m1 += ref2;\n        m2 += ref1;\n        ASSERT_EQ(m1, m2);\n    }\n    // (a + 1) + ~a = allset\n    for (int i = 0; i < 10; i++) {\n        std::uniform_int_distribution<int> dist_bits(1, 1200);\n        int num_bits = dist_bits(rng);\n        simd_bits<W> m1(num_bits);\n        simd_bits<W> zero(num_bits);\n        simd_bits<W> one(num_bits);\n        one[0] = 1;\n        set_random_words_to_all_set(m1, num_bits, rng, dist_real);\n        simd_bits<W> m2(m1);\n        m2.invert_bits();\n        m1 += one;\n        m1 += m2;\n        ASSERT_EQ(m1, zero);\n    }\n    // m1 += x; m1 = ~m1; m1 += x; m1 is unchanged.\n    for (int i = 0; i < 10; i++) {\n        std::uniform_int_distribution<int> dist_bits(1, 1200);\n        int num_bits = dist_bits(rng);\n        simd_bits<W> m1(num_bits);\n        m1.randomize(num_bits, rng);\n        set_random_words_to_all_set(m1, num_bits, rng, dist_real);\n        simd_bits<W> ref(m1);\n        simd_bits<W> m2(num_bits);\n        m1 += m2;\n        m1.invert_bits();\n        m1 += m2;\n        m1.invert_bits();\n        ASSERT_EQ(m1, ref);\n    }\n    // a + (b + c) == (a + b) + c\n    for (int i = 0; i < 10; i++) {\n        std::uniform_int_distribution<int> dist_bits(1, 1200);\n        int num_bits = dist_bits(rng);\n        simd_bits<W> alhs(num_bits);\n        simd_bits<W> blhs(num_bits);\n        simd_bits<W> clhs(num_bits);\n        simd_bits<W> arhs(num_bits);\n        simd_bits<W> brhs(num_bits);\n        simd_bits<W> crhs(num_bits);\n        set_random_words_to_all_set(alhs, num_bits, rng, dist_real);\n        arhs = alhs;\n        set_random_words_to_all_set(blhs, num_bits, rng, dist_real);\n        brhs = blhs;\n        set_random_words_to_all_set(clhs, num_bits, rng, dist_real);\n        crhs = clhs;\n        blhs += clhs;\n        alhs += blhs;\n        arhs += brhs;\n        arhs += crhs;\n        ASSERT_EQ(alhs, arhs);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, right_shift_assignment, {\n    simd_bits<W> m0(512), m1(512);\n    m0[511] = 1;\n    m0 >>= 64;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        uint64_t pattern = 0ULL;\n        for (size_t k = 0; k < 64; k++) {\n            pattern |= (uint64_t{m0[word * 64 + k]} << k);\n        }\n        if (word != m0.num_u64_padded() - 2) {\n            ASSERT_EQ(pattern, 0ULL);\n        } else {\n            ASSERT_EQ(pattern, uint64_t{1} << 63);\n        }\n    }\n    m1 = m0;\n    m1 >>= 0;\n    for (size_t k = 0; k < 512; k++) {\n        ASSERT_EQ(m0[k], m1[k]);\n    }\n    m0.clear();\n    uint64_t on_off = 0xAAAAAAAAAAAAAAAAULL;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        for (size_t k = 0; k < 64; k++) {\n            m0[word * 64 + k] = (bool)(on_off & (1ULL << k));\n        }\n    }\n    m0 >>= 1;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        uint64_t pattern = 0ULL;\n        for (size_t k = 0; k < 64; k++) {\n            pattern |= (uint64_t{m0[word * 64 + k]} << k);\n        }\n        ASSERT_EQ(pattern, 0x5555555555555555ULL);\n    }\n    m0.clear();\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        for (size_t k = 0; k < 64; k++) {\n            m0[word * 64 + k] = (bool)(on_off & (1ULL << k));\n        }\n    }\n    m0 >>= 128;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        uint64_t pattern = 0ULL;\n        for (size_t k = 0; k < 64; k++) {\n            pattern |= (uint64_t{m0[word * 64 + k]} << k);\n        }\n        if (word < 6) {\n            ASSERT_EQ(pattern, 0xAAAAAAAAAAAAAAAA);\n        } else {\n            ASSERT_EQ(pattern, 0ULL);\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, fuzz_right_shift_assignment, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (int i = 0; i < 5; i++) {\n        std::uniform_int_distribution<int> dist_bits(1, 1200);\n        int num_bits = dist_bits(rng);\n        simd_bits<W> m1(num_bits), m2(num_bits);\n        m1.randomize(num_bits, rng);\n        m2 = m1;\n        std::uniform_int_distribution<size_t> dist_shift(0, (int)m1.num_bits_padded());\n        size_t shift = dist_shift(rng);\n        m1 >>= shift;\n        for (size_t k = 0; k < m1.num_bits_padded() - shift; k++) {\n            ASSERT_EQ(m1[k], m2[k + shift]);\n        }\n        for (size_t k = m1.num_bits_padded() - shift; k < m1.num_bits_padded(); k++) {\n            ASSERT_EQ(m1[k], 0);\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, left_shift_assignment, {\n    simd_bits<W> m0(512), m1(512);\n    for (size_t w = 0; w < m0.num_u64_padded(); w++) {\n        m0.u64[w] = 0xAAAAAAAAAAAAAAAAULL;\n    }\n    m0 <<= 1;\n    m1 = m0;\n    m1 <<= 0;\n    for (size_t k = 0; k < 512; k++) {\n        ASSERT_EQ(m0[k], m1[k]);\n    }\n    for (size_t w = 0; w < m0.num_u64_padded(); w++) {\n        if (w == 0) {\n            ASSERT_EQ(m0.u64[w], 0x5555555555555554ULL);\n        } else {\n            ASSERT_EQ(m0.u64[w], 0x5555555555555555ULL);\n        }\n    }\n    m0 <<= 63;\n    for (size_t w = 0; w < m0.num_u64_padded(); w++) {\n        if (w == 0) {\n            ASSERT_EQ(m0.u64[w], 0ULL);\n        } else {\n            ASSERT_EQ(m0.u64[w], 0xAAAAAAAAAAAAAAAAULL);\n        }\n    }\n    m0 <<= 488;\n    ASSERT_TRUE(!m0.not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, fuzz_left_shift_assignment, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (int i = 0; i < 5; i++) {\n        std::uniform_int_distribution<int> dist_bits(1, 1200);\n        int num_bits = dist_bits(rng);\n        simd_bits<W> m1(num_bits), m2(num_bits);\n        m1.randomize(num_bits, rng);\n        m2 = m1;\n        std::uniform_int_distribution<size_t> dist_shift(0, (int)m1.num_bits_padded());\n        size_t shift = dist_shift(rng);\n        m1 <<= shift;\n        for (size_t k = 0; k < m1.num_bits_padded() - shift; k++) {\n            ASSERT_EQ(m1[k + shift], m2[k]);\n        }\n        for (size_t k = 0; k < shift; k++) {\n            ASSERT_EQ(m1[k], 0);\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, assignment, {\n    simd_bits<W> m0(512);\n    simd_bits<W> m1(512);\n    auto rng = INDEPENDENT_TEST_RNG();\n    m0.randomize(512, rng);\n    m1.randomize(512, rng);\n    auto old_m1 = m1.u64[0];\n    ASSERT_NE(m0, m1);\n    m0 = m1;\n    ASSERT_EQ(m0, m1);\n    ASSERT_EQ(m0.u64[0], old_m1);\n    ASSERT_EQ(m1.u64[0], old_m1);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, equality, {\n    simd_bits<W> m0(512);\n    simd_bits<W> m1(512);\n    simd_bits<W> m4(1024);\n\n    ASSERT_TRUE(m0 == m1);\n    ASSERT_FALSE(m0 != m1);\n    ASSERT_FALSE(m0 == m4);\n    ASSERT_TRUE(m0 != m4);\n\n    m1[505] = true;\n    ASSERT_FALSE(m0 == m1);\n    ASSERT_TRUE(m0 != m1);\n    m0[505] = true;\n    ASSERT_TRUE(m0 == m1);\n    ASSERT_FALSE(m0 != m1);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, swap_with, {\n    simd_bits<W> m0(512);\n    simd_bits<W> m1(512);\n    simd_bits<W> m2(512);\n    simd_bits<W> m3(512);\n    auto rng = INDEPENDENT_TEST_RNG();\n    m0.randomize(512, rng);\n    m1.randomize(512, rng);\n    m2 = m0;\n    m3 = m1;\n    ASSERT_EQ(m0, m2);\n    ASSERT_EQ(m1, m3);\n    m0.swap_with(m1);\n    ASSERT_EQ(m0, m3);\n    ASSERT_EQ(m1, m2);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, clear, {\n    simd_bits<W> m0(512);\n    auto rng = INDEPENDENT_TEST_RNG();\n    m0.randomize(512, rng);\n    ASSERT_TRUE(m0.not_zero());\n    m0.clear();\n    ASSERT_TRUE(!m0.not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, not_zero, {\n    simd_bits<W> m0(512);\n    ASSERT_FALSE(m0.not_zero());\n    m0[5] = true;\n    ASSERT_TRUE(m0.not_zero());\n    m0[511] = true;\n    ASSERT_TRUE(m0.not_zero());\n    m0[5] = false;\n    ASSERT_TRUE(m0.not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, word_range_ref, {\n    simd_bits<W> d(1024);\n    const simd_bits<W> &cref = d;\n    auto r1 = d.word_range_ref(1, 2);\n    auto r2 = d.word_range_ref(2, 2);\n    r1[1] = true;\n    ASSERT_TRUE(!r2.not_zero());\n    auto k = W + 1;\n    ASSERT_EQ(r1[k], false);\n    r2[1] = true;\n    ASSERT_EQ(r1[k], true);\n    ASSERT_EQ(cref.word_range_ref(1, 2)[k], true);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, invert_bits, {\n    simd_bits<W> r(100);\n    r[5] = true;\n    r.invert_bits();\n    for (size_t k = 0; k < 100; k++) {\n        ASSERT_EQ(r[k], k != 5);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, mask_assignment_and, {\n    simd_bits<W> a(4);\n    simd_bits<W> b(4);\n    a[2] = true;\n    a[3] = true;\n    b[1] = true;\n    b[3] = true;\n    b &= a;\n    simd_bits<W> expected(4);\n    expected[3] = true;\n    ASSERT_EQ(b, expected);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, mask_assignment_or, {\n    simd_bits<W> a(4);\n    simd_bits<W> b(4);\n    a[2] = true;\n    a[3] = true;\n    b[1] = true;\n    b[3] = true;\n    b |= a;\n    simd_bits<W> expected(4);\n    expected[1] = true;\n    expected[2] = true;\n    expected[3] = true;\n    ASSERT_EQ(b, expected);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, truncated_overwrite_from, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> dat = simd_bits<W>::random(1024, rng);\n    simd_bits<W> mut = simd_bits<W>::random(1024, rng);\n    simd_bits<W> old = mut;\n\n    mut.truncated_overwrite_from(dat, 455);\n\n    for (size_t k = 0; k < 1024; k++) {\n        ASSERT_EQ(mut[k], k < 455 ? dat[k] : old[k]) << k;\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, popcnt, {\n    simd_bits<W> data(1024);\n    ASSERT_EQ(data.popcnt(), 0);\n    data[101] = 1;\n    ASSERT_EQ(data.popcnt(), 1);\n    data[0] = 1;\n    ASSERT_EQ(data.popcnt(), 2);\n    data.u64[8] = 0xFFFFFFFFFFFFFFFFULL;\n    ASSERT_EQ(data.popcnt(), 66);\n    ASSERT_EQ(simd_bits<W>(0).popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, countr_zero, {\n    simd_bits<W> data(1024);\n    ASSERT_EQ(data.countr_zero(), SIZE_MAX);\n    data[1000] = 1;\n    ASSERT_EQ(data.countr_zero(), 1000);\n    data[101] = 1;\n    ASSERT_EQ(data.countr_zero(), 101);\n    data[260] = 1;\n    ASSERT_EQ(data.countr_zero(), 101);\n    data[0] = 1;\n    ASSERT_EQ(data.countr_zero(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, prefix_ref, {\n    simd_bits<W> data(1024);\n    auto prefix = data.prefix_ref(257);\n    ASSERT_TRUE(prefix.num_bits_padded() >= 257);\n    ASSERT_TRUE(prefix.num_bits_padded() < 1024);\n    ASSERT_FALSE(data[0]);\n    prefix[0] = true;\n    ASSERT_TRUE(data[0]);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, out_of_place_bit_masking, {\n    simd_bits<W> m0(4);\n    simd_bits<W> m1(4);\n    m0.ptr_simd[0] = simd_word<W>(0b0101);\n    m1.ptr_simd[0] = simd_word<W>(0b0011);\n    ASSERT_EQ((m0 & m1).ptr_simd[0], 0b0001);\n    ASSERT_EQ((m0 | m1).ptr_simd[0], 0b0111);\n    ASSERT_EQ((m0 ^ m1).ptr_simd[0], 0b0110);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, destructive_resize, {\n    simd_bits<W> m0(512);\n    m0[0] = true;\n    ASSERT_TRUE(m0.not_zero());\n    m0.destructive_resize(256);\n    ASSERT_FALSE(m0.not_zero());\n    m0[0] = true;\n    ASSERT_TRUE(m0.not_zero());\n    m0.destructive_resize(512);\n    ASSERT_FALSE(m0.not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits, preserving_resize, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> m0(256);\n    m0.randomize(m0.num_bits_padded(), rng);\n    auto copy = m0;\n    m0.preserving_resize(512);\n    ASSERT_EQ(m0.ptr_simd[0], copy.ptr_simd[0]);\n    m0.preserving_resize(256);\n    ASSERT_EQ(m0, copy);\n})\n"
  },
  {
    "path": "src/stim/mem/simd_bits_range_ref.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_SIMD_BITS_RANGE_REF_H\n#define _STIM_MEM_SIMD_BITS_RANGE_REF_H\n\n#include <array>\n#include <iostream>\n#include <random>\n#include <vector>\n\n#include \"stim/mem/bit_ref.h\"\n#include \"stim/mem/simd_word.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nconstexpr size_t min_bits_to_num_bits_padded(size_t min_bits) {\n    return (min_bits + (sizeof(bitword<W>) * 8 - 1)) & ~(sizeof(bitword<W>) * 8 - 1);\n}\n\ntemplate <size_t W>\nconstexpr size_t min_bits_to_num_simd_words(size_t min_bits) {\n    return (min_bits_to_num_bits_padded<W>(min_bits) / sizeof(bitword<W>)) >> 3;\n}\n\n/// A reference to a range of bits that support SIMD operations (e.g. they are aligned and padded correctly).\n///\n/// Conceptually behaves the same as a reference like `int &`, as opposed to a pointer like `int *`. For example, the\n/// `=` operator overwrites the contents of the range being referenced instead of changing which range is pointed to.\ntemplate <size_t W>\nstruct simd_bits_range_ref {\n    union {\n        // It is fair to say that this is the most dangerous block, or danger-enabling block, in the entire codebase.\n        // C++ is very particular when it comes to touching the same memory as if it had multiple different types.\n        // If you know how to make something *for sure work as a flexibly-accessible bag of bits*, please fix this.\n        // In the meantime, always build with `-fno-strict-aliasing` and a short ritual prayer to the compiler gods.\n        uint8_t *const u8;\n        uint64_t *const u64;\n        bitword<W> *const ptr_simd;\n    };\n    const size_t num_simd_words;\n\n    /// Construct a simd_bits_range_ref from a given pointer and word count.\n    simd_bits_range_ref(bitword<W> *ptr_simd, size_t num_simd_words);\n\n    /// Overwrite assignment.\n    simd_bits_range_ref operator=(\n        const simd_bits_range_ref\n            other);  // NOLINT(cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator)\n    /// Xor assignment.\n    simd_bits_range_ref operator^=(const simd_bits_range_ref other);\n    /// Mask assignment.\n    simd_bits_range_ref operator&=(const simd_bits_range_ref other);\n    simd_bits_range_ref operator|=(const simd_bits_range_ref other);\n    // Addition assigment\n    simd_bits_range_ref operator+=(const simd_bits_range_ref<W> other);\n    simd_bits_range_ref operator-=(const simd_bits_range_ref<W> other);\n    // Shift assigment\n    simd_bits_range_ref operator>>=(int offset);\n    simd_bits_range_ref operator<<=(int offset);\n    /// Swap assignment.\n    void swap_with(simd_bits_range_ref other);\n\n    /// Equality.\n    bool operator==(const simd_bits_range_ref<W> &other) const;\n    /// Inequality.\n    bool operator!=(const simd_bits_range_ref<W> &other) const;\n    /// Determines whether or not any of the bits in the referenced range are non-zero.\n    bool not_zero() const;\n    /// Treats the referenced range as an unsigned integer, and returns it as a uint64_t.\n    /// If the integer is too large  to fit, an exception is raised.\n    uint64_t as_u64() const;\n\n    /// Returns a reference to a given bit within the referenced range.\n    inline bit_ref operator[](size_t k) {\n        return bit_ref(u8, k);\n    }\n    /// Returns a const reference to a given bit within the referenced range.\n    inline const bit_ref operator[](size_t k) const {\n        return bit_ref(u8, k);\n    }\n    /// Returns a reference to a sub-range of the bits at the start of this simd_bits.\n    inline simd_bits_range_ref prefix_ref(size_t unpadded_bit_length) {\n        return simd_bits_range_ref(ptr_simd, min_bits_to_num_simd_words<W>(unpadded_bit_length));\n    }\n    /// Returns a reference to a sub-range of the bits in the referenced range.\n    inline simd_bits_range_ref word_range_ref(size_t word_offset, size_t sub_num_simd_words) {\n        return simd_bits_range_ref(ptr_simd + word_offset, sub_num_simd_words);\n    }\n    /// Returns a const reference to a sub-range of the bits in the referenced range.\n    inline const simd_bits_range_ref word_range_ref(size_t word_offset, size_t sub_num_simd_words) const {\n        return simd_bits_range_ref(ptr_simd + word_offset, sub_num_simd_words);\n    }\n\n    /// Inverts all bits in the referenced range.\n    void invert_bits();\n    /// Sets all bits in the referenced range to zero.\n    void clear();\n    /// Randomizes the bits in the referenced range, up to the given bit count. Leaves further bits unchanged.\n    void randomize(size_t num_bits, std::mt19937_64 &rng);\n    /// Returns the number of bits that are 1 in the bit range.\n    size_t popcnt() const;\n    /// Returns the power-of-two-ness of the number, or SIZE_MAX if the number has no 1s.\n    size_t countr_zero() const;\n    /// Returns whether or not the two ranges have set bits in common.\n    bool intersects(const simd_bits_range_ref other) const;\n    /// Returns whether or not all bits that are set in `other` are also set in this range.\n    bool is_subset_of_or_equal_to(const simd_bits_range_ref<W> other) const;\n\n    /// Writes bits from another location.\n    /// Bits not part of the write are unchanged.\n    void truncated_overwrite_from(simd_bits_range_ref other, size_t num_bits);\n\n    /// Returns a description of the contents of the range.\n    std::string str() const;\n\n    /// Number of 64 bit words in the referenced range.\n    inline size_t num_u64_padded() const {\n        return num_simd_words * (sizeof(bitword<W>) / sizeof(uint64_t));\n    }\n    /// Number of 32 bit words in the referenced range.\n    inline size_t num_u32_padded() const {\n        return num_simd_words * (sizeof(bitword<W>) / sizeof(uint32_t));\n    }\n    /// Number of 16 bit words in the referenced range.\n    inline size_t num_u16_padded() const {\n        return num_simd_words * (sizeof(bitword<W>) / sizeof(uint16_t));\n    }\n    /// Number of 8 bit words in the referenced range.\n    inline size_t num_u8_padded() const {\n        return num_simd_words * (sizeof(bitword<W>) / sizeof(uint8_t));\n    }\n    /// Number of bits in the referenced range.\n    inline size_t num_bits_padded() const {\n        return num_simd_words * sizeof(bitword<W>) << 3;\n    }\n\n    /// Sets all bits at the given position and beyond it to 0.\n    void clear_bits_past(size_t num_kept_bits);\n\n    /// Runs a function on each word in the range, in sequential order.\n    ///\n    /// The words are passed by reference and have type bitword<W>.\n    ///\n    /// This is a boilerplate reduction method. It could be an iterator, but when experimenting I found that the\n    /// compiler seemed much more amenable to inline the function in the way I wanted when using this approach rather\n    /// than iterators.\n    ///\n    /// Example:\n    ///     size_t simd_popcount(simd_bits_range_ref data) {\n    ///         size_t popcount = 0;\n    ///         data.for_each_word([&](auto &w) {\n    ///             popcount += w.popcount();\n    ///         });\n    ///         return popcount;\n    ///     }\n    ///\n    /// HACK: Templating the function type makes inlining significantly more likely.\n    template <typename FUNC>\n    inline void for_each_word(FUNC body) const {\n        auto *v0 = ptr_simd;\n        auto *v0_end = v0 + num_simd_words;\n        while (v0 != v0_end) {\n            body(*v0);\n            v0++;\n        }\n    }\n\n    /// Runs a function on paired up words from two ranges, in sequential order.\n    ///\n    /// The words are passed by reference and have type bitword<W>.\n    ///\n    /// This is a boilerplate reduction method. It could be an iterator, but when experimenting I found that the\n    /// compiler seemed much more amenable to inline the function in the way I wanted when using this approach rather\n    /// than iterators.\n    ///\n    /// Example:\n    ///     void xor_left_into_right(simd_bits_range_ref data1, simd_bits_range_ref data2) {\n    ///         data1.for_each_word(data2, [&](auto &w1, auto &w2) {\n    ///             w2 ^= w1;\n    ///         });\n    ///     }\n    ///\n    /// HACK: Templating the function type makes inlining significantly more likely.\n    template <typename FUNC>\n    inline void for_each_word(simd_bits_range_ref<W> other, FUNC body) const {\n        auto *v0 = ptr_simd;\n        auto *v1 = other.ptr_simd;\n        auto *v0_end = v0 + num_simd_words;\n        while (v0 != v0_end) {\n            body(*v0, *v1);\n            v0++;\n            v1++;\n        }\n    }\n\n    /// Runs a function on paired up words from three ranges, in sequential order.\n    ///\n    /// The words are passed by reference and have type bitword<W>.\n    ///\n    /// This is a boilerplate reduction method. It could be an iterator, but when experimenting I found that the\n    /// compiler seemed much more amenable to inline the function in the way I wanted when using this approach rather\n    /// than iterators.\n    ///\n    /// Example:\n    ///     void xor_intersection_into_last(simd_bits_range_ref data1, simd_bits_range_ref data2, simd_bits_range_ref\n    ///     data3) {\n    ///         data1.for_each_word(data2, data3, [&](auto &w1, auto &w2, auto &w3) {\n    ///             w3 ^= w1 & w2;\n    ///         });\n    ///     }\n    ///\n    /// HACK: Templating the function type makes inlining significantly more likely.\n    template <typename FUNC>\n    inline void for_each_word(simd_bits_range_ref<W> other1, simd_bits_range_ref<W> other2, FUNC body) const {\n        auto *v0 = ptr_simd;\n        auto *v1 = other1.ptr_simd;\n        auto *v2 = other2.ptr_simd;\n        auto *v0_end = v0 + num_simd_words;\n        while (v0 != v0_end) {\n            body(*v0, *v1, *v2);\n            v0++;\n            v1++;\n            v2++;\n        }\n    }\n\n    /// Runs a function on paired up words from four ranges, in sequential order.\n    ///\n    /// The words are passed by reference and have type bitword<W>.\n    ///\n    /// This is a boilerplate reduction method. It could be an iterator, but when experimenting I found that the\n    /// compiler seemed much more amenable to inline the function in the way I wanted when using this approach rather\n    /// than iterators.\n    ///\n    /// Example:\n    ///     void xor_union_into_last(\n    ///             simd_bits_range_ref data1, simd_bits_range_ref data2, simd_bits_range_ref data3, simd_bits_range_ref\n    ///             data4) {\n    ///         data1.for_each_word(data2, data3, data4, [&](auto &w1, auto &w2, auto &w3, auto &w4) {\n    ///             w4 ^= w1 | w2 | w3;\n    ///         });\n    ///     }\n    ///\n    /// HACK: Templating the function type makes inlining significantly more likely.\n    template <typename FUNC>\n    inline void for_each_word(\n        simd_bits_range_ref<W> other1, simd_bits_range_ref<W> other2, simd_bits_range_ref<W> other3, FUNC body) const {\n        auto *v0 = ptr_simd;\n        auto *v1 = other1.ptr_simd;\n        auto *v2 = other2.ptr_simd;\n        auto *v3 = other3.ptr_simd;\n        auto *v0_end = v0 + num_simd_words;\n        while (v0 != v0_end) {\n            body(*v0, *v1, *v2, *v3);\n            v0++;\n            v1++;\n            v2++;\n            v3++;\n        }\n    }\n\n    /// Runs a function on paired up words from five ranges, in sequential order.\n    ///\n    /// The words are passed by reference and have type bitword<W>.\n    ///\n    /// This is a boilerplate reduction method. It could be an iterator, but when experimenting I found that the\n    /// compiler seemed much more amenable to inline the function in the way I wanted when using this approach rather\n    /// than iterators.\n    ///\n    /// Example:\n    ///     void xor_union_into_last(\n    ///             simd_bits_range_ref data1,\n    ///             simd_bits_range_ref data2,\n    ///             simd_bits_range_ref data3,\n    ///             simd_bits_range_ref data4,\n    ///             simd_bits_range_ref data5) {\n    ///         data1.for_each_word(data2, data3, data4, data5, [&](auto &w1, auto &w2, auto &w3, auto &w4, auto &w5) {\n    ///             w5 ^= w1 | w2 | w3 | w4;\n    ///         });\n    ///     }\n    ///\n    /// HACK: Templating the function type makes inlining significantly more likely.\n    template <typename FUNC>\n    inline void for_each_word(\n        simd_bits_range_ref<W> other1,\n        simd_bits_range_ref<W> other2,\n        simd_bits_range_ref<W> other3,\n        simd_bits_range_ref<W> other4,\n        FUNC body) const {\n        auto *v0 = ptr_simd;\n        auto *v1 = other1.ptr_simd;\n        auto *v2 = other2.ptr_simd;\n        auto *v3 = other3.ptr_simd;\n        auto *v4 = other4.ptr_simd;\n        auto *v0_end = v0 + num_simd_words;\n        while (v0 != v0_end) {\n            body(*v0, *v1, *v2, *v3, *v4);\n            v0++;\n            v1++;\n            v2++;\n            v3++;\n            v4++;\n        }\n    }\n\n    template <typename CALLBACK>\n    void for_each_set_bit(CALLBACK callback) {\n        size_t n = num_u64_padded();\n        for (size_t w = 0; w < n; w++) {\n            uint64_t v = u64[w];\n            while (v) {\n                size_t q = w * 64 + std::countr_zero(v);\n                v &= v - 1;\n                callback(q);\n            }\n        }\n    }\n};\n\n/// Writes a description of the contents of the range to `out`.\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const simd_bits_range_ref<W> m);\n\n}  // namespace stim\n\n#include \"stim/mem/simd_bits_range_ref.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/simd_bits_range_ref.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <cstring>\n#include <sstream>\n\n#include \"stim/mem/simd_util.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nsimd_bits_range_ref<W>::simd_bits_range_ref(bitword<W> *ptr_simd_init, size_t num_simd_words)\n    : ptr_simd(ptr_simd_init), num_simd_words(num_simd_words) {\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> simd_bits_range_ref<W>::operator^=(const simd_bits_range_ref<W> other) {\n    for_each_word(other, [](bitword<W> &w0, bitword<W> &w1) {\n        w0 ^= w1;\n    });\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> simd_bits_range_ref<W>::operator|=(const simd_bits_range_ref<W> other) {\n    for_each_word(other, [](bitword<W> &w0, bitword<W> &w1) {\n        w0 |= w1;\n    });\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> simd_bits_range_ref<W>::operator&=(const simd_bits_range_ref<W> other) {\n    for_each_word(other, [](bitword<W> &w0, bitword<W> &w1) {\n        w0 &= w1;\n    });\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> simd_bits_range_ref<W>::operator=(const simd_bits_range_ref<W> other) {\n    memcpy(ptr_simd, other.ptr_simd, num_u8_padded());\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> simd_bits_range_ref<W>::operator+=(const simd_bits_range_ref<W> other) {\n    size_t num_u64 = num_u64_padded();\n    uint64_t carry{0};\n    for (size_t w = 0; w < num_u64; w++) {\n        uint64_t val_before = u64[w];\n        u64[w] += other.u64[w] + carry;\n        carry = u64[w] < val_before || (carry & (val_before == u64[w]));\n    }\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> simd_bits_range_ref<W>::operator-=(const simd_bits_range_ref<W> other) {\n    invert_bits();\n    *this += other;\n    invert_bits();\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> simd_bits_range_ref<W>::operator>>=(int offset) {\n    uint64_t incoming_word;\n    uint64_t cur_word;\n    if (offset == 0) {\n        return *this;\n    }\n    while (offset >= 64) {\n        incoming_word = 0ULL;\n        for (int w = num_u64_padded() - 1; w >= 0; w--) {\n            cur_word = u64[w];\n            u64[w] = incoming_word;\n            incoming_word = cur_word;\n        }\n        offset -= 64;\n    }\n    if (offset == 0) {\n        return *this;\n    }\n    incoming_word = 0ULL;\n    for (int w = num_u64_padded() - 1; w >= 0; w--) {\n        cur_word = u64[w];\n        u64[w] >>= offset;\n        u64[w] |= incoming_word << (64 - offset);\n        incoming_word = cur_word & ((uint64_t{1} << offset) - 1);\n    }\n    return *this;\n}\n\ntemplate <size_t W>\nsimd_bits_range_ref<W> simd_bits_range_ref<W>::operator<<=(int offset) {\n    uint64_t incoming_word;\n    uint64_t cur_word;\n    if (offset == 0) {\n        return *this;\n    }\n    while (offset >= 64) {\n        incoming_word = 0ULL;\n        for (size_t w = 0; w < num_u64_padded(); w++) {\n            cur_word = u64[w];\n            u64[w] = incoming_word;\n            incoming_word = cur_word;\n        }\n        offset -= 64;\n    }\n    if (offset == 0) {\n        return *this;\n    }\n    incoming_word = 0ULL;\n    for (size_t w = 0; w < num_u64_padded(); w++) {\n        cur_word = u64[w];\n        u64[w] <<= offset;\n        u64[w] |= incoming_word;\n        incoming_word = (cur_word >> (64 - offset));\n    }\n    return *this;\n}\n\ntemplate <size_t W>\nvoid simd_bits_range_ref<W>::swap_with(simd_bits_range_ref<W> other) {\n    for_each_word(other, [](bitword<W> &w0, bitword<W> &w1) {\n        std::swap(w0, w1);\n    });\n}\n\ntemplate <size_t W>\nvoid simd_bits_range_ref<W>::invert_bits() {\n    auto mask = bitword<W>::tile8(0xFF);\n    for_each_word([&mask](bitword<W> &w) {\n        w ^= mask;\n    });\n}\n\ntemplate <size_t W>\nvoid simd_bits_range_ref<W>::clear() {\n    memset(u8, 0, num_u8_padded());\n}\n\ntemplate <size_t W>\nbool simd_bits_range_ref<W>::operator==(const simd_bits_range_ref<W> &other) const {\n    return num_simd_words == other.num_simd_words && memcmp(ptr_simd, other.ptr_simd, num_u8_padded()) == 0;\n}\n\ntemplate <size_t W>\nbool simd_bits_range_ref<W>::not_zero() const {\n    bitword<W> acc{};\n    for_each_word([&acc](bitword<W> &w) {\n        acc |= w;\n    });\n    return (bool)acc;\n}\n\ntemplate <size_t W>\nbool simd_bits_range_ref<W>::operator!=(const simd_bits_range_ref<W> &other) const {\n    return !(*this == other);\n}\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const simd_bits_range_ref<W> m) {\n    for (size_t k = 0; k < m.num_bits_padded(); k++) {\n        out << \"_1\"[m[k]];\n    }\n    return out;\n}\n\ntemplate <size_t W>\nstd::string simd_bits_range_ref<W>::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\ntemplate <size_t W>\nvoid simd_bits_range_ref<W>::randomize(size_t num_bits, std::mt19937_64 &rng) {\n    auto n = num_bits >> 6;\n    for (size_t k = 0; k < n; k++) {\n        u64[k] = rng();\n    }\n    auto leftover = num_bits & 63;\n    if (leftover) {\n        uint64_t mask = ((uint64_t)1 << leftover) - 1;\n        u64[n] &= ~mask;\n        u64[n] |= rng() & mask;\n    }\n}\n\ntemplate <size_t W>\nvoid simd_bits_range_ref<W>::truncated_overwrite_from(simd_bits_range_ref<W> other, size_t num_bits) {\n    size_t n8 = num_bits >> 3;\n    memcpy(u8, other.u8, n8);\n    if (num_bits & 7) {\n        uint8_t m8 = uint8_t{0xFF} >> (8 - (num_bits & 7));\n        u8[n8] &= ~m8;\n        u8[n8] |= other.u8[n8] & m8;\n    }\n}\n\ntemplate <size_t W>\nvoid simd_bits_range_ref<W>::clear_bits_past(size_t num_kept_bits) {\n    if (num_kept_bits >= num_bits_padded()) {\n        return;\n    }\n    size_t n8 = num_kept_bits >> 3;\n    if (num_kept_bits & 7) {\n        uint8_t m8 = uint8_t{0xFF} >> (8 - (num_kept_bits & 7));\n        u8[n8] &= m8;\n        memset(u8 + n8 + 1, 0, num_u8_padded() - n8 - 1);\n    } else {\n        memset(u8 + n8, 0, num_u8_padded() - n8);\n    }\n}\n\ntemplate <size_t W>\nsize_t simd_bits_range_ref<W>::popcnt() const {\n    auto end = u64 + num_u64_padded();\n    size_t result = 0;\n    for (const uint64_t *p = u64; p != end; p++) {\n        result += std::popcount(*p);\n    }\n    return result;\n}\n\ntemplate <size_t W>\nsize_t simd_bits_range_ref<W>::countr_zero() const {\n    size_t n = num_u64_padded();\n    for (size_t k = 0; k < n; k++) {\n        uint64_t u = u64[k];\n        if (u) {\n            for (size_t r = 0; r < 64; r++) {\n                if ((u >> r) & 1) {\n                    return r + 64 * k;\n                }\n            }\n        }\n    }\n    return SIZE_MAX;\n}\n\ntemplate <size_t W>\nbool simd_bits_range_ref<W>::intersects(const simd_bits_range_ref<W> other) const {\n    size_t n = std::min(num_u64_padded(), other.num_u64_padded());\n    uint64_t v = 0;\n    for (size_t k = 0; k < n; k++) {\n        v |= u64[k] & other.u64[k];\n    }\n    return v != 0;\n}\n\ntemplate <size_t W>\nbool simd_bits_range_ref<W>::is_subset_of_or_equal_to(const simd_bits_range_ref<W> other) const {\n    size_t n = std::min(num_u64_padded(), other.num_u64_padded());\n    uint64_t v = 0;\n    for (size_t k = 0; k < n; k++) {\n        v |= u64[k] & ~other.u64[k];\n    }\n    for (size_t k = other.num_u64_padded(); k < num_u64_padded(); k++) {\n        v |= u64[k];\n    }\n    return v == 0;\n}\n\ntemplate <size_t W>\nuint64_t simd_bits_range_ref<W>::as_u64() const {\n    size_t n64 = num_u64_padded();\n    for (size_t k = 1; k < n64; k++) {\n        if (u64[k]) {\n            throw std::invalid_argument(\"Too large to fit into a uint64_t.\");\n        }\n    }\n    size_t n1 = std::min(num_bits_padded(), (size_t)64);\n    uint64_t v = 0;\n    for (size_t k = 0; k < n1; k++) {\n        v ^= uint64_t{(*this)[k]} << k;\n    }\n    return v;\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/mem/simd_bits_range_ref.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_bits_range_ref.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, construct, {\n    alignas(64) std::array<uint64_t, 16> data{};\n    simd_bits_range_ref<W> ref((bitword<W> *)data.data(), sizeof(data) / (W / 8));\n\n    ASSERT_EQ(ref.ptr_simd, (bitword<W> *)&data[0]);\n    ASSERT_EQ(ref.num_simd_words, 16 * sizeof(uint64_t) / sizeof(bitword<W>));\n    ASSERT_EQ(ref.num_bits_padded(), 1024);\n    ASSERT_EQ(ref.num_u8_padded(), 128);\n    ASSERT_EQ(ref.num_u16_padded(), 64);\n    ASSERT_EQ(ref.num_u32_padded(), 32);\n    ASSERT_EQ(ref.num_u64_padded(), 16);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, aliased_editing_and_bit_refs, {\n    alignas(64) std::array<uint64_t, 16> data{};\n    auto c = (char *)&data;\n    simd_bits_range_ref<W> ref((bitword<W> *)data.data(), sizeof(data) / sizeof(bitword<W>));\n    const simd_bits_range_ref<W> cref((bitword<W> *)data.data(), sizeof(data) / sizeof(bitword<W>));\n\n    ASSERT_EQ(c[0], 0);\n    ASSERT_EQ(c[13], 0);\n    ref[5] = true;\n    ASSERT_EQ(c[0], 32);\n    ref[0] = true;\n    ASSERT_EQ(c[0], 33);\n    ref[100] = true;\n    ASSERT_EQ(ref[100], true);\n    ASSERT_EQ(c[12], 16);\n    c[12] = 0;\n    ASSERT_EQ(ref[100], false);\n    ASSERT_EQ(cref[100], ref[100]);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, str, {\n    alignas(64) std::array<uint64_t, 8> data{};\n    simd_bits_range_ref<W> ref((bitword<W> *)data.data(), sizeof(data) / sizeof(bitword<W>));\n    ASSERT_EQ(\n        ref.str(),\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\");\n    ref[5] = 1;\n    ASSERT_EQ(\n        ref.str(),\n        \"_____1__________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\"\n        \"________________________________________________________________\");\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, randomize, {\n    alignas(64) std::array<uint64_t, 16> data{};\n    simd_bits_range_ref<W> ref((bitword<W> *)data.data(), sizeof(data) / sizeof(bitword<W>));\n\n    auto rng = INDEPENDENT_TEST_RNG();\n    ref.randomize(64 + 57, rng);\n    uint64_t mask = (1ULL << 57) - 1;\n    // Randomized.\n    ASSERT_NE(ref.u64[0], 0);\n    ASSERT_NE(ref.u64[0], SIZE_MAX);\n    ASSERT_NE(ref.u64[1] & mask, 0);\n    ASSERT_NE(ref.u64[1] & mask, 0);\n    // Not touched.\n    ASSERT_EQ(ref.u64[1] & ~mask, 0);\n    ASSERT_EQ(ref.u64[2], 0);\n    ASSERT_EQ(ref.u64[3], 0);\n\n    for (size_t k = 0; k < ref.num_u64_padded(); k++) {\n        ref.u64[k] = UINT64_MAX;\n    }\n    ref.randomize(64 + 57, rng);\n    // Randomized.\n    ASSERT_NE(ref.u64[0], 0);\n    ASSERT_NE(ref.u64[0], SIZE_MAX);\n    ASSERT_NE(ref.u64[1] & mask, 0);\n    ASSERT_NE(ref.u64[1] & mask, 0);\n    // Not touched.\n    ASSERT_EQ(ref.u64[1] & ~mask, UINT64_MAX & ~mask);\n    ASSERT_EQ(ref.u64[2], UINT64_MAX);\n    ASSERT_EQ(ref.u64[3], UINT64_MAX);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, xor_assignment, {\n    alignas(64) std::array<uint64_t, 24> data{};\n    simd_bits_range_ref<W> m0((bitword<W> *)&data[0], sizeof(data) / sizeof(bitword<W>) / 3);\n    simd_bits_range_ref<W> m1((bitword<W> *)&data[8], sizeof(data) / sizeof(bitword<W>) / 3);\n    simd_bits_range_ref<W> m2((bitword<W> *)&data[16], sizeof(data) / sizeof(bitword<W>) / 3);\n    auto rng = INDEPENDENT_TEST_RNG();\n    m0.randomize(512, rng);\n    m1.randomize(512, rng);\n    ASSERT_NE(m0, m1);\n    ASSERT_NE(m0, m2);\n    m2 ^= m0;\n    ASSERT_EQ(m0, m2);\n    m2 ^= m1;\n    for (size_t k = 0; k < m0.num_u64_padded(); k++) {\n        ASSERT_EQ(m2.u64[k], m0.u64[k] ^ m1.u64[k]);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, assignment, {\n    alignas(64) std::array<uint64_t, 16> data{};\n    simd_bits_range_ref<W> m0((bitword<W> *)&data[0], sizeof(data) / sizeof(bitword<W>) / 2);\n    simd_bits_range_ref<W> m1((bitword<W> *)&data[8], sizeof(data) / sizeof(bitword<W>) / 2);\n    auto rng = INDEPENDENT_TEST_RNG();\n    m0.randomize(512, rng);\n    m1.randomize(512, rng);\n    auto old_m1 = m1.u64[0];\n    ASSERT_NE(m0, m1);\n    m0 = m1;\n    ASSERT_EQ(m0, m1);\n    ASSERT_EQ(m0.u64[0], old_m1);\n    ASSERT_EQ(m1.u64[0], old_m1);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, equality, {\n    alignas(64) std::array<uint64_t, 32> data{};\n    simd_bits_range_ref<W> m0((bitword<W> *)&data[0], sizeof(data) / sizeof(bitword<W>) / 4);\n    simd_bits_range_ref<W> m1((bitword<W> *)&data[8], sizeof(data) / sizeof(bitword<W>) / 4);\n    simd_bits_range_ref<W> m4((bitword<W> *)&data[16], sizeof(data) / sizeof(bitword<W>) / 2);\n\n    ASSERT_TRUE(m0 == m1);\n    ASSERT_FALSE(m0 != m1);\n    ASSERT_FALSE(m0 == m4);\n    ASSERT_TRUE(m0 != m4);\n\n    m1[505] = 1;\n    ASSERT_FALSE(m0 == m1);\n    ASSERT_TRUE(m0 != m1);\n    m0[505] = 1;\n    ASSERT_TRUE(m0 == m1);\n    ASSERT_FALSE(m0 != m1);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, add_assignment, {\n    alignas(64) std::array<uint64_t, 8> data{\n        0xFFFFFFFFFFFFFFFFULL,\n        0x0F0F0F0F0F0F0F0FULL,\n        0xFFFFFFFFFFFFFFFFULL,\n        0x0F0F0F0F0F0F0F0FULL,\n        0xFFFFFFFFFFFFFFFFULL,\n        0x0F0F0F0F0F0F0F0FULL,\n        0xFFFFFFFFFFFFFFFFULL,\n        0x0F0F0F0F0F0F0F0FULL};\n    simd_bits_range_ref<W> m0((bitword<W> *)&data[0], sizeof(data) / sizeof(bitword<W>) / 2);\n    simd_bits_range_ref<W> m1((bitword<W> *)&data[4], sizeof(data) / sizeof(bitword<W>) / 2);\n    m0 += m1;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        uint64_t pattern = 0ULL;\n        for (size_t k = 0; k < 64; k++) {\n            pattern |= (uint64_t{m0[word * 64 + k]} << k);\n        }\n        if (word % 2 == 0) {\n            ASSERT_EQ(pattern, 0xFFFFFFFFFFFFFFFEULL);\n        } else {\n            ASSERT_EQ(pattern, 0x1E1E1E1E1E1E1E1FULL);\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, right_shift_assignment, {\n    alignas(64) std::array<uint64_t, 8> data{\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n    };\n    simd_bits_range_ref<W> m0((bitword<W> *)&data[0], sizeof(data) / sizeof(bitword<W>));\n    m0 >>= 1;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        uint64_t pattern = 0ULL;\n        for (size_t k = 0; k < 64; k++) {\n            pattern |= (uint64_t{m0[word * 64 + k]} << k);\n        }\n        ASSERT_EQ(pattern, 0x5555555555555555ULL);\n    }\n    m0 >>= 511;\n    ASSERT_TRUE(!m0.not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, left_shift_assignment, {\n    alignas(64) std::array<uint64_t, 8> data{\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n        0xAAAAAAAAAAAAAAAAULL,\n    };\n    simd_bits_range_ref<W> m0((bitword<W> *)&data[0], sizeof(data) / sizeof(bitword<W>));\n    m0 <<= 1;\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        uint64_t pattern = 0ULL;\n        for (size_t k = 0; k < 64; k++) {\n            pattern |= (uint64_t{m0[word * 64 + k]} << k);\n        }\n        if (word == 0) {\n            ASSERT_EQ(pattern, 0x5555555555555554ULL);\n        } else {\n            ASSERT_EQ(pattern, 0x5555555555555555ULL);\n        }\n    }\n    m0 <<= 63;\n    for (size_t w = 0; w < m0.num_u64_padded(); w++) {\n        if (w == 0) {\n            ASSERT_EQ(m0.u64[w], 0ULL);\n        } else {\n            ASSERT_EQ(m0.u64[w], 0xAAAAAAAAAAAAAAAAULL);\n        }\n    }\n    for (size_t word = 0; word < m0.num_u64_padded(); word++) {\n        uint64_t pattern = 0ULL;\n        for (size_t k = 0; k < 64; k++) {\n            pattern |= (uint64_t{m0[word * 64 + k]} << k);\n        }\n        if (word == 0) {\n            ASSERT_EQ(pattern, 0ULL);\n        } else {\n            ASSERT_EQ(pattern, 0xAAAAAAAAAAAAAAAAULL);\n        }\n    }\n    m0 <<= 488;\n    ASSERT_TRUE(!m0.not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, swap_with, {\n    alignas(64) std::array<uint64_t, 32> data{};\n    simd_bits_range_ref<W> m0((bitword<W> *)&data[0], sizeof(data) / sizeof(bitword<W>) / 4);\n    simd_bits_range_ref<W> m1((bitword<W> *)&data[8], sizeof(data) / sizeof(bitword<W>) / 4);\n    simd_bits_range_ref<W> m2((bitword<W> *)&data[16], sizeof(data) / sizeof(bitword<W>) / 4);\n    simd_bits_range_ref<W> m3((bitword<W> *)&data[24], sizeof(data) / sizeof(bitword<W>) / 4);\n    auto rng = INDEPENDENT_TEST_RNG();\n    m0.randomize(512, rng);\n    m1.randomize(512, rng);\n    m2 = m0;\n    m3 = m1;\n    ASSERT_EQ(m0, m2);\n    ASSERT_EQ(m1, m3);\n    m0.swap_with(m1);\n    ASSERT_EQ(m0, m3);\n    ASSERT_EQ(m1, m2);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, clear, {\n    alignas(64) std::array<uint64_t, 8> data{};\n    simd_bits_range_ref<W> m0((bitword<W> *)&data[0], sizeof(data) / sizeof(bitword<W>));\n    auto rng = INDEPENDENT_TEST_RNG();\n    m0.randomize(512, rng);\n    ASSERT_TRUE(m0.not_zero());\n    m0.clear();\n    ASSERT_TRUE(!m0.not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, not_zero256, {\n    alignas(64) std::array<uint64_t, 8> data{};\n    simd_bits_range_ref<W> m0((bitword<W> *)&data[0], sizeof(data) / sizeof(bitword<W>));\n    ASSERT_FALSE(m0.not_zero());\n    m0[5] = true;\n    ASSERT_TRUE(m0.not_zero());\n    m0[511] = true;\n    ASSERT_TRUE(m0.not_zero());\n    m0[5] = false;\n    ASSERT_TRUE(m0.not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, word_range_ref, {\n    bitword<W> d[sizeof(uint64_t) * 16 / sizeof(bitword<W>)]{};\n    simd_bits_range_ref<W> ref(d, sizeof(d) / sizeof(bitword<W>));\n    const simd_bits_range_ref<W> cref(d, sizeof(d) / sizeof(bitword<W>));\n    auto r1 = ref.word_range_ref(1, 2);\n    auto r2 = ref.word_range_ref(2, 2);\n    r1[1] = true;\n    ASSERT_TRUE(!r2.not_zero());\n    auto k = sizeof(bitword<W>) * 8 + 1;\n    ASSERT_EQ(r1[k], false);\n    r2[1] = true;\n    ASSERT_EQ(r1[k], true);\n    ASSERT_EQ(cref.word_range_ref(1, 2)[k], true);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, for_each_set_bit, {\n    simd_bits<W> data(256);\n    simd_bits_range_ref<W> ref(data);\n    ref[5] = true;\n    ref[101] = true;\n    std::vector<size_t> hits;\n    ref.for_each_set_bit([&](size_t k) {\n        hits.push_back(k);\n    });\n    ASSERT_EQ(hits, (std::vector<size_t>{5, 101}));\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, truncated_overwrite_from, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> dat = simd_bits<W>::random(1024, rng);\n    simd_bits<W> mut = simd_bits<W>::random(1024, rng);\n    simd_bits<W> old = mut;\n\n    simd_bits_range_ref<W>(mut).truncated_overwrite_from(dat, 455);\n\n    for (size_t k = 0; k < 1024; k++) {\n        ASSERT_EQ(mut[k], k < 455 ? dat[k] : old[k]) << k;\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, popcnt, {\n    simd_bits<W> data(1024);\n    simd_bits_range_ref<W> ref(data);\n    ASSERT_EQ(ref.popcnt(), 0);\n    data[101] = 1;\n    ASSERT_EQ(ref.popcnt(), 1);\n    data[0] = 1;\n    ASSERT_EQ(ref.popcnt(), 2);\n    data.u64[8] = 0xFFFFFFFFFFFFFFFFULL;\n    ASSERT_EQ(ref.popcnt(), 66);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, countr_zero, {\n    simd_bits<W> data(1024);\n    simd_bits_range_ref<W> ref(data);\n    ASSERT_EQ(ref.countr_zero(), SIZE_MAX);\n    data[1000] = 1;\n    ASSERT_EQ(ref.countr_zero(), 1000);\n    data[101] = 1;\n    ASSERT_EQ(ref.countr_zero(), 101);\n    data[260] = 1;\n    ASSERT_EQ(ref.countr_zero(), 101);\n    data[0] = 1;\n    ASSERT_EQ(ref.countr_zero(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, intersects, {\n    simd_bits<W> data(1024);\n    simd_bits<W> other(512);\n    simd_bits_range_ref<W> ref(data);\n    ASSERT_EQ(data.intersects(other), false);\n    ASSERT_EQ(ref.intersects(other), false);\n    other[511] = true;\n    ASSERT_EQ(data.intersects(other), false);\n    ASSERT_EQ(ref.intersects(other), false);\n    data[513] = true;\n    ASSERT_EQ(data.intersects(other), false);\n    ASSERT_EQ(ref.intersects(other), false);\n    data[511] = true;\n    ASSERT_EQ(data.intersects(other), true);\n    ASSERT_EQ(ref.intersects(other), true);\n    data[101] = true;\n    ASSERT_EQ(data.intersects(other), true);\n    ASSERT_EQ(ref.intersects(other), true);\n    other[101] = true;\n    ASSERT_EQ(data.intersects(other), true);\n    ASSERT_EQ(ref.intersects(other), true);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, is_subset_of_or_equal_to, {\n    simd_bits<W> data(1024);\n    simd_bits<W> other(512);\n    simd_bits_range_ref<W> ref(data);\n    ASSERT_EQ(data.is_subset_of_or_equal_to(other), true);\n    ASSERT_EQ(ref.is_subset_of_or_equal_to(other), true);\n    other[511] = true;\n    ASSERT_EQ(data.is_subset_of_or_equal_to(other), true);\n    ASSERT_EQ(ref.is_subset_of_or_equal_to(other), true);\n    data[511] = true;\n    ASSERT_EQ(data.is_subset_of_or_equal_to(other), true);\n    ASSERT_EQ(ref.is_subset_of_or_equal_to(other), true);\n    other[511] = false;\n    ASSERT_EQ(data.is_subset_of_or_equal_to(other), false);\n    ASSERT_EQ(ref.is_subset_of_or_equal_to(other), false);\n    other[511] = true;\n    data[513] = true;\n    ASSERT_EQ(data.is_subset_of_or_equal_to(other), false);\n    ASSERT_EQ(ref.is_subset_of_or_equal_to(other), false);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, prefix_ref, {\n    simd_bits<W> data(1024);\n    simd_bits_range_ref<W> ref(data);\n    auto prefix = ref.prefix_ref(257);\n    ASSERT_TRUE(prefix.num_bits_padded() >= 257);\n    ASSERT_TRUE(prefix.num_bits_padded() < 1024);\n    ASSERT_FALSE(data[0]);\n    prefix[0] = true;\n    ASSERT_TRUE(data[0]);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, as_u64, {\n    simd_bits<W> data(1024);\n    simd_bits_range_ref<W> ref(data);\n    ASSERT_EQ(data.as_u64(), 0);\n    ASSERT_EQ(ref.as_u64(), 0);\n\n    ref[63] = 1;\n    ASSERT_EQ(data.as_u64(), uint64_t{1} << 63);\n    ASSERT_EQ(ref.as_u64(), uint64_t{1} << 63);\n    ASSERT_EQ(data.word_range_ref(0, 0).as_u64(), 0);\n    ASSERT_EQ(data.word_range_ref(0, 1).as_u64(), uint64_t{1} << 63);\n    ASSERT_EQ(data.word_range_ref(0, 2).as_u64(), uint64_t{1} << 63);\n    ASSERT_EQ(data.word_range_ref(1, 1).as_u64(), 0);\n    ASSERT_EQ(data.word_range_ref(1, 2).as_u64(), 0);\n\n    ref[64] = 1;\n    ASSERT_THROW({ data.as_u64(); }, std::invalid_argument);\n    ASSERT_THROW({ data.word_range_ref(0, 2).as_u64(); }, std::invalid_argument);\n    ASSERT_THROW({ ref.as_u64(); }, std::invalid_argument);\n    if (data.num_simd_words > 2) {\n        ASSERT_EQ(data.word_range_ref(2, 1).as_u64(), 0);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_bits_range_ref, clear_bits_past, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> data(1024);\n    simd_bits<W> copy(1024);\n\n    for (size_t c = 700; c < 710; c++) {\n        data.randomize(1024, rng);\n        copy = data;\n        simd_bits_range_ref<W>(copy).clear_bits_past(c);\n        for (size_t k = c; k < 1024; k++) {\n            data[k] = 0;\n        }\n    }\n\n    ASSERT_EQ(data, copy);\n})\n"
  },
  {
    "path": "src/stim/mem/simd_util.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_util.h\"\n\ntemplate <uint64_t mask, uint64_t shift>\nvoid inplace_transpose_64x64_pass(uint64_t *data, size_t stride) {\n    for (size_t k = 0; k < 64; k++) {\n        if (k & shift) {\n            continue;\n        }\n        uint64_t &x = data[stride * k];\n        uint64_t &y = data[stride * (k + shift)];\n        uint64_t a = x & mask;\n        uint64_t b = x & ~mask;\n        uint64_t c = y & mask;\n        uint64_t d = y & ~mask;\n        x = a | (c << shift);\n        y = (b >> shift) | d;\n    }\n}\n\nvoid stim::inplace_transpose_64x64(uint64_t *data, size_t stride) {\n    inplace_transpose_64x64_pass<0x5555555555555555UL, 1>(data, stride);\n    inplace_transpose_64x64_pass<0x3333333333333333UL, 2>(data, stride);\n    inplace_transpose_64x64_pass<0x0F0F0F0F0F0F0F0FUL, 4>(data, stride);\n    inplace_transpose_64x64_pass<0x00FF00FF00FF00FFUL, 8>(data, stride);\n    inplace_transpose_64x64_pass<0x0000FFFF0000FFFFUL, 16>(data, stride);\n    inplace_transpose_64x64_pass<0x00000000FFFFFFFFUL, 32>(data, stride);\n}\n"
  },
  {
    "path": "src/stim/mem/simd_util.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_SIMD_UTIL_H\n#define _STIM_MEM_SIMD_UTIL_H\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace stim {\n\nconstexpr uint64_t tile64_helper(uint64_t val, size_t shift) {\n    return shift >= 64 ? val : tile64_helper(val | (val << shift), shift << 1);\n}\n\nconstexpr uint64_t interleave_mask(size_t step) {\n    return tile64_helper((uint64_t{1} << step) - 1, step << 1);\n}\n\ninline uint64_t spread_bytes_32_to_64(uint32_t v) {\n    uint64_t r = (((uint64_t)v << 16) | v) & 0xFFFF0000FFFFULL;\n    return ((r << 8) | r) & 0xFF00FF00FF00FFULL;\n}\n\nvoid inplace_transpose_64x64(uint64_t *data, size_t stride);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/simd_util.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_util.h\"\n\n#include <algorithm>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_bit_table.h\"\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\ntemplate <size_t W>\nsimd_bits<W> reference_transpose_of(size_t bit_width, const simd_bits<W> &data) {\n    assert(!(bit_width & 0xFF));\n    auto expected = simd_bits<W>(bit_width * bit_width);\n    for (size_t i = 0; i < bit_width; i++) {\n        for (size_t j = 0; j < bit_width; j++) {\n            expected[i * bit_width + j] = data[j * bit_width + i];\n        }\n    }\n    return expected;\n}\n\ntemplate <size_t A, size_t W>\nuint8_t determine_permutation_bit_else_0xFF(const std::function<void(simd_bits<W> &)> &func, uint8_t bit) {\n    auto data = simd_bits<W>(1 << A);\n    data[1 << bit] = true;\n    func(data);\n    uint32_t seen = 0;\n    for (size_t k = 0; k < 1 << A; k++) {\n        if (data[k]) {\n            seen++;\n        }\n    }\n    if (seen != 1) {\n        return 0xFF;\n    }\n    for (uint8_t k = 0; k < A; k++) {\n        if (data[1 << k]) {\n            return k;\n        }\n    }\n    return 0xFF;\n}\n\ntemplate <size_t A, size_t W>\nstd::string determine_if_function_performs_bit_permutation_helper(\n    const std::function<void(simd_bits<W> &)> &func, const std::array<uint8_t, A> &bit_permutation) {\n    size_t area = 1 << A;\n    auto data = simd_bits<W>::random(area, INDEPENDENT_TEST_RNG());\n    auto expected = simd_bits<W>(area);\n\n    for (size_t k_in = 0; k_in < area; k_in++) {\n        size_t k_out = 0;\n        for (size_t bit = 0; bit < A; bit++) {\n            if ((k_in >> bit) & 1) {\n                k_out ^= 1 << bit_permutation[bit];\n            }\n        }\n        expected[k_out] = data[k_in];\n    }\n    func(data);\n    bool result = data == expected;\n    if (!result) {\n        std::stringstream ss;\n        std::array<uint8_t, A> perm;\n        ss << \"actual permutation:\";\n        for (uint8_t k = 0; k < A; k++) {\n            auto v = (uint32_t)determine_permutation_bit_else_0xFF<A>(func, k);\n            if (v == 0xFF) {\n                ss << \" [not a permutation],\";\n            } else {\n                ss << \" \" << v << \",\";\n            }\n            perm[k] = v;\n        }\n        ss << \"\\n\";\n        if (perm == bit_permutation) {\n            ss << \"[BUT PERMUTATION ACTS INCORRECTLY ON SOME BITS.]\\n\";\n        }\n        return ss.str();\n    }\n    return \"\";\n}\n\ntemplate <size_t A, size_t W>\nvoid EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION(\n    const std::function<void(simd_bits<W> &)> &func, const std::array<uint8_t, A> &bit_permutation) {\n    size_t area = 1 << A;\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto data = simd_bits<W>::random(area, rng);\n    auto expected = simd_bits<W>(area);\n\n    for (size_t k_in = 0; k_in < area; k_in++) {\n        size_t k_out = 0;\n        for (size_t bit = 0; bit < A; bit++) {\n            if ((k_in >> bit) & 1) {\n                k_out ^= 1 << bit_permutation[bit];\n            }\n        }\n        expected[k_out] = data[k_in];\n    }\n    func(data);\n    if (data != expected) {\n        std::stringstream ss;\n        std::array<uint8_t, A> perm;\n        ss << \"\\nexpected permutation:\";\n        for (const auto &e : bit_permutation) {\n            ss << \" \" << (int)e << \",\";\n        }\n\n        ss << \"\\n  actual permutation:\";\n        for (uint8_t k = 0; k < A; k++) {\n            auto v = (uint32_t)determine_permutation_bit_else_0xFF<A>(func, k);\n            if (v == 0xFF) {\n                ss << \" [not a permutation],\";\n            } else {\n                ss << \" \" << v << \",\";\n            }\n            perm[k] = v;\n        }\n        ss << \"\\n\";\n        if (perm == bit_permutation) {\n            ss << \"[BUT PERMUTATION ACTS INCORRECTLY ON SOME BITS.]\\n\";\n        }\n        EXPECT_TRUE(false) << ss.str();\n    }\n}\n\nTEST(simd_util, inplace_transpose_64x64) {\n    constexpr size_t W = 64;\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> data = simd_bits<W>::random(64 * 64, rng);\n    simd_bits<W> copy = data;\n    inplace_transpose_64x64(copy.u64, 1);\n    for (size_t i = 0; i < 64; i++) {\n        for (size_t j = 0; j < 64; j++) {\n            ASSERT_EQ(data[i * 64 + j], copy[j * 64 + i]);\n        }\n    }\n}\n\nTEST_EACH_WORD_SIZE_W(simd_util, inplace_transpose, {\n    if (W == 64) {\n        EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<12, W>(\n            [](simd_bits<W> &d) {\n                inplace_transpose_64x64(d.u64, 1);\n            },\n            {\n                6,\n                7,\n                8,\n                9,\n                10,\n                11,\n                0,\n                1,\n                2,\n                3,\n                4,\n                5,\n            });\n\n        EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<13, W>(\n            [](simd_bits<W> &d) {\n                inplace_transpose_64x64(d.u64, 1);\n                inplace_transpose_64x64(d.u64 + 64, 1);\n            },\n            {\n                6,\n                7,\n                8,\n                9,\n                10,\n                11,\n                0,\n                1,\n                2,\n                3,\n                4,\n                5,\n                12,\n            });\n\n        EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<13, W>(\n            [](simd_bits<W> &d) {\n                inplace_transpose_64x64(d.u64, 2);\n                inplace_transpose_64x64(d.u64 + 1, 2);\n            },\n            {\n                7,\n                8,\n                9,\n                10,\n                11,\n                12,\n                6,\n                0,\n                1,\n                2,\n                3,\n                4,\n                5,\n            });\n    } else if (W == 128) {\n        EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<14, W>(\n            [](simd_bits<W> &d) {\n                bitword<W>::inplace_transpose_square(d.ptr_simd, 1);\n            },\n            {\n                7,\n                8,\n                9,\n                10,\n                11,\n                12,\n                13,\n                0,\n                1,\n                2,\n                3,\n                4,\n                5,\n                6,\n            });\n\n        EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<15, W>(\n            [](simd_bits<W> &d) {\n                bitword<W>::inplace_transpose_square(d.ptr_simd, 1);\n                bitword<W>::inplace_transpose_square(d.ptr_simd + 128, 1);\n            },\n            {\n                7,\n                8,\n                9,\n                10,\n                11,\n                12,\n                13,\n                0,\n                1,\n                2,\n                3,\n                4,\n                5,\n                6,\n                14,\n            });\n\n        EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<15, W>(\n            [](simd_bits<W> &d) {\n                bitword<W>::inplace_transpose_square(d.ptr_simd, 2);\n                bitword<W>::inplace_transpose_square(d.ptr_simd + 1, 2);\n            },\n            {\n                8,\n                9,\n                10,\n                11,\n                12,\n                13,\n                14,\n                7,\n                0,\n                1,\n                2,\n                3,\n                4,\n                5,\n                6,\n            });\n    } else if (W == 256) {\n        EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<16, W>(\n            [](simd_bits<W> &d) {\n                bitword<W>::inplace_transpose_square(d.ptr_simd, 1);\n            },\n            {\n                8,\n                9,\n                10,\n                11,\n                12,\n                13,\n                14,\n                15,\n                0,\n                1,\n                2,\n                3,\n                4,\n                5,\n                6,\n                7,\n            });\n\n        EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<17, W>(\n            [](simd_bits<W> &d) {\n                bitword<W>::inplace_transpose_square(d.ptr_simd, 1);\n                bitword<W>::inplace_transpose_square(d.ptr_simd + 256, 1);\n            },\n            {\n                8,\n                9,\n                10,\n                11,\n                12,\n                13,\n                14,\n                15,\n                0,\n                1,\n                2,\n                3,\n                4,\n                5,\n                6,\n                7,\n                16,\n            });\n\n        EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<17, W>(\n            [](simd_bits<W> &d) {\n                bitword<W>::inplace_transpose_square(d.ptr_simd, 2);\n                bitword<W>::inplace_transpose_square(d.ptr_simd + 1, 2);\n            },\n            {\n                9,\n                10,\n                11,\n                12,\n                13,\n                14,\n                15,\n                16,\n                8,\n                0,\n                1,\n                2,\n                3,\n                4,\n                5,\n                6,\n                7,\n            });\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_util, simd_bit_table_transpose, {\n    EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<20, W>(\n        [](simd_bits<W> &d) {\n            d = reference_transpose_of(1024, d);\n        },\n        {\n            10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,\n        });\n    EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<18, W>(\n        [](simd_bits<W> &d) {\n            simd_bit_table<W> t(512, 512);\n            t.data = d;\n            t.do_square_transpose();\n            d = t.data;\n        },\n        {\n            9,\n            10,\n            11,\n            12,\n            13,\n            14,\n            15,\n            16,\n            17,\n            0,\n            1,\n            2,\n            3,\n            4,\n            5,\n            6,\n            7,\n            8,\n        });\n    EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<20, W>(\n        [](simd_bits<W> &d) {\n            simd_bit_table<W> t(1024, 1024);\n            t.data = d;\n            t.do_square_transpose();\n            d = t.data;\n        },\n        {\n            10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,\n        });\n    EXPECT_FUNCTION_PERFORMS_ADDRESS_BIT_PERMUTATION<19, W>(\n        [](simd_bits<W> &d) {\n            simd_bit_table<W> t(512, 1024);\n            t.data = d;\n            auto t2 = t.transposed();\n            d = t2.data;\n        },\n        {\n            9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 1, 2, 3, 4, 5, 6, 7, 8,\n        });\n})\n\nTEST(simd_util, interleave_mask) {\n    ASSERT_EQ(interleave_mask(1), 0x5555555555555555ULL);\n    ASSERT_EQ(interleave_mask(2), 0x3333333333333333ULL);\n    ASSERT_EQ(interleave_mask(4), 0x0F0F0F0F0F0F0F0FULL);\n    ASSERT_EQ(interleave_mask(8), 0x00FF00FF00FF00FFULL);\n    ASSERT_EQ(interleave_mask(16), 0x0000FFFF0000FFFFULL);\n    ASSERT_EQ(interleave_mask(32), 0x00000000FFFFFFFFULL);\n}\n"
  },
  {
    "path": "src/stim/mem/simd_word.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_word.h\"\n"
  },
  {
    "path": "src/stim/mem/simd_word.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <cstddef>\n#include <cstdint>\n\n#ifndef _STIM_MEM_SIMD_WORD_H\n#define _STIM_MEM_SIMD_WORD_H\n\n#include \"stim/mem/bitword_128_sse.h\"\n#include \"stim/mem/bitword_256_avx.h\"\n#include \"stim/mem/bitword_64.h\"\n\nnamespace stim {\n#if __AVX2__\nconstexpr size_t MAX_BITWORD_WIDTH = 256;\n#elif __SSE2__\nconstexpr size_t MAX_BITWORD_WIDTH = 128;\n#else\nconstexpr size_t MAX_BITWORD_WIDTH = 64;\n#endif\n\ntemplate <size_t W>\nusing simd_word = bitword<W>;\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/simd_word.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_word.h\"\n\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(simd_compat_popcnt) {\n    simd_bits<MAX_BITWORD_WIDTH> d(1024 * 256);\n    std::mt19937_64 rng(0);\n    d.randomize(d.num_bits_padded(), rng);\n\n    uint64_t optimization_blocker = 0;\n    benchmark_go([&]() {\n        d[300] ^= true;\n        for (size_t k = 0; k < d.num_simd_words; k++) {\n            optimization_blocker += d.ptr_simd[k].popcount();\n        }\n    })\n        .goal_micros(1.5)\n        .show_rate(\"Bits\", d.num_bits_padded());\n    if (optimization_blocker == 0) {\n        std::cout << '!';\n    }\n}\n"
  },
  {
    "path": "src/stim/mem/simd_word.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/simd_word.h\"\n\n#include <algorithm>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nunion WordOr64 {\n    simd_word<MAX_BITWORD_WIDTH> w;\n    uint64_t p[sizeof(simd_word<MAX_BITWORD_WIDTH>) / sizeof(uint64_t)];\n\n    WordOr64() : p() {\n    }\n};\n\nTEST_EACH_WORD_SIZE_W(simd_word_pick, popcount, {\n    WordOr64 v;\n    auto n = sizeof(simd_word<W>) * 2;\n\n    for (size_t expected = 0; expected <= n; expected++) {\n        std::vector<uint64_t> bits{};\n        for (size_t i = 0; i < n; i++) {\n            bits.push_back(i < expected);\n        }\n        for (size_t reps = 0; reps < 10; reps++) {\n            std::shuffle(bits.begin(), bits.end(), INDEPENDENT_TEST_RNG());\n            for (size_t i = 0; i < n; i++) {\n                v.p[i >> 6] = 0;\n            }\n            for (size_t i = 0; i < n; i++) {\n                v.p[i >> 6] |= bits[i] << (i & 63);\n            }\n            ASSERT_EQ(v.w.popcount(), expected);\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_word_pick, operator_bool, {\n    bitword<W> w{};\n    auto p = &w.u8[0];\n    ASSERT_EQ((bool)w, false);\n    p[0] = 5;\n    ASSERT_EQ((bool)w, true);\n    p[0] = 0;\n    if (bitword<W>::BIT_SIZE > 64) {\n        p[1] = 5;\n        ASSERT_EQ((bool)w, true);\n        p[1] = 0;\n        ASSERT_EQ((bool)w, false);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(simd_word, integer_conversions, {\n    ASSERT_EQ((uint64_t)(simd_word<W>{23}), 23);\n    ASSERT_EQ((uint64_t)(simd_word<W>{(uint64_t)23}), 23);\n    ASSERT_EQ((int64_t)(simd_word<W>{(uint64_t)23}), 23);\n    ASSERT_EQ((uint64_t)(simd_word<W>{(int64_t)23}), 23);\n    ASSERT_EQ((int64_t)(simd_word<W>{(int64_t)23}), 23);\n    ASSERT_EQ((int64_t)(simd_word<W>{(int64_t)-23}), -23);\n    if (W > 64) {\n        ASSERT_THROW(\n            {\n                uint64_t u = (uint64_t)(simd_word<W>{(int64_t)-23});\n                std::cerr << u;\n            },\n            std::invalid_argument);\n    }\n\n    simd_word<W> w0{(uint64_t)0};\n    simd_word<W> w1{(uint64_t)1};\n    simd_word<W> w2{(uint64_t)2};\n    ASSERT_EQ((uint64_t)(w1 | w2), 3);\n    ASSERT_EQ((uint64_t)w1, 1);\n    ASSERT_EQ((uint64_t)w2, 2);\n    ASSERT_EQ((int)(w1 | w2), 3);\n    ASSERT_EQ((int)w0, 0);\n    ASSERT_EQ((int)w1, 1);\n    ASSERT_EQ((int)w2, 2);\n    ASSERT_EQ((bool)w0, false);\n    ASSERT_EQ((bool)w1, true);\n    ASSERT_EQ((bool)w2, true);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_word, equality, {\n    ASSERT_TRUE((simd_word<W>{1}) == (simd_word<W>{1}));\n    ASSERT_FALSE((simd_word<W>{1}) == (simd_word<W>{2}));\n    ASSERT_TRUE((simd_word<W>{1}) != (simd_word<W>{2}));\n    ASSERT_FALSE((simd_word<W>{1}) != (simd_word<W>{1}));\n})\n\nTEST_EACH_WORD_SIZE_W(simd_word, shifting, {\n    simd_word<W> w{1};\n\n    for (size_t k = 0; k < W; k++) {\n        std::array<uint64_t, W / 64> expected{};\n        expected[k / 64] = uint64_t{1} << (k % 64);\n        EXPECT_EQ((w << static_cast<uint64_t>(k)).to_u64_array(), expected) << k;\n        if (k > 0) {\n            EXPECT_EQ(((w << (static_cast<uint64_t>(k) - 1)) << 1).to_u64_array(), expected) << k;\n        }\n        EXPECT_EQ(w, (w << static_cast<uint64_t>(k)) >> static_cast<uint64_t>(k)) << k;\n    }\n\n    ASSERT_EQ(w << 0, 1);\n    ASSERT_EQ(w >> 0, 1);\n    ASSERT_EQ(w << 1, 2);\n    ASSERT_EQ(w >> 1, 0);\n    ASSERT_EQ(w << 2, 4);\n    ASSERT_EQ(w >> 2, 0);\n    ASSERT_EQ((w << 5) >> 5, 1);\n    ASSERT_EQ((w >> 5) << 5, 0);\n    ASSERT_EQ((w << static_cast<uint64_t>(W - 1)) << 1, 0);\n    ASSERT_EQ((w << static_cast<uint64_t>(W - 1)) >> static_cast<uint64_t>(W - 1), 1);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_word, masking, {\n    simd_word<W> w{0b10011};\n    ASSERT_EQ((w & 1), 1);\n    ASSERT_EQ((w & 2), 2);\n    ASSERT_EQ((w & 4), 0);\n    ASSERT_EQ((w ^ 1), 0b10010);\n    ASSERT_EQ((w ^ 2), 0b10001);\n    ASSERT_EQ((w ^ 4), 0b10111);\n    ASSERT_EQ((w | 1), 0b10011);\n    ASSERT_EQ((w | 2), 0b10011);\n    ASSERT_EQ((w | 4), 0b10111);\n})\n\nTEST_EACH_WORD_SIZE_W(simd_word, ordering, {\n    ASSERT_TRUE(simd_word<W>(1) < simd_word<W>(2));\n    ASSERT_TRUE(!(simd_word<W>(2) < simd_word<W>(2)));\n    ASSERT_TRUE(!(simd_word<W>(3) < simd_word<W>(2)));\n})\n\nTEST_EACH_WORD_SIZE_W(simd_word, from_u64_array, {\n    std::array<uint64_t, W / 64> expected;\n    for (size_t k = 0; k < expected.size(); k++) {\n        expected[k] = k * 3 + 1;\n    }\n    simd_word<W> w(expected);\n    std::array<uint64_t, W / 64> actual = w.to_u64_array();\n    ASSERT_EQ(actual, expected);\n})\n"
  },
  {
    "path": "src/stim/mem/simd_word.test.h",
    "content": "/// Test utilities for working with various sizes of simd words.\n\n#include \"gtest/gtest.h\"\n\n#define TEST_EACH_WORD_SIZE_UP_TO_64(test_suite, test_name, ...) \\\n    TEST(test_suite, test_name##_64) {                           \\\n        constexpr size_t W = 64;                                 \\\n        __VA_ARGS__                                              \\\n    }\n\n#define TEST_EACH_WORD_SIZE_UP_TO_128(test_suite, test_name, ...) \\\n    TEST(test_suite, test_name##_128) {                           \\\n        constexpr size_t W = 128;                                 \\\n        __VA_ARGS__                                               \\\n    }                                                             \\\n    TEST(test_suite, test_name##_64) {                            \\\n        constexpr size_t W = 64;                                  \\\n        __VA_ARGS__                                               \\\n    }\n\n#define TEST_EACH_WORD_SIZE_UP_TO_256(test_suite, test_name, ...) \\\n    TEST(test_suite, test_name##_256) {                           \\\n        constexpr size_t W = 256;                                 \\\n        __VA_ARGS__                                               \\\n    }                                                             \\\n    TEST(test_suite, test_name##_128) {                           \\\n        constexpr size_t W = 128;                                 \\\n        __VA_ARGS__                                               \\\n    }                                                             \\\n    TEST(test_suite, test_name##_64) {                            \\\n        constexpr size_t W = 64;                                  \\\n        __VA_ARGS__                                               \\\n    }\n\n#if __AVX2__\n#define TEST_EACH_WORD_SIZE_W(test_suite, test_name, ...) \\\n    TEST_EACH_WORD_SIZE_UP_TO_256(test_suite, test_name, __VA_ARGS__)\n#elif __SSE2__\n#define TEST_EACH_WORD_SIZE_W(test_suite, test_name, ...) \\\n    TEST_EACH_WORD_SIZE_UP_TO_128(test_suite, test_name, __VA_ARGS__)\n#else\n#define TEST_EACH_WORD_SIZE_W(test_suite, test_name, ...) \\\n    TEST_EACH_WORD_SIZE_UP_TO_64(test_suite, test_name, __VA_ARGS__)\n#endif\n"
  },
  {
    "path": "src/stim/mem/span_ref.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_SPAN_REF_H\n#define _STIM_MEM_SPAN_REF_H\n\n#include <array>\n#include <cstdlib>\n#include <span>\n#include <sstream>\n#include <vector>\n\nnamespace stim {\n\n/// Exposes a collection-like interface to a range of memory delineated by start/end pointers.\n///\n/// A major difference between the semantics of this class and the std::span class added in C++20 is that this class\n/// defines equality and ordering operators that depend on *what is pointed to* instead of the value of the pointers\n/// themselves. Two range refs aren't equal because they have the same pointers, they're equal because they point\n/// to ranges that have the same contents. In other words, this class really acts more like a *reference* than like a\n/// pointer.\ntemplate <typename T>\nstruct SpanRef {\n    T *ptr_start;\n    T *ptr_end;\n    SpanRef() : ptr_start(nullptr), ptr_end(nullptr) {\n    }\n    SpanRef(T *begin, T *end) : ptr_start(begin), ptr_end(end) {\n    }\n\n    // Implicit conversions.\n    SpanRef(T *singleton) : ptr_start(singleton), ptr_end(singleton + 1) {\n    }\n    SpanRef(const SpanRef<typename std::remove_const<T>::type> &other)\n        : ptr_start(other.ptr_start), ptr_end(other.ptr_end) {\n    }\n    SpanRef(std::span<T> &items) : ptr_start(items.data()), ptr_end(items.data() + items.size()) {\n    }\n    SpanRef(const std::span<typename std::remove_const<T>::type> &items)\n        : ptr_start(items.data()), ptr_end(items.data() + items.size()) {\n    }\n    SpanRef(std::vector<T> &items) : ptr_start(items.data()), ptr_end(items.data() + items.size()) {\n    }\n    SpanRef(const std::vector<typename std::remove_const<T>::type> &items)\n        : ptr_start(items.data()), ptr_end(items.data() + items.size()) {\n    }\n    template <size_t K>\n    SpanRef(std::array<T, K> &items) : ptr_start(items.data()), ptr_end(items.data() + items.size()) {\n    }\n    template <size_t K>\n    SpanRef(const std::array<typename std::remove_const<T>::type, K> &items)\n        : ptr_start(items.data()), ptr_end(items.data() + items.size()) {\n    }\n\n    operator std::span<T>() {\n        return {ptr_start, ptr_end};\n    }\n    operator std::span<const T>() const {\n        return {ptr_start, ptr_end};\n    }\n\n    SpanRef sub(size_t start_offset, size_t end_offset) const {\n        return SpanRef<T>(ptr_start + start_offset, ptr_start + end_offset);\n    }\n\n    size_t size() const {\n        return ptr_end - ptr_start;\n    }\n    const T *begin() const {\n        return ptr_start;\n    }\n    const T *end() const {\n        return ptr_end;\n    }\n    const T &back() const {\n        return *(ptr_end - 1);\n    }\n    const T &front() const {\n        return *ptr_start;\n    }\n    bool empty() const {\n        return ptr_end == ptr_start;\n    }\n    T *begin() {\n        return ptr_start;\n    }\n    T *end() {\n        return ptr_end;\n    }\n    T &back() {\n        return *(ptr_end - 1);\n    }\n    T &front() {\n        return *ptr_start;\n    }\n    const T &operator[](size_t index) const {\n        return ptr_start[index];\n    }\n    T &operator[](size_t index) {\n        return ptr_start[index];\n    }\n\n    bool operator==(const SpanRef<const T> &other) const {\n        size_t n = size();\n        if (n != other.size()) {\n            return false;\n        }\n        for (size_t k = 0; k < n; k++) {\n            if (ptr_start[k] != other[k]) {\n                return false;\n            }\n        }\n        return true;\n    }\n    bool operator==(const SpanRef<typename std::remove_const<T>::type> &other) const {\n        return SpanRef<const T>(ptr_start, ptr_end) == SpanRef<const T>(other.ptr_start, other.ptr_end);\n    }\n    bool operator!=(const SpanRef<const T> &other) const {\n        return !(*this == other);\n    }\n    bool operator!=(const SpanRef<typename std::remove_const<T>::type> &other) const {\n        return !(*this == other);\n    }\n\n    std::string str() const {\n        std::stringstream ss;\n        ss << *this;\n        return ss.str();\n    }\n\n    /// Lexicographic ordering.\n    bool operator<(const SpanRef<const T> &other) const {\n        auto n = std::min(size(), other.size());\n        for (size_t k = 0; k < n; k++) {\n            if ((*this)[k] != other[k]) {\n                return (*this)[k] < other[k];\n            }\n        }\n        return size() < other.size();\n    }\n    bool operator<(const SpanRef<typename std::remove_const<T>::type> &other) const {\n        return SpanRef<const T>(ptr_start, ptr_end) < SpanRef<const T>(other.ptr_start, other.ptr_end);\n    }\n};\n\ntemplate <typename T>\nstd::ostream &operator<<(std::ostream &out, const stim::SpanRef<T> &v) {\n    bool first = false;\n    out << \"SpanRef{\";\n    for (const auto &item : v) {\n        if (!first) {\n            first = true;\n        } else {\n            out << \", \";\n        }\n        out << item;\n    }\n    out << \"}\";\n    return out;\n}\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/sparse_xor_vec.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim/mem/sparse_xor_vec.h\"\n"
  },
  {
    "path": "src/stim/mem/sparse_xor_vec.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_MEM_SPARSE_XOR_VEC_H\n#define _STIM_MEM_SPARSE_XOR_VEC_H\n\n#include <algorithm>\n#include <array>\n#include <cassert>\n#include <cstdint>\n#include <functional>\n#include <sstream>\n#include <vector>\n\n#include \"stim/mem/monotonic_buffer.h\"\n\nnamespace stim {\n\n/// Merges the elements of two sorted buffers into an output buffer while cancelling out duplicate items.\n///\n/// \\param sorted_in1: Pointer range covering the first sorted list.\n/// \\param sorted_in2: Pointer range covering the second sorted list.\n/// \\param out: Where to write the output. Must have size of at least sorted_in1.size() + sorted_in2.size().\n/// \\return: A pointer to the end of the output (one past the last place written).\ntemplate <typename T>\ninline T *xor_merge_sort(SpanRef<const T> sorted_in1, SpanRef<const T> sorted_in2, T *out) {\n    // Interleave sorted src and dst into a sorted work buffer.\n    const T *p1 = sorted_in1.ptr_start;\n    const T *p2 = sorted_in2.ptr_start;\n    const T *end1 = sorted_in1.ptr_end;\n    const T *end2 = sorted_in2.ptr_end;\n    while (p1 != end1) {\n        if (p2 == end2 || *p1 < *p2) {\n            *out++ = *p1++;\n        } else if (*p2 < *p1) {\n            *out++ = *p2++;\n        } else {\n            // Same value in both lists. Cancels itself out.\n            p1++;\n            p2++;\n        }\n    }\n    while (p2 != end2) {\n        *out++ = *p2++;\n    }\n    return out;\n}\n\ntemplate <typename T>\ninline SpanRef<T> inplace_xor_sort(SpanRef<T> items) {\n    std::sort(items.begin(), items.end());\n    size_t new_size = 0;\n    for (size_t k = 0; k < items.size(); k++) {\n        if (new_size > 0 && items[k] == items[new_size - 1]) {\n            new_size--;\n        } else {\n            if (k != new_size) {\n                std::swap(items[new_size], items[k]);\n            }\n            new_size++;\n        }\n    }\n    return items.sub(0, new_size);\n}\n\ntemplate <typename T>\nbool is_subset_of_sorted(SpanRef<const T> subset, SpanRef<const T> superset) {\n    const T *p_sub = subset.ptr_start;\n    const T *p_sup = superset.ptr_start;\n    const T *end_sub = subset.ptr_end;\n    const T *end_sup = superset.ptr_end;\n    while (p_sub != end_sub) {\n        if (p_sup == end_sup || *p_sub < *p_sup) {\n            return false;\n        } else if (*p_sup < *p_sub) {\n            p_sup++;\n        } else {\n            // Same value in both lists. Cancels itself out.\n            p_sub++;\n            p_sup++;\n        }\n    }\n    return true;\n}\n\ntemplate <typename T, typename CALLBACK>\ninline void xor_merge_sort_temp_buffer_callback(\n    SpanRef<const T> sorted_items_1, SpanRef<const T> sorted_items_2, CALLBACK handler) {\n    constexpr size_t STACK_SIZE = 64;\n    size_t max = sorted_items_1.size() + sorted_items_2.size();\n    if (max > STACK_SIZE) {\n        T *begin = new T[max];\n        T *end = xor_merge_sort(sorted_items_1, sorted_items_2, begin);\n        handler(SpanRef<const T>(begin, end));\n        delete[] begin;\n    } else {\n        T data[STACK_SIZE];\n        T *begin = &data[0];\n        T *end = xor_merge_sort(sorted_items_1, sorted_items_2, begin);\n        handler(SpanRef<const T>(begin, end));\n    }\n}\n\ntemplate <typename T>\nstruct SparseXorVec;\n\ntemplate <typename T>\nstd::ostream &operator<<(std::ostream &out, const SparseXorVec<T> &v);\n\ntemplate <typename T>\ninline void xor_item_into_sorted_vec(const T &item, std::vector<T> &sorted_items) {\n    // Just do a linear scan to find the insertion point, instead of a binary search.\n    // This is faster at small sizes, and complexity is linear anyways due to the shifting of later items.\n    for (size_t k = 0; k < sorted_items.size(); k++) {\n        const auto &v = sorted_items[k];\n        if (v < item) {\n            continue;\n        } else if (v == item) {\n            sorted_items.erase(sorted_items.begin() + k);\n            return;\n        } else {\n            sorted_items.insert(sorted_items.begin() + k, item);\n            return;\n        }\n    }\n    sorted_items.push_back(item);\n}\n\n/// A sparse set of integers that supports efficient xoring (computing the symmetric difference).\ntemplate <typename T>\nstruct SparseXorVec {\n   public:\n    // Sorted list of entries.\n    std::vector<T> sorted_items;\n\n    SparseXorVec() = default;\n    SparseXorVec(std::vector<T> &&vec) : sorted_items(std::move(vec)) {\n    }\n\n    bool empty() const {\n        return sorted_items.empty();\n    }\n\n    void set_to_xor_merge_sort(SpanRef<const T> sorted_items1, SpanRef<const T> sorted_items2) {\n        sorted_items.resize(sorted_items1.size() + sorted_items2.size());\n        auto written = xor_merge_sort(sorted_items, sorted_items1, sorted_items2);\n        sorted_items.resize(written.size());\n    }\n\n    bool is_superset_of(SpanRef<const T> subset) const {\n        return is_subset_of_sorted(subset, (SpanRef<const T>)sorted_items);\n    }\n\n    bool contains(const T &item) const {\n        return std::find(sorted_items.begin(), sorted_items.end(), item) != sorted_items.end();\n    }\n\n    void xor_sorted_items(SpanRef<const T> sorted) {\n        xor_merge_sort_temp_buffer_callback(range(), sorted, [&](SpanRef<const T> result) {\n            sorted_items.clear();\n            sorted_items.insert(sorted_items.end(), result.begin(), result.end());\n        });\n    }\n\n    void clear() {\n        sorted_items.clear();\n    }\n\n    void xor_item(const T &item) {\n        xor_item_into_sorted_vec(item, sorted_items);\n    }\n\n    SparseXorVec &operator^=(const SparseXorVec<T> &other) {\n        xor_sorted_items(other.range());\n        return *this;\n    }\n\n    SparseXorVec operator^(const SparseXorVec<T> &other) const {\n        SparseXorVec result;\n        result.sorted_items.resize(size() + other.size());\n        auto n = xor_merge_sort<T>(range(), other.range(), result.begin()) - result.begin();\n        result.sorted_items.resize(n);\n        return result;\n    }\n\n    SparseXorVec operator^(const T &other) const {\n        return xor_helper(&other, 1);\n    }\n\n    bool operator<(const SparseXorVec<T> &other) const {\n        return range() < other.range();\n    }\n\n    inline size_t size() const {\n        return sorted_items.size();\n    }\n\n    inline T *begin() {\n        return sorted_items.data();\n    }\n\n    inline T *end() {\n        return sorted_items.data() + size();\n    }\n\n    inline const T *begin() const {\n        return sorted_items.data();\n    }\n\n    inline const T *end() const {\n        return sorted_items.data() + size();\n    }\n\n    bool operator==(const std::vector<T> &other) const {\n        return sorted_items == other;\n    }\n\n    bool operator!=(const std::vector<T> &other) const {\n        return sorted_items != other;\n    }\n\n    bool operator==(const SparseXorVec &other) const {\n        return sorted_items == other.sorted_items;\n    }\n\n    bool operator!=(const SparseXorVec &other) const {\n        return sorted_items != other.sorted_items;\n    }\n\n    SpanRef<const T> range() const {\n        return {begin(), end()};\n    }\n\n    std::string str() const {\n        std::stringstream ss;\n        ss << *this;\n        return ss.str();\n    }\n\n    void check_invariants() const {\n        for (size_t k = 1; k < sorted_items.size(); k++) {\n            if (!(sorted_items[k - 1] < sorted_items[k])) {\n                throw std::invalid_argument(str() + \" is not unique and sorted.\");\n            }\n        }\n    }\n};\n\ntemplate <typename T>\nstd::ostream &operator<<(std::ostream &out, const SparseXorVec<T> &v) {\n    bool first = false;\n    out << \"SparseXorVec{\";\n    for (const auto &item : v) {\n        if (!first) {\n            first = true;\n        } else {\n            out << \", \";\n        }\n        out << item;\n    }\n    out << \"}\";\n    return out;\n}\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/mem/sparse_xor_vec.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/sparse_xor_vec.h\"\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(SparseXorTable_SmallRowXor_1000) {\n    size_t n = 1000;\n    std::vector<SparseXorVec<uint32_t>> table(n);\n    for (uint32_t k = 0; k < n; k++) {\n        table[k].xor_item(k);\n        table[k].xor_item(k + 1);\n        table[k].xor_item(k + 4);\n        table[k].xor_item(k + 8);\n        table[k].xor_item(k + 15);\n    }\n\n    benchmark_go([&]() {\n        for (size_t k = 1; k < n; k++) {\n            table[k - 1] ^= table[k];\n        }\n        for (size_t k = n; --k > 1;) {\n            table[k - 1] ^= table[k];\n        }\n    })\n        .goal_micros(35)\n        .show_rate(\"RowXors\", n * 2)\n        .show_rate(\"WordXors\", n * 3);\n}\n\nBENCHMARK(SparseXorVec_XorItem) {\n    SparseXorVec<uint32_t> buf;\n    std::vector<uint32_t> data{2, 5, 9, 5, 3, 6, 10};\n\n    benchmark_go([&]() {\n        for (auto d : data) {\n            buf.xor_item(d);\n        }\n    })\n        .goal_nanos(30)\n        .show_rate(\"Item\", data.size());\n}\n"
  },
  {
    "path": "src/stim/mem/sparse_xor_vec.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/mem/sparse_xor_vec.h\"\n\n#include <algorithm>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_util.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(sparse_xor_table, inplace_xor) {\n    SparseXorVec<uint32_t> v1;\n    SparseXorVec<uint32_t> v2;\n    v1.xor_item(1);\n    v1.xor_item(3);\n    v2.xor_item(3);\n    v2.xor_item(2);\n    ASSERT_EQ(v1.sorted_items, (std::vector<uint32_t>{1, 3}));\n    ASSERT_EQ(v2.sorted_items, (std::vector<uint32_t>{2, 3}));\n    v1 ^= v2;\n    ASSERT_EQ(v1.sorted_items, (std::vector<uint32_t>{1, 2}));\n    ASSERT_EQ(v2.sorted_items, (std::vector<uint32_t>{2, 3}));\n}\n\nTEST(sparse_xor_table, grow) {\n    SparseXorVec<uint32_t> v1;\n    SparseXorVec<uint32_t> v2;\n    v1.xor_item(1);\n    v1.xor_item(3);\n    v1.xor_item(6);\n    v2.xor_item(2);\n    v2.xor_item(3);\n    v2.xor_item(4);\n    v2.xor_item(5);\n    v1 ^= v2;\n    ASSERT_EQ(v1.sorted_items, (std::vector<uint32_t>{1, 2, 4, 5, 6}));\n}\n\nTEST(sparse_xor_table, historical_failure_case) {\n    SparseXorVec<uint32_t> v1;\n    SparseXorVec<uint32_t> v2;\n    v1.xor_item(1);\n    v1.xor_item(2);\n    v1.xor_item(3);\n    v1.xor_item(6);\n    v1.xor_item(9);\n    v2.xor_item(2);\n    v1.xor_item(2);\n    ASSERT_EQ(v1.sorted_items, (std::vector<uint32_t>{1, 3, 6, 9}));\n    ASSERT_EQ(v2.sorted_items, (std::vector<uint32_t>{2}));\n}\n\nTEST(sparse_xor_table, comparison) {\n    SparseXorVec<uint32_t> v1;\n    v1.xor_item(1);\n    v1.xor_item(3);\n    SparseXorVec<uint32_t> v2;\n    v2.xor_item(1);\n    ASSERT_TRUE(v1 != v2);\n    ASSERT_TRUE(!(v1 == v2));\n    ASSERT_TRUE(v2 < v1);\n    ASSERT_TRUE(!(v1 < v2));\n    v2.xor_item(4);\n    ASSERT_TRUE(v1 != v2);\n    ASSERT_TRUE(!(v1 == v2));\n    ASSERT_TRUE(!(v2 < v1));\n    ASSERT_TRUE(v1 < v2);\n    v2.xor_item(4);\n    v2.xor_item(3);\n    ASSERT_TRUE(v1 == v2);\n    ASSERT_TRUE(!(v1 != v2));\n    ASSERT_TRUE(!(v2 < v1));\n    ASSERT_TRUE(!(v1 < v2));\n}\n\nTEST(sparse_xor_table, str) {\n    SparseXorVec<uint32_t> v;\n    ASSERT_EQ(v.str(), \"SparseXorVec{}\");\n    v.xor_item(5);\n    ASSERT_EQ(v.str(), \"SparseXorVec{5}\");\n    v.xor_item(2);\n    ASSERT_EQ(v.str(), \"SparseXorVec{2, 5}\");\n    v.xor_item(5000);\n    ASSERT_EQ(v.str(), \"SparseXorVec{2, 5, 5000}\");\n}\n\nTEST(sparse_xor_table, empty) {\n    SparseXorVec<uint32_t> v1;\n    ASSERT_TRUE(v1.empty());\n    v1.xor_item(1);\n    ASSERT_FALSE(v1.empty());\n    v1.xor_item(3);\n    ASSERT_FALSE(v1.empty());\n}\n\nTEST(sparse_xor_vec, is_subset_of_sorted) {\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{}, (SpanRef<const uint32_t>)std::vector<uint32_t>{}));\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{}, (SpanRef<const uint32_t>)std::vector<uint32_t>{0}));\n    ASSERT_FALSE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0}, (SpanRef<const uint32_t>)std::vector<uint32_t>{}));\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0}, (SpanRef<const uint32_t>)std::vector<uint32_t>{0}));\n    ASSERT_FALSE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{1}, (SpanRef<const uint32_t>)std::vector<uint32_t>{0}));\n    ASSERT_FALSE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0}, (SpanRef<const uint32_t>)std::vector<uint32_t>{1}));\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{1},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_FALSE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{2},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{5},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{6},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_FALSE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{7},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{8},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_FALSE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{9},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 5},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_TRUE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 6},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n    ASSERT_FALSE(is_subset_of_sorted(\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 2, 6},\n        (SpanRef<const uint32_t>)std::vector<uint32_t>{0, 1, 5, 6, 8}));\n}\n\nTEST(sparse_xor_vec, is_superset_of) {\n    ASSERT_TRUE((SparseXorVec<uint32_t>{{0}}).is_superset_of(SparseXorVec<uint32_t>{{0}}.range()));\n    ASSERT_TRUE((SparseXorVec<uint32_t>{{0, 1}}).is_superset_of(SparseXorVec<uint32_t>{{0}}.range()));\n    ASSERT_FALSE((SparseXorVec<uint32_t>{{0}}).is_superset_of(SparseXorVec<uint32_t>{{0, 1}}.range()));\n}\n\nTEST(sparse_xor_vec, contains) {\n    ASSERT_TRUE((SparseXorVec<uint32_t>{{0}}).contains(0));\n    ASSERT_TRUE((SparseXorVec<uint32_t>{{2}}).contains(2));\n    ASSERT_TRUE((SparseXorVec<uint32_t>{{0, 2}}).contains(0));\n    ASSERT_TRUE((SparseXorVec<uint32_t>{{0, 2}}).contains(2));\n    ASSERT_FALSE((SparseXorVec<uint32_t>{{0, 2}}).contains(1));\n    ASSERT_FALSE((SparseXorVec<uint32_t>{{}}).contains(0));\n    ASSERT_FALSE((SparseXorVec<uint32_t>{{1}}).contains(0));\n}\n\nTEST(sparse_xor_vec, inplace_xor_sort) {\n    auto f = [](std::vector<int> v) -> std::vector<int> {\n        SpanRef<int> s = v;\n        auto r = inplace_xor_sort(s);\n        v.resize(r.size());\n        return v;\n    };\n    ASSERT_EQ(f({}), (std::vector<int>({})));\n    ASSERT_EQ(f({5}), (std::vector<int>({5})));\n    ASSERT_EQ(f({5, 5}), (std::vector<int>({})));\n    ASSERT_EQ(f({5, 5, 5}), (std::vector<int>({5})));\n    ASSERT_EQ(f({5, 5, 5, 5}), (std::vector<int>({})));\n    ASSERT_EQ(f({5, 4, 5, 5}), (std::vector<int>({4, 5})));\n    ASSERT_EQ(f({4, 5, 5, 5}), (std::vector<int>({4, 5})));\n    ASSERT_EQ(f({5, 5, 5, 4}), (std::vector<int>({4, 5})));\n    ASSERT_EQ(f({4, 5, 5, 4}), (std::vector<int>({})));\n    ASSERT_EQ(f({3, 5, 5, 4}), (std::vector<int>({3, 4})));\n}\n"
  },
  {
    "path": "src/stim/perf.perf.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_PERF_PERF_H\n#define _STIM_PERF_PERF_H\n\n#include <chrono>\n#include <functional>\n#include <string>\n#include <vector>\n\nextern double BENCHMARK_CONFIG_TARGET_SECONDS;\n\nstruct BenchmarkResult {\n    double total_seconds;\n    size_t total_reps;\n    std::vector<std::pair<std::string, double>> marginal_rates;\n    double goal_seconds;\n\n    BenchmarkResult(double total_seconds, size_t total_reps)\n        : total_seconds(total_seconds), total_reps(total_reps), marginal_rates(), goal_seconds(-1) {\n    }\n\n    BenchmarkResult &show_rate(std::string_view new_unit_name, double new_multiplier) {\n        marginal_rates.emplace_back(new_unit_name, new_multiplier);\n        return *this;\n    }\n\n    BenchmarkResult &goal_nanos(double nanos) {\n        goal_seconds = nanos / 1000 / 1000 / 1000;\n        return *this;\n    }\n\n    BenchmarkResult &goal_micros(double micros) {\n        goal_seconds = micros / 1000 / 1000;\n        return *this;\n    }\n\n    BenchmarkResult &goal_millis(double millis) {\n        goal_seconds = millis / 1000;\n        return *this;\n    }\n};\n\nstruct RegisteredBenchmark {\n    std::string name;\n    std::function<void(void)> func;\n    std::vector<BenchmarkResult> results;\n};\nextern RegisteredBenchmark *running_benchmark;\nextern std::vector<RegisteredBenchmark> *all_registered_benchmarks_data;\nextern uint64_t registry_initialized;\ninline void add_benchmark(RegisteredBenchmark benchmark) {\n    if (all_registered_benchmarks_data == nullptr || registry_initialized != 4620243525989388168ULL) {\n        registry_initialized = 4620243525989388168ULL;\n        all_registered_benchmarks_data = new std::vector<RegisteredBenchmark>();\n    }\n    all_registered_benchmarks_data->push_back(benchmark);\n}\n\n#define BENCHMARK(name)                                             \\\n    void BENCH_##name##_METHOD();                                   \\\n    struct BENCH_STARTUP_TYPE_##name {                              \\\n        BENCH_STARTUP_TYPE_##name() {                               \\\n            add_benchmark({#name, BENCH_##name##_METHOD});          \\\n        }                                                           \\\n    };                                                              \\\n    static BENCH_STARTUP_TYPE_##name BENCH_STARTUP_INSTANCE_##name; \\\n    void BENCH_##name##_METHOD()\n\n// HACK: Templating the body function type makes inlining significantly more likely.\ntemplate <typename FUNC>\nBenchmarkResult &benchmark_go(FUNC body) {\n    size_t total_reps = 0;\n    double total_seconds = 0.0;\n    double target_wait_time_seconds = BENCHMARK_CONFIG_TARGET_SECONDS;\n\n    for (size_t rep_limit = 1; total_seconds < target_wait_time_seconds; rep_limit *= 100) {\n        double remaining_time = target_wait_time_seconds - total_seconds;\n        size_t reps = rep_limit;\n        if (total_seconds > 0) {\n            reps = (size_t)(remaining_time * total_reps / total_seconds);\n            if (reps < total_reps * 0.1) {\n                break;\n            }\n            if (reps > rep_limit) {\n                reps = rep_limit;\n            }\n            if (reps < 1) {\n                reps = 1;\n            }\n        }\n        auto start = std::chrono::steady_clock::now();\n        for (size_t rep = 0; rep < reps; rep++) {\n            body();\n        }\n        auto end = std::chrono::steady_clock::now();\n        auto micros = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();\n        total_reps += reps;\n        total_seconds += (double)micros / 1000.0 / 1000.0;\n    }\n\n    running_benchmark->results.push_back({total_seconds, total_reps});\n    return running_benchmark->results.back();\n}\n\n#endif\n"
  },
  {
    "path": "src/stim/py/README.md",
    "content": "# `py` directory\n\nThis directory contains code related to exposing a Python 3 API for stim, using `pybind11`.\n"
  },
  {
    "path": "src/stim/py/base.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/py/base.pybind.h\"\n\n#include <memory>\n\n#include \"stim/util_bot/probability_util.h\"\n\nusing namespace stim;\n\nstd::mt19937_64 stim_pybind::make_py_seeded_rng(const pybind11::object &seed) {\n    if (seed.is_none()) {\n        return externally_seeded_rng();\n    }\n\n    try {\n        uint64_t s = pybind11::cast<uint64_t>(seed) ^ INTENTIONAL_VERSION_SEED_INCOMPATIBILITY;\n        return std::mt19937_64(s);\n    } catch (const pybind11::cast_error &) {\n        throw std::invalid_argument(\"Expected seed to be None or a 64 bit unsigned integer.\");\n    }\n}\n\nbool stim_pybind::normalize_index_or_slice(\n    const pybind11::object &index_or_slice,\n    size_t length,\n    pybind11::ssize_t *start,\n    pybind11::ssize_t *step,\n    pybind11::ssize_t *slice_length) {\n    try {\n        *start = pybind11::cast<pybind11::ssize_t>(index_or_slice);\n        if (*start < 0) {\n            *start += length;\n        }\n        if (*start < 0 || (size_t)*start >= length) {\n            throw std::out_of_range(\n                \"Index \" + std::to_string(pybind11::cast<pybind11::ssize_t>(index_or_slice)) +\n                \" not in range for sequence of length \" + std::to_string(length) + \".\");\n        }\n        *step = 0;\n        *slice_length = 1;\n        return false;\n    } catch (const pybind11::cast_error &) {\n    }\n\n    pybind11::slice slice;\n    try {\n        slice = pybind11::cast<pybind11::slice>(index_or_slice);\n    } catch (const pybind11::cast_error &ex) {\n        throw pybind11::type_error(\"Expected an integer index or a slice.\");\n    }\n\n    pybind11::ssize_t stop;\n    if (!slice.compute(length, start, &stop, step, slice_length)) {\n        throw pybind11::error_already_set();\n    }\n    return true;\n}\n\nSampleFormat stim_pybind::format_to_enum(std::string_view format) {\n    auto found_format = format_name_to_enum_map().find(format);\n    if (found_format == format_name_to_enum_map().end()) {\n        std::stringstream msg;\n        msg << \"Unrecognized output format: '\" << format << \"'. Recognized formats are:\\n\";\n        for (const auto &kv : format_name_to_enum_map()) {\n            msg << \"    \" << kv.first << \"\\n\";\n        }\n        throw std::invalid_argument(msg.str());\n    }\n    return found_format->second.id;\n}\n"
  },
  {
    "path": "src/stim/py/base.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_PY_BASE_PYBIND_H\n#define _STIM_PY_BASE_PYBIND_H\n\n#include <pybind11/complex.h>\n#include <pybind11/numpy.h>\n#include <pybind11/operators.h>\n#include <pybind11/pybind11.h>\n#include <pybind11/stl.h>\n#include <random>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/cmd/command_help.h\"\n#include \"stim/io/stim_data_formats.h\"\n\nnamespace stim_pybind {\n\nstd::mt19937_64 make_py_seeded_rng(const pybind11::object &seed);\nstim::SampleFormat format_to_enum(std::string_view format);\n\n/// Converts a python index or slice into a form that's easier to consume.\n///\n/// In particular, replaces negative indices with non-negative indices.\n/// When the object is an integer, it is treated as a slice over a single\n/// index. The boolean returned from the method can be used to distinguish\n/// a single-index slice from an integer index.\n///\n/// The result can be consumed as follows:\n///\n///     pybind11::ssize_t slice_start;\n///     pybind11::ssize_t slice_step;\n///     pybind11::ssize_t slice_length;\n///     bool was_slice = normalize_index_or_slice(\n///        obj,\n///        collection_length,\n///        &slice_start,\n///        &slice_step,\n///        &slice_length)\n///     for (size_t k = 0; k < (size_t)slice_length; k++) {\n///         size_t target_k = index + step * k;\n///         auto &target = collection[slice_start + slice_step*k];\n///         ...\n///     }\n///\n/// Args:\n///     index_or_slice: An int or slice object.\n///     length: The length of the collection being indexed or sliced.\n///     start: Output address for the offset to use when looping.\n///         The value written to this pointer will be non-negative\n//          (unless an exception is thrown).\n///     step: Output address for the stride to use when looping.\n///         The value written to this pointer may be negative.\n///     slice_length: Output address for how many iterations to run the loop.\n///         The value written to this pointer will be non-negative\n//          (unless an exception is thrown).\n///\n/// Returns:\n///     True: the given object was a slice.\n///     False: the given object was an integer index.\n///\n/// Raises:\n///     invalid_argument: The given object was not a valid slice or index for\n///         the given collection length;\nbool normalize_index_or_slice(\n    const pybind11::object &index_or_slice,\n    size_t length,\n    pybind11::ssize_t *start,\n    pybind11::ssize_t *step,\n    pybind11::ssize_t *slice_length);\n\ntemplate <typename T>\npybind11::tuple tuple_tree(const std::vector<T> &val, size_t offset = 0) {\n    // A workaround for https://github.com/pybind/pybind11/issues/1928\n    if (offset >= val.size()) {\n        return pybind11::make_tuple();\n    }\n    if (offset + 1 == val.size()) {\n        return pybind11::make_tuple(val[offset]);\n    }\n    return pybind11::make_tuple(val[offset], tuple_tree(val, offset + 1));\n}\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/py/compiled_detector_sampler.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/py/compiled_detector_sampler.pybind.h\"\n\n#include \"stim/circuit/circuit.pybind.h\"\n#include \"stim/io/raii_file.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nCompiledDetectorSampler::CompiledDetectorSampler(Circuit init_circuit, std::mt19937_64 &&rng)\n    : circuit_stats(init_circuit.compute_stats()),\n      circuit(std::move(init_circuit)),\n      frame_sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 0, std::move(rng)) {\n}\n\npybind11::object CompiledDetectorSampler::sample_to_numpy(\n    size_t num_shots,\n    bool prepend_observables,\n    bool append_observables,\n    bool separate_observables,\n    bool bit_packed,\n    pybind11::object dets_out,\n    pybind11::object obs_out) {\n    if (separate_observables && (append_observables || prepend_observables)) {\n        throw std::invalid_argument(\n            \"Can't specify separate_observables=True with append_observables=True or prepend_observables=True\");\n    }\n\n    {\n        pybind11::gil_scoped_release release;\n        frame_sim.configure_for(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_shots);\n        frame_sim.reset_all();\n        frame_sim.do_circuit(circuit);\n    }\n\n    const auto &det_data = frame_sim.det_record.storage;\n    const auto &obs_data = frame_sim.obs_record;\n\n    pybind11::object py_obs_data = pybind11::none();\n    if (separate_observables || !obs_out.is_none()) {\n        py_obs_data =\n            simd_bit_table_to_numpy(obs_data, circuit_stats.num_observables, num_shots, bit_packed, true, obs_out);\n    }\n\n    pybind11::object py_det_data = pybind11::none();\n    if (append_observables || prepend_observables) {\n        size_t num_concat = circuit_stats.num_detectors;\n        simd_bit_table<MAX_BITWORD_WIDTH> concat_data = det_data;\n        if (append_observables) {\n            concat_data = concat_data.concat_major(obs_data, num_concat, circuit_stats.num_observables);\n            num_concat += circuit_stats.num_observables;\n        }\n        if (prepend_observables) {\n            concat_data = obs_data.concat_major(concat_data, circuit_stats.num_observables, num_concat);\n            num_concat += circuit_stats.num_observables;\n        }\n        py_det_data = simd_bit_table_to_numpy(concat_data, num_concat, num_shots, bit_packed, true, dets_out);\n    } else {\n        py_det_data =\n            simd_bit_table_to_numpy(det_data, circuit_stats.num_detectors, num_shots, bit_packed, true, dets_out);\n    }\n\n    if (separate_observables) {\n        return pybind11::make_tuple(py_det_data, py_obs_data);\n    } else {\n        return py_det_data;\n    }\n}\n\nvoid CompiledDetectorSampler::sample_write(\n    size_t num_samples,\n    pybind11::object filepath_obj,\n    std::string_view format,\n    bool prepend_observables,\n    bool append_observables,\n    pybind11::object obs_out_filepath_obj,\n    std::string_view obs_out_format) {\n    auto f = format_to_enum(format);\n\n    auto py_path = pybind11::module::import(\"pathlib\").attr(\"Path\");\n    if (pybind11::isinstance(filepath_obj, py_path)) {\n        filepath_obj = pybind11::str(filepath_obj);\n    }\n    if (pybind11::isinstance(obs_out_filepath_obj, py_path)) {\n        obs_out_filepath_obj = pybind11::str(obs_out_filepath_obj);\n    }\n\n    std::string_view filepath;\n    if (pybind11::isinstance<pybind11::str>(filepath_obj)) {\n        filepath = pybind11::cast<std::string_view>(filepath_obj);\n    } else {\n        std::stringstream ss;\n        ss << \"Don't know how to write to \";\n        ss << pybind11::repr(filepath_obj);\n        throw std::invalid_argument(ss.str());\n    }\n\n    std::string_view obs_out_filepath_view;\n    if (pybind11::isinstance<pybind11::str>(obs_out_filepath_obj)) {\n        obs_out_filepath_view = pybind11::cast<std::string_view>(obs_out_filepath_obj);\n    } else if (obs_out_filepath_obj.is_none()) {\n        // Empty string view does the right thing.\n    } else {\n        std::stringstream ss;\n        ss << \"Don't know how to write observables to \";\n        ss << pybind11::repr(obs_out_filepath_obj);\n        throw std::invalid_argument(ss.str());\n    }\n\n    RaiiFile out(filepath, \"wb\");\n    RaiiFile obs_out(obs_out_filepath_view, \"wb\");\n    auto parsed_obs_out_format = format_to_enum(obs_out_format);\n    sample_batch_detection_events_writing_results_to_disk<MAX_BITWORD_WIDTH>(\n        circuit,\n        num_samples,\n        prepend_observables,\n        append_observables,\n        out.f,\n        f,\n        frame_sim.rng,\n        obs_out.f,\n        parsed_obs_out_format);\n}\n\nstd::string CompiledDetectorSampler::repr() const {\n    std::stringstream result;\n    result << \"stim.CompiledDetectorSampler(\";\n    result << circuit_repr(circuit);\n    result << \")\";\n    return result.str();\n}\n\nCompiledDetectorSampler stim_pybind::py_init_compiled_detector_sampler(\n    const Circuit &circuit, const pybind11::object &seed) {\n    return CompiledDetectorSampler(circuit, make_py_seeded_rng(seed));\n}\n\npybind11::class_<CompiledDetectorSampler> stim_pybind::pybind_compiled_detector_sampler(pybind11::module &m) {\n    return pybind11::class_<CompiledDetectorSampler>(\n        m, \"CompiledDetectorSampler\", \"An analyzed stabilizer circuit whose detection events can be sampled quickly.\");\n}\n\nvoid stim_pybind::pybind_compiled_detector_sampler_methods(\n    pybind11::module &m, pybind11::class_<CompiledDetectorSampler> &c) {\n    c.def(\n        pybind11::init(&py_init_compiled_detector_sampler),\n        pybind11::arg(\"circuit\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"seed\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            Creates an object that can sample the detection events from a circuit.\n\n            Args:\n                circuit: The circuit to sample from.\n                seed: PARTIALLY determines simulation results by deterministically seeding\n                    the random number generator.\n\n                    Must be None or an integer in range(2**64).\n\n                    Defaults to None. When None, the prng is seeded from system entropy.\n\n                    When set to an integer, making the exact same series calls on the exact\n                    same machine with the exact same version of Stim will produce the exact\n                    same simulation results.\n\n                    CAUTION: simulation results *WILL NOT* be consistent between versions of\n                    Stim. This restriction is present to make it possible to have future\n                    optimizations to the random sampling, and is enforced by introducing\n                    intentional differences in the seeding strategy from version to version.\n\n                    CAUTION: simulation results *MAY NOT* be consistent across machines that\n                    differ in the width of supported SIMD instructions. For example, using\n                    the same seed on a machine that supports AVX instructions and one that\n                    only supports SSE instructions may produce different simulation results.\n\n                    CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                    shots are taken. For example, taking 10 shots and then 90 shots will\n                    give different results from taking 100 shots in one call.\n\n            Returns:\n                An initialized stim.CompiledDetectorSampler.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    H 0\n                ...    CNOT 0 1\n                ...    X_ERROR(1.0) 0\n                ...    M 0 1\n                ...    DETECTOR rec[-1] rec[-2]\n                ... ''')\n                >>> s = c.compile_detector_sampler()\n                >>> s.sample(shots=1)\n                array([[ True]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sample\",\n        [](CompiledDetectorSampler &self,\n           size_t shots,\n           bool prepend,\n           bool append,\n           bool separate_observables,\n           bool bit_packed,\n           pybind11::object dets_out,\n           pybind11::object obs_out) {\n            return self.sample_to_numpy(shots, prepend, append, separate_observables, bit_packed, dets_out, obs_out);\n        },\n        pybind11::arg(\"shots\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"prepend_observables\") = false,\n        pybind11::arg(\"append_observables\") = false,\n        pybind11::arg(\"separate_observables\") = false,\n        pybind11::arg(\"bit_packed\") = false,\n        pybind11::arg(\"dets_out\") = pybind11::none(),\n        pybind11::arg(\"obs_out\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def sample(self, shots: int, *, prepend_observables: bool = False, append_observables: bool = False, separate_observables: bool = False, bit_packed: bool = False, dets_out: Optional[np.ndarray] = None, obs_out: Optional[np.ndarray] = None) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:\n            Returns a numpy array containing a batch of detector samples from the circuit.\n\n            The circuit must define the detectors using DETECTOR instructions. Observables\n            defined by OBSERVABLE_INCLUDE instructions can also be included in the results\n            as honorary detectors.\n\n            Args:\n                shots: The number of times to sample every detector in the circuit.\n                separate_observables: Defaults to False. When set to True, the return value\n                    is a (detection_events, observable_flips) tuple instead of a flat\n                    detection_events array.\n                prepend_observables: Defaults to false. When set, observables are included\n                    with the detectors and are placed at the start of the results.\n                append_observables: Defaults to false. When set, observables are included\n                    with the detectors and are placed at the end of the results.\n                bit_packed: Returns a uint8 numpy array with 8 bits per byte, instead of\n                    a bool_ numpy array with 1 bit per byte. Uses little endian packing.\n                dets_out: Defaults to None. Specifies a pre-allocated numpy array to write\n                    the detection event data into. This array must have the correct shape\n                    and dtype.\n                obs_out: Defaults to None. Specifies a pre-allocated numpy array to write\n                    the observable flip data into. This array must have the correct shape\n                    and dtype.\n\n            Returns:\n                A numpy array or tuple of numpy arrays containing the samples.\n\n                if separate_observables=False and bit_packed=False:\n                    A single numpy array.\n                    dtype=bool_\n                    shape=(\n                        shots,\n                        num_detectors + num_observables * (\n                            append_observables + prepend_observables),\n                    )\n                    The bit for detection event `m` in shot `s` is at\n                        result[s, m]\n\n                if separate_observables=False and bit_packed=True:\n                    A single numpy array.\n                    dtype=uint8\n                    shape=(\n                        shots,\n                        math.ceil((num_detectors + num_observables * (\n                            append_observables + prepend_observables)) / 8),\n                    )\n                    The bit for detection event `m` in shot `s` is at\n                        (result[s, m // 8] >> (m % 8)) & 1\n\n                if separate_observables=True and bit_packed=False:\n                    A (dets, obs) tuple.\n                    dets.dtype=bool_\n                    dets.shape=(shots, num_detectors)\n                    obs.dtype=bool_\n                    obs.shape=(shots, num_observables)\n                    The bit for detection event `m` in shot `s` is at\n                        dets[s, m]\n                    The bit for observable `m` in shot `s` is at\n                        obs[s, m]\n\n                if separate_observables=True and bit_packed=True:\n                    A (dets, obs) tuple.\n                    dets.dtype=uint8\n                    dets.shape=(shots, math.ceil(num_detectors / 8))\n                    obs.dtype=uint8\n                    obs.shape=(shots, math.ceil(num_observables / 8))\n                    The bit for detection event `m` in shot `s` is at\n                        (dets[s, m // 8] >> (m % 8)) & 1\n                    The bit for observable `m` in shot `s` is at\n                        (obs[s, m // 8] >> (m % 8)) & 1\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    H 0\n                ...    CNOT 0 1\n                ...    X_ERROR(1.0) 0\n                ...    M 0 1\n                ...    DETECTOR rec[-1] rec[-2]\n                ... ''')\n                >>> s = c.compile_detector_sampler()\n                >>> s.sample(shots=1)\n                array([[ True]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sample_bit_packed\",\n        [](CompiledDetectorSampler &self, size_t shots, bool prepend, bool append) {\n            return self.sample_to_numpy(shots, prepend, append, false, true, pybind11::none(), pybind11::none());\n        },\n        pybind11::arg(\"shots\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"prepend_observables\") = false,\n        pybind11::arg(\"append_observables\") = false,\n        clean_doc_string(R\"DOC(\n            [DEPRECATED] Use sampler.sample(..., bit_packed=True) instead.\n\n            Returns a numpy array containing bit packed detector samples from the circuit.\n\n            The circuit must define the detectors using DETECTOR instructions. Observables\n            defined by OBSERVABLE_INCLUDE instructions can also be included in the results\n            as honorary detectors.\n\n            Args:\n                shots: The number of times to sample every detector in the circuit.\n                prepend_observables: Defaults to false. When set, observables are included\n                    with the detectors and are placed at the start of the results.\n                append_observables: Defaults to false. When set, observables are included\n                    with the detectors and are placed at the end of the results.\n\n            Returns:\n                A numpy array with `dtype=uint8` and `shape=(shots, n)` where `n` is\n                `num_detectors + num_observables*(append_observables+prepend_observables)`.\n                The bit for detection event `m` in shot `s` is at\n                `result[s, (m // 8)] & 2**(m % 8)`.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sample_write\",\n        &CompiledDetectorSampler::sample_write,\n        pybind11::arg(\"shots\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"filepath\"),\n        pybind11::arg(\"format\") = \"01\",\n        pybind11::arg(\"prepend_observables\") = false,\n        pybind11::arg(\"append_observables\") = false,\n        pybind11::arg(\"obs_out_filepath\") = pybind11::none(),\n        pybind11::arg(\"obs_out_format\") = \"01\",\n        clean_doc_string(R\"DOC(\n            @signature def sample_write(self, shots: int, *, filepath: Union[str, pathlib.Path], format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01', obs_out_filepath: Optional[Union[str, pathlib.Path]] = None, obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01', prepend_observables: bool = False, append_observables: bool = False) -> None:\n            Samples detection events from the circuit and writes them to a file.\n\n            Args:\n                shots: The number of times to sample every measurement in the circuit.\n                filepath: The file to write the results to.\n                format: The output format to write the results with.\n                    Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                    Defaults to \"01\".\n                obs_out_filepath: Sample observables as part of each shot, and write them to\n                    this file. This keeps the observable data separate from the detector\n                    data.\n                obs_out_format: If writing the observables to a file, this is the format to\n                    write them in.\n\n                    Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                    Defaults to \"01\".\n                prepend_observables: Sample observables as part of each shot, and put them\n                    at the start of the detector data.\n                append_observables: Sample observables as part of each shot, and put them at\n                    the end of the detector data.\n\n            Returns:\n                None.\n\n            Examples:\n                >>> import stim\n                >>> import tempfile\n                >>> with tempfile.TemporaryDirectory() as d:\n                ...     path = f\"{d}/tmp.dat\"\n                ...     c = stim.Circuit('''\n                ...         X_ERROR(1) 0\n                ...         M 0 1\n                ...         DETECTOR rec[-2]\n                ...         DETECTOR rec[-1]\n                ...     ''')\n                ...     c.compile_detector_sampler().sample_write(\n                ...         shots=3,\n                ...         filepath=path,\n                ...         format=\"dets\")\n                ...     with open(path) as f:\n                ...         print(f.read(), end='')\n                shot D0\n                shot D0\n                shot D0\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__repr__\",\n        &CompiledDetectorSampler::repr,\n        \"Returns valid python code evaluating to an equivalent `stim.CompiledDetectorSampler`.\");\n}\n"
  },
  {
    "path": "src/stim/py/compiled_detector_sampler.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_PY_COMPILED_DETECTOR_SAMPLER_PYBIND_H\n#define _STIM_PY_COMPILED_DETECTOR_SAMPLER_PYBIND_H\n\n#include <pybind11/numpy.h>\n#include <pybind11/pybind11.h>\n#include <pybind11/stl.h>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/simulators/frame_simulator.h\"\n\nnamespace stim_pybind {\n\nstruct CompiledDetectorSampler {\n    stim::CircuitStats circuit_stats;\n    stim::Circuit circuit;\n    stim::FrameSimulator<stim::MAX_BITWORD_WIDTH> frame_sim;\n\n    CompiledDetectorSampler() = delete;\n    CompiledDetectorSampler(const CompiledDetectorSampler &) = delete;\n    CompiledDetectorSampler(CompiledDetectorSampler &&) = default;\n    CompiledDetectorSampler(stim::Circuit circuit, std::mt19937_64 &&rng);\n    pybind11::object sample_to_numpy(\n        size_t num_shots,\n        bool prepend_observables,\n        bool append_observables,\n        bool separate_observables,\n        bool bit_packed,\n        pybind11::object dets_out,\n        pybind11::object obs_out);\n    void sample_write(\n        size_t num_samples,\n        pybind11::object filepath_obj,\n        std::string_view format,\n        bool prepend_observables,\n        bool append_observables,\n        pybind11::object obs_out_filepath_obj,\n        std::string_view obs_out_format);\n    std::string repr() const;\n};\n\npybind11::class_<CompiledDetectorSampler> pybind_compiled_detector_sampler(pybind11::module &m);\nvoid pybind_compiled_detector_sampler_methods(pybind11::module &m, pybind11::class_<CompiledDetectorSampler> &c);\nCompiledDetectorSampler py_init_compiled_detector_sampler(const stim::Circuit &circuit, const pybind11::object &seed);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/py/compiled_detector_sampler_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport pathlib\n\nimport tempfile\n\nimport numpy as np\nimport pytest\nimport stim\n\n\ndef test_compiled_detector_sampler_trivial():\n    c = stim.Circuit(\"\"\"\n        X_ERROR(1) 0\n        M 0\n        DETECTOR rec[-1]\n    \"\"\")\n    np.testing.assert_array_equal(\n        c.compile_detector_sampler().sample(shots=2),\n        np.array([\n            [1],\n            [1],\n        ], dtype=np.bool_))\n\n\ndef test_compiled_detector_sampler_sample():\n    c = stim.Circuit(\"\"\"\n        X_ERROR(1) 0\n        M 0 1 2\n        DETECTOR rec[-3] rec[-2]\n        DETECTOR rec[-3] rec[-1]\n        DETECTOR rec[-1] rec[-2]\n        OBSERVABLE_INCLUDE(0) rec[-3]\n        OBSERVABLE_INCLUDE(3) rec[-2] rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-2]\n    \"\"\")\n    np.testing.assert_array_equal(\n        c.compile_detector_sampler().sample(5),\n        np.array([\n            [1, 1, 0],\n            [1, 1, 0],\n            [1, 1, 0],\n            [1, 1, 0],\n            [1, 1, 0],\n        ], dtype=np.bool_))\n    np.testing.assert_array_equal(\n        c.compile_detector_sampler().sample(5, prepend_observables=True),\n        np.array([\n            [1, 0, 0, 0, 1, 1, 0],\n            [1, 0, 0, 0, 1, 1, 0],\n            [1, 0, 0, 0, 1, 1, 0],\n            [1, 0, 0, 0, 1, 1, 0],\n            [1, 0, 0, 0, 1, 1, 0],\n        ], dtype=np.bool_))\n    np.testing.assert_array_equal(\n        c.compile_detector_sampler().sample(5, append_observables=True),\n        np.array([\n            [1, 1, 0, 1, 0, 0, 0],\n            [1, 1, 0, 1, 0, 0, 0],\n            [1, 1, 0, 1, 0, 0, 0],\n            [1, 1, 0, 1, 0, 0, 0],\n            [1, 1, 0, 1, 0, 0, 0],\n        ], dtype=np.bool_))\n\n    dets, obs = c.compile_detector_sampler().sample(5, separate_observables=True)\n    np.testing.assert_array_equal(\n        dets,\n        np.array([\n            [1, 1, 0],\n            [1, 1, 0],\n            [1, 1, 0],\n            [1, 1, 0],\n            [1, 1, 0],\n        ], dtype=np.bool_))\n    np.testing.assert_array_equal(\n        obs,\n        np.array([\n            [1, 0, 0, 0],\n            [1, 0, 0, 0],\n            [1, 0, 0, 0],\n            [1, 0, 0, 0],\n            [1, 0, 0, 0],\n        ], dtype=np.uint8))\n    dets, obs = c.compile_detector_sampler().sample(5, separate_observables=True, bit_packed=True)\n    np.testing.assert_array_equal(\n        dets,\n        np.array([\n            [3],\n            [3],\n            [3],\n            [3],\n            [3],\n        ], dtype=np.uint8))\n    np.testing.assert_array_equal(\n        obs,\n        np.array([\n            [1],\n            [1],\n            [1],\n            [1],\n            [1],\n        ], dtype=np.uint8))\n\n    np.testing.assert_array_equal(\n        c.compile_detector_sampler().sample(5, append_observables=True, prepend_observables=True),\n        np.array([\n            [1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0],\n            [1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0],\n            [1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0],\n            [1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0],\n            [1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0],\n        ], dtype=np.bool_))\n    np.testing.assert_array_equal(\n        c.compile_detector_sampler().sample_bit_packed(5),\n        np.array([\n            [0b011],\n            [0b011],\n            [0b011],\n            [0b011],\n            [0b011],\n        ], dtype=np.uint8))\n    np.testing.assert_array_equal(\n        c.compile_detector_sampler().sample(5, bit_packed=True),\n        np.array([\n            [0b011],\n            [0b011],\n            [0b011],\n            [0b011],\n            [0b011],\n        ], dtype=np.uint8))\n\n    with tempfile.TemporaryDirectory() as d:\n        path = f\"{d}/tmp.dat\"\n        c.compile_detector_sampler().sample_write(5, filepath=path, format='b8')\n        with open(path, 'rb') as f:\n            assert f.read() == b'\\x03' * 5\n\n        c.compile_detector_sampler().sample_write(5, filepath=pathlib.Path(path), format='b8')\n        with open(path, 'rb') as f:\n            assert f.read() == b'\\x03' * 5\n\n        c.compile_detector_sampler().sample_write(5, filepath=path, format='01', prepend_observables=True)\n        with open(path, 'r') as f:\n            assert f.readlines() == ['1000110\\n'] * 5\n\n        c.compile_detector_sampler().sample_write(5, filepath=path, format='01', append_observables=True)\n        with open(path, 'r') as f:\n            assert f.readlines() == ['1101000\\n'] * 5\n\n\ndef test_write_obs_file():\n    c = stim.Circuit(\"\"\"\n        X_ERROR(1) 1\n        MR 0 1\n        DETECTOR rec[-2]\n        DETECTOR rec[-2]\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-2]\n        OBSERVABLE_INCLUDE(1) rec[-1]\n        OBSERVABLE_INCLUDE(2) rec[-2]\n    \"\"\")\n    r: stim.CompiledDetectorSampler = c.compile_detector_sampler()\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        r.sample_write(\n            shots=100,\n            filepath=str(d / 'det'),\n            format='dets',\n            obs_out_filepath=str(d / 'obs'),\n            obs_out_format='hits',\n        )\n        with open(d / 'det') as f:\n            assert f.read() == 'shot D3\\n' * 100\n        with open(d / 'obs') as f:\n            assert f.read() == '1\\n' * 100\n\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        r.sample_write(\n            shots=100,\n            filepath=d / 'det',\n            format='dets',\n            obs_out_filepath=d / 'obs',\n            obs_out_format='hits',\n        )\n        with open(d / 'det') as f:\n            assert f.read() == 'shot D3\\n' * 100\n        with open(d / 'obs') as f:\n            assert f.read() == '1\\n' * 100\n\ndef test_detector_sampler_actually_fills_array():\n    circuit = stim.Circuit('''\n       X_ERROR(1) 0\n       M 0\n       DETECTOR rec[-1]\n    ''')\n    sampler = circuit.compile_detector_sampler()\n    detector_data = sampler.sample(shots=10000)\n    assert np.all(detector_data)\n\n\ndef test_manual_output_buffer():\n    circuit = stim.Circuit('''\n        X_ERROR(1) 0\n        M 0\n        DETECTOR\n        DETECTOR\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n\n        DETECTOR rec[-1]\n        DETECTOR\n        DETECTOR\n        DETECTOR rec[-1]\n\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    ''')\n    sampler = circuit.compile_detector_sampler()\n\n    with pytest.raises(ValueError):\n        sampler.sample(shots=17, dets_out=np.zeros(shape=(17, 8), dtype=np.bool_))\n    with pytest.raises(ValueError):\n        sampler.sample(shots=17, dets_out=np.zeros(shape=(17, 10), dtype=np.bool_))\n    with pytest.raises(ValueError):\n        sampler.sample(shots=17, dets_out=np.zeros(shape=(18, 9), dtype=np.bool_))\n    with pytest.raises(ValueError):\n        sampler.sample(shots=17, dets_out=np.zeros(shape=(16, 9), dtype=np.bool_))\n    with pytest.raises(ValueError):\n        sampler.sample(shots=17, dets_out=np.zeros(shape=(17, 9), dtype=np.uint8))\n\n    buf = np.zeros(shape=(17, 9), dtype=np.bool_)\n    ret = sampler.sample(shots=17, dets_out=buf)\n    assert ret is buf\n    assert np.array_equal(buf, [[0, 0, 1, 1, 1, 0, 0, 1, 1]] * 17)\n\n    buf = np.zeros(shape=(17, 2), dtype=np.uint8)\n    ret = sampler.sample(\n        shots=17,\n        dets_out=buf,\n        bit_packed=True,\n    )\n    assert ret is buf\n    assert np.array_equal(buf, [[0b10011100, 0b1]] * 17)\n\n    buf = np.zeros(shape=(2, 17), dtype=np.uint8).transpose()\n    ret = sampler.sample(\n        shots=17,\n        dets_out=buf,\n        bit_packed=True,\n    )\n    assert ret is buf\n    assert np.array_equal(buf, [[0b10011100, 0b1]] * 17)\n\n    buf = np.zeros(shape=(17, 9), dtype=np.bool_)\n    buf2 = np.zeros(shape=(17, 1), dtype=np.bool_)\n    ret = sampler.sample(\n        shots=17,\n        dets_out=buf,\n        obs_out=buf2,\n    )\n    assert ret is buf\n    assert np.array_equal(buf, [[0, 0, 1, 1, 1, 0, 0, 1, 1]] * 17)\n    assert np.array_equal(buf2, [[1]] * 17)\n\n    buf = np.zeros(shape=(17, 9), dtype=np.bool_)\n    buf2 = np.zeros(shape=(17, 1), dtype=np.bool_)\n    ret, ret2 = sampler.sample(\n        shots=17,\n        dets_out=buf,\n        obs_out=buf2,\n        separate_observables=True,\n    )\n    assert ret is buf\n    assert ret2 is buf2\n    assert np.array_equal(buf, [[0, 0, 1, 1, 1, 0, 0, 1, 1]] * 17)\n    assert np.array_equal(buf2, [[1]] * 17)\n\n    buf = np.zeros(shape=(17, 10), dtype=np.bool_)\n    buf2 = np.zeros(shape=(17, 1), dtype=np.bool_)\n    ret = sampler.sample(\n        shots=17,\n        dets_out=buf,\n        obs_out=buf2,\n        append_observables=True,\n    )\n    assert ret is buf\n    assert np.array_equal(buf, [[0, 0, 1, 1, 1, 0, 0, 1, 1, 1]] * 17)\n    assert np.array_equal(buf2, [[1]] * 17)\n\n    buf = np.zeros(shape=(10, 17), dtype=np.bool_).transpose()\n    buf2 = np.zeros(shape=(17, 1), dtype=np.bool_)\n    ret = sampler.sample(\n        shots=17,\n        dets_out=buf,\n        obs_out=buf2,\n        append_observables=True,\n    )\n    assert ret is buf\n    assert np.array_equal(buf, [[0, 0, 1, 1, 1, 0, 0, 1, 1, 1]] * 17)\n    assert np.array_equal(buf2, [[1]] * 17)\n"
  },
  {
    "path": "src/stim/py/compiled_measurement_sampler.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/py/compiled_measurement_sampler.pybind.h\"\n\n#include \"stim/circuit/circuit.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nCompiledMeasurementSampler::CompiledMeasurementSampler(\n    simd_bits<MAX_BITWORD_WIDTH> ref_sample, Circuit circuit, bool skip_reference_sample, std::mt19937_64 &&rng)\n    : ref_sample(ref_sample), circuit(circuit), skip_reference_sample(skip_reference_sample), rng(std::move(rng)) {\n}\n\npybind11::object CompiledMeasurementSampler::sample_to_numpy(size_t num_shots, bool bit_packed) {\n    simd_bit_table<MAX_BITWORD_WIDTH> sample = sample_batch_measurements(circuit, ref_sample, num_shots, rng, false);\n    size_t bits_per_sample = circuit.count_measurements();\n    return simd_bit_table_to_numpy(sample, bits_per_sample, num_shots, bit_packed, true, pybind11::none());\n}\n\nvoid CompiledMeasurementSampler::sample_write(size_t num_samples, std::string_view filepath, std::string_view format) {\n    auto f = format_to_enum(format);\n    FILE *out = fopen(std::string(filepath).c_str(), \"wb\");\n    if (out == nullptr) {\n        throw std::invalid_argument(\"Failed to open '\" + std::string(filepath) + \"' to write.\");\n    }\n    sample_batch_measurements_writing_results_to_disk(circuit, ref_sample, num_samples, out, f, rng);\n    fclose(out);\n}\n\nstd::string CompiledMeasurementSampler::repr() const {\n    std::stringstream result;\n    result << \"stim.CompiledMeasurementSampler(\";\n    result << circuit_repr(circuit);\n    if (skip_reference_sample) {\n        result << \", skip_reference_sample=True\";\n    }\n    result << \")\";\n    return result.str();\n}\n\npybind11::class_<CompiledMeasurementSampler> stim_pybind::pybind_compiled_measurement_sampler(pybind11::module &m) {\n    return pybind11::class_<CompiledMeasurementSampler>(\n        m, \"CompiledMeasurementSampler\", \"An analyzed stabilizer circuit whose measurements can be sampled quickly.\");\n}\n\nCompiledMeasurementSampler stim_pybind::py_init_compiled_sampler(\n    const Circuit &circuit,\n    bool skip_reference_sample,\n    const pybind11::object &seed,\n    const pybind11::object &reference_sample) {\n    if (reference_sample.is_none()) {\n        simd_bits<MAX_BITWORD_WIDTH> ref_sample =\n            skip_reference_sample ? simd_bits<MAX_BITWORD_WIDTH>(circuit.count_measurements())\n                                  : TableauSimulator<MAX_BITWORD_WIDTH>::reference_sample_circuit(circuit);\n        return CompiledMeasurementSampler(ref_sample, circuit, skip_reference_sample, make_py_seeded_rng(seed));\n    } else {\n        if (skip_reference_sample) {\n            throw std::invalid_argument(\"skip_reference_sample = True but reference_sample is not None.\");\n        }\n        uint64_t num_bits = circuit.count_measurements();\n        simd_bits<MAX_BITWORD_WIDTH> ref_sample(num_bits);\n        simd_bits_range_ref<MAX_BITWORD_WIDTH> ref_sample_ref(ref_sample);\n        memcpy_bits_from_numpy_to_simd(num_bits, reference_sample, ref_sample_ref);\n        return CompiledMeasurementSampler(ref_sample, circuit, skip_reference_sample, make_py_seeded_rng(seed));\n    }\n}\n\nvoid stim_pybind::pybind_compiled_measurement_sampler_methods(\n    pybind11::module &m, pybind11::class_<CompiledMeasurementSampler> &c) {\n    c.def(\n        pybind11::init(&py_init_compiled_sampler),\n        pybind11::arg(\"circuit\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"skip_reference_sample\") = false,\n        pybind11::arg(\"seed\") = pybind11::none(),\n        pybind11::arg(\"reference_sample\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            Creates a measurement sampler for the given circuit.\n\n            The sampler uses a noiseless reference sample, collected from the circuit using\n            stim's Tableau simulator during initialization of the sampler, as a baseline for\n            deriving more samples using an error propagation simulator.\n\n            Args:\n                circuit: The stim circuit to sample from.\n                skip_reference_sample: Defaults to False. When set to True, the reference\n                    sample used by the sampler is initialized to all-zeroes instead of being\n                    collected from the circuit. This means that the results returned by the\n                    sampler are actually whether or not each measurement was *flipped*,\n                    instead of true measurement results.\n\n                    Forcing an all-zero reference sample is useful when you are only\n                    interested in error propagation and don't want to have to deal with the\n                    fact that some measurements want to be On when no errors occur. It is\n                    also useful when you know for sure that the all-zero result is actually\n                    a possible result from the circuit (under noiseless execution), meaning\n                    it is a valid reference sample as good as any other. Computing the\n                    reference sample is the most time consuming and memory intensive part of\n                    simulating the circuit, so promising that the simulator can safely skip\n                    that step is an effective optimization.\n                seed: PARTIALLY determines simulation results by deterministically seeding\n                    the random number generator.\n\n                    Must be None or an integer in range(2**64).\n\n                    Defaults to None. When None, the prng is seeded from system entropy.\n\n                    When set to an integer, making the exact same series calls on the exact\n                    same machine with the exact same version of Stim will produce the exact\n                    same simulation results.\n\n                    CAUTION: simulation results *WILL NOT* be consistent between versions of\n                    Stim. This restriction is present to make it possible to have future\n                    optimizations to the random sampling, and is enforced by introducing\n                    intentional differences in the seeding strategy from version to version.\n\n                    CAUTION: simulation results *MAY NOT* be consistent across machines that\n                    differ in the width of supported SIMD instructions. For example, using\n                    the same seed on a machine that supports AVX instructions and one that\n                    only supports SSE instructions may produce different simulation results.\n\n                    CAUTION: simulation results *MAY NOT* be consistent if you vary how many\n                    shots are taken. For example, taking 10 shots and then 90 shots will\n                    give different results from taking 100 shots in one call.\n                reference_sample: The data to xor into the measurement flips produced by the\n                    frame simulator, in order to produce proper measurement results.\n                    This can either be specified as an `np.bool_` array or a bit packed\n                    `np.uint8` array (little endian). Under normal conditions, the reference\n                    sample should be a valid noiseless sample of the circuit, such as the\n                    one returned by `circuit.reference_sample()`. If this argument is not\n                    provided, the reference sample will be set to\n                    `circuit.reference_sample()`, unless `skip_reference_sample=True`\n                    is used, in which case it will be set to all-zeros.\n\n            Returns:\n                An initialized stim.CompiledMeasurementSampler.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    X 0   2 3\n                ...    M 0 1 2 3\n                ... ''')\n                >>> s = c.compile_sampler()\n                >>> s.sample(shots=1)\n                array([[ True, False,  True,  True]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sample\",\n        [](CompiledMeasurementSampler &self, size_t shots, bool bit_packed) {\n            return self.sample_to_numpy(shots, bit_packed);\n        },\n        pybind11::arg(\"shots\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def sample(self, shots: int, *, bit_packed: bool = False) -> np.ndarray:\n            Samples a batch of measurement samples from the circuit.\n\n            Args:\n                shots: The number of times to sample every measurement in the circuit.\n                bit_packed: Returns a uint8 numpy array with 8 bits per byte, instead of\n                    a bool_ numpy array with 1 bit per byte. Uses little endian packing.\n\n            Returns:\n                A numpy array containing the samples.\n\n                If bit_packed=False:\n                    dtype=bool_\n                    shape=(shots, circuit.num_measurements)\n                    The bit for measurement `m` in shot `s` is at\n                        result[s, m]\n                If bit_packed=True:\n                    dtype=uint8\n                    shape=(shots, math.ceil(circuit.num_measurements / 8))\n                    The bit for measurement `m` in shot `s` is at\n                        (result[s, m // 8] >> (m % 8)) & 1\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    X 0   2 3\n                ...    M 0 1 2 3\n                ... ''')\n                >>> s = c.compile_sampler()\n                >>> s.sample(shots=1)\n                array([[ True, False,  True,  True]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sample_bit_packed\",\n        [](CompiledMeasurementSampler &self, size_t shots) {\n            return self.sample_to_numpy(shots, true);\n        },\n        pybind11::arg(\"shots\"),\n        clean_doc_string(R\"DOC(\n            [DEPRECATED] Use sampler.sample(..., bit_packed=True) instead.\n            @signature def sample_bit_packed(self, shots: int) -> np.ndarray:\n\n            Samples a bit packed batch of measurement samples from the circuit.\n\n            Args:\n                shots: The number of times to sample every measurement in the circuit.\n\n            Returns:\n                A numpy array with `dtype=uint8` and\n                `shape=(shots, (num_measurements + 7) // 8)`.\n\n                The bit for measurement `m` in shot `s` is at\n                `result[s, (m // 8)] & 2**(m % 8)`.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit('''\n                ...    X 0 1 2 3 4 5 6 7     10\n                ...    M 0 1 2 3 4 5 6 7 8 9 10\n                ... ''')\n                >>> s = c.compile_sampler()\n                >>> s.sample_bit_packed(shots=1)\n                array([[255,   4]], dtype=uint8)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sample_write\",\n        &CompiledMeasurementSampler::sample_write,\n        pybind11::arg(\"shots\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"filepath\"),\n        pybind11::arg(\"format\") = \"01\",\n        clean_doc_string(R\"DOC(\n            @signature def sample_write(self, shots: int, *, filepath: Union[str, pathlib.Path], format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01') -> None:\n            Samples measurements from the circuit and writes them to a file.\n\n            Examples:\n                >>> import stim\n                >>> import tempfile\n                >>> with tempfile.TemporaryDirectory() as d:\n                ...     path = f\"{d}/tmp.dat\"\n                ...     c = stim.Circuit('''\n                ...         X 0   2 3\n                ...         M 0 1 2 3\n                ...     ''')\n                ...     c.compile_sampler().sample_write(5, filepath=path, format=\"01\")\n                ...     with open(path) as f:\n                ...         print(f.read(), end='')\n                1011\n                1011\n                1011\n                1011\n                1011\n\n            Args:\n                shots: The number of times to sample every measurement in the circuit.\n                filepath: The file to write the results to.\n                format: The output format to write the results with.\n                    Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                    Defaults to \"01\".\n\n            Returns:\n                None.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__repr__\",\n        &CompiledMeasurementSampler::repr,\n        \"Returns text that is a valid python expression evaluating to an equivalent \"\n        \"`stim.CompiledMeasurementSampler`.\");\n}\n"
  },
  {
    "path": "src/stim/py/compiled_measurement_sampler.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_PY_COMPILED_MEASUREMENT_SAMPLER_PYBIND_H\n#define _STIM_PY_COMPILED_MEASUREMENT_SAMPLER_PYBIND_H\n\n#include <pybind11/numpy.h>\n#include <pybind11/pybind11.h>\n#include <pybind11/stl.h>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/mem/simd_bits.h\"\n\nnamespace stim_pybind {\n\nstruct CompiledMeasurementSampler {\n    const stim::simd_bits<stim::MAX_BITWORD_WIDTH> ref_sample;\n    const stim::Circuit circuit;\n    const bool skip_reference_sample;\n    std::mt19937_64 rng;\n    CompiledMeasurementSampler() = delete;\n    CompiledMeasurementSampler(const CompiledMeasurementSampler &) = delete;\n    CompiledMeasurementSampler(CompiledMeasurementSampler &&) = default;\n    CompiledMeasurementSampler(\n        stim::simd_bits<stim::MAX_BITWORD_WIDTH> ref_sample,\n        stim::Circuit circuit,\n        bool skip_reference_sample,\n        std::mt19937_64 &&rng);\n    pybind11::object sample_to_numpy(size_t num_shots, bool bit_packed);\n    void sample_write(size_t num_samples, std::string_view filepath, std::string_view format);\n    std::string repr() const;\n};\n\npybind11::class_<CompiledMeasurementSampler> pybind_compiled_measurement_sampler(pybind11::module &m);\nvoid pybind_compiled_measurement_sampler_methods(pybind11::module &m, pybind11::class_<CompiledMeasurementSampler> &c);\nCompiledMeasurementSampler py_init_compiled_sampler(\n    const stim::Circuit &circuit,\n    bool skip_reference_sample,\n    const pybind11::object &seed,\n    const pybind11::object &reference_sample);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/py/compiled_measurement_sampler_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport tempfile\n\nimport numpy as np\nimport pytest\nimport stim\n\n\ndef test_compiled_measurement_sampler_sample():\n    c = stim.Circuit(\"\"\"\n        X 1\n        M 0 1 2 3\n    \"\"\")\n    np.testing.assert_array_equal(\n        c.compile_sampler().sample(5),\n        np.array([\n            [0, 1, 0, 0],\n            [0, 1, 0, 0],\n            [0, 1, 0, 0],\n            [0, 1, 0, 0],\n            [0, 1, 0, 0],\n        ], dtype=np.bool_))\n    np.testing.assert_array_equal(\n        c.compile_sampler().sample(5, bit_packed=True),\n        np.array([\n            [0b00010],\n            [0b00010],\n            [0b00010],\n            [0b00010],\n            [0b00010],\n        ], dtype=np.uint8))\n    np.testing.assert_array_equal(\n        c.compile_sampler().sample_bit_packed(5),\n        np.array([\n            [0b00010],\n            [0b00010],\n            [0b00010],\n            [0b00010],\n            [0b00010],\n        ], dtype=np.uint8))\n\n\ndef test_measurements_vs_resets():\n    assert not np.any(stim.Circuit(\"\"\"\n        RX 0\n        RY 1\n        RZ 2\n        H 0\n        H_YZ 1\n        M 0 1 2\n    \"\"\").compile_sampler().sample(shots=100))\n\n    assert not np.any(stim.Circuit(\"\"\"\n        H 0\n        H_YZ 1\n        MRX 0\n        MRY 1\n        MRZ 2\n        H 0\n        H_YZ 1\n        M 0 1 2\n    \"\"\").compile_sampler().sample(shots=100))\n\n    assert not np.any(stim.Circuit(\"\"\"\n        H 0\n        H_YZ 1\n        MRX 0\n        MRY 1\n        MRZ 2\n    \"\"\").compile_sampler().sample(shots=100))\n\n\ndef test_sample_write():\n    c = stim.Circuit(\"\"\"\n        X 0 4 5\n        M 0 1 2 3 4 5 6\n    \"\"\")\n    with tempfile.TemporaryDirectory() as d:\n        path = f\"{d}/tmp.dat\"\n        c.compile_sampler().sample_write(5, filepath=path, format='b8')\n        with open(path, 'rb') as f:\n            assert f.read() == b'\\x31' * 5\n\n        c.compile_sampler().sample_write(5, filepath=path, format='01')\n        with open(path, 'r') as f:\n            assert f.readlines() == ['1000110\\n'] * 5\n\n\ndef test_skip_reference_sample():\n    np.testing.assert_array_equal(\n        stim.Circuit(\"X 0\\nM 0\").compile_sampler().sample(1),\n        [[True]],\n    )\n    np.testing.assert_array_equal(\n        stim.Circuit(\"X 0\\nM 0\").compile_sampler(skip_reference_sample=False).sample(1),\n        [[True]],\n    )\n    np.testing.assert_array_equal(\n        stim.Circuit(\"X 0\\nM 0\").compile_sampler(skip_reference_sample=True).sample(1),\n        [[False]],\n    )\n    np.testing.assert_array_equal(\n        stim.Circuit(\"X_ERROR(1) 0\\nM 0\").compile_sampler(skip_reference_sample=False).sample(1),\n        [[True]],\n    )\n    np.testing.assert_array_equal(\n        stim.Circuit(\"X_ERROR(1) 0\\nM 0\").compile_sampler(skip_reference_sample=True).sample(1),\n        [[True]],\n    )\n\ndef test_reference_sample_init():\n    np.testing.assert_array_equal(\n        stim.Circuit(\"X 0\\nM 0\").compile_sampler(reference_sample=None).sample(1),\n        [[True]],\n    )\n    circuit = stim.Circuit(\"X 0\\nM 0\")\n    ref_sample = np.array([False])\n    np.testing.assert_array_equal(\n        circuit.compile_sampler(reference_sample=ref_sample).sample(1),\n        [[False]],\n    )\n    ref_sample = circuit.reference_sample()\n    np.testing.assert_array_equal(\n        circuit.compile_sampler(reference_sample=ref_sample).sample(1),\n        [[True]],\n    )\n    circuit = stim.Circuit(\"X_ERROR(1) 0\\n M 0\")\n    ref_sample = np.array([False])\n    np.testing.assert_array_equal(\n        circuit.compile_sampler(reference_sample=ref_sample).sample(1),\n        [[True]],\n    )\n    ref_sample = circuit.reference_sample()\n    np.testing.assert_array_equal(\n        circuit.compile_sampler(reference_sample=ref_sample).sample(1),\n        [[True]],\n    )\n    with pytest.raises(ValueError):\n        circuit.compile_sampler(reference_sample=ref_sample, skip_reference_sample=True)\n    circuit = stim.Circuit(\"H 0\\n X 1\\n CNOT 0 1\\n H 0 1\\n MPP X0*X1\")\n    ref_sample = circuit.reference_sample()\n    np.testing.assert_array_equal(\n        circuit.compile_sampler(reference_sample=ref_sample, seed=0).sample(10),\n        circuit.compile_sampler(reference_sample=None, seed=0).sample(10),\n    )\n    circuit = stim.Circuit(\"H 0\\n X 1\\n CNOT 0 1\\n H 0 1 2\\n MPP Y1*Y2 X1*X2 Z1*Z2\")\n    ref_sample = circuit.reference_sample()\n    np.testing.assert_array_equal(\n        circuit.compile_sampler(reference_sample=ref_sample, seed=0).sample(11),\n        circuit.compile_sampler(seed=0).sample(11),\n    )\n\n\ndef test_repr():\n    assert repr(stim.Circuit(\"\"\"\n        X 0\n        M 0\n    \"\"\").compile_sampler()) == \"\"\"stim.CompiledMeasurementSampler(stim.Circuit('''\n    X 0\n    M 0\n'''))\"\"\"\n\n    assert repr(stim.Circuit(\"\"\"\n        X 0\n        M 0\n    \"\"\").compile_sampler(skip_reference_sample=True)) == \"\"\"stim.CompiledMeasurementSampler(stim.Circuit('''\n    X 0\n    M 0\n'''), skip_reference_sample=True)\"\"\"\n\n\ndef test_circuit_sampler_actually_fills_array():\n    circuit = stim.Circuit('''\n       X_ERROR(1) 0\n       M 0\n       DETECTOR rec[-1]\n    ''')\n    sampler = circuit.compile_detector_sampler()\n    measure_data = sampler.sample(shots=10000)\n    assert np.all(measure_data)\n"
  },
  {
    "path": "src/stim/py/march.pybind.cc",
    "content": "#include \"stim/py/march.pybind.h\"\n\n#include <pybind11/pybind11.h>\n\n#ifdef _WIN32\n//  Windows\n#include <intrin.h>\n#define cpuid(info, x) __cpuidex(info, x, 0)\n#elif (defined(__arm64__) && defined(__APPLE__)) || defined(__aarch64__) || defined(_ARCH_PPC)\n// macOS ARM64 and IBM PowerPC (dummied out)\nvoid cpuid(int info[4], int infoType) {\n    info[0] = 0;\n    info[1] = 0;\n    info[2] = 0;\n    info[3] = 0;\n}\n#else\n//  GCC Intrinsics\n#include <cpuid.h>\nvoid cpuid(int info[4], int infoType) {\n    __cpuid_count(infoType, 0, info[0], info[1], info[2], info[3]);\n}\n#endif\n\nstd::string detect_march() {\n    // From: https://en.wikipedia.org/wiki/CPUID\n    constexpr int EAX = 0;\n    constexpr int EBX = 1;\n    constexpr int EDX = 3;\n    constexpr int INFO_HIGHEST_FUNCTION_PARAMETER = 0;\n    constexpr int INFO_PROCESSOR_FEATURE_BITS = 1;\n    constexpr int INFO_EXTENDED_FEATURES = 7;\n    constexpr int avx2_bit_in_ebx = 1 << 5;\n    constexpr int sse2_bit_in_edx = 1 << 26;\n\n    int regs[4];\n    cpuid(regs, INFO_HIGHEST_FUNCTION_PARAMETER);\n    auto max_info_param = regs[EAX];\n\n    if (max_info_param >= INFO_EXTENDED_FEATURES) {\n        cpuid(regs, INFO_EXTENDED_FEATURES);\n        if (regs[EBX] & avx2_bit_in_ebx) {\n            return \"avx2\";\n        }\n    }\n\n    if (max_info_param >= INFO_PROCESSOR_FEATURE_BITS) {\n        cpuid(regs, INFO_PROCESSOR_FEATURE_BITS);\n        if (regs[EDX] & sse2_bit_in_edx) {\n            return \"sse2\";\n        }\n    }\n\n    return \"polyfill\";\n}\n\nPYBIND11_MODULE(_detect_machine_architecture, m) {\n    m.doc() = R\"pbdoc(\n        Helper code for detecting AVX/SSE instruction support for Stim.\n    )pbdoc\";\n    m.def(\"_UNSTABLE_detect_march\", &detect_march);\n}\n"
  },
  {
    "path": "src/stim/py/march.pybind.h",
    "content": "#ifndef _STIM_PY_MARCH_PYBIND_H\n#define _STIM_PY_MARCH_PYBIND_H\n\n#include <string>\n\n/// Returns a string indicating the capabilities of the CPU (the M-achine ARCH-itecture).\nstd::string detect_march();\n\n#endif\n"
  },
  {
    "path": "src/stim/py/numpy.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/py/numpy.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nstatic pybind11::object transposed_simd_bit_table_to_numpy_uint8(\n    const simd_bit_table<MAX_BITWORD_WIDTH> &table,\n    size_t num_major_in,\n    size_t num_minor_in,\n    pybind11::object out_buffer) {\n    size_t num_major_bytes_in = (num_major_in + 7) / 8;\n\n    if (out_buffer.is_none()) {\n        auto numpy = pybind11::module::import(\"numpy\");\n        out_buffer = numpy.attr(\"empty\")(pybind11::make_tuple(num_minor_in, num_major_bytes_in), numpy.attr(\"uint8\"));\n    }\n\n    if (!pybind11::isinstance<pybind11::array_t<uint8_t>>(out_buffer)) {\n        throw std::invalid_argument(\"Output buffer wasn't a numpy.ndarray[np.uint8].\");\n    }\n    auto buf = pybind11::cast<pybind11::array_t<uint8_t>>(out_buffer);\n    if (buf.ndim() != 2) {\n        throw std::invalid_argument(\"Output buffer wasn't two dimensional.\");\n    }\n    if ((size_t)buf.shape(0) != num_minor_in || (size_t)buf.shape(1) != num_major_bytes_in) {\n        std::stringstream ss;\n        ss << \"Expected output buffer to have shape=(\" << num_minor_in << \", \" << num_major_bytes_in << \")\";\n        ss << \" but its shape is (\" << buf.shape(0) << \", \" << buf.shape(1) << \").\";\n        throw std::invalid_argument(ss.str());\n    }\n\n    if (num_major_in && num_minor_in) {\n        auto stride = buf.strides(1);\n        for (size_t minor_in = 0; minor_in < num_minor_in; minor_in++) {\n            auto ptr = buf.mutable_data(minor_in, 0);\n            for (size_t major_in = 0; major_in < num_major_in; major_in += 8) {\n                uint8_t v = 0;\n                for (size_t b = 0; b < 8 && major_in + b < num_major_in; b++) {\n                    bool bit = table[major_in + b][minor_in];\n                    v |= bit << b;\n                }\n                *ptr = v;\n                ptr += stride;\n            }\n        }\n    }\n\n    return out_buffer;\n}\n\nstatic pybind11::object transposed_simd_bit_table_to_numpy_bool8(\n    const simd_bit_table<MAX_BITWORD_WIDTH> &table,\n    size_t num_major_in,\n    size_t num_minor_in,\n    pybind11::object out_buffer) {\n    if (out_buffer.is_none()) {\n        auto numpy = pybind11::module::import(\"numpy\");\n        out_buffer = numpy.attr(\"empty\")(pybind11::make_tuple(num_minor_in, num_major_in), numpy.attr(\"bool_\"));\n    }\n\n    if (!pybind11::isinstance<pybind11::array_t<bool>>(out_buffer)) {\n        throw std::invalid_argument(\"Output buffer wasn't a numpy.ndarray[np.bool_].\");\n    }\n    auto buf = pybind11::cast<pybind11::array_t<bool>>(out_buffer);\n    if (buf.ndim() != 2) {\n        throw std::invalid_argument(\"Output buffer wasn't two dimensional.\");\n    }\n    if ((size_t)buf.shape(0) != num_minor_in || (size_t)buf.shape(1) != num_major_in) {\n        std::stringstream ss;\n        ss << \"Expected output buffer to have shape=(\" << num_minor_in << \", \" << num_major_in << \")\";\n        ss << \" but its shape is (\" << buf.shape(0) << \", \" << buf.shape(1) << \").\";\n        throw std::invalid_argument(ss.str());\n    }\n\n    if (num_major_in && num_minor_in) {\n        auto stride = buf.strides(0);\n        for (size_t major = 0; major < num_major_in; major++) {\n            auto row = table[major];\n            auto ptr = buf.mutable_data(0, major);\n            for (size_t minor = 0; minor < num_minor_in; minor++) {\n                *ptr = row[minor];\n                ptr += stride;\n            }\n        }\n    }\n\n    return out_buffer;\n}\n\nstatic pybind11::object simd_bit_table_to_numpy_uint8(\n    const simd_bit_table<MAX_BITWORD_WIDTH> &table, size_t num_major, size_t num_minor, pybind11::object out_buffer) {\n    size_t num_minor_bytes = (num_minor + 7) / 8;\n    if (out_buffer.is_none()) {\n        auto numpy = pybind11::module::import(\"numpy\");\n        out_buffer = numpy.attr(\"empty\")(pybind11::make_tuple(num_major, num_minor_bytes), numpy.attr(\"uint8\"));\n    }\n\n    if (!pybind11::isinstance<pybind11::array_t<uint8_t>>(out_buffer)) {\n        throw std::invalid_argument(\"Output buffer wasn't a numpy.ndarray[np.uint8].\");\n    }\n    auto buf = pybind11::cast<pybind11::array_t<uint8_t>>(out_buffer);\n    if (buf.ndim() != 2) {\n        throw std::invalid_argument(\"Output buffer wasn't two dimensional.\");\n    }\n    if ((size_t)buf.shape(0) != num_major || (size_t)buf.shape(1) != num_minor_bytes) {\n        std::stringstream ss;\n        ss << \"Expected output buffer to have shape=(\" << num_major << \", \" << num_minor_bytes << \")\";\n        ss << \" but its shape is (\" << buf.shape(0) << \", \" << buf.shape(1) << \").\";\n        throw std::invalid_argument(ss.str());\n    }\n\n    uint8_t mask = 0b11111111;\n    if (num_minor & 7) {\n        mask = (1 << (num_minor & 7)) - 1;\n    }\n\n    if (num_major && num_minor) {\n        auto stride = buf.strides(1);\n        if (stride == 1) {\n            for (size_t major = 0; major < num_major; major++) {\n                auto row = table[major];\n                memcpy(buf.mutable_data(major, 0), row.u8, num_minor_bytes);\n                *buf.mutable_data(major, num_minor_bytes - 1) &= mask;\n            }\n        } else {\n            for (size_t major = 0; major < num_major; major++) {\n                auto row = table[major];\n                auto ptr = buf.mutable_data(major, 0);\n                for (size_t minor = 0; minor < num_minor_bytes; minor += 1) {\n                    *ptr = row.u8[minor];\n                    ptr += stride;\n                }\n                *(ptr - stride) &= mask;\n            }\n        }\n    }\n\n    return out_buffer;\n}\n\nstatic pybind11::object simd_bit_table_to_numpy_bool8(\n    const simd_bit_table<MAX_BITWORD_WIDTH> &table, size_t num_major, size_t num_minor, pybind11::object out_buffer) {\n    if (out_buffer.is_none()) {\n        auto numpy = pybind11::module::import(\"numpy\");\n        out_buffer = numpy.attr(\"empty\")(pybind11::make_tuple(num_major, num_minor), numpy.attr(\"bool_\"));\n    }\n    if (!pybind11::isinstance<pybind11::array_t<bool>>(out_buffer)) {\n        throw std::invalid_argument(\"Output buffer wasn't a numpy.ndarray[np.bool_].\");\n    }\n    auto buf = pybind11::cast<pybind11::array_t<bool>>(out_buffer);\n    if (buf.ndim() != 2) {\n        throw std::invalid_argument(\"Output buffer wasn't two dimensional.\");\n    }\n    if ((size_t)buf.shape(0) != num_major || (size_t)buf.shape(1) != num_minor) {\n        std::stringstream ss;\n        ss << \"Expected output buffer to have shape=(\" << num_major << \", \" << num_minor << \")\";\n        ss << \" but its shape is (\" << buf.shape(0) << \", \" << buf.shape(1) << \").\";\n        throw std::invalid_argument(ss.str());\n    }\n\n    if (num_major && num_minor) {\n        auto stride = buf.strides(1);\n        for (size_t major = 0; major < num_major; major++) {\n            auto row = table[major];\n            auto out_ptr = buf.mutable_data(major, 0);\n            for (size_t minor = 0; minor < num_minor; minor++) {\n                *out_ptr = row[minor];\n                out_ptr += stride;\n            }\n        }\n    }\n\n    return out_buffer;\n}\n\npybind11::object stim_pybind::simd_bit_table_to_numpy(\n    const simd_bit_table<MAX_BITWORD_WIDTH> &table,\n    size_t num_major,\n    size_t num_minor,\n    bool bit_pack_result,\n    bool transposed,\n    pybind11::object out_buffer) {\n    if (transposed) {\n        if (bit_pack_result) {\n            return transposed_simd_bit_table_to_numpy_uint8(table, num_major, num_minor, out_buffer);\n        } else {\n            return transposed_simd_bit_table_to_numpy_bool8(table, num_major, num_minor, out_buffer);\n        }\n    } else {\n        if (bit_pack_result) {\n            return simd_bit_table_to_numpy_uint8(table, num_major, num_minor, out_buffer);\n        } else {\n            return simd_bit_table_to_numpy_bool8(table, num_major, num_minor, out_buffer);\n        }\n    }\n}\n\nvoid stim_pybind::memcpy_bits_from_numpy_to_simd_bit_table(\n    size_t num_major,\n    size_t num_minor,\n    const pybind11::object &src,\n    stim::simd_bit_table<stim::MAX_BITWORD_WIDTH> &dst) {\n    if (pybind11::isinstance<pybind11::array_t<uint8_t>>(src)) {\n        auto arr = pybind11::cast<pybind11::array_t<uint8_t>>(src);\n        size_t num_minor_bytes = (num_minor + 7) / 8;\n        auto u = arr.unchecked();\n        for (size_t major = 0; major < num_major; major++) {\n            auto row = dst[major];\n            for (size_t minor_byte = 0; minor_byte < num_minor_bytes; minor_byte++) {\n                uint8_t v = u(major, minor_byte);\n                row.u8[minor_byte] = v;\n            }\n            // Clear overwrite.\n            for (size_t k = num_minor; k < num_minor_bytes * 8; k++) {\n                row[k] = false;\n            }\n        }\n    } else if (pybind11::isinstance<pybind11::array_t<bool>>(src)) {\n        auto arr = pybind11::cast<pybind11::array_t<bool>>(src);\n        auto u = arr.unchecked();\n        for (size_t major = 0; major < num_major; major++) {\n            auto row = dst[major];\n            for (size_t minor = 0; minor < num_minor; minor++) {\n                row[minor] = u(major, minor);\n            }\n        }\n    } else {\n        throw std::invalid_argument(\"Expected a 2-dimensional numpy array with dtype=np.uint8 or dtype=np.bool_\");\n    }\n}\n\nsimd_bit_table<MAX_BITWORD_WIDTH> bit_packed_numpy_uint8_array_to_transposed_simd_table(\n    const pybind11::array_t<uint8_t> &data_u8, size_t expected_bits_per_shot, size_t *num_shots_out) {\n    if (data_u8.ndim() != 2) {\n        throw std::invalid_argument(\"data must be a 2-dimensional numpy array with dtype=np.uint8 or dtype=np.bool_\");\n    }\n\n    size_t num_shots = data_u8.shape(0);\n    *num_shots_out = num_shots;\n\n    size_t expected_bytes_per_shot = (expected_bits_per_shot + 7) / 8;\n    size_t actual_bytes_per_shot = data_u8.shape(1);\n    if (actual_bytes_per_shot != expected_bytes_per_shot) {\n        std::stringstream ss;\n        ss << \"Expected \" << expected_bits_per_shot << \" bits per shot. \";\n        ss << \"Got bit packed data (dtype=np.uint8) but data.shape[1]=\";\n        ss << actual_bytes_per_shot << \" != math.ceil(\" << expected_bits_per_shot\n           << \" / 8)=\" << expected_bytes_per_shot;\n        throw std::invalid_argument(ss.str());\n    }\n\n    simd_bit_table<MAX_BITWORD_WIDTH> result(actual_bytes_per_shot * 8, num_shots);\n\n    auto u = data_u8.unchecked();\n    for (size_t a = 0; a < num_shots; a++) {\n        for (size_t b = 0; b < actual_bytes_per_shot; b++) {\n            uint8_t v = u(a, b);\n            for (size_t k = 0; k < 8; k++) {\n                result[b * 8 + k][a] |= ((v >> k) & 1) != 0;\n            }\n        }\n    }\n\n    return result;\n}\n\nsimd_bit_table<MAX_BITWORD_WIDTH> bit_packed_numpy_bool8_array_to_transposed_simd_table(\n    const pybind11::array_t<bool> &data_bool8, size_t expected_bits_per_shot, size_t *num_shots_out) {\n    size_t num_shots = data_bool8.shape(0);\n    *num_shots_out = num_shots;\n\n    if (data_bool8.ndim() != 2) {\n        throw std::invalid_argument(\"data must be a 2-dimensional numpy array with dtype=np.uint8 or dtype=np.bool_\");\n    }\n\n    size_t actual_bits_per_shot = data_bool8.shape(1);\n    if (actual_bits_per_shot != expected_bits_per_shot) {\n        std::stringstream ss;\n        ss << \"Expected \" << expected_bits_per_shot << \" bits per shot. \";\n        ss << \"Got unpacked boolean data (dtype=np.bool_) but data.shape[1]=\" << actual_bits_per_shot;\n        throw std::invalid_argument(ss.str());\n    }\n    simd_bit_table<MAX_BITWORD_WIDTH> result(actual_bits_per_shot, num_shots);\n\n    auto u = data_bool8.unchecked();\n    for (size_t a = 0; a < num_shots; a++) {\n        for (size_t b = 0; b < actual_bits_per_shot; b++) {\n            result[b][a] |= u(a, b);\n        }\n    }\n\n    return result;\n}\n\nsimd_bit_table<MAX_BITWORD_WIDTH> stim_pybind::numpy_array_to_transposed_simd_table(\n    const pybind11::object &data, size_t bits_per_shot, size_t *num_shots_out) {\n    if (pybind11::isinstance<pybind11::array_t<uint8_t>>(data)) {\n        return bit_packed_numpy_uint8_array_to_transposed_simd_table(\n            pybind11::cast<pybind11::array_t<uint8_t>>(data), bits_per_shot, num_shots_out);\n    } else if (pybind11::isinstance<pybind11::array_t<bool>>(data)) {\n        return bit_packed_numpy_bool8_array_to_transposed_simd_table(\n            pybind11::cast<pybind11::array_t<bool>>(data), bits_per_shot, num_shots_out);\n    } else {\n        throw std::invalid_argument(\"data must be a 2-dimensional numpy array with dtype=np.uint8 or dtype=np.bool_\");\n    }\n}\n\npybind11::object bits_to_numpy_bool8(simd_bits_range_ref<MAX_BITWORD_WIDTH> bits, size_t num_bits) {\n    bool *buffer = new bool[num_bits];\n    for (size_t minor = 0; minor < num_bits; minor++) {\n        buffer[minor] = bits[minor];\n    }\n\n    pybind11::capsule free_when_done(buffer, [](void *f) {\n        delete[] reinterpret_cast<bool *>(f);\n    });\n\n    return pybind11::array_t<bool>({(pybind11::ssize_t)num_bits}, {(pybind11::ssize_t)1}, buffer, free_when_done);\n}\n\npybind11::object bits_to_numpy_uint8_packed(simd_bits_range_ref<MAX_BITWORD_WIDTH> bits, size_t num_bits) {\n    size_t num_bytes = (num_bits + 7) / 8;\n    uint8_t *buffer = new uint8_t[num_bytes];\n    memcpy(buffer, bits.u8, num_bytes);\n\n    pybind11::capsule free_when_done(buffer, [](void *f) {\n        delete[] reinterpret_cast<uint8_t *>(f);\n    });\n\n    return pybind11::array_t<uint8_t>({(pybind11::ssize_t)num_bytes}, {(pybind11::ssize_t)1}, buffer, free_when_done);\n}\n\npybind11::object stim_pybind::simd_bits_to_numpy(\n    simd_bits_range_ref<MAX_BITWORD_WIDTH> bits, size_t num_bits, bool bit_packed) {\n    if (bit_packed) {\n        return bits_to_numpy_uint8_packed(bits, num_bits);\n    }\n    return bits_to_numpy_bool8(bits, num_bits);\n}\n\nvoid stim_pybind::memcpy_bits_from_numpy_to_simd(\n    size_t num_bits, const pybind11::object &src, simd_bits_range_ref<MAX_BITWORD_WIDTH> dst) {\n    if (pybind11::isinstance<pybind11::array_t<uint8_t>>(src)) {\n        auto arr = pybind11::cast<pybind11::array_t<uint8_t>>(src);\n        if (arr.ndim() == 1) {\n            size_t num_bytes = (num_bits + 7) / 8;\n            auto u = arr.unchecked();\n            for (size_t k = 0; k < num_bytes; k++) {\n                uint8_t v = u(k);\n                dst.u8[k] = v;\n            }\n\n            // Clear overwrite.\n            for (size_t k = num_bits; k < num_bytes * 8; k++) {\n                dst[k] = false;\n            }\n            return;\n        }\n    } else if (pybind11::isinstance<pybind11::array_t<bool>>(src)) {\n        auto arr = pybind11::cast<pybind11::array_t<bool>>(src);\n        if (arr.ndim() == 1) {\n            auto u = arr.unchecked();\n            for (size_t k = 0; k < num_bits; k++) {\n                dst[k] = u(k);\n            }\n            return;\n        }\n    }\n\n    throw std::invalid_argument(\"Expected a 1-dimensional numpy array with dtype=np.uint8 or dtype=np.bool_\");\n}\n"
  },
  {
    "path": "src/stim/py/numpy.pybind.h",
    "content": "#ifndef _STIM_PY_NUMPY_PYBIND_H\n#define _STIM_PY_NUMPY_PYBIND_H\n\n#include \"stim/mem/simd_bit_table.h\"\n#include \"stim/py/base.pybind.h\"\n\nnamespace stim_pybind {\n\nstim::simd_bit_table<stim::MAX_BITWORD_WIDTH> numpy_array_to_transposed_simd_table(\n    const pybind11::object &data, size_t expected_bits_per_shot, size_t *num_shots_out);\n\npybind11::object simd_bit_table_to_numpy(\n    const stim::simd_bit_table<stim::MAX_BITWORD_WIDTH> &table,\n    size_t num_major,\n    size_t num_minor,\n    bool bit_pack_result,\n    bool transposed,\n    pybind11::object out_buffer);\n\nvoid memcpy_bits_from_numpy_to_simd_bit_table(\n    size_t num_major,\n    size_t num_minor,\n    const pybind11::object &src,\n    stim::simd_bit_table<stim::MAX_BITWORD_WIDTH> &dst);\n\npybind11::object simd_bits_to_numpy(\n    stim::simd_bits_range_ref<stim::MAX_BITWORD_WIDTH> bits, size_t num_bits, bool bit_packed);\nvoid memcpy_bits_from_numpy_to_simd(\n    size_t num_bits, const pybind11::object &src, stim::simd_bits_range_ref<stim::MAX_BITWORD_WIDTH> dst);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/py/stim.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <pybind11/iostream.h>\n#include <pybind11/pybind11.h>\n\n#include \"stim/circuit/circuit.pybind.h\"\n#include \"stim/circuit/circuit_instruction.pybind.h\"\n#include \"stim/circuit/circuit_repeat_block.pybind.h\"\n#include \"stim/circuit/gate_target.pybind.h\"\n#include \"stim/cmd/command_diagram.pybind.h\"\n#include \"stim/dem/dem_instruction.pybind.h\"\n#include \"stim/dem/detector_error_model.pybind.h\"\n#include \"stim/dem/detector_error_model_repeat_block.pybind.h\"\n#include \"stim/dem/detector_error_model_target.pybind.h\"\n#include \"stim/gates/gates.pybind.h\"\n#include \"stim/io/read_write.pybind.h\"\n#include \"stim/main_namespaced.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/compiled_detector_sampler.pybind.h\"\n#include \"stim/py/compiled_measurement_sampler.pybind.h\"\n#include \"stim/py/march.pybind.h\"\n#include \"stim/simulators/dem_sampler.pybind.h\"\n#include \"stim/simulators/frame_simulator.pybind.h\"\n#include \"stim/simulators/matched_error.pybind.h\"\n#include \"stim/simulators/measurements_to_detection_events.pybind.h\"\n#include \"stim/simulators/tableau_simulator.pybind.h\"\n#include \"stim/stabilizers/clifford_string.pybind.h\"\n#include \"stim/stabilizers/flow.pybind.h\"\n#include \"stim/stabilizers/pauli_string.pybind.h\"\n#include \"stim/stabilizers/pauli_string_iter.pybind.h\"\n#include \"stim/stabilizers/tableau.h\"\n#include \"stim/stabilizers/tableau.pybind.h\"\n#include \"stim/stabilizers/tableau_iter.pybind.h\"\n\n#define xstr_literal(s) str_literal(s)\n#define str_literal(s) #s\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nGateTarget target_rec(int32_t lookback) {\n    return GateTarget::rec(lookback);\n}\n\nGateTarget target_inv(const pybind11::object &qubit) {\n    if (pybind11::isinstance<GateTarget>(qubit)) {\n        return !pybind11::cast<GateTarget>(qubit);\n    }\n    return GateTarget::qubit(pybind11::cast<uint32_t>(qubit), true);\n}\n\nGateTarget target_x(const pybind11::object &qubit, bool invert) {\n    if (pybind11::isinstance<GateTarget>(qubit)) {\n        auto t = pybind11::cast<GateTarget>(qubit);\n        if (!t.is_qubit_target()) {\n            throw std::invalid_argument(\"result of stim.target_x(\" + t.str() + \") is not defined\");\n        }\n        return GateTarget::x(t.qubit_value(), t.is_inverted_result_target() ^ invert);\n    }\n    return GateTarget::x(pybind11::cast<uint32_t>(qubit), invert);\n}\n\nGateTarget target_y(const pybind11::object &qubit, bool invert) {\n    if (pybind11::isinstance<GateTarget>(qubit)) {\n        auto t = pybind11::cast<GateTarget>(qubit);\n        if (!t.is_qubit_target()) {\n            throw std::invalid_argument(\"result of stim.target_y(\" + t.str() + \") is not defined\");\n        }\n        return GateTarget::y(t.qubit_value(), t.is_inverted_result_target() ^ invert);\n    }\n    return GateTarget::y(pybind11::cast<uint32_t>(qubit), invert);\n}\n\nGateTarget target_z(const pybind11::object &qubit, bool invert) {\n    if (pybind11::isinstance<GateTarget>(qubit)) {\n        auto t = pybind11::cast<GateTarget>(qubit);\n        if (!t.is_qubit_target()) {\n            throw std::invalid_argument(\"result of stim.target_z(\" + t.str() + \") is not defined\");\n        }\n        return GateTarget::z(t.qubit_value(), t.is_inverted_result_target() ^ invert);\n    }\n    return GateTarget::z(pybind11::cast<uint32_t>(qubit), invert);\n}\n\nstd::vector<GateTarget> target_combined_paulis(const pybind11::object &paulis, bool invert) {\n    std::vector<GateTarget> result;\n    if (pybind11::isinstance<FlexPauliString>(paulis)) {\n        const FlexPauliString &ps = pybind11::cast<const FlexPauliString &>(paulis);\n        if (ps.imag) {\n            std::stringstream ss;\n            ss << \"Imaginary sign: paulis=\";\n            ss << paulis;\n            throw std::invalid_argument(ss.str());\n        }\n        invert ^= ps.value.sign;\n        for (size_t q = 0; q < ps.value.num_qubits; q++) {\n            bool x = ps.value.xs[q];\n            bool z = ps.value.zs[q];\n            if (x | z) {\n                result.push_back(GateTarget::pauli_xz(q, x, z));\n                result.push_back(GateTarget::combiner());\n            }\n        }\n    } else {\n        for (const auto &h : paulis) {\n            if (pybind11::isinstance<GateTarget>(h)) {\n                GateTarget g = pybind11::cast<GateTarget>(h);\n                if (g.pauli_type() != 'I') {\n                    if (g.is_inverted_result_target()) {\n                        invert ^= true;\n                        g.data ^= TARGET_INVERTED_BIT;\n                    }\n                    result.push_back(g);\n                    result.push_back(GateTarget::combiner());\n                    continue;\n                }\n            }\n\n            std::stringstream ss;\n            ss << \"Expected a pauli string or iterable of stim.GateTarget but got this when iterating: \";\n            ss << h;\n            throw std::invalid_argument(ss.str());\n        }\n    }\n\n    if (result.empty()) {\n        std::stringstream ss;\n        ss << \"Identity pauli product: paulis=\";\n        ss << paulis;\n        throw std::invalid_argument(ss.str());\n    }\n    result.pop_back();\n    if (invert) {\n        result[0].data ^= TARGET_INVERTED_BIT;\n    }\n    return result;\n}\n\nGateTarget target_pauli(uint32_t qubit_index, const pybind11::object &pauli, bool invert) {\n    if ((qubit_index & TARGET_VALUE_MASK) != qubit_index) {\n        std::stringstream ss;\n        ss << \"qubit_index=\" << qubit_index << \" is too large. Maximum qubit index is \" << TARGET_VALUE_MASK << \".\";\n        throw std::invalid_argument(ss.str());\n    }\n    if (pybind11::isinstance<pybind11::str>(pauli)) {\n        std::string_view p = pybind11::cast<std::string_view>(pauli);\n        if (p == \"X\" || p == \"x\") {\n            return GateTarget::x(qubit_index, invert);\n        } else if (p == \"Y\" || p == \"y\") {\n            return GateTarget::y(qubit_index, invert);\n        } else if (p == \"Z\" || p == \"z\") {\n            return GateTarget::z(qubit_index, invert);\n        } else if (p == \"I\") {\n            return GateTarget::qubit(qubit_index, invert);\n        }\n    } else {\n        try {\n            uint8_t p = pybind11::cast<uint8_t>(pauli);\n            if (p == 1) {\n                return GateTarget::x(qubit_index, invert);\n            } else if (p == 2) {\n                return GateTarget::y(qubit_index, invert);\n            } else if (p == 3) {\n                return GateTarget::z(qubit_index, invert);\n            } else if (p == 0) {\n                return GateTarget::qubit(qubit_index, invert);\n            }\n        } catch (const pybind11::cast_error &ex) {\n            // Wasn't an integer.\n        }\n    }\n\n    std::stringstream ss;\n    ss << \"Expected pauli in [0, 1, 2, 3, *'IXYZxyz'] but got pauli=\" << pauli;\n    throw std::invalid_argument(ss.str());\n}\n\nGateTarget target_sweep_bit(uint32_t qubit) {\n    return GateTarget::sweep_bit(qubit);\n}\n\nint stim_main(const std::vector<std::string> &args) {\n    pybind11::scoped_ostream_redirect redirect_out(std::cout, pybind11::module_::import(\"sys\").attr(\"stdout\"));\n    pybind11::scoped_ostream_redirect redirect_err(std::cerr, pybind11::module_::import(\"sys\").attr(\"stderr\"));\n    std::vector<const char *> argv;\n    argv.push_back(\"stim.main\");\n    for (const auto &arg : args) {\n        argv.push_back(arg.c_str());\n    }\n    return stim::main(argv.size(), argv.data());\n}\n\npybind11::object raw_format_data_solo(const FileFormatData &data) {\n    pybind11::dict result;\n    result[\"name\"] = data.name;\n    result[\"parse_example\"] = data.help_python_parse;\n    result[\"save_example\"] = data.help_python_save;\n    result[\"help\"] = data.help;\n    return std::move(result);\n}\n\npybind11::dict raw_format_data() {\n    pybind11::dict result;\n    for (const auto &kv : format_name_to_enum_map()) {\n        result[pybind11::str(kv.first)] = raw_format_data_solo(kv.second);\n    }\n    return result;\n}\n\nvoid top_level(pybind11::module &m) {\n    m.def(\n        \"target_rec\",\n        &target_rec,\n        pybind11::arg(\"lookback_index\"),\n        clean_doc_string(R\"DOC(\n            Returns a measurement record target with the given lookback.\n\n            Measurement record targets are used to refer back to the measurement record;\n            the list of measurements that have been performed so far. Measurement record\n            targets always specify an index relative to the *end* of the measurement record.\n            The latest measurement is `stim.target_rec(-1)`, the next most recent\n            measurement is `stim.target_rec(-2)`, and so forth. Indexing is done this way\n            in order to make it possible to write loops.\n\n            Args:\n                lookback_index: A negative integer indicating how far to look back, relative\n                    to the end of the measurement record.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit()\n                >>> circuit.append(\"M\", [5, 7, 11])\n                >>> circuit.append(\"CX\", [stim.target_rec(-2), 3])\n                >>> circuit\n                stim.Circuit('''\n                    M 5 7 11\n                    CX rec[-2] 3\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_inv\",\n        &target_inv,\n        pybind11::arg(\"qubit_index\"),\n        clean_doc_string(R\"DOC(\n            @signature def target_inv(qubit_index: Union[int, stim.GateTarget]) -> stim.GateTarget:\n            Returns a target flagged as inverted.\n\n            Inverted targets are used to indicate measurement results should be flipped.\n\n            Args:\n                qubit_index: The underlying qubit index of the inverted target.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit()\n                >>> circuit.append(\"M\", [2, stim.target_inv(3)])\n                >>> circuit\n                stim.Circuit('''\n                    M 2 !3\n                ''')\n\n            For example, the '!1' in 'M 0 !1 2' is qubit 1 flagged as inverted,\n            meaning the measurement result from qubit 1 should be inverted when reported.\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_combiner\",\n        &GateTarget::combiner,\n        clean_doc_string(R\"DOC(\n            Returns a target combiner that can be used to build Pauli products.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit()\n                >>> circuit.append(\"MPP\", [\n                ...     stim.target_x(2),\n                ...     stim.target_combiner(),\n                ...     stim.target_y(3),\n                ...     stim.target_combiner(),\n                ...     stim.target_z(5),\n                ... ])\n                >>> circuit\n                stim.Circuit('''\n                    MPP X2*Y3*Z5\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_x\",\n        &target_x,\n        pybind11::arg(\"qubit_index\"),\n        pybind11::arg(\"invert\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def target_x(qubit_index: Union[int, stim.GateTarget], invert: bool = False) -> stim.GateTarget:\n            Returns a Pauli X target that can be passed into `stim.Circuit.append`.\n\n            Args:\n                qubit_index: The qubit that the Pauli applies to.\n                invert: Defaults to False. If True, the target is inverted (indicating\n                    that, for example, measurement results should be inverted).\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit()\n                >>> circuit.append(\"MPP\", [\n                ...     stim.target_x(2),\n                ...     stim.target_combiner(),\n                ...     stim.target_y(3, invert=True),\n                ...     stim.target_combiner(),\n                ...     stim.target_z(5),\n                ... ])\n                >>> circuit\n                stim.Circuit('''\n                    MPP X2*!Y3*Z5\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_y\",\n        &target_y,\n        pybind11::arg(\"qubit_index\"),\n        pybind11::arg(\"invert\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def target_y(qubit_index: Union[int, stim.GateTarget], invert: bool = False) -> stim.GateTarget:\n            Returns a Pauli Y target that can be passed into `stim.Circuit.append`.\n\n            Args:\n                qubit_index: The qubit that the Pauli applies to.\n                invert: Defaults to False. If True, the target is inverted (indicating\n                    that, for example, measurement results should be inverted).\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit()\n                >>> circuit.append(\"MPP\", [\n                ...     stim.target_x(2),\n                ...     stim.target_combiner(),\n                ...     stim.target_y(3, invert=True),\n                ...     stim.target_combiner(),\n                ...     stim.target_z(5),\n                ... ])\n                >>> circuit\n                stim.Circuit('''\n                    MPP X2*!Y3*Z5\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_z\",\n        &target_z,\n        pybind11::arg(\"qubit_index\"),\n        pybind11::arg(\"invert\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def target_z(qubit_index: Union[int, stim.GateTarget], invert: bool = False) -> stim.GateTarget:\n            Returns a Pauli Z target that can be passed into `stim.Circuit.append`.\n\n            Args:\n                qubit_index: The qubit that the Pauli applies to.\n                invert: Defaults to False. If True, the target is inverted (indicating\n                    that, for example, measurement results should be inverted).\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit()\n                >>> circuit.append(\"MPP\", [\n                ...     stim.target_x(2),\n                ...     stim.target_combiner(),\n                ...     stim.target_y(3, invert=True),\n                ...     stim.target_combiner(),\n                ...     stim.target_z(5),\n                ... ])\n                >>> circuit\n                stim.Circuit('''\n                    MPP X2*!Y3*Z5\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_pauli\",\n        &target_pauli,\n        pybind11::arg(\"qubit_index\"),\n        pybind11::arg(\"pauli\"),\n        pybind11::arg(\"invert\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def target_pauli(qubit_index: int, pauli: Union[str, int], invert: bool = False) -> stim.GateTarget:\n            Returns a pauli target that can be passed into `stim.Circuit.append`.\n\n            Args:\n                qubit_index: The qubit that the Pauli applies to.\n                pauli: The pauli gate to use. This can either be a string identifying the\n                    pauli by name (\"x\", \"X\", \"y\", \"Y\", \"z\", or \"Z\") or an integer following\n                    the convention (1=X, 2=Y, 3=Z). Setting this argument to \"I\" or to\n                    0 will return a qubit target instead of a pauli target.\n                invert: Defaults to False. If True, the target is inverted (like \"!X10\"),\n                    indicating that, for example, measurement results should be inverted).\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit()\n                >>> circuit.append(\"MPP\", [\n                ...     stim.target_pauli(2, \"X\"),\n                ...     stim.target_combiner(),\n                ...     stim.target_pauli(3, \"y\", invert=True),\n                ...     stim.target_pauli(5, 3),\n                ... ])\n                >>> circuit\n                stim.Circuit('''\n                    MPP X2*!Y3 Z5\n                ''')\n\n                >>> circuit.append(\"M\", [\n                ...     stim.target_pauli(7, \"I\"),\n                ... ])\n                >>> circuit\n                stim.Circuit('''\n                    MPP X2*!Y3 Z5\n                    M 7\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_combined_paulis\",\n        &target_combined_paulis,\n        pybind11::arg(\"paulis\"),\n        pybind11::arg(\"invert\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def target_combined_paulis(paulis: Union[stim.PauliString, List[stim.GateTarget]], invert: bool = False) -> stim.GateTarget:\n            Returns a list of targets encoding a pauli product for instructions like MPP.\n\n            Args:\n                paulis: The paulis to encode into the targets. This can be a\n                    `stim.PauliString` or a list of pauli targets from `stim.target_x`,\n                    `stim.target_pauli`, etc.\n                invert: Defaults to False. If True, the product is inverted (like \"!X2*Y3\").\n                    Note that this is in addition to any inversions specified by the\n                    `paulis` argument.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit()\n                >>> circuit.append(\"MPP\", [\n                ...     *stim.target_combined_paulis(stim.PauliString(\"-XYZ\")),\n                ...     *stim.target_combined_paulis([stim.target_x(2), stim.target_y(5)]),\n                ...     *stim.target_combined_paulis([stim.target_z(9)], invert=True),\n                ... ])\n                >>> circuit\n                stim.Circuit('''\n                    MPP !X0*Y1*Z2 X2*Y5 !Z9\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"target_sweep_bit\",\n        &target_sweep_bit,\n        pybind11::arg(\"sweep_bit_index\"),\n        clean_doc_string(R\"DOC(\n            Returns a sweep bit target that can be passed into `stim.Circuit.append`.\n\n            Args:\n                sweep_bit_index: The index of the sweep bit to target.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit()\n                >>> circuit.append(\"CX\", [stim.target_sweep_bit(2), 5])\n                >>> circuit\n                stim.Circuit('''\n                    CX sweep[2] 5\n                ''')\n        )DOC\")\n            .data());\n\n    m.def(\n        \"main\",\n        &stim_main,\n        pybind11::kw_only(),\n        pybind11::arg(\"command_line_args\"),\n        clean_doc_string(R\"DOC(\n            Runs the command line tool version of stim on the given arguments.\n\n            Note that by default any input will be read from stdin, any output\n            will print to stdout (as opposed to being intercepted). For most\n            commands, you can use arguments like `--out` to write to a file\n            instead of stdout and `--in` to read from a file instead of stdin.\n\n            Returns:\n                An exit code (0 means success, not zero means failure).\n\n            Raises:\n                A large variety of errors, depending on what you are doing and\n                how it failed! Beware that many errors are caught by the main\n                method itself and printed to stderr, with the only indication\n                that something went wrong being the return code.\n\n            Example:\n                >>> import stim\n                >>> import tempfile\n                >>> with tempfile.TemporaryDirectory() as d:\n                ...     path = f'{d}/tmp.out'\n                ...     return_code = stim.main(command_line_args=[\n                ...         \"gen\",\n                ...         \"--code=repetition_code\",\n                ...         \"--task=memory\",\n                ...         \"--rounds=1000\",\n                ...         \"--distance=2\",\n                ...         \"--out\",\n                ...         path,\n                ...     ])\n                ...     assert return_code == 0\n                ...     with open(path) as f:\n                ...         print(f.read(), end='')\n                # Generated repetition_code circuit.\n                # task: memory\n                # rounds: 1000\n                # distance: 2\n                # before_round_data_depolarization: 0\n                # before_measure_flip_probability: 0\n                # after_reset_flip_probability: 0\n                # after_clifford_depolarization: 0\n                # layout:\n                # L0 Z1 d2\n                # Legend:\n                #     d# = data qubit\n                #     L# = data qubit with logical observable crossing\n                #     Z# = measurement qubit\n                R 0 1 2\n                TICK\n                CX 0 1\n                TICK\n                CX 2 1\n                TICK\n                MR 1\n                DETECTOR(1, 0) rec[-1]\n                REPEAT 999 {\n                    TICK\n                    CX 0 1\n                    TICK\n                    CX 2 1\n                    TICK\n                    MR 1\n                    SHIFT_COORDS(0, 1)\n                    DETECTOR(1, 0) rec[-1] rec[-2]\n                }\n                M 0 2\n                DETECTOR(1, 1) rec[-1] rec[-2] rec[-3]\n                OBSERVABLE_INCLUDE(0) rec[-1]\n        )DOC\")\n            .data());\n\n    m.def(\"_UNSTABLE_raw_format_data\", &raw_format_data);\n}\n\nPYBIND11_MODULE(STIM_PYBIND11_MODULE_NAME, m) {\n    m.attr(\"__version__\") = xstr_literal(VERSION_INFO);\n    m.doc() = R\"pbdoc(\n        Stim: A fast stabilizer circuit library.\n    )pbdoc\";\n\n    /// class registration happens before function/method\n    /// registration. If a class references another before it is\n    /// registered, method signatures can get messed up.  For example,\n    /// if DetectorErrorModel is defined after Circuit then\n    /// Circuit.detector_error_model's return type is described as\n    /// `stim::DetectorErrorModel` instead of `stim.DetectorErrorModel`.\n\n    /// class definitions\n    auto c_dem_sampler = pybind_dem_sampler(m);\n    auto c_compiled_detector_sampler = pybind_compiled_detector_sampler(m);\n    auto c_compiled_measurement_sampler = pybind_compiled_measurement_sampler(m);\n    auto c_compiled_m2d_converter = pybind_compiled_measurements_to_detection_events_converter(m);\n    auto c_clifford_string = pybind_clifford_string(m);\n    auto c_pauli_string = pybind_pauli_string(m);\n    auto c_pauli_string_iter = pybind_pauli_string_iter(m);\n    auto c_tableau = pybind_tableau(m);\n    auto c_tableau_iter = pybind_tableau_iter(m);\n\n    auto c_circuit_gate_target = pybind_circuit_gate_target(m);\n    auto c_gate_data = pybind_gate_data(m);\n    auto c_circuit_instruction = pybind_circuit_instruction(m);\n    auto c_circuit_repeat_block = pybind_circuit_repeat_block(m);\n    auto c_circuit = pybind_circuit(m);\n\n    auto c_detector_error_model_instruction = pybind_detector_error_model_instruction(m);\n    auto c_detector_error_model_target = pybind_detector_error_model_target(m);\n    auto c_detector_error_model_repeat_block = pybind_detector_error_model_repeat_block(m);\n    auto c_detector_error_model = pybind_detector_error_model(m);\n\n    auto c_tableau_simulator = pybind_tableau_simulator(m);\n    auto c_frame_simulator = pybind_frame_simulator(m);\n\n    auto c_circuit_error_location_stack_frame = pybind_circuit_error_location_stack_frame(m);\n    auto c_gate_target_with_coords = pybind_gate_target_with_coords(m);\n    auto c_dem_target_with_coords = pybind_dem_target_with_coords(m);\n    auto c_flipped_measurement = pybind_flipped_measurement(m);\n    auto c_circuit_targets_inside_instruction = pybind_circuit_targets_inside_instruction(m);\n    auto c_circuit_error_location = pybind_circuit_error_location(m);\n    auto c_circuit_error_location_methods = pybind_explained_error(m);\n    auto c_flow = pybind_flow(m);\n\n    auto c_diagram_helper = pybind_diagram(m);\n\n    /// top level function definitions\n    top_level(m);\n    pybind_read_write(m);\n\n    // method definitions\n    pybind_circuit_instruction_methods(m, c_circuit_instruction);\n    pybind_circuit_gate_target_methods(m, c_circuit_gate_target);\n    pybind_gate_data_methods(m, c_gate_data);\n    pybind_circuit_repeat_block_methods(m, c_circuit_repeat_block);\n    pybind_circuit_methods(m, c_circuit);\n    pybind_circuit_methods_extra(m, c_circuit);\n\n    pybind_tableau_iter_methods(m, c_tableau_iter);\n    pybind_dem_sampler_methods(m, c_dem_sampler);\n\n    pybind_detector_error_model_instruction_methods(m, c_detector_error_model_instruction);\n    pybind_detector_error_model_repeat_block_methods(m, c_detector_error_model_repeat_block);\n    pybind_detector_error_model_target_methods(m, c_detector_error_model_target);\n    pybind_detector_error_model_methods(m, c_detector_error_model);\n\n    pybind_tableau_methods(m, c_tableau);\n    pybind_pauli_string_methods(m, c_pauli_string);\n    pybind_clifford_string_methods(m, c_clifford_string);\n    pybind_pauli_string_iter_methods(m, c_pauli_string_iter);\n\n    pybind_compiled_detector_sampler_methods(m, c_compiled_detector_sampler);\n    pybind_compiled_measurement_sampler_methods(m, c_compiled_measurement_sampler);\n    pybind_compiled_measurements_to_detection_events_converter_methods(m, c_compiled_m2d_converter);\n\n    pybind_tableau_simulator_methods(m, c_tableau_simulator);\n    pybind_frame_simulator_methods(m, c_frame_simulator);\n\n    pybind_circuit_error_location_stack_frame_methods(m, c_circuit_error_location_stack_frame);\n    pybind_gate_target_with_coords_methods(m, c_gate_target_with_coords);\n    pybind_dem_target_with_coords_methods(m, c_dem_target_with_coords);\n    pybind_flipped_measurement_methods(m, c_flipped_measurement);\n    pybind_circuit_targets_inside_instruction_methods(m, c_circuit_targets_inside_instruction);\n    pybind_circuit_error_location_methods(m, c_circuit_error_location);\n    pybind_explained_error_methods(m, c_circuit_error_location_methods);\n    pybind_flow_methods(m, c_flow);\n\n    pybind_diagram_methods(m, c_diagram_helper);\n}\n"
  },
  {
    "path": "src/stim/py/stim_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport pathlib\n\nimport tempfile\n\nimport doctest\n\nimport numpy as np\nimport pytest\nimport types\n\nimport stim\nimport re\n\ndef test_version():\n    assert re.match(r\"^\\d\\.\\d+\", stim.__version__)\n\n\ndef test_targets():\n    t = stim.target_x(5)\n    assert isinstance(t, stim.GateTarget)\n    assert t.is_x_target and t.value == 5\n    assert not t.is_y_target\n\n    t = stim.target_y(6)\n    assert isinstance(t, stim.GateTarget)\n    assert t.is_y_target and t.value == 6\n\n    t = stim.target_z(5)\n    assert isinstance(t, stim.GateTarget)\n    assert t.is_z_target and t.value == 5\n\n    t = stim.target_inv(5)\n    assert isinstance(t, stim.GateTarget)\n    assert t.is_inverted_result_target and t.value == 5\n\n    t = stim.target_rec(-5)\n    assert isinstance(t, stim.GateTarget)\n    assert t.is_measurement_record_target and not t.is_inverted_result_target and t.value == -5\n\n    t = stim.target_sweep_bit(4)\n    assert isinstance(t, stim.GateTarget)\n    assert t.is_sweep_bit_target and not t.is_inverted_result_target and t.value == 4\n\n    t = stim.target_combiner()\n    assert isinstance(t, stim.GateTarget)\n\n\ndef test_gate_data():\n    data = stim.gate_data()\n    assert len(data) == 81\n    assert data[\"CX\"].name == \"CX\"\n    assert data[\"CX\"].aliases == [\"CNOT\", \"CX\", \"ZCX\"]\n    assert data[\"X\"].is_unitary\n    assert \"CNOT\" not in data\n\n\ndef test_format_data():\n    format_data = stim._UNSTABLE_raw_format_data()\n    assert len(format_data) >= 6\n\n    # Check that example code has needed imports.\n    for k, v in format_data.items():\n        exec(v[\"parse_example\"], {}, {})\n        exec(v[\"save_example\"], {}, {})\n\n    # Collect sample methods.\n    ctx = {}\n    for k, v in format_data.items():\n        exec(v[\"parse_example\"], {}, ctx)\n        exec(v[\"save_example\"], {}, ctx)\n\n    # Manually test example save/parse methods.\n    data = [[0, 1, 1, 0], [0, 0, 0, 0]]\n    saved = \"0110\\n0000\\n\"\n    assert ctx[\"save_01\"](data) == saved\n    assert ctx[\"parse_01\"](saved) == data\n\n    saved = b\"\\x01\\x00\\x01\\x04\"\n    assert ctx[\"save_r8\"](data) == saved\n    assert ctx[\"parse_r8\"](saved, bits_per_shot=4) == data\n\n    saved = b\"\\x06\\x00\"\n    assert ctx[\"save_b8\"](data) == saved\n    assert ctx[\"parse_b8\"](saved, bits_per_shot=4) == data\n\n    saved = \"1,2\\n\\n\"\n    assert ctx[\"save_hits\"](data) == saved\n    assert ctx[\"parse_hits\"](saved, bits_per_shot=4) == data\n\n    saved = \"shot D1 L0\\nshot\\n\"\n    assert ctx[\"save_dets\"](data, num_detectors=2, num_observables=2) == saved\n    assert ctx[\"parse_dets\"](saved, num_detectors=2, num_observables=2) == data\n\n    big_data = [data[0]] + [data[1]] * 36 + [[1, 0, 1, 0]] * 4 + [data[1]] * (64 - 41)\n    saved = (b\"\\x00\\x00\\x00\\x00\\xe0\\x01\\x00\\x00\"\n             b\"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n             b\"\\x01\\x00\\x00\\x00\\xe0\\x01\\x00\\x00\"\n             b\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\")\n    assert ctx[\"save_ptb64\"](big_data) == saved\n    assert ctx[\"parse_ptb64\"](saved, bits_per_shot=4) == big_data\n\n    # Check that python examples in help strings are correct.\n    for k, v in format_data.items():\n        mod = types.ModuleType('stim_test_fake')\n        mod.f = lambda: 5\n        mod.__test__ = {\"f\": mod.f}\n        mod.f.__doc__ = v[\"help\"]\n        assert doctest.testmod(mod).failed == 0, k\n\n\ndef test_main_write_to_file():\n    with tempfile.TemporaryDirectory() as d:\n        p = pathlib.Path(d) / 'tmp'\n        assert stim.main(command_line_args=[\n            \"gen\",\n            \"--code=repetition_code\",\n            \"--task=memory\",\n            \"--rounds=1000\",\n            \"--distance=2\",\n            f\"--out={p}\"\n        ]) == 0\n        with open(p) as f:\n            assert \"Generated repetition_code\" in f.read()\n\n\ndef test_main_help(capsys):\n    assert stim.main(command_line_args=[\"help\"]) == 0\n    captured = capsys.readouterr()\n    assert captured.err == \"\"\n    assert 'Available stim commands' in captured.out\n\n\ndef test_main_redirects_stdout(capsys):\n    assert stim.main(command_line_args=[\n        \"gen\",\n        \"--code=repetition_code\",\n        \"--task=memory\",\n        \"--rounds=1000\",\n        \"--distance=2\",\n    ]) == 0\n    captured = capsys.readouterr()\n    assert \"Generated repetition_code\" in captured.out\n    assert captured.err == \"\"\n\n\ndef test_main_redirects_stderr(capsys):\n    assert stim.main(command_line_args=[\n        \"gen\",\n        \"--code=XXXXX\",\n        \"--task=memory\",\n        \"--rounds=1000\",\n        \"--distance=2\",\n    ]) == 1\n    captured = capsys.readouterr()\n    assert captured.out == \"\"\n    assert \"Unrecognized value 'XXXXX'\" in captured.err\n\n\ndef test_target_methods_accept_gate_targets():\n    assert stim.target_inv(stim.GateTarget(5)) == stim.target_inv(5)\n    assert stim.target_inv(stim.target_inv(5)) == stim.GateTarget(5)\n    assert stim.target_inv(stim.target_x(5)) == stim.target_x(5, invert=True)\n    assert stim.target_inv(stim.target_y(5)) == stim.target_y(5, invert=True)\n    assert stim.target_inv(stim.target_z(5)) == stim.target_z(5, invert=True)\n\n    assert stim.target_x(stim.GateTarget(5)) == stim.target_x(5)\n    assert stim.target_x(stim.target_inv(stim.GateTarget(5))) == stim.target_x(5, invert=True)\n    assert stim.target_x(stim.GateTarget(5), invert=True) == stim.target_x(5, invert=True)\n    assert stim.target_x(stim.target_inv(stim.GateTarget(5)), invert=True) == stim.target_x(5)\n\n    assert stim.target_y(stim.GateTarget(5)) == stim.target_y(5)\n    assert stim.target_y(stim.target_inv(stim.GateTarget(5))) == stim.target_y(5, invert=True)\n    assert stim.target_y(stim.GateTarget(5), invert=True) == stim.target_y(5, invert=True)\n    assert stim.target_y(stim.target_inv(stim.GateTarget(5)), invert=True) == stim.target_y(5)\n\n    assert stim.target_z(stim.GateTarget(5)) == stim.target_z(5)\n    assert stim.target_z(stim.target_inv(stim.GateTarget(5))) == stim.target_z(5, invert=True)\n    assert stim.target_z(stim.GateTarget(5), invert=True) == stim.target_z(5, invert=True)\n    assert stim.target_z(stim.target_inv(stim.GateTarget(5)), invert=True) == stim.target_z(5)\n\n    with pytest.raises(ValueError):\n        stim.target_inv(stim.target_sweep_bit(4))\n\n    with pytest.raises(ValueError):\n        stim.target_inv(stim.target_rec(-4))\n\n    with pytest.raises(ValueError):\n        stim.target_x(stim.target_sweep_bit(4))\n\n    with pytest.raises(ValueError):\n        stim.target_y(stim.target_sweep_bit(4))\n\n    with pytest.raises(ValueError):\n        stim.target_z(stim.target_sweep_bit(4))\n\n\ndef test_target_pauli():\n    assert stim.target_pauli(2, \"I\") == stim.GateTarget(2)\n    assert stim.target_pauli(2, \"X\") == stim.target_x(2)\n    assert stim.target_pauli(2, \"Y\") == stim.target_y(2)\n    assert stim.target_pauli(2, \"Z\") == stim.target_z(2)\n    assert stim.target_pauli(5, \"x\") == stim.target_x(5)\n    assert stim.target_pauli(2, \"y\") == stim.target_y(2)\n    assert stim.target_pauli(2, \"z\") == stim.target_z(2)\n    assert stim.target_pauli(2, 0) == stim.GateTarget(2)\n    assert stim.target_pauli(2, 1) == stim.target_x(2)\n    assert stim.target_pauli(2, 2) == stim.target_y(2)\n    assert stim.target_pauli(2, 3) == stim.target_z(2)\n    assert stim.target_pauli(2, 3, True) == stim.target_z(2, True)\n    assert stim.target_pauli(qubit_index=2, pauli=3, invert=True) == stim.target_z(2, True)\n    assert stim.target_pauli(5, np.array([2], dtype=np.uint8)[0]) == stim.target_y(5)\n    assert stim.target_pauli(5, np.array([2], dtype=np.uint32)[0]) == stim.target_y(5)\n    assert stim.target_pauli(5, np.array([2], dtype=np.int16)[0]) == stim.target_y(5)\n\n    with pytest.raises(ValueError, match=\"too large\"):\n        stim.target_pauli(2**31, 'X')\n    with pytest.raises(ValueError, match=\"Expected pauli\"):\n        stim.target_pauli(5, 'F')\n    with pytest.raises(ValueError, match=\"Expected pauli\"):\n        stim.target_pauli(5, np.array([257], dtype=np.uint32)[0])\n\n\ndef test_target_combined_paulis():\n    assert stim.target_combined_paulis(stim.PauliString(\"XYZ\")) == [\n        stim.target_x(0),\n        stim.target_combiner(),\n        stim.target_y(1),\n        stim.target_combiner(),\n        stim.target_z(2),\n    ]\n\n    assert stim.target_combined_paulis(stim.PauliString(\"X\"), True) == [\n        stim.target_x(0, True),\n    ]\n\n    assert stim.target_combined_paulis(stim.PauliString(\"-XYIZ\")) == [\n        stim.target_x(0, invert=True),\n        stim.target_combiner(),\n        stim.target_y(1),\n        stim.target_combiner(),\n        stim.target_z(3),\n    ]\n\n    assert stim.target_combined_paulis(stim.PauliString(\"-XYIZ\"), True) == [\n        stim.target_x(0),\n        stim.target_combiner(),\n        stim.target_y(1),\n        stim.target_combiner(),\n        stim.target_z(3),\n    ]\n\n    assert stim.target_combined_paulis([stim.target_x(5), stim.target_z(9)]) == [\n        stim.target_x(5),\n        stim.target_combiner(),\n        stim.target_z(9),\n    ]\n\n    assert stim.target_combined_paulis([stim.target_x(5, True), stim.target_z(9)]) == [\n        stim.target_x(5, True),\n        stim.target_combiner(),\n        stim.target_z(9),\n    ]\n    assert stim.target_combined_paulis([stim.target_x(5), stim.target_z(9, True)]) == [\n        stim.target_x(5, True),\n        stim.target_combiner(),\n        stim.target_z(9),\n    ]\n    assert stim.target_combined_paulis([stim.target_x(5), stim.target_z(9)], True) == [\n        stim.target_x(5, True),\n        stim.target_combiner(),\n        stim.target_z(9),\n    ]\n    assert stim.target_combined_paulis([stim.target_y(4)]) == [\n        stim.target_y(4),\n    ]\n\n    with pytest.raises(ValueError, match=\"Expected a pauli string\"):\n        stim.target_combined_paulis([stim.target_rec(-2)])\n    with pytest.raises(ValueError, match=\"Expected a pauli string\"):\n        stim.target_combined_paulis([object()])\n    with pytest.raises(ValueError, match=\"Identity pauli product\"):\n        stim.target_combined_paulis([])\n    with pytest.raises(ValueError, match=\"Identity pauli product\"):\n        stim.target_combined_paulis(stim.PauliString(0))\n    with pytest.raises(ValueError, match=\"Identity pauli product\"):\n        stim.target_combined_paulis(stim.PauliString(10))\n    with pytest.raises(ValueError, match=\"Imaginary\"):\n        stim.target_combined_paulis(stim.PauliString(\"iX\"))\n"
  },
  {
    "path": "src/stim/search/graphlike/algo.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/algo.h\"\n\n#include <algorithm>\n#include <unordered_map>\n#include <queue>\n#include <sstream>\n\n#include \"stim/search/graphlike/edge.h\"\n#include \"stim/search/graphlike/graph.h\"\n#include \"stim/search/graphlike/node.h\"\n#include \"stim/search/graphlike/search_state.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nDetectorErrorModel backtrack_path(const std::unordered_map<SearchState, SearchState, SearchStateHash> &back_map, const SearchState &final_state) {\n    DetectorErrorModel out;\n    auto cur_state = final_state;\n    while (true) {\n        const auto &prev_state = back_map.at(cur_state);\n        cur_state.append_transition_as_error_instruction_to(prev_state, out);\n        if (prev_state.is_undetected()) {\n            break;\n        }\n        cur_state = prev_state;\n    }\n    std::sort(out.instructions.begin(), out.instructions.end());\n    return out;\n}\n\nDetectorErrorModel stim::shortest_graphlike_undetectable_logical_error(\n    const DetectorErrorModel &model, bool ignore_ungraphlike_errors) {\n    Graph graph = Graph::from_dem(model, ignore_ungraphlike_errors);\n\n    SearchState empty_search_state(graph.num_observables);\n    if (graph.distance_1_error_mask.not_zero()) {\n        DetectorErrorModel out;\n        SearchState s1(NO_NODE_INDEX, NO_NODE_INDEX, graph.distance_1_error_mask);\n        s1.append_transition_as_error_instruction_to(empty_search_state, out);\n        return out;\n    }\n\n    std::queue<SearchState> queue;\n    std::unordered_map<SearchState, SearchState, SearchStateHash> back_map;\n    // Mark the vacuous dead-end state as already seen.\n    back_map.emplace(empty_search_state, empty_search_state);\n\n    // Search starts from any and all edges crossing an observable.\n    for (size_t node1 = 0; node1 < graph.nodes.size(); node1++) {\n        for (const auto &e : graph.nodes[node1].edges) {\n            uint64_t node2 = e.opposite_node_index;\n            if (node1 < node2 && e.crossing_observable_mask.not_zero()) {\n                SearchState start{node1, node2, e.crossing_observable_mask};\n                queue.push(start);\n                back_map.emplace(start, empty_search_state);\n            }\n        }\n    }\n\n    // Breadth first search for a symptomless state that has a frame change.\n    for (; !queue.empty(); queue.pop()) {\n        SearchState cur = queue.front();\n        assert(cur.det_active != NO_NODE_INDEX);\n        for (const auto &e : graph.nodes[cur.det_active].edges) {\n            SearchState next(e.opposite_node_index, cur.det_held, e.crossing_observable_mask ^ cur.obs_mask);\n            if (!back_map.emplace(next, cur).second) {\n                continue;\n            }\n            if (next.is_undetected()) {\n                assert(next.obs_mask.not_zero());  // Otherwise, it would have already been in back_map.\n                return backtrack_path(back_map, next);\n            } else {\n                if (next.det_active == NO_NODE_INDEX) {\n                    // Just resolved one out of two excitations. Move on to the second excitation.\n                    std::swap(next.det_active, next.det_held);\n                }\n                queue.push(next);\n            }\n        }\n    }\n\n    std::stringstream err_msg;\n    err_msg << \"Failed to find any graphlike logical errors.\";\n    if (graph.num_observables == 0) {\n        err_msg << \"\\n    WARNING: NO OBSERVABLES. The circuit or detector error model didn't define any observables, \"\n                   \"making it vacuously impossible to find a logical error.\";\n    }\n    if (graph.nodes.size() == 0) {\n        err_msg << \"\\n    WARNING: NO DETECTORS. The circuit or detector error model didn't define any detectors.\";\n    }\n    if (model.count_errors() == 0) {\n        err_msg << \"\\n    WARNING: NO ERRORS. The circuit or detector error model didn't include any errors, making it \"\n                   \"vacuously impossible to find a logical error.\";\n    } else {\n        bool edges = 0;\n        for (const auto &n : graph.nodes) {\n            edges |= n.edges.size() > 0;\n        }\n        if (!edges) {\n            err_msg << \"\\n    WARNING: NO GRAPHLIKE ERRORS. Although the circuit or detector error model does define \"\n                       \"some errors, none of them are graphlike (i.e. have at most two detection events), making it \"\n                       \"vacuously impossible to find a graphlike logical error.\";\n        }\n    }\n    throw std::invalid_argument(err_msg.str());\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/algo.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_GRAPHLIKE_ALGO_H\n#define _STIM_SEARCH_GRAPHLIKE_ALGO_H\n\n#include \"stim/dem/detector_error_model.h\"\n\nnamespace stim {\n\n/// Finds a list of graphlike errors from the model that form an undetectable logical error.\n///\n/// An error is graphlike if it has at most 2 symptoms (detector indices).\n///\n/// The components of composite errors like D0 ^ D1 D2 are included in the set of graphlike errors being considered when\n/// trying to find an undetectable error (even if that specific graphlike error component doesn't occur on its own\n/// outside a composite error anywhere in the model).\n///\n/// Args:\n///     model: The detector error model to search for undetectable errors.\n///     ignore_ungraphlike_errors: Determines whether or not error components with more than 2 symptoms should raise an\n///         exception, or just be ignored as if they weren't there.\n///\n/// Returns:\n///     A detector error model containing only the error mechanisms that cause the undetectable logical error.\n///     Note that the error mechanisms will have their probabilities set to 1 (indicating they are necessary).\nDetectorErrorModel shortest_graphlike_undetectable_logical_error(\n    const DetectorErrorModel &model, bool ignore_ungraphlike_errors);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/graphlike/algo.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/perf.perf.h\"\n#include \"stim/search/search.h\"\n#include \"stim/simulators/error_analyzer.h\"\n\nusing namespace stim;\n\nBENCHMARK(find_graphlike_logical_error_surface_code_d25) {\n    CircuitGenParameters params(25, 25, \"rotated_memory_x\");\n    params.after_clifford_depolarization = 0.001;\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    params.before_round_data_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto model = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);\n\n    size_t total = 0;\n    benchmark_go([&]() {\n        total += stim::shortest_graphlike_undetectable_logical_error(model, false).instructions.size();\n    }).goal_millis(35);\n    if (total % 25 != 0 || total == 0) {\n        std::cout << \"bad\";\n    }\n}\n\nBENCHMARK(find_graphlike_logical_error_surface_code_d11_r1000) {\n    CircuitGenParameters params(1000, 11, \"rotated_memory_x\");\n    params.after_clifford_depolarization = 0.001;\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    params.before_round_data_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto model = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);\n\n    size_t total = 0;\n    benchmark_go([&]() {\n        total += stim::shortest_graphlike_undetectable_logical_error(model, false).instructions.size();\n    }).goal_millis(100);\n    if (total % 11 != 0 || total == 0) {\n        std::cout << \"bad\";\n    }\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/algo.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/algo.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/search/graphlike/edge.h\"\n#include \"stim/simulators/error_analyzer.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nTEST(shortest_graphlike_undetectable_logical_error, no_error) {\n    // No error.\n    ASSERT_THROW(\n        { stim::shortest_graphlike_undetectable_logical_error(DetectorErrorModel(), false); }, std::invalid_argument);\n\n    // No undetectable error.\n    ASSERT_THROW(\n        {\n            stim::shortest_graphlike_undetectable_logical_error(\n                DetectorErrorModel(R\"MODEL(\n            error(0.1) D0 L0\n        )MODEL\"),\n                false);\n        },\n        std::invalid_argument);\n\n    // No logical flips.\n    ASSERT_THROW(\n        {\n            stim::shortest_graphlike_undetectable_logical_error(\n                DetectorErrorModel(R\"MODEL(\n            error(0.1) D0\n            error(0.1) D0 D1\n            error(0.1) D1\n        )MODEL\"),\n                false);\n        },\n        std::invalid_argument);\n}\n\nTEST(shortest_graphlike_undetectable_logical_error, distance_1) {\n    ASSERT_EQ(\n        stim::shortest_graphlike_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) L0\n            )MODEL\"),\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) L0\n        )MODEL\"));\n}\n\nTEST(shortest_graphlike_undetectable_logical_error, distance_2) {\n    ASSERT_EQ(\n        stim::shortest_graphlike_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0\n                error(0.1) D0 L0\n            )MODEL\"),\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0\n            error(1) D0 L0\n        )MODEL\"));\n\n    ASSERT_EQ(\n        stim::shortest_graphlike_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0 L0\n                error(0.1) D0 L1\n            )MODEL\"),\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0 L0\n            error(1) D0 L1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        stim::shortest_graphlike_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0 D1 L0\n                error(0.1) D0 D1 L1\n            )MODEL\"),\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0 D1 L0\n            error(1) D0 D1 L1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        stim::shortest_graphlike_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0 D1 L1\n                error(0.1) D0 D1 L0\n            )MODEL\"),\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0 D1 L0\n            error(1) D0 D1 L1\n        )MODEL\"));\n}\n\nTEST(shortest_graphlike_undetectable_logical_error, distance_3) {\n    ASSERT_EQ(\n        stim::shortest_graphlike_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0\n                error(0.1) D0 D1 L0\n                error(0.1) D1\n            )MODEL\"),\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0\n            error(1) D0 D1 L0\n            error(1) D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        stim::shortest_graphlike_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D1\n                error(0.1) D1 D0 L0\n                error(0.1) D0\n            )MODEL\"),\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0\n            error(1) D0 D1 L0\n            error(1) D1\n        )MODEL\"));\n}\n\nTEST(shortest_graphlike_undetectable_logical_error, surface_code) {\n    CircuitGenParameters params(5, 5, \"rotated_memory_x\");\n    params.after_clifford_depolarization = 0.001;\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    params.before_round_data_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto graphlike_model = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);\n    auto ungraphlike_model =\n        ErrorAnalyzer::circuit_to_detector_error_model(circuit, false, true, false, 0.0, false, true);\n\n    ASSERT_EQ(stim::shortest_graphlike_undetectable_logical_error(graphlike_model, false).instructions.size(), 5);\n\n    ASSERT_EQ(stim::shortest_graphlike_undetectable_logical_error(graphlike_model, true).instructions.size(), 5);\n\n    ASSERT_EQ(stim::shortest_graphlike_undetectable_logical_error(ungraphlike_model, true).instructions.size(), 5);\n\n    // Throw due to ungraphlike errors.\n    ASSERT_THROW(\n        { stim::shortest_graphlike_undetectable_logical_error(ungraphlike_model, false); }, std::invalid_argument);\n}\n\nTEST(shortest_graphlike_undetectable_logical_error, repetition_code) {\n    CircuitGenParameters params(10, 7, \"memory\");\n    params.before_round_data_depolarization = 0.01;\n    auto circuit = generate_rep_code_circuit(params).circuit;\n    auto graphlike_model = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);\n\n    ASSERT_EQ(stim::shortest_graphlike_undetectable_logical_error(graphlike_model, false).instructions.size(), 7);\n}\n\nTEST(shortest_graphlike_undetectable_logical_error, many_observables) {\n    Circuit circuit(R\"CIRCUIT(\n        MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4\n        X_ERROR(0.1) 0 1 2 3 4\n        MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4\n        DETECTOR rec[-1] rec[-5]\n        DETECTOR rec[-2] rec[-6]\n        DETECTOR rec[-3] rec[-7]\n        DETECTOR rec[-4] rec[-8]\n        M 4\n        OBSERVABLE_INCLUDE(1200) rec[-1]\n    )CIRCUIT\");\n    auto graphlike_model = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);\n    auto err = stim::shortest_graphlike_undetectable_logical_error(graphlike_model, false);\n    ASSERT_EQ(err.instructions.size(), 5);\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/edge.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/edge.h\"\n\n#include <algorithm>\n#include <sstream>\n\n#include \"stim/search/graphlike/node.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nstd::string Edge::str() const {\n    std::stringstream result;\n    result << *this;\n    return result.str();\n}\nbool Edge::operator==(const Edge &other) const {\n    return opposite_node_index == other.opposite_node_index &&\n           crossing_observable_mask == other.crossing_observable_mask;\n}\nbool Edge::operator!=(const Edge &other) const {\n    return !(*this == other);\n}\nstd::ostream &stim::impl_search_graphlike::operator<<(std::ostream &out, const Edge &v) {\n    if (v.opposite_node_index == NO_NODE_INDEX) {\n        out << \"[boundary]\";\n    } else {\n        out << \"D\" << v.opposite_node_index;\n    }\n    auto m = v.crossing_observable_mask;\n    for (size_t k = 0; k < m.num_bits_padded(); k++) {\n        if (m[k]) {\n            out << \" L\" << k;\n        }\n    }\n    return out;\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/edge.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_GRAPHLIKE_EDGE_H\n#define _STIM_SEARCH_GRAPHLIKE_EDGE_H\n\n#include <cstdint>\n#include <iostream>\n#include <string>\n\n#include \"stim/mem/simd_bits.h\"\n\nnamespace stim {\n\nnamespace impl_search_graphlike {\n\n/// A graphlike edge from a detector error model.\nstruct Edge {\n    uint64_t opposite_node_index;\n    simd_bits<64> crossing_observable_mask;\n    std::string str() const;\n    bool operator==(const Edge &other) const;\n    bool operator!=(const Edge &other) const;\n};\nstd::ostream &operator<<(std::ostream &out, const Edge &v);\n\n}  // namespace impl_search_graphlike\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/graphlike/edge.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/edge.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/search/graphlike/node.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nstatic simd_bits<64> obs_mask(uint64_t v) {\n    simd_bits<64> result(64);\n    result.ptr_simd[0] = v;\n    return result;\n}\n\nTEST(search_graphlike, Edge) {\n    Edge e1{NO_NODE_INDEX, obs_mask(0)};\n    Edge e2{1, obs_mask(0)};\n    Edge e3{NO_NODE_INDEX, obs_mask(1)};\n    Edge e4{NO_NODE_INDEX, obs_mask(5)};\n    ASSERT_EQ(e1.str(), \"[boundary]\");\n    ASSERT_EQ(e2.str(), \"D1\");\n    ASSERT_EQ(e3.str(), \"[boundary] L0\");\n    ASSERT_EQ(e4.str(), \"[boundary] L0 L2\");\n\n    ASSERT_TRUE(e1 == e1);\n    ASSERT_TRUE(!(e1 == e2));\n    ASSERT_FALSE(e1 == e2);\n    ASSERT_FALSE(!(e1 == e1));\n\n    ASSERT_EQ(e1, (Edge{NO_NODE_INDEX, obs_mask(0)}));\n    ASSERT_EQ(e2, e2);\n    ASSERT_EQ(e3, e3);\n    ASSERT_NE(e1, e3);\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/graph.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/graph.h\"\n\n#include <algorithm>\n#include <map>\n#include <queue>\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nstd::string Graph::str() const {\n    std::stringstream result;\n    result << *this;\n    return result.str();\n}\n\nvoid Graph::add_outward_edge(size_t src, uint64_t dst, const simd_bits<64> &obs_mask) {\n    assert(src < nodes.size());\n    auto &node = nodes[src];\n\n    // Don't add duplicate edges.\n    // Note: the neighbor list is expected to be short, so we do a linear scan instead of e.g. a binary search.\n    for (const auto &e : node.edges) {\n        if (e.opposite_node_index == dst && e.crossing_observable_mask == obs_mask) {\n            return;\n        }\n    }\n\n    node.edges.push_back({dst, obs_mask});\n}\n\nvoid Graph::add_edges_from_targets_with_no_separators(\n    SpanRef<const DemTarget> targets, bool ignore_ungraphlike_errors) {\n    FixedCapVector<uint64_t, 2> detectors;\n    simd_bits<64> obs_mask(num_observables);\n\n    // Collect detectors and observables.\n    for (const auto &t : targets) {\n        if (t.is_relative_detector_id()) {\n            if (detectors.size() == 2) {\n                if (ignore_ungraphlike_errors) {\n                    return;\n                }\n                throw std::invalid_argument(\n                    \"The detector error model contained a non-graphlike error mechanism.\\n\"\n                    \"You can ignore such errors using `ignore_ungraphlike_errors`.\\n\"\n                    \"You can use `decompose_errors` when converting a circuit into a model \"\n                    \"to ensure no such errors are present.\\n\");\n            }\n            detectors.push_back(t.raw_id());\n        } else if (t.is_observable_id()) {\n            obs_mask[t.raw_id()] ^= true;\n        }\n    }\n\n    // Add edges between detector nodes.\n    if (detectors.size() == 1) {\n        add_outward_edge(detectors[0], NO_NODE_INDEX, obs_mask);\n    } else if (detectors.size() == 2) {\n        add_outward_edge(detectors[0], detectors[1], obs_mask);\n        add_outward_edge(detectors[1], detectors[0], obs_mask);\n    } else if (detectors.empty() && !distance_1_error_mask.not_zero() && obs_mask.not_zero()) {\n        distance_1_error_mask = obs_mask;\n    }\n}\n\nvoid Graph::add_edges_from_separable_targets(SpanRef<const DemTarget> targets, bool ignore_ungraphlike_errors) {\n    const DemTarget *prev = targets.begin();\n    const DemTarget *cur = targets.begin();\n    while (true) {\n        if (cur == targets.end() || cur->is_separator()) {\n            if (ignore_ungraphlike_errors && cur != targets.end()) {\n                return;\n            }\n            add_edges_from_targets_with_no_separators({prev, cur}, ignore_ungraphlike_errors);\n            prev = cur + 1;\n        }\n        if (cur == targets.end()) {\n            break;\n        }\n        cur++;\n    }\n}\n\nGraph Graph::from_dem(const DetectorErrorModel &model, bool ignore_ungraphlike_errors) {\n    Graph result(model.count_detectors(), model.count_observables());\n    model.iter_flatten_error_instructions([&](const DemInstruction &e) {\n        if (e.arg_data[0] != 0) {\n            result.add_edges_from_separable_targets(e.target_data, ignore_ungraphlike_errors);\n        }\n    });\n    return result;\n}\nbool Graph::operator==(const Graph &other) const {\n    return nodes == other.nodes && num_observables == other.num_observables &&\n           distance_1_error_mask == other.distance_1_error_mask;\n}\nbool Graph::operator!=(const Graph &other) const {\n    return !(*this == other);\n}\n\nGraph::Graph(size_t node_count, size_t num_observables)\n    : nodes(node_count), num_observables(num_observables), distance_1_error_mask(num_observables) {\n}\n\nGraph::Graph(std::vector<Node> nodes, size_t num_observables, simd_bits<64> distance_1_error_mask)\n    : nodes(std::move(nodes)),\n      num_observables(num_observables),\n      distance_1_error_mask(std::move(distance_1_error_mask)) {\n}\n\nstd::ostream &stim::impl_search_graphlike::operator<<(std::ostream &out, const Graph &v) {\n    for (size_t k = 0; k < v.nodes.size(); k++) {\n        out << k << \":\\n\" << v.nodes[k];\n    }\n    return out;\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/graph.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_GRAPHLIKE_GRAPH_H\n#define _STIM_SEARCH_GRAPHLIKE_GRAPH_H\n\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/search/graphlike/node.h\"\n\nnamespace stim {\n\nnamespace impl_search_graphlike {\n\nstruct Graph {\n    std::vector<Node> nodes;\n    size_t num_observables;\n    simd_bits<64> distance_1_error_mask;\n\n    explicit Graph(size_t node_count, size_t num_observables);\n    Graph(std::vector<Node> nodes, size_t num_observables, simd_bits<64> distance_1_error_mask);\n\n    void add_outward_edge(size_t src, uint64_t dst, const simd_bits<64> &obs_mask);\n    void add_edges_from_targets_with_no_separators(SpanRef<const DemTarget> targets, bool ignore_ungraphlike_errors);\n    void add_edges_from_separable_targets(SpanRef<const DemTarget> targets, bool ignore_ungraphlike_errors);\n    static Graph from_dem(const DetectorErrorModel &model, bool ignore_ungraphlike_errors);\n    bool operator==(const Graph &other) const;\n    bool operator!=(const Graph &other) const;\n    std::string str() const;\n};\nstd::ostream &operator<<(std::ostream &out, const Graph &v);\n\n}  // namespace impl_search_graphlike\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/graphlike/graph.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/graph.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nstatic simd_bits<64> obs_mask(uint64_t v) {\n    simd_bits<64> result(64);\n    result.ptr_simd[0] = v;\n    return result;\n}\n\nTEST(search_graphlike, DemAdjGraph_equality) {\n    ASSERT_TRUE(Graph(1, 5) == Graph(1, 5));\n    ASSERT_TRUE(Graph(1, 5) != Graph(2, 5));\n    ASSERT_TRUE(Graph(1, 5) != Graph(1, 4));\n    ASSERT_FALSE(Graph(1, 5) == Graph(2, 5));\n    ASSERT_FALSE(Graph(1, 5) != Graph(1, 5));\n\n    Graph a(1, 5);\n    Graph b(1, 5);\n    ASSERT_EQ(a, b);\n    b.distance_1_error_mask = obs_mask(1);\n    ASSERT_NE(a, b);\n}\n\nTEST(search_graphlike, DemAdjGraph_add_outward_edge) {\n    Graph g(3, 64);\n\n    g.add_outward_edge(1, 2, obs_mask(3));\n    ASSERT_EQ(\n        g,\n        (Graph{\n            std::vector<Node>{\n                Node{},\n                Node{{Edge{2, obs_mask(3)}}},\n                Node{},\n            },\n            64,\n            obs_mask(0)}));\n\n    g.add_outward_edge(1, 2, obs_mask(3));\n    ASSERT_EQ(\n        g,\n        (Graph{\n            std::vector<Node>{\n                Node{},\n                Node{{Edge{2, obs_mask(3)}}},\n                Node{},\n            },\n            64,\n            obs_mask(0)}));\n\n    g.add_outward_edge(1, 2, obs_mask(4));\n    ASSERT_EQ(\n        g,\n        (Graph{\n            std::vector<Node>{\n                Node{},\n                Node{{Edge{2, obs_mask(3)}, Edge{2, obs_mask(4)}}},\n                Node{},\n            },\n            64,\n            obs_mask(0)}));\n\n    g.add_outward_edge(2, 1, obs_mask(3));\n    ASSERT_EQ(\n        g,\n        (Graph{\n            std::vector<Node>{\n                Node{},\n                Node{{Edge{2, obs_mask(3)}, Edge{2, obs_mask(4)}}},\n                Node{{Edge{1, obs_mask(3)}}},\n            },\n            64,\n            obs_mask(0)}));\n\n    g.add_outward_edge(2, NO_NODE_INDEX, obs_mask(3));\n    ASSERT_EQ(\n        g,\n        (Graph{\n            std::vector<Node>{\n                Node{},\n                Node{{Edge{2, obs_mask(3)}, Edge{2, obs_mask(4)}}},\n                Node{{Edge{1, obs_mask(3)}, Edge{NO_NODE_INDEX, obs_mask(3)}}},\n            },\n            64,\n            obs_mask(0)}));\n}\n\nTEST(search_graphlike, DemAdjGraph_add_edges_from_targets_with_no_separators) {\n    Graph g(4, 64);\n\n    g.add_edges_from_targets_with_no_separators(std::vector<DemTarget>{DemTarget::relative_detector_id(1)}, false);\n\n    ASSERT_EQ(\n        g,\n        (Graph{\n            {\n                Node{},\n                Node{{Edge{NO_NODE_INDEX, obs_mask(0)}}},\n                Node{},\n                Node{},\n            },\n            64,\n            obs_mask(0)}));\n\n    g.add_edges_from_targets_with_no_separators(\n        std::vector<DemTarget>{\n            DemTarget::relative_detector_id(1),\n            DemTarget::relative_detector_id(3),\n            DemTarget::observable_id(5),\n        },\n        false);\n\n    ASSERT_EQ(\n        g,\n        (Graph{\n            {\n                Node{},\n                Node{{Edge{NO_NODE_INDEX, obs_mask(0)}, Edge{3, obs_mask(32)}}},\n                Node{},\n                Node{{Edge{1, obs_mask(32)}}},\n            },\n            64,\n            obs_mask(0)}));\n\n    g.add_edges_from_targets_with_no_separators(\n        std::vector<DemTarget>{\n            DemTarget::observable_id(3),\n            DemTarget::observable_id(7),\n        },\n        false);\n\n    ASSERT_EQ(\n        g,\n        (Graph{\n            {\n                Node{},\n                Node{{Edge{NO_NODE_INDEX, obs_mask(0)}, Edge{3, obs_mask(32)}}},\n                Node{},\n                Node{{Edge{1, obs_mask(32)}}},\n            },\n            64,\n            obs_mask((1 << 3) + (1 << 7))}));\n\n    Graph same_g = g;\n    std::vector<DemTarget> too_big{\n        DemTarget::relative_detector_id(1),\n        DemTarget::relative_detector_id(2),\n        DemTarget::relative_detector_id(3),\n    };\n    ASSERT_THROW({ same_g.add_edges_from_targets_with_no_separators(too_big, false); }, std::invalid_argument);\n    ASSERT_EQ(g, same_g);\n    same_g.add_edges_from_targets_with_no_separators(too_big, true);\n    ASSERT_EQ(g, same_g);\n}\n\nTEST(search_graphlike, DemAdjGraph_str) {\n    Graph g{\n        {\n            Node{},\n            Node{{Edge{NO_NODE_INDEX, obs_mask(0)}, Edge{3, obs_mask(32)}}},\n            Node{},\n            Node{{Edge{1, obs_mask(32)}}},\n        },\n        64,\n        obs_mask(0)};\n    ASSERT_EQ(\n        g.str(),\n        \"0:\\n\"\n        \"1:\\n\"\n        \"    [boundary]\\n\"\n        \"    D3 L5\\n\"\n        \"2:\\n\"\n        \"3:\\n\"\n        \"    D1 L5\\n\");\n}\n\nTEST(search_graphlike, DemAdjGraph_add_edges_from_separable_targets) {\n    Graph g(4, 64);\n\n    g.add_edges_from_separable_targets(\n        std::vector<DemTarget>{\n            DemTarget::relative_detector_id(1),\n            DemTarget::separator(),\n            DemTarget::relative_detector_id(1),\n            DemTarget::relative_detector_id(2),\n            DemTarget::observable_id(4),\n        },\n        false);\n\n    ASSERT_EQ(\n        g,\n        (Graph{\n            {\n                Node{},\n                Node{{Edge{NO_NODE_INDEX, obs_mask(0)}, Edge{2, obs_mask(16)}}},\n                Node{{Edge{1, obs_mask(16)}}},\n                Node{},\n            },\n            64,\n            obs_mask(0)}));\n}\n\nTEST(search_graphlike, DemAdjGraph_from_dem) {\n    ASSERT_EQ(\n        Graph::from_dem(\n            DetectorErrorModel(R\"MODEL(\n        error(0.1) D0\n        repeat 3 {\n            error(0.1) D0 D1\n            shift_detectors 1\n        }\n        error(0.1) D0 L7\n        error(0.1) D2 ^ D3 D4 L2\n        detector D5\n    )MODEL\"),\n            false),\n        Graph(\n            {\n                Node{{Edge{NO_NODE_INDEX, obs_mask(0)}, Edge{1, obs_mask(0)}}},\n                Node{{Edge{0, obs_mask(0)}, Edge{2, obs_mask(0)}}},\n                Node{{Edge{1, obs_mask(0)}, Edge{3, obs_mask(0)}}},\n                Node{{Edge{2, obs_mask(0)}, Edge{NO_NODE_INDEX, obs_mask(128)}}},\n                Node{},\n                Node{{Edge{NO_NODE_INDEX, obs_mask(0)}}},\n                Node{{Edge{7, obs_mask(4)}}},\n                Node{{Edge{6, obs_mask(4)}}},\n                Node{},\n            },\n            8,\n            obs_mask(0)));\n}\n\nTEST(search_graphlike, add_edges_from_separable_targets_ignore) {\n    Graph actual(10, 64);\n    Graph expected(10, 64);\n    DetectorErrorModel d(R\"DEM(\n        error(0.125) D0 ^ D4 D6\n    )DEM\");\n    ASSERT_EQ(actual, expected);\n    actual.add_edges_from_separable_targets(d.instructions[0].target_data, true);\n    ASSERT_EQ(actual, expected);\n    actual.add_edges_from_separable_targets(d.instructions[0].target_data, false);\n    expected.add_outward_edge(4, 6, obs_mask(0));\n    expected.add_outward_edge(6, 4, obs_mask(0));\n    expected.add_outward_edge(0, NO_NODE_INDEX, obs_mask(0));\n    ASSERT_EQ(actual, expected);\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/node.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/node.h\"\n\n#include <queue>\n#include <sstream>\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nstd::string Node::str() const {\n    std::stringstream result;\n    result << *this;\n    return result.str();\n}\n\nbool Node::operator==(const Node &other) const {\n    return edges == other.edges;\n}\n\nbool Node::operator!=(const Node &other) const {\n    return !(*this == other);\n}\n\nstd::ostream &stim::impl_search_graphlike::operator<<(std::ostream &out, const Node &v) {\n    for (const auto &e : v.edges) {\n        out << \"    \" << e << \"\\n\";\n    }\n    return out;\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/node.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_GRAPHLIKE_NODE_H\n#define _STIM_SEARCH_GRAPHLIKE_NODE_H\n\n#include <vector>\n\n#include \"stim/search/graphlike/edge.h\"\n\nnamespace stim {\n\nnamespace impl_search_graphlike {\n\nconstexpr uint64_t NO_NODE_INDEX = UINT64_MAX;\n\n/// Adjacency list representation of a detector from a detector error model.\n/// Only includes graphlike edges.\nstruct Node {\n    std::vector<Edge> edges;\n    std::string str() const;\n    bool operator==(const Node &other) const;\n    bool operator!=(const Node &other) const;\n};\nstd::ostream &operator<<(std::ostream &out, const Node &v);\n\n}  // namespace impl_search_graphlike\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/graphlike/node.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/node.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nstatic simd_bits<64> obs_mask(uint64_t v) {\n    simd_bits<64> result(64);\n    result.ptr_simd[0] = v;\n    return result;\n}\n\nTEST(search_graphlike, Node) {\n    Node n1{};\n    Node n2{{Edge{NO_NODE_INDEX, obs_mask(0)}}};\n    Node n3{{Edge{1, obs_mask(5)}, Edge{NO_NODE_INDEX, obs_mask(8)}}};\n    ASSERT_EQ(n1.str(), \"\");\n    ASSERT_EQ(n2.str(), \"    [boundary]\\n\");\n    ASSERT_EQ(n3.str(), \"    D1 L0 L2\\n    [boundary] L3\\n\");\n\n    ASSERT_TRUE(n1 == n1);\n    ASSERT_TRUE(!(n1 == n2));\n    ASSERT_FALSE(n1 == n2);\n    ASSERT_FALSE(!(n1 == n1));\n\n    ASSERT_EQ(n1, (Node{}));\n    ASSERT_EQ(n2, n2);\n    ASSERT_EQ(n3, n3);\n    ASSERT_NE(n1, n3);\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/search_state.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/search_state.h\"\n\n#include <algorithm>\n#include <map>\n\n#include \"stim/search/graphlike/node.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nstd::string SearchState::str() const {\n    std::stringstream result;\n    result << *this;\n    return result.str();\n}\n\nSearchState::SearchState(size_t num_observables)\n    : det_active(NO_NODE_INDEX), det_held(NO_NODE_INDEX), obs_mask(num_observables) {\n}\nSearchState::SearchState(uint64_t det_active, uint64_t det_held, simd_bits<64> obs_mask)\n    : det_active(det_active), det_held(det_held), obs_mask(std::move(obs_mask)) {\n}\n\nbool SearchState::is_undetected() const {\n    return det_active == det_held;\n}\n\nSearchState SearchState::canonical() const {\n    if (det_active < det_held) {\n        return SearchState{det_active, det_held, obs_mask};\n    } else if (det_active > det_held) {\n        return SearchState{det_held, det_active, obs_mask};\n    } else {\n        return SearchState{NO_NODE_INDEX, NO_NODE_INDEX, obs_mask};\n    }\n}\n\nvoid SearchState::append_transition_as_error_instruction_to(const SearchState &other, DetectorErrorModel &out) const {\n    // Extract detector indices while cancelling duplicates.\n    std::array<uint64_t, 5> nodes{det_active, det_held, other.det_active, other.det_held, NO_NODE_INDEX};\n    std::sort(nodes.begin(), nodes.end());\n    for (size_t k = 0; k < 4; k++) {\n        if (nodes[k] == nodes[k + 1]) {\n            k++;\n        } else {\n            out.target_buf.append_tail(DemTarget::relative_detector_id(nodes[k]));\n        }\n    }\n\n    // Extract logical observable indices.\n    auto dif_mask = obs_mask ^ other.obs_mask;\n    for (size_t k = 0; k < dif_mask.num_bits_padded(); k++) {\n        if (dif_mask[k]) {\n            out.target_buf.append_tail(DemTarget::observable_id(k));\n        }\n    }\n\n    out.arg_buf.append_tail(1);\n\n    out.instructions.push_back(\n        DemInstruction{\n            .arg_data = out.arg_buf.commit_tail(),\n            .target_data = out.target_buf.commit_tail(),\n            .tag = \"\",\n            .type = DemInstructionType::DEM_ERROR,\n        });\n}\n\nbool SearchState::operator==(const SearchState &other) const {\n    SearchState a = canonical();\n    SearchState b = other.canonical();\n    return a.det_active == b.det_active && a.det_held == b.det_held && a.obs_mask == b.obs_mask;\n}\nbool SearchState::operator!=(const SearchState &other) const {\n    return !(*this == other);\n}\n\nbool SearchState::operator<(const SearchState &other) const {\n    SearchState a = canonical();\n    SearchState b = other.canonical();\n    if (a.det_active != b.det_active) {\n        return a.det_active < b.det_active;\n    }\n    if (a.det_held != b.det_held) {\n        return a.det_held < b.det_held;\n    }\n    return a.obs_mask < b.obs_mask;\n}\n\nstd::ostream &stim::impl_search_graphlike::operator<<(std::ostream &out, const SearchState &v) {\n    if (v.is_undetected()) {\n        out << \"[no symptoms] \";\n    } else {\n        if (v.det_active != NO_NODE_INDEX) {\n            out << \"D\" << v.det_active << \" \";\n        }\n        if (v.det_held != NO_NODE_INDEX) {\n            out << \"D\" << v.det_held << \" \";\n        }\n    }\n\n    for (size_t k = 0; k < v.obs_mask.num_bits_padded(); k++) {\n        if (v.obs_mask[k]) {\n            out << \"L\" << k << \" \";\n        }\n    }\n\n    return out;\n}\n"
  },
  {
    "path": "src/stim/search/graphlike/search_state.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_GRAPHLIKE_SEARCH_STATE_H\n#define _STIM_SEARCH_GRAPHLIKE_SEARCH_STATE_H\n\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/mem/simd_bits.h\"\n\nnamespace stim {\n\nnamespace impl_search_graphlike {\n\nstruct SearchState {\n    uint64_t det_active;     // The detection event being moved around in an attempt to remove it (or NO_NODE_INDEX).\n    uint64_t det_held;       // The detection event being left in the same place (or NO_NODE_INDEX).\n    simd_bits<64> obs_mask;  // The accumulated frame changes from moving the detection events around.\n\n    SearchState() = delete;\n    SearchState(size_t num_observables);\n    SearchState(uint64_t det_active, uint64_t det_held, simd_bits<64> obs_mask);\n    bool is_undetected() const;\n    SearchState canonical() const;\n    void append_transition_as_error_instruction_to(const SearchState &other, DetectorErrorModel &out) const;\n    bool operator==(const SearchState &other) const;\n    bool operator!=(const SearchState &other) const;\n    bool operator<(const SearchState &other) const;\n    std::string str() const;\n};\nstd::ostream &operator<<(std::ostream &out, const SearchState &v);\n\ninline void hash_combine(size_t &h, uint64_t x) {\n    h ^= std::hash<uint64_t>{}(x) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2); // mimic Boost's hash-combine function\n}\n\nstruct SearchStateHash {\n    size_t operator()(const SearchState &s) const {\n        SearchState c = s.canonical();\n        size_t h = std::hash<uint64_t>{}(c.det_active);\n        hash_combine(h, c.det_held);\n        for (size_t i = 0; i < c.obs_mask.num_u64_padded(); i++) {\n            hash_combine(h, c.obs_mask.u64[i]);\n        }\n        return h;\n    }\n};\n\n}  // namespace impl_search_graphlike\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/graphlike/search_state.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/graphlike/search_state.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/search/graphlike/node.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_graphlike;\n\nstatic simd_bits<64> obs_mask(uint64_t v) {\n    simd_bits<64> result(64);\n    result.ptr_simd[0] = v;\n    return result;\n}\n\nTEST(search_graphlike, DemAdjGraphSearchState_construct) {\n    SearchState r(64);\n    ASSERT_EQ(r.det_active, NO_NODE_INDEX);\n    ASSERT_EQ(r.det_held, NO_NODE_INDEX);\n    ASSERT_EQ((uint64_t)r.obs_mask.ptr_simd[0], 0);\n\n    SearchState r2(2, 1, obs_mask(3));\n    ASSERT_EQ(r2.det_active, 2);\n    ASSERT_EQ(r2.det_held, 1);\n    ASSERT_EQ((uint64_t)r2.obs_mask.ptr_simd[0], 3);\n}\n\nTEST(search_graphlike, DemAdjGraphSearchState_is_undetected) {\n    ASSERT_FALSE(SearchState(1, 2, obs_mask(3)).is_undetected());\n    ASSERT_FALSE(SearchState(1, 2, obs_mask(2)).is_undetected());\n    ASSERT_FALSE(SearchState(1, 2, obs_mask(0)).is_undetected());\n    ASSERT_TRUE(SearchState(1, 1, obs_mask(3)).is_undetected());\n    ASSERT_TRUE(SearchState(NO_NODE_INDEX, NO_NODE_INDEX, obs_mask(32)).is_undetected());\n    ASSERT_TRUE(SearchState(NO_NODE_INDEX, NO_NODE_INDEX, obs_mask(0)).is_undetected());\n}\n\nTEST(search_graphlike, DemAdjGraphSearchState_canonical) {\n    SearchState a = SearchState(1, 2, obs_mask(3)).canonical();\n    ASSERT_EQ(a.det_active, 1);\n    ASSERT_EQ(a.det_held, 2);\n    ASSERT_EQ(a.obs_mask, obs_mask(3));\n\n    a = SearchState(2, 1, obs_mask(3)).canonical();\n    ASSERT_EQ(a.det_active, 1);\n    ASSERT_EQ(a.det_held, 2);\n    ASSERT_EQ(a.obs_mask, obs_mask(3));\n\n    a = SearchState(1, 1, obs_mask(3)).canonical();\n    ASSERT_EQ(a.det_active, NO_NODE_INDEX);\n    ASSERT_EQ(a.det_held, NO_NODE_INDEX);\n    ASSERT_EQ(a.obs_mask, obs_mask(3));\n\n    a = SearchState(1, 1, obs_mask(1)).canonical();\n    ASSERT_EQ(a.det_active, NO_NODE_INDEX);\n    ASSERT_EQ(a.det_held, NO_NODE_INDEX);\n    ASSERT_EQ(a.obs_mask, obs_mask(1));\n\n    a = SearchState(1, NO_NODE_INDEX, obs_mask(1)).canonical();\n    ASSERT_EQ(a.det_active, 1);\n    ASSERT_EQ(a.det_held, NO_NODE_INDEX);\n    ASSERT_EQ(a.obs_mask, obs_mask(1));\n}\n\nTEST(search_graphlike, DemAdjGraphSearchState_append_transition_as_error_instruction_to) {\n    DetectorErrorModel out;\n\n    SearchState(1, 2, obs_mask(9)).append_transition_as_error_instruction_to(SearchState(1, 2, obs_mask(16)), out);\n    ASSERT_EQ(out, DetectorErrorModel(R\"MODEL(\n        error(1) L0 L3 L4\n    )MODEL\"));\n\n    SearchState(1, 2, obs_mask(9)).append_transition_as_error_instruction_to(SearchState(3, 2, obs_mask(9)), out);\n    ASSERT_EQ(out, DetectorErrorModel(R\"MODEL(\n        error(1) L0 L3 L4\n        error(1) D1 D3\n    )MODEL\"));\n\n    SearchState(1, 2, obs_mask(9))\n        .append_transition_as_error_instruction_to(SearchState(1, NO_NODE_INDEX, obs_mask(9)), out);\n    ASSERT_EQ(out, DetectorErrorModel(R\"MODEL(\n        error(1) L0 L3 L4\n        error(1) D1 D3\n        error(1) D2\n    )MODEL\"));\n\n    SearchState(NO_NODE_INDEX, NO_NODE_INDEX, obs_mask(0))\n        .append_transition_as_error_instruction_to(SearchState(1, NO_NODE_INDEX, obs_mask(9)), out);\n    ASSERT_EQ(out, DetectorErrorModel(R\"MODEL(\n        error(1) L0 L3 L4\n        error(1) D1 D3\n        error(1) D2\n        error(1) D1 L0 L3\n    )MODEL\"));\n\n    SearchState(1, 1, obs_mask(0)).append_transition_as_error_instruction_to(SearchState(2, 2, obs_mask(4)), out);\n    ASSERT_EQ(out, DetectorErrorModel(R\"MODEL(\n        error(1) L0 L3 L4\n        error(1) D1 D3\n        error(1) D2\n        error(1) D1 L0 L3\n        error(1) L2\n    )MODEL\"));\n}\n\nTEST(search_graphlike, DemAdjGraphSearchState_canonical_equality) {\n    SearchState v1{1, 2, obs_mask(3)};\n    SearchState v2{1, 4, obs_mask(3)};\n    ASSERT_TRUE(v1 == v1);\n    ASSERT_FALSE(v1 == v2);\n    ASSERT_FALSE(v1 != v1);\n    ASSERT_TRUE(v1 != v2);\n\n    ASSERT_EQ(v1, SearchState(2, 1, obs_mask(3)));\n    ASSERT_NE(v1, SearchState(1, NO_NODE_INDEX, obs_mask(3)));\n    ASSERT_EQ(SearchState(NO_NODE_INDEX, NO_NODE_INDEX, obs_mask(0)), SearchState(1, 1, obs_mask(0)));\n    ASSERT_EQ(SearchState(3, 3, obs_mask(0)), SearchState(1, 1, obs_mask(0)));\n    ASSERT_NE(SearchState(3, 3, obs_mask(1)), SearchState(1, 1, obs_mask(0)));\n    ASSERT_EQ(SearchState(3, 3, obs_mask(1)), SearchState(1, 1, obs_mask(1)));\n    ASSERT_EQ(SearchState(2, NO_NODE_INDEX, obs_mask(3)), SearchState(NO_NODE_INDEX, 2, obs_mask(3)));\n}\n\nTEST(search_graphlike, DemAdjGraphSearchState_canonical_ordering) {\n    ASSERT_TRUE(SearchState(1, 999, obs_mask(999)) < SearchState(101, 102, obs_mask(103)));\n    ASSERT_TRUE(SearchState(999, 1, obs_mask(999)) < SearchState(101, 102, obs_mask(103)));\n    ASSERT_TRUE(SearchState(101, 1, obs_mask(999)) < SearchState(101, 102, obs_mask(103)));\n    ASSERT_TRUE(SearchState(102, 1, obs_mask(999)) < SearchState(101, 102, obs_mask(103)));\n    ASSERT_TRUE(SearchState(101, 102, obs_mask(3)) < SearchState(101, 102, obs_mask(103)));\n\n    ASSERT_FALSE(SearchState(101, 102, obs_mask(103)) < SearchState(101, 102, obs_mask(103)));\n    ASSERT_FALSE(SearchState(101, 104, obs_mask(103)) < SearchState(101, 102, obs_mask(103)));\n    ASSERT_FALSE(SearchState(101, 102, obs_mask(104)) < SearchState(101, 102, obs_mask(103)));\n}\n\nTEST(search_graphlike, DemAdjGraphSearchState_str) {\n    ASSERT_EQ(SearchState(1, 2, obs_mask(3)).str(), \"D1 D2 L0 L1 \");\n}\n\nTEST(search_graphlike, SearchStateHash_operator) {\n    ASSERT_EQ(SearchStateHash{}(SearchState(1, 2, obs_mask(3))), SearchStateHash{}(SearchState(2, 1, obs_mask(3))));\n    ASSERT_EQ(SearchStateHash{}(SearchState(1, 2, obs_mask(3))), SearchStateHash{}(SearchState(1, 2, obs_mask(3))));\n\n    ASSERT_NE(SearchStateHash{}(SearchState(1, 2, obs_mask(3))), SearchStateHash{}(SearchState(2, 2, obs_mask(3))));\n    ASSERT_NE(SearchStateHash{}(SearchState(1, 2, obs_mask(3))), SearchStateHash{}(SearchState(1, 2, obs_mask(4))));\n}\n"
  },
  {
    "path": "src/stim/search/hyper/algo.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/algo.h\"\n\n#include <algorithm>\n#include <map>\n#include <queue>\n#include <sstream>\n\n#include \"stim/search/graphlike/algo.h\"\n#include \"stim/search/hyper/edge.h\"\n#include \"stim/search/hyper/graph.h\"\n#include \"stim/search/hyper/search_state.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_hyper;\n\nDetectorErrorModel backtrack_path(const std::map<SearchState, SearchState> &back_map, SearchState &&final_state) {\n    DetectorErrorModel out;\n    SearchState cur_state = std::move(final_state);\n    while (true) {\n        auto prev_state = back_map.at(cur_state);\n        cur_state.append_transition_as_error_instruction_to(prev_state, out);\n        if (prev_state.dets.empty()) {\n            break;\n        }\n        cur_state = prev_state;\n    }\n    std::sort(out.instructions.begin(), out.instructions.end());\n\n    // Because of the search truncation, the same step may have been taken twice at different states.\n    for (size_t k = 0; k < out.instructions.size() - 1; k++) {\n        if (out.instructions[k].target_data == out.instructions[k + 1].target_data) {\n            out.instructions.erase(out.instructions.begin() + k);\n            out.instructions.erase(out.instructions.begin() + k);\n            k -= 1;\n        }\n    }\n\n    return out;\n}\n\nDetectorErrorModel stim::find_undetectable_logical_error(\n    const DetectorErrorModel &model,\n    size_t dont_explore_detection_event_sets_with_size_above,\n    size_t dont_explore_edges_with_degree_above,\n    bool dont_explore_edges_increasing_symptom_degree) {\n    if (dont_explore_edges_with_degree_above == 2 && dont_explore_detection_event_sets_with_size_above == 2) {\n        return stim::shortest_graphlike_undetectable_logical_error(model, true);\n    }\n\n    Graph graph = Graph::from_dem(model, dont_explore_edges_with_degree_above);\n\n    auto empty_search_state = SearchState{{}, simd_bits<64>(graph.num_observables)};\n\n    if (graph.distance_1_error_mask.not_zero()) {\n        DetectorErrorModel out;\n        SearchState s1{{}, graph.distance_1_error_mask};\n        s1.append_transition_as_error_instruction_to(empty_search_state, out);\n        return out;\n    }\n\n    std::queue<SearchState> queue;\n    std::map<SearchState, SearchState> back_map;\n    // Mark the vacuous dead-end state as already seen.\n    back_map.emplace(empty_search_state, empty_search_state);\n\n    // Search starts from any and all edges crossing an observable.\n    for (size_t node = 0; node < graph.nodes.size(); node++) {\n        for (const auto &e : graph.nodes[node].edges) {\n            if (e.crossing_observable_mask.not_zero() && e.nodes.sorted_items[0] == node) {\n                SearchState start{e.nodes, e.crossing_observable_mask};\n                if (start.dets.size() <= dont_explore_detection_event_sets_with_size_above) {\n                    queue.push(start);\n                }\n                back_map.emplace(start, empty_search_state);\n            }\n        }\n    }\n\n    // Breadth first search for a symptomless state that has a frame change.\n    for (; !queue.empty(); queue.pop()) {\n        SearchState cur = queue.front();\n        assert(!cur.dets.empty());\n        size_t active_node = cur.dets.sorted_items[0];\n        for (const auto &e : graph.nodes[active_node].edges) {\n            SearchState next{e.nodes ^ cur.dets, e.crossing_observable_mask ^ cur.obs_mask};\n            if (next.dets.size() > dont_explore_detection_event_sets_with_size_above) {\n                continue;\n            }\n            if (dont_explore_edges_increasing_symptom_degree && next.dets.size() > cur.dets.size()) {\n                continue;\n            }\n            if (!back_map.emplace(next, cur).second) {\n                continue;\n            }\n            if (next.dets.empty()) {\n                assert(next.obs_mask.not_zero());  // Otherwise, it would have already been in back_map.\n                return backtrack_path(back_map, std::move(next));\n            }\n            queue.push(std::move(next));\n        }\n    }\n\n    std::stringstream err_msg;\n    err_msg << \"Failed to find any logical errors.\";\n    if (graph.num_observables == 0) {\n        err_msg << \"\\n    WARNING: NO OBSERVABLES. The circuit or detector error model didn't define any observables, \"\n                   \"making it vacuously impossible to find a logical error.\";\n    }\n    if (graph.nodes.size() == 0) {\n        err_msg << \"\\n    WARNING: NO DETECTORS. The circuit or detector error model didn't define any detectors.\";\n    }\n    if (model.count_errors() == 0) {\n        err_msg << \"\\n    WARNING: NO ERRORS. The circuit or detector error model didn't include any errors, making it \"\n                   \"vacuously impossible to find a logical error.\";\n    }\n    throw std::invalid_argument(err_msg.str());\n}\n"
  },
  {
    "path": "src/stim/search/hyper/algo.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_HYPER_ALGO_H\n#define _STIM_SEARCH_HYPER_ALGO_H\n\n#include <cstdint>\n\n#include \"stim/dem/detector_error_model.h\"\n\nnamespace stim {\n\n/// Finds a list of errors from the model that form an undetectable logical error.\n///\n/// Note that this search considers hyper errors, and so if it is not truncated it has exponential\n/// runtime. It is important to carefully consider how you are truncating the space to trade off\n/// cost versus quality of result.\n///\n/// Beware that the choice of logical observable can interact with the truncation options. Using\n/// different observables can change whether or not the search succeeds, even if those observables\n/// are equal modulo the stabilizers of the code. This is because the edges crossing logical\n/// observables are used as starting points for the search, and starting from different places along\n/// a path will result in different numbers of symptoms in intermediate states as the search\n/// progresses. For example, if the logical observable is next to a boundary, then the starting\n/// edges are likely boundary edges (degree 1) with 'room to grow', whereas if the observable was\n/// running through the bulk then the starting edges will have degree at least 2.\n///\n/// To perform a graphlike search use:\n///     dont_explore_detection_event_sets_with_size_above = 2\n///     dont_explore_edges_with_degree_above = 2\n///     dont_explore_edges_increasing_symptom_degree = [anything]\n///\n/// Args:\n///     model: The detector error model to search for undetectable errors.\n///     dont_explore_detection_event_sets_with_size_above: Truncates the search space by refusing to\n///         cross an edge (i.e. add an error) when doing so would produce an intermediate state that\n///         has more detection events than this limit.\n///     dont_explore_edges_with_degree_above: Truncates the search space by refusing to consider\n///         errors that cause a lot of detection events. For example, you may only want to consider\n///         graphlike errors which have two or fewer detection events.\n///     dont_explore_edges_increasing_symptom_degree: Truncates the search space by refusing to\n///         cross an edge (i.e. add an error) when doing so would produce an intermediate state that\n///         has more detection events that the previous intermediate state. This massively improves\n///         the efficiency of the search because instead of, for example, exploring all n^4 possible\n///         detection event sets with 4 symptoms, the search will attempt to cancel out symptoms one\n///         by one.\n///\n/// Returns:\n///     A detector error model containing only the error mechanisms that cause the undetectable\n///     logical error. The error mechanisms will have their probabilities set to 1 (indicating that\n///     they are necessary) and will not suggest a decomposition.\nDetectorErrorModel find_undetectable_logical_error(\n    const DetectorErrorModel &model,\n    size_t dont_explore_detection_event_sets_with_size_above,\n    size_t dont_explore_edges_with_degree_above,\n    bool dont_explore_edges_increasing_symptom_degree);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/hyper/algo.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/algo.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/simulators/error_analyzer.h\"\n\nusing namespace stim;\n\nTEST(find_undetectable_logical_error, no_error) {\n    // No error.\n    ASSERT_THROW(\n        { stim::find_undetectable_logical_error(DetectorErrorModel(), SIZE_MAX, SIZE_MAX, false); },\n        std::invalid_argument);\n\n    // No undetectable error.\n    ASSERT_THROW(\n        {\n            stim::find_undetectable_logical_error(\n                DetectorErrorModel(R\"MODEL(\n            error(0.1) D0 L0\n        )MODEL\"),\n                SIZE_MAX,\n                SIZE_MAX,\n                false);\n        },\n        std::invalid_argument);\n\n    // No logical flips.\n    ASSERT_THROW(\n        {\n            stim::find_undetectable_logical_error(\n                DetectorErrorModel(R\"MODEL(\n            error(0.1) D0\n            error(0.1) D0 D1\n            error(0.1) D1\n        )MODEL\"),\n                SIZE_MAX,\n                SIZE_MAX,\n                false);\n        },\n        std::invalid_argument);\n}\n\nTEST(find_undetectable_logical_error, distance_1) {\n    ASSERT_EQ(\n        stim::find_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) L0\n            )MODEL\"),\n            SIZE_MAX,\n            SIZE_MAX,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) L0\n        )MODEL\"));\n}\n\nTEST(find_undetectable_logical_error, distance_2) {\n    ASSERT_EQ(\n        stim::find_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0\n                error(0.1) D0 L0\n            )MODEL\"),\n            SIZE_MAX,\n            SIZE_MAX,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0\n            error(1) D0 L0\n        )MODEL\"));\n\n    ASSERT_EQ(\n        stim::find_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0 L0\n                error(0.1) D0 L1\n            )MODEL\"),\n            SIZE_MAX,\n            SIZE_MAX,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0 L0\n            error(1) D0 L1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        stim::find_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0 D1 L0\n                error(0.1) D0 D1 L1\n            )MODEL\"),\n            SIZE_MAX,\n            SIZE_MAX,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0 D1 L0\n            error(1) D0 D1 L1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        stim::find_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0 D1 L1\n                error(0.1) D0 D1 L0\n            )MODEL\"),\n            SIZE_MAX,\n            SIZE_MAX,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0 D1 L0\n            error(1) D0 D1 L1\n        )MODEL\"));\n}\n\nTEST(find_undetectable_logical_error, distance_3) {\n    ASSERT_EQ(\n        stim::find_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0\n                error(0.1) D0 D1 L0\n                error(0.1) D1\n            )MODEL\"),\n            SIZE_MAX,\n            SIZE_MAX,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0\n            error(1) D0 D1 L0\n            error(1) D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        stim::find_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D1\n                error(0.1) D1 D0 L0\n                error(0.1) D0\n            )MODEL\"),\n            SIZE_MAX,\n            SIZE_MAX,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0\n            error(1) D0 D1 L0\n            error(1) D1\n        )MODEL\"));\n}\n\nTEST(find_undetectable_logical_error, hyper_error) {\n    ASSERT_EQ(\n        stim::find_undetectable_logical_error(\n            DetectorErrorModel(R\"MODEL(\n                error(0.1) D0 D1\n                error(0.1) D0 D1 D2 D3\n                error(0.1) D2 D3 D4 D5 L0\n                error(0.1) D4 D5 D6 D7\n                error(0.1) D6 D7 D8 D9\n                error(0.1) D8\n                error(0.1) D9\n            )MODEL\"),\n            4,\n            4,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(1) D0 D1\n            error(1) D0 D1 D2 D3\n            error(1) D2 D3 D4 D5 L0\n            error(1) D4 D5 D6 D7\n            error(1) D6 D7 D8 D9\n            error(1) D8\n            error(1) D9\n        )MODEL\"));\n}\n\nTEST(find_undetectable_logical_error, surface_code) {\n    CircuitGenParameters params(5, 5, \"rotated_memory_x\");\n    params.after_clifford_depolarization = 0.001;\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    params.before_round_data_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto graphlike_model =\n        ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, false, false, true);\n    auto ungraphlike_model =\n        ErrorAnalyzer::circuit_to_detector_error_model(circuit, false, true, false, false, false, true);\n\n    ASSERT_EQ(stim::find_undetectable_logical_error(graphlike_model, 4, 4, true).instructions.size(), 5);\n\n    ASSERT_EQ(stim::find_undetectable_logical_error(ungraphlike_model, 4, 4, true).instructions.size(), 5);\n}\n\nTEST(find_undetectable_logical_error, repetition_code) {\n    CircuitGenParameters params(10, 7, \"memory\");\n    params.before_round_data_depolarization = 0.01;\n    auto circuit = generate_rep_code_circuit(params).circuit;\n    auto graphlike_model = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);\n\n    ASSERT_EQ(stim::find_undetectable_logical_error(graphlike_model, 4, 4, false).instructions.size(), 7);\n}\n\nTEST(find_undetectable_logical_error, many_observables) {\n    Circuit circuit(R\"CIRCUIT(\n        MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4\n        X_ERROR(0.1) 0 1 2 3 4\n        MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4\n        DETECTOR rec[-1] rec[-5]\n        DETECTOR rec[-2] rec[-6]\n        DETECTOR rec[-3] rec[-7]\n        DETECTOR rec[-4] rec[-8]\n        M 4\n        OBSERVABLE_INCLUDE(1200) rec[-1]\n    )CIRCUIT\");\n    auto graphlike_model = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);\n    auto err = stim::find_undetectable_logical_error(graphlike_model, 4, 4, false);\n    ASSERT_EQ(err.instructions.size(), 5);\n}\n"
  },
  {
    "path": "src/stim/search/hyper/edge.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/edge.h\"\n\n#include <algorithm>\n#include <sstream>\n\nusing namespace stim;\nusing namespace stim::impl_search_hyper;\n\nstd::string Edge::str() const {\n    std::stringstream result;\n    result << *this;\n    return result.str();\n}\nbool Edge::operator==(const Edge &other) const {\n    return nodes == other.nodes && crossing_observable_mask == other.crossing_observable_mask;\n}\nbool Edge::operator!=(const Edge &other) const {\n    return !(*this == other);\n}\nstd::ostream &stim::impl_search_hyper::operator<<(std::ostream &out, const Edge &v) {\n    bool sep = false;\n    if (v.nodes.empty()) {\n        out << \"[silent]\";\n        sep = true;\n    } else if (v.nodes.size() == 1) {\n        out << \"[boundary]\";\n        sep = true;\n    }\n    for (const auto &t : v.nodes) {\n        if (sep) {\n            out << ' ';\n        }\n        sep = true;\n        out << \"D\" << t;\n    }\n    for (size_t k = 0; k < v.crossing_observable_mask.num_bits_padded(); k++) {\n        if (v.crossing_observable_mask[k]) {\n            if (sep) {\n                out << ' ';\n            }\n            sep = true;\n            out << \"L\" << k;\n        }\n    }\n    return out;\n}\n"
  },
  {
    "path": "src/stim/search/hyper/edge.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_HYPER_EDGE_H\n#define _STIM_SEARCH_HYPER_EDGE_H\n\n#include <cstdint>\n#include <iostream>\n#include <string>\n\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/mem/sparse_xor_vec.h\"\n\nnamespace stim {\n\nnamespace impl_search_hyper {\n\nstruct Edge {\n    SparseXorVec<uint64_t> nodes;\n    simd_bits<64> crossing_observable_mask;\n    std::string str() const;\n    bool operator==(const Edge &other) const;\n    bool operator!=(const Edge &other) const;\n};\nstd::ostream &operator<<(std::ostream &out, const Edge &v);\n\n}  // namespace impl_search_hyper\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/hyper/edge.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/edge.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_hyper;\n\nstatic simd_bits<64> obs_mask(uint64_t v) {\n    simd_bits<64> result(64);\n    result.ptr_simd[0] = v;\n    return result;\n}\n\nTEST(search_decay, Edge) {\n    Edge e1{{{}}, obs_mask(0)};\n    Edge e2{{{1}}, obs_mask(0)};\n    Edge e3{{{}}, obs_mask(1)};\n    Edge e4{{{1, 2}}, obs_mask(5)};\n    ASSERT_EQ(e1.str(), \"[silent]\");\n    ASSERT_EQ(e2.str(), \"[boundary] D1\");\n    ASSERT_EQ(e3.str(), \"[silent] L0\");\n    ASSERT_EQ(e4.str(), \"D1 D2 L0 L2\");\n\n    ASSERT_TRUE(e1 == e1);\n    ASSERT_TRUE(!(e1 == e2));\n    ASSERT_FALSE(e1 == e2);\n    ASSERT_FALSE(!(e1 == e1));\n\n    ASSERT_EQ(e1, (Edge{{{}}, obs_mask(0)}));\n    ASSERT_EQ(e2, e2);\n    ASSERT_EQ(e3, e3);\n    ASSERT_NE(e1, e3);\n}\n"
  },
  {
    "path": "src/stim/search/hyper/graph.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/graph.h\"\n\n#include <algorithm>\n#include <map>\n#include <queue>\n\nusing namespace stim;\nusing namespace stim::impl_search_hyper;\n\nstd::string Graph::str() const {\n    std::stringstream result;\n    result << *this;\n    return result.str();\n}\n\nvoid Graph::add_edge_from_dem_targets(SpanRef<const DemTarget> targets, size_t dont_explore_edges_with_degree_above) {\n    Edge edge{{}, simd_bits<64>(num_observables)};\n    for (const auto &t : targets) {\n        if (t.is_relative_detector_id()) {\n            edge.nodes.xor_item(t.val());\n        } else if (t.is_observable_id()) {\n            edge.crossing_observable_mask[t.val()] ^= true;\n        }\n    }\n    if (edge.nodes.size() > dont_explore_edges_with_degree_above) {\n        return;\n    }\n    if (edge.nodes.empty() && edge.crossing_observable_mask.not_zero()) {\n        distance_1_error_mask = edge.crossing_observable_mask;\n    }\n    for (const auto &n : edge.nodes) {\n        nodes[n].edges.push_back(edge);\n    }\n}\n\nGraph Graph::from_dem(const DetectorErrorModel &model, size_t dont_explore_edges_with_degree_above) {\n    Graph result(model.count_detectors(), model.count_observables());\n    model.iter_flatten_error_instructions([&](const DemInstruction &e) {\n        if (e.arg_data[0] != 0) {\n            result.add_edge_from_dem_targets(e.target_data, dont_explore_edges_with_degree_above);\n        }\n    });\n    return result;\n}\nbool Graph::operator==(const Graph &other) const {\n    return nodes == other.nodes && num_observables == other.num_observables &&\n           distance_1_error_mask == other.distance_1_error_mask;\n}\nbool Graph::operator!=(const Graph &other) const {\n    return !(*this == other);\n}\n\nGraph::Graph(size_t node_count, size_t num_observables)\n    : nodes(node_count), num_observables(num_observables), distance_1_error_mask(simd_bits<64>(num_observables)) {\n}\n\nGraph::Graph(std::vector<Node> nodes, size_t num_observables, simd_bits<64> distance_1_error_mask)\n    : nodes(std::move(nodes)),\n      num_observables(num_observables),\n      distance_1_error_mask(std::move(distance_1_error_mask)) {\n}\n\nstd::ostream &stim::impl_search_hyper::operator<<(std::ostream &out, const Graph &v) {\n    for (size_t k = 0; k < v.nodes.size(); k++) {\n        out << k << \":\\n\" << v.nodes[k];\n    }\n    return out;\n}\n"
  },
  {
    "path": "src/stim/search/hyper/graph.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_HYPER_GRAPH_H\n#define _STIM_SEARCH_HYPER_GRAPH_H\n\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/search/hyper/node.h\"\n\nnamespace stim {\n\nnamespace impl_search_hyper {\n\nstruct Graph {\n    std::vector<Node> nodes;\n    size_t num_observables;\n    simd_bits<64> distance_1_error_mask;\n\n    explicit Graph(size_t node_count, size_t num_observables);\n    Graph(std::vector<Node> nodes, size_t num_observables, simd_bits<64> distance_1_error_mask);\n\n    void add_edge_from_dem_targets(SpanRef<const DemTarget> targets, size_t dont_explore_edges_with_degree_above);\n    static Graph from_dem(const DetectorErrorModel &model, size_t dont_explore_edges_with_degree_above);\n    bool operator==(const Graph &other) const;\n    bool operator!=(const Graph &other) const;\n    std::string str() const;\n};\nstd::ostream &operator<<(std::ostream &out, const Graph &v);\n\n}  // namespace impl_search_hyper\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/hyper/graph.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/graph.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_hyper;\n\nstatic simd_bits<64> obs_mask(uint64_t v) {\n    simd_bits<64> result(64);\n    result.ptr_simd[0] = v;\n    return result;\n}\n\nTEST(search_hyper_graph, equality) {\n    ASSERT_TRUE(Graph(1, 64) == Graph(1, 64));\n    ASSERT_TRUE(Graph(1, 64) != Graph(2, 64));\n    ASSERT_TRUE(Graph(1, 64) != Graph(1, 32));\n    ASSERT_FALSE(Graph(1, 64) == Graph(2, 64));\n    ASSERT_FALSE(Graph(1, 64) != Graph(1, 64));\n\n    Graph a(1, 64);\n    Graph b(1, 64);\n    ASSERT_EQ(a, b);\n    b.distance_1_error_mask[0] = true;\n    ASSERT_NE(a, b);\n}\n\nTEST(search_hyper_graph, add_edge_from_dem_targets) {\n    Graph g(3, 64);\n    g.add_edge_from_dem_targets(DetectorErrorModel(\"error(0.01) D0 D1 L3 ^ D0\").instructions[0].target_data, SIZE_MAX);\n    ASSERT_EQ(\n        g,\n        (Graph{\n            std::vector<Node>{\n                Node{},\n                Node{{Edge{{{1}}, obs_mask(8)}}},\n                Node{},\n            },\n            64,\n            obs_mask(0)}));\n\n    g.add_edge_from_dem_targets(DetectorErrorModel(\"error(0.01) D0 D1 D2 L0\").instructions[0].target_data, SIZE_MAX);\n    ASSERT_EQ(\n        g,\n        (Graph{\n            std::vector<Node>{\n                Node{{Edge{{{0, 1, 2}}, obs_mask(1)}}},\n                Node{{Edge{{{1}}, obs_mask(8)}, Edge{{{0, 1, 2}}, obs_mask(1)}}},\n                Node{{Edge{{{0, 1, 2}}, obs_mask(1)}}},\n            },\n            64,\n            obs_mask(0)}));\n}\n\nTEST(search_hyper_graph, str) {\n    Graph g{\n        {\n            Node{},\n            Node{{Edge{{{1}}, obs_mask(0)}, Edge{{{1, 3}}, obs_mask(32)}}},\n            Node{},\n            Node{{Edge{{{1, 3}}, obs_mask(32)}}},\n        },\n        64,\n        obs_mask(0)};\n    ASSERT_EQ(\n        g.str(),\n        \"0:\\n\"\n        \"1:\\n\"\n        \"    [boundary] D1\\n\"\n        \"    D1 D3 L5\\n\"\n        \"2:\\n\"\n        \"3:\\n\"\n        \"    D1 D3 L5\\n\");\n}\n\nTEST(search_hyper_graph, from_dem) {\n    DetectorErrorModel dem(R\"MODEL(\n        error(0.1) D0\n        repeat 3 {\n            error(0.1) D0 D1\n            shift_detectors 1\n        }\n        error(0.1) D0 L7\n        error(0.1) D2 ^ D3 D4 L2\n        detector D5\n    )MODEL\");\n\n    ASSERT_EQ(\n        Graph::from_dem(dem, SIZE_MAX),\n        Graph(\n            {\n                Node{{Edge{{{0}}, obs_mask(0)}, Edge{{{0, 1}}, obs_mask(0)}}},\n                Node{{Edge{{{0, 1}}, obs_mask(0)}, Edge{{{1, 2}}, obs_mask(0)}}},\n                Node{{Edge{{{1, 2}}, obs_mask(0)}, Edge{{{2, 3}}, obs_mask(0)}}},\n                Node{{Edge{{{2, 3}}, obs_mask(0)}, Edge{{{3}}, obs_mask(128)}}},\n                Node{},\n                Node{{Edge{{{5, 6, 7}}, obs_mask(4)}}},\n                Node{{Edge{{{5, 6, 7}}, obs_mask(4)}}},\n                Node{{Edge{{{5, 6, 7}}, obs_mask(4)}}},\n                Node{},\n            },\n            8,\n            obs_mask(0)));\n\n    ASSERT_EQ(\n        Graph::from_dem(dem, 2),\n        Graph(\n            {\n                Node{{Edge{{{0}}, obs_mask(0)}, Edge{{{0, 1}}, obs_mask(0)}}},\n                Node{{Edge{{{0, 1}}, obs_mask(0)}, Edge{{{1, 2}}, obs_mask(0)}}},\n                Node{{Edge{{{1, 2}}, obs_mask(0)}, Edge{{{2, 3}}, obs_mask(0)}}},\n                Node{{Edge{{{2, 3}}, obs_mask(0)}, Edge{{{3}}, obs_mask(128)}}},\n                Node{},\n                Node{},\n                Node{},\n                Node{},\n                Node{},\n            },\n            8,\n            obs_mask(0)));\n    ASSERT_EQ(\n        Graph::from_dem(dem, 1),\n        Graph(\n            {\n                Node{{Edge{{{0}}, obs_mask(0)}}},\n                Node{},\n                Node{},\n                Node{{Edge{{{3}}, obs_mask(128)}}},\n                Node{},\n                Node{},\n                Node{},\n                Node{},\n                Node{},\n            },\n            8,\n            obs_mask(0)));\n}\n"
  },
  {
    "path": "src/stim/search/hyper/node.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/node.h\"\n\n#include <queue>\n#include <sstream>\n\nusing namespace stim;\nusing namespace stim::impl_search_hyper;\n\nstd::string Node::str() const {\n    std::stringstream result;\n    result << *this;\n    return result.str();\n}\n\nbool Node::operator==(const Node &other) const {\n    return edges == other.edges;\n}\n\nbool Node::operator!=(const Node &other) const {\n    return !(*this == other);\n}\n\nstd::ostream &stim::impl_search_hyper::operator<<(std::ostream &out, const Node &v) {\n    for (const auto &e : v.edges) {\n        out << \"    \" << e << \"\\n\";\n    }\n    return out;\n}\n"
  },
  {
    "path": "src/stim/search/hyper/node.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_HYPER_NODE_H\n#define _STIM_SEARCH_HYPER_NODE_H\n\n#include <vector>\n\n#include \"stim/search/hyper/edge.h\"\n\nnamespace stim {\n\nnamespace impl_search_hyper {\n\nstruct Node {\n    std::vector<Edge> edges;\n    std::string str() const;\n    bool operator==(const Node &other) const;\n    bool operator!=(const Node &other) const;\n};\nstd::ostream &operator<<(std::ostream &out, const Node &v);\n\n}  // namespace impl_search_hyper\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/hyper/node.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/node.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_hyper;\n\nstatic simd_bits<64> obs_mask(uint64_t v) {\n    simd_bits<64> result(64);\n    result.ptr_simd[0] = v;\n    return result;\n}\n\nTEST(search_decay, Node) {\n    Node n1{};\n    Node n2{{Edge{{{2}}, obs_mask(0)}}};\n    Node n3{{Edge{{{1, 3}}, obs_mask(5)}, Edge{{{3}}, obs_mask(8)}}};\n    ASSERT_EQ(n1.str(), \"\");\n    ASSERT_EQ(n2.str(), \"    [boundary] D2\\n\");\n    ASSERT_EQ(n3.str(), \"    D1 D3 L0 L2\\n    [boundary] D3 L3\\n\");\n\n    ASSERT_TRUE(n1 == n1);\n    ASSERT_TRUE(!(n1 == n2));\n    ASSERT_FALSE(n1 == n2);\n    ASSERT_FALSE(!(n1 == n1));\n\n    ASSERT_EQ(n1, (Node{}));\n    ASSERT_EQ(n2, n2);\n    ASSERT_EQ(n3, n3);\n    ASSERT_NE(n1, n3);\n}\n"
  },
  {
    "path": "src/stim/search/hyper/search_state.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/search_state.h\"\n\n#include <algorithm>\n\n#include \"stim/search/hyper/node.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_hyper;\n\nstd::string SearchState::str() const {\n    std::stringstream result;\n    result << *this;\n    return result.str();\n}\n\nvoid SearchState::append_transition_as_error_instruction_to(const SearchState &other, DetectorErrorModel &out) const {\n    // Extract detector indices while cancelling duplicates.\n    SparseXorVec<uint64_t> dif = dets ^ other.dets;\n    for (const auto &n : dif) {\n        out.target_buf.append_tail(DemTarget::relative_detector_id(n));\n    }\n\n    // Extract logical observable indices.\n    auto dif_mask = obs_mask ^ other.obs_mask;\n    for (size_t k = 0; k < dif_mask.num_bits_padded(); k++) {\n        if (dif_mask[k]) {\n            out.target_buf.append_tail(DemTarget::observable_id(k));\n        }\n    }\n\n    // Default probability to 1.\n    out.arg_buf.append_tail(1);\n\n    out.instructions.push_back(\n        DemInstruction{\n            .arg_data = out.arg_buf.commit_tail(),\n            .target_data = out.target_buf.commit_tail(),\n            .tag = \"\",\n            .type = DemInstructionType::DEM_ERROR,\n        });\n}\n\nbool SearchState::operator==(const SearchState &other) const {\n    return dets == other.dets && obs_mask == other.obs_mask;\n}\nbool SearchState::operator!=(const SearchState &other) const {\n    return !(*this == other);\n}\n\nbool SearchState::operator<(const SearchState &other) const {\n    if (dets != other.dets) {\n        return dets < other.dets;\n    }\n    return obs_mask < other.obs_mask;\n}\n\nstd::ostream &stim::impl_search_hyper::operator<<(std::ostream &out, const SearchState &v) {\n    if (v.dets.empty()) {\n        out << \"[no symptoms] \";\n    } else {\n        for (const auto &d : v.dets) {\n            out << \"D\" << d << \" \";\n        }\n    }\n\n    for (size_t k = 0; k < v.obs_mask.num_bits_padded(); k++) {\n        if (v.obs_mask[k]) {\n            out << \"L\" << k << \" \";\n        }\n    }\n\n    return out;\n}\n"
  },
  {
    "path": "src/stim/search/hyper/search_state.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_HYPER_SEARCH_STATE_H\n#define _STIM_SEARCH_HYPER_SEARCH_STATE_H\n\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/mem/sparse_xor_vec.h\"\n\nnamespace stim {\n\nnamespace impl_search_hyper {\n\nstruct SearchState {\n    SparseXorVec<uint64_t> dets;\n    simd_bits<64> obs_mask;\n\n    void append_transition_as_error_instruction_to(const SearchState &other, DetectorErrorModel &out) const;\n    bool operator==(const SearchState &other) const;\n    bool operator!=(const SearchState &other) const;\n    bool operator<(const SearchState &other) const;\n    std::string str() const;\n};\nstd::ostream &operator<<(std::ostream &out, const SearchState &v);\n\n}  // namespace impl_search_hyper\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/hyper/search_state.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/hyper/search_state.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/search/hyper/node.h\"\n\nusing namespace stim;\nusing namespace stim::impl_search_hyper;\n\nstatic simd_bits<64> obs_mask(uint64_t v) {\n    simd_bits<64> result(64);\n    result.ptr_simd[0] = v;\n    return result;\n}\n\nTEST(search_hyper_search_state, append_transition_as_error_instruction_to) {\n    DetectorErrorModel out;\n\n    SearchState{{{1, 2}}, obs_mask(9)}.append_transition_as_error_instruction_to(\n        SearchState{{{1, 2}}, obs_mask(16)}, out);\n    ASSERT_EQ(out, DetectorErrorModel(R\"MODEL(\n        error(1) L0 L3 L4\n    )MODEL\"));\n\n    SearchState{{{}}, obs_mask(9)}.append_transition_as_error_instruction_to(\n        SearchState{{{1, 2, 4}}, obs_mask(16)}, out);\n    ASSERT_EQ(out, DetectorErrorModel(R\"MODEL(\n        error(1) L0 L3 L4\n        error(1) D1 D2 D4 L0 L3 L4\n    )MODEL\"));\n\n    SearchState{{{1, 2}}, obs_mask(9)}.append_transition_as_error_instruction_to(\n        SearchState{{{2, 3}}, obs_mask(9)}, out);\n    ASSERT_EQ(out, DetectorErrorModel(R\"MODEL(\n        error(1) L0 L3 L4\n        error(1) D1 D2 D4 L0 L3 L4\n        error(1) D1 D3\n    )MODEL\"));\n}\n\nTEST(search_hyper_search_state, equality) {\n    SearchState v1{{{1, 2}}, obs_mask(3)};\n    SearchState v2{{{1, 4}}, obs_mask(3)};\n    ASSERT_TRUE(v1 == v1);\n    ASSERT_FALSE(v1 == v2);\n    ASSERT_FALSE(v1 != v1);\n    ASSERT_TRUE(v1 != v2);\n\n    ASSERT_NE(v1, (SearchState{{{1}}, obs_mask(3)}));\n    ASSERT_NE(v1, (SearchState{{{1, 2}}, obs_mask(4)}));\n}\n\nTEST(search_hyper_search_state, ordering) {\n    ASSERT_TRUE((SearchState{{{1}}, obs_mask(999)}) < (SearchState{{{1, 2}}, obs_mask(999)}));\n    ASSERT_TRUE((SearchState{{{1, 999}}, obs_mask(999)}) < (SearchState{{{101, 102}}, obs_mask(103)}));\n    ASSERT_TRUE((SearchState{{{1, 999}}, obs_mask(999)}) < (SearchState{{{101, 102}}, obs_mask(103)}));\n    ASSERT_TRUE((SearchState{{{1, 101}}, obs_mask(999)}) < (SearchState{{{101, 102}}, obs_mask(103)}));\n    ASSERT_TRUE((SearchState{{{1, 102}}, obs_mask(999)}) < (SearchState{{{101, 102}}, obs_mask(103)}));\n    ASSERT_TRUE((SearchState{{{101, 102}}, obs_mask(3)}) < (SearchState{{{101, 102}}, obs_mask(103)}));\n\n    ASSERT_FALSE((SearchState{{{101, 102}}, obs_mask(103)}) < (SearchState{{{101, 102}}, obs_mask(103)}));\n    ASSERT_FALSE((SearchState{{{101, 104}}, obs_mask(103)}) < (SearchState{{{101, 102}}, obs_mask(103)}));\n    ASSERT_FALSE((SearchState{{{101, 102}}, obs_mask(104)}) < (SearchState{{{101, 102}}, obs_mask(103)}));\n}\n\nTEST(search_hyper_search_state, str) {\n    ASSERT_EQ((SearchState{{{1, 2}}, obs_mask(3)}.str()), \"D1 D2 L0 L1 \");\n}\n"
  },
  {
    "path": "src/stim/search/sat/wcnf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/search/sat/wcnf.h\"\n\nusing namespace stim;\n\ntypedef double Weight;\nconstexpr Weight HARD_CLAUSE_WEIGHT = -1.0;\n\nconst std::string UNSAT_WCNF_STR = \"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\";\n\nconstexpr size_t BOOL_LITERAL_FALSE = SIZE_MAX - 1;\nconstexpr size_t BOOL_LITERAL_TRUE = SIZE_MAX;\n\nstruct BoolRef {\n    size_t variable = BOOL_LITERAL_FALSE;\n    bool negated = false;\n    BoolRef operator~() const {\n        return {variable, !negated};\n    }\n    static BoolRef False() {\n        return {BOOL_LITERAL_FALSE, false};\n    }\n    static BoolRef True() {\n        return {BOOL_LITERAL_TRUE, false};\n    }\n};\n\nstruct Clause {\n    std::vector<BoolRef> vars;\n    Weight weight = HARD_CLAUSE_WEIGHT;\n    void add_var(BoolRef x) {\n        vars.push_back(x);\n    }\n};\n\nstruct MaxSATInstance {\n    size_t num_variables = 0;\n    Weight max_weight = 0;\n    std::vector<Clause> clauses;\n    BoolRef new_bool() {\n        return {num_variables++};\n    }\n    void add_clause(Clause &clause) {\n        if (clause.weight != HARD_CLAUSE_WEIGHT) {\n            if (clause.weight <= 0) {\n                throw std::invalid_argument(\"Clauses must have positive weight or HARD_CLAUSE_WEIGHT.\");\n            }\n            max_weight = std::max(max_weight, clause.weight);\n        }\n        clauses.push_back(clause);\n    }\n    BoolRef Xor(BoolRef &x, BoolRef &y) {\n        if (x.variable == BOOL_LITERAL_FALSE) {\n            return y;\n        }\n        if (x.variable == BOOL_LITERAL_TRUE) {\n            return ~y;\n        }\n        if (y.variable == BOOL_LITERAL_FALSE) {\n            return x;\n        }\n        if (y.variable == BOOL_LITERAL_TRUE) {\n            return ~x;\n        }\n        BoolRef z = new_bool();\n        // Forbid strings (x, y, z) such that z != XOR(x, y)\n        {\n            Clause clause;\n            // hard clause (x, y, z) != (0, 0, 1)\n            clause.add_var(x);\n            clause.add_var(y);\n            clause.add_var(~z);\n            add_clause(clause);\n        }\n        {\n            Clause clause;\n            // hard clause (x, y, z) != (0, 1, 0)\n            clause.add_var(x);\n            clause.add_var(~y);\n            clause.add_var(z);\n            add_clause(clause);\n        }\n        {\n            Clause clause;\n            // hard clause (x, y, z) != (1, 0, 0)\n            clause.add_var(~x);\n            clause.add_var(y);\n            clause.add_var(z);\n            add_clause(clause);\n        }\n        {\n            Clause clause;\n            // hard clause (x, y, z) != (1, 1, 1)\n            clause.add_var(~x);\n            clause.add_var(~y);\n            clause.add_var(~z);\n            add_clause(clause);\n        }\n        return z;\n    }\n\n    size_t quantized_weight(bool weighted, size_t quantization, size_t top, Weight weight) {\n        if (weight == HARD_CLAUSE_WEIGHT) {\n            // Hard clause\n            return top;\n        }\n        // Soft clause\n        if (!weighted) {\n            // For unweighted problems, all soft clauses have weight 1.\n            return 1;\n        }\n        return std::round(weight / max_weight * (double)quantization);\n    }\n\n    std::string to_wdimacs(bool weighted, size_t quantization) {\n        // 'top' is a special weight used to indicate a hard clause.\n        // Should be at least the sum of the weights of all soft clauses plus 1.\n        size_t top;\n        if (weighted) {\n            top = 1 + quantization * clauses.size();\n        } else {\n            top = 1 + clauses.size();\n        }\n\n        // WDIMACS header format: p wcnf nbvar nbclauses top\n        // see http://www.maxhs.org/docs/wdimacs.html\n        std::stringstream ss;\n        ss << \"p wcnf \" << num_variables << \" \" << clauses.size() << \" \" << top << \"\\n\";\n\n        // Add clauses, 1 on each line.\n        for (const auto &clause : clauses) {\n            // WDIMACS clause format: weight var1 var2 ...\n            // To show negation of a variable, the index should be negated.\n            size_t qw = quantized_weight(weighted, quantization, top, clause.weight);\n            // There is no need to add a clause with zero weight.\n            // This can happen if the error has probability 0.5 or if the quantization is too\n            // small to accomodate the entire dynamic range of weight values.\n            if (qw == 0)\n                continue;\n            ss << qw;\n            for (size_t i = 0; i < clause.vars.size(); ++i) {\n                BoolRef var = clause.vars[i];\n                // Variables are 1-indexed\n                if (var.negated) {\n                    ss << \" -\" << (var.variable + 1);\n                } else {\n                    ss << \" \" << (var.variable + 1);\n                }\n            }\n            // Each clause ends with 0\n            ss << \" 0\\n\";\n        }\n        return ss.str();\n    }\n};\n\nstd::string sat_problem_as_wcnf_string(const DetectorErrorModel &model, bool weighted, size_t quantization) {\n    MaxSATInstance inst;\n\n    if (weighted and quantization < 1) {\n        throw std::invalid_argument(\"for weighted problems, quantization must be >= 1\");\n    }\n    if (!weighted and quantization != 0) {\n        throw std::invalid_argument(\"for unweighted problems, quantization must be == 0\");\n    }\n\n    size_t num_observables = model.count_observables();\n    size_t num_detectors = model.count_detectors();\n    size_t num_errors = model.count_errors();\n    if (num_observables == 0 or num_errors == 0) {\n        return UNSAT_WCNF_STR;\n    }\n\n    MaxSATInstance instance;\n    // Create a boolean variable for each error, which indicates whether it is activated.\n    std::vector<BoolRef> errors_activated;\n    for (size_t i = 0; i < num_errors; ++i) {\n        errors_activated.push_back(instance.new_bool());\n    }\n\n    std::vector<BoolRef> detectors_activated(num_detectors, BoolRef::False());\n    std::vector<BoolRef> observables_flipped(num_observables, BoolRef::False());\n\n    size_t error_index = 0;\n    model.iter_flatten_error_instructions([&](const DemInstruction &e) {\n        if (!weighted or e.arg_data[0] != 0) {\n            BoolRef err_x = errors_activated[error_index];\n            // Add parity contribution to the detectors and observables\n            for (const auto &t : e.target_data) {\n                if (t.is_relative_detector_id()) {\n                    detectors_activated[t.val()] = instance.Xor(detectors_activated[t.val()], err_x);\n                } else if (t.is_observable_id()) {\n                    observables_flipped[t.val()] = instance.Xor(observables_flipped[t.val()], err_x);\n                }\n            }\n            // Add a soft clause for this error\n            Clause clause;\n            double p = e.arg_data[0];\n            if (weighted) {\n                // Weighted search\n                if (p < 0.5) {\n                    // If the probability < 0.5, the weight should be positive\n                    // and we add the clause for the error to be inactive.\n                    clause.add_var(~err_x);\n                    clause.weight = -std::log(p / (1 - p));\n                    instance.add_clause(clause);\n                } else if (p == 0.5) {\n                    // If the probability == 0.5, the error can be included \"for free\"\n                    // so we don't bother adding any soft clause.\n                } else {\n                    // If the probability is > 0.5, the cost is negative so we emulate this by\n                    // inverting the sign of the weight and negating the clause so that the\n                    // clause has a positive weight.\n                    clause.add_var(err_x);\n                    clause.weight = -std::log((1 - p) / p);\n                    instance.add_clause(clause);\n                }\n            } else {\n                // For unweighted search the error should be soft clause should be that\n                // the error is inactive.\n                clause.add_var(~err_x);\n                clause.weight = 1.0;\n                instance.add_clause(clause);\n            }\n        }\n        ++error_index;\n    });\n    assert(error_index == num_errors);\n\n    // Add a hard clause for each detector to be inactive\n    for (size_t d = 0; d < num_detectors; ++d) {\n        Clause clause;\n        if (detectors_activated[d].variable == BOOL_LITERAL_FALSE)\n            continue;\n        clause.add_var(~detectors_activated[d]);\n        instance.add_clause(clause);\n    }\n\n    // Add a hard clause for any observable to be flipped\n    Clause clause;\n    for (size_t i = 0; i < num_observables; ++i) {\n        clause.add_var(observables_flipped[i]);\n    }\n    instance.add_clause(clause);\n\n    return instance.to_wdimacs(weighted, quantization);\n}\n\n// Should ignore weights entirely and minimize the cardinality.\nstd::string stim::shortest_error_sat_problem(const DetectorErrorModel &model, std::string_view format) {\n    if (format != \"WDIMACS\") {\n        throw std::invalid_argument(\"Unsupported format.\");\n    }\n    return sat_problem_as_wcnf_string(model, /*weighted=*/false, /*quantization=*/0);\n}\n\nstd::string stim::likeliest_error_sat_problem(\n    const DetectorErrorModel &model, int quantization, std::string_view format) {\n    if (format != \"WDIMACS\") {\n        throw std::invalid_argument(\"Unsupported format.\");\n    }\n    if (quantization < 1) {\n        throw std::invalid_argument(\"Must have quantization >= 1\");\n    }\n    return sat_problem_as_wcnf_string(model, /*weighted=*/true, quantization);\n}\n"
  },
  {
    "path": "src/stim/search/sat/wcnf.h",
    "content": "#ifndef _STIM_SEARCH_SAT_WCNF_H\n#define _STIM_SEARCH_SAT_WCNF_H\n\n#include \"stim/dem/detector_error_model.h\"\n\nnamespace stim {\n\n/// Generates a maxSAT problem instance in .wcnf format from a DetectorErrorModel, such that the optimal value of the\n/// instance corresponds to the minimum distance of the protocol.\n///\n/// The .wcnf (weighted CNF) file format is widely\n/// accepted by numerous maxSAT solvers. For example, the solvers in the 2023 maxSAT competition:\n/// https://maxsat-evaluations.github.io/2023/descriptions.html Note that erformance can greatly vary among solvers. The\n/// conversion involves encoding XOR constraints into CNF clauses using standard techniques.\n///\n/// Args:\n///     model: The detector error model to be converted into .wcnf format for minimum distance calculation.\n///     weighted: (default = false) If false, all errors have cost 1. If true, errors are given a cost based\n///               on their likelihood cost scaled by the weight scale factor divided by the maximum cost value.\n///               if false, must set weight_scale_factor to 0. If true, must set weight_scale_factor >= 1.\n///     weight_scale_factor: The scaling factor used for quantization. (default = 0 for unweighted).\n///\n/// Returns:\n///     A string which is interpreted as the contents of a .wcnf file. This should be written to a file which can then\n///     be passed to various maxSAT solvers to determine the minimum distance of the protocol represented by the model.\n///     The optimal value found by the solver corresponds to the minimum distance of the error correction protocol. In\n///     other words, the smallest number of errors that cause a logical observable flip without any detection events.\n///\n/// Note:\n///     The use of .wcnf format offers significant flexibility in choosing a maxSAT solver, but it also means that\n///     users must separately manage the process of selecting and running the solver. This approach is designed to\n///     sidestep the need for direct integration with any particular solver and allow\n///     for experimentation with different solvers to achieve the best performance.\n\nstd::string shortest_error_sat_problem(const DetectorErrorModel &model, std::string_view format = \"WDIMACS\");\n\nstd::string likeliest_error_sat_problem(\n    const DetectorErrorModel &model, int quantization = 10, std::string_view format = \"WDIMACS\");\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/search/sat/wcnf.test.cc",
    "content": "#include \"stim/search/sat/wcnf.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nconst std::string unsatisfiable_wdimacs = \"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\";\n\nTEST(shortest_error_sat_problem, no_error) {\n    // No errors. Should get an unsatisfiable formula.\n    ASSERT_EQ(stim::shortest_error_sat_problem(DetectorErrorModel()), \"p wcnf 1 2 3\\n3 -1 0\\n3 1 0\\n\");\n}\n\nTEST(shortest_error_sat_problem, single_obs_no_dets) {\n    std::string wcnf = stim::shortest_error_sat_problem(DetectorErrorModel(R\"DEM(\n        error(0.1) L0\n    )DEM\"));\n    EXPECT_EQ(\n        wcnf,\n        R\"WDIMACS(p wcnf 1 2 3\n1 -1 0\n3 1 0\n)WDIMACS\");\n}\n\nTEST(shortest_error_sat_problem, single_dets_no_obs) {\n    std::string wcnf = stim::shortest_error_sat_problem(DetectorErrorModel(R\"DEM(\n        error(0.1) D0\n    )DEM\"));\n    EXPECT_EQ(wcnf, unsatisfiable_wdimacs);\n}\n\nTEST(shortest_error_sat_problem, no_dets_no_obs) {\n    std::string wcnf = stim::shortest_error_sat_problem(DetectorErrorModel(R\"DEM(\n        error(0.1)\n    )DEM\"));\n    EXPECT_EQ(wcnf, unsatisfiable_wdimacs);\n}\n\nTEST(shortest_error_sat_problem, no_errors) {\n    std::string wcnf = stim::shortest_error_sat_problem(DetectorErrorModel(R\"DEM()DEM\"));\n    EXPECT_EQ(wcnf, unsatisfiable_wdimacs);\n}\n\nTEST(shortest_error_sat_problem, single_detector_single_observable) {\n    // To test that it ignores weights entirely, we try several combinations of weights.\n    for (std::string dem_str : {\n             R\"DEM(\n            error(0.1) D0 L0\n            error(0.1) D0\n        )DEM\",\n             R\"DEM(\n            error(1.0) D0 L0\n            error(0) D0\n        )DEM\",\n             R\"DEM(\n            error(0.5) D0 L0\n            error(0.999) D0\n        )DEM\",\n             R\"DEM(\n            error(0.001) D0 L0\n            error(0.999) D0\n        )DEM\",\n             R\"DEM(\n            error(0) D0 L0\n            error(0) D0\n        )DEM\",\n             R\"DEM(\n            error(0.5) D0 L0\n            error(0.5) D0\n        )DEM\"}) {\n        std::string wcnf = stim::shortest_error_sat_problem(DetectorErrorModel(dem_str.c_str()));\n        // x_0 -- error 0 occurred\n        // x_1 -- error 1 occurred\n        // x_2 -- XOR of x_0 and x_1\n        // There should be 2 soft clauses:\n        // soft clause NOT(x_0) with weight 1\n        // soft clause NOT(x_0) with weight 1\n        // There should be 4 hard clauses to forbid the strings such that x_2 != XOR(x_0, x_1):\n        // hard clause x != (0, 0, 1)\n        // hard clause x != (0, 1, 0)\n        // hard clause x != (1, 0, 0)\n        // hard clause x != (1, 1, 1)\n        // Plus 1 hard clause to ensure detector is not flipped\n        // hard clause -x_2\n        // Plus 1 hard clause to ensure an observable is flipped:\n        // hard clause x_0\n        // This gives a total of 8 clauses\n        // The top value should be at least 1 + 1 + 1 = 3. In our implementation ends up being 9.\n        std::stringstream expected;\n        // WDIMACS header format: p wcnf nbvar nbclauses top\n        expected << \"p wcnf 3 8 9\\n\";\n        // Soft clause\n        expected << \"1 -1 0\\n\";\n        // Hard clauses\n        expected << \"9 1 2 -3 0\\n\";\n        expected << \"9 1 -2 3 0\\n\";\n        expected << \"9 -1 2 3 0\\n\";\n        expected << \"9 -1 -2 -3 0\\n\";\n        // Soft clause\n        expected << \"1 -2 0\\n\";\n        // Hard clause for the detector not to be flipped\n        expected << \"9 -3 0\\n\";\n        // Hard clause for the observable flipped\n        expected << \"9 1 0\\n\";\n        ASSERT_EQ(wcnf, expected.str());\n        // The optimal value of this wcnf file should be 2, but we don't have\n        // a maxSAT solver to be able to test it here.\n    }\n}\n\nTEST(likeliest_error_sat_problem, no_error) {\n    // No errors. Should get an unsatisfiable formula.\n    ASSERT_EQ(stim::likeliest_error_sat_problem(DetectorErrorModel()), unsatisfiable_wdimacs);\n}\n\nTEST(likeliest_error_sat_problem, single_detector_single_observable) {\n    std::string wcnf = stim::likeliest_error_sat_problem(DetectorErrorModel(R\"DEM(\n      error(0.1) D0 L0\n      error(0.1) D0\n    )DEM\"));\n    // There should be 3 variables: x = (x_0, x_1, x_2)\n    // x_0 -- error 0 occurred\n    // x_1 -- error 1 occurred\n    // x_2 -- XOR of x_0 and x_1\n    // There should be 2 soft clauses:\n    // soft clause NOT(x_0) with weight 1\n    // soft clause NOT(x_0) with weight 1\n    // There should be 4 hard clauses to forbid the strings such that x_2 != XOR(x_0, x_1):\n    // hard clause x != (0, 0, 1)\n    // hard clause x != (0, 1, 0)\n    // hard clause x != (1, 0, 0)\n    // hard clause x != (1, 1, 1)\n    // Plus 1 hard clause to ensure detector is not flipped\n    // hard clause -x_2\n    // Plus 1 hard clause to ensure an observable is flipped:\n    // hard clause x_0\n    // This gives a total of 8 clauses\n    // The top value should be at least 1 + 1 + 1 = 3. In our implementation ends up being 9.\n    std::stringstream expected;\n    // WDIMACS header format: p wcnf nbvar nbclauses top\n    expected << \"p wcnf 3 8 81\\n\";\n    // Soft clause\n    expected << \"10 -1 0\\n\";\n    // Hard clauses\n    expected << \"81 1 2 -3 0\\n\";\n    expected << \"81 1 -2 3 0\\n\";\n    expected << \"81 -1 2 3 0\\n\";\n    expected << \"81 -1 -2 -3 0\\n\";\n    // Soft clause\n    expected << \"10 -2 0\\n\";\n    // Hard clause for the detector not to be flipped\n    expected << \"81 -3 0\\n\";\n    // Hard clause for the observable flipped\n    expected << \"81 1 0\\n\";\n    ASSERT_EQ(wcnf, expected.str());\n    // The optimal value of this wcnf file should be 20, but we don't have\n    // a maxSAT solver to be able to test it here.\n}\n\nTEST(likeliest_error_sat_problem, single_detector_single_observable_large_probability) {\n    std::string wcnf = stim::likeliest_error_sat_problem(DetectorErrorModel(R\"DEM(\n      error(0.1) D0 L0\n      error(0.9) D0\n    )DEM\"));\n    // There should be 3 variables: x = (x_0, x_1, x_2)\n    // x_0 -- error 0 occurred\n    // x_1 -- error 1 occurred\n    // x_2 -- XOR of x_0 and x_1\n    // There should be 2 soft clauses:\n    // soft clause NOT(x_0) with weight 1\n    // soft clause NOT(x_0) with weight 1\n    // There should be 4 hard clauses to forbid the strings such that x_2 != XOR(x_0, x_1):\n    // hard clause x != (0, 0, 1)\n    // hard clause x != (0, 1, 0)\n    // hard clause x != (1, 0, 0)\n    // hard clause x != (1, 1, 1)\n    // Plus 1 hard clause to ensure detector is not flipped\n    // hard clause -x_2\n    // Plus 1 hard clause to ensure an observable is flipped:\n    // hard clause x_0\n    // This gives a total of 8 clauses\n    // The top value should be at least 1 + 1 + 1 = 3. In our implementation ends up being 9.\n    std::stringstream expected;\n    // WDIMACS header format: p wcnf nbvar nbclauses top\n    expected << \"p wcnf 3 8 81\\n\";\n    // Soft clause\n    expected << \"10 -1 0\\n\";\n    // Hard clauses\n    expected << \"81 1 2 -3 0\\n\";\n    expected << \"81 1 -2 3 0\\n\";\n    expected << \"81 -1 2 3 0\\n\";\n    expected << \"81 -1 -2 -3 0\\n\";\n    // Soft clause for the 2nd error to flip, with weight 10.\n    // This is because the probability of that error is 0.9.\n    expected << \"10 2 0\\n\";\n    // Hard clause for the detector not to be flipped\n    expected << \"81 -3 0\\n\";\n    // Hard clause for the observable flipped\n    expected << \"81 1 0\\n\";\n    ASSERT_EQ(wcnf, expected.str());\n    // The optimal value of this wcnf file should be 20, but we don't have\n    // a maxSAT solver to be able to test it here.\n}\n\nTEST(likeliest_error_sat_problem, single_detector_single_observable_half_probability) {\n    std::string wcnf = stim::likeliest_error_sat_problem(DetectorErrorModel(R\"DEM(\n      error(0.1) D0 L0\n      error(0.5) D0\n    )DEM\"));\n    // There should be 3 variables: x = (x_0, x_1, x_2)\n    // x_0 -- error 0 occurred\n    // x_1 -- error 1 occurred\n    // x_2 -- XOR of x_0 and x_1\n    // There should be 2 soft clauses:\n    // soft clause NOT(x_0) with weight 1\n    // soft clause NOT(x_0) with weight 1\n    // There should be 4 hard clauses to forbid the strings such that x_2 != XOR(x_0, x_1):\n    // hard clause x != (0, 0, 1)\n    // hard clause x != (0, 1, 0)\n    // hard clause x != (1, 0, 0)\n    // hard clause x != (1, 1, 1)\n    // Plus 1 hard clause to ensure detector is not flipped\n    // hard clause -x_2\n    // Plus 1 hard clause to ensure an observable is flipped:\n    // hard clause x_0\n    // This gives a total of 8 clauses\n    // The top value should be at least 1 + 1 + 1 = 3. In our implementation ends up being 9.\n    std::stringstream expected;\n    // WDIMACS header format: p wcnf nbvar nbclauses top\n    expected << \"p wcnf 3 7 71\\n\";\n    // Soft clause\n    expected << \"10 -1 0\\n\";\n    // Hard clauses\n    expected << \"71 1 2 -3 0\\n\";\n    expected << \"71 1 -2 3 0\\n\";\n    expected << \"71 -1 2 3 0\\n\";\n    expected << \"71 -1 -2 -3 0\\n\";\n    // // Soft clause for the 2nd error to flip, with weight 10.\n    // // This is because the probability of that error is 0.9.\n    // expected << \"10 2 0\\n\";\n    // Hard clause for the detector not to be flipped\n    expected << \"71 -3 0\\n\";\n    // Hard clause for the observable flipped\n    expected << \"71 1 0\\n\";\n    ASSERT_EQ(wcnf, expected.str());\n    // The optimal value of this wcnf file should be 20, but we don't have\n    // a maxSAT solver to be able to test it here.\n}\n"
  },
  {
    "path": "src/stim/search/search.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SEARCH_SEARCH_H\n#define _STIM_SEARCH_SEARCH_H\n\n#include \"stim/search/graphlike/algo.h\"\n#include \"stim/search/hyper/algo.h\"\n#include \"stim/search/sat/wcnf.h\"\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/README.md",
    "content": "# `simulators` directory\n\nThis directory contains various quantum circuit simulators, which package up disparate functionality\nfrom elsewhere in the codebase into useful objects.\n"
  },
  {
    "path": "src/stim/simulators/dem_sampler.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_DEM_SAMPLER_H\n#define _STIM_SIMULATORS_DEM_SAMPLER_H\n\n#include <random>\n\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/mem/simd_bit_table.h\"\n\nnamespace stim {\n\n/// Performs high performance bulk sampling of a detector error model.\n///\n/// The template parameter, W, represents the SIMD width\ntemplate <size_t W>\nstruct DemSampler {\n    DetectorErrorModel model;\n    uint64_t num_detectors;\n    uint64_t num_observables;\n    uint64_t num_errors;\n    std::mt19937_64 rng;\n    // TODO: allow these buffers to be streamed instead of entirely stored in memory.\n    simd_bit_table<W> det_buffer;\n    simd_bit_table<W> obs_buffer;\n    simd_bit_table<W> err_buffer;\n    size_t num_stripes;\n\n    /// Compiles a sampler for the given detector error model.\n    DemSampler(DetectorErrorModel model, std::mt19937_64 &&rng, size_t min_stripes);\n\n    /// Clears the buffers and refills them with sampled shot data.\n    void resample(bool replay_errors);\n\n    /// Ensures the internal buffers are sized for a given number of shots.\n    void set_min_stripes(size_t min_stripes);\n\n    /// Samples from the dem, writing results to files.\n    ///\n    /// Args:\n    ///     num_shots: The number of samples to take.\n    ///     det_out: Where to write detection event data. Set to nullptr to not write detection event data.\n    ///     det_out_format: The format to write detection event data in.\n    ///     obs_out: Where to write observable data. Set to nullptr to not write observable data.\n    ///     obs_out_format: The format to write observable data in.\n    ///     err_out: Where to write recorded error data. Set to nullptr to not write recorded error data.\n    ///     err_out_format: The format to write error data in.\n    ///     replay_err_in: If this argument is given a non-null file, error data will be read from that file\n    ///         and replayed (instead of generating new errors randomly).\n    ///     replay_err_in_format: The format to read recorded error data to replay in.\n    void sample_write(\n        size_t num_shots,\n        FILE *det_out,\n        SampleFormat det_out_format,\n        FILE *obs_out,\n        SampleFormat obs_out_format,\n        FILE *err_out,\n        SampleFormat err_out_format,\n        FILE *replay_err_in,\n        SampleFormat replay_err_in_format);\n};\n\n}  // namespace stim\n\n#include \"stim/simulators/dem_sampler.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/dem_sampler.inl",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include <algorithm>\n\n#include \"stim/io/measure_record_reader.h\"\n#include \"stim/io/measure_record_writer.h\"\n#include \"stim/simulators/dem_sampler.h\"\n#include \"stim/util_bot/probability_util.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nDemSampler<W>::DemSampler(DetectorErrorModel init_model, std::mt19937_64 &&rng, size_t min_stripes)\n    : model(std::move(init_model)),\n      num_detectors(model.count_detectors()),\n      num_observables(model.count_observables()),\n      num_errors(model.count_errors()),\n      rng(rng),\n      det_buffer((size_t)num_detectors, min_stripes),\n      obs_buffer((size_t)num_observables, min_stripes),\n      err_buffer((size_t)num_errors, min_stripes),\n      num_stripes(det_buffer.num_minor_bits_padded()) {\n}\n\ntemplate <size_t W>\nvoid DemSampler<W>::set_min_stripes(size_t min_stripes) {\n    size_t new_num_stripes = min_bits_to_num_bits_padded<W>(min_stripes);\n    if (new_num_stripes == num_stripes) {\n        return;\n    }\n    det_buffer = simd_bit_table<W>((size_t)num_detectors, min_stripes),\n    obs_buffer = simd_bit_table<W>((size_t)num_observables, min_stripes),\n    err_buffer = simd_bit_table<W>((size_t)num_errors, min_stripes), num_stripes = new_num_stripes;\n}\n\ntemplate <size_t W>\nvoid DemSampler<W>::resample(bool replay_errors) {\n    det_buffer.clear();\n    obs_buffer.clear();\n    if (!replay_errors) {\n        err_buffer.clear();\n    }\n    size_t error_index = 0;\n    model.iter_flatten_error_instructions([&](const DemInstruction &op) {\n        simd_bits_range_ref<W> err_row = err_buffer[error_index];\n        if (!replay_errors) {\n            biased_randomize_bits((float)op.arg_data[0], err_row.u64, err_row.u64 + err_row.num_u64_padded(), rng);\n        }\n        for (const auto &t : op.target_data) {\n            if (t.is_relative_detector_id()) {\n                det_buffer[(size_t)t.raw_id()] ^= err_row;\n            } else if (t.is_observable_id()) {\n                obs_buffer[(size_t)t.raw_id()] ^= err_row;\n            }\n        }\n        error_index++;\n    });\n}\n\ntemplate <size_t W>\nvoid DemSampler<W>::sample_write(\n    size_t num_shots,\n    FILE *det_out,\n    SampleFormat det_out_format,\n    FILE *obs_out,\n    SampleFormat obs_out_format,\n    FILE *err_out,\n    SampleFormat err_out_format,\n    FILE *err_in,\n    SampleFormat err_in_format) {\n    for (size_t k = 0; k < num_shots; k += num_stripes) {\n        size_t shots_left = std::min(num_stripes, num_shots - k);\n\n        if (err_in != nullptr) {\n            size_t errors_read = read_file_data_into_shot_table(\n                err_in, shots_left, (size_t)num_errors, err_in_format, 'M', err_buffer, false);\n            if (errors_read != shots_left) {\n                throw std::invalid_argument(\"Expected more error data for the requested number of shots.\");\n            }\n        }\n        resample(err_in != nullptr);\n\n        if (err_out != nullptr) {\n            write_table_data(\n                err_out, shots_left, (size_t)num_errors, simd_bits<W>(0), err_buffer, err_out_format, 'M', 'M', false);\n        }\n\n        if (obs_out != nullptr) {\n            write_table_data(\n                obs_out,\n                shots_left,\n                (size_t)num_observables,\n                simd_bits<W>(0),\n                obs_buffer,\n                obs_out_format,\n                'L',\n                'L',\n                false);\n        }\n\n        if (det_out != nullptr) {\n            write_table_data(\n                det_out,\n                shots_left,\n                (size_t)num_detectors,\n                simd_bits<W>(0),\n                det_buffer,\n                det_out_format,\n                'D',\n                'D',\n                false);\n        }\n    }\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/simulators/dem_sampler.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"dem_sampler.h\"\n\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/perf.perf.h\"\n#include \"stim/simulators/error_analyzer.h\"\n\nusing namespace stim;\n\nBENCHMARK(DemSampler_surface_code_rotated_memory_z_distance11_100rounds_1024stripes) {\n    auto params = CircuitGenParameters(100, 11, \"rotated_memory_z\");\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, false, false, false);\n    std::mt19937_64 rng(0);\n    DemSampler<MAX_BITWORD_WIDTH> sampler(dem, std::mt19937_64(0), 1024);\n    size_t count = 0;\n    benchmark_go([&]() {\n        sampler.resample(false);\n        count += sampler.det_buffer[0].popcnt();\n        count += sampler.obs_buffer[0].popcnt();\n    }).goal_millis(35);\n    if (count == 0) {\n        std::cerr << \"Data dependence.\";\n    }\n}\n"
  },
  {
    "path": "src/stim/simulators/dem_sampler.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/dem_sampler.pybind.h\"\n\n#include \"stim/io/raii_file.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nRaiiFile optional_py_path_to_raii_file(const pybind11::object &obj, const char *mode) {\n    try {\n        std::string_view path = pybind11::cast<std::string_view>(obj);\n        return RaiiFile(path, mode);\n    } catch (pybind11::cast_error &ex) {\n    }\n\n    auto py_path = pybind11::module::import(\"pathlib\").attr(\"Path\");\n    if (pybind11::isinstance(obj, py_path)) {\n        pybind11::object str_obj = pybind11::str(obj);\n        std::string_view path = pybind11::cast<std::string_view>(str_obj);\n        return RaiiFile(path, mode);\n    }\n\n    return RaiiFile(nullptr);\n}\n\npybind11::object dem_sampler_py_sample(\n    DemSampler<MAX_BITWORD_WIDTH> &self,\n    size_t shots,\n    bool bit_packed,\n    bool return_errors,\n    pybind11::object &recorded_errors_to_replay) {\n    self.set_min_stripes(shots);\n\n    bool replay = !recorded_errors_to_replay.is_none();\n    if (replay && min_bits_to_num_bits_padded<MAX_BITWORD_WIDTH>(shots) != self.num_stripes) {\n        DemSampler<MAX_BITWORD_WIDTH> perfect_size(self.model, std::move(self.rng), shots);\n        auto result = dem_sampler_py_sample(perfect_size, shots, bit_packed, return_errors, recorded_errors_to_replay);\n        self.rng = std::move(perfect_size.rng);\n        return result;\n    }\n\n    if (replay) {\n        size_t out_shots;\n        simd_bit_table<MAX_BITWORD_WIDTH> converted =\n            numpy_array_to_transposed_simd_table(recorded_errors_to_replay, self.num_errors, &out_shots);\n        if (out_shots != shots) {\n            throw std::invalid_argument(\"recorded_errors_to_replay.shape[0] != shots\");\n        }\n        assert(converted.num_minor_bits_padded() == self.err_buffer.num_minor_bits_padded());\n        assert(converted.num_major_bits_padded() == self.err_buffer.num_major_bits_padded());\n        self.err_buffer = std::move(converted);\n    }\n\n    self.resample(replay);\n\n    pybind11::object err_out = pybind11::none();\n    if (return_errors) {\n        err_out = simd_bit_table_to_numpy(self.err_buffer, self.num_errors, shots, bit_packed, true, pybind11::none());\n    }\n    pybind11::object det_out =\n        simd_bit_table_to_numpy(self.det_buffer, self.num_detectors, shots, bit_packed, true, pybind11::none());\n    pybind11::object obs_out =\n        simd_bit_table_to_numpy(self.obs_buffer, self.num_observables, shots, bit_packed, true, pybind11::none());\n    return pybind11::make_tuple(det_out, obs_out, err_out);\n}\n\npybind11::class_<DemSampler<MAX_BITWORD_WIDTH>> stim_pybind::pybind_dem_sampler(pybind11::module &m) {\n    return pybind11::class_<DemSampler<MAX_BITWORD_WIDTH>>(\n        m,\n        \"CompiledDemSampler\",\n        clean_doc_string(R\"DOC(\n            A helper class for efficiently sampler from a detector error model.\n\n            Examples:\n                >>> import stim\n                >>> dem = stim.DetectorErrorModel('''\n                ...    error(0) D0\n                ...    error(1) D1 D2 L0\n                ... ''')\n                >>> sampler = dem.compile_sampler()\n                >>> det_data, obs_data, err_data = sampler.sample(\n                ...     shots=4,\n                ...     return_errors=True)\n                >>> det_data\n                array([[False,  True,  True],\n                       [False,  True,  True],\n                       [False,  True,  True],\n                       [False,  True,  True]])\n                >>> obs_data\n                array([[ True],\n                       [ True],\n                       [ True],\n                       [ True]])\n                >>> err_data\n                array([[False,  True],\n                       [False,  True],\n                       [False,  True],\n                       [False,  True]])\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_dem_sampler_methods(pybind11::module &m, pybind11::class_<DemSampler<MAX_BITWORD_WIDTH>> &c) {\n    c.def(\n        \"sample\",\n        &dem_sampler_py_sample,\n        pybind11::arg(\"shots\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed\") = false,\n        pybind11::arg(\"return_errors\") = false,\n        pybind11::arg(\"recorded_errors_to_replay\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def sample(self, shots: int, *, bit_packed: bool = False, return_errors: bool = False, recorded_errors_to_replay: Optional[np.ndarray] = None) -> Tuple[np.ndarray, np.ndarray, Optional[np.ndarray]]:\n            Samples the detector error model's error mechanisms to produce sample data.\n\n            Args:\n                shots: The number of times to sample from the model.\n                bit_packed: Defaults to false.\n                    False: the returned numpy arrays have dtype=np.bool_.\n                    True: the returned numpy arrays have dtype=np.uint8 and pack 8 bits into\n                        each byte.\n\n                    Setting this to True is equivalent to running\n                    `np.packbits(data, bitorder='little', axis=1)` on each output value, but\n                    has the performance benefit of the data never being expanded into an\n                    unpacked form.\n                return_errors: Defaults to False.\n                    False: the third entry of the returned tuple is None.\n                    True: the third entry of the returned tuple is a numpy array recording\n                    which errors were sampled.\n                recorded_errors_to_replay: Defaults to None, meaning sample errors randomly.\n                    If not None, this is expected to be a 2d numpy array specifying which\n                    errors to apply (e.g. one returned from a previous call to the sample\n                    method). The array must have dtype=np.bool_ and\n                    shape=(num_shots, num_errors) or dtype=np.uint8 and\n                    shape=(num_shots, math.ceil(num_errors / 8)).\n\n            Returns:\n                A tuple (detector_data, obs_data, error_data).\n\n                Assuming bit_packed is False and return_errors is True:\n                    - If error_data[s, k] is True, then the error with index k fired in the\n                        shot with index s.\n                    - If detector_data[s, k] is True, then the detector with index k ended\n                        up flipped in the shot with index s.\n                    - If obs_data[s, k] is True, then the observable with index k ended up\n                        flipped in the shot with index s.\n\n                The dtype and shape of the data depends on the arguments:\n                    if bit_packed:\n                        detector_data.shape == (num_shots, math.ceil(num_detectors / 8))\n                        detector_data.dtype == np.uint8\n                        obs_data.shape == (num_shots, math.ceil(num_observables / 8))\n                        obs_data.dtype == np.uint8\n                        if return_errors:\n                            error_data.shape = (num_shots, math.ceil(num_errors / 8))\n                            error_data.dtype = np.uint8\n                        else:\n                            error_data is None\n                    else:\n                        detector_data.shape == (num_shots, num_detectors)\n                        detector_data.dtype == np.bool_\n                        obs_data.shape == (num_shots, num_observables)\n                        obs_data.dtype == np.bool_\n                        if return_errors:\n                            error_data.shape = (num_shots, num_errors)\n                            error_data.dtype = np.bool_\n                        else:\n                            error_data is None\n\n                Note that bit packing is done using little endian order on the last axis\n                (i.e. like `np.packbits(data, bitorder='little', axis=1)`).\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n                >>> dem = stim.DetectorErrorModel('''\n                ...    error(0) D0\n                ...    error(1) D1 D2 L0\n                ... ''')\n                >>> sampler = dem.compile_sampler()\n\n                >>> # Taking samples.\n                >>> det_data, obs_data, err_data_not_requested = sampler.sample(shots=4)\n                >>> det_data\n                array([[False,  True,  True],\n                       [False,  True,  True],\n                       [False,  True,  True],\n                       [False,  True,  True]])\n                >>> obs_data\n                array([[ True],\n                       [ True],\n                       [ True],\n                       [ True]])\n                >>> err_data_not_requested is None\n                True\n\n                >>> # Recording errors.\n                >>> det_data, obs_data, err_data = sampler.sample(\n                ...     shots=4,\n                ...     return_errors=True)\n                >>> det_data\n                array([[False,  True,  True],\n                       [False,  True,  True],\n                       [False,  True,  True],\n                       [False,  True,  True]])\n                >>> obs_data\n                array([[ True],\n                       [ True],\n                       [ True],\n                       [ True]])\n                >>> err_data\n                array([[False,  True],\n                       [False,  True],\n                       [False,  True],\n                       [False,  True]])\n\n                >>> # Bit packing.\n                >>> det_data, obs_data, err_data = sampler.sample(\n                ...     shots=4,\n                ...     return_errors=True,\n                ...     bit_packed=True)\n                >>> det_data\n                array([[6],\n                       [6],\n                       [6],\n                       [6]], dtype=uint8)\n                >>> obs_data\n                array([[1],\n                       [1],\n                       [1],\n                       [1]], dtype=uint8)\n                >>> err_data\n                array([[2],\n                       [2],\n                       [2],\n                       [2]], dtype=uint8)\n\n                >>> # Recording and replaying errors.\n                >>> noisy_dem = stim.DetectorErrorModel('''\n                ...    error(0.125) D0\n                ...    error(0.25) D1\n                ... ''')\n                >>> noisy_sampler = noisy_dem.compile_sampler()\n                >>> det_data, obs_data, err_data = noisy_sampler.sample(\n                ...     shots=100,\n                ...     return_errors=True)\n                >>> replay_det_data, replay_obs_data, _ = noisy_sampler.sample(\n                ...     shots=100,\n                ...     recorded_errors_to_replay=err_data)\n                >>> np.array_equal(det_data, replay_det_data)\n                True\n                >>> np.array_equal(obs_data, replay_obs_data)\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sample_write\",\n        [](DemSampler<MAX_BITWORD_WIDTH> &self,\n           size_t shots,\n           pybind11::object &det_out_file,\n           std::string_view det_out_format,\n           pybind11::object &obs_out_file,\n           std::string_view obs_out_format,\n           pybind11::object &err_out_file,\n           std::string_view err_out_format,\n           pybind11::object &replay_err_in_file,\n           std::string_view replay_err_in_format) {\n            RaiiFile fd = optional_py_path_to_raii_file(det_out_file, \"wb\");\n            RaiiFile fo = optional_py_path_to_raii_file(obs_out_file, \"wb\");\n            RaiiFile feo = optional_py_path_to_raii_file(err_out_file, \"wb\");\n            RaiiFile fei = optional_py_path_to_raii_file(replay_err_in_file, \"rb\");\n            self.sample_write(\n                shots,\n                fd.f,\n                format_to_enum(det_out_format),\n                fo.f,\n                format_to_enum(obs_out_format),\n                feo.f,\n                format_to_enum(err_out_format),\n                fei.f,\n                format_to_enum(replay_err_in_format));\n        },\n        pybind11::arg(\"shots\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"det_out_file\"),\n        pybind11::arg(\"det_out_format\") = \"01\",\n        pybind11::arg(\"obs_out_file\"),\n        pybind11::arg(\"obs_out_format\") = \"01\",\n        pybind11::arg(\"err_out_file\") = pybind11::none(),\n        pybind11::arg(\"err_out_format\") = \"01\",\n        pybind11::arg(\"replay_err_in_file\") = pybind11::none(),\n        pybind11::arg(\"replay_err_in_format\") = \"01\",\n        clean_doc_string(R\"DOC(\n            @signature def sample_write(self, shots: int, *, det_out_file: Union[None, str, pathlib.Path], det_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01', obs_out_file: Union[None, str, pathlib.Path], obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01', err_out_file: Union[None, str, pathlib.Path] = None, err_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01', replay_err_in_file: Union[None, str, pathlib.Path] = None, replay_err_in_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01') -> None:\n            Samples the detector error model and writes the results to disk.\n\n            Args:\n                shots: The number of times to sample from the model.\n                det_out_file: Where to write detection event data.\n                    If None: detection event data is not written.\n                    If str or pathlib.Path: opens and overwrites the file at the given path.\n                    NOT IMPLEMENTED: io.IOBase\n                det_out_format: The format to write the detection event data in\n                    (e.g. \"01\" or \"b8\").\n                obs_out_file: Where to write observable flip data.\n                    If None: observable flip data is not written.\n                    If str or pathlib.Path: opens and overwrites the file at the given path.\n                    NOT IMPLEMENTED: io.IOBase\n                obs_out_format: The format to write the observable flip data in\n                    (e.g. \"01\" or \"b8\").\n                err_out_file: Where to write errors-that-occurred data.\n                    If None: errors-that-occurred data is not written.\n                    If str or pathlib.Path: opens and overwrites the file at the given path.\n                    NOT IMPLEMENTED: io.IOBase\n                err_out_format: The format to write the errors-that-occurred data in\n                    (e.g. \"01\" or \"b8\").\n                replay_err_in_file: If this is specified, errors are replayed from data\n                    instead of generated randomly. The following types are supported:\n                    - None: errors are generated randomly according to the probabilities\n                        in the detector error model.\n                    - str or pathlib.Path: the file at the given path is opened and\n                        errors-to-apply data is read from there.\n                    - io.IOBase: NOT IMPLEMENTED\n                replay_err_in_format: The format to write the errors-that-occurred data in\n                    (e.g. \"01\" or \"b8\").\n\n            Returns:\n                Nothing. Results are written to disk.\n\n            Examples:\n                >>> import stim\n                >>> import tempfile\n                >>> import pathlib\n                >>> dem = stim.DetectorErrorModel('''\n                ...    error(0) D0\n                ...    error(0) D1\n                ...    error(0) D0\n                ...    error(1) D1 D2 L0\n                ...    error(0) D0\n                ... ''')\n                >>> sampler = dem.compile_sampler()\n                >>> with tempfile.TemporaryDirectory() as d:\n                ...     d = pathlib.Path(d)\n                ...     sampler.sample_write(\n                ...         shots=1,\n                ...         det_out_file=d / 'dets.01',\n                ...         det_out_format='01',\n                ...         obs_out_file=d / 'obs.01',\n                ...         obs_out_format='01',\n                ...         err_out_file=d / 'err.hits',\n                ...         err_out_format='hits',\n                ...     )\n                ...     with open(d / 'dets.01') as f:\n                ...         assert f.read() == \"011\\n\"\n                ...     with open(d / 'obs.01') as f:\n                ...         assert f.read() == \"1\\n\"\n                ...     with open(d / 'err.hits') as f:\n                ...         assert f.read() == \"3\\n\"\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/simulators/dem_sampler.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_SIMULATORS_DEM_SAMPLER_PYBIND_H\n#define _STIM_SIMULATORS_DEM_SAMPLER_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/simulators/dem_sampler.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::DemSampler<stim::MAX_BITWORD_WIDTH>> pybind_dem_sampler(pybind11::module &m);\nvoid pybind_dem_sampler_methods(pybind11::module &m, pybind11::class_<stim::DemSampler<stim::MAX_BITWORD_WIDTH>> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/dem_sampler.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/dem_sampler.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(DemSampler, basic_sizing, {\n    DemSampler<W> sampler(DetectorErrorModel(R\"DEM()DEM\"), std::mt19937_64(0), 700);\n    ASSERT_EQ(sampler.det_buffer.num_major_bits_padded(), 0);\n    ASSERT_EQ(sampler.obs_buffer.num_major_bits_padded(), 0);\n    ASSERT_GE(sampler.det_buffer.num_minor_bits_padded(), 700);\n    ASSERT_GE(sampler.obs_buffer.num_minor_bits_padded(), 700);\n    sampler.resample(false);\n    ASSERT_FALSE(sampler.obs_buffer.data.not_zero());\n    ASSERT_FALSE(sampler.det_buffer.data.not_zero());\n\n    sampler = DemSampler<W>(\n        DetectorErrorModel(R\"DEM(\n            logical_observable L2000\n            detector D1000\n         )DEM\"),\n        std::mt19937_64(0),\n        200);\n    ASSERT_GE(sampler.det_buffer.num_major_bits_padded(), 1000);\n    ASSERT_GE(sampler.obs_buffer.num_major_bits_padded(), 2000);\n    ASSERT_GE(sampler.det_buffer.num_minor_bits_padded(), 200);\n    ASSERT_GE(sampler.obs_buffer.num_minor_bits_padded(), 200);\n    sampler.resample(false);\n    ASSERT_FALSE(sampler.obs_buffer.data.not_zero());\n    ASSERT_FALSE(sampler.det_buffer.data.not_zero());\n})\n\nTEST_EACH_WORD_SIZE_W(DemSampler, resample_basic_probabilities, {\n    DemSampler<W> sampler(\n        DetectorErrorModel(R\"DEM(\n            error(0) D0\n            error(0.25) D1 L0\n            error(0.5) D2\n            error(0.75) D3\n            error(1) D4 ^ D5\n         )DEM\"),\n        INDEPENDENT_TEST_RNG(),\n        1000);\n    for (size_t k = 0; k < 2; k++) {\n        sampler.resample(false);\n        ASSERT_EQ(sampler.det_buffer[0].popcnt(), 0);\n        ASSERT_GT(sampler.det_buffer[1].popcnt(), 0);\n        ASSERT_LT(sampler.det_buffer[1].popcnt(), 500);\n        ASSERT_GT(sampler.det_buffer[2].popcnt(), 250);\n        ASSERT_LT(sampler.det_buffer[2].popcnt(), 750);\n        ASSERT_GT(sampler.det_buffer[3].popcnt(), 500);\n        ASSERT_LT(sampler.det_buffer[3].popcnt(), 1000);\n        ASSERT_EQ(sampler.det_buffer[4].popcnt(), sampler.det_buffer[4].num_bits_padded());\n\n        ASSERT_EQ(sampler.det_buffer[1], sampler.obs_buffer[0]);\n        ASSERT_EQ(sampler.det_buffer[4], sampler.det_buffer[5]);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(DemSampler, resample_combinations, {\n    DemSampler<W> sampler(\n        DetectorErrorModel(R\"DEM(\n            error(0.1) D0 D1\n            error(0.2) D1 D2\n            error(0.3) D2 D0\n         )DEM\"),\n        INDEPENDENT_TEST_RNG(),\n        1000);\n    for (size_t k = 0; k < 2; k++) {\n        sampler.resample(false);\n        ASSERT_GT(sampler.det_buffer[0].popcnt(), 340 - 100);\n        ASSERT_LT(sampler.det_buffer[0].popcnt(), 340 + 100);\n        ASSERT_GT(sampler.det_buffer[1].popcnt(), 260 - 100);\n        ASSERT_LT(sampler.det_buffer[1].popcnt(), 260 + 100);\n        ASSERT_GT(sampler.det_buffer[2].popcnt(), 380 - 100);\n        ASSERT_LT(sampler.det_buffer[2].popcnt(), 380 + 100);\n\n        simd_bits<W> total = sampler.det_buffer[0];\n        total ^= sampler.det_buffer[1];\n        total ^= sampler.det_buffer[2];\n        ASSERT_FALSE(total.not_zero());\n    }\n})\n"
  },
  {
    "path": "src/stim/simulators/dem_sampler_pybind_test.py",
    "content": "import numpy as np\nimport pathlib\nimport pytest\nimport stim\nimport tempfile\n\n\n@pytest.mark.parametrize(\"bit_packed\", [False, True])\ndef test_dem_sampler_sample(bit_packed: bool):\n    noisy_dem = stim.DetectorErrorModel(\"\"\"\n        error(0.125) D0\n        error(0.25) D1\n    \"\"\")\n    noisy_sampler = noisy_dem.compile_sampler()\n    det_data, obs_data, err_data = noisy_sampler.sample(shots=100, return_errors=True, bit_packed=bit_packed)\n    replay_det_data, replay_obs_data, _ = noisy_sampler.sample(shots=100, recorded_errors_to_replay=err_data, bit_packed=bit_packed)\n    np.testing.assert_array_equal(det_data, replay_det_data)\n    np.testing.assert_array_equal(obs_data, replay_obs_data)\n\n\ndef test_dem_sampler_sampler_write():\n    dem = stim.DetectorErrorModel('''\n       error(0) D0\n       error(0) D1\n       error(0) D0\n       error(1) D1 D2 L0\n       error(0) D0\n    ''')\n    sampler = dem.compile_sampler()\n    with tempfile.TemporaryDirectory() as d:\n        d = pathlib.Path(d)\n        sampler.sample_write(\n            shots=1,\n            det_out_file=d / 'dets.01',\n            det_out_format='01',\n            obs_out_file=d / 'obs.01',\n            obs_out_format='01',\n            err_out_file=d / 'err.hits',\n            err_out_format='hits',\n        )\n        with open(d / 'dets.01') as f:\n            assert f.read() == \"011\\n\"\n        with open(d / 'obs.01') as f:\n            assert f.read() == \"1\\n\"\n        with open(d / 'err.hits') as f:\n            assert f.read() == \"3\\n\"\n\n        sampler = stim.DetectorErrorModel('''\n           error(1) D0  # this should be overridden by the replay.\n           error(1) D1\n           error(1) D0\n           error(1) D1 D2 L0\n           error(1) D0\n        ''').compile_sampler()\n        sampler.sample_write(\n            shots=1,\n            det_out_file=d / 'dets.01',\n            det_out_format='01',\n            obs_out_file=d / 'obs.01',\n            obs_out_format='01',\n            err_out_file=d / 'err2.01',\n            err_out_format='01',\n            replay_err_in_file=d / 'err.hits',\n            replay_err_in_format='hits',\n        )\n        with open(d / 'dets.01') as f:\n            assert f.read() == \"011\\n\"\n        with open(d / 'obs.01') as f:\n            assert f.read() == \"1\\n\"\n        with open(d / 'err.hits') as f:\n            assert f.read() == \"3\\n\"\n        with open(d / 'err2.01') as f:\n            assert f.read() == \"00010\\n\"\n\n\ndef test_dem_sampler_actually_fills_obs_array():\n    dem = stim.DetectorErrorModel('''\n       error(1) L0\n    ''')\n    sampler = dem.compile_sampler()\n    _, obs_data, _ = sampler.sample(shots=10000)\n    assert np.all(obs_data)\n"
  },
  {
    "path": "src/stim/simulators/error_analyzer.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/error_analyzer.h\"\n\n#include <algorithm>\n#include <queue>\n#include <sstream>\n\n#include \"stim/circuit/gate_decomposition.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/util_bot/error_decomp.h\"\n\nusing namespace stim;\n\nvoid ErrorAnalyzer::undo_gate(const CircuitInstruction &inst) {\n    switch (inst.gate_type) {\n        case GateType::DETECTOR:\n            undo_DETECTOR(inst);\n            break;\n        case GateType::OBSERVABLE_INCLUDE:\n            undo_OBSERVABLE_INCLUDE(inst);\n            break;\n        case GateType::TICK:\n            undo_TICK(inst);\n            break;\n        case GateType::QUBIT_COORDS:\n            undo_I(inst);\n            break;\n        case GateType::SHIFT_COORDS:\n            undo_SHIFT_COORDS(inst);\n            break;\n        case GateType::REPEAT:\n            undo_I(inst);\n            break;\n        case GateType::MX:\n            undo_MX(inst);\n            break;\n        case GateType::MY:\n            undo_MY(inst);\n            break;\n        case GateType::M:\n            undo_MZ(inst);\n            break;\n        case GateType::MRX:\n            undo_MRX(inst);\n            break;\n        case GateType::MRY:\n            undo_MRY(inst);\n            break;\n        case GateType::MR:\n            undo_MRZ(inst);\n            break;\n        case GateType::HERALDED_ERASE:\n            undo_HERALDED_ERASE(inst);\n            break;\n        case GateType::HERALDED_PAULI_CHANNEL_1:\n            undo_HERALDED_PAULI_CHANNEL_1(inst);\n            break;\n        case GateType::RX:\n            undo_RX(inst);\n            break;\n        case GateType::RY:\n            undo_RY(inst);\n            break;\n        case GateType::R:\n            undo_RZ(inst);\n            break;\n        case GateType::MPP:\n            undo_MPP(inst);\n            break;\n        case GateType::SPP:\n        case GateType::SPP_DAG:\n            undo_SPP(inst);\n            break;\n        case GateType::MPAD:\n            undo_MPAD(inst);\n            break;\n        case GateType::MXX:\n            undo_MXX(inst);\n            break;\n        case GateType::MYY:\n            undo_MYY(inst);\n            break;\n        case GateType::MZZ:\n            undo_MZZ(inst);\n            break;\n        case GateType::XCX:\n            undo_XCX(inst);\n            break;\n        case GateType::XCY:\n            undo_XCY(inst);\n            break;\n        case GateType::XCZ:\n            undo_XCZ(inst);\n            break;\n        case GateType::YCX:\n            undo_YCX(inst);\n            break;\n        case GateType::YCY:\n            undo_YCY(inst);\n            break;\n        case GateType::YCZ:\n            undo_YCZ(inst);\n            break;\n        case GateType::CX:\n            undo_ZCX(inst);\n            break;\n        case GateType::CY:\n            undo_ZCY(inst);\n            break;\n        case GateType::CZ:\n            undo_ZCZ(inst);\n            break;\n        case GateType::DEPOLARIZE1:\n            undo_DEPOLARIZE1(inst);\n            break;\n        case GateType::DEPOLARIZE2:\n            undo_DEPOLARIZE2(inst);\n            break;\n        case GateType::X_ERROR:\n            undo_X_ERROR(inst);\n            break;\n        case GateType::Y_ERROR:\n            undo_Y_ERROR(inst);\n            break;\n        case GateType::Z_ERROR:\n            undo_Z_ERROR(inst);\n            break;\n        case GateType::PAULI_CHANNEL_1:\n            undo_PAULI_CHANNEL_1(inst);\n            break;\n        case GateType::PAULI_CHANNEL_2:\n            undo_PAULI_CHANNEL_2(inst);\n            break;\n        case GateType::E:\n            undo_CORRELATED_ERROR(inst);\n            break;\n        case GateType::ELSE_CORRELATED_ERROR:\n            undo_ELSE_CORRELATED_ERROR(inst);\n            break;\n        case GateType::I:\n        case GateType::II:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n        case GateType::X:\n        case GateType::Y:\n        case GateType::Z:\n            undo_I(inst);\n            break;\n        case GateType::C_XYZ:\n        case GateType::C_NXYZ:\n        case GateType::C_XNYZ:\n        case GateType::C_XYNZ:\n            undo_C_XYZ(inst);\n            break;\n        case GateType::C_ZYX:\n        case GateType::C_NZYX:\n        case GateType::C_ZNYX:\n        case GateType::C_ZYNX:\n            undo_C_ZYX(inst);\n            break;\n        case GateType::H_YZ:\n        case GateType::SQRT_X:\n        case GateType::SQRT_X_DAG:\n        case GateType::H_NYZ:\n            undo_H_YZ(inst);\n            break;\n        case GateType::SQRT_Y:\n        case GateType::SQRT_Y_DAG:\n        case GateType::H:\n        case GateType::H_NXZ:\n            undo_H_XZ(inst);\n            break;\n        case GateType::S:\n        case GateType::S_DAG:\n        case GateType::H_XY:\n        case GateType::H_NXY:\n            undo_H_XY(inst);\n            break;\n        case GateType::SQRT_XX:\n        case GateType::SQRT_XX_DAG:\n            undo_SQRT_XX(inst);\n            break;\n        case GateType::SQRT_YY:\n        case GateType::SQRT_YY_DAG:\n            undo_SQRT_YY(inst);\n            break;\n        case GateType::SQRT_ZZ:\n        case GateType::SQRT_ZZ_DAG:\n            undo_SQRT_ZZ(inst);\n            break;\n        case GateType::SWAP:\n            undo_SWAP(inst);\n            break;\n        case GateType::ISWAP:\n        case GateType::ISWAP_DAG:\n            undo_ISWAP(inst);\n            break;\n        case GateType::CXSWAP:\n            undo_CXSWAP(inst);\n            break;\n        case GateType::CZSWAP:\n            undo_CZSWAP(inst);\n            break;\n        case GateType::SWAPCX:\n            undo_SWAPCX(inst);\n            break;\n        default:\n            throw std::invalid_argument(\n                \"Not implemented by ErrorAnalyzer::undo_gate: \" + std::string(GATE_DATA[inst.gate_type].name));\n    }\n}\n\nvoid ErrorAnalyzer::remove_gauge(SpanRef<const DemTarget> sorted) {\n    if (sorted.empty()) {\n        return;\n    }\n    const auto &max = sorted.back();\n    // HACK: linear overhead due to not keeping an index of which detectors used where.\n    for (auto &x : tracker.xs) {\n        if (x.contains(max)) {\n            x.xor_sorted_items(sorted);\n        }\n    }\n    for (auto &z : tracker.zs) {\n        if (z.contains(max)) {\n            z.xor_sorted_items(sorted);\n        }\n    }\n}\n\nvoid ErrorAnalyzer::undo_RX(const CircuitInstruction &dat) {\n    undo_RX_with_context(dat, \"an X-basis reset (RX)\");\n}\nvoid ErrorAnalyzer::undo_RY(const CircuitInstruction &dat) {\n    undo_RY_with_context(dat, \"an X-basis reset (RY)\");\n}\nvoid ErrorAnalyzer::undo_RZ(const CircuitInstruction &dat) {\n    undo_RZ_with_context(dat, \"a Z-basis reset (R)\");\n}\n\nvoid ErrorAnalyzer::undo_RX_with_context(const CircuitInstruction &dat, const char *context_op) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        check_for_gauge(tracker.zs[q], context_op, q, dat.tag);\n        tracker.xs[q].clear();\n        tracker.zs[q].clear();\n    }\n}\n\nvoid ErrorAnalyzer::undo_RY_with_context(const CircuitInstruction &inst, const char *context_op) {\n    for (size_t k = inst.targets.size(); k-- > 0;) {\n        auto q = inst.targets[k].qubit_value();\n        check_for_gauge(tracker.xs[q], tracker.zs[q], context_op, q, inst.tag);\n        tracker.xs[q].clear();\n        tracker.zs[q].clear();\n    }\n}\n\nvoid ErrorAnalyzer::undo_RZ_with_context(const CircuitInstruction &inst, const char *context_op) {\n    for (size_t k = inst.targets.size(); k-- > 0;) {\n        auto q = inst.targets[k].qubit_value();\n        check_for_gauge(tracker.xs[q], context_op, q, inst.tag);\n        tracker.xs[q].clear();\n        tracker.zs[q].clear();\n    }\n}\n\nvoid ErrorAnalyzer::undo_MX_with_context(const CircuitInstruction &inst, const char *context_op) {\n    for (size_t k = inst.targets.size(); k-- > 0;) {\n        auto q = inst.targets[k].qubit_value();\n        tracker.num_measurements_in_past--;\n\n        SparseXorVec<DemTarget> &d = tracker.rec_bits[tracker.num_measurements_in_past];\n        xor_sorted_measurement_error(d.range(), inst);\n        tracker.xs[q].xor_sorted_items(d.range());\n        check_for_gauge(tracker.zs[q], context_op, q, inst.tag);\n        tracker.rec_bits.erase(tracker.num_measurements_in_past);\n    }\n}\n\nvoid ErrorAnalyzer::undo_MY_with_context(const CircuitInstruction &inst, const char *context_op) {\n    for (size_t k = inst.targets.size(); k-- > 0;) {\n        auto q = inst.targets[k].qubit_value();\n        tracker.num_measurements_in_past--;\n\n        SparseXorVec<DemTarget> &d = tracker.rec_bits[tracker.num_measurements_in_past];\n        xor_sorted_measurement_error(d.range(), inst);\n        tracker.xs[q].xor_sorted_items(d.range());\n        tracker.zs[q].xor_sorted_items(d.range());\n        check_for_gauge(tracker.xs[q], tracker.zs[q], context_op, q, inst.tag);\n        tracker.rec_bits.erase(tracker.num_measurements_in_past);\n    }\n}\n\nvoid ErrorAnalyzer::undo_MZ_with_context(const CircuitInstruction &inst, const char *context_op) {\n    for (size_t k = inst.targets.size(); k-- > 0;) {\n        auto q = inst.targets[k].qubit_value();\n        tracker.num_measurements_in_past--;\n\n        SparseXorVec<DemTarget> &d = tracker.rec_bits[tracker.num_measurements_in_past];\n        xor_sorted_measurement_error(d.range(), inst);\n        tracker.zs[q].xor_sorted_items(d.range());\n        check_for_gauge(tracker.xs[q], context_op, q, inst.tag);\n        tracker.rec_bits.erase(tracker.num_measurements_in_past);\n    }\n}\n\nvoid ErrorAnalyzer::undo_HERALDED_ERASE(const CircuitInstruction &inst) {\n    check_can_approximate_disjoint(\"HERALDED_ERASE\", inst.args, false);\n    double p = inst.args[0] * 0.25;\n    double i = std::max(0.0, 1.0 - 4 * p);\n\n    for (size_t k = inst.targets.size(); k-- > 0;) {\n        auto q = inst.targets[k].qubit_value();\n        tracker.num_measurements_in_past--;\n\n        SparseXorVec<DemTarget> &herald_symptoms = tracker.rec_bits[tracker.num_measurements_in_past];\n        if (accumulate_errors) {\n            add_error_combinations<3>(\n                {i, 0, 0, 0, p, p, p, p},\n                {tracker.xs[q].range(), tracker.zs[q].range(), herald_symptoms.range()},\n                true,\n                inst.tag);\n        }\n        tracker.rec_bits.erase(tracker.num_measurements_in_past);\n    }\n}\n\nvoid ErrorAnalyzer::undo_HERALDED_PAULI_CHANNEL_1(const CircuitInstruction &inst) {\n    check_can_approximate_disjoint(\"HERALDED_PAULI_CHANNEL_1\", inst.args, true);\n    double hi = inst.args[0];\n    double hx = inst.args[1];\n    double hy = inst.args[2];\n    double hz = inst.args[3];\n    double i = std::max(0.0, 1.0 - hi - hx - hy - hz);\n\n    for (size_t k = inst.targets.size(); k-- > 0;) {\n        auto q = inst.targets[k].qubit_value();\n        tracker.num_measurements_in_past--;\n\n        SparseXorVec<DemTarget> &herald_symptoms = tracker.rec_bits[tracker.num_measurements_in_past];\n        if (accumulate_errors) {\n            add_error_combinations<3>(\n                {i, 0, 0, 0, hi, hz, hx, hy},\n                {tracker.xs[q].range(), tracker.zs[q].range(), herald_symptoms.range()},\n                true,\n                inst.tag);\n        }\n        tracker.rec_bits.erase(tracker.num_measurements_in_past);\n    }\n}\n\nvoid ErrorAnalyzer::undo_MPAD(const CircuitInstruction &inst) {\n    for (size_t k = inst.targets.size(); k-- > 0;) {\n        tracker.num_measurements_in_past--;\n\n        SparseXorVec<DemTarget> &d = tracker.rec_bits[tracker.num_measurements_in_past];\n        xor_sorted_measurement_error(d.range(), inst);\n        tracker.rec_bits.erase(tracker.num_measurements_in_past);\n    }\n}\n\nvoid ErrorAnalyzer::check_for_gauge(\n    SparseXorVec<DemTarget> &potential_gauge_summand_1,\n    const SparseXorVec<DemTarget> &potential_gauge_summand_2,\n    const char *context_op,\n    uint64_t context_qubit,\n    std::string_view tag) {\n    if (potential_gauge_summand_1 == potential_gauge_summand_2) {\n        return;\n    }\n    potential_gauge_summand_1 ^= potential_gauge_summand_2;\n    check_for_gauge(potential_gauge_summand_1, context_op, context_qubit, tag);\n    potential_gauge_summand_1 ^= potential_gauge_summand_2;\n}\n\n// This is redundant with comma_sep from str_util.h, but for reasons I can't figure out\n// (something to do with a dependency cycle involving templates) the compilation fails\n// if I use that one.\ntemplate <typename TIter>\nstd::string comma_sep_workaround(const TIter &iterable) {\n    std::stringstream out;\n    bool first = true;\n    for (const auto &t : iterable) {\n        if (first) {\n            first = false;\n        } else {\n            out << \", \";\n        }\n        out << t;\n    }\n    return out.str();\n}\n\nvoid ErrorAnalyzer::check_for_gauge(\n    const SparseXorVec<DemTarget> &potential_gauge,\n    const char *context_op,\n    uint64_t context_qubit,\n    std::string_view tag) {\n    if (potential_gauge.empty()) {\n        return;\n    }\n\n    bool has_observables = false;\n    bool has_detectors = false;\n    for (const auto &t : potential_gauge) {\n        has_observables |= t.is_observable_id();\n        has_detectors |= t.is_relative_detector_id();\n    }\n    if (allow_gauge_detectors && !has_observables) {\n        remove_gauge(add_error(0.5, potential_gauge.range(), tag).targets);\n        return;\n    }\n\n    // We are now in an error condition, and it's a bit hard to debug for the user.\n    // The goal is to collect a *lot* of information that might be useful to them.\n\n    std::stringstream error_msg;\n    has_detectors &= !allow_gauge_detectors;\n    if (has_observables) {\n        error_msg << \"The circuit contains non-deterministic observables.\\n\";\n    }\n    if (has_detectors) {\n        error_msg << \"The circuit contains non-deterministic detectors.\\n\";\n    }\n    size_t range_start = num_ticks_in_past - std::min((size_t)num_ticks_in_past, size_t{5});\n    size_t range_end = num_ticks_in_past + 5;\n    error_msg << \"\\nTo make an SVG picture of the problem, you can use the python API like this:\\n    \";\n    error_msg << \"your_circuit.diagram('detslice-with-ops-svg'\";\n    error_msg << \", tick=range(\" << range_start << \", \" << range_end << \")\";\n    error_msg << \", filter_coords=[\";\n    for (auto d : potential_gauge) {\n        error_msg << \"'\" << d << \"', \";\n    }\n    error_msg << \"])\";\n    error_msg << \"\\nor the command line API like this:\\n    \";\n    error_msg << \"stim diagram --in your_circuit_file.stim\";\n    error_msg << \" --type detslice-with-ops-svg\";\n    error_msg << \" --tick \" << range_start << \":\" << range_end;\n    error_msg << \" --filter_coords \";\n    for (size_t k = 0; k < potential_gauge.size(); k++) {\n        if (k) {\n            error_msg << ':';\n        }\n        error_msg << potential_gauge.sorted_items[k];\n    }\n    error_msg << \" > output_image.svg\\n\";\n\n    std::map<uint64_t, std::vector<double>> qubit_coords_map;\n    if (current_circuit_being_analyzed != nullptr) {\n        qubit_coords_map = current_circuit_being_analyzed->get_final_qubit_coords();\n    }\n    auto error_msg_qubit_with_coords = [&](uint64_t q, uint8_t p) {\n        error_msg << \"\\n\";\n        auto qubit_coords = qubit_coords_map[q];\n        if (p == 0) {\n            error_msg << \"    qubit \" << q;\n        } else if (p == 1) {\n            error_msg << \"    X\" << q;\n        } else if (p == 2) {\n            error_msg << \"    Z\" << q;\n        } else if (p == 3) {\n            error_msg << \"    Y\" << q;\n        }\n        if (!qubit_coords.empty()) {\n            error_msg << \" [coords (\" << comma_sep_workaround(qubit_coords) << \")]\";\n        }\n    };\n\n    error_msg << \"\\n\";\n    error_msg << \"This was discovered while analyzing \" << context_op << \" on:\";\n    error_msg_qubit_with_coords(context_qubit, 0);\n\n    error_msg << \"\\n\\n\";\n    error_msg << \"The collapse anti-commuted with these detectors/observables:\";\n    for (const auto &t : potential_gauge) {\n        error_msg << \"\\n    \" << t;\n\n        // Try to find recorded coordinate information for the detector.\n        if (t.is_relative_detector_id() && current_circuit_being_analyzed != nullptr) {\n            auto coords = current_circuit_being_analyzed->coords_of_detector(t.raw_id());\n            if (!coords.empty()) {\n                error_msg << \" [coords (\" << comma_sep_workaround(coords) << \")]\";\n            }\n        }\n    }\n\n    for (const auto &t : potential_gauge) {\n        if (t.is_relative_detector_id() && allow_gauge_detectors) {\n            continue;\n        }\n        error_msg << \"\\n\\n\";\n        error_msg << \"The backward-propagating error sensitivity for \" << t << \" was:\";\n        auto sensitivity = current_error_sensitivity_for(t);\n        sensitivity.ref().for_each_active_pauli([&](size_t q) {\n            uint8_t p = sensitivity.xs[q] + sensitivity.zs[q] * 2;\n            error_msg_qubit_with_coords(q, p);\n        });\n    }\n\n    throw std::invalid_argument(error_msg.str());\n}\n\nPauliString<MAX_BITWORD_WIDTH> ErrorAnalyzer::current_error_sensitivity_for(DemTarget t) const {\n    PauliString<MAX_BITWORD_WIDTH> result(tracker.xs.size());\n    for (size_t q = 0; q < tracker.xs.size(); q++) {\n        result.xs[q] = std::ranges::find(tracker.xs[q], t) != tracker.xs[q].end();\n        result.zs[q] = std::ranges::find(tracker.zs[q], t) != tracker.zs[q].end();\n    }\n    return result;\n}\n\nvoid ErrorAnalyzer::xor_sorted_measurement_error(SpanRef<const DemTarget> targets, const CircuitInstruction &inst) {\n    // Measurement error.\n    if (!inst.args.empty() && inst.args[0] > 0) {\n        add_error(inst.args[0], targets, inst.tag);\n    }\n}\n\nvoid ErrorAnalyzer::undo_MX(const CircuitInstruction &dat) {\n    undo_MX_with_context(dat, \"an X-basis measurement (MX)\");\n}\nvoid ErrorAnalyzer::undo_MY(const CircuitInstruction &dat) {\n    undo_MY_with_context(dat, \"a Y-basis measurement (MY)\");\n}\nvoid ErrorAnalyzer::undo_MZ(const CircuitInstruction &dat) {\n    undo_MZ_with_context(dat, \"a Z-basis measurement (M)\");\n}\n\nvoid ErrorAnalyzer::undo_MRX(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k];\n        undo_RX_with_context({GateType::RX, dat.args, &q, dat.tag}, \"an X-basis demolition measurement (MRX)\");\n        undo_MX_with_context({GateType::MX, dat.args, &q, dat.tag}, \"an X-basis demolition measurement (MRX)\");\n    }\n}\n\nvoid ErrorAnalyzer::undo_MRY(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k];\n        undo_RY_with_context({GateType::RY, dat.args, &q, dat.tag}, \"a Y-basis demolition measurement (MRY)\");\n        undo_MY_with_context({GateType::MY, dat.args, &q, dat.tag}, \"a Y-basis demolition measurement (MRY)\");\n    }\n}\n\nvoid ErrorAnalyzer::undo_MRZ(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k];\n        undo_RZ_with_context({GateType::R, dat.args, &q, dat.tag}, \"a Z-basis demolition measurement (MR)\");\n        undo_MZ_with_context({GateType::M, dat.args, &q, dat.tag}, \"a Z-basis demolition measurement (MR)\");\n    }\n}\n\nvoid ErrorAnalyzer::undo_H_XZ(const CircuitInstruction &dat) {\n    tracker.undo_H_XZ(dat);\n}\nvoid ErrorAnalyzer::undo_H_XY(const CircuitInstruction &dat) {\n    tracker.undo_H_XY(dat);\n}\nvoid ErrorAnalyzer::undo_H_YZ(const CircuitInstruction &dat) {\n    tracker.undo_H_YZ(dat);\n}\nvoid ErrorAnalyzer::undo_C_XYZ(const CircuitInstruction &dat) {\n    tracker.undo_C_XYZ(dat);\n}\nvoid ErrorAnalyzer::undo_C_ZYX(const CircuitInstruction &dat) {\n    tracker.undo_C_ZYX(dat);\n}\nvoid ErrorAnalyzer::undo_XCX(const CircuitInstruction &dat) {\n    tracker.undo_XCX(dat);\n}\nvoid ErrorAnalyzer::undo_XCY(const CircuitInstruction &dat) {\n    tracker.undo_XCY(dat);\n}\nvoid ErrorAnalyzer::undo_YCX(const CircuitInstruction &dat) {\n    tracker.undo_YCX(dat);\n}\nvoid ErrorAnalyzer::undo_ZCY(const CircuitInstruction &dat) {\n    tracker.undo_ZCY(dat);\n}\nvoid ErrorAnalyzer::undo_YCZ(const CircuitInstruction &dat) {\n    tracker.undo_YCZ(dat);\n}\nvoid ErrorAnalyzer::undo_YCY(const CircuitInstruction &dat) {\n    tracker.undo_YCY(dat);\n}\nvoid ErrorAnalyzer::undo_ZCX(const CircuitInstruction &dat) {\n    tracker.undo_ZCX(dat);\n}\nvoid ErrorAnalyzer::undo_XCZ(const CircuitInstruction &dat) {\n    tracker.undo_XCZ(dat);\n}\nvoid ErrorAnalyzer::undo_ZCZ(const CircuitInstruction &dat) {\n    tracker.undo_ZCZ(dat);\n}\nvoid ErrorAnalyzer::undo_TICK(const CircuitInstruction &dat) {\n    num_ticks_in_past--;\n}\nvoid ErrorAnalyzer::undo_SQRT_XX(const CircuitInstruction &dat) {\n    tracker.undo_SQRT_XX(dat);\n}\nvoid ErrorAnalyzer::undo_SQRT_YY(const CircuitInstruction &dat) {\n    tracker.undo_SQRT_YY(dat);\n}\nvoid ErrorAnalyzer::undo_SQRT_ZZ(const CircuitInstruction &dat) {\n    tracker.undo_SQRT_ZZ(dat);\n}\nvoid ErrorAnalyzer::undo_I(const CircuitInstruction &dat) {\n}\nvoid ErrorAnalyzer::undo_SWAP(const CircuitInstruction &dat) {\n    tracker.undo_SWAP(dat);\n}\nvoid ErrorAnalyzer::undo_ISWAP(const CircuitInstruction &dat) {\n    tracker.undo_ISWAP(dat);\n}\nvoid ErrorAnalyzer::undo_CXSWAP(const CircuitInstruction &dat) {\n    tracker.undo_CXSWAP(dat);\n}\nvoid ErrorAnalyzer::undo_CZSWAP(const CircuitInstruction &dat) {\n    tracker.undo_CZSWAP(dat);\n}\nvoid ErrorAnalyzer::undo_SWAPCX(const CircuitInstruction &dat) {\n    tracker.undo_SWAPCX(dat);\n}\nvoid ErrorAnalyzer::undo_DETECTOR(const CircuitInstruction &dat) {\n    tracker.undo_DETECTOR(dat);\n    auto id = DemTarget::relative_detector_id(tracker.num_detectors_in_past);\n    flushed_reversed_model.append_detector_instruction(dat.args, id, dat.tag);\n}\n\nvoid ErrorAnalyzer::undo_OBSERVABLE_INCLUDE(const CircuitInstruction &dat) {\n    tracker.undo_OBSERVABLE_INCLUDE(dat);\n    auto id = DemTarget::observable_id((int32_t)dat.args[0]);\n    flushed_reversed_model.append_logical_observable_instruction(id, dat.tag);\n}\n\nErrorAnalyzer::ErrorAnalyzer(\n    uint64_t num_measurements,\n    uint64_t num_detectors,\n    size_t num_qubits,\n    uint64_t num_ticks,\n    bool decompose_errors,\n    bool fold_loops,\n    bool allow_gauge_detectors,\n    double approximate_disjoint_errors_threshold,\n    bool ignore_decomposition_failures,\n    bool block_decomposition_from_introducing_remnant_edges)\n    : tracker(num_qubits, num_measurements, num_detectors),\n      decompose_errors(decompose_errors),\n      accumulate_errors(true),\n      fold_loops(fold_loops),\n      allow_gauge_detectors(allow_gauge_detectors),\n      approximate_disjoint_errors_threshold(approximate_disjoint_errors_threshold),\n      ignore_decomposition_failures(ignore_decomposition_failures),\n      block_decomposition_from_introducing_remnant_edges(block_decomposition_from_introducing_remnant_edges),\n      num_ticks_in_past(num_ticks) {\n}\n\nvoid ErrorAnalyzer::undo_circuit(const Circuit &circuit) {\n    std::vector<CircuitInstruction> stacked_else_correlated_errors;\n    for (size_t k = circuit.operations.size(); k--;) {\n        const auto &op = circuit.operations[k];\n        try {\n            if (op.gate_type == GateType::ELSE_CORRELATED_ERROR) {\n                stacked_else_correlated_errors.push_back(op);\n            } else if (op.gate_type == GateType::E) {\n                stacked_else_correlated_errors.push_back(op);\n                correlated_error_block(stacked_else_correlated_errors);\n                stacked_else_correlated_errors.clear();\n            } else if (!stacked_else_correlated_errors.empty()) {\n                throw std::invalid_argument(\n                    \"ELSE_CORRELATED_ERROR wasn't preceded by ELSE_CORRELATED_ERROR or CORRELATED_ERROR (E)\");\n            } else if (op.gate_type == GateType::REPEAT) {\n                const auto &loop_body = op.repeat_block_body(circuit);\n                uint64_t repeats = op.repeat_block_rep_count();\n                run_loop(loop_body, repeats, op.tag);\n            } else {\n                undo_gate(op);\n            }\n        } catch (std::invalid_argument &ex) {\n            std::stringstream error_msg;\n            std::string body = ex.what();\n            const char *marker = \"\\n\\nCircuit stack trace:\\n    at instruction\";\n            size_t p = body.find(marker);\n            if (p == std::string::npos) {\n                error_msg << body;\n            } else {\n                error_msg << body.substr(0, p);\n            }\n            error_msg << \"\\n\\nCircuit stack trace:\";\n            if (&circuit == current_circuit_being_analyzed) {\n                auto total_ticks = circuit.count_ticks();\n                if (total_ticks) {\n                    uint64_t current_tick = num_ticks_in_past;\n                    error_msg << \"\\n    during TICK layer #\" << (current_tick + 1) << \" of \" << (total_ticks + 1);\n                }\n            }\n            error_msg << '\\n' << circuit.describe_instruction_location(k);\n            if (p != std::string::npos) {\n                error_msg << \"\\n    at block's instruction\" << body.substr(p + strlen(marker));\n            }\n            throw std::invalid_argument(error_msg.str());\n        }\n    }\n\n    if (!stacked_else_correlated_errors.empty()) {\n        throw std::invalid_argument(\n            \"ELSE_CORRELATED_ERROR wasn't preceded by ELSE_CORRELATED_ERROR or CORRELATED_ERROR (E)\");\n    }\n}\n\nvoid ErrorAnalyzer::post_check_initialization() {\n    for (uint32_t q = 0; q < tracker.xs.size(); q++) {\n        check_for_gauge(tracker.xs[q], \"qubit initialization into |0> at the start of the circuit\", q, \"\");\n    }\n}\n\nvoid ErrorAnalyzer::undo_X_ERROR(const CircuitInstruction &inst) {\n    if (!accumulate_errors) {\n        return;\n    }\n    for (auto q : inst.targets) {\n        add_error(inst.args[0], tracker.zs[q.data].range(), inst.tag);\n    }\n}\n\nvoid ErrorAnalyzer::undo_Y_ERROR(const CircuitInstruction &inst) {\n    if (!accumulate_errors) {\n        return;\n    }\n    for (auto q : inst.targets) {\n        add_xored_error(inst.args[0], tracker.xs[q.data].range(), tracker.zs[q.data].range(), inst.tag);\n    }\n}\n\nvoid ErrorAnalyzer::undo_Z_ERROR(const CircuitInstruction &inst) {\n    if (!accumulate_errors) {\n        return;\n    }\n    for (auto q : inst.targets) {\n        add_error(inst.args[0], tracker.xs[q.data].range(), inst.tag);\n    }\n}\n\ntemplate <typename T>\ninline void inplace_xor_tail(MonotonicBuffer<T> &dst, const SparseXorVec<T> &src) {\n    SpanRef<const T> in1 = dst.tail;\n    SpanRef<const T> in2 = src.range();\n    xor_merge_sort_temp_buffer_callback(in1, in2, [&](SpanRef<const T> result) {\n        dst.discard_tail();\n        dst.append_tail(result);\n    });\n}\n\nvoid ErrorAnalyzer::add_composite_error(double probability, SpanRef<const GateTarget> targets, std::string_view tag) {\n    if (!accumulate_errors) {\n        return;\n    }\n    for (auto qp : targets) {\n        auto q = qp.qubit_value();\n        if (qp.data & TARGET_PAULI_Z_BIT) {\n            inplace_xor_tail(mono_buf, tracker.xs[q]);\n        }\n        if (qp.data & TARGET_PAULI_X_BIT) {\n            inplace_xor_tail(mono_buf, tracker.zs[q]);\n        }\n    }\n    add_error_in_sorted_jagged_tail(probability, tag);\n}\n\nvoid ErrorAnalyzer::correlated_error_block(const std::vector<CircuitInstruction> &dats) {\n    assert(!dats.empty());\n\n    if (dats.size() == 1) {\n        add_composite_error(dats[0].args[0], dats[0].targets, dats[0].tag);\n        return;\n    }\n    check_can_approximate_disjoint(\"ELSE_CORRELATED_ERROR\", {}, false);\n\n    double remaining_p = 1;\n    for (size_t k = dats.size(); k--;) {\n        CircuitInstruction dat = dats[k];\n        double actual_p = dat.args[0] * remaining_p;\n        remaining_p *= 1 - dat.args[0];\n        if (actual_p > approximate_disjoint_errors_threshold) {\n            throw std::invalid_argument(\n                \"CORRELATED_ERROR/ELSE_CORRELATED_ERROR block has a component probability '\" +\n                std::to_string(actual_p) +\n                \"' larger than the \"\n                \"`approximate_disjoint_errors` threshold of \"\n                \"'\" +\n                std::to_string(approximate_disjoint_errors_threshold) + \"'.\");\n        }\n        add_composite_error(actual_p, dat.targets, dat.tag);\n    }\n}\n\nvoid ErrorAnalyzer::undo_CORRELATED_ERROR(const CircuitInstruction &inst) {\n    add_composite_error(inst.args[0], inst.targets, inst.tag);\n}\n\nvoid ErrorAnalyzer::undo_DEPOLARIZE1(const CircuitInstruction &inst) {\n    if (!accumulate_errors) {\n        return;\n    }\n    if (inst.args[0] > 0.75) {\n        throw std::invalid_argument(\"Can't analyze over-mixing DEPOLARIZE1 errors (probability > 3/4).\");\n    }\n    double p = depolarize1_probability_to_independent_per_channel_probability(inst.args[0]);\n    for (auto q : inst.targets) {\n        add_error_combinations<2>(\n            {0, p, p, p},\n            {\n                tracker.xs[q.data].range(),\n                tracker.zs[q.data].range(),\n            },\n            false,\n            inst.tag);\n    }\n}\n\nvoid ErrorAnalyzer::undo_DEPOLARIZE2(const CircuitInstruction &inst) {\n    if (!accumulate_errors) {\n        return;\n    }\n    if (inst.args[0] > 15.0 / 16.0) {\n        throw std::invalid_argument(\"Can't analyze over-mixing DEPOLARIZE2 errors (probability > 15/16).\");\n    }\n    double p = depolarize2_probability_to_independent_per_channel_probability(inst.args[0]);\n    for (size_t i = 0; i < inst.targets.size(); i += 2) {\n        auto a = inst.targets[i];\n        auto b = inst.targets[i + 1];\n        add_error_combinations<4>(\n            {0, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p},\n            {\n                tracker.xs[a.data].range(),\n                tracker.zs[a.data].range(),\n                tracker.xs[b.data].range(),\n                tracker.zs[b.data].range(),\n            },\n            false,\n            inst.tag);\n    }\n}\n\nvoid ErrorAnalyzer::undo_ELSE_CORRELATED_ERROR(const CircuitInstruction &dat) {\n    if (accumulate_errors) {\n        throw std::invalid_argument(\"Failed to analyze ELSE_CORRELATED_ERROR: \" + dat.str());\n    }\n}\n\nvoid ErrorAnalyzer::check_can_approximate_disjoint(\n    const char *op_name, SpanRef<const double> probabilities, bool allow_single_component) const {\n    if (allow_single_component) {\n        size_t num_specified = 0;\n        for (double p : probabilities) {\n            num_specified += p > 0;\n        }\n        if (num_specified <= 1) {\n            return;\n        }\n    }\n\n    if (approximate_disjoint_errors_threshold == 0) {\n        std::stringstream msg;\n        msg << \"Encountered the operation \" << op_name\n            << \" during error analysis, but this operation requires the `approximate_disjoint_errors` option to be \"\n               \"enabled.\";\n        msg << \"\\nIf you're calling from python, using stim.Circuit.detector_error_model, you need to add the \"\n               \"argument approximate_disjoint_errors=True.\\n\";\n        msg << \"\\nIf you're calling from the command line, you need to specify --approximate_disjoint_errors.\";\n        throw std::invalid_argument(msg.str());\n    }\n    for (double p : probabilities) {\n        if (p > approximate_disjoint_errors_threshold) {\n            std::stringstream msg;\n            msg << op_name;\n            msg << \" has a probability argument (\";\n            msg << p;\n            msg << \") larger than the `approximate_disjoint_errors` threshold (\";\n            msg << approximate_disjoint_errors_threshold;\n            msg << +\").\";\n            throw std::invalid_argument(msg.str());\n        }\n    }\n}\n\nvoid ErrorAnalyzer::undo_PAULI_CHANNEL_1(const CircuitInstruction &inst) {\n    double dx = inst.args[0];\n    double dy = inst.args[1];\n    double dz = inst.args[2];\n    double ix;\n    double iy;\n    double iz;\n    bool is_independent = try_disjoint_to_independent_xyz_errors_approx(dx, dy, dz, &ix, &iy, &iz);\n    if (!is_independent) {\n        check_can_approximate_disjoint(\"PAULI_CHANNEL_1\", inst.args, true);\n        ix = dx;\n        iy = dy;\n        iz = dz;\n    }\n\n    if (!accumulate_errors) {\n        return;\n    }\n    for (auto q : inst.targets) {\n        add_error_combinations<2>(\n            {0, ix, iz, iy},\n            {\n                tracker.zs[q.data].range(),\n                tracker.xs[q.data].range(),\n            },\n            !is_independent,\n            inst.tag);\n    }\n}\n\nvoid ErrorAnalyzer::undo_PAULI_CHANNEL_2(const CircuitInstruction &inst) {\n    check_can_approximate_disjoint(\"PAULI_CHANNEL_2\", inst.args, true);\n\n    std::array<double, 16> probabilities;\n    for (size_t k = 0; k < 15; k++) {\n        size_t k2 = pauli_xyz_to_xz((k + 1) & 3) | (pauli_xyz_to_xz(((k + 1) >> 2) & 3) << 2);\n        probabilities[k2] = inst.args[k];\n    }\n    if (!accumulate_errors) {\n        return;\n    }\n    for (size_t i = 0; i < inst.targets.size(); i += 2) {\n        auto a = inst.targets[i];\n        auto b = inst.targets[i + 1];\n        add_error_combinations<4>(\n            probabilities,\n            {\n                tracker.zs[b.data].range(),\n                tracker.xs[b.data].range(),\n                tracker.zs[a.data].range(),\n                tracker.xs[a.data].range(),\n            },\n            true,\n            inst.tag);\n    }\n}\n\nDetectorErrorModel unreversed(const DetectorErrorModel &rev, uint64_t &base_detector_id, std::set<DemTarget> &seen) {\n    DetectorErrorModel out;\n    auto conv_append = [&](const DemInstruction &e) {\n        auto stored_targets = out.target_buf.take_copy(e.target_data);\n        auto stored_args = out.arg_buf.take_copy(e.arg_data);\n        auto stored_tag = out.tag_buf.take_copy(e.tag);\n        for (auto &t : stored_targets) {\n            t.shift_if_detector_id(-(int64_t)base_detector_id);\n        }\n        out.instructions.push_back(\n            DemInstruction{\n                .arg_data = stored_args,\n                .target_data = stored_targets,\n                .tag = stored_tag,\n                .type = e.type,\n            });\n    };\n\n    for (auto p = rev.instructions.crbegin(); p != rev.instructions.crend(); p++) {\n        const auto &e = *p;\n        switch (e.type) {\n            case DemInstructionType::DEM_SHIFT_DETECTORS:\n                base_detector_id += e.target_data[0].data;\n                out.append_shift_detectors_instruction(e.arg_data, e.target_data[0].data, e.tag);\n                break;\n            case DemInstructionType::DEM_ERROR:\n                for (auto &t : e.target_data) {\n                    seen.insert(t);\n                }\n                conv_append(e);\n                break;\n            case DemInstructionType::DEM_DETECTOR:\n            case DemInstructionType::DEM_LOGICAL_OBSERVABLE:\n                if (!e.arg_data.empty() || !e.tag.empty() || !seen.contains(e.target_data[0])) {\n                    conv_append(e);\n                }\n                break;\n            case DemInstructionType::DEM_REPEAT_BLOCK: {\n                uint64_t repetitions = e.repeat_block_rep_count();\n                if (repetitions) {\n                    uint64_t old_base_detector_id = base_detector_id;\n                    out.append_repeat_block(\n                        e.repeat_block_rep_count(),\n                        unreversed(e.repeat_block_body(rev), base_detector_id, seen),\n                        e.tag);\n                    uint64_t loop_shift = base_detector_id - old_base_detector_id;\n                    base_detector_id += loop_shift * (repetitions - 1);\n                }\n            } break;\n            default:\n                throw std::invalid_argument(\"Unknown instruction type in 'unreversed'.\");\n        }\n    }\n    return out;\n}\n\nDetectorErrorModel ErrorAnalyzer::circuit_to_detector_error_model(\n    const Circuit &circuit,\n    bool decompose_errors,\n    bool fold_loops,\n    bool allow_gauge_detectors,\n    double approximate_disjoint_errors_threshold,\n    bool ignore_decomposition_failures,\n    bool block_decomposition_from_introducing_remnant_edges) {\n    ErrorAnalyzer analyzer(\n        circuit.count_measurements(),\n        circuit.count_detectors(),\n        circuit.count_qubits(),\n        circuit.count_ticks(),\n        decompose_errors,\n        fold_loops,\n        allow_gauge_detectors,\n        approximate_disjoint_errors_threshold,\n        ignore_decomposition_failures,\n        block_decomposition_from_introducing_remnant_edges);\n    analyzer.current_circuit_being_analyzed = &circuit;\n    analyzer.undo_circuit(circuit);\n    analyzer.post_check_initialization();\n    analyzer.flush();\n    uint64_t t = 0;\n    std::set<DemTarget> seen;\n    return unreversed(analyzer.flushed_reversed_model, t, seen);\n}\n\nvoid ErrorAnalyzer::flush() {\n    do_global_error_decomposition_pass();\n    for (auto kv = error_class_probabilities.crbegin(); kv != error_class_probabilities.crend(); kv++) {\n        const ErrorEquivalenceClass &key = kv->first;\n        const double &probability = kv->second;\n        if (key.targets.empty() || probability == 0) {\n            continue;\n        }\n        flushed_reversed_model.append_error_instruction(probability, key.targets, key.tag);\n    }\n    error_class_probabilities.clear();\n}\n\nErrorEquivalenceClass ErrorAnalyzer::add_xored_error(\n    double probability, SpanRef<const DemTarget> flipped1, SpanRef<const DemTarget> flipped2, std::string_view tag) {\n    mono_buf.ensure_available(flipped1.size() + flipped2.size());\n    mono_buf.tail.ptr_end = xor_merge_sort(flipped1, flipped2, mono_buf.tail.ptr_end);\n    return add_error_in_sorted_jagged_tail(probability, tag);\n}\n\nErrorEquivalenceClass ErrorAnalyzer::mono_dedupe_store_tail(std::string_view tag) {\n    auto v = error_class_probabilities.find(ErrorEquivalenceClass{mono_buf.tail, tag});\n    if (v != error_class_probabilities.end()) {\n        mono_buf.discard_tail();\n        return v->first;\n    }\n    auto result = ErrorEquivalenceClass{mono_buf.commit_tail(), tag};\n    error_class_probabilities.insert({result, 0});\n    return result;\n}\n\nErrorEquivalenceClass ErrorAnalyzer::mono_dedupe_store(ErrorEquivalenceClass sorted) {\n    auto v = error_class_probabilities.find(sorted);\n    if (v != error_class_probabilities.end()) {\n        return v->first;\n    }\n    mono_buf.append_tail(sorted.targets);\n    auto result = ErrorEquivalenceClass{mono_buf.commit_tail(), sorted.tag};\n    error_class_probabilities.insert({result, 0});\n    return result;\n}\n\nErrorEquivalenceClass ErrorAnalyzer::add_error(\n    double probability, SpanRef<const DemTarget> flipped_sorted, std::string_view tag) {\n    auto key = mono_dedupe_store(ErrorEquivalenceClass{flipped_sorted, tag});\n    auto &old_p = error_class_probabilities[key];\n    old_p = old_p * (1 - probability) + (1 - old_p) * probability;\n    return key;\n}\n\nErrorEquivalenceClass ErrorAnalyzer::add_error_in_sorted_jagged_tail(double probability, std::string_view tag) {\n    auto key = mono_dedupe_store_tail(tag);\n    auto &old_p = error_class_probabilities[key];\n    old_p = old_p * (1 - probability) + (1 - old_p) * probability;\n    return key;\n}\n\nvoid ErrorAnalyzer::run_loop(const Circuit &loop, uint64_t iterations, std::string_view loop_tag) {\n    if (!fold_loops) {\n        // If loop folding is disabled, just manually run each iteration.\n        for (size_t k = 0; k < iterations; k++) {\n            undo_circuit(loop);\n        }\n        return;\n    }\n\n    uint64_t hare_iter = 0;\n    uint64_t tortoise_iter = 0;\n    ErrorAnalyzer hare(\n        tracker.num_measurements_in_past,\n        tracker.num_detectors_in_past,\n        tracker.xs.size(),\n        num_ticks_in_past,\n        false,\n        true,\n        allow_gauge_detectors,\n        approximate_disjoint_errors_threshold,\n        false,\n        false);\n    hare.tracker = tracker;\n    hare.accumulate_errors = false;\n\n    // Perform tortoise-and-hare cycle finding.\n    while (hare_iter < iterations) {\n        try {\n            hare.undo_circuit(loop);\n        } catch (const std::invalid_argument &) {\n            // Encountered an error. Abort loop folding so it can be re-triggered in a normal way.\n            hare_iter = iterations;\n            break;\n        }\n        hare_iter++;\n        if (hare.tracker.is_shifted_copy(tracker)) {\n            break;\n        }\n\n        if (hare_iter % 2 == 0) {\n            undo_circuit(loop);\n            tortoise_iter++;\n            if (hare.tracker.is_shifted_copy(tracker)) {\n                break;\n            }\n        }\n    }\n\n    if (hare_iter < iterations) {\n        // Don't bother folding a single iteration into a repeated block.\n        uint64_t period = hare_iter - tortoise_iter;\n        uint64_t period_iterations = (iterations - tortoise_iter) / period;\n        uint64_t ticks_per_period = num_ticks_in_past - hare.num_ticks_in_past;\n        uint64_t detectors_per_period = tracker.num_detectors_in_past - hare.tracker.num_detectors_in_past;\n        uint64_t measurements_per_period = tracker.num_measurements_in_past - hare.tracker.num_measurements_in_past;\n        if (period_iterations > 1) {\n            // Stash error model build up so far.\n            flush();\n            DetectorErrorModel tmp = std::move(flushed_reversed_model);\n\n            // Rewrite state to look like it would if loop had executed all but the last iteration.\n            uint64_t skipped_periods = period_iterations - 1;\n            tracker.shift(\n                -(int64_t)(skipped_periods * measurements_per_period),\n                -(int64_t)(skipped_periods * detectors_per_period));\n            num_ticks_in_past -= skipped_periods * ticks_per_period;\n            tortoise_iter += skipped_periods * period;\n\n            // Compute the loop's error model.\n            for (size_t k = 0; k < period; k++) {\n                undo_circuit(loop);\n                tortoise_iter++;\n            }\n            flush();\n            DetectorErrorModel body = std::move(flushed_reversed_model);\n\n            // The loop ends (well, starts because everything is reversed) by shifting the detector coordinates.\n            uint64_t lower_level_shifts = body.total_detector_shift();\n            DemTarget remaining_shift = {detectors_per_period - lower_level_shifts};\n            if (remaining_shift.data > 0) {\n                if (body.instructions.empty() ||\n                    body.instructions.front().type != DemInstructionType::DEM_SHIFT_DETECTORS) {\n                    auto shift_targets = body.target_buf.take_copy(SpanRef<const DemTarget>(&remaining_shift));\n                    body.instructions.insert(\n                        body.instructions.begin(),\n                        DemInstruction{\n                            .arg_data = {},\n                            .target_data = shift_targets,\n                            .tag = \"\",\n                            .type = DemInstructionType::DEM_SHIFT_DETECTORS,\n                        });\n                } else {\n                    remaining_shift.data += body.instructions[0].target_data[0].data;\n                    auto shift_targets = body.target_buf.take_copy(SpanRef<const DemTarget>(&remaining_shift));\n                    body.instructions[0].target_data = shift_targets;\n                }\n            }\n\n            // Append the loop to the growing error model and put the error model back in its proper place.\n            tmp.append_repeat_block(period_iterations, std::move(body), loop_tag);\n            flushed_reversed_model = std::move(tmp);\n        }\n    }\n\n    // Perform remaining loop iterations leftover after jumping forward by multiples of the recurrence period.\n    while (tortoise_iter < iterations) {\n        undo_circuit(loop);\n        tortoise_iter++;\n    }\n}\n\nvoid ErrorAnalyzer::undo_SHIFT_COORDS(const CircuitInstruction &inst) {\n    flushed_reversed_model.append_shift_detectors_instruction(inst.args, 0, inst.tag);\n}\n\ntemplate <size_t s>\nvoid ErrorAnalyzer::decompose_helper_add_error_combinations(\n    const std::array<uint64_t, 1 << s> &detector_masks,\n    std::array<SpanRef<const DemTarget>, 1 << s> &stored_ids,\n    std::string_view tag) {\n    // Count number of detectors affected by each error.\n    std::array<uint8_t, 1 << s> detector_counts{};\n    for (size_t k = 1; k < 1 << s; k++) {\n        detector_counts[k] = std::popcount(detector_masks[k]);\n    }\n\n    // Find single-detector errors (and empty errors).\n    uint64_t solved = 0;\n    uint64_t single_detectors_union = 0;\n    for (size_t k = 1; k < 1 << s; k++) {\n        if (detector_counts[k] == 1) {\n            single_detectors_union |= detector_masks[k];\n            solved |= 1 << k;\n        }\n    }\n\n    // Find irreducible double-detector errors.\n    FixedCapVector<uint8_t, 1 << s> irreducible_pairs{};\n    for (size_t k = 1; k < 1 << s; k++) {\n        if (detector_counts[k] == 2 && (detector_masks[k] & ~single_detectors_union)) {\n            irreducible_pairs.push_back(k);\n            solved |= 1 << k;\n        }\n    }\n\n    auto append_involved_pairs_to_jag_tail = [&](size_t goal_k) -> uint64_t {\n        uint64_t goal = detector_masks[goal_k];\n\n        // If single-detector excitations are sufficient, just use those.\n        if ((goal & ~single_detectors_union) == 0) {\n            return goal;\n        }\n\n        // Check if one double-detector excitation can get us into the single-detector region.\n        for (auto k : irreducible_pairs) {\n            auto m = detector_masks[k];\n            if ((goal & m) == m && (goal & ~(single_detectors_union | m)) == 0) {\n                mono_buf.append_tail(stored_ids[k]);\n                mono_buf.append_tail(DemTarget::separator());\n                return goal & ~m;\n            }\n        }\n\n        // Check if two double-detector excitations can get us into the single-detector region.\n        for (size_t i1 = 0; i1 < irreducible_pairs.size(); i1++) {\n            auto k1 = irreducible_pairs[i1];\n            auto m1 = detector_masks[k1];\n            for (size_t i2 = i1 + 1; i2 < irreducible_pairs.size(); i2++) {\n                auto k2 = irreducible_pairs[i2];\n                auto m2 = detector_masks[k2];\n                if ((m1 & m2) == 0 && (goal & ~(single_detectors_union | m1 | m2)) == 0) {\n                    if (stored_ids[k2] < stored_ids[k1]) {\n                        std::swap(k1, k2);\n                    }\n                    mono_buf.append_tail(stored_ids[k1]);\n                    mono_buf.append_tail(DemTarget::separator());\n                    mono_buf.append_tail(stored_ids[k2]);\n                    mono_buf.append_tail(DemTarget::separator());\n                    return goal & ~(m1 | m2);\n                }\n            }\n        }\n\n        // Failed to decompose into other components of the same composite Pauli channel.\n        // Put it into the result undecomposed, to be worked on more later.\n        mono_buf.append_tail(stored_ids[goal_k]);\n        mono_buf.append_tail(DemTarget::separator());\n        return 0;\n    };\n\n    // Solve the decomposition of each composite case.\n    for (size_t k = 1; k < 1 << s; k++) {\n        if (detector_counts[k] && ((solved >> k) & 1) == 0) {\n            auto remnants = append_involved_pairs_to_jag_tail(k);\n\n            // Finish off the solution using single-detector components.\n            for (size_t k2 = 0; remnants && k2 < 1 << s; k2++) {\n                if (detector_counts[k2] == 1 && (detector_masks[k2] & ~remnants) == 0) {\n                    remnants &= ~detector_masks[k2];\n                    mono_buf.append_tail(stored_ids[k2]);\n                    mono_buf.append_tail(DemTarget::separator());\n                }\n            }\n            if (!mono_buf.tail.empty()) {\n                mono_buf.tail.ptr_end -= 1;\n            }\n            stored_ids[k] = mono_dedupe_store_tail(tag).targets;\n        }\n    }\n}\n\nbool stim::is_graphlike(const SpanRef<const DemTarget> &components) {\n    size_t symptom_count = 0;\n    for (const auto &t : components) {\n        if (t.is_separator()) {\n            symptom_count = 0;\n        } else if (t.is_relative_detector_id()) {\n            symptom_count++;\n            if (symptom_count > 2) {\n                return false;\n            }\n        }\n    }\n    return true;\n}\n\nbool ErrorAnalyzer::has_unflushed_ungraphlike_errors() const {\n    for (const auto &kv : error_class_probabilities) {\n        const auto &component = kv.first;\n        if (kv.second != 0 && !is_graphlike(component.targets)) {\n            return true;\n        }\n    }\n    return false;\n}\n\nbool ErrorAnalyzer::decompose_and_append_component_to_tail(\n    SpanRef<const DemTarget> component,\n    const std::map<FixedCapVector<DemTarget, 2>, SpanRef<const DemTarget>> &known_symptoms) {\n    std::vector<bool> done(component.size(), false);\n\n    size_t num_component_detectors = 0;\n    for (size_t k = 0; k < component.size(); k++) {\n        if (component[k].is_relative_detector_id()) {\n            num_component_detectors++;\n        } else {\n            done[k] = true;\n        }\n    }\n    if (num_component_detectors <= 2) {\n        mono_buf.append_tail(component);\n        mono_buf.append_tail(DemTarget::separator());\n        return true;\n    }\n\n    SparseXorVec<DemTarget> sparse;\n    sparse.xor_sorted_items(component);\n\n    for (size_t k = 0; k < component.size(); k++) {\n        if (!done[k]) {\n            for (size_t k2 = k + 1; k2 < component.size(); k2++) {\n                if (!done[k2]) {\n                    auto p = known_symptoms.find({component[k], component[k2]});\n                    if (p != known_symptoms.end()) {\n                        done[k] = true;\n                        done[k2] = true;\n                        mono_buf.append_tail(p->second);\n                        mono_buf.append_tail(DemTarget::separator());\n                        sparse.xor_sorted_items(p->second);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    size_t missed = 0;\n    for (size_t k = 0; k < component.size(); k++) {\n        if (!done[k]) {\n            auto p = known_symptoms.find({component[k]});\n            if (p != known_symptoms.end()) {\n                done[k] = true;\n                mono_buf.append_tail(p->second);\n                mono_buf.append_tail(DemTarget::separator());\n                sparse.xor_sorted_items(p->second);\n            }\n        }\n        missed += !done[k];\n    }\n\n    if (missed <= 2) {\n        if (!sparse.empty()) {\n            mono_buf.append_tail({sparse.begin(), sparse.end()});\n            mono_buf.append_tail(DemTarget::separator());\n        }\n        return true;\n    }\n\n    mono_buf.discard_tail();\n    return false;\n}\n\nstd::pair<uint64_t, uint64_t> obs_mask_of_targets(SpanRef<const DemTarget> targets) {\n    uint64_t obs_mask = 0;\n    uint64_t used_mask = 0;\n    for (size_t k = 0; k < targets.size(); k++) {\n        const auto &t = targets[k];\n        if (t.is_observable_id()) {\n            if (t.val() >= 64) {\n                throw std::invalid_argument(\"Not implemented: decomposing errors observable ids larger than 63.\");\n            }\n            obs_mask |= uint64_t{1} << t.val();\n            used_mask |= uint64_t{1} << k;\n        }\n    }\n    return {obs_mask, used_mask};\n}\n\nbool brute_force_decomp_helper(\n    size_t start,\n    uint64_t used_term_mask,\n    uint64_t remaining_obs_mask,\n    SpanRef<const DemTarget> problem,\n    const std::map<FixedCapVector<DemTarget, 2>, SpanRef<const DemTarget>> &known_symptoms,\n    std::vector<SpanRef<const DemTarget>> &out_result) {\n    while (true) {\n        if (start >= problem.size()) {\n            return remaining_obs_mask == 0;\n        }\n        if (((used_term_mask >> start) & 1) == 0) {\n            break;\n        }\n        start++;\n    }\n    used_term_mask |= 1 << start;\n\n    FixedCapVector<DemTarget, 2> key;\n    key.push_back(problem[start]);\n    for (size_t k = start + 1; k <= problem.size(); k++) {\n        if (k < problem.size()) {\n            if ((used_term_mask >> k) & 1) {\n                continue;\n            }\n            key.push_back(problem[k]);\n            used_term_mask ^= 1 << k;\n        }\n        auto match = known_symptoms.find(key);\n        if (match != known_symptoms.end()) {\n            uint64_t obs_change = obs_mask_of_targets(match->second).first;\n            if (brute_force_decomp_helper(\n                    start + 1, used_term_mask, remaining_obs_mask ^ obs_change, problem, known_symptoms, out_result)) {\n                out_result.push_back(match->second);\n                return true;\n            }\n        }\n        if (k < problem.size()) {\n            key.pop_back();\n            used_term_mask ^= 1 << k;\n        }\n    }\n\n    return false;\n}\n\nbool stim::brute_force_decomposition_into_known_graphlike_errors(\n    SpanRef<const DemTarget> problem,\n    const std::map<FixedCapVector<DemTarget, 2>, SpanRef<const DemTarget>> &known_graphlike_errors,\n    MonotonicBuffer<DemTarget> &output) {\n    if (problem.size() >= 64) {\n        throw std::invalid_argument(\"Not implemented: decomposing errors with more than 64 terms.\");\n    }\n\n    std::vector<SpanRef<const DemTarget>> out;\n    out.reserve(problem.size());\n    auto prob_masks = obs_mask_of_targets(problem);\n\n    bool result =\n        brute_force_decomp_helper(0, prob_masks.second, prob_masks.first, problem, known_graphlike_errors, out);\n    if (result) {\n        for (auto r = out.crbegin(); r != out.crend(); r++) {\n            output.append_tail(*r);\n            output.append_tail(DemTarget::separator());\n        }\n    }\n    return result;\n}\n\nvoid ErrorAnalyzer::do_global_error_decomposition_pass() {\n    if (!decompose_errors || !has_unflushed_ungraphlike_errors()) {\n        return;\n    }\n\n    std::vector<DemTarget> component_symptoms;\n\n    // Make a map from all known symptoms singlets and pairs to actual components including frame changes.\n    std::map<FixedCapVector<DemTarget, 2>, SpanRef<const DemTarget>> known_symptoms;\n    for (const auto &kv : error_class_probabilities) {\n        if (kv.second == 0 || kv.first.targets.empty()) {\n            continue;\n        }\n        const auto &targets = kv.first.targets;\n        size_t start = 0;\n        for (size_t k = 0; k <= targets.size(); k++) {\n            if (k == targets.size() || targets[k].is_separator()) {\n                if (component_symptoms.size() == 1) {\n                    known_symptoms[{component_symptoms[0]}] = {&targets[start], &targets[k]};\n                } else if (component_symptoms.size() == 2) {\n                    known_symptoms[{component_symptoms[0], component_symptoms[1]}] = {&targets[start], &targets[k]};\n                }\n                component_symptoms.clear();\n                start = k + 1;\n            } else if (targets[k].is_relative_detector_id()) {\n                component_symptoms.push_back(targets[k]);\n            }\n        }\n    }\n\n    // Find how to rewrite hyper errors into graphlike errors.\n    std::vector<std::pair<ErrorEquivalenceClass, ErrorEquivalenceClass>> rewrites;\n    for (const auto &kv : error_class_probabilities) {\n        if (kv.second == 0 || kv.first.targets.empty()) {\n            continue;\n        }\n\n        const auto &targets = kv.first.targets;\n        if (is_graphlike(targets)) {\n            continue;\n        }\n\n        size_t start = 0;\n        for (size_t k = 0; k <= targets.size(); k++) {\n            if (k == targets.size() || targets[k].is_separator()) {\n                SpanRef<const DemTarget> problem{&targets[start], &targets[k]};\n                if (brute_force_decomposition_into_known_graphlike_errors(problem, known_symptoms, mono_buf)) {\n                    // Solved using only existing edges.\n                } else if (\n                    !block_decomposition_from_introducing_remnant_edges &&\n                    // We are now *really* desperate.\n                    // We need to start considering decomposing into errors that\n                    // don't exist, as long as they can be formed by xoring\n                    // together errors that do exist. This might impact the\n                    // graphlike code distance.\n                    decompose_and_append_component_to_tail({&targets[start], &targets[k]}, known_symptoms)) {\n                    // Solved using a remnant edge.\n                } else if (ignore_decomposition_failures) {\n                    mono_buf.append_tail(problem);\n                    mono_buf.append_tail(DemTarget::separator());\n                } else {\n                    std::stringstream ss;\n                    ss << \"Failed to decompose errors into graphlike components with at most two symptoms.\\n\";\n                    ss << \"The error component that failed to decompose is '\" << comma_sep_workaround(problem)\n                       << \"'.\\n\";\n                    ss << \"\\n\";\n                    ss << \"In Python, you can ignore this error by passing `ignore_decomposition_failures=True` to \"\n                          \"`stim.Circuit.detector_error_model(...)`.\\n\";\n                    ss << \"From the command line, you can ignore this error by passing the flag \"\n                          \"`--ignore_decomposition_failures` to `stim analyze_errors`.\";\n                    if (block_decomposition_from_introducing_remnant_edges) {\n                        ss << \"\\n\\nNote: `block_decomposition_from_introducing_remnant_edges` is ON.\\n\";\n                        ss << \"Turning it off may prevent this error.\";\n                    }\n                    throw std::invalid_argument(ss.str());\n                }\n                start = k + 1;\n            }\n        }\n\n        if (!mono_buf.tail.empty()) {\n            // Drop final separator.\n            mono_buf.tail.ptr_end -= 1;\n        }\n\n        rewrites.push_back({kv.first, ErrorEquivalenceClass{mono_buf.commit_tail(), kv.first.tag}});\n    }\n\n    for (const auto &rewrite : rewrites) {\n        double p = error_class_probabilities[rewrite.first];\n        error_class_probabilities.erase(rewrite.first);\n        add_error(p, rewrite.second.targets, rewrite.second.tag);\n    }\n}\n\ntemplate <size_t s>\nvoid ErrorAnalyzer::add_error_combinations(\n    std::array<double, 1 << s> probabilities,\n    std::array<SpanRef<const DemTarget>, s> basis_errors,\n    bool probabilities_are_disjoint,\n    std::string_view tag) {\n    std::array<uint64_t, 1 << s> detector_masks{};\n    FixedCapVector<DemTarget, 16> involved_detectors{};\n    std::array<SpanRef<const DemTarget>, 1 << s> stored_ids;\n\n    for (size_t k = 0; k < s; k++) {\n        stored_ids[1 << k] = mono_dedupe_store(ErrorEquivalenceClass{basis_errors[k], tag}).targets;\n\n        if (decompose_errors) {\n            for (const auto &id : basis_errors[k]) {\n                if (id.is_relative_detector_id()) {\n                    auto r = involved_detectors.find(id);\n                    if (r == involved_detectors.end()) {\n                        try {\n                            involved_detectors.push_back(id);\n                        } catch (const std::out_of_range &) {\n                            std::stringstream message;\n                            message\n                                << \"An error case in a composite error exceeded the max supported number of symptoms \"\n                                   \"(<=15).\";\n                            message << \"\\nThe \" << std::to_string(s)\n                                    << \" basis error cases (e.g. X, Z) used to form the combined \";\n                            message << \"error cases (e.g. Y = X*Z) are:\\n\";\n                            for (size_t k2 = 0; k2 < s; k2++) {\n                                message << std::to_string(k2) << \":\";\n                                if (!basis_errors[k2].empty()) {\n                                    message << ' ';\n                                }\n                                message << comma_sep_workaround(basis_errors[k2]) << \"\\n\";\n                            }\n                            throw std::invalid_argument(message.str());\n                        }\n                    }\n                    detector_masks[1 << k] ^= 1 << (r - involved_detectors.begin());\n                }\n            }\n        }\n    }\n\n    // Fill in all 2**s - 1 possible combinations from the initial basis values.\n    for (size_t k = 3; k < 1 << s; k++) {\n        auto c1 = k & (k - 1);\n        auto c2 = k ^ c1;\n        if (c1) {\n            mono_buf.ensure_available(stored_ids[c1].size() + stored_ids[c2].size());\n            mono_buf.tail.ptr_end = xor_merge_sort(stored_ids[c1], stored_ids[c2], mono_buf.tail.ptr_end);\n            stored_ids[k] = mono_dedupe_store_tail(tag).targets;\n            detector_masks[k] = detector_masks[c1] ^ detector_masks[c2];\n        }\n    }\n\n    // Determine involved detectors while creating basis masks and storing added data.\n    if (decompose_errors) {\n        decompose_helper_add_error_combinations<s>(detector_masks, stored_ids, tag);\n    }\n    if (probabilities_are_disjoint) {\n        // Merge indistinguishable cases.\n        for (size_t k = 1; k < 1 << s; k++) {\n            if (stored_ids[k].empty()) {\n                // Since symptom k is empty, merge pairs A, B such that A^B = k.\n                for (size_t k_dst = 0; k_dst < 1 << s; k_dst++) {\n                    size_t k_src = k_dst ^ k;\n                    if (k_src > k_dst) {\n                        probabilities[k_dst] += probabilities[k_src];\n                        probabilities[k_src] = 0;\n                    }\n                }\n            }\n        }\n    }\n\n    // Include errors in the record.\n    for (size_t k = 1; k < 1 << s; k++) {\n        add_error(probabilities[k], stored_ids[k], tag);\n    }\n}\n\nvoid ErrorAnalyzer::undo_MPP(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n    decompose_mpp_operation(\n        CircuitInstruction{GateType::MPP, inst.args, reversed_targets, inst.tag},\n        tracker.xs.size(),\n        [&](const CircuitInstruction &sub_inst) {\n            if (sub_inst.gate_type == GateType::M) {\n                reversed_measure_targets.clear();\n                for (size_t k = sub_inst.targets.size(); k--;) {\n                    reversed_measure_targets.push_back(sub_inst.targets[k]);\n                }\n                undo_MZ_with_context(\n                    CircuitInstruction{GateType::M, sub_inst.args, reversed_measure_targets, sub_inst.tag},\n                    \"a Pauli product measurement (MPP)\");\n            } else {\n                undo_gate(sub_inst);\n            }\n        });\n}\n\nvoid ErrorAnalyzer::undo_SPP(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n    decompose_spp_or_spp_dag_operation(\n        CircuitInstruction{GateType::SPP, inst.args, reversed_targets, inst.tag},\n        tracker.xs.size(),\n        false,\n        [&](const CircuitInstruction &sub_inst) {\n            undo_gate(sub_inst);\n        });\n}\n\nvoid ErrorAnalyzer::undo_MXX_disjoint_controls_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    undo_ZCX(CircuitInstruction{GateType::CX, {}, inst.targets, inst.tag});\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        undo_MX_with_context(\n            CircuitInstruction{GateType::MX, inst.args, SpanRef<const GateTarget>{&inst.targets[k]}, inst.tag},\n            \"an X-basis pair measurement (MXX)\");\n    }\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    undo_ZCX(CircuitInstruction{GateType::CX, {}, inst.targets, inst.tag});\n}\n\nvoid ErrorAnalyzer::undo_MYY_disjoint_controls_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    undo_ZCY(CircuitInstruction{GateType::CY, {}, inst.targets, inst.tag});\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        undo_MY_with_context(\n            CircuitInstruction{GateType::MY, inst.args, SpanRef<const GateTarget>{&inst.targets[k]}, inst.tag},\n            \"a Y-basis pair measurement (MYY)\");\n    }\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    undo_ZCY(CircuitInstruction{GateType::CY, {}, inst.targets, inst.tag});\n}\n\nvoid ErrorAnalyzer::undo_MZZ_disjoint_controls_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    undo_XCZ(CircuitInstruction{GateType::XCZ, {}, inst.targets, inst.tag});\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        undo_MZ_with_context(\n            CircuitInstruction{GateType::M, inst.args, SpanRef<const GateTarget>{&inst.targets[k]}, inst.tag},\n            \"a Z-basis pair measurement (MZ)\");\n    }\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    undo_XCZ(CircuitInstruction{GateType::XCZ, {}, inst.targets, inst.tag});\n}\n\nvoid ErrorAnalyzer::undo_MXX(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n\n    decompose_pair_instruction_into_disjoint_segments(\n        CircuitInstruction{inst.gate_type, inst.args, reversed_targets, inst.tag},\n        tracker.xs.size(),\n        [&](CircuitInstruction segment) {\n            undo_MXX_disjoint_controls_segment(segment);\n        });\n}\n\nvoid ErrorAnalyzer::undo_MYY(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n\n    decompose_pair_instruction_into_disjoint_segments(\n        CircuitInstruction{inst.gate_type, inst.args, reversed_targets, inst.tag},\n        tracker.xs.size(),\n        [&](CircuitInstruction segment) {\n            undo_MYY_disjoint_controls_segment(segment);\n        });\n}\n\nvoid ErrorAnalyzer::undo_MZZ(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n\n    decompose_pair_instruction_into_disjoint_segments(\n        CircuitInstruction{inst.gate_type, inst.args, reversed_targets, inst.tag},\n        tracker.xs.size(),\n        [&](CircuitInstruction segment) {\n            undo_MZZ_disjoint_controls_segment(segment);\n        });\n}\n"
  },
  {
    "path": "src/stim/simulators/error_analyzer.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_ERROR_ANALYZER_H\n#define _STIM_SIMULATORS_ERROR_ANALYZER_H\n\n#include <algorithm>\n#include <map>\n#include <memory>\n#include <vector>\n\n#include \"sparse_rev_frame_tracker.h\"\n#include \"stim/circuit/circuit.h\"\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/mem/fixed_cap_vector.h\"\n#include \"stim/mem/monotonic_buffer.h\"\n#include \"stim/mem/sparse_xor_vec.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nnamespace stim {\n\nstruct ErrorEquivalenceClass {\n    SpanRef<const DemTarget> targets;\n    std::string_view tag;\n\n    inline bool operator==(const ErrorEquivalenceClass &other) const {\n        return targets == other.targets && tag == other.tag;\n    }\n    inline bool operator!=(const ErrorEquivalenceClass &other) const {\n        return !(*this == other);\n    }\n    inline bool operator<(const ErrorEquivalenceClass &other) const {\n        if (targets != other.targets) {\n            return targets < other.targets;\n        }\n        if (tag != other.tag) {\n            return tag < other.tag;\n        }\n        return false;\n    }\n};\n\n/// This class is responsible for iterating backwards over a circuit, tracking which detectors are currently\n/// sensitive to an X or Z error on each qubit. This is done by having a SparseXorVec for the X and Z\n/// sensitivities of each qubit, and transforming these collections in response to operations.\n/// For example, applying a CNOT gate from qubit A to qubit B will xor the X sensitivity of A into B and the\n/// Z sensitivity of B into A.\n///\n/// Y error sensitivity is always implicit in the xor of the X and Z components.\n///\n/// Note that the class iterates over the circuit *backward*, so that DETECTOR instructions are seen before\n/// the measurement operations that the detector depends on. When a DETECTOR is seen, it is noted which\n/// measurements it depends on and then when those measurements are seen the detector is added as one of the\n/// things sensitive to errors that anticommute with the measurement.\n///\n/// Be wary that this class is definitely one of the more complex things in Stim. For example:\n/// - There is a monobuf that is often used as a temporary buffer to avoid allocations, meaning\n///     the state and meaning of the monobuf's tail is highly coupled to what method is currently\n///     executing.\n/// - The class recursively uses itself when performing period finding on loops. It is seriously\n///     hard to directly inspect and understand the current state when period finding is happening\n///     inside of period finding.\n/// - When period finding succeeds it flushes the recorded errors to avoid crosstalk between the\n///     in-loop errors and out-of-loop errors. The state of the buffers is coupled across features.\n/// - Error decomposition is done using heuristics that are not guaranteed to work, and prone to\n///     being tweaked, creating churn. Also the decomposition code itself is quite complex in order\n///     to make it fast (e.g. reducing the explicit detectors into bitmasks and then working with\n///     the bitmasks).\n/// - I guess what I'm saying is... have fun!\nstruct ErrorAnalyzer {\n    SparseUnsignedRevFrameTracker tracker;\n\n    /// When false, no error decomposition is performed.\n    /// When true, must decompose any non-graphlike error into graphlike components or fail.\n    bool decompose_errors;\n\n    /// When false, errors are skipped over instead of recorded.\n    /// When true, errors are recorded into the error_class_probabilities dictionary.\n    bool accumulate_errors;\n\n    /// When false, loops are flattened and directly iterated over.\n    /// When true, a tortoise-and-hare algorithm is used to notice periodicity in the errors.\n    /// If periodicity is found, the rest of the loop becomes a loop in the output error model.\n    bool fold_loops;\n\n    /// When false, detectors with non-deterministic parities under noiseless execution cause failure.\n    /// When true, the non-determinism is translated into a 50/50 random error mechanisms.\n    bool allow_gauge_detectors;\n\n    /// Determines how small the probabilities in disjoint error mechanisms like PAULI_CHANNEL_2 must be\n    /// before they can be approximated as being independent. Any larger probabilities cause failure.\n    double approximate_disjoint_errors_threshold;\n\n    /// When true, errors that fail to decompose are inserted into the output\n    /// undecomposed instead of raising an exception that terminates the\n    /// conversion from circuit to detector error model.\n    ///\n    /// Only relevant when decompose_errors=True.\n    bool ignore_decomposition_failures;\n\n    /// When true, decomposition is permitted to split A B C D into A B ^ C D\n    /// when only one of A B or C D exists elsewhere, instead of requiring both\n    /// to exist. This can reduce the code distance of the decoding graph, but\n    /// is sometimes necessary.\n    ///\n    /// Only relevant when decompose_errors=True.\n    bool block_decomposition_from_introducing_remnant_edges;\n\n    /// A buffer containing the growing output error model as the circuit is traversed.\n    /// The buffer is in reverse order because the circuit is traversed back to front.\n    /// Certain events during period solving of loops can cause the error probabilities\n    /// to flush into this buffer.\n    DetectorErrorModel flushed_reversed_model;\n\n    /// Recorded errors. Independent probabilities of flipping various sets of detectors.\n    std::map<ErrorEquivalenceClass, double> error_class_probabilities;\n    /// Backing datastore for values in error_class_probabilities.\n    MonotonicBuffer<DemTarget> mono_buf;\n\n    /// Counts the number of tick operations, for better debug messages.\n    uint64_t num_ticks_in_past = 0;\n\n    /// Used for producing debug information when errors occur.\n    const Circuit *current_circuit_being_analyzed = nullptr;\n\n    /// Creates an instance ready to start processing instructions from a circuit of known size.\n    ErrorAnalyzer(\n        uint64_t num_measurements,\n        uint64_t num_detectors,\n        size_t num_qubits,\n        uint64_t num_ticks,\n        bool decompose_errors,\n        bool fold_loops,\n        bool allow_gauge_detectors,\n        double approximate_disjoint_errors_threshold,\n        bool ignore_decomposition_failures,\n        bool block_decomposition_from_introducing_remnant_edges);\n\n    /// Returns the detector error model of the given circuit.\n    ///\n    /// Args:\n    ///     circuit: The circuit to analyze.\n    ///     decompose_errors: When true, complex errors must be split into graphlike components.\n    ///     fold_loops: When true, use a tortoise-and-hare algorithm to solve loops instead of flattening them.\n    ///     allow_gauge_detectors: When true, replace non-deterministic detectors with 50/50 error mechanisms instead\n    ///         of failing.\n    ///     approximate_disjoint_errors_threshold: When larger than 0, allows disjoint errors like PAULI_CHANNEL_2 to\n    ///         be present in the circuit, as long as their probabilities are not larger than this.\n    ///     ignore_decomposition_failures: Determines whether errors that that fail to decompose are inserted into the\n    ///         output, or cause the conversion to fail and raise an exception.\n    ///     block_decomposition_from_introducing_remnant_edges: When true, it is not permitted to decompose A B C D\n    ///         into A B ^ C D unless both A B and C D appear elsewhere in the error model. When false, only one has\n    ///         to appear elsewhere.\n    ///\n    /// Returns:\n    ///     The detector error model.\n    static DetectorErrorModel circuit_to_detector_error_model(\n        const Circuit &circuit,\n        bool decompose_errors,\n        bool fold_loops,\n        bool allow_gauge_detectors,\n        double approximate_disjoint_errors_threshold,\n        bool ignore_decomposition_failures,\n        bool block_decomposition_from_introducing_remnant_edges);\n\n    /// Copying is unsafe because `error_class_probabilities` has overlapping pointers to `monobuf`'s internals.\n    ErrorAnalyzer(const ErrorAnalyzer &analyzer) = delete;\n    ErrorAnalyzer(ErrorAnalyzer &&analyzer) noexcept = delete;\n    ErrorAnalyzer &operator=(ErrorAnalyzer &&analyzer) noexcept = delete;\n    ErrorAnalyzer &operator=(const ErrorAnalyzer &analyzer) = delete;\n\n    void undo_SHIFT_COORDS(const CircuitInstruction &inst);\n    void undo_RX(const CircuitInstruction &inst);\n    void undo_RY(const CircuitInstruction &inst);\n    void undo_RZ(const CircuitInstruction &inst);\n    void undo_MX(const CircuitInstruction &inst);\n    void undo_MY(const CircuitInstruction &inst);\n    void undo_MZ(const CircuitInstruction &inst);\n    void undo_MPP(const CircuitInstruction &inst);\n    void undo_SPP(const CircuitInstruction &inst);\n    void undo_MXX(const CircuitInstruction &inst);\n    void undo_MYY(const CircuitInstruction &inst);\n    void undo_MZZ(const CircuitInstruction &inst);\n    void undo_MPAD(const CircuitInstruction &inst);\n    void undo_HERALDED_ERASE(const CircuitInstruction &inst);\n    void undo_HERALDED_PAULI_CHANNEL_1(const CircuitInstruction &inst);\n    void undo_MRX(const CircuitInstruction &inst);\n    void undo_MRY(const CircuitInstruction &inst);\n    void undo_MRZ(const CircuitInstruction &inst);\n    void undo_H_XZ(const CircuitInstruction &inst);\n    void undo_H_XY(const CircuitInstruction &inst);\n    void undo_H_YZ(const CircuitInstruction &inst);\n    void undo_C_XYZ(const CircuitInstruction &inst);\n    void undo_C_ZYX(const CircuitInstruction &inst);\n    void undo_XCX(const CircuitInstruction &inst);\n    void undo_XCY(const CircuitInstruction &inst);\n    void undo_XCZ(const CircuitInstruction &inst);\n    void undo_YCX(const CircuitInstruction &inst);\n    void undo_YCY(const CircuitInstruction &inst);\n    void undo_YCZ(const CircuitInstruction &inst);\n    void undo_ZCX(const CircuitInstruction &inst);\n    void undo_ZCY(const CircuitInstruction &inst);\n    void undo_ZCZ(const CircuitInstruction &inst);\n    void undo_I(const CircuitInstruction &inst);\n    void undo_TICK(const CircuitInstruction &inst);\n    void undo_SQRT_XX(const CircuitInstruction &inst);\n    void undo_SQRT_YY(const CircuitInstruction &inst);\n    void undo_SQRT_ZZ(const CircuitInstruction &inst);\n    void undo_SWAP(const CircuitInstruction &inst);\n    void undo_DETECTOR(const CircuitInstruction &inst);\n    void undo_OBSERVABLE_INCLUDE(const CircuitInstruction &inst);\n    void undo_X_ERROR(const CircuitInstruction &inst);\n    void undo_Y_ERROR(const CircuitInstruction &inst);\n    void undo_Z_ERROR(const CircuitInstruction &inst);\n    void undo_CORRELATED_ERROR(const CircuitInstruction &inst);\n    void undo_DEPOLARIZE1(const CircuitInstruction &inst);\n    void undo_DEPOLARIZE2(const CircuitInstruction &inst);\n    void undo_ELSE_CORRELATED_ERROR(const CircuitInstruction &inst);\n    void undo_PAULI_CHANNEL_1(const CircuitInstruction &inst);\n    void undo_PAULI_CHANNEL_2(const CircuitInstruction &inst);\n    void undo_ISWAP(const CircuitInstruction &inst);\n    void undo_CXSWAP(const CircuitInstruction &inst);\n    void undo_CZSWAP(const CircuitInstruction &inst);\n    void undo_SWAPCX(const CircuitInstruction &inst);\n\n    void undo_RX_with_context(const CircuitInstruction &inst, const char *context_op);\n    void undo_RY_with_context(const CircuitInstruction &inst, const char *context_op);\n    void undo_RZ_with_context(const CircuitInstruction &inst, const char *context_op);\n    void undo_MX_with_context(const CircuitInstruction &inst, const char *context_op);\n    void undo_MY_with_context(const CircuitInstruction &inst, const char *context_op);\n    void undo_MZ_with_context(const CircuitInstruction &inst, const char *context_op);\n\n    /// Processes each of the instructions in the circuit, in reverse order.\n    void undo_circuit(const Circuit &circuit);\n    /// This is used at the end of the analysis to check that any remaining sensitivities commute\n    /// with the implicit Z basis initialization at the start of a circuit.\n    void post_check_initialization();\n\n    void undo_gate(const CircuitInstruction &inst);\n\n    /// Returns a PauliString indicating the current error sensitivity of a detector or observable.\n    ///\n    /// The observable or detector is sensitive to the Pauli error P at q if the Pauli sensitivity\n    /// at q anti-commutes with P.\n    PauliString<MAX_BITWORD_WIDTH> current_error_sensitivity_for(DemTarget t) const;\n\n    /// Processes the instructions in a circuit multiple times.\n    /// If loop folding is enabled, also uses a tortoise-and-hare algorithm to attempt to solve the loop's period.\n    void run_loop(const Circuit &loop, uint64_t iterations, std::string_view tag);\n\n   private:\n    /// When detectors anti-commute with a reset, that set of detectors becomes a degree of freedom.\n    /// Use that degree of freedom to delete the largest detector in the set from the system.\n    void remove_gauge(SpanRef<const DemTarget> sorted);\n    /// Sorts the targets coming out of the measurement queue, then optionally inserts a measurement error.\n    void xor_sorted_measurement_error(SpanRef<const DemTarget> targets, const CircuitInstruction &dat);\n    /// Checks if the given sparse vector is empty. If it isn't, something that was supposed to be\n    /// deterministic is actually random. Produces an error message with debug information that can be\n    /// used to understand what went wrong.\n    void check_for_gauge(\n        const SparseXorVec<DemTarget> &potential_gauge,\n        const char *context_op,\n        uint64_t context_qubit,\n        std::string_view tag);\n    /// Checks if the given sparse vectors are equal. If they aren't, something that was supposed to be\n    /// deterministic is actually random. Produces an error message with debug information that can be\n    /// used to understand what went wrong.\n    void check_for_gauge(\n        SparseXorVec<DemTarget> &potential_gauge_summand_1,\n        const SparseXorVec<DemTarget> &potential_gauge_summand_2,\n        const char *context_op,\n        uint64_t context_qubit,\n        std::string_view tag);\n\n    /// Empties error_class_probabilities into flushed_reversed_model.\n    void flush();\n    /// Adds (or folds) an error mechanism into error_class_probabilities.\n    ErrorEquivalenceClass add_error(double probability, SpanRef<const DemTarget> flipped_sorted, std::string_view tag);\n    /// Adds (or folds) an error mechanism equal into error_class_probabilities.\n    /// The error is defined as the xor of two sparse vectors, because this is a common situation.\n    /// Deals with the details of efficiently computing the xor of the vectors with minimal allocations.\n    ErrorEquivalenceClass add_xored_error(\n        double probability, SpanRef<const DemTarget> flipped1, SpanRef<const DemTarget> flipped2, std::string_view tag);\n    /// Adds an error mechanism into error_class_probabilities.\n    /// The error mechanism is not passed as an argument but is instead the current tail of `this->mono_buf`.\n    ErrorEquivalenceClass add_error_in_sorted_jagged_tail(double probability, std::string_view tag);\n    /// Saves the current tail of the monotonic buffer, deduping it to equal already stored data if possible.\n    ///\n    /// Returns:\n    ///    A range over the stored data.\n    ErrorEquivalenceClass mono_dedupe_store_tail(std::string_view tag);\n    /// Saves data to the monotonic buffer, deduping it to equal already stored data if possible.\n    ///\n    /// Args:\n    ///     data: A range of data to store.\n    ///\n    /// Returns:\n    ///    A range over the stored data.\n    ErrorEquivalenceClass mono_dedupe_store(ErrorEquivalenceClass sorted);\n\n    /// Adds each given error, and also each possible combination of the given errors, to the possible errors.\n    ///\n    /// Does analysis of which errors reduce to other errors (in the detector basis, not the given basis).\n    ///\n    /// Args:\n    ///     independent_probabilities: Probability of each error combination (including but ignoring the empty\n    ///         combination) occurring, independent of whether or not the others occurred.\n    ///     basis_errors: Building blocks for the error combinations.\n    template <size_t s>\n    void add_error_combinations(\n        std::array<double, 1 << s> probabilities,\n        std::array<SpanRef<const DemTarget>, s> basis_errors,\n        bool probabilities_are_disjoint,\n        std::string_view tag);\n\n    /// Handles local decomposition of errors.\n    /// When an error has multiple channels, eg. a DEPOLARIZE2 error, this method attempts to express the more complex\n    /// channels (the ones with more symptoms) in terms of the simpler ones that have just 1 or 2 symptoms.\n    /// Works by rewriting the `stored_ids` argument.\n    template <size_t s>\n    void decompose_helper_add_error_combinations(\n        const std::array<uint64_t, 1 << s> &detector_masks,\n        std::array<SpanRef<const DemTarget>, 1 << s> &stored_ids,\n        std::string_view tag);\n\n    /// Handles global decomposition of errors.\n    /// When an error has more than two symptoms, this method attempts to find other known errors that can be used as\n    /// components of this error, so that it is decomposed into graphlike components.\n    bool decompose_and_append_component_to_tail(\n        SpanRef<const DemTarget> component,\n        const std::map<FixedCapVector<DemTarget, 2>, SpanRef<const DemTarget>> &known_symptoms);\n\n    /// Performs a final check that all errors are decomposed.\n    /// If any aren't, attempts to decompose them using other errors in the system.\n    void do_global_error_decomposition_pass();\n\n    /// Checks whether there any errors that need decomposing.\n    bool has_unflushed_ungraphlike_errors() const;\n\n   private:\n    void undo_MXX_disjoint_controls_segment(const CircuitInstruction &inst);\n    void undo_MYY_disjoint_controls_segment(const CircuitInstruction &inst);\n    void undo_MZZ_disjoint_controls_segment(const CircuitInstruction &inst);\n    void check_can_approximate_disjoint(\n        const char *op_name, SpanRef<const double> probabilities, bool allow_single_component) const;\n    void add_composite_error(double probability, SpanRef<const GateTarget> targets, std::string_view tag);\n    void correlated_error_block(const std::vector<CircuitInstruction> &dats);\n};\n\n/// Determines if an error's targets are graphlike.\n///\n/// An error is graphlike if it has at most two symptoms (two detectors) per component.\n/// For example, error(0.1) D0 D1 ^ D2 D3 L55 is graphlike but error(0.1) D0 D1 ^ D2 D3 D55 is not.\nbool is_graphlike(const SpanRef<const DemTarget> &components);\n\nbool brute_force_decomposition_into_known_graphlike_errors(\n    SpanRef<const DemTarget> problem,\n    const std::map<FixedCapVector<DemTarget, 2>, SpanRef<const DemTarget>> &known_graphlike_errors,\n    MonotonicBuffer<DemTarget> &output);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/error_analyzer.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/error_analyzer.h\"\n\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(ErrorAnalyzer_surface_code_rotated_memory_z_d11_r100) {\n    auto params = CircuitGenParameters(100, 11, \"rotated_memory_z\");\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    benchmark_go([&]() {\n        ErrorAnalyzer analyzer(\n            circuit.count_measurements(),\n            circuit.count_detectors(),\n            circuit.count_qubits(),\n            circuit.count_ticks(),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n        analyzer.undo_circuit(circuit);\n    }).goal_millis(320);\n}\n\nBENCHMARK(ErrorAnalyzer_surface_code_rotated_memory_z_d11_r100_find_reducible_errors) {\n    auto params = CircuitGenParameters(100, 11, \"rotated_memory_z\");\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    benchmark_go([&]() {\n        ErrorAnalyzer analyzer(\n            circuit.count_measurements(),\n            circuit.count_detectors(),\n            circuit.count_qubits(),\n            circuit.count_ticks(),\n            true,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n        analyzer.undo_circuit(circuit);\n    }).goal_millis(450);\n}\n\nBENCHMARK(ErrorAnalyzer_surface_code_rotated_memory_z_d11_r100000000_find_loops) {\n    auto params = CircuitGenParameters(100000000, 11, \"rotated_memory_z\");\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    benchmark_go([&]() {\n        ErrorAnalyzer analyzer(\n            circuit.count_measurements(),\n            circuit.count_detectors(),\n            circuit.count_qubits(),\n            circuit.count_ticks(),\n            false,\n            true,\n            false,\n            0.0,\n            false,\n            true);\n        analyzer.undo_circuit(circuit);\n    }).goal_millis(15);\n}\n"
  },
  {
    "path": "src/stim/simulators/error_analyzer.test.cc",
    "content": "#include \"stim/simulators/error_analyzer.h\"\n\n#include <regex>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/util_bot/test_util.test.h\"\n#include \"stim/util_top/circuit_to_dem.h\"\n\nusing namespace stim;\n\nTEST(ErrorAnalyzer, circuit_to_detector_error_model) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                X_ERROR(0.25) 3\n                M 3\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                X_ERROR(0.25) 3\n                M 3\n                DETECTOR rec[-1]\n                OBSERVABLE_INCLUDE(0) rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0 L0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                Y_ERROR(0.25) 3\n                M 3\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                Z_ERROR(0.25) 3\n                M 3\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            detector D0\n        )model\"));\n\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                DEPOLARIZE1(0.25) 3\n                M 3\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.166666) D0\n            )model\"),\n                1e-4));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                X_ERROR(0.25) 0\n                X_ERROR(0.125) 1\n                M 0 1\n                OBSERVABLE_INCLUDE(3) rec[-1]\n                DETECTOR rec[-2]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n            error(0.125) L3\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                X_ERROR(0.25) 0\n                X_ERROR(0.125) 1\n                M 0 1\n                OBSERVABLE_INCLUDE(3) rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n            error(0.125) L3\n        )model\"));\n\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                        DEPOLARIZE2(0.25) 3 5\n                        M 3\n                        M 5\n                        DETECTOR rec[-1]\n                        DETECTOR rec[-2]\n                    )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.0718255) D0\n                error(0.0718255) D0 D1\n                error(0.0718255) D1\n            )model\"),\n                1e-5));\n\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                        H 0 1\n                        CNOT 0 2 1 3\n                        DEPOLARIZE2(0.25) 0 1\n                        CNOT 0 2 1 3\n                        H 0 1\n                        M 0 1 2 3\n                        DETECTOR rec[-1]\n                        DETECTOR rec[-2]\n                        DETECTOR rec[-3]\n                        DETECTOR rec[-4]\n                    )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.019013) D0\n                error(0.019013) D0 D1\n                error(0.019013) D0 D1 D2\n                error(0.019013) D0 D1 D2 D3\n                error(0.019013) D0 D1 D3\n                error(0.019013) D0 D2\n                error(0.019013) D0 D2 D3\n                error(0.019013) D0 D3\n                error(0.019013) D1\n                error(0.019013) D1 D2\n                error(0.019013) D1 D2 D3\n                error(0.019013) D1 D3\n                error(0.019013) D2\n                error(0.019013) D2 D3\n                error(0.019013) D3\n            )model\"),\n                1e-4));\n\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                        H 0 1\n                        CNOT 0 2 1 3\n                        DEPOLARIZE2(0.25) 0 1\n                        CNOT 0 2 1 3\n                        H 0 1\n                        M 0 1 2 3\n                        DETECTOR rec[-1]\n                        DETECTOR rec[-2]\n                        DETECTOR rec[-3]\n                        DETECTOR rec[-4]\n                    )circuit\"),\n            true,\n            false,\n            false,\n            0.0,\n            false,\n            true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.019013) D0\n                error(0.019013) D1\n                error(0.019013) D1 ^ D0\n                error(0.019013) D1 ^ D2\n                error(0.019013) D1 ^ D2 ^ D0\n                error(0.019013) D2\n                error(0.019013) D2 ^ D0\n                error(0.019013) D3\n                error(0.019013) D3 ^ D0\n                error(0.019013) D3 ^ D1\n                error(0.019013) D3 ^ D1 ^ D0\n                error(0.019013) D3 ^ D1 ^ D2\n                error(0.019013) D3 ^ D1 ^ D2 ^ D0\n                error(0.019013) D3 ^ D2\n                error(0.019013) D3 ^ D2 ^ D0\n            )model\"),\n                1e-4));\n\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                        H 0 1\n                        CNOT 0 2 1 3\n                        # Perform depolarizing error in a different basis.\n                        ZCX 0 10\n                        ZCX 0 11\n                        XCX 0 12\n                        XCX 0 13\n                        DEPOLARIZE2(0.25) 0 1\n                        XCX 0 13\n                        XCX 0 12\n                        ZCX 0 11\n                        ZCX 0 10\n                        # Check where error is.\n                        M 10 11 12 13\n                        DETECTOR rec[-1]\n                        DETECTOR rec[-2]\n                        DETECTOR rec[-3]\n                        DETECTOR rec[-4]\n                    )circuit\"),\n            true,\n            false,\n            true,\n            0.0,\n            false,\n            true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.071825) D0 D1\n                error(0.071825) D0 D1 ^ D2 D3\n                error(0.071825) D2 D3\n            )model\"),\n                1e-4));\n}\n\nTEST_EACH_WORD_SIZE_W(ErrorAnalyzer, unitary_gates_match_frame_simulator, {\n    CircuitStats stats;\n    stats.num_qubits = 16;\n    stats.num_measurements = 100;\n    FrameSimulator<W> f(stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 16, INDEPENDENT_TEST_RNG());\n    ErrorAnalyzer e(100, 1, 16, 100, false, false, false, 0.0, false, true);\n    for (size_t q = 0; q < 16; q++) {\n        if (q & 1) {\n            e.tracker.xs[q].xor_item({0});\n            f.x_table[q][0] = true;\n        }\n        if (q & 2) {\n            e.tracker.xs[q].xor_item({1});\n            f.x_table[q][1] = true;\n        }\n        if (q & 4) {\n            e.tracker.zs[q].xor_item({0});\n            f.z_table[q][0] = true;\n        }\n        if (q & 8) {\n            e.tracker.zs[q].xor_item({1});\n            f.z_table[q][1] = true;\n        }\n    }\n\n    std::vector<GateTarget> data;\n    for (size_t k = 0; k < 16; k++) {\n        data.push_back(GateTarget::qubit(k));\n    }\n    for (const auto &gate : GATE_DATA.items) {\n        if (gate.has_known_unitary_matrix()) {\n            e.undo_gate(CircuitInstruction{gate.id, {}, data, \"\"});\n            f.do_gate(CircuitInstruction{gate.inverse().id, {}, data, \"\"});\n            for (size_t q = 0; q < 16; q++) {\n                bool xs[2]{};\n                bool zs[2]{};\n                for (auto x : e.tracker.xs[q]) {\n                    ASSERT_TRUE(x.data < 2) << gate.name;\n                    xs[x.data] = true;\n                }\n                for (auto z : e.tracker.zs[q]) {\n                    ASSERT_TRUE(z.data < 2) << gate.name;\n                    zs[z.data] = true;\n                }\n                ASSERT_EQ(f.x_table[q][0], xs[0]) << gate.name;\n                ASSERT_EQ(f.x_table[q][1], xs[1]) << gate.name;\n                ASSERT_EQ(f.z_table[q][0], zs[0]) << gate.name;\n                ASSERT_EQ(f.z_table[q][1], zs[1]) << gate.name;\n            }\n        }\n    }\n})\n\nTEST(ErrorAnalyzer, reversed_operation_order) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                X_ERROR(0.25) 0\n                CNOT 0 1\n                CNOT 1 0\n                M 0 1\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D1\n            detector D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                X_ERROR(0.25) 0\n                CNOT 0 1\n                CNOT 1 0\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n            detector D1\n        )model\"));\n}\n\nTEST(ErrorAnalyzer, classical_error_propagation) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                X_ERROR(0.125) 0\n                M 0\n                CNOT rec[-1] 1\n                M 1\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.125) D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            X_ERROR(0.125) 0\n            M 0\n            H 1\n            CZ rec[-1] 1\n            H 1\n            M 1\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.125) D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            X_ERROR(0.125) 0\n            M 0\n            H 1\n            CZ 1 rec[-1]\n            H 1\n            M 1\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.125) D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            X_ERROR(0.125) 0\n            M 0\n            CY rec[-1] 1\n            M 1\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.125) D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            X_ERROR(0.125) 0\n            M 0\n            XCZ 1 rec[-1]\n            M 1\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.125) D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            X_ERROR(0.125) 0\n            M 0\n            YCZ 1 rec[-1]\n            M 1\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.125) D0\n        )model\"));\n}\n\nTEST(ErrorAnalyzer, measure_reset_basis) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                RZ 0 1 2\n                X_ERROR(0.25) 0\n                Y_ERROR(0.25) 1\n                Z_ERROR(0.25) 2\n                MZ 0 1 2\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n            error(0.25) D1\n            detector D2\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            RX 0 1 2\n            X_ERROR(0.25) 0\n            Y_ERROR(0.25) 1\n            Z_ERROR(0.25) 2\n            MX 0 1 2\n            DETECTOR rec[-3]\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D1\n            error(0.25) D2\n            detector D0\n        )model\"));\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            RY 0 1 2\n            X_ERROR(0.25) 0\n            Y_ERROR(0.25) 1\n            Z_ERROR(0.25) 2\n            MY 0 1 2\n            DETECTOR rec[-3]\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n            error(0.25) D2\n            detector D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                MRZ 0 1 2\n                X_ERROR(0.25) 0\n                Y_ERROR(0.25) 1\n                Z_ERROR(0.25) 2\n                MRZ 0 1 2\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n            error(0.25) D1\n            detector D2\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                MRX 0 1 2\n                X_ERROR(0.25) 0\n                Y_ERROR(0.25) 1\n                Z_ERROR(0.25) 2\n                MRX 0 1 2\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D1\n            error(0.25) D2\n            detector D0\n        )model\"));\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                MRY 0 1 2\n                X_ERROR(0.25) 0\n                Y_ERROR(0.25) 1\n                Z_ERROR(0.25) 2\n                MRY 0 1 2\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n            error(0.25) D2\n            detector D1\n        )model\"));\n}\n\nTEST(ErrorAnalyzer, repeated_measure_reset) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            MRZ 0 0\n            X_ERROR(0.25) 0\n            MRZ 0 0\n            DETECTOR rec[-4]\n            DETECTOR rec[-3]\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D2\n            detector D0\n            detector D1\n            detector D3\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            RY 0 0\n            MRY 0 0\n            X_ERROR(0.25) 0\n            MRY 0 0\n            DETECTOR rec[-4]\n            DETECTOR rec[-3]\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D2\n            detector D0\n            detector D1\n            detector D3\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                RX 0 0\n                MRX 0 0\n                Z_ERROR(0.25) 0\n                MRX 0 0\n                DETECTOR rec[-4]\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D2\n            detector D0\n            detector D1\n            detector D3\n        )model\"));\n}\n\nTEST(ErrorAnalyzer, period_3_gates) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            RY 0 1 2\n            X_ERROR(1) 0\n            Y_ERROR(1) 1\n            Z_ERROR(1) 2\n            C_XYZ 0 1 2\n            M 0 1 2\n            DETECTOR rec[-3]\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(1) D0\n            error(1) D2\n            detector D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            R 0 1 2\n            C_XYZ 0 1 2\n            X_ERROR(1) 0\n            Y_ERROR(1) 1\n            Z_ERROR(1) 2\n            C_ZYX 0 1 2\n            M 0 1 2\n            DETECTOR rec[-3]\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(1) D1\n            error(1) D2\n            detector D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            R 0 1 2\n            C_ZYX 0 1 2\n            X_ERROR(1) 0\n            Y_ERROR(1) 1\n            Z_ERROR(1) 2\n            C_XYZ 0 1 2\n            M 0 1 2\n            DETECTOR rec[-3]\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(1) D0\n            error(1) D2\n            detector D1\n        )model\"));\n}\n\nTEST(ErrorAnalyzer, detect_gauge_observables) {\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                R 0\n                H 0\n                M 0\n                OBSERVABLE_INCLUDE(0) rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                R 0\n                H 0\n                M 0\n                OBSERVABLE_INCLUDE(0) rec[-1]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true);\n    });\n}\n\nTEST(ErrorAnalyzer, detect_gauge_detectors) {\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                R 0\n                H 0\n                M 0\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                M 0\n                H 0\n                M 0\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                MZ 0\n                MX 0\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                MY 0\n                MX 0\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                MX 0\n                MZ 0\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                RX 0\n                MZ 0\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                RY 0\n                MX 0\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                RZ 0\n                MX 0\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n\n    ASSERT_ANY_THROW({\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                MX 0\n                DETECTOR rec[-1]\n            )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true);\n    });\n}\n\nTEST(ErrorAnalyzer, gauge_detectors) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                H 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n                error(0.5) D0 D1\n            )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                R 0\n                H 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.5) D0 D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n                RX 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.5) D0 D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                RY 0\n                H_XY 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.5) D0 D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                MR 0\n                H 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.5) D0 D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                MRX 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.5) D0 D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                MRY 0\n                H_XY 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.5) D0 D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                M 0\n                H 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.5) D0 D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n                MX 0\n                CNOT 0 1\n                M 0 1\n                DETECTOR rec[-1]\n                DETECTOR rec[-2]\n            )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.5) D0 D1\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                R\"circuit(\n            MY 0\n            H_XY 0\n            CNOT 0 1\n            M 0 1\n            DETECTOR rec[-1]\n            DETECTOR rec[-2]\n        )circuit\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.5) D0 D1\n        )model\"));\n}\n\nTEST(ErrorAnalyzer, composite_error_analysis) {\n    auto measure_stabilizers = Circuit(R\"circuit(\n        XCX 0 1 0 3 0 4\n        MR 0\n        XCZ 0 1 0 2 0 4 0 5\n        MR 0\n        XCX 0 2 0 5 0 6\n        MR 0\n        XCZ 0 3 0 4 0 7\n        MR 0\n        XCX 0 4 0 5 0 7 0 8\n        MR 0\n        XCZ 0 5 0 6 0 7\n        MR 0\n    )circuit\");\n    auto detectors = Circuit(R\"circuit(\n        DETECTOR rec[-6] rec[-12]\n        DETECTOR rec[-5] rec[-11]\n        DETECTOR rec[-4] rec[-10]\n        DETECTOR rec[-3] rec[-9]\n        DETECTOR rec[-2] rec[-8]\n        DETECTOR rec[-1] rec[-7]\n    )circuit\");\n    // .  1  2  .\n    //  X0 Z1 X2\n    // 3  4  5  6\n    //  Z3 X4 Z5\n    // .  7  8  .\n\n    auto encode = measure_stabilizers;\n    auto decode = measure_stabilizers + detectors;\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(encode + Circuit(\"DEPOLARIZE1(0.01) 4\") + decode), true, false, false, 0.0, false, true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.0033445) D0 D4\n                error(0.0033445) D0 D4 ^ D1 D3\n                error(0.0033445) D1 D3\n                detector D2\n                detector D5\n            )model\"),\n                1e-6));\n\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(encode + Circuit(\"DEPOLARIZE2(0.01) 4 5\") + decode), true, false, false, 0.0, false, true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.000669) D0 D2\n                error(0.000669) D0 D2 ^ D1 D3\n                error(0.000669) D0 D2 ^ D1 D5\n                error(0.000669) D0 D2 ^ D3 D5\n                error(0.000669) D0 D4\n                error(0.000669) D0 D4 ^ D1 D3\n                error(0.000669) D0 D4 ^ D1 D5\n                error(0.000669) D0 D4 ^ D3 D5\n                error(0.000669) D1 D3\n                error(0.000669) D1 D3 ^ D2 D4\n                error(0.000669) D1 D5\n                error(0.000669) D1 D5 ^ D2 D4\n                error(0.000669) D2 D4\n                error(0.000669) D2 D4 ^ D3 D5\n                error(0.000669) D3 D5\n            )model\"),\n                1e-6));\n\n    auto expected = DetectorErrorModel(R\"model(\n        error(0.000669) D0 D1 D2 D3\n        error(0.000669) D0 D1 D2 D5\n        error(0.000669) D0 D1 D3 D4\n        error(0.000669) D0 D1 D4 D5\n        error(0.000669) D0 D2\n        error(0.000669) D0 D2 D3 D5\n        error(0.000669) D0 D3 D4 D5\n        error(0.000669) D0 D4\n        error(0.000669) D1 D2 D3 D4\n        error(0.000669) D1 D2 D4 D5\n        error(0.000669) D1 D3\n        error(0.000669) D1 D5\n        error(0.000669) D2 D3 D4 D5\n        error(0.000669) D2 D4\n        error(0.000669) D3 D5\n    )model\");\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(encode + Circuit(\"DEPOLARIZE2(0.01) 4 5\") + decode), false, false, false, 0.0, false, true)\n            .approx_equals(expected, 1e-5));\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(encode + Circuit(\"CNOT 4 5\\nDEPOLARIZE2(0.01) 4 5\\nCNOT 4 5\") + decode),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true)\n            .approx_equals(expected, 1e-5));\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(encode + Circuit(\"H_XY 4\\nCNOT 4 5\\nDEPOLARIZE2(0.01) 4 5\\nCNOT 4 5\\nH_XY 4\") + decode),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true)\n            .approx_equals(expected, 1e-5));\n}\n\nstd::string declare_detectors(size_t min, size_t max) {\n    std::stringstream result;\n    for (size_t k = min; k <= max; k++) {\n        result << \"detector D\" << k << \"\\n\";\n    }\n    return result.str();\n}\n\nTEST(ErrorAnalyzer, loop_folding) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                MR 1\n                REPEAT 12345678987654321 {\n                    X_ERROR(0.25) 0\n                    CNOT 0 1\n                    MR 1\n                    DETECTOR rec[-2] rec[-1]\n                }\n                M 0\n                OBSERVABLE_INCLUDE(9) rec[-1]\n            )CIRCUIT\"),\n            false,\n            true,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n                error(0.25) D0 L9\n                REPEAT 6172839493827159 {\n                    error(0.25) D1 L9\n                    error(0.25) D2 L9\n                    shift_detectors 2\n                }\n                error(0.25) D1 L9\n                error(0.25) D2 L9\n            )MODEL\"));\n\n    // Solve period 8 logical observable oscillation.\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            R 0 1 2 3 4\n            REPEAT 12345678987654321 {\n                CNOT 0 1 1 2 2 3 3 4\n                DETECTOR\n            }\n            M 4\n            OBSERVABLE_INCLUDE(9) rec[-1]\n        )CIRCUIT\"),\n            false,\n            true,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            detector D0\n            detector D1\n            detector D2\n            REPEAT 1543209873456789 {\n                detector D3\n                detector D4\n                detector D5\n                detector D6\n                detector D7\n                detector D8\n                detector D9\n                detector D10\n                shift_detectors 8\n            }\n            detector D3\n            detector D4\n            detector D5\n            detector D6\n            detector D7\n            detector D8\n            logical_observable L9\n        )MODEL\"));\n\n    // Solve period 127 logical observable oscillation.\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            R 0 1 2 3 4 5 6\n            REPEAT 12345678987654321 {\n                CNOT 0 1 1 2 2 3 3 4 4 5 5 6 6 0\n                DETECTOR\n            }\n            M 6\n            OBSERVABLE_INCLUDE(9) rec[-1]\n            R 7\n            X_ERROR(1) 7\n            M 7\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            true,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel((declare_detectors(0, 85) + R\"MODEL(\n            REPEAT 97210070768930 {\n                )MODEL\" + declare_detectors(86, 86 + 127 - 1) +\n                            R\"MODEL(\n                shift_detectors 127\n            }\n            error(1) D211\n            )MODEL\" + declare_detectors(86, 210) +\n                            R\"MODEL(\n            logical_observable L9\n        )MODEL\")\n                               .data()));\n}\n\nTEST(ErrorAnalyzer, loop_folding_nested_loop) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                MR 1\n                REPEAT 1000 {\n                    REPEAT 1000 {\n                        X_ERROR(0.25) 0\n                        CNOT 0 1\n                        MR 1\n                        DETECTOR rec[-2] rec[-1]\n                    }\n                }\n                M 0\n                OBSERVABLE_INCLUDE(9) rec[-1]\n            )CIRCUIT\"),\n            false,\n            true,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n                REPEAT 999 {\n                    REPEAT 1000 {\n                        error(0.25) D0 L9\n                        shift_detectors 1\n                    }\n                }\n                REPEAT 499 {\n                    error(0.25) D0 L9\n                    error(0.25) D1 L9\n                    shift_detectors 2\n                }\n                error(0.25) D0 L9\n                error(0.25) D1 L9\n            )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, loop_folding_rep_code_circuit) {\n    CircuitGenParameters params(100000, 4, \"memory\");\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_rep_code_circuit(params).circuit;\n\n    auto actual = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);\n    auto expected = DetectorErrorModel(R\"MODEL(\n        error(0.000267) D0\n        error(0.000267) D0 D1\n        error(0.000267) D0 D3\n        error(0.000533) D0 D4\n        error(0.000267) D1 D2\n        error(0.000533) D1 D4\n        error(0.000533) D1 D5\n        error(0.000267) D2 D5\n        error(0.000267) D2 L0\n        error(0.000267) D3\n        error(0.000267) D3 D4\n        error(0.000267) D3 ^ D0\n        error(0.000267) D4 D5\n        error(0.000267) D5 L0\n        error(0.000267) D5 L0 ^ D2 L0\n        detector(1, 0) D0\n        detector(3, 0) D1\n        detector(5, 0) D2\n        repeat 99998 {\n            error(0.000267) D3\n            error(0.000267) D3 D4\n            error(0.000267) D3 D6\n            error(0.000533) D3 D7\n            error(0.000267) D4 D5\n            error(0.000533) D4 D7\n            error(0.000533) D4 D8\n            error(0.000267) D5 D8\n            error(0.000267) D5 L0\n            error(0.000267) D6\n            error(0.000267) D6 D7\n            error(0.000267) D6 ^ D3\n            error(0.000267) D7 D8\n            error(0.000267) D8 L0\n            error(0.000267) D8 L0 ^ D5 L0\n            shift_detectors(0, 1) 0\n            detector(1, 0) D3\n            detector(3, 0) D4\n            detector(5, 0) D5\n            shift_detectors 3\n        }\n        error(0.000267) D3\n        error(0.000267) D3 D4\n        error(0.000267) D3 D6\n        error(0.000533) D3 D7\n        error(0.000267) D4 D5\n        error(0.000533) D4 D7\n        error(0.000533) D4 D8\n        error(0.000267) D5 D8\n        error(0.000267) D5 L0\n        error(0.000267) D6\n        error(0.000267) D6 D7\n        error(0.000267) D6 ^ D3\n        error(0.000267) D7 D8\n        error(0.000267) D8 L0\n        error(0.000267) D8 L0 ^ D5 L0\n        shift_detectors(0, 1) 0\n        detector(1, 0) D3\n        detector(3, 0) D4\n        detector(5, 0) D5\n        detector(1, 1) D6\n        detector(3, 1) D7\n        detector(5, 1) D8\n    )MODEL\");\n    ASSERT_TRUE(actual.approx_equals(expected, 0.00001)) << actual;\n}\n\nTEST(ErrorAnalyzer, multi_round_gauge_detectors_dont_grow) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                # Distance 2 Bacon-Shor.\n                ZCX 0 10 1 10\n                ZCX 2 11 3 11\n                XCX 0 12 2 12\n                XCX 1 13 3 13\n                MR 10 11 12 13\n                REPEAT 5 {\n                    ZCX 0 10 1 10\n                    ZCX 2 11 3 11\n                    XCX 0 12 2 12\n                    XCX 1 13 3 13\n                    MR 10 11 12 13\n                    DETECTOR rec[-1] rec[-5]\n                    DETECTOR rec[-2] rec[-6]\n                    DETECTOR rec[-3] rec[-7]\n                    DETECTOR rec[-4] rec[-8]\n                }\n            )CIRCUIT\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.5) D0 D1\n            error(0.5) D2 D3\n            error(0.5) D4 D5\n            error(0.5) D6 D7\n            error(0.5) D8 D9\n            error(0.5) D10 D11\n            error(0.5) D12 D13\n            error(0.5) D14 D15\n            error(0.5) D16 D17\n            error(0.5) D18 D19\n        )MODEL\"));\n\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                        # Distance 2 Bacon-Shor.\n                        ZCX 0 10 1 10\n                        ZCX 2 11 3 11\n                        XCX 0 12 2 12\n                        XCX 1 13 3 13\n                        MR 10 11 12 13\n                        REPEAT 5 {\n                            DEPOLARIZE1(0.01) 0 1 2 3\n                            ZCX 0 10 1 10\n                            ZCX 2 11 3 11\n                            XCX 0 12 2 12\n                            XCX 1 13 3 13\n                            MR 10 11 12 13\n                            DETECTOR rec[-1] rec[-5]\n                            DETECTOR rec[-2] rec[-6]\n                            DETECTOR rec[-3] rec[-7]\n                            DETECTOR rec[-4] rec[-8]\n                        }\n                    )CIRCUIT\"),\n            false,\n            false,\n            true,\n            0.0,\n            false,\n            true)\n            .approx_equals(\n                DetectorErrorModel(R\"MODEL(\n            error(0.00667) D0\n            error(0.5) D0 D1\n            error(0.00334) D0 D2\n            error(0.00334) D0 D3\n            error(0.00667) D1\n            error(0.00334) D1 D2\n            error(0.00334) D1 D3\n            error(0.00667) D2\n            error(0.5) D2 D3\n            error(0.00667) D3\n            error(0.00667) D4\n            error(0.5) D4 D5\n            error(0.00334) D4 D6\n            error(0.00334) D4 D7\n            error(0.00667) D5\n            error(0.00334) D5 D6\n            error(0.00334) D5 D7\n            error(0.00667) D6\n            error(0.5) D6 D7\n            error(0.00667) D7\n            error(0.00667) D8\n            error(0.5) D8 D9\n            error(0.00334) D8 D10\n            error(0.00334) D8 D11\n            error(0.00667) D9\n            error(0.00334) D9 D10\n            error(0.00334) D9 D11\n            error(0.00667) D10\n            error(0.5) D10 D11\n            error(0.00667) D11\n            error(0.00667) D12\n            error(0.5) D12 D13\n            error(0.00334) D12 D14\n            error(0.00334) D12 D15\n            error(0.00667) D13\n            error(0.00334) D13 D14\n            error(0.00334) D13 D15\n            error(0.00667) D14\n            error(0.5) D14 D15\n            error(0.00667) D15\n            error(0.00667) D16\n            error(0.5) D16 D17\n            error(0.00334) D16 D18\n            error(0.00334) D16 D19\n            error(0.00667) D17\n            error(0.00334) D17 D18\n            error(0.00334) D17 D19\n            error(0.00667) D18\n            error(0.5) D18 D19\n            error(0.00667) D19\n        )MODEL\"),\n                0.01));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                # Distance 2 Bacon-Shor.\n                ZCX 0 10 1 10\n                ZCX 2 11 3 11\n                XCX 0 12 2 12\n                XCX 1 13 3 13\n                MR 10 11 12 13\n                REPEAT 1000000000000000 {\n                    ZCX 0 10 1 10\n                    ZCX 2 11 3 11\n                    XCX 0 12 2 12\n                    XCX 1 13 3 13\n                    MR 10 11 12 13\n                    DETECTOR rec[-1] rec[-5]\n                    DETECTOR rec[-2] rec[-6]\n                    DETECTOR rec[-3] rec[-7]\n                    DETECTOR rec[-4] rec[-8]\n                }\n            )CIRCUIT\"),\n            false,\n            true,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.5) D0 D1\n            error(0.5) D2 D3\n            error(0.5) D6 D7\n            repeat 499999999999999 {\n                error(0.5) D4 D5\n                error(0.5) D8 D9\n                error(0.5) D10 D11\n                error(0.5) D14 D15\n                shift_detectors 8\n            }\n            error(0.5) D4 D5\n            detector D0\n            detector D1\n            detector D2\n            detector D3\n            detector D6\n            detector D7\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, coordinate_tracking) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                DETECTOR(1, 2)\n                SHIFT_COORDS(10, 20)\n                DETECTOR(100, 200)\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            detector(1, 2) D0\n            shift_detectors(10, 20) 0\n            detector(100, 200) D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                MR 1\n                REPEAT 1000 {\n                    REPEAT 1000 {\n                        X_ERROR(0.25) 0\n                        CNOT 0 1\n                        MR 1\n                        DETECTOR(1,2,3) rec[-2] rec[-1]\n                        SHIFT_COORDS(4,5)\n                    }\n                    SHIFT_COORDS(6,7)\n                }\n                M 0\n                OBSERVABLE_INCLUDE(9) rec[-1]\n            )CIRCUIT\"),\n            false,\n            true,\n            true,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n                REPEAT 999 {\n                    REPEAT 1000 {\n                        error(0.25) D0 L9\n                        detector(1, 2, 3) D0\n                        shift_detectors(4, 5) 1\n                    }\n                    shift_detectors(6, 7) 0\n                }\n                REPEAT 499 {\n                    error(0.25) D0 L9\n                    error(0.25) D1 L9\n                    detector(1, 2, 3) D0\n                    shift_detectors(4, 5) 0\n                    detector(1, 2, 3) D1\n                    shift_detectors(4, 5) 2\n                }\n                error(0.25) D0 L9\n                error(0.25) D1 L9\n                detector(1, 2, 3) D0\n                shift_detectors(4, 5) 0\n                detector(1, 2, 3) D1\n                shift_detectors(4, 5) 0\n                shift_detectors(6, 7) 0\n            )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, omit_vacuous_detector_observable_instructions) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            X_ERROR(0.25) 3\n            M 3\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            X_ERROR(0.25) 3\n            M 3\n            DETECTOR(1, 0) rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) D0\n            detector(1, 0) D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            M 3\n            DETECTOR rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            detector D0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            X_ERROR(0.25) 3\n            M 3\n            OBSERVABLE_INCLUDE(0) rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            error(0.25) L0\n        )model\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"circuit(\n            M 3\n            OBSERVABLE_INCLUDE(0) rec[-1]\n        )circuit\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"model(\n            logical_observable L0\n        )model\"));\n}\n\nTEST(ErrorAnalyzer, exact_solved_pauli_channel_1_is_let_through) {\n    auto c = Circuit(R\"CIRCUIT(\n        R 0\n        PAULI_CHANNEL_1(0.1, 0.2, 0.15) 0\n        M 0\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n    auto actual_dem = ErrorAnalyzer::circuit_to_detector_error_model(c, false, false, false, 0, false, true);\n    ASSERT_TRUE(actual_dem.approx_equals(\n        DetectorErrorModel(R\"MODEL(\n        error(0.3) D0\n    )MODEL\"),\n        1e-6));\n}\n\nTEST(ErrorAnalyzer, pauli_channel_threshold) {\n    auto c1 = Circuit(R\"CIRCUIT(\nR 0\nPAULI_CHANNEL_1(0.125, 0.25, 0.375) 0\nM 0\nDETECTOR rec[-1]\n    )CIRCUIT\");\n    auto c2 = Circuit(R\"CIRCUIT(\nR 0\nPAULI_CHANNEL_2(0.125, 0.25, 0.375, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 1 0\nM 0\nDETECTOR rec[-1]\n    )CIRCUIT\");\n\n    ASSERT_ANY_THROW({ ErrorAnalyzer::circuit_to_detector_error_model(c1, false, false, false, 0, false, true); });\n    ASSERT_ANY_THROW({ ErrorAnalyzer::circuit_to_detector_error_model(c1, false, false, false, 0.3, false, true); });\n    ASSERT_ANY_THROW({ ErrorAnalyzer::circuit_to_detector_error_model(c2, false, false, false, 0, false, true); });\n    ASSERT_ANY_THROW({ ErrorAnalyzer::circuit_to_detector_error_model(c2, false, false, false, 0.3, false, true); });\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(c1, false, false, false, 0.38, false, true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.375) D0\n        )MODEL\"));\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(c1, false, false, false, 1, false, true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.375) D0\n        )MODEL\"));\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(c2, false, false, false, 0.38, false, true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.375) D0\n        )MODEL\"));\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(c2, false, false, false, 1, false, true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.375) D0\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, pauli_channel_composite_errors) {\n    auto measure_stabilizers = Circuit(R\"circuit(\n        XCX 0 1 0 3 0 4\n        MR 0\n        XCZ 0 1 0 2 0 4 0 5\n        MR 0\n        XCX 0 2 0 5 0 6\n        MR 0\n        XCZ 0 3 0 4 0 7\n        MR 0\n        XCX 0 4 0 5 0 7 0 8\n        MR 0\n        XCZ 0 5 0 6 0 7\n        MR 0\n    )circuit\");\n    auto detectors = Circuit(R\"circuit(\n        DETECTOR rec[-6] rec[-12]\n        DETECTOR rec[-5] rec[-11]\n        DETECTOR rec[-4] rec[-10]\n        DETECTOR rec[-3] rec[-9]\n        DETECTOR rec[-2] rec[-8]\n        DETECTOR rec[-1] rec[-7]\n    )circuit\");\n\n    // .  1  2  .\n    //  X0 Z1 X2\n    // 3  4  5  6\n    //  Z3 X4 Z5\n    // .  7  8  .\n\n    auto encode = measure_stabilizers;\n    auto decode = measure_stabilizers + detectors;\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(encode + Circuit(\"PAULI_CHANNEL_1(0.00001, 0.02, 0.03) 4\") + decode),\n            true,\n            false,\n            false,\n            0.1,\n            false,\n            true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.03) D0 D4\n                error(0.02) D0 D4 ^ D1 D3\n                error(0.00001) D1 D3\n                detector D2\n                detector D5\n            )model\"),\n                1e-6));\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(encode + Circuit(\"PAULI_CHANNEL_1(0.00001, 0.02, 0.03) 5\") + decode),\n            true,\n            false,\n            false,\n            0.1,\n            false,\n            true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.00001) D1 D5\n                error(0.02) D1 D5 ^ D2 D4\n                error(0.03) D2 D4\n                detector D0\n                detector D3\n            )model\"),\n                1e-6));\n\n    ASSERT_TRUE(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(\n                encode +\n                Circuit(\n                    \"PAULI_CHANNEL_2(0.001,0.002,0.003,0.004,0.005,0.006,0.007,0.008,0.009,0.010,0.\"\n                    \"011,0.\"\n                    \"012,0.013,0.014,0.015) 4 5\") +\n                decode),\n            true,\n            false,\n            false,\n            0.02,\n            false,\n            true)\n            .approx_equals(\n                DetectorErrorModel(R\"model(\n                error(0.015) D0 D2          # ZZ\n                error(0.011) D0 D2 ^ D1 D3  # YZ\n                error(0.014) D0 D2 ^ D1 D5  # ZY\n                error(0.010) D0 D2 ^ D3 D5  # YY\n                error(0.012) D0 D4          # Z_ basis\n                error(0.008) D0 D4 ^ D1 D3  # Y_\n                error(0.013) D0 D4 ^ D1 D5  # ZX\n                error(0.009) D0 D4 ^ D3 D5  # YX\n                error(0.004) D1 D3          # X_ basis\n                error(0.007) D1 D3 ^ D2 D4  # XZ\n                error(0.001) D1 D5          # _X basis\n                error(0.002) D1 D5 ^ D2 D4  # _Y\n                error(0.003) D2 D4          # _Z basis\n                error(0.006) D2 D4 ^ D3 D5  # XY\n                error(0.005) D3 D5          # XX\n            )model\"),\n                1e-6));\n}\n\nTEST(ErrorAnalyzer, duplicate_records_in_detectors) {\n    auto m0 = ErrorAnalyzer::circuit_to_detector_error_model(\n        Circuit(R\"CIRCUIT(\n            X_ERROR(0.25) 0\n            M 0\n            DETECTOR\n        )CIRCUIT\"),\n        false,\n        false,\n        false,\n        false,\n        false,\n        true);\n    auto m1 = ErrorAnalyzer::circuit_to_detector_error_model(\n        Circuit(R\"CIRCUIT(\n            X_ERROR(0.25) 0\n            M 0\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        false,\n        false,\n        false,\n        false,\n        false,\n        true);\n    auto m2 = ErrorAnalyzer::circuit_to_detector_error_model(\n        Circuit(R\"CIRCUIT(\n            X_ERROR(0.25) 0\n            M 0\n            DETECTOR rec[-1] rec[-1]\n        )CIRCUIT\"),\n        false,\n        false,\n        false,\n        false,\n        false,\n        true);\n    auto m3 = ErrorAnalyzer::circuit_to_detector_error_model(\n        Circuit(R\"CIRCUIT(\n            X_ERROR(0.25) 0\n            M 0\n            DETECTOR rec[-1] rec[-1] rec[-1]\n        )CIRCUIT\"),\n        false,\n        false,\n        false,\n        false,\n        false,\n        true);\n    ASSERT_EQ(m0, m2);\n    ASSERT_EQ(m1, m3);\n}\n\nTEST(ErrorAnalyzer, noisy_measurement_mx) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RX 0\n            MX(0.125) 0\n            MX 0\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            false,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n            detector D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RX 0 1\n            Y_ERROR(1) 0 1\n            MX(0.125) 0 1\n            MX 0 1\n            DETECTOR rec[-4]\n            DETECTOR rec[-3]\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            false,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n            error(1) D0 D2\n            error(0.125) D1\n            error(1) D1 D3\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, noisy_measurement_my) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RY 0\n            MY(0.125) 0\n            MY 0\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n            detector D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RY 0 1\n            Z_ERROR(1) 0 1\n            MY(0.125) 0 1\n            MY 0 1\n            DETECTOR rec[-4]\n            DETECTOR rec[-3]\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n            error(1) D0 D2\n            error(0.125) D1\n            error(1) D1 D3\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, noisy_measurement_mz) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                RZ 0\n                MZ(0.125) 0\n                MZ 0\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n            detector D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                RZ 0 1\n                X_ERROR(1) 0 1\n                MZ(0.125) 0 1\n                MZ 0 1\n                DETECTOR rec[-4]\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n            error(1) D0 D2\n            error(0.125) D1\n            error(1) D1 D3\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, noisy_measurement_mrx) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                RX 0\n                MRX(0.125) 0\n                MRX 0\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n            detector D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                RX 0 1\n                Z_ERROR(1) 0 1\n                MRX(0.125) 0 1\n                MRX 0 1\n                DETECTOR rec[-4]\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.875) D0\n            error(0.875) D1\n            detector D2\n            detector D3\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, noisy_measurement_mry) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                RY 0\n                MRY(0.125) 0\n                MRY 0\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n            detector D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                RY 0 1\n                X_ERROR(1) 0 1\n                MRY(0.125) 0 1\n                MRY 0 1\n                DETECTOR rec[-4]\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.875) D0\n            error(0.875) D1\n            detector D2\n            detector D3\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, noisy_measurement_mrz) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                RZ 0\n                MRZ(0.125) 0\n                MRZ 0\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n            detector D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                RZ 0 1\n                X_ERROR(1) 0 1\n                MRZ(0.125) 0 1\n                MRZ 0 1\n                DETECTOR rec[-4]\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.875) D0\n            error(0.875) D1\n            detector D2\n            detector D3\n        )MODEL\"));\n}\n\ntemplate <typename TEx>\nstd::string expect_catch_message(std::function<void(void)> func) {\n    try {\n        func();\n        EXPECT_TRUE(false) << \"Function didn't throw an exception.\";\n        return \"\";\n    } catch (const TEx &ex) {\n        return ex.what();\n    }\n}\n\nTEST(ErrorAnalyzer, context_clues_for_errors) {\n    ASSERT_EQ(\n        expect_catch_message<std::invalid_argument>([&]() {\n            ErrorAnalyzer::circuit_to_detector_error_model(\n                Circuit(R\"CIRCUIT(\n                X 0\n                DEPOLARIZE1(1) 0\n            )CIRCUIT\"),\n                false,\n                false,\n                false,\n                0.0,\n                false,\n                true);\n        }),\n        \"Can't analyze over-mixing DEPOLARIZE1 errors (probability > 3/4).\\n\"\n        \"\\n\"\n        \"Circuit stack trace:\\n\"\n        \"    at instruction #2 [which is DEPOLARIZE1(1) 0]\");\n\n    ASSERT_EQ(\n        expect_catch_message<std::invalid_argument>([&]() {\n            circuit_to_dem(\n                Circuit(R\"CIRCUIT(\n                X 0\n                Y 1\n                REPEAT 500 {\n                    DEPOLARIZE1(1) 0\n                }\n                Z 3\n            )CIRCUIT\"),\n                {.block_decomposition_from_introducing_remnant_edges = true});\n        }),\n        \"Can't analyze over-mixing DEPOLARIZE1 errors (probability > 3/4).\\n\"\n        \"\\n\"\n        \"Circuit stack trace:\\n\"\n        \"    at instruction #3 [which is a REPEAT 500 block]\\n\"\n        \"    at block's instruction #1 [which is DEPOLARIZE1(1) 0]\");\n}\n\nTEST(ErrorAnalyzer, too_many_symptoms) {\n    auto symptoms_20 = Circuit(R\"CIRCUIT(\n        DEPOLARIZE1(0.001) 0\n        M 0\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n\n    ASSERT_EQ(\n        expect_catch_message<std::invalid_argument>([&]() {\n            circuit_to_dem(\n                symptoms_20, {.decompose_errors = true, .block_decomposition_from_introducing_remnant_edges = true});\n        }),\n        R\"MSG(An error case in a composite error exceeded the max supported number of symptoms (<=15).\nThe 2 basis error cases (e.g. X, Z) used to form the combined error cases (e.g. Y = X*Z) are:\n0:\n1: D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19\n\n\nCircuit stack trace:\n    at instruction #1 [which is DEPOLARIZE1(0.001) 0])MSG\");\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(symptoms_20, false, false, false, 0.0, false, true),\n        DetectorErrorModel(R\"model(\n            error(0.0006666666666666692465) D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 D14 D15 D16 D17 D18 D19\n        )model\"));\n}\n\nTEST(ErrorAnalyzer, decompose_error_failures) {\n    ASSERT_EQ(\n        expect_catch_message<std::invalid_argument>([&]() {\n            circuit_to_dem(\n                Circuit(R\"CIRCUIT(\n                DEPOLARIZE1(0.001) 0\n                M 0\n                DETECTOR rec[-1]\n                DETECTOR rec[-1]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n                {.decompose_errors = true, .block_decomposition_from_introducing_remnant_edges = true});\n        }),\n        R\"MSG(Failed to decompose errors into graphlike components with at most two symptoms.\nThe error component that failed to decompose is 'D0, D1, D2'.\n\nIn Python, you can ignore this error by passing `ignore_decomposition_failures=True` to `stim.Circuit.detector_error_model(...)`.\nFrom the command line, you can ignore this error by passing the flag `--ignore_decomposition_failures` to `stim analyze_errors`.\n\nNote: `block_decomposition_from_introducing_remnant_edges` is ON.\nTurning it off may prevent this error.)MSG\");\n\n    ASSERT_EQ(\n        expect_catch_message<std::invalid_argument>([&]() {\n            circuit_to_dem(\n                Circuit(R\"CIRCUIT(\n                X_ERROR(0.001) 0\n                M 0\n                DETECTOR rec[-1]\n                DETECTOR rec[-1]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n                {.decompose_errors = true, .block_decomposition_from_introducing_remnant_edges = true});\n        }),\n        R\"MSG(Failed to decompose errors into graphlike components with at most two symptoms.\nThe error component that failed to decompose is 'D0, D1, D2'.\n\nIn Python, you can ignore this error by passing `ignore_decomposition_failures=True` to `stim.Circuit.detector_error_model(...)`.\nFrom the command line, you can ignore this error by passing the flag `--ignore_decomposition_failures` to `stim analyze_errors`.\n\nNote: `block_decomposition_from_introducing_remnant_edges` is ON.\nTurning it off may prevent this error.)MSG\");\n\n    ASSERT_EQ(\n        expect_catch_message<std::invalid_argument>([&]() {\n            circuit_to_dem(\n                Circuit(R\"CIRCUIT(\n                X_ERROR(0.001) 0\n                M 0\n                DETECTOR rec[-1]\n                DETECTOR rec[-1]\n                DETECTOR rec[-1]\n                OBSERVABLE_INCLUDE(5) rec[-1]\n            )CIRCUIT\"),\n                {.decompose_errors = true, .block_decomposition_from_introducing_remnant_edges = true});\n        }),\n        R\"MSG(Failed to decompose errors into graphlike components with at most two symptoms.\nThe error component that failed to decompose is 'D0, D1, D2, L5'.\n\nIn Python, you can ignore this error by passing `ignore_decomposition_failures=True` to `stim.Circuit.detector_error_model(...)`.\nFrom the command line, you can ignore this error by passing the flag `--ignore_decomposition_failures` to `stim analyze_errors`.\n\nNote: `block_decomposition_from_introducing_remnant_edges` is ON.\nTurning it off may prevent this error.)MSG\");\n}\n\nTEST(ErrorAnalyzer, other_error_decomposition_fallback) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                X_ERROR(0.125) 0\n                MR 0\n                X_ERROR(0.25) 0\n                MR 0\n                DETECTOR rec[-2]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1] rec[-2]\n                DETECTOR rec[-1] rec[-2]\n                OBSERVABLE_INCLUDE(5) rec[-2]\n                OBSERVABLE_INCLUDE(6) rec[-1]\n            )CIRCUIT\"),\n            true,\n            false,\n            false,\n            0.0,\n            false,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(0.25) D2 D3 L6\n            error(0.125) D2 D3 L6 ^ D0 D1 L5 L6\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                X_ERROR(0.125) 0\n                MR 0\n                X_ERROR(0.25) 0\n                MR 0\n                DETECTOR rec[-2]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1] rec[-2]\n                DETECTOR rec[-1] rec[-2]\n            )CIRCUIT\"),\n            true,\n            false,\n            false,\n            0.0,\n            false,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(0.25) D2 D3\n            error(0.125) D2 D3 ^ D0 D1\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                X_ERROR(0.125) 0\n                MR 0\n                X_ERROR(0.25) 0\n                MR 0\n                DETECTOR rec[-1]\n                DETECTOR rec[-1]\n                DETECTOR rec[-1] rec[-2]\n                DETECTOR rec[-1] rec[-2]\n            )CIRCUIT\"),\n            true,\n            false,\n            false,\n            0.0,\n            false,\n            false),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D2 D3\n            error(0.25) D2 D3 ^ D0 D1\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, is_graph_like) {\n    ASSERT_TRUE(is_graphlike(std::vector<DemTarget>{}));\n    ASSERT_TRUE(is_graphlike(std::vector<DemTarget>{DemTarget::separator()}));\n    ASSERT_TRUE(is_graphlike(\n        std::vector<DemTarget>{\n            DemTarget::observable_id(0),\n            DemTarget::observable_id(1),\n            DemTarget::observable_id(2),\n            DemTarget::separator(),\n            DemTarget::observable_id(1),\n        }));\n    ASSERT_TRUE(is_graphlike(\n        std::vector<DemTarget>{\n            DemTarget::observable_id(0),\n            DemTarget::relative_detector_id(1),\n            DemTarget::observable_id(2),\n            DemTarget::separator(),\n            DemTarget::observable_id(1),\n        }));\n    ASSERT_TRUE(is_graphlike(\n        std::vector<DemTarget>{\n            DemTarget::observable_id(0),\n            DemTarget::relative_detector_id(1),\n            DemTarget::relative_detector_id(2),\n            DemTarget::separator(),\n            DemTarget::observable_id(1),\n        }));\n    ASSERT_FALSE(is_graphlike(\n        std::vector<DemTarget>{\n            DemTarget::relative_detector_id(0),\n            DemTarget::relative_detector_id(1),\n            DemTarget::relative_detector_id(2),\n            DemTarget::separator(),\n            DemTarget::observable_id(1),\n        }));\n    ASSERT_FALSE(is_graphlike(\n        std::vector<DemTarget>{\n            DemTarget::relative_detector_id(0),\n            DemTarget::relative_detector_id(1),\n            DemTarget::relative_detector_id(2),\n        }));\n    ASSERT_FALSE(is_graphlike(\n        std::vector<DemTarget>{\n            DemTarget::separator(),\n            DemTarget::separator(),\n            DemTarget::relative_detector_id(0),\n            DemTarget::relative_detector_id(1),\n            DemTarget::relative_detector_id(2),\n            DemTarget::separator(),\n            DemTarget::separator(),\n        }));\n    ASSERT_TRUE(is_graphlike(\n        std::vector<DemTarget>{\n            DemTarget::separator(),\n            DemTarget::relative_detector_id(0),\n            DemTarget::separator(),\n            DemTarget::relative_detector_id(1),\n            DemTarget::relative_detector_id(2),\n            DemTarget::separator(),\n            DemTarget::separator(),\n        }));\n}\n\nTEST(ErrorAnalyzer, honeycomb_code_decomposes) {\n    ErrorAnalyzer::circuit_to_detector_error_model(\n        Circuit(R\"CIRCUIT(\n            R 3 5 7 9 11 13 18 20 22 24 26 28\n            X_ERROR(0.001) 3 5 7 9 11 13 18 20 22 24 26 28\n            DEPOLARIZE1(0.001) 0 1 2 4 6 8 10 12 14 15 16 17 19 21 23 25 27 29\n            XCX 24 1 7 6 11 12 3 15 20 21 28 27\n            R 0 8 14 17 23 29\n            DEPOLARIZE2(0.001) 24 1 7 6 11 12 3 15 20 21 28 27\n            X_ERROR(0.001) 0 8 14 17 23 29\n            YCX 20 0 7 8 3 14 11 17 24 23 28 29\n            XCX 9 1 5 6 13 12 18 15 22 21 26 27\n            R 2 4 10 16 19 25\n            DEPOLARIZE2(0.001) 20 0 7 8 3 14 11 17 24 23 28 29 9 1 5 6 13 12 18 15 22 21 26 27\n            X_ERROR(0.001) 2 4 10 16 19 25\n            X_ERROR(0.001) 1 6 12 15 21 27\n            CX 28 2 3 4 11 10 7 16 20 19 24 25\n            YCX 5 0 9 8 13 14 26 17 22 23 18 29\n            MR 1 6 12 15 21 27\n            OBSERVABLE_INCLUDE(0) rec[-5] rec[-4]\n            DEPOLARIZE2(0.001) 28 2 3 4 11 10 7 16 20 19 24 25 5 0 9 8 13 14 26 17 22 23 18 29\n            X_ERROR(0.001) 1 6 12 15 21 27\n            X_ERROR(0.001) 0 8 14 17 23 29\n            XCX 24 1 7 6 11 12 3 15 20 21 28 27\n            CX 13 2 5 4 9 10 22 16 18 19 26 25\n            MR 0 8 14 17 23 29\n            OBSERVABLE_INCLUDE(0) rec[-5] rec[-4]\n            DETECTOR rec[-12] rec[-11] rec[-8] rec[-6] rec[-5] rec[-2]\n            DETECTOR rec[-10] rec[-9] rec[-7] rec[-4] rec[-3] rec[-1]\n            DEPOLARIZE2(0.001) 24 1 7 6 11 12 3 15 20 21 28 27 13 2 5 4 9 10 22 16 18 19 26 25\n            X_ERROR(0.001) 0 8 14 17 23 29\n            X_ERROR(0.001) 2 4 10 16 19 25\n            YCX 20 0 7 8 3 14 11 17 24 23 28 29\n            XCX 9 1 5 6 13 12 18 15 22 21 26 27\n            MR 2 4 10 16 19 25\n            OBSERVABLE_INCLUDE(0) rec[-5] rec[-4]\n            DEPOLARIZE2(0.001) 20 0 7 8 3 14 11 17 24 23 28 29 9 1 5 6 13 12 18 15 22 21 26 27\n            X_ERROR(0.001) 2 4 10 16 19 25\n            X_ERROR(0.001) 1 6 12 15 21 27\n            YCX 5 0 9 8 13 14 26 17 22 23 18 29\n            MR 1 6 12 15 21 27\n            OBSERVABLE_INCLUDE(0) rec[-5] rec[-4]\n            DETECTOR rec[-24] rec[-22] rec[-19] rec[-12] rec[-10] rec[-7] rec[-6] rec[-4] rec[-1]\n            DETECTOR rec[-23] rec[-21] rec[-20] rec[-11] rec[-9] rec[-8] rec[-5] rec[-3] rec[-2]\n            DEPOLARIZE2(0.001) 5 0 9 8 13 14 26 17 22 23 18 29\n            X_ERROR(0.001) 1 6 12 15 21 27\n            X_ERROR(0.001) 0 8 14 17 23 29\n            MR 0 8 14 17 23 29\n            OBSERVABLE_INCLUDE(0) rec[-5] rec[-4]\n            DETECTOR rec[-30] rec[-29] rec[-26] rec[-24] rec[-23] rec[-20] rec[-12] rec[-11] rec[-8] rec[-6] rec[-5] rec[-2]\n            DETECTOR rec[-28] rec[-27] rec[-25] rec[-22] rec[-21] rec[-19] rec[-10] rec[-9] rec[-7] rec[-4] rec[-3] rec[-1]\n            X_ERROR(0.001) 0 8 14 17 23 29\n            X_ERROR(0.001) 3 5 7 9 11 13 18 20 22 24 26 28\n            M 3 5 7 9 11 13 18 20 22 24 26 28\n            DETECTOR rec[-36] rec[-34] rec[-31] rec[-30] rec[-29] rec[-26] rec[-18] rec[-16] rec[-13] rec[-12] rec[-11] rec[-7] rec[-6] rec[-5] rec[-1]\n            DETECTOR rec[-35] rec[-33] rec[-32] rec[-28] rec[-27] rec[-25] rec[-17] rec[-15] rec[-14] rec[-10] rec[-9] rec[-8] rec[-4] rec[-3] rec[-2]\n            DETECTOR rec[-24] rec[-23] rec[-20] rec[-18] rec[-17] rec[-14] rec[-11] rec[-10] rec[-9] rec[-5] rec[-4] rec[-3]\n            DETECTOR rec[-22] rec[-21] rec[-19] rec[-16] rec[-15] rec[-13] rec[-12] rec[-8] rec[-7] rec[-6] rec[-2] rec[-1]\n            OBSERVABLE_INCLUDE(0) rec[-12] rec[-10] rec[-9] rec[-7]\n        )CIRCUIT\"),\n        true,\n        false,\n        false,\n        0.0,\n        false,\n        false);\n}\n\nTEST(ErrorAnalyzer, measure_pauli_product_4body) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                RX 0\n                Z_ERROR(0.125) 0\n                MPP X0*Z1\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D0\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                MPP(0.25) Z0*Z1\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.25) D0\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, ignores_sweep_controls) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                X_ERROR(0.25) 0\n                CNOT sweep[0] 0\n                M 0\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            error(0.25) D0\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, mpp_ordering) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                MPP X0*X1 X0\n                TICK\n                MPP X0\n                DETECTOR rec[-1] rec[-2]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            detector D0\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                MPP X0*X1 X0 X0\n                DETECTOR rec[-1] rec[-2]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            detector D0\n        )MODEL\"));\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n                MPP X2*X1 X0\n                TICK\n                MPP X0\n                DETECTOR rec[-1] rec[-2]\n            )CIRCUIT\"),\n            false,\n            false,\n            false,\n            0.0,\n            false,\n            true),\n        DetectorErrorModel(R\"MODEL(\n            detector D0\n        )MODEL\"));\n\n    ASSERT_THROW(\n        {\n            ErrorAnalyzer::circuit_to_detector_error_model(\n                Circuit(R\"CIRCUIT(\n                MPP X0 X0*X1\n                TICK\n                MPP X0\n                DETECTOR rec[-1] rec[-2]\n            )CIRCUIT\"),\n                false,\n                false,\n                false,\n                0.0,\n                false,\n                true);\n        },\n        std::invalid_argument);\n\n    ASSERT_THROW(\n        {\n            ErrorAnalyzer::circuit_to_detector_error_model(\n                Circuit(R\"CIRCUIT(\n                MPP X0 X2*X1\n                TICK\n                MPP X0\n                DETECTOR rec[-1] rec[-2]\n            )CIRCUIT\"),\n                false,\n                false,\n                false,\n                0.0,\n                false,\n                true);\n        },\n        std::invalid_argument);\n}\n\nTEST(ErrorAnalyzer, anticommuting_observable_error_message_help) {\n    for (size_t folding = 0; folding < 2; folding++) {\n        ASSERT_EQ(\n            expect_catch_message<std::invalid_argument>([&]() {\n                circuit_to_dem(\n                    Circuit(R\"CIRCUIT(\n                        QUBIT_COORDS(1, 2, 3) 0\n                        RX 2\n                        REPEAT 10 {\n                            REPEAT 20 {\n                                C_XYZ 0\n                                R 1\n                                M 1\n                                DETECTOR rec[-1]\n                                TICK\n                            }\n                        }\n                        M 0 2\n                        OBSERVABLE_INCLUDE(0) rec[-1] rec[-2]\n                    )CIRCUIT\"),\n                    {.flatten_loops = folding != 1});\n            }),\n            R\"ERROR(The circuit contains non-deterministic observables.\n\nTo make an SVG picture of the problem, you can use the python API like this:\n    your_circuit.diagram('detslice-with-ops-svg', tick=range(0, 5), filter_coords=['L0', ])\nor the command line API like this:\n    stim diagram --in your_circuit_file.stim --type detslice-with-ops-svg --tick 0:5 --filter_coords L0 > output_image.svg\n\nThis was discovered while analyzing an X-basis reset (RX) on:\n    qubit 2\n\nThe collapse anti-commuted with these detectors/observables:\n    L0\n\nThe backward-propagating error sensitivity for L0 was:\n    X0 [coords (1, 2, 3)]\n    Z2\n\nCircuit stack trace:\n    during TICK layer #1 of 201\n    at instruction #2 [which is RX 2])ERROR\");\n\n        ASSERT_EQ(\n            expect_catch_message<std::invalid_argument>([&]() {\n                circuit_to_dem(\n                    Circuit(R\"CIRCUIT(\n                    TICK\n                    SHIFT_COORDS(1000, 2000)\n                    M 0 1\n                    REPEAT 100 {\n                        RX 0\n                        DETECTOR rec[-1]\n                        TICK\n                    }\n                    REPEAT 200 {\n                        TICK\n                    }\n                    REPEAT 100 {\n                        M 0 1\n                        SHIFT_COORDS(0, 100)\n                        DETECTOR(1, 2, 3) rec[-1] rec[-3]\n                        DETECTOR(4, 5, 6) rec[-2] rec[-4]\n                        OBSERVABLE_INCLUDE(0) rec[-1] rec[-2] rec[-3] rec[-4]\n                        TICK\n                    }\n                    REPEAT 1000 {\n                        TICK\n                    }\n                )CIRCUIT\"),\n                    {.flatten_loops = folding != 1});\n            }),\n            R\"ERROR(The circuit contains non-deterministic observables.\nThe circuit contains non-deterministic detectors.\n\nTo make an SVG picture of the problem, you can use the python API like this:\n    your_circuit.diagram('detslice-with-ops-svg', tick=range(95, 105), filter_coords=['D101', 'L0', ])\nor the command line API like this:\n    stim diagram --in your_circuit_file.stim --type detslice-with-ops-svg --tick 95:105 --filter_coords D101:L0 > output_image.svg\n\nThis was discovered while analyzing an X-basis reset (RX) on:\n    qubit 0\n\nThe collapse anti-commuted with these detectors/observables:\n    D101 [coords (1004, 2105, 6)]\n    L0\n\nThe backward-propagating error sensitivity for D101 was:\n    Z0\n\nThe backward-propagating error sensitivity for L0 was:\n    Z0\n    Z1\n\nCircuit stack trace:\n    during TICK layer #101 of 1402\n    at instruction #4 [which is a REPEAT 100 block]\n    at block's instruction #1 [which is RX 0])ERROR\");\n    }\n}\n\nTEST(ErrorAnalyzer, brute_force_decomp_simple) {\n    MonotonicBuffer<DemTarget> buf;\n    std::map<FixedCapVector<DemTarget, 2>, SpanRef<const DemTarget>> known;\n    bool actual;\n    std::vector<DemTarget> problem{\n        DemTarget::relative_detector_id(0),\n        DemTarget::relative_detector_id(1),\n        DemTarget::relative_detector_id(2),\n    };\n    auto add = [&](uint32_t a, uint32_t b) {\n        DemTarget a2 = DemTarget::relative_detector_id(a);\n        DemTarget b2 = DemTarget::relative_detector_id(b);\n        FixedCapVector<DemTarget, 2> v;\n        v.push_back(a2);\n        if (b != UINT32_MAX) {\n            v.push_back(b2);\n        }\n        buf.append_tail({v.begin(), v.end()});\n        known[v] = buf.commit_tail();\n    };\n\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_FALSE(actual);\n    ASSERT_TRUE(buf.tail.empty());\n\n    add(0, 2);\n\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_FALSE(actual);\n    ASSERT_TRUE(buf.tail.empty());\n\n    add(1, UINT32_MAX);\n\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_TRUE(actual);\n    ASSERT_EQ(buf.tail.size(), 5);\n    ASSERT_EQ(buf.tail[0], DemTarget::relative_detector_id(0));\n    ASSERT_EQ(buf.tail[1], DemTarget::relative_detector_id(2));\n    ASSERT_EQ(buf.tail[2], DemTarget::separator());\n    ASSERT_EQ(buf.tail[3], DemTarget::relative_detector_id(1));\n    ASSERT_EQ(buf.tail[4], DemTarget::separator());\n}\n\nTEST(ErrorAnalyzer, brute_force_decomp_introducing_obs_pair) {\n    MonotonicBuffer<DemTarget> buf;\n    std::map<FixedCapVector<DemTarget, 2>, SpanRef<const DemTarget>> known;\n    bool actual;\n    std::vector<DemTarget> problem{\n        DemTarget::relative_detector_id(0),\n        DemTarget::relative_detector_id(1),\n        DemTarget::relative_detector_id(2),\n    };\n    auto add = [&](uint32_t a, uint32_t b, bool obs) {\n        DemTarget a2 = DemTarget::relative_detector_id(a);\n        DemTarget b2 = DemTarget::relative_detector_id(b);\n        FixedCapVector<DemTarget, 2> v;\n        v.push_back(a2);\n        if (b != UINT32_MAX) {\n            v.push_back(b2);\n        }\n        buf.append_tail({v.begin(), v.end()});\n        if (obs) {\n            buf.append_tail(DemTarget::observable_id(5));\n        }\n        known[v] = buf.commit_tail();\n    };\n\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_FALSE(actual);\n    ASSERT_TRUE(buf.tail.empty());\n\n    add(0, 2, true);\n\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_FALSE(actual);\n    ASSERT_TRUE(buf.tail.empty());\n\n    add(1, UINT32_MAX, false);\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_FALSE(actual);\n    ASSERT_TRUE(buf.tail.empty());\n\n    add(1, UINT32_MAX, true);\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_TRUE(actual);\n    ASSERT_EQ(buf.tail.size(), 7);\n    ASSERT_EQ(buf.tail[0], DemTarget::relative_detector_id(0));\n    ASSERT_EQ(buf.tail[1], DemTarget::relative_detector_id(2));\n    ASSERT_EQ(buf.tail[2], DemTarget::observable_id(5));\n    ASSERT_EQ(buf.tail[3], DemTarget::separator());\n    ASSERT_EQ(buf.tail[4], DemTarget::relative_detector_id(1));\n    ASSERT_EQ(buf.tail[5], DemTarget::observable_id(5));\n    ASSERT_EQ(buf.tail[6], DemTarget::separator());\n}\n\nTEST(ErrorAnalyzer, brute_force_decomp_with_obs) {\n    MonotonicBuffer<DemTarget> buf;\n    std::map<FixedCapVector<DemTarget, 2>, SpanRef<const DemTarget>> known;\n    bool actual;\n    std::vector<DemTarget> problem{\n        DemTarget::relative_detector_id(0),\n        DemTarget::relative_detector_id(1),\n        DemTarget::relative_detector_id(2),\n        DemTarget::observable_id(5),\n    };\n    auto add = [&](uint32_t a, uint32_t b, bool obs) {\n        DemTarget a2 = DemTarget::relative_detector_id(a);\n        DemTarget b2 = DemTarget::relative_detector_id(b);\n        FixedCapVector<DemTarget, 2> v;\n        v.push_back(a2);\n        if (b != UINT32_MAX) {\n            v.push_back(b2);\n        }\n        buf.append_tail({v.begin(), v.end()});\n        if (obs) {\n            buf.append_tail(DemTarget::observable_id(5));\n        }\n        known[v] = buf.commit_tail();\n    };\n\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_FALSE(actual);\n    ASSERT_TRUE(buf.tail.empty());\n\n    add(0, 2, true);\n\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_FALSE(actual);\n    ASSERT_TRUE(buf.tail.empty());\n\n    add(1, UINT32_MAX, false);\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_TRUE(actual);\n    ASSERT_EQ(buf.tail.size(), 6);\n    ASSERT_EQ(buf.tail[0], DemTarget::relative_detector_id(0));\n    ASSERT_EQ(buf.tail[1], DemTarget::relative_detector_id(2));\n    ASSERT_EQ(buf.tail[2], DemTarget::observable_id(5));\n    ASSERT_EQ(buf.tail[3], DemTarget::separator());\n    ASSERT_EQ(buf.tail[4], DemTarget::relative_detector_id(1));\n    ASSERT_EQ(buf.tail[5], DemTarget::separator());\n\n    buf.discard_tail();\n    add(0, 2, false);\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_FALSE(actual);\n    ASSERT_TRUE(buf.tail.empty());\n\n    add(1, UINT32_MAX, true);\n    actual = brute_force_decomposition_into_known_graphlike_errors({problem}, known, buf);\n    ASSERT_TRUE(actual);\n    ASSERT_EQ(buf.tail.size(), 6);\n    ASSERT_EQ(buf.tail[0], DemTarget::relative_detector_id(0));\n    ASSERT_EQ(buf.tail[1], DemTarget::relative_detector_id(2));\n    ASSERT_EQ(buf.tail[2], DemTarget::separator());\n    ASSERT_EQ(buf.tail[3], DemTarget::relative_detector_id(1));\n    ASSERT_EQ(buf.tail[4], DemTarget::observable_id(5));\n    ASSERT_EQ(buf.tail[5], DemTarget::separator());\n}\n\nTEST(ErrorAnalyzer, ignore_failures) {\n    stim::Circuit circuit(Circuit(R\"CIRCUIT(\n        X_ERROR(0.25) 0\n        MR 0\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n\n        X_ERROR(0.125) 0 1 2\n        CORRELATED_ERROR(0.25) X0 X1 X2\n        M 0 1 2\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n    )CIRCUIT\"));\n\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, false, false, 0.0, false, false); },\n        std::invalid_argument);\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, false, false, 0.0, true, false),\n        DetectorErrorModel(R\"MODEL(\n            error(0.25) D0 D1 D2\n            error(0.125) D3\n            error(0.25) D3 ^ D4 ^ D5\n            error(0.125) D4\n            error(0.125) D5\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, block_remnant_edge) {\n    stim::Circuit circuit(Circuit(R\"CIRCUIT(\n        X_ERROR(0.125) 0\n        CORRELATED_ERROR(0.25) X0 X1\n        M 0 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-2]\n    )CIRCUIT\"));\n\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, false, false, 0.0, false, true); },\n        std::invalid_argument);\n\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, false, false, 0.0, false, false),\n        DetectorErrorModel(R\"MODEL(\n            error(0.125) D2 D3\n            error(0.25) D2 D3 ^ D0 D1\n        )MODEL\"));\n}\n\nTEST(ErrorAnalyzer, dont_fold_when_observable_dependencies_cross_iterations) {\n    Circuit c(R\"CIRCUIT(\n        RX 0 2\n        REPEAT 100 {\n            R 1\n            CX 0 1 2 1\n            MRZ 1\n            MRX 2\n        }\n        MX 0\n        # Doesn't include all elements from the loop.\n        OBSERVABLE_INCLUDE(0) rec[-1] rec[-2] rec[-4]\n    )CIRCUIT\");\n    ASSERT_ANY_THROW({ ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 1, false, false); });\n}\n\nTEST(ErrorAnalyzer, else_correlated_error_block) {\n    Circuit c(R\"CIRCUIT(\n        CORRELATED_ERROR(0.25) X0\n        ELSE_CORRELATED_ERROR(0.25) X1\n        ELSE_CORRELATED_ERROR(0.25) X2\n        M 0 1 2\n        DETECTOR rec[-3]\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 1, false, false), DetectorErrorModel(R\"DEM(\n            error(0.25) D0\n            error(0.1875) D1\n            error(0.140625) D2\n        )DEM\"));\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 0.25, false, false),\n        DetectorErrorModel(R\"DEM(\n            error(0.25) D0\n            error(0.1875) D1\n            error(0.140625) D2\n        )DEM\"));\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 0, false, false); },\n        std::invalid_argument);\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 0.1, false, false); },\n        std::invalid_argument);\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 0.24, false, false); },\n        std::invalid_argument);\n\n    c = Circuit(R\"CIRCUIT(\n        CORRELATED_ERROR(0.25) X0\n        ELSE_CORRELATED_ERROR(0.25) X1\n        ELSE_CORRELATED_ERROR(0.25) X2\n        CORRELATED_ERROR(0.25) X3\n        ELSE_CORRELATED_ERROR(0.25) X4\n        ELSE_CORRELATED_ERROR(0.25) X5\n        M 0 1 2 3 4 5\n        DETECTOR rec[-6]\n        DETECTOR rec[-5]\n        DETECTOR rec[-4]\n        DETECTOR rec[-3]\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 1, false, false), DetectorErrorModel(R\"DEM(\n            error(0.25) D0\n            error(0.1875) D1\n            error(0.140625) D2\n            error(0.25) D3\n            error(0.1875) D4\n            error(0.140625) D5\n        )DEM\"));\n\n    c = Circuit(R\"CIRCUIT(\n        CORRELATED_ERROR(0.25) X0\n        ELSE_CORRELATED_ERROR(0.25) Z1\n        H 1\n        ELSE_CORRELATED_ERROR(0.25) X2\n    )CIRCUIT\");\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 1, false, false); },\n        std::invalid_argument);\n\n    c = Circuit(R\"CIRCUIT(\n        CORRELATED_ERROR(0.25) X0\n        REPEAT 1 {\n            ELSE_CORRELATED_ERROR(0.25) Z1\n        }\n    )CIRCUIT\");\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 1, false, false); },\n        std::invalid_argument);\n\n    c = Circuit(R\"CIRCUIT(\n        ELSE_CORRELATED_ERROR(0.25) Z1\n    )CIRCUIT\");\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 1, false, false); },\n        std::invalid_argument);\n}\n\nTEST(ErrorAnalyzer, measurement_before_beginning) {\n    Circuit c(R\"CIRCUIT(\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(c, false, false, false, false, false, false); },\n        std::invalid_argument);\n\n    c = Circuit(R\"CIRCUIT(\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\");\n    ASSERT_THROW(\n        { ErrorAnalyzer::circuit_to_detector_error_model(c, false, false, false, false, false, false); },\n        std::invalid_argument);\n}\n\nTEST(ErrorAnalyzer, mpad) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            M(0.125) 5\n            MPAD 0 1\n            DETECTOR rec[-1] rec[-2]\n            DETECTOR rec[-3]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            false,\n            false,\n            false),\n        DetectorErrorModel(R\"DEM(\n            error(0.125) D1\n            detector D0\n        )DEM\"));\n}\n\nTEST(ErrorAnalyzer, mxx) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RX 0 1\n            MXX(0.125) 0 1\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            false,\n            false,\n            false),\n        DetectorErrorModel(R\"DEM(\n            error(0.125) D0\n        )DEM\"));\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RX 0 1 2 3\n            X_ERROR(0.125) 0\n            Y_ERROR(0.25) 1\n            Z_ERROR(0.375) 2\n            MXX 0 1 !2 !3\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            false,\n            false,\n            false),\n        DetectorErrorModel(R\"DEM(\n            error(0.25) D0\n            error(0.375) D1\n        )DEM\"));\n}\n\nTEST(ErrorAnalyzer, myy) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RY 0 1\n            MYY(0.125) 0 1\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            false,\n            false,\n            false),\n        DetectorErrorModel(R\"DEM(\n            error(0.125) D0\n        )DEM\"));\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RY 0 1 2 3\n            Y_ERROR(0.125) 0\n            X_ERROR(0.25) 1\n            Z_ERROR(0.375) 2\n            MYY 0 1 !2 !3\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            false,\n            false,\n            false),\n        DetectorErrorModel(R\"DEM(\n            error(0.25) D0\n            error(0.375) D1\n        )DEM\"));\n}\n\nTEST(ErrorAnalyzer, mzz) {\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RZ 0 1\n            MZZ(0.125) 0 1\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            false,\n            false,\n            false),\n        DetectorErrorModel(R\"DEM(\n            error(0.125) D0\n        )DEM\"));\n    ASSERT_EQ(\n        ErrorAnalyzer::circuit_to_detector_error_model(\n            Circuit(R\"CIRCUIT(\n            RZ 0 1 2 3\n            Z_ERROR(0.125) 0\n            Y_ERROR(0.25) 1\n            X_ERROR(0.375) 2\n            MZZ 0 1 !2 !3\n            DETECTOR rec[-2]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n            false,\n            false,\n            false,\n            false,\n            false,\n            false),\n        DetectorErrorModel(R\"DEM(\n            error(0.25) D0\n            error(0.375) D1\n        )DEM\"));\n}\n\nTEST(ErrorAnalyzer, heralded_erase_conditional_division) {\n    auto dem = [](bool h, bool x, bool z) {\n        Circuit c(R\"CIRCUIT(\n            MPP X0*X1 Z0*Z1\n            HERALDED_ERASE(1.0) 0\n            MPP X0*X1 Z0*Z1\n        )CIRCUIT\");\n        if (h) {\n            c.append_from_text(\"DETECTOR rec[-3]\");\n        } else {\n            c.append_from_text(\"DETECTOR\");\n        }\n        if (x) {\n            c.append_from_text(\"DETECTOR rec[-2] rec[-5]\");\n        } else {\n            c.append_from_text(\"DETECTOR\");\n        }\n        if (z) {\n            c.append_from_text(\"DETECTOR rec[-1] rec[-4]\");\n        } else {\n            c.append_from_text(\"DETECTOR\");\n        }\n        return ErrorAnalyzer::circuit_to_detector_error_model(c, false, false, false, 1.0, false, false);\n    };\n    EXPECT_EQ(dem(0, 0, 0), DetectorErrorModel(R\"DEM(\n        detector D0\n        detector D1\n        detector D2\n    )DEM\"));\n    EXPECT_EQ(dem(0, 0, 1), DetectorErrorModel(R\"DEM(\n        error(0.5) D2\n        detector D0\n        detector D1\n    )DEM\"));\n    EXPECT_EQ(dem(0, 1, 0), DetectorErrorModel(R\"DEM(\n        error(0.5) D1\n        detector D0\n        detector D2\n    )DEM\"));\n    EXPECT_EQ(dem(0, 1, 1), DetectorErrorModel(R\"DEM(\n        error(0.25) D1\n        error(0.25) D1 D2\n        error(0.25) D2\n        detector D0\n    )DEM\"));\n    EXPECT_EQ(dem(1, 0, 0), DetectorErrorModel(R\"DEM(\n        error(1.0) D0\n        detector D1\n        detector D2\n    )DEM\"));\n    EXPECT_EQ(dem(1, 0, 1), DetectorErrorModel(R\"DEM(\n        error(0.5) D0\n        error(0.5) D0 D2\n        detector D1\n    )DEM\"));\n    EXPECT_EQ(dem(1, 1, 0), DetectorErrorModel(R\"DEM(\n        error(0.5) D0\n        error(0.5) D0 D1\n        detector D2\n    )DEM\"));\n    EXPECT_EQ(dem(1, 1, 1), DetectorErrorModel(R\"DEM(\n        error(0.25) D0\n        error(0.25) D0 D1\n        error(0.25) D0 D1 D2\n        error(0.25) D0 D2\n    )DEM\"));\n}\n\nTEST(ErrorAnalyzer, heralded_erase) {\n    circuit_to_dem(Circuit(\"HERALDED_ERASE(0.25) 0\"), {.approximate_disjoint_errors_threshold = 0.3});\n    ASSERT_THROW(\n        { circuit_to_dem(Circuit(\"HERALDED_ERASE(0.25) 0\"), {.approximate_disjoint_errors_threshold = 0.2}); },\n        std::invalid_argument);\n\n    ASSERT_EQ(\n        circuit_to_dem(\n            Circuit(R\"CIRCUIT(\n                MZZ 0 1\n                MXX 0 1\n                HERALDED_ERASE(0.25) 0\n                MZZ 0 1\n                MXX 0 1\n                DETECTOR rec[-1] rec[-4]\n                DETECTOR rec[-2] rec[-5]\n                DETECTOR rec[-3]\n            )CIRCUIT\"),\n            {.approximate_disjoint_errors_threshold = 1}),\n        DetectorErrorModel(R\"DEM(\n            error(0.0625) D0 D1 D2\n            error(0.0625) D0 D2\n            error(0.0625) D1 D2\n            error(0.0625) D2\n        )DEM\"));\n\n    ASSERT_EQ(\n        circuit_to_dem(\n            Circuit(R\"CIRCUIT(\n                MPP X10*X11*X20*X21\n                MPP Z11*Z12*Z21*Z22\n                MPP Z20*Z21*Z30*Z31\n                MPP X21*X22*X31*X32\n                HERALDED_ERASE(0.25) 21\n                MPP X10*X11*X20*X21\n                MPP Z11*Z12*Z21*Z22\n                MPP Z20*Z21*Z30*Z31\n                MPP X21*X22*X31*X32\n                DETECTOR rec[-1] rec[-6]\n                DETECTOR rec[-2] rec[-7]\n                DETECTOR rec[-3] rec[-8]\n                DETECTOR rec[-4] rec[-9]\n                DETECTOR rec[-5]\n            )CIRCUIT\"),\n            {.decompose_errors = true, .approximate_disjoint_errors_threshold = 1}),\n        DetectorErrorModel(R\"DEM(\n            error(0.0625) D0 D3 ^ D1 D2 ^ D4\n            error(0.0625) D0 D3 ^ D4\n            error(0.0625) D1 D2 ^ D4\n            error(0.0625) D4\n        )DEM\"));\n\n    ASSERT_EQ(\n        circuit_to_dem(\n            Circuit(R\"CIRCUIT(\n                M 0\n                HERALDED_ERASE(0.25) 9 0 9 9 9\n                M 0\n                DETECTOR rec[-1] rec[-7]\n                DETECTOR rec[-5]\n            )CIRCUIT\"),\n            {.approximate_disjoint_errors_threshold = 1}),\n        DetectorErrorModel(R\"DEM(\n            error(0.125) D0 D1\n            error(0.125) D1\n        )DEM\"));\n\n    ASSERT_EQ(\n        circuit_to_dem(\n            Circuit(R\"CIRCUIT(\n                MPAD 0\n                MPAD 0\n                MPP Z20*Z21*Z30*Z31\n                MPP X21*X22*X31*X32\n                HERALDED_ERASE(0.25) 21\n                MPAD 0\n                MPAD 0\n                MPP Z20*Z21*Z30*Z31\n                MPP X21*X22*X31*X32\n                DETECTOR rec[-1] rec[-6]\n                DETECTOR rec[-2] rec[-7]\n                DETECTOR rec[-3] rec[-8]\n                DETECTOR rec[-4] rec[-9]\n                DETECTOR rec[-5]\n            )CIRCUIT\"),\n            {.decompose_errors = true, .approximate_disjoint_errors_threshold = 1}),\n        DetectorErrorModel(R\"DEM(\n            error(0.0625) D0 ^ D1 ^ D4\n            error(0.0625) D0 ^ D4\n            error(0.0625) D1 ^ D4\n            error(0.0625) D4\n            detector D2\n            detector D3\n        )DEM\"));\n}\n\nTEST(ErrorAnalyzer, runs_on_general_circuit) {\n    auto circuit = generate_test_circuit_with_all_operations();\n    auto dem = ErrorAnalyzer::circuit_to_detector_error_model(circuit, false, false, false, true, false, false);\n    ASSERT_GT(dem.instructions.size(), 0);\n}\n\nTEST(ErrorAnalyzer, heralded_pauli_channel_1) {\n    ErrorAnalyzer::circuit_to_detector_error_model(\n        Circuit(\"HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.25, 0.03) 0\"), false, false, false, 0.3, false, false);\n    ASSERT_THROW(\n        {\n            ErrorAnalyzer::circuit_to_detector_error_model(\n                Circuit(\"HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.25, 0.03) 0\"), false, false, false, 0.2, false, false);\n        },\n        std::invalid_argument);\n\n    ASSERT_TRUE(circuit_to_dem(\n                    Circuit(R\"CIRCUIT(\n                        MZZ 0 1\n                        MXX 0 1\n                        HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.04) 0\n                        MZZ 0 1\n                        MXX 0 1\n                        DETECTOR rec[-1] rec[-4]\n                        DETECTOR rec[-2] rec[-5]\n                        DETECTOR rec[-3]\n                    )CIRCUIT\"),\n                    {.approximate_disjoint_errors_threshold = 1})\n                    .approx_equals(\n                        DetectorErrorModel(R\"DEM(\n                            error(0.03) D0 D1 D2\n                            error(0.04) D0 D2\n                            error(0.02) D1 D2\n                            error(0.01) D2\n                        )DEM\"),\n                        1e-6));\n\n    ASSERT_TRUE(circuit_to_dem(\n                    Circuit(R\"CIRCUIT(\n                        MZZ 0 1\n                        MXX 0 1\n                        HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.1) 0\n                        MZZ 0 1\n                        MXX 0 1\n                        DETECTOR\n                        DETECTOR rec[-2] rec[-5]\n                        DETECTOR rec[-3]\n                    )CIRCUIT\"),\n                    {.approximate_disjoint_errors_threshold = 1})\n                    .approx_equals(\n                        DetectorErrorModel(R\"DEM(\n                            error(0.05) D1 D2\n                            error(0.11) D2\n                            detector D0\n                        )DEM\"),\n                        1e-6));\n}\n\nTEST(ErrorAnalyzer, OBS_INCLUDE_PAULIS) {\n    auto circuit = Circuit(R\"CIRCUIT(\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        X_ERROR(0.125) 0\n        Y_ERROR(0.25) 0\n        Z_ERROR(0.375) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n    )CIRCUIT\");\n    ASSERT_EQ(circuit_to_dem(circuit), DetectorErrorModel(R\"DEM(\n        error(0.375) L0 L1\n        error(0.25) L0 L2\n        error(0.125) L1 L2\n    )DEM\"));\n\n    circuit = Circuit(R\"CIRCUIT(\n        DEPOLARIZE1(0.125) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        X_ERROR(0.25) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        DEPOLARIZE1(0.125) 0\n    )CIRCUIT\");\n    ASSERT_EQ(circuit_to_dem(circuit), DetectorErrorModel(R\"DEM(\n        error(0.25) L1 L2\n        logical_observable L0\n        logical_observable L0\n    )DEM\"));\n\n    circuit = Circuit(R\"CIRCUIT(\n        DEPOLARIZE1(0.125) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        Y_ERROR(0.25) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        DEPOLARIZE1(0.125) 0\n    )CIRCUIT\");\n    ASSERT_EQ(circuit_to_dem(circuit), DetectorErrorModel(R\"DEM(\n        error(0.25) L0 L2\n        logical_observable L1\n        logical_observable L1\n    )DEM\"));\n\n    circuit = Circuit(R\"CIRCUIT(\n        DEPOLARIZE1(0.125) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        Z_ERROR(0.25) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        DEPOLARIZE1(0.125) 0\n    )CIRCUIT\");\n    ASSERT_EQ(circuit_to_dem(circuit), DetectorErrorModel(R\"DEM(\n        error(0.25) L0 L1\n        logical_observable L2\n        logical_observable L2\n    )DEM\"));\n}\n\nTEST(ErrorAnalyzer, tagged_noise) {\n    ASSERT_EQ(\n        circuit_to_dem(Circuit(R\"CIRCUIT(\n        R[test-tag-0] 0\n        X_ERROR[test-tag-1](0.25) 0\n        M[test-tag-2] 0\n        DETECTOR[test-tag-3] rec[-1]\n        OBSERVABLE_INCLUDE[test-tag-4](0) rec[-1]\n        SHIFT_COORDS[test-tag-5](1)\n    )CIRCUIT\")),\n        DetectorErrorModel(R\"DEM(\n        error[test-tag-1](0.25) D0 L0\n        detector[test-tag-3] D0\n        logical_observable[test-tag-4] L0\n        shift_detectors[test-tag-5](1.0) 0\n    )DEM\"));\n\n    ASSERT_EQ(\n        circuit_to_dem(Circuit(R\"CIRCUIT(\n        OBSERVABLE_INCLUDE[test-tag-1](0)\n        OBSERVABLE_INCLUDE[test-tag-2](0)\n    )CIRCUIT\")),\n        DetectorErrorModel(R\"DEM(\n        logical_observable[test-tag-1] L0\n        logical_observable[test-tag-2] L0\n    )DEM\"));\n\n    ASSERT_EQ(\n        circuit_to_dem(\n            Circuit(R\"CIRCUIT(\n        R 0\n        X_ERROR[test-tag-0](0.25) 0\n        REPEAT[test-tag-1] 100 {\n            X_ERROR[test-tag-2](0.125) 0\n            MR 0\n            DETECTOR[test-tag-3] rec[-1]\n            OBSERVABLE_INCLUDE[test-tag-4](0) rec[-1]\n        }\n    )CIRCUIT\"),\n            {.decompose_errors = false, .flatten_loops = false}),\n        DetectorErrorModel(R\"DEM(\n        error[test-tag-0](0.25) D0 L0\n        repeat[test-tag-1] 99 {\n            error[test-tag-2](0.125) D0 L0\n            detector[test-tag-3] D0\n            logical_observable[test-tag-4] L0\n            shift_detectors 1\n        }\n        error[test-tag-2](0.125) D0 L0\n        detector[test-tag-3] D0\n        logical_observable[test-tag-4] L0\n    )DEM\"));\n}\n"
  },
  {
    "path": "src/stim/simulators/error_matcher.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/error_matcher.h\"\n\n#include <queue>\n#include <sstream>\n\nusing namespace stim;\n\nErrorMatcher::ErrorMatcher(\n    const Circuit &circuit, const DetectorErrorModel *init_filter, bool reduce_to_one_representative_error)\n    : error_analyzer(\n          circuit.count_measurements(),\n          circuit.count_detectors(),\n          circuit.count_qubits(),\n          circuit.count_ticks(),\n          false,\n          false,\n          true,\n          1,\n          false,\n          false),\n      cur_loc(),\n      output_map(),\n      allow_adding_new_dem_errors_to_output_map(init_filter == nullptr),\n      reduce_to_one_representative_error(reduce_to_one_representative_error),\n      dem_coords_map(),\n      qubit_coords_map(circuit.get_final_qubit_coords()),\n      cur_coord_offset(circuit.final_coord_shift()),\n      total_measurements_in_circuit(error_analyzer.tracker.num_measurements_in_past),\n      total_ticks_in_circuit(error_analyzer.num_ticks_in_past) {\n    // If filtering, get the filter errors into the output map immediately.\n    if (!allow_adding_new_dem_errors_to_output_map) {\n        SparseXorVec<DemTarget> buf;\n        init_filter->iter_flatten_error_instructions([&](const DemInstruction &instruction) {\n            assert(instruction.type == DemInstructionType::DEM_ERROR);\n            buf.clear();\n            // Note: quadratic overhead, but typical size is 4 and 100 would be crazy big.\n            for (const auto &target : instruction.target_data) {\n                if (!target.is_separator()) {\n                    buf.xor_item(target);\n                }\n            }\n            dem_targets_buf.append_tail(buf.sorted_items);\n            output_map.insert({dem_targets_buf.commit_tail(), {{}, {}}});\n        });\n    }\n}\n\nvoid ErrorMatcher::add_dem_error(ErrorEquivalenceClass dem_error) {\n    auto entry = output_map.find(dem_error.targets);\n    if (!dem_error.targets.empty() && (allow_adding_new_dem_errors_to_output_map || entry != output_map.end())) {\n        // We have a desired match! Record it.\n        CircuitErrorLocation new_loc = cur_loc;\n        new_loc.noise_tag = dem_error.tag;\n        if (cur_op != nullptr) {\n            new_loc.instruction_targets.fill_args_and_targets_in_range(*cur_op, qubit_coords_map);\n        }\n        if (entry == output_map.end()) {\n            dem_targets_buf.append_tail(dem_error.targets);\n            auto stored_key = dem_targets_buf.commit_tail();\n            entry = output_map.insert({stored_key, {{}, {}}}).first;\n        }\n        auto &out = entry->second.circuit_error_locations;\n        if (out.empty() || !reduce_to_one_representative_error) {\n            out.push_back(std::move(new_loc));\n        } else if (new_loc.is_simpler_than(out.front())) {\n            out[0] = std::move(new_loc);\n        }\n    }\n}\n\nvoid ErrorMatcher::err_atom(const CircuitInstruction &effect) {\n    assert(error_analyzer.error_class_probabilities.empty());\n    error_analyzer.undo_gate(effect);\n    if (error_analyzer.error_class_probabilities.empty()) {\n        /// Maybe there were no detectors or observables nearby? Or the noise probability was zero?\n        return;\n    }\n\n    assert(error_analyzer.error_class_probabilities.size() == 1);\n    ErrorEquivalenceClass dem_error = error_analyzer.error_class_probabilities.begin()->first;\n    add_dem_error(dem_error);\n\n    // Restore the pristine state.\n    error_analyzer.mono_buf.clear();\n    error_analyzer.error_class_probabilities.clear();\n    error_analyzer.flushed_reversed_model.clear();\n}\n\nvoid ErrorMatcher::resolve_paulis_into(\n    SpanRef<const GateTarget> targets, uint32_t target_flags, std::vector<GateTargetWithCoords> &out) {\n    for (const auto &t : targets) {\n        if (t.is_combiner()) {\n            continue;\n        }\n        auto entry = qubit_coords_map.find(t.qubit_value());\n        if (entry != qubit_coords_map.end()) {\n            out.push_back({t, entry->second});\n        } else {\n            out.push_back({t, {}});\n        }\n        out.back().gate_target.data |= target_flags;\n    }\n}\n\nvoid ErrorMatcher::err_xyz(const CircuitInstruction &op, uint32_t target_flags) {\n    const auto &a = op.args;\n    const auto &t = op.targets;\n\n    assert(a.size() == 1);\n    if (a[0] == 0) {\n        return;\n    }\n    for (size_t k = op.targets.size(); k--;) {\n        cur_loc.instruction_targets.target_range_start = k;\n        cur_loc.instruction_targets.target_range_end = k + 1;\n        resolve_paulis_into(&op.targets[k], target_flags, cur_loc.flipped_pauli_product);\n        err_atom(CircuitInstruction{op.gate_type, a, &t[k], op.tag});\n        cur_loc.flipped_pauli_product.clear();\n    }\n}\n\nvoid ErrorMatcher::err_heralded_pauli_channel_1(const CircuitInstruction &op) {\n    assert(op.args.size() == 4);\n    for (size_t k = op.targets.size(); k--;) {\n        auto q = op.targets[k].qubit_value();\n        cur_loc.instruction_targets.target_range_start = k;\n        cur_loc.instruction_targets.target_range_end = k + 1;\n\n        cur_loc.flipped_measurement.measurement_record_index = error_analyzer.tracker.num_measurements_in_past - 1;\n        SpanRef<const DemTarget> herald_symptoms =\n            error_analyzer.tracker.rec_bits[error_analyzer.tracker.num_measurements_in_past - 1].range();\n        SpanRef<const DemTarget> x_symptoms = error_analyzer.tracker.zs[q].range();\n        SpanRef<const DemTarget> z_symptoms = error_analyzer.tracker.xs[q].range();\n        if (op.args[0] != 0) {\n            add_dem_error(ErrorEquivalenceClass{herald_symptoms, op.tag});\n        }\n        if (op.args[1] != 0) {\n            error_analyzer.mono_buf.append_tail(herald_symptoms);\n            error_analyzer.mono_buf.append_tail(x_symptoms);\n            error_analyzer.mono_buf.tail = inplace_xor_sort(error_analyzer.mono_buf.tail);\n            resolve_paulis_into(&op.targets[k], TARGET_PAULI_X_BIT, cur_loc.flipped_pauli_product);\n            add_dem_error(ErrorEquivalenceClass{error_analyzer.mono_buf.tail, op.tag});\n            cur_loc.flipped_pauli_product.clear();\n            error_analyzer.mono_buf.discard_tail();\n        }\n        if (op.args[2] != 0) {\n            error_analyzer.mono_buf.append_tail(herald_symptoms);\n            error_analyzer.mono_buf.append_tail(x_symptoms);\n            error_analyzer.mono_buf.append_tail(z_symptoms);\n            error_analyzer.mono_buf.tail = inplace_xor_sort(error_analyzer.mono_buf.tail);\n            resolve_paulis_into(&op.targets[k], TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT, cur_loc.flipped_pauli_product);\n            add_dem_error(ErrorEquivalenceClass{error_analyzer.mono_buf.tail, op.tag});\n            cur_loc.flipped_pauli_product.clear();\n            error_analyzer.mono_buf.discard_tail();\n        }\n        if (op.args[3] != 0) {\n            error_analyzer.mono_buf.append_tail(herald_symptoms);\n            error_analyzer.mono_buf.append_tail(z_symptoms);\n            error_analyzer.mono_buf.tail = inplace_xor_sort(error_analyzer.mono_buf.tail);\n            resolve_paulis_into(&op.targets[k], TARGET_PAULI_Z_BIT, cur_loc.flipped_pauli_product);\n            add_dem_error(ErrorEquivalenceClass{error_analyzer.mono_buf.tail, op.tag});\n            cur_loc.flipped_pauli_product.clear();\n            error_analyzer.mono_buf.discard_tail();\n        }\n        cur_loc.flipped_measurement.measurement_record_index = UINT64_MAX;\n\n        assert(error_analyzer.error_class_probabilities.empty());\n        error_analyzer.tracker.undo_gate(\n            CircuitInstruction{\n                op.gate_type,\n                op.args,\n                op.targets.sub(k, k + 1),\n                op.tag,\n            });\n        error_analyzer.mono_buf.clear();\n        error_analyzer.error_class_probabilities.clear();\n        error_analyzer.flushed_reversed_model.clear();\n    }\n}\n\nvoid ErrorMatcher::err_pauli_channel_1(const CircuitInstruction &op) {\n    const auto &a = op.args;\n    const auto &t = op.targets;\n    err_xyz(CircuitInstruction{GateType::X_ERROR, &a[0], t, op.tag}, TARGET_PAULI_X_BIT);\n    err_xyz(CircuitInstruction{GateType::Y_ERROR, &a[1], t, op.tag}, TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT);\n    err_xyz(CircuitInstruction{GateType::Z_ERROR, &a[2], t, op.tag}, TARGET_PAULI_Z_BIT);\n}\n\nvoid ErrorMatcher::err_pauli_channel_2(const CircuitInstruction &op) {\n    const auto &t = op.targets;\n    const auto &a = op.args;\n\n    // Buffers and pointers into them.\n    std::array<GateTarget, 2> pair;\n    double p = 0;\n    CircuitInstruction pair_effect = {GateType::E, &p, pair, op.tag};\n    CircuitInstruction first_effect = {GateType::E, &p, &pair[0], op.tag};\n    CircuitInstruction second_effect = {GateType::E, &p, &pair[1], op.tag};\n\n    for (size_t k = 0; k < t.size(); k += 2) {\n        cur_loc.instruction_targets.target_range_start = k;\n        cur_loc.instruction_targets.target_range_end = k + 2;\n        for (uint8_t p0 = 0; p0 < 4; p0++) {\n            for (uint8_t p1 = !p0; p1 < 4; p1++) {\n                // Extract data for this term of the error.\n                p = a[p0 * 4 + p1 - 1];\n                if (p == 0) {\n                    continue;\n                }\n                bool x0 = p0 & 1;\n                bool z0 = p0 & 2;\n                x0 ^= z0;\n                bool x1 = p1 & 1;\n                bool z1 = p1 & 2;\n                x1 ^= z1;\n                uint32_t m0 = x0 * TARGET_PAULI_X_BIT + z0 * TARGET_PAULI_Z_BIT;\n                uint32_t m1 = x1 * TARGET_PAULI_X_BIT + z1 * TARGET_PAULI_Z_BIT;\n                pair[0].data = t[k].data | m0;\n                pair[1].data = t[k + 1].data | m1;\n\n                // Handle the error term as if it were an isolated CORRELATED_ERROR.\n                if (p0 == 0) {\n                    resolve_paulis_into(&pair[1], 0, cur_loc.flipped_pauli_product);\n                    err_atom(second_effect);\n                } else if (p1 == 0) {\n                    resolve_paulis_into(&pair[0], 0, cur_loc.flipped_pauli_product);\n                    err_atom(first_effect);\n                } else {\n                    resolve_paulis_into(pair, 0, cur_loc.flipped_pauli_product);\n                    err_atom(pair_effect);\n                }\n                cur_loc.flipped_pauli_product.clear();\n            }\n        }\n    }\n}\n\nvoid ErrorMatcher::err_m(const CircuitInstruction &op, uint32_t obs_mask) {\n    const auto &t = op.targets;\n    const auto &a = op.args;\n\n    bool q2 = GATE_DATA[op.gate_type].flags & GATE_TARGETS_PAIRS;\n    size_t end = t.size();\n    while (end > 0) {\n        size_t start = end - 1;\n        while (start > 0 && t[start - 1].is_combiner()) {\n            start -= std::min(start, size_t{2});\n        }\n        if (q2) {\n            start--;\n        }\n\n        SpanRef<const GateTarget> slice{t.begin() + start, t.begin() + end};\n\n        cur_loc.instruction_targets.target_range_start = start;\n        cur_loc.instruction_targets.target_range_end = end;\n        cur_loc.flipped_measurement.measurement_record_index = error_analyzer.tracker.num_measurements_in_past - 1;\n        resolve_paulis_into(slice, obs_mask, cur_loc.flipped_measurement.measured_observable);\n        err_atom(CircuitInstruction{op.gate_type, a, slice, op.tag});\n        cur_loc.flipped_measurement.measurement_record_index = UINT64_MAX;\n        cur_loc.flipped_measurement.measured_observable.clear();\n\n        end = start;\n    }\n}\n\nvoid ErrorMatcher::rev_process_instruction(const CircuitInstruction &op) {\n    cur_loc.instruction_targets.gate_type = op.gate_type;\n    cur_loc.instruction_targets.gate_tag = op.tag;\n    auto flags = GATE_DATA[op.gate_type].flags;\n    cur_loc.tick_offset = error_analyzer.num_ticks_in_past;\n    cur_op = &op;\n\n    if (op.gate_type == GateType::DETECTOR) {\n        error_analyzer.undo_DETECTOR(op);\n        if (!op.args.empty()) {\n            auto id = error_analyzer.tracker.num_detectors_in_past;\n            auto entry = dem_coords_map.insert({id, {}}).first;\n            for (size_t k = 0; k < op.args.size(); k++) {\n                double d = op.args[k];\n                if (k < cur_coord_offset.size()) {\n                    d += cur_coord_offset[k];\n                }\n                entry->second.push_back(d);\n            }\n        }\n        return;\n    } else if (op.gate_type == GateType::SHIFT_COORDS) {\n        error_analyzer.undo_SHIFT_COORDS(op);\n        for (size_t k = 0; k < op.args.size(); k++) {\n            cur_coord_offset[k] -= op.args[k];\n        }\n        return;\n    } else if (!(flags & (GATE_IS_NOISY | GATE_PRODUCES_RESULTS))) {\n        error_analyzer.undo_gate(op);\n        return;\n    }\n    switch (op.gate_type) {\n        case GateType::MPAD:\n            error_analyzer.undo_gate(op);\n            break;\n        case GateType::E:\n        case GateType::ELSE_CORRELATED_ERROR: {\n            cur_loc.instruction_targets.target_range_start = 0;\n            cur_loc.instruction_targets.target_range_end = op.targets.size();\n            resolve_paulis_into(op.targets, 0, cur_loc.flipped_pauli_product);\n            CircuitInstruction op2 = op;\n            op2.gate_type = GateType::E;\n            err_atom(op2);\n            cur_loc.flipped_pauli_product.clear();\n            break;\n        }\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n            // No effect.\n            break;\n        case GateType::X_ERROR:\n            err_xyz(op, TARGET_PAULI_X_BIT);\n            break;\n        case GateType::Y_ERROR:\n            err_xyz(op, TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT);\n            break;\n        case GateType::Z_ERROR:\n            err_xyz(op, TARGET_PAULI_Z_BIT);\n            break;\n        case GateType::PAULI_CHANNEL_1:\n            err_pauli_channel_1(op);\n            break;\n        case GateType::HERALDED_PAULI_CHANNEL_1:\n            err_heralded_pauli_channel_1(op);\n            break;\n        case GateType::HERALDED_ERASE: {\n            float p = op.args[0] / 4;\n            std::array<double, 4> spread{p, p, p, p};\n            err_heralded_pauli_channel_1(CircuitInstruction{op.gate_type, spread, op.targets, op.tag});\n            break;\n        }\n        case GateType::DEPOLARIZE1: {\n            float p = op.args[0];\n            std::array<double, 3> spread{p, p, p};\n            err_pauli_channel_1(CircuitInstruction{op.gate_type, spread, op.targets, op.tag});\n            break;\n        }\n        case GateType::PAULI_CHANNEL_2:\n            err_pauli_channel_2(op);\n            break;\n        case GateType::DEPOLARIZE2: {\n            float p = op.args[0];\n            std::array<double, 15> spread{p, p, p, p, p, p, p, p, p, p, p, p, p, p, p};\n            err_pauli_channel_2(CircuitInstruction{op.gate_type, spread, op.targets, op.tag});\n            break;\n        }\n        case GateType::MPP:\n            err_m(op, 0);\n            break;\n        case GateType::MX:\n        case GateType::MRX:\n        case GateType::MXX:\n            err_m(op, TARGET_PAULI_X_BIT);\n            break;\n        case GateType::MY:\n        case GateType::MRY:\n        case GateType::MYY:\n            err_m(op, TARGET_PAULI_X_BIT | TARGET_PAULI_Z_BIT);\n            break;\n        case GateType::M:\n        case GateType::MR:\n        case GateType::MZZ:\n            err_m(op, TARGET_PAULI_Z_BIT);\n            break;\n        default:\n            throw std::invalid_argument(\n                \"Not implemented in ErrorMatcher::rev_process_instruction: \" +\n                std::string(GATE_DATA[op.gate_type].name));\n    }\n}\n\nvoid ErrorMatcher::rev_process_circuit(uint64_t reps, const Circuit &block) {\n    cur_loc.stack_frames.push_back({0, 0, 0});\n    cur_loc.flipped_measurement.measurement_record_index = UINT64_MAX;\n    for (size_t rep = reps; rep--;) {\n        cur_loc.stack_frames.back().iteration_index = rep;\n        for (size_t k = block.operations.size(); k--;) {\n            cur_loc.stack_frames.back().instruction_offset = k;\n\n            const auto &op = block.operations[k];\n            if (op.gate_type == GateType::REPEAT) {\n                auto rep_count = op.repeat_block_rep_count();\n                cur_loc.stack_frames.back().instruction_repetitions_arg = op.repeat_block_rep_count();\n                rev_process_circuit(rep_count, op.repeat_block_body(block));\n                cur_loc.stack_frames.back().instruction_repetitions_arg = 0;\n            } else {\n                rev_process_instruction(op);\n            }\n        }\n    }\n    cur_loc.stack_frames.pop_back();\n}\n\nstd::vector<ExplainedError> ErrorMatcher::explain_errors_from_circuit(\n    const Circuit &circuit, const DetectorErrorModel *filter, bool reduce_to_one_representative_error) {\n    // Find the matches.\n    ErrorMatcher finder(circuit, filter, reduce_to_one_representative_error);\n    finder.rev_process_circuit(1, circuit);\n\n    // And list them out.\n    std::vector<ExplainedError> result;\n    for (auto &e : finder.output_map) {\n        e.second.fill_in_dem_targets(e.first, finder.dem_coords_map);\n        result.push_back(std::move(e.second));\n    }\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/simulators/error_matcher.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_ERROR_MATCHER_H\n#define _STIM_SIMULATORS_ERROR_MATCHER_H\n\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/simulators/matched_error.h\"\n\nnamespace stim {\n\n/// This class handles matching circuit errors to detector-error-model errors.\nstruct ErrorMatcher {\n    /// The error analyzer handles most of converting circuit errors into detector errors.\n    ErrorAnalyzer error_analyzer;\n\n    // This value is tweaked and adjusted while iterating through the circuit, tracking\n    // where we currently are.\n    CircuitErrorLocation cur_loc;\n    const CircuitInstruction *cur_op;\n\n    // Tracks discovered pairings keyed by their detector-error-model error terms.\n    //\n    // Pointed-to key data is owned by `dem_targets_buf``.\n    std::map<SpanRef<const DemTarget>, ExplainedError> output_map;\n    bool allow_adding_new_dem_errors_to_output_map;\n    bool reduce_to_one_representative_error;\n\n    std::map<uint64_t, std::vector<double>> dem_coords_map;\n    std::map<uint64_t, std::vector<double>> qubit_coords_map;\n    std::vector<double> cur_coord_offset;\n\n    MonotonicBuffer<DemTarget> dem_targets_buf;\n    uint64_t total_measurements_in_circuit;\n    uint64_t total_ticks_in_circuit;\n\n    // This class has pointers into its own data. Can't just copy it around!\n    ErrorMatcher(const ErrorMatcher &) = delete;\n\n    /// Finds detector-error-model errors while matching them with their source circuit errors.\n    ///\n    /// Note that detector-error-model errors are not repeated. Each is matched with one\n    /// representative circuit error, which is chosen arbitrarily from the available options.\n    ///\n    /// Args:\n    ///     circuit: The noisy circuit to search for detector-error-model+circuit matches.\n    ///     filter: Optional. When not empty, any detector-error-model errors that don't appear\n    ///         in this filter will not be included in the result. When empty, all\n    ///         detector-error-model errors are included.\n    ///\n    /// Returns:\n    ///     A list of detector-error-model-paired-with-explanatory-circuit-error items.\n    static std::vector<ExplainedError> explain_errors_from_circuit(\n        const Circuit &circuit, const DetectorErrorModel *filter, bool reduce_to_one_representative_error);\n\n    /// Constructs an error candidate finder based on parameters that are given to\n    /// `ErrorCandidateFinder::explain_errors_from_circuit`.\n    ErrorMatcher(const Circuit &circuit, const DetectorErrorModel *filter, bool reduce_to_one_representative_error);\n\n    /// Looks up the coordinates of qubit/pauli terms, and appends into an output vector.\n    void resolve_paulis_into(\n        SpanRef<const GateTarget> targets, uint32_t target_flags, std::vector<GateTargetWithCoords> &out);\n\n    /// Base case for processing a single-term error mechanism.\n    void err_atom(const CircuitInstruction &effect);\n    /// Processes operations with X, Y, Z errors on each target.\n    void err_pauli_channel_1(const CircuitInstruction &op);\n    /// Processes operations with M, X, Y, Z errors on each target.\n    void err_heralded_pauli_channel_1(const CircuitInstruction &op);\n    /// Processes operations with 15 two-qubit Pauli product errors on each target pair.\n    void err_pauli_channel_2(const CircuitInstruction &op);\n    /// Processes measurement operations.\n    void err_m(const CircuitInstruction &op, uint32_t obs_mask);\n    void err_xyz(const CircuitInstruction &op, uint32_t target_flags);\n\n    /// Processes arbitrary instructions.\n    void rev_process_instruction(const CircuitInstruction &op);\n    /// Processes entire circuits.\n    void rev_process_circuit(uint64_t reps, const Circuit &block);\n\n    void add_dem_error(ErrorEquivalenceClass dem_error);\n};\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/error_matcher.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/error_matcher.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n\nusing namespace stim;\n\nTEST(ErrorMatcher, X_ERROR) {\n    auto actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            QUBIT_COORDS(5, 6) 0\n            X_ERROR(0.25) 0\n            M 0\n            DETECTOR(2, 3) rec[-1]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    std::vector<ExplainedError> expected{\n        ExplainedError{\n            {\n                {DemTarget::relative_detector_id(0), {2, 3}},\n            },\n            {\n                CircuitErrorLocation{\n                    .noise_tag = \"\",\n                    .tick_offset = 0,\n                    .flipped_pauli_product =\n                        {\n                            {GateTarget::x(0), {5, 6}},\n                        },\n                    .flipped_measurement = FlippedMeasurement{UINT64_MAX, {}},\n                    .instruction_targets =\n                        CircuitTargetsInsideInstruction{\n                            .gate_type = GateType::X_ERROR,\n                            .gate_tag = \"\",\n                            .args = {0.25},\n                            .target_range_start = 0,\n                            .target_range_end = 1,\n                            .targets_in_range =\n                                {\n                                    {GateTarget::qubit(0), {5, 6}},\n                                },\n                        },\n                    .stack_frames =\n                        {\n                            CircuitErrorLocationStackFrame{1, 0, 0},\n                        },\n                },\n            }},\n    };\n    ASSERT_EQ(actual, expected);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D0[coords 2,3]\n    CircuitErrorLocation {\n        flipped_pauli_product: X0[coords 5,6]\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #2 (X_ERROR) in the circuit\n            at target #1 of the instruction\n            resolving to X_ERROR(0.25) 0[coords 5,6]\n    }\n})RESULT\");\n}\n\nTEST(ErrorMatcher, CORRELATED_ERROR) {\n    auto actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            SHIFT_COORDS(10, 20)\n            QUBIT_COORDS(5, 6) 0\n            SHIFT_COORDS(100, 200)\n            CORRELATED_ERROR(0.25) X0 Y1\n            M 0\n            DETECTOR(2, 3) rec[-1]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D0[coords 112,223]\n    CircuitErrorLocation {\n        flipped_pauli_product: X0[coords 15,26]*Y1\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #4 (E) in the circuit\n            at targets #1 to #2 of the instruction\n            resolving to E(0.25) X0[coords 15,26] Y1\n    }\n})RESULT\");\n}\n\nTEST(ErrorMatcher, MX_ERROR) {\n    auto actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            QUBIT_COORDS(5, 6) 0\n            RX 0\n            REPEAT 10 {\n                TICK\n            }\n            MX(0.125) 1 2 3 0 4\n            DETECTOR(2, 3) rec[-2]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D0[coords 2,3]\n    CircuitErrorLocation {\n        flipped_measurement.measurement_record_index: 3\n        flipped_measurement.measured_observable: X0[coords 5,6]\n        Circuit location stack trace:\n            (after 10 TICKs)\n            at instruction #4 (MX) in the circuit\n            at target #4 of the instruction\n            resolving to MX(0.125) 0[coords 5,6]\n    }\n})RESULT\");\n}\n\nTEST(ErrorMatcher, MPP_ERROR) {\n    auto actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            QUBIT_COORDS(5, 6) 0\n            RY 0\n            MPP(0.125) Z1 Y0*Z3*Z4 Y5\n            DETECTOR(2, 3) rec[-2]\n            DETECTOR(5, 6) rec[-2]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D0[coords 2,3] D1[coords 5,6]\n    CircuitErrorLocation {\n        flipped_measurement.measurement_record_index: 1\n        flipped_measurement.measured_observable: Y0[coords 5,6]*Z3*Z4\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #3 (MPP) in the circuit\n            at targets #2 to #6 of the instruction\n            resolving to MPP(0.125) Y0[coords 5,6]*Z3*Z4\n    }\n})RESULT\");\n}\n\nTEST(ErrorMatcher, MXX_ERROR) {\n    auto actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            QUBIT_COORDS(5, 6) 0\n            RX 0\n            CX 0 1\n            MXX(0.125) 0 1\n            DETECTOR(2, 3) rec[-1]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D0[coords 2,3]\n    CircuitErrorLocation {\n        flipped_measurement.measurement_record_index: 0\n        flipped_measurement.measured_observable: X0[coords 5,6]*X1\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #4 (MXX) in the circuit\n            at targets #1 to #2 of the instruction\n            resolving to MXX(0.125) 0[coords 5,6] 1\n    }\n})RESULT\");\n}\n\nTEST(ErrorMatcher, ELSE_CORRELATED_ERROR) {\n    auto actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            R 0 1\n            H 1\n            CORRELATED_ERROR(0.25) X0\n            ELSE_CORRELATED_ERROR(0.125) Z1\n            H 1\n            M 0 1\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D0\n    CircuitErrorLocation {\n        flipped_pauli_product: Z1\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #4 (ELSE_CORRELATED_ERROR) in the circuit\n            at target #1 of the instruction\n            resolving to ELSE_CORRELATED_ERROR(0.125) Z1\n    }\n})RESULT\");\n}\n\nTEST(ErrorMatcher, HERALDED_ERASE) {\n    auto actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 1\n            MYY 0 1\n            MZZ 0 1\n            HERALDED_ERASE(0.125) 0\n            MXX 0 1\n            MYY 0 1\n            MZZ 0 1\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 4);\n    ASSERT_EQ(actual[0].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D0 D1 D3\n    CircuitErrorLocation {\n        flipped_pauli_product: X0\n        flipped_measurement.measurement_record_index: 3\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #4 (HERALDED_ERASE) in the circuit\n            at target #1 of the instruction\n            resolving to HERALDED_ERASE(0.125) 0\n    }\n})RESULT\");\n    ASSERT_EQ(actual[1].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D0 D2 D3\n    CircuitErrorLocation {\n        flipped_pauli_product: Y0\n        flipped_measurement.measurement_record_index: 3\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #4 (HERALDED_ERASE) in the circuit\n            at target #1 of the instruction\n            resolving to HERALDED_ERASE(0.125) 0\n    }\n})RESULT\");\n    ASSERT_EQ(actual[2].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D1 D2 D3\n    CircuitErrorLocation {\n        flipped_pauli_product: Z0\n        flipped_measurement.measurement_record_index: 3\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #4 (HERALDED_ERASE) in the circuit\n            at target #1 of the instruction\n            resolving to HERALDED_ERASE(0.125) 0\n    }\n})RESULT\");\n    ASSERT_EQ(actual[3].str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D3\n    CircuitErrorLocation {\n        flipped_measurement.measurement_record_index: 3\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #4 (HERALDED_ERASE) in the circuit\n            at target #1 of the instruction\n            resolving to HERALDED_ERASE(0.125) 0\n    }\n})RESULT\");\n}\n\nTEST(ErrorMatcher, repetition_code_data_depolarization) {\n    CircuitGenParameters params(2, 3, \"memory\");\n    params.before_round_data_depolarization = 0.001;\n    auto circuit = generate_rep_code_circuit(params).circuit;\n\n    auto actual = ErrorMatcher::explain_errors_from_circuit(circuit, nullptr, false);\n    std::stringstream ss;\n    for (const auto &match : actual) {\n        ss << \"\\n\" << match << \"\\n\";\n    }\n    ASSERT_EQ(ss.str(), R\"RESULT(\nExplainedError {\n    dem_error_terms: D0[coords 1,0]\n    CircuitErrorLocation {\n        flipped_pauli_product: X0\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.001) 0\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: Y0\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.001) 0\n    }\n}\n\nExplainedError {\n    dem_error_terms: D0[coords 1,0] D1[coords 3,0]\n    CircuitErrorLocation {\n        flipped_pauli_product: X2\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #2 of the instruction\n            resolving to DEPOLARIZE1(0.001) 2\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: Y2\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #2 of the instruction\n            resolving to DEPOLARIZE1(0.001) 2\n    }\n}\n\nExplainedError {\n    dem_error_terms: D1[coords 3,0] L0\n    CircuitErrorLocation {\n        flipped_pauli_product: X4\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #3 of the instruction\n            resolving to DEPOLARIZE1(0.001) 4\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: Y4\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #3 of the instruction\n            resolving to DEPOLARIZE1(0.001) 4\n    }\n}\n\nExplainedError {\n    dem_error_terms: D2[coords 1,1]\n    CircuitErrorLocation {\n        flipped_pauli_product: X0\n        Circuit location stack trace:\n            (after 4 TICKs)\n            at instruction #12 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.001) 0\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: Y0\n        Circuit location stack trace:\n            (after 4 TICKs)\n            at instruction #12 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.001) 0\n    }\n}\n\nExplainedError {\n    dem_error_terms: D2[coords 1,1] D3[coords 3,1]\n    CircuitErrorLocation {\n        flipped_pauli_product: X2\n        Circuit location stack trace:\n            (after 4 TICKs)\n            at instruction #12 (DEPOLARIZE1) in the circuit\n            at target #2 of the instruction\n            resolving to DEPOLARIZE1(0.001) 2\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: Y2\n        Circuit location stack trace:\n            (after 4 TICKs)\n            at instruction #12 (DEPOLARIZE1) in the circuit\n            at target #2 of the instruction\n            resolving to DEPOLARIZE1(0.001) 2\n    }\n}\n\nExplainedError {\n    dem_error_terms: D3[coords 3,1] L0\n    CircuitErrorLocation {\n        flipped_pauli_product: X4\n        Circuit location stack trace:\n            (after 4 TICKs)\n            at instruction #12 (DEPOLARIZE1) in the circuit\n            at target #3 of the instruction\n            resolving to DEPOLARIZE1(0.001) 4\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: Y4\n        Circuit location stack trace:\n            (after 4 TICKs)\n            at instruction #12 (DEPOLARIZE1) in the circuit\n            at target #3 of the instruction\n            resolving to DEPOLARIZE1(0.001) 4\n    }\n}\n)RESULT\");\n}\n\nTEST(ErrorMatcher, repetition_code_data_depolarization_single_results) {\n    CircuitGenParameters params(2, 3, \"memory\");\n    params.before_round_data_depolarization = 0.001;\n    auto circuit = generate_rep_code_circuit(params).circuit;\n\n    auto actual = ErrorMatcher::explain_errors_from_circuit(circuit, nullptr, true);\n    std::stringstream ss;\n    for (const auto &match : actual) {\n        ss << \"\\n\" << match << \"\\n\";\n    }\n    ASSERT_EQ(ss.str(), R\"RESULT(\nExplainedError {\n    dem_error_terms: D0[coords 1,0]\n    CircuitErrorLocation {\n        flipped_pauli_product: X0\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.001) 0\n    }\n}\n\nExplainedError {\n    dem_error_terms: D0[coords 1,0] D1[coords 3,0]\n    CircuitErrorLocation {\n        flipped_pauli_product: X2\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #2 of the instruction\n            resolving to DEPOLARIZE1(0.001) 2\n    }\n}\n\nExplainedError {\n    dem_error_terms: D1[coords 3,0] L0\n    CircuitErrorLocation {\n        flipped_pauli_product: X4\n        Circuit location stack trace:\n            (after 1 TICKs)\n            at instruction #3 (DEPOLARIZE1) in the circuit\n            at target #3 of the instruction\n            resolving to DEPOLARIZE1(0.001) 4\n    }\n}\n\nExplainedError {\n    dem_error_terms: D2[coords 1,1]\n    CircuitErrorLocation {\n        flipped_pauli_product: X0\n        Circuit location stack trace:\n            (after 4 TICKs)\n            at instruction #12 (DEPOLARIZE1) in the circuit\n            at target #1 of the instruction\n            resolving to DEPOLARIZE1(0.001) 0\n    }\n}\n\nExplainedError {\n    dem_error_terms: D2[coords 1,1] D3[coords 3,1]\n    CircuitErrorLocation {\n        flipped_pauli_product: X2\n        Circuit location stack trace:\n            (after 4 TICKs)\n            at instruction #12 (DEPOLARIZE1) in the circuit\n            at target #2 of the instruction\n            resolving to DEPOLARIZE1(0.001) 2\n    }\n}\n\nExplainedError {\n    dem_error_terms: D3[coords 3,1] L0\n    CircuitErrorLocation {\n        flipped_pauli_product: X4\n        Circuit location stack trace:\n            (after 4 TICKs)\n            at instruction #12 (DEPOLARIZE1) in the circuit\n            at target #3 of the instruction\n            resolving to DEPOLARIZE1(0.001) 4\n    }\n}\n)RESULT\");\n}\n\nTEST(ErrorMatcher, surface_code_filter) {\n    CircuitGenParameters params(5, 5, \"rotated_memory_z\");\n    params.before_round_data_depolarization = 0.001;\n    params.after_clifford_depolarization = 0.001;\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    DetectorErrorModel filter(R\"MODEL(\n        error(1) D97 D98 D102 D103\n)MODEL\");\n\n    auto actual = ErrorMatcher::explain_errors_from_circuit(circuit, &filter, false);\n    std::stringstream ss;\n    for (const auto &match : actual) {\n        ss << \"\\n\" << match << \"\\n\";\n    }\n    ASSERT_EQ(ss.str(), R\"RESULT(\nExplainedError {\n    dem_error_terms: D97[coords 4,6,4] D98[coords 6,6,4] D102[coords 2,8,4] D103[coords 4,8,4]\n    CircuitErrorLocation {\n        flipped_pauli_product: Y37[coords 4,6]*Y36[coords 3,7]\n        Circuit location stack trace:\n            (after 31 TICKs)\n            at instruction #89 (a REPEAT 4 block) in the circuit\n            after 3 completed iterations\n            at instruction #10 (DEPOLARIZE2) in the REPEAT block\n            at targets #9 to #10 of the instruction\n            resolving to DEPOLARIZE2(0.001) 37[coords 4,6] 36[coords 3,7]\n    }\n}\n)RESULT\");\n}\n\nTEST(ErrorMatcher, runs_on_all_gates_circuit) {\n    DetectorErrorModel filter(R\"MODEL(\n        error(1) D0\n)MODEL\");\n\n    auto circuit = generate_test_circuit_with_all_operations();\n    auto actual = ErrorMatcher::explain_errors_from_circuit(circuit, &filter, false);\n    std::stringstream ss;\n    for (const auto &match : actual) {\n        ss << \"\\n\" << match << \"\\n\";\n    }\n    ASSERT_EQ(ss.str(), R\"RESULT(\nExplainedError {\n    dem_error_terms: D0[coords 2,4,6]\n    [no single circuit error had these exact symptoms]\n}\n)RESULT\");\n}\n\nTEST(ErrorMatcher, heralded_error) {\n    Circuit circuit(R\"CIRCUIT(\n        HERALDED_ERASE(0.01) 0\n        DETECTOR rec[-1]\n        HERALDED_ERASE(0.01) 1 2\n    )CIRCUIT\");\n    DetectorErrorModel filter(R\"MODEL(\n        error(1) D0\n    )MODEL\");\n\n    auto actual = ErrorMatcher::explain_errors_from_circuit(circuit, &filter, false);\n    std::stringstream ss;\n    for (const auto &match : actual) {\n        ss << \"\\n\" << match << \"\\n\";\n    }\n    ASSERT_EQ(ss.str(), R\"RESULT(\nExplainedError {\n    dem_error_terms: D0\n    CircuitErrorLocation {\n        flipped_measurement.measurement_record_index: 0\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #1 (HERALDED_ERASE) in the circuit\n            at target #1 of the instruction\n            resolving to HERALDED_ERASE(0.01) 0\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: X0\n        flipped_measurement.measurement_record_index: 0\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #1 (HERALDED_ERASE) in the circuit\n            at target #1 of the instruction\n            resolving to HERALDED_ERASE(0.01) 0\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: Y0\n        flipped_measurement.measurement_record_index: 0\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #1 (HERALDED_ERASE) in the circuit\n            at target #1 of the instruction\n            resolving to HERALDED_ERASE(0.01) 0\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: Z0\n        flipped_measurement.measurement_record_index: 0\n        Circuit location stack trace:\n            (after 0 TICKs)\n            at instruction #1 (HERALDED_ERASE) in the circuit\n            at target #1 of the instruction\n            resolving to HERALDED_ERASE(0.01) 0\n    }\n}\n)RESULT\");\n}\n\nTEST(ErrorMatcher, PAULI_CHANNEL_2) {\n    std::vector<ExplainedError> actual;\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{GateTargetWithCoords{GateTarget::x(1)}}));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{GateTargetWithCoords{GateTarget::y(1)}}));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{GateTargetWithCoords{GateTarget::z(1)}}));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::x(0)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::x(0)},\n            GateTargetWithCoords{GateTarget::x(1)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::x(0)},\n            GateTargetWithCoords{GateTarget::y(1)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0, 0.1, 0, 0, 0, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::x(0)},\n            GateTargetWithCoords{GateTarget::z(1)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0, 0, 0.1, 0, 0, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::y(0)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0, 0, 0, 0.1, 0, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::y(0)},\n            GateTargetWithCoords{GateTarget::x(1)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0, 0, 0, 0, 0.1, 0, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::y(0)},\n            GateTargetWithCoords{GateTarget::y(1)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.1, 0, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::y(0)},\n            GateTargetWithCoords{GateTarget::z(1)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.1, 0, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::z(0)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.1, 0, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::z(0)},\n            GateTargetWithCoords{GateTarget::x(1)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.1, 0) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::z(0)},\n            GateTargetWithCoords{GateTarget::y(1)},\n        }));\n\n    actual = ErrorMatcher::explain_errors_from_circuit(\n        Circuit(R\"CIRCUIT(\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            PAULI_CHANNEL_2(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.1) 0 1\n            MXX 0 2 1 3\n            MZZ 0 2 1 3\n            DETECTOR rec[-1] rec[-5]\n            DETECTOR rec[-2] rec[-6]\n            DETECTOR rec[-3] rec[-7]\n            DETECTOR rec[-4] rec[-8]\n        )CIRCUIT\"),\n        nullptr,\n        false);\n    ASSERT_EQ(actual.size(), 1);\n    ASSERT_EQ(actual[0].circuit_error_locations.size(), 1);\n    ASSERT_EQ(\n        actual[0].circuit_error_locations[0].flipped_pauli_product,\n        (std::vector<GateTargetWithCoords>{\n            GateTargetWithCoords{GateTarget::z(0)},\n            GateTargetWithCoords{GateTarget::z(1)},\n        }));\n}\n"
  },
  {
    "path": "src/stim/simulators/force_streaming.cc",
    "content": "#include \"stim/simulators/force_streaming.h\"\n\n#include <cstddef>\n\nnamespace stim {\n\nstatic size_t force_stream_count = 0;\nDebugForceResultStreamingRaii::DebugForceResultStreamingRaii() {\n    force_stream_count++;\n}\nDebugForceResultStreamingRaii::~DebugForceResultStreamingRaii() {\n    force_stream_count--;\n}\n\nbool should_use_streaming_because_bit_count_is_too_large_to_store(uint64_t bit_count) {\n    return force_stream_count > 0 || bit_count > (uint64_t{1} << 32);\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/simulators/force_streaming.h",
    "content": "#ifndef _STIM_SIMULATORS_FORCE_STREAMING_H\n#define _STIM_SIMULATORS_FORCE_STREAMING_H\n\n#include <cstdint>\n\nnamespace stim {\n\n/// Facilitates testing of simulators with streaming enabled without\n/// having to make enormous circuits.\nbool should_use_streaming_because_bit_count_is_too_large_to_store(uint64_t result_count);\nstruct DebugForceResultStreamingRaii {\n    DebugForceResultStreamingRaii();\n    ~DebugForceResultStreamingRaii();\n};\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_FRAME_SIMULATOR_H\n#define _STIM_SIMULATORS_FRAME_SIMULATOR_H\n\n#include <random>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/io/measure_record_batch.h\"\n#include \"stim/mem/simd_bit_table.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nnamespace stim {\n\nenum class FrameSimulatorMode {\n    STORE_MEASUREMENTS_TO_MEMORY,  // all measurements stored, detections not stored\n    STREAM_MEASUREMENTS_TO_DISK,   // measurements stored up to lookback, detections not stored\n    STORE_DETECTIONS_TO_MEMORY,    // measurements stored up to lookback, all detections stored\n    STREAM_DETECTIONS_TO_DISK,     // measurements stored up to lookback, detections stored until write\n    STORE_EVERYTHING_TO_MEMORY,    // all measurements stored and all detections stored\n};\n\n/// A Pauli Frame simulator that computes many samples simultaneously.\n///\n/// This simulator tracks, for each qubit, whether or not that qubit is bit flipped and/or phase flipped.\n/// Instead of reporting qubit measurements, it reports whether a measurement is inverted or not.\n/// This requires a set of reference measurements to diff against.\n///\n/// The template parameter, W, represents the SIMD width\ntemplate <size_t W>\nstruct FrameSimulator {\n    size_t num_qubits;                 // Number of qubits being tracked.\n    uint64_t num_observables;          // Number of observables being tracked.\n    bool keeping_detection_data;       // Whether or not to store dets and obs data.\n    size_t batch_size;                 // Number of instances being tracked.\n    simd_bit_table<W> x_table;         // x_table[q][k] is whether or not there's an X error on qubit q in instance k.\n    simd_bit_table<W> z_table;         // z_table[q][k] is whether or not there's a Z error on qubit q in instance k.\n    MeasureRecordBatch<W> m_record;    // The measurement record.\n    MeasureRecordBatch<W> det_record;  // Detection event record.\n    simd_bit_table<W> obs_record;      // Accumulating observable flip record.\n    simd_bits<W> rng_buffer;           // Workspace used when sampling error processes.\n    simd_bits<W> tmp_storage;          // Workspace used when sampling compound error processes.\n    simd_bits<W> last_correlated_error_occurred;  // correlated error flag for each instance.\n    simd_bit_table<W> sweep_table;                // Shot-to-shot configuration data.\n    std::mt19937_64 rng;                          // Random number generator used for generating entropy.\n\n    // Determines whether e.g. 50% Z errors are multiplied into the frame when measuring in the Z basis.\n    // This is necessary for correct sampling.\n    // It should only be disabled when e.g. using the frame simulator to understand how a fixed set of errors will\n    // propagate, without interference from other effects.\n    bool guarantee_anticommutation_via_frame_randomization = true;\n\n    /// Constructs a FrameSimulator capable of simulating a circuit with the given size stats.\n    ///\n    /// Args:\n    ///     circuit_stats: Sizes that determine how large internal buffers must be. Get\n    ///         this from stim::Circuit::compute_stats.\n    ///     mode: Describes the intended usage of the simulator, which affects the sizing\n    ///         of buffers.\n    ///     batch_size: How many shots to simulate simultaneously.\n    ///     rng: The random number generator to pull noise from.\n    FrameSimulator(CircuitStats circuit_stats, FrameSimulatorMode mode, size_t batch_size, std::mt19937_64 &&rng);\n    FrameSimulator() = delete;\n\n    PauliString<W> get_frame(size_t sample_index) const;\n    void set_frame(size_t sample_index, const PauliStringRef<W> &new_frame);\n    void configure_for(CircuitStats new_circuit_stats, FrameSimulatorMode new_mode, size_t new_batch_size);\n    void ensure_safe_to_do_circuit_with_stats(const CircuitStats &stats);\n\n    void safe_do_instruction(const CircuitInstruction &instruction);\n    void safe_do_circuit(const Circuit &circuit, uint64_t repetitions = 1);\n\n    void do_circuit(const Circuit &circuit);\n    void reset_all();\n\n    void do_gate(const CircuitInstruction &inst);\n\n    void do_MX(const CircuitInstruction &inst);\n    void do_MY(const CircuitInstruction &inst);\n    void do_MZ(const CircuitInstruction &inst);\n    void do_RX(const CircuitInstruction &inst);\n    void do_RY(const CircuitInstruction &inst);\n    void do_RZ(const CircuitInstruction &inst);\n    void do_MRX(const CircuitInstruction &inst);\n    void do_MRY(const CircuitInstruction &inst);\n    void do_MRZ(const CircuitInstruction &inst);\n\n    void do_DETECTOR(const CircuitInstruction &inst);\n    void do_OBSERVABLE_INCLUDE(const CircuitInstruction &inst);\n\n    void do_I(const CircuitInstruction &inst);\n    void do_H_XZ(const CircuitInstruction &inst);\n    void do_H_XY(const CircuitInstruction &inst);\n    void do_H_YZ(const CircuitInstruction &inst);\n    void do_C_XYZ(const CircuitInstruction &inst);\n    void do_C_ZYX(const CircuitInstruction &inst);\n    void do_ZCX(const CircuitInstruction &inst);\n    void do_ZCY(const CircuitInstruction &inst);\n    void do_ZCZ(const CircuitInstruction &inst);\n    void do_XCX(const CircuitInstruction &inst);\n    void do_XCY(const CircuitInstruction &inst);\n    void do_XCZ(const CircuitInstruction &inst);\n    void do_YCX(const CircuitInstruction &inst);\n    void do_YCY(const CircuitInstruction &inst);\n    void do_YCZ(const CircuitInstruction &inst);\n    void do_SWAP(const CircuitInstruction &inst);\n    void do_ISWAP(const CircuitInstruction &inst);\n    void do_CXSWAP(const CircuitInstruction &inst);\n    void do_CZSWAP(const CircuitInstruction &inst);\n    void do_SWAPCX(const CircuitInstruction &inst);\n    void do_MPP(const CircuitInstruction &inst);\n    void do_SPP(const CircuitInstruction &inst);\n    void do_SPP_DAG(const CircuitInstruction &inst);\n    void do_MXX(const CircuitInstruction &inst);\n    void do_MYY(const CircuitInstruction &inst);\n    void do_MZZ(const CircuitInstruction &inst);\n    void do_MPAD(const CircuitInstruction &inst);\n\n    void do_SQRT_XX(const CircuitInstruction &inst);\n    void do_SQRT_YY(const CircuitInstruction &inst);\n    void do_SQRT_ZZ(const CircuitInstruction &inst);\n\n    void do_DEPOLARIZE1(const CircuitInstruction &inst);\n    void do_DEPOLARIZE2(const CircuitInstruction &inst);\n    void do_X_ERROR(const CircuitInstruction &inst);\n    void do_Y_ERROR(const CircuitInstruction &inst);\n    void do_Z_ERROR(const CircuitInstruction &inst);\n    void do_PAULI_CHANNEL_1(const CircuitInstruction &inst);\n    void do_PAULI_CHANNEL_2(const CircuitInstruction &inst);\n    void do_CORRELATED_ERROR(const CircuitInstruction &inst);\n    void do_ELSE_CORRELATED_ERROR(const CircuitInstruction &inst);\n    void do_HERALDED_ERASE(const CircuitInstruction &inst);\n    void do_HERALDED_PAULI_CHANNEL_1(const CircuitInstruction &inst);\n\n   private:\n    void do_MXX_disjoint_controls_segment(const CircuitInstruction &inst);\n    void do_MYY_disjoint_controls_segment(const CircuitInstruction &inst);\n    void do_MZZ_disjoint_controls_segment(const CircuitInstruction &inst);\n    void xor_control_bit_into(uint32_t control, simd_bits_range_ref<W> target);\n    void single_cx(uint32_t c, uint32_t t);\n    void single_cy(uint32_t c, uint32_t t);\n};\n\n}  // namespace stim\n\n#include \"stim/simulators/frame_simulator.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <algorithm>\n#include <cstring>\n\n#include \"stim/circuit/gate_decomposition.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/probability_util.h\"\n\nnamespace stim {\n\n// Iterates over the X and Z frame components of a pair of qubits, applying a custom FUNC to each.\n//\n// HACK: Templating the body function type makes inlining significantly more likely.\ntemplate <typename FUNC, size_t W>\ninline void for_each_target_pair(FrameSimulator<W> &sim, const CircuitInstruction &target_data, FUNC body) {\n    const auto &targets = target_data.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        size_t q1 = targets[k].data;\n        size_t q2 = targets[k + 1].data;\n        sim.x_table[q1].for_each_word(sim.z_table[q1], sim.x_table[q2], sim.z_table[q2], body);\n    }\n}\n\ntemplate <size_t W>\nFrameSimulator<W>::FrameSimulator(\n    CircuitStats circuit_stats, FrameSimulatorMode mode, size_t batch_size, std::mt19937_64 &&rng)\n    : num_qubits(0),\n      num_observables(0),\n      keeping_detection_data(false),\n      batch_size(0),\n      x_table(0, 0),\n      z_table(0, 0),\n      m_record(0, 0),\n      det_record(0, 0),\n      obs_record(0, 0),\n      rng_buffer(0),\n      tmp_storage(0),\n      last_correlated_error_occurred(0),\n      sweep_table(0, 0),\n      rng(std::move(rng)) {\n    configure_for(circuit_stats, mode, batch_size);\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::configure_for(\n    CircuitStats new_circuit_stats, FrameSimulatorMode new_mode, size_t new_batch_size) {\n    bool storing_all_measurements = new_mode == FrameSimulatorMode::STORE_MEASUREMENTS_TO_MEMORY ||\n                                    new_mode == FrameSimulatorMode::STORE_EVERYTHING_TO_MEMORY;\n    bool storing_all_detections = new_mode == FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY ||\n                                  new_mode == FrameSimulatorMode::STORE_EVERYTHING_TO_MEMORY;\n    bool storing_any_detections = new_mode == FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY ||\n                                  new_mode == FrameSimulatorMode::STORE_EVERYTHING_TO_MEMORY ||\n                                  new_mode == FrameSimulatorMode::STREAM_DETECTIONS_TO_DISK;\n\n    batch_size = new_batch_size;\n    num_qubits = new_circuit_stats.num_qubits;\n    keeping_detection_data = storing_any_detections;\n    x_table.destructive_resize(new_circuit_stats.num_qubits, batch_size);\n    z_table.destructive_resize(new_circuit_stats.num_qubits, batch_size);\n    rng_buffer.destructive_resize(batch_size);\n    tmp_storage.destructive_resize(batch_size);\n    last_correlated_error_occurred.destructive_resize(batch_size);\n    sweep_table.destructive_resize(0, batch_size);\n\n    uint64_t num_stored_measurements = new_circuit_stats.max_lookback;\n    if (storing_all_measurements) {\n        num_stored_measurements = std::max(new_circuit_stats.num_measurements, num_stored_measurements);\n    }\n    m_record.destructive_resize(batch_size, num_stored_measurements);\n\n    num_observables = storing_any_detections ? new_circuit_stats.num_observables : 0;\n    det_record.destructive_resize(\n        batch_size,\n        storing_all_detections   ? new_circuit_stats.num_detectors\n        : storing_any_detections ? 1\n                                 : 0),\n        obs_record.destructive_resize(num_observables, batch_size);\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::ensure_safe_to_do_circuit_with_stats(const CircuitStats &stats) {\n    if (x_table.num_major_bits_padded() < stats.num_qubits) {\n        x_table.resize(stats.num_qubits * 2, batch_size);\n        z_table.resize(stats.num_qubits * 2, batch_size);\n    }\n    while (num_qubits < stats.num_qubits) {\n        if (guarantee_anticommutation_via_frame_randomization) {\n            z_table[num_qubits].randomize(batch_size, rng);\n        }\n        num_qubits += 1;\n    }\n\n    size_t num_used_measurements = m_record.stored + stats.num_measurements;\n    if (m_record.storage.num_major_bits_padded() < num_used_measurements) {\n        m_record.storage.resize(num_used_measurements * 2, batch_size);\n    }\n\n    if (keeping_detection_data) {\n        size_t num_detectors = det_record.stored + stats.num_detectors;\n        if (det_record.storage.num_major_bits_padded() < num_detectors) {\n            det_record.storage.resize(num_detectors * 2, batch_size);\n        }\n        if (obs_record.num_major_bits_padded() < stats.num_observables) {\n            obs_record.resize(stats.num_observables * 2, batch_size);\n        }\n        num_observables = std::max(stats.num_observables, num_observables);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::safe_do_circuit(const Circuit &circuit, uint64_t repetitions) {\n    ensure_safe_to_do_circuit_with_stats(circuit.compute_stats().repeated(repetitions));\n    for (size_t rep = 0; rep < repetitions; rep++) {\n        do_circuit(circuit);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::safe_do_instruction(const CircuitInstruction &instruction) {\n    ensure_safe_to_do_circuit_with_stats(instruction.compute_stats(nullptr));\n    do_gate(instruction);\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::xor_control_bit_into(uint32_t control, simd_bits_range_ref<W> target) {\n    uint32_t raw_control = control & ~(TARGET_RECORD_BIT | TARGET_SWEEP_BIT);\n    assert(control != raw_control);\n    if (control & TARGET_RECORD_BIT) {\n        target ^= m_record.lookback(raw_control);\n    } else {\n        if (raw_control < sweep_table.num_major_bits_padded()) {\n            target ^= sweep_table[raw_control];\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::reset_all() {\n    x_table.clear();\n    if (guarantee_anticommutation_via_frame_randomization) {\n        z_table.data.randomize(z_table.data.num_bits_padded(), rng);\n    } else {\n        z_table.clear();\n    }\n    m_record.clear();\n    det_record.clear();\n    obs_record.clear();\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_circuit(const Circuit &circuit) {\n    circuit.for_each_operation([&](const CircuitInstruction &op) {\n        do_gate(op);\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MX(const CircuitInstruction &inst) {\n    m_record.reserve_noisy_space_for_results(inst, rng);\n    for (auto t : inst.targets) {\n        auto q = t.qubit_value();  // Flipping is ignored because it is accounted for in the reference sample.\n        m_record.xor_record_reserved_result(z_table[q]);\n        if (guarantee_anticommutation_via_frame_randomization) {\n            x_table[q].randomize(x_table[q].num_bits_padded(), rng);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MY(const CircuitInstruction &inst) {\n    m_record.reserve_noisy_space_for_results(inst, rng);\n    for (auto t : inst.targets) {\n        auto q = t.qubit_value();  // Flipping is ignored because it is accounted for in the reference sample.\n        x_table[q] ^= z_table[q];\n        m_record.xor_record_reserved_result(x_table[q]);\n        if (guarantee_anticommutation_via_frame_randomization) {\n            z_table[q].randomize(z_table[q].num_bits_padded(), rng);\n        }\n        x_table[q] ^= z_table[q];\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MZ(const CircuitInstruction &inst) {\n    m_record.reserve_noisy_space_for_results(inst, rng);\n    for (auto t : inst.targets) {\n        auto q = t.qubit_value();  // Flipping is ignored because it is accounted for in the reference sample.\n        m_record.xor_record_reserved_result(x_table[q]);\n        if (guarantee_anticommutation_via_frame_randomization) {\n            z_table[q].randomize(z_table[q].num_bits_padded(), rng);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_RX(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        if (guarantee_anticommutation_via_frame_randomization) {\n            x_table[q].randomize(z_table[q].num_bits_padded(), rng);\n        }\n        z_table[q].clear();\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_DETECTOR(const CircuitInstruction &inst) {\n    if (keeping_detection_data) {\n        auto r = det_record.record_zero_result_to_edit();\n        for (auto t : inst.targets) {\n            uint32_t lookback = t.data & TARGET_VALUE_MASK;\n            r ^= m_record.lookback(lookback);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_OBSERVABLE_INCLUDE(const CircuitInstruction &inst) {\n    if (keeping_detection_data) {\n        auto r = obs_record[(size_t)inst.args[0]];\n        for (auto t : inst.targets) {\n            if (t.is_measurement_record_target()) {\n                uint32_t lookback = t.data & TARGET_VALUE_MASK;\n                r ^= m_record.lookback(lookback);\n            } else if (t.is_pauli_target()) {\n                if (t.data & TARGET_PAULI_X_BIT) {\n                    r ^= z_table[t.qubit_value()];\n                }\n                if (t.data & TARGET_PAULI_Z_BIT) {\n                    r ^= x_table[t.qubit_value()];\n                }\n            } else {\n                throw std::invalid_argument(\"Unexpected target for OBSERVABLE_INCLUDE: \" + t.str());\n            }\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_RY(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        if (guarantee_anticommutation_via_frame_randomization) {\n            z_table[q].randomize(z_table[q].num_bits_padded(), rng);\n        }\n        x_table[q] = z_table[q];\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_RZ(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        x_table[q].clear();\n        if (guarantee_anticommutation_via_frame_randomization) {\n            z_table[q].randomize(z_table[q].num_bits_padded(), rng);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MRX(const CircuitInstruction &target_data) {\n    // Note: Caution when implementing this. Can't group the resets. because the same qubit target may appear twice.\n    m_record.reserve_noisy_space_for_results(target_data, rng);\n    for (auto t : target_data.targets) {\n        auto q = t.qubit_value();  // Flipping is ignored because it is accounted for in the reference sample.\n        m_record.xor_record_reserved_result(z_table[q]);\n        z_table[q].clear();\n        if (guarantee_anticommutation_via_frame_randomization) {\n            x_table[q].randomize(x_table[q].num_bits_padded(), rng);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MRY(const CircuitInstruction &target_data) {\n    // Note: Caution when implementing this. Can't group the resets. because the same qubit target may appear twice.\n    m_record.reserve_noisy_space_for_results(target_data, rng);\n    for (auto t : target_data.targets) {\n        auto q = t.qubit_value();  // Flipping is ignored because it is accounted for in the reference sample.\n        x_table[q] ^= z_table[q];\n        m_record.xor_record_reserved_result(x_table[q]);\n        if (guarantee_anticommutation_via_frame_randomization) {\n            z_table[q].randomize(z_table[q].num_bits_padded(), rng);\n        }\n        x_table[q] = z_table[q];\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MRZ(const CircuitInstruction &target_data) {\n    // Note: Caution when implementing this. Can't group the resets. because the same qubit target may appear twice.\n    m_record.reserve_noisy_space_for_results(target_data, rng);\n    for (auto t : target_data.targets) {\n        auto q = t.qubit_value();  // Flipping is ignored because it is accounted for in the reference sample.\n        m_record.xor_record_reserved_result(x_table[q]);\n        x_table[q].clear();\n        if (guarantee_anticommutation_via_frame_randomization) {\n            z_table[q].randomize(z_table[q].num_bits_padded(), rng);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_I(const CircuitInstruction &target_data) {\n}\n\ntemplate <size_t W>\nPauliString<W> FrameSimulator<W>::get_frame(size_t sample_index) const {\n    assert(sample_index < batch_size);\n    PauliString<W> result(num_qubits);\n    for (size_t q = 0; q < num_qubits; q++) {\n        result.xs[q] = x_table[q][sample_index];\n        result.zs[q] = z_table[q][sample_index];\n    }\n    return result;\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::set_frame(size_t sample_index, const PauliStringRef<W> &new_frame) {\n    assert(sample_index < batch_size);\n    assert(new_frame.num_qubits == num_qubits);\n    for (size_t q = 0; q < num_qubits; q++) {\n        x_table[q][sample_index] = new_frame.xs[q];\n        z_table[q][sample_index] = new_frame.zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_H_XZ(const CircuitInstruction &target_data) {\n    for (auto t : target_data.targets) {\n        auto q = t.data;\n        x_table[q].swap_with(z_table[q]);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_H_XY(const CircuitInstruction &target_data) {\n    for (auto t : target_data.targets) {\n        auto q = t.data;\n        z_table[q] ^= x_table[q];\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_H_YZ(const CircuitInstruction &target_data) {\n    for (auto t : target_data.targets) {\n        auto q = t.data;\n        x_table[q] ^= z_table[q];\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_C_XYZ(const CircuitInstruction &target_data) {\n    for (auto t : target_data.targets) {\n        auto q = t.data;\n        x_table[q] ^= z_table[q];\n        z_table[q] ^= x_table[q];\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_C_ZYX(const CircuitInstruction &target_data) {\n    for (auto t : target_data.targets) {\n        auto q = t.data;\n        z_table[q] ^= x_table[q];\n        x_table[q] ^= z_table[q];\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::single_cx(uint32_t c, uint32_t t) {\n    c &= ~TARGET_INVERTED_BIT;\n    t &= ~TARGET_INVERTED_BIT;\n    if (!((c | t) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        x_table[c].for_each_word(\n            z_table[c],\n            x_table[t],\n            z_table[t],\n            [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n                z1 ^= z2;\n                x2 ^= x1;\n            });\n    } else if (t & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT)) {\n        throw std::invalid_argument(\n            \"Controlled X had a bit (\" + GateTarget{t}.str() + \") as its target, instead of its control.\");\n    } else {\n        xor_control_bit_into(c, x_table[t]);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::single_cy(uint32_t c, uint32_t t) {\n    c &= ~TARGET_INVERTED_BIT;\n    t &= ~TARGET_INVERTED_BIT;\n    if (!((c | t) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        x_table[c].for_each_word(\n            z_table[c],\n            x_table[t],\n            z_table[t],\n            [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n                z1 ^= x2 ^ z2;\n                z2 ^= x1;\n                x2 ^= x1;\n            });\n    } else if (t & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT)) {\n        throw std::invalid_argument(\n            \"Controlled Y had a bit (\" + GateTarget{t}.str() + \") as its target, instead of its control.\");\n    } else {\n        xor_control_bit_into(c, x_table[t]);\n        xor_control_bit_into(c, z_table[t]);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_ZCX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        single_cx(targets[k].data, targets[k + 1].data);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_ZCY(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        single_cy(targets[k].data, targets[k + 1].data);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_ZCZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        size_t c = targets[k].data;\n        size_t t = targets[k + 1].data;\n        c &= ~TARGET_INVERTED_BIT;\n        t &= ~TARGET_INVERTED_BIT;\n        if (!((c | t) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n            x_table[c].for_each_word(\n                z_table[c],\n                x_table[t],\n                z_table[t],\n                [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n                    z1 ^= x2;\n                    z2 ^= x1;\n                });\n        } else if (!(t & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n            xor_control_bit_into(c, z_table[t]);\n        } else if (!(c & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n            xor_control_bit_into(t, z_table[c]);\n        } else {\n            // Both targets are bits. No effect.\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_SWAP(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        size_t q1 = targets[k].data;\n        size_t q2 = targets[k + 1].data;\n        x_table[q1].for_each_word(\n            z_table[q1],\n            x_table[q2],\n            z_table[q2],\n            [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n                std::swap(z1, z2);\n                std::swap(x1, x2);\n            });\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_ISWAP(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            auto dx = x1 ^ x2;\n            auto t1 = z1 ^ dx;\n            auto t2 = z2 ^ dx;\n            z1 = t2;\n            z2 = t1;\n            std::swap(x1, x2);\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_CXSWAP(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            z2 ^= z1;\n            z1 ^= z2;\n            x1 ^= x2;\n            x2 ^= x1;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_CZSWAP(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            std::swap(z1, z2);\n            std::swap(x1, x2);\n            z1 ^= x2;\n            z2 ^= x1;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_SWAPCX(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            z1 ^= z2;\n            z2 ^= z1;\n            x2 ^= x1;\n            x1 ^= x2;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_SQRT_XX(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            auto dz = z1 ^ z2;\n            x1 ^= dz;\n            x2 ^= dz;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_SQRT_YY(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            auto d = x1 ^ z1 ^ x2 ^ z2;\n            x1 ^= d;\n            z1 ^= d;\n            x2 ^= d;\n            z2 ^= d;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_SQRT_ZZ(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            auto dx = x1 ^ x2;\n            z1 ^= dx;\n            z2 ^= dx;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_XCX(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            x1 ^= z2;\n            x2 ^= z1;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_XCY(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            x1 ^= x2 ^ z2;\n            x2 ^= z1;\n            z2 ^= z1;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_XCZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        single_cx(targets[k + 1].data, targets[k].data);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_YCX(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            x2 ^= x1 ^ z1;\n            x1 ^= z2;\n            z1 ^= z2;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_YCY(const CircuitInstruction &target_data) {\n    for_each_target_pair(\n        *this, target_data, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            auto y1 = x1 ^ z1;\n            auto y2 = x2 ^ z2;\n            x1 ^= y2;\n            z1 ^= y2;\n            x2 ^= y1;\n            z2 ^= y1;\n        });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_YCZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        single_cy(targets[k + 1].data, targets[k].data);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_DEPOLARIZE1(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    RareErrorIterator::for_samples(target_data.args[0], targets.size() * batch_size, rng, [&](size_t s) {\n        auto p = 1 + (rng() % 3);\n        auto target_index = s / batch_size;\n        auto sample_index = s % batch_size;\n        auto t = targets[target_index];\n        x_table[t.data][sample_index] ^= p & 1;\n        z_table[t.data][sample_index] ^= p & 2;\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_DEPOLARIZE2(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    auto n = (targets.size() * batch_size) >> 1;\n    RareErrorIterator::for_samples(target_data.args[0], n, rng, [&](size_t s) {\n        auto p = 1 + (rng() % 15);\n        auto target_index = (s / batch_size) << 1;\n        auto sample_index = s % batch_size;\n        size_t t1 = targets[target_index].data;\n        size_t t2 = targets[target_index + 1].data;\n        x_table[t1][sample_index] ^= (bool)(p & 1);\n        z_table[t1][sample_index] ^= (bool)(p & 2);\n        x_table[t2][sample_index] ^= (bool)(p & 4);\n        z_table[t2][sample_index] ^= (bool)(p & 8);\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_X_ERROR(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    RareErrorIterator::for_samples(target_data.args[0], targets.size() * batch_size, rng, [&](size_t s) {\n        auto target_index = s / batch_size;\n        auto sample_index = s % batch_size;\n        auto t = targets[target_index];\n        x_table[t.data][sample_index] ^= true;\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_Y_ERROR(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    RareErrorIterator::for_samples(target_data.args[0], targets.size() * batch_size, rng, [&](size_t s) {\n        auto target_index = s / batch_size;\n        auto sample_index = s % batch_size;\n        auto t = targets[target_index];\n        x_table[t.data][sample_index] ^= true;\n        z_table[t.data][sample_index] ^= true;\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_Z_ERROR(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    RareErrorIterator::for_samples(target_data.args[0], targets.size() * batch_size, rng, [&](size_t s) {\n        auto target_index = s / batch_size;\n        auto sample_index = s % batch_size;\n        auto t = targets[target_index];\n        z_table[t.data][sample_index] ^= true;\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MPP(const CircuitInstruction &target_data) {\n    decompose_mpp_operation(target_data, num_qubits, [&](const CircuitInstruction &inst) {\n        safe_do_instruction(inst);\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_SPP(const CircuitInstruction &target_data) {\n    decompose_spp_or_spp_dag_operation(target_data, num_qubits, false, [&](const CircuitInstruction &inst) {\n        safe_do_instruction(inst);\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_SPP_DAG(const CircuitInstruction &target_data) {\n    decompose_spp_or_spp_dag_operation(target_data, num_qubits, false, [&](const CircuitInstruction &inst) {\n        safe_do_instruction(inst);\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_PAULI_CHANNEL_1(const CircuitInstruction &target_data) {\n    tmp_storage = last_correlated_error_occurred;\n    perform_pauli_errors_via_correlated_errors<1>(\n        target_data,\n        [&]() {\n            last_correlated_error_occurred.clear();\n        },\n        [&](const CircuitInstruction &d) {\n            do_ELSE_CORRELATED_ERROR(d);\n        });\n    last_correlated_error_occurred = tmp_storage;\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_PAULI_CHANNEL_2(const CircuitInstruction &target_data) {\n    tmp_storage = last_correlated_error_occurred;\n    perform_pauli_errors_via_correlated_errors<2>(\n        target_data,\n        [&]() {\n            last_correlated_error_occurred.clear();\n        },\n        [&](const CircuitInstruction &d) {\n            do_ELSE_CORRELATED_ERROR(d);\n        });\n    last_correlated_error_occurred = tmp_storage;\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_CORRELATED_ERROR(const CircuitInstruction &target_data) {\n    last_correlated_error_occurred.clear();\n    do_ELSE_CORRELATED_ERROR(target_data);\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_ELSE_CORRELATED_ERROR(const CircuitInstruction &target_data) {\n    // Sample error locations.\n    biased_randomize_bits(target_data.args[0], rng_buffer.u64, rng_buffer.u64 + ((batch_size + 63) >> 6), rng);\n    if (batch_size & 63) {\n        rng_buffer.u64[batch_size >> 6] &= (uint64_t{1} << (batch_size & 63)) - 1;\n    }\n    // Omit locations blocked by prev error, while updating prev error mask.\n    simd_bits_range_ref<W>{rng_buffer}.for_each_word(\n        last_correlated_error_occurred, [](simd_word<W> &buf, simd_word<W> &prev) {\n            buf = prev.andnot(buf);\n            prev |= buf;\n        });\n\n    // Apply error to only the indicated frames.\n    for (auto qxz : target_data.targets) {\n        auto q = qxz.qubit_value();\n        if (qxz.data & TARGET_PAULI_X_BIT) {\n            x_table[q] ^= rng_buffer;\n        }\n        if (qxz.data & TARGET_PAULI_Z_BIT) {\n            z_table[q] ^= rng_buffer;\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_HERALDED_PAULI_CHANNEL_1(const CircuitInstruction &inst) {\n    auto nt = inst.targets.size();\n    m_record.reserve_space_for_results(nt);\n    for (size_t k = 0; k < nt; k++) {\n        m_record.storage[m_record.stored + k].clear();\n    }\n\n    double hi = inst.args[0];\n    double hx = inst.args[1];\n    double hy = inst.args[2];\n    double hz = inst.args[3];\n    double t = hi + hx + hy + hz;\n    std::uniform_real_distribution<double> dist(0, 1);\n    RareErrorIterator::for_samples(t, nt * batch_size, rng, [&](size_t s) {\n        auto shot = s % batch_size;\n        auto target = s / batch_size;\n        auto qubit = inst.targets[target].qubit_value();\n        m_record.storage[m_record.stored + target][shot] = 1;\n\n        double p = dist(rng) * t;\n        if (p < hx) {\n            x_table[qubit][shot] ^= 1;\n        } else if (p < hx + hz) {\n            z_table[qubit][shot] ^= 1;\n        } else if (p < hx + hz + hy) {\n            x_table[qubit][shot] ^= 1;\n            z_table[qubit][shot] ^= 1;\n        }\n    });\n\n    m_record.stored += nt;\n    m_record.unwritten += nt;\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_HERALDED_ERASE(const CircuitInstruction &inst) {\n    auto nt = inst.targets.size();\n    m_record.reserve_space_for_results(nt);\n    for (size_t k = 0; k < nt; k++) {\n        m_record.storage[m_record.stored + k].clear();\n    }\n\n    uint64_t rng_buf = 0;\n    size_t buf_size = 0;\n    RareErrorIterator::for_samples(inst.args[0], nt * batch_size, rng, [&](size_t s) {\n        auto shot = s % batch_size;\n        auto target = s / batch_size;\n        auto qubit = inst.targets[target].qubit_value();\n        if (buf_size == 0) {\n            rng_buf = rng();\n            buf_size = 64;\n        }\n        x_table[qubit][shot] ^= (bool)(rng_buf & 1);\n        z_table[qubit][shot] ^= (bool)(rng_buf & 2);\n        m_record.storage[m_record.stored + target][shot] = 1;\n        rng_buf >>= 2;\n        buf_size -= 2;\n    });\n    m_record.stored += nt;\n    m_record.unwritten += nt;\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MXX_disjoint_controls_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    do_ZCX(CircuitInstruction{GateType::CX, {}, inst.targets, \"\"});\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        do_MX(CircuitInstruction{GateType::MX, inst.args, SpanRef<const GateTarget>{&inst.targets[k]}, \"\"});\n    }\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    do_ZCX(CircuitInstruction{GateType::CX, {}, inst.targets, \"\"});\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MYY_disjoint_controls_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    do_ZCY(CircuitInstruction{GateType::CY, {}, inst.targets, \"\"});\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        do_MY(CircuitInstruction{GateType::MY, inst.args, SpanRef<const GateTarget>{&inst.targets[k]}, \"\"});\n    }\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    do_ZCY(CircuitInstruction{GateType::CY, {}, inst.targets, \"\"});\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MZZ_disjoint_controls_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    do_XCZ(CircuitInstruction{GateType::XCZ, {}, inst.targets, \"\"});\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        do_MZ(CircuitInstruction{GateType::M, inst.args, SpanRef<const GateTarget>{&inst.targets[k]}, \"\"});\n    }\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    do_XCZ(CircuitInstruction{GateType::XCZ, {}, inst.targets, \"\"});\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MXX(const CircuitInstruction &inst) {\n    decompose_pair_instruction_into_disjoint_segments(inst, num_qubits, [&](CircuitInstruction segment) {\n        do_MXX_disjoint_controls_segment(segment);\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MYY(const CircuitInstruction &inst) {\n    decompose_pair_instruction_into_disjoint_segments(inst, num_qubits, [&](CircuitInstruction segment) {\n        do_MYY_disjoint_controls_segment(segment);\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MZZ(const CircuitInstruction &inst) {\n    decompose_pair_instruction_into_disjoint_segments(inst, num_qubits, [&](CircuitInstruction segment) {\n        do_MZZ_disjoint_controls_segment(segment);\n    });\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_MPAD(const CircuitInstruction &inst) {\n    m_record.reserve_noisy_space_for_results(inst, rng);\n    simd_bits<W> empty(batch_size);\n    for (size_t k = 0; k < inst.targets.size(); k++) {\n        // 0-vs-1 is ignored because it's accounted for in the reference sample.\n        m_record.xor_record_reserved_result(empty);\n    }\n}\n\ntemplate <size_t W>\nvoid FrameSimulator<W>::do_gate(const CircuitInstruction &inst) {\n    switch (inst.gate_type) {\n        case GateType::DETECTOR:\n            do_DETECTOR(inst);\n            break;\n        case GateType::OBSERVABLE_INCLUDE:\n            do_OBSERVABLE_INCLUDE(inst);\n            break;\n        case GateType::MX:\n            do_MX(inst);\n            break;\n        case GateType::MY:\n            do_MY(inst);\n            break;\n        case GateType::M:\n            do_MZ(inst);\n            break;\n        case GateType::MRX:\n            do_MRX(inst);\n            break;\n        case GateType::MRY:\n            do_MRY(inst);\n            break;\n        case GateType::MR:\n            do_MRZ(inst);\n            break;\n        case GateType::RX:\n            do_RX(inst);\n            break;\n        case GateType::RY:\n            do_RY(inst);\n            break;\n        case GateType::R:\n            do_RZ(inst);\n            break;\n        case GateType::MPP:\n            do_MPP(inst);\n            break;\n        case GateType::SPP:\n            do_SPP(inst);\n            break;\n        case GateType::SPP_DAG:\n            do_SPP_DAG(inst);\n            break;\n        case GateType::MPAD:\n            do_MPAD(inst);\n            break;\n        case GateType::MXX:\n            do_MXX(inst);\n            break;\n        case GateType::MYY:\n            do_MYY(inst);\n            break;\n        case GateType::MZZ:\n            do_MZZ(inst);\n            break;\n        case GateType::XCX:\n            do_XCX(inst);\n            break;\n        case GateType::XCY:\n            do_XCY(inst);\n            break;\n        case GateType::XCZ:\n            do_XCZ(inst);\n            break;\n        case GateType::YCX:\n            do_YCX(inst);\n            break;\n        case GateType::YCY:\n            do_YCY(inst);\n            break;\n        case GateType::YCZ:\n            do_YCZ(inst);\n            break;\n        case GateType::CX:\n            do_ZCX(inst);\n            break;\n        case GateType::CY:\n            do_ZCY(inst);\n            break;\n        case GateType::CZ:\n            do_ZCZ(inst);\n            break;\n        case GateType::DEPOLARIZE1:\n            do_DEPOLARIZE1(inst);\n            break;\n        case GateType::DEPOLARIZE2:\n            do_DEPOLARIZE2(inst);\n            break;\n        case GateType::X_ERROR:\n            do_X_ERROR(inst);\n            break;\n        case GateType::Y_ERROR:\n            do_Y_ERROR(inst);\n            break;\n        case GateType::Z_ERROR:\n            do_Z_ERROR(inst);\n            break;\n        case GateType::PAULI_CHANNEL_1:\n            do_PAULI_CHANNEL_1(inst);\n            break;\n        case GateType::PAULI_CHANNEL_2:\n            do_PAULI_CHANNEL_2(inst);\n            break;\n        case GateType::E:\n            do_CORRELATED_ERROR(inst);\n            break;\n        case GateType::ELSE_CORRELATED_ERROR:\n            do_ELSE_CORRELATED_ERROR(inst);\n            break;\n        case GateType::C_XYZ:\n        case GateType::C_NXYZ:\n        case GateType::C_XNYZ:\n        case GateType::C_XYNZ:\n            do_C_XYZ(inst);\n            break;\n        case GateType::C_ZYX:\n        case GateType::C_NZYX:\n        case GateType::C_ZNYX:\n        case GateType::C_ZYNX:\n            do_C_ZYX(inst);\n            break;\n        case GateType::SWAP:\n            do_SWAP(inst);\n            break;\n        case GateType::CXSWAP:\n            do_CXSWAP(inst);\n            break;\n        case GateType::CZSWAP:\n            do_CZSWAP(inst);\n            break;\n        case GateType::SWAPCX:\n            do_SWAPCX(inst);\n            break;\n        case GateType::HERALDED_ERASE:\n            do_HERALDED_ERASE(inst);\n            break;\n        case GateType::HERALDED_PAULI_CHANNEL_1:\n            do_HERALDED_PAULI_CHANNEL_1(inst);\n            break;\n\n        case GateType::SQRT_XX:\n        case GateType::SQRT_XX_DAG:\n            do_SQRT_XX(inst);\n            break;\n\n        case GateType::SQRT_YY:\n        case GateType::SQRT_YY_DAG:\n            do_SQRT_YY(inst);\n            break;\n\n        case GateType::SQRT_ZZ:\n        case GateType::SQRT_ZZ_DAG:\n            do_SQRT_ZZ(inst);\n            break;\n\n        case GateType::ISWAP:\n        case GateType::ISWAP_DAG:\n            do_ISWAP(inst);\n            break;\n\n        case GateType::SQRT_X:\n        case GateType::SQRT_X_DAG:\n        case GateType::H_YZ:\n        case GateType::H_NYZ:\n            do_H_YZ(inst);\n            break;\n\n        case GateType::SQRT_Y:\n        case GateType::SQRT_Y_DAG:\n        case GateType::H:\n        case GateType::H_NXZ:\n            do_H_XZ(inst);\n            break;\n\n        case GateType::S:\n        case GateType::S_DAG:\n        case GateType::H_XY:\n        case GateType::H_NXY:\n            do_H_XY(inst);\n            break;\n\n        case GateType::TICK:\n        case GateType::QUBIT_COORDS:\n        case GateType::SHIFT_COORDS:\n        case GateType::X:\n        case GateType::Y:\n        case GateType::Z:\n        case GateType::I:\n        case GateType::II:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n            do_I(inst);\n            break;\n\n        default:\n            throw std::invalid_argument(\"Not implemented in FrameSimulator<W>::do_gate: \" + inst.str());\n    }\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/frame_simulator.h\"\n\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(FrameSimulator_depolarize1_100Kqubits_1Ksamples_per1000) {\n    CircuitStats stats;\n    stats.num_qubits = 100 * 1000;\n    size_t num_samples = 1000;\n    double probability = 0.001;\n    FrameSimulator<MAX_BITWORD_WIDTH> sim(\n        stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, std::mt19937_64(0));\n\n    std::vector<GateTarget> targets;\n    for (uint32_t k = 0; k < stats.num_qubits; k++) {\n        targets.push_back(GateTarget{k});\n    }\n    CircuitInstruction op_data{GateType::DEPOLARIZE1, &probability, targets, \"\"};\n    benchmark_go([&]() {\n        sim.do_DEPOLARIZE1(op_data);\n    })\n        .goal_millis(5)\n        .show_rate(\"OpQubits\", targets.size() * num_samples);\n}\n\nBENCHMARK(FrameSimulator_depolarize2_100Kqubits_1Ksamples_per1000) {\n    CircuitStats stats;\n    stats.num_qubits = 100 * 1000;\n    size_t num_samples = 1000;\n    double probability = 0.001;\n    FrameSimulator<MAX_BITWORD_WIDTH> sim(\n        stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, std::mt19937_64(0));\n\n    std::vector<GateTarget> targets;\n    for (uint32_t k = 0; k < stats.num_qubits; k++) {\n        targets.push_back({k});\n    }\n    CircuitInstruction op_data{GateType::DEPOLARIZE2, &probability, targets, \"\"};\n\n    benchmark_go([&]() {\n        sim.do_DEPOLARIZE2(op_data);\n    })\n        .goal_millis(5)\n        .show_rate(\"OpQubits\", targets.size() * num_samples);\n}\n\nBENCHMARK(FrameSimulator_hadamard_100Kqubits_1Ksamples) {\n    CircuitStats stats;\n    stats.num_qubits = 100 * 1000;\n    size_t num_samples = 1000;\n    FrameSimulator<MAX_BITWORD_WIDTH> sim(\n        stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, std::mt19937_64(0));\n\n    std::vector<GateTarget> targets;\n    for (uint32_t k = 0; k < stats.num_qubits; k++) {\n        targets.push_back({k});\n    }\n    CircuitInstruction op_data{GateType::H, {}, targets, \"\"};\n\n    benchmark_go([&]() {\n        sim.do_H_XZ(op_data);\n    })\n        .goal_millis(2)\n        .show_rate(\"OpQubits\", targets.size() * num_samples);\n}\n\nBENCHMARK(FrameSimulator_CX_100Kqubits_1Ksamples) {\n    CircuitStats stats;\n    stats.num_qubits = 100 * 1000;\n    size_t num_samples = 1000;\n    FrameSimulator<MAX_BITWORD_WIDTH> sim(\n        stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_samples, std::mt19937_64(0));\n\n    std::vector<GateTarget> targets;\n    for (uint32_t k = 0; k < stats.num_qubits; k++) {\n        targets.push_back({k});\n    }\n    CircuitInstruction op_data{GateType::CX, {}, targets, \"\"};\n\n    benchmark_go([&]() {\n        sim.do_ZCX(op_data);\n    })\n        .goal_millis(2)\n        .show_rate(\"OpQubits\", targets.size() * num_samples);\n}\n\nBENCHMARK(FrameSimulator_surface_code_rotated_memory_z_d11_r100_batch1024) {\n    auto params = CircuitGenParameters(100, 11, \"rotated_memory_z\");\n    params.before_measure_flip_probability = 0.001;\n    params.after_reset_flip_probability = 0.001;\n    params.after_clifford_depolarization = 0.001;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n\n    FrameSimulator<MAX_BITWORD_WIDTH> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_MEASUREMENTS_TO_MEMORY, 1024, std::mt19937_64(0));\n\n    benchmark_go([&]() {\n        sim.reset_all();\n        sim.do_circuit(circuit);\n    })\n        .goal_millis(5.1)\n        .show_rate(\"Shots\", 1024)\n        .show_rate(\"Dets\", circuit.count_detectors() * 1024);\n    sim.reset_all();\n    if (!sim.obs_record[0].not_zero()) {\n        std::cerr << \"data dependence\";\n    }\n}\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator.pybind.cc",
    "content": "#include \"stim/simulators/frame_simulator.pybind.h\"\n\n#include \"stim/circuit/circuit_instruction.pybind.h\"\n#include \"stim/circuit/circuit_repeat_block.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/stabilizers/pauli_string.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nstd::optional<size_t> py_index_to_optional_size_t(\n    const pybind11::object &index, size_t length, const char *val_name, const char *len_name) {\n    if (index.is_none()) {\n        return {};\n    }\n    int64_t i = pybind11::cast<int64_t>(index);\n    if (i < -(int64_t)length || (i >= 0 && (uint64_t)i >= length)) {\n        std::stringstream msg;\n        msg << \"not (\";\n        msg << \"-\" << len_name << \" <= \";\n        msg << val_name << \"=\" << index;\n        msg << \" < \";\n        msg << len_name << \"=\" << length;\n        msg << \")\";\n        throw std::out_of_range(msg.str());\n    }\n    if (i < 0) {\n        i += length;\n    }\n    assert(i >= 0);\n    return (size_t)i;\n}\n\nstatic void generate_biased_samples_bit_packed_contiguous(\n    uint8_t *out, size_t num_bytes, float p, std::mt19937_64 &rng) {\n    uintptr_t start = (uintptr_t)out;\n    uintptr_t end = start + num_bytes;\n    uintptr_t aligned64_start = start & ~0b111ULL;\n    uintptr_t aligned64_end = end & ~0b111ULL;\n    if (aligned64_start != start) {\n        aligned64_start += 8;\n    }\n    biased_randomize_bits(p, (uint64_t *)aligned64_start, (uint64_t *)aligned64_end, rng);\n    if (start < aligned64_start) {\n        uint64_t pad;\n        biased_randomize_bits(p, &pad, &pad + 1, rng);\n        for (size_t k = 0; k < aligned64_start - start; k++) {\n            out[k] = (uint8_t)(pad & 0xFF);\n            pad >>= 8;\n        }\n    }\n    if (aligned64_end < end) {\n        uint64_t pad;\n        biased_randomize_bits(p, &pad, &pad + 1, rng);\n        while (aligned64_end < end) {\n            *(uint8_t *)aligned64_end = (uint8_t)(pad & 0xFF);\n            aligned64_end++;\n            pad >>= 8;\n        }\n    }\n}\n\nstatic void generate_biased_samples_bit_packed_with_stride(\n    uint8_t *out, pybind11::ssize_t stride, size_t num_bytes, float p, std::mt19937_64 &rng) {\n    uint64_t stack[64];\n    uint64_t *stack_ptr = &stack[0];\n    for (size_t k1 = 0; k1 < num_bytes; k1 += 64 * 8) {\n        size_t n2 = std::min(num_bytes - k1, (size_t)(64 * 8));\n        biased_randomize_bits(p, stack_ptr, stack_ptr + (n2 + 7) / 8, rng);\n        uint8_t *stack_data = (uint8_t *)(void *)stack_ptr;\n        for (size_t k2 = 0; k2 < n2; k2++) {\n            *out = *stack_data;\n            stack_data += 1;\n            out += stride;\n        }\n    }\n}\n\nstatic void generate_biased_samples_bool(\n    uint8_t *out, pybind11::ssize_t stride, size_t num_samples, float p, std::mt19937_64 &rng) {\n    uint64_t stack[64];\n    uint64_t *stack_ptr = &stack[0];\n    for (size_t k1 = 0; k1 < num_samples; k1 += 64 * 64) {\n        size_t n2 = std::min(num_samples - k1, (size_t)(64 * 64));\n        biased_randomize_bits(p, stack_ptr, stack_ptr + (n2 + 63) / 64, rng);\n        for (size_t k2 = 0; k2 < n2; k2++) {\n            bool bit = (stack[k2 / 64] >> (k2 & 63)) & 1;\n            *out++ = bit;\n        }\n    }\n}\n\ntemplate <size_t W>\npybind11::object generate_bernoulli_samples(\n    FrameSimulator<W> &self, size_t num_samples, float p, bool bit_packed, pybind11::object out) {\n    if (bit_packed) {\n        size_t num_bytes = (num_samples + 7) / 8;\n        if (out.is_none()) {\n            // Allocate u64 aligned memory.\n            void *buffer = (void *)new uint64_t[(num_bytes + 7) / 8];\n            pybind11::capsule free_when_done(buffer, [](void *f) {\n                delete[] reinterpret_cast<uint64_t *>(f);\n            });\n            out = pybind11::array_t<uint8_t>(\n                {(pybind11::ssize_t)num_bytes}, {(pybind11::ssize_t)1}, (uint8_t *)buffer, free_when_done);\n        } else if (!pybind11::isinstance<pybind11::array_t<uint8_t>>(out)) {\n            throw std::invalid_argument(\"`out` wasn't `None` or a uint8 numpy array.\");\n        }\n        auto buf = pybind11::cast<pybind11::array_t<uint8_t>>(out);\n        if (buf.ndim() != 1) {\n            throw std::invalid_argument(\"Output buffer wasn't one dimensional.\");\n        }\n        if ((size_t)buf.shape(0) != num_bytes) {\n            std::stringstream ss;\n            ss << \"Expected output buffer to have size \" << num_bytes;\n            ss << \" but its size is \" << buf.shape(0) << \".\";\n            throw std::invalid_argument(ss.str());\n        }\n        auto stride = buf.strides(0);\n        void *start_of_data = (void *)buf.mutable_data();\n\n        if (stride == 1) {\n            generate_biased_samples_bit_packed_contiguous((uint8_t *)start_of_data, num_bytes, p, self.rng);\n        } else {\n            generate_biased_samples_bit_packed_with_stride((uint8_t *)start_of_data, stride, num_bytes, p, self.rng);\n        }\n        if (num_samples & 0b111) {\n            uint8_t mask = (1 << (num_samples & 0b111)) - 1;\n            buf.mutable_at(num_bytes - 1) &= mask;\n        }\n    } else {\n        if (out.is_none()) {\n            auto numpy = pybind11::module::import(\"numpy\");\n            out = numpy.attr(\"empty\")(num_samples, numpy.attr(\"bool_\"));\n        } else if (!pybind11::isinstance<pybind11::array_t<bool>>(out)) {\n            throw std::invalid_argument(\"`out` wasn't `None` or a bool_ numpy array.\");\n        }\n        auto buf = pybind11::cast<pybind11::array_t<bool>>(out);\n        if (buf.ndim() != 1) {\n            throw std::invalid_argument(\"Output buffer wasn't one dimensional.\");\n        }\n        if ((size_t)buf.shape(0) != num_samples) {\n            std::stringstream ss;\n            ss << \"Expected output buffer to have size \" << num_samples;\n            ss << \" but its size is \" << buf.shape(0) << \".\";\n            throw std::invalid_argument(ss.str());\n        }\n        auto stride = buf.strides(0);\n        void *start_of_data = (void *)buf.mutable_data();\n\n        generate_biased_samples_bool((uint8_t *)start_of_data, stride, num_samples, p, self.rng);\n    }\n    return out;\n}\n\nuint8_t pybind11_object_to_pauli_ixyz(const pybind11::object &obj) {\n    if (pybind11::isinstance<pybind11::str>(obj)) {\n        std::string_view s = pybind11::cast<std::string_view>(obj);\n        if (s == \"X\") {\n            return 1;\n        } else if (s == \"Y\") {\n            return 2;\n        } else if (s == \"Z\") {\n            return 3;\n        } else if (s == \"I\" || s == \"_\") {\n            return 0;\n        }\n    } else if (pybind11::isinstance<pybind11::int_>(obj)) {\n        uint8_t v = 255;\n        try {\n            v = pybind11::cast<uint8_t>(obj);\n        } catch (const pybind11::cast_error &) {\n        }\n        if (v < 4) {\n            return (uint8_t)v;\n        }\n    }\n\n    throw std::invalid_argument(\"Need pauli in ['I', 'X', 'Y', 'Z', 0, 1, 2, 3, '_'].\");\n}\n\npybind11::class_<FrameSimulator<MAX_BITWORD_WIDTH>> stim_pybind::pybind_frame_simulator(pybind11::module &m) {\n    return pybind11::class_<FrameSimulator<MAX_BITWORD_WIDTH>>(\n        m,\n        \"FlipSimulator\",\n        clean_doc_string(R\"DOC(\n            A simulator that tracks whether things are flipped, instead of what they are.\n\n            Tracking flips is significantly cheaper than tracking actual values, requiring\n            O(1) work per gate (compared to O(n) for unitary operations and O(n^2) for\n            collapsing operations in the tableau simulator, where n is the qubit count).\n\n            Supports interactive usage, where gates and measurements are applied on demand.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=256)\n        )DOC\")\n            .data());\n}\n\ntemplate <size_t W>\npybind11::object peek_pauli_flips(const FrameSimulator<W> &self, const pybind11::object &py_instance_index) {\n    std::optional<size_t> instance_index =\n        py_index_to_optional_size_t(py_instance_index, self.batch_size, \"instance_index\", \"batch_size\");\n\n    if (instance_index.has_value()) {\n        return pybind11::cast(FlexPauliString(self.get_frame(*instance_index)));\n    }\n\n    std::vector<FlexPauliString> result;\n    for (size_t k = 0; k < self.batch_size; k++) {\n        result.push_back(FlexPauliString(self.get_frame(k)));\n    }\n    return pybind11::cast(std::move(result));\n}\n\npybind11::object pick_output_numpy_array(\n    pybind11::object output_vs, bool bit_packed, bool transpose, size_t shape1, size_t shape2, const char *name) {\n    auto numpy = pybind11::module::import(\"numpy\");\n    auto dtype = bit_packed ? numpy.attr(\"uint8\") : numpy.attr(\"bool_\");\n    auto py_bool = pybind11::module::import(\"builtins\").attr(\"bool\");\n    if (transpose) {\n        std::swap(shape1, shape2);\n    }\n    if (bit_packed) {\n        shape2 = (shape2 + 7) >> 3;\n    }\n    auto shape = pybind11::make_tuple(shape1, shape2);\n    if (pybind11::isinstance<pybind11::bool_>(output_vs) && pybind11::bool_(false).equal(output_vs)) {\n        return pybind11::none();\n    } else if (pybind11::isinstance<pybind11::bool_>(output_vs) && pybind11::bool_(true).equal(output_vs)) {\n        return numpy.attr(\"empty\")(shape, dtype);\n    } else if (\n        bit_packed && pybind11::isinstance<pybind11::array_t<uint8_t>>(output_vs) &&\n        shape.equal(output_vs.attr(\"shape\"))) {\n        return output_vs;\n    } else if (\n        !bit_packed && pybind11::isinstance<pybind11::array_t<bool>>(output_vs) &&\n        shape.equal(output_vs.attr(\"shape\"))) {\n        return output_vs;\n    } else {\n        std::stringstream ss;\n        ss << name << \" wasn't set to False, True, or a numpy array with dtype=\" << pybind11::str(dtype)\n           << \" and shape=\" << shape;\n        throw std::invalid_argument(ss.str());\n    }\n}\n\ntemplate <size_t W>\npybind11::object to_numpy(\n    const FrameSimulator<W> &self,\n    bool bit_packed,\n    bool transpose,\n    pybind11::object output_xs,\n    pybind11::object output_zs,\n    pybind11::object output_measure_flips,\n    pybind11::object output_detector_flips,\n    pybind11::object output_observable_flips) {\n    output_xs =\n        pick_output_numpy_array(output_xs, bit_packed, transpose, self.num_qubits, self.batch_size, \"output_xs\");\n    output_zs =\n        pick_output_numpy_array(output_zs, bit_packed, transpose, self.num_qubits, self.batch_size, \"output_zs\");\n    output_measure_flips = pick_output_numpy_array(\n        output_measure_flips, bit_packed, transpose, self.m_record.stored, self.batch_size, \"output_measure_flips\");\n    output_detector_flips = pick_output_numpy_array(\n        output_detector_flips, bit_packed, transpose, self.det_record.stored, self.batch_size, \"output_detector_flips\");\n    output_observable_flips = pick_output_numpy_array(\n        output_observable_flips,\n        bit_packed,\n        transpose,\n        self.num_observables,\n        self.batch_size,\n        \"output_observable_flips\");\n\n    if (!output_xs.is_none()) {\n        simd_bit_table_to_numpy(self.x_table, self.num_qubits, self.batch_size, bit_packed, transpose, output_xs);\n    }\n    if (!output_zs.is_none()) {\n        simd_bit_table_to_numpy(self.z_table, self.num_qubits, self.batch_size, bit_packed, transpose, output_zs);\n    }\n    if (!output_measure_flips.is_none()) {\n        simd_bit_table_to_numpy(\n            self.m_record.storage, self.m_record.stored, self.batch_size, bit_packed, transpose, output_measure_flips);\n    }\n    if (!output_detector_flips.is_none()) {\n        simd_bit_table_to_numpy(\n            self.det_record.storage,\n            self.det_record.stored,\n            self.batch_size,\n            bit_packed,\n            transpose,\n            output_detector_flips);\n    }\n    if (!output_observable_flips.is_none()) {\n        simd_bit_table_to_numpy(\n            self.obs_record, self.num_observables, self.batch_size, bit_packed, transpose, output_observable_flips);\n    }\n    if (output_xs.is_none() + output_zs.is_none() + output_measure_flips.is_none() + output_detector_flips.is_none() +\n            output_observable_flips.is_none() ==\n        5) {\n        throw std::invalid_argument(\"No outputs requested! Specify at least one output_*= argument.\");\n    }\n    return pybind11::make_tuple(\n        output_xs, output_zs, output_measure_flips, output_detector_flips, output_observable_flips);\n}\n\ntemplate <size_t W>\nFrameSimulator<W> create_frame_simulator(\n    size_t batch_size, bool disable_heisenberg_uncertainty, uint32_t num_qubits, const pybind11::object &seed) {\n    FrameSimulator<W> result(\n        CircuitStats{\n            0,  // num_detectors\n            0,  // num_observables\n            0,  // num_measurements\n            num_qubits,\n            0,                    // num_ticks\n            (uint32_t)(1 << 24),  // max_lookback\n            0,                    // num_sweep_bits\n        },\n        FrameSimulatorMode::STORE_EVERYTHING_TO_MEMORY,\n        batch_size,\n        make_py_seeded_rng(seed));\n    result.guarantee_anticommutation_via_frame_randomization = !disable_heisenberg_uncertainty;\n    result.reset_all();\n    return result;\n}\n\ntemplate <size_t W>\npybind11::object sliced_table_to_numpy(\n    const simd_bit_table<W> &table,\n    size_t num_major_exact,\n    size_t num_minor_exact,\n    std::optional<size_t> major_index,\n    std::optional<size_t> minor_index,\n    bool bit_packed) {\n    if (major_index.has_value()) {\n        simd_bits_range_ref<W> row = table[*major_index];\n        if (minor_index.has_value()) {\n            bool b = row[*minor_index];\n            auto np = pybind11::module::import(\"numpy\");\n            return np.attr(\"array\")(b, bit_packed ? np.attr(\"uint8\") : np.attr(\"bool_\"));\n        } else {\n            return simd_bits_to_numpy(row, num_minor_exact, bit_packed);\n        }\n    } else {\n        if (minor_index.has_value()) {\n            auto data = table.read_across_majors_at_minor_index(0, num_major_exact, *minor_index);\n            return simd_bits_to_numpy(data, num_major_exact, bit_packed);\n        } else {\n            return simd_bit_table_to_numpy(\n                table, num_major_exact, num_minor_exact, bit_packed, false, pybind11::none());\n        }\n    }\n}\n\ntemplate <size_t W>\npybind11::object get_measurement_flips(\n    FrameSimulator<W> &self,\n    const pybind11::object &py_record_index,\n    const pybind11::object &py_instance_index,\n    bool bit_packed) {\n    size_t num_measurements = self.m_record.stored;\n\n    std::optional<size_t> instance_index =\n        py_index_to_optional_size_t(py_instance_index, self.batch_size, \"instance_index\", \"batch_size\");\n\n    std::optional<size_t> record_index =\n        py_index_to_optional_size_t(py_record_index, num_measurements, \"record_index\", \"num_measurements\");\n\n    return sliced_table_to_numpy(\n        self.m_record.storage, num_measurements, self.batch_size, record_index, instance_index, bit_packed);\n}\n\ntemplate <size_t W>\npybind11::object get_detector_flips(\n    FrameSimulator<W> &self,\n    const pybind11::object &py_detector_index,\n    const pybind11::object &py_instance_index,\n    bool bit_packed) {\n    size_t num_detectors = self.det_record.stored;\n\n    std::optional<size_t> instance_index =\n        py_index_to_optional_size_t(py_instance_index, self.batch_size, \"instance_index\", \"batch_size\");\n\n    std::optional<size_t> detector_index =\n        py_index_to_optional_size_t(py_detector_index, num_detectors, \"detector_index\", \"num_detectors\");\n\n    return sliced_table_to_numpy(\n        self.det_record.storage, num_detectors, self.batch_size, detector_index, instance_index, bit_packed);\n}\n\ntemplate <size_t W>\npybind11::object get_obs_flips(\n    FrameSimulator<W> &self,\n    const pybind11::object &py_observable_index,\n    const pybind11::object &py_instance_index,\n    bool bit_packed) {\n    std::optional<size_t> instance_index =\n        py_index_to_optional_size_t(py_instance_index, self.batch_size, \"instance_index\", \"batch_size\");\n\n    std::optional<size_t> observable_index =\n        py_index_to_optional_size_t(py_observable_index, self.num_observables, \"observable_index\", \"num_observables\");\n\n    return sliced_table_to_numpy(\n        self.obs_record, self.num_observables, self.batch_size, observable_index, instance_index, bit_packed);\n}\n\nvoid stim_pybind::pybind_frame_simulator_methods(\n    pybind11::module &m, pybind11::class_<FrameSimulator<MAX_BITWORD_WIDTH>> &c) {\n    c.def(\n        pybind11::init(&create_frame_simulator<MAX_BITWORD_WIDTH>),\n        pybind11::kw_only(),\n        pybind11::arg(\"batch_size\"),\n        pybind11::arg(\"disable_stabilizer_randomization\") = false,\n        pybind11::arg(\"num_qubits\") = 0,\n        pybind11::arg(\"seed\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def __init__(self, *, batch_size: int, disable_stabilizer_randomization: bool = False, num_qubits: int = 0, seed: Optional[int] = None) -> None:\n            Initializes a stim.FlipSimulator.\n\n            Args:\n                batch_size: For speed, the flip simulator simulates many instances in\n                    parallel. This argument determines the number of parallel instances.\n\n                    It's recommended to use a multiple of 256, because internally the state\n                    of the instances is striped across SSE (128 bit) or AVX (256 bit)\n                    words with one bit in the word belonging to each instance. The result is\n                    that, even if you only ask for 1 instance, probably the same amount of\n                    work is being done as if you'd asked for 256 instances. The extra\n                    results just aren't being used, creating waste.\n\n                disable_stabilizer_randomization: Determines whether or not the flip\n                    simulator uses stabilizer randomization. Defaults to False (stabilizer\n                    randomization used). Set to True to disable stabilizer randomization.\n\n                    Stabilizer randomization means that, when a qubit is initialized or\n                    measured in the Z basis, a Z error is added to the qubit with 50%\n                    probability. More generally, anytime a stabilizer is introduced into\n                    the system by any means, an error equal to that stabilizer is applied\n                    with 50% probability. This ensures that observables anticommuting with\n                    stabilizers of the system must be maximally uncertain. In other words,\n                    this feature enforces Heisenberg's uncertainty principle.\n\n                    This is a safety feature that you should not turn off unless you have a\n                    reason to do so. Stabilizer randomization is turned on by default\n                    because it catches mistakes. For example, suppose you are trying to\n                    create a stabilizer code but you accidentally have the code measure two\n                    anticommuting stabilizers. With stabilizer randomization turned off, it\n                    will look like this code works. With stabilizer randomization turned on,\n                    the two measurements will correctly randomize each other revealing that\n                    the code doesn't work.\n\n                    In some use cases, stabilizer randomization is a hindrance instead of\n                    helpful. For example, if you are using the flip simulator to understand\n                    how an error propagates through the system, the stabilizer randomization\n                    will be introducing error terms that you don't want.\n\n                num_qubits: Sets the initial number of qubits tracked by the simulation.\n                    The simulator will still automatically resize as needed when qubits\n                    beyond this limit are touched.\n\n                    This parameter exists as a way to hint at the desired size of the\n                    simulator's state for performance, and to ensure methods that\n                    peek at the size have the expected size from the start instead of\n                    only after the relevant qubits have been touched.\n\n                seed: PARTIALLY determines simulation results by deterministically seeding\n                    the random number generator.\n\n                    Must be None or an integer in range(2**64).\n\n                    Defaults to None. When None, the prng is seeded from system entropy.\n\n                    When set to an integer, making the exact same series calls on the exact\n                    same machine with the exact same version of Stim will produce the exact\n                    same simulation results.\n\n                    CAUTION: simulation results *WILL NOT* be consistent between versions of\n                    Stim. This restriction is present to make it possible to have future\n                    optimizations to the random sampling, and is enforced by introducing\n                    intentional differences in the seeding strategy from version to version.\n\n                    CAUTION: simulation results *MAY NOT* be consistent across machines that\n                    differ in the width of supported SIMD instructions. For example, using\n                    the same seed on a machine that supports AVX instructions and one that\n                    only supports SSE instructions may produce different simulation results.\n\n                    CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                    circuit is executed. For example, reordering whether a reset on one\n                    qubit happens before or after a reset on another qubit can result in\n                    different measurement results being observed starting from the same\n                    seed.\n\n            Returns:\n                An initialized stim.FlipSimulator.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=256)\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"batch_size\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self) -> size_t {\n            return self.batch_size;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of instances being simulated by the simulator.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=256)\n                >>> sim.batch_size\n                256\n                >>> sim = stim.FlipSimulator(batch_size=42)\n                >>> sim.batch_size\n                42\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_qubits\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self) -> size_t {\n            return self.num_qubits;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of qubits currently tracked by the simulator.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=256)\n                >>> sim.num_qubits\n                0\n                >>> sim = stim.FlipSimulator(batch_size=256, num_qubits=4)\n                >>> sim.num_qubits\n                4\n                >>> sim.do(stim.Circuit('H 5'))\n                >>> sim.num_qubits\n                6\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_observables\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self) -> size_t {\n            return self.num_observables;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of observables currently tracked by the simulator.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=256)\n                >>> sim.num_observables\n                0\n                >>> sim.do(stim.Circuit('''\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(4) rec[-1]\n                ... '''))\n                >>> sim.num_observables\n                5\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_measurements\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self) -> size_t {\n            return self.m_record.stored;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of measurements that have been simulated and stored.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=256)\n                >>> sim.num_measurements\n                0\n                >>> sim.do(stim.Circuit('M 3 5'))\n                >>> sim.num_measurements\n                2\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_detectors\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self) -> size_t {\n            return self.det_record.stored;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of detectors that have been simulated and stored.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=256)\n                >>> sim.num_detectors\n                0\n                >>> sim.do(stim.Circuit('''\n                ...     M 0 0\n                ...     DETECTOR rec[-1] rec[-2]\n                ... '''))\n                >>> sim.num_detectors\n                1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"set_pauli_flip\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self,\n           const pybind11::object &pauli,\n           int64_t qubit_index,\n           int64_t instance_index) {\n            uint8_t p = pybind11_object_to_pauli_ixyz(pauli);\n            if (instance_index < 0) {\n                instance_index += self.batch_size;\n            }\n            if (qubit_index < 0) {\n                throw std::out_of_range(\"qubit_index\");\n            }\n            if (instance_index < 0 || (uint64_t)instance_index >= self.batch_size) {\n                throw std::out_of_range(\"instance_index\");\n            }\n            if ((uint64_t)qubit_index >= self.num_qubits) {\n                CircuitStats stats;\n                stats.num_qubits = qubit_index + 1;\n                self.ensure_safe_to_do_circuit_with_stats(stats);\n            }\n\n            p ^= p >> 1;\n            self.x_table[qubit_index][instance_index] = (p & 1) != 0;\n            self.z_table[qubit_index][instance_index] = (p & 2) != 0;\n        },\n        pybind11::arg(\"pauli\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"qubit_index\"),\n        pybind11::arg(\"instance_index\"),\n        clean_doc_string(R\"DOC(\n            @signature def set_pauli_flip(self, pauli: Union[str, int], *, qubit_index: int, instance_index: int) -> None:\n            Sets the pauli flip on a given qubit in a given simulation instance.\n\n            Args:\n                pauli: The pauli, specified as an integer or string.\n                    Uses the convention 0=I, 1=X, 2=Y, 3=Z.\n                    Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.\n                qubit_index: The qubit to put the error on. Must be non-negative. The state\n                    will automatically expand as needed to store the error.\n                instance_index: The simulation index to put the error inside. Use negative\n                    indices to index from the end of the list.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(\n                ...     batch_size=2,\n                ...     num_qubits=3,\n                ...     disable_stabilizer_randomization=True,\n                ... )\n                >>> sim.set_pauli_flip('X', qubit_index=2, instance_index=1)\n                >>> sim.peek_pauli_flips()\n                [stim.PauliString(\"+___\"), stim.PauliString(\"+__X\")]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"peek_pauli_flips\",\n        &peek_pauli_flips<MAX_BITWORD_WIDTH>,\n        pybind11::kw_only(),\n        pybind11::arg(\"instance_index\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @overload def peek_pauli_flips(self) -> List[stim.PauliString]:\n            @overload def peek_pauli_flips(self, *, instance_index: int) -> stim.PauliString:\n            @signature def peek_pauli_flips(self, *, instance_index: Optional[int] = None) -> Union[stim.PauliString, List[stim.PauliString]]:\n            Returns the current pauli errors packed into stim.PauliString instances.\n\n            Args:\n                instance_index: Defaults to None. When set to None, the pauli errors from\n                    all instances are returned as a list of `stim.PauliString`. When set to\n                    an integer, a single `stim.PauliString` is returned containing the\n                    errors for the indexed instance.\n\n            Returns:\n                if instance_index is None:\n                    A list of stim.PauliString, with the k'th entry being the errors from\n                    the k'th simulation instance.\n                else:\n                    A stim.PauliString with the errors from the k'th simulation instance.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(\n                ...     batch_size=2,\n                ...     disable_stabilizer_randomization=True,\n                ...     num_qubits=10,\n                ... )\n\n                >>> sim.peek_pauli_flips()\n                [stim.PauliString(\"+__________\"), stim.PauliString(\"+__________\")]\n\n                >>> sim.peek_pauli_flips(instance_index=0)\n                stim.PauliString(\"+__________\")\n\n                >>> sim.do(stim.Circuit('''\n                ...     X_ERROR(1) 0 3 5\n                ...     Z_ERROR(1) 3 6\n                ... '''))\n\n                >>> sim.peek_pauli_flips()\n                [stim.PauliString(\"+X__Y_XZ___\"), stim.PauliString(\"+X__Y_XZ___\")]\n\n                >>> sim = stim.FlipSimulator(\n                ...     batch_size=1,\n                ...     num_qubits=100,\n                ... )\n                >>> flips: stim.PauliString = sim.peek_pauli_flips(instance_index=0)\n                >>> sorted(set(str(flips)))  # Should have Zs from stabilizer randomization\n                ['+', 'Z', '_']\n\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_numpy\",\n        &to_numpy<MAX_BITWORD_WIDTH>,\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed\") = false,\n        pybind11::arg(\"transpose\") = false,\n        pybind11::arg(\"output_xs\") = false,\n        pybind11::arg(\"output_zs\") = false,\n        pybind11::arg(\"output_measure_flips\") = false,\n        pybind11::arg(\"output_detector_flips\") = false,\n        pybind11::arg(\"output_observable_flips\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def to_numpy(self, *, bit_packed: bool = False, transpose: bool = False, output_xs: Union[bool, np.ndarray] = False, output_zs: Union[bool, np.ndarray] = False, output_measure_flips: Union[bool, np.ndarray] = False, output_detector_flips: Union[bool, np.ndarray] = False, output_observable_flips: Union[bool, np.ndarray] = False) -> Optional[Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]]:\n            Writes the simulator state into numpy arrays.\n\n            Args:\n                bit_packed: Whether or not the result is bit packed, storing 8 bits per\n                    byte instead of 1 bit per byte. Bit packing always applies to\n                    the second index of the result. Bits are packed in little endian\n                    order (as if by `np.packbits(X, axis=1, order='little')`).\n                transpose: Defaults to False. When set to False, the second index of the\n                    returned array (the index affected by bit packing) is the shot index\n                    (meaning the first index is the qubit index or measurement index or\n                    etc). When set to True, results are transposed so that the first\n                    index is the shot index.\n                output_xs: Defaults to False. When set to False, the X flip data is not\n                    generated and the corresponding array in the result tuple is set to\n                    None. When set to True, a new array is allocated to hold the X flip\n                    data and this array is returned via the result tuple. When set to\n                    a numpy array, the results are written into that array (the shape and\n                    dtype of the array must be exactly correct).\n                output_zs: Defaults to False. When set to False, the Z flip data is not\n                    generated and the corresponding array in the result tuple is set to\n                    None. When set to True, a new array is allocated to hold the Z flip\n                    data and this array is returned via the result tuple. When set to\n                    a numpy array, the results are written into that array (the shape and\n                    dtype of the array must be exactly correct).\n                output_measure_flips: Defaults to False. When set to False, the measure\n                    flip data is not generated and the corresponding array in the result\n                    tuple is set to None. When set to True, a new array is allocated to\n                    hold the measure flip data and this array is returned via the result\n                    tuple. When set to a numpy array, the results are written into that\n                    array (the shape and dtype of the array must be exactly correct).\n                output_detector_flips: Defaults to False. When set to False, the detector\n                    flip data is not generated and the corresponding array in the result\n                    tuple is set to None. When set to True, a new array is allocated to\n                    hold the detector flip data and this array is returned via the result\n                    tuple. When set to a numpy array, the results are written into that\n                    array (the shape and dtype of the array must be exactly correct).\n                output_observable_flips: Defaults to False. When set to False, the obs\n                    flip data is not generated and the corresponding array in the result\n                    tuple is set to None. When set to True, a new array is allocated to\n                    hold the obs flip data and this array is returned via the result\n                    tuple. When set to a numpy array, the results are written into that\n                    array (the shape and dtype of the array must be exactly correct).\n\n            Returns:\n                A tuple (xs, zs, ms, ds, os) of numpy arrays. The xs and zs arrays are\n                the pauli flip data specified using XZ encoding (00=I, 10=X, 11=Y, 01=Z).\n                The ms array is the measure flip data, the ds array is the detector flip\n                data, and the os array is the obs flip data. The arrays default to\n                `None` when the corresponding `output_*` argument was left False.\n\n                The shape and dtype of the data depends on arguments given to the function.\n                The following specifies each array's shape and dtype for each case:\n\n                    if not transpose and not bit_packed:\n                        xs.shape = (sim.batch_size, sim.num_qubits)\n                        zs.shape = (sim.batch_size, sim.num_qubits)\n                        ms.shape = (sim.batch_size, sim.num_measurements)\n                        ds.shape = (sim.batch_size, sim.num_detectors)\n                        os.shape = (sim.batch_size, sim.num_observables)\n                        xs.dtype = np.bool_\n                        zs.dtype = np.bool_\n                        ms.dtype = np.bool_\n                        ds.dtype = np.bool_\n                        os.dtype = np.bool_\n                    elif not transpose and bit_packed:\n                        xs.shape = (sim.batch_size, math.ceil(sim.num_qubits / 8))\n                        zs.shape = (sim.batch_size, math.ceil(sim.num_qubits / 8))\n                        ms.shape = (sim.batch_size, math.ceil(sim.num_measurements / 8))\n                        ds.shape = (sim.batch_size, math.ceil(sim.num_detectors / 8))\n                        os.shape = (sim.batch_size, math.ceil(sim.num_observables / 8))\n                        xs.dtype = np.uint8\n                        zs.dtype = np.uint8\n                        ms.dtype = np.uint8\n                        ds.dtype = np.uint8\n                        os.dtype = np.uint8\n                    elif transpose and not bit_packed:\n                        xs.shape = (sim.num_qubits, sim.batch_size)\n                        zs.shape = (sim.num_qubits, sim.batch_size)\n                        ms.shape = (sim.num_measurements, sim.batch_size)\n                        ds.shape = (sim.num_detectors, sim.batch_size)\n                        os.shape = (sim.num_observables, sim.batch_size)\n                        xs.dtype = np.bool_\n                        zs.dtype = np.bool_\n                        ms.dtype = np.bool_\n                        ds.dtype = np.bool_\n                        os.dtype = np.bool_\n                    elif transpose and bit_packed:\n                        xs.shape = (sim.num_qubits, math.ceil(sim.batch_size / 8))\n                        zs.shape = (sim.num_qubits, math.ceil(sim.batch_size / 8))\n                        ms.shape = (sim.num_measurements, math.ceil(sim.batch_size / 8))\n                        ds.shape = (sim.num_detectors, math.ceil(sim.batch_size / 8))\n                        os.shape = (sim.num_observables, math.ceil(sim.batch_size / 8))\n                        xs.dtype = np.uint8\n                        zs.dtype = np.uint8\n                        ms.dtype = np.uint8\n                        ds.dtype = np.uint8\n                        os.dtype = np.uint8\n\n            Raises:\n                ValueError:\n                    All the `output_*` arguments were False, or an `output_*` argument\n                    had a shape or dtype inconsistent with the requested data.\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n                >>> sim = stim.FlipSimulator(batch_size=9)\n                >>> sim.do(stim.Circuit('M(1) 0 1 2'))\n\n                >>> ms_buf = np.empty(shape=(9, 1), dtype=np.uint8)\n                >>> xs, zs, ms, ds, os = sim.to_numpy(\n                ...     transpose=True,\n                ...     bit_packed=True,\n                ...     output_xs=True,\n                ...     output_measure_flips=ms_buf,\n                ... )\n                >>> assert ms is ms_buf\n                >>> xs\n                array([[0],\n                       [0],\n                       [0],\n                       [0],\n                       [0],\n                       [0],\n                       [0],\n                       [0],\n                       [0]], dtype=uint8)\n                >>> zs\n                >>> ms\n                array([[7],\n                       [7],\n                       [7],\n                       [7],\n                       [7],\n                       [7],\n                       [7],\n                       [7],\n                       [7]], dtype=uint8)\n                >>> ds\n                >>> os\n        )DOC\")\n            .data());\n\n    c.def(\n        \"generate_bernoulli_samples\",\n        &generate_bernoulli_samples<MAX_BITWORD_WIDTH>,\n        pybind11::arg(\"num_samples\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"p\"),\n        pybind11::arg(\"bit_packed\") = false,\n        pybind11::arg(\"out\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def generate_bernoulli_samples(self, num_samples: int, *, p: float, bit_packed: bool = False, out: Optional[np.ndarray] = None) -> np.ndarray:\n            Uses the simulator's random number generator to produce biased coin flips.\n\n            This method has best performance when specifying `bit_packed=True` and\n            when specifying an `out=` parameter pointing to a numpy array that has\n            contiguous data aligned to a 64 bit boundary. (If `out` isn't specified,\n            the returned numpy array will have this property.)\n\n            Args:\n                num_samples: The number of samples to produce.\n                p: The probability of each sample being True instead of False.\n                bit_packed: Defaults to False (no bit packing). When True, the result\n                    has type np.uint8 instead of np.bool_ and 8 samples are packed into\n                    each byte as if by np.packbits(bitorder='little'). (The bit order\n                    is relevant when producing a number of samples that isn't a multiple\n                    of 8.)\n                out: Defaults to None (allocate new). A numpy array to write the samples\n                    into. Must have the correct size and dtype.\n\n            Returns:\n                A numpy array containing the samples. The shape and dtype depends on\n                the bit_packed argument:\n\n                    if not bit_packed:\n                        shape = (num_samples,)\n                        dtype = np.bool_\n                    elif not transpose and bit_packed:\n                        shape = (math.ceil(num_samples / 8),)\n                        dtype = np.uint8\n\n            Raises:\n                ValueError:\n                    The given `out` argument had a shape or dtype inconsistent with the\n                    requested data.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=256)\n                >>> r = sim.generate_bernoulli_samples(1001, p=0.25)\n                >>> r.dtype\n                dtype('bool')\n                >>> r.shape\n                (1001,)\n\n                >>> r = sim.generate_bernoulli_samples(53, p=0.1, bit_packed=True)\n                >>> r.dtype\n                dtype('uint8')\n                >>> r.shape\n                (7,)\n                >>> r[6] & 0b1110_0000  # zero'd padding bits\n                np.uint8(0)\n\n                >>> r2 = sim.generate_bernoulli_samples(53, p=0.2, bit_packed=True, out=r)\n                >>> r is r2  # Check request to reuse r worked.\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"append_measurement_flips\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::object &measurement_flip_data) {\n            if (pybind11::isinstance<pybind11::array_t<bool>>(measurement_flip_data)) {\n                const pybind11::array_t<bool> &arr = pybind11::cast<pybind11::array_t<bool>>(measurement_flip_data);\n                if (arr.ndim() == 1) {\n                    if ((size_t)arr.shape(0) != self.batch_size) {\n                        std::stringstream ss;\n                        ss << \"dtype=np.bool_ and len(shape) == 1 but shape[0]=\";\n                        ss << arr.shape(0) << \" != batch_size=\" << self.batch_size;\n                        throw std::invalid_argument(ss.str());\n                    }\n                    simd_bits_range_ref<MAX_BITWORD_WIDTH> r = self.m_record.record_zero_result_to_edit();\n                    memcpy_bits_from_numpy_to_simd(self.batch_size, measurement_flip_data, r);\n                    return;\n                } else if (arr.ndim() == 2) {\n                    if ((size_t)arr.shape(1) != self.batch_size) {\n                        std::stringstream ss;\n                        ss << \"dtype=np.uint8 and len(shape) == 2 but shape[1]=\";\n                        ss << arr.shape(1) << \" != batch_size=\" << self.batch_size;\n                        throw std::invalid_argument(ss.str());\n                    }\n\n                    size_t num_measurements = (size_t)arr.shape(0);\n                    for (size_t k = 0; k < num_measurements; k++) {\n                        simd_bits_range_ref<MAX_BITWORD_WIDTH> r = self.m_record.record_zero_result_to_edit();\n                        memcpy_bits_from_numpy_to_simd(self.batch_size, measurement_flip_data[pybind11::cast(k)], r);\n                    }\n                    return;\n                }\n            } else if (pybind11::isinstance<pybind11::array_t<uint8_t>>(measurement_flip_data)) {\n                const pybind11::array_t<bool> &arr = pybind11::cast<pybind11::array_t<uint8_t>>(measurement_flip_data);\n                auto byte_size = (self.batch_size + 7) / 8;\n                if (arr.ndim() == 1) {\n                    auto byte_size = (self.batch_size + 7) / 8;\n                    if ((size_t)arr.shape(0) != byte_size) {\n                        std::stringstream ss;\n                        ss << \"dtype=np.uint8 and len(shape) == 1 but shape[0]=\";\n                        ss << arr.shape(0) << \" != (batch_size + 7) // 8=\" << byte_size;\n                        throw std::invalid_argument(ss.str());\n                    }\n\n                    simd_bits_range_ref<MAX_BITWORD_WIDTH> r = self.m_record.record_zero_result_to_edit();\n                    memcpy_bits_from_numpy_to_simd(self.batch_size, measurement_flip_data, r);\n                    return;\n                } else if (arr.ndim() == 2) {\n                    if ((size_t)arr.shape(1) != byte_size) {\n                        std::stringstream ss;\n                        ss << \"dtype=np.uint8 and len(shape) == 2 but shape[1]=\";\n                        ss << arr.shape(1) << \" != (batch_size + 7) // 8=\" << byte_size;\n                        throw std::invalid_argument(ss.str());\n                    }\n\n                    size_t num_measurements = (size_t)arr.shape(0);\n                    for (size_t k = 0; k < num_measurements; k++) {\n                        simd_bits_range_ref<MAX_BITWORD_WIDTH> r = self.m_record.record_zero_result_to_edit();\n                        memcpy_bits_from_numpy_to_simd(self.batch_size, measurement_flip_data[pybind11::cast(k)], r);\n                    }\n                    return;\n                }\n            }\n\n            std::stringstream ss;\n            ss << \"Unsupported dtype/shape combination for append_measurement_flips.\\n\";\n            ss << \"\\nSupported combinations are:\\n\";\n            ss << \"    dtype=np.bool_, shape=(batch_size,)\\n\";\n            ss << \"    dtype=np.uint8, shape=(math.ceil(batch_size / 8),)\\n\";\n            ss << \"    dtype=np.bool_, shape=(num_measurements, batch_size)\\n\";\n            ss << \"    dtype=np.uint8, shape=(num_measurements, math.ceil(batch_size / 8))\";\n            throw std::invalid_argument(ss.str());\n        },\n        pybind11::arg(\"measurement_flip_data\"),\n        clean_doc_string(R\"DOC(\n            @signature def append_measurement_flips(self, measurement_flip_data: np.ndarray) -> None:\n            Appends measurement flip data to the simulator's measurement record.\n\n            Args:\n                measurement_flip_data: The flip data to append. The following shape/dtype\n                    combinations are supported.\n\n                    Single measurement without bit packing:\n                        shape=(self.batch_size,)\n                        dtype=np.bool_\n\n                    Single measurement with bit packing:\n                        shape=(math.ceil(self.batch_size / 8),)\n                        dtype=np.uint8\n\n                    Multiple measurements without bit packing:\n                        shape=(num_measurements, self.batch_size)\n                        dtype=np.bool_\n\n                    Multiple measurements with bit packing:\n                        shape=(num_measurements, math.ceil(self.batch_size / 8))\n                        dtype=np.uint8\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n                >>> sim = stim.FlipSimulator(batch_size=9)\n                >>> sim.append_measurement_flips(np.array(\n                ...     [0, 1, 0, 0, 1, 0, 0, 1, 1],\n                ...     dtype=np.bool_,\n                ... ))\n\n                >>> sim.get_measurement_flips()\n                array([[False,  True, False, False,  True, False, False,  True,  True]])\n\n                >>> sim.append_measurement_flips(np.array(\n                ...     [0b11001001, 0],\n                ...     dtype=np.uint8,\n                ... ))\n\n                >>> sim.get_measurement_flips()\n                array([[False,  True, False, False,  True, False, False,  True,  True],\n                       [ True, False, False,  True, False, False,  True,  True, False]])\n\n                >>> sim.append_measurement_flips(np.array(\n                ...     [[0b11111111, 0b1], [0b00000000, 0b0], [0b11111111, 0b1]],\n                ...     dtype=np.uint8,\n                ... ))\n\n                >>> sim.get_measurement_flips()\n                array([[False,  True, False, False,  True, False, False,  True,  True],\n                       [ True, False, False,  True, False, False,  True,  True, False],\n                       [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n                       [False, False, False, False, False, False, False, False, False],\n                       [ True,  True,  True,  True,  True,  True,  True,  True,  True]])\n\n                >>> sim.append_measurement_flips(np.array(\n                ...     [[1, 0, 1, 0, 1, 0, 1, 0, 1], [0, 1, 0, 1, 0, 1, 0, 1, 0]],\n                ...     dtype=np.bool_,\n                ... ))\n\n                >>> sim.get_measurement_flips()\n                array([[False,  True, False, False,  True, False, False,  True,  True],\n                       [ True, False, False,  True, False, False,  True,  True, False],\n                       [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n                       [False, False, False, False, False, False, False, False, False],\n                       [ True,  True,  True,  True,  True,  True,  True,  True,  True],\n                       [ True, False,  True, False,  True, False,  True, False,  True],\n                       [False,  True, False,  True, False,  True, False,  True, False]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"get_measurement_flips\",\n        &get_measurement_flips<MAX_BITWORD_WIDTH>,\n        pybind11::kw_only(),\n        pybind11::arg(\"record_index\") = pybind11::none(),\n        pybind11::arg(\"instance_index\") = pybind11::none(),\n        pybind11::arg(\"bit_packed\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def get_measurement_flips(self, *, record_index: Optional[int] = None, instance_index: Optional[int] = None, bit_packed: bool = False) -> np.ndarray:\n            Retrieves measurement flip data from the simulator's measurement record.\n\n            Args:\n                record_index: Identifies a measurement to read results from.\n                    Setting this to None (default) returns results from all measurements.\n                    Setting this to a non-negative integer indexes measurements by the order\n                        they occurred. For example, record index 0 is the first measurement.\n                    Setting this to a negative integer indexes measurements by recency.\n                        For example, recording index -1 is the most recent measurement.\n                instance_index: Identifies a simulation instance to read results from.\n                    Setting this to None (the default) returns results from all instances.\n                    Otherwise this should be set to an integer in range(0, self.batch_size).\n                bit_packed: Defaults to False. Determines whether the result is bit packed.\n                    If this is set to true, the returned numpy array will be bit packed as\n                    if by applying\n\n                        out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n                    Behind the scenes the data is always bit packed, so setting this\n                    argument avoids ever unpacking in the first place. This substantially\n                    improves performance when there is a lot of data.\n\n            Returns:\n                A numpy array containing the requested data. By default this is a 2d array\n                of shape (self.num_measurements, self.batch_size), where the first index is\n                the measurement_index and the second index is the instance_index and the\n                dtype is np.bool_.\n\n                Specifying record_index slices away the first index, leaving a 1d array\n                with only an instance_index.\n\n                Specifying instance_index slices away the last index, leaving a 1d array\n                with only a measurement_index (or a 0d array, a boolean, if record_index\n                was also specified).\n\n                Specifying bit_packed=True bit packs the last remaining index, changing\n                the dtype to np.uint8.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=9)\n                >>> sim.do(stim.Circuit('M 0 1 2'))\n\n                >>> sim.get_measurement_flips()\n                array([[False, False, False, False, False, False, False, False, False],\n                       [False, False, False, False, False, False, False, False, False],\n                       [False, False, False, False, False, False, False, False, False]])\n\n                >>> sim.get_measurement_flips(bit_packed=True)\n                array([[0, 0],\n                       [0, 0],\n                       [0, 0]], dtype=uint8)\n\n                >>> sim.get_measurement_flips(instance_index=1)\n                array([False, False, False])\n\n                >>> sim.get_measurement_flips(record_index=2)\n                array([False, False, False, False, False, False, False, False, False])\n\n                >>> sim.get_measurement_flips(instance_index=1, record_index=2)\n                array(False)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"get_detector_flips\",\n        &get_detector_flips<MAX_BITWORD_WIDTH>,\n        pybind11::kw_only(),\n        pybind11::arg(\"detector_index\") = pybind11::none(),\n        pybind11::arg(\"instance_index\") = pybind11::none(),\n        pybind11::arg(\"bit_packed\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def get_detector_flips(self, *, detector_index: Optional[int] = None, instance_index: Optional[int] = None, bit_packed: bool = False) -> np.ndarray:\n            Retrieves detector flip data from the simulator's detection event record.\n\n            Args:\n                record_index: Identifies a detector to read results from.\n                    Setting this to None (default) returns results from all detectors.\n                    Otherwise this should be an integer in range(0, self.num_detectors).\n                instance_index: Identifies a simulation instance to read results from.\n                    Setting this to None (the default) returns results from all instances.\n                    Otherwise this should be an integer in range(0, self.batch_size).\n                bit_packed: Defaults to False. Determines whether the result is bit packed.\n                    If this is set to true, the returned numpy array will be bit packed as\n                    if by applying\n\n                        out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n                    Behind the scenes the data is always bit packed, so setting this\n                    argument avoids ever unpacking in the first place. This substantially\n                    improves performance when there is a lot of data.\n\n            Returns:\n                A numpy array containing the requested data. By default this is a 2d array\n                of shape (self.num_detectors, self.batch_size), where the first index is\n                the detector_index and the second index is the instance_index and the\n                dtype is np.bool_.\n\n                Specifying detector_index slices away the first index, leaving a 1d array\n                with only an instance_index.\n\n                Specifying instance_index slices away the last index, leaving a 1d array\n                with only a detector_index (or a 0d array, a boolean, if detector_index\n                was also specified).\n\n                Specifying bit_packed=True bit packs the last remaining index, changing\n                the dtype to np.uint8.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=9)\n                >>> sim.do(stim.Circuit('''\n                ...     M 0 0 0\n                ...     DETECTOR rec[-2] rec[-3]\n                ...     DETECTOR rec[-1] rec[-2]\n                ... '''))\n\n                >>> sim.get_detector_flips()\n                array([[False, False, False, False, False, False, False, False, False],\n                       [False, False, False, False, False, False, False, False, False]])\n\n                >>> sim.get_detector_flips(bit_packed=True)\n                array([[0, 0],\n                       [0, 0]], dtype=uint8)\n\n                >>> sim.get_detector_flips(instance_index=2)\n                array([False, False])\n\n                >>> sim.get_detector_flips(detector_index=1)\n                array([False, False, False, False, False, False, False, False, False])\n\n                >>> sim.get_detector_flips(instance_index=2, detector_index=1)\n                array(False)\n\n        )DOC\")\n            .data());\n\n    c.def(\n        \"get_observable_flips\",\n        &get_obs_flips<MAX_BITWORD_WIDTH>,\n        pybind11::kw_only(),\n        pybind11::arg(\"observable_index\") = pybind11::none(),\n        pybind11::arg(\"instance_index\") = pybind11::none(),\n        pybind11::arg(\"bit_packed\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def get_observable_flips(self, *, observable_index: Optional[int] = None, instance_index: Optional[int] = None, bit_packed: bool = False) -> np.ndarray:\n            Retrieves observable flip data from the simulator's detection event record.\n\n            Args:\n                record_index: Identifies a observable to read results from.\n                    Setting this to None (default) returns results from all observables.\n                    Otherwise this should be an integer in range(0, self.num_observables).\n                instance_index: Identifies a simulation instance to read results from.\n                    Setting this to None (the default) returns results from all instances.\n                    Otherwise this should be an integer in range(0, self.batch_size).\n                bit_packed: Defaults to False. Determines whether the result is bit packed.\n                    If this is set to true, the returned numpy array will be bit packed as\n                    if by applying\n\n                        out = np.packbits(out, axis=len(out.shape) - 1, bitorder='little')\n\n                    Behind the scenes the data is always bit packed, so setting this\n                    argument avoids ever unpacking in the first place. This substantially\n                    improves performance when there is a lot of data.\n\n            Returns:\n                A numpy array containing the requested data. By default this is a 2d array\n                of shape (self.num_observables, self.batch_size), where the first index is\n                the observable_index and the second index is the instance_index and the\n                dtype is np.bool_.\n\n                Specifying observable_index slices away the first index, leaving a 1d array\n                with only an instance_index.\n\n                Specifying instance_index slices away the last index, leaving a 1d array\n                with only a observable_index (or a 0d array, a boolean, if observable_index\n                was also specified).\n\n                Specifying bit_packed=True bit packs the last remaining index, changing\n                the dtype to np.uint8.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=9)\n                >>> sim.do(stim.Circuit('''\n                ...     M 0 0 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-2]\n                ...     OBSERVABLE_INCLUDE(1) rec[-1]\n                ... '''))\n\n                >>> sim.get_observable_flips()\n                array([[False, False, False, False, False, False, False, False, False],\n                       [False, False, False, False, False, False, False, False, False]])\n\n                >>> sim.get_observable_flips(bit_packed=True)\n                array([[0, 0],\n                       [0, 0]], dtype=uint8)\n\n                >>> sim.get_observable_flips(instance_index=2)\n                array([False, False])\n\n                >>> sim.get_observable_flips(observable_index=1)\n                array([False, False, False, False, False, False, False, False, False])\n\n                >>> sim.get_observable_flips(instance_index=2, observable_index=1)\n                array(False)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"do\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::object &obj) {\n            if (pybind11::isinstance<Circuit>(obj)) {\n                self.safe_do_circuit(pybind11::cast<const Circuit &>(obj));\n            } else if (pybind11::isinstance<PyCircuitInstruction>(obj)) {\n                self.safe_do_instruction(pybind11::cast<const PyCircuitInstruction &>(obj));\n            } else if (pybind11::isinstance<CircuitRepeatBlock>(obj)) {\n                const CircuitRepeatBlock &block = pybind11::cast<const CircuitRepeatBlock &>(obj);\n                self.safe_do_circuit(block.body, block.repeat_count);\n            } else {\n                std::stringstream ss;\n                ss << \"Don't know how to do a '\";\n                ss << pybind11::repr(obj);\n                ss << \"'.\";\n                throw std::invalid_argument(ss.str());\n            }\n        },\n        pybind11::arg(\"obj\"),\n        clean_doc_string(R\"DOC(\n            @signature def do(self, obj: Union[stim.Circuit, stim.CircuitInstruction, stim.CircuitRepeatBlock]) -> None:\n            Applies a circuit or circuit instruction to the simulator's state.\n\n            The results of any measurements performed can be retrieved using the\n            `get_measurement_flips` method.\n\n            Args:\n                obj: The circuit or instruction to apply to the simulator's state.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(\n                ...     batch_size=1,\n                ...     disable_stabilizer_randomization=True,\n                ... )\n                >>> circuit = stim.Circuit('''\n                ...     X_ERROR(1) 0 1 3\n                ...     REPEAT 5 {\n                ...         H 0\n                ...         C_XYZ 1\n                ...     }\n                ... ''')\n                >>> sim.do(circuit)\n                >>> sim.peek_pauli_flips()\n                [stim.PauliString(\"+ZZ_X\")]\n\n                >>> sim.do(circuit[0])\n                >>> sim.peek_pauli_flips()\n                [stim.PauliString(\"+YY__\")]\n\n                >>> sim.do(circuit[1])\n                >>> sim.peek_pauli_flips()\n                [stim.PauliString(\"+YX__\")]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"broadcast_pauli_errors\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self,\n           const pybind11::object &pauli,\n           const pybind11::object &mask,\n           float p) {\n            uint8_t pb = pybind11_object_to_pauli_ixyz(pauli);\n\n            if (!pybind11::isinstance<pybind11::array_t<bool>>(mask)) {\n                throw std::invalid_argument(\"Need isinstance(mask, np.ndarray) and mask.dtype == np.bool_\");\n            }\n            const pybind11::array_t<bool> &arr = pybind11::cast<pybind11::array_t<bool>>(mask);\n\n            if (arr.ndim() != 2) {\n                throw std::invalid_argument(\n                    \"Need a 2d mask (first axis is qubits, second axis is simulation instances). Need len(mask.shape) \"\n                    \"== 2.\");\n            }\n\n            pybind11::ssize_t s_mask_num_qubits = arr.shape(0);\n            pybind11::ssize_t s_mask_batch_size = arr.shape(1);\n            if ((uint64_t)s_mask_batch_size != self.batch_size) {\n                throw std::invalid_argument(\"Need mask.shape[1] == flip_sim.batch_size\");\n            }\n            if (s_mask_num_qubits > UINT32_MAX) {\n                throw std::invalid_argument(\"Mask exceeds maximum number of simulated qubits.\");\n            }\n            uint32_t mask_num_qubits = (uint32_t)s_mask_num_qubits;\n            uint32_t mask_batch_size = (uint32_t)s_mask_batch_size;\n\n            self.ensure_safe_to_do_circuit_with_stats(CircuitStats{.num_qubits = mask_num_qubits});\n            auto u = arr.unchecked<2>();\n            bool p_x = (0b0110 >> pb) & 1;  // parity of 2 bit number\n            bool p_z = pb & 2;\n\n            if (p != 1 && p != 0) {\n                for (size_t i = 0; i < mask_num_qubits; i++) {\n                    biased_randomize_bits(\n                        p, self.rng_buffer.u64, self.rng_buffer.u64 + (mask_batch_size / 64), self.rng);\n                    for (size_t j = 0; j < mask_batch_size; j++) {\n                        bool b = *u.data(i, j);\n                        bool r = self.rng_buffer[j];\n                        self.x_table[i][j] ^= b & p_x & r;\n                        self.z_table[i][j] ^= b & p_z & r;\n                    }\n                }\n            } else {\n                for (size_t i = 0; i < mask_num_qubits; i++) {\n                    for (size_t j = 0; j < mask_batch_size; j++) {\n                        bool b = *u.data(i, j);\n\n                        self.x_table[i][j] ^= b & p_x;\n                        self.z_table[i][j] ^= b & p_z;\n                    }\n                }\n            }\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"pauli\"),\n        pybind11::arg(\"mask\"),\n        pybind11::arg(\"p\") = 1,\n        clean_doc_string(R\"DOC(\n            @signature def broadcast_pauli_errors(self, *, pauli: Union[str, int], mask: np.ndarray, p: float = 1) -> None:\n            Applies a pauli error to all qubits in all instances, filtered by a mask.\n\n            Args:\n                pauli: The pauli, specified as an integer or string.\n                    Uses the convention 0=I, 1=X, 2=Y, 3=Z.\n                    Any value from [0, 1, 2, 3, 'X', 'Y', 'Z', 'I', '_'] is allowed.\n                mask: A 2d numpy array specifying where to apply errors. The first axis\n                    is qubits, the second axis is simulation instances. The first axis\n                    can have a length less than the current number of qubits (or more,\n                    which adds qubits to the simulation). The length of the second axis\n                    must match the simulator's `batch_size`. The array must satisfy\n\n                        mask.dtype == np.bool_\n                        len(mask.shape) == 2\n                        mask.shape[1] == flip_sim.batch_size\n\n                    The error is only applied to qubit q in instance k when\n\n                        mask[q, k] == True.\n                p: Defaults to 1 (no effect). When specified, the error is applied\n                    probabilistically instead of deterministically to each (instance, qubit)\n                    pair matching the mask. This argument specifies the probability.\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n                >>> sim = stim.FlipSimulator(\n                ...     batch_size=2,\n                ...     num_qubits=3,\n                ...     disable_stabilizer_randomization=True,\n                ... )\n                >>> sim.broadcast_pauli_errors(\n                ...     pauli='X',\n                ...     mask=np.asarray([[True, False],[False, False],[True, True]]),\n                ... )\n                >>> sim.peek_pauli_flips()\n                [stim.PauliString(\"+X_X\"), stim.PauliString(\"+__X\")]\n\n                >>> sim.broadcast_pauli_errors(\n                ...     pauli='Z',\n                ...     mask=np.asarray([[False, True],[False, False],[True, True]]),\n                ... )\n                >>> sim.peek_pauli_flips()\n                [stim.PauliString(\"+X_Y\"), stim.PauliString(\"+Z_Y\")]\n\n        )DOC\")\n            .data());\n\n    c.def(\n        \"copy\",\n        [](const FrameSimulator<MAX_BITWORD_WIDTH> &self, bool copy_rng, pybind11::object &seed) {\n            if (copy_rng && !seed.is_none()) {\n                throw std::invalid_argument(\"seed and copy_rng are incompatible\");\n            }\n\n            FrameSimulator<MAX_BITWORD_WIDTH> copy = self;\n            if (!copy_rng || !seed.is_none()) {\n                copy.rng = make_py_seeded_rng(seed);\n            }\n            return copy;\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"copy_rng\") = false,\n        pybind11::arg(\"seed\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def copy(self, *, copy_rng: bool = False, seed: Optional[int] = None) -> stim.FlipSimulator:\n            Returns a simulator with the same internal state, except perhaps its prng.\n\n            Args:\n                copy_rng: Defaults to False. When False, the copy's pseudo random number\n                    generator is reinitialized with a random seed instead of being a copy\n                    of the original simulator's pseudo random number generator. This\n                    causes the copy and the original to sample independent randomness,\n                    instead of identical randomness, for future random operations. When set\n                    to true, the copy will have the exact same pseudo random number\n                    generator state as the original, and so will produce identical results\n                    if told to do the same noisy operations. This argument is incompatible\n                    with the `seed` argument.\n\n                seed: PARTIALLY determines simulation results by deterministically seeding\n                    the random number generator.\n\n                    Must be None or an integer in range(2**64).\n\n                    Defaults to None. When None, the prng state is either copied from the\n                    original simulator or reseeded from system entropy, depending on the\n                    copy_rng argument.\n\n                    When set to an integer, making the exact same series calls on the exact\n                    same machine with the exact same version of Stim will produce the exact\n                    same simulation results.\n\n                    CAUTION: simulation results *WILL NOT* be consistent between versions of\n                    Stim. This restriction is present to make it possible to have future\n                    optimizations to the random sampling, and is enforced by introducing\n                    intentional differences in the seeding strategy from version to version.\n\n                    CAUTION: simulation results *MAY NOT* be consistent across machines that\n                    differ in the width of supported SIMD instructions. For example, using\n                    the same seed on a machine that supports AVX instructions and one that\n                    only supports SSE instructions may produce different simulation results.\n\n                    CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                    circuit is executed. For example, reordering whether a reset on one\n                    qubit happens before or after a reset on another qubit can result in\n                    different measurement results being observed starting from the same\n                    seed.\n\n            Returns:\n                The copy of the simulator.\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n\n                >>> s1 = stim.FlipSimulator(batch_size=256)\n                >>> s1.set_pauli_flip('X', qubit_index=2, instance_index=3)\n                >>> s2 = s1.copy()\n                >>> s2 is s1\n                False\n                >>> s2.peek_pauli_flips() == s1.peek_pauli_flips()\n                True\n\n                >>> s1 = stim.FlipSimulator(batch_size=256)\n                >>> s2 = s1.copy(copy_rng=True)\n                >>> s1.do(stim.Circuit(\"X_ERROR(0.25) 0 \\n M 0\"))\n                >>> s2.do(stim.Circuit(\"X_ERROR(0.25) 0 \\n M 0\"))\n                >>> np.array_equal(s1.get_measurement_flips(), s2.get_measurement_flips())\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"clear\",\n        [](FrameSimulator<MAX_BITWORD_WIDTH> &self) {\n            self.reset_all();\n        },\n        clean_doc_string(R\"DOC(\n            Clears the simulator's state, so it can be reused for another simulation.\n\n            This clears the measurement flip history, clears the detector flip history,\n            and zeroes the observable flip state. It also resets all qubits to |0>. If\n            stabilizer randomization is disabled, this zeros all pauli flip data. Otherwise\n            it randomizes all pauli flips to be I or Z with equal probability.\n\n            Behind the scenes, this doesn't free memory or resize the simulator. So,\n            repeating the same simulation with calls to `clear` in between will be faster\n            than allocating a new simulator each time (by avoiding re-allocations).\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.FlipSimulator(batch_size=256)\n                >>> sim.do(stim.Circuit(\"M(0.1) 9\"))\n                >>> sim.num_qubits\n                10\n                >>> sim.get_measurement_flips().shape\n                (1, 256)\n\n                >>> sim.clear()\n                >>> sim.num_qubits\n                10\n                >>> sim.get_measurement_flips().shape\n                (0, 256)\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator.pybind.h",
    "content": "#ifndef _STIM_SIMULATORS_FRAME_SIMULATOR_PYBIND_H\n#define _STIM_SIMULATORS_FRAME_SIMULATOR_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/simulators/frame_simulator.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::FrameSimulator<stim::MAX_BITWORD_WIDTH>> pybind_frame_simulator(pybind11::module &m);\n\nvoid pybind_frame_simulator_methods(\n    pybind11::module &m, pybind11::class_<stim::FrameSimulator<stim::MAX_BITWORD_WIDTH>> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/frame_simulator.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, get_set_frame, {\n    CircuitStats circuit_stats;\n    circuit_stats.num_qubits = 6;\n    circuit_stats.max_lookback = 999;\n    FrameSimulator<W> sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 4, INDEPENDENT_TEST_RNG());\n    ASSERT_EQ(sim.get_frame(0), PauliString<W>::from_str(\"______\"));\n    ASSERT_EQ(sim.get_frame(1), PauliString<W>::from_str(\"______\"));\n    ASSERT_EQ(sim.get_frame(2), PauliString<W>::from_str(\"______\"));\n    ASSERT_EQ(sim.get_frame(3), PauliString<W>::from_str(\"______\"));\n    sim.set_frame(0, PauliString<W>::from_str(\"_XYZ__\"));\n    ASSERT_EQ(sim.get_frame(0), PauliString<W>::from_str(\"_XYZ__\"));\n    ASSERT_EQ(sim.get_frame(1), PauliString<W>::from_str(\"______\"));\n    ASSERT_EQ(sim.get_frame(2), PauliString<W>::from_str(\"______\"));\n    ASSERT_EQ(sim.get_frame(3), PauliString<W>::from_str(\"______\"));\n    sim.set_frame(3, PauliString<W>::from_str(\"ZZZZZZ\"));\n    ASSERT_EQ(sim.get_frame(0), PauliString<W>::from_str(\"_XYZ__\"));\n    ASSERT_EQ(sim.get_frame(1), PauliString<W>::from_str(\"______\"));\n    ASSERT_EQ(sim.get_frame(2), PauliString<W>::from_str(\"______\"));\n    ASSERT_EQ(sim.get_frame(3), PauliString<W>::from_str(\"ZZZZZZ\"));\n\n    circuit_stats.num_qubits = 501;\n    circuit_stats.max_lookback = 999;\n    FrameSimulator<W> big_sim(\n        circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1001, INDEPENDENT_TEST_RNG());\n    big_sim.set_frame(258, PauliString<W>::from_func(false, 501, [](size_t k) {\n                          return \"_X\"[k == 303];\n                      }));\n    ASSERT_EQ(big_sim.get_frame(258).ref().sparse_str(), \"+X303\");\n    ASSERT_EQ(big_sim.get_frame(257).ref().sparse_str(), \"+I\");\n})\n\ntemplate <size_t W>\nbool is_bulk_frame_operation_consistent_with_tableau(const Gate &gate) {\n    auto tableau = gate.tableau<W>();\n\n    CircuitStats circuit_stats;\n    circuit_stats.num_qubits = 500;\n    circuit_stats.max_lookback = 10;\n    size_t num_samples = 1000;\n    FrameSimulator<W> sim(circuit_stats, FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1000, INDEPENDENT_TEST_RNG());\n    size_t num_targets = tableau.num_qubits;\n    assert(num_targets == 1 || num_targets == 2);\n    std::vector<GateTarget> targets{{101}, {403}, {202}, {100}};\n    while (targets.size() > num_targets) {\n        targets.pop_back();\n    }\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (size_t k = 7; k < num_samples; k += 101) {\n        auto test_value = PauliString<W>::random(circuit_stats.num_qubits, rng);\n        PauliStringRef<W> test_value_ref(test_value);\n        sim.set_frame(k, test_value);\n        sim.do_gate({gate.id, {}, targets, \"\"});\n        for (size_t k2 = 0; k2 < targets.size(); k2 += num_targets) {\n            size_t target_buf[2];\n            if (num_targets == 1) {\n                target_buf[0] = targets[k2].data;\n                tableau.apply_within(test_value_ref, {&target_buf[0]});\n            } else {\n                target_buf[0] = targets[k2].data;\n                target_buf[1] = targets[k2 + 1].data;\n                tableau.apply_within(test_value_ref, {&target_buf[0], &target_buf[2]});\n            }\n        }\n        test_value.sign = false;\n        if (test_value != sim.get_frame(k)) {\n            return false;\n        }\n    }\n    return true;\n}\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, bulk_operations_consistent_with_tableau_data, {\n    for (const auto &gate : GATE_DATA.items) {\n        if (gate.has_known_unitary_matrix()) {\n            EXPECT_TRUE(is_bulk_frame_operation_consistent_with_tableau<W>(gate)) << gate.name;\n        }\n    }\n})\n\ntemplate <size_t W>\nbool is_output_possible_promising_no_bare_resets(const Circuit &circuit, const simd_bits_range_ref<W> output) {\n    auto tableau_sim = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), circuit.count_qubits());\n    size_t out_p = 0;\n    bool pass = true;\n    circuit.for_each_operation([&](const CircuitInstruction &op) {\n        if (op.gate_type == GateType::M) {\n            for (auto qf : op.targets) {\n                tableau_sim.sign_bias = output[out_p] ? -1 : +1;\n                tableau_sim.do_MZ(CircuitInstruction{GateType::M, {}, &qf, \"\"});\n                if (output[out_p] != tableau_sim.measurement_record.storage.back()) {\n                    pass = false;\n                }\n                out_p++;\n            }\n        } else {\n            tableau_sim.do_gate(op);\n        }\n    });\n    return pass;\n}\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, test_util_is_output_possible, {\n    auto circuit = Circuit(\n        \"H 0\\n\"\n        \"CNOT 0 1\\n\"\n        \"X 0\\n\"\n        \"M 0\\n\"\n        \"M 1\\n\");\n    auto data = simd_bits<W>(2);\n    data.u64[0] = 0;\n    ASSERT_EQ(false, is_output_possible_promising_no_bare_resets<W>(circuit, data));\n    data.u64[0] = 1;\n    ASSERT_EQ(true, is_output_possible_promising_no_bare_resets<W>(circuit, data));\n    data.u64[0] = 2;\n    ASSERT_EQ(true, is_output_possible_promising_no_bare_resets<W>(circuit, data));\n    data.u64[0] = 3;\n    ASSERT_EQ(false, is_output_possible_promising_no_bare_resets<W>(circuit, data));\n})\n\ntemplate <size_t W>\nbool is_sim_frame_consistent_with_sim_tableau(const char *program_text) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(program_text);\n    auto reference_sample = TableauSimulator<W>::reference_sample_circuit(circuit);\n    auto samples = sample_batch_measurements(circuit, reference_sample, 10, rng, true);\n\n    for (size_t k = 0; k < 10; k++) {\n        simd_bits_range_ref<W> sample = samples[k];\n        if (!is_output_possible_promising_no_bare_resets<W>(circuit, sample)) {\n            std::cerr << \"Impossible output: \";\n            for (size_t k2 = 0; k2 < circuit.count_measurements(); k2++) {\n                std::cerr << '0' + sample[k2];\n            }\n            std::cerr << \"\\n\";\n            return false;\n        }\n    }\n    return true;\n}\n\n#define EXPECT_SAMPLES_POSSIBLE(program) EXPECT_TRUE(is_sim_frame_consistent_with_sim_tableau<W>(program)) << program\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, consistency, {\n    EXPECT_SAMPLES_POSSIBLE(\n        \"H 0\\n\"\n        \"CNOT 0 1\\n\"\n        \"M 0\\n\"\n        \"M 1\\n\");\n\n    EXPECT_SAMPLES_POSSIBLE(\n        \"H 0\\n\"\n        \"H 1\\n\"\n        \"CNOT 0 2\\n\"\n        \"CNOT 1 3\\n\"\n        \"X 1\\n\"\n        \"M 0\\n\"\n        \"M 2\\n\"\n        \"M 3\\n\"\n        \"M 1\\n\");\n\n    EXPECT_SAMPLES_POSSIBLE(\n        \"H 0\\n\"\n        \"CNOT 0 1\\n\"\n        \"X 0\\n\"\n        \"M 0\\n\"\n        \"M 1\\n\");\n\n    EXPECT_SAMPLES_POSSIBLE(\n        \"H 0\\n\"\n        \"CNOT 0 1\\n\"\n        \"Z 0\\n\"\n        \"M 0\\n\"\n        \"M 1\\n\");\n\n    EXPECT_SAMPLES_POSSIBLE(\n        \"H 0\\n\"\n        \"M 0\\n\"\n        \"H 0\\n\"\n        \"M 0\\n\"\n        \"R 0\\n\"\n        \"H 0\\n\"\n        \"M 0\\n\");\n\n    EXPECT_SAMPLES_POSSIBLE(\n        \"H 0\\n\"\n        \"CNOT 0 1\\n\"\n        \"M 0\\n\"\n        \"R 0\\n\"\n        \"M 0\\n\"\n        \"M 1\\n\");\n\n    // Distance 2 surface code.\n    EXPECT_SAMPLES_POSSIBLE(\n        \"R 0\\n\"\n        \"R 1\\n\"\n        \"R 5\\n\"\n        \"R 6\\n\"\n        \"tick\\n\"\n        \"tick\\n\"\n        \"R 2\\n\"\n        \"R 3\\n\"\n        \"R 4\\n\"\n        \"tick\\n\"\n        \"H 2\\n\"\n        \"H 3\\n\"\n        \"H 4\\n\"\n        \"tick\\n\"\n        \"CZ 3 0\\n\"\n        \"CNOT 4 1\\n\"\n        \"tick\\n\"\n        \"CZ 3 1\\n\"\n        \"CNOT 4 6\\n\"\n        \"tick\\n\"\n        \"CNOT 2 0\\n\"\n        \"CZ 3 5\\n\"\n        \"tick\\n\"\n        \"CNOT 2 5\\n\"\n        \"CZ 3 6\\n\"\n        \"tick\\n\"\n        \"H 2\\n\"\n        \"H 3\\n\"\n        \"H 4\\n\"\n        \"tick\\n\"\n        \"M 2\\n\"\n        \"M 3\\n\"\n        \"M 4\\n\"\n        \"tick\\n\"\n        \"R 2\\n\"\n        \"R 3\\n\"\n        \"R 4\\n\"\n        \"tick\\n\"\n        \"H 2\\n\"\n        \"H 3\\n\"\n        \"H 4\\n\"\n        \"tick\\n\"\n        \"CZ 3 0\\n\"\n        \"CNOT 4 1\\n\"\n        \"tick\\n\"\n        \"CZ 3 1\\n\"\n        \"CNOT 4 6\\n\"\n        \"tick\\n\"\n        \"CNOT 2 0\\n\"\n        \"CZ 3 5\\n\"\n        \"tick\\n\"\n        \"CNOT 2 5\\n\"\n        \"CZ 3 6\\n\"\n        \"tick\\n\"\n        \"H 2\\n\"\n        \"H 3\\n\"\n        \"H 4\\n\"\n        \"tick\\n\"\n        \"M 2\\n\"\n        \"M 3\\n\"\n        \"M 4\\n\"\n        \"tick\\n\"\n        \"tick\\n\"\n        \"M 0\\n\"\n        \"M 1\\n\"\n        \"M 5\\n\"\n        \"M 6\");\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, sample_batch_measurements_writing_results_to_disk, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(\n        \"X 0\\n\"\n        \"M 1\\n\"\n        \"M 0\\n\"\n        \"M 2\\n\"\n        \"M 3\\n\");\n    auto ref = TableauSimulator<W>::reference_sample_circuit(circuit);\n    auto r = sample_batch_measurements(circuit, ref, 10, rng, true);\n    for (size_t k = 0; k < 10; k++) {\n        ASSERT_EQ(r[k].u64[0], 2);\n    }\n\n    FILE *tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(circuit, ref, 5, tmp, SampleFormat::SAMPLE_FORMAT_01, rng);\n    ASSERT_EQ(rewind_read_close(tmp), \"0100\\n0100\\n0100\\n0100\\n0100\\n\");\n\n    tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(circuit, ref, 5, tmp, SampleFormat::SAMPLE_FORMAT_B8, rng);\n    rewind(tmp);\n    for (size_t k = 0; k < 5; k++) {\n        ASSERT_EQ(getc(tmp), 2);\n    }\n    ASSERT_EQ(getc(tmp), EOF);\n\n    tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(circuit, ref, 64, tmp, SampleFormat::SAMPLE_FORMAT_PTB64, rng);\n    rewind(tmp);\n    for (size_t k = 0; k < 8; k++) {\n        ASSERT_EQ(getc(tmp), 0);\n    }\n    for (size_t k = 0; k < 8; k++) {\n        ASSERT_EQ(getc(tmp), 0xFF);\n    }\n    for (size_t k = 0; k < 8; k++) {\n        ASSERT_EQ(getc(tmp), 0);\n        ASSERT_EQ(getc(tmp), 0);\n    }\n    ASSERT_EQ(getc(tmp), EOF);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, big_circuit_measurements, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    Circuit circuit;\n    for (uint32_t k = 0; k < 1250; k += 3) {\n        circuit.safe_append_u(\"X\", {k});\n    }\n    for (uint32_t k = 0; k < 1250; k++) {\n        circuit.safe_append_u(\"M\", {k});\n    }\n    auto ref = TableauSimulator<W>::reference_sample_circuit(circuit);\n    auto r = sample_batch_measurements(circuit, ref, 750, rng, true);\n    for (size_t i = 0; i < 750; i++) {\n        for (size_t k = 0; k < 1250; k++) {\n            ASSERT_EQ(r[i][k], k % 3 == 0) << k;\n        }\n    }\n\n    FILE *tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(circuit, ref, 750, tmp, SampleFormat::SAMPLE_FORMAT_01, rng);\n    rewind(tmp);\n    for (size_t s = 0; s < 750; s++) {\n        for (size_t k = 0; k < 1250; k++) {\n            ASSERT_EQ(getc(tmp), \"01\"[k % 3 == 0]);\n        }\n        ASSERT_EQ(getc(tmp), '\\n');\n    }\n    ASSERT_EQ(getc(tmp), EOF);\n\n    tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(circuit, ref, 750, tmp, SampleFormat::SAMPLE_FORMAT_B8, rng);\n    rewind(tmp);\n    for (size_t s = 0; s < 750; s++) {\n        for (size_t k = 0; k < 1250; k += 8) {\n            char c = getc(tmp);\n            for (size_t k2 = 0; k + k2 < 1250 && k2 < 8; k2++) {\n                ASSERT_EQ((c >> k2) & 1, (k + k2) % 3 == 0);\n            }\n        }\n    }\n    ASSERT_EQ(getc(tmp), EOF);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, run_length_measurement_formats, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    Circuit circuit;\n    circuit.safe_append_u(\"X\", {100, 500, 501, 551, 1200});\n    for (uint32_t k = 0; k < 1250; k++) {\n        circuit.safe_append_u(\"M\", {k});\n    }\n    auto ref = TableauSimulator<W>::reference_sample_circuit(circuit);\n\n    FILE *tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(circuit, ref, 3, tmp, SampleFormat::SAMPLE_FORMAT_HITS, rng);\n    ASSERT_EQ(rewind_read_close(tmp), \"100,500,501,551,1200\\n100,500,501,551,1200\\n100,500,501,551,1200\\n\");\n\n    tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(circuit, ref, 3, tmp, SampleFormat::SAMPLE_FORMAT_DETS, rng);\n    ASSERT_EQ(\n        rewind_read_close(tmp),\n        \"shot M100 M500 M501 M551 M1200\\nshot M100 M500 M501 M551 M1200\\nshot M100 M500 M501 M551 M1200\\n\");\n\n    tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(circuit, ref, 3, tmp, SampleFormat::SAMPLE_FORMAT_R8, rng);\n    rewind(tmp);\n    for (size_t k = 0; k < 3; k++) {\n        ASSERT_EQ(getc(tmp), 100);\n        ASSERT_EQ(getc(tmp), 255);\n        ASSERT_EQ(getc(tmp), 400 - 255 - 1);\n        ASSERT_EQ(getc(tmp), 0);\n        ASSERT_EQ(getc(tmp), 49);\n        ASSERT_EQ(getc(tmp), 255);\n        ASSERT_EQ(getc(tmp), 255);\n        ASSERT_EQ(getc(tmp), 1200 - 551 - 255 * 2 - 1);\n        ASSERT_EQ(getc(tmp), 1250 - 1200 - 1);\n    }\n    ASSERT_EQ(getc(tmp), EOF);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, big_circuit_random_measurements, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    Circuit circuit;\n    for (uint32_t k = 0; k < 270; k++) {\n        circuit.safe_append_u(\"H_XZ\", {k});\n    }\n    for (uint32_t k = 0; k < 270; k++) {\n        circuit.safe_append_u(\"M\", {k});\n    }\n    auto ref = TableauSimulator<W>::reference_sample_circuit(circuit);\n    auto r = sample_batch_measurements(circuit, ref, 1000, rng, true);\n    for (size_t k = 0; k < 1000; k++) {\n        ASSERT_TRUE(r[k].not_zero()) << k;\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, correlated_error, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> ref(5);\n    simd_bits<W> expected(5);\n\n    expected.clear();\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(0) X0 X1\n        ELSE_CORRELATED_ERROR(0) X1 X2\n        ELSE_CORRELATED_ERROR(0) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(1) X0 X1\n        ELSE_CORRELATED_ERROR(0) X1 X2\n        ELSE_CORRELATED_ERROR(0) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    expected[1] = true;\n    expected[2] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(0) X0 X1\n        ELSE_CORRELATED_ERROR(1) X1 X2\n        ELSE_CORRELATED_ERROR(0) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    expected[2] = true;\n    expected[3] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(0) X0 X1\n        ELSE_CORRELATED_ERROR(0) X1 X2\n        ELSE_CORRELATED_ERROR(1) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(1) X0 X1\n        ELSE_CORRELATED_ERROR(1) X1 X2\n        ELSE_CORRELATED_ERROR(0) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(1) X0 X1\n        ELSE_CORRELATED_ERROR(1) X1 X2\n        ELSE_CORRELATED_ERROR(1) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    expected[3] = true;\n    expected[4] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n                CORRELATED_ERROR(1) X0 X1\n                ELSE_CORRELATED_ERROR(1) X1 X2\n                ELSE_CORRELATED_ERROR(1) X2 X3\n                CORRELATED_ERROR(1) X3 X4\n                M 0 1 2 3 4\n            )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    int hits[3]{};\n    size_t n = 10000;\n    auto samples = sample_batch_measurements(\n        Circuit(R\"circuit(\n                CORRELATED_ERROR(0.5) X0\n                ELSE_CORRELATED_ERROR(0.25) X1\n                ELSE_CORRELATED_ERROR(0.75) X2\n                M 0 1 2\n            )circuit\"),\n        ref,\n        n,\n        rng,\n        true);\n    for (size_t k = 0; k < n; k++) {\n        hits[0] += samples[k][0];\n        hits[1] += samples[k][1];\n        hits[2] += samples[k][2];\n    }\n    ASSERT_TRUE(0.45 * n < hits[0] && hits[0] < 0.55 * n);\n    ASSERT_TRUE((0.125 - 0.05) * n < hits[1] && hits[1] < (0.125 + 0.05) * n);\n    ASSERT_TRUE((0.28125 - 0.05) * n < hits[2] && hits[2] < (0.28125 + 0.05) * n);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, quantum_cannot_control_classical, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> ref(128);\n\n    // Quantum controlling classical operation is not allowed.\n    ASSERT_THROW(\n        {\n            sample_batch_measurements(\n                Circuit(R\"circuit(\n            M 0\n            CNOT 1 rec[-1]\n        )circuit\"),\n                ref,\n                1,\n                rng,\n                true);\n        },\n        std::invalid_argument);\n    ASSERT_THROW(\n        {\n            sample_batch_measurements(\n                Circuit(R\"circuit(\n            M 0\n            CY 1 rec[-1]\n        )circuit\"),\n                ref,\n                1,\n                rng,\n                true);\n        },\n        std::invalid_argument);\n    ASSERT_THROW(\n        {\n            sample_batch_measurements(\n                Circuit(R\"circuit(\n            M 0\n            YCZ rec[-1] 1\n        )circuit\"),\n                ref,\n                1,\n                rng,\n                true);\n        },\n        std::invalid_argument);\n    ASSERT_THROW(\n        {\n            sample_batch_measurements(\n                Circuit(R\"circuit(\n            M 0\n            XCZ rec[-1] 1\n        )circuit\"),\n                ref,\n                1,\n                rng,\n                true);\n        },\n        std::invalid_argument);\n    ASSERT_THROW(\n        {\n            sample_batch_measurements(\n                Circuit(R\"circuit(\n            M 0\n            SWAP 1 rec[-1]\n        )circuit\"),\n                ref,\n                1,\n                rng,\n                true);\n        },\n        std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, classical_can_control_quantum, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> ref(128);\n    simd_bits<W> expected(5);\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        X_ERROR(1) 0\n        M !0\n        CX rec[-1] 1\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        X_ERROR(1) 0\n        M !0\n        CY rec[-1] 1\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        X_ERROR(1) 0\n        M !0\n        XCZ 1 rec[-1]\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        X_ERROR(1) 0\n        M !0\n        YCZ 1 rec[-1]\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, classical_controls, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> ref(128);\n    simd_bits<W> expected(5);\n\n    expected.clear();\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        M 0\n        CX rec[-1] 1\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        M !0\n        CX rec[-1] 1\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        X_ERROR(1) 0\n        M !0\n        CX rec[-1] 1\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        X_ERROR(1) 0\n        M 0\n        CX rec[-1] 1\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n    auto r = sample_batch_measurements(\n        Circuit(R\"circuit(\n        X_ERROR(0.5) 0\n        M 0\n        CX rec[-1] 1\n        M 1\n    )circuit\"),\n        ref,\n        1000,\n        rng,\n        true);\n    size_t hits = 0;\n    for (size_t k = 0; k < 1000; k++) {\n        ASSERT_EQ(r[k][0], r[k][1]);\n        hits += r[k][0];\n    }\n    ASSERT_TRUE(400 < hits && hits < 600);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        X_ERROR(1) 0\n        M 0\n        H 1\n        CZ rec[-1] 1\n        H 1\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        sample_batch_measurements(\n            Circuit(R\"circuit(\n        X_ERROR(1) 0\n        M 0\n        CY rec[-1] 1\n        M 1\n    )circuit\"),\n            ref,\n            1,\n            rng,\n            true)[0],\n        expected);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, record_gets_trimmed, {\n    Circuit c = Circuit(\"M 0 1 2 3 4 5 6 7 8 9\");\n    FrameSimulator<W> sim(\n        c.compute_stats(), FrameSimulatorMode::STREAM_MEASUREMENTS_TO_DISK, 768, INDEPENDENT_TEST_RNG());\n    MeasureRecordBatchWriter b(tmpfile(), 768, SampleFormat::SAMPLE_FORMAT_B8);\n    for (size_t k = 0; k < 1000; k++) {\n        sim.do_MZ(c.operations[0]);\n        sim.m_record.intermediate_write_unwritten_results_to(b, simd_bits<W>(0));\n        ASSERT_LT(sim.m_record.storage.num_major_bits_padded(), 2500);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, stream_huge_case, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    FILE *tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(\n        Circuit(R\"CIRCUIT(\n            X_ERROR(1) 2\n            REPEAT 100000 {\n                M 0 1 2 3\n            }\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        256,\n        tmp,\n        SampleFormat::SAMPLE_FORMAT_B8,\n        rng);\n    rewind(tmp);\n    for (size_t k = 0; k < 256 * 100000 * 4 / 8; k++) {\n        ASSERT_EQ(getc(tmp), 0x44);\n    }\n    ASSERT_EQ(getc(tmp), EOF);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, block_results_single_shot, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(R\"circuit(\n        REPEAT 10000 {\n            X_ERROR(1) 0\n            MR 0\n            M 0 0\n        }\n    )circuit\");\n    FILE *tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(\n        circuit, simd_bits<W>(0), 3, tmp, SampleFormat::SAMPLE_FORMAT_01, rng);\n\n    auto result = rewind_read_close(tmp);\n    for (size_t k = 0; k < 30000; k += 3) {\n        ASSERT_EQ(result[k], '1') << k;\n        ASSERT_EQ(result[k + 1], '0') << (k + 1);\n        ASSERT_EQ(result[k + 2], '0') << (k + 2);\n    }\n    ASSERT_EQ(result[30000], '\\n');\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, block_results_triple_shot, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(R\"circuit(\n        REPEAT 10000 {\n            X_ERROR(1) 0\n            MR 0\n            M 0 0\n        }\n    )circuit\");\n    FILE *tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(\n        circuit, simd_bits<W>(0), 3, tmp, SampleFormat::SAMPLE_FORMAT_01, rng);\n\n    auto result = rewind_read_close(tmp);\n    for (size_t rep = 0; rep < 3; rep++) {\n        size_t s = rep * 30001;\n        for (size_t k = 0; k < 30000; k += 3) {\n            ASSERT_EQ(result[s + k], '1') << (s + k);\n            ASSERT_EQ(result[s + k + 1], '0') << (s + k + 1);\n            ASSERT_EQ(result[s + k + 2], '0') << (s + k + 2);\n        }\n        ASSERT_EQ(result[s + 30000], '\\n');\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, stream_results, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    DebugForceResultStreamingRaii force_streaming;\n    auto circuit = Circuit(R\"circuit(\n        REPEAT 10000 {\n            X_ERROR(1) 0\n            MR 0\n            M 0 0\n        }\n    )circuit\");\n    FILE *tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(\n        circuit, simd_bits<W>(0), 3, tmp, SampleFormat::SAMPLE_FORMAT_01, rng);\n\n    auto result = rewind_read_close(tmp);\n    for (size_t k = 0; k < 30000; k += 3) {\n        ASSERT_EQ(result[k], '1') << k;\n        ASSERT_EQ(result[k + 1], '0') << (k + 1);\n        ASSERT_EQ(result[k + 2], '0') << (k + 2);\n    }\n    ASSERT_EQ(result[30000], '\\n');\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, stream_many_shots, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    DebugForceResultStreamingRaii force_streaming;\n    auto circuit = Circuit(R\"circuit(\n        X_ERROR(1) 1\n        M 0 1 2\n    )circuit\");\n    FILE *tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(\n        circuit, simd_bits<W>(0), 2049, tmp, SampleFormat::SAMPLE_FORMAT_01, rng);\n\n    auto result = rewind_read_close(tmp);\n    ASSERT_EQ(result.size(), 2049 * 4);\n    for (size_t k = 0; k < 2049 * 4; k += 4) {\n        ASSERT_EQ(result[k], '0') << k;\n        ASSERT_EQ(result[k + 1], '1') << (k + 1);\n        ASSERT_EQ(result[k + 2], '0') << (k + 2);\n        ASSERT_EQ(result[k + 3], '\\n') << (k + 3);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, stream_results_triple_shot, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    DebugForceResultStreamingRaii force_streaming;\n    auto circuit = Circuit(R\"circuit(\n        REPEAT 10000 {\n            X_ERROR(1) 0\n            MR 0\n            M 0 0\n        }\n    )circuit\");\n    FILE *tmp = tmpfile();\n    sample_batch_measurements_writing_results_to_disk(\n        circuit, simd_bits<W>(0), 3, tmp, SampleFormat::SAMPLE_FORMAT_01, rng);\n\n    auto result = rewind_read_close(tmp);\n    for (size_t rep = 0; rep < 3; rep++) {\n        size_t s = rep * 30001;\n        for (size_t k = 0; k < 30000; k += 3) {\n            ASSERT_EQ(result[s + k], '1') << (s + k);\n            ASSERT_EQ(result[s + k + 1], '0') << (s + k + 1);\n            ASSERT_EQ(result[s + k + 2], '0') << (s + k + 2);\n        }\n        ASSERT_EQ(result[s + 30000], '\\n');\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, measure_y_without_reset_doesnt_reset, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RY 0\n            MY 0\n            MY 0\n            Z_ERROR(1) 0\n            MY 0\n            MY 0\n            Z_ERROR(1) 0\n            MY 0\n            MY 0\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        10000,\n        rng,\n        false);\n    ASSERT_EQ(r[0].popcnt(), 0);\n    ASSERT_EQ(r[1].popcnt(), 0);\n    ASSERT_EQ(r[2].popcnt(), 10000);\n    ASSERT_EQ(r[3].popcnt(), 10000);\n    ASSERT_EQ(r[4].popcnt(), 0);\n    ASSERT_EQ(r[5].popcnt(), 0);\n\n    r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n        RY 0\n        MRY 0\n        MRY 0\n        Z_ERROR(1) 0\n        MRY 0\n        MRY 0\n        Z_ERROR(1) 0\n        MRY 0\n        MRY 0\n    )CIRCUIT\"),\n        simd_bits<W>(0),\n        10000,\n        rng,\n        false);\n    ASSERT_EQ(r[0].popcnt(), 0);\n    ASSERT_EQ(r[1].popcnt(), 0);\n    ASSERT_EQ(r[2].popcnt(), 10000);\n    ASSERT_EQ(r[3].popcnt(), 0);\n    ASSERT_EQ(r[4].popcnt(), 10000);\n    ASSERT_EQ(r[5].popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, resets_vs_measurements, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto check = [&](const char *circuit, std::vector<bool> results) {\n        simd_bits<W> ref(results.size());\n        for (size_t k = 0; k < results.size(); k++) {\n            ref[k] = results[k];\n        }\n        simd_bit_table<W> t = sample_batch_measurements(Circuit(circuit), ref, 100, rng, true);\n        return !t.data.not_zero();\n    };\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        RX 0\n        RY 1\n        RZ 2\n        H_XZ 0\n        H_YZ 1\n        M 0 1 2\n    )circuit\",\n        {\n            false,\n            false,\n            false,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0 1 2\n        H_YZ 3 4 5\n        X_ERROR(1) 0 3 6\n        Y_ERROR(1) 1 4 7\n        Z_ERROR(1) 2 5 8\n        MX 0 1 2\n        MY 3 4 5\n        MZ 6 7 8\n    )circuit\",\n        {\n            false,\n            true,\n            true,\n            true,\n            false,\n            true,\n            true,\n            true,\n            false,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0 1 2\n        H_YZ 3 4 5\n        X_ERROR(1) 0 3 6\n        Y_ERROR(1) 1 4 7\n        Z_ERROR(1) 2 5 8\n        MX !0 !1 !2\n        MY !3 !4 !5\n        MZ !6 !7 !8\n    )circuit\",\n        {\n            false,\n            true,\n            true,\n            true,\n            false,\n            true,\n            true,\n            true,\n            false,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0 1 2\n        H_YZ 3 4 5\n        X_ERROR(1) 0 3 6\n        Y_ERROR(1) 1 4 7\n        Z_ERROR(1) 2 5 8\n        MRX 0 1 2\n        MRY 3 4 5\n        MRZ 6 7 8\n        H_XZ 0\n        H_YZ 3\n        M 0 3 6\n    )circuit\",\n        {\n            false,\n            true,\n            true,\n            true,\n            false,\n            true,\n            true,\n            true,\n            false,\n            false,\n            false,\n            false,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0 1 2\n        H_YZ 3 4 5\n        X_ERROR(1) 0 3 6\n        Y_ERROR(1) 1 4 7\n        Z_ERROR(1) 2 5 8\n        MRX !0 !1 !2\n        MRY !3 !4 !5\n        MRZ !6 !7 !8\n        H_XZ 0\n        H_YZ 3\n        M 0 3 6\n    )circuit\",\n        {\n            false,\n            true,\n            true,\n            true,\n            false,\n            true,\n            true,\n            true,\n            false,\n            false,\n            false,\n            false,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0\n        H_YZ 1\n        Z_ERROR(1) 0 1\n        X_ERROR(1) 2\n        MRX 0 0\n        MRY 1 1\n        MRZ 2 2\n    )circuit\",\n        {\n            true,\n            false,\n            true,\n            false,\n            true,\n            false,\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_x, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RX 0\n            MX(0.05) 0\n            MX 0\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        10000,\n        rng,\n        false);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RX 0 1\n            Z_ERROR(1) 0 1\n            MX(0.05) 0 1\n            MX 0 1\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        5000,\n        rng,\n        false);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 5000);\n    ASSERT_EQ(r[3].popcnt(), 5000);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_y, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n        RY 0\n        MY(0.05) 0\n        MY 0\n    )CIRCUIT\"),\n        simd_bits<W>(0),\n        10000,\n        rng,\n        false);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n        RY 0 1\n        Z_ERROR(1) 0 1\n        MY(0.05) 0 1\n        MY 0 1\n    )CIRCUIT\"),\n        simd_bits<W>(0),\n        5000,\n        rng,\n        false);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 5000);\n    ASSERT_EQ(r[3].popcnt(), 5000);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_z, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n        RZ 0\n        MZ(0.05) 0\n        MZ 0\n    )CIRCUIT\"),\n        simd_bits<W>(0),\n        10000,\n        rng,\n        false);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RZ 0 1\n            X_ERROR(1) 0 1\n            MZ(0.05) 0 1\n            MZ 0 1\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        5000,\n        rng,\n        false);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 5000);\n    ASSERT_EQ(r[3].popcnt(), 5000);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_x, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RX 0\n            MRX(0.05) 0\n            MRX 0\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        10000,\n        rng,\n        false);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RX 0 1\n            Z_ERROR(1) 0 1\n            MRX(0.05) 0 1\n            MRX 0 1\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        5000,\n        rng,\n        false);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 0);\n    ASSERT_EQ(r[3].popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_y, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RY 0\n            MRY(0.05) 0\n            MRY 0\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        10000,\n        rng,\n        false);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RY 0 1\n            Z_ERROR(1) 0 1\n            MRY(0.05) 0 1\n            MRY 0 1\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        5000,\n        rng,\n        false);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 0);\n    ASSERT_EQ(r[3].popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, noisy_measurement_reset_z, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RZ 0\n            MRZ(0.05) 0\n            MRZ 0\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        10000,\n        rng,\n        false);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            RZ 0 1\n            X_ERROR(1) 0 1\n            MRZ(0.05) 0 1\n            MRZ 0 1\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        5000,\n        rng,\n        false);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 0);\n    ASSERT_EQ(r[3].popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, measure_pauli_product_4body, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto r = sample_batch_measurements(\n        Circuit(R\"CIRCUIT(\n            X_ERROR(0.5) 0 1 2 3\n            Z_ERROR(0.5) 0 1 2 3\n            MPP X0*X1*X2*X3\n            MX 0 1 2 3 4 5\n            MPP X2*X3*X4*X5\n            MPP Z0*Z1*Z4*Z5 !Y0*Y1*Y4*Y5\n        )CIRCUIT\"),\n        simd_bits<W>(0),\n        10,\n        rng,\n        false);\n    for (size_t k = 0; k < 10; k++) {\n        auto x0123 = r[0][k];\n        auto x0 = r[1][k];\n        auto x1 = r[2][k];\n        auto x2 = r[3][k];\n        auto x3 = r[4][k];\n        auto x4 = r[5][k];\n        auto x5 = r[6][k];\n        auto x2345 = r[7][k];\n        auto mz0145 = r[8][k];\n        auto y0145 = r[9][k];\n        ASSERT_EQ(x0123, x0 ^ x1 ^ x2 ^ x3);\n        ASSERT_EQ(x2345, x2 ^ x3 ^ x4 ^ x5);\n        ASSERT_EQ(y0145 ^ mz0145, x0123 ^ x2345);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, non_deterministic_pauli_product_detectors, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto n = sample_batch_measurements(\n                 Circuit(R\"CIRCUIT(\n                     MPP Z8*X9\n                     DETECTOR rec[-1]\n                 )CIRCUIT\"),\n                 simd_bits<W>(0),\n                 1000,\n                 rng,\n                 false)[0]\n                 .popcnt();\n    ASSERT_TRUE(400 < n && n < 600);\n\n    n = sample_batch_measurements(\n            Circuit(R\"CIRCUIT(\n                MPP X9\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            simd_bits<W>(0),\n            1000,\n            rng,\n            false)[0]\n            .popcnt();\n    ASSERT_TRUE(400 < n && n < 600);\n\n    n = sample_batch_measurements(\n            Circuit(R\"CIRCUIT(\n                MX 9\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            simd_bits<W>(0),\n            1000,\n            rng,\n            false)[0]\n            .popcnt();\n    ASSERT_TRUE(400 < n && n < 600);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, ignores_sweep_controls_when_given_no_sweep_data, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto n = sample_batch_measurements(\n                 Circuit(R\"CIRCUIT(\n                     CNOT sweep[0] 0\n                     M 0\n                     DETECTOR rec[-1]\n                 )CIRCUIT\"),\n                 simd_bits<W>(0),\n                 1000,\n                 rng,\n                 false)[0]\n                 .popcnt();\n    ASSERT_EQ(n, 0);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, reconfigure_for, {\n    auto circuit = Circuit(R\"CIRCUIT(\n        X_ERROR(1) 0\n        M 0\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n\n    FrameSimulator<W> frame_sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 0, INDEPENDENT_TEST_RNG());\n    frame_sim.configure_for(circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 256);\n    frame_sim.reset_all();\n    frame_sim.do_circuit(circuit);\n    ASSERT_EQ(frame_sim.det_record.storage[0].popcnt(), 256);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, mpad, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(R\"CIRCUIT(\n        MPAD 0 1\n    )CIRCUIT\");\n    auto sample =\n        sample_batch_measurements(circuit, TableauSimulator<W>::reference_sample_circuit(circuit), 100, rng, false);\n    for (size_t k = 0; k < 100; k++) {\n        ASSERT_EQ(sample[0][k], false);\n        ASSERT_EQ(sample[1][k], true);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, mxxyyzz_basis, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(R\"CIRCUIT(\n        RX 0 1\n        MXX 0 1\n        RY 0 1\n        MYY 0 1\n        RZ 0 1\n        MZZ 0 1\n    )CIRCUIT\");\n    auto sample =\n        sample_batch_measurements(circuit, TableauSimulator<W>::reference_sample_circuit(circuit), 100, rng, false);\n    for (size_t k = 0; k < 100; k++) {\n        ASSERT_EQ(sample[0][k], false);\n        ASSERT_EQ(sample[1][k], false);\n        ASSERT_EQ(sample[2][k], false);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, mxxyyzz_inversion, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(R\"CIRCUIT(\n        MXX 0 1 0 !1 !0 1 !0 !1\n        MYY 0 1 0 !1 !0 1 !0 !1\n        MZZ 0 1 0 !1 !0 1 !0 !1\n    )CIRCUIT\");\n    auto sample =\n        sample_batch_measurements(circuit, TableauSimulator<W>::reference_sample_circuit(circuit), 100, rng, false);\n    for (size_t k = 0; k < 100; k++) {\n        ASSERT_EQ(sample[1][k], !sample[0][k]);\n        ASSERT_EQ(sample[2][k], !sample[0][k]);\n        ASSERT_EQ(sample[3][k], sample[0][k]);\n        ASSERT_EQ(sample[5][k], !sample[4][k]);\n        ASSERT_EQ(sample[6][k], !sample[4][k]);\n        ASSERT_EQ(sample[7][k], sample[4][k]);\n        ASSERT_EQ(sample[8][k], 1 ^ sample[0][k] ^ sample[4][k]);\n        ASSERT_EQ(sample[9][k], !sample[8][k]);\n        ASSERT_EQ(sample[10][k], !sample[8][k]);\n        ASSERT_EQ(sample[11][k], sample[8][k]);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, runs_on_general_circuit, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = generate_test_circuit_with_all_operations();\n    auto sample =\n        sample_batch_measurements(circuit, TableauSimulator<W>::reference_sample_circuit(circuit), 100, rng, false);\n    ASSERT_GT(sample.num_simd_words_minor, 0);\n    ASSERT_GT(sample.num_simd_words_major, 0);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, heralded_erase_detect_statistics, {\n    auto circuit = Circuit(R\"CIRCUIT(\n        MXX 0 1\n        MZZ 0 1\n        HERALDED_ERASE(0.1) 0\n        MXX 0 1\n        MZZ 0 1\n        DETECTOR rec[-1] rec[-4]\n        DETECTOR rec[-2] rec[-5]\n        DETECTOR rec[-3]\n    )CIRCUIT\");\n    size_t n;\n    std::array<size_t, 8> bins{};\n    FrameSimulator<W> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1024, INDEPENDENT_TEST_RNG());\n    for (n = 0; n < 1024 * 256; n += 1024) {\n        sim.reset_all();\n        sim.do_circuit(circuit);\n        auto sample = sim.det_record.storage.transposed();\n        for (size_t k = 0; k < 1024; k++) {\n            bins[sample[k].u8[0]]++;\n        }\n    }\n    EXPECT_NEAR(bins[0] / (double)n, 0.9, 0.05);\n    EXPECT_EQ(bins[1], 0);\n    EXPECT_EQ(bins[2], 0);\n    EXPECT_EQ(bins[3], 0);\n    EXPECT_NEAR(bins[4] / (double)n, 0.025, 0.02);\n    EXPECT_NEAR(bins[5] / (double)n, 0.025, 0.02);\n    EXPECT_NEAR(bins[6] / (double)n, 0.025, 0.02);\n    EXPECT_NEAR(bins[7] / (double)n, 0.025, 0.02);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, heralded_pauli_channel_1_statistics, {\n    auto circuit = Circuit(R\"CIRCUIT(\n        MXX 0 1\n        MZZ 0 1\n        HERALDED_PAULI_CHANNEL_1(0.05, 0.10, 0.15, 0.25) 0\n        MXX 0 1\n        MZZ 0 1\n        DETECTOR rec[-1] rec[-4]\n        DETECTOR rec[-2] rec[-5]\n        DETECTOR rec[-3]\n    )CIRCUIT\");\n    size_t n;\n    std::array<size_t, 8> bins{};\n    FrameSimulator<W> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1024, INDEPENDENT_TEST_RNG());\n    for (n = 0; n < 1024 * 256; n += 1024) {\n        sim.reset_all();\n        sim.do_circuit(circuit);\n        auto sample = sim.det_record.storage.transposed();\n        for (size_t k = 0; k < 1024; k++) {\n            bins[sample[k].u8[0]]++;\n        }\n    }\n    EXPECT_NEAR(bins[0] / (double)n, 0.45, 0.05);\n    EXPECT_EQ(bins[1], 0);\n    EXPECT_EQ(bins[2], 0);\n    EXPECT_EQ(bins[3], 0);\n    EXPECT_NEAR(bins[4] / (double)n, 0.05, 0.04);\n    EXPECT_NEAR(bins[5] / (double)n, 0.10, 0.04);\n    EXPECT_NEAR(bins[6] / (double)n, 0.25, 0.04);\n    EXPECT_NEAR(bins[7] / (double)n, 0.15, 0.04);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, heralded_erase_statistics_offset_by_2, {\n    auto circuit = Circuit(R\"CIRCUIT(\n        MXX 2 3\n        MZZ 2 3\n        HERALDED_ERASE(0.1) 2\n        MXX 2 3\n        MZZ 2 3\n        DETECTOR rec[-1] rec[-4]\n        DETECTOR rec[-2] rec[-5]\n        DETECTOR rec[-3]\n    )CIRCUIT\");\n    size_t n;\n    std::array<size_t, 8> bins{};\n    FrameSimulator<W> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1024, INDEPENDENT_TEST_RNG());\n    for (n = 0; n < 1024 * 256; n += 1024) {\n        sim.reset_all();\n        sim.do_circuit(circuit);\n        auto sample = sim.det_record.storage.transposed();\n        for (size_t k = 0; k < 1024; k++) {\n            bins[sample[k].u8[0]]++;\n        }\n    }\n    EXPECT_NEAR(bins[0] / (double)n, 0.9, 0.05);\n    EXPECT_EQ(bins[1], 0);\n    EXPECT_EQ(bins[2], 0);\n    EXPECT_EQ(bins[3], 0);\n    EXPECT_NEAR(bins[4] / (double)n, 0.025, 0.02);\n    EXPECT_NEAR(bins[5] / (double)n, 0.025, 0.02);\n    EXPECT_NEAR(bins[6] / (double)n, 0.025, 0.02);\n    EXPECT_NEAR(bins[7] / (double)n, 0.025, 0.02);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, heralded_pauli_channel_1_statistics_offset_by_2, {\n    auto circuit = Circuit(R\"CIRCUIT(\n        MXX 2 3\n        MZZ 2 3\n        HERALDED_PAULI_CHANNEL_1(0.05, 0.10, 0.15, 0.25) 2\n        MXX 2 3\n        MZZ 2 3\n        DETECTOR rec[-1] rec[-4]\n        DETECTOR rec[-2] rec[-5]\n        DETECTOR rec[-3]\n    )CIRCUIT\");\n    size_t n;\n    std::array<size_t, 8> bins{};\n    FrameSimulator<W> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1024, INDEPENDENT_TEST_RNG());\n    for (n = 0; n < 1024 * 256; n += 1024) {\n        sim.reset_all();\n        sim.do_circuit(circuit);\n        auto sample = sim.det_record.storage.transposed();\n        for (size_t k = 0; k < 1024; k++) {\n            bins[sample[k].u8[0]]++;\n        }\n    }\n    EXPECT_NEAR(bins[0] / (double)n, 0.45, 0.05);\n    EXPECT_EQ(bins[1], 0);\n    EXPECT_EQ(bins[2], 0);\n    EXPECT_EQ(bins[3], 0);\n    EXPECT_NEAR(bins[4] / (double)n, 0.05, 0.04);\n    EXPECT_NEAR(bins[5] / (double)n, 0.10, 0.04);\n    EXPECT_NEAR(bins[6] / (double)n, 0.25, 0.04);\n    EXPECT_NEAR(bins[7] / (double)n, 0.15, 0.04);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, observable_include_paulis_rz, {\n    auto circuit = Circuit(R\"CIRCUIT(\n        RZ 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n    )CIRCUIT\");\n    FrameSimulator<W> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1024, INDEPENDENT_TEST_RNG());\n    sim.reset_all();\n    sim.do_circuit(circuit);\n    auto x0 = sim.obs_record[0].popcnt();\n    auto y0 = sim.obs_record[1].popcnt();\n    auto z0 = sim.obs_record[2].popcnt();\n    ASSERT_EQ(x0, y0);\n    ASSERT_GT(x0, 300);\n    ASSERT_LT(x0, 700);\n    ASSERT_EQ(z0, 0);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, observable_include_paulis_ry, {\n    auto circuit = Circuit(R\"CIRCUIT(\n        RY 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n    )CIRCUIT\");\n    FrameSimulator<W> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1024, INDEPENDENT_TEST_RNG());\n    sim.reset_all();\n    sim.do_circuit(circuit);\n    auto x0 = sim.obs_record[0].popcnt();\n    auto y0 = sim.obs_record[1].popcnt();\n    auto z0 = sim.obs_record[2].popcnt();\n    ASSERT_EQ(x0, z0);\n    ASSERT_GT(x0, 300);\n    ASSERT_LT(x0, 700);\n    ASSERT_EQ(y0, 0);\n})\n\nTEST_EACH_WORD_SIZE_W(FrameSimulator, observable_include_paulis_rx, {\n    auto circuit = Circuit(R\"CIRCUIT(\n        RX 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n    )CIRCUIT\");\n    FrameSimulator<W> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, 1024, INDEPENDENT_TEST_RNG());\n    sim.reset_all();\n    sim.do_circuit(circuit);\n    auto x0 = sim.obs_record[0].popcnt();\n    auto y0 = sim.obs_record[1].popcnt();\n    auto z0 = sim.obs_record[2].popcnt();\n    ASSERT_EQ(y0, z0);\n    ASSERT_GT(y0, 300);\n    ASSERT_LT(y0, 700);\n    ASSERT_EQ(x0, 0);\n})\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator_pybind_test.py",
    "content": "import collections\n\nimport pytest\nimport stim\nimport numpy as np\n\n\ndef test_get_measurement_flips():\n    s = stim.FlipSimulator(batch_size=11)\n    assert s.num_measurements == 0\n    assert s.num_qubits == 0\n    assert s.batch_size == 11\n\n    s.do(stim.Circuit(\"\"\"\n        X_ERROR(1) 100\n        M 100\n    \"\"\"))\n    assert s.num_measurements == 1\n    assert s.num_qubits == 101\n    assert s.batch_size == 11\n\n    m = s.get_measurement_flips(record_index=0)\n    np.testing.assert_array_equal(m, [True] * 11)\n    assert s.num_measurements == 1\n    assert s.num_qubits == 101\n    assert s.batch_size == 11\n\n\ndef test_stabilizer_randomization():\n    s = stim.FlipSimulator(\n        batch_size=256,\n        num_qubits=10,\n        disable_stabilizer_randomization=True,\n    )\n    assert s.peek_pauli_flips() == [stim.PauliString(10)] * 256\n    s.do(stim.Circuit(\"R 19\"))\n    assert s.peek_pauli_flips() == [stim.PauliString(20)] * 256\n\n    s = stim.FlipSimulator(\n        batch_size=256,\n        num_qubits=10,\n    )\n    v = np.array([list(p) for p in s.peek_pauli_flips()], dtype=np.uint8)\n    assert v.shape == (256, 10)\n    assert np.all((v == 0) | (v == 3))\n    assert 0.2 < np.count_nonzero(v == 3) / (256 * 10) < 0.8\n\n    s = stim.FlipSimulator(\n        batch_size=256,\n        num_qubits=10,\n        disable_stabilizer_randomization=False,\n    )\n    v = np.array([list(p) for p in s.peek_pauli_flips()], dtype=np.uint8)\n    assert v.shape == (256, 10)\n    assert np.all((v == 0) | (v == 3))\n    assert 0.2 < np.count_nonzero(v == 3) / (256 * 10) < 0.8\n    s.do(stim.Circuit(\"R 19\"))\n    v = np.array([list(p) for p in s.peek_pauli_flips()], dtype=np.uint8)\n    assert v.shape == (256, 20)\n    assert np.all((v == 0) | (v == 3))\n    assert 0.2 < np.count_nonzero(v == 3) / (256 * 20) < 0.8\n\n\ndef test_get_detector_flips():\n    s = stim.FlipSimulator(batch_size=11)\n    assert s.num_measurements == 0\n    assert s.num_qubits == 0\n    assert s.batch_size == 11\n\n    s.do(stim.Circuit(\"\"\"\n        X_ERROR(1) 25\n        M 24 25\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n    \"\"\"))\n    assert s.num_measurements == 2\n    assert s.num_detectors == 3\n    assert s.num_qubits == 26\n    assert s.batch_size == 11\n    np.testing.assert_array_equal(\n        s.get_detector_flips(),\n        np.ones(shape=(3, 11), dtype=np.bool_))\n    np.testing.assert_array_equal(\n        s.get_detector_flips(detector_index=1),\n        np.ones(shape=(11,), dtype=np.bool_))\n    np.testing.assert_array_equal(\n        s.get_detector_flips(instance_index=1),\n        np.ones(shape=(3,), dtype=np.bool_))\n    assert s.get_detector_flips(detector_index=1, instance_index=1)\n\n\ndef test_get_observable_flips():\n    s = stim.FlipSimulator(batch_size=11)\n    assert s.num_measurements == 0\n    assert s.num_qubits == 0\n    assert s.batch_size == 11\n    assert s.num_observables == 0\n\n    s.do(stim.Circuit(\"\"\"\n        X_ERROR(1) 25\n        M 24 25\n        OBSERVABLE_INCLUDE(2) rec[-1]\n    \"\"\"))\n    assert s.num_measurements == 2\n    assert s.num_detectors == 0\n    assert s.num_observables == 3\n    assert s.num_qubits == 26\n    assert s.batch_size == 11\n    np.testing.assert_array_equal(\n        s.get_observable_flips(observable_index=1),\n        np.zeros(shape=(11,), dtype=np.bool_))\n    np.testing.assert_array_equal(\n        s.get_observable_flips(observable_index=2),\n        np.ones(shape=(11,), dtype=np.bool_))\n    np.testing.assert_array_equal(\n        s.get_observable_flips(instance_index=1),\n        [False, False, True])\n    assert not s.get_observable_flips(observable_index=1, instance_index=1)\n    assert s.get_observable_flips(observable_index=2, instance_index=1)\n\n\ndef test_peek_pauli_flips():\n    sim = stim.FlipSimulator(batch_size=500, disable_stabilizer_randomization=True)\n    sim.do(stim.Circuit(\"\"\"\n        X_ERROR(0.3) 1\n        Y_ERROR(0.3) 2\n        Z_ERROR(0.3) 3\n        DEPOLARIZE1(0.3) 4\n    \"\"\"))\n    assert sim.num_qubits == 5\n    assert sim.batch_size == 500\n    flips = sim.peek_pauli_flips()\n    assert len(flips) == 500\n    assert len(flips[0]) == 5\n    v0 = collections.Counter([p[0] for p in flips])\n    v1 = collections.Counter([p[1] for p in flips])\n    v2 = collections.Counter([p[2] for p in flips])\n    v3 = collections.Counter([p[3] for p in flips])\n    v4 = collections.Counter([p[4] for p in flips])\n    assert v0.keys() == {0}\n    assert v1.keys() == {0, 1}\n    assert v2.keys() == {0, 2}\n    assert v3.keys() == {0, 3}\n    assert v4.keys() == {0, 1, 2, 3}\n    assert v0[0] == 500\n    assert 250 < v1[0] < 450\n    assert 250 < v2[0] < 450\n    assert 250 < v3[0] < 450\n    assert 250 < v4[0] < 450\n\n\ndef test_set_pauli_flip():\n    sim = stim.FlipSimulator(\n        batch_size=2,\n        disable_stabilizer_randomization=True,\n        num_qubits=3,\n    )\n    assert sim.peek_pauli_flips() == [\n        stim.PauliString('___'),\n        stim.PauliString('___'),\n    ]\n\n    sim.set_pauli_flip('X', qubit_index=2, instance_index=0)\n    assert sim.peek_pauli_flips() == [\n        stim.PauliString('__X'),\n        stim.PauliString('___'),\n    ]\n\n    sim.set_pauli_flip(3, qubit_index=1, instance_index=1)\n    assert sim.peek_pauli_flips() == [\n        stim.PauliString('__X'),\n        stim.PauliString('_Z_'),\n    ]\n\n    sim.set_pauli_flip(2, qubit_index=0, instance_index=1)\n    assert sim.peek_pauli_flips() == [\n        stim.PauliString('__X'),\n        stim.PauliString('YZ_'),\n    ]\n\n    sim.set_pauli_flip(1, qubit_index=0, instance_index=-1)\n    assert sim.peek_pauli_flips() == [\n        stim.PauliString('__X'),\n        stim.PauliString('XZ_'),\n    ]\n\n    sim.set_pauli_flip(0, qubit_index=2, instance_index=-2)\n    assert sim.peek_pauli_flips() == [\n        stim.PauliString('___'),\n        stim.PauliString('XZ_'),\n    ]\n\n    with pytest.raises(ValueError, match='pauli'):\n        sim.set_pauli_flip(-1, qubit_index=0, instance_index=0)\n    with pytest.raises(ValueError, match='pauli'):\n        sim.set_pauli_flip(4, qubit_index=0, instance_index=0)\n    with pytest.raises(ValueError, match='pauli'):\n        sim.set_pauli_flip('R', qubit_index=0, instance_index=0)\n    with pytest.raises(ValueError, match='pauli'):\n        sim.set_pauli_flip('XY', qubit_index=0, instance_index=0)\n    with pytest.raises(ValueError, match='pauli'):\n        sim.set_pauli_flip(object(), qubit_index=0, instance_index=0)\n\n    with pytest.raises(IndexError, match='instance_index'):\n        sim.set_pauli_flip('X', qubit_index=0, instance_index=-3)\n    with pytest.raises(IndexError, match='instance_index'):\n        sim.set_pauli_flip('X', qubit_index=0, instance_index=3)\n\n    with pytest.raises(IndexError, match='qubit_index'):\n        sim.set_pauli_flip('X', qubit_index=-1, instance_index=0)\n\n    sim.set_pauli_flip('X', qubit_index=4, instance_index=0)\n    assert sim.peek_pauli_flips() == [\n        stim.PauliString('____X'),\n        stim.PauliString('XZ___'),\n    ]\n\ndef test_broadcast_pauli_errors():\n    sim = stim.FlipSimulator(\n        batch_size=2,\n        num_qubits=3,\n        disable_stabilizer_randomization=True,\n    )\n    sim.broadcast_pauli_errors(\n        pauli='X',\n        mask=np.asarray([\n            [True, False],\n            [False, False],\n            [True, True]]\n        ),\n    )\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+X_X\"),\n        stim.PauliString(\"+__X\")\n    ]\n    sim.broadcast_pauli_errors(\n        pauli='Z',\n        mask=np.asarray([\n            [True, True],\n            [True, False],\n            [False, False]]\n        ),\n    )\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+YZX\"),\n        stim.PauliString(\"+Z_X\")\n    ]\n    sim.broadcast_pauli_errors(\n        pauli='Y',\n        mask=np.asarray([\n            [True, False],\n            [False, True],\n            [False, True]]\n        ),\n    )\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+_ZX\"),\n        stim.PauliString(\"+ZYZ\")\n    ]\n    sim.broadcast_pauli_errors(\n        pauli='I',\n        mask=np.asarray([\n            [True, True],\n            [False, True],\n            [True, True]]\n        ),\n    )\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+_ZX\"),\n        stim.PauliString(\"+ZYZ\")\n    ]\n\n    # do it again with ints\n    sim = stim.FlipSimulator(\n        batch_size=2,\n        num_qubits=3,\n        disable_stabilizer_randomization=True,\n    )\n    sim.broadcast_pauli_errors(\n        pauli=1,\n        mask=np.asarray([\n            [True, False],\n            [False, False],\n            [True, True]]\n        ),\n    )\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+X_X\"),\n        stim.PauliString(\"+__X\")\n    ]\n    sim.broadcast_pauli_errors(\n        pauli=3,\n        mask=np.asarray([\n            [True, True],\n            [True, False],\n            [False, False]]\n        ),\n    )\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+YZX\"),\n        stim.PauliString(\"+Z_X\")\n    ]\n    sim.broadcast_pauli_errors(\n        pauli=2,\n        mask=np.asarray([\n            [True, False],\n            [False, True],\n            [False, True]]\n        ),\n    )\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+_ZX\"),\n        stim.PauliString(\"+ZYZ\")\n    ]\n    sim.broadcast_pauli_errors(\n        pauli=0,\n        mask=np.asarray([\n            [True, True],\n            [False, True],\n            [True, True]]\n        ),\n    )\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+_ZX\"),\n        stim.PauliString(\"+ZYZ\")\n    ]\n\n    with pytest.raises(ValueError, match='pauli'):\n        sim.broadcast_pauli_errors(\n            pauli='whoops',\n            mask=np.asarray([\n                [True, True],\n                [False, True],\n                [True, True]]\n            ),\n        )\n    with pytest.raises(ValueError, match='pauli'):\n        sim.broadcast_pauli_errors(\n            pauli=4,\n            mask=np.asarray([\n                [True, True],\n                [False, True],\n                [True, True]]\n            ),\n        )\n    with pytest.raises(ValueError, match='batch_size'):\n        sim.broadcast_pauli_errors(\n            pauli='X',\n            mask=np.asarray([\n                [True, True,True],\n                [False, True, True],\n                [True, True, True]]\n            ),\n        )\n    with pytest.raises(ValueError, match='batch_size'):\n        sim.broadcast_pauli_errors(\n            pauli='X',\n            mask=np.asarray([\n                [True],\n                [False],\n                [True]]\n            ),\n        )\n    sim = stim.FlipSimulator(\n        batch_size=2,\n        num_qubits=3,\n        disable_stabilizer_randomization=True,\n    )\n    sim.broadcast_pauli_errors(\n        pauli='X',\n        mask=np.asarray([\n            [True, False],\n            [False, False],\n            [True, True],\n            [True, True]]\n        ),\n    ) # automatically expands the qubit basis\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+X_XX\"),\n        stim.PauliString(\"+__XX\")\n    ]\n    sim.broadcast_pauli_errors(\n        pauli='X',\n        mask=np.asarray([\n            [True, False],\n            [False, False],\n            ]\n        ),\n    )  # tolerates fewer qubits in mask than in simulator\n    peek = sim.peek_pauli_flips()\n    assert peek == [\n        stim.PauliString(\"+__XX\"),\n        stim.PauliString(\"+__XX\")\n    ]\n\n\ndef test_repro_heralded_pauli_channel_1_bug():\n    circuit = stim.Circuit(\"\"\"\n        R 0 1\n        HERALDED_PAULI_CHANNEL_1(0.2, 0.2, 0, 0) 1\n        M 0\n    \"\"\")\n    result = circuit.compile_sampler().sample(1024)\n    assert np.sum(result[:, 0]) > 0\n    assert np.sum(result[:, 1]) == 0\n\n\ndef test_to_numpy():\n    sim = stim.FlipSimulator(batch_size=50)\n    sim.do(stim.Circuit.generated(\n        \"surface_code:rotated_memory_x\",\n        distance=5,\n        rounds=3,\n        after_clifford_depolarization=0.1,\n    ))\n\n    xs0, zs0, ms0, ds0, os0 = sim.to_numpy(\n        output_xs=True,\n        output_zs=True,\n        output_measure_flips=True,\n        output_detector_flips=True,\n        output_observable_flips=True,\n    )\n    for k in range(50):\n        np.testing.assert_array_equal(xs0[:, k], sim.peek_pauli_flips()[k].to_numpy()[0])\n        np.testing.assert_array_equal(zs0[:, k], sim.peek_pauli_flips()[k].to_numpy()[1])\n        np.testing.assert_array_equal(ms0[:, k], sim.get_measurement_flips(instance_index=k))\n        np.testing.assert_array_equal(ds0[:, k], sim.get_detector_flips(instance_index=k))\n        np.testing.assert_array_equal(os0[:, k], sim.get_observable_flips(instance_index=k))\n\n    xs, zs, ms, ds, os = sim.to_numpy(output_xs=True)\n    np.testing.assert_array_equal(xs, xs0)\n    assert zs is None\n    assert ms is None\n    assert ds is None\n    assert os is None\n\n    xs, zs, ms, ds, os = sim.to_numpy(output_zs=True)\n    assert xs is None\n    np.testing.assert_array_equal(zs, zs0)\n    assert ms is None\n    assert ds is None\n    assert os is None\n\n    xs, zs, ms, ds, os = sim.to_numpy(output_measure_flips=True)\n    assert xs is None\n    assert zs is None\n    np.testing.assert_array_equal(ms, ms0)\n    assert ds is None\n    assert os is None\n\n    xs, zs, ms, ds, os = sim.to_numpy(output_detector_flips=True)\n    assert xs is None\n    assert zs is None\n    assert ms is None\n    np.testing.assert_array_equal(ds, ds0)\n    assert os is None\n\n    xs, zs, ms, ds, os = sim.to_numpy(output_observable_flips=True)\n    assert xs is None\n    assert zs is None\n    assert ms is None\n    assert ds is None\n    np.testing.assert_array_equal(os, os0)\n\n    xs1 = np.empty_like(xs0)\n    zs1 = np.empty_like(zs0)\n    ms1 = np.empty_like(ms0)\n    ds1 = np.empty_like(ds0)\n    os1 = np.empty_like(os0)\n    xs2, zs2, ms2, ds2, os2 = sim.to_numpy(\n        output_xs=xs1,\n        output_zs=zs1,\n        output_measure_flips=ms1,\n        output_detector_flips=ds1,\n        output_observable_flips=os1,\n    )\n    assert xs1 is xs2\n    assert zs1 is zs2\n    assert ms1 is ms2\n    assert ds1 is ds2\n    assert os1 is os2\n    np.testing.assert_array_equal(xs1, xs0)\n    np.testing.assert_array_equal(zs1, zs0)\n    np.testing.assert_array_equal(ms1, ms0)\n    np.testing.assert_array_equal(ds1, ds0)\n    np.testing.assert_array_equal(os1, os0)\n\n    xs2, zs2, ms2, ds2, os2 = sim.to_numpy(\n        transpose=True,\n        output_xs=True,\n        output_zs=True,\n        output_measure_flips=True,\n        output_detector_flips=True,\n        output_observable_flips=True,\n    )\n    np.testing.assert_array_equal(xs2, np.transpose(xs0))\n    np.testing.assert_array_equal(zs2, np.transpose(zs0))\n    np.testing.assert_array_equal(ms2, np.transpose(ms0))\n    np.testing.assert_array_equal(ds2, np.transpose(ds0))\n    np.testing.assert_array_equal(os2, np.transpose(os0))\n\n    xs2, zs2, ms2, ds2, os2 = sim.to_numpy(\n        bit_packed=True,\n        output_xs=True,\n        output_zs=True,\n        output_measure_flips=True,\n        output_detector_flips=True,\n        output_observable_flips=True,\n    )\n    np.testing.assert_array_equal(xs2, np.packbits(xs0, axis=1, bitorder='little'))\n    np.testing.assert_array_equal(zs2, np.packbits(zs0, axis=1, bitorder='little'))\n    np.testing.assert_array_equal(ms2, np.packbits(ms0, axis=1, bitorder='little'))\n    np.testing.assert_array_equal(ds2, np.packbits(ds0, axis=1, bitorder='little'))\n    np.testing.assert_array_equal(os2, np.packbits(os0, axis=1, bitorder='little'))\n\n    xs2, zs2, ms2, ds2, os2 = sim.to_numpy(\n        transpose=True,\n        bit_packed=True,\n        output_xs=True,\n        output_zs=True,\n        output_measure_flips=True,\n        output_detector_flips=True,\n        output_observable_flips=True,\n    )\n    np.testing.assert_array_equal(xs2, np.packbits(np.transpose(xs0), axis=1, bitorder='little'))\n    np.testing.assert_array_equal(zs2, np.packbits(np.transpose(zs0), axis=1, bitorder='little'))\n    np.testing.assert_array_equal(ms2, np.packbits(np.transpose(ms0), axis=1, bitorder='little'))\n    np.testing.assert_array_equal(ds2, np.packbits(np.transpose(ds0), axis=1, bitorder='little'))\n    np.testing.assert_array_equal(os2, np.packbits(np.transpose(os0), axis=1, bitorder='little'))\n\n    with pytest.raises(ValueError, match=\"at least one output\"):\n        sim.to_numpy()\n    with pytest.raises(ValueError, match=\"shape=\"):\n        sim.to_numpy(output_xs=np.empty(shape=(0, 0), dtype=np.uint64))\n    with pytest.raises(ValueError, match=\"shape=\"):\n        sim.to_numpy(output_zs=np.empty(shape=(0, 0), dtype=np.uint64))\n    with pytest.raises(ValueError, match=\"shape=\"):\n        sim.to_numpy(output_measure_flips=np.empty(shape=(0, 0), dtype=np.uint64))\n    with pytest.raises(ValueError, match=\"shape=\"):\n        sim.to_numpy(output_detector_flips=np.empty(shape=(0, 0), dtype=np.uint64))\n    with pytest.raises(ValueError, match=\"shape=\"):\n        sim.to_numpy(output_observable_flips=np.empty(shape=(0, 0), dtype=np.uint64))\n\n\ndef test_generate_bernoulli_samples():\n    sim = stim.FlipSimulator(batch_size=10)\n\n    v = sim.generate_bernoulli_samples(1001, p=0, bit_packed=False)\n    assert v.shape == (1001,)\n    assert v.dtype == np.bool_\n    assert np.sum(v) == 0\n\n    v2 = sim.generate_bernoulli_samples(1001, p=1, bit_packed=False, out=v)\n    assert v is v2\n    assert v.shape == (1001,)\n    assert v.dtype == np.bool_\n    assert np.sum(v) == 1001\n\n    v = sim.generate_bernoulli_samples(2**16, p=0.25, bit_packed=False)\n    assert abs(np.sum(v) - 2**16*0.25) < 2**12\n\n    v = sim.generate_bernoulli_samples(1001, p=0, bit_packed=True)\n    assert v.shape == (126,)\n    assert v.dtype == np.uint8\n    assert np.sum(np.unpackbits(v, count=1001, bitorder='little')) == 0\n    assert np.sum(np.unpackbits(v, count=1008, bitorder='little')) == 0\n\n    v2 = sim.generate_bernoulli_samples(1001, p=1, bit_packed=True, out=v)\n    assert v is v2\n    assert v.shape == (126,)\n    assert v.dtype == np.uint8\n    assert np.sum(np.unpackbits(v, count=1001, bitorder='little')) == 1001\n    assert np.sum(np.unpackbits(v, count=1008, bitorder='little')) == 1001\n\n    v = sim.generate_bernoulli_samples(256, p=0, bit_packed=True)\n    assert np.all(v == 0)\n\n    sim.generate_bernoulli_samples(256 - 101, p=1, bit_packed=True, out=v[1:-11])\n    for k in v:\n        print(k)\n    assert np.all(v[1:-12] == 0xFF)\n    assert v[-12] == 7\n    assert np.all(v[-11:] == 0)\n    assert np.all(v[:1] == 0)\n\n    v = sim.generate_bernoulli_samples(2**16, p=0.25, bit_packed=True)\n    assert abs(np.sum(np.unpackbits(v, count=2**16)) - 2**16*0.25) < 2**12\n\n    v[:] = 0\n    sim.generate_bernoulli_samples(2**16 - 1, p=1, bit_packed=True, out=v)\n    assert np.all(v[:-1] == 0xFF)\n    assert v[-1] == 0x7F\n\n    v[:] = 0\n    sim.generate_bernoulli_samples(2**15, p=1, bit_packed=True, out=v[::2])\n    assert np.all(v[0::2] == 0xFF)\n    assert np.all(v[1::2] == 0)\n\n    v[:] = 0\n    sim.generate_bernoulli_samples(2**15 - 1, p=1, bit_packed=True, out=v[::2])\n    assert np.all(v[0::2][:-1] == 0xFF)\n    assert v[0::2][-1] == 0x7F\n    assert np.all(v[1::2] == 0)\n\n\ndef test_get_measurement_flips_negative_index():\n    sim = stim.FlipSimulator(batch_size=8, disable_stabilizer_randomization=True)\n    sim.do(stim.Circuit(\"\"\"\n        X_ERROR(1) 1\n        M 0 1\n    \"\"\"))\n    np.testing.assert_array_equal(sim.get_measurement_flips(record_index=-2), [False] * 8)\n    np.testing.assert_array_equal(sim.get_measurement_flips(record_index=-1), [True] * 8)\n    np.testing.assert_array_equal(sim.get_measurement_flips(record_index=0), [False] * 8)\n    np.testing.assert_array_equal(sim.get_measurement_flips(record_index=1), [True] * 8)\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator_util.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_DETECTION_SIMULATOR_H\n#define _STIM_SIMULATORS_DETECTION_SIMULATOR_H\n\n#include <random>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/mem/simd_bit_table.h\"\n\nnamespace stim {\n\n/// A convenience method for batch sampling detection events from a circuit.\n///\n/// Uses the frame simulator.\n///\n/// This method is intentionally inefficient to make it easier to use. In particular, it\n/// assumes the circuit is small enough that it's reasonable to simply store the\n/// detection event data of all samples in memory simultaneously. It also assumes that it's\n/// acceptable to recreate a fresh FrameSimulator with all its various buffers each time the\n/// method is called.\n///\n/// Args:\n///     circuit: The circuit to sample.\n///     num_shots: The number of samples to take.\n///     rng: Random number generator to use.\n///\n/// Returns:\n///     A pair of simd_bit_tables. The first is the detection event data. The second is the\n///     observable data. Each table is arranged as follows:\n///         major axis (first index): detector index (or observable index)\n///         minor axis (second index): shot index\ntemplate <size_t W>\nstd::pair<simd_bit_table<W>, simd_bit_table<W>> sample_batch_detection_events(\n    const Circuit &circuit, size_t num_shots, std::mt19937_64 &rng);\n\n/// Samples detection events from a circuit and writes them to a file.\n///\n/// Uses the frame simulator.\n///\n/// Args:\n///     circuit: The circuit to sample.\n///     num_shots: The number of samples to take.\n///     prepend_observables: Include the observables in the output, before the detectors.\n///     append_observables: Include the observables in the output, after the detectors.\n///     out: The file to write the result data to.\n///     format: The format to use when encoding the data into the file.\n///     rng: Random number generator to use.\n///     obs_out: An optional secondary file to write observable data to. Set to nullptr to\n///         not use.\n///     obs_out_format: The format to use when writing to the secondary file.\ntemplate <size_t W>\nvoid sample_batch_detection_events_writing_results_to_disk(\n    const Circuit &circuit,\n    size_t num_shots,\n    bool prepend_observables,\n    bool append_observables,\n    FILE *out,\n    SampleFormat format,\n    std::mt19937_64 &rng,\n    FILE *obs_out,\n    SampleFormat obs_out_format);\n\n/// A convenience method for batch sampling measurements from a circuit.\n///\n/// Uses the frame simulator.\n///\n/// This method is intentionally inefficient to make it easier to use. In particular, it\n/// assumes the circuit is small enough that it's reasonable to simply store the\n/// measurement of all samples in memory simultaneously. It also assumes that it's\n/// acceptable to recreate a fresh FrameSimulator with all its various buffers each time the\n/// method is called.\n///\n/// Args:\n///     circuit: The circuit to sample.\n///     num_shots: The number of samples to take.\n///     rng: Random number generator to use.\n///     transposed: Whether or not to exchange the axes of the resulting table.\n///\n/// Returns:\n///     A simd_bit_table containing the sampled measurement data.\n///     If not transposed:\n///         major axis (first index): measurement index\n///         minor axis (second index): shot index\n///     If transposed:\n///         major axis (first index): shot index\n///         minor axis (second index): measurement index\ntemplate <size_t W>\nsimd_bit_table<W> sample_batch_measurements(\n    const Circuit &circuit,\n    const simd_bits<W> &reference_sample,\n    size_t num_samples,\n    std::mt19937_64 &rng,\n    bool transposed);\n\n/// Samples measurements from a circuit and writes them to a file.\n///\n/// Uses the frame simulator.\n///\n/// Args:\n///     circuit: The circuit to sample.\n///     num_shots: The number of samples to take.\n///     reference_sample: A noiseless sample from the circuit, acquired via other means\n///         (for example, via TableauSimulator::reference_sample_circuit).\n///     out: The file to write the result data to.\n///     format: The format to use when encoding the data into the file.\n///     rng: Random number generator to use.\ntemplate <size_t W>\nvoid sample_batch_measurements_writing_results_to_disk(\n    const Circuit &circuit,\n    const simd_bits<W> &reference_sample,\n    uint64_t num_shots,\n    FILE *out,\n    SampleFormat format,\n    std::mt19937_64 &rng);\n\n}  // namespace stim\n\n#include \"stim/simulators/frame_simulator_util.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator_util.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/force_streaming.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nstd::pair<simd_bit_table<W>, simd_bit_table<W>> sample_batch_detection_events(\n    const Circuit &circuit, size_t num_shots, std::mt19937_64 &rng) {\n    FrameSimulator<W> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY, num_shots, std::move(rng));\n    sim.reset_all();\n    sim.do_circuit(circuit);\n    rng = std::move(\n        sim.rng);  // Update input rng as if it was used directly, by moving the updated state out of the simulator.\n\n    return std::pair<simd_bit_table<W>, simd_bit_table<W>>{\n        std::move(sim.det_record.storage),\n        std::move(sim.obs_record),\n    };\n}\n\ntemplate <size_t W>\nvoid rerun_frame_sim_while_streaming_dets_to_disk(\n    const Circuit &circuit,\n    CircuitStats circuit_stats,\n    FrameSimulator<W> &sim,\n    size_t num_shots,\n    bool prepend_observables,\n    bool append_observables,\n    FILE *out,\n    SampleFormat format,\n    FILE *obs_out,\n    SampleFormat obs_out_format) {\n    if (prepend_observables) {\n        throw std::invalid_argument(\n            \"--prepend_observables isn't supported when sampling circuits so large that they require streaming the \"\n            \"results\");\n    }\n\n    MeasureRecordBatchWriter writer(out, num_shots, format);\n    std::vector<simd_bits<W>> observables;\n    sim.reset_all();\n    writer.begin_result_type('D');\n    circuit.for_each_operation([&](const CircuitInstruction &op) {\n        sim.do_gate(op);\n        sim.m_record.mark_all_as_written();\n        if (op.gate_type == GateType::DETECTOR) {\n            constexpr size_t WRITE_SIZE = 256;\n            if (sim.det_record.unwritten >= WRITE_SIZE) {\n                assert(sim.det_record.stored == WRITE_SIZE);\n                assert(sim.det_record.unwritten == WRITE_SIZE);\n                writer.batch_write_bytes<W>(sim.det_record.storage, WRITE_SIZE >> 6);\n                sim.det_record.clear();\n            }\n        }\n    });\n    for (size_t k = sim.det_record.stored - sim.det_record.unwritten; k < sim.det_record.stored; k++) {\n        writer.batch_write_bit<W>(sim.det_record.storage[k]);\n    }\n    if (append_observables) {\n        writer.begin_result_type('L');\n        for (size_t k = 0; k < circuit_stats.num_observables; k++) {\n            writer.batch_write_bit<W>(sim.obs_record[k]);\n        }\n    }\n    writer.write_end();\n\n    if (obs_out != nullptr) {\n        write_table_data(\n            obs_out,\n            num_shots,\n            circuit_stats.num_observables,\n            simd_bits<W>(0),\n            sim.obs_record,\n            obs_out_format,\n            'L',\n            'L',\n            circuit_stats.num_observables);\n    }\n}\n\ntemplate <size_t W>\nvoid rerun_frame_sim_while_streaming_measurements_to_disk(\n    const Circuit &circuit,\n    FrameSimulator<W> &sim,\n    const simd_bits<W> &reference_sample,\n    size_t num_shots,\n    FILE *out,\n    SampleFormat format) {\n    MeasureRecordBatchWriter writer(out, num_shots, format);\n    sim.reset_all();\n    circuit.for_each_operation([&](const CircuitInstruction &op) {\n        sim.do_gate(op);\n        sim.m_record.intermediate_write_unwritten_results_to(writer, reference_sample);\n    });\n    sim.m_record.final_write_unwritten_results_to(writer, reference_sample);\n}\n\ntemplate <size_t W>\nvoid rerun_frame_sim_in_memory_and_write_dets_to_disk(\n    const Circuit &circuit,\n    const CircuitStats &circuit_stats,\n    FrameSimulator<W> &frame_sim,\n    simd_bit_table<W> &out_concat_buf,\n    size_t num_shots,\n    bool prepend_observables,\n    bool append_observables,\n    FILE *out,\n    SampleFormat format,\n    FILE *obs_out,\n    SampleFormat obs_out_format) {\n    if (prepend_observables + append_observables + (obs_out != nullptr) > 1) {\n        throw std::out_of_range(\"Can't combine --prepend_observables, --append_observables, or --obs_out\");\n    }\n\n    frame_sim.reset_all();\n    frame_sim.do_circuit(circuit);\n\n    const auto &obs_data = frame_sim.obs_record;\n    const auto &det_data = frame_sim.det_record.storage;\n    if (obs_out != nullptr) {\n        write_table_data(\n            obs_out,\n            num_shots,\n            circuit_stats.num_observables,\n            simd_bits<W>(0),\n            frame_sim.obs_record,\n            obs_out_format,\n            'L',\n            'L',\n            circuit_stats.num_observables);\n    }\n\n    if (prepend_observables || append_observables) {\n        if (prepend_observables) {\n            assert(!append_observables);\n            out_concat_buf.overwrite_major_range_with(\n                circuit_stats.num_observables, det_data, 0, circuit_stats.num_detectors);\n            out_concat_buf.overwrite_major_range_with(0, obs_data, 0, circuit_stats.num_observables);\n        } else {\n            assert(append_observables);\n            out_concat_buf.overwrite_major_range_with(0, det_data, 0, circuit_stats.num_detectors);\n            out_concat_buf.overwrite_major_range_with(\n                circuit_stats.num_detectors, obs_data, 0, circuit_stats.num_observables);\n        }\n\n        char c1 = append_observables ? 'D' : 'L';\n        char c2 = append_observables ? 'L' : 'D';\n        size_t ct = append_observables ? circuit_stats.num_detectors : circuit_stats.num_observables;\n        write_table_data(\n            out,\n            num_shots,\n            circuit_stats.num_observables + circuit_stats.num_detectors,\n            simd_bits<W>(0),\n            out_concat_buf,\n            format,\n            c1,\n            c2,\n            ct);\n    } else {\n        write_table_data(\n            out,\n            num_shots,\n            circuit_stats.num_detectors,\n            simd_bits<W>(0),\n            det_data,\n            format,\n            'D',\n            'L',\n            circuit_stats.num_detectors);\n    }\n}\n\ntemplate <size_t W>\nvoid rerun_frame_sim_in_memory_and_write_measurements_to_disk(\n    const Circuit &circuit,\n    CircuitStats circuit_stats,\n    FrameSimulator<W> &frame_sim,\n    const simd_bits<W> &reference_sample,\n    size_t num_shots,\n    FILE *out,\n    SampleFormat format) {\n    frame_sim.reset_all();\n    frame_sim.do_circuit(circuit);\n    const auto &measure_data = frame_sim.m_record.storage;\n\n    write_table_data(\n        out, num_shots, circuit_stats.num_measurements, reference_sample, measure_data, format, 'M', 'M', 0);\n}\n\ntemplate <size_t W>\nvoid sample_batch_detection_events_writing_results_to_disk(\n    const Circuit &circuit,\n    size_t num_shots,\n    bool prepend_observables,\n    bool append_observables,\n    FILE *out,\n    SampleFormat format,\n    std::mt19937_64 &rng,\n    FILE *obs_out,\n    SampleFormat obs_out_format) {\n    if (num_shots == 0) {\n        // Vacuously complete.\n        return;\n    }\n\n    auto stats = circuit.compute_stats();\n\n    // Pick a batch size that's not so large that it would cause memory issues.\n    size_t batch_size = 0;\n    while (batch_size < 1024 && batch_size < num_shots) {\n        batch_size += W;\n    }\n    uint64_t memory_per_full_shot =\n        2 * stats.num_qubits + 2 * stats.max_lookback + stats.num_observables + stats.num_detectors;\n    while (batch_size > 0 &&\n           should_use_streaming_because_bit_count_is_too_large_to_store(memory_per_full_shot * batch_size)) {\n        batch_size -= W;\n    }\n\n    // If the batch size ended up at 0, the results won't fit in memory. Need to stream.\n    bool streaming = batch_size == 0;\n    if (streaming) {\n        batch_size = W;\n    }\n\n    // Create a correctly sized frame simulator.\n    FrameSimulator<W> frame_sim(\n        stats,\n        streaming ? FrameSimulatorMode::STREAM_DETECTIONS_TO_DISK : FrameSimulatorMode::STORE_DETECTIONS_TO_MEMORY,\n        batch_size,\n        std::move(rng));  // Will copy rng state back out later.\n\n    // Run the frame simulator until as many shots as requested have been written.\n    simd_bit_table<W> out_concat_buf(0, 0);\n    if (append_observables || prepend_observables) {\n        out_concat_buf = simd_bit_table<W>(stats.num_detectors + stats.num_observables, batch_size);\n    }\n    size_t shots_left = num_shots;\n    while (shots_left) {\n        size_t shots_performed = std::min(shots_left, batch_size);\n        if (streaming) {\n            rerun_frame_sim_while_streaming_dets_to_disk(\n                circuit,\n                stats,\n                frame_sim,\n                shots_performed,\n                prepend_observables,\n                append_observables,\n                out,\n                format,\n                obs_out,\n                obs_out_format);\n        } else {\n            rerun_frame_sim_in_memory_and_write_dets_to_disk(\n                circuit,\n                stats,\n                frame_sim,\n                out_concat_buf,\n                shots_performed,\n                prepend_observables,\n                append_observables,\n                out,\n                format,\n                obs_out,\n                obs_out_format);\n        }\n        shots_left -= shots_performed;\n    }\n\n    // Update input rng as if it was used directly, by moving the updated state out of the simulator.\n    rng = std::move(frame_sim.rng);\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> sample_batch_measurements(\n    const Circuit &circuit,\n    const simd_bits<W> &reference_sample,\n    size_t num_samples,\n    std::mt19937_64 &rng,\n    bool transposed) {\n    FrameSimulator<W> sim(\n        circuit.compute_stats(), FrameSimulatorMode::STORE_MEASUREMENTS_TO_MEMORY, num_samples, std::move(rng));\n    sim.reset_all();\n    sim.do_circuit(circuit);\n    simd_bit_table<W> result = std::move(sim.m_record.storage);\n    rng = std::move(\n        sim.rng);  // Update input rng as if it was used directly, by moving the updated state out of the simulator.\n\n    if (reference_sample.not_zero()) {\n        result = transposed_vs_ref(num_samples, result, reference_sample);\n        transposed = !transposed;\n    }\n\n    if (transposed) {\n        result = result.transposed();\n    }\n\n    return result;\n}\n\ntemplate <size_t W>\nvoid sample_batch_measurements_writing_results_to_disk(\n    const Circuit &circuit,\n    const simd_bits<W> &reference_sample,\n    uint64_t num_shots,\n    FILE *out,\n    SampleFormat format,\n    std::mt19937_64 &rng) {\n    if (num_shots == 0) {\n        // Vacuously complete.\n        return;\n    }\n\n    auto stats = circuit.compute_stats();\n\n    // Pick a batch size that's not so large that it would cause memory issues.\n    size_t batch_size = 0;\n    while (batch_size < 1024 && batch_size < num_shots) {\n        batch_size += W;\n    }\n    uint64_t memory_per_full_shot = 2 * stats.num_qubits + stats.num_measurements;\n    while (batch_size > 0 &&\n           should_use_streaming_because_bit_count_is_too_large_to_store(memory_per_full_shot * batch_size)) {\n        batch_size -= W;\n    }\n\n    // If the batch size ended up at 0, the results won't fit in memory. Need to stream.\n    bool streaming = batch_size == 0;\n    if (streaming) {\n        batch_size = W;\n    }\n\n    // Create a correctly sized frame simulator.\n    FrameSimulator<W> frame_sim(\n        circuit.compute_stats(),\n        streaming ? FrameSimulatorMode::STREAM_MEASUREMENTS_TO_DISK : FrameSimulatorMode::STORE_MEASUREMENTS_TO_MEMORY,\n        batch_size,\n        std::move(rng));  // Temporarily move rng into simulator.\n\n    // Run the frame simulator until as many shots as requested have been written.\n    size_t shots_left = num_shots;\n    while (shots_left) {\n        size_t shots_performed = std::min(shots_left, batch_size);\n        if (streaming) {\n            rerun_frame_sim_while_streaming_measurements_to_disk(\n                circuit, frame_sim, reference_sample, shots_performed, out, format);\n        } else {\n            rerun_frame_sim_in_memory_and_write_measurements_to_disk(\n                circuit, stats, frame_sim, reference_sample, shots_performed, out, format);\n        }\n        shots_left -= shots_performed;\n    }\n\n    // Update input rng as if it was used directly, by moving the updated state out of the simulator.\n    rng = std::move(frame_sim.rng);\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/simulators/frame_simulator_util.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/frame_simulator_util.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\ntemplate <size_t W>\nsimd_bit_table<W> sample_test_detection_events(const Circuit &circuit, size_t num_shots) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    return sample_batch_detection_events<W>(circuit, num_shots, rng).first;\n}\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, sample_test_detection_events, {\n    auto circuit = Circuit(\n        \"X_ERROR(1) 0\\n\"\n        \"M 0\\n\"\n        \"DETECTOR rec[-1]\\n\");\n    auto samples = sample_test_detection_events<W>(circuit, 5);\n    ASSERT_EQ(\n        samples.str(5),\n        \"11111\\n\"\n        \".....\\n\"\n        \".....\\n\"\n        \".....\\n\"\n        \".....\");\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, bad_detector, {\n    ASSERT_THROW({ sample_test_detection_events<W>(Circuit(\"rec[-1]\"), 5); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, sample_batch_detection_events_writing_results_to_disk, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(R\"circuit(\n        X_ERROR(1) 0\n        M 0 1\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        OBSERVABLE_INCLUDE(4) rec[-2]\n    )circuit\");\n\n    FILE *tmp = tmpfile();\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit, 2, false, false, tmp, SampleFormat::SAMPLE_FORMAT_DETS, rng, nullptr, SampleFormat::SAMPLE_FORMAT_01);\n    ASSERT_EQ(rewind_read_close(tmp), \"shot D1\\nshot D1\\n\");\n\n    tmp = tmpfile();\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit, 2, true, false, tmp, SampleFormat::SAMPLE_FORMAT_DETS, rng, nullptr, SampleFormat::SAMPLE_FORMAT_01);\n    ASSERT_EQ(rewind_read_close(tmp), \"shot L4 D1\\nshot L4 D1\\n\");\n\n    tmp = tmpfile();\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit, 2, false, true, tmp, SampleFormat::SAMPLE_FORMAT_DETS, rng, nullptr, SampleFormat::SAMPLE_FORMAT_01);\n    ASSERT_EQ(rewind_read_close(tmp), \"shot D1 L4\\nshot D1 L4\\n\");\n\n    tmp = tmpfile();\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit, 2, false, true, tmp, SampleFormat::SAMPLE_FORMAT_HITS, rng, nullptr, SampleFormat::SAMPLE_FORMAT_01);\n    ASSERT_EQ(rewind_read_close(tmp), \"1,6\\n1,6\\n\");\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_many_shots, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    DebugForceResultStreamingRaii force_streaming;\n    auto circuit = Circuit(R\"circuit(\n        X_ERROR(1) 1\n        M 0 1 2\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n    )circuit\");\n    FILE *tmp = tmpfile();\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit, 2048, false, false, tmp, SampleFormat::SAMPLE_FORMAT_01, rng, nullptr, SampleFormat::SAMPLE_FORMAT_01);\n\n    auto result = rewind_read_close(tmp);\n    for (size_t k = 0; k < 2048 * 4; k += 4) {\n        ASSERT_EQ(result[k], '0') << k;\n        ASSERT_EQ(result[k + 1], '1') << (k + 1);\n        ASSERT_EQ(result[k + 2], '0') << (k + 2);\n        ASSERT_EQ(result[k + 3], '\\n') << (k + 3);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, block_results_single_shot, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(R\"circuit(\n        REPEAT 10000 {\n            M 0\n            X_ERROR(1) 0\n            M 0\n            R 0\n            DETECTOR rec[-1] rec[-2]\n            M 0\n            DETECTOR rec[-1]\n            DETECTOR rec[-1]\n        }\n    )circuit\");\n    FILE *tmp = tmpfile();\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit, 1, false, true, tmp, SampleFormat::SAMPLE_FORMAT_01, rng, nullptr, SampleFormat::SAMPLE_FORMAT_01);\n\n    auto result = rewind_read_close(tmp);\n    for (size_t k = 0; k < 30000; k += 3) {\n        ASSERT_EQ(result[k], '1') << k;\n        ASSERT_EQ(result[k + 1], '0') << (k + 1);\n        ASSERT_EQ(result[k + 2], '0') << (k + 2);\n    }\n    ASSERT_EQ(result[30000], '\\n');\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, block_results_triple_shot, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(R\"circuit(\n        REPEAT 10000 {\n            M 0\n            X_ERROR(1) 0\n            M 0\n            R 0\n            DETECTOR rec[-1] rec[-2]\n            M 0\n            DETECTOR rec[-1]\n            DETECTOR rec[-1]\n        }\n    )circuit\");\n    FILE *tmp = tmpfile();\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit, 3, false, true, tmp, SampleFormat::SAMPLE_FORMAT_01, rng, nullptr, SampleFormat::SAMPLE_FORMAT_01);\n\n    auto result = rewind_read_close(tmp);\n    for (size_t rep = 0; rep < 3; rep++) {\n        size_t s = rep * 30001;\n        for (size_t k = 0; k < 30000; k += 3) {\n            ASSERT_EQ(result[s + k], '1') << (s + k);\n            ASSERT_EQ(result[s + k + 1], '0') << (s + k + 1);\n            ASSERT_EQ(result[s + k + 2], '0') << (s + k + 2);\n        }\n        ASSERT_EQ(result[s + 30000], '\\n');\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_results, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    DebugForceResultStreamingRaii force_streaming;\n    auto circuit = Circuit(R\"circuit(\n        REPEAT 10000 {\n            M 0\n            X_ERROR(1) 0\n            M 0\n            R 0\n            DETECTOR rec[-1] rec[-2]\n            M 0\n            DETECTOR rec[-1]\n            DETECTOR rec[-1]\n        }\n    )circuit\");\n\n    RaiiTempNamedFile tmp;\n    FILE *f = fopen(tmp.path.c_str(), \"w\");\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit, 1, false, true, f, SampleFormat::SAMPLE_FORMAT_01, rng, nullptr, SampleFormat::SAMPLE_FORMAT_01);\n    fclose(f);\n\n    auto result = tmp.read_contents();\n    for (size_t k = 0; k < 30000; k += 3) {\n        ASSERT_EQ(result[k], '1') << k;\n        ASSERT_EQ(result[k + 1], '0') << (k + 1);\n        ASSERT_EQ(result[k + 2], '0') << (k + 2);\n    }\n    ASSERT_EQ(result[30000], '\\n');\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, stream_results_triple_shot, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    DebugForceResultStreamingRaii force_streaming;\n    auto circuit = Circuit(R\"circuit(\n        REPEAT 10000 {\n            M 0\n            X_ERROR(1) 0\n            M 0\n            R 0\n            DETECTOR rec[-1] rec[-2]\n            M 0\n            DETECTOR rec[-1]\n            DETECTOR rec[-1]\n        }\n    )circuit\");\n    FILE *tmp = tmpfile();\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit, 3, false, true, tmp, SampleFormat::SAMPLE_FORMAT_01, rng, nullptr, SampleFormat::SAMPLE_FORMAT_01);\n\n    auto result = rewind_read_close(tmp);\n    for (size_t rep = 0; rep < 3; rep++) {\n        size_t s = rep * 30001;\n        for (size_t k = 0; k < 30000; k += 3) {\n            ASSERT_EQ(result[s + k], '1') << (s + k);\n            ASSERT_EQ(result[s + k + 1], '0') << (s + k + 1);\n            ASSERT_EQ(result[s + k + 2], '0') << (s + k + 2);\n        }\n        ASSERT_EQ(result[s + 30000], '\\n');\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, noisy_measurement_x, {\n    auto r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RX 0\n        MX(0.05) 0\n        MX 0\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        10000);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RX 0 1\n        Z_ERROR(1) 0 1\n        MX(0.05) 0 1\n        MX 0 1\n        DETECTOR rec[-4]\n        DETECTOR rec[-3]\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        5000);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 5000);\n    ASSERT_EQ(r[3].popcnt(), 5000);\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, noisy_measurement_y, {\n    auto r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RY 0\n        MY(0.05) 0\n        MY 0\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        10000);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RY 0 1\n        Z_ERROR(1) 0 1\n        MY(0.05) 0 1\n        MY 0 1\n        DETECTOR rec[-4]\n        DETECTOR rec[-3]\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        5000);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 5000);\n    ASSERT_EQ(r[3].popcnt(), 5000);\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, noisy_measurement_z, {\n    auto r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RZ 0\n        MZ(0.05) 0\n        MZ 0\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        10000);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RZ 0 1\n        X_ERROR(1) 0 1\n        MZ(0.05) 0 1\n        MZ 0 1\n        DETECTOR rec[-4]\n        DETECTOR rec[-3]\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        5000);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 5000);\n    ASSERT_EQ(r[3].popcnt(), 5000);\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, noisy_measure_reset_x, {\n    auto r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RX 0\n        MRX(0.05) 0\n        MRX 0\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        10000);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RX 0 1\n        Z_ERROR(1) 0 1\n        MRX(0.05) 0 1\n        MRX 0 1\n        DETECTOR rec[-4]\n        DETECTOR rec[-3]\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        5000);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 0);\n    ASSERT_EQ(r[3].popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, noisy_measure_reset_y, {\n    auto r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RY 0\n        MRY(0.05) 0\n        MRY 0\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        10000);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RY 0 1\n        Z_ERROR(1) 0 1\n        MRY(0.05) 0 1\n        MRY 0 1\n        DETECTOR rec[-4]\n        DETECTOR rec[-3]\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        5000);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 0);\n    ASSERT_EQ(r[3].popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, noisy_measure_reset_z, {\n    auto r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RZ 0\n        MRZ(0.05) 0\n        MRZ 0\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        10000);\n    ASSERT_FALSE(r[1].not_zero());\n    auto m1 = r[0].popcnt();\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n\n    r = sample_test_detection_events<W>(\n        Circuit(R\"CIRCUIT(\n        RZ 0 1\n        X_ERROR(1) 0 1\n        MRZ(0.05) 0 1\n        MRZ 0 1\n        DETECTOR rec[-4]\n        DETECTOR rec[-3]\n        DETECTOR rec[-2]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        5000);\n    auto m2 = r[0].popcnt() + r[1].popcnt();\n    ASSERT_LT(m2, 10000 - 300);\n    ASSERT_GT(m2, 10000 - 700);\n    ASSERT_EQ(r[2].popcnt(), 0);\n    ASSERT_EQ(r[3].popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(DetectionSimulator, obs_data, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto circuit = Circuit(R\"circuit(\n        REPEAT 399 {\n            X_ERROR(1) 0\n            MR 0\n            DETECTOR rec[-1]\n        }\n        REPEAT 600 {\n            MR 0\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(0) rec[-1]\n        }\n        X_ERROR(1) 0\n        MR 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        OBSERVABLE_INCLUDE(1) rec[-1]\n        MR 0\n        OBSERVABLE_INCLUDE(2) rec[-1]\n    )circuit\");\n    FILE *det_tmp = tmpfile();\n    FILE *obs_tmp = tmpfile();\n    sample_batch_detection_events_writing_results_to_disk<W>(\n        circuit,\n        1001,\n        false,\n        false,\n        det_tmp,\n        SampleFormat::SAMPLE_FORMAT_B8,\n        rng,\n        obs_tmp,\n        SampleFormat::SAMPLE_FORMAT_B8);\n\n    auto det_saved = rewind_read_close(det_tmp);\n    auto obs_saved = rewind_read_close(obs_tmp);\n    ASSERT_EQ(det_saved.size(), 125 * 1001);\n    ASSERT_EQ(obs_saved.size(), 1 * 1001);\n    for (size_t k = 0; k < det_saved.size(); k++) {\n        for (size_t b = 0; b < 8; b++) {\n            size_t det_index = (k % 125) * 8 + b;\n            bool bit = (((uint8_t)det_saved[k]) >> b) & 1;\n            ASSERT_EQ(bit, det_index < 399) << k;\n        }\n    }\n    for (size_t k = 0; k < obs_saved.size(); k++) {\n        ASSERT_EQ(obs_saved[k], 0x3);\n    }\n})\n"
  },
  {
    "path": "src/stim/simulators/graph_simulator.cc",
    "content": "#include \"stim/simulators/graph_simulator.h\"\n\nusing namespace stim;\n\nGraphSimulator::GraphSimulator(size_t num_qubits)\n    : num_qubits(num_qubits), adj(num_qubits, num_qubits), paulis(num_qubits), x2outs(num_qubits), z2outs(num_qubits) {\n    for (size_t k = 0; k < num_qubits; k++) {\n        x2outs.zs[k] = 1;\n        z2outs.xs[k] = 1;\n    }\n}\n\nvoid GraphSimulator::do_1q_gate(GateType gate, size_t qubit) {\n    GateTarget t = GateTarget::qubit(qubit);\n    x2outs.ref().do_instruction(CircuitInstruction{gate, {}, &t, \"\"});\n    z2outs.ref().do_instruction(CircuitInstruction{gate, {}, &t, \"\"});\n    paulis.xs[qubit] ^= z2outs.sign;\n    paulis.zs[qubit] ^= x2outs.sign;\n    x2outs.sign = 0;\n    z2outs.sign = 0;\n}\n\nstd::tuple<bool, bool, bool> GraphSimulator::after2inside_basis_transform(size_t qubit, bool x, bool z) {\n    bool xx = x2outs.xs[qubit];\n    bool xz = x2outs.zs[qubit];\n    bool zx = z2outs.xs[qubit];\n    bool zz = z2outs.zs[qubit];\n    bool out_x = (x & zz) ^ (z & zx);\n    bool out_z = (x & xz) ^ (z & xx);\n    bool sign = false;\n    sign ^= paulis.xs[qubit] & out_z;\n    sign ^= paulis.zs[qubit] & out_x;\n    sign ^= out_x == out_z && !(xx ^ zz) && !(xx ^ xz ^ zx);\n    return {out_x, out_z, sign};\n}\n\nvoid GraphSimulator::inside_do_cz(size_t a, size_t b) {\n    adj[a][b] ^= 1;\n    adj[b][a] ^= 1;\n}\n\nvoid GraphSimulator::inside_do_cx(size_t c, size_t t) {\n    adj[c] ^= adj[t];\n    for (size_t k = 0; k < num_qubits; k++) {\n        adj[k][c] = adj[c][k];\n    }\n    paulis.zs[c] ^= adj[c][c];\n    adj[c][c] = 0;\n}\n\nvoid GraphSimulator::inside_do_sqrt_z(size_t q) {\n    bool x2x = x2outs.xs[q];\n    bool x2z = x2outs.zs[q];\n    bool z2x = z2outs.xs[q];\n    bool z2z = z2outs.zs[q];\n    paulis.zs[q] ^= paulis.xs[q];\n    paulis.zs[q] ^= !(x2x ^ z2z) && !(x2x ^ x2z ^ z2x);\n    x2outs.xs[q] ^= z2x;\n    x2outs.zs[q] ^= z2z;\n}\n\nvoid GraphSimulator::inside_do_sqrt_x_dag(size_t q) {\n    bool x2x = x2outs.xs[q];\n    bool x2z = x2outs.zs[q];\n    bool z2x = z2outs.xs[q];\n    bool z2z = z2outs.zs[q];\n    paulis.xs[q] ^= paulis.zs[q];\n    paulis.xs[q] ^= !(x2x ^ z2z) && !(x2x ^ x2z ^ z2x);\n    z2outs.xs[q] ^= x2x;\n    z2outs.zs[q] ^= x2z;\n}\n\nvoid GraphSimulator::inside_do_cy(size_t c, size_t t) {\n    inside_do_cz(c, t);\n    inside_do_cx(c, t);\n    inside_do_sqrt_z(c);\n}\n\nvoid GraphSimulator::verify_invariants() const {\n    // No self-adjacency.\n    for (size_t q = 0; q < num_qubits; q++) {\n        assert(!adj[q][q]);\n    }\n    // Undirected adjacency.\n    for (size_t q1 = 0; q1 < num_qubits; q1++) {\n        for (size_t q2 = q1 + 1; q2 < num_qubits; q2++) {\n            assert(adj[q1][q2] == adj[q2][q1]);\n        }\n    }\n    // Single qubits gates are clifford.\n    for (size_t q = 0; q < num_qubits; q++) {\n        assert(x2outs.xs[q] || x2outs.zs[q]);\n        assert(z2outs.xs[q] || z2outs.zs[q]);\n        assert((x2outs.xs[q] != z2outs.xs[q]) || (x2outs.zs[q] != z2outs.zs[q]));\n    }\n}\n\nvoid GraphSimulator::do_complementation(size_t q) {\n    buffer.clear();\n    for (size_t neighbor = 0; neighbor < num_qubits; neighbor++) {\n        if (adj[q][neighbor]) {\n            buffer.push_back(neighbor);\n            inside_do_sqrt_z(neighbor);\n        }\n    }\n    for (size_t k1 = 0; k1 < buffer.size(); k1++) {\n        for (size_t k2 = k1 + 1; k2 < buffer.size(); k2++) {\n            inside_do_cz(buffer[k1], buffer[k2]);\n        }\n    }\n    inside_do_sqrt_x_dag(q);\n}\n\nvoid GraphSimulator::inside_do_ycx(size_t q1, size_t q2) {\n    if (adj[q1][q2]) {\n        // Y:X -> SQRT_X(Y):SQRT_Z(X) = Z:Y\n        do_complementation(q1);\n        inside_do_cy(q1, q2);\n        paulis.zs[q1] ^= 1;\n    } else {\n        // Y:X -> SQRT_X(Y):Y = Z:X\n        do_complementation(q1);\n        inside_do_cx(q1, q2);\n    }\n}\n\nvoid GraphSimulator::inside_do_ycy(size_t q1, size_t q2) {\n    if (adj[q1][q2]) {\n        // Y:Y -> SQRT_X(Y):SQRT_Z(Y) = Z:X\n        do_complementation(q1);\n        inside_do_cx(q1, q2);\n    } else {\n        // Y:Y -> SQRT_X(Y):Y = Z:Y\n        do_complementation(q1);\n        inside_do_cy(q1, q2);\n    }\n}\n\nvoid GraphSimulator::inside_do_xcx(size_t q1, size_t q2) {\n    if (adj[q1][q2]) {\n        // X:X -> S(X):SQRT_X_DAG(X) = (-Y):X\n        do_complementation(q2);\n        // (-Y):X -> SQRT_X_DAG(-Y):S(X) = (-Z):(-Y)\n        do_complementation(q1);\n        inside_do_cy(q1, q2);\n        paulis.zs[q1] ^= 1;\n        paulis.xs[q2] ^= 1;\n        paulis.zs[q2] ^= 1;\n    } else {\n        // Need an S gate.\n        // Get it by finding a neighbor to do local complementation on.\n        for (size_t q3 = 0; q3 < num_qubits; q3++) {\n            if (adj[q1][q3]) {\n                do_complementation(q3);\n                if (adj[q2][q3]) {\n                    // X:X -> S(X):S(X) = (-Y):(-Y)\n                    paulis.xs[q1] ^= 1;\n                    paulis.zs[q1] ^= 1;\n                    paulis.xs[q2] ^= 1;\n                    paulis.zs[q2] ^= 1;\n                    inside_do_ycy(q1, q2);\n                } else {\n                    // X:X -> S(X):X = (-Y):X\n                    paulis.xs[q2] ^= 1;\n                    inside_do_ycx(q1, q2);\n                }\n                return;\n            }\n        }\n\n        // q1 has no CZ gates applied to it.\n        // Therefore, inside the single qubit gates, q1 is in the |+> state.\n        // Therefore the XCX gate's control isn't satisfied, and it does nothing.\n        // <-- look at all the doing-nothing right here. -->\n    }\n}\n\nvoid GraphSimulator::inside_do_pauli_interaction(bool x1, bool z1, bool x2, bool z2, size_t q1, size_t q2) {\n    int p1 = x1 + z1 * 2 - 1;\n    int p2 = x2 + z2 * 2 - 1;\n    switch (p1 + p2 * 3) {\n        case 0:  // X:X\n            inside_do_xcx(q1, q2);\n            break;\n        case 1:  // Z:X\n            inside_do_cx(q1, q2);\n            break;\n        case 2:  // Y:X\n            inside_do_ycx(q1, q2);\n            break;\n        case 3:  // X:Z\n            inside_do_cx(q2, q1);\n            break;\n        case 4:  // Z:Z\n            inside_do_cz(q1, q2);\n            break;\n        case 5:  // Y:Z\n            inside_do_cy(q2, q1);\n            break;\n        case 6:  // X:Y\n            inside_do_ycx(q2, q1);\n            break;\n        case 7:  // Z:Y\n            inside_do_cy(q1, q2);\n            break;\n        case 8:  // Y:Y\n            inside_do_ycy(q1, q2);\n            break;\n        default:\n            throw std::invalid_argument(\"Unknown pauli interaction.\");\n    }\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const GraphSimulator &sim) {\n    out << \"stim::GraphSimulator{\\n\";\n    out << \"    .num_qubits=\" << sim.num_qubits << \",\\n\";\n    out << \"    .paulis=\" << sim.paulis << \",\\n\";\n    out << \"    .x2outs=\" << sim.x2outs << \",\\n\";\n    out << \"    .z2outs=\" << sim.z2outs << \",\\n\";\n    out << \"    .adj=stim::simd_bit_table<64>::from_text(R\\\"TAB(\\n\" << sim.adj.str(sim.num_qubits) << \"\\n)TAB\\\"),\\n\";\n    out << \"}\";\n    return out;\n}\n\nstd::string GraphSimulator::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\nGraphSimulator GraphSimulator::random_state(size_t n, std::mt19937_64 &rng) {\n    GraphSimulator sim(n);\n    sim.adj = simd_bit_table<64>::random(n, n, rng);\n    for (size_t q1 = 0; q1 < n; q1++) {\n        sim.adj[q1][q1] = 0;\n        for (size_t q2 = q1 + 1; q2 < n; q2++) {\n            sim.adj[q1][q2] = sim.adj[q2][q1];\n        }\n    }\n    sim.paulis = PauliString<64>::random(n, rng);\n    sim.paulis.sign = 0;\n    std::array<uint8_t, 6> gate_xz_data{\n        0b1001,  // I\n        0b0110,  // H\n        0b1011,  // S\n        0b1101,  // SQRT_X_DAG\n        0b0111,  // C_XYZ\n        0b1110,  // C_ZYX\n    };\n    for (size_t q = 0; q < n; q++) {\n        auto r = gate_xz_data[rng() % 6];\n        sim.x2outs.xs[q] = r & 1;\n        sim.x2outs.zs[q] = r & 2;\n        sim.z2outs.xs[q] = r & 4;\n        sim.z2outs.zs[q] = r & 8;\n    }\n    return sim;\n}\n\nvoid GraphSimulator::do_pauli_interaction(bool x1, bool z1, bool x2, bool z2, size_t qubit1, size_t qubit2) {\n    // Propagate the interaction across the single qubit gate layer.\n    auto [x1_in, z1_in, sign1] = after2inside_basis_transform(qubit1, x1, z1);\n    auto [x2_in, z2_in, sign2] = after2inside_basis_transform(qubit2, x2, z2);\n\n    // Kickback minus signs into Pauli gates on the other side.\n    if (sign1) {\n        paulis.xs[qubit2] ^= x2_in;\n        paulis.zs[qubit2] ^= z2_in;\n    }\n    if (sign2) {\n        paulis.xs[qubit1] ^= x1_in;\n        paulis.zs[qubit1] ^= z1_in;\n    }\n\n    // Do the positive-sign interaction between the single-qubit layer and the CZ layer.\n    inside_do_pauli_interaction(x1_in, z1_in, x2_in, z2_in, qubit1, qubit2);\n}\n\nvoid GraphSimulator::do_gate_by_decomposition(const CircuitInstruction &inst) {\n    const Gate &d = GATE_DATA[inst.gate_type];\n    bool is_all_qubits = true;\n    for (auto t : inst.targets) {\n        is_all_qubits &= t.is_qubit_target();\n    }\n    if (!is_all_qubits || d.h_s_cx_m_r_decomposition == nullptr || !(d.flags & GATE_TARGETS_PAIRS)) {\n        throw std::invalid_argument(\"Not supported: \" + inst.str());\n    }\n\n    Circuit circuit(d.h_s_cx_m_r_decomposition);\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        auto a = inst.targets[k];\n        auto b = inst.targets[k + 1];\n        for (const auto &inst2 : circuit.operations) {\n            assert(\n                inst2.gate_type == GateType::CX || inst2.gate_type == GateType::H || inst2.gate_type == GateType::S ||\n                inst2.gate_type == GateType::R || inst2.gate_type == GateType::M);\n            if (inst2.gate_type == GateType::CX) {\n                for (size_t k2 = 0; k2 < inst2.targets.size(); k2 += 2) {\n                    auto a2 = inst2.targets[k2];\n                    auto b2 = inst2.targets[k2 + 1];\n                    assert(a2.is_qubit_target());\n                    assert(b2.is_qubit_target());\n                    assert(a2.qubit_value() == 0 || a2.qubit_value() == 1);\n                    assert(b2.qubit_value() == 0 || b2.qubit_value() == 1);\n                    auto a3 = a2.qubit_value() == 0 ? a : b;\n                    auto b3 = b2.qubit_value() == 0 ? a : b;\n                    do_pauli_interaction(false, true, true, false, a3.qubit_value(), b3.qubit_value());\n                }\n            } else {\n                for (GateTarget a2 : inst2.targets) {\n                    assert(a2.is_qubit_target());\n                    assert(a2.qubit_value() == 0 || a2.qubit_value() == 1);\n                    auto a3 = a2.qubit_value() == 0 ? a : b;\n                    do_1q_gate(inst2.gate_type, a3.qubit_value());\n                }\n            }\n        }\n    }\n}\n\nvoid GraphSimulator::do_2q_unitary_instruction(const CircuitInstruction &inst) {\n    uint8_t p1;\n    uint8_t p2;\n    constexpr uint8_t X = 0b01;\n    constexpr uint8_t Y = 0b11;\n    constexpr uint8_t Z = 0b10;\n    switch (inst.gate_type) {\n        case GateType::XCX:\n            p1 = X;\n            p2 = X;\n            break;\n        case GateType::XCY:\n            p1 = X;\n            p2 = Y;\n            break;\n        case GateType::XCZ:\n            p1 = X;\n            p2 = Z;\n            break;\n        case GateType::YCX:\n            p1 = Y;\n            p2 = X;\n            break;\n        case GateType::YCY:\n            p1 = Y;\n            p2 = Y;\n            break;\n        case GateType::YCZ:\n            p1 = Y;\n            p2 = Z;\n            break;\n        case GateType::CX:\n            p1 = Z;\n            p2 = X;\n            break;\n        case GateType::CY:\n            p1 = Z;\n            p2 = Y;\n            break;\n        case GateType::CZ:\n            p1 = Z;\n            p2 = Z;\n            break;\n        default:\n            do_gate_by_decomposition(inst);\n            return;\n    }\n    bool x1 = p1 & 1;\n    bool z1 = p1 & 2;\n    bool x2 = p2 & 1;\n    bool z2 = p2 & 2;\n\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        auto t1 = inst.targets[k];\n        auto t2 = inst.targets[k + 1];\n        if (!t1.is_qubit_target() || !t2.is_qubit_target()) {\n            throw std::invalid_argument(\"Unsupported operation: \" + inst.str());\n        }\n        do_pauli_interaction(x1, z1, x2, z2, t1.qubit_value(), t2.qubit_value());\n    }\n}\n\nvoid GraphSimulator::output_pauli_layer(Circuit &out, bool to_hs_xyz) const {\n    std::array<std::vector<GateTarget>, 4> groups;\n\n    for (size_t q = 0; q < paulis.num_qubits; q++) {\n        bool x = paulis.xs[q];\n        bool z = paulis.zs[q];\n        if (to_hs_xyz) {\n            bool xx = x2outs.xs[q];\n            bool xz = x2outs.zs[q];\n            bool zx = z2outs.xs[q];\n            bool zz = z2outs.zs[q];\n            z ^= xx == 1 && xz == 1 && zx == 1 && zz == 0;\n        }\n        groups[x + 2 * z].push_back(GateTarget::qubit(q));\n    }\n\n    auto f = [&](GateType g, int k) {\n        if (!groups[k].empty()) {\n            out.safe_append(CircuitInstruction(g, {}, groups[k], \"\"));\n        }\n    };\n    f(GateType::X, 0b01);\n    f(GateType::Y, 0b11);\n    f(GateType::Z, 0b10);\n}\n\nvoid GraphSimulator::output_clifford_layer(Circuit &out, bool to_hs_xyz) const {\n    output_pauli_layer(out, to_hs_xyz);\n\n    std::array<std::vector<GateTarget>, 16> groups;\n    for (size_t q = 0; q < x2outs.num_qubits; q++) {\n        bool xx = x2outs.xs[q];\n        bool xz = x2outs.zs[q];\n        bool zx = z2outs.xs[q];\n        bool zz = z2outs.zs[q];\n        groups[xx + 2 * xz + 4 * zx + 8 * zz].push_back(GateTarget::qubit(q));\n    }\n\n    std::array<std::vector<GateTarget>, 3> shs;\n    auto f = [&](GateType g, int k, std::array<bool, 3> use_shs) {\n        if (to_hs_xyz) {\n            for (size_t j = 0; j < 3; j++) {\n                if (use_shs[j]) {\n                    shs[j].insert(shs[j].end(), groups[k].begin(), groups[k].end());\n                }\n            }\n        } else {\n            if (!groups[k].empty()) {\n                out.safe_append(CircuitInstruction(g, {}, groups[k], \"\"));\n            }\n        }\n    };\n    f(GateType::C_XYZ, 0b0111, {1, 1, 0});\n    f(GateType::C_ZYX, 0b1110, {0, 1, 1});\n    f(GateType::H, 0b0110, {0, 1, 0});\n    f(GateType::S, 0b1011, {1, 0, 0});\n    f(GateType::SQRT_X_DAG, 0b1101, {1, 1, 1});\n    for (size_t k = 0; k < 3; k++) {\n        if (!shs[k].empty()) {\n            std::sort(shs[k].begin(), shs[k].end());\n            out.safe_append(CircuitInstruction(k == 1 ? GateType::H : GateType::S, {}, shs[k], \"\"));\n        }\n    }\n}\n\nCircuit GraphSimulator::to_circuit(bool to_hs_xyz) const {\n    std::vector<GateTarget> targets;\n    targets.reserve(2 * num_qubits);\n    Circuit out;\n\n    for (size_t q = 0; q < num_qubits; q++) {\n        targets.push_back(GateTarget::qubit(q));\n    }\n    if (!targets.empty()) {\n        out.safe_append(CircuitInstruction(GateType::RX, {}, targets, \"\"));\n    }\n    out.safe_append(CircuitInstruction(GateType::TICK, {}, {}, \"\"));\n\n    bool has_cz = false;\n    for (size_t q = 0; q < num_qubits; q++) {\n        targets.clear();\n        for (size_t q2 = q + 1; q2 < num_qubits; q2++) {\n            if (adj[q][q2]) {\n                targets.push_back(GateTarget::qubit(q));\n                targets.push_back(GateTarget::qubit(q2));\n            }\n        }\n        if (!targets.empty()) {\n            out.safe_append(CircuitInstruction(GateType::CZ, {}, targets, \"\"));\n        }\n        has_cz |= !targets.empty();\n    }\n    if (has_cz) {\n        out.safe_append(CircuitInstruction(GateType::TICK, {}, {}, \"\"));\n    }\n\n    output_clifford_layer(out, to_hs_xyz);\n\n    return out;\n}\n\nvoid GraphSimulator::do_instruction(const CircuitInstruction &instruction) {\n    auto f = GATE_DATA[instruction.gate_type].flags;\n\n    if (f & GATE_IS_UNITARY) {\n        if (f & GATE_IS_SINGLE_QUBIT_GATE) {\n            for (auto t : instruction.targets) {\n                do_1q_gate(instruction.gate_type, t.qubit_value());\n            }\n            return;\n        }\n        if (f & GATE_TARGETS_PAIRS) {\n            do_2q_unitary_instruction(instruction);\n            return;\n        }\n    }\n\n    switch (instruction.gate_type) {\n        case GateType::TICK:\n        case GateType::QUBIT_COORDS:\n        case GateType::SHIFT_COORDS:\n            return;  // No effect.\n        default:\n            throw std::invalid_argument(\"Unsupported operation: \" + instruction.str());\n    }\n}\n\nvoid GraphSimulator::do_circuit(const Circuit &circuit) {\n    circuit.for_each_operation([&](const CircuitInstruction &inst) {\n        do_instruction(inst);\n    });\n}\n"
  },
  {
    "path": "src/stim/simulators/graph_simulator.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_GRAPH_SIMULATOR_H\n#define _STIM_SIMULATORS_GRAPH_SIMULATOR_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/mem/simd_bit_table.h\"\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nnamespace stim {\n\nstruct GraphSimulator {\n    // RX applied to each qubit.\n    size_t num_qubits;\n    // Then CZs applied according to this adjacency matrix.\n    simd_bit_table<64> adj;\n    // Then Paulis adding sign data.\n    PauliString<64> paulis;\n    // Then an unsigned Clifford mapping.\n    PauliString<64> x2outs;\n    PauliString<64> z2outs;\n    // Used as temporary workspace.\n    std::vector<size_t> buffer;\n\n    explicit GraphSimulator(size_t num_qubits);\n    static GraphSimulator random_state(size_t n, std::mt19937_64 &rng);\n\n    Circuit to_circuit(bool to_hs_xyz = false) const;\n\n    void do_circuit(const Circuit &circuit);\n    void do_instruction(const CircuitInstruction &instruction);\n    void do_complementation(size_t c);\n    void verify_invariants() const;\n    void inside_do_sqrt_z(size_t q);\n    void inside_do_sqrt_x_dag(size_t q);\n    std::tuple<bool, bool, bool> after2inside_basis_transform(size_t qubit, bool x, bool z);\n\n    std::string str() const;\n\n   private:\n    void output_pauli_layer(Circuit &out, bool to_hs_xyz) const;\n    void output_clifford_layer(Circuit &out, bool to_hs_xyz) const;\n\n    void do_1q_gate(GateType gate, size_t qubit);\n    void do_2q_unitary_instruction(const CircuitInstruction &inst);\n    void do_pauli_interaction(bool x1, bool z1, bool x2, bool z2, size_t qubit1, size_t qubit2);\n    void do_gate_by_decomposition(const CircuitInstruction &inst);\n\n    // These operations apply to the state inside of the single qubit gates.\n    void inside_do_cz(size_t a, size_t b);\n    void inside_do_cx(size_t c, size_t t);\n    void inside_do_cy(size_t c, size_t t);\n    void inside_do_ycx(size_t q1, size_t q2);\n    void inside_do_ycy(size_t q1, size_t q2);\n    void inside_do_xcx(size_t q1, size_t q2);\n    void inside_do_pauli_interaction(bool x1, bool z1, bool x2, bool z2, size_t q1, size_t q2);\n};\n\nstd::ostream &operator<<(std::ostream &out, const GraphSimulator &sim);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/graph_simulator.test.cc",
    "content": "#include \"stim/simulators/graph_simulator.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/diagram/timeline/timeline_ascii_drawer.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nvoid expect_graph_circuit_is_equivalent(const Circuit &circuit) {\n    auto n = circuit.count_qubits();\n    GraphSimulator sim(n);\n    sim.do_circuit(circuit);\n    sim.verify_invariants();\n    Circuit converted = sim.to_circuit();\n    TableauSimulator<64> sim1(std::mt19937_64{}, n);\n    TableauSimulator<64> sim2(std::mt19937_64{}, n);\n    sim1.safe_do_circuit(circuit);\n    sim2.safe_do_circuit(converted);\n    auto s1 = sim1.canonical_stabilizers();\n    auto s2 = sim2.canonical_stabilizers();\n    if (s1 != s2) {\n        EXPECT_EQ(s1, s2) << \"\\nACTUAL:\\n\"\n                          << stim_draw_internal::DiagramTimelineAsciiDrawer::make_diagram(circuit) << \"\\nCONVERTED:\\n\"\n                          << stim_draw_internal::DiagramTimelineAsciiDrawer::make_diagram(converted);\n    }\n}\n\nvoid expect_graph_sim_effect_matches_tableau_sim(const GraphSimulator &state, const Circuit &effect) {\n    GraphSimulator state_after_effect = state;\n    auto n = state_after_effect.num_qubits;\n    state_after_effect.do_circuit(effect);\n    state_after_effect.verify_invariants();\n\n    TableauSimulator<64> tableau_sim1(std::mt19937_64{}, n);\n    TableauSimulator<64> tableau_sim2(std::mt19937_64{}, n);\n    tableau_sim1.safe_do_circuit(state.to_circuit());\n    tableau_sim1.safe_do_circuit(effect);\n    tableau_sim2.safe_do_circuit(state_after_effect.to_circuit());\n    auto s1 = tableau_sim1.canonical_stabilizers();\n    auto s2 = tableau_sim2.canonical_stabilizers();\n    if (s1 != s2) {\n        EXPECT_EQ(s1, s2) << \"EFFECT:\\nstim::Circuit(R\\\"CIRCUIT(\\n\"\n                          << effect << \"\\n)CIRCUIT\\\")\" << \"\\n\"\n                          << \"STATE:\\n\"\n                          << state << \"\\n\";\n    }\n}\n\nTEST(graph_simulator, converts_circuits) {\n    expect_graph_circuit_is_equivalent(Circuit(R\"CIRCUIT(\n        H 2 3 5\n        S 0 1 2\n        C_XYZ 1 2 3\n        S_DAG 1\n        H_YZ 5 4\n        SQRT_Y 2 4\n        X 1\n    )CIRCUIT\"));\n\n    expect_graph_circuit_is_equivalent(Circuit(R\"CIRCUIT(\n        H 0 1\n        CZ 0 1\n    )CIRCUIT\"));\n\n    expect_graph_circuit_is_equivalent(Circuit(R\"CIRCUIT(\n        H 0 1 2 3\n        CZ 0 1 0 2 0 3\n    )CIRCUIT\"));\n\n    expect_graph_circuit_is_equivalent(Circuit(R\"CIRCUIT(\n        H 0 1 2 3\n        CZ 0 1\n        CX 2 1\n    )CIRCUIT\"));\n}\n\nTEST(graph_simulator, after2inside_basis_transform) {\n    GraphSimulator sim(6);\n    //                            VI+SH-\n    sim.x2outs = PauliString<64>(\"XXYYZZ\");\n    sim.z2outs = PauliString<64>(\"YZXZXY\");\n\n    ASSERT_EQ(sim.after2inside_basis_transform(0u, 1, 0), (std::make_tuple<bool, bool, bool>(1, 0, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(0u, 1, 1), (std::make_tuple<bool, bool, bool>(0, 1, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(0u, 0, 1), (std::make_tuple<bool, bool, bool>(1, 1, true)));\n\n    ASSERT_EQ(sim.after2inside_basis_transform(1u, 1, 0), (std::make_tuple<bool, bool, bool>(1, 0, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(1u, 0, 1), (std::make_tuple<bool, bool, bool>(0, 1, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(1u, 1, 1), (std::make_tuple<bool, bool, bool>(1, 1, false)));\n\n    ASSERT_EQ(sim.after2inside_basis_transform(2u, 1, 1), (std::make_tuple<bool, bool, bool>(1, 0, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(2u, 1, 0), (std::make_tuple<bool, bool, bool>(0, 1, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(2u, 0, 1), (std::make_tuple<bool, bool, bool>(1, 1, false)));\n\n    ASSERT_EQ(sim.after2inside_basis_transform(3u, 1, 1), (std::make_tuple<bool, bool, bool>(1, 0, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(3u, 0, 1), (std::make_tuple<bool, bool, bool>(0, 1, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(3u, 1, 0), (std::make_tuple<bool, bool, bool>(1, 1, true)));\n\n    ASSERT_EQ(sim.after2inside_basis_transform(4u, 0, 1), (std::make_tuple<bool, bool, bool>(1, 0, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(4u, 1, 0), (std::make_tuple<bool, bool, bool>(0, 1, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(4u, 1, 1), (std::make_tuple<bool, bool, bool>(1, 1, true)));\n\n    ASSERT_EQ(sim.after2inside_basis_transform(5u, 0, 1), (std::make_tuple<bool, bool, bool>(1, 0, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(5u, 1, 1), (std::make_tuple<bool, bool, bool>(0, 1, false)));\n    ASSERT_EQ(sim.after2inside_basis_transform(5u, 1, 0), (std::make_tuple<bool, bool, bool>(1, 1, false)));\n}\n\nTEST(graph_simulator, to_hs_xyz) {\n    GraphSimulator sim(10);\n    sim.do_circuit(Circuit(R\"CIRCUIT(\n        H 0 1 2 3 4 5 6 7 8 9\n        I 0\n        H 1\n        S 2\n        SQRT_X_DAG 3\n        C_XYZ 4\n        C_ZYX 5\n        X 6\n        Y 7\n        Z 8\n        H 9\n        Z 9\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.to_circuit(true), Circuit(R\"CIRCUIT(\n        RX 0 1 2 3 4 5 6 7 8 9\n        TICK\n        X 6 9\n        Y 7\n        Z 4 8\n        S 2 3 4\n        H 1 3 4 5 9\n        S 3 5\n    )CIRCUIT\"));\n}\n\nTEST(graph_simulator, inside_do_sqrt_z) {\n    GraphSimulator sim(10);\n    sim.do_circuit(Circuit(R\"CIRCUIT(\n        H 0 1 2 3 4 5 6 7 8 9\n        I 0\n        H 1\n        S 2\n        SQRT_X_DAG 3\n        C_XYZ 4\n        C_ZYX 5\n        X 6\n        Y 7\n        Z 8\n        H 9\n        Z 9\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.to_circuit(), Circuit(R\"CIRCUIT(\n        RX 0 1 2 3 4 5 6 7 8 9\n        TICK\n        X 6 9\n        Y 7\n        Z 8\n        C_XYZ 4\n        C_ZYX 5\n        H 1 9\n        S 2\n        SQRT_X_DAG 3\n    )CIRCUIT\"));\n\n    for (size_t q = 0; q < sim.num_qubits; q++) {\n        sim.inside_do_sqrt_z(q);\n    }\n    sim.verify_invariants();\n    ASSERT_EQ(sim.to_circuit(), Circuit(R\"CIRCUIT(\n        RX 0 1 2 3 4 5 6 7 8 9\n        TICK\n        X 7 9\n        Y 6\n        Z 1 2 3 8\n        C_XYZ 1 9\n        C_ZYX 3\n        H 4\n        S 0 6 7 8\n        SQRT_X_DAG 5\n    )CIRCUIT\"));\n}\n\nTEST(graph_simulator, inside_do_sqrt_x_dag) {\n    GraphSimulator sim(10);\n    sim.do_circuit(Circuit(R\"CIRCUIT(\n        H 0 1 2 3 4 5 6 7 8 9\n        I 0\n        H 1\n        S 2\n        SQRT_X_DAG 3\n        C_XYZ 4\n        C_ZYX 5\n        X 6\n        Y 7\n        Z 8\n        H 9\n        Z 9\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.to_circuit(), Circuit(R\"CIRCUIT(\n        RX 0 1 2 3 4 5 6 7 8 9\n        TICK\n        X 6 9\n        Y 7\n        Z 8\n        C_XYZ 4\n        C_ZYX 5\n        H 1 9\n        S 2\n        SQRT_X_DAG 3\n    )CIRCUIT\"));\n\n    for (size_t q = 0; q < sim.num_qubits; q++) {\n        sim.inside_do_sqrt_x_dag(q);\n    }\n    sim.verify_invariants();\n    ASSERT_EQ(sim.to_circuit(), Circuit(R\"CIRCUIT(\n        RX 0 1 2 3 4 5 6 7 8 9\n        TICK\n        X 1 2 3 6\n        Y 8\n        Z 7\n        C_XYZ 2\n        C_ZYX 1 9\n        H 5\n        S 4\n        SQRT_X_DAG 0 6 7 8\n    )CIRCUIT\"));\n}\n\nTEST(graph_simulator, do_complementation) {\n    for (size_t k = 0; k < 50; k++) {\n        auto rng = INDEPENDENT_TEST_RNG();\n        GraphSimulator sim = GraphSimulator::random_state(8, rng);\n        GraphSimulator sim2 = sim;\n        sim2.do_complementation(3);\n        sim.verify_invariants();\n        sim2.verify_invariants();\n\n        TableauSimulator<64> tableau_sim1(std::mt19937_64{}, 8);\n        TableauSimulator<64> tableau_sim2(std::mt19937_64{}, 8);\n        tableau_sim1.safe_do_circuit(sim.to_circuit());\n        tableau_sim2.safe_do_circuit(sim2.to_circuit());\n        auto s1 = tableau_sim1.canonical_stabilizers();\n        auto s2 = tableau_sim2.canonical_stabilizers();\n        if (s1 != s2) {\n            ASSERT_EQ(s1, s2) << sim;\n        }\n    }\n}\n\nTEST(graph_simulator, all_unitary_gates_work) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    std::vector<GateTarget> targets{GateTarget::qubit(2), GateTarget::qubit(5)};\n    SpanRef<GateTarget> t2 = targets;\n    SpanRef<GateTarget> t1 = t2;\n    t1.ptr_end--;\n    for (const auto &gate : GATE_DATA.items) {\n        if (!gate.has_known_unitary_matrix()) {\n            continue;\n        }\n        Circuit circuit;\n        circuit.safe_append(CircuitInstruction(gate.id, {}, (gate.flags & GATE_TARGETS_PAIRS) ? t2 : t1, \"\"));\n        for (size_t k = 0; k < 20; k++) {\n            expect_graph_sim_effect_matches_tableau_sim(GraphSimulator::random_state(8, rng), circuit);\n        }\n    }\n}\n\nTEST(graph_simulator, to_circuit_single_qubit_gates) {\n    GraphSimulator sim(6);\n    ASSERT_EQ(sim.to_circuit(), Circuit(R\"CIRCUIT(\n        RX 0 1 2 3 4 5\n        TICK\n        H 0 1 2 3 4 5\n    )CIRCUIT\"));\n\n    sim.do_circuit(Circuit(R\"CIRCUIT(\n        H 0 1 2 3 4 5\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.to_circuit(), Circuit(R\"CIRCUIT(\n        RX 0 1 2 3 4 5\n        TICK\n    )CIRCUIT\"));\n\n    sim.do_circuit(Circuit(R\"CIRCUIT(\n        H 0\n        S 1\n        C_XYZ 2 3 3\n        SQRT_X_DAG 4\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.to_circuit(), Circuit(R\"CIRCUIT(\n        RX 0 1 2 3 4 5\n        TICK\n        C_XYZ 2\n        C_ZYX 3\n        H 0\n        S 1\n        SQRT_X_DAG 4\n    )CIRCUIT\"));\n\n    sim.do_circuit(Circuit(R\"CIRCUIT(\n        X 0\n        S 1\n        Y 2\n        Z 3\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.to_circuit(), Circuit(R\"CIRCUIT(\n        RX 0 1 2 3 4 5\n        TICK\n        X 2 3\n        Z 0 1\n        C_XYZ 2\n        C_ZYX 3\n        H 0\n        SQRT_X_DAG 4\n    )CIRCUIT\"));\n}\n"
  },
  {
    "path": "src/stim/simulators/matched_error.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/matched_error.h\"\n\n#include <algorithm>\n#include <queue>\n#include <sstream>\n\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\n\nvoid print_pauli_product(std::ostream &out, const std::vector<GateTargetWithCoords> &pauli_terms) {\n    for (size_t k = 0; k < pauli_terms.size(); k++) {\n        const auto &p = pauli_terms[k];\n        if (k) {\n            out << \"*\";\n        }\n        out << p;\n    }\n}\n\nvoid print_circuit_error_loc_indent(std::ostream &out, const CircuitErrorLocation &e, const char *indent) {\n    out << indent << \"CircuitErrorLocation {\\n\";\n\n    if (!e.noise_tag.empty()) {\n        out << indent << \"    noise_tag: \" << e.noise_tag << \"\\n\";\n    }\n    if (!e.flipped_pauli_product.empty()) {\n        out << indent << \"    flipped_pauli_product: \";\n        print_pauli_product(out, e.flipped_pauli_product);\n        out << \"\\n\";\n    }\n    if (e.flipped_measurement.measurement_record_index != UINT64_MAX) {\n        out << indent\n            << \"    flipped_measurement.measurement_record_index: \" << e.flipped_measurement.measurement_record_index\n            << \"\\n\";\n    }\n    if (!e.flipped_measurement.measured_observable.empty()) {\n        out << indent << \"    flipped_measurement.measured_observable: \";\n        print_pauli_product(out, e.flipped_measurement.measured_observable);\n        out << \"\\n\";\n    }\n\n    out << indent << \"    Circuit location stack trace:\\n\";\n    out << indent << \"        (after \" << e.tick_offset << \" TICKs)\\n\";\n    for (size_t k = 0; k < e.stack_frames.size(); k++) {\n        const auto &frame = e.stack_frames[k];\n        if (k) {\n            out << indent << \"        after \" << frame.iteration_index << \" completed iterations\\n\";\n        }\n        out << indent << \"        \";\n        out << \"at instruction #\" << (frame.instruction_offset + 1);\n        const auto &gate_data = GATE_DATA[e.instruction_targets.gate_type];\n        if (k < e.stack_frames.size() - 1) {\n            out << \" (a REPEAT \" << frame.instruction_repetitions_arg << \" block)\";\n        } else {\n            out << \" (\" << gate_data.name << \")\";\n        }\n        if (k) {\n            out << \" in the REPEAT block\";\n        } else {\n            out << \" in the circuit\";\n        }\n        out << \"\\n\";\n    }\n    if (e.instruction_targets.target_range_start + 1 == e.instruction_targets.target_range_end) {\n        out << indent << \"        at target #\" << (e.instruction_targets.target_range_start + 1);\n    } else {\n        out << indent << \"        at targets #\" << (e.instruction_targets.target_range_start + 1);\n        out << \" to #\" << e.instruction_targets.target_range_end;\n    }\n    out << \" of the instruction\\n\";\n    out << indent << \"        resolving to \" << e.instruction_targets << \"\\n\";\n\n    out << indent << \"}\";\n}\n\nvoid CircuitTargetsInsideInstruction::fill_args_and_targets_in_range(\n    const CircuitInstruction &actual_op, const std::map<uint64_t, std::vector<double>> &qubit_coords) {\n    targets_in_range.clear();\n    for (size_t k = target_range_start; k < target_range_end; k++) {\n        const auto &t = actual_op.targets[k];\n        bool is_non_coord_target = t.data & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT | TARGET_COMBINER);\n        auto entry = qubit_coords.find(t.qubit_value());\n        if (entry == qubit_coords.end() || is_non_coord_target) {\n            targets_in_range.push_back({t, {}});\n        } else {\n            targets_in_range.push_back({t, entry->second});\n        }\n    }\n\n    args.clear();\n    args.insert(args.begin(), actual_op.args.begin(), actual_op.args.end());\n}\n\nvoid ExplainedError::fill_in_dem_targets(\n    SpanRef<const DemTarget> targets, const std::map<uint64_t, std::vector<double>> &dem_coords) {\n    dem_error_terms.clear();\n    for (const auto &t : targets) {\n        auto entry = dem_coords.find(t.raw_id());\n        if (t.is_relative_detector_id() && entry != dem_coords.end()) {\n            dem_error_terms.push_back({t, entry->second});\n        } else {\n            dem_error_terms.push_back({t, {}});\n        }\n    }\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const FlippedMeasurement &e) {\n    out << \"FlippedMeasurement{\";\n    if (e.measurement_record_index == UINT64_MAX) {\n        return out << \"none}\";\n    }\n    out << e.measurement_record_index;\n    out << \", \";\n    print_pauli_product(out, e.measured_observable);\n    out << \"}\";\n    return out;\n}\nstd::ostream &stim::operator<<(std::ostream &out, const CircuitErrorLocation &e) {\n    print_circuit_error_loc_indent(out, e, \"\");\n    return out;\n}\nstd::ostream &stim::operator<<(std::ostream &out, const CircuitErrorLocationStackFrame &e) {\n    out << \"CircuitErrorLocationStackFrame\";\n    out << \"{instruction_offset=\" << e.instruction_offset;\n    out << \", iteration_index=\" << e.iteration_index;\n    out << \", instruction_repetitions_arg=\" << e.instruction_repetitions_arg << \"}\";\n    return out;\n}\nstd::ostream &stim::operator<<(std::ostream &out, const ExplainedError &e) {\n    out << \"ExplainedError {\\n\";\n    out << \"    dem_error_terms: \" << comma_sep(e.dem_error_terms, \" \");\n    if (e.circuit_error_locations.empty()) {\n        out << \"\\n    [no single circuit error had these exact symptoms]\";\n    }\n    for (const auto &loc : e.circuit_error_locations) {\n        out << \"\\n\";\n        print_circuit_error_loc_indent(out, loc, \"    \");\n    }\n    out << \"\\n}\";\n    return out;\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const CircuitTargetsInsideInstruction &e) {\n    const auto &gate_data = GATE_DATA[e.gate_type];\n    if (gate_data.flags == GateFlags::NO_GATE_FLAG) {\n        out << \"null\";\n    } else {\n        out << gate_data.name;\n    }\n    if (!e.gate_tag.empty()) {\n        out << '[';\n        write_tag_escaped_string_to(e.gate_tag, out);\n        out << ']';\n    }\n    if (!e.args.empty()) {\n        out << '(' << comma_sep(e.args) << ')';\n    }\n    bool was_combiner = false;\n    for (const auto &t : e.targets_in_range) {\n        bool is_combiner = t.gate_target.is_combiner();\n        if (!is_combiner && !was_combiner) {\n            out << ' ';\n        }\n        was_combiner = is_combiner;\n        out << t;\n    }\n    return out;\n}\nstd::ostream &stim::operator<<(std::ostream &out, const GateTargetWithCoords &e) {\n    e.gate_target.write_succinct(out);\n    if (!e.coords.empty()) {\n        out << \"[coords \" << comma_sep(e.coords, \",\") << \"]\";\n    }\n    return out;\n}\nstd::ostream &stim::operator<<(std::ostream &out, const DemTargetWithCoords &e) {\n    out << e.dem_target;\n    if (!e.coords.empty()) {\n        out << \"[coords \" << comma_sep(e.coords, \",\") << \"]\";\n    }\n    return out;\n}\n\nbool ExplainedError::operator==(const ExplainedError &other) const {\n    return dem_error_terms == other.dem_error_terms && circuit_error_locations == other.circuit_error_locations;\n}\nbool CircuitErrorLocationStackFrame::operator==(const CircuitErrorLocationStackFrame &other) const {\n    return iteration_index == other.iteration_index && instruction_offset == other.instruction_offset &&\n           instruction_repetitions_arg == other.instruction_repetitions_arg;\n}\nbool CircuitErrorLocation::operator==(const CircuitErrorLocation &other) const {\n    return flipped_measurement == other.flipped_measurement && tick_offset == other.tick_offset &&\n           flipped_pauli_product == other.flipped_pauli_product && instruction_targets == other.instruction_targets &&\n           stack_frames == other.stack_frames;\n}\nbool CircuitTargetsInsideInstruction::operator==(const CircuitTargetsInsideInstruction &other) const {\n    return gate_type == other.gate_type && gate_tag == other.gate_tag &&\n           target_range_start == other.target_range_start && target_range_end == other.target_range_end &&\n           targets_in_range == other.targets_in_range && args == other.args;\n}\nbool DemTargetWithCoords::operator==(const DemTargetWithCoords &other) const {\n    return coords == other.coords && dem_target == other.dem_target;\n}\nbool FlippedMeasurement::operator==(const FlippedMeasurement &other) const {\n    return measured_observable == other.measured_observable &&\n           measurement_record_index == other.measurement_record_index;\n}\nbool GateTargetWithCoords::operator==(const GateTargetWithCoords &other) const {\n    return coords == other.coords && gate_target == other.gate_target;\n}\n\nbool CircuitErrorLocation::operator!=(const CircuitErrorLocation &other) const {\n    return !(*this == other);\n}\nbool CircuitErrorLocationStackFrame::operator!=(const CircuitErrorLocationStackFrame &other) const {\n    return !(*this == other);\n}\nbool CircuitTargetsInsideInstruction::operator!=(const CircuitTargetsInsideInstruction &other) const {\n    return !(*this == other);\n}\nbool DemTargetWithCoords::operator!=(const DemTargetWithCoords &other) const {\n    return !(*this == other);\n}\nbool FlippedMeasurement::operator!=(const FlippedMeasurement &other) const {\n    return !(*this == other);\n}\nbool GateTargetWithCoords::operator!=(const GateTargetWithCoords &other) const {\n    return !(*this == other);\n}\nbool ExplainedError::operator!=(const ExplainedError &other) const {\n    return !(*this == other);\n}\n\nstd::string CircuitErrorLocation::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\nstd::string CircuitErrorLocationStackFrame::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\nstd::string CircuitTargetsInsideInstruction::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\nstd::string DemTargetWithCoords::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\nstd::string FlippedMeasurement::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\nstd::string GateTargetWithCoords::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\nstd::string ExplainedError::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\nvoid ExplainedError::canonicalize() {\n    for (auto &c : circuit_error_locations) {\n        c.canonicalize();\n    }\n    std::sort(dem_error_terms.begin(), dem_error_terms.end());\n    std::sort(circuit_error_locations.begin(), circuit_error_locations.end());\n}\n\nvoid CircuitErrorLocation::canonicalize() {\n    std::sort(flipped_pauli_product.begin(), flipped_pauli_product.end());\n    std::sort(flipped_measurement.measured_observable.begin(), flipped_measurement.measured_observable.end());\n}\n\ntemplate <typename T>\nbool vec_less_than(const std::vector<T> &vec1, const std::vector<T> &vec2) {\n    SpanRef<const T> c1 = vec1;\n    SpanRef<const T> c2 = vec2;\n    return c1 < c2;\n}\nbool GateTargetWithCoords::operator<(const GateTargetWithCoords &other) const {\n    if (gate_target != other.gate_target) {\n        return gate_target < other.gate_target;\n    }\n    if (coords != other.coords) {\n        return vec_less_than(coords, other.coords);\n    }\n\n    return false;\n}\nbool DemTargetWithCoords::operator<(const DemTargetWithCoords &other) const {\n    if (dem_target != other.dem_target) {\n        return dem_target < other.dem_target;\n    }\n    if (coords != other.coords) {\n        return vec_less_than(coords, other.coords);\n    }\n\n    return false;\n}\nbool CircuitErrorLocation::operator<(const CircuitErrorLocation &other) const {\n    if (tick_offset != other.tick_offset) {\n        return tick_offset < other.tick_offset;\n    }\n    if (flipped_pauli_product != other.flipped_pauli_product) {\n        return vec_less_than(flipped_pauli_product, other.flipped_pauli_product);\n    }\n    if (flipped_measurement != other.flipped_measurement) {\n        return flipped_measurement < other.flipped_measurement;\n    }\n    if (instruction_targets != other.instruction_targets) {\n        return instruction_targets < other.instruction_targets;\n    }\n    if (stack_frames != other.stack_frames) {\n        return vec_less_than(stack_frames, other.stack_frames);\n    }\n    return false;\n}\nbool FlippedMeasurement::operator<(const FlippedMeasurement &other) const {\n    if (measurement_record_index != other.measurement_record_index) {\n        return measurement_record_index < other.measurement_record_index;\n    }\n    if (measured_observable != other.measured_observable) {\n        return vec_less_than(measured_observable, other.measured_observable);\n    }\n    return false;\n}\nbool CircuitErrorLocationStackFrame::operator<(const CircuitErrorLocationStackFrame &other) const {\n    if (instruction_offset != other.instruction_offset) {\n        return instruction_offset < other.instruction_offset;\n    }\n    if (iteration_index != other.iteration_index) {\n        return iteration_index < other.iteration_index;\n    }\n    if (instruction_repetitions_arg != other.instruction_repetitions_arg) {\n        return instruction_repetitions_arg < other.instruction_repetitions_arg;\n    }\n    return false;\n}\nbool CircuitTargetsInsideInstruction::operator<(const CircuitTargetsInsideInstruction &other) const {\n    if (target_range_start != other.target_range_start) {\n        return target_range_start < other.target_range_start;\n    }\n    if (target_range_end != other.target_range_end) {\n        return target_range_end < other.target_range_end;\n    }\n    if (targets_in_range != other.targets_in_range) {\n        return vec_less_than(targets_in_range, other.targets_in_range);\n    }\n    if (args != other.args) {\n        return vec_less_than(args, other.args);\n    }\n    if (gate_type == GateType::NOT_A_GATE || other.gate_type == GateType::NOT_A_GATE) {\n        return gate_type < other.gate_type;\n    }\n    return GATE_DATA[gate_type].name < GATE_DATA[other.gate_type].name;\n}\n\nbool CircuitErrorLocation::is_simpler_than(const CircuitErrorLocation &other) const {\n    if (flipped_measurement.measured_observable.size() != other.flipped_measurement.measured_observable.size()) {\n        return other.flipped_measurement.measured_observable.size() <\n               other.flipped_measurement.measured_observable.size();\n    }\n    if (flipped_pauli_product.size() != other.flipped_pauli_product.size()) {\n        return flipped_pauli_product.size() < other.flipped_pauli_product.size();\n    }\n    return *this < other;\n}\n"
  },
  {
    "path": "src/stim/simulators/matched_error.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_MATCHED_ERROR_H\n#define _STIM_SIMULATORS_MATCHED_ERROR_H\n\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/dem/detector_error_model.h\"\n\nnamespace stim {\n\n/// Describes the location of an instruction being executed within a\n/// circuit or loop, distinguishing between separate loop iterations.\n///\n/// The full location is a stack of these frames, drilling down from\n/// the top level circuit to the inner-most loop that the instruction\n/// is within.\nstruct CircuitErrorLocationStackFrame {\n    /// The index of the instruction in the circuit (or block).\n    uint64_t instruction_offset;\n    /// If inside a loop, the number of iterations of the loop that completed\n    /// before the moment that we are trying to refer to.\n    /// If not in a loop, set to 0.\n    uint64_t iteration_index;\n    /// If the instruction is a REPEAT block, this is how many times it repeats.\n    /// If not, set to 0.\n    uint64_t instruction_repetitions_arg;\n\n    bool operator<(const CircuitErrorLocationStackFrame &other) const;\n\n    /// Standard methods for easy testing.\n    bool operator==(const CircuitErrorLocationStackFrame &other) const;\n    bool operator!=(const CircuitErrorLocationStackFrame &other) const;\n    std::string str() const;\n};\n\n/// A gate target with qubit coordinate metadata attached to it.\nstruct GateTargetWithCoords {\n    GateTarget gate_target;\n    std::vector<double> coords;\n\n    bool operator<(const GateTargetWithCoords &other) const;\n\n    /// Standard methods for easy testing.\n    bool operator==(const GateTargetWithCoords &other) const;\n    bool operator!=(const GateTargetWithCoords &other) const;\n    std::string str() const;\n};\n\n/// A dem target with detector coordinate metadata attached to it.\nstruct DemTargetWithCoords {\n    DemTarget dem_target;\n    std::vector<double> coords;\n\n    bool operator<(const DemTargetWithCoords &other) const;\n\n    /// Standard methods for easy testing.\n    bool operator==(const DemTargetWithCoords &other) const;\n    bool operator!=(const DemTargetWithCoords &other) const;\n    std::string str() const;\n};\n\n/// Stores additional details about measurement errors.\nstruct FlippedMeasurement {\n    /// Which output bit this measurement corresponds to.\n    /// UINT64_MAX means \"no measurement error occurred\".\n    uint64_t measurement_record_index;\n    /// Which observable this measurement was responsible for measuring.\n    std::vector<GateTargetWithCoords> measured_observable;\n\n    bool operator<(const FlippedMeasurement &other) const;\n\n    /// Standard methods for easy testing.\n    bool operator==(const FlippedMeasurement &other) const;\n    bool operator!=(const FlippedMeasurement &other) const;\n    std::string str() const;\n};\n\n/// Describes a specific range of targets within a parameterized instruction.\nstruct CircuitTargetsInsideInstruction {\n    /// The instruction type.\n    GateType gate_type;\n    std::string gate_tag;\n\n    /// The parens arguments for the instruction.\n    std::vector<double> args;\n\n    /// The range of targets within the instruction that were executing.\n    size_t target_range_start;\n    size_t target_range_end;\n    std::vector<GateTargetWithCoords> targets_in_range;\n\n    void fill_args_and_targets_in_range(\n        const CircuitInstruction &actual_op, const std::map<uint64_t, std::vector<double>> &qubit_coords);\n\n    bool operator<(const CircuitTargetsInsideInstruction &other) const;\n\n    /// Standard methods for easy testing.\n    bool operator==(const CircuitTargetsInsideInstruction &other) const;\n    bool operator!=(const CircuitTargetsInsideInstruction &other) const;\n    std::string str() const;\n};\n\n/// Describes the location of an error within a circuit, with as much extra information\n/// as possible in order to make it easier for users to grok the location.\nstruct CircuitErrorLocation {\n    /// The tag on the noise instruction.\n    std::string noise_tag;\n\n    /// The number of ticks that have been executed by this point.\n    uint64_t tick_offset;\n\n    /// The pauli terms corresponding to the circuit error.\n    /// For non-measurement errors, this is the actual pauli error that triggers the problem.\n    /// For measurement errors, this is the observable that was being measured.\n    std::vector<GateTargetWithCoords> flipped_pauli_product;\n\n    /// Determines if the circuit error was a measurement error.\n    /// UINT64_MAX means NOT a measurement error.\n    /// Other values refer to a specific measurement index in the measurement record.\n    FlippedMeasurement flipped_measurement;\n\n    /// These two values identify a specific range of targets within the executing instruction.\n    CircuitTargetsInsideInstruction instruction_targets;\n\n    // Stack trace within the circuit and nested loop blocks.\n    std::vector<CircuitErrorLocationStackFrame> stack_frames;\n\n    void canonicalize();\n    bool operator<(const CircuitErrorLocation &other) const;\n    bool is_simpler_than(const CircuitErrorLocation &other) const;\n\n    /// Standard methods for easy testing.\n    bool operator==(const CircuitErrorLocation &other) const;\n    bool operator!=(const CircuitErrorLocation &other) const;\n    std::string str() const;\n};\n\n/// Explains how an error from a detector error model matches error(s) from a circuit.\nstruct ExplainedError {\n    /// A sorted list of detector and observable targets flipped by the error.\n    /// This list should never contain target separators.\n    std::vector<DemTargetWithCoords> dem_error_terms;\n\n    /// Locations of matching errors in the circuit.\n    std::vector<CircuitErrorLocation> circuit_error_locations;\n\n    void fill_in_dem_targets(\n        SpanRef<const DemTarget> targets, const std::map<uint64_t, std::vector<double>> &dem_coords);\n\n    void canonicalize();\n\n    /// Standard methods for easy testing.\n    std::string str() const;\n    bool operator==(const ExplainedError &other) const;\n    bool operator!=(const ExplainedError &other) const;\n};\n\nstd::ostream &operator<<(std::ostream &out, const CircuitErrorLocation &e);\nstd::ostream &operator<<(std::ostream &out, const CircuitErrorLocationStackFrame &e);\nstd::ostream &operator<<(std::ostream &out, const CircuitTargetsInsideInstruction &e);\nstd::ostream &operator<<(std::ostream &out, const DemTargetWithCoords &e);\nstd::ostream &operator<<(std::ostream &out, const FlippedMeasurement &e);\nstd::ostream &operator<<(std::ostream &out, const GateTargetWithCoords &e);\nstd::ostream &operator<<(std::ostream &out, const ExplainedError &e);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/matched_error.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/matched_error.pybind.h\"\n\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/circuit/gate_target.pybind.h\"\n#include \"stim/dem/detector_error_model_target.pybind.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/simulators/matched_error.h\"\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nstd::string CircuitErrorLocationStackFrame_repr(const CircuitErrorLocationStackFrame &self) {\n    std::stringstream out;\n    out << \"stim.CircuitErrorLocationStackFrame(\";\n    out << \"\\n    instruction_offset=\" << self.instruction_offset << \",\";\n    out << \"\\n    iteration_index=\" << self.iteration_index << \",\";\n    out << \"\\n    instruction_repetitions_arg=\" << self.instruction_repetitions_arg << \",\";\n    out << \"\\n)\";\n    return out.str();\n}\n\nstd::string DemTargetWithCoords_repr(const DemTargetWithCoords &self) {\n    std::stringstream out;\n    out << \"stim.DemTargetWithCoords\";\n    out << \"(dem_target=\" << ExposedDemTarget(self.dem_target).repr();\n    out << \", coords=[\" << comma_sep(self.coords) << \"]\";\n    out << \")\";\n    return out.str();\n}\n\npybind11::ssize_t CircuitTargetsInsideInstruction_hash(const CircuitTargetsInsideInstruction &self) {\n    return pybind11::hash(\n        pybind11::make_tuple(\n            \"CircuitTargetsInsideInstruction\",\n            self.gate_type == GateType::NOT_A_GATE ? std::string_view(\"\") : GATE_DATA[self.gate_type].name,\n            self.target_range_start,\n            self.target_range_end,\n            tuple_tree(self.targets_in_range),\n            tuple_tree(self.args)));\n}\n\nstd::string GateTargetWithCoords_repr(const GateTargetWithCoords &self) {\n    std::stringstream out;\n    out << \"stim.GateTargetWithCoords\";\n    out << \"(\" << self.gate_target;\n    out << \", [\" << comma_sep(self.coords) << \"]\";\n    out << \")\";\n    return out.str();\n}\n\nstd::string FlippedMeasurement_repr(const FlippedMeasurement &self) {\n    std::stringstream out;\n    out << \"stim.FlippedMeasurement(\";\n    out << \"\\n    record_index=\";\n    if (self.measurement_record_index == UINT64_MAX) {\n        out << \"None\";\n    } else {\n        out << self.measurement_record_index;\n    }\n    out << \",\\n    observable=(\";\n    for (const auto &e : self.measured_observable) {\n        out << GateTargetWithCoords_repr(e) << \",\";\n    }\n    out << \"),\\n)\";\n    return out.str();\n}\n\nstd::string CircuitTargetsInsideInstruction_repr(const CircuitTargetsInsideInstruction &self) {\n    std::stringstream out;\n    out << \"stim.CircuitTargetsInsideInstruction\";\n    out << \"(gate='\" << (self.gate_type == GateType::NOT_A_GATE ? \"NULL\" : GATE_DATA[self.gate_type].name) << \"'\";\n    out << \", args=[\" << comma_sep(self.args) << \"]\";\n    out << \", target_range_start=\" << self.target_range_start;\n    out << \", target_range_end=\" << self.target_range_end;\n    out << \", targets_in_range=(\";\n    for (const auto &e : self.targets_in_range) {\n        out << GateTargetWithCoords_repr(e) << \",\";\n    }\n    out << \"))\";\n    return out.str();\n}\n\nstd::string CircuitErrorLocation_repr(const CircuitErrorLocation &self) {\n    std::stringstream out;\n    out << \"stim.CircuitErrorLocation\";\n    out << \"(tick_offset=\" << self.tick_offset;\n\n    out << \", flipped_pauli_product=(\";\n    for (const auto &e : self.flipped_pauli_product) {\n        out << GateTargetWithCoords_repr(e) << \",\";\n    }\n    out << \")\";\n\n    out << \", flipped_measurement=\" << FlippedMeasurement_repr(self.flipped_measurement);\n    out << \", instruction_targets=\" << CircuitTargetsInsideInstruction_repr(self.instruction_targets);\n\n    out << \", stack_frames=(\";\n    for (const auto &e : self.stack_frames) {\n        out << CircuitErrorLocationStackFrame_repr(e) << \",\";\n    }\n    out << \")\";\n\n    out << \")\";\n    return out.str();\n}\n\nstd::string MatchedError_repr(const ExplainedError &self) {\n    std::stringstream out;\n    out << \"stim.ExplainedError\";\n    out << \"(dem_error_terms=(\";\n    for (const auto &e : self.dem_error_terms) {\n        out << DemTargetWithCoords_repr(e) << \",\";\n    }\n    out << \")\";\n\n    out << \", circuit_error_locations=(\";\n    for (const auto &e : self.circuit_error_locations) {\n        out << CircuitErrorLocation_repr(e) << \",\";\n    }\n    out << \")\";\n\n    out << \")\";\n    return out.str();\n}\n\npybind11::class_<CircuitErrorLocationStackFrame> stim_pybind::pybind_circuit_error_location_stack_frame(\n    pybind11::module &m) {\n    return pybind11::class_<CircuitErrorLocationStackFrame>(\n        m,\n        \"CircuitErrorLocationStackFrame\",\n        clean_doc_string(R\"DOC(\n            Describes the location of an instruction being executed within a\n            circuit or loop, distinguishing between separate loop iterations.\n\n            The full location of an instruction is a list of these frames,\n            drilling down from the top level circuit to the inner-most loop\n            that the instruction is within.\n\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     REPEAT 5 {\n                ...         R 0\n                ...         Y_ERROR(0.125) 0\n                ...         M 0\n                ...     }\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].stack_frames[0]\n                stim.CircuitErrorLocationStackFrame(\n                    instruction_offset=0,\n                    iteration_index=0,\n                    instruction_repetitions_arg=5,\n                )\n                >>> err[0].circuit_error_locations[0].stack_frames[1]\n                stim.CircuitErrorLocationStackFrame(\n                    instruction_offset=1,\n                    iteration_index=4,\n                    instruction_repetitions_arg=0,\n                )\n            )DOC\")\n            .data());\n}\nvoid stim_pybind::pybind_circuit_error_location_stack_frame_methods(\n    pybind11::module &m, pybind11::class_<stim::CircuitErrorLocationStackFrame> &c) {\n    c.def_readonly(\n        \"instruction_offset\",\n        &CircuitErrorLocationStackFrame::instruction_offset,\n        clean_doc_string(R\"DOC(\n            The index of the instruction within the circuit, or within the\n            instruction's parent REPEAT block. This is slightly different\n            from the line number, because blank lines and commented lines\n            don't count and also because the offset of the first instruction\n            is 0 instead of 1.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     TICK\n                ...     Y_ERROR(0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].stack_frames[0].instruction_offset\n                2\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"iteration_index\",\n        &CircuitErrorLocationStackFrame::iteration_index,\n        clean_doc_string(R\"DOC(\n            Disambiguates which iteration of the loop containing this instruction\n            is being referred to. If the instruction isn't in a REPEAT block, this\n            field defaults to 0.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     REPEAT 5 {\n                ...         R 0\n                ...         Y_ERROR(0.125) 0\n                ...         M 0\n                ...     }\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> full = err[0].circuit_error_locations[0].stack_frames[0]\n                >>> loop = err[0].circuit_error_locations[0].stack_frames[1]\n                >>> full.iteration_index\n                0\n                >>> loop.iteration_index\n                4\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"instruction_repetitions_arg\",\n        &CircuitErrorLocationStackFrame::instruction_repetitions_arg,\n        clean_doc_string(R\"DOC(\n            If the instruction being referred to is a REPEAT block,\n            this is the repetition count of that REPEAT block. Otherwise\n            this field defaults to 0.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     REPEAT 5 {\n                ...         R 0\n                ...         Y_ERROR(0.125) 0\n                ...         M 0\n                ...     }\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> full = err[0].circuit_error_locations[0].stack_frames[0]\n                >>> loop = err[0].circuit_error_locations[0].stack_frames[1]\n                >>> full.instruction_repetitions_arg\n                5\n                >>> loop.instruction_repetitions_arg\n                0\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self);\n    c.def(pybind11::self != pybind11::self);\n    c.def(\"__hash__\", [](const CircuitErrorLocationStackFrame &self) {\n        return pybind11::hash(\n            pybind11::make_tuple(\n                \"CircuitErrorLocationStackFrame\",\n                self.instruction_offset,\n                self.iteration_index,\n                self.instruction_repetitions_arg));\n    });\n    c.def(\n        pybind11::init(\n            [](uint64_t instruction_offset,\n               uint64_t iteration_index,\n               uint64_t instruction_repetitions_arg) -> CircuitErrorLocationStackFrame {\n                return CircuitErrorLocationStackFrame{instruction_offset, iteration_index, instruction_repetitions_arg};\n            }),\n        pybind11::kw_only(),\n        pybind11::arg(\"instruction_offset\"),\n        pybind11::arg(\"iteration_index\"),\n        pybind11::arg(\"instruction_repetitions_arg\"),\n        clean_doc_string(R\"DOC(\n            Creates a stim.CircuitErrorLocationStackFrame.\n\n            Examples:\n                >>> import stim\n                >>> frame = stim.CircuitErrorLocationStackFrame(\n                ...     instruction_offset=1,\n                ...     iteration_index=2,\n                ...     instruction_repetitions_arg=3,\n                ... )\n        )DOC\")\n            .data());\n    c.def(\"__str__\", &CircuitErrorLocationStackFrame_repr);\n    c.def(\"__repr__\", &CircuitErrorLocationStackFrame_repr);\n}\n\npybind11::class_<GateTargetWithCoords> stim_pybind::pybind_gate_target_with_coords(pybind11::module &m) {\n    return pybind11::class_<GateTargetWithCoords>(\n        m,\n        \"GateTargetWithCoords\",\n        clean_doc_string(R\"DOC(\n            A gate target with associated coordinate information.\n\n            For example, if the gate target is a qubit from a circuit with\n            QUBIT_COORDS instructions, the coords field will contain the\n            coordinate data from the QUBIT_COORDS instruction for the qubit.\n\n            This is helpful information to have available when debugging a\n            problem in a circuit, instead of having to constantly manually\n            look up the coordinates of a qubit index in order to understand\n            what is happening.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n                >>> t.gate_target\n                stim.GateTarget(0)\n                >>> t.coords\n                [1.5, 2.0]\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_gate_target_with_coords_methods(\n    pybind11::module &m, pybind11::class_<stim::GateTargetWithCoords> &c) {\n    c.def_readonly(\n        \"gate_target\",\n        &GateTargetWithCoords::gate_target,\n        clean_doc_string(R\"DOC(\n            Returns the actual gate target as a `stim.GateTarget`.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n                >>> t.gate_target\n                stim.GateTarget(0)\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"coords\",\n        &GateTargetWithCoords::coords,\n        clean_doc_string(R\"DOC(\n            Returns the associated coordinate information as a list of floats.\n\n            If there is no coordinate information, returns an empty list.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n                >>> t.coords\n                [1.5, 2.0]\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self);\n    c.def(pybind11::self != pybind11::self);\n    c.def(\"__hash__\", [](const GateTargetWithCoords &self) {\n        return pybind11::hash(pybind11::make_tuple(\"GateTargetWithCoords\", self.gate_target, tuple_tree(self.coords)));\n    });\n    c.def(\"__str__\", &GateTargetWithCoords::str);\n    c.def(\n        pybind11::init(\n            [](const pybind11::object &gate_target, const std::vector<double> &coords) -> GateTargetWithCoords {\n                return GateTargetWithCoords{obj_to_gate_target(gate_target), coords};\n            }),\n        pybind11::arg(\"gate_target\"),\n        pybind11::arg(\"coords\"),\n        clean_doc_string(R\"DOC(\n            Creates a stim.GateTargetWithCoords.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.GateTargetWithCoords(0, [1.5, 2.0])\n                >>> t.gate_target\n                stim.GateTarget(0)\n                >>> t.coords\n                [1.5, 2.0]\n        )DOC\")\n            .data());\n    c.def(\"__repr__\", &GateTargetWithCoords_repr);\n}\n\npybind11::class_<DemTargetWithCoords> stim_pybind::pybind_dem_target_with_coords(pybind11::module &m) {\n    return pybind11::class_<DemTargetWithCoords>(\n        m,\n        \"DemTargetWithCoords\",\n        clean_doc_string(R\"DOC(\n            A detector error model instruction target with associated coords.\n\n            It is also guaranteed that, if the type of the DEM target is a\n            relative detector id, it is actually absolute (i.e. relative to\n            0).\n\n            For example, if the DEM target is a detector from a circuit with\n            coordinate arguments given to detectors, the coords field will\n            contain the coordinate data for the detector.\n\n            This is helpful information to have available when debugging a\n            problem in a circuit, instead of having to constantly manually\n            look up the coordinates of a detector index in order to understand\n            what is happening.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.DemTargetWithCoords(stim.DemTarget(\"D1\"), [1.5, 2.0])\n                >>> t.dem_target\n                stim.DemTarget('D1')\n                >>> t.coords\n                [1.5, 2.0]\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_dem_target_with_coords_methods(\n    pybind11::module &m, pybind11::class_<stim::DemTargetWithCoords> &c) {\n    c.def_property_readonly(\n        \"dem_target\",\n        [](const DemTargetWithCoords &self) -> ExposedDemTarget {\n            return ExposedDemTarget(self.dem_target);\n        },\n        clean_doc_string(R\"DOC(\n            Returns the actual DEM target as a `stim.DemTarget`.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0 1\n                ...     X_ERROR(0.25) 0 1\n                ...     M 0 1\n                ...     DETECTOR(2, 3) rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].dem_error_terms[0].dem_target\n                stim.DemTarget('D0')\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"coords\",\n        &DemTargetWithCoords::coords,\n        clean_doc_string(R\"DOC(\n            Returns the associated coordinate information as a list of floats.\n\n            If there is no coordinate information, returns an empty list.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0 1\n                ...     X_ERROR(0.25) 0 1\n                ...     M 0 1\n                ...     DETECTOR(2, 3) rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].dem_error_terms[0].coords\n                [2.0, 3.0]\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self);\n    c.def(pybind11::self != pybind11::self);\n    c.def(\"__hash__\", [](const DemTargetWithCoords &self) {\n        return pybind11::hash(\n            pybind11::make_tuple(\"DemTargetWithCoords\", self.dem_target.data, tuple_tree(self.coords)));\n    });\n    c.def(\"__str__\", &DemTargetWithCoords::str);\n    c.def(\n        pybind11::init(\n            [](const ExposedDemTarget &dem_target, const std::vector<double> &coords) -> DemTargetWithCoords {\n                return DemTargetWithCoords{dem_target, coords};\n            }),\n        pybind11::arg(\"dem_target\"),\n        pybind11::arg(\"coords\"),\n        clean_doc_string(R\"DOC(\n            Creates a stim.DemTargetWithCoords.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0 1\n                ...     X_ERROR(0.25) 0 1\n                ...     M 0 1\n                ...     DETECTOR(2, 3) rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].dem_error_terms[0]\n                stim.DemTargetWithCoords(dem_target=stim.DemTarget('D0'), coords=[2, 3])\n        )DOC\")\n            .data());\n    c.def(\"__repr__\", DemTargetWithCoords_repr);\n}\n\npybind11::class_<FlippedMeasurement> stim_pybind::pybind_flipped_measurement(pybind11::module &m) {\n    return pybind11::class_<FlippedMeasurement>(\n        m,\n        \"FlippedMeasurement\",\n        clean_doc_string(R\"DOC(\n            Describes a measurement that was flipped.\n\n            Gives the measurement's index in the measurement record, and also\n            the observable of the measurement.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     M(0.25) 1 10\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].flipped_measurement\n                stim.FlippedMeasurement(\n                    record_index=1,\n                    observable=(stim.GateTargetWithCoords(stim.target_z(10), []),),\n                )\n        )DOC\")\n            .data());\n}\nvoid stim_pybind::pybind_flipped_measurement_methods(\n    pybind11::module &m, pybind11::class_<stim::FlippedMeasurement> &c) {\n    c.def_readonly(\n        \"record_index\",\n        &FlippedMeasurement::measurement_record_index,\n        clean_doc_string(R\"DOC(\n            The measurement record index of the flipped measurement.\n            For example, the fifth measurement in a circuit has a measurement\n            record index of 4.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     M(0.25) 1 10\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].flipped_measurement.record_index\n                1\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"observable\",\n        &FlippedMeasurement::measured_observable,\n        clean_doc_string(R\"DOC(\n            Returns the observable of the flipped measurement.\n\n            For example, an `MX 5` measurement will have the observable X5.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     M(0.25) 1 10\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].flipped_measurement.observable\n                [stim.GateTargetWithCoords(stim.target_z(10), [])]\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self);\n    c.def(pybind11::self != pybind11::self);\n    c.def(\"__hash__\", [](const FlippedMeasurement &self) {\n        return pybind11::hash(\n            pybind11::make_tuple(\n                \"FlippedMeasurement\", self.measurement_record_index, tuple_tree(self.measured_observable)));\n    });\n    c.def(\n        pybind11::init(\n            [](const pybind11::object &measurement_record_index,\n               const pybind11::object &measured_observable) -> FlippedMeasurement {\n                uint64_t u;\n                if (measurement_record_index.is_none()) {\n                    u = UINT64_MAX;\n                } else {\n                    u = pybind11::cast<uint64_t>(measurement_record_index);\n                }\n                FlippedMeasurement result{u, {}};\n                for (const auto &e : measured_observable) {\n                    result.measured_observable.push_back(pybind11::cast<GateTargetWithCoords>(e));\n                }\n                return result;\n            }),\n        pybind11::kw_only(),\n        pybind11::arg(\"record_index\"),\n        pybind11::arg(\"observable\"),\n        clean_doc_string(R\"DOC(\n            @signature def __init__(self, measurement_record_index: Optional[int], measured_observable: Iterable[stim.GateTargetWithCoords]):\n            Creates a stim.FlippedMeasurement.\n\n            Examples:\n                >>> import stim\n                >>> print(stim.FlippedMeasurement(\n                ...     record_index=5,\n                ...     observable=[],\n                ... ))\n                stim.FlippedMeasurement(\n                    record_index=5,\n                    observable=(),\n                )\n        )DOC\")\n            .data());\n    c.def(\"__repr__\", &FlippedMeasurement_repr);\n    c.def(\"__str__\", &FlippedMeasurement_repr);\n}\n\npybind11::class_<CircuitTargetsInsideInstruction> stim_pybind::pybind_circuit_targets_inside_instruction(\n    pybind11::module &m) {\n    return pybind11::class_<CircuitTargetsInsideInstruction>(\n        m,\n        \"CircuitTargetsInsideInstruction\",\n        clean_doc_string(R\"DOC(\n            Describes a range of targets within a circuit instruction.\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_circuit_targets_inside_instruction_methods(\n    pybind11::module &m, pybind11::class_<stim::CircuitTargetsInsideInstruction> &c) {\n    c.def_property_readonly(\n        \"gate\",\n        [](const CircuitTargetsInsideInstruction &self) -> pybind11::object {\n            if (self.gate_type == GateType::NOT_A_GATE) {\n                return pybind11::none();\n            }\n            return pybind11::str(GATE_DATA[self.gate_type].name);\n        },\n        clean_doc_string(R\"DOC(\n            Returns the name of the gate / instruction that was being executed.\n            @signature def gate(self) -> Optional[str]:\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0 1\n                ...     X_ERROR(0.25) 0 1\n                ...     M 0 1\n                ...     DETECTOR(2, 3) rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n                >>> loc.instruction_targets.gate\n                'X_ERROR'\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"tag\",\n        [](const CircuitTargetsInsideInstruction &self) {\n            return self.gate_tag;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the tag of the gate / instruction that was being executed.\n            @signature def tag(self) -> str:\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0 1\n                ...     X_ERROR[look-at-me-imma-tag](0.25) 0 1\n                ...     M 0 1\n                ...     DETECTOR(2, 3) rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n                >>> loc.instruction_targets.tag\n                'look-at-me-imma-tag'\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"target_range_start\",\n        &CircuitTargetsInsideInstruction::target_range_start,\n        clean_doc_string(R\"DOC(\n            Returns the inclusive start of the range of targets that were executing\n            within the gate / instruction.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0 1\n                ...     X_ERROR(0.25) 0 1\n                ...     M 0 1\n                ...     DETECTOR(2, 3) rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n                >>> loc.instruction_targets.target_range_start\n                0\n                >>> loc.instruction_targets.target_range_end\n                1\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"target_range_end\",\n        &CircuitTargetsInsideInstruction::target_range_end,\n        clean_doc_string(R\"DOC(\n            Returns the exclusive end of the range of targets that were executing\n            within the gate / instruction.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0 1\n                ...     X_ERROR(0.25) 0 1\n                ...     M 0 1\n                ...     DETECTOR(2, 3) rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n                >>> loc.instruction_targets.target_range_start\n                0\n                >>> loc.instruction_targets.target_range_end\n                1\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"args\",\n        &CircuitTargetsInsideInstruction::args,\n        clean_doc_string(R\"DOC(\n            Returns parens arguments of the gate / instruction that was being executed.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0 1\n                ...     X_ERROR(0.25) 0 1\n                ...     M 0 1\n                ...     DETECTOR(2, 3) rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n                >>> loc.instruction_targets.args\n                [0.25]\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"targets_in_range\",\n        &CircuitTargetsInsideInstruction::targets_in_range,\n        clean_doc_string(R\"DOC(\n            Returns the subset of targets of the gate/instruction that were being executed.\n\n            Includes coordinate data with the targets.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0 1\n                ...     X_ERROR(0.25) 0 1\n                ...     M 0 1\n                ...     DETECTOR(2, 3) rec[-1] rec[-2]\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> loc: stim.CircuitErrorLocation = err[0].circuit_error_locations[0]\n                >>> loc.instruction_targets.targets_in_range\n                [stim.GateTargetWithCoords(0, [])]\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self);\n    c.def(pybind11::self != pybind11::self);\n    c.def(\"__hash__\", &CircuitTargetsInsideInstruction_hash);\n    c.def(\n        pybind11::init(\n            [](std::string_view gate,\n               std::string_view tag,\n               const std::vector<double> &args,\n               size_t target_range_start,\n               size_t target_range_end,\n               const std::vector<GateTargetWithCoords> &targets_in_range) -> CircuitTargetsInsideInstruction {\n                CircuitTargetsInsideInstruction result{\n                    GATE_DATA.at(gate).id,\n                    std::string(tag),\n                    args,\n                    target_range_start,\n                    target_range_end,\n                    targets_in_range};\n                return result;\n            }),\n        pybind11::kw_only(),\n        pybind11::arg(\"gate\"),\n        pybind11::arg(\"tag\") = \"\",\n        pybind11::arg(\"args\"),\n        pybind11::arg(\"target_range_start\"),\n        pybind11::arg(\"target_range_end\"),\n        pybind11::arg(\"targets_in_range\"),\n        clean_doc_string(R\"DOC(\n            Creates a stim.CircuitTargetsInsideInstruction.\n\n            Examples:\n                >>> import stim\n                >>> val = stim.CircuitTargetsInsideInstruction(\n                ...     gate='X_ERROR',\n                ...     tag='',\n                ...     args=[0.25],\n                ...     target_range_start=0,\n                ...     target_range_end=1,\n                ...     targets_in_range=[stim.GateTargetWithCoords(0, [])],\n                ... )\n        )DOC\")\n            .data());\n    c.def(\"__repr__\", &CircuitTargetsInsideInstruction_repr);\n    c.def(\"__str__\", &CircuitTargetsInsideInstruction::str);\n}\n\npybind11::class_<CircuitErrorLocation> stim_pybind::pybind_circuit_error_location(pybind11::module &m) {\n    return pybind11::class_<CircuitErrorLocation>(\n        m,\n        \"CircuitErrorLocation\",\n        clean_doc_string(R\"DOC(\n            Describes the location of an error mechanism from a stim circuit.\n\n            Examples:\n                >>> import stim\n                >>> circuit = stim.Circuit.generated(\n                ...     \"repetition_code:memory\",\n                ...     distance=5,\n                ...     rounds=5,\n                ...     before_round_data_depolarization=1e-3,\n                ... )\n                >>> logical_error = circuit.shortest_graphlike_error()\n                >>> error_location = logical_error[0].circuit_error_locations[0]\n                >>> print(error_location)\n                CircuitErrorLocation {\n                    flipped_pauli_product: X0\n                    Circuit location stack trace:\n                        (after 1 TICKs)\n                        at instruction #3 (DEPOLARIZE1) in the circuit\n                        at target #1 of the instruction\n                        resolving to DEPOLARIZE1(0.001) 0\n                }\n            )DOC\")\n            .data());\n}\nvoid stim_pybind::pybind_circuit_error_location_methods(\n    pybind11::module &m, pybind11::class_<stim::CircuitErrorLocation> &c) {\n    c.def_readonly(\n        \"tick_offset\",\n        &CircuitErrorLocation::tick_offset,\n        clean_doc_string(R\"DOC(\n            The number of TICKs that executed before the error happened.\n\n            This counts TICKs occurring multiple times during loops.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     TICK\n                ...     TICK\n                ...     TICK\n                ...     Y_ERROR(0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].tick_offset\n                3\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"noise_tag\",\n        &CircuitErrorLocation::noise_tag,\n        clean_doc_string(R\"DOC(\n            The tag on the noise instruction that caused the error.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     Y_ERROR[test-tag](0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].noise_tag\n                'test-tag'\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"flipped_pauli_product\",\n        &CircuitErrorLocation::flipped_pauli_product,\n        clean_doc_string(R\"DOC(\n            The Pauli errors that the error mechanism applied to qubits.\n\n            When the error is a measurement error, this will be an empty list.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     Y_ERROR(0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].flipped_pauli_product\n                [stim.GateTargetWithCoords(stim.target_y(0), [])]\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"flipped_measurement\",\n        [](const CircuitErrorLocation &self) -> pybind11::object {\n            if (self.flipped_measurement.measured_observable.empty()) {\n                return pybind11::none();\n            }\n            return pybind11::cast(self.flipped_measurement);\n        },\n        clean_doc_string(R\"DOC(\n            @signature def flipped_measurement(self) -> Optional[stim.FlippedMeasurement]:\n            The measurement that was flipped by the error mechanism.\n\n            If the error isn't a measurement error, this will be None.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     M(0.125) 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].flipped_measurement\n                stim.FlippedMeasurement(\n                    record_index=0,\n                    observable=(stim.GateTargetWithCoords(stim.target_z(0), []),),\n                )\n\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"instruction_targets\",\n        &CircuitErrorLocation::instruction_targets,\n        clean_doc_string(R\"DOC(\n            Within the error instruction, which may have hundreds of\n            targets, which specific targets were being executed to\n            produce the error.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     TICK\n                ...     Y_ERROR(0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> targets = err[0].circuit_error_locations[0].instruction_targets\n                >>> targets == stim.CircuitTargetsInsideInstruction(\n                ...     gate='Y_ERROR',\n                ...     args=[0.125],\n                ...     target_range_start=0,\n                ...     target_range_end=1,\n                ...     targets_in_range=(stim.GateTargetWithCoords(0, []),),\n                ... )\n                True\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"stack_frames\",\n        &CircuitErrorLocation::stack_frames,\n        clean_doc_string(R\"DOC(\n            Describes where in the circuit's execution the error happened.\n\n            Multiple frames are needed because the error may occur within a loop,\n            or a loop nested inside a loop, or etc.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     TICK\n                ...     Y_ERROR(0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> err[0].circuit_error_locations[0].stack_frames\n                [stim.CircuitErrorLocationStackFrame(\n                    instruction_offset=2,\n                    iteration_index=0,\n                    instruction_repetitions_arg=0,\n                )]\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self);\n    c.def(pybind11::self != pybind11::self);\n    c.def(\"__hash__\", [](const CircuitErrorLocation &self) {\n        return pybind11::hash(\n            pybind11::make_tuple(\n                \"CircuitErrorLocation\",\n                self.tick_offset,\n                tuple_tree(self.flipped_pauli_product),\n                self.flipped_measurement,\n                self.instruction_targets,\n                tuple_tree(self.stack_frames)));\n    });\n    c.def(\n        pybind11::init(\n            [](uint64_t tick_offset,\n               const std::vector<GateTargetWithCoords> &flipped_pauli_product,\n               const pybind11::object &flipped_measurement,\n               const CircuitTargetsInsideInstruction &instruction_targets,\n               const std::vector<CircuitErrorLocationStackFrame> &stack_frames,\n               std::string_view noise_tag) -> CircuitErrorLocation {\n                FlippedMeasurement m{0, {}};\n                if (!flipped_measurement.is_none()) {\n                    m = pybind11::cast<FlippedMeasurement>(flipped_measurement);\n                }\n                CircuitErrorLocation result{\n                    std::string(noise_tag), tick_offset, flipped_pauli_product, m, instruction_targets, stack_frames};\n                return result;\n            }),\n        pybind11::kw_only(),\n        pybind11::arg(\"tick_offset\"),\n        pybind11::arg(\"flipped_pauli_product\"),\n        pybind11::arg(\"flipped_measurement\"),\n        pybind11::arg(\"instruction_targets\"),\n        pybind11::arg(\"stack_frames\"),\n        pybind11::arg(\"noise_tag\") = \"\",\n        clean_doc_string(R\"DOC(\n            Creates a stim.CircuitErrorLocation.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.CircuitErrorLocation(\n                ...     tick_offset=1,\n                ...     flipped_pauli_product=(\n                ...         stim.GateTargetWithCoords(\n                ...             gate_target=stim.target_x(0),\n                ...             coords=[],\n                ...         ),\n                ...     ),\n                ...     flipped_measurement=stim.FlippedMeasurement(\n                ...         record_index=None,\n                ...         observable=(),\n                ...     ),\n                ...     instruction_targets=stim.CircuitTargetsInsideInstruction(\n                ...         gate='DEPOLARIZE1',\n                ...         args=[0.001],\n                ...         target_range_start=0,\n                ...         target_range_end=1,\n                ...         targets_in_range=(stim.GateTargetWithCoords(\n                ...             gate_target=0,\n                ...             coords=[],\n                ...         ),)\n                ...     ),\n                ...     stack_frames=(\n                ...         stim.CircuitErrorLocationStackFrame(\n                ...             instruction_offset=2,\n                ...             iteration_index=0,\n                ...             instruction_repetitions_arg=0,\n                ...         ),\n                ...     ),\n                ...     noise_tag='test-tag',\n                ... )\n                >>> print(err)\n                CircuitErrorLocation {\n                    noise_tag: test-tag\n                    flipped_pauli_product: X0\n                    Circuit location stack trace:\n                        (after 1 TICKs)\n                        at instruction #3 (DEPOLARIZE1) in the circuit\n                        at target #1 of the instruction\n                        resolving to DEPOLARIZE1(0.001) 0\n                }\n        )DOC\")\n            .data());\n    c.def(\"__repr__\", &CircuitErrorLocation_repr);\n    c.def(\"__str__\", &CircuitErrorLocation::str);\n}\n\npybind11::class_<ExplainedError> stim_pybind::pybind_explained_error(pybind11::module &m) {\n    return pybind11::class_<ExplainedError>(\n        m,\n        \"ExplainedError\",\n        clean_doc_string(R\"DOC(\n            Describes the location of an error mechanism from a stim circuit.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     TICK\n                ...     Y_ERROR(0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> print(err[0])\n                ExplainedError {\n                    dem_error_terms: L0\n                    CircuitErrorLocation {\n                        flipped_pauli_product: Y0\n                        Circuit location stack trace:\n                            (after 1 TICKs)\n                            at instruction #3 (Y_ERROR) in the circuit\n                            at target #1 of the instruction\n                            resolving to Y_ERROR(0.125) 0\n                    }\n                }\n        )DOC\")\n            .data());\n}\nvoid stim_pybind::pybind_explained_error_methods(pybind11::module &m, pybind11::class_<stim::ExplainedError> &c) {\n    c.def_readonly(\n        \"dem_error_terms\",\n        &ExplainedError::dem_error_terms,\n        clean_doc_string(R\"DOC(\n            The detectors and observables flipped by this error mechanism.\n        )DOC\")\n            .data());\n\n    c.def_readonly(\n        \"circuit_error_locations\",\n        &ExplainedError::circuit_error_locations,\n        clean_doc_string(R\"DOC(\n            The locations of circuit errors that produce the symptoms in dem_error_terms.\n\n            Note: if this list contains a single entry, it may be because a result\n            with a single representative error was requested (as opposed to all possible\n            errors).\n\n            Note: if this list is empty, it may be because there was a DEM error decomposed\n            into parts where one of the parts is impossible to make on its own from a single\n            circuit error.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     TICK\n                ...     Y_ERROR(0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> print(err[0].circuit_error_locations[0])\n                CircuitErrorLocation {\n                    flipped_pauli_product: Y0\n                    Circuit location stack trace:\n                        (after 1 TICKs)\n                        at instruction #3 (Y_ERROR) in the circuit\n                        at target #1 of the instruction\n                        resolving to Y_ERROR(0.125) 0\n                }\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self);\n    c.def(pybind11::self != pybind11::self);\n    c.def(\"__hash__\", [](const ExplainedError &self) {\n        return pybind11::hash(\n            pybind11::make_tuple(\n                \"ExplainedError\", tuple_tree(self.dem_error_terms), tuple_tree(self.circuit_error_locations)));\n    });\n    c.def(\n        pybind11::init(\n            [](const std::vector<DemTargetWithCoords> dem_error_terms,\n               const std::vector<CircuitErrorLocation> &circuit_error_locations) -> ExplainedError {\n                ExplainedError result{\n                    dem_error_terms,\n                    circuit_error_locations,\n                };\n                return result;\n            }),\n        pybind11::kw_only(),\n        pybind11::arg(\"dem_error_terms\"),\n        pybind11::arg(\"circuit_error_locations\"),\n        clean_doc_string(R\"DOC(\n            Creates a stim.ExplainedError.\n\n            Examples:\n                >>> import stim\n                >>> err = stim.Circuit('''\n                ...     R 0\n                ...     TICK\n                ...     Y_ERROR(0.125) 0\n                ...     M 0\n                ...     OBSERVABLE_INCLUDE(0) rec[-1]\n                ... ''').shortest_graphlike_error()\n                >>> print(err[0])\n                ExplainedError {\n                    dem_error_terms: L0\n                    CircuitErrorLocation {\n                        flipped_pauli_product: Y0\n                        Circuit location stack trace:\n                            (after 1 TICKs)\n                            at instruction #3 (Y_ERROR) in the circuit\n                            at target #1 of the instruction\n                            resolving to Y_ERROR(0.125) 0\n                    }\n                }\n        )DOC\")\n            .data());\n    c.def(\"__repr__\", &MatchedError_repr);\n    c.def(\"__str__\", &ExplainedError::str);\n}\n"
  },
  {
    "path": "src/stim/simulators/matched_error.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_SIMULATORS_MATCHED_ERROR_PYBIND_H\n#define _STIM_SIMULATORS_MATCHED_ERROR_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/simulators/matched_error.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::CircuitErrorLocationStackFrame> pybind_circuit_error_location_stack_frame(pybind11::module &m);\npybind11::class_<stim::GateTargetWithCoords> pybind_gate_target_with_coords(pybind11::module &m);\npybind11::class_<stim::DemTargetWithCoords> pybind_dem_target_with_coords(pybind11::module &m);\npybind11::class_<stim::FlippedMeasurement> pybind_flipped_measurement(pybind11::module &m);\npybind11::class_<stim::CircuitTargetsInsideInstruction> pybind_circuit_targets_inside_instruction(pybind11::module &m);\npybind11::class_<stim::CircuitErrorLocation> pybind_circuit_error_location(pybind11::module &m);\npybind11::class_<stim::ExplainedError> pybind_explained_error(pybind11::module &m);\n\nvoid pybind_circuit_error_location_stack_frame_methods(\n    pybind11::module &m, pybind11::class_<stim::CircuitErrorLocationStackFrame> &c);\n\nvoid pybind_gate_target_with_coords_methods(pybind11::module &m, pybind11::class_<stim::GateTargetWithCoords> &c);\n\nvoid pybind_dem_target_with_coords_methods(pybind11::module &m, pybind11::class_<stim::DemTargetWithCoords> &c);\nvoid pybind_flipped_measurement_methods(pybind11::module &m, pybind11::class_<stim::FlippedMeasurement> &c);\nvoid pybind_circuit_targets_inside_instruction_methods(\n    pybind11::module &m, pybind11::class_<stim::CircuitTargetsInsideInstruction> &c);\n\nvoid pybind_circuit_error_location_methods(pybind11::module &m, pybind11::class_<stim::CircuitErrorLocation> &c);\nvoid pybind_explained_error_methods(pybind11::module &m, pybind11::class_<stim::ExplainedError> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/matched_error.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/simulators/error_matcher.h\"\n\nusing namespace stim;\n\nTEST(matched_error, FlippedMeasurement_basics) {\n}\nTEST(matched_error, DemTargetWithCoords_basics) {\n    DemTargetWithCoords c{DemTarget::relative_detector_id(5), {1, 2, 3}};\n    DemTargetWithCoords c2{DemTarget::relative_detector_id(5)};\n    ASSERT_EQ(c.str(), \"D5[coords 1,2,3]\");\n    ASSERT_EQ(c2.str(), \"D5\");\n\n    ASSERT_TRUE(c2 == (DemTargetWithCoords{DemTarget::relative_detector_id(5), {}}));\n    ASSERT_FALSE(c2 != (DemTargetWithCoords{DemTarget::relative_detector_id(5), {}}));\n    ASSERT_TRUE(c != c2);\n    ASSERT_FALSE(c == c2);\n\n    ASSERT_NE(c, c2);\n    ASSERT_EQ(c, (DemTargetWithCoords{DemTarget::relative_detector_id(5), {1, 2, 3}}));\n    ASSERT_NE(c, (DemTargetWithCoords{DemTarget::relative_detector_id(5), {1, 2, 4}}));\n    ASSERT_NE(c, (DemTargetWithCoords{DemTarget::relative_detector_id(6), {1, 2, 3}}));\n}\nTEST(matched_error, GateTargetWithCoords_basics) {\n    GateTargetWithCoords c{GateTarget::qubit(5), {1, 2, 3}};\n    GateTargetWithCoords c2{GateTarget::qubit(5)};\n    GateTargetWithCoords c3{GateTarget::x(5), {1, 2, 3}};\n    ASSERT_EQ(c.str(), \"5[coords 1,2,3]\");\n    ASSERT_EQ(c2.str(), \"5\");\n    ASSERT_EQ(c3.str(), \"X5[coords 1,2,3]\");\n\n    ASSERT_TRUE(c2 == (GateTargetWithCoords{GateTarget::qubit(5), {}}));\n    ASSERT_FALSE(c2 != (GateTargetWithCoords{GateTarget::qubit(5), {}}));\n    ASSERT_TRUE(c != c2);\n    ASSERT_FALSE(c == c2);\n\n    ASSERT_NE(c, c2);\n    ASSERT_EQ(c, (GateTargetWithCoords{GateTarget::qubit(5), {1, 2, 3}}));\n    ASSERT_NE(c, (GateTargetWithCoords{GateTarget::qubit(5), {1, 2, 4}}));\n    ASSERT_NE(c, (GateTargetWithCoords{GateTarget::qubit(6), {1, 2, 3}}));\n}\nTEST(matched_error, CircuitErrorLocationStackFrame_basics) {\n    CircuitErrorLocationStackFrame c{1, 2, 3};\n    ASSERT_EQ(\n        c.str(),\n        \"CircuitErrorLocationStackFrame{\"\n        \"instruction_offset=1, \"\n        \"iteration_index=2, \"\n        \"instruction_repetitions_arg=3}\");\n\n    ASSERT_TRUE(c == (CircuitErrorLocationStackFrame{1, 2, 3}));\n    ASSERT_FALSE(c != (CircuitErrorLocationStackFrame{1, 2, 3}));\n    ASSERT_TRUE(c != (CircuitErrorLocationStackFrame{2, 2, 3}));\n    ASSERT_FALSE(c == (CircuitErrorLocationStackFrame{2, 2, 3}));\n\n    ASSERT_EQ(c, (CircuitErrorLocationStackFrame{1, 2, 3}));\n    ASSERT_NE(c, (CircuitErrorLocationStackFrame{9, 2, 3}));\n    ASSERT_NE(c, (CircuitErrorLocationStackFrame{1, 9, 3}));\n    ASSERT_NE(c, (CircuitErrorLocationStackFrame{1, 2, 9}));\n}\n\nTEST(matched_error, CircuitTargetsInsideInstruction_basics) {\n    CircuitTargetsInsideInstruction targets{\n        GateType::X_ERROR,\n        \"\",\n        {0.125},\n        11,\n        17,\n        {\n            {GateTarget::qubit(5), {1, 2, 3}},\n            {GateTarget::x(6), {}},\n            {GateTarget::combiner(), {}},\n            {GateTarget::y(9), {3, 4}},\n            {GateTarget::rec(-5), {}},\n        },\n    };\n    ASSERT_EQ(targets.str(), \"X_ERROR(0.125) 5[coords 1,2,3] X6*Y9[coords 3,4] rec[-5]\");\n    ASSERT_TRUE(targets == targets);\n    ASSERT_FALSE(targets != targets);\n    auto targets2 = targets;\n    targets2.target_range_start++;\n    ASSERT_TRUE(targets != targets2);\n    ASSERT_FALSE(targets == targets2);\n}\n\nTEST(matched_error, CircuitTargetsInsideInstruction_fill) {\n    CircuitTargetsInsideInstruction not_filled{\n        GateType::X_ERROR,\n        \"\",\n        {0.125},\n        2,\n        5,\n        {},\n    };\n    not_filled.fill_args_and_targets_in_range(\n        Circuit(\"X_ERROR(0.125) 0 1 2 3 4 5 6 7 8 9\").operations[0], {{4, {11, 13}}});\n    ASSERT_EQ(not_filled.str(), \"X_ERROR(0.125) 2 3 4[coords 11,13]\");\n}\n\nTEST(matched_error, CircuitErrorLocation_basics) {\n    CircuitErrorLocation loc{\n        \"\",\n        6,\n        {\n            {GateTarget::x(3), {11, 12}},\n            {GateTarget::z(5), {}},\n        },\n        FlippedMeasurement{\n            5,\n            {\n                {GateTarget::x(3), {}},\n                {GateTarget::y(4), {14, 15}},\n            },\n        },\n        CircuitTargetsInsideInstruction{\n            GateType::X_ERROR,\n            \"\",\n            {0.125},\n            11,\n            17,\n            {\n                {GateTarget::qubit(5), {1, 2, 3}},\n                {GateTarget::x(6), {}},\n                {GateTarget::combiner(), {}},\n                {GateTarget::y(9), {3, 4}},\n                {GateTarget::rec(-5), {}},\n            },\n        },\n        {\n            CircuitErrorLocationStackFrame{9, 0, 100},\n            CircuitErrorLocationStackFrame{13, 15, 0},\n        },\n    };\n    ASSERT_EQ(loc.str(), R\"RESULT(CircuitErrorLocation {\n    flipped_pauli_product: X3[coords 11,12]*Z5\n    flipped_measurement.measurement_record_index: 5\n    flipped_measurement.measured_observable: X3*Y4[coords 14,15]\n    Circuit location stack trace:\n        (after 6 TICKs)\n        at instruction #10 (a REPEAT 100 block) in the circuit\n        after 15 completed iterations\n        at instruction #14 (X_ERROR) in the REPEAT block\n        at targets #12 to #17 of the instruction\n        resolving to X_ERROR(0.125) 5[coords 1,2,3] X6*Y9[coords 3,4] rec[-5]\n})RESULT\");\n    ASSERT_TRUE(loc == loc);\n    ASSERT_FALSE(loc != loc);\n    auto loc2 = loc;\n    loc2.tick_offset++;\n    ASSERT_TRUE(loc != loc2);\n    ASSERT_FALSE(loc == loc2);\n}\n\nTEST(matched_error, MatchedError_basics) {\n    CircuitErrorLocation loc{\n        \"\",\n        6,\n        {\n            {GateTarget::x(3), {11, 12}},\n            {GateTarget::z(5), {}},\n        },\n        FlippedMeasurement{\n            5,\n            {\n                {GateTarget::x(3), {}},\n                {GateTarget::y(4), {14, 15}},\n            },\n        },\n        CircuitTargetsInsideInstruction{\n            GateType::X_ERROR,\n            \"\",\n            {0.125},\n            11,\n            17,\n            {\n                {GateTarget::qubit(5), {1, 2, 3}},\n                {GateTarget::x(6), {}},\n                {GateTarget::combiner(), {}},\n                {GateTarget::y(9), {3, 4}},\n                {GateTarget::rec(-5), {}},\n            },\n        },\n        {\n            CircuitErrorLocationStackFrame{9, 0, 100},\n            CircuitErrorLocationStackFrame{13, 15, 0},\n        },\n    };\n    CircuitErrorLocation loc2 = loc;\n    loc2.tick_offset++;\n\n    ExplainedError err{\n        {\n            {DemTarget::relative_detector_id(5), {1, 2}},\n            {DemTarget::observable_id(5), {}},\n        },\n        {loc, loc2},\n    };\n    ExplainedError err2{\n        {\n            {DemTarget::relative_detector_id(5), {1, 2}},\n        },\n        {loc2, loc},\n    };\n    ASSERT_TRUE(err == err);\n    ASSERT_FALSE(err != err);\n    ASSERT_TRUE(err != err2);\n    ASSERT_FALSE(err == err2);\n    ASSERT_EQ(err.str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D5[coords 1,2] L5\n    CircuitErrorLocation {\n        flipped_pauli_product: X3[coords 11,12]*Z5\n        flipped_measurement.measurement_record_index: 5\n        flipped_measurement.measured_observable: X3*Y4[coords 14,15]\n        Circuit location stack trace:\n            (after 6 TICKs)\n            at instruction #10 (a REPEAT 100 block) in the circuit\n            after 15 completed iterations\n            at instruction #14 (X_ERROR) in the REPEAT block\n            at targets #12 to #17 of the instruction\n            resolving to X_ERROR(0.125) 5[coords 1,2,3] X6*Y9[coords 3,4] rec[-5]\n    }\n    CircuitErrorLocation {\n        flipped_pauli_product: X3[coords 11,12]*Z5\n        flipped_measurement.measurement_record_index: 5\n        flipped_measurement.measured_observable: X3*Y4[coords 14,15]\n        Circuit location stack trace:\n            (after 7 TICKs)\n            at instruction #10 (a REPEAT 100 block) in the circuit\n            after 15 completed iterations\n            at instruction #14 (X_ERROR) in the REPEAT block\n            at targets #12 to #17 of the instruction\n            resolving to X_ERROR(0.125) 5[coords 1,2,3] X6*Y9[coords 3,4] rec[-5]\n    }\n})RESULT\");\n}\n\nTEST(matched_error, MatchedError_fill) {\n    ExplainedError err{{}, {}};\n    err.fill_in_dem_targets(\n        std::vector<DemTarget>{DemTarget::relative_detector_id(5), DemTarget::relative_detector_id(6)},\n        {{5, {11, 13}}});\n    ASSERT_EQ(err.str(), R\"RESULT(ExplainedError {\n    dem_error_terms: D5[coords 11,13] D6\n    [no single circuit error had these exact symptoms]\n})RESULT\");\n}\n"
  },
  {
    "path": "src/stim/simulators/matched_error_pybind_test.py",
    "content": "import stim\n\n\ndef test_CircuitErrorLocationStackFrame():\n    v1 = stim.CircuitErrorLocationStackFrame(\n        instruction_offset=1,\n        iteration_index=2,\n        instruction_repetitions_arg=3,\n    )\n    assert v1.instruction_offset == 1\n    assert v1.iteration_index == 2\n    assert v1.instruction_repetitions_arg == 3\n\n    v2 = stim.CircuitErrorLocationStackFrame(\n        instruction_offset=2,\n        iteration_index=3,\n        instruction_repetitions_arg=5,\n    )\n    assert v1 != v2\n    assert v1 == v1\n    assert len({v1, v1, v2}) == 2  # Check hashable.\n    assert eval(repr(v1), {\"stim\": stim}) == v1\n    assert eval(repr(v2), {\"stim\": stim}) == v2\n    assert str(v1) == repr(v1)\n\n\ndef test_GateTargetWithCoords():\n    v1 = stim.GateTargetWithCoords(\n        gate_target=stim.target_x(5),\n        coords=[1, 2, 3],\n    )\n    assert v1.gate_target == stim.GateTarget(stim.target_x(5))\n    assert v1.coords == [1, 2, 3]\n    v2 = stim.GateTargetWithCoords(\n        gate_target=stim.GateTarget(4),\n        coords=[1, 2],\n    )\n    assert v1 != v2\n    assert v1 == v1\n    assert len({v1, v1, v2}) == 2  # Check hashable.\n    assert eval(repr(v1), {\"stim\": stim}) == v1\n    assert eval(repr(v2), {\"stim\": stim}) == v2\n    assert str(v1) == 'X5[coords 1,2,3]'\n\n\ndef test_DemTargetWithCoords():\n    v1 = stim.DemTargetWithCoords(\n        dem_target=stim.DemTarget.relative_detector_id(5),\n        coords=[1, 2, 3],\n    )\n    assert v1.dem_target == stim.DemTarget.relative_detector_id(5)\n    assert v1.coords == [1, 2, 3]\n    v2 = stim.DemTargetWithCoords(\n        dem_target=stim.DemTarget.logical_observable_id(3),\n        coords=(),\n    )\n    assert v1 != v2\n    assert v1 == v1\n    assert len({v1, v1, v2}) == 2  # Check hashable.\n    assert eval(repr(v1), {\"stim\": stim}) == v1\n    assert eval(repr(v2), {\"stim\": stim}) == v2\n    assert str(v1) == 'D5[coords 1,2,3]'\n\n\ndef test_FlippedMeasurement():\n    v1 = stim.FlippedMeasurement(\n        record_index=5,\n        observable=[\n            stim.GateTargetWithCoords(\n                gate_target=stim.target_x(5),\n                coords=[1, 2, 3]),\n        ],\n    )\n    assert v1.record_index == 5\n    assert v1.observable == [\n        stim.GateTargetWithCoords(\n            gate_target=stim.target_x(5),\n            coords=[1, 2, 3]),\n    ]\n    v2 = stim.FlippedMeasurement(\n        record_index=5,\n        observable=[],\n    )\n    assert v1 != v2\n    assert v1 == v1\n    assert len({v1, v1, v2}) == 2  # Check hashable.\n    assert eval(repr(v1), {\"stim\": stim}) == v1\n    assert eval(repr(v2), {\"stim\": stim}) == v2\n    assert str(v1) == repr(v1)\n\n\ndef test_CircuitTargetsInsideInstruction():\n    v1 = stim.CircuitTargetsInsideInstruction(\n        gate=\"X_ERROR\",\n        args=[0.25],\n        target_range_start=2,\n        target_range_end=5,\n        targets_in_range=[\n            stim.GateTargetWithCoords(gate_target=5, coords=[1, 2]),\n            stim.GateTargetWithCoords(gate_target=6, coords=[1, 3]),\n            stim.GateTargetWithCoords(gate_target=7, coords=[]),\n        ],\n    )\n    assert v1.gate == \"X_ERROR\"\n    assert v1.args == [0.25]\n    assert v1.target_range_start == 2\n    assert v1.target_range_end == 5\n    assert v1.targets_in_range == [\n        stim.GateTargetWithCoords(gate_target=5, coords=[1, 2]),\n        stim.GateTargetWithCoords(gate_target=6, coords=[1, 3]),\n        stim.GateTargetWithCoords(gate_target=7, coords=[]),\n    ]\n    v2 = stim.CircuitTargetsInsideInstruction(\n        gate=\"Z_ERROR\",\n        args=[0.125],\n        target_range_start=3,\n        target_range_end=3,\n        targets_in_range=[],\n    )\n    assert v1 != v2\n    assert v1 == v1\n    assert len({v1, v1, v2}) == 2  # Check hashable.\n    assert eval(repr(v1), {\"stim\": stim}) == v1\n    assert eval(repr(v2), {\"stim\": stim}) == v2\n    assert str(v1) == \"X_ERROR(0.25) 5[coords 1,2] 6[coords 1,3] 7\"\n\n\ndef test_CircuitErrorLocation():\n    m = stim.FlippedMeasurement(\n        record_index=5,\n        observable=[\n            stim.GateTargetWithCoords(\n                gate_target=stim.target_x(5),\n                coords=[1, 2, 3]),\n        ],\n    )\n    p = [\n        stim.GateTargetWithCoords(\n            gate_target=stim.target_y(6),\n            coords=[1, 2, 3]),\n    ]\n    t = stim.CircuitTargetsInsideInstruction(\n        gate=\"X_ERROR\",\n        args=[0.25],\n        target_range_start=2,\n        target_range_end=5,\n        targets_in_range=[\n            stim.GateTargetWithCoords(gate_target=5, coords=[1, 2]),\n            stim.GateTargetWithCoords(gate_target=6, coords=[1, 3]),\n            stim.GateTargetWithCoords(gate_target=7, coords=[]),\n        ],\n    )\n    s = [\n        stim.CircuitErrorLocationStackFrame(\n            instruction_offset=1,\n            iteration_index=2,\n            instruction_repetitions_arg=3,\n        )\n    ] * 2\n    v1 = stim.CircuitErrorLocation(\n        tick_offset=5,\n        flipped_pauli_product=p,\n        flipped_measurement=m,\n        instruction_targets=t,\n        stack_frames=s,\n    )\n    assert v1.tick_offset == 5\n    assert v1.flipped_pauli_product == p\n    assert v1.flipped_measurement == m\n    assert v1.instruction_targets == t\n    assert v1.stack_frames == s\n    v2 = stim.CircuitErrorLocation(\n        tick_offset=5,\n        flipped_pauli_product=[],\n        flipped_measurement=None,\n        instruction_targets=t,\n        stack_frames=[],\n    )\n    assert v2.flipped_measurement is None\n    assert v1 != v2\n    assert v1 == v1\n    assert len({v1, v1, v2}) == 2  # Check hashable.\n    assert eval(repr(v1), {\"stim\": stim}) == v1\n    assert eval(repr(v2), {\"stim\": stim}) == v2\n    assert str(v1) == \"\"\"CircuitErrorLocation {\n    flipped_pauli_product: Y6[coords 1,2,3]\n    flipped_measurement.measurement_record_index: 5\n    flipped_measurement.measured_observable: X5[coords 1,2,3]\n    Circuit location stack trace:\n        (after 5 TICKs)\n        at instruction #2 (a REPEAT 3 block) in the circuit\n        after 2 completed iterations\n        at instruction #2 (X_ERROR) in the REPEAT block\n        at targets #3 to #5 of the instruction\n        resolving to X_ERROR(0.25) 5[coords 1,2] 6[coords 1,3] 7\n}\"\"\"\n\n\ndef test_MatchedError():\n    m = stim.FlippedMeasurement(\n        record_index=5,\n        observable=[\n            stim.GateTargetWithCoords(\n                gate_target=stim.target_x(5),\n                coords=[1, 2, 3]),\n        ],\n    )\n    p = [\n        stim.GateTargetWithCoords(\n            gate_target=stim.target_y(6),\n            coords=[1, 2, 3]),\n    ]\n    t = stim.CircuitTargetsInsideInstruction(\n        gate=\"X_ERROR\",\n        args=[0.25],\n        target_range_start=2,\n        target_range_end=5,\n        targets_in_range=[\n            stim.GateTargetWithCoords(gate_target=5, coords=[1, 2]),\n            stim.GateTargetWithCoords(gate_target=6, coords=[1, 3]),\n            stim.GateTargetWithCoords(gate_target=7, coords=[]),\n        ],\n    )\n    s = [\n        stim.CircuitErrorLocationStackFrame(\n            instruction_offset=1,\n            iteration_index=2,\n            instruction_repetitions_arg=3,\n        )\n    ] * 2\n    e = stim.CircuitErrorLocation(\n        tick_offset=5,\n        flipped_pauli_product=p,\n        flipped_measurement=m,\n        instruction_targets=t,\n        stack_frames=s,\n    )\n    v1 = stim.ExplainedError(\n        dem_error_terms=[stim.DemTargetWithCoords(\n            dem_target=stim.DemTarget.relative_detector_id(5),\n            coords=[1, 2, 3],\n        )],\n        circuit_error_locations=[e],\n    )\n    assert v1.dem_error_terms == [stim.DemTargetWithCoords(\n        dem_target=stim.DemTarget.relative_detector_id(5),\n        coords=[1, 2, 3],\n    )]\n    assert v1.circuit_error_locations == [e]\n    v2 = stim.ExplainedError(\n        dem_error_terms=[],\n        circuit_error_locations=[],\n    )\n    assert v1 != v2\n    assert v1 == v1\n    assert len({v1, v1, v2}) == 2  # Check hashable.\n    assert eval(repr(v1), {\"stim\": stim}) == v1\n    assert eval(repr(v2), {\"stim\": stim}) == v2\n    assert str(v1) == \"\"\"ExplainedError {\n    dem_error_terms: D5[coords 1,2,3]\n    CircuitErrorLocation {\n        flipped_pauli_product: Y6[coords 1,2,3]\n        flipped_measurement.measurement_record_index: 5\n        flipped_measurement.measured_observable: X5[coords 1,2,3]\n        Circuit location stack trace:\n            (after 5 TICKs)\n            at instruction #2 (a REPEAT 3 block) in the circuit\n            after 2 completed iterations\n            at instruction #2 (X_ERROR) in the REPEAT block\n            at targets #3 to #5 of the instruction\n            resolving to X_ERROR(0.25) 5[coords 1,2] 6[coords 1,3] 7\n    }\n}\"\"\"\n"
  },
  {
    "path": "src/stim/simulators/measurements_to_detection_events.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_MEASUREMENTS_TO_DETECTION_EVENTS_H\n#define _STIM_SIMULATORS_MEASUREMENTS_TO_DETECTION_EVENTS_H\n\n#include <cassert>\n#include <functional>\n#include <iostream>\n#include <new>\n#include <random>\n#include <sstream>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/io/measure_record.h\"\n#include \"stim/stabilizers/tableau.h\"\n#include \"stim/stabilizers/tableau_transposed_raii.h\"\n\nnamespace stim {\n\n/// Reads measurement data from a file, converts it to detection event data, and writes that out to another file.\n///\n/// Args:\n///     measurements_in: The file to read measurement data from.\n///     input_format: The format of the measurement data in the file.\n///     optional_sweep_bits_in: An optional file containing sweep data for each shot in the measurements file.\n///     sweep_bits_in_format: The format of the sweep data file. Ignored when optional_sweep_bits_in == nullptr.\n///     results_out: The file to write detection event data to.\n///     output_format: The format to use when writing the detection event data.\n///     circuit: The circuit that the measurement data corresponds to, with DETECTOR and OBSERVABLE_INCLUDE annotations\n///         indicating how to perform the conversion.\n///     append_observables: Whether or not to include observable flip data in the detection event data.\n///     skip_reference_sample: When set to True, the reference sample used by the conversion is initialized to\n///         all-zeroes instead of being collected from the circuit. This should probably only be done if you know the\n///         all-zero sample is a valid sample, or if you know that the measurements were generated by a frame simulator\n///         that was also incorrectly assuming an all-zero reference sample.\ntemplate <size_t W>\nvoid stream_measurements_to_detection_events(\n    FILE *measurements_in,\n    SampleFormat measurements_in_format,\n    FILE *optional_sweep_bits_in,\n    SampleFormat sweep_bits_in_format,\n    FILE *results_out,\n    SampleFormat results_out_format,\n    const Circuit &circuit,\n    bool append_observables,\n    bool skip_reference_sample,\n    FILE *obs_out,\n    SampleFormat obs_out_format);\n\n/// A variant of `stim::stream_measurements_to_detection_events` with derived values passed in, not recomputed.\ntemplate <size_t W>\nvoid stream_measurements_to_detection_events_helper(\n    FILE *measurements_in,\n    SampleFormat measurements_in_format,\n    FILE *optional_sweep_bits_in,\n    SampleFormat sweep_bits_in_format,\n    FILE *results_out,\n    SampleFormat results_out_format,\n    const Circuit &circuit,\n    CircuitStats circuit_stats,\n    bool append_observables,\n    simd_bits_range_ref<W> reference_sample,\n    FILE *obs_out,\n    SampleFormat obs_out_format);\n\n/// Converts measurement data into detection event data based on a circuit.\n///\n/// Args:\n///     measurements__minor_shot_index: Recorded measurement data.\n///         Major axis: measurement bit index.\n///         Minor axis: shot index.\n///     sweep_bits__minor_shot_index: Per-shot configuration data controlling operations like `CNOT sweep[0] 1`.\n///         Major axis: sweep bit index.\n///         Minor axis: shot index.\n///\n///         To not specify sweep data, set the major axis length of sweep_bits__minor_shot_index to 0 (the minor axis\n///         length must still match the number of shots). The major axis can also be partially truncated. Sweep bits\n///         beyond that length default to False.\n///     circuit: The circuit that the measurement data corresponds to, with DETECTOR and OBSERVABLE_INCLUDE annotations\n///         indicating how to perform the conversion.\n///     append_observables: Whether or not to include observable flip data in the detection event data.\n///     skip_reference_sample: When set to True, the reference sample used by the conversion is initialized to\n///         all-zeroes instead of being collected from the circuit. This should probably only be done if you know the\n///         all-zero sample is a valid sample, or if you know that the measurements were generated by a frame simulator\n///         that was also incorrectly assuming an all-zero reference sample.\n///\n/// Returns:\n///     Detection event data. Major axis is detector index (+ observable index). Minor axis is shot index.\ntemplate <size_t W>\nsimd_bit_table<W> measurements_to_detection_events(\n    const simd_bit_table<W> &measurements__minor_shot_index,\n    const simd_bit_table<W> &sweep_bits__minor_shot_index,\n    const Circuit &circuit,\n    bool append_observables,\n    bool skip_reference_sample);\n\n/// A variant of `stim::measurements_to_detection_events` with derived values passed in, not recomputed.\ntemplate <size_t W>\nvoid measurements_to_detection_events_helper(\n    const simd_bit_table<W> &measurements__minor_shot_index,\n    const simd_bit_table<W> &sweep_bits__minor_shot_index,\n    simd_bit_table<W> &out_detection_results__minor_shot_index,\n    const Circuit &noiseless_circuit,\n    CircuitStats circuit_stats,\n    const simd_bits<W> &reference_sample,\n    bool append_observables);\n\n}  // namespace stim\n\n#include \"stim/simulators/measurements_to_detection_events.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/measurements_to_detection_events.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <cassert>\n\n#include \"stim/gates/gates.h\"\n#include \"stim/io/measure_record_batch_writer.h\"\n#include \"stim/io/measure_record_reader.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/mem/simd_util.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/simulators/measurements_to_detection_events.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nvoid measurements_to_detection_events_helper(\n    const simd_bit_table<W> &measurements__minor_shot_index,\n    const simd_bit_table<W> &sweep_bits__minor_shot_index,\n    simd_bit_table<W> &out_detection_results__minor_shot_index,\n    const Circuit &noiseless_circuit,\n    CircuitStats circuit_stats,\n    const simd_bits<W> &reference_sample,\n    bool append_observables) {\n    // Tables should agree on the batch size.\n    size_t batch_size = out_detection_results__minor_shot_index.num_minor_bits_padded();\n    if (measurements__minor_shot_index.num_minor_bits_padded() != batch_size) {\n        throw std::invalid_argument(\"measurements__minor_shot_index.num_minor_bits_padded() != batch_size\");\n    }\n    if (sweep_bits__minor_shot_index.num_minor_bits_padded() != batch_size) {\n        throw std::invalid_argument(\"sweep_bits__minor_shot_index.num_minor_bits_padded() != batch_size\");\n    }\n    // Tables should have the right number of bits per shot.\n    if (out_detection_results__minor_shot_index.num_major_bits_padded() <\n        circuit_stats.num_detectors + circuit_stats.num_observables * append_observables) {\n        throw std::invalid_argument(\n            \"out_detection_results__minor_shot_index.num_major_bits_padded() < num_detectors + num_observables * \"\n            \"append_observables\");\n    }\n    if (measurements__minor_shot_index.num_major_bits_padded() < circuit_stats.num_measurements) {\n        throw std::invalid_argument(\"measurements__minor_shot_index.num_major_bits_padded() < num_measurements\");\n    }\n\n    // The frame simulator is used to account for flips in the measurement results that originate from the sweep data.\n    // Eg. a `CNOT sweep[5] 0` can bit flip qubit 0, which can invert later measurement results, which will invert the\n    // expected parity of detectors involving that measurement. This can vary from shot to shot.\n    FrameSimulator<W> frame_sim(\n        circuit_stats, FrameSimulatorMode::STREAM_DETECTIONS_TO_DISK, batch_size, std::mt19937_64(0));\n    frame_sim.sweep_table = sweep_bits__minor_shot_index;\n    frame_sim.guarantee_anticommutation_via_frame_randomization = false;\n\n    uint64_t detector_offset = 0;\n    uint64_t measure_count_so_far = 0;\n    noiseless_circuit.for_each_operation([&](const CircuitInstruction &op) {\n        frame_sim.do_gate(op);\n\n        switch (op.gate_type) {\n            case GateType::DETECTOR: {\n                simd_bits_range_ref<W> out_row = out_detection_results__minor_shot_index[detector_offset];\n                detector_offset++;\n\n                // Include dependence from gates controlled by sweep bits.\n                out_row ^= frame_sim.det_record.lookback(1);\n\n                bool expectation = false;\n                for (const auto &t : op.targets) {\n                    uint32_t lookback = t.data & TARGET_VALUE_MASK;\n                    // Include dependence from physical measurement results.\n                    out_row ^= measurements__minor_shot_index[measure_count_so_far - lookback];\n                    // Include dependence from reference sample expectation.\n                    expectation ^= reference_sample[measure_count_so_far - lookback];\n                }\n                if (expectation) {\n                    out_row.invert_bits();\n                }\n\n                frame_sim.det_record.clear();\n                break;\n            }\n            case GateType::OBSERVABLE_INCLUDE: {\n                simd_bits_range_ref<W> obs_row = frame_sim.obs_record[(uint64_t)op.args[0]];\n                bool expectation = false;\n                for (const auto &t : op.targets) {\n                    if (t.is_classical_bit_target()) {\n                        uint32_t lookback = t.data & TARGET_VALUE_MASK;\n                        // Include dependence from physical measurement results.\n                        obs_row ^= measurements__minor_shot_index[measure_count_so_far - lookback];\n                        // Include dependence from reference sample expectation.\n                        expectation ^= reference_sample[measure_count_so_far - lookback];\n                    } else if (t.is_pauli_target()) {\n                        // Ignored.\n                    } else {\n                        throw std::invalid_argument(\"Unexpected target for OBSERVABLE_INCLUDE: \" + t.str());\n                    }\n                }\n                if (expectation) {\n                    obs_row.invert_bits();\n                }\n                break;\n            }\n            default:\n                measure_count_so_far += op.count_measurement_results();\n        }\n    });\n\n    if (append_observables) {\n        for (size_t k = 0; k < circuit_stats.num_observables; k++) {\n            // Include dependence from gates controlled by sweep bits.\n            out_detection_results__minor_shot_index[circuit_stats.num_detectors + k] ^= frame_sim.obs_record[k];\n        }\n    }\n\n    // Safety check verifying no randomness was used by the frame simulator.\n    std::mt19937_64 fresh_rng(0);\n    if (frame_sim.rng() != fresh_rng() || frame_sim.rng() != fresh_rng() || frame_sim.rng() != fresh_rng()) {\n        throw std::invalid_argument(\"Something is wrong. Converting measurements consumed entropy, but it shouldn't.\");\n    }\n}\n\ntemplate <size_t W>\nsimd_bit_table<W> measurements_to_detection_events(\n    const simd_bit_table<W> &measurements__minor_shot_index,\n    const simd_bit_table<W> &sweep_bits__minor_shot_index,\n    const Circuit &circuit,\n    bool append_observables,\n    bool skip_reference_sample) {\n    CircuitStats circuit_stats = circuit.compute_stats();\n    simd_bits<W> reference_sample(circuit_stats.num_measurements);\n    if (!skip_reference_sample) {\n        reference_sample = TableauSimulator<W>::reference_sample_circuit(circuit);\n    }\n    simd_bit_table<W> out(\n        circuit_stats.num_detectors + circuit_stats.num_observables * append_observables,\n        measurements__minor_shot_index.num_minor_bits_padded());\n    measurements_to_detection_events_helper(\n        measurements__minor_shot_index,\n        sweep_bits__minor_shot_index,\n        out,\n        circuit.aliased_noiseless_circuit(),\n        circuit_stats,\n        reference_sample,\n        append_observables);\n    return out;\n}\n\ntemplate <size_t W>\nvoid stream_measurements_to_detection_events(\n    FILE *measurements_in,\n    SampleFormat measurements_in_format,\n    FILE *optional_sweep_bits_in,\n    SampleFormat sweep_bits_format,\n    FILE *results_out,\n    SampleFormat results_out_format,\n    const Circuit &circuit,\n    bool append_observables,\n    bool skip_reference_sample,\n    FILE *obs_out,\n    SampleFormat obs_out_format) {\n    // Circuit metadata.\n    CircuitStats circuit_stats = circuit.compute_stats();\n    simd_bits<W> reference_sample(circuit_stats.num_measurements);\n    Circuit noiseless_circuit = circuit.aliased_noiseless_circuit();\n    if (!skip_reference_sample) {\n        reference_sample = TableauSimulator<W>::reference_sample_circuit(circuit);\n    }\n\n    stream_measurements_to_detection_events_helper<W>(\n        measurements_in,\n        measurements_in_format,\n        optional_sweep_bits_in,\n        sweep_bits_format,\n        results_out,\n        results_out_format,\n        noiseless_circuit,\n        circuit_stats,\n        append_observables,\n        reference_sample,\n        obs_out,\n        obs_out_format);\n}\n\ntemplate <size_t W>\nvoid stream_measurements_to_detection_events_helper(\n    FILE *measurements_in,\n    SampleFormat measurements_in_format,\n    FILE *optional_sweep_bits_in,\n    SampleFormat sweep_bits_in_format,\n    FILE *results_out,\n    SampleFormat results_out_format,\n    const Circuit &noiseless_circuit,\n    CircuitStats circuit_stats,\n    bool append_observables,\n    simd_bits_range_ref<W> reference_sample,\n    FILE *obs_out,\n    SampleFormat obs_out_format) {\n    bool internally_append_observables = append_observables || obs_out != nullptr;\n    size_t num_out_bits_including_any_obs =\n        circuit_stats.num_detectors + circuit_stats.num_observables * internally_append_observables;\n    size_t num_sweep_bits_available = optional_sweep_bits_in == nullptr ? 0 : circuit_stats.num_sweep_bits;\n    size_t num_buffered_shots = 1024;\n\n    // Readers / writers.\n    auto reader = MeasureRecordReader<W>::make(measurements_in, measurements_in_format, circuit_stats.num_measurements);\n    std::unique_ptr<MeasureRecordReader<W>> sweep_data_reader;\n    std::unique_ptr<MeasureRecordWriter> obs_writer;\n    if (obs_out != nullptr) {\n        obs_writer = MeasureRecordWriter::make(obs_out, obs_out_format);\n    }\n    auto writer = MeasureRecordWriter::make(results_out, results_out_format);\n    if (optional_sweep_bits_in != nullptr) {\n        sweep_data_reader =\n            MeasureRecordReader<W>::make(optional_sweep_bits_in, sweep_bits_in_format, circuit_stats.num_sweep_bits);\n    }\n\n    // Buffers and transposed buffers.\n    simd_bit_table<W> measurements__minor_shot_index(circuit_stats.num_measurements, num_buffered_shots);\n    simd_bit_table<W> out__minor_shot_index(num_out_bits_including_any_obs, num_buffered_shots);\n    simd_bit_table<W> out__major_shot_index(num_buffered_shots, num_out_bits_including_any_obs);\n    simd_bit_table<W> sweep_bits__minor_shot_index(num_sweep_bits_available, num_buffered_shots);\n    if (reader->expects_empty_serialized_data_for_each_shot()) {\n        throw std::invalid_argument(\n            \"Can't tell how many shots are in the measurement data.\\n\"\n            \"The circuit has no measurements and the measurement format encodes empty shots into no bytes.\");\n    }\n\n    // Data streaming loop.\n    size_t total_read = 0;\n    while (true) {\n        // Read measurement data and sweep data for a batch of shots.\n        size_t record_count = reader->read_records_into(measurements__minor_shot_index, false);\n        if (sweep_data_reader != nullptr) {\n            size_t sweep_data_count = sweep_data_reader->read_records_into(sweep_bits__minor_shot_index, false);\n            if (sweep_data_count != record_count && !sweep_data_reader->expects_empty_serialized_data_for_each_shot()) {\n                std::stringstream ss;\n                ss << \"The sweep data contained a different number of shots than the measurement data.\\n\";\n                ss << \"There was \" << (record_count + total_read) << \" shot records total.\\n\";\n                if (sweep_data_count < record_count) {\n                    ss << \"But there was \" << (record_count + sweep_data_count) << \" sweep records total.\";\n                } else {\n                    ss << \"But there was at least \" << (record_count + sweep_data_count) << \" sweep records.\";\n                }\n                throw std::invalid_argument(ss.str());\n            }\n        }\n        if (record_count == 0) {\n            break;\n        }\n        total_read += record_count;\n\n        // Convert measurement data into detection event data.\n        out__minor_shot_index.clear();\n        measurements_to_detection_events_helper<W>(\n            measurements__minor_shot_index,\n            sweep_bits__minor_shot_index,\n            out__minor_shot_index,\n            noiseless_circuit,\n            circuit_stats,\n            reference_sample,\n            internally_append_observables);\n        out__minor_shot_index.transpose_into(out__major_shot_index);\n\n        // Write detection event data.\n        for (size_t k = 0; k < record_count; k++) {\n            simd_bits_range_ref<W> record = out__major_shot_index[k];\n            writer->begin_result_type('D');\n            writer->write_bits(record.u8, circuit_stats.num_detectors);\n            if (append_observables) {\n                writer->begin_result_type('L');\n                for (size_t k2 = 0; k2 < circuit_stats.num_observables; k2++) {\n                    writer->write_bit(record[circuit_stats.num_detectors + k2]);\n                }\n            }\n            writer->write_end();\n\n            if (obs_out != nullptr) {\n                obs_writer->begin_result_type('L');\n                for (size_t k2 = 0; k2 < circuit_stats.num_observables; k2++) {\n                    obs_writer->write_bit(record[circuit_stats.num_detectors + k2]);\n                }\n                obs_writer->write_end();\n            }\n        }\n    }\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/simulators/measurements_to_detection_events.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/measurements_to_detection_events.pybind.h\"\n\n#include \"stim/circuit/circuit.pybind.h\"\n#include \"stim/io/raii_file.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n#include \"stim/simulators/measurements_to_detection_events.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nCompiledMeasurementsToDetectionEventsConverter::CompiledMeasurementsToDetectionEventsConverter(\n    simd_bits<MAX_BITWORD_WIDTH> ref_sample, Circuit circuit, bool skip_reference_sample)\n    : skip_reference_sample(skip_reference_sample),\n      ref_sample(ref_sample),\n      circuit_stats(circuit.compute_stats()),\n      circuit(std::move(circuit)) {\n}\nstd::string CompiledMeasurementsToDetectionEventsConverter::repr() const {\n    std::stringstream result;\n    result << \"stim.CompiledMeasurementsToDetectionEventsConverter(\";\n    result << circuit_repr(circuit);\n    if (skip_reference_sample) {\n        result << \", skip_reference_sample=True\";\n    }\n    result << \")\";\n    return result.str();\n}\n\nvoid CompiledMeasurementsToDetectionEventsConverter::convert_file(\n    std::string_view measurements_filepath,\n    std::string_view measurements_format,\n    const char *sweep_bits_filepath,\n    std::string_view sweep_bits_format,\n    std::string_view detection_events_filepath,\n    std::string_view detection_events_format,\n    bool append_observables,\n    const char *obs_out_filepath,\n    std::string_view obs_out_format) {\n    auto format_in = format_to_enum(measurements_format);\n    auto format_sweep_bits = format_to_enum(sweep_bits_format);\n    auto format_out = format_to_enum(detection_events_format);\n    RaiiFile file_in(measurements_filepath, \"rb\");\n    RaiiFile obs_out(obs_out_filepath, \"wb\");\n    RaiiFile sweep_bits_in(sweep_bits_filepath, \"rb\");\n    RaiiFile detections_out(detection_events_filepath, \"wb\");\n    auto parsed_obs_out_format = format_to_enum(obs_out_format);\n\n    stream_measurements_to_detection_events_helper<MAX_BITWORD_WIDTH>(\n        file_in.f,\n        format_in,\n        sweep_bits_in.f,\n        format_sweep_bits,\n        detections_out.f,\n        format_out,\n        circuit.aliased_noiseless_circuit(),\n        circuit_stats,\n        append_observables,\n        ref_sample,\n        obs_out.f,\n        parsed_obs_out_format);\n}\n\npybind11::object CompiledMeasurementsToDetectionEventsConverter::convert(\n    const pybind11::object &measurements,\n    const pybind11::object &sweep_bits,\n    const pybind11::object &separate_observables_obj,\n    const pybind11::object &append_observables_obj,\n    bool bit_pack_result_old_compat,\n    bool bit_pack_result) {\n    bit_pack_result |= bit_pack_result_old_compat;\n\n    if (separate_observables_obj.is_none() && append_observables_obj.is_none()) {\n        throw std::invalid_argument(\n            \"To ignore observable flip data, you must explicitly specify either separate_observables=False or \"\n            \"append_observables=False.\");\n    }\n    bool separate_observables = pybind11::cast<bool>(separate_observables_obj);\n    bool append_observables = pybind11::cast<bool>(append_observables_obj);\n    size_t num_shots;\n    simd_bit_table<MAX_BITWORD_WIDTH> measurements_minor_shot_index =\n        numpy_array_to_transposed_simd_table(measurements, circuit_stats.num_measurements, &num_shots);\n\n    simd_bit_table<MAX_BITWORD_WIDTH> sweep_bits_minor_shot_index{0, num_shots};\n    if (!sweep_bits.is_none()) {\n        size_t num_sweep_shots;\n        sweep_bits_minor_shot_index =\n            numpy_array_to_transposed_simd_table(sweep_bits, circuit_stats.num_sweep_bits, &num_sweep_shots);\n        if (num_shots != num_sweep_shots) {\n            throw std::invalid_argument(\"Need sweep_bits.shape[0] == measurements.shape[0]\");\n        }\n    }\n\n    size_t num_intermediate_bits =\n        circuit_stats.num_detectors + circuit_stats.num_observables * (append_observables || separate_observables);\n    simd_bit_table<MAX_BITWORD_WIDTH> out_detection_results_minor_shot_index(num_intermediate_bits, num_shots);\n    stim::measurements_to_detection_events_helper(\n        measurements_minor_shot_index,\n        sweep_bits_minor_shot_index,\n        out_detection_results_minor_shot_index,\n        circuit.aliased_noiseless_circuit(),\n        circuit_stats,\n        ref_sample,\n        append_observables || separate_observables);\n\n    size_t num_output_bits = circuit_stats.num_detectors + circuit_stats.num_observables * append_observables;\n    pybind11::object obs_data = pybind11::none();\n    if (separate_observables) {\n        simd_bit_table<MAX_BITWORD_WIDTH> obs_table(circuit_stats.num_observables, num_shots);\n        for (size_t obs = 0; obs < circuit_stats.num_observables; obs++) {\n            auto obs_slice = out_detection_results_minor_shot_index[circuit_stats.num_detectors + obs];\n            obs_table[obs] = obs_slice;\n            if (!append_observables) {\n                obs_slice.clear();\n            }\n        }\n        obs_data = simd_bit_table_to_numpy(\n            obs_table, circuit_stats.num_observables, num_shots, bit_pack_result, true, pybind11::none());\n    }\n\n    // Caution: only do this after extracting the observable data, lest it leak into the packed bytes.\n    pybind11::object det_data = simd_bit_table_to_numpy(\n        out_detection_results_minor_shot_index, num_output_bits, num_shots, bit_pack_result, true, pybind11::none());\n\n    if (separate_observables) {\n        return pybind11::make_tuple(det_data, obs_data);\n    }\n    return det_data;\n}\n\npybind11::class_<CompiledMeasurementsToDetectionEventsConverter>\nstim_pybind::pybind_compiled_measurements_to_detection_events_converter(pybind11::module &m) {\n    return pybind11::class_<CompiledMeasurementsToDetectionEventsConverter>(\n        m,\n        \"CompiledMeasurementsToDetectionEventsConverter\",\n        \"A tool for quickly converting measurements from an analyzed stabilizer circuit into detection events.\");\n}\n\nCompiledMeasurementsToDetectionEventsConverter stim_pybind::py_init_compiled_measurements_to_detection_events_converter(\n    const Circuit &circuit, bool skip_reference_sample) {\n    simd_bits<MAX_BITWORD_WIDTH> ref_sample =\n        skip_reference_sample ? simd_bits<MAX_BITWORD_WIDTH>(circuit.count_measurements())\n                              : TableauSimulator<MAX_BITWORD_WIDTH>::reference_sample_circuit(circuit);\n    return CompiledMeasurementsToDetectionEventsConverter(ref_sample, circuit, skip_reference_sample);\n}\n\nvoid stim_pybind::pybind_compiled_measurements_to_detection_events_converter_methods(\n    pybind11::module &m, pybind11::class_<CompiledMeasurementsToDetectionEventsConverter> &c) {\n    using SerializationTuple = std::tuple<stim::Circuit, bool, pybind11::object, size_t>;\n    c.def(\n        pybind11::init(&py_init_compiled_measurements_to_detection_events_converter),\n        pybind11::arg(\"circuit\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"skip_reference_sample\") = false,\n        clean_doc_string(R\"DOC(\n            Creates a measurement-to-detection-events converter for the given circuit.\n\n            The converter uses a noiseless reference sample, collected from the circuit\n            using stim's Tableau simulator during initialization of the converter, as a\n            baseline for determining what the expected value of a detector is.\n\n            Note that the expected behavior of gauge detectors (detectors that are not\n            actually deterministic under noiseless execution) can vary depending on the\n            reference sample. Stim mitigates this by always generating the same reference\n            sample for a given circuit.\n\n            Args:\n                circuit: The stim circuit to use for conversions.\n                skip_reference_sample: Defaults to False. When set to True, the reference\n                    sample used by the converter is initialized to all-zeroes instead of\n                    being collected from the circuit. This should only be used if it's known\n                    that the all-zeroes sample is actually a possible result from the\n                    circuit (under noiseless execution).\n\n            Returns:\n                An initialized stim.CompiledMeasurementsToDetectionEventsConverter.\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n                >>> converter = stim.Circuit('''\n                ...    X 0\n                ...    M 0\n                ...    DETECTOR rec[-1]\n                ... ''').compile_m2d_converter()\n                >>> converter.convert(\n                ...     measurements=np.array([[0], [1]], dtype=np.bool_),\n                ...     append_observables=False,\n                ... )\n                array([[ True],\n                       [False]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"convert_file\",\n        &CompiledMeasurementsToDetectionEventsConverter::convert_file,\n        pybind11::kw_only(),\n        pybind11::arg(\"measurements_filepath\"),\n        pybind11::arg(\"measurements_format\") = \"01\",\n        pybind11::arg(\"sweep_bits_filepath\") = pybind11::none(),\n        pybind11::arg(\"sweep_bits_format\") = \"01\",\n        pybind11::arg(\"detection_events_filepath\"),\n        pybind11::arg(\"detection_events_format\") = \"01\",\n        pybind11::arg(\"append_observables\") = false,\n        pybind11::arg(\"obs_out_filepath\") = nullptr,\n        pybind11::arg(\"obs_out_format\") = \"01\",\n        clean_doc_string(R\"DOC(\n            @signature def convert_file(self, *, measurements_filepath: Union[str, pathlib.Path], measurements_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01', sweep_bits_filepath: Optional[Union[str, pathlib.Path]] = None, sweep_bits_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01', detection_events_filepath: Union[str, pathlib.Path], detection_events_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01', append_observables: bool = False, obs_out_filepath: Optional[Union[str, pathlib.Path]] = None, obs_out_format: Literal[\"01\", \"b8\", \"r8\", \"ptb64\", \"hits\", \"dets\"] = '01') -> None:\n            Reads measurement data from a file and writes detection events to another file.\n\n            Args:\n                measurements_filepath: A file containing measurement data to be converted.\n                measurements_format: The format the measurement data is stored in.\n                    Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                    Defaults to \"01\".\n                detection_events_filepath: Where to save detection event data to.\n                detection_events_format: The format to save the detection event data in.\n                    Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                    Defaults to \"01\".\n                sweep_bits_filepath: Defaults to None. A file containing sweep data, or\n                    None. When specified, sweep data (used for `sweep[k]` controls in the\n                    circuit, which can vary from shot to shot) will be read from the given\n                    file. When not specified, all sweep bits default to False and no\n                    sweep-controlled operations occur.\n                sweep_bits_format: The format the sweep data is stored in.\n                    Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                    Defaults to \"01\".\n                obs_out_filepath: Sample observables as part of each shot, and write them to\n                    this file. This keeps the observable data separate from the detector\n                    data.\n                obs_out_format: If writing the observables to a file, this is the format to\n                    write them in.\n                    Valid values are \"01\", \"b8\", \"r8\", \"hits\", \"dets\", and \"ptb64\".\n                    Defaults to \"01\".\n                append_observables: When True, the observables in the circuit are included\n                    as part of the detection event data. Specifically, they are treated as\n                    if they were additional detectors at the end of the circuit. When False,\n                    observable data is not output.\n\n            Examples:\n                >>> import stim\n                >>> import tempfile\n                >>> converter = stim.Circuit('''\n                ...    X 0\n                ...    M 0\n                ...    DETECTOR rec[-1]\n                ... ''').compile_m2d_converter()\n                >>> with tempfile.TemporaryDirectory() as d:\n                ...    with open(f\"{d}/measurements.01\", \"w\") as f:\n                ...        print(\"0\", file=f)\n                ...        print(\"1\", file=f)\n                ...    converter.convert_file(\n                ...        measurements_filepath=f\"{d}/measurements.01\",\n                ...        detection_events_filepath=f\"{d}/detections.01\",\n                ...        append_observables=False,\n                ...    )\n                ...    with open(f\"{d}/detections.01\") as f:\n                ...        print(f.read(), end=\"\")\n                1\n                0\n        )DOC\")\n            .data());\n\n    c.def(\n        \"convert\",\n        &CompiledMeasurementsToDetectionEventsConverter::convert,\n        pybind11::kw_only(),\n        pybind11::arg(\"measurements\"),\n        pybind11::arg(\"sweep_bits\") = pybind11::none(),\n        pybind11::arg(\"separate_observables\") = pybind11::none(),\n        pybind11::arg(\"append_observables\") = pybind11::none(),\n        pybind11::arg(\"bit_packed\") = false,\n        pybind11::arg(\"bit_pack_result\") = false,  // deprecated variant\n        clean_doc_string(R\"DOC(\n            Converts measurement data into detection event data.\n            @overload def convert(self, *, measurements: np.ndarray, sweep_bits: Optional[np.ndarray] = None, append_observables: bool = False, bit_packed: bool = False) -> np.ndarray:\n            @overload def convert(self, *, measurements: np.ndarray, sweep_bits: Optional[np.ndarray] = None, separate_observables: Literal[True], append_observables: bool = False, bit_packed: bool = False) -> Tuple[np.ndarray, np.ndarray]:\n            @signature def convert(self, *, measurements: np.ndarray, sweep_bits: Optional[np.ndarray] = None, separate_observables: bool = False, append_observables: bool = False, bit_packed: bool = False) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]:\n\n            Args:\n                measurements: A numpy array containing measurement data.\n\n                    The dtype of the array is used to determine if it is bit packed or not.\n                    dtype=np.bool_ (unpacked data):\n                        shape=(num_shots, circuit.num_measurements)\n                    dtype=np.uint8 (bit packed data):\n                        shape=(num_shots, math.ceil(circuit.num_measurements / 8))\n                sweep_bits: Optional. A numpy array containing sweep data for the `sweep[k]`\n                    controls in the circuit.\n\n                    The dtype of the array is used to determine if it is bit packed or not.\n                    dtype=np.bool_ (unpacked data):\n                        shape=(num_shots, circuit.num_sweep_bits)\n                    dtype=np.uint8 (bit packed data):\n                        shape=(num_shots, math.ceil(circuit.num_sweep_bits / 8))\n                separate_observables: Defaults to False. When set to True, two numpy arrays\n                    are returned instead of one, with the second array containing the\n                    observable flip data.\n                append_observables: Defaults to False. When set to True, the observables in\n                    the circuit are treated as if they were additional detectors. Their\n                    results are appended to the end of the detection event data.\n                bit_packed: Defaults to False. When set to True, the returned numpy\n                    array contains bit packed data (dtype=np.uint8 with 8 bits per item)\n                    instead of unpacked data (dtype=np.bool_).\n\n            Returns:\n                The detection event data and (optionally) observable data. The result is a\n                single numpy array if separate_observables is false, otherwise it's a tuple\n                of two numpy arrays.\n\n                When returning two numpy arrays, the first array is the detection event data\n                and the second is the observable flip data.\n\n                The dtype of the returned arrays is np.bool_ if bit_packed is false,\n                otherwise they're np.uint8 arrays.\n\n                shape[0] of the array(s) is the number of shots.\n                shape[1] of the array(s) is the number of bits per shot (divided by 8 if bit\n                packed) (e.g. for just detection event data it would be\n                circuit.num_detectors).\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n                >>> converter = stim.Circuit('''\n                ...    X 0\n                ...    M 0 1\n                ...    DETECTOR rec[-1]\n                ...    DETECTOR rec[-2]\n                ...    OBSERVABLE_INCLUDE(0) rec[-2]\n                ... ''').compile_m2d_converter()\n                >>> dets, obs = converter.convert(\n                ...     measurements=np.array([[1, 0],\n                ...                            [1, 0],\n                ...                            [1, 0],\n                ...                            [0, 0],\n                ...                            [1, 0]], dtype=np.bool_),\n                ...     separate_observables=True,\n                ... )\n                >>> dets\n                array([[False, False],\n                       [False, False],\n                       [False, False],\n                       [False,  True],\n                       [False, False]])\n                >>> obs\n                array([[False],\n                       [False],\n                       [False],\n                       [ True],\n                       [False]])\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__repr__\",\n        &CompiledMeasurementsToDetectionEventsConverter::repr,\n        \"Returns text that is a valid python expression evaluating to an equivalent \"\n        \"`stim.CompiledMeasurementsToDetectionEventsConverter`.\");\n\n    c.def(\n        pybind11::pickle(\n            // __getstate__ function: returns a tuple to be pickled.\n            [](const CompiledMeasurementsToDetectionEventsConverter &self) -> SerializationTuple {\n                size_t num_ref_bits = self.circuit_stats.num_measurements;\n                pybind11::object ref_sample_numpy = stim_pybind::simd_bits_to_numpy(\n                    self.ref_sample,\n                    num_ref_bits,\n                    /*bit_packed=*/true);\n\n                return SerializationTuple(self.circuit, self.skip_reference_sample, ref_sample_numpy, num_ref_bits);\n            },\n            // __setstate__ function: reconstructs the object from the Python tuple.\n            [](SerializationTuple t_py) {\n                const auto &[circuit, skip_ref, ref_bits_npy, num_ref_bits] = t_py;\n\n                stim::simd_bits<stim::MAX_BITWORD_WIDTH> reconstructed_ref_sample(num_ref_bits);\n                stim_pybind::memcpy_bits_from_numpy_to_simd(num_ref_bits, ref_bits_npy, reconstructed_ref_sample);\n\n                return CompiledMeasurementsToDetectionEventsConverter(\n                    std::move(reconstructed_ref_sample), circuit, skip_ref);\n            }));\n}\n"
  },
  {
    "path": "src/stim/simulators/measurements_to_detection_events.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_PY_SIMULATORS_MEASUREMENTS_TO_DETECTION_EVENTS_PYBIND_H\n#define _STIM_PY_SIMULATORS_MEASUREMENTS_TO_DETECTION_EVENTS_PYBIND_H\n\n#include <pybind11/numpy.h>\n#include <pybind11/pybind11.h>\n#include <pybind11/stl.h>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/mem/simd_bits.h\"\n\nnamespace stim_pybind {\n\nstruct CompiledMeasurementsToDetectionEventsConverter {\n    const bool skip_reference_sample;\n    const stim::simd_bits<stim::MAX_BITWORD_WIDTH> ref_sample;\n    const stim::CircuitStats circuit_stats;\n    const stim::Circuit circuit;\n\n    CompiledMeasurementsToDetectionEventsConverter() = delete;\n    CompiledMeasurementsToDetectionEventsConverter(const CompiledMeasurementsToDetectionEventsConverter &) = delete;\n    CompiledMeasurementsToDetectionEventsConverter(CompiledMeasurementsToDetectionEventsConverter &&) = default;\n\n    CompiledMeasurementsToDetectionEventsConverter(\n        stim::simd_bits<stim::MAX_BITWORD_WIDTH> ref_sample, stim::Circuit circuit, bool skip_reference_sample);\n\n    pybind11::object convert(\n        const pybind11::object &measurements,\n        const pybind11::object &sweep_bits,\n        const pybind11::object &separate_observables,\n        const pybind11::object &append_observables,\n        bool bit_pack_result_old_compat,\n        bool bit_pack_result);\n    void convert_file(\n        std::string_view measurements_filepath,\n        std::string_view measurements_format,\n        const char *sweep_bits_filepath,\n        std::string_view sweep_bits_format,\n        std::string_view detection_events_filepath,\n        std::string_view detection_events_format,\n        bool append_observables,\n        const char *obs_out_filepath,\n        std::string_view obs_out_format);\n\n    std::string repr() const;\n};\n\npybind11::class_<CompiledMeasurementsToDetectionEventsConverter>\npybind_compiled_measurements_to_detection_events_converter(pybind11::module &m);\nvoid pybind_compiled_measurements_to_detection_events_converter_methods(\n    pybind11::module &m, pybind11::class_<CompiledMeasurementsToDetectionEventsConverter> &c);\nCompiledMeasurementsToDetectionEventsConverter py_init_compiled_measurements_to_detection_events_converter(\n    const stim::Circuit &circuit, bool skip_reference_sample);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/measurements_to_detection_events.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/measurements_to_detection_events.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, single_detector_no_sweep_data, {\n    simd_bit_table<W> measurement_data(1, 256);\n    simd_bit_table<W> sweep_data(0, 256);\n    simd_bit_table<W> converted(1, 256);\n\n    // Matches false expectation.\n    ASSERT_EQ(\n        measurements_to_detection_events(\n            measurement_data,\n            sweep_data,\n            Circuit(R\"CIRCUIT(\n                M 0\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false),\n        simd_bit_table<W>::from_text(\"0\", 1, 256));\n\n    // Violates true expectation.\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            M !0\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], true);\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], true);\n\n    // Violates false expectation.\n    measurement_data[0][0] = true;\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            M 0\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], true);\n\n    // Matches true expectation.\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            M !0\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], false);\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], false);\n\n    // Indexing.\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            M 0 1\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], false);\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            M 0 1\n            DETECTOR rec[-2]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], true);\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            M 0 1\n            DETECTOR rec[-1] rec[-2]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], true);\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            M 0 1\n            DETECTOR\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], false);\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, sweep_data, {\n    auto expected = simd_bit_table<W>::from_text(R\"DETECTOR_DATA(\n            ..1.....1\n            111....1.\n            .._1..1..\n            ..1..111.\n            ..1.1..11\n            ..11.....\n            11_......\n            .1_1.....\n            1.1...11.\n            ..1....11\n            11_1..1_1\n        )DETECTOR_DATA\");\n    for (size_t k = 11; k < expected.num_major_bits_padded(); k++) {\n        expected[k][2] = true;\n    }\n\n    ASSERT_EQ(\n        measurements_to_detection_events(\n            simd_bit_table<W>::from_text(R\"MEASUREMENT_DATA(\n                .........1\n                ........1.\n                .......1..\n                ......1...\n                .....1....\n                ....1.....\n                ...1......\n                ..1.......\n                .1........\n                1.........\n                ..........\n            )MEASUREMENT_DATA\")\n                .transposed(),\n            simd_bit_table<W>::from_text(R\"SWEEP_DATA(\n                ....\n                1...\n                .1..\n                ..1.\n                ...1\n                ....\n                1...\n                .1..\n                ..1.\n                ...1\n                1111\n            )SWEEP_DATA\")\n                .transposed(),\n            Circuit(R\"CIRCUIT(\n                CNOT sweep[0] 1 sweep[0] 2\n                CNOT sweep[1] 3 sweep[1] 4\n                CNOT sweep[3] 8 sweep[3] 9\n                CNOT sweep[2] 8 sweep[2] 7\n                X 3\n                X_ERROR(1) 4\n                M 0 1 2 3 4 5 6 7 8 9\n                DETECTOR rec[-9]\n                DETECTOR rec[-8]\n                DETECTOR rec[-7]\n                DETECTOR rec[-6]\n                DETECTOR rec[-5]\n                DETECTOR rec[-4]\n                DETECTOR rec[-3]\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            )CIRCUIT\"),\n            false,\n            false)\n            .transposed(),\n        expected);\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, empty_cases, {\n    simd_bit_table<W> measurement_data(256, 256);\n    simd_bit_table<W> converted(256, 256);\n    simd_bit_table<W> sweep_data(0, 256);\n\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted.num_major_bits_padded(), 0);\n    ASSERT_EQ(converted.num_minor_bits_padded(), 256);\n\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted.num_major_bits_padded(), 0);\n    ASSERT_EQ(converted.num_minor_bits_padded(), 256);\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, big_shots, {\n    simd_bit_table<W> measurement_data(256, 512);\n    simd_bit_table<W> converted(256, 512);\n    simd_bit_table<W> sweep_data(0, 512);\n\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            M 0 !1\n            REPEAT 50 {\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            }\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0].popcnt(), 0);\n    ASSERT_EQ(converted[1].popcnt(), 512);\n    ASSERT_EQ(converted[2].popcnt(), 0);\n    ASSERT_EQ(converted[3].popcnt(), 512);\n    ASSERT_EQ(converted[98].popcnt(), 0);\n    ASSERT_EQ(converted[99].popcnt(), 512);\n    ASSERT_EQ(converted[100].popcnt(), 0);\n    ASSERT_EQ(converted[101].popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, big_data, {\n    simd_bit_table<W> measurement_data(512, 256);\n    simd_bit_table<W> converted(512, 256);\n    simd_bit_table<W> sweep_data(0, 256);\n\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            M 0 !1\n            REPEAT 200 {\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            }\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0].popcnt(), 0);\n    ASSERT_EQ(converted[1].popcnt(), 256);\n    ASSERT_EQ(converted[2].popcnt(), 0);\n    ASSERT_EQ(converted[3].popcnt(), 256);\n    ASSERT_EQ(converted[398].popcnt(), 0);\n    ASSERT_EQ(converted[399].popcnt(), 256);\n    ASSERT_EQ(converted[400].popcnt(), 0);\n    ASSERT_EQ(converted[401].popcnt(), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, append_observables, {\n    simd_bit_table<W> measurement_data(256, 256);\n    simd_bit_table<W> sweep_data(0, 256);\n    simd_bit_table<W> converted(256, 256);\n    size_t min_bits = sizeof(simd_word<W>) * 8;\n\n    // Appended.\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            OBSERVABLE_INCLUDE(9) rec[-1]\n        )CIRCUIT\"),\n        true,\n        false);\n    ASSERT_EQ(converted.num_major_bits_padded(), min_bits);\n    ASSERT_EQ(converted.num_minor_bits_padded(), 256);\n    ASSERT_EQ(converted[0][0], 0);\n    ASSERT_EQ(converted[1][0], 0);\n    ASSERT_EQ(converted[9][0], 1);\n    ASSERT_EQ(converted[11][0], 0);\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(9) rec[-1]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        true,\n        false);\n    ASSERT_EQ(converted.num_major_bits_padded(), min_bits);\n    ASSERT_EQ(converted.num_minor_bits_padded(), 256);\n    ASSERT_EQ(converted[0][0], 1);\n    ASSERT_EQ(converted[1][0], 1);\n    ASSERT_EQ(converted[9][0], 0);\n    ASSERT_EQ(converted[11][0], 1);\n\n    // Not appended.\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            OBSERVABLE_INCLUDE(9) rec[-1]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted.num_major_bits_padded(), 0);\n    ASSERT_EQ(converted.num_minor_bits_padded(), 256);\n    converted = measurements_to_detection_events(\n        measurement_data,\n        sweep_data,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(9) rec[-1]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        false,\n        false);\n    ASSERT_EQ(converted[0][0], 1);\n    ASSERT_EQ(converted[1][0], 1);\n    ASSERT_EQ(converted[9][0], 0);\n    ASSERT_EQ(converted[11][0], 0);\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, file_01_to_dets_no_obs, {\n    FILE *in = tmpfile();\n    fprintf(in, \"%s\", \"0\\n0\\n1\\n\");\n    rewind(in);\n    FILE *out = tmpfile();\n\n    stream_measurements_to_detection_events<W>(\n        in,\n        SampleFormat::SAMPLE_FORMAT_01,\n        nullptr,\n        (SampleFormat)0,\n        out,\n        SampleFormat::SAMPLE_FORMAT_DETS,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(9) rec[-1]\n            DETECTOR\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        false,\n        false,\n        nullptr,\n        SampleFormat::SAMPLE_FORMAT_01);\n    ASSERT_EQ(rewind_read_close(out), \"shot D0 D2\\nshot D0 D2\\nshot\\n\");\n    fclose(in);\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, file_01_to_dets_yes_obs, {\n    FILE *in = tmpfile();\n    fprintf(in, \"%s\", \"0\\n0\\n1\\n\");\n    rewind(in);\n    FILE *out = tmpfile();\n\n    stream_measurements_to_detection_events<W>(\n        in,\n        SampleFormat::SAMPLE_FORMAT_01,\n        nullptr,\n        (SampleFormat)0,\n        out,\n        SampleFormat::SAMPLE_FORMAT_DETS,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(9) rec[-1]\n            DETECTOR\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        true,\n        false,\n        nullptr,\n        SampleFormat::SAMPLE_FORMAT_01);\n    fclose(in);\n    ASSERT_EQ(rewind_read_close(out), \"shot D0 D2 L9\\nshot D0 D2 L9\\nshot\\n\");\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, with_error_propagation, {\n    FILE *in = tmpfile();\n    fprintf(\n        in,\n        \"%s\",\n        \"00\\n\"\n        \"00\\n\"\n        \"00\\n\"\n        \"00\\n\"\n        \"00\\n\"\n        \"00\\n\"\n\n        \"01\\n\"\n        \"01\\n\"\n\n        \"11\\n\"\n        \"11\\n\");\n    rewind(in);\n    FILE *in_sweep_bits = tmpfile();\n    fprintf(\n        in_sweep_bits,\n        \"%s\",\n        \"0000\\n\"\n        \"1000\\n\"\n        \"0100\\n\"\n        \"0010\\n\"\n        \"0001\\n\"\n        \"1111\\n\"\n\n        \"0000\\n\"\n        \"1111\\n\"\n\n        \"0000\\n\"\n        \"1111\\n\");\n    rewind(in_sweep_bits);\n    FILE *out = tmpfile();\n\n    stream_measurements_to_detection_events<W>(\n        in,\n        SampleFormat::SAMPLE_FORMAT_01,\n        in_sweep_bits,\n        SampleFormat::SAMPLE_FORMAT_01,\n        out,\n        SampleFormat::SAMPLE_FORMAT_DETS,\n        Circuit(R\"CIRCUIT(\n            CX sweep[0] 0\n            CX sweep[1] 1\n            CZ sweep[2] 0\n            CZ sweep[3] 1\n            H 0 1\n            CZ 0 1\n            M 0\n            MX 1\n            DETECTOR rec[-1] rec[-2]\n        )CIRCUIT\"),\n        true,\n        false,\n        nullptr,\n        SampleFormat::SAMPLE_FORMAT_01);\n    fclose(in);\n    fclose(in_sweep_bits);\n    ASSERT_EQ(\n        rewind_read_close(out),\n        \"shot\\n\"     // No error no flip.\n        \"shot\\n\"     // X0 doesn't flip.\n        \"shot D0\\n\"  // X1 does flip.\n        \"shot\\n\"     // Z0 doesn't flip.\n        \"shot\\n\"     // Z1 doesn't flip.\n        \"shot D0\\n\"  // All together flips.\n\n        \"shot D0\\n\"  // One excited measurement causes a detection event.\n        \"shot\\n\"     // All together restores.\n\n        \"shot\\n\"     // Two excited measurements is not a detection.\n        \"shot D0\\n\"  // All together still flips.\n    );\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, many_shots, {\n    FILE *in = tmpfile();\n    std::string expected;\n    for (size_t k = 0; k < 500; k++) {\n        fprintf(in, \"%s\", \"0\\n1\\n\");\n        expected += \"shot D0 D1\\nshot\\n\";\n    }\n    rewind(in);\n    FILE *out = tmpfile();\n\n    stream_measurements_to_detection_events<W>(\n        in,\n        SampleFormat::SAMPLE_FORMAT_01,\n        nullptr,\n        (SampleFormat)0,\n        out,\n        SampleFormat::SAMPLE_FORMAT_DETS,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            DETECTOR rec[-1]\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        true,\n        false,\n        nullptr,\n        SampleFormat::SAMPLE_FORMAT_01);\n    fclose(in);\n    ASSERT_EQ(rewind_read_close(out), expected);\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, many_measurements_and_detectors, {\n    FILE *in = tmpfile();\n    std::string expected = \"shot\";\n    for (size_t k = 0; k < 500; k++) {\n        fprintf(in, \"%s\", \"01\");\n        expected += \" D\" + std::to_string(2 * k + 1);\n    }\n    expected += \"\\n\";\n    fprintf(in, \"%s\", \"\\n\");\n    rewind(in);\n    FILE *out = tmpfile();\n\n    stream_measurements_to_detection_events<W>(\n        in,\n        SampleFormat::SAMPLE_FORMAT_01,\n        nullptr,\n        (SampleFormat)0,\n        out,\n        SampleFormat::SAMPLE_FORMAT_DETS,\n        Circuit(R\"CIRCUIT(\n            REPEAT 500 {\n                M 0 1\n                DETECTOR rec[-2]\n                DETECTOR rec[-1]\n            }\n        )CIRCUIT\"),\n        true,\n        false,\n        nullptr,\n        SampleFormat::SAMPLE_FORMAT_01);\n    fclose(in);\n    ASSERT_EQ(rewind_read_close(out), expected);\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, file_01_to_01_yes_obs, {\n    FILE *in = tmpfile();\n    fprintf(in, \"%s\", \"0\\n0\\n1\\n\");\n    rewind(in);\n    FILE *out = tmpfile();\n\n    stream_measurements_to_detection_events<W>(\n        in,\n        SampleFormat::SAMPLE_FORMAT_01,\n        nullptr,\n        (SampleFormat)0,\n        out,\n        SampleFormat::SAMPLE_FORMAT_01,\n        Circuit(R\"CIRCUIT(\n            X 0\n            M 0\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(9) rec[-1]\n            DETECTOR\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n        true,\n        false,\n        nullptr,\n        SampleFormat::SAMPLE_FORMAT_01);\n    fclose(in);\n    ASSERT_EQ(rewind_read_close(out), \"1010000000001\\n1010000000001\\n0000000000000\\n\");\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, empty_input_01_empty_sweep_b8, {\n    FILE *in = tmpfile();\n    FILE *sweep = tmpfile();\n    FILE *out = tmpfile();\n\n    stream_measurements_to_detection_events<W>(\n        in,\n        SampleFormat::SAMPLE_FORMAT_01,\n        sweep,\n        SampleFormat::SAMPLE_FORMAT_B8,\n        out,\n        SampleFormat::SAMPLE_FORMAT_01,\n        Circuit(),\n        true,\n        false,\n        nullptr,\n        SampleFormat::SAMPLE_FORMAT_01);\n    fclose(in);\n    fclose(sweep);\n    ASSERT_EQ(rewind_read_close(out), \"\");\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, some_input_01_empty_sweep_b8, {\n    FILE *in = tmpfile();\n    fprintf(in, \"%s\", \"\\n\\n\");\n    rewind(in);\n    FILE *sweep = tmpfile();\n    FILE *out = tmpfile();\n\n    stream_measurements_to_detection_events<W>(\n        in,\n        SampleFormat::SAMPLE_FORMAT_01,\n        sweep,\n        SampleFormat::SAMPLE_FORMAT_B8,\n        out,\n        SampleFormat::SAMPLE_FORMAT_01,\n        Circuit(),\n        true,\n        false,\n        nullptr,\n        SampleFormat::SAMPLE_FORMAT_01);\n    fclose(in);\n    fclose(sweep);\n    ASSERT_EQ(rewind_read_close(out), \"\\n\\n\");\n})\n\nTEST_EACH_WORD_SIZE_W(measurements_to_detection_events, empty_input_b8_empty_sweep_b8, {\n    FILE *in = tmpfile();\n    FILE *sweep = tmpfile();\n    FILE *out = tmpfile();\n\n    ASSERT_THROW(\n        {\n            stream_measurements_to_detection_events<W>(\n                in,\n                SampleFormat::SAMPLE_FORMAT_B8,\n                sweep,\n                SampleFormat::SAMPLE_FORMAT_B8,\n                out,\n                SampleFormat::SAMPLE_FORMAT_01,\n                Circuit(),\n                true,\n                false,\n                nullptr,\n                SampleFormat::SAMPLE_FORMAT_01);\n        },\n        std::invalid_argument);\n    fclose(in);\n    fclose(sweep);\n    ASSERT_EQ(rewind_read_close(out), \"\");\n})\n"
  },
  {
    "path": "src/stim/simulators/measurements_to_detection_events_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport tempfile\n\nimport numpy as np\nimport pytest\nimport pickle\nimport stim\n\n\ndef test_convert_file_without_sweep_bits():\n    converter = stim.Circuit('''\n        X_ERROR(0.1) 0\n        X 0\n        CNOT sweep[0] 0\n        M 0\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    ''').compile_m2d_converter()\n\n    with tempfile.TemporaryDirectory() as d:\n        with open(f\"{d}/measurements.01\", \"w\") as f:\n            print(\"0\", file=f)\n            print(\"1\", file=f)\n\n        converter.convert_file(\n            measurements_filepath=f\"{d}/measurements.01\",\n            detection_events_filepath=f\"{d}/detections.01\",\n            append_observables=False,\n        )\n\n        with open(f\"{d}/detections.01\") as f:\n            assert f.read() == \"1\\n0\\n\"\n\n    with tempfile.TemporaryDirectory() as d:\n        with open(f\"{d}/measurements.b8\", \"wb\") as f:\n            f.write((0).to_bytes(1, 'big'))\n            f.write((1).to_bytes(1, 'big'))\n            f.write((0).to_bytes(1, 'big'))\n            f.write((1).to_bytes(1, 'big'))\n        with open(f\"{d}/sweep.hits\", \"w\") as f:\n            print(\"\", file=f)\n            print(\"\", file=f)\n            print(\"0\", file=f)\n            print(\"0\", file=f)\n\n        converter.convert_file(\n            measurements_filepath=f\"{d}/measurements.b8\",\n            measurements_format=\"b8\",\n            sweep_bits_filepath=f\"{d}/sweep.hits\",\n            sweep_bits_format=\"hits\",\n            detection_events_filepath=f\"{d}/detections.dets\",\n            detection_events_format=\"dets\",\n            append_observables=True,\n        )\n\n        with open(f\"{d}/detections.dets\") as f:\n            assert f.read() == \"shot D0 L0\\nshot\\nshot\\nshot D0 L0\\n\"\n\n        converter.convert_file(\n            measurements_filepath=f\"{d}/measurements.b8\",\n            measurements_format=\"b8\",\n            sweep_bits_filepath=f\"{d}/sweep.hits\",\n            sweep_bits_format=\"hits\",\n            detection_events_filepath=f\"{d}/detections.dets\",\n            detection_events_format=\"dets\",\n            obs_out_filepath=f\"{d}/obs.hits\",\n            obs_out_format=\"hits\",\n        )\n\n        with open(f\"{d}/detections.dets\") as f:\n            assert f.read() == \"shot D0\\nshot\\nshot\\nshot D0\\n\"\n        with open(f\"{d}/obs.hits\") as f:\n            assert f.read() == \"0\\n\\n\\n0\\n\"\n\n\ndef test_convert():\n    converter = stim.Circuit('''\n       X_ERROR(0.1) 0\n       X 0\n       CNOT sweep[0] 0\n       M 0\n       DETECTOR rec[-1]\n       OBSERVABLE_INCLUDE(0) rec[-1]\n    ''').compile_m2d_converter()\n\n    result = converter.convert(\n        measurements=np.array([[0], [1]], dtype=np.bool_),\n        append_observables=False,\n    )\n    assert result.dtype == np.bool_\n    assert result.shape == (2, 1)\n    np.testing.assert_array_equal(result, [[1], [0]])\n\n    result = converter.convert(\n        measurements=np.array([[0], [1]], dtype=np.bool_),\n        append_observables=True,\n    )\n    assert result.dtype == np.bool_\n    assert result.shape == (2, 2)\n    np.testing.assert_array_equal(result, [[1, 1], [0, 0]])\n\n    result = converter.convert(\n        measurements=np.array([[0], [1], [0], [1]], dtype=np.bool_),\n        sweep_bits=np.array([[0], [0], [1], [1]], dtype=np.bool_),\n        append_observables=True,\n    )\n    assert result.dtype == np.bool_\n    assert result.shape == (4, 2)\n    np.testing.assert_array_equal(result, [[1, 1], [0, 0], [0, 0], [1, 1]])\n\n\ndef test_convert_bit_packed():\n    converter = stim.Circuit('''\n       REPEAT 100 {\n           X_ERROR(0.1) 0\n           X 0\n           MR 0\n           DETECTOR rec[-1]\n       }\n    ''').compile_m2d_converter()\n\n    measurements = np.array([[0] * 100, [1] * 100], dtype=np.bool_)\n    expected_detections = np.array([[1] * 100, [0] * 100], dtype=np.bool_)\n    measurements_bit_packed = np.packbits(measurements, axis=1, bitorder='little')\n    expected_detections_packed = np.packbits(expected_detections, axis=1, bitorder='little')\n\n    for m in measurements, measurements_bit_packed:\n        result = converter.convert(\n            measurements=m,\n            append_observables=False,\n        )\n        assert result.dtype == np.bool_\n        assert result.shape == (2, 100)\n        np.testing.assert_array_equal(result, expected_detections)\n\n        # Check legacy argument name `bit_pack_result`.\n        result = converter.convert(\n            measurements=m,\n            append_observables=False,\n            bit_pack_result=True,\n        )\n        assert result.dtype == np.uint8\n        assert result.shape == (2, 13)\n        np.testing.assert_array_equal(result, expected_detections_packed)\n\n        result = converter.convert(\n            measurements=m,\n            append_observables=False,\n            bit_packed=True,\n        )\n        assert result.dtype == np.uint8\n        assert result.shape == (2, 13)\n        np.testing.assert_array_equal(result, expected_detections_packed)\n\n\ndef test_convert_bit_packed_swept():\n    converter = stim.Circuit('''\n       REPEAT 100 {\n           CNOT sweep[0] 0\n           X_ERROR(0.1) 0\n           X 0\n           MR 0\n           DETECTOR rec[-1]\n       }\n    ''').compile_m2d_converter()\n\n    measurements = np.array([[0] * 100, [1] * 100], dtype=np.bool_)\n    sweeps = np.array([[1], [0]], dtype=np.bool_)\n    expected_detections = np.array([[0] * 100, [0] * 100], dtype=np.bool_)\n\n    measurements_packed = np.packbits(measurements, axis=1, bitorder='little')\n    expected_detections_packed = np.packbits(expected_detections, axis=1, bitorder='little')\n    sweeps_packed = np.packbits(sweeps, axis=1, bitorder='little')\n\n    for m in measurements, measurements_packed:\n        for s in sweeps, sweeps_packed:\n            result = converter.convert(\n                measurements=m,\n                sweep_bits=s,\n                append_observables=False,\n            )\n            assert result.dtype == np.bool_\n            assert result.shape == (2, 100)\n            np.testing.assert_array_equal(result, expected_detections)\n\n            result = converter.convert(\n                measurements=m,\n                sweep_bits=s,\n                append_observables=False,\n                bit_pack_result=True,\n            )\n            assert result.dtype == np.uint8\n            assert result.shape == (2, 13)\n            np.testing.assert_array_equal(result, expected_detections_packed)\n\n\ndef test_convert_bit_packed_separate_observables():\n    converter = stim.Circuit('''\n       REPEAT 100 {\n           X_ERROR(0.1) 0\n           X 0\n           MR 0\n           DETECTOR rec[-1]\n       }\n       OBSERVABLE_INCLUDE(0) rec[-1]\n       OBSERVABLE_INCLUDE(6) rec[-2]\n       OBSERVABLE_INCLUDE(14) rec[-3]\n    ''').compile_m2d_converter()\n\n    measurements = np.array([[0] * 100, [1] * 100], dtype=np.bool_)\n    expected_dets = np.array([[1] * 100, [0] * 100], dtype=np.bool_)\n    expected_obs = np.array([[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], [0] * 15], dtype=np.bool_)\n    measurements_bit_packed = np.packbits(measurements, axis=1, bitorder='little')\n    expected_dets_packed = np.packbits(expected_dets, axis=1, bitorder='little')\n    expected_obs_packed = np.packbits(expected_obs, axis=1, bitorder='little')\n\n    for m in measurements, measurements_bit_packed:\n        actual_dets, actual_obs = converter.convert(\n            measurements=m,\n            separate_observables=True,\n        )\n        assert actual_dets.dtype == actual_obs.dtype == np.bool_\n        assert actual_dets.shape == (2, 100)\n        assert actual_obs.shape == (2, 15)\n        np.testing.assert_array_equal(actual_dets, expected_dets)\n        np.testing.assert_array_equal(actual_obs, expected_obs)\n\n        actual_dets, actual_obs = converter.convert(\n            measurements=m,\n            separate_observables=True,\n            bit_pack_result=True,\n        )\n        assert actual_dets.dtype == actual_obs.dtype == np.uint8\n        assert actual_dets.shape == (2, 13)\n        assert actual_obs.shape == (2, 2)\n        np.testing.assert_array_equal(actual_dets, expected_dets_packed)\n        np.testing.assert_array_equal(actual_obs, expected_obs_packed)\n\n\ndef test_noiseless_conversion():\n    converter = stim.Circuit('''\n       MR 0\n       DETECTOR rec[-1]\n       X 0\n       MR 0\n       DETECTOR rec[-1]\n       OBSERVABLE_INCLUDE(0) rec[-1]\n    ''').compile_m2d_converter()\n\n    measurements = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=np.bool_)\n    expected_dets = np.array([[0, 1], [0, 0], [1, 1], [1, 0]], dtype=np.bool_)\n    expected_obs = np.array([[1], [0], [1], [0]], dtype=np.bool_)\n\n    actual_dets, actual_obs = converter.convert(\n        measurements=measurements,\n        separate_observables=True,\n    )\n    assert actual_dets.dtype == actual_obs.dtype == np.bool_\n    assert actual_dets.shape == (4, 2)\n    assert actual_obs.shape == (4, 1)\n    np.testing.assert_array_equal(actual_dets, expected_dets)\n    np.testing.assert_array_equal(actual_obs, expected_obs)\n\n\ndef test_needs_append_or_separate():\n    converter = stim.Circuit().compile_m2d_converter()\n    ms = np.zeros(shape=(50, 0), dtype=np.bool_)\n    with pytest.raises(ValueError, match=\"explicitly specify either separate\"):\n        converter.convert(measurements=ms)\n    d1 = converter.convert(measurements=ms, append_observables=True)\n    d2, d3 = converter.convert(measurements=ms, separate_observables=True)\n    d4, d5 = converter.convert(measurements=ms, separate_observables=True, append_observables=True)\n    np.testing.assert_array_equal(d1, d2)\n    np.testing.assert_array_equal(d1, d3)\n    np.testing.assert_array_equal(d1, d4)\n    np.testing.assert_array_equal(d1, d5)\n\n\ndef test_anticommuting_pieces_combining_into_deterministic_observable():\n    c = stim.Circuit('''\n        MX 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        MX 0\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    ''').without_noise()\n    m = c.compile_sampler().sample_bit_packed(shots=1000)\n    det, obs = c.compile_m2d_converter().convert(measurements=m, separate_observables=True)\n    np.testing.assert_array_equal(obs, obs * 0)\n\n\ndef test_converter_pickle():\n    converter = stim.Circuit('''\n       X_ERROR(0.1) 0\n       X 0\n       CNOT sweep[0] 0\n       M 0\n       DETECTOR rec[-1]\n       OBSERVABLE_INCLUDE(0) rec[-1]\n    ''').compile_m2d_converter()\n\n    roundtripped = pickle.loads(pickle.dumps(converter))\n    assert str(converter) == str(roundtripped)\n\n    result = roundtripped.convert(\n        measurements=np.array([[0], [1]], dtype=np.bool_),\n        append_observables=False,\n    )\n    assert result.dtype == np.bool_\n    assert result.shape == (2, 1)\n    np.testing.assert_array_equal(result, [[1], [0]])\n\n    result = roundtripped.convert(\n        measurements=np.array([[0], [1]], dtype=np.bool_),\n        append_observables=True,\n    )\n    assert result.dtype == np.bool_\n    assert result.shape == (2, 2)\n    np.testing.assert_array_equal(result, [[1, 1], [0, 0]])\n\n    result = roundtripped.convert(\n        measurements=np.array([[0], [1], [0], [1]], dtype=np.bool_),\n        sweep_bits=np.array([[0], [0], [1], [1]], dtype=np.bool_),\n        append_observables=True,\n    )\n    assert result.dtype == np.bool_\n    assert result.shape == (4, 2)\n    np.testing.assert_array_equal(result, [[1, 1], [0, 0], [0, 0], [1, 1]])\n"
  },
  {
    "path": "src/stim/simulators/sparse_rev_frame_tracker.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/sparse_rev_frame_tracker.h\"\n\n#include \"stim/circuit/gate_decomposition.h\"\n\nusing namespace stim;\n\nvoid SparseUnsignedRevFrameTracker::undo_gate(const CircuitInstruction &inst) {\n    switch (inst.gate_type) {\n        case GateType::DETECTOR:\n            undo_DETECTOR(inst);\n            break;\n        case GateType::OBSERVABLE_INCLUDE:\n            undo_OBSERVABLE_INCLUDE(inst);\n            break;\n        case GateType::MX:\n            undo_MX(inst);\n            break;\n        case GateType::MY:\n            undo_MY(inst);\n            break;\n        case GateType::M:\n            undo_MZ(inst);\n            break;\n        case GateType::MRX:\n            undo_MRX(inst);\n            break;\n        case GateType::MRY:\n            undo_MRY(inst);\n            break;\n        case GateType::MR:\n            undo_MRZ(inst);\n            break;\n        case GateType::RX:\n            undo_RX(inst);\n            break;\n        case GateType::RY:\n            undo_RY(inst);\n            break;\n        case GateType::R:\n            undo_RZ(inst);\n            break;\n        case GateType::MPP:\n            undo_MPP(inst);\n            break;\n        case GateType::SPP:\n        case GateType::SPP_DAG:\n            undo_SPP(inst);\n            break;\n        case GateType::XCX:\n            undo_XCX(inst);\n            break;\n        case GateType::XCY:\n            undo_XCY(inst);\n            break;\n        case GateType::XCZ:\n            undo_XCZ(inst);\n            break;\n        case GateType::YCX:\n            undo_YCX(inst);\n            break;\n        case GateType::YCY:\n            undo_YCY(inst);\n            break;\n        case GateType::YCZ:\n            undo_YCZ(inst);\n            break;\n        case GateType::CX:\n            undo_ZCX(inst);\n            break;\n        case GateType::CY:\n            undo_ZCY(inst);\n            break;\n        case GateType::CZ:\n            undo_ZCZ(inst);\n            break;\n        case GateType::C_XYZ:\n        case GateType::C_NXYZ:\n        case GateType::C_XNYZ:\n        case GateType::C_XYNZ:\n            undo_C_XYZ(inst);\n            break;\n        case GateType::C_ZYX:\n        case GateType::C_NZYX:\n        case GateType::C_ZNYX:\n        case GateType::C_ZYNX:\n            undo_C_ZYX(inst);\n            break;\n        case GateType::SWAP:\n            undo_SWAP(inst);\n            break;\n        case GateType::CXSWAP:\n            undo_CXSWAP(inst);\n            break;\n        case GateType::CZSWAP:\n            undo_CZSWAP(inst);\n            break;\n        case GateType::SWAPCX:\n            undo_SWAPCX(inst);\n            break;\n        case GateType::MXX:\n            undo_MXX(inst);\n            break;\n        case GateType::MYY:\n            undo_MYY(inst);\n            break;\n        case GateType::MZZ:\n            undo_MZZ(inst);\n            break;\n\n        case GateType::SQRT_XX:\n        case GateType::SQRT_XX_DAG:\n            undo_SQRT_XX(inst);\n            break;\n\n        case GateType::SQRT_YY:\n        case GateType::SQRT_YY_DAG:\n            undo_SQRT_YY(inst);\n            break;\n\n        case GateType::SQRT_ZZ:\n        case GateType::SQRT_ZZ_DAG:\n            undo_SQRT_ZZ(inst);\n            break;\n\n        case GateType::SQRT_X:\n        case GateType::SQRT_X_DAG:\n        case GateType::H_YZ:\n        case GateType::H_NYZ:\n            undo_H_YZ(inst);\n            break;\n\n        case GateType::SQRT_Y:\n        case GateType::SQRT_Y_DAG:\n        case GateType::H:\n        case GateType::H_NXZ:\n            undo_H_XZ(inst);\n            break;\n\n        case GateType::S:\n        case GateType::S_DAG:\n        case GateType::H_XY:\n        case GateType::H_NXY:\n            undo_H_XY(inst);\n            break;\n\n        case GateType::ISWAP:\n        case GateType::ISWAP_DAG:\n            undo_ISWAP(inst);\n            break;\n\n        case GateType::TICK:\n        case GateType::QUBIT_COORDS:\n        case GateType::SHIFT_COORDS:\n        case GateType::REPEAT:\n        case GateType::DEPOLARIZE1:\n        case GateType::DEPOLARIZE2:\n        case GateType::X_ERROR:\n        case GateType::Y_ERROR:\n        case GateType::Z_ERROR:\n        case GateType::PAULI_CHANNEL_1:\n        case GateType::PAULI_CHANNEL_2:\n        case GateType::E:\n        case GateType::ELSE_CORRELATED_ERROR:\n        case GateType::X:\n        case GateType::Y:\n        case GateType::Z:\n        case GateType::I:\n        case GateType::II:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n            undo_I(inst);\n            break;\n\n        case GateType::MPAD:\n        case GateType::HERALDED_ERASE:\n        case GateType::HERALDED_PAULI_CHANNEL_1:\n            undo_MPAD(inst);\n            break;\n\n        default:\n            throw std::invalid_argument(\n                \"Not implemented by SparseUnsignedRevFrameTracker::undo_gate: \" +\n                std::string(GATE_DATA[inst.gate_type].name));\n    }\n}\n\nSparseUnsignedRevFrameTracker::SparseUnsignedRevFrameTracker(\n    uint64_t num_qubits, uint64_t num_measurements_in_past, uint64_t num_detectors_in_past, bool fail_on_anticommute)\n    : xs(num_qubits),\n      zs(num_qubits),\n      rec_bits(),\n      num_measurements_in_past(num_measurements_in_past),\n      num_detectors_in_past(num_detectors_in_past),\n      fail_on_anticommute(fail_on_anticommute),\n      anticommutations() {\n}\n\nvoid SparseUnsignedRevFrameTracker::fail_due_to_anticommutation(const CircuitInstruction &inst) {\n    std::stringstream ss;\n    ss << \"While running backwards through the circuit, during reverse-execution of the instruction\\n\";\n    ss << \"    \" << inst << \"\\n\";\n    ss << \"the following detecting region vs dissipation anticommutations occurred\\n\";\n    for (auto &[d, g] : anticommutations) {\n        ss << \"    \" << d << \" vs \" << g << \"\\n\";\n    }\n    ss << \"Therefore invalid detectors/observables are present in the circuit.\\n\";\n    throw std::invalid_argument(ss.str());\n}\n\nvoid SparseUnsignedRevFrameTracker::handle_xor_gauge(\n    SpanRef<const DemTarget> sorted1,\n    SpanRef<const DemTarget> sorted2,\n    const CircuitInstruction &inst,\n    GateTarget location) {\n    if (sorted1 == sorted2) {\n        return;\n    }\n    SparseXorVec<DemTarget> dif;\n    dif.xor_sorted_items(sorted1);\n    dif.xor_sorted_items(sorted2);\n    for (const auto &d : dif) {\n        anticommutations.insert({d, location});\n    }\n    if (fail_on_anticommute) {\n        fail_due_to_anticommutation(inst);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::handle_gauge(\n    SpanRef<const DemTarget> sorted, const CircuitInstruction &inst, GateTarget location) {\n    if (sorted.empty()) {\n        return;\n    }\n    for (const auto &d : sorted) {\n        anticommutations.insert({d, location});\n    }\n    if (fail_on_anticommute) {\n        fail_due_to_anticommutation(inst);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_classical_pauli(GateTarget classical_control, GateTarget target) {\n    if (classical_control.is_sweep_bit_target()) {\n        // Sweep bits have no effect on error propagation.\n        return;\n    }\n    assert(classical_control.is_measurement_record_target());\n\n    uint64_t measurement_index = num_measurements_in_past + classical_control.value();\n    SparseXorVec<DemTarget> &rec_dst = rec_bits[measurement_index];\n\n    auto q = target.data & TARGET_VALUE_MASK;\n    if (target.data & TARGET_PAULI_X_BIT) {\n        rec_dst ^= zs[q];\n    }\n    if (target.data & TARGET_PAULI_Z_BIT) {\n        rec_dst ^= xs[q];\n    }\n    if (rec_dst.empty()) {\n        rec_bits.erase(measurement_index);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_ZCX_single(GateTarget c, GateTarget t) {\n    auto cd = c.data;\n    auto td = t.data;\n    cd &= ~TARGET_INVERTED_BIT;\n    td &= ~TARGET_INVERTED_BIT;\n    if (!((cd | td) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        // Pure quantum operation.\n        zs[cd] ^= zs[td];\n        xs[td] ^= xs[cd];\n    } else if (!t.is_qubit_target()) {\n        throw std::invalid_argument(\"CX gate had '\" + t.str() + \"' as its target, but its target must be a qubit.\");\n    } else {\n        undo_classical_pauli(c, GateTarget::x(td));\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_ZCY_single(GateTarget c, GateTarget t) {\n    auto cd = c.data;\n    auto td = t.data;\n    cd &= ~TARGET_INVERTED_BIT;\n    td &= ~TARGET_INVERTED_BIT;\n    if (!((cd | td) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        // Pure quantum operation.\n        zs[cd] ^= zs[td];\n        zs[cd] ^= xs[td];\n        xs[td] ^= xs[cd];\n        zs[td] ^= xs[cd];\n    } else if (!t.is_qubit_target()) {\n        throw std::invalid_argument(\"CY gate had '\" + t.str() + \"' as its target, but its target must be a qubit.\");\n    } else {\n        undo_classical_pauli(c, GateTarget::y(td));\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_ZCZ_single(GateTarget c, GateTarget t) {\n    auto cd = c.data;\n    auto td = t.data;\n    cd &= ~TARGET_INVERTED_BIT;\n    td &= ~TARGET_INVERTED_BIT;\n    if (!((cd | td) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        // Pure quantum operation.\n        zs[cd] ^= xs[td];\n        zs[td] ^= xs[cd];\n    } else if (!(td & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        undo_classical_pauli(c, GateTarget::z(td));\n    } else if (!(cd & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        undo_classical_pauli(t, GateTarget::z(cd));\n    } else {\n        // Both targets are classical. No effect.\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::handle_x_gauges(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        handle_gauge(xs[q].range(), dat, GateTarget::x(q));\n    }\n}\nvoid SparseUnsignedRevFrameTracker::handle_y_gauges(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        handle_xor_gauge(xs[q].range(), zs[q].range(), dat, GateTarget::y(q));\n    }\n}\nvoid SparseUnsignedRevFrameTracker::handle_z_gauges(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        handle_gauge(zs[q].range(), dat, GateTarget::z(q));\n    }\n}\nvoid SparseUnsignedRevFrameTracker::undo_MPP(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n    decompose_mpp_operation(\n        CircuitInstruction{inst.gate_type, inst.args, reversed_targets, inst.tag},\n        xs.size(),\n        [&](const CircuitInstruction &inst) {\n            if (inst.gate_type == GateType::M) {\n                reversed_measure_targets.clear();\n                for (size_t k = inst.targets.size(); k--;) {\n                    reversed_measure_targets.push_back(inst.targets[k]);\n                }\n                undo_MZ({GateType::M, inst.args, reversed_measure_targets, inst.tag});\n            } else {\n                undo_gate(inst);\n            }\n        });\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_SPP(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n    decompose_spp_or_spp_dag_operation(\n        CircuitInstruction{inst.gate_type, inst.args, reversed_targets, inst.tag},\n        xs.size(),\n        false,\n        [&](const CircuitInstruction &inst) {\n            undo_gate(inst);\n        });\n}\n\nvoid SparseUnsignedRevFrameTracker::clear_qubits(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        xs[q].clear();\n        zs[q].clear();\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_RX(const CircuitInstruction &dat) {\n    handle_z_gauges(dat);\n    clear_qubits(dat);\n}\nvoid SparseUnsignedRevFrameTracker::undo_RY(const CircuitInstruction &dat) {\n    handle_y_gauges(dat);\n    clear_qubits(dat);\n}\nvoid SparseUnsignedRevFrameTracker::undo_RZ(const CircuitInstruction &dat) {\n    handle_x_gauges(dat);\n    clear_qubits(dat);\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_implicit_RZs_at_start_of_circuit() {\n    for (size_t q = 0; q < xs.size(); q++) {\n        for (const auto &d : xs[q]) {\n            anticommutations.insert({d, GateTarget::qubit(q)});\n        }\n    }\n    if (!anticommutations.empty() && fail_on_anticommute) {\n        std::stringstream ss;\n        ss << \"While running backwards through the circuit,\\n\";\n        ss << \"during reverse-execution of the implicit resets at the beginning of the circuit,\\n\";\n        ss << \"the following detecting region vs dissipation anticommutations occurred\\n\";\n        for (auto &[d, g] : anticommutations) {\n            ss << \"    \" << d << \" vs \" << g << \"\\n\";\n        }\n        ss << \"Therefore invalid detectors/observables are present in the circuit.\\n\";\n        throw std::invalid_argument(ss.str());\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MPAD(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        num_measurements_in_past--;\n        auto f = rec_bits.find(num_measurements_in_past);\n        if (f != rec_bits.end()) {\n            rec_bits.erase(f);\n        }\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MX(const CircuitInstruction &dat) {\n    handle_z_gauges(dat);\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        num_measurements_in_past--;\n        auto f = rec_bits.find(num_measurements_in_past);\n        if (f != rec_bits.end()) {\n            xs[q].xor_sorted_items(f->second.range());\n            rec_bits.erase(f);\n        }\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MY(const CircuitInstruction &dat) {\n    handle_y_gauges(dat);\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        num_measurements_in_past--;\n        auto f = rec_bits.find(num_measurements_in_past);\n        if (f != rec_bits.end()) {\n            xs[q].xor_sorted_items(f->second.range());\n            zs[q].xor_sorted_items(f->second.range());\n            rec_bits.erase(f);\n        }\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MZ(const CircuitInstruction &dat) {\n    handle_x_gauges(dat);\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        num_measurements_in_past--;\n        auto f = rec_bits.find(num_measurements_in_past);\n        if (f != rec_bits.end()) {\n            zs[q].xor_sorted_items(f->second.range());\n            rec_bits.erase(f);\n        }\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MXX_disjoint_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    undo_ZCX(CircuitInstruction{GateType::CX, {}, inst.targets, \"\"});\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        undo_MX(CircuitInstruction{GateType::MX, inst.args, SpanRef<const GateTarget>{&inst.targets[k]}, \"\"});\n    }\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    undo_ZCX(CircuitInstruction{GateType::CX, {}, inst.targets, \"\"});\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MYY_disjoint_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    undo_ZCY(CircuitInstruction{GateType::CY, {}, inst.targets, \"\"});\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        undo_MY(CircuitInstruction{GateType::MY, inst.args, SpanRef<const GateTarget>{&inst.targets[k]}, \"\"});\n    }\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    undo_ZCY(CircuitInstruction{GateType::CY, {}, inst.targets, \"\"});\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MZZ_disjoint_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    undo_XCZ(CircuitInstruction{GateType::XCZ, {}, inst.targets, \"\"});\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        undo_MZ(CircuitInstruction{GateType::M, inst.args, SpanRef<const GateTarget>{&inst.targets[k]}, \"\"});\n    }\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    undo_XCZ(CircuitInstruction{GateType::XCZ, {}, inst.targets, \"\"});\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MXX(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n\n    decompose_pair_instruction_into_disjoint_segments(\n        CircuitInstruction{inst.gate_type, inst.args, reversed_targets, \"\"},\n        xs.size(),\n        [&](CircuitInstruction segment) {\n            undo_MXX_disjoint_segment(segment);\n        });\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MYY(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n\n    decompose_pair_instruction_into_disjoint_segments(\n        CircuitInstruction{inst.gate_type, inst.args, reversed_targets, \"\"},\n        xs.size(),\n        [&](CircuitInstruction segment) {\n            undo_MYY_disjoint_segment(segment);\n        });\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MZZ(const CircuitInstruction &inst) {\n    size_t n = inst.targets.size();\n    std::vector<GateTarget> reversed_targets(n);\n    std::vector<GateTarget> reversed_measure_targets;\n    for (size_t k = 0; k < n; k++) {\n        reversed_targets[k] = inst.targets[n - k - 1];\n    }\n\n    decompose_pair_instruction_into_disjoint_segments(\n        CircuitInstruction{inst.gate_type, inst.args, reversed_targets, \"\"},\n        xs.size(),\n        [&](CircuitInstruction segment) {\n            undo_MZZ_disjoint_segment(segment);\n        });\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MRX(const CircuitInstruction &dat) {\n    handle_z_gauges(dat);\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        num_measurements_in_past--;\n        xs[q].clear();\n        zs[q].clear();\n        auto f = rec_bits.find(num_measurements_in_past);\n        if (f != rec_bits.end()) {\n            xs[q].xor_sorted_items(f->second.range());\n            rec_bits.erase(f);\n        }\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MRY(const CircuitInstruction &dat) {\n    handle_y_gauges(dat);\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        num_measurements_in_past--;\n        xs[q].clear();\n        zs[q].clear();\n        auto f = rec_bits.find(num_measurements_in_past);\n        if (f != rec_bits.end()) {\n            xs[q].xor_sorted_items(f->second.range());\n            zs[q].xor_sorted_items(f->second.range());\n            rec_bits.erase(f);\n        }\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_MRZ(const CircuitInstruction &dat) {\n    handle_x_gauges(dat);\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].qubit_value();\n        num_measurements_in_past--;\n        xs[q].clear();\n        zs[q].clear();\n        auto f = rec_bits.find(num_measurements_in_past);\n        if (f != rec_bits.end()) {\n            zs[q].xor_sorted_items(f->second.range());\n            rec_bits.erase(f);\n        }\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_H_XZ(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].data;\n        std::swap(xs[q], zs[q]);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_H_XY(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].data;\n        zs[q] ^= xs[q];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_H_YZ(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].data;\n        xs[q] ^= zs[q];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_C_XYZ(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].data;\n        zs[q] ^= xs[q];\n        xs[q] ^= zs[q];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_C_ZYX(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size(); k-- > 0;) {\n        auto q = dat.targets[k].data;\n        xs[q] ^= zs[q];\n        zs[q] ^= xs[q];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_XCX(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto q1 = dat.targets[k].data;\n        auto q2 = dat.targets[k + 1].data;\n        xs[q1] ^= zs[q2];\n        xs[q2] ^= zs[q1];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_XCY(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto tx = dat.targets[k].data;\n        auto ty = dat.targets[k + 1].data;\n        xs[tx] ^= xs[ty];\n        xs[tx] ^= zs[ty];\n        xs[ty] ^= zs[tx];\n        zs[ty] ^= zs[tx];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_YCX(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto tx = dat.targets[k + 1].data;\n        auto ty = dat.targets[k].data;\n        xs[tx] ^= xs[ty];\n        xs[tx] ^= zs[ty];\n        xs[ty] ^= zs[tx];\n        zs[ty] ^= zs[tx];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_ZCY(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto c = dat.targets[k];\n        auto t = dat.targets[k + 1];\n        undo_ZCY_single(c, t);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_YCZ(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto t = dat.targets[k];\n        auto c = dat.targets[k + 1];\n        undo_ZCY_single(c, t);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_YCY(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto a = dat.targets[k].data;\n        auto b = dat.targets[k + 1].data;\n        zs[a] ^= xs[b];\n        zs[a] ^= zs[b];\n        xs[a] ^= xs[b];\n        xs[a] ^= zs[b];\n\n        zs[b] ^= xs[a];\n        zs[b] ^= zs[a];\n        xs[b] ^= xs[a];\n        xs[b] ^= zs[a];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_ZCX(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto c = dat.targets[k];\n        auto t = dat.targets[k + 1];\n        undo_ZCX_single(c, t);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_XCZ(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto t = dat.targets[k];\n        auto c = dat.targets[k + 1];\n        undo_ZCX_single(c, t);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_ZCZ(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto q1 = dat.targets[k];\n        auto q2 = dat.targets[k + 1];\n        undo_ZCZ_single(q1, q2);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_SQRT_XX(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto a = dat.targets[k].data;\n        auto b = dat.targets[k + 1].data;\n        xs[a] ^= zs[a];\n        xs[a] ^= zs[b];\n        xs[b] ^= zs[a];\n        xs[b] ^= zs[b];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_SQRT_YY(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto a = dat.targets[k].data;\n        auto b = dat.targets[k + 1].data;\n        zs[a] ^= xs[a];\n        zs[b] ^= xs[b];\n        xs[a] ^= zs[a];\n        xs[a] ^= zs[b];\n        xs[b] ^= zs[a];\n        xs[b] ^= zs[b];\n        zs[a] ^= xs[a];\n        zs[b] ^= xs[b];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_SQRT_ZZ(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto a = dat.targets[k].data;\n        auto b = dat.targets[k + 1].data;\n        zs[a] ^= xs[a];\n        zs[a] ^= xs[b];\n        zs[b] ^= xs[a];\n        zs[b] ^= xs[b];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_I(const CircuitInstruction &dat) {\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_SWAP(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto a = dat.targets[k].data;\n        auto b = dat.targets[k + 1].data;\n        std::swap(xs[a], xs[b]);\n        std::swap(zs[a], zs[b]);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_CXSWAP(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto a = dat.targets[k].data;\n        auto b = dat.targets[k + 1].data;\n        zs[a] ^= zs[b];\n        zs[b] ^= zs[a];\n        xs[b] ^= xs[a];\n        xs[a] ^= xs[b];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_CZSWAP(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto a = dat.targets[k].data;\n        auto b = dat.targets[k + 1].data;\n        zs[a] ^= xs[b];\n        zs[b] ^= xs[a];\n        std::swap(xs[a], xs[b]);\n        std::swap(zs[a], zs[b]);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_SWAPCX(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto a = dat.targets[k].data;\n        auto b = dat.targets[k + 1].data;\n        zs[b] ^= zs[a];\n        zs[a] ^= zs[b];\n        xs[a] ^= xs[b];\n        xs[b] ^= xs[a];\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_ISWAP(const CircuitInstruction &dat) {\n    for (size_t k = dat.targets.size() - 2; k + 2 != 0; k -= 2) {\n        auto a = dat.targets[k].data;\n        auto b = dat.targets[k + 1].data;\n        zs[a] ^= xs[a];\n        zs[a] ^= xs[b];\n        zs[b] ^= xs[a];\n        zs[b] ^= xs[b];\n        std::swap(xs[a], xs[b]);\n        std::swap(zs[a], zs[b]);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_DETECTOR(const CircuitInstruction &dat) {\n    num_detectors_in_past--;\n    auto det = DemTarget::relative_detector_id(num_detectors_in_past);\n    for (auto t : dat.targets) {\n        int64_t index = t.rec_offset() + (int64_t)num_measurements_in_past;\n        if (index < 0) {\n            throw std::invalid_argument(\"Referred to a measurement result before the beginning of time.\");\n        }\n        rec_bits[(size_t)index].xor_item(det);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_OBSERVABLE_INCLUDE(const CircuitInstruction &dat) {\n    uint64_t obs_id = (uint32_t)dat.args[0];\n    auto obs = DemTarget::observable_id(obs_id);\n    for (auto t : dat.targets) {\n        if (t.is_measurement_record_target()) {\n            int64_t index = t.rec_offset() + (int64_t)num_measurements_in_past;\n            if (index < 0) {\n                throw std::invalid_argument(\"Referred to a measurement result before the beginning of time.\");\n            }\n            rec_bits[index].xor_item(obs);\n        } else if (t.is_pauli_target()) {\n            if (t.data & TARGET_PAULI_X_BIT) {\n                xs[t.qubit_value()].xor_item(obs);\n            }\n            if (t.data & TARGET_PAULI_Z_BIT) {\n                zs[t.qubit_value()].xor_item(obs);\n            }\n        } else {\n            throw std::invalid_argument(\"Unexpected target for OBSERVABLE_INCLUDE: \" + t.str());\n        }\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_gate(const CircuitInstruction &op, const Circuit &parent) {\n    if (op.gate_type == GateType::REPEAT) {\n        const auto &loop_body = op.repeat_block_body(parent);\n        uint64_t repeats = op.repeat_block_rep_count();\n        undo_loop(loop_body, repeats);\n    } else {\n        undo_gate(op);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_circuit(const Circuit &circuit) {\n    for (size_t k = circuit.operations.size(); k--;) {\n        undo_gate(circuit.operations[k], circuit);\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_loop_by_unrolling(const Circuit &loop, uint64_t iterations) {\n    for (size_t rep = 0; rep < iterations; rep++) {\n        undo_circuit(loop);\n    }\n}\n\nbool _det_vec_is_equal_to_after_shift(\n    SpanRef<const DemTarget> unshifted, SpanRef<const DemTarget> expected, int64_t detector_shift) {\n    if (unshifted.size() != expected.size()) {\n        return false;\n    }\n    for (size_t k = 0; k < unshifted.size(); k++) {\n        DemTarget a = unshifted[k];\n        DemTarget e = expected[k];\n        a.shift_if_detector_id(detector_shift);\n        if (a != e) {\n            return false;\n        }\n    }\n    return true;\n}\n\nbool _rec_to_det_is_equal_to_after_shift(\n    const std::map<uint64_t, SparseXorVec<DemTarget>> &unshifted,\n    const std::map<uint64_t, SparseXorVec<DemTarget>> &expected,\n    int64_t measure_offset,\n    int64_t detector_offset) {\n    if (unshifted.size() != expected.size()) {\n        return false;\n    }\n    for (const auto &unshifted_entry : unshifted) {\n        const auto &shifted_entry = expected.find(unshifted_entry.first + measure_offset);\n        if (shifted_entry == expected.end()) {\n            return false;\n        }\n        if (!_det_vec_is_equal_to_after_shift(\n                unshifted_entry.second.range(), shifted_entry->second.range(), detector_offset)) {\n            return false;\n        }\n    }\n    return true;\n}\n\nbool _vec_to_det_is_equal_to_after_shift(\n    const std::vector<SparseXorVec<DemTarget>> &unshifted,\n    const std::vector<SparseXorVec<DemTarget>> &expected,\n    int64_t detector_offset) {\n    if (unshifted.size() != expected.size()) {\n        return false;\n    }\n    for (size_t k = 0; k < unshifted.size(); k++) {\n        if (!_det_vec_is_equal_to_after_shift(unshifted[k].range(), expected[k].range(), detector_offset)) {\n            return false;\n        }\n    }\n    return true;\n}\n\nbool SparseUnsignedRevFrameTracker::is_shifted_copy(const SparseUnsignedRevFrameTracker &other) const {\n    int64_t measurement_offset = (int64_t)other.num_measurements_in_past - (int64_t)num_measurements_in_past;\n    int64_t detector_offset = (int64_t)other.num_detectors_in_past - (int64_t)num_detectors_in_past;\n    return _rec_to_det_is_equal_to_after_shift(rec_bits, other.rec_bits, measurement_offset, detector_offset) &&\n           _vec_to_det_is_equal_to_after_shift(xs, other.xs, detector_offset) &&\n           _vec_to_det_is_equal_to_after_shift(zs, other.zs, detector_offset);\n}\n\nbool SparseUnsignedRevFrameTracker::operator==(const SparseUnsignedRevFrameTracker &other) const {\n    return xs == other.xs && zs == other.zs && rec_bits == other.rec_bits &&\n           num_measurements_in_past == other.num_measurements_in_past &&\n           num_detectors_in_past == other.num_detectors_in_past;\n}\n\nbool SparseUnsignedRevFrameTracker::operator!=(const SparseUnsignedRevFrameTracker &other) const {\n    return !(*this == other);\n}\n\nvoid SparseUnsignedRevFrameTracker::shift(int64_t measurement_offset, int64_t detector_offset) {\n    num_measurements_in_past += measurement_offset;\n    num_detectors_in_past += detector_offset;\n\n    std::vector<std::pair<uint64_t, SparseXorVec<DemTarget>>> shifted;\n    shifted.reserve(rec_bits.size());\n    for (const auto &t : rec_bits) {\n        shifted.push_back({t.first + measurement_offset, std::move(t.second)});\n        for (auto &e : shifted.back().second) {\n            e.shift_if_detector_id(detector_offset);\n        }\n    }\n    rec_bits.clear();\n    for (const auto &e : shifted) {\n        rec_bits.insert(std::move(e));\n    }\n\n    for (auto &x : xs) {\n        for (auto &e : x.sorted_items) {\n            e.shift_if_detector_id(detector_offset);\n        }\n    }\n    for (auto &z : zs) {\n        for (auto &e : z.sorted_items) {\n            e.shift_if_detector_id(detector_offset);\n        }\n    }\n}\n\nvoid SparseUnsignedRevFrameTracker::undo_loop(const Circuit &loop, uint64_t iterations) {\n    if (iterations < 5) {\n        undo_loop_by_unrolling(loop, iterations);\n        return;\n    }\n\n    SparseUnsignedRevFrameTracker tortoise(*this);\n    uint64_t hare_steps = 0;\n    uint64_t tortoise_steps = 0;\n\n    while (true) {\n        undo_circuit(loop);\n        hare_steps++;\n        if (is_shifted_copy(tortoise)) {\n            break;\n        }\n\n        if (hare_steps > iterations - hare_steps) {\n            undo_loop_by_unrolling(loop, iterations - hare_steps);\n            return;\n        }\n\n        if ((hare_steps & 1) == 0) {\n            tortoise.undo_circuit(loop);\n            tortoise_steps++;\n            if (is_shifted_copy(tortoise)) {\n                break;\n            }\n        }\n    }\n\n    uint64_t period = hare_steps - tortoise_steps;\n    assert(period > 0);\n    uint64_t skipped_iterations = (iterations - hare_steps) / period;\n    uint64_t detectors_per_period = tortoise.num_detectors_in_past - num_detectors_in_past;\n    uint64_t measurements_per_period = tortoise.num_measurements_in_past - num_measurements_in_past;\n    shift(\n        -(int64_t)(measurements_per_period * skipped_iterations),\n        -(int64_t)(detectors_per_period * skipped_iterations));\n    hare_steps += skipped_iterations * period;\n\n    undo_loop_by_unrolling(loop, iterations - hare_steps);\n}\n\nstd::string SparseUnsignedRevFrameTracker::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const SparseUnsignedRevFrameTracker &tracker) {\n    out << \"SparseUnsignedRevFrameTracker {\\n\";\n    out << \"    num_measurements_in_past=\" << tracker.num_measurements_in_past << \"\\n\";\n    out << \"    num_detectors_in_past=\" << tracker.num_detectors_in_past << \"\\n\";\n    for (size_t q = 0; q < tracker.xs.size(); q++) {\n        out << \"    xs[\" << q << \"]=\" << tracker.xs[q] << \"\\n\";\n    }\n    for (size_t q = 0; q < tracker.zs.size(); q++) {\n        out << \"    zs[\" << q << \"]=\" << tracker.zs[q] << \"\\n\";\n    }\n    for (const auto &t : tracker.rec_bits) {\n        out << \"    rec_bits[\" << t.first << \"]=\" << t.second << \"\\n\";\n    }\n    out << \"}\";\n    return out;\n}\n"
  },
  {
    "path": "src/stim/simulators/sparse_rev_frame_tracker.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_SPARSE_REV_FRAME_TRACKER_H\n#define _STIM_SIMULATORS_SPARSE_REV_FRAME_TRACKER_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/mem/sparse_xor_vec.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\n/// Tracks pauli frames through the circuit, assuming few frames depend on any one qubit.\nstruct SparseUnsignedRevFrameTracker {\n    /// Per qubit, what terms have X basis dependence on this qubit.\n    std::vector<SparseXorVec<DemTarget>> xs;\n    /// Per qubit, what terms have Z basis dependence on this qubit.\n    std::vector<SparseXorVec<DemTarget>> zs;\n    /// Per classical bit, what terms have dependence on measurement bits.\n    std::map<uint64_t, SparseXorVec<DemTarget>> rec_bits;\n    /// Number of measurements that have not yet been processed.\n    uint64_t num_measurements_in_past;\n    /// Number of detectors that have not yet been processed.\n    uint64_t num_detectors_in_past;\n    /// If false, anticommuting dets and obs are stored .\n    /// If true, an exception is raised if anticommutation is detected.\n    bool fail_on_anticommute;\n    /// Where anticommuting dets and obs are stored.\n    std::set<std::pair<DemTarget, GateTarget>> anticommutations;\n\n    SparseUnsignedRevFrameTracker(\n        uint64_t num_qubits,\n        uint64_t num_measurements_in_past,\n        uint64_t num_detectors_in_past,\n        bool fail_on_anticommute = true);\n\n    template <size_t W>\n    PauliString<W> current_error_sensitivity_for(DemTarget target) const {\n        PauliString<W> result(xs.size());\n        for (size_t q = 0; q < xs.size(); q++) {\n            result.xs[q] = std::find(xs[q].begin(), xs[q].end(), target) != xs[q].end();\n            result.zs[q] = std::find(zs[q].begin(), zs[q].end(), target) != zs[q].end();\n        }\n        return result;\n    }\n\n    void undo_gate(const CircuitInstruction &inst);\n    void undo_gate(const CircuitInstruction &op, const Circuit &parent);\n\n    void handle_xor_gauge(\n        SpanRef<const DemTarget> sorted1,\n        SpanRef<const DemTarget> sorted2,\n        const CircuitInstruction &inst,\n        GateTarget location);\n    void handle_gauge(SpanRef<const DemTarget> sorted, const CircuitInstruction &inst, GateTarget location);\n    void fail_due_to_anticommutation(const CircuitInstruction &inst);\n    void undo_classical_pauli(GateTarget classical_control, GateTarget target);\n    void undo_ZCX_single(GateTarget c, GateTarget t);\n    void undo_ZCY_single(GateTarget c, GateTarget t);\n    void undo_ZCZ_single(GateTarget c, GateTarget t);\n    void undo_circuit(const Circuit &circuit);\n    void undo_loop(const Circuit &loop, uint64_t repetitions);\n    void undo_loop_by_unrolling(const Circuit &loop, uint64_t repetitions);\n    void clear_qubits(const CircuitInstruction &inst);\n    void handle_x_gauges(const CircuitInstruction &inst);\n    void handle_y_gauges(const CircuitInstruction &inst);\n    void handle_z_gauges(const CircuitInstruction &inst);\n\n    void undo_implicit_RZs_at_start_of_circuit();\n    void undo_DETECTOR(const CircuitInstruction &inst);\n    void undo_OBSERVABLE_INCLUDE(const CircuitInstruction &inst);\n    void undo_RX(const CircuitInstruction &inst);\n    void undo_RY(const CircuitInstruction &inst);\n    void undo_RZ(const CircuitInstruction &inst);\n    void undo_MX(const CircuitInstruction &inst);\n    void undo_MY(const CircuitInstruction &inst);\n    void undo_MZ(const CircuitInstruction &inst);\n    void undo_MPP(const CircuitInstruction &inst);\n    void undo_SPP(const CircuitInstruction &inst);\n    void undo_MXX(const CircuitInstruction &inst);\n    void undo_MYY(const CircuitInstruction &inst);\n    void undo_MZZ(const CircuitInstruction &inst);\n    void undo_MPAD(const CircuitInstruction &inst);\n    void undo_MRX(const CircuitInstruction &inst);\n    void undo_MRY(const CircuitInstruction &inst);\n    void undo_MRZ(const CircuitInstruction &inst);\n    void undo_H_XZ(const CircuitInstruction &inst);\n    void undo_H_XY(const CircuitInstruction &inst);\n    void undo_H_YZ(const CircuitInstruction &inst);\n    void undo_C_XYZ(const CircuitInstruction &inst);\n    void undo_C_ZYX(const CircuitInstruction &inst);\n    void undo_XCX(const CircuitInstruction &inst);\n    void undo_XCY(const CircuitInstruction &inst);\n    void undo_XCZ(const CircuitInstruction &inst);\n    void undo_YCX(const CircuitInstruction &inst);\n    void undo_YCY(const CircuitInstruction &inst);\n    void undo_YCZ(const CircuitInstruction &inst);\n    void undo_ZCX(const CircuitInstruction &inst);\n    void undo_ZCY(const CircuitInstruction &inst);\n    void undo_ZCZ(const CircuitInstruction &inst);\n    void undo_I(const CircuitInstruction &inst);\n    void undo_SQRT_XX(const CircuitInstruction &inst);\n    void undo_SQRT_YY(const CircuitInstruction &inst);\n    void undo_SQRT_ZZ(const CircuitInstruction &inst);\n    void undo_SWAP(const CircuitInstruction &inst);\n    void undo_ISWAP(const CircuitInstruction &inst);\n    void undo_CXSWAP(const CircuitInstruction &inst);\n    void undo_CZSWAP(const CircuitInstruction &inst);\n    void undo_SWAPCX(const CircuitInstruction &inst);\n\n    template <size_t W>\n    void undo_tableau(const Tableau<W> &tableau, SpanRef<const uint32_t> targets) {\n        size_t n = tableau.num_qubits;\n        if (n != targets.size()) {\n            throw new std::invalid_argument(\"tableau.num_qubits != targets.size()\");\n        }\n        std::set<uint32_t> target_set;\n        for (size_t k = 0; k < n; k++) {\n            if (!target_set.insert(targets[k]).second) {\n                throw new std::invalid_argument(\"duplicate target\");\n            }\n        }\n\n        std::vector<SparseXorVec<DemTarget>> old_xs;\n        std::vector<SparseXorVec<DemTarget>> old_zs;\n        old_xs.reserve(n);\n        old_zs.reserve(n);\n        for (size_t k = 0; k < n; k++) {\n            old_xs.push_back(std::move(xs[targets[k]]));\n            old_zs.push_back(std::move(zs[targets[k]]));\n            xs[targets[k]].clear();\n            zs[targets[k]].clear();\n        }\n\n        for (size_t i = 0; i < n; i++) {\n            for (size_t j = 0; j < n; j++) {\n                uint64_t px = tableau.inverse_x_output_pauli_xyz(j, i);\n                if (px == 1 || px == 2) {\n                    xs[targets[i]] ^= old_xs[j];\n                }\n                if (px == 2 || px == 3) {\n                    zs[targets[i]] ^= old_xs[j];\n                }\n\n                uint64_t pz = tableau.inverse_z_output_pauli_xyz(j, i);\n                if (pz == 1 || pz == 2) {\n                    xs[targets[i]] ^= old_zs[j];\n                }\n                if (pz == 2 || pz == 3) {\n                    zs[targets[i]] ^= old_zs[j];\n                }\n            }\n        }\n    }\n\n    bool is_shifted_copy(const SparseUnsignedRevFrameTracker &other) const;\n    void shift(int64_t measurement_offset, int64_t detector_offset);\n    bool operator==(const SparseUnsignedRevFrameTracker &other) const;\n    bool operator!=(const SparseUnsignedRevFrameTracker &other) const;\n    std::string str() const;\n\n   private:\n    void undo_MXX_disjoint_segment(const CircuitInstruction &inst);\n    void undo_MYY_disjoint_segment(const CircuitInstruction &inst);\n    void undo_MZZ_disjoint_segment(const CircuitInstruction &inst);\n};\nstd::ostream &operator<<(std::ostream &out, const SparseUnsignedRevFrameTracker &tracker);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/sparse_rev_frame_tracker.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/sparse_rev_frame_tracker.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\ntemplate <size_t W>\nSparseUnsignedRevFrameTracker _tracker_from_pauli_string(const char *text) {\n    auto p = PauliString<W>::from_str(text);\n    SparseUnsignedRevFrameTracker result(p.num_qubits, 0, 0);\n    for (size_t q = 0; q < p.num_qubits; q++) {\n        if (p.xs[q]) {\n            result.xs[q].xor_item(DemTarget::observable_id(0));\n        }\n        if (p.zs[q]) {\n            result.zs[q].xor_item(DemTarget::observable_id(0));\n        }\n    }\n    return result;\n}\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, undo_tableau_h, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n    std::vector<uint32_t> targets{0};\n    auto tableau = GATE_DATA.at(\"H\").tableau<W>();\n\n    actual = _tracker_from_pauli_string<W>(\"I\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"I\"));\n\n    actual = _tracker_from_pauli_string<W>(\"X\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"Z\"));\n\n    actual = _tracker_from_pauli_string<W>(\"Y\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"Y\"));\n\n    actual = _tracker_from_pauli_string<W>(\"Z\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"X\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, undo_tableau_s, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n    std::vector<uint32_t> targets{0};\n    auto tableau = GATE_DATA.at(\"S\").tableau<W>();\n\n    actual = _tracker_from_pauli_string<W>(\"I\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"I\"));\n\n    actual = _tracker_from_pauli_string<W>(\"X\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"Y\"));\n\n    actual = _tracker_from_pauli_string<W>(\"Y\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"X\"));\n\n    actual = _tracker_from_pauli_string<W>(\"Z\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"Z\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, undo_tableau_c_xyz, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n    std::vector<uint32_t> targets{0};\n    auto tableau = GATE_DATA.at(\"C_XYZ\").tableau<W>();\n\n    actual = _tracker_from_pauli_string<W>(\"I\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"I\"));\n\n    actual = _tracker_from_pauli_string<W>(\"X\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"Z\"));\n\n    actual = _tracker_from_pauli_string<W>(\"Y\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"X\"));\n\n    actual = _tracker_from_pauli_string<W>(\"Z\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"Y\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, undo_tableau_cx, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n    std::vector<uint32_t> targets{0, 1};\n    auto tableau = GATE_DATA.at(\"CX\").tableau<W>();\n\n    actual = _tracker_from_pauli_string<W>(\"II\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"II\"));\n\n    actual = _tracker_from_pauli_string<W>(\"IZ\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"ZZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"ZI\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"ZI\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XI\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XX\"));\n\n    actual = _tracker_from_pauli_string<W>(\"IX\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"IX\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YY\");\n    actual.undo_tableau<W>(tableau, targets);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XZ\"));\n})\n\nstatic std::vector<GateTarget> qubit_targets(const std::vector<uint32_t> &targets) {\n    std::vector<GateTarget> result;\n    for (uint32_t t : targets) {\n        result.push_back(GateTarget::qubit(t));\n    }\n    return result;\n}\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, fuzz_all_unitary_gates_vs_tableau, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (const auto &gate : GATE_DATA.items) {\n        if (gate.has_known_unitary_matrix()) {\n            size_t n = (gate.flags & GATE_TARGETS_PAIRS) ? 2 : 1;\n            SparseUnsignedRevFrameTracker tracker_gate(n + 3, 0, 0);\n            for (size_t q = 0; q < n; q++) {\n                uint64_t mask = rng();\n                for (size_t d = 0; d < 32; d++) {\n                    if (mask & 1) {\n                        tracker_gate.xs[q].sorted_items.push_back(DemTarget::relative_detector_id(d));\n                    }\n                    mask >>= 1;\n                    if (mask & 1) {\n                        tracker_gate.zs[q].sorted_items.push_back(DemTarget::relative_detector_id(d));\n                    }\n                    mask >>= 1;\n                }\n            }\n\n            SparseUnsignedRevFrameTracker tracker_tableau = tracker_gate;\n            std::vector<uint32_t> targets;\n            for (size_t k = 0; k < n; k++) {\n                targets.push_back(n - k + 1);\n            }\n            tracker_gate.undo_gate(CircuitInstruction{gate.id, {}, qubit_targets(targets), \"\"});\n            tracker_tableau.undo_tableau<W>(gate.tableau<W>(), targets);\n            EXPECT_EQ(tracker_gate, tracker_tableau) << gate.name;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, RX, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.undo_RX(CircuitInstruction{GateType::RX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XXX\");\n    actual.undo_RX(CircuitInstruction{GateType::RX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"IXI\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XIZ\");\n    ASSERT_THROW({ actual.undo_RX({GateType::RX, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XIZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YIX\");\n    ASSERT_THROW({ actual.undo_RX({GateType::RX, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YIX\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, RY, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.undo_RY({GateType::RY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YYY\");\n    actual.undo_RY({GateType::RY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"IYI\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YIZ\");\n    ASSERT_THROW({ actual.undo_RY({GateType::RY, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YIZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XIY\");\n    ASSERT_THROW({ actual.undo_RY({GateType::RY, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XIY\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, RZ, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.undo_RZ({GateType::R, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"ZZZ\");\n    actual.undo_RZ({GateType::R, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"IZI\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YIZ\");\n    ASSERT_THROW({ actual.undo_RZ({GateType::R, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YIZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"ZIX\");\n    ASSERT_THROW({ actual.undo_RZ({GateType::R, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"ZIX\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, MX, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MX({GateType::MX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XXX\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MX({GateType::MX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XXX\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XIZ\");\n    ASSERT_THROW({ actual.undo_MX({GateType::MX, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XIZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YIX\");\n    ASSERT_THROW({ actual.undo_MX({GateType::MX, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YIX\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, MY, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MY({GateType::MY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YYY\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MY({GateType::MY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YYY\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YIZ\");\n    ASSERT_THROW({ actual.undo_MY({GateType::MY, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YIZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XIY\");\n    ASSERT_THROW({ actual.undo_MY({GateType::MY, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XIY\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, MZ, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MZ({GateType::M, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"ZZZ\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MZ({GateType::M, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"ZZZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YIZ\");\n    ASSERT_THROW({ actual.undo_MZ({GateType::M, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YIZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"ZIX\");\n    ASSERT_THROW({ actual.undo_MZ({GateType::M, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"ZIX\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, MRX, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MRX({GateType::MRX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XXX\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MRX({GateType::MRX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"IXI\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XIZ\");\n    ASSERT_THROW({ actual.undo_MRX({GateType::MRX, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XIZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YIX\");\n    ASSERT_THROW({ actual.undo_MRX({GateType::MRX, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YIX\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, MRY, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MRY({GateType::MRY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YYY\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MRY({GateType::MRY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"IYI\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YIZ\");\n    ASSERT_THROW({ actual.undo_MRY({GateType::MRY, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YIZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"XIY\");\n    ASSERT_THROW({ actual.undo_MRY({GateType::MRY, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XIY\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, MRZ, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MRZ({GateType::MR, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"ZZZ\");\n    actual.num_measurements_in_past = 2;\n    actual.undo_MRZ({GateType::MR, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"IZI\"));\n\n    actual = _tracker_from_pauli_string<W>(\"YIZ\");\n    ASSERT_THROW({ actual.undo_MRZ({GateType::MR, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YIZ\"));\n\n    actual = _tracker_from_pauli_string<W>(\"ZIX\");\n    ASSERT_THROW({ actual.undo_MRZ({GateType::MR, {}, qubit_targets({0, 2}), \"\"}); }, std::invalid_argument);\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"ZIX\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, feedback_from_measurement, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MX({GateType::MX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XII\"));\n    actual = _tracker_from_pauli_string<W>(\"XII\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MX({GateType::MX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MY({GateType::MY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YII\"));\n    actual = _tracker_from_pauli_string<W>(\"YII\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MY({GateType::MY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MZ({GateType::M, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"ZII\"));\n    actual = _tracker_from_pauli_string<W>(\"ZII\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MZ({GateType::M, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"III\"));\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MRX({GateType::MRX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XII\"));\n    actual = _tracker_from_pauli_string<W>(\"XII\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MRX({GateType::MRX, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"XII\"));\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MRY({GateType::MRY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YII\"));\n    actual = _tracker_from_pauli_string<W>(\"YII\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MRY({GateType::MRY, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"YII\"));\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MRZ({GateType::MR, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"ZII\"));\n    actual = _tracker_from_pauli_string<W>(\"ZII\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[0].xor_item(DemTarget::observable_id(0));\n    actual.undo_MRZ({GateType::MR, {}, qubit_targets({0, 2}), \"\"});\n    ASSERT_EQ(actual, _tracker_from_pauli_string<W>(\"ZII\"));\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, feedback_into_measurement, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n    SparseUnsignedRevFrameTracker expected(0, 0, 0);\n    std::vector<GateTarget> targets{GateTarget::rec(-5), GateTarget::qubit(0)};\n\n    actual = _tracker_from_pauli_string<W>(\"XII\");\n    actual.num_measurements_in_past = 12;\n    actual.undo_ZCX({GateType::CX, {}, targets, \"\"});\n    expected = _tracker_from_pauli_string<W>(\"XII\");\n    expected.num_measurements_in_past = 12;\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"YII\");\n    actual.num_measurements_in_past = 12;\n    actual.undo_ZCX({GateType::CX, {}, targets, \"\"});\n    expected = _tracker_from_pauli_string<W>(\"YII\");\n    expected.num_measurements_in_past = 12;\n    expected.rec_bits[7].xor_item(DemTarget::observable_id(0));\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"ZII\");\n    actual.num_measurements_in_past = 12;\n    actual.undo_ZCX({GateType::CX, {}, targets, \"\"});\n    expected = _tracker_from_pauli_string<W>(\"ZII\");\n    expected.num_measurements_in_past = 12;\n    expected.rec_bits[7].xor_item(DemTarget::observable_id(0));\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"XII\");\n    actual.num_measurements_in_past = 12;\n    actual.undo_ZCY({GateType::CY, {}, targets, \"\"});\n    expected = _tracker_from_pauli_string<W>(\"XII\");\n    expected.num_measurements_in_past = 12;\n    expected.rec_bits[7].xor_item(DemTarget::observable_id(0));\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"YII\");\n    actual.num_measurements_in_past = 12;\n    actual.undo_ZCY({GateType::CY, {}, targets, \"\"});\n    expected = _tracker_from_pauli_string<W>(\"YII\");\n    expected.num_measurements_in_past = 12;\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"ZII\");\n    actual.num_measurements_in_past = 12;\n    actual.undo_ZCY({GateType::CY, {}, targets, \"\"});\n    expected = _tracker_from_pauli_string<W>(\"ZII\");\n    expected.num_measurements_in_past = 12;\n    expected.rec_bits[7].xor_item(DemTarget::observable_id(0));\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"XII\");\n    actual.num_measurements_in_past = 12;\n    actual.undo_ZCZ({GateType::CZ, {}, targets, \"\"});\n    expected = _tracker_from_pauli_string<W>(\"XII\");\n    expected.num_measurements_in_past = 12;\n    expected.rec_bits[7].xor_item(DemTarget::observable_id(0));\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"YII\");\n    actual.num_measurements_in_past = 12;\n    actual.undo_ZCZ({GateType::CZ, {}, targets, \"\"});\n    expected = _tracker_from_pauli_string<W>(\"YII\");\n    expected.num_measurements_in_past = 12;\n    expected.rec_bits[7].xor_item(DemTarget::observable_id(0));\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"ZII\");\n    actual.num_measurements_in_past = 12;\n    actual.undo_ZCZ({GateType::CZ, {}, targets, \"\"});\n    expected = _tracker_from_pauli_string<W>(\"ZII\");\n    expected.num_measurements_in_past = 12;\n    ASSERT_EQ(actual, expected);\n})\n\nTEST(SparseUnsignedRevFrameTracker, undo_circuit_feedback) {\n    SparseUnsignedRevFrameTracker actual(20, 100, 10);\n    actual.undo_circuit(Circuit(R\"CIRCUIT(\n        MR 0\n        CX rec[-1] 0\n        M 0\n        DETECTOR rec[-1]\n    )CIRCUIT\"));\n    SparseUnsignedRevFrameTracker expected(20, 98, 9);\n    expected.zs[0].xor_item(DemTarget::relative_detector_id(9));\n    ASSERT_EQ(actual, expected);\n}\n\nTEST(SparseUnsignedRevFrameTracker, equal_shifted) {\n    SparseUnsignedRevFrameTracker actual(10, 200, 300);\n    SparseUnsignedRevFrameTracker expected(10, 2000, 3000);\n    ASSERT_TRUE(actual.is_shifted_copy(expected));\n\n    actual.rec_bits[200 - 5].xor_item(DemTarget::observable_id(2));\n    ASSERT_FALSE(actual.is_shifted_copy(expected));\n    expected.rec_bits[2000 - 5].xor_item(DemTarget::observable_id(2));\n    ASSERT_TRUE(actual.is_shifted_copy(expected));\n\n    actual.rec_bits[200 - 5].xor_item(DemTarget::relative_detector_id(300 - 7));\n    ASSERT_FALSE(actual.is_shifted_copy(expected));\n    expected.rec_bits[2000 - 5].xor_item(DemTarget::relative_detector_id(300 - 7));\n    ASSERT_FALSE(actual.is_shifted_copy(expected));\n    expected.rec_bits[2000 - 5].xor_item(DemTarget::relative_detector_id(300 - 7));\n    expected.rec_bits[2000 - 5].xor_item(DemTarget::relative_detector_id(3000 - 7));\n    ASSERT_TRUE(actual.is_shifted_copy(expected));\n\n    actual.xs[5].xor_item(DemTarget::observable_id(3));\n    ASSERT_FALSE(actual.is_shifted_copy(expected));\n    expected.xs[5].xor_item(DemTarget::observable_id(3));\n    ASSERT_TRUE(actual.is_shifted_copy(expected));\n\n    actual.zs[6].xor_item(DemTarget::observable_id(3));\n    ASSERT_FALSE(actual.is_shifted_copy(expected));\n    expected.zs[6].xor_item(DemTarget::observable_id(3));\n    ASSERT_TRUE(actual.is_shifted_copy(expected));\n\n    actual.xs[5].xor_item(DemTarget::relative_detector_id(300 - 13));\n    ASSERT_FALSE(actual.is_shifted_copy(expected));\n    expected.xs[5].xor_item(DemTarget::relative_detector_id(3000 - 13));\n    ASSERT_TRUE(actual.is_shifted_copy(expected));\n\n    actual.zs[6].xor_item(DemTarget::relative_detector_id(300 - 13));\n    ASSERT_FALSE(actual.is_shifted_copy(expected));\n    expected.zs[6].xor_item(DemTarget::relative_detector_id(3000 - 13));\n    ASSERT_TRUE(actual.is_shifted_copy(expected));\n\n    actual.shift(2000 - 200, 3000 - 300);\n    ASSERT_EQ(actual, expected);\n}\n\nTEST(SparseUnsignedRevFrameTracker, undo_circuit_loop_big_period) {\n    SparseUnsignedRevFrameTracker actual(20, 5000000000000ULL, 4000000000000ULL);\n    SparseUnsignedRevFrameTracker expected = actual;\n    Circuit body(R\"CIRCUIT(\n        CX 0 1 1 2 2 3 3 0\n        M 0 0 1\n        DETECTOR rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(3) rec[-1]\n    )CIRCUIT\");\n\n    actual.undo_loop(body, 500);\n    expected.undo_loop_by_unrolling(body, 500);\n\n    ASSERT_EQ(actual, expected);\n\n    // Make test timeout if folding fails.\n    actual.undo_loop(body, 1000000000001ULL);\n    ASSERT_EQ(actual.zs[0].sorted_items, std::vector<DemTarget>{DemTarget::observable_id(3)});\n    ASSERT_EQ(actual.num_measurements_in_past, 5000000000000ULL - 3000000000003ULL - 1500);\n    ASSERT_EQ(actual.num_detectors_in_past, 4000000000000ULL - 1000000000001ULL - 500);\n}\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, mpad, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n    SparseUnsignedRevFrameTracker expected(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"IIZ\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::relative_detector_id(5));\n    actual.undo_MPAD({GateType::MRY, {}, qubit_targets({0}), \"\"});\n\n    expected = _tracker_from_pauli_string<W>(\"IIZ\");\n    expected.num_measurements_in_past = 1;\n\n    ASSERT_EQ(actual, expected);\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, mxx, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n    SparseUnsignedRevFrameTracker expected(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::observable_id(0));\n    actual.undo_circuit(Circuit(\"MXX 0 1\"));\n    expected = _tracker_from_pauli_string<W>(\"XXI\");\n    expected.num_measurements_in_past = 1;\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"ZZI\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::observable_id(0));\n    actual.undo_circuit(Circuit(\"MXX !0 !1\"));\n    expected = _tracker_from_pauli_string<W>(\"YYI\");\n    expected.num_measurements_in_past = 1;\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"ZXI\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::observable_id(0));\n    ASSERT_THROW({ actual.undo_circuit(Circuit(\"MXX 0 1\")); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, myy, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n    SparseUnsignedRevFrameTracker expected(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::observable_id(0));\n    actual.undo_circuit(Circuit(\"MYY 0 1\"));\n    expected = _tracker_from_pauli_string<W>(\"YYI\");\n    expected.num_measurements_in_past = 1;\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"ZZI\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::observable_id(0));\n    actual.undo_circuit(Circuit(\"MYY !0 !1\"));\n    expected = _tracker_from_pauli_string<W>(\"XXI\");\n    expected.num_measurements_in_past = 1;\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"ZYI\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::observable_id(0));\n    ASSERT_THROW({ actual.undo_circuit(Circuit(\"MYY 0 1\")); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(SparseUnsignedRevFrameTracker, mzz, {\n    SparseUnsignedRevFrameTracker actual(0, 0, 0);\n    SparseUnsignedRevFrameTracker expected(0, 0, 0);\n\n    actual = _tracker_from_pauli_string<W>(\"III\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::observable_id(0));\n    actual.undo_circuit(Circuit(\"MZZ 0 1\"));\n    expected = _tracker_from_pauli_string<W>(\"ZZI\");\n    expected.num_measurements_in_past = 1;\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"XXI\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::observable_id(0));\n    actual.undo_circuit(Circuit(\"MZZ !0 !1\"));\n    expected = _tracker_from_pauli_string<W>(\"YYI\");\n    expected.num_measurements_in_past = 1;\n    ASSERT_EQ(actual, expected);\n\n    actual = _tracker_from_pauli_string<W>(\"ZYI\");\n    actual.num_measurements_in_past = 2;\n    actual.rec_bits[1].xor_item(DemTarget::observable_id(0));\n    ASSERT_THROW({ actual.undo_circuit(Circuit(\"MZZ 0 1\")); }, std::invalid_argument);\n})\n\nTEST(SparseUnsignedRevFrameTracker, runs_on_general_circuit) {\n    auto circuit = generate_test_circuit_with_all_operations();\n    SparseUnsignedRevFrameTracker s(circuit.count_qubits(), circuit.count_measurements(), circuit.count_detectors());\n    s.undo_circuit(circuit);\n    ASSERT_EQ(s.num_measurements_in_past, 0);\n    ASSERT_EQ(s.num_detectors_in_past, 0);\n}\n\nTEST(SparseUnsignedRevFrameTracker, tracks_anticommutation) {\n    Circuit circuit(R\"CIRCUIT(\n        R 0 1 2\n        H 0\n        CX 0 1 0 2\n        MX 0 1 2\n        DETECTOR rec[-1]\n        DETECTOR rec[-1] rec[-2] rec[-3]\n        DETECTOR rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(2) rec[-3]\n        OBSERVABLE_INCLUDE(1) rec[-1] rec[-2] rec[-3]\n    )CIRCUIT\");\n\n    SparseUnsignedRevFrameTracker rev(\n        circuit.count_qubits(), circuit.count_measurements(), circuit.count_detectors(), false);\n    rev.undo_circuit(circuit);\n    ASSERT_EQ(\n        rev.anticommutations,\n        (std::set<std::pair<DemTarget, GateTarget>>{\n            {DemTarget::relative_detector_id(0), GateTarget::x(2)},\n            {DemTarget::relative_detector_id(2), GateTarget::x(2)},\n            {DemTarget::observable_id(2), GateTarget::x(1)},\n            {DemTarget::observable_id(2), GateTarget::x(2)}}));\n\n    SparseUnsignedRevFrameTracker rev2(circuit.count_qubits(), circuit.count_measurements(), circuit.count_detectors());\n    ASSERT_THROW({ rev.undo_circuit(circuit); }, std::invalid_argument);\n}\n\nTEST(SparseUnsignedRevFrameTracker, MZZ) {\n    Circuit circuit(R\"CIRCUIT(\n        MZZ 0 1 1 2\n        M 2\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n\n    SparseUnsignedRevFrameTracker rev(\n        circuit.count_qubits(), circuit.count_measurements(), circuit.count_detectors(), false);\n    rev.undo_circuit(circuit);\n    ASSERT_TRUE(rev.xs[0].empty());\n    ASSERT_TRUE(rev.xs[1].empty());\n    ASSERT_TRUE(rev.xs[2].empty());\n    ASSERT_TRUE(rev.zs[0].empty());\n    ASSERT_TRUE(rev.zs[1].empty());\n    ASSERT_EQ(rev.zs[2].sorted_items, (std::vector<DemTarget>{DemTarget::relative_detector_id(0)}));\n}\n\nTEST(SparseUnsignedRevFrameTracker, fail_anticommute) {\n    Circuit circuit(R\"CIRCUIT(\n        RX 0 1 2\n        M 2\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n\n    SparseUnsignedRevFrameTracker rev(\n        circuit.count_qubits(), circuit.count_measurements(), circuit.count_detectors(), true);\n    ASSERT_THROW({ rev.undo_circuit(circuit); }, std::invalid_argument);\n}\n\nTEST(SparseUnsignedRevFrameTracker, OBS_INCLUDE_PAULIS) {\n    SparseUnsignedRevFrameTracker rev(4, 4, 4);\n\n    rev.undo_circuit(Circuit(\"OBSERVABLE_INCLUDE(5) X1 Y2 Z3 rec[-1]\"));\n    ASSERT_TRUE(rev.xs[0].empty());\n    ASSERT_TRUE(rev.zs[0].empty());\n    ASSERT_EQ(rev.xs[1], (std::vector<DemTarget>{DemTarget::observable_id(5)}));\n    ASSERT_TRUE(rev.zs[1].empty());\n    ASSERT_EQ(rev.xs[2], (std::vector<DemTarget>{DemTarget::observable_id(5)}));\n    ASSERT_EQ(rev.zs[2], (std::vector<DemTarget>{DemTarget::observable_id(5)}));\n    ASSERT_TRUE(rev.xs[3].empty());\n    ASSERT_EQ(rev.zs[3], (std::vector<DemTarget>{DemTarget::observable_id(5)}));\n}\n"
  },
  {
    "path": "src/stim/simulators/tableau_simulator.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_TABLEAU_SIMULATOR_H\n#define _STIM_SIMULATORS_TABLEAU_SIMULATOR_H\n\n#include <cassert>\n#include <functional>\n#include <iostream>\n#include <new>\n#include <random>\n#include <sstream>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/io/measure_record.h\"\n#include \"stim/stabilizers/tableau.h\"\n#include \"stim/stabilizers/tableau_transposed_raii.h\"\n\nnamespace stim {\n\n/// A stabilizer circuit simulator that tracks an inverse stabilizer tableau\n/// and allows interactive usage, where gates and measurements are applied\n/// on demand.\n///\n/// The template parameter, W, represents the SIMD width\ntemplate <size_t W>\nstruct TableauSimulator {\n    Tableau<W> inv_state;\n    std::mt19937_64 rng;\n    int8_t sign_bias;\n    MeasureRecord measurement_record;\n    bool last_correlated_error_occurred;\n\n    /// Args:\n    ///     num_qubits: The initial number of qubits in the simulator state.\n    ///     rng: The random number generator to use for random operations.\n    ///     sign_bias: 0 means collapse randomly, -1 means collapse towards True, +1 means collapse towards False.\n    ///     record: Measurement record configuration.\n    explicit TableauSimulator(\n        std::mt19937_64 &&rng, size_t num_qubits = 0, int8_t sign_bias = 0, MeasureRecord record = MeasureRecord());\n    /// Args:\n    ///     other: TableauSimulator to copy state from.\n    ///     rng: The random number generator to use for random operations.\n    TableauSimulator(const TableauSimulator &other, std::mt19937_64 &&rng);\n\n    /// Samples the given circuit in a deterministic fashion.\n    ///\n    /// Discards all noisy operations, and biases all collapse events towards +Z instead of randomly +Z/-Z.\n    static simd_bits<W> reference_sample_circuit(const Circuit &circuit);\n    static simd_bits<W> sample_circuit(const Circuit &circuit, std::mt19937_64 &rng, int8_t sign_bias = 0);\n    static void sample_stream(FILE *in, FILE *out, SampleFormat format, bool interactive, std::mt19937_64 &rng);\n\n    /// Expands the internal state of the simulator (if needed) to ensure the given qubit exists.\n    ///\n    /// Failing to ensure the state is large enough for a qubit, before that qubit is acted on for the first time,\n    /// results in undefined behavior.\n    void ensure_large_enough_for_qubits(size_t num_qubits);\n\n    /// Forces the size of the internal state of the simulator.\n    ///\n    /// Shrinking the size will result in qubits beyond the size threshold being collapsed and discarded.\n    void set_num_qubits(size_t new_num_qubits);\n\n    /// Finds a state vector satisfying the current stabilizer generators, and returns a vector simulator in that state.\n    VectorSimulator to_vector_sim() const;\n\n    /// Returns a state vector satisfying the current stabilizer generators.\n    std::vector<std::complex<float>> to_state_vector(bool little_endian) const;\n\n    /// Collapses then records an observable.\n    ///\n    /// Args:\n    ///     pauli_string: The observable to measure.\n    bool measure_pauli_string(const PauliStringRef<W> pauli_string, double flip_probability);\n\n    /// Determines if a qubit's X observable commutes (vs anti-commutes) with the current stabilizer generators.\n    bool is_deterministic_x(size_t target) const;\n    /// Determines if a qubit's Y observable commutes (vs anti-commutes) with the current stabilizer generators.\n    bool is_deterministic_y(size_t target) const;\n    /// Determines if a qubit's Z observable commutes (vs anti-commutes) with the current stabilizer generators.\n    bool is_deterministic_z(size_t target) const;\n\n    /// Runs all of the operations in the given circuit.\n    ///\n    /// Automatically expands the tableau simulator's state, if needed.\n    void safe_do_circuit(const Circuit &circuit, uint64_t reps = 1);\n    void do_operation_ensure_size(const CircuitInstruction &operation);\n\n    void apply_tableau(const Tableau<W> &tableau, const std::vector<size_t> &targets);\n\n    std::vector<PauliString<W>> canonical_stabilizers() const;\n\n    void do_gate(const CircuitInstruction &inst);\n\n    /// === SPECIALIZED VECTORIZED OPERATION IMPLEMENTATIONS ===\n    void do_I(const CircuitInstruction &inst);\n    void do_H_XZ(const CircuitInstruction &inst);\n    void do_H_YZ(const CircuitInstruction &inst);\n    void do_H_XY(const CircuitInstruction &inst);\n    void do_H_NXY(const CircuitInstruction &inst);\n    void do_H_NXZ(const CircuitInstruction &inst);\n    void do_H_NYZ(const CircuitInstruction &inst);\n    void do_C_XYZ(const CircuitInstruction &inst);\n    void do_C_NXYZ(const CircuitInstruction &inst);\n    void do_C_XNYZ(const CircuitInstruction &inst);\n    void do_C_XYNZ(const CircuitInstruction &inst);\n    void do_C_ZYX(const CircuitInstruction &inst);\n    void do_C_NZYX(const CircuitInstruction &inst);\n    void do_C_ZNYX(const CircuitInstruction &inst);\n    void do_C_ZYNX(const CircuitInstruction &inst);\n    void do_SQRT_X(const CircuitInstruction &inst);\n    void do_SQRT_Y(const CircuitInstruction &inst);\n    void do_SQRT_Z(const CircuitInstruction &inst);\n    void do_SQRT_X_DAG(const CircuitInstruction &inst);\n    void do_SQRT_Y_DAG(const CircuitInstruction &inst);\n    void do_SQRT_Z_DAG(const CircuitInstruction &inst);\n    void do_SQRT_XX(const CircuitInstruction &inst);\n    void do_SQRT_XX_DAG(const CircuitInstruction &inst);\n    void do_SQRT_YY(const CircuitInstruction &inst);\n    void do_SQRT_YY_DAG(const CircuitInstruction &inst);\n    void do_SQRT_ZZ(const CircuitInstruction &inst);\n    void do_SQRT_ZZ_DAG(const CircuitInstruction &inst);\n    void do_ZCX(const CircuitInstruction &inst);\n    void do_ZCY(const CircuitInstruction &inst);\n    void do_ZCZ(const CircuitInstruction &inst);\n    void do_SWAP(const CircuitInstruction &inst);\n    void do_X(const CircuitInstruction &inst);\n    void do_Y(const CircuitInstruction &inst);\n    void do_Z(const CircuitInstruction &inst);\n    void do_ISWAP(const CircuitInstruction &inst);\n    void do_ISWAP_DAG(const CircuitInstruction &inst);\n    void do_CXSWAP(const CircuitInstruction &inst);\n    void do_CZSWAP(const CircuitInstruction &inst);\n    void do_SWAPCX(const CircuitInstruction &inst);\n    void do_XCX(const CircuitInstruction &inst);\n    void do_XCY(const CircuitInstruction &inst);\n    void do_XCZ(const CircuitInstruction &inst);\n    void do_YCX(const CircuitInstruction &inst);\n    void do_YCY(const CircuitInstruction &inst);\n    void do_YCZ(const CircuitInstruction &inst);\n    void do_DEPOLARIZE1(const CircuitInstruction &inst);\n    void do_DEPOLARIZE2(const CircuitInstruction &inst);\n    void do_HERALDED_ERASE(const CircuitInstruction &inst);\n    void do_HERALDED_PAULI_CHANNEL_1(const CircuitInstruction &inst);\n    void do_X_ERROR(const CircuitInstruction &inst);\n    void do_Y_ERROR(const CircuitInstruction &inst);\n    void do_Z_ERROR(const CircuitInstruction &inst);\n    void do_PAULI_CHANNEL_1(const CircuitInstruction &inst);\n    void do_PAULI_CHANNEL_2(const CircuitInstruction &inst);\n    void do_CORRELATED_ERROR(const CircuitInstruction &inst);\n    void do_ELSE_CORRELATED_ERROR(const CircuitInstruction &inst);\n    void do_MPP(const CircuitInstruction &inst);\n    void do_SPP(const CircuitInstruction &inst);\n    void do_SPP_DAG(const CircuitInstruction &inst);\n    void do_MXX(const CircuitInstruction &inst);\n    void do_MYY(const CircuitInstruction &inst);\n    void do_MZZ(const CircuitInstruction &inst);\n    void do_MPAD(const CircuitInstruction &inst);\n    void do_MX(const CircuitInstruction &inst);\n    void do_MY(const CircuitInstruction &inst);\n    void do_MZ(const CircuitInstruction &inst);\n    void do_RX(const CircuitInstruction &inst);\n    void do_RY(const CircuitInstruction &inst);\n    void do_RZ(const CircuitInstruction &inst);\n    void do_MRX(const CircuitInstruction &inst);\n    void do_MRY(const CircuitInstruction &inst);\n    void do_MRZ(const CircuitInstruction &inst);\n\n    /// Returns the single-qubit stabilizer of a target or, if it is entangled, the identity operation.\n    PauliString<W> peek_bloch(uint32_t target) const;\n\n    /// Returns the expectation value of measuring the qubit in the X basis.\n    int8_t peek_x(uint32_t target) const;\n    /// Returns the expectation value of measuring the qubit in the Y basis.\n    int8_t peek_y(uint32_t target) const;\n    /// Returns the expectation value of measuring the qubit in the Z basis.\n    int8_t peek_z(uint32_t target) const;\n\n    /// Projects the system into a desired qubit X observable, or raises an exception if it was impossible.\n    void postselect_x(SpanRef<const GateTarget> targets, bool desired_result);\n    /// Projects the system into a desired qubit Y observable, or raises an exception if it was impossible.\n    void postselect_y(SpanRef<const GateTarget> targets, bool desired_result);\n    /// Projects the system into a desired qubit Z observable, or raises an exception if it was impossible.\n    void postselect_z(SpanRef<const GateTarget> targets, bool desired_result);\n\n    /// Applies all of the Pauli operations in the given PauliString to the simulator's state.\n    void paulis(const PauliString<W> &paulis);\n\n    /// Performs a measurement and returns a kickback that flips between the possible post-measurement states.\n    ///\n    /// Deterministic measurements have no kickback.\n    /// This is represented by setting the kickback to the empty Pauli string.\n    std::pair<bool, PauliString<W>> measure_kickback_z(GateTarget target);\n    std::pair<bool, PauliString<W>> measure_kickback_y(GateTarget target);\n    std::pair<bool, PauliString<W>> measure_kickback_x(GateTarget target);\n\n    bool read_measurement_record(uint32_t encoded_target) const;\n    void single_cx(uint32_t c, uint32_t t);\n    void single_cy(uint32_t c, uint32_t t);\n\n    /// Forces a qubit to have a collapsed Z observable.\n    ///\n    /// If the qubit already has a collapsed Z observable, this method has no effect.\n    /// Other, the qubit's Z observable anticommutes with the current stabilizers and this method will apply state\n    /// transformations that pick out a single stabilizer generator to destroy and replace with the measurement's\n    /// stabilizer.\n    ///\n    /// Args:\n    ///     target: The index of the qubit to collapse.\n    ///     transposed_raii: A RAII value whose existence certifies the tableau data is currently transposed\n    ///         (to make operations efficient).\n    ///\n    /// Returns:\n    ///    SIZE_MAX: Already collapsed.\n    ///    Else: The pivot index. The start-of-time qubit whose X flips the measurement.\n    size_t collapse_qubit_z(size_t target, TableauTransposedRaii<W> &transposed_raii);\n\n    /// Collapses the given qubits into the X basis.\n    ///\n    /// Args:\n    ///     targets: The qubits to collapse.\n    ///     stride: Defaults to 1. Set to 2 to skip over every other target.\n    void collapse_x(SpanRef<const GateTarget> targets, size_t stride = 1);\n\n    /// Collapses the given qubits into the Y basis.\n    ///\n    /// Args:\n    ///     targets: The qubits to collapse.\n    ///     stride: Defaults to 1. Set to 2 to skip over every other target.\n    void collapse_y(SpanRef<const GateTarget> targets, size_t stride = 1);\n\n    /// Collapses the given qubits into the Z basis.\n    ///\n    /// Args:\n    ///     targets: The qubits to collapse.\n    ///     stride: Defaults to 1. Set to 2 to skip over every other target.\n    void collapse_z(SpanRef<const GateTarget> targets, size_t stride = 1);\n\n    /// Completely isolates a qubit from the other qubits tracked by the simulator, so it can be safely discarded.\n    ///\n    /// After this runs, it is guaranteed that the inverse tableau maps the target qubit's X and Z observables to\n    /// themselves (possibly negated) and that it maps all other qubits to Pauli products not involving the target\n    /// qubit.\n    void collapse_isolate_qubit_z(size_t target, TableauTransposedRaii<W> &transposed_raii);\n\n    /// Determines the expected value of an observable (which will always be -1, 0, or +1).\n    ///\n    /// This is a non-physical operation.\n    /// It reports information about the quantum state without disturbing it.\n    ///\n    /// Args:\n    ///     observable: The observable to determine the expected value of.\n    ///\n    /// Returns:\n    ///     +1: Observable will be deterministically false when measured.\n    ///     -1: Observable will be deterministically true when measured.\n    ///     0: Observable will be random when measured.\n    int8_t peek_observable_expectation(const PauliString<W> &observable) const;\n\n    /// Forces a desired measurement result, or raises an exception if it was impossible.\n    void postselect_observable(PauliStringRef<W> observable, bool desired_result);\n\n   private:\n    uint32_t try_isolate_observable_to_qubit_z(PauliStringRef<W> observable, bool undo);\n    void do_MXX_disjoint_controls_segment(const CircuitInstruction &inst);\n    void do_MYY_disjoint_controls_segment(const CircuitInstruction &inst);\n    void do_MZZ_disjoint_controls_segment(const CircuitInstruction &inst);\n    void noisify_new_measurements(SpanRef<const double> args, size_t num_targets);\n    void noisify_new_measurements(const CircuitInstruction &target_data);\n    void postselect_helper(\n        SpanRef<const GateTarget> targets,\n        bool desired_result,\n        GateType basis_change_gate,\n        const char *false_name,\n        const char *true_name);\n};\n\ntemplate <size_t Q, typename RESET_FLAG, typename ELSE_CORR>\nvoid perform_pauli_errors_via_correlated_errors(\n    const CircuitInstruction &target_data, RESET_FLAG reset_flag, ELSE_CORR else_corr) {\n    double target_p{};\n    GateTarget target_t[Q];\n    CircuitInstruction data{GateType::E, {&target_p}, {&target_t[0], &target_t[Q]}, \"\"};\n    for (size_t k = 0; k < target_data.targets.size(); k += Q) {\n        reset_flag();\n        double used_probability = 0;\n        for (size_t pauli = 1; pauli < 1 << (2 * Q); pauli++) {\n            double p = target_data.args[pauli - 1];\n            if (p == 0) {\n                continue;\n            }\n            double remaining = 1 - used_probability;\n            double conditional_prob = remaining <= 0 ? 0 : remaining <= p ? 1 : p / remaining;\n            used_probability += p;\n\n            for (size_t q = 0; q < Q; q++) {\n                target_t[q] = target_data.targets[k + q];\n                bool z = (pauli >> (2 * (Q - q - 1))) & 2;\n                bool y = (pauli >> (2 * (Q - q - 1))) & 1;\n                if (z ^ y) {\n                    target_t[q].data |= TARGET_PAULI_X_BIT;\n                }\n                if (z) {\n                    target_t[q].data |= TARGET_PAULI_Z_BIT;\n                }\n            }\n            target_p = conditional_prob;\n            else_corr(data);\n        }\n    }\n}\n\n}  // namespace stim\n\n#include \"stim/simulators/tableau_simulator.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/tableau_simulator.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <set>\n\n#include \"stim/circuit/gate_decomposition.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/simulators/vector_simulator.h\"\n#include \"stim/util_bot/probability_util.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nTableauSimulator<W>::TableauSimulator(std::mt19937_64 &&rng, size_t num_qubits, int8_t sign_bias, MeasureRecord record)\n    : inv_state(Tableau<W>::identity(num_qubits)),\n      rng(std::move(rng)),\n      sign_bias(sign_bias),\n      measurement_record(std::move(record)),\n      last_correlated_error_occurred(false) {\n}\n\ntemplate <size_t W>\nTableauSimulator<W>::TableauSimulator(const TableauSimulator<W> &other, std::mt19937_64 &&rng)\n    : inv_state(other.inv_state),\n      rng(std::move(rng)),\n      sign_bias(other.sign_bias),\n      measurement_record(other.measurement_record),\n      last_correlated_error_occurred(other.last_correlated_error_occurred) {\n}\n\ntemplate <size_t W>\nbool TableauSimulator<W>::is_deterministic_x(size_t target) const {\n    return !inv_state.xs[target].xs.not_zero();\n}\n\ntemplate <size_t W>\nbool TableauSimulator<W>::is_deterministic_y(size_t target) const {\n    return inv_state.xs[target].xs == inv_state.zs[target].xs;\n}\n\ntemplate <size_t W>\nbool TableauSimulator<W>::is_deterministic_z(size_t target) const {\n    return !inv_state.zs[target].xs.not_zero();\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MPP(const CircuitInstruction &target_data) {\n    decompose_mpp_operation(target_data, inv_state.num_qubits, [&](const CircuitInstruction &inst) {\n        do_gate(inst);\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SPP(const CircuitInstruction &target_data) {\n    decompose_spp_or_spp_dag_operation(target_data, inv_state.num_qubits, false, [&](const CircuitInstruction &inst) {\n        do_gate(inst);\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SPP_DAG(const CircuitInstruction &target_data) {\n    decompose_spp_or_spp_dag_operation(target_data, inv_state.num_qubits, false, [&](const CircuitInstruction &inst) {\n        do_gate(inst);\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::postselect_helper(\n    SpanRef<const GateTarget> targets,\n    bool desired_result,\n    GateType basis_change_gate,\n    const char *false_name,\n    const char *true_name) {\n    std::set<GateTarget> unique_targets;\n    unique_targets.insert(targets.begin(), targets.end());\n    std::vector<GateTarget> unique_targets_vec;\n    unique_targets_vec.insert(unique_targets_vec.end(), unique_targets.begin(), unique_targets.end());\n\n    size_t finished = 0;\n    do_gate({basis_change_gate, {}, unique_targets_vec, \"\"});\n    {\n        uint8_t old_bias = sign_bias;\n        sign_bias = desired_result ? -1 : +1;\n        TableauTransposedRaii<W> temp_transposed(inv_state);\n        while (finished < targets.size()) {\n            size_t q = (size_t)targets[finished].qubit_value();\n            collapse_qubit_z(q, temp_transposed);\n            if (inv_state.zs.signs[q] != desired_result) {\n                break;\n            }\n            finished++;\n        }\n        sign_bias = old_bias;\n    }\n    do_gate({basis_change_gate, {}, unique_targets_vec, \"\"});\n\n    if (finished < targets.size()) {\n        std::stringstream msg;\n        msg << \"The requested postselection was impossible.\\n\";\n        msg << \"Desired state: |\" << (desired_result ? true_name : false_name) << \">\\n\";\n        msg << \"Qubit \" << targets[finished] << \" is in the perpendicular state |\"\n            << (desired_result ? false_name : true_name) << \">\\n\";\n        if (finished > 0) {\n            msg << finished << \" of the requested postselections were finished (\";\n            for (size_t k = 0; k < finished; k++) {\n                msg << \"qubit \" << targets[k] << \", \";\n            }\n            msg << \"[failed here])\\n\";\n        }\n        throw std::invalid_argument(msg.str());\n    }\n}\n\ntemplate <size_t W>\nuint32_t TableauSimulator<W>::try_isolate_observable_to_qubit_z(PauliStringRef<W> observable, bool undo) {\n    uint32_t pivot = UINT32_MAX;\n    observable.for_each_active_pauli([&](size_t q) {\n        uint8_t p = observable.xs[q] + observable.zs[q] * 2;\n        if (pivot == UINT32_MAX) {\n            pivot = q;\n            if (!undo) {\n                if (p == 1) {\n                    inv_state.prepend_H_XZ(pivot);\n                } else if (p == 3) {\n                    inv_state.prepend_H_YZ(pivot);\n                }\n                if (observable.sign) {\n                    inv_state.prepend_X(pivot);\n                }\n            }\n        } else {\n            if (p == 1) {\n                inv_state.prepend_XCX(pivot, q);\n            } else if (p == 2) {\n                inv_state.prepend_XCZ(pivot, q);\n            } else if (p == 3) {\n                inv_state.prepend_XCY(pivot, q);\n            }\n        }\n    });\n    if (undo && pivot != UINT32_MAX) {\n        uint8_t p = observable.xs[pivot] + observable.zs[pivot] * 2;\n        if (observable.sign) {\n            inv_state.prepend_X(pivot);\n        }\n        if (p == 1) {\n            inv_state.prepend_H_XZ(pivot);\n        } else if (p == 3) {\n            inv_state.prepend_H_YZ(pivot);\n        }\n    }\n    return pivot;\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::postselect_observable(PauliStringRef<W> observable, bool desired_result) {\n    ensure_large_enough_for_qubits(observable.num_qubits);\n\n    uint32_t pivot = try_isolate_observable_to_qubit_z(observable, false);\n    int8_t expected;\n    if (pivot != UINT32_MAX) {\n        expected = peek_z(pivot);\n    } else {\n        expected = observable.sign ? -1 : +1;\n    }\n    if (desired_result) {\n        expected *= -1;\n    }\n\n    if (expected != -1 && pivot != UINT32_MAX) {\n        GateTarget t{pivot};\n        postselect_z(&t, desired_result);\n    }\n    try_isolate_observable_to_qubit_z(observable, true);\n\n    if (expected == -1) {\n        std::stringstream msg;\n        msg << \"It's impossible to postselect into the \";\n        msg << (desired_result ? \"-1\" : \"+1\");\n        msg << \" eigenstate of \";\n        msg << observable;\n        msg << \" because the system is deterministically in the \";\n        msg << (desired_result ? \"+1\" : \"-1\");\n        msg << \" eigenstate.\";\n        throw std::invalid_argument(msg.str());\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::postselect_x(SpanRef<const GateTarget> targets, bool desired_result) {\n    postselect_helper(targets, desired_result, GateType::H, \"+\", \"-\");\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::postselect_y(SpanRef<const GateTarget> targets, bool desired_result) {\n    postselect_helper(targets, desired_result, GateType::H_YZ, \"i\", \"-i\");\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::postselect_z(SpanRef<const GateTarget> targets, bool desired_result) {\n    postselect_helper(targets, desired_result, GateType::I, \"0\", \"1\");\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MX(const CircuitInstruction &target_data) {\n    // Ensure measurement observables are collapsed.\n    collapse_x(target_data.targets);\n\n    // Record measurement results.\n    for (auto t : target_data.targets) {\n        auto q = t.qubit_value();\n        bool flipped = t.is_inverted_result_target();\n        bool b = inv_state.xs.signs[q] ^ flipped;\n        measurement_record.record_result(b);\n    }\n    noisify_new_measurements(target_data);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MXX_disjoint_controls_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    do_ZCX(CircuitInstruction{GateType::CX, {}, inst.targets, \"\"});\n\n    // Ensure measurement observables are collapsed.\n    collapse_x(inst.targets, 2);\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        GateTarget t1 = inst.targets[k];\n        GateTarget t2 = inst.targets[k + 1];\n        auto q = t1.qubit_value();\n        bool flipped = t1.is_inverted_result_target() ^ t2.is_inverted_result_target();\n        bool b = inv_state.xs.signs[q] ^ flipped;\n        measurement_record.record_result(b);\n    }\n    noisify_new_measurements(inst.args, inst.targets.size() / 2);\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    do_ZCX(CircuitInstruction{GateType::CX, {}, inst.targets, \"\"});\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MYY_disjoint_controls_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    do_ZCY(CircuitInstruction{GateType::CY, {}, inst.targets, \"\"});\n\n    // Ensure measurement observables are collapsed.\n    collapse_y(inst.targets, 2);\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        GateTarget t1 = inst.targets[k];\n        GateTarget t2 = inst.targets[k + 1];\n        auto q = t1.qubit_value();\n        bool flipped = t1.is_inverted_result_target() ^ t2.is_inverted_result_target();\n        bool b = inv_state.eval_y_obs(q).sign ^ flipped;\n        measurement_record.record_result(b);\n    }\n    noisify_new_measurements(inst.args, inst.targets.size() / 2);\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    do_ZCY(CircuitInstruction{GateType::CY, {}, inst.targets, \"\"});\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MZZ_disjoint_controls_segment(const CircuitInstruction &inst) {\n    // Transform from 2 qubit measurements to single qubit measurements.\n    do_XCZ(CircuitInstruction{GateType::XCZ, {}, inst.targets, \"\"});\n\n    // Ensure measurement observables are collapsed.\n    collapse_z(inst.targets, 2);\n\n    // Record measurement results.\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        GateTarget t1 = inst.targets[k];\n        GateTarget t2 = inst.targets[k + 1];\n        auto q = t1.qubit_value();\n        bool flipped = t1.is_inverted_result_target() ^ t2.is_inverted_result_target();\n        bool b = inv_state.zs.signs[q] ^ flipped;\n        measurement_record.record_result(b);\n    }\n    noisify_new_measurements(inst.args, inst.targets.size() / 2);\n\n    // Untransform from single qubit measurements back to 2 qubit measurements.\n    do_XCZ(CircuitInstruction{GateType::XCZ, {}, inst.targets, \"\"});\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MXX(const CircuitInstruction &inst) {\n    decompose_pair_instruction_into_disjoint_segments(inst, inv_state.num_qubits, [&](CircuitInstruction segment) {\n        do_MXX_disjoint_controls_segment(segment);\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MYY(const CircuitInstruction &inst) {\n    decompose_pair_instruction_into_disjoint_segments(inst, inv_state.num_qubits, [&](CircuitInstruction segment) {\n        do_MYY_disjoint_controls_segment(segment);\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MZZ(const CircuitInstruction &inst) {\n    decompose_pair_instruction_into_disjoint_segments(inst, inv_state.num_qubits, [&](CircuitInstruction segment) {\n        do_MZZ_disjoint_controls_segment(segment);\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MPAD(const CircuitInstruction &inst) {\n    for (const auto &t : inst.targets) {\n        measurement_record.record_result(t.qubit_value() != 0);\n    }\n    noisify_new_measurements(inst);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MY(const CircuitInstruction &target_data) {\n    // Ensure measurement observables are collapsed.\n    collapse_y(target_data.targets);\n\n    // Record measurement results.\n    for (auto t : target_data.targets) {\n        auto q = t.qubit_value();\n        bool flipped = t.is_inverted_result_target();\n        bool b = inv_state.eval_y_obs(q).sign ^ flipped;\n        measurement_record.record_result(b);\n    }\n    noisify_new_measurements(target_data);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MZ(const CircuitInstruction &target_data) {\n    // Ensure measurement observables are collapsed.\n    collapse_z(target_data.targets);\n\n    // Record measurement results.\n    for (auto t : target_data.targets) {\n        auto q = t.qubit_value();\n        bool flipped = t.is_inverted_result_target();\n        bool b = inv_state.zs.signs[q] ^ flipped;\n        measurement_record.record_result(b);\n    }\n    noisify_new_measurements(target_data);\n}\n\ntemplate <size_t W>\nbool TableauSimulator<W>::measure_pauli_string(const PauliStringRef<W> pauli_string, double flip_probability) {\n    if (!(0 <= flip_probability && flip_probability <= 1)) {\n        throw std::invalid_argument(\"Need 0 <= flip_probability <= 1\");\n    }\n    ensure_large_enough_for_qubits(pauli_string.num_qubits);\n\n    std::vector<GateTarget> targets;\n    targets.reserve(pauli_string.num_qubits * 2);\n    for (size_t k = 0; k < pauli_string.num_qubits; k++) {\n        bool x = pauli_string.xs[k];\n        bool z = pauli_string.zs[k];\n        if (x || z) {\n            GateTarget target{(uint32_t)k};\n            if (x) {\n                target.data |= TARGET_PAULI_X_BIT;\n            }\n            if (z) {\n                target.data |= TARGET_PAULI_Z_BIT;\n            }\n            targets.push_back(target);\n            targets.push_back(GateTarget::combiner());\n        }\n    }\n    double p = flip_probability;\n    if (pauli_string.sign) {\n        p = 1 - p;\n    }\n    if (targets.empty()) {\n        measurement_record.record_result(std::bernoulli_distribution(p)(rng));\n    } else {\n        targets.pop_back();\n        do_MPP(CircuitInstruction{GateType::MPP, &p, targets, \"\"});\n    }\n    return measurement_record.lookback(1);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MRX(const CircuitInstruction &target_data) {\n    // Note: Caution when implementing this. Can't group the resets. because the same qubit target may appear twice.\n\n    // Ensure measurement observables are collapsed.\n    collapse_x(target_data.targets);\n\n    // Record measurement results while triggering resets.\n    for (auto t : target_data.targets) {\n        auto q = t.qubit_value();\n        bool flipped = t.is_inverted_result_target();\n        bool b = inv_state.xs.signs[q] ^ flipped;\n        measurement_record.record_result(b);\n        inv_state.xs.signs[q] = false;\n        inv_state.zs.signs[q] = false;\n    }\n    noisify_new_measurements(target_data);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MRY(const CircuitInstruction &target_data) {\n    // Note: Caution when implementing this. Can't group the resets. because the same qubit target may appear twice.\n\n    // Ensure measurement observables are collapsed.\n    collapse_y(target_data.targets);\n\n    // Record measurement results while triggering resets.\n    for (auto t : target_data.targets) {\n        auto q = t.qubit_value();\n        bool flipped = t.is_inverted_result_target();\n        bool cur_sign = inv_state.eval_y_obs(q).sign;\n        bool b = cur_sign ^ flipped;\n        measurement_record.record_result(b);\n        inv_state.zs.signs[q] ^= cur_sign;\n    }\n    noisify_new_measurements(target_data);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_MRZ(const CircuitInstruction &target_data) {\n    // Note: Caution when implementing this. Can't group the resets. because the same qubit target may appear twice.\n\n    // Ensure measurement observables are collapsed.\n    collapse_z(target_data.targets);\n\n    // Record measurement results while triggering resets.\n    for (auto t : target_data.targets) {\n        auto q = t.qubit_value();\n        bool flipped = t.is_inverted_result_target();\n        bool b = inv_state.zs.signs[q] ^ flipped;\n        measurement_record.record_result(b);\n        inv_state.xs.signs[q] = false;\n        inv_state.zs.signs[q] = false;\n    }\n    noisify_new_measurements(target_data);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::noisify_new_measurements(SpanRef<const double> args, size_t num_targets) {\n    if (args.empty()) {\n        return;\n    }\n    size_t last = measurement_record.storage.size() - 1;\n    RareErrorIterator::for_samples(args[0], num_targets, rng, [&](size_t k) {\n        measurement_record.storage[last - k] = !measurement_record.storage[last - k];\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::noisify_new_measurements(const CircuitInstruction &inst) {\n    noisify_new_measurements(inst.args, inst.targets.size());\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_RX(const CircuitInstruction &target_data) {\n    // Collapse the qubits to be reset.\n    collapse_x(target_data.targets);\n\n    // Force the collapsed qubits into the ground state.\n    for (auto q : target_data.targets) {\n        inv_state.xs.signs[q.data] = false;\n        inv_state.zs.signs[q.data] = false;\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_RY(const CircuitInstruction &target_data) {\n    // Collapse the qubits to be reset.\n    collapse_y(target_data.targets);\n\n    // Force the collapsed qubits into the ground state.\n    for (auto q : target_data.targets) {\n        inv_state.xs.signs[q.data] = false;\n        inv_state.zs.signs[q.data] = false;\n        inv_state.zs.signs[q.data] ^= inv_state.eval_y_obs(q.data).sign;\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_RZ(const CircuitInstruction &target_data) {\n    // Collapse the qubits to be reset.\n    collapse_z(target_data.targets);\n\n    // Force the collapsed qubits into the ground state.\n    for (auto q : target_data.targets) {\n        inv_state.xs.signs[q.data] = false;\n        inv_state.zs.signs[q.data] = false;\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_I(const CircuitInstruction &target_data) {\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_H_XZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        inv_state.prepend_H_XZ(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_H_XY(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        inv_state.prepend_H_XY(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_H_YZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        inv_state.prepend_H_YZ(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_H_NXY(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        inv_state.prepend_H_NXY(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_H_NXZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        inv_state.prepend_H_NXZ(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_H_NYZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        inv_state.prepend_H_NYZ(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_C_XYZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_C_ZYX(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_C_NXYZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_C_ZYNX(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_C_XNYZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_C_ZNYX(q.data);\n    }\n}\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_C_XYNZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_C_NZYX(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_C_ZYX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_C_XYZ(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_C_NZYX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_C_XYNZ(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_C_ZNYX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_C_XNYZ(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_C_ZYNX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_C_NXYZ(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_Z(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_Z_DAG(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_Z_DAG(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_Z(q.data);\n    }\n}\n\ntemplate <size_t W>\nPauliString<W> TableauSimulator<W>::peek_bloch(uint32_t target) const {\n    PauliStringRef<W> x = inv_state.xs[target];\n    PauliStringRef<W> z = inv_state.zs[target];\n\n    PauliString<W> result(1);\n    if (!x.xs.not_zero()) {\n        result.sign = x.sign;\n        result.xs[0] = true;\n    } else if (!z.xs.not_zero()) {\n        result.sign = z.sign;\n        result.zs[0] = true;\n    } else if (x.xs == z.xs) {\n        PauliString<W> y = inv_state.eval_y_obs(target);\n        result.sign = y.sign;\n        result.xs[0] = true;\n        result.zs[0] = true;\n    }\n\n    return result;\n}\n\ntemplate <size_t W>\nint8_t TableauSimulator<W>::peek_x(uint32_t target) const {\n    PauliStringRef<W> x = inv_state.xs[target];\n    return x.xs.not_zero() ? 0 : x.sign ? -1 : +1;\n}\n\ntemplate <size_t W>\nint8_t TableauSimulator<W>::peek_y(uint32_t target) const {\n    PauliString<W> y = inv_state.eval_y_obs(target);\n    return y.xs.not_zero() ? 0 : y.sign ? -1 : +1;\n}\n\ntemplate <size_t W>\nint8_t TableauSimulator<W>::peek_z(uint32_t target) const {\n    PauliStringRef<W> z = inv_state.zs[target];\n    return z.xs.not_zero() ? 0 : z.sign ? -1 : +1;\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_X(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_X_DAG(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_X_DAG(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_X(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_Y(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_Y_DAG(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_Y_DAG(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_Y(q.data);\n    }\n}\n\ntemplate <size_t W>\nbool TableauSimulator<W>::read_measurement_record(uint32_t encoded_target) const {\n    if (encoded_target & TARGET_SWEEP_BIT) {\n        // Shot-to-shot variation currently not supported by the tableau simulator. Use frame simulator.\n        return false;\n    }\n    assert(encoded_target & TARGET_RECORD_BIT);\n    return measurement_record.lookback(encoded_target ^ TARGET_RECORD_BIT);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::single_cx(uint32_t c, uint32_t t) {\n    c &= ~TARGET_INVERTED_BIT;\n    t &= ~TARGET_INVERTED_BIT;\n    if (!((c | t) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        inv_state.prepend_ZCX(c, t);\n    } else if (t & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT)) {\n        throw std::invalid_argument(\"Measurement record editing is not supported.\");\n    } else {\n        if (read_measurement_record(c)) {\n            inv_state.prepend_X(t);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::single_cy(uint32_t c, uint32_t t) {\n    c &= ~TARGET_INVERTED_BIT;\n    t &= ~TARGET_INVERTED_BIT;\n    if (!((c | t) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        inv_state.prepend_ZCY(c, t);\n    } else if (t & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT)) {\n        throw std::invalid_argument(\"Measurement record editing is not supported.\");\n    } else {\n        if (read_measurement_record(c)) {\n            inv_state.prepend_Y(t);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_ZCX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        single_cx(targets[k].data, targets[k + 1].data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_ZCY(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        single_cy(targets[k].data, targets[k + 1].data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_ZCZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        q1 &= ~TARGET_INVERTED_BIT;\n        q2 &= ~TARGET_INVERTED_BIT;\n        if (!((q1 | q2) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n            inv_state.prepend_ZCZ(q1, q2);\n            continue;\n        } else if (!(q2 & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n            if (read_measurement_record(q1)) {\n                inv_state.prepend_Z(q2);\n            }\n        } else if (!(q1 & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n            if (read_measurement_record(q2)) {\n                inv_state.prepend_Z(q1);\n            }\n        } else {\n            // Both targets are bits. No effect.\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SWAP(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto c = targets[k].data;\n        auto t = targets[k + 1].data;\n        inv_state.prepend_SWAP(c, t);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_CXSWAP(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        inv_state.prepend_ZCX(q2, q1);\n        inv_state.prepend_ZCX(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_CZSWAP(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        inv_state.prepend_ZCZ(q1, q2);\n        inv_state.prepend_SWAP(q2, q1);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SWAPCX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        inv_state.prepend_ZCX(q1, q2);\n        inv_state.prepend_ZCX(q2, q1);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_ISWAP(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_ISWAP_DAG(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_ISWAP_DAG(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_ISWAP(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_XCX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        inv_state.prepend_XCX(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_ZZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_ZZ_DAG(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_ZZ_DAG(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_ZZ(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_YY(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_YY_DAG(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_YY_DAG(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_YY(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_XX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_XX_DAG(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_SQRT_XX_DAG(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        // Note: inverted because we're tracking the inverse tableau.\n        inv_state.prepend_SQRT_XX(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_XCY(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        inv_state.prepend_XCY(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_XCZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        single_cx(targets[k + 1].data, targets[k].data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_YCX(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        inv_state.prepend_YCX(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_YCY(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        auto q1 = targets[k].data;\n        auto q2 = targets[k + 1].data;\n        inv_state.prepend_YCY(q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_YCZ(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        single_cy(targets[k + 1].data, targets[k].data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_DEPOLARIZE1(const CircuitInstruction &target_data) {\n    RareErrorIterator::for_samples(target_data.args[0], target_data.targets, rng, [&](GateTarget q) {\n        auto p = 1 + (rng() % 3);\n        inv_state.xs.signs[q.data] ^= p & 1;\n        inv_state.zs.signs[q.data] ^= p & 2;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_DEPOLARIZE2(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    assert(!(targets.size() & 1));\n    auto n = targets.size() >> 1;\n    RareErrorIterator::for_samples(target_data.args[0], n, rng, [&](size_t s) {\n        auto p = 1 + (rng() % 15);\n        auto q1 = targets[s << 1].data;\n        auto q2 = targets[1 | (s << 1)].data;\n        inv_state.xs.signs[q1] ^= p & 1;\n        inv_state.zs.signs[q1] ^= p & 2;\n        inv_state.xs.signs[q2] ^= p & 4;\n        inv_state.zs.signs[q2] ^= p & 8;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_HERALDED_ERASE(const CircuitInstruction &inst) {\n    auto nt = inst.targets.size();\n    size_t offset = measurement_record.storage.size();\n    measurement_record.storage.insert(measurement_record.storage.end(), nt, false);\n\n    uint64_t rng_buf = 0;\n    size_t buf_size = 0;\n    RareErrorIterator::for_samples(inst.args[0], nt, rng, [&](size_t target) {\n        auto qubit = inst.targets[target].qubit_value();\n        if (buf_size == 0) {\n            rng_buf = rng();\n            buf_size = 64;\n        }\n        inv_state.xs.signs[qubit] ^= (bool)(rng_buf & 1);\n        inv_state.zs.signs[qubit] ^= (bool)(rng_buf & 2);\n        measurement_record.storage[offset + target] = true;\n        rng_buf >>= 2;\n        buf_size -= 2;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_HERALDED_PAULI_CHANNEL_1(const CircuitInstruction &inst) {\n    auto nt = inst.targets.size();\n    size_t offset = measurement_record.storage.size();\n    measurement_record.storage.insert(measurement_record.storage.end(), nt, false);\n\n    double hi = inst.args[0];\n    double hx = inst.args[1];\n    double hy = inst.args[2];\n    double hz = inst.args[3];\n    double ht = std::min(1.0, hi + hx + hy + hz);\n    std::array<double, 3> conditionals{hx, hy, hz};\n    if (ht != 0) {\n        conditionals[0] /= ht;\n        conditionals[1] /= ht;\n        conditionals[2] /= ht;\n    }\n    RareErrorIterator::for_samples(ht, nt, rng, [&](size_t target) {\n        measurement_record.storage[offset + target] = true;\n        do_PAULI_CHANNEL_1(CircuitInstruction{GateType::PAULI_CHANNEL_1, conditionals, &inst.targets[target], \"\"});\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_X_ERROR(const CircuitInstruction &target_data) {\n    RareErrorIterator::for_samples(target_data.args[0], target_data.targets, rng, [&](GateTarget q) {\n        inv_state.zs.signs[q.data] ^= true;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_Y_ERROR(const CircuitInstruction &target_data) {\n    RareErrorIterator::for_samples(target_data.args[0], target_data.targets, rng, [&](GateTarget q) {\n        inv_state.xs.signs[q.data] ^= true;\n        inv_state.zs.signs[q.data] ^= true;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_Z_ERROR(const CircuitInstruction &target_data) {\n    RareErrorIterator::for_samples(target_data.args[0], target_data.targets, rng, [&](GateTarget q) {\n        inv_state.xs.signs[q.data] ^= true;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_PAULI_CHANNEL_1(const CircuitInstruction &target_data) {\n    bool tmp = last_correlated_error_occurred;\n    perform_pauli_errors_via_correlated_errors<1>(\n        target_data,\n        [&]() {\n            last_correlated_error_occurred = false;\n        },\n        [&](const CircuitInstruction &d) {\n            do_ELSE_CORRELATED_ERROR(d);\n        });\n    last_correlated_error_occurred = tmp;\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_PAULI_CHANNEL_2(const CircuitInstruction &target_data) {\n    bool tmp = last_correlated_error_occurred;\n    perform_pauli_errors_via_correlated_errors<2>(\n        target_data,\n        [&]() {\n            last_correlated_error_occurred = false;\n        },\n        [&](const CircuitInstruction &d) {\n            do_ELSE_CORRELATED_ERROR(d);\n        });\n    last_correlated_error_occurred = tmp;\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_CORRELATED_ERROR(const CircuitInstruction &target_data) {\n    last_correlated_error_occurred = false;\n    do_ELSE_CORRELATED_ERROR(target_data);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_ELSE_CORRELATED_ERROR(const CircuitInstruction &target_data) {\n    if (last_correlated_error_occurred) {\n        return;\n    }\n    last_correlated_error_occurred = std::bernoulli_distribution(target_data.args[0])(rng);\n    if (!last_correlated_error_occurred) {\n        return;\n    }\n    for (auto qxz : target_data.targets) {\n        auto q = qxz.qubit_value();\n        if (qxz.data & TARGET_PAULI_X_BIT) {\n            inv_state.prepend_X(q);\n        }\n        if (qxz.data & TARGET_PAULI_Z_BIT) {\n            inv_state.prepend_Z(q);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_X(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        inv_state.prepend_X(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_Y(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        inv_state.prepend_Y(q.data);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_Z(const CircuitInstruction &target_data) {\n    const auto &targets = target_data.targets;\n    for (auto q : targets) {\n        inv_state.prepend_Z(q.data);\n    }\n}\n\ntemplate <size_t W>\nsimd_bits<W> TableauSimulator<W>::sample_circuit(const Circuit &circuit, std::mt19937_64 &rng, int8_t sign_bias) {\n    TableauSimulator<W> sim(std::move(rng), circuit.count_qubits(), sign_bias);\n    sim.safe_do_circuit(circuit);\n\n    const std::vector<bool> &v = sim.measurement_record.storage;\n    simd_bits<W> result(v.size());\n    for (size_t k = 0; k < v.size(); k++) {\n        result[k] ^= v[k];\n    }\n    rng = std::move(sim.rng);\n    return result;\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::ensure_large_enough_for_qubits(size_t num_qubits) {\n    if (num_qubits <= inv_state.num_qubits) {\n        return;\n    }\n    inv_state.expand(num_qubits, 1.1);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::sample_stream(\n    FILE *in, FILE *out, SampleFormat format, bool interactive, std::mt19937_64 &rng) {\n    TableauSimulator<W> sim(std::move(rng), 1);\n    auto writer = MeasureRecordWriter::make(out, format);\n    Circuit unprocessed;\n    while (true) {\n        unprocessed.clear();\n        if (interactive) {\n            try {\n                unprocessed.append_from_file(in, true);\n            } catch (const std::exception &ex) {\n                std::cerr << \"\\033[31m\" << ex.what() << \"\\033[0m\\n\";\n                continue;\n            }\n        } else {\n            unprocessed.append_from_file(in, true);\n        }\n        if (unprocessed.operations.empty()) {\n            break;\n        }\n        sim.ensure_large_enough_for_qubits(unprocessed.count_qubits());\n\n        unprocessed.for_each_operation([&](const CircuitInstruction &op) {\n            sim.do_gate(op);\n            sim.measurement_record.write_unwritten_results_to(*writer);\n            if (interactive && op.count_measurement_results()) {\n                putc('\\n', out);\n                fflush(out);\n            }\n        });\n    }\n    rng = std::move(sim.rng);\n    writer->write_end();\n}\n\ntemplate <size_t W>\nVectorSimulator TableauSimulator<W>::to_vector_sim() const {\n    auto inv = inv_state.inverse();\n    std::vector<PauliStringRef<W>> stabilizers;\n    for (size_t k = 0; k < inv.num_qubits; k++) {\n        stabilizers.push_back(inv.zs[k]);\n    }\n    return VectorSimulator::from_stabilizers<W>(stabilizers);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::apply_tableau(const Tableau<W> &tableau, const std::vector<size_t> &targets) {\n    inv_state.inplace_scatter_prepend(tableau.inverse(), targets);\n}\n\ntemplate <size_t W>\nstd::vector<std::complex<float>> TableauSimulator<W>::to_state_vector(bool little_endian) const {\n    auto sim = to_vector_sim();\n    if (!little_endian && inv_state.num_qubits > 0) {\n        for (size_t q = 0; q < inv_state.num_qubits - q - 1; q++) {\n            sim.apply(GateType::SWAP, q, inv_state.num_qubits - q - 1);\n        }\n    }\n    return sim.state;\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::collapse_x(SpanRef<const GateTarget> targets, size_t stride) {\n    // Find targets that need to be collapsed.\n    std::set<GateTarget> unique_collapse_targets;\n    for (size_t k = 0; k < targets.size(); k += stride) {\n        GateTarget t = targets[k];\n        t.data &= TARGET_VALUE_MASK;\n        if (!is_deterministic_x(t.data)) {\n            unique_collapse_targets.insert(t);\n        }\n    }\n\n    // Only pay the cost of transposing if collapsing is needed.\n    if (!unique_collapse_targets.empty()) {\n        std::vector<GateTarget> collapse_targets(unique_collapse_targets.begin(), unique_collapse_targets.end());\n        do_H_XZ({GateType::H, {}, collapse_targets, \"\"});\n        {\n            TableauTransposedRaii<W> temp_transposed(inv_state);\n            for (auto q : collapse_targets) {\n                collapse_qubit_z(q.data, temp_transposed);\n            }\n        }\n        do_H_XZ({GateType::H, {}, collapse_targets, \"\"});\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::collapse_y(SpanRef<const GateTarget> targets, size_t stride) {\n    // Find targets that need to be collapsed.\n    std::set<GateTarget> unique_collapse_targets;\n    for (size_t k = 0; k < targets.size(); k += stride) {\n        GateTarget t = targets[k];\n        t.data &= TARGET_VALUE_MASK;\n        if (!is_deterministic_y(t.data)) {\n            unique_collapse_targets.insert(t);\n        }\n    }\n\n    // Only pay the cost of transposing if collapsing is needed.\n    if (!unique_collapse_targets.empty()) {\n        std::vector<GateTarget> collapse_targets(unique_collapse_targets.begin(), unique_collapse_targets.end());\n        do_H_YZ({GateType::H_YZ, {}, collapse_targets, \"\"});\n        {\n            TableauTransposedRaii<W> temp_transposed(inv_state);\n            for (auto q : collapse_targets) {\n                collapse_qubit_z(q.data, temp_transposed);\n            }\n        }\n        do_H_YZ({GateType::H_YZ, {}, collapse_targets, \"\"});\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::collapse_z(SpanRef<const GateTarget> targets, size_t stride) {\n    // Find targets that need to be collapsed.\n    std::vector<GateTarget> collapse_targets;\n    collapse_targets.reserve(targets.size());\n    for (size_t k = 0; k < targets.size(); k += stride) {\n        GateTarget t = targets[k];\n        t.data &= TARGET_VALUE_MASK;\n        if (!is_deterministic_z(t.data)) {\n            collapse_targets.push_back(t);\n        }\n    }\n\n    // Only pay the cost of transposing if collapsing is needed.\n    if (!collapse_targets.empty()) {\n        TableauTransposedRaii<W> temp_transposed(inv_state);\n        for (auto target : collapse_targets) {\n            collapse_qubit_z(target.data, temp_transposed);\n        }\n    }\n}\n\ntemplate <size_t W>\nsize_t TableauSimulator<W>::collapse_qubit_z(size_t target, TableauTransposedRaii<W> &transposed_raii) {\n    auto n = inv_state.num_qubits;\n\n    // Search for any stabilizer generator that anti-commutes with the measurement observable.\n    size_t pivot = 0;\n    while (pivot < n && !transposed_raii.tableau.zs.xt[pivot][target]) {\n        pivot++;\n    }\n    if (pivot == n) {\n        // No anti-commuting stabilizer generator. Measurement is deterministic.\n        return SIZE_MAX;\n    }\n\n    // Perform partial Gaussian elimination over the stabilizer generators that anti-commute with the measurement.\n    // Do this by introducing no-effect-because-control-is-zero CNOTs at the beginning of time.\n    for (size_t k = pivot + 1; k < n; k++) {\n        if (transposed_raii.tableau.zs.xt[k][target]) {\n            transposed_raii.append_ZCX(pivot, k);\n        }\n    }\n\n    // Swap the now-isolated anti-commuting stabilizer generator for one that commutes with the measurement.\n    if (transposed_raii.tableau.zs.zt[pivot][target]) {\n        transposed_raii.append_H_YZ(pivot);\n    } else {\n        transposed_raii.append_H_XZ(pivot);\n    }\n\n    // Assign a measurement result.\n    bool result_if_measured = sign_bias == 0 ? (rng() & 1) : sign_bias < 0;\n    if (inv_state.zs.signs[target] != result_if_measured) {\n        transposed_raii.append_X(pivot);\n    }\n\n    return pivot;\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::collapse_isolate_qubit_z(size_t target, TableauTransposedRaii<W> &transposed_raii) {\n    // Force T(Z_target) to be a product of Z operations.\n    collapse_qubit_z(target, transposed_raii);\n\n    // Ensure T(Z_target) is a product of Z operations containing Z_target.\n    auto n = inv_state.num_qubits;\n    for (size_t q = 0; true; q++) {\n        assert(q < n);\n        if (transposed_raii.tableau.zs.zt[q][target]) {\n            if (q != target) {\n                transposed_raii.append_SWAP(q, target);\n            }\n            break;\n        }\n    }\n\n    // Ensure T(Z_target) = +-Z_target.\n    for (size_t q = 0; q < n; q++) {\n        if (q != target && transposed_raii.tableau.zs.zt[q][target]) {\n            // Cancel Z term on non-target q.\n            transposed_raii.append_ZCX(q, target);\n        }\n    }\n\n    // Note T(X_target) now contains X_target or Y_target because it has to anti-commute with T(Z_target) = Z_target.\n    // Ensure T(X_target) contains X_target instead of Y_target.\n    if (transposed_raii.tableau.xs.zt[target][target]) {\n        transposed_raii.append_S(target);\n    }\n\n    // Ensure T(X_target) = +-X_target.\n    for (size_t q = 0; q < n; q++) {\n        if (q != target) {\n            int p = transposed_raii.tableau.xs.xt[q][target] + 2 * transposed_raii.tableau.xs.zt[q][target];\n            if (p == 1) {\n                transposed_raii.append_ZCX(target, q);\n            } else if (p == 2) {\n                transposed_raii.append_ZCZ(target, q);\n            } else if (p == 3) {\n                transposed_raii.append_ZCY(target, q);\n            }\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::safe_do_circuit(const Circuit &circuit, uint64_t reps) {\n    ensure_large_enough_for_qubits(circuit.count_qubits());\n    for (uint64_t k = 0; k < reps; k++) {\n        circuit.for_each_operation([&](const CircuitInstruction &op) {\n            do_gate(op);\n        });\n    }\n}\n\ntemplate <size_t W>\nsimd_bits<W> TableauSimulator<W>::reference_sample_circuit(const Circuit &circuit) {\n    std::mt19937_64 irrelevant_rng(0);\n    return TableauSimulator<W>::sample_circuit(circuit.aliased_noiseless_circuit(), irrelevant_rng, +1);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::paulis(const PauliString<W> &paulis) {\n    auto nw = paulis.xs.num_simd_words;\n    inv_state.zs.signs.word_range_ref(0, nw) ^= paulis.xs;\n    inv_state.xs.signs.word_range_ref(0, nw) ^= paulis.zs;\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_operation_ensure_size(const CircuitInstruction &operation) {\n    uint64_t n = 0;\n    for (const auto &t : operation.targets) {\n        if (t.has_qubit_value()) {\n            n = std::max(n, (uint64_t)t.qubit_value() + 1);\n        }\n    }\n    ensure_large_enough_for_qubits(n);\n    do_gate(operation);\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::set_num_qubits(size_t new_num_qubits) {\n    if (new_num_qubits >= inv_state.num_qubits) {\n        ensure_large_enough_for_qubits(new_num_qubits);\n        return;\n    }\n\n    // Collapse qubits past the new size and ensure the internal state totally decouples them.\n    {\n        TableauTransposedRaii<W> temp_transposed(inv_state);\n        for (size_t q = new_num_qubits; q < inv_state.num_qubits; q++) {\n            collapse_isolate_qubit_z(q, temp_transposed);\n        }\n    }\n\n    Tableau<W> old_state = std::move(inv_state);\n    inv_state = Tableau<W>(new_num_qubits);\n    inv_state.xs.signs.truncated_overwrite_from(old_state.xs.signs, new_num_qubits);\n    inv_state.zs.signs.truncated_overwrite_from(old_state.zs.signs, new_num_qubits);\n    for (size_t q = 0; q < new_num_qubits; q++) {\n        inv_state.xs[q].xs.truncated_overwrite_from(old_state.xs[q].xs, new_num_qubits);\n        inv_state.xs[q].zs.truncated_overwrite_from(old_state.xs[q].zs, new_num_qubits);\n        inv_state.zs[q].xs.truncated_overwrite_from(old_state.zs[q].xs, new_num_qubits);\n        inv_state.zs[q].zs.truncated_overwrite_from(old_state.zs[q].zs, new_num_qubits);\n    }\n}\n\ntemplate <size_t W>\nstd::pair<bool, PauliString<W>> TableauSimulator<W>::measure_kickback_z(GateTarget target) {\n    bool flipped = target.is_inverted_result_target();\n    uint32_t q = target.qubit_value();\n    PauliString<W> kickback(0);\n    bool has_kickback = !is_deterministic_z(q);  // Note: do this before transposing the state!\n\n    {\n        TableauTransposedRaii<W> temp_transposed(inv_state);\n        if (has_kickback) {\n            size_t pivot = collapse_qubit_z(q, temp_transposed);\n            kickback = temp_transposed.unsigned_x_input(pivot);\n        }\n        bool result = inv_state.zs.signs[q] ^ flipped;\n        measurement_record.storage.push_back(result);\n\n        // Prevent later measure_kickback calls from unnecessarily targeting this qubit with a Z gate.\n        collapse_isolate_qubit_z(q, temp_transposed);\n\n        return {result, kickback};\n    }\n}\n\ntemplate <size_t W>\nstd::pair<bool, PauliString<W>> TableauSimulator<W>::measure_kickback_y(GateTarget target) {\n    do_H_YZ({GateType::H, {}, &target, \"\"});\n    auto result = measure_kickback_z(target);\n    do_H_YZ({GateType::H, {}, &target, \"\"});\n    if (result.second.num_qubits) {\n        // Also conjugate the kickback by H_YZ.\n        result.second.xs[target.qubit_value()] ^= result.second.zs[target.qubit_value()];\n    }\n    return result;\n}\n\ntemplate <size_t W>\nstd::pair<bool, PauliString<W>> TableauSimulator<W>::measure_kickback_x(GateTarget target) {\n    do_H_XZ({GateType::H, {}, &target, \"\"});\n    auto result = measure_kickback_z(target);\n    do_H_XZ({GateType::H, {}, &target, \"\"});\n    if (result.second.num_qubits) {\n        // Also conjugate the kickback by H_XZ.\n        result.second.xs[target.qubit_value()].swap_with(result.second.zs[target.qubit_value()]);\n    }\n    return result;\n}\n\ntemplate <size_t W>\nstd::vector<PauliString<W>> TableauSimulator<W>::canonical_stabilizers() const {\n    return inv_state.inverse().stabilizers(true);\n}\n\ntemplate <size_t W>\nint8_t TableauSimulator<W>::peek_observable_expectation(const PauliString<W> &observable) const {\n    TableauSimulator<W> state = *this;\n\n    // Kick the observable onto an ancilla qubit's Z observable.\n    auto n = (uint32_t)std::max(state.inv_state.num_qubits, observable.num_qubits);\n    state.ensure_large_enough_for_qubits(n + 1);\n    GateTarget anc{n};\n    if (observable.sign) {\n        state.do_X({GateType::X, {}, &anc, \"\"});\n    }\n    observable.ref().for_each_active_pauli([&](size_t q) {\n        int p = observable.xs[q] + (observable.zs[q] << 1);\n        std::array<GateTarget, 2> targets{GateTarget{(uint32_t)q}, anc};\n        GateType c2_type = GateType::CX;\n        if (p == 1) {\n            c2_type = GateType::XCX;\n        } else if (p == 3) {\n            c2_type = GateType::YCX;\n        }\n        state.do_gate({c2_type, {}, targets, \"\"});\n    });\n\n    // Use simulator features to determines if the measurement is deterministic.\n    if (!state.is_deterministic_z(anc.data)) {\n        return 0;\n    }\n    state.do_MZ({GateType::M, {}, &anc, \"\"});\n    return state.measurement_record.storage.back() ? -1 : +1;\n}\n\ntemplate <size_t W>\nvoid TableauSimulator<W>::do_gate(const CircuitInstruction &inst) {\n    switch (inst.gate_type) {\n        case GateType::DETECTOR:\n            do_I(inst);\n            break;\n        case GateType::OBSERVABLE_INCLUDE:\n            do_I(inst);\n            break;\n        case GateType::TICK:\n            do_I(inst);\n            break;\n        case GateType::QUBIT_COORDS:\n            do_I(inst);\n            break;\n        case GateType::SHIFT_COORDS:\n            do_I(inst);\n            break;\n        case GateType::REPEAT:\n            do_I(inst);\n            break;\n        case GateType::MX:\n            do_MX(inst);\n            break;\n        case GateType::MY:\n            do_MY(inst);\n            break;\n        case GateType::M:\n            do_MZ(inst);\n            break;\n        case GateType::MRX:\n            do_MRX(inst);\n            break;\n        case GateType::MRY:\n            do_MRY(inst);\n            break;\n        case GateType::MR:\n            do_MRZ(inst);\n            break;\n        case GateType::RX:\n            do_RX(inst);\n            break;\n        case GateType::RY:\n            do_RY(inst);\n            break;\n        case GateType::R:\n            do_RZ(inst);\n            break;\n        case GateType::MPP:\n            do_MPP(inst);\n            break;\n        case GateType::SPP:\n            do_SPP(inst);\n            break;\n        case GateType::SPP_DAG:\n            do_SPP_DAG(inst);\n            break;\n        case GateType::MXX:\n            do_MXX(inst);\n            break;\n        case GateType::MYY:\n            do_MYY(inst);\n            break;\n        case GateType::MZZ:\n            do_MZZ(inst);\n            break;\n        case GateType::MPAD:\n            do_MPAD(inst);\n            break;\n        case GateType::XCX:\n            do_XCX(inst);\n            break;\n        case GateType::XCY:\n            do_XCY(inst);\n            break;\n        case GateType::XCZ:\n            do_XCZ(inst);\n            break;\n        case GateType::YCX:\n            do_YCX(inst);\n            break;\n        case GateType::YCY:\n            do_YCY(inst);\n            break;\n        case GateType::YCZ:\n            do_YCZ(inst);\n            break;\n        case GateType::CX:\n            do_ZCX(inst);\n            break;\n        case GateType::CY:\n            do_ZCY(inst);\n            break;\n        case GateType::CZ:\n            do_ZCZ(inst);\n            break;\n        case GateType::H:\n            do_H_XZ(inst);\n            break;\n        case GateType::H_XY:\n            do_H_XY(inst);\n            break;\n        case GateType::H_YZ:\n            do_H_YZ(inst);\n            break;\n        case GateType::H_NXY:\n            do_H_NXY(inst);\n            break;\n        case GateType::H_NXZ:\n            do_H_NXZ(inst);\n            break;\n        case GateType::H_NYZ:\n            do_H_NYZ(inst);\n            break;\n        case GateType::DEPOLARIZE1:\n            do_DEPOLARIZE1(inst);\n            break;\n        case GateType::DEPOLARIZE2:\n            do_DEPOLARIZE2(inst);\n            break;\n        case GateType::X_ERROR:\n            do_X_ERROR(inst);\n            break;\n        case GateType::Y_ERROR:\n            do_Y_ERROR(inst);\n            break;\n        case GateType::Z_ERROR:\n            do_Z_ERROR(inst);\n            break;\n        case GateType::PAULI_CHANNEL_1:\n            do_PAULI_CHANNEL_1(inst);\n            break;\n        case GateType::PAULI_CHANNEL_2:\n            do_PAULI_CHANNEL_2(inst);\n            break;\n        case GateType::E:\n            do_CORRELATED_ERROR(inst);\n            break;\n        case GateType::ELSE_CORRELATED_ERROR:\n            do_ELSE_CORRELATED_ERROR(inst);\n            break;\n        case GateType::I:\n        case GateType::II:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n            do_I(inst);\n            break;\n        case GateType::X:\n            do_X(inst);\n            break;\n        case GateType::Y:\n            do_Y(inst);\n            break;\n        case GateType::Z:\n            do_Z(inst);\n            break;\n        case GateType::C_XYZ:\n            do_C_XYZ(inst);\n            break;\n        case GateType::C_NXYZ:\n            do_C_NXYZ(inst);\n            break;\n        case GateType::C_XNYZ:\n            do_C_XNYZ(inst);\n            break;\n        case GateType::C_XYNZ:\n            do_C_XYNZ(inst);\n            break;\n        case GateType::C_ZYX:\n            do_C_ZYX(inst);\n            break;\n        case GateType::C_NZYX:\n            do_C_NZYX(inst);\n            break;\n        case GateType::C_ZNYX:\n            do_C_ZNYX(inst);\n            break;\n        case GateType::C_ZYNX:\n            do_C_ZYNX(inst);\n            break;\n        case GateType::SQRT_X:\n            do_SQRT_X(inst);\n            break;\n        case GateType::SQRT_X_DAG:\n            do_SQRT_X_DAG(inst);\n            break;\n        case GateType::SQRT_Y:\n            do_SQRT_Y(inst);\n            break;\n        case GateType::SQRT_Y_DAG:\n            do_SQRT_Y_DAG(inst);\n            break;\n        case GateType::S:\n            do_SQRT_Z(inst);\n            break;\n        case GateType::S_DAG:\n            do_SQRT_Z_DAG(inst);\n            break;\n        case GateType::SQRT_XX:\n            do_SQRT_XX(inst);\n            break;\n        case GateType::SQRT_XX_DAG:\n            do_SQRT_XX_DAG(inst);\n            break;\n        case GateType::SQRT_YY:\n            do_SQRT_YY(inst);\n            break;\n        case GateType::SQRT_YY_DAG:\n            do_SQRT_YY_DAG(inst);\n            break;\n        case GateType::SQRT_ZZ:\n            do_SQRT_ZZ(inst);\n            break;\n        case GateType::SQRT_ZZ_DAG:\n            do_SQRT_ZZ_DAG(inst);\n            break;\n        case GateType::SWAP:\n            do_SWAP(inst);\n            break;\n        case GateType::ISWAP:\n            do_ISWAP(inst);\n            break;\n        case GateType::ISWAP_DAG:\n            do_ISWAP_DAG(inst);\n            break;\n        case GateType::CXSWAP:\n            do_CXSWAP(inst);\n            break;\n        case GateType::CZSWAP:\n            do_CZSWAP(inst);\n            break;\n        case GateType::SWAPCX:\n            do_SWAPCX(inst);\n            break;\n        case GateType::HERALDED_ERASE:\n            do_HERALDED_ERASE(inst);\n            break;\n        case GateType::HERALDED_PAULI_CHANNEL_1:\n            do_HERALDED_PAULI_CHANNEL_1(inst);\n            break;\n        default:\n            throw std::invalid_argument(\n                \"Not implemented by TableauSimulator::do_gate: \" + std::string(GATE_DATA[inst.gate_type].name));\n    }\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/simulators/tableau_simulator.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/tableau_simulator.h\"\n\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(TableauSimulator_CX_10Kqubits) {\n    size_t num_qubits = 10 * 1000;\n    TableauSimulator<MAX_BITWORD_WIDTH> sim(std::mt19937_64(0), num_qubits);\n\n    std::vector<GateTarget> targets;\n    for (uint32_t k = 0; k < (uint32_t)num_qubits; k++) {\n        targets.push_back(GateTarget{k});\n    }\n    CircuitInstruction op_data{GateType::CX, {}, targets, \"\"};\n\n    benchmark_go([&]() {\n        sim.do_ZCX(op_data);\n    })\n        .goal_millis(5)\n        .show_rate(\"OpQubits\", targets.size());\n}\n"
  },
  {
    "path": "src/stim/simulators/tableau_simulator.pybind.cc",
    "content": "#include \"stim/simulators/tableau_simulator.pybind.h\"\n\n#include \"stim/circuit/circuit_instruction.pybind.h\"\n#include \"stim/circuit/circuit_repeat_block.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/stabilizers/pauli_string.pybind.h\"\n#include \"stim/stabilizers/tableau.h\"\n#include \"stim/util_bot/str_util.h\"\n#include \"stim/util_top/circuit_vs_amplitudes.h\"\n#include \"stim/util_top/stabilizers_to_tableau.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\ntemplate <size_t W>\nvoid do_obj(TableauSimulator<W> &self, const pybind11::object &obj) {\n    if (pybind11::isinstance<Circuit>(obj)) {\n        self.safe_do_circuit(pybind11::cast<Circuit>(obj));\n    } else if (pybind11::isinstance<CircuitRepeatBlock>(obj)) {\n        const CircuitRepeatBlock &block = pybind11::cast<CircuitRepeatBlock>(obj);\n        self.safe_do_circuit(block.body, block.repeat_count);\n    } else if (pybind11::isinstance<FlexPauliString>(obj)) {\n        const FlexPauliString &pauli_string = pybind11::cast<FlexPauliString>(obj);\n        self.ensure_large_enough_for_qubits(pauli_string.value.num_qubits);\n        self.paulis(pauli_string.value);\n    } else if (pybind11::isinstance<PyCircuitInstruction>(obj)) {\n        const PyCircuitInstruction &circuit_instruction = pybind11::cast<PyCircuitInstruction>(obj);\n        self.do_operation_ensure_size(circuit_instruction);\n    } else {\n        std::stringstream ss;\n        ss << \"Don't know how to handle \";\n        ss << pybind11::repr(obj);\n        throw std::invalid_argument(ss.str());\n    }\n}\n\ntemplate <size_t W>\nTableauSimulator<W> create_tableau_simulator(const pybind11::object &seed) {\n    return TableauSimulator<W>(make_py_seeded_rng(seed));\n}\n\ntemplate <size_t W>\nstd::vector<GateTarget> arg_to_qubit_or_qubits(TableauSimulator<W> &self, const pybind11::object &obj) {\n    std::vector<GateTarget> arguments;\n    uint32_t max_q = 0;\n    try {\n        try {\n            uint32_t q = pybind11::cast<uint32_t>(obj);\n            arguments.push_back(GateTarget::qubit(q));\n            max_q = q;\n        } catch (const pybind11::cast_error &) {\n            for (const auto &e : obj) {\n                uint32_t q = e.cast<uint32_t>();\n                max_q = std::max(max_q, q);\n                arguments.push_back(GateTarget::qubit(q));\n            }\n        }\n    } catch (const pybind11::cast_error &) {\n        throw std::out_of_range(\"'targets' must be a non-negative integer or iterable of non-negative integers.\");\n    }\n\n    // Note: quadratic behavior.\n    self.ensure_large_enough_for_qubits(max_q + 1);\n\n    return arguments;\n}\n\ntemplate <size_t W>\nPyCircuitInstruction build_single_qubit_gate_instruction_ensure_size(\n    TableauSimulator<W> &self, GateType gate_type, const pybind11::args &args, SpanRef<const double> gate_args = {}) {\n    std::vector<GateTarget> targets;\n    uint32_t max_q = 0;\n    try {\n        for (const auto &e : args) {\n            if (pybind11::isinstance<GateTarget>(e)) {\n                targets.push_back(pybind11::cast<GateTarget>(e));\n            } else {\n                uint32_t q = e.cast<uint32_t>();\n                max_q = std::max(max_q, q & TARGET_VALUE_MASK);\n                targets.push_back(GateTarget{q});\n            }\n        }\n    } catch (const pybind11::cast_error &) {\n        throw std::out_of_range(\"Target qubits must be non-negative integers.\");\n    }\n\n    std::vector<double> gate_args_vec;\n    for (const auto &e : gate_args) {\n        gate_args_vec.push_back(e);\n    }\n\n    // Note: quadratic behavior.\n    self.ensure_large_enough_for_qubits(max_q + 1);\n\n    return PyCircuitInstruction(gate_type, targets, gate_args_vec, \"\");\n}\n\ntemplate <size_t W>\nPyCircuitInstruction build_two_qubit_gate_instruction_ensure_size(\n    TableauSimulator<W> &self, GateType gate_type, const pybind11::args &args, SpanRef<const double> gate_args = {}) {\n    if (pybind11::len(args) & 1) {\n        throw std::invalid_argument(\"Two qubit operation requires an even number of targets.\");\n    }\n    auto result = build_single_qubit_gate_instruction_ensure_size<W>(self, gate_type, args, gate_args);\n    for (size_t k = 0; k < result.targets.size(); k += 2) {\n        if (result.targets[k] == result.targets[k + 1]) {\n            throw std::invalid_argument(\"Two qubit operation can't target the same qubit twice.\");\n        }\n    }\n    return result;\n}\n\npybind11::class_<TableauSimulator<MAX_BITWORD_WIDTH>> stim_pybind::pybind_tableau_simulator(pybind11::module &m) {\n    return pybind11::class_<TableauSimulator<MAX_BITWORD_WIDTH>>(\n        m,\n        \"TableauSimulator\",\n        clean_doc_string(R\"DOC(\n            A stabilizer circuit simulator that tracks an inverse stabilizer tableau.\n\n            Supports interactive usage, where gates and measurements are applied on demand.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.h(0)\n                >>> if s.measure(0):\n                ...     s.h(1)\n                ...     s.cnot(1, 2)\n                >>> s.measure(1) == s.measure(2)\n                True\n\n                >>> s = stim.TableauSimulator()\n                >>> s.h(0)\n                >>> s.cnot(0, 1)\n                >>> s.current_inverse_tableau()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+ZX\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+X_\"),\n                        stim.PauliString(\"+XZ\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_tableau_simulator_methods(\n    pybind11::module &m, pybind11::class_<TableauSimulator<MAX_BITWORD_WIDTH>> &c) {\n    c.def(\n        pybind11::init(&create_tableau_simulator<MAX_BITWORD_WIDTH>),\n        pybind11::kw_only(),\n        pybind11::arg(\"seed\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def __init__(self, *, seed: Optional[int] = None) -> None:\n            Initializes a stim.TableauSimulator.\n\n            Args:\n                seed: PARTIALLY determines simulation results by deterministically seeding\n                    the random number generator.\n\n                    Must be None or an integer in range(2**64).\n\n                    Defaults to None. When None, the prng is seeded from system entropy.\n\n                    When set to an integer, making the exact same series calls on the exact\n                    same machine with the exact same version of Stim will produce the exact\n                    same simulation results.\n\n                    CAUTION: simulation results *WILL NOT* be consistent between versions of\n                    Stim. This restriction is present to make it possible to have future\n                    optimizations to the random sampling, and is enforced by introducing\n                    intentional differences in the seeding strategy from version to version.\n\n                    CAUTION: simulation results *MAY NOT* be consistent across machines that\n                    differ in the width of supported SIMD instructions. For example, using\n                    the same seed on a machine that supports AVX instructions and one that\n                    only supports SSE instructions may produce different simulation results.\n\n                    CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                    circuit is executed. For example, reordering whether a reset on one\n                    qubit happens before or after a reset on another qubit can result in\n                    different measurement results being observed starting from the same\n                    seed.\n\n            Returns:\n                An initialized stim.TableauSimulator.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator(seed=0)\n                >>> s2 = stim.TableauSimulator(seed=0)\n                >>> s.h(0)\n                >>> s2.h(0)\n                >>> s.measure(0) == s2.measure(0)\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"current_inverse_tableau\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self) {\n            return self.inv_state;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the internal state of the simulator as a stim.Tableau.\n\n            Returns:\n                A stim.Tableau copy of the simulator's state.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.h(0)\n                >>> s.current_inverse_tableau()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+X\"),\n                    ],\n                )\n                >>> s.cnot(0, 1)\n                >>> s.current_inverse_tableau()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+ZX\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+X_\"),\n                        stim.PauliString(\"+XZ\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def(\n        \"state_vector\",\n        [](const TableauSimulator<MAX_BITWORD_WIDTH> &self, std::string_view endian) {\n            bool little_endian;\n            if (endian == \"little\") {\n                little_endian = true;\n            } else if (endian == \"big\") {\n                little_endian = false;\n            } else {\n                throw std::invalid_argument(\"endian not in ['little', 'big']\");\n            }\n            auto complex_vec = self.to_state_vector(little_endian);\n\n            std::complex<float> *buffer = new std::complex<float>[complex_vec.size()];\n            for (size_t k = 0; k < complex_vec.size(); k++) {\n                buffer[k] = complex_vec[k];\n            }\n\n            pybind11::capsule free_when_done(buffer, [](void *f) {\n                delete[] reinterpret_cast<std::complex<float> *>(f);\n            });\n\n            return pybind11::array_t<std::complex<float>>(\n                {(pybind11::ssize_t)complex_vec.size()},\n                {(pybind11::ssize_t)sizeof(std::complex<float>)},\n                buffer,\n                free_when_done);\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"endian\") = \"little\",\n        clean_doc_string(R\"DOC(\n            @signature def state_vector(self, *, endian: Literal[\"little\", \"big\"] = 'little') -> np.ndarray[np.complex64]:\n            Returns a wavefunction for the simulator's current state.\n\n            This function takes O(n * 2**n) time and O(2**n) space, where n is the number of\n            qubits. The computation is done by initialization a random state vector and\n            iteratively projecting it into the +1 eigenspace of each stabilizer of the\n            state. The state is then canonicalized so that zero values are actually exactly\n            0, and so that the first non-zero entry is positive.\n\n            Args:\n                endian:\n                    \"little\" (default): state vector is in little endian order, where higher\n                        index qubits correspond to larger changes in the state index.\n                    \"big\": state vector is in big endian order, where higher index qubits\n                        correspond to smaller changes in the state index.\n\n            Returns:\n                A `numpy.ndarray[numpy.complex64]` of computational basis amplitudes.\n\n                If the result is in little endian order then the amplitude at offset\n                b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n                computational basis state where the qubit with index 0 is storing the bit\n                b_0, the qubit with index 1 is storing the bit b_1, etc.\n\n                If the result is in big endian order then the amplitude at offset\n                b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n                computational basis state where the qubit with index 0 is storing the bit\n                b_{n-1}, the qubit with index 1 is storing the bit b_{n-2}, etc.\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n                >>> s = stim.TableauSimulator()\n                >>> s.x(2)\n                >>> s.state_vector(endian='little')\n                array([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                      dtype=complex64)\n\n                >>> s.state_vector(endian='big')\n                array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                      dtype=complex64)\n\n                >>> s.sqrt_x(1, 2)\n                >>> s.state_vector()\n                array([0.5+0.j , 0. +0.j , 0. -0.5j, 0. +0.j , 0. +0.5j, 0. +0.j ,\n                       0.5+0.j , 0. +0.j ], dtype=complex64)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"canonical_stabilizers\",\n        [](const TableauSimulator<MAX_BITWORD_WIDTH> &self) {\n            auto stabilizers = self.canonical_stabilizers();\n            std::vector<FlexPauliString> result;\n            result.reserve(stabilizers.size());\n            for (auto &s : stabilizers) {\n                result.emplace_back(std::move(s), false);\n            }\n            return result;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a standardized list of the simulator's current stabilizer generators.\n\n            Two simulators have the same canonical stabilizers if and only if their current\n            quantum state is equal (and tracking the same number of qubits).\n\n            The canonical form is computed as follows:\n\n                1. Get a list of stabilizers using the `z_output`s of\n                    `simulator.current_inverse_tableau()**-1`.\n                2. Perform Gaussian elimination on each generator g.\n                    2a) The generators are considered in order X0, Z0, X1, Z1, X2, Z2, etc.\n                    2b) Pick any stabilizer that uses the generator g. If there are none,\n                        go to the next g.\n                    2c) Multiply that stabilizer into all other stabilizers that use the\n                        generator g.\n                    2d) Swap that stabilizer with the stabilizer at position `next_output`\n                        then increment `next_output`.\n\n            Returns:\n                A List[stim.PauliString] of the simulator's state's stabilizers.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.h(0)\n                >>> s.cnot(0, 1)\n                >>> s.x(2)\n                >>> for e in s.canonical_stabilizers():\n                ...     print(repr(e))\n                stim.PauliString(\"+XX_\")\n                stim.PauliString(\"+ZZ_\")\n                stim.PauliString(\"-__Z\")\n\n                >>> # Scramble the stabilizers then check the canonical form is unchanged.\n                >>> s.set_inverse_tableau(s.current_inverse_tableau()**-1)\n                >>> s.cnot(0, 1)\n                >>> s.cz(0, 2)\n                >>> s.s(0, 2)\n                >>> s.cy(2, 1)\n                >>> s.set_inverse_tableau(s.current_inverse_tableau()**-1)\n                >>> for e in s.canonical_stabilizers():\n                ...     print(repr(e))\n                stim.PauliString(\"+XX_\")\n                stim.PauliString(\"+ZZ_\")\n                stim.PauliString(\"-__Z\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"current_measurement_record\",\n        [](const TableauSimulator<MAX_BITWORD_WIDTH> &self) {\n            return self.measurement_record.storage;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the record of all measurements performed by the simulator.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.current_measurement_record()\n                []\n                >>> s.measure(0)\n                False\n                >>> s.x(0)\n                >>> s.measure(0)\n                True\n                >>> s.current_measurement_record()\n                [False, True]\n                >>> s.do(stim.Circuit(\"M 0\"))\n                >>> s.current_measurement_record()\n                [False, True, True]\n\n            Returns:\n                A list of booleans containing the result of every measurement performed by\n                the simulator so far.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"do\",\n        &do_obj<MAX_BITWORD_WIDTH>,\n        pybind11::arg(\"circuit_or_pauli_string\"),\n        clean_doc_string(R\"DOC(\n            Applies a circuit or pauli string to the simulator's state.\n            @signature def do(self, circuit_or_pauli_string: Union[stim.Circuit, stim.PauliString, stim.CircuitInstruction, stim.CircuitRepeatBlock]) -> None:\n\n            Args:\n                circuit_or_pauli_string: A stim.Circuit, stim.PauliString,\n                    stim.CircuitInstruction, or stim.CircuitRepeatBlock\n                    with operations to apply to the simulator's state.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.do(stim.Circuit('''\n                ...     X 0\n                ...     M 0\n                ... '''))\n                >>> s.current_measurement_record()\n                [True]\n\n                >>> s = stim.TableauSimulator()\n                >>> s.do(stim.PauliString(\"IXYZ\"))\n                >>> s.measure_many(0, 1, 2, 3)\n                [False, True, True, False]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"do_pauli_string\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, FlexPauliString &pauli_string) {\n            self.ensure_large_enough_for_qubits(pauli_string.value.num_qubits);\n            self.paulis(pauli_string.value);\n        },\n        pybind11::arg(\"pauli_string\"),\n        clean_doc_string(R\"DOC(\n            Applies the paulis from a pauli string to the simulator's state.\n\n            Args:\n                pauli_string: A stim.PauliString containing Paulis to apply.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.do_pauli_string(stim.PauliString(\"IXYZ\"))\n                >>> s.measure_many(0, 1, 2, 3)\n                [False, True, True, False]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"do_circuit\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const Circuit &circuit) {\n            self.safe_do_circuit(circuit);\n        },\n        pybind11::arg(\"circuit\"),\n        clean_doc_string(R\"DOC(\n            Applies a circuit to the simulator's state.\n\n            Args:\n                circuit: A stim.Circuit containing operations to apply.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.do_circuit(stim.Circuit('''\n                ...     X 0\n                ...     M 0\n                ... '''))\n                >>> s.current_measurement_record()\n                [True]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"do_tableau\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self,\n           const Tableau<MAX_BITWORD_WIDTH> &tableau,\n           const std::vector<size_t> &targets) {\n            if (targets.size() != tableau.num_qubits) {\n                throw std::invalid_argument(\"len(tableau) != len(targets)\");\n            }\n            size_t max_target = 0;\n            for (size_t i = 0; i < targets.size(); i++) {\n                max_target = std::max(max_target, targets[i]);\n                for (size_t j = i + 1; j < targets.size(); j++) {\n                    if (targets[i] == targets[j]) {\n                        std::stringstream ss;\n                        ss << \"targets contains duplicates: \";\n                        ss << comma_sep(targets);\n                        throw std::invalid_argument(ss.str());\n                    }\n                }\n            }\n            self.ensure_large_enough_for_qubits(max_target + 1);\n            self.apply_tableau(tableau, targets);\n        },\n        pybind11::arg(\"tableau\"),\n        pybind11::arg(\"targets\"),\n        clean_doc_string(R\"DOC(\n            Applies a custom tableau operation to qubits in the simulator.\n\n            Note that this method has to compute the inverse of the tableau, because the\n            simulator's internal state is an inverse tableau.\n\n            Args:\n                tableau: A stim.Tableau representing the Clifford operation to apply.\n                targets: The indices of the qubits to operate on.\n\n            Examples:\n                >>> import stim\n                >>> sim = stim.TableauSimulator()\n                >>> sim.h(1)\n                >>> sim.h_yz(2)\n                >>> [str(sim.peek_bloch(k)) for k in range(4)]\n                ['+Z', '+X', '+Y', '+Z']\n                >>> rot3 = stim.Tableau.from_conjugated_generators(\n                ...     xs=[\n                ...         stim.PauliString(\"_X_\"),\n                ...         stim.PauliString(\"__X\"),\n                ...         stim.PauliString(\"X__\"),\n                ...     ],\n                ...     zs=[\n                ...         stim.PauliString(\"_Z_\"),\n                ...         stim.PauliString(\"__Z\"),\n                ...         stim.PauliString(\"Z__\"),\n                ...     ],\n                ... )\n\n                >>> sim.do_tableau(rot3, [1, 2, 3])\n                >>> [str(sim.peek_bloch(k)) for k in range(4)]\n                ['+Z', '+Z', '+X', '+Y']\n\n                >>> sim.do_tableau(rot3, [1, 2, 3])\n                >>> [str(sim.peek_bloch(k)) for k in range(4)]\n                ['+Z', '+Y', '+Z', '+X']\n        )DOC\")\n            .data());\n\n    c.def(\n        \"h\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_H_XZ(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::H, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a Hadamard gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.h(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +Z -Y +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"depolarize1\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args, const pybind11::kwargs &kwargs) {\n            double p = pybind11::cast<double>(kwargs[\"p\"]);\n            if (kwargs.size() != 1) {\n                throw std::invalid_argument(\"Unexpected argument. Expected position-only targets and p=probability.\");\n            }\n            self.do_DEPOLARIZE1(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(\n                    self, GateType::DEPOLARIZE1, args, &p));\n        },\n        clean_doc_string(R\"DOC(\n            @signature def depolarize1(self, *targets: int, p: float):\n            Probabilistically applies single-qubit depolarization to targets.\n\n            Args:\n                *targets: The indices of the qubits to target with the noise.\n                p: The chance of the error being applied,\n                    independently, to each qubit.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.depolarize1(0, 1, 2, p=0.01)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"depolarize2\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args, const pybind11::kwargs &kwargs) {\n            double p = pybind11::cast<double>(kwargs[\"p\"]);\n            if (kwargs.size() != 1) {\n                throw std::invalid_argument(\"Unexpected argument. Expected position-only targets and p=probability.\");\n            }\n            self.do_DEPOLARIZE2(\n                build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::DEPOLARIZE2, args, &p));\n        },\n        clean_doc_string(R\"DOC(\n            @signature def depolarize2(self, *targets: int, p: float):\n            Probabilistically applies two-qubit depolarization to targets.\n\n            Args:\n                *targets: The indices of the qubits to target with the noise.\n                    The pairs of qubits are formed by\n                    zip(targets[::1], targets[1::2]).\n                p: The chance of the error being applied,\n                    independently, to each qubit pair.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.depolarize1(0, 1, 4, 5, p=0.01)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"x_error\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args, const pybind11::kwargs &kwargs) {\n            double p = pybind11::cast<double>(kwargs[\"p\"]);\n            if (kwargs.size() != 1) {\n                throw std::invalid_argument(\"Unexpected argument. Expected position-only targets and p=probability.\");\n            }\n            self.do_X_ERROR(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(\n                    self, GateType::X_ERROR, args, {&p}));\n        },\n        clean_doc_string(R\"DOC(\n            @signature def x_error(self, *targets: int, p: float):\n            Probabilistically applies X errors to targets.\n\n            Args:\n                *targets: The indices of the qubits to target with the noise.\n                p: The chance of the X error being applied,\n                    independently, to each qubit.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.x_error(0, 1, 2, p=0.01)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"y_error\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args, const pybind11::kwargs &kwargs) {\n            double p = pybind11::cast<double>(kwargs[\"p\"]);\n            if (kwargs.size() != 1) {\n                throw std::invalid_argument(\"Unexpected argument. Expected position-only targets and p=probability.\");\n            }\n            self.do_Y_ERROR(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::Y_ERROR, args, &p));\n        },\n        clean_doc_string(R\"DOC(\n            @signature def y_error(self, *targets: int, p: float):\n            Probabilistically applies Y errors to targets.\n\n            Args:\n                *targets: The indices of the qubits to target with the noise.\n                p: The chance of the Y error being applied,\n                    independently, to each qubit.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.y_error(0, 1, 2, p=0.01)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"z_error\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args, const pybind11::kwargs &kwargs) {\n            double p = pybind11::cast<double>(kwargs[\"p\"]);\n            if (kwargs.size() != 1) {\n                throw std::invalid_argument(\"Unexpected argument. Expected position-only targets and p=probability.\");\n            }\n            self.do_Z_ERROR(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::Z_ERROR, args, &p));\n        },\n        clean_doc_string(R\"DOC(\n            @signature def z_error(self, *targets: int, p: float):\n            Probabilistically applies Z errors to targets.\n\n            Args:\n                *targets: The indices of the qubits to target with the noise.\n                p: The chance of the Z error being applied,\n                    independently, to each qubit.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.z_error(0, 1, 2, p=0.01)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"h_xz\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_H_XZ(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::H, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a Hadamard gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.h_xz(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +Z -Y +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"c_xyz\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_C_XYZ(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::C_XYZ, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a C_XYZ gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.c_xyz(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +Y +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"c_zyx\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_C_ZYX(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::C_ZYX, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a C_ZYX gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.c_zyx(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +Z +X +Y\n        )DOC\")\n            .data());\n\n    c.def(\n        \"h_xy\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_H_XY(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::H_XY, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies an operation that swaps the X and Y axes to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.h_xy(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +Y +X -Z\n        )DOC\")\n            .data());\n\n    c.def(\n        \"h_yz\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_H_YZ(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::H_YZ, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies an operation that swaps the Y and Z axes to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.h_yz(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                -X +Z +Y\n        )DOC\")\n            .data());\n\n    c.def(\n        \"x\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_X(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::X, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a Pauli X gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.x(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X -Y -Z\n        )DOC\")\n            .data());\n\n    c.def(\n        \"y\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_Y(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::Y, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a Pauli Y gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.y(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                -X +Y -Z\n        )DOC\")\n            .data());\n\n    c.def(\n        \"z\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, pybind11::args targets) {\n            self.do_Z(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::Z, targets));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a Pauli Z gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.z(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                -X -Y +Z\n        )DOC\")\n            .data());\n\n    c.def(\n        \"s\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_SQRT_Z(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::S, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a SQRT_Z gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.s(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +Y -X +Z\n        )DOC\")\n            .data());\n\n    c.def(\n        \"s_dag\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_SQRT_Z_DAG(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::S_DAG, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a SQRT_Z_DAG gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.s_dag(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                -Y +X +Z\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sqrt_x\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_SQRT_X(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::SQRT_X, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a SQRT_X gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.sqrt_x(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Z -Y\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sqrt_x_dag\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_SQRT_X_DAG(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::SQRT_X_DAG, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a SQRT_X_DAG gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.sqrt_x_dag(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X -Z +Y\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sqrt_y\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_SQRT_Y(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::SQRT_Y, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a SQRT_Y gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.sqrt_y(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                -Z +Y +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"sqrt_y_dag\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_SQRT_Y_DAG(\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::SQRT_Y_DAG, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a SQRT_Y_DAG gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +X +Y +Z\n                >>> s.sqrt_y_dag(0, 1, 2)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(3)))\n                +Z +Y -X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"swap\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_SWAP(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::SWAP, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a swap gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.swap(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +Y +X +X +Z\n        )DOC\")\n            .data());\n\n    c.def(\n        \"iswap\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_ISWAP(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::ISWAP, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies an ISWAP gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.iswap(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +_ +_ +Y +Z\n        )DOC\")\n            .data());\n\n    c.def(\n        \"iswap_dag\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_ISWAP_DAG(\n                build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::ISWAP_DAG, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies an ISWAP_DAG gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.iswap_dag(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +_ +_ -Y +Z\n        )DOC\")\n            .data());\n\n    c.def(\n        \"cnot\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_ZCX(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::CX, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a controlled X gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.cnot(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +_ +_ +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"zcx\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_ZCX(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::CX, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a controlled X gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.zcx(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +_ +_ +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"cx\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_ZCX(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::CX, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a controlled X gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.cx(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +_ +_ +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"cz\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_ZCZ(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::CZ, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a controlled Z gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.cz(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +_ +_ +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"zcz\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_ZCZ(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::CZ, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a controlled Z gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.zcz(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +_ +_ +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"cy\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_ZCY(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::CY, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a controlled Y gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.cy(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"zcy\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_ZCY(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::CY, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a controlled Y gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.zcy(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"xcx\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_XCX(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::XCX, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies an X-controlled X gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.xcx(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"xcy\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_XCY(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::XCY, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies an X-controlled Y gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.xcy(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +_ +_\n        )DOC\")\n            .data());\n\n    c.def(\n        \"xcz\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_XCZ(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::XCZ, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies an X-controlled Z gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.xcz(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +_ +_\n        )DOC\")\n            .data());\n\n    c.def(\n        \"ycx\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_YCX(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::YCX, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a Y-controlled X gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.ycx(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +_ +_ +Z +X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"ycy\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_YCY(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::YCY, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a Y-controlled Y gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.ycy(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +_ +_\n        )DOC\")\n            .data());\n\n    c.def(\n        \"ycz\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_YCZ(build_two_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::YCZ, args));\n        },\n        clean_doc_string(R\"DOC(\n            Applies a Y-controlled Z gate to the simulator's state.\n\n            Args:\n                *targets: The indices of the qubits to target with the gate.\n                    Applies the gate to the first two targets, then the next two targets,\n                    and so forth. There must be an even number of targets.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0, 3)\n                >>> s.reset_y(1)\n\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +X +Y +Z +X\n                >>> s.ycz(0, 1, 2, 3)\n                >>> print(\" \".join(str(s.peek_bloch(k)) for k in range(4)))\n                +_ +_ +_ +_\n        )DOC\")\n            .data());\n\n    c.def(\n        \"reset\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_RZ(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::R, args));\n        },\n        clean_doc_string(R\"DOC(\n            Resets qubits to the |0> state.\n\n            Args:\n                *targets: The indices of the qubits to reset.\n\n            Example:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.x(0)\n                >>> s.reset(0)\n                >>> s.peek_bloch(0)\n                stim.PauliString(\"+Z\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"reset_x\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_RX(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::RX, args));\n        },\n        clean_doc_string(R\"DOC(\n            Resets qubits to the |+> state.\n\n            Args:\n                *targets: The indices of the qubits to reset.\n\n            Example:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.peek_bloch(0)\n                stim.PauliString(\"+X\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"reset_y\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_RY(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::RY, args));\n        },\n        clean_doc_string(R\"DOC(\n            Resets qubits to the |i> state.\n\n            Args:\n                *targets: The indices of the qubits to reset.\n\n            Example:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_y(0)\n                >>> s.peek_bloch(0)\n                stim.PauliString(\"+Y\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"reset_z\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            self.do_RZ(build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::R, args));\n        },\n        clean_doc_string(R\"DOC(\n            Resets qubits to the |0> state.\n\n            Args:\n                *targets: The indices of the qubits to reset.\n\n            Example:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.h(0)\n                >>> s.reset_z(0)\n                >>> s.peek_bloch(0)\n                stim.PauliString(\"+Z\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"peek_x\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, uint32_t target) -> int8_t {\n            self.ensure_large_enough_for_qubits(target + 1);\n            return self.peek_x(target);\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns the expected value of a qubit's X observable.\n\n            Because the simulator's state is always a stabilizer state, the expectation will\n            always be exactly -1, 0, or +1.\n\n            This is a non-physical operation.\n            It reports information about the quantum state without disturbing it.\n\n            Args:\n                target: The qubit to analyze.\n\n            Returns:\n                +1: Qubit is in the |+> state.\n                -1: Qubit is in the |-> state.\n                0: Qubit is in some other state.\n\n            Example:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_z(0)\n                >>> s.peek_x(0)\n                0\n                >>> s.reset_x(0)\n                >>> s.peek_x(0)\n                1\n                >>> s.z(0)\n                >>> s.peek_x(0)\n                -1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"peek_y\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, uint32_t target) -> int8_t {\n            self.ensure_large_enough_for_qubits(target + 1);\n            return self.peek_y(target);\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns the expected value of a qubit's Y observable.\n\n            Because the simulator's state is always a stabilizer state, the expectation will\n            always be exactly -1, 0, or +1.\n\n            This is a non-physical operation.\n            It reports information about the quantum state without disturbing it.\n\n            Args:\n                target: The qubit to analyze.\n\n            Returns:\n                +1: Qubit is in the |i> state.\n                -1: Qubit is in the |-i> state.\n                0: Qubit is in some other state.\n\n            Example:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_z(0)\n                >>> s.peek_y(0)\n                0\n                >>> s.reset_y(0)\n                >>> s.peek_y(0)\n                1\n                >>> s.z(0)\n                >>> s.peek_y(0)\n                -1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"peek_z\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, uint32_t target) -> int8_t {\n            self.ensure_large_enough_for_qubits(target + 1);\n            return self.peek_z(target);\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns the expected value of a qubit's Z observable.\n\n            Because the simulator's state is always a stabilizer state, the expectation will\n            always be exactly -1, 0, or +1.\n\n            This is a non-physical operation.\n            It reports information about the quantum state without disturbing it.\n\n            Args:\n                target: The qubit to analyze.\n\n            Returns:\n                +1: Qubit is in the |0> state.\n                -1: Qubit is in the |1> state.\n                0: Qubit is in some other state.\n\n            Example:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.reset_x(0)\n                >>> s.peek_z(0)\n                0\n                >>> s.reset_z(0)\n                >>> s.peek_z(0)\n                1\n                >>> s.x(0)\n                >>> s.peek_z(0)\n                -1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"peek_bloch\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, size_t target) {\n            self.ensure_large_enough_for_qubits(target + 1);\n            return FlexPauliString(self.peek_bloch(target));\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns the state of the qubit as a single-qubit stim.PauliString stabilizer.\n\n            This is a non-physical operation. It reports information about the qubit without\n            disturbing it.\n\n            Args:\n                target: The qubit to peek at.\n\n            Returns:\n                stim.PauliString(\"I\"):\n                    The qubit is entangled. Its bloch vector is x=y=z=0.\n                stim.PauliString(\"+Z\"):\n                    The qubit is in the |0> state. Its bloch vector is z=+1, x=y=0.\n                stim.PauliString(\"-Z\"):\n                    The qubit is in the |1> state. Its bloch vector is z=-1, x=y=0.\n                stim.PauliString(\"+Y\"):\n                    The qubit is in the |i> state. Its bloch vector is y=+1, x=z=0.\n                stim.PauliString(\"-Y\"):\n                    The qubit is in the |-i> state. Its bloch vector is y=-1, x=z=0.\n                stim.PauliString(\"+X\"):\n                    The qubit is in the |+> state. Its bloch vector is x=+1, y=z=0.\n                stim.PauliString(\"-X\"):\n                    The qubit is in the |-> state. Its bloch vector is x=-1, y=z=0.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.peek_bloch(0)\n                stim.PauliString(\"+Z\")\n                >>> s.x(0)\n                >>> s.peek_bloch(0)\n                stim.PauliString(\"-Z\")\n                >>> s.h(0)\n                >>> s.peek_bloch(0)\n                stim.PauliString(\"-X\")\n                >>> s.sqrt_x(1)\n                >>> s.peek_bloch(1)\n                stim.PauliString(\"-Y\")\n                >>> s.cz(0, 1)\n                >>> s.peek_bloch(0)\n                stim.PauliString(\"+_\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"peek_observable_expectation\",\n        [](const TableauSimulator<MAX_BITWORD_WIDTH> &self, const FlexPauliString &observable) -> int8_t {\n            if (observable.imag) {\n                throw std::invalid_argument(\n                    \"Observable isn't Hermitian; it has imaginary sign. Need observable.sign in [1, -1].\");\n            }\n            return self.peek_observable_expectation(observable.value);\n        },\n        pybind11::arg(\"observable\"),\n        clean_doc_string(R\"DOC(\n            Determines the expected value of an observable.\n\n            Because the simulator's state is always a stabilizer state, the expectation will\n            always be exactly -1, 0, or +1.\n\n            This is a non-physical operation.\n            It reports information about the quantum state without disturbing it.\n\n            Args:\n                observable: The observable to determine the expected value of.\n                    This observable must have a real sign, not an imaginary sign.\n\n            Returns:\n                +1: Observable will be deterministically false when measured.\n                -1: Observable will be deterministically true when measured.\n                0: Observable will be random when measured.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.peek_observable_expectation(stim.PauliString(\"+Z\"))\n                1\n                >>> s.peek_observable_expectation(stim.PauliString(\"+X\"))\n                0\n                >>> s.peek_observable_expectation(stim.PauliString(\"-Z\"))\n                -1\n\n                >>> s.do(stim.Circuit('''\n                ...     H 0\n                ...     CNOT 0 1\n                ... '''))\n                >>> queries = ['XX', 'YY', 'ZZ', '-ZZ', 'ZI', 'II', 'IIZ']\n                >>> for q in queries:\n                ...     print(q, s.peek_observable_expectation(stim.PauliString(q)))\n                XX 1\n                YY -1\n                ZZ 1\n                -ZZ -1\n                ZI 0\n                II 1\n                IIZ 1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"measure_observable\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self,\n           const FlexPauliString &observable,\n           double flip_probability) -> bool {\n            if (observable.imag) {\n                throw std::invalid_argument(\n                    \"Observable isn't Hermitian; it has imaginary sign. Need observable.sign in [1, -1].\");\n            }\n            return self.measure_pauli_string(observable.value, flip_probability);\n        },\n        pybind11::arg(\"observable\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"flip_probability\") = 0.0,\n        clean_doc_string(R\"DOC(\n            Measures an pauli string observable, as if by an MPP instruction.\n\n            Args:\n                observable: The observable to measure, specified as a stim.PauliString.\n                flip_probability: Probability of the recorded measurement result being\n                    flipped.\n\n            Returns:\n                The result of the measurement.\n\n                The result is also recorded into the measurement record.\n\n            Raises:\n                ValueError: The given pauli string isn't Hermitian, or the given probability\n                    isn't a valid probability.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.h(0)\n                >>> s.cnot(0, 1)\n\n                >>> s.measure_observable(stim.PauliString(\"XX\"))\n                False\n\n                >>> s.measure_observable(stim.PauliString(\"YY\"))\n                True\n\n                >>> s.measure_observable(stim.PauliString(\"-ZZ\"))\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"postselect_observable\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const FlexPauliString &observable, bool desired_value) {\n            if (observable.imag) {\n                throw std::invalid_argument(\n                    \"Observable isn't Hermitian; it has imaginary sign. Need observable.sign in [1, -1].\");\n            }\n            self.postselect_observable(observable.value, desired_value);\n        },\n        pybind11::arg(\"observable\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"desired_value\") = false,\n        clean_doc_string(R\"DOC(\n            Projects into a desired observable, or raises an exception if it was impossible.\n\n            Postselecting an observable forces it to collapse to a specific eigenstate,\n            as if it was measured and that state was the result of the measurement.\n\n            Args:\n                observable: The observable to postselect, specified as a pauli string.\n                    The pauli string's sign must be -1 or +1 (not -i or +i).\n                desired_value:\n                    False (default): Postselect into the +1 eigenstate of the observable.\n                    True: Postselect into the -1 eigenstate of the observable.\n\n            Raises:\n                ValueError:\n                    The given observable had an imaginary sign.\n                    OR\n                    The postselection was impossible. The observable was in the opposite\n                    eigenstate, so measuring it would never ever return the desired result.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.postselect_observable(stim.PauliString(\"+XX\"))\n                >>> s.postselect_observable(stim.PauliString(\"+ZZ\"))\n                >>> s.peek_observable_expectation(stim.PauliString(\"+YY\"))\n                -1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"measure\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, uint32_t target) {\n            self.ensure_large_enough_for_qubits(target + 1);\n            GateTarget g{target};\n            self.do_MZ(CircuitInstruction{GateType::M, {}, &g, \"\"});\n            return (bool)self.measurement_record.storage.back();\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Measures a single qubit.\n\n            Unlike the other methods on TableauSimulator, this one does not broadcast\n            over multiple targets. This is to avoid returning a list, which would\n            create a pitfall where typing `if sim.measure(qubit)` would be a bug.\n\n            To measure multiple qubits, use `TableauSimulator.measure_many`.\n\n            Args:\n                target: The index of the qubit to measure.\n\n            Returns:\n                The measurement result as a bool.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.x(1)\n                >>> s.measure(0)\n                False\n                >>> s.measure(1)\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"measure_many\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::args &args) {\n            auto converted_args =\n                build_single_qubit_gate_instruction_ensure_size<MAX_BITWORD_WIDTH>(self, GateType::M, args);\n            self.do_MZ(converted_args);\n            auto e = self.measurement_record.storage.end();\n            return std::vector<bool>(e - converted_args.targets.size(), e);\n        },\n        clean_doc_string(R\"DOC(\n            Measures multiple qubits.\n\n            Args:\n                *targets: The indices of the qubits to measure.\n\n            Returns:\n                The measurement results as a list of bools.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.x(1)\n                >>> s.measure_many(0, 1)\n                [False, True]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"postselect_x\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::object &targets, bool desired_value) {\n            auto gate_targets = arg_to_qubit_or_qubits<MAX_BITWORD_WIDTH>(self, targets);\n            self.postselect_x(gate_targets, desired_value);\n        },\n        pybind11::arg(\"targets\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"desired_value\"),\n        clean_doc_string(R\"DOC(\n            @signature def postselect_x(self, targets: Union[int, Iterable[int]], *, desired_value: bool) -> None:\n            Postselects qubits in the X basis, or raises an exception.\n\n            Postselecting a qubit forces it to collapse to a specific state, as\n            if it was measured and that state was the result of the measurement.\n\n            Args:\n                targets: The qubit index or indices to postselect.\n                desired_value:\n                    False: postselect targets into the |+> state.\n                    True: postselect targets into the |-> state.\n\n            Raises:\n                ValueError:\n                    The postselection failed. One of the qubits was in a state\n                    orthogonal to the desired state, so it was literally\n                    impossible for a measurement of the qubit to return the\n                    desired result.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.peek_x(0)\n                0\n                >>> s.postselect_x(0, desired_value=False)\n                >>> s.peek_x(0)\n                1\n                >>> s.h(0)\n                >>> s.peek_x(0)\n                0\n                >>> s.postselect_x(0, desired_value=True)\n                >>> s.peek_x(0)\n                -1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"postselect_y\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::object &targets, bool desired_value) {\n            auto gate_targets = arg_to_qubit_or_qubits<MAX_BITWORD_WIDTH>(self, targets);\n            self.postselect_y(gate_targets, desired_value);\n        },\n        pybind11::arg(\"targets\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"desired_value\"),\n        clean_doc_string(R\"DOC(\n            @signature def postselect_y(self, targets: Union[int, Iterable[int]], *, desired_value: bool) -> None:\n            Postselects qubits in the Y basis, or raises an exception.\n\n            Postselecting a qubit forces it to collapse to a specific state, as\n            if it was measured and that state was the result of the measurement.\n\n            Args:\n                targets: The qubit index or indices to postselect.\n                desired_value:\n                    False: postselect targets into the |i> state.\n                    True: postselect targets into the |-i> state.\n\n            Raises:\n                ValueError:\n                    The postselection failed. One of the qubits was in a state\n                    orthogonal to the desired state, so it was literally\n                    impossible for a measurement of the qubit to return the\n                    desired result.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.peek_y(0)\n                0\n                >>> s.postselect_y(0, desired_value=False)\n                >>> s.peek_y(0)\n                1\n                >>> s.reset_x(0)\n                >>> s.peek_y(0)\n                0\n                >>> s.postselect_y(0, desired_value=True)\n                >>> s.peek_y(0)\n                -1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"postselect_z\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const pybind11::object &targets, bool desired_value) {\n            auto gate_targets = arg_to_qubit_or_qubits<MAX_BITWORD_WIDTH>(self, targets);\n            self.postselect_z(gate_targets, desired_value);\n        },\n        pybind11::arg(\"targets\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"desired_value\"),\n        clean_doc_string(R\"DOC(\n            @signature def postselect_z(self, targets: Union[int, Iterable[int]], *, desired_value: bool) -> None:\n            Postselects qubits in the Z basis, or raises an exception.\n\n            Postselecting a qubit forces it to collapse to a specific state, as if it was\n            measured and that state was the result of the measurement.\n\n            Args:\n                targets: The qubit index or indices to postselect.\n                desired_value:\n                    False: postselect targets into the |0> state.\n                    True: postselect targets into the |1> state.\n\n            Raises:\n                ValueError:\n                    The postselection failed. One of the qubits was in a state\n                    orthogonal to the desired state, so it was literally\n                    impossible for a measurement of the qubit to return the\n                    desired result.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.h(0)\n                >>> s.peek_z(0)\n                0\n                >>> s.postselect_z(0, desired_value=False)\n                >>> s.peek_z(0)\n                1\n                >>> s.h(0)\n                >>> s.peek_z(0)\n                0\n                >>> s.postselect_z(0, desired_value=True)\n                >>> s.peek_z(0)\n                -1\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"num_qubits\",\n        [](const TableauSimulator<MAX_BITWORD_WIDTH> &self) -> size_t {\n            return self.inv_state.num_qubits;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of qubits currently being tracked by the simulator.\n\n            Note that the number of qubits being tracked will implicitly increase if qubits\n            beyond the current limit are touched. Untracked qubits are always assumed to be\n            in the |0> state.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> s.num_qubits\n                0\n                >>> s.h(2)\n                >>> s.num_qubits\n                3\n        )DOC\")\n            .data());\n\n    c.def(\n        \"set_num_qubits\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, uint32_t new_num_qubits) {\n            self.set_num_qubits(new_num_qubits);\n        },\n        pybind11::arg(\"new_num_qubits\"),\n        clean_doc_string(R\"DOC(\n            Resizes the simulator's internal state.\n\n            This forces the simulator's internal state to track exactly the qubits whose\n            indices are in `range(new_num_qubits)`.\n\n            Note that untracked qubits are always assumed to be in the |0> state. Therefore,\n            calling this method will effectively force any qubit whose index is outside\n            `range(new_num_qubits)` to be reset to |0>.\n\n            Note that this method does not prevent future operations from implicitly\n            expanding the size of the tracked state (e.g. setting the number of qubits to 5\n            will not prevent a Hadamard from then being applied to qubit 100, increasing the\n            number of qubits back to 101).\n\n            Args:\n                new_num_qubits: The length of the range of qubits the internal simulator\n                    should be tracking.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> len(s.current_inverse_tableau())\n                0\n\n                >>> s.set_num_qubits(5)\n                >>> len(s.current_inverse_tableau())\n                5\n\n                >>> s.x(0, 1, 2, 3)\n                >>> s.set_num_qubits(2)\n                >>> s.measure_many(0, 1, 2, 3)\n                [True, True, False, False]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"set_inverse_tableau\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, const Tableau<MAX_BITWORD_WIDTH> &new_inverse_tableau) {\n            self.inv_state = new_inverse_tableau;\n        },\n        pybind11::arg(\"new_inverse_tableau\"),\n        clean_doc_string(R\"DOC(\n            Overwrites the simulator's internal state with the given inverse tableau.\n\n            The inverse tableau specifies how Pauli product observables of qubits at the\n            current time transform into equivalent Pauli product observables at the\n            beginning of time, when all qubits were in the |0> state. For example, if the Z\n            observable on qubit 5 maps to a product of Z observables at the start of time\n            then a Z basis measurement on qubit 5 will be deterministic and equal to the\n            sign of the product. Whereas if it mapped to a product of observables including\n            an X or a Y then the Z basis measurement would be random.\n\n            Any qubits not within the length of the tableau are implicitly in the |0> state.\n\n            Args:\n                new_inverse_tableau: The tableau to overwrite the internal state with.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n                >>> t = stim.Tableau.random(4)\n                >>> s.set_inverse_tableau(t)\n                >>> s.current_inverse_tableau() == t\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"copy\",\n        [](const TableauSimulator<MAX_BITWORD_WIDTH> &self, bool copy_rng, pybind11::object &seed) {\n            if (copy_rng && !seed.is_none()) {\n                throw std::invalid_argument(\"seed and copy_rng are incompatible\");\n            }\n\n            if (!copy_rng || !seed.is_none()) {\n                TableauSimulator<MAX_BITWORD_WIDTH> copy_with_new_rng(self, make_py_seeded_rng(seed));\n                return copy_with_new_rng;\n            }\n\n            TableauSimulator<MAX_BITWORD_WIDTH> copy = self;\n            return copy;\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"copy_rng\") = false,\n        pybind11::arg(\"seed\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def copy(self, *, copy_rng: bool = False, seed: Optional[int] = None) -> stim.TableauSimulator:\n            Returns a simulator with the same internal state, except perhaps its prng.\n\n            Args:\n                copy_rng: By default, new simulator's prng is reinitialized with a random\n                    seed. However, one can set this argument to True in order to have the\n                    prng state copied together with the rest of the original simulator's\n                    state. Consequently, in this case the two simulators will produce the\n                    same measurement outcomes for the same quantum circuits.  If both seed\n                    and copy_rng are set, an exception is raised. Defaults to False.\n                seed: PARTIALLY determines simulation results by deterministically seeding\n                    the random number generator.\n\n                    Must be None or an integer in range(2**64).\n\n                    Defaults to None. When None, the prng state is either copied from the\n                    original simulator or reseeded from system entropy, depending on the\n                    copy_rng argument.\n\n                    When set to an integer, making the exact same series calls on the exact\n                    same machine with the exact same version of Stim will produce the exact\n                    same simulation results.\n\n                    CAUTION: simulation results *WILL NOT* be consistent between versions of\n                    Stim. This restriction is present to make it possible to have future\n                    optimizations to the random sampling, and is enforced by introducing\n                    intentional differences in the seeding strategy from version to version.\n\n                    CAUTION: simulation results *MAY NOT* be consistent across machines that\n                    differ in the width of supported SIMD instructions. For example, using\n                    the same seed on a machine that supports AVX instructions and one that\n                    only supports SSE instructions may produce different simulation results.\n\n                    CAUTION: simulation results *MAY NOT* be consistent if you vary how the\n                    circuit is executed. For example, reordering whether a reset on one\n                    qubit happens before or after a reset on another qubit can result in\n                    different measurement results being observed starting from the same\n                    seed.\n\n            Examples:\n                >>> import stim\n\n                >>> s1 = stim.TableauSimulator()\n                >>> s1.set_inverse_tableau(stim.Tableau.random(1))\n                >>> s2 = s1.copy()\n                >>> s2 is s1\n                False\n                >>> s2.current_inverse_tableau() == s1.current_inverse_tableau()\n                True\n\n                >>> s1 = stim.TableauSimulator()\n                >>> s2 = s1.copy(copy_rng=True)\n                >>> s1.h(0)\n                >>> s2.h(0)\n                >>> assert s1.measure(0) == s2.measure(0)\n\n                >>> s = stim.TableauSimulator()\n                >>> def brute_force_post_select(qubit, desired_result):\n                ...     global s\n                ...     while True:\n                ...         s2 = s.copy()\n                ...         if s2.measure(qubit) == desired_result:\n                ...             s = s2\n                ...             break\n                >>> s.h(0)\n                >>> brute_force_post_select(qubit=0, desired_result=True)\n                >>> s.measure(0)\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"measure_kickback\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, uint32_t target) {\n            self.ensure_large_enough_for_qubits(target + 1);\n            auto result = self.measure_kickback_z({target});\n            if (result.second.num_qubits == 0) {\n                return pybind11::make_tuple(result.first, pybind11::none());\n            }\n            return pybind11::make_tuple(result.first, FlexPauliString(result.second));\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Measures a qubit and returns the result as well as its Pauli kickback (if any).\n\n            The \"Pauli kickback\" of a stabilizer circuit measurement is a set of Pauli\n            operations that flip the post-measurement system state between the two possible\n            post-measurement states. For example, consider measuring one of the qubits in\n            the state |00>+|11> in the Z basis. If the measurement result is False, then the\n            system projects into the state |00>. If the measurement result is True, then the\n            system projects into the state |11>. Applying a Pauli X operation to both qubits\n            flips between |00> and |11>. Therefore the Pauli kickback of the measurement is\n            `stim.PauliString(\"XX\")`. Note that there are often many possible equivalent\n            Pauli kickbacks. For example, if in the previous example there was a third qubit\n            in the |0> state, then both `stim.PauliString(\"XX_\")` and\n            `stim.PauliString(\"XXZ\")` are valid kickbacks.\n\n            Measurements with deterministic results don't have a Pauli kickback.\n\n            Args:\n                target: The index of the qubit to measure.\n\n            Returns:\n                A (result, kickback) tuple.\n                The result is a bool containing the measurement's output.\n                The kickback is either None (meaning the measurement was deterministic) or a\n                stim.PauliString (meaning the measurement was random, and the operations in\n                the Pauli string flip between the two possible post-measurement states).\n\n            Examples:\n                >>> import stim\n                >>> s = stim.TableauSimulator()\n\n                >>> s.measure_kickback(0)\n                (False, None)\n\n                >>> s.h(0)\n                >>> s.measure_kickback(0)[1]\n                stim.PauliString(\"+X\")\n\n                >>> def pseudo_post_select(qubit, desired_result):\n                ...     m, kick = s.measure_kickback(qubit)\n                ...     if m != desired_result:\n                ...         if kick is None:\n                ...             raise ValueError(\"Post-selected the impossible!\")\n                ...         s.do(kick)\n                >>> s = stim.TableauSimulator()\n                >>> s.h(0)\n                >>> s.cnot(0, 1)\n                >>> s.cnot(0, 2)\n                >>> pseudo_post_select(qubit=2, desired_result=True)\n                >>> s.measure_many(0, 1, 2)\n                [True, True, True]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"set_state_from_stabilizers\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self,\n           pybind11::object &stabilizers,\n           bool allow_redundant,\n           bool allow_underconstrained) {\n            std::vector<PauliString<MAX_BITWORD_WIDTH>> converted_stabilizers;\n            for (const auto &stabilizer : stabilizers) {\n                const FlexPauliString &p = pybind11::cast<FlexPauliString>(stabilizer);\n                if (p.imag) {\n                    throw std::invalid_argument(\"Stabilizers can't have imaginary sign.\");\n                }\n                converted_stabilizers.push_back(p.value);\n            }\n            self.inv_state = stabilizers_to_tableau<MAX_BITWORD_WIDTH>(\n                converted_stabilizers, allow_redundant, allow_underconstrained, true);\n        },\n        pybind11::arg(\"stabilizers\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"allow_redundant\") = false,\n        pybind11::arg(\"allow_underconstrained\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def set_state_from_stabilizers(self, stabilizers: Iterable[stim.PauliString], *, allow_redundant: bool = False, allow_underconstrained: bool = False) -> None:\n            Sets the tableau simulator's state to a state satisfying the given stabilizers.\n\n            The old quantum state is completely overwritten, even if the new state is\n            underconstrained by the given stabilizers. The number of qubits is changed to\n            exactly match the number of qubits in the longest given stabilizer.\n\n            Args:\n                stabilizers: A list of `stim.PauliString`s specifying the stabilizers that\n                    the new state must have. It is permitted for stabilizers to have\n                    different lengths. All stabilizers are padded up to the length of the\n                    longest stabilizer by appending identity terms.\n                allow_redundant: Defaults to False. If set to False, then the given\n                    stabilizers must all be independent. If any one of them is a product of\n                    the others (including the empty product), an exception will be raised.\n                    If set to True, then redundant stabilizers are simply ignored.\n                allow_underconstrained: Defaults to False. If set to False, then the given\n                    stabilizers must form a complete set of generators. They must exactly\n                    specify the desired stabilizer state, with no degrees of freedom left\n                    over. For an n-qubit state there must be n independent stabilizers. If\n                    set to True, then there can be leftover degrees of freedom which can be\n                    set arbitrarily.\n\n            Returns:\n                Nothing. Mutates the states of the simulator to match the desired\n                stabilizers.\n\n                Guarantees that self.current_inverse_tableau().inverse_z_output(k) will be\n                equal to the k'th independent stabilizer from the `stabilizers` argument.\n\n            Raises:\n                ValueError:\n                    A stabilizer is redundant but allow_redundant=True wasn't set.\n                    OR\n                    The given stabilizers are contradictory (e.g. \"+Z\" and \"-Z\" both\n                    specified).\n                    OR\n                    The given stabilizers anticommute (e.g. \"+Z\" and \"+X\" both specified).\n                    OR\n                    The stabilizers left behind a degree of freedom but\n                    allow_underconstrained=True wasn't set.\n                    OR\n                    A stabilizer has an imaginary sign (i or -i).\n\n            Examples:\n\n                >>> import stim\n                >>> tab_sim = stim.TableauSimulator()\n                >>> tab_sim.set_state_from_stabilizers([\n                ...     stim.PauliString(\"XX\"),\n                ...     stim.PauliString(\"ZZ\"),\n                ... ])\n                >>> tab_sim.current_inverse_tableau().inverse()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z_\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+XX\"),\n                        stim.PauliString(\"+ZZ\"),\n                    ],\n                )\n\n                >>> tab_sim.set_state_from_stabilizers([\n                ...     stim.PauliString(\"XX_\"),\n                ...     stim.PauliString(\"ZZ_\"),\n                ...     stim.PauliString(\"-YY_\"),\n                ...     stim.PauliString(\"\"),\n                ... ], allow_underconstrained=True, allow_redundant=True)\n                >>> tab_sim.current_inverse_tableau().inverse()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z__\"),\n                        stim.PauliString(\"+_X_\"),\n                        stim.PauliString(\"+__X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+XX_\"),\n                        stim.PauliString(\"+ZZ_\"),\n                        stim.PauliString(\"+__Z\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def(\n        \"set_state_from_state_vector\",\n        [](TableauSimulator<MAX_BITWORD_WIDTH> &self, pybind11::object &state_vector, std::string_view endian) {\n            bool little_endian;\n            if (endian == \"little\") {\n                little_endian = true;\n            } else if (endian == \"big\") {\n                little_endian = false;\n            } else {\n                throw std::invalid_argument(\"endian not in ['little', 'big']\");\n            }\n\n            std::vector<std::complex<float>> v;\n            for (const auto &obj : state_vector) {\n                v.push_back(pybind11::cast<std::complex<float>>(obj));\n            }\n\n            self.inv_state = circuit_to_tableau<MAX_BITWORD_WIDTH>(\n                                 stabilizer_state_vector_to_circuit(v, little_endian), false, false, false)\n                                 .inverse();\n        },\n        pybind11::arg(\"state_vector\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"endian\"),\n        clean_doc_string(R\"DOC(\n            @signature def set_state_from_state_vector(self, state_vector: Iterable[float], *, endian: Literal[\"little\", \"big\"]) -> None:\n            Sets the simulator's state to a superposition specified by an amplitude vector.\n\n            Args:\n                state_vector: A list of complex amplitudes specifying a superposition. The\n                    vector must correspond to a state that is reachable using Clifford\n                    operations, and must be normalized (i.e. it must be a unit vector).\n                endian:\n                    \"little\": state vector is in little endian order, where higher index\n                        qubits correspond to larger changes in the state index.\n                    \"big\": state vector is in big endian order, where higher index qubits\n                        correspond to smaller changes in the state index.\n\n            Returns:\n                Nothing. Mutates the states of the simulator to match the desired state.\n\n            Raises:\n                ValueError:\n                    The given state vector isn't a list of complex values specifying a\n                    stabilizer state.\n                    OR\n                    The given endian value isn't 'little' or 'big'.\n\n            Examples:\n\n                >>> import stim\n                >>> tab_sim = stim.TableauSimulator()\n                >>> tab_sim.set_state_from_state_vector([\n                ...     0.5**0.5,\n                ...     0.5**0.5 * 1j,\n                ... ], endian='little')\n                >>> tab_sim.current_inverse_tableau().inverse()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+Y\"),\n                    ],\n                )\n                >>> tab_sim.set_state_from_state_vector([\n                ...     0.5**0.5,\n                ...     0,\n                ...     0,\n                ...     0.5**0.5,\n                ... ], endian='little')\n                >>> tab_sim.current_inverse_tableau().inverse()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z_\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+XX\"),\n                        stim.PauliString(\"+ZZ\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/simulators/tableau_simulator.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_SIMULATORS_TABLEAU_SIMULATOR_PYBIND_H\n#define _STIM_SIMULATORS_TABLEAU_SIMULATOR_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/simulators/tableau_simulator.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::TableauSimulator<stim::MAX_BITWORD_WIDTH>> pybind_tableau_simulator(pybind11::module &m);\nvoid pybind_tableau_simulator_methods(\n    pybind11::module &m, pybind11::class_<stim::TableauSimulator<stim::MAX_BITWORD_WIDTH>> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/tableau_simulator.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/tableau_simulator.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/vector_simulator.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nstatic std::vector<GateTarget> qubit_targets(const std::vector<uint32_t> &targets) {\n    std::vector<GateTarget> result;\n    for (uint32_t t : targets) {\n        result.push_back(GateTarget::qubit(t & ~TARGET_INVERTED_BIT, t & TARGET_INVERTED_BIT));\n    }\n    return result;\n}\nstruct OpDat {\n    std::vector<GateTarget> targets;\n    OpDat(uint32_t u) : targets(qubit_targets({u})) {\n    }\n    OpDat(std::vector<uint32_t> u) : targets(qubit_targets(u)) {\n    }\n    operator CircuitInstruction() const {\n        return {(GateType)0, {}, targets, \"\"};\n    }\n};\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, identity, {\n    auto s = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 1);\n    ASSERT_EQ(s.measurement_record.storage, (std::vector<bool>{}));\n    s.do_MZ({GateType::Z, {}, qubit_targets({0}), \"\"});\n    ASSERT_EQ(s.measurement_record.storage, (std::vector<bool>{false}));\n    s.do_MZ({GateType::Z, {}, qubit_targets({0 | TARGET_INVERTED_BIT}), \"\"});\n    ASSERT_EQ(s.measurement_record.storage, (std::vector<bool>{false, true}));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, bit_flip, {\n    auto s = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 1);\n    s.do_H_XZ(OpDat(0));\n    s.do_SQRT_Z(OpDat(0));\n    s.do_SQRT_Z(OpDat(0));\n    s.do_H_XZ(OpDat(0));\n    s.do_MZ(OpDat(0));\n    s.do_X(OpDat(0));\n    s.do_MZ(OpDat(0));\n    ASSERT_EQ(s.measurement_record.storage, (std::vector<bool>{true, false}));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, identity2, {\n    auto s = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 2);\n    s.do_MZ(OpDat(0));\n    ASSERT_EQ(s.measurement_record.storage, (std::vector<bool>{false}));\n    s.do_MZ(OpDat(1));\n    ASSERT_EQ(s.measurement_record.storage, (std::vector<bool>{false, false}));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, bit_flip_2, {\n    auto s = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 2);\n    s.do_H_XZ(OpDat(0));\n    s.do_SQRT_Z(OpDat(0));\n    s.do_SQRT_Z(OpDat(0));\n    s.do_H_XZ(OpDat(0));\n    s.do_MZ(OpDat(0));\n    ASSERT_EQ(s.measurement_record.storage, (std::vector<bool>{true}));\n    s.do_MZ(OpDat(1));\n    ASSERT_EQ(s.measurement_record.storage, (std::vector<bool>{true, false}));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, epr, {\n    auto s = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 2);\n    s.do_H_XZ(OpDat(0));\n    s.do_ZCX(OpDat({0, 1}));\n    ASSERT_EQ(s.is_deterministic_z(0), false);\n    ASSERT_EQ(s.is_deterministic_z(1), false);\n    s.do_MZ(OpDat(0));\n    ASSERT_EQ(s.is_deterministic_z(0), true);\n    ASSERT_EQ(s.is_deterministic_z(1), true);\n    s.do_MZ(OpDat(1));\n    ASSERT_EQ(s.measurement_record.storage[0], s.measurement_record.storage[1]);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, big_determinism, {\n    auto s = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 1000);\n    s.do_H_XZ(OpDat(0));\n    s.do_H_YZ(OpDat(1));\n    ASSERT_FALSE(s.is_deterministic_z(0));\n    ASSERT_FALSE(s.is_deterministic_z(1));\n    ASSERT_TRUE(s.is_deterministic_x(0));\n    ASSERT_FALSE(s.is_deterministic_x(1));\n    ASSERT_FALSE(s.is_deterministic_y(0));\n    ASSERT_TRUE(s.is_deterministic_y(1));\n    for (size_t k = 2; k < 1000; k++) {\n        ASSERT_TRUE(s.is_deterministic_z(k));\n        ASSERT_FALSE(s.is_deterministic_x(k));\n        ASSERT_FALSE(s.is_deterministic_y(k));\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, phase_kickback_consume_s_state, {\n    for (size_t k = 0; k < 8; k++) {\n        auto s = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 2);\n        s.do_H_XZ(OpDat(1));\n        s.do_SQRT_Z(OpDat(1));\n        s.do_H_XZ(OpDat(0));\n        s.do_ZCX(OpDat({0, 1}));\n        ASSERT_EQ(s.is_deterministic_z(1), false);\n        s.do_MZ(OpDat(1));\n        auto v1 = s.measurement_record.storage.back();\n        if (v1) {\n            s.do_SQRT_Z(OpDat(0));\n            s.do_SQRT_Z(OpDat(0));\n        }\n        s.do_SQRT_Z(OpDat(0));\n        s.do_H_XZ(OpDat(0));\n        ASSERT_EQ(s.is_deterministic_z(0), true);\n        s.do_MZ(OpDat(0));\n        ASSERT_EQ(s.measurement_record.storage.back(), true);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, phase_kickback_preserve_s_state, {\n    auto s = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 2);\n\n    // Prepare S state.\n    s.do_H_XZ(OpDat(1));\n    s.do_SQRT_Z(OpDat(1));\n\n    // Prepare test input.\n    s.do_H_XZ(OpDat(0));\n\n    // Kickback.\n    s.do_ZCX(OpDat({0, 1}));\n    s.do_H_XZ(OpDat(1));\n    s.do_ZCX(OpDat({0, 1}));\n    s.do_H_XZ(OpDat(1));\n\n    // Check.\n    s.do_SQRT_Z(OpDat(0));\n    s.do_H_XZ(OpDat(0));\n    ASSERT_EQ(s.is_deterministic_z(0), true);\n    s.do_MZ(OpDat(0));\n    ASSERT_EQ(s.measurement_record.storage.back(), true);\n    s.do_SQRT_Z(OpDat(1));\n    s.do_H_XZ(OpDat(1));\n    ASSERT_EQ(s.is_deterministic_z(1), true);\n    s.do_MZ(OpDat(1));\n    ASSERT_EQ(s.measurement_record.storage.back(), true);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, kickback_vs_stabilizer, {\n    auto sim = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 3);\n    sim.do_H_XZ(OpDat(2));\n    sim.do_ZCX(OpDat({2, 0}));\n    sim.do_ZCX(OpDat({2, 1}));\n    sim.do_SQRT_Z(OpDat(0));\n    sim.do_SQRT_Z(OpDat(1));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_H_XZ(OpDat(1));\n    sim.do_H_XZ(OpDat(2));\n    ASSERT_EQ(\n        sim.inv_state.str(),\n        \"+-xz-xz-xz-\\n\"\n        \"| +- +- ++\\n\"\n        \"| ZY __ _X\\n\"\n        \"| __ ZY _X\\n\"\n        \"| XX XX XZ\");\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, s_state_distillation_low_depth, {\n    for (size_t reps = 0; reps < 10; reps++) {\n        auto sim = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 9);\n\n        std::vector<std::vector<uint8_t>> stabilizers = {\n            {0, 1, 2, 3},\n            {0, 1, 4, 5},\n            {0, 2, 4, 6},\n            {1, 2, 4, 7},\n        };\n        std::vector<std::unordered_map<std::string, std::vector<uint8_t>>> checks{\n            {{\"s\", {0}}, {\"q\", stabilizers[0]}},\n            {{\"s\", {1}}, {\"q\", stabilizers[1]}},\n            {{\"s\", {2}}, {\"q\", stabilizers[2]}},\n        };\n\n        std::vector<bool> stabilizer_measurements;\n        uint32_t anc = 8;\n        for (const auto &stabilizer : stabilizers) {\n            sim.do_H_XZ(OpDat(anc));\n            for (const auto &k : stabilizer) {\n                sim.do_ZCX(OpDat({anc, k}));\n            }\n            sim.do_H_XZ(OpDat(anc));\n            ASSERT_EQ(sim.is_deterministic_z(anc), false);\n            sim.do_MZ(OpDat(anc));\n            bool v = sim.measurement_record.storage.back();\n            if (v) {\n                sim.do_X(OpDat(anc));\n            }\n            stabilizer_measurements.push_back(v);\n        }\n\n        std::vector<bool> qubit_measurements;\n        for (size_t k = 0; k < 7; k++) {\n            sim.do_SQRT_Z(OpDat(k));\n            sim.do_H_XZ(OpDat(k));\n            sim.do_MZ(OpDat(k));\n            qubit_measurements.push_back(sim.measurement_record.storage.back());\n        }\n\n        bool sum = false;\n        for (auto e : stabilizer_measurements) {\n            sum ^= e;\n        }\n        for (auto e : qubit_measurements) {\n            sum ^= e;\n        }\n        if (sum) {\n            sim.do_Z(OpDat(7));\n        }\n\n        sim.do_SQRT_Z(OpDat(7));\n        sim.do_H_XZ(OpDat(7));\n        ASSERT_EQ(sim.is_deterministic_z(7), true);\n        sim.do_MZ(OpDat(7));\n        ASSERT_EQ(sim.measurement_record.storage.back(), false);\n\n        for (const auto &c : checks) {\n            bool r = false;\n            for (auto k : c.at(\"s\")) {\n                r ^= stabilizer_measurements[k];\n            }\n            for (auto k : c.at(\"q\")) {\n                r ^= qubit_measurements[k];\n            }\n            ASSERT_EQ(r, false);\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, s_state_distillation_low_space, {\n    for (size_t rep = 0; rep < 10; rep++) {\n        auto sim = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 5);\n\n        std::vector<std::vector<uint8_t>> phasors = {\n            {\n                0,\n            },\n            {\n                1,\n            },\n            {\n                2,\n            },\n            {0, 1, 2},\n            {0, 1, 3},\n            {0, 2, 3},\n            {1, 2, 3},\n        };\n\n        uint32_t anc = 4;\n        for (const auto &phasor : phasors) {\n            sim.do_H_XZ(OpDat(anc));\n            for (const auto &k : phasor) {\n                sim.do_ZCX(OpDat({anc, k}));\n            }\n            sim.do_H_XZ(OpDat(anc));\n            sim.do_SQRT_Z(OpDat(anc));\n            sim.do_H_XZ(OpDat(anc));\n            ASSERT_EQ(sim.is_deterministic_z(anc), false);\n            sim.do_MZ(OpDat(anc));\n            bool v = sim.measurement_record.storage.back();\n            if (v) {\n                for (const auto &k : phasor) {\n                    sim.do_X(OpDat(k));\n                }\n                sim.do_X(OpDat(anc));\n            }\n        }\n\n        for (size_t k = 0; k < 3; k++) {\n            ASSERT_EQ(sim.is_deterministic_z(k), true);\n            sim.do_MZ(OpDat(k));\n            ASSERT_EQ(sim.measurement_record.storage.back(), false);\n        }\n        sim.do_SQRT_Z(OpDat(3));\n        sim.do_H_XZ(OpDat(3));\n        ASSERT_EQ(sim.is_deterministic_z(3), true);\n        sim.do_MZ(OpDat(3));\n        ASSERT_EQ(sim.measurement_record.storage.back(), true);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, unitary_gates_consistent_with_tableau_data, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t = Tableau<W>::random(10, rng);\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 10);\n    for (const auto &gate : GATE_DATA.items) {\n        if (!gate.has_known_unitary_matrix()) {\n            continue;\n        }\n        sim.inv_state = t;\n\n        const auto &inverse_op_tableau = gate.inverse().tableau<W>();\n        if (inverse_op_tableau.num_qubits == 2) {\n            sim.do_gate({gate.id, {}, qubit_targets({7, 4}), \"\"});\n            t.inplace_scatter_prepend(inverse_op_tableau, {7, 4});\n        } else {\n            sim.do_gate({gate.id, {}, qubit_targets({5}), \"\"});\n            t.inplace_scatter_prepend(inverse_op_tableau, {5});\n        }\n        EXPECT_EQ(sim.inv_state, t) << gate.name;\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, certain_errors_consistent_with_gates, {\n    TableauSimulator<W> sim1(INDEPENDENT_TEST_RNG(), 2);\n    TableauSimulator<W> sim2(INDEPENDENT_TEST_RNG(), 2);\n    GateTarget targets[]{GateTarget{0}};\n    double p0 = 0.0;\n    double p1 = 1.0;\n    CircuitInstruction d0{(GateType)0, {&p0}, {targets}, \"\"};\n    CircuitInstruction d1{(GateType)0, {&p1}, {targets}, \"\"};\n\n    sim1.do_X_ERROR(d1);\n    sim2.do_X(d0);\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n    sim1.do_X_ERROR(d0);\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n\n    sim1.do_Y_ERROR(d1);\n    sim2.do_Y(d0);\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n    sim1.do_Y_ERROR(d0);\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n\n    sim1.do_Z_ERROR(d1);\n    sim2.do_Z(d0);\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n    sim1.do_Z_ERROR(d0);\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, simulate, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto results = TableauSimulator<W>::sample_circuit(\n        Circuit(\n            \"H 0\\n\"\n            \"CNOT 0 1\\n\"\n            \"M 0\\n\"\n            \"M 1\\n\"\n            \"M 2\\n\"),\n        rng);\n    ASSERT_EQ(results[0], results[1]);\n    ASSERT_EQ(results[2], false);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, simulate_reset, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto results = TableauSimulator<W>::sample_circuit(\n        Circuit(\n            \"X 0\\n\"\n            \"M 0\\n\"\n            \"R 0\\n\"\n            \"M 0\\n\"\n            \"R 0\\n\"\n            \"M 0\\n\"),\n        rng);\n    ASSERT_EQ(results[0], true);\n    ASSERT_EQ(results[1], false);\n    ASSERT_EQ(results[2], false);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, to_vector_sim, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim_tab(INDEPENDENT_TEST_RNG(), 2);\n    VectorSimulator sim_vec(2);\n    ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true));\n\n    sim_tab.do_X(OpDat(0));\n    sim_vec.apply(GateType::X, 0);\n    ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true));\n\n    sim_tab.do_H_XZ(OpDat(0));\n    sim_vec.apply(GateType::H, 0);\n    ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true));\n\n    sim_tab.do_SQRT_Z(OpDat(0));\n    sim_vec.apply(GateType::S, 0);\n    ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true));\n\n    sim_tab.do_ZCX(OpDat({0, 1}));\n    sim_vec.apply(GateType::CX, 0, 1);\n    ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true));\n\n    sim_tab.inv_state = Tableau<W>::random(10, rng);\n    sim_vec = sim_tab.to_vector_sim();\n    ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true));\n\n    sim_tab.do_gate({GateType::XCX, {}, qubit_targets({4, 7}), \"\"});\n    sim_vec.apply(GateType::XCX, 4, 7);\n    ASSERT_TRUE(sim_tab.to_vector_sim().approximate_equals(sim_vec, true));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector, {\n    auto v = TableauSimulator<W>(INDEPENDENT_TEST_RNG(), 0).to_state_vector(true);\n    ASSERT_EQ(v.size(), 1);\n    auto r = v[0].real();\n    auto i = v[0].imag();\n    ASSERT_LT(r * r + i * i - 1, 1e-4);\n\n    TableauSimulator<W> sim_tab(INDEPENDENT_TEST_RNG(), 3);\n    auto sim_vec = sim_tab.to_vector_sim();\n    VectorSimulator sim_vec2(3);\n    sim_vec2.state = sim_tab.to_state_vector(true);\n    ASSERT_TRUE(sim_vec.approximate_equals(sim_vec2, true));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector_endian, {\n    VectorSimulator sim_vec0(3);\n    VectorSimulator sim_vec2(3);\n    sim_vec0.apply(GateType::H, 0);\n    sim_vec2.apply(GateType::H, 2);\n\n    TableauSimulator<W> sim_tab(INDEPENDENT_TEST_RNG(), 3);\n    sim_tab.do_H_XZ(OpDat(2));\n\n    VectorSimulator cmp(3);\n    cmp.state = sim_tab.to_state_vector(true);\n    ASSERT_TRUE(cmp.approximate_equals(sim_vec2, true));\n    cmp.state = sim_tab.to_state_vector(false);\n    ASSERT_TRUE(cmp.approximate_equals(sim_vec0, true));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, to_state_vector_canonical, {\n    TableauSimulator<W> sim_tab(INDEPENDENT_TEST_RNG(), 3);\n    sim_tab.do_H_XZ(OpDat(2));\n    std::vector<float> expected;\n\n    auto actual = sim_tab.to_state_vector(true);\n    expected = {sqrtf(0.5), 0, 0, 0, sqrtf(0.5), 0, 0, 0};\n    ASSERT_EQ(actual.size(), expected.size());\n    for (size_t k = 0; k < 8; k++) {\n        ASSERT_LT(abs(actual[k] - expected[k]), 1e-4) << k;\n    }\n\n    actual = sim_tab.to_state_vector(false);\n    expected = {sqrtf(0.5), sqrtf(0.5), 0, 0, 0, 0, 0, 0};\n    ASSERT_EQ(actual.size(), expected.size());\n    for (size_t k = 0; k < 8; k++) {\n        ASSERT_LT(abs(actual[k] - expected[k]), 1e-4) << k;\n    }\n})\n\ntemplate <size_t W>\nbool vec_sim_corroborates_measurement_process(\n    const Tableau<W> &state, const std::vector<uint32_t> &measurement_targets) {\n    TableauSimulator<W> sim_tab(INDEPENDENT_TEST_RNG(), 2);\n    sim_tab.inv_state = state;\n    auto vec_sim = sim_tab.to_vector_sim();\n    sim_tab.do_MZ(OpDat(measurement_targets));\n    PauliString<W> buf(sim_tab.inv_state.num_qubits);\n    size_t k = 0;\n    for (auto t : measurement_targets) {\n        buf.zs[t] = true;\n        buf.sign = sim_tab.measurement_record.storage[k++];\n        float f = vec_sim.template project<W>(buf);\n        if (fabs(f - 0.5) > 1e-4 && fabsf(f - 1) > 1e-4) {\n            return false;\n        }\n        buf.zs[t] = false;\n    }\n    return true;\n}\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measurement_vs_vector_sim, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (size_t k = 0; k < 5; k++) {\n        auto state = Tableau<W>::random(2, rng);\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0}));\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {1}));\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 1}));\n    }\n    for (size_t k = 0; k < 5; k++) {\n        auto state = Tableau<W>::random(4, rng);\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 1}));\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {2, 1}));\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 1, 2, 3}));\n    }\n    {\n        auto state = Tableau<W>::random(8, rng);\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 1, 2, 3}));\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 6, 7}));\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {7, 3, 4}));\n        ASSERT_TRUE(vec_sim_corroborates_measurement_process(state, {0, 1, 2, 3, 4, 5, 6, 7}));\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, correlated_error, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> expected(5);\n\n    expected.clear();\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(0) X0 X1\n        ELSE_CORRELATED_ERROR(0) X1 X2\n        ELSE_CORRELATED_ERROR(0) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            rng),\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(1) X0 X1\n        ELSE_CORRELATED_ERROR(0) X1 X2\n        ELSE_CORRELATED_ERROR(0) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            rng),\n        expected);\n\n    expected.clear();\n    expected[1] = true;\n    expected[2] = true;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(0) X0 X1\n        ELSE_CORRELATED_ERROR(1) X1 X2\n        ELSE_CORRELATED_ERROR(0) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            rng),\n        expected);\n\n    expected.clear();\n    expected[2] = true;\n    expected[3] = true;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(0) X0 X1\n        ELSE_CORRELATED_ERROR(0) X1 X2\n        ELSE_CORRELATED_ERROR(1) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            rng),\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(1) X0 X1\n        ELSE_CORRELATED_ERROR(1) X1 X2\n        ELSE_CORRELATED_ERROR(0) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            rng),\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(1) X0 X1\n        ELSE_CORRELATED_ERROR(1) X1 X2\n        ELSE_CORRELATED_ERROR(1) X2 X3\n        M 0 1 2 3\n    )circuit\"),\n            rng),\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    expected[3] = true;\n    expected[4] = true;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        CORRELATED_ERROR(1) X0 X1\n        ELSE_CORRELATED_ERROR(1) X1 X2\n        ELSE_CORRELATED_ERROR(1) X2 X3\n        CORRELATED_ERROR(1) X3 X4\n        M 0 1 2 3 4\n    )circuit\"),\n            rng),\n        expected);\n\n    int hits[3]{};\n    size_t n = 5000;\n    for (size_t k = 0; k < n; k++) {\n        auto sample = TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n            CORRELATED_ERROR(0.5) X0\n            ELSE_CORRELATED_ERROR(0.25) X1\n            ELSE_CORRELATED_ERROR(0.75) X2\n            M 0 1 2\n        )circuit\"),\n            rng);\n        hits[0] += sample[0];\n        hits[1] += sample[1];\n        hits[2] += sample[2];\n    }\n    ASSERT_TRUE(0.45 * n < hits[0] && hits[0] < 0.55 * n);\n    ASSERT_TRUE((0.125 - 0.08) * n < hits[1] && hits[1] < (0.125 + 0.08) * n);\n    ASSERT_TRUE((0.28125 - 0.08) * n < hits[2] && hits[2] < (0.28125 + 0.08) * n);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, quantum_cannot_control_classical, {\n    auto rng = INDEPENDENT_TEST_RNG();\n\n    // Quantum controlling classical operation is not allowed.\n    ASSERT_THROW(\n        {\n            TableauSimulator<W>::sample_circuit(\n                Circuit(R\"circuit(\n            M 0\n            CNOT 1 rec[-1]\n        )circuit\"),\n                rng);\n        },\n        std::invalid_argument);\n    ASSERT_THROW(\n        {\n            TableauSimulator<W>::sample_circuit(\n                Circuit(R\"circuit(\n            M 0\n            CY 1 rec[-1]\n        )circuit\"),\n                rng);\n        },\n        std::invalid_argument);\n    ASSERT_THROW(\n        {\n            TableauSimulator<W>::sample_circuit(\n                Circuit(R\"circuit(\n            M 0\n            YCZ rec[-1] 1\n        )circuit\"),\n                rng);\n        },\n        std::invalid_argument);\n    ASSERT_THROW(\n        {\n            TableauSimulator<W>::sample_circuit(\n                Circuit(R\"circuit(\n            M 0\n            XCZ rec[-1] 1\n        )circuit\"),\n                rng);\n        },\n        std::invalid_argument);\n    ASSERT_THROW(\n        {\n            TableauSimulator<W>::sample_circuit(\n                Circuit(R\"circuit(\n            M 0\n            SWAP 1 rec[-1]\n        )circuit\"),\n                rng);\n        },\n        std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, classical_can_control_quantum, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> expected(5);\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        M !0\n        CX rec[-1] 1\n        M 1\n    )circuit\"),\n            rng),\n        expected);\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        M !0\n        CY rec[-1] 1\n        M 1\n    )circuit\"),\n            rng),\n        expected);\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        M !0\n        XCZ 1 rec[-1]\n        M 1\n    )circuit\"),\n            rng),\n        expected);\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        M !0\n        YCZ 1 rec[-1]\n        M 1\n    )circuit\"),\n            rng),\n        expected);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, classical_control_cases, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> expected(5);\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        M !0\n        H 1\n        CZ rec[-1] 1\n        H 1\n        M 1\n    )circuit\"),\n            rng),\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = true;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        M !0\n        CY rec[-1] 1\n        M 1\n    )circuit\"),\n            rng),\n        expected);\n\n    expected.clear();\n    expected[0] = false;\n    expected[1] = false;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        M 0\n        CX rec[-1] 1\n        M 1\n    )circuit\"),\n            rng),\n        expected);\n\n    expected.clear();\n    expected[0] = true;\n    expected[1] = false;\n    expected[2] = true;\n    expected[3] = false;\n    expected[4] = false;\n    ASSERT_EQ(\n        TableauSimulator<W>::sample_circuit(\n            Circuit(R\"circuit(\n        X 0\n        M 0\n        R 0\n        M 0\n        CX rec[-2] 1\n        CX rec[-1] 2\n        M 1 2 3\n    )circuit\"),\n            rng),\n        expected);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, mr_repeated_target, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    simd_bits<W> expected(2);\n    expected[0] = true;\n    auto r = TableauSimulator<W>::sample_circuit(Circuit(\"X 0\\nMR 0 0\"), rng);\n    ASSERT_EQ(r, expected);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, peek_bloch, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 3);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"+Z\"));\n\n    sim.do_H_XZ(OpDat(0));\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"+Z\"));\n\n    sim.do_X(OpDat(1));\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"+Z\"));\n\n    sim.do_H_YZ(OpDat(2));\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"+Y\"));\n\n    sim.do_X(OpDat(0));\n    sim.do_X(OpDat(1));\n    sim.do_X(OpDat(2));\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"-Y\"));\n\n    sim.do_Y(OpDat(0));\n    sim.do_Y(OpDat(1));\n    sim.do_Y(OpDat(2));\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"-Y\"));\n\n    sim.do_ZCZ(OpDat({0, 1}));\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"-Y\"));\n\n    sim.do_ZCZ(OpDat({1, 2}));\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"+Y\"));\n\n    sim.do_ZCZ(OpDat({0, 2}));\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+I\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"+I\"));\n\n    sim.do_X(OpDat(0));\n    sim.do_X(OpDat(1));\n    sim.do_X(OpDat(2));\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+I\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(sim.peek_bloch(2), PauliString<W>::from_str(\"+I\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, paulis, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim1(INDEPENDENT_TEST_RNG(), 300);\n    TableauSimulator<W> sim2(INDEPENDENT_TEST_RNG(), 300);\n    sim1.inv_state = Tableau<W>::random(300, rng);\n    sim2.inv_state = sim1.inv_state;\n\n    sim1.paulis(PauliString<W>(300));\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n    sim1.paulis(PauliString<W>(5));\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n    sim1.paulis(PauliString<W>(0));\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n\n    sim1.paulis(PauliString<W>::from_str(\"IXYZ\"));\n    sim2.do_X(OpDat(1));\n    sim2.do_Y(OpDat(2));\n    sim2.do_Z(OpDat(3));\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, set_num_qubits, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim1(INDEPENDENT_TEST_RNG(), 10);\n    TableauSimulator<W> sim2(INDEPENDENT_TEST_RNG(), 10);\n    sim1.inv_state = Tableau<W>::random(10, rng);\n    sim2.inv_state = sim1.inv_state;\n\n    sim1.set_num_qubits(20);\n    sim1.set_num_qubits(10);\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n\n    sim1.set_num_qubits(20);\n    sim1.do_X(OpDat(10));\n    sim1.do_Z(OpDat(11));\n    sim1.do_H_XZ(OpDat(12));\n    sim1.do_ZCX(OpDat({12, 13}));\n    sim1.set_num_qubits(10);\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n\n    sim1.set_num_qubits(20);\n    sim2.ensure_large_enough_for_qubits(20);\n    ASSERT_EQ(sim1.inv_state, sim2.inv_state);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, set_num_qubits_reduce_random, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 10);\n    sim.inv_state = Tableau<W>::random(10, rng);\n    sim.set_num_qubits(5);\n    ASSERT_EQ(sim.inv_state.num_qubits, 5);\n    ASSERT_TRUE(sim.inv_state.satisfies_invariants());\n})\n\ntemplate <size_t W>\nvoid scramble_stabilizers(TableauSimulator<W> &s) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauTransposedRaii<W> tmp(s.inv_state);\n    for (size_t i = 0; i < s.inv_state.num_qubits; i++) {\n        for (size_t j = i + 1; j < s.inv_state.num_qubits; j++) {\n            if (rng() & 1) {\n                tmp.append_ZCX(i, j);\n            }\n            if (rng() & 1) {\n                tmp.append_ZCX(j, i);\n            }\n            if (rng() & 1) {\n                tmp.append_ZCZ(i, j);\n            }\n        }\n        if (rng() & 1) {\n            tmp.append_S(i);\n        }\n    }\n}\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, canonical_stabilizers, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 2);\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    ASSERT_EQ(\n        sim.canonical_stabilizers(),\n        (std::vector<PauliString<W>>{\n            PauliString<W>::from_str(\"XX\"),\n            PauliString<W>::from_str(\"ZZ\"),\n        }));\n    sim.do_SQRT_Y(OpDat({0, 1}));\n    ASSERT_EQ(\n        sim.canonical_stabilizers(),\n        (std::vector<PauliString<W>>{\n            PauliString<W>::from_str(\"XX\"),\n            PauliString<W>::from_str(\"ZZ\"),\n        }));\n    sim.do_SQRT_X(OpDat({0, 1}));\n    ASSERT_EQ(\n        sim.canonical_stabilizers(),\n        (std::vector<PauliString<W>>{\n            PauliString<W>::from_str(\"XX\"),\n            PauliString<W>::from_str(\"-ZZ\"),\n        }));\n    sim.set_num_qubits(3);\n    ASSERT_EQ(\n        sim.canonical_stabilizers(),\n        (std::vector<PauliString<W>>{\n            PauliString<W>::from_str(\"+XX_\"),\n            PauliString<W>::from_str(\"-ZZ_\"),\n            PauliString<W>::from_str(\"+__Z\"),\n        }));\n    sim.do_ZCX(OpDat({2, 0}));\n    ASSERT_EQ(\n        sim.canonical_stabilizers(),\n        (std::vector<PauliString<W>>{\n            PauliString<W>::from_str(\"+XX_\"),\n            PauliString<W>::from_str(\"-ZZ_\"),\n            PauliString<W>::from_str(\"+__Z\"),\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, canonical_stabilizers_random, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 4);\n    sim.inv_state = Tableau<W>::random(4, rng);\n    auto s1 = sim.canonical_stabilizers();\n    scramble_stabilizers<W>(sim);\n    auto s2 = sim.canonical_stabilizers();\n    ASSERT_EQ(s1, s2);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, set_num_qubits_reduce_preserves_scrambled_stabilizers, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 4);\n    sim.inv_state = Tableau<W>::random(4, rng);\n    auto s1 = sim.canonical_stabilizers();\n    sim.inv_state.expand(8, 1.0);\n    scramble_stabilizers<W>(sim);\n    sim.set_num_qubits(4);\n    auto s2 = sim.canonical_stabilizers();\n    ASSERT_EQ(s1, s2);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_z, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 4);\n    sim.do_H_XZ(OpDat({0, 2}));\n    sim.do_ZCX(OpDat({0, 1, 2, 3}));\n    auto k1 = sim.measure_kickback_z(GateTarget::qubit(1));\n    auto k2 = sim.measure_kickback_z(GateTarget::qubit(2));\n    auto k3 = sim.measure_kickback_z(GateTarget::qubit(3));\n    ASSERT_EQ(k1.second, PauliString<W>::from_str(\"XX__\"));\n    ASSERT_EQ(k2.second, PauliString<W>::from_str(\"__XX\"));\n    ASSERT_EQ(k3.second, PauliString<W>(0));\n    ASSERT_EQ(k2.first, k3.first);\n    auto p = PauliString<W>::from_str(\"+Z\");\n    auto pn = PauliString<W>::from_str(\"-Z\");\n    ASSERT_EQ(sim.peek_bloch(0), k1.first ? pn : p);\n    ASSERT_EQ(sim.peek_bloch(1), k1.first ? pn : p);\n    ASSERT_EQ(sim.peek_bloch(2), k2.first ? pn : p);\n    ASSERT_EQ(sim.peek_bloch(3), k2.first ? pn : p);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_x, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 4);\n    sim.do_H_XZ(OpDat({0, 2}));\n    sim.do_ZCX(OpDat({0, 1, 2, 3}));\n    auto k1 = sim.measure_kickback_x(GateTarget::qubit(1));\n    auto k2 = sim.measure_kickback_x(GateTarget::qubit(2));\n    auto k3 = sim.measure_kickback_x(GateTarget::qubit(3));\n    ASSERT_EQ(k1.second, PauliString<W>::from_str(\"ZZ__\"));\n    ASSERT_EQ(k2.second, PauliString<W>::from_str(\"__ZZ\"));\n    ASSERT_EQ(k3.second, PauliString<W>(0));\n    ASSERT_EQ(k2.first, k3.first);\n    auto p = PauliString<W>::from_str(\"+X\");\n    auto pn = PauliString<W>::from_str(\"-X\");\n    ASSERT_EQ(sim.peek_bloch(0), k1.first ? pn : p);\n    ASSERT_EQ(sim.peek_bloch(1), k1.first ? pn : p);\n    ASSERT_EQ(sim.peek_bloch(2), k2.first ? pn : p);\n    ASSERT_EQ(sim.peek_bloch(3), k2.first ? pn : p);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_y, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 4);\n    sim.do_H_XZ(OpDat({0, 2}));\n    sim.do_ZCX(OpDat({0, 1, 2, 3}));\n    auto k1 = sim.measure_kickback_y(GateTarget::qubit(1));\n    auto k2 = sim.measure_kickback_y(GateTarget::qubit(2));\n    auto k3 = sim.measure_kickback_y(GateTarget::qubit(3));\n    ASSERT_EQ(k1.second, PauliString<W>::from_str(\"ZX__\"));\n    ASSERT_EQ(k2.second, PauliString<W>::from_str(\"__ZX\"));\n    ASSERT_EQ(k3.second, PauliString<W>(0));\n    ASSERT_NE(k2.first, k3.first);\n    auto p = PauliString<W>::from_str(\"+Y\");\n    auto pn = PauliString<W>::from_str(\"-Y\");\n    ASSERT_EQ(sim.peek_bloch(0), k1.first ? p : pn);\n    ASSERT_EQ(sim.peek_bloch(1), k1.first ? pn : p);\n    ASSERT_EQ(sim.peek_bloch(2), k2.first ? pn : p);\n    ASSERT_EQ(sim.peek_bloch(3), k2.first ? p : pn);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_kickback_isolates, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 4);\n    sim.inv_state = Tableau<W>::random(4, rng);\n    for (size_t k = 0; k < 4; k++) {\n        auto result = sim.measure_kickback_z(GateTarget::qubit(k));\n        for (size_t j = 0; j < result.second.num_qubits && j < k; j++) {\n            ASSERT_FALSE(result.second.xs[j]);\n            ASSERT_FALSE(result.second.zs[j]);\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, collapse_isolate_completely, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (size_t k = 0; k < 10; k++) {\n        TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 6);\n        sim.inv_state = Tableau<W>::random(6, rng);\n        {\n            TableauTransposedRaii<W> tmp(sim.inv_state);\n            sim.collapse_isolate_qubit_z(2, tmp);\n        }\n        PauliString<W> x2 = sim.inv_state.xs[2];\n        PauliString<W> z2 = sim.inv_state.zs[2];\n        x2.sign = false;\n        z2.sign = false;\n        ASSERT_EQ(x2, PauliString<W>::from_str(\"__X___\"));\n        ASSERT_EQ(z2, PauliString<W>::from_str(\"__Z___\"));\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, reset_pure, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 1);\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n    t.do_RY(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n    t.do_RX(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n    t.do_RY(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n    t.do_RZ(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, reset_random, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 5);\n\n    t.inv_state = Tableau<W>::random(5, rng);\n    t.do_RX(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n\n    t.inv_state = Tableau<W>::random(5, rng);\n    t.do_RY(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n\n    t.inv_state = Tableau<W>::random(5, rng);\n    t.do_RZ(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n\n    t.inv_state = Tableau<W>::random(5, rng);\n    t.do_MRX(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n\n    t.inv_state = Tableau<W>::random(5, rng);\n    t.do_MRY(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n\n    t.inv_state = Tableau<W>::random(5, rng);\n    t.do_MRZ(OpDat(0));\n    ASSERT_EQ(t.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, reset_x_entangled, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 2);\n    t.do_H_XZ(OpDat(0));\n    t.do_ZCX(OpDat({0, 1}));\n    t.do_RX(OpDat(0));\n    auto p1 = t.peek_bloch(0);\n    auto p2 = t.peek_bloch(1);\n    p2.sign = false;\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+X\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, reset_y_entangled, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 2);\n    t.do_H_XZ(OpDat(0));\n    t.do_ZCX(OpDat({0, 1}));\n    t.do_RY(OpDat(0));\n    auto p1 = t.peek_bloch(0);\n    auto p2 = t.peek_bloch(1);\n    p2.sign = false;\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+Y\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, reset_z_entangled, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 2);\n    t.do_H_XZ(OpDat(0));\n    t.do_ZCX(OpDat({0, 1}));\n    t.do_RZ(OpDat(0));\n    auto p1 = t.peek_bloch(0);\n    auto p2 = t.peek_bloch(1);\n    p2.sign = false;\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+Z\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_x_entangled, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 2);\n    t.do_H_XZ(OpDat(0));\n    t.do_ZCX(OpDat({0, 1}));\n    t.do_MX(OpDat(0));\n    auto b = t.measurement_record.storage.back();\n    auto p1 = t.peek_bloch(0);\n    auto p2 = t.peek_bloch(1);\n    p1.sign ^= b;\n    p2.sign ^= b;\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+X\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_y_entangled, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 2);\n    t.do_H_XZ(OpDat(0));\n    t.do_ZCX(OpDat({0, 1}));\n    t.do_MY(OpDat(0));\n    auto b = t.measurement_record.storage.back();\n    auto p1 = t.peek_bloch(0);\n    auto p2 = t.peek_bloch(1);\n    p1.sign ^= b;\n    p2.sign ^= !b;\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+Y\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_z_entangled, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 2);\n    t.do_H_XZ(OpDat(0));\n    t.do_ZCX(OpDat({0, 1}));\n    t.do_MZ(OpDat(0));\n    auto b = t.measurement_record.storage.back();\n    auto p1 = t.peek_bloch(0);\n    auto p2 = t.peek_bloch(1);\n    p1.sign ^= b;\n    p2.sign ^= b;\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+Z\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_reset_x_entangled, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 2);\n    t.do_H_XZ(OpDat(0));\n    t.do_ZCX(OpDat({0, 1}));\n    t.do_MRX(OpDat(0));\n    auto b = t.measurement_record.storage.back();\n    auto p1 = t.peek_bloch(0);\n    auto p2 = t.peek_bloch(1);\n    p2.sign ^= b;\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+X\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_reset_y_entangled, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 2);\n    t.do_H_XZ(OpDat(0));\n    t.do_ZCX(OpDat({0, 1}));\n    t.do_MRY(OpDat(0));\n    auto b = t.measurement_record.storage.back();\n    auto p1 = t.peek_bloch(0);\n    auto p2 = t.peek_bloch(1);\n    p2.sign ^= !b;\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+Y\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_reset_z_entangled, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG(), 2);\n    t.do_H_XZ(OpDat(0));\n    t.do_ZCX(OpDat({0, 1}));\n    t.do_MRZ(OpDat(0));\n    auto b = t.measurement_record.storage.back();\n    auto p1 = t.peek_bloch(0);\n    auto p2 = t.peek_bloch(1);\n    p2.sign ^= b;\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+Z\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, reset_vs_measurements, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto check = [&](const char *circuit, std::vector<bool> results) {\n        simd_bits<W> ref(results.size());\n        for (size_t k = 0; k < results.size(); k++) {\n            ref[k] = results[k];\n        }\n        for (size_t reps = 0; reps < 5; reps++) {\n            simd_bits<W> t = TableauSimulator<W>::sample_circuit(Circuit(circuit), rng);\n            if (t != ref) {\n                return false;\n            }\n        }\n        return true;\n    };\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        RX 0\n        RY 1\n        RZ 2\n        H_XZ 0\n        H_YZ 1\n        M 0 1 2\n    )circuit\",\n        {\n            false,\n            false,\n            false,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0 1 2\n        H_YZ 3 4 5\n        X_ERROR(1) 0 3 6\n        Y_ERROR(1) 1 4 7\n        Z_ERROR(1) 2 5 8\n        MX 0 1 2\n        MY 3 4 5\n        MZ 6 7 8\n    )circuit\",\n        {\n            false,\n            true,\n            true,\n            true,\n            false,\n            true,\n            true,\n            true,\n            false,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0 1 2\n        H_YZ 3 4 5\n        X_ERROR(1) 0 3 6\n        Y_ERROR(1) 1 4 7\n        Z_ERROR(1) 2 5 8\n        MX !0 !1 !2\n        MY !3 !4 !5\n        MZ !6 !7 !8\n    )circuit\",\n        {\n            true,\n            false,\n            false,\n            false,\n            true,\n            false,\n            false,\n            false,\n            true,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0 1 2\n        H_YZ 3 4 5\n        X_ERROR(1) 0 3 6\n        Y_ERROR(1) 1 4 7\n        Z_ERROR(1) 2 5 8\n        MRX 0 1 2\n        MRY 3 4 5\n        MRZ 6 7 8\n        H_XZ 0\n        H_YZ 3\n        M 0 3 6\n    )circuit\",\n        {\n            false,\n            true,\n            true,\n            true,\n            false,\n            true,\n            true,\n            true,\n            false,\n            false,\n            false,\n            false,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0 1 2\n        H_YZ 3 4 5\n        X_ERROR(1) 0 3 6\n        Y_ERROR(1) 1 4 7\n        Z_ERROR(1) 2 5 8\n        MRX !0 !1 !2\n        MRY !3 !4 !5\n        MRZ !6 !7 !8\n        H_XZ 0\n        H_YZ 3\n        M 0 3 6\n    )circuit\",\n        {\n            true,\n            false,\n            false,\n            false,\n            true,\n            false,\n            false,\n            false,\n            true,\n            false,\n            false,\n            false,\n        }));\n\n    ASSERT_TRUE(check(\n        R\"circuit(\n        H_XZ 0\n        H_YZ 1\n        Z_ERROR(1) 0 1\n        X_ERROR(1) 2\n        MRX 0 0\n        MRY 1 1\n        MRZ 2 2\n    )circuit\",\n        {\n            true,\n            false,\n            true,\n            false,\n            true,\n            false,\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, sample_circuit_mutates_rng_state, {\n    std::mt19937_64 rng(1234);\n    TableauSimulator<W>::sample_circuit(Circuit(\"H 0\\nM 0\"), rng);\n    ASSERT_NE(rng, std::mt19937_64(1234));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, sample_stream_mutates_rng_state, {\n    FILE *in = tmpfile();\n    FILE *out = tmpfile();\n    fprintf(in, \"H 0\\nM 0\\n\");\n    rewind(in);\n\n    std::mt19937_64 rng(2345);\n    TableauSimulator<W>::sample_stream(in, out, SampleFormat::SAMPLE_FORMAT_B8, false, rng);\n\n    ASSERT_NE(rng, std::mt19937_64(2345));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measurement_x, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RX 0\n        REPEAT 10000 {\n            MX(0.05) 0\n        }\n    )CIRCUIT\"));\n    auto m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n    t.safe_do_circuit(Circuit(\"MX 0\"));\n    ASSERT_FALSE(t.measurement_record.storage.back());\n\n    t.measurement_record.storage.clear();\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RX 0 1\n        Y 0 1\n        REPEAT 5000 {\n            MX(0.05) 0 1\n        }\n    )CIRCUIT\"));\n    m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 10000 - 700);\n    ASSERT_LT(m1, 10000 - 300);\n    t.safe_do_circuit(Circuit(\"MX 0\"));\n    ASSERT_TRUE(t.measurement_record.storage.back());\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measurement_y, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RY 0\n        REPEAT 10000 {\n            MY(0.05) 0\n        }\n    )CIRCUIT\"));\n    auto m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n    t.safe_do_circuit(Circuit(\"MY 0\"));\n    ASSERT_FALSE(t.measurement_record.storage.back());\n\n    t.measurement_record.storage.clear();\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RY 0 1\n        X 0 1\n        REPEAT 5000 {\n            MY(0.05) 0 1\n        }\n    )CIRCUIT\"));\n    m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 10000 - 700);\n    ASSERT_LT(m1, 10000 - 300);\n    t.safe_do_circuit(Circuit(\"MY 0\"));\n    ASSERT_TRUE(t.measurement_record.storage.back());\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measurement_z, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RZ 0\n        REPEAT 10000 {\n            MZ(0.05) 0\n        }\n    )CIRCUIT\"));\n    auto m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n    t.safe_do_circuit(Circuit(\"MZ 0\"));\n    ASSERT_FALSE(t.measurement_record.storage.back());\n\n    t.measurement_record.storage.clear();\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RZ 0 1\n        X 0 1\n        REPEAT 5000 {\n            MZ(0.05) 0 1\n        }\n    )CIRCUIT\"));\n    m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 10000 - 700);\n    ASSERT_LT(m1, 10000 - 300);\n    t.safe_do_circuit(Circuit(\"MZ 0\"));\n    ASSERT_TRUE(t.measurement_record.storage.back());\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measure_reset_x, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RX 0\n        REPEAT 10000 {\n            MRX(0.05) 0\n        }\n    )CIRCUIT\"));\n    auto m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n    t.safe_do_circuit(Circuit(\"MX 0\"));\n    ASSERT_FALSE(t.measurement_record.storage.back());\n\n    t.measurement_record.storage.clear();\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RX 0 1\n        REPEAT 5000 {\n            Z 0 1\n            MRX(0.05) 0 1\n        }\n    )CIRCUIT\"));\n    m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 10000 - 700);\n    ASSERT_LT(m1, 10000 - 300);\n    t.safe_do_circuit(Circuit(\"MX 0\"));\n    ASSERT_FALSE(t.measurement_record.storage.back());\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measure_reset_y, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RY 0 1\n        REPEAT 5000 {\n            MRY(0.05) 0 1\n        }\n    )CIRCUIT\"));\n    auto m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n    t.safe_do_circuit(Circuit(\"MY 0\"));\n    ASSERT_FALSE(t.measurement_record.storage.back());\n\n    t.measurement_record.storage.clear();\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RY 0 1\n        REPEAT 5000 {\n            X 0 1\n            MRY(0.05) 0 1\n        }\n    )CIRCUIT\"));\n    m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 10000 - 700);\n    ASSERT_LT(m1, 10000 - 300);\n    t.safe_do_circuit(Circuit(\"MY 0\"));\n    ASSERT_FALSE(t.measurement_record.storage.back());\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, noisy_measure_reset_z, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RZ 0 1\n        REPEAT 5000 {\n            MRZ(0.05) 0 1\n        }\n    )CIRCUIT\"));\n    auto m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n    t.safe_do_circuit(Circuit(\"MZ 0\"));\n    ASSERT_FALSE(t.measurement_record.storage.back());\n\n    t.measurement_record.storage.clear();\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        RZ 0 1\n        REPEAT 5000 {\n            X 0 1\n            MRZ(0.05) 0 1\n        }\n    )CIRCUIT\"));\n    m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 10000 - 700);\n    ASSERT_LT(m1, 10000 - 300);\n    t.safe_do_circuit(Circuit(\"MZ 0\"));\n    ASSERT_FALSE(t.measurement_record.storage.back());\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_bad, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(\"MPP X0*X0 !X0*X0\"));\n    ASSERT_EQ(t.measurement_record.storage, (std::vector<bool>{false, true}));\n    ASSERT_THROW({ t.safe_do_circuit(Circuit(\"MPP X0*Z0\")); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_1, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        REPEAT 100 {\n            RX 0\n            RY 1\n            RZ 2\n            MPP X0 Y1 Z2 X0*Y1*Z2\n        }\n    )CIRCUIT\"));\n    ASSERT_EQ(t.measurement_record.storage.size(), 400);\n    ASSERT_EQ(std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_4body, {\n    for (size_t k = 0; k < 10; k++) {\n        TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n        t.safe_do_circuit(Circuit(R\"CIRCUIT(\n            MPP X0*X1*X2*X3\n            MX 0 1 2 3 4 5\n            MPP X2*X3*X4*X5\n            MPP Z0*Z1*Z4*Z5 !Y0*Y1*Y4*Y5\n        )CIRCUIT\"));\n        auto x0123 = t.measurement_record.storage[0];\n        auto x0 = t.measurement_record.storage[1];\n        auto x1 = t.measurement_record.storage[2];\n        auto x2 = t.measurement_record.storage[3];\n        auto x3 = t.measurement_record.storage[4];\n        auto x4 = t.measurement_record.storage[5];\n        auto x5 = t.measurement_record.storage[6];\n        auto x2345 = t.measurement_record.storage[7];\n        auto mz0145 = t.measurement_record.storage[8];\n        auto y0145 = t.measurement_record.storage[9];\n        ASSERT_EQ(x0123, x0 ^ x1 ^ x2 ^ x3);\n        ASSERT_EQ(x2345, x2 ^ x3 ^ x4 ^ x5);\n        ASSERT_EQ(y0145 ^ mz0145 ^ 1, x0123 ^ x2345);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_epr, {\n    for (size_t k = 0; k < 10; k++) {\n        TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n        t.safe_do_circuit(Circuit(R\"CIRCUIT(\n            MPP X0*X1 Z0*Z1 Y0*Y1\n            CNOT 0 1\n            H 0\n            M 0 1\n        )CIRCUIT\"));\n        auto x01 = t.measurement_record.storage[0];\n        auto z01 = t.measurement_record.storage[1];\n        auto y01 = t.measurement_record.storage[2];\n        auto m0 = t.measurement_record.storage[3];\n        auto m1 = t.measurement_record.storage[4];\n        ASSERT_EQ(m0, x01);\n        ASSERT_EQ(m1, z01);\n        ASSERT_EQ(x01 ^ z01, y01 ^ 1);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_inversions, {\n    for (size_t k = 0; k < 10; k++) {\n        TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n        t.safe_do_circuit(Circuit(R\"CIRCUIT(\n            MPP !X0*!X1 !X0*X1 X0*!X1 X0*X1 X0 X1 !X0 !X1\n        )CIRCUIT\"));\n        auto a = t.measurement_record.storage[0];\n        auto b = t.measurement_record.storage[1];\n        auto c = t.measurement_record.storage[2];\n        auto d = t.measurement_record.storage[3];\n        auto e = t.measurement_record.storage[4];\n        auto f = t.measurement_record.storage[5];\n        auto g = t.measurement_record.storage[6];\n        auto h = t.measurement_record.storage[7];\n        ASSERT_EQ(a, d);\n        ASSERT_EQ(b, c);\n        ASSERT_NE(a, b);\n        ASSERT_EQ(a, e ^ f);\n        ASSERT_NE(e, g);\n        ASSERT_NE(f, h);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_product_noisy, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        H 0\n        CNOT 0 1\n        REPEAT 5000 {\n            MPP(0.05) X0*X1 Z0*Z1\n        }\n    )CIRCUIT\"));\n    auto m1 = std::accumulate(t.measurement_record.storage.begin(), t.measurement_record.storage.end(), 0);\n    ASSERT_GT(m1, 300);\n    ASSERT_LT(m1, 700);\n    t.safe_do_circuit(Circuit(\"MPP Y0*Y1\"));\n    ASSERT_EQ(t.measurement_record.storage.back(), true);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, ignores_sweep_controls, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        X 0\n        CNOT sweep[0] 0\n        M 0\n    )CIRCUIT\"));\n    ASSERT_EQ(t.measurement_record.lookback(1), true);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, peek_observable_expectation, {\n    TableauSimulator<W> t(INDEPENDENT_TEST_RNG());\n    t.safe_do_circuit(Circuit(R\"CIRCUIT(\n        H 0\n        CNOT 0 1\n        X 0\n    )CIRCUIT\"));\n\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"XX\")), 1);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"YY\")), 1);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"ZZ\")), -1);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"-XX\")), -1);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"-ZZ\")), 1);\n\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"\")), 1);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"-I\")), -1);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"X\")), 0);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"Z\")), 0);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"Z_\")), 0);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"ZZZ\")), -1);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"XXX\")), 0);\n    ASSERT_EQ(t.peek_observable_expectation(PauliString<W>::from_str(\"ZZZZZZZZ\")), -1);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_x, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 2);\n\n    // Postselect from +X.\n    sim.do_RX(OpDat(0));\n    sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n\n    // Postselect from -X.\n    sim.do_RX(OpDat(0));\n    sim.do_Z(OpDat(0));\n    ASSERT_THROW({ sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(0)}, false); }, std::invalid_argument);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-X\"));\n\n    // Postselect from +Y.\n    sim.do_RY(OpDat(0));\n    sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n\n    // Postselect from -Y.\n    sim.do_RY(OpDat(0));\n    sim.do_X(OpDat(0));\n    sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n\n    // Postselect from +Z.\n    sim.do_RZ(OpDat(0));\n    sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n\n    // Postselect from -Z.\n    sim.do_RZ(OpDat(0));\n    sim.do_X(OpDat(0));\n    sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n\n    // Postselect entangled.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(1)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+X\"));\n\n    // Postselect opposite state entangled.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(1)}, true);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-X\"));\n\n    // Postselect both independent.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(0), GateTarget::qubit(1)}, true);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-X\"));\n\n    // Postselect both entangled.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(0), GateTarget::qubit(1)}, true);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-X\"));\n\n    // Contradiction reached during second postselection.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.do_Z(OpDat(0));\n    ASSERT_THROW(\n        { sim.postselect_x(std::vector<GateTarget>{GateTarget::qubit(0), GateTarget::qubit(1)}, true); },\n        std::invalid_argument);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-X\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+X\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_y, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 2);\n\n    // Postselect from +X.\n    sim.do_RX(OpDat(0));\n    sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n\n    // Postselect from -X.\n    sim.do_RX(OpDat(0));\n    sim.do_Z(OpDat(0));\n    sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n\n    // Postselect from +Y.\n    sim.do_RY(OpDat(0));\n    sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n\n    // Postselect from -Y.\n    sim.do_RY(OpDat(0));\n    sim.do_X(OpDat(0));\n    ASSERT_THROW({ sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(0)}, false); }, std::invalid_argument);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Y\"));\n\n    // Postselect from +Z.\n    sim.do_RZ(OpDat(0));\n    sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n\n    // Postselect from -Z.\n    sim.do_RZ(OpDat(0));\n    sim.do_X(OpDat(0));\n    sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n\n    // Postselect entangled.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(1)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Y\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+Y\"));\n\n    // Postselect opposite state entangled.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(1)}, true);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Y\"));\n\n    // Postselect both independent.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(0), GateTarget::qubit(1)}, true);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Y\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Y\"));\n\n    // Postselect both entangled.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.do_Z(OpDat(0));\n    sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(0), GateTarget::qubit(1)}, true);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Y\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Y\"));\n\n    // Contradiction reached during second postselection.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    ASSERT_THROW(\n        { sim.postselect_y(std::vector<GateTarget>{GateTarget::qubit(0), GateTarget::qubit(1)}, true); },\n        std::invalid_argument);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Y\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+Y\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_z, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 2);\n\n    // Postselect from +X.\n    sim.do_RX(OpDat(0));\n    sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n\n    // Postselect from -X.\n    sim.do_RX(OpDat(0));\n    sim.do_Z(OpDat(0));\n    sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n\n    // Postselect from +Y.\n    sim.do_RY(OpDat(0));\n    sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n\n    // Postselect from -Y.\n    sim.do_RY(OpDat(0));\n    sim.do_X(OpDat(0));\n    sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n\n    // Postselect from +Z.\n    sim.do_RZ(OpDat(0));\n    sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(0)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n\n    // Postselect from -Z.\n    sim.do_RZ(OpDat(0));\n    sim.do_X(OpDat(0));\n    ASSERT_THROW({ sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(0)}, false); }, std::invalid_argument);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Z\"));\n\n    // Postselect entangled.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(1)}, false);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+Z\"));\n\n    // Postselect opposite state entangled.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(1)}, true);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Z\"));\n\n    // Postselect both independent.\n    sim.do_RX(OpDat({0, 1}));\n    sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(0), GateTarget::qubit(1)}, true);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Z\"));\n\n    // Postselect both entangled.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(0), GateTarget::qubit(1)}, true);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-Z\"));\n\n    // Contradiction reached during second postselection.\n    sim.do_RZ(OpDat({0, 1}));\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.do_X(OpDat(0));\n    ASSERT_THROW(\n        { sim.postselect_z(std::vector<GateTarget>{GateTarget::qubit(0), GateTarget::qubit(1)}, true); },\n        std::invalid_argument);\n    ASSERT_EQ(sim.peek_bloch(0), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+Z\"));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, peek_x, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 3);\n    ASSERT_EQ(sim.peek_x(0), 0);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), +1);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), +1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), 0);\n    ASSERT_EQ(sim.peek_z(2), +1);\n\n    sim.do_H_XZ(OpDat(0));\n    ASSERT_EQ(sim.peek_x(0), +1);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), 0);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), +1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), 0);\n    ASSERT_EQ(sim.peek_z(2), +1);\n\n    sim.do_X(OpDat(1));\n    ASSERT_EQ(sim.peek_x(0), +1);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), 0);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), -1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), 0);\n    ASSERT_EQ(sim.peek_z(2), +1);\n\n    sim.do_H_YZ(OpDat(2));\n    ASSERT_EQ(sim.peek_x(0), +1);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), 0);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), -1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), +1);\n    ASSERT_EQ(sim.peek_z(2), 0);\n\n    sim.do_X(OpDat(0));\n    sim.do_X(OpDat(1));\n    sim.do_X(OpDat(2));\n    ASSERT_EQ(sim.peek_x(0), +1);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), 0);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), +1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), -1);\n    ASSERT_EQ(sim.peek_z(2), 0);\n\n    sim.do_Y(OpDat(0));\n    sim.do_Y(OpDat(1));\n    sim.do_Y(OpDat(2));\n    ASSERT_EQ(sim.peek_x(0), -1);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), 0);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), -1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), -1);\n    ASSERT_EQ(sim.peek_z(2), 0);\n\n    sim.do_ZCZ(OpDat({0, 1}));\n    ASSERT_EQ(sim.peek_x(0), +1);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), 0);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), -1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), -1);\n    ASSERT_EQ(sim.peek_z(2), 0);\n\n    sim.do_ZCZ(OpDat({1, 2}));\n    ASSERT_EQ(sim.peek_x(0), +1);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), 0);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), -1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), +1);\n    ASSERT_EQ(sim.peek_z(2), 0);\n\n    sim.do_ZCZ(OpDat({0, 2}));\n    ASSERT_EQ(sim.peek_x(0), 0);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), 0);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), -1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), 0);\n    ASSERT_EQ(sim.peek_z(2), 0);\n\n    sim.do_X(OpDat(0));\n    sim.do_X(OpDat(1));\n    sim.do_X(OpDat(2));\n    ASSERT_EQ(sim.peek_x(0), 0);\n    ASSERT_EQ(sim.peek_y(0), 0);\n    ASSERT_EQ(sim.peek_z(0), 0);\n    ASSERT_EQ(sim.peek_x(1), 0);\n    ASSERT_EQ(sim.peek_y(1), 0);\n    ASSERT_EQ(sim.peek_z(1), +1);\n    ASSERT_EQ(sim.peek_x(2), 0);\n    ASSERT_EQ(sim.peek_y(2), 0);\n    ASSERT_EQ(sim.peek_z(2), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, apply_tableau, {\n    auto cnot = GATE_DATA.at(\"CNOT\").tableau<W>();\n    auto s = GATE_DATA.at(\"S\").tableau<W>();\n    auto h = GATE_DATA.at(\"H\").tableau<W>();\n    auto cxyz = GATE_DATA.at(\"C_XYZ\").tableau<W>();\n\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 4);\n    sim.apply_tableau(h, {1});\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+X\"));\n    sim.apply_tableau(s, {1});\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"+Y\"));\n    sim.apply_tableau(s, {1});\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-X\"));\n    sim.apply_tableau(cnot, {2, 1});\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"-X\"));\n    sim.apply_tableau(cnot, {1, 2});\n    ASSERT_EQ(sim.peek_bloch(1), PauliString<W>::from_str(\"I\"));\n    ASSERT_EQ(sim.peek_observable_expectation(PauliString<W>::from_str(\"IXXI\")), -1);\n    ASSERT_EQ(sim.peek_observable_expectation(PauliString<W>::from_str(\"IZZI\")), +1);\n\n    sim.apply_tableau(cxyz, {2});\n    sim.apply_tableau(cxyz.inverse(), {1});\n    ASSERT_EQ(sim.peek_observable_expectation(PauliString<W>::from_str(\"IZYI\")), -1);\n    ASSERT_EQ(sim.peek_observable_expectation(PauliString<W>::from_str(\"IYXI\")), +1);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, measure_pauli_string, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 4);\n    sim.do_H_XZ(OpDat(0));\n    sim.do_ZCX(OpDat({0, 1}));\n    sim.do_X(OpDat(0));\n\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"XX\"), 0.0));\n    ASSERT_TRUE(sim.measure_pauli_string(PauliString<W>::from_str(\"XX\"), 1.0));\n    ASSERT_TRUE(sim.measure_pauli_string(PauliString<W>::from_str(\"-XX\"), 0.0));\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"-XX\"), 1.0));\n\n    ASSERT_TRUE(sim.measure_pauli_string(PauliString<W>::from_str(\"ZZ\"), 0.0));\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"ZZ\"), 1.0));\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"-ZZ\"), 0.0));\n    ASSERT_TRUE(sim.measure_pauli_string(PauliString<W>::from_str(\"-ZZ\"), 1.0));\n\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"YY\"), 0.0));\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"XXZ\"), 0.0));\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"__Z\"), 0.0));\n\n    auto b = sim.measure_pauli_string(PauliString<W>::from_str(\"XXX\"), 0.0);\n    ASSERT_EQ(sim.measure_pauli_string(PauliString<W>::from_str(\"XXX\"), 0.0), b);\n    ASSERT_EQ(sim.measure_pauli_string(PauliString<W>::from_str(\"-XXX\"), 0.0), !b);\n    ASSERT_EQ(sim.measure_pauli_string(PauliString<W>::from_str(\"XXX\"), 1.0), !b);\n\n    ASSERT_TRUE(sim.measure_pauli_string(PauliString<W>::from_str(\"XX\"), 1.0));\n\n    ASSERT_THROW({ sim.measure_pauli_string(PauliString<W>::from_str(\"\"), -0.5); }, std::invalid_argument);\n    ASSERT_THROW({ sim.measure_pauli_string(PauliString<W>::from_str(\"\"), 2.5); }, std::invalid_argument);\n    ASSERT_THROW({ sim.measure_pauli_string(PauliString<W>::from_str(\"\"), NAN); }, std::invalid_argument);\n\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"+\"), 0.0));\n    ASSERT_TRUE(sim.measure_pauli_string(PauliString<W>::from_str(\"+\"), 1.0));\n    ASSERT_TRUE(sim.measure_pauli_string(PauliString<W>::from_str(\"-\"), 0.0));\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"-\"), 1.0));\n    ASSERT_FALSE(sim.measure_pauli_string(PauliString<W>::from_str(\"____________Z\"), 0.0));\n    ASSERT_EQ(sim.inv_state.num_qubits, 13);\n\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{0, 1, 1,  0,  1, 0, 0, 1, 0, 0, 0,\n                                                                 b, b, !b, !b, 1, 0, 1, 1, 0, 0}));\n\n    size_t t = 0;\n    for (size_t k = 0; k < 10000; k++) {\n        t += sim.measure_pauli_string(PauliString<W>::from_str(\"-ZZ\"), 0.2);\n    }\n    ASSERT_GT(t / 10000.0, 0.05);\n    ASSERT_LT(t / 10000.0, 0.35);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, amortized_resizing, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 5120);\n    sim.ensure_large_enough_for_qubits(5121);\n    ASSERT_GT(sim.inv_state.xs.xt.num_minor_bits_padded(), 5600);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, mpad, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 5);\n    ASSERT_EQ(sim.inv_state, Tableau<W>(5));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{}));\n\n    sim.safe_do_circuit(Circuit(\"MPAD 0\"));\n    ASSERT_EQ(sim.inv_state, Tableau<W>(5));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{0}));\n\n    sim.safe_do_circuit(Circuit(\"MPAD 1\"));\n    ASSERT_EQ(sim.inv_state, Tableau<W>(5));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{0, 1}));\n\n    sim.safe_do_circuit(Circuit(\"MPAD 0 0 1 1 0\"));\n    ASSERT_EQ(sim.inv_state, Tableau<W>(5));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{0, 1, 0, 0, 1, 1, 0}));\n})\n\ntemplate <size_t W>\nvoid expect_same_final_state(const Tableau<W> &start, const Circuit &c1, const Circuit &c2, bool unsigned_stabilizers) {\n    size_t n = start.num_qubits;\n    TableauSimulator<W> sim1(INDEPENDENT_TEST_RNG(), n);\n    TableauSimulator<W> sim2(INDEPENDENT_TEST_RNG(), n);\n    sim1.inv_state = start;\n    sim2.inv_state = start;\n    sim1.safe_do_circuit(c1);\n    sim2.safe_do_circuit(c2);\n    auto t1 = sim1.canonical_stabilizers();\n    auto t2 = sim2.canonical_stabilizers();\n    if (unsigned_stabilizers) {\n        for (auto &e1 : t1) {\n            e1.sign = false;\n        }\n        for (auto &e2 : t2) {\n            e2.sign = false;\n        }\n    }\n    EXPECT_EQ(t1, t2);\n}\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, mxx_myy_mzz_vs_mpp_unsigned, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    expect_same_final_state(\n        Tableau<W>::random(5, rng), Circuit(\"MXX 1 3 1 2 3 4\"), Circuit(\"MPP X1*X3 X1*X2 X3*X4\"), true);\n    expect_same_final_state(\n        Tableau<W>::random(5, rng), Circuit(\"MYY 1 3 1 2 3 4\"), Circuit(\"MPP Y1*Y3 Y1*Y2 Y3*Y4\"), true);\n    expect_same_final_state(\n        Tableau<W>::random(5, rng), Circuit(\"MZZ 1 3 1 2 3 4\"), Circuit(\"MPP Z1*Z3 Z1*Z2 Z3*Z4\"), true);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, mxx, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 5);\n    sim.safe_do_circuit(Circuit(\"RX 0 1\"));\n    sim.safe_do_circuit(Circuit(\"MXX 0 1\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{false}));\n    sim.measurement_record.storage.clear();\n\n    sim.inv_state = Tableau<W>::random(5, rng);\n    sim.safe_do_circuit(Circuit(\"MXX 1 3\"));\n    bool x13 = sim.measurement_record.storage.back();\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MXX 1 3\"));\n    sim.safe_do_circuit(Circuit(\"MXX 1 !3\"));\n    sim.safe_do_circuit(Circuit(\"MXX !1 3\"));\n    sim.safe_do_circuit(Circuit(\"MXX !1 !3\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{x13, !x13, !x13, x13}));\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MXX 2 3\"));\n    bool x23 = sim.measurement_record.storage.back();\n    bool x12 = x13 ^ x23;\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MXX 1 2\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{x12}));\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MXX 3 4\"));\n    bool x34 = sim.measurement_record.storage.back();\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MXX 1 2 3 4 2 3 1 3\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{x12, x34, x23, x13}));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, myy, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 5);\n    sim.safe_do_circuit(Circuit(\"RY 0 1\"));\n    sim.safe_do_circuit(Circuit(\"MYY 0 1\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{false}));\n    sim.measurement_record.storage.clear();\n\n    sim.inv_state = Tableau<W>::random(5, rng);\n    sim.safe_do_circuit(Circuit(\"MYY 1 3\"));\n    bool x13 = sim.measurement_record.storage.back();\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MYY 1 3\"));\n    sim.safe_do_circuit(Circuit(\"MYY 1 !3\"));\n    sim.safe_do_circuit(Circuit(\"MYY !1 3\"));\n    sim.safe_do_circuit(Circuit(\"MYY !1 !3\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{x13, !x13, !x13, x13}));\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MYY 2 3\"));\n    bool x23 = sim.measurement_record.storage.back();\n    bool x12 = x13 ^ x23;\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MYY 1 2\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{x12}));\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MYY 3 4\"));\n    bool x34 = sim.measurement_record.storage.back();\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MYY 1 2 3 4 2 3 1 3\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{x12, x34, x23, x13}));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, mzz, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 5);\n    sim.safe_do_circuit(Circuit(\"RZ 0 1\"));\n    sim.safe_do_circuit(Circuit(\"MZZ 0 1\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{false}));\n    sim.measurement_record.storage.clear();\n\n    sim.inv_state = Tableau<W>::random(5, rng);\n    sim.safe_do_circuit(Circuit(\"MZZ 1 3\"));\n    bool x13 = sim.measurement_record.storage.back();\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MZZ 1 3\"));\n    sim.safe_do_circuit(Circuit(\"MZZ 1 !3\"));\n    sim.safe_do_circuit(Circuit(\"MZZ !1 3\"));\n    sim.safe_do_circuit(Circuit(\"MZZ !1 !3\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{x13, !x13, !x13, x13}));\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MZZ 2 3\"));\n    bool x23 = sim.measurement_record.storage.back();\n    bool x12 = x13 ^ x23;\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MZZ 1 2\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{x12}));\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MZZ 3 4\"));\n    bool x34 = sim.measurement_record.storage.back();\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(\"MZZ 1 2 3 4 2 3 1 3\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{x12, x34, x23, x13}));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, runs_on_general_circuit, {\n    auto circuit = generate_test_circuit_with_all_operations();\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 1);\n    sim.safe_do_circuit(circuit);\n    ASSERT_GT(sim.inv_state.xs.num_qubits, 1);\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, heralded_erase, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 1);\n    sim.safe_do_circuit(Circuit(R\"CIRCUIT(\n        HERALDED_ERASE(0) 0 1 2 3 10 11 12 13\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{0, 0, 0, 0, 0, 0, 0, 0}));\n    sim.measurement_record.storage.clear();\n    ASSERT_EQ(sim.inv_state, Tableau<W>(14));\n\n    sim.safe_do_circuit(Circuit(R\"CIRCUIT(\n        HERALDED_ERASE(1) 0 1 2 3 4 5 6 10 11 12 13\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}));\n    ASSERT_NE(sim.inv_state, Tableau<W>(14));\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, heralded_pauli_channel_1, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 1);\n    Tableau<W> expected(14);\n\n    sim.safe_do_circuit(Circuit(R\"CIRCUIT(\n        HERALDED_PAULI_CHANNEL_1(0, 0, 0, 0) 0 1 2 3 10 11 12 13\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{0, 0, 0, 0, 0, 0, 0, 0}));\n    ASSERT_EQ(sim.inv_state, Tableau<W>(14));\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(R\"CIRCUIT(\n        HERALDED_PAULI_CHANNEL_1(1, 0, 0, 0) 0 1 2 3 4 5 6 10 11 12 13\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}));\n    ASSERT_EQ(sim.inv_state, Tableau<W>(14));\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(R\"CIRCUIT(\n        HERALDED_PAULI_CHANNEL_1(0, 1, 0, 0) 13\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{true}));\n    expected.prepend_X(13);\n    ASSERT_EQ(sim.inv_state, expected);\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(R\"CIRCUIT(\n        HERALDED_PAULI_CHANNEL_1(0, 0, 1, 0) 5 10\n    )CIRCUIT\"));\n    expected.prepend_Y(5);\n    expected.prepend_Y(10);\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{1, 1}));\n    ASSERT_EQ(sim.inv_state, expected);\n    sim.measurement_record.storage.clear();\n\n    sim.safe_do_circuit(Circuit(R\"CIRCUIT(\n        HERALDED_PAULI_CHANNEL_1(0, 0, 0, 1) 1 10 11\n    )CIRCUIT\"));\n    expected.prepend_Z(1);\n    expected.prepend_Z(10);\n    expected.prepend_Z(11);\n    ASSERT_EQ(sim.measurement_record.storage, (std::vector<bool>{1, 1, 1}));\n    ASSERT_EQ(sim.inv_state, expected);\n    sim.measurement_record.storage.clear();\n})\n\nTEST_EACH_WORD_SIZE_W(TableauSimulator, postselect_observable, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 0);\n    sim.postselect_observable(PauliString<W>(\"ZZ\"), false);\n    sim.postselect_observable(PauliString<W>(\"XX\"), false);\n\n    auto initial_state = sim.inv_state;\n    ASSERT_THROW({ sim.postselect_observable(PauliString<W>(\"YY\"), false); }, std::invalid_argument);\n\n    sim.postselect_observable(PauliString<W>(\"ZZ\"), false);\n    ASSERT_EQ(sim.inv_state, initial_state);\n\n    sim.postselect_observable(PauliString<W>(\"ZZ\"), false);\n    ASSERT_EQ(sim.inv_state, initial_state);\n\n    ASSERT_THROW({ sim.postselect_observable(PauliString<W>(\"ZZ\"), true); }, std::invalid_argument);\n    ASSERT_EQ(sim.inv_state, initial_state);\n\n    ASSERT_THROW({ sim.postselect_observable(PauliString<W>(\"ZZ\"), true); }, std::invalid_argument);\n    ASSERT_EQ(sim.inv_state, initial_state);\n\n    sim.postselect_observable(PauliString<W>(\"ZZ\"), false);\n    ASSERT_EQ(sim.inv_state, initial_state);\n\n    sim.postselect_observable(PauliString<W>(\"XX\"), false);\n    ASSERT_EQ(sim.inv_state, initial_state);\n\n    sim.postselect_observable(PauliString<W>(\"-YY\"), false);\n    ASSERT_EQ(sim.inv_state, initial_state);\n\n    sim.postselect_observable(PauliString<W>(\"YY\"), true);\n    ASSERT_EQ(sim.inv_state, initial_state);\n\n    sim.postselect_observable(PauliString<W>(\"XZ\"), true);\n    ASSERT_NE(sim.inv_state, initial_state);\n})\n"
  },
  {
    "path": "src/stim/simulators/tableau_simulator_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport pytest\nimport stim\nimport numpy as np\n\n\ndef test_basic():\n    s = stim.TableauSimulator()\n    assert s.measure(0) is False\n    assert s.measure(0) is False\n    s.x(0)\n    assert s.measure(0) is True\n    assert s.measure(0) is True\n    s.reset(0)\n    assert s.measure(0) is False\n    s.h(0)\n    s.h(0)\n    s.sqrt_x(1)\n    s.sqrt_x(1)\n    assert s.measure_many(0, 1) == [False, True]\n\n\ndef test_access_tableau():\n    s = stim.TableauSimulator()\n    assert s.current_inverse_tableau() == stim.Tableau(0)\n\n    s.h(0)\n    assert s.current_inverse_tableau() == stim.Tableau.from_named_gate(\"H\")\n\n    s.h(0)\n    assert s.current_inverse_tableau() == stim.Tableau(1)\n\n    s.h(1)\n    s.h(1)\n    assert s.current_inverse_tableau() == stim.Tableau(2)\n\n    s.h(2)\n    assert s.current_inverse_tableau() == stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"X__\"),\n            stim.PauliString(\"_X_\"),\n            stim.PauliString(\"__Z\"),\n        ],\n        zs=[\n            stim.PauliString(\"Z__\"),\n            stim.PauliString(\"_Z_\"),\n            stim.PauliString(\"__X\"),\n        ],\n    )\n\n\n@pytest.mark.parametrize(\"name\", [\n    \"x\",\n    \"y\",\n    \"z\",\n    \"h\",\n    \"h_xy\",\n    \"h_yz\",\n    \"sqrt_x\",\n    \"sqrt_x_dag\",\n    \"sqrt_y\",\n    \"sqrt_y_dag\",\n    \"s\",\n    \"s_dag\",\n    \"swap\",\n    \"iswap\",\n    \"iswap_dag\",\n    \"xcx\",\n    \"xcy\",\n    \"xcz\",\n    \"ycx\",\n    \"ycy\",\n    \"ycz\",\n    \"cnot\",\n    \"cy\",\n    \"cz\",\n])\ndef test_gates_present(name: str):\n    t = stim.Tableau.from_named_gate(name)\n    n = len(t)\n    s1 = stim.TableauSimulator()\n    s2 = stim.TableauSimulator()\n    for k in range(n):\n        s1.h(k)\n        s2.h(k)\n        s1.cnot(k, k + n)\n        s2.cnot(k, k + n)\n    getattr(s1, name)(*range(n))\n    s2.do(stim.Circuit(f\"{name} \" + \" \".join(str(e) for e in range(n))))\n    assert s1.current_inverse_tableau() == s2.current_inverse_tableau()\n\n\ndef test_do():\n    s = stim.TableauSimulator()\n    s.do(stim.Circuit(\"\"\"\n        S 0\n    \"\"\"))\n    assert s.current_inverse_tableau() == stim.Tableau.from_named_gate(\"S_DAG\")\n\n\ndef test_peek_bloch():\n    s = stim.TableauSimulator()\n    assert s.peek_bloch(0) == stim.PauliString(\"+Z\")\n    s.x(0)\n    assert s.peek_bloch(0) == stim.PauliString(\"-Z\")\n    s.h(0)\n    assert s.peek_bloch(0) == stim.PauliString(\"-X\")\n    s.sqrt_x(1)\n    assert s.peek_bloch(1) == stim.PauliString(\"-Y\")\n    s.cz(0, 1)\n    assert s.peek_bloch(0) == stim.PauliString(\"+I\")\n    assert s.peek_bloch(1) == stim.PauliString(\"+I\")\n\n\ndef test_copy():\n    s = stim.TableauSimulator()\n    s.h(0)\n    s2 = s.copy()\n    assert s.current_inverse_tableau() == s2.current_inverse_tableau()\n    assert s is not s2\n\n\ndef test_paulis():\n    s = stim.TableauSimulator()\n    s.h(*range(0, 22, 2))\n    s.cnot(*range(22))\n\n    s.do(stim.PauliString(\"ZZZ_YYY_XXX\"))\n    s.z(0, 1, 2)\n    s.y(4, 5, 6)\n    s.x(8, 9, 10)\n\n    s.cnot(*range(22))\n    s.h(*range(0, 22, 2))\n    assert s.measure_many(*range(22)) == [False] * 22\n\n    s = stim.TableauSimulator()\n    s.do(stim.PauliString(\"Z\" * 500))\n    assert s.measure_many(*range(500)) == [False] * 500\n    s.do(stim.PauliString(\"X\" * 500))\n    assert s.measure_many(*range(500)) == [True] * 500\n\n\ndef test_measure_kickback():\n    s = stim.TableauSimulator()\n    assert s.measure_kickback(0) == (False, None)\n    assert s.measure_kickback(0) == (False, None)\n    assert s.current_measurement_record() == [False, False]\n\n    s.h(0)\n    v = s.measure_kickback(0)\n    assert isinstance(v[0], bool)\n    assert v[1] == stim.PauliString(\"X\")\n    assert s.measure_kickback(0) == (v[0], None)\n    assert s.current_measurement_record() == [False, False, v[0], v[0]]\n\n    s = stim.TableauSimulator()\n    s.h(0)\n    s.cnot(0, 1)\n    v = s.measure_kickback(0)\n    assert isinstance(v[0], bool)\n    assert v[1] == stim.PauliString(\"XX\")\n    assert s.measure_kickback(0) == (v[0], None)\n\n    s = stim.TableauSimulator()\n    s.h(0)\n    s.cnot(0, 1)\n    v = s.measure_kickback(1)\n    assert isinstance(v[0], bool)\n    assert v[1] == stim.PauliString(\"XX\")\n    assert s.measure_kickback(0) == (v[0], None)\n\n\ndef test_post_select_using_measure_kickback():\n    s = stim.TableauSimulator()\n\n    def pseudo_post_select(qubit, desired_result):\n        m, kick = s.measure_kickback(qubit)\n        if m != desired_result:\n            if kick is None:\n                raise ValueError(\"Deterministic measurement differed from desired result.\")\n            s.do(kick)\n\n    s.h(0)\n    s.cnot(0, 1)\n    s.cnot(0, 2)\n    pseudo_post_select(qubit=2, desired_result=True)\n    assert s.measure_many(0, 1, 2) == [True, True, True]\n\n\ndef test_measure_kickback_random_branches():\n    s = stim.TableauSimulator()\n    s.set_inverse_tableau(stim.Tableau.random(8))\n\n    r = s.peek_bloch(4)\n    if r[0] == 3:  # +-Z?\n        assert s.measure_kickback(4) == (r.sign == -1, None)\n        return\n\n    post_false = None\n    post_true = None\n    for _ in range(100):\n        if post_false is not None and post_true is not None:\n            break\n        s2 = s.copy()\n        if s2.measure(4):\n            post_true = s2\n        else:\n            post_false = s2\n    assert post_false is not None and post_true is not None\n\n    result, kick = s.measure_kickback(4)\n    assert isinstance(kick, stim.PauliString) and len(kick) == 8\n    if result:\n        s.do(kick)\n    assert s.canonical_stabilizers() == post_false.canonical_stabilizers()\n    s.do(kick)\n    assert s.canonical_stabilizers() == post_true.canonical_stabilizers()\n\n\ndef test_set_num_qubits():\n    s = stim.TableauSimulator()\n    s.h(0)\n    s.cnot(0, 1)\n    s.cnot(0, 2)\n    s.cnot(0, 3)\n    t = s.current_inverse_tableau()\n    s.set_num_qubits(8)\n    s.set_num_qubits(4)\n    assert s.current_inverse_tableau() == t\n    assert s.peek_bloch(0) == stim.PauliString(\"_\")\n    s.set_num_qubits(8)\n    s.set_num_qubits(4)\n    s.cnot(0, 4)\n    s.set_num_qubits(4)\n    assert s.peek_bloch(0) in [stim.PauliString(\"+Z\"), stim.PauliString(\"-Z\")]\n\n\ndef test_canonical_stabilizers():\n    s = stim.TableauSimulator()\n    s.h(0)\n    s.h(1)\n    s.h(2)\n    s.cz(0, 1)\n    s.cz(1, 2)\n    assert s.canonical_stabilizers() == [\n        stim.PauliString(\"+X_X\"),\n        stim.PauliString(\"+ZXZ\"),\n        stim.PauliString(\"+_ZX\"),\n    ]\n    s.s(1)\n    assert s.canonical_stabilizers() == [\n        stim.PauliString(\"+X_X\"),\n        stim.PauliString(\"-ZXY\"),\n        stim.PauliString(\"+_ZX\"),\n    ]\n\n\ndef test_classical_control_cnot():\n    s = stim.TableauSimulator()\n\n    with pytest.raises(IndexError, match=\"beginning of time\"):\n        s.cnot(stim.target_rec(-1), 0)\n\n    assert not s.measure(1)\n    s.cnot(stim.target_rec(-1), 0)\n    assert not s.measure(0)\n\n    s.x(1)\n    assert s.measure(1)\n    s.cnot(stim.target_rec(-1), 0)\n    assert s.measure(0)\n\n\ndef test_collision():\n    s = stim.TableauSimulator()\n    with pytest.raises(ValueError, match=\"same target\"):\n        s.cnot(0, 0)\n    with pytest.raises(ValueError, match=\"same target\"):\n        s.swap(0, 1, 2, 2)\n    s.swap(0, 2, 2, 1)\n\n\ndef is_parallel_state_vector(actual, expected) -> bool:\n    actual = np.array(actual, dtype=np.complex64)\n    expected = np.array(expected, dtype=np.complex64)\n    assert len(expected.shape) == 1\n    if actual.shape != expected.shape:\n        return False\n    assert abs(np.linalg.norm(actual) - 1) < 1e-4\n    assert abs(np.linalg.norm(expected) - 1) < 1e-4\n    return abs(abs(np.dot(actual, np.conj(expected))) - 1) < 1e-4\n\n\ndef test_is_parallel_state_vector():\n    assert is_parallel_state_vector([1], [1])\n    assert is_parallel_state_vector([1], [1j])\n    assert is_parallel_state_vector([1j], [1])\n    assert not is_parallel_state_vector([1], [1, 2])\n    assert is_parallel_state_vector([0.5, 0.5, 0.5, 0.5], [0.5, 0.5, 0.5, 0.5])\n    assert is_parallel_state_vector([0.5, 0.5, 0.5, 0.5], [0.5j, 0.5j, 0.5j, 0.5j])\n    assert is_parallel_state_vector([0.5, 0.5, 0.5, 0.5], [-0.5j, -0.5j, -0.5j, -0.5j])\n    assert not is_parallel_state_vector([0.5, 0.5, 0.5, 0.5], [-0.5j, -0.5j, -0.5j, 0.5j])\n    assert not is_parallel_state_vector([0.5, 0.5, 0.5, 0.5], [1, 0, 0, 0])\n\n\ndef test_to_state_vector():\n    s = stim.TableauSimulator()\n    assert is_parallel_state_vector(s.state_vector(), [1])\n    s.set_num_qubits(1)\n    assert is_parallel_state_vector(s.state_vector(), [1, 0])\n    s.set_num_qubits(2)\n    s.x(0)\n    assert is_parallel_state_vector(s.state_vector(), [0, 1, 0, 0])\n    s.h(1)\n    assert is_parallel_state_vector(s.state_vector(), [0, 0.5**0.5, 0, 0.5**0.5])\n    s.h(0)\n    assert is_parallel_state_vector(s.state_vector(), [0.5, -0.5, 0.5, -0.5])\n    s.cnot(1, 0)\n    assert is_parallel_state_vector(s.state_vector(), [0.5, -0.5, -0.5, 0.5])\n    s.x(2)\n    assert is_parallel_state_vector(s.state_vector(), [0, 0, 0, 0, 0.5, -0.5, -0.5, 0.5])\n    v = s.state_vector().reshape((2,) * 3)\n    assert v[0, 0, 0] == 0\n    assert v[1, 0, 0] != 0\n    assert v[0, 1, 0] == 0\n    assert v[0, 0, 1] == 0\n\n    s = stim.TableauSimulator()\n    s.set_num_qubits(3)\n    s.sqrt_x(2)\n    np.testing.assert_allclose(\n        s.state_vector(endian='little'),\n        [np.sqrt(0.5), 0, 0, 0, -1j*np.sqrt(0.5), 0, 0, 0],\n        atol=1e-4,\n    )\n    np.testing.assert_allclose(\n        s.state_vector(endian='big'),\n        [np.sqrt(0.5), -1j*np.sqrt(0.5), 0, 0, 0, 0, 0, 0],\n        atol=1e-4,\n    )\n    with pytest.raises(ValueError, match=\"endian\"):\n        s.state_vector(endian='unknown')\n\n    # Exact precision.\n    s.h(1)\n    np.testing.assert_array_equal(\n        s.state_vector(),\n        [0.5, 0, 0.5, 0, -0.5j, 0, -0.5j, 0],\n    )\n\n\ndef test_peek_observable_expectation():\n    s = stim.TableauSimulator()\n    s.do(stim.Circuit('''\n        H 0\n        CNOT 0 1 0 2\n        X 0\n    '''))\n\n    assert s.peek_observable_expectation(stim.PauliString(\"ZZ_\")) == -1\n    assert s.peek_observable_expectation(stim.PauliString(\"_ZZ\")) == 1\n    assert s.peek_observable_expectation(stim.PauliString(\"Z_Z\")) == -1\n    assert s.peek_observable_expectation(stim.PauliString(\"XXX\")) == 1\n    assert s.peek_observable_expectation(stim.PauliString(\"-XXX\")) == -1\n    assert s.peek_observable_expectation(stim.PauliString(\"YYX\")) == +1\n    assert s.peek_observable_expectation(stim.PauliString(\"XYY\")) == -1\n\n    assert s.peek_observable_expectation(stim.PauliString(\"\")) == 1\n    assert s.peek_observable_expectation(stim.PauliString(\"-I\")) == -1\n    assert s.peek_observable_expectation(stim.PauliString(\"_____\")) == 1\n    assert s.peek_observable_expectation(stim.PauliString(\"XXXZZZZZ\")) == 1\n    assert s.peek_observable_expectation(stim.PauliString(\"XXXZZZZX\")) == 0\n\n    with pytest.raises(ValueError, match=\"imaginary sign\"):\n        s.peek_observable_expectation(stim.PauliString(\"iZZ\"))\n    with pytest.raises(ValueError, match=\"imaginary sign\"):\n        s.peek_observable_expectation(stim.PauliString(\"-iZZ\"))\n\n\ndef test_postselect():\n    s = stim.TableauSimulator()\n    s.h(0)\n    s.cnot(0, 1)\n    s.postselect_x(0, desired_value=False)\n    assert s.peek_bloch(0) == stim.PauliString(\"+X\")\n    assert s.peek_bloch(1) == stim.PauliString(\"+X\")\n\n    s.postselect_y([2, 3, 4], desired_value=False)\n    assert s.peek_bloch(4) == stim.PauliString(\"+Y\")\n    s.postselect_x(8, desired_value=True)\n    assert s.peek_bloch(8) == stim.PauliString(\"-X\")\n\n    s.postselect_z(9, desired_value=False)\n    assert s.peek_bloch(9) == stim.PauliString(\"+Z\")\n    with pytest.raises(ValueError, match=\"impossible\"):\n        s.postselect_z(10, desired_value=True)\n\n    s.postselect_y(1000, desired_value=True)\n    assert s.peek_bloch(1000) == stim.PauliString(\"-Y\")\n\n\ndef test_peek_pauli():\n    s = stim.TableauSimulator()\n    assert s.peek_x(0) == 0\n    assert s.peek_y(0) == 0\n    assert s.peek_z(0) == +1\n\n    assert s.peek_x(1000) == 0\n    assert s.peek_y(1000) == 0\n    assert s.peek_z(1000) == +1\n\n    s.h(100)\n    s.z(100)\n    assert s.peek_x(100) == -1\n    assert s.peek_y(100) == 0\n    assert s.peek_z(100) == 0\n\n    s.h_xy(100)\n    assert s.peek_x(100) == 0\n    assert s.peek_y(100) == -1\n    assert s.peek_z(100) == 0\n\n\ndef test_do_circuit():\n    s = stim.TableauSimulator()\n    s.do_circuit(stim.Circuit(\"\"\"\n        H 0\n    \"\"\"))\n    assert s.peek_bloch(0) == stim.PauliString('+X')\n\n\ndef test_do_pauli_string():\n    s = stim.TableauSimulator()\n    s.do_pauli_string(stim.PauliString(\"IXYZ\"))\n    assert s.peek_bloch(0) == stim.PauliString('+Z')\n    assert s.peek_bloch(1) == stim.PauliString('-Z')\n    assert s.peek_bloch(2) == stim.PauliString('-Z')\n    assert s.peek_bloch(3) == stim.PauliString('+Z')\n\n\ndef test_do_tableau():\n    s = stim.TableauSimulator()\n    s.do_tableau(stim.Tableau.from_named_gate(\"H\"), [0])\n    assert s.peek_bloch(0) == stim.PauliString('+X')\n    s.do_tableau(stim.Tableau.from_named_gate(\"CNOT\"), [0, 1])\n    assert s.peek_bloch(0) == stim.PauliString('+I')\n    assert s.peek_observable_expectation(stim.PauliString('XX')) == +1\n    assert s.peek_observable_expectation(stim.PauliString('ZZ')) == +1\n\n    with pytest.raises(ValueError, match='len'):\n        s.do_tableau(stim.Tableau(1), [1, 2])\n    with pytest.raises(ValueError, match='duplicates'):\n        s.do_tableau(stim.Tableau(3), [2, 3, 2])\n\n    s.do_tableau(stim.Tableau(0), [])\n\n\ndef test_c_xyz_zyx():\n    s = stim.TableauSimulator()\n    s.c_xyz(0, 2)\n    s.c_zyx(1, 2)\n    assert s.peek_bloch(0) == stim.PauliString(\"X\")\n    assert s.peek_bloch(1) == stim.PauliString(\"Y\")\n    assert s.peek_bloch(2) == stim.PauliString(\"Z\")\n\n\ndef test_gate_aliases():\n    s = stim.TableauSimulator()\n    s.h_xz(0)\n    assert s.peek_bloch(0) == stim.PauliString(\"X\")\n\n    s.zcx(0, 1)\n    assert s.canonical_stabilizers() == [\n        stim.PauliString(\"+XX\"),\n        stim.PauliString(\"+ZZ\")\n    ]\n    s.cx(0, 1)\n    assert s.canonical_stabilizers() == [\n        stim.PauliString(\"+X_\"),\n        stim.PauliString(\"+_Z\")\n    ]\n\n    s.zcy(0, 1)\n    assert s.canonical_stabilizers() == [\n        stim.PauliString(\"+XY\"),\n        stim.PauliString(\"+ZZ\")\n    ]\n\n    s.zcz(0, 1)\n    assert s.canonical_stabilizers() == [\n        stim.PauliString(\"-XY\"),\n        stim.PauliString(\"+ZZ\")\n    ]\n\n\ndef test_num_qubits():\n    s = stim.TableauSimulator()\n    assert s.num_qubits == 0\n    s.cx(3, 1)\n    assert s.num_qubits == 4\n\n\ndef test_set_state_from_state_vector():\n    s = stim.TableauSimulator()\n    expected = [0.5, 0.5, 0, 0, -0.5, 0.5, 0, 0]\n    s.set_state_from_state_vector(expected, endian='little')\n    np.testing.assert_allclose(s.state_vector(), expected, atol=1e-6)\n\n\ndef test_set_state_from_stabilizers():\n    s = stim.TableauSimulator()\n    s.set_state_from_stabilizers([])\n    assert s.current_inverse_tableau() == stim.Tableau(0)\n    s.set_state_from_stabilizers([stim.PauliString(\"XXX\"), stim.PauliString(\"_ZZ\"), stim.PauliString(\"ZZ_\")])\n    np.testing.assert_allclose(s.state_vector(), [0.5**0.5, 0, 0, 0, 0, 0, 0, 0.5**0.5], atol=1e-6)\n\n\ndef test_seed():\n    ss1 = [stim.TableauSimulator(seed=0) for _ in range(5)]\n    ss2 = [stim.TableauSimulator(seed=1) for _ in range(5)]\n\n    def hadamard_and_measure(sim, reps=5):\n        \"\"\"Repeats Hadamard+measurement reps times and returns result as reps-bit integer.\"\"\"\n        r, v = 0, 1\n        for _ in range(reps):\n            sim.h(0)\n            r += v * sim.measure(0)\n            v *= 2\n        return r\n\n    ms1 = {hadamard_and_measure(sim) for sim in ss1}\n    ms2 = {hadamard_and_measure(sim) for sim in ss2}\n\n    assert len(ms1) == 1\n    assert len(ms2) == 1\n    assert ms1 != ms2\n\n\ndef test_copy_without_fresh_entropy():\n    s1 = stim.TableauSimulator(seed=0)\n    s2 = s1.copy(copy_rng=True)\n\n    for _ in range(100):\n        s1.h(0)\n        s2.h(0)\n        assert s1.measure(0) == s2.measure(0)\n\n\ndef test_copy_with_fresh_entropy():\n    s1 = stim.TableauSimulator(seed=0)\n    s2 = s1.copy()\n\n    eq = set()\n    for _ in range(100):\n        s1.h(0)\n        s2.h(0)\n        eq.add(s1.measure(0) == s2.measure(0))\n    assert eq == {False, True}\n\n\ndef test_copy_with_explicit_seed():\n    s1 = stim.TableauSimulator(seed=0)\n    s2 = stim.TableauSimulator(seed=1)\n    s3 = s1.copy(seed=1)\n\n    eq = set()\n    for _ in range(100):\n        s1.h(0)\n        s2.h(0)\n        s3.h(0)\n        m1 = s1.measure(0)\n        m2 = s2.measure(0)\n        m3 = s3.measure(0)\n        assert m2 == m3\n        eq.add(m1 == m3)\n\n    assert eq == {False, True}\n\n\ndef test_copy_with_explicit_copy_rng_and_seed():\n    s = stim.TableauSimulator()\n    with pytest.raises(ValueError, match='seed and copy_rng are incompatible'):\n        _ = s.copy(copy_rng=True, seed=0)\n\n\ndef test_do_circuit_instruction():\n    s = stim.TableauSimulator()\n    assert s.peek_z(0) == +1\n    s.do(stim.Circuit(\"X 0\")[0])\n    assert s.peek_z(0) == -1\n\n    s.do(stim.Circuit(\"\"\"\n        REPEAT 100 {\n            CNOT 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 0\n        }\n    \"\"\")[0])\n    assert s.peek_z(0) == +1\n    assert s.peek_z(1) == +1\n    assert s.peek_z(2) == +1\n    assert s.peek_z(3) == -1\n    assert s.peek_z(4) == +1\n    assert s.peek_z(5) == -1\n    assert s.peek_z(6) == +1\n    assert s.peek_z(7) == +1\n\n    s.do(stim.Circuit(\"X 500\")[0])\n    assert s.peek_z(499) == +1\n    assert s.peek_z(500) == -1\n    assert s.peek_z(501) == +1\n\n\ndef test_measure_observable():\n    s = stim.TableauSimulator()\n\n    with pytest.raises(ValueError, match=\"0 <= flip\"):\n        s.measure_observable(stim.PauliString(\"XX\"), flip_probability=-0.1)\n    with pytest.raises(ValueError, match=\"Hermitian\"):\n        s.measure_observable(stim.PauliString(\"iXX\"))\n\n    s.h(0)\n    s.cnot(0, 1)\n    assert not s.measure_observable(stim.PauliString(\"ZZ\"))\n    assert s.measure_observable(stim.PauliString(\"YY\"))\n    assert s.measure_observable(stim.PauliString(\"-\"))\n    assert not s.measure_observable(stim.PauliString(0))\n    assert not s.measure_observable(stim.PauliString(2))\n    assert not s.measure_observable(stim.PauliString(5))\n    n = sum(s.measure_observable(stim.PauliString(0), flip_probability=0.1) for _ in range(1000))\n    assert 25 <= n <= 300\n\n\ndef test_x_error():\n    s = stim.TableauSimulator()\n    assert s.peek_bloch(0) == stim.PauliString(\"+Z\")\n    s.x_error(0, 1, 2, p=0)\n    assert s.peek_bloch(0) == stim.PauliString(\"+Z\")\n    s.x_error(0, p=1)\n    assert s.peek_bloch(0) == stim.PauliString(\"-Z\")\n\n\ndef test_z_error():\n    s = stim.TableauSimulator()\n    s.reset_x(0)\n    assert s.peek_bloch(0) == stim.PauliString(\"+X\")\n    s.z_error(0, p=0)\n    assert s.peek_bloch(0) == stim.PauliString(\"+X\")\n    s.z_error(0, p=1)\n    assert s.peek_bloch(0) == stim.PauliString(\"-X\")\n\n\ndef test_y_error():\n    s = stim.TableauSimulator()\n    s.reset_y(0)\n    assert s.peek_bloch(0) == stim.PauliString(\"+Y\")\n    s.x_error(0, p=0)\n    assert s.peek_bloch(0) == stim.PauliString(\"+Y\")\n    s.x_error(0, p=1)\n    assert s.peek_bloch(0) == stim.PauliString(\"-Y\")\n\n\ndef test_depolarize1_error():\n    s = stim.TableauSimulator()\n    s.h(0)\n    s.cnot(0, 1)\n    t = s.current_inverse_tableau()\n    s.depolarize1(0, p=0)\n    assert s.current_inverse_tableau() == t\n    s.depolarize1(0, p=1)\n    assert s.current_inverse_tableau() != t\n\n\ndef test_depolarize2_error():\n    s = stim.TableauSimulator()\n    s.h(0, 1)\n    s.cnot(0, 2, 1, 3)\n    t = s.current_inverse_tableau()\n    s.depolarize2(0, 1, p=0)\n    assert s.current_inverse_tableau() == t\n    with pytest.raises(ValueError, match='Two qubit'):\n        s.depolarize2(1, p=1)\n    assert s.current_inverse_tableau() == t\n    s.depolarize2(0, 1, p=1)\n    assert s.current_inverse_tableau() != t\n\n    with pytest.raises(ValueError, match='Unexpected argument'):\n        s.depolarize2(1, p=1, q=2)\n\n\ndef test_bad_inverse_padding_issue_is_fixed():\n    circuit = stim.Circuit()\n    circuit.append(\"H\", range(467))\n    sim = stim.TableauSimulator()\n    sim.do(circuit)\n    stabs = sim.canonical_stabilizers()\n    assert stabs[-1] == stim.PauliString(466 * '_' + 'X')\n\n\ndef test_postselect_observable():\n    sim = stim.TableauSimulator()\n    assert sim.peek_bloch(0) == stim.PauliString(\"+Z\")\n\n    sim.postselect_observable(stim.PauliString(\"+X\"))\n    assert sim.peek_bloch(0) == stim.PauliString(\"+X\")\n\n    sim.postselect_observable(stim.PauliString(\"+Z\"))\n    assert sim.peek_bloch(0) == stim.PauliString(\"+Z\")\n\n    sim.postselect_observable(stim.PauliString(\"-X\"))\n    assert sim.peek_bloch(0) == stim.PauliString(\"-X\")\n\n    sim.postselect_observable(stim.PauliString(\"+Z\"))\n    assert sim.peek_bloch(0) == stim.PauliString(\"+Z\")\n\n    sim.postselect_observable(stim.PauliString(\"-X\"), desired_value=True)\n    assert sim.peek_bloch(0) == stim.PauliString(\"+X\")\n\n    with pytest.raises(ValueError, match=\"impossible\"):\n        sim.postselect_observable(stim.PauliString(\"-X\"))\n    assert sim.peek_bloch(0) == stim.PauliString(\"+X\")\n\n    with pytest.raises(ValueError, match=\"imaginary sign\"):\n        sim.postselect_observable(stim.PauliString(\"iZ\"))\n    assert sim.peek_bloch(0) == stim.PauliString(\"+X\")\n\n    sim.postselect_observable(stim.PauliString(\"+XX\"))\n    sim.postselect_observable(stim.PauliString(\"+ZZ\"))\n    assert sim.peek_observable_expectation(stim.PauliString(\"+YY\")) == -1\n"
  },
  {
    "path": "src/stim/simulators/vector_simulator.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/vector_simulator.h\"\n\n#include <cassert>\n\n#include \"stim/gates/gates.h\"\n#include \"stim/mem/simd_util.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nusing namespace stim;\n\nVectorSimulator::VectorSimulator(size_t num_qubits) {\n    state.resize(size_t{1} << num_qubits, 0.0f);\n    state[0] = 1;\n}\n\ninline std::vector<std::complex<float>> mat_vec_mul(\n    const std::vector<std::vector<std::complex<float>>> &matrix, const std::vector<std::complex<float>> &vec) {\n    std::vector<std::complex<float>> result;\n    for (size_t row = 0; row < vec.size(); row++) {\n        std::complex<float> v = 0;\n        for (size_t col = 0; col < vec.size(); col++) {\n            v += matrix[row][col] * vec[col];\n        }\n        result.push_back(v);\n    }\n    return result;\n}\n\nvoid VectorSimulator::apply(\n    const std::vector<std::vector<std::complex<float>>> &matrix, const std::vector<size_t> &qubits) {\n    size_t n = size_t{1} << qubits.size();\n    assert(matrix.size() == n);\n    std::vector<size_t> masks;\n    for (size_t k = 0; k < n; k++) {\n        size_t m = 0;\n        for (size_t q = 0; q < qubits.size(); q++) {\n            if ((k >> q) & 1) {\n                m |= size_t{1} << qubits[q];\n            }\n        }\n        masks.push_back(m);\n    }\n    assert(masks.back() < state.size());\n    for (size_t base = 0; base < state.size(); base++) {\n        if (base & masks.back()) {\n            continue;\n        }\n        std::vector<std::complex<float>> in;\n        in.reserve(masks.size());\n        for (auto m : masks) {\n            in.push_back(state[base | m]);\n        }\n        auto out = mat_vec_mul(matrix, in);\n        for (size_t k = 0; k < masks.size(); k++) {\n            state[base | masks[k]] = out[k];\n        }\n    }\n}\n\nvoid VectorSimulator::apply(GateType gate, size_t qubit) {\n    try {\n        apply(GATE_DATA[gate].unitary(), {qubit});\n    } catch (const std::out_of_range &) {\n        throw std::out_of_range(\n            \"Single qubit gate isn't supported by VectorSimulator: \" + std::string(GATE_DATA[gate].name));\n    }\n}\n\nvoid VectorSimulator::apply(GateType gate, size_t qubit1, size_t qubit2) {\n    try {\n        apply(GATE_DATA[gate].unitary(), {qubit1, qubit2});\n    } catch (const std::out_of_range &) {\n        throw std::out_of_range(\n            \"Two qubit gate isn't supported by VectorSimulator: \" + std::string(GATE_DATA[gate].name));\n    }\n}\n\nvoid VectorSimulator::smooth_stabilizer_state(std::complex<float> base_value) {\n    std::vector<std::complex<float>> ratio_values{\n        {0, 0},\n        {1, 0},\n        {-1, 0},\n        {0, 1},\n        {0, -1},\n    };\n    for (size_t k = 0; k < state.size(); k++) {\n        auto ratio = state[k] / base_value;\n        bool solved = false;\n        for (const auto &r : ratio_values) {\n            if (std::norm(ratio - r) < 0.125) {\n                state[k] = r;\n                solved = true;\n            }\n        }\n        if (!solved) {\n            throw std::invalid_argument(\"The state vector wasn't a stabilizer state.\");\n        }\n    }\n}\n\nbool VectorSimulator::approximate_equals(const VectorSimulator &other, bool up_to_global_phase) const {\n    if (state.size() != other.state.size()) {\n        return false;\n    }\n    std::complex<float> dot = 0;\n    float mag1 = 0;\n    float mag2 = 0;\n    for (size_t k = 0; k < state.size(); k++) {\n        auto c = state[k];\n        auto c2 = other.state[k];\n        dot += c * std::conj(c2);\n        mag1 += c.real() * c.real() + c.imag() * c.imag();\n        mag2 += c2.real() * c2.real() + c2.imag() * c2.imag();\n    }\n    assert(1 - 1e-4 <= mag1 && mag1 <= 1 + 1e-4);\n    assert(1 - 1e-4 <= mag2 && mag2 <= 1 + 1e-4);\n    float f;\n    if (up_to_global_phase) {\n        f = dot.real() * dot.real() + dot.imag() * dot.imag();\n    } else {\n        f = dot.real();\n    }\n    return 1 - 1e-4 <= f && f <= 1 + 1e-4;\n}\n\nstd::string VectorSimulator::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const VectorSimulator &sim) {\n    out << \"VectorSimulator {\\n\";\n    for (size_t k = 0; k < sim.state.size(); k++) {\n        out << \"    \" << k << \": \" << sim.state[k] << \"\\n\";\n    }\n    out << \"}\";\n    return out;\n}\n\nvoid VectorSimulator::canonicalize_assuming_stabilizer_state(double norm2) {\n    // Find a solid non-zero entry.\n    size_t nz = 0;\n    for (size_t k = 1; k < state.size(); k++) {\n        if (abs(state[k]) > abs(state[nz]) * 2) {\n            nz = k;\n        }\n    }\n\n    // Rescale so that the non-zero entries are 1, -1, 1j, or -1j.\n    size_t num_non_zero = 0;\n    std::complex<float> big_v = state[nz];\n    for (auto &v : state) {\n        v /= big_v;\n        if (abs(v) < 0.1) {\n            v = 0;\n            continue;\n        }\n        num_non_zero++;\n        if (abs(v - std::complex<float>{1, 0}) < 0.1) {\n            v = std::complex<float>{1, 0};\n        } else if (abs(v - std::complex<float>{0, 1}) < 0.1) {\n            v = std::complex<float>{0, 1};\n        } else if (abs(v - std::complex<float>{-1, 0}) < 0.1) {\n            v = std::complex<float>{-1, 0};\n        } else if (abs(v - std::complex<float>{0, -1}) < 0.1) {\n            v = std::complex<float>{0, -1};\n        } else {\n            throw std::invalid_argument(\"State vector extraction failed. This shouldn't occur.\");\n        }\n    }\n\n    // Normalize the entries so the result is a unit vector.\n    std::complex<float> scale = (float)(sqrt(norm2 / (double)num_non_zero));\n    for (auto &v : state) {\n        v *= scale;\n    }\n}\n\nvoid VectorSimulator::do_unitary_circuit(const Circuit &circuit) {\n    std::vector<size_t> targets1{1};\n    std::vector<size_t> targets2{1, 2};\n    circuit.for_each_operation([&](const CircuitInstruction &op) {\n        const auto &gate_data = GATE_DATA[op.gate_type];\n        if (!(gate_data.flags & GATE_IS_UNITARY)) {\n            std::stringstream ss;\n            ss << \"Not a unitary gate: \" << gate_data.name;\n            throw std::invalid_argument(ss.str());\n        }\n        auto unitary = gate_data.unitary();\n        for (auto t : op.targets) {\n            if (!t.is_qubit_target() || (size_t{1} << t.data) >= state.size()) {\n                std::stringstream ss;\n                ss << \"Targets out of range: \" << op;\n                throw std::invalid_argument(ss.str());\n            }\n        }\n        if (gate_data.flags & stim::GATE_TARGETS_PAIRS) {\n            for (size_t k = 0; k < op.targets.size(); k += 2) {\n                targets2[0] = (size_t)op.targets[k].data;\n                targets2[1] = (size_t)op.targets[k + 1].data;\n                apply(unitary, targets2);\n            }\n        } else {\n            for (auto t : op.targets) {\n                targets1[0] = (size_t)t.data;\n                apply(unitary, targets1);\n            }\n        }\n    });\n}\n"
  },
  {
    "path": "src/stim/simulators/vector_simulator.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_SIMULATORS_VECTOR_SIMULATOR_H\n#define _STIM_SIMULATORS_VECTOR_SIMULATOR_H\n\n#include <complex>\n#include <iostream>\n#include <random>\n#include <unordered_map>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/mem/simd_word.h\"\n#include \"stim/util_bot/probability_util.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nstruct PauliStringRef;\n\ntemplate <size_t W>\nstruct PauliString;\n\n/// A state vector quantum circuit simulator.\n///\n/// Not intended to be particularly performant. Mostly used as a reference when testing.\nstruct VectorSimulator {\n    std::vector<std::complex<float>> state;\n\n    /// Creates a state vector for the given number of qubits, initialized to the zero state.\n    explicit VectorSimulator(size_t num_qubits);\n\n    /// Returns a VectorSimulator with a state vector satisfying all the given stabilizers.\n    ///\n    /// Assumes the stabilizers commute. Works by generating a random state vector and projecting onto\n    /// each of the given stabilizers. Global phase will vary.\n    template <size_t W>\n    static VectorSimulator from_stabilizers(const std::vector<PauliStringRef<W>> &stabilizers) {\n        VectorSimulator result(0);\n        result.state = state_vector_from_stabilizers(stabilizers, 1);\n        return result;\n    }\n\n    template <size_t W>\n    static std::vector<std::complex<float>> state_vector_from_stabilizers(\n        const std::vector<PauliStringRef<W>> &stabilizers, float norm2 = 1) {\n        size_t num_qubits = stabilizers.empty() ? 0 : stabilizers[0].num_qubits;\n        VectorSimulator sim(num_qubits);\n\n        // Create an initial state $|A\\rangle^{\\otimes n}$ which overlaps with all possible stabilizers.\n        std::uniform_real_distribution<float> dist(-1.0, +1.0);\n\n        auto rng = externally_seeded_rng();\n        for (auto &s : sim.state) {\n            s = {dist(rng), dist(rng)};\n        }\n\n        // Project out the non-overlapping parts.\n        for (const auto &p : stabilizers) {\n            sim.project<W>(p);\n        }\n        if (stabilizers.empty()) {\n            sim.project<W>(PauliString<W>(0));\n        }\n\n        sim.canonicalize_assuming_stabilizer_state(norm2);\n\n        return sim.state;\n    }\n\n    /// Applies a unitary operation to the given qubits, updating the state vector.\n    void apply(const std::vector<std::vector<std::complex<float>>> &matrix, const std::vector<size_t> &qubits);\n\n    /// Helper method for applying named single qubit gates.\n    void apply(GateType gate, size_t qubit);\n    /// Helper method for applying named two qubit gates.\n    void apply(GateType gate, size_t qubit1, size_t qubit2);\n\n    /// Helper method for applying the gates in a Pauli string.\n    template <size_t W>\n    void apply(const PauliStringRef<W> &gate, size_t qubit_offset) {\n        if (gate.sign) {\n            for (auto &e : state) {\n                e *= -1;\n            }\n        }\n        for (size_t k = 0; k < gate.num_qubits; k++) {\n            bool x = gate.xs[k];\n            bool z = gate.zs[k];\n            size_t q = qubit_offset + k;\n            if (x && z) {\n                apply(GateType::Y, q);\n            } else if (x) {\n                apply(GateType::X, q);\n            } else if (z) {\n                apply(GateType::Z, q);\n            }\n        }\n    }\n\n    /// Applies the unitary operations within a circuit to the simulator's state.\n    void do_unitary_circuit(const Circuit &circuit);\n\n    /// Modifies the state vector to be EXACTLY entries of 0, 1, -1, i, or -i.\n    ///\n    /// Each entry is a ratio relative to the given base value.\n    /// If any entry has a ratio not near the desired set, an exception is raised.\n    void smooth_stabilizer_state(std::complex<float> base_value);\n\n    /// Projects the state vector into the +1 eigenstate of the given observable, and renormalizes.\n    ///\n    /// Returns:\n    ///     The 2-norm of the component of the state vector that was already in the +1 eigenstate.\n    ///     In other words, the probability that measuring the observable would have returned +1 instead of -1.\n    template <size_t W>\n    float project(const PauliStringRef<W> &observable) {\n        assert(1ULL << observable.num_qubits == state.size());\n        auto basis_change = [&]() {\n            for (size_t k = 0; k < observable.num_qubits; k++) {\n                if (observable.xs[k]) {\n                    if (observable.zs[k]) {\n                        apply(GateType::H_YZ, k);\n                    } else {\n                        apply(GateType::H, k);\n                    }\n                }\n            }\n        };\n\n        uint64_t mask = 0;\n        for (size_t k = 0; k < observable.num_qubits; k++) {\n            if (observable.xs[k] || observable.zs[k]) {\n                mask |= 1ULL << k;\n            }\n        }\n\n        basis_change();\n        float mag2 = 0;\n        for (size_t i = 0; i < state.size(); i++) {\n            bool reject = observable.sign;\n            reject ^= (std::popcount(i & mask) & 1) != 0;\n            if (reject) {\n                state[i] = 0;\n            } else {\n                mag2 += state[i].real() * state[i].real() + state[i].imag() * state[i].imag();\n            }\n        }\n        assert(mag2 > 1e-8);\n        auto w = sqrtf(mag2);\n        for (size_t i = 0; i < state.size(); i++) {\n            state[i] /= w;\n        }\n        basis_change();\n        return mag2;\n    }\n\n    /// Determines if two vector simulators have similar state vectors.\n    bool approximate_equals(const VectorSimulator &other, bool up_to_global_phase = false) const;\n\n    /// A description of the state vector's state.\n    std::string str() const;\n\n    void canonicalize_assuming_stabilizer_state(double norm2);\n};\n\n/// Writes a description of the state vector's state to an output stream.\nstd::ostream &operator<<(std::ostream &out, const VectorSimulator &sim);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/simulators/vector_simulator.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/simulators/vector_simulator.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gates/gates.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nusing namespace stim;\n\nstatic float complex_distance(std::complex<float> a, std::complex<float> b) {\n    auto d = a - b;\n    return sqrtf(d.real() * d.real() + d.imag() * d.imag());\n}\n\n#define ASSERT_NEAR_C(a, b) ASSERT_LE(complex_distance(a, b), 1e-4)\n\nTEST(vector_sim, qubit_order) {\n    VectorSimulator sim(2);\n    sim.apply(GateType::H, 0);\n    sim.apply(GateType::CX, 0, 1);\n    ASSERT_NEAR_C(sim.state[0], sqrtf(0.5));\n    ASSERT_NEAR_C(sim.state[1], 0);\n    ASSERT_NEAR_C(sim.state[2], 0);\n    ASSERT_NEAR_C(sim.state[3], sqrtf(0.5));\n}\n\nTEST(vector_sim, h_squared) {\n    VectorSimulator sim(1);\n    sim.apply(GateType::H, 0);\n    sim.apply(GateType::H, 0);\n    ASSERT_NEAR_C(sim.state[0], 1);\n    ASSERT_NEAR_C(sim.state[1], 0);\n}\n\nTEST(vector_sim, sqrt_x_squared) {\n    VectorSimulator sim(1);\n    sim.apply(GateType::SQRT_X_DAG, 0);\n    sim.apply(GateType::SQRT_X_DAG, 0);\n    ASSERT_NEAR_C(sim.state[0], 0);\n    ASSERT_NEAR_C(sim.state[1], 1);\n}\n\nTEST(vector_sim, state_channel_duality_cnot) {\n    VectorSimulator sim(4);\n    sim.apply(GateType::H, 0);\n    sim.apply(GateType::H, 1);\n    sim.apply(GateType::CX, 0, 2);\n    sim.apply(GateType::CX, 1, 3);\n    sim.apply(GateType::CX, 2, 3);\n    auto u = GATE_DATA.at(\"ZCX\").unitary();\n    for (size_t row = 0; row < 4; row++) {\n        for (size_t col = 0; col < 4; col++) {\n            ASSERT_NEAR_C(sim.state[row * 4 + col], u[row][col] * 0.5f);\n        }\n    }\n}\n\nTEST(vector_sim, state_channel_duality_y) {\n    VectorSimulator sim(2);\n    sim.apply(GateType::H, 0);\n    sim.apply(GateType::CX, 0, 1);\n    sim.apply(GateType::Y, 1);\n    auto u = GATE_DATA.at(\"Y\").unitary();\n    for (size_t row = 0; row < 2; row++) {\n        for (size_t col = 0; col < 2; col++) {\n            ASSERT_NEAR_C(sim.state[row * 2 + col], u[row][col] * sqrtf(0.5f));\n        }\n    }\n}\n\nTEST_EACH_WORD_SIZE_W(vector_sim, apply_pauli, {\n    VectorSimulator sim(2);\n\n    sim.apply(PauliString<W>::from_str(\"+II\").ref(), 0);\n    ASSERT_NEAR_C(sim.state[0], 1);\n    ASSERT_NEAR_C(sim.state[1], 0);\n    ASSERT_NEAR_C(sim.state[2], 0);\n    ASSERT_NEAR_C(sim.state[3], 0);\n\n    sim.apply(PauliString<W>::from_str(\"-II\").ref(), 0);\n    ASSERT_NEAR_C(sim.state[0], -1);\n    ASSERT_NEAR_C(sim.state[1], 0);\n    ASSERT_NEAR_C(sim.state[2], 0);\n    ASSERT_NEAR_C(sim.state[3], 0);\n\n    sim.apply(PauliString<W>::from_str(\"+XI\").ref(), 0);\n    ASSERT_NEAR_C(sim.state[0], 0);\n    ASSERT_NEAR_C(sim.state[1], -1);\n    ASSERT_NEAR_C(sim.state[2], 0);\n    ASSERT_NEAR_C(sim.state[3], 0);\n\n    sim.apply(PauliString<W>::from_str(\"+IZ\").ref(), 0);\n    ASSERT_NEAR_C(sim.state[0], 0);\n    ASSERT_NEAR_C(sim.state[1], -1);\n    ASSERT_NEAR_C(sim.state[2], 0);\n    ASSERT_NEAR_C(sim.state[3], 0);\n\n    sim.apply(PauliString<W>::from_str(\"+ZI\").ref(), 0);\n    ASSERT_NEAR_C(sim.state[0], 0);\n    ASSERT_NEAR_C(sim.state[1], 1);\n    ASSERT_NEAR_C(sim.state[2], 0);\n    ASSERT_NEAR_C(sim.state[3], 0);\n\n    sim.apply(PauliString<W>::from_str(\"+IY\").ref(), 0);\n    ASSERT_NEAR_C(sim.state[0], 0);\n    ASSERT_NEAR_C(sim.state[1], 0);\n    ASSERT_NEAR_C(sim.state[2], 0);\n    ASSERT_NEAR_C(sim.state[3], std::complex<float>(0, 1));\n\n    sim.apply(PauliString<W>::from_str(\"+XX\").ref(), 0);\n    ASSERT_NEAR_C(sim.state[0], std::complex<float>(0, 1));\n    ASSERT_NEAR_C(sim.state[1], 0);\n    ASSERT_NEAR_C(sim.state[2], 0);\n    ASSERT_NEAR_C(sim.state[3], 0);\n\n    sim.apply(PauliString<W>::from_str(\"+X\").ref(), 1);\n    ASSERT_NEAR_C(sim.state[0], 0);\n    ASSERT_NEAR_C(sim.state[1], 0);\n    ASSERT_NEAR_C(sim.state[2], std::complex<float>(0, 1));\n    ASSERT_NEAR_C(sim.state[3], 0);\n})\n\nTEST(vector_sim, approximate_equals) {\n    VectorSimulator s1(2);\n    VectorSimulator s2(2);\n    ASSERT_TRUE(s1.approximate_equals(s2));\n    ASSERT_TRUE(s1.approximate_equals(s2, false));\n    ASSERT_TRUE(s1.approximate_equals(s2, true));\n    s1.state[0] *= -1;\n    ASSERT_FALSE(s1.approximate_equals(s2));\n    ASSERT_FALSE(s1.approximate_equals(s2, false));\n    ASSERT_TRUE(s1.approximate_equals(s2, true));\n    s1.state[0] *= std::complex<float>(0, 1);\n    ASSERT_FALSE(s1.approximate_equals(s2));\n    ASSERT_FALSE(s2.approximate_equals(s1));\n    ASSERT_FALSE(s1.approximate_equals(s2, false));\n    ASSERT_TRUE(s1.approximate_equals(s2, true));\n    ASSERT_FALSE(s2.approximate_equals(s1, false));\n    ASSERT_TRUE(s2.approximate_equals(s1, true));\n    s1.state[0] = 0;\n    s1.state[1] = 1;\n    ASSERT_FALSE(s1.approximate_equals(s2));\n    ASSERT_FALSE(s1.approximate_equals(s2, false));\n    ASSERT_FALSE(s1.approximate_equals(s2, true));\n    s2.state[0] = 0;\n    s2.state[1] = 1;\n    ASSERT_TRUE(s1.approximate_equals(s2));\n    s1.state[0] = sqrtf(0.5);\n    s1.state[1] = sqrtf(0.5);\n    s2.state[0] = sqrtf(0.5);\n    s2.state[1] = sqrtf(0.5);\n    ASSERT_TRUE(s1.approximate_equals(s2));\n    s1.state[0] *= -1;\n    ASSERT_FALSE(s1.approximate_equals(s2));\n}\n\nTEST_EACH_WORD_SIZE_W(vector_sim, project_empty, {\n    VectorSimulator sim(0);\n    sim.project<W>(PauliString<W>(0));\n    VectorSimulator ref(0);\n    ref.state = {1};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n})\n\nTEST_EACH_WORD_SIZE_W(vector_sim, project, {\n    VectorSimulator sim(2);\n    VectorSimulator ref(2);\n\n    sim.state = {0.5, 0.5, 0.5, 0.5};\n    ASSERT_NEAR_C(sim.project<W>(PauliString<W>::from_str(\"ZI\")), 0.5);\n    ref.state = {sqrtf(0.5), 0, sqrtf(0.5), 0};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n    ASSERT_NEAR_C(sim.project<W>(PauliString<W>::from_str(\"ZI\")), 1);\n    ASSERT_TRUE(sim.approximate_equals(ref));\n\n    sim.state = {0.5, 0.5, 0.5, 0.5};\n    sim.project<W>(PauliString<W>::from_str(\"-ZI\"));\n    ref.state = {0, sqrtf(0.5), 0, sqrtf(0.5)};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n\n    sim.state = {0.5, 0.5, 0.5, 0.5};\n    sim.project<W>(PauliString<W>::from_str(\"IZ\"));\n    ref.state = {sqrtf(0.5), sqrtf(0.5), 0, 0};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n\n    sim.state = {0.5, 0.5, 0.5, 0.5};\n    sim.project<W>(PauliString<W>::from_str(\"-IZ\"));\n    ref.state = {0, 0, sqrtf(0.5), sqrtf(0.5)};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n\n    sim.state = {0.5, 0.5, 0.5, 0.5};\n    sim.project<W>(PauliString<W>::from_str(\"ZZ\"));\n    ref.state = {sqrtf(0.5), 0, 0, sqrtf(0.5)};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n\n    sim.state = {0.5, 0.5, 0.5, 0.5};\n    sim.project<W>(PauliString<W>::from_str(\"-ZZ\"));\n    ref.state = {0, sqrtf(0.5), sqrtf(0.5), 0};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n\n    sim.project<W>(PauliString<W>::from_str(\"ZI\"));\n    sim.state = {1, 0, 0, 0};\n    sim.project<W>(PauliString<W>::from_str(\"ZZ\"));\n    ref.state = {1, 0, 0, 0};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n\n    sim.project<W>(PauliString<W>::from_str(\"XX\"));\n    ref.state = {sqrtf(0.5f), 0, 0, sqrtf(0.5f)};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n\n    sim.project<W>(PauliString<W>::from_str(\"-YZ\"));\n    ref.state = {0.5, {0, -0.5}, {0, -0.5}, 0.5};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n\n    sim.project<W>(PauliString<W>::from_str(\"-ZI\"));\n    ref.state = {0, {0, -sqrtf(0.5)}, 0, sqrtf(0.5)};\n    ASSERT_TRUE(sim.approximate_equals(ref));\n})\n\nTEST_EACH_WORD_SIZE_W(vector_sim, from_stabilizers, {\n    VectorSimulator ref(2);\n    auto sim = VectorSimulator::from_stabilizers<W>({PauliString<W>::from_str(\"ZI\"), PauliString<W>::from_str(\"IZ\")});\n    ref.state = {1, 0, 0, 0};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n\n    sim = VectorSimulator::from_stabilizers<W>({PauliString<W>::from_str(\"-YX\"), PauliString<W>::from_str(\"ZZ\")});\n    ref.state = {sqrtf(0.5), 0, 0, {0, -sqrtf(0.5)}};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n\n    sim = VectorSimulator::from_stabilizers<W>({PauliString<W>::from_str(\"ZI\"), PauliString<W>::from_str(\"ZZ\")});\n    ref.state = {1, 0, 0, 0};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n\n    sim = VectorSimulator::from_stabilizers<W>({PauliString<W>::from_str(\"ZI\"), PauliString<W>::from_str(\"-ZZ\")});\n    ref.state = {0, 0, 1, 0};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n\n    sim = VectorSimulator::from_stabilizers<W>({PauliString<W>::from_str(\"ZI\"), PauliString<W>::from_str(\"IX\")});\n    ref.state = {sqrtf(0.5), 0, sqrtf(0.5), 0};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n\n    sim = VectorSimulator::from_stabilizers<W>({PauliString<W>::from_str(\"ZZ\"), PauliString<W>::from_str(\"XX\")});\n    ref.state = {sqrtf(0.5), 0, 0, sqrtf(0.5)};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n\n    sim = VectorSimulator::from_stabilizers<W>(\n        {PauliString<W>::from_str(\"XXX\"), PauliString<W>::from_str(\"ZZI\"), PauliString<W>::from_str(\"IZZ\")});\n    ref.state = {sqrtf(0.5), 0, 0, 0, 0, 0, 0, sqrtf(0.5)};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n\n    sim = VectorSimulator::from_stabilizers<W>(\n        {PauliString<W>::from_str(\"YYY\"), PauliString<W>::from_str(\"ZZI\"), PauliString<W>::from_str(\"IZZ\")});\n    ref.state = {sqrtf(0.5), 0, 0, 0, 0, 0, 0, {0, -sqrtf(0.5)}};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n\n    sim = VectorSimulator::from_stabilizers<W>(\n        {PauliString<W>::from_str(\"-YYY\"), PauliString<W>::from_str(\"-ZZI\"), PauliString<W>::from_str(\"IZZ\")});\n    ref.state = {0, sqrtf(0.5), 0, 0, 0, 0, {0, -sqrtf(0.5)}, 0};\n    ASSERT_TRUE(sim.approximate_equals(ref, true));\n})\n\nTEST(vector_sim, smooth_stabilizer_state) {\n    VectorSimulator sim(0);\n    sim.state = {{1, 0}, {1, 1}};\n    ASSERT_THROW({ sim.smooth_stabilizer_state(1); }, std::invalid_argument);\n\n    sim.state = {{0.25, 0.25}, {-0.25, 0.25}};\n    ASSERT_THROW({ sim.smooth_stabilizer_state(1); }, std::invalid_argument);\n\n    sim.state = {{0.25, 0.25}, {-0.25, 0.25}};\n    sim.smooth_stabilizer_state({-0.25, -0.25});\n    ASSERT_EQ(sim.state, (std::vector<std::complex<float>>{{-1, 0}, {0, -1}}));\n}\n\nTEST(vector_sim, do_unitary_circuit) {\n    VectorSimulator sim(3);\n    sim.do_unitary_circuit(Circuit(R\"CIRCUIT(\n        H 0 1\n        S 0\n    )CIRCUIT\"));\n    sim.smooth_stabilizer_state(0.5);\n    ASSERT_EQ(sim.state, (std::vector<std::complex<float>>({1, {0, 1}, 1, {0, 1}, 0, 0, 0, 0})));\n\n    sim.do_unitary_circuit(Circuit(R\"CIRCUIT(\n        CNOT 0 2 2 0 0 2\n    )CIRCUIT\"));\n    ASSERT_EQ(sim.state, (std::vector<std::complex<float>>({1, 0, 1, 0, {0, 1}, 0, {0, 1}, 0})));\n\n    ASSERT_THROW({ sim.do_unitary_circuit(Circuit(\"H 3\")); }, std::invalid_argument);\n    ASSERT_THROW({ sim.do_unitary_circuit(Circuit(\"CX rec[-1] 0\")); }, std::invalid_argument);\n    ASSERT_THROW({ sim.do_unitary_circuit(Circuit(\"X_ERROR(0.1) 0\")); }, std::invalid_argument);\n}\n"
  },
  {
    "path": "src/stim/stabilizers/README.md",
    "content": "# `stabilizers` directory\n\nThis directory contains data structures and code related to the stabilizer formalism,\nsuch as code for conjugating Pauli products with Clifford operations.\n"
  },
  {
    "path": "src/stim/stabilizers/clifford_string.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_STABILIZERS_CLIFFORD_STRING_H\n#define _STIM_STABILIZERS_CLIFFORD_STRING_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/mem/simd_bits.h\"\n\nnamespace stim {\n\n/// A fixed-size list of W single-qubit Clifford rotations.\ntemplate <typename Word>\nstruct CliffordWord {\n    Word x_signs;\n    Word z_signs;\n    Word inv_x2x;  // Inverted so that zero-initializing gives the identity gate.\n    Word x2z;\n    Word z2x;\n    Word inv_z2z;  // Inverted so that zero-initializing gives the identity gate.\n};\n\nconstexpr std::array<GateType, 64> INT_TO_SINGLE_QUBIT_CLIFFORD_TABLE{\n    GateType::I,          GateType::X,          GateType::Z,          GateType::Y,\n\n    GateType::NOT_A_GATE,  // These should be impossible if the class is in a good state.\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::S,          GateType::H_XY,       GateType::S_DAG,      GateType::H_NXY,\n\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::SQRT_X_DAG, GateType::SQRT_X,     GateType::H_YZ,       GateType::H_NYZ,\n\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::C_ZYX,      GateType::C_ZNYX,     GateType::C_ZYNX,     GateType::C_NZYX,\n\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE, GateType::NOT_A_GATE,\n\n    GateType::C_XYZ,      GateType::C_XYNZ,     GateType::C_XNYZ,     GateType::C_NXYZ,\n\n    GateType::H,          GateType::SQRT_Y_DAG, GateType::SQRT_Y,     GateType::H_NXZ,\n};\n\ninline GateType bits2gate(std::array<bool, 6> bits) {\n    int k = (bits[0] << 0) | (bits[1] << 1) | (bits[2] << 2) | (bits[3] << 3) | (bits[4] << 4) | (bits[5] << 5);\n    return INT_TO_SINGLE_QUBIT_CLIFFORD_TABLE[k];\n}\n\ninline std::array<bool, 6> gate_to_bits(GateType gate_type) {\n    Gate g = GATE_DATA[gate_type];\n    if (!(g.flags & GATE_IS_SINGLE_QUBIT_GATE) || !(g.flags & GATE_IS_UNITARY)) {\n        throw std::invalid_argument(\"Not a single qubit Clifford gate: \" + std::string(g.name));\n    }\n    const auto &flows = g.flow_data;\n    std::string_view tx = flows[0];\n    std::string_view tz = flows[1];\n    bool z_sign = tz[0] == '-';\n    bool inv_x2x = !(tx[1] == 'X' || tx[1] == 'Y');\n    bool x2z = tx[1] == 'Z' || tx[1] == 'Y';\n    bool x_sign = tx[0] == '-';\n    bool z2x = tz[1] == 'X' || tz[1] == 'Y';\n    bool inv_z2z = !(tz[1] == 'Z' || tz[1] == 'Y');\n    return {z_sign, x_sign, inv_x2x, x2z, z2x, inv_z2z};\n}\n\n/// Returns the result of multiplying W rotations pair-wise.\ntemplate <typename Word>\ninline CliffordWord<Word> operator*(const CliffordWord<Word> &lhs, const CliffordWord<Word> &rhs) {\n    CliffordWord<Word> result;\n\n    // I don't have a simple explanation of why this is correct. It was produced by starting from something that was\n    // obviously correct, having tests to check all 24*24 cases, then iteratively applying simple rewrites to reduce\n    // the number of operations. So the result is correct, but somewhat incomprehensible.\n    result.inv_x2x = (lhs.inv_x2x | rhs.inv_x2x) ^ (lhs.z2x & rhs.x2z);\n    result.x2z = andnot(rhs.inv_x2x, lhs.x2z) ^ andnot(lhs.inv_z2z, rhs.x2z);\n    result.z2x = andnot(lhs.inv_x2x, rhs.z2x) ^ andnot(rhs.inv_z2z, lhs.z2x);\n    result.inv_z2z = (lhs.x2z & rhs.z2x) ^ (lhs.inv_z2z | rhs.inv_z2z);\n\n    // I *especially* don't have an explanation of why this part is correct. But every case is tested and verified.\n    Word rhs_x2y = andnot(rhs.inv_x2x, rhs.x2z);\n    Word rhs_z2y = andnot(rhs.inv_z2z, rhs.z2x);\n    Word dy = (lhs.x2z & lhs.z2x) ^ lhs.inv_x2x ^ lhs.z2x ^ lhs.x2z ^ lhs.inv_z2z;\n    result.x_signs = rhs.x_signs ^ andnot(rhs.inv_x2x, lhs.x_signs) ^ (rhs_x2y & dy) ^ (rhs.x2z & lhs.z_signs);\n    result.z_signs = rhs.z_signs ^ (rhs.z2x & lhs.x_signs) ^ (rhs_z2y & dy) ^ andnot(rhs.inv_z2z, lhs.z_signs);\n\n    return result;\n}\n\ntemplate <size_t W>\nstruct CliffordString;\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const CliffordString<W> &v);\n\ntemplate <size_t W>\nGateType single_qubit_tableau_to_gate_type(const stim::Tableau<W> &tableau) {\n    return bits2gate(std::array<bool, 6>{\n        tableau.zs.signs[0],\n        tableau.xs.signs[0],\n        !tableau.xs.xt[0][0],\n        tableau.xs.zt[0][0],\n        tableau.zs.xt[0][0],\n        !tableau.zs.zt[0][0],\n    });\n}\n\n/// A string of single-qubit Clifford rotations.\ntemplate <size_t W>\nstruct CliffordString {\n    size_t num_qubits;\n\n    // The 2 sign bits of a single qubit Clifford, packed into arrays for easy processing.\n    simd_bits<W> x_signs;\n    simd_bits<W> z_signs;\n\n    // The 4 tableau bits of a single qubit Clifford, packed into arrays for easy processing.\n    // The x2x and z2z terms are inverted so that zero-initializing produces the identity gate.\n    simd_bits<W> inv_x2x;\n    simd_bits<W> x2z;\n    simd_bits<W> z2x;\n    simd_bits<W> inv_z2z;\n\n    /// Constructs an identity CliffordString for the given number of qubits.\n    explicit CliffordString(size_t num_qubits)\n        : num_qubits(num_qubits),\n          x_signs(num_qubits),\n          z_signs(num_qubits),\n          inv_x2x(num_qubits),\n          x2z(num_qubits),\n          z2x(num_qubits),\n          inv_z2z(num_qubits) {\n    }\n\n    void randomize(std::mt19937_64 &rng) {\n        CliffordString<W> result(num_qubits);\n        x_signs.randomize(num_qubits, rng);\n        z_signs.randomize(num_qubits, rng);\n        for (size_t k = 0; k < num_qubits; k++) {\n            uint64_t v = rng() % 6;\n            uint8_t p1 = v % 3 + 1;\n            uint8_t p2 = v / 3 + 1;\n            p2 += p2 >= p1;\n            inv_x2x[k] = !(p1 & 1);\n            x2z[k] = p1 & 2;\n            z2x[k] = p2 & 1;\n            inv_z2z[k] = !(p2 & 2);\n        }\n    }\n\n    static CliffordString<W> random(size_t num_qubits, std::mt19937_64 &rng) {\n        CliffordString<W> result(num_qubits);\n        result.randomize(rng);\n        return result;\n    }\n\n    CliffordString<W> operator+(const CliffordString<W> &other) const {\n        if (num_qubits + other.num_qubits < num_qubits) {\n            throw std::invalid_argument(\"Couldn't concatenate Clifford strings due to size overflowing.\");\n        }\n        CliffordString<W> result(num_qubits + other.num_qubits);\n        for (size_t k = 0; k < num_qubits; k++) {\n            result.set_gate_at(k, gate_at(k));\n        }\n        for (size_t k = 0; k < other.num_qubits; k++) {\n            result.set_gate_at(num_qubits + k, other.gate_at(k));\n        }\n        return result;\n    }\n\n    CliffordString<W> &operator+=(const CliffordString<W> &other) {\n        CliffordString<W> tmp = *this + other;\n        *this = std::move(tmp);\n        return *this;\n    }\n\n    CliffordString<W> operator*(size_t repetitions) const {\n        if (repetitions == 0) {\n            return CliffordString<W>(0);\n        }\n\n        size_t new_num_qubits = num_qubits * repetitions;\n        if (new_num_qubits / repetitions != num_qubits) {\n            throw std::invalid_argument(\"Couldn't repeat CliffordString due to size overflowing.\");\n        }\n\n        CliffordString<W> result(new_num_qubits);\n        for (size_t k = 0; k < num_qubits; k++) {\n            GateType g = gate_at(k);\n            for (size_t k2 = k; k2 < new_num_qubits; k2 += num_qubits) {\n                result.set_gate_at(k2, g);\n            }\n        }\n        return result;\n    }\n\n    CliffordString<W> &operator*=(size_t repetitions) {\n        CliffordString<W> tmp = *this * repetitions;\n        *this = std::move(tmp);\n        return *this;\n    }\n\n    /// Extracts rotations k*W through (k+1)*W into a CliffordWord<W>.\n    inline CliffordWord<bitword<W>> word_at(size_t k) const {\n        return CliffordWord<bitword<W>>{\n            x_signs.ptr_simd[k],\n            z_signs.ptr_simd[k],\n            inv_x2x.ptr_simd[k],\n            x2z.ptr_simd[k],\n            z2x.ptr_simd[k],\n            inv_z2z.ptr_simd[k],\n        };\n    }\n    /// Writes rotations k*W through (k+1)*W from a CliffordWord<W>.\n    inline void set_word_at(size_t k, CliffordWord<bitword<W>> new_value) const {\n        x_signs.ptr_simd[k] = new_value.x_signs;\n        z_signs.ptr_simd[k] = new_value.z_signs;\n        inv_x2x.ptr_simd[k] = new_value.inv_x2x;\n        x2z.ptr_simd[k] = new_value.x2z;\n        z2x.ptr_simd[k] = new_value.z2x;\n        inv_z2z.ptr_simd[k] = new_value.inv_z2z;\n    }\n\n    /// Converts the internal rotation representation into a GateType.\n    GateType gate_at(size_t q) const {\n        return bits2gate(std::array<bool, 6>{z_signs[q], x_signs[q], inv_x2x[q], x2z[q], z2x[q], inv_z2z[q]});\n    }\n\n    /// Sets an internal rotation from a GateType.\n    void set_gate_at(size_t q, GateType gate_type) {\n        std::array<bool, 6> bits = gate_to_bits(gate_type);\n        z_signs[q] = bits[0];\n        x_signs[q] = bits[1];\n        inv_x2x[q] = bits[2];\n        x2z[q] = bits[3];\n        z2x[q] = bits[4];\n        inv_z2z[q] = bits[5];\n    }\n\n    /// Inplace right-multiplication of rotations.\n    CliffordString &operator*=(const CliffordString &rhs) {\n        ensure_num_qubits(rhs.num_qubits);\n        for (size_t k = 0; k < rhs.x_signs.num_simd_words; k++) {\n            auto lhs_w = word_at(k);\n            auto rhs_w = rhs.word_at(k);\n            set_word_at(k, lhs_w * rhs_w);\n        }\n        return *this;\n    }\n\n    void inplace_then(CircuitInstruction inst) {\n        // Ignore annotations.\n        switch (inst.gate_type) {\n            case GateType::TICK:\n            case GateType::QUBIT_COORDS:\n            case GateType::SHIFT_COORDS:\n            case GateType::DETECTOR:\n            case GateType::OBSERVABLE_INCLUDE:\n                return;\n            default:\n                break;\n        }\n\n        std::array<bool, 6> v = gate_to_bits(inst.gate_type);\n        for (const auto &t : inst.targets) {\n            if (!t.is_qubit_target()) {\n                continue;\n            }\n            uint32_t q = t.qubit_value();\n            if (q >= num_qubits) {\n                throw std::invalid_argument(\"Circuit acted on qubit past end of string.\");\n            }\n            size_t w = q / W;\n            size_t k = q % W;\n            CliffordWord<bitword<W>> tmp{};\n            bit_ref(&tmp.z_signs, k) ^= v[0];\n            bit_ref(&tmp.x_signs, k) ^= v[1];\n            bit_ref(&tmp.inv_x2x, k) ^= v[2];\n            bit_ref(&tmp.x2z, k) ^= v[3];\n            bit_ref(&tmp.z2x, k) ^= v[4];\n            bit_ref(&tmp.inv_z2z, k) ^= v[5];\n            set_word_at(w, tmp * word_at(w));\n        }\n    }\n\n    static CliffordString<W> from_circuit(const Circuit &circuit) {\n        CliffordString<W> result(circuit.count_qubits());\n        circuit.for_each_operation([&](CircuitInstruction inst) {\n            result.inplace_then(inst);\n        });\n        return result;\n    }\n\n    Circuit to_circuit() const {\n        Circuit result;\n        for (size_t q = 0; q < num_qubits; q++) {\n            GateType g = gate_at(q);\n            if (g != GateType::I || q + 1 == num_qubits) {\n                GateTarget t = GateTarget::qubit(q);\n                result.safe_append(CircuitInstruction{g, {}, &t, {}});\n            }\n        }\n        return result;\n    }\n\n    void ensure_num_qubits(size_t min_num_qubits) {\n        if (num_qubits < min_num_qubits) {\n            num_qubits = min_num_qubits;\n            x_signs.preserving_resize(num_qubits);\n            z_signs.preserving_resize(num_qubits);\n            inv_x2x.preserving_resize(num_qubits);\n            x2z.preserving_resize(num_qubits);\n            z2x.preserving_resize(num_qubits);\n            inv_z2z.preserving_resize(num_qubits);\n        }\n    }\n\n    /// Inplace left-multiplication of rotations.\n    CliffordString &inplace_left_mul_by(const CliffordString &lhs) {\n        ensure_num_qubits(lhs.num_qubits);\n        for (size_t k = 0; k < x_signs.num_simd_words; k++) {\n            auto lhs_w = lhs.word_at(k);\n            auto rhs_w = word_at(k);\n            set_word_at(k, lhs_w * rhs_w);\n        }\n        return *this;\n    }\n\n    /// Inplace raises to a power.\n    void ipow(int64_t power) const {\n        power %= 12;\n        if (power < 0) {\n            power += 12;\n        }\n        for (size_t k = 0; k < x_signs.num_simd_words; k++) {\n            auto delta = word_at(k);\n            CliffordWord<bitword<W>> total{};\n            for (size_t step = 0; step < power; step++) {\n                total = total * delta;\n            }\n            set_word_at(k, total);\n        }\n    }\n\n    PauliString<W> x_outputs() const {\n        PauliString<W> result(num_qubits);\n        result.xs = inv_x2x;\n        result.zs = x2z;\n        result.xs.invert_bits();\n        result.xs.clear_bits_past(num_qubits);\n        return result;\n    }\n    PauliString<W> y_outputs_and_signs(simd_bits_range_ref<W> y_signs_out) const {\n        PauliString<W> result(num_qubits);\n        result.xs = inv_x2x;\n        result.zs = x2z;\n        y_signs_out = x_signs;\n        y_signs_out ^= z_signs;\n        simd_bits_range_ref<W>(result.xs).for_each_word(\n            result.zs,\n            z2x,\n            inv_z2z,\n            y_signs_out,\n            [](simd_word<W> &x_out,\n               simd_word<W> &z_out,\n               const simd_word<W> &x2,\n               const simd_word<W> &inv_z2,\n               simd_word<W> &y_sign) {\n                y_sign ^= ~x_out & ~inv_z2 & (z_out ^ x2);\n                y_sign ^= x_out & inv_z2 & z_out & x2;\n                x_out ^= ~x2;\n                z_out ^= ~inv_z2;\n            });\n        result.xs.clear_bits_past(num_qubits);\n        result.zs.clear_bits_past(num_qubits);\n        return result;\n    }\n    PauliString<W> z_outputs() const {\n        PauliString<W> result(num_qubits);\n        result.xs = z2x;\n        result.zs = inv_z2z;\n        result.zs.invert_bits();\n        result.zs.clear_bits_past(num_qubits);\n        return result;\n    }\n\n    /// Out-of-place multiplication of rotations.\n    CliffordString operator*(const CliffordString &rhs) const {\n        CliffordString<W> result = CliffordString<W>(std::max(num_qubits, rhs.num_qubits));\n        size_t min_words = std::min(x_signs.num_simd_words, rhs.x_signs.num_simd_words);\n        for (size_t k = 0; k < min_words; k++) {\n            auto lhs_w = word_at(k);\n            auto rhs_w = rhs.word_at(k);\n            result.set_word_at(k, lhs_w * rhs_w);\n        }\n\n        // The longer string copies its tail into the result.\n        size_t min_qubits = std::min(num_qubits, rhs.num_qubits);\n        for (size_t q = min_qubits; q < num_qubits; q++) {\n            result.x_signs[q] = x_signs[q];\n            result.z_signs[q] = z_signs[q];\n            result.inv_x2x[q] = inv_x2x[q];\n            result.x2z[q] = x2z[q];\n            result.z2x[q] = z2x[q];\n            result.inv_z2z[q] = inv_z2z[q];\n        }\n        for (size_t q = min_qubits; q < rhs.num_qubits; q++) {\n            result.x_signs[q] = rhs.x_signs[q];\n            result.z_signs[q] = rhs.z_signs[q];\n            result.inv_x2x[q] = rhs.inv_x2x[q];\n            result.x2z[q] = rhs.x2z[q];\n            result.z2x[q] = rhs.z2x[q];\n            result.inv_z2z[q] = rhs.inv_z2z[q];\n        }\n\n        return result;\n    }\n\n    /// Determines if two Clifford strings have the same length and contents.\n    bool operator==(const CliffordString<W> &other) const {\n        return x_signs == other.x_signs && z_signs == other.z_signs && inv_x2x == other.inv_x2x && x2z == other.x2z &&\n               z2x == other.z2x && inv_z2z == other.inv_z2z;\n    }\n    /// Determines if two Clifford strings have different lengths or contents.\n    bool operator!=(const CliffordString<W> &other) const {\n        return !(*this == other);\n    }\n\n    /// Returns a description of the Clifford string.\n    std::string str() const {\n        std::stringstream ss;\n        ss << *this;\n        return ss.str();\n    }\n\n    std::string py_str() const {\n        std::stringstream ss;\n        for (size_t q = 0; q < num_qubits; q++) {\n            if (q) {\n                ss << ',';\n            }\n            ss << GATE_DATA[gate_at(q)].name;\n        }\n        return ss.str();\n    }\n\n    CliffordString<W> py_get_slice(int64_t start, int64_t step, int64_t slice_length) const {\n        assert(slice_length >= 0);\n        assert(slice_length == 0 || start >= 0);\n        CliffordString<W> result(slice_length);\n        for (size_t k = 0; k < (size_t)slice_length; k++) {\n            size_t old_k = start + step * k;\n            result.x_signs[k] = x_signs[old_k];\n            result.z_signs[k] = z_signs[old_k];\n            result.inv_x2x[k] = inv_x2x[old_k];\n            result.x2z[k] = x2z[old_k];\n            result.z2x[k] = z2x[old_k];\n            result.inv_z2z[k] = inv_z2z[old_k];\n        }\n        return result;\n    }\n\n    std::string py_repr() const {\n        std::stringstream ss;\n        ss << \"stim.CliffordString(\\\"\";\n        for (size_t q = 0; q < num_qubits; q++) {\n            if (q) {\n                ss << ',';\n            }\n            ss << GATE_DATA[gate_at(q)].name;\n        }\n        ss << \"\\\")\";\n        return ss.str();\n    }\n};\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const CliffordString<W> &v) {\n    for (size_t q = 0; q < v.num_qubits; q++) {\n        if (q > 0) {\n            out << \" \";\n        }\n        int c = v.inv_x2x[q] + v.x2z[q] * 2 + v.z2x[q] * 4 + v.inv_z2z[q] * 8;\n        int p = v.z_signs[q] + v.x_signs[q] * 2;\n        out << \"_?S?V??d??????uH\"[c];\n        out << \"IXZY\"[p];\n    }\n    return out;\n}\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/clifford_string.perf.cc",
    "content": "#include \"stim/stabilizers/clifford_string.h\"\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(CliffordString_multiplication_10K) {\n    size_t n = 10 * 1000;\n    CliffordString<MAX_BITWORD_WIDTH> p1(n);\n    CliffordString<MAX_BITWORD_WIDTH> p2(n);\n    benchmark_go([&]() {\n        p1 *= p2;\n    })\n        .goal_nanos(430)\n        .show_rate(\"Rots\", n);\n}\n"
  },
  {
    "path": "src/stim/stabilizers/clifford_string.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/clifford_string.pybind.h\"\n\n#include \"stim/gates/gates.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n#include \"stim/stabilizers/flex_pauli_string.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\n\npybind11::class_<CliffordString<MAX_BITWORD_WIDTH>> stim_pybind::pybind_clifford_string(pybind11::module &m) {\n    return pybind11::class_<CliffordString<MAX_BITWORD_WIDTH>>(\n        m,\n        \"CliffordString\",\n        clean_doc_string(R\"DOC(\n            A tensor product of single qubit Clifford gates (e.g. \"H \\u2297 X \\u2297 S\").\n\n            Represents a collection of Clifford operations applied pairwise to a\n            collection of qubits. Ignores global phase.\n\n            Examples:\n                >>> import stim\n                >>> stim.CliffordString(\"H,S,C_XYZ\") * stim.CliffordString(\"H,H,H\")\n                stim.CliffordString(\"I,C_ZYX,SQRT_X_DAG\")\n        )DOC\")\n            .data());\n}\n\nstatic std::string_view trim(std::string_view text) {\n    size_t s = 0;\n    size_t e = text.size();\n    while (s < e && std::isspace(text[s])) {\n        s++;\n    }\n    while (s < e && std::isspace(text[e - 1])) {\n        e--;\n    }\n    return text.substr(s, e - s);\n}\n\nvoid stim_pybind::pybind_clifford_string_methods(\n    pybind11::module &m, pybind11::class_<CliffordString<MAX_BITWORD_WIDTH>> &c) {\n    c.def(\n        pybind11::init([](const pybind11::object &arg) -> CliffordString<MAX_BITWORD_WIDTH> {\n            if (pybind11::isinstance<pybind11::int_>(arg)) {\n                return CliffordString<MAX_BITWORD_WIDTH>(pybind11::cast<int64_t>(arg));\n            }\n\n            if (pybind11::isinstance<pybind11::str>(arg)) {\n                std::string_view text = pybind11::cast<std::string_view>(arg);\n                text = trim(text);\n                if (text.empty()) {\n                    return CliffordString<MAX_BITWORD_WIDTH>(0);\n                }\n                if (text.ends_with(',')) {\n                    text = text.substr(0, text.size() - 1);\n                }\n\n                size_t n = 1;\n                for (char e : text) {\n                    n += e == ',';\n                }\n                CliffordString<MAX_BITWORD_WIDTH> result(n);\n                size_t start = 0;\n                size_t out_index = 0;\n                for (size_t end = 0; end <= text.size(); end++) {\n                    if (end == text.size() || text[end] == ',') {\n                        std::string_view segment = text.substr(start, end - start);\n                        segment = trim(segment);\n                        auto [z_sign, x_sign, inv_x2x, x2z, z2x, inv_z2z] = gate_to_bits(GATE_DATA.at(segment).id);\n                        result.z_signs[out_index] = z_sign;\n                        result.x_signs[out_index] = x_sign;\n                        result.inv_x2x[out_index] = inv_x2x;\n                        result.x2z[out_index] = x2z;\n                        result.z2x[out_index] = z2x;\n                        result.inv_z2z[out_index] = inv_z2z;\n                        start = end + 1;\n                        out_index += 1;\n                    }\n                }\n                return result;\n            }\n\n            if (pybind11::isinstance<CliffordString<MAX_BITWORD_WIDTH>>(arg)) {\n                auto copy = pybind11::cast<const CliffordString<MAX_BITWORD_WIDTH> &>(arg);\n                return copy;\n            }\n\n            if (pybind11::isinstance<FlexPauliString>(arg)) {\n                const FlexPauliString &other = pybind11::cast<const FlexPauliString &>(arg);\n                CliffordString<MAX_BITWORD_WIDTH> result(other.value.num_qubits);\n                result.z_signs = other.value.xs;\n                result.x_signs = other.value.zs;\n                return result;\n            }\n\n            if (pybind11::isinstance<Circuit>(arg)) {\n                const Circuit &circuit = pybind11::cast<const Circuit &>(arg);\n                return CliffordString<MAX_BITWORD_WIDTH>::from_circuit(circuit);\n            }\n\n            pybind11::module collections = pybind11::module::import(\"collections.abc\");\n            pybind11::object iterable_type = collections.attr(\"Iterable\");\n            if (pybind11::isinstance(arg, iterable_type)) {\n                std::vector<GateType> gates;\n                for (const auto &t : arg) {\n                    if (pybind11::isinstance<GateTypeWrapper>(t)) {\n                        gates.push_back(pybind11::cast<GateTypeWrapper>(t).type);\n                        continue;\n                    } else if (pybind11::isinstance<pybind11::str>(t)) {\n                        gates.push_back(GATE_DATA.at(pybind11::cast<std::string_view>(t)).id);\n                        continue;\n                    }\n                    throw std::invalid_argument(\n                        \"Don't know how to convert the following item into a Clifford: \" +\n                        pybind11::cast<std::string>(pybind11::repr(t)));\n                }\n                CliffordString<MAX_BITWORD_WIDTH> result(gates.size());\n                for (size_t k = 0; k < gates.size(); k++) {\n                    result.set_gate_at(k, gates[k]);\n                }\n                return result;\n            }\n\n            throw std::invalid_argument(\n                \"Don't know how to initialize a stim.CliffordString from \" +\n                pybind11::cast<std::string>(pybind11::repr(arg)));\n        }),\n        pybind11::arg(\"arg\"),\n        pybind11::pos_only(),\n        clean_doc_string(R\"DOC(\n            @signature def __init__(self, arg: Union[int, str, stim.CliffordString, stim.PauliString, stim.Circuit], /) -> None:\n            Initializes a stim.CliffordString from the given argument.\n\n            Args:\n                arg [position-only]: This can be a variety of types, including:\n                    int: initializes an identity Clifford string of the given length.\n                    str: initializes by parsing a comma-separated list of gate names.\n                    stim.CliffordString: initializes by copying the given Clifford string.\n                    stim.PauliString: initializes by copying from the given Pauli string\n                        (ignores the sign of the Pauli string).\n                    stim.Circuit: initializes a CliffordString equivalent to the action\n                        of the circuit (as long as the circuit only contains single qubit\n                        unitary operations and annotations).\n                    Iterable: initializes by interpreting each item as a Clifford.\n                        Each item can be a single-qubit Clifford gate name (like \"SQRT_X\")\n                        or stim.GateData instance.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.CliffordString(5)\n                stim.CliffordString(\"I,I,I,I,I\")\n\n                >>> stim.CliffordString(\"X,Y,Z,SQRT_X\")\n                stim.CliffordString(\"X,Y,Z,SQRT_X\")\n\n                >>> stim.CliffordString([\"H\", stim.gate_data(\"S\")])\n                stim.CliffordString(\"H,S\")\n\n                >>> stim.CliffordString(stim.PauliString(\"XYZ\"))\n                stim.CliffordString(\"X,Y,Z\")\n\n                >>> stim.CliffordString(stim.CliffordString(\"X,Y,Z\"))\n                stim.CliffordString(\"X,Y,Z\")\n\n                >>> stim.CliffordString(stim.Circuit('''\n                ...     H 0 1 2\n                ...     S 2 3\n                ...     TICK\n                ...     S 3\n                ...     I 6\n                ... '''))\n                stim.CliffordString(\"H,H,C_ZYX,Z,I,I,I\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__str__\",\n        &CliffordString<MAX_BITWORD_WIDTH>::py_str,\n        \"Returns a string representation of the CliffordString's operations.\");\n    c.def(\n        \"__repr__\",\n        &CliffordString<MAX_BITWORD_WIDTH>::py_repr,\n        \"Returns text that is a valid python expression evaluating to an equivalent `stim.CliffordString`.\");\n    c.def(\n        \"__len__\",\n        [](const CliffordString<MAX_BITWORD_WIDTH> &self) {\n            return self.num_qubits;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of Clifford operations in the string.\n\n            Examples:\n                >>> import stim\n                >>> len(stim.CliffordString(\"I,X,Y,Z,H\"))\n                5\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two Clifford strings have identical contents.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two Clifford strings have non-identical contents.\");\n\n    c.def(\n        \"__getitem__\",\n        [](const CliffordString<MAX_BITWORD_WIDTH> &self, const pybind11::object &index_or_slice) {\n            pybind11::ssize_t index, step, slice_length;\n            if (normalize_index_or_slice(index_or_slice, self.num_qubits, &index, &step, &slice_length)) {\n                return pybind11::cast(self.py_get_slice(index, step, slice_length));\n            }\n            return pybind11::cast(GateTypeWrapper{self.gate_at(index)});\n        },\n        pybind11::arg(\"index_or_slice\"),\n        clean_doc_string(R\"DOC(\n            @overload def __getitem__(self, index_or_slice: int) -> stim.GateData:\n            @overload def __getitem__(self, index_or_slice: slice) -> stim.CliffordString:\n            @signature def __getitem__(self, index_or_slice: Union[int, slice]) -> Union[stim.GateData, stim.CliffordString]:\n            Returns a Clifford or substring from the CliffordString.\n\n            Args:\n                index_or_slice: The index of the Clifford to return, or the slice\n                    corresponding to the sub CliffordString to return.\n\n            Returns:\n                The indexed Clifford (as a stim.GateData instance) or the sliced\n                CliffordString.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.CliffordString(\"I,X,Y,Z,H\")\n\n                >>> s[2]\n                stim.gate_data('Y')\n\n                >>> s[-1]\n                stim.gate_data('H')\n\n                >>> s[:-1]\n                stim.CliffordString(\"I,X,Y,Z\")\n\n                >>> s[::2]\n                stim.CliffordString(\"I,Y,H\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__setitem__\",\n        [](CliffordString<MAX_BITWORD_WIDTH> &self,\n           const pybind11::object &index_or_slice,\n           const pybind11::object &new_value) {\n            pybind11::ssize_t index, step, slice_length;\n            bool is_slice = normalize_index_or_slice(index_or_slice, self.num_qubits, &index, &step, &slice_length);\n            if (pybind11::isinstance<GateTypeWrapper>(new_value)) {\n                GateType g = pybind11::cast<GateTypeWrapper>(new_value).type;\n                for (size_t k = 0; k < (size_t)slice_length; k++) {\n                    size_t target_k = index + step * k;\n                    self.set_gate_at(target_k, g);\n                }\n                return;\n            } else if (pybind11::isinstance<pybind11::str>(new_value)) {\n                GateType g = GATE_DATA.at(pybind11::cast<std::string_view>(new_value)).id;\n                for (size_t k = 0; k < (size_t)slice_length; k++) {\n                    size_t target_k = index + step * k;\n                    self.set_gate_at(target_k, g);\n                }\n                return;\n            } else if (pybind11::isinstance<Tableau<MAX_BITWORD_WIDTH>>(new_value)) {\n                const Tableau<MAX_BITWORD_WIDTH> &t = pybind11::cast<const Tableau<MAX_BITWORD_WIDTH> &>(new_value);\n                if (t.num_qubits == 1) {\n                    GateType g = single_qubit_tableau_to_gate_type(t);\n                    for (size_t k = 0; k < (size_t)slice_length; k++) {\n                        size_t target_k = index + step * k;\n                        self.set_gate_at(target_k, g);\n                    }\n                    return;\n                }\n            } else if (is_slice && pybind11::isinstance<CliffordString<MAX_BITWORD_WIDTH>>(new_value)) {\n                const CliffordString<MAX_BITWORD_WIDTH> &v =\n                    pybind11::cast<const CliffordString<MAX_BITWORD_WIDTH> &>(new_value);\n                if (v.num_qubits != (size_t)slice_length) {\n                    std::stringstream ss;\n                    ss << \"Length mismatch. The targeted slice covers \" << slice_length;\n                    ss << \" values but the given CliffordString has \" << v.num_qubits << \" values.\";\n                    throw std::invalid_argument(ss.str());\n                }\n                for (size_t k = 0; k < (size_t)slice_length; k++) {\n                    size_t target_k = index + step * k;\n                    self.set_gate_at(target_k, v.gate_at(k));\n                }\n                return;\n            } else if (is_slice && pybind11::isinstance<FlexPauliString>(new_value)) {\n                const FlexPauliString &v = pybind11::cast<const FlexPauliString &>(new_value);\n                if (v.value.num_qubits != (size_t)slice_length) {\n                    std::stringstream ss;\n                    ss << \"Length mismatch. The targeted slice covers \" << slice_length;\n                    ss << \" values but the given PauliString has \" << v.value.num_qubits << \" values.\";\n                    throw std::invalid_argument(ss.str());\n                }\n                for (size_t k = 0; k < (size_t)slice_length; k++) {\n                    size_t target_k = index + step * k;\n                    self.inv_x2x[target_k] = 0;\n                    self.x2z[target_k] = 0;\n                    self.z2x[target_k] = 0;\n                    self.inv_z2z[target_k] = 0;\n                    self.x_signs[target_k] = v.value.zs[k];\n                    self.z_signs[target_k] = v.value.xs[k];\n                }\n                return;\n            }\n\n            std::stringstream ss;\n            ss << \"Don't know how to write an object of type \";\n            ss << pybind11::repr(pybind11::type::of(new_value));\n            ss << \" to index \";\n            ss << pybind11::repr(index_or_slice);\n            throw std::invalid_argument(ss.str());\n        },\n        pybind11::arg(\"index_or_slice\"),\n        pybind11::arg(\"new_value\"),\n        clean_doc_string(R\"DOC(\n            @signature def __setitem__(self, index_or_slice: Union[int, slice], new_value: Union[str, stim.GateData, stim.CliffordString, stim.PauliString, stim.Tableau]) -> None:\n            Overwrites an indexed Clifford, or slice of Cliffords, with the given value.\n\n            Args:\n                index_or_slice: The index of the Clifford to overwrite, or the slice\n                    of Cliffords to overwrite.\n                new_value: Specifies the value to write into the Clifford string. This can\n                    be set to a few different types of values:\n                    - str: Name of the single qubit Clifford gate to write to the index or\n                        broadcast over the slice.\n                    - stim.GateData: The single qubit Clifford gate to write to the index\n                        or broadcast over the slice.\n                    - stim.Tableau: Must be a single qubit tableau. Specifies the single\n                        qubit Clifford gate to write to the index or broadcast over the\n                        slice.\n                    - stim.CliffordString: String of Cliffords to write into the slice.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.CliffordString(\"I,I,I,I,I\")\n\n                >>> s[1] = 'H'\n                >>> s\n                stim.CliffordString(\"I,H,I,I,I\")\n\n                >>> s[2:] = 'SQRT_X'\n                >>> s\n                stim.CliffordString(\"I,H,SQRT_X,SQRT_X,SQRT_X\")\n\n                >>> s[0] = stim.gate_data('S_DAG').inverse\n                >>> s\n                stim.CliffordString(\"S,H,SQRT_X,SQRT_X,SQRT_X\")\n\n                >>> s[:] = 'I'\n                >>> s\n                stim.CliffordString(\"I,I,I,I,I\")\n\n                >>> s[::2] = stim.CliffordString(\"X,Y,Z\")\n                >>> s\n                stim.CliffordString(\"X,I,Y,I,Z\")\n\n                >>> s[0] = stim.Tableau.from_named_gate(\"H\")\n                >>> s\n                stim.CliffordString(\"H,I,Y,I,Z\")\n\n                >>> s[:] = stim.Tableau.from_named_gate(\"S\")\n                >>> s\n                stim.CliffordString(\"S,S,S,S,S\")\n\n                >>> s[:4] = stim.PauliString(\"IXYZ\")\n                >>> s\n                stim.CliffordString(\"I,X,Y,Z,S\")\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"random\",\n        [](size_t num_qubits) {\n            auto rng = make_py_seeded_rng(pybind11::none());\n            return CliffordString<MAX_BITWORD_WIDTH>::random(num_qubits, rng);\n        },\n        pybind11::arg(\"num_qubits\"),\n        clean_doc_string(R\"DOC(\n            Samples a uniformly random CliffordString.\n\n            Args:\n                num_qubits: The number of qubits the CliffordString should act upon.\n\n            Examples:\n                >>> import stim\n                >>> p = stim.CliffordString.random(5)\n                >>> len(p)\n                5\n\n            Returns:\n                The sampled Clifford string.\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"all_cliffords_string\",\n        []() -> CliffordString<MAX_BITWORD_WIDTH> {\n            CliffordString<MAX_BITWORD_WIDTH> result(24);\n            result.set_gate_at(0, GateType::I);\n            result.set_gate_at(4, GateType::H_XY);\n            result.set_gate_at(8, GateType::H);\n            result.set_gate_at(12, GateType::H_YZ);\n            result.set_gate_at(16, GateType::C_XYZ);\n            result.set_gate_at(20, GateType::C_ZYX);\n            for (size_t q = 0; q < 24; q++) {\n                if (q % 4) {\n                    result.set_gate_at(q, result.gate_at(q - 1));\n                }\n            }\n\n            CliffordString<MAX_BITWORD_WIDTH> ixyz(24);\n            for (size_t q = 0; q < 24; q += 4) {\n                ixyz.set_gate_at(q + 0, GateType::I);\n                ixyz.set_gate_at(q + 1, GateType::X);\n                ixyz.set_gate_at(q + 2, GateType::Y);\n                ixyz.set_gate_at(q + 3, GateType::Z);\n            }\n            result *= ixyz;\n            return result;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a stim.CliffordString containing each single qubit Clifford once.\n\n            Useful for things like testing that a method works on every single Clifford.\n\n            Examples:\n                >>> import stim\n                >>> cliffords = stim.CliffordString.all_cliffords_string()\n                >>> len(cliffords)\n                24\n\n                >>> print(cliffords[:8])\n                I,X,Y,Z,H_XY,S,S_DAG,H_NXY\n\n                >>> print(cliffords[8:16])\n                H,SQRT_Y_DAG,H_NXZ,SQRT_Y,H_YZ,H_NYZ,SQRT_X,SQRT_X_DAG\n\n                >>> print(cliffords[16:])\n                C_XYZ,C_XYNZ,C_NXYZ,C_XNYZ,C_ZYX,C_ZNYX,C_NZYX,C_ZYNX\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__ipow__\",\n        [](pybind11::object self, int64_t power) {\n            pybind11::cast<CliffordString<MAX_BITWORD_WIDTH> &>(self).ipow(power);\n            return self;\n        },\n        pybind11::arg(\"num_qubits\"),\n        clean_doc_string(R\"DOC(\n            Mutates the CliffordString into itself raised to a power.\n\n            Args:\n                power: The power to raise the CliffordString's Cliffords to.\n                    This value can be negative (e.g. -1 inverts the string).\n\n            Returns:\n                The mutated Clifford string.\n\n            Examples:\n                >>> import stim\n\n                >>> p = stim.CliffordString(\"I,X,H,S,C_XYZ\")\n                >>> p **= 3\n                >>> p\n                stim.CliffordString(\"I,X,H,S_DAG,I\")\n\n                >>> p **= 2\n                >>> p\n                stim.CliffordString(\"I,I,I,Z,I\")\n\n                >>> alias = p\n                >>> alias **= 2\n                >>> p\n                stim.CliffordString(\"I,I,I,I,I\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__pow__\",\n        [](const CliffordString<MAX_BITWORD_WIDTH> &self, int64_t power) -> CliffordString<MAX_BITWORD_WIDTH> {\n            auto copy = self;\n            copy.ipow(power);\n            return copy;\n        },\n        pybind11::arg(\"power\"),\n        clean_doc_string(R\"DOC(\n            Returns the CliffordString raised to a power.\n\n            Args:\n                power: The power to raise the CliffordString's Cliffords to.\n                    This value can be negative (e.g. -1 returns the inverse string).\n\n            Returns:\n                The Clifford string raised to the power.\n\n            Examples:\n                >>> import stim\n\n                >>> p = stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n                >>> p**0\n                stim.CliffordString(\"I,I,I,I,I\")\n\n                >>> p**1\n                stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n                >>> p**12000001\n                stim.CliffordString(\"I,X,H,S,C_XYZ\")\n\n                >>> p**2\n                stim.CliffordString(\"I,I,I,Z,C_ZYX\")\n\n                >>> p**3\n                stim.CliffordString(\"I,X,H,S_DAG,I\")\n\n                >>> p**-1\n                stim.CliffordString(\"I,X,H,S_DAG,C_ZYX\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__add__\",\n        &CliffordString<MAX_BITWORD_WIDTH>::operator+,\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Concatenates two CliffordStrings.\n\n            Args:\n                rhs: The suffix of the concatenation.\n\n            Returns:\n                The concatenated Clifford string.\n\n            Examples:\n                >>> import stim\n                >>> stim.CliffordString(\"I,X,H\") + stim.CliffordString(\"Y,S\")\n                stim.CliffordString(\"I,X,H,Y,S\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"copy\",\n        [](const CliffordString<MAX_BITWORD_WIDTH> &self) -> CliffordString<MAX_BITWORD_WIDTH> {\n            return self;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the CliffordString.\n\n            Returns:\n                The copy.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.CliffordString(\"H,X\")\n                >>> alias = c\n                >>> copy = c.copy()\n                >>> c *= 5\n                >>> alias\n                stim.CliffordString(\"H,X,H,X,H,X,H,X,H,X\")\n                >>> copy\n                stim.CliffordString(\"H,X\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__iadd__\",\n        &CliffordString<MAX_BITWORD_WIDTH>::operator+=,\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Mutates the CliffordString by concatenating onto it.\n\n            Args:\n                rhs: The suffix to concatenate onto the target CliffordString.\n\n            Returns:\n                The mutated Clifford string.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.CliffordString(\"I,X,H\")\n                >>> alias = c\n                >>> alias += stim.CliffordString(\"Y,S\")\n                >>> c\n                stim.CliffordString(\"I,X,H,Y,S\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__rmul__\",\n        [](const CliffordString<MAX_BITWORD_WIDTH> &self, size_t rhs) -> CliffordString<MAX_BITWORD_WIDTH> {\n            return self * rhs;\n        },\n        pybind11::arg(\"lhs\"),\n        clean_doc_string(R\"DOC(\n            CliffordString left-multiplication.\n\n            Args:\n                lhs: The number of times to repeat the Clifford string's contents.\n\n            Returns:\n                The repeated Clifford string.\n\n            Examples:\n                >>> import stim\n\n                >>> 2 * stim.CliffordString(\"I,X,H\")\n                stim.CliffordString(\"I,X,H,I,X,H\")\n\n                >>> 0 * stim.CliffordString(\"I,X,H\")\n                stim.CliffordString(\"\")\n\n                >>> 5 * stim.CliffordString(\"I\")\n                stim.CliffordString(\"I,I,I,I,I\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__mul__\",\n        [](const CliffordString<MAX_BITWORD_WIDTH> &self, pybind11::object rhs) -> CliffordString<MAX_BITWORD_WIDTH> {\n            if (pybind11::isinstance<pybind11::int_>(rhs)) {\n                return self * pybind11::cast<size_t>(rhs);\n            } else if (pybind11::isinstance<CliffordString<MAX_BITWORD_WIDTH>>(rhs)) {\n                return self * pybind11::cast<const CliffordString<MAX_BITWORD_WIDTH> &>(rhs);\n            } else {\n                std::stringstream ss;\n                ss << \"Don't know how to multiply by \";\n                ss << pybind11::repr(rhs);\n                throw std::invalid_argument(ss.str());\n            }\n        },\n        clean_doc_string(R\"DOC(\n            @signature def __mul__(self, rhs: Union[stim.CliffordString, int]) -> stim.CliffordString:\n            CliffordString multiplication.\n\n            Args:\n                rhs: Either a stim.CliffordString or an int. If rhs is a\n                    stim.CliffordString, then the Cliffords from each string are multiplied\n                    pairwise. If rhs is an int, it is the number of times to repeat the\n                    Clifford string's contents.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.CliffordString(\"S,X,X\") * stim.CliffordString(\"S,Z,H,Z\")\n                stim.CliffordString(\"Z,Y,SQRT_Y,Z\")\n\n                >>> stim.CliffordString(\"I,X,H\") * 3\n                stim.CliffordString(\"I,X,H,I,X,H,I,X,H\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__imul__\",\n        [](pybind11::object self_obj, pybind11::object rhs) -> pybind11::object {\n            CliffordString<MAX_BITWORD_WIDTH> &self = pybind11::cast<CliffordString<MAX_BITWORD_WIDTH> &>(self_obj);\n            if (pybind11::isinstance<pybind11::int_>(rhs)) {\n                self *= pybind11::cast<size_t>(rhs);\n                return self_obj;\n            } else if (pybind11::isinstance<CliffordString<MAX_BITWORD_WIDTH>>(rhs)) {\n                self *= pybind11::cast<const CliffordString<MAX_BITWORD_WIDTH> &>(rhs);\n                return self_obj;\n            } else {\n                std::stringstream ss;\n                ss << \"Don't know how to multiply by \";\n                ss << pybind11::repr(rhs);\n                throw std::invalid_argument(ss.str());\n            }\n        },\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            @signature def __imul__(self, rhs: Union[stim.CliffordString, int]) -> stim.CliffordString:\n            Inplace CliffordString multiplication.\n\n            Mutates the CliffordString into itself multiplied by another CliffordString\n            (via pairwise Clifford multipliation) or by an integer (via repeating the\n            contents).\n\n            Args:\n                rhs: Either a stim.CliffordString or an int. If rhs is a\n                    stim.CliffordString, then the Cliffords from each string are multiplied\n                    pairwise. If rhs is an int, it is the number of times to repeat the\n                    Clifford string's contents.\n\n            Returns:\n                The mutated Clifford string.\n\n            Examples:\n                >>> import stim\n\n                >>> c = stim.CliffordString(\"S,X,X\")\n                >>> alias = c\n                >>> alias *= stim.CliffordString(\"S,Z,H,Z\")\n                >>> c\n                stim.CliffordString(\"Z,Y,SQRT_Y,Z\")\n\n                >>> c = stim.CliffordString(\"I,X,H\")\n                >>> alias = c\n                >>> alias *= 2\n                >>> c\n                stim.CliffordString(\"I,X,H,I,X,H\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"x_outputs\",\n        [](const CliffordString<MAX_BITWORD_WIDTH> &self, bool bit_packed_signs) -> pybind11::object {\n            auto ps = self.x_outputs();\n            FlexPauliString result(std::move(ps));\n            return pybind11::make_tuple(\n                pybind11::cast(result), simd_bits_to_numpy(self.x_signs, self.num_qubits, bit_packed_signs));\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed_signs\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def x_outputs(self, *, bit_packed_signs: bool = False) -> tuple[stim.PauliString, np.ndarray]:\n            Returns what each Clifford in the CliffordString conjugates an X input into.\n\n            For example, H conjugates X into +Z and S_DAG conjugates X into -Y.\n\n            Combined with `z_outputs`, the results of this method completely specify\n            the single qubit Clifford applied to each qubit.\n\n            Args:\n                bit_packed_signs: Defaults to False. When False, the sign data is returned\n                    in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n                    `np.uint8` and 8 bits are packed into each byte (in little endian\n                    order).\n\n            Returns:\n                A (paulis, signs) tuple.\n\n                `paulis` has type stim.PauliString. Its sign is always positive.\n\n                `signs` has type np.ndarray and an argument-dependent shape:\n                    bit_packed_signs=False:\n                        dtype=np.bool_\n                        shape=(num_qubits,)\n                    bit_packed_signs=True:\n                        dtype=np.uint8\n                        shape=(math.ceil(num_qubits / 8),)\n\n            Examples:\n                >>> import stim\n                >>> x_paulis, x_signs = stim.CliffordString(\"I,Y,H,S\").x_outputs()\n                >>> x_paulis\n                stim.PauliString(\"+XXZY\")\n                >>> x_signs\n                array([False,  True, False, False])\n\n                >>> stim.CliffordString(\"I,Y,H,S\").x_outputs(bit_packed_signs=True)[1]\n                array([2], dtype=uint8)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"y_outputs\",\n        [](CliffordString<MAX_BITWORD_WIDTH> &self, bool bit_packed_signs) -> pybind11::object {\n            simd_bits<MAX_BITWORD_WIDTH> signs(self.num_qubits);\n            auto ys = self.y_outputs_and_signs(signs);\n            FlexPauliString result(std::move(ys));\n            return pybind11::make_tuple(\n                pybind11::cast(result), simd_bits_to_numpy(signs, self.num_qubits, bit_packed_signs));\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed_signs\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def y_outputs(self, *, bit_packed_signs: bool = False) -> tuple[stim.PauliString, np.ndarray]:\n            Returns what each Clifford in the CliffordString conjugates a Y input into.\n\n            For example, H conjugates Y into -Y and S_DAG conjugates Y into +X.\n\n            Args:\n                bit_packed_signs: Defaults to False. When False, the sign data is returned\n                    in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n                    `np.uint8` and 8 bits are packed into each byte (in little endian\n                    order).\n\n            Returns:\n                A (paulis, signs) tuple.\n\n                `paulis` has type stim.PauliString. Its sign is always positive.\n\n                `signs` has type np.ndarray and an argument-dependent shape:\n                    bit_packed_signs=False:\n                        dtype=np.bool_\n                        shape=(num_qubits,)\n                    bit_packed_signs=True:\n                        dtype=np.uint8\n                        shape=(math.ceil(num_qubits / 8),)\n\n            Examples:\n                >>> import stim\n                >>> y_paulis, y_signs = stim.CliffordString(\"I,X,H,S\").y_outputs()\n                >>> y_paulis\n                stim.PauliString(\"+YYYX\")\n                >>> y_signs\n                array([False,  True,  True,  True])\n\n                >>> stim.CliffordString(\"I,X,H,S\").y_outputs(bit_packed_signs=True)[1]\n                array([14], dtype=uint8)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"z_outputs\",\n        [](const CliffordString<MAX_BITWORD_WIDTH> &self, bool bit_packed_signs) -> pybind11::object {\n            auto ps = self.z_outputs();\n            FlexPauliString result(std::move(ps));\n            return pybind11::make_tuple(\n                pybind11::cast(result), simd_bits_to_numpy(self.z_signs, self.num_qubits, bit_packed_signs));\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed_signs\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def z_outputs(self, *, bit_packed_signs: bool = False) -> tuple[stim.PauliString, np.ndarray]:\n            Returns what each Clifford in the CliffordString conjugates a Z input into.\n\n            For example, H conjugates Z into +X and SQRT_X conjugates Z into -Y.\n\n            Combined with `x_outputs`, the results of this method completely specify\n            the single qubit Clifford applied to each qubit.\n\n            Args:\n                bit_packed_signs: Defaults to False. When False, the sign data is returned\n                    in a numpy array with dtype `np.bool_`. When True, the dtype is instead\n                    `np.uint8` and 8 bits are packed into each byte (in little endian\n                    order).\n\n            Returns:\n                A (paulis, signs) tuple.\n\n                `paulis` has type stim.PauliString. Its sign is always positive.\n\n                `signs` has type np.ndarray and an argument-dependent shape:\n                    bit_packed_signs=False:\n                        dtype=np.bool_\n                        shape=(num_qubits,)\n                    bit_packed_signs=True:\n                        dtype=np.uint8\n                        shape=(math.ceil(num_qubits / 8),)\n\n            Examples:\n                >>> import stim\n                >>> z_paulis, z_signs = stim.CliffordString(\"I,Y,H,S\").z_outputs()\n                >>> z_paulis\n                stim.PauliString(\"+ZZXZ\")\n                >>> z_signs\n                array([False,  True, False, False])\n\n                >>> stim.CliffordString(\"I,Y,H,S\").z_outputs(bit_packed_signs=True)[1]\n                array([2], dtype=uint8)\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/stabilizers/clifford_string.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_STABILIZERS_CLIFFORD_STRING_PYBIND_H\n#define _STIM_STABILIZERS_CLIFFORD_STRING_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/stabilizers/clifford_string.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::CliffordString<stim::MAX_BITWORD_WIDTH>> pybind_clifford_string(pybind11::module &m);\nvoid pybind_clifford_string_methods(\n    pybind11::module &m, pybind11::class_<stim::CliffordString<stim::MAX_BITWORD_WIDTH>> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/clifford_string.test.cc",
    "content": "#include \"stim/stabilizers/clifford_string.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/stabilizers/tableau.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nstd::vector<Gate> single_qubit_clifford_rotations() {\n    std::vector<Gate> result;\n    for (size_t g = 0; g < NUM_DEFINED_GATES; g++) {\n        const Gate &gate = GATE_DATA[(GateType)g];\n        if ((gate.flags & GateFlags::GATE_IS_SINGLE_QUBIT_GATE) && (gate.flags & GateFlags::GATE_IS_UNITARY)) {\n            result.push_back(gate);\n        }\n    }\n    assert(result.size() == 24);\n    return result;\n}\n\nTEST_EACH_WORD_SIZE_W(clifford_string, set_gate_at_vs_str_vs_gate_at, {\n    CliffordString<W> p = CliffordString<W>(24);\n    int x = 0;\n\n    p.set_gate_at(x++, GateType::I);\n    p.set_gate_at(x++, GateType::X);\n    p.set_gate_at(x++, GateType::Y);\n    p.set_gate_at(x++, GateType::Z);\n\n    p.set_gate_at(x++, GateType::H);\n    p.set_gate_at(x++, GateType::SQRT_Y_DAG);\n    p.set_gate_at(x++, GateType::H_NXZ);\n    p.set_gate_at(x++, GateType::SQRT_Y);\n\n    p.set_gate_at(x++, GateType::S);\n    p.set_gate_at(x++, GateType::H_XY);\n    p.set_gate_at(x++, GateType::H_NXY);\n    p.set_gate_at(x++, GateType::S_DAG);\n\n    p.set_gate_at(x++, GateType::SQRT_X_DAG);\n    p.set_gate_at(x++, GateType::SQRT_X);\n    p.set_gate_at(x++, GateType::H_NYZ);\n    p.set_gate_at(x++, GateType::H_YZ);\n\n    p.set_gate_at(x++, GateType::C_XYZ);\n    p.set_gate_at(x++, GateType::C_XYNZ);\n    p.set_gate_at(x++, GateType::C_NXYZ);\n    p.set_gate_at(x++, GateType::C_XNYZ);\n\n    p.set_gate_at(x++, GateType::C_ZYX);\n    p.set_gate_at(x++, GateType::C_ZNYX);\n    p.set_gate_at(x++, GateType::C_NZYX);\n    p.set_gate_at(x++, GateType::C_ZYNX);\n\n    ASSERT_EQ(p.str(), \"_I _X _Y _Z HI HX HY HZ SI SX SY SZ VI VX VY VZ uI uX uY uZ dI dX dY dZ\");\n\n    x = 0;\n\n    EXPECT_EQ(p.gate_at(x++), GateType::I);\n    EXPECT_EQ(p.gate_at(x++), GateType::X);\n    EXPECT_EQ(p.gate_at(x++), GateType::Y);\n    EXPECT_EQ(p.gate_at(x++), GateType::Z);\n\n    EXPECT_EQ(p.gate_at(x++), GateType::H);\n    EXPECT_EQ(p.gate_at(x++), GateType::SQRT_Y_DAG);\n    EXPECT_EQ(p.gate_at(x++), GateType::H_NXZ);\n    EXPECT_EQ(p.gate_at(x++), GateType::SQRT_Y);\n\n    EXPECT_EQ(p.gate_at(x++), GateType::S);\n    EXPECT_EQ(p.gate_at(x++), GateType::H_XY);\n    EXPECT_EQ(p.gate_at(x++), GateType::H_NXY);\n    EXPECT_EQ(p.gate_at(x++), GateType::S_DAG);\n\n    EXPECT_EQ(p.gate_at(x++), GateType::SQRT_X_DAG);\n    EXPECT_EQ(p.gate_at(x++), GateType::SQRT_X);\n    EXPECT_EQ(p.gate_at(x++), GateType::H_NYZ);\n    EXPECT_EQ(p.gate_at(x++), GateType::H_YZ);\n\n    EXPECT_EQ(p.gate_at(x++), GateType::C_XYZ);\n    EXPECT_EQ(p.gate_at(x++), GateType::C_XYNZ);\n    EXPECT_EQ(p.gate_at(x++), GateType::C_NXYZ);\n    EXPECT_EQ(p.gate_at(x++), GateType::C_XNYZ);\n\n    EXPECT_EQ(p.gate_at(x++), GateType::C_ZYX);\n    EXPECT_EQ(p.gate_at(x++), GateType::C_ZNYX);\n    EXPECT_EQ(p.gate_at(x++), GateType::C_NZYX);\n    EXPECT_EQ(p.gate_at(x++), GateType::C_ZYNX);\n});\n\nTEST_EACH_WORD_SIZE_W(clifford_string, multiplication_table_vs_tableau_multiplication, {\n    std::vector<Gate> single_qubit_gates = single_qubit_clifford_rotations();\n\n    std::map<std::string, GateType> t2g;\n    for (const auto &g : single_qubit_gates) {\n        t2g[g.tableau<W>().str()] = g.id;\n    }\n\n    CliffordString<W> p1 = CliffordString<W>(24 * 24);\n    CliffordString<W> p2 = CliffordString<W>(24 * 24);\n    CliffordString<W> p12 = CliffordString<W>(24 * 24);\n    for (size_t k1 = 0; k1 < 24; k1++) {\n        for (size_t k2 = 0; k2 < 24; k2++) {\n            size_t k = k1 * 24 + k2;\n            Gate g1 = single_qubit_gates[k1];\n            Gate g2 = single_qubit_gates[k2];\n            p1.set_gate_at(k, g1.id);\n            p2.set_gate_at(k, g2.id);\n            auto t1 = g1.tableau<W>();\n            auto t2 = g2.tableau<W>();\n            auto t3 = t2.then(t1);\n            auto g3 = t2g[t3.str()];\n            p12.set_gate_at(k, g3);\n        }\n    }\n    ASSERT_EQ(p1 * p2, p12);\n})\n\nTEST_EACH_WORD_SIZE_W(clifford_string, to_from_circuit, {\n    Circuit circuit(R\"CIRCUIT(\n        H 0\n        H_XY 1\n        H_YZ 2\n        H_NXY 3\n        H_NXZ 4\n        H_NYZ 5\n        S_DAG 6\n        X 7\n        Y 8\n        Z 9\n        C_XYZ 10\n        C_ZYX 11\n        C_NXYZ 12\n        C_XNYZ 13\n        C_XYNZ 14\n        C_NZYX 15\n        C_ZNYX 16\n        C_ZYNX 17\n        SQRT_X 18\n        SQRT_X_DAG 19\n        SQRT_Y 20\n        SQRT_Y_DAG 21\n        S 22\n        I 23\n    )CIRCUIT\");\n    CliffordString<W> s = CliffordString<W>::from_circuit(circuit);\n    ASSERT_EQ(s.to_circuit(), circuit);\n})\n\nTEST_EACH_WORD_SIZE_W(clifford_string, known_identities, {\n    auto s1 = CliffordString<W>::from_circuit(Circuit(R\"CIRCUIT(\n        H 0\n    )CIRCUIT\"));\n    auto s2 = CliffordString<W>::from_circuit(Circuit(R\"CIRCUIT(\n        H 0\n    )CIRCUIT\"));\n    auto s3 = CliffordString<W>::from_circuit(Circuit(R\"CIRCUIT(\n        I 0\n    )CIRCUIT\"));\n    ASSERT_EQ(s2 * s1, s3);\n\n    s1 = CliffordString<W>::from_circuit(Circuit(R\"CIRCUIT(\n        S 0\n    )CIRCUIT\"));\n    s2 = CliffordString<W>::from_circuit(Circuit(R\"CIRCUIT(\n        S 0\n    )CIRCUIT\"));\n    s3 = CliffordString<W>::from_circuit(Circuit(R\"CIRCUIT(\n        Z 0\n    )CIRCUIT\"));\n    ASSERT_EQ(s2 * s1, s3);\n\n    s1 = CliffordString<W>::from_circuit(Circuit(R\"CIRCUIT(\n        S_DAG 0\n    )CIRCUIT\"));\n    s2 = CliffordString<W>::from_circuit(Circuit(R\"CIRCUIT(\n        H 0\n    )CIRCUIT\"));\n    s3 = CliffordString<W>::from_circuit(Circuit(R\"CIRCUIT(\n        C_XYZ 0\n    )CIRCUIT\"));\n    ASSERT_EQ(s2 * s1, s3);\n})\n\nTEST_EACH_WORD_SIZE_W(clifford_string, random, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    CliffordString<W> c = CliffordString<W>::random(256, rng);\n    std::array<uint64_t, NUM_DEFINED_GATES> counts{};\n    for (size_t k = 0; k < 256; k++) {\n        for (size_t q = 0; q < 256; q++) {\n            GateType t = c.gate_at(q);\n            counts[(uint8_t)t] += 1;\n        }\n        c.randomize(rng);\n    }\n    ASSERT_EQ(counts[(uint8_t)GateType::NOT_A_GATE], 0);\n    size_t seen_gates = 0;\n    for (const auto &g : GATE_DATA.items) {\n        if ((g.flags & GATE_IS_UNITARY) && (g.flags & GATE_IS_SINGLE_QUBIT_GATE)) {\n            ASSERT_LT(counts[(uint8_t)g.id], 256.0 * 256.0 / 24.0 * (1.0 + 0.5));\n            ASSERT_GT(counts[(uint8_t)g.id], 256.0 * 256.0 / 24.0 * (1.0 - 0.5));\n            seen_gates++;\n        }\n    }\n    ASSERT_EQ(seen_gates, 24);\n})\n"
  },
  {
    "path": "src/stim/stabilizers/clifford_string_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport numpy as np\nimport pytest\nimport stim\n\n\ndef test_trivial():\n    p = stim.CliffordString(3)\n    assert repr(p) == 'stim.CliffordString(\"I,I,I\")'\n    assert len(p) == 3\n    assert p[1:] == stim.CliffordString(2)\n    assert p[0] == stim.gate_data('I')\n\n\ndef test_simple():\n    assert stim.CliffordString(\"X,Y,Z,H,SQRT_X,C_XYZ,H_NXZ\") == stim.CliffordString(\"  X  ,   Y  ,  Z  , H_XZ , SQRT_X,C_XYZ,H_NXZ,   \")\n    p = stim.CliffordString(\"X,Y,Z,H,SQRT_X,C_XYZ,H_NXZ\")\n    assert repr(p) == 'stim.CliffordString(\"X,Y,Z,H,SQRT_X,C_XYZ,H_NXZ\")'\n    assert str(p) == 'X,Y,Z,H,SQRT_X,C_XYZ,H_NXZ'\n    assert len(p) == 7\n    assert p != stim.CliffordString(\"Y,Y,Z,H,SQRT_X,C_XYZ,H_NXZ\")\n    assert not (p != stim.CliffordString(\"X,Y,Z,H,SQRT_X,C_XYZ,H_NXZ\"))\n    assert not (p == stim.CliffordString(\"Y,Y,Z,H,SQRT_X,C_XYZ,H_NXZ\"))\n    assert p[1::2] == stim.CliffordString(\"Y,H,C_XYZ\")\n\n    assert stim.CliffordString(6) == stim.CliffordString(\"I,I,I,I,I,I\")\n\n    assert stim.CliffordString(stim.PauliString(\"XYZ_XYZ\")) == stim.CliffordString(\"X,Y,Z,I,X,Y,Z\")\n\n    v = stim.CliffordString(\"X,Y,H\")\n    v2 = stim.CliffordString(v)\n    assert v == v2\n    assert v is not v2\n\n    assert stim.CliffordString(['X', 'Y', 'Z', stim.gate_data('H'), 'S']) == stim.CliffordString('X,Y,Z,H,S')\n\n\ndef test_multiplication():\n    a = stim.CliffordString(\"Z,H,S,C_XYZ\")\n    b = stim.CliffordString(\"S,Z,S,C_XYZ,I\")\n    assert a * b == stim.CliffordString(\"S_DAG,SQRT_Y,Z,C_ZYX,I\")\n    a *= b\n    assert a == stim.CliffordString(\"S_DAG,SQRT_Y,Z,C_ZYX,I\")\n\n    assert stim.CliffordString(\"X\") * stim.CliffordString(\"H\") == stim.CliffordString(\"H\") * stim.CliffordString(\"Z\")\n    assert stim.CliffordString(\"X\") * stim.CliffordString(\"H\") != stim.CliffordString(\"Z\") * stim.CliffordString(\"H\")\n    assert stim.CliffordString(\"X\") * stim.CliffordString(\"H\") == stim.CliffordString(\"SQRT_Y\")\n\n\ndef test_random():\n    c1 = stim.CliffordString.random(128)\n    c2 = stim.CliffordString.random(128)\n    assert len(c1) == len(c2) == 128\n    assert c1 != c2\n\n\ndef test_set_item():\n    c = stim.CliffordString(5)\n    c[1] = \"H\"\n    assert c == stim.CliffordString(\"I,H,I,I,I\")\n    with pytest.raises(ValueError, match=\"index\"):\n        c[2:3] = None\n    with pytest.raises(ValueError, match=\"index\"):\n        c[2] = None\n    c[2:4] = stim.CliffordString(\"X,Y\")\n    assert c == stim.CliffordString(\"I,H,X,Y,I\")\n    c[::2] = stim.CliffordString(\"S,Z,S_DAG\")\n    assert c == stim.CliffordString(\"S,H,Z,Y,S_DAG\")\n    c[:] = 'H'\n    assert c == stim.CliffordString(\"H,H,H,H,H\")\n    c[:-2] = stim.gate_data('S')\n    assert c == stim.CliffordString(\"S,S,S,H,H\")\n    c[0] = stim.gate_data('X')\n    assert c == stim.CliffordString(\"X,S,S,H,H\")\n\n    with pytest.raises(ValueError, match=\"object of type\"):\n        c[0] = stim.CliffordString(\"Y\")\n    with pytest.raises(ValueError, match=\"Length mismatch\"):\n        c[:2] = stim.CliffordString(\"Y\")\n    assert c == stim.CliffordString(\"X,S,S,H,H\")\n    c[:2] = stim.CliffordString(\"Y,Y\")\n    assert c == stim.CliffordString(\"Y,Y,S,H,H\")\n\n\ndef all_cliffords_string_from_gate_data():\n    c = stim.CliffordString(24)\n    r = 0\n    for g in stim.gate_data().values():\n        if g.is_unitary and g.is_single_qubit_gate:\n            c[r] = g\n            r += 1\n    return c\n\n\ndef test_x_outputs():\n    paulis, signs = stim.CliffordString(\"I,X,Y,Z,H,S,S_DAG,C_XYZ,C_ZYX,SQRT_X,SQRT_X_DAG\").x_outputs()\n    assert paulis == stim.PauliString(\"XXXXZYYYZXX\")\n    np.testing.assert_array_equal(signs, [0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0])\n\n    c = all_cliffords_string_from_gate_data()\n    paulis, signs = c.x_outputs()\n    for k in range(len(c)):\n        expected = c[k].tableau.x_output(0)\n        assert (-1 if signs[k] else 1) == expected.sign\n        assert paulis[k] == expected[0]\n\n\ndef test_y_outputs():\n    paulis, signs = stim.CliffordString(\"I,X,Y,Z,H,S,S_DAG,C_XYZ,C_ZYX,SQRT_X,SQRT_X_DAG\").y_outputs()\n    assert paulis == stim.PauliString(\"YYYYYXXZXZZ\")\n    np.testing.assert_array_equal(signs, [0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1])\n\n    c = all_cliffords_string_from_gate_data()\n    paulis, signs = c.y_outputs()\n    for k in range(len(c)):\n        expected = c[k].tableau.y_output(0)\n        assert (-1 if signs[k] else 1) == expected.sign\n        assert paulis[k] == expected[0]\n\n\ndef test_z_outputs():\n    paulis, signs = stim.CliffordString(\"I,X,Y,Z,H,S,S_DAG,C_XYZ,C_ZYX,SQRT_X,SQRT_X_DAG\").z_outputs()\n    assert paulis == stim.PauliString(\"ZZZZXZZXYYY\")\n    np.testing.assert_array_equal(signs, [0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0])\n\n    c = all_cliffords_string_from_gate_data()\n    paulis, signs = c.z_outputs()\n    for k in range(len(c)):\n        expected = c[k].tableau.z_output(0)\n        assert (-1 if signs[k] else 1) == expected.sign\n        assert paulis[k] == expected[0]\n\n\ndef test_all_cliffords_string():\n    c = stim.CliffordString.all_cliffords_string()\n    assert len(c) == 24\n    assert set(e.name for e in all_cliffords_string_from_gate_data()) == set(e.name for e in c)\n"
  },
  {
    "path": "src/stim/stabilizers/flex_pauli_string.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/flex_pauli_string.h\"\n\nusing namespace stim;\n\nFlexPauliString::FlexPauliString(size_t num_qubits) : value(num_qubits), imag(false) {\n}\n\nFlexPauliString::FlexPauliString(const PauliStringRef<MAX_BITWORD_WIDTH> val, bool imag) : value(val), imag(imag) {\n}\n\nFlexPauliString::FlexPauliString(PauliString<MAX_BITWORD_WIDTH> &&val, bool imag) : value(std::move(val)), imag(imag) {\n}\n\nFlexPauliString FlexPauliString::operator+(const FlexPauliString &rhs) const {\n    FlexPauliString copy = *this;\n    copy += rhs;\n    return copy;\n}\n\nFlexPauliString &FlexPauliString::operator+=(const FlexPauliString &rhs) {\n    if (&rhs == this) {\n        *this *= 2;\n        return *this;\n    }\n\n    size_t n = value.num_qubits;\n    value.ensure_num_qubits(value.num_qubits + rhs.value.num_qubits, 1.1);\n    for (size_t k = 0; k < rhs.value.num_qubits; k++) {\n        value.xs[k + n] = rhs.value.xs[k];\n        value.zs[k + n] = rhs.value.zs[k];\n    }\n    *this *= rhs.get_phase();\n    return *this;\n}\n\nFlexPauliString FlexPauliString::operator*(std::complex<float> scale) const {\n    FlexPauliString copy = *this;\n    copy *= scale;\n    return copy;\n}\n\nFlexPauliString FlexPauliString::operator/(const std::complex<float> &scale) const {\n    FlexPauliString copy = *this;\n    copy /= scale;\n    return copy;\n}\n\nFlexPauliString FlexPauliString::operator*(size_t power) const {\n    FlexPauliString copy = *this;\n    copy *= power;\n    return copy;\n}\n\nFlexPauliString &FlexPauliString::operator*=(size_t power) {\n    switch (power & 3) {\n        case 0:\n            imag = false;\n            value.sign = false;\n            break;\n        case 1:\n            break;\n        case 2:\n            value.sign = imag;\n            imag = false;\n            break;\n        case 3:\n            value.sign ^= imag;\n            break;\n    }\n\n    value = PauliString<MAX_BITWORD_WIDTH>::from_func(value.sign, value.num_qubits * power, [&](size_t k) {\n        return \"_XZY\"[value.xs[k % value.num_qubits] + 2 * value.zs[k % value.num_qubits]];\n    });\n    return *this;\n}\n\nFlexPauliString &FlexPauliString::operator/=(const std::complex<float> &rhs) {\n    if (rhs == std::complex<float>{+1, 0}) {\n        return *this;\n    } else if (rhs == std::complex<float>{-1, 0}) {\n        return *this *= std::complex<float>{-1, 0};\n    } else if (rhs == std::complex<float>{0, 1}) {\n        return *this *= std::complex<float>{0, -1};\n    } else if (rhs == std::complex<float>{0, -1}) {\n        return *this *= std::complex<float>{0, +1};\n    }\n    throw std::invalid_argument(\"divisor not in (1, -1, 1j, -1j)\");\n}\n\nFlexPauliString &FlexPauliString::operator*=(std::complex<float> scale) {\n    if (scale == std::complex<float>(-1)) {\n        value.sign ^= true;\n    } else if (scale == std::complex<float>(0, 1)) {\n        value.sign ^= imag;\n        imag ^= true;\n    } else if (scale == std::complex<float>(0, -1)) {\n        imag ^= true;\n        value.sign ^= imag;\n    } else if (scale != std::complex<float>(1)) {\n        throw std::invalid_argument(\"phase factor not in [1, -1, 1, 1j]\");\n    }\n    return *this;\n}\n\nbool FlexPauliString::operator==(const FlexPauliString &other) const {\n    return value == other.value && imag == other.imag;\n}\n\nbool FlexPauliString::operator!=(const FlexPauliString &other) const {\n    return !(*this == other);\n}\n\nstd::complex<float> FlexPauliString::get_phase() const {\n    std::complex<float> result{value.sign ? -1.0f : +1.0f};\n    if (imag) {\n        result *= std::complex<float>{0, 1};\n    }\n    return result;\n}\n\nFlexPauliString FlexPauliString::operator*(const FlexPauliString &rhs) const {\n    FlexPauliString copy = *this;\n    copy *= rhs;\n    return copy;\n}\n\nFlexPauliString &FlexPauliString::operator*=(const FlexPauliString &rhs) {\n    value.ensure_num_qubits(rhs.value.num_qubits, 1.1);\n    if (rhs.value.num_qubits < value.num_qubits) {\n        FlexPauliString copy = rhs;\n        copy.value.ensure_num_qubits(value.num_qubits, 1.0);\n        *this *= copy;\n        return *this;\n    }\n\n    uint8_t log_i = value.ref().inplace_right_mul_returning_log_i_scalar(rhs.value.ref());\n    if (log_i & 2) {\n        value.sign ^= true;\n    }\n    if (log_i & 1) {\n        *this *= std::complex<float>{0, 1};\n    }\n    if (rhs.imag) {\n        *this *= std::complex<float>{0, 1};\n    }\n    return *this;\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const FlexPauliString &v) {\n    out << \"+-\"[v.value.sign];\n    if (v.imag) {\n        out << 'i';\n    }\n    for (size_t k = 0; k < v.value.num_qubits; k++) {\n        out << \"_XZY\"[v.value.xs[k] + 2 * v.value.zs[k]];\n    }\n    return out;\n}\n\nstd::string FlexPauliString::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\nstatic size_t parse_size_of_pauli_string_shorthand_if_sparse(std::string_view text) {\n    uint64_t cur_index = 0;\n    bool has_cur_index = false;\n    size_t num_qubits = 0;\n\n    auto flush = [&]() {\n        if (has_cur_index) {\n            num_qubits = std::max(num_qubits, (size_t)cur_index + 1);\n            if (cur_index == UINT64_MAX || num_qubits <= cur_index) {\n                throw std::invalid_argument(\"\");\n            }\n            cur_index = 0;\n            has_cur_index = false;\n        }\n    };\n\n    for (char c : text) {\n        switch (c) {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                has_cur_index = true;\n                cur_index = mul_saturate(cur_index, 10);\n                cur_index = add_saturate(cur_index, c - '0');\n                break;\n            default:\n                flush();\n                break;\n        }\n    }\n    flush();\n    return num_qubits;\n}\n\nstatic void parse_sparse_pauli_string(std::string_view text, FlexPauliString *out) {\n    uint64_t cur_index = 0;\n    bool has_cur_index = false;\n    char cur_pauli = '\\0';\n\n    auto flush = [&]() {\n        if (cur_pauli == '\\0' || !has_cur_index || cur_index > out->value.num_qubits) {\n            throw std::invalid_argument(\"\");\n        }\n        if (cur_pauli != 'I') {\n            out->value.right_mul_pauli(\n                GateTarget::pauli_xz(\n                    cur_index, cur_pauli == 'X' || cur_pauli == 'Y', cur_pauli == 'Z' || cur_pauli == 'Y'),\n                &out->imag);\n        }\n        has_cur_index = false;\n        cur_pauli = '\\0';\n        cur_index = 0;\n    };\n\n    for (char c : text) {\n        switch (c) {\n            case '*':\n                flush();\n                break;\n            case 'I':\n            case 'x':\n            case 'X':\n            case 'y':\n            case 'Y':\n            case 'z':\n            case 'Z':\n                if (cur_pauli != '\\0') {\n                    throw std::invalid_argument(\"\");\n                }\n                cur_pauli = toupper(c);\n                break;\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                if (cur_pauli == '\\0') {\n                    throw std::invalid_argument(\"\");\n                }\n                has_cur_index = true;\n                cur_index = mul_saturate(cur_index, 10);\n                cur_index = add_saturate(cur_index, c - '0');\n                break;\n            default:\n                throw std::invalid_argument(\"\");\n        }\n    }\n    flush();\n}\n\nFlexPauliString FlexPauliString::from_text(std::string_view text) {\n    bool negated = false;\n    bool imaginary = false;\n    if (text.starts_with(\"-\")) {\n        negated = true;\n        text = text.substr(1);\n    } else if (text.starts_with(\"+\")) {\n        text = text.substr(1);\n    }\n    if (text.starts_with(\"i\")) {\n        imaginary = true;\n        text = text.substr(1);\n    }\n\n    size_t sparse_size = parse_size_of_pauli_string_shorthand_if_sparse(text);\n    size_t num_qubits = sparse_size > 0 ? sparse_size : text.size();\n    FlexPauliString result(num_qubits);\n    result.imag = imaginary;\n    result.value.sign = negated;\n    if (sparse_size > 0) {\n        try {\n            parse_sparse_pauli_string(text, &result);\n        } catch (const std::invalid_argument &) {\n            throw std::invalid_argument(\"Not a valid Pauli string shorthand: '\" + std::string(text) + \"'\");\n        }\n    } else {\n        for (size_t k = 0; k < text.size(); k++) {\n            switch (text[k]) {\n                case 'I':\n                case '_':\n                    break;\n                case 'x':\n                case 'X':\n                    result.value.xs[k] = true;\n                    break;\n                case 'y':\n                case 'Y':\n                    result.value.xs[k] = true;\n                    result.value.zs[k] = true;\n                    break;\n                case 'z':\n                case 'Z':\n                    result.value.zs[k] = true;\n                    break;\n                default:\n                    throw std::invalid_argument(\"Not a valid Pauli string shorthand: '\" + std::string(text) + \"'\");\n            }\n        }\n    }\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/stabilizers/flex_pauli_string.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_STABILIZERS_FLEX_PAULI_STRING_H\n#define _STIM_STABILIZERS_FLEX_PAULI_STRING_H\n\n#include <complex>\n\n#include \"stim/mem/sparse_xor_vec.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nnamespace stim {\n\n/// This is the backing class for the python stim.PauliString.\n/// It's more flexible than the C++ stim::PauliString.\n/// For example, it allows imaginary signs.\nstruct FlexPauliString {\n    stim::PauliString<stim::MAX_BITWORD_WIDTH> value;\n    bool imag;\n\n    FlexPauliString(size_t num_qubits);\n    FlexPauliString(const stim::PauliStringRef<stim::MAX_BITWORD_WIDTH> val, bool imag = false);\n    FlexPauliString(stim::PauliString<stim::MAX_BITWORD_WIDTH> &&val, bool imag = false);\n\n    static FlexPauliString from_text(std::string_view text);\n    std::complex<float> get_phase() const;\n\n    FlexPauliString operator+(const FlexPauliString &rhs) const;\n    FlexPauliString &operator+=(const FlexPauliString &rhs);\n\n    FlexPauliString operator*(size_t power) const;\n    FlexPauliString operator*(std::complex<float> scale) const;\n    FlexPauliString operator*(const FlexPauliString &rhs) const;\n    FlexPauliString operator/(const std::complex<float> &divisor) const;\n\n    FlexPauliString &operator*=(size_t power);\n    FlexPauliString &operator*=(std::complex<float> scale);\n    FlexPauliString &operator*=(const FlexPauliString &rhs);\n    FlexPauliString &operator/=(const std::complex<float> &divisor);\n\n    bool operator==(const FlexPauliString &other) const;\n    bool operator!=(const FlexPauliString &other) const;\n    std::string str() const;\n};\nstd::ostream &operator<<(std::ostream &out, const FlexPauliString &v);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/flex_pauli_string.test.cc",
    "content": "#include \"stim/stabilizers/flex_pauli_string.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(flex_pauli_string, mul) {\n    FlexPauliString p1 = FlexPauliString::from_text(\"iXYZ\");\n    FlexPauliString p2 = FlexPauliString::from_text(\"i__Z\");\n    ASSERT_EQ(p1 * p2, FlexPauliString::from_text(\"-XY_\"));\n}\n\nTEST(flex_pauli_string, from_text) {\n    auto f = FlexPauliString::from_text(\"-iIXYZ_xyz\");\n    ASSERT_EQ(f.value.num_qubits, 8);\n    ASSERT_EQ(f.imag, true);\n    ASSERT_EQ(f.value.sign, true);\n    ASSERT_EQ(f.value.xs.as_u64(), 0b01100110);\n    ASSERT_EQ(f.value.zs.as_u64(), 0b11001100);\n\n    f = FlexPauliString::from_text(\"iX\");\n    ASSERT_EQ(f.value.num_qubits, 1);\n    ASSERT_EQ(f.imag, true);\n    ASSERT_EQ(f.value.sign, false);\n    ASSERT_EQ(f.value.xs.as_u64(), 0b1);\n    ASSERT_EQ(f.value.zs.as_u64(), 0b0);\n\n    f = FlexPauliString::from_text(\"Y\");\n    ASSERT_EQ(f.value.num_qubits, 1);\n    ASSERT_EQ(f.imag, false);\n    ASSERT_EQ(f.value.sign, false);\n    ASSERT_EQ(f.value.xs.as_u64(), 0b1);\n    ASSERT_EQ(f.value.zs.as_u64(), 0b1);\n\n    f = FlexPauliString::from_text(\"+Z\");\n    ASSERT_EQ(f.value.num_qubits, 1);\n    ASSERT_EQ(f.imag, false);\n    ASSERT_EQ(f.value.sign, false);\n    ASSERT_EQ(f.value.xs.as_u64(), 0b0);\n    ASSERT_EQ(f.value.zs.as_u64(), 0b1);\n\n    f = FlexPauliString::from_text(\"X8\");\n    ASSERT_EQ(f.value.num_qubits, 9);\n    ASSERT_EQ(f.imag, false);\n    ASSERT_EQ(f.value.sign, false);\n    ASSERT_EQ(f.value.xs.as_u64(), 0b100000000);\n    ASSERT_EQ(f.value.zs.as_u64(), 0b000000000);\n\n    f = FlexPauliString::from_text(\"X8*Y2\");\n    ASSERT_EQ(f.value.num_qubits, 9);\n    ASSERT_EQ(f.imag, false);\n    ASSERT_EQ(f.value.sign, false);\n    ASSERT_EQ(f.value.xs.as_u64(), 0b100000100);\n    ASSERT_EQ(f.value.zs.as_u64(), 0b000000100);\n\n    f = FlexPauliString::from_text(\"X8*Y2*X8\");\n    ASSERT_EQ(f.value.num_qubits, 9);\n    ASSERT_EQ(f.imag, false);\n    ASSERT_EQ(f.value.sign, false);\n    ASSERT_EQ(f.value.xs.as_u64(), 0b000000100);\n    ASSERT_EQ(f.value.zs.as_u64(), 0b000000100);\n\n    f = FlexPauliString::from_text(\"X8*Y2*Y8\");\n    ASSERT_EQ(f.value.num_qubits, 9);\n    ASSERT_EQ(f.imag, true);\n    ASSERT_EQ(f.value.sign, false);\n    ASSERT_EQ(f.value.xs.as_u64(), 0b000000100);\n    ASSERT_EQ(f.value.zs.as_u64(), 0b100000100);\n\n    f = FlexPauliString::from_text(\"Y8*Y2*X8\");\n    ASSERT_EQ(f.value.num_qubits, 9);\n    ASSERT_EQ(f.imag, true);\n    ASSERT_EQ(f.value.sign, true);\n    ASSERT_EQ(f.value.xs.as_u64(), 0b000000100);\n    ASSERT_EQ(f.value.zs.as_u64(), 0b100000100);\n\n    ASSERT_EQ(FlexPauliString::from_text(\"X1\"), FlexPauliString::from_text(\"_X\"));\n\n    ASSERT_EQ(FlexPauliString::from_text(\"X20*I21\"), FlexPauliString::from_text(\"____________________X_\"));\n}\n"
  },
  {
    "path": "src/stim/stabilizers/flow.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_STABILIZERS_FLOW_H\n#define _STIM_STABILIZERS_FLOW_H\n\n#include \"stim/stabilizers/pauli_string.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nstruct Flow {\n    /// The stabilizer at the beginning of the circuit.\n    stim::PauliString<W> input;\n    /// The equivalent stabilizer at the end the circuit.\n    stim::PauliString<W> output;\n    /// The measurements mediating the equivalence.\n    /// Indexing follows python convention: -1 is the last element, 0 is the first element.\n    /// ENTRIES MUST BE SORTED AND UNIQUE.\n    std::vector<int32_t> measurements;\n    /// Indices of observables included in the flow.\n    /// Determines which OBSERVABLE_INCLUDE instructions are included.\n    /// ENTRIES MUST BE SORTED AND UNIQUE.\n    std::vector<uint32_t> observables;\n\n    /// Fixes non-unique non-sorted measurements and observables.\n    void canonicalize();\n\n    static Flow<W> from_str(std::string_view text);\n    Flow<W> operator*(const Flow<W> &rhs) const;\n    bool operator<(const Flow<W> &other) const;\n    bool operator==(const Flow<W> &other) const;\n    bool operator!=(const Flow<W> &other) const;\n    std::string str() const;\n};\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const Flow<W> &flow);\n\n}  // namespace stim\n\n#include \"stim/stabilizers/flow.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/flow.inl",
    "content": "#include \"stim/circuit/circuit.h\"\n#include \"stim/stabilizers/flex_pauli_string.h\"\n#include \"stim/stabilizers/flow.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\ninline bool parse_obs_index(std::string_view obs, uint32_t *out) {\n    if (obs.size() < 6 || obs[0] != 'o' || obs[1] != 'b' || obs[2] != 's' || obs[3] != '[' || obs.back() != ']') {\n        throw std::invalid_argument(\"\");  // Caught and given a message by caller.\n    }\n    int64_t i = 0;\n    if (!parse_int64(obs.substr(4, obs.size() - 5), &i)) {\n        return false;\n    }\n\n    if (i >= 0 && i <= UINT32_MAX) {\n        *out = (uint32_t)i;\n        return true;\n    }\n    return false;\n}\n\ninline bool parse_rec_allowing_non_negative(std::string_view rec, int32_t *out) {\n    if (rec.size() < 6 || rec[0] != 'r' || rec[1] != 'e' || rec[2] != 'c' || rec[3] != '[' || rec.back() != ']') {\n        throw std::invalid_argument(\"\");  // Caught and given a message by caller.\n    }\n    int64_t i = 0;\n    if (!parse_int64(rec.substr(4, rec.size() - 5), &i)) {\n        return false;\n    }\n\n    if (i >= INT32_MIN && i <= INT32_MAX) {\n        *out = (int32_t)i;\n        return true;\n    }\n    return false;\n}\n\ntemplate <size_t W>\nPauliString<W> parse_non_empty_pauli_string_allowing_i(std::string_view text, bool *imag_out) {\n    *imag_out = false;\n    if (text == \"+1\" || text == \"1\") {\n        return PauliString<W>(0);\n    }\n    if (text == \"-1\") {\n        PauliString<W> r(0);\n        r.sign = true;\n        return r;\n    }\n    if (text.empty()) {\n        throw std::invalid_argument(\"Got an ambiguously blank pauli string. Use '1' for the empty Pauli string.\");\n    }\n\n    auto flex = FlexPauliString::from_text(text);\n    *imag_out = flex.imag;\n\n    PauliString<W> result(flex.value.num_qubits);\n    size_t nb = std::min(flex.value.xs.num_u8_padded(), result.xs.num_u8_padded());\n    memcpy(result.xs.u8, flex.value.xs.u8, nb);\n    memcpy(result.zs.u8, flex.value.zs.u8, nb);\n    result.sign = flex.value.sign;\n    return result;\n}\n\ntemplate <size_t W>\nFlow<W> Flow<W>::from_str(std::string_view text) {\n    try {\n        auto parts = split_view('>', text);\n        if (parts.size() != 2 || parts[0].empty() || parts[0].back() != '-') {\n            throw std::invalid_argument(\"\");  // Caught and given a message below.\n        }\n        parts[0] = parts[0].substr(0, parts[0].size() - 1);\n        while (!parts[0].empty() && parts[0].back() == ' ') {\n            parts[0] = parts[0].substr(0, parts[0].size() - 1);\n        }\n        bool imag_inp = false;\n        bool imag_out = false;\n        PauliString<W> inp = parse_non_empty_pauli_string_allowing_i<W>(parts[0], &imag_inp);\n\n        parts = split_view(' ', parts[1]);\n        size_t k = 0;\n        while (k < parts.size() && parts[k].empty()) {\n            k += 1;\n        }\n        if (k >= parts.size()) {\n            throw std::invalid_argument(\"\");  // Caught and given a message below.\n        }\n        PauliString<W> out(0);\n        std::vector<int32_t> measurements;\n        std::vector<uint32_t> observables;\n        bool flip_out = false;\n        if (parts[k].starts_with('-')) {\n            flip_out = true;\n            parts[k] = parts[k].substr(1);\n        }\n        if (!parts[k].empty() && parts[k][0] != 'r' && parts[k][0] != 'o') {\n            out = parse_non_empty_pauli_string_allowing_i<W>(parts[k], &imag_out);\n        } else if (parts[k][0] == 'r') {\n            int32_t rec;\n            if (!parse_rec_allowing_non_negative(parts[k], &rec)) {\n                throw std::invalid_argument(\"\");  // Caught and given a message below.\n            }\n            measurements.push_back(rec);\n        } else if (parts[k][0] == 'o') {\n            uint32_t rec;\n            if (!parse_obs_index(parts[k], &rec)) {\n                throw std::invalid_argument(\"\");  // Caught and given a message below.\n            }\n            observables.push_back(rec);\n        } else {\n            throw std::invalid_argument(\"Parsing reached an expected-to-be-impossible state. \"\n                                        \"Failed to understand a Pauli term.\");\n        }\n        out.sign ^= flip_out;\n        k++;\n        while (k < parts.size()) {\n            if (parts[k] != \"xor\" || k + 1 == parts.size()) {\n                throw std::invalid_argument(\"\");  // Caught and given a message below.\n            }\n            if (parts[k + 1].starts_with(\"r\")) {\n                int32_t rec;\n                if (!parse_rec_allowing_non_negative(parts[k + 1], &rec)) {\n                    throw std::invalid_argument(\"\");  // Caught and given a message below.\n                }\n                measurements.push_back(rec);\n            } else if (parts[k + 1].starts_with(\"o\")) {\n                uint32_t obs;\n                if (!parse_obs_index(parts[k + 1], &obs)) {\n                    throw std::invalid_argument(\"\");  // Caught and given a message below.\n                }\n                observables.push_back(obs);\n            } else {\n                throw std::invalid_argument(\"\");  // Caught and given a message below.\n            }\n            k += 2;\n        }\n        if (imag_inp != imag_out) {\n            throw std::invalid_argument(\"Anti-Hermitian flows aren't allowed.\");\n        }\n        size_t measurements_kept = inplace_xor_sort(SpanRef<int32_t>(measurements)).size();\n        size_t obs_kept = inplace_xor_sort(SpanRef<uint32_t>(observables)).size();\n        measurements.resize(measurements_kept);\n        observables.resize(obs_kept);\n        return Flow{inp, out, measurements, observables};\n    } catch (const std::invalid_argument &ex) {\n        if (*ex.what() != '\\0') {\n            throw;\n        }\n        throw std::invalid_argument(\"Invalid stabilizer flow text: '\" + std::string(text) + \"'.\");\n    }\n}\n\ntemplate <size_t W>\nbool Flow<W>::operator==(const Flow<W> &other) const {\n    return input == other.input && output == other.output && measurements == other.measurements && observables == other.observables;\n}\n\ntemplate <size_t W>\nbool Flow<W>::operator<(const Flow<W> &other) const {\n    if (input != other.input) {\n        return input < other.input;\n    }\n    if (output != other.output) {\n        return output < other.output;\n    }\n    if (measurements != other.measurements) {\n        return SpanRef<const int32_t>(measurements) < SpanRef<const int32_t>(other.measurements);\n    }\n    if (observables != other.observables) {\n        return SpanRef<const uint32_t>(observables) < SpanRef<const uint32_t>(other.observables);\n    }\n    return false;\n}\n\ntemplate <size_t W>\nbool Flow<W>::operator!=(const Flow<W> &other) const {\n    return !(*this == other);\n}\n\ntemplate <size_t W>\nstd::string Flow<W>::str() const {\n    std::stringstream result;\n    result << *this;\n    return result.str();\n}\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const Flow<W> &flow) {\n    bool use_sparse = false;\n\n    // Sparse is only useful if most terms are identity.\n    if (flow.input.num_qubits > 8 && flow.input.ref().weight() * 8 <= flow.input.num_qubits) {\n        use_sparse = true;\n    }\n    if (flow.output.num_qubits > 8 && flow.output.ref().weight() * 8 <= flow.output.num_qubits) {\n        use_sparse = true;\n    }\n\n    // Sparse would lose length data if the last pauli is an identity.\n    if (flow.input.num_qubits > 0 && !flow.input.xs[flow.input.num_qubits - 1] &&\n        !flow.input.zs[flow.input.num_qubits - 1]) {\n        use_sparse = false;\n    }\n    if (flow.output.num_qubits > 0 && !flow.output.xs[flow.output.num_qubits - 1] &&\n        !flow.output.zs[flow.output.num_qubits - 1]) {\n        use_sparse = false;\n    }\n\n    auto write_sparse = [&](const PauliString<W> &ps) -> bool {\n        if (ps.sign) {\n            out << \"-\";\n        }\n        bool has_any = false;\n        if (use_sparse) {\n            ps.ref().for_each_active_pauli([&](size_t q) {\n                uint8_t p = ps.xs[q] + 2 * ps.zs[q];\n                if (has_any) {\n                    out << \"*\";\n                }\n                out << \"_XZY\"[p];\n                out << q;\n                has_any = true;\n            });\n        } else {\n            for (size_t q = 0; q < ps.num_qubits; q++) {\n                uint8_t p = ps.xs[q] + 2 * ps.zs[q];\n                out << \"_XZY\"[p];\n                has_any = true;\n            }\n        }\n        return has_any;\n    };\n\n    if (!write_sparse(flow.input)) {\n        out << \"1\";\n    }\n    out << \" -> \";\n    bool has_out = write_sparse(flow.output);\n    for (const auto &t : flow.measurements) {\n        if (has_out) {\n            out << \" xor \";\n        }\n        has_out = true;\n        out << \"rec[\" << t << \"]\";\n    }\n    for (const auto &t : flow.observables) {\n        if (has_out) {\n            out << \" xor \";\n        }\n        has_out = true;\n        out << \"obs[\" << t << \"]\";\n    }\n    if (!has_out) {\n        out << \"1\";\n    }\n    return out;\n}\n\ntemplate <size_t W>\nvoid Flow<W>::canonicalize() {\n    size_t measurements_kept = inplace_xor_sort(SpanRef<int32_t>(measurements)).size();\n    size_t observables_kept = inplace_xor_sort(SpanRef<uint32_t>(observables)).size();\n    measurements.resize(measurements_kept);\n    observables.resize(observables_kept);\n}\n\ntemplate <size_t W>\nFlow<W> Flow<W>::operator*(const Flow<W> &rhs) const {\n    Flow<W> result = *this;\n\n    result.input.ensure_num_qubits(rhs.input.num_qubits, 1.1);\n    result.output.ensure_num_qubits(rhs.output.num_qubits, 1.1);\n    uint8_t log_i = 0;\n    log_i -= result.input.ref().inplace_right_mul_returning_log_i_scalar(rhs.input.ref());\n    log_i += result.output.ref().inplace_right_mul_returning_log_i_scalar(rhs.output.ref());\n    if (log_i & 1) {\n        throw std::invalid_argument(str() + \" anticommutes with \" + rhs.str());\n    }\n    if (log_i & 2) {\n        result.output.sign ^= true;\n    }\n\n    result.measurements.insert(result.measurements.end(), rhs.measurements.begin(), rhs.measurements.end());\n    result.observables.insert(result.observables.end(), rhs.observables.begin(), rhs.observables.end());\n    result.canonicalize();\n    return result;\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/stabilizers/flow.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/flow.h\"\n\n#include \"stim/py/base.pybind.h\"\n#include \"stim/stabilizers/flow.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\npybind11::class_<Flow<MAX_BITWORD_WIDTH>> stim_pybind::pybind_flow(pybind11::module &m) {\n    return pybind11::class_<Flow<MAX_BITWORD_WIDTH>>(\n        m,\n        \"Flow\",\n        clean_doc_string(R\"DOC(\n            A stabilizer flow (e.g. \"XI -> XX xor rec[-1]\").\n\n            Stabilizer circuits implement, and can be defined by, how they turn input\n            stabilizers into output stabilizers mediated by measurements. These\n            relationships are called stabilizer flows, and `stim.Flow` is a representation\n            of such a flow. For example, a `stim.Flow` can be given to\n            `stim.Circuit.has_flow` to verify that a circuit implements the flow.\n\n            A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer\n            P at the start of the circuit to the instantaneous stabilizer Q at the end of\n            the circuit. The flow may be mediated by certain measurements. For example,\n            a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and\n            the CNOT flows implemented by the circuit involve these measurements.\n\n            A flow like P -> Q means the circuit transforms P into Q.\n            A flow like 1 -> P means the circuit prepares P.\n            A flow like P -> 1 means the circuit measures P.\n            A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR).\n\n            References:\n                Stim's gate documentation includes the stabilizer flows of each gate.\n\n                Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are\n                defined and provides a circuit construction for experimentally verifying\n                their presence.\n\n            Examples:\n                >>> import stim\n                >>> c = stim.Circuit(\"CNOT 2 4\")\n\n                >>> c.has_flow(stim.Flow(\"__X__ -> __X_X\"))\n                True\n\n                >>> c.has_flow(stim.Flow(\"X2*X4 -> X2\"))\n                True\n\n                >>> c.has_flow(stim.Flow(\"Z4 -> Z4\"))\n                False\n        )DOC\")\n            .data());\n}\n\nstatic Flow<MAX_BITWORD_WIDTH> py_init_flow(\n    const pybind11::object &arg,\n    const pybind11::object &input,\n    const pybind11::object &output,\n    const pybind11::object &measurements,\n    const pybind11::object &included_observables) {\n    if (arg.is_none()) {\n        Flow<MAX_BITWORD_WIDTH> result{PauliString<MAX_BITWORD_WIDTH>(0), PauliString<MAX_BITWORD_WIDTH>(0)};\n        bool imag = false;\n        if (!input.is_none()) {\n            auto f = pybind11::cast<FlexPauliString>(input);\n            imag ^= f.imag;\n            result.input = std::move(f.value);\n        }\n        if (!output.is_none()) {\n            auto f = pybind11::cast<FlexPauliString>(output);\n            imag ^= f.imag;\n            result.output = std::move(f.value);\n        }\n        if (imag) {\n            throw std::invalid_argument(\"Anti-Hermitian flows aren't allowed.\");\n        }\n        if (!measurements.is_none()) {\n            for (const auto &h : measurements) {\n                if (pybind11::isinstance<GateTarget>(h)) {\n                    GateTarget g = pybind11::cast<GateTarget>(h);\n                    if (!g.is_measurement_record_target()) {\n                        throw std::invalid_argument(\"Not a measurement offset: \" + g.str());\n                    }\n                    result.measurements.push_back(g.rec_offset());\n                } else {\n                    result.measurements.push_back(pybind11::cast<int32_t>(h));\n                }\n            }\n        }\n        if (!included_observables.is_none()) {\n            for (const auto &h : included_observables) {\n                result.observables.push_back(pybind11::cast<uint32_t>(h));\n            }\n        }\n        result.canonicalize();\n        return result;\n    }\n\n    if (!input.is_none()) {\n        throw std::invalid_argument(\"Can't specify both a positional argument and `input=`.\");\n    }\n    if (!output.is_none()) {\n        throw std::invalid_argument(\"Can't specify both a positional argument and `output=`.\");\n    }\n    if (!measurements.is_none()) {\n        throw std::invalid_argument(\"Can't specify both a positional argument and `measurements=`.\");\n    }\n    if (!included_observables.is_none()) {\n        throw std::invalid_argument(\"Can't specify both a positional argument and `included_observables=`.\");\n    }\n\n    if (pybind11::isinstance<Flow<MAX_BITWORD_WIDTH>>(arg)) {\n        return pybind11::cast<Flow<MAX_BITWORD_WIDTH>>(arg);\n    } else if (pybind11::isinstance<pybind11::str>(arg)) {\n        return Flow<MAX_BITWORD_WIDTH>::from_str(pybind11::cast<std::string_view>(arg));\n    }\n\n    std::stringstream ss;\n    ss << \"Don't know how to turn '\" << arg << \" into a flow.\";\n    throw std::invalid_argument(ss.str());\n}\n\nvoid stim_pybind::pybind_flow_methods(pybind11::module &m, pybind11::class_<Flow<MAX_BITWORD_WIDTH>> &c) {\n    c.def(\n        pybind11::init(&py_init_flow),\n        pybind11::arg(\"arg\") = pybind11::none(),\n        pybind11::pos_only(),\n        pybind11::kw_only(),\n        pybind11::arg(\"input\") = pybind11::none(),\n        pybind11::arg(\"output\") = pybind11::none(),\n        pybind11::arg(\"measurements\") = pybind11::none(),\n        pybind11::arg(\"included_observables\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def __init__(self, arg: Union[None, str, stim.Flow] = None, /, *, input: Optional[stim.PauliString] = None, output: Optional[stim.PauliString] = None, measurements: Optional[Iterable[Union[int, GateTarget]]] = None, included_observables: Optional[Iterable[int]] = None) -> None:\n            Initializes a stim.Flow.\n\n            When given a string, the string is parsed as flow shorthand. For example,\n            the string \"X_ -> ZZ xor rec[-1]\" will result in a flow with input pauli string\n            \"X_\", output pauli string \"ZZ\", and measurement indices [-1].\n\n            Args:\n                arg [position-only]: Defaults to None. Must be specified by itself if used.\n                    str: Initializes a flow by parsing the given shorthand text.\n                    stim.Flow: Initializes a copy of the given flow.\n                    None (default): Initializes an empty flow.\n                input: Defaults to None. Can be set to a stim.PauliString to directly\n                    specify the flow's input stabilizer.\n                output: Defaults to None. Can be set to a stim.PauliString to directly\n                    specify the flow's output stabilizer.\n                measurements: Defaults to None. Can be set to a list of integers or gate\n                    targets like `stim.target_rec(-1)`, to specify the measurements that\n                    mediate the flow. Negative and positive measurement indices are allowed.\n                    Indexes follow the python convention where -1 is the last measurement in\n                    a circuit and 0 is the first measurement in a circuit.\n                included_observables: Defaults to None. `OBSERVABLE_INCLUDE` instructions\n                    that target an observable index from this list will be implicitly\n                    included in the flow. This allows flows to refer to observables. For\n                    example, the flow \"X5 -> obs[3]\" says \"At the start of the circuit,\n                    observable 3 should be an X term on qubit 5. By the end of the circuit\n                    it will be measured. The `OBSERVABLE_INCLUDE(3)` instructions in the\n                    circuit should explain how this happened.\".\n\n            Examples:\n                >>> import stim\n\n                >>> stim.Flow(\"X2 -> -Y2*Z4 xor rec[-1]\")\n                stim.Flow(\"__X -> -__Y_Z xor rec[-1]\")\n\n                >>> stim.Flow(\"Z -> 1 xor rec[-1]\")\n                stim.Flow(\"Z -> rec[-1]\")\n\n                >>> stim.Flow(\n                ...     input=stim.PauliString(\"XX\"),\n                ...     output=stim.PauliString(\"_X\"),\n                ...     measurements=[],\n                ... )\n                stim.Flow(\"XX -> _X\")\n\n                >>> # Identical terms cancel.\n                >>> stim.Flow(\"X2 -> Y2*Y2 xor rec[-2] xor rec[-2]\")\n                stim.Flow(\"__X -> ___\")\n\n                >>> stim.Flow(\"X -> Y xor obs[3] xor obs[3] xor obs[3]\")\n                stim.Flow(\"X -> Y xor obs[3]\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"input_copy\",\n        [](const Flow<MAX_BITWORD_WIDTH> &self) -> FlexPauliString {\n            return FlexPauliString{self.input, false};\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the flow's input stabilizer.\n\n            Examples:\n                >>> import stim\n                >>> f = stim.Flow(input=stim.PauliString('XX'))\n                >>> f.input_copy()\n                stim.PauliString(\"+XX\")\n\n                >>> f.input_copy() is f.input_copy()\n                False\n        )DOC\")\n            .data());\n\n    c.def(\n        \"output_copy\",\n        [](const Flow<MAX_BITWORD_WIDTH> &self) -> FlexPauliString {\n            return FlexPauliString{self.output, false};\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the flow's output stabilizer.\n\n            Examples:\n                >>> import stim\n                >>> f = stim.Flow(output=stim.PauliString('XX'))\n                >>> f.output_copy()\n                stim.PauliString(\"+XX\")\n\n                >>> f.output_copy() is f.output_copy()\n                False\n        )DOC\")\n            .data());\n\n    c.def(\n        \"measurements_copy\",\n        [](const Flow<MAX_BITWORD_WIDTH> &self) -> std::vector<int32_t> {\n            return self.measurements;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the flow's measurement indices.\n\n            Examples:\n                >>> import stim\n                >>> f = stim.Flow(measurements=[-1, 2])\n                >>> f.measurements_copy()\n                [-1, 2]\n\n                >>> f.measurements_copy() is f.measurements_copy()\n                False\n        )DOC\")\n            .data());\n\n    c.def(\n        \"included_observables_copy\",\n        [](const Flow<MAX_BITWORD_WIDTH> &self) -> std::vector<uint32_t> {\n            return self.observables;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the flow's included observable indices.\n\n            When an observable is included in a flow, the flow implicitly includes all\n            measurements and pauli terms from `OBSERVABLE_INCLUDE` instructions targeting\n            that observable index.\n\n            Examples:\n                >>> import stim\n                >>> f = stim.Flow(included_observables=[3, 2])\n                >>> f.included_observables_copy()\n                [2, 3]\n\n                >>> f.included_observables_copy() is f.included_observables_copy()\n                False\n\n                >>> f = stim.Flow(\"X2 -> obs[3]\")\n                >>> f.included_observables_copy()\n                [3]\n                >>> stim.Circuit(\"OBSERVABLE_INCLUDE(3) X2\").has_flow(f)\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__mul__\",\n        &Flow<MAX_BITWORD_WIDTH>::operator*,\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Computes the product of two flows.\n\n            Args:\n                rhs: The right hand side of the multiplication.\n\n            Returns:\n                The product of the two flows.\n\n            Raises:\n                ValueError: The inputs anti-commute (their product would be anti-Hermitian).\n                    For example, 1 -> X times 1 -> Y fails because it would give 1 -> iZ.\n\n            Examples:\n                >>> import stim\n                >>> stim.Flow(\"X -> X\") * stim.Flow(\"Z -> Z\")\n                stim.Flow(\"Y -> Y\")\n\n                >>> stim.Flow(\"1 -> XX\") * stim.Flow(\"1 -> ZZ\")\n                stim.Flow(\"1 -> -YY\")\n\n                >>> stim.Flow(\"X -> rec[-1]\") * stim.Flow(\"X -> rec[-2]\")\n                stim.Flow(\"_ -> rec[-2] xor rec[-1]\")\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two flows have identical contents.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two flows have non-identical contents.\");\n    c.def(\"__str__\", &Flow<MAX_BITWORD_WIDTH>::str, \"Returns a shorthand description of the flow.\");\n\n    c.def(\n        \"__repr__\",\n        [](const Flow<MAX_BITWORD_WIDTH> &self) {\n            return \"stim.Flow(\\\"\" + self.str() + \"\\\")\";\n        },\n        \"Returns valid python code evaluating to an equivalent `stim.Flow`.\");\n}\n"
  },
  {
    "path": "src/stim/stabilizers/flow.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_STABILIZERS_FLOW_PYBIND_H\n#define _STIM_STABILIZERS_FLOW_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/stabilizers/flow.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::Flow<stim::MAX_BITWORD_WIDTH>> pybind_flow(pybind11::module &m);\nvoid pybind_flow_methods(pybind11::module &m, pybind11::class_<stim::Flow<stim::MAX_BITWORD_WIDTH>> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/flow.test.cc",
    "content": "#include \"stim/stabilizers/flow.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/mem/simd_word.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, from_str_dedupe, {\n    EXPECT_EQ(\n        Flow<W>::from_str(\n            \"X -> Y xor rec[-1] xor rec[-1] xor rec[-1] xor rec[-2] xor rec[-2] xor rec[-3] xor obs[1] xor obs[1] xor \"\n            \"obs[3] xor obs[3] xor obs[3]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"X\"),\n            .output = PauliString<W>::from_str(\"Y\"),\n            .measurements = {-3, -1},\n            .observables = {3},\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, from_str, {\n    ASSERT_THROW({ Flow<W>::from_str(\"\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X>X\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X-X\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X > X\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X - X\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"->X\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X->\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"rec[0] -> X\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X -> rec[ -1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X -> X rec[-1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X -> X xor\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X -> rec[-1] xor X\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X -> obs[-1]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X -> obs[A]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X -> obs[]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X -> obs[ 5]\"); }, std::invalid_argument);\n    ASSERT_THROW({ Flow<W>::from_str(\"X -> rec[]\"); }, std::invalid_argument);\n\n    ASSERT_EQ(\n        Flow<W>::from_str(\"1 -> 1\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"\"),\n            .output = PauliString<W>::from_str(\"\"),\n            .measurements = {},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"1 -> -rec[0]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"\"),\n            .output = PauliString<W>::from_str(\"-\"),\n            .measurements = {0},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"i -> -i\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"\"),\n            .output = PauliString<W>::from_str(\"-\"),\n            .measurements = {},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"iX -> -iY\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"X\"),\n            .output = PauliString<W>::from_str(\"-Y\"),\n            .measurements = {},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"X->-Y\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"X\"),\n            .output = PauliString<W>::from_str(\"-Y\"),\n            .measurements = {},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"X -> -Y\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"X\"),\n            .output = PauliString<W>::from_str(\"-Y\"),\n            .measurements = {},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"-X -> Y\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"-X\"),\n            .output = PauliString<W>::from_str(\"Y\"),\n            .measurements = {},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"XYZ -> -Z_Z\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"XYZ\"),\n            .output = PauliString<W>::from_str(\"-Z_Z\"),\n            .measurements = {},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"XYZ -> Z_Y xor rec[-1]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"XYZ\"),\n            .output = PauliString<W>::from_str(\"Z_Y\"),\n            .measurements = {-1},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"XYZ -> Z_Y xor rec[5]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"XYZ\"),\n            .output = PauliString<W>::from_str(\"Z_Y\"),\n            .measurements = {5},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"XYZ -> rec[-1]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"XYZ\"),\n            .output = PauliString<W>::from_str(\"\"),\n            .measurements = {-1},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"XYZ -> Z_Y xor rec[-1] xor rec[-3]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"XYZ\"),\n            .output = PauliString<W>::from_str(\"Z_Y\"),\n            .measurements = {-3, -1},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"XYZ -> ZIY xor rec[55] xor rec[-3]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"XYZ\"),\n            .output = PauliString<W>::from_str(\"Z_Y\"),\n            .measurements = {-3, 55},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"XYZ -> ZIY xor rec[-3] xor rec[55]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"XYZ\"),\n            .output = PauliString<W>::from_str(\"Z_Y\"),\n            .measurements = {-3, 55},\n            .observables = {},\n        }));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"X9 -> -Z5*Y3 xor rec[55] xor rec[-3]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"_________X\"),\n            .output = PauliString<W>::from_str(\"-___Y_Z\"),\n            .measurements = {-3, 55},\n            .observables = {},\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, from_str_obs, {\n    EXPECT_EQ(\n        Flow<W>::from_str(\"X9 -> obs[5]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"_________X\"),\n            .output = PauliString<W>::from_str(\"\"),\n            .measurements = {},\n            .observables = {5},\n        }));\n    EXPECT_EQ(\n        Flow<W>::from_str(\"X9 -> X xor obs[5] xor obs[3] xor rec[-1]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"_________X\"),\n            .output = PauliString<W>::from_str(\"X\"),\n            .measurements = {-1},\n            .observables = {3, 5},\n        }));\n    EXPECT_EQ(\n        Flow<W>::from_str(\"X9 -> X xor obs[5] xor rec[-1] xor obs[3]\"),\n        (Flow<W>{\n            .input = PauliString<W>::from_str(\"_________X\"),\n            .output = PauliString<W>::from_str(\"X\"),\n            .measurements = {-1},\n            .observables = {3, 5},\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, str_and_from_str, {\n    auto flow = Flow<W>{\n        PauliString<W>::from_str(\"XY\"),\n        PauliString<W>::from_str(\"_Z\"),\n        {-3},\n    };\n    auto s_dense = \"XY -> _Z xor rec[-3]\";\n    auto s_sparse = \"X0*Y1 -> Z1 xor rec[-3]\";\n    ASSERT_EQ(flow.str(), s_dense);\n    ASSERT_EQ(Flow<W>::from_str(s_sparse), flow);\n    ASSERT_EQ(Flow<W>::from_str(s_dense), flow);\n\n    ASSERT_EQ(Flow<W>::from_str(\"1 -> rec[-1]\"), (Flow<W>{PauliString<W>(0), PauliString<W>(0), {-1}}));\n    ASSERT_EQ(Flow<W>::from_str(\"1 -> 1 xor rec[-1]\"), (Flow<W>{PauliString<W>(0), PauliString<W>(0), {-1}}));\n    ASSERT_EQ(\n        Flow<W>::from_str(\"1 -> Z9 xor rec[55]\"), (Flow<W>{PauliString<W>(0), PauliString<W>(\"_________Z\"), {55}}));\n\n    ASSERT_EQ(\n        Flow<W>::from_str(\"-1 -> -X xor rec[-1] xor rec[-3]\"),\n        (Flow<W>{PauliString<W>::from_str(\"-\"), PauliString<W>::from_str(\"-X\"), {-3, -1}}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, ordering, {\n    ASSERT_FALSE(Flow<W>::from_str(\"1 -> 1\") < Flow<W>::from_str(\"1 -> 1\"));\n    ASSERT_FALSE(Flow<W>::from_str(\"X -> 1\") < Flow<W>::from_str(\"1 -> 1\"));\n    ASSERT_FALSE(Flow<W>::from_str(\"1 -> X\") < Flow<W>::from_str(\"1 -> 1\"));\n    ASSERT_FALSE(Flow<W>::from_str(\"1 -> rec[-1]\") < Flow<W>::from_str(\"1 -> 1\"));\n    ASSERT_TRUE(Flow<W>::from_str(\"1 -> 1\") < Flow<W>::from_str(\"X -> 1\"));\n    ASSERT_TRUE(Flow<W>::from_str(\"1 -> 1\") < Flow<W>::from_str(\"1 -> X\"));\n    ASSERT_TRUE(Flow<W>::from_str(\"1 -> 1\") < Flow<W>::from_str(\"1 -> rec[-1]\"));\n})\n"
  },
  {
    "path": "src/stim/stabilizers/flow_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport numpy as np\nimport stim\nimport pytest\n\n\ndef test_basics():\n    p = stim.Flow()\n    assert p.input_copy() == stim.PauliString(0)\n    assert p.output_copy() == stim.PauliString(0)\n    assert p.measurements_copy() == []\n    assert str(p) == \"1 -> 1\"\n    assert repr(p) == 'stim.Flow(\"1 -> 1\")'\n\n    p = stim.Flow(\n        input=stim.PauliString(\"XX\"),\n        output=stim.PauliString(\"-YYZ\"),\n        measurements=[-1, 2, 3],\n    )\n    assert p.input_copy() == stim.PauliString(\"XX\")\n    assert p.output_copy() == stim.PauliString(\"-YYZ\")\n    assert p.measurements_copy() == [-1, 2, 3]\n    assert str(p) == \"XX -> -YYZ xor rec[-1] xor rec[2] xor rec[3]\"\n    assert repr(p) == 'stim.Flow(\"XX -> -YYZ xor rec[-1] xor rec[2] xor rec[3]\")'\n\n    p = stim.Flow(\"-X1*Z2 -> Y3 xor rec[-1]\")\n    assert p.input_copy() == stim.PauliString(\"-_XZ\")\n    assert p.output_copy() == stim.PauliString(\"___Y\")\n    assert p.measurements_copy() == [-1]\n    assert str(p) == \"-_XZ -> ___Y xor rec[-1]\"\n    assert repr(p) == 'stim.Flow(\"-_XZ -> ___Y xor rec[-1]\")'\n\n    p = stim.Flow(\"X20 -> Y xor rec[-1]\")\n    assert p.input_copy() == stim.PauliString(\"X20\")\n    assert p.output_copy() == stim.PauliString(\"Y\")\n    assert p.measurements_copy() == [-1]\n    assert str(p) == \"X20 -> Y0 xor rec[-1]\"\n    assert repr(p) == 'stim.Flow(\"X20 -> Y0 xor rec[-1]\")'\n\n    p = stim.Flow(\"X20*I21 -> Y xor rec[-1]\")\n    assert p.input_copy() == stim.PauliString(\"____________________X_\")\n    assert p.output_copy() == stim.PauliString(\"Y\")\n    assert p.measurements_copy() == [-1]\n    assert str(p) == \"____________________X_ -> Y xor rec[-1]\"\n    assert repr(p) == 'stim.Flow(\"____________________X_ -> Y xor rec[-1]\")'\n\n    p = stim.Flow(\"iX -> iY\")\n    assert p.input_copy() == stim.PauliString(\"X\")\n    assert p.output_copy() == stim.PauliString(\"Y\")\n    assert p.measurements_copy() == []\n\n    p = stim.Flow(input=stim.PauliString(\"iX\"), output=stim.PauliString(\"iY\"))\n    assert p.input_copy() == stim.PauliString(\"X\")\n    assert p.output_copy() == stim.PauliString(\"Y\")\n    assert p.measurements_copy() == []\n\n    with pytest.raises(ValueError, match=\"Anti-Hermitian\"):\n        stim.Flow(\"iX -> Y\")\n    with pytest.raises(ValueError, match=\"Anti-Hermitian\"):\n        stim.Flow(input=stim.PauliString(\"iX\"), output=stim.PauliString(\"Y\"))\n\n\ndef test_equality():\n    assert not (stim.Flow() == None)\n    assert not (stim.Flow() == \"other object\")\n    assert not (stim.Flow() == object())\n    assert stim.Flow() != None\n    assert stim.Flow() != \"other object\"\n    assert stim.Flow() != object()\n\n    assert stim.Flow('X -> Y') == stim.Flow('X -> Y')\n    assert stim.Flow('X -> X') != stim.Flow('X -> Y')\n    assert not (stim.Flow('X -> Y') != stim.Flow('X -> Y'))\n    assert not (stim.Flow('X -> Y') == stim.Flow('X -> X'))\n\n    assert stim.Flow(\"X -> X xor rec[-1]\") == stim.Flow(\"X -> X xor rec[-1]\")\n    assert stim.Flow(\"X -> X xor rec[-1]\") != stim.Flow(\"Y -> X xor rec[-1]\")\n    assert stim.Flow(\"X -> X xor rec[-1]\") != stim.Flow(\"X -> Y xor rec[-1]\")\n    assert stim.Flow(\"X -> X xor rec[-1]\") != stim.Flow(\"X -> X xor rec[-2]\")\n\n\n@pytest.mark.parametrize(\"value\", [\n    stim.Flow(),\n    stim.Flow(\"X -> Y xor rec[-1]\"),\n    stim.Flow(\"X -> 1\"),\n    stim.Flow(\"-X -> Y\"),\n    stim.Flow(\"X -> -Y\"),\n    stim.Flow(\"-X -> -Y\"),\n    stim.Flow(\"1 -> X\"),\n    stim.Flow(\"X__________________ -> ________Y\"),\n])\ndef test_repr(value):\n    assert eval(repr(value), {'stim': stim}) == value\n    assert repr(eval(repr(value), {'stim': stim})) == repr(value)\n\n\ndef test_obs_flows():\n    assert stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(1) X2\n    \"\"\").has_flow(stim.Flow(\"X2 -> obs[1]\"))\n    assert not stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(1) !X2\n    \"\"\").has_flow(stim.Flow(\"X2 -> obs[1]\"))\n    assert stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(1) !X2\n    \"\"\").has_flow(stim.Flow(\"X2 -> obs[1]\"), unsigned=True)\n    assert stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(1) !X2\n    \"\"\").has_flow(stim.Flow(\"-X2 -> obs[1]\"))\n    assert not stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(1) X2\n    \"\"\").has_flow(stim.Flow(\"Y2 -> obs[1]\"))\n    assert not stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(1) X2\n    \"\"\").has_flow(stim.Flow(\"Y2 -> obs[1]\"), unsigned=True)\n\n\ndef test_obs_include_pauli_terms_sensitivity():\n    _, obs = stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(0) X0\n        X_ERROR(0.5) 0\n        OBSERVABLE_INCLUDE(0) X0\n    \"\"\").compile_detector_sampler().sample(shots=1024, separate_observables=True)\n    assert np.count_nonzero(obs) == 0\n\n    _, obs = stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        X_ERROR(0.5) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n    \"\"\").compile_detector_sampler().sample(shots=1024, separate_observables=True)\n    xs, ys, zs = np.count_nonzero(obs, axis=0)\n    assert xs == 0\n    assert 256 <= ys <= 768\n    assert zs == ys\n\n    _, obs = stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        Y_ERROR(0.5) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n    \"\"\").compile_detector_sampler().sample(shots=1024, separate_observables=True)\n    xs, ys, zs = np.count_nonzero(obs, axis=0)\n    assert ys == 0\n    assert 256 <= xs <= 768\n    assert zs == xs\n\n    _, obs = stim.Circuit(\"\"\"\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n        Z_ERROR(0.5) 0\n        OBSERVABLE_INCLUDE(0) X0\n        OBSERVABLE_INCLUDE(1) Y0\n        OBSERVABLE_INCLUDE(2) Z0\n    \"\"\").compile_detector_sampler().sample(shots=1024, separate_observables=True)\n    xs, ys, zs = np.count_nonzero(obs, axis=0)\n    assert zs == 0\n    assert 256 <= ys <= 768\n    assert xs == ys\n\n\ndef test_flow_canonicalization():\n    assert stim.Flow(measurements=[4, 0, 4]) == stim.Flow(measurements=[0])\n    assert stim.Flow(included_observables=[4, 0, 4]) == stim.Flow(included_observables=[0])\n\n\ndef test_flow_multiplication():\n    assert stim.Flow(\"XYZ -> 1\") * stim.Flow(\"1 -> XYZ\") == stim.Flow(\"XYZ -> XYZ\")\n    assert stim.Flow(\"XX_ -> 1\") * stim.Flow(\"_XX -> 1\") == stim.Flow(\"X_X -> 1\")\n    assert stim.Flow(\"1 -> XX_\") * stim.Flow(\"1 -> _XX\") == stim.Flow(\"1 -> X_X\")\n    assert stim.Flow(\"1 -> rec[-1] xor rec[-3]\") * stim.Flow(\"1 -> rec[-1] xor rec[-2]\") == stim.Flow(\"1 -> rec[-2] xor rec[-3]\")\n    assert stim.Flow(\"1 -> obs[1] xor obs[3]\") * stim.Flow(\"1 -> obs[1] xor obs[2]\") == stim.Flow(\"1 -> obs[2] xor obs[3]\")\n    assert stim.Flow(\"X -> X\") * stim.Flow(\"Z -> Z\") == stim.Flow(\"Y -> Y\")\n    assert stim.Flow(\"1 -> XX\") * stim.Flow(\"1 -> ZZ\") == stim.Flow(\"1 -> -YY\")\n    assert stim.Flow(\"1 -> obs[1]\") * stim.Flow(\"1 -> obs[1]\") == stim.Flow(\"1 -> 1\")\n    assert stim.Flow(\"1 -> rec[1]\") * stim.Flow(\"1 -> rec[1]\") == stim.Flow(\"1 -> 1\")\n    with pytest.raises(ValueError, match=\"anticommute\"):\n        _ = stim.Flow(\"1 -> X\") * stim.Flow(\"1 -> Y\")\n    with pytest.raises(ValueError, match=\"anticommute\"):\n        _ = stim.Flow(\"1 -> Y\") * stim.Flow(\"1 -> X\")\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_STABILIZERS_PAULI_STRING_H\n#define _STIM_STABILIZERS_PAULI_STRING_H\n\n#include <functional>\n#include <iostream>\n\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/stabilizers/pauli_string_ref.h\"\n\nnamespace stim {\n\n/// Converts from the xz encoding\n///\n///     0b00: I\n///     0b01: X\n///     0b10: Z\n///     0b11: Y\n///\n/// To the xyz encoding\n///\n///     0: I\n///     1: X\n///     2: Y\n///     3: Z\ninline uint8_t pauli_xz_to_xyz(bool x, bool z) {\n    return (uint8_t)(x ^ z) | ((uint8_t)z << 1);\n}\n\n/// Converts from the xyz encoding\n///\n///     0: I\n///     1: X\n///     2: Y\n///     3: Z\n///\n/// To the xz encoding\n///\n///     0b00: I\n///     0b01: X\n///     0b10: Z\n///     0b11: Y\ninline uint8_t pauli_xyz_to_xz(uint8_t xyz) {\n    xyz ^= xyz >> 1;\n    return xyz;\n}\n\n/// A Pauli string is a product of Pauli operations (I, X, Y, Z) to apply to various qubits.\n///\n/// In most cases, methods will take a PauliStringRef instead of a PauliString. This is because PauliStringRef can\n/// have contents referring into densely packed table row data (or to a PauliString or to other sources). Basically,\n/// PauliString is for the special somewhat-unusual case where you want to create data to back a PauliStringRef instead\n/// of simply passing existing data along. It's a convenience class.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstruct PauliString {\n    /// The length of the Pauli string.\n    size_t num_qubits;\n    /// Whether or not the Pauli string is negated. True means -1, False means +1. Imaginary phase is not permitted.\n    bool sign;\n    /// The Paulis in the Pauli string, densely bit packed in a fashion enabling the use vectorized instructions.\n    /// Paulis are xz-encoded (P=xz: I=00, X=10, Y=11, Z=01) pairwise across the two bit vectors.\n    simd_bits<W> xs, zs;\n\n    /// Standard constructors.\n    explicit PauliString(size_t num_qubits);\n    PauliString(const PauliStringRef<W> &other);  // NOLINT(google-explicit-constructor)\n    PauliString(const PauliString<W> &other);\n    PauliString(PauliString<W> &&other) noexcept;\n    PauliString &operator=(const PauliStringRef<W> &other);\n    PauliString &operator=(const PauliString<W> &other);\n    PauliString &operator=(PauliString<W> &&other);\n\n    /// Parse constructor.\n    explicit PauliString(std::string_view text);\n    /// Factory method for creating a PauliString whose Pauli entries are returned by a function.\n    static PauliString<W> from_func(bool sign, size_t num_qubits, const std::function<char(size_t)> &func);\n    /// Factory method for creating a PauliString by parsing a string (e.g. \"-XIIYZ\").\n    static PauliString<W> from_str(std::string_view text);\n    /// Factory method for creating a PauliString with uniformly random sign and Pauli entries.\n    static PauliString<W> random(size_t num_qubits, std::mt19937_64 &rng);\n\n    /// Equality.\n    bool operator==(const PauliStringRef<W> &other) const;\n    bool operator==(const PauliString<W> &other) const;\n    /// Inequality.\n    bool operator!=(const PauliStringRef<W> &other) const;\n    bool operator!=(const PauliString<W> &other) const;\n    bool operator<(const PauliStringRef<W> &other) const;\n    bool operator<(const PauliString<W> &other) const;\n\n    /// Implicit conversion to a reference.\n    operator PauliStringRef<W>();\n    /// Implicit conversion to a const reference.\n    operator const PauliStringRef<W>() const;\n    /// Explicit conversion to a reference.\n    PauliStringRef<W> ref();\n    /// Explicit conversion to a const reference.\n    const PauliStringRef<W> ref() const;\n\n    /// Returns a python-style slice of the Paulis in the Pauli string.\n    PauliString<W> py_get_slice(int64_t start, int64_t step, int64_t slice_length) const;\n    /// Returns a Pauli from the pauli string, allowing python-style negative indices, using IXYZ encoding.\n    uint8_t py_get_item(int64_t index) const;\n\n    /// Returns a string describing the given Pauli string, with one character per qubit.\n    std::string str() const;\n\n    /// Grows the pauli string to be at least as large as the given number\n    /// of qubits.\n    ///\n    /// Requires:\n    ///     resize_pad_factor >= 1\n    ///\n    /// Args:\n    ///     min_num_qubits: A minimum number of qubits that will be needed.\n    ///     resize_pad_factor: When resizing, memory will be overallocated\n    ///          so that the pauli string can be expanded to at least this\n    ///          many times the number of requested qubits. Use this to\n    ///          avoid quadratic overheads from constant slight expansions.\n    void ensure_num_qubits(size_t min_num_qubits, double resize_pad_factor);\n\n    void mul_pauli_term(GateTarget t, bool *imag, bool right_mul);\n    void left_mul_pauli(GateTarget t, bool *imag);\n    void right_mul_pauli(GateTarget t, bool *imag);\n};\n\n/// Writes a string describing the given Pauli string to an output stream.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const PauliString<W> &ps);\n\n}  // namespace stim\n\n#include \"stim/stabilizers/pauli_string.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <cassert>\n#include <cstring>\n#include <string>\n\n#include \"stim/mem/simd_util.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nPauliString<W>::operator const PauliStringRef<W>() const {\n    return ref();\n}\n\ntemplate <size_t W>\nPauliString<W>::operator PauliStringRef<W>() {\n    return ref();\n}\n\ntemplate <size_t W>\nPauliString<W>::PauliString(size_t num_qubits) : num_qubits(num_qubits), sign(false), xs(num_qubits), zs(num_qubits) {\n}\n\ntemplate <size_t W>\nPauliString<W>::PauliString(std::string_view text) : num_qubits(0), sign(false), xs(0), zs(0) {\n    *this = std::move(PauliString<W>::from_str(text));\n}\n\ntemplate <size_t W>\nPauliString<W>::PauliString(const PauliStringRef<W> &other)\n    : num_qubits(other.num_qubits), sign((bool)other.sign), xs(other.xs), zs(other.zs) {\n}\n\ntemplate <size_t W>\nPauliString<W>::PauliString(const PauliString<W> &other)\n    : num_qubits(other.num_qubits), sign((bool)other.sign), xs(other.xs), zs(other.zs) {\n}\n\ntemplate <size_t W>\nPauliString<W>::PauliString(PauliString<W> &&other) noexcept\n    : num_qubits(other.num_qubits), sign((bool)other.sign), xs(std::move(other.xs)), zs(std::move(other.zs)) {\n    other.num_qubits = 0;\n    other.sign = false;\n}\n\ntemplate <size_t W>\nPauliString<W> &PauliString<W>::operator=(const PauliStringRef<W> &other) {\n    xs = other.xs;\n    zs = other.zs;\n    num_qubits = other.num_qubits;\n    sign = other.sign;\n    return *this;\n}\n\ntemplate <size_t W>\nPauliString<W> &PauliString<W>::operator=(const PauliString<W> &other) {\n    xs = other.xs;\n    zs = other.zs;\n    num_qubits = other.num_qubits;\n    sign = other.sign;\n    return *this;\n}\n\ntemplate <size_t W>\nPauliString<W> &PauliString<W>::operator=(PauliString<W> &&other) {\n    if (&other == this) {\n        return *this;\n    }\n    xs = std::move(other.xs);\n    zs = std::move(other.zs);\n    num_qubits = other.num_qubits;\n    sign = other.sign;\n    other.num_qubits = 0;\n    other.sign = false;\n    return *this;\n}\n\ntemplate <size_t W>\nconst PauliStringRef<W> PauliString<W>::ref() const {\n    size_t nw = (num_qubits + W - 1) / W;\n    return PauliStringRef<W>(\n        num_qubits,\n        // HACK: const correctness is temporarily removed, but immediately restored.\n        bit_ref((bool *)&sign, 0),\n        xs.word_range_ref(0, nw),\n        zs.word_range_ref(0, nw));\n}\n\ntemplate <size_t W>\nPauliStringRef<W> PauliString<W>::ref() {\n    size_t nw = (num_qubits + W - 1) / W;\n    return PauliStringRef<W>(num_qubits, bit_ref(&sign, 0), xs.word_range_ref(0, nw), zs.word_range_ref(0, nw));\n}\n\ntemplate <size_t W>\nstd::string PauliString<W>::str() const {\n    return ref().str();\n}\n\ntemplate <size_t W>\nPauliString<W> PauliString<W>::from_func(bool sign, size_t num_qubits, const std::function<char(size_t)> &func) {\n    PauliString<W> result(num_qubits);\n    result.sign = sign;\n    for (size_t i = 0; i < num_qubits; i++) {\n        char c = func(i);\n        bool x;\n        bool z;\n        if (c == 'X') {\n            x = true;\n            z = false;\n        } else if (c == 'Y') {\n            x = true;\n            z = true;\n        } else if (c == 'Z') {\n            x = false;\n            z = true;\n        } else if (c == '_' || c == 'I') {\n            x = false;\n            z = false;\n        } else {\n            throw std::invalid_argument(\"Unrecognized pauli character. \" + std::to_string(c));\n        }\n        result.xs.u64[i / 64] ^= (uint64_t)x << (i & 63);\n        result.zs.u64[i / 64] ^= (uint64_t)z << (i & 63);\n    }\n    return result;\n}\n\ntemplate <size_t W>\nPauliString<W> PauliString<W>::from_str(std::string_view text) {\n    bool is_negated = text.starts_with('-');\n    bool is_prefixed = text.starts_with('+');\n    if (is_prefixed || is_negated) {\n        text = text.substr(1);\n    }\n    return PauliString::from_func(is_negated, text.size(), [&](size_t i) {\n        return text[i];\n    });\n}\n\ntemplate <size_t W>\nPauliString<W> PauliString<W>::random(size_t num_qubits, std::mt19937_64 &rng) {\n    auto result = PauliString(num_qubits);\n    result.xs.randomize(num_qubits, rng);\n    result.zs.randomize(num_qubits, rng);\n    result.sign ^= rng() & 1;\n    return result;\n}\n\ntemplate <size_t W>\nbool PauliString<W>::operator==(const PauliStringRef<W> &other) const {\n    return ref() == other;\n}\n\ntemplate <size_t W>\nbool PauliString<W>::operator==(const PauliString<W> &other) const {\n    return ref() == other.ref();\n}\n\ntemplate <size_t W>\nbool PauliString<W>::operator!=(const PauliStringRef<W> &other) const {\n    return ref() != other;\n}\n\ntemplate <size_t W>\nbool PauliString<W>::operator!=(const PauliString<W> &other) const {\n    return ref() != other.ref();\n}\n\ntemplate <size_t W>\nbool PauliString<W>::operator<(const PauliString<W> &other) const {\n    return ref() < other.ref();\n}\n\ntemplate <size_t W>\nbool PauliString<W>::operator<(const PauliStringRef<W> &other) const {\n    return ref() < other;\n}\n\ntemplate <size_t W>\nvoid PauliString<W>::ensure_num_qubits(size_t min_num_qubits, double resize_pad_factor) {\n    assert(resize_pad_factor >= 1);\n    if (min_num_qubits <= num_qubits) {\n        return;\n    }\n    if (xs.num_bits_padded() >= min_num_qubits) {\n        num_qubits = min_num_qubits;\n        return;\n    }\n\n    size_t new_num_qubits = (size_t)(min_num_qubits * resize_pad_factor);\n    simd_bits<W> new_xs(new_num_qubits);\n    simd_bits<W> new_zs(new_num_qubits);\n    new_xs.truncated_overwrite_from(xs, num_qubits);\n    new_zs.truncated_overwrite_from(zs, num_qubits);\n    xs = std::move(new_xs);\n    zs = std::move(new_zs);\n    num_qubits = min_num_qubits;\n}\n\ntemplate <size_t W>\nvoid PauliString<W>::mul_pauli_term(GateTarget t, bool *imag, bool right_mul) {\n    auto q = t.qubit_value();\n    ensure_num_qubits(q + 1, 1.25);\n    bool x2 = (bool)(t.data & TARGET_PAULI_X_BIT);\n    bool z2 = (bool)(t.data & TARGET_PAULI_Z_BIT);\n    if (!(x2 | z2)) {\n        throw std::invalid_argument(\"Not a pauli target: \" + t.str());\n    }\n\n    bit_ref x1 = xs[q];\n    bit_ref z1 = zs[q];\n    bool old_x1 = x1;\n    bool old_z1 = z1;\n    x1 ^= x2;\n    z1 ^= z2;\n\n    // At each bit position: accumulate anti-commutation (+i or -i) counts.\n    bool x1z2 = x1 & z2;\n    bool anti_commutes = (x2 & z1) ^ x1z2;\n    sign ^= (*imag ^ old_x1 ^ old_z1 ^ x1z2) & anti_commutes;\n    sign ^= (bool)(t.data & TARGET_INVERTED_BIT);\n    *imag ^= anti_commutes;\n    sign ^= right_mul && anti_commutes;\n}\n\ntemplate <size_t W>\nvoid PauliString<W>::left_mul_pauli(GateTarget t, bool *imag) {\n    mul_pauli_term(t, imag, false);\n}\n\ntemplate <size_t W>\nvoid PauliString<W>::right_mul_pauli(GateTarget t, bool *imag) {\n    mul_pauli_term(t, imag, true);\n}\n\ntemplate <size_t W>\nuint8_t PauliString<W>::py_get_item(int64_t index) const {\n    if (index < 0) {\n        index += num_qubits;\n    }\n    if (index < 0 || (size_t)index >= num_qubits) {\n        throw std::out_of_range(\"index\");\n    }\n    size_t u = (size_t)index;\n    int x = xs[u];\n    int z = zs[u];\n    return pauli_xz_to_xyz(x, z);\n}\n\ntemplate <size_t W>\nPauliString<W> PauliString<W>::py_get_slice(int64_t start, int64_t step, int64_t slice_length) const {\n    assert(slice_length >= 0);\n    assert(slice_length == 0 || start >= 0);\n    return PauliString::from_func(false, slice_length, [&](size_t i) {\n        int j = start + i * step;\n        return \"_XZY\"[xs[j] + zs[j] * 2];\n    });\n}\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const PauliString<W> &ps) {\n    return out << ps.ref();\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/pauli_string.h\"\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(PauliString_multiplication_1M) {\n    size_t n = 1000 * 1000;\n    PauliString<MAX_BITWORD_WIDTH> p1(n);\n    PauliString<MAX_BITWORD_WIDTH> p2(n);\n    benchmark_go([&]() {\n        p1.ref().inplace_right_mul_returning_log_i_scalar(p2);\n    })\n        .goal_micros(8.5)\n        .show_rate(\"Paulis\", n);\n}\n\nBENCHMARK(PauliString_multiplication_100K) {\n    size_t n = 100 * 1000;\n    PauliString<MAX_BITWORD_WIDTH> p1(n);\n    PauliString<MAX_BITWORD_WIDTH> p2(n);\n    benchmark_go([&]() {\n        p1.ref().inplace_right_mul_returning_log_i_scalar(p2);\n    })\n        .goal_nanos(700)\n        .show_rate(\"Paulis\", n);\n}\n\nBENCHMARK(PauliString_multiplication_10K) {\n    size_t n = 10 * 1000;\n    PauliString<MAX_BITWORD_WIDTH> p1(n);\n    PauliString<MAX_BITWORD_WIDTH> p2(n);\n    benchmark_go([&]() {\n        p1.ref().inplace_right_mul_returning_log_i_scalar(p2);\n    })\n        .goal_nanos(90)\n        .show_rate(\"Paulis\", n);\n}\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/pauli_string.h\"\n\n#include \"stim/circuit/circuit_instruction.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n#include \"stim/stabilizers/pauli_string.pybind.h\"\n#include \"stim/stabilizers/pauli_string_iter.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\npybind11::object flex_pauli_string_to_unitary_matrix(const stim::FlexPauliString &ps, std::string_view endian) {\n    bool little_endian;\n    if (endian == \"little\") {\n        little_endian = true;\n    } else if (endian == \"big\") {\n        little_endian = false;\n    } else {\n        throw std::invalid_argument(\"endian not in ['little', 'big']\");\n    }\n    size_t q = ps.value.num_qubits;\n    if (q >= 32) {\n        throw std::invalid_argument(\"Too many qubits.\");\n    }\n    size_t n = 1 << q;\n    std::complex<float> *buffer = new std::complex<float>[n * n];\n    uint64_t x = 0;\n    uint64_t z = 0;\n    for (size_t k = 0; k < q; k++) {\n        x <<= 1;\n        z <<= 1;\n        if (little_endian) {\n            x |= ps.value.xs[q - k - 1];\n            z |= ps.value.zs[q - k - 1];\n        } else {\n            x |= ps.value.xs[k];\n            z |= ps.value.zs[k];\n        }\n    }\n    uint8_t start_phase = 0;\n    start_phase += std::popcount(x & z);\n    if (ps.imag) {\n        start_phase += 1;\n    }\n    if (ps.value.sign) {\n        start_phase += 2;\n    }\n    for (size_t col = 0; col < n; col++) {\n        size_t row = col ^ x;\n        uint8_t phase = start_phase;\n        if (std::popcount(col & z) & 1) {\n            phase += 2;\n        }\n        std::complex<float> v{1, 0};\n        if (phase & 2) {\n            v *= -1;\n        }\n        if (phase & 1) {\n            v *= std::complex<float>{0, 1};\n        }\n        buffer[row * n + col] = v;\n    }\n\n    pybind11::capsule free_when_done(buffer, [](void *f) {\n        delete[] reinterpret_cast<std::complex<float> *>(f);\n    });\n\n    pybind11::ssize_t sn = (pybind11::ssize_t)n;\n    pybind11::ssize_t itemsize = sizeof(std::complex<float>);\n    return pybind11::array_t<std::complex<float>>({sn, sn}, {sn * itemsize, itemsize}, buffer, free_when_done);\n}\n\nFlexPauliString &flex_pauli_string_obj_imul(FlexPauliString &lhs, const pybind11::object &rhs) {\n    if (pybind11::isinstance<FlexPauliString>(rhs)) {\n        return lhs *= pybind11::cast<FlexPauliString>(rhs);\n    } else if (rhs.equal(pybind11::cast(std::complex<float>{+1, 0}))) {\n        return lhs;\n    } else if (rhs.equal(pybind11::cast(std::complex<float>{-1, 0}))) {\n        return lhs *= std::complex<float>{-1, 0};\n    } else if (rhs.equal(pybind11::cast(std::complex<float>{0, 1}))) {\n        return lhs *= std::complex<float>{0, 1};\n    } else if (rhs.equal(pybind11::cast(std::complex<float>{0, -1}))) {\n        return lhs *= std::complex<float>{0, -1};\n    } else if (pybind11::isinstance<pybind11::int_>(rhs)) {\n        pybind11::ssize_t k = pybind11::int_(rhs);\n        if (k >= 0) {\n            return lhs *= (pybind11::size_t)k;\n        }\n    }\n    throw std::out_of_range(\"need isinstance(rhs, (stim.PauliString, int)) or rhs in (1, -1, 1j, -1j)\");\n}\n\nFlexPauliString flex_pauli_string_obj_mul(const FlexPauliString &lhs, const pybind11::object &rhs) {\n    FlexPauliString copy = lhs;\n    flex_pauli_string_obj_imul(copy, rhs);\n    return copy;\n}\n\nsize_t numpy_to_size(const pybind11::object &numpy_array, size_t expected_size) {\n    if (pybind11::isinstance<pybind11::array_t<uint8_t>>(numpy_array)) {\n        auto arr = pybind11::cast<pybind11::array_t<uint8_t>>(numpy_array);\n        if (arr.ndim() == 1) {\n            size_t max_n = arr.shape(0) * 8;\n            size_t min_n = max_n == 0 ? 0 : max_n - 7;\n            if (expected_size == SIZE_MAX) {\n                throw std::invalid_argument(\n                    \"Need to specify expected number of pauli terms (the `num_qubits` argument) when bit packing.\\n\"\n                    \"A numpy array is bit packed (has dtype=np.uint8) but `num_qubits=None`.\");\n            }\n            if (expected_size < min_n || expected_size > max_n) {\n                std::stringstream ss;\n                ss << \"Numpy array has dtype=np.uint8 (meaning it is bit packed) and shape=\";\n                ss << arr.shape(0) << \" (meaning it has between \" << min_n << \" and \" << max_n << \" bits)\";\n                ss << \" but len=\" << expected_size << \" is outside that range.\";\n                throw std::invalid_argument(ss.str());\n            }\n            return expected_size;\n        }\n    } else if (pybind11::isinstance<pybind11::array_t<bool>>(numpy_array)) {\n        auto arr = pybind11::cast<pybind11::array_t<bool>>(numpy_array);\n        if (arr.ndim() == 1) {\n            size_t num_bits = arr.shape(0);\n            if (expected_size != SIZE_MAX && num_bits != expected_size) {\n                std::stringstream ss;\n                ss << \"Numpy array has dtype=bool_ and shape=\" << num_bits\n                   << \" which is different from the given len=\" << expected_size;\n                ss << \".\\nEither don't specify len (as it is not needed when using bool_ arrays) or ensure the given \"\n                      \"len agrees with the given array shapes.\";\n                throw std::invalid_argument(ss.str());\n            }\n            return num_bits;\n        }\n    }\n    throw std::invalid_argument(\"Bit data must be a 1-dimensional numpy array with dtype=np.uint8 or dtype=np.bool_\");\n}\n\nsize_t numpy_pair_to_size(\n    const pybind11::object &numpy_array1, const pybind11::object &numpy_array2, const pybind11::object &expected_size) {\n    size_t n0 = SIZE_MAX;\n    if (!expected_size.is_none()) {\n        n0 = pybind11::cast<size_t>(expected_size);\n    }\n    size_t n1 = numpy_to_size(numpy_array1, n0);\n    size_t n2 = numpy_to_size(numpy_array2, n0);\n    if (n1 != n2) {\n        throw std::invalid_argument(\"Inconsistent array shapes.\");\n    }\n    return n2;\n}\n\nFlexPauliString flex_pauli_string_from_unitary_matrix(\n    const pybind11::object &matrix, std::string_view endian, bool ignore_sign) {\n    bool little_endian;\n    if (endian == \"little\") {\n        little_endian = true;\n    } else if (endian == \"big\") {\n        little_endian = false;\n    } else {\n        throw std::invalid_argument(\"endian not in ['little', 'big']\");\n    }\n\n    std::complex<float> unphase = 0;\n    auto row_index_phase = [&](const pybind11::handle &row) -> std::tuple<uint64_t, uint8_t, uint64_t> {\n        size_t num_cells = 0;\n        size_t non_zero_index = SIZE_MAX;\n        uint8_t phase = 0;\n        for (const auto &cell : row) {\n            auto c = pybind11::cast<std::complex<float>>(cell);\n            if (abs(c) < 1e-2) {\n                num_cells++;\n                continue;\n            }\n            if (unphase == std::complex<float>{0}) {\n                if (ignore_sign) {\n                    unphase = conj(c);\n                } else {\n                    unphase = 1;\n                }\n            }\n            c *= unphase;\n\n            if (abs(c - std::complex<float>{1, 0}) < 1e-2) {\n                phase = 0;\n            } else if (abs(c - std::complex<float>{0, 1}) < 1e-2) {\n                phase = 1;\n            } else if (abs(c - std::complex<float>{-1, 0}) < 1e-2) {\n                phase = 2;\n            } else if (abs(c - std::complex<float>{0, -1}) < 1e-2) {\n                phase = 3;\n            } else {\n                std::stringstream ss;\n                ss << \"The given unitary matrix isn't a Pauli string matrix. \";\n                ss << \"It has values besides 0, 1, -1, 1j, and -1j\";\n                if (ignore_sign) {\n                    ss << \" (up to global phase)\";\n                }\n                ss << '.';\n                throw std::invalid_argument(ss.str());\n            }\n            if (non_zero_index != SIZE_MAX) {\n                throw std::invalid_argument(\n                    \"The given unitary matrix isn't a Pauli string matrix. It has two non-zero entries in the same \"\n                    \"row.\");\n            }\n            non_zero_index = num_cells;\n            num_cells++;\n        }\n        if (non_zero_index == SIZE_MAX) {\n            throw std::invalid_argument(\n                \"The given unitary matrix isn't a Pauli string matrix. It has a row with no non-zero entries.\");\n        }\n        return {non_zero_index, phase, num_cells};\n    };\n\n    uint64_t x = 0;\n    uint64_t n = 0;\n    std::vector<uint8_t> phases;\n    for (const auto &row : matrix) {\n        auto row_data = row_index_phase(row);\n        uint64_t index = std::get<0>(row_data) ^ (uint64_t)phases.size();\n        phases.push_back(std::get<1>(row_data));\n        size_t len = std::get<2>(row_data);\n        if (phases.size() == 1) {\n            x = index;\n            n = len;\n        } else {\n            if (x != index) {\n                throw std::invalid_argument(\n                    \"The given unitary matrix isn't a Pauli string matrix. Rows disagree about which qubits are \"\n                    \"flipped.\");\n            }\n            if (n != len) {\n                throw std::invalid_argument(\n                    \"The given unitary matrix isn't a Pauli string matrix. Rows have different lengths.\");\n            }\n        }\n    }\n\n    if (phases.size() != n) {\n        throw std::invalid_argument(\"The given unitary matrix isn't a Pauli string matrix. It isn't square.\");\n    }\n    if (n == 0 || (n & (n - 1))) {\n        throw std::invalid_argument(\n            \"The given unitary matrix isn't a Pauli string matrix. Its height isn't a power of 2.\");\n    }\n\n    uint64_t z = 0;\n    size_t q = 0;\n    for (size_t p = n >> 1; p > 0; p >>= 1) {\n        z <<= 1;\n        z |= ((phases[p] - phases[0]) & 2) != 0;\n        q++;\n    }\n    for (size_t k = 0; k < n; k++) {\n        uint8_t expected_phase = phases[0];\n        if (std::popcount(k & z) & 1) {\n            expected_phase += 2;\n        }\n        if ((expected_phase & 3) != phases[k]) {\n            throw std::invalid_argument(\n                \"The given unitary matrix isn't a Pauli string matrix. It doesn't have consistent phase flips.\");\n        }\n    }\n\n    uint8_t leftover_phase = phases[0] + std::popcount(x & z);\n    FlexPauliString result(q);\n    result.imag = (leftover_phase & 1) != 0;\n    result.value.sign = (leftover_phase & 2) != 0;\n    auto &rx = result.value.xs.u64[0];\n    auto &rz = result.value.zs.u64[0];\n    if (little_endian) {\n        rx = x;\n        rz = z;\n    } else {\n        for (size_t k = 0; k < q; k++) {\n            rx <<= 1;\n            rz <<= 1;\n            rx |= x & 1;\n            rz |= z & 1;\n            x >>= 1;\n            z >>= 1;\n        }\n    }\n    if (ignore_sign) {\n        result.imag = false;\n        result.value.sign = false;\n    }\n    return result;\n}\n\npybind11::class_<FlexPauliString> stim_pybind::pybind_pauli_string(pybind11::module &m) {\n    return pybind11::class_<FlexPauliString>(\n        m,\n        \"PauliString\",\n        clean_doc_string(R\"DOC(\n            A signed Pauli tensor product (e.g. \"+X \\u2297 X \\u2297 X\" or \"-Y \\u2297 Z\".\n\n            Represents a collection of Pauli operations (I, X, Y, Z) applied pairwise to a\n            collection of qubits.\n\n            Examples:\n                >>> import stim\n                >>> stim.PauliString(\"XX\") * stim.PauliString(\"YY\")\n                stim.PauliString(\"-ZZ\")\n                >>> print(stim.PauliString(5))\n                +_____\n        )DOC\")\n            .data());\n}\n\nstatic uint8_t convert_pauli_to_int(const pybind11::handle &h) {\n    int64_t v = -1;\n    if (pybind11::isinstance<pybind11::int_>(h)) {\n        try {\n            v = pybind11::cast<int64_t>(h);\n        } catch (const pybind11::cast_error &) {\n        }\n    } else if (pybind11::isinstance<pybind11::str>(h)) {\n        std::string_view s = pybind11::cast<std::string_view>(h);\n        if (s == \"I\" || s == \"_\") {\n            v = 0;\n        } else if (s == \"X\" || s == \"x\") {\n            v = 1;\n        } else if (s == \"Y\" || s == \"y\") {\n            v = 2;\n        } else if (s == \"Z\" || s == \"z\") {\n            v = 3;\n        }\n    }\n    if (v >= 0 && v < 4) {\n        return (uint8_t)v;\n    } else {\n        throw std::invalid_argument(\n            \"Don't know how to convert \" + pybind11::cast<std::string>(pybind11::repr(h)) +\n            \" into a pauli.\\n\"\n            \"Expected something from {0, 1, 2, 3, 'I', 'X', 'Y', 'Z', '_'}.\");\n    }\n}\n\nstatic FlexPauliString pauli_string_from_dict(const pybind11::dict &dict) {\n    // Handle empty dict:\n    if (dict.empty()) {\n        return FlexPauliString(0);\n    }\n\n    const auto &first_entry = dict.begin();\n    std::vector<std::pair<size_t, uint8_t>> pauli_by_location;\n    size_t max_index = 0;\n\n    auto add_pauli_to_index = [&pauli_by_location, &max_index](pybind11::handle index, uint8_t pauli) {\n        int64_t index_value = pybind11::cast<int64_t>(index);\n        if (index_value < 0) {\n            throw std::invalid_argument(\"Qubit index must be non-negative. got: \" + std::to_string(index_value));\n        }\n\n        size_t index_ = static_cast<size_t>(index_value);\n        if (index_ > max_index) {\n            max_index = index_;\n        }\n        pauli_by_location.push_back(std::make_pair(index_, pauli));\n    };\n\n    if (pybind11::isinstance<pybind11::int_>(first_entry->second) ||\n        pybind11::isinstance<pybind11::str>(first_entry->second)) {\n        // Value is int or str -> key is qubit index:\n        for (const auto &item : dict) {\n            const auto &index = item.first;\n            const auto &pauli_string = item.second;\n            // Verify index is int for consistency:\n            if (!pybind11::isinstance<pybind11::int_>(index)) {\n                throw std::invalid_argument(\n                    \"When constructing stim.PauliString from Dict, keys must all be ints (indices) with single Pauli \"\n                    \"values, or Pauli keys with iterable values. Conflicting key: \" +\n                    pybind11::cast<std::string>(pybind11::repr(index)));\n            }\n\n            add_pauli_to_index(index, convert_pauli_to_int(pauli_string));\n        }\n\n    } else if (pybind11::isinstance<pybind11::iterable>(first_entry->second)) {\n        // Value is iterable -> key is Pauli:\n\n        // Find maximum number of indices:\n        size_t max_expected_indices = 0;\n        for (const auto &item : dict) {\n            const auto &indices = item.second;\n            if (pybind11::isinstance<pybind11::iterable>(indices)) {\n                max_expected_indices += static_cast<size_t>(pybind11::len(indices));\n            } else {\n                // In the iterable case - all values must also be iterables:\n                throw std::invalid_argument(\n                    \"When constructing stim.PauliString from Dict, with values as iterables, all values must be \"\n                    \"iterables. got: \" +\n                    pybind11::cast<std::string>(pybind11::repr(indices)));\n            }\n        }\n\n        std::unordered_map<size_t, uint8_t> used_indices;\n        used_indices.reserve(max_expected_indices);\n\n        auto verify_index_not_used = [&used_indices](pybind11::handle index, uint8_t pauli) -> bool {\n            // This helper function checks if an index has been used before. It doesn't allow non-trivial\n            // Pauli strings to collide, but it does allow collisions with trivial (\"I\") Pauli strings by not keeping\n            // track of them. return true if the new index should be added to the final result.\n\n            int64_t index_value = pybind11::cast<int64_t>(index);\n            if (index_value < 0) {\n                throw std::invalid_argument(\"Qubit index must be non-negative. got: \" + std::to_string(index_value));\n            }\n\n            size_t index_size_t = static_cast<size_t>(index_value);\n            const auto index_found = used_indices.find(index_size_t);\n\n            if (index_found == used_indices.end()) {\n                // Index has not been seed yet - add to map if non-trivial:\n                if (pauli != 0) {\n                    used_indices.emplace(index_size_t, pauli);\n                }\n            } else {\n                // Index has been seen before\n                if (pauli == 0) {\n                    // Must not add that Pauli to final result, it will override the older non-trivial one.\n                    return false;\n                }\n\n                // Check if older index is not the same Pauli:\n                if (index_found->second != pauli) {\n                    throw std::invalid_argument(\n                        \"More than one Pauli definitions use the same qubit index. Conflict for index:\" +\n                        pybind11::cast<std::string>(pybind11::repr(index)));\n                }\n            }\n\n            // Add new inde to final result:\n            return true;\n        };\n\n        for (const auto &item : dict) {\n            const auto &pauli_str_or_int = item.first;\n            const auto &indices = item.second;\n\n            // Verify pauli_str_or_int is str or int for consistency:\n            if (!(pybind11::isinstance<pybind11::str>(pauli_str_or_int) ||\n                  pybind11::isinstance<pybind11::int_>(pauli_str_or_int))) {\n                throw std::invalid_argument(\n                    \"When constructing stim.PauliString from Dict, keys must all be ints (indices) with single Pauli \"\n                    \"values, or Pauli keys with iterable values. Conflicting key: \" +\n                    pybind11::cast<std::string>(pybind11::repr(pauli_str_or_int)));\n            }\n\n            for (const auto &qubit_index : indices) {\n                // Verify index is an int:\n                if (!pybind11::isinstance<pybind11::int_>(qubit_index)) {\n                    throw std::invalid_argument(\n                        \"Qubit index must be an int. got:\" + pybind11::cast<std::string>(pybind11::repr(qubit_index)));\n                }\n\n                uint8_t pauli = convert_pauli_to_int(pauli_str_or_int);\n                bool should_add_new_pauli = verify_index_not_used(qubit_index, pauli);\n                if (should_add_new_pauli) {\n                    add_pauli_to_index(qubit_index, pauli);\n                }\n            }\n        }\n    } else {\n        throw std::invalid_argument(\n            \"Don't know how to initialize a stim.PauliString from \" +\n            pybind11::cast<std::string>(pybind11::repr(dict)));\n    }\n\n    // Format collected info into a FlexPauliString:\n    FlexPauliString result(pauli_by_location.empty() ? 0 : max_index + 1);\n\n    for (const auto &[key, value] : pauli_by_location) {\n        // Conver 0-3 to x,z values (00, 01, 10, 11)\n        uint8_t p = value;\n        p ^= p >> 1;\n        result.value.xs[key] = p & 1;\n        result.value.zs[key] = (p & 2) >> 1;\n    }\n\n    return result;\n}\n\nvoid stim_pybind::pybind_pauli_string_methods(pybind11::module &m, pybind11::class_<FlexPauliString> &c) {\n    c.def(\n        pybind11::init(\n            [](const pybind11::object &arg,\n               const pybind11::object &num_qubits,\n               const pybind11::object &text,\n               const pybind11::object &other,\n               const pybind11::object &pauli_indices) -> FlexPauliString {\n                size_t count = 0;\n                count += !arg.is_none();\n                count += !num_qubits.is_none();\n                count += !text.is_none();\n                count += !other.is_none();\n                count += !pauli_indices.is_none();\n                if (count > 1) {\n                    throw std::invalid_argument(\"Multiple arguments specified.\");\n                }\n                if (count == 0) {\n                    return FlexPauliString(0);\n                }\n\n                const auto &num_qubits_or = pybind11::isinstance<pybind11::int_>(arg) ? arg : num_qubits;\n                if (!num_qubits_or.is_none()) {\n                    return FlexPauliString(pybind11::cast<size_t>(num_qubits_or));\n                }\n\n                pybind11::object text_or = pybind11::isinstance<pybind11::str>(arg) ? arg : text;\n                if (!text_or.is_none()) {\n                    return FlexPauliString::from_text(pybind11::cast<std::string_view>(text_or));\n                }\n\n                pybind11::object other_or = pybind11::isinstance<FlexPauliString>(arg) ? arg : other;\n                if (!other_or.is_none()) {\n                    return pybind11::cast<FlexPauliString>(other_or);\n                }\n\n                if (pybind11::isinstance<pybind11::dict>(arg)) {\n                    return pauli_string_from_dict(pybind11::cast<pybind11::dict>(arg));\n                }\n\n                pybind11::object pauli_indices_or = pybind11::isinstance<pybind11::iterable>(arg) ? arg : pauli_indices;\n                if (!pauli_indices_or.is_none()) {\n                    std::vector<uint8_t> ps;\n                    for (const pybind11::handle &h : pauli_indices_or) {\n                        ps.push_back(convert_pauli_to_int(h));\n                    }\n                    FlexPauliString result(ps.size());\n                    for (size_t k = 0; k < ps.size(); k++) {\n                        uint8_t p = ps[k];\n                        p ^= p >> 1;\n                        result.value.xs[k] = p & 1;\n                        result.value.zs[k] = p & 2;\n                    }\n                    return result;\n                }\n\n                throw std::invalid_argument(\n                    \"Don't know how to initialize a stim.PauliString from \" +\n                    pybind11::cast<std::string>(pybind11::repr(arg)));\n            }),\n        pybind11::arg(\"arg\") = pybind11::none(),\n        pybind11::pos_only(),\n        // These are no longer needed, and hidden from documentation, but are included to guarantee backwards\n        // compatibility.\n        pybind11::arg(\"num_qubits\") = pybind11::none(),\n        pybind11::arg(\"text\") = pybind11::none(),\n        pybind11::arg(\"other\") = pybind11::none(),\n        pybind11::arg(\"pauli_indices\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def __init__(self, arg: Union[None, int, str, stim.PauliString, Iterable[Union[int, Literal[\"_\", \"I\", \"X\", \"Y\", \"Z\"]]]] = None, /) -> None:\n            Initializes a stim.PauliString from the given argument.\n\n            When given a string, the string is parsed as a pauli string. The string can\n            optionally start with a sign ('+', '-', 'i', '+i', or '-i'). The rest of the\n            string should be either a dense pauli string or a sparse pauli string. A dense\n            pauli string is made up of characters from '_IXYZ' where '_' and 'I' mean\n            identity, 'X' means Pauli X, 'Y' means Pauli Y, and 'Z' means Pauli Z. A sparse\n            pauli string is a series of integers seperated by '*' and prefixed by 'I', 'X',\n            'Y', or 'Z'.\n\n            Args:\n                arg [position-only]: This can be a variety of types, including:\n                    None (default): initializes an empty Pauli string.\n                    int: initializes an identity Pauli string of the given length.\n                    str: initializes by parsing the given text.\n                    stim.PauliString: initializes a copy of the given Pauli string.\n                    Iterable: initializes by interpreting each item as a Pauli.\n                        Each item can be a single-qubit Pauli string (like \"X\"),\n                        or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n                    Dict[int, Union[int, str]]: initializes by interpreting keys as\n                        the qubit index and values as the Pauli for that index.\n                        Each value can be a single-qubit Pauli string (like \"X\"),\n                        or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n                    Dict[Union[int, str], Iterable[int]]: initializes by interpreting keys\n                        as Pauli operators and values as the qubit indices for that Pauli.\n                        Each key can be a single-qubit Pauli string (like \"X\"),\n                        or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.PauliString(\"-XYZ\")\n                stim.PauliString(\"-XYZ\")\n\n                >>> stim.PauliString()\n                stim.PauliString(\"+\")\n\n                >>> stim.PauliString(5)\n                stim.PauliString(\"+_____\")\n\n                >>> stim.PauliString(stim.PauliString(\"XX\"))\n                stim.PauliString(\"+XX\")\n\n                >>> stim.PauliString([0, 1, 3, 2])\n                stim.PauliString(\"+_XZY\")\n\n                >>> stim.PauliString(\"X\" for _ in range(4))\n                stim.PauliString(\"+XXXX\")\n\n                >>> stim.PauliString(\"-X2*Y6\")\n                stim.PauliString(\"-__X___Y\")\n\n                >>> stim.PauliString(\"X6*Y6\")\n                stim.PauliString(\"+i______Z\")\n\n                >>> stim.PauliString({0: \"X\", 2: \"Y\", 3: \"X\"})\n                stim.PauliString(\"+X_YX\")\n\n                >>> stim.PauliString({0: \"X\", 2: 2, 3: 1})\n                stim.PauliString(\"+X_YX\")\n\n                >>> stim.PauliString({\"X\": [1], 2: [4], \"Z\": [0, 3]})\n                stim.PauliString(\"+ZX_ZY\")\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"random\",\n        [](size_t num_qubits, bool allow_imaginary) {\n            auto rng = make_py_seeded_rng(pybind11::none());\n            return FlexPauliString(\n                PauliString<MAX_BITWORD_WIDTH>::random(num_qubits, rng), allow_imaginary ? (rng() & 1) : false);\n        },\n        pybind11::arg(\"num_qubits\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"allow_imaginary\") = false,\n        clean_doc_string(R\"DOC(\n            Samples a uniformly random Hermitian Pauli string.\n\n            Args:\n                num_qubits: The number of qubits the Pauli string should act on.\n                allow_imaginary: Defaults to False. If True, the sign of the result may be\n                    1j or -1j in addition to +1 or -1. In other words, setting this to True\n                    allows the result to be non-Hermitian.\n\n            Examples:\n                >>> import stim\n                >>> p = stim.PauliString.random(5)\n                >>> len(p)\n                5\n                >>> p.sign in [-1, +1]\n                True\n\n                >>> p2 = stim.PauliString.random(3, allow_imaginary=True)\n                >>> len(p2)\n                3\n                >>> p2.sign in [-1, +1, 1j, -1j]\n                True\n\n            Returns:\n                The sampled Pauli string.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_tableau\",\n        [](const FlexPauliString &self) {\n            return Tableau<MAX_BITWORD_WIDTH>::from_pauli_string(self.value);\n        },\n        clean_doc_string(R\"DOC(\n            Creates a Tableau equivalent to this Pauli string.\n\n            The tableau represents a Clifford operation that multiplies qubits\n            by the corresponding Pauli operations from this Pauli string.\n            The global phase of the pauli operation is lost in the conversion.\n\n            Returns:\n                The created tableau.\n\n            Examples:\n                >>> import stim\n                >>> p = stim.PauliString(\"ZZ\")\n                >>> p.to_tableau()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"-X_\"),\n                        stim.PauliString(\"-_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+Z_\"),\n                        stim.PauliString(\"+_Z\"),\n                    ],\n                )\n                >>> q = stim.PauliString(\"YX_Z\")\n                >>> q.to_tableau()\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"-X___\"),\n                        stim.PauliString(\"+_X__\"),\n                        stim.PauliString(\"+__X_\"),\n                        stim.PauliString(\"-___X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"-Z___\"),\n                        stim.PauliString(\"-_Z__\"),\n                        stim.PauliString(\"+__Z_\"),\n                        stim.PauliString(\"+___Z\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_unitary_matrix\",\n        &flex_pauli_string_to_unitary_matrix,\n        pybind11::kw_only(),\n        pybind11::arg(\"endian\"),\n        clean_doc_string(R\"DOC(\n            @signature def to_unitary_matrix(self, *, endian: Literal[\"little\", \"big\"]) -> np.ndarray[np.complex64]:\n            Converts the pauli string into a unitary matrix.\n\n            Args:\n                endian:\n                    \"little\": The first qubit is the least significant (corresponds\n                        to an offset of 1 in the matrix).\n                    \"big\": The first qubit is the most significant (corresponds\n                        to an offset of 2**(n - 1) in the matrix).\n\n            Returns:\n                A numpy array with dtype=np.complex64 and\n                shape=(1 << len(pauli_string), 1 << len(pauli_string)).\n\n            Example:\n                >>> import stim\n                >>> stim.PauliString(\"-YZ\").to_unitary_matrix(endian=\"little\")\n                array([[0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j],\n                       [0.-1.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                       [0.+0.j, 0.+0.j, 0.+0.j, 0.-1.j],\n                       [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j]], dtype=complex64)\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_unitary_matrix\",\n        &flex_pauli_string_from_unitary_matrix,\n        pybind11::arg(\"matrix\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"endian\") = \"little\",\n        pybind11::arg(\"unsigned\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def from_unitary_matrix(matrix: Iterable[Iterable[Union[int, float, complex]]], *, endian: Literal[\"little\", \"big\"] = 'little', unsigned: bool = False) -> stim.PauliString:\n            Creates a stim.PauliString from the unitary matrix of a Pauli group member.\n\n            Args:\n                matrix: A unitary matrix specified as an iterable of rows, with each row is\n                    an iterable of amplitudes. The unitary matrix must correspond to a\n                    Pauli string, including global phase.\n                endian:\n                    \"little\": matrix entries are in little endian order, where higher index\n                        qubits correspond to larger changes in row/col indices.\n                    \"big\": matrix entries are in big endian order, where higher index\n                        qubits correspond to smaller changes in row/col indices.\n                unsigned: When False, the input must only contain the values\n                    [0, 1, -1, 1j, -1j] and the output will have the correct global phase.\n                    When True, the input is permitted to be scaled by an arbitrary unit\n                    complex value and the output will always have positive sign.\n                    False is stricter but provides more information, while True is more\n                    flexible but provides less information.\n\n            Returns:\n                The pauli string equal to the given unitary matrix.\n\n            Raises:\n                ValueError: The given matrix isn't the unitary matrix of a Pauli string.\n\n            Examples:\n                >>> import stim\n                >>> stim.PauliString.from_unitary_matrix([\n                ...     [1j, 0],\n                ...     [0, -1j],\n                ... ], endian='little')\n                stim.PauliString(\"+iZ\")\n\n                >>> stim.PauliString.from_unitary_matrix([\n                ...     [1j**0.1, 0],\n                ...     [0, -(1j**0.1)],\n                ... ], endian='little', unsigned=True)\n                stim.PauliString(\"+Z\")\n\n                >>> stim.PauliString.from_unitary_matrix([\n                ...     [0, 1, 0, 0],\n                ...     [1, 0, 0, 0],\n                ...     [0, 0, 0, -1],\n                ...     [0, 0, -1, 0],\n                ... ], endian='little')\n                stim.PauliString(\"+XZ\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"pauli_indices\",\n        [](const FlexPauliString &self, std::string_view include) {\n            std::vector<uint64_t> result;\n            size_t n64 = self.value.xs.num_u64_padded();\n            bool keep_i = false;\n            bool keep_x = false;\n            bool keep_y = false;\n            bool keep_z = false;\n            for (char c : include) {\n                switch (c) {\n                    case '_':\n                    case 'I':\n                        keep_i = true;\n                        break;\n                    case 'x':\n                    case 'X':\n                        keep_x = true;\n                        break;\n                    case 'y':\n                    case 'Y':\n                        keep_y = true;\n                        break;\n                    case 'z':\n                    case 'Z':\n                        keep_z = true;\n                        break;\n                    default:\n                        throw std::invalid_argument(\"Invalid character in include string: \" + std::string(1, c));\n                }\n            }\n            for (size_t k = 0; k < n64; k++) {\n                uint64_t x = self.value.xs.u64[k];\n                uint64_t z = self.value.zs.u64[k];\n                uint64_t u = 0;\n                if (keep_i) {\n                    u |= ~x & ~z;\n                }\n                if (keep_x) {\n                    u |= x & ~z;\n                }\n                if (keep_y) {\n                    u |= x & z;\n                }\n                if (keep_z) {\n                    u |= ~x & z;\n                }\n                while (u) {\n                    uint8_t v = std::countr_zero(u);\n                    uint64_t q = k * 64 + v;\n                    if (q >= self.value.num_qubits) {\n                        return result;\n                    }\n                    result.push_back(q);\n                    u &= u - 1;\n                }\n            }\n            return result;\n        },\n        pybind11::arg(\"included_paulis\") = \"XYZ\",\n        clean_doc_string(R\"DOC(\n            @signature def pauli_indices(self, included_paulis: str = \"XYZ\") -> List[int]:\n            Returns the indices of non-identity Paulis, or of specified Paulis.\n\n            Args:\n                include: A string containing the Pauli types to include.\n                    X type Pauli indices are included if \"X\" or \"x\" is in the string.\n                    Y type Pauli indices are included if \"Y\" or \"y\" is in the string.\n                    Z type Pauli indices are included if \"Z\" or \"z\" is in the string.\n                    I type Pauli indices are included if \"I\" or \"_\" is in the string.\n                    An exception is thrown if other characters are in the string.\n\n            Returns:\n                A list containing the ascending indices of matching Pauli terms.\n\n            Examples:\n                >>> import stim\n                >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices()\n                [5, 9, 14]\n\n                >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"XZ\")\n                [5, 14]\n\n                >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"X\")\n                [5]\n\n                >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"Y\")\n                [9]\n\n                >>> stim.PauliString(\"_____X___Y____Z___\").pauli_indices(\"IY\")\n                [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17]\n\n                >>> stim.PauliString(\"-X103*Y100\").pauli_indices()\n                [100, 103]\n        )DOC\")\n            .data());\n\n    c.def(\n        \"commutes\",\n        [](const FlexPauliString &self, const FlexPauliString &other) {\n            return self.value.ref().commutes(other.value.ref());\n        },\n        pybind11::arg(\"other\"),\n        clean_doc_string(R\"DOC(\n            Determines if two Pauli strings commute or not.\n\n            Two Pauli strings commute if they have an even number of matched\n            non-equal non-identity Pauli terms. Otherwise they anticommute.\n\n            Args:\n                other: The other Pauli string.\n\n            Examples:\n                >>> import stim\n                >>> xx = stim.PauliString(\"XX\")\n                >>> xx.commutes(stim.PauliString(\"X_\"))\n                True\n                >>> xx.commutes(stim.PauliString(\"XX\"))\n                True\n                >>> xx.commutes(stim.PauliString(\"XY\"))\n                False\n                >>> xx.commutes(stim.PauliString(\"XZ\"))\n                False\n                >>> xx.commutes(stim.PauliString(\"ZZ\"))\n                True\n                >>> xx.commutes(stim.PauliString(\"X_Y__\"))\n                True\n                >>> xx.commutes(stim.PauliString(\"\"))\n                True\n\n            Returns:\n                True if the Pauli strings commute, False if they anti-commute.\n        )DOC\")\n            .data());\n\n    c.def(\"__str__\", &FlexPauliString::str, \"Returns a text description.\");\n\n    c.def(\n        \"__repr__\",\n        [](const FlexPauliString &self) {\n            return \"stim.PauliString(\\\"\" + self.str() + \"\\\")\";\n        },\n        \"Returns valid python code evaluating to an equivalent `stim.PauliString`.\");\n\n    c.def_property(\n        \"sign\",\n        &FlexPauliString::get_phase,\n        [](FlexPauliString &self, std::complex<float> new_sign) {\n            if (new_sign == std::complex<float>(1)) {\n                self.value.sign = false;\n                self.imag = false;\n            } else if (new_sign == std::complex<float>(-1)) {\n                self.value.sign = true;\n                self.imag = false;\n            } else if (new_sign == std::complex<float>(0, 1)) {\n                self.value.sign = false;\n                self.imag = true;\n            } else if (new_sign == std::complex<float>(0, -1)) {\n                self.value.sign = true;\n                self.imag = true;\n            } else {\n                throw std::invalid_argument(\"new_sign not in [1, -1, 1j, -1j]\");\n            }\n        },\n        clean_doc_string(R\"DOC(\n            The sign of the Pauli string. Can be +1, -1, 1j, or -1j.\n\n            Examples:\n                >>> import stim\n                >>> stim.PauliString(\"X\").sign\n                (1+0j)\n                >>> stim.PauliString(\"-X\").sign\n                (-1+0j)\n                >>> stim.PauliString(\"iX\").sign\n                1j\n                >>> stim.PauliString(\"-iX\").sign\n                (-0-1j)\n        )DOC\")\n            .data());\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two Pauli strings have identical contents.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two Pauli strings have non-identical contents.\");\n\n    c.def(\n        \"__len__\",\n        [](const FlexPauliString &self) {\n            return self.value.num_qubits;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the length the pauli string; the number of qubits it operates on.\n\n            Examples:\n                >>> import stim\n                >>> len(stim.PauliString(\"XY_ZZ\"))\n                5\n                >>> len(stim.PauliString(\"X0*Z99\"))\n                100\n        )DOC\")\n            .data());\n\n    c.def_property_readonly(\n        \"weight\",\n        [](const FlexPauliString &self) {\n            return self.value.ref().weight();\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of non-identity pauli terms in the pauli string.\n\n            Examples:\n                >>> import stim\n                >>> stim.PauliString(\"+___\").weight\n                0\n                >>> stim.PauliString(\"+__X\").weight\n                1\n                >>> stim.PauliString(\"+XYZ\").weight\n                3\n                >>> stim.PauliString(\"-XXX___XXYZ\").weight\n                7\n        )DOC\")\n            .data());\n\n    c.def(\n        \"extended_product\",\n        [](const FlexPauliString &self, const FlexPauliString &other) {\n            return std::make_tuple(std::complex<float>(1, 0), self * other);\n        },\n        pybind11::arg(\"other\"),\n        clean_doc_string(R\"DOC(\n             [DEPRECATED] Use multiplication (__mul__ or *) instead.\n        )DOC\")\n            .data());\n\n    c.def(\n        pybind11::self + pybind11::self,\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Returns the tensor product of two Pauli strings.\n\n            Concatenates the Pauli strings and multiplies their signs.\n\n            Args:\n                rhs: A second stim.PauliString.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.PauliString(\"X\") + stim.PauliString(\"YZ\")\n                stim.PauliString(\"+XYZ\")\n\n                >>> stim.PauliString(\"iX\") + stim.PauliString(\"-X\")\n                stim.PauliString(\"-iXX\")\n\n            Returns:\n                The tensor product.\n        )DOC\")\n            .data());\n\n    c.def(\n        pybind11::self += pybind11::self,\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Performs an inplace tensor product.\n\n            Concatenates the given Pauli string onto the receiving string and multiplies\n            their signs.\n\n            Args:\n                rhs: A second stim.PauliString.\n\n            Examples:\n                >>> import stim\n\n                >>> p = stim.PauliString(\"iX\")\n                >>> alias = p\n                >>> p += stim.PauliString(\"-YY\")\n                >>> p\n                stim.PauliString(\"-iXYY\")\n                >>> alias is p\n                True\n\n            Returns:\n                The mutated pauli string.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__mul__\",\n        &flex_pauli_string_obj_mul,\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Right-multiplies the Pauli string.\n\n            Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n            Args:\n                rhs: The right hand side of the multiplication. This can be:\n                    - A stim.PauliString to right-multiply term-by-term with the paulis of\n                        the pauli string.\n                    - A complex unit (1, -1, 1j, -1j) to multiply with the sign of the pauli\n                        string.\n                    - A non-negative integer indicating the tensor power to raise the pauli\n                        string to (how many times to repeat it).\n\n            Examples:\n                >>> import stim\n\n                >>> stim.PauliString(\"X\") * 1\n                stim.PauliString(\"+X\")\n                >>> stim.PauliString(\"X\") * -1\n                stim.PauliString(\"-X\")\n                >>> stim.PauliString(\"X\") * 1j\n                stim.PauliString(\"+iX\")\n\n                >>> stim.PauliString(\"X\") * 2\n                stim.PauliString(\"+XX\")\n                >>> stim.PauliString(\"-X\") * 2\n                stim.PauliString(\"+XX\")\n                >>> stim.PauliString(\"iX\") * 2\n                stim.PauliString(\"-XX\")\n                >>> stim.PauliString(\"X\") * 3\n                stim.PauliString(\"+XXX\")\n                >>> stim.PauliString(\"iX\") * 3\n                stim.PauliString(\"-iXXX\")\n\n                >>> stim.PauliString(\"X\") * stim.PauliString(\"Y\")\n                stim.PauliString(\"+iZ\")\n                >>> stim.PauliString(\"X\") * stim.PauliString(\"XX_\")\n                stim.PauliString(\"+_X_\")\n                >>> stim.PauliString(\"XXXX\") * stim.PauliString(\"_XYZ\")\n                stim.PauliString(\"+X_ZY\")\n\n            Returns:\n                The product or tensor power.\n\n            Raises:\n                TypeError: The right hand side isn't a stim.PauliString, a non-negative\n                    integer, or a complex unit (1, -1, 1j, or -1j).\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__rmul__\",\n        [](const FlexPauliString &self, const pybind11::object &lhs) {\n            if (pybind11::isinstance<FlexPauliString>(lhs)) {\n                return pybind11::cast<FlexPauliString>(lhs) * self;\n            }\n            return flex_pauli_string_obj_mul(self, lhs);\n        },\n        pybind11::arg(\"lhs\"),\n        clean_doc_string(R\"DOC(\n            Left-multiplies the Pauli string.\n\n            Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n            Args:\n                lhs: The left hand side of the multiplication. This can be:\n                    - A stim.PauliString to right-multiply term-by-term with the paulis of\n                        the pauli string.\n                    - A complex unit (1, -1, 1j, -1j) to multiply with the sign of the pauli\n                        string.\n                    - A non-negative integer indicating the tensor power to raise the pauli\n                        string to (how many times to repeat it).\n\n            Examples:\n                >>> import stim\n\n                >>> 1 * stim.PauliString(\"X\")\n                stim.PauliString(\"+X\")\n                >>> -1 * stim.PauliString(\"X\")\n                stim.PauliString(\"-X\")\n                >>> 1j * stim.PauliString(\"X\")\n                stim.PauliString(\"+iX\")\n\n                >>> 2 * stim.PauliString(\"X\")\n                stim.PauliString(\"+XX\")\n                >>> 2 * stim.PauliString(\"-X\")\n                stim.PauliString(\"+XX\")\n                >>> 2 * stim.PauliString(\"iX\")\n                stim.PauliString(\"-XX\")\n                >>> 3 * stim.PauliString(\"X\")\n                stim.PauliString(\"+XXX\")\n                >>> 3 * stim.PauliString(\"iX\")\n                stim.PauliString(\"-iXXX\")\n\n                >>> stim.PauliString(\"X\") * stim.PauliString(\"Y\")\n                stim.PauliString(\"+iZ\")\n                >>> stim.PauliString(\"X\") * stim.PauliString(\"XX_\")\n                stim.PauliString(\"+_X_\")\n                >>> stim.PauliString(\"XXXX\") * stim.PauliString(\"_XYZ\")\n                stim.PauliString(\"+X_ZY\")\n\n            Returns:\n                The product.\n\n            Raises:\n                ValueError: The scalar phase factor isn't 1, -1, 1j, or -1j.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__imul__\",\n        &flex_pauli_string_obj_imul,\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Inplace right-multiplies the Pauli string.\n\n            Can multiply by another Pauli string, a complex unit, or a tensor power.\n\n            Args:\n                rhs: The right hand side of the multiplication. This can be:\n                    - A stim.PauliString to right-multiply term-by-term into the paulis of\n                        the pauli string.\n                    - A complex unit (1, -1, 1j, -1j) to multiply into the sign of the pauli\n                        string.\n                    - A non-negative integer indicating the tensor power to raise the pauli\n                        string to (how many times to repeat it).\n\n            Examples:\n                >>> import stim\n\n                >>> p = stim.PauliString(\"X\")\n                >>> p *= 1j\n                >>> p\n                stim.PauliString(\"+iX\")\n\n                >>> p = stim.PauliString(\"iXY_\")\n                >>> p *= 3\n                >>> p\n                stim.PauliString(\"-iXY_XY_XY_\")\n\n                >>> p = stim.PauliString(\"X\")\n                >>> alias = p\n                >>> p *= stim.PauliString(\"Y\")\n                >>> alias\n                stim.PauliString(\"+iZ\")\n\n                >>> p = stim.PauliString(\"X\")\n                >>> p *= stim.PauliString(\"_YY\")\n                >>> p\n                stim.PauliString(\"+XYY\")\n\n            Returns:\n                The mutated Pauli string.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__itruediv__\",\n        &FlexPauliString::operator/=,\n        pybind11::is_operator(),\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Inplace divides the Pauli string by a complex unit.\n\n            Args:\n                rhs: The divisor. Can be 1, -1, 1j, or -1j.\n\n            Examples:\n                >>> import stim\n\n                >>> p = stim.PauliString(\"X\")\n                >>> p /= 1j\n                >>> p\n                stim.PauliString(\"-iX\")\n\n            Returns:\n                The mutated Pauli string.\n\n            Raises:\n                ValueError: The divisor isn't 1, -1, 1j, or -1j.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__truediv__\",\n        &FlexPauliString::operator/,\n        pybind11::is_operator(),\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Divides the Pauli string by a complex unit.\n\n            Args:\n                rhs: The divisor. Can be 1, -1, 1j, or -1j.\n\n            Examples:\n                >>> import stim\n\n                >>> stim.PauliString(\"X\") / 1j\n                stim.PauliString(\"-iX\")\n\n            Returns:\n                The quotient.\n\n            Raises:\n                ValueError: The divisor isn't 1, -1, 1j, or -1j.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__neg__\",\n        [](const FlexPauliString &self) {\n            FlexPauliString result = self;\n            result.value.sign ^= 1;\n            return result;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the negation of the pauli string.\n\n            Examples:\n                >>> import stim\n                >>> -stim.PauliString(\"X\")\n                stim.PauliString(\"-X\")\n                >>> -stim.PauliString(\"-Y\")\n                stim.PauliString(\"+Y\")\n                >>> -stim.PauliString(\"iZZZ\")\n                stim.PauliString(\"-iZZZ\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"copy\",\n        [](const FlexPauliString &self) {\n            FlexPauliString copy = self;\n            return copy;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the pauli string.\n\n            The copy is an independent pauli string with the same contents.\n\n            Examples:\n                >>> import stim\n                >>> p1 = stim.PauliString.random(2)\n                >>> p2 = p1.copy()\n                >>> p2 is p1\n                False\n                >>> p2 == p1\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_numpy\",\n        [](const FlexPauliString &self, bool bit_packed) {\n            return pybind11::make_tuple(\n                simd_bits_to_numpy(self.value.xs, self.value.num_qubits, bit_packed),\n                simd_bits_to_numpy(self.value.zs, self.value.num_qubits, bit_packed));\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def to_numpy(self, *, bit_packed: bool = False) -> Tuple[np.ndarray, np.ndarray]:\n\n            Decomposes the contents of the pauli string into X bit and Z bit numpy arrays.\n\n            Args:\n                bit_packed: Defaults to False. Determines whether the output numpy arrays\n                    use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n            Returns:\n                An (xs, zs) tuple encoding the paulis from the string. The k'th Pauli from\n                the string is encoded into k'th bit of xs and the k'th bit of zs using\n                the \"xz\" encoding:\n\n                    P=I -> x=0 and z=0\n                    P=X -> x=1 and z=0\n                    P=Y -> x=1 and z=1\n                    P=Z -> x=0 and z=1\n\n                The dtype and shape of the result depends on the bit_packed argument.\n\n                If bit_packed=False:\n                    Each bit gets its own byte.\n                    xs.dtype = zs.dtype = np.bool_\n                    xs.shape = zs.shape = len(self)\n                    xs_k = xs[k]\n                    zs_k = zs[k]\n\n                If bit_packed=True:\n                    Equivalent to applying np.packbits(bitorder='little') to the result.\n                    xs.dtype = zs.dtype = np.uint8\n                    xs.shape = zs.shape = math.ceil(len(self) / 8)\n                    xs_k = (xs[k // 8] >> (k % 8)) & 1\n                    zs_k = (zs[k // 8] >> (k % 8)) & 1\n\n            Examples:\n                >>> import stim\n\n                >>> xs, zs = stim.PauliString(\"XXXXYYYZZ\").to_numpy()\n                >>> xs\n                array([ True,  True,  True,  True,  True,  True,  True, False, False])\n                >>> zs\n                array([False, False, False, False,  True,  True,  True,  True,  True])\n\n                >>> xs, zs = stim.PauliString(\"XXXXYYYZZ\").to_numpy(bit_packed=True)\n                >>> xs\n                array([127,   0], dtype=uint8)\n                >>> zs\n                array([240,   1], dtype=uint8)\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_numpy\",\n        [](const pybind11::object &xs,\n           const pybind11::object &zs,\n           const pybind11::object &sign,\n           const pybind11::object &num_qubits) -> FlexPauliString {\n            size_t n = numpy_pair_to_size(xs, zs, num_qubits);\n            FlexPauliString result(n);\n            memcpy_bits_from_numpy_to_simd(n, xs, result.value.xs);\n            memcpy_bits_from_numpy_to_simd(n, zs, result.value.zs);\n            flex_pauli_string_obj_imul(result, sign);\n            return result;\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"xs\"),\n        pybind11::arg(\"zs\"),\n        pybind11::arg(\"sign\") = +1,\n        pybind11::arg(\"num_qubits\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def from_numpy(*, xs: np.ndarray, zs: np.ndarray, sign: Union[int, float, complex] = +1, num_qubits: Optional[int] = None) -> stim.PauliString:\n\n            Creates a pauli string from X bit and Z bit numpy arrays, using the encoding:\n\n                x=0 and z=0 -> P=I\n                x=1 and z=0 -> P=X\n                x=1 and z=1 -> P=Y\n                x=0 and z=1 -> P=Z\n\n            Args:\n                xs: The X bits of the pauli string. This array can either be a 1-dimensional\n                    numpy array with dtype=np.bool_, or a bit packed 1-dimensional numpy\n                    array with dtype=np.uint8. If the dtype is np.uint8 then the array is\n                    assumed to be bit packed in little endian order and the \"num_qubits\"\n                    argument must be specified. When bit packed, the x bit with offset k is\n                    stored at (xs[k // 8] >> (k % 8)) & 1.\n                zs: The Z bits of the pauli string. This array can either be a 1-dimensional\n                    numpy array with dtype=np.bool_, or a bit packed 1-dimensional numpy\n                    array with dtype=np.uint8. If the dtype is np.uint8 then the array is\n                    assumed to be bit packed in little endian order and the \"num_qubits\"\n                    argument must be specified. When bit packed, the x bit with offset k is\n                    stored at (xs[k // 8] >> (k % 8)) & 1.\n                sign: Defaults to +1. Set to +1, -1, 1j, or -1j to control the sign of the\n                    returned Pauli string.\n                num_qubits: Must be specified if xs or zs is a bit packed array. Specifies\n                    the expected length of the Pauli string.\n\n            Returns:\n                The created pauli string.\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n\n                >>> xs = np.array([1, 1, 1, 1, 1, 1, 1, 0, 0], dtype=np.bool_)\n                >>> zs = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1], dtype=np.bool_)\n                >>> stim.PauliString.from_numpy(xs=xs, zs=zs, sign=-1)\n                stim.PauliString(\"-XXXXYYYZZ\")\n\n                >>> xs = np.array([127, 0], dtype=np.uint8)\n                >>> zs = np.array([240, 1], dtype=np.uint8)\n                >>> stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=9)\n                stim.PauliString(\"+XXXXYYYZZ\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__pos__\",\n        [](const FlexPauliString &self) {\n            FlexPauliString copy = self;\n            return copy;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a pauli string with the same contents.\n\n            Examples:\n                >>> import stim\n                >>> +stim.PauliString(\"+X\")\n                stim.PauliString(\"+X\")\n                >>> +stim.PauliString(\"-YY\")\n                stim.PauliString(\"-YY\")\n                >>> +stim.PauliString(\"iZZZ\")\n                stim.PauliString(\"+iZZZ\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__setitem__\",\n        [](FlexPauliString &self, pybind11::ssize_t index, const pybind11::object &arg_new_pauli) {\n            if (index < 0) {\n                index += self.value.num_qubits;\n            }\n            if (index < 0 || (size_t)index >= self.value.num_qubits) {\n                throw std::out_of_range(\"index\");\n            }\n            size_t u = (size_t)index;\n            try {\n                pybind11::ssize_t new_pauli = pybind11::cast<pybind11::ssize_t>(arg_new_pauli);\n                if (new_pauli < 0 || new_pauli > 3) {\n                    throw std::out_of_range(\"Expected new_pauli in [0, 1, 2, 3, '_', 'I', 'X', 'Y', 'Z']\");\n                }\n                int z = (new_pauli >> 1) & 1;\n                int x = (new_pauli & 1) ^ z;\n                self.value.xs[u] = x;\n                self.value.zs[u] = z;\n            } catch (const pybind11::cast_error &) {\n                char new_pauli = pybind11::cast<char>(arg_new_pauli);\n                if (new_pauli == 'X') {\n                    self.value.xs[u] = 1;\n                    self.value.zs[u] = 0;\n                } else if (new_pauli == 'Y') {\n                    self.value.xs[u] = 1;\n                    self.value.zs[u] = 1;\n                } else if (new_pauli == 'Z') {\n                    self.value.xs[u] = 0;\n                    self.value.zs[u] = 1;\n                } else if (new_pauli == 'I' || new_pauli == '_') {\n                    self.value.xs[u] = 0;\n                    self.value.zs[u] = 0;\n                } else {\n                    throw std::out_of_range(\"Expected new_pauli in [0, 1, 2, 3, '_', 'I', 'X', 'Y', 'Z']\");\n                }\n            }\n        },\n        pybind11::arg(\"index\"),\n        pybind11::arg(\"new_pauli\"),\n        clean_doc_string(R\"DOC(\n           Mutates an entry in the pauli string using the encoding 0=I, 1=X, 2=Y, 3=Z.\n\n           Args:\n               index: The index of the pauli to overwrite.\n               new_pauli: Either a character from '_IXYZ' or an integer from range(4).\n\n           Examples:\n               >>> import stim\n               >>> p = stim.PauliString(4)\n               >>> p[2] = 1\n               >>> print(p)\n               +__X_\n               >>> p[0] = 3\n               >>> p[1] = 2\n               >>> p[3] = 0\n               >>> print(p)\n               +ZYX_\n               >>> p[0] = 'I'\n               >>> p[1] = 'X'\n               >>> p[2] = 'Y'\n               >>> p[3] = 'Z'\n               >>> print(p)\n               +_XYZ\n               >>> p[-1] = 'Y'\n               >>> print(p)\n               +_XYY\n        )DOC\")\n            .data());\n\n    c.def(\n        \"after\",\n        [](const FlexPauliString &self,\n           const pybind11::object &operation,\n           const pybind11::object &targets) -> FlexPauliString {\n            PauliString<MAX_BITWORD_WIDTH> result(0);\n            if (pybind11::isinstance<Circuit>(operation)) {\n                if (!targets.is_none()) {\n                    throw std::invalid_argument(\"Don't specify 'targets' when the operation is a stim.Circuit\");\n                }\n                result = self.value.ref().after(pybind11::cast<Circuit>(operation));\n            } else if (pybind11::isinstance<PyCircuitInstruction>(operation)) {\n                if (!targets.is_none()) {\n                    throw std::invalid_argument(\n                        \"Don't specify 'targets' when the operation is a stim.CircuitInstruction\");\n                }\n                result = self.value.ref().after(pybind11::cast<PyCircuitInstruction>(operation).as_operation_ref());\n            } else if (pybind11::isinstance<Tableau<MAX_BITWORD_WIDTH>>(operation)) {\n                if (targets.is_none()) {\n                    throw std::invalid_argument(\"Must specify 'targets' when the operation is a stim.Tableau\");\n                }\n                std::vector<size_t> raw_targets;\n                for (const auto &e : targets) {\n                    raw_targets.push_back(pybind11::cast<size_t>(e));\n                }\n                result = self.value.ref().after(pybind11::cast<Tableau<MAX_BITWORD_WIDTH>>(operation), raw_targets);\n            } else {\n                throw std::invalid_argument(\n                    \"Don't know how to apply \" + pybind11::cast<std::string>(pybind11::repr(operation)));\n            }\n            return FlexPauliString(result, self.imag);\n        },\n        pybind11::arg(\"operation\"),\n        pybind11::arg(\"targets\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @overload def after(self, operation: Union[stim.Circuit, stim.CircuitInstruction]) -> stim.PauliString:\n            @overload def after(self, operation: stim.Tableau, targets: Iterable[int]) -> stim.PauliString:\n            @signature def after(self, operation: Union[stim.Circuit, stim.Tableau, stim.CircuitInstruction], targets: Optional[Iterable[int]] = None) -> stim.PauliString:\n            Returns the result of conjugating the Pauli string by an operation.\n\n            Args:\n                operation: A circuit, tableau, or circuit instruction to\n                    conjugate the Pauli string by. Must be Clifford (e.g.\n                    if it's a circuit, the circuit can't have noise or\n                    measurements).\n                targets: Required if and only if the operation is a tableau.\n                    Specifies which qubits to target.\n\n            Examples:\n                >>> import stim\n                >>> p = stim.PauliString(\"_XYZ\")\n\n                >>> p.after(stim.CircuitInstruction(\"H\", [1]))\n                stim.PauliString(\"+_ZYZ\")\n\n                >>> p.after(stim.Circuit('''\n                ...     C_XYZ 1 2 3\n                ... '''))\n                stim.PauliString(\"+_YZX\")\n\n                >>> p.after(stim.Tableau.from_named_gate('CZ'), targets=[0, 1])\n                stim.PauliString(\"+ZXYZ\")\n\n            Returns:\n                The conjugated Pauli string. The Pauli string after the\n                operation that is exactly equivalent to the given Pauli\n                string before the operation.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"before\",\n        [](const FlexPauliString &self,\n           const pybind11::object &operation,\n           const pybind11::object &targets) -> FlexPauliString {\n            PauliString<MAX_BITWORD_WIDTH> result(0);\n            if (pybind11::isinstance<Circuit>(operation)) {\n                if (!targets.is_none()) {\n                    throw std::invalid_argument(\"Don't specify 'targets' when the operation is a stim.Circuit\");\n                }\n                result = self.value.ref().before(pybind11::cast<Circuit>(operation));\n            } else if (pybind11::isinstance<PyCircuitInstruction>(operation)) {\n                if (!targets.is_none()) {\n                    throw std::invalid_argument(\n                        \"Don't specify 'targets' when the operation is a stim.CircuitInstruction\");\n                }\n                result = self.value.ref().before(pybind11::cast<PyCircuitInstruction>(operation).as_operation_ref());\n            } else if (pybind11::isinstance<Tableau<MAX_BITWORD_WIDTH>>(operation)) {\n                if (targets.is_none()) {\n                    throw std::invalid_argument(\"Must specify 'targets' when the operation is a stim.Tableau\");\n                }\n                std::vector<size_t> raw_targets;\n                for (const auto &e : targets) {\n                    raw_targets.push_back(pybind11::cast<size_t>(e));\n                }\n                result = self.value.ref().before(pybind11::cast<Tableau<MAX_BITWORD_WIDTH>>(operation), raw_targets);\n            } else {\n                throw std::invalid_argument(\n                    \"Don't know how to apply \" + pybind11::cast<std::string>(pybind11::repr(operation)));\n            }\n            return FlexPauliString(result, self.imag);\n        },\n        pybind11::arg(\"operation\"),\n        pybind11::arg(\"targets\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @overload def before(self, operation: Union[stim.Circuit, stim.CircuitInstruction]) -> stim.PauliString:\n            @overload def before(self, operation: stim.Tableau, targets: Iterable[int]) -> stim.PauliString:\n            @signature def before(self, operation: Union[stim.Circuit, stim.Tableau, stim.CircuitInstruction], targets: Optional[Iterable[int]] = None) -> stim.PauliString:\n            Returns the result of conjugating the Pauli string by an operation.\n\n            Args:\n                operation: A circuit, tableau, or circuit instruction to\n                    anti-conjugate the Pauli string by. Must be Clifford (e.g.\n                    if it's a circuit, the circuit can't have noise or\n                    measurements).\n                targets: Required if and only if the operation is a tableau.\n                    Specifies which qubits to target.\n\n            Examples:\n                >>> import stim\n                >>> p = stim.PauliString(\"_XYZ\")\n\n                >>> p.before(stim.CircuitInstruction(\"H\", [1]))\n                stim.PauliString(\"+_ZYZ\")\n\n                >>> p.before(stim.Circuit('''\n                ...     C_XYZ 1 2 3\n                ... '''))\n                stim.PauliString(\"+_ZXY\")\n\n                >>> p.before(stim.Tableau.from_named_gate('CZ'), targets=[0, 1])\n                stim.PauliString(\"+ZXYZ\")\n\n            Returns:\n                The conjugated Pauli string. The Pauli string before the\n                operation that is exactly equivalent to the given Pauli\n                string after the operation.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__getitem__\",\n        [](const FlexPauliString &self, const pybind11::object &index_or_slice) -> pybind11::object {\n            pybind11::ssize_t start, step, slice_length;\n            if (normalize_index_or_slice(index_or_slice, self.value.num_qubits, &start, &step, &slice_length)) {\n                return pybind11::cast(FlexPauliString(self.value.py_get_slice(start, step, slice_length)));\n            } else {\n                return pybind11::cast(self.value.py_get_item(start));\n            }\n        },\n        pybind11::arg(\"index_or_slice\"),\n        clean_doc_string(R\"DOC(\n            Returns an individual Pauli or Pauli string slice from the pauli string.\n            @overload def __getitem__(self, index_or_slice: int) -> int:\n            @overload def __getitem__(self, index_or_slice: slice) -> stim.PauliString:\n\n            Individual Paulis are returned as an int using the encoding 0=I, 1=X, 2=Y, 3=Z.\n            Slices are returned as a stim.PauliString (always with positive sign).\n\n            Examples:\n                >>> import stim\n                >>> p = stim.PauliString(\"_XYZ\")\n                >>> p[2]\n                2\n                >>> p[-1]\n                3\n                >>> p[:2]\n                stim.PauliString(\"+_X\")\n                >>> p[::-1]\n                stim.PauliString(\"+ZYX_\")\n\n            Args:\n                index_or_slice: The index of the pauli to return, or the slice of paulis to\n                    return.\n\n            Returns:\n                0: Identity.\n                1: Pauli X.\n                2: Pauli Y.\n                3: Pauli Z.\n        )DOC\")\n            .data());\n\n    c.def(\n        pybind11::pickle(\n            [](const FlexPauliString &self) -> pybind11::str {\n                return self.str();\n            },\n            [](const pybind11::str &d) {\n                return FlexPauliString::from_text(pybind11::cast<std::string_view>(d));\n            }));\n\n    c.def_static(\n        \"iter_all\",\n        [](size_t num_qubits,\n           size_t min_weight,\n           const pybind11::object &max_weight_obj,\n           std::string_view allowed_paulis) -> PauliStringIterator<MAX_BITWORD_WIDTH> {\n            bool allow_x = false;\n            bool allow_y = false;\n            bool allow_z = false;\n            for (char c : allowed_paulis) {\n                switch (c) {\n                    case 'X':\n                        allow_x = true;\n                        break;\n                    case 'Y':\n                        allow_y = true;\n                        break;\n                    case 'Z':\n                        allow_z = true;\n                        break;\n                    default:\n                        throw std::invalid_argument(\n                            \"allowed_paulis='\" + std::string(allowed_paulis) +\n                            \"' had characters other than 'X', 'Y', and 'Z'.\");\n                }\n            }\n            size_t max_weight = num_qubits;\n            if (!max_weight_obj.is_none()) {\n                int64_t v = pybind11::cast<int64_t>(max_weight_obj);\n                if (v < 0) {\n                    min_weight = 1;\n                    max_weight = 0;\n                } else {\n                    max_weight = (size_t)v;\n                }\n            }\n            return PauliStringIterator<MAX_BITWORD_WIDTH>(\n                num_qubits, min_weight, max_weight, allow_x, allow_y, allow_z);\n        },\n        pybind11::arg(\"num_qubits\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"min_weight\") = 0,\n        pybind11::arg(\"max_weight\") = pybind11::none(),\n        pybind11::arg(\"allowed_paulis\") = \"XYZ\",\n        clean_doc_string(R\"DOC(\n            Returns an iterator that iterates over all matching pauli strings.\n\n            Args:\n                num_qubits: The desired number of qubits in the pauli strings.\n                min_weight: Defaults to 0. The minimum number of non-identity terms that\n                    must be present in each yielded pauli string.\n                max_weight: Defaults to None (unused). The maximum number of non-identity\n                    terms that must be present in each yielded pauli string.\n                allowed_paulis: Defaults to \"XYZ\". Set this to a string containing the\n                    non-identity paulis that are allowed to appear in each yielded pauli\n                    string. This argument must be a string made up of only \"X\", \"Y\", and\n                    \"Z\" characters. A non-identity Pauli is allowed if it appears in the\n                    string, and not allowed if it doesn't. Identity Paulis are always\n                    allowed.\n\n            Returns:\n                An Iterable[stim.PauliString] that yields the requested pauli strings.\n\n            Examples:\n                >>> import stim\n                >>> pauli_string_iterator = stim.PauliString.iter_all(\n                ...     num_qubits=3,\n                ...     min_weight=1,\n                ...     max_weight=2,\n                ...     allowed_paulis=\"XZ\",\n                ... )\n                >>> for p in pauli_string_iterator:\n                ...     print(p)\n                +X__\n                +Z__\n                +_X_\n                +_Z_\n                +__X\n                +__Z\n                +XX_\n                +XZ_\n                +ZX_\n                +ZZ_\n                +X_X\n                +X_Z\n                +Z_X\n                +Z_Z\n                +_XX\n                +_XZ\n                +_ZX\n                +_ZZ\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_STABILIZERS_PAULI_STRING_PYBIND_H\n#define _STIM_STABILIZERS_PAULI_STRING_PYBIND_H\n\n#include <complex>\n#include <pybind11/pybind11.h>\n\n#include \"stim/stabilizers/flex_pauli_string.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::FlexPauliString> pybind_pauli_string(pybind11::module &m);\nvoid pybind_pauli_string_methods(pybind11::module &m, pybind11::class_<stim::FlexPauliString> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/pauli_string.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(pauli_string, str, {\n    auto p1 = PauliString<W>::from_str(\"+IXYZ\");\n    ASSERT_EQ(p1.str(), \"+_XYZ\");\n\n    auto p2 = PauliString<W>::from_str(\"X\");\n    ASSERT_EQ(p2.str(), \"+X\");\n\n    auto p3 = PauliString<W>::from_str(\"-XZ\");\n    ASSERT_EQ(p3.str(), \"-XZ\");\n\n    auto s1 = PauliString<W>::from_func(true, 24 * 24, [](size_t i) {\n        return \"_XYZ\"[i & 3];\n    });\n    ASSERT_EQ(\n        s1.str(),\n        \"-\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\"\n        \"_XYZ_XYZ_XYZ_XYZ_XYZ_XYZ\");\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, log_i_scalar_byproduct, {\n    auto id = PauliString<W>::from_str(\"_\");\n    auto x = PauliString<W>::from_str(\"X\");\n    auto y = PauliString<W>::from_str(\"Y\");\n    auto z = PauliString<W>::from_str(\"Z\");\n\n    auto f = [](PauliString<W> a, PauliString<W> b) {\n        // Note: copying is intentational. Do not change args to references.\n        return a.ref().inplace_right_mul_returning_log_i_scalar(b);\n    };\n\n    ASSERT_EQ(f(id, id), 0);\n    ASSERT_EQ(f(id, x), 0);\n    ASSERT_EQ(f(id, y), 0);\n    ASSERT_EQ(f(id, z), 0);\n\n    ASSERT_EQ(f(x, id), 0);\n    ASSERT_EQ(f(x, x), 0);\n    ASSERT_EQ(f(x, y), 1);\n    ASSERT_EQ(f(x, z), 3);\n\n    ASSERT_EQ(f(y, id), 0);\n    ASSERT_EQ(f(y, x), 3);\n    ASSERT_EQ(f(y, y), 0);\n    ASSERT_EQ(f(y, z), 1);\n\n    ASSERT_EQ(f(z, id), 0);\n    ASSERT_EQ(f(z, x), 1);\n    ASSERT_EQ(f(z, y), 3);\n    ASSERT_EQ(f(z, z), 0);\n\n    ASSERT_EQ(f(PauliString<W>::from_str(\"XX\"), PauliString<W>::from_str(\"XY\")), 1);\n    ASSERT_EQ(f(PauliString<W>::from_str(\"XX\"), PauliString<W>::from_str(\"ZY\")), 0);\n    ASSERT_EQ(f(PauliString<W>::from_str(\"XX\"), PauliString<W>::from_str(\"YY\")), 2);\n    for (size_t n : std::vector<size_t>{1, 499, 4999, 5000}) {\n        auto all_x = PauliString<W>::from_func(false, n, [](size_t i) {\n            return 'X';\n        });\n        auto all_z = PauliString<W>::from_func(false, n, [](size_t i) {\n            return 'Z';\n        });\n        ASSERT_EQ(f(all_x, all_z), (-(int)n) & 3);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, equality, {\n    ASSERT_TRUE(PauliString<W>::from_str(\"\") == PauliString<W>::from_str(\"\"));\n    ASSERT_FALSE(PauliString<W>::from_str(\"\") != PauliString<W>::from_str(\"\"));\n    ASSERT_FALSE(PauliString<W>::from_str(\"\") == PauliString<W>::from_str(\"-\"));\n    ASSERT_FALSE(PauliString<W>::from_str(\"X\") == PauliString<W>::from_str(\"\"));\n    ASSERT_TRUE(PauliString<W>::from_str(\"XX\") == PauliString<W>::from_str(\"XX\"));\n    ASSERT_FALSE(PauliString<W>::from_str(\"XX\") == PauliString<W>::from_str(\"XY\"));\n    ASSERT_FALSE(PauliString<W>::from_str(\"XX\") == PauliString<W>::from_str(\"XZ\"));\n    ASSERT_FALSE(PauliString<W>::from_str(\"XX\") == PauliString<W>::from_str(\"X_\"));\n\n    auto all_x1 = PauliString<W>::from_func(false, 1000, [](size_t i) {\n        return 'X';\n    });\n    auto all_x2 = PauliString<W>::from_func(false, 1000, [](size_t i) {\n        return 'X';\n    });\n    auto all_z = PauliString<W>::from_func(false, 1000, [](size_t i) {\n        return 'Z';\n    });\n    ASSERT_EQ(all_x1, all_x2);\n    ASSERT_NE(all_x1, all_z);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, multiplication, {\n    auto x = PauliString<W>::from_str(\"X\");\n    auto y = PauliString<W>::from_str(\"Y\");\n    auto z = PauliString<W>::from_str(\"Z\");\n\n    auto lhs = x;\n    uint8_t log_i = lhs.ref().inplace_right_mul_returning_log_i_scalar(y);\n    ASSERT_EQ(log_i, 1);\n    ASSERT_EQ(lhs, z);\n\n    auto xxi = PauliString<W>::from_str(\"XXI\");\n    auto yyy = PauliString<W>::from_str(\"YYY\");\n    xxi.ref() *= yyy;\n    ASSERT_EQ(xxi, PauliString<W>::from_str(\"-ZZY\"));\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, identity, { ASSERT_EQ(PauliString<W>(5).str(), \"+_____\"); })\n\nTEST_EACH_WORD_SIZE_W(pauli_string, gather, {\n    auto p = PauliString<W>::from_str(\"-____XXXXYYYYZZZZ\");\n    auto p2 = PauliString<W>(4);\n    p.ref().gather_into(p2, std::vector<size_t>{0, 1, 2, 3});\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+IIII\"));\n    p.ref().gather_into(p2, std::vector<size_t>{4, 7, 8, 9});\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+XXYY\"));\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, swap_with_overwrite_with, {\n    auto a = PauliString<W>::from_func(false, 500, [](size_t k) {\n        return \"XYZIX\"[k % 5];\n    });\n    auto b = PauliString<W>::from_func(false, 500, [](size_t k) {\n        return \"ZZYIXXY\"[k % 7];\n    });\n    auto a2 = a;\n    auto b2 = b;\n\n    a2.ref().swap_with(b2);\n    ASSERT_EQ(a2, b);\n    ASSERT_EQ(b2, a);\n\n    a2.ref() = b2;\n    ASSERT_EQ(a2, a);\n    ASSERT_EQ(b2, a);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, scatter, {\n    auto s1 = PauliString<W>::from_str(\"-_XYZ\");\n    auto s2 = PauliString<W>::from_str(\"+XXZZ\");\n    auto p = PauliString<W>(8);\n    s1.ref().scatter_into(p, std::vector<size_t>{1, 3, 5, 7});\n    ASSERT_EQ(p, PauliString<W>::from_str(\"-___X_Y_Z\"));\n    s1.ref().scatter_into(p, std::vector<size_t>{1, 3, 5, 7});\n    ASSERT_EQ(p, PauliString<W>::from_str(\"+___X_Y_Z\"));\n    s2.ref().scatter_into(p, std::vector<size_t>{1, 3, 5, 7});\n    ASSERT_EQ(p, PauliString<W>::from_str(\"+_X_X_Z_Z\"));\n    s2.ref().scatter_into(p, std::vector<size_t>{4, 5, 6, 7});\n    ASSERT_EQ(p, PauliString<W>::from_str(\"+_X_XXXZZ\"));\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, move_copy_assignment, {\n    PauliString<W> x = PauliString<W>::from_str(\"XYZ\");\n    ASSERT_EQ(x, PauliString<W>::from_str(\"XYZ\"));\n\n    // Move.\n    PauliString<W> z = PauliString<W>::from_str(\"XXY\");\n    x = std::move(z);\n    ASSERT_EQ(x, PauliString<W>::from_str(\"XXY\"));\n    z = PauliString<W>::from_str(\"-IIX\");\n    x = std::move(z);\n    ASSERT_EQ(x, PauliString<W>::from_str(\"-IIX\"));\n\n    // Copy.\n    auto y = PauliString<W>::from_str(\"ZZZ\");\n    x = y;\n    ASSERT_EQ(x, PauliString<W>::from_str(\"ZZZ\"));\n    y = PauliString<W>::from_str(\"-ZZZ\");\n    x = y;\n    ASSERT_EQ(x, PauliString<W>::from_str(\"-ZZZ\"));\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, foreign_memory, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    size_t bits = 2048;\n    auto buffer = simd_bits<W>::random(bits, rng);\n    bool signs = false;\n    size_t num_qubits = W * 2 - 12;\n\n    auto p1 =\n        PauliStringRef<W>(num_qubits, bit_ref(&signs, 0), buffer.word_range_ref(0, 2), buffer.word_range_ref(4, 2));\n    auto p1b =\n        new PauliStringRef<W>(num_qubits, bit_ref(&signs, 0), buffer.word_range_ref(0, 2), buffer.word_range_ref(4, 2));\n    auto p2 =\n        PauliStringRef<W>(num_qubits, bit_ref(&signs, 1), buffer.word_range_ref(2, 2), buffer.word_range_ref(6, 2));\n    PauliString<W> copy_p1 = p1;\n    // p1 aliases p1b.\n    ASSERT_EQ(p1, *p1b);\n    ASSERT_EQ(p1, copy_p1);\n    p1.inplace_right_mul_returning_log_i_scalar(p2);\n    ASSERT_EQ(p1, *p1b);\n    ASSERT_NE(p1, copy_p1);\n    // Deleting p1b shouldn't delete the backing buffer. So p1 survives.\n    copy_p1 = p1;\n    ASSERT_EQ(p1, copy_p1);\n    delete p1b;\n    ASSERT_EQ(p1, copy_p1);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, commutes, {\n    auto f = [](const char *a, const char *b) {\n        auto pa = PauliString<W>::from_str(a);\n        auto pb = PauliString<W>::from_str(b);\n        return pa.ref().commutes(pb);\n    };\n    ASSERT_EQ(f(\"I\", \"I\"), true);\n    ASSERT_EQ(f(\"I\", \"X\"), true);\n    ASSERT_EQ(f(\"I\", \"Y\"), true);\n    ASSERT_EQ(f(\"I\", \"Z\"), true);\n    ASSERT_EQ(f(\"X\", \"I\"), true);\n    ASSERT_EQ(f(\"X\", \"X\"), true);\n    ASSERT_EQ(f(\"X\", \"Y\"), false);\n    ASSERT_EQ(f(\"X\", \"Z\"), false);\n    ASSERT_EQ(f(\"Y\", \"I\"), true);\n    ASSERT_EQ(f(\"Y\", \"X\"), false);\n    ASSERT_EQ(f(\"Y\", \"Y\"), true);\n    ASSERT_EQ(f(\"Y\", \"Z\"), false);\n    ASSERT_EQ(f(\"Z\", \"I\"), true);\n    ASSERT_EQ(f(\"Z\", \"X\"), false);\n    ASSERT_EQ(f(\"Z\", \"Y\"), false);\n    ASSERT_EQ(f(\"Z\", \"Z\"), true);\n\n    ASSERT_EQ(f(\"XX\", \"ZZ\"), true);\n    ASSERT_EQ(f(\"-XX\", \"ZZ\"), true);\n    ASSERT_EQ(f(\"XZ\", \"ZZ\"), false);\n    ASSERT_EQ(f(\"-XZ\", \"ZZ\"), false);\n\n    auto qa = PauliString<W>::from_func(false, 5000, [](size_t k) {\n        return k == 0 ? 'X' : 'Z';\n    });\n    auto qb = PauliString<W>::from_func(false, 5000, [](size_t k) {\n        return 'Z';\n    });\n    ASSERT_EQ(qa.ref().commutes(qa), true);\n    ASSERT_EQ(qb.ref().commutes(qb), true);\n    ASSERT_EQ(qa.ref().commutes(qb), false);\n    ASSERT_EQ(qb.ref().commutes(qa), false);\n\n    // Differing sizes.\n    ASSERT_EQ(qa.ref().commutes(PauliString<W>(0)), true);\n    ASSERT_EQ(PauliString<W>(0).ref().commutes(qa), true);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, sparse_str, {\n    ASSERT_EQ(PauliString<W>::from_str(\"IIIII\").ref().sparse_str(), \"+I\");\n    ASSERT_EQ(PauliString<W>::from_str(\"-IIIII\").ref().sparse_str(), \"-I\");\n    ASSERT_EQ(PauliString<W>::from_str(\"IIIXI\").ref().sparse_str(), \"+X3\");\n    ASSERT_EQ(PauliString<W>::from_str(\"IYIXZ\").ref().sparse_str(), \"+Y1*X3*Z4\");\n    ASSERT_EQ(PauliString<W>::from_str(\"-IYIXZ\").ref().sparse_str(), \"-Y1*X3*Z4\");\n    auto x501 = PauliString<W>::from_func(\n                    false,\n                    1000,\n                    [](size_t k) {\n                        return \"IX\"[k == 501];\n                    })\n                    .ref()\n                    .sparse_str();\n    ASSERT_EQ(x501, \"+X501\");\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, ensure_num_qubits, {\n    auto p = PauliString<W>::from_str(\"IXYZ_I\");\n    p.ensure_num_qubits(1, 1.0);\n    ASSERT_EQ(p, PauliString<W>::from_str(\"IXYZ_I\"));\n    p.ensure_num_qubits(6, 1.0);\n    ASSERT_EQ(p, PauliString<W>::from_str(\"IXYZ_I\"));\n    p.ensure_num_qubits(7, 1.0);\n    ASSERT_EQ(p, PauliString<W>::from_str(\"IXYZ_I_\"));\n    p.ensure_num_qubits(1000, 1.0);\n    PauliString<W> p2(1000);\n    p2.xs[1] = true;\n    p2.xs[2] = true;\n    p2.zs[2] = true;\n    p2.zs[3] = true;\n    ASSERT_EQ(p, p2);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, ensure_num_qubits_padded, {\n    auto p = PauliString<W>::from_str(\"IXYZ_I\");\n    auto p2 = p;\n    p.ensure_num_qubits(1121, 10.0);\n    p2.ensure_num_qubits(1121, 1.0);\n    ASSERT_GT(p.xs.num_simd_words, p2.xs.num_simd_words);\n    ASSERT_EQ(p, p2);\n})\n\nTEST(PauliString, pauli_xz_to_xyz) {\n    ASSERT_EQ(pauli_xz_to_xyz(false, false), 0);\n    ASSERT_EQ(pauli_xz_to_xyz(true, false), 1);\n    ASSERT_EQ(pauli_xz_to_xyz(true, true), 2);\n    ASSERT_EQ(pauli_xz_to_xyz(false, true), 3);\n}\n\nTEST(PauliString, pauli_xyz_to_xz) {\n    uint8_t x = 1;\n    uint8_t z = 2;\n    ASSERT_EQ(pauli_xyz_to_xz(0), 0);\n    ASSERT_EQ(pauli_xyz_to_xz(1), x);\n    ASSERT_EQ(pauli_xyz_to_xz(2), x + z);\n    ASSERT_EQ(pauli_xyz_to_xz(3), z);\n}\n\nTEST_EACH_WORD_SIZE_W(pauli_string, py_get_item, {\n    auto p = PauliString<W>::from_str(\"-XYZ_XYZ_XX\");\n    ASSERT_EQ(p.py_get_item(0), 1);\n    ASSERT_EQ(p.py_get_item(1), 2);\n    ASSERT_EQ(p.py_get_item(2), 3);\n    ASSERT_EQ(p.py_get_item(3), 0);\n    ASSERT_EQ(p.py_get_item(8), 1);\n    ASSERT_EQ(p.py_get_item(9), 1);\n\n    ASSERT_EQ(p.py_get_item(-1), 1);\n    ASSERT_EQ(p.py_get_item(-2), 1);\n    ASSERT_EQ(p.py_get_item(-3), 0);\n    ASSERT_EQ(p.py_get_item(-4), 3);\n    ASSERT_EQ(p.py_get_item(-9), 2);\n    ASSERT_EQ(p.py_get_item(-10), 1);\n\n    ASSERT_ANY_THROW({ p.py_get_item(10); });\n    ASSERT_ANY_THROW({ p.py_get_item(-11); });\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, py_get_slice, {\n    auto p = PauliString<W>::from_str(\"-XYZ_XYZ_YX\");\n    ASSERT_EQ(p.py_get_slice(0, 2, 0), PauliString<W>::from_str(\"\"));\n    ASSERT_EQ(p.py_get_slice(0, 2, 1), PauliString<W>::from_str(\"X\"));\n    ASSERT_EQ(p.py_get_slice(0, 2, 2), PauliString<W>::from_str(\"XZ\"));\n    ASSERT_EQ(p.py_get_slice(1, 2, 2), PauliString<W>::from_str(\"Y_\"));\n    ASSERT_EQ(p.py_get_slice(5, 1, 4), PauliString<W>::from_str(\"YZ_Y\"));\n    ASSERT_EQ(p.py_get_slice(5, -1, 4), PauliString<W>::from_str(\"YX_Z\"));\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, after_circuit, {\n    auto actual = PauliString<W>::from_str(\"+_XYZ\").ref().after(Circuit(R\"CIRCUIT(\n        H 1\n        CNOT 1 2\n        S 2\n    )CIRCUIT\"));\n    ASSERT_EQ(actual, PauliString<W>::from_str(\"-__XZ\"));\n\n    actual = PauliString<W>::from_str(\"+X___\").ref().after(Circuit(R\"CIRCUIT(\n        CX 0 1 1 2 2 3\n    )CIRCUIT\"));\n    ASSERT_EQ(actual, PauliString<W>::from_str(\"+XXXX\"));\n\n    actual = PauliString<W>::from_str(\"+X___\").ref().after(Circuit(R\"CIRCUIT(\n        REPEAT 6 {\n            CX 0 1 1 2 2 3\n        }\n    )CIRCUIT\"));\n    ASSERT_EQ(actual, PauliString<W>::from_str(\"+X_X_\"));\n\n    ASSERT_THROW(\n        {\n            PauliString<W>::from_str(\"+X___\").ref().after(Circuit(R\"CIRCUIT(\n            M(0.1) 0\n        )CIRCUIT\"));\n        },\n        std::invalid_argument);\n\n    ASSERT_THROW(\n        {\n            PauliString<W>::from_str(\"+X\").ref().after(Circuit(R\"CIRCUIT(\n                Z_ERROR(0.1) 0\n            )CIRCUIT\"));\n        },\n        std::invalid_argument);\n\n    ASSERT_THROW(\n        {\n            PauliString<W>::from_str(\"+X\").ref().after(Circuit(R\"CIRCUIT(\n            H 9\n        )CIRCUIT\"));\n        },\n        std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, before_after_circuit_ignores_annotations, {\n    auto c = Circuit(R\"CIRCUIT(\n        QUBIT_COORDS(2, 3) 5\n        REPEAT 5 {\n            DETECTOR rec[-1]\n        }\n        H 1\n        TICK\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        CNOT 1 2\n        S 2\n        SHIFT_COORDS(1, 2, 3)\n        TICK\n    )CIRCUIT\");\n    auto before = PauliString<W>::from_str(\"+_XYZ\");\n    auto after = PauliString<W>::from_str(\"-__XZ\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, before_after_circuit_understands_avoiding_resets, {\n    auto c = Circuit(R\"CIRCUIT(\n        R 0\n        MR 1\n        RX 2\n        MRX 3\n        RY 4\n        MRY 5\n        H 6\n    )CIRCUIT\");\n    auto before = PauliString<W>::from_str(\"+______X\");\n    auto after = PauliString<W>::from_str(\"+______Z\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    ASSERT_THROW({ PauliString<W>::from_str(\"+Z______\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+X______\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+_Z_____\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+__Z____\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+___Z___\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+____Z__\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+_____Z_\").ref().after(c); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, before_after_circuit_understands_commutation_with_m, {\n    auto c = Circuit(R\"CIRCUIT(\n        M 0\n        H 1\n    )CIRCUIT\");\n    auto before = PauliString<W>::from_str(\"+_X\");\n    auto after = PauliString<W>::from_str(\"+_Z\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = after = PauliString<W>::from_str(\"+Z_\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    ASSERT_THROW({ PauliString<W>::from_str(\"+X_\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+Y_\").ref().after(c); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, before_after_circuit_understands_commutation_with_mx, {\n    auto c = Circuit(R\"CIRCUIT(\n        MX 0\n        H 1\n    )CIRCUIT\");\n    auto before = PauliString<W>::from_str(\"+_X\");\n    auto after = PauliString<W>::from_str(\"+_Z\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = after = PauliString<W>::from_str(\"+X_\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    ASSERT_THROW({ PauliString<W>::from_str(\"+Z_\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+Y_\").ref().after(c); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, before_after_circuit_understands_commutation_with_my, {\n    auto c = Circuit(R\"CIRCUIT(\n        MY 0\n        H 1\n    )CIRCUIT\");\n    auto before = PauliString<W>::from_str(\"+_X\");\n    auto after = PauliString<W>::from_str(\"+_Z\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = after = PauliString<W>::from_str(\"+Y_\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    ASSERT_THROW({ PauliString<W>::from_str(\"+X_\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+Z_\").ref().after(c); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, before_after_circuit_understands_commutation_with_mpp, {\n    auto c = Circuit(R\"CIRCUIT(\n        MPP X2*Y3*Z4 X5*X6\n        H 1\n    )CIRCUIT\");\n    auto before = PauliString<W>::from_str(\"+_X_____\");\n    auto after = PauliString<W>::from_str(\"+_Z_____\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = PauliString<W>::from_str(\"+_XXYZXX\");\n    after = PauliString<W>::from_str(\"+_ZXYZXX\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = PauliString<W>::from_str(\"+_XX____\");\n    after = PauliString<W>::from_str(\"+_ZX____\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = after = PauliString<W>::from_str(\"+__ZX___\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = after = PauliString<W>::from_str(\"+__ZZ_ZZ\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = after = PauliString<W>::from_str(\"+___XYZZ\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = after = PauliString<W>::from_str(\"+__XXYZZ\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    before = after = PauliString<W>::from_str(\"+__X____\");\n    ASSERT_EQ(before.ref().after(c), after);\n    ASSERT_EQ(after.ref().before(c), before);\n\n    ASSERT_THROW({ PauliString<W>::from_str(\"+__XXYZX\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+_____ZX\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+__Z____\").ref().after(c); }, std::invalid_argument);\n    ASSERT_THROW({ PauliString<W>::from_str(\"+__XXYXY\").ref().after(c); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, before_circuit, {\n    auto actual = PauliString<W>::from_str(\"-__XZ\").ref().before(Circuit(R\"CIRCUIT(\n        H 1\n        CNOT 1 2\n        S 2\n    )CIRCUIT\"));\n    ASSERT_EQ(actual, PauliString<W>::from_str(\"+_XYZ\"));\n\n    actual = PauliString<W>::from_str(\"+XXXX\").ref().before(Circuit(R\"CIRCUIT(\n        CX 0 1 1 2 2 3\n    )CIRCUIT\"));\n    ASSERT_EQ(actual, PauliString<W>::from_str(\"+X___\"));\n\n    actual = PauliString<W>::from_str(\"+X_X_\").ref().after(Circuit(R\"CIRCUIT(\n        REPEAT 6 {\n            CX 0 1 1 2 2 3\n        }\n    )CIRCUIT\"));\n    ASSERT_EQ(actual, PauliString<W>::from_str(\"+X___\"));\n\n    ASSERT_THROW(\n        {\n            PauliString<W>::from_str(\"+X___\").ref().before(Circuit(R\"CIRCUIT(\n            M(0.1) 0\n        )CIRCUIT\"));\n        },\n        std::invalid_argument);\n\n    ASSERT_THROW(\n        {\n            PauliString<W>::from_str(\"+X\").ref().before(Circuit(R\"CIRCUIT(\n            H 9\n        )CIRCUIT\"));\n        },\n        std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, after_tableau, {\n    auto actual =\n        PauliString<W>::from_str(\"+XZ_\").ref().after(GATE_DATA.at(\"CX\").tableau<W>(), std::vector<size_t>{0, 1, 1, 2});\n    ASSERT_EQ(actual, PauliString<W>::from_str(\"-YYX\"));\n\n    ASSERT_THROW(\n        {\n            PauliString<W>::from_str(\"+XZ_\").ref().after(GATE_DATA.at(\"CX\").tableau<W>(), std::vector<size_t>{0, 1, 1});\n        },\n        std::invalid_argument);\n\n    ASSERT_THROW(\n        { PauliString<W>::from_str(\"+XZ_\").ref().after(GATE_DATA.at(\"CX\").tableau<W>(), std::vector<size_t>{0, 5}); },\n        std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, before_tableau, {\n    auto actual =\n        PauliString<W>::from_str(\"-YYX\").ref().before(GATE_DATA.at(\"CX\").tableau<W>(), std::vector<size_t>{0, 1, 1, 2});\n    ASSERT_EQ(actual, PauliString<W>::from_str(\"+XZ_\"));\n\n    ASSERT_THROW(\n        {\n            PauliString<W>::from_str(\"+XZ_\").ref().before(\n                GATE_DATA.at(\"CX\").tableau<W>(), std::vector<size_t>{0, 1, 1});\n        },\n        std::invalid_argument);\n\n    ASSERT_THROW(\n        { PauliString<W>::from_str(\"+XZ_\").ref().before(GATE_DATA.at(\"CX\").tableau<W>(), std::vector<size_t>{0, 5}); },\n        std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, left_mul_pauli, {\n    PauliString<W> p(0);\n    bool imag = false;\n\n    p.left_mul_pauli(GateTarget::x(5), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"_____X\"));\n\n    p.left_mul_pauli(GateTarget::x(5), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"______\"));\n\n    p.left_mul_pauli(GateTarget::x(5), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"_____X\"));\n\n    p.left_mul_pauli(GateTarget::z(5), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"_____Y\"));\n\n    p.left_mul_pauli(GateTarget::z(5), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"_____X\"));\n\n    p.left_mul_pauli(GateTarget::y(5), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-_____Z\"));\n\n    p.left_mul_pauli(GateTarget::y(15), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-_____Z_________Y\"));\n\n    p.left_mul_pauli(GateTarget::y(15, true), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"_____Z__________\"));\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, left_mul_pauli_mul_table, {\n    PauliString<W> p(1);\n    bool imag = false;\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::x(0), &imag);\n    p.left_mul_pauli(GateTarget::y(0), &imag);\n    p.left_mul_pauli(GateTarget::z(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-I\"));\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::z(0), &imag);\n    p.left_mul_pauli(GateTarget::y(0), &imag);\n    p.left_mul_pauli(GateTarget::x(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"I\"));\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::x(0), &imag);\n    p.left_mul_pauli(GateTarget::x(0), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"I\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::x(0), &imag);\n    p.left_mul_pauli(GateTarget::y(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-Z\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::x(0), &imag);\n    p.left_mul_pauli(GateTarget::z(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"Y\"));\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::y(0), &imag);\n    p.left_mul_pauli(GateTarget::x(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"Z\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::y(0), &imag);\n    p.left_mul_pauli(GateTarget::y(0), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"I\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::y(0), &imag);\n    p.left_mul_pauli(GateTarget::z(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-X\"));\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::z(0), &imag);\n    p.left_mul_pauli(GateTarget::x(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-Y\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::z(0), &imag);\n    p.left_mul_pauli(GateTarget::y(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"X\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.left_mul_pauli(GateTarget::z(0), &imag);\n    p.left_mul_pauli(GateTarget::z(0), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"I\"));\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, right_mul_pauli_mul_table, {\n    PauliString<W> p(1);\n    bool imag = false;\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::x(0), &imag);\n    p.right_mul_pauli(GateTarget::y(0), &imag);\n    p.right_mul_pauli(GateTarget::z(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"+I\"));\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::z(0), &imag);\n    p.right_mul_pauli(GateTarget::y(0), &imag);\n    p.right_mul_pauli(GateTarget::x(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-I\"));\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::x(0), &imag);\n    p.right_mul_pauli(GateTarget::x(0), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"I\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::x(0), &imag);\n    p.right_mul_pauli(GateTarget::y(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"Z\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::x(0), &imag);\n    p.right_mul_pauli(GateTarget::z(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-Y\"));\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::y(0), &imag);\n    p.right_mul_pauli(GateTarget::x(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-Z\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::y(0), &imag);\n    p.right_mul_pauli(GateTarget::y(0), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"I\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::y(0), &imag);\n    p.right_mul_pauli(GateTarget::z(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"X\"));\n\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::z(0), &imag);\n    p.right_mul_pauli(GateTarget::x(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"Y\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::z(0), &imag);\n    p.right_mul_pauli(GateTarget::y(0), &imag);\n    ASSERT_EQ(imag, 1);\n    ASSERT_EQ(p, PauliString<W>(\"-X\"));\n    p = PauliString<W>(1);\n    imag = false;\n    p.right_mul_pauli(GateTarget::z(0), &imag);\n    p.right_mul_pauli(GateTarget::z(0), &imag);\n    ASSERT_EQ(imag, 0);\n    ASSERT_EQ(p, PauliString<W>(\"I\"));\n})\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_iter.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_STABILIZERS_PAULI_STRING_ITER_H\n#define _STIM_STABILIZERS_PAULI_STRING_ITER_H\n\n#include \"stim/mem/fixed_cap_vector.h\"\n#include \"stim/mem/span_ref.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\n/// Tracks the state of a loop.\nstruct NestedLooperLoop {\n    /// The first index that should be iterated.\n    uint64_t start;\n    /// One past the last index that should be iterated.\n    uint64_t end;\n    /// If this is set to the index of another loop, the starting offset is shifted by that other loop's value.\n    /// Set to UINT64_MAX to not use.\n    /// This is used in 'append_combination_loops' to avoid repeating combinations.\n    uint64_t offset_from_other = UINT64_MAX;\n    /// The current value of the iteration variable for this loop.\n    /// UINT64_MAX means 'loop is not started yet'.\n    uint64_t cur = UINT64_MAX;\n};\n\n/// A helper class for managing dynamically nested loops.\nstruct NestedLooper {\n    std::vector<NestedLooperLoop> loops;\n    uint64_t k = 0;\n\n    /// Adds a series of nested loops for iterating combinations of w values from [0, n).\n    inline void append_combination_loops(uint64_t n, uint64_t w) {\n        if (w > 0) {\n            loops.push_back(NestedLooperLoop{0, n - w + 1});\n            for (uint64_t j = 1; j < w; j++) {\n                auto v = loops.size() - 1;\n                loops.push_back(NestedLooperLoop{1, n - w + j + 1, v});\n            }\n        }\n    }\n\n    /// Clears all loop variables and sets the loop index to the outermost loop.\n    inline void start() {\n        k = 0;\n        for (auto &loop : loops) {\n            loop.cur = UINT64_MAX;\n        }\n    }\n\n    inline bool iter_next(const std::function<void(size_t)> &on_iter) {\n        if (loops.empty()) {\n            return false;\n        }\n\n        // k is the index of the loop to advance.\n        // In the first step, k will be 0.\n        // In later step, k is loops.size().\n        if (k == loops.size()) {\n            // Drop k by 1 to advance the innermost loop.\n            k--;\n        }\n\n        while (true) {\n            // Start or advance the current loop.\n            if (loops[k].cur == UINT64_MAX) {\n                loops[k].cur = loops[k].start;\n                if (loops[k].offset_from_other != UINT64_MAX) {\n                    loops[k].cur += loops[loops[k].offset_from_other].cur;\n                }\n            } else {\n                loops[k].cur++;\n            }\n\n            // Notify the caller so they can dynamically add inner loops if needed.\n            on_iter(k);\n\n            // Check if the current loop has ended.\n            if (loops[k].cur >= loops[k].end) {\n                if (k == 0) {\n                    // The outermost loop ended.\n                    return false;\n                }\n                loops[k].cur = UINT64_MAX;\n                k -= 1;\n                continue;\n            }\n\n            // Move down to the next loop.\n            k++;\n            if (k == loops.size()) {\n                // We're inside the innermost loop.\n                return true;\n            }\n        }\n    }\n};\n\n/// Iterates over pauli strings matching specified parameters.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstruct PauliStringIterator {\n    // Parameter storage.\n    size_t num_qubits;  /// Number of qubits in results.\n    size_t min_weight;  /// Minimum number of non-identity terms in results.\n    size_t max_weight;  /// Maximum number of non-identity terms in results.\n    bool allow_x;       /// Whether results are permitted to contain 'X' terms.\n    bool allow_y;       /// Whether results are permitted to contain 'Y' terms.\n    bool allow_z;       /// Whether results are permitted to contain 'Z' terms.\n\n    // Progress storage.\n    NestedLooper looper;    /// Tracks nested loops over target weight, the target qubits, and the target paulis.\n    PauliString<W> result;  /// When iter_next() returns true, the result is stored in this field.\n\n    PauliStringIterator(\n        size_t num_qubits, size_t min_weight, size_t max_weight, bool allow_x, bool allow_y, bool allow_z);\n\n    /// Updates the `result` field to point at the next yielded pauli string.\n    /// Returns true if this succeeded, or false if iteration has ended.\n    bool iter_next();\n\n    // Restarts iteration.\n    void restart();\n};\n\n}  // namespace stim\n\n#include \"stim/stabilizers/pauli_string_iter.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_iter.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/stabilizers/pauli_string_iter.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nPauliStringIterator<W>::PauliStringIterator(\n    size_t num_qubits, size_t min_weight, size_t max_weight, bool allow_x, bool allow_y, bool allow_z)\n    : num_qubits(num_qubits),\n      min_weight(min_weight),\n      max_weight(max_weight),\n      allow_x(allow_x),\n      allow_y(allow_y),\n      allow_z(allow_z),\n      result(num_qubits) {\n    restart();\n}\n\ntemplate <size_t W>\nbool PauliStringIterator<W>::iter_next() {\n    return looper.iter_next([&](size_t loop_index) {\n        const NestedLooperLoop &loop = looper.loops[loop_index];\n        if (loop_index == 0) {\n            // Reached a new weight. Need to iterate over xs.\n            looper.loops.resize(loop_index + 1);\n            looper.append_combination_loops(num_qubits, loop.cur);\n        } else if (loop_index == looper.loops[0].cur) {\n            // Reached a new weight mask. Need to iterate over X/Z values.\n            looper.loops.resize(loop_index + 1);\n            result.xs.clear();\n            result.zs.clear();\n            size_t pauli_weight = allow_x + allow_y + allow_z;\n            for (size_t j = 0; j < looper.loops[0].cur; j++) {\n                looper.loops.push_back(NestedLooperLoop{1, 1 + pauli_weight});\n            }\n        } else if (loop_index > looper.loops[0].cur) {\n            // Iterating a pauli. Keep the results up to date as the paulis change.\n            auto q = looper.loops[loop_index - looper.loops[0].cur].cur;\n            auto v = loop.cur;\n            v += !allow_x && v >= 1;\n            v += !allow_y && v >= 2;\n            v += !allow_z && v >= 3;\n            bool y = (v & 1) != 0;\n            bool z = (v & 2) != 0;\n            result.xs[q] = y ^ z;\n            result.zs[q] = z;\n        }\n    });\n}\n\ntemplate <size_t W>\nvoid PauliStringIterator<W>::restart() {\n    looper.loops.clear();\n    size_t clamped_max_weight = std::min(max_weight, num_qubits);\n    if (clamped_max_weight >= min_weight) {\n        looper.loops.push_back({min_weight, clamped_max_weight + 1, UINT64_MAX});\n    }\n    looper.start();\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_iter.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/pauli_string_iter.h\"\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(pauli_iter_xz_2_to_5_of_5) {\n    size_t c = 0;\n    size_t n = 0;\n    benchmark_go([&]() {\n        PauliStringIterator<MAX_BITWORD_WIDTH> iter(5, 2, 5, true, false, true);\n        n = 0;\n        while (iter.iter_next()) {\n            c += iter.result.num_qubits;\n            n += 1;\n        }\n    })\n        .goal_micros(8)\n        .show_rate(\"PauliStrings\", n);\n    if (c == 0) {\n        std::cerr << \"use the output\\n\";\n    }\n}\n\nBENCHMARK(pauli_iter_xyz_1_of_1000) {\n    size_t c = 0;\n    size_t n = 0;\n    benchmark_go([&]() {\n        PauliStringIterator<MAX_BITWORD_WIDTH> iter(1000, 1, 1, true, true, true);\n        n = 0;\n        while (iter.iter_next()) {\n            c += iter.result.num_qubits;\n            n += 1;\n        }\n    })\n        .goal_micros(55)\n        .show_rate(\"PauliStrings\", n);\n    if (c == 0) {\n        std::cerr << \"use the output\\n\";\n    }\n}\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_iter.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/pauli_string_iter.pybind.h\"\n\n#include \"pauli_string.pybind.h\"\n#include \"stim/py/base.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\npybind11::class_<PauliStringIterator<MAX_BITWORD_WIDTH>> stim_pybind::pybind_pauli_string_iter(pybind11::module &m) {\n    auto c = pybind11::class_<PauliStringIterator<MAX_BITWORD_WIDTH>>(\n        m,\n        \"PauliStringIterator\",\n        clean_doc_string(R\"DOC(\n            Iterates over all pauli strings matching specified patterns.\n\n            Examples:\n                >>> import stim\n                >>> pauli_string_iterator = stim.PauliString.iter_all(\n                ...     2,\n                ...     min_weight=1,\n                ...     max_weight=1,\n                ...     allowed_paulis=\"XZ\",\n                ... )\n                >>> for p in pauli_string_iterator:\n                ...     print(p)\n                +X_\n                +Z_\n                +_X\n                +_Z\n        )DOC\")\n            .data());\n    return c;\n}\n\nvoid stim_pybind::pybind_pauli_string_iter_methods(\n    pybind11::module &m, pybind11::class_<PauliStringIterator<MAX_BITWORD_WIDTH>> &c) {\n    c.def(\n        \"__iter__\",\n        [](PauliStringIterator<MAX_BITWORD_WIDTH> &self) -> PauliStringIterator<MAX_BITWORD_WIDTH> {\n            PauliStringIterator<MAX_BITWORD_WIDTH> copy = self;\n            return copy;\n        },\n        clean_doc_string(R\"DOC(\n            Returns an independent copy of the pauli string iterator.\n\n            Since for-loops and loop-comprehensions call `iter` on things they\n            iterate, this effectively allows the iterator to be iterated\n            multiple times.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__next__\",\n        [](PauliStringIterator<MAX_BITWORD_WIDTH> &self) -> FlexPauliString {\n            if (!self.iter_next()) {\n                throw pybind11::stop_iteration();\n            }\n            return FlexPauliString(self.result);\n        },\n        clean_doc_string(R\"DOC(\n            Returns the next iterated pauli string.\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_iter.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_STABILIZERS_PAULI_STRING_ITER_PYBIND_H\n#define _STIM_STABILIZERS_PAULI_STRING_ITER_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/stabilizers/pauli_string_iter.h\"\n\nnamespace stim_pybind {\npybind11::class_<stim::PauliStringIterator<stim::MAX_BITWORD_WIDTH>> pybind_pauli_string_iter(pybind11::module &m);\nvoid pybind_pauli_string_iter_methods(\n    pybind11::module &m, pybind11::class_<stim::PauliStringIterator<stim::MAX_BITWORD_WIDTH>> &c);\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_iter.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/pauli_string_iter.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n\nusing namespace stim;\n\nstd::vector<uint64_t> loop_state(const NestedLooper &looper) {\n    std::vector<uint64_t> state;\n    for (const auto &e : looper.loops) {\n        state.push_back(e.cur);\n    }\n    return state;\n}\n\nstd::vector<std::vector<uint64_t>> loop_drain(NestedLooper &looper) {\n    std::vector<std::vector<uint64_t>> state;\n    looper.start();\n    while (looper.iter_next([](size_t k) {\n    })) {\n        state.push_back(loop_state(looper));\n    }\n    return state;\n}\n\nTEST(pauli_string_iter, NestedLooper_simple) {\n    NestedLooper looper;\n    looper.loops.push_back(NestedLooperLoop{0, 3});\n    looper.loops.push_back(NestedLooperLoop{2, 6});\n\n    ASSERT_EQ(\n        loop_drain(looper),\n        (std::vector<std::vector<uint64_t>>{\n            {0, 2},\n            {0, 3},\n            {0, 4},\n            {0, 5},\n            {1, 2},\n            {1, 3},\n            {1, 4},\n            {1, 5},\n            {2, 2},\n            {2, 3},\n            {2, 4},\n            {2, 5},\n        }));\n}\n\nTEST(pauli_string_iter, NestedLooper_shifted) {\n    NestedLooper looper;\n    looper.loops.push_back(NestedLooperLoop{0, 3});\n    looper.loops.push_back(NestedLooperLoop{2, 6, 0});\n    ASSERT_EQ(\n        loop_drain(looper),\n        (std::vector<std::vector<uint64_t>>{\n            {0, 2},\n            {0, 3},\n            {0, 4},\n            {0, 5},\n            {1, 3},\n            {1, 4},\n            {1, 5},\n            {2, 4},\n            {2, 5},\n        }));\n}\n\nTEST(pauli_string_iter, NestedLooper_append_combination_loops) {\n    NestedLooper looper;\n    looper.append_combination_loops(6, 3);\n    ASSERT_EQ(\n        loop_drain(looper),\n        (std::vector<std::vector<uint64_t>>{\n            {0, 1, 2}, {0, 1, 3}, {0, 1, 4}, {0, 1, 5}, {0, 2, 3}, {0, 2, 4}, {0, 2, 5},\n            {0, 3, 4}, {0, 3, 5}, {0, 4, 5}, {1, 2, 3}, {1, 2, 4}, {1, 2, 5}, {1, 3, 4},\n            {1, 3, 5}, {1, 4, 5}, {2, 3, 4}, {2, 3, 5}, {2, 4, 5}, {3, 4, 5},\n        }));\n\n    looper.loops.clear();\n    looper.append_combination_loops(10, 9);\n    ASSERT_EQ(\n        loop_drain(looper),\n        (std::vector<std::vector<uint64_t>>{\n            {0, 1, 2, 3, 4, 5, 6, 7, 8},\n            {0, 1, 2, 3, 4, 5, 6, 7, 9},\n            {0, 1, 2, 3, 4, 5, 6, 8, 9},\n            {0, 1, 2, 3, 4, 5, 7, 8, 9},\n            {0, 1, 2, 3, 4, 6, 7, 8, 9},\n            {0, 1, 2, 3, 5, 6, 7, 8, 9},\n            {0, 1, 2, 4, 5, 6, 7, 8, 9},\n            {0, 1, 3, 4, 5, 6, 7, 8, 9},\n            {0, 2, 3, 4, 5, 6, 7, 8, 9},\n            {1, 2, 3, 4, 5, 6, 7, 8, 9},\n        }));\n}\n\nTEST(pauli_string_iter, NestedLooper_inplace_edit) {\n    NestedLooper looper;\n    looper.loops.push_back(NestedLooperLoop{1, 3});\n\n    std::vector<std::vector<uint64_t>> state;\n    looper.start();\n    while (looper.iter_next([&](size_t k) {\n        if (k == 0 && looper.loops[0].cur == 2) {\n            looper.loops.push_back(NestedLooperLoop{2, 4});\n        }\n    })) {\n        state.push_back(loop_state(looper));\n    }\n\n    ASSERT_EQ(\n        state,\n        (std::vector<std::vector<uint64_t>>{\n            {1},\n            {2, 2},\n            {2, 3},\n        }));\n}\n\ntemplate <size_t W>\nstd::vector<std::string> record_pauli_string(PauliStringIterator<W> iter) {\n    std::vector<std::string> results;\n    while (iter.iter_next()) {\n        results.push_back(iter.result.str());\n    }\n    return results;\n}\n\nTEST_EACH_WORD_SIZE_W(pauli_string_iter, small_cases, {\n    // Empty.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(3, 0, 0, true, true, true)),\n        (std::vector<std::string>{\n            \"+___\",\n        }));\n\n    // Empty or single.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 0, 1, true, true, true)),\n        (std::vector<std::string>{\n            \"+__\",\n            \"+X_\",\n            \"+Y_\",\n            \"+Z_\",\n            \"+_X\",\n            \"+_Y\",\n            \"+_Z\",\n        }));\n\n    // Single.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(3, 1, 1, true, true, true)),\n        (std::vector<std::string>{\n            \"+X__\",\n            \"+Y__\",\n            \"+Z__\",\n            \"+_X_\",\n            \"+_Y_\",\n            \"+_Z_\",\n            \"+__X\",\n            \"+__Y\",\n            \"+__Z\",\n        }));\n\n    // Full doubles.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 2, 2, true, true, true)),\n        (std::vector<std::string>{\n            \"+XX\",\n            \"+XY\",\n            \"+XZ\",\n            \"+YX\",\n            \"+YY\",\n            \"+YZ\",\n            \"+ZX\",\n            \"+ZY\",\n            \"+ZZ\",\n        }));\n\n    // All length 2.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 0, 2, true, true, true)),\n        (std::vector<std::string>{\n            \"+__\",\n            \"+X_\",\n            \"+Y_\",\n            \"+Z_\",\n            \"+_X\",\n            \"+_Y\",\n            \"+_Z\",\n            \"+XX\",\n            \"+XY\",\n            \"+XZ\",\n            \"+YX\",\n            \"+YY\",\n            \"+YZ\",\n            \"+ZX\",\n            \"+ZY\",\n            \"+ZZ\",\n        }));\n\n    // XY subset.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 0, 2, false, true, true)),\n        (std::vector<std::string>{\n            \"+__\",\n            \"+Y_\",\n            \"+Z_\",\n            \"+_Y\",\n            \"+_Z\",\n            \"+YY\",\n            \"+YZ\",\n            \"+ZY\",\n            \"+ZZ\",\n        }));\n    // XZ subset.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 0, 2, true, false, true)),\n        (std::vector<std::string>{\n            \"+__\",\n            \"+X_\",\n            \"+Z_\",\n            \"+_X\",\n            \"+_Z\",\n            \"+XX\",\n            \"+XZ\",\n            \"+ZX\",\n            \"+ZZ\",\n        }));\n    // YZ subset.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 0, 2, true, true, false)),\n        (std::vector<std::string>{\n            \"+__\",\n            \"+X_\",\n            \"+Y_\",\n            \"+_X\",\n            \"+_Y\",\n            \"+XX\",\n            \"+XY\",\n            \"+YX\",\n            \"+YY\",\n        }));\n\n    // X subset.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 0, 2, true, false, false)),\n        (std::vector<std::string>{\n            \"+__\",\n            \"+X_\",\n            \"+_X\",\n            \"+XX\",\n        }));\n    // Y subset.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 0, 2, false, true, false)),\n        (std::vector<std::string>{\n            \"+__\",\n            \"+Y_\",\n            \"+_Y\",\n            \"+YY\",\n        }));\n    // Z subset.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 0, 2, false, false, true)),\n        (std::vector<std::string>{\n            \"+__\",\n            \"+Z_\",\n            \"+_Z\",\n            \"+ZZ\",\n        }));\n\n    // No pauli subset.\n    ASSERT_EQ(\n        record_pauli_string(PauliStringIterator<W>(2, 0, 2, false, false, false)),\n        (std::vector<std::string>{\n            \"+__\",\n        }));\n    ASSERT_EQ(record_pauli_string(PauliStringIterator<W>(2, 1, 2, false, false, false)), (std::vector<std::string>{}));\n    ASSERT_EQ(record_pauli_string(PauliStringIterator<W>(2, 3, 6, false, false, false)), (std::vector<std::string>{}));\n    ASSERT_EQ(record_pauli_string(PauliStringIterator<W>(2, 2, 1, false, false, false)), (std::vector<std::string>{}));\n})\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport itertools\nimport numpy as np\nimport stim\nimport pytest\n\n\ndef test_identity():\n    p = stim.PauliString(3)\n    assert len(p) == 3\n    assert p[0] == p[1] == p[2] == 0\n    assert p.sign == +1\n\n\ndef test_from_str():\n    p = stim.PauliString(\"-_XYZ_ZYX\")\n    assert len(p) == 8\n    assert p[0] == 0\n    assert p[1] == 1\n    assert p[2] == 2\n    assert p[3] == 3\n    assert p[4] == 0\n    assert p[5] == 3\n    assert p[6] == 2\n    assert p[7] == 1\n    assert p.sign == -1\n\n    p = stim.PauliString(\"\")\n    assert len(p) == 0\n    assert p.sign == +1\n\n    p = stim.PauliString(\"X\")\n    assert len(p) == 1\n    assert p[0] == 1\n    assert p.sign == +1\n\n    p = stim.PauliString(\"+X\")\n    assert len(p) == 1\n    assert p[0] == 1\n    assert p.sign == +1\n\n    p = stim.PauliString(\"iX\")\n    assert len(p) == 1\n    assert p[0] == 1\n    assert p.sign == 1j\n\n    p = stim.PauliString(\"+iX\")\n    assert len(p) == 1\n    assert p[0] == 1\n    assert p.sign == 1j\n\n    p = stim.PauliString(\"-iX\")\n    assert len(p) == 1\n    assert p[0] == 1\n    assert p.sign == -1j\n\n    assert stim.PauliString(\"X5*Y10\") == stim.PauliString(\"_____X____Y\")\n    assert stim.PauliString(\"X5*Y5\") == stim.PauliString(\"iZ5\")\n\n\ndef test_equality():\n    assert not (stim.PauliString(4) == None)\n    assert not (stim.PauliString(4) == \"other object\")\n    assert not (stim.PauliString(4) == object())\n    assert stim.PauliString(4) != None\n    assert stim.PauliString(4) != \"other object\"\n    assert stim.PauliString(4) != object()\n\n    assert stim.PauliString(4) == stim.PauliString(4)\n    assert stim.PauliString(3) != stim.PauliString(4)\n    assert not (stim.PauliString(4) != stim.PauliString(4))\n    assert not (stim.PauliString(3) == stim.PauliString(4))\n\n    assert stim.PauliString(\"+X\") == stim.PauliString(\"+X\")\n    assert stim.PauliString(\"+X\") != stim.PauliString(\"-X\")\n    assert stim.PauliString(\"+X\") != stim.PauliString(\"+Y\")\n    assert stim.PauliString(\"+X\") != stim.PauliString(\"-Y\")\n    assert stim.PauliString(\"+X\") != stim.PauliString(\"+iX\")\n    assert stim.PauliString(\"+X\") != stim.PauliString(\"-iX\")\n\n    assert stim.PauliString(\"__\") != stim.PauliString(\"_X\")\n    assert stim.PauliString(\"__\") != stim.PauliString(\"X_\")\n    assert stim.PauliString(\"__\") != stim.PauliString(\"XX\")\n    assert stim.PauliString(\"__\") == stim.PauliString(\"__\")\n\n\ndef test_random():\n    p1 = stim.PauliString.random(100)\n    p2 = stim.PauliString.random(100)\n    assert p1 != p2\n\n    seen_signs = {stim.PauliString.random(1).sign for _ in range(200)}\n    assert seen_signs == {1, -1}\n\n    seen_signs = {stim.PauliString.random(1, allow_imaginary=True).sign for _ in range(200)}\n    assert seen_signs == {1, -1, 1j, -1j}\n\n\ndef test_str():\n    assert str(stim.PauliString(3)) == \"+___\"\n    assert str(stim.PauliString(\"XYZ\")) == \"+XYZ\"\n    assert str(stim.PauliString(\"-XYZ\")) == \"-XYZ\"\n    assert str(stim.PauliString(\"iXYZ\")) == \"+iXYZ\"\n    assert str(stim.PauliString(\"-iXYZ\")) == \"-iXYZ\"\n\n\ndef test_repr():\n    assert repr(stim.PauliString(3)) == 'stim.PauliString(\"+___\")'\n    assert repr(stim.PauliString(\"-XYZ\")) == 'stim.PauliString(\"-XYZ\")'\n    vs = [\n        stim.PauliString(\"\"),\n        stim.PauliString(\"ZXYZZ\"),\n        stim.PauliString(\"-XYZ\"),\n        stim.PauliString(\"I\"),\n        stim.PauliString(\"iIXYZ\"),\n        stim.PauliString(\"-iIXYZ\"),\n    ]\n    for v in vs:\n        r = repr(v)\n        assert eval(r, {'stim': stim}) == v\n\ndef test_to_tableau():\n    p = stim.PauliString(\"XZ_Y\")\n    t = p.to_tableau()\n    assert t.x_output(0) == stim.PauliString(\"+X___\")\n    assert t.x_output(1) == stim.PauliString(\"-_X__\")\n    assert t.x_output(2) == stim.PauliString(\"+__X_\")\n    assert t.x_output(3) == stim.PauliString(\"-___X\")\n    assert t.z_output(0) == stim.PauliString(\"-Z___\")\n    assert t.z_output(1) == stim.PauliString(\"+_Z__\")\n    assert t.z_output(2) == stim.PauliString(\"+__Z_\")\n    assert t.z_output(3) == stim.PauliString(\"-___Z\")\n\n    p_random = stim.PauliString.random(32)\n    p_random.sign = 1\n    p_random_roundtrip = p_random.to_tableau().to_pauli_string()\n    assert p_random == p_random_roundtrip\n\ndef test_commutes():\n    def c(a: str, b: str) -> bool:\n        return stim.PauliString(a).commutes(stim.PauliString(b))\n\n    assert c(\"\", \"\")\n    assert c(\"X\", \"_\")\n    assert c(\"X\", \"X\")\n    assert not c(\"X\", \"Y\")\n    assert not c(\"X\", \"Z\")\n\n    assert c(\"XXXX\", \"YYYY\")\n    assert c(\"XXXX\", \"YYYZ\")\n    assert not c(\"XXXX\", \"XXXZ\")\n    assert not c(\"XXXX\", \"___Z\")\n    assert not c(\"XXXX\", \"Z___\")\n    assert c(\"XXXX\", \"Z_Z_\")\n\n\ndef test_product():\n    assert stim.PauliString(\"\") * stim.PauliString(\"\") == stim.PauliString(\"\")\n    assert stim.PauliString(\"i\") * stim.PauliString(\"i\") == stim.PauliString(\"-\")\n    assert stim.PauliString(\"i\") * stim.PauliString(\"-i\") == stim.PauliString(\"+\")\n    assert stim.PauliString(\"-i\") * stim.PauliString(\"-i\") == stim.PauliString(\"-\")\n    assert stim.PauliString(\"i\") * stim.PauliString(\"-\") == stim.PauliString(\"-i\")\n\n    x = stim.PauliString(\"X\")\n    y = stim.PauliString(\"Y\")\n    z = stim.PauliString(\"Z\")\n\n    assert x == +1 * x == x * +1 == +x\n    assert x * -1 == -x == -1 * x\n    assert (-x)[0] == 1\n    assert (-x).sign == -1\n    assert -(-x) == x\n\n    assert stim.PauliString(10) * stim.PauliString(11) == stim.PauliString(11)\n\n    assert x * z == stim.PauliString(\"-iY\")\n    assert x * x == stim.PauliString(1)\n    assert x * y == stim.PauliString(\"iZ\")\n    assert y * x == stim.PauliString(\"-iZ\")\n    assert x * y == 1j * z\n    assert y * x == z * -1j\n    assert x.extended_product(y) == (1, 1j * z)\n    assert y.extended_product(x) == (1, -1j * z)\n    assert x.extended_product(x) == (1, stim.PauliString(1))\n\n    xx = stim.PauliString(\"+XX\")\n    yy = stim.PauliString(\"+YY\")\n    zz = stim.PauliString(\"+ZZ\")\n    assert xx * zz == -yy\n    assert xx.extended_product(zz) == (1, -yy)\n\n\ndef test_inplace_product():\n    p = stim.PauliString(\"X\")\n    alias = p\n\n    p *= 1j\n    assert alias == stim.PauliString(\"iX\")\n    assert alias is p\n    p *= 1j\n    assert alias == stim.PauliString(\"-X\")\n    p *= 1j\n    assert alias == stim.PauliString(\"-iX\")\n    p *= 1j\n    assert alias == stim.PauliString(\"+X\")\n\n    p *= stim.PauliString(\"Z\")\n    assert alias == stim.PauliString(\"-iY\")\n\n    p *= -1j\n    assert alias == stim.PauliString(\"-Y\")\n    p *= -1j\n    assert alias == stim.PauliString(\"iY\")\n    p *= -1j\n    assert alias == stim.PauliString(\"+Y\")\n    p *= -1j\n    assert alias == stim.PauliString(\"-iY\")\n\n    p *= stim.PauliString(\"i_\")\n    assert alias == stim.PauliString(\"+Y\")\n    p *= stim.PauliString(\"i_\")\n    assert alias == stim.PauliString(\"iY\")\n    p *= stim.PauliString(\"i_\")\n    assert alias == stim.PauliString(\"-Y\")\n    p *= stim.PauliString(\"i_\")\n    assert alias == stim.PauliString(\"-iY\")\n\n    p *= stim.PauliString(\"-i_\")\n    assert alias == stim.PauliString(\"-Y\")\n    p *= stim.PauliString(\"-i_\")\n    assert alias == stim.PauliString(\"iY\")\n    p *= stim.PauliString(\"-i_\")\n    assert alias == stim.PauliString(\"+Y\")\n    p *= stim.PauliString(\"-i_\")\n    assert alias == stim.PauliString(\"-iY\")\n\n    assert alias is p\n\n\ndef test_imaginary_phase():\n    p = stim.PauliString(\"IXYZ\")\n    ip = stim.PauliString(\"iIXYZ\")\n    assert 1j * p == p * 1j == ip == -stim.PauliString(\"-iIXYZ\")\n    assert p.sign == 1\n    assert (-p).sign == -1\n    assert ip.sign == 1j\n    assert (-ip).sign == -1j\n    assert stim.PauliString(\"X\") * stim.PauliString(\"Y\") == 1j * stim.PauliString(\"Z\")\n    assert stim.PauliString(\"Y\") * stim.PauliString(\"X\") == -1j * stim.PauliString(\"Z\")\n\n\ndef test_get_set_sign():\n    p = stim.PauliString(2)\n    assert p.sign == +1\n    p.sign = -1\n    assert str(p) == \"-__\"\n    assert p.sign == -1\n    p.sign = +1\n    assert str(p) == \"+__\"\n    assert p.sign == +1\n    with pytest.raises(ValueError, match=\"new_sign\"):\n        p.sign = 5\n\n    p.sign = 1j\n    assert str(p) == \"+i__\"\n    assert p.sign == 1j\n\n    p.sign = -1j\n    assert str(p) == \"-i__\"\n    assert p.sign == -1j\n\n\ndef test_get_set_item():\n    p = stim.PauliString(5)\n    assert list(p) == [0, 0, 0, 0, 0]\n    assert p[0] == 0\n    p[0] = 1\n    assert p[0] == 1\n    p[0] = 'Y'\n    assert p[0] == 2\n    p[0] = 'Z'\n    assert p[0] == 3\n\n    with pytest.raises(IndexError, match=\"new_pauli\"):\n        p[0] = 't'\n    with pytest.raises(IndexError, match=\"new_pauli\"):\n        p[0] = 10\n\n    assert p[1] == 0\n    p[1] = 2\n    assert p[1] == 2\n\n\ndef test_get_slice():\n    p = stim.PauliString(\"XXXX__YYYY__ZZZZX\")\n    assert p[:7] == stim.PauliString(\"XXXX__Y\")\n    assert p[:-3] == stim.PauliString(\"XXXX__YYYY__ZZ\")\n    assert p[::2] == stim.PauliString(\"XX_YY_ZZX\")\n    assert p[::-1] == stim.PauliString(\"XZZZZ__YYYY__XXXX\")\n    assert p[-3:3] == stim.PauliString(\"\")\n    assert p[-6:-1] == stim.PauliString(\"_ZZZZ\")\n    assert p[3:5:-1] == stim.PauliString(\"\")\n    assert p[5:3:-1] == stim.PauliString(\"__\")\n    assert p[4:2:-1] == stim.PauliString(\"_X\")\n    assert p[2:0:-1] == stim.PauliString(\"XX\")\n\n\ndef test_copy():\n    p = stim.PauliString(3)\n    p2 = p.copy()\n    assert p == p2\n    assert p is not p2\n\n    p = stim.PauliString(\"-i_XYZ\")\n    p2 = p.copy()\n    assert p == p2\n    assert p is not p2\n\n\ndef test_hash():\n    # stim.PauliString is mutable. It must not also be value-hashable.\n    # Defining __hash__ requires defining a FrozenPauliString variant instead.\n    with pytest.raises(TypeError, match=\"unhashable\"):\n        _ = hash(stim.PauliString(1))\n\n\ndef test_add():\n    ps = stim.PauliString\n    assert ps(0) + ps(0) == ps(0)\n    assert ps(3) + ps(1000) == ps(1003)\n    assert ps(1000) + ps(3) == ps(1003)\n    assert ps(\"_XYZ\") + ps(\"_ZZZ_\") == ps(\"_XYZ_ZZZ_\")\n\n    p = ps(\"_XYZ\")\n    p += p\n    assert p == ps(\"_XYZ_XYZ\")\n    for k in range(1, 8):\n        p += p\n        assert p == ps(\"_XYZ_XYZ\" * 2**k)\n\n    p = ps(\"_XXX\")\n    p += ps(\"Y\")\n    assert p == ps(\"_XXXY\")\n\n    p = ps(\"\")\n    alias = p\n    p += ps(\"X\")\n    assert alias is p\n    assert alias == ps(\"X\")\n    p += p\n    assert alias is p\n    assert alias == ps(\"XX\")\n\n\ndef test_mul_different_sizes():\n    ps = stim.PauliString\n    assert ps(\"\") * ps(\"X\" * 1000) == ps(\"X\" * 1000)\n    assert ps(\"X\" * 1000) * ps(\"\") == ps(\"X\" * 1000)\n    assert ps(\"Z\" * 1000) * ps(\"\") == ps(\"Z\" * 1000)\n\n    p = ps(\"Z\")\n    alias = p\n    p *= ps(\"ZZZ\")\n    assert p == ps(\"_ZZ\")\n    p *= ps(\"Z\")\n    assert p == ps(\"ZZZ\")\n    assert alias is p\n\n\ndef test_div():\n    assert stim.PauliString(\"+XYZ\") / +1 == stim.PauliString(\"+XYZ\")\n    assert stim.PauliString(\"+XYZ\") / -1 == stim.PauliString(\"-XYZ\")\n    assert stim.PauliString(\"+XYZ\") / 1j == stim.PauliString(\"-iXYZ\")\n    assert stim.PauliString(\"+XYZ\") / -1j == stim.PauliString(\"iXYZ\")\n    assert stim.PauliString(\"iXYZ\") / 1j == stim.PauliString(\"XYZ\")\n    p = stim.PauliString(\"__\")\n    alias = p\n    assert p / -1 == stim.PauliString(\"-__\")\n    assert alias == stim.PauliString(\"__\")\n    p /= -1\n    assert alias == stim.PauliString(\"-__\")\n    p /= 1j\n    assert alias == stim.PauliString(\"i__\")\n    p /= 1j\n    assert alias == stim.PauliString(\"__\")\n    p /= -1j\n    assert alias == stim.PauliString(\"i__\")\n    p /= 1\n    assert alias == stim.PauliString(\"i__\")\n\n\ndef test_mul_repeat():\n    ps = stim.PauliString\n    assert ps(\"\") * 100 == ps(\"\")\n    assert ps(\"X\") * 100 == ps(\"X\" * 100)\n    assert ps(\"XYZ_\") * 1000 == ps(\"XYZ_\" * 1000)\n    assert ps(\"XYZ_\") * 1 == ps(\"XYZ_\")\n    assert ps(\"XYZ_\") * 0 == ps(\"\")\n\n    assert 100 * ps(\"\") == ps(\"\")\n    assert 100 * ps(\"X\") == ps(\"X\" * 100)\n    assert 1000 * ps(\"XYZ_\") == ps(\"XYZ_\" * 1000)\n    assert 1 * ps(\"XYZ_\") == ps(\"XYZ_\")\n    assert 0 * ps(\"XYZ_\") == ps(\"\")\n\n    assert ps(\"i\") * 0 == ps(\"+\")\n    assert ps(\"i\") * 1 == ps(\"i\")\n    assert ps(\"i\") * 2 == ps(\"-\")\n    assert ps(\"i\") * 3 == ps(\"-i\")\n    assert ps(\"i\") * 4 == ps(\"+\")\n    assert ps(\"i\") * 5 == ps(\"i\")\n\n    assert ps(\"-i\") * 0 == ps(\"+\")\n    assert ps(\"-i\") * 1 == ps(\"-i\")\n    assert ps(\"-i\") * 2 == ps(\"-\")\n    assert ps(\"-i\") * 3 == ps(\"i\")\n    assert ps(\"-i\") * 4 == ps(\"+\")\n    assert ps(\"-i\") * 5 == ps(\"-i\")\n\n    assert ps(\"-\") * 0 == ps(\"+\")\n    assert ps(\"-\") * 1 == ps(\"-\")\n    assert ps(\"-\") * 2 == ps(\"+\")\n    assert ps(\"-\") * 3 == ps(\"-\")\n    assert ps(\"-\") * 4 == ps(\"+\")\n    assert ps(\"-\") * 5 == ps(\"-\")\n\n    p = ps(\"XYZ\")\n    alias = p\n    p *= 1000\n    assert p == ps(\"XYZ\" * 1000)\n    assert alias is p\n\n\ndef test_init_list():\n    assert stim.PauliString([]) == stim.PauliString(0)\n    assert stim.PauliString([0, 1, 2, 3]) == stim.PauliString(\"_XYZ\")\n\n    with pytest.raises(ValueError, match=\"pauli\"):\n        _ = stim.PauliString([-1])\n    with pytest.raises(ValueError, match=\"pauli\"):\n        _ = stim.PauliString([4])\n    with pytest.raises(ValueError):\n        _ = stim.PauliString([2**500])\n\n\ndef test_init_copy():\n    p = stim.PauliString(\"_XYZ\")\n    p2 = stim.PauliString(p)\n    assert p is not p2\n    assert p == p2\n\n    p = stim.PauliString(\"-i_XYZ\")\n    p2 = stim.PauliString(p)\n    assert p is not p2\n    assert p == p2\n\n\ndef test_commutes_different_lengths():\n    x1000 = stim.PauliString(\"X\" * 1000)\n    z1000 = stim.PauliString(\"Z\" * 1000)\n    x1 = stim.PauliString(\"X\")\n    z1 = stim.PauliString(\"Z\")\n    assert x1.commutes(x1000)\n    assert x1000.commutes(x1)\n    assert z1.commutes(z1000)\n    assert z1000.commutes(z1)\n    assert not z1.commutes(x1000)\n    assert not x1000.commutes(z1)\n    assert not x1.commutes(z1000)\n    assert not z1000.commutes(x1)\n\n\ndef test_pickle():\n    import pickle\n\n    t = stim.PauliString.random(4)\n    a = pickle.dumps(t)\n    assert pickle.loads(a) == t\n\n    t = stim.PauliString(\"i_XYZ\")\n    a = pickle.dumps(t)\n    assert pickle.loads(a) == t\n\n\ndef test_to_numpy():\n    p = stim.PauliString(\"_XYZ___XYXZYZ\")\n\n    xs, zs = p.to_numpy()\n    assert xs.dtype == np.bool_\n    assert zs.dtype == np.bool_\n    np.testing.assert_array_equal(xs, [0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0])\n    np.testing.assert_array_equal(zs, [0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1])\n\n    xs, zs = p.to_numpy(bit_packed=True)\n    assert xs.dtype == np.uint8\n    assert zs.dtype == np.uint8\n    np.testing.assert_array_equal(xs, [0x86, 0x0B])\n    np.testing.assert_array_equal(zs, [0x0C, 0x1D])\n\n\ndef test_from_numpy():\n    p = stim.PauliString.from_numpy(\n        xs=np.array([0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0], dtype=np.bool_),\n        zs=np.array([0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1], dtype=np.bool_))\n    assert p == stim.PauliString(\"_XYZ___XYXZYZ\")\n\n    p = stim.PauliString.from_numpy(\n        xs=np.array([0x86, 0x0B], dtype=np.uint8),\n        zs=np.array([0x0C, 0x1D], dtype=np.uint8),\n        num_qubits=13)\n\n    assert p == stim.PauliString(\"_XYZ___XYXZYZ\")\n    p = stim.PauliString.from_numpy(\n        xs=np.array([0x86, 0x0B], dtype=np.uint8),\n        zs=np.array([0x0C, 0x1D], dtype=np.uint8),\n        num_qubits=15,\n        sign=1j)\n    assert p == stim.PauliString(\"i_XYZ___XYXZYZ__\")\n\n\ndef test_from_numpy_bad_bit_packed_len():\n    xs = np.array([0x86, 0x0B], dtype=np.uint8)\n    zs = np.array([0x0C, 0x1D], dtype=np.uint8)\n    with pytest.raises(ValueError, match=\"specify expected number\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs)\n\n    with pytest.raises(ValueError, match=\"between 9 and 16 bits\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=100)\n\n    with pytest.raises(ValueError, match=\"between 9 and 16 bits\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=0)\n\n    with pytest.raises(ValueError, match=\"between 9 and 16 bits\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=8)\n\n    with pytest.raises(ValueError, match=\"between 9 and 16 bits\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=17)\n\n    with pytest.raises(ValueError, match=\"between 0 and 0 bits\"):\n        stim.PauliString.from_numpy(xs=xs[:0], zs=zs, num_qubits=9)\n\n    with pytest.raises(ValueError, match=\"between 1 and 8 bits\"):\n        stim.PauliString.from_numpy(xs=xs[:1], zs=zs, num_qubits=9)\n\n    with pytest.raises(ValueError, match=\"between 1 and 8 bits\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs[:1], num_qubits=9)\n\n    with pytest.raises(ValueError, match=\"1-dimensional\"):\n        stim.PauliString.from_numpy(xs=np.array([xs, xs]), zs=np.array([zs, zs]), num_qubits=9)\n\n    with pytest.raises(ValueError, match=\"uint8\"):\n        stim.PauliString.from_numpy(xs=np.array(xs, dtype=np.uint64), zs=np.array(xs, dtype=np.uint64), num_qubits=9)\n\n\ndef test_from_numpy_bad_bool_len():\n    xs = np.array([0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0], dtype=np.bool_)\n    zs = np.array([0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0], dtype=np.bool_)\n    with pytest.raises(ValueError, match=\"shape=13\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=12)\n\n    with pytest.raises(ValueError, match=\"shape=13\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=14)\n\n    with pytest.raises(ValueError, match=\"shape=12\"):\n        stim.PauliString.from_numpy(xs=xs[:-1], zs=zs, num_qubits=13)\n\n    with pytest.raises(ValueError, match=\"shape=12\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs[:-1], num_qubits=13)\n\n    with pytest.raises(ValueError, match=\"Inconsistent\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs[:-1])\n\n    with pytest.raises(RuntimeError, match=\"Unable to cast\"):\n        stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=-1)\n\n\n@pytest.mark.parametrize(\"n\", [0, 1, 41, 42, 1023, 1024, 1025])\ndef test_to_from_numpy_round_trip(n: int):\n    p = stim.PauliString.random(n)\n    xs, zs = p.to_numpy()\n    p2 = stim.PauliString.from_numpy(xs=xs, zs=zs, sign=p.sign)\n    assert p2 == p\n    xs, zs = p.to_numpy(bit_packed=True)\n    p2 = stim.PauliString.from_numpy(xs=xs, zs=zs, num_qubits=n, sign=p.sign)\n    assert p2 == p\n\n\ndef test_to_unitary_matrix():\n    np.testing.assert_array_equal(\n        stim.PauliString(\"\").to_unitary_matrix(endian=\"little\"),\n        [[1]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"-\").to_unitary_matrix(endian=\"big\"),\n        [[-1]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"i\").to_unitary_matrix(endian=\"big\"),\n        [[1j]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"-i\").to_unitary_matrix(endian=\"big\"),\n        [[-1j]],\n    )\n\n    np.testing.assert_array_equal(\n        stim.PauliString(\"I\").to_unitary_matrix(endian=\"little\"),\n        [[1, 0], [0, 1]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"X\").to_unitary_matrix(endian=\"little\"),\n        [[0, 1], [1, 0]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"Y\").to_unitary_matrix(endian=\"little\"),\n        [[0, -1j], [1j, 0]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"iY\").to_unitary_matrix(endian=\"little\"),\n        [[0, 1], [-1, 0]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"Z\").to_unitary_matrix(endian=\"little\"),\n        [[1, 0], [0, -1]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"-Z\").to_unitary_matrix(endian=\"little\"),\n        [[-1, 0], [0, 1]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"YY\").to_unitary_matrix(endian=\"little\"),\n        [[0, 0, 0, -1], [0, 0, 1, 0], [0, 1, 0, 0], [-1, 0, 0, 0]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"-YZ\").to_unitary_matrix(endian=\"little\"),\n        [[0, 1j, 0, 0], [-1j, 0, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0]],\n    )\n    np.testing.assert_array_equal(\n        stim.PauliString(\"XYZ\").to_unitary_matrix(endian=\"little\"), [\n            [0, 0, 0, -1j, 0, 0, 0, 0],\n            [0, 0, -1j, 0, 0, 0, 0, 0],\n            [0, 1j, 0, 0, 0, 0, 0, 0],\n            [1j, 0, 0, 0, 0, 0, 0, 0],\n            [0, 0, 0, 0, 0, 0, 0, 1j],\n            [0, 0, 0, 0, 0, 0, 1j, 0],\n            [0, 0, 0, 0, 0, -1j, 0, 0],\n            [0, 0, 0, 0, -1j, 0, 0, 0],\n        ])\n    np.testing.assert_array_equal(\n        stim.PauliString(\"ZYX\").to_unitary_matrix(endian=\"big\"), [\n            [0, 0, 0, -1j, 0, 0, 0, 0],\n            [0, 0, -1j, 0, 0, 0, 0, 0],\n            [0, 1j, 0, 0, 0, 0, 0, 0],\n            [1j, 0, 0, 0, 0, 0, 0, 0],\n            [0, 0, 0, 0, 0, 0, 0, 1j],\n            [0, 0, 0, 0, 0, 0, 1j, 0],\n            [0, 0, 0, 0, 0, -1j, 0, 0],\n            [0, 0, 0, 0, -1j, 0, 0, 0],\n        ])\n\n\ndef test_from_unitary_matrix():\n    assert stim.PauliString.from_unitary_matrix(\n        [[1]]\n    ) == stim.PauliString(\"\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[-1]]\n    ) == stim.PauliString(\"-\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[1j]]\n    ) == stim.PauliString(\"i\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[-1j]]\n    ) == stim.PauliString(\"-i\")\n\n    assert stim.PauliString.from_unitary_matrix(\n        [[1, 0], [0, 1]]\n    ) == stim.PauliString(\"I\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[0, 1], [1, 0]]\n    ) == stim.PauliString(\"X\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[0, -1j], [1j, 0]]\n    ) == stim.PauliString(\"Y\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[1, 0], [0, -1]]\n    ) == stim.PauliString(\"Z\")\n\n    assert stim.PauliString.from_unitary_matrix(\n        [[0, 1], [-1, 0]]\n    ) == stim.PauliString(\"iY\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[0, 1j], [-1j, 0]]\n    ) == stim.PauliString(\"-Y\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[1j, 0], [0, -1j]]\n    ) == stim.PauliString(\"iZ\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[-1, 0], [0, 1]]\n    ) == stim.PauliString(\"-Z\")\n\n    assert stim.PauliString.from_unitary_matrix(\n        [[1]], unsigned=True\n    ) == stim.PauliString(\"\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[-1]], unsigned=True\n    ) == stim.PauliString(\"\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[0, 1], [-1, 0]], unsigned=True\n    ) == stim.PauliString(\"Y\")\n    assert stim.PauliString.from_unitary_matrix(\n        [[0, +1 * 1j**0.1], [-1 * 1j**0.1, 0]], unsigned=True\n    ) == stim.PauliString(\"Y\")\n\n    assert stim.PauliString.from_unitary_matrix([\n        [0, 0, 0, -1j, 0, 0, 0, 0],\n        [0, 0, -1j, 0, 0, 0, 0, 0],\n        [0, 1j, 0, 0, 0, 0, 0, 0],\n        [1j, 0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0, 1j],\n        [0, 0, 0, 0, 0, 0, 1j, 0],\n        [0, 0, 0, 0, 0, -1j, 0, 0],\n        [0, 0, 0, 0, -1j, 0, 0, 0],\n    ], endian=\"little\") == stim.PauliString(\"XYZ\")\n    assert stim.PauliString.from_unitary_matrix([\n        [0, 0, 0, -1j, 0, 0, 0, 0],\n        [0, 0, -1j, 0, 0, 0, 0, 0],\n        [0, 1j, 0, 0, 0, 0, 0, 0],\n        [1j, 0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0, 1j],\n        [0, 0, 0, 0, 0, 0, 1j, 0],\n        [0, 0, 0, 0, 0, -1j, 0, 0],\n        [0, 0, 0, 0, -1j, 0, 0, 0],\n    ], endian=\"big\") == stim.PauliString(\"ZYX\")\n    assert stim.PauliString.from_unitary_matrix(np.array([\n        [0, 0, 0, -1j, 0, 0, 0, 0],\n        [0, 0, -1j, 0, 0, 0, 0, 0],\n        [0, 1j, 0, 0, 0, 0, 0, 0],\n        [1j, 0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0, 1j],\n        [0, 0, 0, 0, 0, 0, 1j, 0],\n        [0, 0, 0, 0, 0, -1j, 0, 0],\n        [0, 0, 0, 0, -1j, 0, 0, 0],\n    ]) * 1j**0.1, endian=\"big\", unsigned=True) == stim.PauliString(\"ZYX\")\n    assert stim.PauliString.from_unitary_matrix(np.array([\n        [0, 0, 0, -1j, 0, 0, 0, 0],\n        [0, 0, -1j, 0, 0, 0, 0, 0],\n        [0, 1j, 0, 0, 0, 0, 0, 0],\n        [1j, 0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0, 1j],\n        [0, 0, 0, 0, 0, 0, 1j, 0],\n        [0, 0, 0, 0, 0, -1j, 0, 0],\n        [0, 0, 0, 0, -1j, 0, 0, 0],\n    ]) * -1, endian=\"big\", unsigned=True) == stim.PauliString(\"ZYX\")\n\n\ndef test_from_unitary_matrix_detect_bad_matrix():\n    with pytest.raises(ValueError, match=\"power of 2\"):\n        stim.PauliString.from_unitary_matrix([])\n    with pytest.raises(ValueError, match=\"row with no non-zero\"):\n        stim.PauliString.from_unitary_matrix([[]])\n    with pytest.raises(ValueError, match=\"row with no non-zero\"):\n        stim.PauliString.from_unitary_matrix([[0]])\n    with pytest.raises(ValueError, match=\"values besides 0, 1,\"):\n        stim.PauliString.from_unitary_matrix([[0.5]])\n    with pytest.raises(ValueError, match=\"isn't square\"):\n        stim.PauliString.from_unitary_matrix([[1, 0]])\n    with pytest.raises(ValueError, match=\"no non-zero entries\"):\n        stim.PauliString.from_unitary_matrix([[1], [0]])\n    with pytest.raises(ValueError, match=\"different lengths\"):\n        stim.PauliString.from_unitary_matrix([[0, 1], [1]])\n    with pytest.raises(ValueError, match=\"two non-zero entries\"):\n        stim.PauliString.from_unitary_matrix([[1, 1],\n                                              [0, 1]])\n    with pytest.raises(ValueError, match=\"which qubits are flipped\"):\n        stim.PauliString.from_unitary_matrix([[1, 0],\n                                              [1, 0]])\n    with pytest.raises(ValueError, match=\"isn't square\"):\n        stim.PauliString.from_unitary_matrix([[1, 0, 0],\n                                              [0, 1, 0]])\n    with pytest.raises(ValueError, match=\"consistent phase flips\"):\n        stim.PauliString.from_unitary_matrix([[1, 0],\n                                              [0, 1j]])\n\n    with pytest.raises(ValueError, match=\"power of 2\"):\n        stim.PauliString.from_unitary_matrix([[1, 0, 0],\n                                              [0, 1, 0],\n                                              [0, 0, 1]])\n    with pytest.raises(ValueError, match=\"which qubits are flipped\"):\n        stim.PauliString.from_unitary_matrix([[1, 0, 0, 0],\n                                              [0, 1, 0, 0],\n                                              [0, 0, 0, 1],\n                                              [0, 0, 1, 0]])\n    with pytest.raises(ValueError, match=\"consistent phase flips\"):\n        stim.PauliString.from_unitary_matrix([[1, 0, 0, 0],\n                                              [0, 1, 0, 0],\n                                              [0, 0, 1, 0],\n                                              [0, 0, 0, -1]])\n    with pytest.raises(ValueError, match=\"consistent phase flips\"):\n        stim.PauliString.from_unitary_matrix([[1, 0, 0, 0],\n                                              [0, 1, 0, 0],\n                                              [0, 0, -1, 0],\n                                              [0, 0, 0, 1]])\n\n\n@pytest.mark.parametrize(\"n,endian\", itertools.product(range(8), ['little', 'big']))\ndef test_fuzz_to_from_unitary_matrix(n: int, endian: str):\n    p = stim.PauliString.random(n, allow_imaginary=True)\n    u = p.to_unitary_matrix(endian=endian)\n    r = stim.PauliString.from_unitary_matrix(u, endian=endian)\n    assert p == r\n\n    via_tableau = stim.Tableau.from_unitary_matrix(u, endian=endian).to_pauli_string()\n    r.sign = +1\n    assert via_tableau == r\n\n\ndef test_before_after():\n    before = stim.PauliString(\"XXXYYYZZZ\")\n    after = stim.PauliString(\"XYXYZYXZZ\")\n    assert before.after(stim.Circuit(\"C_XYZ 1 4 6\")) == after\n    assert before.after(stim.Circuit(\"C_XYZ 1 4 6\")[0]) == after\n    assert before.after(stim.Tableau.from_named_gate(\"C_XYZ\"), targets=[1, 4, 6]) == after\n    assert after.before(stim.Circuit(\"C_XYZ 1 4 6\")) == before\n    assert after.before(stim.Circuit(\"C_XYZ 1 4 6\")[0]) == before\n    assert after.before(stim.Tableau.from_named_gate(\"C_XYZ\"), targets=[1, 4, 6]) == before\n\n\ndef test_iter_small():\n    assert list(stim.PauliString.iter_all(0)) == [stim.PauliString(0)]\n    assert list(stim.PauliString.iter_all(1)) == [\n        stim.PauliString(\"_\"),\n        stim.PauliString(\"X\"),\n        stim.PauliString(\"Y\"),\n        stim.PauliString(\"Z\"),\n    ]\n    assert list(stim.PauliString.iter_all(1, max_weight=-1)) == [\n    ]\n    assert list(stim.PauliString.iter_all(1, max_weight=0)) == [\n        stim.PauliString(\"_\"),\n    ]\n    assert list(stim.PauliString.iter_all(1, max_weight=1)) == [\n        stim.PauliString(\"_\"),\n        stim.PauliString(\"X\"),\n        stim.PauliString(\"Y\"),\n        stim.PauliString(\"Z\"),\n    ]\n    assert list(stim.PauliString.iter_all(1, min_weight=1, max_weight=1)) == [\n        stim.PauliString(\"X\"),\n        stim.PauliString(\"Y\"),\n        stim.PauliString(\"Z\"),\n    ]\n    assert list(stim.PauliString.iter_all(2, min_weight=1, max_weight=1, allowed_paulis=\"XY\")) == [\n        stim.PauliString(\"X_\"),\n        stim.PauliString(\"Y_\"),\n        stim.PauliString(\"_X\"),\n        stim.PauliString(\"_Y\"),\n    ]\n\n    with pytest.raises(ValueError, match=\"characters other than\"):\n        stim.PauliString.iter_all(2, allowed_paulis=\"A\")\n\n\ndef test_iter_reusable():\n    v = stim.PauliString.iter_all(2)\n    vs1 = list(v)\n    vs2 = list(v)\n    assert vs1 == vs2\n    assert len(vs1) == 4**2\n\n\ndef test_backwards_compatibility_init():\n    assert stim.PauliString() == stim.PauliString(\"+\")\n    assert stim.PauliString(5) == stim.PauliString(\"+_____\")\n    assert stim.PauliString([1, 2, 3]) == stim.PauliString(\"+XYZ\")\n    assert stim.PauliString(\"XYZ\") == stim.PauliString(\"+XYZ\")\n    assert stim.PauliString(stim.PauliString(\"XYZ\")) == stim.PauliString(\"+XYZ\")\n    assert stim.PauliString(\"X\" for _ in range(4)) == stim.PauliString(\"+XXXX\")\n\n    # These keywords have been removed from the documentation and the .pyi, but\n    # their functionality needs to be maintained for backwards compatibility.\n    # noinspection PyArgumentList\n    assert stim.PauliString(num_qubits=5) == stim.PauliString(\"+_____\")\n    # noinspection PyArgumentList\n    assert stim.PauliString(pauli_indices=[1, 2, 3]) == stim.PauliString(\"+XYZ\")\n    # noinspection PyArgumentList\n    assert stim.PauliString(text=\"XYZ\") == stim.PauliString(\"+XYZ\")\n    # noinspection PyArgumentList\n    assert stim.PauliString(other=stim.PauliString(\"XYZ\")) == stim.PauliString(\"+XYZ\")\n\n\ndef test_pauli_indices():\n    assert stim.PauliString().pauli_indices() == []\n    assert stim.PauliString().pauli_indices(\"X\") == []\n    assert stim.PauliString().pauli_indices(\"I\") == []\n    assert stim.PauliString(5).pauli_indices() == []\n    assert stim.PauliString(5).pauli_indices(\"X\") == []\n    assert stim.PauliString(5).pauli_indices(\"I\") == [0, 1, 2, 3, 4]\n    assert stim.PauliString(\"X1000\").pauli_indices() == [1000]\n    assert stim.PauliString(\"Y1000\").pauli_indices() == [1000]\n    assert stim.PauliString(\"Z1000\").pauli_indices() == [1000]\n    assert stim.PauliString(\"X1000\").pauli_indices(\"YZ\") == []\n    assert stim.PauliString(\"Y1000\").pauli_indices(\"XZ\") == []\n    assert stim.PauliString(\"Z1000\").pauli_indices(\"XY\") == []\n    assert stim.PauliString(\"X1000\").pauli_indices(\"X\") == [1000]\n    assert stim.PauliString(\"Y1000\").pauli_indices(\"Y\") == [1000]\n    assert stim.PauliString(\"Z1000\").pauli_indices(\"Z\") == [1000]\n\n    assert stim.PauliString(\"_XYZ\").pauli_indices(\"x\") == [1]\n    assert stim.PauliString(\"_XYZ\").pauli_indices(\"X\") == [1]\n    assert stim.PauliString(\"_XYZ\").pauli_indices(\"y\") == [2]\n    assert stim.PauliString(\"_XYZ\").pauli_indices(\"Y\") == [2]\n    assert stim.PauliString(\"_XYZ\").pauli_indices(\"z\") == [3]\n    assert stim.PauliString(\"_XYZ\").pauli_indices(\"Z\") == [3]\n    assert stim.PauliString(\"_XYZ\").pauli_indices(\"I\") == [0]\n    assert stim.PauliString(\"_XYZ\").pauli_indices(\"_\") == [0]\n    with pytest.raises(ValueError, match=\"Invalid character\"):\n        assert stim.PauliString(\"_XYZ\").pauli_indices(\"k\")\n\n\ndef test_before_reset():\n    assert stim.PauliString(\"Z\").before(stim.Circuit(\"R 0\")) == stim.PauliString(\"_\")\n    assert stim.PauliString(\"Z\").before(stim.Circuit(\"MR 0\")) == stim.PauliString(\"_\")\n    assert stim.PauliString(\"Z\").before(stim.Circuit(\"M 0\")) == stim.PauliString(\"Z\")\n\n    assert stim.PauliString(\"X\").before(stim.Circuit(\"RX 0\")) == stim.PauliString(\"_\")\n    assert stim.PauliString(\"X\").before(stim.Circuit(\"MRX 0\")) == stim.PauliString(\"_\")\n    assert stim.PauliString(\"X\").before(stim.Circuit(\"MX 0\")) == stim.PauliString(\"X\")\n\n    assert stim.PauliString(\"Y\").before(stim.Circuit(\"RY 0\")) == stim.PauliString(\"_\")\n    assert stim.PauliString(\"Y\").before(stim.Circuit(\"MRY 0\")) == stim.PauliString(\"_\")\n    assert stim.PauliString(\"Y\").before(stim.Circuit(\"MY 0\")) == stim.PauliString(\"Y\")\n\n    with pytest.raises(ValueError):\n        stim.PauliString(\"Z\").before(stim.Circuit(\"RX 0\"))\n    with pytest.raises(ValueError):\n        stim.PauliString(\"Z\").before(stim.Circuit(\"RY 0\"))\n    with pytest.raises(ValueError):\n        stim.PauliString(\"Z\").before(stim.Circuit(\"MRX 0\"))\n    with pytest.raises(ValueError):\n        stim.PauliString(\"Z\").before(stim.Circuit(\"MRY 0\"))\n    with pytest.raises(ValueError):\n        stim.PauliString(\"Z\").before(stim.Circuit(\"MX 0\"))\n    with pytest.raises(ValueError):\n        stim.PauliString(\"Z\").before(stim.Circuit(\"MY 0\"))\n\ndef test_constructor_from_dict():\n    # Values are single Pauli -> Key is the qubit index:\n    assert stim.PauliString({2: \"X\", 4: \"Z\"}) == stim.PauliString(\"__X_Z\")\n    assert stim.PauliString({0: 1, 1: 2}) == stim.PauliString(\"XY\")\n    assert stim.PauliString({1: 1, 3: 2, 5: \"Z\"}) == stim.PauliString(\"_X_Y_Z\")\n    assert stim.PauliString({1: 0, 3: \"I\", 4: \"_\"}) == stim.PauliString(\"_____\")\n    assert stim.PauliString({0: \"X\", 2: \"x\", 4: \"y\"}) == stim.PauliString(\"X_X_Y\") # Case-insensitive\n    assert stim.PauliString({}) == stim.PauliString(\"\")\n\n    # Values are iterable -> Key is the Pauli:\n    assert stim.PauliString({\"X\": [0], \"Z\": [1]}) == stim.PauliString(\"XZ\")\n    assert stim.PauliString({1: [0], 3: [1]}) == stim.PauliString(\"XZ\")\n    assert stim.PauliString({\"X\": [2], \"Z\": [4], \"Y\": [6], \"I\": [5]}) == stim.PauliString(\"__X_Z_Y\")\n    assert stim.PauliString({\"X\": [0], \"Z\": [1,2]}) == stim.PauliString(\"XZZ\")\n    assert stim.PauliString({\"x\": [0,2], \"Y\": [4]}) == stim.PauliString(\"X_X_Y\") # Case-insensitive\n    assert stim.PauliString({\"I\": [1,2]}) == stim.PauliString(\"___\")\n    assert stim.PauliString({\"I\": []}) == stim.PauliString(\"\")\n    assert stim.PauliString({\"I\": [9]}) == stim.PauliString(10)\n    assert stim.PauliString({0: [9]}) == stim.PauliString(10)\n    assert stim.PauliString({\"_\": [9]}) == stim.PauliString(10)\n\n    # Acceptable collisions:\n    assert stim.PauliString({\"X\": [2], \"I\": [2]}) == stim.PauliString(\"__X\") # Trivial Pauli should not cause a conflict\n    assert stim.PauliString({\"X\": [2], 1: [2]}) == stim.PauliString(\"__X\") # Same Pauli should not cause conflict between int/str\n    assert stim.PauliString({\"X\": [2], \"I\": [0,1,2,3], \"Z\": [0], 0: [0,1,2,3], \"Y\": [1], \"_\": [0,1,2,3]}) == stim.PauliString(\"ZYX_\") # A more complex example\n\ndef test_constructor_from_dict_errors():\n    with pytest.raises(ValueError, match=\"keys must all be ints\"):\n        stim.PauliString({\"X\": 0}) # When value is non-itetable, key must be int (index)\n\n    with pytest.raises(ValueError, match=\"Don't know how to convert\"):\n        stim.PauliString({\"A\": [0]})\n\n    with pytest.raises(ValueError, match=\"Don't know how to convert\"):\n        stim.PauliString({0: \"A\"})\n\n    with pytest.raises(ValueError, match=\"Don't know how to convert\"):\n        stim.PauliString({0: 4}) # Paulis correspond to 0-3\n\n    with pytest.raises(ValueError, match=\"Don't know how to convert\"):\n        stim.PauliString({0: -1}) # Paulis correspond to 0-3\n\n    with pytest.raises(ValueError, match=\"Don't know how to convert\"):\n        stim.PauliString({\"ZX\": [0]}) # Paulis need to be single characters\n\n    with pytest.raises(ValueError, match=\"Pauli keys with iterable values\"):\n        stim.PauliString({\"X\": \"not an iterable\"})\n\n    with pytest.raises(ValueError, match=\"Qubit index must be an int\"):\n        stim.PauliString({\"Y\": [0, \"not an int\"]})\n\n    with pytest.raises(ValueError, match=\"keys must all be ints\"):\n        stim.PauliString({\"X\": 0, 1: \"Y\"})\n\n    with pytest.raises(ValueError, match=\"Qubit index must be an int\"):\n        stim.PauliString({\"X\": [0], 1: \"Y\"})\n\n    with pytest.raises(ValueError, match=\"Qubit index must be an int\"):\n        stim.PauliString({\"X\": [0], 1: [\"Y\"]})\n\n    with pytest.raises(ValueError, match=\"same qubit index\"):\n        stim.PauliString({\"X\": [0], \"Y\": [0]}) # Different non-trivial Paulies can't use the same index\n\n    with pytest.raises(ValueError, match=\"same qubit index\"):\n        stim.PauliString({\"Z\": [1], \"Y\": [4,1]}) # Different non-trivial Paulies can't use the same index\n\n    with pytest.raises(ValueError, match=\"same qubit index\"):\n        stim.PauliString({\"I\": [0,1,4], \"Z\": [1], \"Y\": [4,1]}) # Different non-trivial Paulies can't use the same index\n\n    with pytest.raises(ValueError, match=\"keys must all be ints\"):\n        stim.PauliString({(): []})\n\n    with pytest.raises(ValueError, match=\"keys must all be ints\"):\n        stim.PauliString({(): 0})\n\n    with pytest.raises(ValueError, match=\"Qubit index must be an int\"):\n        stim.PauliString({\"X\": [()]})\n\n    with pytest.raises(ValueError, match=\"Qubit index must be non-negative\"):\n        stim.PauliString({\"X\": [-1]})\n\n    with pytest.raises(ValueError, match=\"Qubit index must be non-negative\"):\n        stim.PauliString({-1: \"X\"})\n    \n    with pytest.raises(ValueError, match=\"Qubit index must be non-negative\"):\n        stim.PauliString({\"I\": [-1]})"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_ref.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_STABILIZERS_PAULI_STRING_REF_H\n#define _STIM_STABILIZERS_PAULI_STRING_REF_H\n\n#include <iostream>\n\n#include \"stim/mem/bit_ref.h\"\n#include \"stim/mem/simd_bits_range_ref.h\"\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nstruct PauliString;\nstruct Circuit;\ntemplate <size_t W>\nstruct Tableau;\nstruct CircuitInstruction;\n\n/// A Pauli string is a product of Pauli operations (I, X, Y, Z) to apply to various qubits.\n///\n/// A PauliStringRef is a Pauli string whose contents are backed by referenced memory, instead of memory owned by the\n/// class instance. For example, the memory may be a row from the densely packed bits of a stabilizer tableau. This\n/// avoids unnecessary copying, and allows for conveniently applying operations inplace on existing data.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstruct PauliStringRef {\n    /// The length of the Pauli string.\n    size_t num_qubits;\n    /// Whether or not the Pauli string is negated. True means -1, False means +1. Imaginary phase is not permitted.\n    bit_ref sign;\n    /// The Paulis in the Pauli string, densely bit packed in a fashion enabling the use of vectorized instructions.\n    /// Paulis are xz-encoded (P=xz: I=00, X=10, Y=11, Z=01) pairwise across the two bit vectors.\n    simd_bits_range_ref<W> xs, zs;\n\n    /// Constructs a PauliStringRef pointing at the given sign, x, and z data.\n    ///\n    /// Requires:\n    ///     xs.num_bits_padded() == zs.num_bits_padded()\n    ///     xs.num_simd_words == ceil(num_qubits / W)\n    PauliStringRef(size_t num_qubits, bit_ref sign, simd_bits_range_ref<W> xs, simd_bits_range_ref<W> zs);\n\n    /// Equality.\n    bool operator==(const PauliStringRef<W> &other) const;\n    /// Inequality.\n    bool operator!=(const PauliStringRef<W> &other) const;\n    bool operator<(const PauliStringRef<W> &other) const;\n\n    /// Overwrite assignment.\n    PauliStringRef<W> &operator=(const PauliStringRef<W> &other);\n    /// Swap assignment.\n    void swap_with(PauliStringRef<W> other);\n\n    /// Multiplies a commuting Pauli string into this one.\n    ///\n    /// If the two Pauli strings may anticommute, use `inplace_right_mul_returning_log_i_scalar` instead.\n    ///\n    /// ASSERTS:\n    ///     The given Pauli strings have the same size.\n    ///     The given Pauli strings commute.\n    PauliStringRef<W> &operator*=(const PauliStringRef<W> &commuting_rhs);\n\n    // A more general version  of `*this *= rhs` which works for anti-commuting Paulis.\n    //\n    // Instead of updating the sign of `*this`, the base i logarithm of a scalar factor that still needs to be included\n    // into the result is returned. For example, when multiplying XZ to get iY, the left hand side would become `Y`\n    // and the returned value would be `1` (meaning a factor of `i**1 = i` is missing from the `Y`).\n    //\n    // Returns:\n    //     The logarithm, base i, of a scalar byproduct from the multiplication.\n    //     0 if the scalar byproduct is 1.\n    //     1 if the scalar byproduct is i.\n    //     2 if the scalar byproduct is -1.\n    //     3 if the scalar byproduct is -i.\n    //\n    // ASSERTS:\n    //     The given Pauli strings have the same size.\n    uint8_t inplace_right_mul_returning_log_i_scalar(const PauliStringRef<W> &rhs) noexcept;\n\n    /// Overwrites the entire given Pauli string's contents with a subset of Paulis from this Pauli string.\n    /// Does not affect the sign of the given Pauli string.\n    ///\n    /// Args:\n    ///     out: The Pauli string to overwrite.\n    ///     in_indices: For each qubit position in the output Pauli string, which qubit positions is read from in this\n    ///         Pauli string.\n    void gather_into(PauliStringRef<W> out, SpanRef<const size_t> in_indices) const;\n\n    /// Overwrites part of the given Pauli string with the contents of this Pauli string.\n    /// Also multiplies this Pauli string's sign into the given Pauli string's sign.\n    ///\n    /// Args:\n    ///     out: The Pauli string to partially overwrite.\n    ///     out_indices: For each qubit position in this Pauli string, which qubit position is overwritten in the output\n    ///         Pauli string.\n    void scatter_into(PauliStringRef<W> out, SpanRef<const size_t> out_indices) const;\n\n    /// Determines if this Pauli string commutes with the given Pauli string.\n    bool commutes(const PauliStringRef<W> &other) const noexcept;\n\n    /// Returns a string describing the given Pauli string, with one character per qubit.\n    std::string str() const;\n    /// Returns a string describing the given Pauli string, indexing the Paulis so that identities can be omitted.\n    std::string sparse_str() const;\n\n    /// Applies the given tableau to the pauli string, at the given targets.\n    ///\n    /// Args:\n    ///     tableau: The Clifford operation to apply.\n    ///     targets: The qubits to target. Broadcasting is supported. The length of the span must be a multiple of the\n    ///         tableau's size.\n    ///     inverse: When true, applies the inverse of the tableau instead of the tableau.\n    void do_tableau(const Tableau<W> &tableau, SpanRef<const size_t> targets, bool inverse);\n    void do_circuit(const Circuit &circuit);\n    void undo_circuit(const Circuit &circuit);\n    void do_instruction(const CircuitInstruction &inst);\n    void undo_instruction(const CircuitInstruction &inst);\n\n    PauliString<W> after(const Circuit &circuit) const;\n    PauliString<W> after(const Tableau<W> &tableau, SpanRef<const size_t> indices) const;\n    PauliString<W> after(const CircuitInstruction &operation) const;\n    PauliString<W> before(const Circuit &circuit) const;\n    PauliString<W> before(const Tableau<W> &tableau, SpanRef<const size_t> indices) const;\n    PauliString<W> before(const CircuitInstruction &operation) const;\n\n    size_t weight() const;\n    bool has_no_pauli_terms() const;\n    bool intersects(PauliStringRef<W> other) const;\n\n    template <typename CALLBACK>\n    void for_each_active_pauli(CALLBACK callback) const {\n        size_t n = xs.num_u64_padded();\n        for (size_t w = 0; w < n; w++) {\n            uint64_t v = xs.u64[w] | zs.u64[w];\n            while (v) {\n                size_t q = w * 64 + std::countr_zero(v);\n                v &= v - 1;\n                callback(q);\n            }\n        }\n    }\n\n   private:\n    void check_avoids_MPP(const CircuitInstruction &inst);\n    void check_avoids_reset(const CircuitInstruction &inst);\n    void check_avoids_measurement(const CircuitInstruction &inst);\n    void undo_reset_xyz(const CircuitInstruction &inst);\n\n    void do_single_cx(const CircuitInstruction &inst, uint32_t c, uint32_t t);\n    void do_single_cy(const CircuitInstruction &inst, uint32_t c, uint32_t t);\n    void do_single_cz(const CircuitInstruction &inst, uint32_t c, uint32_t t);\n\n    void do_H_XZ(const CircuitInstruction &inst);\n    void do_H_YZ(const CircuitInstruction &inst);\n    void do_H_XY(const CircuitInstruction &inst);\n    void do_H_NXY(const CircuitInstruction &inst);\n    void do_H_NXZ(const CircuitInstruction &inst);\n    void do_H_NYZ(const CircuitInstruction &inst);\n    void do_C_XYZ(const CircuitInstruction &inst);\n    void do_C_NXYZ(const CircuitInstruction &inst);\n    void do_C_XNYZ(const CircuitInstruction &inst);\n    void do_C_XYNZ(const CircuitInstruction &inst);\n    void do_C_ZYX(const CircuitInstruction &inst);\n    void do_C_NZYX(const CircuitInstruction &inst);\n    void do_C_ZNYX(const CircuitInstruction &inst);\n    void do_C_ZYNX(const CircuitInstruction &inst);\n    void do_SQRT_X(const CircuitInstruction &inst);\n    void do_SQRT_Y(const CircuitInstruction &inst);\n    void do_SQRT_Z(const CircuitInstruction &inst);\n    void do_SQRT_X_DAG(const CircuitInstruction &inst);\n    void do_SQRT_Y_DAG(const CircuitInstruction &inst);\n    void do_SQRT_Z_DAG(const CircuitInstruction &inst);\n    void do_SQRT_XX(const CircuitInstruction &inst);\n    void do_SQRT_XX_DAG(const CircuitInstruction &inst);\n    void do_SQRT_YY(const CircuitInstruction &inst);\n    void do_SQRT_YY_DAG(const CircuitInstruction &inst);\n    void do_SQRT_ZZ(const CircuitInstruction &inst);\n    void do_SQRT_ZZ_DAG(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_ZCX(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_ZCY(const CircuitInstruction &inst);\n    void do_ZCZ(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_SWAP(const CircuitInstruction &inst);\n    void do_X(const CircuitInstruction &inst);\n    void do_Y(const CircuitInstruction &inst);\n    void do_Z(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_ISWAP(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_ISWAP_DAG(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_CXSWAP(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_CZSWAP(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_SWAPCX(const CircuitInstruction &inst);\n    void do_XCX(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_XCY(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_XCZ(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_YCX(const CircuitInstruction &inst);\n    void do_YCY(const CircuitInstruction &inst);\n    template <bool reverse_order>\n    void do_YCZ(const CircuitInstruction &inst);\n};\n\n/// Writes a string describing the given Pauli string to an output stream.\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const PauliStringRef<W> &ps);\n\n}  // namespace stim\n\n#include \"stim/stabilizers/pauli_string_ref.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_ref.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <cassert>\n#include <sstream>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/circuit/gate_decomposition.h\"\n#include \"stim/mem/simd_util.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nPauliStringRef<W>::PauliStringRef(\n    size_t init_num_qubits, bit_ref init_sign, simd_bits_range_ref<W> init_xs, simd_bits_range_ref<W> init_zs)\n    : num_qubits(init_num_qubits), sign(init_sign), xs(init_xs), zs(init_zs) {\n    assert(init_xs.num_bits_padded() == init_zs.num_bits_padded());\n    assert(init_xs.num_simd_words == (init_num_qubits + W - 1) / W);\n}\n\ntemplate <size_t W>\nstd::string PauliStringRef<W>::sparse_str() const {\n    std::stringstream out;\n    out << \"+-\"[(bool)sign];\n    bool first = true;\n    for_each_active_pauli([&](size_t q) {\n        auto p = xs[q] + 2 * zs[q];\n        if (!first) {\n            out << '*';\n        }\n        first = false;\n        out << \"IXZY\"[p] << q;\n    });\n    if (first) {\n        out << 'I';\n    }\n    return out.str();\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::swap_with(PauliStringRef<W> other) {\n    assert(num_qubits == other.num_qubits);\n    sign.swap_with(other.sign);\n    xs.swap_with(other.xs);\n    zs.swap_with(other.zs);\n}\n\ntemplate <size_t W>\nPauliStringRef<W> &PauliStringRef<W>::operator=(const PauliStringRef<W> &other) {\n    assert(num_qubits == other.num_qubits);\n    sign = other.sign;\n    assert((bool)sign == (bool)other.sign);\n    xs = other.xs;\n    zs = other.zs;\n    return *this;\n}\n\ntemplate <size_t W>\nstd::string PauliStringRef<W>::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\ntemplate <size_t W>\nbool PauliStringRef<W>::operator==(const PauliStringRef<W> &other) const {\n    return num_qubits == other.num_qubits && sign == other.sign && xs == other.xs && zs == other.zs;\n}\n\ntemplate <size_t W>\nbool PauliStringRef<W>::operator!=(const PauliStringRef<W> &other) const {\n    return !(*this == other);\n}\n\ntemplate <size_t W>\nbool PauliStringRef<W>::operator<(const PauliStringRef<W> &other) const {\n    size_t n = std::min(num_qubits, other.num_qubits);\n    for (size_t q = 0; q < n; q++) {\n        uint8_t p1 = (xs[q] ^ zs[q]) + zs[q] * 2;\n        uint8_t p2 = (other.xs[q] ^ other.zs[q]) + other.zs[q] * 2;\n        if (p1 != p2) {\n            return p1 < p2;\n        }\n    }\n    if (num_qubits != other.num_qubits) {\n        return num_qubits < other.num_qubits;\n    }\n    if (sign != other.sign) {\n        return sign < other.sign;\n    }\n    return false;\n}\n\ntemplate <size_t W>\nPauliStringRef<W> &PauliStringRef<W>::operator*=(const PauliStringRef<W> &rhs) {\n    uint8_t log_i = inplace_right_mul_returning_log_i_scalar(rhs);\n    assert((log_i & 1) == 0);\n    sign ^= log_i & 2;\n    return *this;\n}\n\ntemplate <size_t W>\nuint8_t PauliStringRef<W>::inplace_right_mul_returning_log_i_scalar(const PauliStringRef<W> &rhs) noexcept {\n    assert(num_qubits >= rhs.num_qubits);\n\n    // Accumulator registers for counting mod 4 in parallel across each bit position.\n    simd_word<W> cnt1{};\n    simd_word<W> cnt2{};\n\n    rhs.xs.for_each_word(\n        rhs.zs, xs, zs, [&cnt1, &cnt2](simd_word<W> &x2, simd_word<W> &z2, simd_word<W> &x1, simd_word<W> &z1) {\n            // Update the left hand side Paulis.\n            auto old_x1 = x1;\n            auto old_z1 = z1;\n            x1 ^= x2;\n            z1 ^= z2;\n\n            // At each bit position: accumulate anti-commutation (+i or -i) counts.\n            auto x1z2 = old_x1 & z2;\n            auto anti_commutes = (x2 & old_z1) ^ x1z2;\n            cnt2 ^= (cnt1 ^ x1 ^ z1 ^ x1z2) & anti_commutes;\n            cnt1 ^= anti_commutes;\n        });\n\n    // Combine final anti-commutation phase tally (mod 4).\n    auto s = (uint8_t)cnt1.popcount();\n    s ^= cnt2.popcount() << 1;\n    s ^= (uint8_t)rhs.sign << 1;\n    return s & 3;\n}\n\ntemplate <size_t W>\nbool PauliStringRef<W>::commutes(const PauliStringRef<W> &other) const noexcept {\n    if (num_qubits > other.num_qubits) {\n        return other.commutes(*this);\n    }\n    simd_word<W> cnt1{};\n    xs.for_each_word(\n        zs, other.xs, other.zs, [&cnt1](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2) {\n            cnt1 ^= (x1 & z2) ^ (x2 & z1);\n        });\n    return (cnt1.popcount() & 1) == 0;\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_tableau(const Tableau<W> &tableau, SpanRef<const size_t> indices, bool inverse) {\n    if (tableau.num_qubits == 0 || indices.size() % tableau.num_qubits != 0) {\n        throw std::invalid_argument(\"len(tableau) == 0 or len(indices) % len(tableau) != 0\");\n    }\n    for (auto e : indices) {\n        if (e >= num_qubits) {\n            throw std::invalid_argument(\"Attempted to apply a tableau past the end of the pauli string.\");\n        }\n    }\n    if (inverse) {\n        auto inverse_tableau = tableau.inverse();\n        for (size_t k = indices.size(); k > 0;) {\n            k -= tableau.num_qubits;\n            inverse_tableau.apply_within(*this, {indices.ptr_start + k, indices.ptr_start + k + tableau.num_qubits});\n        }\n    } else {\n        for (size_t k = 0; k < indices.size(); k += tableau.num_qubits) {\n            tableau.apply_within(*this, {indices.ptr_start + k, indices.ptr_start + k + tableau.num_qubits});\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::undo_circuit(const Circuit &circuit) {\n    circuit.for_each_operation_reverse([&](const CircuitInstruction &inst) {\n        undo_instruction(inst);\n    });\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_circuit(const Circuit &circuit) {\n    circuit.for_each_operation([&](const CircuitInstruction &inst) {\n        do_instruction(inst);\n    });\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::undo_reset_xyz(const CircuitInstruction &inst) {\n    bool x_dep, z_dep;\n    if (inst.gate_type == GateType::R || inst.gate_type == GateType::MR) {\n        x_dep = true;\n        z_dep = false;\n    } else if (inst.gate_type == GateType::RX || inst.gate_type == GateType::MRX) {\n        x_dep = false;\n        z_dep = true;\n    } else if (inst.gate_type == GateType::RY || inst.gate_type == GateType::MRY) {\n        x_dep = true;\n        z_dep = true;\n    } else {\n        throw std::invalid_argument(\"Unrecognized measurement type: \" + inst.str());\n    }\n    for (const auto &t : inst.targets) {\n        assert(t.is_qubit_target());\n        auto q = t.qubit_value();\n        if (q < num_qubits && ((xs[q] & x_dep) ^ (zs[q] & z_dep))) {\n            std::stringstream ss;\n            ss << \"The pauli observable '\" << *this;\n            ss << \"' doesn't have a well specified value before '\" << inst;\n            ss << \"' because it anticommutes with the reset.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n    for (const auto &t : inst.targets) {\n        auto q = t.qubit_value();\n        xs[q] = false;\n        zs[q] = false;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::check_avoids_measurement(const CircuitInstruction &inst) {\n    bool x_dep, z_dep;\n    if (inst.gate_type == GateType::M) {\n        x_dep = true;\n        z_dep = false;\n    } else if (inst.gate_type == GateType::MX) {\n        x_dep = false;\n        z_dep = true;\n    } else if (inst.gate_type == GateType::MY) {\n        x_dep = true;\n        z_dep = true;\n    } else {\n        throw std::invalid_argument(\"Unrecognized measurement type: \" + inst.str());\n    }\n    for (const auto &t : inst.targets) {\n        assert(t.is_qubit_target());\n        auto q = t.qubit_value();\n        if (q < num_qubits && ((xs[q] & x_dep) ^ (zs[q] & z_dep))) {\n            std::stringstream ss;\n            ss << \"The pauli observable '\" << *this;\n            ss << \"' doesn't have a well specified value across '\" << inst;\n            ss << \"' because it anticommutes with the measurement.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::check_avoids_reset(const CircuitInstruction &inst) {\n    // Only fail if the pauli string actually touches the reset.\n    for (const auto &t : inst.targets) {\n        assert(t.is_qubit_target());\n        auto q = t.qubit_value();\n        if (q < num_qubits && (xs[q] || zs[q])) {\n            std::stringstream ss;\n            ss << \"The pauli observable '\" << *this;\n            ss << \"' doesn't have a well specified value after '\" << inst;\n            ss << \"' because the reset discards information.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::check_avoids_MPP(const CircuitInstruction &inst) {\n    size_t start = 0;\n    const auto &targets = inst.targets;\n    while (start < targets.size()) {\n        size_t end = start + 1;\n        bool anticommutes = false;\n        while (true) {\n            auto t = targets[end - 1];\n            auto q = t.qubit_value();\n            if (q < num_qubits) {\n                anticommutes ^= zs[q] && (t.data & TARGET_PAULI_X_BIT);\n                anticommutes ^= xs[q] && (t.data & TARGET_PAULI_Z_BIT);\n            }\n            if (end >= targets.size() || !targets[end].is_combiner()) {\n                break;\n            }\n            end += 2;\n        }\n        if (anticommutes) {\n            std::stringstream ss;\n            ss << \"The pauli observable '\" << *this;\n            ss << \"' doesn't have a well specified value across '\" << inst;\n            ss << \"' because it anticommutes with the measurement.\";\n            throw std::invalid_argument(ss.str());\n        }\n        start = end;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_instruction(const CircuitInstruction &inst) {\n    for (const auto &t : inst.targets) {\n        if (t.has_qubit_value() && t.qubit_value() >= num_qubits &&\n            !(GATE_DATA[inst.gate_type].flags & GATE_HAS_NO_EFFECT_ON_QUBITS)) {\n            std::stringstream ss;\n            ss << \"The instruction '\" << inst;\n            ss << \"' targets qubits outside the pauli string '\" << *this;\n            ss << \"'.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n\n    const auto &gate_data = GATE_DATA[inst.gate_type];\n    switch (gate_data.id) {\n        case GateType::H:\n            do_H_XZ(inst);\n            break;\n        case GateType::H_YZ:\n            do_H_YZ(inst);\n            break;\n        case GateType::H_XY:\n            do_H_XY(inst);\n            break;\n        case GateType::H_NXY:\n            do_H_NXY(inst);\n            break;\n        case GateType::H_NXZ:\n            do_H_NXZ(inst);\n            break;\n        case GateType::H_NYZ:\n            do_H_NYZ(inst);\n            break;\n        case GateType::C_XYZ:\n            do_C_XYZ(inst);\n            break;\n        case GateType::C_NXYZ:\n            do_C_NXYZ(inst);\n            break;\n        case GateType::C_XNYZ:\n            do_C_XNYZ(inst);\n            break;\n        case GateType::C_XYNZ:\n            do_C_XYNZ(inst);\n            break;\n        case GateType::C_ZYX:\n            do_C_ZYX(inst);\n            break;\n        case GateType::C_NZYX:\n            do_C_NZYX(inst);\n            break;\n        case GateType::C_ZNYX:\n            do_C_ZNYX(inst);\n            break;\n        case GateType::C_ZYNX:\n            do_C_ZYNX(inst);\n            break;\n        case GateType::SQRT_X:\n            do_SQRT_X(inst);\n            break;\n        case GateType::SQRT_Y:\n            do_SQRT_Y(inst);\n            break;\n        case GateType::S:\n            do_SQRT_Z(inst);\n            break;\n        case GateType::SQRT_X_DAG:\n            do_SQRT_X_DAG(inst);\n            break;\n        case GateType::SQRT_Y_DAG:\n            do_SQRT_Y_DAG(inst);\n            break;\n        case GateType::S_DAG:\n            do_SQRT_Z_DAG(inst);\n            break;\n        case GateType::SQRT_XX:\n            do_SQRT_XX(inst);\n            break;\n        case GateType::SQRT_XX_DAG:\n            do_SQRT_XX_DAG(inst);\n            break;\n        case GateType::SQRT_YY:\n            do_SQRT_YY(inst);\n            break;\n        case GateType::SQRT_YY_DAG:\n            do_SQRT_YY_DAG(inst);\n            break;\n        case GateType::SQRT_ZZ:\n            do_SQRT_ZZ(inst);\n            break;\n        case GateType::SQRT_ZZ_DAG:\n            do_SQRT_ZZ_DAG(inst);\n            break;\n        case GateType::CX:\n            do_ZCX<false>(inst);\n            break;\n        case GateType::CY:\n            do_ZCY<false>(inst);\n            break;\n        case GateType::CZ:\n            do_ZCZ(inst);\n            break;\n        case GateType::SWAP:\n            do_SWAP<false>(inst);\n            break;\n        case GateType::X:\n            do_X(inst);\n            break;\n        case GateType::Y:\n            do_Y(inst);\n            break;\n        case GateType::Z:\n            do_Z(inst);\n            break;\n        case GateType::ISWAP:\n            do_ISWAP<false>(inst);\n            break;\n        case GateType::ISWAP_DAG:\n            do_ISWAP_DAG<false>(inst);\n            break;\n        case GateType::CXSWAP:\n            do_CXSWAP<false>(inst);\n            break;\n        case GateType::CZSWAP:\n            do_CZSWAP<false>(inst);\n            break;\n        case GateType::SWAPCX:\n            do_SWAPCX<false>(inst);\n            break;\n        case GateType::XCX:\n            do_XCX(inst);\n            break;\n        case GateType::XCY:\n            do_XCY<false>(inst);\n            break;\n        case GateType::XCZ:\n            do_XCZ<false>(inst);\n            break;\n        case GateType::YCX:\n            do_YCX<false>(inst);\n            break;\n        case GateType::YCY:\n            do_YCY(inst);\n            break;\n        case GateType::YCZ:\n            do_YCZ<false>(inst);\n            break;\n\n        case GateType::DETECTOR:\n        case GateType::OBSERVABLE_INCLUDE:\n        case GateType::TICK:\n        case GateType::QUBIT_COORDS:\n        case GateType::SHIFT_COORDS:\n        case GateType::MPAD:\n        case GateType::I:\n        case GateType::II:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n            // No effect.\n            break;\n\n        case GateType::R:\n        case GateType::RX:\n        case GateType::RY:\n        case GateType::MR:\n        case GateType::MRX:\n        case GateType::MRY:\n            check_avoids_reset(inst);\n            break;\n\n        case GateType::M:\n        case GateType::MX:\n        case GateType::MY:\n            check_avoids_measurement(inst);\n            break;\n\n        case GateType::MPP:\n            check_avoids_MPP(inst);\n            break;\n\n        case GateType::SPP:\n        case GateType::SPP_DAG:\n            decompose_spp_or_spp_dag_operation(inst, num_qubits, false, [&](CircuitInstruction sub_inst) {\n                do_instruction(sub_inst);\n            });\n            break;\n\n        case GateType::X_ERROR:\n        case GateType::Y_ERROR:\n        case GateType::Z_ERROR:\n        case GateType::DEPOLARIZE1:\n        case GateType::DEPOLARIZE2:\n        case GateType::E:\n        case GateType::ELSE_CORRELATED_ERROR: {\n            std::stringstream ss;\n            ss << \"The pauli string '\" << *this;\n            ss << \"' doesn't have a well defined deterministic value after '\" << inst;\n            ss << \"'.\";\n            throw std::invalid_argument(ss.str());\n        }\n\n        default:\n            throw std::invalid_argument(\"Not implemented in PauliStringRef<W>::do_instruction: \" + inst.str());\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::undo_instruction(const CircuitInstruction &inst) {\n    for (const auto &t : inst.targets) {\n        if (t.has_qubit_value() && t.qubit_value() >= num_qubits &&\n            !(GATE_DATA[inst.gate_type].flags & GATE_HAS_NO_EFFECT_ON_QUBITS)) {\n            std::stringstream ss;\n            ss << \"The instruction '\" << inst;\n            ss << \"' targets qubits outside the pauli string '\" << *this;\n            ss << \"'.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n\n    const auto &gate_data = GATE_DATA[inst.gate_type];\n    switch (gate_data.id) {\n        case GateType::H:\n            do_H_XZ(inst);\n            break;\n        case GateType::H_YZ:\n            do_H_YZ(inst);\n            break;\n        case GateType::H_XY:\n            do_H_XY(inst);\n            break;\n        case GateType::H_NXY:\n            do_H_NXY(inst);\n            break;\n        case GateType::H_NXZ:\n            do_H_NXZ(inst);\n            break;\n        case GateType::H_NYZ:\n            do_H_NYZ(inst);\n            break;\n        case GateType::C_XYZ:\n            do_C_ZYX(inst);\n            break;\n        case GateType::C_NXYZ:\n            do_C_ZYNX(inst);\n            break;\n        case GateType::C_XNYZ:\n            do_C_ZNYX(inst);\n            break;\n        case GateType::C_XYNZ:\n            do_C_NZYX(inst);\n            break;\n        case GateType::C_ZYX:\n            do_C_XYZ(inst);\n            break;\n        case GateType::C_NZYX:\n            do_C_XYNZ(inst);\n            break;\n        case GateType::C_ZNYX:\n            do_C_XNYZ(inst);\n            break;\n        case GateType::C_ZYNX:\n            do_C_NXYZ(inst);\n            break;\n        case GateType::SQRT_X:\n            do_SQRT_X_DAG(inst);\n            break;\n        case GateType::SQRT_Y:\n            do_SQRT_Y_DAG(inst);\n            break;\n        case GateType::S:\n            do_SQRT_Z_DAG(inst);\n            break;\n        case GateType::SQRT_X_DAG:\n            do_SQRT_X(inst);\n            break;\n        case GateType::SQRT_Y_DAG:\n            do_SQRT_Y(inst);\n            break;\n        case GateType::S_DAG:\n            do_SQRT_Z(inst);\n            break;\n        case GateType::SQRT_XX:\n            do_SQRT_XX_DAG(inst);\n            break;\n        case GateType::SQRT_XX_DAG:\n            do_SQRT_XX(inst);\n            break;\n        case GateType::SQRT_YY:\n            do_SQRT_YY_DAG(inst);\n            break;\n        case GateType::SQRT_YY_DAG:\n            do_SQRT_YY(inst);\n            break;\n        case GateType::SQRT_ZZ:\n            do_SQRT_ZZ_DAG(inst);\n            break;\n        case GateType::SQRT_ZZ_DAG:\n            do_SQRT_ZZ(inst);\n            break;\n        case GateType::CX:\n            do_ZCX<true>(inst);\n            break;\n        case GateType::CY:\n            do_ZCY<true>(inst);\n            break;\n        case GateType::CZ:\n            do_ZCZ(inst);\n            break;\n        case GateType::SWAP:\n            do_SWAP<true>(inst);\n            break;\n        case GateType::X:\n            do_X(inst);\n            break;\n        case GateType::Y:\n            do_Y(inst);\n            break;\n        case GateType::Z:\n            do_Z(inst);\n            break;\n        case GateType::ISWAP:\n            do_ISWAP_DAG<true>(inst);\n            break;\n        case GateType::ISWAP_DAG:\n            do_ISWAP<true>(inst);\n            break;\n        case GateType::CXSWAP:\n            do_SWAPCX<true>(inst);\n            break;\n        case GateType::CZSWAP:\n            do_CZSWAP<true>(inst);\n            break;\n        case GateType::SWAPCX:\n            do_CXSWAP<true>(inst);\n            break;\n        case GateType::XCX:\n            do_XCX(inst);\n            break;\n        case GateType::XCY:\n            do_XCY<true>(inst);\n            break;\n        case GateType::XCZ:\n            do_XCZ<true>(inst);\n            break;\n        case GateType::YCX:\n            do_YCX<true>(inst);\n            break;\n        case GateType::YCY:\n            do_YCY(inst);\n            break;\n        case GateType::YCZ:\n            do_YCZ<true>(inst);\n            break;\n\n        case GateType::SPP:\n        case GateType::SPP_DAG: {\n            std::vector<GateTarget> buf_targets;\n            buf_targets.insert(buf_targets.end(), inst.targets.begin(), inst.targets.end());\n            std::reverse(buf_targets.begin(), buf_targets.end());\n            decompose_spp_or_spp_dag_operation(\n                CircuitInstruction{inst.gate_type, {}, buf_targets, inst.tag},\n                num_qubits,\n                false,\n                [&](CircuitInstruction sub_inst) {\n                    undo_instruction(sub_inst);\n                });\n            break;\n        }\n\n        case GateType::DETECTOR:\n        case GateType::OBSERVABLE_INCLUDE:\n        case GateType::TICK:\n        case GateType::QUBIT_COORDS:\n        case GateType::SHIFT_COORDS:\n        case GateType::MPAD:\n        case GateType::I:\n        case GateType::II:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n            // No effect.\n            break;\n\n        case GateType::R:\n        case GateType::RX:\n        case GateType::RY:\n        case GateType::MR:\n        case GateType::MRX:\n        case GateType::MRY:\n            undo_reset_xyz(inst);\n            break;\n\n        case GateType::M:\n        case GateType::MX:\n        case GateType::MY:\n            check_avoids_measurement(inst);\n            break;\n\n        case GateType::MPP:\n            check_avoids_MPP(inst);\n            break;\n\n        case GateType::X_ERROR:\n        case GateType::Y_ERROR:\n        case GateType::Z_ERROR:\n        case GateType::DEPOLARIZE1:\n        case GateType::DEPOLARIZE2:\n        case GateType::E:\n        case GateType::ELSE_CORRELATED_ERROR: {\n            std::stringstream ss;\n            ss << \"The pauli string '\" << *this;\n            ss << \"' doesn't have a well defined deterministic value before '\" << inst;\n            ss << \"'.\";\n            throw std::invalid_argument(ss.str());\n        }\n\n        default:\n            throw std::invalid_argument(\"Not implemented in PauliStringRef<W>::undo_instruction: \" + inst.str());\n    }\n}\n\ntemplate <size_t W>\nPauliString<W> PauliStringRef<W>::after(const Circuit &circuit) const {\n    PauliString<W> result = *this;\n    result.ref().do_circuit(circuit);\n    return result;\n}\n\ntemplate <size_t W>\nPauliString<W> PauliStringRef<W>::after(const Tableau<W> &tableau, SpanRef<const size_t> indices) const {\n    PauliString<W> result = *this;\n    result.ref().do_tableau(tableau, indices, false);\n    return result;\n}\n\ntemplate <size_t W>\nPauliString<W> PauliStringRef<W>::after(const CircuitInstruction &inst) const {\n    PauliString<W> result = *this;\n    result.ref().do_instruction(inst);\n    return result;\n}\n\ntemplate <size_t W>\nPauliString<W> PauliStringRef<W>::before(const Circuit &circuit) const {\n    PauliString<W> result = *this;\n    result.ref().undo_circuit(circuit);\n    return result;\n}\n\ntemplate <size_t W>\nPauliString<W> PauliStringRef<W>::before(const CircuitInstruction &inst) const {\n    PauliString<W> result = *this;\n    result.ref().undo_instruction(inst);\n    return result;\n}\n\ntemplate <size_t W>\nPauliString<W> PauliStringRef<W>::before(const Tableau<W> &tableau, SpanRef<const size_t> indices) const {\n    PauliString<W> result = *this;\n    result.ref().do_tableau(tableau, indices, true);\n    return result;\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::gather_into(PauliStringRef<W> out, SpanRef<const size_t> in_indices) const {\n    assert(in_indices.size() == out.num_qubits);\n    for (size_t k_out = 0; k_out < out.num_qubits; k_out++) {\n        size_t k_in = in_indices[k_out];\n        out.xs[k_out] = xs[k_in];\n        out.zs[k_out] = zs[k_in];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::scatter_into(PauliStringRef<W> out, SpanRef<const size_t> out_indices) const {\n    assert(num_qubits == out_indices.size());\n    for (size_t k_in = 0; k_in < num_qubits; k_in++) {\n        size_t k_out = out_indices[k_in];\n        out.xs[k_out] = xs[k_in];\n        out.zs[k_out] = zs[k_in];\n    }\n    out.sign ^= sign;\n}\n\ntemplate <size_t W>\nbool PauliStringRef<W>::intersects(const PauliStringRef<W> other) const {\n    size_t n = std::min(xs.num_u64_padded(), other.xs.num_u64_padded());\n    uint64_t v = 0;\n    for (size_t k = 0; k < n; k++) {\n        v |= (xs.u64[k] | zs.u64[k]) & (other.xs.u64[k] | other.zs.u64[k]);\n    }\n    return v != 0;\n}\n\ntemplate <size_t W>\nsize_t PauliStringRef<W>::weight() const {\n    size_t total = 0;\n    xs.for_each_word(zs, [&](const simd_word<W> &w1, const simd_word<W> &w2) {\n        total += (w1 | w2).popcount();\n    });\n    return total;\n}\n\ntemplate <size_t W>\nbool PauliStringRef<W>::has_no_pauli_terms() const {\n    size_t total = 0;\n    size_t n = xs.num_u64_padded();\n    for (size_t k = 0; k < n; k++) {\n        total |= xs.u64[k] | zs.u64[k];\n    }\n    return total == 0;\n}\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const PauliStringRef<W> &ps) {\n    out << \"+-\"[ps.sign];\n    for (size_t k = 0; k < ps.num_qubits; k++) {\n        out << \"_XZY\"[ps.xs[k] + 2 * ps.zs[k]];\n    }\n    return out;\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_H_XZ(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        xs[q].swap_with(zs[q]);\n        sign ^= xs[q] && zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_H_NXY(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        zs[q] ^= xs[q];\n        sign ^= !xs[q] && !zs[q];\n        sign ^= true;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_H_NXZ(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        xs[q].swap_with(zs[q]);\n        sign ^= !xs[q] && !zs[q];\n        sign ^= true;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_H_NYZ(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        xs[q] ^= zs[q];\n        sign ^= !xs[q] && !zs[q];\n        sign ^= true;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_Y(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        xs[q].swap_with(zs[q]);\n        sign ^= !xs[q] && zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_Y_DAG(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        xs[q].swap_with(zs[q]);\n        sign ^= xs[q] && !zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_H_XY(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        zs[q] ^= xs[q];\n        sign ^= !xs[q] && zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_Z(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        zs[q] ^= xs[q];\n        sign ^= xs[q] && !zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_Z_DAG(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        zs[q] ^= xs[q];\n        sign ^= xs[q] && zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_H_YZ(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        xs[q] ^= zs[q];\n        sign ^= xs[q] && !zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_X(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        xs[q] ^= zs[q];\n        sign ^= xs[q] && zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_X_DAG(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        xs[q] ^= zs[q];\n        sign ^= !xs[q] && zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_C_XYZ(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        xs[q] ^= zs[q];\n        zs[q] ^= xs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_C_NXYZ(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        sign ^= xs[q];\n        sign ^= zs[q];\n        xs[q] ^= zs[q];\n        zs[q] ^= xs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_C_XNYZ(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        sign ^= xs[q];\n        xs[q] ^= zs[q];\n        zs[q] ^= xs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_C_XYNZ(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        sign ^= zs[q];\n        xs[q] ^= zs[q];\n        zs[q] ^= xs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_C_ZYX(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        zs[q] ^= xs[q];\n        xs[q] ^= zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_C_ZYNX(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        sign ^= xs[q];\n        zs[q] ^= xs[q];\n        xs[q] ^= zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_C_ZNYX(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        sign ^= zs[q];\n        zs[q] ^= xs[q];\n        xs[q] ^= zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_C_NZYX(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        sign ^= xs[q];\n        sign ^= zs[q];\n        zs[q] ^= xs[q];\n        xs[q] ^= zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_X(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        sign ^= zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_Y(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        sign ^= xs[q] ^ zs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_Z(const CircuitInstruction &inst) {\n    for (auto t : inst.targets) {\n        auto q = t.data;\n        sign ^= xs[q];\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_single_cx(const CircuitInstruction &inst, uint32_t c, uint32_t t) {\n    c &= ~TARGET_INVERTED_BIT;\n    t &= ~TARGET_INVERTED_BIT;\n    if (!((c | t) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        bit_ref x1 = xs[c], x2 = xs[t], z1 = zs[c], z2 = zs[t];\n        z1 ^= z2;\n        x2 ^= x1;\n        sign ^= x1 && z2 && (z1 == x2);\n    } else if (t & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT)) {\n        throw std::invalid_argument(\n            \"CX had a bit (\" + GateTarget{t}.str() + \") as its target, instead of its control.\");\n    } else {\n        if (zs[t]) {\n            std::stringstream ss;\n            ss << \"The pauli observable '\" << *this;\n            ss << \"' is affected by a controlled operation in '\" << inst;\n            ss << \"' but the controlling measurement result isn't known.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_single_cy(const CircuitInstruction &inst, uint32_t c, uint32_t t) {\n    c &= ~TARGET_INVERTED_BIT;\n    t &= ~TARGET_INVERTED_BIT;\n    if (!((c | t) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        bit_ref x1 = xs[c], x2 = xs[t], z1 = zs[c], z2 = zs[t];\n        z1 ^= x2 ^ z2;\n        z2 ^= x1;\n        x2 ^= x1;\n        sign ^= x1 && !z1 && x2 && !z2;\n        sign ^= x1 && z1 && !x2 && z2;\n    } else if (t & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT)) {\n        throw std::invalid_argument(\n            \"CY had a bit (\" + GateTarget{t}.str() + \") as its target, instead of its control.\");\n    } else {\n        if (xs[t] ^ zs[t]) {\n            std::stringstream ss;\n            ss << \"The pauli observable '\" << *this;\n            ss << \"' is affected by a controlled operation in '\" << inst;\n            ss << \"' but the controlling measurement result isn't known.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_single_cz(const CircuitInstruction &inst, uint32_t c, uint32_t t) {\n    c &= ~TARGET_INVERTED_BIT;\n    t &= ~TARGET_INVERTED_BIT;\n    if (!((c | t) & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT))) {\n        bit_ref x1 = xs[c], x2 = xs[t], z1 = zs[c], z2 = zs[t];\n        z1 ^= x2;\n        z2 ^= x1;\n        sign ^= x1 && x2 && (z1 ^ z2);\n    } else {\n        bool bc = !(c & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT)) && xs[c];\n        bool bt = !(t & (TARGET_RECORD_BIT | TARGET_SWEEP_BIT)) && xs[t];\n        if (bc || bt) {\n            std::stringstream ss;\n            ss << \"The pauli observable '\" << *this;\n            ss << \"' is affected by a controlled operation in '\" << inst;\n            ss << \"' but the controlling measurement result isn't known.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_ZCX(const CircuitInstruction &inst) {\n    assert((inst.targets.size() & 1) == 0);\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t k2 = reverse_order ? inst.targets.size() - 2 - k : k;\n        size_t q1 = inst.targets[k2].data, q2 = inst.targets[k2 + 1].data;\n        do_single_cx(inst, q1, q2);\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_ZCY(const CircuitInstruction &inst) {\n    assert((inst.targets.size() & 1) == 0);\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t k2 = reverse_order ? inst.targets.size() - 2 - k : k;\n        size_t q1 = inst.targets[k2].data, q2 = inst.targets[k2 + 1].data;\n        do_single_cy(inst, q1, q2);\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_ZCZ(const CircuitInstruction &inst) {\n    const auto &targets = inst.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        do_single_cz(inst, targets[k].data, targets[k + 1].data);\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_SWAP(const CircuitInstruction &inst) {\n    const auto &targets = inst.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        size_t k2 = reverse_order ? targets.size() - 2 - k : k;\n        size_t q1 = targets[k2].data, q2 = targets[k2 + 1].data;\n        zs[q1].swap_with(zs[q2]);\n        xs[q1].swap_with(xs[q2]);\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_ISWAP(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t k2 = reverse_order ? inst.targets.size() - 2 - k : k;\n        size_t q1 = inst.targets[k2].data, q2 = inst.targets[k2 + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        sign ^= x1 && z1 && !x2 && !z2;\n        sign ^= !x1 && !z1 && x2 && z2;\n        sign ^= (x1 ^ x2) && z1 && z2;\n        auto dx = x1 ^ x2;\n        z1 ^= dx;\n        z2 ^= dx;\n        z1.swap_with(z2);\n        x1.swap_with(x2);\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_ISWAP_DAG(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t k2 = reverse_order ? inst.targets.size() - 2 - k : k;\n        size_t q1 = inst.targets[k2].data, q2 = inst.targets[k2 + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        auto dx = x1 ^ x2;\n        z1 ^= dx;\n        z2 ^= dx;\n        z1.swap_with(z2);\n        x1.swap_with(x2);\n        sign ^= x1 && z1 && !x2 && !z2;\n        sign ^= !x1 && !z1 && x2 && z2;\n        sign ^= (x1 ^ x2) && z1 && z2;\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_CXSWAP(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t k2 = reverse_order ? inst.targets.size() - 2 - k : k;\n        size_t q1 = inst.targets[k2].data, q2 = inst.targets[k2 + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        sign ^= x1 && z2 && (z1 == x2);\n        z2 ^= z1;\n        z1 ^= z2;\n        x1 ^= x2;\n        x2 ^= x1;\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_CZSWAP(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t k2 = reverse_order ? inst.targets.size() - 2 - k : k;\n        size_t q1 = inst.targets[k2].data, q2 = inst.targets[k2 + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        z1.swap_with(z2);\n        x1.swap_with(x2);\n        z1 ^= x2;\n        z2 ^= x1;\n        sign ^= x1 && x2 && (z1 ^ z2);\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_SWAPCX(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t k2 = reverse_order ? inst.targets.size() - 2 - k : k;\n        size_t q1 = inst.targets[k2].data, q2 = inst.targets[k2 + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        z1 ^= z2;\n        z2 ^= z1;\n        x2 ^= x1;\n        x1 ^= x2;\n        sign ^= x1 && z2 && (z1 == x2);\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_XX(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t q1 = inst.targets[k].data, q2 = inst.targets[k + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        sign ^= !x1 && z1 && !z2;\n        sign ^= !x2 && !z1 && z2;\n        auto dz = z1 ^ z2;\n        x1 ^= dz;\n        x2 ^= dz;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_XX_DAG(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t q1 = inst.targets[k].data, q2 = inst.targets[k + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        auto dz = z1 ^ z2;\n        x1 ^= dz;\n        x2 ^= dz;\n        sign ^= !x1 && z1 && !z2;\n        sign ^= !x2 && !z1 && z2;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_YY(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t q1 = inst.targets[k].data, q2 = inst.targets[k + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        sign ^= x1 && z1 && x2 && !z2;\n        sign ^= x1 && !z1 && x2 && z2;\n        sign ^= x1 && !z1 && !x2 && !z2;\n        sign ^= !x1 && !z1 && x2 && !z2;\n        auto d = x1 ^ z1 ^ x2 ^ z2;\n        x1 ^= d;\n        z1 ^= d;\n        x2 ^= d;\n        z2 ^= d;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_YY_DAG(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t q1 = inst.targets[k].data, q2 = inst.targets[k + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        auto d = x1 ^ z1 ^ x2 ^ z2;\n        x1 ^= d;\n        z1 ^= d;\n        x2 ^= d;\n        z2 ^= d;\n        sign ^= x1 && z1 && x2 && !z2;\n        sign ^= x1 && !z1 && x2 && z2;\n        sign ^= x1 && !z1 && !x2 && !z2;\n        sign ^= !x1 && !z1 && x2 && !z2;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_ZZ(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t q1 = inst.targets[k].data, q2 = inst.targets[k + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        auto dx = x1 ^ x2;\n        z1 ^= dx;\n        z2 ^= dx;\n        sign ^= !z1 && x1 && !x2;\n        sign ^= !z2 && !x1 && x2;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_SQRT_ZZ_DAG(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t q1 = inst.targets[k].data, q2 = inst.targets[k + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        sign ^= !z1 && x1 && !x2;\n        sign ^= !z2 && !x1 && x2;\n        auto dx = x1 ^ x2;\n        z1 ^= dx;\n        z2 ^= dx;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_XCX(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t q1 = inst.targets[k].data, q2 = inst.targets[k + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        sign ^= (x1 != x2) && z1 && z2;\n        x1 ^= z2;\n        x2 ^= z1;\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_XCY(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t k2 = reverse_order ? inst.targets.size() - 2 - k : k;\n        size_t q1 = inst.targets[k2].data, q2 = inst.targets[k2 + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        x1 ^= x2 ^ z2;\n        x2 ^= z1;\n        z2 ^= z1;\n        sign ^= !x1 && z1 && !x2 && z2;\n        sign ^= x1 && z1 && x2 && !z2;\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_XCZ(const CircuitInstruction &inst) {\n    const auto &targets = inst.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        size_t k2 = reverse_order ? targets.size() - 2 - k : k;\n        size_t q1 = targets[k2].data, q2 = targets[k2 + 1].data;\n        do_single_cx(inst, q2, q1);\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_YCX(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t k2 = reverse_order ? inst.targets.size() - 2 - k : k;\n        size_t q1 = inst.targets[k2].data, q2 = inst.targets[k2 + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        x2 ^= x1 ^ z1;\n        x1 ^= z2;\n        z1 ^= z2;\n        sign ^= !x2 && z2 && !x1 && z1;\n        sign ^= x2 && z2 && x1 && !z1;\n    }\n}\n\ntemplate <size_t W>\nvoid PauliStringRef<W>::do_YCY(const CircuitInstruction &inst) {\n    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n        size_t q1 = inst.targets[k].data, q2 = inst.targets[k + 1].data;\n        bit_ref x1 = xs[q1], z1 = zs[q1], x2 = xs[q2], z2 = zs[q2];\n        bool y1 = x1 ^ z1;\n        bool y2 = x2 ^ z2;\n        x1 ^= y2;\n        z1 ^= y2;\n        x2 ^= y1;\n        z2 ^= y1;\n        sign ^= x1 && !z1 && !x2 && z2;\n        sign ^= !x1 && z1 && x2 && !z2;\n    }\n}\n\ntemplate <size_t W>\ntemplate <bool reverse_order>\nvoid PauliStringRef<W>::do_YCZ(const CircuitInstruction &inst) {\n    const auto &targets = inst.targets;\n    assert((targets.size() & 1) == 0);\n    for (size_t k = 0; k < targets.size(); k += 2) {\n        size_t k2 = reverse_order ? targets.size() - 2 - k : k;\n        size_t q1 = targets[k2].data, q2 = targets[k2 + 1].data;\n        do_single_cy(inst, q2, q1);\n    }\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/stabilizers/pauli_string_ref.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/pauli_string_ref.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\ntemplate <size_t W>\nvoid check_pauli_string_do_instruction_agrees_with_tableau_sim(Gate gate, TableauSimulator<W> &sim) {\n    std::vector<GateTarget> targets{\n        GateTarget::qubit(3),\n        GateTarget::qubit(5),\n        GateTarget::qubit(8),\n        GateTarget::qubit(5),\n    };\n    CircuitInstruction inst{gate.id, {}, targets, \"\"};\n\n    std::vector<PauliString<W>> before;\n    for (size_t k = 0; k < 16; k++) {\n        sim.inv_state.zs[k].sign = false;\n        before.push_back(sim.inv_state.zs[k]);\n    }\n    auto tableau = gate.tableau<W>();\n    if (gate.flags & GATE_TARGETS_PAIRS) {\n        sim.inv_state.inplace_scatter_append(tableau, {3, 5});\n        sim.inv_state.inplace_scatter_append(tableau, {8, 5});\n    } else {\n        sim.inv_state.inplace_scatter_append(tableau, {3});\n        sim.inv_state.inplace_scatter_append(tableau, {5});\n        sim.inv_state.inplace_scatter_append(tableau, {8});\n        sim.inv_state.inplace_scatter_append(tableau, {5});\n    }\n\n    PauliString<W> v(0);\n    for (size_t k = 0; k < before.size(); k++) {\n        v = before[k];\n        v.ref().do_instruction(inst);\n        if (v != sim.inv_state.zs[k]) {\n            EXPECT_EQ(v, sim.inv_state.zs[k]) << \"do_\" << gate.name << \"\\nbefore=\" << before[k];\n            return;\n        }\n\n        v.ref().undo_instruction(inst);\n        if (v != before[k]) {\n            EXPECT_EQ(v, sim.inv_state.zs[k]) << \"undo_\" << gate.name;\n            return;\n        }\n    }\n}\n\nTEST_EACH_WORD_SIZE_W(pauli_string, do_instruction_agrees_with_tableau_sim, {\n    TableauSimulator<W> sim(INDEPENDENT_TEST_RNG(), 16);\n    sim.inv_state = Tableau<W>::random(sim.inv_state.num_qubits, sim.rng);\n\n    for (const auto &gate : GATE_DATA.items) {\n        if (gate.has_known_unitary_matrix()) {\n            check_pauli_string_do_instruction_agrees_with_tableau_sim<W>(gate, sim);\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, intersects, {\n    ASSERT_FALSE((PauliString<W>(\"_\").ref().intersects(PauliString<W>(\"_\"))));\n    ASSERT_FALSE((PauliString<W>(\"_\").ref().intersects(PauliString<W>(\"X\"))));\n    ASSERT_FALSE((PauliString<W>(\"_\").ref().intersects(PauliString<W>(\"Y\"))));\n    ASSERT_FALSE((PauliString<W>(\"_\").ref().intersects(PauliString<W>(\"Z\"))));\n    ASSERT_FALSE((PauliString<W>(\"X\").ref().intersects(PauliString<W>(\"_\"))));\n    ASSERT_TRUE((PauliString<W>(\"X\").ref().intersects(PauliString<W>(\"X\"))));\n    ASSERT_TRUE((PauliString<W>(\"X\").ref().intersects(PauliString<W>(\"Y\"))));\n    ASSERT_TRUE((PauliString<W>(\"X\").ref().intersects(PauliString<W>(\"Z\"))));\n    ASSERT_FALSE((PauliString<W>(\"Y\").ref().intersects(PauliString<W>(\"_\"))));\n    ASSERT_TRUE((PauliString<W>(\"Y\").ref().intersects(PauliString<W>(\"X\"))));\n    ASSERT_TRUE((PauliString<W>(\"Y\").ref().intersects(PauliString<W>(\"Y\"))));\n    ASSERT_TRUE((PauliString<W>(\"Y\").ref().intersects(PauliString<W>(\"Z\"))));\n    ASSERT_FALSE((PauliString<W>(\"Z\").ref().intersects(PauliString<W>(\"_\"))));\n    ASSERT_TRUE((PauliString<W>(\"Z\").ref().intersects(PauliString<W>(\"X\"))));\n    ASSERT_TRUE((PauliString<W>(\"Z\").ref().intersects(PauliString<W>(\"Y\"))));\n    ASSERT_TRUE((PauliString<W>(\"Z\").ref().intersects(PauliString<W>(\"Z\"))));\n\n    ASSERT_TRUE((PauliString<W>(\"_Z\").ref().intersects(PauliString<W>(\"ZZ\"))));\n    ASSERT_TRUE((PauliString<W>(\"Z_\").ref().intersects(PauliString<W>(\"ZZ\"))));\n    ASSERT_TRUE((PauliString<W>(\"ZZ\").ref().intersects(PauliString<W>(\"ZZ\"))));\n    ASSERT_FALSE((PauliString<W>(\"ZZ\").ref().intersects(PauliString<W>(\"__\"))));\n    ASSERT_FALSE((PauliString<W>(\"__\").ref().intersects(PauliString<W>(\"XZ\"))));\n    ASSERT_FALSE((PauliString<W>(\"________________________________________________\")\n                      .ref()\n                      .intersects(PauliString<W>(\"________________________________________________\"))));\n    ASSERT_TRUE((PauliString<W>(\"_______________________________________X________\")\n                     .ref()\n                     .intersects(PauliString<W>(\"_______________________________________X________\"))));\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, weight, {\n    ASSERT_EQ(PauliString<W>::from_str(\"+\").ref().weight(), 0);\n    ASSERT_EQ(PauliString<W>::from_str(\"+I\").ref().weight(), 0);\n    ASSERT_EQ(PauliString<W>::from_str(\"+X\").ref().weight(), 1);\n    ASSERT_EQ(PauliString<W>::from_str(\"+Y\").ref().weight(), 1);\n    ASSERT_EQ(PauliString<W>::from_str(\"+Z\").ref().weight(), 1);\n\n    ASSERT_EQ(PauliString<W>::from_str(\"+IX\").ref().weight(), 1);\n    ASSERT_EQ(PauliString<W>::from_str(\"+XZ\").ref().weight(), 2);\n    ASSERT_EQ(PauliString<W>::from_str(\"+YY\").ref().weight(), 2);\n    ASSERT_EQ(PauliString<W>::from_str(\"+XI\").ref().weight(), 1);\n\n    PauliString<W> p(1000);\n    ASSERT_EQ(p.ref().weight(), 0);\n    for (size_t k = 0; k < 1000; k++) {\n        p.xs[k] = k % 3 == 1;\n        p.zs[k] = k % 5 == 1;\n    }\n    ASSERT_EQ(p.ref().weight(), 333 + 199 - 66);\n    p.sign = true;\n    ASSERT_EQ(p.ref().weight(), 333 + 199 - 66);\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, has_no_pauli_terms, {\n    ASSERT_EQ((PauliString<W>::from_str(\"+\").ref().has_no_pauli_terms()), true);\n    ASSERT_EQ((PauliString<W>::from_str(\"+I\").ref().has_no_pauli_terms()), true);\n    ASSERT_EQ((PauliString<W>::from_str(\"+X\").ref().has_no_pauli_terms()), false);\n    ASSERT_EQ((PauliString<W>::from_str(\"+Y\").ref().has_no_pauli_terms()), false);\n    ASSERT_EQ((PauliString<W>::from_str(\"+Z\").ref().has_no_pauli_terms()), false);\n\n    ASSERT_EQ((PauliString<W>::from_str(\"+II\").ref().has_no_pauli_terms()), true);\n    ASSERT_EQ((PauliString<W>::from_str(\"+IX\").ref().has_no_pauli_terms()), false);\n    ASSERT_EQ((PauliString<W>::from_str(\"+XZ\").ref().has_no_pauli_terms()), false);\n    ASSERT_EQ((PauliString<W>::from_str(\"+YY\").ref().has_no_pauli_terms()), false);\n    ASSERT_EQ((PauliString<W>::from_str(\"+XI\").ref().has_no_pauli_terms()), false);\n\n    PauliString<W> p(1000);\n    ASSERT_TRUE(p.ref().has_no_pauli_terms());\n    p.xs[700] = true;\n    ASSERT_FALSE(p.ref().has_no_pauli_terms());\n    p.zs[700] = true;\n    ASSERT_FALSE(p.ref().has_no_pauli_terms());\n    p.xs[700] = false;\n    ASSERT_FALSE(p.ref().has_no_pauli_terms());\n})\n\nTEST_EACH_WORD_SIZE_W(pauli_string, for_each_active_pauli, {\n    auto v = PauliString<W>(500);\n    v.zs[0] = true;\n    v.xs[20] = true;\n    v.xs[50] = true;\n    v.zs[50] = true;\n    v.xs[63] = true;\n    v.zs[63] = true;\n    v.zs[100] = true;\n    v.xs[200] = true;\n    v.xs[301] = true;\n    v.zs[301] = true;\n    std::vector<size_t> indices;\n    v.ref().for_each_active_pauli([&](size_t index) {\n        indices.push_back(index);\n    });\n    ASSERT_EQ(indices, (std::vector<size_t>{0, 20, 50, 63, 100, 200, 301}));\n})\n"
  },
  {
    "path": "src/stim/stabilizers/tableau.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_STABILIZERS_TABLEAU_H\n#define _STIM_STABILIZERS_TABLEAU_H\n\n#include <complex>\n#include <iostream>\n#include <unordered_map>\n\n#include \"stim/mem/simd_bit_table.h\"\n#include \"stim/mem/simd_util.h\"\n#include \"stim/mem/span_ref.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nstruct TableauHalf {\n    size_t num_qubits;\n    simd_bit_table<W> xt;\n    simd_bit_table<W> zt;\n    simd_bits<W> signs;\n    PauliStringRef<W> operator[](size_t input_qubit);\n    const PauliStringRef<W> operator[](size_t input_qubit) const;\n    TableauHalf(size_t num_qubits);\n};\n\n/// A Tableau is a stabilizer tableau representation of a Clifford operation.\n/// It stores, for each X and Z observable for each qubit, what is produced when\n/// conjugating that observable by the operation. In other words, it explains how\n/// to transform \"input side\" Pauli products into \"output side\" Pauli products.\n///\n/// The memory layout used by this class is column major, meaning iterating over\n/// the output observable is iterating along the grain of memory. This makes\n/// prepending operations cheap. To append operations, use TableauTransposedRaii.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstruct Tableau {\n    size_t num_qubits;\n    TableauHalf<W> xs;\n    TableauHalf<W> zs;\n\n    explicit Tableau(size_t num_qubits);\n    bool operator==(const Tableau &other) const;\n    bool operator!=(const Tableau &other) const;\n\n    PauliString<W> eval_y_obs(size_t qubit) const;\n\n    std::string str() const;\n\n    /// Grows the size of the tableau (or leaves it the same) by adding\n    /// new rows and columns with identity elements along the diagonal.\n    ///\n    /// Requires:\n    ///     new_num_qubits >= this.num_qubits\n    ///     resize_pad_factor >= 1\n    ///\n    /// Args:\n    ///     new_num_qubits: The new number of qubits the tableau represents.\n    ///     resize_pad_factor: When resizing, memory will be overallocated\n    ///          so that the tableau can be expanded to at least this many\n    ///          times the number of requested qubits. Use this to avoid\n    ///          quadratic overheads from constant slight expansions.\n    void expand(size_t new_num_qubits, double resize_pad_factor);\n\n    /// Creates a Tableau representing the identity operation.\n    static Tableau<W> identity(size_t num_qubits);\n    /// Creates a Tableau from a PauliString via conjugation\n    static Tableau<W> from_pauli_string(const PauliString<W> &pauli_string);\n    /// Creates a Tableau representing a randomly sampled Clifford operation from a uniform distribution.\n    static Tableau<W> random(size_t num_qubits, std::mt19937_64 &rng);\n    /// Returns the inverse Tableau.\n    ///\n    /// Args:\n    ///     skip_signs: Instead of computing the signs, just set them all to positive.\n    Tableau<W> inverse(bool skip_signs = false) const;\n    /// Returns the Tableau raised to an integer power (using repeated squaring).\n    Tableau<W> raised_to(int64_t exponent) const;\n\n    std::vector<std::complex<float>> to_flat_unitary_matrix(bool little_endian) const;\n    bool satisfies_invariants() const;\n\n    /// If a Tableau fixes each pauli upto sign, then it is conjugation by a pauli\n    bool is_pauli_product() const;\n\n    /// If tableau is conjugation by a pauli, then return that pauli. Else throw exception.\n    PauliString<W> to_pauli_string() const;\n\n    /// Creates a Tableau representing a single qubit gate.\n    ///\n    /// All observables specified using the string format accepted by `PauliString::from_str`.\n    /// For example: \"-X\" or \"+Y\".\n    ///\n    /// Args:\n    ///    x: The output-side observable that the input-side X observable gets mapped to.\n    ///    z: The output-side observable that the input-side Y observable gets mapped to.\n    static Tableau<W> gate1(const char *x, const char *z);\n\n    /// Creates a Tableau representing a two qubit gate.\n    ///\n    /// All observables specified using the string format accepted by `PauliString::from_str`.\n    /// For example: \"-IX\" or \"+YZ\".\n    ///\n    /// Args:\n    ///    x1: The output-side observable that the input-side XI observable gets mapped to.\n    ///    z1: The output-side observable that the input-side YI observable gets mapped to.\n    ///    x2: The output-side observable that the input-side IX observable gets mapped to.\n    ///    z2: The output-side observable that the input-side IY observable gets mapped to.\n    static Tableau<W> gate2(const char *x1, const char *z1, const char *x2, const char *z2);\n\n    /// Returns the result of applying the tableau to the given Pauli string.\n    ///\n    /// Args:\n    ///     p: The input-side Pauli string.\n    ///\n    /// Returns:\n    ///     The output-side Pauli string.\n    ///     Algebraically: $c p c^{-1}$ where $c$ is the tableau's Clifford operation.\n    PauliString<W> operator()(const PauliStringRef<W> &p) const;\n\n    /// Returns the result of applying the tableau to `gathered_input.scatter(scattered_indices)`.\n    PauliString<W> scatter_eval(\n        const PauliStringRef<W> &gathered_input, const std::vector<size_t> &scattered_indices) const;\n\n    /// Returns a tableau equivalent to the composition of two tableaus of the same size.\n    Tableau<W> then(const Tableau<W> &second) const;\n\n    /// Applies the Tableau inplace to a subset of a Pauli string.\n    void apply_within(PauliStringRef<W> &target, SpanRef<const size_t> target_qubits) const;\n\n    /// Appends a smaller operation into this tableau's operation.\n    ///\n    /// The new value T' of this tableau will equal the composition T o P = PT where T is the old\n    /// value of this tableau and P is the operation to append.\n    ///\n    /// Args:\n    ///     operation: The smaller operation to append into this tableau.\n    ///     target_qubits: The qubits being acted on by `operation`.\n    void inplace_scatter_append(const Tableau<W> &operation, const std::vector<size_t> &target_qubits);\n\n    /// Prepends a smaller operation into this tableau's operation.\n    ///\n    /// The new value T' of this tableau will equal the composition P o T = TP where T is the old\n    /// value of this tableau and P is the operation to append.\n    ///\n    /// Args:\n    ///     operation: The smaller operation to prepend into this tableau.\n    ///     target_qubits: The qubits being acted on by `operation`.\n    void inplace_scatter_prepend(const Tableau<W> &operation, const std::vector<size_t> &target_qubits);\n\n    /// Applies a transpose to the X2X, X2Z, Z2X, and Z2Z bit tables within the tableau.\n    void do_transpose_quadrants();\n\n    /// Returns the direct sum of two tableaus.\n    Tableau<W> operator+(const Tableau<W> &second) const;\n    /// Appends the other tableau onto this one, resulting in the direct sum.\n    Tableau<W> &operator+=(const Tableau<W> &second);\n\n    /// === Specialized vectorized methods for prepending operations onto the tableau === ///\n    void prepend_SWAP(size_t q1, size_t q2);\n    void prepend_X(size_t q);\n    void prepend_Y(size_t q);\n    void prepend_Z(size_t q);\n    void prepend_H_XZ(size_t q);\n    void prepend_H_YZ(size_t q);\n    void prepend_H_XY(size_t q);\n    void prepend_H_NXY(size_t q);\n    void prepend_H_NXZ(size_t q);\n    void prepend_H_NYZ(size_t q);\n    void prepend_C_XYZ(size_t q);\n    void prepend_C_NXYZ(size_t q);\n    void prepend_C_XNYZ(size_t q);\n    void prepend_C_XYNZ(size_t q);\n    void prepend_C_ZYX(size_t q);\n    void prepend_C_NZYX(size_t q);\n    void prepend_C_ZNYX(size_t q);\n    void prepend_C_ZYNX(size_t q);\n    void prepend_SQRT_X(size_t q);\n    void prepend_SQRT_X_DAG(size_t q);\n    void prepend_SQRT_Y(size_t q);\n    void prepend_SQRT_Y_DAG(size_t q);\n    void prepend_SQRT_Z(size_t q);\n    void prepend_SQRT_Z_DAG(size_t q);\n    void prepend_SQRT_XX(size_t q1, size_t q2);\n    void prepend_SQRT_XX_DAG(size_t q1, size_t q2);\n    void prepend_SQRT_YY(size_t q1, size_t q2);\n    void prepend_SQRT_YY_DAG(size_t q1, size_t q2);\n    void prepend_SQRT_ZZ(size_t q1, size_t q2);\n    void prepend_SQRT_ZZ_DAG(size_t q1, size_t q2);\n    void prepend_ZCX(size_t control, size_t target);\n    void prepend_ZCY(size_t control, size_t target);\n    void prepend_ZCZ(size_t control, size_t target);\n    void prepend_ISWAP(size_t q1, size_t q2);\n    void prepend_ISWAP_DAG(size_t q1, size_t q2);\n    void prepend_XCX(size_t control, size_t target);\n    void prepend_XCY(size_t control, size_t target);\n    void prepend_XCZ(size_t control, size_t target);\n    void prepend_YCX(size_t control, size_t target);\n    void prepend_YCY(size_t control, size_t target);\n    void prepend_YCZ(size_t control, size_t target);\n    void prepend_pauli_product(const PauliStringRef<W> &op);\n\n    /// Builds the Y output by using Y = iXZ.\n    PauliString<W> y_output(size_t input_index) const;\n\n    /// Constant-time version of tableau.xs[input_index][output_index].\n    uint8_t x_output_pauli_xyz(size_t input_index, size_t output_index) const;\n    /// Constant-time version of tableau.y_output(input_index)[output_index].\n    uint8_t y_output_pauli_xyz(size_t input_index, size_t output_index) const;\n    /// Constant-time version of tableau.zs[input_index][output_index].\n    uint8_t z_output_pauli_xyz(size_t input_index, size_t output_index) const;\n    /// Constant-time version of tableau.inverse().xs[input_index][output_index].\n    uint8_t inverse_x_output_pauli_xyz(size_t input_index, size_t output_index) const;\n    /// Constant-time version of tableau.inverse().y_output(input_index)[output_index].\n    uint8_t inverse_y_output_pauli_xyz(size_t input_index, size_t output_index) const;\n    /// Constant-time version of tableau.inverse().zs[input_index][output_index].\n    uint8_t inverse_z_output_pauli_xyz(size_t input_index, size_t output_index) const;\n    /// Faster version of tableau.inverse().xs[input_index].\n    PauliString<W> inverse_x_output(size_t input_index, bool skip_sign = false) const;\n    /// Faster version of tableau.inverse().y_output(input_index).\n    PauliString<W> inverse_y_output(size_t input_index, bool skip_sign = false) const;\n    /// Faster version of tableau.inverse().zs[input_index].\n    PauliString<W> inverse_z_output(size_t input_index, bool skip_sign = false) const;\n\n    std::vector<PauliString<W>> stabilizers(bool canonical) const;\n};\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const Tableau<W> &ps);\n\n}  // namespace stim\n\n#include \"stim/stabilizers/tableau.inl\"\n#include \"stim/stabilizers/tableau_specialized_prepend.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/tableau.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <cassert>\n#include <cmath>\n#include <cstring>\n#include <iostream>\n#include <map>\n#include <random>\n\n#include \"stim/gates/gates.h\"\n#include \"stim/simulators/vector_simulator.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nvoid Tableau<W>::expand(size_t new_num_qubits, double resize_pad_factor) {\n    // If the new qubits fit inside the padding, just extend into it.\n    assert(new_num_qubits >= num_qubits);\n    assert(resize_pad_factor >= 1);\n    if (new_num_qubits <= xs.xt.num_major_bits_padded()) {\n        size_t old_num_qubits = num_qubits;\n        num_qubits = new_num_qubits;\n        xs.num_qubits = new_num_qubits;\n        zs.num_qubits = new_num_qubits;\n        // Initialize identity elements along the diagonal.\n        for (size_t k = old_num_qubits; k < new_num_qubits; k++) {\n            xs[k].xs[k] = true;\n            zs[k].zs[k] = true;\n        }\n        return;\n    }\n\n    // Move state to temporary storage then re-allocate to make room for additional qubits.\n    size_t old_num_simd_words = xs.xt.num_simd_words_major;\n    size_t old_num_qubits = num_qubits;\n    Tableau<W> old_state = std::move(*this);\n    *this = Tableau<W>((size_t)(new_num_qubits * resize_pad_factor));\n    this->num_qubits = new_num_qubits;\n    this->xs.num_qubits = new_num_qubits;\n    this->zs.num_qubits = new_num_qubits;\n\n    // Copy stored state back into new larger space.\n    auto partial_copy = [=](simd_bits_range_ref<W> dst, simd_bits_range_ref<W> src) {\n        dst.word_range_ref(0, old_num_simd_words) = src;\n    };\n    partial_copy(xs.signs, old_state.xs.signs);\n    partial_copy(zs.signs, old_state.zs.signs);\n    for (size_t k = 0; k < old_num_qubits; k++) {\n        partial_copy(xs[k].xs, old_state.xs[k].xs);\n        partial_copy(xs[k].zs, old_state.xs[k].zs);\n        partial_copy(zs[k].xs, old_state.zs[k].xs);\n        partial_copy(zs[k].zs, old_state.zs[k].zs);\n    }\n}\n\ntemplate <size_t W>\nPauliStringRef<W> TableauHalf<W>::operator[](size_t input_qubit) {\n    size_t nw = (num_qubits + W - 1) / W;\n    return PauliStringRef<W>(\n        num_qubits, signs[input_qubit], xt[input_qubit].word_range_ref(0, nw), zt[input_qubit].word_range_ref(0, nw));\n}\n\ntemplate <size_t W>\nconst PauliStringRef<W> TableauHalf<W>::operator[](size_t input_qubit) const {\n    size_t nw = (num_qubits + W - 1) / W;\n    return PauliStringRef<W>(\n        num_qubits, signs[input_qubit], xt[input_qubit].word_range_ref(0, nw), zt[input_qubit].word_range_ref(0, nw));\n}\n\ntemplate <size_t W>\nPauliString<W> Tableau<W>::eval_y_obs(size_t qubit) const {\n    PauliString<W> result(xs[qubit]);\n    uint8_t log_i = result.ref().inplace_right_mul_returning_log_i_scalar(zs[qubit]);\n    log_i++;\n    assert((log_i & 1) == 0);\n    if (log_i & 2) {\n        result.sign ^= true;\n    }\n    return result;\n}\n\ntemplate <size_t W>\nTableau<W>::Tableau(size_t num_qubits) : num_qubits(num_qubits), xs(num_qubits), zs(num_qubits) {\n    for (size_t q = 0; q < num_qubits; q++) {\n        xs.xt[q][q] = true;\n        zs.zt[q][q] = true;\n    }\n}\n\ntemplate <size_t W>\nTableauHalf<W>::TableauHalf(size_t num_qubits)\n    : num_qubits(num_qubits), xt(num_qubits, num_qubits), zt(num_qubits, num_qubits), signs(num_qubits) {\n}\n\ntemplate <size_t W>\nTableau<W> Tableau<W>::identity(size_t num_qubits) {\n    return Tableau<W>(num_qubits);\n}\n\ntemplate <size_t W>\nTableau<W> Tableau<W>::from_pauli_string(const PauliString<W> &pauli_string) {\n    Tableau<W> tableau = identity(pauli_string.num_qubits);\n    tableau.xs.signs = pauli_string.zs;\n    tableau.zs.signs = pauli_string.xs;\n    return tableau;\n}\n\ntemplate <size_t W>\nTableau<W> Tableau<W>::gate1(const char *x, const char *z) {\n    Tableau<W> result(1);\n    result.xs[0] = PauliString<W>::from_str(x);\n    result.zs[0] = PauliString<W>::from_str(z);\n    assert((bool)result.zs[0].sign == (z[0] == '-'));\n    return result;\n}\n\ntemplate <size_t W>\nTableau<W> Tableau<W>::gate2(const char *x1, const char *z1, const char *x2, const char *z2) {\n    Tableau<W> result(2);\n    result.xs[0] = PauliString<W>::from_str(x1);\n    result.zs[0] = PauliString<W>::from_str(z1);\n    result.xs[1] = PauliString<W>::from_str(x2);\n    result.zs[1] = PauliString<W>::from_str(z2);\n    return result;\n}\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const Tableau<W> &t) {\n    out << \"+-\";\n    for (size_t k = 0; k < t.num_qubits; k++) {\n        out << 'x';\n        out << 'z';\n        out << '-';\n    }\n    out << \"\\n|\";\n    for (size_t k = 0; k < t.num_qubits; k++) {\n        out << ' ';\n        out << \"+-\"[t.xs[k].sign];\n        out << \"+-\"[t.zs[k].sign];\n    }\n    for (size_t q = 0; q < t.num_qubits; q++) {\n        out << \"\\n|\";\n        for (size_t k = 0; k < t.num_qubits; k++) {\n            out << ' ';\n            auto x = t.xs[k];\n            auto z = t.zs[k];\n            out << \"_XZY\"[x.xs[q] + 2 * x.zs[q]];\n            out << \"_XZY\"[z.xs[q] + 2 * z.zs[q]];\n        }\n    }\n    return out;\n}\n\ntemplate <size_t W>\nstd::string Tableau<W>::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::inplace_scatter_append(const Tableau<W> &operation, const std::vector<size_t> &target_qubits) {\n    assert(operation.num_qubits == target_qubits.size());\n    if (&operation == this) {\n        Tableau<W> independent_copy(operation);\n        inplace_scatter_append(independent_copy, target_qubits);\n        return;\n    }\n    for (size_t q = 0; q < num_qubits; q++) {\n        auto x = xs[q];\n        auto z = zs[q];\n        operation.apply_within(x, target_qubits);\n        operation.apply_within(z, target_qubits);\n    }\n}\n\ntemplate <size_t W>\nbool truncated_bits_equals(size_t nw, const simd_bits_range_ref<W> &t1, const simd_bits_range_ref<W> &t2) {\n    return t1.word_range_ref(0, nw) == t2.word_range_ref(0, nw);\n}\n\ntemplate <size_t W>\nbool truncated_tableau_equals(size_t n, const simd_bit_table<W> &t1, const simd_bit_table<W> &t2) {\n    size_t nw = (n + W - 1) / W;\n    for (size_t k = 0; k < n; k++) {\n        if (!truncated_bits_equals(nw, t1[k], t2[k])) {\n            return false;\n        }\n    }\n    return true;\n}\n\ntemplate <size_t W>\nbool Tableau<W>::operator==(const Tableau<W> &other) const {\n    size_t nw = (num_qubits + W - 1) / W;\n    return num_qubits == other.num_qubits && truncated_tableau_equals(num_qubits, xs.xt, other.xs.xt) &&\n           truncated_tableau_equals(num_qubits, xs.zt, other.xs.zt) &&\n           truncated_tableau_equals(num_qubits, zs.xt, other.zs.xt) &&\n           truncated_tableau_equals(num_qubits, zs.zt, other.zs.zt) &&\n           xs.signs.word_range_ref(0, nw) == other.xs.signs.word_range_ref(0, nw) &&\n           zs.signs.word_range_ref(0, nw) == other.zs.signs.word_range_ref(0, nw);\n}\n\ntemplate <size_t W>\nbool Tableau<W>::operator!=(const Tableau<W> &other) const {\n    return !(*this == other);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::inplace_scatter_prepend(const Tableau<W> &operation, const std::vector<size_t> &target_qubits) {\n    assert(operation.num_qubits == target_qubits.size());\n    if (&operation == this) {\n        Tableau<W> independent_copy(operation);\n        inplace_scatter_prepend(independent_copy, target_qubits);\n        return;\n    }\n\n    std::vector<PauliString<W>> new_x;\n    std::vector<PauliString<W>> new_z;\n    new_x.reserve(operation.num_qubits);\n    new_z.reserve(operation.num_qubits);\n    for (size_t q = 0; q < operation.num_qubits; q++) {\n        new_x.push_back(scatter_eval(operation.xs[q], target_qubits));\n        new_z.push_back(scatter_eval(operation.zs[q], target_qubits));\n    }\n    for (size_t q = 0; q < operation.num_qubits; q++) {\n        xs[target_qubits[q]] = new_x[q];\n        zs[target_qubits[q]] = new_z[q];\n    }\n}\n\ntemplate <size_t W>\nPauliString<W> Tableau<W>::scatter_eval(\n    const PauliStringRef<W> &gathered_input, const std::vector<size_t> &scattered_indices) const {\n    assert(gathered_input.num_qubits == scattered_indices.size());\n    auto result = PauliString<W>(num_qubits);\n    result.sign = gathered_input.sign;\n    for (size_t k_gathered = 0; k_gathered < gathered_input.num_qubits; k_gathered++) {\n        size_t k_scattered = scattered_indices[k_gathered];\n        bool x = gathered_input.xs[k_gathered];\n        bool z = gathered_input.zs[k_gathered];\n        if (x) {\n            if (z) {\n                // Multiply by Y using Y = i*X*Z.\n                uint8_t log_i = 1;\n                log_i += result.ref().inplace_right_mul_returning_log_i_scalar(xs[k_scattered]);\n                log_i += result.ref().inplace_right_mul_returning_log_i_scalar(zs[k_scattered]);\n                assert((log_i & 1) == 0);\n                result.sign ^= (log_i & 2) != 0;\n            } else {\n                result.ref() *= xs[k_scattered];\n            }\n        } else if (z) {\n            result.ref() *= zs[k_scattered];\n        }\n    }\n    return result;\n}\n\ntemplate <size_t W>\nPauliString<W> Tableau<W>::operator()(const PauliStringRef<W> &p) const {\n    if (p.num_qubits != num_qubits) {\n        throw std::out_of_range(\"pauli_string.num_qubits != tableau.num_qubits\");\n    }\n    std::vector<size_t> indices;\n    for (size_t k = 0; k < p.num_qubits; k++) {\n        indices.push_back(k);\n    }\n    return scatter_eval(p, indices);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::apply_within(PauliStringRef<W> &target, SpanRef<const size_t> target_qubits) const {\n    assert(num_qubits == target_qubits.size());\n    auto inp = PauliString<W>(num_qubits);\n    target.gather_into(inp, target_qubits);\n    auto out = (*this)(inp);\n    out.ref().scatter_into(target, target_qubits);\n}\n\n/// Samples a vector of bits and a permutation from a skewed distribution.\n///\n/// Reference:\n///     \"Hadamard-free circuits expose the structure of the Clifford group\"\n///     Sergey Bravyi, Dmitri Maslov\n///     https://arxiv.org/abs/2003.09412\ninline std::pair<std::vector<bool>, std::vector<size_t>> sample_qmallows(size_t n, std::mt19937_64 &gen) {\n    auto uni = std::uniform_real_distribution<double>(0, 1);\n\n    std::vector<bool> hada;\n    std::vector<size_t> permutation;\n    std::vector<size_t> remaining_indices;\n    for (size_t k = 0; k < n; k++) {\n        remaining_indices.push_back(k);\n    }\n    for (size_t i = 0; i < n; i++) {\n        auto m = remaining_indices.size();\n        auto u = uni(gen);\n        auto eps = pow(4, -(int)m);\n        auto k = (size_t)-ceil(log2(u + (1 - u) * eps));\n        hada.push_back(k < m);\n        if (k >= m) {\n            k = 2 * m - k - 1;\n        }\n        permutation.push_back(remaining_indices[k]);\n        remaining_indices.erase(remaining_indices.begin() + k);\n    }\n    return {hada, permutation};\n}\n\n/// Samples a random valid stabilizer tableau.\n///\n/// Reference:\n///     \"Hadamard-free circuits expose the structure of the Clifford group\"\n///     Sergey Bravyi, Dmitri Maslov\n///     https://arxiv.org/abs/2003.09412\ntemplate <size_t W>\nsimd_bit_table<W> random_stabilizer_tableau_raw(size_t n, std::mt19937_64 &rng) {\n    auto hs_pair = sample_qmallows(n, rng);\n    const auto &hada = hs_pair.first;\n    const auto &perm = hs_pair.second;\n\n    simd_bit_table<W> symmetric(n, n);\n    for (size_t row = 0; row < n; row++) {\n        symmetric[row].randomize(row + 1, rng);\n        for (size_t col = 0; col < row; col++) {\n            symmetric[col][row] = symmetric[row][col];\n        }\n    }\n\n    simd_bit_table<W> symmetric_m(n, n);\n    for (size_t row = 0; row < n; row++) {\n        symmetric_m[row].randomize(row + 1, rng);\n        symmetric_m[row][row] &= hada[row];\n        for (size_t col = 0; col < row; col++) {\n            bool b = hada[row] && hada[col];\n            b |= hada[row] > hada[col] && perm[row] < perm[col];\n            b |= hada[row] < hada[col] && perm[row] > perm[col];\n            symmetric_m[row][col] &= b;\n            symmetric_m[col][row] = symmetric_m[row][col];\n        }\n    }\n\n    auto lower = simd_bit_table<W>::identity(n);\n    for (size_t row = 0; row < n; row++) {\n        lower[row].randomize(row, rng);\n    }\n\n    auto lower_m = simd_bit_table<W>::identity(n);\n    for (size_t row = 0; row < n; row++) {\n        lower_m[row].randomize(row, rng);\n        for (size_t col = 0; col < row; col++) {\n            bool b = hada[row] < hada[col];\n            b |= hada[row] && hada[col] && perm[row] > perm[col];\n            b |= !hada[row] && !hada[col] && perm[row] < perm[col];\n            lower_m[row][col] &= b;\n        }\n    }\n\n    auto prod = symmetric.square_mat_mul(lower, n);\n    auto prod_m = symmetric_m.square_mat_mul(lower_m, n);\n\n    auto inv = lower.inverse_assuming_lower_triangular(n);\n    auto inv_m = lower_m.inverse_assuming_lower_triangular(n);\n    inv.do_square_transpose();\n    inv_m.do_square_transpose();\n\n    auto fused = simd_bit_table<W>::from_quadrants(n, lower, simd_bit_table<W>(n, n), prod, inv);\n    auto fused_m = simd_bit_table<W>::from_quadrants(n, lower_m, simd_bit_table<W>(n, n), prod_m, inv_m);\n\n    simd_bit_table<W> u(2 * n, 2 * n);\n\n    // Apply permutation.\n    for (size_t row = 0; row < n; row++) {\n        u[row] = fused[perm[row]];\n        u[row + n] = fused[perm[row] + n];\n    }\n    // Apply Hadamards.\n    for (size_t row = 0; row < n; row++) {\n        if (hada[row]) {\n            u[row].swap_with(u[row + n]);\n        }\n    }\n\n    return fused_m.square_mat_mul(u, 2 * n);\n}\n\ntemplate <size_t W>\nTableau<W> Tableau<W>::random(size_t num_qubits, std::mt19937_64 &rng) {\n    auto raw = random_stabilizer_tableau_raw<W>(num_qubits, rng);\n    Tableau result(num_qubits);\n    for (size_t row = 0; row < num_qubits; row++) {\n        for (size_t col = 0; col < num_qubits; col++) {\n            result.xs[row].xs[col] = raw[row][col];\n            result.xs[row].zs[col] = raw[row][col + num_qubits];\n            result.zs[row].xs[col] = raw[row + num_qubits][col];\n            result.zs[row].zs[col] = raw[row + num_qubits][col + num_qubits];\n        }\n    }\n    result.xs.signs.randomize(num_qubits, rng);\n    result.zs.signs.randomize(num_qubits, rng);\n    return result;\n}\n\ntemplate <size_t W>\nbool Tableau<W>::satisfies_invariants() const {\n    for (size_t q1 = 0; q1 < num_qubits; q1++) {\n        auto x1 = xs[q1];\n        auto z1 = zs[q1];\n        if (x1.commutes(z1)) {\n            return false;\n        }\n        for (size_t q2 = q1 + 1; q2 < num_qubits; q2++) {\n            auto x2 = xs[q2];\n            auto z2 = zs[q2];\n            if (!x1.commutes(x2) || !x1.commutes(z2) || !z1.commutes(x2) || !z1.commutes(z2)) {\n                return false;\n            }\n        }\n    }\n    return true;\n}\n\ntemplate <size_t W>\nbool Tableau<W>::is_pauli_product() const {\n    size_t pop_count = xs.xt.data.popcnt() + xs.zt.data.popcnt() + zs.xt.data.popcnt() + zs.zt.data.popcnt();\n\n    if (pop_count != 2 * num_qubits) {\n        return false;\n    }\n\n    for (size_t q = 0; q < num_qubits; q++) {\n        if (xs.xt[q][q] == false)\n            return false;\n    }\n\n    for (size_t q = 0; q < num_qubits; q++) {\n        if (zs.zt[q][q] == false)\n            return false;\n    }\n\n    return true;\n}\n\ntemplate <size_t W>\nPauliString<W> Tableau<W>::to_pauli_string() const {\n    if (!is_pauli_product()) {\n        throw std::invalid_argument(\"The Tableau isn't equivalent to a Pauli product.\");\n    }\n\n    PauliString<W> pauli_string(num_qubits);\n    pauli_string.xs = zs.signs;\n    pauli_string.zs = xs.signs;\n    return pauli_string;\n}\n\ntemplate <size_t W>\nTableau<W> Tableau<W>::inverse(bool skip_signs) const {\n    Tableau<W> result(xs.xt.num_major_bits_padded());\n    result.num_qubits = num_qubits;\n    result.xs.num_qubits = num_qubits;\n    result.zs.num_qubits = num_qubits;\n\n    // Transpose data with xx zz swap tweak.\n    result.xs.xt.data = zs.zt.data;\n    result.xs.zt.data = xs.zt.data;\n    result.zs.xt.data = zs.xt.data;\n    result.zs.zt.data = xs.xt.data;\n    result.do_transpose_quadrants();\n\n    // Fix signs by checking for consistent round trips.\n    if (!skip_signs) {\n        PauliString<W> singleton(num_qubits);\n        for (size_t k = 0; k < num_qubits; k++) {\n            singleton.xs[k] = true;\n            bool x_round_trip_sign = (*this)(result(singleton)).sign;\n            singleton.xs[k] = false;\n            singleton.zs[k] = true;\n            bool z_round_trip_sign = (*this)(result(singleton)).sign;\n            singleton.zs[k] = false;\n\n            result.xs[k].sign ^= x_round_trip_sign;\n            result.zs[k].sign ^= z_round_trip_sign;\n        }\n    }\n\n    return result;\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::do_transpose_quadrants() {\n    xs.xt.do_square_transpose();\n    xs.zt.do_square_transpose();\n    zs.xt.do_square_transpose();\n    zs.zt.do_square_transpose();\n}\n\ntemplate <size_t W>\nTableau<W> Tableau<W>::then(const Tableau<W> &second) const {\n    assert(num_qubits == second.num_qubits);\n    Tableau<W> result(num_qubits);\n    for (size_t q = 0; q < num_qubits; q++) {\n        result.xs[q] = second(xs[q]);\n        result.zs[q] = second(zs[q]);\n    }\n    return result;\n}\n\ntemplate <size_t W>\nTableau<W> Tableau<W>::raised_to(int64_t exponent) const {\n    Tableau<W> result(num_qubits);\n    if (exponent) {\n        Tableau<W> square = *this;\n\n        if (exponent < 0) {\n            square = square.inverse();\n            exponent *= -1;\n        }\n\n        while (true) {\n            if (exponent & 1) {\n                result = result.then(square);\n            }\n            exponent >>= 1;\n            if (exponent == 0) {\n                break;\n            }\n            square = square.then(square);\n        }\n    }\n    return result;\n}\n\ntemplate <size_t W>\nTableau<W> Tableau<W>::operator+(const Tableau<W> &second) const {\n    Tableau<W> copy = *this;\n    copy += second;\n    return copy;\n}\n\ntemplate <size_t W>\nTableau<W> &Tableau<W>::operator+=(const Tableau<W> &second) {\n    size_t n = num_qubits;\n    expand(n + second.num_qubits, 1.1);\n    for (size_t i = 0; i < second.num_qubits; i++) {\n        xs.signs[n + i] = second.xs.signs[i];\n        zs.signs[n + i] = second.zs.signs[i];\n        for (size_t j = 0; j < second.num_qubits; j++) {\n            xs.xt[n + i][n + j] = second.xs.xt[i][j];\n            xs.zt[n + i][n + j] = second.xs.zt[i][j];\n            zs.xt[n + i][n + j] = second.zs.xt[i][j];\n            zs.zt[n + i][n + j] = second.zs.zt[i][j];\n        }\n    }\n    return *this;\n}\n\ntemplate <size_t W>\nuint8_t Tableau<W>::x_output_pauli_xyz(size_t input_index, size_t output_index) const {\n    if (input_index >= num_qubits) {\n        throw std::invalid_argument(\"input_index >= len(tableau)\");\n    }\n    if (output_index >= num_qubits) {\n        throw std::invalid_argument(\"output_index >= len(tableau)\");\n    }\n    PauliStringRef<W> x = xs[input_index];\n    return pauli_xz_to_xyz(x.xs[output_index], x.zs[output_index]);\n}\n\ntemplate <size_t W>\nuint8_t Tableau<W>::y_output_pauli_xyz(size_t input_index, size_t output_index) const {\n    if (input_index >= num_qubits) {\n        throw std::invalid_argument(\"input_index >= len(tableau)\");\n    }\n    if (output_index >= num_qubits) {\n        throw std::invalid_argument(\"output_index >= len(tableau)\");\n    }\n    PauliStringRef<W> x = xs[input_index];\n    PauliStringRef<W> z = zs[input_index];\n    return pauli_xz_to_xyz(x.xs[output_index] ^ z.xs[output_index], x.zs[output_index] ^ z.zs[output_index]);\n}\n\ntemplate <size_t W>\nuint8_t Tableau<W>::z_output_pauli_xyz(size_t input_index, size_t output_index) const {\n    if (input_index >= num_qubits) {\n        throw std::invalid_argument(\"input_index >= len(tableau)\");\n    }\n    if (output_index >= num_qubits) {\n        throw std::invalid_argument(\"output_index >= len(tableau)\");\n    }\n    PauliStringRef<W> z = zs[input_index];\n    return pauli_xz_to_xyz(z.xs[output_index], z.zs[output_index]);\n}\n\ntemplate <size_t W>\nuint8_t Tableau<W>::inverse_x_output_pauli_xyz(size_t input_index, size_t output_index) const {\n    if (input_index >= num_qubits) {\n        throw std::invalid_argument(\"input_index >= len(tableau)\");\n    }\n    if (output_index >= num_qubits) {\n        throw std::invalid_argument(\"output_index >= len(tableau)\");\n    }\n    return pauli_xz_to_xyz(zs[output_index].zs[input_index], xs[output_index].zs[input_index]);\n}\n\ntemplate <size_t W>\nuint8_t Tableau<W>::inverse_y_output_pauli_xyz(size_t input_index, size_t output_index) const {\n    if (input_index >= num_qubits) {\n        throw std::invalid_argument(\"input_index >= len(tableau)\");\n    }\n    if (output_index >= num_qubits) {\n        throw std::invalid_argument(\"output_index >= len(tableau)\");\n    }\n    PauliStringRef<W> x = xs[output_index];\n    PauliStringRef<W> z = zs[output_index];\n    return pauli_xz_to_xyz(z.zs[input_index] ^ z.xs[input_index], x.zs[input_index] ^ x.xs[input_index]);\n}\n\ntemplate <size_t W>\nuint8_t Tableau<W>::inverse_z_output_pauli_xyz(size_t input_index, size_t output_index) const {\n    if (input_index >= num_qubits) {\n        throw std::invalid_argument(\"input_index >= len(tableau)\");\n    }\n    if (output_index >= num_qubits) {\n        throw std::invalid_argument(\"output_index >= len(tableau)\");\n    }\n    return pauli_xz_to_xyz(zs[output_index].xs[input_index], xs[output_index].xs[input_index]);\n}\n\ntemplate <size_t W>\nPauliString<W> Tableau<W>::inverse_x_output(size_t input_index, bool skip_sign) const {\n    if (input_index >= num_qubits) {\n        throw std::invalid_argument(\"input_index >= len(tableau)\");\n    }\n    PauliString<W> result(num_qubits);\n    for (size_t k = 0; k < num_qubits; k++) {\n        result.xs[k] = zs[k].zs[input_index];\n        result.zs[k] = xs[k].zs[input_index];\n    }\n    if (!skip_sign) {\n        result.sign = (*this)(result).sign;\n    }\n    return result;\n}\n\ntemplate <size_t W>\nPauliString<W> Tableau<W>::inverse_y_output(size_t input_index, bool skip_sign) const {\n    if (input_index >= num_qubits) {\n        throw std::invalid_argument(\"input_index >= len(tableau)\");\n    }\n    PauliString<W> result(num_qubits);\n    for (size_t k = 0; k < num_qubits; k++) {\n        result.xs[k] = zs[k].zs[input_index] ^ zs[k].xs[input_index];\n        result.zs[k] = xs[k].zs[input_index] ^ xs[k].xs[input_index];\n    }\n    if (!skip_sign) {\n        result.sign = (*this)(result).sign;\n    }\n    return result;\n}\n\ntemplate <size_t W>\nPauliString<W> Tableau<W>::inverse_z_output(size_t input_index, bool skip_sign) const {\n    if (input_index >= num_qubits) {\n        throw std::invalid_argument(\"input_index >= len(tableau)\");\n    }\n    PauliString<W> result(num_qubits);\n    for (size_t k = 0; k < num_qubits; k++) {\n        result.xs[k] = zs[k].xs[input_index];\n        result.zs[k] = xs[k].xs[input_index];\n    }\n    if (!skip_sign) {\n        result.sign = (*this)(result).sign;\n    }\n    return result;\n}\n\ntemplate <size_t W>\nstd::vector<std::complex<float>> Tableau<W>::to_flat_unitary_matrix(bool little_endian) const {\n    std::vector<PauliString<W>> pauli_strings;\n    size_t nw = xs[0].xs.num_simd_words;\n\n    // Add X transformation stabilizers.\n    for (size_t k = 0; k < num_qubits; k++) {\n        PauliString<W> p(num_qubits * 2);\n        p.xs.word_range_ref(0, nw) = xs[k].xs;\n        p.zs.word_range_ref(0, nw) = xs[k].zs;\n        p.sign = xs[k].sign;\n        p.xs[num_qubits + k] ^= true;\n        pauli_strings.push_back(p);\n    }\n\n    // Add Z transformation stabilizers.\n    for (size_t k = 0; k < num_qubits; k++) {\n        PauliString<W> p(num_qubits * 2);\n        p.xs.word_range_ref(0, nw) = zs[k].xs;\n        p.zs.word_range_ref(0, nw) = zs[k].zs;\n        p.sign = zs[k].sign;\n        p.zs[num_qubits + k] ^= true;\n        pauli_strings.push_back(p);\n    }\n\n    for (auto &p : pauli_strings) {\n        for (size_t q = 0; q < num_qubits - q - 1; q++) {\n            size_t q2 = num_qubits - q - 1;\n            if (!little_endian) {\n                p.xs[q].swap_with(p.xs[q2]);\n                p.zs[q].swap_with(p.zs[q2]);\n                p.xs[q + num_qubits].swap_with(p.xs[q2 + num_qubits]);\n                p.zs[q + num_qubits].swap_with(p.zs[q2 + num_qubits]);\n            }\n        }\n        for (size_t q = 0; q < num_qubits; q++) {\n            p.xs[q].swap_with(p.xs[q + num_qubits]);\n            p.zs[q].swap_with(p.zs[q + num_qubits]);\n        }\n    }\n\n    // Turn it into a vector.\n    std::vector<PauliStringRef<W>> refs;\n    for (const auto &e : pauli_strings) {\n        refs.push_back(e.ref());\n    }\n\n    return VectorSimulator::state_vector_from_stabilizers<W>(refs, 1 << num_qubits);\n}\n\ntemplate <size_t W>\nPauliString<W> Tableau<W>::y_output(size_t input_index) const {\n    uint8_t log_i = 1;\n    PauliString<W> result = xs[input_index];\n    log_i += result.ref().inplace_right_mul_returning_log_i_scalar(zs[input_index]);\n    assert((log_i & 1) == 0);\n    result.sign ^= (log_i & 2) != 0;\n    return result;\n}\n\ntemplate <size_t W>\nstd::vector<PauliString<W>> Tableau<W>::stabilizers(bool canonical) const {\n    std::vector<PauliString<W>> stabilizers;\n    for (size_t k = 0; k < num_qubits; k++) {\n        stabilizers.push_back(zs[k]);\n    }\n\n    if (canonical) {\n        size_t min_pivot = 0;\n        for (size_t q = 0; q < num_qubits; q++) {\n            for (size_t b = 0; b < 2; b++) {\n                size_t pivot = min_pivot;\n                while (pivot < num_qubits && !(b ? stabilizers[pivot].zs : stabilizers[pivot].xs)[q]) {\n                    pivot++;\n                }\n                if (pivot == num_qubits) {\n                    continue;\n                }\n                for (size_t s = 0; s < num_qubits; s++) {\n                    if (s != pivot && (b ? stabilizers[s].zs : stabilizers[s].xs)[q]) {\n                        stabilizers[s].ref() *= stabilizers[pivot];\n                    }\n                }\n                if (min_pivot != pivot) {\n                    std::swap(stabilizers[min_pivot], stabilizers[pivot]);\n                }\n                min_pivot += 1;\n            }\n        }\n    }\n\n    return stabilizers;\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/stabilizers/tableau.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/tableau.h\"\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(tableau_random_10) {\n    size_t n = 10;\n    Tableau<MAX_BITWORD_WIDTH> t(n);\n    std::mt19937_64 rng(0);\n    benchmark_go([&]() {\n        t = Tableau<MAX_BITWORD_WIDTH>::random(n, rng);\n    }).goal_micros(30);\n}\n\nBENCHMARK(tableau_random_100) {\n    size_t n = 100;\n    Tableau<MAX_BITWORD_WIDTH> t(n);\n    std::mt19937_64 rng(0);\n    benchmark_go([&]() {\n        t = Tableau<MAX_BITWORD_WIDTH>::random(n, rng);\n    }).goal_millis(1.1);\n}\n\nBENCHMARK(tableau_random_256) {\n    size_t n = 256;\n    Tableau<MAX_BITWORD_WIDTH> t(n);\n    std::mt19937_64 rng(0);\n    benchmark_go([&]() {\n        t = Tableau<MAX_BITWORD_WIDTH>::random(n, rng);\n    }).goal_millis(7.5);\n}\n\nBENCHMARK(tableau_random_1000) {\n    size_t n = 1000;\n    Tableau<MAX_BITWORD_WIDTH> t(n);\n    std::mt19937_64 rng(0);\n    benchmark_go([&]() {\n        t = Tableau<MAX_BITWORD_WIDTH>::random(n, rng);\n    }).goal_millis(130);\n}\n\nBENCHMARK(tableau_cnot_10Kqubits) {\n    size_t n = 10 * 1000;\n    Tableau<MAX_BITWORD_WIDTH> t(n);\n    benchmark_go([&]() {\n        t.prepend_ZCX(5, 20);\n    }).goal_nanos(170);\n}\n"
  },
  {
    "path": "src/stim/stabilizers/tableau.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/tableau.pybind.h\"\n\n#include \"flex_pauli_string.h\"\n#include \"stim/py/base.pybind.h\"\n#include \"stim/py/numpy.pybind.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/stabilizers/tableau.h\"\n#include \"stim/stabilizers/tableau_iter.h\"\n#include \"stim/util_top/circuit_vs_amplitudes.h\"\n#include \"stim/util_top/stabilizers_to_tableau.h\"\n#include \"stim/util_top/stabilizers_vs_amplitudes.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\nvoid check_tableau_signs_shape(const pybind11::object &numpy_array, size_t n, const char *name) {\n    if (pybind11::isinstance<pybind11::array_t<uint8_t>>(numpy_array)) {\n        auto arr = pybind11::cast<pybind11::array_t<uint8_t>>(numpy_array);\n        if (arr.ndim() == 1) {\n            size_t minor = arr.shape(0);\n            if (minor != (n + 7) / 8) {\n                std::stringstream ss;\n                ss << name << \" had dtype=uint8 (meaning it is bit packed) \";\n                ss << \"but its shape was \" << minor << \" instead of \";\n                ss << (n + 7) / 8 << \".\";\n                throw std::invalid_argument(ss.str());\n            }\n            return;\n        }\n    } else if (pybind11::isinstance<pybind11::array_t<bool>>(numpy_array)) {\n        auto arr = pybind11::cast<pybind11::array_t<bool>>(numpy_array);\n        if (arr.ndim() == 1) {\n            size_t minor = arr.shape(0);\n            if (minor != n) {\n                std::stringstream ss;\n                ss << name << \" had dtype=bool_ \";\n                ss << \"but its shape was \" << minor << \" instead of \";\n                ss << n << \".\";\n                throw std::invalid_argument(ss.str());\n            }\n        }\n        return;\n    }\n\n    std::stringstream ss;\n    ss << name << \" wasn't a 1d numpy array with dtype=bool_ or dtype=uint8\";\n    throw std::invalid_argument(ss.str());\n}\n\nvoid check_tableau_shape(const pybind11::object &numpy_array, size_t n, const char *name) {\n    if (pybind11::isinstance<pybind11::array_t<uint8_t>>(numpy_array)) {\n        auto arr = pybind11::cast<pybind11::array_t<uint8_t>>(numpy_array);\n        if (arr.ndim() == 2) {\n            size_t major = arr.shape(0);\n            size_t minor = arr.shape(1);\n            if (major != n || minor != (n + 7) / 8) {\n                std::stringstream ss;\n                ss << name << \" had dtype=uint8 (meaning it is bit packed) \";\n                ss << \"but its shape was (\" << major << \", \" << minor << \") instead of (\";\n                ss << n << \", \" << (n + 7) / 8 << \").\";\n                throw std::invalid_argument(ss.str());\n            }\n            return;\n        }\n    } else if (pybind11::isinstance<pybind11::array_t<bool>>(numpy_array)) {\n        auto arr = pybind11::cast<pybind11::array_t<bool>>(numpy_array);\n        if (arr.ndim() == 2) {\n            size_t major = arr.shape(0);\n            size_t minor = arr.shape(1);\n            if (major != n || minor != n) {\n                std::stringstream ss;\n                ss << name << \" had dtype=bool_ \";\n                ss << \"but its shape was (\" << major << \", \" << minor << \") instead of (\";\n                ss << n << \", \" << n << \").\";\n                throw std::invalid_argument(ss.str());\n            }\n        }\n        return;\n    }\n\n    std::stringstream ss;\n    ss << name << \" wasn't a 2d numpy array with dtype=bool_ or dtype=uint8\";\n    throw std::invalid_argument(ss.str());\n}\n\nsize_t determine_tableau_shape(const pybind11::object &numpy_array, const char *name) {\n    size_t n = 0;\n    if (pybind11::isinstance<pybind11::array_t<uint8_t>>(numpy_array)) {\n        auto arr = pybind11::cast<pybind11::array_t<uint8_t>>(numpy_array);\n        if (arr.ndim() == 2) {\n            n = arr.shape(0);\n        }\n    } else if (pybind11::isinstance<pybind11::array_t<bool>>(numpy_array)) {\n        auto arr = pybind11::cast<pybind11::array_t<bool>>(numpy_array);\n        if (arr.ndim() == 2) {\n            n = arr.shape(0);\n        }\n    }\n\n    check_tableau_shape(numpy_array, n, name);\n    return n;\n}\n\npybind11::class_<Tableau<MAX_BITWORD_WIDTH>> stim_pybind::pybind_tableau(pybind11::module &m) {\n    return pybind11::class_<Tableau<MAX_BITWORD_WIDTH>>(\n        m,\n        \"Tableau\",\n        clean_doc_string(R\"DOC(\n            A stabilizer tableau.\n\n            Represents a Clifford operation by explicitly storing how that operation\n            conjugates a list of Pauli group generators into composite Pauli products.\n\n            Examples:\n                >>> import stim\n                >>> stim.Tableau.from_named_gate(\"H\")\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+X\"),\n                    ],\n                )\n\n                >>> t = stim.Tableau.random(5)\n                >>> t_inv = t**-1\n                >>> print(t * t_inv)\n                +-xz-xz-xz-xz-xz-\n                | ++ ++ ++ ++ ++\n                | XZ __ __ __ __\n                | __ XZ __ __ __\n                | __ __ XZ __ __\n                | __ __ __ XZ __\n                | __ __ __ __ XZ\n\n                >>> x2z3 = t.x_output(2) * t.z_output(3)\n                >>> t_inv(x2z3)\n                stim.PauliString(\"+__XZ_\")\n        )DOC\")\n            .data());\n}\n\nvoid stim_pybind::pybind_tableau_methods(pybind11::module &m, pybind11::class_<Tableau<MAX_BITWORD_WIDTH>> &c) {\n    c.def(\n        pybind11::init<size_t>(),\n        pybind11::arg(\"num_qubits\"),\n        clean_doc_string(R\"DOC(\n            Creates an identity tableau over the given number of qubits.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.Tableau(3)\n                >>> print(t)\n                +-xz-xz-xz-\n                | ++ ++ ++\n                | XZ __ __\n                | __ XZ __\n                | __ __ XZ\n\n            Args:\n                num_qubits: The number of qubits the tableau's operation acts on.\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"random\",\n        [](size_t num_qubits) {\n            auto rng = make_py_seeded_rng(pybind11::none());\n            return Tableau<MAX_BITWORD_WIDTH>::random(num_qubits, rng);\n        },\n        pybind11::arg(\"num_qubits\"),\n        clean_doc_string(R\"DOC(\n            Samples a uniformly random Clifford operation and returns its tableau.\n\n            Args:\n                num_qubits: The number of qubits the tableau should act on.\n\n            Returns:\n                The sampled tableau.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.Tableau.random(42)\n\n            References:\n                \"Hadamard-free circuits expose the structure of the Clifford group\"\n                Sergey Bravyi, Dmitri Maslov\n                https://arxiv.org/abs/2003.09412\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"iter_all\",\n        [](size_t num_qubits, bool unsigned_only) -> TableauIterator<MAX_BITWORD_WIDTH> {\n            return TableauIterator<MAX_BITWORD_WIDTH>(num_qubits, !unsigned_only);\n        },\n        pybind11::arg(\"num_qubits\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"unsigned\") = false,\n        clean_doc_string(R\"DOC(\n            Returns an iterator that iterates over all Tableaus of a given size.\n\n            Args:\n                num_qubits: The size of tableau to iterate over.\n                unsigned: Defaults to False. If set to True, only tableaus where\n                    all columns have positive sign are yielded by the iterator.\n                    This substantially reduces the total number of tableaus to\n                    iterate over.\n\n            Returns:\n                An Iterable[stim.Tableau] that yields the requested tableaus.\n\n            Examples:\n                >>> import stim\n                >>> single_qubit_gate_reprs = set()\n                >>> for t in stim.Tableau.iter_all(1):\n                ...     single_qubit_gate_reprs.add(repr(t))\n                >>> len(single_qubit_gate_reprs)\n                24\n\n                >>> num_2q_gates_mod_paulis = 0\n                >>> for _ in stim.Tableau.iter_all(2, unsigned=True):\n                ...     num_2q_gates_mod_paulis += 1\n                >>> num_2q_gates_mod_paulis\n                720\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_unitary_matrix\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self, std::string_view endian) {\n            bool little_endian;\n            if (endian == \"little\") {\n                little_endian = true;\n            } else if (endian == \"big\") {\n                little_endian = false;\n            } else {\n                throw std::invalid_argument(\"endian not in ['little', 'big']\");\n            }\n            auto data = self.to_flat_unitary_matrix(little_endian);\n\n            std::complex<float> *buffer = new std::complex<float>[data.size()];\n            for (size_t k = 0; k < data.size(); k++) {\n                buffer[k] = data[k];\n            }\n\n            pybind11::capsule free_when_done(buffer, [](void *f) {\n                delete[] reinterpret_cast<std::complex<float> *>(f);\n            });\n\n            pybind11::ssize_t n = 1 << self.num_qubits;\n            pybind11::ssize_t itemsize = sizeof(std::complex<float>);\n            return pybind11::array_t<std::complex<float>>({n, n}, {n * itemsize, itemsize}, buffer, free_when_done);\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"endian\"),\n        clean_doc_string(R\"DOC(\n            @signature def to_unitary_matrix(self, *, endian: Literal[\"little\", \"big\"]) -> np.ndarray[np.complex64]:\n            Converts the tableau into a unitary matrix.\n\n            For an n-qubit tableau, this method performs O(n 4^n) work. It uses the state\n            channel duality to transform the tableau into a list of stabilizers, then\n            generates a random state vector and projects it into the +1 eigenspace of each\n            stabilizer.\n\n            Note that tableaus don't have a defined global phase, so the result's global\n            phase may be different from what you expect. For example, the square of\n            SQRT_X's unitary might equal -X instead of +X.\n\n            Args:\n                endian:\n                    \"little\": The first qubit is the least significant (corresponds\n                        to an offset of 1 in the state vector).\n                    \"big\": The first qubit is the most significant (corresponds\n                        to an offset of 2**(n - 1) in the state vector).\n\n            Returns:\n                A numpy array with dtype=np.complex64 and\n                shape=(1 << len(tableau), 1 << len(tableau)).\n\n            Example:\n                >>> import stim\n                >>> cnot = stim.Tableau.from_conjugated_generators(\n                ...     xs=[\n                ...         stim.PauliString(\"XX\"),\n                ...         stim.PauliString(\"_X\"),\n                ...     ],\n                ...     zs=[\n                ...         stim.PauliString(\"Z_\"),\n                ...         stim.PauliString(\"ZZ\"),\n                ...     ],\n                ... )\n                >>> cnot.to_unitary_matrix(endian='big')\n                array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],\n                       [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],\n                       [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],\n                       [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]], dtype=complex64)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_numpy\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self, bool bit_packed) {\n            auto n = self.num_qubits;\n\n            return pybind11::make_tuple(\n                simd_bit_table_to_numpy(self.xs.xt, n, n, bit_packed, false, pybind11::none()),\n                simd_bit_table_to_numpy(self.xs.zt, n, n, bit_packed, false, pybind11::none()),\n                simd_bit_table_to_numpy(self.zs.xt, n, n, bit_packed, false, pybind11::none()),\n                simd_bit_table_to_numpy(self.zs.zt, n, n, bit_packed, false, pybind11::none()),\n                simd_bits_to_numpy(self.xs.signs, n, bit_packed),\n                simd_bits_to_numpy(self.zs.signs, n, bit_packed));\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"bit_packed\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def to_numpy(self, *, bit_packed: bool = False) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:\n\n            Decomposes the contents of the tableau into six numpy arrays.\n\n            The first four numpy arrays correspond to the four quadrants of the table\n            defined in Aaronson and Gottesman's \"Improved Simulation of Stabilizer Circuits\"\n            ( https://arxiv.org/abs/quant-ph/0406196 ).\n\n            The last two numpy arrays are the X and Z sign bit vectors of the tableau.\n\n            Args:\n                bit_packed: Defaults to False. Determines whether the output numpy arrays\n                    use dtype=bool_ or dtype=uint8 with 8 bools packed into each byte.\n\n            Returns:\n                An (x2x, x2z, z2x, z2z, x_signs, z_signs) tuple encoding the tableau.\n\n                x2x: A 2d table of whether tableau(X_i)_j is X or Y (instead of I or Z).\n                x2z: A 2d table of whether tableau(X_i)_j is Z or Y (instead of I or X).\n                z2x: A 2d table of whether tableau(Z_i)_j is X or Y (instead of I or Z).\n                z2z: A 2d table of whether tableau(Z_i)_j is Z or Y (instead of I or X).\n                x_signs: A vector of whether tableau(X_i) is negative.\n                z_signs: A vector of whether tableau(Z_i) is negative.\n\n                If bit_packed=False then:\n                    x2x.dtype = np.bool_\n                    x2z.dtype = np.bool_\n                    z2x.dtype = np.bool_\n                    z2z.dtype = np.bool_\n                    x_signs.dtype = np.bool_\n                    z_signs.dtype = np.bool_\n                    x2x.shape = (len(tableau), len(tableau))\n                    x2z.shape = (len(tableau), len(tableau))\n                    z2x.shape = (len(tableau), len(tableau))\n                    z2z.shape = (len(tableau), len(tableau))\n                    x_signs.shape = len(tableau)\n                    z_signs.shape = len(tableau)\n                    x2x[i, j] = tableau.x_output_pauli(i, j) in [1, 2]\n                    x2z[i, j] = tableau.x_output_pauli(i, j) in [2, 3]\n                    z2x[i, j] = tableau.z_output_pauli(i, j) in [1, 2]\n                    z2z[i, j] = tableau.z_output_pauli(i, j) in [2, 3]\n\n                If bit_packed=True then:\n                    x2x.dtype = np.uint8\n                    x2z.dtype = np.uint8\n                    z2x.dtype = np.uint8\n                    z2z.dtype = np.uint8\n                    x_signs.dtype = np.uint8\n                    z_signs.dtype = np.uint8\n                    x2x.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                    x2z.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                    z2x.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                    z2z.shape = (len(tableau), math.ceil(len(tableau) / 8))\n                    x_signs.shape = math.ceil(len(tableau) / 8)\n                    z_signs.shape = math.ceil(len(tableau) / 8)\n                    (x2x[i, j // 8] >> (j % 8)) & 1 = tableau.x_output_pauli(i, j) in [1, 2]\n                    (x2z[i, j // 8] >> (j % 8)) & 1 = tableau.x_output_pauli(i, j) in [2, 3]\n                    (z2x[i, j // 8] >> (j % 8)) & 1 = tableau.z_output_pauli(i, j) in [1, 2]\n                    (z2z[i, j // 8] >> (j % 8)) & 1 = tableau.z_output_pauli(i, j) in [2, 3]\n\n            Examples:\n                >>> import stim\n                >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n                >>> print(repr(cnot))\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+XX\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+Z_\"),\n                        stim.PauliString(\"+ZZ\"),\n                    ],\n                )\n                >>> x2x, x2z, z2x, z2z, x_signs, z_signs = cnot.to_numpy()\n                >>> x2x\n                array([[ True,  True],\n                       [False,  True]])\n                >>> x2z\n                array([[False, False],\n                       [False, False]])\n                >>> z2x\n                array([[False, False],\n                       [False, False]])\n                >>> z2z\n                array([[ True, False],\n                       [ True,  True]])\n                >>> x_signs\n                array([False, False])\n                >>> z_signs\n                array([False, False])\n\n                >>> t = stim.Tableau.from_conjugated_generators(\n                ...     xs=[\n                ...         stim.PauliString(\"-Y_ZY\"),\n                ...         stim.PauliString(\"-Y_YZ\"),\n                ...         stim.PauliString(\"-XXX_\"),\n                ...         stim.PauliString(\"+ZYX_\"),\n                ...     ],\n                ...     zs=[\n                ...         stim.PauliString(\"-_ZZX\"),\n                ...         stim.PauliString(\"+YZXZ\"),\n                ...         stim.PauliString(\"+XZ_X\"),\n                ...         stim.PauliString(\"-YYXX\"),\n                ...     ],\n                ... )\n\n                >>> x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy()\n                >>> x2x\n                array([[ True, False, False,  True],\n                       [ True, False,  True, False],\n                       [ True,  True,  True, False],\n                       [False,  True,  True, False]])\n                >>> x2z\n                array([[ True, False,  True,  True],\n                       [ True, False,  True,  True],\n                       [False, False, False, False],\n                       [ True,  True, False, False]])\n                >>> z2x\n                array([[False, False, False,  True],\n                       [ True, False,  True, False],\n                       [ True, False, False,  True],\n                       [ True,  True,  True,  True]])\n                >>> z2z\n                array([[False,  True,  True, False],\n                       [ True,  True, False,  True],\n                       [False,  True, False, False],\n                       [ True,  True, False, False]])\n                >>> x_signs\n                array([ True,  True,  True, False])\n                >>> z_signs\n                array([ True, False, False,  True])\n\n                >>> x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy(bit_packed=True)\n                >>> x2x\n                array([[9],\n                       [5],\n                       [7],\n                       [6]], dtype=uint8)\n                >>> x2z\n                array([[13],\n                       [13],\n                       [ 0],\n                       [ 3]], dtype=uint8)\n                >>> z2x\n                array([[ 8],\n                       [ 5],\n                       [ 9],\n                       [15]], dtype=uint8)\n                >>> z2z\n                array([[ 6],\n                       [11],\n                       [ 2],\n                       [ 3]], dtype=uint8)\n                >>> x_signs\n                array([7], dtype=uint8)\n                >>> z_signs\n                array([9], dtype=uint8)\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_numpy\",\n        [](const pybind11::object &x2x,\n           const pybind11::object &x2z,\n           const pybind11::object &z2x,\n           const pybind11::object &z2z,\n           const pybind11::object &x_signs,\n           const pybind11::object &z_signs) {\n            size_t n = determine_tableau_shape(x2x, \"x2x\");\n            check_tableau_shape(x2z, n, \"x2z\");\n            check_tableau_shape(z2x, n, \"z2x\");\n            check_tableau_shape(z2z, n, \"z2z\");\n            if (!x_signs.is_none()) {\n                check_tableau_signs_shape(x_signs, n, \"x_signs\");\n            }\n            if (!z_signs.is_none()) {\n                check_tableau_signs_shape(z_signs, n, \"z_signs\");\n            }\n\n            Tableau<MAX_BITWORD_WIDTH> result(n);\n            memcpy_bits_from_numpy_to_simd_bit_table(n, n, x2x, result.xs.xt);\n            memcpy_bits_from_numpy_to_simd_bit_table(n, n, x2z, result.xs.zt);\n            memcpy_bits_from_numpy_to_simd_bit_table(n, n, z2x, result.zs.xt);\n            memcpy_bits_from_numpy_to_simd_bit_table(n, n, z2z, result.zs.zt);\n            if (!x_signs.is_none()) {\n                memcpy_bits_from_numpy_to_simd(n, x_signs, result.xs.signs);\n            }\n            if (!z_signs.is_none()) {\n                memcpy_bits_from_numpy_to_simd(n, z_signs, result.zs.signs);\n            }\n            if (!result.satisfies_invariants()) {\n                throw std::invalid_argument(\n                    \"The given tableau data don't describe a valid Clifford operation.\\n\"\n                    \"It doesn't preserve commutativity.\\n\"\n                    \"All generator outputs must commute, except for the output of X_k anticommuting with the output of \"\n                    \"Z_k for each k.\");\n            }\n            return result;\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"x2x\"),\n        pybind11::arg(\"x2z\"),\n        pybind11::arg(\"z2x\"),\n        pybind11::arg(\"z2z\"),\n        pybind11::arg(\"x_signs\") = pybind11::none(),\n        pybind11::arg(\"z_signs\") = pybind11::none(),\n        clean_doc_string(R\"DOC(\n            @signature def from_numpy(self, *, x2x: np.ndarray, x2z: np.ndarray, z2x: np.ndarray, z2z: np.ndarray, x_signs: Optional[np.ndarray] = None, z_signs: Optional[np.ndarray] = None) -> stim.Tableau:\n\n            Creates a tableau from numpy arrays x2x, x2z, z2x, z2z, x_signs, and z_signs.\n\n            The x2x, x2z, z2x, z2z arrays are the four quadrants of the table defined in\n            Aaronson and Gottesman's \"Improved Simulation of Stabilizer Circuits\"\n            ( https://arxiv.org/abs/quant-ph/0406196 ).\n\n            Args:\n                x2x: A 2d numpy array containing the x-to-x coupling bits. The bits can be\n                    bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                    result will satisfy result.x_output_pauli(i, j) in [1, 2] == x2x[i, j].\n                    Bit packing must be in little endian order and only applies to the\n                    second axis.\n                x2z: A 2d numpy array containing the x-to-z coupling bits. The bits can be\n                    bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                    result will satisfy result.x_output_pauli(i, j) in [2, 3] == x2z[i, j].\n                    Bit packing must be in little endian order and only applies to the\n                    second axis.\n                z2x: A 2d numpy array containing the z-to-x coupling bits. The bits can be\n                    bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                    result will satisfy result.z_output_pauli(i, j) in [1, 2] == z2x[i, j].\n                    Bit packing must be in little endian order and only applies to the\n                    second axis.\n                z2z: A 2d numpy array containing the z-to-z coupling bits. The bits can be\n                    bit packed (dtype=uint8) or not (dtype=bool_). When not bit packed, the\n                    result will satisfy result.z_output_pauli(i, j) in [2, 3] == z2z[i, j].\n                    Bit packing must be in little endian order and only applies to the\n                    second axis.\n                x_signs: Defaults to all-positive if not specified. A 1d numpy array\n                    containing the sign bits for the X generator outputs. False means\n                    positive and True means negative. The bits can be bit packed\n                    (dtype=uint8) or not (dtype=bool_). Bit packing must be in little endian\n                    order.\n                z_signs: Defaults to all-positive if not specified. A 1d numpy array\n                    containing the sign bits for the Z generator outputs. False means\n                    positive and True means negative. The bits can be bit packed\n                    (dtype=uint8) or not (dtype=bool_). Bit packing must be in little endian\n                    order.\n\n            Returns:\n                The tableau created from the numpy data.\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n\n                >>> tableau = stim.Tableau.from_numpy(\n                ...     x2x=np.array([[1, 1], [0, 1]], dtype=np.bool_),\n                ...     z2x=np.array([[0, 0], [0, 0]], dtype=np.bool_),\n                ...     x2z=np.array([[0, 0], [0, 0]], dtype=np.bool_),\n                ...     z2z=np.array([[1, 0], [1, 1]], dtype=np.bool_),\n                ... )\n                >>> tableau\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+XX\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+Z_\"),\n                        stim.PauliString(\"+ZZ\"),\n                    ],\n                )\n                >>> tableau == stim.Tableau.from_named_gate(\"CNOT\")\n                True\n\n                >>> stim.Tableau.from_numpy(\n                ...     x2x=np.array([[9], [5], [7], [6]], dtype=np.uint8),\n                ...     x2z=np.array([[13], [13], [0], [3]], dtype=np.uint8),\n                ...     z2x=np.array([[8], [5], [9], [15]], dtype=np.uint8),\n                ...     z2z=np.array([[6], [11], [2], [3]], dtype=np.uint8),\n                ...     x_signs=np.array([7], dtype=np.uint8),\n                ...     z_signs=np.array([9], dtype=np.uint8),\n                ... )\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"-Y_ZY\"),\n                        stim.PauliString(\"-Y_YZ\"),\n                        stim.PauliString(\"-XXX_\"),\n                        stim.PauliString(\"+ZYX_\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"-_ZZX\"),\n                        stim.PauliString(\"+YZXZ\"),\n                        stim.PauliString(\"+XZ_X\"),\n                        stim.PauliString(\"-YYXX\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_pauli_string\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self) {\n            return FlexPauliString(self.to_pauli_string());\n        },\n        clean_doc_string(R\"DOC(\n            Return a Pauli string equivalent to the tableau.\n\n            If the tableau is equivalent to a pauli product, creates\n            an equivalent pauli string. If not, then an error is raised.\n\n            Returns:\n                The created pauli string\n\n            Raises:\n                ValueError: The Tableau isn't equivalent to a Pauli product.\n\n            Example:\n                >>> import stim\n                >>> t = (stim.Tableau.from_named_gate(\"Z\") +\n                ...      stim.Tableau.from_named_gate(\"Y\") +\n                ...      stim.Tableau.from_named_gate(\"I\") +\n                ...      stim.Tableau.from_named_gate(\"X\"))\n                >>> print(t)\n                +-xz-xz-xz-xz-\n                | -+ -- ++ +-\n                | XZ __ __ __\n                | __ XZ __ __\n                | __ __ XZ __\n                | __ __ __ XZ\n                >>> print(t.to_pauli_string())\n                +ZY_X\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_circuit\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self, std::string_view method) {\n            return tableau_to_circuit(self, method);\n        },\n        pybind11::arg(\"method\") = \"elimination\",\n        clean_doc_string(R\"DOC(\n            @signature def to_circuit(self, method: Literal[\"elimination\", \"graph_state\"] = 'elimination') -> stim.Circuit:\n            Synthesizes a circuit that implements the tableau's Clifford operation.\n\n            The circuits returned by this method are not guaranteed to be stable\n            from version to version, and may be produced using randomization.\n\n            Args:\n                method: The method to use when synthesizing the circuit. Available values:\n                    \"elimination\": Cancels off-diagonal terms using Gaussian elimination.\n                        Gate set: H, S, CX\n                        Circuit qubit count: n\n                        Circuit operation count: O(n^2)\n                        Circuit depth: O(n^2)\n                    \"graph_state\": Prepares the tableau's state using a graph state circuit.\n                        Gate set: RX, CZ, H, S, X, Y, Z\n                        Circuit qubit count: n\n                        Circuit operation count: O(n^2)\n\n                        The circuit will be made up of three layers:\n                            1. An RX layer initializing all qubits.\n                            2. A CZ layer coupling the qubits.\n                                (Each CZ is an edge in the graph state.)\n                            3. A single qubit rotation layer.\n\n                        Note: \"graph_state\" treats the tableau as a state instead of as a\n                        Clifford operation. It will preserve the set of stabilizers, but\n                        not the exact choice of generators.\n                    \"mpp_state\": Prepares the tableau's state using MPP and feedback.\n                        Gate set: MPP, CX rec, CY rec, CZ rec\n                        Circuit qubit count: n\n                        Circuit operation count: O(n^2)\n\n                        The circuit will be made up of two layers:\n                            1. An MPP layer measuring each of the tableau's stabilizers.\n                            2. A feedback layer using the measurement results to control\n                                whether or not to apply each of the tableau's destabilizers\n                                in order to get the correct sign for each stabilizer.\n\n                        Note: \"mpp_state\" treats the tableau as a state instead of as a\n                        Clifford operation. It will preserve the set of stabilizers, but\n                        not the exact choice of generators.\n                    \"mpp_state_unsigned\": Prepares the tableau's state up to sign using MPP.\n                        Gate set: MPP\n                        Circuit qubit count: n\n                        Circuit operation count: O(n^2)\n\n                        The circuit will contain a series of MPP measurements measuring each\n                        of the tableau's stabilizers. The stabilizers are measured in the\n                        order used by the tableau (i.e. tableau.z_output(k) is the k'th\n                        stabilizer measured).\n\n                        Note: \"mpp_state_unsigned\" treats the tableau as a state instead of\n                        as a Clifford operation. It will preserve the set of stabilizers,\n                        but not the exact choice of generators.\n            Returns:\n                The synthesized circuit.\n\n            Example:\n                >>> import stim\n                >>> tableau = stim.Tableau.from_conjugated_generators(\n                ...     xs=[\n                ...         stim.PauliString(\"+YZ__\"),\n                ...         stim.PauliString(\"-Y_XY\"),\n                ...         stim.PauliString(\"+___Y\"),\n                ...         stim.PauliString(\"+YZX_\"),\n                ...     ],\n                ...     zs=[\n                ...         stim.PauliString(\"+XZYY\"),\n                ...         stim.PauliString(\"-XYX_\"),\n                ...         stim.PauliString(\"-ZXXZ\"),\n                ...         stim.PauliString(\"+XXZ_\"),\n                ...     ],\n                ... )\n\n                >>> tableau.to_circuit()\n                stim.Circuit('''\n                    S 0\n                    H 0 1 3\n                    CX 0 1 0 2 0 3\n                    S 1 3\n                    H 1 3\n                    CX 1 0 3 0 3 1 1 3 3 1\n                    H 1\n                    S 1\n                    CX 1 3\n                    H 2 3\n                    CX 2 1 3 1 3 2 2 3 3 2\n                    H 3\n                    CX 2 3\n                    S 3\n                    H 3 0 1 2\n                    S 0 0 1 1 2 2\n                    H 0 1 2\n                    S 3 3\n                ''')\n\n                >>> tableau.to_circuit(\"graph_state\")\n                stim.Circuit('''\n                    RX 0 1 2 3\n                    TICK\n                    CZ 0 3 1 2 1 3\n                    TICK\n                    X 0 1\n                    Z 2\n                    S 2 3\n                    H 3\n                    S 3\n                ''')\n\n                >>> tableau.to_circuit(\"mpp_state_unsigned\")\n                stim.Circuit('''\n                    MPP X0*Z1*Y2*Y3 !X0*Y1*X2 !Z0*X1*X2*Z3 X0*X1*Z2\n                ''')\n\n                >>> tableau.to_circuit(\"mpp_state\")\n                stim.Circuit('''\n                    MPP X0*Z1*Y2*Y3 !X0*Y1*X2 !Z0*X1*X2*Z3 X0*X1*Z2\n                    CX rec[-3] 2 rec[-1] 2\n                    CY rec[-4] 0 rec[-3] 0 rec[-3] 3 rec[-2] 3 rec[-1] 0\n                    CZ rec[-4] 1 rec[-1] 1\n                ''')\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_named_gate\",\n        [](const char *name) {\n            const Gate &gate = GATE_DATA.at(name);\n            if (!(gate.flags & GATE_IS_UNITARY)) {\n                throw std::out_of_range(\"Recognized name, but not unitary: \" + std::string(name));\n            }\n            return gate.tableau<MAX_BITWORD_WIDTH>();\n        },\n        pybind11::arg(\"name\"),\n        clean_doc_string(R\"DOC(\n            Returns the tableau of a named Clifford gate.\n\n            Args:\n                name: The name of the Clifford gate.\n\n            Returns:\n                The gate's tableau.\n\n            Examples:\n                >>> import stim\n                >>> print(stim.Tableau.from_named_gate(\"H\"))\n                +-xz-\n                | ++\n                | ZX\n                >>> print(stim.Tableau.from_named_gate(\"CNOT\"))\n                +-xz-xz-\n                | ++ ++\n                | XZ _Z\n                | X_ XZ\n                >>> print(stim.Tableau.from_named_gate(\"S\"))\n                +-xz-\n                | ++\n                | YZ\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__len__\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self) {\n            return self.num_qubits;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the number of qubits operated on by the tableau.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n                >>> len(t)\n                2\n        )DOC\")\n            .data());\n\n    c.def(\"__str__\", &Tableau<MAX_BITWORD_WIDTH>::str, \"Returns a text description.\");\n\n    c.def(pybind11::self == pybind11::self, \"Determines if two tableaus have identical contents.\");\n    c.def(pybind11::self != pybind11::self, \"Determines if two tableaus have non-identical contents.\");\n\n    c.def(\n        \"__pow__\",\n        &Tableau<MAX_BITWORD_WIDTH>::raised_to,\n        pybind11::arg(\"exponent\"),\n        clean_doc_string(R\"DOC(\n            Raises the tableau to an integer power.\n\n            Large powers are reached efficiently using repeated squaring.\n            Negative powers are reached by inverting the tableau.\n\n            Args:\n                exponent: The power to raise to. Can be negative, zero, or positive.\n\n            Examples:\n                >>> import stim\n                >>> s = stim.Tableau.from_named_gate(\"S\")\n                >>> s**0 == stim.Tableau(1)\n                True\n                >>> s**1 == s\n                True\n                >>> s**2 == stim.Tableau.from_named_gate(\"Z\")\n                True\n                >>> s**-1 == s**3 == stim.Tableau.from_named_gate(\"S_DAG\")\n                True\n                >>> s**5 == s\n                True\n                >>> s**(400000000 + 1) == s\n                True\n                >>> s**(-400000000 + 1) == s\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"inverse\",\n        &Tableau<MAX_BITWORD_WIDTH>::inverse,\n        pybind11::kw_only(),\n        pybind11::arg(\"unsigned\") = false,\n        clean_doc_string(R\"DOC(\n            Computes the inverse of the tableau.\n\n            The inverse T^-1 of a tableau T is the unique tableau with the property that\n            T * T^-1 = T^-1 * T = I where I is the identity tableau.\n\n            Args:\n                unsigned: Defaults to false. When set to true, skips computing the signs of\n                    the output observables and instead just set them all to be positive.\n                    This is beneficial because computing the signs takes O(n^3) time and the\n                    rest of the inverse computation is O(n^2) where n is the number of\n                    qubits in the tableau. So, if you only need the Pauli terms (not the\n                    signs), it is significantly cheaper.\n\n            Returns:\n                The inverse tableau.\n\n            Examples:\n                >>> import stim\n\n                >>> # Check that the inverse agrees with hard-coded tableaus.\n                >>> s = stim.Tableau.from_named_gate(\"S\")\n                >>> s_dag = stim.Tableau.from_named_gate(\"S_DAG\")\n                >>> s.inverse() == s_dag\n                True\n                >>> z = stim.Tableau.from_named_gate(\"Z\")\n                >>> z.inverse() == z\n                True\n\n                >>> # Check that multiplying by the inverse produces the identity.\n                >>> t = stim.Tableau.random(10)\n                >>> t_inv = t.inverse()\n                >>> identity = stim.Tableau(10)\n                >>> t * t_inv == t_inv * t == identity\n                True\n\n                >>> # Check a manual case.\n                >>> t = stim.Tableau.from_conjugated_generators(\n                ...     xs=[\n                ...         stim.PauliString(\"-__Z\"),\n                ...         stim.PauliString(\"+XZ_\"),\n                ...         stim.PauliString(\"+_ZZ\"),\n                ...     ],\n                ...     zs=[\n                ...         stim.PauliString(\"-YYY\"),\n                ...         stim.PauliString(\"+Z_Z\"),\n                ...         stim.PauliString(\"-ZYZ\")\n                ...     ],\n                ... )\n                >>> print(t.inverse())\n                +-xz-xz-xz-\n                | -- +- --\n                | XX XX YX\n                | XZ Z_ X_\n                | X_ YX Y_\n                >>> print(t.inverse(unsigned=True))\n                +-xz-xz-xz-\n                | ++ ++ ++\n                | XX XX YX\n                | XZ Z_ X_\n                | X_ YX Y_\n        )DOC\")\n            .data());\n\n    c.def(\n        \"append\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self,\n           const Tableau<MAX_BITWORD_WIDTH> &gate,\n           const std::vector<size_t> targets) {\n            std::vector<bool> use(self.num_qubits, false);\n            if (targets.size() != gate.num_qubits) {\n                throw std::invalid_argument(\"len(targets) != len(gate)\");\n            }\n            for (size_t k : targets) {\n                if (k >= self.num_qubits) {\n                    throw std::invalid_argument(\"target >= len(tableau)\");\n                }\n                if (use[k]) {\n                    throw std::invalid_argument(\"target collision on qubit \" + std::to_string(k));\n                }\n                use[k] = true;\n            }\n            self.inplace_scatter_append(gate, targets);\n        },\n        pybind11::arg(\"gate\"),\n        pybind11::arg(\"targets\"),\n        clean_doc_string(R\"DOC(\n            @signature def append(self, gate: stim.Tableau, targets: Sequence[int]) -> None:\n            Appends an operation's effect into this tableau, mutating this tableau.\n\n            Time cost is O(n*m*m) where n=len(self) and m=len(gate).\n\n            Args:\n                gate: The tableau of the operation being appended into this tableau.\n                targets: The qubits being targeted by the gate.\n\n            Examples:\n                >>> import stim\n                >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n                >>> t = stim.Tableau(2)\n                >>> t.append(cnot, [0, 1])\n                >>> t.append(cnot, [1, 0])\n                >>> t.append(cnot, [0, 1])\n                >>> t == stim.Tableau.from_named_gate(\"SWAP\")\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"then\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self, const Tableau<MAX_BITWORD_WIDTH> &second) {\n            if (self.num_qubits != second.num_qubits) {\n                throw std::invalid_argument(\"len(self) != len(second)\");\n            }\n            return self.then(second);\n        },\n        pybind11::arg(\"second\"),\n        clean_doc_string(R\"DOC(\n            Returns the result of composing two tableaus.\n\n            If the tableau T1 represents the Clifford operation with unitary C1,\n            and the tableau T2 represents the Clifford operation with unitary C2,\n            then the tableau T1.then(T2) represents the Clifford operation with unitary\n            C2*C1.\n\n            Args:\n                second: The result is equivalent to applying the second tableau after\n                    the receiving tableau.\n\n            Examples:\n                >>> import stim\n                >>> t1 = stim.Tableau.random(4)\n                >>> t2 = stim.Tableau.random(4)\n                >>> t3 = t1.then(t2)\n                >>> p = stim.PauliString.random(4)\n                >>> t3(p) == t2(t1(p))\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__mul__\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self, const Tableau<MAX_BITWORD_WIDTH> &rhs) {\n            if (self.num_qubits != rhs.num_qubits) {\n                throw std::invalid_argument(\"len(lhs) != len(rhs)\");\n            }\n            return rhs.then(self);\n        },\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Returns the product of two tableaus.\n\n            If the tableau T1 represents the Clifford operation with unitary C1,\n            and the tableau T2 represents the Clifford operation with unitary C2,\n            then the tableau T1*T2 represents the Clifford operation with unitary C1*C2.\n\n            Args:\n                rhs: The tableau  on the right hand side of the multiplication.\n\n            Examples:\n                >>> import stim\n                >>> t1 = stim.Tableau.random(4)\n                >>> t2 = stim.Tableau.random(4)\n                >>> t3 = t2 * t1\n                >>> p = stim.PauliString.random(4)\n                >>> t3(p) == t2(t1(p))\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"prepend\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self,\n           const Tableau<MAX_BITWORD_WIDTH> &gate,\n           const std::vector<size_t> targets) {\n            std::vector<bool> use(self.num_qubits, false);\n            if (targets.size() != gate.num_qubits) {\n                throw std::invalid_argument(\"len(targets) != len(gate)\");\n            }\n            for (size_t k : targets) {\n                if (k >= self.num_qubits) {\n                    throw std::invalid_argument(\"target >= len(tableau)\");\n                }\n                if (use[k]) {\n                    throw std::invalid_argument(\"target collision on qubit \" + std::to_string(k));\n                }\n                use[k] = true;\n            }\n            self.inplace_scatter_prepend(gate, targets);\n        },\n        pybind11::arg(\"gate\"),\n        pybind11::arg(\"targets\"),\n        clean_doc_string(R\"DOC(\n            @signature def prepend(self, gate: stim.Tableau, targets: Sequence[int]) -> None:\n            Prepends an operation's effect into this tableau, mutating this tableau.\n\n            Time cost is O(n*m*m) where n=len(self) and m=len(gate).\n\n            Args:\n                gate: The tableau of the operation being prepended into this tableau.\n                targets: The qubits being targeted by the gate.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.Tableau.from_named_gate(\"H\")\n                >>> t.prepend(stim.Tableau.from_named_gate(\"X\"), [0])\n                >>> t == stim.Tableau.from_named_gate(\"SQRT_Y_DAG\")\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"x_output\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self, size_t target) {\n            if (target >= self.num_qubits) {\n                throw std::invalid_argument(\"target >= len(tableau)\");\n            }\n            return FlexPauliString(self.xs[target]);\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns the result of conjugating a Pauli X by the tableau's Clifford operation.\n\n            Args:\n                target: The qubit targeted by the Pauli X operation.\n\n            Examples:\n                >>> import stim\n                >>> h = stim.Tableau.from_named_gate(\"H\")\n                >>> h.x_output(0)\n                stim.PauliString(\"+Z\")\n\n                >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n                >>> cnot.x_output(0)\n                stim.PauliString(\"+XX\")\n                >>> cnot.x_output(1)\n                stim.PauliString(\"+_X\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"x_sign\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self, pybind11::ssize_t target) -> int {\n            if (target < 0 || (size_t)target >= self.num_qubits) {\n                throw std::invalid_argument(\"not 0 <= target < len(tableau)\");\n            }\n            return self.xs.signs[target] ? -1 : +1;\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns just the sign of the result of conjugating an X generator.\n\n            This operation runs in constant time.\n\n            Args:\n                target: The qubit the X generator applies to.\n\n            Examples:\n                >>> import stim\n                >>> stim.Tableau.from_named_gate(\"S_DAG\").x_sign(0)\n                -1\n                >>> stim.Tableau.from_named_gate(\"S\").x_sign(0)\n                1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"z_sign\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self, pybind11::ssize_t target) -> int {\n            if (target < 0 || (size_t)target >= self.num_qubits) {\n                throw std::invalid_argument(\"not 0 <= target < len(tableau)\");\n            }\n            return self.zs.signs[target] ? -1 : +1;\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns just the sign of the result of conjugating a Z generator.\n\n            This operation runs in constant time.\n\n            Args:\n                target: The qubit the Z generator applies to.\n\n            Examples:\n                >>> import stim\n                >>> stim.Tableau.from_named_gate(\"SQRT_X_DAG\").z_sign(0)\n                1\n                >>> stim.Tableau.from_named_gate(\"SQRT_X\").z_sign(0)\n                -1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"y_sign\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self, pybind11::ssize_t target) -> int {\n            if (target < 0 || (size_t)target >= self.num_qubits) {\n                throw std::invalid_argument(\"not 0 <= target < len(tableau)\");\n            }\n            return self.y_output(target).sign ? -1 : +1;\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns just the sign of the result of conjugating a Y generator.\n\n            Unlike x_sign and z_sign, this operation runs in linear time.\n            The Y generator has to be computed by multiplying the X and Z\n            outputs and the sign depends on all terms.\n\n            Args:\n                target: The qubit the Y generator applies to.\n\n            Examples:\n                >>> import stim\n                >>> stim.Tableau.from_named_gate(\"S_DAG\").y_sign(0)\n                1\n                >>> stim.Tableau.from_named_gate(\"S\").y_sign(0)\n                -1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"y_output\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self, size_t target) {\n            if (target >= self.num_qubits) {\n                throw std::invalid_argument(\"target >= len(tableau)\");\n            }\n            return FlexPauliString(self.y_output(target));\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns the result of conjugating a Pauli Y by the tableau's Clifford operation.\n\n            Args:\n                target: The qubit targeted by the Pauli Y operation.\n\n            Examples:\n                >>> import stim\n                >>> h = stim.Tableau.from_named_gate(\"H\")\n                >>> h.y_output(0)\n                stim.PauliString(\"-Y\")\n\n                >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n                >>> cnot.y_output(0)\n                stim.PauliString(\"+YX\")\n                >>> cnot.y_output(1)\n                stim.PauliString(\"+ZY\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"z_output\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self, size_t target) {\n            if (target >= self.num_qubits) {\n                throw std::invalid_argument(\"target >= len(tableau)\");\n            }\n            return FlexPauliString(self.zs[target]);\n        },\n        pybind11::arg(\"target\"),\n        clean_doc_string(R\"DOC(\n            Returns the result of conjugating a Pauli Z by the tableau's Clifford operation.\n\n            Args:\n                target: The qubit targeted by the Pauli Z operation.\n\n            Examples:\n                >>> import stim\n                >>> h = stim.Tableau.from_named_gate(\"H\")\n                >>> h.z_output(0)\n                stim.PauliString(\"+X\")\n\n                >>> cnot = stim.Tableau.from_named_gate(\"CNOT\")\n                >>> cnot.z_output(0)\n                stim.PauliString(\"+Z_\")\n                >>> cnot.z_output(1)\n                stim.PauliString(\"+ZZ\")\n        )DOC\")\n            .data());\n\n    c.def(\n        \"x_output_pauli\",\n        &Tableau<MAX_BITWORD_WIDTH>::x_output_pauli_xyz,\n        pybind11::arg(\"input_index\"),\n        pybind11::arg(\"output_index\"),\n        clean_doc_string(R\"DOC(\n            Constant-time version of `tableau.x_output(input_index)[output_index]`\n\n            Args:\n                input_index: Identifies the tableau column (the qubit of the input X\n                    generator).\n                output_index: Identifies the tableau row (the output qubit).\n\n            Returns:\n                An integer identifying Pauli at the given location in the tableau:\n\n                    0: I\n                    1: X\n                    2: Y\n                    3: Z\n\n            Examples:\n                >>> import stim\n\n                >>> t = stim.Tableau.from_conjugated_generators(\n                ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n                ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n                ... )\n                >>> t.x_output_pauli(0, 0)\n                2\n                >>> t.x_output_pauli(0, 1)\n                0\n                >>> t.x_output_pauli(1, 0)\n                2\n                >>> t.x_output_pauli(1, 1)\n                3\n        )DOC\")\n            .data());\n\n    c.def(\n        \"y_output_pauli\",\n        &Tableau<MAX_BITWORD_WIDTH>::y_output_pauli_xyz,\n        pybind11::arg(\"input_index\"),\n        pybind11::arg(\"output_index\"),\n        clean_doc_string(R\"DOC(\n            Constant-time version of `tableau.y_output(input_index)[output_index]`\n\n            Args:\n                input_index: Identifies the tableau column (the qubit of the input Y\n                    generator).\n                output_index: Identifies the tableau row (the output qubit).\n\n            Returns:\n                An integer identifying Pauli at the given location in the tableau:\n\n                    0: I\n                    1: X\n                    2: Y\n                    3: Z\n\n            Examples:\n                >>> import stim\n\n                >>> t = stim.Tableau.from_conjugated_generators(\n                ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n                ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n                ... )\n                >>> t.y_output_pauli(0, 0)\n                1\n                >>> t.y_output_pauli(0, 1)\n                2\n                >>> t.y_output_pauli(1, 0)\n                0\n                >>> t.y_output_pauli(1, 1)\n                2\n        )DOC\")\n            .data());\n\n    c.def(\n        \"z_output_pauli\",\n        &Tableau<MAX_BITWORD_WIDTH>::z_output_pauli_xyz,\n        pybind11::arg(\"input_index\"),\n        pybind11::arg(\"output_index\"),\n        clean_doc_string(R\"DOC(\n            Constant-time version of `tableau.z_output(input_index)[output_index]`\n\n            Args:\n                input_index: Identifies the tableau column (the qubit of the input Z\n                    generator).\n                output_index: Identifies the tableau row (the output qubit).\n\n            Returns:\n                An integer identifying Pauli at the given location in the tableau:\n\n                    0: I\n                    1: X\n                    2: Y\n                    3: Z\n\n            Examples:\n                >>> import stim\n\n                >>> t = stim.Tableau.from_conjugated_generators(\n                ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n                ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n                ... )\n                >>> t.z_output_pauli(0, 0)\n                3\n                >>> t.z_output_pauli(0, 1)\n                2\n                >>> t.z_output_pauli(1, 0)\n                2\n                >>> t.z_output_pauli(1, 1)\n                1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"inverse_x_output_pauli\",\n        &Tableau<MAX_BITWORD_WIDTH>::inverse_x_output_pauli_xyz,\n        pybind11::arg(\"input_index\"),\n        pybind11::arg(\"output_index\"),\n        clean_doc_string(R\"DOC(\n            Constant-time version of `tableau.inverse().x_output(input_index)[output_index]`\n\n            Args:\n                input_index: Identifies the column (the qubit of the input X generator) in\n                    the inverse tableau.\n                output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n            Returns:\n                An integer identifying Pauli at the given location in the inverse tableau:\n\n                    0: I\n                    1: X\n                    2: Y\n                    3: Z\n\n            Examples:\n                >>> import stim\n\n                >>> t_inv = stim.Tableau.from_conjugated_generators(\n                ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n                ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n                ... ).inverse()\n                >>> t_inv.inverse_x_output_pauli(0, 0)\n                2\n                >>> t_inv.inverse_x_output_pauli(0, 1)\n                0\n                >>> t_inv.inverse_x_output_pauli(1, 0)\n                2\n                >>> t_inv.inverse_x_output_pauli(1, 1)\n                3\n        )DOC\")\n            .data());\n\n    c.def(\n        \"inverse_y_output_pauli\",\n        &Tableau<MAX_BITWORD_WIDTH>::inverse_y_output_pauli_xyz,\n        pybind11::arg(\"input_index\"),\n        pybind11::arg(\"output_index\"),\n        clean_doc_string(R\"DOC(\n            Constant-time version of `tableau.inverse().y_output(input_index)[output_index]`\n\n            Args:\n                input_index: Identifies the column (the qubit of the input Y generator) in\n                    the inverse tableau.\n                output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n            Returns:\n                An integer identifying Pauli at the given location in the inverse tableau:\n\n                    0: I\n                    1: X\n                    2: Y\n                    3: Z\n\n            Examples:\n                >>> import stim\n\n                >>> t_inv = stim.Tableau.from_conjugated_generators(\n                ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n                ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n                ... ).inverse()\n                >>> t_inv.inverse_y_output_pauli(0, 0)\n                1\n                >>> t_inv.inverse_y_output_pauli(0, 1)\n                2\n                >>> t_inv.inverse_y_output_pauli(1, 0)\n                0\n                >>> t_inv.inverse_y_output_pauli(1, 1)\n                2\n        )DOC\")\n            .data());\n\n    c.def(\n        \"inverse_z_output_pauli\",\n        &Tableau<MAX_BITWORD_WIDTH>::inverse_z_output_pauli_xyz,\n        pybind11::arg(\"input_index\"),\n        pybind11::arg(\"output_index\"),\n        clean_doc_string(R\"DOC(\n            Constant-time version of `tableau.inverse().z_output(input_index)[output_index]`\n\n            Args:\n                input_index: Identifies the column (the qubit of the input Z generator) in\n                    the inverse tableau.\n                output_index: Identifies the row (the output qubit) in the inverse tableau.\n\n            Returns:\n                An integer identifying Pauli at the given location in the inverse tableau:\n\n                    0: I\n                    1: X\n                    2: Y\n                    3: Z\n\n            Examples:\n                >>> import stim\n\n                >>> t_inv = stim.Tableau.from_conjugated_generators(\n                ...     xs=[stim.PauliString(\"-Y_\"), stim.PauliString(\"+YZ\")],\n                ...     zs=[stim.PauliString(\"-ZY\"), stim.PauliString(\"+YX\")],\n                ... ).inverse()\n                >>> t_inv.inverse_z_output_pauli(0, 0)\n                3\n                >>> t_inv.inverse_z_output_pauli(0, 1)\n                2\n                >>> t_inv.inverse_z_output_pauli(1, 0)\n                2\n                >>> t_inv.inverse_z_output_pauli(1, 1)\n                1\n        )DOC\")\n            .data());\n\n    c.def(\n        \"inverse_x_output\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self, size_t input_index, bool skip_sign) {\n            return FlexPauliString(self.inverse_x_output(input_index, skip_sign));\n        },\n        pybind11::arg(\"input_index\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"unsigned\") = false,\n        clean_doc_string(R\"DOC(\n            Conjugates a single-qubit X Pauli generator by the inverse of the tableau.\n\n            A faster version of `tableau.inverse(unsigned).x_output(input_index)`.\n\n            Args:\n                input_index: Identifies the column (the qubit of the X generator) to return\n                    from the inverse tableau.\n                unsigned: Defaults to false. When set to true, skips computing the result's\n                    sign and instead just sets it to positive. This is beneficial because\n                    computing the sign takes O(n^2) time whereas all other parts of the\n                    computation take O(n) time where n is the number of qubits in the\n                    tableau.\n\n            Returns:\n                The result of conjugating an X generator by the inverse of the tableau.\n\n            Examples:\n                >>> import stim\n\n                # Check equivalence with the inverse's x_output.\n                >>> t = stim.Tableau.random(4)\n                >>> expected = t.inverse().x_output(0)\n                >>> t.inverse_x_output(0) == expected\n                True\n                >>> expected.sign = +1\n                >>> t.inverse_x_output(0, unsigned=True) == expected\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"inverse_y_output\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self, size_t input_index, bool skip_sign) {\n            return FlexPauliString(self.inverse_y_output(input_index, skip_sign));\n        },\n        pybind11::arg(\"input_index\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"unsigned\") = false,\n        clean_doc_string(R\"DOC(\n            Conjugates a single-qubit Y Pauli generator by the inverse of the tableau.\n\n            A faster version of `tableau.inverse(unsigned).y_output(input_index)`.\n\n            Args:\n                input_index: Identifies the column (the qubit of the Y generator) to return\n                    from the inverse tableau.\n                unsigned: Defaults to false. When set to true, skips computing the result's\n                    sign and instead just sets it to positive. This is beneficial because\n                    computing the sign takes O(n^2) time whereas all other parts of the\n                    computation take O(n) time where n is the number of qubits in the\n                    tableau.\n\n            Returns:\n                The result of conjugating a Y generator by the inverse of the tableau.\n\n            Examples:\n                >>> import stim\n\n                # Check equivalence with the inverse's y_output.\n                >>> t = stim.Tableau.random(4)\n                >>> expected = t.inverse().y_output(0)\n                >>> t.inverse_y_output(0) == expected\n                True\n                >>> expected.sign = +1\n                >>> t.inverse_y_output(0, unsigned=True) == expected\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"inverse_z_output\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self, size_t input_index, bool skip_sign) {\n            return FlexPauliString(self.inverse_z_output(input_index, skip_sign));\n        },\n        pybind11::arg(\"input_index\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"unsigned\") = false,\n        clean_doc_string(R\"DOC(\n            Conjugates a single-qubit Z Pauli generator by the inverse of the tableau.\n\n            A faster version of `tableau.inverse(unsigned).z_output(input_index)`.\n\n            Args:\n                input_index: Identifies the column (the qubit of the Z generator) to return\n                    from the inverse tableau.\n                unsigned: Defaults to false. When set to true, skips computing the result's\n                    sign and instead just sets it to positive. This is beneficial because\n                    computing the sign takes O(n^2) time whereas all other parts of the\n                    computation take O(n) time where n is the number of qubits in the\n                    tableau.\n\n            Returns:\n                The result of conjugating a Z generator by the inverse of the tableau.\n\n            Examples:\n                >>> import stim\n\n                >>> import stim\n\n                # Check equivalence with the inverse's z_output.\n                >>> t = stim.Tableau.random(4)\n                >>> expected = t.inverse().z_output(0)\n                >>> t.inverse_z_output(0) == expected\n                True\n                >>> expected.sign = +1\n                >>> t.inverse_z_output(0, unsigned=True) == expected\n                True\n        )DOC\")\n            .data());\n\n    c.def(\n        \"copy\",\n        [](Tableau<MAX_BITWORD_WIDTH> &self) {\n            Tableau<MAX_BITWORD_WIDTH> copy = self;\n            return copy;\n        },\n        clean_doc_string(R\"DOC(\n            Returns a copy of the tableau. An independent tableau with the same contents.\n\n            Examples:\n                >>> import stim\n                >>> t1 = stim.Tableau.random(2)\n                >>> t2 = t1.copy()\n                >>> t2 is t1\n                False\n                >>> t2 == t1\n                True\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_conjugated_generators\",\n        [](const std::vector<FlexPauliString> &xs, const std::vector<FlexPauliString> &zs) {\n            size_t n = xs.size();\n            if (n != zs.size()) {\n                throw std::invalid_argument(\"len(xs) != len(zs)\");\n            }\n            for (const auto &p : xs) {\n                if (p.imag) {\n                    throw std::invalid_argument(\"Conjugated generator can't have imaginary sign.\");\n                }\n                if (p.value.num_qubits != n) {\n                    throw std::invalid_argument(\"not all(len(p) == len(xs) for p in xs)\");\n                }\n            }\n            for (const auto &p : zs) {\n                if (p.imag) {\n                    throw std::invalid_argument(\"Conjugated generator can't have imaginary sign.\");\n                }\n                if (p.value.num_qubits != n) {\n                    throw std::invalid_argument(\"not all(len(p) == len(zs) for p in zs)\");\n                }\n            }\n            Tableau<MAX_BITWORD_WIDTH> result(n);\n            for (size_t q = 0; q < n; q++) {\n                result.xs[q] = xs[q].value;\n                result.zs[q] = zs[q].value;\n            }\n            if (!result.satisfies_invariants()) {\n                throw std::invalid_argument(\n                    \"The given generator outputs don't describe a valid Clifford operation.\\n\"\n                    \"They don't preserve commutativity.\\n\"\n                    \"Everything must commute, except for X_k anticommuting with Z_k for each k.\");\n            }\n            return result;\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"xs\"),\n        pybind11::arg(\"zs\"),\n        clean_doc_string(R\"DOC(\n            Creates a tableau from the given outputs for each generator.\n\n            Verifies that the tableau is well formed.\n\n            Args:\n                xs: A List[stim.PauliString] with the results of conjugating X0, X1, etc.\n                zs: A List[stim.PauliString] with the results of conjugating Z0, Z1, etc.\n\n            Returns:\n                The created tableau.\n\n            Raises:\n                ValueError: The given outputs are malformed. Their lengths are inconsistent,\n                    or they don't satisfy the required commutation relationships.\n\n            Examples:\n                >>> import stim\n                >>> identity3 = stim.Tableau.from_conjugated_generators(\n                ...     xs=[\n                ...         stim.PauliString(\"X__\"),\n                ...         stim.PauliString(\"_X_\"),\n                ...         stim.PauliString(\"__X\"),\n                ...     ],\n                ...     zs=[\n                ...         stim.PauliString(\"Z__\"),\n                ...         stim.PauliString(\"_Z_\"),\n                ...         stim.PauliString(\"__Z\"),\n                ...     ],\n                ... )\n                >>> identity3 == stim.Tableau(3)\n                True\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_unitary_matrix\",\n        [](const pybind11::object &matrix, std::string_view endian) {\n            bool little_endian;\n            if (endian == \"little\") {\n                little_endian = true;\n            } else if (endian == \"big\") {\n                little_endian = false;\n            } else {\n                throw std::invalid_argument(\"endian not in ['little', 'big']\");\n            }\n\n            std::vector<std::vector<std::complex<float>>> converted_matrix;\n            for (const auto &row : matrix) {\n                converted_matrix.push_back({});\n                for (const auto &cell : row) {\n                    converted_matrix.back().push_back(pybind11::cast<std::complex<float>>(cell));\n                }\n            }\n            return unitary_to_tableau<MAX_BITWORD_WIDTH>(converted_matrix, little_endian);\n        },\n        pybind11::arg(\"matrix\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"endian\"),\n        clean_doc_string(R\"DOC(\n            @signature def from_unitary_matrix(matrix: Iterable[Iterable[float]], *, endian: Literal[\"little\", \"big\"] = 'little') -> stim.Tableau:\n            Creates a tableau from the unitary matrix of a Clifford operation.\n\n            Args:\n                matrix: A unitary matrix specified as an iterable of rows, with each row is\n                    an iterable of amplitudes. The unitary matrix must correspond to a\n                    Clifford operation.\n                endian:\n                    \"little\": matrix entries are in little endian order, where higher index\n                        qubits correspond to larger changes in row/col indices.\n                    \"big\": matrix entries are in big endian order, where higher index\n                        qubits correspond to smaller changes in row/col indices.\n            Returns:\n                The tableau equivalent to the given unitary matrix (up to global phase).\n\n            Raises:\n                ValueError: The given matrix isn't the unitary matrix of a Clifford\n                    operation.\n\n            Examples:\n                >>> import stim\n                >>> stim.Tableau.from_unitary_matrix([\n                ...     [1, 0],\n                ...     [0, 1j],\n                ... ], endian='little')\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Y\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+Z\"),\n                    ],\n                )\n\n                >>> stim.Tableau.from_unitary_matrix([\n                ...     [1, 0, 0, 0],\n                ...     [0, 1, 0, 0],\n                ...     [0, 0, 0, -1j],\n                ...     [0, 0, 1j, 0],\n                ... ], endian='little')\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+XZ\"),\n                        stim.PauliString(\"+YX\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+ZZ\"),\n                        stim.PauliString(\"+_Z\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_circuit\",\n        [](const Circuit &circuit, bool ignore_noise, bool ignore_measurement, bool ignore_reset) {\n            return circuit_to_tableau<MAX_BITWORD_WIDTH>(circuit, ignore_noise, ignore_measurement, ignore_reset);\n        },\n        pybind11::arg(\"circuit\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"ignore_noise\") = false,\n        pybind11::arg(\"ignore_measurement\") = false,\n        pybind11::arg(\"ignore_reset\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def from_circuit(circuit: stim.Circuit, *, ignore_noise: bool = False, ignore_measurement: bool = False, ignore_reset: bool = False) -> stim.Tableau:\n            Converts a circuit into an equivalent stabilizer tableau.\n\n            Args:\n                circuit: The circuit to compile into a tableau.\n                ignore_noise: Defaults to False. When False, any noise operations in the\n                    circuit will cause the conversion to fail with an exception. When True,\n                    noise operations are skipped over as if they weren't even present in the\n                    circuit.\n                ignore_measurement: Defaults to False. When False, any measurement\n                    operations in the circuit will cause the conversion to fail with an\n                    exception. When True, measurement operations are skipped over as if they\n                    weren't even present in the circuit.\n                ignore_reset: Defaults to False. When False, any reset operations in the\n                    circuit will cause the conversion to fail with an exception. When True,\n                    reset operations are skipped over as if they weren't even present in the\n                    circuit.\n\n            Returns:\n                The tableau equivalent to the given circuit (up to global phase).\n\n            Raises:\n                ValueError:\n                    The circuit contains noise operations but ignore_noise=False.\n                    OR\n                    The circuit contains measurement operations but\n                    ignore_measurement=False.\n                    OR\n                    The circuit contains reset operations but ignore_reset=False.\n\n            Examples:\n                >>> import stim\n                >>> stim.Tableau.from_circuit(stim.Circuit('''\n                ...     H 0\n                ...     CNOT 0 1\n                ... '''))\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z_\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+XX\"),\n                        stim.PauliString(\"+ZZ\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__repr__\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self) {\n            std::stringstream result;\n            result << \"stim.Tableau.from_conjugated_generators(\\n    xs=[\\n\";\n            for (size_t q = 0; q < self.num_qubits; q++) {\n                result << \"        stim.PauliString(\\\"\" << self.xs[q].str() << \"\\\"),\\n\";\n            }\n            result << \"    ],\\n    zs=[\\n\";\n            for (size_t q = 0; q < self.num_qubits; q++) {\n                result << \"        stim.PauliString(\\\"\" << self.zs[q].str() << \"\\\"),\\n\";\n            }\n            result << \"    ],\\n)\";\n            return result.str();\n        },\n        \"Returns valid python code evaluating to an equal `stim.Tableau`.\");\n\n    c.def(\n        \"__call__\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self, const FlexPauliString &pauli_string) {\n            FlexPauliString result{self(pauli_string.value)};\n            if (pauli_string.imag) {\n                result *= std::complex<float>(0, 1);\n            }\n            return result;\n        },\n        pybind11::arg(\"pauli_string\"),\n        clean_doc_string(R\"DOC(\n             Returns the equivalent PauliString after the Tableau's Clifford operation.\n\n             If P is a Pauli product before a Clifford operation C, then this method returns\n             Q = C * P * C**-1 (the conjugation of P by C). Q is the equivalent Pauli product\n             after C. This works because:\n            \n                 C*P\n                 = C*P * I\n                 = C*P * (C**-1 * C)\n                 = (C*P*C**-1) * C\n                 = Q*C\n\n            (Keep in mind that A*B means first B is applied, then A is applied.)\n\n             Args:\n                 pauli_string: The pauli string to conjugate.\n\n             Returns:\n                 The new conjugated pauli string.\n\n             Examples:\n                 >>> import stim\n                 >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n                 >>> p = stim.PauliString(\"XX\")\n                 >>> result = t(p)\n                 >>> print(result)\n                 +X_\n        )DOC\")\n            .data());\n\n    c.def(\n        pybind11::self + pybind11::self,\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Returns the direct sum (diagonal concatenation) of two Tableaus.\n\n            Args:\n                rhs: A second stim.Tableau.\n\n            Examples:\n                >>> import stim\n\n                >>> s = stim.Tableau.from_named_gate(\"S\")\n                >>> cz = stim.Tableau.from_named_gate(\"CZ\")\n                >>> print(s + cz)\n                +-xz-xz-xz-\n                | ++ ++ ++\n                | YZ __ __\n                | __ XZ Z_\n                | __ Z_ XZ\n\n            Returns:\n                The direct sum.\n        )DOC\")\n            .data());\n\n    c.def(\n        pybind11::self += pybind11::self,\n        pybind11::arg(\"rhs\"),\n        clean_doc_string(R\"DOC(\n            Performs an inplace direct sum (diagonal concatenation).\n\n            Args:\n                rhs: A second stim.Tableau.\n\n            Examples:\n                >>> import stim\n\n                >>> s = stim.Tableau.from_named_gate(\"S\")\n                >>> cz = stim.Tableau.from_named_gate(\"CZ\")\n                >>> alias = s\n                >>> s += cz\n                >>> alias is s\n                True\n                >>> print(s)\n                +-xz-xz-xz-\n                | ++ ++ ++\n                | YZ __ __\n                | __ XZ Z_\n                | __ Z_ XZ\n\n            Returns:\n                The mutated tableau.\n        )DOC\")\n            .data());\n\n    c.def(\n        pybind11::pickle(\n            [](const Tableau<MAX_BITWORD_WIDTH> &self) {\n                pybind11::dict d;\n                std::vector<FlexPauliString> xs;\n                std::vector<FlexPauliString> zs;\n                for (size_t q = 0; q < self.num_qubits; q++) {\n                    xs.push_back(FlexPauliString(self.xs[q]));\n                }\n                for (size_t q = 0; q < self.num_qubits; q++) {\n                    zs.push_back(FlexPauliString(self.zs[q]));\n                }\n                d[\"xs\"] = xs;\n                d[\"zs\"] = zs;\n                return d;\n            },\n            [](const pybind11::dict &d) {\n                std::vector<FlexPauliString> xs;\n                std::vector<FlexPauliString> zs;\n                for (const auto &e : d[\"xs\"]) {\n                    xs.push_back(pybind11::cast<FlexPauliString>(e));\n                }\n                for (const auto &e : d[\"zs\"]) {\n                    zs.push_back(pybind11::cast<FlexPauliString>(e));\n                }\n\n                size_t n = xs.size();\n                bool correct_shape = zs.size() == n;\n                for (const auto &e : xs) {\n                    correct_shape &= !e.imag;\n                    correct_shape &= e.value.num_qubits == n;\n                }\n                for (const auto &e : zs) {\n                    correct_shape &= !e.imag;\n                    correct_shape &= e.value.num_qubits == n;\n                }\n                if (!correct_shape) {\n                    throw std::invalid_argument(\"Invalid pickle.\");\n                }\n\n                Tableau<MAX_BITWORD_WIDTH> result(n);\n                for (size_t q = 0; q < n; q++) {\n                    result.xs[q] = xs[q].value;\n                    result.zs[q] = zs[q].value;\n                }\n                if (!result.satisfies_invariants()) {\n                    throw std::invalid_argument(\"Pickled tableau was invalid. It doesn't preserve commutativity.\");\n                }\n                return result;\n            }));\n\n    c.def_static(\n        \"from_stabilizers\",\n        [](pybind11::object &stabilizers, bool allow_redundant, bool allow_underconstrained) {\n            std::vector<PauliString<MAX_BITWORD_WIDTH>> converted_stabilizers;\n            for (const auto &stabilizer : stabilizers) {\n                const FlexPauliString &p = pybind11::cast<FlexPauliString>(stabilizer);\n                if (p.imag) {\n                    throw std::invalid_argument(\"Stabilizers can't have imaginary sign.\");\n                }\n                converted_stabilizers.push_back(p.value);\n            }\n            return stabilizers_to_tableau<MAX_BITWORD_WIDTH>(\n                converted_stabilizers, allow_redundant, allow_underconstrained, false);\n        },\n        pybind11::arg(\"stabilizers\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"allow_redundant\") = false,\n        pybind11::arg(\"allow_underconstrained\") = false,\n        clean_doc_string(R\"DOC(\n            @signature def from_stabilizers(stabilizers: Iterable[stim.PauliString], *, allow_redundant: bool = False, allow_underconstrained: bool = False) -> stim.Tableau:\n            Creates a tableau representing a state with the given stabilizers.\n\n            Args:\n                stabilizers: A list of `stim.PauliString`s specifying the stabilizers that\n                    the state must have. It is permitted for stabilizers to have different\n                    lengths. All stabilizers are padded up to the length of the longest\n                    stabilizer by appending identity terms.\n                allow_redundant: Defaults to False. If set to False, then the given\n                    stabilizers must all be independent. If any one of them is a product of\n                    the others (including the empty product), an exception will be raised.\n                    If set to True, then redundant stabilizers are simply ignored.\n                allow_underconstrained: Defaults to False. If set to False, then the given\n                    stabilizers must form a complete set of generators. They must exactly\n                    specify the desired stabilizer state, with no degrees of freedom left\n                    over. For an n-qubit state there must be n independent stabilizers. If\n                    set to True, then there can be leftover degrees of freedom which can be\n                    set arbitrarily.\n\n            Returns:\n                A tableau which, when applied to the all-zeroes state, produces a state\n                with the given stabilizers.\n\n                Guarantees that result.z_output(k) will be equal to the k'th independent\n                stabilizer from the `stabilizers` argument.\n\n            Raises:\n                ValueError:\n                    A stabilizer is redundant but allow_redundant=True wasn't set.\n                    OR\n                    The given stabilizers are contradictory (e.g. \"+Z\" and \"-Z\" both\n                    specified).\n                    OR\n                    The given stabilizers anticommute (e.g. \"+Z\" and \"+X\" both specified).\n                    OR\n                    The stabilizers left behind a degree of freedom but\n                    allow_underconstrained=True wasn't set.\n                    OR\n                    A stabilizer has an imaginary sign (i or -i).\n\n            Examples:\n\n                >>> import stim\n                >>> stim.Tableau.from_stabilizers([\n                ...     stim.PauliString(\"XX\"),\n                ...     stim.PauliString(\"ZZ\"),\n                ... ])\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z_\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+XX\"),\n                        stim.PauliString(\"+ZZ\"),\n                    ],\n                )\n\n                >>> stim.Tableau.from_stabilizers([\n                ...     stim.PauliString(\"XX_\"),\n                ...     stim.PauliString(\"ZZ_\"),\n                ...     stim.PauliString(\"-YY_\"),\n                ...     stim.PauliString(\"\"),\n                ... ], allow_underconstrained=True, allow_redundant=True)\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z__\"),\n                        stim.PauliString(\"+_X_\"),\n                        stim.PauliString(\"+__X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+XX_\"),\n                        stim.PauliString(\"+ZZ_\"),\n                        stim.PauliString(\"+__Z\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def_static(\n        \"from_state_vector\",\n        [](pybind11::object &state_vector, std::string_view endian) {\n            bool little_endian;\n            if (endian == \"little\") {\n                little_endian = true;\n            } else if (endian == \"big\") {\n                little_endian = false;\n            } else {\n                throw std::invalid_argument(\"endian not in ['little', 'big']\");\n            }\n\n            std::vector<std::complex<float>> v;\n            for (const auto &obj : state_vector) {\n                v.push_back(pybind11::cast<std::complex<float>>(obj));\n            }\n\n            return circuit_to_tableau<MAX_BITWORD_WIDTH>(\n                stabilizer_state_vector_to_circuit(v, little_endian), false, false, false);\n        },\n        pybind11::arg(\"state_vector\"),\n        pybind11::kw_only(),\n        pybind11::arg(\"endian\"),\n        clean_doc_string(R\"DOC(\n            @signature def from_state_vector(state_vector: Iterable[float], *, endian: Literal[\"little\", \"big\"]) -> stim.Tableau:\n            Creates a tableau representing the stabilizer state of the given state vector.\n\n            Args:\n                state_vector: A list of complex amplitudes specifying a superposition. The\n                    vector must correspond to a state that is reachable using Clifford\n                    operations, and can be unnormalized.\n                endian:\n                    \"little\": state vector is in little endian order, where higher index\n                        qubits correspond to larger changes in the state index.\n                    \"big\": state vector is in big endian order, where higher index qubits\n                        correspond to smaller changes in the state index.\n\n            Returns:\n                A tableau which, when applied to the all-zeroes state, produces a state\n                with the given state vector.\n\n            Raises:\n                ValueError:\n                    The given state vector isn't a list of complex values specifying a\n                    stabilizer state.\n                    OR\n                    The given endian value isn't 'little' or 'big'.\n\n            Examples:\n\n                >>> import stim\n                >>> stim.Tableau.from_state_vector([\n                ...     0.5**0.5,\n                ...     0.5**0.5 * 1j,\n                ... ], endian='little')\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+Y\"),\n                    ],\n                )\n                >>> stim.Tableau.from_state_vector([\n                ...     0.5**0.5,\n                ...     0,\n                ...     0,\n                ...     0.5**0.5,\n                ... ], endian='little')\n                stim.Tableau.from_conjugated_generators(\n                    xs=[\n                        stim.PauliString(\"+Z_\"),\n                        stim.PauliString(\"+_X\"),\n                    ],\n                    zs=[\n                        stim.PauliString(\"+XX\"),\n                        stim.PauliString(\"+ZZ\"),\n                    ],\n                )\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_state_vector\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self, std::string_view endian) {\n            bool little_endian;\n            if (endian == \"little\") {\n                little_endian = true;\n            } else if (endian == \"big\") {\n                little_endian = false;\n            } else {\n                throw std::invalid_argument(\"endian not in ['little', 'big']\");\n            }\n            TableauSimulator<MAX_BITWORD_WIDTH> sim(std::mt19937_64{0}, self.num_qubits);\n            sim.inv_state = self.inverse(false);\n            auto complex_vec = sim.to_state_vector(little_endian);\n\n            std::complex<float> *buffer = new std::complex<float>[complex_vec.size()];\n            for (size_t k = 0; k < complex_vec.size(); k++) {\n                buffer[k] = complex_vec[k];\n            }\n\n            pybind11::capsule free_when_done(buffer, [](void *f) {\n                delete[] reinterpret_cast<std::complex<float> *>(f);\n            });\n\n            return pybind11::array_t<std::complex<float>>(\n                {(pybind11::ssize_t)complex_vec.size()},\n                {(pybind11::ssize_t)sizeof(std::complex<float>)},\n                buffer,\n                free_when_done);\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"endian\") = \"little\",\n        clean_doc_string(R\"DOC(\n            @signature def to_state_vector(self, *, endian: Literal[\"little\", \"big\"] = 'little') -> np.ndarray[np.complex64]:\n            Returns the state vector produced by applying the tableau to the |0..0> state.\n\n            This function takes O(n * 2**n) time and O(2**n) space, where n is the number of\n            qubits. The computation is done by initialization a random state vector and\n            iteratively projecting it into the +1 eigenspace of each stabilizer of the\n            state. The state is then canonicalized so that zero values are actually exactly\n            0, and so that the first non-zero entry is positive.\n\n            Args:\n                endian:\n                    \"little\" (default): state vector is in little endian order, where higher\n                        index qubits correspond to larger changes in the state index.\n                    \"big\": state vector is in big endian order, where higher index qubits\n                        correspond to smaller changes in the state index.\n\n            Returns:\n                A `numpy.ndarray[numpy.complex64]` of computational basis amplitudes.\n\n                If the result is in little endian order then the amplitude at offset\n                b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n                computational basis state where the qubit with index 0 is storing the bit\n                b_0, the qubit with index 1 is storing the bit b_1, etc.\n\n                If the result is in big endian order then the amplitude at offset\n                b_0 + b_1*2 + b_2*4 + ... + b_{n-1}*2^{n-1} is the amplitude for the\n                computational basis state where the qubit with index 0 is storing the bit\n                b_{n-1}, the qubit with index 1 is storing the bit b_{n-2}, etc.\n\n            Examples:\n                >>> import stim\n                >>> import numpy as np\n                >>> i2 = stim.Tableau.from_named_gate('I')\n                >>> x = stim.Tableau.from_named_gate('X')\n                >>> h = stim.Tableau.from_named_gate('H')\n\n                >>> (x + i2).to_state_vector(endian='little')\n                array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)\n\n                >>> (i2 + x).to_state_vector(endian='little')\n                array([0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], dtype=complex64)\n\n                >>> (i2 + x).to_state_vector(endian='big')\n                array([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)\n\n                >>> (h + h).to_state_vector(endian='little')\n                array([0.5+0.j, 0.5+0.j, 0.5+0.j, 0.5+0.j], dtype=complex64)\n        )DOC\")\n            .data());\n\n    c.def(\n        \"to_stabilizers\",\n        [](const Tableau<MAX_BITWORD_WIDTH> &self, bool canonical) {\n            auto stabilizers = self.stabilizers(canonical);\n            std::vector<FlexPauliString> result;\n            result.reserve(stabilizers.size());\n            for (auto &s : stabilizers) {\n                result.emplace_back(std::move(s), false);\n            }\n            return result;\n        },\n        pybind11::kw_only(),\n        pybind11::arg(\"canonicalize\") = false,\n        clean_doc_string(R\"DOC(\n            Returns the stabilizer generators of the tableau, optionally canonicalized.\n\n            The stabilizer generators of the tableau are its Z outputs. Canonicalizing\n            standardizes the generators, so that states that are equal will produce the\n            same generators. For example, [ZI, IZ], [ZI, ZZ], amd [ZZ, ZI] describe equal\n            states and all canonicalize to [ZI, IZ].\n\n            The canonical form is computed as follows:\n\n                1. Get a list of stabilizers using `tableau.z_output(k)` for each k.\n                2. Perform Gaussian elimination. pivoting on standard generators.\n                    2a) Pivot on g=X0 first, then Z0, X1, Z1, X2, Z2, etc.\n                    2b) Find a stabilizer that uses the generator g. If there are none,\n                        go to the next g.\n                    2c) Multiply that stabilizer into all other stabilizers that use the\n                        generator g.\n                    2d) Swap that stabilizer with the stabilizer at position `r` then\n                        increment `r`. `r` starts at 0.\n\n            Args:\n                canonicalize: Defaults to False. When False, the tableau's Z outputs\n                    are returned unchanged. When True, the Z outputs are rewritten\n                    into a standard form. Two stabilizer states have the same standard\n                    form if and only if they describe equivalent quantum states.\n\n            Returns:\n                A List[stim.PauliString] of the tableau's stabilizer generators.\n\n            Examples:\n                >>> import stim\n                >>> t = stim.Tableau.from_named_gate(\"CNOT\")\n\n                >>> raw_stabilizers = t.to_stabilizers()\n                >>> for e in raw_stabilizers:\n                ...     print(repr(e))\n                stim.PauliString(\"+Z_\")\n                stim.PauliString(\"+ZZ\")\n\n                >>> canonical_stabilizers = t.to_stabilizers(canonicalize=True)\n                >>> for e in canonical_stabilizers:\n                ...     print(repr(e))\n                stim.PauliString(\"+Z_\")\n                stim.PauliString(\"+_Z\")\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/stabilizers/tableau.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_STABILIZERS_TABLEAU_PYBIND_H\n#define _STIM_STABILIZERS_TABLEAU_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim_pybind {\n\npybind11::class_<stim::Tableau<stim::MAX_BITWORD_WIDTH>> pybind_tableau(pybind11::module &m);\nvoid pybind_tableau_methods(pybind11::module &m, pybind11::class_<stim::Tableau<stim::MAX_BITWORD_WIDTH>> &c);\n\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/tableau.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/tableau.h\"\n\n#include <random>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gates/gates.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/vector_simulator.h\"\n#include \"stim/stabilizers/tableau_transposed_raii.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nstatic float complex_distance(std::complex<float> a, std::complex<float> b) {\n    auto d = a - b;\n    return sqrtf(d.real() * d.real() + d.imag() * d.imag());\n}\n\nTEST_EACH_WORD_SIZE_W(tableau, identity, {\n    auto t = Tableau<W>::identity(4);\n    ASSERT_EQ(\n        t.str(),\n        \"+-xz-xz-xz-xz-\\n\"\n        \"| ++ ++ ++ ++\\n\"\n        \"| XZ __ __ __\\n\"\n        \"| __ XZ __ __\\n\"\n        \"| __ __ XZ __\\n\"\n        \"| __ __ __ XZ\");\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, gate1, {\n    auto gate1 = Tableau<W>::gate1(\"+X\", \"+Z\");\n    ASSERT_EQ(gate1.xs[0].str(), \"+X\");\n    ASSERT_EQ(gate1.eval_y_obs(0).str(), \"+Y\");\n    ASSERT_EQ(gate1.zs[0].str(), \"+Z\");\n})\n\ntemplate <size_t W>\nbool tableau_agrees_with_unitary(\n    const Tableau<W> &tableau, const std::vector<std::vector<std::complex<float>>> &unitary) {\n    auto n = tableau.num_qubits;\n    assert(unitary.size() == 1ULL << n);\n\n    std::vector<PauliString<W>> basis;\n    for (size_t x = 0; x < 2; x++) {\n        for (size_t k = 0; k < n; k++) {\n            basis.emplace_back(n);\n            if (x) {\n                basis.back().xs[k] ^= 1;\n            } else {\n                basis.back().zs[k] ^= 1;\n            }\n        }\n    }\n\n    for (const auto &input_side_obs : basis) {\n        VectorSimulator sim(n * 2);\n        // Create EPR pairs to test all possible inputs via state channel duality.\n        for (size_t q = 0; q < n; q++) {\n            sim.apply(GateType::H, q);\n            sim.apply(GateType::CX, q, q + n);\n        }\n        // Apply input-side observable.\n        sim.apply<W>(input_side_obs, n);\n        // Apply operation's unitary.\n        std::vector<size_t> qs;\n        for (size_t q = 0; q < n; q++) {\n            qs.push_back(q + n);\n        }\n        sim.apply(unitary, {qs});\n        // Apply output-side observable, which should cancel input-side.\n        sim.apply<W>(tableau(input_side_obs), n);\n\n        // Verify that the state encodes the unitary matrix, with the\n        // input-side and output-side observables having perfectly cancelled out.\n        auto scale = powf(0.5f, 0.5f * n);\n        for (size_t row = 0; row < 1u << n; row++) {\n            for (size_t col = 0; col < 1u << n; col++) {\n                auto a = sim.state[(row << n) | col];\n                auto b = unitary[row][col] * scale;\n                if (complex_distance(a, b) > 1e-4) {\n                    return false;\n                }\n            }\n        }\n    }\n\n    return true;\n}\n\nTEST_EACH_WORD_SIZE_W(tableau, big_not_seeing_double, {\n    Tableau<W> t(500);\n    auto s = t.xs[0].str();\n    size_t n = 0;\n    for (size_t k = 1; k < s.size(); k++) {\n        if (s[k] != '_') {\n            n += 1;\n        }\n    }\n    ASSERT_EQ(n, 1) << s;\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, str, {\n    ASSERT_EQ(\n        Tableau<W>::gate1(\"+X\", \"-Z\").str(),\n        \"+-xz-\\n\"\n        \"| +-\\n\"\n        \"| XZ\");\n    ASSERT_EQ(\n        GATE_DATA.at(\"X\").tableau<W>().str(),\n        \"+-xz-\\n\"\n        \"| +-\\n\"\n        \"| XZ\");\n    ASSERT_EQ(\n        GATE_DATA.at(\"SQRT_Z\").tableau<W>().str(),\n        \"+-xz-\\n\"\n        \"| ++\\n\"\n        \"| YZ\");\n    ASSERT_EQ(\n        GATE_DATA.at(\"SQRT_Z_DAG\").tableau<W>().str(),\n        \"+-xz-\\n\"\n        \"| -+\\n\"\n        \"| YZ\");\n    ASSERT_EQ(\n        GATE_DATA.at(\"H_XZ\").tableau<W>().str(),\n        \"+-xz-\\n\"\n        \"| ++\\n\"\n        \"| ZX\");\n    ASSERT_EQ(\n        GATE_DATA.at(\"ZCX\").tableau<W>().str(),\n        \"+-xz-xz-\\n\"\n        \"| ++ ++\\n\"\n        \"| XZ _Z\\n\"\n        \"| X_ XZ\");\n\n    Tableau<W> t(4);\n    t.prepend_H_XZ(0);\n    t.prepend_H_XZ(1);\n    t.prepend_SQRT_Z(1);\n    t.prepend_ZCX(0, 2);\n    t.prepend_ZCX(1, 3);\n    t.prepend_ZCX(0, 1);\n    t.prepend_ZCX(1, 0);\n    ASSERT_EQ(\n        t.inverse().str(),\n        \"+-xz-xz-xz-xz-\\n\"\n        \"| ++ +- ++ ++\\n\"\n        \"| Z_ ZY _Z _Z\\n\"\n        \"| ZX _X _Z __\\n\"\n        \"| _X __ XZ __\\n\"\n        \"| __ _X __ XZ\");\n    ASSERT_EQ(\n        t.inverse(true).str(),\n        \"+-xz-xz-xz-xz-\\n\"\n        \"| ++ ++ ++ ++\\n\"\n        \"| Z_ ZY _Z _Z\\n\"\n        \"| ZX _X _Z __\\n\"\n        \"| _X __ XZ __\\n\"\n        \"| __ _X __ XZ\");\n    ASSERT_EQ(\n        t.str(),\n        \"+-xz-xz-xz-xz-\\n\"\n        \"| -+ ++ ++ ++\\n\"\n        \"| Z_ ZX _X __\\n\"\n        \"| YX _X __ _X\\n\"\n        \"| X_ X_ XZ __\\n\"\n        \"| X_ __ __ XZ\");\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, gate_tableau_data_vs_unitary_data, {\n    for (const auto &gate : GATE_DATA.items) {\n        if (gate.has_known_unitary_matrix()) {\n            EXPECT_TRUE(tableau_agrees_with_unitary<W>(gate.tableau<W>(), gate.unitary())) << gate.name;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, inverse_data, {\n    for (const auto &gate : GATE_DATA.items) {\n        if (gate.has_known_unitary_matrix()) {\n            auto &inv_gate = gate.inverse();\n            auto tab = gate.tableau<W>();\n            auto inv_tab = inv_gate.tableau<W>();\n            ASSERT_EQ(tab.then(inv_tab), Tableau<W>::identity(tab.num_qubits)) << gate.name << \" -> \" << inv_gate.name;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, eval, {\n    const auto &cnot = GATE_DATA.at(\"ZCX\").tableau<W>();\n    ASSERT_EQ(cnot(PauliString<W>::from_str(\"-XX\")), PauliString<W>::from_str(\"-XI\"));\n    ASSERT_EQ(cnot(PauliString<W>::from_str(\"+XX\")), PauliString<W>::from_str(\"+XI\"));\n    ASSERT_EQ(cnot(PauliString<W>::from_str(\"+ZZ\")), PauliString<W>::from_str(\"+IZ\"));\n    ASSERT_EQ(cnot(PauliString<W>::from_str(\"+IY\")), PauliString<W>::from_str(\"+ZY\"));\n    ASSERT_EQ(cnot(PauliString<W>::from_str(\"+YI\")), PauliString<W>::from_str(\"+YX\"));\n    ASSERT_EQ(cnot(PauliString<W>::from_str(\"+YY\")), PauliString<W>::from_str(\"-XZ\"));\n\n    const auto &x2 = GATE_DATA.at(\"SQRT_X\").tableau<W>();\n    ASSERT_EQ(x2(PauliString<W>::from_str(\"+X\")), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(x2(PauliString<W>::from_str(\"+Y\")), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(x2(PauliString<W>::from_str(\"+Z\")), PauliString<W>::from_str(\"-Y\"));\n\n    const auto &s = GATE_DATA.at(\"SQRT_Z\").tableau<W>();\n    ASSERT_EQ(s(PauliString<W>::from_str(\"+X\")), PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(s(PauliString<W>::from_str(\"+Y\")), PauliString<W>::from_str(\"-X\"));\n    ASSERT_EQ(s(PauliString<W>::from_str(\"+Z\")), PauliString<W>::from_str(\"+Z\"));\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, apply_within, {\n    const auto &cnot = GATE_DATA.at(\"ZCX\").tableau<W>();\n\n    auto p1 = PauliString<W>::from_str(\"-XX\");\n    PauliStringRef<W> p1_ptr(p1);\n    cnot.apply_within(p1_ptr, std::vector<size_t>{0, 1});\n    ASSERT_EQ(p1, PauliString<W>::from_str(\"-XI\"));\n\n    auto p2 = PauliString<W>::from_str(\"+XX\");\n    PauliStringRef<W> p2_ptr(p2);\n    cnot.apply_within(p2_ptr, std::vector<size_t>{0, 1});\n    ASSERT_EQ(p2, PauliString<W>::from_str(\"+XI\"));\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, equality, {\n    ASSERT_TRUE(GATE_DATA.at(\"SQRT_Z\").tableau<W>() == GATE_DATA.at(\"SQRT_Z\").tableau<W>());\n    ASSERT_FALSE(GATE_DATA.at(\"SQRT_Z\").tableau<W>() != GATE_DATA.at(\"SQRT_Z\").tableau<W>());\n    ASSERT_FALSE(GATE_DATA.at(\"SQRT_Z\").tableau<W>() == GATE_DATA.at(\"ZCX\").tableau<W>());\n    ASSERT_TRUE(GATE_DATA.at(\"SQRT_Z\").tableau<W>() != GATE_DATA.at(\"ZCX\").tableau<W>());\n    ASSERT_FALSE(GATE_DATA.at(\"SQRT_Z\").tableau<W>() == GATE_DATA.at(\"SQRT_X\").tableau<W>());\n    ASSERT_TRUE(GATE_DATA.at(\"SQRT_Z\").tableau<W>() != GATE_DATA.at(\"SQRT_X\").tableau<W>());\n    ASSERT_EQ(Tableau<W>(1), GATE_DATA.at(\"I\").tableau<W>());\n    ASSERT_NE(Tableau<W>(1), GATE_DATA.at(\"X\").tableau<W>());\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, inplace_scatter_append, {\n    auto t1 = Tableau<W>::identity(1);\n    t1.inplace_scatter_append(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {0});\n    ASSERT_EQ(t1, GATE_DATA.at(\"SQRT_Z\").tableau<W>());\n    t1.inplace_scatter_append(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {0});\n    ASSERT_EQ(t1, GATE_DATA.at(\"Z\").tableau<W>());\n    t1.inplace_scatter_append(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {0});\n    ASSERT_EQ(t1, GATE_DATA.at(\"SQRT_Z_DAG\").tableau<W>());\n\n    // Test swap decomposition into exp(i pi/2 (XX + YY + ZZ)).\n    auto t2 = Tableau<W>::identity(2);\n    // ZZ^0.5\n    t2.inplace_scatter_append(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {0});\n    t2.inplace_scatter_append(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {1});\n    t2.inplace_scatter_append(GATE_DATA.at(\"ZCZ\").tableau<W>(), {0, 1});\n    // YY^0.5\n    t2.inplace_scatter_append(GATE_DATA.at(\"SQRT_Y\").tableau<W>(), {0});\n    t2.inplace_scatter_append(GATE_DATA.at(\"SQRT_Y\").tableau<W>(), {1});\n    t2.inplace_scatter_append(GATE_DATA.at(\"H_YZ\").tableau<W>(), {0});\n    t2.inplace_scatter_append(GATE_DATA.at(\"ZCY\").tableau<W>(), {0, 1});\n    t2.inplace_scatter_append(GATE_DATA.at(\"H_YZ\").tableau<W>(), {0});\n    // XX^0.5\n    t2.inplace_scatter_append(GATE_DATA.at(\"SQRT_X\").tableau<W>(), {0});\n    t2.inplace_scatter_append(GATE_DATA.at(\"SQRT_X\").tableau<W>(), {1});\n    t2.inplace_scatter_append(GATE_DATA.at(\"H_XZ\").tableau<W>(), {0});\n    t2.inplace_scatter_append(GATE_DATA.at(\"ZCX\").tableau<W>(), {0, 1});\n    t2.inplace_scatter_append(GATE_DATA.at(\"H_XZ\").tableau<W>(), {0});\n    ASSERT_EQ(t2, GATE_DATA.at(\"SWAP\").tableau<W>());\n\n    // Test order dependence.\n    auto t3 = Tableau<W>::identity(2);\n    t3.inplace_scatter_append(GATE_DATA.at(\"H_XZ\").tableau<W>(), {0});\n    t3.inplace_scatter_append(GATE_DATA.at(\"SQRT_X\").tableau<W>(), {1});\n    t3.inplace_scatter_append(GATE_DATA.at(\"ZCX\").tableau<W>(), {0, 1});\n    ASSERT_EQ(t3(PauliString<W>::from_str(\"XI\")), PauliString<W>::from_str(\"ZI\"));\n    ASSERT_EQ(t3(PauliString<W>::from_str(\"ZI\")), PauliString<W>::from_str(\"XX\"));\n    ASSERT_EQ(t3(PauliString<W>::from_str(\"IX\")), PauliString<W>::from_str(\"IX\"));\n    ASSERT_EQ(t3(PauliString<W>::from_str(\"IZ\")), PauliString<W>::from_str(\"-ZY\"));\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, inplace_scatter_prepend, {\n    auto t1 = Tableau<W>::identity(1);\n    t1.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {0});\n    ASSERT_EQ(t1, GATE_DATA.at(\"SQRT_Z\").tableau<W>());\n    t1.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {0});\n    ASSERT_EQ(t1, GATE_DATA.at(\"Z\").tableau<W>());\n    t1.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {0});\n    ASSERT_EQ(t1, GATE_DATA.at(\"SQRT_Z_DAG\").tableau<W>());\n\n    // Test swap decomposition into exp(i pi/2 (XX + YY + ZZ)).\n    auto t2 = Tableau<W>::identity(2);\n    // ZZ^0.5\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {0});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), {1});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"ZCZ\").tableau<W>(), {0, 1});\n    // YY^0.5\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Y\").tableau<W>(), {0});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Y\").tableau<W>(), {1});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"H_YZ\").tableau<W>(), {0});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"ZCY\").tableau<W>(), {0, 1});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"H_YZ\").tableau<W>(), {0});\n    // XX^0.5\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_X\").tableau<W>(), {0});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_X\").tableau<W>(), {1});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"H_XZ\").tableau<W>(), {0});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"ZCX\").tableau<W>(), {0, 1});\n    t2.inplace_scatter_prepend(GATE_DATA.at(\"H_XZ\").tableau<W>(), {0});\n    ASSERT_EQ(t2, GATE_DATA.at(\"SWAP\").tableau<W>());\n\n    // Test order dependence.\n    auto t3 = Tableau<W>::identity(2);\n    t3.inplace_scatter_prepend(GATE_DATA.at(\"H_XZ\").tableau<W>(), {0});\n    t3.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_X\").tableau<W>(), {1});\n    t3.inplace_scatter_prepend(GATE_DATA.at(\"ZCX\").tableau<W>(), {0, 1});\n    ASSERT_EQ(t3(PauliString<W>::from_str(\"XI\")), PauliString<W>::from_str(\"ZX\"));\n    ASSERT_EQ(t3(PauliString<W>::from_str(\"ZI\")), PauliString<W>::from_str(\"XI\"));\n    ASSERT_EQ(t3(PauliString<W>::from_str(\"IX\")), PauliString<W>::from_str(\"IX\"));\n    ASSERT_EQ(t3(PauliString<W>::from_str(\"IZ\")), PauliString<W>::from_str(\"-XY\"));\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, eval_y, {\n    ASSERT_EQ(GATE_DATA.at(\"H_XZ\").tableau<W>().zs[0], PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(GATE_DATA.at(\"SQRT_Z\").tableau<W>().zs[0], PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(GATE_DATA.at(\"H_YZ\").tableau<W>().zs[0], PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(GATE_DATA.at(\"SQRT_Y\").tableau<W>().zs[0], PauliString<W>::from_str(\"X\"));\n    ASSERT_EQ(GATE_DATA.at(\"SQRT_Y_DAG\").tableau<W>().zs[0], PauliString<W>::from_str(\"-X\"));\n    ASSERT_EQ(GATE_DATA.at(\"ZCX\").tableau<W>().zs[1], PauliString<W>::from_str(\"ZZ\"));\n\n    ASSERT_EQ(GATE_DATA.at(\"H_XZ\").tableau<W>().eval_y_obs(0), PauliString<W>::from_str(\"-Y\"));\n    ASSERT_EQ(GATE_DATA.at(\"SQRT_Z\").tableau<W>().eval_y_obs(0), PauliString<W>::from_str(\"-X\"));\n    ASSERT_EQ(GATE_DATA.at(\"H_YZ\").tableau<W>().eval_y_obs(0), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(GATE_DATA.at(\"SQRT_Y\").tableau<W>().eval_y_obs(0), PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(GATE_DATA.at(\"SQRT_Y_DAG\").tableau<W>().eval_y_obs(0), PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(GATE_DATA.at(\"SQRT_X\").tableau<W>().eval_y_obs(0), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(GATE_DATA.at(\"SQRT_X_DAG\").tableau<W>().eval_y_obs(0), PauliString<W>::from_str(\"-Z\"));\n    ASSERT_EQ(GATE_DATA.at(\"ZCX\").tableau<W>().eval_y_obs(1), PauliString<W>::from_str(\"ZY\"));\n})\n\ntemplate <size_t W>\nbool are_tableau_mutations_equivalent(\n    size_t n,\n    const std::function<void(Tableau<W> &t, const std::vector<size_t> &)> &mutation1,\n    const std::function<void(Tableau<W> &t, const std::vector<size_t> &)> &mutation2) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto test_tableau_dual = Tableau<W>::identity(2 * n);\n    std::vector<size_t> targets1;\n    std::vector<size_t> targets2;\n    std::vector<size_t> targets3;\n    for (size_t k = 0; k < n; k++) {\n        test_tableau_dual.inplace_scatter_append(GATE_DATA.at(\"H_XZ\").tableau<W>(), {k});\n        test_tableau_dual.inplace_scatter_append(GATE_DATA.at(\"ZCX\").tableau<W>(), {k, k + n});\n        targets1.push_back(k);\n        targets2.push_back(k + n);\n        targets3.push_back(k + (k % 2 == 0 ? 0 : n));\n    }\n\n    std::vector<Tableau<W>> tableaus{\n        test_tableau_dual,\n        Tableau<W>::random(n + 10, rng),\n        Tableau<W>::random(n + 30, rng),\n    };\n    std::vector<std::vector<size_t>> cases{targets1, targets2, targets3};\n    for (const auto &t : tableaus) {\n        for (const auto &targets : cases) {\n            auto t1 = t;\n            auto t2 = t;\n            mutation1(t1, targets);\n            mutation2(t2, targets);\n            if (t1 != t2) {\n                return false;\n            }\n        }\n    }\n    return true;\n}\n\ntemplate <size_t W>\nbool are_tableau_prepends_equivalent(std::string_view name, const std::function<void(Tableau<W> &t, size_t)> &func) {\n    return are_tableau_mutations_equivalent<W>(\n        1,\n        [&](Tableau<W> &t, const std::vector<size_t> &targets) {\n            t.inplace_scatter_prepend(GATE_DATA.at(name).tableau<W>(), targets);\n        },\n        [&](Tableau<W> &t, const std::vector<size_t> &targets) {\n            func(t, targets[0]);\n        });\n}\n\ntemplate <size_t W>\nbool are_tableau_prepends_equivalent(\n    std::string_view name, const std::function<void(Tableau<W> &t, size_t, size_t)> &func) {\n    return are_tableau_mutations_equivalent<W>(\n        2,\n        [&](Tableau<W> &t, const std::vector<size_t> &targets) {\n            t.inplace_scatter_prepend(GATE_DATA.at(name).tableau<W>(), targets);\n        },\n        [&](Tableau<W> &t, const std::vector<size_t> &targets) {\n            func(t, targets[0], targets[1]);\n        });\n}\n\nTEST_EACH_WORD_SIZE_W(tableau, check_invariants, {\n    ASSERT_TRUE(Tableau<W>::gate1(\"X\", \"Z\").satisfies_invariants());\n    ASSERT_TRUE(Tableau<W>::gate2(\"XI\", \"ZI\", \"IX\", \"IZ\").satisfies_invariants());\n    ASSERT_FALSE(Tableau<W>::gate1(\"X\", \"X\").satisfies_invariants());\n    ASSERT_FALSE(Tableau<W>::gate2(\"XI\", \"ZI\", \"XI\", \"ZI\").satisfies_invariants());\n    ASSERT_FALSE(Tableau<W>::gate2(\"XI\", \"II\", \"IX\", \"IZ\").satisfies_invariants());\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, is_conjugation_by_pauli, {\n    Tableau<W> tableau(8);\n    ASSERT_TRUE(tableau.is_pauli_product());\n    tableau.xs.signs[0] = true;\n    tableau.xs.signs[3] = true;\n    ASSERT_TRUE(tableau.is_pauli_product());\n    tableau.xs.zt[0][2] = true;\n    tableau.zs.zt[0][2] = true;\n    ASSERT_FALSE(tableau.is_pauli_product());\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, to_pauli_string, {\n    Tableau<W> tableau(8);\n    tableau.xs.signs[3] = true;\n    auto pauli_string_z = tableau.to_pauli_string();\n    ASSERT_EQ(pauli_string_z.str(), \"+___Z____\");\n    tableau.zs.signs[3] = true;\n    auto pauli_string_y = tableau.to_pauli_string();\n    ASSERT_EQ(pauli_string_y.str(), \"+___Y____\");\n    tableau.xs.signs[3] = false;\n    tableau.xs.signs[5] = true;\n    auto pauli_string_xz = tableau.to_pauli_string();\n    ASSERT_EQ(pauli_string_xz.str(), \"+___X_Z__\");\n    tableau.xs.zt[0][1] = true;\n    ASSERT_THROW(tableau.to_pauli_string(), std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, from_pauli_string, {\n    auto pauli_string_empty = PauliString<W>::from_str(\"\");\n    auto tableau_empty = Tableau<W>::from_pauli_string(pauli_string_empty);\n    ASSERT_EQ(tableau_empty.to_pauli_string(), pauli_string_empty);\n    auto pauli_string = PauliString<W>::from_str(\"+_XZX__YZZX\");\n    auto tableau = Tableau<W>::from_pauli_string(pauli_string);\n    ASSERT_EQ(tableau.to_pauli_string(), pauli_string);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, random, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (size_t k = 0; k < 20; k++) {\n        auto t = Tableau<W>::random(1, rng);\n        ASSERT_TRUE(t.satisfies_invariants()) << t;\n    }\n    for (size_t k = 0; k < 20; k++) {\n        auto t = Tableau<W>::random(2, rng);\n        ASSERT_TRUE(t.satisfies_invariants()) << t;\n    }\n    for (size_t k = 0; k < 20; k++) {\n        auto t = Tableau<W>::random(3, rng);\n        ASSERT_TRUE(t.satisfies_invariants()) << t;\n    }\n    for (size_t k = 0; k < 20; k++) {\n        auto t = Tableau<W>::random(30, rng);\n        ASSERT_TRUE(t.satisfies_invariants());\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, specialized_operation, {\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            1,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"X\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"X\").tableau<W>(), targets);\n            }));\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            1,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Z\").tableau<W>(), targets);\n            }));\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            2,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"ZCX\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"ZCX\").tableau<W>(), targets);\n            }));\n    EXPECT_FALSE(\n        are_tableau_mutations_equivalent<W>(\n            1,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"H_XZ\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"SQRT_Y\").tableau<W>(), targets);\n            }));\n    EXPECT_FALSE(\n        are_tableau_mutations_equivalent<W>(\n            2,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"ZCX\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_prepend(GATE_DATA.at(\"ZCZ\").tableau<W>(), targets);\n            }));\n\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"H_XZ\", &Tableau<W>::prepend_H_XZ));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"H_YZ\", &Tableau<W>::prepend_H_YZ));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"H_XY\", &Tableau<W>::prepend_H_XY));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"X\", &Tableau<W>::prepend_X));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"Y\", &Tableau<W>::prepend_Y));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"Z\", &Tableau<W>::prepend_Z));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"C_XYZ\", &Tableau<W>::prepend_C_XYZ));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"C_ZYX\", &Tableau<W>::prepend_C_ZYX));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_X\", &Tableau<W>::prepend_SQRT_X));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_Y\", &Tableau<W>::prepend_SQRT_Y));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_Z\", &Tableau<W>::prepend_SQRT_Z));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_X_DAG\", &Tableau<W>::prepend_SQRT_X_DAG));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_Y_DAG\", &Tableau<W>::prepend_SQRT_Y_DAG));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_Z_DAG\", &Tableau<W>::prepend_SQRT_Z_DAG));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SWAP\", &Tableau<W>::prepend_SWAP));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"ZCX\", &Tableau<W>::prepend_ZCX));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"ZCY\", &Tableau<W>::prepend_ZCY));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"ZCZ\", &Tableau<W>::prepend_ZCZ));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"ISWAP\", &Tableau<W>::prepend_ISWAP));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"ISWAP_DAG\", &Tableau<W>::prepend_ISWAP_DAG));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"XCX\", &Tableau<W>::prepend_XCX));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"XCY\", &Tableau<W>::prepend_XCY));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"XCZ\", &Tableau<W>::prepend_XCZ));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"YCX\", &Tableau<W>::prepend_YCX));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"YCY\", &Tableau<W>::prepend_YCY));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"YCZ\", &Tableau<W>::prepend_YCZ));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_XX\", &Tableau<W>::prepend_SQRT_XX));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_XX_DAG\", &Tableau<W>::prepend_SQRT_XX_DAG));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_YY\", &Tableau<W>::prepend_SQRT_YY));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_YY_DAG\", &Tableau<W>::prepend_SQRT_YY_DAG));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_ZZ\", &Tableau<W>::prepend_SQRT_ZZ));\n    EXPECT_TRUE(are_tableau_prepends_equivalent<W>(\"SQRT_ZZ_DAG\", &Tableau<W>::prepend_SQRT_ZZ_DAG));\n\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            1,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_append(GATE_DATA.at(\"X\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                TableauTransposedRaii<W>(t).append_X(targets[0]);\n            }));\n\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            1,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_append(GATE_DATA.at(\"H_XZ\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                TableauTransposedRaii<W>(t).append_H_XZ(targets[0]);\n            }));\n\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            1,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_append(GATE_DATA.at(\"H_XY\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                TableauTransposedRaii<W>(t).append_H_XY(targets[0]);\n            }));\n\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            1,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_append(GATE_DATA.at(\"H_YZ\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                TableauTransposedRaii<W>(t).append_H_YZ(targets[0]);\n            }));\n\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            1,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_append(GATE_DATA.at(\"S\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                TableauTransposedRaii<W>(t).append_S(targets[0]);\n            }));\n\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            2,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_append(GATE_DATA.at(\"ZCX\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                TableauTransposedRaii<W>(t).append_ZCX(targets[0], targets[1]);\n            }));\n\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            2,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_append(GATE_DATA.at(\"ZCY\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                TableauTransposedRaii<W>(t).append_ZCY(targets[0], targets[1]);\n            }));\n\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            2,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_append(GATE_DATA.at(\"ZCZ\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                TableauTransposedRaii<W>(t).append_ZCZ(targets[0], targets[1]);\n            }));\n\n    EXPECT_TRUE(\n        are_tableau_mutations_equivalent<W>(\n            2,\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                t.inplace_scatter_append(GATE_DATA.at(\"SWAP\").tableau<W>(), targets);\n            },\n            [](Tableau<W> &t, const std::vector<size_t> &targets) {\n                TableauTransposedRaii<W>(t).append_SWAP(targets[0], targets[1]);\n            }));\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, expand, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t = Tableau<W>::random(4, rng);\n    auto t2 = t;\n    for (size_t n = 8; n < 500; n += 255) {\n        t2.expand(n, 1.0);\n        ASSERT_EQ(t2.num_qubits, n);\n        for (size_t k = 0; k < n; k++) {\n            if (k < 4) {\n                ASSERT_EQ(t.xs[k].sign, t2.xs[k].sign);\n                ASSERT_EQ(t.zs[k].sign, t2.zs[k].sign);\n            } else {\n                ASSERT_EQ(t2.xs[k].sign, false);\n                ASSERT_EQ(t2.zs[k].sign, false);\n            }\n            for (size_t k2 = 0; k2 < n; k2++) {\n                if (k < 4 && k2 < 4) {\n                    ASSERT_EQ(t.xs[k].xs[k2], t2.xs[k].xs[k2]);\n                    ASSERT_EQ(t.xs[k].zs[k2], t2.xs[k].zs[k2]);\n                    ASSERT_EQ(t.zs[k].xs[k2], t2.zs[k].xs[k2]);\n                    ASSERT_EQ(t.zs[k].zs[k2], t2.zs[k].zs[k2]);\n                } else if (k == k2) {\n                    ASSERT_EQ(t2.xs[k].xs[k2], true);\n                    ASSERT_EQ(t2.xs[k].zs[k2], false);\n                    ASSERT_EQ(t2.zs[k].xs[k2], false);\n                    ASSERT_EQ(t2.zs[k].zs[k2], true);\n                } else {\n                    ASSERT_EQ(t2.xs[k].xs[k2], false);\n                    ASSERT_EQ(t2.xs[k].zs[k2], false);\n                    ASSERT_EQ(t2.zs[k].xs[k2], false);\n                    ASSERT_EQ(t2.zs[k].zs[k2], false);\n                }\n            }\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, expand_pad, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t = Tableau<W>::random(4, rng);\n    auto t2 = t;\n    size_t n = 8;\n    while (n < 10000) {\n        n++;\n        t2.expand(n, 2);\n    }\n\n    ASSERT_EQ(t2.num_qubits, n);\n    for (size_t k = 0; k < n; k++) {\n        if (k < 4) {\n            ASSERT_EQ(t.xs[k].sign, t2.xs[k].sign);\n            ASSERT_EQ(t.zs[k].sign, t2.zs[k].sign);\n        } else {\n            ASSERT_EQ(t2.xs[k].sign, false);\n            ASSERT_EQ(t2.zs[k].sign, false);\n        }\n        for (size_t k2 = 0; k2 < n; k2++) {\n            if (k2 == 4 && k > 8) {\n                k2 = k - 2;\n            }\n            if (k2 == k + 2) {\n                k2 = n - 1;\n            }\n            if (k < 4 && k2 < 4) {\n                ASSERT_EQ(t.xs[k].xs[k2], t2.xs[k].xs[k2]);\n                ASSERT_EQ(t.xs[k].zs[k2], t2.xs[k].zs[k2]);\n                ASSERT_EQ(t.zs[k].xs[k2], t2.zs[k].xs[k2]);\n                ASSERT_EQ(t.zs[k].zs[k2], t2.zs[k].zs[k2]);\n            } else if (k == k2) {\n                ASSERT_EQ(t2.xs[k].xs[k2], true);\n                ASSERT_EQ(t2.xs[k].zs[k2], false);\n                ASSERT_EQ(t2.zs[k].xs[k2], false);\n                ASSERT_EQ(t2.zs[k].zs[k2], true);\n            } else {\n                ASSERT_EQ(t2.xs[k].xs[k2], false);\n                ASSERT_EQ(t2.xs[k].zs[k2], false);\n                ASSERT_EQ(t2.zs[k].xs[k2], false);\n                ASSERT_EQ(t2.zs[k].zs[k2], false);\n            }\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, expand_pad_equals, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t = Tableau<W>::random(15, rng);\n    auto t2 = t;\n    t.expand(500, 1.0);\n    t2.expand(500, 2.0);\n    ASSERT_EQ(t, t2);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, transposed_access, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    size_t n = W > 256 ? 1000 : 400;\n    Tableau<W> t(n);\n    auto m = t.xs.xt.data.num_bits_padded();\n    t.xs.xt.data.randomize(m, rng);\n    t.xs.zt.data.randomize(m, rng);\n    t.zs.xt.data.randomize(m, rng);\n    t.zs.zt.data.randomize(m, rng);\n    for (size_t inp_qubit = 0; inp_qubit < n; inp_qubit += 99) {\n        for (size_t out_qubit = 0; out_qubit < n; out_qubit += 99) {\n            bool bxx = t.xs.xt[inp_qubit][out_qubit];\n            bool bxz = t.xs.zt[inp_qubit][out_qubit];\n            bool bzx = t.zs.xt[inp_qubit][out_qubit];\n            bool bzz = t.zs.zt[inp_qubit][out_qubit];\n\n            ASSERT_EQ(t.xs[inp_qubit].xs[out_qubit], bxx) << inp_qubit << \", \" << out_qubit;\n            ASSERT_EQ(t.xs[inp_qubit].zs[out_qubit], bxz) << inp_qubit << \", \" << out_qubit;\n            ASSERT_EQ(t.zs[inp_qubit].xs[out_qubit], bzx) << inp_qubit << \", \" << out_qubit;\n            ASSERT_EQ(t.zs[inp_qubit].zs[out_qubit], bzz) << inp_qubit << \", \" << out_qubit;\n\n            {\n                TableauTransposedRaii<W> trans(t);\n                ASSERT_EQ(t.xs.xt[out_qubit][inp_qubit], bxx);\n                ASSERT_EQ(t.xs.zt[out_qubit][inp_qubit], bxz);\n                ASSERT_EQ(t.zs.xt[out_qubit][inp_qubit], bzx);\n                ASSERT_EQ(t.zs.zt[out_qubit][inp_qubit], bzz);\n            }\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, inverse, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    Tableau<W> t1(1);\n    ASSERT_EQ(t1, t1.inverse());\n    t1.prepend_X(0);\n    ASSERT_EQ(t1, GATE_DATA.at(\"X\").tableau<W>());\n    auto t2 = t1.inverse();\n    ASSERT_EQ(t1, GATE_DATA.at(\"X\").tableau<W>());\n    ASSERT_EQ(t2, GATE_DATA.at(\"X\").tableau<W>());\n\n    for (size_t k = 5; k < 20; k += 7) {\n        t1 = Tableau<W>::random(k, rng);\n        t2 = t1.inverse();\n        ASSERT_TRUE(t2.satisfies_invariants());\n        auto p = PauliString<W>::random(k, rng);\n        auto p2 = t1(t2(p));\n        auto x1 = p.xs.str();\n        auto x2 = p2.xs.str();\n        auto z1 = p.zs.str();\n        auto z2 = p2.zs.str();\n        ASSERT_EQ(p, p2);\n        ASSERT_EQ(p, t2(t1(p)));\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, prepend_pauli_product, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t = Tableau<W>::random(6, rng);\n    auto ref = t;\n    t.prepend_pauli_product(PauliString<W>::from_str(\"_XYZ__\"));\n    ref.prepend_X(1);\n    ref.prepend_Y(2);\n    ref.prepend_Z(3);\n    ASSERT_EQ(t, ref);\n    t.prepend_pauli_product(PauliString<W>::from_str(\"Y_ZX__\"));\n    ref.prepend_X(3);\n    ref.prepend_Y(0);\n    ref.prepend_Z(2);\n    ASSERT_EQ(t, ref);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, then, {\n    auto cnot = GATE_DATA.at(\"CNOT\").tableau<W>();\n    auto swap = GATE_DATA.at(\"SWAP\").tableau<W>();\n    Tableau<W> hh(2);\n    hh.inplace_scatter_append(GATE_DATA.at(\"H\").tableau<W>(), {0});\n    hh.inplace_scatter_append(GATE_DATA.at(\"H\").tableau<W>(), {1});\n\n    ASSERT_EQ(cnot.then(cnot), Tableau<W>(2));\n    ASSERT_EQ(hh.then(cnot).then(hh), swap.then(cnot).then(swap));\n    ASSERT_EQ(cnot.then(cnot), Tableau<W>(2));\n\n    Tableau<W> t(2);\n    t.inplace_scatter_append(GATE_DATA.at(\"SQRT_X_DAG\").tableau<W>(), {1});\n    t = t.then(GATE_DATA.at(\"CY\").tableau<W>());\n    t.inplace_scatter_append(GATE_DATA.at(\"SQRT_X\").tableau<W>(), {1});\n    ASSERT_EQ(t, GATE_DATA.at(\"CZ\").tableau<W>());\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, raised_to, {\n    auto cnot = GATE_DATA.at(\"CNOT\").tableau<W>();\n    ASSERT_EQ(cnot.raised_to(-97268202), Tableau<W>(2));\n    ASSERT_EQ(cnot.raised_to(-97268201), cnot);\n    ASSERT_EQ(cnot.raised_to(-3), cnot);\n    ASSERT_EQ(cnot.raised_to(-2), Tableau<W>(2));\n    ASSERT_EQ(cnot.raised_to(-1), cnot);\n    ASSERT_EQ(cnot.raised_to(0), Tableau<W>(2));\n    ASSERT_EQ(cnot.raised_to(1), cnot);\n    ASSERT_EQ(cnot.raised_to(2), Tableau<W>(2));\n    ASSERT_EQ(cnot.raised_to(3), cnot);\n    ASSERT_EQ(cnot.raised_to(4), Tableau<W>(2));\n    ASSERT_EQ(cnot.raised_to(97268201), cnot);\n    ASSERT_EQ(cnot.raised_to(97268202), Tableau<W>(2));\n\n    auto s = GATE_DATA.at(\"S\").tableau<W>();\n    auto z = GATE_DATA.at(\"Z\").tableau<W>();\n    auto s_dag = GATE_DATA.at(\"S_DAG\").tableau<W>();\n    ASSERT_EQ(s.raised_to(4 * -437829 + 0), Tableau<W>(1));\n    ASSERT_EQ(s.raised_to(4 * -437829 + 1), s);\n    ASSERT_EQ(s.raised_to(4 * -437829 + 2), z);\n    ASSERT_EQ(s.raised_to(4 * -437829 + 3), s_dag);\n    ASSERT_EQ(s.raised_to(-5), s_dag);\n    ASSERT_EQ(s.raised_to(-4), Tableau<W>(1));\n    ASSERT_EQ(s.raised_to(-3), s);\n    ASSERT_EQ(s.raised_to(-2), z);\n    ASSERT_EQ(s.raised_to(-1), s_dag);\n    ASSERT_EQ(s.raised_to(0), Tableau<W>(1));\n    ASSERT_EQ(s.raised_to(1), s);\n    ASSERT_EQ(s.raised_to(2), z);\n    ASSERT_EQ(s.raised_to(3), s_dag);\n    ASSERT_EQ(s.raised_to(4), Tableau<W>(1));\n    ASSERT_EQ(s.raised_to(5), s);\n    ASSERT_EQ(s.raised_to(6), z);\n    ASSERT_EQ(s.raised_to(7), s_dag);\n    ASSERT_EQ(s.raised_to(4 * 437829 + 0), Tableau<W>(1));\n    ASSERT_EQ(s.raised_to(4 * 437829 + 1), s);\n    ASSERT_EQ(s.raised_to(4 * 437829 + 2), z);\n    ASSERT_EQ(s.raised_to(4 * 437829 + 3), s_dag);\n\n    Tableau<W> p15(3);\n    p15.inplace_scatter_append(GATE_DATA.at(\"SQRT_X\").tableau<W>(), {0});\n    p15.inplace_scatter_append(s, {2});\n    p15.inplace_scatter_append(cnot, {0, 1});\n    p15.inplace_scatter_append(cnot, {1, 2});\n    for (size_t k = 1; k < 15; k++) {\n        ASSERT_NE(p15.raised_to(k), Tableau<W>(3));\n    }\n    ASSERT_EQ(p15.raised_to(15), Tableau<W>(3));\n    ASSERT_EQ(p15.raised_to(15 * 47321 + 4), p15.raised_to(4));\n    ASSERT_EQ(p15.raised_to(15 * 47321 + 1), p15);\n    ASSERT_EQ(p15.raised_to(15 * -47321 + 1), p15);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, transposed_xz_input, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t = Tableau<W>::random(4, rng);\n    PauliString<W> x0(0);\n    PauliString<W> x1(0);\n    {\n        TableauTransposedRaii<W> tmp(t);\n        x0 = tmp.unsigned_x_input(0);\n        x1 = tmp.unsigned_x_input(1);\n    }\n    auto tx0 = t(x0);\n    auto tx1 = t(x1);\n    tx0.sign = false;\n    tx1.sign = false;\n    ASSERT_EQ(tx0, PauliString<W>::from_str(\"X___\"));\n    ASSERT_EQ(tx1, PauliString<W>::from_str(\"_X__\"));\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, direct_sum, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t1 = Tableau<W>::random(160, rng);\n    auto t2 = Tableau<W>::random(170, rng);\n    auto t3 = t1;\n    t3 += t2;\n    ASSERT_EQ(t3, t1 + t2);\n\n    PauliString<W> p1 = t1.xs[5];\n    p1.ensure_num_qubits(160 + 170, 1.0);\n    ASSERT_EQ(t3.xs[5], p1);\n\n    std::string p2 = t2.xs[6].str();\n    std::string p3 = t3.xs[166].str();\n    ASSERT_EQ(p2[0], p3[0]);\n    p2 = p2.substr(1);\n    p3 = p3.substr(1);\n    for (size_t k = 0; k < 160; k++) {\n        ASSERT_EQ(p3[k], '_');\n    }\n    for (size_t k = 0; k < 170; k++) {\n        ASSERT_EQ(p3[160 + k], p2[k]);\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, pauli_access_methods, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t = Tableau<W>::random(3, rng);\n    auto t_inv = t.inverse();\n    for (size_t i = 0; i < 3; i++) {\n        auto x = t.xs[i];\n        auto y = t.eval_y_obs(i);\n        auto z = t.zs[i];\n        for (size_t j = 0; j < 3; j++) {\n            ASSERT_EQ(t.x_output_pauli_xyz(i, j), pauli_xz_to_xyz(x.xs[j], x.zs[j]));\n            ASSERT_EQ(t.y_output_pauli_xyz(i, j), pauli_xz_to_xyz(y.xs[j], y.zs[j]));\n            ASSERT_EQ(t.z_output_pauli_xyz(i, j), pauli_xz_to_xyz(z.xs[j], z.zs[j]));\n            ASSERT_EQ(t_inv.inverse_x_output_pauli_xyz(i, j), pauli_xz_to_xyz(x.xs[j], x.zs[j]));\n            ASSERT_EQ(t_inv.inverse_y_output_pauli_xyz(i, j), pauli_xz_to_xyz(y.xs[j], y.zs[j]));\n            ASSERT_EQ(t_inv.inverse_z_output_pauli_xyz(i, j), pauli_xz_to_xyz(z.xs[j], z.zs[j]));\n        }\n    }\n\n    t = Tableau<W>(3);\n    t.xs[0] = PauliString<W>::from_str(\"+XXX\");\n    t.xs[1] = PauliString<W>::from_str(\"-XZY\");\n    t.xs[2] = PauliString<W>::from_str(\"+Z_Z\");\n    t.zs[0] = PauliString<W>::from_str(\"-_XZ\");\n    t.zs[1] = PauliString<W>::from_str(\"-_X_\");\n    t.zs[2] = PauliString<W>::from_str(\"-X__\");\n\n    ASSERT_EQ(t.x_output_pauli_xyz(0, 0), 1);\n    ASSERT_EQ(t.x_output_pauli_xyz(0, 1), 1);\n    ASSERT_EQ(t.x_output_pauli_xyz(0, 2), 1);\n    ASSERT_EQ(t.x_output_pauli_xyz(1, 0), 1);\n    ASSERT_EQ(t.x_output_pauli_xyz(1, 1), 3);\n    ASSERT_EQ(t.x_output_pauli_xyz(1, 2), 2);\n    ASSERT_EQ(t.x_output_pauli_xyz(2, 0), 3);\n    ASSERT_EQ(t.x_output_pauli_xyz(2, 1), 0);\n    ASSERT_EQ(t.x_output_pauli_xyz(2, 2), 3);\n\n    ASSERT_EQ(t.z_output_pauli_xyz(0, 0), 0);\n    ASSERT_EQ(t.z_output_pauli_xyz(0, 1), 1);\n    ASSERT_EQ(t.z_output_pauli_xyz(0, 2), 3);\n    ASSERT_EQ(t.z_output_pauli_xyz(1, 0), 0);\n    ASSERT_EQ(t.z_output_pauli_xyz(1, 1), 1);\n    ASSERT_EQ(t.z_output_pauli_xyz(1, 2), 0);\n    ASSERT_EQ(t.z_output_pauli_xyz(2, 0), 1);\n    ASSERT_EQ(t.z_output_pauli_xyz(2, 1), 0);\n    ASSERT_EQ(t.z_output_pauli_xyz(2, 2), 0);\n\n    t = t.inverse();\n    ASSERT_EQ(t.inverse_x_output_pauli_xyz(0, 0), 1);\n    ASSERT_EQ(t.inverse_x_output_pauli_xyz(0, 1), 1);\n    ASSERT_EQ(t.inverse_x_output_pauli_xyz(0, 2), 1);\n    ASSERT_EQ(t.inverse_x_output_pauli_xyz(1, 0), 1);\n    ASSERT_EQ(t.inverse_x_output_pauli_xyz(1, 1), 3);\n    ASSERT_EQ(t.inverse_x_output_pauli_xyz(1, 2), 2);\n    ASSERT_EQ(t.inverse_x_output_pauli_xyz(2, 0), 3);\n    ASSERT_EQ(t.inverse_x_output_pauli_xyz(2, 1), 0);\n    ASSERT_EQ(t.inverse_x_output_pauli_xyz(2, 2), 3);\n\n    ASSERT_EQ(t.inverse_z_output_pauli_xyz(0, 0), 0);\n    ASSERT_EQ(t.inverse_z_output_pauli_xyz(0, 1), 1);\n    ASSERT_EQ(t.inverse_z_output_pauli_xyz(0, 2), 3);\n    ASSERT_EQ(t.inverse_z_output_pauli_xyz(1, 0), 0);\n    ASSERT_EQ(t.inverse_z_output_pauli_xyz(1, 1), 1);\n    ASSERT_EQ(t.inverse_z_output_pauli_xyz(1, 2), 0);\n    ASSERT_EQ(t.inverse_z_output_pauli_xyz(2, 0), 1);\n    ASSERT_EQ(t.inverse_z_output_pauli_xyz(2, 1), 0);\n    ASSERT_EQ(t.inverse_z_output_pauli_xyz(2, 2), 0);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, inverse_pauli_string_acces_methods, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto t = Tableau<W>::random(5, rng);\n    auto t_inv = t.inverse();\n    auto y0 = t_inv.eval_y_obs(0);\n    auto y1 = t_inv.eval_y_obs(1);\n    auto y2 = t_inv.eval_y_obs(2);\n    ASSERT_EQ(t.inverse_x_output(0), t_inv.xs[0]);\n    ASSERT_EQ(t.inverse_x_output(1), t_inv.xs[1]);\n    ASSERT_EQ(t.inverse_x_output(2), t_inv.xs[2]);\n    ASSERT_EQ(t.inverse_y_output(0), y0);\n    ASSERT_EQ(t.inverse_y_output(1), y1);\n    ASSERT_EQ(t.inverse_y_output(2), y2);\n    ASSERT_EQ(t.inverse_z_output(0), t_inv.zs[0]);\n    ASSERT_EQ(t.inverse_z_output(1), t_inv.zs[1]);\n    ASSERT_EQ(t.inverse_z_output(2), t_inv.zs[2]);\n\n    t_inv.xs.signs.clear();\n    t_inv.zs.signs.clear();\n    y0.sign = false;\n    y1.sign = false;\n    y2.sign = false;\n    ASSERT_EQ(t.inverse_x_output(0, true), t_inv.xs[0]);\n    ASSERT_EQ(t.inverse_x_output(1, true), t_inv.xs[1]);\n    ASSERT_EQ(t.inverse_x_output(2, true), t_inv.xs[2]);\n    ASSERT_EQ(t.inverse_y_output(0, true), y0);\n    ASSERT_EQ(t.inverse_y_output(1, true), y1);\n    ASSERT_EQ(t.inverse_y_output(2, true), y2);\n    ASSERT_EQ(t.inverse_z_output(0, true), t_inv.zs[0]);\n    ASSERT_EQ(t.inverse_z_output(1, true), t_inv.zs[1]);\n    ASSERT_EQ(t.inverse_z_output(2, true), t_inv.zs[2]);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, unitary_little_endian, {\n    Tableau<W> t(1);\n    ASSERT_EQ(t.to_flat_unitary_matrix(false), (std::vector<std::complex<float>>{1, 0, 0, 1}));\n    t.prepend_SQRT_Y(0);\n    auto s = sqrtf(0.5);\n    ASSERT_EQ(t.to_flat_unitary_matrix(false), (std::vector<std::complex<float>>{s, -s, s, s}));\n    t.prepend_SQRT_Y(0);\n    ASSERT_EQ(t.to_flat_unitary_matrix(false), (std::vector<std::complex<float>>{0, 1, -1, 0}));\n    t.prepend_SQRT_Y(0);\n    ASSERT_EQ(t.to_flat_unitary_matrix(false), (std::vector<std::complex<float>>{s, s, -s, s}));\n\n    t = Tableau<W>(2);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}));\n    t.prepend_X(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}));\n    t.prepend_X(0);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0}));\n    t.prepend_X(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0}));\n    t.prepend_X(0);\n\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}));\n    t.prepend_Z(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1}));\n    t.prepend_Z(0);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1}));\n    t.prepend_Z(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1}));\n    t.prepend_Z(0);\n\n    t.prepend_SQRT_Z(0);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, {0, 1}, 0, 0, 0, 0, {0, 1}}));\n    t.prepend_SQRT_Z_DAG(0);\n\n    t.prepend_H_XZ(0);\n    t.prepend_H_XZ(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(false),\n        (std::vector<std::complex<float>>{\n            0.5,\n            0.5,\n            0.5,\n            0.5,\n            0.5,\n            -0.5,\n            0.5,\n            -0.5,\n            0.5,\n            0.5,\n            -0.5,\n            -0.5,\n            0.5,\n            -0.5,\n            -0.5,\n            0.5,\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, unitary_big_endian, {\n    Tableau<W> t(1);\n    ASSERT_EQ(t.to_flat_unitary_matrix(true), (std::vector<std::complex<float>>{1, 0, 0, 1}));\n    t.prepend_SQRT_Y(0);\n    auto s = sqrtf(0.5);\n    ASSERT_EQ(t.to_flat_unitary_matrix(false), (std::vector<std::complex<float>>{s, -s, s, s}));\n    t.prepend_SQRT_Y(0);\n    ASSERT_EQ(t.to_flat_unitary_matrix(false), (std::vector<std::complex<float>>{0, 1, -1, 0}));\n    t.prepend_SQRT_Y(0);\n    ASSERT_EQ(t.to_flat_unitary_matrix(false), (std::vector<std::complex<float>>{s, s, -s, s}));\n\n    t = Tableau<W>(2);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}));\n    t.prepend_X(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0}));\n    t.prepend_X(0);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0}));\n    t.prepend_X(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0}));\n    t.prepend_X(0);\n\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}));\n    t.prepend_Z(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1}));\n    t.prepend_Z(0);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1}));\n    t.prepend_Z(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1}));\n    t.prepend_Z(0);\n\n    t.prepend_SQRT_Z(0);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{1, 0, 0, 0, 0, {0, 1}, 0, 0, 0, 0, 1, 0, 0, 0, 0, {0, 1}}));\n    t.prepend_SQRT_Z_DAG(0);\n\n    t.prepend_H_XZ(0);\n    t.prepend_H_XZ(1);\n    ASSERT_EQ(\n        t.to_flat_unitary_matrix(true),\n        (std::vector<std::complex<float>>{\n            0.5,\n            0.5,\n            0.5,\n            0.5,\n            0.5,\n            -0.5,\n            0.5,\n            -0.5,\n            0.5,\n            0.5,\n            -0.5,\n            -0.5,\n            0.5,\n            -0.5,\n            -0.5,\n            0.5,\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, unitary_vs_gate_data, {\n    for (const auto &gate : GATE_DATA.items) {\n        if (gate.has_known_unitary_matrix()) {\n            std::vector<std::complex<float>> flat_expected;\n            for (const auto &row : gate.unitary()) {\n                flat_expected.insert(flat_expected.end(), row.begin(), row.end());\n            }\n            VectorSimulator v(0);\n            v.state = std::move(flat_expected);\n            v.canonicalize_assuming_stabilizer_state((gate.flags & stim::GATE_TARGETS_PAIRS) ? 4 : 2);\n            EXPECT_EQ(gate.tableau<W>().to_flat_unitary_matrix(true), v.state) << gate.name;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(tableau, inverse_not_confused_by_size_padding, {\n    // Create a tableau where the avoid-quadratic-overhead padding causes it to pad over a simd word size boundary.\n    Tableau<W> t(1);\n    t += Tableau<W>(500);\n\n    // Check that inverting it doesn't produce garbage.\n    Tableau<W> t_inv = t.inverse();\n    ASSERT_EQ(t_inv, t);\n})\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_iter.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_STABILIZERS_TABLEAU_ITER_H\n#define _STIM_STABILIZERS_TABLEAU_ITER_H\n\n#include \"stim/mem/fixed_cap_vector.h\"\n#include \"stim/mem/span_ref.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\n/// Iterates over Pauli strings that match commutators and anticommutators.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstruct CommutingPauliStringIterator {\n    // Fields defining the pauli strings that will be iterated.\n    size_t num_qubits;\n    SpanRef<const PauliStringRef<W>> cur_desired_commutators;\n    SpanRef<const PauliStringRef<W>> cur_desired_anticommutators;\n\n    // Fields tracking progress of the iteration.\n    PauliString<W> current;                  // The current Pauli string being considered.\n    size_t next_output_index;                // Next thing to return from buffer.\n    size_t filled_output;                    // Number of used entries in buffer.\n    std::vector<PauliString<W>> output_buf;  // Pre-allocated buffer.\n\n    CommutingPauliStringIterator(size_t num_qubits);\n\n    /// Restarts iteration, and changes the target commutators/anticommutators.\n    void restart_iter(SpanRef<const PauliStringRef<W>> commutators, SpanRef<const PauliStringRef<W>> anticommutators);\n    void restart_iter_same_constraints();\n\n    /// Yields the next iterated Pauli string (or nullptr if iteration over).\n    const PauliString<W> *iter_next();\n\n    /// Checks whether the given Pauli string (versus) commutes with 64 variants\n    /// of `current` created by varying its first three Paulis. Assumes that the\n    /// first three Paulis of current are set to I.\n    ///\n    /// Args:\n    ///     versus: The Pauli string to compare to (to see if we commute or\n    ///         anticommute.\n    ///\n    /// Returns:\n    ///     A 64 bit integer where the k'th bit corresponds to whether the k'th\n    ///     variant of the current Pauli string commuted or not. The bits of k\n    ///     (where k is the index of a bit in the result) are x0, x1, x2, z0,\n    ///     z1, z2 in little endian order.\n    uint64_t mass_anticommute_check(const PauliStringRef<W> versus);\n\n    /// Internal method used for refilling a buffer of results.\n    void load_more();\n};\n\n/// Iterates over tableaus of a given size.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstruct TableauIterator {\n    bool also_iter_signs;                                // If false, only unsigned tableaus are yielded.\n    Tableau<W> result;                                   // Pre-allocated result storage.\n    std::vector<PauliStringRef<W>> tableau_column_refs;  // Quick access to tableau columns.\n\n    // Fields tracking the progress of iteration.\n    size_t cur_k;\n    std::vector<CommutingPauliStringIterator<W>> pauli_string_iterators;\n\n    TableauIterator(size_t num_qubits, bool also_iter_signs);\n    TableauIterator(const TableauIterator<W> &);\n    TableauIterator &operator=(const TableauIterator<W> &);\n    TableauIterator &operator=(TableauIterator<W> &&) = delete;\n\n    /// Updates the `result` field to point at the next yielded tableau.\n    /// Returns true if this succeeded, or false if iteration has ended.\n    bool iter_next();\n\n    // Restarts iteration.\n    void restart();\n    std::pair<SpanRef<const PauliStringRef<W>>, SpanRef<const PauliStringRef<W>>> constraints_for_pauli_iterator(\n        size_t k) const;\n};\n\n}  // namespace stim\n\n#include \"stim/stabilizers/tableau_iter.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_iter.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/stabilizers/tableau_iter.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nCommutingPauliStringIterator<W>::CommutingPauliStringIterator(size_t num_qubits)\n    : num_qubits(num_qubits),\n      cur_desired_commutators(),\n      cur_desired_anticommutators(),\n      current(num_qubits),\n      next_output_index(0),\n      filled_output(0),\n      output_buf() {\n    if (num_qubits < 1) {\n        throw std::invalid_argument(\"Too few qubits (num_qubits < 1).\");\n    }\n    if (num_qubits >= 64) {\n        throw std::invalid_argument(\"Too many qubits to iterate tableaus (num_qubits > 64).\");\n    }\n    while (output_buf.size() < 64) {\n        output_buf.push_back(PauliString<W>(num_qubits));\n    }\n}\n\ntemplate <size_t W>\nuint64_t CommutingPauliStringIterator<W>::mass_anticommute_check(const PauliStringRef<W> versus) {\n    constexpr uint64_t x0 = 0xAAAAAAAAAAAAAAAAUL;\n    constexpr uint64_t x1 = 0xCCCCCCCCCCCCCCCCUL;\n    constexpr uint64_t x2 = 0xF0F0F0F0F0F0F0F0UL;\n    constexpr uint64_t z0 = 0xFF00FF00FF00FF00UL;\n    constexpr uint64_t z1 = 0xFFFF0000FFFF0000UL;\n    constexpr uint64_t z2 = 0xFFFFFFFF00000000UL;\n\n    uint64_t result = 0;\n    if (versus.zs[0])\n        result ^= x0;\n    if (versus.zs[1])\n        result ^= x1;\n    if (versus.zs[2])\n        result ^= x2;\n    if (versus.xs[0])\n        result ^= z0;\n    if (versus.xs[1])\n        result ^= z1;\n    if (versus.xs[2])\n        result ^= z2;\n    if (versus.num_qubits > 3 && !versus.commutes(current)) {\n        result ^= -1;\n    }\n    return result;\n}\n\ntemplate <size_t W>\nvoid CommutingPauliStringIterator<W>::restart_iter_same_constraints() {\n    current.xs.u64[0] = 0;\n    current.zs.u64[0] = 0;\n    next_output_index = 0;\n    filled_output = 0;\n}\n\ntemplate <size_t W>\nvoid CommutingPauliStringIterator<W>::restart_iter(\n    SpanRef<const PauliStringRef<W>> commutators, SpanRef<const PauliStringRef<W>> anticommutators) {\n    restart_iter_same_constraints();\n    cur_desired_commutators = commutators;\n    cur_desired_anticommutators = anticommutators;\n}\n\ntemplate <size_t W>\nconst PauliString<W> *CommutingPauliStringIterator<W>::iter_next() {\n    if (next_output_index >= filled_output) {\n        load_more();\n    }\n    if (next_output_index >= filled_output) {\n        return nullptr;\n    }\n    return &output_buf[next_output_index++];\n}\n\ntemplate <size_t W>\nvoid CommutingPauliStringIterator<W>::load_more() {\n    next_output_index = 0;\n    filled_output = 0;\n\n    uint64_t start_pass_mask = -1;\n    if (num_qubits < 2) {\n        // Drop bits corresponding to cases where x2 or z2 or x1 or z1 are set.\n        start_pass_mask &= 0x0000000000000303UL;\n    } else if (num_qubits < 3) {\n        // Drop bits corresponding to cases where x2 or z2 are set.\n        start_pass_mask &= 0x000000000F0F0F0FUL;\n    }\n\n    uint64_t num_bit_strings = 1 << num_qubits;\n    while (filled_output == 0 && current.zs.u64[0] < num_bit_strings) {\n        uint64_t pass_mask = start_pass_mask;\n        if (current.xs.u64[0] == 0 && current.zs.u64[0] == 0) {\n            pass_mask &= ~1;  // Don't search the identity.\n        }\n        for (const auto &p : cur_desired_commutators) {\n            pass_mask &= ~mass_anticommute_check(p);\n        }\n        for (const auto &p : cur_desired_anticommutators) {\n            pass_mask &= mass_anticommute_check(p);\n        }\n        if (pass_mask) {\n            for (size_t b = 0; b < 64; b++) {\n                if ((pass_mask >> b) & 1) {\n                    output_buf[filled_output] = current;\n                    output_buf[filled_output].xs.u64[0] |= b & 7;\n                    output_buf[filled_output].zs.u64[0] |= (b >> 3) & 7;\n                    filled_output++;\n                }\n            }\n        }\n\n        current.xs.u64[0] += 8;\n        if (current.xs.u64[0] >= num_bit_strings) {\n            current.xs.u64[0] = 0;\n            current.zs.u64[0] += 8;\n        }\n    }\n}\n\ntemplate <size_t W>\nTableauIterator<W>::TableauIterator(size_t num_qubits, bool also_iter_signs)\n    : also_iter_signs(also_iter_signs), result(num_qubits), cur_k(0) {\n    for (size_t k = 0; k < num_qubits; k++) {\n        // Iterator for X_k's output.\n        pauli_string_iterators.push_back(CommutingPauliStringIterator<W>(num_qubits));\n        tableau_column_refs.push_back(result.xs[k]);\n\n        // Iterator for Z_k's output.\n        pauli_string_iterators.push_back(CommutingPauliStringIterator<W>(num_qubits));\n        tableau_column_refs.push_back(result.zs[k]);\n    }\n\n    for (size_t k = 0; k < 2 * num_qubits; k++) {\n        auto constraints = constraints_for_pauli_iterator(k);\n        pauli_string_iterators[k].cur_desired_commutators = constraints.first;\n        pauli_string_iterators[k].cur_desired_anticommutators = constraints.second;\n    }\n}\n\ntemplate <size_t W>\nTableauIterator<W>::TableauIterator(const TableauIterator<W> &other) : result(0) {\n    *this = other;\n}\n\ntemplate <size_t W>\nTableauIterator<W> &TableauIterator<W>::operator=(const TableauIterator<W> &other) {\n    also_iter_signs = other.also_iter_signs;\n    result = other.result;\n    cur_k = other.cur_k;\n    pauli_string_iterators = other.pauli_string_iterators;\n\n    tableau_column_refs.clear();\n    for (size_t k = 0; k < result.num_qubits; k++) {\n        tableau_column_refs.push_back(result.xs[k]);\n        tableau_column_refs.push_back(result.zs[k]);\n    }\n\n    for (size_t k = 0; k < 2 * result.num_qubits; k++) {\n        auto constraints = constraints_for_pauli_iterator(k);\n        pauli_string_iterators[k].cur_desired_commutators = constraints.first;\n        pauli_string_iterators[k].cur_desired_anticommutators = constraints.second;\n    }\n\n    return *this;\n}\n\ntemplate <size_t W>\nstd::pair<SpanRef<const PauliStringRef<W>>, SpanRef<const PauliStringRef<W>>>\nTableauIterator<W>::constraints_for_pauli_iterator(size_t k) const {\n    const PauliStringRef<W> *tab_obs_start = &tableau_column_refs[0];\n    SpanRef<const PauliStringRef<W>> commute_rng = {tab_obs_start, tab_obs_start + k};\n    SpanRef<const PauliStringRef<W>> anticommute_rng;\n    if (k & 1) {\n        anticommute_rng.ptr_end = commute_rng.ptr_end;\n        commute_rng.ptr_end--;\n        anticommute_rng.ptr_start = commute_rng.ptr_end;\n    }\n    return {commute_rng, anticommute_rng};\n}\n\ntemplate <size_t W>\nbool TableauIterator<W>::iter_next() {\n    if (result.num_qubits == 0) {\n        if (cur_k == 0) {\n            cur_k = 1;\n            return true;\n        }\n        return false;\n    }\n\n    if (result.xs.signs.u64[0] > 0) {\n        result.xs.signs.u64[0]--;\n        return true;\n    }\n    if (result.zs.signs.u64[0] > 0) {\n        result.zs.signs.u64[0]--;\n        result.xs.signs.u64[0] = (uint64_t{1} << result.num_qubits) - uint64_t{1};\n        return true;\n    }\n\n    while (cur_k != SIZE_MAX) {\n        const PauliString<W> *out = pauli_string_iterators[cur_k].iter_next();\n        if (out == nullptr) {\n            // Exhausted all Paulis strings at this level; go back a level.\n            cur_k--;  // At 0 this underflows to SIZE_MAX, exiting the loop.\n            continue;\n        }\n\n        tableau_column_refs[cur_k] = *out;\n        cur_k++;\n        if (cur_k == 2 * result.num_qubits) {\n            cur_k--;\n            if (also_iter_signs) {\n                // Okay, look, I admit this is technically wrong. It fails if num_qubits > 64 because\n                // not all sign variations are explored. But no one is actually going to be able to finish\n                // iterating the tableaus that are actually yielded, so good look demonstrating it's wrong.\n                // :P\n                result.xs.signs.u64[0] = (uint64_t{1} << result.num_qubits) - uint64_t{1};\n                result.zs.signs.u64[0] = (uint64_t{1} << result.num_qubits) - uint64_t{1};\n            }\n            return true;\n        }\n\n        pauli_string_iterators[cur_k].restart_iter_same_constraints();\n    }\n\n    return false;\n}\n\ntemplate <size_t W>\nvoid TableauIterator<W>::restart() {\n    cur_k = 0;\n    pauli_string_iterators[0].restart_iter({}, {});\n    result.xs.signs.clear();\n    result.zs.signs.clear();\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_iter.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/tableau_iter.h\"\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(tableau_iter_unsigned_3q) {\n    size_t c = 0;\n    benchmark_go([&]() {\n        TableauIterator<MAX_BITWORD_WIDTH> iter(3, false);\n        while (iter.iter_next()) {\n            c += iter.result.num_qubits;\n        }\n    })\n        .goal_millis(200)\n        .show_rate(\"Tableaus\", 1451520);\n    if (c == 0) {\n        std::cerr << \"use the output\\n\";\n    }\n}\n\nBENCHMARK(tableau_iter_all_3q) {\n    size_t c = 0;\n    benchmark_go([&]() {\n        TableauIterator<MAX_BITWORD_WIDTH> iter(3, true);\n        while (iter.iter_next()) {\n            c += iter.result.num_qubits;\n        }\n    })\n        .goal_millis(420)\n        .show_rate(\"Tableaus\", 92897280);\n    if (c == 0) {\n        std::cerr << \"use the output\\n\";\n    }\n}\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_iter.pybind.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/tableau_iter.pybind.h\"\n\n#include \"stim/py/base.pybind.h\"\n\nusing namespace stim;\nusing namespace stim_pybind;\n\npybind11::class_<TableauIterator<MAX_BITWORD_WIDTH>> stim_pybind::pybind_tableau_iter(pybind11::module &m) {\n    auto c = pybind11::class_<TableauIterator<MAX_BITWORD_WIDTH>>(\n        m,\n        \"TableauIterator\",\n        clean_doc_string(R\"DOC(\n            Iterates over all stabilizer tableaus of a specified size.\n\n            Examples:\n                >>> import stim\n                >>> tableau_iterator = stim.Tableau.iter_all(1)\n                >>> n = 0\n                >>> for single_qubit_clifford in tableau_iterator:\n                ...     n += 1\n                >>> n\n                24\n        )DOC\")\n            .data());\n    return c;\n}\n\nvoid stim_pybind::pybind_tableau_iter_methods(\n    pybind11::module &m, pybind11::class_<TableauIterator<MAX_BITWORD_WIDTH>> &c) {\n    c.def(\n        \"__iter__\",\n        [](TableauIterator<MAX_BITWORD_WIDTH> &self) -> TableauIterator<MAX_BITWORD_WIDTH> {\n            TableauIterator<MAX_BITWORD_WIDTH> copy = self;\n            return copy;\n        },\n        clean_doc_string(R\"DOC(\n            Returns an independent copy of the tableau iterator.\n\n            Since for-loops and loop-comprehensions call `iter` on things they\n            iterate, this effectively allows the iterator to be iterated\n            multiple times.\n        )DOC\")\n            .data());\n\n    c.def(\n        \"__next__\",\n        [](TableauIterator<MAX_BITWORD_WIDTH> &self) -> Tableau<MAX_BITWORD_WIDTH> {\n            if (!self.iter_next()) {\n                throw pybind11::stop_iteration();\n            }\n            return self.result;\n        },\n        clean_doc_string(R\"DOC(\n            Returns the next iterated tableau.\n        )DOC\")\n            .data());\n}\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_iter.pybind.h",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#ifndef _STIM_STABILIZERS_TABLEAU_ITER_PYBIND_H\n#define _STIM_STABILIZERS_TABLEAU_ITER_PYBIND_H\n\n#include <pybind11/pybind11.h>\n\n#include \"stim/stabilizers/tableau_iter.h\"\n\nnamespace stim_pybind {\npybind11::class_<stim::TableauIterator<stim::MAX_BITWORD_WIDTH>> pybind_tableau_iter(pybind11::module &m);\nvoid pybind_tableau_iter_methods(\n    pybind11::module &m, pybind11::class_<stim::TableauIterator<stim::MAX_BITWORD_WIDTH>> &c);\n}  // namespace stim_pybind\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_iter.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/stabilizers/tableau_iter.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(tableau_iter, CommutingPauliStringIterator_1, {\n    CommutingPauliStringIterator<W> iter(1);\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(iter.iter_next(), nullptr);\n\n    iter.restart_iter({}, {});\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(iter.iter_next(), nullptr);\n\n    auto ps = PauliString<W>::from_str(\"X\");\n    PauliStringRef<W> r = ps;\n\n    iter.restart_iter({&r}, {});\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+X\"));\n    ASSERT_EQ(iter.iter_next(), nullptr);\n\n    iter.restart_iter({}, {&r});\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+Z\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+Y\"));\n    ASSERT_EQ(iter.iter_next(), nullptr);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau_iter, CommutingPauliStringIterator_2, {\n    std::vector<PauliString<W>> coms;\n    std::vector<PauliStringRef<W>> refs;\n    coms.push_back(PauliString<W>::from_str(\"+Z_\"));\n    refs.push_back(coms[0]);\n\n    std::vector<PauliString<W>> anti_coms;\n    std::vector<PauliStringRef<W>> anti_refs;\n    anti_coms.push_back(PauliString<W>::from_str(\"+XX\"));\n    anti_refs.push_back(anti_coms[0]);\n\n    CommutingPauliStringIterator<W> iter(2);\n    iter.restart_iter(refs, anti_refs);\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+Z_\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+ZX\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+_Z\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+_Y\"));\n    ASSERT_EQ(iter.iter_next(), nullptr);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau_iter, CommutingPauliStringIterator_4, {\n    CommutingPauliStringIterator<W> iter(4);\n\n    iter.restart_iter({}, {});\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+X___\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+_X__\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+XX__\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+__X_\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+X_X_\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+_XX_\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+XXX_\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+Z___\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+Y___\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+ZX__\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+YX__\"));\n\n    std::vector<PauliString<W>> coms;\n    std::vector<PauliStringRef<W>> refs;\n    coms.push_back(PauliString<W>::from_str(\"+Z___\"));\n    coms.push_back(PauliString<W>::from_str(\"+_Z__\"));\n    coms.push_back(PauliString<W>::from_str(\"+___Z\"));\n    refs.push_back(coms[0]);\n    refs.push_back(coms[1]);\n    refs.push_back(coms[2]);\n\n    std::vector<PauliString<W>> anti_coms;\n    std::vector<PauliStringRef<W>> anti_refs;\n    anti_coms.push_back(PauliString<W>::from_str(\"+X___\"));\n    anti_coms.push_back(PauliString<W>::from_str(\"+_X__\"));\n    anti_coms.push_back(PauliString<W>::from_str(\"+___X\"));\n    anti_refs.push_back(anti_coms[0]);\n    anti_refs.push_back(anti_coms[1]);\n    anti_refs.push_back(anti_coms[2]);\n\n    iter.restart_iter(refs, anti_refs);\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+ZZ_Z\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+ZZXZ\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+ZZZZ\"));\n    ASSERT_EQ(*iter.iter_next(), PauliString<W>::from_str(\"+ZZYZ\"));\n    ASSERT_EQ(iter.iter_next(), nullptr);\n\n    iter.restart_iter(&refs[0], &refs[0]);\n    ASSERT_EQ(iter.iter_next(), nullptr);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau_iter, iter_tableau, {\n    TableauIterator<W> iter1(1, false);\n    TableauIterator<W> iter1_signs(1, true);\n    TableauIterator<W> iter2(2, false);\n    TableauIterator<W> iter3(3, false);\n    int n1 = 0;\n    while (iter1.iter_next()) {\n        n1++;\n    }\n    ASSERT_EQ(n1, 6);\n\n    int s1 = 0;\n    while (iter1_signs.iter_next()) {\n        s1++;\n    }\n    ASSERT_EQ(s1, 24);\n\n    int n2 = 0;\n    while (iter2.iter_next()) {\n        n2++;\n    }\n    ASSERT_EQ(n2, 720);\n\n    // Note: disabled because it takes 2-3 seconds.\n    // int n3 = 0;\n    // while (iter3.iter_next()) {\n    //     n3++;\n    // }\n    // ASSERT_EQ(n3, 1451520);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau_iter, iter_tableau_distinct, {\n    std::set<std::string> seen;\n    TableauIterator<W> iter2_signs(2, true);\n    while (iter2_signs.iter_next()) {\n        seen.insert(iter2_signs.result.str());\n    }\n    ASSERT_EQ(seen.size(), 11520);\n})\n\nTEST_EACH_WORD_SIZE_W(tableau_iter, iter_tableau_copy, {\n    TableauIterator<W> iter2(2, true);\n    {\n        TableauIterator<W> iter1(3, false);\n        iter2 = iter1;\n    }\n    ASSERT_TRUE(iter2.iter_next());\n\n    {\n        TableauIterator<W> iter1(3, false);\n        for (size_t k = 0; k < 100; k++) {\n            iter2 = iter1;\n            ASSERT_EQ(iter1.iter_next(), iter2.iter_next());\n            ASSERT_EQ(iter2.result, iter1.result);\n        }\n        for (size_t k = 0; k < 1000; k++) {\n            ASSERT_EQ(iter1.iter_next(), iter2.iter_next());\n            ASSERT_EQ(iter2.result, iter1.result);\n        }\n    }\n})\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_pybind_test.py",
    "content": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport random\nimport re\n\nimport numpy as np\nimport stim\nimport pytest\n\n\ndef test_init_equality():\n    assert stim.Tableau(3) != None\n    assert stim.Tableau(3) != object()\n    assert stim.Tableau(3) != \"another type\"\n    assert not (stim.Tableau(3) == None)\n    assert not (stim.Tableau(3) == object())\n    assert not (stim.Tableau(3) == \"another type\")\n\n    assert stim.Tableau(3) == stim.Tableau(3)\n    assert not (stim.Tableau(3) != stim.Tableau(3))\n    assert stim.Tableau(3) != stim.Tableau(4)\n    assert not (stim.Tableau(3) == stim.Tableau(4))\n\n    assert stim.Tableau.from_named_gate(\"S\") == stim.Tableau.from_named_gate(\"S\")\n    assert stim.Tableau.from_named_gate(\"S\") != stim.Tableau.from_named_gate(\"S_DAG\")\n    assert stim.Tableau.from_named_gate(\"S\") != stim.Tableau.from_named_gate(\"H\")\n    assert stim.Tableau.from_named_gate(\"S_DAG\") == stim.Tableau.from_named_gate(\"S_DAG\")\n\n\ndef test_from_named_gate():\n    assert str(stim.Tableau.from_named_gate(\"H\")).strip() == \"\"\"\n+-xz-\n| ++\n| ZX\n\"\"\".strip()\n    assert str(stim.Tableau.from_named_gate(\"I\")).strip() == \"\"\"\n+-xz-\n| ++\n| XZ\n\"\"\".strip()\n\n    assert stim.Tableau.from_named_gate(\"H_XZ\") == stim.Tableau.from_named_gate(\"h\")\n\n    with pytest.raises(IndexError, match=\"not found\"):\n        stim.Tableau.from_named_gate(\"not a gate\")\n    with pytest.raises(IndexError, match=\"not unitary\"):\n        stim.Tableau.from_named_gate(\"X_ERROR\")\n\n\ndef test_from_state_vector_fuzz():\n    for n in range(1, 7):\n        t = stim.Tableau.random(n)\n        v = t.to_state_vector() * (random.random() + 1j*random.random())\n        t2 = stim.Tableau.from_state_vector(v, endian='little')\n        np.testing.assert_array_equal(t.to_stabilizers(canonicalize=True), t2.to_stabilizers(canonicalize=True))\n\n\ndef test_identity():\n    t = stim.Tableau(3)\n    assert len(t) == 3\n    assert t.x_output(0) == stim.PauliString(\"X__\")\n    assert t.x_output(1) == stim.PauliString(\"_X_\")\n    assert t.x_output(2) == stim.PauliString(\"__X\")\n    assert t.z_output(0) == stim.PauliString(\"Z__\")\n    assert t.z_output(1) == stim.PauliString(\"_Z_\")\n    assert t.z_output(2) == stim.PauliString(\"__Z\")\n    assert t.y_output(0) == stim.PauliString(\"Y__\")\n    assert t.y_output(1) == stim.PauliString(\"_Y_\")\n    assert t.y_output(2) == stim.PauliString(\"__Y\")\n\n\ndef test_pauli_output():\n    h = stim.Tableau.from_named_gate(\"H\")\n    assert h.x_output(0) == stim.PauliString(\"Z\")\n    assert h.y_output(0) == stim.PauliString(\"-Y\")\n    assert h.z_output(0) == stim.PauliString(\"X\")\n\n    s = stim.Tableau.from_named_gate(\"S\")\n    assert s.x_output(0) == stim.PauliString(\"Y\")\n    assert s.y_output(0) == stim.PauliString(\"-X\")\n    assert s.z_output(0) == stim.PauliString(\"Z\")\n\n    s_dag = stim.Tableau.from_named_gate(\"S_DAG\")\n    assert s_dag.x_output(0) == stim.PauliString(\"-Y\")\n    assert s_dag.y_output(0) == stim.PauliString(\"X\")\n    assert s_dag.z_output(0) == stim.PauliString(\"Z\")\n\n    cz = stim.Tableau.from_named_gate(\"CZ\")\n    assert cz.x_output(0) == stim.PauliString(\"XZ\")\n    assert cz.y_output(0) == stim.PauliString(\"YZ\")\n    assert cz.z_output(0) == stim.PauliString(\"Z_\")\n    assert cz.x_output(1) == stim.PauliString(\"ZX\")\n    assert cz.y_output(1) == stim.PauliString(\"ZY\")\n    assert cz.z_output(1) == stim.PauliString(\"_Z\")\n\n\ndef test_random():\n    t = stim.Tableau.random(10)\n    assert len(t) == 10\n    assert t != stim.Tableau.random(10)\n\n\ndef test_str():\n    assert str(stim.Tableau.from_named_gate(\"cnot\")).strip() == \"\"\"\n+-xz-xz-\n| ++ ++\n| XZ _Z\n| X_ XZ\n\"\"\".strip()\n\n\ndef test_append():\n    t = stim.Tableau(2)\n    with pytest.raises(ValueError, match=re.escape(\"len(targets) != len(gate)\")):\n        t.append(stim.Tableau.from_named_gate(\"CY\"), [0])\n    with pytest.raises(ValueError, match=\"collision\"):\n        t.append(stim.Tableau.from_named_gate(\"CY\"), [0, 0])\n    with pytest.raises(ValueError, match=re.escape(\"target >= len(tableau)\")):\n        t.append(stim.Tableau.from_named_gate(\"CY\"), [1, 2])\n\n    t.append(stim.Tableau.from_named_gate(\"SQRT_X_DAG\"), [1])\n    t.append(stim.Tableau.from_named_gate(\"CY\"), [0, 1])\n    t.append(stim.Tableau.from_named_gate(\"SQRT_X\"), [1])\n    assert t == stim.Tableau.from_named_gate(\"CZ\")\n\n    t = stim.Tableau(2)\n    t.append(stim.Tableau.from_named_gate(\"SQRT_X\"), [1])\n    t.append(stim.Tableau.from_named_gate(\"CY\"), [0, 1])\n    t.append(stim.Tableau.from_named_gate(\"SQRT_X_DAG\"), [1])\n    assert t != stim.Tableau.from_named_gate(\"CZ\")\n\n\ndef test_prepend():\n    t = stim.Tableau(2)\n    with pytest.raises(ValueError, match=re.escape(\"len(targets) != len(gate)\")):\n        t.prepend(stim.Tableau.from_named_gate(\"CY\"), [0])\n    with pytest.raises(ValueError, match=\"collision\"):\n        t.prepend(stim.Tableau.from_named_gate(\"CY\"), [0, 0])\n    with pytest.raises(ValueError, match=re.escape(\"target >= len(tableau)\")):\n        t.prepend(stim.Tableau.from_named_gate(\"CY\"), [1, 2])\n\n    t.prepend(stim.Tableau.from_named_gate(\"SQRT_X_DAG\"), [1])\n    t.prepend(stim.Tableau.from_named_gate(\"CY\"), [0, 1])\n    t.prepend(stim.Tableau.from_named_gate(\"SQRT_X\"), [1])\n    assert t != stim.Tableau.from_named_gate(\"CZ\")\n\n    t = stim.Tableau(2)\n    t.prepend(stim.Tableau.from_named_gate(\"SQRT_X\"), [1])\n    t.prepend(stim.Tableau.from_named_gate(\"CY\"), [0, 1])\n    t.prepend(stim.Tableau.from_named_gate(\"SQRT_X_DAG\"), [1])\n    assert t == stim.Tableau.from_named_gate(\"CZ\")\n\n\ndef test_from_conjugated_generators():\n    assert stim.Tableau(3) == stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"X__\"),\n            stim.PauliString(\"_X_\"),\n            stim.PauliString(\"__X\"),\n        ],\n        zs=[\n            stim.PauliString(\"Z__\"),\n            stim.PauliString(\"_Z_\"),\n            stim.PauliString(\"__Z\"),\n        ],\n    )\n\n    assert stim.Tableau.from_named_gate(\"S\") == stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"Y\"),\n        ],\n        zs=[\n            stim.PauliString(\"Z\"),\n        ],\n    )\n\n    assert stim.Tableau.from_named_gate(\"S_DAG\") == stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"-Y\"),\n        ],\n        zs=[\n            stim.PauliString(\"Z\"),\n        ],\n    )\n\n    assert stim.Tableau(2) == stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"X_\"),\n            stim.PauliString(\"_X\"),\n        ],\n        zs=[\n            stim.PauliString(\"Z_\"),\n            stim.PauliString(\"_Z\"),\n        ],\n    )\n\n    with pytest.raises(ValueError, match=re.escape(\"len(p) == len(zs)\")):\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"X_\"),\n                stim.PauliString(\"_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"Z_\"),\n                stim.PauliString(\"_Z_\"),\n            ],\n        )\n\n    with pytest.raises(ValueError, match=\"imag\"):\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"iX_\"),\n                stim.PauliString(\"_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"Z_\"),\n                stim.PauliString(\"_Z\"),\n            ],\n        )\n    with pytest.raises(ValueError, match=\"imag\"):\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"X_\"),\n                stim.PauliString(\"_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"Z_\"),\n                stim.PauliString(\"i_Z\"),\n            ],\n        )\n\n    with pytest.raises(ValueError, match=re.escape(\"len(p) == len(xs)\")):\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"X_\"),\n                stim.PauliString(\"_X_\"),\n            ],\n            zs=[\n                stim.PauliString(\"Z_\"),\n                stim.PauliString(\"_Z\"),\n            ],\n        )\n\n    with pytest.raises(ValueError, match=re.escape(\"len(xs) != len(zs)\")):\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"X_\"),\n            ],\n            zs=[\n                stim.PauliString(\"Z_\"),\n                stim.PauliString(\"_Z\"),\n            ],\n        )\n\n    with pytest.raises(ValueError, match=re.escape(\"len(xs) != len(zs)\")):\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"X_\"),\n                stim.PauliString(\"_X\"),\n            ],\n            zs=[\n                stim.PauliString(\"Z_\"),\n            ],\n        )\n\n    with pytest.raises(ValueError, match=\"commutativity\"):\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"X_\"),\n                stim.PauliString(\"_Z\"),\n            ],\n            zs=[\n                stim.PauliString(\"Z_\"),\n                stim.PauliString(\"_Z\"),\n            ],\n        )\n\n    with pytest.raises(ValueError, match=\"commutativity\"):\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"X_\"),\n                stim.PauliString(\"Z_\"),\n            ],\n            zs=[\n                stim.PauliString(\"Z_\"),\n                stim.PauliString(\"X_\"),\n            ],\n        )\n\n    with pytest.raises(ValueError, match=\"commutativity\"):\n        stim.Tableau.from_conjugated_generators(\n            xs=[\n                stim.PauliString(\"X_\"),\n                stim.PauliString(\"X_\"),\n            ],\n            zs=[\n                stim.PauliString(\"Z_\"),\n                stim.PauliString(\"Z_\"),\n            ],\n        )\n\n\ndef test_repr():\n    v = stim.Tableau.from_named_gate(\"H\")\n    r = repr(v)\n    assert r == \"\"\"stim.Tableau.from_conjugated_generators(\n    xs=[\n        stim.PauliString(\"+Z\"),\n    ],\n    zs=[\n        stim.PauliString(\"+X\"),\n    ],\n)\"\"\"\n    assert eval(r, {\"stim\": stim}) == v\n\n\ndef test_call():\n    t = stim.Tableau.from_named_gate(\"CNOT\")\n    assert t(stim.PauliString(\"__\")) == stim.PauliString(\"__\")\n    assert t(stim.PauliString(\"-__\")) == stim.PauliString(\"-__\")\n    assert t(stim.PauliString(\"i__\")) == stim.PauliString(\"i__\")\n    assert t(stim.PauliString(\"-i__\")) == stim.PauliString(\"-i__\")\n    assert t(stim.PauliString(\"X_\")) == stim.PauliString(\"XX\")\n    assert t(stim.PauliString(\"Y_\")) == stim.PauliString(\"YX\")\n    assert t(stim.PauliString(\"Z_\")) == stim.PauliString(\"Z_\")\n    assert t(stim.PauliString(\"_X\")) == stim.PauliString(\"_X\")\n    assert t(stim.PauliString(\"_Y\")) == stim.PauliString(\"ZY\")\n    assert t(stim.PauliString(\"_Z\")) == stim.PauliString(\"ZZ\")\n    assert t(stim.PauliString(\"YY\")) == stim.PauliString(\"-XZ\")\n    assert t(stim.PauliString(\"-YY\")) == stim.PauliString(\"XZ\")\n\n\ndef test_pow():\n    s = stim.Tableau.from_named_gate(\"S\")\n    s_dag = stim.Tableau.from_named_gate(\"S_DAG\")\n    z = stim.Tableau.from_named_gate(\"Z\")\n    assert stim.Tableau(1) == s**0 == s**4 == s**-4\n    assert s == s**1 == s**5 == s**-3 == s**(40000 + 1) == s**(-40000 + 1)\n    assert s_dag == s**-1 == s**3 == s**7 == s**(40000 + 3) == s**(-40000 + 3)\n    assert z == s**2 == s**6 == s**-2 == s**(40000 + 2) == s**(-40000 + 2)\n\n\ndef test_aliasing():\n    t = stim.Tableau.random(4)\n    t2 = t**1\n    t.append(t2, range(4))\n    t2.append(t2, range(4))\n    assert t == t2\n\n    t = stim.Tableau.random(4)\n    t2 = t**1\n    t.prepend(t2, range(4))\n    t2.prepend(t2, range(4))\n    assert t == t2\n\n\ndef test_composition():\n    assert stim.Tableau(0) * stim.Tableau(0) == stim.Tableau(0)\n    assert stim.Tableau(0).then(stim.Tableau(0)) == stim.Tableau(0)\n    assert stim.Tableau(1) * stim.Tableau(1) == stim.Tableau(1)\n    assert stim.Tableau(1).then(stim.Tableau(1)) == stim.Tableau(1)\n\n    t = stim.Tableau.random(4)\n    t2 = stim.Tableau.random(4)\n    t3 = t.then(t2)\n    assert t3 == t2 * t\n    p = stim.PauliString.random(4)\n    assert t2(t(p)) == t3(p)\n\n    with pytest.raises(ValueError, match=\"!= len\"):\n        _ = stim.Tableau(3) * stim.Tableau(4)\n    with pytest.raises(ValueError, match=\"!= len\"):\n        _ = stim.Tableau(3).then(stim.Tableau(4))\n\n\ndef test_copy():\n    t = stim.Tableau(3)\n    t2 = t.copy()\n    assert t == t2\n    assert t is not t2\n\n\ndef test_hash():\n    # stim.Tableau is mutable. It must not also be value-hashable.\n    # Defining __hash__ requires defining a FrozenTableau variant instead.\n    with pytest.raises(TypeError, match=\"unhashable\"):\n        _ = hash(stim.Tableau(1))\n\n\ndef test_add():\n    h = stim.Tableau.from_named_gate(\"H\")\n    swap = stim.Tableau.from_named_gate(\"SWAP\")\n    cnot = stim.Tableau.from_named_gate(\"CNOT\")\n    combo = h + swap + cnot\n    assert str(combo).strip() == \"\"\"\n+-xz-xz-xz-xz-xz-\n| ++ ++ ++ ++ ++\n| ZX __ __ __ __\n| __ __ XZ __ __\n| __ XZ __ __ __\n| __ __ __ XZ _Z\n| __ __ __ X_ XZ\n    \"\"\".strip()\n\n    alias = h\n    h += swap\n    h += cnot\n    assert h == combo\n    h += stim.Tableau(0)\n    assert h == combo\n    assert h is alias\n    assert h is not combo\n    assert swap == stim.Tableau.from_named_gate(\"SWAP\")\n\n    assert stim.Tableau(0) + stim.Tableau(0) == stim.Tableau(0)\n    assert stim.Tableau(1) + stim.Tableau(2) == stim.Tableau(3)\n    assert stim.Tableau(100) + stim.Tableau(500) == stim.Tableau(600)\n    assert stim.Tableau(0) + cnot + stim.Tableau(0) == cnot\n\n    x = stim.Tableau.from_named_gate(\"X\")\n    y = stim.Tableau.from_named_gate(\"Y\")\n    z = stim.Tableau.from_named_gate(\"Z\")\n    assert str(y + y).strip() == \"\"\"\n+-xz-xz-\n| -- --\n| XZ __\n| __ XZ\n    \"\"\".strip()\n    assert str(x + x).strip() == \"\"\"\n+-xz-xz-\n| +- +-\n| XZ __\n| __ XZ\n    \"\"\".strip()\n    assert str(z + z).strip() == \"\"\"\n+-xz-xz-\n| -+ -+\n| XZ __\n| __ XZ\n    \"\"\".strip()\n    assert str(x + z).strip() == \"\"\"\n+-xz-xz-\n| +- -+\n| XZ __\n| __ XZ\n    \"\"\".strip()\n    assert str(z + x).strip() == \"\"\"\n+-xz-xz-\n| -+ +-\n| XZ __\n| __ XZ\n    \"\"\".strip()\n\n\ndef test_xyz_output_pauli():\n    t = stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"-__Z\"),\n            stim.PauliString(\"+XZ_\"),\n            stim.PauliString(\"+_ZZ\"),\n        ],\n        zs=[\n            stim.PauliString(\"-YYY\"),\n            stim.PauliString(\"+Z_Z\"),\n            stim.PauliString(\"-ZYZ\"),\n        ],\n    )\n\n    assert t.x_output_pauli(0, 0) == 0\n    assert t.x_output_pauli(0, 1) == 0\n    assert t.x_output_pauli(0, 2) == 3\n    assert t.x_output_pauli(1, 0) == 1\n    assert t.x_output_pauli(1, 1) == 3\n    assert t.x_output_pauli(1, 2) == 0\n    assert t.x_output_pauli(2, 0) == 0\n    assert t.x_output_pauli(2, 1) == 3\n    assert t.x_output_pauli(2, 2) == 3\n\n    assert t.y_output_pauli(0, 0) == 2\n    assert t.y_output_pauli(0, 1) == 2\n    assert t.y_output_pauli(0, 2) == 1\n    assert t.y_output_pauli(1, 0) == 2\n    assert t.y_output_pauli(1, 1) == 3\n    assert t.y_output_pauli(1, 2) == 3\n    assert t.y_output_pauli(2, 0) == 3\n    assert t.y_output_pauli(2, 1) == 1\n    assert t.y_output_pauli(2, 2) == 0\n\n    assert t.z_output_pauli(0, 0) == 2\n    assert t.z_output_pauli(0, 1) == 2\n    assert t.z_output_pauli(0, 2) == 2\n    assert t.z_output_pauli(1, 0) == 3\n    assert t.z_output_pauli(1, 1) == 0\n    assert t.z_output_pauli(1, 2) == 3\n    assert t.z_output_pauli(2, 0) == 3\n    assert t.z_output_pauli(2, 1) == 2\n    assert t.z_output_pauli(2, 2) == 3\n\n    with pytest.raises(TypeError):\n        t.x_output_pauli(-1, 0)\n    with pytest.raises(ValueError):\n        t.x_output_pauli(3, 0)\n    with pytest.raises(TypeError):\n        t.x_output_pauli(0, -1)\n    with pytest.raises(ValueError):\n        t.x_output_pauli(0, 3)\n\n    with pytest.raises(TypeError):\n        t.y_output_pauli(-1, 0)\n    with pytest.raises(ValueError):\n        t.y_output_pauli(3, 0)\n    with pytest.raises(TypeError):\n        t.y_output_pauli(0, -1)\n    with pytest.raises(ValueError):\n        t.y_output_pauli(0, 3)\n\n    with pytest.raises(TypeError):\n        t.z_output_pauli(-1, 0)\n    with pytest.raises(ValueError):\n        t.z_output_pauli(3, 0)\n    with pytest.raises(TypeError):\n        t.z_output_pauli(0, -1)\n    with pytest.raises(ValueError):\n        t.z_output_pauli(0, 3)\n\n\ndef test_inverse_xyz_output_pauli():\n    t = stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"-__Z\"),\n            stim.PauliString(\"+XZ_\"),\n            stim.PauliString(\"+_ZZ\"),\n        ],\n        zs=[\n            stim.PauliString(\"-YYY\"),\n            stim.PauliString(\"+Z_Z\"),\n            stim.PauliString(\"-ZYZ\"),\n        ],\n    ).inverse()\n\n    assert t.inverse_x_output_pauli(0, 0) == 0\n    assert t.inverse_x_output_pauli(0, 1) == 0\n    assert t.inverse_x_output_pauli(0, 2) == 3\n    assert t.inverse_x_output_pauli(1, 0) == 1\n    assert t.inverse_x_output_pauli(1, 1) == 3\n    assert t.inverse_x_output_pauli(1, 2) == 0\n    assert t.inverse_x_output_pauli(2, 0) == 0\n    assert t.inverse_x_output_pauli(2, 1) == 3\n    assert t.inverse_x_output_pauli(2, 2) == 3\n\n    assert t.inverse_y_output_pauli(0, 0) == 2\n    assert t.inverse_y_output_pauli(0, 1) == 2\n    assert t.inverse_y_output_pauli(0, 2) == 1\n    assert t.inverse_y_output_pauli(1, 0) == 2\n    assert t.inverse_y_output_pauli(1, 1) == 3\n    assert t.inverse_y_output_pauli(1, 2) == 3\n    assert t.inverse_y_output_pauli(2, 0) == 3\n    assert t.inverse_y_output_pauli(2, 1) == 1\n    assert t.inverse_y_output_pauli(2, 2) == 0\n\n    assert t.inverse_z_output_pauli(0, 0) == 2\n    assert t.inverse_z_output_pauli(0, 1) == 2\n    assert t.inverse_z_output_pauli(0, 2) == 2\n    assert t.inverse_z_output_pauli(1, 0) == 3\n    assert t.inverse_z_output_pauli(1, 1) == 0\n    assert t.inverse_z_output_pauli(1, 2) == 3\n    assert t.inverse_z_output_pauli(2, 0) == 3\n    assert t.inverse_z_output_pauli(2, 1) == 2\n    assert t.inverse_z_output_pauli(2, 2) == 3\n\n    with pytest.raises(TypeError):\n        t.inverse_x_output_pauli(-1, 0)\n    with pytest.raises(ValueError):\n        t.inverse_x_output_pauli(3, 0)\n    with pytest.raises(TypeError):\n        t.inverse_x_output_pauli(0, -1)\n    with pytest.raises(ValueError):\n        t.inverse_x_output_pauli(0, 3)\n\n    with pytest.raises(TypeError):\n        t.inverse_y_output_pauli(-1, 0)\n    with pytest.raises(ValueError):\n        t.inverse_y_output_pauli(3, 0)\n    with pytest.raises(TypeError):\n        t.inverse_y_output_pauli(0, -1)\n    with pytest.raises(ValueError):\n        t.inverse_y_output_pauli(0, 3)\n\n    with pytest.raises(TypeError):\n        t.inverse_z_output_pauli(-1, 0)\n    with pytest.raises(ValueError):\n        t.inverse_z_output_pauli(3, 0)\n    with pytest.raises(TypeError):\n        t.inverse_z_output_pauli(0, -1)\n    with pytest.raises(ValueError):\n        t.inverse_z_output_pauli(0, 3)\n\n\ndef test_inverse_xyz_output():\n    t = stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"-__Z\"),\n            stim.PauliString(\"+XZ_\"),\n            stim.PauliString(\"+_ZZ\"),\n        ],\n        zs=[\n            stim.PauliString(\"-YYY\"),\n            stim.PauliString(\"+Z_Z\"),\n            stim.PauliString(\"-ZYZ\"),\n        ],\n    )\n    t_inv = t.inverse()\n\n    for k in range(3):\n        assert t_inv.inverse_x_output(k) == t.x_output(k)\n        assert t_inv.inverse_y_output(k) == t.y_output(k)\n        assert t_inv.inverse_z_output(k) == t.z_output(k)\n        assert t_inv.inverse_x_output(k, unsigned=True) == t.x_output(k) / t.x_output(k).sign\n        assert t_inv.inverse_y_output(k, unsigned=True) == t.y_output(k) / t.y_output(k).sign\n        assert t_inv.inverse_z_output(k, unsigned=True) == t.z_output(k) / t.z_output(k).sign\n\n    with pytest.raises(TypeError):\n        t.inverse_x_output(-1)\n    with pytest.raises(ValueError):\n        t.inverse_x_output(3)\n\n    with pytest.raises(TypeError):\n        t.inverse_y_output(-1)\n    with pytest.raises(ValueError):\n        t.inverse_y_output(3)\n\n    with pytest.raises(TypeError):\n        t.inverse_z_output(-1)\n    with pytest.raises(ValueError):\n        t.inverse_z_output(3)\n\n\ndef test_inverse():\n    t = stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"+XXX\"),\n            stim.PauliString(\"-XZY\"),\n            stim.PauliString(\"+Z_Z\"),\n        ],\n        zs=[\n            stim.PauliString(\"-_XZ\"),\n            stim.PauliString(\"-_X_\"),\n            stim.PauliString(\"-X__\"),\n        ],\n    )\n    assert t.inverse() == t.inverse(unsigned=False) == stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"-__Z\"),\n            stim.PauliString(\"-_Z_\"),\n            stim.PauliString(\"+XZZ\"),\n        ],\n        zs=[\n            stim.PauliString(\"+ZZX\"),\n            stim.PauliString(\"+YX_\"),\n            stim.PauliString(\"+ZZ_\"),\n        ],\n    )\n\n    assert t.inverse(unsigned=True) == stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"+__Z\"),\n            stim.PauliString(\"+_Z_\"),\n            stim.PauliString(\"+XZZ\"),\n        ],\n        zs=[\n            stim.PauliString(\"+ZZX\"),\n            stim.PauliString(\"+YX_\"),\n            stim.PauliString(\"+ZZ_\"),\n        ],\n    )\n\n\ndef test_pickle():\n    import pickle\n    t = stim.Tableau.random(4)\n    a = pickle.dumps(t)\n    assert pickle.loads(a) == t\n\n\ndef test_unitary():\n    swap = stim.Tableau.from_named_gate(\"SWAP\")\n    np.testing.assert_array_equal(swap.to_unitary_matrix(endian='big'), [\n        [1, 0, 0, 0],\n        [0, 0, 1, 0],\n        [0, 1, 0, 0],\n        [0, 0, 0, 1],\n    ])\n\n\ndef test_to_pauli_string():\n    assert stim.PauliString(0).to_tableau() == stim.Tableau(0)\n    p = stim.PauliString(\"+YX_Z\")\n    assert p.to_tableau().to_pauli_string() == p\n\n    cnot = stim.Tableau.from_named_gate(\"CNOT\")\n    with pytest.raises(ValueError, match=\"The Tableau isn't equivalent to a Pauli product.\"):\n        cnot.to_pauli_string()\n\n\ndef test_iter_0q():\n    assert list(stim.Tableau.iter_all(0, unsigned=True)) == [stim.Tableau(0)]\n    assert list(stim.Tableau.iter_all(0, unsigned=False)) == [stim.Tableau(0)]\n\n\ndef test_iter_1q():\n    r = stim.Tableau.iter_all(1, unsigned=True)\n    assert len(set(repr(e) for e in r)) == 6\n    assert len(set(repr(e) for e in r)) == 6  # Can re-iterate.\n    assert sum(1 for _ in stim.Tableau.iter_all(1)) == 24\n\n\ndef test_iter_2q():\n    u2 = stim.Tableau.iter_all(2, unsigned=True)\n    assert sum(1 for _ in u2) == 720\n    assert sum(1 for _ in stim.Tableau.iter_all(2, unsigned=False)) == 11520\n    assert len(set(repr(e) for e in u2)) == 720\n\n\ndef test_iter_3q():\n    n = 0\n    for _ in stim.Tableau.iter_all(3, unsigned=True):\n        n += 1\n    assert n == 1451520\n\n\ndef test_from_unitary_matrix():\n    s = 0.5**0.5\n    t = stim.Tableau.from_unitary_matrix([\n        [s, s],\n        [s, -s]\n    ], endian='little')\n    assert t == stim.Tableau.from_named_gate(\"H\")\n\n    with pytest.raises(ValueError, match=\"Clifford operation\"):\n        stim.Tableau.from_unitary_matrix([\n            [1, 0],\n            [0, 0],\n        ], endian='little')\n\n\ndef test_to_circuit_vs_from_circuit():\n    t = stim.Tableau.random(4)\n    assert t.to_circuit() is not None\n    c = t.to_circuit(method=\"elimination\")\n    sim = stim.TableauSimulator()\n    sim.do_circuit(c)\n    assert sim.current_inverse_tableau().inverse() == t\n    assert stim.Tableau.from_circuit(c) == t\n\n\ndef test_to_numpy():\n    t = stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"+_XXY\"),\n            stim.PauliString(\"+X_ZX\"),\n            stim.PauliString(\"+_X__\"),\n            stim.PauliString(\"-XXXY\"),\n        ],\n        zs=[\n            stim.PauliString(\"+Z_ZY\"),\n            stim.PauliString(\"+_X_Y\"),\n            stim.PauliString(\"-_ZXZ\"),\n            stim.PauliString(\"-Y_X_\"),\n        ],\n    )\n\n    x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy()\n    np.testing.assert_array_equal(x_signs, [0, 0, 0, 1])\n    np.testing.assert_array_equal(z_signs, [0, 0, 1, 1])\n    np.testing.assert_array_equal(x2x, [\n        [0, 1, 1, 1],\n        [1, 0, 0, 1],\n        [0, 1, 0, 0],\n        [1, 1, 1, 1],\n    ])\n    np.testing.assert_array_equal(x2z, [\n        [0, 0, 0, 1],\n        [0, 0, 1, 0],\n        [0, 0, 0, 0],\n        [0, 0, 0, 1],\n    ])\n    np.testing.assert_array_equal(z2x, [\n        [0, 0, 0, 1],\n        [0, 1, 0, 1],\n        [0, 0, 1, 0],\n        [1, 0, 1, 0],\n    ])\n    np.testing.assert_array_equal(z2z, [\n        [1, 0, 1, 1],\n        [0, 0, 0, 1],\n        [0, 1, 0, 1],\n        [1, 0, 0, 0],\n    ])\n\n    x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy(bit_packed=True)\n    np.testing.assert_array_equal(x_signs, [8])\n    np.testing.assert_array_equal(z_signs, [12])\n    np.testing.assert_array_equal(x2x, [\n        [14],\n        [9],\n        [2],\n        [15],\n    ])\n    np.testing.assert_array_equal(x2z, [\n        [8],\n        [4],\n        [0],\n        [8],\n    ])\n    np.testing.assert_array_equal(z2x, [\n        [8],\n        [10],\n        [4],\n        [5],\n    ])\n    np.testing.assert_array_equal(z2z, [\n        [13],\n        [8],\n        [10],\n        [1],\n    ])\n\n\ndef test_from_numpy():\n    expected = stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"+_XXY\"),\n            stim.PauliString(\"+X_ZX\"),\n            stim.PauliString(\"+_X__\"),\n            stim.PauliString(\"-XXXY\"),\n        ],\n        zs=[\n            stim.PauliString(\"+Z_ZY\"),\n            stim.PauliString(\"+_X_Y\"),\n            stim.PauliString(\"-_ZXZ\"),\n            stim.PauliString(\"-Y_X_\"),\n        ],\n    )\n\n    assert stim.Tableau.from_numpy(\n        x_signs=np.array([0, 0, 0, 1], dtype=np.bool_),\n        z_signs=np.array([0, 0, 1, 1], dtype=np.bool_),\n        x2x=np.array([\n            [0, 1, 1, 1],\n            [1, 0, 0, 1],\n            [0, 1, 0, 0],\n            [1, 1, 1, 1],\n        ], dtype=np.bool_),\n        x2z=np.array([\n            [0, 0, 0, 1],\n            [0, 0, 1, 0],\n            [0, 0, 0, 0],\n            [0, 0, 0, 1],\n        ], dtype=np.bool_),\n        z2x=np.array([\n            [0, 0, 0, 1],\n            [0, 1, 0, 1],\n            [0, 0, 1, 0],\n            [1, 0, 1, 0],\n        ], dtype=np.bool_),\n        z2z=np.array([\n            [1, 0, 1, 1],\n            [0, 0, 0, 1],\n            [0, 1, 0, 1],\n            [1, 0, 0, 0],\n        ], dtype=np.bool_),\n    ) == expected\n\n\n@pytest.mark.parametrize(\"n\", [0, 1, 15, 16, 17, 301])\ndef test_to_from_numpy_fuzz(n: int):\n    t = stim.Tableau.random(n)\n    x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy()\n    t1 = stim.Tableau.from_numpy(x2x=x2x, x2z=x2z, z2x=z2x, z2z=z2z, x_signs=x_signs, z_signs=z_signs)\n    assert t1 == t\n    x2x, x2z, z2x, z2z, x_signs, z_signs = t.to_numpy(bit_packed=True)\n    t2 = stim.Tableau.from_numpy(x2x=x2x, x2z=x2z, z2x=z2x, z2z=z2z, x_signs=x_signs, z_signs=z_signs)\n    assert t2 == t\n\n\ndef test_signs():\n    t = stim.Tableau.from_named_gate(\"S\")\n    assert t.x_sign(0) == +1\n    assert t.y_sign(0) == -1\n    assert t.z_sign(0) == +1\n    t = stim.Tableau.from_named_gate(\"S_DAG\")\n    assert t.x_sign(0) == -1\n    assert t.y_sign(0) == +1\n    assert t.z_sign(0) == +1\n    t = stim.Tableau.from_named_gate(\"SQRT_X\")\n    assert t.x_sign(0) == +1\n    assert t.y_sign(0) == +1\n    assert t.z_sign(0) == -1\n\n    t = stim.Tableau.from_conjugated_generators(\n        xs=[\n            stim.PauliString(\"-XX\"),\n            stim.PauliString(\"-ZZ\"),\n        ],\n        zs=[\n            stim.PauliString(\"+IZ\"),\n            stim.PauliString(\"-XI\"),\n        ],\n    )\n    assert t.x_sign(0) == -1 == t.x_output(0).sign\n    assert t.x_sign(1) == -1 == t.x_output(1).sign\n    assert t.y_sign(0) == -1 == t.y_output(0).sign\n    assert t.y_sign(1) == -1 == t.y_output(1).sign\n    assert t.z_sign(0) == +1 == t.z_output(0).sign\n    assert t.z_sign(1) == -1 == t.z_output(1).sign\n\n    with pytest.raises(ValueError, match=\"target\"):\n        _ = t.x_sign(-1)\n    with pytest.raises(ValueError, match=\"target\"):\n        _ = t.y_sign(-1)\n    with pytest.raises(ValueError, match=\"target\"):\n        _ = t.z_sign(-1)\n    with pytest.raises(ValueError, match=\"target\"):\n        _ = t.x_sign(2)\n    with pytest.raises(ValueError, match=\"target\"):\n        _ = t.y_sign(2)\n    with pytest.raises(ValueError, match=\"target\"):\n        _ = t.z_sign(2)\n\n\ndef test_to_stabilizers():\n    t = stim.Tableau.from_stabilizers([\n        stim.PauliString(\"XXXX\"),\n        stim.PauliString(\"YYYY\"),\n        stim.PauliString(\"YYZZ\"),\n        stim.PauliString(\"XXZZ\"),\n    ])\n    assert t.to_stabilizers() == [\n        stim.PauliString(\"XXXX\"),\n        stim.PauliString(\"YYYY\"),\n        stim.PauliString(\"YYZZ\"),\n        stim.PauliString(\"XXZZ\"),\n    ]\n    assert t.to_stabilizers(canonicalize=True) == [\n        stim.PauliString(\"-XX__\"),\n        stim.PauliString(\"-ZZ__\"),\n        stim.PauliString(\"-__XX\"),\n        stim.PauliString(\"-__ZZ\"),\n    ]\n\n\ndef test_to_circuit_graph_state_preserves_stabilizers():\n    t = stim.Tableau.random(10)\n    c = t.to_circuit(\"graph_state\")\n    c = stim.Circuit(str(c).replace('RX', 'H'))\n    original = t.to_stabilizers(canonicalize=True)\n    reconstructed = c.to_tableau().to_stabilizers(canonicalize=True)\n    assert original == reconstructed\n\n\ndef test_to_circuit_mpp_preserves_stabilizers():\n    t = stim.Tableau.random(10)\n    original = t.to_stabilizers(canonicalize=True)\n    sim = stim.TableauSimulator()\n    sim.do_circuit(t.to_circuit(\"mpp_state\"))\n    reconstructed = sim.canonical_stabilizers()\n    assert original == reconstructed\n\n\ndef test_to_circuit_mpp_unsigned_preserves_stabilizers():\n    t = stim.Tableau.random(10)\n    original = t.to_stabilizers(canonicalize=True)\n    sim = stim.TableauSimulator()\n    sim.do_circuit(t.to_circuit(\"mpp_state_unsigned\"))\n    reconstructed = sim.canonical_stabilizers()\n    for e in original:\n        e.sign = +1\n    for e in reconstructed:\n        e.sign = +1\n    assert original == reconstructed\n\n\ndef test_from_stabilizers_error_messages():\n    with pytest.raises(ValueError, match=\"anticommute\"):\n        stim.Tableau.from_stabilizers([\n            stim.PauliString(\"Z\"),\n            stim.PauliString(\"X\"),\n        ])\n    with pytest.raises(ValueError, match=\"anticommute\"):\n        stim.Tableau.from_stabilizers([\n            stim.PauliString(\"Z\"),\n            stim.PauliString(\"X\" + \"_\"*500),\n        ])\n    with pytest.raises(ValueError, match=\"contradict\"):\n        stim.Tableau.from_stabilizers([\n            stim.PauliString(\"Z_\"),\n            stim.PauliString(\"-_Z\"),\n            stim.PauliString(\"Z\" + \"_\"*500 + \"X\"),\n            stim.PauliString(\"ZZ\"),\n        ])\n    with pytest.raises(ValueError, match=\"redundant\"):\n        stim.Tableau.from_stabilizers([\n            stim.PauliString(\"-Z_\"),\n            stim.PauliString(\"Z\" + \"_\"*500 + \"X\"),\n            stim.PauliString(\"-__Z\"),\n            stim.PauliString(\"_Z_\"),\n            stim.PauliString(\"Z_Z\"),\n        ])\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_specialized_prepend.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <cassert>\n\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_X(size_t q) {\n    zs[q].sign ^= 1;\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_Y(size_t q) {\n    xs[q].sign ^= 1;\n    zs[q].sign ^= 1;\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_Z(size_t q) {\n    xs[q].sign ^= 1;\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_pauli_product(const PauliStringRef<W> &op) {\n    assert(op.num_qubits == num_qubits);\n    zs.signs ^= op.xs;\n    xs.signs ^= op.zs;\n}\n\ntemplate <size_t W>\nstruct IgnoreAntiCommute {\n    PauliStringRef<W> rhs;\n    IgnoreAntiCommute(PauliStringRef<W> rhs) : rhs(rhs) {\n    }\n};\n\ntemplate <size_t W>\nvoid operator*=(PauliStringRef<W> lhs, const IgnoreAntiCommute<W> &rhs) {\n    lhs.sign ^= 2 & lhs.inplace_right_mul_returning_log_i_scalar(rhs.rhs);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_H_XZ(const size_t q) {\n    xs[q].swap_with(zs[q]);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_H_YZ(const size_t q) {\n    zs[q] *= IgnoreAntiCommute<W>(xs[q]);\n    prepend_Z(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_H_XY(const size_t q) {\n    xs[q] *= IgnoreAntiCommute<W>(zs[q]);\n    prepend_Y(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_H_NXY(const size_t q) {\n    xs[q] *= IgnoreAntiCommute<W>(zs[q]);\n    prepend_X(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_H_NXZ(const size_t q) {\n    xs[q].swap_with(zs[q]);\n    prepend_Y(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_H_NYZ(const size_t q) {\n    zs[q] *= IgnoreAntiCommute<W>(xs[q]);\n    prepend_Y(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_C_XYZ(const size_t q) {\n    PauliStringRef<W> x = xs[q];\n    PauliStringRef<W> z = zs[q];\n    z *= IgnoreAntiCommute<W>(x);\n    x.swap_with(z);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_C_NXYZ(const size_t q) {\n    PauliStringRef<W> x = xs[q];\n    PauliStringRef<W> z = zs[q];\n    z *= IgnoreAntiCommute<W>(x);\n    x.swap_with(z);\n    prepend_Y(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_C_XNYZ(const size_t q) {\n    PauliStringRef<W> x = xs[q];\n    PauliStringRef<W> z = zs[q];\n    z *= IgnoreAntiCommute<W>(x);\n    x.swap_with(z);\n    prepend_Z(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_C_XYNZ(const size_t q) {\n    PauliStringRef<W> x = xs[q];\n    PauliStringRef<W> z = zs[q];\n    z *= IgnoreAntiCommute<W>(x);\n    x.swap_with(z);\n    prepend_X(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_C_ZYX(const size_t q) {\n    PauliStringRef<W> x = xs[q];\n    PauliStringRef<W> z = zs[q];\n    x.swap_with(z);\n    z *= IgnoreAntiCommute<W>(x);\n    prepend_X(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_C_ZYNX(const size_t q) {\n    PauliStringRef<W> x = xs[q];\n    PauliStringRef<W> z = zs[q];\n    x.swap_with(z);\n    z *= IgnoreAntiCommute<W>(x);\n    prepend_Y(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_C_ZNYX(const size_t q) {\n    PauliStringRef<W> x = xs[q];\n    PauliStringRef<W> z = zs[q];\n    x.swap_with(z);\n    z *= IgnoreAntiCommute<W>(x);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_C_NZYX(const size_t q) {\n    PauliStringRef<W> x = xs[q];\n    PauliStringRef<W> z = zs[q];\n    x.swap_with(z);\n    z *= IgnoreAntiCommute<W>(x);\n    prepend_Z(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_X(size_t q) {\n    prepend_SQRT_X_DAG(q);\n    prepend_X(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_X_DAG(size_t q) {\n    zs[q] *= IgnoreAntiCommute<W>(xs[q]);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_Y(size_t q) {\n    PauliStringRef<W> z = zs[q];\n    z.sign ^= 1;\n    xs[q].swap_with(z);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_Y_DAG(size_t q) {\n    PauliStringRef<W> z = zs[q];\n    xs[q].swap_with(z);\n    z.sign ^= 1;\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_Z(size_t q) {\n    prepend_SQRT_Z_DAG(q);\n    prepend_Z(q);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_Z_DAG(size_t q) {\n    xs[q] *= IgnoreAntiCommute<W>(zs[q]);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SWAP(size_t q1, size_t q2) {\n    zs[q1].swap_with(zs[q2]);\n    xs[q1].swap_with(xs[q2]);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_ISWAP(size_t q1, size_t q2) {\n    prepend_SWAP(q1, q2);\n    prepend_ZCZ(q1, q2);\n    prepend_SQRT_Z(q1);\n    prepend_SQRT_Z(q2);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_ISWAP_DAG(size_t q1, size_t q2) {\n    prepend_SWAP(q1, q2);\n    prepend_ZCZ(q1, q2);\n    prepend_SQRT_Z_DAG(q1);\n    prepend_SQRT_Z_DAG(q2);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_ZCX(size_t control, size_t target) {\n    zs[target] *= zs[control];\n    xs[control] *= xs[target];\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_ZCY(size_t control, size_t target) {\n    prepend_H_YZ(target);\n    prepend_ZCZ(control, target);\n    prepend_H_YZ(target);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_ZCZ(size_t control, size_t target) {\n    xs[target] *= zs[control];\n    xs[control] *= zs[target];\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_XCX(size_t control, size_t target) {\n    zs[target] *= xs[control];\n    zs[control] *= xs[target];\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_XX(size_t q1, size_t q2) {\n    prepend_SQRT_XX_DAG(q1, q2);\n    prepend_X(q1);\n    prepend_X(q2);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_XX_DAG(size_t q1, size_t q2) {\n    zs[q1] *= IgnoreAntiCommute<W>(xs[q1]);\n    zs[q1] *= IgnoreAntiCommute<W>(xs[q2]);\n    zs[q2] *= IgnoreAntiCommute<W>(xs[q1]);\n    zs[q2] *= IgnoreAntiCommute<W>(xs[q2]);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_YY(size_t q1, size_t q2) {\n    prepend_SQRT_YY_DAG(q1, q2);\n    prepend_Y(q1);\n    prepend_Y(q2);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_YY_DAG(size_t q1, size_t q2) {\n    auto z1 = zs[q1];\n    auto z2 = zs[q2];\n    auto x1 = xs[q1];\n    auto x2 = xs[q2];\n\n    x1 *= IgnoreAntiCommute<W>(z1);\n    z1 *= IgnoreAntiCommute<W>(z2);\n    z1 *= IgnoreAntiCommute<W>(x2);\n    x2 *= IgnoreAntiCommute<W>(x1);\n    z2 *= IgnoreAntiCommute<W>(x1);\n    x1 *= IgnoreAntiCommute<W>(z1);\n    x1.swap_with(z1);\n    x2.swap_with(z2);\n\n    prepend_Z(q2);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_ZZ(size_t q1, size_t q2) {\n    prepend_SQRT_ZZ_DAG(q1, q2);\n    prepend_Z(q1);\n    prepend_Z(q2);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_SQRT_ZZ_DAG(size_t q1, size_t q2) {\n    xs[q1] *= IgnoreAntiCommute<W>(zs[q1]);\n    xs[q1] *= IgnoreAntiCommute<W>(zs[q2]);\n    xs[q2] *= IgnoreAntiCommute<W>(zs[q1]);\n    xs[q2] *= IgnoreAntiCommute<W>(zs[q2]);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_XCY(size_t control, size_t target) {\n    prepend_H_XY(target);\n    prepend_XCX(control, target);\n    prepend_H_XY(target);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_XCZ(size_t control, size_t target) {\n    prepend_ZCX(target, control);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_YCX(size_t control, size_t target) {\n    prepend_XCY(target, control);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_YCY(size_t control, size_t target) {\n    prepend_H_YZ(control);\n    prepend_H_YZ(target);\n    prepend_ZCZ(control, target);\n    prepend_H_YZ(target);\n    prepend_H_YZ(control);\n}\n\ntemplate <size_t W>\nvoid Tableau<W>::prepend_YCZ(size_t control, size_t target) {\n    prepend_ZCY(target, control);\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_transposed_raii.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_STABILIZERS_TABLEAU_TRANSPOSED_RAII_H\n#define _STIM_STABILIZERS_TABLEAU_TRANSPOSED_RAII_H\n\n#include <iostream>\n#include <unordered_map>\n\n#include \"stim/mem/simd_bit_table.h\"\n#include \"stim/mem/simd_util.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\n/// When this class is constructed, it transposes the tableau given to it.\n/// The transpose is undone on deconstruction.\n///\n/// This is useful when appending operations to the tableau, since otherwise\n/// the append would be working against the grain of memory.\n///\n/// The template parameter, W, represents the SIMD width.\ntemplate <size_t W>\nstruct TableauTransposedRaii {\n    Tableau<W> &tableau;\n\n    explicit TableauTransposedRaii(Tableau<W> &tableau);\n    ~TableauTransposedRaii();\n\n    TableauTransposedRaii() = delete;\n    TableauTransposedRaii(const TableauTransposedRaii &) = delete;\n    TableauTransposedRaii(TableauTransposedRaii &&) = delete;\n\n    PauliString<W> unsigned_x_input(size_t q) const;\n\n    void append_H_XZ(size_t q);\n    void append_H_XY(size_t q);\n    void append_H_YZ(size_t q);\n    void append_S(size_t q);\n    void append_ZCX(size_t control, size_t target);\n    void append_ZCY(size_t control, size_t target);\n    void append_ZCZ(size_t control, size_t target);\n    void append_X(size_t q);\n    void append_SWAP(size_t q1, size_t q2);\n};\n\n}  // namespace stim\n\n#include \"stim/stabilizers/tableau_transposed_raii.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/stabilizers/tableau_transposed_raii.inl",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include <cstring>\n#include <map>\n\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/stabilizers/tableau_transposed_raii.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nTableauTransposedRaii<W>::TableauTransposedRaii(Tableau<W> &tableau) : tableau(tableau) {\n    tableau.do_transpose_quadrants();\n}\n\ntemplate <size_t W>\nTableauTransposedRaii<W>::~TableauTransposedRaii() {\n    tableau.do_transpose_quadrants();\n}\n\n/// Iterates over the Paulis in a row of the tableau.\n///\n/// Args:\n///     trans: The transposed tableau (where rows are contiguous in memory and so operations can be done efficiently).\n///     q: The row to iterate over.\n///     body: A function taking X, Z, and SIGN words.\n///         The X and Z words are chunks of xz-encoded Paulis from the row.\n///         The SIGN word is the corresponding chunk of sign bits from the sign row.\ntemplate <size_t W, typename FUNC>\ninline void for_each_trans_obs(TableauTransposedRaii<W> &trans, size_t q, FUNC body) {\n    for (size_t k = 0; k < 2; k++) {\n        TableauHalf<W> &h = k == 0 ? trans.tableau.xs : trans.tableau.zs;\n        PauliStringRef<W> p = h[q];\n        p.xs.for_each_word(p.zs, h.signs, body);\n    }\n}\n\ntemplate <size_t W, typename FUNC>\ninline void for_each_trans_obs(TableauTransposedRaii<W> &trans, size_t q1, size_t q2, FUNC body) {\n    for (size_t k = 0; k < 2; k++) {\n        TableauHalf<W> &h = k == 0 ? trans.tableau.xs : trans.tableau.zs;\n        PauliStringRef<W> p1 = h[q1];\n        PauliStringRef<W> p2 = h[q2];\n        p1.xs.for_each_word(p1.zs, p2.xs, p2.zs, h.signs, body);\n    }\n}\n\ntemplate <size_t W>\nvoid TableauTransposedRaii<W>::append_ZCX(size_t control, size_t target) {\n    for_each_trans_obs<W>(\n        *this,\n        control,\n        target,\n        [](simd_word<W> &cx, simd_word<W> &cz, simd_word<W> &tx, simd_word<W> &tz, simd_word<W> &s) {\n            s ^= (cz ^ tx).andnot(cx & tz);\n            cz ^= tz;\n            tx ^= cx;\n        });\n}\n\ntemplate <size_t W>\nvoid TableauTransposedRaii<W>::append_ZCY(size_t control, size_t target) {\n    for_each_trans_obs<W>(\n        *this,\n        control,\n        target,\n        [](simd_word<W> &cx, simd_word<W> &cz, simd_word<W> &tx, simd_word<W> &tz, simd_word<W> &s) {\n            cz ^= tx;\n            s ^= cx & cz & (tx ^ tz);\n            cz ^= tz;\n            tx ^= cx;\n            tz ^= cx;\n        });\n}\n\ntemplate <size_t W>\nvoid TableauTransposedRaii<W>::append_ZCZ(size_t control, size_t target) {\n    for_each_trans_obs<W>(\n        *this,\n        control,\n        target,\n        [](simd_word<W> &cx, simd_word<W> &cz, simd_word<W> &tx, simd_word<W> &tz, simd_word<W> &s) {\n            s ^= cx & tx & (cz ^ tz);\n            cz ^= tx;\n            tz ^= cx;\n        });\n}\n\ntemplate <size_t W>\nvoid TableauTransposedRaii<W>::append_SWAP(size_t q1, size_t q2) {\n    for_each_trans_obs<W>(\n        *this, q1, q2, [](simd_word<W> &x1, simd_word<W> &z1, simd_word<W> &x2, simd_word<W> &z2, simd_word<W> &s) {\n            std::swap(x1, x2);\n            std::swap(z1, z2);\n        });\n}\n\ntemplate <size_t W>\nvoid TableauTransposedRaii<W>::append_H_XY(size_t target) {\n    for_each_trans_obs<W>(*this, target, [](simd_word<W> &x, simd_word<W> &z, simd_word<W> &s) {\n        s ^= x.andnot(z);\n        z ^= x;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauTransposedRaii<W>::append_H_YZ(size_t target) {\n    for_each_trans_obs<W>(*this, target, [](simd_word<W> &x, simd_word<W> &z, simd_word<W> &s) {\n        s ^= z.andnot(x);\n        x ^= z;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauTransposedRaii<W>::append_S(size_t target) {\n    for_each_trans_obs<W>(*this, target, [](simd_word<W> &x, simd_word<W> &z, simd_word<W> &s) {\n        s ^= x & z;\n        z ^= x;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauTransposedRaii<W>::append_H_XZ(size_t q) {\n    for_each_trans_obs<W>(*this, q, [](simd_word<W> &x, simd_word<W> &z, simd_word<W> &s) {\n        std::swap(x, z);\n        s ^= x & z;\n    });\n}\n\ntemplate <size_t W>\nvoid TableauTransposedRaii<W>::append_X(size_t target) {\n    for_each_trans_obs<W>(*this, target, [](simd_word<W> &x, simd_word<W> &z, simd_word<W> &s) {\n        s ^= z;\n    });\n}\n\ntemplate <size_t W>\nPauliString<W> TableauTransposedRaii<W>::unsigned_x_input(size_t q) const {\n    PauliString<W> result(tableau.num_qubits);\n    result.xs = tableau.zs[q].zs;\n    result.zs = tableau.xs[q].zs;\n    return result;\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/util_bot/arg_parse.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_bot/arg_parse.h\"\n\n#include <algorithm>\n#include <array>\n#include <cmath>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <fstream>\n#include <iostream>\n#include <set>\n\nusing namespace stim;\n\nstd::string SubCommandHelp::str_help() const {\n    std::stringstream ss;\n    write_help(ss);\n    return ss.str();\n}\n\nvoid write_indented(std::string_view s, std::ostream &out, size_t indent) {\n    bool was_new_line = true;\n    for (char c : s) {\n        if (was_new_line && c != '\\n') {\n            for (size_t k = 0; k < indent; k++) {\n                out.put(' ');\n            }\n        }\n        out.put(c);\n        was_new_line = c == '\\n';\n    }\n}\n\nvoid SubCommandHelp::write_help(std::ostream &out) const {\n    std::vector<SubCommandHelpFlag> flags_copy = flags;\n    std::sort(flags_copy.begin(), flags_copy.end(), [](const SubCommandHelpFlag &f1, const SubCommandHelpFlag &f2) {\n        return f1.flag_name < f2.flag_name;\n    });\n    out << \"NAME\\n\";\n    out << \"    stim \" << subcommand_name << \"\\n\\n\";\n    out << \"SYNOPSIS\\n\";\n    out << \"    stim \" << subcommand_name;\n    for (const auto &flag : flags_copy) {\n        out << \" \\\\\\n        \";\n        bool allows_none =\n            std::find(flag.allowed_values.begin(), flag.allowed_values.end(), \"[none]\") != flag.allowed_values.end();\n        bool allows_empty =\n            std::find(flag.allowed_values.begin(), flag.allowed_values.end(), \"[switch]\") != flag.allowed_values.end();\n        if (allows_none) {\n            out << \"[\";\n        }\n        out << flag.flag_name;\n        if (flag.type != \"bool\") {\n            out << \" \";\n            if (allows_empty) {\n                out << \"[\";\n            }\n            out << flag.type;\n            if (allows_empty) {\n                out << \"]\";\n            }\n        }\n        if (allows_none) {\n            out << \"]\";\n        }\n    }\n    out << \"\\n\\n\";\n    out << \"DESCRIPTION\\n\";\n    write_indented(description, out, 4);\n    out << \"\\n\\n\";\n    if (!flags_copy.empty()) {\n        out << \"OPTIONS\\n\";\n        for (const auto &f : flags_copy) {\n            out << \"    \" << f.flag_name << \"\\n\";\n            write_indented(f.description, out, 8);\n            out << \"\\n\\n\";\n        }\n    }\n    if (!examples.empty()) {\n        out << \"EXAMPLES\\n\";\n        for (size_t k = 0; k < examples.size(); k++) {\n            if (k) {\n                out << \"\\n\\n\";\n            }\n            out << \"    Example #\" << (k + 1) << \"\\n\";\n            write_indented(examples[k], out, 8);\n        }\n    }\n}\n\nconst char *stim::require_find_argument(const char *name_c_str, int argc, const char **argv) {\n    const char *result = find_argument(name_c_str, argc, argv);\n    if (result == 0) {\n        std::stringstream msg;\n        msg << \"\\033[31mMissing command line argument: '\" << name_c_str << \"'\";\n        throw std::invalid_argument(msg.str());\n    }\n    return result;\n}\n\nconst char *stim::find_argument(const char *name_c_str, int argc, const char **argv) {\n    // Respect that the \"--\" argument terminates flags.\n    size_t flag_count = 1;\n    while (flag_count < (size_t)argc && strcmp(argv[flag_count], \"--\") != 0) {\n        flag_count++;\n    }\n\n    // Search for the desired flag.\n    size_t n = strlen(name_c_str);\n    for (size_t i = 1; i < flag_count; i++) {\n        // Check if argument starts with expected flag.\n        const char *loc = strstr(argv[i], name_c_str);\n        if (loc != argv[i] || (loc[n] != '\\0' && loc[n] != '=')) {\n            continue;\n        }\n\n        // If the flag is alone and followed by the end or another flag, no\n        // argument was provided. Return the empty string to indicate this.\n        if (loc[n] == '\\0' && ((int)i == argc - 1 || (argv[i + 1][0] == '-' && !isdigit(argv[i + 1][1])))) {\n            return argv[i] + n;\n        }\n\n        // If the flag value is specified inline with '=', return a pointer to\n        // the start of the value within the flag string.\n        if (loc[n] == '=') {\n            // Argument provided inline.\n            return loc + n + 1;\n        }\n\n        // The argument value is specified by the next command line argument.\n        return argv[i + 1];\n    }\n\n    // Not found.\n    return 0;\n}\n\nvoid stim::check_for_unknown_arguments(\n    const std::vector<const char *> &known_arguments,\n    const std::vector<const char *> &known_but_deprecated_arguments,\n    const char *for_mode,\n    int argc,\n    const char **argv) {\n    for (int i = 1; i < argc; i++) {\n        if (for_mode != nullptr && i == 1 && strcmp(argv[i], for_mode) == 0) {\n            continue;\n        }\n        // Respect that the \"--\" argument terminates flags.\n        if (!strcmp(argv[i], \"--\")) {\n            break;\n        }\n\n        // Check if there's a matching command line argument.\n        int matched = 0;\n        std::array<const std::vector<const char *> *, 2> both{&known_arguments, &known_but_deprecated_arguments};\n        for (const auto &knowns : both) {\n            for (const auto &known : *knowns) {\n                const char *loc = strstr(argv[i], known);\n                size_t n = strlen(known);\n                if (loc == argv[i] && (loc[n] == '\\0' || loc[n] == '=')) {\n                    // Skip words that are values for a previous flag.\n                    if (loc[n] == '\\0' && i < argc - 1 && argv[i + 1][0] != '-') {\n                        i++;\n                    }\n                    matched = 1;\n                    break;\n                }\n            }\n        }\n\n        // Print error and exit if flag is not recognized.\n        if (!matched) {\n            std::stringstream msg;\n            if (for_mode == nullptr) {\n                msg << \"Unrecognized command line argument \" << argv[i] << \".\\n\";\n                msg << \"Recognized command line arguments:\\n\";\n            } else {\n                msg << \"Unrecognized command line argument \" << argv[i] << \" for `stim \" << for_mode << \"`.\\n\";\n                msg << \"Recognized command line arguments for `stim \" << for_mode << \"`:\\n\";\n            }\n            std::set<std::string> known_sorted;\n            for (const auto &v : known_arguments) {\n                known_sorted.insert(v);\n            }\n            for (const auto &v : known_sorted) {\n                msg << \"    \" << v << \"\\n\";\n            }\n            throw std::invalid_argument(msg.str());\n        }\n    }\n}\n\nbool stim::find_bool_argument(const char *name_c_str, int argc, const char **argv) {\n    const char *text = find_argument(name_c_str, argc, argv);\n    if (text == nullptr) {\n        return false;\n    }\n    if (text[0] == '\\0') {\n        return true;\n    }\n    std::stringstream msg;\n    msg << \"Got non-empty value '\" << text << \"' for boolean flag '\" << name_c_str << \"'.\";\n    throw std::invalid_argument(msg.str());\n}\n\nbool stim::parse_int64(std::string_view data, int64_t *out) {\n    if (data.empty()) {\n        return false;\n    }\n    bool negate = false;\n    if (data.starts_with(\"-\")) {\n        negate = true;\n        data = data.substr(1);\n    } else if (data.starts_with(\"+\")) {\n        data = data.substr(1);\n    }\n\n    uint64_t accumulator = 0;\n    for (char c : data) {\n        if (!(c >= '0' && c <= '9')) {\n            return false;\n        }\n        uint64_t digit = c - '0';\n        uint64_t next = accumulator * 10 + digit;\n        if (accumulator != (next - digit) / 10) {\n            return false;  // Overflow.\n        }\n        accumulator = next;\n    }\n\n    if (negate && accumulator == (uint64_t)INT64_MAX + uint64_t{1}) {\n        *out = INT64_MIN;\n        return true;\n    }\n    if (accumulator > INT64_MAX) {\n        return false;\n    }\n\n    *out = (int64_t)accumulator;\n    if (negate) {\n        *out *= -1;\n    }\n    return true;\n}\n\nint64_t stim::find_int64_argument(\n    const char *name_c_str, int64_t default_value, int64_t min_value, int64_t max_value, int argc, const char **argv) {\n    const char *text = find_argument(name_c_str, argc, argv);\n    if (text == nullptr || text[0] == '\\0') {\n        if (default_value < min_value || default_value > max_value) {\n            std::stringstream msg;\n            msg << \"Must specify a value for int flag '\" << name_c_str << \"'.\";\n            throw std::invalid_argument(msg.str());\n        }\n        return default_value;\n    }\n\n    // Attempt to parse.\n    int64_t i;\n    if (!parse_int64(text, &i)) {\n        std::stringstream msg;\n        msg << \"Got non-int64 value '\" << text << \"' for int64 flag '\" << name_c_str << \"'.\";\n        throw std::invalid_argument(msg.str());\n    }\n\n    // In range?\n    if (i < min_value || i > max_value) {\n        std::stringstream msg;\n        msg << \"Integer value '\" << text << \"' for flag '\" << name_c_str << \"' doesn't satisfy \" << min_value\n            << \" <= \" << i << \" <= \" << max_value << \".\";\n        throw std::invalid_argument(msg.str());\n    }\n\n    return i;\n}\n\nfloat stim::find_float_argument(\n    const char *name_c_str, float default_value, float min_value, float max_value, int argc, const char **argv) {\n    const char *text = find_argument(name_c_str, argc, argv);\n    if (text == nullptr) {\n        if (default_value < min_value || default_value > max_value) {\n            std::stringstream msg;\n            msg << \"Must specify a value for float flag '\" << name_c_str << \"'.\";\n            throw std::invalid_argument(msg.str());\n        }\n        return default_value;\n    }\n\n    // Attempt to parse.\n    char *processed;\n    float f = strtof(text, &processed);\n    if (*processed != '\\0') {\n        std::stringstream msg;\n        msg << \"Got non-float value '\" << text << \"' for float flag '\" << name_c_str << \"'.\";\n        throw std::invalid_argument(msg.str());\n    }\n\n    // In range?\n    if (f < min_value || f > max_value || f != f) {\n        std::stringstream msg;\n        msg << \"Float value '\" << text << \"' for flag '\" << name_c_str << \"' doesn't satisfy \" << min_value\n            << \" <= \" << f << \" <= \" << max_value << \".\";\n        throw std::invalid_argument(msg.str());\n    }\n\n    return f;\n}\n\nFILE *stim::find_open_file_argument(\n    const char *name_c_str, FILE *default_file, const char *mode, int argc, const char **argv) {\n    const char *path_c_str = find_argument(name_c_str, argc, argv);\n    if (path_c_str == nullptr) {\n        if (default_file == nullptr) {\n            std::stringstream msg;\n            msg << \"Missing command line argument: '\" << name_c_str << \"'\";\n            throw std::invalid_argument(msg.str());\n        }\n        return default_file;\n    }\n    if (*path_c_str == '\\0') {\n        std::stringstream msg;\n        msg << \"Command line argument '\" << name_c_str << \"' can't be empty. It's supposed to be a file path.\";\n        throw std::invalid_argument(msg.str());\n    }\n    FILE *file = fopen(path_c_str, mode);\n    if (file == nullptr) {\n        std::stringstream msg;\n        msg << \"Failed to open '\" << path_c_str << \"'\";\n        throw std::invalid_argument(msg.str());\n    }\n    return file;\n}\n\nostream_else_cout::ostream_else_cout(std::unique_ptr<std::ostream> &&held) : held(std::move(held)) {\n}\n\nstd::ostream &ostream_else_cout::stream() {\n    if (held) {\n        return *held;\n    } else {\n        return std::cout;\n    }\n}\n\nostream_else_cout stim::find_output_stream_argument(\n    const char *name_c_str, bool default_std_out, int argc, const char **argv) {\n    const char *path_c_str = find_argument(name_c_str, argc, argv);\n    if (path_c_str == nullptr) {\n        if (!default_std_out) {\n            std::stringstream msg;\n            msg << \"Missing command line argument: '\" << name_c_str << \"'\";\n            throw std::invalid_argument(msg.str());\n        }\n        return ostream_else_cout(nullptr);\n    }\n    if (*path_c_str == '\\0') {\n        std::stringstream msg;\n        msg << \"Command line argument '\" << name_c_str << \"' can't be empty. It's supposed to be a file path.\";\n        throw std::invalid_argument(msg.str());\n    }\n    std::unique_ptr<std::ostream> f(new std::ofstream(path_c_str));\n    if (f->fail()) {\n        std::stringstream msg;\n        msg << \"Failed to open '\" << path_c_str << \"'\";\n        throw std::invalid_argument(msg.str());\n    }\n    return ostream_else_cout(std::move(f));\n}\n\nstd::vector<std::string_view> stim::split_view(char splitter, std::string_view text) {\n    std::vector<std::string_view> result;\n    size_t start = 0;\n    for (size_t k = 0; k < text.size(); k++) {\n        if (text[k] == splitter) {\n            result.push_back(text.substr(start, k - start));\n            start = k + 1;\n        }\n    }\n    result.push_back(text.substr(start, text.size() - start));\n    return result;\n}\n\nstatic double parse_exact_double_from_null_terminated(const char *c, size_t size) {\n    char *end = nullptr;\n    double d = strtod(c, &end);\n    if (size > 0 && !isspace(*c)) {\n        if (end == c + size && !std::isinf(d) && !std::isnan(d)) {\n            return d;\n        }\n    }\n    std::stringstream ss;\n    ss << \"Not an exact finite double: '\" << c << \"'\";\n    throw std::invalid_argument(ss.str());\n}\n\ndouble stim::parse_exact_double_from_string(std::string_view text) {\n    if (text.size() + 1 < 15) {\n        char buf[16];\n        memcpy(buf, text.data(), text.size());\n        buf[text.size()] = '\\0';\n        return parse_exact_double_from_null_terminated(&buf[0], text.size());\n    } else {\n        std::string s(text);\n        return parse_exact_double_from_null_terminated(s.c_str(), text.size());\n    }\n}\n\nstatic bool try_parse_exact_uint64_t_from_string(std::string_view text, uint64_t *out) {\n    if (text.empty()) {\n        return false;\n    }\n    if (text[0] == '-') {\n        return false;\n    }\n    size_t k = 0;\n    if (text[k] == '+') {\n        k += 1;\n    }\n    uint64_t acc = 0;\n    while (k < text.size()) {\n        char c = text[k];\n        if (c < '0' || c > '9') {\n            return false;\n        }\n        if (acc > UINT64_MAX / 10) {\n            return false;\n        }\n        acc *= 10;\n        uint8_t d = c - '0';\n        if (acc > UINT64_MAX - d) {\n            return false;\n        }\n        acc += d;\n        k++;\n    }\n    *out = acc;\n    return true;\n}\n\nuint64_t stim::parse_exact_uint64_t_from_string(std::string_view text) {\n    uint64_t result = 0;\n    if (try_parse_exact_uint64_t_from_string(text, &result)) {\n        return result;\n    }\n    std::stringstream ss;\n    ss << \"Not an exact integer that can be stored in a uint64_t: '\" << text << \"'\";\n    throw std::invalid_argument(ss.str());\n}\n"
  },
  {
    "path": "src/stim/util_bot/arg_parse.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_UTIL_BOT_ARG_PARSE_H\n#define _STIM_UTIL_BOT_ARG_PARSE_H\n\n#include <cstdint>\n#include <map>\n#include <memory>\n#include <sstream>\n#include <string>\n#include <vector>\n\nnamespace stim {\n\nstruct SubCommandHelpFlag {\n    std::string flag_name;\n    std::string type;\n    std::string default_value;\n    std::vector<std::string> allowed_values;\n    std::string description;\n};\n\nstruct SubCommandHelp {\n    std::string subcommand_name;\n    std::string description;\n    std::vector<std::string> examples;\n    std::vector<SubCommandHelpFlag> flags;\n\n    void write_help(std::ostream &out) const;\n    std::string str_help() const;\n};\n\n/// Searches through command line flags for a particular flag's argument.\n///\n/// Args:\n///     name: The flag's name, including any hyphens. For example, \"-mode\".\n///     argc: Number of command line arguments.\n///     argv: Array of command line argument strings.\n///\n/// Returns:\n///     A pointer to the command line flag's value string, or else 0 if the flag\n///     is not specified. Flags that are set without specifying a value will\n///     cause the method to return a pointer to an empty string.\nconst char *find_argument(const char *name, int argc, const char **argv);\n\n/// Searches through command line flags for a particular flag's argument.\n///\n/// Args:\n///     name: The flag's name, including any hyphens. For example, \"-mode\".\n///     argc: Number of command line arguments.\n///     argv: Array of command line argument strings.\n///\n/// Returns:\n///     A pointer to the command line flag's value string. Flags that are set\n///     without specifying a value will cause the method to return a pointer to\n///     an empty string.\n///\n/// Raises:\n///     std::invalid_argument: The argument isn't present.\nconst char *require_find_argument(const char *name, int argc, const char **argv);\n\n/// Checks that all command line arguments are recognized.\n///\n/// Args:\n///     known_arguments: Names of known arguments.\n///     for_mode: Can be set to nullptr. Modifies error message.\n///     argc: Number of command line arguments.\n///     argv: Array of command line argument strings.\n///\n/// Raises:\n///     std::invalid_argument: Unknown arguments are present.\nvoid check_for_unknown_arguments(\n    const std::vector<const char *> &known_arguments,\n    const std::vector<const char *> &known_but_deprecated_arguments,\n    const char *for_mode,\n    int argc,\n    const char **argv);\n\n/// Returns a floating point value that can be modified using command line arguments.\n///\n/// If default_value is smaller than min_value or larger than max_value, the argument is required.\n///\n/// If the specified value is invalid, the program exits with a non-zero return code and prints\n/// a message describing the problem.\n///\n/// Args:\n///     name: The name of the float flag.\n///     default_value: The value to use if the flag is not specified. If this value is less than\n///         min_value or larger than max_value, the flag is required.\n///     min_value: Values less than this are rejected.\n///     max_value: Values more than this are rejected.\n///     argc: Number of command line arguments.\n///     argv: Array of command line argument strings.\n///\n/// Returns:\n///     The floating point value.\n///\n/// Raises:\n///     std::invalid_argument:\n///         The command line flag was specified but failed to parse into a float in range.\n///     std::invalid_argument:\n///         The command line flag was not specified and default_value was not in range.\nfloat find_float_argument(\n    const char *name, float default_value, float min_value, float max_value, int argc, const char **argv);\n\n/// Returns an integer value that can be modified using command line arguments.\n///\n/// If default_value is smaller than min_value or larger than max_value, the argument is required.\n///\n/// If the specified value is invalid, the program exits with a non-zero return code and prints\n/// a message describing the problem.\n///\n/// Args:\n///     name: The name of the int flag.\n///     default_value: The value to use if the flag is not specified. If this value is less than\n///         min_value or larger than max_value, the flag is required.\n///     min_value: Values less than this are rejected.\n///     max_value: Values more than this are rejected.\n///     argc: Number of command line arguments.\n///     argv: Array of command line argument strings.\n///\n/// Returns:\n///     The integer value.\n///\n/// Raises:\n///     std::invalid_argument:\n///         The command line flag was specified but failed to parse into an int in range.\n///     std::invalid_argument:\n///         The command line flag was not specified and default_value was not in range.\nint64_t find_int64_argument(\n    const char *name, int64_t default_value, int64_t min_value, int64_t max_value, int argc, const char **argv);\n\n///\n/// Returns a boolean value that can be enabled using a command line argument.\n///\n/// If the specified value is invalid, the program exits with a non-zero return code and prints\n/// a message describing the problem.\n///\n/// Args:\n///     name: The name of the boolean flag.\n///     argc: Number of command line arguments.\n///     argv: Array of command line argument strings.\n///\n/// Returns:\n///     The boolean value.\n///\nbool find_bool_argument(const char *name, int argc, const char **argv);\n\n/// Returns the index of an argument value within an enumerated list of allowed values.\n///\n/// Args:\n///     name: The name of the enumerated flag.\n///     default_key: The default value of the flag. Set to a key that's not in the map to make the\n///         flag required.\n///     known_values: A map from allowed keys to returned values.\n///     argc: Number of command line arguments.\n///     argv: Array of command line argument strings.\n///\n/// Returns:\n///     The chosen value.\n///\n/// Raises:\n///     std::invalid_argument:\n///         The command line flag is specified but its key is not in the map.\n///     std::invalid_argument:\n///         The command line flag is not specified and the default key is not in the map.\ntemplate <typename T>\nconst T &find_enum_argument(\n    const char *name,\n    const char *default_key,\n    const std::map<std::string_view, T> &values,\n    int argc,\n    const char **argv) {\n    const char *text = find_argument(name, argc, argv);\n    if (text == nullptr) {\n        if (default_key == nullptr) {\n            std::stringstream msg;\n            msg << \"\\033[31mMust specify a value for enum flag '\" << name << \"'.\\n\";\n            throw std::invalid_argument(msg.str());\n        }\n        return values.at(default_key);\n    }\n    if (!values.contains(text)) {\n        std::stringstream msg;\n        msg << \"\\033[31mUnrecognized value '\" << text << \"' for enum flag '\" << name << \"'.\\n\";\n        msg << \"Recognized values are:\\n\";\n        for (const auto &kv : values) {\n            msg << \"    '\" << kv.first << \"'\";\n            if (default_key != nullptr && kv.first == default_key) {\n                msg << \" (default)\";\n            }\n            msg << \"\\n\";\n        }\n        msg << \"\\033[0m\";\n        throw std::invalid_argument(msg.str());\n    }\n    return values.at(text);\n}\n\n/// Returns an opened file from a command line argument.\n///\n/// Args:\n///     name: The name of the file flag that will specify the file path.\n///     default_file: The file pointer to return if the flag isn't specified (e.g. stdin). Set to\n///         nullptr to make the argument required.\n///     mode: The mode to open the file path in.\n///     argc: Number of command line arguments.\n///     argv: Array of command line argument strings.\n///\n/// Returns:\n///     The default file pointer or the opened file.\n///\n/// Raises:\n///     std::invalid_argument:\n///         Failed to open the filepath.\n///     std::invalid_argument:\n///         No argument specified and default file is nullptr.\nFILE *find_open_file_argument(const char *name, FILE *default_file, const char *mode, int argc, const char **argv);\n\n/// Exposes an owned ostream or else falls back to std::cout.\nstruct ostream_else_cout {\n   private:\n    std::unique_ptr<std::ostream> held;\n\n   public:\n    explicit ostream_else_cout(std::unique_ptr<std::ostream> &&held);\n    std::ostream &stream();\n};\n\n/// Returns an opened ostream from a command line argument.\n///\n/// Args:\n///     name: The name of the command line flag that will specify the file path.\n///     default_std_out: If true, defaults to stdout when the command line argument isn't given. Otherwise exits with\n///         failure when the command line argument isn't given.\n///     argc: Number of command line arguments.\n///     argv: Array of command line argument strings.\n///\n/// Returns:\n///     The default file pointer or the opened file.\n///\n/// Raises:\n///     std::invalid_argument:\n///         Failed to open the filepath.\n///     std::invalid_argument:\n///         Command line argument isn't present and default_std_out is false.\nostream_else_cout find_output_stream_argument(const char *name, bool default_std_out, int argc, const char **argv);\n\nstd::vector<std::string_view> split_view(char splitter, std::string_view text);\n\ndouble parse_exact_double_from_string(std::string_view text);\nuint64_t parse_exact_uint64_t_from_string(std::string_view text);\nbool parse_int64(std::string_view data, int64_t *out);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_bot/arg_parse.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_bot/arg_parse.h\"\n\n#include <stdio.h>\n#include <string>\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(arg_parse, check_for_unknown_arguments_recognize_arguments) {\n    std::vector<const char *> known{\n        \"--mode\",\n        \"--test\",\n        \"--other\",\n    };\n    const char *argv[] = {\"skipped\", \"--mode\", \"2\", \"--test\", \"5\"};\n    check_for_unknown_arguments(known, {}, nullptr, sizeof(argv) / sizeof(char *), argv);\n    check_for_unknown_arguments({}, known, nullptr, sizeof(argv) / sizeof(char *), argv);\n}\n\nTEST(arg_parse, check_for_unknown_arguments_bad_arguments) {\n    std::vector<const char *> known{\n        \"--mode\",\n        \"--test\",\n    };\n    const char *argv[] = {\"skipped\", \"--mode\", \"2\", \"--unknown\", \"5\"};\n\n    ASSERT_THROW(\n        { check_for_unknown_arguments(known, {}, nullptr, sizeof(argv) / sizeof(char *), argv); },\n        std::invalid_argument);\n    ASSERT_THROW(\n        { check_for_unknown_arguments({}, known, nullptr, sizeof(argv) / sizeof(char *), argv); },\n        std::invalid_argument);\n}\n\nTEST(arg_parse, check_for_unknown_arguments_terminator) {\n    std::vector<const char *> known{\n        \"--mode\",\n    };\n    const char *argv[] = {\"skipped\", \"--mode\", \"2\", \"--\", \"--unknown\"};\n    check_for_unknown_arguments(known, {}, nullptr, sizeof(argv) / sizeof(char *), argv);\n}\n\nTEST(arg_parse, find_argument) {\n    const char *argv[] = {\n        \"skipped\",\n        \"--mode\",\n        \"2\",\n        \"--test\",\n        \"aba\",\n        \"--a\",\n        \"-b\",\n    };\n    int n = sizeof(argv) / sizeof(char *);\n    ASSERT_TRUE(find_argument(\"--mode\", n, argv) == argv[2]);\n    ASSERT_TRUE(find_argument(\"-mode\", n, argv) == 0);\n    ASSERT_TRUE(find_argument(\"mode\", n, argv) == 0);\n    ASSERT_TRUE(find_argument(\"--test\", n, argv) == argv[4]);\n    ASSERT_TRUE(find_argument(\"--a\", n, argv) == argv[5] + 3);\n    ASSERT_TRUE(find_argument(\"-a\", n, argv) == 0);\n    ASSERT_TRUE(find_argument(\"-b\", n, argv) == argv[6] + 2);\n    ASSERT_TRUE(find_argument(\"--b\", n, argv) == 0);\n    ASSERT_TRUE(!strcmp(find_argument(\"--a\", n, argv), \"\"));\n    ASSERT_TRUE(!strcmp(find_argument(\"-b\", n, argv), \"\"));\n}\n\nTEST(arg_parse, require_find_argument) {\n    const char *argv[] = {\n        \"skipped\",\n        \"--mode\",\n        \"2\",\n        \"--test\",\n        \"aba\",\n        \"--a\",\n        \"-b\",\n    };\n    int n = sizeof(argv) / sizeof(char *);\n    assert(require_find_argument(\"--mode\", n, argv) == argv[2]);\n    assert(require_find_argument(\"--test\", n, argv) == argv[4]);\n    assert(require_find_argument(\"--a\", n, argv) == argv[5] + 3);\n    assert(require_find_argument(\"-b\", n, argv) == argv[6] + 2);\n    assert(!strcmp(require_find_argument(\"--a\", n, argv), \"\"));\n    assert(!strcmp(require_find_argument(\"-b\", n, argv), \"\"));\n    ASSERT_THROW({ require_find_argument(\"-mode\", n, argv); }, std::invalid_argument);\n    ASSERT_THROW({ require_find_argument(\"-a\", n, argv); }, std::invalid_argument);\n    ASSERT_THROW({ require_find_argument(\"--b\", n, argv); }, std::invalid_argument);\n}\n\nTEST(arg_parse, find_bool_argument) {\n    const char *argv[] = {\n        \"\",\n        \"-other\",\n        \"2\",\n        \"do\",\n        \"-not\",\n        \"-be\",\n        \"activate\",\n        \"-par\",\n        \"--\",\n        \"-okay\",\n    };\n    int n = sizeof(argv) / sizeof(char *);\n    ASSERT_EQ(find_bool_argument(\"-activate\", n, argv), 0);\n    ASSERT_EQ(find_bool_argument(\"-okay\", n, argv), 0);\n    ASSERT_EQ(find_bool_argument(\"-not\", n, argv), 1);\n    ASSERT_EQ(find_bool_argument(\"-par\", n, argv), 1);\n    ASSERT_THROW({ find_bool_argument(\"-be\", n, argv); }, std::invalid_argument);\n    ASSERT_THROW({ find_bool_argument(\"-other\", n, argv); }, std::invalid_argument);\n}\n\ntemplate <typename TEx>\nstd::string catch_msg_helper(std::function<void(void)> func, std::string expected_substring) {\n    try {\n        func();\n        return \"Expected an exception with message '\" + expected_substring + \"', but no exception was thrown.\";\n    } catch (const TEx &ex) {\n        std::string s = ex.what();\n        if (s.find(expected_substring) == std::string::npos) {\n            return \"Didn't find '\" + expected_substring + \"' in '\" + std::string(ex.what()) + \"'.\";\n        }\n        return \"\";\n    }\n}\n\n#define ASSERT_THROW_MSG(body, type, msg) ASSERT_EQ(\"\", catch_msg_helper<type>([&]() body, msg))\n\nTEST(arg_parse, find_int_argument) {\n    const char *argv[] = {\n        \"\",\n        \"-small=-23\",\n        \"-empty\",\n        \"-text\",\n        \"abc\",\n        \"-zero\",\n        \"0\",\n        \"-large\",\n        \"50\",\n        \"--\",\n        \"-okay\",\n    };\n    int n = sizeof(argv) / sizeof(char *);\n    ASSERT_EQ(find_int64_argument(\"-missing\", 5, -100, +100, n, argv), 5);\n    ASSERT_EQ(find_int64_argument(\"-small\", 5, -100, +100, n, argv), -23);\n    ASSERT_EQ(find_int64_argument(\"-large\", 5, -100, +100, n, argv), 50);\n    ASSERT_EQ(find_int64_argument(\"-zero\", 5, -100, +100, n, argv), 0);\n    ASSERT_THROW_MSG({ find_int64_argument(\"-large\", 0, 0, 49, n, argv); }, std::invalid_argument, \"50 <= 49\");\n    ASSERT_THROW_MSG({ find_int64_argument(\"-large\", 100, 51, 100, n, argv); }, std::invalid_argument, \"51 <= 50\");\n    ASSERT_THROW_MSG({ find_int64_argument(\"-text\", 0, 0, 0, n, argv); }, std::invalid_argument, \"non-int\");\n\n    ASSERT_THROW_MSG({ find_int64_argument(\"-missing\", -1, 0, 10, n, argv); }, std::invalid_argument, \"Must specify\");\n    ASSERT_THROW_MSG({ find_int64_argument(\"-missing\", 11, 0, 10, n, argv); }, std::invalid_argument, \"Must specify\");\n    ASSERT_THROW_MSG(\n        { find_int64_argument(\"-missing\", -101, -100, 100, n, argv); }, std::invalid_argument, \"Must specify\");\n\n    std::vector<const char *> args;\n    args = {\"\", \"-val\", \"99999999999999999999999999999999999999999999999999\"};\n    ASSERT_THROW_MSG(\n        { find_int64_argument(\"-val\", 0, INT64_MIN, INT64_MAX, args.size(), args.data()); },\n        std::invalid_argument,\n        \"non-int64\");\n    args = {\"\", \"-val\", \"9223372036854775807\"};\n    ASSERT_EQ(find_int64_argument(\"-val\", 0, INT64_MIN, INT64_MAX, args.size(), args.data()), INT64_MAX);\n    args = {\"\", \"-val\", \"9223372036854775808\"};\n    ASSERT_THROW_MSG(\n        { find_int64_argument(\"-val\", 0, INT64_MIN, INT64_MAX, args.size(), args.data()); },\n        std::invalid_argument,\n        \"non-int64\");\n    args = {\"\", \"-val\", \"-9223372036854775808\"};\n    ASSERT_EQ(find_int64_argument(\"-val\", 0, INT64_MIN, INT64_MAX, args.size(), args.data()), INT64_MIN);\n    args = {\"\", \"-val\", \"-9223372036854775809\"};\n    ASSERT_THROW_MSG(\n        { find_int64_argument(\"-val\", 0, INT64_MIN, INT64_MAX, args.size(), args.data()); },\n        std::invalid_argument,\n        \"non-int64\");\n}\n\nTEST(arg_parse, find_float_argument) {\n    const char *argv[] = {\n        \"\",\n        \"-small=-23.5\",\n        \"-empty\",\n        \"-text\",\n        \"abc\",\n        \"-inf\",\n        \"inf\",\n        \"-nan\",\n        \"nan\",\n        \"-zero\",\n        \"0\",\n        \"-large\",\n        \"50\",\n        \"--\",\n        \"-okay\",\n    };\n    int n = sizeof(argv) / sizeof(char *);\n    ASSERT_EQ(find_float_argument(\"-missing\", 5.5, -100, +100, n, argv), 5.5);\n    ASSERT_EQ(find_float_argument(\"-small\", 5, -100, +100, n, argv), -23.5);\n    ASSERT_EQ(find_float_argument(\"-large\", 5, -100, +100, n, argv), 50);\n    ASSERT_EQ(find_float_argument(\"-large\", 5, -100, +100, n, argv), 50);\n    ASSERT_EQ(find_float_argument(\"-zero\", 5, -100, +100, n, argv), 0);\n    ASSERT_THROW_MSG({ find_float_argument(\"-large\", 0, 0, 49, n, argv); }, std::invalid_argument, \"0 <= 49\");\n    ASSERT_THROW_MSG({ find_float_argument(\"-nan\", 0, -100, 100, n, argv); }, std::invalid_argument, \"nan <= 100\");\n    ASSERT_THROW_MSG({ find_float_argument(\"-large\", 100, 51, 100, n, argv); }, std::invalid_argument, \"<= 50\");\n    ASSERT_THROW_MSG({ find_float_argument(\"-text\", 0, 0, 0, n, argv); }, std::invalid_argument, \"non-float\");\n\n    ASSERT_THROW_MSG({ find_float_argument(\"-missing\", -1, 0, 10, n, argv); }, std::invalid_argument, \"Must specify\");\n    ASSERT_THROW_MSG({ find_float_argument(\"-missing\", -1, 11, 10, n, argv); }, std::invalid_argument, \"Must specify\");\n    ASSERT_THROW_MSG(\n        { find_float_argument(\"-missing\", -101, -100, 100, n, argv); }, std::invalid_argument, \"Must specify\");\n}\n\nTEST(arg_parse, find_enum_argument) {\n    std::vector<const char *> args{\n        \"\",\n        \"-a=test\",\n        \"-b\",\n        \"-c=rest\",\n    };\n    std::map<std::string_view, int> enums{\n        {\"\", 10},\n        {\"test\", 20},\n        {\"rest\", 30},\n    };\n    ASSERT_EQ(find_enum_argument(\"-a\", nullptr, enums, args.size(), args.data()), 20);\n    ASSERT_EQ(find_enum_argument(\"-b\", nullptr, enums, args.size(), args.data()), 10);\n    ASSERT_EQ(find_enum_argument(\"-c\", nullptr, enums, args.size(), args.data()), 30);\n    ASSERT_EQ(find_enum_argument(\"-d\", \"test\", enums, args.size(), args.data()), 20);\n    ASSERT_EQ(find_enum_argument(\"-d\", \"rest\", enums, args.size(), args.data()), 30);\n    ASSERT_THROW_MSG(\n        { find_enum_argument(\"-d\", nullptr, enums, args.size(), args.data()); },\n        std::invalid_argument,\n        \"specify a value\");\n\n    enums.erase(\"test\");\n    ASSERT_THROW_MSG(\n        { find_enum_argument(\"-a\", nullptr, enums, args.size(), args.data()); },\n        std::invalid_argument,\n        \"Unrecognized value\");\n}\n\nTEST(arg_parse, find_open_file_argument) {\n    std::vector<const char *> args;\n    FILE *tmp = tmpfile();\n\n    args = {\"\"};\n    ASSERT_THROW_MSG(\n        { find_open_file_argument(\"-arg\", nullptr, \"rb\", args.size(), args.data()); },\n        std::invalid_argument,\n        \"Missing\");\n    args = {\"\"};\n    ASSERT_EQ(find_open_file_argument(\"-arg\", tmp, \"rb\", args.size(), args.data()), tmp);\n\n    args = {\"\", \"-arg\"};\n    ASSERT_THROW_MSG(\n        { find_open_file_argument(\"-arg\", nullptr, \"rb\", args.size(), args.data()); }, std::invalid_argument, \"empty\");\n    args = {\"\", \"-arg\"};\n    ASSERT_THROW_MSG(\n        { find_open_file_argument(\"-arg\", tmp, \"rb\", args.size(), args.data()); }, std::invalid_argument, \"empty\");\n\n    RaiiTempNamedFile f;\n    FILE *f2 = fdopen(f.descriptor, \"wb\");\n    putc('x', f2);\n    fclose(f2);\n    args = {\"\", \"-arg\", f.path.data()};\n    f2 = find_open_file_argument(\"-arg\", nullptr, \"rb\", args.size(), args.data());\n    ASSERT_NE(f2, nullptr);\n    ASSERT_EQ(getc(f2), 'x');\n    fclose(f2);\n\n    remove(f.path.c_str());\n    args = {\"\", \"-arg\", f.path.data()};\n    ASSERT_THROW_MSG(\n        { find_open_file_argument(\"-arg\", nullptr, \"rb\", args.size(), args.data()); },\n        std::invalid_argument,\n        \"Failed to open\");\n    f2 = find_open_file_argument(\"-arg\", nullptr, \"wb\", args.size(), args.data());\n    fclose(f2);\n\n    fclose(tmp);\n}\n\nTEST(arg_parse, split_view) {\n    ASSERT_EQ(split_view(',', \"\"), (std::vector<std::string_view>{\"\"}));\n    ASSERT_EQ(split_view(',', \"abc\"), (std::vector<std::string_view>{\"abc\"}));\n    ASSERT_EQ(split_view(',', \",\"), (std::vector<std::string_view>{\"\", \"\"}));\n    ASSERT_EQ(split_view(',', \"abc,\"), (std::vector<std::string_view>{\"abc\", \"\"}));\n    ASSERT_EQ(split_view(',', \",abc\"), (std::vector<std::string_view>{\"\", \"abc\"}));\n    ASSERT_EQ(split_view(',', \"abc,def,ghi\"), (std::vector<std::string_view>{\"abc\", \"def\", \"ghi\"}));\n    ASSERT_EQ(split_view(',', \"abc,def,ghi,\"), (std::vector<std::string_view>{\"abc\", \"def\", \"ghi\", \"\"}));\n}\n\nTEST(arg_parse, parse_exact_double_from_string) {\n    ASSERT_THROW({ parse_exact_double_from_string(\"\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_double_from_string(\"a\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_double_from_string(\" 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_double_from_string(\"\\t1\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_double_from_string(\"1 \"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_double_from_string(\"banana\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_double_from_string(\"1.2.3\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_double_from_string(\"INFINITY\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_double_from_string(\"inf\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_double_from_string(\"nan\"); }, std::invalid_argument);\n\n    ASSERT_EQ(parse_exact_double_from_string(\"0\"), 0);\n    ASSERT_EQ(parse_exact_double_from_string(\"1\"), 1);\n    ASSERT_EQ(parse_exact_double_from_string(\"+1\"), 1);\n    ASSERT_EQ(parse_exact_double_from_string(\"-1\"), -1);\n    ASSERT_EQ(parse_exact_double_from_string(\"1e3\"), 1000);\n    ASSERT_EQ(parse_exact_double_from_string(\"1.5\"), 1.5);\n    ASSERT_EQ(parse_exact_double_from_string(\"-1.5\"), -1.5);\n}\n\nTEST(arg_parse, parse_exact_uint64_t_from_string) {\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"a\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\" 1\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"\\t1\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"1 \"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"banana\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"1.2.3\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"INFINITY\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"inf\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"nan\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"1e3\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"1.5\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"-1\"); }, std::invalid_argument);\n    ASSERT_THROW({ parse_exact_uint64_t_from_string(\"18446744073709551616\"); }, std::invalid_argument);\n\n    ASSERT_EQ(parse_exact_uint64_t_from_string(\"0\"), 0);\n    ASSERT_EQ(parse_exact_uint64_t_from_string(\"1\"), 1);\n    ASSERT_EQ(parse_exact_uint64_t_from_string(\"+1\"), 1);\n    ASSERT_EQ(parse_exact_uint64_t_from_string(\"2\"), 2);\n    ASSERT_EQ(parse_exact_uint64_t_from_string(\"13\"), 13);\n    ASSERT_EQ(parse_exact_uint64_t_from_string(\"18446744073709551615\"), UINT64_MAX);\n}\n\nTEST(arg_parse, parse_int64) {\n    int64_t x = 0;\n\n    ASSERT_TRUE(parse_int64(\"+0\", &x));\n    ASSERT_EQ(x, 0);\n    ASSERT_TRUE(parse_int64(\"-0\", &x));\n    ASSERT_EQ(x, 0);\n    ASSERT_TRUE(parse_int64(\"0\", &x));\n    ASSERT_EQ(x, 0);\n    ASSERT_TRUE(parse_int64(\"1\", &x));\n    ASSERT_EQ(x, 1);\n    ASSERT_TRUE(parse_int64(\"-1\", &x));\n    ASSERT_EQ(x, -1);\n    ASSERT_FALSE(parse_int64(\"i\", &x));\n    ASSERT_FALSE(parse_int64(\"1i\", &x));\n    ASSERT_FALSE(parse_int64(\"i1\", &x));\n    ASSERT_FALSE(parse_int64(\"1e2\", &x));\n    ASSERT_FALSE(parse_int64(\"12i1\", &x));\n    ASSERT_FALSE(parse_int64(\"12 \", &x));\n    ASSERT_FALSE(parse_int64(\" 12\", &x));\n\n    ASSERT_TRUE(parse_int64(\"0123\", &x));\n    ASSERT_EQ(x, 123);\n    ASSERT_TRUE(parse_int64(\"-0123\", &x));\n    ASSERT_EQ(x, -123);\n\n    ASSERT_FALSE(parse_int64(\"-9223372036854775809\", &x));\n    ASSERT_TRUE(parse_int64(\"-9223372036854775808\", &x));\n    ASSERT_EQ(x, INT64_MIN);\n    ASSERT_FALSE(parse_int64(\"9223372036854775808\", &x));\n    ASSERT_TRUE(parse_int64(\"9223372036854775807\", &x));\n    ASSERT_EQ(x, INT64_MAX);\n}\n"
  },
  {
    "path": "src/stim/util_bot/error_decomp.cc",
    "content": "#include \"stim/util_bot/error_decomp.h\"\n\n#include <algorithm>\n#include <cmath>\n#include <stdexcept>\n#include <string>\n\nusing namespace stim;\n\nvoid stim::independent_to_disjoint_xyz_errors(\n    double x, double y, double z, double *out_x, double *out_y, double *out_z) {\n    if (x < 0 || y < 0 || z < 0 || x > 1 || y > 1 || z > 1) {\n        throw std::invalid_argument(\"x < 0 || y < 0 || z < 0 || x > 1 || y > 1 || z > 1\");\n    }\n    double ab = x * y;\n    double ac = x * z;\n    double bc = y * z;\n    double a_i = 1.0 - x;\n    double b_i = 1.0 - y;\n    double c_i = 1.0 - z;\n    double ab_i = a_i * b_i;\n    double ac_i = a_i * c_i;\n    double bc_i = b_i * c_i;\n    *out_x = x * bc_i + a_i * bc;\n    *out_y = y * ac_i + b_i * ac;\n    *out_z = z * ab_i + c_i * ab;\n}\n\nbool stim::try_disjoint_to_independent_xyz_errors_approx(\n    double x, double y, double z, double *out_x, double *out_y, double *out_z, size_t max_steps) {\n    if (x < 0 || y < 0 || z < 0 || x + y + z > 1) {\n        throw std::invalid_argument(\"x < 0 || y < 0 || z < 0 || x + y + z > 1\");\n    }\n\n    // Re-arrange the problem so identity is the most likely case.\n    double i = std::max(0.0, 1.0 - x - y - z);\n    if (i < x) {\n        auto result = try_disjoint_to_independent_xyz_errors_approx(i, z, y, out_x, out_y, out_z, max_steps);\n        *out_x = 1 - *out_x;\n        return result;\n    }\n    if (i < y) {\n        auto result = try_disjoint_to_independent_xyz_errors_approx(z, i, x, out_x, out_y, out_z, max_steps);\n        *out_y = 1 - *out_y;\n        return result;\n    }\n    if (i < z) {\n        auto result = try_disjoint_to_independent_xyz_errors_approx(y, x, i, out_x, out_y, out_z, max_steps);\n        *out_z = 1 - *out_z;\n        return result;\n    }\n\n    // Solve analytically if an exact solution exists.\n    if (x + z < 0.5 && x + y < 0.5 && y + z < 0.5) {\n        double s_xz = sqrt(1 - 2 * x - 2 * z);\n        double s_xy = sqrt(1 - 2 * x - 2 * y);\n        double s_yz = sqrt(1 - 2 * y - 2 * z);\n        double a = 0.5 - 0.5 * s_xz * s_xy / s_yz;\n        double b = 0.5 - 0.5 * s_xy * s_yz / s_xz;\n        double c = 0.5 - 0.5 * s_xz * s_yz / s_xy;\n        if (a >= 0 && b >= 0 && c >= 0) {\n            *out_x = a;\n            *out_y = b;\n            *out_z = c;\n            return true;\n        }\n    }\n\n    // If no exact solution exists, resort to approximations.\n    double a = x;\n    double b = y;\n    double c = z;\n    for (size_t step = 0; step < max_steps; step++) {\n        // Compute current error.\n        double ab = a * b;\n        double ac = a * c;\n        double bc = b * c;\n        double a_i = 1.0 - a;\n        double b_i = 1.0 - b;\n        double c_i = 1.0 - c;\n        double ab_i = a_i * b_i;\n        double ac_i = a_i * c_i;\n        double bc_i = b_i * c_i;\n        double x2 = a * bc_i + a_i * bc;\n        double y2 = b * ac_i + b_i * ac;\n        double z2 = c * ab_i + c_i * ab;\n        double dx = x2 - x;\n        double dy = y2 - y;\n        double dz = z2 - z;\n        double err = fabs(dx) + fabs(dy) + fabs(dz);\n        if (err < 1e-14) {\n            // Good enough.\n            *out_x = a;\n            *out_y = b;\n            *out_z = c;\n            return true;\n        }\n\n        // Make a Newton-Raphson step towards the solution.\n        double da = bc_i - bc;\n        double db = ac_i - ac;\n        double dc = ab_i - ac;\n        a -= dx / da;\n        b -= dy / db;\n        c -= dz / dc;\n        a = std::max(a, 0.0);\n        b = std::max(b, 0.0);\n        c = std::max(c, 0.0);\n    }\n    *out_x = a;\n    *out_y = b;\n    *out_z = c;\n    return false;\n}\n\ndouble stim::depolarize1_probability_to_independent_per_channel_probability(double p) {\n    if (p > 0.75) {\n        throw std::invalid_argument(\n            \"depolarize1_probability_to_independent_per_channel_probability with p>0.75; p=\" + std::to_string(p));\n    }\n    return 0.5 - 0.5 * sqrt(1 - (4 * p) / 3);\n}\n\ndouble stim::depolarize2_probability_to_independent_per_channel_probability(double p) {\n    if (p > 0.9375) {\n        throw std::invalid_argument(\n            \"depolarize2_probability_to_independent_per_channel_probability with p>15.0/16.0; p=\" + std::to_string(p));\n    }\n    return 0.5 - 0.5 * pow(1 - (16 * p) / 15, 0.125);\n}\n\ndouble stim::independent_per_channel_probability_to_depolarize1_probability(double p) {\n    double q = 1.0 - 2.0 * p;\n    q *= q;\n    return 3.0 / 4.0 * (1.0 - q);\n}\n\ndouble stim::independent_per_channel_probability_to_depolarize2_probability(double p) {\n    double q = 1.0 - 2.0 * p;\n    q *= q;\n    q *= q;\n    q *= q;\n    return 15.0 / 16.0 * (1.0 - q);\n}\n"
  },
  {
    "path": "src/stim/util_bot/error_decomp.h",
    "content": "#ifndef _STIM_UTIL_BOT_ERROR_DECOM_H\n#define _STIM_UTIL_BOT_ERROR_DECOM_H\n\n#include <cstddef>\n\nnamespace stim {\n\nvoid independent_to_disjoint_xyz_errors(double x, double y, double z, double *out_x, double *out_y, double *out_z);\nbool try_disjoint_to_independent_xyz_errors_approx(\n    double x, double y, double z, double *out_x, double *out_y, double *out_z, size_t max_steps = 50);\ndouble depolarize1_probability_to_independent_per_channel_probability(double p);\ndouble depolarize2_probability_to_independent_per_channel_probability(double p);\ndouble independent_per_channel_probability_to_depolarize1_probability(double p);\ndouble independent_per_channel_probability_to_depolarize2_probability(double p);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_bot/error_decomp.perf.cc",
    "content": "#include \"stim/util_bot/error_decomp.h\"\n\n#include <iostream>\n\n#include \"stim/perf.perf.h\"\n#include \"stim/util_bot/str_util.h\"\n\nusing namespace stim;\n\nBENCHMARK(disjoint_to_independent_xyz_errors_approx_exact) {\n    double w = 0;\n    benchmark_go([&]() {\n        double a;\n        double b;\n        double c;\n        try_disjoint_to_independent_xyz_errors_approx(0.1, 0.2, 0.15, &a, &b, &c);\n        w += a;\n        w += b;\n        w += c;\n    }).goal_nanos(11);\n    if (w == 0) {\n        std::cout << \"data dependence\";\n    }\n}\n\nBENCHMARK(disjoint_to_independent_xyz_errors_approx_p10) {\n    double w = 0;\n    benchmark_go([&]() {\n        double a;\n        double b;\n        double c;\n        try_disjoint_to_independent_xyz_errors_approx(0.1, 0.2, 0.0, &a, &b, &c);\n        w += a;\n        w += b;\n        w += c;\n    }).goal_nanos(550);\n    if (w == 0) {\n        std::cout << \"data dependence\";\n    }\n}\n\nBENCHMARK(disjoint_to_independent_xyz_errors_approx_p100) {\n    double w = 0;\n    benchmark_go([&]() {\n        double a;\n        double b;\n        double c;\n        try_disjoint_to_independent_xyz_errors_approx(0.01, 0.02, 0.0, &a, &b, &c);\n        w += a;\n        w += b;\n        w += c;\n    }).goal_nanos(550);\n    if (w == 0) {\n        std::cout << \"data dependence\";\n    }\n}\n\nBENCHMARK(independent_to_disjoint_xyz_errors) {\n    double w = 0;\n    benchmark_go([&]() {\n        double a;\n        double b;\n        double c;\n        independent_to_disjoint_xyz_errors(0.1, 0.2, 0.3, &a, &b, &c);\n        w += a;\n        w += b;\n        w += c;\n    }).goal_nanos(4);\n    if (w == 0) {\n        std::cout << \"data dependence\";\n    }\n}\n"
  },
  {
    "path": "src/stim/util_bot/error_decomp.test.cc",
    "content": "#include \"stim/util_bot/error_decomp.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(conversions, independent_to_disjoint_xyz_errors) {\n    double out_x;\n    double out_y;\n    double out_z;\n\n    independent_to_disjoint_xyz_errors(0.5, 0.5, 0.5, &out_x, &out_y, &out_z);\n    ASSERT_NEAR(out_x, 1 / 4.0, 1e-6);\n    ASSERT_NEAR(out_y, 1 / 4.0, 1e-6);\n    ASSERT_NEAR(out_z, 1 / 4.0, 1e-6);\n\n    independent_to_disjoint_xyz_errors(0.1, 0, 0, &out_x, &out_y, &out_z);\n    ASSERT_NEAR(out_x, 0.1, 1e-6);\n    ASSERT_NEAR(out_y, 0, 1e-6);\n    ASSERT_NEAR(out_z, 0, 1e-6);\n\n    independent_to_disjoint_xyz_errors(0, 0.2, 0, &out_x, &out_y, &out_z);\n    ASSERT_NEAR(out_x, 0, 1e-6);\n    ASSERT_NEAR(out_y, 0.2, 1e-6);\n    ASSERT_NEAR(out_z, 0, 1e-6);\n\n    independent_to_disjoint_xyz_errors(0, 0, 0.05, &out_x, &out_y, &out_z);\n    ASSERT_NEAR(out_x, 0, 1e-6);\n    ASSERT_NEAR(out_y, 0, 1e-6);\n    ASSERT_NEAR(out_z, 0.05, 1e-6);\n\n    independent_to_disjoint_xyz_errors(0.1, 0.1, 0, &out_x, &out_y, &out_z);\n    ASSERT_NEAR(out_x, 0.1 - 0.01, 1e-6);\n    ASSERT_NEAR(out_y, 0.1 - 0.01, 1e-6);\n    ASSERT_NEAR(out_z, 0.01, 1e-6);\n}\n\nTEST(conversions, disjoint_to_independent_xyz_errors_approx) {\n    double out_x;\n    double out_y;\n    double out_z;\n\n    ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(0.4, 0.0, 0.0, &out_x, &out_y, &out_z));\n    ASSERT_NEAR(out_x, 0.4, 1e-6);\n    ASSERT_NEAR(out_y, 0.0, 1e-6);\n    ASSERT_NEAR(out_z, 0.0, 1e-6);\n\n    ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(0.5, 0.0, 0.0, &out_x, &out_y, &out_z));\n    ASSERT_NEAR(out_x, 0.5, 1e-6);\n    ASSERT_NEAR(out_y, 0.0, 1e-6);\n    ASSERT_NEAR(out_z, 0.0, 1e-6);\n\n    ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(0.6, 0.0, 0.0, &out_x, &out_y, &out_z));\n    ASSERT_NEAR(out_x, 0.6, 1e-6);\n    ASSERT_NEAR(out_y, 0.0, 1e-6);\n    ASSERT_NEAR(out_z, 0.0, 1e-6);\n\n    ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(0.25, 0.25, 0.25, &out_x, &out_y, &out_z));\n    ASSERT_NEAR(out_x, 0.5, 1e-6);\n    ASSERT_NEAR(out_y, 0.5, 1e-6);\n    ASSERT_NEAR(out_z, 0.5, 1e-6);\n\n    ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(0.1, 0, 0, &out_x, &out_y, &out_z));\n    ASSERT_NEAR(out_x, 0.1, 1e-6);\n    ASSERT_NEAR(out_y, 0, 1e-6);\n    ASSERT_NEAR(out_z, 0, 1e-6);\n\n    ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(0, 0.2, 0, &out_x, &out_y, &out_z));\n    ASSERT_NEAR(out_x, 0, 1e-6);\n    ASSERT_NEAR(out_y, 0.2, 1e-6);\n    ASSERT_NEAR(out_z, 0, 1e-6);\n\n    ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(0, 0, 0.05, &out_x, &out_y, &out_z));\n    ASSERT_NEAR(out_x, 0, 1e-6);\n    ASSERT_NEAR(out_y, 0, 1e-6);\n    ASSERT_NEAR(out_z, 0.05, 1e-6);\n\n    ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(0.1 - 0.01, 0.1 - 0.01, 0.01, &out_x, &out_y, &out_z));\n    ASSERT_NEAR(out_x, 0.1, 1e-6);\n    ASSERT_NEAR(out_y, 0.1, 1e-6);\n    ASSERT_NEAR(out_z, 0, 1e-6);\n\n    ASSERT_FALSE(try_disjoint_to_independent_xyz_errors_approx(0.2, 0.2, 0, &out_x, &out_y, &out_z));\n    independent_to_disjoint_xyz_errors(out_x, out_y, out_z, &out_x, &out_y, &out_z);\n    ASSERT_NEAR(out_x, 0.2, 1e-6);\n    ASSERT_NEAR(out_y, 0.2, 1e-6);\n    ASSERT_LT(out_z, 0.08);\n\n    ASSERT_FALSE(try_disjoint_to_independent_xyz_errors_approx(0.2, 0.1, 0, &out_x, &out_y, &out_z));\n    independent_to_disjoint_xyz_errors(out_x, out_y, out_z, &out_x, &out_y, &out_z);\n    ASSERT_NEAR(out_x, 0.2, 1e-6);\n    ASSERT_NEAR(out_y, 0.1, 1e-6);\n    ASSERT_LT(out_z, 0.03);\n\n    ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(0.3 * 0.6, 0.4 * 0.7, 0.3 * 0.4, &out_x, &out_y, &out_z));\n    ASSERT_NEAR(out_x, 0.3, 1e-6);\n    ASSERT_NEAR(out_y, 0.4, 1e-6);\n    ASSERT_NEAR(out_z, 0.0, 1e-6);\n    independent_to_disjoint_xyz_errors(out_x, out_y, out_z, &out_x, &out_y, &out_z);\n    ASSERT_NEAR(out_x, 0.3 * 0.6, 1e-6);\n    ASSERT_NEAR(out_y, 0.4 * 0.7, 1e-6);\n    ASSERT_NEAR(out_z, 0.3 * 0.4, 1e-6);\n}\n\nTEST(conversions, fuzz_depolarize1_consistency) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    std::uniform_real_distribution<double> dis(0, 1);\n    for (size_t k = 0; k < 10; k++) {\n        double p = dis(rng) * 0.75;\n        double p2 = depolarize1_probability_to_independent_per_channel_probability(p);\n        double x2, y2, z2;\n        ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(p / 3, p / 3, p / 3, &x2, &y2, &z2));\n        ASSERT_NEAR(x2, p2, 1e-6) << \"p=\" << p;\n        ASSERT_NEAR(y2, p2, 1e-6) << \"p=\" << p;\n        ASSERT_NEAR(z2, p2, 1e-6) << \"p=\" << p;\n\n        double p3 = independent_per_channel_probability_to_depolarize1_probability(p2);\n        double x3, y3, z3;\n        independent_to_disjoint_xyz_errors(x2, y2, z2, &x3, &y3, &z3);\n        ASSERT_NEAR(x3, p / 3, 1e-6) << \"p=\" << p;\n        ASSERT_NEAR(y3, p / 3, 1e-6) << \"p=\" << p;\n        ASSERT_NEAR(z3, p / 3, 1e-6) << \"p=\" << p;\n        ASSERT_NEAR(p3, p, 1e-6) << \"p=\" << p;\n    }\n}\n\nTEST(conversions, fuzz_depolarize2_consistency) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    std::uniform_real_distribution<double> dis(0, 1);\n    for (size_t k = 0; k < 10; k++) {\n        double p = dis(rng) * 0.75;\n        double p2 = depolarize2_probability_to_independent_per_channel_probability(p);\n        double p3 = independent_per_channel_probability_to_depolarize2_probability(p2);\n        ASSERT_NEAR(p3, p, 1e-6) << \"p=\" << p;\n    }\n}\n\nTEST(conversions, independent_vs_disjoint_xyz_errors_round_trip_fuzz) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    std::uniform_real_distribution<double> dis(0, 1);\n    for (size_t k = 0; k < 25; k++) {\n        double x;\n        double y;\n        double z;\n        do {\n            x = dis(rng);\n            y = dis(rng);\n            z = dis(rng);\n        } while (x + y + z >= 0.999);\n        double x2, y2, z2;\n        independent_to_disjoint_xyz_errors(x, y, z, &x2, &y2, &z2);\n        double x3, y3, z3;\n        ASSERT_TRUE(try_disjoint_to_independent_xyz_errors_approx(x2, y2, z2, &x3, &y3, &z3));\n        ASSERT_NEAR(x, x3, 1e-6) << \"x=\" << x << \",y=\" << y << \",z=\" << z;\n        ASSERT_NEAR(y, y3, 1e-6) << \"x=\" << x << \",y=\" << y << \",z=\" << z;\n        ASSERT_NEAR(z, z3, 1e-6) << \"x=\" << x << \",y=\" << y << \",z=\" << z;\n    }\n}\n"
  },
  {
    "path": "src/stim/util_bot/probability_util.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_bot/probability_util.h\"\n\n#include <cstring>\n\n#include \"stim/util_bot/arg_parse.h\"\n\nusing namespace stim;\n\nRareErrorIterator::RareErrorIterator(float probability)\n    : next_candidate(0), is_one(probability == 1), dist(probability) {\n    if (!(probability >= 0 && probability <= 1)) {\n        throw std::out_of_range(\"Invalid probability: \" + std::to_string(probability));\n    }\n}\n\nsize_t RareErrorIterator::next(std::mt19937_64 &rng) {\n    size_t result = next_candidate + (is_one ? 0 : dist(rng));\n    next_candidate = result + 1;\n    return result;\n}\n\nstd::vector<size_t> stim::sample_hit_indices(float probability, size_t attempts, std::mt19937_64 &rng) {\n    std::vector<size_t> result;\n    RareErrorIterator::for_samples(probability, attempts, rng, [&](size_t s) {\n        result.push_back(s);\n    });\n    return result;\n}\n\nstd::mt19937_64 stim::externally_seeded_rng() {\n#if defined(__linux) && defined(__GLIBCXX__) && __GLIBCXX__ >= 20200128\n    // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94087\n    // See https://github.com/quantumlib/Stim/issues/26\n    std::random_device d(\"/dev/urandom\");\n#else\n    std::random_device d;\n#endif\n    std::seed_seq seq{d(), d(), d(), d(), d(), d(), d(), d()};\n    std::mt19937_64 result(seq);\n    return result;\n}\n\nstd::mt19937_64 stim::optionally_seeded_rng(int argc, const char **argv) {\n    if (find_argument(\"--seed\", argc, argv) == nullptr) {\n        return externally_seeded_rng();\n    }\n    uint64_t seed = (uint64_t)find_int64_argument(\"--seed\", 0, 0, INT64_MAX, argc, argv);\n    return std::mt19937_64(seed ^ INTENTIONAL_VERSION_SEED_INCOMPATIBILITY);\n}\n\nvoid stim::biased_randomize_bits(float probability, uint64_t *start, uint64_t *end, std::mt19937_64 &rng) {\n    if (probability > 0.5) {\n        // Recurse and invert for probabilities larger than 0.5.\n        biased_randomize_bits(1 - probability, start, end, rng);\n        while (start != end) {\n            *start ^= UINT64_MAX;\n            start++;\n        }\n    } else if (probability == 0.5) {\n        // For the 50/50 case, just copy the bits directly into the buffer.\n        while (start != end) {\n            *start = rng();\n            start++;\n        }\n    } else if (probability < 0.02) {\n        // For small probabilities, sample gaps using a geometric distribution.\n        size_t n = (end - start) << 6;\n        memset(start, 0, n >> 3);\n        RareErrorIterator::for_samples(probability, n, rng, [&](size_t s) {\n            start[s >> 6] |= uint64_t{1} << (s & 63);\n        });\n    } else {\n        // To generate a bit with probability p < 1, you can flip a coin until (after k flips) you\n        // get heads, and then return the k'th fractional bit in the binary representation of p.\n        //\n        // Alternatively, you can flip a coin at most N times until you either fail to get any heads\n        // or you get your first heads after k flips. If you got a heads, return the k'th fractional\n        // bit in the binary representation of p. Account for the leftover probability (from the\n        // bits that couldn't be reached due to clamping the coin flip count) by OR'ing with a low\n        // entropy bit that's been generated with just the right probability to fix the difference.\n        constexpr size_t COIN_FLIPS = 8;\n        constexpr float BUCKETS = (float)(1 << COIN_FLIPS);\n        float raised = probability * BUCKETS;\n        float raised_floor = floorf(raised);\n        float raised_leftover = raised - raised_floor;\n        float p_truncated = raised_floor / BUCKETS;\n        float p_leftover = raised_leftover / BUCKETS;\n        uint64_t p_top_bits = (uint64_t)raised_floor;\n\n        // Flip coins, using the position of the first HEADS result to\n        // select a bit from the probability's binary representation.\n        for (uint64_t *cur = start; cur != end; cur++) {\n            uint64_t alive = rng();\n            uint64_t result = 0;\n            for (size_t k_bit = COIN_FLIPS - 1; k_bit--;) {\n                uint64_t shoot = rng();\n                result ^= shoot & alive & -((p_top_bits >> k_bit) & 1);\n                alive &= ~shoot;\n            }\n            *cur = result;\n        }\n\n        // Correct distortion from truncation.\n        size_t n = (end - start) << 6;\n        RareErrorIterator::for_samples(p_leftover / (1 - p_truncated), n, rng, [&](size_t s) {\n            start[s >> 6] |= uint64_t{1} << (s & 63);\n        });\n    }\n}\n"
  },
  {
    "path": "src/stim/util_bot/probability_util.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_UTIL_BOT_PROBABILITY_UTIL_H\n#define _STIM_UTIL_BOT_PROBABILITY_UTIL_H\n\n#include <random>\n#include <stdexcept>\n#include <vector>\n\n#include \"stim/mem/span_ref.h\"\n\nnamespace stim {\n\n// Change this number from time to time to ensure people don't rely on seeds across versions.\nconstexpr uint64_t INTENTIONAL_VERSION_SEED_INCOMPATIBILITY = 0xDEADBEEF124CULL;\n\n/// Yields the indices of hits sampled from a Bernoulli distribution.\n/// Gets more efficient as the hit probability drops.\nstruct RareErrorIterator {\n    size_t next_candidate;\n    bool is_one = false;\n    std::geometric_distribution<size_t> dist;\n    RareErrorIterator(float probability);\n    size_t next(std::mt19937_64 &rng);\n\n    template <typename BODY>\n    inline static void for_samples(double p, size_t n, std::mt19937_64 &rng, BODY body) {\n        if (p == 0) {\n            return;\n        }\n        RareErrorIterator skipper((float)p);\n        while (true) {\n            size_t s = skipper.next(rng);\n            if (s >= n) {\n                break;\n            }\n            body(s);\n        }\n    }\n\n    template <typename BODY, typename T>\n    inline static void for_samples(double p, const SpanRef<const T> &vals, std::mt19937_64 &rng, BODY body) {\n        if (p == 0) {\n            return;\n        }\n        RareErrorIterator skipper((float)p);\n        while (true) {\n            size_t s = skipper.next(rng);\n            if (s >= vals.size()) {\n                break;\n            }\n            body(vals[s]);\n        }\n    }\n};\n\nstd::vector<size_t> sample_hit_indices(float probability, size_t attempts, std::mt19937_64 &rng);\n\n/// Create a fresh random number generator seeded by entropy from the operating system.\nstd::mt19937_64 externally_seeded_rng();\n\n/// Create a random number generator either seeded by a --seed argument, or else by entropy from the operating system.\nstd::mt19937_64 optionally_seeded_rng(int argc, const char **argv);\n\n/// Overwrite the given span with random data where bits are set with the given probability.\n///\n/// Args:\n///     probability: The chance that each bit will be on.\n///     start: Inclusive start of the memory span to overwrite.\n///     end: Exclusive end of the memory span to overwrite.\n///     rng: The random number generator to use to generate entropy.\nvoid biased_randomize_bits(float probability, uint64_t *start, uint64_t *end, std::mt19937_64 &rng);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_bot/probability_util.perf.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_bot/probability_util.h\"\n\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(biased_random_1024_0point1percent) {\n    std::mt19937_64 rng(0);\n    float p = 0.001;\n    size_t n = 1024;\n    simd_bits<MAX_BITWORD_WIDTH> data(n);\n    benchmark_go([&]() {\n        biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng);\n    })\n        .goal_nanos(70)\n        .show_rate(\"bits\", n);\n}\n\nBENCHMARK(biased_random_1024_0point01percent) {\n    std::mt19937_64 rng(0);\n    float p = 0.0001;\n    size_t n = 1024;\n    simd_bits<MAX_BITWORD_WIDTH> data(n);\n    benchmark_go([&]() {\n        biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng);\n    })\n        .goal_nanos(35)\n        .show_rate(\"bits\", n);\n}\n\nBENCHMARK(biased_random_1024_1percent) {\n    std::mt19937_64 rng(0);\n    float p = 0.01;\n    size_t n = 1024;\n    simd_bits<MAX_BITWORD_WIDTH> data(n);\n    benchmark_go([&]() {\n        biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng);\n    })\n        .goal_nanos(250)\n        .show_rate(\"bits\", n);\n}\n\nBENCHMARK(biased_random_1024_40percent) {\n    std::mt19937_64 rng(0);\n    float p = 0.4;\n    size_t n = 1024;\n    simd_bits<MAX_BITWORD_WIDTH> data(n);\n    benchmark_go([&]() {\n        biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng);\n    })\n        .goal_nanos(420)\n        .show_rate(\"bits\", n);\n}\n\nBENCHMARK(biased_random_1024_50percent) {\n    std::mt19937_64 rng(0);\n    float p = 0.5;\n    size_t n = 1024;\n    simd_bits<MAX_BITWORD_WIDTH> data(n);\n    benchmark_go([&]() {\n        biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng);\n    })\n        .goal_nanos(40)\n        .show_rate(\"bits\", n);\n}\n\nBENCHMARK(biased_random_1024_90percent) {\n    std::mt19937_64 rng(0);\n    float p = 0.9;\n    size_t n = 1024;\n    simd_bits<MAX_BITWORD_WIDTH> data(n);\n    benchmark_go([&]() {\n        biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng);\n    })\n        .goal_nanos(450)\n        .show_rate(\"bits\", n);\n}\n\nBENCHMARK(biased_random_1024_99percent) {\n    std::mt19937_64 rng(0);\n    float p = 0.99;\n    size_t n = 1024;\n    simd_bits<MAX_BITWORD_WIDTH> data(n);\n    benchmark_go([&]() {\n        biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng);\n    })\n        .goal_nanos(260)\n        .show_rate(\"bits\", n);\n}\n"
  },
  {
    "path": "src/stim/util_bot/probability_util.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_bot/probability_util.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(probability_util, sample_hit_indices_corner_cases) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    ASSERT_EQ(sample_hit_indices(0, 100000, rng), (std::vector<size_t>{}));\n    ASSERT_EQ(sample_hit_indices(1, 10, rng), (std::vector<size_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));\n}\n\nTEST(probability_util, sample_hit_indices) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    size_t num_buckets = 10000;\n    size_t num_samples = 100000;\n    double p = 0.001;\n    std::vector<size_t> buckets(num_buckets, 0);\n    for (size_t k = 0; k < num_samples; k++) {\n        for (auto bucket : sample_hit_indices(p, num_buckets, rng)) {\n            buckets[bucket] += 1;\n        }\n    }\n    size_t total = 0;\n    for (auto b : buckets) {\n        total += b;\n    }\n    ASSERT_TRUE(abs(total / (double)(num_buckets * num_samples) - p) <= 0.0001);\n    for (auto b : buckets) {\n        ASSERT_TRUE(abs(b / (double)num_samples - p) <= 0.01);\n    }\n}\n\nTEST_EACH_WORD_SIZE_W(probability_util, biased_random, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    std::vector<float> probs{0, 0.01, 0.03, 0.1, 0.4, 0.49, 0.5, 0.6, 0.9, 0.99, 0.999, 1};\n    simd_bits<W> data(1000000);\n    size_t n = data.num_bits_padded();\n    for (auto p : probs) {\n        biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng);\n        size_t t = 0;\n        for (size_t k = 0; k < data.num_u64_padded(); k++) {\n            t += std::popcount(data.u64[k]);\n        }\n        float dev = sqrtf(p * (1 - p) * n);\n        float min_expected = n * p - dev * 5;\n        float max_expected = n * p + dev * 5;\n        ASSERT_TRUE(min_expected >= 0 && max_expected <= n) << min_expected << \", \" << max_expected;\n        EXPECT_TRUE(min_expected <= t && t <= max_expected)\n            << min_expected / n << \" < \" << t / (float)n << \" < \" << max_expected / n << \" for p=\" << p;\n    }\n})\n"
  },
  {
    "path": "src/stim/util_bot/str_util.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_STR_UTIL_H\n#define _STIM_STR_UTIL_H\n\n#include <ostream>\n#include <sstream>\n#include <string>\n\nnamespace stim {\n/// Wraps an iterable object so that its values are printed with comma separators.\ntemplate <typename TIter>\nstruct CommaSep;\n\n/// A wrapper indicating a range of values should be printed with comma separators.\ntemplate <typename TIter>\nstruct CommaSep {\n    const TIter &iter;\n    const char *sep;\n    std::string str() const {\n        std::stringstream out;\n        out << *this;\n        return out.str();\n    }\n};\n\ntemplate <typename TIter>\nCommaSep<TIter> comma_sep(const TIter &v, const char *sep = \", \") {\n    return CommaSep<TIter>{v, sep};\n}\n\ntemplate <typename TIter>\nstd::ostream &operator<<(std::ostream &out, const CommaSep<TIter> &v) {\n    bool first = true;\n    for (const auto &t : v.iter) {\n        if (first) {\n            first = false;\n        } else {\n            out << v.sep;\n        }\n        out << t;\n    }\n    return out;\n}\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_bot/str_util.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_bot/str_util.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(str_util, comma_sep) {\n    std::vector<int> v{1, 2, 3};\n    std::stringstream out;\n    out << comma_sep(v);\n    ASSERT_EQ(out.str(), \"1, 2, 3\");\n    ASSERT_EQ(comma_sep(v).str(), \"1, 2, 3\");\n    ASSERT_EQ(comma_sep(std::vector<int>{}).str(), \"\");\n    ASSERT_EQ(comma_sep(std::vector<int>{4}).str(), \"4\");\n    ASSERT_EQ(comma_sep(std::vector<int>{5, 6}).str(), \"5, 6\");\n}\n"
  },
  {
    "path": "src/stim/util_bot/test_util.test.cc",
    "content": "#include \"stim/util_bot/test_util.test.h\"\n\n#include <filesystem>\n#include <fstream>\n\n#include \"stim/util_bot/probability_util.h\"\n\nusing namespace stim;\n\nstatic bool shared_test_rng_initialized;\nstatic std::mt19937_64 shared_test_rng;\n\nstd::string resolve_test_file(std::string_view name) {\n    std::vector<std::string> prefixes{\n        \"testdata/\",\n        \"../testdata/\",\n    };\n    for (const auto &prefix : prefixes) {\n        std::string full_path = prefix + std::string(name);\n        FILE *f = fopen(full_path.c_str(), \"rb\");\n        if (f != nullptr) {\n            fclose(f);\n            return full_path;\n        }\n    }\n    for (const auto &prefix : prefixes) {\n        std::string full_path = prefix + std::string(name);\n        FILE *f = fopen(full_path.c_str(), \"wb\");\n        if (f != nullptr) {\n            fclose(f);\n            return full_path;\n        }\n    }\n    throw std::invalid_argument(\"Run tests from the repo root so they can find the testdata/ directory.\");\n}\n\nvoid expect_string_is_identical_to_saved_file(std::string_view actual, std::string_view key) {\n    auto path = resolve_test_file(key);\n    FILE *f = fopen(path.c_str(), \"rb\");\n    auto expected = rewind_read_close(f);\n\n    if (expected != actual) {\n        auto dot = key.rfind('.');\n        std::string new_path;\n        if (dot == std::string::npos) {\n            new_path = path + \".new\";\n        } else {\n            dot += path.size() - key.size();\n            new_path = path.substr(0, dot) + \".new\" + path.substr(dot);\n        }\n        std::ofstream out;\n        out.open(new_path);\n        out << actual;\n        out.close();\n        EXPECT_TRUE(false) << \"Diagram didn't agree.\\n\"\n                           << \"    key=\" << key << \"\\n\"\n                           << \"    expected: file://\"\n                           << std::filesystem::weakly_canonical(std::filesystem::path(path)).c_str() << \"\\n\"\n                           << \"    actual: file://\"\n                           << std::filesystem::weakly_canonical(std::filesystem::path(new_path)).c_str() << \"\\n\";\n    }\n}\n\nstd::mt19937_64 INDEPENDENT_TEST_RNG() {\n    if (!shared_test_rng_initialized) {\n        shared_test_rng = externally_seeded_rng();\n        shared_test_rng_initialized = true;\n    }\n    std::seed_seq seq{shared_test_rng(), shared_test_rng(), shared_test_rng(), shared_test_rng()};\n    return std::mt19937_64(seq);\n}\n\nstd::string rewind_read_close(FILE *f) {\n    rewind(f);\n    std::string result;\n    while (true) {\n        int c = getc(f);\n        if (c == EOF) {\n            fclose(f);\n            return result;\n        }\n        result.push_back((char)c);\n    }\n}\n\nstatic void init_path(RaiiTempNamedFile &self) {\n    char tmp_stdin_filename[] = \"/tmp/stim_test_named_file_XXXXXX\";\n    self.descriptor = mkstemp(tmp_stdin_filename);\n    if (self.descriptor == -1) {\n        throw std::runtime_error(\"Failed to create temporary file.\");\n    }\n    self.path = std::string(tmp_stdin_filename);\n}\n\nRaiiTempNamedFile::RaiiTempNamedFile() {\n    init_path(*this);\n}\n\nRaiiTempNamedFile::RaiiTempNamedFile(std::string_view contents) {\n    init_path(*this);\n    write_contents(contents);\n}\n\nRaiiTempNamedFile::~RaiiTempNamedFile() {\n    if (!path.empty()) {\n        remove(path.c_str());\n        path = \"\";\n    }\n}\n\nstd::string RaiiTempNamedFile::read_contents() {\n    FILE *f = fopen(path.c_str(), \"rb\");\n    if (f == nullptr) {\n        throw std::runtime_error(\"Failed to open temp named file \" + path);\n    }\n    std::string result;\n    while (true) {\n        int c = getc(f);\n        if (c == EOF) {\n            break;\n        }\n        result.push_back(c);\n    }\n    fclose(f);\n    return result;\n}\n\nvoid RaiiTempNamedFile::write_contents(std::string_view contents) {\n    FILE *f = fopen(path.c_str(), \"wb\");\n    if (f == nullptr) {\n        throw std::runtime_error(\"Failed to open temp named file \" + path);\n    }\n    for (char c : contents) {\n        putc(c, f);\n    }\n    fclose(f);\n}\n"
  },
  {
    "path": "src/stim/util_bot/test_util.test.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_TEST_UTIL_TEST_H\n#define _STIM_TEST_UTIL_TEST_H\n\n#include <random>\n\n#include \"gtest/gtest.h\"\n\nstd::mt19937_64 INDEPENDENT_TEST_RNG();\n\nstd::string rewind_read_close(FILE *f);\n\nstd::string resolve_test_file(std::string_view name);\nvoid expect_string_is_identical_to_saved_file(std::string_view actual, std::string_view key);\n\nstruct RaiiTempNamedFile {\n    int descriptor;\n    std::string path;\n    RaiiTempNamedFile();\n    ~RaiiTempNamedFile();\n    RaiiTempNamedFile(std::string_view contents);\n    std::string read_contents();\n    void write_contents(std::string_view contents);\n};\n\n#endif\n"
  },
  {
    "path": "src/stim/util_bot/twiddle.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_UTIL_BOT_TWIDDLE_H\n#define _STIM_UTIL_BOT_TWIDDLE_H\n\n#include <bit>\n#include <cstddef>\n#include <cstdint>\n#include <stdexcept>\n\nnamespace stim {\n\ninline uint8_t is_power_of_2(size_t value) {\n    // Note: would use std::has_single_bit here, but as of March 2024 that method is missing when building with\n    // emscripten.\n    return std::popcount(value) == 1;\n}\n\ninline uint8_t floor_lg2(size_t value) {\n    return sizeof(value) * 8 - 1 - std::countl_zero(value);\n}\n\ninline size_t first_set_bit(size_t value, size_t min_result) {\n    value >>= min_result;\n    if (!value) {\n        throw std::invalid_argument(\"No matching set bit.\");\n    }\n    return std::countr_zero(value) + min_result;\n}\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_bot/twiddle.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_bot/twiddle.h\"\n\n#include <bit>\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(twiddle, is_power_of_2) {\n    ASSERT_EQ(is_power_of_2(0), 0);\n    ASSERT_EQ(is_power_of_2(1), 1);\n    ASSERT_EQ(is_power_of_2(2), 1);\n    ASSERT_EQ(is_power_of_2(3), 0);\n    ASSERT_EQ(is_power_of_2(4), 1);\n    ASSERT_EQ(is_power_of_2(5), 0);\n    ASSERT_EQ(is_power_of_2(6), 0);\n    ASSERT_EQ(is_power_of_2(7), 0);\n    ASSERT_EQ(is_power_of_2(8), 1);\n    ASSERT_EQ(is_power_of_2(9), 0);\n}\n\nTEST(twiddle, floor_lg2) {\n    ASSERT_EQ(floor_lg2(1), 0);\n    ASSERT_EQ(floor_lg2(2), 1);\n    ASSERT_EQ(floor_lg2(3), 1);\n    ASSERT_EQ(floor_lg2(4), 2);\n    ASSERT_EQ(floor_lg2(5), 2);\n    ASSERT_EQ(floor_lg2(6), 2);\n    ASSERT_EQ(floor_lg2(7), 2);\n    ASSERT_EQ(floor_lg2(8), 3);\n    ASSERT_EQ(floor_lg2(9), 3);\n}\n\nTEST(twiddle, first_set_bit) {\n    ASSERT_EQ(first_set_bit(0b0000111001000, 0), 3);\n    ASSERT_EQ(first_set_bit(0b0000111001000, 1), 3);\n    ASSERT_EQ(first_set_bit(0b0000111001000, 2), 3);\n    ASSERT_EQ(first_set_bit(0b0000111001000, 3), 3);\n    ASSERT_EQ(first_set_bit(0b0000111001000, 4), 6);\n    ASSERT_EQ(first_set_bit(0b0000111001000, 5), 6);\n    ASSERT_EQ(first_set_bit(0b0000111001000, 6), 6);\n    ASSERT_EQ(first_set_bit(0b0000111001000, 7), 7);\n    ASSERT_EQ(first_set_bit(0b0000111001000, 8), 8);\n\n    ASSERT_EQ(first_set_bit(0b0000111001001, 0), 0);\n    ASSERT_EQ(first_set_bit(1 << 20, 0), 20);\n}\n"
  },
  {
    "path": "src/stim/util_top/circuit_flow_generators.h",
    "content": "#ifndef _STIM_UTIL_TOP_CIRCUIT_FLOW_GENERATORS_H\n#define _STIM_UTIL_TOP_CIRCUIT_FLOW_GENERATORS_H\n\n#include <optional>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/mem/simd_bits.h\"\n\nnamespace stim {\n\n/// Finds a basis of flows for the circuit.\ntemplate <size_t W>\nstd::vector<Flow<W>> circuit_flow_generators(const Circuit &circuit);\n\n/// Finds measurements that explain each given flow for the circuit.\n///\n/// Args:\n///     flows: A list of flows to solve measurements for.\n///\n/// Returns:\n///     A list of results, one for each flow in the flows argument.\n///     When no solution exists for the circuit for a flow, its result is the empty optional.\n///     Otherwise a flow's result is a list of measurement indices.\ntemplate <size_t W>\nstd::vector<std::optional<std::vector<int32_t>>> solve_for_flow_measurements(\n    const Circuit &circuit, std::span<const Flow<W>> flows);\n\ntemplate <size_t W>\nstruct CircuitFlowGeneratorSolver {\n    std::vector<Flow<W>> table;\n    simd_bits<W> imag_bits;\n    size_t num_qubits;\n    size_t num_measurements;\n    size_t num_measurements_in_past;\n    std::vector<Flow<W>> measurements_only_table;\n    std::vector<size_t> buf_for_rows_with;\n    std::vector<int32_t> buf_for_xor_merge;\n    std::vector<GateTarget> buf_targets;\n    std::vector<GateTarget> buf_targets_2;\n\n    explicit CircuitFlowGeneratorSolver(CircuitStats stats);\n    static CircuitFlowGeneratorSolver<W> solver_with_circuit_generators(\n        const Circuit &circuit, uint32_t min_num_qubits);\n\n    Flow<W> &add_row();\n    void add_1q_measure_terms(CircuitInstruction inst, bool x, bool z);\n    void add_2q_measure_terms(CircuitInstruction inst, bool x, bool z);\n    void remove_single_qubit_reset_terms(CircuitInstruction inst);\n    void handle_anticommutations(std::span<const size_t> anticommutation_set);\n    void check_for_2q_anticommutations(CircuitInstruction inst, bool x, bool z);\n    void check_for_1q_anticommutations(CircuitInstruction inst, bool x, bool z);\n    void mult_row_into(size_t src_row, size_t dst_row);\n    void undo_mrb(CircuitInstruction inst, bool x, bool z);\n    void undo_mb(CircuitInstruction inst, bool x, bool z);\n    void undo_rb(CircuitInstruction inst, bool x, bool z);\n    void undo_2q_m(CircuitInstruction inst, bool x, bool z);\n    void undo_instruction(CircuitInstruction inst);\n    void elimination_step(std::span<const size_t> elimination_set, size_t &num_eliminated, size_t num_available_rows);\n    void eliminate_input_xz_terms(size_t &num_eliminated, size_t num_available_rows);\n    void eliminate_output_xz_terms(size_t &num_eliminated, size_t num_available_rows);\n    void eliminate_measurement_terms(size_t &num_eliminated, size_t num_available_rows);\n    void canonicalize_over_qubits(size_t num_available_rows);\n    void final_canonicalize_into_table();\n    void undo_feedback_capable_instruction(CircuitInstruction inst, bool x, bool z);\n    std::span<const size_t> rows_anticommuting_with(uint32_t q, bool x, bool z);\n\n    template <typename PREDICATE>\n    std::span<const size_t> rows_with(PREDICATE predicate);\n};\n\n}  // namespace stim\n\n#include \"stim/util_top/circuit_flow_generators.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/circuit_flow_generators.inl",
    "content": "#include \"stim/util_top/circuit_inverse_qec.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nCircuitFlowGeneratorSolver<W>::CircuitFlowGeneratorSolver(CircuitStats stats)\n    : table(),\n      imag_bits(stats.num_qubits),\n      num_qubits(stats.num_qubits),\n      num_measurements(stats.num_measurements),\n      num_measurements_in_past(stats.num_measurements),\n      measurements_only_table(),\n      buf_for_rows_with(),\n      buf_for_xor_merge() {\n    if (num_measurements_in_past > INT32_MAX) {\n        throw std::invalid_argument(\"Circuit is too large. Max flow measurement index is \" + std::to_string(INT32_MAX));\n    }\n}\n\ntemplate <size_t W>\nFlow<W> &CircuitFlowGeneratorSolver<W>::add_row() {\n    table.push_back(\n        Flow<W>{\n            .input = PauliString<W>(num_qubits),\n            .output = PauliString<W>(num_qubits),\n            .measurements = {},\n        });\n    return table.back();\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::add_1q_measure_terms(CircuitInstruction inst, bool x, bool z) {\n    for (size_t k = inst.targets.size(); k--;) {\n        num_measurements_in_past--;\n\n        auto t = inst.targets[k];\n        if (!t.is_qubit_target()) {\n            throw std::invalid_argument(\"Bad target in \" + inst.str());\n        }\n        uint32_t q = t.qubit_value();\n        auto &row = add_row();\n        row.measurements.push_back(num_measurements_in_past);\n        row.input.xs[q] = x;\n        row.input.zs[q] = z;\n        row.input.sign ^= t.is_inverted_result_target();\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::add_2q_measure_terms(CircuitInstruction inst, bool x, bool z) {\n    size_t k = inst.targets.size();\n    while (k > 0) {\n        k -= 2;\n        num_measurements_in_past--;\n\n        auto t1 = inst.targets[k];\n        auto t2 = inst.targets[k + 1];\n        if (!t1.is_qubit_target() || !t2.is_qubit_target()) {\n            throw std::invalid_argument(\"Bad target in \" + inst.str());\n        }\n        uint32_t q1 = t1.qubit_value();\n        uint32_t q2 = t2.qubit_value();\n        auto &row = add_row();\n        row.measurements.push_back(num_measurements_in_past);\n        row.input.xs[q1] = x;\n        row.input.zs[q1] = z;\n        row.input.xs[q2] = x;\n        row.input.zs[q2] = z;\n        row.input.sign ^= t1.is_inverted_result_target();\n        row.input.sign ^= t2.is_inverted_result_target();\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::remove_single_qubit_reset_terms(CircuitInstruction inst) {\n    for (auto t : inst.targets) {\n        if (!t.is_qubit_target()) {\n            throw std::invalid_argument(\"Bad target in \" + inst.str());\n        }\n        uint32_t q = t.qubit_value();\n        for (auto &row : table) {\n            row.input.xs[q] = 0;\n            row.input.zs[q] = 0;\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::handle_anticommutations(std::span<const size_t> anticommutation_set) {\n    if (anticommutation_set.empty()) {\n        return;\n    }\n\n    // Sacrifice the first anticommutation to save the others.\n    for (size_t k = 1; k < buf_for_rows_with.size(); k++) {\n        mult_row_into(anticommutation_set[0], anticommutation_set[k]);\n    }\n    table.erase(table.begin() + anticommutation_set[0]);\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::check_for_2q_anticommutations(CircuitInstruction inst, bool x, bool z) {\n    size_t k = inst.targets.size();\n    while (k > 0) {\n        k -= 2;\n\n        auto t1 = inst.targets[k];\n        auto t2 = inst.targets[k + 1];\n        if (!t1.is_qubit_target() || !t2.is_qubit_target()) {\n            throw std::invalid_argument(\"Bad target in \" + inst.str());\n        }\n        uint32_t q1 = t1.qubit_value();\n        uint32_t q2 = t2.qubit_value();\n\n        auto anticommutations = rows_with([&](const Flow<W> &flow) {\n            bool anticommutes = false;\n            anticommutes ^= flow.input.xs[q1] & z;\n            anticommutes ^= flow.input.zs[q1] & x;\n            anticommutes ^= flow.input.xs[q2] & z;\n            anticommutes ^= flow.input.zs[q2] & x;\n            return anticommutes;\n        });\n\n        handle_anticommutations(anticommutations);\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::check_for_1q_anticommutations(CircuitInstruction inst, bool x, bool z) {\n    for (auto t : inst.targets) {\n        if (!t.is_qubit_target()) {\n            throw std::invalid_argument(\"Bad target in \" + inst.str());\n        }\n        uint32_t q = t.qubit_value();\n\n        handle_anticommutations(rows_anticommuting_with(q, x, z));\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::mult_row_into(size_t src_row, size_t dst_row) {\n    auto &src = table[src_row];\n    auto &dst = table[dst_row];\n\n    // Combine the pauli strings.\n    uint8_t log_i = 0;\n    log_i += dst.input.ref().inplace_right_mul_returning_log_i_scalar(src.input);\n    log_i -= dst.output.ref().inplace_right_mul_returning_log_i_scalar(src.output);\n    if (log_i & 1) {\n        imag_bits[dst_row] ^= 1;\n    }\n    if (log_i & 2) {\n        dst.input.sign ^= 1;\n    }\n\n    // Xor-merge-sort the measurement indices.\n    buf_for_xor_merge.resize(std::max(buf_for_xor_merge.size(), dst.measurements.size() + src.measurements.size() + 1));\n    const int32_t *end = xor_merge_sort(\n        SpanRef<const int32_t>(dst.measurements), SpanRef<const int32_t>(src.measurements), buf_for_xor_merge.data());\n    size_t n = end - buf_for_xor_merge.data();\n    dst.measurements.resize(n);\n    if (n > 0) {\n        memcpy(dst.measurements.data(), buf_for_xor_merge.data(), n * sizeof(int32_t));\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::undo_mrb(CircuitInstruction inst, bool x, bool z) {\n    check_for_1q_anticommutations(inst, x, z);\n    remove_single_qubit_reset_terms(inst);\n    add_1q_measure_terms(inst, x, z);\n}\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::undo_mb(CircuitInstruction inst, bool x, bool z) {\n    check_for_1q_anticommutations(inst, x, z);\n    add_1q_measure_terms(inst, x, z);\n}\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::undo_rb(CircuitInstruction inst, bool x, bool z) {\n    check_for_1q_anticommutations(inst, x, z);\n    remove_single_qubit_reset_terms(inst);\n}\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::undo_2q_m(CircuitInstruction inst, bool x, bool z) {\n    check_for_2q_anticommutations(inst, x, z);\n    add_2q_measure_terms(inst, x, z);\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::undo_feedback_capable_instruction(CircuitInstruction inst, bool x, bool z) {\n    size_t k = inst.targets.size();\n    while (k > 0) {\n        k -= 2;\n\n        auto t1 = inst.targets[k];\n        auto t2 = inst.targets[k + 1];\n        bool m1 = t1.is_measurement_record_target();\n        bool m2 = t2.is_measurement_record_target();\n        bool f1 = t1.is_qubit_target();\n        bool f2 = t2.is_qubit_target();\n        if ((m1 && f2) || (m2 && f1)) {\n            uint32_t q = f1 ? t1.qubit_value() : t2.qubit_value();\n            int32_t t = (m1 ? t1.value() : t2.value()) + num_measurements_in_past;\n            if (t < 0) {\n                throw std::invalid_argument(\"Referred to measurement before start of time in \" + inst.str());\n            }\n            for (auto r : rows_anticommuting_with(q, x, z)) {\n                xor_item_into_sorted_vec(t, table[r].measurements);\n            }\n        } else if (f1 && f2) {\n            CircuitInstruction sub_inst = CircuitInstruction{inst.gate_type, {}, inst.targets.sub(k, k + 2), inst.tag};\n            for (auto &row : table) {\n                row.input.ref().undo_instruction(sub_inst);\n            }\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::undo_instruction(CircuitInstruction inst) {\n    if (table.size() > num_qubits * 3) {\n        canonicalize_over_qubits(table.size());\n    }\n\n    switch (inst.gate_type) {\n        case GateType::MRX:\n        case GateType::MRY:\n        case GateType::MR:\n            undo_mrb(inst, inst.gate_type != GateType::MR, inst.gate_type != GateType::MRX);\n            break;\n\n        case GateType::MX:\n        case GateType::MY:\n        case GateType::M:\n            undo_mb(inst, inst.gate_type != GateType::M, inst.gate_type != GateType::MX);\n            break;\n\n        case GateType::RX:\n        case GateType::RY:\n        case GateType::R:\n            undo_rb(inst, inst.gate_type != GateType::R, inst.gate_type != GateType::RX);\n            break;\n\n        case GateType::MXX:\n        case GateType::MYY:\n        case GateType::MZZ:\n            undo_2q_m(inst, inst.gate_type != GateType::MZZ, inst.gate_type != GateType::MXX);\n            break;\n\n        case GateType::DETECTOR:\n        case GateType::OBSERVABLE_INCLUDE:\n        case GateType::TICK:\n        case GateType::QUBIT_COORDS:\n        case GateType::SHIFT_COORDS:\n        case GateType::DEPOLARIZE1:\n        case GateType::DEPOLARIZE2:\n        case GateType::X_ERROR:\n        case GateType::Y_ERROR:\n        case GateType::Z_ERROR:\n        case GateType::PAULI_CHANNEL_1:\n        case GateType::PAULI_CHANNEL_2:\n        case GateType::E:\n        case GateType::ELSE_CORRELATED_ERROR:\n            // Ignored.\n            break;\n\n        case GateType::HERALDED_ERASE:\n        case GateType::HERALDED_PAULI_CHANNEL_1:\n            // Heralds.\n            for (auto t : inst.targets) {\n                num_measurements_in_past--;\n                if (!t.is_qubit_target()) {\n                    throw std::invalid_argument(\"Bad target in \" + inst.str());\n                }\n                auto &row = add_row();\n                row.measurements.push_back(num_measurements_in_past);\n            }\n            break;\n\n        case GateType::MPAD:\n            // Pads.\n            for (auto t : inst.targets) {\n                num_measurements_in_past--;\n                if (!t.is_qubit_target()) {\n                    throw std::invalid_argument(\"Bad target in \" + inst.str());\n                }\n                auto &row = add_row();\n                row.measurements.push_back(num_measurements_in_past);\n                if (t.qubit_value()) {\n                    row.output.sign = 1;\n                }\n            }\n            break;\n\n        case GateType::CX:\n        case GateType::XCZ:\n            undo_feedback_capable_instruction(inst, true, false);\n            break;\n\n        case GateType::YCZ:\n        case GateType::CY:\n            undo_feedback_capable_instruction(inst, true, true);\n            break;\n\n        case GateType::CZ:\n            undo_feedback_capable_instruction(inst, false, true);\n            break;\n\n        case GateType::XCX:\n        case GateType::XCY:\n        case GateType::YCX:\n        case GateType::YCY:\n        case GateType::H:\n        case GateType::H_XY:\n        case GateType::H_YZ:\n        case GateType::H_NXY:\n        case GateType::H_NXZ:\n        case GateType::H_NYZ:\n        case GateType::I:\n        case GateType::II:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n        case GateType::X:\n        case GateType::Y:\n        case GateType::Z:\n        case GateType::C_XYZ:\n        case GateType::C_NXYZ:\n        case GateType::C_XNYZ:\n        case GateType::C_XYNZ:\n        case GateType::C_ZYX:\n        case GateType::C_NZYX:\n        case GateType::C_ZNYX:\n        case GateType::C_ZYNX:\n        case GateType::SQRT_X:\n        case GateType::SQRT_X_DAG:\n        case GateType::SQRT_Y:\n        case GateType::SQRT_Y_DAG:\n        case GateType::S:\n        case GateType::S_DAG:\n        case GateType::SQRT_XX:\n        case GateType::SQRT_XX_DAG:\n        case GateType::SQRT_YY:\n        case GateType::SQRT_YY_DAG:\n        case GateType::SQRT_ZZ:\n        case GateType::SQRT_ZZ_DAG:\n        case GateType::SPP:\n        case GateType::SPP_DAG:\n        case GateType::SWAP:\n        case GateType::ISWAP:\n        case GateType::CXSWAP:\n        case GateType::SWAPCX:\n        case GateType::CZSWAP:\n        case GateType::ISWAP_DAG:\n            for (auto &row : table) {\n                row.input.ref().undo_instruction(inst);\n            }\n            break;\n\n        case GateType::MPP:\n            buf_targets.clear();\n            buf_targets.insert(buf_targets.end(), inst.targets.begin(), inst.targets.end());\n            std::reverse(buf_targets.begin(), buf_targets.end());\n            decompose_mpp_operation(\n                CircuitInstruction{inst.gate_type, {}, buf_targets, inst.tag},\n                num_qubits,\n                [&](CircuitInstruction sub_inst) {\n                    buf_targets_2.clear();\n                    buf_targets_2.insert(buf_targets_2.end(), sub_inst.targets.begin(), sub_inst.targets.end());\n                    if (sub_inst.gate_type == GateType::M) {\n                        std::reverse(buf_targets_2.begin(), buf_targets_2.end());\n                    }\n                    undo_instruction(CircuitInstruction{sub_inst.gate_type, sub_inst.args, buf_targets_2, sub_inst.tag});\n                });\n            break;\n\n        default:\n            throw std::invalid_argument(\"Not handled by circuit flow generators method: \" + inst.str());\n    }\n}\n\ntemplate <size_t W>\nstd::span<const size_t> CircuitFlowGeneratorSolver<W>::rows_anticommuting_with(uint32_t q, bool x, bool z) {\n    return rows_with([&](const Flow<W> &flow) {\n        bool anticommutes = false;\n        anticommutes ^= flow.input.xs[q] & z;\n        anticommutes ^= flow.input.zs[q] & x;\n        return anticommutes;\n    });\n}\n\ntemplate <size_t W>\ntemplate <typename PREDICATE>\nstd::span<const size_t> CircuitFlowGeneratorSolver<W>::rows_with(PREDICATE predicate) {\n    buf_for_rows_with.clear();\n    for (size_t r = 0; r < table.size(); r++) {\n        if (predicate(table[r])) {\n            buf_for_rows_with.push_back(r);\n        }\n    }\n    return buf_for_rows_with;\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::elimination_step(std::span<const size_t> elimination_set, size_t &num_eliminated, size_t num_available_rows) {\n    size_t pivot = SIZE_MAX;\n    for (auto p : elimination_set) {\n        if (p >= num_eliminated && p < num_available_rows) {\n            pivot = p;\n            break;\n        }\n    }\n    if (pivot == SIZE_MAX) {\n        return;\n    }\n\n    for (auto p : elimination_set) {\n        if (p != pivot) {\n            mult_row_into(pivot, p);\n        }\n    }\n    std::swap(table[pivot], table[num_eliminated]);\n    num_eliminated++;\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::canonicalize_over_qubits(size_t num_available_rows) {\n    size_t num_eliminated = 0;\n    for (size_t q = 0; q < num_qubits; q++) {\n        elimination_step(\n            rows_with([&](const Flow<W> &flow) {\n                return flow.input.xs[q];\n            }),\n            num_eliminated, num_available_rows);\n        elimination_step(\n            rows_with([&](const Flow<W> &flow) {\n                return flow.input.zs[q];\n            }),\n            num_eliminated, num_available_rows);\n        elimination_step(\n            rows_with([&](const Flow<W> &flow) {\n                return flow.output.xs[q];\n            }),\n            num_eliminated, num_available_rows);\n        elimination_step(\n            rows_with([&](const Flow<W> &flow) {\n                return flow.output.zs[q];\n            }),\n            num_eliminated, num_available_rows);\n    }\n\n    for (size_t r = 0; r < table.size(); r++) {\n        if (table[r].input.ref().has_no_pauli_terms() && table[r].output.ref().has_no_pauli_terms()) {\n            measurements_only_table.push_back(std::move(table[r]));\n            std::swap(table[r], table.back());\n            table.pop_back();\n            r--;\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::eliminate_input_xz_terms(size_t &num_eliminated, size_t num_available_rows) {\n    for (size_t q = 0; q < num_qubits; q++) {\n        elimination_step(\n            rows_with([&](const Flow<W> &flow) {\n                return flow.input.xs[q];\n            }),\n            num_eliminated, num_available_rows);\n        elimination_step(\n            rows_with([&](const Flow<W> &flow) {\n                return flow.input.zs[q];\n            }),\n            num_eliminated, num_available_rows);\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::eliminate_output_xz_terms(size_t &num_eliminated, size_t num_available_rows) {\n    for (size_t q = 0; q < num_qubits; q++) {\n        elimination_step(\n            rows_with([&](const Flow<W> &flow) {\n                return flow.output.xs[q];\n            }),\n            num_eliminated, num_available_rows);\n        elimination_step(\n            rows_with([&](const Flow<W> &flow) {\n                return flow.output.zs[q];\n            }),\n            num_eliminated, num_available_rows);\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::eliminate_measurement_terms(size_t &num_eliminated, size_t num_available_rows) {\n    for (size_t m = 0; m < num_measurements; m++) {\n        elimination_step(\n            rows_with([&](const Flow<W> &flow) {\n                return std::find(flow.measurements.begin(), flow.measurements.end(), (int32_t)m) !=\n                       flow.measurements.end();\n            }),\n            num_eliminated, num_available_rows);\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowGeneratorSolver<W>::final_canonicalize_into_table() {\n    for (auto &row : measurements_only_table) {\n        table.push_back(std::move(row));\n    }\n\n    size_t num_eliminated = 0;\n    eliminate_input_xz_terms(num_eliminated, table.size());\n    eliminate_output_xz_terms(num_eliminated, table.size());\n    eliminate_measurement_terms(num_eliminated, table.size());\n    for (auto &row : table) {\n        row.output.sign ^= row.input.sign;\n        row.input.sign = 0;\n        if (row.input.ref().has_no_pauli_terms()) {\n            row.input.xs.destructive_resize(0);\n            row.input.zs.destructive_resize(0);\n            row.input.num_qubits = 0;\n        }\n        if (row.output.ref().has_no_pauli_terms()) {\n            row.output.xs.destructive_resize(0);\n            row.output.zs.destructive_resize(0);\n            row.output.num_qubits = 0;\n        }\n    }\n\n    std::sort(table.begin(), table.end());\n}\n\ntemplate <size_t W>\nCircuitFlowGeneratorSolver<W> CircuitFlowGeneratorSolver<W>::solver_with_circuit_generators(const Circuit &circuit, uint32_t min_num_qubits) {\n    auto stats = circuit.compute_stats();\n    stats.num_qubits = std::max(stats.num_qubits, min_num_qubits);\n    CircuitFlowGeneratorSolver<W> solver(stats);\n    for (size_t q = 0; q < solver.num_qubits; q++) {\n        auto &x = solver.add_row();\n        x.output.xs[q] = 1;\n        x.input.xs[q] = 1;\n        auto &z = solver.add_row();\n        z.output.zs[q] = 1;\n        z.input.zs[q] = 1;\n    }\n    circuit.for_each_operation_reverse([&](CircuitInstruction inst) {\n        solver.undo_instruction(inst);\n    });\n    return solver;\n}\n\ntemplate <size_t W>\nstd::vector<Flow<W>> circuit_flow_generators(const Circuit &circuit) {\n    CircuitFlowGeneratorSolver<W> solver = CircuitFlowGeneratorSolver<W>::solver_with_circuit_generators(circuit, 0);\n    if (solver.imag_bits.not_zero()) {\n        throw std::invalid_argument(\"Unexpected anticommutation while solving for flow generators.\");\n    }\n    solver.final_canonicalize_into_table();\n    return solver.table;\n}\n\ntemplate <size_t W>\nstd::vector<std::optional<std::vector<int32_t>>> solve_for_flow_measurements(const Circuit &circuit, std::span<const Flow<W>> flows) {\n    size_t num_flow_qubits = 0;\n    for (const auto &flow : flows) {\n        num_flow_qubits = std::max(num_flow_qubits, flow.input.num_qubits);\n        num_flow_qubits = std::max(num_flow_qubits, flow.output.num_qubits);\n        if (flow.input.ref().has_no_pauli_terms() && flow.output.ref().has_no_pauli_terms()) {\n            throw std::invalid_argument(\n                \"Given a 1 -> 1 flow (empty input, empty output). \"\n                \"Only solving non-empty flows is supported by this method.\");\n        }\n    }\n\n    CircuitFlowGeneratorSolver<W> solver = CircuitFlowGeneratorSolver<W>::solver_with_circuit_generators(circuit, num_flow_qubits);\n\n    // Copy pauli terms from flows into the table.\n    size_t num_circuit_flows = solver.table.size();\n    for (size_t k = 0; k < flows.size(); k++) {\n        const auto &flow = flows[k];\n        auto &dst = solver.add_row();\n        dst.input.xs.word_range_ref(0, flow.input.xs.num_simd_words) = flow.input.xs;\n        dst.input.zs.word_range_ref(0, flow.input.zs.num_simd_words) = flow.input.zs;\n        dst.output.xs.word_range_ref(0, flow.output.xs.num_simd_words) = flow.output.xs;\n        dst.output.zs.word_range_ref(0, flow.output.zs.num_simd_words) = flow.output.zs;\n    }\n\n    // Eliminate the pauli terms.\n    size_t num_eliminated = 0;\n    solver.eliminate_input_xz_terms(num_eliminated, num_circuit_flows);\n    solver.eliminate_output_xz_terms(num_eliminated, num_circuit_flows);\n\n    // Greedily attempt to reduce measurement counts.\n    // This avoids bad scenarios like stability experiments putting the global measurement set into local flows.\n    for (size_t k = num_eliminated; k < num_circuit_flows; k++) {\n        if (solver.table[k].input.ref().has_no_pauli_terms() && solver.table[k].output.ref().has_no_pauli_terms()) {\n            const auto &src = solver.table[k].measurements;\n            for (size_t k2 = num_circuit_flows; k2 < solver.table.size(); k2++) {\n                auto &dst = solver.table[k2].measurements;\n                if (dst.size() >= src.size() * 2) {\n                    continue;\n                }\n\n                solver.buf_for_xor_merge.resize(std::max(solver.buf_for_xor_merge.size(), src.size() + dst.size() + 1));\n                const int32_t *end = xor_merge_sort(\n                    SpanRef<const int32_t>(dst),\n                    SpanRef<const int32_t>(src),\n                    solver.buf_for_xor_merge.data());\n                size_t n = end - solver.buf_for_xor_merge.data();\n                if (n < dst.size()) {\n                    memcpy(dst.data(), solver.buf_for_xor_merge.data(), n * sizeof(int32_t));\n                    dst.resize(n);\n                }\n            }\n        }\n    }\n\n    // Collect the measurements, checking the pauli terms were actually cleared.\n    std::vector<std::optional<std::vector<int32_t>>> result;\n    for (size_t k = 0; k < flows.size(); k++) {\n        Flow<W> &solved = solver.table[k + num_circuit_flows];\n        if (solver.imag_bits[k] || !solved.input.ref().has_no_pauli_terms() || !solved.output.ref().has_no_pauli_terms()) {\n            result.push_back(std::optional<std::vector<int32_t>>{});\n            continue;\n        }\n        result.emplace_back(std::move(solved.measurements));\n    }\n\n    return result;\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/util_top/circuit_flow_generators.test.cc",
    "content": "#include \"stim/util_top/circuit_flow_generators.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_top/circuit_inverse_qec.h\"\n#include \"stim/util_top/has_flow.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(circuit_flow_generators, various, {\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{}));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            X 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X -> X\"),\n            Flow<W>::from_str(\"Z -> -Z\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            H 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X -> Z\"),\n            Flow<W>::from_str(\"Z -> X\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            M 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> Z xor rec[0]\"),\n            Flow<W>::from_str(\"Z -> rec[0]\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            M 0 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> rec[0] xor rec[1]\"),\n            Flow<W>::from_str(\"1 -> Z xor rec[1]\"),\n            Flow<W>::from_str(\"Z -> rec[1]\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            MXX 2 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> X_X xor rec[0]\"),\n            Flow<W>::from_str(\"__X -> __X\"),\n            Flow<W>::from_str(\"_X_ -> _X_\"),\n            Flow<W>::from_str(\"_Z_ -> _Z_\"),\n            Flow<W>::from_str(\"X__ -> __X xor rec[0]\"),\n            Flow<W>::from_str(\"Z_Z -> Z_Z\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            MYY 3 1 2 3\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> __YY xor rec[1]\"),\n            Flow<W>::from_str(\"1 -> _Y_Y xor rec[0]\"),\n            Flow<W>::from_str(\"___Y -> ___Y\"),\n            Flow<W>::from_str(\"__Y_ -> ___Y xor rec[1]\"),\n            Flow<W>::from_str(\"_XZZ -> _ZZX xor rec[0]\"),\n            Flow<W>::from_str(\"_ZZZ -> _ZZZ\"),\n            Flow<W>::from_str(\"X___ -> X___\"),\n            Flow<W>::from_str(\"Z___ -> Z___\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            MZZ 3 1 2 3\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> __ZZ xor rec[1]\"),\n            Flow<W>::from_str(\"1 -> _Z_Z xor rec[0]\"),\n            Flow<W>::from_str(\"___Z -> ___Z\"),\n            Flow<W>::from_str(\"__Z_ -> ___Z xor rec[1]\"),\n            Flow<W>::from_str(\"_XXX -> _XXX\"),\n            Flow<W>::from_str(\"_Z__ -> ___Z xor rec[0]\"),\n            Flow<W>::from_str(\"X___ -> X___\"),\n            Flow<W>::from_str(\"Z___ -> Z___\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            ISWAP 3 1 2 3\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"___X -> _YZ_\"),\n            Flow<W>::from_str(\"___Z -> _Z__\"),\n            Flow<W>::from_str(\"__X_ -> __ZY\"),\n            Flow<W>::from_str(\"__Z_ -> ___Z\"),\n            Flow<W>::from_str(\"_X__ -> -_ZXZ\"),\n            Flow<W>::from_str(\"_Z__ -> __Z_\"),\n            Flow<W>::from_str(\"X___ -> X___\"),\n            Flow<W>::from_str(\"Z___ -> Z___\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            S 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X -> Y\"),\n            Flow<W>::from_str(\"Z -> Z\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            S_DAG 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X -> -Y\"),\n            Flow<W>::from_str(\"Z -> Z\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            SPP Z0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X -> Y\"),\n            Flow<W>::from_str(\"Z -> Z\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            SQRT_X 0\n            S 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X -> Y\"),\n            Flow<W>::from_str(\"Z -> X\"),\n        }));\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            SPP X0 Z0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X -> Y\"),\n            Flow<W>::from_str(\"Z -> X\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            SPP X0*X1\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"_X -> _X\"),\n            Flow<W>::from_str(\"_Z -> -XY\"),\n            Flow<W>::from_str(\"X_ -> X_\"),\n            Flow<W>::from_str(\"Z_ -> -YX\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            SPP_DAG Z0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X -> -Y\"),\n            Flow<W>::from_str(\"Z -> Z\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            M 0\n            CX rec[-1] 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> Z\"),\n            Flow<W>::from_str(\"Z -> rec[0]\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            R 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> Z\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            MR 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> Z\"),\n            Flow<W>::from_str(\"Z -> rec[0]\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            M 0\n            XCZ 0 rec[-1]\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> Z\"),\n            Flow<W>::from_str(\"Z -> rec[0]\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            MPAD 0 1 1 0\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> rec[0]\"),\n            Flow<W>::from_str(\"1 -> rec[3]\"),\n            Flow<W>::from_str(\"1 -> -rec[1]\"),\n            Flow<W>::from_str(\"1 -> -rec[2]\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            M 0\n            CY rec[-1] 1\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> Z_ xor rec[0]\"),\n            Flow<W>::from_str(\"_X -> _X xor rec[0]\"),\n            Flow<W>::from_str(\"_Z -> _Z xor rec[0]\"),\n            Flow<W>::from_str(\"Z_ -> rec[0]\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            HERALDED_ERASE(0.04) 1\n            HERALDED_PAULI_CHANNEL_1(0.01, 0.02, 0.03, 0.04) 1\n            TICK\n            MPP X0*Y1*Z2 Z0*Z1\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> rec[0]\"),\n            Flow<W>::from_str(\"1 -> rec[1]\"),\n            Flow<W>::from_str(\"1 -> XYZ xor rec[2]\"),\n            Flow<W>::from_str(\"1 -> ZZ_ xor rec[3]\"),\n            Flow<W>::from_str(\"__Z -> __Z\"),\n            Flow<W>::from_str(\"_ZX -> _ZX\"),\n            Flow<W>::from_str(\"XXX -> _ZY xor rec[2]\"),\n            Flow<W>::from_str(\"Z_X -> _ZX xor rec[3]\"),\n        }));\n\n    EXPECT_EQ(\n        circuit_flow_generators<W>(Circuit(R\"CIRCUIT(\n            MPP Y0*Y1 Y2*Y3\n        )CIRCUIT\")),\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> __YY xor rec[1]\"),\n            Flow<W>::from_str(\"1 -> YY__ xor rec[0]\"),\n            Flow<W>::from_str(\"___Y -> ___Y\"),\n            Flow<W>::from_str(\"__XZ -> __ZX xor rec[1]\"),\n            Flow<W>::from_str(\"__ZZ -> __ZZ\"),\n            Flow<W>::from_str(\"_Y__ -> _Y__\"),\n            Flow<W>::from_str(\"XZ__ -> ZX__ xor rec[0]\"),\n            Flow<W>::from_str(\"ZZ__ -> ZZ__\"),\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_flow_generators, all_operations, {\n    auto circuit = generate_test_circuit_with_all_operations();\n    auto generators = circuit_flow_generators<W>(circuit);\n    auto rng = externally_seeded_rng();\n    auto passes = sample_if_circuit_has_stabilizer_flows<W>(256, rng, circuit, generators);\n    for (size_t k = 0; k < passes.size(); k++) {\n        EXPECT_TRUE(passes[k]) << k << \": \" << generators[k];\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(solve_for_flow_measurements, empty, {\n    EXPECT_EQ(\n        solve_for_flow_measurements<W>(\n            Circuit(R\"CIRCUIT(\n            )CIRCUIT\"),\n            (std::vector<Flow<W>>{})),\n        (std::vector<std::optional<std::vector<int32_t>>>{}));\n})\n\nTEST_EACH_WORD_SIZE_W(solve_for_flow_measurements, simple, {\n    EXPECT_EQ(\n        solve_for_flow_measurements<W>(\n            Circuit(R\"CIRCUIT(\n                MX 0\n            )CIRCUIT\"),\n            (std::vector<Flow<W>>{\n                Flow<W>::from_str(\"1 -> X0\"),\n            })),\n        (std::vector<std::optional<std::vector<int32_t>>>{\n            {std::vector<int32_t>{0}},\n        }));\n\n    EXPECT_EQ(\n        solve_for_flow_measurements<W>(\n            Circuit(R\"CIRCUIT(\n                MX 0\n            )CIRCUIT\"),\n            (std::vector<Flow<W>>{\n                Flow<W>::from_str(\"1 -> Y0\"),\n            })),\n        (std::vector<std::optional<std::vector<int32_t>>>{\n            {},\n        }));\n\n    EXPECT_EQ(\n        solve_for_flow_measurements<W>(\n            Circuit(R\"CIRCUIT(\n                MX 0\n            )CIRCUIT\"),\n            (std::vector<Flow<W>>{\n                Flow<W>::from_str(\"1 -> X0\"),\n                Flow<W>::from_str(\"Y0 -> Y0\"),\n                Flow<W>::from_str(\"X0 -> 1\"),\n                Flow<W>::from_str(\"X0 -> Z0\"),\n                Flow<W>::from_str(\"Y1 -> Y1\"),\n            })),\n        (std::vector<std::optional<std::vector<int32_t>>>{\n            {std::vector<int32_t>{0}},\n            {},\n            {std::vector<int32_t>{0}},\n            {},\n            {std::vector<int32_t>{}},\n        }));\n\n    EXPECT_THROW(\n        { solve_for_flow_measurements<W>(Circuit(), (std::vector<Flow<W>>{Flow<W>::from_str(\"1 -> 1\")})); },\n        std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(solve_for_flow_measurements, rep_code, {\n    EXPECT_EQ(\n        solve_for_flow_measurements<W>(\n            Circuit(R\"CIRCUIT(\n                R 1 3\n                CX 0 1 2 3\n                CX 4 3 2 1\n                M 1 3\n            )CIRCUIT\"),\n            (std::vector<Flow<W>>{\n                Flow<W>::from_str(\"Z0*Z2 -> 1\"),\n                Flow<W>::from_str(\"1 -> Z2*Z4\"),\n                Flow<W>::from_str(\"1 -> Z0*Z4\"),\n                Flow<W>::from_str(\"Z0*Z4 -> Z0*Z2\"),\n                Flow<W>::from_str(\"Z0 -> Z0\"),\n                Flow<W>::from_str(\"Z0 -> Z1\"),\n                Flow<W>::from_str(\"Z0 -> Z2\"),\n                Flow<W>::from_str(\"X0*X2*X4 -> X0*X2*X4\"),\n                Flow<W>::from_str(\"X0 -> X0\"),\n                Flow<W>::from_str(\"X0 -> Z0\"),\n            })),\n        (std::vector<std::optional<std::vector<int32_t>>>{\n            {std::vector<int32_t>{0}},\n            {std::vector<int32_t>{1}},\n            {std::vector<int32_t>{0, 1}},\n            {std::vector<int32_t>{1}},\n            {std::vector<int32_t>{}},\n            {},\n            {std::vector<int32_t>{0}},\n            {std::vector<int32_t>{}},\n            {},\n            {},\n        }));\n})\n"
  },
  {
    "path": "src/stim/util_top/circuit_flow_generators_test.py",
    "content": "import stim\n\n\ndef test_solve_flow_measurements():\n    assert stim.Circuit(\"\"\"\n        M 2\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"X2 -> X2\"),\n    ]) == [None]\n\n    assert stim.Circuit(\"\"\"\n        M 2\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"X2 -> X2\"),\n        stim.Flow(\"Y2 -> Y2\"),\n        stim.Flow(\"Z2 -> Z2\"),\n        stim.Flow(\"Z2 -> 1\"),\n    ]) == [None, None, [], [0]]\n\n    assert stim.Circuit(\"\"\"\n        MXX 0 1\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"YY -> ZZ\"),\n        stim.Flow(\"YY -> YY\"),\n        stim.Flow(\"YZ -> ZY\"),\n    ]) == [[0], [], [0]]\n\n\ndef test_solve_flow_generators_measurements_multi_target():\n    assert stim.Circuit(\"\"\"\n        M 1 2\n    \"\"\").flow_generators() == [\n        stim.Flow(\"1 -> __Z xor rec[1]\"),\n        stim.Flow(\"1 -> _Z_ xor rec[0]\"),\n        stim.Flow(\"__Z -> rec[1]\"),\n        stim.Flow(\"_Z_ -> rec[0]\"),\n        stim.Flow(\"X__ -> X__\"),\n        stim.Flow(\"Z__ -> Z__\"),\n    ]\n\n    assert stim.Circuit(\"\"\"\n        MX 1 2\n    \"\"\").flow_generators() == [\n        stim.Flow(\"1 -> __X xor rec[1]\"),\n        stim.Flow(\"1 -> _X_ xor rec[0]\"),\n        stim.Flow(\"__X -> rec[1]\"),\n        stim.Flow(\"_X_ -> rec[0]\"),\n        stim.Flow(\"X__ -> X__\"),\n        stim.Flow(\"Z__ -> Z__\"),\n    ]\n\n    assert stim.Circuit(\"\"\"\n        MYY 1 2 3 4\n    \"\"\").flow_generators() == [\n        stim.Flow(\"1 -> ___YY xor rec[1]\"),\n        stim.Flow(\"1 -> _YY__ xor rec[0]\"),\n        stim.Flow(\"____Y -> ____Y\"),\n        stim.Flow(\"___XZ -> ___ZX xor rec[1]\"),\n        stim.Flow(\"___ZZ -> ___ZZ\"),\n        stim.Flow(\"__Y__ -> __Y__\"),\n        stim.Flow(\"_XZ__ -> _ZX__ xor rec[0]\"),\n        stim.Flow(\"_ZZ__ -> _ZZ__\"),\n        stim.Flow(\"X____ -> X____\"),\n        stim.Flow(\"Z____ -> Z____\"),\n    ]\n    assert stim.Circuit(\"\"\"\n        MPP Y1*Y2 Y3*Y4\n    \"\"\").flow_generators() == [\n        stim.Flow(\"1 -> ___YY xor rec[1]\"),\n        stim.Flow(\"1 -> _YY__ xor rec[0]\"),\n        stim.Flow(\"____Y -> ____Y\"),\n        stim.Flow(\"___XZ -> ___ZX xor rec[1]\"),\n        stim.Flow(\"___ZZ -> ___ZZ\"),\n        stim.Flow(\"__Y__ -> __Y__\"),\n        stim.Flow(\"_XZ__ -> _ZX__ xor rec[0]\"),\n        stim.Flow(\"_ZZ__ -> _ZZ__\"),\n        stim.Flow(\"X____ -> X____\"),\n        stim.Flow(\"Z____ -> Z____\"),\n    ]\n\n\ndef test_solve_flow_measurements_multi_target():\n    assert stim.Circuit(\"\"\"\n        M 1 2\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"Z1 -> 1\"),\n    ]) == [[0]]\n\n    assert stim.Circuit(\"\"\"\n        MX 1 2\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"X1 -> 1\"),\n    ]) == [[0]]\n\n    assert stim.Circuit(\"\"\"\n        MYY 1 2 3 4\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"Y1*Y2 -> 1\"),\n    ]) == [[0]]\n\n    assert stim.Circuit(\"\"\"\n        MPP Y1*Y2 Y3*Y4\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"Y1*Y2 -> 1\"),\n    ]) == [[0]]\n\n\ndef test_solve_flow_measurements_fewer_measurements_heuristic():\n    assert stim.Circuit(\"\"\"\n        MPP Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8\n        M 0 1 2 3 4 5 6 7 8\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"1 -> Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8\"),\n    ]) == [[0]]\n\n    assert stim.Circuit(\"\"\"\n        MPP Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8\n        M 0 1 2 3 4 5 6 7 8\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8 -> 1\"),\n    ]) == [[0]]\n\n    assert stim.Circuit(\"\"\"\n        M 0 1 2 3 4 5 6 7 8\n        MPP Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"1 -> Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8\"),\n    ]) == [[9]]\n\n    assert stim.Circuit(\"\"\"\n        M 0 1 2 3 4 5 6 7 8\n        MPP Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8\n    \"\"\").solve_flow_measurements([\n        stim.Flow(\"Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8 -> 1\"),\n    ]) == [[9]]\n"
  },
  {
    "path": "src/stim/util_top/circuit_inverse_qec.cc",
    "content": "#include \"stim/util_top/circuit_inverse_qec.h\"\n\nusing namespace stim;\nusing namespace stim::internal;\n\nCircuitFlowReverser::CircuitFlowReverser(CircuitStats stats, bool dont_turn_measurements_into_resets)\n    : stats(stats),\n      dont_turn_measurements_into_resets(dont_turn_measurements_into_resets),\n      rev(stats.num_qubits, stats.num_measurements, stats.num_detectors, true),\n      qubit_workspace(stats.num_qubits),\n      num_new_measurements(0) {\n}\n\nvoid CircuitFlowReverser::recompute_active_terms() {\n    active_terms.clear();\n    for (const auto &ds : rev.xs) {\n        for (const auto &t : ds) {\n            active_terms.insert(t);\n        }\n    }\n    for (const auto &ds : rev.zs) {\n        for (const auto &t : ds) {\n            active_terms.insert(t);\n        }\n    }\n    for (const auto &d : rev.rec_bits) {\n        for (const auto &e : d.second) {\n            active_terms.insert(e);\n        }\n    }\n}\n\nvoid CircuitFlowReverser::do_rp_mrp_instruction(const CircuitInstruction &inst) {\n    Gate g = GATE_DATA[inst.gate_type];\n    for_each_disjoint_target_segment_in_instruction_reversed(inst, qubit_workspace, [&](CircuitInstruction segment) {\n        // Each reset effect becomes a measurement effect in the inverted circuit. Index these\n        // measurements.\n        for (size_t k = inst.targets.size(); k-- > 0;) {\n            auto q = inst.targets[k].qubit_value();\n            for (auto d : rev.xs[q]) {\n                d2ms[d].insert(num_new_measurements);\n            }\n            for (auto d : rev.zs[q]) {\n                d2ms[d].insert(num_new_measurements);\n            }\n            num_new_measurements++;\n        }\n\n        // Undo the gate, ignoring measurement noise.\n        rev.undo_gate(segment);\n        inverted_circuit.safe_append_reversed_targets(\n            CircuitInstruction(g.best_candidate_inverse_id, {}, segment.targets, inst.tag), false);\n\n        // Measurement noise becomes noise-after-reset in the reversed circuit.\n        if (!inst.args.empty()) {\n            GateType ejected_noise;\n            if (inst.gate_type == GateType::MRX) {\n                ejected_noise = GateType::Z_ERROR;\n            } else if (inst.gate_type == GateType::MRY) {\n                ejected_noise = GateType::Z_ERROR;\n            } else if (inst.gate_type == GateType::MR) {\n                ejected_noise = GateType::X_ERROR;\n            } else {\n                throw std::invalid_argument(\"Don't know how to invert \" + inst.str());\n            }\n            inverted_circuit.safe_append_reversed_targets(\n                CircuitInstruction(ejected_noise, segment.args, segment.targets, inst.tag), false);\n        }\n    });\n}\n\nvoid CircuitFlowReverser::do_m2r_instruction(const CircuitInstruction &inst) {\n    // Figure out the type of reset each measurement might be turned into.\n    GateType reset;\n    if (inst.gate_type == GateType::MX) {\n        reset = GateType::RX;\n    } else if (inst.gate_type == GateType::MY) {\n        reset = GateType::RY;\n    } else if (inst.gate_type == GateType::M) {\n        reset = GateType::R;\n    } else {\n        throw std::invalid_argument(\"Don't know how to invert \" + inst.str());\n    }\n\n    Gate g = GATE_DATA[inst.gate_type];\n    for (size_t k = inst.targets.size(); k-- > 0;) {\n        GateTarget t = inst.targets[k];\n        auto q = t.qubit_value();\n        if (!dont_turn_measurements_into_resets && rev.xs[q].empty() && rev.zs[q].empty() &&\n            rev.rec_bits.contains(rev.num_measurements_in_past - 1) && inst.args.empty()) {\n            // Noiseless measurements with past-dependence and no future-dependence become resets.\n            inverted_circuit.safe_append(CircuitInstruction(reset, inst.args, &t, inst.tag));\n        } else {\n            // Measurements that aren't turned into resets need to be re-indexed.\n            auto f = rev.rec_bits.find(rev.num_measurements_in_past - 1);\n            if (f != rev.rec_bits.end()) {\n                for (auto &dem_target : f->second) {\n                    d2ms[dem_target].insert(num_new_measurements);\n                }\n            }\n            num_new_measurements++;\n            inverted_circuit.safe_append(CircuitInstruction(g.best_candidate_inverse_id, inst.args, &t, inst.tag));\n        }\n\n        rev.undo_gate(CircuitInstruction{g.id, {}, &t, inst.tag});\n    }\n}\n\nvoid CircuitFlowReverser::do_measuring_instruction(const CircuitInstruction &inst) {\n    Gate g = GATE_DATA[inst.gate_type];\n    auto m = inst.count_measurement_results();\n\n    // Re-index the measurements for the reversed detectors.\n    for (size_t k = 0; k < m; k++) {\n        auto f = rev.rec_bits.find(rev.num_measurements_in_past - k - 1);\n        if (f != rev.rec_bits.end()) {\n            for (auto &dem_target : f->second) {\n                d2ms[dem_target].insert(num_new_measurements);\n            }\n        }\n        num_new_measurements++;\n    }\n    inverted_circuit.safe_append_reversed_targets(\n        CircuitInstruction(g.best_candidate_inverse_id, inst.args, inst.targets, inst.tag),\n        g.flags & GATE_TARGETS_PAIRS);\n\n    rev.undo_gate(inst);\n}\n\nvoid CircuitFlowReverser::do_feedback_capable_instruction(const CircuitInstruction &inst) {\n    for (GateTarget t : inst.targets) {\n        if (t.is_measurement_record_target()) {\n            throw std::invalid_argument(\n                \"Time-reversing feedback isn't supported yet. Found feedback in: \" + inst.str());\n        }\n    }\n    do_simple_instruction(inst);\n}\n\nvoid CircuitFlowReverser::do_simple_instruction(const CircuitInstruction &inst) {\n    Gate g = GATE_DATA[inst.gate_type];\n    rev.undo_gate(inst);\n    inverted_circuit.safe_append_reversed_targets(\n        CircuitInstruction(g.best_candidate_inverse_id, inst.args, inst.targets, inst.tag),\n        g.flags & GATE_TARGETS_PAIRS);\n}\n\nvoid CircuitFlowReverser::flush_detectors_and_observables() {\n    recompute_active_terms();\n\n    terms_to_erase.clear();\n    for (auto d : d2ms) {\n        SpanRef<const double> out_args{};\n        GateType out_gate = GateType::DETECTOR;\n        double id = 0;\n\n        if (d.first.is_observable_id()) {\n            if (d.first.raw_id() >= stats.num_observables) {\n                continue;\n            }\n            id = d.first.raw_id();\n            out_args = &id;\n            out_gate = GateType::OBSERVABLE_INCLUDE;\n        } else if (active_terms.contains(d.first)) {\n            continue;\n        } else {\n            out_args = d2coords[d.first];\n        }\n        buf.clear();\n        for (auto e : d.second) {\n            buf.push_back(GateTarget::rec((int32_t)e - (int32_t)num_new_measurements));\n        }\n        inverted_circuit.safe_append(CircuitInstruction(out_gate, out_args, buf, d2tag[d.first]));\n        terms_to_erase.push_back(d.first);\n    }\n    for (auto e : terms_to_erase) {\n        d2coords.erase(e);\n        d2ms.erase(e);\n        d2tag.erase(e);\n    }\n}\n\nvoid CircuitFlowReverser::do_instruction(const CircuitInstruction &inst) {\n    switch (inst.gate_type) {\n        case GateType::DETECTOR: {\n            rev.undo_gate(inst);\n            d2tag[DemTarget::relative_detector_id(rev.num_detectors_in_past)] = inst.tag;\n            auto &v = d2coords[DemTarget::relative_detector_id(rev.num_detectors_in_past)];\n            for (size_t k = 0; k < inst.args.size(); k++) {\n                v.push_back(inst.args[k] + (k < coord_shifts.size() ? coord_shifts[k] : 0));\n            }\n            break;\n        }\n        case GateType::OBSERVABLE_INCLUDE: {\n            for (const auto &t : inst.targets) {\n                if (t.is_pauli_target()) {\n                    inverted_circuit.target_buf.append_tail(t);\n                }\n            }\n            if (inverted_circuit.target_buf.tail.empty()) {\n                d2tag[DemTarget::observable_id((uint64_t)inst.args[0])] = inst.tag;\n            } else {\n                inverted_circuit.operations.push_back(\n                    CircuitInstruction{\n                        GateType::OBSERVABLE_INCLUDE,\n                        inverted_circuit.arg_buf.take_copy(inst.args),\n                        inverted_circuit.target_buf.commit_tail(),\n                        inverted_circuit.tag_buf.take_copy(inst.tag),\n                    });\n            }\n            rev.undo_gate(inst);\n            break;\n        }\n        case GateType::TICK:\n        case GateType::I:\n        case GateType::II:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n        case GateType::X:\n        case GateType::Y:\n        case GateType::Z:\n        case GateType::C_XYZ:\n        case GateType::C_NXYZ:\n        case GateType::C_XNYZ:\n        case GateType::C_XYNZ:\n        case GateType::C_ZYX:\n        case GateType::C_NZYX:\n        case GateType::C_ZNYX:\n        case GateType::C_ZYNX:\n        case GateType::SQRT_X:\n        case GateType::SQRT_X_DAG:\n        case GateType::SQRT_Y:\n        case GateType::SQRT_Y_DAG:\n        case GateType::S:\n        case GateType::S_DAG:\n        case GateType::SQRT_XX:\n        case GateType::SQRT_XX_DAG:\n        case GateType::SQRT_YY:\n        case GateType::SQRT_YY_DAG:\n        case GateType::SQRT_ZZ:\n        case GateType::SQRT_ZZ_DAG:\n        case GateType::SPP:\n        case GateType::SPP_DAG:\n        case GateType::SWAP:\n        case GateType::ISWAP:\n        case GateType::CXSWAP:\n        case GateType::SWAPCX:\n        case GateType::CZSWAP:\n        case GateType::ISWAP_DAG:\n        case GateType::XCX:\n        case GateType::XCY:\n        case GateType::YCX:\n        case GateType::YCY:\n        case GateType::H:\n        case GateType::H_XY:\n        case GateType::H_YZ:\n        case GateType::H_NXZ:\n        case GateType::H_NXY:\n        case GateType::H_NYZ:\n        case GateType::DEPOLARIZE1:\n        case GateType::DEPOLARIZE2:\n        case GateType::X_ERROR:\n        case GateType::Y_ERROR:\n        case GateType::Z_ERROR:\n        case GateType::PAULI_CHANNEL_1:\n        case GateType::PAULI_CHANNEL_2:\n        case GateType::E:\n        case GateType::HERALDED_ERASE:\n        case GateType::HERALDED_PAULI_CHANNEL_1:\n            do_simple_instruction(inst);\n            return;\n        case GateType::XCZ:\n        case GateType::YCZ:\n        case GateType::CX:\n        case GateType::CY:\n        case GateType::CZ:\n            do_feedback_capable_instruction(inst);\n            break;\n        case GateType::MRX:\n        case GateType::MRY:\n        case GateType::MR:\n        case GateType::RX:\n        case GateType::RY:\n        case GateType::R:\n            do_rp_mrp_instruction(inst);\n            flush_detectors_and_observables();\n            break;\n\n        case GateType::MX:\n        case GateType::MY:\n        case GateType::M:\n            do_m2r_instruction(inst);\n            flush_detectors_and_observables();\n            break;\n\n        case GateType::MPAD:\n        case GateType::MPP:\n        case GateType::MXX:\n        case GateType::MYY:\n        case GateType::MZZ:\n            do_measuring_instruction(inst);\n            flush_detectors_and_observables();\n            break;\n\n        case GateType::QUBIT_COORDS:\n            for (size_t k = 0; k < inst.args.size(); k++) {\n                qubit_coords_circuit.arg_buf.append_tail(\n                    inst.args[k] + (k < coord_shifts.size() ? coord_shifts[k] : 0));\n            }\n            qubit_coords_circuit.operations.push_back(\n                CircuitInstruction{\n                    inst.gate_type,\n                    qubit_coords_circuit.arg_buf.commit_tail(),\n                    qubit_coords_circuit.target_buf.take_copy(inst.targets),\n                    inst.tag,\n                });\n            break;\n        case GateType::SHIFT_COORDS:\n            vec_pad_add_mul(coord_shifts, inst.args);\n            break;\n        case GateType::ELSE_CORRELATED_ERROR:\n        default:\n            throw std::invalid_argument(\"Don't know how to invert \" + inst.str());\n    }\n}\n\nCircuit &&CircuitFlowReverser::build_and_move_final_inverted_circuit() {\n    if (qubit_coords_circuit.operations.empty()) {\n        return std::move(inverted_circuit);\n    }\n\n    std::reverse(qubit_coords_circuit.operations.begin(), qubit_coords_circuit.operations.end());\n    qubit_coords_circuit += inverted_circuit;\n    return std::move(qubit_coords_circuit);\n}\n"
  },
  {
    "path": "src/stim/util_top/circuit_inverse_qec.h",
    "content": "#ifndef _STIM_UTIL_TOP_CIRCUIT_INVERSE_QEC_H\n#define _STIM_UTIL_TOP_CIRCUIT_INVERSE_QEC_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/simulators/sparse_rev_frame_tracker.h\"\n#include \"stim/stabilizers/flow.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nstd::pair<Circuit, std::vector<Flow<W>>> circuit_inverse_qec(\n    const Circuit &circuit, std::span<const Flow<W>> flows, bool dont_turn_measurements_into_resets = false);\n\nnamespace internal {\n\nstruct CircuitFlowReverser {\n    CircuitStats stats;\n    bool dont_turn_measurements_into_resets;\n\n    SparseUnsignedRevFrameTracker rev;\n    simd_bits<64> qubit_workspace;\n    size_t num_new_measurements;\n\n    Circuit inverted_circuit;\n    std::map<DemTarget, std::string_view> d2tag;\n    std::map<DemTarget, std::vector<double>> d2coords;\n    std::vector<double> coord_buf;\n    std::vector<double> coord_shifts;\n    Circuit qubit_coords_circuit;\n    std::vector<GateTarget> buf;\n    std::map<DemTarget, std::set<size_t>> d2ms;\n    std::set<DemTarget> active_terms;\n    std::vector<DemTarget> terms_to_erase;\n\n    CircuitFlowReverser(CircuitStats stats, bool dont_turn_measurements_into_resets);\n\n    void recompute_active_terms();\n    void do_rp_mrp_instruction(const CircuitInstruction &inst);\n    void do_m2r_instruction(const CircuitInstruction &inst);\n    void do_measuring_instruction(const CircuitInstruction &inst);\n    void do_simple_instruction(const CircuitInstruction &inst);\n    void do_feedback_capable_instruction(const CircuitInstruction &inst);\n    void flush_detectors_and_observables();\n\n    void do_instruction(const CircuitInstruction &inst);\n\n    template <size_t W>\n    void xor_pauli_string_into_tracker_as_target(const PauliString<W> &pauli_string, DemTarget target);\n\n    template <size_t W>\n    void xor_flow_ends_into_tracker(std::span<const Flow<W>> flows);\n\n    template <size_t W>\n    void xor_flow_measurements_into_tracker(std::span<const Flow<W>> flows);\n\n    template <size_t W>\n    void xor_flow_starts_into_tracker(std::span<const Flow<W>> flows);\n\n    template <size_t W>\n    void verify_flow_observables_disappeared(std::span<const Flow<W>> flows);\n\n    template <size_t W>\n    std::vector<Flow<W>> build_inverted_flows(std::span<const Flow<W>> flows);\n\n    Circuit &&build_and_move_final_inverted_circuit();\n};\n\n}  // namespace internal\n}  // namespace stim\n\n#include \"stim/util_top/circuit_inverse_qec.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/circuit_inverse_qec.inl",
    "content": "#include \"stim/stabilizers/flow.h\"\n#include \"stim/util_top/circuit_inverse_qec.h\"\n\nnamespace stim {\n\nnamespace internal {\ntemplate <size_t W>\nvoid CircuitFlowReverser::xor_pauli_string_into_tracker_as_target(\n    const PauliString<W> &pauli_string, DemTarget target) {\n    pauli_string.ref().for_each_active_pauli([&](size_t q) {\n        bool x = pauli_string.xs[q];\n        bool z = pauli_string.zs[q];\n        if (x) {\n            rev.xs[q].xor_item(target);\n        }\n        if (z) {\n            rev.zs[q].xor_item(target);\n        }\n    });\n}\n\ntemplate <size_t W>\nvoid CircuitFlowReverser::xor_flow_ends_into_tracker(std::span<const Flow<W>> flows) {\n    for (size_t k = 0; k < flows.size(); k++) {\n        const auto &flow = flows[k];\n        DemTarget flow_target = DemTarget::observable_id(stats.num_observables + k);\n        xor_pauli_string_into_tracker_as_target(flow.output, flow_target);\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowReverser::xor_flow_measurements_into_tracker(std::span<const Flow<W>> flows) {\n    for (size_t k = 0; k < flows.size(); k++) {\n        const auto &flow = flows[k];\n        DemTarget flow_target = DemTarget::observable_id(stats.num_observables + k);\n\n        for (int32_t m : flow.measurements) {\n            if (m < 0) {\n                m += stats.num_measurements;\n            }\n            if (m < 0 || (uint64_t)m >= stats.num_measurements) {\n                std::stringstream ss;\n                ss << \"Out of range measurement in one of the flows: \" << flow;\n                throw std::invalid_argument(ss.str());\n            }\n            rev.rec_bits[m].sorted_items.push_back(flow_target);\n        }\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowReverser::xor_flow_starts_into_tracker(std::span<const Flow<W>> flows) {\n    for (size_t k = 0; k < flows.size(); k++) {\n        const auto &flow = flows[k];\n        DemTarget flow_target = DemTarget::observable_id(stats.num_observables + k);\n        xor_pauli_string_into_tracker_as_target(flow.input, flow_target);\n    }\n}\n\ntemplate <size_t W>\nvoid CircuitFlowReverser::verify_flow_observables_disappeared(std::span<const Flow<W>> flows) {\n    bool failed = false;\n    DemTarget example{};\n    for (size_t q = 0; q < stats.num_qubits; q++) {\n        for (auto &e : rev.xs[q]) {\n            failed = true;\n            example = e;\n        }\n        for (auto &e : rev.zs[q]) {\n            failed = true;\n            example = e;\n        }\n    }\n    if (failed) {\n        if (example.is_relative_detector_id() ||\n            (example.is_observable_id() && example.raw_id() < stats.num_observables)) {\n            std::stringstream ss;\n            ss << \"The detecting region of \" << example << \" reached the start of the circuit.\\n\";\n            ss << \"Only flows given as arguments are permitted to touch the start or end of the circuit.\\n\";\n            ss << \"There are four potential ways to fix this issue, depending on what's wrong:\\n\";\n            ss << \"- If \" + example.str() +\n                      \" was relying on implicit initialization into |0> at the start of the circuit, add explicit \"\n                      \"resets to the circuit.\\n\";\n            ss << \"- If \" + example.str() + \" shouldn't be reaching the start of the circuit, fix its declaration.\\n\";\n            ss << \"- If \" + example.str() + \" isn't needed, delete it from the circuit.\\n\";\n            ss << \"- If the given circuit is a partial circuit, and \" << example\n               << \" is reaching outside of it, refactor \" << example << \"into a flow argument.\";\n            throw std::invalid_argument(ss.str());\n        } else {\n            std::stringstream ss;\n            const auto &flow = flows[example.raw_id() - stats.num_observables];\n            ss << \"The circuit didn't satisfy one of the given flows (ignoring sign): \";\n            ss << flow;\n            auto v = rev.current_error_sensitivity_for<W>(example);\n            v.xs ^= flow.input.xs;\n            v.zs ^= flow.input.zs;\n            ss << \"\\nChanging the flow to '\"\n               << Flow<W>{.input = v, .output = flow.output, .measurements = flow.measurements}\n               << \"' would make it a valid flow.\";\n            throw std::invalid_argument(ss.str());\n        }\n    }\n}\n\ntemplate <size_t W>\nstd::vector<Flow<W>> CircuitFlowReverser::build_inverted_flows(std::span<const Flow<W>> flows) {\n    std::vector<Flow<W>> inverted_flows;\n    for (size_t k = 0; k < flows.size(); k++) {\n        const auto &f = flows[k];\n        inverted_flows.push_back(\n            Flow<W>{\n                .input = f.output,\n                .output = f.input,\n                .measurements = {},\n            });\n        auto &f2 = inverted_flows.back();\n        f2.input.sign = false;\n        f2.output.sign = false;\n        for (auto &m : d2ms[DemTarget::observable_id(k + stats.num_observables)]) {\n            f2.measurements.push_back((int32_t)m - (int32_t)num_new_measurements);\n        }\n    }\n    return inverted_flows;\n}\n}  // namespace internal\n\ntemplate <size_t W>\nstd::pair<Circuit, std::vector<Flow<W>>> circuit_inverse_qec(\n    const Circuit &circuit, std::span<const Flow<W>> flows, bool dont_turn_measurements_into_resets) {\n    size_t max_flow_qubit = 0;\n    for (const auto &flow : flows) {\n        max_flow_qubit = std::max(max_flow_qubit, flow.input.num_qubits);\n        max_flow_qubit = std::max(max_flow_qubit, flow.output.num_qubits);\n    }\n    if (max_flow_qubit >= UINT32_MAX) {\n        throw std::invalid_argument(\"Flow qubit is too large. Not supported.\");\n    }\n\n    CircuitStats stats = circuit.compute_stats();\n    stats.num_qubits = std::max(stats.num_qubits, (uint32_t)max_flow_qubit + 1);\n    internal::CircuitFlowReverser reverser(stats, dont_turn_measurements_into_resets);\n\n    reverser.xor_flow_ends_into_tracker(flows);\n    reverser.xor_flow_measurements_into_tracker(flows);\n    circuit.for_each_operation_reverse([&](const CircuitInstruction &inst) {\n        reverser.do_instruction(inst);\n    });\n    reverser.xor_flow_starts_into_tracker(flows);\n    reverser.verify_flow_observables_disappeared(flows);\n\n    auto inverted_flows = reverser.build_inverted_flows(flows);\n    Circuit inverted_circuit = reverser.build_and_move_final_inverted_circuit();\n    return {inverted_circuit, inverted_flows};\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/util_top/circuit_inverse_qec.test.cc",
    "content": "#include \"stim/util_top/circuit_inverse_qec.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_top/circuit_to_detecting_regions.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, unitary, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        H 0\n        ISWAP 0 1 1 2 3 2\n        S 0 3 4\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        S_DAG 4 3 0\n        ISWAP_DAG 3 2 1 2 0 1\n        H 0\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, r_m_det, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        R 0\n        M 0\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        R 0\n        M 0\n        DETECTOR rec[-1]\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, r_m_det_keep_m, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        R 0\n        M 0\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        {},\n        true);\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        M 0\n        M 0\n        DETECTOR rec[-2] rec[-1]\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, two_to_one, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        R 0 1\n        CX 0 1\n        M 0 1\n        DETECTOR rec[-1] rec[-2]\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        R 1 0\n        CX 0 1\n        M 1 0\n        DETECTOR rec[-2]\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, pass_through, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        R 0\n        M 0\n        MR 0\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        MR 0\n        M 0\n        M 0\n        DETECTOR rec[-1]\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, anticommute, {\n    ASSERT_THROW(\n        {\n            circuit_inverse_qec<W>(\n                Circuit(R\"CIRCUIT(\n            R 0\n            MX 0\n            MR 0\n            DETECTOR rec[-1]\n        )CIRCUIT\"),\n                {});\n        },\n        std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, noisy_mr, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        MR(0.125) 0 1 2 0 2 4\n        MRX(0.25) 0\n        MRY(0.375) 0\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        MRY 0\n        Z_ERROR(0.375) 0\n        MRX 0\n        Z_ERROR(0.25) 0\n        MR 4 2 0\n        X_ERROR(0.125) 4 2 0\n        MR 2 1 0\n        X_ERROR(0.125) 2 1 0\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, noisy_m, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        M(0.125) 0 1 2 0 2 4\n        MX(0.25) 0\n        MY(0.375) 0\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        MY(0.375) 0\n        MX(0.25) 0\n        M(0.125) 4 2 0 2 1 0\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, noisy_mr_det, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        MR(0.125) 0\n        TICK\n        MR(0.25) 0\n        MR(0.375) 0\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        MR 0\n        X_ERROR(0.375) 0\n        MR 0\n        X_ERROR(0.25) 0\n        DETECTOR rec[-1]\n        TICK\n        MR 0\n        X_ERROR(0.125) 0\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, m_det, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        R 0 1 2\n        TICK\n        M 0 1 2\n        TICK\n        M 0 1 2\n        DETECTOR(2) rec[-1]\n        DETECTOR(1) rec[-2]\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        R 2 1\n        M 0\n        TICK\n        M 2 1 0\n        TICK\n        M 2 1 0\n        DETECTOR(2) rec[-3]\n        DETECTOR(1) rec[-2]\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, mzz, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        MRY 0 1\n        M 0\n        TICK\n        MZZ(0.125) 0 1 2 3\n        TICK\n        M 1\n        MRY 0 1\n        DETECTOR rec[-3] rec[-5] rec[-6]\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        MRY 1 0\n        R 1\n        TICK\n        MZZ(0.125) 2 3 0 1\n        TICK\n        M 0\n        DETECTOR rec[-2] rec[-1]\n        MRY 1 0\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, mpp, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        MPP !X0*X1 Y0*Y1 Z0*Z1\n        DETECTOR rec[-1] rec[-2] rec[-3]\n    )CIRCUIT\"),\n        {});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        MPP Z1*Z0 Y1*Y0 X1*!X0\n        DETECTOR rec[-3] rec[-2] rec[-1]\n    )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, flow_reverse, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        M 0\n    )CIRCUIT\"),\n        {std::vector<Flow<W>>{Flow<W>::from_str(\"1 -> Z0 xor rec[-1]\")}});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        M 0\n    )CIRCUIT\"));\n    ASSERT_EQ(actual.second, (std::vector<Flow<W>>{Flow<W>::from_str(\"Z0 -> rec[-1]\")}));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, flow_through_mzz, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        MZZ 0 1\n    )CIRCUIT\"),\n        {std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X0*X1 -> Y0*Y1 xor rec[-1]\"),\n            Flow<W>::from_str(\"X0*X1 -> X0*X1\"),\n            Flow<W>::from_str(\"Z0 -> Z1 xor rec[-1]\"),\n            Flow<W>::from_str(\"Z0 -> Z0\"),\n        }});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        MZZ 0 1\n    )CIRCUIT\"));\n    ASSERT_EQ(\n        actual.second,\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"Y0*Y1 -> X0*X1 xor rec[-1]\"),\n            Flow<W>::from_str(\"X0*X1 -> X0*X1\"),\n            Flow<W>::from_str(\"Z1 -> Z0 xor rec[-1]\"),\n            Flow<W>::from_str(\"Z0 -> Z0\"),\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, flow_through_mzz_h_cx_s, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        MZZ 0 1\n        H 0\n        CX 0 1\n        S 1\n    )CIRCUIT\"),\n        {std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X0*X1 -> X0*Z1 xor rec[-1]\"),\n            Flow<W>::from_str(\"X0*X1 -> Z0*Y1\"),\n            Flow<W>::from_str(\"Z0 -> Z0*Z1 xor rec[-1]\"),\n            Flow<W>::from_str(\"Z0 -> X0*Y1\"),\n        }});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        S_DAG 1\n        CX 0 1\n        H 0\n        MZZ 0 1\n    )CIRCUIT\"));\n    ASSERT_EQ(\n        actual.second,\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X0*Z1 -> X0*X1 xor rec[-1]\"),\n            Flow<W>::from_str(\"Z0*Y1 -> X0*X1\"),\n            Flow<W>::from_str(\"Z0*Z1 -> Z0 xor rec[-1]\"),\n            Flow<W>::from_str(\"X0*Y1 -> Z0\"),\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, flow_flip, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n        MY 0\n        MRX 0\n        MR 1\n        R 0\n    )CIRCUIT\"),\n        {std::vector<Flow<W>>{\n            Flow<W>::from_str(\"Y0*Z1 -> rec[-3] xor rec[-1]\"),\n            Flow<W>::from_str(\"1 -> Z0*Z1\"),\n            Flow<W>::from_str(\"1 -> Z1\"),\n            Flow<W>::from_str(\"1 -> Z0\"),\n        }});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        M 0\n        MR 1\n        MRX 0\n        RY 0\n    )CIRCUIT\"));\n    ASSERT_EQ(\n        actual.second,\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"1 -> Y0*Z1\"),\n            Flow<W>::from_str(\"Z0*Z1 -> rec[-3] xor rec[-2]\"),\n            Flow<W>::from_str(\"Z1 -> rec[-2]\"),\n            Flow<W>::from_str(\"Z0 -> rec[-3]\"),\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, flow_past_end_of_circuit, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n            H 0\n        )CIRCUIT\"),\n        {std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X300*Z0 -> X300*X0\"),\n        }});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        H 0\n    )CIRCUIT\"));\n    ASSERT_EQ(\n        actual.second,\n        (std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X300*X0 -> X300*Z0\"),\n        }));\n})\n\nTEST_EACH_WORD_SIZE_W(circuit_inverse_qec, obs_include_pauli, {\n    auto actual = circuit_inverse_qec<W>(\n        Circuit(R\"CIRCUIT(\n            RX 1\n            OBSERVABLE_INCLUDE[test](1) X1\n        )CIRCUIT\"),\n        {std::vector<Flow<W>>{}});\n    ASSERT_EQ(actual.first, Circuit(R\"CIRCUIT(\n        OBSERVABLE_INCLUDE[test](1) X1\n        MX 1\n        OBSERVABLE_INCLUDE(1) rec[-1]\n    )CIRCUIT\"));\n    ASSERT_EQ(actual.second, (std::vector<Flow<W>>{}));\n})\n"
  },
  {
    "path": "src/stim/util_top/circuit_inverse_qec_test.py",
    "content": "import pytest\nimport stim\n\n\ndef test_inv_circuit():\n    inv_circuit, inv_flows = stim.Circuit().time_reversed_for_flows([])\n    assert inv_circuit == stim.Circuit()\n    assert inv_flows == []\n\n    inv_circuit, inv_flows = stim.Circuit(\"\"\"\n        R 0\n        H 0\n        MX 0\n        DETECTOR rec[-1]\n    \"\"\").time_reversed_for_flows([])\n    assert inv_circuit == stim.Circuit(\"\"\"\n        RX 0\n        H 0\n        M 0\n        DETECTOR rec[-1]\n    \"\"\")\n    assert inv_flows == []\n\n    inv_circuit, inv_flows = stim.Circuit(\"\"\"\n        M 0\n    \"\"\").time_reversed_for_flows([stim.Flow('Z -> rec[-1]')])\n    assert inv_circuit == stim.Circuit(\"\"\"\n        R 0\n    \"\"\")\n    assert inv_flows == [stim.Flow('1 -> Z')]\n    assert inv_circuit.has_all_flows(inv_flows, unsigned=True)\n\n    inv_circuit, inv_flows = stim.Circuit(\"\"\"\n        R 0\n    \"\"\").time_reversed_for_flows([stim.Flow('1 -> Z')])\n    assert inv_circuit == stim.Circuit(\"\"\"\n        M 0\n    \"\"\")\n    assert inv_flows == [stim.Flow('Z -> rec[-1]')]\n\n    inv_circuit, inv_flows = stim.Circuit(\"\"\"\n        M 0\n    \"\"\").time_reversed_for_flows([stim.Flow('1 -> Z xor rec[-1]')])\n    assert inv_circuit == stim.Circuit(\"\"\"\n        M 0\n    \"\"\")\n    assert inv_flows == [stim.Flow('Z -> rec[-1]')]\n\n    inv_circuit, inv_flows = stim.Circuit(\"\"\"\n        M 0\n    \"\"\").time_reversed_for_flows(\n        flows=[stim.Flow('Z -> rec[-1]')],\n        dont_turn_measurements_into_resets=True,\n    )\n    assert inv_circuit == stim.Circuit(\"\"\"\n        M 0\n    \"\"\")\n    assert inv_flows == [stim.Flow('1 -> Z xor rec[-1]')]\n\n    inv_circuit, inv_flows = stim.Circuit(\"\"\"\n        MR(0.125) 0\n    \"\"\").time_reversed_for_flows([])\n    assert inv_circuit == stim.Circuit(\"\"\"\n        MR 0\n        X_ERROR(0.125) 0\n    \"\"\")\n    assert inv_flows == []\n\n\ndef test_inv_circuit_surface_code():\n    circuit = stim.Circuit.generated(\n        \"surface_code:rotated_memory_x\",\n        distance=3,\n        rounds=2,\n    )\n    det_regions = circuit.detecting_regions()\n    inv_circuit, _ = circuit.time_reversed_for_flows([])\n    keys = det_regions.keys()\n    inv_det_regions = inv_circuit.detecting_regions()\n    assert inv_det_regions.keys() == keys\n\n    # Check observable is time reversed.\n    num_ticks = circuit.num_ticks\n    l0 = stim.target_logical_observable_id(0)\n    assert inv_circuit.num_ticks == num_ticks\n    assert {num_ticks - t - 1: v for t, v in det_regions[l0].items()} == inv_det_regions[l0]\n\n    # Check all regions are time reversed (though may be indexed differently)\n    original_region_sets_reversed = set()\n    for k, v in det_regions.items():\n        original_region_sets_reversed.add(frozenset({num_ticks - t - 1: str(p) for t, p in v.items()}.items()))\n    inv_region_sets = set()\n    for k, v in inv_det_regions.items():\n        inv_region_sets.add(frozenset({t: str(p) for t, p in v.items()}.items()))\n    assert len(original_region_sets_reversed) == len(det_regions)\n    assert original_region_sets_reversed == inv_region_sets\n\n\ndef test_more_flow_qubits_than_circuit_qubits():\n    flows = [\n        stim.Flow(\"X300 -> X300\"),\n        stim.Flow(\"X2*Z301 -> Z2*Z301\"),\n    ]\n    circuit = stim.Circuit(\"H 2\")\n    assert circuit.has_flow(flows[0])\n    assert circuit.has_flow(flows[1])\n    assert circuit.has_all_flows(flows)\n    new_circuit, new_flows = circuit.time_reversed_for_flows(flows=flows)\n    assert new_circuit == circuit\n    assert new_flows == [\n        stim.Flow(\"X300 -> X300\"),\n        stim.Flow(\"Z2*Z301 -> X2*Z301\"),\n    ]\n\n\ndef test_measurement_ordering():\n    circuit = stim.Circuit(\"\"\"\n        M 0 1\n    \"\"\")\n    flows = [\n        stim.Flow(\"I -> Z0 xor rec[-2]\"),\n        stim.Flow(\"I -> Z1 xor rec[-1]\"),\n    ]\n    assert circuit.has_all_flows(flows, unsigned=True)\n    new_circuit, new_flows = circuit.time_reversed_for_flows(flows)\n    assert new_circuit.has_all_flows(new_flows, unsigned=True)\n\n\ndef test_measurement_ordering_2():\n    circuit = stim.Circuit(\"\"\"\n        MZZ 0 1 2 3\n    \"\"\")\n    flows = [\n        stim.Flow(\"I -> Z0*Z1 xor rec[-2]\"),\n        stim.Flow(\"I -> Z2*Z3 xor rec[-1]\"),\n    ]\n    assert circuit.has_all_flows(flows, unsigned=True)\n    new_circuit, new_flows = circuit.time_reversed_for_flows(flows)\n    assert new_circuit.has_all_flows(new_flows, unsigned=True)\n\n\ndef test_measurement_ordering_3():\n    circuit = stim.Circuit(\"\"\"\n        MR 0 1\n    \"\"\")\n    flows = [\n        stim.Flow(\"Z0 -> rec[-2]\"),\n        stim.Flow(\"Z1 -> rec[-1]\"),\n        stim.Flow(\"I -> Z0\"),\n        stim.Flow(\"I -> Z1\"),\n    ]\n    assert circuit.has_all_flows(flows, unsigned=True)\n    new_circuit, new_flows = circuit.time_reversed_for_flows(flows)\n    assert new_circuit.has_all_flows(new_flows, unsigned=True)\n\n\ndef test_feedback():\n    c = stim.Circuit(\"\"\"\n        R 1\n        M 1\n        CX rec[-1] 0\n    \"\"\")\n    with pytest.raises(ValueError):\n        c.time_reversed_for_flows([stim.Flow(\"Z0 -> Z0\")])\n        # TODO: once feedback is supported verify the inv flow is correct\n\n\ndef test_obs_include_paulis():\n    c = stim.Circuit(\"\"\"\n        RX 0\n        OBSERVABLE_INCLUDE[test1](2) X0\n        OBSERVABLE_INCLUDE[test2](3) Y1\n        MY 1\n        OBSERVABLE_INCLUDE(3) rec[-1]\n    \"\"\")\n    assert c.time_reversed_for_flows([]) == (stim.Circuit(\"\"\"\n        RY 1\n        OBSERVABLE_INCLUDE[test2](3) Y1\n        OBSERVABLE_INCLUDE[test1](2) X0\n        MX 0\n        OBSERVABLE_INCLUDE(2) rec[-1]\n    \"\"\"), [])\n"
  },
  {
    "path": "src/stim/util_top/circuit_inverse_unitary.cc",
    "content": "#include \"stim/util_top/circuit_inverse_unitary.h\"\n\nusing namespace stim;\n\nCircuit stim::circuit_inverse_unitary(const Circuit &unitary_circuit) {\n    Circuit inverted;\n    unitary_circuit.for_each_operation_reverse([&](const CircuitInstruction &op) {\n        const auto &gate_data = GATE_DATA[op.gate_type];\n        if (!(gate_data.flags & GATE_IS_UNITARY)) {\n            throw std::invalid_argument(\"Not unitary: \" + op.str());\n        }\n        size_t step = (gate_data.flags & GATE_TARGETS_PAIRS) ? 2 : 1;\n        auto s = op.targets.ptr_start;\n        const auto &inv_gate = gate_data.inverse();\n        for (size_t k = op.targets.size(); k > 0; k -= step) {\n            inverted.safe_append(CircuitInstruction(inv_gate.id, op.args, {s + k - step, s + k}, op.tag));\n        }\n    });\n    return inverted;\n}\n"
  },
  {
    "path": "src/stim/util_top/circuit_inverse_unitary.h",
    "content": "#ifndef _STIM_UTIL_TOP_CIRCUIT_INVERSE_UNITARY_H\n#define _STIM_UTIL_TOP_CIRCUIT_INVERSE_UNITARY_H\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim {\n\n/// Inverts the given circuit, as long as it only contains unitary operations.\nCircuit circuit_inverse_unitary(const Circuit &unitary_circuit);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/circuit_inverse_unitary.test.cc",
    "content": "#include \"stim/util_top/circuit_inverse_unitary.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(conversions, circuit_inverse_unitary) {\n    ASSERT_EQ(\n        circuit_inverse_unitary(Circuit(R\"CIRCUIT(\n        H 0\n        ISWAP 0 1 1 2 3 2\n        S 0 3 4\n    )CIRCUIT\")),\n        Circuit(R\"CIRCUIT(\n        S_DAG 4 3 0\n        ISWAP_DAG 3 2 1 2 0 1\n        H 0\n    )CIRCUIT\"));\n\n    ASSERT_THROW({ circuit_inverse_unitary(Circuit(\"M 0\")); }, std::invalid_argument);\n}\n"
  },
  {
    "path": "src/stim/util_top/circuit_to_dem.h",
    "content": "#ifndef _STIM_UTIL_TOP_CIRCUIT_TO_DEM_H\n#define _STIM_UTIL_TOP_CIRCUIT_TO_DEM_H\n\n#include \"stim/simulators/error_analyzer.h\"\n\nnamespace stim {\n\nstruct DemOptions {\n    bool decompose_errors = false;\n    bool flatten_loops = true;\n    bool allow_gauge_detectors = false;\n    double approximate_disjoint_errors_threshold = 0;\n    bool ignore_decomposition_failures = false;\n    bool block_decomposition_from_introducing_remnant_edges = false;\n};\n\ninline DetectorErrorModel circuit_to_dem(const Circuit &circuit, DemOptions options = {}) {\n    return ErrorAnalyzer::circuit_to_detector_error_model(\n        circuit,\n        options.decompose_errors,\n        !options.flatten_loops,\n        options.allow_gauge_detectors,\n        options.approximate_disjoint_errors_threshold,\n        options.ignore_decomposition_failures,\n        options.block_decomposition_from_introducing_remnant_edges);\n}\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/circuit_to_dem.test.cc",
    "content": "#include \"stim/util_top/circuit_to_dem.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(circuit_to_dem, heralded_noise_basis) {\n    ASSERT_EQ(\n        circuit_to_dem(Circuit(R\"CIRCUIT(\n            MXX 0 1\n            MZZ 0 1\n            HERALDED_PAULI_CHANNEL_1(0.25, 0, 0, 0) 0\n            MXX 0 1\n            MZZ 0 1\n            DETECTOR(2) rec[-3]\n            DETECTOR(3) rec[-2] rec[-5]\n            DETECTOR(5) rec[-1] rec[-4]\n        )CIRCUIT\")),\n        DetectorErrorModel(R\"DEM(\n            error(0.25) D0\n            detector(2) D0\n            detector(3) D1\n            detector(5) D2\n        )DEM\"));\n\n    ASSERT_EQ(\n        circuit_to_dem(Circuit(R\"CIRCUIT(\n            MXX 0 1\n            MZZ 0 1\n            HERALDED_PAULI_CHANNEL_1(0, 0.25, 0, 0) 0\n            MXX 0 1\n            MZZ 0 1\n            DETECTOR(2) rec[-3]\n            DETECTOR(3) rec[-2] rec[-5]\n            DETECTOR(5) rec[-1] rec[-4]\n        )CIRCUIT\")),\n        DetectorErrorModel(R\"DEM(\n            error(0.25) D0 D2\n            detector(2) D0\n            detector(3) D1\n            detector(5) D2\n        )DEM\"));\n\n    ASSERT_EQ(\n        circuit_to_dem(Circuit(R\"CIRCUIT(\n            MXX 0 1\n            MZZ 0 1\n            HERALDED_PAULI_CHANNEL_1(0, 0, 0.25, 0) 0\n            MXX 0 1\n            MZZ 0 1\n            DETECTOR(2) rec[-3]\n            DETECTOR(3) rec[-2] rec[-5]\n            DETECTOR(5) rec[-1] rec[-4]\n        )CIRCUIT\")),\n        DetectorErrorModel(R\"DEM(\n            error(0.25) D0 D1 D2\n            detector(2) D0\n            detector(3) D1\n            detector(5) D2\n        )DEM\"));\n\n    ASSERT_EQ(\n        circuit_to_dem(Circuit(R\"CIRCUIT(\n            MXX 0 1\n            MZZ 0 1\n            HERALDED_PAULI_CHANNEL_1(0, 0, 0, 0.25) 0\n            MXX 0 1\n            MZZ 0 1\n            DETECTOR(2) rec[-3]\n            DETECTOR(3) rec[-2] rec[-5]\n            DETECTOR(5) rec[-1] rec[-4]\n        )CIRCUIT\")),\n        DetectorErrorModel(R\"DEM(\n            error(0.25) D0 D1\n            detector(2) D0\n            detector(3) D1\n            detector(5) D2\n        )DEM\"));\n\n    ASSERT_EQ(\n        circuit_to_dem(\n            Circuit(R\"CIRCUIT(\n            MXX 0 1\n            MZZ 0 1\n            HERALDED_PAULI_CHANNEL_1(0.125, 0, 0.25, 0) 0\n            MXX 0 1\n            MZZ 0 1\n            DETECTOR(2) rec[-3]\n            DETECTOR(3) rec[-2] rec[-5]\n            DETECTOR(5) rec[-1] rec[-4]\n        )CIRCUIT\"),\n            {.approximate_disjoint_errors_threshold = 1}),\n        DetectorErrorModel(R\"DEM(\n            error(0.125) D0\n            error(0.25) D0 D1 D2\n            detector(2) D0\n            detector(3) D1\n            detector(5) D2\n        )DEM\"));\n\n    ASSERT_THROW(\n        {\n            circuit_to_dem(Circuit(R\"CIRCUIT(\n            MXX 0 1\n            MZZ 0 1\n            HERALDED_PAULI_CHANNEL_1(0.125, 0, 0.25, 0) 0\n            MXX 0 1\n            MZZ 0 1\n            DETECTOR(2) rec[-3]\n            DETECTOR(3) rec[-2] rec[-5]\n            DETECTOR(5) rec[-1] rec[-4]\n        )CIRCUIT\"));\n        },\n        std::invalid_argument);\n}\n"
  },
  {
    "path": "src/stim/util_top/circuit_to_detecting_regions.cc",
    "content": "#include \"stim/util_top/circuit_to_detecting_regions.h\"\n\n#include \"stim/simulators/sparse_rev_frame_tracker.h\"\n\nusing namespace stim;\n\nstd::map<DemTarget, std::map<uint64_t, FlexPauliString>> stim::circuit_to_detecting_regions(\n    const Circuit &circuit,\n    std::set<DemTarget> included_targets,\n    std::set<uint64_t> included_ticks,\n    bool ignore_anticommutation_errors) {\n    CircuitStats stats = circuit.compute_stats();\n    uint64_t tick_index = stats.num_ticks;\n    SparseUnsignedRevFrameTracker tracker(\n        stats.num_qubits, stats.num_measurements, stats.num_detectors, !ignore_anticommutation_errors);\n    std::map<DemTarget, std::map<uint64_t, FlexPauliString>> result;\n    circuit.for_each_operation_reverse([&](const CircuitInstruction &inst) {\n        if (inst.gate_type == GateType::TICK) {\n            tick_index -= 1;\n            if (included_ticks.contains(tick_index)) {\n                for (size_t q = 0; q < stats.num_qubits; q++) {\n                    for (auto target : tracker.xs[q]) {\n                        if (included_targets.contains(target)) {\n                            auto &m = result[target];\n                            if (!m.contains(tick_index)) {\n                                m.insert({tick_index, FlexPauliString(stats.num_qubits)});\n                            }\n                            m.at(tick_index).value.xs[q] ^= 1;\n                        }\n                    }\n                    for (auto target : tracker.zs[q]) {\n                        if (included_targets.contains(target)) {\n                            auto &m = result[target];\n                            if (!m.contains(tick_index)) {\n                                m.insert({tick_index, FlexPauliString(stats.num_qubits)});\n                            }\n                            m.at(tick_index).value.zs[q] ^= 1;\n                        }\n                    }\n                }\n            }\n        }\n        tracker.undo_gate(inst);\n    });\n    tracker.undo_implicit_RZs_at_start_of_circuit();\n    return result;\n}\n"
  },
  {
    "path": "src/stim/util_top/circuit_to_detecting_regions.h",
    "content": "#ifndef _STIM_UTIL_TOP_CIRCUIT_TO_DETECTING_REGIONS\n#define _STIM_UTIL_TOP_CIRCUIT_TO_DETECTING_REGIONS\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/dem/dem_instruction.h\"\n#include \"stim/stabilizers/flex_pauli_string.h\"\n\nnamespace stim {\n\nstd::map<DemTarget, std::map<uint64_t, FlexPauliString>> circuit_to_detecting_regions(\n    const Circuit &circuit,\n    std::set<stim::DemTarget> included_targets,\n    std::set<uint64_t> included_ticks,\n    bool ignore_anticommutation_errors);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/circuit_to_detecting_regions.test.cc",
    "content": "#include \"stim/util_top/circuit_to_detecting_regions.h\"\n\n#include \"gtest/gtest.h\"\n\nusing namespace stim;\n\nTEST(circuit_to_detecting_regions, simple) {\n    Circuit circuit(R\"CIRCUIT(\n        H 0\n        TICK\n        CX 0 1\n        TICK\n        MXX 0 1\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n    auto actual = circuit_to_detecting_regions(circuit, {DemTarget::relative_detector_id(0)}, {0, 1}, false);\n    std::map<DemTarget, std::map<uint64_t, FlexPauliString>> expected{\n        {DemTarget::relative_detector_id(0),\n         {\n             {0, FlexPauliString::from_text(\"X_\")},\n             {1, FlexPauliString::from_text(\"XX\")},\n         }},\n    };\n}\n"
  },
  {
    "path": "src/stim/util_top/circuit_to_detecting_regions_test.py",
    "content": "import pytest\nimport stim\n\n\ndef test_detecting_regions_fails_on_anticommutations_at_start_of_circuit():\n    c = stim.Circuit(\"\"\"\n        TICK\n        R 0\n        TICK\n        MX 0\n        DETECTOR rec[-1]\n    \"\"\")\n    assert 'magenta' in str(c.diagram('detslice-with-ops-svg'))\n    with pytest.raises(ValueError, match=\"anticommutation\"):\n        c.detecting_regions()\n\n    c = stim.Circuit(\"\"\"\n        R 0\n        TICK\n        MX 0\n        DETECTOR rec[-1]\n    \"\"\")\n    assert 'magenta' in str(c.diagram('detslice-with-ops-svg'))\n    with pytest.raises(ValueError, match=\"anticommutation\"):\n        c.detecting_regions()\n\n    c = stim.Circuit(\"\"\"\n        MX 0\n        DETECTOR rec[-1]\n    \"\"\")\n    assert 'magenta' in str(c.diagram('detslice-with-ops-svg'))\n    with pytest.raises(ValueError, match=\"anticommutation\"):\n        c.detecting_regions()\n"
  },
  {
    "path": "src/stim/util_top/circuit_vs_amplitudes.cc",
    "content": "#include \"stim/util_top/circuit_vs_amplitudes.h\"\n\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/simulators/vector_simulator.h\"\n#include \"stim/util_bot/twiddle.h\"\n#include \"stim/util_top/circuit_inverse_unitary.h\"\n\nusing namespace stim;\n\ninline static size_t biggest_index(const std::vector<std::complex<float>> &state_vector) {\n    size_t best_index = 0;\n    float best_size = std::norm(state_vector[0]);\n    for (size_t k = 1; k < state_vector.size(); k++) {\n        float size = std::norm(state_vector[k]);\n        if (size > best_size) {\n            best_size = size;\n            best_index = k;\n        }\n    }\n    return best_index;\n}\n\ninline static size_t compute_occupation(const std::vector<std::complex<float>> &state_vector) {\n    size_t c = 0;\n    for (const auto &v : state_vector) {\n        if (v != std::complex<float>{0, 0}) {\n            c++;\n        }\n    }\n    return c;\n}\n\nCircuit stim::stabilizer_state_vector_to_circuit(\n    const std::vector<std::complex<float>> &state_vector, bool little_endian) {\n    if (!is_power_of_2(state_vector.size())) {\n        std::stringstream ss;\n        ss << \"Expected number of amplitudes to be a power of 2.\";\n        ss << \" The given state vector had \" << state_vector.size() << \" amplitudes.\";\n        throw std::invalid_argument(ss.str());\n    }\n\n    uint8_t num_qubits = floor_lg2(state_vector.size());\n    VectorSimulator sim(num_qubits);\n    sim.state = state_vector;\n\n    Circuit recorded;\n    auto apply = [&](GateType gate_type, uint32_t target) {\n        sim.apply(gate_type, target);\n        recorded.safe_append(CircuitInstruction(\n            gate_type,\n            {},\n            std::vector<GateTarget>{\n                GateTarget::qubit(little_endian ? target : (num_qubits - target - 1)),\n            },\n            \"\"));\n    };\n    auto apply2 = [&](GateType gate_type, uint32_t target, uint32_t target2) {\n        sim.apply(gate_type, target, target2);\n        recorded.safe_append(CircuitInstruction(\n            gate_type,\n            {},\n            std::vector<GateTarget>{\n                GateTarget::qubit(little_endian ? target : (num_qubits - target - 1)),\n                GateTarget::qubit(little_endian ? target2 : (num_qubits - target2 - 1)),\n            },\n            \"\"));\n    };\n\n    // Move biggest amplitude to start of state vector.\n    size_t pivot = biggest_index(state_vector);\n    for (size_t q = 0; q < num_qubits; q++) {\n        if ((pivot >> q) & 1) {\n            apply(GateType::X, q);\n        }\n    }\n    sim.smooth_stabilizer_state(sim.state[0]);\n    size_t occupation = compute_occupation(sim.state);\n    if (!is_power_of_2(occupation)) {\n        throw std::invalid_argument(\"State vector isn't a stabilizer state.\");\n    }\n\n    // Repeatedly cancel amplitudes\n    while (occupation > 1) {\n        size_t k = 1;\n        for (; k < state_vector.size(); k++) {\n            if (sim.state[k].real() || sim.state[k].imag()) {\n                break;\n            }\n        }\n        if (k == state_vector.size()) {\n            break;\n        }\n\n        size_t base_qubit = SIZE_MAX;\n        for (size_t q = 0; q < num_qubits; q++) {\n            if ((k >> q) & 1) {\n                if (base_qubit == SIZE_MAX) {\n                    base_qubit = q;\n                } else {\n                    apply2(GateType::CX, base_qubit, q);\n                }\n            }\n        }\n\n        auto s = sim.state[1 << base_qubit];\n        assert(s != (std::complex<float>{0, 0}));\n        if (s == std::complex<float>{-1, 0}) {\n            apply(GateType::Z, base_qubit);\n        } else if (s == std::complex<float>{0, 1}) {\n            apply(GateType::S_DAG, base_qubit);\n        } else if (s == std::complex<float>{0, -1}) {\n            apply(GateType::S, base_qubit);\n        }\n        apply(GateType::H, base_qubit);\n\n        sim.smooth_stabilizer_state(sim.state[0]);\n        if (compute_occupation(sim.state) * 2 != occupation) {\n            throw std::invalid_argument(\"State vector isn't a stabilizer state.\");\n        }\n        occupation >>= 1;\n    }\n\n    recorded = circuit_inverse_unitary(recorded);\n    if (recorded.count_qubits() < num_qubits) {\n        recorded.safe_append_u(\"I\", {(uint32_t)(num_qubits - 1)});\n    }\n\n    return recorded;\n}\n\nstd::vector<std::complex<float>> stim::circuit_to_output_state_vector(const Circuit &circuit, bool little_endian) {\n    Tableau<64> result(circuit.count_qubits());\n    TableauSimulator<64> sim(std::mt19937_64(0), circuit.count_qubits());\n\n    circuit.for_each_operation([&](const CircuitInstruction &op) {\n        const auto &flags = GATE_DATA[op.gate_type].flags;\n        if (flags & GATE_IS_UNITARY) {\n            sim.do_gate(op);\n        } else if (flags & (GATE_IS_NOISY | GATE_IS_RESET | GATE_PRODUCES_RESULTS)) {\n            throw std::invalid_argument(\n                \"The circuit has no well-defined tableau because it contains noisy or dissipative operations.\\n\"\n                \"The first such operation is: \" +\n                op.str());\n        } else {\n            // Operation should be an annotation like TICK or DETECTOR.\n        }\n    });\n\n    return sim.to_state_vector(little_endian);\n}\n"
  },
  {
    "path": "src/stim/util_top/circuit_vs_amplitudes.h",
    "content": "#ifndef _STIM_UTIL_TOP_CIRCUIT_VS_AMPLITUDES_H\n#define _STIM_UTIL_TOP_CIRCUIT_VS_AMPLITUDES_H\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim {\n\n/// Synthesizes a circuit to generate the given state vector.\n///\n/// Args:\n///     stabilizer_state_vector: The vector of amplitudes to produce using a circuit. Does not need to be a unit vector,\n///     but must be non-zero.\n///     little_endian: Whether the vector is using little endian or big endian ordering.\n///     inverted_circuit: If false, returns a circuit that sends |000...0> to the state vector.\n///         If true, returns a circuit that sends the state vector to |000...0> instead of a cir.\n///\n/// Returns:\n///     A circuit that outputs the given state vector (up to global phase).\n///\n/// Throws:\n///     std::invalid_argument: The given state vector cannot be produced by a stabilizer circuit.\nCircuit stabilizer_state_vector_to_circuit(\n    const std::vector<std::complex<float>> &stabilizer_state_vector, bool little_endian);\n\n/// Simulates the given circuit and outputs a state vector.\n///\n/// Args:\n///     circuit: The circuit to simulate. Cannot contain noisy or dissipative operations.\n///     little_endian: Whether the returned vector uses little endian or big endian qubit order.\n///\n/// Returns:\n///     The state vector, using the requested endianness.\nstd::vector<std::complex<float>> circuit_to_output_state_vector(const Circuit &circuit, bool little_endian);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/circuit_vs_amplitudes.test.cc",
    "content": "#include \"stim/util_top/circuit_vs_amplitudes.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST(conversions, stabilizer_state_vector_to_circuit_basic) {\n    ASSERT_THROW(stabilizer_state_vector_to_circuit({}, false), std::invalid_argument);\n\n    ASSERT_THROW(\n        stabilizer_state_vector_to_circuit(\n            {\n                {0},\n            },\n            false),\n        std::invalid_argument);\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {1},\n            },\n            false),\n        stim::Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {-1},\n            },\n            false),\n        stim::Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {0, 1},\n                {0},\n            },\n            false),\n        stim::Circuit(R\"CIRCUIT(\n        I 0\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {0},\n                {1},\n            },\n            false),\n        stim::Circuit(R\"CIRCUIT(\n        X 0\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {sqrtf(0.5)},\n                {sqrtf(0.5)},\n            },\n            false),\n        stim::Circuit(R\"CIRCUIT(\n        H 0\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {0},\n                {1},\n                {0},\n                {0},\n            },\n            false),\n        stim::Circuit(R\"CIRCUIT(\n        X 1\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {0},\n                {0},\n                {1},\n                {0},\n            },\n            false),\n        stim::Circuit(R\"CIRCUIT(\n        X 0\n        I 1\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {0},\n                {1},\n                {0},\n                {0},\n            },\n            true),\n        stim::Circuit(R\"CIRCUIT(\n        X 0\n        I 1\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {0},\n                {0},\n                {1},\n                {0},\n            },\n            true),\n        stim::Circuit(R\"CIRCUIT(\n        X 1\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {sqrtf(0.5)},\n                {0, sqrtf(0.5)},\n            },\n            true),\n        stim::Circuit(R\"CIRCUIT(\n        H 0\n        S 0\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {sqrtf(0.5)},\n                {0, -sqrtf(0.5)},\n            },\n            true),\n        stim::Circuit(R\"CIRCUIT(\n        H 0\n        S_DAG 0\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        stabilizer_state_vector_to_circuit(\n            {\n                {sqrtf(0.5)},\n                {-sqrtf(0.5)},\n            },\n            true),\n        stim::Circuit(R\"CIRCUIT(\n        H 0\n        Z 0\n    )CIRCUIT\"));\n}\n\nTEST(conversions, stabilizer_state_vector_to_circuit_fuzz_round_trip) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (const auto &little_endian : std::vector<bool>{false, true}) {\n        for (size_t n = 0; n < 5; n++) {\n            // Pick a random stabilizer state.\n            TableauSimulator<64> sim(INDEPENDENT_TEST_RNG(), n);\n            sim.inv_state = Tableau<64>::random(n, rng);\n            auto desired_vec = sim.to_state_vector(little_endian);\n\n            // Round trip through a circuit.\n            auto circuit = stabilizer_state_vector_to_circuit(desired_vec, little_endian);\n            auto actual_vec = circuit_to_output_state_vector(circuit, little_endian);\n            ASSERT_EQ(actual_vec, desired_vec) << \"little_endian=\" << little_endian << \", n=\" << n;\n        }\n    }\n}\n\nTEST(conversions, stabilizer_state_vector_to_circuit_unnormalized_fuzz_round_trip) {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto little_endian = true;\n\n    for (size_t i = 0; i < 100; i++) {\n        // Pick a random stabilizer state.\n        size_t n = i % 5;\n        TableauSimulator<64> sim(INDEPENDENT_TEST_RNG(), n);\n        sim.inv_state = Tableau<64>::random(n, rng);\n        auto desired_vec = sim.to_state_vector(little_endian);\n\n        // Unnormalize by multiplying by a random non-zero factor.\n        auto scaled_vec = desired_vec;\n        std::uniform_real_distribution<float> dist(-1000.0, +1000.0);\n        std::complex<float> scale = {dist(rng), dist(rng)};\n        while (std::norm(scale) < 0.01) {\n            scale = {dist(rng), dist(rng)};\n        }\n        for (auto &c : scaled_vec) {\n            c *= scale;\n        }\n\n        // Round trip through a circuit.\n        auto circuit = stabilizer_state_vector_to_circuit(scaled_vec, little_endian);\n        auto actual_vec = circuit_to_output_state_vector(circuit, little_endian);\n        ASSERT_EQ(actual_vec, desired_vec) << \" scale=\" << scale;\n    }\n}\n\nTEST(conversions, circuit_to_output_state_vector) {\n    ASSERT_EQ(circuit_to_output_state_vector(Circuit(\"\"), false), (std::vector<std::complex<float>>{{1}}));\n    ASSERT_EQ(\n        circuit_to_output_state_vector(Circuit(\"H 0 1\"), false),\n        (std::vector<std::complex<float>>{{0.5}, {0.5}, {0.5}, {0.5}}));\n    ASSERT_EQ(\n        circuit_to_output_state_vector(Circuit(\"X 1\"), false), (std::vector<std::complex<float>>{{0}, {1}, {0}, {0}}));\n    ASSERT_EQ(\n        circuit_to_output_state_vector(Circuit(\"X 1\"), true), (std::vector<std::complex<float>>{{0}, {0}, {1}, {0}}));\n}\n"
  },
  {
    "path": "src/stim/util_top/circuit_vs_tableau.h",
    "content": "#ifndef _STIM_UTIL_TOP_CIRCUIT_VS_TABLEAU_H\n#define _STIM_UTIL_TOP_CIRCUIT_VS_TABLEAU_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\n/// Compiles the given circuit into a tableau.\n///\n/// Args:\n///     circuit: The circuit to compile. Should only contain unitary operations.\n///     ignore_noise: If the circuit contains noise channels, ignore them instead of raising an exception.\n///     ignore_measurement: If the circuit contains measurements, ignore them instead of raising an exception.\n///     ignore_reset: If the circuit contains resets, ignore them instead of raising an exception.\n///     inverse: The last step of the implementation is to invert the tableau. Setting this argument\n///         to true will skip this inversion, saving time but returning the inverse tableau.\n///\n/// Returns:\n///     A tableau encoding the given circuit's Clifford operation.\ntemplate <size_t W>\nTableau<W> circuit_to_tableau(\n    const Circuit &circuit, bool ignore_noise, bool ignore_measurement, bool ignore_reset, bool inverse = false);\n\n/// Synthesizes a circuit that implements the given tableau's Clifford operation.\n///\n/// This method is allowed to output different circuits, from call to call or version\n/// to version, for the same input tableau.\n///\n/// Args:\n///     tableau: The tableau to synthesize into a circuit.\n///     method: The method to use when synthesizing the circuit. Available values:\n///         \"elimination\": Cancels off-diagonal terms using Gaussian elimination.\n///             Gate set: H, S, CX\n///             Circuit qubit count: n\n///             Circuit operation count: O(n^2)\n///             Circuit depth: O(n^2)\n///         \"graph_state\": Prepares the tableau's state using a graph state circuit.\n///             Gate set: RX, CZ, H, S, X, Y, Z\n///             Circuit qubit count: n\n///             Circuit operation count: O(n^2)\n///\n///             The circuit will be made up of three layers:\n///                 1. An RX layer initializing all qubits.\n///                 2. A CZ layer coupling the qubits.\n///                     an edge in the graph state.)\n///                 3. A single qubit rotation layer.\n///\n///             Note: \"graph_state\" treats the tableau as a state instead of as a\n///             Clifford operation. It will preserve the set of stabilizers, but\n///             not the exact choice of generators.\n///\n/// Returns:\n///     The synthesized circuit.\ntemplate <size_t W>\nCircuit tableau_to_circuit(const Tableau<W> &tableau, std::string_view method);\ntemplate <size_t W>\nCircuit tableau_to_circuit_graph_method(const Tableau<W> &tableau);\ntemplate <size_t W>\nCircuit tableau_to_circuit_mpp_method(const Tableau<W> &tableau, bool skip_sign);\ntemplate <size_t W>\nCircuit tableau_to_circuit_elimination_method(const Tableau<W> &tableau);\n\n}  // namespace stim\n\n#include \"stim/util_top/circuit_vs_tableau.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/circuit_vs_tableau.inl",
    "content": "#include \"stim/simulators/graph_simulator.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_top/circuit_vs_tableau.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nTableau<W> circuit_to_tableau(\n    const Circuit &circuit, bool ignore_noise, bool ignore_measurement, bool ignore_reset, bool inverse) {\n    Tableau<W> result(circuit.count_qubits());\n    TableauSimulator<W> sim(std::mt19937_64(0), circuit.count_qubits());\n\n    circuit.for_each_operation([&](const CircuitInstruction &op) {\n        const auto &flags = GATE_DATA[op.gate_type].flags;\n        if (!ignore_measurement && (flags & GATE_PRODUCES_RESULTS)) {\n            throw std::invalid_argument(\n                \"The circuit has no well-defined tableau because it contains measurement operations.\\n\"\n                \"To ignore measurement operations, pass the argument ignore_measurement=True.\\n\"\n                \"The first measurement operation is: \" +\n                op.str());\n        }\n        if (!ignore_reset && (flags & GATE_IS_RESET)) {\n            throw std::invalid_argument(\n                \"The circuit has no well-defined tableau because it contains reset operations.\\n\"\n                \"To ignore reset operations, pass the argument ignore_reset=True.\\n\"\n                \"The first reset operation is: \" +\n                op.str());\n        }\n        if (!ignore_noise && (flags & GATE_IS_NOISY)) {\n            for (const auto &f : op.args) {\n                if (f > 0) {\n                    throw std::invalid_argument(\n                        \"The circuit has no well-defined tableau because it contains noisy operations.\\n\"\n                        \"To ignore noisy operations, pass the argument ignore_noise=True.\\n\"\n                        \"The first noisy operation is: \" +\n                        op.str());\n                }\n            }\n        }\n        if (flags & GATE_IS_UNITARY) {\n            sim.do_gate(op);\n        }\n    });\n\n    if (!inverse) {\n        return sim.inv_state.inverse();\n    }\n    return sim.inv_state;\n}\n\ntemplate <size_t W>\nCircuit tableau_to_circuit(const Tableau<W> &tableau, std::string_view method) {\n    if (method == \"elimination\") {\n        return tableau_to_circuit_elimination_method(tableau);\n    } else if (method == \"graph_state\") {\n        return tableau_to_circuit_graph_method(tableau);\n    } else if (method == \"mpp_state\") {\n        return tableau_to_circuit_mpp_method(tableau, false);\n    } else if (method == \"mpp_state_unsigned\") {\n        return tableau_to_circuit_mpp_method(tableau, true);\n    } else {\n        std::stringstream ss;\n        ss << \"Unknown method: '\" << method << \"'. Known methods:\\n\";\n        ss << \"    - 'elimination'\\n\";\n        ss << \"    - 'graph_state'\\n\";\n        ss << \"    - 'mpp_state'\\n\";\n        ss << \"    - 'mpp_state_unsigned'\\n\";\n        throw std::invalid_argument(ss.str());\n    }\n}\n\ntemplate <size_t W>\nCircuit tableau_to_circuit_graph_method(const Tableau<W> &tableau) {\n    GraphSimulator sim(tableau.num_qubits);\n    sim.do_circuit(tableau_to_circuit_elimination_method(tableau));\n    return sim.to_circuit(true);\n}\n\ntemplate <size_t W>\nCircuit tableau_to_circuit_mpp_method(const Tableau<W> &tableau, bool skip_sign) {\n    Circuit result;\n    std::vector<GateTarget> targets;\n    size_t n = tableau.num_qubits;\n\n    // Measure each stabilizer with MPP.\n    for (size_t k = 0; k < n; k++) {\n        const auto &stabilizer = tableau.zs[k];\n        bool need_sign = stabilizer.sign;\n        for (size_t q = 0; q < n; q++) {\n            bool x = stabilizer.xs[q];\n            bool z = stabilizer.zs[q];\n            if (x || z) {\n                targets.push_back(GateTarget::pauli_xz(q, x, z, need_sign));\n                targets.push_back(GateTarget::combiner());\n                need_sign = false;\n            }\n        }\n        assert(!targets.empty());\n        targets.pop_back();\n        result.safe_append(CircuitInstruction(GateType::MPP, {}, targets, \"\"));\n        targets.clear();\n    }\n\n    if (!skip_sign) {\n        // Correct each stabilizer's sign with feedback.\n        std::vector<GateTarget> targets_x;\n        std::vector<GateTarget> targets_y;\n        std::vector<GateTarget> targets_z;\n        std::array<std::vector<GateTarget> *, 4> targets_ptrs = {nullptr, &targets_x, &targets_z, &targets_y};\n        for (size_t k = 0; k < n; k++) {\n            const auto &destabilizer = tableau.xs[k];\n            for (size_t q = 0; q < n; q++) {\n                bool x = destabilizer.xs[q];\n                bool z = destabilizer.zs[q];\n                auto *out = targets_ptrs[x + z * 2];\n                if (out != nullptr) {\n                    out->push_back(GateTarget::rec(-(int32_t)(n - k)));\n                    out->push_back(GateTarget::qubit(q));\n                }\n            }\n        }\n        if (!targets_x.empty()) {\n            result.safe_append(CircuitInstruction(GateType::CX, {}, targets_x, \"\"));\n        }\n        if (!targets_y.empty()) {\n            result.safe_append(CircuitInstruction(GateType::CY, {}, targets_y, \"\"));\n        }\n        if (!targets_z.empty()) {\n            result.safe_append(CircuitInstruction(GateType::CZ, {}, targets_z, \"\"));\n        }\n    }\n\n    return result;\n}\n\ntemplate <size_t W>\nCircuit tableau_to_circuit_elimination_method(const Tableau<W> &tableau) {\n    Tableau<W> remaining = tableau.inverse();\n    Circuit recorded_circuit;\n    auto apply = [&](GateType gate_type, uint32_t target) {\n        remaining.inplace_scatter_append(GATE_DATA[gate_type].tableau<W>(), {target});\n        recorded_circuit.safe_append(\n            CircuitInstruction(gate_type, {}, std::vector<GateTarget>{GateTarget::qubit(target)}, \"\"));\n    };\n    auto apply2 = [&](GateType gate_type, uint32_t target, uint32_t target2) {\n        remaining.inplace_scatter_append(GATE_DATA[gate_type].tableau<W>(), {target, target2});\n        recorded_circuit.safe_append(CircuitInstruction(\n            gate_type, {}, std::vector<GateTarget>{GateTarget::qubit(target), GateTarget::qubit(target2)}, \"\"));\n    };\n    auto x_out = [&](size_t inp, size_t out) {\n        const auto &p = remaining.xs[inp];\n        return p.xs[out] + 2 * p.zs[out];\n    };\n    auto z_out = [&](size_t inp, size_t out) {\n        const auto &p = remaining.zs[inp];\n        return p.xs[out] + 2 * p.zs[out];\n    };\n\n    size_t n = remaining.num_qubits;\n    for (size_t col = 0; col < n; col++) {\n        // Find a cell with an anti-commuting pair of Paulis.\n        size_t pivot_row;\n        for (pivot_row = col; pivot_row < n; pivot_row++) {\n            int px = x_out(col, pivot_row);\n            int pz = z_out(col, pivot_row);\n            if (px && pz && px != pz) {\n                break;\n            }\n        }\n        assert(pivot_row < n);  // Ensured by unitarity of the tableau.\n\n        // Move the pivot to the diagonal.\n        if (pivot_row != col) {\n            apply2(GateType::CX, pivot_row, col);\n            apply2(GateType::CX, col, pivot_row);\n            apply2(GateType::CX, pivot_row, col);\n        }\n\n        // Transform the pivot to XZ.\n        if (z_out(col, col) == 3) {\n            apply(GateType::S, col);\n        }\n        if (z_out(col, col) != 2) {\n            apply(GateType::H, col);\n        }\n        if (x_out(col, col) != 1) {\n            apply(GateType::S, col);\n        }\n\n        // Use the pivot to remove all other terms in the X observable.\n        for (size_t row = col + 1; row < n; row++) {\n            if (x_out(col, row) == 3) {\n                apply(GateType::S, row);\n            }\n        }\n        for (size_t row = col + 1; row < n; row++) {\n            if (x_out(col, row) == 2) {\n                apply(GateType::H, row);\n            }\n        }\n        for (size_t row = col + 1; row < n; row++) {\n            if (x_out(col, row)) {\n                apply2(GateType::CX, col, row);\n            }\n        }\n\n        // Use the pivot to remove all other terms in the Z observable.\n        for (size_t row = col + 1; row < n; row++) {\n            if (z_out(col, row) == 3) {\n                apply(GateType::S, row);\n            }\n        }\n        for (size_t row = col + 1; row < n; row++) {\n            if (z_out(col, row) == 1) {\n                apply(GateType::H, row);\n            }\n        }\n        for (size_t row = col + 1; row < n; row++) {\n            if (z_out(col, row)) {\n                apply2(GateType::CX, row, col);\n            }\n        }\n    }\n\n    // Fix pauli signs.\n    simd_bits<W> signs_copy = remaining.zs.signs;\n    for (size_t col = 0; col < n; col++) {\n        if (signs_copy[col]) {\n            apply(GateType::H, col);\n        }\n    }\n    for (size_t col = 0; col < n; col++) {\n        if (signs_copy[col]) {\n            apply(GateType::S, col);\n            apply(GateType::S, col);\n        }\n    }\n    for (size_t col = 0; col < n; col++) {\n        if (signs_copy[col]) {\n            apply(GateType::H, col);\n        }\n    }\n    for (size_t col = 0; col < n; col++) {\n        if (remaining.xs.signs[col]) {\n            apply(GateType::S, col);\n            apply(GateType::S, col);\n        }\n    }\n\n    if (recorded_circuit.count_qubits() < n) {\n        apply(GateType::H, n - 1);\n        apply(GateType::H, n - 1);\n    }\n    return recorded_circuit;\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/util_top/circuit_vs_tableau.test.cc",
    "content": "#include \"stim/util_top/circuit_vs_tableau.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(conversions, circuit_to_tableau_ignoring_gates, {\n    Circuit unitary(R\"CIRCUIT(\n        I 0\n        X 0\n        Y 0\n        Z 0\n        C_XYZ 0\n        C_ZYX 0\n        H 0\n        H_XY 0\n        H_XZ 0\n        H_YZ 0\n        S 0\n        SQRT_X 0\n        SQRT_X_DAG 0\n        SQRT_Y 0\n        SQRT_Y_DAG 0\n        SQRT_Z 0\n        SQRT_Z_DAG 0\n        S_DAG 0\n        CNOT 0 1\n        CX 0 1\n        CY 0 1\n        CZ 0 1\n        ISWAP 0 1\n        ISWAP_DAG 0 1\n        SQRT_XX 0 1\n        SQRT_XX_DAG 0 1\n        SQRT_YY 0 1\n        SQRT_YY_DAG 0 1\n        SQRT_ZZ 0 1\n        SQRT_ZZ_DAG 0 1\n        SWAP 0 1\n        XCX 0 1\n        XCY 0 1\n        XCZ 0 1\n        YCX 0 1\n        YCY 0 1\n        YCZ 0 1\n        ZCX 0 1\n        ZCY 0 1\n        ZCZ 0 1\n    )CIRCUIT\");\n    Circuit noise(R\"CIRCUIT(\n        CORRELATED_ERROR(0.1) X0\n        DEPOLARIZE1(0.1) 0\n        DEPOLARIZE2(0.1) 0 1\n        E(0.1) X0\n        ELSE_CORRELATED_ERROR(0.1) Y1\n        PAULI_CHANNEL_1(0.1,0.2,0.3) 0\n        PAULI_CHANNEL_2(0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.01) 0 1\n        X_ERROR(0.1) 0\n        Y_ERROR(0.1) 0\n        Z_ERROR(0.1) 0\n    )CIRCUIT\");\n    Circuit measure(R\"CIRCUIT(\n        M 0\n        MPP X0\n        MX 0\n        MY 0\n        MZ 0\n    )CIRCUIT\");\n    Circuit reset(R\"CIRCUIT(\n        R 0\n        RX 0\n        RY 0\n        RZ 0\n    )CIRCUIT\");\n    Circuit measure_reset(R\"CIRCUIT(\n        MR 0\n        MRX 0\n        MRY 0\n        MRZ 0\n    )CIRCUIT\");\n    Circuit annotations(R\"CIRCUIT(\n        REPEAT 10 {\n            I 0\n        }\n        DETECTOR(1, 2)\n        OBSERVABLE_INCLUDE(1)\n        QUBIT_COORDS(0,1,2) 0\n        SHIFT_COORDS(2, 3, 4)\n        TICK\n    )CIRCUIT\");\n\n    ASSERT_EQ(circuit_to_tableau<W>(unitary, false, false, false).num_qubits, 2);\n\n    ASSERT_THROW({ circuit_to_tableau<W>(noise, false, false, false); }, std::invalid_argument);\n    ASSERT_THROW({ circuit_to_tableau<W>(noise, false, true, true); }, std::invalid_argument);\n    ASSERT_EQ(circuit_to_tableau<W>(noise, true, false, false), Tableau<W>(2));\n\n    ASSERT_THROW({ circuit_to_tableau<W>(measure, false, false, false); }, std::invalid_argument);\n    ASSERT_THROW({ circuit_to_tableau<W>(measure, true, false, true); }, std::invalid_argument);\n    ASSERT_EQ(circuit_to_tableau<W>(measure, false, true, false), Tableau<W>(1));\n\n    ASSERT_THROW({ circuit_to_tableau<W>(reset, false, false, false); }, std::invalid_argument);\n    ASSERT_THROW({ circuit_to_tableau<W>(reset, true, true, false); }, std::invalid_argument);\n    ASSERT_EQ(circuit_to_tableau<W>(reset, false, false, true), Tableau<W>(1));\n\n    ASSERT_THROW({ circuit_to_tableau<W>(measure_reset, false, false, false); }, std::invalid_argument);\n    ASSERT_THROW({ circuit_to_tableau<W>(measure_reset, true, false, true); }, std::invalid_argument);\n    ASSERT_THROW({ circuit_to_tableau<W>(measure_reset, true, true, false); }, std::invalid_argument);\n    ASSERT_EQ(circuit_to_tableau<W>(measure_reset, false, true, true), Tableau<W>(1));\n\n    ASSERT_EQ(circuit_to_tableau<W>(annotations, false, false, false), Tableau<W>(1));\n\n    ASSERT_EQ(\n        circuit_to_tableau<W>(annotations + measure_reset + measure + reset + unitary + noise, true, true, true)\n            .num_qubits,\n        2);\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, circuit_to_tableau, {\n    ASSERT_EQ(\n        circuit_to_tableau<W>(\n            Circuit(R\"CIRCUIT(\n        )CIRCUIT\"),\n            false,\n            false,\n            false),\n        Tableau<W>(0));\n\n    ASSERT_EQ(\n        circuit_to_tableau<W>(\n            Circuit(R\"CIRCUIT(\n            REPEAT 10 {\n                X 0\n                TICK\n            }\n        )CIRCUIT\"),\n            false,\n            false,\n            false),\n        Tableau<W>(1));\n\n    ASSERT_EQ(\n        circuit_to_tableau<W>(\n            Circuit(R\"CIRCUIT(\n            REPEAT 11 {\n                X 0\n                TICK\n            }\n        )CIRCUIT\"),\n            false,\n            false,\n            false),\n        GATE_DATA.at(\"X\").tableau<W>());\n\n    ASSERT_EQ(\n        circuit_to_tableau<W>(\n            Circuit(R\"CIRCUIT(\n            S 0\n        )CIRCUIT\"),\n            false,\n            false,\n            false),\n        GATE_DATA.at(\"S\").tableau<W>());\n\n    ASSERT_EQ(\n        circuit_to_tableau<W>(\n            Circuit(R\"CIRCUIT(\n            SQRT_Y_DAG 1\n            CZ 0 1\n            SQRT_Y 1\n        )CIRCUIT\"),\n            false,\n            false,\n            false),\n        GATE_DATA.at(\"CX\").tableau<W>());\n\n    ASSERT_EQ(\n        circuit_to_tableau<W>(\n            Circuit(R\"CIRCUIT(\n            R 0\n            X_ERROR(0.1) 0\n            SQRT_Y_DAG 1\n            CZ 0 1\n            SQRT_Y 1\n            M 0\n        )CIRCUIT\"),\n            true,\n            true,\n            true),\n        GATE_DATA.at(\"CX\").tableau<W>());\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, tableau_to_circuit_fuzz_vs_circuit_to_tableau, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (size_t n = 0; n < 10; n++) {\n        auto desired = Tableau<W>::random(n, rng);\n        Circuit circuit = tableau_to_circuit<W>(desired, \"elimination\");\n        auto actual = circuit_to_tableau<W>(circuit, false, false, false);\n        ASSERT_EQ(actual, desired);\n\n        for (const auto &op : circuit.operations) {\n            ASSERT_TRUE(op.gate_type == GateType::S || op.gate_type == GateType::H || op.gate_type == GateType::CX)\n                << op;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, tableau_to_circuit, {\n    ASSERT_EQ(tableau_to_circuit<W>(GATE_DATA.at(\"I\").tableau<W>(), \"elimination\"), Circuit(R\"CIRCUIT(\n            H 0\n            H 0\n        )CIRCUIT\"));\n\n    ASSERT_EQ(tableau_to_circuit<W>(GATE_DATA.at(\"X\").tableau<W>(), \"elimination\"), Circuit(R\"CIRCUIT(\n            H 0\n            S 0\n            S 0\n            H 0\n        )CIRCUIT\"));\n\n    ASSERT_EQ(tableau_to_circuit<W>(GATE_DATA.at(\"S\").tableau<W>(), \"elimination\"), Circuit(R\"CIRCUIT(\n            S 0\n        )CIRCUIT\"));\n\n    ASSERT_EQ(tableau_to_circuit<W>(GATE_DATA.at(\"ISWAP\").tableau<W>(), \"elimination\"), Circuit(R\"CIRCUIT(\n            CX 1 0 0 1 1 0\n            S 0\n            H 1\n            CX 0 1\n            H 1\n            S 1\n        )CIRCUIT\"));\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, fuzz_mpp_circuit_produces_correct_state, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto tableau = Tableau<W>::random(10, rng);\n    auto circuit = tableau_to_circuit_mpp_method<W>(tableau, false);\n    TableauSimulator<W> sim(std::move(rng), 10);\n    sim.safe_do_circuit(circuit);\n    auto expected = tableau.stabilizers(true);\n    auto actual = sim.canonical_stabilizers();\n    ASSERT_EQ(actual, expected);\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, fuzz_mpp_circuit_produces_correct_state_unsigned, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto tableau = Tableau<W>::random(10, rng);\n    auto circuit = tableau_to_circuit_mpp_method<W>(tableau, true);\n    TableauSimulator<W> sim(std::move(rng), 10);\n    sim.safe_do_circuit(circuit);\n    auto expected = tableau.stabilizers(true);\n    auto actual = sim.canonical_stabilizers();\n    for (auto &e : expected) {\n        e.sign = false;\n    }\n    for (auto &e : actual) {\n        e.sign = false;\n    }\n    ASSERT_EQ(actual, expected);\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, perfect_code_mpp_circuit, {\n    Tableau<W> tableau(5);\n\n    tableau.zs[0] = PauliString<W>(\"XZZX_\");\n    tableau.zs[1] = PauliString<W>(\"_XZZX\");\n    tableau.zs[2] = PauliString<W>(\"X_XZZ\");\n    tableau.zs[3] = PauliString<W>(\"ZX_XZ\");\n    tableau.zs[4] = PauliString<W>(\"ZZZZZ\");\n\n    tableau.xs[0] = PauliString<W>(\"Z_Z__\");\n    tableau.xs[1] = PauliString<W>(\"ZZZZ_\");\n    tableau.xs[2] = PauliString<W>(\"ZZ_ZZ\");\n    tableau.xs[3] = PauliString<W>(\"_Z__Z\");\n    tableau.xs[4] = PauliString<W>(\"XXXXX\");\n\n    ASSERT_TRUE(tableau.satisfies_invariants());\n\n    ASSERT_EQ(tableau_to_circuit_mpp_method<W>(tableau, true), Circuit(R\"CIRCUIT(\n        MPP X0*Z1*Z2*X3 X1*Z2*Z3*X4 X0*X2*Z3*Z4 Z0*X1*X3*Z4 Z0*Z1*Z2*Z3*Z4\n    )CIRCUIT\"));\n\n    ASSERT_EQ(tableau_to_circuit_mpp_method<W>(tableau, false), Circuit(R\"CIRCUIT(\n        MPP X0*Z1*Z2*X3 X1*Z2*Z3*X4 X0*X2*Z3*Z4 Z0*X1*X3*Z4 Z0*Z1*Z2*Z3*Z4\n        CX rec[-1] 0 rec[-1] 1 rec[-1] 2 rec[-1] 3 rec[-1] 4\n        CZ rec[-5] 0 rec[-5] 2 rec[-4] 0 rec[-4] 1 rec[-4] 2 rec[-4] 3 rec[-3] 0 rec[-3] 1 rec[-3] 3 rec[-3] 4 rec[-2] 1 rec[-2] 4\n    )CIRCUIT\"));\n})\n"
  },
  {
    "path": "src/stim/util_top/count_determined_measurements.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_UTIL_TOP_COUNT_DETERMINED_MEASUREMENTS_H\n#define _STIM_UTIL_TOP_COUNT_DETERMINED_MEASUREMENTS_H\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nuint64_t count_determined_measurements(const Circuit &circuit, bool unknown_input = false);\n\n}  // namespace stim\n\n#include \"stim/util_top/count_determined_measurements.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/count_determined_measurements.inl",
    "content": "#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_top/count_determined_measurements.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nuint64_t count_determined_measurements(const Circuit &circuit, bool unknown_input) {\n    auto n = circuit.count_qubits();\n    TableauSimulator<W> sim(std::mt19937_64{0}, n);\n    if (unknown_input) {\n        sim.ensure_large_enough_for_qubits(2*n);\n        for (uint32_t k = 0; k < n; k++) {\n            std::array<GateTarget, 2> targets{GateTarget::qubit(k), GateTarget::qubit(k + (uint32_t)n)};\n            sim.do_XCX(CircuitInstruction{GateType::XCX, {}, targets, \"\"});\n        }\n        n *= 2;\n    }\n    PauliString<W> obs_buffer(n);\n\n    uint64_t result = 0;\n    circuit.for_each_operation([&](const CircuitInstruction &inst) {\n        if (!(GATE_DATA[inst.gate_type].flags & GATE_PRODUCES_RESULTS)) {\n            sim.do_gate(inst);\n            return;\n        }\n        switch (inst.gate_type) {\n            case GateType::M:\n                [[fallthrough]];\n            case GateType::MR: {\n                for (const auto &t : inst.targets) {\n                    assert(t.is_qubit_target());\n                    result += sim.peek_z(t.qubit_value()) != 0;\n                    sim.do_gate(CircuitInstruction{inst.gate_type, {}, {&t}, \"\"});\n                }\n                break;\n            }\n\n            case GateType::MX:\n                [[fallthrough]];\n            case GateType::MRX: {\n                for (const auto &t : inst.targets) {\n                    assert(t.is_qubit_target());\n                    result += sim.peek_x(t.qubit_value()) != 0;\n                    sim.do_gate(CircuitInstruction{inst.gate_type, {}, {&t}, \"\"});\n                }\n                break;\n            }\n\n            case GateType::MY:\n                [[fallthrough]];\n            case GateType::MRY: {\n                for (const auto &t : inst.targets) {\n                    assert(t.is_qubit_target());\n                    result += sim.peek_y(t.qubit_value()) != 0;\n                    sim.do_gate(CircuitInstruction{inst.gate_type, {}, {&t}, \"\"});\n                }\n                break;\n            }\n\n            case GateType::MXX:\n                [[fallthrough]];\n            case GateType::MYY:\n                [[fallthrough]];\n            case GateType::MZZ: {\n                bool x = inst.gate_type != GateType::MZZ;\n                bool z = inst.gate_type != GateType::MXX;\n                for (size_t k = 0; k < inst.targets.size(); k += 2) {\n                    auto q0 = inst.targets[k].qubit_value();\n                    auto q1 = inst.targets[k + 1].qubit_value();\n                    obs_buffer.xs[q0] = x;\n                    obs_buffer.xs[q1] = x;\n                    obs_buffer.zs[q0] = z;\n                    obs_buffer.zs[q1] = z;\n                    result += sim.peek_observable_expectation(obs_buffer) != 0;\n                    obs_buffer.xs[q0] = 0;\n                    obs_buffer.xs[q1] = 0;\n                    obs_buffer.zs[q0] = 0;\n                    obs_buffer.zs[q1] = 0;\n                    sim.do_gate(CircuitInstruction{inst.gate_type, {}, inst.targets.sub(k, k + 2), \"\"});\n                }\n                break;\n            }\n\n            case GateType::MPP: {\n                for (size_t start = 0; start < inst.targets.size();) {\n                    size_t end = start + 1;\n                    while (end < inst.targets.size() && inst.targets[end].is_combiner()) {\n                        end += 2;\n                    }\n\n                    for (size_t k = start; k < end; k += 2) {\n                        auto t = inst.targets[k];\n                        auto q = t.qubit_value();\n                        obs_buffer.xs[q] = (bool)(t.data & TARGET_PAULI_X_BIT);\n                        obs_buffer.zs[q] = (bool)(t.data & TARGET_PAULI_Z_BIT);\n                    }\n                    result += sim.peek_observable_expectation(obs_buffer) != 0;\n                    obs_buffer.xs.clear();\n                    obs_buffer.zs.clear();\n\n                    sim.do_gate({inst.gate_type, {}, inst.targets.sub(start, end), \"\"});\n                    start = end;\n                }\n                break;\n            }\n            default:\n                throw std::invalid_argument(\"count_determined_measurements unhandled measurement type \" + inst.str());\n        }\n    });\n    return result;\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/util_top/count_determined_measurements.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_top/count_determined_measurements.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/mem/simd_word.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(count_determined_measurements, unknown_input, {\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n            MZZ 0 1\n        )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(\n            Circuit(R\"CIRCUIT(\n            MZZ 0 1\n        )CIRCUIT\"),\n            true),\n        0);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n            MPP Z0*Z1 X2*X3\n        )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(\n            Circuit(R\"CIRCUIT(\n            MPP Z0*Z1 X2*X3\n        )CIRCUIT\"),\n            true),\n        0);\n    ASSERT_EQ(\n        count_determined_measurements<W>(\n            Circuit(R\"CIRCUIT(\n            MPP Z0*Z1 X2*X3\n            TICK\n            MPP Z0*Z1 X2*X3\n        )CIRCUIT\"),\n            true),\n        2);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n            MPP Z0*Z1 X2*X3\n            TICK\n            MPP Z0*Z1 X2*X3\n        )CIRCUIT\")),\n        3);\n})\n\nTEST_EACH_WORD_SIZE_W(count_determined_measurements, single_qubit_measurements_baseline, {\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n    )CIRCUIT\")),\n        0);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MX 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MRX 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RZ 0\n        MX 0\n    )CIRCUIT\")),\n        0);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RZ 0\n        MRX 0\n    )CIRCUIT\")),\n        0);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RY 0\n        MY 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RY 0\n        MRY 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MY 0\n    )CIRCUIT\")),\n        0);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MRY 0\n    )CIRCUIT\")),\n        0);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RZ 0\n        MZ 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RZ 0\n        MRZ 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MZ 0\n    )CIRCUIT\")),\n        0);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MRZ 0\n    )CIRCUIT\")),\n        0);\n})\n\nTEST_EACH_WORD_SIZE_W(count_determined_measurements, pair_measurements_baseline, {\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0 1\n        MXX 0 1\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RY 0 1\n        MXX 0 1\n    )CIRCUIT\")),\n        0);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RY 0 1\n        MYY 0 1\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0 1\n        MYY 0 1\n    )CIRCUIT\")),\n        0);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RZ 0 1\n        MZZ 0 1\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RY 0 1\n        MZZ 0 1\n    )CIRCUIT\")),\n        0);\n})\n\nTEST_EACH_WORD_SIZE_W(count_determined_measurements, mpp_baseline, {\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MPP X0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RY 0\n        MPP X0\n    )CIRCUIT\")),\n        0);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RY 0\n        MPP Y0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MPP Y0\n    )CIRCUIT\")),\n        0);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RZ 0\n        MPP Z0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MPP Z0\n    )CIRCUIT\")),\n        0);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        RY 1\n        RZ 2\n        MPP X0*Y1*Z2\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        RX 1\n        RZ 2\n        MPP X0*Y1*Z2\n    )CIRCUIT\")),\n        0);\n})\n\nTEST_EACH_WORD_SIZE_W(count_determined_measurements, converge, {\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MX 0 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MY 0 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MZ 0 0\n    )CIRCUIT\")),\n        1);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MRX 0 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MRY 0 0\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0\n        MRZ 0 0\n    )CIRCUIT\")),\n        1);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MXX 0 1 0 1\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MYY 0 1 0 1\n    )CIRCUIT\")),\n        1);\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0 1\n        MZZ 0 1 0 1\n    )CIRCUIT\")),\n        1);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MXX 0 1\n        MYY 0 1\n    )CIRCUIT\")),\n        1);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MPP X0*X1 Y0*Y1\n    )CIRCUIT\")),\n        1);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MPP X0*X1 X1*X2 !X0*X2\n    )CIRCUIT\")),\n        1);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        REPEAT 3 {\n            MPP X0*X1\n        }\n    )CIRCUIT\")),\n        2);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MXX 0 1\n        MX 0 1\n    )CIRCUIT\")),\n        1);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        MYY 0 1\n        MY 0 1\n    )CIRCUIT\")),\n        1);\n\n    ASSERT_EQ(\n        count_determined_measurements<W>(Circuit(R\"CIRCUIT(\n        RX 0 1\n        MZZ 0 1\n        MZ 0 1\n    )CIRCUIT\")),\n        1);\n})\n\nTEST_EACH_WORD_SIZE_W(count_determined_measurements, surface_code, {\n    CircuitGenParameters params(7, 5, \"rotated_memory_x\");\n    params.after_clifford_depolarization = 0.01;\n    params.before_measure_flip_probability = 0;\n    params.after_reset_flip_probability = 0;\n    params.before_round_data_depolarization = 0;\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto actual = count_determined_measurements<W>(circuit);\n    ASSERT_EQ(actual, circuit.count_detectors() + circuit.count_observables());\n})\n"
  },
  {
    "path": "src/stim/util_top/export_crumble_url.cc",
    "content": "#include \"stim/util_top/export_crumble_url.h\"\n\n#include \"stim/simulators/matched_error.h\"\n\nusing namespace stim;\n\nvoid write_crumble_name_with_args(const CircuitInstruction &instruction, std::ostream &out) {\n    if (instruction.gate_type == GateType::DETECTOR) {\n        out << \"DT\";\n    } else if (instruction.gate_type == GateType::QUBIT_COORDS) {\n        out << \"Q\";\n    } else if (instruction.gate_type == GateType::OBSERVABLE_INCLUDE) {\n        out << \"OI\";\n    } else {\n        out << GATE_DATA[instruction.gate_type].name;\n    }\n    if (!instruction.args.empty()) {\n        out << '(';\n        bool first = true;\n        for (auto e : instruction.args) {\n            if (first) {\n                first = false;\n            } else {\n                out << \",\";\n            }\n            if (e > (double)INT64_MIN && e < (double)INT64_MAX && (int64_t)e == e) {\n                out << (int64_t)e;\n            } else {\n                out << e;\n            }\n        }\n        out << ')';\n    }\n}\n\nvoid write_crumble_url(\n    const Circuit &circuit,\n    bool skip_detectors,\n    const std::vector<std::pair<int, CircuitErrorLocation>> &marks,\n    std::ostream &out) {\n    ExplainedError err;\n    std::vector<std::pair<int, CircuitErrorLocation>> active_marks;\n    for (size_t k = 0; k < circuit.operations.size(); k++) {\n        active_marks.clear();\n        for (const auto &mark : marks) {\n            if (!mark.second.stack_frames.empty() && mark.second.stack_frames.back().instruction_offset == k) {\n                active_marks.push_back(mark);\n                active_marks.back().second.stack_frames.pop_back();\n            }\n        }\n\n        bool adding_markers = false;\n        for (const auto &mark : active_marks) {\n            adding_markers |= mark.second.stack_frames.empty();\n        }\n        if (adding_markers) {\n            out << \";TICK\";\n        }\n        for (const auto &mark : active_marks) {\n            if (mark.second.stack_frames.empty()) {\n                const auto &v1 = mark.second.flipped_pauli_product;\n                const auto &v2 = mark.second.flipped_measurement.measured_observable;\n                for (const auto &e : v1) {\n                    out << \";MARK\" << e.gate_target.pauli_type() << \"(\" << mark.first << \")\"\n                        << e.gate_target.qubit_value();\n                }\n                if (!v2.empty()) {\n                    auto t = v2[0].gate_target;\n                    char c = \"XZ\"[t.pauli_type() == 'X'];\n                    out << \";MARK\" << c << \"(\" << mark.first << \")\" << v2[0].gate_target.qubit_value();\n                }\n            }\n        }\n        if (adding_markers) {\n            out << \";TICK\";\n        }\n\n        const auto &instruction = circuit.operations[k];\n        if (instruction.gate_type == GateType::DETECTOR && skip_detectors) {\n            continue;\n        }\n        if (k > 0 || adding_markers) {\n            out << ';';\n        }\n\n        if (instruction.gate_type == GateType::REPEAT) {\n            if (active_marks.empty()) {\n                out << \"REPEAT_\" << instruction.repeat_block_rep_count() << \"_{;\";\n                write_crumble_url(instruction.repeat_block_body(circuit), skip_detectors, active_marks, out);\n                out << \";}\";\n            } else {\n                std::vector<std::pair<int, CircuitErrorLocation>> iter_marks;\n                for (size_t k2 = 0; k2 < instruction.repeat_block_rep_count(); k2++) {\n                    iter_marks.clear();\n                    for (const auto &mark : active_marks) {\n                        if (!mark.second.stack_frames.empty() &&\n                            mark.second.stack_frames.back().iteration_index == k2) {\n                            iter_marks.push_back(mark);\n                        }\n                    }\n                    write_crumble_url(instruction.repeat_block_body(circuit), skip_detectors, iter_marks, out);\n                }\n            }\n            continue;\n        }\n        write_crumble_name_with_args(instruction, out);\n\n        for (size_t k2 = 0; k2 < instruction.targets.size(); k2++) {\n            auto target = instruction.targets[k2];\n            if (target.is_combiner()) {\n                out << '*';\n                k2 += 1;\n                target = instruction.targets[k2];\n            } else if (k2 > 0 || instruction.args.empty()) {\n                out << '_';\n            }\n            target.write_succinct(out);\n        }\n    }\n}\n\nstd::string stim::export_crumble_url(\n    const Circuit &circuit, bool skip_detectors, const std::map<int, std::vector<ExplainedError>> &mark) {\n    std::vector<std::pair<int, CircuitErrorLocation>> marks;\n    for (const auto &[k, vs] : mark) {\n        for (const auto &v : vs) {\n            if (!v.circuit_error_locations.empty()) {\n                marks.push_back({k, v.circuit_error_locations[0]});\n            }\n        }\n    }\n    std::stringstream s;\n    s << \"https://algassert.com/crumble#circuit=\";\n    write_crumble_url(circuit, skip_detectors, marks, s);\n    s << \"_\";  // This is a workaround for colab clipping a single character off the end of the URL in some contexts\n    return s.str();\n}\n"
  },
  {
    "path": "src/stim/util_top/export_crumble_url.h",
    "content": "#ifndef _STIM_UTIL_TOP_EXPORT_CRUMBLE_URL_H\n#define _STIM_UTIL_TOP_EXPORT_CRUMBLE_URL_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/simulators/matched_error.h\"\n\nnamespace stim {\n\nstd::string export_crumble_url(\n    const Circuit &circuit, bool skip_detectors = false, const std::map<int, std::vector<ExplainedError>> &mark = {});\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/export_crumble_url.test.cc",
    "content": "#include \"stim/util_top/export_crumble_url.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/search/graphlike/algo.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/simulators/error_matcher.h\"\n\nusing namespace stim;\n\nTEST(export_crumble, all_operations) {\n    auto actual = export_crumble_url(generate_test_circuit_with_all_operations());\n    auto expected =\n        \"https://algassert.com/crumble#circuit=\"\n        \"Q(1,2,3)0;\"\n        \"I_0;\"\n        \"X_1;\"\n        \"Y_2;\"\n        \"Z_3;\"\n        \"TICK;\"\n        \"C_XYZ_0;\"\n        \"C_NXYZ_1;\"\n        \"C_XNYZ_2;\"\n        \"C_XYNZ_3;\"\n        \"C_ZYX_4;\"\n        \"C_NZYX_5;\"\n        \"C_ZNYX_6;\"\n        \"C_ZYNX_7;\"\n        \"H_XY_0;\"\n        \"H_1;\"\n        \"H_YZ_2;\"\n        \"H_NXY_3;\"\n        \"H_NXZ_4;\"\n        \"H_NYZ_5;\"\n        \"SQRT_X_0;\"\n        \"SQRT_X_DAG_1;\"\n        \"SQRT_Y_2;\"\n        \"SQRT_Y_DAG_3;\"\n        \"S_4;\"\n        \"S_DAG_5;\"\n        \"TICK;\"\n        \"CXSWAP_0_1;\"\n        \"ISWAP_2_3;\"\n        \"ISWAP_DAG_4_5;\"\n        \"SWAP_6_7;\"\n        \"SWAPCX_8_9;\"\n        \"CZSWAP_10_11;\"\n        \"SQRT_XX_0_1;\"\n        \"SQRT_XX_DAG_2_3;\"\n        \"SQRT_YY_4_5;\"\n        \"SQRT_YY_DAG_6_7;\"\n        \"SQRT_ZZ_8_9;\"\n        \"SQRT_ZZ_DAG_10_11;\"\n        \"II_12_13;\"\n        \"XCX_0_1;\"\n        \"XCY_2_3;\"\n        \"XCZ_4_5;\"\n        \"YCX_6_7;\"\n        \"YCY_8_9;\"\n        \"YCZ_10_11;\"\n        \"CX_12_13;\"\n        \"CY_14_15;\"\n        \"CZ_16_17;\"\n        \"TICK;\"\n        \"E(0.01)X1_Y2_Z3;\"\n        \"ELSE_CORRELATED_ERROR(0.02)X4_Y7_Z6;\"\n        \"DEPOLARIZE1(0.02)0;\"\n        \"DEPOLARIZE2(0.03)1_2;\"\n        \"PAULI_CHANNEL_1(0.01,0.02,0.03)3;\"\n        \"PAULI_CHANNEL_2(0.001,0.002,0.003,0.004,0.005,0.006,0.007,0.008,0.009,0.01,0.011,0.012,0.013,0.014,0.015)4_5;\"\n        \"X_ERROR(0.01)0;\"\n        \"Y_ERROR(0.02)1;\"\n        \"Z_ERROR(0.03)2;\"\n        \"HERALDED_ERASE(0.04)3;\"\n        \"HERALDED_PAULI_CHANNEL_1(0.01,0.02,0.03,0.04)6;\"\n        \"I_ERROR(0.06)7;\"\n        \"II_ERROR(0.07)8_9;\"\n        \"TICK;\"\n        \"MPP_X0*Y1*Z2_Z0*Z1;\"\n        \"SPP_X0*Y1*Z2_X3;\"\n        \"SPP_DAG_X0*Y1*Z2_X2;\"\n        \"TICK;\"\n        \"MRX_0;\"\n        \"MRY_1;\"\n        \"MR_2;\"\n        \"MX_3;\"\n        \"MY_4;\"\n        \"M_5_6;\"\n        \"RX_7;\"\n        \"RY_8;\"\n        \"R_9;\"\n        \"TICK;\"\n        \"MXX_0_1_2_3;\"\n        \"MYY_4_5;\"\n        \"MZZ_6_7;\"\n        \"TICK;\"\n        \"REPEAT_3_{;\"\n        \"H_0;\"\n        \"CX_0_1;\"\n        \"S_1;\"\n        \"TICK;\"\n        \"};\"\n        \"TICK;\"\n        \"MR_0;\"\n        \"X_ERROR(0.1)0;\"\n        \"MR(0.01)0;\"\n        \"SHIFT_COORDS(1,2,3);\"\n        \"DT(1,2,3)rec[-1];\"\n        \"OI(0)rec[-1];\"\n        \"MPAD_0_1_0;\"\n        \"OI(1)Z2_Z3;\"\n        \"TICK;\"\n        \"MRX_!0;\"\n        \"MY_!1;\"\n        \"MZZ_!2_3;\"\n        \"OI(1)rec[-1];\"\n        \"MYY_!4_!5;\"\n        \"MPP_X6*!Y7*Z8;\"\n        \"TICK;\"\n        \"CX_rec[-1]_0;\"\n        \"CY_sweep[0]_1;\"\n        \"CZ_2_rec[-1]\"\n        \"_\";\n    ASSERT_EQ(actual, expected);\n}\n\nTEST(export_crumble, graphlike_error) {\n    Circuit circuit(R\"CIRCUIT(\n        R 0 1 2 3\n        X_ERROR(0.125) 0 1\n        M 0 1\n        M(0.125) 2 3\n        DETECTOR rec[-1] rec[-2]\n        DETECTOR rec[-2] rec[-3]\n        DETECTOR rec[-3] rec[-4]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\");\n    DetectorErrorModel dem =\n        ErrorAnalyzer::circuit_to_detector_error_model(circuit, false, true, false, 1, false, false);\n    DetectorErrorModel filter = shortest_graphlike_undetectable_logical_error(dem, false);\n    auto error = ErrorMatcher::explain_errors_from_circuit(circuit, &filter, false);\n\n    auto actual = export_crumble_url(circuit, true, {{0, error}});\n    auto expected =\n        \"https://algassert.com/crumble#circuit=\"\n        \"R_0_1_2_3;\"\n        \"TICK;\"\n        \"MARKX(0)1;\"\n        \"MARKX(0)0;\"\n        \"TICK;\"\n        \"X_ERROR(0.125)0_1;\"\n        \"M_0_1;\"\n        \"TICK;\"\n        \"MARKX(0)2;\"\n        \"MARKX(0)3;\"\n        \"TICK;\"\n        \"M(0.125)2_3;\"\n        \"OI(0)rec[-1]\"\n        \"_\";\n    ASSERT_EQ(actual, expected);\n}\n"
  },
  {
    "path": "src/stim/util_top/export_crumble_url_pybind_test.py",
    "content": "import stim\n\n\ndef test_to_crumble_url_simple():\n    c = stim.Circuit(\"\"\"\n        QUBIT_COORDS(2, 1) 0\n        QUBIT_COORDS(2, 2) 1\n        H 0\n        TICK\n        CX 0 1\n        TICK\n        C_XYZ 0\n        S 1\n        TICK\n        MZZ 1 0\n    \"\"\")\n    assert c.to_crumble_url() == \"https://algassert.com/crumble#circuit=Q(2,1)0;Q(2,2)1;H_0;TICK;CX_0_1;TICK;C_XYZ_0;S_1;TICK;MZZ_1_0_\"\n\n\ndef test_to_crumble_url_complex():\n    c = stim.Circuit.generated('surface_code:rotated_memory_x', distance=3, rounds=2, after_clifford_depolarization=0.001)\n    assert 'DEPOLARIZE1' in c.to_crumble_url()\n\n\ndef test_to_crumble_url_mark_error():\n    c = stim.Circuit.generated('surface_code:rotated_memory_x', distance=3, rounds=2, after_clifford_depolarization=0.001, before_round_data_depolarization=0.001)\n    err = c.shortest_graphlike_error(canonicalize_circuit_errors=True)\n    url = c.to_crumble_url(skip_detectors=True, mark={1: err})\n    assert 'MARKZ' in url\n    assert 'DT' not in url\n"
  },
  {
    "path": "src/stim/util_top/export_qasm.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_top/export_qasm.h\"\n\n#include <bitset>\n\n#include \"stim/simulators/tableau_simulator.h\"\n\nusing namespace stim;\n\nstruct QasmExporter {\n    std::ostream &out;\n    CircuitStats stats;\n    int open_qasm_version;\n    bool skip_dets_and_obs;\n    simd_bits<64> reference_sample;\n    uint64_t measurement_offset;\n    uint64_t detector_offset;\n    std::array<const char *, NUM_DEFINED_GATES> qasm_names{};\n    std::bitset<NUM_DEFINED_GATES> used_gates{};\n    std::stringstream buf_q1;\n    std::stringstream buf_q2;\n    std::stringstream buf_m;\n\n    QasmExporter() = delete;\n    QasmExporter(const QasmExporter &) = delete;\n    QasmExporter(QasmExporter &&) = delete;\n    QasmExporter(std::ostream &out, const Circuit &circuit, int open_qasm_version, bool skip_dets_and_obs)\n        : out(out),\n          stats(circuit.compute_stats()),\n          open_qasm_version(open_qasm_version),\n          skip_dets_and_obs(skip_dets_and_obs),\n          reference_sample(stats.num_measurements),\n          measurement_offset(0),\n          detector_offset(0) {\n        // Init used_gates.\n        collect_used_gates(circuit);\n\n        // Init reference_sample.\n        if (stats.num_detectors > 0 || stats.num_observables > 0) {\n            reference_sample = TableauSimulator<64>::reference_sample_circuit(circuit);\n        }\n    }\n\n    void output_measurement(bool invert_measurement_result, const char *q_name, const char *m_name) {\n        if (invert_measurement_result) {\n            if (open_qasm_version == 3) {\n                out << \"measure \" << q_name << \" -> \" << m_name << \";\";\n                out << m_name << \" = \" << m_name << \" ^ 1;\";\n            } else {\n                out << \"x \" << q_name << \";\";\n                out << \"measure \" << q_name << \" -> \" << m_name << \";\";\n                out << \"x \" << q_name << \";\";\n            }\n        } else {\n            out << \"measure \" << q_name << \" -> \" << m_name << \";\";\n        }\n    }\n\n    void output_decomposed_operation(\n        bool invert_measurement_result, GateType g, const char *q0_name, const char *q1_name, const char *m_name) {\n        auto q2n = [&](GateTarget t) {\n            return t.qubit_value() == 0 ? q0_name : q1_name;\n        };\n        bool first = true;\n        for (const auto &inst : Circuit(GATE_DATA[g].h_s_cx_m_r_decomposition).operations) {\n            switch (inst.gate_type) {\n                case GateType::S:\n                    for (const auto &t : inst.targets) {\n                        if (!first) {\n                            out << \" \";\n                        }\n                        first = false;\n                        out << \"s \" << q2n(t) << \";\";\n                    }\n                    break;\n                case GateType::H:\n                    for (const auto &t : inst.targets) {\n                        if (!first) {\n                            out << \" \";\n                        }\n                        first = false;\n                        out << \"h \" << q2n(t) << \";\";\n                    }\n                    break;\n                case GateType::R:\n                    for (const auto &t : inst.targets) {\n                        if (!first) {\n                            out << \" \";\n                        }\n                        first = false;\n                        out << \"reset \" << q2n(t) << \";\";\n                    }\n                    break;\n                case GateType::CX:\n                    for (size_t k = 0; k < inst.targets.size(); k += 2) {\n                        if (!first) {\n                            out << \" \";\n                        }\n                        first = false;\n                        auto t1 = inst.targets[k];\n                        auto t2 = inst.targets[k + 1];\n                        out << \"cx \" << q2n(t1) << \", \" << q2n(t2) << \";\";\n                    }\n                    break;\n                case GateType::M:\n                    for (const auto &t : inst.targets) {\n                        if (!first) {\n                            out << \" \";\n                        }\n                        first = false;\n                        output_measurement(invert_measurement_result, q2n(t), m_name);\n                    }\n                    break;\n                default:\n                    throw std::invalid_argument(\"Unhandled: \" + inst.str());\n            }\n        }\n    }\n\n    void output_decomposed_mpp_operation(const CircuitInstruction &inst) {\n        out << \"// --- begin decomposed \" << inst << \"\\n\";\n        decompose_mpp_operation(inst, stats.num_qubits, [&](const CircuitInstruction &inst) {\n            output_instruction(inst);\n        });\n        out << \"// --- end decomposed MPP\\n\";\n    }\n\n    void output_decomposed_spp_or_spp_dag_operation(const CircuitInstruction &inst) {\n        out << \"// --- begin decomposed \" << inst << \"\\n\";\n        decompose_spp_or_spp_dag_operation(inst, stats.num_qubits, false, [&](const CircuitInstruction &inst) {\n            output_instruction(inst);\n        });\n        out << \"// --- end decomposed SPP\\n\";\n    }\n\n    void output_decomposable_instruction(const CircuitInstruction &instruction, bool decompose_inline) {\n        auto f = GATE_DATA[instruction.gate_type].flags;\n        auto step = (f & GATE_TARGETS_PAIRS) ? 2 : 1;\n        for (size_t k = 0; k < instruction.targets.size(); k += step) {\n            auto t0 = instruction.targets[k];\n            auto t1 = instruction.targets[k + step - 1];\n            bool invert_measurement_result = t0.is_inverted_result_target();\n            if (step == 2) {\n                invert_measurement_result ^= t1.is_inverted_result_target();\n            }\n            if (decompose_inline) {\n                buf_q1.str(\"\");\n                buf_q2.str(\"\");\n                buf_q1 << \"q[\" << t0.qubit_value() << \"]\";\n                buf_q2 << \"q[\" << t1.qubit_value() << \"]\";\n                if (f & GATE_PRODUCES_RESULTS) {\n                    buf_m.str(\"\");\n                    buf_m << \"rec[\" << measurement_offset << \"]\";\n                    measurement_offset++;\n                }\n                output_decomposed_operation(\n                    invert_measurement_result,\n                    instruction.gate_type,\n                    buf_q1.str().c_str(),\n                    buf_q2.str().c_str(),\n                    buf_m.str().c_str());\n                out << \" // decomposed \" << GATE_DATA[instruction.gate_type].name << \"\\n\";\n            } else {\n                if (f & GATE_PRODUCES_RESULTS) {\n                    out << \"rec[\" << measurement_offset << \"] = \";\n                    measurement_offset++;\n                }\n                out << qasm_names[(int)instruction.gate_type] << \"(\";\n                out << \"q[\" << t0.qubit_value() << \"]\";\n                if (step == 2) {\n                    out << \", q[\" << t1.qubit_value() << \"]\";\n                }\n                out << \")\";\n                if ((f & GATE_PRODUCES_RESULTS) && invert_measurement_result) {\n                    out << \" ^ 1\";\n                }\n                out << \";\\n\";\n            }\n        }\n    }\n\n    void output_two_qubit_unitary_instruction_with_possible_feedback(const CircuitInstruction &instruction) {\n        for (size_t k = 0; k < instruction.targets.size(); k += 2) {\n            auto t1 = instruction.targets[k];\n            auto t2 = instruction.targets[k + 1];\n            if (t1.is_qubit_target() && t2.is_qubit_target()) {\n                out << qasm_names[(int)instruction.gate_type] << \" q[\" << t1.qubit_value() << \"], q[\"\n                    << t2.qubit_value() << \"];\\n\";\n            } else if (t1.is_qubit_target() || t2.is_qubit_target()) {\n                GateTarget control;\n                GateTarget target;\n                char basis;\n                switch (instruction.gate_type) {\n                    case GateType::CX:\n                        basis = 'X';\n                        control = t1;\n                        target = t2;\n                        break;\n                    case GateType::CY:\n                        basis = 'Y';\n                        control = t1;\n                        target = t2;\n                        break;\n                    case GateType::CZ:\n                        basis = 'Z';\n                        control = t1;\n                        target = t2;\n                        if (control.is_qubit_target()) {\n                            std::swap(control, target);\n                        }\n                        break;\n                    case GateType::XCZ:\n                        basis = 'X';\n                        control = t2;\n                        target = t1;\n                        break;\n                    case GateType::YCZ:\n                        basis = 'Y';\n                        control = t2;\n                        target = t1;\n                        break;\n                    default:\n                        throw std::invalid_argument(\n                            \"Not implemented in output_two_qubit_unitary_instruction_with_possible_feedback: \" +\n                            instruction.str());\n                }\n\n                out << \"if (\";\n                if (control.is_measurement_record_target()) {\n                    if (open_qasm_version == 2) {\n                        throw std::invalid_argument(\n                            \"The circuit contains feedback, but OPENQASM 2 doesn't support feedback.\\n\"\n                            \"You can use `stim.Circuit.with_inlined_feedback` to drop feedback operations.\\n\"\n                            \"Alternatively, pass the argument `open_qasm_version=3`.\");\n                    }\n                    out << \"ms[\" << (measurement_offset + control.rec_offset()) << \"]\";\n                } else if (control.is_sweep_bit_target()) {\n                    if (open_qasm_version == 2) {\n                        throw std::invalid_argument(\n                            \"The circuit contains sweep operation, but OPENQASM 2 doesn't support feedback.\\n\"\n                            \"Remove these operations, or pass the argument `open_qasm_version=3`.\");\n                    }\n                    out << \"sweep[\" << control.value() << \"]\";\n                } else {\n                    throw std::invalid_argument(\n                        \"Not implemented in output_two_qubit_unitary_instruction_with_possible_feedback: \" +\n                        instruction.str());\n                }\n                out << \") {\\n\";\n                out << \"    \" << basis << \" q[\" << target.qubit_value() << \"];\\n\";\n                out << \"}\\n\";\n            }\n        }\n    }\n\n    void define_custom_single_qubit_gate(GateType g, const char *name) {\n        const auto &gate = GATE_DATA[g];\n        qasm_names[(int)g] = name;\n        if (!used_gates[(int)g]) {\n            return;\n        }\n\n        out << \"gate \" << name << \" q0 { U(\";\n        auto xyz = gate.to_euler_angles();\n        std::array<const char *, 4> angles{\"0\", \"pi/2\", \"pi\", \"-pi/2\"};\n        out << angles[(int)round(xyz[0] / 3.14159265359f) & 3];\n        out << \", \" << angles[(int)round(xyz[1] / 3.14159265359f) & 3];\n        out << \", \" << angles[(int)round(xyz[2] / 3.14159265359f) & 3];\n        out << \") q0; }\\n\";\n    }\n\n    void define_custom_decomposed_gate(GateType g, const char *name) {\n        const auto &gate = GATE_DATA[g];\n        qasm_names[(int)g] = name;\n        if (!used_gates[(int)g]) {\n            return;\n        }\n\n        Circuit c(gate.h_s_cx_m_r_decomposition);\n        bool is_unitary = true;\n        for (const auto &inst : c.operations) {\n            is_unitary &= (GATE_DATA[inst.gate_type].flags & GATE_IS_UNITARY) != 0;\n        }\n        auto num_measurements = c.count_measurements();\n        if (is_unitary) {\n            out << \"gate \" << name;\n            out << \" q0\";\n            if (gate.flags & GateFlags::GATE_TARGETS_PAIRS) {\n                out << \", q1\";\n            }\n            out << \" { \";\n        } else {\n            if (open_qasm_version == 2) {\n                // Have to decompose inline in the circuit.\n                return;\n            }\n            out << \"def \" << name << \"(qubit q0\";\n            if (gate.flags & GateFlags::GATE_TARGETS_PAIRS) {\n                out << \", qubit q1\";\n            }\n            out << \")\";\n            if (num_measurements > 1) {\n                throw std::invalid_argument(\"Multiple measurement gates not supported.\");\n            } else if (num_measurements == 1) {\n                out << \" -> bit { bit b; \";\n            } else {\n                out << \" { \";\n            }\n        }\n\n        output_decomposed_operation(false, g, \"q0\", \"q1\", \"b\");\n        if (num_measurements > 0) {\n            out << \" return b;\";\n        }\n        out << \" }\\n\";\n    }\n\n    void collect_used_gates(const Circuit &c) {\n        for (const auto &inst : c.operations) {\n            used_gates[(int)inst.gate_type] = true;\n            if (inst.gate_type == GateType::REPEAT) {\n                collect_used_gates(inst.repeat_block_body(c));\n            }\n        }\n    }\n\n    void output_header() {\n        if (open_qasm_version == 2) {\n            out << \"OPENQASM 2.0;\\n\";\n        } else {\n            out << \"OPENQASM 3.0;\\n\";\n        }\n    }\n\n    void output_storage_declarations() {\n        if (stats.num_qubits > 0) {\n            out << \"qreg q[\" << stats.num_qubits << \"];\\n\";\n        }\n        if (stats.num_measurements > 0) {\n            out << \"creg rec[\" << stats.num_measurements << \"];\\n\";\n        }\n        if (stats.num_detectors > 0 && !skip_dets_and_obs) {\n            out << \"creg dets[\" << stats.num_detectors << \"];\\n\";\n        }\n        if (stats.num_observables > 0 && !skip_dets_and_obs) {\n            out << \"creg obs[\" << stats.num_observables << \"];\\n\";\n        }\n        if (stats.num_sweep_bits > 0) {\n            out << \"creg sweep[\" << stats.num_sweep_bits << \"];\\n\";\n        }\n        out << \"\\n\";\n    }\n\n    void define_all_gates_and_output_gate_declarations() {\n        if (open_qasm_version == 2) {\n            out << \"include \\\"qelib1.inc\\\";\\n\";\n        } else if (open_qasm_version == 3) {\n            out << \"include \\\"stdgates.inc\\\";\\n\";\n        } else {\n            throw std::invalid_argument(\"Unrecognized open_qasm_version.\");\n        }\n        qasm_names[(int)GateType::I] = \"id\";\n        qasm_names[(int)GateType::X] = \"x\";\n        qasm_names[(int)GateType::Y] = \"y\";\n        qasm_names[(int)GateType::Z] = \"z\";\n        qasm_names[(int)GateType::SQRT_X] = \"sx\";\n        qasm_names[(int)GateType::SQRT_X_DAG] = \"sxdg\";\n        qasm_names[(int)GateType::S] = \"s\";\n        qasm_names[(int)GateType::S_DAG] = \"sdg\";\n        qasm_names[(int)GateType::CX] = \"cx\";\n        qasm_names[(int)GateType::CY] = \"cy\";\n        qasm_names[(int)GateType::CZ] = \"cz\";\n        qasm_names[(int)GateType::SWAP] = \"swap\";\n        qasm_names[(int)GateType::H] = \"h\";\n        define_custom_single_qubit_gate(GateType::C_XYZ, \"cxyz\");\n        define_custom_single_qubit_gate(GateType::C_ZYX, \"czyx\");\n        define_custom_single_qubit_gate(GateType::C_NXYZ, \"cnxyz\");\n        define_custom_single_qubit_gate(GateType::C_XNYZ, \"cxnyz\");\n        define_custom_single_qubit_gate(GateType::C_XYNZ, \"cxynz\");\n        define_custom_single_qubit_gate(GateType::C_NZYX, \"cnzyx\");\n        define_custom_single_qubit_gate(GateType::C_ZNYX, \"cznyx\");\n        define_custom_single_qubit_gate(GateType::C_ZYNX, \"czynx\");\n        define_custom_single_qubit_gate(GateType::H_XY, \"hxy\");\n        define_custom_single_qubit_gate(GateType::H_YZ, \"hyz\");\n        define_custom_single_qubit_gate(GateType::H_NXY, \"hnxy\");\n        define_custom_single_qubit_gate(GateType::H_NXZ, \"hnxz\");\n        define_custom_single_qubit_gate(GateType::H_NYZ, \"hnyz\");\n        define_custom_single_qubit_gate(GateType::SQRT_Y, \"sy\");\n        define_custom_single_qubit_gate(GateType::SQRT_Y_DAG, \"sydg\");\n\n        define_custom_decomposed_gate(GateType::CXSWAP, \"cxswap\");\n        define_custom_decomposed_gate(GateType::CZSWAP, \"czswap\");\n        define_custom_decomposed_gate(GateType::ISWAP, \"iswap\");\n        define_custom_decomposed_gate(GateType::ISWAP_DAG, \"iswapdg\");\n        define_custom_decomposed_gate(GateType::SQRT_XX, \"sxx\");\n        define_custom_decomposed_gate(GateType::SQRT_XX_DAG, \"sxxdg\");\n        define_custom_decomposed_gate(GateType::SQRT_YY, \"syy\");\n        define_custom_decomposed_gate(GateType::SQRT_YY_DAG, \"syydg\");\n        define_custom_decomposed_gate(GateType::SQRT_ZZ, \"szz\");\n        define_custom_decomposed_gate(GateType::SQRT_ZZ_DAG, \"szzdg\");\n        define_custom_decomposed_gate(GateType::SWAPCX, \"swapcx\");\n        define_custom_decomposed_gate(GateType::XCX, \"xcx\");\n        define_custom_decomposed_gate(GateType::XCY, \"xcy\");\n        define_custom_decomposed_gate(GateType::XCZ, \"xcz\");\n        define_custom_decomposed_gate(GateType::YCX, \"ycx\");\n        define_custom_decomposed_gate(GateType::YCY, \"ycy\");\n        define_custom_decomposed_gate(GateType::YCZ, \"ycz\");\n\n        define_custom_decomposed_gate(GateType::MR, \"mr\");\n        define_custom_decomposed_gate(GateType::MRX, \"mrx\");\n        define_custom_decomposed_gate(GateType::MRY, \"mry\");\n        define_custom_decomposed_gate(GateType::MX, \"mx\");\n        define_custom_decomposed_gate(GateType::MXX, \"mxx\");\n        define_custom_decomposed_gate(GateType::MY, \"my\");\n        define_custom_decomposed_gate(GateType::MYY, \"myy\");\n        define_custom_decomposed_gate(GateType::MZZ, \"mzz\");\n        define_custom_decomposed_gate(GateType::RX, \"rx\");\n        define_custom_decomposed_gate(GateType::RY, \"ry\");\n\n        out << \"\\n\";\n    }\n\n    void output_instruction(const CircuitInstruction &instruction) {\n        GateFlags f = GATE_DATA[instruction.gate_type].flags;\n\n        switch (instruction.gate_type) {\n            case GateType::QUBIT_COORDS:\n            case GateType::SHIFT_COORDS:\n            case GateType::II:\n            case GateType::I_ERROR:\n            case GateType::II_ERROR:\n                // Skipped.\n                return;\n\n            case GateType::MPAD:\n                for (const auto &t : instruction.targets) {\n                    if (open_qasm_version == 3) {\n                        out << \"rec[\" << measurement_offset << \"] = \" << t.qubit_value() << \";\\n\";\n                    } else {\n                        if (t.qubit_value()) {\n                            throw std::invalid_argument(\n                                \"The circuit contains a vacuous measurement with a non-zero result \"\n                                \"(like MPAD 1 or MPP !X1*X1) but OPENQASM 2 doesn't support classical assignment.\\n\"\n                                \"Pass the argument `open_qasm_version=3` to fix this.\");\n                        }\n                    }\n                    measurement_offset++;\n                }\n                return;\n\n            case GateType::TICK:\n                out << \"barrier q;\\n\\n\";\n                return;\n\n            case GateType::M:\n                for (const auto &t : instruction.targets) {\n                    if (t.is_inverted_result_target()) {\n                        if (open_qasm_version == 3) {\n                            out << \"measure q[\" << t.qubit_value() << \"] -> rec[\" << measurement_offset << \"];\";\n                            out << \"rec[\" << measurement_offset << \"] = rec[\" << measurement_offset << \"] ^ 1;\";\n                        } else {\n                            out << \"x q[\" << t.qubit_value() << \"];\";\n                            out << \"measure q[\" << t.qubit_value() << \"] -> rec[\" << measurement_offset << \"];\";\n                            out << \"x q[\" << t.qubit_value() << \"];\";\n                        }\n                    } else {\n                        out << \"measure q[\" << t.qubit_value() << \"] -> rec[\" << measurement_offset << \"];\";\n                    }\n                    out << \"\\n\";\n                    measurement_offset++;\n                }\n                return;\n            case GateType::R:\n                for (const auto &t : instruction.targets) {\n                    out << \"reset q[\" << t.qubit_value() << \"];\\n\";\n                }\n                return;\n            case GateType::DETECTOR:\n            case GateType::OBSERVABLE_INCLUDE: {\n                if (skip_dets_and_obs) {\n                    return;\n                }\n                if (open_qasm_version == 2) {\n                    throw std::invalid_argument(\n                        \"The circuit contains detectors or observables, but OPENQASM 2 doesn't support the operations \"\n                        \"needed for accumulating detector and observable values.\\n\"\n                        \"To simply ignore detectors and observables, pass the argument `skip_dets_and_obs=True`.\\n\"\n                        \"Alternatively, pass the argument `open_qasm_version=3`.\");\n                }\n                if (instruction.gate_type == GateType::DETECTOR) {\n                    out << \"dets[\" << detector_offset << \"] = \";\n                    detector_offset++;\n                } else {\n                    out << \"obs[\" << (int)instruction.args[0] << \"] = obs[\" << (int)instruction.args[0] << \"] ^ \";\n                }\n\n                int ref_value = 0;\n                bool had_paulis = false;\n                for (auto t : instruction.targets) {\n                    if (t.is_measurement_record_target()) {\n                        auto i = measurement_offset + t.rec_offset();\n                        ref_value ^= reference_sample[i];\n                        out << \"rec[\" << (measurement_offset + t.rec_offset()) << \"] ^ \";\n                    } else if (t.is_pauli_target()) {\n                        had_paulis = true;\n                    } else {\n                        throw std::invalid_argument(\"Unexpected target for OBSERVABLE_INCLUDE: \" + t.str());\n                    }\n                }\n                out << ref_value << \";\\n\";\n\n                if (had_paulis) {\n                    out << \"// Warning: ignored pauli terms in \" << instruction << \"\\n\";\n                }\n                return;\n            }\n\n            case GateType::DEPOLARIZE1:\n            case GateType::DEPOLARIZE2:\n            case GateType::X_ERROR:\n            case GateType::Y_ERROR:\n            case GateType::Z_ERROR:\n            case GateType::PAULI_CHANNEL_1:\n            case GateType::PAULI_CHANNEL_2:\n            case GateType::E:\n            case GateType::ELSE_CORRELATED_ERROR:\n            case GateType::HERALDED_ERASE:\n            case GateType::HERALDED_PAULI_CHANNEL_1:\n                throw std::invalid_argument(\n                    \"The circuit contains noise, but OPENQASM 2 doesn't support noise operations.\\n\"\n                    \"Use `stim.Circuit.without_noise` to get a version of the circuit without noise.\");\n\n            case GateType::MPP:\n                output_decomposed_mpp_operation(instruction);\n                return;\n            case GateType::SPP:\n            case GateType::SPP_DAG:\n                output_decomposed_spp_or_spp_dag_operation(instruction);\n                return;\n\n            default:\n                break;\n        }\n\n        if (f & (stim::GATE_IS_RESET | stim::GATE_PRODUCES_RESULTS)) {\n            output_decomposable_instruction(instruction, open_qasm_version == 2);\n            return;\n        }\n\n        if (f & stim::GATE_IS_UNITARY) {\n            if (f & stim::GATE_IS_SINGLE_QUBIT_GATE) {\n                for (const auto &t : instruction.targets) {\n                    assert(t.is_qubit_target());\n                    out << qasm_names[(int)instruction.gate_type] << \" q[\" << t.qubit_value() << \"];\\n\";\n                }\n                return;\n            }\n            if (f & stim::GATE_TARGETS_PAIRS) {\n                output_two_qubit_unitary_instruction_with_possible_feedback(instruction);\n                return;\n            }\n        }\n\n        throw std::invalid_argument(\"Not implemented in QasmExporter::output_instruction: \" + instruction.str());\n    }\n};\n\nvoid stim::export_open_qasm(const Circuit &circuit, std::ostream &out, int open_qasm_version, bool skip_dets_and_obs) {\n    if (open_qasm_version != 2 && open_qasm_version != 3) {\n        throw std::invalid_argument(\"Only open_qasm_version=2 and open_qasm_version=3 are supported.\");\n    }\n\n    QasmExporter exporter(out, circuit, open_qasm_version, skip_dets_and_obs);\n    exporter.output_header();\n    exporter.define_all_gates_and_output_gate_declarations();\n    exporter.output_storage_declarations();\n    circuit.for_each_operation([&](const CircuitInstruction &instruction) {\n        exporter.output_instruction(instruction);\n    });\n}\n"
  },
  {
    "path": "src/stim/util_top/export_qasm.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_CIRCUIT_EXPORT_CIRCUIT_H\n#define _STIM_CIRCUIT_EXPORT_CIRCUIT_H\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim {\n\nvoid export_open_qasm(const Circuit &circuit, std::ostream &out, int open_qasm_version, bool skip_dets_and_obs);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/export_qasm.test.cc",
    "content": "#include \"stim/util_top/export_qasm.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n#include \"stim/util_top/transform_without_feedback.h\"\n\nusing namespace stim;\n\nTEST(export_qasm, export_open_qasm_feedback) {\n    Circuit c(R\"CIRCUIT(\n        H 0\n        CX 0 1\n        C_XYZ 1\n        M 0\n        CX rec[-1] 1\n        CX sweep[5] 1\n        TICK\n        H 0\n    )CIRCUIT\");\n    std::stringstream out;\n    export_open_qasm(c, out, 3, false);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 3.0;\ninclude \"stdgates.inc\";\ngate cxyz q0 { U(pi/2, 0, pi/2) q0; }\n\nqreg q[2];\ncreg rec[1];\ncreg sweep[6];\n\nh q[0];\ncx q[0], q[1];\ncxyz q[1];\nmeasure q[0] -> rec[0];\nif (ms[0]) {\n    X q[1];\n}\nif (sweep[5]) {\n    X q[1];\n}\nbarrier q;\n\nh q[0];\n)QASM\");\n}\n\nTEST(export_qasm, export_open_qasm_inverted_measurements) {\n    Circuit c(R\"CIRCUIT(\n        M !0\n        MX !0\n        MXX !0 1\n        MPP !X0*Z1\n    )CIRCUIT\");\n    std::stringstream out;\n    export_open_qasm(c, out, 3, false);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 3.0;\ninclude \"stdgates.inc\";\ndef mx(qubit q0) -> bit { bit b; h q0; measure q0 -> b; h q0; return b; }\ndef mxx(qubit q0, qubit q1) -> bit { bit b; cx q0, q1; h q0; measure q0 -> b; h q0; cx q0, q1; return b; }\n\nqreg q[2];\ncreg rec[4];\n\nmeasure q[0] -> rec[0];rec[0] = rec[0] ^ 1;\nrec[1] = mx(q[0]) ^ 1;\nrec[2] = mxx(q[0], q[1]) ^ 1;\n// --- begin decomposed MPP !X0*Z1\nh q[0];\ncx q[1], q[0];\nmeasure q[0] -> rec[3];rec[3] = rec[3] ^ 1;\ncx q[1], q[0];\nh q[0];\n// --- end decomposed MPP\n)QASM\");\n}\n\nTEST(export_qasm, export_open_qasm_qec) {\n    Circuit c(R\"CIRCUIT(\n        R 0 1 2\n        TICK\n        X 0\n        TICK\n        CX 0 1\n        TICK\n        CX 2 1\n        TICK\n        M 1\n        DETECTOR rec[-1]\n        TICK\n        R 1\n        TICK\n        CX 0 1\n        TICK\n        CX 2 1\n        TICK\n        M 0 1 2\n        DETECTOR rec[-2] rec[-4]\n        DETECTOR rec[-1] rec[-2] rec[-3]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\");\n\n    std::stringstream out;\n    export_open_qasm(c, out, 3, false);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 3.0;\ninclude \"stdgates.inc\";\n\nqreg q[3];\ncreg rec[4];\ncreg dets[3];\ncreg obs[1];\n\nreset q[0];\nreset q[1];\nreset q[2];\nbarrier q;\n\nx q[0];\nbarrier q;\n\ncx q[0], q[1];\nbarrier q;\n\ncx q[2], q[1];\nbarrier q;\n\nmeasure q[1] -> rec[0];\ndets[0] = rec[0] ^ 1;\nbarrier q;\n\nreset q[1];\nbarrier q;\n\ncx q[0], q[1];\nbarrier q;\n\ncx q[2], q[1];\nbarrier q;\n\nmeasure q[0] -> rec[1];\nmeasure q[1] -> rec[2];\nmeasure q[2] -> rec[3];\ndets[1] = rec[2] ^ rec[0] ^ 0;\ndets[2] = rec[3] ^ rec[2] ^ rec[1] ^ 0;\nobs[0] = obs[0] ^ rec[3] ^ 0;\n)QASM\");\n\n    out.str(\"\");\n    export_open_qasm(c, out, 2, true);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 2.0;\ninclude \"qelib1.inc\";\n\nqreg q[3];\ncreg rec[4];\n\nreset q[0];\nreset q[1];\nreset q[2];\nbarrier q;\n\nx q[0];\nbarrier q;\n\ncx q[0], q[1];\nbarrier q;\n\ncx q[2], q[1];\nbarrier q;\n\nmeasure q[1] -> rec[0];\nbarrier q;\n\nreset q[1];\nbarrier q;\n\ncx q[0], q[1];\nbarrier q;\n\ncx q[2], q[1];\nbarrier q;\n\nmeasure q[0] -> rec[1];\nmeasure q[1] -> rec[2];\nmeasure q[2] -> rec[3];\n)QASM\");\n}\n\nTEST(export_qasm, export_open_qasm_mpad) {\n    Circuit c(R\"CIRCUIT(\n        H 0\n        MPAD 0 1 0\n        M 0\n    )CIRCUIT\");\n\n    std::stringstream out;\n    export_open_qasm(c, out, 3, false);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 3.0;\ninclude \"stdgates.inc\";\n\nqreg q[1];\ncreg rec[4];\n\nh q[0];\nrec[0] = 0;\nrec[1] = 1;\nrec[2] = 0;\nmeasure q[0] -> rec[3];\n)QASM\");\n\n    out.str(\"\");\n    ASSERT_THROW({ export_open_qasm(c, out, 2, true); }, std::invalid_argument);\n    c = Circuit(R\"CIRCUIT(\n        H 0\n        MPAD 0 0 0\n        M 0\n    )CIRCUIT\");\n\n    out.str(\"\");\n    export_open_qasm(c, out, 2, true);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 2.0;\ninclude \"qelib1.inc\";\n\nqreg q[1];\ncreg rec[4];\n\nh q[0];\nmeasure q[0] -> rec[3];\n)QASM\");\n}\n\nTEST(export_qasm, export_qasm_decomposed_operations) {\n    Circuit c(R\"CIRCUIT(\n        R 3\n        RX 0 1\n        MX 2\n        TICK\n\n        MXX 0 1\n        DETECTOR rec[-1]\n        TICK\n\n        M 2\n        MR 3\n        MRX 4\n    )CIRCUIT\");\n\n    std::stringstream out;\n    export_open_qasm(c, out, 3, false);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 3.0;\ninclude \"stdgates.inc\";\ndef mr(qubit q0) -> bit { bit b; measure q0 -> b; reset q0; return b; }\ndef mrx(qubit q0) -> bit { bit b; h q0; measure q0 -> b; reset q0; h q0; return b; }\ndef mx(qubit q0) -> bit { bit b; h q0; measure q0 -> b; h q0; return b; }\ndef mxx(qubit q0, qubit q1) -> bit { bit b; cx q0, q1; h q0; measure q0 -> b; h q0; cx q0, q1; return b; }\ndef rx(qubit q0) { reset q0; h q0; }\n\nqreg q[5];\ncreg rec[5];\ncreg dets[1];\n\nreset q[3];\nrx(q[0]);\nrx(q[1]);\nrec[0] = mx(q[2]);\nbarrier q;\n\nrec[1] = mxx(q[0], q[1]);\ndets[0] = rec[1] ^ 0;\nbarrier q;\n\nmeasure q[2] -> rec[2];\nrec[3] = mr(q[3]);\nrec[4] = mrx(q[4]);\n)QASM\");\n\n    out.str(\"\");\n    export_open_qasm(c, out, 2, true);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 2.0;\ninclude \"qelib1.inc\";\n\nqreg q[5];\ncreg rec[5];\n\nreset q[3];\nreset q[0]; h q[0]; // decomposed RX\nreset q[1]; h q[1]; // decomposed RX\nh q[2]; measure q[2] -> rec[0]; h q[2]; // decomposed MX\nbarrier q;\n\ncx q[0], q[1]; h q[0]; measure q[0] -> rec[1]; h q[0]; cx q[0], q[1]; // decomposed MXX\nbarrier q;\n\nmeasure q[2] -> rec[2];\nmeasure q[3] -> rec[3]; reset q[3]; // decomposed MR\nh q[4]; measure q[4] -> rec[4]; reset q[4]; h q[4]; // decomposed MRX\n)QASM\");\n}\n\nTEST(export_qasm, export_qasm_all_operations_v3) {\n    Circuit c = generate_test_circuit_with_all_operations();\n    c = c.without_noise();\n\n    std::stringstream out;\n    export_open_qasm(c, out, 3, false);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 3.0;\ninclude \"stdgates.inc\";\ngate cxyz q0 { U(pi/2, 0, pi/2) q0; }\ngate czyx q0 { U(pi/2, pi/2, pi/2) q0; }\ngate cnxyz q0 { U(pi/2, pi/2, pi/2) q0; }\ngate cxnyz q0 { U(pi/2, 0, -pi/2) q0; }\ngate cxynz q0 { U(pi/2, pi/2, -pi/2) q0; }\ngate cnzyx q0 { U(pi/2, -pi/2, 0) q0; }\ngate cznyx q0 { U(pi/2, -pi/2, pi/2) q0; }\ngate czynx q0 { U(pi/2, pi/2, 0) q0; }\ngate hxy q0 { U(pi/2, 0, pi/2) q0; }\ngate hyz q0 { U(pi/2, pi/2, pi/2) q0; }\ngate hnxy q0 { U(pi/2, 0, -pi/2) q0; }\ngate hnxz q0 { U(pi/2, pi/2, 0) q0; }\ngate hnyz q0 { U(pi/2, -pi/2, -pi/2) q0; }\ngate sy q0 { U(pi/2, 0, 0) q0; }\ngate sydg q0 { U(pi/2, pi/2, pi/2) q0; }\ngate cxswap q0, q1 { cx q1, q0; cx q0, q1; }\ngate czswap q0, q1 { h q0; cx q0, q1; cx q1, q0; h q1; }\ngate iswap q0, q1 { h q0; cx q0, q1; cx q1, q0; h q1; s q1; s q0; }\ngate iswapdg q0, q1 { s q0; s q0; s q0; s q1; s q1; s q1; h q1; cx q1, q0; cx q0, q1; h q0; }\ngate sxx q0, q1 { h q0; cx q0, q1; h q1; s q0; s q1; h q0; h q1; }\ngate sxxdg q0, q1 { h q0; cx q0, q1; h q1; s q0; s q0; s q0; s q1; s q1; s q1; h q0; h q1; }\ngate syy q0, q1 { s q0; s q0; s q0; s q1; s q1; s q1; h q0; cx q0, q1; h q1; s q0; s q1; h q0; h q1; s q0; s q1; }\ngate syydg q0, q1 { s q0; s q0; s q0; s q1; h q0; cx q0, q1; h q1; s q0; s q1; h q0; h q1; s q0; s q1; s q1; s q1; }\ngate szz q0, q1 { h q1; cx q0, q1; h q1; s q0; s q1; }\ngate szzdg q0, q1 { h q1; cx q0, q1; h q1; s q0; s q0; s q0; s q1; s q1; s q1; }\ngate swapcx q0, q1 { cx q0, q1; cx q1, q0; }\ngate xcx q0, q1 { h q0; cx q0, q1; h q0; }\ngate xcy q0, q1 { h q0; s q1; s q1; s q1; cx q0, q1; h q0; s q1; }\ngate xcz q0, q1 { cx q1, q0; }\ngate ycx q0, q1 { s q0; s q0; s q0; h q1; cx q1, q0; s q0; h q1; }\ngate ycy q0, q1 { s q0; s q0; s q0; s q1; s q1; s q1; h q0; cx q0, q1; h q0; s q0; s q1; }\ngate ycz q0, q1 { s q0; s q0; s q0; cx q1, q0; s q0; }\ndef mr(qubit q0) -> bit { bit b; measure q0 -> b; reset q0; return b; }\ndef mrx(qubit q0) -> bit { bit b; h q0; measure q0 -> b; reset q0; h q0; return b; }\ndef mry(qubit q0) -> bit { bit b; s q0; s q0; s q0; h q0; measure q0 -> b; reset q0; h q0; s q0; return b; }\ndef mx(qubit q0) -> bit { bit b; h q0; measure q0 -> b; h q0; return b; }\ndef mxx(qubit q0, qubit q1) -> bit { bit b; cx q0, q1; h q0; measure q0 -> b; h q0; cx q0, q1; return b; }\ndef my(qubit q0) -> bit { bit b; s q0; s q0; s q0; h q0; measure q0 -> b; h q0; s q0; return b; }\ndef myy(qubit q0, qubit q1) -> bit { bit b; s q0; s q1; cx q0, q1; h q0; measure q0 -> b; s q1; s q1; h q0; cx q0, q1; s q0; s q1; return b; }\ndef mzz(qubit q0, qubit q1) -> bit { bit b; cx q0, q1; measure q1 -> b; cx q0, q1; return b; }\ndef rx(qubit q0) { reset q0; h q0; }\ndef ry(qubit q0) { reset q0; h q0; s q0; }\n\nqreg q[18];\ncreg rec[25];\ncreg dets[1];\ncreg obs[2];\ncreg sweep[1];\n\nid q[0];\nx q[1];\ny q[2];\nz q[3];\nbarrier q;\n\ncxyz q[0];\ncnxyz q[1];\ncxnyz q[2];\ncxynz q[3];\nczyx q[4];\ncnzyx q[5];\ncznyx q[6];\nczynx q[7];\nhxy q[0];\nh q[1];\nhyz q[2];\nhnxy q[3];\nhnxz q[4];\nhnyz q[5];\nsx q[0];\nsxdg q[1];\nsy q[2];\nsydg q[3];\ns q[4];\nsdg q[5];\nbarrier q;\n\ncxswap q[0], q[1];\niswap q[2], q[3];\niswapdg q[4], q[5];\nswap q[6], q[7];\nswapcx q[8], q[9];\nczswap q[10], q[11];\nsxx q[0], q[1];\nsxxdg q[2], q[3];\nsyy q[4], q[5];\nsyydg q[6], q[7];\nszz q[8], q[9];\nszzdg q[10], q[11];\nxcx q[0], q[1];\nxcy q[2], q[3];\nxcz q[4], q[5];\nycx q[6], q[7];\nycy q[8], q[9];\nycz q[10], q[11];\ncx q[12], q[13];\ncy q[14], q[15];\ncz q[16], q[17];\nbarrier q;\n\nrec[0] = 0;\nrec[1] = 0;\nbarrier q;\n\n// --- begin decomposed MPP X0*Y1*Z2 Z0*Z1\nh q[0];\nhyz q[1];\ncx q[1], q[0];\ncx q[2], q[0];\nmeasure q[0] -> rec[2];\ncx q[1], q[0];\ncx q[2], q[0];\nhyz q[1];\nh q[0];\ncx q[1], q[0];\nmeasure q[0] -> rec[3];\ncx q[1], q[0];\n// --- end decomposed MPP\n// --- begin decomposed SPP X0*Y1*Z2 X3\nh q[0];\nhyz q[1];\ncx q[1], q[0];\ncx q[2], q[0];\ns q[0];\ncx q[1], q[0];\ncx q[2], q[0];\nhyz q[1];\nh q[0];\nh q[3];\ns q[3];\nh q[3];\n// --- end decomposed SPP\n// --- begin decomposed SPP_DAG X0*Y1*Z2 X2\nh q[0];\nhyz q[1];\ncx q[1], q[0];\ncx q[2], q[0];\nsdg q[0];\ncx q[1], q[0];\ncx q[2], q[0];\nhyz q[1];\nh q[0];\nh q[2];\nsdg q[2];\nh q[2];\n// --- end decomposed SPP\nbarrier q;\n\nrec[4] = mrx(q[0]);\nrec[5] = mry(q[1]);\nrec[6] = mr(q[2]);\nrec[7] = mx(q[3]);\nrec[8] = my(q[4]);\nmeasure q[5] -> rec[9];\nmeasure q[6] -> rec[10];\nrx(q[7]);\nry(q[8]);\nreset q[9];\nbarrier q;\n\nrec[11] = mxx(q[0], q[1]);\nrec[12] = mxx(q[2], q[3]);\nrec[13] = myy(q[4], q[5]);\nrec[14] = mzz(q[6], q[7]);\nbarrier q;\n\nh q[0];\ncx q[0], q[1];\ns q[1];\nbarrier q;\n\nh q[0];\ncx q[0], q[1];\ns q[1];\nbarrier q;\n\nh q[0];\ncx q[0], q[1];\ns q[1];\nbarrier q;\n\nbarrier q;\n\nrec[15] = mr(q[0]);\nrec[16] = mr(q[0]);\ndets[0] = rec[16] ^ 0;\nobs[0] = obs[0] ^ rec[16] ^ 0;\nrec[17] = 0;\nrec[18] = 1;\nrec[19] = 0;\nobs[1] = obs[1] ^ 0;\n// Warning: ignored pauli terms in OBSERVABLE_INCLUDE(1) Z2 Z3\nbarrier q;\n\nrec[20] = mrx(q[0]) ^ 1;\nrec[21] = my(q[1]) ^ 1;\nrec[22] = mzz(q[2], q[3]) ^ 1;\nobs[1] = obs[1] ^ rec[22] ^ 1;\nrec[23] = myy(q[4], q[5]);\n// --- begin decomposed MPP X6*!Y7*Z8\nh q[6];\nhyz q[7];\ncx q[7], q[6];\ncx q[8], q[6];\nmeasure q[6] -> rec[24];rec[24] = rec[24] ^ 1;\ncx q[7], q[6];\ncx q[8], q[6];\nhyz q[7];\nh q[6];\n// --- end decomposed MPP\nbarrier q;\n\nif (ms[24]) {\n    X q[0];\n}\nif (sweep[0]) {\n    Y q[1];\n}\nif (ms[24]) {\n    Z q[2];\n}\n)QASM\");\n}\n\nTEST(export_qasm, export_qasm_all_operations_v2) {\n    Circuit c = generate_test_circuit_with_all_operations();\n    c = c.without_noise();\n\n    std::stringstream out;\n    c = circuit_with_inlined_feedback(c);\n    for (size_t k = 0; k < c.operations.size(); k++) {\n        bool drop = false;\n        for (auto t : c.operations[k].targets) {\n            drop |= t.is_sweep_bit_target();\n            drop |= c.operations[k].gate_type == GateType::MPAD && t.qubit_value() > 0;\n        }\n        if (drop) {\n            c.operations.erase(c.operations.begin() + k);\n            k--;\n        }\n    }\n    export_open_qasm(c, out, 2, true);\n    ASSERT_EQ(out.str(), R\"QASM(OPENQASM 2.0;\ninclude \"qelib1.inc\";\ngate cxyz q0 { U(pi/2, 0, pi/2) q0; }\ngate czyx q0 { U(pi/2, pi/2, pi/2) q0; }\ngate cnxyz q0 { U(pi/2, pi/2, pi/2) q0; }\ngate cxnyz q0 { U(pi/2, 0, -pi/2) q0; }\ngate cxynz q0 { U(pi/2, pi/2, -pi/2) q0; }\ngate cnzyx q0 { U(pi/2, -pi/2, 0) q0; }\ngate cznyx q0 { U(pi/2, -pi/2, pi/2) q0; }\ngate czynx q0 { U(pi/2, pi/2, 0) q0; }\ngate hxy q0 { U(pi/2, 0, pi/2) q0; }\ngate hyz q0 { U(pi/2, pi/2, pi/2) q0; }\ngate hnxy q0 { U(pi/2, 0, -pi/2) q0; }\ngate hnxz q0 { U(pi/2, pi/2, 0) q0; }\ngate hnyz q0 { U(pi/2, -pi/2, -pi/2) q0; }\ngate sy q0 { U(pi/2, 0, 0) q0; }\ngate sydg q0 { U(pi/2, pi/2, pi/2) q0; }\ngate cxswap q0, q1 { cx q1, q0; cx q0, q1; }\ngate czswap q0, q1 { h q0; cx q0, q1; cx q1, q0; h q1; }\ngate iswap q0, q1 { h q0; cx q0, q1; cx q1, q0; h q1; s q1; s q0; }\ngate iswapdg q0, q1 { s q0; s q0; s q0; s q1; s q1; s q1; h q1; cx q1, q0; cx q0, q1; h q0; }\ngate sxx q0, q1 { h q0; cx q0, q1; h q1; s q0; s q1; h q0; h q1; }\ngate sxxdg q0, q1 { h q0; cx q0, q1; h q1; s q0; s q0; s q0; s q1; s q1; s q1; h q0; h q1; }\ngate syy q0, q1 { s q0; s q0; s q0; s q1; s q1; s q1; h q0; cx q0, q1; h q1; s q0; s q1; h q0; h q1; s q0; s q1; }\ngate syydg q0, q1 { s q0; s q0; s q0; s q1; h q0; cx q0, q1; h q1; s q0; s q1; h q0; h q1; s q0; s q1; s q1; s q1; }\ngate szz q0, q1 { h q1; cx q0, q1; h q1; s q0; s q1; }\ngate szzdg q0, q1 { h q1; cx q0, q1; h q1; s q0; s q0; s q0; s q1; s q1; s q1; }\ngate swapcx q0, q1 { cx q0, q1; cx q1, q0; }\ngate xcx q0, q1 { h q0; cx q0, q1; h q0; }\ngate xcy q0, q1 { h q0; s q1; s q1; s q1; cx q0, q1; h q0; s q1; }\ngate xcz q0, q1 { cx q1, q0; }\ngate ycx q0, q1 { s q0; s q0; s q0; h q1; cx q1, q0; s q0; h q1; }\ngate ycy q0, q1 { s q0; s q0; s q0; s q1; s q1; s q1; h q0; cx q0, q1; h q0; s q0; s q1; }\ngate ycz q0, q1 { s q0; s q0; s q0; cx q1, q0; s q0; }\n\nqreg q[18];\ncreg rec[22];\n\nid q[0];\nx q[1];\ny q[2];\nz q[3];\nbarrier q;\n\ncxyz q[0];\ncnxyz q[1];\ncxnyz q[2];\ncxynz q[3];\nczyx q[4];\ncnzyx q[5];\ncznyx q[6];\nczynx q[7];\nhxy q[0];\nh q[1];\nhyz q[2];\nhnxy q[3];\nhnxz q[4];\nhnyz q[5];\nsx q[0];\nsxdg q[1];\nsy q[2];\nsydg q[3];\ns q[4];\nsdg q[5];\nbarrier q;\n\ncxswap q[0], q[1];\niswap q[2], q[3];\niswapdg q[4], q[5];\nswap q[6], q[7];\nswapcx q[8], q[9];\nczswap q[10], q[11];\nsxx q[0], q[1];\nsxxdg q[2], q[3];\nsyy q[4], q[5];\nsyydg q[6], q[7];\nszz q[8], q[9];\nszzdg q[10], q[11];\nxcx q[0], q[1];\nxcy q[2], q[3];\nxcz q[4], q[5];\nycx q[6], q[7];\nycy q[8], q[9];\nycz q[10], q[11];\ncx q[12], q[13];\ncy q[14], q[15];\ncz q[16], q[17];\nbarrier q;\n\nbarrier q;\n\n// --- begin decomposed MPP X0*Y1*Z2 Z0*Z1\nh q[0];\nhyz q[1];\ncx q[1], q[0];\ncx q[2], q[0];\nmeasure q[0] -> rec[2];\ncx q[1], q[0];\ncx q[2], q[0];\nhyz q[1];\nh q[0];\ncx q[1], q[0];\nmeasure q[0] -> rec[3];\ncx q[1], q[0];\n// --- end decomposed MPP\n// --- begin decomposed SPP X0*Y1*Z2 X3\nh q[0];\nhyz q[1];\ncx q[1], q[0];\ncx q[2], q[0];\ns q[0];\ncx q[1], q[0];\ncx q[2], q[0];\nhyz q[1];\nh q[0];\nh q[3];\ns q[3];\nh q[3];\n// --- end decomposed SPP\n// --- begin decomposed SPP_DAG X0*Y1*Z2 X2\nh q[0];\nhyz q[1];\ncx q[1], q[0];\ncx q[2], q[0];\nsdg q[0];\ncx q[1], q[0];\ncx q[2], q[0];\nhyz q[1];\nh q[0];\nh q[2];\nsdg q[2];\nh q[2];\n// --- end decomposed SPP\nbarrier q;\n\nh q[0]; measure q[0] -> rec[4]; reset q[0]; h q[0]; // decomposed MRX\ns q[1]; s q[1]; s q[1]; h q[1]; measure q[1] -> rec[5]; reset q[1]; h q[1]; s q[1]; // decomposed MRY\nmeasure q[2] -> rec[6]; reset q[2]; // decomposed MR\nh q[3]; measure q[3] -> rec[7]; h q[3]; // decomposed MX\ns q[4]; s q[4]; s q[4]; h q[4]; measure q[4] -> rec[8]; h q[4]; s q[4]; // decomposed MY\nmeasure q[5] -> rec[9];\nmeasure q[6] -> rec[10];\nreset q[7]; h q[7]; // decomposed RX\nreset q[8]; h q[8]; s q[8]; // decomposed RY\nreset q[9];\nbarrier q;\n\ncx q[0], q[1]; h q[0]; measure q[0] -> rec[11]; h q[0]; cx q[0], q[1]; // decomposed MXX\ncx q[2], q[3]; h q[2]; measure q[2] -> rec[12]; h q[2]; cx q[2], q[3]; // decomposed MXX\ns q[4]; s q[5]; cx q[4], q[5]; h q[4]; measure q[4] -> rec[13]; s q[5]; s q[5]; h q[4]; cx q[4], q[5]; s q[4]; s q[5]; // decomposed MYY\ncx q[6], q[7]; measure q[7] -> rec[14]; cx q[6], q[7]; // decomposed MZZ\nbarrier q;\n\nh q[0];\ncx q[0], q[1];\ns q[1];\nbarrier q;\n\nh q[0];\ncx q[0], q[1];\ns q[1];\nbarrier q;\n\nh q[0];\ncx q[0], q[1];\ns q[1];\nbarrier q;\n\nbarrier q;\n\nmeasure q[0] -> rec[15]; reset q[0]; // decomposed MR\nmeasure q[0] -> rec[16]; reset q[0]; // decomposed MR\nbarrier q;\n\nh q[0]; x q[0];measure q[0] -> rec[17];x q[0]; reset q[0]; h q[0]; // decomposed MRX\ns q[1]; s q[1]; s q[1]; h q[1]; x q[1];measure q[1] -> rec[18];x q[1]; h q[1]; s q[1]; // decomposed MY\ncx q[2], q[3]; x q[3];measure q[3] -> rec[19];x q[3]; cx q[2], q[3]; // decomposed MZZ\ns q[4]; s q[5]; cx q[4], q[5]; h q[4]; measure q[4] -> rec[20]; s q[5]; s q[5]; h q[4]; cx q[4], q[5]; s q[4]; s q[5]; // decomposed MYY\n// --- begin decomposed MPP X6*!Y7*Z8\nh q[6];\nhyz q[7];\ncx q[7], q[6];\ncx q[8], q[6];\nx q[6];measure q[6] -> rec[21];x q[6];\ncx q[7], q[6];\ncx q[8], q[6];\nhyz q[7];\nh q[6];\n// --- end decomposed MPP\nbarrier q;\n\n)QASM\");\n}\n"
  },
  {
    "path": "src/stim/util_top/export_qasm_pybind_test.py",
    "content": "import pytest\nimport stim\n\n\ndef test_to_qasm_exact_strings():\n    c = stim.Circuit(\"\"\"\n        RX 0 1\n        TICK\n        H 1\n        CX 0 1\n        TICK\n        M 0 1\n        DETECTOR rec[-1] rec[-2]\n        C_XYZ 0\n    \"\"\")\n\n    assert c.to_qasm(open_qasm_version=3).strip() == \"\"\"\nOPENQASM 3.0;\ninclude \"stdgates.inc\";\ngate cxyz q0 { U(pi/2, 0, pi/2) q0; }\ndef rx(qubit q0) { reset q0; h q0; }\n\nqreg q[2];\ncreg rec[2];\ncreg dets[1];\n\nrx(q[0]);\nrx(q[1]);\nbarrier q;\n\nh q[1];\ncx q[0], q[1];\nbarrier q;\n\nmeasure q[0] -> rec[0];\nmeasure q[1] -> rec[1];\ndets[0] = rec[1] ^ rec[0] ^ 0;\ncxyz q[0];\n    \"\"\".strip()\n\n    assert c.to_qasm(open_qasm_version=2, skip_dets_and_obs=True).strip() == \"\"\"\nOPENQASM 2.0;\ninclude \"qelib1.inc\";\ngate cxyz q0 { U(pi/2, 0, pi/2) q0; }\n\nqreg q[2];\ncreg rec[2];\n\nreset q[0]; h q[0]; // decomposed RX\nreset q[1]; h q[1]; // decomposed RX\nbarrier q;\n\nh q[1];\ncx q[0], q[1];\nbarrier q;\n\nmeasure q[0] -> rec[0];\nmeasure q[1] -> rec[1];\ncxyz q[0];\n    \"\"\".strip()\n\n\ndef test_to_qasm2_runs_in_qiskit():\n    pytest.importorskip(\"qiskit\")\n    pytest.importorskip(\"qiskit_aer\")\n    import qiskit\n    import qiskit_aer\n\n    stim_circuit = stim.Circuit(\"\"\"\n        R 0 1\n        MZZ !0 1\n        MPAD 0 0\n    \"\"\")\n    qasm = stim_circuit.to_qasm(open_qasm_version=2)\n\n    qiskit_circuit = qiskit.QuantumCircuit.from_qasm_str(qasm)\n    counts = qiskit_aer.AerSimulator().run(qiskit_circuit, shots=8).result().get_counts(qiskit_circuit)\n    assert counts['001'] == 8\n\n\ndef test_to_qasm3_parses_in_qiskit():\n    pytest.importorskip(\"qiskit\")\n    pytest.importorskip(\"qiskit_qasm3_import\")\n    import qiskit.qasm3\n\n    # Note: can't really exercise this because currently `qiskit.qasm3.loads`\n    # fails on subroutines, classical assignments, and all the other non-qasm-2\n    # stuff that's actually worth testing.\n    stim_circuit = stim.Circuit(\"\"\"\n        R 0 1\n        SQRT_XX 0 1\n        M 0 1\n    \"\"\")\n\n    qiskit_circuit = qiskit.qasm3.loads(stim_circuit.to_qasm(open_qasm_version=3))\n    assert qiskit_circuit is not None\n"
  },
  {
    "path": "src/stim/util_top/export_quirk_url.cc",
    "content": "#include \"stim/util_top/export_quirk_url.h\"\n\n#include \"stim/circuit/gate_decomposition.h\"\n\nusing namespace stim;\n\nstatic void for_each_target_group(\n    CircuitInstruction instruction, const std::function<void(CircuitInstruction)> &callback) {\n    Gate g = GATE_DATA[instruction.gate_type];\n    if (g.flags & GATE_TARGETS_COMBINERS) {\n        return for_each_combined_targets_group(instruction, callback);\n    } else if (g.flags & GATE_TARGETS_PAIRS) {\n        for (size_t k = 0; k < instruction.targets.size(); k += 2) {\n            callback({instruction.gate_type, instruction.args, instruction.targets.sub(k, k + 2), instruction.tag});\n        }\n    } else if (g.flags & GATE_IS_SINGLE_QUBIT_GATE) {\n        for (GateTarget t : instruction.targets) {\n            callback({instruction.gate_type, instruction.args, &t, instruction.tag});\n        }\n    } else {\n        callback(instruction);\n    }\n}\n\nstruct QuirkExporter {\n    size_t num_qubits;\n    size_t col_offset = 0;\n    std::array<bool, NUM_DEFINED_GATES> used{};\n    std::array<std::string_view, NUM_DEFINED_GATES> stim_name_to_quirk_name{};\n    std::array<std::pair<std::string_view, std::string_view>, NUM_DEFINED_GATES> control_target_type{};\n    std::array<std::string_view, NUM_DEFINED_GATES> phase_type{};\n    std::array<std::string_view, NUM_DEFINED_GATES> custom_gate_definition{};\n    std::map<size_t, std::map<size_t, std::string>> cols;\n\n    QuirkExporter(size_t num_qubits) : num_qubits(num_qubits) {\n        custom_gate_definition[(int)GateType::H_XY] =\n            R\"URL({\"id\":\"~Hxy\",\"name\":\"Hxy\",\"matrix\":\"{{0,-√½-√½i},{√½-√½i,0}}\"})URL\";\n        custom_gate_definition[(int)GateType::H_YZ] =\n            R\"URL({\"id\":\"~Hyz\",\"name\":\"Hyz\",\"matrix\":\"{{-√½i,-√½},{√½,√½i}}\"})URL\";\n        custom_gate_definition[(int)GateType::H_NXY] =\n            R\"URL({\"id\":\"~Hnxy\",\"name\":\"Hnxy\",\"matrix\":\"{{0,√½+√½i},{√½-√½i,0}}\"})URL\";\n        custom_gate_definition[(int)GateType::H_NXZ] =\n            R\"URL({\"id\":\"~Hnxz\",\"name\":\"Hnxz\",\"matrix\":\"{{-√½,√½},{√½,√½}}\"})URL\";\n        custom_gate_definition[(int)GateType::H_NYZ] =\n            R\"URL({\"id\":\"~Hnyz\",\"name\":\"Hnyz\",\"matrix\":\"{{-√½,-√½i},{√½i,√½}}\"})URL\";\n\n        custom_gate_definition[(int)GateType::C_XYZ] =\n            R\"URL({\"id\":\"~Cxyz\",\"name\":\"Cxyz\",\"matrix\":\"{{½-½i,-½-½i},{½-½i,½+½i}}\"})URL\";\n        custom_gate_definition[(int)GateType::C_NXYZ] =\n            R\"URL({\"id\":\"~Cnxyz\",\"name\":\"Cnxyz\",\"matrix\":\"{{½+½i,½-½i},{-½-½i,½-½i}}\"})URL\";\n        custom_gate_definition[(int)GateType::C_XNYZ] =\n            R\"URL({\"id\":\"~Cxnyz\",\"name\":\"Cxnyz\",\"matrix\":\"{{½+½i,-½+½i},{½+½i,½-½i}}\"})URL\";\n        custom_gate_definition[(int)GateType::C_XYNZ] =\n            R\"URL({\"id\":\"~Cxynz\",\"name\":\"Cxynz\",\"matrix\":\"{{½-½i,½+½i},{-½+½i,½+½i}}\"})URL\";\n\n        custom_gate_definition[(int)GateType::C_ZYX] =\n            R\"URL({\"id\":\"~Czyx\",\"name\":\"Czyx\",\"matrix\":\"{{½+½i,½+½i},{-½+½i,½-½i}}\"})URL\";\n        custom_gate_definition[(int)GateType::C_ZYNX] =\n            R\"URL({\"id\":\"~Czynx\",\"name\":\"Czynx\",\"matrix\":\"{{½-½i,-½+½i},{½+½i,½+½i}}\"})URL\";\n        custom_gate_definition[(int)GateType::C_ZNYX] =\n            R\"URL({\"id\":\"~Cznyx\",\"name\":\"Cznyx\",\"matrix\":\"{{½-½i,½-½i},{-½-½i,½+½i}}\"})URL\";\n        custom_gate_definition[(int)GateType::C_NZYX] =\n            R\"URL({\"id\":\"~Cnzyx\",\"name\":\"Cnzyx\",\"matrix\":\"{{½+½i,-½-½i},{½-½i,½-½i}}\"})URL\";\n\n        stim_name_to_quirk_name[(int)GateType::H] = \"H\";\n        stim_name_to_quirk_name[(int)GateType::H_XY] = \"~Hxy\";\n        stim_name_to_quirk_name[(int)GateType::H_YZ] = \"~Hyz\";\n        stim_name_to_quirk_name[(int)GateType::H_NXY] = \"~Hnxy\";\n        stim_name_to_quirk_name[(int)GateType::H_NXZ] = \"~Hnxz\";\n        stim_name_to_quirk_name[(int)GateType::H_NYZ] = \"~Hnyz\";\n        stim_name_to_quirk_name[(int)GateType::I] = \"…\";\n        stim_name_to_quirk_name[(int)GateType::X] = \"X\";\n        stim_name_to_quirk_name[(int)GateType::Y] = \"Y\";\n        stim_name_to_quirk_name[(int)GateType::Z] = \"Z\";\n        stim_name_to_quirk_name[(int)GateType::C_XYZ] = \"~Cxyz\";\n        stim_name_to_quirk_name[(int)GateType::C_NXYZ] = \"~Cnxyz\";\n        stim_name_to_quirk_name[(int)GateType::C_XNYZ] = \"~Cxnyz\";\n        stim_name_to_quirk_name[(int)GateType::C_XYNZ] = \"~Cxynz\";\n        stim_name_to_quirk_name[(int)GateType::C_ZYX] = \"~Czyx\";\n        stim_name_to_quirk_name[(int)GateType::C_NZYX] = \"~Cnzyx\";\n        stim_name_to_quirk_name[(int)GateType::C_ZNYX] = \"~Cznyx\";\n        stim_name_to_quirk_name[(int)GateType::C_ZYNX] = \"~Czynx\";\n        stim_name_to_quirk_name[(int)GateType::SQRT_X] = \"X^½\";\n        stim_name_to_quirk_name[(int)GateType::SQRT_X_DAG] = \"X^-½\";\n        stim_name_to_quirk_name[(int)GateType::SQRT_Y] = \"Y^½\";\n        stim_name_to_quirk_name[(int)GateType::SQRT_Y_DAG] = \"Y^-½\";\n        stim_name_to_quirk_name[(int)GateType::S] = \"Z^½\";\n        stim_name_to_quirk_name[(int)GateType::S_DAG] = \"Z^-½\";\n        stim_name_to_quirk_name[(int)GateType::MX] = \"XDetector\";\n        stim_name_to_quirk_name[(int)GateType::MY] = \"YDetector\";\n        stim_name_to_quirk_name[(int)GateType::M] = \"ZDetector\";\n        stim_name_to_quirk_name[(int)GateType::MRX] = \"XDetectControlReset\";\n        stim_name_to_quirk_name[(int)GateType::MRY] = \"YDetectControlReset\";\n        stim_name_to_quirk_name[(int)GateType::MR] = \"ZDetectControlReset\";\n        stim_name_to_quirk_name[(int)GateType::RX] = \"XDetectControlReset\";\n        stim_name_to_quirk_name[(int)GateType::RY] = \"YDetectControlReset\";\n        stim_name_to_quirk_name[(int)GateType::R] = \"ZDetectControlReset\";\n\n        std::string_view x_control = \"⊖\";\n        std::string_view y_control = \"(/)\";\n        std::string_view z_control = \"•\";\n        control_target_type[(int)GateType::XCX] = {x_control, \"X\"};\n        control_target_type[(int)GateType::XCY] = {x_control, \"Y\"};\n        control_target_type[(int)GateType::XCZ] = {x_control, \"Z\"};\n        control_target_type[(int)GateType::YCX] = {y_control, \"X\"};\n        control_target_type[(int)GateType::YCY] = {y_control, \"Y\"};\n        control_target_type[(int)GateType::YCZ] = {y_control, \"Z\"};\n        control_target_type[(int)GateType::CX] = {z_control, \"X\"};\n        control_target_type[(int)GateType::CY] = {z_control, \"Y\"};\n        control_target_type[(int)GateType::CZ] = {z_control, \"Z\"};\n        control_target_type[(int)GateType::SWAPCX] = {z_control, \"X\"};\n        control_target_type[(int)GateType::CXSWAP] = {x_control, \"Z\"};\n        control_target_type[(int)GateType::CZSWAP] = {z_control, \"Z\"};\n        control_target_type[(int)GateType::ISWAP] = {\"zpar\", \"zpar\"};\n        control_target_type[(int)GateType::ISWAP_DAG] = {\"zpar\", \"zpar\"};\n        control_target_type[(int)GateType::SQRT_XX] = {\"xpar\", \"xpar\"};\n        control_target_type[(int)GateType::SQRT_YY] = {\"ypar\", \"ypar\"};\n        control_target_type[(int)GateType::SQRT_ZZ] = {\"zpar\", \"zpar\"};\n        control_target_type[(int)GateType::SQRT_XX_DAG] = {\"xpar\", \"xpar\"};\n        control_target_type[(int)GateType::SQRT_YY_DAG] = {\"ypar\", \"ypar\"};\n        control_target_type[(int)GateType::SQRT_ZZ_DAG] = {\"zpar\", \"zpar\"};\n        control_target_type[(int)GateType::MXX] = {\"xpar\", \"xpar\"};\n        control_target_type[(int)GateType::MYY] = {\"xpar\", \"xpar\"};\n        control_target_type[(int)GateType::MZZ] = {\"xpar\", \"xpar\"};\n\n        phase_type[(int)GateType::SQRT_XX] = \"i\";\n        phase_type[(int)GateType::SQRT_YY] = \"i\";\n        phase_type[(int)GateType::SQRT_ZZ] = \"i\";\n        phase_type[(int)GateType::SQRT_XX_DAG] = \"-i\";\n        phase_type[(int)GateType::SQRT_YY_DAG] = \"-i\";\n        phase_type[(int)GateType::SQRT_ZZ_DAG] = \"-i\";\n        phase_type[(int)GateType::SPP] = \"i\";\n        phase_type[(int)GateType::SPP_DAG] = \"-i\";\n        phase_type[(int)GateType::ISWAP] = \"i\";\n        phase_type[(int)GateType::ISWAP_DAG] = \"-i\";\n    }\n\n    void write_pauli_par_controls(GateType g, size_t col, std::span<const GateTarget> targets) {\n        for (auto t : targets) {\n            if (t.has_qubit_value()) {\n                bool x = t.data & TARGET_PAULI_X_BIT;\n                bool z = t.data & TARGET_PAULI_Z_BIT;\n                uint8_t p = x + z * 2;\n                if (!p) {\n                    cols[col][t.value()] = control_target_type[(int)g].first;\n                } else {\n                    cols[col][t.value()] = std::array<std::string_view, 4>{\"\", \"xpar\", \"zpar\", \"ypar\"}[p];\n                }\n            }\n        }\n    }\n\n    size_t pick_free_qubit(std::span<const GateTarget> targets) {\n        if (num_qubits <= 16) {\n            return num_qubits;\n        }\n        std::set<size_t> qs;\n        for (auto t : targets) {\n            if (t.has_qubit_value()) {\n                qs.insert(t.value());\n            }\n        }\n        size_t q = 0;\n        while (qs.contains(q)) {\n            q += 1;\n        }\n        return q;\n    }\n\n    size_t pick_merge_qubit(std::span<const GateTarget> targets) {\n        if (num_qubits <= 16) {\n            return num_qubits;\n        }\n        for (auto t : targets) {\n            uint8_t p = t.pauli_type();\n            if (p && t.has_qubit_value() && t.qubit_value() <= 16) {\n                return t.qubit_value();\n            }\n        }\n\n        return num_qubits;\n    }\n\n    void do_single_qubit_gate(GateType g, GateTarget t) {\n        if (t.has_qubit_value()) {\n            if (cols[col_offset].contains(t.value()) || cols[col_offset + 1].contains(t.value()) ||\n                cols[col_offset + 2].contains(t.value())) {\n                col_offset += 3;\n            }\n            auto n = stim_name_to_quirk_name[(int)g];\n            if (n == \"XDetectControlReset\") {\n                cols[col_offset][t.value()] = n;\n                cols[col_offset + 1][t.value()] = \"H\";\n            } else if (n == \"YDetectControlReset\") {\n                cols[col_offset][t.value()] = n;\n                cols[col_offset + 1][t.value()] = \"~Hyz\";\n                used[(int)GateType::H_YZ] = true;\n            } else if (n == \"ZDetectControlReset\") {\n                cols[col_offset][t.value()] = n;\n            } else {\n                cols[col_offset + 1][t.value()] = n;\n            }\n        }\n    }\n\n    void do_multi_phase_gate(GateType g, std::span<const GateTarget> group) {\n        col_offset += 3;\n        size_t q_free = pick_free_qubit(group);\n        write_pauli_par_controls(g, col_offset, group);\n        cols[col_offset][q_free] = phase_type[(int)g];\n        col_offset += 3;\n    }\n\n    void do_multi_measure_gate(GateType g, std::span<const GateTarget> group) {\n        col_offset += 3;\n        size_t q_free = pick_merge_qubit(group);\n        write_pauli_par_controls(g, col_offset, group);\n        if (q_free == num_qubits) {\n            cols[col_offset][q_free] = \"X\";\n            cols[col_offset + 1][q_free] = \"ZDetectControlReset\";\n        } else {\n            write_pauli_par_controls(g, col_offset + 2, group);\n\n            auto r = cols[col_offset][q_free];\n            if (r == \"xpar\") {\n                cols[col_offset][q_free] = \"Z\";\n                cols[col_offset + 1][q_free] = \"XDetector\";\n                cols[col_offset + 2][q_free] = \"Z\";\n            } else if (r == \"ypar\") {\n                cols[col_offset][q_free] = \"X\";\n                cols[col_offset + 1][q_free] = \"YDetector\";\n                cols[col_offset + 2][q_free] = \"X\";\n            } else {\n                cols[col_offset][q_free] = \"X\";\n                cols[col_offset + 1][q_free] = \"ZDetector\";\n                cols[col_offset + 2][q_free] = \"X\";\n            }\n        }\n        col_offset += 3;\n    }\n\n    void do_controlled_gate(GateType g, GateTarget t1, GateTarget t2) {\n        if (t1.has_qubit_value() && t2.has_qubit_value()) {\n            col_offset += 3;\n            auto [c, t] = control_target_type[(int)g];\n            cols[col_offset][t1.qubit_value()] = c;\n            cols[col_offset][t2.qubit_value()] = t;\n            col_offset += 3;\n        }\n    }\n\n    void do_swap_plus_gate(GateType g, GateTarget t1, GateTarget t2) {\n        if (t1.has_qubit_value() && t2.has_qubit_value()) {\n            col_offset += 3;\n            cols[col_offset][t1.qubit_value()] = \"Swap\";\n            cols[col_offset][t2.qubit_value()] = \"Swap\";\n            if (g == GateType::ISWAP || g == GateType::ISWAP_DAG) {\n                std::array<GateTarget, 2> group{t1, t2};\n                do_multi_phase_gate(g, group);\n            } else {\n                do_controlled_gate(g, t1, t2);\n            }\n            col_offset += 3;\n        }\n    }\n\n    void do_circuit(const Circuit &circuit) {\n        circuit.for_each_operation([&](CircuitInstruction full_instruction) {\n            used[(int)full_instruction.gate_type] = true;\n            for_each_target_group(full_instruction, [&](CircuitInstruction inst) {\n                switch (inst.gate_type) {\n                    case GateType::DETECTOR:\n                    case GateType::OBSERVABLE_INCLUDE:\n                    case GateType::QUBIT_COORDS:\n                    case GateType::SHIFT_COORDS:\n                    case GateType::MPAD:\n                    case GateType::DEPOLARIZE1:\n                    case GateType::DEPOLARIZE2:\n                    case GateType::X_ERROR:\n                    case GateType::Y_ERROR:\n                    case GateType::Z_ERROR:\n                    case GateType::PAULI_CHANNEL_1:\n                    case GateType::PAULI_CHANNEL_2:\n                    case GateType::E:\n                    case GateType::ELSE_CORRELATED_ERROR:\n                    case GateType::HERALDED_ERASE:\n                    case GateType::HERALDED_PAULI_CHANNEL_1:\n                    case GateType::II:\n                    case GateType::I_ERROR:\n                    case GateType::II_ERROR:\n                        // Ignored.\n                        break;\n\n                    case GateType::TICK:\n                        col_offset += 3;\n                        break;\n\n                    case GateType::MX:\n                    case GateType::MY:\n                    case GateType::M:\n                    case GateType::MRX:\n                    case GateType::MRY:\n                    case GateType::MR:\n                    case GateType::RX:\n                    case GateType::RY:\n                    case GateType::R:\n                    case GateType::H:\n                    case GateType::H_XY:\n                    case GateType::H_YZ:\n                    case GateType::H_NXY:\n                    case GateType::H_NXZ:\n                    case GateType::H_NYZ:\n                    case GateType::I:\n                    case GateType::X:\n                    case GateType::Y:\n                    case GateType::Z:\n                    case GateType::C_XYZ:\n                    case GateType::C_NXYZ:\n                    case GateType::C_XNYZ:\n                    case GateType::C_XYNZ:\n                    case GateType::C_ZYX:\n                    case GateType::C_NZYX:\n                    case GateType::C_ZNYX:\n                    case GateType::C_ZYNX:\n                    case GateType::SQRT_X:\n                    case GateType::SQRT_X_DAG:\n                    case GateType::SQRT_Y:\n                    case GateType::SQRT_Y_DAG:\n                    case GateType::S:\n                    case GateType::S_DAG:\n                        do_single_qubit_gate(inst.gate_type, inst.targets[0]);\n                        break;\n\n                    case GateType::SQRT_XX:\n                    case GateType::SQRT_YY:\n                    case GateType::SQRT_ZZ:\n                    case GateType::SQRT_XX_DAG:\n                    case GateType::SQRT_YY_DAG:\n                    case GateType::SQRT_ZZ_DAG:\n                    case GateType::SPP:\n                    case GateType::SPP_DAG:\n                        do_multi_phase_gate(inst.gate_type, inst.targets);\n                        break;\n\n                    case GateType::XCX:\n                    case GateType::XCY:\n                    case GateType::XCZ:\n                    case GateType::YCX:\n                    case GateType::YCY:\n                    case GateType::YCZ:\n                    case GateType::CX:\n                    case GateType::CY:\n                    case GateType::CZ:\n                        do_controlled_gate(inst.gate_type, inst.targets[0], inst.targets[1]);\n                        break;\n\n                    case GateType::SWAP:\n                    case GateType::ISWAP:\n                    case GateType::CXSWAP:\n                    case GateType::SWAPCX:\n                    case GateType::CZSWAP:\n                    case GateType::ISWAP_DAG:\n                        do_swap_plus_gate(inst.gate_type, inst.targets[0], inst.targets[1]);\n                        break;\n\n                    case GateType::MXX:\n                    case GateType::MYY:\n                    case GateType::MZZ:\n                    case GateType::MPP:\n                        do_multi_measure_gate(inst.gate_type, inst.targets);\n                        break;\n\n                    default:\n                        throw std::invalid_argument(\"Not supported in export_quirk_url: \" + full_instruction.str());\n                }\n            });\n        });\n    }\n};\n\nstd::string stim::export_quirk_url(const Circuit &circuit) {\n    QuirkExporter exporter(circuit.count_qubits());\n    exporter.do_circuit(circuit);\n\n    std::stringstream out;\n    exporter.col_offset += 3;\n\n    out << R\"URL(https://algassert.com/quirk#circuit={\"cols\":[)URL\";\n    bool has_col = false;\n    for (size_t k = 0; k < exporter.col_offset; k++) {\n        if (!exporter.cols.contains(k)) {\n            continue;\n        }\n        const auto &col = exporter.cols.at(k);\n        if (col.empty()) {\n            continue;\n        }\n        std::vector<std::string> entries;\n        for (auto kv : col) {\n            while (entries.size() <= kv.first) {\n                entries.push_back(\"\");\n            }\n            entries[kv.first] = kv.second;\n        }\n        if (has_col) {\n            out << \",\";\n        }\n        has_col = true;\n        out << \"[\";\n        for (size_t q = 0; q < entries.size(); q++) {\n            if (q) {\n                out << \",\";\n            }\n            if (entries[q].empty()) {\n                out << \"1\";\n            } else {\n                out << '\"';\n                out << entries[q];\n                out << '\"';\n            }\n        }\n        out << \"]\";\n    }\n    out << R\"URL(])URL\";\n    bool has_custom_gates = false;\n    for (size_t k = 0; k < NUM_DEFINED_GATES; k++) {\n        if (!exporter.custom_gate_definition[k].empty() && exporter.used[k]) {\n            if (!has_custom_gates) {\n                out << R\"URL(,\"gates\":[)URL\";\n                has_custom_gates = true;\n            } else {\n                out << ',';\n            }\n            out << exporter.custom_gate_definition[k];\n        }\n    }\n    if (has_custom_gates) {\n        out << \"]\";\n    }\n    out << \"}\";\n\n    return out.str();\n}\n"
  },
  {
    "path": "src/stim/util_top/export_quirk_url.h",
    "content": "#ifndef _STIM_UTIL_TOP_EXPORT_QUIRK_URL_H\n#define _STIM_UTIL_TOP_EXPORT_QUIRK_URL_H\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim {\n\nstd::string export_quirk_url(const Circuit &circuit);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/export_quirk_url.test.cc",
    "content": "#include \"stim/util_top/export_quirk_url.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.test.h\"\n\nusing namespace stim;\n\nTEST(export_quirk, simple) {\n    auto actual = export_quirk_url(Circuit(R\"CIRCUIT(\n        R 0\n        H 0 1\n        S 2\n        H 2\n        CX 0 1\n        M 1\n        SQRT_ZZ 2 3\n        MXX 0 1\n    )CIRCUIT\"));\n    auto expected = R\"URL(https://algassert.com/quirk#circuit={\"cols\":[)URL\"\n                    R\"URL([\"ZDetectControlReset\"],)URL\"\n                    R\"URL([\"H\",\"H\",\"Z^½\"],)URL\"\n                    R\"URL([1,1,\"H\"],)URL\"\n                    R\"URL([\"•\",\"X\"],)URL\"\n                    R\"URL([1,\"ZDetector\"],)URL\"\n                    R\"URL([1,1,\"zpar\",\"zpar\",\"i\"],)URL\"\n                    R\"URL([\"xpar\",\"xpar\",1,1,\"X\"],)URL\"\n                    R\"URL([1,1,1,1,\"ZDetectControlReset\"])URL\"\n                    R\"URL(]})URL\";\n    ASSERT_EQ(actual, expected);\n\n    actual = export_quirk_url(Circuit(R\"CIRCUIT(\n        MRY 0\n    )CIRCUIT\"));\n    expected = R\"URL(https://algassert.com/quirk#circuit={\"cols\":[)URL\"\n               R\"URL([\"YDetectControlReset\"],)URL\"\n               R\"URL([\"~Hyz\"])URL\"\n               R\"URL(],\"gates\":[)URL\"\n               R\"URL({\"id\":\"~Hyz\",\"name\":\"Hyz\",\"matrix\":\"{{-√½i,-√½},{√½,√½i}}\"}]})URL\";\n    ASSERT_EQ(actual, expected);\n\n    actual = export_quirk_url(Circuit(R\"CIRCUIT(\n        R 0\n        H_XY 0 1\n        S 2\n        H 2\n        CX 0 1\n        M 1\n        SQRT_ZZ 2 3\n        MXX 0 1\n    )CIRCUIT\"));\n    expected = R\"URL(https://algassert.com/quirk#circuit={\"cols\":[)URL\"\n               R\"URL([\"ZDetectControlReset\"],)URL\"\n               R\"URL([\"~Hxy\",\"~Hxy\",\"Z^½\"],)URL\"\n               R\"URL([1,1,\"H\"],)URL\"\n               R\"URL([\"•\",\"X\"],)URL\"\n               R\"URL([1,\"ZDetector\"],)URL\"\n               R\"URL([1,1,\"zpar\",\"zpar\",\"i\"],)URL\"\n               R\"URL([\"xpar\",\"xpar\",1,1,\"X\"],)URL\"\n               R\"URL([1,1,1,1,\"ZDetectControlReset\"])URL\"\n               R\"URL(],\"gates\":[)URL\"\n               R\"URL({\"id\":\"~Hxy\",\"name\":\"Hxy\",\"matrix\":\"{{0,-√½-√½i},{√½-√½i,0}}\"}]})URL\";\n    ASSERT_EQ(actual, expected);\n\n    actual = export_quirk_url(Circuit(R\"CIRCUIT(\n        R 0\n        H_XY 0\n        H_YZ 1\n        S 2\n        H 2\n        CX 0 1\n        M 1\n        SQRT_ZZ 2 3\n        MXX 0 1\n    )CIRCUIT\"));\n    expected = R\"URL(https://algassert.com/quirk#circuit={\"cols\":[)URL\"\n               R\"URL([\"ZDetectControlReset\"],)URL\"\n               R\"URL([\"~Hxy\",\"~Hyz\",\"Z^½\"],)URL\"\n               R\"URL([1,1,\"H\"],)URL\"\n               R\"URL([\"•\",\"X\"],)URL\"\n               R\"URL([1,\"ZDetector\"],)URL\"\n               R\"URL([1,1,\"zpar\",\"zpar\",\"i\"],)URL\"\n               R\"URL([\"xpar\",\"xpar\",1,1,\"X\"],)URL\"\n               R\"URL([1,1,1,1,\"ZDetectControlReset\"])URL\"\n               R\"URL(],\"gates\":[)URL\"\n               R\"URL({\"id\":\"~Hxy\",\"name\":\"Hxy\",\"matrix\":\"{{0,-√½-√½i},{√½-√½i,0}}\"},)URL\"\n               R\"URL({\"id\":\"~Hyz\",\"name\":\"Hyz\",\"matrix\":\"{{-√½i,-√½},{√½,√½i}}\"}]})URL\";\n    ASSERT_EQ(actual, expected);\n}\n\nTEST(export_quirk, all_operations) {\n    auto actual = export_quirk_url(generate_test_circuit_with_all_operations());\n    auto expected =\n        R\"URL(https://algassert.com/quirk#circuit={\"cols\":[)URL\"\n        R\"URL([\"…\",\"X\",\"Y\",\"Z\"],)URL\"\n        R\"URL([\"~Cxyz\",\"~Cnxyz\",\"~Cxnyz\",\"~Cxynz\",\"~Czyx\",\"~Cnzyx\",\"~Cznyx\",\"~Czynx\"],)URL\"\n        R\"URL([\"~Hxy\",\"H\",\"~Hyz\",\"~Hnxy\",\"~Hnxz\",\"~Hnyz\"],)URL\"\n        R\"URL([\"X^½\",\"X^-½\",\"Y^½\",\"Y^-½\",\"Z^½\",\"Z^-½\"],)URL\"\n        R\"URL([\"Swap\",\"Swap\"],)URL\"\n        R\"URL([\"⊖\",\"Z\"],)URL\"\n        R\"URL([1,1,\"Swap\",\"Swap\"],)URL\"\n        R\"URL([\"i\",1,\"zpar\",\"zpar\"],)URL\"\n        R\"URL([1,1,1,1,\"Swap\",\"Swap\"],)URL\"\n        R\"URL([\"-i\",1,1,1,\"zpar\",\"zpar\"],)URL\"\n        R\"URL([1,1,1,1,1,1,\"Swap\",\"Swap\"],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1,\"Swap\",\"Swap\"],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1,\"•\",\"X\"],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1,1,1,\"Swap\",\"Swap\"],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1,1,1,\"•\",\"Z\"],)URL\"\n        R\"URL([\"xpar\",\"xpar\",\"i\"],)URL\"\n        R\"URL([\"-i\",1,\"xpar\",\"xpar\"],)URL\"\n        R\"URL([\"i\",1,1,1,\"ypar\",\"ypar\"],)URL\"\n        R\"URL([\"-i\",1,1,1,1,1,\"ypar\",\"ypar\"],)URL\"\n        R\"URL([\"i\",1,1,1,1,1,1,1,\"zpar\",\"zpar\"],)URL\"\n        R\"URL([\"-i\",1,1,1,1,1,1,1,1,1,\"zpar\",\"zpar\"],)URL\"\n        R\"URL([\"⊖\",\"X\"],)URL\"\n        R\"URL([1,1,\"⊖\",\"Y\"],)URL\"\n        R\"URL([1,1,1,1,\"⊖\",\"Z\"],)URL\"\n        R\"URL([1,1,1,1,1,1,\"(/)\",\"X\"],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1,\"(/)\",\"Y\"],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1,1,1,\"(/)\",\"Z\"],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1,1,1,1,1,\"•\",\"X\"],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1,1,1,1,1,1,1,\"•\",\"Y\"],)URL\"\n        R\"URL([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\"•\",\"Z\"],)URL\"\n        R\"URL([\"Z\",\"ypar\",\"zpar\"],)URL\"\n        R\"URL([\"XDetector\"],)URL\"\n        R\"URL([\"Z\",\"ypar\",\"zpar\"],)URL\"\n        R\"URL([\"X\",\"zpar\"],)URL\"\n        R\"URL([\"ZDetector\"],)URL\"\n        R\"URL([\"X\",\"zpar\"],)URL\"\n        R\"URL([\"xpar\",\"ypar\",\"zpar\",\"i\"],)URL\"\n        R\"URL([\"i\",1,1,\"xpar\"],)URL\"\n        R\"URL([\"xpar\",\"ypar\",\"zpar\",\"-i\"],)URL\"\n        R\"URL([\"-i\",1,\"xpar\"],)URL\"\n        R\"URL([\"XDetectControlReset\",\"YDetectControlReset\",\"ZDetectControlReset\",1,1,1,1,\"XDetectControlReset\",\"YDetectControlReset\",\"ZDetectControlReset\"],)URL\"\n        R\"URL([\"H\",\"~Hyz\",1,\"XDetector\",\"YDetector\",\"ZDetector\",\"ZDetector\",\"H\",\"~Hyz\"],)URL\"\n        R\"URL([\"Z\",\"xpar\"],)URL\"\n        R\"URL([\"XDetector\"],)URL\"\n        R\"URL([\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,\"XDetector\"],)URL\"\n        R\"URL([1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,1,1,\"XDetector\"],)URL\"\n        R\"URL([1,1,1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,1,1,1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,1,1,1,1,\"XDetector\"],)URL\"\n        R\"URL([1,1,1,1,1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([\"H\"],)URL\"\n        R\"URL([\"•\",\"X\"],)URL\"\n        R\"URL([1,\"Z^½\"],)URL\"\n        R\"URL([\"H\"],)URL\"\n        R\"URL([\"•\",\"X\"],)URL\"\n        R\"URL([1,\"Z^½\"],)URL\"\n        R\"URL([\"H\"],)URL\"\n        R\"URL([\"•\",\"X\"],)URL\"\n        R\"URL([1,\"Z^½\"],)URL\"\n        R\"URL([\"ZDetectControlReset\"],)URL\"\n        R\"URL([\"ZDetectControlReset\"],)URL\"\n        R\"URL([\"XDetectControlReset\"],)URL\"\n        R\"URL([\"H\",\"YDetector\"],)URL\"\n        R\"URL([1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,\"XDetector\"],)URL\"\n        R\"URL([1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,1,1,\"XDetector\"],)URL\"\n        R\"URL([1,1,1,1,\"Z\",\"xpar\"],)URL\"\n        R\"URL([1,1,1,1,1,1,\"Z\",\"ypar\",\"zpar\"],)URL\"\n        R\"URL([1,1,1,1,1,1,\"XDetector\"],)URL\"\n        R\"URL([1,1,1,1,1,1,\"Z\",\"ypar\",\"zpar\"]],\"gates\":)URL\"\n        R\"URL([{\"id\":\"~Hxy\",\"name\":\"Hxy\",\"matrix\":\"{{0,-√½-√½i},{√½-√½i,0}}\"},)URL\"\n        R\"URL({\"id\":\"~Hyz\",\"name\":\"Hyz\",\"matrix\":\"{{-√½i,-√½},{√½,√½i}}\"},)URL\"\n        R\"URL({\"id\":\"~Hnxy\",\"name\":\"Hnxy\",\"matrix\":\"{{0,√½+√½i},{√½-√½i,0}}\"},)URL\"\n        R\"URL({\"id\":\"~Hnxz\",\"name\":\"Hnxz\",\"matrix\":\"{{-√½,√½},{√½,√½}}\"},)URL\"\n        R\"URL({\"id\":\"~Hnyz\",\"name\":\"Hnyz\",\"matrix\":\"{{-√½,-√½i},{√½i,√½}}\"},)URL\"\n        R\"URL({\"id\":\"~Cxyz\",\"name\":\"Cxyz\",\"matrix\":\"{{½-½i,-½-½i},{½-½i,½+½i}}\"},)URL\"\n        R\"URL({\"id\":\"~Czyx\",\"name\":\"Czyx\",\"matrix\":\"{{½+½i,½+½i},{-½+½i,½-½i}}\"},)URL\"\n        R\"URL({\"id\":\"~Cnxyz\",\"name\":\"Cnxyz\",\"matrix\":\"{{½+½i,½-½i},{-½-½i,½-½i}}\"},)URL\"\n        R\"URL({\"id\":\"~Cxnyz\",\"name\":\"Cxnyz\",\"matrix\":\"{{½+½i,-½+½i},{½+½i,½-½i}}\"},)URL\"\n        R\"URL({\"id\":\"~Cxynz\",\"name\":\"Cxynz\",\"matrix\":\"{{½-½i,½+½i},{-½+½i,½+½i}}\"},)URL\"\n        R\"URL({\"id\":\"~Cnzyx\",\"name\":\"Cnzyx\",\"matrix\":\"{{½+½i,-½-½i},{½-½i,½-½i}}\"},)URL\"\n        R\"URL({\"id\":\"~Cznyx\",\"name\":\"Cznyx\",\"matrix\":\"{{½-½i,½-½i},{-½-½i,½+½i}}\"},)URL\"\n        R\"URL({\"id\":\"~Czynx\",\"name\":\"Czynx\",\"matrix\":\"{{½-½i,-½+½i},{½+½i,½+½i}}\"}]})URL\";\n    ASSERT_EQ(actual, expected);\n}\n"
  },
  {
    "path": "src/stim/util_top/export_quirk_url_pybind_test.py",
    "content": "import stim\n\n\ndef test_to_quirk_url_simple():\n    c = stim.Circuit(\"\"\"\n        QUBIT_COORDS(2, 1) 0\n        QUBIT_COORDS(2, 2) 1\n        H 0\n        TICK\n        CX 0 1\n        TICK\n        C_XYZ 0\n        S 1\n        TICK\n        MZZ 1 0\n    \"\"\")\n    assert c.to_quirk_url() == 'https://algassert.com/quirk#circuit={\"cols\":[[\"H\"],[\"•\",\"X\"],[\"~Cxyz\",\"Z^½\"],[\"xpar\",\"xpar\",\"X\"],[1,1,\"ZDetectControlReset\"]],\"gates\":[{\"id\":\"~Cxyz\",\"name\":\"Cxyz\",\"matrix\":\"{{½-½i,-½-½i},{½-½i,½+½i}}\"}]}'\n\n\ndef test_to_quirk_url_complex():\n    c = stim.Circuit.generated('surface_code:rotated_memory_x', distance=2, rounds=2, after_clifford_depolarization=0.001)\n    assert '\"H\"' in c.to_quirk_url()\n"
  },
  {
    "path": "src/stim/util_top/has_flow.cc",
    "content": "#include \"stim/util_top/has_flow.h\"\n\nusing namespace stim;\n\nCircuit stim::flow_test_block_for_circuit(\n    const Circuit &circuit, GateTarget ancilla_qubit, const std::set<uint32_t> &obs_indices) {\n    Circuit result;\n\n    for (CircuitInstruction inst : circuit.operations) {\n        if (inst.gate_type == GateType::REPEAT) {\n            const Circuit &body = inst.repeat_block_body(circuit);\n            Circuit new_body = flow_test_block_for_circuit(body, ancilla_qubit, obs_indices);\n            result.append_repeat_block(inst.repeat_block_rep_count(), std::move(new_body), inst.tag);\n        } else if (inst.gate_type == GateType::OBSERVABLE_INCLUDE && obs_indices.contains((uint32_t)inst.args[0])) {\n            for (GateTarget t : inst.targets) {\n                if (t.is_inverted_result_target()) {\n                    result.safe_append(CircuitInstruction{GateType::X, {}, &ancilla_qubit, inst.tag});\n                }\n                if (t.is_measurement_record_target()) {\n                    std::array<GateTarget, 2> targets{t, ancilla_qubit};\n                    result.safe_append(\n                        CircuitInstruction{\n                            GateType::CX,\n                            {},\n                            targets,\n                            inst.tag,\n                        });\n                } else if (t.is_x_target()) {\n                    std::array<GateTarget, 2> targets{GateTarget::qubit(t.qubit_value()), ancilla_qubit};\n                    result.safe_append(\n                        CircuitInstruction{\n                            GateType::XCX,\n                            {},\n                            targets,\n                            inst.tag,\n                        });\n                } else if (t.is_y_target()) {\n                    std::array<GateTarget, 2> targets{GateTarget::qubit(t.qubit_value()), ancilla_qubit};\n                    result.safe_append(\n                        CircuitInstruction{\n                            GateType::YCX,\n                            {},\n                            targets,\n                            inst.tag,\n                        });\n                } else if (t.is_z_target()) {\n                    std::array<GateTarget, 2> targets{GateTarget::qubit(t.qubit_value()), ancilla_qubit};\n                    result.safe_append(\n                        CircuitInstruction{\n                            GateType::CX,\n                            {},\n                            targets,\n                            inst.tag,\n                        });\n                } else {\n                    throw std::invalid_argument(\"Not handled: \" + inst.str());\n                }\n            }\n        } else {\n            result.safe_append(inst);\n        }\n    }\n\n    return result;\n}\n"
  },
  {
    "path": "src/stim/util_top/has_flow.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_UTIL_TOP_HAS_FLOW_H\n#define _STIM_UTIL_TOP_HAS_FLOW_H\n\n#include <iostream>\n#include <span>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/stabilizers/flow.h\"\n\nnamespace stim {\n\n/// Probabilistically verifies that the given circuit has the specified flows.\n///\n/// Args:\n///     num_samples: How many times to sample the circuit. Each sample has a 50/50 chance\n///         of catching a bad stabilizer flow.\n///     rng: Random number generator for the sampling process.\n///     circuit: The circuit that should have the given flows.\n///     flows: The flows that the circuit should have,\n///\n/// Returns:\n///     A vector containing one boolean for each flow. The k'th boolean is true if the\n///     k'th flow passed all checks.\ntemplate <size_t W>\nstd::vector<bool> sample_if_circuit_has_stabilizer_flows(\n    size_t num_samples, std::mt19937_64 &rng, const Circuit &circuit, std::span<const Flow<W>> flows);\n\ntemplate <size_t W>\nstd::vector<bool> check_if_circuit_has_unsigned_stabilizer_flows(\n    const Circuit &circuit, std::span<const Flow<W>> flows);\n\ntemplate <size_t W>\nstd::ostream &operator<<(std::ostream &out, const Flow<W> &flow);\n\n/// Internal helper method.\nCircuit flow_test_block_for_circuit(\n    const Circuit &circuit, GateTarget ancilla_qubit, const std::set<uint32_t> &obs_indices);\n\n}  // namespace stim\n\n#include \"stim/util_top/has_flow.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/has_flow.inl",
    "content": "#include \"stim/util_top/has_flow.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/simulators/sparse_rev_frame_tracker.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nvoid _pauli_string_controlled_not(PauliStringRef<W> control, uint32_t target, Circuit &out) {\n    control.for_each_active_pauli([&](size_t q) {\n        uint32_t q32 = (uint32_t)q;\n        auto p = control.xs[q] + 2 * control.zs[q];\n        if (p == 1) {\n            out.safe_append_u(\"XCX\", {q32, target});\n        } else if (p == 2) {\n            out.safe_append_u(\"ZCX\", {q32, target});\n        } else if (p == 3) {\n            out.safe_append_u(\"YCX\", {q32, target});\n        }\n    });\n    if (control.sign) {\n        out.safe_append_u(\"X\", {target});\n    }\n}\n\ntemplate <size_t W>\nstatic GateTarget measurement_index_to_target(int32_t m, uint64_t num_measurements, const Flow<W> &flow) {\n    if ((m >= 0 && (uint64_t)m >= num_measurements) || (m < 0 && (uint64_t)-(int64_t)m > num_measurements)) {\n        std::stringstream ss;\n        ss << \"The flow '\" << flow;\n        ss << \"' is malformed for the given circuit. \";\n        ss << \"The flow mentions a measurement index '\" << m;\n        ss << \"', but this index out of range because the circuit only has \";\n        ss << num_measurements << \" measurements.\";\n        throw std::invalid_argument(ss.str());\n    }\n    if (m >= 0) {\n        m -= num_measurements;\n    }\n    return GateTarget::rec(m);\n}\n\ntemplate <size_t W>\nbool _sample_if_noiseless_circuit_has_stabilizer_flow(\n    size_t num_samples, std::mt19937_64 &rng, const Circuit &circuit, const Flow<W> &flow) {\n    uint32_t num_qubits = (uint32_t)circuit.count_qubits();\n    uint64_t num_measurements = circuit.count_measurements();\n\n    num_qubits = std::max(num_qubits, (uint32_t)flow.input.num_qubits);\n    num_qubits = std::max(num_qubits, (uint32_t)flow.output.num_qubits);\n    std::set<uint32_t> obs_indices;\n    for (uint32_t obs_index : flow.observables) {\n        obs_indices.insert(obs_index);\n    }\n\n    // Max-mix all the qubits.\n    Circuit augmented_circuit;\n    GateTarget ancilla = GateTarget::qubit(num_qubits);\n    for (uint32_t k = 0; k < num_qubits; k++) {\n        augmented_circuit.safe_append_u(\"X_ERROR\", {k}, {0.5});\n    }\n    for (uint32_t k = 0; k < num_qubits; k++) {\n        augmented_circuit.safe_append_u(\"Z_ERROR\", {k}, {0.5});\n    }\n\n    // Xor input onto ancilla.\n    _pauli_string_controlled_not<W>(flow.input, num_qubits, augmented_circuit);\n    // Perform circuit (accounting for desired observables impacting ancilla)\n    augmented_circuit += flow_test_block_for_circuit(circuit, ancilla, obs_indices);\n    for (int32_t m : flow.measurements) {\n        std::array<GateTarget, 2> targets{measurement_index_to_target<W>(m, num_measurements, flow), ancilla};\n        augmented_circuit.safe_append(CircuitInstruction(GateType::CX, {}, targets, \"\"));\n    }\n    // Xor output onto ancilla.\n    _pauli_string_controlled_not<W>(flow.output, num_qubits, augmented_circuit);\n\n    // The ancilla should end up deterministically in |0> if the flow is valid.\n    augmented_circuit.safe_append_u(\"M\", {num_qubits}, {});\n\n    simd_bits<W> reference_sample = TableauSimulator<W>::reference_sample_circuit(augmented_circuit);\n    num_samples = (num_samples + W - 1) / W * W;\n    auto result = sample_batch_measurements<W>(\n        augmented_circuit,\n        reference_sample,\n        num_samples,\n        rng,\n        false);\n\n    return !result[num_measurements].not_zero();\n}\n\ntemplate <size_t W>\nstd::vector<bool> sample_if_circuit_has_stabilizer_flows(\n    size_t num_samples, std::mt19937_64 &rng, const Circuit &circuit, std::span<const Flow<W>> flows) {\n    const auto &noiseless = circuit.aliased_noiseless_circuit();\n    std::vector<bool> result;\n    for (const auto &flow : flows) {\n        result.push_back(_sample_if_noiseless_circuit_has_stabilizer_flow(num_samples, rng, noiseless, flow));\n    }\n    return result;\n}\n\ntemplate <size_t W>\nstd::vector<bool> check_if_circuit_has_unsigned_stabilizer_flows(\n    const Circuit &circuit, std::span<const Flow<W>> flows) {\n    auto stats = circuit.compute_stats();\n    size_t num_qubits = stats.num_qubits;\n    for (const auto &flow : flows) {\n        num_qubits = std::max(num_qubits, flow.input.num_qubits);\n        num_qubits = std::max(num_qubits, flow.output.num_qubits);\n    }\n    SparseUnsignedRevFrameTracker rev(num_qubits, stats.num_measurements, flows.size(), false);\n\n    // Add end of flows into frames.\n    for (size_t f = 0; f < flows.size(); f++) {\n        const auto &flow = flows[f];\n        for (size_t q = 0; q < flow.output.num_qubits; q++) {\n            if (flow.output.xs[q]) {\n                rev.xs[q].xor_item(DemTarget::relative_detector_id(f));\n            }\n            if (flow.output.zs[q]) {\n                rev.zs[q].xor_item(DemTarget::relative_detector_id(f));\n            }\n        }\n    }\n\n    // Add observable-to-flow effects.\n    std::map<uint64_t, SparseXorVec<DemTarget>> obs_effects;\n    for (size_t f = 0; f < flows.size(); f++) {\n        const auto &flow = flows[f];\n        for (const auto &obs : flow.observables) {\n            obs_effects[obs].sorted_items.push_back(DemTarget::relative_detector_id(f));\n        }\n    }\n\n    // Mark measurements for inclusion.\n    for (size_t f = flows.size(); f--;) {\n        const auto &flow = flows[f];\n        std::vector<GateTarget> targets;\n        for (int32_t m : flow.measurements) {\n            targets.push_back(measurement_index_to_target<W>(m, stats.num_measurements, flow));\n        }\n        rev.undo_DETECTOR(CircuitInstruction{GateType::DETECTOR, {}, targets, \"\"});\n    }\n\n    // Undo the circuit.\n    circuit.for_each_operation_reverse([&](const CircuitInstruction &inst) {\n        if (inst.gate_type == GateType::DETECTOR) {\n            // Ignore detectors; we're using them for tracking flows.\n        } else if (inst.gate_type == GateType::OBSERVABLE_INCLUDE) {\n            // Map observable effects onto the flows that depended on that observable.\n            uint64_t obs_id = (uint32_t)inst.args[0];\n            auto effects = obs_effects.find(obs_id);\n            if (effects == obs_effects.end()) {\n                return;\n            }\n            for (auto t : inst.targets) {\n                if (t.is_measurement_record_target()) {\n                    int64_t index = t.rec_offset() + (int64_t)rev.num_measurements_in_past;\n                    if (index < 0) {\n                        throw std::invalid_argument(\"Referred to a measurement result before the beginning of time.\");\n                    }\n                    rev.rec_bits[index] ^= effects->second;\n                } else if (t.is_pauli_target()) {\n                    if (t.data & TARGET_PAULI_X_BIT) {\n                        rev.xs[t.qubit_value()] ^= effects->second;\n                    }\n                    if (t.data & TARGET_PAULI_Z_BIT) {\n                        rev.zs[t.qubit_value()] ^= effects->second;\n                    }\n                } else {\n                    throw std::invalid_argument(\"Unexpected target for OBSERVABLE_INCLUDE: \" + t.str());\n                }\n            }\n        } else {\n            rev.undo_gate(inst);\n        }\n    });\n\n    // Remove start of flows from frames.\n    for (size_t f = 0; f < flows.size(); f++) {\n        const auto &flow = flows[f];\n        for (size_t q = 0; q < flow.input.num_qubits; q++) {\n            if (flow.input.xs[q]) {\n                rev.xs[q].xor_item(DemTarget::relative_detector_id(f));\n            }\n            if (flow.input.zs[q]) {\n                rev.zs[q].xor_item(DemTarget::relative_detector_id(f));\n            }\n        }\n    }\n\n    // Determine which flows survived.\n    std::vector<bool> result(flows.size(), true);\n    for (const auto &xs : rev.xs) {\n        for (const auto &t : xs) {\n            result[t.val()] = false;\n        }\n    }\n    for (const auto &zs : rev.zs) {\n        for (const auto &t : zs) {\n            result[t.val()] = false;\n        }\n    }\n    for (const auto &[dem_target, gate_target] : rev.anticommutations) {\n        result[dem_target.val()] = false;\n    }\n\n    return result;\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/util_top/has_flow.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_top/has_flow.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, sample_if_circuit_has_stabilizer_flows, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto results = sample_if_circuit_has_stabilizer_flows<W>(\n        256,\n        rng,\n        Circuit(R\"CIRCUIT(\n            R 4\n            CX 0 4 1 4 2 4 3 4\n            M 4\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"Z___ -> Z____\"),\n            Flow<W>::from_str(\"_Z__ -> _Z__\"),\n            Flow<W>::from_str(\"__Z_ -> __Z_\"),\n            Flow<W>::from_str(\"___Z -> ___Z\"),\n            Flow<W>::from_str(\"XX__ -> XX__\"),\n            Flow<W>::from_str(\"XXXX -> XXXX\"),\n            Flow<W>::from_str(\"XYZ_ -> XYZ_\"),\n            Flow<W>::from_str(\"XXX_ -> XXX_\"),\n            Flow<W>::from_str(\"ZZZZ -> ____ xor rec[-1]\"),\n            Flow<W>::from_str(\"+___Z -> -___Z\"),\n            Flow<W>::from_str(\"-___Z -> -___Z\"),\n            Flow<W>::from_str(\"-___Z -> +___Z\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, sample_if_circuit_has_stabilizer_flows_signed_checked, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto results = sample_if_circuit_has_stabilizer_flows<W>(\n        256,\n        rng,\n        Circuit(R\"CIRCUIT(\n            R 2 3\n            X 1 3\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"Z0 -> Z0\"),\n            Flow<W>::from_str(\"Z1 -> -Z1\"),\n            Flow<W>::from_str(\"1 -> Z2\"),\n            Flow<W>::from_str(\"1 -> -Z3\"),\n\n            Flow<W>::from_str(\"Z0 -> -Z0\"),\n            Flow<W>::from_str(\"Z1 -> Z1\"),\n            Flow<W>::from_str(\"1 -> -Z2\"),\n            Flow<W>::from_str(\"1 -> Z3\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 1, 1, 0, 0, 0, 0}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, sample_if_circuit_has_stabilizer_flows_measurements_signed_checked, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto results = sample_if_circuit_has_stabilizer_flows<W>(\n        256,\n        rng,\n        Circuit(R\"CIRCUIT(\n            X 1\n            M 0 1 2\n            X 2\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"Z0 -> Z0\"),\n            Flow<W>::from_str(\"Z1 -> -Z1\"),\n            Flow<W>::from_str(\"Z2 -> -Z2\"),\n            Flow<W>::from_str(\"Z0 -> rec[-3]\"),\n            Flow<W>::from_str(\"-Z1 -> rec[-2]\"),\n            Flow<W>::from_str(\"Z2 -> rec[-1]\"),\n            Flow<W>::from_str(\"1 -> Z0 xor rec[-3]\"),\n            Flow<W>::from_str(\"1 -> Z1 xor rec[-2]\"),\n            Flow<W>::from_str(\"1 -> -Z2 xor rec[-1]\"),\n\n            Flow<W>::from_str(\"Z0 -> -Z0\"),\n            Flow<W>::from_str(\"Z1 -> Z1\"),\n            Flow<W>::from_str(\"Z2 -> Z2\"),\n            Flow<W>::from_str(\"-Z0 -> rec[-3]\"),\n            Flow<W>::from_str(\"Z1 -> rec[-2]\"),\n            Flow<W>::from_str(\"-Z2 -> rec[-1]\"),\n            Flow<W>::from_str(\"1 -> -Z0 xor rec[-3]\"),\n            Flow<W>::from_str(\"1 -> -Z1 xor rec[-2]\"),\n            Flow<W>::from_str(\"1 -> Z2 xor rec[-1]\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, sample_if_circuit_has_stabilizer_flows_signed_obs, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto results = sample_if_circuit_has_stabilizer_flows<W>(\n        256,\n        rng,\n        Circuit(R\"CIRCUIT(\n            X 1\n            M 0 1 2\n            X 2\n            OBSERVABLE_INCLUDE(0) rec[-3]\n            OBSERVABLE_INCLUDE(1) rec[-2]\n            OBSERVABLE_INCLUDE(2) rec[-1]\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"Z0 -> Z0\"),\n            Flow<W>::from_str(\"Z1 -> -Z1\"),\n            Flow<W>::from_str(\"Z2 -> -Z2\"),\n            Flow<W>::from_str(\"Z0 -> obs[0]\"),\n            Flow<W>::from_str(\"-Z1 -> obs[1]\"),\n            Flow<W>::from_str(\"Z2 -> obs[2]\"),\n            Flow<W>::from_str(\"1 -> Z0 xor obs[0]\"),\n            Flow<W>::from_str(\"1 -> Z1 xor obs[1]\"),\n            Flow<W>::from_str(\"1 -> -Z2 xor obs[2]\"),\n\n            Flow<W>::from_str(\"Z0 -> -Z0\"),\n            Flow<W>::from_str(\"Z1 -> Z1\"),\n            Flow<W>::from_str(\"Z2 -> Z2\"),\n            Flow<W>::from_str(\"-Z0 -> obs[0]\"),\n            Flow<W>::from_str(\"Z1 -> obs[1]\"),\n            Flow<W>::from_str(\"-Z2 -> obs[2]\"),\n            Flow<W>::from_str(\"1 -> -Z0 xor obs[0]\"),\n            Flow<W>::from_str(\"1 -> -Z1 xor obs[1]\"),\n            Flow<W>::from_str(\"1 -> Z2 xor obs[2]\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, sample_if_circuit_has_stabilizer_flows_obs, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto results = sample_if_circuit_has_stabilizer_flows<W>(\n        256,\n        rng,\n        Circuit(R\"CIRCUIT(\n            OBSERVABLE_INCLUDE(3) X0\n            OBSERVABLE_INCLUDE(2) Y0\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X0 -> obs[3]\"),\n            Flow<W>::from_str(\"Y0 -> obs[2]\"),\n            Flow<W>::from_str(\"-X0 -> obs[3]\"),\n            Flow<W>::from_str(\"X0 -> obs[2]\"),\n            Flow<W>::from_str(\"Y0 -> obs[3]\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 0, 0, 0}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, sample_if_circuit_has_stabilizer_flows_inverted_obs_pauli, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto results = sample_if_circuit_has_stabilizer_flows<W>(\n        256,\n        rng,\n        Circuit(R\"CIRCUIT(\n            OBSERVABLE_INCLUDE(3) X0\n            OBSERVABLE_INCLUDE(2) !X0\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X0 -> obs[3]\"),\n            Flow<W>::from_str(\"-X0 -> obs[2]\"),\n            Flow<W>::from_str(\"-X0 -> obs[3]\"),\n            Flow<W>::from_str(\"X0 -> obs[2]\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 0, 0}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, sample_if_circuit_has_stabilizer_flows_inverted_obs_rec, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    auto results = sample_if_circuit_has_stabilizer_flows<W>(\n        256,\n        rng,\n        Circuit(R\"CIRCUIT(\n            M !0\n            OBSERVABLE_INCLUDE(3) rec[-1]\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"-Z0 -> obs[3]\"),\n            Flow<W>::from_str(\"Z0 -> obs[3]\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 0}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, check_if_circuit_has_unsigned_stabilizer_flows, {\n    auto results = check_if_circuit_has_unsigned_stabilizer_flows<W>(\n        Circuit(R\"CIRCUIT(\n            R 4\n            CX 0 4 1 4 2 4 3 4\n            M 4\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"Z___ -> Z____\"),\n            Flow<W>::from_str(\"_Z__ -> _Z__\"),\n            Flow<W>::from_str(\"__Z_ -> __Z_\"),\n            Flow<W>::from_str(\"___Z -> ___Z\"),\n            Flow<W>::from_str(\"XX__ -> XX__\"),\n            Flow<W>::from_str(\"XXXX -> XXXX\"),\n            Flow<W>::from_str(\"XYZ_ -> XYZ_\"),\n            Flow<W>::from_str(\"XXX_ -> XXX_\"),\n            Flow<W>::from_str(\"ZZZZ -> ____ xor rec[-1]\"),\n            Flow<W>::from_str(\"+___Z -> -___Z\"),\n            Flow<W>::from_str(\"-___Z -> -___Z\"),\n            Flow<W>::from_str(\"-___Z -> +___Z\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1}));\n});\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, check_if_circuit_has_unsigned_stabilizer_flows_historical_failure, {\n    auto results = check_if_circuit_has_unsigned_stabilizer_flows<W>(\n        Circuit(R\"CIRCUIT(\n            CX 0 1\n            S 0\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X_ -> YX\"),\n            Flow<W>::from_str(\"Y_ -> XX\"),\n            Flow<W>::from_str(\"X_ -> XX\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 0}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, check_if_circuit_has_unsigned_stabilizer_flows_mzz, {\n    auto results = check_if_circuit_has_unsigned_stabilizer_flows<W>(\n        Circuit(R\"CIRCUIT(\n            MZZ 0 1\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X0*X1 -> Y0*Y1 xor rec[-1]\"),\n            Flow<W>::from_str(\"X0*X1 -> Z0*Z1 xor rec[-1]\"),\n            Flow<W>::from_str(\"X0*X1 -> X0*X1\"),\n            Flow<W>::from_str(\"Z0 -> Z1 xor rec[-1]\"),\n            Flow<W>::from_str(\"Z0 -> Z0\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 0, 1, 1, 1}));\n})\n\nTEST_EACH_WORD_SIZE_W(stabilizer_flow, has_flow_observable, {\n    auto results = check_if_circuit_has_unsigned_stabilizer_flows<W>(\n        Circuit(R\"CIRCUIT(\n            MZZ 0 1\n            OBSERVABLE_INCLUDE(2) rec[-1]\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"Z0*Z1 -> obs[2]\"),\n            Flow<W>::from_str(\"1 -> Z0*Z1 xor obs[2]\"),\n            Flow<W>::from_str(\"X0*X1 -> X0*X1 xor obs[0]\"),\n            Flow<W>::from_str(\"X0*X1 -> Y0*Y1 xor obs[2]\"),\n            Flow<W>::from_str(\"X0*X1 -> Y0*Y1 xor obs[1]\"),\n            Flow<W>::from_str(\"X0*X1 -> Y0*Y1 xor rec[-1]\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 1, 1, 0, 1}));\n\n    results = check_if_circuit_has_unsigned_stabilizer_flows<W>(\n        Circuit(R\"CIRCUIT(\n            OBSERVABLE_INCLUDE(3) X0 Y1 Z2\n            OBSERVABLE_INCLUDE(2) Y0\n        )CIRCUIT\"),\n        std::vector<Flow<W>>{\n            Flow<W>::from_str(\"X0*Y1*Z2 -> obs[3]\"),\n            Flow<W>::from_str(\"-Y0 -> obs[2]\"),\n            Flow<W>::from_str(\"Y0 -> obs[3]\"),\n            Flow<W>::from_str(\"1 -> X0*Y1*Z2 xor obs[3]\"),\n        });\n    ASSERT_EQ(results, (std::vector<bool>{1, 1, 0, 1}));\n})\n"
  },
  {
    "path": "src/stim/util_top/mbqc_decomposition.cc",
    "content": "#include \"stim/util_top/mbqc_decomposition.h\"\n\nusing namespace stim;\n\nconst char *stim::mbqc_decomposition(GateType gate) {\n    switch (gate) {\n        case GateType::NOT_A_GATE:\n        case GateType::DETECTOR:\n        case GateType::OBSERVABLE_INCLUDE:\n        case GateType::TICK:\n        case GateType::QUBIT_COORDS:\n        case GateType::SHIFT_COORDS:\n        case GateType::REPEAT:\n        case GateType::MPAD:\n        case GateType::DEPOLARIZE1:\n        case GateType::DEPOLARIZE2:\n        case GateType::X_ERROR:\n        case GateType::Y_ERROR:\n        case GateType::Z_ERROR:\n        case GateType::I_ERROR:\n        case GateType::II_ERROR:\n        case GateType::PAULI_CHANNEL_1:\n        case GateType::PAULI_CHANNEL_2:\n        case GateType::E:\n        case GateType::ELSE_CORRELATED_ERROR:\n        case GateType::HERALDED_ERASE:\n        case GateType::HERALDED_PAULI_CHANNEL_1:\n            return nullptr;\n        case GateType::MX:\n            return R\"CIRCUIT(\nMX 0\n            )CIRCUIT\";\n        case GateType::MY:\n            return R\"CIRCUIT(\nMY 0\n            )CIRCUIT\";\n        case GateType::M:\n            return R\"CIRCUIT(\nMZ 0\n            )CIRCUIT\";\n        case GateType::MRX:\n            return R\"CIRCUIT(\nMX 0\nCZ rec[-1] 0\n            )CIRCUIT\";\n        case GateType::MRY:\n            return R\"CIRCUIT(\nMY 0\nCX rec[-1] 0\n            )CIRCUIT\";\n        case GateType::MR:\n            return R\"CIRCUIT(\nMZ 0\nCX rec[-1] 0\n            )CIRCUIT\";\n        case GateType::RX:\n            return R\"CIRCUIT(\nMX 0\nCZ rec[-1] 0\n            )CIRCUIT\";\n        case GateType::RY:\n            return R\"CIRCUIT(\nMY 0\nCX rec[-1] 0\n            )CIRCUIT\";\n        case GateType::R:\n            return R\"CIRCUIT(\nMZ 0\nCX rec[-1] 0\n            )CIRCUIT\";\n        case GateType::XCX:\n            return R\"CIRCUIT(\nMX 2\nMZZ 0 2\nMY 2\nMXX 0 2\nMZ 2\nMXX 1 2\nMZZ 0 2\nMX 2\nMZ 2\nMXX 0 2\nMY 2\nMZZ 0 2\nMX 2\nCX rec[-11] 0 rec[-10] 1 rec[-8] 0 rec[-6] 0 rec[-3] 0 rec[-13] 1 rec[-12] 1 rec[-7] 1\nCY rec[-10] 0 rec[-9] 0 rec[-5] 0 rec[-4] 0\nCZ rec[-13] 0 rec[-12] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::XCY:\n            return R\"CIRCUIT(\nMY 2\nMXX 1 2\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nMZ 2\nMXX 1 2\nMY 2\nX 0\nCX rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1\nCY rec[-6] 1 rec[-4] 1\n            )CIRCUIT\";\n        case GateType::XCZ:\n            return R\"CIRCUIT(\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nCX rec[-4] 0 rec[-2] 0\nCZ rec[-3] 1 rec[-1] 1\n            )CIRCUIT\";\n        case GateType::YCX:\n            return R\"CIRCUIT(\nMY 2\nMXX 0 2\nMZ 2\nMXX 1 2\nMZZ 0 2\nMX 2\nMZ 2\nMXX 0 2\nMY 2\nX 1\nCX rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-7] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-5] 1\nCY rec[-6] 0 rec[-4] 0\n            )CIRCUIT\";\n        case GateType::YCY:\n            return R\"CIRCUIT(\nMX 2\nMZZ 1 2\nMY 2\nMXX 0 2\nMZ 2\nMXX 1 2\nMZZ 0 2\nMX 2\nMZ 2\nMXX 0 2\nMY 2\nMZZ 1 2\nMX 2\nY 1\nCX rec[-10] 0 rec[-9] 0 rec[-5] 0 rec[-4] 0 rec[-3] 0 rec[-11] 1\nCY rec[-13] 0 rec[-12] 0 rec[-10] 1 rec[-8] 0 rec[-6] 0 rec[-7] 1\nCZ rec[-13] 1 rec[-12] 1 rec[-11] 0 rec[-3] 1 rec[-2] 1 rec[-1] 1\n            )CIRCUIT\";\n        case GateType::YCZ:\n            return R\"CIRCUIT(\nMX 2\nMZZ 0 2\nMY 2\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nMZZ 0 2\nMY 2\nZ 0\nCY rec[-6] 0 rec[-4] 0\nCZ rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-7] 0 rec[-7] 1 rec[-3] 0 rec[-3] 1 rec[-2] 0 rec[-1] 0 rec[-5] 1\n            )CIRCUIT\";\n        case GateType::CX:\n            return R\"CIRCUIT(\nMX 2\nMZZ 0 2\nMXX 1 2\nMZ 2\nCX rec[-3] 1 rec[-1] 1\nCZ rec[-4] 0 rec[-2] 0\n            )CIRCUIT\";\n        case GateType::CY:\n            return R\"CIRCUIT(\nMY 2\nMZZ 1 2\nMX 2\nMZZ 0 2\nMXX 1 2\nMZ 2\nMX 2\nMZZ 1 2\nMY 2\nZ 0\nCY rec[-6] 1 rec[-4] 1\nCZ rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1\n            )CIRCUIT\";\n        case GateType::CZ:\n            return R\"CIRCUIT(\nMZ 2\nMXX 0 2\nMY 2\nMZZ 0 2\nMX 2\nMZZ 1 2\nMXX 0 2\nMZ 2\nMX 2\nMZZ 0 2\nMY 2\nMXX 0 2\nMZ 2\nCX rec[-13] 0 rec[-12] 0 rec[-2] 0 rec[-1] 0\nCY rec[-10] 0 rec[-9] 0 rec[-5] 0 rec[-4] 0\nCZ rec[-11] 0 rec[-10] 1 rec[-8] 0 rec[-6] 0 rec[-3] 0 rec[-13] 1 rec[-12] 1 rec[-7] 1\n            )CIRCUIT\";\n        case GateType::H:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nMXX 0 1\nMZ 1\nMX 1\nMZZ 0 1\nMY 1\nCX rec[-8] 0 rec[-7] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::H_XY:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nX 0\nCZ rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::H_YZ:\n            return R\"CIRCUIT(\nMZ 1\nMXX 0 1\nMY 1\nZ 0\nCX rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::H_NXY:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nY 0\nCZ rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::H_NXZ:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nMXX 0 1\nMZ 1\nMX 1\nMZZ 0 1\nMY 1\nY 0\nCX rec[-8] 0 rec[-7] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::H_NYZ:\n            return R\"CIRCUIT(\nMZ 1\nMXX 0 1\nMY 1\nY 0\nCX rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::I:\n            return R\"CIRCUIT(\n            )CIRCUIT\";\n        case GateType::X:\n            return R\"CIRCUIT(\nX 0\n            )CIRCUIT\";\n        case GateType::Y:\n            return R\"CIRCUIT(\nY 0\n            )CIRCUIT\";\n        case GateType::Z:\n            return R\"CIRCUIT(\nZ 0\n            )CIRCUIT\";\n        case GateType::C_XYZ:\n            return R\"CIRCUIT(\nMZ 1\nMXX 0 1\nMY 1\nMZZ 0 1\nMX 1\nCX rec[-3] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::C_ZYX:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nMXX 0 1\nMZ 1\nCX rec[-2] 0 rec[-1] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-3] 0\n            )CIRCUIT\";\n        case GateType::C_NXYZ:\n            return R\"CIRCUIT(\nMZ 1\nMXX 0 1\nMY 1\nMZZ 0 1\nMX 1\nZ 0\nCX rec[-3] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::C_XNYZ:\n            return R\"CIRCUIT(\nMZ 1\nMXX 0 1\nMY 1\nMZZ 0 1\nMX 1\nX 0\nCX rec[-3] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::C_XYNZ:\n            return R\"CIRCUIT(\nMZ 1\nMXX 0 1\nMY 1\nMZZ 0 1\nMX 1\nY 0\nCX rec[-3] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::C_NZYX:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nMXX 0 1\nMZ 1\nX 0\nCX rec[-2] 0 rec[-1] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-3] 0\n            )CIRCUIT\";\n        case GateType::C_ZNYX:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nMXX 0 1\nMZ 1\nZ 0\nCX rec[-2] 0 rec[-1] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-3] 0\n            )CIRCUIT\";\n        case GateType::C_ZYNX:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nMXX 0 1\nMZ 1\nY 0\nCX rec[-2] 0 rec[-1] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-3] 0\n            )CIRCUIT\";\n        case GateType::SQRT_X:\n            return R\"CIRCUIT(\nMZ 1\nMXX 0 1\nMY 1\nCX rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::SQRT_X_DAG:\n            return R\"CIRCUIT(\nMY 1\nMXX 0 1\nMZ 1\nCX rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::SQRT_Y:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nMXX 0 1\nMZ 1\nMX 1\nMZZ 0 1\nMY 1\nX 0\nCX rec[-8] 0 rec[-7] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::SQRT_Y_DAG:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nMXX 0 1\nMZ 1\nMX 1\nMZZ 0 1\nMY 1\nZ 0\nCX rec[-8] 0 rec[-7] 0\nCY rec[-5] 0 rec[-4] 0\nCZ rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::S:\n            return R\"CIRCUIT(\nMY 1\nMZZ 0 1\nMX 1\nCZ rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::S_DAG:\n            return R\"CIRCUIT(\nMX 1\nMZZ 0 1\nMY 1\nCZ rec[-3] 0 rec[-2] 0 rec[-1] 0\n            )CIRCUIT\";\n        case GateType::II:\n            return \"\";\n        case GateType::SQRT_XX:\n            return R\"CIRCUIT(\nMX 2\nMZZ 0 2\nMY 2\nMXX 0 2\nMZ 2\nMXX 1 2\nMZZ 0 2\nMX 2\nMY 2\nMXX 1 2\nMZ 2\nMXX 0 2\nMY 2\nMZZ 0 2\nMX 2\nMZ 2\nMXX 0 2\nMY 2\nX 1\nCX rec[-18] 1 rec[-17] 1 rec[-16] 0 rec[-13] 0 rec[-11] 0 rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-15] 1 rec[-12] 1 rec[-10] 1 rec[-9] 1 rec[-8] 1\nCY rec[-18] 0 rec[-17] 0 rec[-5] 0 rec[-4] 0\nCZ rec[-15] 0 rec[-14] 0 rec[-8] 0 rec[-7] 0\n            )CIRCUIT\";\n        case GateType::SQRT_XX_DAG:\n            return R\"CIRCUIT(\nMX 2\nMZZ 0 2\nMY 2\nMXX 0 2\nMZ 2\nMXX 1 2\nMZZ 0 2\nMX 2\nMY 2\nMXX 1 2\nMZ 2\nMXX 0 2\nMY 2\nMZZ 0 2\nMX 2\nMZ 2\nMXX 0 2\nMY 2\nX 0\nCX rec[-18] 1 rec[-17] 1 rec[-16] 0 rec[-13] 0 rec[-11] 0 rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-15] 1 rec[-12] 1 rec[-10] 1 rec[-9] 1 rec[-8] 1\nCY rec[-18] 0 rec[-17] 0 rec[-5] 0 rec[-4] 0\nCZ rec[-15] 0 rec[-14] 0 rec[-8] 0 rec[-7] 0\n            )CIRCUIT\";\n        case GateType::SQRT_YY:\n            return R\"CIRCUIT(\nMX 2\nMZZ 1 2\nMY 2\nMXX 0 2\nMZ 2\nMXX 1 2\nMZZ 0 2\nMX 2\nMZZ 0 2\nMY 2\nMXX 0 2\nMZ 2\nMXX 1 2\nMY 2\nMZZ 1 2\nMX 2\nX 0\nY 1\nCX rec[-16] 1 rec[-15] 1 rec[-14] 0 rec[-6] 0 rec[-5] 0 rec[-3] 1\nCY rec[-16] 0 rec[-15] 0 rec[-11] 0 rec[-8] 0 rec[-5] 1 rec[-13] 1 rec[-10] 1 rec[-4] 1\nCZ rec[-13] 0 rec[-12] 0 rec[-7] 0 rec[-14] 1 rec[-2] 1 rec[-1] 1\n            )CIRCUIT\";\n        case GateType::SQRT_YY_DAG:\n            return R\"CIRCUIT(\nMX 2\nMZZ 1 2\nMY 2\nMXX 0 2\nMZ 2\nMXX 1 2\nMZZ 0 2\nMX 2\nMZZ 0 2\nMY 2\nMXX 0 2\nMZ 2\nMXX 1 2\nMY 2\nMZZ 1 2\nMX 2\nZ 0\nCX rec[-16] 1 rec[-15] 1 rec[-14] 0 rec[-6] 0 rec[-5] 0 rec[-3] 1\nCY rec[-16] 0 rec[-15] 0 rec[-11] 0 rec[-8] 0 rec[-5] 1 rec[-13] 1 rec[-10] 1 rec[-4] 1\nCZ rec[-13] 0 rec[-12] 0 rec[-7] 0 rec[-14] 1 rec[-2] 1 rec[-1] 1\n            )CIRCUIT\";\n        case GateType::SQRT_ZZ:\n            return R\"CIRCUIT(\nMZ 2\nMXX 0 2\nMY 2\nMZZ 0 2\nMX 2\nMZZ 1 2\nMXX 0 2\nMZ 2\nMY 2\nMZZ 1 2\nMX 2\nMZZ 0 2\nMY 2\nMXX 0 2\nMZ 2\nMX 2\nMZZ 0 2\nMY 2\nZ 0\nCX rec[-15] 0 rec[-14] 0 rec[-8] 0 rec[-7] 0\nCY rec[-18] 0 rec[-17] 0 rec[-5] 0 rec[-4] 0\nCZ rec[-18] 1 rec[-17] 1 rec[-16] 0 rec[-13] 0 rec[-11] 0 rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-15] 1 rec[-12] 1 rec[-10] 1 rec[-9] 1 rec[-8] 1\n            )CIRCUIT\";\n        case GateType::SQRT_ZZ_DAG:\n            return R\"CIRCUIT(\nMZ 2\nMXX 0 2\nMY 2\nMZZ 0 2\nMX 2\nMZZ 1 2\nMXX 0 2\nMZ 2\nMY 2\nMZZ 1 2\nMX 2\nMZZ 0 2\nMY 2\nMXX 0 2\nMZ 2\nMX 2\nMZZ 0 2\nMY 2\nZ 1\nCX rec[-15] 0 rec[-14] 0 rec[-8] 0 rec[-7] 0\nCY rec[-18] 0 rec[-17] 0 rec[-5] 0 rec[-4] 0\nCZ rec[-18] 1 rec[-17] 1 rec[-16] 0 rec[-13] 0 rec[-11] 0 rec[-6] 0 rec[-3] 0 rec[-2] 0 rec[-1] 0 rec[-15] 1 rec[-12] 1 rec[-10] 1 rec[-9] 1 rec[-8] 1\n            )CIRCUIT\";\n        case GateType::SWAP:\n            return R\"CIRCUIT(\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nMZZ 0 2\nMXX 1 2\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nCX rec[-6] 0 rec[-6] 1 rec[-2] 0 rec[-10] 1 rec[-8] 1 rec[-4] 1\nCZ rec[-9] 0 rec[-5] 0 rec[-5] 1 rec[-7] 1 rec[-3] 1 rec[-1] 1\n            )CIRCUIT\";\n        case GateType::ISWAP:\n            return R\"CIRCUIT(\nMX 2\nMZZ 0 2\nMY 2\nMZZ 1 2\nMX 2\nMZ 2\nMXX 0 2\nMY 2\nMZZ 0 2\nMX 2\nMZZ 0 2\nMXX 1 2\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nMZZ 1 2\nMY 2\nMXX 1 2\nMZ 2\nZ 1\nCX rec[-10] 0 rec[-6] 0 rec[-15] 1 rec[-14] 1 rec[-2] 1 rec[-1] 1\nCY rec[-12] 1 rec[-9] 1 rec[-7] 1 rec[-4] 1\nCZ rec[-18] 0 rec[-18] 1 rec[-17] 0 rec[-16] 0 rec[-15] 0 rec[-14] 0 rec[-12] 0 rec[-9] 0 rec[-20] 1 rec[-19] 1 rec[-13] 1 rec[-10] 1 rec[-8] 1 rec[-3] 1\n            )CIRCUIT\";\n        case GateType::CXSWAP:\n            return R\"CIRCUIT(\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nMZZ 0 2\nMXX 1 2\nMZ 2\nCX rec[-7] 0 rec[-7] 1 rec[-5] 0 rec[-5] 1 rec[-3] 1 rec[-1] 1\nCZ rec[-6] 0 rec[-6] 1 rec[-2] 0 rec[-4] 1\n            )CIRCUIT\";\n        case GateType::SWAPCX:\n            return R\"CIRCUIT(\nMX 2\nMZZ 0 2\nMXX 1 2\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nCX rec[-6] 0 rec[-6] 1 rec[-2] 0 rec[-4] 1\nCZ rec[-7] 0 rec[-7] 1 rec[-5] 0 rec[-5] 1 rec[-3] 1 rec[-1] 1\n            )CIRCUIT\";\n        case GateType::CZSWAP:\n            return R\"CIRCUIT(\nMZ 2\nMXX 0 2\nMY 2\nMZZ 0 2\nMX 2\nMZZ 0 2\nMXX 1 2\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nMZZ 1 2\nMY 2\nMXX 1 2\nMZ 2\nCX rec[-10] 0 rec[-6] 0 rec[-15] 1 rec[-14] 1 rec[-2] 1 rec[-1] 1\nCY rec[-12] 1 rec[-9] 1 rec[-7] 1 rec[-4] 1\nCZ rec[-15] 0 rec[-14] 0 rec[-12] 0 rec[-9] 0 rec[-13] 1 rec[-10] 1 rec[-8] 1 rec[-3] 1\n            )CIRCUIT\";\n        case GateType::ISWAP_DAG:\n            return R\"CIRCUIT(\nMX 2\nMZZ 0 2\nMY 2\nMZZ 1 2\nMX 2\nMZ 2\nMXX 0 2\nMY 2\nMZZ 0 2\nMX 2\nMZZ 0 2\nMXX 1 2\nMZ 2\nMXX 0 2\nMZZ 1 2\nMX 2\nMZZ 1 2\nMY 2\nMXX 1 2\nMZ 2\nZ 0\nCX rec[-10] 0 rec[-6] 0 rec[-15] 1 rec[-14] 1 rec[-2] 1 rec[-1] 1\nCY rec[-12] 1 rec[-9] 1 rec[-7] 1 rec[-4] 1\nCZ rec[-18] 0 rec[-18] 1 rec[-17] 0 rec[-16] 0 rec[-15] 0 rec[-14] 0 rec[-12] 0 rec[-9] 0 rec[-20] 1 rec[-19] 1 rec[-13] 1 rec[-10] 1 rec[-8] 1 rec[-3] 1\n            )CIRCUIT\";\n        case GateType::MXX:\n            return R\"CIRCUIT(\nMXX 0 1\n            )CIRCUIT\";\n        case GateType::MYY:\n            return R\"CIRCUIT(\nMX 2\nMZZ 0 2\nMY 2\nMX 2\nMZZ 1 2\nMY 2\nMXX 0 1\nMX 2\nMZZ 0 2\nMY 2\nMX 2\nMZZ 1 2\nMY 2\nZ 0 1\nCZ rec[-13] 0 rec[-12] 0 rec[-11] 0 rec[-6] 0 rec[-5] 0 rec[-4] 0 rec[-10] 1 rec[-9] 1 rec[-8] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1\n            )CIRCUIT\";\n        case GateType::MZZ:\n            return R\"CIRCUIT(\nMZZ 0 1\n            )CIRCUIT\";\n\n        case GateType::SPP:\n            return R\"CIRCUIT(\nMY 3\nMZZ 1 3\nMX 3\nMZZ 0 3\nMXX 1 3\nMZ 3\nMX 3\nMZZ 1 3\nMY 3\nMZ 3\nMXX 0 3\nMY 3\nMZZ 0 3\nMX 3\nMZZ 2 3\nMXX 0 3\nMZ 3\nMX 3\nMZZ 0 3\nMY 3\nMXX 0 3\nMZ 3\nMXX 0 3\nMY 3\nMZ 3\nMXX 0 3\nMY 3\nMZZ 0 3\nMX 3\nMZZ 2 3\nMXX 0 3\nMZ 3\nMX 3\nMZZ 0 3\nMY 3\nMXX 0 3\nMZ 3\nMY 3\nMZZ 1 3\nMX 3\nMZZ 0 3\nMXX 1 3\nMZ 3\nMX 3\nMZZ 1 3\nMY 3\nX 0\nY 1\nZ 2\nCX rec[-46] 0 rec[-46] 1 rec[-45] 0 rec[-45] 1 rec[-37] 0 rec[-36] 0 rec[-26] 0 rec[-24] 0 rec[-23] 0 rec[-22] 0 rec[-21] 0 rec[-11] 0 rec[-10] 0\nCY rec[-42] 0 rec[-42] 1 rec[-37] 1 rec[-36] 1 rec[-35] 0 rec[-35] 1 rec[-32] 0 rec[-32] 1 rec[-30] 0 rec[-30] 1 rec[-27] 0 rec[-27] 1 rec[-26] 1 rec[-24] 1 rec[-23] 1 rec[-22] 1 rec[-21] 1 rec[-19] 0 rec[-19] 1 rec[-18] 0 rec[-18] 1 rec[-14] 0 rec[-14] 1 rec[-13] 0 rec[-13] 1 rec[-11] 1 rec[-10] 1 rec[-43] 1 rec[-41] 1 rec[-6] 1 rec[-4] 1\nCZ rec[-44] 0 rec[-44] 1 rec[-42] 2 rec[-40] 0 rec[-40] 1 rec[-39] 0 rec[-39] 1 rec[-38] 0 rec[-38] 1 rec[-35] 2 rec[-34] 0 rec[-34] 2 rec[-33] 0 rec[-32] 2 rec[-30] 2 rec[-29] 0 rec[-28] 0 rec[-27] 2 rec[-20] 0 rec[-19] 2 rec[-17] 0 rec[-15] 0 rec[-12] 0 rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-26] 2 rec[-24] 2 rec[-23] 2 rec[-22] 2 rec[-21] 2 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1 rec[-46] 2 rec[-45] 2 rec[-31] 2 rec[-16] 2\n            )CIRCUIT\";\n        case GateType::SPP_DAG:\n            return R\"CIRCUIT(\nMY 3\nMZZ 1 3\nMX 3\nMZZ 0 3\nMXX 1 3\nMZ 3\nMX 3\nMZZ 1 3\nMY 3\nMZ 3\nMXX 0 3\nMY 3\nMZZ 0 3\nMX 3\nMZZ 2 3\nMXX 0 3\nMZ 3\nMX 3\nMZZ 0 3\nMY 3\nMXX 0 3\nMZ 3\nMXX 0 3\nMY 3\nMZ 3\nMXX 0 3\nMY 3\nMZZ 0 3\nMX 3\nMZZ 2 3\nMXX 0 3\nMZ 3\nMX 3\nMZZ 0 3\nMY 3\nMXX 0 3\nMZ 3\nMY 3\nMZZ 1 3\nMX 3\nMZZ 0 3\nMXX 1 3\nMZ 3\nMX 3\nMZZ 1 3\nMY 3\nCX rec[-46] 0 rec[-46] 1 rec[-45] 0 rec[-45] 1 rec[-37] 0 rec[-36] 0 rec[-26] 0 rec[-24] 0 rec[-23] 0 rec[-22] 0 rec[-21] 0 rec[-11] 0 rec[-10] 0\nCY rec[-42] 0 rec[-42] 1 rec[-37] 1 rec[-36] 1 rec[-35] 0 rec[-35] 1 rec[-32] 0 rec[-32] 1 rec[-30] 0 rec[-30] 1 rec[-27] 0 rec[-27] 1 rec[-26] 1 rec[-24] 1 rec[-23] 1 rec[-22] 1 rec[-21] 1 rec[-19] 0 rec[-19] 1 rec[-18] 0 rec[-18] 1 rec[-14] 0 rec[-14] 1 rec[-13] 0 rec[-13] 1 rec[-11] 1 rec[-10] 1 rec[-43] 1 rec[-41] 1 rec[-6] 1 rec[-4] 1\nCZ rec[-44] 0 rec[-44] 1 rec[-42] 2 rec[-40] 0 rec[-40] 1 rec[-39] 0 rec[-39] 1 rec[-38] 0 rec[-38] 1 rec[-35] 2 rec[-34] 0 rec[-34] 2 rec[-33] 0 rec[-32] 2 rec[-30] 2 rec[-29] 0 rec[-28] 0 rec[-27] 2 rec[-20] 0 rec[-19] 2 rec[-17] 0 rec[-15] 0 rec[-12] 0 rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-26] 2 rec[-24] 2 rec[-23] 2 rec[-22] 2 rec[-21] 2 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1 rec[-46] 2 rec[-45] 2 rec[-31] 2 rec[-16] 2\n            )CIRCUIT\";\n        case GateType::MPP:\n            return R\"CIRCUIT(\nMY 5\nMZZ 1 5\nMX 5\nMZZ 0 5\nMXX 1 5\nMZ 5\nMX 5\nMZZ 1 5\nMY 5\nMZ 5\nMXX 2 5\nMY 5\nMZZ 2 5\nMX 5\nMXX 0 2\nMXX 3 4\nMX 5\nMZZ 2 5\nMY 5\nMXX 2 5\nMZ 5\nMY 5\nMZZ 1 5\nMX 5\nMZZ 0 5\nMXX 1 5\nMZ 5\nMX 5\nMZZ 1 5\nMY 5\nCX rec[-21] 2 rec[-20] 2 rec[-11] 2 rec[-10] 2\nCY rec[-27] 1 rec[-25] 1 rec[-6] 1 rec[-4] 1 rec[-18] 2 rec[-13] 2\nCZ rec[-28] 0 rec[-28] 1 rec[-26] 0 rec[-24] 0 rec[-24] 1 rec[-23] 0 rec[-23] 1 rec[-22] 0 rec[-22] 1 rec[-9] 0 rec[-9] 1 rec[-8] 0 rec[-8] 1 rec[-5] 0 rec[-30] 1 rec[-29] 1 rec[-7] 1 rec[-3] 1 rec[-2] 1 rec[-1] 1 rec[-19] 2 rec[-12] 2\n            )CIRCUIT\";\n        default:\n            throw std::invalid_argument(\"Unhandled gate type \" + std::string(GATE_DATA[gate].name));\n    }\n}\n"
  },
  {
    "path": "src/stim/util_top/mbqc_decomposition.h",
    "content": "#ifndef _STIM_UTIL_TOP_MBQC_DECOMPOSITION_H\n#define _STIM_UTIL_TOP_MBQC_DECOMPOSITION_H\n\n#include \"stim/gates/gates.h\"\n\nnamespace stim {\n\nconst char *mbqc_decomposition(GateType gate);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/mbqc_decomposition.test.cc",
    "content": "#include \"stim/util_top/mbqc_decomposition.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/util_bot/test_util.test.h\"\n#include \"stim/util_top/has_flow.h\"\n\nusing namespace stim;\n\nTEST(mbqc_decomposition, all_gates) {\n    auto rng = INDEPENDENT_TEST_RNG();\n\n    for (const auto &g : GATE_DATA.items) {\n        const char *decomp = mbqc_decomposition(g.id);\n        if (decomp == nullptr) {\n            EXPECT_TRUE(g.flow_data.empty()) << g.name;\n            continue;\n        } else {\n            EXPECT_FALSE(g.flow_data.empty()) << g.name;\n        }\n\n        Circuit circuit(decomp);\n        std::vector<Flow<64>> verified_flows;\n        for (auto &flow : g.flows<64>()) {\n            if (flow.input.ref().weight() && flow.output.ref().weight()) {\n                verified_flows.push_back(std::move(flow));\n            }\n        }\n        std::vector<bool> result = sample_if_circuit_has_stabilizer_flows<64>(256, rng, circuit, verified_flows);\n        bool correct = true;\n        for (auto b : result) {\n            correct &= b;\n        }\n        EXPECT_TRUE(correct) << g.name;\n    }\n}\n"
  },
  {
    "path": "src/stim/util_top/missing_detectors.cc",
    "content": "#include \"stim/util_top/missing_detectors.h\"\n\n#include \"stim/util_top/circuit_flow_generators.h\"\n\nusing namespace stim;\n\nstatic Circuit missing_detectors_impl(const Circuit &circuit) {\n    size_t num_measurements = circuit.count_measurements();\n    std::vector<std::pair<simd_bits<64>, bool>> rows;\n    std::vector<simd_bits<64>> logical_operators;\n    std::set<size_t> ignored_logical_operators;\n\n    // Turn existing detectors and observables into rows in the table.\n    uint64_t measurement_offset = 0;\n    circuit.for_each_operation([&](CircuitInstruction inst) {\n        measurement_offset += inst.count_measurement_results();\n\n        if (inst.gate_type == GateType::DETECTOR || inst.gate_type == GateType::OBSERVABLE_INCLUDE) {\n            if (inst.gate_type == GateType::DETECTOR) {\n                rows.push_back({simd_bits<64>(num_measurements), false});\n            } else {\n                while (logical_operators.size() <= (size_t)inst.args[0]) {\n                    logical_operators.push_back(simd_bits<64>(num_measurements));\n                }\n            }\n            simd_bits_range_ref<64> row =\n                inst.gate_type == GateType::DETECTOR ? rows.back().first : logical_operators[(size_t)inst.args[0]];\n            for (auto e : inst.targets) {\n                if (e.is_measurement_record_target()) {\n                    row[e.rec_offset() + measurement_offset] ^= true;\n                } else if (e.is_pauli_target() && inst.gate_type == GateType::OBSERVABLE_INCLUDE) {\n                    ignored_logical_operators.insert((size_t)inst.args[0]);\n                }\n            }\n        }\n    });\n    for (size_t k = 0; k < logical_operators.size(); k++) {\n        if (!ignored_logical_operators.contains(k)) {\n            rows.push_back({std::move(logical_operators[k]), false});\n        }\n    }\n    std::vector<simd_bits<64>> original_detector_rows_for_cleanup;\n    for (const auto &row : rows) {\n        original_detector_rows_for_cleanup.push_back(row.first);\n    }\n\n    // Turn measurement invariants into rows in the table.\n    for (const auto &generator : circuit_flow_generators<64>(circuit)) {\n        if (generator.input.ref().has_no_pauli_terms() && generator.output.ref().has_no_pauli_terms() &&\n            generator.observables.empty()) {\n            rows.push_back({simd_bits<64>(num_measurements), true});\n            for (int32_t e : generator.measurements) {\n                if (e < 0) {\n                    rows.back().first[e + num_measurements] ^= true;\n                } else {\n                    rows.back().first[e] ^= true;\n                }\n            }\n        }\n    }\n\n    // Perform Gaussian elimination on the table.\n    size_t num_solved = 0;\n    for (size_t k = 0; k < num_measurements; k++) {\n        size_t pivot = SIZE_MAX;\n        // Try to find a DETECTOR pivot.\n        for (size_t r = num_solved; r < rows.size() && pivot == SIZE_MAX; r++) {\n            if (rows[r].first[k] && !rows[r].second) {\n                pivot = r;\n            }\n        }\n        // Fall back to a flow invariant pivot.\n        for (size_t r = num_solved; r < rows.size() && pivot == SIZE_MAX; r++) {\n            if (rows[r].first[k]) {\n                pivot = r;\n            }\n        }\n        if (pivot == SIZE_MAX) {\n            continue;\n        }\n\n        for (size_t r = 0; r < rows.size(); r++) {\n            if (rows[r].first[k] && r != pivot) {\n                rows[r].first ^= rows[pivot].first;\n            }\n        }\n        if (pivot != num_solved) {\n            std::swap(rows[pivot], rows[num_solved]);\n        }\n        num_solved++;\n    }\n\n    // Any rows from invariants that the detector rows failed to clear are assumed to be the missing detectors.\n    Circuit result;\n    for (auto &r : rows) {\n        if (r.second && r.first.not_zero()) {\n            // Attempt to reduce the weight of the results by at least not overlapping with existing detectors.\n            for (const auto &det : original_detector_rows_for_cleanup) {\n                if (r.first.is_subset_of_or_equal_to(det)) {\n                    r.first ^= det;\n                }\n            }\n\n            // Convert set bits into a DETECTOR instruction.\n            r.first.for_each_set_bit([&](size_t bit_position) {\n                result.target_buf.append_tail(GateTarget::rec((int32_t)bit_position - (int32_t)num_measurements));\n            });\n            result.operations.push_back(\n                CircuitInstruction{\n                    GateType::DETECTOR,\n                    {},\n                    result.target_buf.commit_tail(),\n                    \"\",\n                });\n        }\n    }\n\n    return result;\n}\n\nCircuit stim::missing_detectors(const Circuit &circuit, bool unknown_input) {\n    if (unknown_input) {\n        return missing_detectors_impl(circuit);\n    } else {\n        Circuit with_resets;\n        uint32_t num_qubits = (uint32_t)circuit.count_qubits();\n        for (uint32_t k = 0; k < num_qubits; k++) {\n            with_resets.target_buf.append_tail(GateTarget::qubit(k));\n        }\n        with_resets.operations.push_back(\n            CircuitInstruction{\n                GateType::R,\n                {},\n                with_resets.target_buf.commit_tail(),\n                \"\",\n            });\n        with_resets += circuit;\n        return missing_detectors_impl(with_resets);\n    }\n}\n"
  },
  {
    "path": "src/stim/util_top/missing_detectors.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_UTIL_TOP_MISSING_DETECTORS_H\n#define _STIM_UTIL_TOP_MISSING_DETECTORS_H\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim {\n\nCircuit missing_detectors(const Circuit &circuit, bool unknown_input);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/missing_detectors.test.cc",
    "content": "#include \"stim/util_top/missing_detectors.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/util_bot/test_util.test.h\"\n#include \"stim/util_top/has_flow.h\"\n\nusing namespace stim;\n\nTEST(missing_detectors, circuit) {\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n    )CIRCUIT\"),\n            false),\n        Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        R 0\n        M 0\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n            false),\n        Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        R 0\n        M 0\n        DETECTOR rec[-1]\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n            false),\n        Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        R 0\n        M 0\n    )CIRCUIT\"),\n            false),\n        Circuit(R\"CIRCUIT(\n        DETECTOR rec[-1]\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        M 0\n    )CIRCUIT\"),\n            false),\n        Circuit(R\"CIRCUIT(\n        DETECTOR rec[-1]\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        M 0\n    )CIRCUIT\"),\n            true),\n        Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        R 0 1\n        M 0 1\n        DETECTOR rec[-1]\n    )CIRCUIT\"),\n            false),\n        Circuit(R\"CIRCUIT(\n        DETECTOR rec[-2]\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        MPP Z0*Z1 X0*X1\n        TICK\n        MPP Z0*Z1 X0*X1\n        DETECTOR rec[-1] rec[-3]\n        DETECTOR rec[-2] rec[-4]\n    )CIRCUIT\"),\n            false),\n        Circuit(R\"CIRCUIT(\n        DETECTOR rec[-4]\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        MPP Z0*Z1 X0*X1\n        TICK\n        MPP Z0*Z1 X0*X1\n        DETECTOR rec[-1] rec[-3]\n        DETECTOR rec[-2] rec[-4]\n        DETECTOR rec[-1] rec[-3] rec[-2] rec[-4]\n    )CIRCUIT\"),\n            false),\n        Circuit(R\"CIRCUIT(\n        DETECTOR rec[-3] rec[-2] rec[-1]\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        MPP Z0*Z1 X0*X1\n        TICK\n        MPP Z0*Z1 X0*X1\n        DETECTOR rec[-1] rec[-3]\n        DETECTOR rec[-2] rec[-4]\n    )CIRCUIT\"),\n            true),\n        Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        MPP Z0*Z1 X0*X1\n        TICK\n        MPP Z0*Z1 X0*X1\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        DETECTOR rec[-2] rec[-4]\n        OBSERVABLE_INCLUDE(0) rec[-3]\n    )CIRCUIT\"),\n            true),\n        Circuit(R\"CIRCUIT(\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        missing_detectors(\n            Circuit(R\"CIRCUIT(\n        OBSERVABLE_INCLUDE(0) Z0 Z1\n        MPP Z0*Z1 X0*X1\n        TICK\n        MPP Z0*Z1 X0*X1\n        OBSERVABLE_INCLUDE(0) Z0 Z1\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        DETECTOR rec[-2] rec[-4]\n        OBSERVABLE_INCLUDE(0) rec[-3]\n    )CIRCUIT\"),\n            true),\n        Circuit(R\"CIRCUIT(\n        DETECTOR rec[-3] rec[-1]\n    )CIRCUIT\"));\n}\n\nTEST(missing_detectors, big_case_honeycomb_code) {\n    Circuit c = Circuit(R\"CIRCUIT(\n        R 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53\n        TICK\n        MYY 8 9 17 18 26 27 35 36 44 45 51 52 5 6 14 15 23 24 32 33 41 42 0 1 7 16 25 34 43 50 11 12 20 21 29 30 38 39 47 48 3 4 13 22 31 40 2 10 19 28 37 46 49 53\n        TICK\n        MX 0 1 2 3 4 8 51 50 52 41 47 53\n        MXX 48 49 9 10 18 19 27 28 36 37 45 46 11 20 29 38 6 7 15 16 24 25 33 34 42 43 12 13 21 22 30 31 39 40 5 14 23 32 17 26 35 44\n        DETECTOR rec[-32] rec[-33] rec[-49]\n        DETECTOR rec[-29] rec[-30] rec[-40]\n        DETECTOR rec[-25] rec[-27] rec[-55]\n        DETECTOR rec[-21] rec[-22] rec[-23] rec[-34] rec[-41]\n        DETECTOR rec[-20] rec[-28] rec[-31] rec[-37] rec[-60]\n        DETECTOR rec[-9] rec[-24] rec[-26] rec[-46] rec[-50]\n        DETECTOR rec[-7] rec[-8] rec[-15] rec[-39] rec[-44] rec[-45]\n        DETECTOR rec[-5] rec[-6] rec[-14] rec[-38] rec[-42] rec[-43]\n        DETECTOR rec[-4] rec[-12] rec[-13] rec[-48] rec[-53] rec[-54]\n        DETECTOR rec[-3] rec[-10] rec[-11] rec[-47] rec[-51] rec[-52]\n        DETECTOR rec[-2] rec[-18] rec[-19] rec[-36] rec[-58] rec[-59]\n        DETECTOR rec[-1] rec[-16] rec[-17] rec[-35] rec[-56] rec[-57]\n        TICK\n        M 0 5 14 23 32 41 13 22 31 40 49 53\n        MZZ 19 20 28 29 37 38 46 47 10 11 21 30 4 12 2 3 39 48 16 17 25 26 34 35 43 44 50 51 7 8 15 24 1 6 33 42 9 18 27 36 45 52\n        TICK\n        MYY 8 9 17 18 26 27 35 36 44 45 51 52 5 6 14 15 23 24 32 33 41 42 0 1 7 16 25 34 43 50 11 12 20 21 29 30 38 39 47 48 3 4 13 22 31 40 2 10 19 28 37 46 49 53\n        DETECTOR rec[-15] rec[-26] rec[-27] rec[-30] rec[-34] rec[-39] rec[-108] rec[-119] rec[-120]\n        DETECTOR rec[-14] rec[-24] rec[-25] rec[-29] rec[-37] rec[-38] rec[-107] rec[-117] rec[-118]\n        DETECTOR rec[-13] rec[-22] rec[-23] rec[-28] rec[-35] rec[-36] rec[-106] rec[-115] rec[-116]\n        DETECTOR rec[-4] rec[-7] rec[-12] rec[-41] rec[-42] rec[-44] rec[-97] rec[-100] rec[-105]\n        DETECTOR rec[-3] rec[-10] rec[-11] rec[-43] rec[-47] rec[-48] rec[-96] rec[-103] rec[-104]\n        DETECTOR rec[-2] rec[-8] rec[-9] rec[-40] rec[-45] rec[-46] rec[-95] rec[-101] rec[-102]\n        TICK\n        M 0 5 14 23 32 41 13 22 31 40 49 53\n        MZZ 19 20 28 29 37 38 46 47 10 11 21 30 4 12 2 3 39 48 16 17 25 26 34 35 43 44 50 51 7 8 15 24 1 6 33 42 9 18 27 36 45 52\n        DETECTOR rec[-26] rec[-27] rec[-86] rec[-87]\n        DETECTOR rec[-24] rec[-25] rec[-84] rec[-85]\n        DETECTOR rec[-22] rec[-23] rec[-82] rec[-83]\n        DETECTOR rec[-16] rec[-20] rec[-21] rec[-76] rec[-80] rec[-81]\n        DETECTOR rec[-14] rec[-15] rec[-17] rec[-74] rec[-75] rec[-77]\n        DETECTOR rec[-13] rec[-18] rec[-19] rec[-73] rec[-78] rec[-79]\n        DETECTOR rec[-6] rec[-30] rec[-31] rec[-66] rec[-90] rec[-91]\n        DETECTOR rec[-5] rec[-32] rec[-33] rec[-65] rec[-92] rec[-93]\n        DETECTOR rec[-4] rec[-28] rec[-29] rec[-64] rec[-88] rec[-89]\n        DETECTOR rec[-3] rec[-7] rec[-12] rec[-63] rec[-67] rec[-72]\n        DETECTOR rec[-2] rec[-10] rec[-11] rec[-62] rec[-70] rec[-71]\n        DETECTOR rec[-1] rec[-8] rec[-9] rec[-61] rec[-68] rec[-69]\n        TICK\n        MX 0 1 2 3 4 8 51 50 52 41 47 53\n        MXX 48 49 9 10 18 19 27 28 36 37 45 46 11 20 29 38 6 7 15 16 24 25 33 34 42 43 12 13 21 22 30 31 39 40 5 14 23 32 17 26 35 44\n        DETECTOR rec[-30] rec[-31] rec[-47] rec[-107] rec[-156] rec[-157]\n        DETECTOR rec[-26] rec[-27] rec[-41] rec[-101] rec[-152] rec[-153]\n        DETECTOR rec[-16] rec[-23] rec[-25] rec[-34] rec[-51] rec[-94] rec[-111] rec[-142] rec[-149] rec[-151]\n        DETECTOR rec[-15] rec[-19] rec[-20] rec[-36] rec[-50] rec[-54] rec[-96] rec[-110] rec[-114] rec[-141] rec[-145] rec[-146]\n        DETECTOR rec[-14] rec[-17] rec[-18] rec[-35] rec[-52] rec[-53] rec[-95] rec[-112] rec[-113] rec[-140] rec[-143] rec[-144]\n        DETECTOR rec[-13] rec[-28] rec[-32] rec[-38] rec[-40] rec[-98] rec[-100] rec[-139] rec[-154] rec[-158]\n        DETECTOR rec[-2] rec[-11] rec[-12] rec[-39] rec[-44] rec[-45] rec[-99] rec[-104] rec[-105] rec[-128] rec[-137] rec[-138]\n        DETECTOR rec[-1] rec[-9] rec[-10] rec[-37] rec[-42] rec[-43] rec[-97] rec[-102] rec[-103] rec[-127] rec[-135] rec[-136]\n        TICK\n        MYY 8 9 17 18 26 27 35 36 44 45 51 52 5 6 14 15 23 24 32 33 41 42 0 1 7 16 25 34 43 50 11 12 20 21 29 30 38 39 47 48 3 4 13 22 31 40 2 10 19 28 37 46 49 53\n        DETECTOR rec[-15] rec[-20] rec[-21] rec[-31] rec[-39] rec[-40] rec[-157] rec[-165] rec[-166] rec[-201] rec[-206] rec[-207]\n        DETECTOR rec[-14] rec[-18] rec[-19] rec[-30] rec[-37] rec[-38] rec[-156] rec[-163] rec[-164] rec[-200] rec[-204] rec[-205]\n        DETECTOR rec[-6] rec[-11] rec[-12] rec[-34] rec[-35] rec[-42] rec[-160] rec[-161] rec[-168] rec[-192] rec[-197] rec[-198]\n        DETECTOR rec[-5] rec[-9] rec[-10] rec[-32] rec[-33] rec[-41] rec[-158] rec[-159] rec[-167] rec[-191] rec[-195] rec[-196]\n        DETECTOR rec[-3] rec[-25] rec[-26] rec[-29] rec[-45] rec[-46] rec[-155] rec[-171] rec[-172] rec[-189] rec[-211] rec[-212]\n        DETECTOR rec[-2] rec[-23] rec[-24] rec[-28] rec[-43] rec[-44] rec[-154] rec[-169] rec[-170] rec[-188] rec[-209] rec[-210]\n        TICK\n        MX 0 1 2 3 4 8 51 50 52 41 47 53\n        MXX 48 49 9 10 18 19 27 28 36 37 45 46 11 20 29 38 6 7 15 16 24 25 33 34 42 43 12 13 21 22 30 31 39 40 5 14 23 32 17 26 35 44\n        DETECTOR rec[-32] rec[-33] rec[-92] rec[-93]\n        DETECTOR rec[-29] rec[-30] rec[-89] rec[-90]\n        DETECTOR rec[-25] rec[-27] rec[-85] rec[-87]\n        DETECTOR rec[-21] rec[-22] rec[-23] rec[-81] rec[-82] rec[-83]\n        DETECTOR rec[-20] rec[-28] rec[-31] rec[-80] rec[-88] rec[-91]\n        DETECTOR rec[-9] rec[-24] rec[-26] rec[-69] rec[-84] rec[-86]\n        DETECTOR rec[-7] rec[-8] rec[-15] rec[-67] rec[-68] rec[-75]\n        DETECTOR rec[-5] rec[-6] rec[-14] rec[-65] rec[-66] rec[-74]\n        DETECTOR rec[-4] rec[-12] rec[-13] rec[-64] rec[-72] rec[-73]\n        DETECTOR rec[-3] rec[-10] rec[-11] rec[-63] rec[-70] rec[-71]\n        DETECTOR rec[-2] rec[-18] rec[-19] rec[-62] rec[-78] rec[-79]\n        DETECTOR rec[-1] rec[-16] rec[-17] rec[-61] rec[-76] rec[-77]\n        TICK\n        M 0 5 14 23 32 41 13 22 31 40 49 53\n        MZZ 19 20 28 29 37 38 46 47 10 11 21 30 4 12 2 3 39 48 16 17 25 26 34 35 43 44 50 51 7 8 15 24 1 6 33 42 9 18 27 36 45 52\n        DETECTOR rec[-31] rec[-32] rec[-37] rec[-97] rec[-157] rec[-158]\n        DETECTOR rec[-29] rec[-30] rec[-36] rec[-96] rec[-155] rec[-156]\n        DETECTOR rec[-16] rec[-25] rec[-26] rec[-39] rec[-40] rec[-99] rec[-100] rec[-142] rec[-151] rec[-152]\n        DETECTOR rec[-13] rec[-23] rec[-24] rec[-38] rec[-54] rec[-98] rec[-114] rec[-139] rec[-149] rec[-150]\n        DETECTOR rec[-6] rec[-11] rec[-12] rec[-35] rec[-44] rec[-45] rec[-95] rec[-104] rec[-105] rec[-132] rec[-137] rec[-138]\n        DETECTOR rec[-4] rec[-9] rec[-10] rec[-34] rec[-42] rec[-43] rec[-94] rec[-102] rec[-103] rec[-130] rec[-135] rec[-136]\n        DETECTOR rec[-3] rec[-17] rec[-21] rec[-48] rec[-52] rec[-53] rec[-108] rec[-112] rec[-113] rec[-129] rec[-143] rec[-147]\n        DETECTOR rec[-2] rec[-19] rec[-20] rec[-47] rec[-50] rec[-51] rec[-107] rec[-110] rec[-111] rec[-128] rec[-145] rec[-146]\n        TICK\n        MYY 8 9 17 18 26 27 35 36 44 45 51 52 5 6 14 15 23 24 32 33 41 42 0 1 7 16 25 34 43 50 11 12 20 21 29 30 38 39 47 48 3 4 13 22 31 40 2 10 19 28 37 46 49 53\n        DETECTOR rec[-15] rec[-26] rec[-27] rec[-30] rec[-34] rec[-39] rec[-156] rec[-160] rec[-165] rec[-201] rec[-212] rec[-213]\n        DETECTOR rec[-14] rec[-24] rec[-25] rec[-29] rec[-37] rec[-38] rec[-155] rec[-163] rec[-164] rec[-200] rec[-210] rec[-211]\n        DETECTOR rec[-13] rec[-22] rec[-23] rec[-28] rec[-35] rec[-36] rec[-154] rec[-161] rec[-162] rec[-199] rec[-208] rec[-209]\n        DETECTOR rec[-4] rec[-7] rec[-12] rec[-41] rec[-42] rec[-44] rec[-167] rec[-168] rec[-170] rec[-190] rec[-193] rec[-198]\n        DETECTOR rec[-3] rec[-10] rec[-11] rec[-43] rec[-47] rec[-48] rec[-169] rec[-173] rec[-174] rec[-189] rec[-196] rec[-197]\n        DETECTOR rec[-2] rec[-8] rec[-9] rec[-40] rec[-45] rec[-46] rec[-166] rec[-171] rec[-172] rec[-188] rec[-194] rec[-195]\n        TICK\n        M 0 5 14 23 32 41 13 22 31 40 49 53\n        MZZ 19 20 28 29 37 38 46 47 10 11 21 30 4 12 2 3 39 48 16 17 25 26 34 35 43 44 50 51 7 8 15 24 1 6 33 42 9 18 27 36 45 52\n        DETECTOR rec[-26] rec[-27] rec[-86] rec[-87]\n        DETECTOR rec[-24] rec[-25] rec[-84] rec[-85]\n        DETECTOR rec[-22] rec[-23] rec[-82] rec[-83]\n        DETECTOR rec[-16] rec[-20] rec[-21] rec[-76] rec[-80] rec[-81]\n        # OOPS DETECTOR rec[-14] rec[-15] rec[-17] rec[-74] rec[-75] rec[-77]\n        DETECTOR rec[-13] rec[-18] rec[-19] rec[-73] rec[-78] rec[-79]\n        DETECTOR rec[-6] rec[-30] rec[-31] rec[-66] rec[-90] rec[-91]\n        DETECTOR rec[-5] rec[-32] rec[-33] rec[-65] rec[-92] rec[-93]\n        DETECTOR rec[-4] rec[-28] rec[-29] rec[-64] rec[-88] rec[-89]\n        DETECTOR rec[-3] rec[-7] rec[-12] rec[-63] rec[-67] rec[-72]\n        DETECTOR rec[-2] rec[-10] rec[-11] rec[-62] rec[-70] rec[-71]\n        DETECTOR rec[-1] rec[-8] rec[-9] rec[-61] rec[-68] rec[-69]\n        TICK\n        MX 0 1 2 3 4 8 51 50 52 41 47 53\n        MXX 48 49 9 10 18 19 27 28 36 37 45 46 11 20 29 38 6 7 15 16 24 25 33 34 42 43 12 13 21 22 30 31 39 40 5 14 23 32 17 26 35 44\n        DETECTOR rec[-30] rec[-31] rec[-47] rec[-107] rec[-156] rec[-157]\n        DETECTOR rec[-26] rec[-27] rec[-41] rec[-101] rec[-152] rec[-153]\n        DETECTOR rec[-16] rec[-23] rec[-25] rec[-34] rec[-51] rec[-94] rec[-111] rec[-142] rec[-149] rec[-151]\n        DETECTOR rec[-15] rec[-19] rec[-20] rec[-36] rec[-50] rec[-54] rec[-96] rec[-110] rec[-114] rec[-141] rec[-145] rec[-146]\n        DETECTOR rec[-14] rec[-17] rec[-18] rec[-35] rec[-52] rec[-53] rec[-95] rec[-112] rec[-113] rec[-140] rec[-143] rec[-144]\n        DETECTOR rec[-13] rec[-28] rec[-32] rec[-38] rec[-40] rec[-98] rec[-100] rec[-139] rec[-154] rec[-158]\n        DETECTOR rec[-2] rec[-11] rec[-12] rec[-39] rec[-44] rec[-45] rec[-99] rec[-104] rec[-105] rec[-128] rec[-137] rec[-138]\n        DETECTOR rec[-1] rec[-9] rec[-10] rec[-37] rec[-42] rec[-43] rec[-97] rec[-102] rec[-103] rec[-127] rec[-135] rec[-136]\n        TICK\n        MYY 8 9 17 18 26 27 35 36 44 45 51 52 5 6 14 15 23 24 32 33 41 42 0 1 7 16 25 34 43 50 11 12 20 21 29 30 38 39 47 48 3 4 13 22 31 40 2 10 19 28 37 46 49 53\n        DETECTOR rec[-15] rec[-20] rec[-21] rec[-31] rec[-39] rec[-40] rec[-157] rec[-165] rec[-166] rec[-201] rec[-206] rec[-207]\n        DETECTOR rec[-14] rec[-18] rec[-19] rec[-30] rec[-37] rec[-38] rec[-156] rec[-163] rec[-164] rec[-200] rec[-204] rec[-205]\n        DETECTOR rec[-6] rec[-11] rec[-12] rec[-34] rec[-35] rec[-42] rec[-160] rec[-161] rec[-168] rec[-192] rec[-197] rec[-198]\n        DETECTOR rec[-5] rec[-9] rec[-10] rec[-32] rec[-33] rec[-41] rec[-158] rec[-159] rec[-167] rec[-191] rec[-195] rec[-196]\n        DETECTOR rec[-3] rec[-25] rec[-26] rec[-29] rec[-45] rec[-46] rec[-155] rec[-171] rec[-172] rec[-189] rec[-211] rec[-212]\n        DETECTOR rec[-2] rec[-23] rec[-24] rec[-28] rec[-43] rec[-44] rec[-154] rec[-169] rec[-170] rec[-188] rec[-209] rec[-210]\n        TICK\n        MX 0 1 2 3 4 8 51 50 52 41 47 53\n        MXX 48 49 9 10 18 19 27 28 36 37 45 46 11 20 29 38 6 7 15 16 24 25 33 34 42 43 12 13 21 22 30 31 39 40 5 14 23 32 17 26 35 44\n        DETECTOR rec[-32] rec[-33] rec[-92] rec[-93]\n        DETECTOR rec[-29] rec[-30] rec[-89] rec[-90]\n        DETECTOR rec[-25] rec[-27] rec[-85] rec[-87]\n        DETECTOR rec[-21] rec[-22] rec[-23] rec[-81] rec[-82] rec[-83]\n        DETECTOR rec[-20] rec[-28] rec[-31] rec[-80] rec[-88] rec[-91]\n        DETECTOR rec[-9] rec[-24] rec[-26] rec[-69] rec[-84] rec[-86]\n        DETECTOR rec[-7] rec[-8] rec[-15] rec[-67] rec[-68] rec[-75]\n        DETECTOR rec[-5] rec[-6] rec[-14] rec[-65] rec[-66] rec[-74]\n        DETECTOR rec[-4] rec[-12] rec[-13] rec[-64] rec[-72] rec[-73]\n        DETECTOR rec[-3] rec[-10] rec[-11] rec[-63] rec[-70] rec[-71]\n        DETECTOR rec[-2] rec[-18] rec[-19] rec[-62] rec[-78] rec[-79]\n        DETECTOR rec[-1] rec[-16] rec[-17] rec[-61] rec[-76] rec[-77]\n        TICK\n        M 0 5 14 23 32 41 13 22 31 40 49 53\n        MZZ 19 20 28 29 37 38 46 47 10 11 21 30 4 12 2 3 39 48 16 17 25 26 34 35 43 44 50 51 7 8 15 24 1 6 33 42 9 18 27 36 45 52\n        DETECTOR rec[-31] rec[-32] rec[-37] rec[-97] rec[-157] rec[-158]\n        DETECTOR rec[-29] rec[-30] rec[-36] rec[-96] rec[-155] rec[-156]\n        DETECTOR rec[-16] rec[-25] rec[-26] rec[-39] rec[-40] rec[-99] rec[-100] rec[-142] rec[-151] rec[-152]\n        DETECTOR rec[-13] rec[-23] rec[-24] rec[-38] rec[-54] rec[-98] rec[-114] rec[-139] rec[-149] rec[-150]\n        DETECTOR rec[-6] rec[-11] rec[-12] rec[-35] rec[-44] rec[-45] rec[-95] rec[-104] rec[-105] rec[-132] rec[-137] rec[-138]\n        DETECTOR rec[-4] rec[-9] rec[-10] rec[-34] rec[-42] rec[-43] rec[-94] rec[-102] rec[-103] rec[-130] rec[-135] rec[-136]\n        DETECTOR rec[-3] rec[-17] rec[-21] rec[-48] rec[-52] rec[-53] rec[-108] rec[-112] rec[-113] rec[-129] rec[-143] rec[-147]\n        DETECTOR rec[-2] rec[-19] rec[-20] rec[-47] rec[-50] rec[-51] rec[-107] rec[-110] rec[-111] rec[-128] rec[-145] rec[-146]\n        TICK\n        MYY 8 9 17 18 26 27 35 36 44 45 51 52 5 6 14 15 23 24 32 33 41 42 0 1 7 16 25 34 43 50 11 12 20 21 29 30 38 39 47 48 3 4 13 22 31 40 2 10 19 28 37 46 49 53\n        DETECTOR rec[-15] rec[-26] rec[-27] rec[-30] rec[-34] rec[-39] rec[-156] rec[-160] rec[-165] rec[-201] rec[-212] rec[-213]\n        DETECTOR rec[-14] rec[-24] rec[-25] rec[-29] rec[-37] rec[-38] rec[-155] rec[-163] rec[-164] rec[-200] rec[-210] rec[-211]\n        DETECTOR rec[-13] rec[-22] rec[-23] rec[-28] rec[-35] rec[-36] rec[-154] rec[-161] rec[-162] rec[-199] rec[-208] rec[-209]\n        DETECTOR rec[-4] rec[-7] rec[-12] rec[-41] rec[-42] rec[-44] rec[-167] rec[-168] rec[-170] rec[-190] rec[-193] rec[-198]\n        DETECTOR rec[-3] rec[-10] rec[-11] rec[-43] rec[-47] rec[-48] rec[-169] rec[-173] rec[-174] rec[-189] rec[-196] rec[-197]\n        DETECTOR rec[-2] rec[-8] rec[-9] rec[-40] rec[-45] rec[-46] rec[-166] rec[-171] rec[-172] rec[-188] rec[-194] rec[-195]\n        TICK\n        M 0 5 14 23 32 41 13 22 31 40 49 53\n        MZZ 19 20 28 29 37 38 46 47 10 11 21 30 4 12 2 3 39 48 16 17 25 26 34 35 43 44 50 51 7 8 15 24 1 6 33 42 9 18 27 36 45 52\n        DETECTOR rec[-26] rec[-27] rec[-86] rec[-87]\n        DETECTOR rec[-24] rec[-25] rec[-84] rec[-85]\n        DETECTOR rec[-22] rec[-23] rec[-82] rec[-83]\n        DETECTOR rec[-16] rec[-20] rec[-21] rec[-76] rec[-80] rec[-81]\n        DETECTOR rec[-14] rec[-15] rec[-17] rec[-74] rec[-75] rec[-77]\n        DETECTOR rec[-13] rec[-18] rec[-19] rec[-73] rec[-78] rec[-79]\n        DETECTOR rec[-6] rec[-30] rec[-31] rec[-66] rec[-90] rec[-91]\n        DETECTOR rec[-5] rec[-32] rec[-33] rec[-65] rec[-92] rec[-93]\n        DETECTOR rec[-4] rec[-28] rec[-29] rec[-64] rec[-88] rec[-89]\n        DETECTOR rec[-3] rec[-7] rec[-12] rec[-63] rec[-67] rec[-72]\n        DETECTOR rec[-2] rec[-10] rec[-11] rec[-62] rec[-70] rec[-71]\n        DETECTOR rec[-1] rec[-8] rec[-9] rec[-61] rec[-68] rec[-69]\n        TICK\n        MX 0 1 2 3 4 8 51 50 52 41 47 53\n        MXX 9 10 18 19 27 28 36 37 45 46 11 20 29 38 6 7 15 16 24 25 33 34 42 43 12 13 21 22 30 31 39 40 5 14 23 32 17 26 35 44 48 49\n        DETECTOR rec[-30] rec[-31] rec[-47] rec[-107] rec[-156] rec[-157]\n        DETECTOR rec[-26] rec[-27] rec[-41] rec[-101] rec[-152] rec[-153]\n        DETECTOR rec[-17] rec[-23] rec[-25] rec[-34] rec[-51] rec[-94] rec[-111] rec[-142] rec[-149] rec[-151]\n        DETECTOR rec[-16] rec[-20] rec[-21] rec[-36] rec[-50] rec[-54] rec[-96] rec[-110] rec[-114] rec[-141] rec[-145] rec[-146]\n        DETECTOR rec[-15] rec[-18] rec[-19] rec[-35] rec[-52] rec[-53] rec[-95] rec[-112] rec[-113] rec[-140] rec[-143] rec[-144]\n        DETECTOR rec[-14] rec[-28] rec[-32] rec[-38] rec[-40] rec[-98] rec[-100] rec[-139] rec[-154] rec[-158]\n        DETECTOR rec[-3] rec[-12] rec[-13] rec[-39] rec[-44] rec[-45] rec[-99] rec[-104] rec[-105] rec[-128] rec[-137] rec[-138]\n        DETECTOR rec[-2] rec[-10] rec[-11] rec[-37] rec[-42] rec[-43] rec[-97] rec[-102] rec[-103] rec[-127] rec[-135] rec[-136]\n        TICK\n        MYY 8 9 17 18 26 27 35 36 44 45 51 52 5 6 14 15 23 24 32 33 41 42 0 1 7 16 25 34 43 50 11 12 20 21 29 30 38 39 47 48 3 4 13 22 31 40 2 10 19 28 37 46 49 53\n        DETECTOR rec[-15] rec[-20] rec[-21] rec[-32] rec[-40] rec[-41] rec[-157] rec[-165] rec[-166] rec[-201] rec[-206] rec[-207]\n        DETECTOR rec[-14] rec[-18] rec[-19] rec[-31] rec[-38] rec[-39] rec[-156] rec[-163] rec[-164] rec[-200] rec[-204] rec[-205]\n        DETECTOR rec[-6] rec[-11] rec[-12] rec[-35] rec[-36] rec[-43] rec[-160] rec[-161] rec[-168] rec[-192] rec[-197] rec[-198]\n        DETECTOR rec[-5] rec[-9] rec[-10] rec[-33] rec[-34] rec[-42] rec[-158] rec[-159] rec[-167] rec[-191] rec[-195] rec[-196]\n        DETECTOR rec[-3] rec[-25] rec[-26] rec[-30] rec[-46] rec[-47] rec[-155] rec[-171] rec[-172] rec[-189] rec[-211] rec[-212]\n        DETECTOR rec[-2] rec[-23] rec[-24] rec[-29] rec[-44] rec[-45] rec[-154] rec[-169] rec[-170] rec[-188] rec[-209] rec[-210]\n        TICK\n        M 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53\n        DETECTOR rec[-53] rec[-54] rec[-70] rec[-113] rec[-114]\n        DETECTOR rec[-50] rec[-51] rec[-61] rec[-110] rec[-111]\n        DETECTOR rec[-44] rec[-45] rec[-46] rec[-52] rec[-58] rec[-81] rec[-102] rec[-109] rec[-112]\n        DETECTOR rec[-42] rec[-43] rec[-44] rec[-50] rec[-51] rec[-52] rec[-58] rec[-61] rec[-66] rec[-128] rec[-129] rec[-131] rec[-151] rec[-154] rec[-159]\n        DETECTOR rec[-38] rec[-39] rec[-40] rec[-47] rec[-48] rec[-49] rec[-69] rec[-74] rec[-75] rec[-86] rec[-94] rec[-95]\n        DETECTOR rec[-36] rec[-37] rec[-38] rec[-45] rec[-46] rec[-47] rec[-69] rec[-80] rec[-81] rec[-117] rec[-121] rec[-126] rec[-162] rec[-173] rec[-174]\n        DETECTOR rec[-32] rec[-33] rec[-34] rec[-41] rec[-42] rec[-43] rec[-60] rec[-65] rec[-66] rec[-89] rec[-90] rec[-97]\n        DETECTOR rec[-26] rec[-27] rec[-28] rec[-35] rec[-36] rec[-37] rec[-57] rec[-79] rec[-80] rec[-84] rec[-100] rec[-101]\n        DETECTOR rec[-24] rec[-25] rec[-26] rec[-33] rec[-34] rec[-35] rec[-57] rec[-64] rec[-65] rec[-130] rec[-134] rec[-135] rec[-150] rec[-157] rec[-158]\n        DETECTOR rec[-20] rec[-21] rec[-22] rec[-29] rec[-30] rec[-31] rec[-68] rec[-72] rec[-73] rec[-85] rec[-92] rec[-93]\n        DETECTOR rec[-18] rec[-19] rec[-20] rec[-27] rec[-28] rec[-29] rec[-68] rec[-78] rec[-79] rec[-116] rec[-124] rec[-125] rec[-161] rec[-171] rec[-172]\n        DETECTOR rec[-14] rec[-15] rec[-16] rec[-23] rec[-24] rec[-25] rec[-59] rec[-63] rec[-64] rec[-87] rec[-88] rec[-96]\n        DETECTOR rec[-8] rec[-9] rec[-10] rec[-17] rec[-18] rec[-19] rec[-56] rec[-77] rec[-78] rec[-83] rec[-98] rec[-99]\n        DETECTOR rec[-6] rec[-7] rec[-8] rec[-15] rec[-16] rec[-17] rec[-56] rec[-62] rec[-63] rec[-127] rec[-132] rec[-133] rec[-149] rec[-155] rec[-156]\n        DETECTOR rec[-4] rec[-11] rec[-12] rec[-13] rec[-67] rec[-71] rec[-91] rec[-105] rec[-107]\n        DETECTOR rec[-2] rec[-3] rec[-76] rec[-106] rec[-108]\n        DETECTOR rec[-2] rec[-3] rec[-4] rec[-9] rec[-10] rec[-11] rec[-67] rec[-76] rec[-77] rec[-115] rec[-122] rec[-123] rec[-160] rec[-169] rec[-170]\n        DETECTOR rec[-1] rec[-5] rec[-6] rec[-7] rec[-55] rec[-62] rec[-82] rec[-103] rec[-104]\n        OBSERVABLE_INCLUDE(0) rec[-2] rec[-3] rec[-9] rec[-10] rec[-18] rec[-19] rec[-27] rec[-28] rec[-36] rec[-37] rec[-45] rec[-46] rec[-76] rec[-77] rec[-78] rec[-79] rec[-80] rec[-81] rec[-83] rec[-84] rec[-108] rec[-109] rec[-115] rec[-116] rec[-117] rec[-175] rec[-176] rec[-177] rec[-208] rec[-209] rec[-234] rec[-235] rec[-268] rec[-269] rec[-294] rec[-295] rec[-301] rec[-302] rec[-303] rec[-361] rec[-362] rec[-363] rec[-394] rec[-395] rec[-420] rec[-421] rec[-454] rec[-455] rec[-480] rec[-481] rec[-487] rec[-488] rec[-489] rec[-547] rec[-548] rec[-549] rec[-580] rec[-581] rec[-606] rec[-607] rec[-634] rec[-635] rec[-636] rec[-637] rec[-638] rec[-639]\n    )CIRCUIT\");\n    Circuit suffix = missing_detectors(c, true);\n    ASSERT_EQ(suffix, Circuit(R\"CIRCUIT(\n        DETECTOR rec[-377] rec[-375] rec[-374] rec[-317] rec[-315] rec[-314]\n    )CIRCUIT\"));\n}\n\nTEST(missing_detectors, toric_code_global_stabilizer_product) {\n    Circuit c = Circuit(R\"CIRCUIT(\n        R 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n        TICK\n        MPP X0*X4*X5*X1 X2*X6*X7*X3 X10*X14*X15*X11 X8*X12*X13*X9\n        TICK\n        MPP X5*X9*X10*X6 X1*X13*X14*X2 X0*X12*X15*X3 X4*X8*X11*X7\n        TICK\n        MPP Z4*Z8*Z9*Z5 Z6*Z10*Z11*Z7 Z2*Z14*Z15*Z3 Z0*Z12*Z13*Z1\n        TICK\n        MPP Z1*Z5*Z6*Z2 Z9*Z13*Z14*Z10 Z8*Z12*Z15*Z11 Z0*Z4*Z7*Z3\n        DETECTOR rec[-1]\n        DETECTOR rec[-2]\n        DETECTOR rec[-3]\n        DETECTOR rec[-4]\n        DETECTOR rec[-5]\n        DETECTOR rec[-6]\n        DETECTOR rec[-7]\n        DETECTOR rec[-8]\n    )CIRCUIT\");\n    Circuit suffix = missing_detectors(c, true);\n    ASSERT_EQ(suffix, Circuit(R\"CIRCUIT(\n        DETECTOR rec[-16] rec[-15] rec[-14] rec[-13] rec[-12] rec[-11] rec[-10] rec[-9]\n    )CIRCUIT\"));\n}\n"
  },
  {
    "path": "src/stim/util_top/reference_sample_tree.cc",
    "content": "#include \"stim/util_top/reference_sample_tree.h\"\n\n#if defined(_WIN32)\n#include <intrin.h>\n#pragma intrinsic(_umul128)\n#endif\n\nusing namespace stim;\n\nbool ReferenceSampleTree::empty() const {\n    if (repetitions == 0) {\n        return true;\n    }\n    if (!prefix_bits.empty()) {\n        return false;\n    }\n    for (const auto &child : suffix_children) {\n        if (!child.empty()) {\n            return false;\n        }\n    }\n    return true;\n}\n\nvoid ReferenceSampleTree::flatten_and_simplify_into(std::vector<ReferenceSampleTree> &out) const {\n    if (repetitions == 0) {\n        return;\n    }\n\n    // Flatten children.\n    std::vector<ReferenceSampleTree> flattened;\n    if (!prefix_bits.empty()) {\n        flattened.push_back(\n            ReferenceSampleTree{\n                .prefix_bits = prefix_bits,\n                .suffix_children = {},\n                .repetitions = 1,\n            });\n    }\n    for (const auto &child : suffix_children) {\n        child.flatten_and_simplify_into(flattened);\n    }\n\n    // Fuse children.\n    std::vector<ReferenceSampleTree> fused;\n    if (!flattened.empty()) {\n        fused.push_back(std::move(flattened[0]));\n    }\n    for (size_t k = 1; k < flattened.size(); k++) {\n        auto &dst = fused.back();\n        auto &src = flattened[k];\n\n        // Combine children with identical contents by adding their rep counts.\n        if (dst.prefix_bits == src.prefix_bits && dst.suffix_children == src.suffix_children) {\n            dst.repetitions += src.repetitions;\n\n            // Fuse children with unrepeated contents if they can be fused.\n        } else if (src.repetitions == 1 && dst.repetitions == 1 && dst.suffix_children.empty()) {\n            dst.suffix_children = std::move(src.suffix_children);\n            dst.prefix_bits.insert(dst.prefix_bits.end(), src.prefix_bits.begin(), src.prefix_bits.end());\n\n        } else {\n            fused.push_back(std::move(src));\n        }\n    }\n\n    if (repetitions == 1) {\n        // Un-nest all the children.\n        for (auto &e : fused) {\n            out.push_back(e);\n        }\n    } else if (fused.size() == 1) {\n        // Merge with single child.\n        fused[0].repetitions *= repetitions;\n        out.push_back(std::move(fused[0]));\n    } else if (fused.empty()) {\n        // Nothing to report.\n    } else if (fused[0].suffix_children.empty() && fused[0].repetitions == 1) {\n        // Take payload from first child.\n        ReferenceSampleTree result = std::move(fused[0]);\n        fused.erase(fused.begin());\n        result.repetitions = repetitions;\n        result.suffix_children = std::move(fused);\n        out.push_back(std::move(result));\n    } else {\n        out.push_back(\n            ReferenceSampleTree{\n                .prefix_bits = {},\n                .suffix_children = std::move(fused),\n                .repetitions = repetitions,\n            });\n    }\n}\n\n/// Finds how far back feedback operations ever look, within the loop.\nuint64_t stim::max_feedback_lookback_in_loop(const Circuit &loop) {\n    uint64_t furthest_lookback = 0;\n    for (const auto &inst : loop.operations) {\n        if (inst.gate_type == GateType::REPEAT) {\n            furthest_lookback =\n                std::max(furthest_lookback, max_feedback_lookback_in_loop(inst.repeat_block_body(loop)));\n        } else {\n            auto f = GATE_DATA[inst.gate_type].flags;\n            if ((f & GateFlags::GATE_CAN_TARGET_BITS) && (f & GateFlags::GATE_TARGETS_PAIRS)) {\n                // Feedback-capable operation. Check for any measurement record targets.\n                for (auto t : inst.targets) {\n                    if (t.is_measurement_record_target()) {\n                        furthest_lookback = std::max(furthest_lookback, (uint64_t)-t.rec_offset());\n                    }\n                }\n            }\n        }\n    }\n    return furthest_lookback;\n}\n\nvoid ReferenceSampleTree::try_factorize(size_t period_factor) {\n    if (prefix_bits.size() != 0 || suffix_children.size() % period_factor != 0) {\n        return;\n    }\n\n    // Check if contents are periodic with the factor.\n    size_t h = suffix_children.size() / period_factor;\n    for (size_t k = h; k < suffix_children.size(); k++) {\n        if (suffix_children[k - h] != suffix_children[k]) {\n            return;\n        }\n    }\n\n    // Factorize.\n    suffix_children.resize(h);\n    repetitions *= period_factor;\n}\n\nReferenceSampleTree ReferenceSampleTree::simplified() const {\n    std::vector<ReferenceSampleTree> flat;\n    flatten_and_simplify_into(flat);\n    if (flat.empty()) {\n        return ReferenceSampleTree();\n    } else if (flat.size() == 1) {\n        return std::move(flat[0]);\n    }\n\n    ReferenceSampleTree result;\n    result.repetitions = 1;\n\n    // Take payload from first child.\n    if (flat[0].repetitions == 1 && flat[0].suffix_children.empty()) {\n        result = std::move(flat[0]);\n        flat.erase(flat.begin());\n    }\n\n    result.suffix_children = std::move(flat);\n    return result;\n}\n\nuint64_t ReferenceSampleTree::size() const {\n    uint64_t result = prefix_bits.size();\n    for (const auto &child : suffix_children) {\n        result += child.size();\n    }\n#if defined(__GNUC__) || defined(__clang__)\n    bool overflow = __builtin_mul_overflow(result, repetitions, &result);\n    assert(!overflow);\n#elif defined(_WIN64)\n    uint64_t overflow;\n    result = _umul128(result, repetitions, &overflow);\n    assert(overflow == 0);\n#else\n    assert((repetitions == 0) || (result <= (UINT64_MAX / repetitions)));\n    result *= repetitions;\n#endif\n    return result;\n}\n\nvoid ReferenceSampleTree::decompress_into(std::vector<bool> &output) const {\n    for (uint64_t k = 0; k < repetitions; k++) {\n        output.insert(output.end(), prefix_bits.begin(), prefix_bits.end());\n        for (const auto &child : suffix_children) {\n            child.decompress_into(output);\n        }\n    }\n}\n\nReferenceSampleTree ReferenceSampleTree::from_circuit_reference_sample(const Circuit &circuit) {\n    auto stats = circuit.compute_stats();\n    std::mt19937_64 irrelevant_rng{0};\n    CompressedReferenceSampleHelper<MAX_BITWORD_WIDTH> helper(\n        TableauSimulator<MAX_BITWORD_WIDTH>(\n            std::move(irrelevant_rng), stats.num_qubits, +1, MeasureRecord(stats.max_lookback)));\n    return helper.do_loop_with_tortoise_hare_folding(circuit, 1).simplified();\n}\n\nstd::string ReferenceSampleTree::str() const {\n    std::stringstream ss;\n    ss << *this;\n    return ss.str();\n}\n\nbool ReferenceSampleTree::operator==(const ReferenceSampleTree &other) const {\n    return repetitions == other.repetitions && prefix_bits == other.prefix_bits &&\n           suffix_children == other.suffix_children;\n}\nbool ReferenceSampleTree::operator!=(const ReferenceSampleTree &other) const {\n    return !(*this == other);\n}\n\nbool ReferenceSampleTree::operator[](uint64_t index) const {\n    uint64_t current_absolute_index = 0;\n    bool result;\n    bool value_found = try_get_bit_value(index, current_absolute_index, result);\n    assert(value_found);\n    return result;\n}\n\nbool ReferenceSampleTree::try_get_bit_value(\n    uint64_t desired_absolute_index, uint64_t &current_absolute_index, bool &bit_value) const {\n    // Run through once to allow shallow accesses (without unnecessary full iteration of the tree).\n    const uint64_t current_relative_starting_index = current_absolute_index;\n    {\n        const uint64_t relative_index = desired_absolute_index - current_absolute_index;\n        if (relative_index < prefix_bits.size()) {\n            bit_value = prefix_bits[relative_index];\n            return true;\n        }\n        current_absolute_index += prefix_bits.size();\n        for (const ReferenceSampleTree &child : suffix_children) {\n            if (child.try_get_bit_value(desired_absolute_index, current_absolute_index, bit_value)) {\n                return true;\n            }\n        }\n    }\n    // After the first full iteration, extrapolate the repetition size and skip to the proper iteration.\n    const uint64_t single_iteration_size = current_absolute_index - current_relative_starting_index;\n    const uint64_t skip_to_iteration_count =\n        (desired_absolute_index - current_relative_starting_index) / single_iteration_size;\n    if (skip_to_iteration_count < repetitions) {\n        // If the desired index is in this part of the tree, skip forward to the appropriate iteration.\n        current_absolute_index += single_iteration_size * (skip_to_iteration_count - 1);\n        // Do the final iteration to find the value.\n        const uint64_t relative_index = desired_absolute_index - current_absolute_index;\n        if (relative_index < prefix_bits.size()) {\n            bit_value = prefix_bits[relative_index];\n            return true;\n        }\n        current_absolute_index += prefix_bits.size();\n        for (const ReferenceSampleTree &child : suffix_children) {\n            if (child.try_get_bit_value(desired_absolute_index, current_absolute_index, bit_value)) {\n                return true;\n            }\n        }\n    } else {\n        // Advance past this node for parent to continue.\n        current_absolute_index += single_iteration_size * (repetitions - 1);\n    }\n    return false;\n}\n\nstd::ostream &stim::operator<<(std::ostream &out, const ReferenceSampleTree &v) {\n    out << v.repetitions << \"*\";\n    out << \"(\";\n    out << \"'\";\n    for (auto b : v.prefix_bits) {\n        out << \"01\"[b];\n    }\n    out << \"'\";\n    for (const auto &child : v.suffix_children) {\n        out << \"+\";\n        out << child;\n    }\n    out << \")\";\n    return out;\n}\n"
  },
  {
    "path": "src/stim/util_top/reference_sample_tree.h",
    "content": "#ifndef _STIM_UTIL_TOP_REFERENCE_SAMPLE_TREE_H\n#define _STIM_UTIL_TOP_REFERENCE_SAMPLE_TREE_H\n\n#include \"stim/simulators/tableau_simulator.h\"\n\nnamespace stim {\n\n/// A compressed tree representation of a reference sample.\nstruct ReferenceSampleTree {\n    /// Raw bits to output before bits from the children.\n    std::vector<bool> prefix_bits;\n    /// Compressed representations of additional bits to output after the prefix.\n    std::vector<ReferenceSampleTree> suffix_children;\n    /// The number of times to repeatedly output the prefix+suffix bits.\n    size_t repetitions = 0;\n\n    /// Initializes a reference sample tree containing a reference sample for the given circuit.\n    static ReferenceSampleTree from_circuit_reference_sample(const Circuit &circuit);\n\n    /// Returns a tree with the same compressed contents, but a simpler tree structure.\n    ReferenceSampleTree simplified() const;\n\n    /// Checks if two trees are exactly the same, including structure (not just uncompressed contents).\n    bool operator==(const ReferenceSampleTree &other) const;\n    /// Checks if two trees are not exactly the same, including structure (not just uncompressed contents).\n    bool operator!=(const ReferenceSampleTree &other) const;\n    /// Returns the bit value for a given absolute index.\n    bool operator[](uint64_t index) const;\n    /// Returns a simple description of the tree's structure, like \"5*('101'+6*('11'))\".\n    std::string str() const;\n\n    /// Determines whether the tree contains any bits at all.\n    bool empty() const;\n    /// Computes the total size of the uncompressed bits represented by the tree.\n    uint64_t size() const;\n\n    /// Writes the contents of the tree into the given output vector.\n    void decompress_into(std::vector<bool> &output) const;\n\n    /// Writes the contents of the tree into the given output simd_bits.\n    template <size_t W>\n    void decompress_into(simd_bits<W> &output) const;\n\n    /// Folds redundant children into the repetition count, if they repeat this many times.\n    ///\n    /// For example, if the tree's children are [A, B, C, A, B, C] and the tree has no\n    /// prefix, then `try_factorize(2)` will reduce the children to [A, B, C] and double\n    /// the repetition count.\n    void try_factorize(size_t period_factor);\n\n   private:\n    /// Helper method for `simplified`.\n    void flatten_and_simplify_into(std::vector<ReferenceSampleTree> &out) const;\n    /// Helper method for `operator[]`.\n    bool try_get_bit_value(uint64_t desired_absolute_index, uint64_t &current_absolute_index, bool &bit_value) const;\n};\nstd::ostream &operator<<(std::ostream &out, const ReferenceSampleTree &v);\n\n/// Helper class for computing compressed reference samples.\ntemplate <size_t W>\nstruct CompressedReferenceSampleHelper {\n    TableauSimulator<W> sim;\n\n    CompressedReferenceSampleHelper(TableauSimulator<MAX_BITWORD_WIDTH> sim) : sim(sim) {\n    }\n\n    /// Processes a loop with no top-level folding.\n    ///\n    /// Loops containing within the body of this loop (or circuit body) may\n    /// still be compressed. Only the top-level loop is not folded.\n    ReferenceSampleTree do_loop_with_no_folding(const Circuit &loop, uint64_t reps);\n\n    /// Runs tortoise-and-hare analysis of the loop while simulating its\n    /// reference sample, in order to attempt to return a compressed\n    /// representation.\n    ReferenceSampleTree do_loop_with_tortoise_hare_folding(const Circuit &loop, uint64_t reps);\n\n    bool in_same_recent_state_as(\n        const CompressedReferenceSampleHelper<W> &other, uint64_t max_record_lookback, bool allow_false_negative) const;\n};\n\nuint64_t max_feedback_lookback_in_loop(const Circuit &loop);\n\n}  // namespace stim\n\n#include \"stim/util_top/reference_sample_tree.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/reference_sample_tree.inl",
    "content": "#include \"stim/util_top/reference_sample_tree.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nvoid ReferenceSampleTree::decompress_into(simd_bits<W> &output) const {\n    std::vector<bool> v;\n    this->decompress_into(v);\n\n    simd_bits<W> result(v.size());\n    for (size_t k = 0; k < v.size(); k++) {\n        result[k] ^= v[k];\n    }\n\n    output = std::move(result);\n}\n\ntemplate <size_t W>\nReferenceSampleTree CompressedReferenceSampleHelper<W>::do_loop_with_no_folding(const Circuit &loop, uint64_t reps) {\n    ReferenceSampleTree result;\n    result.repetitions = 1;\n    size_t start_size = sim.measurement_record.storage.size();\n\n    auto flush_recorded_into_result = [&]() {\n        size_t end_size = sim.measurement_record.storage.size();\n        if (end_size > start_size) {\n            result.suffix_children.push_back({});\n            auto &child = result.suffix_children.back();\n            child.repetitions = 1;\n            child.prefix_bits.insert(\n                child.prefix_bits.end(),\n                sim.measurement_record.storage.begin() + start_size,\n                sim.measurement_record.storage.begin() + end_size);\n        }\n        start_size = end_size;\n    };\n\n    for (size_t k = 0; k < reps; k++) {\n        for (const auto &inst : loop.operations) {\n            if (inst.gate_type == GateType::REPEAT) {\n                uint64_t repeats = inst.repeat_block_rep_count();\n                const auto &block = inst.repeat_block_body(loop);\n                flush_recorded_into_result();\n                result.suffix_children.push_back(do_loop_with_tortoise_hare_folding(block, repeats));\n                start_size = sim.measurement_record.storage.size();\n            } else {\n                sim.do_gate(inst);\n            }\n        }\n    }\n\n    flush_recorded_into_result();\n    return result;\n}\n\ntemplate <size_t W>\nReferenceSampleTree CompressedReferenceSampleHelper<W>::do_loop_with_tortoise_hare_folding(\n    const Circuit &loop, uint64_t reps) {\n    if (reps < 10) {\n        // Probably not worth the overhead of tortoise-and-hare. Just run it raw.\n        return do_loop_with_no_folding(loop, reps);\n    }\n\n    ReferenceSampleTree result;\n    result.repetitions = 1;\n\n    CompressedReferenceSampleHelper<W> tortoise(sim);\n    CompressedReferenceSampleHelper<W> hare(std::move(sim));\n    uint64_t max_feedback_lookback = max_feedback_lookback_in_loop(loop);\n    uint64_t tortoise_steps = 0;\n    uint64_t hare_steps = 0;\n    while (hare_steps < reps) {\n        hare_steps++;\n        result.suffix_children.push_back(hare.do_loop_with_no_folding(loop, 1));\n        assert(result.suffix_children.size() == hare_steps);\n\n        if (tortoise.in_same_recent_state_as(hare, max_feedback_lookback, hare_steps < 10)) {\n            break;\n        }\n\n        // Tortoise advances half as quickly.\n        if (hare_steps & 1) {\n            tortoise_steps++;\n            tortoise.do_loop_with_no_folding(loop, 1);\n        }\n    }\n\n    if (hare_steps == reps) {\n        // No periodic state found before reaching the end of the loop.\n        sim = std::move(hare.sim);\n        return result;\n    }\n\n    // Run more loop iterations until the remaining iterations are a multiple of the found period.\n    assert(result.suffix_children.size() == hare_steps);\n    uint64_t period = hare_steps - tortoise_steps;\n    size_t period_steps_left = (reps - hare_steps) / period;\n    while ((reps - hare_steps) % period) {\n        result.suffix_children.push_back(hare.do_loop_with_no_folding(loop, 1));\n        hare_steps += 1;\n    }\n    assert(hare_steps + period_steps_left * period == reps);\n    assert(hare_steps >= period);\n    sim = std::move(hare.sim);\n\n    // Move the periodic measurements out of the hare's tail, into a loop node.\n    ReferenceSampleTree loop_contents;\n    for (size_t k = hare_steps - period; k < hare_steps; k++) {\n        loop_contents.suffix_children.push_back(std::move(result.suffix_children[k]));\n    }\n    result.suffix_children.resize(hare_steps - period);\n\n    // Add skipped iterations' measurement data into the sim's measurement record.\n    loop_contents.repetitions = 1;\n    sim.measurement_record.discard_results_past_max_lookback();\n    for (size_t k = 0;\n         k < period_steps_left && sim.measurement_record.storage.size() < sim.measurement_record.max_lookback * 2;\n         k++) {\n        loop_contents.decompress_into(sim.measurement_record.storage);\n    }\n    sim.measurement_record.discard_results_past_max_lookback();\n\n    // Add the loop node to the output data.\n    loop_contents.repetitions = period_steps_left + 1;\n    loop_contents.try_factorize(2);\n    loop_contents.try_factorize(3);\n    loop_contents.try_factorize(5);\n    result.suffix_children.push_back(std::move(loop_contents));\n\n    return result;\n}\n\ntemplate <size_t W>\nbool CompressedReferenceSampleHelper<W>::in_same_recent_state_as(\n    const CompressedReferenceSampleHelper<W> &other, uint64_t max_record_lookback, bool allow_false_negative) const {\n    const auto &s1 = sim.measurement_record.storage;\n    const auto &s2 = other.sim.measurement_record.storage;\n\n    // Check that recent measurements gave identical results.\n    if (s1.size() < max_record_lookback || s2.size() < max_record_lookback) {\n        return false;\n    }\n    for (size_t k = 0; k < max_record_lookback; k++) {\n        if (s1[s1.size() - k - 1] != s2[s2.size() - k - 1]) {\n            return false;\n        }\n    }\n\n    // Check that quantum states are identical.\n    if (allow_false_negative) {\n        return sim.inv_state == other.sim.inv_state;\n    }\n    return sim.canonical_stabilizers() == other.sim.canonical_stabilizers();\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/util_top/reference_sample_tree.perf.cc",
    "content": "#include \"stim/util_top/reference_sample_tree.h\"\n\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(reference_sample_tree_surface_code_d31_r1000000000) {\n    CircuitGenParameters params(1000000000, 31, \"rotated_memory_x\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    simd_bits<MAX_BITWORD_WIDTH> ref(0);\n    auto total = 0;\n    benchmark_go([&]() {\n        auto result = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n        total += result.empty();\n    }).goal_millis(25);\n    if (total) {\n        std::cerr << \"data dependence\";\n    }\n}\n\nBENCHMARK(reference_sample_tree_nested_circuit) {\n    Circuit circuit(R\"CIRCUIT(\n        M 0\n        REPEAT 100000 {\n            REPEAT 100000 {\n                REPEAT 100000 {\n                    X 0\n                    M 0\n                }\n                X 0\n                M 0\n            }\n            X 0\n            M 0\n        }\n        X 0\n        M 0\n    )CIRCUIT\");\n    simd_bits<MAX_BITWORD_WIDTH> ref(0);\n    auto total = 0;\n    benchmark_go([&]() {\n        auto result = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n        total += result.empty();\n    }).goal_micros(230);\n    if (total) {\n        std::cerr << \"data dependence\";\n    }\n}\n"
  },
  {
    "path": "src/stim/util_top/reference_sample_tree.test.cc",
    "content": "#include \"stim/util_top/reference_sample_tree.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/gen/gen_surface_code.h\"\n\nusing namespace stim;\n\nvoid expect_tree_matches_normal_reference_sample_of(const ReferenceSampleTree &tree, const Circuit &circuit) {\n    std::vector<bool> decompressed;\n    tree.decompress_into(decompressed);\n    simd_bits<MAX_BITWORD_WIDTH> actual(decompressed.size());\n    for (size_t k = 0; k < decompressed.size(); k++) {\n        actual[k] = decompressed[k];\n    }\n    auto expected = TableauSimulator<MAX_BITWORD_WIDTH>::reference_sample_circuit(circuit);\n    EXPECT_EQ(actual, expected);\n    for (size_t index = 0; index < decompressed.size(); ++index) {\n        ASSERT_EQ(tree[index], decompressed[index]) << \"index: \" << index;\n    }\n}\n\nTEST(ReferenceSampleTree, equality) {\n    ReferenceSampleTree empty1{\n        .prefix_bits = {},\n        .suffix_children = {},\n        .repetitions = 0,\n    };\n    ReferenceSampleTree empty2;\n    ASSERT_EQ(empty1, empty2);\n\n    ASSERT_FALSE(empty1 != empty2);\n    ASSERT_NE(empty1, (ReferenceSampleTree{.prefix_bits = {}, .suffix_children{}, .repetitions = 1}));\n    ASSERT_NE(empty1, (ReferenceSampleTree{.prefix_bits = {0}, .suffix_children{}, .repetitions = 0}));\n    ASSERT_NE(empty1, (ReferenceSampleTree{.prefix_bits = {}, .suffix_children{{}}, .repetitions = 0}));\n}\n\nTEST(ReferenceSampleTree, str) {\n    ASSERT_EQ(\n        (ReferenceSampleTree{\n            .prefix_bits = {},\n            .suffix_children = {},\n            .repetitions = 0,\n        }\n             .str()),\n        \"0*('')\");\n\n    ASSERT_EQ(\n        (ReferenceSampleTree{\n            .prefix_bits = {1, 1, 0, 1},\n            .suffix_children = {},\n            .repetitions = 0,\n        }\n             .str()),\n        \"0*('1101')\");\n\n    ASSERT_EQ(\n        (ReferenceSampleTree{\n            .prefix_bits = {1, 1, 0, 1},\n            .suffix_children = {},\n            .repetitions = 2,\n        }\n             .str()),\n        \"2*('1101')\");\n\n    ASSERT_EQ(\n        (ReferenceSampleTree{\n            .prefix_bits = {1, 1, 0, 1},\n            .suffix_children = {ReferenceSampleTree{\n                .prefix_bits = {1},\n                .suffix_children = {},\n                .repetitions = 5,\n            }},\n            .repetitions = 2,\n        }\n             .str()),\n        \"2*('1101'+5*('1'))\");\n}\n\nTEST(ReferenceSampleTree, simplified) {\n    ReferenceSampleTree raw{\n        .prefix_bits = {},\n        .suffix_children =\n            {\n                ReferenceSampleTree{\n                    .prefix_bits = {},\n                    .suffix_children = {},\n                    .repetitions = 1,\n                },\n                ReferenceSampleTree{\n                    .prefix_bits = {1, 0, 1},\n                    .suffix_children = {{}},\n                    .repetitions = 0,\n                },\n                ReferenceSampleTree{\n                    .prefix_bits = {1, 1, 1},\n                    .suffix_children = {},\n                    .repetitions = 2,\n                },\n            },\n        .repetitions = 3,\n    };\n    ASSERT_EQ(raw.simplified().str(), \"6*('111')\");\n}\n\nTEST(ReferenceSampleTree, decompress_into) {\n    std::vector<bool> result;\n    ReferenceSampleTree tree_under_test{\n        .prefix_bits = {1, 1, 0, 1},\n        .suffix_children = {ReferenceSampleTree{\n            .prefix_bits = {1},\n            .suffix_children = {},\n            .repetitions = 5,\n        }},\n        .repetitions = 2,\n    };\n    tree_under_test.decompress_into(result);\n    std::vector<bool> expected = std::vector<bool>{1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1};\n    ASSERT_EQ(result, expected);\n    for (size_t index = 0; index < expected.size(); ++index) {\n        ASSERT_EQ(tree_under_test[index], expected[index]) << \"index: \" << index;\n    }\n\n    result.clear();\n    tree_under_test = ReferenceSampleTree{\n        .prefix_bits = {1, 1, 0, 1},\n        .suffix_children =\n            {\n                ReferenceSampleTree{\n                    .prefix_bits = {1, 0, 1},\n                    .suffix_children = {},\n                    .repetitions = 8,\n                },\n                ReferenceSampleTree{\n                    .prefix_bits = {0, 0},\n                    .suffix_children = {},\n                    .repetitions = 1,\n                },\n            },\n        .repetitions = 1,\n    };\n    tree_under_test.decompress_into(result);\n    expected =\n        std::vector<bool>{1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0};\n    ASSERT_EQ(result, expected);\n    for (size_t index = 0; index < expected.size(); ++index) {\n        ASSERT_EQ(tree_under_test[index], expected[index]) << \"index: \" << index;\n    }\n}\n\nTEST(ReferenceSampleTree, simple_circuit) {\n    Circuit circuit(R\"CIRCUIT(\n        M 0\n        X 0\n        M 0\n    )CIRCUIT\");\n    auto ref = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n    expect_tree_matches_normal_reference_sample_of(ref, circuit);\n    ASSERT_EQ(ref.str(), \"1*('01')\");\n}\n\nTEST(ReferenceSampleTree, simple_loop) {\n    Circuit circuit(R\"CIRCUIT(\n        REPEAT 50 {\n            M 0\n            X 0\n            M 0\n        }\n    )CIRCUIT\");\n    auto ref = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n    expect_tree_matches_normal_reference_sample_of(ref, circuit);\n    ASSERT_EQ(ref.str(), \"25*('0110')\");\n}\n\nTEST(ReferenceSampleTree, period4_loop) {\n    Circuit circuit(R\"CIRCUIT(\n        M 0\n        X 0\n        M 0\n        REPEAT 50 {\n            CX 0 1 1 2 2 3\n            M 0 1 2 3\n        }\n        X 0\n        M 0\n        X 2\n        M 2 2 2 2 2\n        MPAD 1 0 1 0 1 1\n    )CIRCUIT\");\n    auto ref = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n    ASSERT_EQ(ref.size(), circuit.count_measurements());\n    expect_tree_matches_normal_reference_sample_of(ref, circuit);\n    ASSERT_EQ(ref.str(), \"1*('01111110101100100011111010'+11*('1100100011111010')+1*('000000101011'))\");\n}\n\nTEST(ReferenceSampleTree, feedback) {\n    Circuit circuit(R\"CIRCUIT(\n        MPAD 0 0 1 0\n        REPEAT 200 {\n            CX rec[-4] 1\n            M 1\n        }\n    )CIRCUIT\");\n    auto ref = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n    ASSERT_EQ(ref.size(), circuit.count_measurements());\n    expect_tree_matches_normal_reference_sample_of(ref, circuit);\n    ASSERT_EQ(ref.str(), \"1*('0010'+2*('0')+4*('1')+1*('01011001000111')+12*('101011001000111'))\");\n}\n\nTEST(max_feedback_lookback_in_loop, simple) {\n    ASSERT_EQ(max_feedback_lookback_in_loop(Circuit()), 0);\n\n    ASSERT_EQ(\n        max_feedback_lookback_in_loop(Circuit(R\"CIRCUIT(\n        REPEAT 100 {\n            REPEAT 100 {\n                M 0\n                X 0\n                M 0\n            }\n            REPEAT 200 {\n                M 0\n                DETECTOR rec[-1]\n            }\n            X 1\n            CX 1 0\n        }\n    )CIRCUIT\")),\n        0);\n\n    ASSERT_EQ(\n        max_feedback_lookback_in_loop(Circuit(R\"CIRCUIT(\n        CX rec[-1] 0\n    )CIRCUIT\")),\n        1);\n\n    ASSERT_EQ(\n        max_feedback_lookback_in_loop(Circuit(R\"CIRCUIT(\n        CZ 0 rec[-2]\n    )CIRCUIT\")),\n        2);\n\n    ASSERT_EQ(\n        max_feedback_lookback_in_loop(Circuit(R\"CIRCUIT(\n        CZ 0 rec[-2]\n        CY 0 rec[-3]\n    )CIRCUIT\")),\n        3);\n\n    ASSERT_EQ(\n        max_feedback_lookback_in_loop(Circuit(R\"CIRCUIT(\n        CZ 0 rec[-2]\n        REPEAT 100 {\n            CX rec[-5] 0\n        }\n    )CIRCUIT\")),\n        5);\n}\n\nTEST(ReferenceSampleTree, nested_loops) {\n    Circuit circuit(R\"CIRCUIT(\n        REPEAT 100 {\n            REPEAT 100 {\n                M 0\n                X 0\n                M 0\n            }\n            REPEAT 200 {\n                M 0\n            }\n            X 1\n            CX 1 0\n        }\n    )CIRCUIT\");\n    auto ref = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n    expect_tree_matches_normal_reference_sample_of(ref, circuit);\n    ASSERT_EQ(\n        ref.str(),\n        \"1*(''+50*('0110')+200*('0')+50*('1001')+200*('1')+50*('1001')+200*('1')+50*('0110')+200*('0')+24*(''+50*('\"\n        \"0110')+200*('0')+50*('1001')+200*('1')+50*('1001')+200*('1')+50*('0110')+200*('0')))\");\n}\n\nTEST(ReferenceSampleTree, surface_code) {\n    CircuitGenParameters params(10000, 5, \"rotated_memory_x\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    auto ref = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n    ASSERT_EQ(ref.str(), \"1*(''+10000*('000000000000000000000000')+1*('0000000000000000000000000'))\");\n}\n\nTEST(ReferenceSampleTree, surface_code_with_pauli) {\n    CircuitGenParameters params(10000, 3, \"rotated_memory_x\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    circuit.blocks[0].append_from_text(\"X 10 11 12 13\");\n    auto ref = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n    ASSERT_EQ(ref.str(), \"1*(''+2*('00000000')+4999*('0110000000110000')+1*('000000000'))\");\n}\n\nTEST(ReferenceSampleTree, surface_code_with_pauli_vs_normal_reference_sample) {\n    CircuitGenParameters params(20, 3, \"rotated_memory_x\");\n    auto circuit = generate_surface_code_circuit(params).circuit;\n    circuit.blocks[0].append_from_text(\"X 10 11 12 13\");\n    auto ref = ReferenceSampleTree::from_circuit_reference_sample(circuit);\n    ASSERT_EQ(ref.size(), circuit.count_measurements());\n    expect_tree_matches_normal_reference_sample_of(ref, circuit);\n}\n\nTEST(ReferenceSampleTree, random_access_large_tree) {\n    ReferenceSampleTree tree_under_test{\n        .prefix_bits = {1, 1, 0, 1},\n        .suffix_children =\n            {ReferenceSampleTree{\n                 .prefix_bits = {1, 0, 1},\n                 .suffix_children = {},\n                 .repetitions = 60'000'000,\n             },\n             ReferenceSampleTree{\n                 .prefix_bits = {0, 0, 0, 0, 0, 0, 1},\n                 .suffix_children = {ReferenceSampleTree{\n                     .prefix_bits = {1, 1, 1, 0, 0, 1},\n                     .suffix_children = {},\n                     .repetitions = 42,\n                 }},\n                 .repetitions = 2'000'000'000,\n             },\n             ReferenceSampleTree{\n                 .prefix_bits = {0, 0, 0, 0, 1},\n                 .suffix_children = {},\n                 .repetitions = 999'000'000,\n             }},\n        .repetitions = 1'234'000,\n    };\n\n    std::vector<bool> expected_beginning = std::vector<bool>{1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1};\n    for (size_t index = 0; index < expected_beginning.size(); ++index) {\n        ASSERT_EQ(tree_under_test[index], expected_beginning[index]) << \"index: \" << index;\n    }\n\n    uint64_t whole_tree_size = tree_under_test.size();\n    ASSERT_EQ(\n        whole_tree_size,\n        1'234'000ULL * (4 + (60'000'000ULL * 3) + (2'000'000'000ULL * (7 + (42 * 6))) + (999'000'000ULL * 5)));\n\n    std::vector<bool> expected_ending =\n        std::vector<bool>{0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};\n    for (uint64_t index = 0; index < expected_ending.size(); ++index) {\n        ASSERT_EQ(tree_under_test[whole_tree_size - expected_ending.size() + index], expected_ending[index])\n            << \"index: \" << index;\n    }\n    // Same thing on previous outer iteration.\n    uint64_t one_outer_iter_before_ending = whole_tree_size - (whole_tree_size / 1'234'000ULL);\n    for (uint64_t index = 0; index < expected_ending.size(); ++index) {\n        ASSERT_EQ(\n            tree_under_test[one_outer_iter_before_ending - expected_ending.size() + index], expected_ending[index])\n            << \"index: \" << index;\n    }\n}\n"
  },
  {
    "path": "src/stim/util_top/simplified_circuit.cc",
    "content": "#include \"stim/util_top/simplified_circuit.h\"\n\n#include <functional>\n\n#include \"stim/circuit/gate_decomposition.h\"\n#include \"stim/mem/simd_bits.h\"\n\nusing namespace stim;\n\nstruct Simplifier {\n    size_t num_qubits;\n    std::function<void(const CircuitInstruction &inst)> yield;\n    simd_bits<64> used;\n    std::vector<GateTarget> qs1_buf;\n    std::vector<GateTarget> qs2_buf;\n    std::vector<GateTarget> qs_buf;\n\n    Simplifier(size_t num_qubits, std::function<void(const CircuitInstruction &inst)> init_yield)\n        : num_qubits(num_qubits), yield(init_yield), used(num_qubits) {\n    }\n\n    void do_xcz(SpanRef<const GateTarget> targets, std::string_view tag) {\n        if (targets.empty()) {\n            return;\n        }\n\n        qs_buf.clear();\n        for (size_t k = 0; k < targets.size(); k += 2) {\n            qs_buf.push_back(targets[k + 1]);\n            qs_buf.push_back(targets[k]);\n        }\n        yield(CircuitInstruction{GateType::CX, {}, qs_buf, tag});\n    }\n\n    void simplify_potentially_overlapping_1q_instruction(const CircuitInstruction &inst) {\n        used.clear();\n\n        size_t start = 0;\n        for (size_t k = 0; k < inst.targets.size(); k++) {\n            auto t = inst.targets[k];\n            if (t.has_qubit_value() && used[t.qubit_value()]) {\n                CircuitInstruction disjoint =\n                    CircuitInstruction{inst.gate_type, inst.args, inst.targets.sub(start, k), inst.tag};\n                simplify_disjoint_1q_instruction(disjoint);\n                used.clear();\n                start = k;\n            }\n            if (t.has_qubit_value()) {\n                used[t.qubit_value()] = true;\n            }\n        }\n        simplify_disjoint_1q_instruction(\n            CircuitInstruction{inst.gate_type, inst.args, inst.targets.sub(start, inst.targets.size()), inst.tag});\n    }\n\n    void simplify_potentially_overlapping_2q_instruction(const CircuitInstruction &inst) {\n        used.clear();\n\n        size_t start = 0;\n        for (size_t k = 0; k < inst.targets.size(); k += 2) {\n            auto a = inst.targets[k];\n            auto b = inst.targets[k + 1];\n            if ((a.has_qubit_value() && used[a.qubit_value()]) || (b.has_qubit_value() && used[b.qubit_value()])) {\n                CircuitInstruction disjoint =\n                    CircuitInstruction{inst.gate_type, inst.args, inst.targets.sub(start, k), inst.tag};\n                simplify_disjoint_2q_instruction(disjoint);\n                used.clear();\n                start = k;\n            }\n            if (a.has_qubit_value()) {\n                used[a.qubit_value()] = true;\n            }\n            if (b.has_qubit_value()) {\n                used[b.qubit_value()] = true;\n            }\n        }\n        simplify_disjoint_2q_instruction(\n            CircuitInstruction{inst.gate_type, inst.args, inst.targets.sub(start, inst.targets.size()), inst.tag});\n    }\n\n    void simplify_disjoint_1q_instruction(const CircuitInstruction &inst) {\n        const auto &ts = inst.targets;\n\n        switch (inst.gate_type) {\n            case GateType::I:\n                // Do nothing.\n                break;\n            case GateType::X:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::Y:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::Z:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::C_XYZ:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::C_NXYZ:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::C_XNYZ:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::C_XYNZ:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::C_ZYX:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::C_ZYNX:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::C_ZNYX:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::C_NZYX:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::H:\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::H_XY:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::H_YZ:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::H_NXY:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::H_NXZ:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::H_NYZ:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::S:\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::SQRT_X:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::SQRT_X_DAG:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::SQRT_Y:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::SQRT_Y_DAG:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::S_DAG:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n\n            case GateType::MX:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::M, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::MY:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::M, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::M:\n                yield({GateType::M, {}, ts, inst.tag});\n                break;\n            case GateType::MRX:\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::M, {}, ts, inst.tag});\n                yield({GateType::R, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::MRY:\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::M, {}, ts, inst.tag});\n                yield({GateType::R, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::MR:\n                yield({GateType::M, {}, ts, inst.tag});\n                yield({GateType::R, {}, ts, inst.tag});\n                break;\n            case GateType::RX:\n                yield({GateType::R, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                break;\n            case GateType::RY:\n                yield({GateType::R, {}, ts, inst.tag});\n                yield({GateType::H, {}, ts, inst.tag});\n                yield({GateType::S, {}, ts, inst.tag});\n                break;\n            case GateType::R:\n                yield({GateType::R, {}, ts, inst.tag});\n                break;\n\n            default:\n                throw std::invalid_argument(\"Unhandled in Simplifier::simplify_disjoint_1q_instruction: \" + inst.str());\n        }\n    }\n\n    void simplify_disjoint_2q_instruction(const CircuitInstruction &inst) {\n        const auto &ts = inst.targets;\n        qs_buf.clear();\n        qs1_buf.clear();\n        qs2_buf.clear();\n        for (size_t k = 0; k < inst.targets.size(); k += 2) {\n            auto a = inst.targets[k];\n            auto b = inst.targets[k + 1];\n            if (a.has_qubit_value()) {\n                auto t = GateTarget::qubit(a.qubit_value());\n                qs1_buf.push_back(t);\n                qs_buf.push_back(t);\n            }\n            if (b.has_qubit_value()) {\n                auto t = GateTarget::qubit(b.qubit_value());\n                qs2_buf.push_back(t);\n                qs_buf.push_back(t);\n            }\n        }\n\n        switch (inst.gate_type) {\n            case GateType::CX:\n                yield({GateType::CX, {}, ts, inst.tag});\n                break;\n            case GateType::XCZ:\n                do_xcz(ts, inst.tag);\n                break;\n            case GateType::XCX:\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                break;\n            case GateType::XCY:\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                break;\n            case GateType::YCX:\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                break;\n            case GateType::YCY:\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                break;\n            case GateType::YCZ:\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                do_xcz(ts, inst.tag);\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                break;\n            case GateType::CY:\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                break;\n            case GateType::CZ:\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                break;\n            case GateType::SQRT_XX:\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::H, {}, qs_buf, inst.tag});\n                break;\n            case GateType::SQRT_XX_DAG:\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::H, {}, qs_buf, inst.tag});\n                break;\n            case GateType::SQRT_YY:\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::H, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                break;\n            case GateType::SQRT_YY_DAG:\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                yield({GateType::S, {}, qs1_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::H, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                break;\n            case GateType::SQRT_ZZ:\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                break;\n            case GateType::SQRT_ZZ_DAG:\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                break;\n            case GateType::SWAP:\n                yield({GateType::CX, {}, ts, inst.tag});\n                do_xcz(ts, inst.tag);\n                yield({GateType::CX, {}, ts, inst.tag});\n                break;\n            case GateType::ISWAP:\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                do_xcz(ts, inst.tag);\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                break;\n            case GateType::ISWAP_DAG:\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                do_xcz(ts, inst.tag);\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                break;\n            case GateType::CXSWAP:\n                do_xcz(ts, inst.tag);\n                yield({GateType::CX, {}, ts, inst.tag});\n                break;\n            case GateType::SWAPCX:\n                yield({GateType::CX, {}, ts, inst.tag});\n                do_xcz(ts, inst.tag);\n                break;\n            case GateType::CZSWAP:\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                do_xcz(ts, inst.tag);\n                yield({GateType::H, {}, qs2_buf, inst.tag});\n                break;\n\n            case GateType::MXX:\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::M, {}, qs1_buf, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                break;\n            case GateType::MYY:\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                yield({GateType::S, {}, qs2_buf, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::M, {}, qs1_buf, inst.tag});\n                yield({GateType::H, {}, qs1_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::S, {}, qs_buf, inst.tag});\n                break;\n            case GateType::MZZ:\n                yield({GateType::CX, {}, ts, inst.tag});\n                yield({GateType::M, {}, qs2_buf, inst.tag});\n                yield({GateType::CX, {}, ts, inst.tag});\n                break;\n\n            default:\n                throw std::invalid_argument(\"Unhandled in Simplifier::simplify_instruction: \" + inst.str());\n        }\n    }\n\n    void simplify_instruction(const CircuitInstruction &inst) {\n        const Gate &g = GATE_DATA[inst.gate_type];\n\n        switch (inst.gate_type) {\n            case GateType::I:\n            case GateType::II:\n                // Dropped.\n                break;\n\n            case GateType::MPP:\n                decompose_mpp_operation(inst, num_qubits, [&](const CircuitInstruction sub) {\n                    simplify_instruction(sub);\n                });\n                break;\n            case GateType::SPP:\n            case GateType::SPP_DAG:\n                decompose_spp_or_spp_dag_operation(inst, num_qubits, false, [&](const CircuitInstruction sub) {\n                    simplify_instruction(sub);\n                });\n                break;\n\n            case GateType::MPAD:\n                // Can't be easily simplified into M.\n                yield(inst);\n                break;\n\n            case GateType::DETECTOR:\n            case GateType::OBSERVABLE_INCLUDE:\n            case GateType::TICK:\n            case GateType::QUBIT_COORDS:\n            case GateType::SHIFT_COORDS:\n                // Annotations can't be simplified.\n                yield(inst);\n                break;\n\n            case GateType::DEPOLARIZE1:\n            case GateType::DEPOLARIZE2:\n            case GateType::X_ERROR:\n            case GateType::Y_ERROR:\n            case GateType::Z_ERROR:\n            case GateType::I_ERROR:\n            case GateType::II_ERROR:\n            case GateType::PAULI_CHANNEL_1:\n            case GateType::PAULI_CHANNEL_2:\n            case GateType::E:\n            case GateType::ELSE_CORRELATED_ERROR:\n            case GateType::HERALDED_ERASE:\n            case GateType::HERALDED_PAULI_CHANNEL_1:\n                // Noise isn't simplified.\n                yield(inst);\n                break;\n\n            default: {\n                if (g.flags & GATE_IS_SINGLE_QUBIT_GATE) {\n                    simplify_potentially_overlapping_1q_instruction(inst);\n                } else if (g.flags & GATE_TARGETS_PAIRS) {\n                    simplify_potentially_overlapping_2q_instruction(inst);\n                } else {\n                    throw std::invalid_argument(\n                        \"Unhandled in simplify_potentially_overlapping_instruction: \" + inst.str());\n                }\n            }\n        }\n    }\n};\n\nCircuit stim::simplified_circuit(const Circuit &circuit) {\n    Circuit output;\n    Simplifier simplifier(circuit.count_qubits(), [&](const CircuitInstruction &inst) {\n        output.safe_append(inst);\n    });\n    for (auto inst : circuit.operations) {\n        if (inst.gate_type == GateType::REPEAT) {\n            output.append_repeat_block(\n                inst.repeat_block_rep_count(), simplified_circuit(inst.repeat_block_body(circuit)), inst.tag);\n        } else {\n            simplifier.simplify_instruction(inst);\n        }\n    }\n    return output;\n}\n"
  },
  {
    "path": "src/stim/util_top/simplified_circuit.h",
    "content": "#ifndef _STIM_UTIL_TOP_SIMPLIFIED_CIRCUIT_H\n#define _STIM_UTIL_TOP_SIMPLIFIED_CIRCUIT_H\n\n#include \"stim/circuit/circuit.h\"\n\nnamespace stim {\n\nCircuit simplified_circuit(const Circuit &circuit);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/simplified_circuit.test.cc",
    "content": "#include \"stim/util_top/simplified_circuit.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/cmd/command_help.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nstatic std::pair<std::vector<PauliString<64>>, std::vector<PauliString<64>>> circuit_output_eq_val(\n    const Circuit &circuit) {\n    // CAUTION: this is not 100% reliable when measurement count is larger than 1.\n    TableauSimulator<64> sim1(INDEPENDENT_TEST_RNG(), circuit.count_qubits(), -1);\n    TableauSimulator<64> sim2(INDEPENDENT_TEST_RNG(), circuit.count_qubits(), +1);\n    sim1.safe_do_circuit(circuit);\n    sim2.safe_do_circuit(circuit);\n    return {sim1.canonical_stabilizers(), sim2.canonical_stabilizers()};\n}\n\nbool is_simplification_correct(const Gate &gate) {\n    std::vector<double> args;\n    while (args.size() < gate.arg_count && gate.arg_count != ARG_COUNT_SYGIL_ANY &&\n           gate.arg_count != ARG_COUNT_SYGIL_ZERO_OR_ONE) {\n        args.push_back(args.empty() ? 1 : 0);\n    }\n\n    Circuit original;\n    original.safe_append(CircuitInstruction(gate.id, args, gate_decomposition_help_targets_for_gate_type(gate.id), \"\"));\n    Circuit simplified = simplified_circuit(original);\n\n    if (gate.h_s_cx_m_r_decomposition == nullptr) {\n        return simplified == original;\n    }\n\n    uint32_t n = original.count_qubits();\n\n    Circuit epr;\n    for (uint32_t q = 0; q < n; q++) {\n        epr.safe_append_u(\"H\", {q});\n    }\n    for (uint32_t q = 0; q < n; q++) {\n        epr.safe_append_u(\"CNOT\", {q, q + n});\n    }\n\n    Circuit circuit1 = epr + original;\n    Circuit circuit2 = epr + simplified;\n\n    // Reset gates make the ancillary qubits irrelevant because the final value is unrelated to the initial value.\n    // So, for reset gates, discard the ancillary qubits.\n    // CAUTION: this could give false positives if \"partial reset\" gates are added in the future.\n    //          (E.g. a two qubit gate that resets only one of the qubits.)\n    if ((gate.flags & GATE_IS_RESET) && !(gate.flags & GATE_PRODUCES_RESULTS)) {\n        for (uint32_t q = 0; q < n; q++) {\n            circuit1.safe_append_u(\"R\", {q + n});\n            circuit2.safe_append_u(\"R\", {q + n});\n        }\n    }\n\n    // Verify decomposed all the way to base gate set, if the gate has a decomposition.\n    for (const auto &op : circuit2.operations) {\n        if (op.gate_type != GateType::CX && op.gate_type != GateType::H && op.gate_type != GateType::S &&\n            op.gate_type != GateType::M && op.gate_type != GateType::R) {\n            return false;\n        }\n    }\n\n    auto v1 = circuit_output_eq_val(circuit1);\n    auto v2 = circuit_output_eq_val(circuit2);\n    return v1 == v2;\n}\n\nTEST(gate_decomposition, simplifications_are_correct) {\n    for (const auto &g : GATE_DATA.items) {\n        if (g.id != GateType::NOT_A_GATE && g.id != GateType::REPEAT) {\n            EXPECT_TRUE(is_simplification_correct(g)) << g.name;\n        }\n    }\n}\n"
  },
  {
    "path": "src/stim/util_top/stabilizers_to_tableau.h",
    "content": "#ifndef _STIM_STABILIZERS_CONVERSIONS_H\n#define _STIM_STABILIZERS_CONVERSIONS_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/dem/dem_instruction.h\"\n#include \"stim/stabilizers/flex_pauli_string.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\n/// Computes destabilizers for the given stabilizers, and packages into a tableau.\n///\n/// Args:\n///     stabilizers: The desired stabilizers for the tableau. Every stabilizer must have the same number of qubits.\n///     allow_redundant: If false, including a redundant stabilizer will result in an error.\n///         If true, redundant stabilizers are quietly dropped.\n///     allow_underconstrained: If false, the number of independent stabilizers must equal the number of qubits in each\n///         stabilizer. If true, the returned result will arbitrarily fill in missing stabilizers.\n///     invert: Return the inverse tableau instead of the tableau with the stabilizers as its Z outputs.\n///\n/// Returns:\n///     A tableau containing the given stabilizers, but extended to also include matching stabilizers.\n///     The Z outputs of the tableau will be the given stabilizers (skipping any redundant ones).\ntemplate <size_t W>\nTableau<W> stabilizers_to_tableau(\n    const std::vector<stim::PauliString<W>> &stabilizers,\n    bool allow_redundant,\n    bool allow_underconstrained,\n    bool invert);\n\n}  // namespace stim\n\n#include \"stim/util_top/stabilizers_to_tableau.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/stabilizers_to_tableau.inl",
    "content": "#include \"stim/util_top/circuit_vs_tableau.h\"\n#include \"stim/util_top/stabilizers_to_tableau.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nTableau<W> stabilizers_to_tableau(\n    const std::vector<PauliString<W>> &stabilizers, bool allow_redundant, bool allow_underconstrained, bool invert) {\n    size_t num_qubits = 0;\n    for (const auto &e : stabilizers) {\n        num_qubits = std::max(num_qubits, e.num_qubits);\n    }\n\n    simd_bit_table<W> buf_xs(stabilizers.size(), num_qubits);\n    simd_bit_table<W> buf_zs(stabilizers.size(), num_qubits);\n    simd_bits<W> buf_signs(stabilizers.size());\n    for (size_t k = 0; k < stabilizers.size(); k++) {\n        memcpy(buf_xs[k].u8, stabilizers[k].xs.u8, stabilizers[k].xs.num_u8_padded());\n        memcpy(buf_zs[k].u8, stabilizers[k].zs.u8, stabilizers[k].zs.num_u8_padded());\n        buf_signs[k] = stabilizers[k].sign;\n    }\n    buf_xs = buf_xs.transposed();\n    buf_zs = buf_zs.transposed();\n\n    Circuit elimination_instructions;\n\n    auto fail_due_to_anticommutation = [&]() {\n        for (size_t k1 = 0; k1 < stabilizers.size(); k1++) {\n            for (size_t k2 = k1 + 1; k2 < stabilizers.size(); k2++) {\n                if (!stabilizers[k1].ref().commutes(stabilizers[k2])) {\n                    std::stringstream ss;\n                    ss << \"Some of the given stabilizers anticommute.\\n\";\n                    ss << \"For example:\";\n                    ss << \"\\n    stabilizers[\" << k1 << \"] = \" << stabilizers[k1];\n                    ss << \"\\nanticommutes with\";\n                    ss << \"\\n    stabilizers[\" << k2 << \"] = \" << stabilizers[k2];\n                    throw std::invalid_argument(ss.str());\n                }\n            }\n        }\n        throw std::invalid_argument(\n            \"The given stabilizers commute but the solver failed in a way that suggests they anticommute. Please \"\n            \"report this as a bug.\");\n    };\n\n    auto print_redundant_z_product_parts = [&](size_t stabilizer_index, std::ostream &out) {\n        PauliString<W> target = stabilizers[stabilizer_index];\n        target.ensure_num_qubits(num_qubits, 1.0);\n        target = target.ref().after(elimination_instructions);\n        if (num_qubits > 0) {\n            GateTarget t = GateTarget::qubit(num_qubits - 1);\n            elimination_instructions.safe_append(CircuitInstruction{GateType::X, {}, &t, \"\"});\n            elimination_instructions.safe_append(CircuitInstruction{GateType::X, {}, &t, \"\"});\n        }\n        Tableau<W> inverse = circuit_to_tableau<W>(elimination_instructions, false, false, false, true);\n        target.ref().for_each_active_pauli([&](size_t q) {\n            out << \"\\n    \";\n            for (size_t k = 0; k < stabilizers.size(); k++) {\n                PauliString<W> s = stabilizers[k];\n                s.ensure_num_qubits(num_qubits, 1.0);\n                if (s == inverse.zs[q]) {\n                    out << \"stabilizers[\" << k << \"] = \" << stabilizers[k];\n                    return;\n                }\n            }\n            out << inverse.zs[q];\n        });\n    };\n\n    size_t used = 0;\n    for (size_t k = 0; k < stabilizers.size(); k++) {\n        // Find a non-identity term in the Pauli string past the region used by other stabilizers.\n        size_t pivot;\n        for (size_t q = 0; q < used; q++) {\n            if (buf_xs[q][k]) {\n                fail_due_to_anticommutation();\n            }\n        }\n        for (pivot = used; pivot < num_qubits; pivot++) {\n            if (buf_xs[pivot][k] || buf_zs[pivot][k]) {\n                break;\n            }\n        }\n\n        // Check for incompatible / redundant stabilizers.\n        if (pivot == num_qubits) {\n            if (buf_signs[k]) {\n                std::stringstream ss;\n                ss << \"Some of the given stabilizers contradict each other.\\n\";\n                ss << \"For example:\";\n                ss << \"\\n    stabilizers[\" << k << \"] = \" << stabilizers[k];\n                ss << \"\\nis the negation of the product of the following stabilizers: {\";\n                print_redundant_z_product_parts(k, ss);\n                ss << \"\\n}\";\n                throw std::invalid_argument(ss.str());\n            }\n            if (!allow_redundant) {\n                std::stringstream ss;\n                ss << \"Some of the given stabilizers are redundant.\";\n                ss << \"\\nTo allow redundant stabilizers, pass the argument allow_redundant=True.\";\n                ss << \"\\n\";\n                ss << \"\\nFor example:\";\n                ss << \"\\n    stabilizers[\" << k << \"] = \" << stabilizers[k];\n                ss << \"\\nis the product of the following stabilizers: {\";\n                print_redundant_z_product_parts(k, ss);\n                ss << \"\\n}\";\n                throw std::invalid_argument(ss.str());\n            }\n            continue;\n        }\n\n        // Change pivot basis to the Z axis.\n        if (buf_xs[pivot][k]) {\n            GateType g = buf_zs[pivot][k] ? GateType::H_YZ : GateType::H;\n            GateTarget t = GateTarget::qubit(pivot);\n            CircuitInstruction instruction{g, {}, &t, \"\"};\n            elimination_instructions.safe_append(instruction);\n            size_t q = pivot;\n            simd_bits_range_ref<W> xs1 = buf_xs[q];\n            simd_bits_range_ref<W> zs1 = buf_zs[q];\n            simd_bits_range_ref<W> ss = buf_signs;\n            switch (g) {\n                case GateType::H_YZ:\n                    ss.for_each_word(xs1, zs1, [](auto &s, auto &x, auto &z) {\n                        x ^= z;\n                        s ^= z.andnot(x);\n                    });\n                    break;\n                case GateType::H:\n                    ss.for_each_word(xs1, zs1, [](auto &s, auto &x, auto &z) {\n                        std::swap(x, z);\n                        s ^= x & z;\n                    });\n                    break;\n                default:\n                    throw std::invalid_argument(\"Unrecognized gate type.\");\n            }\n        }\n\n        // Cancel other terms in Pauli string.\n        for (size_t q = 0; q < num_qubits; q++) {\n            int p = buf_xs[q][k] + buf_zs[q][k] * 2;\n            if (p && q != pivot) {\n                std::array<GateTarget, 2> targets{GateTarget::qubit(pivot), GateTarget::qubit(q)};\n                GateType g = p == 1 ? GateType::XCX : p == 2 ? GateType::XCZ : GateType::XCY;\n                CircuitInstruction instruction{g, {}, targets, \"\"};\n                elimination_instructions.safe_append(instruction);\n                size_t q1 = targets[0].qubit_value();\n                size_t q2 = targets[1].qubit_value();\n                simd_bits_range_ref<W> ss = buf_signs;\n                simd_bits_range_ref<W> xs1 = buf_xs[q1];\n                simd_bits_range_ref<W> zs1 = buf_zs[q1];\n                simd_bits_range_ref<W> xs2 = buf_xs[q2];\n                simd_bits_range_ref<W> zs2 = buf_zs[q2];\n                switch (g) {\n                    case GateType::XCX:\n                        ss.for_each_word(xs1, zs1, xs2, zs2, [](auto &s, auto &x1, auto &z1, auto &x2, auto &z2) {\n                            s ^= (x1 ^ x2) & z1 & z2;\n                            x1 ^= z2;\n                            x2 ^= z1;\n                        });\n                        break;\n                    case GateType::XCY:\n                        ss.for_each_word(xs1, zs1, xs2, zs2, [](auto &s, auto &x1, auto &z1, auto &x2, auto &z2) {\n                            x1 ^= x2 ^ z2;\n                            x2 ^= z1;\n                            z2 ^= z1;\n                            s ^= x1.andnot(z1) & x2.andnot(z2);\n                            s ^= x1 & z1 & z2.andnot(x2);\n                        });\n                        break;\n                    case GateType::XCZ:\n                        ss.for_each_word(xs1, zs1, xs2, zs2, [](auto &s, auto &x1, auto &z1, auto &x2, auto &z2) {\n                            z2 ^= z1;\n                            x1 ^= x2;\n                            s ^= (z2 ^ x1).andnot(z1 & x2);\n                        });\n                        break;\n                    default:\n                        throw std::invalid_argument(\"Unrecognized gate type.\");\n                }\n            }\n        }\n\n        // Move pivot to diagonal.\n        if (pivot != used) {\n            std::array<GateTarget, 2> targets{GateTarget::qubit(pivot), GateTarget::qubit(used)};\n            CircuitInstruction instruction{GateType::SWAP, {}, targets, \"\"};\n            elimination_instructions.safe_append(instruction);\n            buf_xs[pivot].swap_with(buf_xs[used]);\n            buf_zs[pivot].swap_with(buf_zs[used]);\n        }\n\n        // Fix sign.\n        if (buf_signs[k]) {\n            GateTarget t = GateTarget::qubit(used);\n            CircuitInstruction instruction{GateType::X, {}, &t, \"\"};\n            elimination_instructions.safe_append(instruction);\n            buf_signs ^= buf_zs[used];\n        }\n\n        used++;\n    }\n\n    if (used < num_qubits) {\n        if (!allow_underconstrained) {\n            throw std::invalid_argument(\n                \"There weren't enough stabilizers to uniquely specify the state. \"\n                \"To allow underspecifying the state, pass the argument allow_underconstrained=True.\");\n        }\n    }\n\n    if (num_qubits > 0) {\n        // Force size of resulting tableau to be correct.\n        GateTarget t = GateTarget::qubit(num_qubits - 1);\n        elimination_instructions.safe_append(CircuitInstruction{GateType::X, {}, &t, \"\"});\n        elimination_instructions.safe_append(CircuitInstruction{GateType::X, {}, &t, \"\"});\n    }\n\n    if (invert) {\n        return circuit_to_tableau<W>(elimination_instructions.inverse(), false, false, false, true);\n    }\n    return circuit_to_tableau<W>(elimination_instructions, false, false, false, true);\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/util_top/stabilizers_to_tableau.perf.cc",
    "content": "#include \"stim/util_top/stabilizers_to_tableau.h\"\n\n#include \"stim/perf.perf.h\"\n\nusing namespace stim;\n\nBENCHMARK(stabilizers_to_tableau_144) {\n    std::vector<std::complex<float>> offsets{\n        {1, 0},\n        {-1, 0},\n        {0, 1},\n        {0, -1},\n        {3, 6},\n        {-6, 3},\n    };\n    size_t w = 24;\n    size_t h = 12;\n\n    auto normalize = [&](std::complex<float> c) -> std::complex<float> {\n        return {fmodf(c.real() + w * 10, w), fmodf(c.imag() + h * 10, h)};\n    };\n    auto q2i = [&](std::complex<float> c) -> size_t {\n        c = normalize(c);\n        return (int)c.real() / 2 + c.imag() * (w / 2);\n    };\n\n    std::vector<stim::PauliString<64>> stabilizers;\n    for (size_t x = 0; x < w; x++) {\n        for (size_t y = x % 2; y < h; y += 2) {\n            std::complex<float> s{x % 2 ? -1.0f : +1.0f, 0.0f};\n            std::complex<float> c{(float)x, (float)y};\n            stim::PauliString<64> ps(w * h / 2);\n            for (const auto &offset : offsets) {\n                size_t i = q2i(c + offset * s);\n                if (x % 2 == 0) {\n                    ps.xs[i] = 1;\n                } else {\n                    ps.zs[i] = 1;\n                }\n            }\n            stabilizers.push_back(ps);\n        }\n    }\n\n    size_t dep = 0;\n    benchmark_go([&]() {\n        Tableau<64> t = stabilizers_to_tableau(stabilizers, true, true, false);\n        dep += t.xs[0].zs[0];\n    }).goal_micros(500);\n    if (dep == 99999999) {\n        std::cout << \"data dependence\";\n    }\n}\n\nBENCHMARK(stabilizers_to_tableau_576) {\n    std::vector<std::complex<float>> offsets{\n        {1, 0},\n        {-1, 0},\n        {0, 1},\n        {0, -1},\n        {3, 6},\n        {-6, 3},\n    };\n    size_t w = 24 * 4;\n    size_t h = 12 * 4;\n\n    auto normalize = [&](std::complex<float> c) -> std::complex<float> {\n        return {fmodf(c.real() + w * 10, w), fmodf(c.imag() + h * 10, h)};\n    };\n    auto q2i = [&](std::complex<float> c) -> size_t {\n        c = normalize(c);\n        return (int)c.real() / 2 + c.imag() * (w / 2);\n    };\n\n    std::vector<stim::PauliString<64>> stabilizers;\n    for (size_t x = 0; x < w; x++) {\n        for (size_t y = x % 2; y < h; y += 2) {\n            std::complex<float> s{x % 2 ? -1.0f : +1.0f, 0.0f};\n            std::complex<float> c{(float)x, (float)y};\n            stim::PauliString<64> ps(w * h / 2);\n            for (const auto &offset : offsets) {\n                size_t i = q2i(c + offset * s);\n                if (x % 2 == 0) {\n                    ps.xs[i] = 1;\n                } else {\n                    ps.zs[i] = 1;\n                }\n            }\n            stabilizers.push_back(ps);\n        }\n    }\n\n    size_t dep = 0;\n    benchmark_go([&]() {\n        Tableau<64> t = stabilizers_to_tableau(stabilizers, true, true, false);\n        dep += t.xs[0].zs[0];\n    }).goal_millis(200);\n    if (dep == 99999999) {\n        std::cout << \"data dependence\";\n    }\n}\n"
  },
  {
    "path": "src/stim/util_top/stabilizers_to_tableau.test.cc",
    "content": "#include \"stim/util_top/stabilizers_to_tableau.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(conversions, stabilizers_to_tableau_fuzz, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (size_t n = 0; n < 10; n++) {\n        auto t = Tableau<W>::random(n, rng);\n        std::vector<PauliString<W>> expected_stabilizers;\n        for (size_t k = 0; k < n; k++) {\n            expected_stabilizers.push_back(t.zs[k]);\n        }\n        auto actual = stabilizers_to_tableau<W>(expected_stabilizers, false, false, false);\n        for (size_t k = 0; k < n; k++) {\n            ASSERT_EQ(actual.zs[k], expected_stabilizers[k]);\n        }\n\n        ASSERT_TRUE(actual.satisfies_invariants());\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, stabilizers_to_tableau_partial_fuzz, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (size_t n = 0; n < 10; n++) {\n        for (size_t skipped = 1; skipped < n && skipped < 4; skipped++) {\n            auto t = Tableau<W>::random(n, rng);\n            std::vector<PauliString<W>> expected_stabilizers;\n            for (size_t k = 0; k < n - skipped; k++) {\n                expected_stabilizers.push_back(t.zs[k]);\n            }\n            ASSERT_THROW(\n                { stabilizers_to_tableau<W>(expected_stabilizers, false, false, false); }, std::invalid_argument);\n            auto actual = stabilizers_to_tableau<W>(expected_stabilizers, false, true, false);\n            for (size_t k = 0; k < n - skipped; k++) {\n                ASSERT_EQ(actual.zs[k], expected_stabilizers[k]);\n            }\n\n            ASSERT_TRUE(actual.satisfies_invariants());\n\n            auto inverted = stabilizers_to_tableau<W>(expected_stabilizers, false, true, true);\n            ASSERT_EQ(actual.inverse(), inverted);\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, stabilizers_to_tableau_overconstrained, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (size_t n = 4; n < 10; n++) {\n        auto t = Tableau<W>::random(n, rng);\n        std::vector<PauliString<W>> expected_stabilizers;\n        expected_stabilizers.push_back(PauliString<W>(n));\n        expected_stabilizers.push_back(PauliString<W>(n));\n        uint8_t s = 0;\n        s += expected_stabilizers.back().ref().inplace_right_mul_returning_log_i_scalar(t.zs[1]);\n        s += expected_stabilizers.back().ref().inplace_right_mul_returning_log_i_scalar(t.zs[3]);\n        if (s & 2) {\n            expected_stabilizers.back().sign ^= true;\n        }\n        for (size_t k = 0; k < n; k++) {\n            expected_stabilizers.push_back(t.zs[k]);\n        }\n        ASSERT_THROW({ stabilizers_to_tableau<W>(expected_stabilizers, false, false, false); }, std::invalid_argument);\n        auto actual = stabilizers_to_tableau<W>(expected_stabilizers, true, false, false);\n        for (size_t k = 0; k < n; k++) {\n            ASSERT_EQ(actual.zs[k], expected_stabilizers[k + 1 + (k > 3)]);\n        }\n\n        ASSERT_TRUE(actual.satisfies_invariants());\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, stabilizers_to_tableau_bell_pair, {\n    std::vector<stim::PauliString<W>> input_stabilizers;\n    input_stabilizers.push_back(PauliString<W>::from_str(\"XX\"));\n    input_stabilizers.push_back(PauliString<W>::from_str(\"ZZ\"));\n    auto actual = stabilizers_to_tableau<W>(input_stabilizers, false, false, false);\n    Tableau<W> expected(2);\n    expected.zs[0] = PauliString<W>::from_str(\"XX\");\n    expected.zs[1] = PauliString<W>::from_str(\"ZZ\");\n    expected.xs[0] = PauliString<W>::from_str(\"Z_\");\n    expected.xs[1] = PauliString<W>::from_str(\"_X\");\n    ASSERT_EQ(actual, expected);\n\n    input_stabilizers.push_back(PauliString<W>::from_str(\"-YY\"));\n    ASSERT_THROW({ stabilizers_to_tableau<W>(input_stabilizers, false, false, false); }, std::invalid_argument);\n    actual = stabilizers_to_tableau<W>(input_stabilizers, true, false, false);\n    ASSERT_EQ(actual, expected);\n\n    input_stabilizers[2] = PauliString<W>::from_str(\"+YY\");\n    // Sign is wrong!\n    ASSERT_THROW({ stabilizers_to_tableau<W>(input_stabilizers, true, true, false); }, std::invalid_argument);\n\n    input_stabilizers[2] = PauliString<W>::from_str(\"+Z_\");\n    // Anticommutes!\n    ASSERT_THROW({ stabilizers_to_tableau<W>(input_stabilizers, true, true, false); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, stabilizer_to_tableau_detect_anticommutation, {\n    std::vector<stim::PauliString<W>> input_stabilizers;\n    input_stabilizers.push_back(PauliString<W>::from_str(\"YY\"));\n    input_stabilizers.push_back(PauliString<W>::from_str(\"YX\"));\n    ASSERT_THROW({ stabilizers_to_tableau<W>(input_stabilizers, false, false, false); }, std::invalid_argument);\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, stabilizer_to_tableau_size_affecting_redundancy, {\n    std::vector<stim::PauliString<W>> input_stabilizers;\n    input_stabilizers.push_back(PauliString<W>::from_str(\"X_\"));\n    input_stabilizers.push_back(PauliString<W>::from_str(\"_X\"));\n    for (size_t k = 0; k < 150; k++) {\n        input_stabilizers.push_back(PauliString<W>::from_str(\"__\"));\n    }\n    auto t = stabilizers_to_tableau<W>(input_stabilizers, true, true, false);\n    ASSERT_EQ(t.num_qubits, 2);\n    ASSERT_EQ(t.zs[0], PauliString<W>::from_str(\"X_\"));\n    ASSERT_EQ(t.zs[1], PauliString<W>::from_str(\"_X\"));\n})\n"
  },
  {
    "path": "src/stim/util_top/stabilizers_vs_amplitudes.h",
    "content": "#ifndef _STIM_UTIL_TOP_STABILIZERS_VS_AMPLITUDES_H\n#define _STIM_UTIL_TOP_STABILIZERS_VS_AMPLITUDES_H\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/stabilizers/tableau.h\"\n\nnamespace stim {\n\n/// Converts a tableau into a unitary matrix.\ntemplate <size_t W>\nstd::vector<std::vector<std::complex<float>>> tableau_to_unitary(const Tableau<W> &tableau, bool little_endian);\n\n/// Converts a unitary matrix into a stabilizer tableau.\n///\n/// Args:\n///     matrix: The unitary matrix to convert. Must correspond to a Clifford.\n//      little_endian: Whether the amplitude ordering is little endian or big endian.\n///\n/// Returns:\n///     A tableau implementing the same operation as the unitary matrix (up to global phase).\n///\n/// Throws:\n///     std::invalid_argument: The given unitary matrix isn't a Clifford operation.\ntemplate <size_t W>\nTableau<W> unitary_to_tableau(const std::vector<std::vector<std::complex<float>>> &matrix, bool little_endian);\n\n}  // namespace stim\n\n#include \"stim/util_top/stabilizers_vs_amplitudes.inl\"\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/stabilizers_vs_amplitudes.inl",
    "content": "#include \"stim/util_bot/twiddle.h\"\n#include \"stim/util_top/circuit_inverse_unitary.h\"\n#include \"stim/util_top/circuit_vs_amplitudes.h\"\n#include \"stim/util_top/circuit_vs_tableau.h\"\n\nnamespace stim {\n\ntemplate <size_t W>\nstd::vector<std::vector<std::complex<float>>> tableau_to_unitary(const Tableau<W> &tableau, bool little_endian) {\n    auto flat = tableau.to_flat_unitary_matrix(little_endian);\n    std::vector<std::vector<std::complex<float>>> result;\n    size_t n = 1 << tableau.num_qubits;\n    for (size_t row = 0; row < n; row++) {\n        result.push_back({});\n        auto &back = result.back();\n        std::complex<float> *start = &flat[row * n];\n        back.insert(back.end(), start, start + n);\n    }\n    return result;\n}\n\ntemplate <size_t W>\nTableau<W> unitary_to_tableau(const std::vector<std::vector<std::complex<float>>> &matrix, bool little_endian) {\n    // Verify matrix is square.\n    size_t num_amplitudes = matrix.size();\n    if (!is_power_of_2(num_amplitudes)) {\n        throw std::invalid_argument(\n            \"Matrix width and height must be a power of 2. Height was \" + std::to_string(num_amplitudes));\n    }\n    for (size_t r = 0; r < num_amplitudes; r++) {\n        if (matrix[r].size() != num_amplitudes) {\n            std::stringstream ss;\n            ss << \"Matrix must be square, but row \" << r;\n            ss << \" had width \" << matrix[r].size();\n            ss << \" while matrix had height \" << num_amplitudes;\n            throw std::invalid_argument(ss.str());\n        }\n    }\n\n    // Use first column to solve how to get out of superposition and to a phased permutation.\n    std::vector<std::complex<float>> first_col;\n    for (const auto &row : matrix) {\n        first_col.push_back(row[0]);\n    }\n    Circuit recorded_circuit = stabilizer_state_vector_to_circuit(first_col, true);\n    recorded_circuit = circuit_inverse_unitary(recorded_circuit);\n\n    // Use the state channel duality to get the operation into the vector simulator.\n    VectorSimulator sim(0);\n    float m2v = sqrtf(num_amplitudes);\n    sim.state.clear();\n    sim.state.reserve(num_amplitudes * num_amplitudes);\n    for (size_t r = 0; r < num_amplitudes; r++) {\n        for (size_t c = 0; c < num_amplitudes; c++) {\n            sim.state.push_back(matrix[c][r] / m2v);\n        }\n    }\n    // Convert to a phased permutation (assuming the matrix was Clifford).\n    sim.do_unitary_circuit(recorded_circuit);\n    sim.smooth_stabilizer_state(sim.state[0]);\n\n    auto apply = [&](GateType gate_type, uint32_t target) {\n        sim.apply(gate_type, target);\n        recorded_circuit.safe_append(\n            CircuitInstruction(gate_type, {}, std::vector<GateTarget>{GateTarget::qubit(target)}, \"\"));\n    };\n    auto apply2 = [&](GateType gate_type, uint32_t target, uint32_t target2) {\n        sim.apply(gate_type, target, target2);\n        recorded_circuit.safe_append(CircuitInstruction(\n            gate_type, {}, std::vector<GateTarget>{GateTarget::qubit(target), GateTarget::qubit(target2)}, \"\"));\n    };\n\n    // Undo the permutation and also single-qubit phases.\n    size_t num_qubits = floor_lg2(num_amplitudes);\n    for (size_t q = 0; q < num_qubits; q++) {\n        size_t c = 1 << q;\n\n        // Find the single entry in the column and move it to the diagonal.\n        for (size_t r = 0; r < num_amplitudes; r++) {\n            auto ratio = sim.state[c * num_amplitudes + r];\n            if (ratio != std::complex<float>{0, 0}) {\n                // Move to diagonal.\n                if (r != c) {\n                    size_t pivot = first_set_bit(r, q);\n                    for (size_t b = 0; b < num_qubits; b++) {\n                        if (((r >> b) & 1) != 0 && b != pivot) {\n                            apply2(GateType::CX, pivot, b);\n                        }\n                    }\n                    if (pivot != q) {\n                        apply2(GateType::SWAP, q, pivot);\n                    }\n                }\n\n                // Undo phasing on this qubit.\n                if (ratio.real() == -1) {\n                    apply(GateType::Z, q);\n                } else if (ratio.imag() == -1) {\n                    apply(GateType::S, q);\n                } else if (ratio.imag() == +1) {\n                    apply(GateType::S_DAG, q);\n                }\n                break;\n            }\n        }\n    }\n\n    // Undo double qubit phases.\n    for (size_t q1 = 0; q1 < num_qubits; q1++) {\n        for (size_t q2 = q1 + 1; q2 < num_qubits; q2++) {\n            size_t v = (1 << q1) | (1 << q2);\n            size_t d = v * num_amplitudes + v;\n            if (sim.state[d].real() == -1) {\n                apply2(GateType::CZ, q1, q2);\n            }\n        }\n    }\n\n    // Verify that we actually reduced the matrix to the identity.\n    // If we failed, it wasn't actually a Clifford.\n    for (size_t r = 0; r < num_amplitudes; r++) {\n        for (size_t c = 0; c < num_amplitudes; c++) {\n            if (sim.state[r * num_amplitudes + c] != std::complex<float>{r == c ? 1.0f : 0.0f}) {\n                throw std::invalid_argument(\"The given unitary matrix wasn't a Clifford operation.\");\n            }\n        }\n    }\n\n    // Conjugate by swaps to handle endianness.\n    if (!little_endian) {\n        for (size_t q = 0; 2 * q + 1 < num_qubits; q++) {\n            recorded_circuit.safe_append_u(\"SWAP\", {(uint32_t)q, (uint32_t)(num_qubits - q - 1)});\n        }\n    }\n    recorded_circuit = circuit_inverse_unitary(recorded_circuit);\n    if (!little_endian) {\n        for (size_t q = 0; 2 * q + 1 < num_qubits; q++) {\n            recorded_circuit.safe_append_u(\"SWAP\", {(uint32_t)q, (uint32_t)(num_qubits - q - 1)});\n        }\n    }\n\n    return circuit_to_tableau<W>(recorded_circuit, false, false, false);\n}\n\n}  // namespace stim\n"
  },
  {
    "path": "src/stim/util_top/stabilizers_vs_amplitudes.test.cc",
    "content": "#include \"stim/util_top/stabilizers_vs_amplitudes.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/mem/simd_word.test.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/util_bot/test_util.test.h\"\n\nusing namespace stim;\n\nTEST_EACH_WORD_SIZE_W(conversions, unitary_to_tableau_vs_gate_data, {\n    for (const auto &gate : GATE_DATA.items) {\n        if (gate.has_known_unitary_matrix()) {\n            EXPECT_EQ(unitary_to_tableau<W>(gate.unitary(), true), gate.tableau<W>()) << gate.name;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, tableau_to_unitary_vs_gate_data, {\n    VectorSimulator v1(2);\n    VectorSimulator v2(2);\n    for (const auto &gate : GATE_DATA.items) {\n        if (gate.has_known_unitary_matrix()) {\n            auto actual = tableau_to_unitary<W>(gate.tableau<W>(), true);\n            auto expected = gate.unitary();\n            v1.state.clear();\n            for (const auto &row : actual) {\n                v1.state.insert(v1.state.end(), row.begin(), row.end());\n            }\n            v2.state.clear();\n            for (const auto &row : expected) {\n                v2.state.insert(v2.state.end(), row.begin(), row.end());\n            }\n            for (auto &v : v1.state) {\n                v /= sqrtf(actual.size());\n            }\n            for (auto &v : v2.state) {\n                v /= sqrtf(actual.size());\n            }\n            ASSERT_TRUE(v1.approximate_equals(v2, true)) << gate.name;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, unitary_vs_tableau_basic, {\n    ASSERT_EQ(unitary_to_tableau<W>(GATE_DATA.at(\"XCZ\").unitary(), false), GATE_DATA.at(\"ZCX\").tableau<W>());\n    ASSERT_EQ(unitary_to_tableau<W>(GATE_DATA.at(\"XCZ\").unitary(), true), GATE_DATA.at(\"XCZ\").tableau<W>());\n    ASSERT_EQ(unitary_to_tableau<W>(GATE_DATA.at(\"ZCX\").unitary(), false), GATE_DATA.at(\"XCZ\").tableau<W>());\n    ASSERT_EQ(unitary_to_tableau<W>(GATE_DATA.at(\"ZCX\").unitary(), true), GATE_DATA.at(\"ZCX\").tableau<W>());\n\n    ASSERT_EQ(unitary_to_tableau<W>(GATE_DATA.at(\"XCY\").unitary(), false), GATE_DATA.at(\"YCX\").tableau<W>());\n    ASSERT_EQ(unitary_to_tableau<W>(GATE_DATA.at(\"XCY\").unitary(), true), GATE_DATA.at(\"XCY\").tableau<W>());\n    ASSERT_EQ(unitary_to_tableau<W>(GATE_DATA.at(\"YCX\").unitary(), false), GATE_DATA.at(\"XCY\").tableau<W>());\n    ASSERT_EQ(unitary_to_tableau<W>(GATE_DATA.at(\"YCX\").unitary(), true), GATE_DATA.at(\"YCX\").tableau<W>());\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, unitary_to_tableau_fuzz_vs_tableau_to_unitary, {\n    auto rng = INDEPENDENT_TEST_RNG();\n    for (bool little_endian : std::vector<bool>{false, true}) {\n        for (size_t n = 0; n < 6; n++) {\n            auto desired = Tableau<W>::random(n, rng);\n            auto unitary = tableau_to_unitary<W>(desired, little_endian);\n            auto actual = unitary_to_tableau<W>(unitary, little_endian);\n            ASSERT_EQ(actual, desired) << \"little_endian=\" << little_endian << \", n=\" << n;\n        }\n    }\n})\n\nTEST_EACH_WORD_SIZE_W(conversions, unitary_to_tableau_fail, {\n    ASSERT_THROW(\n        { unitary_to_tableau<W>({{{1}, {0}}, {{0}, {sqrtf(0.5), sqrtf(0.5)}}}, false); }, std::invalid_argument);\n    ASSERT_THROW(\n        {\n            unitary_to_tableau<W>(\n                {\n                    {1, 0, 0, 0},\n                    {0, 1, 0, 0},\n                    {0, 0, 1, 0},\n                    {0, 0, 0, {0, 1}},\n                },\n                false);\n        },\n        std::invalid_argument);\n    ASSERT_THROW(\n        {\n            unitary_to_tableau<W>(\n                {\n                    {1, 0, 0, 0, 0, 0, 0, 0},\n                    {0, 1, 0, 0, 0, 0, 0, 0},\n                    {0, 0, 1, 0, 0, 0, 0, 0},\n                    {0, 0, 0, 1, 0, 0, 0, 0},\n                    {0, 0, 0, 0, 1, 0, 0, 0},\n                    {0, 0, 0, 0, 0, 1, 0, 0},\n                    {0, 0, 0, 0, 0, 0, 0, 1},\n                    {0, 0, 0, 0, 0, 0, 1, 0},\n                },\n                false);\n        },\n        std::invalid_argument);\n})\n"
  },
  {
    "path": "src/stim/util_top/transform_without_feedback.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_top/transform_without_feedback.h\"\n\n#include <algorithm>\n#include <queue>\n#include <sstream>\n\n#include \"stim/circuit/gate_decomposition.h\"\n#include \"stim/simulators/sparse_rev_frame_tracker.h\"\n\nusing namespace stim;\n\nstruct WithoutFeedbackHelper {\n    Circuit reversed_semi_flattened_output;\n\n    SparseUnsignedRevFrameTracker tracker;\n    SparseXorVec<DemTarget> tmp_sensitivity_buf;\n    std::map<uint64_t, SparseXorVec<GateTarget>> obs_changes;\n    std::map<uint64_t, SparseXorVec<uint64_t>> det_changes;\n\n    WithoutFeedbackHelper(const Circuit &circuit)\n        : tracker(circuit.count_qubits(), circuit.count_measurements(), circuit.count_detectors()) {\n    }\n\n    const SparseXorVec<DemTarget> &anticommuting_sensitivity_at(uint32_t qubit, bool x, bool z) {\n        if (x > z) {\n            return tracker.zs[qubit];\n        } else if (z > x) {\n            return tracker.xs[qubit];\n        } else {\n            tmp_sensitivity_buf.clear();\n            tmp_sensitivity_buf ^= tracker.xs[qubit];\n            tmp_sensitivity_buf ^= tracker.zs[qubit];\n            return tmp_sensitivity_buf;\n        }\n    }\n\n    void do_single_feedback(GateTarget rec, uint32_t qubit, bool x, bool z) {\n        const SparseXorVec<DemTarget> &sensitivity = anticommuting_sensitivity_at(qubit, x, z);\n        for (const auto &d : sensitivity) {\n            if (d.is_observable_id()) {\n                obs_changes[d.raw_id()].xor_item(rec);\n            } else {\n                det_changes[d.raw_id()].xor_item(tracker.num_measurements_in_past + rec.rec_offset());\n            }\n        }\n    }\n\n    void undo_feedback_capable_pcp_operation(const CircuitInstruction &op) {\n        for (size_t k = op.targets.size(); k > 0;) {\n            k -= 2;\n            CircuitInstruction op_piece = {op.gate_type, op.args, {&op.targets[k], &op.targets[k + 2]}, op.tag};\n            auto t1 = op.targets[k];\n            auto t2 = op.targets[k + 1];\n            auto b1 = t1.is_measurement_record_target();\n            auto b2 = t2.is_measurement_record_target();\n            if (b1 > b2) {\n                if (op.gate_type == GateType::CX) {\n                    do_single_feedback(t1, t2.qubit_value(), true, false);\n                } else if (op.gate_type == GateType::CY) {\n                    do_single_feedback(t1, t2.qubit_value(), true, true);\n                } else if (op.gate_type == GateType::CZ) {\n                    do_single_feedback(t1, t2.qubit_value(), false, true);\n                } else {\n                    throw std::invalid_argument(\"Unknown feedback gate.\");\n                }\n            } else if (b2 > b1) {\n                if (op.gate_type == GateType::CX) {\n                    do_single_feedback(t2, t1.qubit_value(), true, false);\n                } else if (op.gate_type == GateType::CY) {\n                    do_single_feedback(t2, t1.qubit_value(), true, true);\n                } else if (op.gate_type == GateType::CZ) {\n                    do_single_feedback(t2, t1.qubit_value(), false, true);\n                } else {\n                    throw std::invalid_argument(\"Unknown feedback gate.\");\n                }\n            } else if (!b1 && !b2) {\n                reversed_semi_flattened_output.operations.push_back(\n                    CircuitInstruction{\n                        op_piece.gate_type,\n                        reversed_semi_flattened_output.arg_buf.take_copy(op_piece.args),\n                        reversed_semi_flattened_output.target_buf.take_copy(op_piece.targets),\n                        op_piece.tag,\n                    });\n            }\n            tracker.undo_gate(op_piece);\n        }\n\n        for (const auto &e : obs_changes) {\n            if (!e.second.empty()) {\n                reversed_semi_flattened_output.arg_buf.append_tail((double)e.first);\n                reversed_semi_flattened_output.operations.push_back(\n                    CircuitInstruction{\n                        GateType::OBSERVABLE_INCLUDE,\n                        reversed_semi_flattened_output.arg_buf.commit_tail(),\n                        reversed_semi_flattened_output.target_buf.take_copy(e.second.range()),\n                        op.tag,\n                    });\n            }\n        }\n        obs_changes.clear();\n    }\n\n    void undo_repeat_block(const Circuit &circuit, const CircuitInstruction &op) {\n        const Circuit &loop = op.repeat_block_body(circuit);\n        uint64_t reps = op.repeat_block_rep_count();\n\n        Circuit tmp = std::move(reversed_semi_flattened_output);\n        for (size_t rep = 0; rep < reps; rep++) {\n            reversed_semi_flattened_output.clear();\n            undo_circuit(loop);\n            tmp.append_repeat_block(1, std::move(reversed_semi_flattened_output), op.tag);\n        }\n        reversed_semi_flattened_output = std::move(tmp);\n    }\n\n    void undo_gate(const CircuitInstruction &op) {\n        if (GATE_DATA[op.gate_type].flags & GATE_CAN_TARGET_BITS) {\n            undo_feedback_capable_pcp_operation(op);\n        } else {\n            reversed_semi_flattened_output.safe_append(op, true);\n            tracker.undo_gate(op);\n        }\n    }\n\n    void undo_circuit(const Circuit &circuit) {\n        for (size_t k = circuit.operations.size(); k--;) {\n            const auto &op = circuit.operations[k];\n            if (op.gate_type == GateType::REPEAT) {\n                undo_repeat_block(circuit, op);\n            } else {\n                undo_gate(op);\n            }\n        }\n    }\n\n    Circuit build_output(const Circuit &reversed) {\n        Circuit result;\n\n        for (size_t k = reversed.operations.size(); k--;) {\n            const auto &op = reversed.operations[k];\n            tracker.num_measurements_in_past += op.count_measurement_results();\n\n            if (op.gate_type == GateType::REPEAT) {\n                result.append_repeat_block(\n                    op.repeat_block_rep_count(), build_output(op.repeat_block_body(reversed)), op.tag);\n                continue;\n            }\n\n            if (op.gate_type == GateType::DETECTOR) {\n                auto p = det_changes.find(tracker.num_detectors_in_past);\n                tracker.num_detectors_in_past++;\n                if (p != det_changes.end()) {\n                    auto &changes = p->second;\n                    for (const auto &t : op.targets) {\n                        changes.xor_item(tracker.num_measurements_in_past + t.rec_offset());\n                    }\n\n                    // Build new targets at tail of reversed_semi_flattened_output.\n                    for (const auto &m : changes) {\n                        reversed_semi_flattened_output.target_buf.append_tail(\n                            GateTarget::rec((int64_t)m - (int64_t)tracker.num_measurements_in_past));\n                    }\n                    result.safe_append(CircuitInstruction(\n                        op.gate_type, op.args, reversed_semi_flattened_output.target_buf.tail, op.tag));\n                    reversed_semi_flattened_output.target_buf.discard_tail();\n\n                    continue;\n                }\n            }\n\n            result.safe_append(op);\n        }\n        return result;\n    }\n};\n\nCircuit circuit_with_identical_adjacent_loops_fused(const Circuit &circuit) {\n    Circuit result;\n    Circuit growing_loop;\n    uint64_t loop_reps = 0;\n    std::string_view loop_tag;\n\n    auto flush_loop = [&]() {\n        if (loop_reps > 0) {\n            growing_loop = circuit_with_identical_adjacent_loops_fused(growing_loop);\n            if (loop_reps > 1) {\n                result.append_repeat_block(loop_reps, std::move(growing_loop), loop_tag);\n            } else if (loop_reps == 1) {\n                result += growing_loop;\n            }\n        }\n        loop_tag = \"\";\n        loop_reps = 0;\n    };\n    for (const auto &op : circuit.operations) {\n        bool is_loop = op.gate_type == GateType::REPEAT;\n\n        // Grow the growing loop or flush it if needed.\n        if (loop_reps > 0) {\n            if (is_loop && growing_loop == op.repeat_block_body(circuit)) {\n                loop_reps += op.repeat_block_rep_count();\n                continue;\n            }\n            flush_loop();\n        }\n\n        // Start a new growing loop if needed.\n        assert(loop_reps == 0);\n        if (is_loop) {\n            growing_loop = op.repeat_block_body(circuit);\n            loop_reps = op.repeat_block_rep_count();\n            loop_tag = op.tag;\n            continue;\n        }\n\n        assert(loop_reps == 0);\n        result.safe_append(op);\n    }\n    flush_loop();\n\n    return result;\n}\n\nCircuit stim::circuit_with_inlined_feedback(const Circuit &circuit) {\n    WithoutFeedbackHelper helper(circuit);\n    helper.undo_circuit(circuit);\n    assert(helper.tracker.num_measurements_in_past == 0);\n    assert(helper.tracker.num_detectors_in_past == 0);\n    Circuit output = helper.build_output(helper.reversed_semi_flattened_output);\n    return circuit_with_identical_adjacent_loops_fused(output);\n}\n"
  },
  {
    "path": "src/stim/util_top/transform_without_feedback.h",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#ifndef _STIM_UTIL_TOP_TRANSFORM_WITHOUT_FEEDBACK_H\n#define _STIM_UTIL_TOP_TRANSFORM_WITHOUT_FEEDBACK_H\n\n#include <complex>\n#include <iostream>\n#include <random>\n#include <unordered_map>\n\n#include \"stim/circuit/circuit.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n\nnamespace stim {\n\nCircuit circuit_with_inlined_feedback(const Circuit &circuit);\n\n}  // namespace stim\n\n#endif\n"
  },
  {
    "path": "src/stim/util_top/transform_without_feedback.test.cc",
    "content": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n#include \"stim/util_top/transform_without_feedback.h\"\n\n#include \"gtest/gtest.h\"\n\n#include \"stim/simulators/error_analyzer.h\"\n\nusing namespace stim;\n\nTEST(circuit_with_inlined_feedback, basic) {\n    ASSERT_EQ(\n        circuit_with_inlined_feedback(Circuit(R\"CIRCUIT(\n            MR 0\n            H 0\n            CX sweep[5] 0\n            CY rec[-1] 0 rec[-1] 0 2 3 rec[-1] 0\n            H 0\n            M 0\n            DETECTOR rec[-1]\n            OBSERVABLE_INCLUDE(2) rec[-1]\n        )CIRCUIT\")),\n        Circuit(R\"CIRCUIT(\n            MR 0\n            H 0\n            CX sweep[5] 0\n            OBSERVABLE_INCLUDE(2) rec[-1]\n            CY 2 3\n            H 0\n            M 0\n            DETECTOR rec[-2] rec[-1]\n            OBSERVABLE_INCLUDE(2) rec[-1]\n        )CIRCUIT\"));\n}\n\nTEST(circuit_with_inlined_feedback, demolition_feedback) {\n    Circuit inp = Circuit(R\"CIRCUIT(\n        CX 0 1\n        M 1\n        CX rec[-1] 1\n        CX 0 1\n        M 1\n        DETECTOR rec[-1] rec[-2]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\");\n    ASSERT_EQ(circuit_with_inlined_feedback(inp), Circuit(R\"CIRCUIT(\n        CX 0 1\n        M 1\n        OBSERVABLE_INCLUDE(0) rec[-1]\n        CX 0 1\n        M 1\n        DETECTOR rec[-1]\n        OBSERVABLE_INCLUDE(0) rec[-1]\n    )CIRCUIT\"));\n}\n\nTEST(circuit_with_inlined_feedback, loop) {\n    Circuit inp = Circuit(R\"CIRCUIT(\n        R 0 1\n        X_ERROR(0.125) 0 1\n        CX 0 1\n        M 1\n        CX rec[-1] 1\n        DETECTOR rec[-1]\n        REPEAT 30 {\n            X_ERROR(0.125) 0 1\n            CX 0 1\n            M 1\n            CX rec[-1] 1\n            DETECTOR rec[-1] rec[-2]\n        }\n\n        M 0\n        DETECTOR rec[-1] rec[-2]\n    )CIRCUIT\");\n    auto actual = circuit_with_inlined_feedback(inp);\n\n    auto dem1 = ErrorAnalyzer::circuit_to_detector_error_model(inp, true, true, false, 0, false, true);\n    auto dem2 = ErrorAnalyzer::circuit_to_detector_error_model(actual, true, true, false, 0, false, true);\n    dem1 = dem1.flattened();\n    dem2 = dem2.flattened();\n    ASSERT_TRUE(dem1.approx_equals(dem2, 1e-5));\n\n    ASSERT_EQ(actual, Circuit(R\"CIRCUIT(\n        R 0 1\n        X_ERROR(0.125) 0 1\n        CX 0 1\n        M 1\n        DETECTOR rec[-1]\n\n        X_ERROR(0.125) 0 1\n        CX 0 1\n        M 1\n        DETECTOR rec[-1]\n\n        REPEAT 29 {\n            X_ERROR(0.125) 0 1\n            CX 0 1\n            M 1\n            DETECTOR rec[-3] rec[-1]\n        }\n\n        M 0\n        DETECTOR rec[-3] rec[-2] rec[-1]\n    )CIRCUIT\"));\n}\n\nTEST(circuit_with_inlined_feedback, mpp) {\n    Circuit inp = Circuit(R\"CIRCUIT(\n        RX 0\n        RY 1\n        RZ 2\n        MPP X0*Y1*Z2 Z5\n        CX rec[-2] 3\n        M 3\n        DETECTOR rec[-1]\n    )CIRCUIT\");\n    auto actual = circuit_with_inlined_feedback(inp);\n\n    auto dem1 = ErrorAnalyzer::circuit_to_detector_error_model(inp, true, true, false, 0, false, true);\n    auto dem2 = ErrorAnalyzer::circuit_to_detector_error_model(actual, true, true, false, 0, false, true);\n    dem1 = dem1.flattened();\n    dem2 = dem2.flattened();\n    ASSERT_TRUE(dem1.approx_equals(dem2, 1e-5));\n\n    ASSERT_EQ(actual, Circuit(R\"CIRCUIT(\n        RX 0\n        RY 1\n        R 2\n        MPP X0*Y1*Z2 Z5\n        M 3\n        DETECTOR rec[-3] rec[-1]\n    )CIRCUIT\"));\n}\n\nTEST(circuit_with_inlined_feedback, interleaved_feedback_does_not_reorder_operations) {\n    ASSERT_EQ(\n        circuit_with_inlined_feedback(Circuit(R\"CIRCUIT(\n        H 0\n        CZ\n        H 1\n    )CIRCUIT\")),\n        Circuit(R\"CIRCUIT(\n        H 0 1\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        circuit_with_inlined_feedback(Circuit(R\"CIRCUIT(\n        M 0\n        CX\n        M 1\n    )CIRCUIT\")),\n        Circuit(R\"CIRCUIT(\n        M 0 1\n    )CIRCUIT\"));\n\n    ASSERT_EQ(\n        circuit_with_inlined_feedback(Circuit(R\"CIRCUIT(\n        M 0 1\n        CX\n        M 2\n        CX rec[-1] 3\n        M 3\n        DETECTOR rec[-1]\n    )CIRCUIT\")),\n        Circuit(R\"CIRCUIT(\n        M 0 1 2 3\n        DETECTOR rec[-2] rec[-1]\n    )CIRCUIT\"));\n}\n"
  },
  {
    "path": "src/stim.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim.h\"\n"
  },
  {
    "path": "src/stim.h",
    "content": "#ifndef _STIM_H\n#define _STIM_H\n/// WARNING: THE STIM C++ API MAKES NO COMPATIBILITY GUARANTEES.\n/// It may change arbitrarily and catastrophically from minor version to minor version.\n/// If you need a stable API, use stim's Python API.\n#include \"stim/circuit/circuit.h\"\n#include \"stim/circuit/circuit_instruction.h\"\n#include \"stim/circuit/gate_decomposition.h\"\n#include \"stim/circuit/gate_target.h\"\n#include \"stim/cmd/command_analyze_errors.h\"\n#include \"stim/cmd/command_convert.h\"\n#include \"stim/cmd/command_detect.h\"\n#include \"stim/cmd/command_diagram.h\"\n#include \"stim/cmd/command_explain_errors.h\"\n#include \"stim/cmd/command_gen.h\"\n#include \"stim/cmd/command_help.h\"\n#include \"stim/cmd/command_m2d.h\"\n#include \"stim/cmd/command_repl.h\"\n#include \"stim/cmd/command_sample.h\"\n#include \"stim/cmd/command_sample_dem.h\"\n#include \"stim/dem/dem_instruction.h\"\n#include \"stim/dem/detector_error_model.h\"\n#include \"stim/diagram/ascii_diagram.h\"\n#include \"stim/diagram/base64.h\"\n#include \"stim/diagram/basic_3d_diagram.h\"\n#include \"stim/diagram/circuit_timeline_helper.h\"\n#include \"stim/diagram/coord.h\"\n#include \"stim/diagram/crumble.h\"\n#include \"stim/diagram/crumble_data.h\"\n#include \"stim/diagram/detector_slice/detector_slice_set.h\"\n#include \"stim/diagram/diagram_util.h\"\n#include \"stim/diagram/gate_data_3d.h\"\n#include \"stim/diagram/gate_data_3d_texture_data.h\"\n#include \"stim/diagram/gate_data_svg.h\"\n#include \"stim/diagram/gltf.h\"\n#include \"stim/diagram/graph/match_graph_3d_drawer.h\"\n#include \"stim/diagram/graph/match_graph_svg_drawer.h\"\n#include \"stim/diagram/json_obj.h\"\n#include \"stim/diagram/lattice_map.h\"\n#include \"stim/diagram/timeline/timeline_3d_drawer.h\"\n#include \"stim/diagram/timeline/timeline_ascii_drawer.h\"\n#include \"stim/diagram/timeline/timeline_svg_drawer.h\"\n#include \"stim/gates/gates.h\"\n#include \"stim/gen/circuit_gen_params.h\"\n#include \"stim/gen/gen_color_code.h\"\n#include \"stim/gen/gen_rep_code.h\"\n#include \"stim/gen/gen_surface_code.h\"\n#include \"stim/io/measure_record.h\"\n#include \"stim/io/measure_record_batch.h\"\n#include \"stim/io/measure_record_batch_writer.h\"\n#include \"stim/io/measure_record_reader.h\"\n#include \"stim/io/measure_record_writer.h\"\n#include \"stim/io/raii_file.h\"\n#include \"stim/io/sparse_shot.h\"\n#include \"stim/io/stim_data_formats.h\"\n#include \"stim/main_namespaced.h\"\n#include \"stim/mem/bit_ref.h\"\n#include \"stim/mem/bitword.h\"\n#include \"stim/mem/bitword_128_sse.h\"\n#include \"stim/mem/bitword_256_avx.h\"\n#include \"stim/mem/bitword_64.h\"\n#include \"stim/mem/fixed_cap_vector.h\"\n#include \"stim/mem/monotonic_buffer.h\"\n#include \"stim/mem/simd_bit_table.h\"\n#include \"stim/mem/simd_bits.h\"\n#include \"stim/mem/simd_bits_range_ref.h\"\n#include \"stim/mem/simd_util.h\"\n#include \"stim/mem/simd_word.h\"\n#include \"stim/mem/span_ref.h\"\n#include \"stim/mem/sparse_xor_vec.h\"\n#include \"stim/search/graphlike/algo.h\"\n#include \"stim/search/graphlike/edge.h\"\n#include \"stim/search/graphlike/graph.h\"\n#include \"stim/search/graphlike/node.h\"\n#include \"stim/search/graphlike/search_state.h\"\n#include \"stim/search/hyper/algo.h\"\n#include \"stim/search/hyper/edge.h\"\n#include \"stim/search/hyper/graph.h\"\n#include \"stim/search/hyper/node.h\"\n#include \"stim/search/hyper/search_state.h\"\n#include \"stim/search/sat/wcnf.h\"\n#include \"stim/search/search.h\"\n#include \"stim/simulators/dem_sampler.h\"\n#include \"stim/simulators/error_analyzer.h\"\n#include \"stim/simulators/error_matcher.h\"\n#include \"stim/simulators/force_streaming.h\"\n#include \"stim/simulators/frame_simulator.h\"\n#include \"stim/simulators/frame_simulator_util.h\"\n#include \"stim/simulators/graph_simulator.h\"\n#include \"stim/simulators/matched_error.h\"\n#include \"stim/simulators/measurements_to_detection_events.h\"\n#include \"stim/simulators/sparse_rev_frame_tracker.h\"\n#include \"stim/simulators/tableau_simulator.h\"\n#include \"stim/simulators/vector_simulator.h\"\n#include \"stim/stabilizers/clifford_string.h\"\n#include \"stim/stabilizers/flex_pauli_string.h\"\n#include \"stim/stabilizers/flow.h\"\n#include \"stim/stabilizers/pauli_string.h\"\n#include \"stim/stabilizers/pauli_string_iter.h\"\n#include \"stim/stabilizers/pauli_string_ref.h\"\n#include \"stim/stabilizers/tableau.h\"\n#include \"stim/stabilizers/tableau_iter.h\"\n#include \"stim/stabilizers/tableau_transposed_raii.h\"\n#include \"stim/util_bot/arg_parse.h\"\n#include \"stim/util_bot/error_decomp.h\"\n#include \"stim/util_bot/probability_util.h\"\n#include \"stim/util_bot/str_util.h\"\n#include \"stim/util_bot/twiddle.h\"\n#include \"stim/util_top/circuit_flow_generators.h\"\n#include \"stim/util_top/circuit_inverse_qec.h\"\n#include \"stim/util_top/circuit_inverse_unitary.h\"\n#include \"stim/util_top/circuit_to_dem.h\"\n#include \"stim/util_top/circuit_to_detecting_regions.h\"\n#include \"stim/util_top/circuit_vs_amplitudes.h\"\n#include \"stim/util_top/circuit_vs_tableau.h\"\n#include \"stim/util_top/count_determined_measurements.h\"\n#include \"stim/util_top/export_crumble_url.h\"\n#include \"stim/util_top/export_qasm.h\"\n#include \"stim/util_top/export_quirk_url.h\"\n#include \"stim/util_top/has_flow.h\"\n#include \"stim/util_top/mbqc_decomposition.h\"\n#include \"stim/util_top/missing_detectors.h\"\n#include \"stim/util_top/reference_sample_tree.h\"\n#include \"stim/util_top/simplified_circuit.h\"\n#include \"stim/util_top/stabilizers_to_tableau.h\"\n#include \"stim/util_top/stabilizers_vs_amplitudes.h\"\n#include \"stim/util_top/transform_without_feedback.h\"\n#endif\n"
  },
  {
    "path": "src/stim.test.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"stim.h\"\n\n#include \"gtest/gtest.h\"\n\nTEST(stim, include1) {\n    stim::Circuit c(\"H 0\");\n    ASSERT_EQ(c.count_qubits(), 1);\n    ASSERT_EQ(stim::GATE_DATA.at(\"PAULI_CHANNEL_2\").arg_count, 15);\n}\n\nTEST(stim, include3) {\n    stim::ErrorAnalyzer::circuit_to_detector_error_model({}, false, false, false, 0.0, false, true);\n}\n"
  },
  {
    "path": "src/stim_included_twice.test.cc",
    "content": "/*\n * Copyright 2021 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n#include \"gtest/gtest.h\"\n\n#include \"stim.h\"  // The other include is in stim.test.cc; this is the second one.\n\nTEST(stim, include2) {\n    stim::Circuit c(\"H 0\");\n    ASSERT_EQ(c.count_qubits(), 1);\n    ASSERT_EQ(stim::GATE_DATA.at(\"PAULI_CHANNEL_2\").arg_count, 15);\n}\n"
  },
  {
    "path": "testdata/circuit_all_ops_3d.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.4375],\"min\":[0,0.375],\"name\":\"tex_coords_gate_I\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.4375],\"min\":[0,0.375],\"name\":\"tex_coords_gate_X\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.5],\"min\":[0,0.4375],\"name\":\"tex_coords_gate_Y\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.5625],\"min\":[0,0.5],\"name\":\"tex_coords_gate_Z\",\"type\":\"VEC2\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.625],\"min\":[0.0625,0.5625],\"name\":\"tex_coords_gate_C_XYZ\",\"type\":\"VEC2\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.6875],\"min\":[0.375,0.625],\"name\":\"tex_coords_gate_C_NXYZ\",\"type\":\"VEC2\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.6875],\"min\":[0.4375,0.625],\"name\":\"tex_coords_gate_C_XNYZ\",\"type\":\"VEC2\"},{\"bufferView\":8,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.6875],\"min\":[0.5,0.625],\"name\":\"tex_coords_gate_C_XYNZ\",\"type\":\"VEC2\"},{\"bufferView\":9,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.625],\"min\":[0.125,0.5625],\"name\":\"tex_coords_gate_C_ZYX\",\"type\":\"VEC2\"},{\"bufferView\":10,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.6875],\"min\":[0.5625,0.625],\"name\":\"tex_coords_gate_C_NZYX\",\"type\":\"VEC2\"},{\"bufferView\":11,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.6875],\"min\":[0.625,0.625],\"name\":\"tex_coords_gate_C_ZNYX\",\"type\":\"VEC2\"},{\"bufferView\":12,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.6875],\"min\":[0.6875,0.625],\"name\":\"tex_coords_gate_C_ZYNX\",\"type\":\"VEC2\"},{\"bufferView\":13,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.5625],\"min\":[0.0625,0.5],\"name\":\"tex_coords_gate_H_XY\",\"type\":\"VEC2\"},{\"bufferView\":14,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.5],\"min\":[0.0625,0.4375],\"name\":\"tex_coords_gate_H\",\"type\":\"VEC2\"},{\"bufferView\":15,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.4375],\"min\":[0.0625,0.375],\"name\":\"tex_coords_gate_H_YZ\",\"type\":\"VEC2\"},{\"bufferView\":16,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.6875],\"min\":[0.75,0.625],\"name\":\"tex_coords_gate_H_NXY\",\"type\":\"VEC2\"},{\"bufferView\":17,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.875,0.6875],\"min\":[0.8125,0.625],\"name\":\"tex_coords_gate_H_NXZ\",\"type\":\"VEC2\"},{\"bufferView\":18,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.9375,0.6875],\"min\":[0.875,0.625],\"name\":\"tex_coords_gate_H_NYZ\",\"type\":\"VEC2\"},{\"bufferView\":19,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.4375],\"min\":[0.125,0.375],\"name\":\"tex_coords_gate_SQRT_X\",\"type\":\"VEC2\"},{\"bufferView\":20,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.4375],\"min\":[0.1875,0.375],\"name\":\"tex_coords_gate_SQRT_X_DAG\",\"type\":\"VEC2\"},{\"bufferView\":21,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.5],\"min\":[0.125,0.4375],\"name\":\"tex_coords_gate_SQRT_Y\",\"type\":\"VEC2\"},{\"bufferView\":22,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.5],\"min\":[0.1875,0.4375],\"name\":\"tex_coords_gate_SQRT_Y_DAG\",\"type\":\"VEC2\"},{\"bufferView\":23,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.5625],\"min\":[0.125,0.5],\"name\":\"tex_coords_gate_S\",\"type\":\"VEC2\"},{\"bufferView\":24,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.5625],\"min\":[0.1875,0.5],\"name\":\"tex_coords_gate_S_DAG\",\"type\":\"VEC2\"},{\"bufferView\":25,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":26,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.45254835486412,0.45254835486412],\"min\":[0,-0.45254835486412,-0.45254835486412],\"name\":\"control_zswap_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":27,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":28,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.45254835486412,0.45254835486412],\"min\":[0,-0.45254835486412,-0.45254835486412],\"name\":\"control_xswap_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":29,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.625],\"min\":[0.3125,0.5625],\"name\":\"tex_coords_gate_ISWAP\",\"type\":\"VEC2\"},{\"bufferView\":30,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.625],\"min\":[0.375,0.5625],\"name\":\"tex_coords_gate_ISWAP_DAG\",\"type\":\"VEC2\"},{\"bufferView\":31,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.625],\"min\":[0.4375,0.5625],\"name\":\"tex_coords_gate_SWAP\",\"type\":\"VEC2\"},{\"bufferView\":32,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.4375],\"min\":[0.6875,0.375],\"name\":\"tex_coords_gate_SQRT_XX\",\"type\":\"VEC2\"},{\"bufferView\":33,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.4375],\"min\":[0.75,0.375],\"name\":\"tex_coords_gate_SQRT_XX_DAG\",\"type\":\"VEC2\"},{\"bufferView\":34,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.5],\"min\":[0.6875,0.4375],\"name\":\"tex_coords_gate_SQRT_YY\",\"type\":\"VEC2\"},{\"bufferView\":35,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.5],\"min\":[0.75,0.4375],\"name\":\"tex_coords_gate_SQRT_YY_DAG\",\"type\":\"VEC2\"},{\"bufferView\":36,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.5625],\"min\":[0.6875,0.5],\"name\":\"tex_coords_gate_SQRT_ZZ\",\"type\":\"VEC2\"},{\"bufferView\":37,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.5625],\"min\":[0.75,0.5],\"name\":\"tex_coords_gate_SQRT_ZZ_DAG\",\"type\":\"VEC2\"},{\"bufferView\":38,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[1,0.6875],\"min\":[0.9375,0.625],\"name\":\"tex_coords_gate_II\",\"type\":\"VEC2\"},{\"bufferView\":39,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":40,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"control_x_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":41,\"byteOffset\":0,\"componentType\":5126,\"count\":3,\"max\":[0,0.400000005960464,0.346410155296326],\"min\":[0,-0.200000032782555,-0.346410185098648],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":42,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":43,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.4375],\"min\":[0.5,0.375],\"name\":\"tex_coords_gate_E:X\",\"type\":\"VEC2\"},{\"bufferView\":44,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.5],\"min\":[0.5,0.4375],\"name\":\"tex_coords_gate_E:Y\",\"type\":\"VEC2\"},{\"bufferView\":45,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.5625],\"min\":[0.5,0.5],\"name\":\"tex_coords_gate_E:Z\",\"type\":\"VEC2\"},{\"bufferView\":46,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.4375],\"min\":[0.5625,0.375],\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:X\",\"type\":\"VEC2\"},{\"bufferView\":47,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.5],\"min\":[0.5625,0.4375],\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Y\",\"type\":\"VEC2\"},{\"bufferView\":48,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.5625],\"min\":[0.5625,0.5],\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Z\",\"type\":\"VEC2\"},{\"bufferView\":49,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.625],\"min\":[0.1875,0.5625],\"name\":\"tex_coords_gate_DEPOLARIZE1\",\"type\":\"VEC2\"},{\"bufferView\":50,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.625],\"min\":[0.25,0.5625],\"name\":\"tex_coords_gate_DEPOLARIZE2\",\"type\":\"VEC2\"},{\"bufferView\":51,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.625],\"min\":[0.5,0.5625],\"name\":\"tex_coords_gate_PAULI_CHANNEL_1\",\"type\":\"VEC2\"},{\"bufferView\":52,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.625],\"min\":[0.5625,0.5625],\"name\":\"tex_coords_gate_PAULI_CHANNEL_2\",\"type\":\"VEC2\"},{\"bufferView\":53,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.4375],\"min\":[0.4375,0.375],\"name\":\"tex_coords_gate_X_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":54,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.5],\"min\":[0.4375,0.4375],\"name\":\"tex_coords_gate_Y_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":55,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.5625],\"min\":[0.4375,0.5],\"name\":\"tex_coords_gate_Z_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":56,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.9375,0.625],\"min\":[0.875,0.5625],\"name\":\"tex_coords_gate_HERALDED_ERASE\",\"type\":\"VEC2\"},{\"bufferView\":57,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[1,0.625],\"min\":[0.9375,0.5625],\"name\":\"tex_coords_gate_HERALDED_PAULI_CHANNEL_1\",\"type\":\"VEC2\"},{\"bufferView\":58,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[1,0.5625],\"min\":[0.9375,0.5],\"name\":\"tex_coords_gate_I_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":59,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[1,0.75],\"min\":[0.9375,0.6875],\"name\":\"tex_coords_gate_II_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":60,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.4375],\"min\":[0.625,0.375],\"name\":\"tex_coords_gate_MPP:X\",\"type\":\"VEC2\"},{\"bufferView\":61,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.5],\"min\":[0.625,0.4375],\"name\":\"tex_coords_gate_MPP:Y\",\"type\":\"VEC2\"},{\"bufferView\":62,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.5625],\"min\":[0.625,0.5],\"name\":\"tex_coords_gate_MPP:Z\",\"type\":\"VEC2\"},{\"bufferView\":63,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.6875],\"min\":[0,0.625],\"name\":\"tex_coords_gate_SPP:X\",\"type\":\"VEC2\"},{\"bufferView\":64,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.6875],\"min\":[0.0625,0.625],\"name\":\"tex_coords_gate_SPP:Y\",\"type\":\"VEC2\"},{\"bufferView\":65,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.6875],\"min\":[0.125,0.625],\"name\":\"tex_coords_gate_SPP:Z\",\"type\":\"VEC2\"},{\"bufferView\":66,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.6875],\"min\":[0.1875,0.625],\"name\":\"tex_coords_gate_SPP_DAG:X\",\"type\":\"VEC2\"},{\"bufferView\":67,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.6875],\"min\":[0.25,0.625],\"name\":\"tex_coords_gate_SPP_DAG:Y\",\"type\":\"VEC2\"},{\"bufferView\":68,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.6875],\"min\":[0.3125,0.625],\"name\":\"tex_coords_gate_SPP_DAG:Z\",\"type\":\"VEC2\"},{\"bufferView\":69,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.4375],\"min\":[0.375,0.375],\"name\":\"tex_coords_gate_MRX\",\"type\":\"VEC2\"},{\"bufferView\":70,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.5],\"min\":[0.375,0.4375],\"name\":\"tex_coords_gate_MRY\",\"type\":\"VEC2\"},{\"bufferView\":71,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.5625],\"min\":[0.375,0.5],\"name\":\"tex_coords_gate_MR\",\"type\":\"VEC2\"},{\"bufferView\":72,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.4375],\"min\":[0.25,0.375],\"name\":\"tex_coords_gate_MX\",\"type\":\"VEC2\"},{\"bufferView\":73,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5],\"min\":[0.25,0.4375],\"name\":\"tex_coords_gate_MY\",\"type\":\"VEC2\"},{\"bufferView\":74,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5625],\"min\":[0.25,0.5],\"name\":\"tex_coords_gate_M\",\"type\":\"VEC2\"},{\"bufferView\":75,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.4375],\"min\":[0.3125,0.375],\"name\":\"tex_coords_gate_RX\",\"type\":\"VEC2\"},{\"bufferView\":76,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.5],\"min\":[0.3125,0.4375],\"name\":\"tex_coords_gate_RY\",\"type\":\"VEC2\"},{\"bufferView\":77,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.5625],\"min\":[0.3125,0.5],\"name\":\"tex_coords_gate_R\",\"type\":\"VEC2\"},{\"bufferView\":78,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.625],\"min\":[0.625,0.5625],\"name\":\"tex_coords_gate_MXX\",\"type\":\"VEC2\"},{\"bufferView\":79,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.625],\"min\":[0.6875,0.5625],\"name\":\"tex_coords_gate_MYY\",\"type\":\"VEC2\"},{\"bufferView\":80,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.625],\"min\":[0.75,0.5625],\"name\":\"tex_coords_gate_MZZ\",\"type\":\"VEC2\"},{\"bufferView\":81,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.875,0.625],\"min\":[0.8125,0.5625],\"name\":\"tex_coords_gate_MPAD\",\"type\":\"VEC2\"},{\"bufferView\":82,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.875,0.4375],\"min\":[0.8125,0.375],\"name\":\"tex_coords_gate_X:REC\",\"type\":\"VEC2\"},{\"bufferView\":83,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.9375,0.5],\"min\":[0.875,0.4375],\"name\":\"tex_coords_gate_Y:SWEEP\",\"type\":\"VEC2\"},{\"bufferView\":84,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.875,0.5625],\"min\":[0.8125,0.5],\"name\":\"tex_coords_gate_Z:REC\",\"type\":\"VEC2\"},{\"bufferView\":85,\"byteOffset\":0,\"componentType\":5126,\"count\":146,\"max\":[1,-2,-0],\"min\":[-30,-34,-32],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":86,\"byteOffset\":0,\"componentType\":5126,\"count\":30,\"max\":[0,0.5,1],\"min\":[-21.25,-35,-33],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":87,\"byteOffset\":0,\"componentType\":5126,\"count\":96,\"max\":[-0.75,-1.20000004768372,0.5],\"min\":[-27.25,-1.60000002384186,-32.5],\"name\":\"buf_blue_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_I\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_X\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Y\",\"target\":34962},{\"buffer\":4,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Z\",\"target\":34962},{\"buffer\":5,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_XYZ\",\"target\":34962},{\"buffer\":6,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_NXYZ\",\"target\":34962},{\"buffer\":7,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_XNYZ\",\"target\":34962},{\"buffer\":8,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_XYNZ\",\"target\":34962},{\"buffer\":9,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_ZYX\",\"target\":34962},{\"buffer\":10,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_NZYX\",\"target\":34962},{\"buffer\":11,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_ZNYX\",\"target\":34962},{\"buffer\":12,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_ZYNX\",\"target\":34962},{\"buffer\":13,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H_XY\",\"target\":34962},{\"buffer\":14,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H\",\"target\":34962},{\"buffer\":15,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H_YZ\",\"target\":34962},{\"buffer\":16,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H_NXY\",\"target\":34962},{\"buffer\":17,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H_NXZ\",\"target\":34962},{\"buffer\":18,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H_NYZ\",\"target\":34962},{\"buffer\":19,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_X\",\"target\":34962},{\"buffer\":20,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_X_DAG\",\"target\":34962},{\"buffer\":21,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_Y\",\"target\":34962},{\"buffer\":22,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_Y_DAG\",\"target\":34962},{\"buffer\":23,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_S\",\"target\":34962},{\"buffer\":24,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_S_DAG\",\"target\":34962},{\"buffer\":25,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":26,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_zswap_line_cross\",\"target\":34962},{\"buffer\":27,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":28,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_xswap_line_cross\",\"target\":34962},{\"buffer\":29,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ISWAP\",\"target\":34962},{\"buffer\":30,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ISWAP_DAG\",\"target\":34962},{\"buffer\":31,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SWAP\",\"target\":34962},{\"buffer\":32,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_XX\",\"target\":34962},{\"buffer\":33,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_XX_DAG\",\"target\":34962},{\"buffer\":34,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_YY\",\"target\":34962},{\"buffer\":35,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_YY_DAG\",\"target\":34962},{\"buffer\":36,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_ZZ\",\"target\":34962},{\"buffer\":37,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_ZZ_DAG\",\"target\":34962},{\"buffer\":38,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_II\",\"target\":34962},{\"buffer\":39,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":40,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_x_line_cross\",\"target\":34962},{\"buffer\":41,\"byteLength\":36,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":42,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":43,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_E:X\",\"target\":34962},{\"buffer\":44,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_E:Y\",\"target\":34962},{\"buffer\":45,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_E:Z\",\"target\":34962},{\"buffer\":46,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:X\",\"target\":34962},{\"buffer\":47,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Y\",\"target\":34962},{\"buffer\":48,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Z\",\"target\":34962},{\"buffer\":49,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_DEPOLARIZE1\",\"target\":34962},{\"buffer\":50,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_DEPOLARIZE2\",\"target\":34962},{\"buffer\":51,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_PAULI_CHANNEL_1\",\"target\":34962},{\"buffer\":52,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_PAULI_CHANNEL_2\",\"target\":34962},{\"buffer\":53,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_X_ERROR\",\"target\":34962},{\"buffer\":54,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Y_ERROR\",\"target\":34962},{\"buffer\":55,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Z_ERROR\",\"target\":34962},{\"buffer\":56,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_HERALDED_ERASE\",\"target\":34962},{\"buffer\":57,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_HERALDED_PAULI_CHANNEL_1\",\"target\":34962},{\"buffer\":58,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_I_ERROR\",\"target\":34962},{\"buffer\":59,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_II_ERROR\",\"target\":34962},{\"buffer\":60,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:X\",\"target\":34962},{\"buffer\":61,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:Y\",\"target\":34962},{\"buffer\":62,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:Z\",\"target\":34962},{\"buffer\":63,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SPP:X\",\"target\":34962},{\"buffer\":64,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SPP:Y\",\"target\":34962},{\"buffer\":65,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SPP:Z\",\"target\":34962},{\"buffer\":66,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SPP_DAG:X\",\"target\":34962},{\"buffer\":67,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SPP_DAG:Y\",\"target\":34962},{\"buffer\":68,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SPP_DAG:Z\",\"target\":34962},{\"buffer\":69,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MRX\",\"target\":34962},{\"buffer\":70,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MRY\",\"target\":34962},{\"buffer\":71,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MR\",\"target\":34962},{\"buffer\":72,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MX\",\"target\":34962},{\"buffer\":73,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MY\",\"target\":34962},{\"buffer\":74,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_M\",\"target\":34962},{\"buffer\":75,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_RX\",\"target\":34962},{\"buffer\":76,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_RY\",\"target\":34962},{\"buffer\":77,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_R\",\"target\":34962},{\"buffer\":78,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MXX\",\"target\":34962},{\"buffer\":79,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MYY\",\"target\":34962},{\"buffer\":80,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MZZ\",\"target\":34962},{\"buffer\":81,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPAD\",\"target\":34962},{\"buffer\":82,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_X:REC\",\"target\":34962},{\"buffer\":83,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Y:SWEEP\",\"target\":34962},{\"buffer\":84,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Z:REC\",\"target\":34962},{\"buffer\":85,\"byteLength\":1752,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":86,\"byteLength\":360,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962},{\"buffer\":87,\"byteLength\":1152,\"byteOffset\":0,\"name\":\"buf_blue_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_I\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAwD4AAAAAAADAPgAAgD0AAOA+AAAAAAAAwD4AAAAAAADgPgAAgD0AAOA+AACAPQAA4D4AAIA9AADAPgAAAAAAAOA+AAAAAAAA4D4AAIA9AADAPgAAAAAAAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_X\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAwD4AAAAAAADAPgAAgD0AAOA+AAAAAAAAwD4AAAAAAADgPgAAgD0AAOA+AACAPQAA4D4AAIA9AADAPgAAAAAAAOA+AAAAAAAA4D4AAIA9AADAPgAAAAAAAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Y\",\"uri\":\"data:application/octet-stream;base64,AACAPQAA4D4AAAAAAADgPgAAgD0AAAA/AAAAAAAA4D4AAAAAAAAAPwAAgD0AAAA/AACAPQAAAD8AAIA9AADgPgAAAAAAAAA/AAAAAAAAAD8AAIA9AADgPgAAAAAAAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Z\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAAD8AAAAAAAAAPwAAgD0AABA/AAAAAAAAAD8AAAAAAAAQPwAAgD0AABA/AACAPQAAED8AAIA9AAAAPwAAAAAAABA/AAAAAAAAED8AAIA9AAAAPwAAAAAAAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_XYZ\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAED8AAIA9AAAQPwAAAD4AACA/AACAPQAAED8AAIA9AAAgPwAAAD4AACA/AAAAPgAAID8AAAA+AAAQPwAAgD0AACA/AACAPQAAID8AAAA+AAAQPwAAgD0AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_NXYZ\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAID8AAMA+AAAgPwAA4D4AADA/AADAPgAAID8AAMA+AAAwPwAA4D4AADA/AADgPgAAMD8AAOA+AAAgPwAAwD4AADA/AADAPgAAMD8AAOA+AAAgPwAAwD4AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_XNYZ\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAID8AAOA+AAAgPwAAAD8AADA/AADgPgAAID8AAOA+AAAwPwAAAD8AADA/AAAAPwAAMD8AAAA/AAAgPwAA4D4AADA/AADgPgAAMD8AAAA/AAAgPwAA4D4AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_XYNZ\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAID8AAAA/AAAgPwAAED8AADA/AAAAPwAAID8AAAA/AAAwPwAAED8AADA/AAAQPwAAMD8AABA/AAAgPwAAAD8AADA/AAAAPwAAMD8AABA/AAAgPwAAAD8AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_ZYX\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAED8AAAA+AAAQPwAAQD4AACA/AAAAPgAAED8AAAA+AAAgPwAAQD4AACA/AABAPgAAID8AAEA+AAAQPwAAAD4AACA/AAAAPgAAID8AAEA+AAAQPwAAAD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_NZYX\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAID8AABA/AAAgPwAAID8AADA/AAAQPwAAID8AABA/AAAwPwAAID8AADA/AAAgPwAAMD8AACA/AAAgPwAAED8AADA/AAAQPwAAMD8AACA/AAAgPwAAED8AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_ZNYX\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAID8AACA/AAAgPwAAMD8AADA/AAAgPwAAID8AACA/AAAwPwAAMD8AADA/AAAwPwAAMD8AADA/AAAgPwAAID8AADA/AAAgPwAAMD8AADA/AAAgPwAAID8AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_ZYNX\",\"uri\":\"data:application/octet-stream;base64,AABAPwAAID8AADA/AAAgPwAAQD8AADA/AAAwPwAAID8AADA/AAAwPwAAQD8AADA/AABAPwAAMD8AAEA/AAAgPwAAMD8AADA/AAAwPwAAMD8AAEA/AAAgPwAAMD8AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H_XY\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAAD8AAIA9AAAAPwAAAD4AABA/AACAPQAAAD8AAIA9AAAQPwAAAD4AABA/AAAAPgAAED8AAAA+AAAAPwAAgD0AABA/AACAPQAAED8AAAA+AAAAPwAAgD0AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAA4D4AAIA9AADgPgAAAD4AAAA/AACAPQAA4D4AAIA9AAAAPwAAAD4AAAA/AAAAPgAAAD8AAAA+AADgPgAAgD0AAAA/AACAPQAAAD8AAAA+AADgPgAAgD0AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H_YZ\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAwD4AAIA9AADAPgAAAD4AAOA+AACAPQAAwD4AAIA9AADgPgAAAD4AAOA+AAAAPgAA4D4AAAA+AADAPgAAgD0AAOA+AACAPQAA4D4AAAA+AADAPgAAgD0AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H_NXY\",\"uri\":\"data:application/octet-stream;base64,AABQPwAAID8AAEA/AAAgPwAAUD8AADA/AABAPwAAID8AAEA/AAAwPwAAUD8AADA/AABQPwAAMD8AAFA/AAAgPwAAQD8AADA/AABAPwAAMD8AAFA/AAAgPwAAQD8AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H_NXZ\",\"uri\":\"data:application/octet-stream;base64,AABgPwAAID8AAFA/AAAgPwAAYD8AADA/AABQPwAAID8AAFA/AAAwPwAAYD8AADA/AABgPwAAMD8AAGA/AAAgPwAAUD8AADA/AABQPwAAMD8AAGA/AAAgPwAAUD8AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H_NYZ\",\"uri\":\"data:application/octet-stream;base64,AABwPwAAID8AAGA/AAAgPwAAcD8AADA/AABgPwAAID8AAGA/AAAwPwAAcD8AADA/AABwPwAAMD8AAHA/AAAgPwAAYD8AADA/AABgPwAAMD8AAHA/AAAgPwAAYD8AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_X\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAwD4AAAA+AADAPgAAQD4AAOA+AAAAPgAAwD4AAAA+AADgPgAAQD4AAOA+AABAPgAA4D4AAEA+AADAPgAAAD4AAOA+AAAAPgAA4D4AAEA+AADAPgAAAD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_X_DAG\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAwD4AAEA+AADAPgAAgD4AAOA+AABAPgAAwD4AAEA+AADgPgAAgD4AAOA+AACAPgAA4D4AAIA+AADAPgAAQD4AAOA+AABAPgAA4D4AAIA+AADAPgAAQD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_Y\",\"uri\":\"data:application/octet-stream;base64,AABAPgAA4D4AAAA+AADgPgAAQD4AAAA/AAAAPgAA4D4AAAA+AAAAPwAAQD4AAAA/AABAPgAAAD8AAEA+AADgPgAAAD4AAAA/AAAAPgAAAD8AAEA+AADgPgAAAD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_Y_DAG\",\"uri\":\"data:application/octet-stream;base64,AACAPgAA4D4AAEA+AADgPgAAgD4AAAA/AABAPgAA4D4AAEA+AAAAPwAAgD4AAAA/AACAPgAAAD8AAIA+AADgPgAAQD4AAAA/AABAPgAAAD8AAIA+AADgPgAAQD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_S\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAAD8AAAA+AAAAPwAAQD4AABA/AAAAPgAAAD8AAAA+AAAQPwAAQD4AABA/AABAPgAAED8AAEA+AAAAPwAAAD4AABA/AAAAPgAAED8AAEA+AAAAPwAAAD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_S_DAG\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAAD8AAEA+AAAAPwAAgD4AABA/AABAPgAAAD8AAEA+AAAQPwAAgD4AABA/AACAPgAAED8AAIA+AAAAPwAAQD4AABA/AABAPgAAED8AAIA+AAAAPwAAQD4AAAA/\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_zswap_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAGu0575rtOe+AAAAAGu05z5rtOc+AAAAAGu0575rtOc+AAAAAGu05z5rtOe+\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_xswap_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAGu0575rtOe+AAAAAGu05z5rtOc+AAAAAGu0575rtOc+AAAAAGu05z5rtOe+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ISWAP\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAED8AAKA+AAAQPwAAwD4AACA/AACgPgAAED8AAKA+AAAgPwAAwD4AACA/AADAPgAAID8AAMA+AAAQPwAAoD4AACA/AACgPgAAID8AAMA+AAAQPwAAoD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ISWAP_DAG\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAED8AAMA+AAAQPwAA4D4AACA/AADAPgAAED8AAMA+AAAgPwAA4D4AACA/AADgPgAAID8AAOA+AAAQPwAAwD4AACA/AADAPgAAID8AAOA+AAAQPwAAwD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SWAP\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAED8AAOA+AAAQPwAAAD8AACA/AADgPgAAED8AAOA+AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AAAQPwAA4D4AACA/AADgPgAAID8AAAA/AAAQPwAA4D4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_XX\",\"uri\":\"data:application/octet-stream;base64,AABAPwAAwD4AADA/AADAPgAAQD8AAOA+AAAwPwAAwD4AADA/AADgPgAAQD8AAOA+AABAPwAA4D4AAEA/AADAPgAAMD8AAOA+AAAwPwAA4D4AAEA/AADAPgAAMD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_XX_DAG\",\"uri\":\"data:application/octet-stream;base64,AABQPwAAwD4AAEA/AADAPgAAUD8AAOA+AABAPwAAwD4AAEA/AADgPgAAUD8AAOA+AABQPwAA4D4AAFA/AADAPgAAQD8AAOA+AABAPwAA4D4AAFA/AADAPgAAQD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_YY\",\"uri\":\"data:application/octet-stream;base64,AABAPwAA4D4AADA/AADgPgAAQD8AAAA/AAAwPwAA4D4AADA/AAAAPwAAQD8AAAA/AABAPwAAAD8AAEA/AADgPgAAMD8AAAA/AAAwPwAAAD8AAEA/AADgPgAAMD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_YY_DAG\",\"uri\":\"data:application/octet-stream;base64,AABQPwAA4D4AAEA/AADgPgAAUD8AAAA/AABAPwAA4D4AAEA/AAAAPwAAUD8AAAA/AABQPwAAAD8AAFA/AADgPgAAQD8AAAA/AABAPwAAAD8AAFA/AADgPgAAQD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_ZZ\",\"uri\":\"data:application/octet-stream;base64,AABAPwAAAD8AADA/AAAAPwAAQD8AABA/AAAwPwAAAD8AADA/AAAQPwAAQD8AABA/AABAPwAAED8AAEA/AAAAPwAAMD8AABA/AAAwPwAAED8AAEA/AAAAPwAAMD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_ZZ_DAG\",\"uri\":\"data:application/octet-stream;base64,AABQPwAAAD8AAEA/AAAAPwAAUD8AABA/AABAPwAAAD8AAEA/AAAQPwAAUD8AABA/AABQPwAAED8AAFA/AAAAPwAAQD8AABA/AABAPwAAED8AAFA/AAAAPwAAQD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_II\",\"uri\":\"data:application/octet-stream;base64,AACAPwAAID8AAHA/AAAgPwAAgD8AADA/AABwPwAAID8AAHA/AAAwPwAAgD8AADA/AACAPwAAMD8AAIA/AAAgPwAAcD8AADA/AABwPwAAMD8AAIA/AAAgPwAAcD8AACA/\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_x_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzL4AAAAAAAAAAM3MzD4AAAAAAAAAAAAAAADNzMy+AAAAAAAAAADNzMw+\"},{\"byteLength\":36,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAM/MTL6sXLE+AAAAAMvMTL6tXLG+\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_E:X\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAwD4AAAA/AADAPgAAED8AAOA+AAAAPwAAwD4AAAA/AADgPgAAED8AAOA+AAAQPwAA4D4AABA/AADAPgAAAD8AAOA+AAAAPwAA4D4AABA/AADAPgAAAD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_E:Y\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAA4D4AAAA/AADgPgAAED8AAAA/AAAAPwAA4D4AAAA/AAAAPwAAED8AAAA/AAAQPwAAAD8AABA/AADgPgAAAD8AAAA/AAAAPwAAAD8AABA/AADgPgAAAD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_E:Z\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAAD8AAAA/AAAAPwAAED8AABA/AAAAPwAAAD8AAAA/AAAQPwAAED8AABA/AAAQPwAAED8AABA/AAAAPwAAAD8AABA/AAAAPwAAED8AABA/AAAAPwAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:X\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAwD4AABA/AADAPgAAID8AAOA+AAAQPwAAwD4AABA/AADgPgAAID8AAOA+AAAgPwAA4D4AACA/AADAPgAAED8AAOA+AAAQPwAA4D4AACA/AADAPgAAED8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Y\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAA4D4AABA/AADgPgAAID8AAAA/AAAQPwAA4D4AABA/AAAAPwAAID8AAAA/AAAgPwAAAD8AACA/AADgPgAAED8AAAA/AAAQPwAAAD8AACA/AADgPgAAED8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Z\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAAD8AABA/AAAAPwAAID8AABA/AAAQPwAAAD8AABA/AAAQPwAAID8AABA/AAAgPwAAED8AACA/AAAAPwAAED8AABA/AAAQPwAAED8AACA/AAAAPwAAED8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_DEPOLARIZE1\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAED8AAEA+AAAQPwAAgD4AACA/AABAPgAAED8AAEA+AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AAAQPwAAQD4AACA/AABAPgAAID8AAIA+AAAQPwAAQD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_DEPOLARIZE2\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAED8AAIA+AAAQPwAAoD4AACA/AACAPgAAED8AAIA+AAAgPwAAoD4AACA/AACgPgAAID8AAKA+AAAQPwAAgD4AACA/AACAPgAAID8AAKA+AAAQPwAAgD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_PAULI_CHANNEL_1\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAED8AAAA/AAAQPwAAED8AACA/AAAAPwAAED8AAAA/AAAgPwAAED8AACA/AAAQPwAAID8AABA/AAAQPwAAAD8AACA/AAAAPwAAID8AABA/AAAQPwAAAD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_PAULI_CHANNEL_2\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAED8AABA/AAAQPwAAID8AACA/AAAQPwAAED8AABA/AAAgPwAAID8AACA/AAAgPwAAID8AACA/AAAQPwAAED8AACA/AAAQPwAAID8AACA/AAAQPwAAED8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_X_ERROR\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAwD4AAOA+AADAPgAAAD8AAOA+AADgPgAAwD4AAOA+AADgPgAAAD8AAOA+AAAAPwAA4D4AAAA/AADAPgAA4D4AAOA+AADgPgAA4D4AAAA/AADAPgAA4D4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Y_ERROR\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAA4D4AAOA+AADgPgAAAD8AAAA/AADgPgAA4D4AAOA+AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AADgPgAA4D4AAAA/AADgPgAAAD8AAAA/AADgPgAA4D4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Z_ERROR\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAAD8AAOA+AAAAPwAAAD8AABA/AADgPgAAAD8AAOA+AAAQPwAAAD8AABA/AAAAPwAAED8AAAA/AAAAPwAA4D4AABA/AADgPgAAED8AAAA/AAAAPwAA4D4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_HERALDED_ERASE\",\"uri\":\"data:application/octet-stream;base64,AABwPwAAED8AAGA/AAAQPwAAcD8AACA/AABgPwAAED8AAGA/AAAgPwAAcD8AACA/AABwPwAAID8AAHA/AAAQPwAAYD8AACA/AABgPwAAID8AAHA/AAAQPwAAYD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_HERALDED_PAULI_CHANNEL_1\",\"uri\":\"data:application/octet-stream;base64,AACAPwAAED8AAHA/AAAQPwAAgD8AACA/AABwPwAAED8AAHA/AAAgPwAAgD8AACA/AACAPwAAID8AAIA/AAAQPwAAcD8AACA/AABwPwAAID8AAIA/AAAQPwAAcD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_I_ERROR\",\"uri\":\"data:application/octet-stream;base64,AACAPwAAAD8AAHA/AAAAPwAAgD8AABA/AABwPwAAAD8AAHA/AAAQPwAAgD8AABA/AACAPwAAED8AAIA/AAAAPwAAcD8AABA/AABwPwAAED8AAIA/AAAAPwAAcD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_II_ERROR\",\"uri\":\"data:application/octet-stream;base64,AACAPwAAMD8AAHA/AAAwPwAAgD8AAEA/AABwPwAAMD8AAHA/AABAPwAAgD8AAEA/AACAPwAAQD8AAIA/AAAwPwAAcD8AAEA/AABwPwAAQD8AAIA/AAAwPwAAcD8AADA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:X\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAwD4AACA/AADAPgAAMD8AAOA+AAAgPwAAwD4AACA/AADgPgAAMD8AAOA+AAAwPwAA4D4AADA/AADAPgAAID8AAOA+AAAgPwAA4D4AADA/AADAPgAAID8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:Y\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAA4D4AACA/AADgPgAAMD8AAAA/AAAgPwAA4D4AACA/AAAAPwAAMD8AAAA/AAAwPwAAAD8AADA/AADgPgAAID8AAAA/AAAgPwAAAD8AADA/AADgPgAAID8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:Z\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAAD8AACA/AAAAPwAAMD8AABA/AAAgPwAAAD8AACA/AAAQPwAAMD8AABA/AAAwPwAAED8AADA/AAAAPwAAID8AABA/AAAgPwAAED8AADA/AAAAPwAAID8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SPP:X\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAID8AAAAAAAAgPwAAgD0AADA/AAAAAAAAID8AAAAAAAAwPwAAgD0AADA/AACAPQAAMD8AAIA9AAAgPwAAAAAAADA/AAAAAAAAMD8AAIA9AAAgPwAAAAAAACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SPP:Y\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAID8AAIA9AAAgPwAAAD4AADA/AACAPQAAID8AAIA9AAAwPwAAAD4AADA/AAAAPgAAMD8AAAA+AAAgPwAAgD0AADA/AACAPQAAMD8AAAA+AAAgPwAAgD0AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SPP:Z\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAID8AAAA+AAAgPwAAQD4AADA/AAAAPgAAID8AAAA+AAAwPwAAQD4AADA/AABAPgAAMD8AAEA+AAAgPwAAAD4AADA/AAAAPgAAMD8AAEA+AAAgPwAAAD4AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SPP_DAG:X\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAID8AAEA+AAAgPwAAgD4AADA/AABAPgAAID8AAEA+AAAwPwAAgD4AADA/AACAPgAAMD8AAIA+AAAgPwAAQD4AADA/AABAPgAAMD8AAIA+AAAgPwAAQD4AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SPP_DAG:Y\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAID8AAIA+AAAgPwAAoD4AADA/AACAPgAAID8AAIA+AAAwPwAAoD4AADA/AACgPgAAMD8AAKA+AAAgPwAAgD4AADA/AACAPgAAMD8AAKA+AAAgPwAAgD4AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SPP_DAG:Z\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAID8AAKA+AAAgPwAAwD4AADA/AACgPgAAID8AAKA+AAAwPwAAwD4AADA/AADAPgAAMD8AAMA+AAAgPwAAoD4AADA/AACgPgAAMD8AAMA+AAAgPwAAoD4AACA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MRX\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAwD4AAMA+AADAPgAA4D4AAOA+AADAPgAAwD4AAMA+AADgPgAA4D4AAOA+AADgPgAA4D4AAOA+AADAPgAAwD4AAOA+AADAPgAA4D4AAOA+AADAPgAAwD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MRY\",\"uri\":\"data:application/octet-stream;base64,AADgPgAA4D4AAMA+AADgPgAA4D4AAAA/AADAPgAA4D4AAMA+AAAAPwAA4D4AAAA/AADgPgAAAD8AAOA+AADgPgAAwD4AAAA/AADAPgAAAD8AAOA+AADgPgAAwD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MR\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAAD8AAMA+AAAAPwAA4D4AABA/AADAPgAAAD8AAMA+AAAQPwAA4D4AABA/AADgPgAAED8AAOA+AAAAPwAAwD4AABA/AADAPgAAED8AAOA+AAAAPwAAwD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MX\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAwD4AAIA+AADAPgAAoD4AAOA+AACAPgAAwD4AAIA+AADgPgAAoD4AAOA+AACgPgAA4D4AAKA+AADAPgAAgD4AAOA+AACAPgAA4D4AAKA+AADAPgAAgD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MY\",\"uri\":\"data:application/octet-stream;base64,AACgPgAA4D4AAIA+AADgPgAAoD4AAAA/AACAPgAA4D4AAIA+AAAAPwAAoD4AAAA/AACgPgAAAD8AAKA+AADgPgAAgD4AAAA/AACAPgAAAD8AAKA+AADgPgAAgD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_M\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAAD8AAIA+AAAAPwAAoD4AABA/AACAPgAAAD8AAIA+AAAQPwAAoD4AABA/AACgPgAAED8AAKA+AAAAPwAAgD4AABA/AACAPgAAED8AAKA+AAAAPwAAgD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_RX\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAwD4AAKA+AADAPgAAwD4AAOA+AACgPgAAwD4AAKA+AADgPgAAwD4AAOA+AADAPgAA4D4AAMA+AADAPgAAoD4AAOA+AACgPgAA4D4AAMA+AADAPgAAoD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_RY\",\"uri\":\"data:application/octet-stream;base64,AADAPgAA4D4AAKA+AADgPgAAwD4AAAA/AACgPgAA4D4AAKA+AAAAPwAAwD4AAAA/AADAPgAAAD8AAMA+AADgPgAAoD4AAAA/AACgPgAAAD8AAMA+AADgPgAAoD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_R\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAAD8AAKA+AAAAPwAAwD4AABA/AACgPgAAAD8AAKA+AAAQPwAAwD4AABA/AADAPgAAED8AAMA+AAAAPwAAoD4AABA/AACgPgAAED8AAMA+AAAAPwAAoD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MXX\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAED8AACA/AAAQPwAAMD8AACA/AAAgPwAAED8AACA/AAAgPwAAMD8AACA/AAAwPwAAID8AADA/AAAQPwAAID8AACA/AAAgPwAAID8AADA/AAAQPwAAID8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MYY\",\"uri\":\"data:application/octet-stream;base64,AABAPwAAED8AADA/AAAQPwAAQD8AACA/AAAwPwAAED8AADA/AAAgPwAAQD8AACA/AABAPwAAID8AAEA/AAAQPwAAMD8AACA/AAAwPwAAID8AAEA/AAAQPwAAMD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MZZ\",\"uri\":\"data:application/octet-stream;base64,AABQPwAAED8AAEA/AAAQPwAAUD8AACA/AABAPwAAED8AAEA/AAAgPwAAUD8AACA/AABQPwAAID8AAFA/AAAQPwAAQD8AACA/AABAPwAAID8AAFA/AAAQPwAAQD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPAD\",\"uri\":\"data:application/octet-stream;base64,AABgPwAAED8AAFA/AAAQPwAAYD8AACA/AABQPwAAED8AAFA/AAAgPwAAYD8AACA/AABgPwAAID8AAGA/AAAQPwAAUD8AACA/AABQPwAAID8AAGA/AAAQPwAAUD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_X:REC\",\"uri\":\"data:application/octet-stream;base64,AABgPwAAwD4AAFA/AADAPgAAYD8AAOA+AABQPwAAwD4AAFA/AADgPgAAYD8AAOA+AABgPwAA4D4AAGA/AADAPgAAUD8AAOA+AABQPwAA4D4AAGA/AADAPgAAUD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Y:SWEEP\",\"uri\":\"data:application/octet-stream;base64,AABwPwAA4D4AAGA/AADgPgAAcD8AAAA/AABgPwAA4D4AAGA/AAAAPwAAcD8AAAA/AABwPwAAAD8AAHA/AADgPgAAYD8AAAA/AABgPwAAAD8AAHA/AADgPgAAYD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Z:REC\",\"uri\":\"data:application/octet-stream;base64,AABgPwAAAD8AAFA/AAAAPwAAYD8AABA/AABQPwAAAD8AAFA/AAAQPwAAYD8AABA/AABgPwAAED8AAGA/AAAAPwAAUD8AABA/AABQPwAAED8AAGA/AAAAPwAAUD8AAAA/\"},{\"byteLength\":1752,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAwAAAAMIAAADCAACIwAAAiMEAAIDBAACIwAAAiMEAAIDBAACAwAAAAMAAAACAAACAwAAAgMAAAACAAACAwAAAwMAAAACAAACAwAAAAMEAAACAAACAwAAAIMEAAACAAACAwAAAQMEAAACAAACAwAAAYMEAAACAAACAwAAAgMEAAACAAACAwAAAkMEAAACAAACAwAAAoMEAAACAAACAwAAAsMEAAACAAACgwAAAAMIAAADCAACowAAAiMEAAIDBAACowAAAiMEAAIDBAACgwAAAAMAAAACAAACgwAAAgMAAAACAAACgwAAAwMAAAACAAACgwAAAAMEAAACAAACgwAAAIMEAAACAAACgwAAAQMEAAACAAACgwAAAYMEAAACAAACgwAAAgMEAAACAAACgwAAAkMEAAACAAACgwAAAoMEAAACAAACgwAAAsMEAAACAAACgwAAAwMEAAACAAACgwAAA0MEAAACAAADAwAAAAMIAAADCAADIwAAAiMEAAIDBAADIwAAAiMEAAIDBAADAwAAAAMAAAACAAADAwAAAgMAAAACAAADAwAAAwMAAAACAAADAwAAAAMEAAACAAADAwAAAIMEAAACAAADAwAAAQMEAAACAAADAwAAAYMEAAACAAADAwAAAgMEAAACAAADAwAAAkMEAAACAAADAwAAAoMEAAACAAADAwAAAsMEAAACAAADAwAAAwMEAAACAAADAwAAA0MEAAACAAADAwAAA4MEAAACAAADAwAAA8MEAAACAAADAwAAAAMIAAACAAADAwAAACMIAAACAAADgwAAAgMAAAACAAADgwAAAAMAAAACAAADgwAAAwMAAAACAAADgwAAAgMAAAACAAADgwAAAYMEAAACAAADowAAAMMEAAACAAADowAAAMMEAAACAAADgwAAAAMEAAACAAADgwAAAQMEAAACAAADgwAAAYMEAAACAAAAAwQAAAMAAAACAAAAAwQAAgMAAAACAAAAAwQAAAMEAAACAAAAAwQAAIMEAAACAAAAQwQAAgMEAAACAAAAQwQAAkMEAAACAAAAgwQAAAMAAAACAAAAkwQAAiMEAAIDBAAAkwQAAiMEAAIDBAAAgwQAAAMIAAADCAAAgwQAAgMAAAACAAAAgwQAAAMAAAACAAAAwwQAAAMAAAACAAAA0wQAAiMEAAIDBAAA0wQAAiMEAAIDBAAAwwQAAAMIAAADCAABAwQAAAMAAAACAAABEwQAAiMEAAIDBAABEwQAAiMEAAIDBAABAwQAAAMIAAADCAABAwQAAgMAAAACAAABAwQAAAMAAAACAAABQwQAAAMAAAACAAABUwQAAiMEAAIDBAABUwQAAiMEAAIDBAABQwQAAAMIAAADCAABQwQAAgMAAAACAAABQwQAAAMAAAACAAACAwQAAAMIAAADCAACCwQAAiMEAAIDBAACCwQAAiMEAAIDBAACAwQAAAMAAAACAAACAwQAAgMAAAACAAACAwQAAwMAAAACAAACAwQAAAMEAAACAAACAwQAAIMEAAACAAACAwQAAQMEAAACAAACAwQAAYMEAAACAAACYwQAAAMIAAADCAACawQAAiMEAAIDBAACawQAAiMEAAIDBAACYwQAAAMAAAACAAADgwQAAgMAAAACAAADgwQAAwMAAAACAAADgwQAAAMEAAACAAADgwQAAIMEAAACAAADgwQAAYMEAAACAAADgwQAAQMEAAACAAADgwQAAgMEAAACAAADgwQAAYMEAAACAAACAPwAAAMIAAADCAADwwQAAAMIAAADCAACAPwAAAMAAAACAAADwwQAAAMAAAACAAACAPwAAgMAAAACAAADwwQAAgMAAAACAAACAPwAAwMAAAACAAADwwQAAwMAAAACAAACAPwAAAMEAAACAAADwwQAAAMEAAACAAACAPwAAIMEAAACAAADwwQAAIMEAAACAAACAPwAAQMEAAACAAADwwQAAQMEAAACAAACAPwAAYMEAAACAAADwwQAAYMEAAACAAACAPwAAgMEAAACAAADwwQAAgMEAAACAAACAPwAAkMEAAACAAADwwQAAkMEAAACAAACAPwAAoMEAAACAAADwwQAAoMEAAACAAACAPwAAsMEAAACAAADwwQAAsMEAAACAAACAPwAAwMEAAACAAADwwQAAwMEAAACAAACAPwAA0MEAAACAAADwwQAA0MEAAACAAACAPwAA4MEAAACAAADwwQAA4MEAAACAAACAPwAA8MEAAACAAADwwQAA8MEAAACAAACAPwAAAMIAAACAAADwwQAAAMIAAACAAACAPwAACMIAAACAAADwwQAACMIAAACA\"},{\"byteLength\":360,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAIAAAIDBAABAwAAAAIAAAIDBAAAgwAAAAL8AAIDBAABAwAAAAIAAAIDBAAAgwAAAAD8AAIDBAABAwAAAAIAAAIDBAACOwQAAgL8AAIA/AACOwQAAgL8AAATCAACOwQAAgL8AAIA/AACOwQAADMIAAIA/AACOwQAAgL8AAIA/AACqwQAAgL8AAIA/AACOwQAAgL8AAATCAACOwQAADMIAAATCAACOwQAAgL8AAATCAACqwQAAgL8AAATCAACOwQAADMIAAIA/AACOwQAADMIAAATCAACOwQAADMIAAIA/AACqwQAADMIAAIA/AACOwQAADMIAAATCAACqwQAADMIAAATCAACqwQAAgL8AAIA/AACqwQAAgL8AAATCAACqwQAAgL8AAIA/AACqwQAADMIAAIA/AACqwQAAgL8AAATCAACqwQAADMIAAATCAACqwQAADMIAAIA/AACqwQAADMIAAATC\"},{\"byteLength\":1152,\"name\":\"buf_blue_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AABAv83MzL8AAAA/AABAv5qZmb8AAAA/AABAv83MzL8AAALCAABAv5qZmb8AAALCAABAv5qZmb8AAAA/AABAv5qZmb8AAALCAABAv5qZmb8AAAA/AABQwJqZmb8AAAA/AABAv5qZmb8AAALCAABQwJqZmb8AAALCAABQwM3MzL8AAAA/AABQwJqZmb8AAAA/AABQwM3MzL8AAALCAABQwJqZmb8AAALCAABQwJqZmb8AAAA/AABQwJqZmb8AAALCAABwwM3MzL8AAAA/AABwwJqZmb8AAAA/AABwwM3MzL8AAALCAABwwJqZmb8AAALCAABwwJqZmb8AAAA/AABwwJqZmb8AAALCAABwwJqZmb8AAAA/AADIwJqZmb8AAAA/AABwwJqZmb8AAALCAADIwJqZmb8AAALCAADIwM3MzL8AAAA/AADIwJqZmb8AAAA/AADIwM3MzL8AAALCAADIwJqZmb8AAALCAADIwJqZmb8AAAA/AADIwJqZmb8AAALCAADYwM3MzL8AAAA/AADYwJqZmb8AAAA/AADYwM3MzL8AAALCAADYwJqZmb8AAALCAADYwJqZmb8AAAA/AADYwJqZmb8AAALCAADYwJqZmb8AAAA/AAAUwZqZmb8AAAA/AADYwJqZmb8AAALCAAAUwZqZmb8AAALCAAAUwc3MzL8AAAA/AAAUwZqZmb8AAAA/AAAUwc3MzL8AAALCAAAUwZqZmb8AAALCAAAUwZqZmb8AAAA/AAAUwZqZmb8AAALCAAAcwc3MzL8AAAA/AAAcwZqZmb8AAAA/AAAcwc3MzL8AAALCAAAcwZqZmb8AAALCAAAcwZqZmb8AAAA/AAAcwZqZmb8AAALCAAAcwZqZmb8AAAA/AABkwZqZmb8AAAA/AAAcwZqZmb8AAALCAABkwZqZmb8AAALCAABkwc3MzL8AAAA/AABkwZqZmb8AAAA/AABkwc3MzL8AAALCAABkwZqZmb8AAALCAABkwZqZmb8AAAA/AABkwZqZmb8AAALCAACOwc3MzL8AAAA/AACOwZqZmb8AAAA/AACOwc3MzL8AAALCAACOwZqZmb8AAALCAACOwZqZmb8AAAA/AACOwZqZmb8AAALCAACOwZqZmb8AAAA/AACiwZqZmb8AAAA/AACOwZqZmb8AAALCAACiwZqZmb8AAALCAACiwc3MzL8AAAA/AACiwZqZmb8AAAA/AACiwc3MzL8AAALCAACiwZqZmb8AAALCAACiwZqZmb8AAAA/AACiwZqZmb8AAALCAAC2wc3MzL8AAAA/AAC2wZqZmb8AAAA/AAC2wc3MzL8AAALCAAC2wZqZmb8AAALCAAC2wZqZmb8AAAA/AAC2wZqZmb8AAALCAAC2wZqZmb8AAAA/AADawZqZmb8AAAA/AAC2wZqZmb8AAALCAADawZqZmb8AAALCAADawc3MzL8AAAA/AADawZqZmb8AAAA/AADawc3MzL8AAALCAADawZqZmb8AAALCAADawZqZmb8AAAA/AADawZqZmb8AAALC\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0.5,0.5,0.5,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,1,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":4},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":5},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":6},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":7},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":8},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":9},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":10},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":11},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":12},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":13},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":14},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":15},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":16},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":17},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":18},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":19},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":20},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":21},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":22},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":23},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":24},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":25},\"material\":1,\"mode\":6},{\"attributes\":{\"POSITION\":26},\"material\":2,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":27},\"material\":3,\"mode\":6},{\"attributes\":{\"POSITION\":27},\"material\":4,\"mode\":3},{\"attributes\":{\"POSITION\":28},\"material\":4,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":29},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":30},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":31},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":32},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":33},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":34},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":35},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":36},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":37},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":38},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":39},\"material\":5,\"mode\":6},{\"attributes\":{\"POSITION\":39},\"material\":6,\"mode\":3},{\"attributes\":{\"POSITION\":40},\"material\":6,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":41},\"material\":7,\"mode\":2},{\"attributes\":{\"POSITION\":41},\"material\":8,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":42},\"material\":9,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":43},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":44},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":45},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":46},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":47},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":48},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":49},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":50},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":51},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":52},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":53},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":54},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":55},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":56},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":57},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":58},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":59},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":60},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":61},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":62},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":63},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":64},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":65},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":66},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":67},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":68},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":69},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":70},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":71},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":72},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":73},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":74},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":75},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":76},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":77},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":78},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":79},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":80},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":81},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":82},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":83},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":84},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":85},\"material\":10,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":86},\"material\":11,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":87},\"material\":12,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-32,-32]},{\"mesh\":1,\"translation\":[-0,-2,-0]},{\"mesh\":2,\"translation\":[-0,-4,-0]},{\"mesh\":3,\"translation\":[-0,-6,-0]},{\"mesh\":4,\"translation\":[-1,-32,-32]},{\"mesh\":5,\"translation\":[-1,-2,-0]},{\"mesh\":6,\"translation\":[-1,-4,-0]},{\"mesh\":7,\"translation\":[-1,-6,-0]},{\"mesh\":8,\"translation\":[-1,-8,-0]},{\"mesh\":9,\"translation\":[-1,-10,-0]},{\"mesh\":10,\"translation\":[-1,-12,-0]},{\"mesh\":11,\"translation\":[-1,-14,-0]},{\"mesh\":12,\"translation\":[-2,-32,-32]},{\"mesh\":13,\"translation\":[-2,-2,-0]},{\"mesh\":14,\"translation\":[-2,-4,-0]},{\"mesh\":15,\"translation\":[-2,-6,-0]},{\"mesh\":16,\"translation\":[-2,-8,-0]},{\"mesh\":17,\"translation\":[-2,-10,-0]},{\"mesh\":18,\"translation\":[-3,-32,-32]},{\"mesh\":19,\"translation\":[-3,-2,-0]},{\"mesh\":20,\"translation\":[-3,-4,-0]},{\"mesh\":21,\"translation\":[-3,-6,-0]},{\"mesh\":22,\"translation\":[-3,-8,-0]},{\"mesh\":23,\"translation\":[-3,-10,-0]},{\"mesh\":24,\"translation\":[-4,-32,-32]},{\"mesh\":25,\"translation\":[-4,-2,-0]},{\"mesh\":26,\"translation\":[-4,-4,-0]},{\"mesh\":26,\"translation\":[-4,-6,-0]},{\"mesh\":27,\"translation\":[-4,-8,-0]},{\"mesh\":27,\"translation\":[-4,-10,-0]},{\"mesh\":28,\"translation\":[-4,-12,-0]},{\"mesh\":28,\"translation\":[-4,-14,-0]},{\"mesh\":25,\"translation\":[-4,-16,-0]},{\"mesh\":24,\"translation\":[-4,-18,-0]},{\"mesh\":24,\"translation\":[-4,-20,-0]},{\"mesh\":24,\"translation\":[-4,-22,-0]},{\"mesh\":29,\"translation\":[-5,-32,-32]},{\"mesh\":29,\"translation\":[-5,-2,-0]},{\"mesh\":30,\"translation\":[-5,-4,-0]},{\"mesh\":30,\"translation\":[-5,-6,-0]},{\"mesh\":31,\"translation\":[-5,-8,-0]},{\"mesh\":31,\"translation\":[-5,-10,-0]},{\"mesh\":32,\"translation\":[-5,-12,-0]},{\"mesh\":32,\"translation\":[-5,-14,-0]},{\"mesh\":33,\"translation\":[-5,-16,-0]},{\"mesh\":33,\"translation\":[-5,-18,-0]},{\"mesh\":34,\"translation\":[-5,-20,-0]},{\"mesh\":34,\"translation\":[-5,-22,-0]},{\"mesh\":35,\"translation\":[-5,-24,-0]},{\"mesh\":35,\"translation\":[-5,-26,-0]},{\"mesh\":36,\"translation\":[-6,-32,-32]},{\"mesh\":36,\"translation\":[-6,-2,-0]},{\"mesh\":36,\"translation\":[-6,-4,-0]},{\"mesh\":37,\"translation\":[-6,-6,-0]},{\"mesh\":36,\"translation\":[-6,-8,-0]},{\"mesh\":38,\"translation\":[-6,-10,-0]},{\"mesh\":37,\"translation\":[-6,-12,-0]},{\"mesh\":36,\"translation\":[-6,-14,-0]},{\"mesh\":37,\"translation\":[-6,-16,-0]},{\"mesh\":37,\"translation\":[-6,-18,-0]},{\"mesh\":37,\"translation\":[-6,-20,-0]},{\"mesh\":38,\"translation\":[-6,-22,-0]},{\"mesh\":38,\"translation\":[-6,-24,-0]},{\"mesh\":36,\"translation\":[-6,-26,-0]},{\"mesh\":38,\"translation\":[-6,-28,-0]},{\"mesh\":37,\"translation\":[-6,-30,-0]},{\"mesh\":38,\"translation\":[-6,-32,-0]},{\"mesh\":38,\"translation\":[-6,-34,-0]},{\"mesh\":39,\"translation\":[-7,-2,-0]},{\"mesh\":40,\"translation\":[-7,-4,-0]},{\"mesh\":41,\"translation\":[-7,-6,-0]},{\"mesh\":42,\"translation\":[-7,-8,-0]},{\"mesh\":43,\"translation\":[-7,-14,-0]},{\"mesh\":44,\"translation\":[-7,-12,-0]},{\"mesh\":45,\"translation\":[-7,-32,-32]},{\"mesh\":46,\"translation\":[-8,-2,-0]},{\"mesh\":46,\"translation\":[-8,-4,-0]},{\"mesh\":47,\"translation\":[-8,-6,-0]},{\"mesh\":48,\"translation\":[-8,-8,-0]},{\"mesh\":48,\"translation\":[-8,-10,-0]},{\"mesh\":49,\"translation\":[-8,-32,-32]},{\"mesh\":50,\"translation\":[-9,-2,-0]},{\"mesh\":51,\"translation\":[-9,-4,-0]},{\"mesh\":52,\"translation\":[-9,-6,-0]},{\"mesh\":53,\"translation\":[-9,-12,-0]},{\"mesh\":54,\"translation\":[-9,-14,-0]},{\"mesh\":55,\"translation\":[-9,-16,-0]},{\"mesh\":55,\"translation\":[-9,-18,-0]},{\"mesh\":56,\"translation\":[-10,-32,-32]},{\"mesh\":57,\"translation\":[-10,-2,-0]},{\"mesh\":58,\"translation\":[-10,-4,-0]},{\"mesh\":58,\"translation\":[-11,-32,-32]},{\"mesh\":58,\"translation\":[-11,-2,-0]},{\"mesh\":59,\"translation\":[-12,-32,-32]},{\"mesh\":60,\"translation\":[-12,-2,-0]},{\"mesh\":61,\"translation\":[-12,-4,-0]},{\"mesh\":59,\"translation\":[-12,-6,-0]},{\"mesh\":62,\"translation\":[-13,-32,-32]},{\"mesh\":63,\"translation\":[-13,-2,-0]},{\"mesh\":64,\"translation\":[-13,-4,-0]},{\"mesh\":62,\"translation\":[-14,-4,-0]},{\"mesh\":65,\"translation\":[-15,-32,-32]},{\"mesh\":66,\"translation\":[-15,-2,-0]},{\"mesh\":67,\"translation\":[-15,-4,-0]},{\"mesh\":68,\"translation\":[-15,-6,-0]},{\"mesh\":69,\"translation\":[-15,-8,-0]},{\"mesh\":70,\"translation\":[-15,-10,-0]},{\"mesh\":70,\"translation\":[-15,-12,-0]},{\"mesh\":71,\"translation\":[-15,-14,-0]},{\"mesh\":72,\"translation\":[-15,-16,-0]},{\"mesh\":73,\"translation\":[-15,-18,-0]},{\"mesh\":74,\"translation\":[-16,-32,-32]},{\"mesh\":74,\"translation\":[-16,-2,-0]},{\"mesh\":74,\"translation\":[-16,-4,-0]},{\"mesh\":74,\"translation\":[-16,-6,-0]},{\"mesh\":75,\"translation\":[-16,-8,-0]},{\"mesh\":75,\"translation\":[-16,-10,-0]},{\"mesh\":76,\"translation\":[-16,-12,-0]},{\"mesh\":76,\"translation\":[-16,-14,-0]},{\"mesh\":13,\"translation\":[-18,-32,-32]},{\"mesh\":38,\"translation\":[-19,-32,-32]},{\"mesh\":36,\"translation\":[-19,-2,-0]},{\"mesh\":22,\"translation\":[-20,-2,-0]},{\"mesh\":67,\"translation\":[-23,-32,-32]},{\"mesh\":49,\"translation\":[-24,-32,-32]},{\"mesh\":67,\"translation\":[-25,-32,-32]},{\"mesh\":77,\"translation\":[-26,-32,-32]},{\"mesh\":77,\"translation\":[-26,-2,-0]},{\"mesh\":77,\"translation\":[-27,-32,-32]},{\"mesh\":65,\"translation\":[-28,-32,-32]},{\"mesh\":69,\"translation\":[-28,-2,-0]},{\"mesh\":76,\"translation\":[-28,-4,-0]},{\"mesh\":76,\"translation\":[-28,-6,-0]},{\"mesh\":75,\"translation\":[-28,-8,-0]},{\"mesh\":75,\"translation\":[-28,-10,-0]},{\"mesh\":56,\"translation\":[-28,-12,-0]},{\"mesh\":57,\"translation\":[-28,-14,-0]},{\"mesh\":58,\"translation\":[-28,-16,-0]},{\"mesh\":78,\"translation\":[-29,-32,-32]},{\"mesh\":79,\"translation\":[-29,-2,-0]},{\"mesh\":80,\"translation\":[-29,-4,-0]},{\"mesh\":81,\"translation\":[0,0,0]},{\"mesh\":82,\"translation\":[0,0,0]},{\"mesh\":83,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/classical_feedback.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5625],\"min\":[0.25,0.5],\"name\":\"tex_coords_gate_M\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.875,0.4375],\"min\":[0.8125,0.375],\"name\":\"tex_coords_gate_X:REC\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.9375,0.5],\"min\":[0.875,0.4375],\"name\":\"tex_coords_gate_Y:SWEEP\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":6,\"max\":[1,-0,-0],\"min\":[-1,-4,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":6,\"max\":[0,2.5,-0],\"min\":[-3,1.5,-0],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_M\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_X:REC\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Y:SWEEP\",\"target\":34962},{\"buffer\":4,\"byteLength\":72,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":5,\"byteLength\":72,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_M\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAAD8AAIA+AAAAPwAAoD4AABA/AACAPgAAAD8AAIA+AAAQPwAAoD4AABA/AACgPgAAED8AAKA+AAAAPwAAgD4AABA/AACAPgAAED8AAKA+AAAAPwAAgD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_X:REC\",\"uri\":\"data:application/octet-stream;base64,AABgPwAAwD4AAFA/AADAPgAAYD8AAOA+AABQPwAAwD4AAFA/AADgPgAAYD8AAOA+AABgPwAA4D4AAGA/AADAPgAAUD8AAOA+AABQPwAA4D4AAGA/AADAPgAAUD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Y:SWEEP\",\"uri\":\"data:application/octet-stream;base64,AABwPwAA4D4AAGA/AADgPgAAcD8AAAA/AABgPwAA4D4AAGA/AAAAPwAAcD8AAAA/AABwPwAAAD8AAHA/AADgPgAAYD8AAAA/AABgPwAAAD8AAHA/AADgPgAAYD8AAOA+\"},{\"byteLength\":72,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAPwAAAIAAAACAAACAvwAAAIAAAACAAACAPwAAAMAAAACAAACAvwAAAMAAAACAAACAPwAAgMAAAACAAACAvwAAgMAAAACA\"},{\"byteLength\":72,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACA\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":5},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":1,\"translation\":[-0,-2,-0]},{\"mesh\":2,\"translation\":[-0,-4,-0]},{\"mesh\":3,\"translation\":[0,0,0]},{\"mesh\":4,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/collapsing.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.5625],\"min\":[0.3125,0.5],\"name\":\"tex_coords_gate_R\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.4375],\"min\":[0.3125,0.375],\"name\":\"tex_coords_gate_RX\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.5],\"min\":[0.3125,0.4375],\"name\":\"tex_coords_gate_RY\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5625],\"min\":[0.25,0.5],\"name\":\"tex_coords_gate_M\",\"type\":\"VEC2\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.5625],\"min\":[0.375,0.5],\"name\":\"tex_coords_gate_MR\",\"type\":\"VEC2\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.4375],\"min\":[0.375,0.375],\"name\":\"tex_coords_gate_MRX\",\"type\":\"VEC2\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.5],\"min\":[0.375,0.4375],\"name\":\"tex_coords_gate_MRY\",\"type\":\"VEC2\"},{\"bufferView\":8,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.4375],\"min\":[0.25,0.375],\"name\":\"tex_coords_gate_MX\",\"type\":\"VEC2\"},{\"bufferView\":9,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5],\"min\":[0.25,0.4375],\"name\":\"tex_coords_gate_MY\",\"type\":\"VEC2\"},{\"bufferView\":10,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.4375],\"min\":[0.625,0.375],\"name\":\"tex_coords_gate_MPP:X\",\"type\":\"VEC2\"},{\"bufferView\":11,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.5],\"min\":[0.625,0.4375],\"name\":\"tex_coords_gate_MPP:Y\",\"type\":\"VEC2\"},{\"bufferView\":12,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.5625],\"min\":[0.625,0.5],\"name\":\"tex_coords_gate_MPP:Z\",\"type\":\"VEC2\"},{\"bufferView\":13,\"byteOffset\":0,\"componentType\":5126,\"count\":14,\"max\":[1,-0,-0],\"min\":[-8,-6,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":14,\"byteOffset\":0,\"componentType\":5126,\"count\":6,\"max\":[0,2.5,-0],\"min\":[-3,1.5,-0],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_R\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_RX\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_RY\",\"target\":34962},{\"buffer\":4,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_M\",\"target\":34962},{\"buffer\":5,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MR\",\"target\":34962},{\"buffer\":6,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MRX\",\"target\":34962},{\"buffer\":7,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MRY\",\"target\":34962},{\"buffer\":8,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MX\",\"target\":34962},{\"buffer\":9,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MY\",\"target\":34962},{\"buffer\":10,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:X\",\"target\":34962},{\"buffer\":11,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:Y\",\"target\":34962},{\"buffer\":12,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:Z\",\"target\":34962},{\"buffer\":13,\"byteLength\":168,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":14,\"byteLength\":72,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_R\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAAD8AAKA+AAAAPwAAwD4AABA/AACgPgAAAD8AAKA+AAAQPwAAwD4AABA/AADAPgAAED8AAMA+AAAAPwAAoD4AABA/AACgPgAAED8AAMA+AAAAPwAAoD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_RX\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAwD4AAKA+AADAPgAAwD4AAOA+AACgPgAAwD4AAKA+AADgPgAAwD4AAOA+AADAPgAA4D4AAMA+AADAPgAAoD4AAOA+AACgPgAA4D4AAMA+AADAPgAAoD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_RY\",\"uri\":\"data:application/octet-stream;base64,AADAPgAA4D4AAKA+AADgPgAAwD4AAAA/AACgPgAA4D4AAKA+AAAAPwAAwD4AAAA/AADAPgAAAD8AAMA+AADgPgAAoD4AAAA/AACgPgAAAD8AAMA+AADgPgAAoD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_M\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAAD8AAIA+AAAAPwAAoD4AABA/AACAPgAAAD8AAIA+AAAQPwAAoD4AABA/AACgPgAAED8AAKA+AAAAPwAAgD4AABA/AACAPgAAED8AAKA+AAAAPwAAgD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MR\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAAD8AAMA+AAAAPwAA4D4AABA/AADAPgAAAD8AAMA+AAAQPwAA4D4AABA/AADgPgAAED8AAOA+AAAAPwAAwD4AABA/AADAPgAAED8AAOA+AAAAPwAAwD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MRX\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAwD4AAMA+AADAPgAA4D4AAOA+AADAPgAAwD4AAMA+AADgPgAA4D4AAOA+AADgPgAA4D4AAOA+AADAPgAAwD4AAOA+AADAPgAA4D4AAOA+AADAPgAAwD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MRY\",\"uri\":\"data:application/octet-stream;base64,AADgPgAA4D4AAMA+AADgPgAA4D4AAAA/AADAPgAA4D4AAMA+AAAAPwAA4D4AAAA/AADgPgAAAD8AAOA+AADgPgAAwD4AAAA/AADAPgAAAD8AAOA+AADgPgAAwD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MX\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAwD4AAIA+AADAPgAAoD4AAOA+AACAPgAAwD4AAIA+AADgPgAAoD4AAOA+AACgPgAA4D4AAKA+AADAPgAAgD4AAOA+AACAPgAA4D4AAKA+AADAPgAAgD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MY\",\"uri\":\"data:application/octet-stream;base64,AACgPgAA4D4AAIA+AADgPgAAoD4AAAA/AACAPgAA4D4AAIA+AAAAPwAAoD4AAAA/AACgPgAAAD8AAKA+AADgPgAAgD4AAAA/AACAPgAAAD8AAKA+AADgPgAAgD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:X\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAwD4AACA/AADAPgAAMD8AAOA+AAAgPwAAwD4AACA/AADgPgAAMD8AAOA+AAAwPwAA4D4AADA/AADAPgAAID8AAOA+AAAgPwAA4D4AADA/AADAPgAAID8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:Y\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAA4D4AACA/AADgPgAAMD8AAAA/AAAgPwAA4D4AACA/AAAAPwAAMD8AAAA/AAAwPwAAAD8AADA/AADgPgAAID8AAAA/AAAgPwAAAD8AADA/AADgPgAAID8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:Z\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAAD8AACA/AAAAPwAAMD8AABA/AAAgPwAAAD8AACA/AAAQPwAAMD8AABA/AAAwPwAAED8AADA/AAAAPwAAID8AABA/AAAgPwAAED8AADA/AAAAPwAAID8AAAA/\"},{\"byteLength\":168,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AADAwAAAgMAAAACAAADIwAAAAMAAAACAAADIwAAAAMAAAACAAADAwAAAAIAAAACAAADgwAAAwMAAAACAAADgwAAAgMAAAACAAACAPwAAAIAAAACAAAAAwQAAAIAAAACAAACAPwAAAMAAAACAAAAAwQAAAMAAAACAAACAPwAAgMAAAACAAAAAwQAAgMAAAACAAACAPwAAwMAAAACAAAAAwQAAwMAAAACA\"},{\"byteLength\":72,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACA\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":4},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":5},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":6},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":7},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":8},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":9},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":10},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":11},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":12},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":13},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":14},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":1,\"translation\":[-0,-2,-0]},{\"mesh\":2,\"translation\":[-0,-4,-0]},{\"mesh\":0,\"translation\":[-0,-6,-0]},{\"mesh\":3,\"translation\":[-1,-0,-0]},{\"mesh\":3,\"translation\":[-1,-2,-0]},{\"mesh\":4,\"translation\":[-2,-2,-0]},{\"mesh\":4,\"translation\":[-2,-0,-0]},{\"mesh\":5,\"translation\":[-3,-2,-0]},{\"mesh\":5,\"translation\":[-3,-4,-0]},{\"mesh\":6,\"translation\":[-3,-0,-0]},{\"mesh\":6,\"translation\":[-3,-6,-0]},{\"mesh\":6,\"translation\":[-4,-2,-0]},{\"mesh\":4,\"translation\":[-4,-0,-0]},{\"mesh\":7,\"translation\":[-5,-2,-0]},{\"mesh\":8,\"translation\":[-5,-4,-0]},{\"mesh\":3,\"translation\":[-5,-6,-0]},{\"mesh\":9,\"translation\":[-6,-0,-0]},{\"mesh\":10,\"translation\":[-6,-4,-0]},{\"mesh\":11,\"translation\":[-6,-6,-0]},{\"mesh\":9,\"translation\":[-6,-2,-0]},{\"mesh\":11,\"translation\":[-7,-4,-0]},{\"mesh\":10,\"translation\":[-7,-6,-0]},{\"mesh\":12,\"translation\":[0,0,0]},{\"mesh\":13,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/detector_pseudo_targets.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5625],\"min\":[0.25,0.5],\"name\":\"tex_coords_gate_M\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[1,-0,-0],\"min\":[-3,-10,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":30,\"max\":[0,2.5,1],\"min\":[-3,-11,-1],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_M\",\"target\":34962},{\"buffer\":2,\"byteLength\":144,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":3,\"byteLength\":360,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_M\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAAD8AAIA+AAAAPwAAoD4AABA/AACAPgAAAD8AAIA+AAAQPwAAoD4AABA/AACgPgAAED8AAKA+AAAAPwAAgD4AABA/AACAPgAAED8AAKA+AAAAPwAAgD4AAAA/\"},{\"byteLength\":144,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAPwAAAIAAAACAAABAwAAAAIAAAACAAACAPwAAAMAAAACAAABAwAAAAMAAAACAAACAPwAAgMAAAACAAABAwAAAgMAAAACAAACAPwAAwMAAAACAAABAwAAAwMAAAACAAACAPwAAAMEAAACAAABAwAAAAMEAAACAAACAPwAAIMEAAACAAABAwAAAIMEAAACA\"},{\"byteLength\":360,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACAAABAvwAAgD8AAIA/AABAvwAAgD8AAIC/AABAvwAAgD8AAIA/AABAvwAAMMEAAIA/AABAvwAAgD8AAIA/AACgvwAAgD8AAIA/AABAvwAAgD8AAIC/AABAvwAAMMEAAIC/AABAvwAAgD8AAIC/AACgvwAAgD8AAIC/AABAvwAAMMEAAIA/AABAvwAAMMEAAIC/AABAvwAAMMEAAIA/AACgvwAAMMEAAIA/AABAvwAAMMEAAIC/AACgvwAAMMEAAIC/AACgvwAAgD8AAIA/AACgvwAAgD8AAIC/AACgvwAAgD8AAIA/AACgvwAAMMEAAIA/AACgvwAAgD8AAIC/AACgvwAAMMEAAIC/AACgvwAAMMEAAIA/AACgvwAAMMEAAIC/\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":2},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":0,\"translation\":[-0,-2,-0]},{\"mesh\":0,\"translation\":[-0,-4,-0]},{\"mesh\":0,\"translation\":[-0,-6,-0]},{\"mesh\":0,\"translation\":[-0,-8,-0]},{\"mesh\":0,\"translation\":[-0,-10,-0]},{\"mesh\":0,\"translation\":[-1,-2,-0]},{\"mesh\":0,\"translation\":[-1,-4,-0]},{\"mesh\":1,\"translation\":[0,0,0]},{\"mesh\":2,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/empty_match_graph.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":32,\"max\":[8,2,0],\"min\":[0,-1,0],\"name\":\"buf_blue_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":384,\"byteOffset\":0,\"name\":\"buf_blue_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":384,\"name\":\"buf_blue_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAAAAACAPwAAAEAAAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAQAAAgD8AAAAAAABAQAAAgD8AAAAAAAAAQAAAAAAAAAAAAAAAQAAAgD8AAAAAAAAgQAAAAAAAAAAAAAAgQAAAgD8AAAAAAABAQAAAAAAAAAAAAABAQAAAgD8AAAAAAACAQAAAgD8AAAAAAACAQAAAgL8AAAAAAACAQAAAgD8AAAAAAACgQAAAgD8AAAAAAACgQAAAgD8AAAAAAACgQAAAAAAAAAAAAACAQAAAAAAAAAAAAACgQAAAAAAAAAAAAADAQAAAAAAAAAAAAADAQAAAAEAAAAAAAACwQAAAwD8AAAAAAADQQAAAwD8AAAAAAADgQAAAgL8AAAAAAAAAQQAAgD8AAAAAAADgQAAAgD8AAAAAAADwQAAAAAAAAAAA\"}],\"materials\":[{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0},\"material\":0,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[0,0,0]}],\"scene\":0,\"scenes\":[{\"nodes\":[0]}]}"
  },
  {
    "path": "testdata/lattice_surgery_cnot.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.5625],\"min\":[0.3125,0.5],\"name\":\"tex_coords_gate_R\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.4375],\"min\":[0.625,0.375],\"name\":\"tex_coords_gate_MPP:X\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.5625],\"min\":[0.625,0.5],\"name\":\"tex_coords_gate_MPP:Z\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.4375],\"min\":[0.25,0.375],\"name\":\"tex_coords_gate_MX\",\"type\":\"VEC2\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.875,0.5625],\"min\":[0.8125,0.5],\"name\":\"tex_coords_gate_Z:REC\",\"type\":\"VEC2\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.875,0.4375],\"min\":[0.8125,0.375],\"name\":\"tex_coords_gate_X:REC\",\"type\":\"VEC2\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[1,-0,-0],\"min\":[-5,-4,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":8,\"byteOffset\":0,\"componentType\":5126,\"count\":6,\"max\":[0,2.5,-0],\"min\":[-3,1.5,-0],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_R\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:X\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:Z\",\"target\":34962},{\"buffer\":4,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MX\",\"target\":34962},{\"buffer\":5,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Z:REC\",\"target\":34962},{\"buffer\":6,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_X:REC\",\"target\":34962},{\"buffer\":7,\"byteLength\":144,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":8,\"byteLength\":72,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_R\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAAD8AAKA+AAAAPwAAwD4AABA/AACgPgAAAD8AAKA+AAAQPwAAwD4AABA/AADAPgAAED8AAMA+AAAAPwAAoD4AABA/AACgPgAAED8AAMA+AAAAPwAAoD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:X\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAwD4AACA/AADAPgAAMD8AAOA+AAAgPwAAwD4AACA/AADgPgAAMD8AAOA+AAAwPwAA4D4AADA/AADAPgAAID8AAOA+AAAgPwAA4D4AADA/AADAPgAAID8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:Z\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAAD8AACA/AAAAPwAAMD8AABA/AAAgPwAAAD8AACA/AAAQPwAAMD8AABA/AAAwPwAAED8AADA/AAAAPwAAID8AABA/AAAgPwAAED8AADA/AAAAPwAAID8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MX\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAwD4AAIA+AADAPgAAoD4AAOA+AACAPgAAwD4AAIA+AADgPgAAoD4AAOA+AACgPgAA4D4AAKA+AADAPgAAgD4AAOA+AACAPgAA4D4AAKA+AADAPgAAgD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Z:REC\",\"uri\":\"data:application/octet-stream;base64,AABgPwAAAD8AAFA/AAAAPwAAYD8AABA/AABQPwAAAD8AAFA/AAAQPwAAYD8AABA/AABgPwAAED8AAGA/AAAAPwAAUD8AABA/AABQPwAAED8AAGA/AAAAPwAAUD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_X:REC\",\"uri\":\"data:application/octet-stream;base64,AABgPwAAwD4AAFA/AADAPgAAYD8AAOA+AABQPwAAwD4AAFA/AADgPgAAYD8AAOA+AABgPwAA4D4AAGA/AADAPgAAUD8AAOA+AABQPwAA4D4AAGA/AADAPgAAUD8AAMA+\"},{\"byteLength\":144,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAvwAAgMAAAACAAACAvwAAAMAAAACAAAAAwAAAgMAAAACAAAAQwAAAAMAAAACAAAAQwAAAAMAAAACAAAAAwAAAAIAAAACAAACAPwAAAIAAAACAAACgwAAAAIAAAACAAACAPwAAAMAAAACAAACgwAAAAMAAAACAAACAPwAAgMAAAACAAACgwAAAgMAAAACA\"},{\"byteLength\":72,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACA\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":4},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":5},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":6},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":7},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":8},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-4,-0]},{\"mesh\":1,\"translation\":[-1,-2,-0]},{\"mesh\":1,\"translation\":[-1,-4,-0]},{\"mesh\":2,\"translation\":[-2,-0,-0]},{\"mesh\":2,\"translation\":[-2,-4,-0]},{\"mesh\":3,\"translation\":[-3,-4,-0]},{\"mesh\":4,\"translation\":[-3,-0,-0]},{\"mesh\":5,\"translation\":[-3,-2,-0]},{\"mesh\":4,\"translation\":[-4,-0,-0]},{\"mesh\":6,\"translation\":[0,0,0]},{\"mesh\":7,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/match_graph_no_coords.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0,0.400000005960464],\"min\":[-0.400000005960464,0,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0.400000005960464,0],\"min\":[-0.400000005960464,-0.400000005960464,0],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0,0.400000005960464],\"min\":[-0.400000005960464,0,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0.400000005960464,0],\"min\":[-0.400000005960464,-0.400000005960464,0],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":18,\"max\":[9,14.9442720413208,-1],\"min\":[-1.4721360206604,0,-1],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":2,\"max\":[0,0,-1],\"min\":[-8.32050228118896,-5.54700183868408,-1],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":1,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":2,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":3,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":4,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":5,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":6,\"byteLength\":216,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":7,\"byteLength\":24,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAMPQkD7D0JA+AAAAAPIwlrLNzMw+AAAAAMPQkL7D0JA+AAAAAM3MzL7yMBazAAAAAMHQkL7E0JC+AAAAAPLkozHNzMy+AAAAAMbQkD6/0JC+AAAAAM3MzD4AAAAA\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAADNzMw+w9CQPgAAAADD0JA+zczMPgAAAADyMJayw9CQPgAAAADD0JC+8jAWswAAAADNzMy+xNCQvgAAAADB0JC+zczMvgAAAADy5KMxv9CQvgAAAADG0JA+AAAAAAAAAADNzMw+\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,zczMPgAAAAAAAAAAw9CQPsPQkD4AAAAA8jCWss3MzD4AAAAAw9CQvsPQkD4AAAAAzczMvvIwFrMAAAAAwdCQvsTQkL4AAAAA8uSjMc3MzL4AAAAAxtCQPr/QkL4AAAAAzczMPgAAAAAAAAAA\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAMPQkD7D0JA+AAAAAPIwlrLNzMw+AAAAAMPQkL7D0JA+AAAAAM3MzL7yMBazAAAAAMHQkL7E0JC+AAAAAPLkozHNzMy+AAAAAMbQkD6/0JC+AAAAAM3MzD4AAAAA\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAADNzMw+w9CQPgAAAADD0JA+zczMPgAAAADyMJayw9CQPgAAAADD0JC+8jAWswAAAADNzMy+xNCQvgAAAADB0JC+zczMvgAAAADy5KMxv9CQvgAAAADG0JA+AAAAAAAAAADNzMw+\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,zczMPgAAAAAAAAAAw9CQPsPQkD4AAAAA8jCWss3MzD4AAAAAw9CQvsPQkD4AAAAAzczMvvIwFrMAAAAAwdCQvsTQkL4AAAAA8uSjMc3MzL4AAAAAxtCQPr/QkL4AAAAAzczMPgAAAAAAAAAA\"},{\"byteLength\":216,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAAAAAIC/AABAQAAAAAAAAIC/AABAQAAAAAAAAIC/AAAAAAAAQEAAAIC/AAAAAAAAQEAAAIC/AAAAAAAAwEAAAIC/AAAAAAAAwEAAAIC/AABAQAAAQEAAAIC/AABAQAAAQEAAAIC/AADAQAAAAAAAAIC/AADAQAAAAAAAAIC/AAAQQQAAAAAAAIC/AAAQQQAAAAAAAIC/AADAQAAAQEAAAIC/AADAQAAAQEAAAIC/AABAQAAAwEAAAIC/AABAQAAAwEAAAIC/9G68v70bb0EAAIC/\"},{\"byteLength\":24,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAAAAAIC/xyAFwQqBscAAAIC/\"}],\"materials\":[{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0.5,0.5,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0},\"material\":0,\"mode\":6},{\"attributes\":{\"POSITION\":1},\"material\":0,\"mode\":6},{\"attributes\":{\"POSITION\":2},\"material\":0,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":1,\"mode\":6},{\"attributes\":{\"POSITION\":4},\"material\":1,\"mode\":6},{\"attributes\":{\"POSITION\":5},\"material\":1,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":6},\"material\":2,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":7},\"material\":3,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[0,0,-1]},{\"mesh\":1,\"translation\":[3,0,-1]},{\"mesh\":1,\"translation\":[0,3,-1]},{\"mesh\":1,\"translation\":[0,6,-1]},{\"mesh\":1,\"translation\":[3,3,-1]},{\"mesh\":1,\"translation\":[6,0,-1]},{\"mesh\":1,\"translation\":[9,0,-1]},{\"mesh\":1,\"translation\":[6,3,-1]},{\"mesh\":1,\"translation\":[3,6,-1]},{\"mesh\":2,\"translation\":[0,0,0]},{\"mesh\":3,\"translation\":[0,0,0]}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10]}]}"
  },
  {
    "path": "testdata/match_graph_repetition_code.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0,0.400000005960464],\"min\":[-0.400000005960464,0,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0.400000005960464,0],\"min\":[-0.400000005960464,-0.400000005960464,0],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0,0.400000005960464],\"min\":[-0.400000005960464,0,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0.400000005960464,0],\"min\":[-0.400000005960464,-0.400000005960464,0],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":500,\"max\":[33,37.0710678100586,0],\"min\":[-7,-7.07106781005859,0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":80,\"max\":[43,37.0710678100586,0],\"min\":[33,-7.07106781005859,0],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":1,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":2,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":3,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":4,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":5,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":6,\"byteLength\":6000,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":7,\"byteLength\":960,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAMPQkD7D0JA+AAAAAPIwlrLNzMw+AAAAAMPQkL7D0JA+AAAAAM3MzL7yMBazAAAAAMHQkL7E0JC+AAAAAPLkozHNzMy+AAAAAMbQkD6/0JC+AAAAAM3MzD4AAAAA\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAADNzMw+w9CQPgAAAADD0JA+zczMPgAAAADyMJayw9CQPgAAAADD0JC+8jAWswAAAADNzMy+xNCQvgAAAADB0JC+zczMvgAAAADy5KMxv9CQvgAAAADG0JA+AAAAAAAAAADNzMw+\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,zczMPgAAAAAAAAAAw9CQPsPQkD4AAAAA8jCWss3MzD4AAAAAw9CQvsPQkD4AAAAAzczMvvIwFrMAAAAAwdCQvsTQkL4AAAAA8uSjMc3MzL4AAAAAxtCQPr/QkL4AAAAAzczMPgAAAAAAAAAA\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAMPQkD7D0JA+AAAAAPIwlrLNzMw+AAAAAMPQkL7D0JA+AAAAAM3MzL7yMBazAAAAAMHQkL7E0JC+AAAAAPLkozHNzMy+AAAAAMbQkD6/0JC+AAAAAM3MzD4AAAAA\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAADNzMw+w9CQPgAAAADD0JA+zczMPgAAAADyMJayw9CQPgAAAADD0JC+8jAWswAAAADNzMy+xNCQvgAAAADB0JC+zczMvgAAAADy5KMxv9CQvgAAAADG0JA+AAAAAAAAAADNzMw+\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,zczMPgAAAAAAAAAAw9CQPsPQkD4AAAAA8jCWss3MzD4AAAAAw9CQvsPQkD4AAAAAzczMvvIwFrMAAAAAwdCQvsTQkL4AAAAA8uSjMc3MzL4AAAAAxtCQPr/QkL4AAAAAzczMPgAAAAAAAAAA\"},{\"byteLength\":6000,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AABAQAAAAAAAAAAAMEaCwDBG4sAAAAAAAABAQAAAAAAAAAAAAAAQQQAAAAAAAAAAAABAQAAAAAAAAAAAAABAQAAAQEAAAAAAAABAQAAAAAAAAAAAAAAQQQAAQEAAAAAAAAAQQQAAAAAAAAAAAABwQQAAAAAAAAAAAAAQQQAAAAAAAAAAAAAQQQAAQEAAAAAAAAAQQQAAAAAAAAAAAABwQQAAQEAAAAAAAABwQQAAAAAAAAAAAACoQQAAAAAAAAAAAABwQQAAAAAAAAAAAABwQQAAQEAAAAAAAABwQQAAAAAAAAAAAACoQQAAQEAAAAAAAACoQQAAAAAAAAAAAADYQQAAAAAAAAAAAACoQQAAAAAAAAAAAACoQQAAQEAAAAAAAACoQQAAAAAAAAAAAADYQQAAQEAAAAAAAADYQQAAAAAAAAAAAAAEQgAAAAAAAAAAAADYQQAAAAAAAAAAAADYQQAAQEAAAAAAAADYQQAAAAAAAAAAAAAEQgAAQEAAAAAAAAAEQgAAAAAAAAAAAAAEQgAAQEAAAAAAAABAQAAAQEAAAAAAxeCZwAjOT8AAAAAAAABAQAAAQEAAAAAAAAAQQQAAQEAAAAAAAABAQAAAQEAAAAAAxeCZwAjOT8AAAAAAAABAQAAAAAAAAAAAMEaCwDBG4sAAAAAAAAAQQQAAQEAAAAAAAABwQQAAQEAAAAAAAABwQQAAQEAAAAAAAACoQQAAQEAAAAAAAACoQQAAQEAAAAAAAADYQQAAQEAAAAAAAADYQQAAQEAAAAAAAAAEQgAAQEAAAAAAAABAQAAAQEAAAAAAxeCZwAjOT8AAAAAAAABAQAAAQEAAAAAAAAAQQQAAQEAAAAAAAABAQAAAQEAAAAAAAABAQAAAwEAAAAAAAABAQAAAQEAAAAAAAAAQQQAAwEAAAAAAAAAQQQAAQEAAAAAAAABwQQAAQEAAAAAAAAAQQQAAQEAAAAAAAAAQQQAAwEAAAAAAAAAQQQAAQEAAAAAAAABwQQAAwEAAAAAAAABwQQAAQEAAAAAAAACoQQAAQEAAAAAAAABwQQAAQEAAAAAAAABwQQAAwEAAAAAAAABwQQAAQEAAAAAAAACoQQAAwEAAAAAAAACoQQAAQEAAAAAAAADYQQAAQEAAAAAAAACoQQAAQEAAAAAAAACoQQAAwEAAAAAAAACoQQAAQEAAAAAAAADYQQAAwEAAAAAAAADYQQAAQEAAAAAAAAAEQgAAQEAAAAAAAADYQQAAQEAAAAAAAADYQQAAwEAAAAAAAADYQQAAQEAAAAAAAAAEQgAAwEAAAAAAAAAEQgAAQEAAAAAAAAAEQgAAwEAAAAAAAABAQAAAwEAAAAAA1GWywAjkWj8AAAAAAABAQAAAwEAAAAAAAAAQQQAAwEAAAAAAAABAQAAAwEAAAAAA1GWywAjkWj8AAAAAAABAQAAAQEAAAAAAxeCZwAjOT8AAAAAAAAAQQQAAwEAAAAAAAABwQQAAwEAAAAAAAABwQQAAwEAAAAAAAACoQQAAwEAAAAAAAACoQQAAwEAAAAAAAADYQQAAwEAAAAAAAADYQQAAwEAAAAAAAAAEQgAAwEAAAAAAAABAQAAAwEAAAAAA1GWywAjkWj8AAAAAAABAQAAAwEAAAAAAAAAQQQAAwEAAAAAAAABAQAAAwEAAAAAAAABAQAAAEEEAAAAAAABAQAAAwEAAAAAAAAAQQQAAEEEAAAAAAAAQQQAAwEAAAAAAAABwQQAAwEAAAAAAAAAQQQAAwEAAAAAAAAAQQQAAEEEAAAAAAAAQQQAAwEAAAAAAAABwQQAAEEEAAAAAAABwQQAAwEAAAAAAAACoQQAAwEAAAAAAAABwQQAAwEAAAAAAAABwQQAAEEEAAAAAAABwQQAAwEAAAAAAAACoQQAAEEEAAAAAAACoQQAAwEAAAAAAAADYQQAAwEAAAAAAAACoQQAAwEAAAAAAAACoQQAAEEEAAAAAAACoQQAAwEAAAAAAAADYQQAAEEEAAAAAAADYQQAAwEAAAAAAAAAEQgAAwEAAAAAAAADYQQAAwEAAAAAAAADYQQAAEEEAAAAAAADYQQAAwEAAAAAAAAAEQgAAEEEAAAAAAAAEQgAAwEAAAAAAAAAEQgAAEEEAAAAAAABAQAAAEEEAAAAA0BzJwK0nqUAAAAAAAABAQAAAEEEAAAAAAAAQQQAAEEEAAAAAAABAQAAAEEEAAAAA0BzJwK0nqUAAAAAAAABAQAAAwEAAAAAA1GWywAjkWj8AAAAAAAAQQQAAEEEAAAAAAABwQQAAEEEAAAAAAABwQQAAEEEAAAAAAACoQQAAEEEAAAAAAACoQQAAEEEAAAAAAADYQQAAEEEAAAAAAADYQQAAEEEAAAAAAAAEQgAAEEEAAAAAAABAQAAAEEEAAAAA0BzJwK0nqUAAAAAAAABAQAAAEEEAAAAAAAAQQQAAEEEAAAAAAABAQAAAEEEAAAAAAABAQAAAQEEAAAAAAABAQAAAEEEAAAAAAAAQQQAAQEEAAAAAAAAQQQAAEEEAAAAAAABwQQAAEEEAAAAAAAAQQQAAEEEAAAAAAAAQQQAAQEEAAAAAAAAQQQAAEEEAAAAAAABwQQAAQEEAAAAAAABwQQAAEEEAAAAAAACoQQAAEEEAAAAAAABwQQAAEEEAAAAAAABwQQAAQEEAAAAAAABwQQAAEEEAAAAAAACoQQAAQEEAAAAAAACoQQAAEEEAAAAAAADYQQAAEEEAAAAAAACoQQAAEEEAAAAAAACoQQAAQEEAAAAAAACoQQAAEEEAAAAAAADYQQAAQEEAAAAAAADYQQAAEEEAAAAAAAAEQgAAEEEAAAAAAADYQQAAEEEAAAAAAADYQQAAQEEAAAAAAADYQQAAEEEAAAAAAAAEQgAAQEEAAAAAAAAEQgAAEEEAAAAAAAAEQgAAQEEAAAAAAABAQAAAQEEAAAAALMnZwBWfIEEAAAAAAABAQAAAQEEAAAAAAAAQQQAAQEEAAAAAAABAQAAAQEEAAAAALMnZwBWfIEEAAAAAAABAQAAAEEEAAAAA0BzJwK0nqUAAAAAAAAAQQQAAQEEAAAAAAABwQQAAQEEAAAAAAABwQQAAQEEAAAAAAACoQQAAQEEAAAAAAACoQQAAQEEAAAAAAADYQQAAQEEAAAAAAADYQQAAQEEAAAAAAAAEQgAAQEEAAAAAAABAQAAAQEEAAAAALMnZwBWfIEEAAAAAAABAQAAAQEEAAAAAAAAQQQAAQEEAAAAAAABAQAAAQEEAAAAAAABAQAAAcEEAAAAAAABAQAAAQEEAAAAAAAAQQQAAcEEAAAAAAAAQQQAAQEEAAAAAAABwQQAAQEEAAAAAAAAQQQAAQEEAAAAAAAAQQQAAcEEAAAAAAAAQQQAAQEEAAAAAAABwQQAAcEEAAAAAAABwQQAAQEEAAAAAAACoQQAAQEEAAAAAAABwQQAAQEEAAAAAAABwQQAAcEEAAAAAAABwQQAAQEEAAAAAAACoQQAAcEEAAAAAAACoQQAAQEEAAAAAAADYQQAAQEEAAAAAAACoQQAAQEEAAAAAAACoQQAAcEEAAAAAAACoQQAAQEEAAAAAAADYQQAAcEEAAAAAAADYQQAAQEEAAAAAAAAEQgAAQEEAAAAAAADYQQAAQEEAAAAAAADYQQAAcEEAAAAAAADYQQAAQEEAAAAAAAAEQgAAcEEAAAAAAAAEQgAAQEEAAAAAAAAEQgAAcEEAAAAAAABAQAAAcEEAAAAAAADgwAAAcEEAAAAAAABAQAAAcEEAAAAAAAAQQQAAcEEAAAAAAABAQAAAcEEAAAAAAADgwAAAcEEAAAAAAABAQAAAQEEAAAAALMnZwBWfIEEAAAAAAAAQQQAAcEEAAAAAAABwQQAAcEEAAAAAAABwQQAAcEEAAAAAAACoQQAAcEEAAAAAAACoQQAAcEEAAAAAAADYQQAAcEEAAAAAAADYQQAAcEEAAAAAAAAEQgAAcEEAAAAAAABAQAAAcEEAAAAAAADgwAAAcEEAAAAAAABAQAAAcEEAAAAAAAAQQQAAcEEAAAAAAABAQAAAcEEAAAAAAABAQAAAkEEAAAAAAABAQAAAcEEAAAAAAAAQQQAAkEEAAAAAAAAQQQAAcEEAAAAAAABwQQAAcEEAAAAAAAAQQQAAcEEAAAAAAAAQQQAAkEEAAAAAAAAQQQAAcEEAAAAAAABwQQAAkEEAAAAAAABwQQAAcEEAAAAAAACoQQAAcEEAAAAAAABwQQAAcEEAAAAAAABwQQAAkEEAAAAAAABwQQAAcEEAAAAAAACoQQAAkEEAAAAAAACoQQAAcEEAAAAAAADYQQAAcEEAAAAAAACoQQAAcEEAAAAAAACoQQAAkEEAAAAAAACoQQAAcEEAAAAAAADYQQAAkEEAAAAAAADYQQAAcEEAAAAAAAAEQgAAcEEAAAAAAADYQQAAcEEAAAAAAADYQQAAkEEAAAAAAADYQQAAcEEAAAAAAAAEQgAAkEEAAAAAAAAEQgAAcEEAAAAAAAAEQgAAkEEAAAAAAABAQAAAkEEAAAAALMnZwHWwn0EAAAAAAABAQAAAkEEAAAAAAAAQQQAAkEEAAAAAAABAQAAAkEEAAAAALMnZwHWwn0EAAAAAAABAQAAAcEEAAAAAAADgwAAAcEEAAAAAAAAQQQAAkEEAAAAAAABwQQAAkEEAAAAAAABwQQAAkEEAAAAAAACoQQAAkEEAAAAAAACoQQAAkEEAAAAAAADYQQAAkEEAAAAAAADYQQAAkEEAAAAAAAAEQgAAkEEAAAAAAABAQAAAkEEAAAAALMnZwHWwn0EAAAAAAABAQAAAkEEAAAAAAAAQQQAAkEEAAAAAAABAQAAAkEEAAAAAAABAQAAAqEEAAAAAAABAQAAAkEEAAAAAAAAQQQAAqEEAAAAAAAAQQQAAkEEAAAAAAABwQQAAkEEAAAAAAAAQQQAAkEEAAAAAAAAQQQAAqEEAAAAAAAAQQQAAkEEAAAAAAABwQQAAqEEAAAAAAABwQQAAkEEAAAAAAACoQQAAkEEAAAAAAABwQQAAkEEAAAAAAABwQQAAqEEAAAAAAABwQQAAkEEAAAAAAACoQQAAqEEAAAAAAACoQQAAkEEAAAAAAADYQQAAkEEAAAAAAACoQQAAkEEAAAAAAACoQQAAqEEAAAAAAACoQQAAkEEAAAAAAADYQQAAqEEAAAAAAADYQQAAkEEAAAAAAAAEQgAAkEEAAAAAAADYQQAAkEEAAAAAAADYQQAAqEEAAAAAAADYQQAAkEEAAAAAAAAEQgAAqEEAAAAAAAAEQgAAkEEAAAAAAAAEQgAAqEEAAAAAAABAQAAAqEEAAAAA0BzJwBW2xUEAAAAAAABAQAAAqEEAAAAAAAAQQQAAqEEAAAAAAABAQAAAqEEAAAAA0BzJwBW2xUEAAAAAAABAQAAAkEEAAAAALMnZwHWwn0EAAAAAAAAQQQAAqEEAAAAAAABwQQAAqEEAAAAAAABwQQAAqEEAAAAAAACoQQAAqEEAAAAAAACoQQAAqEEAAAAAAADYQQAAqEEAAAAAAADYQQAAqEEAAAAAAAAEQgAAqEEAAAAAAABAQAAAqEEAAAAA0BzJwBW2xUEAAAAAAABAQAAAqEEAAAAAAAAQQQAAqEEAAAAAAABAQAAAqEEAAAAAAABAQAAAwEEAAAAAAABAQAAAqEEAAAAAAAAQQQAAwEEAAAAAAAAQQQAAqEEAAAAAAABwQQAAqEEAAAAAAAAQQQAAqEEAAAAAAAAQQQAAwEEAAAAAAAAQQQAAqEEAAAAAAABwQQAAwEEAAAAAAABwQQAAqEEAAAAAAACoQQAAqEEAAAAAAABwQQAAqEEAAAAAAABwQQAAwEEAAAAAAABwQQAAqEEAAAAAAACoQQAAwEEAAAAAAACoQQAAqEEAAAAAAADYQQAAqEEAAAAAAACoQQAAqEEAAAAAAACoQQAAwEEAAAAAAACoQQAAqEEAAAAAAADYQQAAwEEAAAAAAADYQQAAqEEAAAAAAAAEQgAAqEEAAAAAAADYQQAAqEEAAAAAAADYQQAAwEEAAAAAAADYQQAAqEEAAAAAAAAEQgAAwEEAAAAAAAAEQgAAqEEAAAAAAAAEQgAAwEEAAAAAAABAQAAAwEEAAAAA1GWywOAo6UEAAAAAAABAQAAAwEEAAAAAAAAQQQAAwEEAAAAAAABAQAAAwEEAAAAA1GWywOAo6UEAAAAAAABAQAAAqEEAAAAA0BzJwBW2xUEAAAAAAAAQQQAAwEEAAAAAAABwQQAAwEEAAAAAAABwQQAAwEEAAAAAAACoQQAAwEEAAAAAAACoQQAAwEEAAAAAAADYQQAAwEEAAAAAAADYQQAAwEEAAAAAAAAEQgAAwEEAAAAAAABAQAAAwEEAAAAA1GWywOAo6UEAAAAAAABAQAAAwEEAAAAAAAAQQQAAwEEAAAAAAABAQAAAwEEAAAAAAABAQAAA2EEAAAAAAABAQAAAwEEAAAAAAAAQQQAA2EEAAAAAAAAQQQAAwEEAAAAAAABwQQAAwEEAAAAAAAAQQQAAwEEAAAAAAAAQQQAA2EEAAAAAAAAQQQAAwEEAAAAAAABwQQAA2EEAAAAAAABwQQAAwEEAAAAAAACoQQAAwEEAAAAAAABwQQAAwEEAAAAAAABwQQAA2EEAAAAAAABwQQAAwEEAAAAAAACoQQAA2EEAAAAAAACoQQAAwEEAAAAAAADYQQAAwEEAAAAAAACoQQAAwEEAAAAAAACoQQAA2EEAAAAAAACoQQAAwEEAAAAAAADYQQAA2EEAAAAAAADYQQAAwEEAAAAAAAAEQgAAwEEAAAAAAADYQQAAwEEAAAAAAADYQQAA2EEAAAAAAADYQQAAwEEAAAAAAAAEQgAA2EEAAAAAAAAEQgAAwEEAAAAAAAAEQgAA2EEAAAAAAABAQAAA2EEAAAAAxeCZwOD8BEIAAAAAAABAQAAA2EEAAAAAAAAQQQAA2EEAAAAAAABAQAAA2EEAAAAAxeCZwOD8BEIAAAAAAABAQAAAwEEAAAAA1GWywOAo6UEAAAAAAAAQQQAA2EEAAAAAAABwQQAA2EEAAAAAAABwQQAA2EEAAAAAAACoQQAA2EEAAAAAAACoQQAA2EEAAAAAAADYQQAA2EEAAAAAAADYQQAA2EEAAAAAAAAEQgAA2EEAAAAAAABAQAAA2EEAAAAAxeCZwOD8BEIAAAAAAABAQAAA2EEAAAAAAAAQQQAA2EEAAAAAAABAQAAA2EEAAAAAAABAQAAA8EEAAAAAAABAQAAA2EEAAAAAAAAQQQAA8EEAAAAAAAAQQQAA2EEAAAAAAABwQQAA2EEAAAAAAAAQQQAA2EEAAAAAAAAQQQAA8EEAAAAAAAAQQQAA2EEAAAAAAABwQQAA8EEAAAAAAABwQQAA2EEAAAAAAACoQQAA2EEAAAAAAABwQQAA2EEAAAAAAABwQQAA8EEAAAAAAABwQQAA2EEAAAAAAACoQQAA8EEAAAAAAACoQQAA2EEAAAAAAADYQQAA2EEAAAAAAACoQQAA2EEAAAAAAACoQQAA8EEAAAAAAACoQQAA2EEAAAAAAADYQQAA8EEAAAAAAADYQQAA2EEAAAAAAAAEQgAA2EEAAAAAAADYQQAA2EEAAAAAAADYQQAA8EEAAAAAAADYQQAA2EEAAAAAAAAEQgAA8EEAAAAAAAAEQgAA2EEAAAAAAAAEQgAA8EEAAAAAAABAQAAA8EEAAAAAMEaCwMZIFEIAAAAAAABAQAAA8EEAAAAAAAAQQQAA8EEAAAAAAABAQAAA8EEAAAAAMEaCwMZIFEIAAAAAAABAQAAA2EEAAAAAxeCZwOD8BEIAAAAAAAAQQQAA8EEAAAAAAABwQQAA8EEAAAAAAABwQQAA8EEAAAAAAACoQQAA8EEAAAAAAACoQQAA8EEAAAAAAADYQQAA8EEAAAAAAADYQQAA8EEAAAAAAAAEQgAA8EEAAAAA\"},{\"byteLength\":960,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAEQgAAAAAAAAAAxkggQjBG4sAAAAAAAAAEQgAAQEAAAAAAGTwjQgjOT8AAAAAAAAAEQgAAQEAAAAAAGTwjQgjOT8AAAAAAAAAEQgAAAAAAAAAAxkggQjBG4sAAAAAAAAAEQgAAQEAAAAAAGTwjQgjOT8AAAAAAAAAEQgAAwEAAAAAAukwmQgjkWj8AAAAAAAAEQgAAwEAAAAAAukwmQgjkWj8AAAAAAAAEQgAAQEAAAAAAGTwjQgjOT8AAAAAAAAAEQgAAwEAAAAAAukwmQgjkWj8AAAAAAAAEQgAAEEEAAAAAmiMpQq0nqUAAAAAAAAAEQgAAEEEAAAAAmiMpQq0nqUAAAAAAAAAEQgAAwEAAAAAAukwmQgjkWj8AAAAAAAAEQgAAEEEAAAAAmiMpQq0nqUAAAAAAAAAEQgAAQEEAAAAAJjkrQhWfIEEAAAAAAAAEQgAAQEEAAAAAJjkrQhWfIEEAAAAAAAAEQgAAEEEAAAAAmiMpQq0nqUAAAAAAAAAEQgAAQEEAAAAAJjkrQhWfIEEAAAAAAAAEQgAAcEEAAAAAAAAsQgAAcEEAAAAAAAAEQgAAcEEAAAAAAAAsQgAAcEEAAAAAAAAEQgAAQEEAAAAAJjkrQhWfIEEAAAAAAAAEQgAAcEEAAAAAAAAsQgAAcEEAAAAAAAAEQgAAkEEAAAAAJjkrQnWwn0EAAAAAAAAEQgAAkEEAAAAAJjkrQnWwn0EAAAAAAAAEQgAAcEEAAAAAAAAsQgAAcEEAAAAAAAAEQgAAkEEAAAAAJjkrQnWwn0EAAAAAAAAEQgAAqEEAAAAAmiMpQhW2xUEAAAAAAAAEQgAAqEEAAAAAmiMpQhW2xUEAAAAAAAAEQgAAkEEAAAAAJjkrQnWwn0EAAAAAAAAEQgAAqEEAAAAAmiMpQhW2xUEAAAAAAAAEQgAAwEEAAAAAukwmQuAo6UEAAAAAAAAEQgAAwEEAAAAAukwmQuAo6UEAAAAAAAAEQgAAqEEAAAAAmiMpQhW2xUEAAAAAAAAEQgAAwEEAAAAAukwmQuAo6UEAAAAAAAAEQgAA2EEAAAAAGTwjQuD8BEIAAAAAAAAEQgAA2EEAAAAAGTwjQuD8BEIAAAAAAAAEQgAAwEEAAAAAukwmQuAo6UEAAAAAAAAEQgAA2EEAAAAAGTwjQuD8BEIAAAAAAAAEQgAA8EEAAAAAxkggQsZIFEIAAAAAAAAEQgAA8EEAAAAAxkggQsZIFEIAAAAAAAAEQgAA2EEAAAAAGTwjQuD8BEIAAAAA\"}],\"materials\":[{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0.5,0.5,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0},\"material\":0,\"mode\":6},{\"attributes\":{\"POSITION\":1},\"material\":0,\"mode\":6},{\"attributes\":{\"POSITION\":2},\"material\":0,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":1,\"mode\":6},{\"attributes\":{\"POSITION\":4},\"material\":1,\"mode\":6},{\"attributes\":{\"POSITION\":5},\"material\":1,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":6},\"material\":2,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":7},\"material\":3,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[3,0,0]},{\"mesh\":0,\"translation\":[9,0,0]},{\"mesh\":0,\"translation\":[15,0,0]},{\"mesh\":0,\"translation\":[21,0,0]},{\"mesh\":0,\"translation\":[27,0,0]},{\"mesh\":1,\"translation\":[33,0,0]},{\"mesh\":0,\"translation\":[3,3,0]},{\"mesh\":0,\"translation\":[9,3,0]},{\"mesh\":0,\"translation\":[15,3,0]},{\"mesh\":0,\"translation\":[21,3,0]},{\"mesh\":0,\"translation\":[27,3,0]},{\"mesh\":1,\"translation\":[33,3,0]},{\"mesh\":0,\"translation\":[3,6,0]},{\"mesh\":0,\"translation\":[9,6,0]},{\"mesh\":0,\"translation\":[15,6,0]},{\"mesh\":0,\"translation\":[21,6,0]},{\"mesh\":0,\"translation\":[27,6,0]},{\"mesh\":1,\"translation\":[33,6,0]},{\"mesh\":0,\"translation\":[3,9,0]},{\"mesh\":0,\"translation\":[9,9,0]},{\"mesh\":0,\"translation\":[15,9,0]},{\"mesh\":0,\"translation\":[21,9,0]},{\"mesh\":0,\"translation\":[27,9,0]},{\"mesh\":1,\"translation\":[33,9,0]},{\"mesh\":0,\"translation\":[3,12,0]},{\"mesh\":0,\"translation\":[9,12,0]},{\"mesh\":0,\"translation\":[15,12,0]},{\"mesh\":0,\"translation\":[21,12,0]},{\"mesh\":0,\"translation\":[27,12,0]},{\"mesh\":1,\"translation\":[33,12,0]},{\"mesh\":0,\"translation\":[3,15,0]},{\"mesh\":0,\"translation\":[9,15,0]},{\"mesh\":0,\"translation\":[15,15,0]},{\"mesh\":0,\"translation\":[21,15,0]},{\"mesh\":0,\"translation\":[27,15,0]},{\"mesh\":1,\"translation\":[33,15,0]},{\"mesh\":0,\"translation\":[3,18,0]},{\"mesh\":0,\"translation\":[9,18,0]},{\"mesh\":0,\"translation\":[15,18,0]},{\"mesh\":0,\"translation\":[21,18,0]},{\"mesh\":0,\"translation\":[27,18,0]},{\"mesh\":1,\"translation\":[33,18,0]},{\"mesh\":0,\"translation\":[3,21,0]},{\"mesh\":0,\"translation\":[9,21,0]},{\"mesh\":0,\"translation\":[15,21,0]},{\"mesh\":0,\"translation\":[21,21,0]},{\"mesh\":0,\"translation\":[27,21,0]},{\"mesh\":1,\"translation\":[33,21,0]},{\"mesh\":0,\"translation\":[3,24,0]},{\"mesh\":0,\"translation\":[9,24,0]},{\"mesh\":0,\"translation\":[15,24,0]},{\"mesh\":0,\"translation\":[21,24,0]},{\"mesh\":0,\"translation\":[27,24,0]},{\"mesh\":1,\"translation\":[33,24,0]},{\"mesh\":0,\"translation\":[3,27,0]},{\"mesh\":0,\"translation\":[9,27,0]},{\"mesh\":0,\"translation\":[15,27,0]},{\"mesh\":0,\"translation\":[21,27,0]},{\"mesh\":0,\"translation\":[27,27,0]},{\"mesh\":1,\"translation\":[33,27,0]},{\"mesh\":0,\"translation\":[3,30,0]},{\"mesh\":0,\"translation\":[9,30,0]},{\"mesh\":0,\"translation\":[15,30,0]},{\"mesh\":0,\"translation\":[21,30,0]},{\"mesh\":0,\"translation\":[27,30,0]},{\"mesh\":1,\"translation\":[33,30,0]},{\"mesh\":2,\"translation\":[0,0,0]},{\"mesh\":3,\"translation\":[0,0,0]}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67]}]}"
  },
  {
    "path": "testdata/match_graph_surface_code.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0,0.400000005960464],\"min\":[-0.400000005960464,0,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0.400000005960464,0],\"min\":[-0.400000005960464,-0.400000005960464,0],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0,0.400000005960464],\"min\":[-0.400000005960464,0,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":9,\"max\":[0.400000005960464,0.400000005960464,0],\"min\":[-0.400000005960464,-0.400000005960464,0],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":8192,\"max\":[20.9442710876465,20.9442710876465,39.8058090209961],\"min\":[-8.9442720413208,-8.9442720413208,-9.80580711364746],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":1336,\"max\":[20.9442710876465,3,39.8058090209961],\"min\":[-8.9442720413208,-7,-9.80580711364746],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":1,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":2,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":3,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":4,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":5,\"byteLength\":108,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":6,\"byteLength\":98304,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":7,\"byteLength\":16032,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAMPQkD7D0JA+AAAAAPIwlrLNzMw+AAAAAMPQkL7D0JA+AAAAAM3MzL7yMBazAAAAAMHQkL7E0JC+AAAAAPLkozHNzMy+AAAAAMbQkD6/0JC+AAAAAM3MzD4AAAAA\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAADNzMw+w9CQPgAAAADD0JA+zczMPgAAAADyMJayw9CQPgAAAADD0JC+8jAWswAAAADNzMy+xNCQvgAAAADB0JC+zczMvgAAAADy5KMxv9CQvgAAAADG0JA+AAAAAAAAAADNzMw+\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,zczMPgAAAAAAAAAAw9CQPsPQkD4AAAAA8jCWss3MzD4AAAAAw9CQvsPQkD4AAAAAzczMvvIwFrMAAAAAwdCQvsTQkL4AAAAA8uSjMc3MzL4AAAAAxtCQPr/QkL4AAAAAzczMPgAAAAAAAAAA\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAMPQkD7D0JA+AAAAAPIwlrLNzMw+AAAAAMPQkL7D0JA+AAAAAM3MzL7yMBazAAAAAMHQkL7E0JC+AAAAAPLkozHNzMy+AAAAAMbQkD6/0JC+AAAAAM3MzD4AAAAA\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAADNzMw+w9CQPgAAAADD0JA+zczMPgAAAADyMJayw9CQPgAAAADD0JC+8jAWswAAAADNzMy+xNCQvgAAAADB0JC+zczMvgAAAADy5KMxv9CQvgAAAADG0JA+AAAAAAAAAADNzMw+\"},{\"byteLength\":108,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,zczMPgAAAAAAAAAAw9CQPsPQkD4AAAAA8jCWss3MzD4AAAAAw9CQvsPQkD4AAAAAzczMvvIwFrMAAAAAwdCQvsTQkL4AAAAA8uSjMc3MzL4AAAAAxtCQPr/QkL4AAAAAzczMPgAAAAAAAAAA\"},{\"byteLength\":98304,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAQEAAAAAAAAAAAAAAEEEAAAAAAAAAAAAAQEAAAAAAAADAQAAAQEAAAAAAAAAAAAAAQEAAAAAAAAAAAAAAQEAAAEBAAAAAAAAAEEEAAAAA6LFpwD02LUEyDxLBAAAAAAAAEEEAAAAAAADAQAAAEEEAAAAAAAAAAAAAEEEAAAAAAAAAAAAAQEAAAEBAAAAAAAAAEEEAAAAAAAAAAAAAEEEAAEBAAADAQAAAQEAAAAAAAADAQAAAEEEAAAAAAADAQAAAQEAAAAAAAADAQAAAEEEAAAAAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAQEAAAAAAAABAQQAAQEAAAAAAAADAQAAAQEAAAAAAAAAAAAAAQEAAAEBAAADAQAAAQEAAAAAAAAAAAAAAQEAAAEBAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAADAQAAAQEAAAAAAAAAAAAAAQEAAAEBAAABAQAAAAAAAAEBAAABAQAAAwEAAAEBAAADAQAAAQEAAAAAAAAAAAAAAQEAAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAQEAAAAAAAAAAAAAAQEAAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAADAQAAAQEAAAAAAAADAQAAAQEAAAEBAAADAQAAAQEAAAAAAAADAQAAAQEAAAEBAAABAQAAAAAAAAEBAAABAQAAAwEAAAEBAAADAQAAAQEAAAAAAAADAQAAAQEAAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAQEAAAAAAAAAAAAAAEEEAAEBAAADAQAAAQEAAAAAAAAAAAAAAEEEAAEBAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAADAQAAAQEAAAAAAAAAAAAAAEEEAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAQEAAAAAAAAAAAAAAEEEAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAADAQAAAEEEAAAAAAADAQOtgL0GW5BzBAADAQAAAEEEAAAAAAABAQQAAEEEAAAAAAADAQAAAEEEAAAAAAADAQAAAQEAAAEBAAADAQAAAEEEAAAAAAADAQAAAQEAAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAEEEAAAAAAADAQAAAQEAAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAADAQAAAEEEAAAAAAADAQAAAQEAAAEBAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAADAQAAAEEEAAAAAAAAAAAAAEEEAAEBAAADAQAAAEEEAAAAAAAAAAAAAEEEAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAEEEAAAAAAAAAAAAAEEEAAEBAAABAQAAAwEAAAEBAAABAQAAAQEEAAEBAAADAQAAAEEEAAAAAAADAQAAAEEEAAEBAAADAQAAAEEEAAAAAAADAQAAAEEEAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAEEEAAAAAAADAQAAAEEEAAEBAAABAQAAAwEAAAEBAAABAQAAAQEEAAEBAAADAQAAAEEEAAAAAAADAQAAAEEEAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAADAQAAAEEEAAAAAAADAQAAAEEEAAEBAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAABAQQAAQEAAAAAAAABAQQAAEEEAAAAAAABAQQAAQEAAAAAAAABAQQAAEEEAAAAAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQQAAQEAAAAAAAADAQAAAQEAAAEBAAABAQQAAQEAAAAAAAADAQAAAQEAAAEBAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAABAQQAAQEAAAAAAAADAQAAAQEAAAEBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAABAQQAAQEAAAAAAAADAQAAAQEAAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQQAAQEAAAAAAAADAQAAAQEAAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAABAQQAAQEAAAAAAAABAQQAAQEAAAEBAAABAQQAAQEAAAAAAAABAQQAAQEAAAEBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAABAQQAAQEAAAAAAAABAQQAAQEAAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQQAAQEAAAAAAAADAQAAAEEEAAEBAAABAQQAAQEAAAAAAAADAQAAAEEEAAEBAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAABAQQAAQEAAAAAAAADAQAAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQQAAQEAAAAAAAADAQAAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAABAQQAAEEEAAAAAemx6QT02LUEyDxLBAABAQQAAEEEAAAAAAABAQQAAQEAAAEBAAABAQQAAEEEAAAAAAABAQQAAQEAAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQQAAEEEAAAAAAABAQQAAQEAAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAQEEAAEBANOoyQTTqgkGiUbfAAABAQQAAEEEAAAAAAABAQQAAQEAAAEBAAAAQQQAAQEEAAEBANOoyQTTqgkGiUbfAAABAQQAAEEEAAAAAAADAQAAAEEEAAEBAAABAQQAAEEEAAAAAAADAQAAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQQAAEEEAAAAAAADAQAAAEEEAAEBAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAABAQQAAEEEAAAAAAABAQQAAEEEAAEBAAABAQQAAEEEAAAAAAABAQQAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQQAAEEEAAAAAAABAQQAAEEEAAEBAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAABAQQAAEEEAAAAAAABAQQAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAQEEAAEBANOoyQTTqgkGiUbfAAABAQQAAEEEAAAAAAABAQQAAEEEAAEBAAAAQQQAAQEEAAEBANOoyQTTqgkGiUbfAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAAAAAAEBAAAAQQQAAAAAAAEBAAABAQAAAAAAAAEBAAAAQQQAAAAAAAEBAAABAQAAAAAAAAEBAAABAQAAAwEAAAEBAAABAQAAAAAAAAEBAAABAQAAAwEAAAEBAAAAAAAAAQEAAAEBAAADAQAAAQEAAAEBAAABAQAAAAAAAAEBAAABAQAAAwEAAAEBAAAAAAAAAQEAAAEBAAAAAAAAAQEAAAMBAAABAQAAAAAAAAEBAAABAQAAAwEAAAEBAAADAQAAAQEAAAEBAAAAAAAAAQEAAAMBAAABAQAAAAAAAAEBAAABAQAAAwEAAAEBAAABAQAAAAAAAAEBAAABAQAAAwEAAAEBAAABAQAAAAAAAAEBAAABAQAAAwEAAAEBAAABAQAAAAAAAAEBAAABAQAAAAAAAAMBAAABAQAAAAAAAAEBAAABAQAAAAAAAAMBAAABAQAAAAAAAAEBAAABAQAAAAAAAAMBAAABAQAAAAAAAAEBAAABAQAAAAAAAAMBAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAADAQAAAQEAAAEBAAABAQQAAQEAAAEBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAADAQAAAQEAAAEBAAADAQAAAQEAAAMBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAABAQQAAQEAAAEBAAADAQAAAQEAAAMBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAADAQAAAEEEAAEBAAADAQAAAQEAAAMBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAEBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAEBAAABAQAAAAAAAAMBAAAAQQQAAAAAAAEBAAABAQAAAAAAAAMBAAAAQQQAAAAAAAEBAAABAQAAAAAAAAMBAAAAQQQAAAAAAAEBAAABAQAAAAAAAAMBAAAAQQQAAAAAAAEBAAAAQQQAAAAAAAMBAAAAQQQAAAAAAAEBAAAAQQQAAAAAAAMBAAAAQQQAAAAAAAEBAAAAQQQAAAAAAAMBAAAAQQQAAAAAAAEBAAAAQQQAAAAAAAMBAAAAQQQAAAAAAAEBAAABAQAAAwEAAAMBAAAAQQQAAAAAAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAAAQQQAAAAAAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAADAQAAAQEAAAMBAAAAQQQAAAAAAAEBAAABAQAAAwEAAAMBAAAAQQQAAAAAAAEBAAABAQAAAwEAAAMBAAADAQAAAEEEAAEBAAADAQAAAQEAAAMBAAAAQQQAAAAAAAEBAAABAQAAAwEAAAMBAAAAQQQAAAAAAAEBAAABAQAAAwEAAAMBAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAAAAAAQEAAAEBAAADAQAAAQEAAAEBAAAAAAAAAQEAAAEBAAAAAAAAAEEEAAEBAAAAAAAAAQEAAAEBAAAAAAAAAEEEAAEBAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAAAAAAAAQEAAAEBAAAAAAAAAEEEAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAAAAAAAAQEAAAEBAAAAAAAAAEEEAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAAAAAAAAQEAAAEBAAAAAAAAAQEAAAMBAAAAAAAAAQEAAAEBAAAAAAAAAQEAAAMBAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAAAAAAAAQEAAAEBAAAAAAAAAQEAAAMBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAAAAAAAAQEAAAEBAAAAAAAAAQEAAAMBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAADAQAAAQEAAAEBAAABAQQAAQEAAAEBAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAABAQAAAwEAAAEBAAAAQQQAAwEAAAEBAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAABAQAAAwEAAAEBAAABAQAAAQEEAAEBAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAABAQAAAwEAAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAAAQQQAAwEAAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAADAQAAAQEAAAEBAAADAQAAAEEEAAEBAAABAQAAAQEEAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAAAAAAAAQEAAAMBAAADAQAAAQEAAAEBAAAAAAAAAQEAAAMBAAABAQAAAwEAAAEBAAABAQAAAAAAAAMBAAADAQAAAQEAAAEBAAAAAAAAAQEAAAMBAAABAQAAAwEAAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAAAAAAAAQEAAAMBAAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAADAQAAAQEAAAMBAAADAQAAAQEAAAEBAAADAQAAAQEAAAMBAAAAQQQAAwEAAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAADAQAAAQEAAAMBAAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAAAAAAAAEEEAAMBAAADAQAAAQEAAAEBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAEBAAABAQAAAQEEAAEBAAADAQAAAQEAAAEBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAEBAAABAQAAAAAAAAMBAAADAQAAAQEAAAEBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAAAAAAAAEEEAAMBAAABAQAAAQEEAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAEBAAAAAAAAAEEEAAMBAAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQQAAQEAAAEBAAABAQQAAEEEAAEBAAABAQQAAQEAAAEBAAABAQQAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQQAAQEAAAEBAAABAQQAAEEEAAEBAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAABAQQAAQEAAAEBAAABAQQAAEEEAAEBAAAAQQQAAwEAAAEBAAAAQQQAAwEAAAMBAAABAQQAAQEAAAEBAAABAQQAAEEEAAEBAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAQEEAAEBANOoyQTTqgkGiUbfAAABAQQAAQEAAAEBAAABAQQAAEEEAAEBAAAAQQQAAQEEAAEBANOoyQTTqgkGiUbfAAABAQQAAQEAAAEBAAABAQQAAEEEAAEBAAAAQQQAAQEEAAEBAAAAQQQAAwEAAAMBAAABAQQAAQEAAAEBAAABAQQAAEEEAAEBAAAAQQQAAwEAAAMBAsJhCQQAAwEBIKF/AAABAQQAAQEAAAEBAAABAQQAAEEEAAEBAAAAQQQAAwEAAAMBAsJhCQQAAwEBIKF/AAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAABAQQAAQEAAAEBAAADAQAAAQEAAAMBAAABAQQAAQEAAAEBAAADAQAAAQEAAAMBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAMBAAABAQQAAQEAAAEBAAADAQAAAQEAAAMBAAAAQQQAAwEAAAEBAAAAQQQAAwEAAAMBAAABAQQAAQEAAAEBAAADAQAAAQEAAAMBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAABAQQAAQEAAAEBAAABAQQAAQEAAAMBAAABAQQAAQEAAAEBAAABAQQAAQEAAAMBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAABAQQAAQEAAAEBAAABAQQAAQEAAAMBAAAAQQQAAwEAAAMBAsJhCQQAAwEBIKF/AAABAQQAAQEAAAEBAAADAQAAAEEEAAMBAAABAQQAAQEAAAEBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAABAQQAAQEAAAEBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAMBAAABAQQAAQEAAAEBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAAAQQQAAwEAAAMBAAABAQQAAQEAAAEBAAADAQAAAEEEAAMBAAAAQQQAAQEEAAEBAAAAQQQAAwEAAAMBAAABAQQAAQEAAAEBAAADAQAAAEEEAAMBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAAAAAAMBABcM6QRUMq8BAJAHAAAAQQQAAAAAAAMBABcM6QRUMq8BAJAHAAAAQQQAAAAAAAEBANOoyQdGoi8CiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAwEAAAEBAAAAQQQAAwEAAAEBAAABAQAAAwEAAAEBAAABAQAAAQEEAAEBAAABAQAAAwEAAAEBAAABAQAAAQEEAAEBAAAAAAAAAEEEAAEBAAADAQAAAEEEAAEBAAABAQAAAwEAAAEBAAABAQAAAQEEAAEBAAAAAAAAAEEEAAEBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAEBAAABAQAAAQEEAAEBAAADAQAAAEEEAAEBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAEBAAABAQAAAAAAAAMBAAABAQAAAwEAAAEBAAABAQAAAAAAAAMBAAABAQAAAwEAAAEBAAABAQAAAAAAAAMBAAAAAAAAAQEAAAMBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAEBAAABAQAAAAAAAAMBAAABAQAAAwEAAAEBAAABAQAAAAAAAAMBAAABAQAAAwEAAAEBAAABAQAAAwEAAAMBAAABAQAAAwEAAAEBAAABAQAAAwEAAAMBAAADAQAAAEEEAAEBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAEBAAABAQAAAwEAAAMBAAAAAAAAAQEAAAMBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAEEEAAAAAAADAQOtgL0GW5BzBAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAAAAAAEBAvFxRP9Goi8CiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAAAAAAAAEEEAAEBA0aiLwDTqMkGiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAAAQQQAAwEAAAEBAQs42QQAAwEASctbAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAADAQAAAEEEAAEBAAADAQELONkESctbAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAADAQAAAEEEAAEBAAABAQQAAEEEAAEBAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAADAQAAAEEEAAEBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAABAQQAAEEEAAEBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAAAQQQAAwEAAAEBAAAAQQQAAQEEAAEBAAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAADAQAAAEEEAAEBAAADAQELONkESctbAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAMBAAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAEBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAEBAAABAQAAAwEAAAMBAAAAQQQAAwEAAAEBAAABAQAAAwEAAAMBAAADAQAAAEEEAAEBAAADAQAAAQEAAAMBAAAAQQQAAwEAAAEBAAABAQAAAwEAAAMBAAADAQAAAEEEAAEBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAABAQAAAwEAAAMBAAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAAAQQQAAwEAAAMBAAAAQQQAAwEAAAEBAAAAQQQAAwEAAAMBAAABAQQAAEEEAAEBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAAAQQQAAwEAAAMBAAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAEBAAABAQAAAQEEAAMBAAAAQQQAAwEAAAEBAAABAQAAAQEEAAMBAAADAQAAAEEEAAEBAAADAQELONkESctbA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AABAQAAAQEEAAMBAAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAABAQAAAQEEAAEBAAABAQAAAQEEAAMBAAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAADAQAAAEEEAAEBAAADAQELONkESctbAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAADAQAAAEEEAAAAAAADAQOtgL0GW5BzBAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAEEEAAAAAAADAQOtgL0GW5BzBAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAAAAAAAAEEEAAEBA0aiLwDTqMkGiUbfAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAAAAAAAAEEEAAEBA0aiLwDTqMkGiUbfAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAAAAAAAAEEEAAEBA0aiLwDTqMkGiUbfAAADAQAAAEEEAAAAAAADAQOtgL0GW5BzBAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAAAAAAAAEEEAAEBA0aiLwDTqMkGiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAAAAAAAAEEEAAEBA0aiLwDTqMkGiUbfAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAADAQAAAEEEAAAAAAADAQOtgL0GW5BzBAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAADAQAAAEEEAAEBAAADAQELONkESctbAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAADAQAAAEEEAAEBAAADAQELONkESctbAAADAQAAAEEEAAAAAAADAQOtgL0GW5BzBAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfAAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAABAQAAAwEAAAEBA3BsTPwAAwEASctbAAABAQAAAQEEAAEBAvFxRPzTqgkGiUbfA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BcOKQQXDOkFAJAHAAAAQQQAAQEEAAMBABcM6QQXDikFAJAHAAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAABAQQAAEEEAAEBANOqCQTTqMkGiUbfAAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAABAQAAAAAAAAMBAAAAQQQAAAAAAAMBAAABAQAAAAAAAAMBAAAAQQQAAAAAAAMBAAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAAAAAAAAQEAAAMBAAADAQAAAQEAAAMBAAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAAAAAAAAQEAAAMBAAAAAAAAAQEAAABBBAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAADAQAAAQEAAAMBAAAAAAAAAQEAAABBBAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAABAQAAAAAAAAMBAAABAQAAAwEAAAMBAAABAQAAAAAAAAMBAAABAQAAAAAAAABBBAABAQAAAAAAAAMBAAABAQAAAAAAAABBBAABAQAAAAAAAAMBAAABAQAAAAAAAABBBAABAQAAAAAAAAMBAAABAQAAAAAAAABBBAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAAAQQQAAAAAAAMBABcM6QRUMq8BAJAHAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAADAQAAAQEAAAMBAAABAQQAAQEAAAMBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAADAQAAAQEAAAMBAAADAQAAAQEAAABBBAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAABAQQAAQEAAAMBAAADAQAAAQEAAABBBAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAADAQAAAEEEAAMBAAADAQAAAQEAAABBBAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAAAQQQAAAAAAAMBAAAAQQQAAwEAAAMBAAAAQQQAAAAAAAMBAAABAQAAAAAAAABBBAAAQQQAAAAAAAMBAAABAQAAAAAAAABBBAAAQQQAAAAAAAMBAAABAQAAAAAAAABBBAAAQQQAAAAAAAMBAAABAQAAAAAAAABBBAAAQQQAAAAAAAMBAAAAQQQAAAAAAABBBAAAQQQAAAAAAAMBAAAAQQQAAAAAAABBBAAAQQQAAAAAAAMBAAAAQQQAAAAAAABBBAAAQQQAAAAAAAMBAAAAQQQAAAAAAABBBAAAQQQAAAAAAAMBAAABAQAAAwEAAABBBAAAQQQAAAAAAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAAAQQQAAAAAAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAADAQAAAQEAAABBBAAAQQQAAAAAAAMBAAABAQAAAwEAAABBBAAAQQQAAAAAAAMBAAABAQAAAwEAAABBBAADAQAAAEEEAAMBAAADAQAAAQEAAABBBAAAQQQAAAAAAAMBAAABAQAAAwEAAABBBAAAQQQAAAAAAAMBAAABAQAAAwEAAABBBAAAAAAAAQEAAAMBAAADAQAAAQEAAAMBAAAAAAAAAQEAAAMBAAAAAAAAAEEEAAMBAAAAAAAAAQEAAAMBAAAAAAAAAEEEAAMBAAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAAAAAAAAQEAAAMBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAQEAAAMBAAAAAAAAAEEEAAMBAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAAAAAAAAQEAAAMBAAAAAAAAAQEAAABBBAAAAAAAAQEAAAMBAAAAAAAAAQEAAABBBAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAAAAAAAAQEAAAMBAAAAAAAAAQEAAABBBAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAQEAAAMBAAAAAAAAAQEAAABBBAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAADAQAAAQEAAAMBAAABAQQAAQEAAAMBAAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAABAQAAAwEAAAMBAAAAQQQAAwEAAAMBAAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAABAQAAAwEAAAMBAAABAQAAAQEEAAMBAAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAABAQAAAwEAAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAAAQQQAAwEAAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAADAQAAAEEEAAMBAAABAQAAAQEEAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAAAAAAAAQEAAABBBAADAQAAAQEAAAMBAAAAAAAAAQEAAABBBAABAQAAAwEAAAMBAAABAQAAAAAAAABBBAADAQAAAQEAAAMBAAAAAAAAAQEAAABBBAABAQAAAwEAAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAAAAAAAAQEAAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAADAQAAAQEAAABBBAADAQAAAQEAAAMBAAADAQAAAQEAAABBBAAAQQQAAwEAAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAADAQAAAQEAAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAAAAAAAAEEEAABBBAADAQAAAQEAAAMBAAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAAABAQAAAQEEAAMBAAADAQAAAQEAAAMBAAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAAABAQAAAAAAAABBBAADAQAAAQEAAAMBAAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAAAAAAAAEEEAABBBAABAQAAAQEEAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAAMBAAAAAAAAAEEEAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAABAQQAAQEAAAMBAAABAQQAAEEEAAMBAAABAQQAAQEAAAMBAAABAQQAAEEEAAMBAAAAQQQAAwEAAAMBAsJhCQQAAwEBIKF/AAABAQQAAQEAAAMBAAABAQQAAEEEAAMBAAAAQQQAAwEAAAMBAAAAQQQAAQEEAAMBAAABAQQAAQEAAAMBAAABAQQAAEEEAAMBAAAAQQQAAwEAAAMBAAAAQQQAAwEAAABBBAABAQQAAQEAAAMBAAABAQQAAEEEAAMBAAAAQQQAAQEEAAMBAAAAQQQAAwEAAABBBAABAQQAAQEAAAMBAAABAQQAAEEEAAMBAAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AABAQQAAQEAAAMBAAABAQQAAEEEAAMBAAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAwEAAAMBAsJhCQQAAwEBIKF/AAABAQQAAQEAAAMBAAADAQAAAQEAAABBBAABAQQAAQEAAAMBAAADAQAAAQEAAABBBAAAQQQAAwEAAAMBAAAAQQQAAAAAAABBBAABAQQAAQEAAAMBAAADAQAAAQEAAABBBAAAQQQAAwEAAAMBAAAAQQQAAwEAAABBBAABAQQAAQEAAAMBAAADAQAAAQEAAABBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAABAQQAAQEAAAMBAAABAQQAAQEAAABBBAABAQQAAQEAAAMBAAABAQQAAQEAAABBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAABAQQAAQEAAAMBAAABAQQAAQEAAABBBAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AABAQQAAQEAAAMBAAADAQAAAEEEAABBBAABAQQAAQEAAAMBAAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAAAQQQAAQEEAAMBAAABAQQAAQEAAAMBAAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAAAQQQAAAAAAABBBAABAQQAAQEAAAMBAAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAAAQQQAAwEAAABBBAABAQQAAQEAAAMBAAADAQAAAEEEAABBBAAAQQQAAQEEAAMBAAAAQQQAAwEAAABBBAABAQQAAQEAAAMBAAADAQAAAEEEAABBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAAAQQQAAAAAAAMBABcM6QRUMq8BAJAHAAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAAAAAAMBABcM6QRUMq8BAJAHAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAABAQAAAwEAAAMBAAAAQQQAAwEAAAMBAAABAQAAAwEAAAMBAAABAQAAAQEEAAMBAAABAQAAAwEAAAMBAAABAQAAAQEEAAMBAAAAAAAAAEEEAAMBAAADAQAAAEEEAAMBAAABAQAAAwEAAAMBAAABAQAAAQEEAAMBAAAAAAAAAEEEAAMBAAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAAABAQAAAQEEAAMBAAADAQAAAEEEAAMBAAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAAABAQAAAAAAAABBBAABAQAAAwEAAAMBAAABAQAAAAAAAABBBAABAQAAAwEAAAMBAAABAQAAAAAAAABBBAAAAAAAAQEAAABBBAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAAABAQAAAAAAAABBBAABAQAAAwEAAAMBAAABAQAAAAAAAABBBAABAQAAAwEAAAMBAAABAQAAAwEAAABBBAABAQAAAwEAAAMBAAABAQAAAwEAAABBBAADAQAAAEEEAAMBAAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAAABAQAAAwEAAABBBAAAAAAAAQEAAABBBAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAAAQQQAAwEAAAMBAsJhCQQAAwEBIKF/AAAAQQQAAwEAAAMBAAAAQQQAAQEEAAMBAAAAQQQAAwEAAAMBAAAAQQQAAQEEAAMBAAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAAAQQQAAwEAAAMBAAAAQQQAAQEEAAMBAAADAQAAAEEEAAMBAAABAQQAAEEEAAMBAAAAQQQAAwEAAAMBAAAAQQQAAQEEAAMBAAADAQAAAEEEAAMBAAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAAAQQQAAQEEAAMBAAABAQQAAEEEAAMBAAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAAAQQQAAQEEAAMBAAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAwEAAAMBAAAAQQQAAQEEAAMBAAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAAAQQQAAwEAAAMBAAAAQQQAAAAAAABBBAAAQQQAAwEAAAMBAAAAQQQAAAAAAABBBAAAQQQAAwEAAAMBAAAAQQQAAAAAAABBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAAAQQQAAAAAAABBBAAAQQQAAwEAAAMBAAAAQQQAAAAAAABBBAAAQQQAAwEAAAMBAAABAQAAAwEAAABBBAAAQQQAAwEAAAMBAAABAQAAAwEAAABBBAADAQAAAEEEAAMBAAADAQAAAQEAAABBBAAAQQQAAwEAAAMBAAABAQAAAwEAAABBBAADAQAAAEEEAAMBAAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAABAQAAAwEAAABBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAAAQQQAAwEAAABBBAAAQQQAAwEAAAMBAAAAQQQAAwEAAABBBAABAQQAAEEEAAMBAAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAAAQQQAAwEAAABBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAABAQAAAQEEAABBBAAAQQQAAwEAAAMBAAABAQAAAQEEAABBBAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAAAQQQAAwEAAAMBAAABAQAAAQEEAABBBAADAQAAAEEEAAMBAAADAQAAAQEAAABBBAAAQQQAAwEAAAMBAAABAQAAAQEEAABBBAADAQAAAEEEAAMBAAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAABAQAAAQEEAABBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAAAQQQAAwEAAAMBAAABAQAAAQEEAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAwEAAAMBAAABAQAAAQEEAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAAAAAAAAEEEAAMBAAADAQAAAEEEAAMBAAAAAAAAAEEEAAMBAAAAAAAAAQEAAABBBAAAAAAAAEEEAAMBAAAAAAAAAQEAAABBBAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAAAAAAAAEEEAAMBAAAAAAAAAQEAAABBBAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAEEEAAMBAAAAAAAAAQEAAABBBAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAAAAAAAAEEEAAMBAAAAAAAAAEEEAABBBAAAAAAAAEEEAAMBAAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAADAQAAAEEEAAMBAAABAQQAAEEEAAMBAAADAQAAAEEEAAMBAAADAQAAAQEAAABBBAADAQAAAEEEAAMBAAADAQAAAQEAAABBBAABAQAAAwEAAABBBAABAQAAAQEEAABBBAADAQAAAEEEAAMBAAAAAAAAAEEEAABBBAADAQAAAEEEAAMBAAAAAAAAAEEEAABBBAABAQAAAQEEAAMBAAABAQAAAwEAAABBBAADAQAAAEEEAAMBAAAAAAAAAEEEAABBBAABAQAAAwEAAABBBAABAQAAAQEEAABBBAADAQAAAEEEAAMBAAADAQAAAEEEAABBBAADAQAAAEEEAAMBAAADAQAAAEEEAABBBAABAQAAAwEAAABBBAABAQAAAQEEAABBBAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAABAQQAAEEEAAMBAAABAQQAAQEAAABBBAABAQQAAEEEAAMBAAABAQQAAQEAAABBBAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AABAQQAAEEEAAMBAAABAQQAAQEAAABBBAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAEEEAAMBAAABAQQAAQEAAABBBAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAEEEAAMBAAADAQAAAEEEAABBBAABAQQAAEEEAAMBAAADAQAAAEEEAABBBAAAQQQAAQEEAAMBAAAAQQQAAwEAAABBBAABAQQAAEEEAAMBAAADAQAAAEEEAABBBAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAABAQQAAEEEAAMBAAABAQQAAEEEAABBBAABAQQAAEEEAAMBAAABAQQAAEEEAABBBAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AABAQQAAEEEAAMBAAABAQQAAEEEAABBBAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAABAQQAAEEEAAMBAAABAQQAAEEEAABBBAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAEEEAAMBAAABAQQAAEEEAABBBAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAAAQQQAAQEEAAMBABcM6QQXDikFAJAHAAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAAAQQQAAQEEAAMBABcM6QQXDikFAJAHAAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAABAQAAAQEEAAMBAAAAQQQAAQEEAAMBAAABAQAAAQEEAAMBAAAAQQQAAQEEAAMBAAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAABAQAAAQEEAAMBAAABAQAAAwEAAABBBAABAQAAAQEEAAMBAAABAQAAAwEAAABBBAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAABAQAAAQEEAAMBAAABAQAAAwEAAABBBAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAQEEAAMBAAABAQAAAwEAAABBBAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAABAQAAAQEEAAMBAAABAQAAAQEEAABBBAABAQAAAQEEAAMBAAABAQAAAQEEAABBBAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAABAQAAAQEEAAMBAAABAQAAAQEEAABBBAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAQEEAAMBAAABAQAAAQEEAABBBAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAAAQQQAAQEEAAMBABcM6QQXDikFAJAHAAAAQQQAAQEEAAMBAAAAQQQAAwEAAABBBAAAQQQAAQEEAAMBAAAAQQQAAwEAAABBBAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAAAQQQAAQEEAAMBAAAAQQQAAwEAAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAQEEAAMBAAAAQQQAAwEAAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAAAQQQAAQEEAAMBAAABAQAAAQEEAABBBAAAQQQAAQEEAAMBAAABAQAAAQEEAABBBAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAAAQQQAAQEEAAMBAAABAQAAAQEEAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAQEEAAMBAAABAQAAAQEEAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAAAQQQAAQEEAAMBAAAAQQQAAQEEAABBBAAAQQQAAQEEAAMBAAAAQQQAAQEEAABBBAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAAAQQQAAQEEAAMBAAAAQQQAAQEEAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAQEEAAMBAAAAQQQAAQEEAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAABAQAAAAAAAABBBAAAQQQAAAAAAABBBAABAQAAAAAAAABBBAAAQQQAAAAAAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAAAAAAAAQEAAABBBAADAQAAAQEAAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAAAAAAAAQEAAABBBAAAAAAAAEEEAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAAAAAAAAQEAAABBBAAAAAAAAQEAAAEBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAADAQAAAQEAAABBBAAAAAAAAQEAAAEBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAABAQAAAAAAAABBBAABAQAAAwEAAABBBAABAQAAAAAAAABBBAABAQAAAAAAAAEBBAABAQAAAAAAAABBBAABAQAAAAAAAAEBBAABAQAAAAAAAABBBAABAQAAAAAAAAEBBAABAQAAAAAAAABBBAABAQAAAAAAAAEBBAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAABAQAAAAAAAAMBAWJ+nPhUMq8BAJAHAAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAADAQAAAQEAAABBBAABAQQAAQEAAABBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAADAQAAAQEAAABBBAADAQAAAQEAAAEBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAABAQQAAQEAAABBBAADAQAAAQEAAAEBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAADAQAAAEEEAABBBAADAQAAAQEAAAEBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAAAQQQAAAAAAABBBAAAQQQAAwEAAABBBAAAQQQAAAAAAABBBAABAQAAAAAAAAEBBAAAQQQAAAAAAABBBAABAQAAAAAAAAEBBAAAQQQAAAAAAABBBAABAQAAAAAAAAEBBAAAQQQAAAAAAABBBAABAQAAAAAAAAEBBAAAQQQAAAAAAABBBAAAQQQAAAAAAAEBBAAAQQQAAAAAAABBBAAAQQQAAAAAAAEBBAAAQQQAAAAAAABBBAAAQQQAAAAAAAEBBAAAQQQAAAAAAABBBAAAQQQAAAAAAAEBBAAAQQQAAAAAAABBBAABAQAAAwEAAAEBBAAAQQQAAAAAAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAAAQQQAAAAAAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAADAQAAAQEAAAEBBAAAQQQAAAAAAABBBAABAQAAAwEAAAEBBAAAQQQAAAAAAABBBAABAQAAAwEAAAEBBAADAQAAAEEEAABBBAADAQAAAQEAAAEBBAAAQQQAAAAAAABBBAABAQAAAwEAAAEBBAAAQQQAAAAAAABBBAABAQAAAwEAAAEBBAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAAAAAAMBABcM6QRUMq8BAJAHAAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAAAAAAQEAAABBBAADAQAAAQEAAABBBAAAAAAAAQEAAABBBAAAAAAAAEEEAABBBAAAAAAAAQEAAABBBAAAAAAAAEEEAABBBAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAQEAAABBBAAAAAAAAEEEAABBBAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAAAAAAAAQEAAABBBAAAAAAAAEEEAABBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAQEAAABBBAAAAAAAAEEEAABBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAQEAAABBBAAAAAAAAEEEAABBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAAAAAAAAQEAAABBBAAAAAAAAQEAAAEBBAAAAAAAAQEAAABBBAAAAAAAAQEAAAEBBAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAAAAAAAAQEAAABBBAAAAAAAAQEAAAEBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAQEAAABBBAAAAAAAAQEAAAEBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAADAQAAAQEAAABBBAABAQQAAQEAAABBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAABAQAAAwEAAABBBAAAQQQAAwEAAABBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAABAQAAAwEAAABBBAABAQAAAQEEAABBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAABAQAAAwEAAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAAAQQQAAwEAAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAADAQAAAEEEAABBBAABAQAAAQEEAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAAAAAAAAQEAAAEBBAADAQAAAQEAAABBBAAAAAAAAQEAAAEBBAABAQAAAwEAAABBBAABAQAAAAAAAAEBBAADAQAAAQEAAABBBAAAAAAAAQEAAAEBBAABAQAAAwEAAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAAAAAAAAQEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAADAQAAAQEAAAEBBAADAQAAAQEAAABBBAADAQAAAQEAAAEBBAAAQQQAAwEAAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAADAQAAAQEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAAAAAAAAEEEAAEBBAADAQAAAQEAAABBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBBAABAQAAAQEEAABBBAADAQAAAQEAAABBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBBAABAQAAAAAAAAEBBAADAQAAAQEAAABBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAAAAAAAAEEEAAEBBAABAQAAAQEEAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAABBBAAAAAAAAEEEAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAABAQQAAQEAAABBBAABAQQAAEEEAABBBAABAQQAAQEAAABBBAABAQQAAEEEAABBBAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AABAQQAAQEAAABBBAABAQQAAEEEAABBBAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAABAQQAAQEAAABBBAABAQQAAEEEAABBBAAAQQQAAwEAAABBBAAAQQQAAwEAAAEBBAABAQQAAQEAAABBBAABAQQAAEEEAABBBAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAQEAAABBBAABAQQAAEEEAABBBAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAQEAAABBBAABAQQAAEEEAABBBAAAQQQAAQEEAABBBAAAQQQAAwEAAAEBBAABAQQAAQEAAABBBAABAQQAAEEEAABBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAABAQQAAQEAAABBBAABAQQAAEEEAABBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AABAQQAAQEAAABBBAADAQAAAQEAAAEBBAABAQQAAQEAAABBBAADAQAAAQEAAAEBBAAAQQQAAwEAAABBBAAAQQQAAAAAAAEBBAABAQQAAQEAAABBBAADAQAAAQEAAAEBBAAAQQQAAwEAAABBBAAAQQQAAwEAAAEBBAABAQQAAQEAAABBBAADAQAAAQEAAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAABAQQAAQEAAABBBAABAQQAAQEAAAEBBAABAQQAAQEAAABBBAABAQQAAQEAAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAABAQQAAQEAAABBBAABAQQAAQEAAAEBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAABAQQAAQEAAABBBAADAQAAAEEEAAEBBAABAQQAAQEAAABBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAABAQQAAQEAAABBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAAAQQQAAAAAAAEBBAABAQQAAQEAAABBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAAAQQQAAwEAAAEBBAABAQQAAQEAAABBBAADAQAAAEEEAAEBBAAAQQQAAQEEAABBBAAAQQQAAwEAAAEBBAABAQQAAQEAAABBBAADAQAAAEEEAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AABAQAAAwEAAABBBAAAQQQAAwEAAABBBAABAQAAAwEAAABBBAABAQAAAQEEAABBBAABAQAAAwEAAABBBAABAQAAAQEEAABBBAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAABAQAAAwEAAABBBAABAQAAAQEEAABBBAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAwEAAABBBAABAQAAAQEEAABBBAAAAAAAAEEEAABBBAADAQAAAEEEAABBBAABAQAAAwEAAABBBAABAQAAAQEEAABBBAAAAAAAAEEEAABBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBBAABAQAAAQEEAABBBAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAABAQAAAwEAAABBBAABAQAAAQEEAABBBAADAQAAAEEEAABBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBBAABAQAAAAAAAAEBBAABAQAAAwEAAABBBAABAQAAAAAAAAEBBAABAQAAAwEAAABBBAABAQAAAAAAAAEBBAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBBAABAQAAAAAAAAEBBAABAQAAAwEAAABBBAABAQAAAAAAAAEBBAABAQAAAwEAAABBBAABAQAAAwEAAAEBBAABAQAAAwEAAABBBAABAQAAAwEAAAEBBAADAQAAAEEEAABBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBBAABAQAAAwEAAAEBBAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAADAQAAAEEEAABBBAABAQQAAEEEAABBBAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAADAQAAAEEEAABBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAABAQQAAEEEAABBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAwEAAABBBAAAQQQAAQEEAABBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAwEAAABBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAABBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAABBBAAAQQQAAAAAAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAABBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAABBBAABAQAAAwEAAAEBBAAAQQQAAwEAAABBBAABAQAAAwEAAAEBBAADAQAAAEEEAABBBAADAQAAAQEAAAEBBAAAQQQAAwEAAABBBAABAQAAAwEAAAEBBAADAQAAAEEEAABBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAABAQAAAwEAAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAAAQQQAAwEAAAEBBAAAQQQAAwEAAABBBAAAQQQAAwEAAAEBBAABAQQAAEEEAABBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAAAQQQAAwEAAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAABAQAAAQEEAAEBBAAAQQQAAwEAAABBBAABAQAAAQEEAAEBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAwEAAABBBAABAQAAAQEEAAEBBAADAQAAAEEEAABBBAADAQAAAQEAAAEBBAAAQQQAAwEAAABBBAABAQAAAQEEAAEBBAADAQAAAEEEAABBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAABAQAAAQEEAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAAAQQQAAwEAAABBBAABAQAAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAwEAAABBBAABAQAAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAwEAAAMBAsJhCQQAAwEBIKF/AAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAAAAAAAAEEEAABBBAADAQAAAEEEAABBBAAAAAAAAEEEAABBBAAAAAAAAQEAAAEBBAAAAAAAAEEEAABBBAAAAAAAAQEAAAEBBAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAAAAAAAAEEEAABBBAAAAAAAAQEAAAEBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAEEEAABBBAAAAAAAAQEAAAEBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAAAAAAAAEEEAABBBAAAAAAAAEEEAAEBBAAAAAAAAEEEAABBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAwEAAAMBAICwmvgAAwEBIKF/AAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAAAAAAAAEEEAAMBAFQyrwAXDOkFAJAHAAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AADAQAAAEEEAABBBAABAQQAAEEEAABBBAADAQAAAEEEAABBBAADAQAAAQEAAAEBBAADAQAAAEEEAABBBAADAQAAAQEAAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAADAQAAAEEEAABBBAAAAAAAAEEEAAEBBAADAQAAAEEEAABBBAAAAAAAAEEEAAEBBAABAQAAAQEEAABBBAABAQAAAwEAAAEBBAADAQAAAEEEAABBBAAAAAAAAEEEAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAADAQAAAEEEAABBBAADAQAAAEEEAAEBBAADAQAAAEEEAABBBAADAQAAAEEEAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AADAQAAAEEEAAMBAAADAQLCYQkFIKF/AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAABAQQAAEEEAABBBAABAQQAAQEAAAEBBAABAQQAAEEEAABBBAABAQQAAQEAAAEBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAABAQQAAEEEAABBBAABAQQAAQEAAAEBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAEEEAABBBAABAQQAAQEAAAEBBAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAEEEAABBBAADAQAAAEEEAAEBBAABAQQAAEEEAABBBAADAQAAAEEEAAEBBAAAQQQAAQEEAABBBAAAQQQAAwEAAAEBBAABAQQAAEEEAABBBAADAQAAAEEEAAEBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAABAQQAAEEEAABBBAABAQQAAEEEAAEBBAABAQQAAEEEAABBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAABAQQAAEEEAABBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAABAQQAAEEEAABBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAEEEAABBBAABAQQAAEEEAAEBBAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAABAQAAAQEEAABBBAAAQQQAAQEEAABBBAABAQAAAQEEAABBBAAAQQQAAQEEAABBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQAAAQEEAABBBAABAQAAAwEAAAEBBAABAQAAAQEEAABBBAABAQAAAwEAAAEBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQAAAQEEAABBBAABAQAAAwEAAAEBBAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAQEEAABBBAABAQAAAwEAAAEBBAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQAAAQEEAABBBAABAQAAAQEEAAEBBAABAQAAAQEEAABBBAABAQAAAQEEAAEBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQAAAQEEAABBBAABAQAAAQEEAAEBBAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAQEEAABBBAABAQAAAQEEAAEBBAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAABAQAAAQEEAAMBAWJ+nPgXDikFAJAHAAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAAAQQQAAQEEAABBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAABBBAAAQQQAAwEAAAEBBAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAQEEAABBBAAAQQQAAwEAAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAQEEAABBBAAAQQQAAwEAAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAQEEAABBBAABAQAAAQEEAAEBBAAAQQQAAQEEAABBBAABAQAAAQEEAAEBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAQEEAABBBAABAQAAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAQEEAABBBAABAQAAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AAAQQQAAQEEAABBBAAAQQQAAQEEAAEBBAAAQQQAAQEEAABBBAAAQQQAAQEEAAEBBAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAQEEAABBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAQEEAABBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAAAQQQAAQEEAAMBABcM6QQXDikFAJAHAAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAABAQQAAEEEAAMBABcOKQQXDOkFAJAHAAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAABAQAAAAAAAAEBBAAAQQQAAAAAAAEBBAABAQAAAAAAAAEBBAAAQQQAAAAAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAAAAAAAAQEAAAEBBAADAQAAAQEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAABAQAAAAAAAABBBsKqqvlZV1cBUVRVAAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAADAQAAAQEAAAEBBAABAQQAAQEAAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAABBBVlVFQVZV1cBUVRVAAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAAAAAAQEAAAEBBAADAQAAAQEAAAEBBAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AADAQAAAQEAAAEBBAABAQQAAQEAAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAABAQAAAwEAAAEBBAAAQQQAAwEAAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAwEAAAEBBAAAQQQAAwEAAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAAAAAAAAEEEAAEBBAADAQAAAEEEAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAwEAAABBB3o1XQQAAwEAAQ2Q9AAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAAAAAAAAEEEAAEBBAADAQAAAEEEAAEBBAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAwEAAABBB9G68vwAAwEAAQ2Q9AAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAAAAAAAAEEEAABBBVlXVwFZVRUFUVRVAAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAADAQAAAEEEAAEBBAABAQQAAEEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAADAQAAAEEEAABBBAADAQN6NV0EAQ2Q9AADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAABAQAAAQEEAAEBBAAAQQQAAQEEAAEBBAABAQAAAQEEAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAABAQAAAQEEAABBBsKqqvlZVlUFUVRVAAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAAAQQQAAQEEAABBBVlVFQVZVlUFUVRVAAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAABAQQAAEEEAABBBVlWVQVZVRUFUVRVAAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAABAQAAAAAAAAEBBAAAQQQAAAAAAAEBBAABAQAAAAAAAAEBBAAAQQQAAAAAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAAAAAAAAQEAAAEBBAADAQAAAQEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAAAAAAAAQEAAAEBBAAAAAAAAQEAAAHBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAADAQAAAQEAAAEBBAAAAAAAAQEAAAHBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAABAQAAAAAAAAEBBAABAQAAAwEAAAEBBAABAQAAAAAAAAEBBAABAQAAAAAAAAHBBAABAQAAAAAAAAEBBAABAQAAAAAAAAHBBAABAQAAAAAAAAEBBAABAQAAAAAAAAHBBAABAQAAAAAAAAEBBAABAQAAAAAAAAHBBAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAADAQAAAQEAAAEBBAABAQQAAQEAAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAADAQAAAQEAAAEBBAADAQAAAQEAAAHBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAABAQQAAQEAAAEBBAADAQAAAQEAAAHBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAADAQAAAEEEAAEBBAADAQAAAQEAAAHBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAEBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAEBBAABAQAAAAAAAAHBBAAAQQQAAAAAAAEBBAABAQAAAAAAAAHBBAAAQQQAAAAAAAEBBAABAQAAAAAAAAHBBAAAQQQAAAAAAAEBBAABAQAAAAAAAAHBBAAAQQQAAAAAAAEBBAAAQQQAAAAAAAHBBAAAQQQAAAAAAAEBBAAAQQQAAAAAAAHBBAAAQQQAAAAAAAEBBAAAQQQAAAAAAAHBBAAAQQQAAAAAAAEBBAAAQQQAAAAAAAHBBAAAQQQAAAAAAAEBBAABAQAAAwEAAAHBBAAAQQQAAAAAAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAAAQQQAAAAAAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAADAQAAAQEAAAHBBAAAQQQAAAAAAAEBBAABAQAAAwEAAAHBBAAAQQQAAAAAAAEBBAABAQAAAwEAAAHBBAADAQAAAEEEAAEBBAADAQAAAQEAAAHBBAAAQQQAAAAAAAEBBAABAQAAAwEAAAHBBAAAQQQAAAAAAAEBBAABAQAAAwEAAAHBBAAAAAAAAQEAAAEBBAADAQAAAQEAAAEBBAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAQEAAAEBBAAAAAAAAEEEAAEBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAAAAAAAAQEAAAEBBAAAAAAAAQEAAAHBBAAAAAAAAQEAAAEBBAAAAAAAAQEAAAHBBAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAAAAAAAAQEAAAEBBAAAAAAAAQEAAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAQEAAAEBBAAAAAAAAQEAAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAADAQAAAQEAAAEBBAABAQQAAQEAAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAABAQAAAwEAAAEBBAAAQQQAAwEAAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAABAQAAAwEAAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAAAQQQAAwEAAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAADAQAAAEEEAAEBBAABAQAAAQEEAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAAAAAAAAQEAAAHBBAADAQAAAQEAAAEBBAAAAAAAAQEAAAHBBAABAQAAAwEAAAEBBAABAQAAAAAAAAHBBAADAQAAAQEAAAEBBAAAAAAAAQEAAAHBBAABAQAAAwEAAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAAAAAAAAQEAAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAADAQAAAQEAAAHBBAADAQAAAQEAAAEBBAADAQAAAQEAAAHBBAAAQQQAAwEAAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAADAQAAAQEAAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAAAAAAAAEEEAAHBBAADAQAAAQEAAAEBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAADAQAAAQEAAAEBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBAABAQAAAAAAAAHBBAADAQAAAQEAAAEBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAAAAAAAAEEEAAHBBAABAQAAAQEEAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAEBBAAAAAAAAEEEAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBAAAQQQAAwEAAAHBBAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAAAQQQAAQEEAAEBBAAAQQQAAwEAAAHBBAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAABAQQAAQEAAAEBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAABAQQAAQEAAAEBBAADAQAAAQEAAAHBBAABAQQAAQEAAAEBBAADAQAAAQEAAAHBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAHBBAABAQQAAQEAAAEBBAADAQAAAQEAAAHBBAAAQQQAAwEAAAEBBAAAQQQAAwEAAAHBBAABAQQAAQEAAAEBBAADAQAAAQEAAAHBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAABAQQAAQEAAAEBBAABAQQAAQEAAAHBBAABAQQAAQEAAAEBBAABAQQAAQEAAAHBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAABAQQAAQEAAAEBBAABAQQAAQEAAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAABAQQAAQEAAAEBBAADAQAAAEEEAAHBBAABAQQAAQEAAAEBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAABAQQAAQEAAAEBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAHBBAABAQQAAQEAAAEBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAAAQQQAAwEAAAHBBAABAQQAAQEAAAEBBAADAQAAAEEEAAHBBAAAQQQAAQEEAAEBBAAAQQQAAwEAAAHBBAABAQQAAQEAAAEBBAADAQAAAEEEAAHBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAwEAAAEBBAAAQQQAAwEAAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAAAAAAAAEEEAAEBBAADAQAAAEEEAAEBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAAAAAAAAEEEAAEBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBAABAQAAAQEEAAEBBAADAQAAAEEEAAEBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBAABAQAAAAAAAAHBBAABAQAAAwEAAAEBBAABAQAAAAAAAAHBBAABAQAAAwEAAAEBBAABAQAAAAAAAAHBBAAAAAAAAQEAAAHBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBAABAQAAAAAAAAHBBAABAQAAAwEAAAEBBAABAQAAAAAAAAHBBAABAQAAAwEAAAEBBAABAQAAAwEAAAHBBAABAQAAAwEAAAEBBAABAQAAAwEAAAHBBAADAQAAAEEEAAEBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBAABAQAAAwEAAAHBBAAAAAAAAQEAAAHBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAABAQQAAEEEAAEBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAABAQQAAEEEAAEBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAAAQQQAAwEAAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAwEAAAEBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAHBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAEBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAEBBAABAQAAAwEAAAHBBAAAQQQAAwEAAAEBBAABAQAAAwEAAAHBBAADAQAAAEEEAAEBBAADAQAAAQEAAAHBBAAAQQQAAwEAAAEBBAABAQAAAwEAAAHBBAADAQAAAEEEAAEBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAABAQAAAwEAAAHBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAAAQQQAAwEAAAHBBAAAQQQAAwEAAAEBBAAAQQQAAwEAAAHBBAABAQQAAEEEAAEBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAAAQQQAAwEAAAHBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAABAQAAAQEEAAHBBAAAQQQAAwEAAAEBBAABAQAAAQEEAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAwEAAAEBBAABAQAAAQEEAAHBBAADAQAAAEEEAAEBBAADAQAAAQEAAAHBBAAAQQQAAwEAAAEBBAABAQAAAQEEAAHBBAADAQAAAEEEAAEBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAABAQAAAQEEAAHBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAEBBAABAQAAAQEEAAHBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAAAQQQAAwEAAAEBBAABAQAAAQEEAAHBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAAAAAAAAEEEAAEBBAADAQAAAEEEAAEBBAAAAAAAAEEEAAEBBAAAAAAAAQEAAAHBBAAAAAAAAEEEAAEBBAAAAAAAAQEAAAHBBAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAAAAAAAAEEEAAEBBAAAAAAAAQEAAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAEEEAAEBBAAAAAAAAQEAAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAAAAAAAAEEEAAEBBAAAAAAAAEEEAAHBBAAAAAAAAEEEAAEBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAADAQAAAEEEAAEBBAABAQQAAEEEAAEBBAADAQAAAEEEAAEBBAADAQAAAQEAAAHBBAADAQAAAEEEAAEBBAADAQAAAQEAAAHBBAABAQAAAwEAAAHBBAABAQAAAQEEAAHBBAADAQAAAEEEAAEBBAAAAAAAAEEEAAHBBAADAQAAAEEEAAEBBAAAAAAAAEEEAAHBBAABAQAAAQEEAAEBBAABAQAAAwEAAAHBBAADAQAAAEEEAAEBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAHBBAABAQAAAQEEAAHBBAADAQAAAEEEAAEBBAADAQAAAEEEAAHBBAADAQAAAEEEAAEBBAADAQAAAEEEAAHBBAABAQAAAwEAAAHBBAABAQAAAQEEAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAABAQQAAEEEAAEBBAABAQQAAQEAAAHBBAABAQQAAEEEAAEBBAABAQQAAQEAAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAABAQQAAEEEAAEBBAABAQQAAQEAAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAEEEAAEBBAABAQQAAQEAAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAEEEAAEBBAADAQAAAEEEAAHBBAABAQQAAEEEAAEBBAADAQAAAEEEAAHBBAAAQQQAAQEEAAEBBAAAQQQAAwEAAAHBBAABAQQAAEEEAAEBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAHBBAAAQQQAAQEEAAHBBAABAQQAAEEEAAEBBAABAQQAAEEEAAHBBAABAQQAAEEEAAEBBAABAQQAAEEEAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAABAQQAAEEEAAEBBAABAQQAAEEEAAHBBAAAQQQAAwEAAAHBBAAAQQQAAQEEAAHBBAABAQQAAEEEAAEBBAABAQQAAEEEAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAEEEAAEBBAABAQQAAEEEAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAABAQAAAQEEAAEBBAAAQQQAAQEEAAEBBAABAQAAAQEEAAEBBAAAQQQAAQEEAAEBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQAAAQEEAAEBBAABAQAAAwEAAAHBBAABAQAAAQEEAAEBBAABAQAAAwEAAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQAAAQEEAAEBBAABAQAAAwEAAAHBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAQEEAAEBBAABAQAAAwEAAAHBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQAAAQEEAAEBBAABAQAAAQEEAAHBBAABAQAAAQEEAAEBBAABAQAAAQEEAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQAAAQEEAAEBBAABAQAAAQEEAAHBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAQEEAAEBBAABAQAAAQEEAAHBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAAAQQQAAQEEAAEBBAAAQQQAAwEAAAHBBAAAQQQAAQEEAAEBBAAAQQQAAwEAAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAAAQQQAAQEEAAEBBAAAQQQAAwEAAAHBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAAAQQQAAQEEAAEBBAAAQQQAAwEAAAHBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAAAQQQAAQEEAAEBBAABAQAAAQEEAAHBBAAAQQQAAQEEAAEBBAABAQAAAQEEAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAQEEAAEBBAABAQAAAQEEAAHBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAAAQQQAAQEEAAEBBAABAQAAAQEEAAHBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAAAQQQAAQEEAAEBBAAAQQQAAQEEAAHBBAAAQQQAAQEEAAEBBAAAQQQAAQEEAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAAAQQQAAQEEAAEBBAAAQQQAAQEEAAHBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAAAQQQAAQEEAAEBBAAAQQQAAQEEAAHBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAABAQAAAAAAAAHBBAAAQQQAAAAAAAHBBAABAQAAAAAAAAHBBAAAQQQAAAAAAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAAAAAAAAQEAAAHBBAADAQAAAQEAAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAAAAAAAAQEAAAHBBAAAAAAAAEEEAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAAAAAAAAQEAAAHBBAAAAAAAAQEAAAJBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAADAQAAAQEAAAHBBAAAAAAAAQEAAAJBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAABAQAAAAAAAAHBBAABAQAAAwEAAAHBBAABAQAAAAAAAAHBBAABAQAAAAAAAAJBBAABAQAAAAAAAAHBBAABAQAAAAAAAAJBBAABAQAAAAAAAAHBBAABAQAAAAAAAAJBBAABAQAAAAAAAAHBBAABAQAAAAAAAAJBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAABAQAAAAAAAAEBBzI6Kv7OjAsFNXP1AAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAADAQAAAQEAAAHBBAABAQQAAQEAAAHBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAADAQAAAQEAAAHBBAADAQAAAQEAAAJBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAABAQQAAQEAAAHBBAADAQAAAQEAAAJBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAADAQAAAEEEAAHBBAADAQAAAQEAAAJBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAAAQQQAAAAAAAHBBAAAQQQAAwEAAAHBBAAAQQQAAAAAAAHBBAABAQAAAAAAAAJBBAAAQQQAAAAAAAHBBAABAQAAAAAAAAJBBAAAQQQAAAAAAAHBBAABAQAAAAAAAAJBBAAAQQQAAAAAAAHBBAABAQAAAAAAAAJBBAAAQQQAAAAAAAHBBAAAQQQAAAAAAAJBBAAAQQQAAAAAAAHBBAAAQQQAAAAAAAJBBAAAQQQAAAAAAAHBBAAAQQQAAAAAAAJBBAAAQQQAAAAAAAHBBAAAQQQAAAAAAAJBBAAAQQQAAAAAAAHBBAABAQAAAwEAAAJBBAAAQQQAAAAAAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAAAQQQAAAAAAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAADAQAAAQEAAAJBBAAAQQQAAAAAAAHBBAABAQAAAwEAAAJBBAAAQQQAAAAAAAHBBAABAQAAAwEAAAJBBAADAQAAAEEEAAHBBAADAQAAAQEAAAJBBAAAQQQAAAAAAAHBBAABAQAAAwEAAAJBBAAAQQQAAAAAAAHBBAABAQAAAwEAAAJBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAAAAAAEBB2lFRQbOjAsFNXP1AAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAAAAAAQEAAAHBBAADAQAAAQEAAAHBBAAAAAAAAQEAAAHBBAAAAAAAAEEEAAHBBAAAAAAAAQEAAAHBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAQEAAAHBBAAAAAAAAEEEAAHBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAAAAAAAAQEAAAHBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAAAAAAAAQEAAAHBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAQEAAAHBBAAAAAAAAEEEAAHBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAAAAAAAAQEAAAHBBAAAAAAAAQEAAAJBBAAAAAAAAQEAAAHBBAAAAAAAAQEAAAJBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAAAAAAAAQEAAAHBBAAAAAAAAQEAAAJBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAAAAAAAAQEAAAHBBAAAAAAAAQEAAAJBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAADAQAAAQEAAAHBBAABAQQAAQEAAAHBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAABAQAAAwEAAAHBBAAAQQQAAwEAAAHBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAABAQAAAwEAAAHBBAABAQAAAQEEAAHBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAABAQAAAwEAAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAAAQQQAAwEAAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAADAQAAAEEEAAHBBAABAQAAAQEEAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAAAAAAAAQEAAAJBBAADAQAAAQEAAAHBBAAAAAAAAQEAAAJBBAABAQAAAwEAAAHBBAABAQAAAAAAAAJBBAADAQAAAQEAAAHBBAAAAAAAAQEAAAJBBAABAQAAAwEAAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAAAAAAAAQEAAAJBBAABAQAAAAAAAAJBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAADAQAAAQEAAAJBBAADAQAAAQEAAAHBBAADAQAAAQEAAAJBBAAAQQQAAwEAAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAADAQAAAQEAAAJBBAABAQAAAAAAAAJBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAAAAAAAAEEEAAJBBAADAQAAAQEAAAHBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAHBBAABAQAAAQEEAAHBBAADAQAAAQEAAAHBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAHBBAABAQAAAAAAAAJBBAADAQAAAQEAAAHBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAAAAAAAAEEEAAJBBAABAQAAAQEEAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAHBBAAAAAAAAEEEAAJBBAABAQAAAAAAAAJBBAABAQAAAwEAAAJBBAABAQQAAQEAAAHBBAABAQQAAEEEAAHBBAABAQQAAQEAAAHBBAABAQQAAEEEAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAABAQQAAQEAAAHBBAABAQQAAEEEAAHBBAAAQQQAAwEAAAHBBAAAQQQAAQEEAAHBBAABAQQAAQEAAAHBBAABAQQAAEEEAAHBBAAAQQQAAwEAAAHBBAAAQQQAAwEAAAJBBAABAQQAAQEAAAHBBAABAQQAAEEEAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAQEAAAHBBAABAQQAAEEEAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAQEAAAHBBAABAQQAAEEEAAHBBAAAQQQAAQEEAAHBBAAAQQQAAwEAAAJBBAABAQQAAQEAAAHBBAABAQQAAEEEAAHBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAABAQQAAQEAAAHBBAABAQQAAEEEAAHBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAABAQQAAQEAAAHBBAADAQAAAQEAAAJBBAABAQQAAQEAAAHBBAADAQAAAQEAAAJBBAAAQQQAAwEAAAHBBAAAQQQAAAAAAAJBBAABAQQAAQEAAAHBBAADAQAAAQEAAAJBBAAAQQQAAwEAAAHBBAAAQQQAAwEAAAJBBAABAQQAAQEAAAHBBAADAQAAAQEAAAJBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAABAQQAAQEAAAHBBAABAQQAAQEAAAJBB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AAAQQQAAwEAAAHBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAHBBAAAQQQAAAAAAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAAAQQQAAwEAAAHBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAHBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAHBBAABAQAAAwEAAAJBBAAAQQQAAwEAAAHBBAABAQAAAwEAAAJBBAADAQAAAEEEAAHBBAADAQAAAQEAAAJBBAAAQQQAAwEAAAHBBAABAQAAAwEAAAJBBAADAQAAAEEEAAHBBAADAQAAAEEEAAJBBAAAQQQAAwEAAAHBBAABAQAAAwEAAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAAAQQQAAwEAAAHBBAAAQQQAAwEAAAJBBAAAQQQAAwEAAAHBBAAAQQQAAwEAAAJBBAABAQQAAEEEAAHBBAADAQAAAEEEAAJBBAAAQQQAAwEAAAHBBAAAQQQAAwEAAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAAAQQQAAwEAAAHBBAABAQAAAQEEAAJBBAAAQQQAAwEAAAHBBAABAQAAAQEEAAJBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAAAQQQAAwEAAAHBBAABAQAAAQEEAAJBBAADAQAAAEEEAAHBBAADAQAAAQEAAAJBBAAAQQQAAwEAAAHBBAABAQAAAQEEAAJBBAADAQAAAEEEAAHBBAADAQAAAEEEAAJBBAAAQQQAAwEAAAHBBAABAQAAAQEEAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAAAQQQAAwEAAAHBBAABAQAAAQEEAAJBBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAAAQQQAAwEAAAHBBAABAQAAAQEEAAJBBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAwEAAAEBBjJGAQQAAwEDPuZ1AAAAQQQAAwEAAAHBBAACYQQAAwEAAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAAAAAAAAEEEAAHBBAADAQAAAEEEAAHBBAAAAAAAAEEEAAHBBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAHBBAAAAAAAAQEAAAJBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAAAAAAAAEEEAAHBBAAAAAAAAQEAAAJBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAAAAAAAAEEEAAHBBAAAAAAAAQEAAAJBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAAAAAAAAEEEAAHBBAAAAAAAAEEEAAJBBAAAAAAAAEEEAAHBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAwEAAAEBBMUaCwAAAwEDPuZ1AAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAAAAAAAAEEEAAEBBs6MCwdpRUUFNXP1AAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAADAQAAAEEEAAHBBAABAQQAAEEEAAHBBAADAQAAAEEEAAHBBAADAQAAAQEAAAJBBAADAQAAAEEEAAHBBAADAQAAAQEAAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAADAQAAAEEEAAHBBAAAAAAAAEEEAAJBBAADAQAAAEEEAAHBBAAAAAAAAEEEAAJBBAABAQAAAQEEAAHBBAABAQAAAwEAAAJBBAADAQAAAEEEAAHBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAADAQAAAEEEAAHBBAADAQAAAEEEAAJBBAADAQAAAEEEAAHBBAADAQAAAEEEAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAADAQAAAEEEAAEBBAADAQIyRgEHPuZ1AAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAABAQQAAEEEAAHBBAABAQQAAQEAAAJBBAABAQQAAEEEAAHBBAABAQQAAQEAAAJBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAABAQQAAEEEAAHBBAABAQQAAQEAAAJBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAQEEAAJBB2lFRQdpRoUHtqLBBAABAQQAAEEEAAHBBAABAQQAAQEAAAJBBAAAQQQAAQEEAAJBB2lFRQdpRoUHtqLBBAABAQQAAEEEAAHBBAADAQAAAEEEAAJBBAABAQQAAEEEAAHBBAADAQAAAEEEAAJBBAAAQQQAAQEEAAHBBAAAQQQAAwEAAAJBBAABAQQAAEEEAAHBBAADAQAAAEEEAAJBBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAABAQQAAEEEAAHBBAABAQQAAEEEAAJBBAABAQQAAEEEAAHBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAABAQQAAEEEAAHBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAABAQQAAEEEAAHBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAQEEAAJBB2lFRQdpRoUHtqLBBAABAQQAAEEEAAHBBAABAQQAAEEEAAJBBAAAQQQAAQEEAAJBB2lFRQdpRoUHtqLBBAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAAAQQQAAQEEAAJBB2lFRQdpRoUHtqLBBAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAAAQQQAAQEEAAJBB2lFRQdpRoUHtqLBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAABAQAAAQEEAAHBBAAAQQQAAQEEAAHBBAABAQAAAQEEAAHBBAAAQQQAAQEEAAHBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQAAAQEEAAHBBAABAQAAAwEAAAJBBAABAQAAAQEEAAHBBAABAQAAAwEAAAJBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQAAAQEEAAHBBAABAQAAAwEAAAJBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAABAQAAAQEEAAHBBAABAQAAAwEAAAJBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQAAAQEEAAHBBAABAQAAAQEEAAJBBAABAQAAAQEEAAHBBAABAQAAAQEEAAJBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQAAAQEEAAHBBAABAQAAAQEEAAJBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAABAQAAAQEEAAHBBAABAQAAAQEEAAJBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAABAQAAAQEEAAEBBzI6Kv9pRoUFNXP1AAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAABAQAAAQEEAAHBB9G68v96Np0EAAHBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAAAAAAAAEEEAAHBBvRsPwd6NV0EAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAAAQQQAAQEEAAHBBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAHBBAAAQQQAAwEAAAJBBAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAAAQQQAAQEEAAHBBAAAQQQAAwEAAAJBBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAAAQQQAAQEEAAHBBAAAQQQAAwEAAAJBBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAAAQQQAAQEEAAHBBAABAQAAAQEEAAJBBAAAQQQAAQEEAAHBBAABAQAAAQEEAAJBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAAAQQQAAQEEAAHBBAABAQAAAQEEAAJBBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAAAQQQAAQEEAAHBBAABAQAAAQEEAAJBBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAAAQQQAAQEEAAHBBAAAQQQAAQEEAAJBBAAAQQQAAQEEAAHBBAAAQQQAAQEEAAJBBAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAAAQQQAAQEEAAHBBAAAQQQAAQEEAAJBBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAAAQQQAAQEEAAHBBAAAQQQAAQEEAAJBBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAAAQQQAAQEEAAEBB2lFRQdpRoUFNXP1AAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAAAQQQAAQEEAAHBB3o1XQd6Np0EAAHBBAABAQQAAEEEAAHBB3o2nQd6NV0EAAHBBAABAQQAAEEEAAEBB2lGhQdpRUUFNXP1AAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAABAQAAAAAAAAJBBAAAQQQAAAAAAAJBBAABAQAAAAAAAAJBBAAAQQQAAAAAAAJBBAABAQAAAAAAAAJBBAABAQAAAwEAAAJBBAABAQAAAAAAAAJBBAABAQAAAwEAAAJBBAABAQAAAAAAAAJBBAABAQAAAwEAAAJBBAAAAAAAAQEAAAJBBAADAQAAAQEAAAJBBAABAQAAAAAAAAJBBAABAQAAAwEAAAJBBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAJBBAABAQAAAAAAAAJBBAABAQAAAwEAAAJBBAABAQAAAAAAAAJBBAABAQAAAwEAAAJBBAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAABAQAAAAAAAAHBB9G68v70bD8EAAHBBAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAADAQAAAQEAAAJBBAABAQQAAQEAAAJBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAAAAAAHBB3o1XQb0bD8EAAHBBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAAAAAAQEAAAJBBAADAQAAAQEAAAJBBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAJBBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAADAQAAAQEAAAJBBAABAQQAAQEAAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAABAQAAAwEAAAJBBAAAQQQAAwEAAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAQEEAAJBB2lFRQdpRoUHtqLBBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAAAQQQAAQEEAAJBB2lFRQdpRoUHtqLBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAABAQAAAwEAAAJBBAAAQQQAAwEAAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAAAAAAAAEEEAAJBBAADAQAAAEEEAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAADAQAAAEEEAAHBBAADAQAAAmEEAAHBBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAABAQAAAwEAAAHBBAADgwAAAwEAAAHBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAAAQQQAAwEAAAJBB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2lFRQbOjAsHtqLBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAADAQAAAQEAAAJBBAABAQQAAQEAAAJBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAADAQAAAQEAAAJBBAADAQAAAQEAAAKhBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAABAQQAAQEAAAJBBAADAQAAAQEAAAKhBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAADAQAAAEEEAAJBBAADAQAAAQEAAAKhBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAJBBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAJBBAABAQAAAAAAAAKhBAAAQQQAAAAAAAJBBAABAQAAAAAAAAKhBAAAQQQAAAAAAAJBBAABAQAAAAAAAAKhBAAAQQQAAAAAAAJBBAABAQAAAAAAAAKhBAAAQQQAAAAAAAJBBAAAQQQAAAAAAAKhBAAAQQQAAAAAAAJBBAAAQQQAAAAAAAKhBAAAQQQAAAAAAAJBBAAAQQQAAAAAAAKhBAAAQQQAAAAAAAJBBAAAQQQAAAAAAAKhBAAAQQQAAAAAAAJBBAABAQAAAwEAAAKhBAAAQQQAAAAAAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAAAQQQAAAAAAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAADAQAAAQEAAAKhBAAAQQQAAAAAAAJBBAABAQAAAwEAAAKhBAAAQQQAAAAAAAJBBAABAQAAAwEAAAKhBAADAQAAAEEEAAJBBAADAQAAAQEAAAKhBAAAQQQAAAAAAAJBBAABAQAAAwEAAAKhBAAAQQQAAAAAAAJBBAABAQAAAwEAAAKhBAAAAAAAAQEAAAJBBAADAQAAAQEAAAJBBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAJBBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAJBBAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAAAAAAAAQEAAAJBBAAAAAAAAEEEAAJBBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAAAAAAAAQEAAAJBBAAAAAAAAQEAAAKhBAAAAAAAAQEAAAJBBAAAAAAAAQEAAAKhBAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAAAAAAAAQEAAAJBBAAAAAAAAQEAAAKhBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAAAAAAAAQEAAAJBBAAAAAAAAQEAAAKhBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAADAQAAAQEAAAJBBAABAQQAAQEAAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAABAQAAAwEAAAJBBAAAQQQAAwEAAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAABAQAAAwEAAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAAAQQQAAwEAAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAADAQAAAEEEAAJBBAABAQAAAQEEAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAAAAAAAAQEAAAKhBAADAQAAAQEAAAJBBAAAAAAAAQEAAAKhBAABAQAAAwEAAAJBBAABAQAAAAAAAAKhBAADAQAAAQEAAAJBBAAAAAAAAQEAAAKhBAABAQAAAwEAAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAAAAAAAAQEAAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAADAQAAAQEAAAKhBAADAQAAAQEAAAJBBAADAQAAAQEAAAKhBAAAQQQAAwEAAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAADAQAAAQEAAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAAAAAAAAEEEAAKhBAADAQAAAQEAAAJBBAAAAAAAAEEEAAKhBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAADAQAAAQEAAAJBBAAAAAAAAEEEAAKhBAABAQAAAwEAAAJBBAABAQAAAAAAAAKhBAADAQAAAQEAAAJBBAAAAAAAAEEEAAKhBAABAQAAAwEAAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAAAAAAAAEEEAAKhBAABAQAAAQEEAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAJBBAAAAAAAAEEEAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAJBBAAAQQQAAwEAAAKhBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAAAQQQAAQEEAAJBBAAAQQQAAwEAAAKhBAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAABAQQAAQEAAAJBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAABAQQAAQEAAAJBBAADAQAAAQEAAAKhBAABAQQAAQEAAAJBBAADAQAAAQEAAAKhBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAKhBAABAQQAAQEAAAJBBAADAQAAAQEAAAKhBAAAQQQAAwEAAAJBBAAAQQQAAwEAAAKhBAABAQQAAQEAAAJBBAADAQAAAQEAAAKhBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAABAQQAAQEAAAJBBAABAQQAAQEAAAKhBAABAQQAAQEAAAJBBAABAQQAAQEAAAKhBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAABAQQAAQEAAAJBBAABAQQAAQEAAAKhBAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAABAQQAAQEAAAJBBAADAQAAAEEEAAKhBAABAQQAAQEAAAJBBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAABAQQAAQEAAAJBBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAKhBAABAQQAAQEAAAJBBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAAAQQQAAwEAAAKhBAABAQQAAQEAAAJBBAADAQAAAEEEAAKhBAAAQQQAAQEEAAJBBAAAQQQAAwEAAAKhBAABAQQAAQEAAAJBBAADAQAAAEEEAAKhBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAABAQAAAwEAAAJBBAAAQQQAAwEAAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAAAAAAAAEEEAAJBBAADAQAAAEEEAAJBBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAAAAAAAAEEEAAJBBAAAAAAAAEEEAAKhBAABAQAAAwEAAAJBBAABAQAAAQEEAAJBBAADAQAAAEEEAAJBBAAAAAAAAEEEAAKhBAABAQAAAwEAAAJBBAABAQAAAAAAAAKhBAABAQAAAwEAAAJBBAABAQAAAAAAAAKhBAABAQAAAwEAAAJBBAABAQAAAAAAAAKhBAAAAAAAAQEAAAKhBAAAAAAAAEEEAAKhBAABAQAAAwEAAAJBBAABAQAAAAAAAAKhBAABAQAAAwEAAAJBBAABAQAAAAAAAAKhBAABAQAAAwEAAAJBBAABAQAAAwEAAAKhBAABAQAAAwEAAAJBBAABAQAAAwEAAAKhBAADAQAAAEEEAAJBBAAAAAAAAEEEAAKhBAABAQAAAwEAAAJBBAABAQAAAwEAAAKhBAAAAAAAAQEAAAKhBAAAAAAAAEEEAAKhBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAAAAAAAAEEEAAJBBs6MCwdpRUUHtqLBBAAAQQQAAwEAAAJBBjJGAQQAAwECMkchBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAADAQAAAEEEAAJBBAABAQQAAEEEAAJBBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAADAQAAAEEEAAJBBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAABAQQAAEEEAAJBBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAADAQAAAEEEAAKhBAADAQN6NV0Heje9BAAAQQQAAwEAAAJBBAAAQQQAAQEEAAJBBAADAQAAAEEEAAKhBAADAQN6NV0Heje9BAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAKhBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAJBBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAJBBAABAQAAAwEAAAKhBAAAQQQAAwEAAAJBBAABAQAAAwEAAAKhBAADAQAAAEEEAAJBBAADAQAAAQEAAAKhBAAAQQQAAwEAAAJBBAABAQAAAwEAAAKhBAADAQAAAEEEAAJBBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAABAQAAAwEAAAKhBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAAAQQQAAwEAAAKhBAAAQQQAAwEAAAJBBAAAQQQAAwEAAAKhBAABAQQAAEEEAAJBBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAAAQQQAAwEAAAKhBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAAAQQQAAwEAAAJBBAABAQAAAQEEAAKhBAAAQQQAAwEAAAJBBAABAQAAAQEEAAKhBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAAAQQQAAwEAAAJBBAABAQAAAQEEAAKhBAADAQAAAEEEAAJBBAADAQAAAQEAAAKhB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AADAQN6NV0Heje9BAABAQQAAEEEAAJBB2lGhQdpRUUHtqLBBAAAQQQAAQEEAAJBBAABAQAAAQEEAAKhBAAAQQQAAQEEAAJBBAABAQAAAQEEAAKhBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAAAQQQAAQEEAAJBBAABAQAAAQEEAAKhBAADAQAAAEEEAAKhBAADAQN6NV0Heje9BAAAQQQAAQEEAAJBBAABAQAAAQEEAAKhBAADAQAAAEEEAAKhBAADAQN6NV0Heje9BAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAAAQQQAAQEEAAJBBAAAQQQAAQEEAAKhBAAAQQQAAQEEAAJBBAAAQQQAAQEEAAKhBAABAQQAAEEEAAJBB2lGhQdpRUUHtqLBBAAAQQQAAQEEAAJBBAAAQQQAAQEEAAKhBAADAQAAAEEEAAKhBAADAQN6NV0Heje9BAAAQQQAAQEEAAJBBAAAQQQAAQEEAAKhBAADAQAAAEEEAAKhBAADAQN6NV0Heje9BAABAQQAAEEEAAJBB2lGhQdpRUUHtqLBBAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAABAQAAAAAAAAKhBAAAQQQAAAAAAAKhBAABAQAAAAAAAAKhBAAAQQQAAAAAAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAAAAAAAAQEAAAKhBAADAQAAAQEAAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAAAAAAAAQEAAAKhBAAAAAAAAEEEAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAAAAAAAAQEAAAKhBAAAAAAAAQEAAAMBBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAADAQAAAQEAAAKhBAAAAAAAAQEAAAMBBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAABAQAAAAAAAAKhBAABAQAAAwEAAAKhBAABAQAAAAAAAAKhBAABAQAAAAAAAAMBBAABAQAAAAAAAAKhBAABAQAAAAAAAAMBBAABAQAAAAAAAAKhBAABAQAAAAAAAAMBBAABAQAAAAAAAAKhBAABAQAAAAAAAAMBBAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAABAQAAAAAAAAJBBzI6Kv7OjAsHtqLBBAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAADAQAAAQEAAAKhBAABAQQAAQEAAAKhBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAADAQAAAQEAAAKhBAADAQAAAQEAAAMBBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAABAQQAAQEAAAKhBAADAQAAAQEAAAMBBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAADAQAAAEEEAAKhBAADAQAAAQEAAAMBBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAAAQQQAAAAAAAKhBAAAQQQAAwEAAAKhBAAAQQQAAAAAAAKhBAABAQAAAAAAAAMBBAAAQQQAAAAAAAKhBAABAQAAAAAAAAMBBAAAQQQAAAAAAAKhBAABAQAAAAAAAAMBBAAAQQQAAAAAAAKhBAABAQAAAAAAAAMBBAAAQQQAAAAAAAKhBAAAQQQAAAAAAAMBBAAAQQQAAAAAAAKhBAAAQQQAAAAAAAMBBAAAQQQAAAAAAAKhBAAAQQQAAAAAAAMBBAAAQQQAAAAAAAKhBAAAQQQAAAAAAAMBBAAAQQQAAAAAAAKhBAABAQAAAwEAAAMBBAAAQQQAAAAAAAKhBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAAAQQQAAAAAAAKhBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAADAQAAAQEAAAMBBAAAQQQAAAAAAAKhBAABAQAAAwEAAAMBBAAAQQQAAAAAAAKhBAABAQAAAwEAAAMBBAADAQAAAEEEAAKhBAADAQAAAQEAAAMBBAAAQQQAAAAAAAKhBAABAQAAAwEAAAMBBAAAQQQAAAAAAAKhBAABAQAAAwEAAAMBBAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAAAAAAJBB2lFRQbOjAsHtqLBBAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAAAAAAAAQEAAAKhBAADAQAAAQEAAAKhBAAAAAAAAQEAAAKhBAAAAAAAAEEEAAKhBAAAAAAAAQEAAAKhBAAAAAAAAEEEAAKhBAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAAAAAAAAQEAAAKhBAAAAAAAAEEEAAKhBAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAAAAAAAAQEAAAKhBAAAAAAAAEEEAAKhBAABAQAAAwEAAAKhB9G68vwAAwEDeje9BAAAAAAAAQEAAAKhBAAAAAAAAEEEAAKhBAABAQAAAwEAAAKhB9G68vwAAwEDeje9BAABAQAAAwEAAAJBBMUaCwAAAwECMkchBAAAAAAAAQEAAAKhBAAAAAAAAEEEAAKhBAABAQAAAwEAAAKhB9G68vwAAwEDeje9BAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAAAAAAAAQEAAAKhBAAAAAAAAQEAAAMBBAAAAAAAAQEAAAKhBAAAAAAAAQEAAAMBBAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAAAAAAAAQEAAAKhBAAAAAAAAQEAAAMBBAABAQAAAwEAAAKhB9G68vwAAwEDeje9BAAAAAAAAQEAAAKhBAAAAAAAAQEAAAMBBAABAQAAAwEAAAKhB9G68vwAAwEDeje9BAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAADAQAAAQEAAAKhBAABAQQAAQEAAAKhBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAABAQAAAwEAAAKhBAAAQQQAAwEAAAKhBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAABAQAAAwEAAAKhBAABAQAAAQEEAAKhBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAABAQAAAwEAAAKhBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAAAQQQAAwEAAAKhBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAADAQAAAEEEAAKhBAABAQAAAQEEAAKhBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAAAAAAAAQEAAAMBBAADAQAAAQEAAAKhBAAAAAAAAQEAAAMBBAABAQAAAwEAAAKhBAABAQAAAAAAAAMBBAADAQAAAQEAAAKhBAAAAAAAAQEAAAMBBAABAQAAAwEAAAKhBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAAAAAAAAQEAAAMBBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAADAQAAAQEAAAMBBAADAQAAAQEAAAKhBAADAQAAAQEAAAMBBAAAQQQAAwEAAAKhBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAADAQAAAQEAAAMBBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAAAAAAAAEEEAAMBBAADAQAAAQEAAAKhBAAAAAAAAEEEAAMBBAABAQAAAwEAAAKhBAABAQAAAQEEAAKhBAADAQAAAQEAAAKhBAAAAAAAAEEEAAMBBAABAQAAAwEAAAKhBAABAQAAAAAAAAMBBAADAQAAAQEAAAKhBAAAAAAAAEEEAAMBBAABAQAAAwEAAAKhBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAAAAAAAAEEEAAMBBAABAQAAAQEEAAKhBAABAQAAAwEAAAMBBAADAQAAAQEAAAKhBAAAAAAAAEEEAAMBBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAABAQQAAQEAAAKhBAABAQQAAEEEAAKhBAABAQQAAQEAAAKhBAABAQQAAEEEAAKhBAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAABAQQAAQEAAAKhBAABAQQAAEEEAAKhBAAAQQQAAwEAAAKhBAAAQQQAAQEEAAKhBAABAQQAAQEAAAKhBAABAQQAAEEEAAKhBAAAQQQAAwEAAAKhBAAAQQQAAwEAAAMBBAABAQQAAQEAAAKhBAABAQQAAEEEAAKhBAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAAAQQQAAQEEAAKhBVlVFQVZVlUFWVd1BAABAQQAAQEAAAKhBAABAQQAAEEEAAKhBAAAQQQAAQEEAAKhBVlVFQVZVlUFWVd1BAABAQQAAQEAAAKhBAABAQQAAEEEAAKhBAAAQQQAAQEEAAKhBAAAQQQAAwEAAAMBBAABAQQAAQEAAAKhBAABAQQAAEEEAAKhBAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAABAQQAAQEAAAKhBAABAQQAAEEEAAKhBAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAABAQQAAQEAAAKhBAADAQAAAQEAAAMBBAABAQQAAQEAAAKhBAADAQAAAQEAAAMBBAAAQQQAAwEAAAKhBAAAQQQAAAAAAAMBBAABAQQAAQEAAAKhBAADAQAAAQEAAAMBBAAAQQQAAwEAAAKhBAAAQQQAAwEAAAMBBAABAQQAAQEAAAKhBAADAQAAAQEAAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAABAQQAAQEAAAKhBAABAQQAAQEAAAMBBAABAQQAAQEAAAKhBAABAQQAAQEAAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAABAQQAAQEAAAKhBAABAQQAAQEAAAMBBAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAABAQQAAQEAAAKhBAADAQAAAEEEAAMBBAABAQQAAQEAAAKhBAADAQAAAEEEAAMBBAAAQQQAAwEAAAKhBAAAQQQAAQEEAAKhBAABAQQAAQEAAAKhBAADAQAAAEEEAAMBBAAAQQQAAwEAAAKhBAAAQQQAAAAAAAMBBAABAQQAAQEAAAKhBAADAQAAAEEEAAMBBAAAQQQAAwEAAAKhBAAAQQQAAwEAAAMBBAABAQQAAQEAAAKhBAADAQAAAEEEAAMBBAAAQQQAAQEEAAKhBAAAQQQAAwEAAAMBBAABAQQAAQEAAAKhBAADAQAAAEEEAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAAAQQQAAwEAAAKhB3o1XQQAAwEDeje9BAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAABAQAAAwEAAAKhB9G68vwAAwEDeje9BAABAQAAAwEAAAKhBAAAQQQAAwEAAAKhBAABAQAAAwEAAAKhBAABAQAAAQEEAAKhBAABAQAAAwEAAAKhBAABAQAAAQEEAAKhBAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAABAQAAAwEAAAKhBAABAQAAAQEEAAKhBAAAAAAAAEEEAAKhBVlXVwFZVRUFWVd1BAABAQAAAwEAAAKhBAABAQAAAQEEAAKhBAAAAAAAAEEEAAKhBAADAQAAAEEEAAKhBAABAQAAAwEAAAKhBAABAQAAAQEEAAKhBAAAAAAAAEEEAAKhBAAAAAAAAEEEAAMBBAABAQAAAwEAAAKhBAABAQAAAQEEAAKhBAAAAAAAAEEEAAKhBVlXVwFZVRUFWVd1BAADAQAAAEEEAAJBBAADAQIyRgEGMkchBAABAQAAAwEAAAKhBAABAQAAAQEEAAKhBAADAQAAAEEEAAKhBAAAAAAAAEEEAAMBBAABAQAAAwEAAAKhBAABAQAAAAAAAAMBBAABAQAAAwEAAAKhBAABAQAAAAAAAAMBBAABAQAAAwEAAAKhBAABAQAAAAAAAAMBBAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAABAQAAAwEAAAKhBAABAQAAAAAAAAMBBAABAQAAAwEAAAKhBAABAQAAAAAAAAMBBAABAQAAAwEAAAKhBAABAQAAAwEAAAMBBAABAQAAAwEAAAKhBAABAQAAAwEAAAMBBAADAQAAAEEEAAKhBAAAAAAAAEEEAAMBBAABAQAAAwEAAAKhBAABAQAAAwEAAAMBBAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAABAQAAAwEAAAKhB9G68vwAAwEDeje9BAABAQAAAwEAAAJBB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WJ+nPhUMq8BEEgBCAABAQAAAAAAAAKhBsKqqvlZV1cBWVd1BAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAADAQAAAQEAAAMBBAABAQQAAQEAAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAAKhBVlVFQVZV1cBWVd1BAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAAAAAAAAQEAAAMBBAADAQAAAQEAAAMBBAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAABAQAAAwEAAAKhB9G68vwAAwEDeje9BAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAABAQAAAwEAAAKhB9G68vwAAwEDeje9BAADAQAAAQEAAAMBBAABAQQAAQEAAAMBBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAABAQAAAwEAAAMBBAAAQQQAAwEAAAMBBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAABAQAAAwEAAAMBBAABAQAAAQEEAAMBBAABAQQAAQEAAAMBBAABAQQAAEEEAAMBB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AAAQQQAAQEEAAMBBBcM6QQXDikFEEgBCAABAQQAAEEEAAMBBBcOKQQXDOkFEEgBCAAAQQQAAQEEAAMBBBcM6QQXDikFEEgBCAABAQQAAEEEAAMBBBcOKQQXDOkFEEgBCAABAQQAAEEEAAKhBVlWVQVZVRUFWVd1BAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAABAQAAAAAAAAMBBAAAQQQAAAAAAAMBBAABAQAAAAAAAAMBBAAAQQQAAAAAAAMBBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAAAAAAAAQEAAAMBBAADAQAAAQEAAAMBBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAAAAAAAAQEAAAMBBAAAAAAAAQEAAANhBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAADAQAAAQEAAAMBBAAAAAAAAQEAAANhBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAABAQAAAAAAAAMBBAABAQAAAwEAAAMBBAABAQAAAAAAAAMBBAABAQAAAAAAAANhBAABAQAAAAAAAAMBBAABAQAAAAAAAANhBAABAQAAAAAAAAMBBAABAQAAAAAAAANhBAABAQAAAAAAAAMBBAABAQAAAAAAAANhBAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAADAQAAAQEAAAMBBAABAQQAAQEAAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAADAQAAAQEAAAMBBAADAQAAAQEAAANhBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAABAQQAAQEAAAMBBAADAQAAAQEAAANhBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAADAQAAAEEEAAMBBAADAQAAAQEAAANhBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAAAQQQAAAAAAAMBBAAAQQQAAwEAAAMBBAAAQQQAAAAAAAMBBAABAQAAAAAAAANhBAAAQQQAAAAAAAMBBAABAQAAAAAAAANhBAAAQQQAAAAAAAMBBAABAQAAAAAAAANhBAAAQQQAAAAAAAMBBAABAQAAAAAAAANhBAAAQQQAAAAAAAMBBAAAQQQAAAAAAANhBAAAQQQAAAAAAAMBBAAAQQQAAAAAAANhBAAAQQQAAAAAAAMBBAAAQQQAAAAAAANhBAAAQQQAAAAAAAMBBAAAQQQAAAAAAANhBAAAQQQAAAAAAAMBBAABAQAAAwEAAANhBAAAQQQAAAAAAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAAAQQQAAAAAAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAADAQAAAQEAAANhBAAAQQQAAAAAAAMBBAABAQAAAwEAAANhBAAAQQQAAAAAAAMBBAABAQAAAwEAAANhBAADAQAAAEEEAAMBBAADAQAAAQEAAANhBAAAQQQAAAAAAAMBBAABAQAAAwEAAANhBAAAQQQAAAAAAAMBBAABAQAAAwEAAANhBAAAAAAAAQEAAAMBBAADAQAAAQEAAAMBBAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAAAAAAAAQEAAAMBBAAAAAAAAEEEAAMBBAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAAAAAAAAQEAAAMBBAAAAAAAAQEAAANhBAAAAAAAAQEAAAMBBAAAAAAAAQEAAANhBAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAAAAAAAAQEAAAMBBAAAAAAAAQEAAANhBAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAAAAAAAAQEAAAMBBAAAAAAAAQEAAANhBAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAADAQAAAQEAAAMBBAABAQQAAQEAAAMBBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAABAQAAAwEAAAMBBAAAQQQAAwEAAAMBBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAABAQAAAwEAAAMBBAABAQAAAQEEAAMBBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAABAQAAAwEAAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAAAQQQAAwEAAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAADAQAAAEEEAAMBBAABAQAAAQEEAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAAAAAAAAQEAAANhBAADAQAAAQEAAAMBBAAAAAAAAQEAAANhBAABAQAAAwEAAAMBBAABAQAAAAAAAANhBAADAQAAAQEAAAMBBAAAAAAAAQEAAANhBAABAQAAAwEAAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAAAAAAAAQEAAANhBAABAQAAAAAAAANhBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAADAQAAAQEAAANhBAADAQAAAQEAAAMBBAADAQAAAQEAAANhBAAAQQQAAwEAAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAADAQAAAQEAAANhBAABAQAAAAAAAANhBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAAAAAAAAEEEAANhBAADAQAAAQEAAAMBBAAAAAAAAEEEAANhBAABAQAAAwEAAAMBBAABAQAAAQEEAAMBBAADAQAAAQEAAAMBBAAAAAAAAEEEAANhBAABAQAAAwEAAAMBBAABAQAAAAAAAANhBAADAQAAAQEAAAMBBAAAAAAAAEEEAANhBAABAQAAAwEAAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAAAAAAAAEEEAANhBAABAQAAAQEEAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAAMBBAAAAAAAAEEEAANhBAABAQAAAAAAAANhBAABAQAAAwEAAANhBAABAQQAAQEAAAMBBAABAQQAAEEEAAMBBAABAQQAAQEAAAMBBAABAQQAAEEEAAMBBAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAABAQQAAQEAAAMBBAABAQQAAEEEAAMBBAAAQQQAAwEAAAMBBAAAQQQAAQEEAAMBBAABAQQAAQEAAAMBBAABAQQAAEEEAAMBBAAAQQQAAwEAAAMBBAAAQQQAAwEAAANhBAABAQQAAQEAAAMBBAABAQQAAEEEAAMBBAAAQQQAAQEEAAMBBAAAQQQAAwEAAANhBAABAQQAAQEAAAMBBAABAQQAAEEEAAMBBAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAABAQQAAQEAAAMBBAABAQQAAEEEAAMBBAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAABAQQAAQEAAAMBBAADAQAAAQEAAANhBAABAQQAAQEAAAMBBAADAQAAAQEAAANhBAAAQQQAAwEAAAMBBAAAQQQAAAAAAANhBAABAQQAAQEAAAMBBAADAQAAAQEAAANhBAAAQQQAAwEAAAMBBAAAQQQAAwEAAANhBAABAQQAAQEAAAMBBAADAQAAAQEAAANhBAAAQQQAAAAAAANhBAAAQQQAAwEAAANhBAABAQQAAQEAAAMBBAABAQQAAQEAAANhBAABAQQAAQEAAAMBBAABAQQAAQEAAANhBAAAQQQAAAAAAANhBAAAQQQAAwEAAANhBAABAQQAAQEAAAMBBAABAQQAAQEAAANhBAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAABAQQAAQEAAAMBBAADAQAAAEEEAANhBAABAQQAAQEAAAMBBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAAAQQQAAQEEAAMBBAABAQQAAQEAAAMBBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAAAQQQAAAAAAANhBAABAQQAAQEAAAMBBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAAAQQQAAwEAAANhBAABAQQAAQEAAAMBBAADAQAAAEEEAANhBAAAQQQAAQEEAAMBBAAAQQQAAwEAAANhBAABAQQAAQEAAAMBBAADAQAAAEEEAANhBAAAQQQAAAAAAANhBAAAQQQAAwEAAANhBAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAABAQAAAwEAAAMBBAAAQQQAAwEAAAMBBAABAQAAAwEAAAMBBAABAQAAAQEEAAMBBAABAQAAAwEAAAMBBAABAQAAAQEEAAMBBAAAAAAAAEEEAAMBBAADAQAAAEEEAAMBBAABAQAAAwEAAAMBBAABAQAAAQEEAAMBBAAAAAAAAEEEAAMBBAAAAAAAAEEEAANhBAABAQAAAwEAAAMBBAABAQAAAQEEAAMBBAADAQAAAEEEAAMBBAAAAAAAAEEEAANhBAABAQAAAwEAAAMBBAABAQAAAAAAAANhBAABAQAAAwEAAAMBBAABAQAAAAAAAANhBAABAQAAAwEAAAMBBAABAQAAAAAAAANhBAAAAAAAAQEAAANhBAAAAAAAAEEEAANhBAABAQAAAwEAAAMBBAABAQAAAAAAAANhBAABAQAAAwEAAAMBBAABAQAAAAAAAANhBAABAQAAAwEAAAMBBAABAQAAAwEAAANhBAABAQAAAwEAAAMBBAABAQAAAwEAAANhBAADAQAAAEEEAAMBBAAAAAAAAEEEAANhBAABAQAAAwEAAAMBBAABAQAAAwEAAANhBAAAAAAAAQEAAANhBAAAAAAAAEEEAANhBAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAABAQAAAAAAAAMBBWJ+nPhUMq8BEEgBCAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAAAAAAAAEEEAAMBBFQyrwAXDOkFEEgBCAAAQQQAAwEAAAMBBsJhCQQAAwECE8gVCAAAQQQAAwEAAAMBBAAAQQQAAQEEAAMBBAAAQQQAAwEAAAMBBAAAQQQAAQEEAAMBBAADAQAAAEEEAAMBBAADAQLCYQkGE8gVCAAAQQQAAwEAAAMBBAAAQQQAAQEEAAMBBAADAQAAAEEEAAMBBAABAQQAAEEEAAMBBAAAQQQAAwEAAAMBBAAAQQQAAQEEAAMBBAADAQAAAEEEAAMBBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAAAQQQAAQEEAAMBBAABAQQAAEEEAAMBBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAAAQQQAAQEEAAMBBAADAQAAAEEEAANhBAADAQELONkFCzhJCAAAQQQAAwEAAAMBBAAAQQQAAQEEAAMBBAADAQAAAEEEAANhBAADAQELONkFCzhJCAADAQAAAEEEAAMBBAADAQLCYQkGE8gVCAAAQQQAAwEAAAMBBAAAQQQAAAAAAANhBAAAQQQAAwEAAAMBBAAAQQQAAAAAAANhBAAAQQQAAwEAAAMBBAAAQQQAAAAAAANhBAADAQAAAQEAAANhBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAAAQQQAAAAAAANhBAAAQQQAAwEAAAMBBAAAQQQAAAAAAANhBAAAQQQAAwEAAAMBBAABAQAAAwEAAANhBAAAQQQAAwEAAAMBBAABAQAAAwEAAANhBAADAQAAAEEEAAMBBAADAQAAAQEAAANhBAAAQQQAAwEAAAMBBAABAQAAAwEAAANhBAADAQAAAEEEAAMBBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAABAQAAAwEAAANhBAADAQAAAQEAAANhBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAAAQQQAAwEAAANhBAAAQQQAAwEAAAMBBAAAQQQAAwEAAANhBAABAQQAAEEEAAMBBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAAAQQQAAwEAAANhBAADAQAAAQEAAANhBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAABAQAAAQEEAANhBAAAQQQAAwEAAAMBBAABAQAAAQEEAANhBAADAQAAAEEEAAMBBAADAQLCYQkGE8gVCAAAQQQAAwEAAAMBBAABAQAAAQEEAANhBAADAQAAAEEEAAMBBAADAQAAAQEAAANhBAAAQQQAAwEAAAMBBAABAQAAAQEEAANhBAADAQAAAEEEAAMBBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAABAQAAAQEEAANhBAADAQAAAQEAAANhBAADAQAAAEEEAANhBAAAQQQAAwEAAAMBBAABAQAAAQEEAANhBAADAQAAAEEEAANhBAADAQELONkFCzhJCAAAQQQAAwEAAAMBBAABAQAAAQEEAANhBAADAQAAAEEEAANhBAADAQELONkFCzhJCAADAQAAAEEEAAMBBAADAQLCYQkGE8gVCAAAAAAAAEEEAAMBBFQyrwAXDOkFEEgBCAAAAAAAAEEEAAMBBAADAQAAAEEEAAMBBAAAAAAAAEEEAAMBBAAAAAAAAQEAAANhB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AABAQAAAAAAAANhBvFxRP9Goi8A06g5CAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAABAQAAAAAAAANhBvFxRP9Goi8A06g5CAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBAAAQQQAAwEAAANhBAAAQQQAAAAAAANhBAAAQQQAAwEAAANhBAADAQAAAQEAAANhBAABAQQAAQEAAANhBAAAQQQAAAAAAANhBAAAQQQAAwEAAANhBAADAQAAAQEAAANhBAADAQAAAEEEAANhBAAAQQQAAAAAAANhBAAAQQQAAwEAAANhBAADAQAAAQEAAANhBAADAQAAAQEAAAPBBAAAQQQAAAAAAANhBAAAQQQAAwEAAANhBAABAQQAAQEAAANhBAADAQAAAQEAAAPBBAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAAMBBBcM6QRUMq8BEEgBCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAAAAAAQEAAANhBAADAQAAAQEAAANhBAAAAAAAAQEAAANhBAAAAAAAAEEEAANhBAAAAAAAAQEAAANhBAAAAAAAAEEEAANhBAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAAAAAAAAQEAAANhBAAAAAAAAEEEAANhBAABAQAAAAAAAANhBvFxRP9Goi8A06g5CAAAAAAAAQEAAANhBAAAAAAAAEEEAANhBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAAAAAAAAQEAAANhBAAAAAAAAEEEAANhBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAABAQAAAwEAAAMBBICwmvgAAwECE8gVCAAAAAAAAQEAAANhBAAAAAAAAEEEAANhBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAABAQAAAAAAAANhBvFxRP9Goi8A06g5CAAAAAAAAQEAAANhBAAAAAAAAQEAAAPBBAAAAAAAAQEAAANhBAAAAAAAAQEAAAPBBAABAQAAAAAAAANhBvFxRP9Goi8A06g5CAAAAAAAAQEAAANhBAAAAAAAAQEAAAPBBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAAAAAAAAQEAAANhBAAAAAAAAQEAAAPBBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAABAQAAAAAAAANhBvFxRP9Goi8A06g5CAADAQAAAQEAAANhBAABAQQAAQEAAANhBAADAQAAAQEAAANhBAADAQAAAEEEAANhBAADAQAAAQEAAANhBAADAQAAAEEEAANhBAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAADAQAAAQEAAANhBAADAQAAAEEEAANhBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAADAQAAAQEAAANhBAADAQAAAEEEAANhBAABAQAAAwEAAANhBAAAQQQAAwEAAANhBAADAQAAAQEAAANhBAADAQAAAEEEAANhBAABAQAAAwEAAANhBAABAQAAAQEEAANhBAADAQAAAQEAAANhBAADAQAAAEEEAANhBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAADAQAAAQEAAANhBAADAQAAAEEEAANhBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAABAQAAAQEEAANhBvFxRPzTqgkE06g5CAADAQAAAQEAAANhBAADAQAAAEEEAANhBAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAADAQAAAQEAAANhBAADAQAAAEEEAANhBAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAADAQAAAQEAAANhBAADAQAAAEEEAANhBAABAQAAAQEEAANhBvFxRPzTqgkE06g5CAADAQAAAQEAAANhBAAAAAAAAQEAAAPBBAADAQAAAQEAAANhBAAAAAAAAQEAAAPBBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAADAQAAAQEAAANhBAAAAAAAAEEEAAPBBAADAQAAAQEAAANhBAAAAAAAAEEEAAPBBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAADAQAAAQEAAANhBAAAAAAAAEEEAAPBBAABAQAAAwEAAANhB3BsTPwAAwEBCzhJCAABAQAAAQEEAANhBvFxRPzTqgkE06g5CAADAQAAAQEAAANhBAAAAAAAAEEEAAPBBAABAQAAAQEEAANhBvFxRPzTqgkE06g5CAADAQAAAQEAAANhBAADAQAAAQEAAAPBBAADAQAAAQEAAANhBAADAQAAAQEAAAPBBAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAADAQAAAQEAAANhBAADAQAAAQEAAAPBBAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAADAQAAAQEAAANhBAADAQAAAQEAAAPBBAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAAAQQQAAAAAAANhBNOoyQdGoi8A06g5CAABAQQAAQEAAANhBAABAQQAAEEEAANhBAABAQQAAQEAAANhBAABAQQAAEEEAANhBAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAABAQQAAQEAAANhBAABAQQAAEEEAANhBAAAQQQAAwEAAANhBQs42QQAAwEBCzhJCAAAQQQAAQEEAANhBNOoyQTTqgkE06g5CAABAQQAAQEAAANhBAABAQQAAEEEAANhBAAAQQQAAQEEAANhBNOoyQTTqgkE06g5CAABAQQAAQEAAANhBAADAQAAAQEAAAPBBAABAQQAAQEAAANhBAADAQAAAQEAAAPBBAAAQQQAAwEAAANhB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\"},{\"byteLength\":16032,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,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AADAQDFGgsDPuZ1AAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAAAAAAAAQEAAAHBBvRsPwfRuvL8AAHBBAAAAAAAAQEAAAHBBvRsPwfRuvL8AAHBBAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAAAAAAAAQEAAAHBBvRsPwfRuvL8AAHBBAAAAAAAAQEAAAHBBvRsPwfRuvL8AAHBBAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAAAAAAAAQEAAAEBBs6MCwcyOir9NXP1AAAAAAAAAQEAAAHBBvRsPwfRuvL8AAHBBAAAAAAAAQEAAAHBBvRsPwfRuvL8AAHBBAAAAAAAAQEAAAEBBs6MCwcyOir9NXP1AAABAQQAAQEAAAEBB2lGhQcyOir9NXP1AAADAQAAAQEAAAHBBAADAQAAA4MAAAHBBAADAQAAAQEAAAHBBAADAQAAA4MAAAHBBAABAQQAAQEAAAEBB2lGhQcyOir9NXP1AAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAADAQAAAQEAAAHBBAADAQAAA4MAAAHBBAADAQAAAQEAAAHBBAADAQAAA4MAAAHBBAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAABAQQAAQEAAAEBB2lGhQcyOir9NXP1AAADAQAAAQEAAAHBBAADAQAAA4MAAAHBBAADAQAAAQEAAAHBBAADAQAAA4MAAAHBBAABAQQAAQEAAAEBB2lGhQcyOir9NXP1AAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAADAQAAAQEAAAHBBAADAQAAA4MAAAHBBAADAQAAAQEAAAHBBAADAQAAA4MAAAHBBAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAAAAAAAAQEAAAEBBs6MCwcyOir9NXP1AAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAABAQQAAQEAAAEBB2lGhQcyOir9NXP1AAABAQQAAQEAAAEBB2lGhQcyOir9NXP1AAABAQQAAQEAAAEBB2lGhQcyOir9NXP1AAABAQQAAQEAAAEBB2lGhQcyOir9NXP1AAADAQAAAQEAAAEBBAADAQDFGgsDPuZ1AAAAAAAAAQEAAAHBBvRsPwfRuvL8AAHBBAAAAAAAAQEAAAHBBvRsPwfRuvL8AAHBB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FQyrwFifpz5EEgBCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAADAQAAAQEAAAMBBAADAQCAsJr6E8gVCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAAMBBAADAQCAsJr6E8gVCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAADAQAAAQEAAAMBBAADAQCAsJr6E8gVCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAAMBBAADAQCAsJr6E8gVCAAAAAAAAQEAAAMBBFQyrwFifpz5EEgBCAADAQAAAQEAAAMBBAADAQCAsJr6E8gVCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAADAQAAAQEAAAMBBAADAQCAsJr6E8gVCAAAAAAAAQEAAANhB0aiLwLxcUT806g5CAAAAAAAAQEAAANhB0aiLwLxcUT806g5CAADAQAAAQEAAAMBBAADAQCAsJr6E8gVCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAABAQQAAQEAAAMBBBcOKQVifpz5EEgBCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAAMBBAADAQCAsJr6E8gVCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAANhBAADAQNwbEz9CzhJCAADAQAAAQEAAAMBBAADAQCAsJr6E8gVCAAAAAAAAQEAAANhB0aiLwLxcUT806g5CAAAAAAAAQEAAANhB0aiLwLxcUT806g5C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\"}],\"materials\":[{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0.5,0.5,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0},\"material\":0,\"mode\":6},{\"attributes\":{\"POSITION\":1},\"material\":0,\"mode\":6},{\"attributes\":{\"POSITION\":2},\"material\":0,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":1,\"mode\":6},{\"attributes\":{\"POSITION\":4},\"material\":1,\"mode\":6},{\"attributes\":{\"POSITION\":5},\"material\":1,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":6},\"material\":2,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":7},\"material\":3,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[0,3,0]},{\"mesh\":1,\"translation\":[0,9,0]},{\"mesh\":0,\"translation\":[6,3,0]},{\"mesh\":1,\"translation\":[6,9,0]},{\"mesh\":0,\"translation\":[12,3,0]},{\"mesh\":1,\"translation\":[12,9,0]},{\"mesh\":1,\"translation\":[3,0,3]},{\"mesh\":1,\"translation\":[9,0,3]},{\"mesh\":0,\"translation\":[0,3,3]},{\"mesh\":0,\"translation\":[6,3,3]},{\"mesh\":0,\"translation\":[12,3,3]},{\"mesh\":1,\"translation\":[3,6,3]},{\"mesh\":1,\"translation\":[9,6,3]},{\"mesh\":1,\"translation\":[0,9,3]},{\"mesh\":1,\"translation\":[6,9,3]},{\"mesh\":1,\"translation\":[12,9,3]},{\"mesh\":1,\"translation\":[3,12,3]},{\"mesh\":1,\"translation\":[9,12,3]},{\"mesh\":1,\"translation\":[3,0,6]},{\"mesh\":1,\"translation\":[9,0,6]},{\"mesh\":0,\"translation\":[0,3,6]},{\"mesh\":0,\"translation\":[6,3,6]},{\"mesh\":0,\"translation\":[12,3,6]},{\"mesh\":1,\"translation\":[3,6,6]},{\"mesh\":1,\"translation\":[9,6,6]},{\"mesh\":1,\"translation\":[0,9,6]},{\"mesh\":1,\"translation\":[6,9,6]},{\"mesh\":1,\"translation\":[12,9,6]},{\"mesh\":1,\"translation\":[3,12,6]},{\"mesh\":1,\"translation\":[9,12,6]},{\"mesh\":1,\"translation\":[3,0,9]},{\"mesh\":1,\"translation\":[9,0,9]},{\"mesh\":0,\"translation\":[0,3,9]},{\"mesh\":0,\"translation\":[6,3,9]},{\"mesh\":0,\"translation\":[12,3,9]},{\"mesh\":1,\"translation\":[3,6,9]},{\"mesh\":1,\"translation\":[9,6,9]},{\"mesh\":1,\"translation\":[0,9,9]},{\"mesh\":1,\"translation\":[6,9,9]},{\"mesh\":1,\"translation\":[12,9,9]},{\"mesh\":1,\"translation\":[3,12,9]},{\"mesh\":1,\"translation\":[9,12,9]},{\"mesh\":1,\"translation\":[3,0,12]},{\"mesh\":1,\"translation\":[9,0,12]},{\"mesh\":0,\"translation\":[0,3,12]},{\"mesh\":0,\"translation\":[6,3,12]},{\"mesh\":0,\"translation\":[12,3,12]},{\"mesh\":1,\"translation\":[3,6,12]},{\"mesh\":1,\"translation\":[9,6,12]},{\"mesh\":1,\"translation\":[0,9,12]},{\"mesh\":1,\"translation\":[6,9,12]},{\"mesh\":1,\"translation\":[12,9,12]},{\"mesh\":1,\"translation\":[3,12,12]},{\"mesh\":1,\"translation\":[9,12,12]},{\"mesh\":1,\"translation\":[3,0,15]},{\"mesh\":1,\"translation\":[9,0,15]},{\"mesh\":0,\"translation\":[0,3,15]},{\"mesh\":0,\"translation\":[6,3,15]},{\"mesh\":0,\"translation\":[12,3,15]},{\"mesh\":1,\"translation\":[3,6,15]},{\"mesh\":1,\"translation\":[9,6,15]},{\"mesh\":1,\"translation\":[0,9,15]},{\"mesh\":1,\"translation\":[6,9,15]},{\"mesh\":1,\"translation\":[12,9,15]},{\"mesh\":1,\"translation\":[3,12,15]},{\"mesh\":1,\"translation\":[9,12,15]},{\"mesh\":1,\"translation\":[3,0,18]},{\"mesh\":1,\"translation\":[9,0,18]},{\"mesh\":0,\"translation\":[0,3,18]},{\"mesh\":0,\"translation\":[6,3,18]},{\"mesh\":0,\"translation\":[12,3,18]},{\"mesh\":1,\"translation\":[3,6,18]},{\"mesh\":1,\"translation\":[9,6,18]},{\"mesh\":1,\"translation\":[0,9,18]},{\"mesh\":1,\"translation\":[6,9,18]},{\"mesh\":1,\"translation\":[12,9,18]},{\"mesh\":1,\"translation\":[3,12,18]},{\"mesh\":1,\"translation\":[9,12,18]},{\"mesh\":1,\"translation\":[3,0,21]},{\"mesh\":1,\"translation\":[9,0,21]},{\"mesh\":0,\"translation\":[0,3,21]},{\"mesh\":0,\"translation\":[6,3,21]},{\"mesh\":0,\"translation\":[12,3,21]},{\"mesh\":1,\"translation\":[3,6,21]},{\"mesh\":1,\"translation\":[9,6,21]},{\"mesh\":1,\"translation\":[0,9,21]},{\"mesh\":1,\"translation\":[6,9,21]},{\"mesh\":1,\"translation\":[12,9,21]},{\"mesh\":1,\"translation\":[3,12,21]},{\"mesh\":1,\"translation\":[9,12,21]},{\"mesh\":1,\"translation\":[3,0,24]},{\"mesh\":1,\"translation\":[9,0,24]},{\"mesh\":0,\"translation\":[0,3,24]},{\"mesh\":0,\"translation\":[6,3,24]},{\"mesh\":0,\"translation\":[12,3,24]},{\"mesh\":1,\"translation\":[3,6,24]},{\"mesh\":1,\"translation\":[9,6,24]},{\"mesh\":1,\"translation\":[0,9,24]},{\"mesh\":1,\"translation\":[6,9,24]},{\"mesh\":1,\"translation\":[12,9,24]},{\"mesh\":1,\"translation\":[3,12,24]},{\"mesh\":1,\"translation\":[9,12,24]},{\"mesh\":1,\"translation\":[3,0,27]},{\"mesh\":1,\"translation\":[9,0,27]},{\"mesh\":0,\"translation\":[0,3,27]},{\"mesh\":0,\"translation\":[6,3,27]},{\"mesh\":0,\"translation\":[12,3,27]},{\"mesh\":1,\"translation\":[3,6,27]},{\"mesh\":1,\"translation\":[9,6,27]},{\"mesh\":1,\"translation\":[0,9,27]},{\"mesh\":1,\"translation\":[6,9,27]},{\"mesh\":1,\"translation\":[12,9,27]},{\"mesh\":1,\"translation\":[3,12,27]},{\"mesh\":1,\"translation\":[9,12,27]},{\"mesh\":0,\"translation\":[0,3,30]},{\"mesh\":1,\"translation\":[0,9,30]},{\"mesh\":0,\"translation\":[6,3,30]},{\"mesh\":1,\"translation\":[6,9,30]},{\"mesh\":0,\"translation\":[12,3,30]},{\"mesh\":1,\"translation\":[12,9,30]},{\"mesh\":2,\"translation\":[0,0,0]},{\"mesh\":3,\"translation\":[0,0,0]}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121]}]}"
  },
  {
    "path": "testdata/measurement_looping.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5625],\"min\":[0.25,0.5],\"name\":\"tex_coords_gate_M\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.4375],\"min\":[0.625,0.375],\"name\":\"tex_coords_gate_MPP:X\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.5],\"min\":[0.625,0.4375],\"name\":\"tex_coords_gate_MPP:Y\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[1,-0,-0],\"min\":[-7,-8,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":78,\"max\":[0,2.5,1],\"min\":[-5.25,-9,-1],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_M\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:X\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:Y\",\"target\":34962},{\"buffer\":4,\"byteLength\":144,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":5,\"byteLength\":936,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_M\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAAD8AAIA+AAAAPwAAoD4AABA/AACAPgAAAD8AAIA+AAAQPwAAoD4AABA/AACgPgAAED8AAKA+AAAAPwAAgD4AABA/AACAPgAAED8AAKA+AAAAPwAAgD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:X\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAwD4AACA/AADAPgAAMD8AAOA+AAAgPwAAwD4AACA/AADgPgAAMD8AAOA+AAAwPwAA4D4AADA/AADAPgAAID8AAOA+AAAgPwAA4D4AADA/AADAPgAAID8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:Y\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAA4D4AACA/AADgPgAAMD8AAAA/AAAgPwAA4D4AACA/AAAAPwAAMD8AAAA/AAAwPwAAAD8AADA/AADgPgAAID8AAAA/AAAgPwAAAD8AADA/AADgPgAAID8AAOA+\"},{\"byteLength\":144,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAwAAAAMEAAACAAACAwAAAwMAAAACAAACAPwAAAIAAAACAAADgwAAAAIAAAACAAACAPwAAAMAAAACAAADgwAAAAMAAAACAAACAPwAAgMAAAACAAADgwAAAgMAAAACAAACAPwAAwMAAAACAAADgwAAAwMAAAACAAACAPwAAAMEAAACAAADgwAAAAMEAAACA\"},{\"byteLength\":936,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACAAADgvwAAQD8AAEA/AADgvwAAQD8AAEC/AADgvwAAQD8AAEA/AADgvwAADMEAAEA/AADgvwAAQD8AAEA/AAAQwAAAQD8AAEA/AADgvwAAQD8AAEC/AADgvwAADMEAAEC/AADgvwAAQD8AAEC/AAAQwAAAQD8AAEC/AADgvwAADMEAAEA/AADgvwAADMEAAEC/AADgvwAADMEAAEA/AAAQwAAADMEAAEA/AADgvwAADMEAAEC/AAAQwAAADMEAAEC/AAAQwAAAQD8AAEA/AAAQwAAAQD8AAEC/AAAQwAAAQD8AAEA/AAAQwAAADMEAAEA/AAAQwAAAQD8AAEC/AAAQwAAADMEAAEC/AAAQwAAADMEAAEA/AAAQwAAADMEAAEC/AABwwAAAQD8AAEA/AABwwAAAQD8AAEC/AABwwAAAQD8AAEA/AABwwAAADMEAAEA/AABwwAAAQD8AAEA/AACIwAAAQD8AAEA/AABwwAAAQD8AAEC/AABwwAAADMEAAEC/AABwwAAAQD8AAEC/AACIwAAAQD8AAEC/AABwwAAADMEAAEA/AABwwAAADMEAAEC/AABwwAAADMEAAEA/AACIwAAADMEAAEA/AABwwAAADMEAAEC/AACIwAAADMEAAEC/AACIwAAAQD8AAEA/AACIwAAAQD8AAEC/AACIwAAAQD8AAEA/AACIwAAADMEAAEA/AACIwAAAQD8AAEC/AACIwAAADMEAAEC/AACIwAAADMEAAEA/AACIwAAADMEAAEC/AABAvwAAgD8AAIA/AABAvwAAgD8AAIC/AABAvwAAgD8AAIA/AABAvwAAEMEAAIA/AABAvwAAgD8AAIA/AACowAAAgD8AAIA/AABAvwAAgD8AAIC/AABAvwAAEMEAAIC/AABAvwAAgD8AAIC/AACowAAAgD8AAIC/AABAvwAAEMEAAIA/AABAvwAAEMEAAIC/AABAvwAAEMEAAIA/AACowAAAEMEAAIA/AABAvwAAEMEAAIC/AACowAAAEMEAAIC/AACowAAAgD8AAIA/AACowAAAgD8AAIC/AACowAAAgD8AAIA/AACowAAAEMEAAIA/AACowAAAgD8AAIC/AACowAAAEMEAAIC/AACowAAAEMEAAIA/AACowAAAEMEAAIC/\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":5},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":0,\"translation\":[-1,-2,-0]},{\"mesh\":0,\"translation\":[-2,-4,-0]},{\"mesh\":1,\"translation\":[-4,-6,-0]},{\"mesh\":2,\"translation\":[-4,-8,-0]},{\"mesh\":3,\"translation\":[0,0,0]},{\"mesh\":4,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/noise_gates_1.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.625],\"min\":[0.1875,0.5625],\"name\":\"tex_coords_gate_DEPOLARIZE1\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.625],\"min\":[0.25,0.5625],\"name\":\"tex_coords_gate_DEPOLARIZE2\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.4375],\"min\":[0.4375,0.375],\"name\":\"tex_coords_gate_X_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.5],\"min\":[0.4375,0.4375],\"name\":\"tex_coords_gate_Y_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.5625],\"min\":[0.4375,0.5],\"name\":\"tex_coords_gate_Z_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":18,\"max\":[1,-0,-0],\"min\":[-4,-10,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":6,\"max\":[0,2.5,-0],\"min\":[-3,1.5,-0],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_DEPOLARIZE1\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_DEPOLARIZE2\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_X_ERROR\",\"target\":34962},{\"buffer\":4,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Y_ERROR\",\"target\":34962},{\"buffer\":5,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Z_ERROR\",\"target\":34962},{\"buffer\":6,\"byteLength\":216,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":7,\"byteLength\":72,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_DEPOLARIZE1\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAED8AAEA+AAAQPwAAgD4AACA/AABAPgAAED8AAEA+AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AAAQPwAAQD4AACA/AABAPgAAID8AAIA+AAAQPwAAQD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_DEPOLARIZE2\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAED8AAIA+AAAQPwAAoD4AACA/AACAPgAAED8AAIA+AAAgPwAAoD4AACA/AACgPgAAID8AAKA+AAAQPwAAgD4AACA/AACAPgAAID8AAKA+AAAQPwAAgD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_X_ERROR\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAwD4AAOA+AADAPgAAAD8AAOA+AADgPgAAwD4AAOA+AADgPgAAAD8AAOA+AAAAPwAA4D4AAAA/AADAPgAA4D4AAOA+AADgPgAA4D4AAAA/AADAPgAA4D4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Y_ERROR\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAA4D4AAOA+AADgPgAAAD8AAAA/AADgPgAA4D4AAOA+AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AADgPgAA4D4AAAA/AADgPgAAAD8AAAA/AADgPgAA4D4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Z_ERROR\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAAD8AAOA+AAAAPwAAAD8AABA/AADgPgAAAD8AAOA+AAAQPwAAAD8AABA/AAAAPwAAED8AAAA/AAAAPwAA4D4AABA/AADgPgAAED8AAAA/AAAAPwAA4D4AAAA/\"},{\"byteLength\":216,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAvwAAAIAAAACAAACgvwAAAMAAAACAAACgvwAAAMAAAACAAACAvwAAgMAAAACAAACAvwAAAMEAAACAAACAvwAAIMEAAACAAACAPwAAAIAAAACAAACAwAAAAIAAAACAAACAPwAAAMAAAACAAACAwAAAAMAAAACAAACAPwAAgMAAAACAAACAwAAAgMAAAACAAACAPwAAwMAAAACAAACAwAAAwMAAAACAAACAPwAAAMEAAACAAACAwAAAAMEAAACAAACAPwAAIMEAAACAAACAwAAAIMEAAACA\"},{\"byteLength\":72,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACA\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":4},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":5},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":6},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":7},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":0,\"translation\":[-0,-2,-0]},{\"mesh\":1,\"translation\":[-1,-0,-0]},{\"mesh\":1,\"translation\":[-1,-4,-0]},{\"mesh\":1,\"translation\":[-1,-8,-0]},{\"mesh\":1,\"translation\":[-1,-10,-0]},{\"mesh\":2,\"translation\":[-2,-0,-0]},{\"mesh\":2,\"translation\":[-2,-2,-0]},{\"mesh\":2,\"translation\":[-2,-4,-0]},{\"mesh\":3,\"translation\":[-3,-0,-0]},{\"mesh\":3,\"translation\":[-3,-2,-0]},{\"mesh\":3,\"translation\":[-3,-8,-0]},{\"mesh\":4,\"translation\":[-3,-4,-0]},{\"mesh\":4,\"translation\":[-3,-6,-0]},{\"mesh\":4,\"translation\":[-3,-10,-0]},{\"mesh\":5,\"translation\":[0,0,0]},{\"mesh\":6,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/noise_gates_2.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.4375],\"min\":[0.5,0.375],\"name\":\"tex_coords_gate_E:X\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.5],\"min\":[0.5,0.4375],\"name\":\"tex_coords_gate_E:Y\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.5625],\"min\":[0.5,0.5],\"name\":\"tex_coords_gate_E:Z\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.4375],\"min\":[0.5625,0.375],\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:X\",\"type\":\"VEC2\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.5],\"min\":[0.5625,0.4375],\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Y\",\"type\":\"VEC2\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.5625],\"min\":[0.5625,0.5],\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Z\",\"type\":\"VEC2\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":22,\"max\":[1,-2,-0],\"min\":[-3,-10,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":8,\"byteOffset\":0,\"componentType\":5126,\"count\":6,\"max\":[0,0.5,-0],\"min\":[-3,-0.5,-0],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_E:X\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_E:Y\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_E:Z\",\"target\":34962},{\"buffer\":4,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:X\",\"target\":34962},{\"buffer\":5,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Y\",\"target\":34962},{\"buffer\":6,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Z\",\"target\":34962},{\"buffer\":7,\"byteLength\":264,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":8,\"byteLength\":72,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_E:X\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAwD4AAAA/AADAPgAAED8AAOA+AAAAPwAAwD4AAAA/AADgPgAAED8AAOA+AAAQPwAA4D4AABA/AADAPgAAAD8AAOA+AAAAPwAA4D4AABA/AADAPgAAAD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_E:Y\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAA4D4AAAA/AADgPgAAED8AAAA/AAAAPwAA4D4AAAA/AAAAPwAAED8AAAA/AAAQPwAAAD8AABA/AADgPgAAAD8AAAA/AAAAPwAAAD8AABA/AADgPgAAAD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_E:Z\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAAD8AAAA/AAAAPwAAED8AABA/AAAAPwAAAD8AAAA/AAAQPwAAED8AABA/AAAQPwAAED8AABA/AAAAPwAAAD8AABA/AAAAPwAAED8AABA/AAAAPwAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:X\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAwD4AABA/AADAPgAAID8AAOA+AAAQPwAAwD4AABA/AADgPgAAID8AAOA+AAAgPwAA4D4AACA/AADAPgAAED8AAOA+AAAQPwAA4D4AACA/AADAPgAAED8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Y\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAA4D4AABA/AADgPgAAID8AAAA/AAAQPwAA4D4AABA/AAAAPwAAID8AAAA/AAAgPwAAAD8AACA/AADgPgAAED8AAAA/AAAQPwAAAD8AACA/AADgPgAAED8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Z\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAAD8AABA/AAAAPwAAID8AABA/AAAQPwAAAD8AABA/AAAQPwAAID8AABA/AAAgPwAAED8AACA/AAAAPwAAED8AABA/AAAQPwAAED8AACA/AAAAPwAAED8AAAA/\"},{\"byteLength\":264,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAgAAAgMAAAACAAAAAgAAAAMAAAACAAACAvwAAgMAAAACAAACAvwAAAMAAAACAAACAvwAAwMAAAACAAACAvwAAgMAAAACAAAAAwAAAAMEAAACAAAAQwAAAwMAAAACAAAAQwAAAwMAAAACAAAAAwAAAgMAAAACAAAAAwAAAwMAAAACAAAAAwAAAAMEAAACAAACAPwAAAMAAAACAAABAwAAAAMAAAACAAACAPwAAgMAAAACAAABAwAAAgMAAAACAAACAPwAAwMAAAACAAABAwAAAwMAAAACAAACAPwAAAMEAAACAAABAwAAAAMEAAACAAACAPwAAIMEAAACAAABAwAAAIMEAAACA\"},{\"byteLength\":72,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAIAAAACAAABAwAAAAIAAAACAAAAgwAAAAL8AAACAAABAwAAAAIAAAACAAAAgwAAAAD8AAACAAABAwAAAAIAAAACA\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":4},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":5},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":6},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":7},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":8},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-2,-0]},{\"mesh\":0,\"translation\":[-0,-4,-0]},{\"mesh\":0,\"translation\":[-1,-2,-0]},{\"mesh\":1,\"translation\":[-1,-4,-0]},{\"mesh\":2,\"translation\":[-1,-6,-0]},{\"mesh\":3,\"translation\":[-2,-4,-0]},{\"mesh\":4,\"translation\":[-2,-8,-0]},{\"mesh\":5,\"translation\":[-2,-6,-0]},{\"mesh\":3,\"translation\":[-2,-10,-0]},{\"mesh\":6,\"translation\":[0,0,0]},{\"mesh\":7,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/noise_gates_3.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.625],\"min\":[0.5,0.5625],\"name\":\"tex_coords_gate_PAULI_CHANNEL_1\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.625],\"min\":[0.5625,0.5625],\"name\":\"tex_coords_gate_PAULI_CHANNEL_2\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":16,\"max\":[1,-0,-0],\"min\":[-2,-8,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":6,\"max\":[0,2.5,-0],\"min\":[-3,1.5,-0],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_PAULI_CHANNEL_1\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_PAULI_CHANNEL_2\",\"target\":34962},{\"buffer\":3,\"byteLength\":192,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":4,\"byteLength\":72,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_PAULI_CHANNEL_1\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAED8AAAA/AAAQPwAAED8AACA/AAAAPwAAED8AAAA/AAAgPwAAED8AACA/AAAQPwAAID8AABA/AAAQPwAAAD8AACA/AAAAPwAAID8AABA/AAAQPwAAAD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_PAULI_CHANNEL_2\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAED8AABA/AAAQPwAAID8AACA/AAAQPwAAED8AABA/AAAgPwAAID8AACA/AAAgPwAAID8AACA/AAAQPwAAED8AACA/AAAQPwAAID8AACA/AAAQPwAAED8AABA/\"},{\"byteLength\":192,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAvwAAAIAAAACAAACAvwAAAMAAAACAAACAvwAAgMAAAACAAACgvwAAwMAAAACAAACgvwAAwMAAAACAAACAvwAAAMEAAACAAACAPwAAAIAAAACAAAAAwAAAAIAAAACAAACAPwAAAMAAAACAAAAAwAAAAMAAAACAAACAPwAAgMAAAACAAAAAwAAAgMAAAACAAACAPwAAwMAAAACAAAAAwAAAwMAAAACAAACAPwAAAMEAAACAAAAAwAAAAMEAAACA\"},{\"byteLength\":72,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACA\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":0,\"translation\":[-0,-2,-0]},{\"mesh\":0,\"translation\":[-0,-4,-0]},{\"mesh\":0,\"translation\":[-0,-6,-0]},{\"mesh\":1,\"translation\":[-1,-0,-0]},{\"mesh\":1,\"translation\":[-1,-2,-0]},{\"mesh\":1,\"translation\":[-1,-4,-0]},{\"mesh\":1,\"translation\":[-1,-8,-0]},{\"mesh\":2,\"translation\":[0,0,0]},{\"mesh\":3,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/repeat.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.5],\"min\":[0.0625,0.4375],\"name\":\"tex_coords_gate_H\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.4375],\"min\":[0.3125,0.375],\"name\":\"tex_coords_gate_RX\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":8,\"max\":[1,-0,-0],\"min\":[-6,-6,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":54,\"max\":[0,2.5,1],\"min\":[-4.25,-7,-1],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_RX\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":4,\"byteLength\":648,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAA4D4AAIA9AADgPgAAAD4AAAA/AACAPQAA4D4AAIA9AAAAPwAAAD4AAAA/AAAAPgAAAD8AAAA+AADgPgAAgD0AAAA/AACAPQAAAD8AAAA+AADgPgAAgD0AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_RX\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAwD4AAKA+AADAPgAAwD4AAOA+AACgPgAAwD4AAKA+AADgPgAAwD4AAOA+AADAPgAA4D4AAMA+AADAPgAAoD4AAOA+AACgPgAA4D4AAMA+AADAPgAAoD4AAMA+\"},{\"byteLength\":96,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAPwAAAIAAAACAAADAwAAAAIAAAACAAACAPwAAAMAAAACAAADAwAAAAMAAAACAAACAPwAAgMAAAACAAADAwAAAgMAAAACAAACAPwAAwMAAAACAAADAwAAAwMAAAACA\"},{\"byteLength\":648,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACAAADgvwAAQD8AAEA/AADgvwAAQD8AAEC/AADgvwAAQD8AAEA/AADgvwAA2MAAAEA/AADgvwAAQD8AAEA/AABQwAAAQD8AAEA/AADgvwAAQD8AAEC/AADgvwAA2MAAAEC/AADgvwAAQD8AAEC/AABQwAAAQD8AAEC/AADgvwAA2MAAAEA/AADgvwAA2MAAAEC/AADgvwAA2MAAAEA/AABQwAAA2MAAAEA/AADgvwAA2MAAAEC/AABQwAAA2MAAAEC/AABQwAAAQD8AAEA/AABQwAAAQD8AAEC/AABQwAAAQD8AAEA/AABQwAAA2MAAAEA/AABQwAAAQD8AAEC/AABQwAAA2MAAAEC/AABQwAAA2MAAAEA/AABQwAAA2MAAAEC/AABAvwAAgD8AAIA/AABAvwAAgD8AAIC/AABAvwAAgD8AAIA/AABAvwAA4MAAAIA/AABAvwAAgD8AAIA/AACIwAAAgD8AAIA/AABAvwAAgD8AAIC/AABAvwAA4MAAAIC/AABAvwAAgD8AAIC/AACIwAAAgD8AAIC/AABAvwAA4MAAAIA/AABAvwAA4MAAAIC/AABAvwAA4MAAAIA/AACIwAAA4MAAAIA/AABAvwAA4MAAAIC/AACIwAAA4MAAAIC/AACIwAAAgD8AAIA/AACIwAAAgD8AAIC/AACIwAAAgD8AAIA/AACIwAAA4MAAAIA/AACIwAAAgD8AAIC/AACIwAAA4MAAAIC/AACIwAAA4MAAAIA/AACIwAAA4MAAAIC/\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":0,\"translation\":[-0,-2,-0]},{\"mesh\":0,\"translation\":[-0,-4,-0]},{\"mesh\":1,\"translation\":[-1,-4,-0]},{\"mesh\":0,\"translation\":[-2,-0,-0]},{\"mesh\":0,\"translation\":[-2,-2,-0]},{\"mesh\":0,\"translation\":[-2,-6,-0]},{\"mesh\":0,\"translation\":[-3,-6,-0]},{\"mesh\":2,\"translation\":[0,0,0]},{\"mesh\":3,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/repetition_code.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.5625],\"min\":[0.3125,0.5],\"name\":\"tex_coords_gate_R\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"control_x_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.5625],\"min\":[0.375,0.5],\"name\":\"tex_coords_gate_MR\",\"type\":\"VEC2\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5625],\"min\":[0.25,0.5],\"name\":\"tex_coords_gate_M\",\"type\":\"VEC2\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":26,\"max\":[1,-0,-0],\"min\":[-9,-8,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":8,\"byteOffset\":0,\"componentType\":5126,\"count\":30,\"max\":[0,2.5,1],\"min\":[-7.25,-9,-1],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_R\",\"target\":34962},{\"buffer\":2,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":3,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":4,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_x_line_cross\",\"target\":34962},{\"buffer\":5,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MR\",\"target\":34962},{\"buffer\":6,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_M\",\"target\":34962},{\"buffer\":7,\"byteLength\":312,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":8,\"byteLength\":360,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_R\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAAD8AAKA+AAAAPwAAwD4AABA/AACgPgAAAD8AAKA+AAAQPwAAwD4AABA/AADAPgAAED8AAMA+AAAAPwAAoD4AABA/AACgPgAAED8AAMA+AAAAPwAAoD4AAAA/\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_x_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzL4AAAAAAAAAAM3MzD4AAAAAAAAAAAAAAADNzMy+AAAAAAAAAADNzMw+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MR\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAAD8AAMA+AAAAPwAA4D4AABA/AADAPgAAAD8AAMA+AAAQPwAA4D4AABA/AADgPgAAED8AAOA+AAAAPwAAwD4AABA/AADAPgAAED8AAOA+AAAAPwAAwD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_M\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAAD8AAIA+AAAAPwAAoD4AABA/AACAPgAAAD8AAIA+AAAQPwAAoD4AABA/AACgPgAAED8AAKA+AAAAPwAAgD4AABA/AACAPgAAED8AAKA+AAAAPwAAgD4AAAA/\"},{\"byteLength\":312,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAvwAAAIAAAACAAACAvwAAAMAAAACAAACAvwAAgMAAAACAAACAvwAAwMAAAACAAAAAwAAAgMAAAACAAAAAwAAAAMAAAACAAAAAwAAAAMEAAACAAAAAwAAAwMAAAACAAACgwAAAAIAAAACAAACgwAAAAMAAAACAAACgwAAAgMAAAACAAACgwAAAwMAAAACAAADAwAAAgMAAAACAAADAwAAAAMAAAACAAADAwAAAAMEAAACAAADAwAAAwMAAAACAAACAPwAAAIAAAACAAAAQwQAAAIAAAACAAACAPwAAAMAAAACAAAAQwQAAAMAAAACAAACAPwAAgMAAAACAAAAQwQAAgMAAAACAAACAPwAAwMAAAACAAAAQwQAAwMAAAACAAACAPwAAAMEAAACAAAAQwQAAAMEAAACA\"},{\"byteLength\":360,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACAAABwwAAAgD8AAIA/AABwwAAAgD8AAIC/AABwwAAAgD8AAIA/AABwwAAAEMEAAIA/AABwwAAAgD8AAIA/AADowAAAgD8AAIA/AABwwAAAgD8AAIC/AABwwAAAEMEAAIC/AABwwAAAgD8AAIC/AADowAAAgD8AAIC/AABwwAAAEMEAAIA/AABwwAAAEMEAAIC/AABwwAAAEMEAAIA/AADowAAAEMEAAIA/AABwwAAAEMEAAIC/AADowAAAEMEAAIC/AADowAAAgD8AAIA/AADowAAAgD8AAIC/AADowAAAgD8AAIA/AADowAAAEMEAAIA/AADowAAAgD8AAIC/AADowAAAEMEAAIC/AADowAAAEMEAAIA/AADowAAAEMEAAIC/\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":2},\"material\":1,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":2,\"mode\":6},{\"attributes\":{\"POSITION\":3},\"material\":3,\"mode\":3},{\"attributes\":{\"POSITION\":4},\"material\":3,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":5},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":6},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":7},\"material\":4,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":8},\"material\":5,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":0,\"translation\":[-0,-2,-0]},{\"mesh\":0,\"translation\":[-0,-4,-0]},{\"mesh\":0,\"translation\":[-0,-6,-0]},{\"mesh\":0,\"translation\":[-0,-8,-0]},{\"mesh\":1,\"translation\":[-1,-0,-0]},{\"mesh\":2,\"translation\":[-1,-2,-0]},{\"mesh\":1,\"translation\":[-1,-4,-0]},{\"mesh\":2,\"translation\":[-1,-6,-0]},{\"mesh\":1,\"translation\":[-2,-4,-0]},{\"mesh\":2,\"translation\":[-2,-2,-0]},{\"mesh\":1,\"translation\":[-2,-8,-0]},{\"mesh\":2,\"translation\":[-2,-6,-0]},{\"mesh\":3,\"translation\":[-3,-2,-0]},{\"mesh\":3,\"translation\":[-3,-6,-0]},{\"mesh\":1,\"translation\":[-5,-0,-0]},{\"mesh\":2,\"translation\":[-5,-2,-0]},{\"mesh\":1,\"translation\":[-5,-4,-0]},{\"mesh\":2,\"translation\":[-5,-6,-0]},{\"mesh\":1,\"translation\":[-6,-4,-0]},{\"mesh\":2,\"translation\":[-6,-2,-0]},{\"mesh\":1,\"translation\":[-6,-8,-0]},{\"mesh\":2,\"translation\":[-6,-6,-0]},{\"mesh\":3,\"translation\":[-7,-2,-0]},{\"mesh\":3,\"translation\":[-7,-6,-0]},{\"mesh\":4,\"translation\":[-8,-0,-0]},{\"mesh\":4,\"translation\":[-8,-4,-0]},{\"mesh\":4,\"translation\":[-8,-8,-0]},{\"mesh\":5,\"translation\":[0,0,0]},{\"mesh\":6,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/single_qubits_gates.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.4375],\"min\":[0,0.375],\"name\":\"tex_coords_gate_I\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.4375],\"min\":[0,0.375],\"name\":\"tex_coords_gate_X\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.5],\"min\":[0,0.4375],\"name\":\"tex_coords_gate_Y\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.5625],\"min\":[0,0.5],\"name\":\"tex_coords_gate_Z\",\"type\":\"VEC2\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.625],\"min\":[0.0625,0.5625],\"name\":\"tex_coords_gate_C_XYZ\",\"type\":\"VEC2\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.625],\"min\":[0.125,0.5625],\"name\":\"tex_coords_gate_C_ZYX\",\"type\":\"VEC2\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.5],\"min\":[0.0625,0.4375],\"name\":\"tex_coords_gate_H\",\"type\":\"VEC2\"},{\"bufferView\":8,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.5625],\"min\":[0.0625,0.5],\"name\":\"tex_coords_gate_H_XY\",\"type\":\"VEC2\"},{\"bufferView\":9,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.4375],\"min\":[0.0625,0.375],\"name\":\"tex_coords_gate_H_YZ\",\"type\":\"VEC2\"},{\"bufferView\":10,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.5625],\"min\":[0.125,0.5],\"name\":\"tex_coords_gate_S\",\"type\":\"VEC2\"},{\"bufferView\":11,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.4375],\"min\":[0.125,0.375],\"name\":\"tex_coords_gate_SQRT_X\",\"type\":\"VEC2\"},{\"bufferView\":12,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.4375],\"min\":[0.1875,0.375],\"name\":\"tex_coords_gate_SQRT_X_DAG\",\"type\":\"VEC2\"},{\"bufferView\":13,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.5],\"min\":[0.125,0.4375],\"name\":\"tex_coords_gate_SQRT_Y\",\"type\":\"VEC2\"},{\"bufferView\":14,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.5],\"min\":[0.1875,0.4375],\"name\":\"tex_coords_gate_SQRT_Y_DAG\",\"type\":\"VEC2\"},{\"bufferView\":15,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.5625],\"min\":[0.1875,0.5],\"name\":\"tex_coords_gate_S_DAG\",\"type\":\"VEC2\"},{\"bufferView\":16,\"byteOffset\":0,\"componentType\":5126,\"count\":8,\"max\":[1,-0,-0],\"min\":[-6,-6,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":17,\"byteOffset\":0,\"componentType\":5126,\"count\":6,\"max\":[0,2.5,-0],\"min\":[-3,1.5,-0],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_I\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_X\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Y\",\"target\":34962},{\"buffer\":4,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Z\",\"target\":34962},{\"buffer\":5,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_XYZ\",\"target\":34962},{\"buffer\":6,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_ZYX\",\"target\":34962},{\"buffer\":7,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H\",\"target\":34962},{\"buffer\":8,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H_XY\",\"target\":34962},{\"buffer\":9,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H_YZ\",\"target\":34962},{\"buffer\":10,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_S\",\"target\":34962},{\"buffer\":11,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_X\",\"target\":34962},{\"buffer\":12,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_X_DAG\",\"target\":34962},{\"buffer\":13,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_Y\",\"target\":34962},{\"buffer\":14,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_Y_DAG\",\"target\":34962},{\"buffer\":15,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_S_DAG\",\"target\":34962},{\"buffer\":16,\"byteLength\":96,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":17,\"byteLength\":72,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_I\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAwD4AAAAAAADAPgAAgD0AAOA+AAAAAAAAwD4AAAAAAADgPgAAgD0AAOA+AACAPQAA4D4AAIA9AADAPgAAAAAAAOA+AAAAAAAA4D4AAIA9AADAPgAAAAAAAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_X\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAwD4AAAAAAADAPgAAgD0AAOA+AAAAAAAAwD4AAAAAAADgPgAAgD0AAOA+AACAPQAA4D4AAIA9AADAPgAAAAAAAOA+AAAAAAAA4D4AAIA9AADAPgAAAAAAAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Y\",\"uri\":\"data:application/octet-stream;base64,AACAPQAA4D4AAAAAAADgPgAAgD0AAAA/AAAAAAAA4D4AAAAAAAAAPwAAgD0AAAA/AACAPQAAAD8AAIA9AADgPgAAAAAAAAA/AAAAAAAAAD8AAIA9AADgPgAAAAAAAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Z\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAAD8AAAAAAAAAPwAAgD0AABA/AAAAAAAAAD8AAAAAAAAQPwAAgD0AABA/AACAPQAAED8AAIA9AAAAPwAAAAAAABA/AAAAAAAAED8AAIA9AAAAPwAAAAAAAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_XYZ\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAED8AAIA9AAAQPwAAAD4AACA/AACAPQAAED8AAIA9AAAgPwAAAD4AACA/AAAAPgAAID8AAAA+AAAQPwAAgD0AACA/AACAPQAAID8AAAA+AAAQPwAAgD0AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_ZYX\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAED8AAAA+AAAQPwAAQD4AACA/AAAAPgAAED8AAAA+AAAgPwAAQD4AACA/AABAPgAAID8AAEA+AAAQPwAAAD4AACA/AAAAPgAAID8AAEA+AAAQPwAAAD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAA4D4AAIA9AADgPgAAAD4AAAA/AACAPQAA4D4AAIA9AAAAPwAAAD4AAAA/AAAAPgAAAD8AAAA+AADgPgAAgD0AAAA/AACAPQAAAD8AAAA+AADgPgAAgD0AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H_XY\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAAD8AAIA9AAAAPwAAAD4AABA/AACAPQAAAD8AAIA9AAAQPwAAAD4AABA/AAAAPgAAED8AAAA+AAAAPwAAgD0AABA/AACAPQAAED8AAAA+AAAAPwAAgD0AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H_YZ\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAwD4AAIA9AADAPgAAAD4AAOA+AACAPQAAwD4AAIA9AADgPgAAAD4AAOA+AAAAPgAA4D4AAAA+AADAPgAAgD0AAOA+AACAPQAA4D4AAAA+AADAPgAAgD0AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_S\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAAD8AAAA+AAAAPwAAQD4AABA/AAAAPgAAAD8AAAA+AAAQPwAAQD4AABA/AABAPgAAED8AAEA+AAAAPwAAAD4AABA/AAAAPgAAED8AAEA+AAAAPwAAAD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_X\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAwD4AAAA+AADAPgAAQD4AAOA+AAAAPgAAwD4AAAA+AADgPgAAQD4AAOA+AABAPgAA4D4AAEA+AADAPgAAAD4AAOA+AAAAPgAA4D4AAEA+AADAPgAAAD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_X_DAG\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAwD4AAEA+AADAPgAAgD4AAOA+AABAPgAAwD4AAEA+AADgPgAAgD4AAOA+AACAPgAA4D4AAIA+AADAPgAAQD4AAOA+AABAPgAA4D4AAIA+AADAPgAAQD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_Y\",\"uri\":\"data:application/octet-stream;base64,AABAPgAA4D4AAAA+AADgPgAAQD4AAAA/AAAAPgAA4D4AAAA+AAAAPwAAQD4AAAA/AABAPgAAAD8AAEA+AADgPgAAAD4AAAA/AAAAPgAAAD8AAEA+AADgPgAAAD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_Y_DAG\",\"uri\":\"data:application/octet-stream;base64,AACAPgAA4D4AAEA+AADgPgAAgD4AAAA/AABAPgAA4D4AAEA+AAAAPwAAgD4AAAA/AACAPgAAAD8AAIA+AADgPgAAQD4AAAA/AABAPgAAAD8AAIA+AADgPgAAQD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_S_DAG\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAAD8AAEA+AAAAPwAAgD4AABA/AABAPgAAAD8AAEA+AAAQPwAAgD4AABA/AACAPgAAED8AAIA+AAAAPwAAQD4AABA/AABAPgAAED8AAIA+AAAAPwAAQD4AAAA/\"},{\"byteLength\":96,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAPwAAAIAAAACAAADAwAAAAIAAAACAAACAPwAAAMAAAACAAADAwAAAAMAAAACAAACAPwAAgMAAAACAAADAwAAAgMAAAACAAACAPwAAwMAAAACAAADAwAAAwMAAAACA\"},{\"byteLength\":72,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACA\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":4},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":5},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":6},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":7},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":8},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":9},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":10},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":11},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":12},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":13},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":14},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":15},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":16},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":17},\"material\":2,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":1,\"translation\":[-0,-2,-0]},{\"mesh\":2,\"translation\":[-0,-4,-0]},{\"mesh\":3,\"translation\":[-0,-6,-0]},{\"mesh\":4,\"translation\":[-1,-0,-0]},{\"mesh\":5,\"translation\":[-1,-2,-0]},{\"mesh\":6,\"translation\":[-1,-4,-0]},{\"mesh\":7,\"translation\":[-1,-6,-0]},{\"mesh\":6,\"translation\":[-2,-0,-0]},{\"mesh\":8,\"translation\":[-2,-2,-0]},{\"mesh\":9,\"translation\":[-2,-4,-0]},{\"mesh\":10,\"translation\":[-2,-6,-0]},{\"mesh\":11,\"translation\":[-3,-0,-0]},{\"mesh\":12,\"translation\":[-3,-2,-0]},{\"mesh\":13,\"translation\":[-3,-4,-0]},{\"mesh\":9,\"translation\":[-3,-6,-0]},{\"mesh\":14,\"translation\":[-4,-0,-0]},{\"mesh\":14,\"translation\":[-4,-2,-0]},{\"mesh\":6,\"translation\":[-4,-4,-0]},{\"mesh\":6,\"translation\":[-5,-0,-0]},{\"mesh\":6,\"translation\":[-5,-6,-0]},{\"mesh\":15,\"translation\":[0,0,0]},{\"mesh\":16,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/surface_code.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.5625],\"min\":[0.3125,0.5],\"name\":\"tex_coords_gate_R\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.5],\"min\":[0.0625,0.4375],\"name\":\"tex_coords_gate_H\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"control_x_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.5625],\"min\":[0.375,0.5],\"name\":\"tex_coords_gate_MR\",\"type\":\"VEC2\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5625],\"min\":[0.25,0.5],\"name\":\"tex_coords_gate_M\",\"type\":\"VEC2\"},{\"bufferView\":8,\"byteOffset\":0,\"componentType\":5126,\"count\":210,\"max\":[1,-32,-32],\"min\":[-17,-40,-40],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":9,\"byteOffset\":0,\"componentType\":5126,\"count\":30,\"max\":[0,-29.5,-31],\"min\":[-15.25,-41,-41],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_R\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H\",\"target\":34962},{\"buffer\":3,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":4,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":5,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_x_line_cross\",\"target\":34962},{\"buffer\":6,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MR\",\"target\":34962},{\"buffer\":7,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_M\",\"target\":34962},{\"buffer\":8,\"byteLength\":2520,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":9,\"byteLength\":360,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_R\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAAD8AAKA+AAAAPwAAwD4AABA/AACgPgAAAD8AAKA+AAAQPwAAwD4AABA/AADAPgAAED8AAMA+AAAAPwAAoD4AABA/AACgPgAAED8AAMA+AAAAPwAAoD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAA4D4AAIA9AADgPgAAAD4AAAA/AACAPQAA4D4AAIA9AAAAPwAAAD4AAAA/AAAAPgAAAD8AAAA+AADgPgAAgD0AAAA/AACAPQAAAD8AAAA+AADgPgAAgD0AAOA+\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_x_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzL4AAAAAAAAAAM3MzD4AAAAAAAAAAAAAAADNzMy+AAAAAAAAAADNzMw+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MR\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAAD8AAMA+AAAAPwAA4D4AABA/AADAPgAAAD8AAMA+AAAQPwAA4D4AABA/AADgPgAAED8AAOA+AAAAPwAAwD4AABA/AADAPgAAED8AAOA+AAAAPwAAwD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_M\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAAD8AAIA+AAAAPwAAoD4AABA/AACAPgAAAD8AAIA+AAAQPwAAoD4AABA/AACgPgAAED8AAKA+AAAAPwAAgD4AABA/AACAPgAAED8AAKA+AAAAPwAAgD4AAAA/\"},{\"byteLength\":2520,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAwAAACMIAAADCAAAAwAAAEMIAAADCAAAAwAAACMIAABDCAAAAwAAAEMIAABDCAAAAwAAACMIAACDCAAAAwAAAEMIAACDCAAAAwAAAGMIAAADCAAAAwAAAIMIAAADCAAAAwAAAGMIAABDCAAAAwAAAIMIAABDCAAAAwAAAGMIAACDCAAAAwAAAIMIAACDCAAAAwAAACMIAAAjCAAAAwAAAAMIAAAjCAAAAwAAACMIAABjCAAAAwAAAAMIAABjCAAAAwAAAGMIAAAjCAAAAwAAAEMIAAAjCAAAAwAAAGMIAABjCAAAAwAAAEMIAABjCAABAwAAACMIAAADCAABAwAAACMIAAAjCAABAwAAACMIAABDCAABAwAAACMIAABjCAABAwAAAGMIAAADCAABAwAAAGMIAAAjCAABAwAAAGMIAABDCAABAwAAAGMIAABjCAABAwAAAAMIAABDCAABAwAAAAMIAAAjCAABAwAAAAMIAACDCAABAwAAAAMIAABjCAABAwAAAEMIAABDCAABAwAAAEMIAAAjCAABAwAAAEMIAACDCAABAwAAAEMIAABjCAABAwAAAIMIAABDCAABAwAAAIMIAAAjCAABAwAAAIMIAACDCAABAwAAAIMIAABjCAACAwAAACMIAABDCAACAwAAACMIAAAjCAACAwAAACMIAACDCAACAwAAACMIAABjCAACAwAAAGMIAABDCAACAwAAAGMIAAAjCAACAwAAAGMIAACDCAACAwAAAGMIAABjCAACAwAAAAMIAAADCAACAwAAAAMIAAAjCAACAwAAAAMIAABDCAACAwAAAAMIAABjCAACAwAAAEMIAAADCAACAwAAAEMIAAAjCAACAwAAAEMIAABDCAACAwAAAEMIAABjCAACAwAAAIMIAAADCAACAwAAAIMIAAAjCAACAwAAAIMIAABDCAACAwAAAIMIAABjCAACgwAAACMIAAADCAACgwAAAAMIAAADCAACgwAAACMIAABDCAACgwAAAAMIAABDCAACgwAAACMIAACDCAACgwAAAAMIAACDCAACgwAAAGMIAAADCAACgwAAAEMIAAADCAACgwAAAGMIAABDCAACgwAAAEMIAABDCAACgwAAAGMIAACDCAACgwAAAEMIAACDCAACgwAAACMIAAAjCAACgwAAAEMIAAAjCAACgwAAACMIAABjCAACgwAAAEMIAABjCAACgwAAAGMIAAAjCAACgwAAAIMIAAAjCAACgwAAAGMIAABjCAACgwAAAIMIAABjCAAAgwQAACMIAAADCAAAgwQAAEMIAAADCAAAgwQAACMIAABDCAAAgwQAAEMIAABDCAAAgwQAACMIAACDCAAAgwQAAEMIAACDCAAAgwQAAGMIAAADCAAAgwQAAIMIAAADCAAAgwQAAGMIAABDCAAAgwQAAIMIAABDCAAAgwQAAGMIAACDCAAAgwQAAIMIAACDCAAAgwQAACMIAAAjCAAAgwQAAAMIAAAjCAAAgwQAACMIAABjCAAAgwQAAAMIAABjCAAAgwQAAGMIAAAjCAAAgwQAAEMIAAAjCAAAgwQAAGMIAABjCAAAgwQAAEMIAABjCAAAwwQAACMIAAADCAAAwwQAACMIAAAjCAAAwwQAACMIAABDCAAAwwQAACMIAABjCAAAwwQAAGMIAAADCAAAwwQAAGMIAAAjCAAAwwQAAGMIAABDCAAAwwQAAGMIAABjCAAAwwQAAAMIAABDCAAAwwQAAAMIAAAjCAAAwwQAAAMIAACDCAAAwwQAAAMIAABjCAAAwwQAAEMIAABDCAAAwwQAAEMIAAAjCAAAwwQAAEMIAACDCAAAwwQAAEMIAABjCAAAwwQAAIMIAABDCAAAwwQAAIMIAAAjCAAAwwQAAIMIAACDCAAAwwQAAIMIAABjCAABAwQAACMIAABDCAABAwQAACMIAAAjCAABAwQAACMIAACDCAABAwQAACMIAABjCAABAwQAAGMIAABDCAABAwQAAGMIAAAjCAABAwQAAGMIAACDCAABAwQAAGMIAABjCAABAwQAAAMIAAADCAABAwQAAAMIAAAjCAABAwQAAAMIAABDCAABAwQAAAMIAABjCAABAwQAAEMIAAADCAABAwQAAEMIAAAjCAABAwQAAEMIAABDCAABAwQAAEMIAABjCAABAwQAAIMIAAADCAABAwQAAIMIAAAjCAABAwQAAIMIAABDCAABAwQAAIMIAABjCAABQwQAACMIAAADCAABQwQAAAMIAAADCAABQwQAACMIAABDCAABQwQAAAMIAABDCAABQwQAACMIAACDCAABQwQAAAMIAACDCAABQwQAAGMIAAADCAABQwQAAEMIAAADCAABQwQAAGMIAABDCAABQwQAAEMIAABDCAABQwQAAGMIAACDCAABQwQAAEMIAACDCAABQwQAACMIAAAjCAABQwQAAEMIAAAjCAABQwQAACMIAABjCAABQwQAAEMIAABjCAABQwQAAGMIAAAjCAABQwQAAIMIAAAjCAABQwQAAGMIAABjCAABQwQAAIMIAABjCAACAPwAAAMIAAADCAACIwQAAAMIAAADCAACAPwAACMIAAADCAACIwQAACMIAAADCAACAPwAAEMIAAADCAACIwQAAEMIAAADCAACAPwAAGMIAAADCAACIwQAAGMIAAADCAACAPwAAIMIAAADCAACIwQAAIMIAAADCAACAPwAAAMIAAAjCAACIwQAAAMIAAAjCAACAPwAACMIAAAjCAACIwQAACMIAAAjCAACAPwAAEMIAAAjCAACIwQAAEMIAAAjCAACAPwAAGMIAAAjCAACIwQAAGMIAAAjCAACAPwAAIMIAAAjCAACIwQAAIMIAAAjCAACAPwAAAMIAABDCAACIwQAAAMIAABDCAACAPwAACMIAABDCAACIwQAACMIAABDCAACAPwAAEMIAABDCAACIwQAAEMIAABDCAACAPwAAGMIAABDCAACIwQAAGMIAABDCAACAPwAAIMIAABDCAACIwQAAIMIAABDCAACAPwAAAMIAABjCAACIwQAAAMIAABjCAACAPwAACMIAABjCAACIwQAACMIAABjCAACAPwAAEMIAABjCAACIwQAAEMIAABjCAACAPwAAGMIAABjCAACIwQAAGMIAABjCAACAPwAAIMIAABjCAACIwQAAIMIAABjCAACAPwAAAMIAACDCAACIwQAAAMIAACDCAACAPwAACMIAACDCAACIwQAACMIAACDCAACAPwAAEMIAACDCAACIwQAAEMIAACDCAACAPwAAGMIAACDCAACIwQAAGMIAACDCAACAPwAAIMIAACDCAACIwQAAIMIAACDC\"},{\"byteLength\":360,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAA8MEAABDCAABAwAAA8MEAABDCAAAgwAAA9MEAABDCAABAwAAA8MEAABDCAAAgwAAA7MEAABDCAABAwAAA8MEAABDCAAD4wAAA+MEAAPjBAAD4wAAA+MEAACTCAAD4wAAA+MEAAPjBAAD4wAAAJMIAAPjBAAD4wAAA+MEAAPjBAAB0wQAA+MEAAPjBAAD4wAAA+MEAACTCAAD4wAAAJMIAACTCAAD4wAAA+MEAACTCAAB0wQAA+MEAACTCAAD4wAAAJMIAAPjBAAD4wAAAJMIAACTCAAD4wAAAJMIAAPjBAAB0wQAAJMIAAPjBAAD4wAAAJMIAACTCAAB0wQAAJMIAACTCAAB0wQAA+MEAAPjBAAB0wQAA+MEAACTCAAB0wQAA+MEAAPjBAAB0wQAAJMIAAPjBAAB0wQAA+MEAACTCAAB0wQAAJMIAACTCAAB0wQAAJMIAAPjBAAB0wQAAJMIAACTC\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":1,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4},\"material\":2,\"mode\":6},{\"attributes\":{\"POSITION\":4},\"material\":3,\"mode\":3},{\"attributes\":{\"POSITION\":5},\"material\":3,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":6},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":7},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":8},\"material\":4,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":9},\"material\":5,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-32,-32]},{\"mesh\":0,\"translation\":[-0,-36,-32]},{\"mesh\":0,\"translation\":[-0,-40,-32]},{\"mesh\":0,\"translation\":[-0,-34,-34]},{\"mesh\":0,\"translation\":[-0,-38,-34]},{\"mesh\":0,\"translation\":[-0,-32,-36]},{\"mesh\":0,\"translation\":[-0,-36,-36]},{\"mesh\":0,\"translation\":[-0,-40,-36]},{\"mesh\":0,\"translation\":[-0,-34,-38]},{\"mesh\":0,\"translation\":[-0,-38,-38]},{\"mesh\":0,\"translation\":[-0,-32,-40]},{\"mesh\":0,\"translation\":[-0,-36,-40]},{\"mesh\":0,\"translation\":[-0,-40,-40]},{\"mesh\":0,\"translation\":[-0,-34,-32]},{\"mesh\":0,\"translation\":[-0,-38,-32]},{\"mesh\":0,\"translation\":[-0,-32,-34]},{\"mesh\":0,\"translation\":[-0,-36,-34]},{\"mesh\":0,\"translation\":[-0,-40,-34]},{\"mesh\":0,\"translation\":[-0,-34,-36]},{\"mesh\":0,\"translation\":[-0,-38,-36]},{\"mesh\":0,\"translation\":[-0,-32,-38]},{\"mesh\":0,\"translation\":[-0,-36,-38]},{\"mesh\":0,\"translation\":[-0,-40,-38]},{\"mesh\":0,\"translation\":[-0,-34,-40]},{\"mesh\":0,\"translation\":[-0,-38,-40]},{\"mesh\":1,\"translation\":[-1,-34,-32]},{\"mesh\":1,\"translation\":[-1,-38,-32]},{\"mesh\":1,\"translation\":[-1,-34,-36]},{\"mesh\":1,\"translation\":[-1,-38,-36]},{\"mesh\":1,\"translation\":[-1,-34,-40]},{\"mesh\":1,\"translation\":[-1,-38,-40]},{\"mesh\":2,\"translation\":[-2,-34,-32]},{\"mesh\":3,\"translation\":[-2,-36,-32]},{\"mesh\":2,\"translation\":[-2,-34,-36]},{\"mesh\":3,\"translation\":[-2,-36,-36]},{\"mesh\":2,\"translation\":[-2,-34,-40]},{\"mesh\":3,\"translation\":[-2,-36,-40]},{\"mesh\":2,\"translation\":[-2,-38,-32]},{\"mesh\":3,\"translation\":[-2,-40,-32]},{\"mesh\":2,\"translation\":[-2,-38,-36]},{\"mesh\":3,\"translation\":[-2,-40,-36]},{\"mesh\":2,\"translation\":[-2,-38,-40]},{\"mesh\":3,\"translation\":[-2,-40,-40]},{\"mesh\":2,\"translation\":[-2,-34,-34]},{\"mesh\":3,\"translation\":[-2,-32,-34]},{\"mesh\":2,\"translation\":[-2,-34,-38]},{\"mesh\":3,\"translation\":[-2,-32,-38]},{\"mesh\":2,\"translation\":[-2,-38,-34]},{\"mesh\":3,\"translation\":[-2,-36,-34]},{\"mesh\":2,\"translation\":[-2,-38,-38]},{\"mesh\":3,\"translation\":[-2,-36,-38]},{\"mesh\":2,\"translation\":[-3,-34,-32]},{\"mesh\":3,\"translation\":[-3,-34,-34]},{\"mesh\":2,\"translation\":[-3,-34,-36]},{\"mesh\":3,\"translation\":[-3,-34,-38]},{\"mesh\":2,\"translation\":[-3,-38,-32]},{\"mesh\":3,\"translation\":[-3,-38,-34]},{\"mesh\":2,\"translation\":[-3,-38,-36]},{\"mesh\":3,\"translation\":[-3,-38,-38]},{\"mesh\":2,\"translation\":[-3,-32,-36]},{\"mesh\":3,\"translation\":[-3,-32,-34]},{\"mesh\":2,\"translation\":[-3,-32,-40]},{\"mesh\":3,\"translation\":[-3,-32,-38]},{\"mesh\":2,\"translation\":[-3,-36,-36]},{\"mesh\":3,\"translation\":[-3,-36,-34]},{\"mesh\":2,\"translation\":[-3,-36,-40]},{\"mesh\":3,\"translation\":[-3,-36,-38]},{\"mesh\":2,\"translation\":[-3,-40,-36]},{\"mesh\":3,\"translation\":[-3,-40,-34]},{\"mesh\":2,\"translation\":[-3,-40,-40]},{\"mesh\":3,\"translation\":[-3,-40,-38]},{\"mesh\":2,\"translation\":[-4,-34,-36]},{\"mesh\":3,\"translation\":[-4,-34,-34]},{\"mesh\":2,\"translation\":[-4,-34,-40]},{\"mesh\":3,\"translation\":[-4,-34,-38]},{\"mesh\":2,\"translation\":[-4,-38,-36]},{\"mesh\":3,\"translation\":[-4,-38,-34]},{\"mesh\":2,\"translation\":[-4,-38,-40]},{\"mesh\":3,\"translation\":[-4,-38,-38]},{\"mesh\":2,\"translation\":[-4,-32,-32]},{\"mesh\":3,\"translation\":[-4,-32,-34]},{\"mesh\":2,\"translation\":[-4,-32,-36]},{\"mesh\":3,\"translation\":[-4,-32,-38]},{\"mesh\":2,\"translation\":[-4,-36,-32]},{\"mesh\":3,\"translation\":[-4,-36,-34]},{\"mesh\":2,\"translation\":[-4,-36,-36]},{\"mesh\":3,\"translation\":[-4,-36,-38]},{\"mesh\":2,\"translation\":[-4,-40,-32]},{\"mesh\":3,\"translation\":[-4,-40,-34]},{\"mesh\":2,\"translation\":[-4,-40,-36]},{\"mesh\":3,\"translation\":[-4,-40,-38]},{\"mesh\":2,\"translation\":[-5,-34,-32]},{\"mesh\":3,\"translation\":[-5,-32,-32]},{\"mesh\":2,\"translation\":[-5,-34,-36]},{\"mesh\":3,\"translation\":[-5,-32,-36]},{\"mesh\":2,\"translation\":[-5,-34,-40]},{\"mesh\":3,\"translation\":[-5,-32,-40]},{\"mesh\":2,\"translation\":[-5,-38,-32]},{\"mesh\":3,\"translation\":[-5,-36,-32]},{\"mesh\":2,\"translation\":[-5,-38,-36]},{\"mesh\":3,\"translation\":[-5,-36,-36]},{\"mesh\":2,\"translation\":[-5,-38,-40]},{\"mesh\":3,\"translation\":[-5,-36,-40]},{\"mesh\":2,\"translation\":[-5,-34,-34]},{\"mesh\":3,\"translation\":[-5,-36,-34]},{\"mesh\":2,\"translation\":[-5,-34,-38]},{\"mesh\":3,\"translation\":[-5,-36,-38]},{\"mesh\":2,\"translation\":[-5,-38,-34]},{\"mesh\":3,\"translation\":[-5,-40,-34]},{\"mesh\":2,\"translation\":[-5,-38,-38]},{\"mesh\":3,\"translation\":[-5,-40,-38]},{\"mesh\":1,\"translation\":[-6,-34,-32]},{\"mesh\":1,\"translation\":[-6,-38,-32]},{\"mesh\":1,\"translation\":[-6,-34,-36]},{\"mesh\":1,\"translation\":[-6,-38,-36]},{\"mesh\":1,\"translation\":[-6,-34,-40]},{\"mesh\":1,\"translation\":[-6,-38,-40]},{\"mesh\":4,\"translation\":[-7,-34,-32]},{\"mesh\":4,\"translation\":[-7,-38,-32]},{\"mesh\":4,\"translation\":[-7,-32,-34]},{\"mesh\":4,\"translation\":[-7,-36,-34]},{\"mesh\":4,\"translation\":[-7,-40,-34]},{\"mesh\":4,\"translation\":[-7,-34,-36]},{\"mesh\":4,\"translation\":[-7,-38,-36]},{\"mesh\":4,\"translation\":[-7,-32,-38]},{\"mesh\":4,\"translation\":[-7,-36,-38]},{\"mesh\":4,\"translation\":[-7,-40,-38]},{\"mesh\":4,\"translation\":[-7,-34,-40]},{\"mesh\":4,\"translation\":[-7,-38,-40]},{\"mesh\":1,\"translation\":[-9,-34,-32]},{\"mesh\":1,\"translation\":[-9,-38,-32]},{\"mesh\":1,\"translation\":[-9,-34,-36]},{\"mesh\":1,\"translation\":[-9,-38,-36]},{\"mesh\":1,\"translation\":[-9,-34,-40]},{\"mesh\":1,\"translation\":[-9,-38,-40]},{\"mesh\":2,\"translation\":[-10,-34,-32]},{\"mesh\":3,\"translation\":[-10,-36,-32]},{\"mesh\":2,\"translation\":[-10,-34,-36]},{\"mesh\":3,\"translation\":[-10,-36,-36]},{\"mesh\":2,\"translation\":[-10,-34,-40]},{\"mesh\":3,\"translation\":[-10,-36,-40]},{\"mesh\":2,\"translation\":[-10,-38,-32]},{\"mesh\":3,\"translation\":[-10,-40,-32]},{\"mesh\":2,\"translation\":[-10,-38,-36]},{\"mesh\":3,\"translation\":[-10,-40,-36]},{\"mesh\":2,\"translation\":[-10,-38,-40]},{\"mesh\":3,\"translation\":[-10,-40,-40]},{\"mesh\":2,\"translation\":[-10,-34,-34]},{\"mesh\":3,\"translation\":[-10,-32,-34]},{\"mesh\":2,\"translation\":[-10,-34,-38]},{\"mesh\":3,\"translation\":[-10,-32,-38]},{\"mesh\":2,\"translation\":[-10,-38,-34]},{\"mesh\":3,\"translation\":[-10,-36,-34]},{\"mesh\":2,\"translation\":[-10,-38,-38]},{\"mesh\":3,\"translation\":[-10,-36,-38]},{\"mesh\":2,\"translation\":[-11,-34,-32]},{\"mesh\":3,\"translation\":[-11,-34,-34]},{\"mesh\":2,\"translation\":[-11,-34,-36]},{\"mesh\":3,\"translation\":[-11,-34,-38]},{\"mesh\":2,\"translation\":[-11,-38,-32]},{\"mesh\":3,\"translation\":[-11,-38,-34]},{\"mesh\":2,\"translation\":[-11,-38,-36]},{\"mesh\":3,\"translation\":[-11,-38,-38]},{\"mesh\":2,\"translation\":[-11,-32,-36]},{\"mesh\":3,\"translation\":[-11,-32,-34]},{\"mesh\":2,\"translation\":[-11,-32,-40]},{\"mesh\":3,\"translation\":[-11,-32,-38]},{\"mesh\":2,\"translation\":[-11,-36,-36]},{\"mesh\":3,\"translation\":[-11,-36,-34]},{\"mesh\":2,\"translation\":[-11,-36,-40]},{\"mesh\":3,\"translation\":[-11,-36,-38]},{\"mesh\":2,\"translation\":[-11,-40,-36]},{\"mesh\":3,\"translation\":[-11,-40,-34]},{\"mesh\":2,\"translation\":[-11,-40,-40]},{\"mesh\":3,\"translation\":[-11,-40,-38]},{\"mesh\":2,\"translation\":[-12,-34,-36]},{\"mesh\":3,\"translation\":[-12,-34,-34]},{\"mesh\":2,\"translation\":[-12,-34,-40]},{\"mesh\":3,\"translation\":[-12,-34,-38]},{\"mesh\":2,\"translation\":[-12,-38,-36]},{\"mesh\":3,\"translation\":[-12,-38,-34]},{\"mesh\":2,\"translation\":[-12,-38,-40]},{\"mesh\":3,\"translation\":[-12,-38,-38]},{\"mesh\":2,\"translation\":[-12,-32,-32]},{\"mesh\":3,\"translation\":[-12,-32,-34]},{\"mesh\":2,\"translation\":[-12,-32,-36]},{\"mesh\":3,\"translation\":[-12,-32,-38]},{\"mesh\":2,\"translation\":[-12,-36,-32]},{\"mesh\":3,\"translation\":[-12,-36,-34]},{\"mesh\":2,\"translation\":[-12,-36,-36]},{\"mesh\":3,\"translation\":[-12,-36,-38]},{\"mesh\":2,\"translation\":[-12,-40,-32]},{\"mesh\":3,\"translation\":[-12,-40,-34]},{\"mesh\":2,\"translation\":[-12,-40,-36]},{\"mesh\":3,\"translation\":[-12,-40,-38]},{\"mesh\":2,\"translation\":[-13,-34,-32]},{\"mesh\":3,\"translation\":[-13,-32,-32]},{\"mesh\":2,\"translation\":[-13,-34,-36]},{\"mesh\":3,\"translation\":[-13,-32,-36]},{\"mesh\":2,\"translation\":[-13,-34,-40]},{\"mesh\":3,\"translation\":[-13,-32,-40]},{\"mesh\":2,\"translation\":[-13,-38,-32]},{\"mesh\":3,\"translation\":[-13,-36,-32]},{\"mesh\":2,\"translation\":[-13,-38,-36]},{\"mesh\":3,\"translation\":[-13,-36,-36]},{\"mesh\":2,\"translation\":[-13,-38,-40]},{\"mesh\":3,\"translation\":[-13,-36,-40]},{\"mesh\":2,\"translation\":[-13,-34,-34]},{\"mesh\":3,\"translation\":[-13,-36,-34]},{\"mesh\":2,\"translation\":[-13,-34,-38]},{\"mesh\":3,\"translation\":[-13,-36,-38]},{\"mesh\":2,\"translation\":[-13,-38,-34]},{\"mesh\":3,\"translation\":[-13,-40,-34]},{\"mesh\":2,\"translation\":[-13,-38,-38]},{\"mesh\":3,\"translation\":[-13,-40,-38]},{\"mesh\":1,\"translation\":[-14,-34,-32]},{\"mesh\":1,\"translation\":[-14,-38,-32]},{\"mesh\":1,\"translation\":[-14,-34,-36]},{\"mesh\":1,\"translation\":[-14,-38,-36]},{\"mesh\":1,\"translation\":[-14,-34,-40]},{\"mesh\":1,\"translation\":[-14,-38,-40]},{\"mesh\":4,\"translation\":[-15,-34,-32]},{\"mesh\":4,\"translation\":[-15,-38,-32]},{\"mesh\":4,\"translation\":[-15,-32,-34]},{\"mesh\":4,\"translation\":[-15,-36,-34]},{\"mesh\":4,\"translation\":[-15,-40,-34]},{\"mesh\":4,\"translation\":[-15,-34,-36]},{\"mesh\":4,\"translation\":[-15,-38,-36]},{\"mesh\":4,\"translation\":[-15,-32,-38]},{\"mesh\":4,\"translation\":[-15,-36,-38]},{\"mesh\":4,\"translation\":[-15,-40,-38]},{\"mesh\":4,\"translation\":[-15,-34,-40]},{\"mesh\":4,\"translation\":[-15,-38,-40]},{\"mesh\":5,\"translation\":[-16,-32,-32]},{\"mesh\":5,\"translation\":[-16,-36,-32]},{\"mesh\":5,\"translation\":[-16,-40,-32]},{\"mesh\":5,\"translation\":[-16,-34,-34]},{\"mesh\":5,\"translation\":[-16,-38,-34]},{\"mesh\":5,\"translation\":[-16,-32,-36]},{\"mesh\":5,\"translation\":[-16,-36,-36]},{\"mesh\":5,\"translation\":[-16,-40,-36]},{\"mesh\":5,\"translation\":[-16,-34,-38]},{\"mesh\":5,\"translation\":[-16,-38,-38]},{\"mesh\":5,\"translation\":[-16,-32,-40]},{\"mesh\":5,\"translation\":[-16,-36,-40]},{\"mesh\":5,\"translation\":[-16,-40,-40]},{\"mesh\":6,\"translation\":[0,0,0]},{\"mesh\":7,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/test_circuit_all_ops.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.4375],\"min\":[0,0.375],\"name\":\"tex_coords_gate_I\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.4375],\"min\":[0,0.375],\"name\":\"tex_coords_gate_X\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.5],\"min\":[0,0.4375],\"name\":\"tex_coords_gate_Y\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.0625,0.5625],\"min\":[0,0.5],\"name\":\"tex_coords_gate_Z\",\"type\":\"VEC2\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.625],\"min\":[0.0625,0.5625],\"name\":\"tex_coords_gate_C_XYZ\",\"type\":\"VEC2\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.625],\"min\":[0.125,0.5625],\"name\":\"tex_coords_gate_C_ZYX\",\"type\":\"VEC2\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.5625],\"min\":[0.0625,0.5],\"name\":\"tex_coords_gate_H_XY\",\"type\":\"VEC2\"},{\"bufferView\":8,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.5],\"min\":[0.0625,0.4375],\"name\":\"tex_coords_gate_H\",\"type\":\"VEC2\"},{\"bufferView\":9,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.4375],\"min\":[0.0625,0.375],\"name\":\"tex_coords_gate_H_YZ\",\"type\":\"VEC2\"},{\"bufferView\":10,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.4375],\"min\":[0.125,0.375],\"name\":\"tex_coords_gate_SQRT_X\",\"type\":\"VEC2\"},{\"bufferView\":11,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.4375],\"min\":[0.1875,0.375],\"name\":\"tex_coords_gate_SQRT_X_DAG\",\"type\":\"VEC2\"},{\"bufferView\":12,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.5],\"min\":[0.125,0.4375],\"name\":\"tex_coords_gate_SQRT_Y\",\"type\":\"VEC2\"},{\"bufferView\":13,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.5],\"min\":[0.1875,0.4375],\"name\":\"tex_coords_gate_SQRT_Y_DAG\",\"type\":\"VEC2\"},{\"bufferView\":14,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.5625],\"min\":[0.125,0.5],\"name\":\"tex_coords_gate_S\",\"type\":\"VEC2\"},{\"bufferView\":15,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.5625],\"min\":[0.1875,0.5],\"name\":\"tex_coords_gate_S_DAG\",\"type\":\"VEC2\"},{\"bufferView\":16,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":17,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.45254835486412,0.45254835486412],\"min\":[0,-0.45254835486412,-0.45254835486412],\"name\":\"control_zswap_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":18,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":19,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.45254835486412,0.45254835486412],\"min\":[0,-0.45254835486412,-0.45254835486412],\"name\":\"control_xswap_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":20,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.625],\"min\":[0.3125,0.5625],\"name\":\"tex_coords_gate_ISWAP\",\"type\":\"VEC2\"},{\"bufferView\":21,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.625],\"min\":[0.375,0.5625],\"name\":\"tex_coords_gate_ISWAP_DAG\",\"type\":\"VEC2\"},{\"bufferView\":22,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.625],\"min\":[0.4375,0.5625],\"name\":\"tex_coords_gate_SWAP\",\"type\":\"VEC2\"},{\"bufferView\":23,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.4375],\"min\":[0.6875,0.375],\"name\":\"tex_coords_gate_SQRT_XX\",\"type\":\"VEC2\"},{\"bufferView\":24,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.4375],\"min\":[0.75,0.375],\"name\":\"tex_coords_gate_SQRT_XX_DAG\",\"type\":\"VEC2\"},{\"bufferView\":25,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.5],\"min\":[0.6875,0.4375],\"name\":\"tex_coords_gate_SQRT_YY\",\"type\":\"VEC2\"},{\"bufferView\":26,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.5],\"min\":[0.75,0.4375],\"name\":\"tex_coords_gate_SQRT_YY_DAG\",\"type\":\"VEC2\"},{\"bufferView\":27,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.5625],\"min\":[0.6875,0.5],\"name\":\"tex_coords_gate_SQRT_ZZ\",\"type\":\"VEC2\"},{\"bufferView\":28,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.5625],\"min\":[0.75,0.5],\"name\":\"tex_coords_gate_SQRT_ZZ_DAG\",\"type\":\"VEC2\"},{\"bufferView\":29,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":30,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"control_x_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":31,\"byteOffset\":0,\"componentType\":5126,\"count\":3,\"max\":[0,0.400000005960464,0.346410155296326],\"min\":[0,-0.200000032782555,-0.346410185098648],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":32,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":33,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.4375],\"min\":[0.5,0.375],\"name\":\"tex_coords_gate_E:X\",\"type\":\"VEC2\"},{\"bufferView\":34,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.5],\"min\":[0.5,0.4375],\"name\":\"tex_coords_gate_E:Y\",\"type\":\"VEC2\"},{\"bufferView\":35,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.5625],\"min\":[0.5,0.5],\"name\":\"tex_coords_gate_E:Z\",\"type\":\"VEC2\"},{\"bufferView\":36,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.4375],\"min\":[0.5625,0.375],\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:X\",\"type\":\"VEC2\"},{\"bufferView\":37,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.5],\"min\":[0.5625,0.4375],\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Y\",\"type\":\"VEC2\"},{\"bufferView\":38,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.5625],\"min\":[0.5625,0.5],\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Z\",\"type\":\"VEC2\"},{\"bufferView\":39,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.25,0.625],\"min\":[0.1875,0.5625],\"name\":\"tex_coords_gate_DEPOLARIZE1\",\"type\":\"VEC2\"},{\"bufferView\":40,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.625],\"min\":[0.25,0.5625],\"name\":\"tex_coords_gate_DEPOLARIZE2\",\"type\":\"VEC2\"},{\"bufferView\":41,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5625,0.625],\"min\":[0.5,0.5625],\"name\":\"tex_coords_gate_PAULI_CHANNEL_1\",\"type\":\"VEC2\"},{\"bufferView\":42,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.625,0.625],\"min\":[0.5625,0.5625],\"name\":\"tex_coords_gate_PAULI_CHANNEL_2\",\"type\":\"VEC2\"},{\"bufferView\":43,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.4375],\"min\":[0.4375,0.375],\"name\":\"tex_coords_gate_X_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":44,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.5],\"min\":[0.4375,0.4375],\"name\":\"tex_coords_gate_Y_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":45,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.5625],\"min\":[0.4375,0.5],\"name\":\"tex_coords_gate_Z_ERROR\",\"type\":\"VEC2\"},{\"bufferView\":46,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.4375],\"min\":[0.625,0.375],\"name\":\"tex_coords_gate_MPP:X\",\"type\":\"VEC2\"},{\"bufferView\":47,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.5],\"min\":[0.625,0.4375],\"name\":\"tex_coords_gate_MPP:Y\",\"type\":\"VEC2\"},{\"bufferView\":48,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.5625],\"min\":[0.625,0.5],\"name\":\"tex_coords_gate_MPP:Z\",\"type\":\"VEC2\"},{\"bufferView\":49,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.4375],\"min\":[0.375,0.375],\"name\":\"tex_coords_gate_MRX\",\"type\":\"VEC2\"},{\"bufferView\":50,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.5],\"min\":[0.375,0.4375],\"name\":\"tex_coords_gate_MRY\",\"type\":\"VEC2\"},{\"bufferView\":51,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.5625],\"min\":[0.375,0.5],\"name\":\"tex_coords_gate_MR\",\"type\":\"VEC2\"},{\"bufferView\":52,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.4375],\"min\":[0.25,0.375],\"name\":\"tex_coords_gate_MX\",\"type\":\"VEC2\"},{\"bufferView\":53,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5],\"min\":[0.25,0.4375],\"name\":\"tex_coords_gate_MY\",\"type\":\"VEC2\"},{\"bufferView\":54,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.3125,0.5625],\"min\":[0.25,0.5],\"name\":\"tex_coords_gate_M\",\"type\":\"VEC2\"},{\"bufferView\":55,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.4375],\"min\":[0.3125,0.375],\"name\":\"tex_coords_gate_RX\",\"type\":\"VEC2\"},{\"bufferView\":56,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.5],\"min\":[0.3125,0.4375],\"name\":\"tex_coords_gate_RY\",\"type\":\"VEC2\"},{\"bufferView\":57,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.5625],\"min\":[0.3125,0.5],\"name\":\"tex_coords_gate_R\",\"type\":\"VEC2\"},{\"bufferView\":58,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.6875,0.625],\"min\":[0.625,0.5625],\"name\":\"tex_coords_gate_MXX\",\"type\":\"VEC2\"},{\"bufferView\":59,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.625],\"min\":[0.6875,0.5625],\"name\":\"tex_coords_gate_MYY\",\"type\":\"VEC2\"},{\"bufferView\":60,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.625],\"min\":[0.75,0.5625],\"name\":\"tex_coords_gate_MZZ\",\"type\":\"VEC2\"},{\"bufferView\":61,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.875,0.625],\"min\":[0.8125,0.5625],\"name\":\"tex_coords_gate_MPAD\",\"type\":\"VEC2\"},{\"bufferView\":62,\"byteOffset\":0,\"componentType\":5126,\"count\":120,\"max\":[1,-2,-0],\"min\":[-25,-34,-32],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":63,\"byteOffset\":0,\"componentType\":5126,\"count\":30,\"max\":[0,0.5,1],\"min\":[-17.25,-35,-33],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":64,\"byteOffset\":0,\"componentType\":5126,\"count\":96,\"max\":[-0.75,-1.20000004768372,0.5],\"min\":[-23.25,-1.60000002384186,-32.5],\"name\":\"buf_blue_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_I\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_X\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Y\",\"target\":34962},{\"buffer\":4,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Z\",\"target\":34962},{\"buffer\":5,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_XYZ\",\"target\":34962},{\"buffer\":6,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_C_ZYX\",\"target\":34962},{\"buffer\":7,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H_XY\",\"target\":34962},{\"buffer\":8,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H\",\"target\":34962},{\"buffer\":9,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H_YZ\",\"target\":34962},{\"buffer\":10,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_X\",\"target\":34962},{\"buffer\":11,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_X_DAG\",\"target\":34962},{\"buffer\":12,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_Y\",\"target\":34962},{\"buffer\":13,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_Y_DAG\",\"target\":34962},{\"buffer\":14,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_S\",\"target\":34962},{\"buffer\":15,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_S_DAG\",\"target\":34962},{\"buffer\":16,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":17,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_zswap_line_cross\",\"target\":34962},{\"buffer\":18,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":19,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_xswap_line_cross\",\"target\":34962},{\"buffer\":20,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ISWAP\",\"target\":34962},{\"buffer\":21,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ISWAP_DAG\",\"target\":34962},{\"buffer\":22,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SWAP\",\"target\":34962},{\"buffer\":23,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_XX\",\"target\":34962},{\"buffer\":24,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_XX_DAG\",\"target\":34962},{\"buffer\":25,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_YY\",\"target\":34962},{\"buffer\":26,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_YY_DAG\",\"target\":34962},{\"buffer\":27,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_ZZ\",\"target\":34962},{\"buffer\":28,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_ZZ_DAG\",\"target\":34962},{\"buffer\":29,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":30,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_x_line_cross\",\"target\":34962},{\"buffer\":31,\"byteLength\":36,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":32,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":33,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_E:X\",\"target\":34962},{\"buffer\":34,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_E:Y\",\"target\":34962},{\"buffer\":35,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_E:Z\",\"target\":34962},{\"buffer\":36,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:X\",\"target\":34962},{\"buffer\":37,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Y\",\"target\":34962},{\"buffer\":38,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Z\",\"target\":34962},{\"buffer\":39,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_DEPOLARIZE1\",\"target\":34962},{\"buffer\":40,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_DEPOLARIZE2\",\"target\":34962},{\"buffer\":41,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_PAULI_CHANNEL_1\",\"target\":34962},{\"buffer\":42,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_PAULI_CHANNEL_2\",\"target\":34962},{\"buffer\":43,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_X_ERROR\",\"target\":34962},{\"buffer\":44,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Y_ERROR\",\"target\":34962},{\"buffer\":45,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_Z_ERROR\",\"target\":34962},{\"buffer\":46,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:X\",\"target\":34962},{\"buffer\":47,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:Y\",\"target\":34962},{\"buffer\":48,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPP:Z\",\"target\":34962},{\"buffer\":49,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MRX\",\"target\":34962},{\"buffer\":50,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MRY\",\"target\":34962},{\"buffer\":51,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MR\",\"target\":34962},{\"buffer\":52,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MX\",\"target\":34962},{\"buffer\":53,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MY\",\"target\":34962},{\"buffer\":54,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_M\",\"target\":34962},{\"buffer\":55,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_RX\",\"target\":34962},{\"buffer\":56,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_RY\",\"target\":34962},{\"buffer\":57,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_R\",\"target\":34962},{\"buffer\":58,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MXX\",\"target\":34962},{\"buffer\":59,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MYY\",\"target\":34962},{\"buffer\":60,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MZZ\",\"target\":34962},{\"buffer\":61,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_MPAD\",\"target\":34962},{\"buffer\":62,\"byteLength\":1440,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":63,\"byteLength\":360,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962},{\"buffer\":64,\"byteLength\":1152,\"byteOffset\":0,\"name\":\"buf_blue_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_I\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAwD4AAAAAAADAPgAAgD0AAOA+AAAAAAAAwD4AAAAAAADgPgAAgD0AAOA+AACAPQAA4D4AAIA9AADAPgAAAAAAAOA+AAAAAAAA4D4AAIA9AADAPgAAAAAAAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_X\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAwD4AAAAAAADAPgAAgD0AAOA+AAAAAAAAwD4AAAAAAADgPgAAgD0AAOA+AACAPQAA4D4AAIA9AADAPgAAAAAAAOA+AAAAAAAA4D4AAIA9AADAPgAAAAAAAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Y\",\"uri\":\"data:application/octet-stream;base64,AACAPQAA4D4AAAAAAADgPgAAgD0AAAA/AAAAAAAA4D4AAAAAAAAAPwAAgD0AAAA/AACAPQAAAD8AAIA9AADgPgAAAAAAAAA/AAAAAAAAAD8AAIA9AADgPgAAAAAAAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Z\",\"uri\":\"data:application/octet-stream;base64,AACAPQAAAD8AAAAAAAAAPwAAgD0AABA/AAAAAAAAAD8AAAAAAAAQPwAAgD0AABA/AACAPQAAED8AAIA9AAAAPwAAAAAAABA/AAAAAAAAED8AAIA9AAAAPwAAAAAAAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_XYZ\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAED8AAIA9AAAQPwAAAD4AACA/AACAPQAAED8AAIA9AAAgPwAAAD4AACA/AAAAPgAAID8AAAA+AAAQPwAAgD0AACA/AACAPQAAID8AAAA+AAAQPwAAgD0AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_C_ZYX\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAED8AAAA+AAAQPwAAQD4AACA/AAAAPgAAED8AAAA+AAAgPwAAQD4AACA/AABAPgAAID8AAEA+AAAQPwAAAD4AACA/AAAAPgAAID8AAEA+AAAQPwAAAD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H_XY\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAAD8AAIA9AAAAPwAAAD4AABA/AACAPQAAAD8AAIA9AAAQPwAAAD4AABA/AAAAPgAAED8AAAA+AAAAPwAAgD0AABA/AACAPQAAED8AAAA+AAAAPwAAgD0AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAA4D4AAIA9AADgPgAAAD4AAAA/AACAPQAA4D4AAIA9AAAAPwAAAD4AAAA/AAAAPgAAAD8AAAA+AADgPgAAgD0AAAA/AACAPQAAAD8AAAA+AADgPgAAgD0AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H_YZ\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAAwD4AAIA9AADAPgAAAD4AAOA+AACAPQAAwD4AAIA9AADgPgAAAD4AAOA+AAAAPgAA4D4AAAA+AADAPgAAgD0AAOA+AACAPQAA4D4AAAA+AADAPgAAgD0AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_X\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAwD4AAAA+AADAPgAAQD4AAOA+AAAAPgAAwD4AAAA+AADgPgAAQD4AAOA+AABAPgAA4D4AAEA+AADAPgAAAD4AAOA+AAAAPgAA4D4AAEA+AADAPgAAAD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_X_DAG\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAwD4AAEA+AADAPgAAgD4AAOA+AABAPgAAwD4AAEA+AADgPgAAgD4AAOA+AACAPgAA4D4AAIA+AADAPgAAQD4AAOA+AABAPgAA4D4AAIA+AADAPgAAQD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_Y\",\"uri\":\"data:application/octet-stream;base64,AABAPgAA4D4AAAA+AADgPgAAQD4AAAA/AAAAPgAA4D4AAAA+AAAAPwAAQD4AAAA/AABAPgAAAD8AAEA+AADgPgAAAD4AAAA/AAAAPgAAAD8AAEA+AADgPgAAAD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_Y_DAG\",\"uri\":\"data:application/octet-stream;base64,AACAPgAA4D4AAEA+AADgPgAAgD4AAAA/AABAPgAA4D4AAEA+AAAAPwAAgD4AAAA/AACAPgAAAD8AAIA+AADgPgAAQD4AAAA/AABAPgAAAD8AAIA+AADgPgAAQD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_S\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAAD8AAAA+AAAAPwAAQD4AABA/AAAAPgAAAD8AAAA+AAAQPwAAQD4AABA/AABAPgAAED8AAEA+AAAAPwAAAD4AABA/AAAAPgAAED8AAEA+AAAAPwAAAD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_S_DAG\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAAD8AAEA+AAAAPwAAgD4AABA/AABAPgAAAD8AAEA+AAAQPwAAgD4AABA/AACAPgAAED8AAIA+AAAAPwAAQD4AABA/AABAPgAAED8AAIA+AAAAPwAAQD4AAAA/\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_zswap_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAGu0575rtOe+AAAAAGu05z5rtOc+AAAAAGu0575rtOc+AAAAAGu05z5rtOe+\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_xswap_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAGu0575rtOe+AAAAAGu05z5rtOc+AAAAAGu0575rtOc+AAAAAGu05z5rtOe+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ISWAP\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAED8AAKA+AAAQPwAAwD4AACA/AACgPgAAED8AAKA+AAAgPwAAwD4AACA/AADAPgAAID8AAMA+AAAQPwAAoD4AACA/AACgPgAAID8AAMA+AAAQPwAAoD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ISWAP_DAG\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAED8AAMA+AAAQPwAA4D4AACA/AADAPgAAED8AAMA+AAAgPwAA4D4AACA/AADgPgAAID8AAOA+AAAQPwAAwD4AACA/AADAPgAAID8AAOA+AAAQPwAAwD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SWAP\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAED8AAOA+AAAQPwAAAD8AACA/AADgPgAAED8AAOA+AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AAAQPwAA4D4AACA/AADgPgAAID8AAAA/AAAQPwAA4D4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_XX\",\"uri\":\"data:application/octet-stream;base64,AABAPwAAwD4AADA/AADAPgAAQD8AAOA+AAAwPwAAwD4AADA/AADgPgAAQD8AAOA+AABAPwAA4D4AAEA/AADAPgAAMD8AAOA+AAAwPwAA4D4AAEA/AADAPgAAMD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_XX_DAG\",\"uri\":\"data:application/octet-stream;base64,AABQPwAAwD4AAEA/AADAPgAAUD8AAOA+AABAPwAAwD4AAEA/AADgPgAAUD8AAOA+AABQPwAA4D4AAFA/AADAPgAAQD8AAOA+AABAPwAA4D4AAFA/AADAPgAAQD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_YY\",\"uri\":\"data:application/octet-stream;base64,AABAPwAA4D4AADA/AADgPgAAQD8AAAA/AAAwPwAA4D4AADA/AAAAPwAAQD8AAAA/AABAPwAAAD8AAEA/AADgPgAAMD8AAAA/AAAwPwAAAD8AAEA/AADgPgAAMD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_YY_DAG\",\"uri\":\"data:application/octet-stream;base64,AABQPwAA4D4AAEA/AADgPgAAUD8AAAA/AABAPwAA4D4AAEA/AAAAPwAAUD8AAAA/AABQPwAAAD8AAFA/AADgPgAAQD8AAAA/AABAPwAAAD8AAFA/AADgPgAAQD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_ZZ\",\"uri\":\"data:application/octet-stream;base64,AABAPwAAAD8AADA/AAAAPwAAQD8AABA/AAAwPwAAAD8AADA/AAAQPwAAQD8AABA/AABAPwAAED8AAEA/AAAAPwAAMD8AABA/AAAwPwAAED8AAEA/AAAAPwAAMD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_ZZ_DAG\",\"uri\":\"data:application/octet-stream;base64,AABQPwAAAD8AAEA/AAAAPwAAUD8AABA/AABAPwAAAD8AAEA/AAAQPwAAUD8AABA/AABQPwAAED8AAFA/AAAAPwAAQD8AABA/AABAPwAAED8AAFA/AAAAPwAAQD8AAAA/\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_x_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzL4AAAAAAAAAAM3MzD4AAAAAAAAAAAAAAADNzMy+AAAAAAAAAADNzMw+\"},{\"byteLength\":36,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAM/MTL6sXLE+AAAAAMvMTL6tXLG+\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_E:X\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAwD4AAAA/AADAPgAAED8AAOA+AAAAPwAAwD4AAAA/AADgPgAAED8AAOA+AAAQPwAA4D4AABA/AADAPgAAAD8AAOA+AAAAPwAA4D4AABA/AADAPgAAAD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_E:Y\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAA4D4AAAA/AADgPgAAED8AAAA/AAAAPwAA4D4AAAA/AAAAPwAAED8AAAA/AAAQPwAAAD8AABA/AADgPgAAAD8AAAA/AAAAPwAAAD8AABA/AADgPgAAAD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_E:Z\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAAD8AAAA/AAAAPwAAED8AABA/AAAAPwAAAD8AAAA/AAAQPwAAED8AABA/AAAQPwAAED8AABA/AAAAPwAAAD8AABA/AAAAPwAAED8AABA/AAAAPwAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:X\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAwD4AABA/AADAPgAAID8AAOA+AAAQPwAAwD4AABA/AADgPgAAID8AAOA+AAAgPwAA4D4AACA/AADAPgAAED8AAOA+AAAQPwAA4D4AACA/AADAPgAAED8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Y\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAA4D4AABA/AADgPgAAID8AAAA/AAAQPwAA4D4AABA/AAAAPwAAID8AAAA/AAAgPwAAAD8AACA/AADgPgAAED8AAAA/AAAQPwAAAD8AACA/AADgPgAAED8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ELSE_CORRELATED_ERROR:Z\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAAD8AABA/AAAAPwAAID8AABA/AAAQPwAAAD8AABA/AAAQPwAAID8AABA/AAAgPwAAED8AACA/AAAAPwAAED8AABA/AAAQPwAAED8AACA/AAAAPwAAED8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_DEPOLARIZE1\",\"uri\":\"data:application/octet-stream;base64,AACAPgAAED8AAEA+AAAQPwAAgD4AACA/AABAPgAAED8AAEA+AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AAAQPwAAQD4AACA/AABAPgAAID8AAIA+AAAQPwAAQD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_DEPOLARIZE2\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAED8AAIA+AAAQPwAAoD4AACA/AACAPgAAED8AAIA+AAAgPwAAoD4AACA/AACgPgAAID8AAKA+AAAQPwAAgD4AACA/AACAPgAAID8AAKA+AAAQPwAAgD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_PAULI_CHANNEL_1\",\"uri\":\"data:application/octet-stream;base64,AAAQPwAAED8AAAA/AAAQPwAAED8AACA/AAAAPwAAED8AAAA/AAAgPwAAED8AACA/AAAQPwAAID8AABA/AAAQPwAAAD8AACA/AAAAPwAAID8AABA/AAAQPwAAAD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_PAULI_CHANNEL_2\",\"uri\":\"data:application/octet-stream;base64,AAAgPwAAED8AABA/AAAQPwAAID8AACA/AAAQPwAAED8AABA/AAAgPwAAID8AACA/AAAgPwAAID8AACA/AAAQPwAAED8AACA/AAAQPwAAID8AACA/AAAQPwAAED8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_X_ERROR\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAwD4AAOA+AADAPgAAAD8AAOA+AADgPgAAwD4AAOA+AADgPgAAAD8AAOA+AAAAPwAA4D4AAAA/AADAPgAA4D4AAOA+AADgPgAA4D4AAAA/AADAPgAA4D4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Y_ERROR\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAA4D4AAOA+AADgPgAAAD8AAAA/AADgPgAA4D4AAOA+AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AADgPgAA4D4AAAA/AADgPgAAAD8AAAA/AADgPgAA4D4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_Z_ERROR\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAAD8AAOA+AAAAPwAAAD8AABA/AADgPgAAAD8AAOA+AAAQPwAAAD8AABA/AAAAPwAAED8AAAA/AAAAPwAA4D4AABA/AADgPgAAED8AAAA/AAAAPwAA4D4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:X\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAwD4AACA/AADAPgAAMD8AAOA+AAAgPwAAwD4AACA/AADgPgAAMD8AAOA+AAAwPwAA4D4AADA/AADAPgAAID8AAOA+AAAgPwAA4D4AADA/AADAPgAAID8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:Y\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAA4D4AACA/AADgPgAAMD8AAAA/AAAgPwAA4D4AACA/AAAAPwAAMD8AAAA/AAAwPwAAAD8AADA/AADgPgAAID8AAAA/AAAgPwAAAD8AADA/AADgPgAAID8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPP:Z\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAAD8AACA/AAAAPwAAMD8AABA/AAAgPwAAAD8AACA/AAAQPwAAMD8AABA/AAAwPwAAED8AADA/AAAAPwAAID8AABA/AAAgPwAAED8AADA/AAAAPwAAID8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MRX\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAwD4AAMA+AADAPgAA4D4AAOA+AADAPgAAwD4AAMA+AADgPgAA4D4AAOA+AADgPgAA4D4AAOA+AADAPgAAwD4AAOA+AADAPgAA4D4AAOA+AADAPgAAwD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MRY\",\"uri\":\"data:application/octet-stream;base64,AADgPgAA4D4AAMA+AADgPgAA4D4AAAA/AADAPgAA4D4AAMA+AAAAPwAA4D4AAAA/AADgPgAAAD8AAOA+AADgPgAAwD4AAAA/AADAPgAAAD8AAOA+AADgPgAAwD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MR\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAAD8AAMA+AAAAPwAA4D4AABA/AADAPgAAAD8AAMA+AAAQPwAA4D4AABA/AADgPgAAED8AAOA+AAAAPwAAwD4AABA/AADAPgAAED8AAOA+AAAAPwAAwD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MX\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAwD4AAIA+AADAPgAAoD4AAOA+AACAPgAAwD4AAIA+AADgPgAAoD4AAOA+AACgPgAA4D4AAKA+AADAPgAAgD4AAOA+AACAPgAA4D4AAKA+AADAPgAAgD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MY\",\"uri\":\"data:application/octet-stream;base64,AACgPgAA4D4AAIA+AADgPgAAoD4AAAA/AACAPgAA4D4AAIA+AAAAPwAAoD4AAAA/AACgPgAAAD8AAKA+AADgPgAAgD4AAAA/AACAPgAAAD8AAKA+AADgPgAAgD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_M\",\"uri\":\"data:application/octet-stream;base64,AACgPgAAAD8AAIA+AAAAPwAAoD4AABA/AACAPgAAAD8AAIA+AAAQPwAAoD4AABA/AACgPgAAED8AAKA+AAAAPwAAgD4AABA/AACAPgAAED8AAKA+AAAAPwAAgD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_RX\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAwD4AAKA+AADAPgAAwD4AAOA+AACgPgAAwD4AAKA+AADgPgAAwD4AAOA+AADAPgAA4D4AAMA+AADAPgAAoD4AAOA+AACgPgAA4D4AAMA+AADAPgAAoD4AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_RY\",\"uri\":\"data:application/octet-stream;base64,AADAPgAA4D4AAKA+AADgPgAAwD4AAAA/AACgPgAA4D4AAKA+AAAAPwAAwD4AAAA/AADAPgAAAD8AAMA+AADgPgAAoD4AAAA/AACgPgAAAD8AAMA+AADgPgAAoD4AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_R\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAAD8AAKA+AAAAPwAAwD4AABA/AACgPgAAAD8AAKA+AAAQPwAAwD4AABA/AADAPgAAED8AAMA+AAAAPwAAoD4AABA/AACgPgAAED8AAMA+AAAAPwAAoD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MXX\",\"uri\":\"data:application/octet-stream;base64,AAAwPwAAED8AACA/AAAQPwAAMD8AACA/AAAgPwAAED8AACA/AAAgPwAAMD8AACA/AAAwPwAAID8AADA/AAAQPwAAID8AACA/AAAgPwAAID8AADA/AAAQPwAAID8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MYY\",\"uri\":\"data:application/octet-stream;base64,AABAPwAAED8AADA/AAAQPwAAQD8AACA/AAAwPwAAED8AADA/AAAgPwAAQD8AACA/AABAPwAAID8AAEA/AAAQPwAAMD8AACA/AAAwPwAAID8AAEA/AAAQPwAAMD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MZZ\",\"uri\":\"data:application/octet-stream;base64,AABQPwAAED8AAEA/AAAQPwAAUD8AACA/AABAPwAAED8AAEA/AAAgPwAAUD8AACA/AABQPwAAID8AAFA/AAAQPwAAQD8AACA/AABAPwAAID8AAFA/AAAQPwAAQD8AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_MPAD\",\"uri\":\"data:application/octet-stream;base64,AABgPwAAED8AAFA/AAAQPwAAYD8AACA/AABQPwAAED8AAFA/AAAgPwAAYD8AACA/AABgPwAAID8AAGA/AAAQPwAAUD8AACA/AABQPwAAID8AAGA/AAAQPwAAUD8AABA/\"},{\"byteLength\":1440,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AABAwAAAAMIAAADCAABQwAAAiMEAAIDBAABQwAAAiMEAAIDBAABAwAAAAMAAAACAAABAwAAAgMAAAACAAABAwAAAwMAAAACAAABAwAAAAMEAAACAAABAwAAAIMEAAACAAABAwAAAQMEAAACAAABAwAAAYMEAAACAAABAwAAAgMEAAACAAABAwAAAkMEAAACAAACAwAAAAMIAAADCAACIwAAAiMEAAIDBAACIwAAAiMEAAIDBAACAwAAAAMAAAACAAACAwAAAgMAAAACAAACAwAAAwMAAAACAAACAwAAAAMEAAACAAACAwAAAIMEAAACAAACAwAAAQMEAAACAAACAwAAAYMEAAACAAACAwAAAgMEAAACAAACAwAAAkMEAAACAAACAwAAAoMEAAACAAACAwAAAsMEAAACAAACgwAAAAMIAAADCAACowAAAiMEAAIDBAACowAAAiMEAAIDBAACgwAAAAMAAAACAAACgwAAAgMAAAACAAACgwAAAwMAAAACAAACgwAAAAMEAAACAAACgwAAAIMEAAACAAACgwAAAQMEAAACAAACgwAAAYMEAAACAAACgwAAAgMEAAACAAACgwAAAkMEAAACAAACgwAAAoMEAAACAAACgwAAAsMEAAACAAACgwAAAwMEAAACAAACgwAAA0MEAAACAAACgwAAA4MEAAACAAACgwAAA8MEAAACAAACgwAAAAMIAAACAAACgwAAACMIAAACAAADAwAAAgMAAAACAAADAwAAAAMAAAACAAADAwAAAwMAAAACAAADAwAAAgMAAAACAAADAwAAAYMEAAACAAADIwAAAMMEAAACAAADIwAAAMMEAAACAAADAwAAAAMEAAACAAADAwAAAQMEAAACAAADAwAAAYMEAAACAAADgwAAAAMAAAACAAADgwAAAgMAAAACAAADgwAAAAMEAAACAAADgwAAAIMEAAACAAAAQwQAAAMAAAACAAAAUwQAAiMEAAIDBAAAUwQAAiMEAAIDBAAAQwQAAAMIAAADCAAAQwQAAgMAAAACAAAAQwQAAAMAAAACAAAAgwQAAAMAAAACAAAAkwQAAiMEAAIDBAAAkwQAAiMEAAIDBAAAgwQAAAMIAAADCAABAwQAAAMIAAADCAABEwQAAiMEAAIDBAABEwQAAiMEAAIDBAABAwQAAAMAAAACAAABAwQAAgMAAAACAAABAwQAAwMAAAACAAABAwQAAAMEAAACAAABAwQAAIMEAAACAAABAwQAAQMEAAACAAABAwQAAYMEAAACAAABwwQAAAMIAAADCAAB0wQAAiMEAAIDBAAB0wQAAiMEAAIDBAABwwQAAAMAAAACAAACAPwAAAMIAAADCAADIwQAAAMIAAADCAACAPwAAAMAAAACAAADIwQAAAMAAAACAAACAPwAAgMAAAACAAADIwQAAgMAAAACAAACAPwAAwMAAAACAAADIwQAAwMAAAACAAACAPwAAAMEAAACAAADIwQAAAMEAAACAAACAPwAAIMEAAACAAADIwQAAIMEAAACAAACAPwAAQMEAAACAAADIwQAAQMEAAACAAACAPwAAYMEAAACAAADIwQAAYMEAAACAAACAPwAAgMEAAACAAADIwQAAgMEAAACAAACAPwAAkMEAAACAAADIwQAAkMEAAACAAACAPwAAoMEAAACAAADIwQAAoMEAAACAAACAPwAAsMEAAACAAADIwQAAsMEAAACAAACAPwAAwMEAAACAAADIwQAAwMEAAACAAACAPwAA0MEAAACAAADIwQAA0MEAAACAAACAPwAA4MEAAACAAADIwQAA4MEAAACAAACAPwAA8MEAAACAAADIwQAA8MEAAACAAACAPwAAAMIAAACAAADIwQAAAMIAAACAAACAPwAACMIAAACAAADIwQAACMIAAACA\"},{\"byteLength\":360,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAIAAAIDBAABAwAAAAIAAAIDBAAAgwAAAAL8AAIDBAABAwAAAAIAAAIDBAAAgwAAAAD8AAIDBAABAwAAAAIAAAIDBAABcwQAAgL8AAIA/AABcwQAAgL8AAATCAABcwQAAgL8AAIA/AABcwQAADMIAAIA/AABcwQAAgL8AAIA/AACKwQAAgL8AAIA/AABcwQAAgL8AAATCAABcwQAADMIAAATCAABcwQAAgL8AAATCAACKwQAAgL8AAATCAABcwQAADMIAAIA/AABcwQAADMIAAATCAABcwQAADMIAAIA/AACKwQAADMIAAIA/AABcwQAADMIAAATCAACKwQAADMIAAATCAACKwQAAgL8AAIA/AACKwQAAgL8AAATCAACKwQAAgL8AAIA/AACKwQAADMIAAIA/AACKwQAAgL8AAATCAACKwQAADMIAAATCAACKwQAADMIAAIA/AACKwQAADMIAAATC\"},{\"byteLength\":1152,\"name\":\"buf_blue_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AABAv83MzL8AAAA/AABAv5qZmb8AAAA/AABAv83MzL8AAALCAABAv5qZmb8AAALCAABAv5qZmb8AAAA/AABAv5qZmb8AAALCAABAv5qZmb8AAAA/AAAQwJqZmb8AAAA/AABAv5qZmb8AAALCAAAQwJqZmb8AAALCAAAQwM3MzL8AAAA/AAAQwJqZmb8AAAA/AAAQwM3MzL8AAALCAAAQwJqZmb8AAALCAAAQwJqZmb8AAAA/AAAQwJqZmb8AAALCAAAwwM3MzL8AAAA/AAAwwJqZmb8AAAA/AAAwwM3MzL8AAALCAAAwwJqZmb8AAALCAAAwwJqZmb8AAAA/AAAwwJqZmb8AAALCAAAwwJqZmb8AAAA/AACowJqZmb8AAAA/AAAwwJqZmb8AAALCAACowJqZmb8AAALCAACowM3MzL8AAAA/AACowJqZmb8AAAA/AACowM3MzL8AAALCAACowJqZmb8AAALCAACowJqZmb8AAAA/AACowJqZmb8AAALCAAC4wM3MzL8AAAA/AAC4wJqZmb8AAAA/AAC4wM3MzL8AAALCAAC4wJqZmb8AAALCAAC4wJqZmb8AAAA/AAC4wJqZmb8AAALCAAC4wJqZmb8AAAA/AAAEwZqZmb8AAAA/AAC4wJqZmb8AAALCAAAEwZqZmb8AAALCAAAEwc3MzL8AAAA/AAAEwZqZmb8AAAA/AAAEwc3MzL8AAALCAAAEwZqZmb8AAALCAAAEwZqZmb8AAAA/AAAEwZqZmb8AAALCAAAMwc3MzL8AAAA/AAAMwZqZmb8AAAA/AAAMwc3MzL8AAALCAAAMwZqZmb8AAALCAAAMwZqZmb8AAAA/AAAMwZqZmb8AAALCAAAMwZqZmb8AAAA/AAA0wZqZmb8AAAA/AAAMwZqZmb8AAALCAAA0wZqZmb8AAALCAAA0wc3MzL8AAAA/AAA0wZqZmb8AAAA/AAA0wc3MzL8AAALCAAA0wZqZmb8AAALCAAA0wZqZmb8AAAA/AAA0wZqZmb8AAALCAABcwc3MzL8AAAA/AABcwZqZmb8AAAA/AABcwc3MzL8AAALCAABcwZqZmb8AAALCAABcwZqZmb8AAAA/AABcwZqZmb8AAALCAABcwZqZmb8AAAA/AACCwZqZmb8AAAA/AABcwZqZmb8AAALCAACCwZqZmb8AAALCAACCwc3MzL8AAAA/AACCwZqZmb8AAAA/AACCwc3MzL8AAALCAACCwZqZmb8AAALCAACCwZqZmb8AAAA/AACCwZqZmb8AAALCAACWwc3MzL8AAAA/AACWwZqZmb8AAAA/AACWwc3MzL8AAALCAACWwZqZmb8AAALCAACWwZqZmb8AAAA/AACWwZqZmb8AAALCAACWwZqZmb8AAAA/AAC6wZqZmb8AAAA/AACWwZqZmb8AAALCAAC6wZqZmb8AAALCAAC6wc3MzL8AAAA/AAC6wZqZmb8AAAA/AAC6wc3MzL8AAALCAAC6wZqZmb8AAALCAAC6wZqZmb8AAAA/AAC6wZqZmb8AAALC\"}],\"images\":[{\"name\":\"gates_image\",\"uri\":\"data:image/png;base64,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E2JjY9H8uR/56pw9exZmZmbSq8/G8APAaoANGr+sGuC7egCurhvw77//4ty5c3j06BG6du0KR0dH2bqf+/fv4/jx4xAKhfj444/lcmGkpKTg+PHjSEpKgqWlJfr3749nz57h7NmzePToEVq0aAFdXV1ZoSwrKyt069ZNbgTuXa8G2OAdgNqWA6776CMbND7LAb/+6ZeUlARfX1+sX78eRUVFWLJkCSZPnowWLVrUyzEXFRVh+/bt+Oabb5CYmIhRo0Zh1qxZ6FbDbpAyf/75JywtLevt2NgBYAfgbesANCR2ANgBYAfgPzICQOwAsAPADgA7AERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERPT/gnx31HLEbHgAAAAASUVORK5CYII=\"}],\"materials\":[{\"doubleSided\":false,\"name\":\"gates_material\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"name\":\"black\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"name\":\"white\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"name\":\"white\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"name\":\"black\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"name\":\"white\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"name\":\"black\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"name\":\"black\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"name\":\"gray\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[0.5,0.5,0.5,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"name\":\"black\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"name\":\"black\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"name\":\"red\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"name\":\"blue\",\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,1,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":4},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":5},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":6},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":7},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":8},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":9},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":10},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":11},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":12},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":13},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":14},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":15},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":16},\"material\":1,\"mode\":6},{\"attributes\":{\"POSITION\":17},\"material\":2,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":18},\"material\":3,\"mode\":6},{\"attributes\":{\"POSITION\":18},\"material\":4,\"mode\":3},{\"attributes\":{\"POSITION\":19},\"material\":4,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":20},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":21},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":22},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":23},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":24},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":25},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":26},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":27},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":28},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":29},\"material\":5,\"mode\":6},{\"attributes\":{\"POSITION\":29},\"material\":6,\"mode\":3},{\"attributes\":{\"POSITION\":30},\"material\":6,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":31},\"material\":7,\"mode\":2},{\"attributes\":{\"POSITION\":31},\"material\":8,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":32},\"material\":9,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":33},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":34},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":35},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":36},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":37},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":38},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":39},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":40},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":41},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":42},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":43},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":44},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":45},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":46},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":47},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":48},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":49},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":50},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":51},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":52},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":53},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":54},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":55},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":56},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":57},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":58},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":59},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":60},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":61},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":62},\"material\":10,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":63},\"material\":11,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":64},\"material\":12,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-32,-32]},{\"mesh\":1,\"translation\":[-0,-2,-0]},{\"mesh\":2,\"translation\":[-0,-4,-0]},{\"mesh\":3,\"translation\":[-0,-6,-0]},{\"mesh\":4,\"translation\":[-1,-32,-32]},{\"mesh\":5,\"translation\":[-1,-2,-0]},{\"mesh\":6,\"translation\":[-1,-4,-0]},{\"mesh\":7,\"translation\":[-1,-6,-0]},{\"mesh\":8,\"translation\":[-1,-8,-0]},{\"mesh\":9,\"translation\":[-2,-32,-32]},{\"mesh\":10,\"translation\":[-2,-2,-0]},{\"mesh\":11,\"translation\":[-2,-4,-0]},{\"mesh\":12,\"translation\":[-2,-6,-0]},{\"mesh\":13,\"translation\":[-2,-8,-0]},{\"mesh\":14,\"translation\":[-2,-10,-0]},{\"mesh\":15,\"translation\":[-3,-32,-32]},{\"mesh\":16,\"translation\":[-3,-2,-0]},{\"mesh\":17,\"translation\":[-3,-4,-0]},{\"mesh\":17,\"translation\":[-3,-6,-0]},{\"mesh\":18,\"translation\":[-3,-8,-0]},{\"mesh\":18,\"translation\":[-3,-10,-0]},{\"mesh\":19,\"translation\":[-3,-12,-0]},{\"mesh\":19,\"translation\":[-3,-14,-0]},{\"mesh\":16,\"translation\":[-3,-16,-0]},{\"mesh\":15,\"translation\":[-3,-18,-0]},{\"mesh\":20,\"translation\":[-4,-32,-32]},{\"mesh\":20,\"translation\":[-4,-2,-0]},{\"mesh\":21,\"translation\":[-4,-4,-0]},{\"mesh\":21,\"translation\":[-4,-6,-0]},{\"mesh\":22,\"translation\":[-4,-8,-0]},{\"mesh\":22,\"translation\":[-4,-10,-0]},{\"mesh\":23,\"translation\":[-4,-12,-0]},{\"mesh\":23,\"translation\":[-4,-14,-0]},{\"mesh\":24,\"translation\":[-4,-16,-0]},{\"mesh\":24,\"translation\":[-4,-18,-0]},{\"mesh\":25,\"translation\":[-4,-20,-0]},{\"mesh\":25,\"translation\":[-4,-22,-0]},{\"mesh\":26,\"translation\":[-5,-32,-32]},{\"mesh\":26,\"translation\":[-5,-2,-0]},{\"mesh\":26,\"translation\":[-5,-4,-0]},{\"mesh\":27,\"translation\":[-5,-6,-0]},{\"mesh\":26,\"translation\":[-5,-8,-0]},{\"mesh\":28,\"translation\":[-5,-10,-0]},{\"mesh\":27,\"translation\":[-5,-12,-0]},{\"mesh\":26,\"translation\":[-5,-14,-0]},{\"mesh\":27,\"translation\":[-5,-16,-0]},{\"mesh\":27,\"translation\":[-5,-18,-0]},{\"mesh\":27,\"translation\":[-5,-20,-0]},{\"mesh\":28,\"translation\":[-5,-22,-0]},{\"mesh\":28,\"translation\":[-5,-24,-0]},{\"mesh\":26,\"translation\":[-5,-26,-0]},{\"mesh\":28,\"translation\":[-5,-28,-0]},{\"mesh\":27,\"translation\":[-5,-30,-0]},{\"mesh\":28,\"translation\":[-5,-32,-0]},{\"mesh\":28,\"translation\":[-5,-34,-0]},{\"mesh\":29,\"translation\":[-6,-2,-0]},{\"mesh\":30,\"translation\":[-6,-4,-0]},{\"mesh\":31,\"translation\":[-6,-6,-0]},{\"mesh\":32,\"translation\":[-6,-8,-0]},{\"mesh\":33,\"translation\":[-6,-14,-0]},{\"mesh\":34,\"translation\":[-6,-12,-0]},{\"mesh\":35,\"translation\":[-6,-32,-32]},{\"mesh\":36,\"translation\":[-7,-2,-0]},{\"mesh\":36,\"translation\":[-7,-4,-0]},{\"mesh\":37,\"translation\":[-7,-6,-0]},{\"mesh\":38,\"translation\":[-7,-8,-0]},{\"mesh\":38,\"translation\":[-7,-10,-0]},{\"mesh\":39,\"translation\":[-7,-32,-32]},{\"mesh\":40,\"translation\":[-8,-2,-0]},{\"mesh\":41,\"translation\":[-8,-4,-0]},{\"mesh\":42,\"translation\":[-9,-32,-32]},{\"mesh\":43,\"translation\":[-9,-2,-0]},{\"mesh\":44,\"translation\":[-9,-4,-0]},{\"mesh\":44,\"translation\":[-10,-32,-32]},{\"mesh\":44,\"translation\":[-10,-2,-0]},{\"mesh\":45,\"translation\":[-11,-32,-32]},{\"mesh\":46,\"translation\":[-11,-2,-0]},{\"mesh\":47,\"translation\":[-11,-4,-0]},{\"mesh\":48,\"translation\":[-11,-6,-0]},{\"mesh\":49,\"translation\":[-11,-8,-0]},{\"mesh\":50,\"translation\":[-11,-10,-0]},{\"mesh\":50,\"translation\":[-11,-12,-0]},{\"mesh\":51,\"translation\":[-11,-14,-0]},{\"mesh\":52,\"translation\":[-11,-16,-0]},{\"mesh\":53,\"translation\":[-11,-18,-0]},{\"mesh\":54,\"translation\":[-12,-32,-32]},{\"mesh\":54,\"translation\":[-12,-2,-0]},{\"mesh\":54,\"translation\":[-12,-4,-0]},{\"mesh\":54,\"translation\":[-12,-6,-0]},{\"mesh\":55,\"translation\":[-12,-8,-0]},{\"mesh\":55,\"translation\":[-12,-10,-0]},{\"mesh\":56,\"translation\":[-12,-12,-0]},{\"mesh\":56,\"translation\":[-12,-14,-0]},{\"mesh\":7,\"translation\":[-14,-32,-32]},{\"mesh\":28,\"translation\":[-15,-32,-32]},{\"mesh\":26,\"translation\":[-15,-2,-0]},{\"mesh\":13,\"translation\":[-16,-2,-0]},{\"mesh\":47,\"translation\":[-19,-32,-32]},{\"mesh\":39,\"translation\":[-20,-32,-32]},{\"mesh\":47,\"translation\":[-21,-32,-32]},{\"mesh\":57,\"translation\":[-22,-32,-32]},{\"mesh\":57,\"translation\":[-22,-2,-0]},{\"mesh\":57,\"translation\":[-23,-32,-32]},{\"mesh\":58,\"translation\":[0,0,0]},{\"mesh\":59,\"translation\":[0,0,0]},{\"mesh\":60,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105]}],\"textures\":[{\"name\":\"gates_texture\",\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/tick.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.125,0.5],\"min\":[0.0625,0.4375],\"name\":\"tex_coords_gate_H\",\"type\":\"VEC2\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.5625],\"min\":[0.125,0.5],\"name\":\"tex_coords_gate_S\",\"type\":\"VEC2\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.1875,0.4375],\"min\":[0.125,0.375],\"name\":\"tex_coords_gate_SQRT_X\",\"type\":\"VEC2\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[1,-0,-0],\"min\":[-12,-2,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":30,\"max\":[0,2.5,1],\"min\":[-6.25,-3,-1],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":32,\"max\":[0.25,0.800000011920929,0.5],\"min\":[-9.25,0.400000005960464,-0.5],\"name\":\"buf_blue_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":1,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_H\",\"target\":34962},{\"buffer\":2,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_S\",\"target\":34962},{\"buffer\":3,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_X\",\"target\":34962},{\"buffer\":4,\"byteLength\":48,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":5,\"byteLength\":360,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962},{\"buffer\":6,\"byteLength\":384,\"byteOffset\":0,\"name\":\"buf_blue_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_H\",\"uri\":\"data:application/octet-stream;base64,AAAAPgAA4D4AAIA9AADgPgAAAD4AAAA/AACAPQAA4D4AAIA9AAAAPwAAAD4AAAA/AAAAPgAAAD8AAAA+AADgPgAAgD0AAAA/AACAPQAAAD8AAAA+AADgPgAAgD0AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_S\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAAD8AAAA+AAAAPwAAQD4AABA/AAAAPgAAAD8AAAA+AAAQPwAAQD4AABA/AABAPgAAED8AAEA+AAAAPwAAAD4AABA/AAAAPgAAED8AAEA+AAAAPwAAAD4AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_X\",\"uri\":\"data:application/octet-stream;base64,AABAPgAAwD4AAAA+AADAPgAAQD4AAOA+AAAAPgAAwD4AAAA+AADgPgAAQD4AAOA+AABAPgAA4D4AAEA+AADAPgAAAD4AAOA+AAAAPgAA4D4AAEA+AADAPgAAAD4AAMA+\"},{\"byteLength\":48,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAPwAAAIAAAACAAABAwQAAAIAAAACAAACAPwAAAMAAAACAAABAwQAAAMAAAACA\"},{\"byteLength\":360,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACAAABwwAAAgD8AAIA/AABwwAAAgD8AAIC/AABwwAAAgD8AAIA/AABwwAAAQMAAAIA/AABwwAAAgD8AAIA/AADIwAAAgD8AAIA/AABwwAAAgD8AAIC/AABwwAAAQMAAAIC/AABwwAAAgD8AAIC/AADIwAAAgD8AAIC/AABwwAAAQMAAAIA/AABwwAAAQMAAAIC/AABwwAAAQMAAAIA/AADIwAAAQMAAAIA/AABwwAAAQMAAAIC/AADIwAAAQMAAAIC/AADIwAAAgD8AAIA/AADIwAAAgD8AAIC/AADIwAAAgD8AAIA/AADIwAAAQMAAAIA/AADIwAAAgD8AAIC/AADIwAAAQMAAAIC/AADIwAAAQMAAAIA/AADIwAAAQMAAAIC/\"},{\"byteLength\":384,\"name\":\"buf_blue_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AACAPs3MzD4AAAA/AACAPs3MTD8AAAA/AACAPs3MzD4AAAC/AACAPs3MTD8AAAC/AACAPs3MTD8AAAA/AACAPs3MTD8AAAC/AACAPs3MTD8AAAA/AACgv83MTD8AAAA/AACAPs3MTD8AAAC/AACgv83MTD8AAAC/AACgv83MzD4AAAA/AACgv83MTD8AAAA/AACgv83MzD4AAAC/AACgv83MTD8AAAC/AACgv83MTD8AAAA/AACgv83MTD8AAAC/AADYwM3MzD4AAAA/AADYwM3MTD8AAAA/AADYwM3MzD4AAAC/AADYwM3MTD8AAAC/AADYwM3MTD8AAAA/AADYwM3MTD8AAAC/AADYwM3MTD8AAAA/AAAUwc3MTD8AAAA/AADYwM3MTD8AAAC/AAAUwc3MTD8AAAC/AAAUwc3MzD4AAAA/AAAUwc3MTD8AAAA/AAAUwc3MzD4AAAC/AAAUwc3MTD8AAAC/AAAUwc3MTD8AAAA/AAAUwc3MTD8AAAC/\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,1,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":1},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":2},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":0,\"TEXCOORD_0\":3},\"material\":0,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":5},\"material\":2,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":6},\"material\":3,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":0,\"translation\":[-1,-0,-0]},{\"mesh\":0,\"translation\":[-2,-0,-0]},{\"mesh\":0,\"translation\":[-2,-2,-0]},{\"mesh\":0,\"translation\":[-3,-0,-0]},{\"mesh\":0,\"translation\":[-4,-0,-0]},{\"mesh\":0,\"translation\":[-4,-2,-0]},{\"mesh\":0,\"translation\":[-5,-0,-0]},{\"mesh\":1,\"translation\":[-6,-0,-0]},{\"mesh\":0,\"translation\":[-7,-0,-0]},{\"mesh\":0,\"translation\":[-8,-0,-0]},{\"mesh\":2,\"translation\":[-9,-0,-0]},{\"mesh\":0,\"translation\":[-10,-0,-0]},{\"mesh\":0,\"translation\":[-11,-0,-0]},{\"mesh\":3,\"translation\":[0,0,0]},{\"mesh\":4,\"translation\":[0,0,0]},{\"mesh\":5,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  },
  {
    "path": "testdata/two_qubits_gates.gltf",
    "content": "{\"accessors\":[{\"bufferView\":0,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":1,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"control_x_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":3,\"max\":[0,0.400000005960464,0.346410155296326],\"min\":[0,-0.200000032782555,-0.346410185098648],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":4,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0,0.5,0.5],\"min\":[0,-0.5,-0.5],\"name\":\"cube\",\"type\":\"VEC3\"},{\"bufferView\":5,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.375,0.625],\"min\":[0.3125,0.5625],\"name\":\"tex_coords_gate_ISWAP\",\"type\":\"VEC2\"},{\"bufferView\":6,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.4375,0.625],\"min\":[0.375,0.5625],\"name\":\"tex_coords_gate_ISWAP_DAG\",\"type\":\"VEC2\"},{\"bufferView\":7,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.4375],\"min\":[0.6875,0.375],\"name\":\"tex_coords_gate_SQRT_XX\",\"type\":\"VEC2\"},{\"bufferView\":8,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.4375],\"min\":[0.75,0.375],\"name\":\"tex_coords_gate_SQRT_XX_DAG\",\"type\":\"VEC2\"},{\"bufferView\":9,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.5],\"min\":[0.6875,0.4375],\"name\":\"tex_coords_gate_SQRT_YY\",\"type\":\"VEC2\"},{\"bufferView\":10,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.5],\"min\":[0.75,0.4375],\"name\":\"tex_coords_gate_SQRT_YY_DAG\",\"type\":\"VEC2\"},{\"bufferView\":11,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.75,0.5625],\"min\":[0.6875,0.5],\"name\":\"tex_coords_gate_SQRT_ZZ\",\"type\":\"VEC2\"},{\"bufferView\":12,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.8125,0.5625],\"min\":[0.75,0.5],\"name\":\"tex_coords_gate_SQRT_ZZ_DAG\",\"type\":\"VEC2\"},{\"bufferView\":13,\"byteOffset\":0,\"componentType\":5126,\"count\":12,\"max\":[0.5,0.625],\"min\":[0.4375,0.5625],\"name\":\"tex_coords_gate_SWAP\",\"type\":\"VEC2\"},{\"bufferView\":14,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":15,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.45254835486412,0.45254835486412],\"min\":[0,-0.45254835486412,-0.45254835486412],\"name\":\"control_zswap_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":16,\"byteOffset\":0,\"componentType\":5126,\"count\":17,\"max\":[0,0.400000005960464,0.400000005960464],\"min\":[0,-0.400000005960464,-0.400000005960464],\"name\":\"circle_loop\",\"type\":\"VEC3\"},{\"bufferView\":17,\"byteOffset\":0,\"componentType\":5126,\"count\":4,\"max\":[0,0.45254835486412,0.45254835486412],\"min\":[0,-0.45254835486412,-0.45254835486412],\"name\":\"control_xswap_line_cross\",\"type\":\"VEC3\"},{\"bufferView\":18,\"byteOffset\":0,\"componentType\":5126,\"count\":82,\"max\":[1,-0,-0],\"min\":[-12,-10,-0],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":19,\"byteOffset\":0,\"componentType\":5126,\"count\":6,\"max\":[0,2.5,-0],\"min\":[-3,1.5,-0],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":1,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":2,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_x_line_cross\",\"target\":34962},{\"buffer\":3,\"byteLength\":36,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":4,\"byteLength\":144,\"byteOffset\":0,\"name\":\"cube\",\"target\":34962},{\"buffer\":5,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ISWAP\",\"target\":34962},{\"buffer\":6,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_ISWAP_DAG\",\"target\":34962},{\"buffer\":7,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_XX\",\"target\":34962},{\"buffer\":8,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_XX_DAG\",\"target\":34962},{\"buffer\":9,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_YY\",\"target\":34962},{\"buffer\":10,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_YY_DAG\",\"target\":34962},{\"buffer\":11,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_ZZ\",\"target\":34962},{\"buffer\":12,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SQRT_ZZ_DAG\",\"target\":34962},{\"buffer\":13,\"byteLength\":96,\"byteOffset\":0,\"name\":\"tex_coords_gate_SWAP\",\"target\":34962},{\"buffer\":14,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":15,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_zswap_line_cross\",\"target\":34962},{\"buffer\":16,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":17,\"byteLength\":48,\"byteOffset\":0,\"name\":\"control_xswap_line_cross\",\"target\":34962},{\"buffer\":18,\"byteLength\":984,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":19,\"byteLength\":72,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962}],\"buffers\":[{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_x_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzL4AAAAAAAAAAM3MzD4AAAAAAAAAAAAAAADNzMy+AAAAAAAAAADNzMw+\"},{\"byteLength\":36,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAM/MTL6sXLE+AAAAAMvMTL6tXLG+\"},{\"byteLength\":144,\"name\":\"cube\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAD8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAC/AAAAAAAAAD8AAAC/AAAAAAAAAL8AAAA/AAAAAAAAAL8AAAA/AAAAAAAAAD8AAAC/AAAAAAAAAD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ISWAP\",\"uri\":\"data:application/octet-stream;base64,AADAPgAAED8AAKA+AAAQPwAAwD4AACA/AACgPgAAED8AAKA+AAAgPwAAwD4AACA/AADAPgAAID8AAMA+AAAQPwAAoD4AACA/AACgPgAAID8AAMA+AAAQPwAAoD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_ISWAP_DAG\",\"uri\":\"data:application/octet-stream;base64,AADgPgAAED8AAMA+AAAQPwAA4D4AACA/AADAPgAAED8AAMA+AAAgPwAA4D4AACA/AADgPgAAID8AAOA+AAAQPwAAwD4AACA/AADAPgAAID8AAOA+AAAQPwAAwD4AABA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_XX\",\"uri\":\"data:application/octet-stream;base64,AABAPwAAwD4AADA/AADAPgAAQD8AAOA+AAAwPwAAwD4AADA/AADgPgAAQD8AAOA+AABAPwAA4D4AAEA/AADAPgAAMD8AAOA+AAAwPwAA4D4AAEA/AADAPgAAMD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_XX_DAG\",\"uri\":\"data:application/octet-stream;base64,AABQPwAAwD4AAEA/AADAPgAAUD8AAOA+AABAPwAAwD4AAEA/AADgPgAAUD8AAOA+AABQPwAA4D4AAFA/AADAPgAAQD8AAOA+AABAPwAA4D4AAFA/AADAPgAAQD8AAMA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_YY\",\"uri\":\"data:application/octet-stream;base64,AABAPwAA4D4AADA/AADgPgAAQD8AAAA/AAAwPwAA4D4AADA/AAAAPwAAQD8AAAA/AABAPwAAAD8AAEA/AADgPgAAMD8AAAA/AAAwPwAAAD8AAEA/AADgPgAAMD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_YY_DAG\",\"uri\":\"data:application/octet-stream;base64,AABQPwAA4D4AAEA/AADgPgAAUD8AAAA/AABAPwAA4D4AAEA/AAAAPwAAUD8AAAA/AABQPwAAAD8AAFA/AADgPgAAQD8AAAA/AABAPwAAAD8AAFA/AADgPgAAQD8AAOA+\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_ZZ\",\"uri\":\"data:application/octet-stream;base64,AABAPwAAAD8AADA/AAAAPwAAQD8AABA/AAAwPwAAAD8AADA/AAAQPwAAQD8AABA/AABAPwAAED8AAEA/AAAAPwAAMD8AABA/AAAwPwAAED8AAEA/AAAAPwAAMD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SQRT_ZZ_DAG\",\"uri\":\"data:application/octet-stream;base64,AABQPwAAAD8AAEA/AAAAPwAAUD8AABA/AABAPwAAAD8AAEA/AAAQPwAAUD8AABA/AABQPwAAED8AAFA/AAAAPwAAQD8AABA/AABAPwAAED8AAFA/AAAAPwAAQD8AAAA/\"},{\"byteLength\":96,\"name\":\"tex_coords_gate_SWAP\",\"uri\":\"data:application/octet-stream;base64,AAAAPwAAED8AAOA+AAAQPwAAAD8AACA/AADgPgAAED8AAOA+AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AAAQPwAA4D4AACA/AADgPgAAID8AAAA/AAAQPwAA4D4AABA/\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_zswap_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAGu0575rtOe+AAAAAGu05z5rtOc+AAAAAGu0575rtOc+AAAAAGu05z5rtOe+\"},{\"byteLength\":204,\"name\":\"circle_loop\",\"uri\":\"data:application/octet-stream;base64,AAAAAM3MzD4AAAAAAAAAAOU1vT5Fvxw+AAAAAMPQkD7D0JA+AAAAAES/HD7lNb0+AAAAAPIwlrLNzMw+AAAAAEe/HL7lNb0+AAAAAMPQkL7D0JA+AAAAAOc1vb5Avxw+AAAAAM3MzL7yMBazAAAAAOU1vb5Evxy+AAAAAMHQkL7E0JC+AAAAADy/HL7nNb2+AAAAAPLkozHNzMy+AAAAAEm/HD7kNb2+AAAAAMbQkD6/0JC+AAAAAOY1vT5Evxy+AAAAAM3MzD4AAAAA\"},{\"byteLength\":48,\"name\":\"control_xswap_line_cross\",\"uri\":\"data:application/octet-stream;base64,AAAAAGu0575rtOe+AAAAAGu05z5rtOc+AAAAAGu0575rtOc+AAAAAGu05z5rtOe+\"},{\"byteLength\":984,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAgAAAAIAAAACAAAAAgAAAAMAAAACAAAAAgAAAgMAAAACAAAAAgAAAwMAAAACAAAAAgAAAAMEAAACAAAAAgAAAIMEAAACAAACAvwAAIMEAAACAAACAvwAAAMEAAACAAACAvwAAAIAAAACAAACgvwAAAMAAAACAAACgvwAAAMAAAACAAACAvwAAgMAAAACAAACAvwAAAMAAAACAAACgvwAAgMAAAACAAACgvwAAgMAAAACAAACAvwAAwMAAAACAAAAAwAAAgMAAAACAAAAQwAAAwMAAAACAAAAQwAAAwMAAAACAAAAAwAAAAMEAAACAAAAAwAAAwMAAAACAAAAQwAAAAMEAAACAAAAQwAAAAMEAAACAAAAAwAAAIMEAAACAAABAwAAAAIAAAACAAABQwAAAoMAAAACAAABQwAAAoMAAAACAAABAwAAAIMEAAACAAABAwAAAwMAAAACAAABAwAAAAMEAAACAAACAwAAAAMEAAACAAACAwAAAwMAAAACAAACAwAAAAIAAAACAAACAwAAAAMAAAACAAACgwAAAgMAAAACAAACgwAAAwMAAAACAAACgwAAAAMEAAACAAACgwAAAIMEAAACAAACgwAAAAIAAAACAAACgwAAAAMAAAACAAADAwAAAgMAAAACAAADAwAAAwMAAAACAAADgwAAAwMAAAACAAADgwAAAAMEAAACAAADgwAAAAIAAAACAAADgwAAAAMAAAACAAAAAwQAAgMAAAACAAAAAwQAAwMAAAACAAAAAwQAAAMEAAACAAAAAwQAAIMEAAACAAAAAwQAAAIAAAACAAAAAwQAAAMAAAACAAAAQwQAAgMAAAACAAAAQwQAAwMAAAACAAAAQwQAAAMEAAACAAAAQwQAAIMEAAACAAAAgwQAAAIAAAACAAAAkwQAAoMAAAACAAAAkwQAAoMAAAACAAAAgwQAAIMEAAACAAAAgwQAAgMAAAACAAAAgwQAAwMAAAACAAAAgwQAAAMAAAACAAAAkwQAAoMAAAACAAAAkwQAAoMAAAACAAAAgwQAAAMEAAACAAAAwwQAAAIAAAACAAAAwwQAAAMAAAACAAAAwwQAAgMAAAACAAAAwwQAAwMAAAACAAACAPwAAAIAAAACAAABAwQAAAIAAAACAAACAPwAAAMAAAACAAABAwQAAAMAAAACAAACAPwAAgMAAAACAAABAwQAAgMAAAACAAACAPwAAwMAAAACAAABAwQAAwMAAAACAAACAPwAAAMEAAACAAABAwQAAAMEAAACAAACAPwAAIMEAAACAAABAwQAAIMEAAACA\"},{\"byteLength\":72,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,AAAAAAAAAEAAAACAAABAwAAAAEAAAACAAAAgwAAAwD8AAACAAABAwAAAAEAAAACAAAAgwAAAIEAAAACAAABAwAAAAEAAAACA\"}],\"images\":[{\"uri\":\"data:image/png;base64,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\"}],\"materials\":[{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0.5,0.5,0.5,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":false,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"baseColorTexture\":{\"index\":0,\"texCoord\":0},\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,1,1,1],\"metallicFactor\":0.4,\"roughnessFactor\":0.5}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[0,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}},{\"doubleSided\":true,\"pbrMetallicRoughness\":{\"baseColorFactor\":[1,0,0,1],\"metallicFactor\":1,\"roughnessFactor\":1}}],\"meshes\":[{\"primitives\":[{\"attributes\":{\"POSITION\":0},\"material\":0,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":1},\"material\":1,\"mode\":6},{\"attributes\":{\"POSITION\":1},\"material\":2,\"mode\":3},{\"attributes\":{\"POSITION\":2},\"material\":2,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":3,\"mode\":2},{\"attributes\":{\"POSITION\":3},\"material\":4,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4,\"TEXCOORD_0\":5},\"material\":5,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4,\"TEXCOORD_0\":6},\"material\":5,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4,\"TEXCOORD_0\":7},\"material\":5,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4,\"TEXCOORD_0\":8},\"material\":5,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4,\"TEXCOORD_0\":9},\"material\":5,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4,\"TEXCOORD_0\":10},\"material\":5,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4,\"TEXCOORD_0\":11},\"material\":5,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4,\"TEXCOORD_0\":12},\"material\":5,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":4,\"TEXCOORD_0\":13},\"material\":5,\"mode\":4}]},{\"primitives\":[{\"attributes\":{\"POSITION\":14},\"material\":6,\"mode\":6},{\"attributes\":{\"POSITION\":15},\"material\":7,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":16},\"material\":8,\"mode\":6},{\"attributes\":{\"POSITION\":16},\"material\":9,\"mode\":3},{\"attributes\":{\"POSITION\":17},\"material\":9,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":18},\"material\":10,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":19},\"material\":11,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[-0,-0,-0]},{\"mesh\":1,\"translation\":[-0,-2,-0]},{\"mesh\":0,\"translation\":[-0,-4,-0]},{\"mesh\":1,\"translation\":[-0,-6,-0]},{\"mesh\":0,\"translation\":[-0,-8,-0]},{\"mesh\":2,\"translation\":[-0,-10,-0]},{\"mesh\":0,\"translation\":[-1,-10,-0]},{\"mesh\":2,\"translation\":[-1,-8,-0]},{\"mesh\":0,\"translation\":[-1,-0,-0]},{\"mesh\":0,\"translation\":[-1,-4,-0]},{\"mesh\":3,\"translation\":[-1,-2,-0]},{\"mesh\":3,\"translation\":[-1,-6,-0]},{\"mesh\":4,\"translation\":[-2,-4,-0]},{\"mesh\":4,\"translation\":[-2,-8,-0]},{\"mesh\":5,\"translation\":[-2,-6,-0]},{\"mesh\":5,\"translation\":[-2,-10,-0]},{\"mesh\":6,\"translation\":[-3,-0,-0]},{\"mesh\":6,\"translation\":[-3,-10,-0]},{\"mesh\":7,\"translation\":[-3,-6,-0]},{\"mesh\":7,\"translation\":[-3,-8,-0]},{\"mesh\":7,\"translation\":[-4,-8,-0]},{\"mesh\":7,\"translation\":[-4,-6,-0]},{\"mesh\":8,\"translation\":[-4,-0,-0]},{\"mesh\":8,\"translation\":[-4,-2,-0]},{\"mesh\":9,\"translation\":[-5,-4,-0]},{\"mesh\":9,\"translation\":[-5,-6,-0]},{\"mesh\":10,\"translation\":[-5,-8,-0]},{\"mesh\":10,\"translation\":[-5,-10,-0]},{\"mesh\":11,\"translation\":[-5,-0,-0]},{\"mesh\":11,\"translation\":[-5,-2,-0]},{\"mesh\":1,\"translation\":[-6,-4,-0]},{\"mesh\":1,\"translation\":[-6,-6,-0]},{\"mesh\":1,\"translation\":[-7,-6,-0]},{\"mesh\":2,\"translation\":[-7,-8,-0]},{\"mesh\":1,\"translation\":[-7,-0,-0]},{\"mesh\":0,\"translation\":[-7,-2,-0]},{\"mesh\":2,\"translation\":[-8,-4,-0]},{\"mesh\":1,\"translation\":[-8,-6,-0]},{\"mesh\":2,\"translation\":[-8,-8,-0]},{\"mesh\":2,\"translation\":[-8,-10,-0]},{\"mesh\":2,\"translation\":[-8,-0,-0]},{\"mesh\":0,\"translation\":[-8,-2,-0]},{\"mesh\":0,\"translation\":[-9,-4,-0]},{\"mesh\":1,\"translation\":[-9,-6,-0]},{\"mesh\":0,\"translation\":[-9,-8,-0]},{\"mesh\":2,\"translation\":[-9,-10,-0]},{\"mesh\":0,\"translation\":[-10,-0,-0]},{\"mesh\":0,\"translation\":[-10,-10,-0]},{\"mesh\":0,\"translation\":[-10,-4,-0]},{\"mesh\":0,\"translation\":[-10,-6,-0]},{\"mesh\":0,\"translation\":[-10,-2,-0]},{\"mesh\":0,\"translation\":[-10,-8,-0]},{\"mesh\":12,\"translation\":[-11,-0,-0]},{\"mesh\":13,\"translation\":[-11,-2,-0]},{\"mesh\":13,\"translation\":[-11,-4,-0]},{\"mesh\":12,\"translation\":[-11,-6,-0]},{\"mesh\":14,\"translation\":[0,0,0]},{\"mesh\":15,\"translation\":[0,0,0]}],\"samplers\":[{\"magFilter\":9728,\"minFilter\":9728,\"wrapS\":33071,\"wrapT\":33071}],\"scene\":0,\"scenes\":[{\"nodes\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57]}],\"textures\":[{\"sampler\":0,\"source\":0}]}"
  }
]